Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 15 May 2014 09:55:22 +0000 (UTC)
From:      Marius Strobl <marius@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r266118 - in stable/8/sys/cam: . ata scsi
Message-ID:  <201405150955.s4F9tMmh095603@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201405150955.s4F9tMmh095603>