From owner-svn-src-stable-10@freebsd.org Mon Nov 30 21:40:21 2015 Return-Path: Delivered-To: svn-src-stable-10@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id C1BB1A3D407; Mon, 30 Nov 2015 21:40:21 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::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 606E712EC; Mon, 30 Nov 2015 21:40:21 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id tAULeKFL070583; Mon, 30 Nov 2015 21:40:20 GMT (envelope-from mav@FreeBSD.org) Received: (from mav@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id tAULeKwI070581; Mon, 30 Nov 2015 21:40:20 GMT (envelope-from mav@FreeBSD.org) Message-Id: <201511302140.tAULeKwI070581@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: mav set sender to mav@FreeBSD.org using -f From: Alexander Motin Date: Mon, 30 Nov 2015 21:40:20 +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: r291514 - 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.20 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: Mon, 30 Nov 2015 21:40:22 -0000 Author: mav Date: Mon Nov 30 21:40:20 2015 New Revision: 291514 URL: https://svnweb.freebsd.org/changeset/base/291514 Log: MFC r291080: Another round of port scanner rewrite. This change simplifies and unifies port adding/updating for loop and fabric scanners. It also fixes problems with scanning restarts due to concurrent port databases changes. It also fixes many cosmetic issues. Modified: stable/10/sys/dev/isp/isp.c stable/10/sys/dev/isp/isp_freebsd.c stable/10/sys/dev/isp/isp_library.c stable/10/sys/dev/isp/isp_library.h stable/10/sys/dev/isp/ispmbox.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 Mon Nov 30 21:39:33 2015 (r291513) +++ stable/10/sys/dev/isp/isp.c Mon Nov 30 21:40:20 2015 (r291514) @@ -68,9 +68,7 @@ __FBSDID("$FreeBSD$"); /* * Local static data */ -static const char fconf[] = "Chan %d PortDB[%d] changed:\n current =(0x%x@0x%06x 0x%08x%08x 0x%08x%08x)\n database=(0x%x@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 topology[] = "Chan %d WWPN 0x%08x%08x PortID 0x%06x LoopID 0x%x Connection '%s'"; static const char bun[] = "bad underrun (count %d, resid %d, status %s)"; static const char lipd[] = "Chan %d LIP destroyed %d active commands"; static const char sacq[] = "unable to acquire scratch area"; @@ -108,7 +106,8 @@ static void isp_scsi_init(ispsoftc_t *); static void isp_scsi_channel_init(ispsoftc_t *, int); static void isp_fibre_init(ispsoftc_t *); static void isp_fibre_init_2400(ispsoftc_t *); -static void isp_mark_portdb(ispsoftc_t *, int, int); +static void isp_clear_portdb(ispsoftc_t *, int); +static void isp_mark_portdb(ispsoftc_t *, int); static int isp_plogx(ispsoftc_t *, int, uint16_t, uint32_t, int, int); static int isp_port_login(ispsoftc_t *, uint16_t, uint32_t); static int isp_port_logout(ispsoftc_t *, uint16_t, uint32_t); @@ -2283,7 +2282,7 @@ isp_fibre_init_2400(ispsoftc_t *isp) } static void -isp_mark_portdb(ispsoftc_t *isp, int chan, int disposition) +isp_clear_portdb(ispsoftc_t *isp, int chan) { fcparam *fcp = FCPARAM(isp, chan); fcportdb_t *lp; @@ -2292,30 +2291,41 @@ isp_mark_portdb(ispsoftc_t *isp, int cha for (i = 0; i < MAX_FC_TARG; i++) { lp = &fcp->portdb[i]; switch (lp->state) { - case FC_PORTDB_STATE_PROBATIONAL: case FC_PORTDB_STATE_DEAD: case FC_PORTDB_STATE_CHANGED: - case FC_PORTDB_STATE_PENDING_VALID: case FC_PORTDB_STATE_VALID: - if (disposition > 0) - lp->state = FC_PORTDB_STATE_PROBATIONAL; - else { - lp->state = FC_PORTDB_STATE_NIL; - isp_async(isp, ISPASYNC_DEV_GONE, chan, lp); - } - break; - case FC_PORTDB_STATE_ZOMBIE: + lp->state = FC_PORTDB_STATE_NIL; + isp_async(isp, ISPASYNC_DEV_GONE, chan, lp); break; case FC_PORTDB_STATE_NIL: case FC_PORTDB_STATE_NEW: - default: - ISP_MEMZERO(lp, sizeof(*lp)); lp->state = FC_PORTDB_STATE_NIL; break; + case FC_PORTDB_STATE_ZOMBIE: + break; + default: + panic("Don't know how to clear state %d\n", lp->state); } } } +static void +isp_mark_portdb(ispsoftc_t *isp, int chan) +{ + fcparam *fcp = FCPARAM(isp, chan); + fcportdb_t *lp; + int i; + + for (i = 0; i < MAX_FC_TARG; i++) { + lp = &fcp->portdb[i]; + if (lp->state == FC_PORTDB_STATE_NIL) + continue; + if ((lp->portid & 0xfffc00) == 0xfffc00) + continue; + fcp->portdb[i].probational = 1; + } +} + /* * Perform an IOCB PLOGI or LOGO via EXECUTE IOCB A64 for 24XX cards * or via FABRIC LOGIN/FABRIC LOGOUT for other cards. @@ -2333,6 +2343,9 @@ isp_plogx(ispsoftc_t *isp, int chan, uin const char *msg; char buf[64]; + isp_prt(isp, ISP_LOG_SANCFG, "Chan %d PLOGX %s PortID 0x%06x nphdl 0x%x", + chan, (flags & PLOGX_FLG_CMD_MASK) == PLOGX_FLG_CMD_PLOGI ? + "Login":"Logout", portid, handle); if (!IS_24XX(isp)) { int action = flags & PLOGX_FLG_CMD_MASK; if (action == PLOGX_FLG_CMD_PLOGI) { @@ -2766,7 +2779,7 @@ static int isp_fclink_test(ispsoftc_t *isp, int chan, int usdelay) { mbreg_t mbs; - int r; + int i, r; uint16_t nphdl; fcparam *fcp; isp_pdb_t pdb; @@ -2774,8 +2787,8 @@ isp_fclink_test(ispsoftc_t *isp, int cha fcp = FCPARAM(isp, chan); - /* Mark port database entries for following scan. */ - isp_mark_portdb(isp, chan, 1); + /* Mark port database entries probational for following scan. */ + isp_mark_portdb(isp, chan); if (fcp->isp_loopstate >= LOOP_LTEST_DONE) return (0); @@ -2818,12 +2831,6 @@ isp_fclink_test(ispsoftc_t *isp, int cha return (-1); } - if (ISP_CAP_2KLOGIN(isp)) { - fcp->isp_loopid = mbs.param[1]; - } else { - fcp->isp_loopid = mbs.param[1] & 0xff; - } - if (IS_2100(isp)) { /* * Don't bother with fabric if we are using really old @@ -2842,30 +2849,17 @@ isp_fclink_test(ispsoftc_t *isp, int cha } fcp->isp_portid = mbs.param[2] | (mbs.param[3] << 16); - /* - * Check to make sure we got a valid loopid - * The 24XX seems to mess this up for multiple channels. - */ - if (fcp->isp_topo == TOPO_FL_PORT || fcp->isp_topo == TOPO_NL_PORT) { + if (!TOPO_IS_FABRIC(fcp->isp_topo)) { + fcp->isp_loopid = mbs.param[1] & 0xff; + } else if (fcp->isp_topo != TOPO_F_PORT) { uint8_t alpa = fcp->isp_portid; - if (alpa == 0) { - /* "Cannot Happen" */ - isp_prt(isp, ISP_LOGWARN, "Zero AL_PA for Loop Topology?"); - } else { - int i; - for (i = 0; alpa_map[i]; i++) { - if (alpa_map[i] == alpa) { - break; - } - } - if (alpa_map[i] && fcp->isp_loopid != i) { - isp_prt(isp, ISP_LOG_SANCFG, - "Chan %d Deriving loopid %d from AL_PA map (AL_PA 0x%x) and ignoring returned value %d (AL_PA 0x%x)", - chan, i, alpa_map[i], fcp->isp_loopid, alpa); - fcp->isp_loopid = i; - } + for (i = 0; alpa_map[i]; i++) { + if (alpa_map[i] == alpa) + break; } + if (alpa_map[i]) + fcp->isp_loopid = i; } if (fcp->isp_topo == TOPO_F_PORT || fcp->isp_topo == TOPO_FL_PORT) { @@ -2899,6 +2893,7 @@ isp_fclink_test(ispsoftc_t *isp, int cha } not_on_fabric: + /* Get link speed. */ fcp->isp_gbspeed = 1; if (IS_23XX(isp) || IS_24XX(isp)) { MBSINIT(&mbs, MBOX_GET_SET_DATA_RATE, MBLOGALL, 3000000); @@ -2906,27 +2901,29 @@ not_on_fabric: /* mbs.param[2] undefined if we're just getting rate */ isp_mboxcmd(isp, &mbs); if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { - if (mbs.param[1] == MBGSD_EIGHTGB) { - isp_prt(isp, ISP_LOGINFO, "Chan %d 8Gb link speed", chan); + if (mbs.param[1] == MBGSD_10GB) + fcp->isp_gbspeed = 10; + else if (mbs.param[1] == MBGSD_16GB) + fcp->isp_gbspeed = 16; + else if (mbs.param[1] == MBGSD_8GB) fcp->isp_gbspeed = 8; - } else if (mbs.param[1] == MBGSD_FOURGB) { - isp_prt(isp, ISP_LOGINFO, "Chan %d 4Gb link speed", chan); + else if (mbs.param[1] == MBGSD_4GB) fcp->isp_gbspeed = 4; - } else if (mbs.param[1] == MBGSD_TWOGB) { - isp_prt(isp, ISP_LOGINFO, "Chan %d 2Gb link speed", chan); + else if (mbs.param[1] == MBGSD_2GB) fcp->isp_gbspeed = 2; - } else if (mbs.param[1] == MBGSD_ONEGB) { - isp_prt(isp, ISP_LOGINFO, "Chan %d 1Gb link speed", chan); + else if (mbs.param[1] == MBGSD_1GB) fcp->isp_gbspeed = 1; - } } } fcp->isp_loopstate = LOOP_LTEST_DONE; - /* - * Announce ourselves, too. - */ - isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGCONFIG, topology, chan, (uint32_t) (fcp->isp_wwpn >> 32), (uint32_t) fcp->isp_wwpn, fcp->isp_portid, fcp->isp_loopid, isp_fc_toponame(fcp)); + isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGCONFIG, + "Chan %d WWPN %016jx WWNN %016jx", + chan, (uintmax_t)fcp->isp_wwpn, (uintmax_t)fcp->isp_wwnn); + isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGCONFIG, + "Chan %d %dGb %s PortID 0x%06x LoopID 0x%02x", + chan, fcp->isp_gbspeed, isp_fc_toponame(fcp), fcp->isp_portid, + fcp->isp_loopid); isp_prt(isp, ISP_LOG_SANCFG, "Chan %d FC link test done", chan); return (0); } @@ -2963,13 +2960,11 @@ isp_pdb_sync(ispsoftc_t *isp, int chan) for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { lp = &fcp->portdb[dbidx]; - if (lp->state == FC_PORTDB_STATE_NIL || - lp->state == FC_PORTDB_STATE_VALID) { + if (lp->state == FC_PORTDB_STATE_NIL) continue; - } - + if (lp->probational && lp->state != FC_PORTDB_STATE_ZOMBIE) + lp->state = FC_PORTDB_STATE_DEAD; switch (lp->state) { - case FC_PORTDB_STATE_PROBATIONAL: case FC_PORTDB_STATE_DEAD: lp->state = FC_PORTDB_STATE_NIL; isp_async(isp, ISPASYNC_DEV_GONE, chan, lp); @@ -2979,36 +2974,23 @@ isp_pdb_sync(ispsoftc_t *isp, int chan) PLOGX_FLG_CMD_LOGO | PLOGX_FLG_IMPLICIT | PLOGX_FLG_FREE_NPHDL, 0); - } else { - lp->autologin = 0; } - lp->new_prli_word3 = 0; - lp->new_portid = 0; /* * Note that we might come out of this with our state * set to FC_PORTDB_STATE_ZOMBIE. */ break; case FC_PORTDB_STATE_NEW: - lp->portid = lp->new_portid; - lp->prli_word3 = lp->new_prli_word3; lp->state = FC_PORTDB_STATE_VALID; isp_async(isp, ISPASYNC_DEV_ARRIVED, chan, lp); - lp->new_prli_word3 = 0; - lp->new_portid = 0; break; case FC_PORTDB_STATE_CHANGED: lp->state = FC_PORTDB_STATE_VALID; isp_async(isp, ISPASYNC_DEV_CHANGED, chan, lp); lp->portid = lp->new_portid; lp->prli_word3 = lp->new_prli_word3; - lp->new_prli_word3 = 0; - lp->new_portid = 0; break; - case FC_PORTDB_STATE_PENDING_VALID: - lp->portid = lp->new_portid; - lp->prli_word3 = lp->new_prli_word3; - lp->state = FC_PORTDB_STATE_VALID; + case FC_PORTDB_STATE_VALID: isp_async(isp, ISPASYNC_DEV_STAYED, chan, lp); break; case FC_PORTDB_STATE_ZOMBIE: @@ -3032,15 +3014,78 @@ isp_pdb_sync(ispsoftc_t *isp, int chan) return (0); } +static void +isp_pdb_add_update(ispsoftc_t *isp, int chan, isp_pdb_t *pdb) +{ + fcportdb_t *lp; + uint64_t wwnn, wwpn; + + MAKE_WWN_FROM_NODE_NAME(wwnn, pdb->nodename); + MAKE_WWN_FROM_NODE_NAME(wwpn, pdb->portname); + + /* Search port database for the same WWPN. */ + if (isp_find_pdb_by_wwpn(isp, chan, wwpn, &lp)) { + if (!lp->probational) { + isp_prt(isp, ISP_LOGERR, + "Chan %d Port 0x%06x@0x%04x [%d] is not probational (0x%x)", + chan, lp->portid, lp->handle, + FC_PORTDB_TGT(isp, chan, lp), lp->state); + isp_dump_portdb(isp, chan); + return; + } + lp->probational = 0; + lp->node_wwn = wwnn; + + /* Old device, nothing new. */ + if (lp->portid == pdb->portid && + lp->handle == pdb->handle && + lp->prli_word3 == pdb->prli_word3) { + if (lp->state != FC_PORTDB_STATE_NEW) + lp->state = FC_PORTDB_STATE_VALID; + isp_prt(isp, ISP_LOG_SANCFG, + "Chan %d Port 0x%06x@0x%04x is valid", + chan, pdb->portid, pdb->handle); + return; + } + + /* Something has changed. */ + lp->state = FC_PORTDB_STATE_CHANGED; + lp->handle = pdb->handle; + lp->new_portid = pdb->portid; + lp->new_prli_word3 = pdb->prli_word3; + isp_prt(isp, ISP_LOG_SANCFG, + "Chan %d Port 0x%06x@0x%04x is changed", + chan, pdb->portid, pdb->handle); + return; + } + + /* It seems like a new port. Find an empty slot for it. */ + if (!isp_find_pdb_empty(isp, chan, &lp)) { + isp_prt(isp, ISP_LOGERR, "Chan %d out of portdb entries", chan); + return; + } + + ISP_MEMZERO(lp, sizeof (fcportdb_t)); + lp->autologin = 1; + lp->probational = 0; + lp->state = FC_PORTDB_STATE_NEW; + lp->portid = lp->new_portid = pdb->portid; + lp->prli_word3 = lp->new_prli_word3 = pdb->prli_word3; + lp->handle = pdb->handle; + lp->port_wwn = wwpn; + lp->node_wwn = wwnn; + isp_prt(isp, ISP_LOG_SANCFG, "Chan %d Port 0x%06x@0x%04x is new", + chan, pdb->portid, pdb->handle); +} + /* * Scan local loop for devices. */ static int isp_scan_loop(ispsoftc_t *isp, int chan) { - fcportdb_t *lp, tmp; fcparam *fcp = FCPARAM(isp, chan); - int i, idx, lim, r; + int idx, lim, r; isp_pdb_t pdb; uint16_t handles[LOCAL_LOOP_LIM]; uint16_t handle; @@ -3052,8 +3097,7 @@ isp_scan_loop(ispsoftc_t *isp, int chan) return (0); } isp_prt(isp, ISP_LOG_SANCFG, "Chan %d FC loop scan", chan); - if (fcp->isp_topo != TOPO_NL_PORT && fcp->isp_topo != TOPO_FL_PORT && - fcp->isp_topo != TOPO_N_PORT) { + if (TOPO_IS_FABRIC(fcp->isp_topo)) { isp_prt(isp, ISP_LOG_SANCFG, "Chan %d FC loop scan done (no loop)", chan); fcp->isp_loopstate = LOOP_LSCAN_DONE; @@ -3066,7 +3110,6 @@ isp_scan_loop(ispsoftc_t *isp, int chan) if (r != 0) { isp_prt(isp, ISP_LOG_SANCFG, "Chan %d Getting list of handles failed with %x", chan, r); -fail: isp_prt(isp, ISP_LOG_SANCFG, "Chan %d FC loop scan done (bad)", chan); return (-1); @@ -3113,6 +3156,8 @@ abort: * Get the port database entity for this index. */ r = isp_getpdb(isp, chan, handle, &pdb, 1); + if (fcp->isp_loopstate < LOOP_SCANNING_LOOP) + goto abort; if (r != 0) { isp_prt(isp, ISP_LOGDEBUG1, "Chan %d FC Scan Loop handle %d returned %x", @@ -3122,145 +3167,7 @@ abort: continue; } - if (fcp->isp_loopstate < LOOP_SCANNING_LOOP) - goto abort; - - /* - * On *very* old 2100 firmware we would end up sometimes - * with the firmware returning the port database entry - * for something else. We used to restart this, but - * now we just punt. - */ - if (IS_2100(isp) && pdb.handle != handle) { - isp_prt(isp, ISP_LOGWARN, - "Chan %d getpdb() returned wrong handle %x != %x", - chan, pdb.handle, handle); - goto fail; - } - - /* - * Save the pertinent info locally. - */ - MAKE_WWN_FROM_NODE_NAME(tmp.node_wwn, pdb.nodename); - MAKE_WWN_FROM_NODE_NAME(tmp.port_wwn, pdb.portname); - tmp.prli_word3 = pdb.prli_word3; - tmp.portid = pdb.portid; - tmp.handle = pdb.handle; - - /* - * Check to make sure it's still a valid entry. The 24XX seems - * to return a portid but not a WWPN/WWNN or role for devices - * which shift on a loop. - */ - if (tmp.node_wwn == 0 || tmp.port_wwn == 0 || tmp.portid == 0) { - int a, b, c; - isp_prt(isp, ISP_LOGWARN, - "Chan %d bad pdb (WWNN %016jx, WWPN %016jx, PortID %06x, W3 0x%x, H 0x%x) @ handle 0x%x", - chan, tmp.node_wwn, tmp.port_wwn, tmp.portid, tmp.prli_word3, tmp.handle, handle); - a = (tmp.node_wwn == 0); - b = (tmp.port_wwn == 0); - c = (tmp.portid == 0); - if (a == 0 && b == 0) { - tmp.node_wwn = - isp_get_wwn(isp, chan, handle, 1); - tmp.port_wwn = - isp_get_wwn(isp, chan, handle, 0); - if (tmp.node_wwn && tmp.port_wwn) { - isp_prt(isp, ISP_LOGWARN, "DODGED!"); - goto cont; - } - } - isp_dump_portdb(isp, chan); - continue; - } - cont: - - /* - * Now search the entire port database - * for the same Port WWN. - */ - if (isp_find_pdb_by_wwn(isp, chan, tmp.port_wwn, &lp)) { - /* - * Okay- we've found a non-nil entry that matches. - * Check to make sure it's probational or a zombie. - */ - if (lp->state != FC_PORTDB_STATE_PROBATIONAL && - lp->state != FC_PORTDB_STATE_ZOMBIE && - lp->state != FC_PORTDB_STATE_VALID) { - isp_prt(isp, ISP_LOGERR, - "Chan %d [%d] not probational/zombie (0x%x)", - chan, FC_PORTDB_TGT(isp, chan, lp), lp->state); - isp_dump_portdb(isp, chan); - goto fail; - } - - /* - * Mark the device as something the f/w logs into - * automatically. - */ - lp->autologin = 1; - lp->node_wwn = tmp.node_wwn; - - /* - * Check to make see if really still the same - * device. If it is, we mark it pending valid. - */ - if (lp->portid == tmp.portid && lp->handle == tmp.handle && lp->prli_word3 == tmp.prli_word3) { - lp->new_portid = tmp.portid; - lp->new_prli_word3 = tmp.prli_word3; - lp->state = FC_PORTDB_STATE_PENDING_VALID; - isp_prt(isp, ISP_LOG_SANCFG, - "Chan %d Loop port 0x%06x@0x%04x now pending valid", - chan, tmp.portid, tmp.handle); - continue; - } - - /* - * We can wipe out the old handle value - * here because it's no longer valid. - */ - lp->handle = tmp.handle; - - /* - * Claim that this has changed and let somebody else - * decide what to do. - */ - isp_prt(isp, ISP_LOG_SANCFG, - "Chan %d Loop port 0x%06x@0x%04x changed", - chan, tmp.portid, tmp.handle); - lp->state = FC_PORTDB_STATE_CHANGED; - lp->new_portid = tmp.portid; - lp->new_prli_word3 = tmp.prli_word3; - continue; - } - - /* - * Ah. A new device entry. Find an empty slot - * for it and save info for later disposition. - */ - for (i = 0; i < MAX_FC_TARG; i++) { - if (fcp->portdb[i].state == FC_PORTDB_STATE_NIL) { - break; - } - } - if (i == MAX_FC_TARG) { - isp_prt(isp, ISP_LOGERR, - "Chan %d out of portdb entries", chan); - continue; - } - lp = &fcp->portdb[i]; - - ISP_MEMZERO(lp, sizeof (fcportdb_t)); - lp->autologin = 1; - lp->state = FC_PORTDB_STATE_NEW; - lp->new_portid = tmp.portid; - lp->new_prli_word3 = tmp.prli_word3; - lp->handle = tmp.handle; - lp->port_wwn = tmp.port_wwn; - lp->node_wwn = tmp.node_wwn; - isp_prt(isp, ISP_LOG_SANCFG, - "Chan %d Loop port 0x%06x@0x%04x is a new entry", - chan, tmp.portid, tmp.handle); + isp_pdb_add_update(isp, chan, &pdb); } if (fcp->isp_loopstate < LOOP_SCANNING_LOOP) goto abort; @@ -3359,10 +3266,6 @@ isp_gid_ft_ct_passthru(ispsoftc_t *isp, isp_prt(isp, ISP_LOGDEBUG0, "Chan %d scanning fabric (GID_FT) via CT", chan); - if (!IS_24XX(isp)) { - return (1); - } - /* * Build a Passthrough IOCB in memory. */ @@ -3445,6 +3348,7 @@ static int isp_scan_fabric(ispsoftc_t *isp, int chan) { fcparam *fcp = FCPARAM(isp, chan); + fcportdb_t *lp; uint32_t portid; uint16_t nphdl; isp_pdb_t pdb; @@ -3458,7 +3362,7 @@ isp_scan_fabric(ispsoftc_t *isp, int cha return (0); } isp_prt(isp, ISP_LOG_SANCFG, "Chan %d FC fabric scan", chan); - if (fcp->isp_topo != TOPO_FL_PORT && fcp->isp_topo != TOPO_F_PORT) { + if (!TOPO_IS_FABRIC(fcp->isp_topo)) { fcp->isp_loopstate = LOOP_FSCAN_DONE; isp_prt(isp, ISP_LOG_SANCFG, "Chan %d FC fabric scan done (no fabric)", chan); @@ -3495,16 +3399,13 @@ abort: goto fail; } - if (IS_24XX(isp)) { + /* Get list of port IDs from SNS. */ + if (IS_24XX(isp)) r = isp_gid_ft_ct_passthru(isp, chan); - } else { + else r = isp_gid_ft_sns(isp, chan); - } - - if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) { + if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) goto abort; - } - if (r > 0) { fcp->isp_loopstate = LOOP_FSCAN_DONE; FC_SCRATCH_RELEASE(isp, chan); @@ -3519,9 +3420,8 @@ abort: rs0 = (sns_gid_ft_rsp_t *) ((uint8_t *)fcp->isp_scratch+IGPOFF); rs1 = (sns_gid_ft_rsp_t *) ((uint8_t *)fcp->isp_scratch+OGPOFF); isp_get_gid_ft_response(isp, rs0, rs1, NGENT); - if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) { + if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) goto abort; - } if (rs1->snscb_cthdr.ct_cmd_resp != LS_ACC) { int level; if (rs1->snscb_cthdr.ct_reason == 9 && rs1->snscb_cthdr.ct_explanation == 7) { @@ -3538,21 +3438,11 @@ abort: return (0); } - /* - * Go through the list and remove duplicate port ids. - */ - - portlim = 0; - portidx = 0; + /* Check our buffer was big enough to get the full list. */ for (portidx = 0; portidx < NGENT-1; portidx++) { - if (rs1->snscb_ports[portidx].control & 0x80) { + if (rs1->snscb_ports[portidx].control & 0x80) break; - } } - - /* - * If we're not at the last entry, our list wasn't big enough. - */ if ((rs1->snscb_ports[portidx].control & 0x80) == 0) { isp_prt(isp, ISP_LOGWARN, "fabric too big for scratch area: increase ISP_FC_SCRLEN"); @@ -3561,6 +3451,7 @@ abort: isp_prt(isp, ISP_LOG_SANCFG, "Chan %d Got %d ports back from name server", chan, portlim); + /* Go through the list and remove duplicate port ids. */ for (portidx = 0; portidx < portlim; portidx++) { int npidx; @@ -3603,55 +3494,34 @@ abort: */ for (portidx = 0; portidx < portlim; portidx++) { - fcportdb_t *lp; - uint64_t wwnn, wwpn; - int dbidx, nr; - - portid = - ((rs1->snscb_ports[portidx].portid[0]) << 16) | - ((rs1->snscb_ports[portidx].portid[1]) << 8) | - ((rs1->snscb_ports[portidx].portid[2])); - + portid = ((rs1->snscb_ports[portidx].portid[0]) << 16) | + ((rs1->snscb_ports[portidx].portid[1]) << 8) | + ((rs1->snscb_ports[portidx].portid[2])); + isp_prt(isp, ISP_LOG_SANCFG, + "Chan %d Checking fabric port 0x%06x", chan, portid); if (portid == 0) { isp_prt(isp, ISP_LOG_SANCFG, "Chan %d Skipping null PortID at idx %d", chan, portidx); continue; } - if (portid == fcp->isp_portid) { isp_prt(isp, ISP_LOG_SANCFG, "Chan %d Skipping our PortID 0x%06x", chan, portid); continue; } - isp_prt(isp, ISP_LOG_SANCFG, - "Chan %d Checking fabric port 0x%06x", chan, portid); - - /* - * We now search our Port Database for any - * probational entries with this PortID. We don't - * look for zombies here- only probational - * entries (we've already logged out of zombies). - */ - for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { - lp = &fcp->portdb[dbidx]; - - if (lp->state != FC_PORTDB_STATE_PROBATIONAL) { - continue; - } - if (lp->portid == portid) { - break; + /* Now search the entire port database for the same portid. */ + if (isp_find_pdb_by_portid(isp, chan, portid, &lp)) { + if (!lp->probational) { + isp_prt(isp, ISP_LOGERR, + "Chan %d Port 0x%06x@0x%04x [%d] is not probational (0x%x)", + chan, lp->portid, lp->handle, + FC_PORTDB_TGT(isp, chan, lp), lp->state); + FC_SCRATCH_RELEASE(isp, chan); + isp_dump_portdb(isp, chan); + goto fail; } - } - - /* - * We found a probational entry with this Port ID. - */ - if (dbidx < MAX_FC_TARG) { - int handle_changed = 0; - - lp = &fcp->portdb[dbidx]; /* * See if we're still logged into it. @@ -3667,241 +3537,38 @@ abort: * and leave the new portid and role in the * database entry for somebody further along to * decide what to do (policy choice). - * */ - r = isp_getpdb(isp, chan, lp->handle, &pdb, 0); - if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) { + if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) goto abort; - } if (r != 0) { - lp->new_portid = portid; lp->state = FC_PORTDB_STATE_DEAD; - isp_prt(isp, ISP_LOG_SANCFG, "Chan %d Fabric PortID 0x%06x handle 0x%x is dead (%d)", chan, portid, lp->handle, r); - continue; - } - - - /* - * Check to make sure that handle, portid, WWPN and - * 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); - if (pdb.handle != lp->handle || - pdb.portid != portid || - wwpn != lp->port_wwn || - (lp->node_wwn != 0 && wwnn != lp->node_wwn)) { isp_prt(isp, ISP_LOG_SANCFG, - fconf, chan, 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); - /* - * 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 ((fcp->role & ISP_ROLE_INITIATOR) == 0 || - isp_login_device(isp, chan, portid, &pdb, - &FCPARAM(isp, 0)->isp_lasthdl)) { - lp->new_portid = portid; - lp->state = FC_PORTDB_STATE_DEAD; - if (fcp->isp_loopstate < - LOOP_SCANNING_FABRIC) { - goto abort; - } - continue; - } - if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) { - goto abort; - } - MAKE_WWN_FROM_NODE_NAME(wwnn, pdb.nodename); - MAKE_WWN_FROM_NODE_NAME(wwpn, pdb.portname); - if (wwpn != lp->port_wwn || - (lp->node_wwn != 0 && 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++; + "Chan %d Port 0x%06x handle 0x%x is dead (%d)", + chan, portid, lp->handle, r); + goto relogin; } - nr = pdb.prli_word3; - - /* - * Check to see whether the portid and roles have - * stayed the same. If they have stayed the same, - * we believe that this is the same device and it - * hasn't become disconnected and reconnected, so - * mark it as pending valid. - * - * If they aren't the same, mark the device as a - * changed device and save the new port id and role - * and let somebody else decide. - */ - - lp->new_portid = portid; - lp->new_prli_word3 = nr; - if (pdb.portid != lp->portid || nr != lp->prli_word3 || handle_changed) { - isp_prt(isp, ISP_LOG_SANCFG, - "Chan %d Fabric port 0x%06x changed", - chan, portid); - lp->state = FC_PORTDB_STATE_CHANGED; - } else { - isp_prt(isp, ISP_LOG_SANCFG, - "Chan %d Fabric port 0x%06x now pending valid", - chan, portid); - lp->state = FC_PORTDB_STATE_PENDING_VALID; - } + isp_pdb_add_update(isp, chan, &pdb); continue; } +relogin: if ((fcp->role & ISP_ROLE_INITIATOR) == 0) continue; - /* - * Ah- a new entry. Search the database again for all non-NIL - * entries to make sure we never ever make a new database entry - * with the same port id. While we're at it, mark where the - * last free entry was. - */ - - dbidx = MAX_FC_TARG; - for (lp = fcp->portdb; lp < &fcp->portdb[MAX_FC_TARG]; lp++) { - if (lp->state == FC_PORTDB_STATE_NIL) { - if (dbidx == MAX_FC_TARG) { - dbidx = lp - fcp->portdb; - } - continue; - } - if (lp->state == FC_PORTDB_STATE_ZOMBIE) { - continue; - } - if (lp->portid == portid) { - break; - } - } - - if (lp < &fcp->portdb[MAX_FC_TARG]) { - isp_prt(isp, ISP_LOGWARN, "Chan %d PortID 0x%06x " - "already at %d handle %d state %d", - chan, portid, dbidx, lp->handle, lp->state); - continue; - } - - /* - * We should have the index of the first free entry seen. - */ - if (dbidx == MAX_FC_TARG) { - isp_prt(isp, ISP_LOGERR, - "port database too small to login PortID 0x%06x" - "- increase MAX_FC_TARG", portid); - continue; - } - - /* - * Otherwise, point to our new home. - */ - lp = &fcp->portdb[dbidx]; - - /* - * Try to see if we are logged into this device, - * and maybe log into it. - * - * isp_login_device will check for handle and - * portid consistency after login. - */ if (isp_login_device(isp, chan, portid, &pdb, &FCPARAM(isp, 0)->isp_lasthdl)) { - if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) { + if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) goto abort; - } - continue; - } - if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) { - goto abort; - } - - nphdl = pdb.handle; - MAKE_WWN_FROM_NODE_NAME(wwnn, pdb.nodename); - MAKE_WWN_FROM_NODE_NAME(wwpn, pdb.portname); - nr = pdb.prli_word3; - - /* - * And go through the database *one* more time to make sure - * that we do not make more than one entry that has the same - * WWNN/WWPN duple - */ - for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { - if ((fcp->portdb[dbidx].node_wwn == wwnn || - fcp->portdb[dbidx].node_wwn == 0) && - fcp->portdb[dbidx].port_wwn == wwpn) { - break; - } - } - - if (dbidx == MAX_FC_TARG) { - ISP_MEMZERO(lp, sizeof (fcportdb_t)); - lp->handle = nphdl; - lp->node_wwn = wwnn; - lp->port_wwn = wwpn; - lp->new_portid = portid; - lp->new_prli_word3 = nr; - lp->state = FC_PORTDB_STATE_NEW; - isp_prt(isp, ISP_LOG_SANCFG, "Chan %d Fabric port 0x%06x is a new entry", chan, portid); continue; } - if (fcp->portdb[dbidx].state != FC_PORTDB_STATE_ZOMBIE) { - isp_prt(isp, ISP_LOGWARN, - "Chan %d PortID 0x%x 0x%08x%08x/0x%08x%08x %ld " - "already at idx %d, state 0x%x", chan, portid, - (uint32_t) (wwnn >> 32), (uint32_t) wwnn, - (uint32_t) (wwpn >> 32), (uint32_t) wwpn, - (long) (lp - fcp->portdb), dbidx, - fcp->portdb[dbidx].state); - continue; - } - - /* - * We found a zombie entry that matches us. - * Revive it. We know that WWN and WWPN - * are the same. For fabric devices, we - * don't care that handle is different - * as we assign that. If role or portid - * are different, it maybe a changed device. - */ - lp = &fcp->portdb[dbidx]; - lp->handle = nphdl; - lp->node_wwn = wwnn; - lp->new_portid = portid; - lp->new_prli_word3 = nr; - if (lp->portid != portid || lp->prli_word3 != nr) { - isp_prt(isp, ISP_LOG_SANCFG, "Chan %d Zombie fabric port 0x%06x now changed", chan, portid); - lp->state = FC_PORTDB_STATE_CHANGED; - } else { - isp_prt(isp, ISP_LOG_SANCFG, "Chan %d Zombie fabric port 0x%06x now pending valid", chan, portid); - lp->state = FC_PORTDB_STATE_PENDING_VALID; - } + isp_pdb_add_update(isp, chan, &pdb); } - if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) { + if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) goto abort; - } FC_SCRATCH_RELEASE(isp, chan); fcp->isp_loopstate = LOOP_FSCAN_DONE; isp_prt(isp, ISP_LOG_SANCFG, "Chan %d FC fabric scan done", chan); @@ -3925,27 +3592,26 @@ isp_login_device(ispsoftc_t *isp, int ch handle = isp_next_handle(isp, ohp); for (i = 0; i < lim; i++) { - /* - * See if we're still logged into something with - * this handle and that something agrees with this - * port id. - */ + if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC) + return (-1); + + /* Check if this handle is free. */ 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 | PLOGX_FLG_FREE_NPHDL, 1); - } else if (r == 0) { + if (r == 0) { + if (p->portid != portid) { + /* This handle is busy, try next one. */ + handle = isp_next_handle(isp, ohp); + continue; + } break; } - if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC) { + if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC) return (-1); - } + /* * Now try and log into the device */ 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) { break; } else if ((r & 0xffff) == MBOX_PORT_ID_USED) { @@ -3957,13 +3623,9 @@ isp_login_device(ispsoftc_t *isp, int ch 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) { + 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) i = lim; break; @@ -3988,9 +3650,6 @@ isp_login_device(ispsoftc_t *isp, int ch * is and that we also have the role it plays */ *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***