diff options
author | sos <sos@FreeBSD.org> | 2002-07-22 18:35:01 +0000 |
---|---|---|
committer | sos <sos@FreeBSD.org> | 2002-07-22 18:35:01 +0000 |
commit | dacb15ae37d0a379f5da8f8a654055b7a28ca7cc (patch) | |
tree | 52daf8e8e817a60bd92139ca58025aac21034b34 /sys | |
parent | d1de8b21e3190c8aecc980999a4af733d05a518b (diff) | |
download | FreeBSD-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.c | 49 | ||||
-rw-r--r-- | sys/dev/ata/ata-disk.c | 105 | ||||
-rw-r--r-- | sys/dev/ata/ata-disk.h | 1 |
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 |