summaryrefslogtreecommitdiffstats
path: root/sys/dev/isci
diff options
context:
space:
mode:
authorjimharris <jimharris@FreeBSD.org>2012-04-10 16:33:19 +0000
committerjimharris <jimharris@FreeBSD.org>2012-04-10 16:33:19 +0000
commit9daad3b04b7269c64f326876b55dac3ae0d7b844 (patch)
tree5e273e5e49ef5af0a3d25e0afdd915456b69098d /sys/dev/isci
parentc41a4a0d879c72675b7d273de7fc8a7e3e57dbd7 (diff)
downloadFreeBSD-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/isci')
-rw-r--r--sys/dev/isci/isci.h1
-rw-r--r--sys/dev/isci/isci_controller.c1
-rw-r--r--sys/dev/isci/isci_io_request.c62
-rw-r--r--sys/dev/isci/isci_remote_device.c21
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);
+ }
}
OpenPOWER on IntegriCloud