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.
This commit is contained in:
sos 2006-02-23 20:15:22 +00:00
parent 555253faf1
commit cacaead301
2 changed files with 27 additions and 17 deletions

View File

@ -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 */

View File

@ -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