diff options
author | mjacob <mjacob@FreeBSD.org> | 2010-02-18 18:35:09 +0000 |
---|---|---|
committer | mjacob <mjacob@FreeBSD.org> | 2010-02-18 18:35:09 +0000 |
commit | 9931d796aceeb9642bb924fbe31f6703f892ce41 (patch) | |
tree | 9ec071066a652725c222671328b9734d87a0d07d /sys/dev/isp | |
parent | a7b90d4600d4de5685ca5ab24fc3c007daec91db (diff) | |
download | FreeBSD-src-9931d796aceeb9642bb924fbe31f6703f892ce41.zip FreeBSD-src-9931d796aceeb9642bb924fbe31f6703f892ce41.tar.gz |
Don't try and re-use a handle, even if the firmware tells you that's what is logged in.
PR: kern/144026
MFC after: 1 week
Diffstat (limited to 'sys/dev/isp')
-rw-r--r-- | sys/dev/isp/isp.c | 63 |
1 files changed, 33 insertions, 30 deletions
diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c index 1945e4f..33ba5ec 100644 --- a/sys/dev/isp/isp.c +++ b/sys/dev/isp/isp.c @@ -2182,9 +2182,7 @@ isp_plogx(ispsoftc_t *isp, int chan, uint16_t handle, uint32_t portid, int flags msg = "no Exchange Control Block"; break; case PLOGX_IOCBERR_FAILED: - ISP_SNPRINTF(buf, sizeof (buf), - "reason 0x%x (last LOGIN state 0x%x)", - parm1 & 0xff, (parm1 >> 8) & 0xff); + ISP_SNPRINTF(buf, sizeof (buf), "reason 0x%x (last LOGIN state 0x%x)", parm1 & 0xff, (parm1 >> 8) & 0xff); msg = buf; break; case PLOGX_IOCBERR_NOFABRIC: @@ -2194,8 +2192,7 @@ isp_plogx(ispsoftc_t *isp, int chan, uint16_t handle, uint32_t portid, int flags msg = "firmware not ready"; break; case PLOGX_IOCBERR_NOLOGIN: - ISP_SNPRINTF(buf, sizeof (buf), "not logged in (last state 0x%x)", - parm1); + ISP_SNPRINTF(buf, sizeof (buf), "not logged in (last state 0x%x)", parm1); msg = buf; rval = MBOX_NOT_LOGGED_IN; break; @@ -2207,21 +2204,18 @@ isp_plogx(ispsoftc_t *isp, int chan, uint16_t handle, uint32_t portid, int flags msg = "no PCB allocated"; break; case PLOGX_IOCBERR_EINVAL: - ISP_SNPRINTF(buf, sizeof (buf), "invalid parameter at offset 0x%x", - parm1); + ISP_SNPRINTF(buf, sizeof (buf), "invalid parameter at offset 0x%x", parm1); msg = buf; break; case PLOGX_IOCBERR_PORTUSED: lev = ISP_LOGSANCFG|ISP_LOGDEBUG0; - ISP_SNPRINTF(buf, sizeof (buf), - "already logged in with N-Port handle 0x%x", parm1); + ISP_SNPRINTF(buf, sizeof (buf), "already logged in with N-Port handle 0x%x", parm1); msg = buf; rval = MBOX_PORT_ID_USED | (parm1 << 16); break; case PLOGX_IOCBERR_HNDLUSED: lev = ISP_LOGSANCFG|ISP_LOGDEBUG0; - ISP_SNPRINTF(buf, sizeof (buf), - "handle already used for PortID 0x%06x", parm1); + ISP_SNPRINTF(buf, sizeof (buf), "handle already used for PortID 0x%06x", parm1); msg = buf; rval = MBOX_LOOP_ID_USED; break; @@ -2232,15 +2226,12 @@ isp_plogx(ispsoftc_t *isp, int chan, uint16_t handle, uint32_t portid, int flags msg = "no FLOGI_ACC"; break; default: - ISP_SNPRINTF(buf, sizeof (buf), "status %x from %x", - plp->plogx_status, flags); + ISP_SNPRINTF(buf, sizeof (buf), "status %x from %x", plp->plogx_status, flags); msg = buf; break; } if (msg) { - isp_prt(isp, ISP_LOGERR, - "Chan %d PLOGX PortID 0x%06x to N-Port handle 0x%x: %s", - chan, portid, handle, msg); + isp_prt(isp, ISP_LOGERR, "Chan %d PLOGX PortID 0x%06x to N-Port handle 0x%x: %s", chan, portid, handle, msg); } out: if (gs == 0) { @@ -3901,8 +3892,7 @@ isp_scan_fabric(ispsoftc_t *isp, int chan) * Find an unused handle and try and use to login to a port. */ static int -isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p, - uint16_t *ohp) +isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p, uint16_t *ohp) { int lim, i, r; uint16_t handle; @@ -3922,8 +3912,7 @@ isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p, */ 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, 1); + (void) isp_plogx(isp, chan, handle, portid, PLOGX_FLG_CMD_LOGO | PLOGX_FLG_IMPLICIT | PLOGX_FLG_FREE_NPHDL, 1); } else if (r == 0) { break; } @@ -3933,8 +3922,7 @@ isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p, /* * Now try and log into the device */ - r = isp_plogx(isp, chan, handle, portid, - PLOGX_FLG_CMD_PLOGI, 1); + r = isp_plogx(isp, chan, handle, portid, PLOGX_FLG_CMD_PLOGI, 1); if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC) { return (-1); } @@ -3942,7 +3930,26 @@ isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p, *ohp = handle; break; } else if ((r & 0xffff) == MBOX_PORT_ID_USED) { - handle = r >> 16; + /* + * If we get here, then the firmwware still thinks we're logged into this device, but with a different + * handle. We need to break that association. We used to try and just substitute the handle, but then + * failed to get any data via isp_getpdb (below). + */ + 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) { + 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) { + *ohp = handle; + } else { + i = lim; + } break; } else if (r != MBOX_LOOP_ID_USED) { i = lim; @@ -3956,8 +3963,7 @@ isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p, } if (i == lim) { - isp_prt(isp, ISP_LOGWARN, "Chan %d PLOGI 0x%06x failed", - chan, portid); + isp_prt(isp, ISP_LOGWARN, "Chan %d PLOGI 0x%06x failed", chan, portid); return (-1); } @@ -3971,15 +3977,12 @@ isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p, return (-1); } if (r != 0) { - isp_prt(isp, ISP_LOGERR, - "Chan %d new device 0x%06x@0x%x disappeared", - chan, portid, handle); + isp_prt(isp, ISP_LOGERR, "Chan %d new device 0x%06x@0x%x disappeared", chan, portid, handle); return (-1); } if (p->handle != handle || p->portid != portid) { - isp_prt(isp, ISP_LOGERR, - "Chan %d new device 0x%06x@0x%x changed (0x%06x@0x%0x)", + isp_prt(isp, ISP_LOGERR, "Chan %d new device 0x%06x@0x%x changed (0x%06x@0x%0x)", chan, portid, handle, p->portid, p->handle); return (-1); } |