diff --git a/sys/dev/isci/isci.h b/sys/dev/isci/isci.h index 50f0236826e6..d6ad93cef067 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 851140063375..a4b7cfe9dae1 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 b671e67e950e..985a2e4b67a2 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 d22b4d4abff7..c9434f863261 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); + } }