Author: jimharris
Date: Tue Apr 10 16:33:19 2012
New Revision: 234106
URL: http://svn.freebsd.org/changeset/base/234106

Log:
  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

Modified:
  head/sys/dev/isci/isci.h
  head/sys/dev/isci/isci_controller.c
  head/sys/dev/isci/isci_io_request.c
  head/sys/dev/isci/isci_remote_device.c

Modified: head/sys/dev/isci/isci.h
==============================================================================
--- head/sys/dev/isci/isci.h    Tue Apr 10 16:08:46 2012        (r234105)
+++ head/sys/dev/isci/isci.h    Tue Apr 10 16:33:19 2012        (r234106)
@@ -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 {

Modified: head/sys/dev/isci/isci_controller.c
==============================================================================
--- head/sys/dev/isci/isci_controller.c Tue Apr 10 16:08:46 2012        
(r234105)
+++ head/sys/dev/isci/isci_controller.c Tue Apr 10 16:33:19 2012        
(r234106)
@@ -430,6 +430,7 @@ int isci_controller_allocate_memory(stru
                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

Modified: head/sys/dev/isci/isci_io_request.c
==============================================================================
--- head/sys/dev/isci/isci_io_request.c Tue Apr 10 16:08:46 2012        
(r234105)
+++ head/sys/dev/isci/isci_io_request.c Tue Apr 10 16:33:19 2012        
(r234106)
@@ -85,7 +85,9 @@ isci_io_request_complete(SCI_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_
 
        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_
                            
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_
                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_
        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);
+       }
 }
 
 /**

Modified: head/sys/dev/isci/isci_remote_device.c
==============================================================================
--- head/sys/dev/isci/isci_remote_device.c      Tue Apr 10 16:08:46 2012        
(r234105)
+++ head/sys/dev/isci/isci_remote_device.c      Tue Apr 10 16:33:19 2012        
(r234106)
@@ -289,9 +289,22 @@ isci_remote_device_release_lun_queue(str
 
 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);
+       }
 }
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to