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
This commit is contained in:
parent
0fec3e2d81
commit
cb77f0da67
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user