diff options
author | sos <sos@FreeBSD.org> | 2006-02-23 20:15:22 +0000 |
---|---|---|
committer | sos <sos@FreeBSD.org> | 2006-02-23 20:15:22 +0000 |
commit | cacaead301f6371dc869b89b0125ad91aec267be (patch) | |
tree | 99956d77de5b96904426b9266a74189acc6d63b0 /sys | |
parent | 555253faf1b3b727cb9a09bd92162e674bb91a50 (diff) | |
download | FreeBSD-src-cacaead301f6371dc869b89b0125ad91aec267be.zip FreeBSD-src-cacaead301f6371dc869b89b0125ad91aec267be.tar.gz |
Keep the parent device (in this case the channel) around in ata_request,
so we dont panic device removal or failure.
Clean up ata_fail_requests to prevent the queue munging to fail.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/ata/ata-all.h | 1 | ||||
-rw-r--r-- | sys/dev/ata/ata-queue.c | 43 |
2 files changed, 27 insertions, 17 deletions
diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h index 670c580..1b98e04 100644 --- a/sys/dev/ata/ata-all.h +++ b/sys/dev/ata/ata-all.h @@ -338,6 +338,7 @@ struct ata_composite { /* structure used to queue an ATA/ATAPI request */ struct ata_request { device_t dev; /* device handle */ + device_t parent; /* channel handle */ union { struct { u_int8_t command; /* command reg */ diff --git a/sys/dev/ata/ata-queue.c b/sys/dev/ata/ata-queue.c index da590f49..e7116fe 100644 --- a/sys/dev/ata/ata-queue.c +++ b/sys/dev/ata/ata-queue.c @@ -55,6 +55,7 @@ ata_queue_request(struct ata_request *request) /* mark request as virgin (this might be a ATA_R_REQUEUE) */ request->result = request->status = request->error = 0; + request->parent = device_get_parent(request->dev); callout_init_mtx(&request->callout, &ch->state_mtx, CALLOUT_RETURNUNLOCKED); if (!request->callback && !(request->flags & ATA_R_REQUEUE)) @@ -218,7 +219,7 @@ ata_start(device_t dev) void ata_finish(struct ata_request *request) { - struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_channel *ch = device_get_softc(request->parent); /* * if in ATA_STALL_QUEUE state or request has ATA_R_DIRECT flags set @@ -247,7 +248,7 @@ static void ata_completed(void *context, int dummy) { struct ata_request *request = (struct ata_request *)context; - struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_channel *ch = device_get_softc(request->parent); struct ata_device *atadev = device_get_softc(request->dev); struct ata_composite *composite; @@ -466,7 +467,7 @@ ata_completed(void *context, int dummy) void ata_timeout(struct ata_request *request) { - struct ata_channel *ch = device_get_softc(device_get_parent(request->dev)); + struct ata_channel *ch = device_get_softc(request->parent); //request->flags |= ATA_R_DEBUG; ATA_DEBUG_RQ(request, "timeout"); @@ -479,7 +480,6 @@ ata_timeout(struct ata_request *request) */ if (ch->state == ATA_ACTIVE) { request->flags |= ATA_R_TIMEOUT; - ch->running = NULL; mtx_unlock(&ch->state_mtx); ATA_LOCKING(ch->dev, ATA_LF_UNLOCK); ata_finish(request); @@ -493,34 +493,43 @@ void ata_fail_requests(device_t dev) { struct ata_channel *ch = device_get_softc(device_get_parent(dev)); - struct ata_request *request; + struct ata_request *request, *tmp; + TAILQ_HEAD(, ata_request) fail_requests; + TAILQ_INIT(&fail_requests); - /* do we have any outstanding request to care about ?*/ + /* grap all channel locks to avoid races */ + mtx_lock(&ch->queue_mtx); mtx_lock(&ch->state_mtx); + + /* do we have any running request to care about ? */ if ((request = ch->running) && (!dev || request->dev == dev)) { callout_stop(&request->callout); ch->running = NULL; - } - else - request = NULL; - mtx_unlock(&ch->state_mtx); - if (request) { + ch->state = ATA_IDLE; request->result = ENXIO; - ata_finish(request); + TAILQ_INSERT_TAIL(&fail_requests, request, chain); } /* fail all requests queued on this channel for device dev if !NULL */ - mtx_lock(&ch->queue_mtx); - while ((request = TAILQ_FIRST(&ch->ata_queue))) { + TAILQ_FOREACH_SAFE(request, &ch->ata_queue, chain, tmp) { if (!dev || request->dev == dev) { TAILQ_REMOVE(&ch->ata_queue, request, chain); - mtx_unlock(&ch->queue_mtx); request->result = ENXIO; - ata_finish(request); - mtx_lock(&ch->queue_mtx); + TAILQ_INSERT_TAIL(&fail_requests, request, chain); } } + + mtx_unlock(&ch->state_mtx); mtx_unlock(&ch->queue_mtx); + + /* finish up all requests collected above */ + TAILQ_FOREACH_SAFE(request, &fail_requests, chain, tmp) { + TAILQ_REMOVE(&fail_requests, request, chain); + ata_finish(request); + } + + /* we might have work for the other device on this channel */ + ata_start(ch->dev); } static u_int64_t |