Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 14 Nov 2006 08:33:58 GMT
From:      Matt Jacob <mjacob@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 109909 for review
Message-ID:  <200611140833.kAE8Xw0v065342@repoman.freebsd.org>

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

Change 109909 by mjacob@newisp on 2006/11/14 08:33:00

	More cleanup on initial startup conditions that have loop down.
	Clean up sleeping in isp_kthread. Add more ISP_LOGSANCFG lines.

Affected files ...

.. //depot/projects/newisp/dev/isp/isp_freebsd.c#27 edit

Differences ...

==== //depot/projects/newisp/dev/isp/isp_freebsd.c#27 (text+ko) ====

@@ -50,14 +50,15 @@
 int isp_fabric_hysteresis = 5;
 int isp_loop_down_limit = 300;	/* default loop down limit */
 int isp_change_is_bad = 0;	/* "changed" devices are bad */
-int isp_quickboot_time = 5;	/* don't wait more than N secs for loop up */
-int isp_gone_device_time = 60;	/* grace time before reporting device lost */
+int isp_quickboot_time = 15;	/* don't wait more than N secs for loop up */
+int isp_gone_device_time = 30;	/* grace time before reporting device lost */
 static const char *roles[4] = {
     "(none)", "Target", "Initiator", "Target/Initiator"
 };
 static const char prom3[] =
     "PortID 0x%06x Departed from Target %u because of %s";
 
+static void isp_freeze_loopdown(ispsoftc_t *, char *);
 static d_ioctl_t ispioctl;
 static void isp_intr_enable(void *);
 static void isp_cam_async(void *, uint32_t, struct cam_path *, void *);
@@ -180,7 +181,6 @@
 	if (IS_FC(isp)) {
 		ISPLOCK_2_CAMLOCK(isp);
 #if __FreeBSD_version >= 500000  
-		/* XXX: LOCK VIOLATION */
 		cv_init(&isp->isp_osinfo.kthread_cv, "isp_kthread_cv");
 		if (kthread_create(isp_kthread, isp, &isp->isp_osinfo.kproc,
 		    RFHIGHPID, 0, "%s: fc_thrd",
@@ -198,6 +198,17 @@
 			return;
 		}
 		CAMLOCK_2_ISPLOCK(isp);
+		/*
+		 * We start by being "loop down" if we have an initiator role
+		 */
+		if (isp->isp_role & ISP_ROLE_INITIATOR) {
+			isp_freeze_loopdown(isp, "isp_attach");
+			isp->isp_osinfo.ldt =
+			    timeout(isp_ldt, isp, isp_quickboot_time * hz);
+			isp->isp_osinfo.ldt_running = 1;
+			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
+			   "Starting Initial Loop Down Timer");
+		}
 	}
 
 
@@ -268,7 +279,7 @@
 	isp_sysctl_update(isp);
 }
 
-static __inline void
+static void
 isp_freeze_loopdown(ispsoftc_t *isp, char *msg)
 {
 	if (isp->isp_osinfo.simqfrozen == 0) {
@@ -661,11 +672,6 @@
 	       "World Wide Port Name");
 
 	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
-	    "loop_down_time",
-	    CTLFLAG_RD, &isp->isp_osinfo.loop_down_time, 0,
-	    "How long Loop has been down");
-
-	SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
 	    "loop_down_limit",
 	    CTLFLAG_RW, &isp->isp_osinfo.loop_down_limit, 0,
 	    "How long to wait for loop to come back up");
@@ -2226,7 +2232,7 @@
 	fcportdb_t *lp;
 	int dbidx, tgt;
 
-	isp_prt(isp, ISP_LOGDEBUG0, "LDT timer expired");
+	isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Loop Down Timer expired");
 	ISP_LOCK(isp);
 
 	/*
@@ -2265,13 +2271,29 @@
 		    "Loop Down Timeout");
 		isp_make_gone(isp, tgt);
 	}
+
+	/*
+	 * The loop down timer has expired. Wake up the kthread
+	 * to notice that fact (or make it false).
+	 */
+	isp->isp_osinfo.loop_down_time = isp->isp_osinfo.loop_down_limit+1;
+#if __FreeBSD_version < 500000  
+	wakeup(&isp->isp_osinfo.kproc);
+#else
+#ifdef	ISP_SMPLOCK
+	cv_signal(&isp->isp_osinfo.kthread_cv);
+#else
+	wakeup(&isp->isp_osinfo.kthread_cv);
+#endif
+#endif
+	ISP_UNLOCK(isp);
 }
 
 static void
 isp_kthread(void *arg)
 {
 	ispsoftc_t *isp = arg;
-	int slp;
+	int slp = 0;
 #if __FreeBSD_version < 500000  
         int s;
 
@@ -2288,21 +2310,25 @@
 	 * gotten good fibre channel state.
 	 */
 	for (;;) {
-		int wasfrozen, lb;
+		int wasfrozen, lb, lim;
 
-		isp_prt(isp, ISP_LOGDEBUG0, "kthread: checking FC state");
+		isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
+		    "isp_kthread: checking FC state");
 		isp->isp_osinfo.mbox_sleep_ok = 1;
 		lb = isp_fc_runstate(isp, 250000);
 		isp->isp_osinfo.mbox_sleep_ok = 0;
 		if (lb) {
-			unsigned int inc = 1;
+			/*
+			 * Increment loop down time by the last sleep interval
+			 */
+			isp->isp_osinfo.loop_down_time += slp;
 
 			if (lb < 0) {
-				isp_prt(isp, ISP_LOGDEBUG0,
+				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
 				    "kthread: FC loop not up (down count %d)",
 				    isp->isp_osinfo.loop_down_time);
 			} else {
-				isp_prt(isp, ISP_LOGDEBUG0,
+				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
 				    "kthread: FC got to %d (down count %d)",
 				    lb, isp->isp_osinfo.loop_down_time);
 			}
@@ -2310,33 +2336,33 @@
 
 			/*
 			 * If we've never seen loop up and we've waited longer
-			 * than quickboot time, give up and go to sleep until
-			 * loop comes up. Otherwise, increment the loop down
-			 * time and figure out how long to sleep to the next
-			 * check. 
+			 * than quickboot time, or we've seen loop up but we've
+			 * waited longer than loop_down_limit, give up and go
+			 * to sleep until loop comes up.
 			 */
-			if (FCPARAM(isp)->loop_seen_once == 0 &&
-			    isp->isp_osinfo.loop_down_time >=
-			    isp_quickboot_time) {
-				isp->isp_osinfo.loop_down_time = 0xffff;
+			if (FCPARAM(isp)->loop_seen_once == 0) {
+				lim = isp_quickboot_time;
+			} else {
+				lim = isp->isp_osinfo.loop_down_limit;
+			}
+			if (isp->isp_osinfo.loop_down_time >= lim) {
+				isp_freeze_loopdown(isp, "loop limit hit");
 				slp = 0;
-			} else if (isp->isp_osinfo.loop_down_time > 30) {
-				inc = 30;
-				slp = 30 * hz;
-			} else if (isp->isp_osinfo.loop_down_time > 1) {
-				slp = hz;
+			} else if (isp->isp_osinfo.loop_down_time < 10) {
+				slp = 1;
+			} else if (isp->isp_osinfo.loop_down_time < 30) {
+				slp = 5;
+			} else if (isp->isp_osinfo.loop_down_time < 60) {
+				slp = 10;
+			} else if (isp->isp_osinfo.loop_down_time < 120) {
+				slp = 20;
 			} else {
-				slp = 1;
+				slp = 30;
 			}
 
-			inc += isp->isp_osinfo.loop_down_time;
-			if (inc < 0xffff) {
-				isp->isp_osinfo.loop_down_time = inc;
-			} else {
-				isp->isp_osinfo.loop_down_time = 0xfffe;
-			}
 		} else {
-			isp_prt(isp, ISP_LOGDEBUG0, "kthread: FC state OK");
+			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
+			    "isp_kthread: FC state OK");
 			isp->isp_osinfo.loop_down_time = 0;
 			slp = 0;
 		}
@@ -2350,18 +2376,24 @@
 		wasfrozen = isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN;
 		isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN;
 		if (wasfrozen && isp->isp_osinfo.simqfrozen == 0) {
-			isp_prt(isp, ISP_LOGDEBUG0, "kthread: releasing simq");
+			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
+			    "isp_kthread: releasing simq");
 			ISPLOCK_2_CAMLOCK(isp);
 			xpt_release_simq(isp->isp_sim, 1);
 			CAMLOCK_2_ISPLOCK(isp);
 		}
+		isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
+		    "isp_kthread: sleep time %d", slp);
 #if __FreeBSD_version < 500000  
-		tsleep(&isp->isp_osinfo.kproc, PRIBIO, "ispf", slp);
+		tsleep(&isp->isp_osinfo.kproc, PRIBIO, "ispf",
+		    slp * hz);
 #else
 #ifdef	ISP_SMPLOCK
-		cv_timed_wait(&isp->isp_osinfo.kthread_cv, &isp->isp_lock, slp);
+		cv_timed_wait(&isp->isp_osinfo.kthread_cv, &isp->isp_lock,
+		    slp * hz);
 #else
-		(void) tsleep(&isp->isp_osinfo.kthread_cv, PRIBIO, "ispf", slp);
+		(void) tsleep(&isp->isp_osinfo.kthread_cv, PRIBIO, "ispf",
+		    slp * hz);
 #endif
 #endif
 		/*
@@ -2372,6 +2404,9 @@
 		 * to settle.
 		 */
 		if (slp == 0 && isp->isp_osinfo.hysteresis) {
+			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
+			    "isp_kthread: sleep hysteresis tick time %d",
+			    isp->isp_osinfo.hysteresis * hz);
 			(void) tsleep(&isp_fabric_hysteresis, PRIBIO, "ispT",
 			    (isp->isp_osinfo.hysteresis * hz));
 		}
@@ -2381,7 +2416,7 @@
 static void
 isp_action(struct cam_sim *sim, union ccb *ccb)
 {
-	int bus, tgt, error;
+	int bus, tgt, error, lim;
 	ispsoftc_t *isp;
 	struct ccb_trans_settings *cts;
 
@@ -2456,11 +2491,37 @@
 			}
 			break;
 		case CMD_RQLATER:
-			ISPLOCK_2_CAMLOCK(isp);
 			/*
 			 * This can only happen for Fibre Channel
 			 */
 			KASSERT((IS_FC(isp)), ("CMD_RQLATER for FC only"));
+
+			/*
+			 * Handle initial and subsequent loop down cases
+			 */
+			if (FCPARAM(isp)->loop_seen_once == 0) {
+				lim = isp_quickboot_time;
+			} else {
+				lim = isp->isp_osinfo.loop_down_limit;
+			}
+			if (isp->isp_osinfo.loop_down_time >= lim) {
+				isp_prt(isp, ISP_LOGDEBUG0,
+				    "%d.%d downtime (%d) > lim (%d)",
+				    XS_TGT(ccb), XS_LUN(ccb),
+				    isp->isp_osinfo.loop_down_time, lim);
+				ccb->ccb_h.status =
+				    CAM_SEL_TIMEOUT|CAM_DEV_QFRZN;
+				xpt_freeze_devq(ccb->ccb_h.path, 1);
+				ISPLOCK_2_CAMLOCK(isp);
+				xpt_done(ccb);
+				break;
+			}
+			isp_prt(isp, ISP_LOGDEBUG0,
+			    "%d.%d retry later", XS_TGT(ccb), XS_LUN(ccb));
+			/*
+			 * Otherwise, retry in a while.
+			 */
+			ISPLOCK_2_CAMLOCK(isp);
 			cam_freeze_devq(ccb->ccb_h.path);
 			cam_release_devq(ccb->ccb_h.path,
 			    RELSIM_RELEASE_AFTER_TIMEOUT, 0, 1000, 0);
@@ -3244,6 +3305,8 @@
 		 * If the loop down timer is running, cancel it.
 		 */
 		if (isp->isp_osinfo.ldt_running) {
+			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0,
+			   "Stopping Loop Down Timer");
 			isp->isp_osinfo.ldt_running = 0;
 			untimeout(isp_ldt, isp, isp->isp_osinfo.ldt);
 			callout_handle_init(&isp->isp_osinfo.ldt);



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