summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorsos <sos@FreeBSD.org>2006-02-23 20:15:22 +0000
committersos <sos@FreeBSD.org>2006-02-23 20:15:22 +0000
commitcacaead301f6371dc869b89b0125ad91aec267be (patch)
tree99956d77de5b96904426b9266a74189acc6d63b0 /sys
parent555253faf1b3b727cb9a09bd92162e674bb91a50 (diff)
downloadFreeBSD-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.h1
-rw-r--r--sys/dev/ata/ata-queue.c43
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
OpenPOWER on IntegriCloud