mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-19 23:03:55 +00:00
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:
parent
a2033c9615
commit
dc26948b0c
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=134380
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue