summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorsos <sos@FreeBSD.org>2002-07-22 18:35:01 +0000
committersos <sos@FreeBSD.org>2002-07-22 18:35:01 +0000
commitdacb15ae37d0a379f5da8f8a654055b7a28ca7cc (patch)
tree52daf8e8e817a60bd92139ca58025aac21034b34 /sys
parentd1de8b21e3190c8aecc980999a4af733d05a518b (diff)
downloadFreeBSD-src-dacb15ae37d0a379f5da8f8a654055b7a28ca7cc.zip
FreeBSD-src-dacb15ae37d0a379f5da8f8a654055b7a28ca7cc.tar.gz
Update the tags handling a bit, which makes support for the
older IBM DTTA series of drives possible. Update error handling a bit now we are here.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ata/ata-all.c49
-rw-r--r--sys/dev/ata/ata-disk.c105
-rw-r--r--sys/dev/ata/ata-disk.h1
3 files changed, 72 insertions, 83 deletions
diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c
index c3c252d..24ed916 100644
--- a/sys/dev/ata/ata-all.c
+++ b/sys/dev/ata/ata-all.c
@@ -611,38 +611,23 @@ ata_intr(void *data)
return;
break;
#endif
- case ATA_WAIT_INTR:
- case ATA_WAIT_INTR | ATA_CONTROL:
- wakeup((caddr_t)ch);
- break;
-
- case ATA_WAIT_READY:
- case ATA_WAIT_READY | ATA_CONTROL:
- break;
-
- case ATA_IDLE:
- if (ch->flags & ATA_QUEUED) {
- ch->active = ATA_ACTIVE;
- if (ata_service(ch) == ATA_OP_CONTINUES)
- return;
- }
- /* FALLTHROUGH */
-
default:
-#ifdef ATA_DEBUG
- {
- static int intr_count = 0;
+ if (ch->active & ATA_WAIT_INTR)
+ wakeup((caddr_t)ch);
+ }
- if (intr_count++ < 10)
- ata_printf(ch, -1, "unwanted interrupt #%d active=%02x s=%02x\n",
- intr_count, ch->active, ch->status);
+ if (ch->active & ATA_CONTROL) {
+ ATA_FORCELOCK_CH(ch, ATA_CONTROL);
+ return;
}
-#endif
- break;
+
+ if ((ch->flags & ATA_QUEUED) &&
+ ATA_INB(ch->r_altio, ATA_ALTSTAT) & ATA_S_SERVICE) {
+ ATA_FORCELOCK_CH(ch, ATA_ACTIVE);
+ if (ata_service(ch) == ATA_OP_CONTINUES)
+ return;
}
- ch->active &= ATA_CONTROL;
- if (ch->active & ATA_CONTROL)
- return;
+ ATA_UNLOCK_CH(ch);
ch->running = NULL;
ata_start(ch);
return;
@@ -700,8 +685,8 @@ ata_start(struct ata_channel *ch)
}
}
#endif
- splx(s);
ATA_UNLOCK_CH(ch);
+ splx(s);
}
void
@@ -843,12 +828,10 @@ ata_reinit(struct ata_channel *ch)
ATA_FORCELOCK_CH(ch, ATA_CONTROL);
ch->running = NULL;
devices = ch->devices;
- ata_printf(ch, -1, "resetting devices .. ");
+ ata_printf(ch, -1, "resetting devices ..\n");
ata_reset(ch);
if ((misdev = devices & ~ch->devices)) {
- if (misdev)
- printf("\n");
#ifdef DEV_ATADISK
if (misdev & ATA_ATA_MASTER && ch->device[MASTER].driver)
ad_detach(&ch->device[MASTER], 0);
@@ -886,8 +869,6 @@ ata_reinit(struct ata_channel *ch)
if (ata_getparam(&ch->device[SLAVE], ATA_C_ATAPI_IDENTIFY))
newdev &= ~ATA_ATAPI_SLAVE;
}
- if (!misdev && newdev)
- printf("\n");
#ifdef DEV_ATADISK
if (newdev & ATA_ATA_MASTER && !ch->device[MASTER].driver)
ad_attach(&ch->device[MASTER]);
diff --git a/sys/dev/ata/ata-disk.c b/sys/dev/ata/ata-disk.c
index f28f7f4..1211e0a 100644
--- a/sys/dev/ata/ata-disk.c
+++ b/sys/dev/ata/ata-disk.c
@@ -123,6 +123,7 @@ ad_attach(struct ata_device *atadev)
adp->heads = atadev->param->heads;
adp->sectors = atadev->param->sectors;
adp->total_secs = atadev->param->cylinders * adp->heads * adp->sectors;
+ adp->max_iosize = 256 * DEV_BSIZE;
bioq_init(&adp->queue);
lbasize = (u_int32_t)atadev->param->lba_size_1 |
@@ -147,6 +148,7 @@ ad_attach(struct ata_device *atadev)
adp->total_secs = lbasize48;
ATA_SLEEPLOCK_CH(atadev->channel, ATA_CONTROL);
+
/* use multiple sectors/interrupt if device supports it */
adp->transfersize = DEV_BSIZE;
if (ad_version(atadev->param->version_major)) {
@@ -203,7 +205,7 @@ ad_attach(struct ata_device *atadev)
dev = disk_create(adp->lun, &adp->disk, 0, &ad_cdevsw, &addisk_cdevsw);
dev->si_drv1 = adp;
- dev->si_iosize_max = 256 * DEV_BSIZE;
+ dev->si_iosize_max = adp->max_iosize;
adp->dev = dev;
/* construct the disklabel */
@@ -373,10 +375,9 @@ ad_start(struct ata_device *atadev)
request->tag = tag;
if (bp->bio_cmd == BIO_READ)
request->flags |= ADR_F_READ;
- if (adp->device->mode >= ATA_DMA) {
- if (ata_dmaalloc(atadev))
- adp->device->mode = ATA_PIO;
- }
+
+ if (adp->device->mode >= ATA_DMA && ata_dmaalloc(atadev))
+ adp->device->mode = ATA_PIO;
/* insert in tag array */
adp->tags[tag] = request;
@@ -393,7 +394,7 @@ ad_transfer(struct ad_request *request)
{
struct ad_softc *adp;
u_int64_t lba;
- u_int32_t count, max_count;
+ u_int32_t count;
u_int8_t cmd;
int flags = ATA_IMMEDIATE;
@@ -402,23 +403,27 @@ ad_transfer(struct ad_request *request)
/* calculate transfer details */
lba = request->blockaddr + (request->donecount / DEV_BSIZE);
+
+ /* start timeout for this transfer */
+ if (!request->timeout_handle.callout && !dumping)
+ request->timeout_handle =
+ timeout((timeout_t*)ad_timeout, request, 10 * hz);
if (request->donecount == 0) {
- /* start timeout for this transfer */
- if (dumping)
- request->timeout_handle.callout = NULL;
+ /* check & setup transfer parameters */
+ if (request->bytecount > adp->max_iosize) {
+ ata_prtdev(adp->device,
+ "%d byte transfers not supported\n", request->bytecount);
+ count = howmany(adp->max_iosize, DEV_BSIZE);
+ }
else
- request->timeout_handle =
- timeout((timeout_t*)ad_timeout, request, 10 * hz);
+ count = howmany(request->bytecount, DEV_BSIZE);
- /* setup transfer parameters */
- count = howmany(request->bytecount, DEV_BSIZE);
- max_count = adp->device->param->support.address48 ? 65536 : 256;
- if (count > max_count) {
+ if (count > (adp->device->param->support.address48 ? 65536 : 256)) {
ata_prtdev(adp->device,
- "count %d size transfers not supported\n", count);
- count = max_count;
+ "%d block transfers not supported\n", count);
+ count = adp->device->param->support.address48 ? 65536 : 256;
}
if (adp->flags & AD_F_CHS_USED) {
@@ -430,9 +435,6 @@ ad_transfer(struct ad_request *request)
adp->device->flags |= ATA_D_USE_CHS;
}
- /* setup first transfer length */
- request->currentsize = min(request->bytecount, adp->transfersize);
-
devstat_start_transaction(&adp->stats);
/* does this drive & transfer work with DMA ? */
@@ -493,7 +495,7 @@ ad_transfer(struct ad_request *request)
}
/* does this drive support multi sector transfers ? */
- if (request->currentsize > DEV_BSIZE)
+ if (adp->transfersize > DEV_BSIZE)
cmd = request->flags&ADR_F_READ ? ATA_C_READ_MUL : ATA_C_WRITE_MUL;
/* just plain old single sector transfer */
@@ -533,7 +535,6 @@ ad_transfer(struct ad_request *request)
transfer_failed:
untimeout((timeout_t *)ad_timeout, request, request->timeout_handle);
ad_invalidatequeue(adp, request);
- printf(" - resetting\n");
/* if retries still permit, reinject this request */
if (request->retries++ < AD_MAX_RETRIES)
@@ -648,7 +649,7 @@ ad_interrupt(struct ad_request *request)
else {
request->bytecount -= request->currentsize;
request->donecount += request->currentsize;
- if (request->bytecount > 0) {
+ if (!(request->flags & ADR_F_DMA_USED) && request->bytecount > 0) {
ad_transfer(request);
return ATA_OP_CONTINUES;
}
@@ -663,7 +664,7 @@ ad_interrupt(struct ad_request *request)
ad_free(request);
adp->outstanding--;
- /* check for SERVICE (tagged operations only) */
+ /* check for SERVICE */
return ad_service(adp, 1);
}
@@ -738,7 +739,7 @@ ad_service(struct ad_softc *adp, int change)
ad_invalidatequeue(adp, NULL);
return ATA_OP_FINISHED;
}
- adp->device->channel->active = ATA_ACTIVE_ATA;
+ ATA_FORCELOCK_CH(adp->device->channel, ATA_ACTIVE_ATA);
adp->device->channel->running = request;
request->serv++;
@@ -767,7 +768,7 @@ ad_free(struct ad_request *request)
static void
ad_invalidatequeue(struct ad_softc *adp, struct ad_request *request)
{
- /* if tags used invalidate all other tagged transfers */
+ /* if tags in use invalidate all other outstanding transfers */
if (adp->flags & AD_F_TAG_ENABLED) {
struct ad_request *tmpreq;
int tag;
@@ -781,40 +782,45 @@ ad_invalidatequeue(struct ad_softc *adp, struct ad_request *request)
untimeout((timeout_t *)ad_timeout, tmpreq, tmpreq->timeout_handle);
TAILQ_INSERT_HEAD(&adp->device->channel->ata_queue, tmpreq, chain);
}
+ adp->outstanding = 0;
if (ata_command(adp->device, ATA_C_NOP,
0, 0, ATA_C_F_FLUSHQUEUE, ATA_WAIT_READY))
ata_prtdev(adp->device, "flush queue failed\n");
- adp->outstanding = 0;
}
}
static int
ad_tagsupported(struct ad_softc *adp)
{
- const char *good[] = {"IBM-DPTA", "IBM-DTLA", NULL};
- int i = 0;
-
switch (adp->device->channel->chiptype) {
- case 0x4d33105a: /* Promises before TX2 doesn't work with tagged queuing */
- case 0x4d38105a:
- case 0x0d30105a:
+ case 0x0d30105a: /* Promises before TX2 doesn't work with tagged queuing */
+ case 0x0d38105a:
case 0x4d30105a:
+ case 0x4d33105a:
+ case 0x4d38105a:
return 0;
}
/* check that drive does DMA, has tags enabled, and is one we know works */
if (adp->device->mode >= ATA_DMA && adp->device->param->support.queued &&
adp->device->param->enabled.queued) {
- while (good[i] != NULL) {
- if (!strncmp(adp->device->param->model, good[i], strlen(good[i])))
- return 1;
- i++;
+
+ /* IBM DTTA series needs transfers <= 64K for tags to work properly */
+ if (!strncmp(adp->device->param->model, "IBM-DTTA", 8)) {
+ adp->max_iosize = 128 * DEV_BSIZE;
+ return 1;
}
- /*
- * check IBM's new obscure way of naming drives
- * we want "IC" (IBM CORP) and "AT" or "AV" (ATA interface)
- * but doesn't care about the other info (size, capacity etc)
- */
+
+ /* IBM DJNA series has broken tags, corrupts data */
+ if (!strncmp(adp->device->param->model, "IBM-DJNA", 8))
+ return 0;
+
+ /* IBM DPTA & IBM DTLA series supports tags */
+ if (!strncmp(adp->device->param->model, "IBM-DPTA", 8) ||
+ !strncmp(adp->device->param->model, "IBM-DTLA", 8))
+ return 1;
+
+ /* IBM IC series ATA drives supports tags */
if (!strncmp(adp->device->param->model, "IC", 2) &&
(!strncmp(adp->device->param->model + 8, "AT", 2) ||
!strncmp(adp->device->param->model + 8, "AV", 2)))
@@ -829,6 +835,7 @@ ad_timeout(struct ad_request *request)
struct ad_softc *adp = request->softc;
adp->device->channel->running = NULL;
+ request->timeout_handle.callout = NULL;
ata_prtdev(adp->device, "%s command timeout tag=%d serv=%d - resetting\n",
(request->flags & ADR_F_READ) ? "READ" : "WRITE",
request->tag, request->serv);
@@ -846,7 +853,7 @@ ad_timeout(struct ad_request *request)
/* if retries still permit, reinject this request */
if (request->retries++ < AD_MAX_RETRIES) {
TAILQ_INSERT_HEAD(&adp->device->channel->ata_queue, request, chain);
- }
+ }
else {
/* retries all used up, return error */
request->bp->bio_error = EIO;
@@ -887,10 +894,10 @@ ad_print(struct ad_softc *adp)
ata_prtdev(adp->device,
"%lluMB (%llu sectors), %llu C, %u H, %u S, %u B\n",
(unsigned long long)(adp->total_secs /
- ((1024L*1024L)/DEV_BSIZE)),
- (unsigned long long) adp->total_secs,
- (unsigned long long) (adp->total_secs /
- (adp->heads * adp->sectors)),
+ ((1024L*1024L)/DEV_BSIZE)),
+ (unsigned long long)adp->total_secs,
+ (unsigned long long)(adp->total_secs /
+ (adp->heads * adp->sectors)),
adp->heads, adp->sectors, DEV_BSIZE);
ata_prtdev(adp->device, "%d secs/int, %d depth queue, %s%s\n",
@@ -907,10 +914,10 @@ ad_print(struct ad_softc *adp)
else
ata_prtdev(adp->device,"%lluMB <%.40s> [%lld/%d/%d] at ata%d-%s %s%s\n",
(unsigned long long)(adp->total_secs /
- ((1024L * 1024L) / DEV_BSIZE)),
+ ((1024L * 1024L) / DEV_BSIZE)),
adp->device->param->model,
(unsigned long long)(adp->total_secs /
- (adp->heads*adp->sectors)),
+ (adp->heads * adp->sectors)),
adp->heads, adp->sectors,
device_get_unit(adp->device->channel->dev),
(adp->device->unit == ATA_MASTER) ? "master" : "slave",
diff --git a/sys/dev/ata/ata-disk.h b/sys/dev/ata/ata-disk.h
index 80ae15c..0c190d1 100644
--- a/sys/dev/ata/ata-disk.h
+++ b/sys/dev/ata/ata-disk.h
@@ -60,6 +60,7 @@ struct ad_softc {
u_int8_t sectors;
u_int32_t transfersize; /* size of each transfer */
int num_tags; /* number of tags supported */
+ int max_iosize; /* max size of transfer */
int flags; /* drive flags */
#define AD_F_LABELLING 0x0001
#define AD_F_CHS_USED 0x0002
OpenPOWER on IntegriCloud