diff options
| author | Kenneth D. Merry <ken@FreeBSD.org> | 2017-05-03 13:17:01 +0000 |
|---|---|---|
| committer | Kenneth D. Merry <ken@FreeBSD.org> | 2017-05-03 13:17:01 +0000 |
| commit | 57b6261f94d5b633223299f7b1e12f6ec8275baa (patch) | |
| tree | 6e9f55a6dc8ad861b4f43d2d1332ad11e3d5d784 /sys/dev/isp | |
| parent | fca08fe6a22dbe2f868bb13f9b62e775a4a57ed0 (diff) | |
Notes
Diffstat (limited to 'sys/dev/isp')
| -rw-r--r-- | sys/dev/isp/isp.c | 7 | ||||
| -rw-r--r-- | sys/dev/isp/isp_freebsd.c | 130 | ||||
| -rw-r--r-- | sys/dev/isp/ispmbox.h | 6 | ||||
| -rw-r--r-- | sys/dev/isp/ispvar.h | 4 |
4 files changed, 111 insertions, 36 deletions
diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c index c75b95ed55ec..f1fb54ad118e 100644 --- a/sys/dev/isp/isp.c +++ b/sys/dev/isp/isp.c @@ -2771,10 +2771,11 @@ isp_getpdb(ispsoftc_t *isp, int chan, uint16_t id, isp_pdb_t *pdb) pdb->portid = BITS2WORD_24XX(un.bill.pdb_portid_bits); ISP_MEMCPY(pdb->portname, un.bill.pdb_portname, 8); ISP_MEMCPY(pdb->nodename, un.bill.pdb_nodename, 8); - isp_prt(isp, ISP_LOGDEBUG1, - "Chan %d handle 0x%x Port 0x%06x flags 0x%x curstate %x", + isp_prt(isp, ISP_LOGDEBUG0, + "Chan %d handle 0x%x Port 0x%06x flags 0x%x curstate %x laststate %x", chan, id, pdb->portid, un.bill.pdb_flags, - un.bill.pdb_curstate); + un.bill.pdb_curstate, un.bill.pdb_laststate); + if (un.bill.pdb_curstate < PDB2400_STATE_PLOGI_DONE || un.bill.pdb_curstate > PDB2400_STATE_LOGGED_IN) { mbs.param[0] = MBOX_NOT_LOGGED_IN; return (mbs.param[0]); diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c index 5ce037a154c7..4b9e0b386bca 100644 --- a/sys/dev/isp/isp_freebsd.c +++ b/sys/dev/isp/isp_freebsd.c @@ -2567,8 +2567,7 @@ isp_watchdog(void *arg) } isp_destroy_handle(isp, handle); isp_prt(isp, ISP_LOGERR, "%s: timeout for handle 0x%x", __func__, handle); - xs->ccb_h.status &= ~CAM_STATUS_MASK; - xs->ccb_h.status |= CAM_CMD_TIMEOUT; + XS_SETERR(xs, CAM_CMD_TIMEOUT); isp_done(xs); } else { if (ohandle != ISP_HANDLE_FREE) { @@ -2739,9 +2738,6 @@ isp_loop_dead(ispsoftc_t *isp, int chan) if (lp->state == FC_PORTDB_STATE_NIL) continue; - /* - * XXX: CLEAN UP AND COMPLETE ANY PENDING COMMANDS FIRST! - */ for (i = 0; i < isp->isp_maxcmds; i++) { struct ccb_scsiio *xs; @@ -2757,6 +2753,25 @@ isp_loop_dead(ispsoftc_t *isp, int chan) isp_prt(isp, ISP_LOGWARN, "command handle 0x%x for %d.%d.%jx orphaned by loop down timeout", isp->isp_xflist[i].handle, chan, XS_TGT(xs), (uintmax_t)XS_LUN(xs)); + + /* + * Just like in isp_watchdog, abort the outstanding + * command or immediately free its resources if it is + * not active + */ + if (isp_control(isp, ISPCTL_ABORT_CMD, xs) == 0) { + continue; + } + + if (XS_XFRLEN(xs)) { + ISP_DMAFREE(isp, xs, isp->isp_xflist[i].handle); + } + isp_destroy_handle(isp, isp->isp_xflist[i].handle); + isp_prt(isp, ISP_LOGWARN, "command handle 0x%x for %d.%d.%jx could not be aborted and was destroyed", + isp->isp_xflist[i].handle, chan, XS_TGT(xs), + (uintmax_t)XS_LUN(xs)); + XS_SETERR(xs, HBA_BUSRESET); + isp_done(xs); } isp_prt(isp, ISP_LOGCONFIG, prom3, chan, dbidx, lp->portid, "Loop Down Timeout"); @@ -3562,7 +3577,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...) static const char prom[] = "Chan %d [%d] WWPN 0x%16jx PortID 0x%06x handle 0x%x %s %s"; char buf[64]; char *msg = NULL; - target_id_t tgt; + target_id_t tgt = 0; fcportdb_t *lp; struct isp_fc *fc; struct cam_path *tmppath; @@ -3639,30 +3654,50 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...) } break; } + case ISPASYNC_LOOP_RESET: + { + uint16_t lipp; + fcparam *fcp; + va_start(ap, cmd); + bus = va_arg(ap, int); + va_end(ap); + + lipp = ISP_READ(isp, OUTMAILBOX1); + fcp = FCPARAM(isp, bus); + + isp_prt(isp, ISP_LOGINFO, "Chan %d LOOP Reset, LIP primitive %x", bus, lipp); + /* + * Per FCP-4, a Reset LIP should result in a CRN reset. Other + * LIPs and loop up/down events should never reset the CRN. For + * an as of yet unknown reason, 24xx series cards (and + * potentially others) can interrupt with a LIP Reset status + * when no LIP reset came down the wire. Additionally, the LIP + * primitive accompanying this status would not be a valid LIP + * Reset primitive, but some variation of an invalid AL_PA + * LIP. As a result, we have to verify the AL_PD in the LIP + * addresses our port before blindly resetting. + */ + if (FCP_IS_DEST_ALPD(fcp, (lipp & 0x00FF))) + isp_fcp_reset_crn(isp, bus, /*tgt*/0, /*tgt_set*/ 0); + isp_loop_changed(isp, bus); + break; + } case ISPASYNC_LIP: if (msg == NULL) msg = "LIP Received"; /* FALLTHROUGH */ - case ISPASYNC_LOOP_RESET: - if (msg == NULL) - msg = "LOOP Reset"; - /* FALLTHROUGH */ case ISPASYNC_LOOP_DOWN: if (msg == NULL) msg = "LOOP Down"; - va_start(ap, cmd); - bus = va_arg(ap, int); - va_end(ap); - isp_fcp_reset_crn(isp, bus, /*tgt*/0, /*tgt_set*/ 0); - isp_loop_changed(isp, bus); - isp_prt(isp, ISP_LOGINFO, "Chan %d %s", bus, msg); - break; + /* FALLTHROUGH */ case ISPASYNC_LOOP_UP: + if (msg == NULL) + msg = "LOOP Up"; va_start(ap, cmd); bus = va_arg(ap, int); va_end(ap); isp_loop_changed(isp, bus); - isp_prt(isp, ISP_LOGINFO, "Chan %d Loop UP", bus); + isp_prt(isp, ISP_LOGINFO, "Chan %d %s", bus, msg); break; case ISPASYNC_DEV_ARRIVED: va_start(ap, cmd); @@ -3692,6 +3727,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...) } break; case ISPASYNC_DEV_CHANGED: + case ISPASYNC_DEV_STAYED: va_start(ap, cmd); bus = va_arg(ap, int); lp = va_arg(ap, fcportdb_t *); @@ -3699,18 +3735,23 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...) fc = ISP_FC_PC(isp, bus); tgt = FC_PORTDB_TGT(isp, bus, lp); isp_gen_role_str(buf, sizeof (buf), lp->new_prli_word3); - isp_prt(isp, ISP_LOGCONFIG, prom, bus, tgt, lp->port_wwn, lp->new_portid, lp->handle, buf, "changed"); -changed: + if (cmd == ISPASYNC_DEV_CHANGED) + isp_prt(isp, ISP_LOGCONFIG, prom, bus, tgt, lp->port_wwn, lp->new_portid, lp->handle, buf, "changed"); + else + isp_prt(isp, ISP_LOGCONFIG, prom, bus, tgt, lp->port_wwn, lp->portid, lp->handle, buf, "stayed"); + if (lp->is_target != ((FCPARAM(isp, bus)->role & ISP_ROLE_INITIATOR) && (lp->new_prli_word3 & PRLI_WD3_TARGET_FUNCTION))) { lp->is_target = !lp->is_target; if (lp->is_target) { - isp_fcp_reset_crn(isp, bus, tgt, /*tgt_set*/ 1); + if (cmd == ISPASYNC_DEV_CHANGED) + isp_fcp_reset_crn(isp, bus, tgt, /*tgt_set*/ 1); isp_make_here(isp, lp, bus, tgt); } else { isp_make_gone(isp, lp, bus, tgt); - isp_fcp_reset_crn(isp, bus, tgt, /*tgt_set*/ 1); + if (cmd == ISPASYNC_DEV_CHANGED) + isp_fcp_reset_crn(isp, bus, tgt, /*tgt_set*/ 1); } } if (lp->is_initiator != @@ -3726,16 +3767,6 @@ changed: xpt_async(AC_CONTRACT, fc->path, &ac); } break; - case ISPASYNC_DEV_STAYED: - va_start(ap, cmd); - bus = va_arg(ap, int); - lp = va_arg(ap, fcportdb_t *); - va_end(ap); - fc = ISP_FC_PC(isp, bus); - tgt = FC_PORTDB_TGT(isp, bus, lp); - isp_gen_role_str(buf, sizeof (buf), lp->prli_word3); - isp_prt(isp, ISP_LOGCONFIG, prom, bus, tgt, lp->port_wwn, lp->portid, lp->handle, buf, "stayed"); - goto changed; case ISPASYNC_DEV_GONE: va_start(ap, cmd); bus = va_arg(ap, int); @@ -3781,10 +3812,45 @@ changed: va_end(ap); if (evt == ISPASYNC_CHANGE_PDB) { + int tgt_set = 0; msg = "Port Database Changed"; isp_prt(isp, ISP_LOGINFO, "Chan %d %s (nphdl 0x%x state 0x%x reason 0x%x)", bus, msg, nphdl, nlstate, reason); + /* + * Port database syncs are not sufficient for + * determining that logins or logouts are done on the + * loop, but this information is directly available from + * the reason code from the incoming mbox. We must reset + * the fcp crn on these events according to FCP-4 + */ + switch (reason) { + case PDB24XX_AE_IMPL_LOGO_1: + case PDB24XX_AE_IMPL_LOGO_2: + case PDB24XX_AE_IMPL_LOGO_3: + case PDB24XX_AE_PLOGI_RCVD: + case PDB24XX_AE_PRLI_RCVD: + case PDB24XX_AE_PRLO_RCVD: + case PDB24XX_AE_LOGO_RCVD: + case PDB24XX_AE_PLOGI_DONE: + case PDB24XX_AE_PRLI_DONE: + /* + * If the event is not global, twiddle tgt and + * tgt_set to nominate only the target + * associated with the nphdl. + */ + if (nphdl != PDB24XX_AE_GLOBAL) { + /* Break if we don't yet have the pdb */ + if (!isp_find_pdb_by_handle(isp, bus, nphdl, &lp)) + break; + tgt = FC_PORTDB_TGT(isp, bus, lp); + tgt_set = 1; + } + isp_fcp_reset_crn(isp, bus, tgt, tgt_set); + break; + default: + break; /* NOP */ + } } else if (evt == ISPASYNC_CHANGE_SNS) { msg = "Name Server Database Changed"; isp_prt(isp, ISP_LOGINFO, "Chan %d %s (PortID 0x%06x)", diff --git a/sys/dev/isp/ispmbox.h b/sys/dev/isp/ispmbox.h index f672b429b59f..e747c5544fbc 100644 --- a/sys/dev/isp/ispmbox.h +++ b/sys/dev/isp/ispmbox.h @@ -1421,6 +1421,10 @@ typedef struct { /* * Port Database Changed Async Event information for 24XX cards */ +/* N-Port Handle */ +#define PDB24XX_AE_GLOBAL 0xFFFF + +/* Reason Codes */ #define PDB24XX_AE_OK 0x00 #define PDB24XX_AE_IMPL_LOGO_1 0x01 #define PDB24XX_AE_IMPL_LOGO_2 0x02 @@ -1440,7 +1444,7 @@ typedef struct { #define PDB24XX_AE_FLOGI_TIMO 0x10 #define PDB24XX_AE_ABX_LOGO 0x11 #define PDB24XX_AE_PLOGI_DONE 0x12 -#define PDB24XX_AE_PRLI_DONJE 0x13 +#define PDB24XX_AE_PRLI_DONE 0x13 #define PDB24XX_AE_OPN_1 0x14 #define PDB24XX_AE_OPN_2 0x15 #define PDB24XX_AE_TXERR 0x16 diff --git a/sys/dev/isp/ispvar.h b/sys/dev/isp/ispvar.h index a19430ca1261..89c132b39875 100644 --- a/sys/dev/isp/ispvar.h +++ b/sys/dev/isp/ispvar.h @@ -502,6 +502,10 @@ typedef struct { #define TOPO_IS_FABRIC(x) ((x) == TOPO_FL_PORT || (x) == TOPO_F_PORT) +#define FCP_AL_DA_ALL 0xFF +#define FCP_AL_PA(fcp) ((uint8_t)(fcp->isp_portid)) +#define FCP_IS_DEST_ALPD(fcp, alpd) (FCP_AL_PA((fcp)) == FCP_AL_DA_ALL || FCP_AL_PA((fcp)) == alpd) + /* * Soft Structure per host adapter */ |
