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

Kenneth D. Merry ken at FreeBSD.org
Thu Jan 8 17:41:30 UTC 2015


Author: ken
Date: Thu Jan  8 17:41:28 2015
New Revision: 276839
URL: https://svnweb.freebsd.org/changeset/base/276839

Log:
  Fix Fibre Channel Command Reference Number handling in the isp(4) driver.
  
  The Command Reference Number is used for precise delivery of
  commands, and is part of the FC-Tape functionality set.  (This is
  only enabled for devices that support precise delivery of commands.)
  It is an 8-bit unsigned number that increments from 1 to 255.  The
  commands sent by the initiator must be processed by the target in
  CRN order if the CRN is non-zero.
  
  There are certain scenarios where the Command Reference Number
  sequence needs to be reset.  When the target is power cycled, for
  instance, the initiator needs to reset the CRN to 1.  The initiator
  will know this because it will see a LIP (when directly connected)
  or get a logout/login event (when connected to a switch).
  
  The isp(4) driver was not resetting the CRN when a target
  went away and came back.  When it saw the target again after a
  power cycle, it would continue the CRN sequence where it left off.
  The target would ignore the command because the CRN sequence is
  supposed to be reset to 1 after a power cycle or other similar
  event.
  
  The symptom that the user would see is that there would be lots of
  aborted INQUIRY commands after a tape library was power cycled, and
  the library would fail to probe.  The INQUIRY commands were being
  ignored by the tape drive due to the CRN issue mentioned above.
  
  isp_freebsd.c:
  	Add a new function, isp_fcp_reset_crn().  This will reset
  	all of the CRNs for a given port, or the CRNs for all LUNs
  	on a target.
  
  	Reset the CRNs for all targets on a port when we get a LIP,
  	loop reset, or loop down event.
  
  	Reset the CRN for a particular target when it arrives, is changed
  	or departs.  This is less precise behavior than the
  	clearing behavior specified in the FCP-4 spec (which says
  	that it should be reset for PRLI, PRLO, PLOGI and LOGO),
  	but this is the level of information we have here.  If this
  	is insufficient, then we will need to add more precise
  	notification from the lower level isp(4) code.
  
  isp_freebsd.h:
  	Add a prototype for isp_fcp_reset_crn().
  
  Sponsored by:	Spectra Logic
  MFC after:	1 week

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 Jan  8 17:38:03 2015	(r276838)
+++ head/sys/dev/isp/isp_freebsd.c	Thu Jan  8 17:41:28 2015	(r276839)
@@ -5696,6 +5696,8 @@ isp_async(ispsoftc_t *isp, ispasync_t cm
 				}
 			}
 		}
+		isp_fcp_reset_crn(fc, /*tgt*/0, /*tgt_set*/ 0);
+
 		isp_prt(isp, ISP_LOGINFO, "Chan %d: %s", bus, msg);
 		break;
 	}
@@ -5747,6 +5749,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cm
 		if (lp->dev_map_idx) {
 			tgt = lp->dev_map_idx - 1;
 			isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, buf, "arrived at", tgt, (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
+			isp_fcp_reset_crn(fc, tgt, /*tgt_set*/ 1);
 			isp_make_here(isp, bus, tgt);
 		} else {
 			isp_prt(isp, ISP_LOGCONFIG, prom0, bus, lp->portid, lp->handle, buf, "arrived", (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
@@ -5783,6 +5786,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cm
 				tgt = lp->dev_map_idx - 1;
 				isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, buf, "changed at", tgt,
 				    (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
+				isp_fcp_reset_crn(fc, tgt, /*tgt_set*/ 1);
 			} else {
 				isp_prt(isp, ISP_LOGCONFIG, prom0, bus, lp->portid, lp->handle, buf, "changed", (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
 			}
@@ -5795,6 +5799,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cm
 		va_end(ap);
 		isp_gen_role_str(buf, sizeof (buf), lp->prli_word3);
 		if (lp->dev_map_idx) {
+			fc = ISP_FC_PC(isp, bus);
 			tgt = lp->dev_map_idx - 1;
 			isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, buf, "stayed at", tgt,
 		    	    (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
@@ -5829,6 +5834,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cm
 			}
 			tgt = lp->dev_map_idx - 1;
 			isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, buf, "gone zombie at", tgt, (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
+			isp_fcp_reset_crn(fc, tgt, /*tgt_set*/ 1);
 		} else if (lp->announced == 0) {
 			isp_prt(isp, ISP_LOGCONFIG, prom0, bus, lp->portid, lp->handle, buf, "departed", (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
 		}
@@ -6377,6 +6383,33 @@ isp_common_dmateardown(ispsoftc_t *isp, 
 	bus_dmamap_unload(isp->isp_osinfo.dmat, PISP_PCMD(csio)->dmap);
 }
 
+/*
+ * Reset the command reference number for all LUNs on a specific target
+ * (needed when a target arrives again) or for all targets on a port
+ * (needed for events like a LIP).
+ */
+void
+isp_fcp_reset_crn(struct isp_fc *fc, uint32_t tgt, int tgt_set)
+{
+	int i;
+	struct isp_nexus *nxp;
+
+	if (tgt_set == 0)
+		isp_prt(fc->isp, ISP_LOG_SANCFG, "resetting CRN on all targets");
+	else
+		isp_prt(fc->isp, ISP_LOG_SANCFG, "resetting CRN target %u", tgt);
+
+	for (i = 0; i < NEXUS_HASH_WIDTH; i++) {
+		nxp = fc->nexus_hash[i];
+		while (nxp) {
+			if ((tgt_set != 0) && (tgt == nxp->tgt))
+				nxp->crnseed = 0;
+
+			nxp = nxp->next;
+		}
+	}
+}
+
 int
 isp_fcp_next_crn(ispsoftc_t *isp, uint8_t *crnp, XS_T *cmd)
 {

Modified: head/sys/dev/isp/isp_freebsd.h
==============================================================================
--- head/sys/dev/isp/isp_freebsd.h	Thu Jan  8 17:38:03 2015	(r276838)
+++ head/sys/dev/isp/isp_freebsd.h	Thu Jan  8 17:41:28 2015	(r276839)
@@ -754,6 +754,7 @@ int isp_fc_scratch_acquire(ispsoftc_t *,
 int isp_mstohz(int);
 void isp_platform_intr(void *);
 void isp_common_dmateardown(ispsoftc_t *, struct ccb_scsiio *, uint32_t);
+void isp_fcp_reset_crn(struct isp_fc *, uint32_t, int);
 int isp_fcp_next_crn(ispsoftc_t *, uint8_t *, XS_T *);
 
 /*


More information about the svn-src-head mailing list