summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsos <sos@FreeBSD.org>2004-01-19 15:20:00 +0000
committersos <sos@FreeBSD.org>2004-01-19 15:20:00 +0000
commit5948092ae2b6900a66d24190cc2ee6d4c61f52f0 (patch)
tree813a85f55f80b3469bf9df09c0922c434a2f78a0
parentb6945f083eda9ba4a2c3418c60a4583889812645 (diff)
downloadFreeBSD-src-5948092ae2b6900a66d24190cc2ee6d4c61f52f0.zip
FreeBSD-src-5948092ae2b6900a66d24190cc2ee6d4c61f52f0.tar.gz
Fix breakage on timeout/retries. The bug cause a sema to be leaked so
that the calling process would newer wakeup.
-rw-r--r--sys/dev/ata/ata-all.c3
-rw-r--r--sys/dev/ata/ata-all.h2
-rw-r--r--sys/dev/ata/ata-queue.c44
-rw-r--r--sys/dev/ata/atapi-cd.c2
4 files changed, 27 insertions, 24 deletions
diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c
index a194694..d23c3d9 100644
--- a/sys/dev/ata/ata-all.c
+++ b/sys/dev/ata/ata-all.c
@@ -565,7 +565,7 @@ ata_getparam(struct ata_device *atadev, u_int8_t command)
if (request) {
request->device = atadev;
request->u.ata.command = command;
- request->flags = (ATA_R_READ | ATA_R_AT_HEAD | ATA_R_QUIET);
+ request->flags = (ATA_R_READ | ATA_R_IMMEDIATE | ATA_R_QUIET);
request->data = (caddr_t)atadev->param;
request->timeout = 2;
request->retries = 3;
@@ -576,6 +576,7 @@ ata_getparam(struct ata_device *atadev, u_int8_t command)
if (!(error = request->result))
break;
request->retries--;
+ request->flags |= ATA_R_REQUEUE;
}
ata_free_request(request);
}
diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h
index 70a26a9..495f5ec 100644
--- a/sys/dev/ata/ata-all.h
+++ b/sys/dev/ata/ata-all.h
@@ -193,7 +193,7 @@ struct ata_request {
#define ATA_R_TIMEOUT 0x0080
#define ATA_R_ORDERED 0x0100
-#define ATA_R_AT_HEAD 0x0200
+#define ATA_R_IMMEDIATE 0x0200
#define ATA_R_REQUEUE 0x0400
#define ATA_R_SKIPSTART 0x0800
diff --git a/sys/dev/ata/ata-queue.c b/sys/dev/ata/ata-queue.c
index ca43afd..24c9b50 100644
--- a/sys/dev/ata/ata-queue.c
+++ b/sys/dev/ata/ata-queue.c
@@ -53,12 +53,13 @@ ata_queue_request(struct ata_request *request)
{
/* mark request as virgin */
request->result = request->status = request->error = 0;
- if (!request->callback)
+ if (!request->callback && !(request->flags & ATA_R_REQUEUE))
sema_init(&request->done, 0, "ATA request done");
- if (request->device->channel->flags & ATA_IMMEDIATE_MODE) {
-
- // request->flags |= ATA_R_DEBUG;
+ /* in IMMEDIATE_MODE we dont queue but call HW directly */
+ /* used only during reinit for getparm and config */
+ if ((request->device->channel->flags & ATA_IMMEDIATE_MODE) &&
+ (request->flags & (ATA_R_CONTROL | ATA_R_IMMEDIATE))) {
/* arm timeout */
if (!request->timeout_handle.callout && !dumping) {
@@ -67,16 +68,16 @@ ata_queue_request(struct ata_request *request)
}
/* kick HW into action */
- if (request->device->channel->hw.transaction(request) ==
- ATA_OP_CONTINUES) {
- ATA_DEBUG_RQ(request, "wait for completition");
- sema_wait(&request->done);
+ if (request->device->channel->hw.transaction(request)==ATA_OP_FINISHED){
+ if (!request->callback)
+ sema_destroy(&request->done);
+ return;
}
}
else {
/* put request on the locked queue at the specified location */
mtx_lock(&request->device->channel->queue_mtx);
- if (request->flags & ATA_R_AT_HEAD)
+ if (request->flags & ATA_R_IMMEDIATE)
TAILQ_INSERT_HEAD(&request->device->channel->ata_queue,
request, chain);
else
@@ -86,21 +87,21 @@ ata_queue_request(struct ata_request *request)
ATA_DEBUG_RQ(request, "queued");
- /* should we skip start ? */
+ /* should we skip start to avoid lock recursion ? */
if (!(request->flags & ATA_R_SKIPSTART))
ata_start(request->device->channel);
-
- /* if this is a requeued request callback/sleep is already setup */
- if (request->flags & ATA_R_REQUEUE)
- return;
- /* if this is not a callback wait until request is completed */
- if (!request->callback) {
- ATA_DEBUG_RQ(request, "wait for completition");
- sema_wait(&request->done);
- }
}
- if (!request->callback)
+
+ /* if this is a requeued request callback/sleep has been setup */
+ if (request->flags & ATA_R_REQUEUE)
+ return;
+
+ /* if this is not a callback wait until request is completed */
+ if (!request->callback) {
+ ATA_DEBUG_RQ(request, "wait for completition");
+ sema_wait(&request->done);
sema_destroy(&request->done);
+ }
}
int
@@ -231,7 +232,7 @@ ata_completed(void *context, int pending)
/* if retries still permit, reinject this request */
if (request->retries-- > 0) {
request->flags &= ~(ATA_R_TIMEOUT | ATA_R_SKIPSTART);
- request->flags |= (ATA_R_AT_HEAD | ATA_R_REQUEUE);
+ request->flags |= (ATA_R_IMMEDIATE | ATA_R_REQUEUE);
ata_queue_request(request);
return;
}
@@ -269,6 +270,7 @@ ata_completed(void *context, int pending)
printf(" LBA=%llu", (unsigned long long)request->u.ata.lba);
printf("\n");
request->flags &= ~ATA_R_SKIPSTART;
+ request->flags |= (ATA_R_IMMEDIATE | ATA_R_REQUEUE);
ata_queue_request(request);
return;
}
diff --git a/sys/dev/ata/atapi-cd.c b/sys/dev/ata/atapi-cd.c
index 9dea17d..3896917 100644
--- a/sys/dev/ata/atapi-cd.c
+++ b/sys/dev/ata/atapi-cd.c
@@ -1345,7 +1345,7 @@ acd_select_slot(struct acd_softc *cdp)
ATA_PROTO_ATAPI_12 ? 16 : 12);
request->timeout = 30;
request->callback = acd_unload_done;
- request->flags |= (ATA_R_ATAPI | ATA_R_AT_HEAD);
+ request->flags |= (ATA_R_ATAPI | ATA_R_IMMEDIATE);
ata_queue_request(request);
}
OpenPOWER on IntegriCloud