PERFORCE change 106809 for review

Matt Jacob mjacob at FreeBSD.org
Wed Sep 27 23:56:51 PDT 2006


http://perforce.freebsd.org/chv.cgi?CH=106809

Change 106809 by mjacob at newisp on 2006/09/28 06:56:23

	Handle fabric case of cycling through old portdb members
	and finding that the handle for that member now returns
	info for some other device.
	
	Let's say we have a disk at handle 0x82, PortID 0x10300.
	We get a PDB event and go ask the fabric name server
	for a list of portids.
	
	When we get to 0x10300 in that list, we say "AhHa!"- because
	we already know about it. But we call isp_get_pdb to check
	out the info for handle 0x82 and we get info for PortID 0x105e0!
	
	Whups! So w/o telling us, the disk did a LOGO and somebody else
	then did a PLOGI to us which the QLogic f/w then reassigned
	handle 0x82 to that new member.
	
	The fix here is that when we get to this situation, we know that
	portid 0x10300 is still out there (we got that from the fabric
	name server)- it's just that the handle we'd been using to
	talk to it is no longer valid. This is *almost* like the arrival
	of a brand new device- except that we don't have to allocate
	a portdb entry (we already have one)- but we *do* have to go
	find an unused handle and try and log back into the old device,
	preserving our original virtual target id assignment.
	
	Finally, we have to mark this device as "CHANGED" so that later,
	in isp_pdb_sync, we could apply a policy of disbelieving
	that CHANGED devices are the same.

Affected files ...

.. //depot/projects/newisp/dev/isp/isp.c#14 edit

Differences ...

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

@@ -65,8 +65,8 @@
  * Local static data
  */
 static const char fconf[] =
-    "portdb[%d] confusion: 0x%x,0x%x 0x%x,0x%x, 0x%08x%08x/0x%08x%08x, "
-    "0x%08x%08x/0x%08x%08x";
+    "PortDB[%d] changed:\n current =(0x%x at 0x%06x 0x%08x%08x 0x%08x%08x)\n"
+    " database=(0x%x at 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 xact1[] =
@@ -122,6 +122,7 @@
 static int isp_gid_ft_sns(ispsoftc_t *);
 static int isp_gid_ft_ct_passthru(ispsoftc_t *);
 static int isp_scan_fabric(ispsoftc_t *);
+static int isp_login_device(ispsoftc_t *, uint32_t, isp_pdb_t *, uint16_t *);
 static int isp_register_fc4_type(ispsoftc_t *);
 static int isp_register_fc4_type_24xx(ispsoftc_t *);
 static uint16_t isp_nxt_handle(ispsoftc_t *, uint16_t);
@@ -1999,15 +2000,36 @@
 	int i;
 
 	for (i = 0; i < MAX_FC_TARG; i++) {
+		char mb[4];
+		const char *dbs[8] = {
+			"NIL ",
+			"PROB",
+			"DEAD",
+			"CHGD",
+			"NEW ",
+			"PVLD",
+			"????",
+			"VLD "
+		};
+		const char *roles[4] = {
+			" UNK", " TGT", " INI", "TINI"
+		};
 		fcportdb_t *lp = &fcp->portdb[i];
+
 		if (lp->state == FC_PORTDB_STATE_NIL) {
 			continue;
 		}
-		isp_prt(isp, ISP_LOGALL, "%d: state %d al %d tgt %d role 0x%x"
-		    " PortID 0x%06x nr %x np 0x%06x WWNN 0x%08x%08x WWPN "
-		    "0x%08x%08x", i, lp->state, lp->autologin,
-		    ((int) lp->ini_map_idx) - 1, lp->roles, lp->portid,
-		    lp->new_roles, lp->new_portid,
+		if (lp->ini_map_idx) {
+			SNPRINTF(mb, sizeof (mb), "%3d",
+			    ((int) lp->ini_map_idx) - 1);
+		} else {
+			SNPRINTF(mb, sizeof (mb), "---");
+		}
+		isp_prt(isp, ISP_LOGALL, "%d: %s al%d tgt %s %s 0x%06x =>%s"
+		    " 0x%06x; WWNN 0x%08x%08x WWPN 0x%08x%08x", i,
+		    dbs[lp->state], lp->autologin, mb,
+		    roles[lp->roles], lp->portid,
+		    roles[lp->new_roles], lp->new_portid,
 		    (uint32_t) (lp->node_wwn >> 32),
 		    (uint32_t) (lp->node_wwn),
 		    (uint32_t) (lp->port_wwn >> 32),
@@ -3306,12 +3328,11 @@
 	 * WWNN/WWPN duple, we enter the device into our database.
 	 */
 
-
 	for (portidx = 0; portidx < portlim; portidx++) {
 		fcportdb_t *lp;
 		isp_pdb_t pdb;
 		uint64_t wwnn, wwpn;
-		int base, dbidx, r, nr, lim;
+		int dbidx, r, nr;
 
 		portid =
 		    ((rs1->snscb_ports[portidx].portid[0]) << 16) |
@@ -3351,9 +3372,10 @@
 
 		/*
 		 * We found a probational entry with this Port ID.
-		 *
 		 */
 		if (dbidx < MAX_FC_TARG) {
+			int handle_changed = 0;
+
 			lp = &fcp->portdb[dbidx];
 
 			/*
@@ -3388,11 +3410,9 @@
 
 			/*
 			 * Check to make sure that handle, portid, WWPN and
-			 * WWNN agree. If they don't, things have gotten
-			 * messed up because we can only have gotten here if
-			 * we're logged into this device at this portid with
-			 * this handle at this WWNN && WPPN, so treat the
-			 * device as dead.
+			 * 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);
@@ -3400,18 +3420,48 @@
 			    pdb.portid != portid ||
 			    wwpn != lp->port_wwn ||
 			    wwnn != lp->node_wwn) {
-				isp_prt(isp, ISP_LOGERR, fconf, dbidx,
-				    pdb.handle, lp->handle, pdb.portid,
-				    portid, (uint32_t) (wwpn >> 32),
-				    (uint32_t) wwpn, (uint32_t) (wwnn >> 32),
-				    (uint32_t) wwnn,
+				isp_prt(isp, ISP_LOGDEBUG0, fconf, 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,
-				    (uint32_t) (lp->node_wwn >> 32),
-				    (uint32_t) lp->node_wwn);
-				lp->new_portid = portid;
-				lp->state = FC_PORTDB_STATE_DEAD;
-				continue;
+				    (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 (isp_login_device(isp, portid, &pdb,
+				    &oldhandle)) {
+					lp->new_portid = portid;
+					lp->state = FC_PORTDB_STATE_DEAD;
+					if (fcp->isp_loopstate !=
+					    LOOP_SCANNING_FABRIC) {
+						FC_SCRATCH_RELEASE(isp);
+						isp_mark_portdb(isp, 1);
+						return (-1);
+					}
+					continue;
+				}
+				MAKE_WWN_FROM_NODE_NAME(wwnn, pdb.nodename);
+				MAKE_WWN_FROM_NODE_NAME(wwpn, pdb.portname);
+				if (wwpn != lp->port_wwn ||
+				    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++;
 			}
 
 			nr = (pdb.s3_role & SVC3_ROLE_MASK) >> SVC3_ROLE_SHIFT;
@@ -3430,7 +3480,8 @@
 
 			lp->new_portid = portid;
 			lp->new_roles = nr;
-			if (pdb.portid != lp->portid || nr != lp->roles) {
+			if (pdb.portid != lp->portid || nr != lp->roles ||
+			    handle_changed) {
 				lp->state = FC_PORTDB_STATE_CHANGED;
 			} else {
 				lp->state = FC_PORTDB_STATE_PENDING_VALID;
@@ -3466,13 +3517,7 @@
 		/*
 		 * Find an empty database entry for it.
 		 */
-		if (fcp->isp_topo == TOPO_FL_PORT) {
-			base = SNS_ID+1;
-		} else {
-			base = 0;
-		}
-		
-		for (dbidx = base; dbidx < MAX_FC_TARG; dbidx++) {
+		for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) {
 			if (dbidx >= FL_ID && dbidx <= SNS_ID) {
 				continue;
 			}
@@ -3488,97 +3533,13 @@
 			continue;
 		}
 
-		if (IS_24XX(isp)) {
-			lim = 0xffff;
-		} else {
-			lim = MAX_FC_TARG;
-		}
-		handle = isp_nxt_handle(isp, oldhandle);
-		for (r = 0; r < lim; r++) {
-			int logval;
-
-			/*
-			 * See if we're still logged into something with
-			 * this handle and that something agrees with this
-			 * port id.
-			 */
-			r = isp_getpdb(isp, handle, &pdb, 0);
-			if (r == 0 && pdb.portid != portid) {
-				if (IS_24XX(isp)) {
-					logval =
-					    PLOGX_FLG_CMD_LOGO |
-					    PLOGX_FLG_IMPLICIT;
-					isp_plogx_24xx(isp, handle, portid,
-					    &logval);
-				} else {
-					isp_port_logout(isp, handle, portid);
-				}
-			} else if (r == 0) {
-				break;
-			}
-			if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) {
-				FC_SCRATCH_RELEASE(isp);
-				isp_mark_portdb(isp, 1);
-				return (-1);
-			}
-
-			/*
-			 * Now try and log into the device
-			 */
-			if (IS_24XX(isp)) {
-				logval = PLOGX_FLG_CMD_PLOGI;
-				isp_plogx_24xx(isp, handle, portid, &logval);
-			} else {
-				logval = isp_port_login(isp, handle, portid);
-			}
-			if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) {
-				FC_SCRATCH_RELEASE(isp);
-				isp_mark_portdb(isp, 1);
-				return (-1);
-			}
-			if (logval == 0) {
-				oldhandle = handle;
-				break;
-			} else if ((logval & 0xffff) == MBOX_PORT_ID_USED) {
-				handle = logval >> 16;
-				break;
-			} else if (logval != MBOX_LOOP_ID_USED) {
-				r = lim;
-				break;
-			} else {
-				oldhandle = handle;
-				handle = isp_nxt_handle(isp, oldhandle);
-			}
-		}
-
-		if (r == lim) {
-			isp_prt(isp, ISP_LOGERR,
-			    "could not log PortID 0x%06x in", portid);
-			continue;
-		}
-
 		/*
-		 * If we successfully logged into it, get the PDB for it
-		 * so we can crosscheck that it is still what we think it
-		 * is and that we also have the role it plays
+		 * Try to log into this device.
+		 *
+		 * isp_login_device will check for handle and
+		 * portid consistency after login.
 		 */
-		r = isp_getpdb(isp, handle, &pdb, 0);
-		if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) {
-			FC_SCRATCH_RELEASE(isp);
-			isp_mark_portdb(isp, 1);
-			return (-1);
-		}
-		if (r != 0) {
-			isp_prt(isp, ISP_LOGERR,
-			    "new device 0x%06x at 0x%x disappeared",
-			    portid, handle);
-			continue;
-		}
-
-		if (pdb.handle != handle || pdb.portid != portid) {
-			isp_prt(isp, ISP_LOGERR,
-			    "new device 0x%06x at 0x%x changed (0x%06x at 0x%0x",
-			    portid, handle, pdb.portid, pdb.handle);
+		if (isp_login_device(isp, portid, &pdb, &oldhandle)) {
 			if (fcp->isp_loopstate != LOOP_SCANNING_FABRIC) {
 				FC_SCRATCH_RELEASE(isp);
 				isp_mark_portdb(isp, 1);
@@ -3587,6 +3548,7 @@
 			continue;
 		}
 
+		handle = pdb.handle;
 		MAKE_WWN_FROM_NODE_NAME(wwnn, pdb.nodename);
 		MAKE_WWN_FROM_NODE_NAME(wwpn, pdb.portname);
 		nr = (pdb.s3_role & SVC3_ROLE_MASK) >> SVC3_ROLE_SHIFT;
@@ -3641,6 +3603,100 @@
 	return (0);
 }
 
+/*
+ * Find an unused handle and try and use to login to a port.
+ */
+static int
+isp_login_device(ispsoftc_t *isp, uint32_t portid, isp_pdb_t *p, uint16_t *ohp)
+{
+	int lim, r, logval;
+	uint16_t handle;
+
+	if (IS_24XX(isp)) {
+		lim = 0xffff;
+	} else {
+		lim = MAX_FC_TARG;
+	}
+
+	handle = isp_nxt_handle(isp, *ohp);
+	for (r = 0; r < lim; r++) {
+		/*
+		 * See if we're still logged into something with
+		 * this handle and that something agrees with this
+		 * port id.
+		 */
+		r = isp_getpdb(isp, handle, p, 0);
+		if (r == 0 && p->portid != portid) {
+			if (IS_24XX(isp)) {
+				logval =
+				    PLOGX_FLG_CMD_LOGO |
+				    PLOGX_FLG_IMPLICIT;
+				isp_plogx_24xx(isp, handle, portid, &logval);
+			} else {
+				isp_port_logout(isp, handle, portid);
+			}
+		} else if (r == 0) {
+			break;
+		}
+		if (FCPARAM(isp)->isp_loopstate != LOOP_SCANNING_FABRIC) {
+			return (-1);
+		}
+		/*
+		 * Now try and log into the device
+		 */
+		if (IS_24XX(isp)) {
+			logval = PLOGX_FLG_CMD_PLOGI;
+			isp_plogx_24xx(isp, handle, portid, &logval);
+		} else {
+			logval = isp_port_login(isp, handle, portid);
+		}
+		if (FCPARAM(isp)->isp_loopstate != LOOP_SCANNING_FABRIC) {
+			return (-1);
+		}
+		if (logval == 0) {
+			*ohp = handle;
+			break;
+		} else if ((logval & 0xffff) == MBOX_PORT_ID_USED) {
+			handle = logval >> 16;
+			break;
+		} else if (logval != MBOX_LOOP_ID_USED) {
+			r = lim;
+			break;
+		} else {
+			*ohp = handle;
+			handle = isp_nxt_handle(isp, *ohp);
+		}
+	}
+
+	if (r == lim) {
+		isp_prt(isp, ISP_LOGERR, "PLOGI 0x%06x failed", portid);
+		return (-1);
+	}
+
+	/*
+	 * If we successfully logged into it, get the PDB for it
+	 * so we can crosscheck that it is still what we think it
+	 * is and that we also have the role it plays
+	 */
+	r = isp_getpdb(isp, handle, p, 0);
+	if (FCPARAM(isp)->isp_loopstate != LOOP_SCANNING_FABRIC) {
+		return (-1);
+	}
+	if (r != 0) {
+		isp_prt(isp, ISP_LOGERR, "new device 0x%06x at 0x%x disappeared",
+		    portid, handle);
+		return (-1);
+	}
+
+	if (p->handle != handle || p->portid != portid) {
+		isp_prt(isp, ISP_LOGERR,
+		    "new device 0x%06x at 0x%x changed (0x%06x at 0x%0x",
+		    portid, handle, p->portid, p->handle);
+		return (-1);
+	}
+	return (0);
+}
+
 static int
 isp_register_fc4_type(ispsoftc_t *isp)
 {


More information about the p4-projects mailing list