Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 9 Jan 2010 18:51:06 GMT
From:      Alexander Motin <mav@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 172860 for review
Message-ID:  <201001091851.o09Ip6LS003835@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/chv.cgi?CH=172860

Change 172860 by mav@mav_mavtest on 2010/01/09 18:50:43

	Improve device queue freezeing. Improvement consists of two parts:
	- Add support for multiple freeze levels (run levels). Freeze with
	level X blocks execution of requests with priority of X00h and bigger.
	Requests with priorities numerically less then X00h are allowed.
	This allows, for example, to delay regular requests until device
	initialization or complicated error recovery will be completed.
	For now I've defined such levels:
		CAM_RL_NORMAL - regular payload requests,
		CAM_RL_DEV - device driver level (cache control, ...),
		CAM_RL_XPT - XPT level (probing, transfer negotiation),
		CAM_RL_BUS - BUS level (bus topology management),
		CAM_RL_HOST - absolute priority (no requests use this).
	- To avoid deadlocks, when frozen regular low-priority requests
	block high-priority managemen request, which need to be run first, 
	exclude frozen requests from allocation busy counters. On release
	these counters are restored. It may cause a bit more requests to be
	allocated then device can handle simultanously, but there is no
	problem, as send counters are working as before and will control it.
	
	All together this allows to correctly recover from SATA hard reset
	in complicated environment with Port Multiplier used. It works in
	that way:
	- Hard reset happens for some reason, like command timeout,
	- XPT receives Reset Async event and freezes PMP management device,
	- PMP driver receives Reset Async event and freezes child devices,
	- device drivers receive Reset Async event and freeze their devices,
	- everything is stalled, ready to unwind levels one by one,
	- XPT completes probe sequence for PMP control device and releases it,
	- PMP driver initializes Multiplier, enables it's ports, runs probe
	sequences for child devices and releases them,
	- probe routines freeze devices from driver requests, proceed probe
	sequence, then release,
	- device drivers proceed initialization and release devices,
	- payload traffic is free to run! :)

Affected files ...

.. //depot/projects/scottl-camlock/src/sys/cam/ata/ata_da.c#47 edit
.. //depot/projects/scottl-camlock/src/sys/cam/ata/ata_pmp.c#26 edit
.. //depot/projects/scottl-camlock/src/sys/cam/ata/ata_xpt.c#67 edit
.. //depot/projects/scottl-camlock/src/sys/cam/cam.h#12 edit
.. //depot/projects/scottl-camlock/src/sys/cam/cam_ccb.h#37 edit
.. //depot/projects/scottl-camlock/src/sys/cam/cam_periph.c#45 edit
.. //depot/projects/scottl-camlock/src/sys/cam/cam_periph.h#24 edit
.. //depot/projects/scottl-camlock/src/sys/cam/cam_queue.h#7 edit
.. //depot/projects/scottl-camlock/src/sys/cam/cam_xpt.c#134 edit
.. //depot/projects/scottl-camlock/src/sys/cam/cam_xpt_internal.h#16 edit
.. //depot/projects/scottl-camlock/src/sys/cam/cam_xpt_sim.h#6 edit
.. //depot/projects/scottl-camlock/src/sys/cam/scsi/scsi_cd.c#36 edit
.. //depot/projects/scottl-camlock/src/sys/cam/scsi/scsi_low.c#18 edit
.. //depot/projects/scottl-camlock/src/sys/cam/scsi/scsi_xpt.c#26 edit

Differences ...

==== //depot/projects/scottl-camlock/src/sys/cam/ata/ata_da.c#47 (text+ko) ====

@@ -689,7 +689,7 @@
 
 	/* Check if the SIM does not want queued commands */
 	bzero(&cpi, sizeof(cpi));
-	xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
+	xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NONE);
 	cpi.ccb_h.func_code = XPT_PATH_INQ;
 	xpt_action((union ccb *)&cpi);
 	if (cpi.ccb_h.status != CAM_REQ_CMP ||

==== //depot/projects/scottl-camlock/src/sys/cam/ata/ata_pmp.c#26 (text+ko) ====

@@ -179,7 +179,8 @@
 		    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);
 		}
 	}
@@ -200,7 +201,8 @@
 		    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);
 		}
@@ -310,7 +312,7 @@
 		if (softc->state == PMP_STATE_NORMAL) {
 			softc->state = PMP_STATE_PORTS;
 			cam_periph_acquire(periph);
-			xpt_schedule(periph, CAM_PRIORITY_BUS);
+			xpt_schedule(periph, CAM_PRIORITY_DEV);
 		} else
 			softc->restart = 1;
 		break;
@@ -383,7 +385,7 @@
 
 	/* Check if the SIM does not want queued commands */
 	bzero(&cpi, sizeof(cpi));
-	xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
+	xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NONE);
 	cpi.ccb_h.func_code = XPT_PATH_INQ;
 	xpt_action((union ccb *)&cpi);
 
@@ -408,7 +410,7 @@
 	 * the end of probe.
 	 */
 	(void)cam_periph_acquire(periph);
-	xpt_schedule(periph, CAM_PRIORITY_BUS);
+	xpt_schedule(periph, CAM_PRIORITY_DEV);
 
 	return(CAM_REQ_CMP);
 }
@@ -436,7 +438,7 @@
 		    xpt_path_path_id(periph->path),
 		    softc->pm_step, 0) == CAM_REQ_CMP) {
 			bzero(&cts, sizeof(cts));
-			xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NORMAL);
+			xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NONE);
 			cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
 			cts.type = CTS_TYPE_USER_SETTINGS;
 			xpt_action((union ccb *)&cts);
@@ -539,7 +541,6 @@
 	struct ccb_trans_settings cts;
 	struct pmp_softc *softc;
 	struct ccb_ataio *ataio;
-	union ccb *work_ccb;
 	struct cam_path *path, *dpath;
 	u_int32_t  priority, res;
 
@@ -569,13 +570,11 @@
 		softc->restart = 0;
 		if (softc->state == PMP_STATE_SCAN) {
 			pmpfreeze(periph, 1 << softc->pm_step);
-			work_ccb = done_ccb;
-			done_ccb = (union ccb*)work_ccb->ccb_h.ppriv_ptr0;
 			/* Free the current request path- we're done with it. */
-		    	xpt_free_path(work_ccb->ccb_h.path);
-			xpt_free_ccb(work_ccb);
-		}
-		xpt_release_ccb(done_ccb);
+		    	xpt_free_path(done_ccb->ccb_h.path);
+			xpt_free_ccb(done_ccb);
+		} else
+			xpt_release_ccb(done_ccb);
 		softc->state = PMP_STATE_PORTS;
 		xpt_schedule(periph, priority);
 		return;
@@ -665,7 +664,7 @@
 			    xpt_path_path_id(periph->path),
 			    softc->pm_step, 0) == CAM_REQ_CMP) {
 				bzero(&cts, sizeof(cts));
-				xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NORMAL);
+				xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NONE);
 				cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
 				cts.type = CTS_TYPE_CURRENT_SETTINGS;
 				cts.xport_specific.sata.revision = (res & 0x0f0) >> 4;
@@ -728,17 +727,16 @@
 		if (softc->found) {
 			softc->pm_step = 0;
 			softc->state = PMP_STATE_SCAN;
-			work_ccb = xpt_alloc_ccb_nowait();
-			if (work_ccb != NULL)
-				goto do_scan;
 			xpt_release_ccb(done_ccb);
+			done_ccb = xpt_alloc_ccb_nowait();
+			if (done_ccb == NULL)
+				goto done1;
+			goto do_scan;
 		}
 		break;
 	case PMP_STATE_SCAN:
-		work_ccb = done_ccb;
-		done_ccb = (union ccb*)work_ccb->ccb_h.ppriv_ptr0;
 		/* Free the current request path- we're done with it. */
-		xpt_free_path(work_ccb->ccb_h.path);
+		xpt_free_path(done_ccb->ccb_h.path);
 		softc->pm_step++;
 do_scan:
 		while (softc->pm_step < softc->pm_ports &&
@@ -746,24 +744,22 @@
 			softc->pm_step++;
 		}
 		if (softc->pm_step >= softc->pm_ports) {
-			xpt_free_ccb(work_ccb);
-			break;
+			xpt_free_ccb(done_ccb);
+			goto done1;
 		}
 		if (xpt_create_path(&dpath, periph,
-		    done_ccb->ccb_h.path_id,
+		    xpt_path_path_id(periph->path),
 		    softc->pm_step, 0) != CAM_REQ_CMP) {
 			printf("pmpdone: xpt_create_path failed"
 			    ", bus scan halted\n");
-			xpt_free_ccb(work_ccb);
-			break;
+			xpt_free_ccb(done_ccb);
+			goto done1;
 		}
-		xpt_setup_ccb(&work_ccb->ccb_h, dpath,
-		    done_ccb->ccb_h.pinfo.priority);
-		work_ccb->ccb_h.func_code = XPT_SCAN_LUN;
-		work_ccb->ccb_h.cbfcnp = pmpdone;
-		work_ccb->ccb_h.ppriv_ptr0 = done_ccb;
-		work_ccb->crcn.flags = done_ccb->crcn.flags;
-		xpt_action(work_ccb);
+		xpt_setup_ccb(&done_ccb->ccb_h, dpath, CAM_PRIORITY_XPT);
+		done_ccb->ccb_h.func_code = XPT_SCAN_LUN;
+		done_ccb->ccb_h.cbfcnp = pmpdone;
+		done_ccb->crcn.flags = done_ccb->crcn.flags;
+		xpt_action(done_ccb);
 		pmprelease(periph, 1 << softc->pm_step);
 		return;
 	default:
@@ -771,6 +767,7 @@
 	}
 done:
 	xpt_release_ccb(done_ccb);
+done1:
 	softc->state = PMP_STATE_NORMAL;
 	pmprelease(periph, -1);
 	cam_periph_release_locked(periph);

==== //depot/projects/scottl-camlock/src/sys/cam/ata/ata_xpt.c#67 (text+ko) ====

@@ -232,7 +232,6 @@
 		return (status);
 	}
 
-
 	/*
 	 * Ensure we've waited at least a bus settle
 	 * delay before attempting to probe the device.
@@ -240,6 +239,11 @@
 	 */
 	cam_periph_freeze_after_event(periph, &periph->path->bus->last_reset,
 				      scsi_delay);
+	/*
+	 * 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);
 }
@@ -254,7 +258,7 @@
 	softc = (probe_softc *)periph->softc;
 	ccb = (union ccb *)TAILQ_FIRST(&softc->request_ccbs);
 
-	xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
+	xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NONE);
 	cpi.ccb_h.func_code = XPT_PATH_INQ;
 	xpt_action((union ccb *)&cpi);
 
@@ -269,7 +273,7 @@
 	else
 		softc->flags &= ~PROBE_NO_ANNOUNCE;
 
-	xpt_schedule(periph, CAM_PRIORITY_HOST);
+	xpt_schedule(periph, CAM_PRIORITY_XPT);
 }
 
 static void
@@ -339,7 +343,7 @@
 		mode = 0;
 		/* Fetch user modes from SIM. */
 		bzero(&cts, sizeof(cts));
-		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
 		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
 		cts.type = CTS_TYPE_USER_SETTINGS;
 		xpt_action((union ccb *)&cts);
@@ -355,7 +359,7 @@
 		wantmode = mode = ata_max_mode(ident_buf, mode);
 		/* Report modes to SIM. */
 		bzero(&cts, sizeof(cts));
-		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
 		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
 		cts.type = CTS_TYPE_CURRENT_SETTINGS;
 		if (path->device->transport == XPORT_ATA) {
@@ -368,7 +372,7 @@
 		xpt_action((union ccb *)&cts);
 		/* Fetch current modes from SIM. */
 		bzero(&cts, sizeof(cts));
-		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
 		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
 		cts.type = CTS_TYPE_CURRENT_SETTINGS;
 		xpt_action((union ccb *)&cts);
@@ -400,7 +404,7 @@
 		bytecount = 8192;	/* SATA maximum */
 		/* Fetch user bytecount from SIM. */
 		bzero(&cts, sizeof(cts));
-		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
 		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
 		cts.type = CTS_TYPE_USER_SETTINGS;
 		xpt_action((union ccb *)&cts);
@@ -416,7 +420,7 @@
 		    bytecount / ata_logical_sector_size(ident_buf)));
 		/* Report bytecount to SIM. */
 		bzero(&cts, sizeof(cts));
-		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
 		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
 		cts.type = CTS_TYPE_CURRENT_SETTINGS;
 		if (path->device->transport == XPORT_ATA) {
@@ -431,7 +435,7 @@
 		xpt_action((union ccb *)&cts);
 		/* Fetch current bytecount from SIM. */
 		bzero(&cts, sizeof(cts));
-		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
 		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
 		cts.type = CTS_TYPE_CURRENT_SETTINGS;
 		xpt_action((union ccb *)&cts);
@@ -462,7 +466,7 @@
 		bytecount = 8192;	/* SATA maximum */
 		/* Fetch user bytecount from SIM. */
 		bzero(&cts, sizeof(cts));
-		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
 		cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
 		cts.type = CTS_TYPE_USER_SETTINGS;
 		xpt_action((union ccb *)&cts);
@@ -482,7 +486,7 @@
 		}
 		/* Report bytecount to SIM. */
 		bzero(&cts, sizeof(cts));
-		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+		xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
 		cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
 		cts.type = CTS_TYPE_CURRENT_SETTINGS;
 		if (path->device->transport == XPORT_ATA) {
@@ -560,7 +564,7 @@
 {
 	struct ccb_trans_settings cts;
 
-	xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
+	xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE);
 	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
 	cts.type = CTS_TYPE_USER_SETTINGS;
 	xpt_action((union ccb *)&cts);
@@ -582,7 +586,7 @@
 	struct ccb_trans_settings_spi *spi;
 
 	memset(&cts, 0, sizeof (cts));
-	xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
+	xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE);
 	cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
 	cts.type = CTS_TYPE_CURRENT_SETTINGS;
 	xpt_action((union ccb *)&cts);
@@ -739,7 +743,7 @@
 		    done_ccb->ccb_h.target_id == 15) {
 			/* Report SIM that PM is present. */
 			bzero(&cts, sizeof(cts));
-			xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+			xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
 			cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
 			cts.type = CTS_TYPE_CURRENT_SETTINGS;
 			cts.xport_specific.sata.pm_present = 1;
@@ -836,7 +840,7 @@
 		    path->bus->sim->max_tagged_dev_openings != 0) {
 			/* Report SIM which tags are allowed. */
 			bzero(&cts, sizeof(cts));
-			xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+			xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
 			cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
 			cts.type = CTS_TYPE_CURRENT_SETTINGS;
 			cts.xport_specific.sata.tags = path->device->maxtags;
@@ -964,6 +968,8 @@
 	done_ccb->ccb_h.ppriv_field1 = found;
 	xpt_done(done_ccb);
 	if (TAILQ_FIRST(&softc->request_ccbs) == NULL) {
+		cam_release_devq(periph->path,
+		    RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_XPT + 1, FALSE);
 		cam_periph_invalidate(periph);
 		cam_periph_release_locked(periph);
 	} else {
@@ -1147,7 +1153,7 @@
 	CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE,
 		  ("xpt_scan_lun\n"));
 
-	xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL);
+	xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
 	cpi.ccb_h.func_code = XPT_PATH_INQ;
 	xpt_action((union ccb *)&cpi);
 
@@ -1185,7 +1191,7 @@
 			free(new_path, M_CAMXPT);
 			return;
 		}
-		xpt_setup_ccb(&request_ccb->ccb_h, new_path, CAM_PRIORITY_NORMAL);
+		xpt_setup_ccb(&request_ccb->ccb_h, new_path, CAM_PRIORITY_XPT);
 		request_ccb->ccb_h.cbfcnp = xptscandone;
 		request_ccb->ccb_h.func_code = XPT_SCAN_LUN;
 		request_ccb->crcn.flags = flags;
@@ -1284,7 +1290,7 @@
 	struct ata_params *ident_buf = NULL;
 
 	/* Get transport information from the SIM */
-	xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NORMAL);
+	xpt_setup_ccb(&cpi.ccb_h, path, CAM_PRIORITY_NONE);
 	cpi.ccb_h.func_code = XPT_PATH_INQ;
 	xpt_action((union ccb *)&cpi);
 
@@ -1304,7 +1310,7 @@
 	    ata_version(ident_buf->version_major) : cpi.transport_version;
 
 	/* Tell the controller what we think */
-	xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
+	xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NONE);
 	cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
 	cts.type = CTS_TYPE_CURRENT_SETTINGS;
 	cts.transport = path->device->transport;
@@ -1432,7 +1438,7 @@
 
 	inq_data = &device->inq_data;
 	scsi = &cts->proto_specific.scsi;
-	xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NORMAL);
+	xpt_setup_ccb(&cpi.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NONE);
 	cpi.ccb_h.func_code = XPT_PATH_INQ;
 	xpt_action((union ccb *)&cpi);
 
@@ -1453,7 +1459,7 @@
 		 * Perform sanity checking against what the
 		 * controller and device can do.
 		 */
-		xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NORMAL);
+		xpt_setup_ccb(&cur_cts.ccb_h, cts->ccb_h.path, CAM_PRIORITY_NONE);
 		cur_cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
 		cur_cts.type = cts->type;
 		xpt_action((union ccb *)&cur_cts);

==== //depot/projects/scottl-camlock/src/sys/cam/cam.h#12 (text+ko) ====

@@ -60,18 +60,29 @@
 struct cam_periph;
 
 /*
- * Priority information for a CAM structure.  The generation number is
- * incremented everytime a new entry is entered into the queue giving round
- * robin per priority level scheduling.
+ * Priority information for a CAM structure. 
+ */
+typedef enum {
+    CAM_RL_HOST,
+    CAM_RL_BUS,
+    CAM_RL_XPT,
+    CAM_RL_DEV,
+    CAM_RL_NORMAL,
+    CAM_RL_VALUES
+} cam_rl;
+/*
+ * The generation number is incremented everytime a new entry is entered into
+ * the queue giving round robin per priority level scheduling.
  */
 typedef struct {
 	u_int32_t priority;
-#define CAM_PRIORITY_HOST	100
-#define CAM_PRIORITY_BUS	200
-#define CAM_PRIORITY_DEV	300
-#define CAM_PRIORITY_HIGH	400
-#define CAM_PRIORITY_NORMAL	500
+#define CAM_PRIORITY_HOST	((CAM_RL_HOST << 8) + 0x80)
+#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_NORMAL	((CAM_RL_NORMAL << 8) + 0x80)
 #define CAM_PRIORITY_NONE	(u_int32_t)-1
+#define CAM_PRIORITY_TO_RL(x)	((x) >> 8)
 	u_int32_t generation;
 	int       index;
 #define CAM_UNQUEUED_INDEX	-1

==== //depot/projects/scottl-camlock/src/sys/cam/cam_ccb.h#37 (text+ko) ====

@@ -126,7 +126,7 @@
 	XPT_PATH_INQ		= 0x04,
 				/* Path routing inquiry */
 	XPT_REL_SIMQ		= 0x05,
-				/* Release a frozen SIM queue */
+				/* Release a frozen device queue */
 	XPT_SASYNC_CB		= 0x06,
 				/* Set Asynchronous Callback Parameters */
 	XPT_SDEV_TYPE		= 0x07,
@@ -142,6 +142,8 @@
 				/* 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 */
@@ -685,8 +687,9 @@
 #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;
+	u_int32_t      release_timeout;	/* Abstract argument. */
 	u_int32_t      qfrozen_cnt;
 };
 

==== //depot/projects/scottl-camlock/src/sys/cam/cam_periph.c#45 (text+ko) ====

@@ -950,17 +950,26 @@
 void
 cam_freeze_devq(struct cam_path *path)
 {
-	struct ccb_hdr 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(&ccb_h, path, CAM_PRIORITY_NORMAL);
-	ccb_h.func_code = XPT_NOOP;
-	ccb_h.flags = CAM_DEV_QFREEZE;
-	xpt_action((union ccb *)&ccb_h);
+	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
 cam_release_devq(struct cam_path *path, u_int32_t relsim_flags,
-		 u_int32_t openings, u_int32_t timeout,
+		 u_int32_t openings, u_int32_t arg,
 		 int getcount_only)
 {
 	struct ccb_relsim crs;
@@ -970,7 +979,7 @@
 	crs.ccb_h.flags = getcount_only ? CAM_DEV_QFREEZE : 0;
 	crs.release_flags = relsim_flags;
 	crs.openings = openings;
-	crs.release_timeout = timeout;
+	crs.release_timeout = arg;
 	xpt_action((union ccb *)&crs);
 	return (crs.qfrozen_cnt);
 }
@@ -1580,7 +1589,7 @@
 			 * the proper order before we release normal 
 			 * transactions to the device.
 			 */
-			ccb->ccb_h.pinfo.priority = CAM_PRIORITY_DEV;
+			ccb->ccb_h.pinfo.priority--;
 			ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
 			ccb->ccb_h.saved_ccb_ptr = save_ccb;
 			error = ERESTART;

==== //depot/projects/scottl-camlock/src/sys/cam/cam_periph.h#24 (text+ko) ====

@@ -165,8 +165,10 @@
 						      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 timeout,
+				 u_int32_t opening_reduction, u_int32_t arg,
 				 int getcount_only);
 void		cam_periph_async(struct cam_periph *periph, u_int32_t code,
 		 		 struct cam_path *path, void *arg);

==== //depot/projects/scottl-camlock/src/sys/cam/cam_queue.h#7 (text+ko) ====

@@ -34,6 +34,7 @@
 #ifdef _KERNEL
 
 #include <sys/queue.h>
+#include <cam/cam.h>
 
 /*
  * This structure implements a heap based priority queue.  The queue
@@ -47,7 +48,7 @@
 	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);
@@ -140,6 +141,10 @@
 /* Index the first element in the heap */
 #define CAMQ_GET_HEAD(camq) ((camq)->queue_array[CAMQ_HEAD])
 
+/* Get the first element priority. */
+#define CAMQ_GET_PRIO(camq) (((camq)->entries > 0) ?			\
+			    ((camq)->queue_array[CAMQ_HEAD]->priority) : 0)
+
 /*
  * camq_change_priority: Raise or lower the priority of an entry
  * maintaining queue order.
@@ -153,10 +158,10 @@
 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 *
@@ -185,17 +190,33 @@
 	ccbq->held++;
 }
 
-static __inline void
+static __inline int
 cam_ccbq_insert_ccb(struct cam_ccbq *ccbq, union ccb *new_ccb)
 {
 	ccbq->held--;
 	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->dev_openings++;
+		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)
 {
 	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->dev_openings--;
+		ccbq->devq_openings--;
+		ccbq->held--;
+		return (1);
+	} else
+		return (0);
 }
 
 static __inline union ccb *
@@ -229,5 +250,83 @@
 	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->dev_openings++;
+		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->dev_openings--;
+		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 */

==== //depot/projects/scottl-camlock/src/sys/cam/cam_xpt.c#134 (text+ko) ====

@@ -210,11 +210,12 @@
 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_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);
@@ -285,19 +286,19 @@
 static xpt_busfunc_t	xptsetasyncbusfunc;
 static cam_status	xptregister(struct cam_periph *periph,
 				    void *arg);
-static __inline int xpt_schedule_dev_allocq(struct cam_eb *bus,
-					    struct cam_ed *dev);
 static __inline int periph_is_queued(struct cam_periph *periph);
 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 dev_allocq_is_runnable(struct cam_devq *devq);
 
 static __inline int
 xpt_schedule_dev_allocq(struct cam_eb *bus, struct cam_ed *dev)
 {
 	int retval;
 
-	if (dev->ccbq.devq_openings > 0) {
+	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 the highest priority peripheral driver
@@ -305,7 +306,7 @@
 		 */
 		retval = xpt_schedule_dev(&bus->sim->devq->alloc_queue,
 					  &dev->alloc_ccb_entry.pinfo,
-					  CAMQ_GET_HEAD(&dev->drvq)->priority);
+					  CAMQ_GET_PRIO(&dev->drvq));
 	} else {
 		retval = 0;
 	}
@@ -318,7 +319,9 @@
 {
 	int	retval;
 
-	if (dev->ccbq.dev_openings > 0) {
+	if ((dev->ccbq.queue.entries > 0) &&
+	    (dev->ccbq.dev_openings > 0) &&
+	    (cam_ccbq_frozen_top(&dev->ccbq) == 0)) {
 		/*
 		 * The priority of a device waiting for controller
 		 * resources is that of the the highest priority CCB
@@ -327,7 +330,7 @@
 		retval =
 		    xpt_schedule_dev(&bus->sim->devq->send_queue,
 				     &dev->send_ccb_entry.pinfo,
-				     CAMQ_GET_HEAD(&dev->ccbq.queue)->priority);
+				     CAMQ_GET_PRIO(&dev->ccbq.queue));
 	} else {
 		retval = 0;
 	}
@@ -352,19 +355,6 @@
 	return (device->send_ccb_entry.pinfo.index != CAM_UNQUEUED_INDEX);
 }
 
-static __inline int
-dev_allocq_is_runnable(struct cam_devq *devq)
-{
-	/*
-	 * Have work to do.
-	 * Have space to do more work.
-	 * Allowed to do work.
-	 */
-	return ((devq->alloc_queue.qfrozen_cnt == 0)
-	     && (devq->alloc_queue.entries > 0)
-	     && (devq->alloc_openings > 0));
-}
-
 static void
 xpt_periph_init()
 {
@@ -852,7 +842,7 @@
 			else
 				ccb->ccb_h.func_code = XPT_SCAN_LUN;
 			ccb->ccb_h.cbfcnp = xptdone;
-			xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, CAM_PRIORITY_BUS);
+			xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, CAM_PRIORITY_XPT);
 			cam_periph_runccb(ccb, NULL, 0, 0, NULL);
 			xpt_free_path(ccb->ccb_h.path);
 			xpt_free_ccb(ccb);
@@ -2546,17 +2536,14 @@
 	case XPT_RESET_DEV:
 	case XPT_ENG_EXEC:
 	{
-		struct cam_path *path;
-		int runq;
+		struct cam_path *path = start_ccb->ccb_h.path;
+		int frozen;
 
-		path = start_ccb->ccb_h.path;
-
-		cam_ccbq_insert_ccb(&path->device->ccbq, start_ccb);
-		if (path->device->ccbq.queue.qfrozen_cnt == 0)
-			runq = xpt_schedule_dev_sendq(path->bus, path->device);
-		else
-			runq = 0;
-		if (runq != 0)
+		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;
 	}
@@ -2601,9 +2588,12 @@
 
 			if (abort_ccb->ccb_h.pinfo.index >= 0) {
 				struct cam_ccbq *ccbq;
+				struct cam_ed *device;
 
-				ccbq = &abort_ccb->ccb_h.path->device->ccbq;
-				cam_ccbq_remove_ccb(ccbq, abort_ccb);
+				device = abort_ccb->ccb_h.path->device;
+				ccbq = &device->ccbq;
+				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);
@@ -3008,11 +2998,12 @@
 		}
 
 		if ((start_ccb->ccb_h.flags & CAM_DEV_QFREEZE) == 0) {
-
-			xpt_release_devq(crs->ccb_h.path, /*count*/1,
-					 /*run_queue*/TRUE);
+			xpt_release_devq_rl(crs->ccb_h.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;
+		start_ccb->crs.qfrozen_cnt = dev->ccbq.queue.qfrozen_cnt[0];
 		start_ccb->ccb_h.status = CAM_REQ_CMP;
 		break;
 	}
@@ -3049,6 +3040,16 @@
 #endif /* CAMDEBUG */
 		break;
 	}
+	case XPT_FREEZE_QUEUE:
+	{
+		struct ccb_relsim *crs = &start_ccb->crs;
+
+		xpt_freeze_devq_rl(crs->ccb_h.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(start_ccb->ccb_h.path, 1);
@@ -3129,7 +3130,7 @@
 xpt_schedule(struct cam_periph *perph, u_int32_t new_priority)
 {
 	struct cam_ed *device;
-	int runq;
+	int runq = 0;
 
 	mtx_assert(perph->sim->mtx, MA_OWNED);
 
@@ -3144,7 +3145,6 @@
 					     perph->pinfo.index,
 					     new_priority);
 		}
-		runq = 0;
 	} else {
 		/* New entry on the queue */
 		CAM_DEBUG(perph->path, CAM_DEBUG_SUBTRACE,
@@ -3219,15 +3219,15 @@
 	CAM_DEBUG_PRINT(CAM_DEBUG_XPT,
 			("   qfrozen_cnt == 0x%x, entries == %d, "
 			 "openings == %d, active == %d\n",
-			 devq->alloc_queue.qfrozen_cnt,
+			 devq->alloc_queue.qfrozen_cnt[0],
 			 devq->alloc_queue.entries,
 			 devq->alloc_openings,
 			 devq->alloc_active));
 
-	devq->alloc_queue.qfrozen_cnt++;
+	devq->alloc_queue.qfrozen_cnt[0]++;
 	while ((devq->alloc_queue.entries > 0)
 	    && (devq->alloc_openings > 0)
-	    && (devq->alloc_queue.qfrozen_cnt <= 1)) {
+	    && (devq->alloc_queue.qfrozen_cnt[0] <= 1)) {
 		struct	cam_ed_qinfo *qinfo;
 		struct	cam_ed *device;
 		union	ccb *work_ccb;
@@ -3238,6 +3238,14 @@
 							   CAMQ_HEAD);
 		device = qinfo->device;
 
+		/*
+		 * If the device has been "frozen", don't attempt
+		 * to run it.
+		 */
+		if (cam_ccbq_frozen(&device->ccbq,
+		    CAM_PRIORITY_TO_RL(qinfo->pinfo.priority)) > 0)
+			continue;
+
 		CAM_DEBUG_PRINT(CAM_DEBUG_XPT,
 				("running device %p\n", device));
 
@@ -3271,15 +3279,13 @@
 			break;
 		}
 
-		if (drvq->entries > 0) {
-			/* We have more work.  Attempt to reschedule */
-			xpt_schedule_dev_allocq(bus, device);
-		}
+		/* We may have more work. Attempt to reschedule. */
+		xpt_schedule_dev_allocq(bus, device);
 	}
-	devq->alloc_queue.qfrozen_cnt--;
+	devq->alloc_queue.qfrozen_cnt[0]--;
 }
 
-void
+static void
 xpt_run_dev_sendq(struct cam_eb *bus)
 {
 	struct	cam_devq *devq;
@@ -3288,10 +3294,10 @@
 
 	devq = bus->sim->devq;
 
-	devq->send_queue.qfrozen_cnt++;
+	devq->send_queue.qfrozen_cnt[0]++;
 	while ((devq->send_queue.entries > 0)
 	    && (devq->send_openings > 0)
-	    && (devq->send_queue.qfrozen_cnt <= 1)) {
+	    && (devq->send_queue.qfrozen_cnt[0] <= 1)) {

>>> TRUNCATED FOR MAIL (1000 lines) <<<



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