From owner-svn-src-stable-10@FreeBSD.ORG Tue Feb 3 22:49:13 2015 Return-Path: Delivered-To: svn-src-stable-10@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id B7104C97; Tue, 3 Feb 2015 22:49:13 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id A0777AC8; Tue, 3 Feb 2015 22:49:13 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t13MnD8m022639; Tue, 3 Feb 2015 22:49:13 GMT (envelope-from ken@FreeBSD.org) Received: (from ken@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t13MnCQV022632; Tue, 3 Feb 2015 22:49:12 GMT (envelope-from ken@FreeBSD.org) Message-Id: <201502032249.t13MnCQV022632@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: ken set sender to ken@FreeBSD.org using -f From: "Kenneth D. Merry" Date: Tue, 3 Feb 2015 22:49:12 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r278171 - stable/10/sys/dev/isp X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable-10@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: SVN commit messages for only the 10-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 03 Feb 2015 22:49:13 -0000 Author: ken Date: Tue Feb 3 22:49:12 2015 New Revision: 278171 URL: https://svnweb.freebsd.org/changeset/base/278171 Log: MFC isp(4) driver changes: r276839, r276842, r277513, r277514, r277515 ------------------------------------------------------------------------ r276839 | ken | 2015-01-08 10:41:28 -0700 (Thu, 08 Jan 2015) | 49 lines 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 ------------------------------------------------------------------------ r276842 | ken | 2015-01-08 10:51:12 -0700 (Thu, 08 Jan 2015) | 44 lines Close a race in the isp(4) driver that caused devices to disappear and not automatically come back if they were gone for a short period of time. The isp(4) driver has a 30 second gone device timer that gets activated whenever a device goes away. If the device comes back before the timer expires, we don't send a notification to CAM that it has gone away. If, however, there is a command sent to the device while it is gone and before it comes back, the isp(4) driver sends the command back with CAM_SEL_TIMEOUT status. CAM responds to the CAM_SEL_TIMEOUT status by removing the device. In the case where a device comes back within the 30 second gone device timer window, though, we weren't telling CAM the device came back. So, fix this by tracking whether we have told CAM the device is gone, and if we have, send a rescan if it comes back within the 30 second window. ispvar.h: In the fcportdb_t structure, add a new bitfield, reported_gone. This gets set whenever we return a command with CAM_SEL_TIMEOUT status on a Fibre Channel device. isp_freebsd.c: In isp_done(), if we're sending CAM_SEL_TIMEOUT for for a command sent to a FC device, set the reported_gone bit. In isp_async(), in the ISPASYNC_DEV_STAYED case, rescan the device in question if it is mapped to a target ID and has been reported gone. In isp_make_here(), take a port database entry argument, and clear the reported_gone bit when we send a rescan to CAM. In isp_make_gone(), take a port database entry as an argument, and set the reported_gone bit when we send an async event telling CAM consumers that the device is gone. Sponsored by: Spectra Logic MFC after: 1 week ------------------------------------------------------------------------ r277514 | will | 2015-01-21 13:27:11 -0700 (Wed, 21 Jan 2015) | 18 lines Force commit to record the correct log for r277513. If the user sends an XPT_RESET_DEV CCB, make sure to reset the Fibre Channel Command Reference Number if we're running on a FC controller. We send a SCSI Target Reset when we get this CCB, and as a result need to reset the CRN to 1 on the next command. isp_freebsd.c: In the XPT_RESET_DEV implementation in isp_action(), reset the CRN if we're on a FC controller. Submitted by: ken MFC after: 1 week Sponsored by: Spectra Logic MFSpectraBSD: 1112787 on 2015/01/15 ------------------------------------------------------------------------ r277515 | will | 2015-01-21 13:32:36 -0700 (Wed, 21 Jan 2015) | 25 lines Fix SCSI status byte reporting on 4Gb and 8Gb Qlogic boards. The newer boards don't have the response field that indicates whether the SCSI status byte is present. You have to just look to see whether it is non-zero. The code was looking to see whether the sense length was valid before propagating the SCSI status byte (and sense information) up the stack. With a status like Reservation Conflict, there is no sense information, only the SCSI status byte. So it wasn't getting correctly returned. isp.c: In isp_intr(), if we are on a 2400 or 2500 type board and get a response, look at the actual contents of the SCSI status value and set the RQSF_GOT_STATUS flag accordingly so that return any SCSI status value we get. The RQSF_GOT_SENSE flag will get set later on if there is actual sense information returned. Submitted by: ken MFC after: 1 week Sponsored by: Spectra Logic MFSpectraBSD: 1112791 on 2015/01/15 ------------------------------------------------------------------------ Sponsored by: Spectra Logic Modified: stable/10/sys/dev/isp/isp.c stable/10/sys/dev/isp/isp_freebsd.c stable/10/sys/dev/isp/isp_freebsd.h stable/10/sys/dev/isp/ispvar.h Directory Properties: stable/10/ (props changed) Modified: stable/10/sys/dev/isp/isp.c ============================================================================== --- stable/10/sys/dev/isp/isp.c Tue Feb 3 22:18:48 2015 (r278170) +++ stable/10/sys/dev/isp/isp.c Tue Feb 3 22:49:12 2015 (r278171) @@ -5224,7 +5224,10 @@ again: } scsi_status = sp2->req_scsi_status; completion_status = sp2->req_completion_status; - req_state_flags = 0; + if ((scsi_status & 0xff) != 0) + req_state_flags = RQSF_GOT_STATUS; + else + req_state_flags = 0; resid = sp2->req_resid; } else if (etype == RQSTYPE_RESPONSE) { isp_get_response(isp, (ispstatusreq_t *) hp, sp); Modified: stable/10/sys/dev/isp/isp_freebsd.c ============================================================================== --- stable/10/sys/dev/isp/isp_freebsd.c Tue Feb 3 22:18:48 2015 (r278170) +++ stable/10/sys/dev/isp/isp_freebsd.c Tue Feb 3 22:49:12 2015 (r278171) @@ -29,6 +29,7 @@ */ #include __FBSDID("$FreeBSD$"); + #include #include #include @@ -4538,7 +4539,7 @@ isp_watchdog(void *arg) } static void -isp_make_here(ispsoftc_t *isp, int chan, int tgt) +isp_make_here(ispsoftc_t *isp, fcportdb_t *fcp, int chan, int tgt) { union ccb *ccb; struct isp_fc *fc = ISP_FC_PC(isp, chan); @@ -4561,11 +4562,18 @@ isp_make_here(ispsoftc_t *isp, int chan, xpt_free_ccb(ccb); return; } + + /* + * Since we're about to issue a rescan, mark this device as not + * reported gone. + */ + fcp->reported_gone = 0; + xpt_rescan(ccb); } static void -isp_make_gone(ispsoftc_t *isp, int chan, int tgt) +isp_make_gone(ispsoftc_t *isp, fcportdb_t *fcp, int chan, int tgt) { struct cam_path *tp; struct isp_fc *fc = ISP_FC_PC(isp, chan); @@ -4574,6 +4582,11 @@ isp_make_gone(ispsoftc_t *isp, int chan, return; } if (xpt_create_path(&tp, NULL, cam_sim_path(fc->sim), tgt, CAM_LUN_WILDCARD) == CAM_REQ_CMP) { + /* + * We're about to send out the lost device async + * notification, so indicate that we have reported it gone. + */ + fcp->reported_gone = 1; xpt_async(AC_LOST_DEVICE, tp, NULL); xpt_free_path(tp); } @@ -4627,7 +4640,7 @@ isp_gdt_task(void *arg, int pending) lp->dev_map_idx = 0; lp->state = FC_PORTDB_STATE_NIL; isp_prt(isp, ISP_LOGCONFIG, prom3, chan, lp->portid, tgt, "Gone Device Timeout"); - isp_make_gone(isp, chan, tgt); + isp_make_gone(isp, lp, chan, tgt); } if (fc->ready) { if (more_to_do) { @@ -4720,7 +4733,7 @@ isp_ldt_task(void *arg, int pending) lp->dev_map_idx = 0; lp->state = FC_PORTDB_STATE_NIL; isp_prt(isp, ISP_LOGCONFIG, prom3, chan, lp->portid, tgt, "Loop Down Timeout"); - isp_make_gone(isp, chan, tgt); + isp_make_gone(isp, lp, chan, tgt); } if (FCPARAM(isp, chan)->role & ISP_ROLE_INITIATOR) { @@ -5082,19 +5095,34 @@ isp_action(struct cam_sim *sim, union cc break; #endif case XPT_RESET_DEV: /* BDR the specified SCSI device */ + { + struct isp_fc *fc; bus = cam_sim_bus(xpt_path_sim(ccb->ccb_h.path)); tgt = ccb->ccb_h.target_id; tgt |= (bus << 16); + if (IS_FC(isp)) + fc = ISP_FC_PC(isp, bus); + else + fc = NULL; error = isp_control(isp, ISPCTL_RESET_DEV, bus, tgt); if (error) { ccb->ccb_h.status = CAM_REQ_CMP_ERR; } else { + /* + * If we have a FC device, reset the Command + * Reference Number, because the target will expect + * that we re-start the CRN at 1 after a reset. + */ + if (fc != NULL) + isp_fcp_reset_crn(fc, tgt, /*tgt_set*/ 1); + ccb->ccb_h.status = CAM_REQ_CMP; } xpt_done(ccb); break; + } case XPT_ABORT: /* Abort the specified CCB */ { union ccb *accb = ccb->cab.abort_ccb; @@ -5532,6 +5560,21 @@ isp_done(XS_T *sccb) if (status != CAM_REQ_CMP) { if (status != CAM_SEL_TIMEOUT) isp_prt(isp, ISP_LOGDEBUG0, "target %d lun %d CAM status 0x%x SCSI status 0x%x", XS_TGT(sccb), XS_LUN(sccb), sccb->ccb_h.status, sccb->scsi_status); + else if ((IS_FC(isp)) + && (XS_TGT(sccb) < MAX_FC_TARG)) { + fcparam *fcp; + int hdlidx; + + fcp = FCPARAM(isp, XS_CHANNEL(sccb)); + hdlidx = fcp->isp_dev_map[XS_TGT(sccb)] - 1; + /* + * Note that we have reported that this device is + * gone. If it reappears, we'll need to issue a + * rescan. + */ + if (hdlidx > 0 && hdlidx < MAX_FC_TARG) + fcp->portdb[hdlidx].reported_gone = 1; + } if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { sccb->ccb_h.status |= CAM_DEV_QFRZN; xpt_freeze_devq(sccb->ccb_h.path, 1); @@ -5667,6 +5710,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; } @@ -5718,7 +5763,8 @@ 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_make_here(isp, bus, tgt); + isp_fcp_reset_crn(fc, tgt, /*tgt_set*/ 1); + isp_make_here(isp, lp, 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); } @@ -5738,7 +5784,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cm FCPARAM(isp, bus)->isp_dev_map[tgt] = 0; lp->dev_map_idx = 0; isp_prt(isp, ISP_LOGCONFIG, prom3, bus, lp->portid, tgt, "change is bad"); - isp_make_gone(isp, bus, tgt); + isp_make_gone(isp, lp, bus, tgt); } else { isp_gen_role_str(buf, sizeof (buf), lp->prli_word3); isp_prt(isp, ISP_LOGCONFIG, prom0, bus, lp->portid, lp->handle, buf, "changed and departed", @@ -5754,6 +5800,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); } @@ -5766,9 +5813,19 @@ 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); + /* + * Only issue a rescan if we've actually reported + * that this device is gone. + */ + if (lp->reported_gone != 0) { + isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, buf, "rescanned at", tgt, + (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn); + isp_make_here(isp, lp, bus, tgt); + } } else { isp_prt(isp, ISP_LOGCONFIG, prom0, bus, lp->portid, lp->handle, buf, "stayed", (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn); @@ -5800,6 +5857,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); } @@ -6346,6 +6404,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: stable/10/sys/dev/isp/isp_freebsd.h ============================================================================== --- stable/10/sys/dev/isp/isp_freebsd.h Tue Feb 3 22:18:48 2015 (r278170) +++ stable/10/sys/dev/isp/isp_freebsd.h Tue Feb 3 22:49:12 2015 (r278171) @@ -748,6 +748,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 *); /* Modified: stable/10/sys/dev/isp/ispvar.h ============================================================================== --- stable/10/sys/dev/isp/ispvar.h Tue Feb 3 22:18:48 2015 (r278170) +++ stable/10/sys/dev/isp/ispvar.h Tue Feb 3 22:49:12 2015 (r278171) @@ -421,7 +421,8 @@ typedef struct { target_mode : 1, portid : 24; uint32_t - : 6, + : 5, + reported_gone : 1, announced : 1, dirty : 1, /* commands have been run */ new_portid : 24;