summaryrefslogtreecommitdiffstats
path: root/sys/dev/ata/ata-disk.c
diff options
context:
space:
mode:
authorsos <sos@FreeBSD.org>2001-03-15 15:36:25 +0000
committersos <sos@FreeBSD.org>2001-03-15 15:36:25 +0000
commit23f582a09c988d09419508393c9ba442b96ca16d (patch)
treec3403bfcb9f609eab209b622bd5e8892609a7fe5 /sys/dev/ata/ata-disk.c
parent7889f80f2c049148650a01110ac012342f5afce0 (diff)
downloadFreeBSD-src-23f582a09c988d09419508393c9ba442b96ca16d.zip
FreeBSD-src-23f582a09c988d09419508393c9ba442b96ca16d.tar.gz
Provide the interface to atacontrol and associated logic.
see atacontrol(8) for more. Also the ATA_ENABLE_ATAPI_DMA, ATA_ENABLE_WC and ATA_ENABLE_TAGS options are gone, use the tuneables listed in ata.4 instead from the loader (this makes it possible to switch off DMA before the driver has to touch the devices on broken hardware).
Diffstat (limited to 'sys/dev/ata/ata-disk.c')
-rw-r--r--sys/dev/ata/ata-disk.c175
1 files changed, 101 insertions, 74 deletions
diff --git a/sys/dev/ata/ata-disk.c b/sys/dev/ata/ata-disk.c
index e7d15ed..7910e94 100644
--- a/sys/dev/ata/ata-disk.c
+++ b/sys/dev/ata/ata-disk.c
@@ -32,6 +32,7 @@
#include "opt_ata.h"
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/ata.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/bio.h>
@@ -81,6 +82,10 @@ static int ad_version(u_int16_t);
/* internal vars */
static u_int32_t adp_lun_map = 0;
static MALLOC_DEFINE(M_AD, "AD driver", "ATA disk driver");
+static int ata_dma, ata_wc, ata_tags;
+TUNABLE_INT_DECL("hw.ata.ata_dma", 1, ata_dma);
+TUNABLE_INT_DECL("hw.ata.wc", 0, ata_wc);
+TUNABLE_INT_DECL("hw.ata.tags", 0, ata_tags);
/* defines */
#define AD_MAX_RETRIES 3
@@ -95,6 +100,7 @@ ad_attach(struct ata_softc *scp, int device)
struct ad_softc *adp;
dev_t dev;
int secsperint;
+ char name[16];
if (!(adp = malloc(sizeof(struct ad_softc), M_AD, M_NOWAIT | M_ZERO))) {
ata_printf(scp, device, "failed to allocate driver storage\n");
@@ -107,6 +113,8 @@ ad_attach(struct ata_softc *scp, int device)
#else
adp->lun = ata_get_lun(&adp_lun_map);
#endif
+ sprintf(name, "ad%d", adp->lun);
+ ata_set_name(scp, device, name);
adp->heads = AD_PARAM->heads;
adp->sectors = AD_PARAM->sectors;
adp->total_secs = AD_PARAM->cylinders * adp->heads * adp->sectors;
@@ -127,35 +135,41 @@ ad_attach(struct ata_softc *scp, int device)
adp->transfersize *= secsperint;
}
- /* enable read/write cacheing if not default on device */
+ /* enable read cacheing if not default on device */
if (ata_command(adp->controller, adp->unit, ATA_C_SETFEATURES,
0, 0, 0, 0, ATA_C_F_ENAB_RCACHE, ATA_WAIT_INTR))
- printf("ad%d: enabling readahead cache failed\n", adp->lun);
+ ata_printf(scp, device, "enabling readahead cache failed\n");
-#if defined(ATA_ENABLE_WC) || defined(ATA_ENABLE_TAGS)
- if (ata_command(adp->controller, adp->unit, ATA_C_SETFEATURES,
- 0, 0, 0, 0, ATA_C_F_ENAB_WCACHE, ATA_WAIT_INTR))
- printf("ad%d: enabling write cache failed\n", adp->lun);
-#else
- if (ata_command(adp->controller, adp->unit, ATA_C_SETFEATURES,
- 0, 0, 0, 0, ATA_C_F_DIS_WCACHE, ATA_WAIT_INTR))
- printf("ad%d: disabling write cache failed\n", adp->lun);
-#endif
- /* use DMA if drive & controller supports it */
- ata_dmainit(adp->controller, adp->unit,
- ata_pmode(AD_PARAM), ata_wmode(AD_PARAM), ata_umode(AD_PARAM));
+ /* enable write cacheing if allowed and not default on device */
+ if (ata_wc || ata_tags) {
+ if (ata_command(adp->controller, adp->unit, ATA_C_SETFEATURES,
+ 0, 0, 0, 0, ATA_C_F_ENAB_WCACHE, ATA_WAIT_INTR))
+ ata_printf(scp, device, "enabling write cache failed\n");
+ }
+ else {
+ if (ata_command(adp->controller, adp->unit, ATA_C_SETFEATURES,
+ 0, 0, 0, 0, ATA_C_F_DIS_WCACHE, ATA_WAIT_INTR))
+ ata_printf(scp, device, "disabling write cache failed\n");
+ }
- /* use tagged queueing if supported */
- if (ad_tagsupported(adp)) {
+ /* use DMA if allowed and if drive/controller supports it */
+ if (ata_dma)
+ ata_dmainit(adp->controller, adp->unit, ata_pmode(AD_PARAM),
+ ata_wmode(AD_PARAM), ata_umode(AD_PARAM));
+ else
+ ata_dmainit(adp->controller, adp->unit, ata_pmode(AD_PARAM), -1, -1);
+
+ /* use tagged queueing if allowed and supported */
+ if (ata_tags && ad_tagsupported(adp)) {
adp->num_tags = AD_PARAM->queuelen;
adp->flags |= AD_F_TAG_ENABLED;
adp->controller->flags |= ATA_QUEUED;
if (ata_command(adp->controller, adp->unit, ATA_C_SETFEATURES,
0, 0, 0, 0, ATA_C_F_DIS_RELIRQ, ATA_WAIT_INTR))
- printf("ad%d: disabling release interrupt failed\n", adp->lun);
+ ata_printf(scp, device, "disabling release interrupt failed\n");
if (ata_command(adp->controller, adp->unit, ATA_C_SETFEATURES,
0, 0, 0, 0, ATA_C_F_DIS_SRVIRQ, ATA_WAIT_INTR))
- printf("ad%d: disabling service interrupt failed\n", adp->lun);
+ ata_printf(scp, device, "disabling service interrupt failed\n");
}
devstat_add_entry(&adp->stats, "ad", adp->lun, DEV_BSIZE,
@@ -170,32 +184,31 @@ ad_attach(struct ata_softc *scp, int device)
bioq_init(&adp->queue);
if (bootverbose) {
- printf("ad%d: <%.40s/%.8s> ATA-%d disk at ata%d-%s\n",
- adp->lun, AD_PARAM->model, AD_PARAM->revision,
- ad_version(AD_PARAM->versmajor), device_get_unit(scp->dev),
- (adp->unit == ATA_MASTER) ? "master" : "slave");
-
- printf("ad%d: %luMB (%u sectors), %u cyls, %u heads, %u S/T, %u B/S\n",
- adp->lun, adp->total_secs / ((1024L * 1024L)/DEV_BSIZE),
- adp->total_secs,
- adp->total_secs / (adp->heads * adp->sectors),
- adp->heads, adp->sectors, DEV_BSIZE);
-
- printf("ad%d: %d secs/int, %d depth queue, %s%s\n",
- adp->lun, adp->transfersize / DEV_BSIZE, adp->num_tags + 1,
- (adp->flags & AD_F_TAG_ENABLED) ? "tagged " : "",
- ata_mode2str(adp->controller->mode[ATA_DEV(adp->unit)]));
+ ata_printf(scp, device, "<%.40s/%.8s> ATA-%d disk at ata%d-%s\n",
+ AD_PARAM->model, AD_PARAM->revision,
+ ad_version(AD_PARAM->versmajor), device_get_unit(scp->dev),
+ (adp->unit == ATA_MASTER) ? "master" : "slave");
- printf("ad%d: piomode=%d dmamode=%d udmamode=%d cblid=%d\n",
- adp->lun, ata_pmode(AD_PARAM), ata_wmode(AD_PARAM),
- ata_umode(AD_PARAM), AD_PARAM->cblid);
+ ata_printf(scp, device, "%luMB (%u sectors), %u C, %u H, %u S, %u B\n",
+ adp->total_secs / ((1024L*1024L)/DEV_BSIZE), adp->total_secs,
+ adp->total_secs / (adp->heads * adp->sectors),
+ adp->heads, adp->sectors, DEV_BSIZE);
+
+ ata_printf(scp, device, "%d secs/int, %d depth queue, %s%s\n",
+ adp->transfersize / DEV_BSIZE, adp->num_tags + 1,
+ (adp->flags & AD_F_TAG_ENABLED) ? "tagged " : "",
+ ata_mode2str(adp->controller->mode[ATA_DEV(adp->unit)]));
+
+ ata_printf(scp, device, "piomode=%d dmamode=%d udmamode=%d cblid=%d\n",
+ ata_pmode(AD_PARAM), ata_wmode(AD_PARAM),
+ ata_umode(AD_PARAM), AD_PARAM->cblid);
}
/* if this disk belongs to an ATA RAID dont print the probe */
if (ar_probe(adp))
- printf("ad%d: %luMB <%.40s> [%d/%d/%d] at ata%d-%s %s%s\n",
- adp->lun, adp->total_secs / ((1024L * 1024L) / DEV_BSIZE),
+ ata_printf(scp, device, "%luMB <%.40s> [%d/%d/%d] at ata%d-%s %s%s\n",
+ adp->total_secs / ((1024L * 1024L) / DEV_BSIZE),
AD_PARAM->model, adp->total_secs / (adp->heads * adp->sectors),
adp->heads, adp->sectors, device_get_unit(scp->dev),
(adp->unit == ATA_MASTER) ? "master" : "slave",
@@ -213,7 +226,7 @@ ad_detach(struct ad_softc *adp, int flush)
struct bio *bp;
adp->flags |= AD_F_DETACHING;
- printf("\nad%d: being removed from configuration", adp->lun);
+ ata_printf(adp->controller, adp->unit, "removed from configuration\n");
TAILQ_FOREACH(request, &adp->controller->ata_queue, chain) {
if (request->device != adp)
continue;
@@ -234,7 +247,8 @@ ad_detach(struct ad_softc *adp, int flush)
if (flush) {
if (ata_command(adp->controller, adp->unit, ATA_C_FLUSHCACHE,
0, 0, 0, 0, 0, ATA_WAIT_INTR))
- printf("ad%d: flushing cache on detach failed\n", adp->lun);
+ ata_printf(adp->controller, adp->unit,
+ "flushing cache on detach failed\n");
}
ata_free_lun(&adp_lun_map, adp->lun);
adp->controller->dev_softc[ATA_DEV(adp->unit)] = NULL;
@@ -354,8 +368,8 @@ addump(dev_t dev)
}
if (ata_wait(adp->controller, adp->unit, ATA_S_READY | ATA_S_DSC) < 0)
- printf("ad%d: timeout waiting for final ready\n", adp->lun);
-
+ ata_printf(adp->controller, adp->unit,
+ "timeout waiting for final ready\n");
return 0;
}
@@ -388,7 +402,7 @@ ad_start(struct ad_softc *adp)
}
if (!(request = malloc(sizeof(struct ad_request), M_AD, M_NOWAIT|M_ZERO))) {
- printf("ad%d: out of memory in start\n", adp->lun);
+ ata_printf(adp->controller, adp->unit, "out of memory in start\n");
return;
}
@@ -442,8 +456,8 @@ ad_transfer(struct ad_request *request)
count = howmany(request->bytecount, DEV_BSIZE);
if (count > 256) {
count = 256;
- printf("ad%d: count %d size transfers not supported\n",
- adp->lun, count);
+ ata_printf(adp->controller, adp->unit,
+ "count %d size transfers not supported\n", count);
}
if (adp->flags & AD_F_LBA_ENABLED) {
@@ -479,11 +493,13 @@ ad_transfer(struct ad_request *request)
if (ata_command(adp->controller, adp->unit, cmd,
cylinder, head, sector, request->tag << 3,
count, ATA_IMMEDIATE)) {
- printf("ad%d: error executing command", adp->lun);
+ ata_printf(adp->controller, adp->unit,
+ "error executing command");
goto transfer_failed;
}
if (ata_wait(adp->controller, adp->unit, ATA_S_READY)) {
- printf("ad%d: timeout waiting for READY\n", adp->lun);
+ ata_printf(adp->controller, adp->unit,
+ "timeout waiting for READY\n");
goto transfer_failed;
}
adp->outstanding++;
@@ -500,7 +516,8 @@ ad_transfer(struct ad_request *request)
if (ata_command(adp->controller, adp->unit, cmd, cylinder,
head, sector, count, 0, ATA_IMMEDIATE)) {
- printf("ad%d: error executing command", adp->lun);
+ ata_printf(adp->controller, adp->unit,
+ "error executing command");
goto transfer_failed;
}
#if 0
@@ -514,7 +531,8 @@ ad_transfer(struct ad_request *request)
*/
if (ata_wait(adp->controller, adp->unit,
ATA_S_READY | ATA_S_DRQ)) {
- printf("ad%d: timeout waiting for data phase\n", adp->lun);
+ ata_printf(adp->controller, adp->unit,
+ "timeout waiting for data phase\n");
goto transfer_failed;
}
#endif
@@ -536,7 +554,7 @@ ad_transfer(struct ad_request *request)
if (ata_command(adp->controller, adp->unit, cmd,
cylinder, head, sector, count, 0, ATA_IMMEDIATE)) {
- printf("ad%d: error executing command", adp->lun);
+ ata_printf(adp->controller, adp->unit, "error executing command");
goto transfer_failed;
}
}
@@ -551,7 +569,7 @@ ad_transfer(struct ad_request *request)
/* ready to write PIO data ? */
if (ata_wait(adp->controller, adp->unit,
(ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) < 0) {
- printf("ad%d: timeout waiting for DRQ", adp->lun);
+ ata_printf(adp->controller, adp->unit, "timeout waiting for DRQ");
goto transfer_failed;
}
@@ -650,7 +668,8 @@ ad_interrupt(struct ad_request *request)
/* if we arrived here with forced PIO mode, DMA doesn't work right */
if (request->flags & ADR_F_FORCE_PIO)
- printf("ad%d: DMA problem fallback to PIO mode\n", adp->lun);
+ ata_printf(adp->controller, adp->unit,
+ "DMA problem fallback to PIO mode\n");
/* if this was a PIO read operation, get the data */
if (!(request->flags & ADR_F_DMA_USED) &&
@@ -659,11 +678,13 @@ ad_interrupt(struct ad_request *request)
/* ready to receive data? */
if ((adp->controller->status & (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ))
!= (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ))
- printf("ad%d: read interrupt arrived early", adp->lun);
+ ata_printf(adp->controller, adp->unit,
+ "read interrupt arrived early");
if (ata_wait(adp->controller, adp->unit,
(ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) != 0) {
- printf("ad%d: read error detected (too) late", adp->lun);
+ ata_printf(adp->controller, adp->unit,
+ "read error detected (too) late");
request->flags |= ADR_F_ERROR;
}
else {
@@ -703,7 +724,7 @@ ad_interrupt(struct ad_request *request)
request->flags |= ADR_F_FLUSHCACHE;
if (ata_command(adp->controller, adp->unit, ATA_C_FLUSHCACHE,
0, 0, 0, 0, 0, ATA_IMMEDIATE))
- printf("ad%d: flushing cache failed\n", adp->lun);
+ ata_printf(adp->controller, adp->unit, "flushing cache failed\n");
else
return ATA_OP_CONTINUES;
}
@@ -758,8 +779,9 @@ ad_service(struct ad_softc *adp, int change)
/* check for error */
if (adp->controller->status & ATA_S_ERROR) {
- printf("ad%d: Oops! controller says s=0x%02x e=0x%02x\n",
- adp->lun, adp->controller->status, adp->controller->error);
+ ata_printf(adp->controller, adp->unit,
+ "Oops! controller says s=0x%02x e=0x%02x\n",
+ adp->controller->status, adp->controller->error);
ad_invalidatequeue(adp, NULL);
return ATA_OP_FINISHED;
}
@@ -767,22 +789,25 @@ ad_service(struct ad_softc *adp, int change)
/* issue SERVICE cmd */
if (ata_command(adp->controller, adp->unit, ATA_C_SERVICE,
0, 0, 0, 0, 0, ATA_IMMEDIATE)) {
- printf("ad%d: problem executing SERVICE cmd\n", adp->lun);
+ ata_printf(adp->controller, adp->unit,
+ "problem executing SERVICE cmd\n");
ad_invalidatequeue(adp, NULL);
return ATA_OP_FINISHED;
}
/* setup the transfer environment when ready */
if (ata_wait(adp->controller, adp->unit, ATA_S_READY)) {
- printf("ad%d: problem issueing SERVICE tag=%d s=0x%02x e=0x%02x\n",
- adp->lun, ATA_INB(adp->controller->r_io, ATA_COUNT) >> 3,
- adp->controller->status, adp->controller->error);
+ ata_printf(adp->controller, adp->unit,
+ "problem issueing SERVICE tag=%d s=0x%02x e=0x%02x\n",
+ ATA_INB(adp->controller->r_io, ATA_COUNT) >> 3,
+ adp->controller->status, adp->controller->error);
ad_invalidatequeue(adp, NULL);
return ATA_OP_FINISHED;
}
tag = ATA_INB(adp->controller->r_io, ATA_COUNT) >> 3;
if (!(request = adp->tags[tag])) {
- printf("ad%d: no request for this tag=%d??\n", adp->lun, tag);
+ ata_printf(adp->controller, adp->unit,
+ "no request for tag=%d\n", tag);
ad_invalidatequeue(adp, NULL);
return ATA_OP_FINISHED;
}
@@ -792,8 +817,9 @@ ad_service(struct ad_softc *adp, int change)
/* start DMA transfer when ready */
if (ata_wait(adp->controller, adp->unit, ATA_S_READY | ATA_S_DRQ)) {
- printf("ad%d: timeout waiting for data phase s=%02x e=%02x\n",
- adp->lun, adp->controller->status, adp->controller->error);
+ ata_printf(adp->controller, adp->unit,
+ "timeout waiting for data phase s=%02x e=%02x\n",
+ adp->controller->status, adp->controller->error);
ad_invalidatequeue(adp, NULL);
return ATA_OP_FINISHED;
}
@@ -825,7 +851,7 @@ ad_invalidatequeue(struct ad_softc *adp, struct ad_request *request)
struct ad_request *tmpreq;
int tag;
- printf("ad%d: invalidating queued requests\n", adp->lun);
+ ata_printf(adp->controller, adp->unit,"invalidating queued requests\n");
for (tag = 0; tag <= adp->num_tags; tag++) {
tmpreq = adp->tags[tag];
adp->tags[tag] = NULL;
@@ -836,7 +862,7 @@ ad_invalidatequeue(struct ad_softc *adp, struct ad_request *request)
}
if (ata_command(adp->controller, adp->unit, ATA_C_NOP,
0, 0, 0, 0, ATA_C_F_FLUSHQUEUE, ATA_WAIT_READY))
- printf("ad%d: flushing queue failed\n", adp->lun);
+ ata_printf(adp->controller, adp->unit, "flush queue failed\n");
adp->outstanding = 0;
}
}
@@ -844,7 +870,6 @@ ad_invalidatequeue(struct ad_softc *adp, struct ad_request *request)
static int
ad_tagsupported(struct ad_softc *adp)
{
-#ifdef ATA_ENABLE_TAGS
const char *drives[] = {"IBM-DPTA", "IBM-DTLA", NULL};
int i = 0;
@@ -852,15 +877,15 @@ ad_tagsupported(struct ad_softc *adp)
if ((adp->controller->chiptype & 0x0000ffff) == 0x0000105a)
return 0;
- /* check that drive has tags enabled, and is one we know works */
- if (AD_PARAM->supqueued && AD_PARAM->enabqueued) {
+ /* check that drive does DMA, has tags enabled, and is one we know works */
+ if (adp->controller->mode[ATA_DEV(adp->unit)] >= ATA_DMA &&
+ AD_PARAM->supqueued && AD_PARAM->enabqueued) {
while (drives[i] != NULL) {
if (!strncmp(AD_PARAM->model, drives[i], strlen(drives[i])))
return 1;
i++;
}
}
-#endif
return 0;
}
@@ -871,9 +896,10 @@ ad_timeout(struct ad_request *request)
int s = splbio();
adp->controller->running = NULL;
- printf("ad%d: %s command timeout tag=%d serv=%d - resetting\n",
- adp->lun, (request->flags & ADR_F_READ) ? "READ" : "WRITE",
- request->tag, request->serv);
+ ata_printf(adp->controller, adp->unit,
+ "%s command timeout tag=%d serv=%d - resetting\n",
+ (request->flags & ADR_F_READ) ? "READ" : "WRITE",
+ request->tag, request->serv);
if (request->flags & ADR_F_DMA_USED) {
ata_dmadone(adp->controller);
@@ -881,7 +907,8 @@ ad_timeout(struct ad_request *request)
if (request->retries == AD_MAX_RETRIES) {
ata_dmainit(adp->controller, adp->unit,
ata_pmode(AD_PARAM), -1, -1);
- printf("ad%d: trying fallback to PIO mode\n", adp->lun);
+ ata_printf(adp->controller, adp->unit,
+ "trying fallback to PIO mode\n");
request->retries = 0;
}
}
OpenPOWER on IntegriCloud