Author: marius
Date: Thu May 15 09:55:21 2014
New Revision: 266118
URL: http://svnweb.freebsd.org/changeset/base/266118

Log:
  Revert the following MFCs done as part of r265147:
  r249438, r249466, r249481, r250025, r253958
  leaving the MFCs of r241028 and r241444 in place. While the CAM queuing
  changes in question are pretty much self-contained and work fine with all
  kinds of SAS, SATA and USB devices, for reasons unknown they cause a hang
  with Initio INIC-1610P USB disks not seen with later branches containing
  these rewrites. In turn, r241444 actually is sufficient to fix the panic
  and problems I was seeing and that lead me to bringing CAM queuing up to
  date.
  
  Reported by:  Scott Allendorf

Modified:
  stable/8/sys/cam/ata/ata_da.c
  stable/8/sys/cam/ata/ata_pmp.c
  stable/8/sys/cam/ata/ata_xpt.c
  stable/8/sys/cam/cam.h
  stable/8/sys/cam/cam_ccb.h
  stable/8/sys/cam/cam_periph.c
  stable/8/sys/cam/cam_periph.h
  stable/8/sys/cam/cam_queue.c
  stable/8/sys/cam/cam_queue.h
  stable/8/sys/cam/cam_xpt.c
  stable/8/sys/cam/cam_xpt_internal.h
  stable/8/sys/cam/cam_xpt_sim.h
  stable/8/sys/cam/scsi/scsi_cd.c
  stable/8/sys/cam/scsi/scsi_pass.c
  stable/8/sys/cam/scsi/scsi_xpt.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/cam/   (props changed)

Modified: stable/8/sys/cam/ata/ata_da.c
==============================================================================
--- stable/8/sys/cam/ata/ata_da.c       Thu May 15 05:35:00 2014        
(r266117)
+++ stable/8/sys/cam/ata/ata_da.c       Thu May 15 09:55:21 2014        
(r266118)
@@ -978,6 +978,8 @@ adaasync(void *callback_arg, u_int32_t c
                else
                    break;
                cam_periph_acquire(periph);
+               cam_freeze_devq_arg(periph->path,
+                   RELSIM_RELEASE_RUNLEVEL, CAM_RL_DEV + 1);
                xpt_schedule(periph, CAM_PRIORITY_DEV);
        }
        default:
@@ -1273,11 +1275,15 @@ adaregister(struct cam_periph *periph, v
            cgd->ident_data.support.command1 & ATA_SUPPORT_LOOKAHEAD) {
                softc->state = ADA_STATE_RAHEAD;
                cam_periph_acquire(periph);
+               cam_freeze_devq_arg(periph->path,
+                   RELSIM_RELEASE_RUNLEVEL, CAM_RL_DEV + 1);
                xpt_schedule(periph, CAM_PRIORITY_DEV);
        } else if (ADA_WC >= 0 &&
            cgd->ident_data.support.command1 & ATA_SUPPORT_WRITECACHE) {
                softc->state = ADA_STATE_WCACHE;
                cam_periph_acquire(periph);
+               cam_freeze_devq_arg(periph->path,
+                   RELSIM_RELEASE_RUNLEVEL, CAM_RL_DEV + 1);
                xpt_schedule(periph, CAM_PRIORITY_DEV);
        } else
                softc->state = ADA_STATE_NORMAL;
@@ -1561,6 +1567,8 @@ out:
                if (softc->flags & ADA_FLAG_PACK_INVALID) {
                        softc->state = ADA_STATE_NORMAL;
                        xpt_release_ccb(start_ccb);
+                       cam_release_devq(periph->path,
+                           RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_DEV + 1, FALSE);
                        adaschedule(periph);
                        cam_periph_release_locked(periph);
                        return;
@@ -1584,7 +1592,6 @@ out:
                            ATA_SF_ENAB_WCACHE : ATA_SF_DIS_WCACHE, 0, 0);
                        start_ccb->ccb_h.ccb_state = ADA_CCB_WCACHE;
                }
-               start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
                xpt_action(start_ccb);
                break;
        }
@@ -1597,13 +1604,11 @@ adadone(struct cam_periph *periph, union
        struct ada_softc *softc;
        struct ccb_ataio *ataio;
        struct ccb_getdev *cgd;
-       struct cam_path *path;
 
        softc = (struct ada_softc *)periph->softc;
        ataio = &done_ccb->ataio;
-       path = done_ccb->ccb_h.path;
 
-       CAM_DEBUG(path, CAM_DEBUG_TRACE, ("adadone\n"));
+       CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("adadone\n"));
 
        switch (ataio->ccb_h.ccb_state & ADA_CCB_TYPE_MASK) {
        case ADA_CCB_BUFFER_IO:
@@ -1631,7 +1636,8 @@ adadone(struct cam_periph *periph, union
                                         * XXX See if this is really a media
                                         * XXX change first?
                                         */
-                                       xpt_print(path, "Invalidating pack\n");
+                                       xpt_print(periph->path,
+                                           "Invalidating pack\n");
                                        softc->flags |= ADA_FLAG_PACK_INVALID;
                                }
                                bp->bio_error = error;
@@ -1644,7 +1650,7 @@ adadone(struct cam_periph *periph, union
                                        bp->bio_flags |= BIO_ERROR;
                        }
                        if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0)
-                               cam_release_devq(path,
+                               cam_release_devq(done_ccb->ccb_h.path,
                                                 /*relsim_flags*/0,
                                                 /*reduction*/0,
                                                 /*timeout*/0,
@@ -1685,12 +1691,9 @@ adadone(struct cam_periph *periph, union
        {
                if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
                        if (adaerror(done_ccb, 0, 0) == ERESTART) {
-out:
-                               /* Drop freeze taken due to CAM_DEV_QFREEZE */
-                               cam_release_devq(path, 0, 0, 0, FALSE);
                                return;
                        } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 
0) {
-                               cam_release_devq(path,
+                               cam_release_devq(done_ccb->ccb_h.path,
                                    /*relsim_flags*/0,
                                    /*reduction*/0,
                                    /*timeout*/0,
@@ -1707,7 +1710,7 @@ out:
                 * operation.
                 */
                cgd = (struct ccb_getdev *)done_ccb;
-               xpt_setup_ccb(&cgd->ccb_h, path, CAM_PRIORITY_NORMAL);
+               xpt_setup_ccb(&cgd->ccb_h, periph->path, CAM_PRIORITY_NORMAL);
                cgd->ccb_h.func_code = XPT_GDEV_TYPE;
                xpt_action((union ccb *)cgd);
                if (ADA_WC >= 0 &&
@@ -1715,12 +1718,12 @@ out:
                        softc->state = ADA_STATE_WCACHE;
                        xpt_release_ccb(done_ccb);
                        xpt_schedule(periph, CAM_PRIORITY_DEV);
-                       goto out;
+                       return;
                }
                softc->state = ADA_STATE_NORMAL;
                xpt_release_ccb(done_ccb);
-               /* Drop freeze taken due to CAM_DEV_QFREEZE */
-               cam_release_devq(path, 0, 0, 0, FALSE);
+               cam_release_devq(periph->path,
+                   RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_DEV + 1, FALSE);
                adaschedule(periph);
                cam_periph_release_locked(periph);
                return;
@@ -1729,9 +1732,9 @@ out:
        {
                if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
                        if (adaerror(done_ccb, 0, 0) == ERESTART) {
-                               goto out;
+                               return;
                        } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 
0) {
-                               cam_release_devq(path,
+                               cam_release_devq(done_ccb->ccb_h.path,
                                    /*relsim_flags*/0,
                                    /*reduction*/0,
                                    /*timeout*/0,
@@ -1749,8 +1752,8 @@ out:
                 * operation.
                 */
                xpt_release_ccb(done_ccb);
-               /* Drop freeze taken due to CAM_DEV_QFREEZE */
-               cam_release_devq(path, 0, 0, 0, FALSE);
+               cam_release_devq(periph->path,
+                   RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_DEV + 1, FALSE);
                adaschedule(periph);
                cam_periph_release_locked(periph);
                return;

Modified: stable/8/sys/cam/ata/ata_pmp.c
==============================================================================
--- stable/8/sys/cam/ata/ata_pmp.c      Thu May 15 05:35:00 2014        
(r266117)
+++ stable/8/sys/cam/ata/ata_pmp.c      Thu May 15 09:55:21 2014        
(r266118)
@@ -193,7 +193,8 @@ pmpfreeze(struct cam_periph *periph, int
                    i, 0) == CAM_REQ_CMP) {
                        softc->frozen |= (1 << i);
                        xpt_acquire_device(dpath->device);
-                       cam_freeze_devq(dpath);
+                       cam_freeze_devq_arg(dpath,
+                           RELSIM_RELEASE_RUNLEVEL, CAM_RL_BUS + 1);
                        xpt_free_path(dpath);
                }
        }
@@ -214,7 +215,8 @@ pmprelease(struct cam_periph *periph, in
                    xpt_path_path_id(periph->path),
                    i, 0) == CAM_REQ_CMP) {
                        softc->frozen &= ~(1 << i);
-                       cam_release_devq(dpath, 0, 0, 0, FALSE);
+                       cam_release_devq(dpath,
+                           RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_BUS + 1, FALSE);
                        xpt_release_device(dpath->device);
                        xpt_free_path(dpath);
                }

Modified: stable/8/sys/cam/ata/ata_xpt.c
==============================================================================
--- stable/8/sys/cam/ata/ata_xpt.c      Thu May 15 05:35:00 2014        
(r266117)
+++ stable/8/sys/cam/ata/ata_xpt.c      Thu May 15 09:55:21 2014        
(r266118)
@@ -250,6 +250,12 @@ proberegister(struct cam_periph *periph,
                return (status);
        }
        CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe started\n"));
+
+       /*
+        * Ensure nobody slip in until probe finish.
+        */
+       cam_freeze_devq_arg(periph->path,
+           RELSIM_RELEASE_RUNLEVEL, CAM_RL_XPT + 1);
        probeschedule(periph);
        return(CAM_REQ_CMP);
 }
@@ -624,7 +630,6 @@ negotiate:
        default:
                panic("probestart: invalid action state 0x%x\n", softc->action);
        }
-       start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
        xpt_action(start_ccb);
 }
 
@@ -670,15 +675,12 @@ probedone(struct cam_periph *periph, uni
                                cam_error_print(done_ccb,
                                    CAM_ESF_ALL, CAM_EPF_ALL);
                        }
-               } else if (cam_periph_error(done_ccb, 0, 0, NULL) == ERESTART) {
-out:
-                       /* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */
-                       cam_release_devq(path, 0, 0, 0, FALSE);
+               } else if (cam_periph_error(done_ccb, 0, 0, NULL) == ERESTART)
                        return;
-               }
                if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) {
                        /* Don't wedge the queue */
-                       xpt_release_devq(path, /*count*/1, /*run_queue*/TRUE);
+                       xpt_release_devq(done_ccb->ccb_h.path, /*count*/1,
+                                        /*run_queue*/TRUE);
                }
                status = done_ccb->ccb_h.status & CAM_STATUS_MASK;
                if (softc->restart) {
@@ -771,7 +773,7 @@ noerror:
                }
                xpt_release_ccb(done_ccb);
                xpt_schedule(periph, priority);
-               goto out;
+               return;
        }
        case PROBE_IDENTIFY:
        {
@@ -806,7 +808,7 @@ noerror:
                        PROBE_SET_ACTION(softc, PROBE_SPINUP);
                        xpt_release_ccb(done_ccb);
                        xpt_schedule(periph, priority);
-                       goto out;
+                       return;
                }
                ident_buf = &path->device->ident_data;
                if ((periph->path->device->flags & CAM_DEV_UNCONFIGURED) == 0) {
@@ -879,7 +881,7 @@ noerror:
                PROBE_SET_ACTION(softc, PROBE_SETMODE);
                xpt_release_ccb(done_ccb);
                xpt_schedule(periph, priority);
-               goto out;
+               return;
        }
        case PROBE_SPINUP:
                if (bootverbose)
@@ -888,7 +890,7 @@ noerror:
                PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
                xpt_release_ccb(done_ccb);
                xpt_schedule(periph, priority);
-               goto out;
+               return;
        case PROBE_SETMODE:
                if (path->device->transport != XPORT_SATA)
                        goto notsata;
@@ -933,7 +935,7 @@ noerror:
                        PROBE_SET_ACTION(softc, PROBE_SETPM);
                        xpt_release_ccb(done_ccb);
                        xpt_schedule(periph, priority);
-                       goto out;
+                       return;
                }
                /* FALLTHROUGH */
        case PROBE_SETPM:
@@ -944,7 +946,7 @@ noerror:
                        PROBE_SET_ACTION(softc, PROBE_SETAPST);
                        xpt_release_ccb(done_ccb);
                        xpt_schedule(periph, priority);
-                       goto out;
+                       return;
                }
                /* FALLTHROUGH */
        case PROBE_SETAPST:
@@ -954,7 +956,7 @@ noerror:
                        PROBE_SET_ACTION(softc, PROBE_SETDMAAA);
                        xpt_release_ccb(done_ccb);
                        xpt_schedule(periph, priority);
-                       goto out;
+                       return;
                }
                /* FALLTHROUGH */
        case PROBE_SETDMAAA:
@@ -964,7 +966,7 @@ noerror:
                        PROBE_SET_ACTION(softc, PROBE_SETAN);
                        xpt_release_ccb(done_ccb);
                        xpt_schedule(periph, priority);
-                       goto out;
+                       return;
                }
                /* FALLTHROUGH */
        case PROBE_SETAN:
@@ -976,14 +978,15 @@ notsata:
                }
                xpt_release_ccb(done_ccb);
                xpt_schedule(periph, priority);
-               goto out;
+               return;
        case PROBE_SET_MULTI:
                if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
                        path->device->flags &= ~CAM_DEV_UNCONFIGURED;
                        xpt_acquire_device(path->device);
                        done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
                        xpt_action(done_ccb);
-                       xpt_async(AC_FOUND_DEVICE, path, done_ccb);
+                       xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path,
+                           done_ccb);
                }
                PROBE_SET_ACTION(softc, PROBE_DONE);
                break;
@@ -1018,7 +1021,7 @@ notsata:
                        PROBE_SET_ACTION(softc, PROBE_FULL_INQUIRY);
                        xpt_release_ccb(done_ccb);
                        xpt_schedule(periph, priority);
-                       goto out;
+                       return;
                }
 
                ata_device_transport(path);
@@ -1027,7 +1030,7 @@ notsata:
                        xpt_acquire_device(path->device);
                        done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
                        xpt_action(done_ccb);
-                       xpt_async(AC_FOUND_DEVICE, path, done_ccb);
+                       xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path, 
done_ccb);
                }
                PROBE_SET_ACTION(softc, PROBE_DONE);
                break;
@@ -1045,7 +1048,7 @@ notsata:
                PROBE_SET_ACTION(softc, PROBE_PM_PRV);
                xpt_release_ccb(done_ccb);
                xpt_schedule(periph, priority);
-               goto out;
+               return;
        case PROBE_PM_PRV:
                softc->pm_prv = (done_ccb->ataio.res.lba_high << 24) +
                    (done_ccb->ataio.res.lba_mid << 16) +
@@ -1094,11 +1097,12 @@ notsata:
                        xpt_acquire_device(path->device);
                        done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
                        xpt_action(done_ccb);
-                       xpt_async(AC_FOUND_DEVICE, path, done_ccb);
+                       xpt_async(AC_FOUND_DEVICE, done_ccb->ccb_h.path,
+                           done_ccb);
                } else {
                        done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
                        xpt_action(done_ccb);
-                       xpt_async(AC_SCSI_AEN, path, done_ccb);
+                       xpt_async(AC_SCSI_AEN, done_ccb->ccb_h.path, done_ccb);
                }
                PROBE_SET_ACTION(softc, PROBE_DONE);
                break;
@@ -1110,7 +1114,7 @@ done:
                softc->restart = 0;
                xpt_release_ccb(done_ccb);
                probeschedule(periph);
-               goto out;
+               return;
        }
        xpt_release_ccb(done_ccb);
        CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe completed\n"));
@@ -1120,9 +1124,9 @@ done:
                done_ccb->ccb_h.status = found ? CAM_REQ_CMP : CAM_REQ_CMP_ERR;
                xpt_done(done_ccb);
        }
-       /* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */
-       cam_release_devq(path, 0, 0, 0, FALSE);
        cam_periph_invalidate(periph);
+       cam_release_devq(periph->path,
+           RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_XPT + 1, FALSE);
        cam_periph_release_locked(periph);
 }
 

Modified: stable/8/sys/cam/cam.h
==============================================================================
--- stable/8/sys/cam/cam.h      Thu May 15 05:35:00 2014        (r266117)
+++ stable/8/sys/cam/cam.h      Thu May 15 09:55:21 2014        (r266118)
@@ -80,15 +80,15 @@ typedef struct {
 #define CAM_PRIORITY_BUS       ((CAM_RL_BUS << 8) + 0x80)
 #define CAM_PRIORITY_XPT       ((CAM_RL_XPT << 8) + 0x80)
 #define CAM_PRIORITY_DEV       ((CAM_RL_DEV << 8) + 0x80)
-#define CAM_PRIORITY_OOB       (CAM_RL_DEV << 8)
 #define CAM_PRIORITY_NORMAL    ((CAM_RL_NORMAL << 8) + 0x80)
 #define CAM_PRIORITY_NONE      (u_int32_t)-1
+#define CAM_PRIORITY_TO_RL(x)  ((x) >> 8)
+#define CAM_RL_TO_PRIORITY(x)  ((x) << 8)
        u_int32_t generation;
        int       index;
 #define CAM_UNQUEUED_INDEX     -1
 #define CAM_ACTIVE_INDEX       -2      
 #define CAM_DONEQ_INDEX                -3      
-#define CAM_EXTRAQ_INDEX       INT_MAX
 } cam_pinfo;
 
 /*

Modified: stable/8/sys/cam/cam_ccb.h
==============================================================================
--- stable/8/sys/cam/cam_ccb.h  Thu May 15 05:35:00 2014        (r266117)
+++ stable/8/sys/cam/cam_ccb.h  Thu May 15 09:55:21 2014        (r266118)
@@ -142,6 +142,8 @@ typedef enum {
                                /* Path statistics (error counts, etc.) */
        XPT_GDEV_STATS          = 0x0c,
                                /* Device statistics (error counts, etc.) */
+       XPT_FREEZE_QUEUE        = 0x0d,
+                               /* Freeze device queue */
 /* SCSI Control Functions: 0x10->0x1F */
        XPT_ABORT               = 0x10,
                                /* Abort the specified CCB */
@@ -698,6 +700,7 @@ struct ccb_relsim {
 #define RELSIM_RELEASE_AFTER_TIMEOUT   0x02
 #define RELSIM_RELEASE_AFTER_CMDCMPLT  0x04
 #define RELSIM_RELEASE_AFTER_QEMPTY    0x08
+#define RELSIM_RELEASE_RUNLEVEL                0x10
        u_int32_t      openings;
        u_int32_t      release_timeout; /* Abstract argument. */
        u_int32_t      qfrozen_cnt;

Modified: stable/8/sys/cam/cam_periph.c
==============================================================================
--- stable/8/sys/cam/cam_periph.c       Thu May 15 05:35:00 2014        
(r266117)
+++ stable/8/sys/cam/cam_periph.c       Thu May 15 09:55:21 2014        
(r266118)
@@ -998,12 +998,21 @@ cam_periph_runccb(union ccb *ccb,
 void
 cam_freeze_devq(struct cam_path *path)
 {
-       struct ccb_hdr ccb_h;
 
-       xpt_setup_ccb(&ccb_h, path, /*priority*/1);
-       ccb_h.func_code = XPT_NOOP;
-       ccb_h.flags = CAM_DEV_QFREEZE;
-       xpt_action((union ccb *)&ccb_h);
+       cam_freeze_devq_arg(path, 0, 0);
+}
+
+void
+cam_freeze_devq_arg(struct cam_path *path, uint32_t flags, uint32_t arg)
+{
+       struct ccb_relsim crs;
+
+       xpt_setup_ccb(&crs.ccb_h, path, CAM_PRIORITY_NONE);
+       crs.ccb_h.func_code = XPT_FREEZE_QUEUE;
+       crs.release_flags = flags;
+       crs.openings = arg;
+       crs.release_timeout = arg;
+       xpt_action((union ccb *)&crs);
 }
 
 u_int32_t

Modified: stable/8/sys/cam/cam_periph.h
==============================================================================
--- stable/8/sys/cam/cam_periph.h       Thu May 15 05:35:00 2014        
(r266117)
+++ stable/8/sys/cam/cam_periph.h       Thu May 15 09:55:21 2014        
(r266118)
@@ -169,6 +169,8 @@ int         cam_periph_ioctl(struct cam_periph 
                                                      cam_flags camflags,
                                                      u_int32_t sense_flags));
 void           cam_freeze_devq(struct cam_path *path);
+void           cam_freeze_devq_arg(struct cam_path *path, u_int32_t flags,
+                   uint32_t arg);
 u_int32_t      cam_release_devq(struct cam_path *path, u_int32_t relsim_flags,
                                 u_int32_t opening_reduction, u_int32_t arg,
                                 int getcount_only);

Modified: stable/8/sys/cam/cam_queue.c
==============================================================================
--- stable/8/sys/cam/cam_queue.c        Thu May 15 05:35:00 2014        
(r266117)
+++ stable/8/sys/cam/cam_queue.c        Thu May 15 09:55:21 2014        
(r266118)
@@ -230,8 +230,15 @@ int
 cam_devq_init(struct cam_devq *devq, int devices, int openings)
 {
        bzero(devq, sizeof(*devq));
-       if (camq_init(&devq->send_queue, devices) != 0)
+       if (camq_init(&devq->alloc_queue, devices) != 0) {
                return (1);
+       }
+       if (camq_init(&devq->send_queue, devices) != 0) {
+               camq_fini(&devq->alloc_queue);
+               return (1);
+       }
+       devq->alloc_openings = openings;
+       devq->alloc_active = 0;
        devq->send_openings = openings;
        devq->send_active = 0;  
        return (0);     
@@ -240,6 +247,7 @@ cam_devq_init(struct cam_devq *devq, int
 void
 cam_devq_free(struct cam_devq *devq)
 {
+       camq_fini(&devq->alloc_queue);
        camq_fini(&devq->send_queue);
        free(devq, M_CAMDEVQ);
 }
@@ -249,7 +257,11 @@ cam_devq_resize(struct cam_devq *camq, i
 {
        u_int32_t retval;
 
-       retval = camq_resize(&camq->send_queue, devices);
+       retval = camq_resize(&camq->alloc_queue, devices);
+
+       if (retval == CAM_REQ_CMP)
+               retval = camq_resize(&camq->send_queue, devices);
+
        return (retval);
 }
 
@@ -284,27 +296,43 @@ u_int32_t
 cam_ccbq_resize(struct cam_ccbq *ccbq, int new_size)
 {
        int delta;
+       int space_left;
 
        delta = new_size - (ccbq->dev_active + ccbq->dev_openings);
-       ccbq->devq_openings += delta;
-       ccbq->dev_openings += delta;
-
-       new_size = imax(64, 1 << fls(new_size + new_size / 2));
-       if (new_size > ccbq->queue.array_size)
-               return (camq_resize(&ccbq->queue, new_size));
-       else
+       space_left = new_size
+           - ccbq->queue.entries
+           - ccbq->held
+           - ccbq->dev_active;
+
+       /*
+        * Only attempt to change the underlying queue size if we are
+        * shrinking it and there is space for all outstanding entries
+        * in the new array or we have been requested to grow the array.
+        * We don't fail in the case where we can't reduce the array size,
+        * but clients that care that the queue be "garbage collected"
+        * should detect this condition and call us again with the
+        * same size once the outstanding entries have been processed.
+        */
+       if (space_left < 0
+        || camq_resize(&ccbq->queue, new_size + (CAM_RL_VALUES - 1)) ==
+           CAM_REQ_CMP) {
+               ccbq->devq_openings += delta;
+               ccbq->dev_openings += delta;
                return (CAM_REQ_CMP);
+       } else {
+               return (CAM_RESRC_UNAVAIL);
+       }
 }
 
 int
 cam_ccbq_init(struct cam_ccbq *ccbq, int openings)
 {
        bzero(ccbq, sizeof(*ccbq));
-       if (camq_init(&ccbq->queue,
-           imax(64, 1 << fls(openings + openings / 2))) != 0)
+       if (camq_init(&ccbq->queue, openings + (CAM_RL_VALUES - 1)) != 0) {
                return (1);
+       }
        ccbq->devq_openings = openings;
-       ccbq->dev_openings = openings;
+       ccbq->dev_openings = openings;  
        return (0);
 }
 

Modified: stable/8/sys/cam/cam_queue.h
==============================================================================
--- stable/8/sys/cam/cam_queue.h        Thu May 15 05:35:00 2014        
(r266117)
+++ stable/8/sys/cam/cam_queue.h        Thu May 15 09:55:21 2014        
(r266118)
@@ -48,7 +48,7 @@ struct camq {
        int        array_size;
        int        entries;
        u_int32_t  generation;
-       u_int32_t  qfrozen_cnt;
+       u_int32_t  qfrozen_cnt[CAM_RL_VALUES];
 };
 
 TAILQ_HEAD(ccb_hdr_tailq, ccb_hdr);
@@ -57,11 +57,8 @@ SLIST_HEAD(ccb_hdr_slist, ccb_hdr);
 
 struct cam_ccbq {
        struct  camq queue;
-       struct ccb_hdr_tailq    queue_extra_head;
-       int     queue_extra_entries;
        int     devq_openings;
-       int     devq_allocating;
-       int     dev_openings;
+       int     dev_openings;   
        int     dev_active;
        int     held;
 };
@@ -69,7 +66,11 @@ struct cam_ccbq {
 struct cam_ed;
 
 struct cam_devq {
+       struct  camq alloc_queue;
        struct  camq send_queue;
+       struct  cam_ed *active_dev;
+       int     alloc_openings;
+       int     alloc_active;
        int     send_openings;
        int     send_active;
 };
@@ -157,10 +158,10 @@ cam_ccbq_pending_ccb_count(struct cam_cc
 static __inline void
 cam_ccbq_take_opening(struct cam_ccbq *ccbq);
 
-static __inline void
+static __inline int
 cam_ccbq_insert_ccb(struct cam_ccbq *ccbq, union ccb *new_ccb);
 
-static __inline void
+static __inline int
 cam_ccbq_remove_ccb(struct cam_ccbq *ccbq, union ccb *ccb);
 
 static __inline union ccb *
@@ -179,7 +180,7 @@ cam_ccbq_release_opening(struct cam_ccbq
 static __inline int
 cam_ccbq_pending_ccb_count(struct cam_ccbq *ccbq)
 {
-       return (ccbq->queue.entries + ccbq->queue_extra_entries);
+       return (ccbq->queue.entries);
 }
 
 static __inline void
@@ -189,64 +190,31 @@ cam_ccbq_take_opening(struct cam_ccbq *c
        ccbq->held++;
 }
 
-static __inline void
+static __inline int
 cam_ccbq_insert_ccb(struct cam_ccbq *ccbq, union ccb *new_ccb)
 {
-       struct ccb_hdr *old_ccb;
-       struct camq *queue = &ccbq->queue;
-
        ccbq->held--;
-
-       /*
-        * If queue is already full, try to resize.
-        * If resize fail, push CCB with lowest priority out to the TAILQ.
-        */
-       if (queue->entries == queue->array_size &&
-           camq_resize(&ccbq->queue, queue->array_size * 2) != CAM_REQ_CMP) {
-               old_ccb = (struct ccb_hdr *)camq_remove(queue, queue->entries);
-               TAILQ_INSERT_HEAD(&ccbq->queue_extra_head, old_ccb,
-                   xpt_links.tqe);
-               old_ccb->pinfo.index = CAM_EXTRAQ_INDEX;
-               ccbq->queue_extra_entries++;
-       }
-
-       camq_insert(queue, &new_ccb->ccb_h.pinfo);
+       camq_insert(&ccbq->queue, &new_ccb->ccb_h.pinfo);
+       if (ccbq->queue.qfrozen_cnt[CAM_PRIORITY_TO_RL(
+           new_ccb->ccb_h.pinfo.priority)] > 0) {
+               ccbq->devq_openings++;
+               ccbq->held++;
+               return (1);
+       } else
+               return (0);
 }
 
-static __inline void
+static __inline int
 cam_ccbq_remove_ccb(struct cam_ccbq *ccbq, union ccb *ccb)
 {
-       struct ccb_hdr *cccb, *bccb;
-       struct camq *queue = &ccbq->queue;
-
-       /* If the CCB is on the TAILQ, remove it from there. */
-       if (ccb->ccb_h.pinfo.index == CAM_EXTRAQ_INDEX) {
-               TAILQ_REMOVE(&ccbq->queue_extra_head, &ccb->ccb_h,
-                   xpt_links.tqe);
-               ccb->ccb_h.pinfo.index = CAM_UNQUEUED_INDEX;
-               ccbq->queue_extra_entries--;
-               return;
-       }
-
-       camq_remove(queue, ccb->ccb_h.pinfo.index);
-
-       /*
-        * If there are some CCBs on TAILQ, find the best one and move it
-        * to the emptied space in the queue.
-        */
-       bccb = TAILQ_FIRST(&ccbq->queue_extra_head);
-       if (bccb == NULL)
-               return;
-       TAILQ_FOREACH(cccb, &ccbq->queue_extra_head, xpt_links.tqe) {
-               if (bccb->pinfo.priority > cccb->pinfo.priority ||
-                   (bccb->pinfo.priority == cccb->pinfo.priority &&
-                    GENERATIONCMP(bccb->pinfo.generation, >,
-                     cccb->pinfo.generation)))
-                       bccb = cccb;
-       }
-       TAILQ_REMOVE(&ccbq->queue_extra_head, bccb, xpt_links.tqe);
-       ccbq->queue_extra_entries--;
-       camq_insert(queue, &bccb->pinfo);
+       camq_remove(&ccbq->queue, ccb->ccb_h.pinfo.index);
+       if (ccbq->queue.qfrozen_cnt[CAM_PRIORITY_TO_RL(
+           ccb->ccb_h.pinfo.priority)] > 0) {
+               ccbq->devq_openings--;
+               ccbq->held--;
+               return (1);
+       } else
+               return (0);
 }
 
 static __inline union ccb *
@@ -280,5 +248,81 @@ cam_ccbq_release_opening(struct cam_ccbq
        ccbq->devq_openings++;
 }
 
+static __inline int
+cam_ccbq_freeze(struct cam_ccbq *ccbq, cam_rl rl, u_int32_t cnt)
+{
+       int i, frozen = 0;
+       cam_rl p, n;
+
+       /* Find pevious run level. */
+       for (p = 0; p < CAM_RL_VALUES && ccbq->queue.qfrozen_cnt[p] == 0; p++);
+       /* Find new run level. */
+       n = min(rl, p);
+       /* Apply new run level. */
+       for (i = rl; i < CAM_RL_VALUES; i++)
+               ccbq->queue.qfrozen_cnt[i] += cnt;
+       /* Update ccbq statistics. */
+       if (n == p)
+               return (0);
+       for (i = CAMQ_HEAD; i <= ccbq->queue.entries; i++) {
+               cam_rl rrl =
+                   CAM_PRIORITY_TO_RL(ccbq->queue.queue_array[i]->priority);
+               if (rrl < n)
+                       continue;
+               if (rrl >= p)
+                       break;
+               ccbq->devq_openings++;
+               ccbq->held++;
+               frozen++;
+       }
+       return (frozen);
+}
+
+static __inline int
+cam_ccbq_release(struct cam_ccbq *ccbq, cam_rl rl, u_int32_t cnt)
+{
+       int i, released = 0;
+       cam_rl p, n;
+
+       /* Apply new run level. */
+       for (i = rl; i < CAM_RL_VALUES; i++)
+               ccbq->queue.qfrozen_cnt[i] -= cnt;
+       /* Find new run level. */
+       for (n = 0; n < CAM_RL_VALUES && ccbq->queue.qfrozen_cnt[n] == 0; n++);
+       /* Find previous run level. */
+       p = min(rl, n);
+       /* Update ccbq statistics. */
+       if (n == p)
+               return (0);
+       for (i = CAMQ_HEAD; i <= ccbq->queue.entries; i++) {
+               cam_rl rrl =
+                   CAM_PRIORITY_TO_RL(ccbq->queue.queue_array[i]->priority);
+               if (rrl < p)
+                       continue;
+               if (rrl >= n)
+                       break;
+               ccbq->devq_openings--;
+               ccbq->held--;
+               released++;
+       }
+       return (released);
+}
+
+static __inline u_int32_t
+cam_ccbq_frozen(struct cam_ccbq *ccbq, cam_rl rl)
+{
+       
+       return (ccbq->queue.qfrozen_cnt[rl]);
+}
+
+static __inline u_int32_t
+cam_ccbq_frozen_top(struct cam_ccbq *ccbq)
+{
+       cam_rl rl;
+       
+       rl = CAM_PRIORITY_TO_RL(CAMQ_GET_PRIO(&ccbq->queue));
+       return (ccbq->queue.qfrozen_cnt[rl]);
+}
+
 #endif /* _KERNEL */
 #endif  /* _CAM_CAM_QUEUE_H */

Modified: stable/8/sys/cam/cam_xpt.c
==============================================================================
--- stable/8/sys/cam/cam_xpt.c  Thu May 15 05:35:00 2014        (r266117)
+++ stable/8/sys/cam/cam_xpt.c  Thu May 15 09:55:21 2014        (r266118)
@@ -96,7 +96,7 @@ struct xpt_softc {
        u_int32_t               xpt_generation;
 
        /* number of high powered commands that can go through right now */
-       STAILQ_HEAD(highpowerlist, cam_ed)      highpowerq;
+       STAILQ_HEAD(highpowerlist, ccb_hdr)     highpowerq;
        int                     num_highpower;
 
        /* queue for handling async rescan requests. */
@@ -221,13 +221,13 @@ static void               xpt_async_bcast(struct asyn
 static path_id_t xptnextfreepathid(void);
 static path_id_t xptpathid(const char *sim_name, int sim_unit, int sim_bus);
 static union ccb *xpt_get_ccb(struct cam_ed *device);
-static void     xpt_run_dev_allocq(struct cam_ed *device);
-static void     xpt_run_devq(struct cam_devq *devq);
+static void     xpt_run_dev_allocq(struct cam_eb *bus);
+static void     xpt_run_dev_sendq(struct cam_eb *bus);
 static timeout_t xpt_release_devq_timeout;
 static void     xpt_release_simq_timeout(void *arg) __unused;
 static void     xpt_release_bus(struct cam_eb *bus);
-static void     xpt_release_devq_device(struct cam_ed *dev, u_int count,
-                   int run_queue);
+static void     xpt_release_devq_device(struct cam_ed *dev, cam_rl rl,
+                   u_int count, int run_queue);
 static struct cam_et*
                 xpt_alloc_target(struct cam_eb *bus, target_id_t target_id);
 static void     xpt_release_target(struct cam_et *target);
@@ -297,24 +297,49 @@ static xpt_busfunc_t      xptsetasyncbusfunc;
 static cam_status      xptregister(struct cam_periph *periph,
                                    void *arg);
 static __inline int periph_is_queued(struct cam_periph *periph);
-static __inline int device_is_queued(struct cam_ed *device);
+static __inline int device_is_alloc_queued(struct cam_ed *device);
+static __inline int device_is_send_queued(struct cam_ed *device);
 
 static __inline int
-xpt_schedule_devq(struct cam_devq *devq, struct cam_ed *dev)
+xpt_schedule_dev_allocq(struct cam_eb *bus, struct cam_ed *dev)
+{
+       int retval;
+
+       if ((dev->drvq.entries > 0) &&
+           (dev->ccbq.devq_openings > 0) &&
+           (cam_ccbq_frozen(&dev->ccbq, CAM_PRIORITY_TO_RL(
+               CAMQ_GET_PRIO(&dev->drvq))) == 0)) {
+               /*
+                * The priority of a device waiting for CCB resources
+                * is that of the highest priority peripheral driver
+                * enqueued.
+                */
+               retval = xpt_schedule_dev(&bus->sim->devq->alloc_queue,
+                                         &dev->alloc_ccb_entry.pinfo,
+                                         CAMQ_GET_PRIO(&dev->drvq));
+       } else {
+               retval = 0;
+       }
+
+       return (retval);
+}
+
+static __inline int
+xpt_schedule_dev_sendq(struct cam_eb *bus, struct cam_ed *dev)
 {
        int     retval;
 
        if ((dev->ccbq.queue.entries > 0) &&
            (dev->ccbq.dev_openings > 0) &&
-           (dev->ccbq.queue.qfrozen_cnt == 0)) {
+           (cam_ccbq_frozen_top(&dev->ccbq) == 0)) {
                /*
                 * The priority of a device waiting for controller
                 * resources is that of the highest priority CCB
                 * enqueued.
                 */
                retval =
-                   xpt_schedule_dev(&devq->send_queue,
-                                    &dev->devq_entry.pinfo,
+                   xpt_schedule_dev(&bus->sim->devq->send_queue,
+                                    &dev->send_ccb_entry.pinfo,
                                     CAMQ_GET_PRIO(&dev->ccbq.queue));
        } else {
                retval = 0;
@@ -329,9 +354,15 @@ periph_is_queued(struct cam_periph *peri
 }
 
 static __inline int
-device_is_queued(struct cam_ed *device)
+device_is_alloc_queued(struct cam_ed *device)
 {
-       return (device->devq_entry.pinfo.index != CAM_UNQUEUED_INDEX);
+       return (device->alloc_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX);
+}
+
+static __inline int
+device_is_send_queued(struct cam_ed *device)
+{
+       return (device->send_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX);
 }
 
 static void
@@ -2456,10 +2487,17 @@ xpt_action_default(union ccb *start_ccb)
                /* FALLTHROUGH */
        case XPT_RESET_DEV:
        case XPT_ENG_EXEC:
-               cam_ccbq_insert_ccb(&path->device->ccbq, start_ccb);
-               if (xpt_schedule_devq(path->bus->sim->devq, path->device))
-                       xpt_run_devq(path->bus->sim->devq);
+       {
+               int frozen;
+
+               frozen = cam_ccbq_insert_ccb(&path->device->ccbq, start_ccb);
+               path->device->sim->devq->alloc_openings += frozen;
+               if (frozen > 0)
+                       xpt_run_dev_allocq(path->bus);
+               if (xpt_schedule_dev_sendq(path->bus, path->device))
+                       xpt_run_dev_sendq(path->bus);
                break;
+       }
        case XPT_CALC_GEOMETRY:
        {
                struct cam_sim *sim;
@@ -2508,7 +2546,8 @@ xpt_action_default(union ccb *start_ccb)
 
                                device = abort_ccb->ccb_h.path->device;
                                ccbq = &device->ccbq;
-                               cam_ccbq_remove_ccb(ccbq, abort_ccb);
+                               device->sim->devq->alloc_openings -= 
+                                   cam_ccbq_remove_ccb(ccbq, abort_ccb);
                                abort_ccb->ccb_h.status =
                                    CAM_REQ_ABORTED|CAM_DEV_QFRZN;
                                xpt_freeze_devq(abort_ccb->ccb_h.path, 1);
@@ -2616,7 +2655,7 @@ xpt_action_default(union ccb *start_ccb)
                        cgds->dev_openings = dev->ccbq.dev_openings;
                        cgds->dev_active = dev->ccbq.dev_active;
                        cgds->devq_openings = dev->ccbq.devq_openings;
-                       cgds->devq_queued = 
cam_ccbq_pending_ccb_count(&dev->ccbq);
+                       cgds->devq_queued = dev->ccbq.queue.entries;
                        cgds->held = dev->ccbq.held;
                        cgds->last_reset = tar->last_reset;
                        cgds->maxtags = dev->maxtags;
@@ -2883,9 +2922,13 @@ xpt_action_default(union ccb *start_ccb)
                        }
                }
 
-               if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) == 0)
-                       xpt_release_devq(path, /*count*/1, /*run_queue*/TRUE);
-               start_ccb->crs.qfrozen_cnt = dev->ccbq.queue.qfrozen_cnt;
+               if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) == 0) {
+                       xpt_release_devq_rl(path, /*runlevel*/
+                           (crs->release_flags & RELSIM_RELEASE_RUNLEVEL) ?
+                               crs->release_timeout : 0,
+                           /*count*/1, /*run_queue*/TRUE);
+               }
+               start_ccb->crs.qfrozen_cnt = dev->ccbq.queue.qfrozen_cnt[0];
                start_ccb->ccb_h.status = CAM_REQ_CMP;
                break;
        }
@@ -2920,6 +2963,16 @@ xpt_action_default(union ccb *start_ccb)
                }
                break;
        }
+       case XPT_FREEZE_QUEUE:
+       {
+               struct ccb_relsim *crs = &start_ccb->crs;
+
+               xpt_freeze_devq_rl(path, /*runlevel*/
+                   (crs->release_flags & RELSIM_RELEASE_RUNLEVEL) ?
+                   crs->release_timeout : 0, /*count*/1);
+               start_ccb->ccb_h.status = CAM_REQ_CMP;
+               break;
+       }
        case XPT_NOOP:
                if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) != 0)
                        xpt_freeze_devq(path, 1);
@@ -3023,7 +3076,7 @@ xpt_schedule(struct cam_periph *perph, u
                        camq_change_priority(&device->drvq,
                                             perph->pinfo.index,
                                             new_priority);
-                       runq = 1;
+                       runq = xpt_schedule_dev_allocq(perph->path->bus, 
device);
                }
        } else {
                /* New entry on the queue */
@@ -3032,12 +3085,12 @@ xpt_schedule(struct cam_periph *perph, u
                perph->pinfo.priority = new_priority;
                perph->pinfo.generation = ++device->drvq.generation;
                camq_insert(&device->drvq, &perph->pinfo);
-               runq = 1;
+               runq = xpt_schedule_dev_allocq(perph->path->bus, device);
        }
        if (runq != 0) {
                CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE,
-                         ("   calling xpt_run_dev_allocq\n"));
-               xpt_run_dev_allocq(device);
+                         ("   calling xpt_run_devq\n"));
+               xpt_run_dev_allocq(perph->path->bus);
        }
 }
 
@@ -3090,25 +3143,43 @@ xpt_schedule_dev(struct camq *queue, cam
 }
 
 static void
-xpt_run_dev_allocq(struct cam_ed *device)
+xpt_run_dev_allocq(struct cam_eb *bus)
 {
-       struct camq     *drvq;
+       struct  cam_devq *devq;
 
-       if (device->ccbq.devq_allocating)
-               return;
-       device->ccbq.devq_allocating = 1;
-       CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_run_dev_allocq(%p)\n", device));
-       drvq = &device->drvq;
-       while ((drvq->entries > 0) &&
-           (device->ccbq.devq_openings > 0 ||
-            CAMQ_GET_PRIO(drvq) <= CAM_PRIORITY_OOB) &&
-           (device->ccbq.queue.qfrozen_cnt == 0)) {
+       CAM_DEBUG_PRINT(CAM_DEBUG_XPT, ("xpt_run_dev_allocq\n"));
+       devq = bus->sim->devq;
+
+       CAM_DEBUG_PRINT(CAM_DEBUG_XPT,
+                       ("   qfrozen_cnt == 0x%x, entries == %d, "
+                        "openings == %d, active == %d\n",
+                        devq->alloc_queue.qfrozen_cnt[0],
+                        devq->alloc_queue.entries,
+                        devq->alloc_openings,
+                        devq->alloc_active));
+
+       devq->alloc_queue.qfrozen_cnt[0]++;
+       while ((devq->alloc_queue.entries > 0)
+           && (devq->alloc_openings > 0)
+           && (devq->alloc_queue.qfrozen_cnt[0] <= 1)) {
+               struct  cam_ed_qinfo *qinfo;
+               struct  cam_ed *device;
                union   ccb *work_ccb;
                struct  cam_periph *drv;
+               struct  camq *drvq;
+
+               qinfo = (struct cam_ed_qinfo *)camq_remove(&devq->alloc_queue,
+                                                          CAMQ_HEAD);
+               device = qinfo->device;
+               CAM_DEBUG_PRINT(CAM_DEBUG_XPT,
+                               ("running device %p\n", device));
 

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to