diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h index 1b98e0407389..436182495cd0 100644 --- a/sys/dev/ata/ata-all.h +++ b/sys/dev/ata/ata-all.h @@ -372,6 +372,8 @@ struct ata_request { #define ATA_R_DIRECT 0x00001000 #define ATA_R_DEBUG 0x10000000 +#define ATA_R_DANGER1 0x20000000 +#define ATA_R_DANGER2 0x40000000 u_int8_t status; /* ATA status */ u_int8_t error; /* ATA error */ @@ -569,8 +571,10 @@ int ata_generic_command(struct ata_request *request); /* macros for alloc/free of struct ata_request */ extern uma_zone_t ata_request_zone; #define ata_alloc_request() uma_zalloc(ata_request_zone, M_NOWAIT | M_ZERO) -#define ata_free_request(request) uma_zfree(ata_request_zone, request) - +#define ata_free_request(request) { \ + if (!(request->flags & ATA_R_DANGER2)) \ + uma_zfree(ata_request_zone, request); \ + } /* macros for alloc/free of struct ata_composite */ extern uma_zone_t ata_composite_zone; #define ata_alloc_composite() uma_zalloc(ata_composite_zone, M_NOWAIT | M_ZERO) diff --git a/sys/dev/ata/ata-queue.c b/sys/dev/ata/ata-queue.c index 036b0081f9ab..5de54ffadc9e 100644 --- a/sys/dev/ata/ata-queue.c +++ b/sys/dev/ata/ata-queue.c @@ -95,12 +95,14 @@ ata_queue_request(struct ata_request *request) /* if this is not a callback wait until request is completed */ if (!request->callback) { ATA_DEBUG_RQ(request, "wait for completition"); - while (!dumping && - sema_timedwait(&request->done, request->timeout * hz * 4)) { + if (!dumping && + sema_timedwait(&request->done, request->timeout * hz * 4)) { device_printf(request->dev, - "req=%p %s semaphore timeout !! DANGER Will Robinson !!\n", - request, ata_cmd2str(request)); - ata_start(ch->dev); + "WARNING - %s taskqueue timeout " + "- completing request directly\n", + ata_cmd2str(request)); + request->flags |= ATA_R_DANGER1; + ata_completed(request, 0); } sema_destroy(&request->done); } @@ -252,6 +254,17 @@ ata_completed(void *context, int dummy) struct ata_device *atadev = device_get_softc(request->dev); struct ata_composite *composite; + if (request->flags & ATA_R_DANGER2) { + device_printf(request->dev, + "WARNING - %s freeing taskqueue zombie request\n", + ata_cmd2str(request)); + request->flags &= ~(ATA_R_DANGER1 | ATA_R_DANGER2); + ata_free_request(request); + return; + } + if (request->flags & ATA_R_DANGER1) + request->flags |= ATA_R_DANGER2 + ATA_DEBUG_RQ(request, "completed entered"); /* if we had a timeout, reinit channel and deal with the falldown */