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.
This commit is contained in:
Søren Schmidt 2004-08-27 14:48:32 +00:00
parent a2033c9615
commit dc26948b0c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=134380
4 changed files with 35 additions and 7 deletions

View file

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

View file

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

View file

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

View file

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