svn commit: r200089 - head/sys/dev/isp

Matt Jacob mjacob at FreeBSD.org
Fri Dec 4 03:34:13 UTC 2009


Author: mjacob
Date: Fri Dec  4 03:34:12 2009
New Revision: 200089
URL: http://svn.freebsd.org/changeset/base/200089

Log:
  Fix cases where we've managed to get a Loop UP event prior to initializing
  the loop down counter, as well as other things. This was brought to my
  attention with a different fix, more for RELENG_7- this one covers the
  multiple channel case.
  
  PR:		140438
  MFC after:	1 month

Modified:
  head/sys/dev/isp/isp_freebsd.c
  head/sys/dev/isp/isp_freebsd.h

Modified: head/sys/dev/isp/isp_freebsd.c
==============================================================================
--- head/sys/dev/isp/isp_freebsd.c	Thu Dec  3 23:57:06 2009	(r200088)
+++ head/sys/dev/isp/isp_freebsd.c	Fri Dec  4 03:34:12 2009	(r200089)
@@ -133,33 +133,37 @@ isp_attach_chan(ispsoftc_t *isp, struct 
 		}
 #endif
 	} else {
+		fcparam *fcp = FCPARAM(isp, chan);
 		struct isp_fc *fc = ISP_FC_PC(isp, chan);
 
+		ISP_LOCK(isp);
 		fc->sim = sim;
 		fc->path = path;
 		fc->isp = isp;
+		fc->ready = 1;
 
 		callout_init_mtx(&fc->ldt, &isp->isp_osinfo.lock, 0);
 		callout_init_mtx(&fc->gdt, &isp->isp_osinfo.lock, 0);
-
-		if (THREAD_CREATE(isp_kthread, fc, &fc->kproc, 0, 0, "%s: fc_thrd%d", device_get_nameunit(isp->isp_osinfo.dev), chan)) {
-			xpt_free_path(fc->path);
-			ISP_LOCK(isp);
-			xpt_bus_deregister(cam_sim_path(fc->sim));
-			ISP_UNLOCK(isp);
-			cam_sim_free(fc->sim, FALSE);
-		}
 		/*
 		 * We start by being "loop down" if we have an initiator role
 		 */
-		ISP_LOCK(isp);
-		if ((FCPARAM(isp, chan)->role & ISP_ROLE_INITIATOR) && fc->ldt_running == 0) {
+		if (fcp->role & ISP_ROLE_INITIATOR) {
 			isp_freeze_loopdown(isp, chan, "isp_attach");
-			fc->ldt_running = 1;
 			callout_reset(&fc->ldt, isp_quickboot_time * hz, isp_ldt, fc);
 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Starting Initial Loop Down Timer @ %lu", (unsigned long) time_uptime);
 		}
 		ISP_UNLOCK(isp);
+		if (THREAD_CREATE(isp_kthread, fc, &fc->kproc, 0, 0, "%s: fc_thrd%d", device_get_nameunit(isp->isp_osinfo.dev), chan)) {
+			xpt_free_path(fc->path);
+			ISP_LOCK(isp);
+			if (callout_active(&fc->ldt)) {
+				callout_stop(&fc->ldt);
+			}
+			xpt_bus_deregister(cam_sim_path(fc->sim));
+			ISP_UNLOCK(isp);
+			cam_sim_free(fc->sim, FALSE);
+			return (ENOMEM);
+		}
 #ifdef	ISP_INTERNAL_TARGET
 		ISP_SET_PC(isp, chan, proc_active, 1);
 		if (THREAD_CREATE(isp_target_thread_fc, fc, &fc->target_proc, 0, 0, "%s: isp_test_tgt%d", device_get_nameunit(isp->isp_osinfo.dev), chan)) {
@@ -3935,12 +3939,12 @@ isp_gdt(void *arg)
 		isp_prt(isp, ISP_LOGCONFIG, prom3, chan, lp->portid, tgt, "Gone Device Timeout");
 		isp_make_gone(isp, chan, tgt);
 	}
-	if (more_to_do) {
-		fc->gdt_running = 1;
-		callout_reset(&fc->gdt, hz, isp_gdt, fc);
-	} else {
-		isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d stopping Gone Device Timer", chan);
-		fc->gdt_running = 0;
+	if (fc->ready) {
+		if (more_to_do) {
+			callout_reset(&fc->gdt, hz, isp_gdt, fc);
+		} else {
+			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d stopping Gone Device Timer", chan);
+		}
 	}
 }
 
@@ -4017,6 +4021,7 @@ isp_kthread(void *arg)
 	ispsoftc_t *isp = fc->isp;
 	int chan = fc - isp->isp_osinfo.pc.fc;
 	int slp = 0;
+
 	mtx_lock(&isp->isp_osinfo.lock);
 
 	for (;;) {
@@ -4802,6 +4807,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cm
 	char *msg = NULL;
 	target_id_t tgt;
 	fcportdb_t *lp;
+	struct isp_fc *fc;
 	struct cam_path *tmppath;
 	va_list ap;
 
@@ -4886,7 +4892,6 @@ isp_async(ispsoftc_t *isp, ispasync_t cm
 		/* FALLTHROUGH */
 	case ISPASYNC_LOOP_DOWN:
 	{
-		struct isp_fc *fc;
 		if (msg == NULL) {
 			msg = "LOOP Down";
 		}
@@ -4894,20 +4899,21 @@ isp_async(ispsoftc_t *isp, ispasync_t cm
 		bus = va_arg(ap, int);
 		va_end(ap);
 
-		FCPARAM(isp, bus)->link_active = 1;
+		FCPARAM(isp, bus)->link_active = 0;
 
 		fc = ISP_FC_PC(isp, bus);
-		/*
-		 * We don't do any simq freezing if we are only in target mode
-		 */
-		if (fc->role & ISP_ROLE_INITIATOR) {
-			if (fc->path) {
-				isp_freeze_loopdown(isp, bus, msg);
-			}
-			if (fc->ldt_running == 0) {
-				fc->ldt_running = 1;
-				callout_reset(&fc->ldt, fc->loop_down_limit * hz, isp_ldt, fc);
-				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "starting Loop Down Timer @ %lu", (unsigned long) time_uptime);
+		if (cmd == ISPASYNC_LOOP_DOWN && fc->ready) {
+			/*
+			 * We don't do any simq freezing if we are only in target mode
+			 */
+			if (fc->role & ISP_ROLE_INITIATOR) {
+				if (fc->path) {
+					isp_freeze_loopdown(isp, bus, msg);
+				}
+				if (!callout_active(&fc->ldt)) {
+					callout_reset(&fc->ldt, fc->loop_down_limit * hz, isp_ldt, fc);
+					isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "starting Loop Down Timer @ %lu", (unsigned long) time_uptime);
+				}
 			}
 		}
 		isp_prt(isp, ISP_LOGINFO, "Chan %d: %s", bus, msg);
@@ -4917,6 +4923,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cm
 		va_start(ap, cmd);
 		bus = va_arg(ap, int);
 		va_end(ap);
+		fc = ISP_FC_PC(isp, bus);
 		/*
 		 * Now we just note that Loop has come up. We don't
 		 * actually do anything because we're waiting for a
@@ -4924,8 +4931,8 @@ isp_async(ispsoftc_t *isp, ispasync_t cm
 		 * thread to look at the state of the loop again.
 		 */
 		FCPARAM(isp, bus)->link_active = 1;
-		ISP_FC_PC(isp, bus)->loop_dead = 0;
-		ISP_FC_PC(isp, bus)->loop_down_time = 0;
+		fc->loop_dead = 0;
+		fc->loop_down_time = 0;
 		isp_prt(isp, ISP_LOGINFO, "Chan %d Loop UP", bus);
 		break;
 	case ISPASYNC_DEV_ARRIVED:
@@ -4933,8 +4940,9 @@ isp_async(ispsoftc_t *isp, ispasync_t cm
 		bus = va_arg(ap, int);
 		lp = va_arg(ap, fcportdb_t *);
 		va_end(ap);
+		fc = ISP_FC_PC(isp, bus);
 		lp->reserved = 0;
-		if ((ISP_FC_PC(isp, bus)->role & ISP_ROLE_INITIATOR) && (lp->roles & (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT))) {
+		if ((fc->role & ISP_ROLE_INITIATOR) && (lp->roles & (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT))) {
 			int dbidx = lp - FCPARAM(isp, bus)->portdb;
 			int i;
 
@@ -4967,6 +4975,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cm
 		bus = va_arg(ap, int);
 		lp = va_arg(ap, fcportdb_t *);
 		va_end(ap);
+		fc = ISP_FC_PC(isp, bus);
 		lp->reserved = 0;
 		if (isp_change_is_bad) {
 			lp->state = FC_PORTDB_STATE_NIL;
@@ -5013,6 +5022,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cm
 		bus = va_arg(ap, int);
 		lp = va_arg(ap, fcportdb_t *);
 		va_end(ap);
+		fc = ISP_FC_PC(isp, bus);
 		/*
 		 * If this has a virtual target and we haven't marked it
 		 * that we're going to have isp_gdt tell the OS it's gone,
@@ -5025,10 +5035,9 @@ isp_async(ispsoftc_t *isp, ispasync_t cm
 			lp->reserved = 1;
 			lp->new_reserved = ISP_FC_PC(isp, bus)->gone_device_time;
 			lp->state = FC_PORTDB_STATE_ZOMBIE;
-			if (ISP_FC_PC(isp, bus)->gdt_running == 0) {
+			if (fc->ready && !callout_active(&fc->gdt)) {
 				isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d starting Gone Device Timer", bus);
-				ISP_FC_PC(isp, bus)->gdt_running = 1;
-				callout_reset(&ISP_FC_PC(isp, bus)->gdt, hz, isp_gdt, ISP_FC_PC(isp, bus));
+				callout_reset(&fc->gdt, hz, isp_gdt, fc);
 			}
 			tgt = lp->dev_map_idx - 1;
 			isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, roles[lp->roles], "gone zombie at", tgt, (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
@@ -5053,6 +5062,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cm
 			nlstate = reason = 0;
 		}
 		va_end(ap);
+		fc = ISP_FC_PC(isp, bus);
 
 		if (evt == ISPASYNC_CHANGE_PDB) {
 			msg = "Chan %d Port Database Changed";
@@ -5065,16 +5075,15 @@ isp_async(ispsoftc_t *isp, ispasync_t cm
 		/*
 		 * If the loop down timer is running, cancel it.
 		 */
-		if (ISP_FC_PC(isp, bus)->ldt_running) {
+		if (fc->ready && callout_active(&fc->ldt)) {
 			isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Stopping Loop Down Timer @ %lu", (unsigned long) time_uptime);
-			ISP_FC_PC(isp, bus)->ldt_running = 0;
-			callout_stop(&ISP_FC_PC(isp, bus)->ldt);
+			callout_stop(&fc->ldt);
 		}
 		isp_prt(isp, ISP_LOGINFO, msg, bus);
-		if (ISP_FC_PC(isp, bus)->role & ISP_ROLE_INITIATOR) {
+		if (fc->role & ISP_ROLE_INITIATOR) {
 			isp_freeze_loopdown(isp, bus, msg);
 		}
-		wakeup(ISP_FC_PC(isp, bus));
+		wakeup(fc);
 		break;
 	}
 #ifdef	ISP_TARGET_MODE

Modified: head/sys/dev/isp/isp_freebsd.h
==============================================================================
--- head/sys/dev/isp/isp_freebsd.h	Thu Dec  3 23:57:06 2009	(r200088)
+++ head/sys/dev/isp/isp_freebsd.h	Fri Dec  4 03:34:12 2009	(r200089)
@@ -177,9 +177,9 @@ struct isp_fc {
 		hysteresis	: 8,
 		role		: 2,
 		gdt_running	: 1,
-		ldt_running	: 1,
 		loop_dead	: 1,
-		fcbsy		: 1;
+		fcbsy		: 1,
+		ready		: 1;
 	struct callout ldt;	/* loop down timer */
 	struct callout gdt;	/* gone device timer */
 #ifdef	ISP_TARGET_MODE


More information about the svn-src-head mailing list