diff options
author | jimharris <jimharris@FreeBSD.org> | 2012-04-10 16:33:19 +0000 |
---|---|---|
committer | jimharris <jimharris@FreeBSD.org> | 2012-04-10 16:33:19 +0000 |
commit | 9daad3b04b7269c64f326876b55dac3ae0d7b844 (patch) | |
tree | 5e273e5e49ef5af0a3d25e0afdd915456b69098d /sys/dev | |
parent | c41a4a0d879c72675b7d273de7fc8a7e3e57dbd7 (diff) | |
download | FreeBSD-src-9daad3b04b7269c64f326876b55dac3ae0d7b844.zip FreeBSD-src-9daad3b04b7269c64f326876b55dac3ae0d7b844.tar.gz |
Queue CCBs internally instead of using CAM_REQUEUE_REQ status. This fixes
problem where userspace apps such as smartctl fail due to CAM_REQUEUE_REQ
status getting returned when tagged commands are outstanding when smartctl
sends its I/O using the pass(4) interface.
Sponsored by: Intel
Found and tested by: Ravi Pokala <rpokala at panasas dot com>
Reviewed by: scottl
Approved by: scottl
MFC after: 1 week
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/isci/isci.h | 1 | ||||
-rw-r--r-- | sys/dev/isci/isci_controller.c | 1 | ||||
-rw-r--r-- | sys/dev/isci/isci_io_request.c | 62 | ||||
-rw-r--r-- | sys/dev/isci/isci_remote_device.c | 21 |
4 files changed, 56 insertions, 29 deletions
diff --git a/sys/dev/isci/isci.h b/sys/dev/isci/isci.h index 50f0236..d6ad93c 100644 --- a/sys/dev/isci/isci.h +++ b/sys/dev/isci/isci.h @@ -86,6 +86,7 @@ struct ISCI_REMOTE_DEVICE { BOOL is_resetting; uint32_t frozen_lun_mask; SCI_FAST_LIST_ELEMENT_T pending_device_reset_element; + TAILQ_HEAD(,ccb_hdr) queued_ccbs; }; struct ISCI_DOMAIN { diff --git a/sys/dev/isci/isci_controller.c b/sys/dev/isci/isci_controller.c index 8511400..a4b7cfe 100644 --- a/sys/dev/isci/isci_controller.c +++ b/sys/dev/isci/isci_controller.c @@ -430,6 +430,7 @@ int isci_controller_allocate_memory(struct ISCI_CONTROLLER *controller) remote_device->frozen_lun_mask = 0; sci_fast_list_element_init(remote_device, &remote_device->pending_device_reset_element); + TAILQ_INIT(&remote_device->queued_ccbs); /* * For the first SCI_MAX_DOMAINS device objects, do not put diff --git a/sys/dev/isci/isci_io_request.c b/sys/dev/isci/isci_io_request.c index b671e67..985a2e4 100644 --- a/sys/dev/isci/isci_io_request.c +++ b/sys/dev/isci/isci_io_request.c @@ -85,7 +85,9 @@ isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller, struct ISCI_CONTROLLER *isci_controller; struct ISCI_REMOTE_DEVICE *isci_remote_device; union ccb *ccb; + BOOL complete_ccb; + complete_ccb = TRUE; isci_controller = (struct ISCI_CONTROLLER *) sci_object_get_association(scif_controller); isci_remote_device = (struct ISCI_REMOTE_DEVICE *) sci_object_get_association(remote_device); @@ -163,9 +165,7 @@ isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller, case SCI_IO_FAILURE_INVALID_STATE: case SCI_IO_FAILURE_INSUFFICIENT_RESOURCES: - ccb->ccb_h.status |= CAM_REQUEUE_REQ; - isci_remote_device_freeze_lun_queue(isci_remote_device, - ccb->ccb_h.target_lun); + complete_ccb = FALSE; break; case SCI_IO_FAILURE_INVALID_REMOTE_DEVICE: @@ -189,7 +189,7 @@ isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller, scif_remote_device_get_max_queue_depth(remote_device); xpt_action((union ccb *)&ccb_relsim); xpt_free_path(path); - ccb->ccb_h.status |= CAM_REQUEUE_REQ; + complete_ccb = FALSE; } break; @@ -209,17 +209,6 @@ isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller, break; } - if (ccb->ccb_h.status != CAM_REQ_CMP) { - /* ccb will be completed with some type of non-success - * status. So temporarily freeze the queue until the - * upper layers can act on the status. The CAM_DEV_QFRZN - * flag will then release the queue after the status is - * acted upon. - */ - ccb->ccb_h.status |= CAM_DEV_QFRZN; - xpt_freeze_devq(ccb->ccb_h.path, 1); - } - callout_stop(&isci_request->parent.timer); bus_dmamap_sync(isci_request->parent.dma_tag, isci_request->parent.dma_map, @@ -228,20 +217,43 @@ isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller, bus_dmamap_unload(isci_request->parent.dma_tag, isci_request->parent.dma_map); - if (isci_remote_device->frozen_lun_mask != 0 && - !(ccb->ccb_h.status & CAM_REQUEUE_REQ)) - isci_remote_device_release_device_queue(isci_remote_device); - - xpt_done(ccb); isci_request->ccb = NULL; - if (isci_controller->is_frozen == TRUE) { - isci_controller->is_frozen = FALSE; - xpt_release_simq(isci_controller->sim, TRUE); - } - sci_pool_put(isci_controller->request_pool, (struct ISCI_REQUEST *)isci_request); + + if (complete_ccb) { + if (ccb->ccb_h.status != CAM_REQ_CMP) { + /* ccb will be completed with some type of non-success + * status. So temporarily freeze the queue until the + * upper layers can act on the status. The + * CAM_DEV_QFRZN flag will then release the queue + * after the status is acted upon. + */ + ccb->ccb_h.status |= CAM_DEV_QFRZN; + xpt_freeze_devq(ccb->ccb_h.path, 1); + } + + if (isci_remote_device->frozen_lun_mask != 0) { + isci_remote_device_release_device_queue(isci_remote_device); + } + + xpt_done(ccb); + + if (isci_controller->is_frozen == TRUE) { + isci_controller->is_frozen = FALSE; + xpt_release_simq(isci_controller->sim, TRUE); + } + } else { + isci_remote_device_freeze_lun_queue(isci_remote_device, + ccb->ccb_h.target_lun); + + isci_log_message(1, "ISCI", "queue %p %x\n", ccb, + ccb->csio.cdb_io.cdb_bytes[0]); + ccb->ccb_h.status |= CAM_SIM_QUEUED; + TAILQ_INSERT_TAIL(&isci_remote_device->queued_ccbs, + &ccb->ccb_h, sim_links.tqe); + } } /** diff --git a/sys/dev/isci/isci_remote_device.c b/sys/dev/isci/isci_remote_device.c index d22b4d4..c9434f8 100644 --- a/sys/dev/isci/isci_remote_device.c +++ b/sys/dev/isci/isci_remote_device.c @@ -289,9 +289,22 @@ isci_remote_device_release_lun_queue(struct ISCI_REMOTE_DEVICE *remote_device, void isci_remote_device_release_device_queue( - struct ISCI_REMOTE_DEVICE *remote_device) + struct ISCI_REMOTE_DEVICE *device) { - lun_id_t lun; - for (lun = 0; lun < ISCI_MAX_LUN; lun++) - isci_remote_device_release_lun_queue(remote_device, lun); + if (TAILQ_EMPTY(&device->queued_ccbs)) { + lun_id_t lun; + + for (lun = 0; lun < ISCI_MAX_LUN; lun++) + isci_remote_device_release_lun_queue(device, lun); + } else { + struct ccb_hdr *ccb_h; + + ccb_h = TAILQ_FIRST(&device->queued_ccbs); + TAILQ_REMOVE(&device->queued_ccbs, ccb_h, sim_links.tqe); + ccb_h->status &= ~CAM_SIM_QUEUED; + isci_log_message(1, "ISCI", "release %p %x\n", ccb_h, + ((union ccb*)ccb_h)->csio.cdb_io.cdb_bytes[0]); + isci_io_request_execute_scsi_io((union ccb *)ccb_h, + device->domain->controller); + } } |