summaryrefslogtreecommitdiffstats
path: root/sys/dev/ata
diff options
context:
space:
mode:
authorsos <sos@FreeBSD.org>2004-08-27 14:48:32 +0000
committersos <sos@FreeBSD.org>2004-08-27 14:48:32 +0000
commite873df18d574f684805529211de77980a932bb65 (patch)
treed6fa2eb01371bd02d62bb46a665ce9eb547349c4 /sys/dev/ata
parent4759b478a24308f1b05879cbaa6f87337dd14121 (diff)
downloadFreeBSD-src-e873df18d574f684805529211de77980a932bb65.zip
FreeBSD-src-e873df18d574f684805529211de77980a932bb65.tar.gz
Fix the handling of "inflight" requests when doing reinit's.
Add missing untimeout that would get lost in handling of some error situations, and caused what looked like random timeouts afterwards when the timeout fired.
Diffstat (limited to 'sys/dev/ata')
-rw-r--r--sys/dev/ata/ata-all.c7
-rw-r--r--sys/dev/ata/ata-all.h1
-rw-r--r--sys/dev/ata/ata-lowlevel.c11
-rw-r--r--sys/dev/ata/ata-queue.c23
4 files changed, 35 insertions, 7 deletions
diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c
index e66a4f6..fba9edc 100644
--- a/sys/dev/ata/ata-all.c
+++ b/sys/dev/ata/ata-all.c
@@ -115,7 +115,6 @@ ata_probe(device_t dev)
return 0;
}
-
int
ata_attach(device_t dev)
{
@@ -190,7 +189,6 @@ ata_detach(device_t dev)
ata_fail_requests(ch, NULL);
/* unlock the channel */
- ch->running = NULL;
ATA_UNLOCK_CH(ch);
ch->locking(ch, ATA_LF_UNLOCK);
@@ -237,12 +235,14 @@ ata_reinit(struct ata_channel *ch)
if (!ch->r_irq)
return ENXIO;
- /* reset the HW */
if (bootverbose)
ata_printf(ch, -1, "reiniting channel ..\n");
+
ATA_FORCELOCK_CH(ch);
+ ata_catch_inflight(ch);
ch->flags |= ATA_IMMEDIATE_MODE;
devices = ch->devices;
+
ch->hw.reset(ch);
if (bootverbose)
@@ -267,7 +267,6 @@ ata_reinit(struct ata_channel *ch)
}
/* unlock the channel */
- ch->running = NULL;
ATA_UNLOCK_CH(ch);
ch->locking(ch, ATA_LF_UNLOCK);
diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h
index 4065a81..6d85989 100644
--- a/sys/dev/ata/ata-all.h
+++ b/sys/dev/ata/ata-all.h
@@ -410,6 +410,7 @@ int ata_controlcmd(struct ata_device *atadev, u_int8_t command, u_int16_t featur
int ata_atapicmd(struct ata_device *atadev, u_int8_t *ccb, caddr_t data, int count, int flags, int timeout);
void ata_queue_request(struct ata_request *request);
void ata_finish(struct ata_request *request);
+void ata_catch_inflight(struct ata_channel *ch);
void ata_fail_requests(struct ata_channel *ch, struct ata_device *device);
char *ata_cmd2str(struct ata_request *request);
diff --git a/sys/dev/ata/ata-lowlevel.c b/sys/dev/ata/ata-lowlevel.c
index 0f93deb..eeaf006 100644
--- a/sys/dev/ata/ata-lowlevel.c
+++ b/sys/dev/ata/ata-lowlevel.c
@@ -526,7 +526,8 @@ ata_generic_interrupt(void *data)
break;
}
- /* schedule completition for this request */
+ /* finished running this request schedule completition */
+ ch->running = NULL;
ata_finish(request);
}
@@ -538,6 +539,14 @@ ata_generic_reset(struct ata_channel *ch)
u_int8_t stat0 = 0, stat1 = 0;
int mask = 0, timeout;
+ /* if DMA functionality present stop it */
+ if (ch->dma) {
+ if (ch->dma->stop)
+ ch->dma->stop(ch);
+ if (ch->dma->flags & ATA_DMA_LOADED)
+ ch->dma->unload(ch);
+ }
+
/* reset host end of channel (if supported) */
if (ch->reset)
ch->reset(ch);
diff --git a/sys/dev/ata/ata-queue.c b/sys/dev/ata/ata-queue.c
index 7151dcd..8f5d19c 100644
--- a/sys/dev/ata/ata-queue.c
+++ b/sys/dev/ata/ata-queue.c
@@ -70,6 +70,7 @@ ata_queue_request(struct ata_request *request)
/* kick HW into action */
if (request->device->channel->hw.transaction(request)==ATA_OP_FINISHED){
+ untimeout((timeout_t *)ata_timeout,request,request->timeout_handle);
if (!request->callback)
sema_destroy(&request->done);
return;
@@ -209,7 +210,6 @@ ata_finish(struct ata_request *request)
/* if we timed out the unlocking of the ATA channel is done later */
if (!(request->flags & ATA_R_TIMEOUT)) {
- ch->running = NULL;
ATA_UNLOCK_CH(ch);
ch->locking(ch, ATA_LF_UNLOCK);
}
@@ -466,7 +466,25 @@ ata_timeout(struct ata_request *request)
/* now simulate the missing interrupt */
request->flags |= ATA_R_TIMEOUT;
request->device->channel->hw.interrupt(request->device->channel);
- return;
+}
+
+void
+ata_catch_inflight(struct ata_channel *ch)
+{
+ struct ata_request *request = ch->running;
+
+ ch->running = NULL;
+ if (request) {
+ untimeout((timeout_t *)ata_timeout, request, request->timeout_handle);
+ ata_prtdev(request->device,
+ "WARNING - %s requeued due to channel reset",
+ ata_cmd2str(request));
+ if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL)))
+ printf(" LBA=%llu", (unsigned long long)request->u.ata.lba);
+ printf("\n");
+ request->flags |= ATA_R_REQUEUE;
+ ata_queue_request(request);
+ }
}
void
@@ -491,6 +509,7 @@ ata_fail_requests(struct ata_channel *ch, struct ata_device *device)
/* if we have a request "in flight" fail it as well */
if ((request = ch->running) && (!device || request->device == device)) {
untimeout((timeout_t *)ata_timeout, request, request->timeout_handle);
+ ch->running = NULL;
request->result = ENXIO;
if (request->callback)
(request->callback)(request);
OpenPOWER on IntegriCloud