Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 19 Nov 2015 17:43:47 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r291080 - head/sys/dev/isp
Message-ID:  <201511191743.tAJHhlDL029640@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Thu Nov 19 17:43:47 2015
New Revision: 291080
URL: https://svnweb.freebsd.org/changeset/base/291080

Log:
  Another round of port scanner rewrite.
  
  This change simplifies and unifies port adding/updating for loop and
  fabric scanners.  It also fixes problems with scanning restarts due to
  concurrent port databases changes.  It also fixes many cosmetic issues.

Modified:
  head/sys/dev/isp/isp.c
  head/sys/dev/isp/isp_freebsd.c
  head/sys/dev/isp/isp_library.c
  head/sys/dev/isp/isp_library.h
  head/sys/dev/isp/ispmbox.h
  head/sys/dev/isp/ispvar.h

Modified: head/sys/dev/isp/isp.c
==============================================================================
--- head/sys/dev/isp/isp.c	Thu Nov 19 17:06:12 2015	(r291079)
+++ head/sys/dev/isp/isp.c	Thu Nov 19 17:43:47 2015	(r291080)
@@ -68,9 +68,7 @@ __FBSDID("$FreeBSD$");
 /*
  * Local static data
  */
-static const char fconf[] = "Chan %d PortDB[%d] changed:\n current =(0x%x@0x%06x 0x%08x%08x 0x%08x%08x)\n database=(0x%x@0x%06x 0x%08x%08x 0x%08x%08x)";
 static const char notresp[] = "Not RESPONSE in RESPONSE Queue (type 0x%x) @ idx %d (next %d) nlooked %d";
-static const char topology[] = "Chan %d WWPN 0x%08x%08x PortID 0x%06x LoopID 0x%x Connection '%s'";
 static const char bun[] = "bad underrun (count %d, resid %d, status %s)";
 static const char lipd[] = "Chan %d LIP destroyed %d active commands";
 static const char sacq[] = "unable to acquire scratch area";
@@ -108,7 +106,8 @@ static void isp_scsi_init(ispsoftc_t *);
 static void isp_scsi_channel_init(ispsoftc_t *, int);
 static void isp_fibre_init(ispsoftc_t *);
 static void isp_fibre_init_2400(ispsoftc_t *);
-static void isp_mark_portdb(ispsoftc_t *, int, int);
+static void isp_clear_portdb(ispsoftc_t *, int);
+static void isp_mark_portdb(ispsoftc_t *, int);
 static int isp_plogx(ispsoftc_t *, int, uint16_t, uint32_t, int, int);
 static int isp_port_login(ispsoftc_t *, uint16_t, uint32_t);
 static int isp_port_logout(ispsoftc_t *, uint16_t, uint32_t);
@@ -2283,7 +2282,7 @@ isp_fibre_init_2400(ispsoftc_t *isp)
 }
 
 static void
-isp_mark_portdb(ispsoftc_t *isp, int chan, int disposition)
+isp_clear_portdb(ispsoftc_t *isp, int chan)
 {
 	fcparam *fcp = FCPARAM(isp, chan);
 	fcportdb_t *lp;
@@ -2292,30 +2291,41 @@ isp_mark_portdb(ispsoftc_t *isp, int cha
 	for (i = 0; i < MAX_FC_TARG; i++) {
 		lp = &fcp->portdb[i];
 		switch (lp->state) {
-		case FC_PORTDB_STATE_PROBATIONAL:
 		case FC_PORTDB_STATE_DEAD:
 		case FC_PORTDB_STATE_CHANGED:
-		case FC_PORTDB_STATE_PENDING_VALID:
 		case FC_PORTDB_STATE_VALID:
-			if (disposition > 0)
-				lp->state = FC_PORTDB_STATE_PROBATIONAL;
-			else {
-				lp->state = FC_PORTDB_STATE_NIL;
-				isp_async(isp, ISPASYNC_DEV_GONE, chan, lp);
-			}
-			break;
-		case FC_PORTDB_STATE_ZOMBIE:
+			lp->state = FC_PORTDB_STATE_NIL;
+			isp_async(isp, ISPASYNC_DEV_GONE, chan, lp);
 			break;
 		case FC_PORTDB_STATE_NIL:
 		case FC_PORTDB_STATE_NEW:
-		default:
-			ISP_MEMZERO(lp, sizeof(*lp));
 			lp->state = FC_PORTDB_STATE_NIL;
 			break;
+		case FC_PORTDB_STATE_ZOMBIE:
+			break;
+		default:
+			panic("Don't know how to clear state %d\n", lp->state);
 		}
 	}
 }
 
+static void
+isp_mark_portdb(ispsoftc_t *isp, int chan)
+{
+	fcparam *fcp = FCPARAM(isp, chan);
+	fcportdb_t *lp;
+	int i;
+
+	for (i = 0; i < MAX_FC_TARG; i++) {
+		lp = &fcp->portdb[i];
+		if (lp->state == FC_PORTDB_STATE_NIL)
+			continue;
+		if ((lp->portid & 0xfffc00) == 0xfffc00)
+			continue;
+		fcp->portdb[i].probational = 1;
+	}
+}
+
 /*
  * Perform an IOCB PLOGI or LOGO via EXECUTE IOCB A64 for 24XX cards
  * or via FABRIC LOGIN/FABRIC LOGOUT for other cards.
@@ -2333,6 +2343,9 @@ isp_plogx(ispsoftc_t *isp, int chan, uin
 	const char *msg;
 	char buf[64];
 
+	isp_prt(isp, ISP_LOG_SANCFG, "Chan %d PLOGX %s PortID 0x%06x nphdl 0x%x",
+	    chan, (flags & PLOGX_FLG_CMD_MASK) == PLOGX_FLG_CMD_PLOGI ?
+	    "Login":"Logout", portid, handle);
 	if (!IS_24XX(isp)) {
 		int action = flags & PLOGX_FLG_CMD_MASK;
 		if (action == PLOGX_FLG_CMD_PLOGI) {
@@ -2766,7 +2779,7 @@ static int
 isp_fclink_test(ispsoftc_t *isp, int chan, int usdelay)
 {
 	mbreg_t mbs;
-	int r;
+	int i, r;
 	uint16_t nphdl;
 	fcparam *fcp;
 	isp_pdb_t pdb;
@@ -2774,8 +2787,8 @@ isp_fclink_test(ispsoftc_t *isp, int cha
 
 	fcp = FCPARAM(isp, chan);
 
-	/* Mark port database entries for following scan. */
-	isp_mark_portdb(isp, chan, 1);
+	/* Mark port database entries probational for following scan. */
+	isp_mark_portdb(isp, chan);
 
 	if (fcp->isp_loopstate >= LOOP_LTEST_DONE)
 		return (0);
@@ -2818,12 +2831,6 @@ isp_fclink_test(ispsoftc_t *isp, int cha
 		return (-1);
 	}
 
-	if (ISP_CAP_2KLOGIN(isp)) {
-		fcp->isp_loopid = mbs.param[1];
-	} else {
-		fcp->isp_loopid = mbs.param[1] & 0xff;
-	}
-
 	if (IS_2100(isp)) {
 		/*
 		 * Don't bother with fabric if we are using really old
@@ -2842,30 +2849,17 @@ isp_fclink_test(ispsoftc_t *isp, int cha
 	}
 	fcp->isp_portid = mbs.param[2] | (mbs.param[3] << 16);
 
-	/*
-	 * Check to make sure we got a valid loopid
-	 * The 24XX seems to mess this up for multiple channels.
-	 */
-	if (fcp->isp_topo == TOPO_FL_PORT || fcp->isp_topo == TOPO_NL_PORT) {
+	if (!TOPO_IS_FABRIC(fcp->isp_topo)) {
+		fcp->isp_loopid = mbs.param[1] & 0xff;
+	} else if (fcp->isp_topo != TOPO_F_PORT) {
 		uint8_t alpa = fcp->isp_portid;
 
-		if (alpa == 0) {
-			/* "Cannot Happen" */
-			isp_prt(isp, ISP_LOGWARN, "Zero AL_PA for Loop Topology?");
-		} else {
-			int i;
-			for (i = 0; alpa_map[i]; i++) {
-				if (alpa_map[i] == alpa) {
-					break;
-				}
-			}
-			if (alpa_map[i] && fcp->isp_loopid != i) {
-				isp_prt(isp, ISP_LOG_SANCFG,
-				    "Chan %d Deriving loopid %d from AL_PA map (AL_PA 0x%x) and ignoring returned value %d (AL_PA 0x%x)",
-				    chan, i, alpa_map[i], fcp->isp_loopid, alpa);
-				fcp->isp_loopid = i;
-			}
+		for (i = 0; alpa_map[i]; i++) {
+			if (alpa_map[i] == alpa)
+				break;
 		}
+		if (alpa_map[i])
+			fcp->isp_loopid = i;
 	}
 
 	if (fcp->isp_topo == TOPO_F_PORT || fcp->isp_topo == TOPO_FL_PORT) {
@@ -2899,6 +2893,7 @@ isp_fclink_test(ispsoftc_t *isp, int cha
 	}
 
 not_on_fabric:
+	/* Get link speed. */
 	fcp->isp_gbspeed = 1;
 	if (IS_23XX(isp) || IS_24XX(isp)) {
 		MBSINIT(&mbs, MBOX_GET_SET_DATA_RATE, MBLOGALL, 3000000);
@@ -2906,27 +2901,29 @@ not_on_fabric:
 		/* mbs.param[2] undefined if we're just getting rate */
 		isp_mboxcmd(isp, &mbs);
 		if (mbs.param[0] == MBOX_COMMAND_COMPLETE) {
-			if (mbs.param[1] == MBGSD_EIGHTGB) {
-				isp_prt(isp, ISP_LOGINFO, "Chan %d 8Gb link speed", chan);
+			if (mbs.param[1] == MBGSD_10GB)
+				fcp->isp_gbspeed = 10;
+			else if (mbs.param[1] == MBGSD_16GB)
+				fcp->isp_gbspeed = 16;
+			else if (mbs.param[1] == MBGSD_8GB)
 				fcp->isp_gbspeed = 8;
-			} else if (mbs.param[1] == MBGSD_FOURGB) {
-				isp_prt(isp, ISP_LOGINFO, "Chan %d 4Gb link speed", chan);
+			else if (mbs.param[1] == MBGSD_4GB)
 				fcp->isp_gbspeed = 4;
-			} else if (mbs.param[1] == MBGSD_TWOGB) {
-				isp_prt(isp, ISP_LOGINFO, "Chan %d 2Gb link speed", chan);
+			else if (mbs.param[1] == MBGSD_2GB)
 				fcp->isp_gbspeed = 2;
-			} else if (mbs.param[1] == MBGSD_ONEGB) {
-				isp_prt(isp, ISP_LOGINFO, "Chan %d 1Gb link speed", chan);
+			else if (mbs.param[1] == MBGSD_1GB)
 				fcp->isp_gbspeed = 1;
-			}
 		}
 	}
 
 	fcp->isp_loopstate = LOOP_LTEST_DONE;
-	/*
-	 * Announce ourselves, too.
-	 */
-	isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGCONFIG, topology, chan, (uint32_t) (fcp->isp_wwpn >> 32), (uint32_t) fcp->isp_wwpn, fcp->isp_portid, fcp->isp_loopid, isp_fc_toponame(fcp));
+	isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGCONFIG,
+	    "Chan %d WWPN %016jx WWNN %016jx",
+	    chan, (uintmax_t)fcp->isp_wwpn, (uintmax_t)fcp->isp_wwnn);
+	isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGCONFIG,
+	    "Chan %d %dGb %s PortID 0x%06x LoopID 0x%02x",
+	    chan, fcp->isp_gbspeed, isp_fc_toponame(fcp), fcp->isp_portid,
+	    fcp->isp_loopid);
 	isp_prt(isp, ISP_LOG_SANCFG, "Chan %d FC link test done", chan);
 	return (0);
 }
@@ -2963,13 +2960,11 @@ isp_pdb_sync(ispsoftc_t *isp, int chan)
 	for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) {
 		lp = &fcp->portdb[dbidx];
 
-		if (lp->state == FC_PORTDB_STATE_NIL ||
-		    lp->state == FC_PORTDB_STATE_VALID) {
+		if (lp->state == FC_PORTDB_STATE_NIL)
 			continue;
-		}
-
+		if (lp->probational && lp->state != FC_PORTDB_STATE_ZOMBIE)
+			lp->state = FC_PORTDB_STATE_DEAD;
 		switch (lp->state) {
-		case FC_PORTDB_STATE_PROBATIONAL:
 		case FC_PORTDB_STATE_DEAD:
 			lp->state = FC_PORTDB_STATE_NIL;
 			isp_async(isp, ISPASYNC_DEV_GONE, chan, lp);
@@ -2979,36 +2974,23 @@ isp_pdb_sync(ispsoftc_t *isp, int chan)
 				    PLOGX_FLG_CMD_LOGO |
 				    PLOGX_FLG_IMPLICIT |
 				    PLOGX_FLG_FREE_NPHDL, 0);
-			} else {
-				lp->autologin = 0;
 			}
-			lp->new_prli_word3 = 0;
-			lp->new_portid = 0;
 			/*
 			 * Note that we might come out of this with our state
 			 * set to FC_PORTDB_STATE_ZOMBIE.
 			 */
 			break;
 		case FC_PORTDB_STATE_NEW:
-			lp->portid = lp->new_portid;
-			lp->prli_word3 = lp->new_prli_word3;
 			lp->state = FC_PORTDB_STATE_VALID;
 			isp_async(isp, ISPASYNC_DEV_ARRIVED, chan, lp);
-			lp->new_prli_word3 = 0;
-			lp->new_portid = 0;
 			break;
 		case FC_PORTDB_STATE_CHANGED:
 			lp->state = FC_PORTDB_STATE_VALID;
 			isp_async(isp, ISPASYNC_DEV_CHANGED, chan, lp);
 			lp->portid = lp->new_portid;
 			lp->prli_word3 = lp->new_prli_word3;
-			lp->new_prli_word3 = 0;
-			lp->new_portid = 0;
 			break;
-		case FC_PORTDB_STATE_PENDING_VALID:
-			lp->portid = lp->new_portid;
-			lp->prli_word3 = lp->new_prli_word3;
-			lp->state = FC_PORTDB_STATE_VALID;
+		case FC_PORTDB_STATE_VALID:
 			isp_async(isp, ISPASYNC_DEV_STAYED, chan, lp);
 			break;
 		case FC_PORTDB_STATE_ZOMBIE:
@@ -3032,15 +3014,78 @@ isp_pdb_sync(ispsoftc_t *isp, int chan)
 	return (0);
 }
 
+static void
+isp_pdb_add_update(ispsoftc_t *isp, int chan, isp_pdb_t *pdb)
+{
+	fcportdb_t *lp;
+	uint64_t wwnn, wwpn;
+
+	MAKE_WWN_FROM_NODE_NAME(wwnn, pdb->nodename);
+	MAKE_WWN_FROM_NODE_NAME(wwpn, pdb->portname);
+
+	/* Search port database for the same WWPN. */
+	if (isp_find_pdb_by_wwpn(isp, chan, wwpn, &lp)) {
+		if (!lp->probational) {
+			isp_prt(isp, ISP_LOGERR,
+			    "Chan %d Port 0x%06x@0x%04x [%d] is not probational (0x%x)",
+			    chan, lp->portid, lp->handle,
+			    FC_PORTDB_TGT(isp, chan, lp), lp->state);
+			isp_dump_portdb(isp, chan);
+			return;
+		}
+		lp->probational = 0;
+		lp->node_wwn = wwnn;
+
+		/* Old device, nothing new. */
+		if (lp->portid == pdb->portid &&
+		    lp->handle == pdb->handle &&
+		    lp->prli_word3 == pdb->prli_word3) {
+			if (lp->state != FC_PORTDB_STATE_NEW)
+				lp->state = FC_PORTDB_STATE_VALID;
+			isp_prt(isp, ISP_LOG_SANCFG,
+			    "Chan %d Port 0x%06x@0x%04x is valid",
+			    chan, pdb->portid, pdb->handle);
+			return;
+		}
+
+		/* Something has changed. */
+		lp->state = FC_PORTDB_STATE_CHANGED;
+		lp->handle = pdb->handle;
+		lp->new_portid = pdb->portid;
+		lp->new_prli_word3 = pdb->prli_word3;
+		isp_prt(isp, ISP_LOG_SANCFG,
+		    "Chan %d Port 0x%06x@0x%04x is changed",
+		    chan, pdb->portid, pdb->handle);
+		return;
+	}
+
+	/* It seems like a new port. Find an empty slot for it. */
+	if (!isp_find_pdb_empty(isp, chan, &lp)) {
+		isp_prt(isp, ISP_LOGERR, "Chan %d out of portdb entries", chan);
+		return;
+	}
+
+	ISP_MEMZERO(lp, sizeof (fcportdb_t));
+	lp->autologin = 1;
+	lp->probational = 0;
+	lp->state = FC_PORTDB_STATE_NEW;
+	lp->portid = lp->new_portid = pdb->portid;
+	lp->prli_word3 = lp->new_prli_word3 = pdb->prli_word3;
+	lp->handle = pdb->handle;
+	lp->port_wwn = wwpn;
+	lp->node_wwn = wwnn;
+	isp_prt(isp, ISP_LOG_SANCFG, "Chan %d Port 0x%06x@0x%04x is new",
+	    chan, pdb->portid, pdb->handle);
+}
+
 /*
  * Scan local loop for devices.
  */
 static int
 isp_scan_loop(ispsoftc_t *isp, int chan)
 {
-	fcportdb_t *lp, tmp;
 	fcparam *fcp = FCPARAM(isp, chan);
-	int i, idx, lim, r;
+	int idx, lim, r;
 	isp_pdb_t pdb;
 	uint16_t handles[LOCAL_LOOP_LIM];
 	uint16_t handle;
@@ -3052,8 +3097,7 @@ isp_scan_loop(ispsoftc_t *isp, int chan)
 		return (0);
 	}
 	isp_prt(isp, ISP_LOG_SANCFG, "Chan %d FC loop scan", chan);
-	if (fcp->isp_topo != TOPO_NL_PORT && fcp->isp_topo != TOPO_FL_PORT &&
-	    fcp->isp_topo != TOPO_N_PORT) {
+	if (TOPO_IS_FABRIC(fcp->isp_topo)) {
 		isp_prt(isp, ISP_LOG_SANCFG,
 		    "Chan %d FC loop scan done (no loop)", chan);
 		fcp->isp_loopstate = LOOP_LSCAN_DONE;
@@ -3066,7 +3110,6 @@ isp_scan_loop(ispsoftc_t *isp, int chan)
 	if (r != 0) {
 		isp_prt(isp, ISP_LOG_SANCFG,
 		    "Chan %d Getting list of handles failed with %x", chan, r);
-fail:
 		isp_prt(isp, ISP_LOG_SANCFG,
 		    "Chan %d FC loop scan done (bad)", chan);
 		return (-1);
@@ -3113,6 +3156,8 @@ abort:
 		 * Get the port database entity for this index.
 		 */
 		r = isp_getpdb(isp, chan, handle, &pdb, 1);
+		if (fcp->isp_loopstate < LOOP_SCANNING_LOOP)
+			goto abort;
 		if (r != 0) {
 			isp_prt(isp, ISP_LOGDEBUG1,
 			    "Chan %d FC Scan Loop handle %d returned %x",
@@ -3122,145 +3167,7 @@ abort:
 			continue;
 		}
 
-		if (fcp->isp_loopstate < LOOP_SCANNING_LOOP)
-			goto abort;
-
-		/*
-		 * On *very* old 2100 firmware we would end up sometimes
-		 * with the firmware returning the port database entry
-		 * for something else. We used to restart this, but
-		 * now we just punt.
-		 */
-		if (IS_2100(isp) && pdb.handle != handle) {
-			isp_prt(isp, ISP_LOGWARN,
-			    "Chan %d getpdb() returned wrong handle %x != %x",
-			    chan, pdb.handle, handle);
-			goto fail;
-		}
-
-		/*
-		 * Save the pertinent info locally.
-		 */
-		MAKE_WWN_FROM_NODE_NAME(tmp.node_wwn, pdb.nodename);
-		MAKE_WWN_FROM_NODE_NAME(tmp.port_wwn, pdb.portname);
-		tmp.prli_word3 = pdb.prli_word3;
-		tmp.portid = pdb.portid;
-		tmp.handle = pdb.handle;
-
-		/*
-		 * Check to make sure it's still a valid entry. The 24XX seems
-		 * to return a portid but not a WWPN/WWNN or role for devices
-		 * which shift on a loop.
-		 */
-		if (tmp.node_wwn == 0 || tmp.port_wwn == 0 || tmp.portid == 0) {
-			int a, b, c;
-			isp_prt(isp, ISP_LOGWARN,
-			    "Chan %d bad pdb (WWNN %016jx, WWPN %016jx, PortID %06x, W3 0x%x, H 0x%x) @ handle 0x%x",
-			    chan, tmp.node_wwn, tmp.port_wwn, tmp.portid, tmp.prli_word3, tmp.handle, handle);
-			a = (tmp.node_wwn == 0);
-			b = (tmp.port_wwn == 0);
-			c = (tmp.portid == 0);
-			if (a == 0 && b == 0) {
-				tmp.node_wwn =
-				    isp_get_wwn(isp, chan, handle, 1);
-				tmp.port_wwn =
-				    isp_get_wwn(isp, chan, handle, 0);
-				if (tmp.node_wwn && tmp.port_wwn) {
-					isp_prt(isp, ISP_LOGWARN, "DODGED!");
-					goto cont;
-				}
-			}
-			isp_dump_portdb(isp, chan);
-			continue;
-		}
-  cont:
-
-		/*
-		 * Now search the entire port database
-		 * for the same Port WWN.
-		 */
-		if (isp_find_pdb_by_wwn(isp, chan, tmp.port_wwn, &lp)) {
-			/*
-			 * Okay- we've found a non-nil entry that matches.
-			 * Check to make sure it's probational or a zombie.
-			 */
-			if (lp->state != FC_PORTDB_STATE_PROBATIONAL &&
-			    lp->state != FC_PORTDB_STATE_ZOMBIE &&
-			    lp->state != FC_PORTDB_STATE_VALID) {
-				isp_prt(isp, ISP_LOGERR,
-				    "Chan %d [%d] not probational/zombie (0x%x)",
-				    chan, FC_PORTDB_TGT(isp, chan, lp), lp->state);
-				isp_dump_portdb(isp, chan);
-				goto fail;
-			}
-
-			/*
-			 * Mark the device as something the f/w logs into
-			 * automatically.
-			 */
-			lp->autologin = 1;
-			lp->node_wwn = tmp.node_wwn;
-
-			/*
-			 * Check to make see if really still the same
-			 * device. If it is, we mark it pending valid.
-			 */
-			if (lp->portid == tmp.portid && lp->handle == tmp.handle && lp->prli_word3 == tmp.prli_word3) {
-				lp->new_portid = tmp.portid;
-				lp->new_prli_word3 = tmp.prli_word3;
-				lp->state = FC_PORTDB_STATE_PENDING_VALID;
-				isp_prt(isp, ISP_LOG_SANCFG,
-				    "Chan %d Loop port 0x%06x@0x%04x now pending valid",
-				    chan, tmp.portid, tmp.handle);
-				continue;
-			}
-
-			/*
-			 * We can wipe out the old handle value
-			 * here because it's no longer valid.
-			 */
-			lp->handle = tmp.handle;
-
-			/*
-			 * Claim that this has changed and let somebody else
-			 * decide what to do.
-			 */
-			isp_prt(isp, ISP_LOG_SANCFG,
-			    "Chan %d Loop port 0x%06x@0x%04x changed",
-			    chan, tmp.portid, tmp.handle);
-			lp->state = FC_PORTDB_STATE_CHANGED;
-			lp->new_portid = tmp.portid;
-			lp->new_prli_word3 = tmp.prli_word3;
-			continue;
-		}
-
-		/*
-		 * Ah. A new device entry. Find an empty slot
-		 * for it and save info for later disposition.
-		 */
-		for (i = 0; i < MAX_FC_TARG; i++) {
-			if (fcp->portdb[i].state == FC_PORTDB_STATE_NIL) {
-				break;
-			}
-		}
-		if (i == MAX_FC_TARG) {
-			isp_prt(isp, ISP_LOGERR,
-			    "Chan %d out of portdb entries", chan);
-			continue;
-		}
-		lp = &fcp->portdb[i];
-
-		ISP_MEMZERO(lp, sizeof (fcportdb_t));
-		lp->autologin = 1;
-		lp->state = FC_PORTDB_STATE_NEW;
-		lp->new_portid = tmp.portid;
-		lp->new_prli_word3 = tmp.prli_word3;
-		lp->handle = tmp.handle;
-		lp->port_wwn = tmp.port_wwn;
-		lp->node_wwn = tmp.node_wwn;
-		isp_prt(isp, ISP_LOG_SANCFG,
-		    "Chan %d Loop port 0x%06x@0x%04x is a new entry",
-		    chan, tmp.portid, tmp.handle);
+		isp_pdb_add_update(isp, chan, &pdb);
 	}
 	if (fcp->isp_loopstate < LOOP_SCANNING_LOOP)
 		goto abort;
@@ -3359,10 +3266,6 @@ isp_gid_ft_ct_passthru(ispsoftc_t *isp, 
 
 	isp_prt(isp, ISP_LOGDEBUG0, "Chan %d scanning fabric (GID_FT) via CT", chan);
 
-	if (!IS_24XX(isp)) {
-		return (1);
-	}
-
 	/*
 	 * Build a Passthrough IOCB in memory.
 	 */
@@ -3445,6 +3348,7 @@ static int
 isp_scan_fabric(ispsoftc_t *isp, int chan)
 {
 	fcparam *fcp = FCPARAM(isp, chan);
+	fcportdb_t *lp;
 	uint32_t portid;
 	uint16_t nphdl;
 	isp_pdb_t pdb;
@@ -3458,7 +3362,7 @@ isp_scan_fabric(ispsoftc_t *isp, int cha
 		return (0);
 	}
 	isp_prt(isp, ISP_LOG_SANCFG, "Chan %d FC fabric scan", chan);
-	if (fcp->isp_topo != TOPO_FL_PORT && fcp->isp_topo != TOPO_F_PORT) {
+	if (!TOPO_IS_FABRIC(fcp->isp_topo)) {
 		fcp->isp_loopstate = LOOP_FSCAN_DONE;
 		isp_prt(isp, ISP_LOG_SANCFG,
 		    "Chan %d FC fabric scan done (no fabric)", chan);
@@ -3495,16 +3399,13 @@ abort:
 		goto fail;
 	}
 
-	if (IS_24XX(isp)) {
+	/* Get list of port IDs from SNS. */
+	if (IS_24XX(isp))
 		r = isp_gid_ft_ct_passthru(isp, chan);
-	} else {
+	else
 		r = isp_gid_ft_sns(isp, chan);
-	}
-
-	if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) {
+	if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC)
 		goto abort;
-	}
-
 	if (r > 0) {
 		fcp->isp_loopstate = LOOP_FSCAN_DONE;
 		FC_SCRATCH_RELEASE(isp, chan);
@@ -3519,9 +3420,8 @@ abort:
 	rs0 = (sns_gid_ft_rsp_t *) ((uint8_t *)fcp->isp_scratch+IGPOFF);
 	rs1 = (sns_gid_ft_rsp_t *) ((uint8_t *)fcp->isp_scratch+OGPOFF);
 	isp_get_gid_ft_response(isp, rs0, rs1, NGENT);
-	if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) {
+	if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC)
 		goto abort;
-	}
 	if (rs1->snscb_cthdr.ct_cmd_resp != LS_ACC) {
 		int level;
 		if (rs1->snscb_cthdr.ct_reason == 9 && rs1->snscb_cthdr.ct_explanation == 7) {
@@ -3538,21 +3438,11 @@ abort:
 		return (0);
 	}
 
-	/*
-	 * Go through the list and remove duplicate port ids.
-	 */
-
-	portlim = 0;
-	portidx = 0;
+	/* Check our buffer was big enough to get the full list. */
 	for (portidx = 0; portidx < NGENT-1; portidx++) {
-		if (rs1->snscb_ports[portidx].control & 0x80) {
+		if (rs1->snscb_ports[portidx].control & 0x80)
 			break;
-		}
 	}
-
-	/*
-	 * If we're not at the last entry, our list wasn't big enough.
-	 */
 	if ((rs1->snscb_ports[portidx].control & 0x80) == 0) {
 		isp_prt(isp, ISP_LOGWARN,
 		    "fabric too big for scratch area: increase ISP_FC_SCRLEN");
@@ -3561,6 +3451,7 @@ abort:
 	isp_prt(isp, ISP_LOG_SANCFG,
 	    "Chan %d Got %d ports back from name server", chan, portlim);
 
+	/* Go through the list and remove duplicate port ids. */
 	for (portidx = 0; portidx < portlim; portidx++) {
 		int npidx;
 
@@ -3603,55 +3494,34 @@ abort:
 	 */
 
 	for (portidx = 0; portidx < portlim; portidx++) {
-		fcportdb_t *lp;
-		uint64_t wwnn, wwpn;
-		int dbidx, nr;
-
-		portid =
-		    ((rs1->snscb_ports[portidx].portid[0]) << 16) |
-		    ((rs1->snscb_ports[portidx].portid[1]) << 8) |
-		    ((rs1->snscb_ports[portidx].portid[2]));
-
+		portid = ((rs1->snscb_ports[portidx].portid[0]) << 16) |
+			 ((rs1->snscb_ports[portidx].portid[1]) << 8) |
+			 ((rs1->snscb_ports[portidx].portid[2]));
+		isp_prt(isp, ISP_LOG_SANCFG,
+		    "Chan %d Checking fabric port 0x%06x", chan, portid);
 		if (portid == 0) {
 			isp_prt(isp, ISP_LOG_SANCFG,
 			    "Chan %d Skipping null PortID at idx %d",
 			    chan, portidx);
 			continue;
 		}
-
 		if (portid == fcp->isp_portid) {
 			isp_prt(isp, ISP_LOG_SANCFG,
 			    "Chan %d Skipping our PortID 0x%06x", chan, portid);
 			continue;
 		}
 
-		isp_prt(isp, ISP_LOG_SANCFG,
-		    "Chan %d Checking fabric port 0x%06x", chan, portid);
-
-		/*
-		 * We now search our Port Database for any
-		 * probational entries with this PortID. We don't
-		 * look for zombies here- only probational
-		 * entries (we've already logged out of zombies).
-		 */
-		for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) {
-			lp = &fcp->portdb[dbidx];
-
-			if (lp->state != FC_PORTDB_STATE_PROBATIONAL) {
-				continue;
-			}
-			if (lp->portid == portid) {
-				break;
+		/* Now search the entire port database for the same portid. */
+		if (isp_find_pdb_by_portid(isp, chan, portid, &lp)) {
+			if (!lp->probational) {
+				isp_prt(isp, ISP_LOGERR,
+				    "Chan %d Port 0x%06x@0x%04x [%d] is not probational (0x%x)",
+				    chan, lp->portid, lp->handle,
+				    FC_PORTDB_TGT(isp, chan, lp), lp->state);
+				FC_SCRATCH_RELEASE(isp, chan);
+				isp_dump_portdb(isp, chan);
+				goto fail;
 			}
-		}
-
-		/*
-		 * We found a probational entry with this Port ID.
-		 */
-		if (dbidx < MAX_FC_TARG) {
-			int handle_changed = 0;
-
-			lp = &fcp->portdb[dbidx];
 
 			/*
 			 * See if we're still logged into it.
@@ -3667,241 +3537,38 @@ abort:
 			 * and leave the new portid and role in the
 			 * database entry for somebody further along to
 			 * decide what to do (policy choice).
-			 *
 			 */
-
 			r = isp_getpdb(isp, chan, lp->handle, &pdb, 0);
-			if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) {
+			if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC)
 				goto abort;
-			}
 			if (r != 0) {
-				lp->new_portid = portid;
 				lp->state = FC_PORTDB_STATE_DEAD;
-				isp_prt(isp, ISP_LOG_SANCFG, "Chan %d Fabric PortID 0x%06x handle 0x%x is dead (%d)", chan, portid, lp->handle, r);
-				continue;
-			}
-
-
-			/*
-			 * Check to make sure that handle, portid, WWPN and
-			 * WWNN agree. If they don't, then the association
-			 * between this PortID and the stated handle has been
-			 * broken by the firmware.
-			 */
-			MAKE_WWN_FROM_NODE_NAME(wwnn, pdb.nodename);
-			MAKE_WWN_FROM_NODE_NAME(wwpn, pdb.portname);
-			if (pdb.handle != lp->handle ||
-			    pdb.portid != portid ||
-			    wwpn != lp->port_wwn ||
-			    (lp->node_wwn != 0 && wwnn != lp->node_wwn)) {
 				isp_prt(isp, ISP_LOG_SANCFG,
-				    fconf, chan, dbidx, pdb.handle, pdb.portid,
-				    (uint32_t) (wwnn >> 32), (uint32_t) wwnn,
-				    (uint32_t) (wwpn >> 32), (uint32_t) wwpn,
-				    lp->handle, portid,
-				    (uint32_t) (lp->node_wwn >> 32),
-				    (uint32_t) lp->node_wwn,
-				    (uint32_t) (lp->port_wwn >> 32),
-				    (uint32_t) lp->port_wwn);
-				/*
-				 * Try to re-login to this device using a
-				 * new handle. If that fails, mark it dead.
-				 *
-				 * isp_login_device will check for handle and
-				 * portid consistency after re-login.
-				 *
-				 */
-				if ((fcp->role & ISP_ROLE_INITIATOR) == 0 ||
-				    isp_login_device(isp, chan, portid, &pdb,
-				     &FCPARAM(isp, 0)->isp_lasthdl)) {
-					lp->new_portid = portid;
-					lp->state = FC_PORTDB_STATE_DEAD;
-					if (fcp->isp_loopstate <
-					    LOOP_SCANNING_FABRIC) {
-						goto abort;
-					}
-					continue;
-				}
-				if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) {
-					goto abort;
-				}
-				MAKE_WWN_FROM_NODE_NAME(wwnn, pdb.nodename);
-				MAKE_WWN_FROM_NODE_NAME(wwpn, pdb.portname);
-				if (wwpn != lp->port_wwn ||
-				    (lp->node_wwn != 0 && wwnn != lp->node_wwn)) {
-					isp_prt(isp, ISP_LOGWARN, "changed WWN"
-					    " after relogin");
-					lp->new_portid = portid;
-					lp->state = FC_PORTDB_STATE_DEAD;
-					continue;
-				}
-
-				lp->handle = pdb.handle;
-				handle_changed++;
+				    "Chan %d Port 0x%06x handle 0x%x is dead (%d)",
+				    chan, portid, lp->handle, r);
+				goto relogin;
 			}
 
-			nr = pdb.prli_word3;
-
-			/*
-			 * Check to see whether the portid and roles have
-			 * stayed the same. If they have stayed the same,
-			 * we believe that this is the same device and it
-			 * hasn't become disconnected and reconnected, so
-			 * mark it as pending valid.
-			 *
-			 * If they aren't the same, mark the device as a
-			 * changed device and save the new port id and role
-			 * and let somebody else decide.
-			 */
-
-			lp->new_portid = portid;
-			lp->new_prli_word3 = nr;
-			if (pdb.portid != lp->portid || nr != lp->prli_word3 || handle_changed) {
-				isp_prt(isp, ISP_LOG_SANCFG,
-				    "Chan %d Fabric port 0x%06x changed",
-				    chan, portid);
-				lp->state = FC_PORTDB_STATE_CHANGED;
-			} else {
-				isp_prt(isp, ISP_LOG_SANCFG,
-				    "Chan %d Fabric port 0x%06x now pending valid",
-				    chan, portid);
-				lp->state = FC_PORTDB_STATE_PENDING_VALID;
-			}
+			isp_pdb_add_update(isp, chan, &pdb);
 			continue;
 		}
 
+relogin:
 		if ((fcp->role & ISP_ROLE_INITIATOR) == 0)
 			continue;
 
-		/*
-		 * Ah- a new entry. Search the database again for all non-NIL
-		 * entries to make sure we never ever make a new database entry
-		 * with the same port id. While we're at it, mark where the
-		 * last free entry was.
-		 */
-
-		dbidx = MAX_FC_TARG;
-		for (lp = fcp->portdb; lp < &fcp->portdb[MAX_FC_TARG]; lp++) {
-			if (lp->state == FC_PORTDB_STATE_NIL) {
-				if (dbidx == MAX_FC_TARG) {
-					dbidx = lp - fcp->portdb;
-				}
-				continue;
-			}
-			if (lp->state == FC_PORTDB_STATE_ZOMBIE) {
-				continue;
-			}
-			if (lp->portid == portid) {
-				break;
-			}
-		}
-
-		if (lp < &fcp->portdb[MAX_FC_TARG]) {
-			isp_prt(isp, ISP_LOGWARN, "Chan %d PortID 0x%06x "
-			    "already at %d handle %d state %d",
-			    chan, portid, dbidx, lp->handle, lp->state);
-			continue;
-		}
-
-		/*
-		 * We should have the index of the first free entry seen.
-		 */
-		if (dbidx == MAX_FC_TARG) {
-			isp_prt(isp, ISP_LOGERR,
-			    "port database too small to login PortID 0x%06x"
-			    "- increase MAX_FC_TARG", portid);
-			continue;
-		}
-
-		/*
-		 * Otherwise, point to our new home.
-		 */
-		lp = &fcp->portdb[dbidx];
-
-		/*
-		 * Try to see if we are logged into this device,
-		 * and maybe log into it.
-		 *
-		 * isp_login_device will check for handle and
-		 * portid consistency after login.
-		 */
 		if (isp_login_device(isp, chan, portid, &pdb,
 		    &FCPARAM(isp, 0)->isp_lasthdl)) {
-			if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) {
+			if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC)
 				goto abort;
-			}
-			continue;
-		}
-		if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) {
-			goto abort;
-		}
-
-		nphdl = pdb.handle;
-		MAKE_WWN_FROM_NODE_NAME(wwnn, pdb.nodename);
-		MAKE_WWN_FROM_NODE_NAME(wwpn, pdb.portname);
-		nr = pdb.prli_word3;
-
-		/*
-		 * And go through the database *one* more time to make sure
-		 * that we do not make more than one entry that has the same
-		 * WWNN/WWPN duple
-		 */
-		for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) {
-			if ((fcp->portdb[dbidx].node_wwn == wwnn ||
-			     fcp->portdb[dbidx].node_wwn == 0) &&
-			    fcp->portdb[dbidx].port_wwn == wwpn) {
-				break;
-			}
-		}
-
-		if (dbidx == MAX_FC_TARG) {
-			ISP_MEMZERO(lp, sizeof (fcportdb_t));
-			lp->handle = nphdl;
-			lp->node_wwn = wwnn;
-			lp->port_wwn = wwpn;
-			lp->new_portid = portid;
-			lp->new_prli_word3 = nr;
-			lp->state = FC_PORTDB_STATE_NEW;
-			isp_prt(isp, ISP_LOG_SANCFG, "Chan %d Fabric port 0x%06x is a new entry", chan, portid);
 			continue;
 		}
 
-    		if (fcp->portdb[dbidx].state != FC_PORTDB_STATE_ZOMBIE) {
-			isp_prt(isp, ISP_LOGWARN,
-			    "Chan %d PortID 0x%x 0x%08x%08x/0x%08x%08x %ld "
-			    "already at idx %d, state 0x%x", chan, portid,
-			    (uint32_t) (wwnn >> 32), (uint32_t) wwnn,
-			    (uint32_t) (wwpn >> 32), (uint32_t) wwpn,
-			    (long) (lp - fcp->portdb), dbidx,
-			    fcp->portdb[dbidx].state);
-			continue;
-		}
-
-		/*
-		 * We found a zombie entry that matches us.
-		 * Revive it. We know that WWN and WWPN
-		 * are the same. For fabric devices, we
-		 * don't care that handle is different
-		 * as we assign that. If role or portid
-		 * are different, it maybe a changed device.
-		 */
-		lp = &fcp->portdb[dbidx];
-		lp->handle = nphdl;
-		lp->node_wwn = wwnn;
-		lp->new_portid = portid;
-		lp->new_prli_word3 = nr;
-		if (lp->portid != portid || lp->prli_word3 != nr) {
-			isp_prt(isp, ISP_LOG_SANCFG, "Chan %d Zombie fabric port 0x%06x now changed", chan, portid);
-			lp->state = FC_PORTDB_STATE_CHANGED;
-		} else {
-			isp_prt(isp, ISP_LOG_SANCFG, "Chan %d Zombie fabric port 0x%06x now pending valid", chan, portid);
-			lp->state = FC_PORTDB_STATE_PENDING_VALID;
-		}
+		isp_pdb_add_update(isp, chan, &pdb);
 	}
 
-	if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) {
+	if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC)
 		goto abort;
-	}
 	FC_SCRATCH_RELEASE(isp, chan);
 	fcp->isp_loopstate = LOOP_FSCAN_DONE;
 	isp_prt(isp, ISP_LOG_SANCFG, "Chan %d FC fabric scan done", chan);
@@ -3925,27 +3592,26 @@ isp_login_device(ispsoftc_t *isp, int ch
 
 	handle = isp_next_handle(isp, ohp);
 	for (i = 0; i < lim; i++) {
-		/*
-		 * See if we're still logged into something with
-		 * this handle and that something agrees with this
-		 * port id.
-		 */
+		if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC)
+			return (-1);
+
+		/* Check if this handle is free. */
 		r = isp_getpdb(isp, chan, handle, p, 0);
-		if (r == 0 && p->portid != portid) {
-			(void) isp_plogx(isp, chan, handle, portid, PLOGX_FLG_CMD_LOGO | PLOGX_FLG_IMPLICIT | PLOGX_FLG_FREE_NPHDL, 1);
-		} else if (r == 0) {
+		if (r == 0) {
+			if (p->portid != portid) {
+				/* This handle is busy, try next one. */
+				handle = isp_next_handle(isp, ohp);
+				continue;
+			}
 			break;
 		}
-		if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC) {
+		if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC)
 			return (-1);
-		}
+
 		/*
 		 * Now try and log into the device
 		 */
 		r = isp_plogx(isp, chan, handle, portid, PLOGX_FLG_CMD_PLOGI, 1);
-		if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC) {
-			return (-1);
-		}
 		if (r == 0) {
 			break;
 		} else if ((r & 0xffff) == MBOX_PORT_ID_USED) {
@@ -3957,13 +3623,9 @@ isp_login_device(ispsoftc_t *isp, int ch
 			if (isp_plogx(isp, chan, r >> 16, portid, PLOGX_FLG_CMD_LOGO | PLOGX_FLG_IMPLICIT | PLOGX_FLG_FREE_NPHDL, 1)) {
 				isp_prt(isp, ISP_LOGERR, "baw... logout of %x failed", r >> 16);
 			}
-			if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC) {
+			if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC)
 				return (-1);
-			}
 			r = isp_plogx(isp, chan, handle, portid, PLOGX_FLG_CMD_PLOGI, 1);
-			if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC) {
-				return (-1);
-			}
 			if (r != 0)
 				i = lim;
 			break;
@@ -3988,9 +3650,6 @@ isp_login_device(ispsoftc_t *isp, int ch
 	 * is and that we also have the role it plays
 	 */

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



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