From 0f5d275414d1030bfac3a843f5292afbe3356ee1 Mon Sep 17 00:00:00 2001 From: mav Date: Sun, 28 Jun 2015 09:24:02 +0000 Subject: [PATCH] MFC r284681: Rewrite port database handling for target mode. Previous implementation was too fragile to initiator parameters changes. In case of port role change it could not survive different handle assigned to the same initiator by firmware, even though initiator was logged out. The new implementation should be more resillient to this kind of problems, trying to work in any situation and only warn user about suspisious events. git-svn-id: svn://svn.freebsd.org/base/stable/10@284904 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- sys/dev/isp/isp_freebsd.c | 9 +- sys/dev/isp/isp_library.c | 238 ++++++++++++++++++++------------------ 2 files changed, 128 insertions(+), 119 deletions(-) diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c index 0e7c1b539..5d2c88094 100644 --- a/sys/dev/isp/isp_freebsd.c +++ b/sys/dev/isp/isp_freebsd.c @@ -2435,18 +2435,11 @@ isp_handle_platform_atio2(ispsoftc_t *isp, at2_entry_t *aep) * If we're not in the port database, add ourselves. */ if (!IS_2100(isp) && isp_find_pdb_by_loopid(isp, 0, atiop->init_id, &lp) == 0) { - uint64_t iid = + uint64_t iid = (((uint64_t) aep->at_wwpn[0]) << 48) | (((uint64_t) aep->at_wwpn[1]) << 32) | (((uint64_t) aep->at_wwpn[2]) << 16) | (((uint64_t) aep->at_wwpn[3]) << 0); - /* - * However, make sure we delete ourselves if otherwise - * we were there but at a different loop id. - */ - if (isp_find_pdb_by_wwn(isp, 0, iid, &lp)) { - isp_del_wwn_entry(isp, 0, iid, lp->handle, lp->portid); - } isp_add_wwn_entry(isp, 0, iid, atiop->init_id, PORT_ANY, 0); } atiop->cdb_len = ATIO2_CDBLEN; diff --git a/sys/dev/isp/isp_library.c b/sys/dev/isp/isp_library.c index cb9c4ffef..b56b1dc91 100644 --- a/sys/dev/isp/isp_library.c +++ b/sys/dev/isp/isp_library.c @@ -2367,18 +2367,17 @@ isp_find_pdb_by_wwn(ispsoftc_t *isp, int chan, uint64_t wwn, fcportdb_t **lptr) fcparam *fcp; int i; - if (chan < isp->isp_nchan) { - fcp = FCPARAM(isp, chan); - for (i = MAX_FC_TARG - 1; i >= 0; i--) { - fcportdb_t *lp = &fcp->portdb[i]; + if (chan >= isp->isp_nchan) + return (0); + fcp = FCPARAM(isp, chan); + for (i = MAX_FC_TARG - 1; i >= 0; i--) { + fcportdb_t *lp = &fcp->portdb[i]; - if (lp->target_mode == 0) { - continue; - } - if (lp->port_wwn == wwn) { - *lptr = lp; - return (1); - } + if (lp->target_mode == 0) + continue; + if (lp->port_wwn == wwn) { + *lptr = lp; + return (1); } } return (0); @@ -2390,19 +2389,12 @@ isp_find_pdb_by_loopid(ispsoftc_t *isp, int chan, uint32_t loopid, fcportdb_t ** fcparam *fcp; int i; - if (chan < isp->isp_nchan) { - fcp = FCPARAM(isp, chan); - for (i = MAX_FC_TARG - 1; i >= 0; i--) { - fcportdb_t *lp = &fcp->portdb[i]; - - if (lp->target_mode == 0) { - continue; - } - if (lp->handle == loopid) { - *lptr = lp; - return (1); - } - } + if (chan >= isp->isp_nchan) + return (0); + fcp = FCPARAM(isp, chan); + if ((i = fcp->isp_tgt_map[loopid]) > 0) { + *lptr = &fcp->portdb[i - 1]; + return (1); } return (0); } @@ -2413,17 +2405,14 @@ isp_find_pdb_by_sid(ispsoftc_t *isp, int chan, uint32_t sid, fcportdb_t **lptr) fcparam *fcp; int i; - if (chan >= isp->isp_nchan) { + if (chan >= isp->isp_nchan) return (0); - } - fcp = FCPARAM(isp, chan); for (i = MAX_FC_TARG - 1; i >= 0; i--) { fcportdb_t *lp = &fcp->portdb[i]; - if (lp->target_mode == 0) { + if (lp->target_mode == 0) continue; - } if (lp->portid == sid) { *lptr = lp; return (1); @@ -2460,125 +2449,151 @@ isp_add_wwn_entry(ispsoftc_t *isp, int chan, uint64_t ini, uint16_t nphdl, uint3 fcparam *fcp; fcportdb_t *lp; isp_notify_t nt; - int i; + int i, something, take, taken; fcp = FCPARAM(isp, chan); - if (nphdl >= MAX_NPORT_HANDLE) { - isp_prt(isp, ISP_LOGWARN, "Chan %d IID 0x%016llx bad N-Port handle 0x%04x Port ID 0x%06x", + isp_prt(isp, ISP_LOGWARN, "Chan %d IID 0x%016llx " + "N-Port handle 0x%04x Port ID 0x%06x -- bad handle", chan, (unsigned long long) ini, nphdl, s_id); return; } - lp = NULL; - if (fcp->isp_tgt_map[nphdl]) { - i = fcp->isp_tgt_map[nphdl] - 1; - lp = &fcp->portdb[i]; - } else { - /* - * Make sure the addition of a new target mode entry doesn't duplicate entries - * with the same N-Port handles, the same portids or the same Port WWN. - */ - for (i = 0; i < MAX_FC_TARG; i++) { - lp = &fcp->portdb[i]; - if (lp->target_mode == 0) { - lp = NULL; - continue; - } - if (lp->handle == nphdl) { - break; - } - if (s_id != PORT_ANY && lp->portid == s_id) { - break; - } - if (VALID_INI(ini) && lp->port_wwn == ini) { - break; - } - lp = NULL; - } - - } - - if (lp) { - int something = 0; - if (lp->handle != nphdl) { - isp_prt(isp, ISP_LOGWARN, "Chan %d attempt to re-enter N-port handle 0x%04x IID 0x%016llx Port ID 0x%06x finds IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x", - chan, nphdl, (unsigned long long)ini, s_id, (unsigned long long) lp->port_wwn, lp->handle, lp->portid); - isp_dump_portdb(isp, chan); - return; - } - if (s_id != PORT_NONE) { + /* + * If valid record for requested handle already exists, update it + * with new parameters. Some cases of update can be suspicious, + * so log them verbosely and dump the whole port database. + */ + if ((i = fcp->isp_tgt_map[nphdl]) > 0) { + take = taken = i - 1; + lp = &fcp->portdb[taken]; + something = 0; + if (s_id != PORT_NONE && lp->portid != s_id) { if (lp->portid == PORT_NONE) { - lp->portid = s_id; - isp_prt(isp, ISP_LOGTINFO, "Chan %d N-port handle 0x%04x gets Port ID 0x%06x", chan, nphdl, s_id); - something++; - } else if (lp->portid != s_id) { - isp_prt(isp, ISP_LOGTINFO, "Chan %d N-port handle 0x%04x tries to change Port ID 0x%06x to 0x%06x", chan, nphdl, lp->portid, s_id); - isp_dump_portdb(isp, chan); - return; + isp_prt(isp, ISP_LOGTINFO, + "Chan %d IID 0x%016llx N-port handle 0x%04x " + "gets Port ID 0x%06x", + chan, (unsigned long long) lp->port_wwn, + nphdl, s_id); + } else { + isp_prt(isp, ISP_LOGTINFO|ISP_LOGWARN, + "Chan %d IID 0x%016llx N-port handle 0x%04x " + "changes Port ID 0x%06x to 0x%06x", + chan, (unsigned long long) lp->port_wwn, + nphdl, lp->portid, s_id); + if (isp->isp_dblev & (ISP_LOGTINFO|ISP_LOGWARN)) + isp_dump_portdb(isp, chan); } + lp->portid = s_id; + something++; } - if (VALID_INI(ini)) { + if (VALID_INI(ini) && lp->port_wwn != ini) { if (!VALID_INI(lp->port_wwn)) { - lp->port_wwn = ini; - isp_prt(isp, ISP_LOGTINFO, "Chan %d N-port handle 0x%04x gets WWN 0x%016llxx", chan, nphdl, (unsigned long long) ini); - something++; + isp_prt(isp, ISP_LOGTINFO, + "Chan %d N-port handle 0x%04x Port ID " + "0x%06x gets WWN 0x%016llxx", + chan, nphdl, lp->portid, + (unsigned long long) ini); } else if (lp->port_wwn != ini) { - isp_prt(isp, ISP_LOGWARN, "Chan %d N-port handle 0x%04x tries to change WWN 0x%016llx to 0x%016llx", chan, nphdl, - (unsigned long long) lp->port_wwn, (unsigned long long) ini); - isp_dump_portdb(isp, chan); - return; + isp_prt(isp, ISP_LOGTINFO|ISP_LOGWARN, + "Chan %d N-port handle 0x%04x Port ID " + "0x%06x changes WWN 0x%016llx to 0x%016llx", + chan, nphdl, lp->portid, + (unsigned long long) lp->port_wwn, + (unsigned long long) ini); + if (isp->isp_dblev & (ISP_LOGTINFO|ISP_LOGWARN)) + isp_dump_portdb(isp, chan); } + lp->port_wwn = ini; + something++; } - if (prli_params != lp->prli_word3) { + if (lp->prli_word3 != prli_params) { lp->prli_word3 = prli_params; isp_gen_role_str(buf, sizeof (buf), lp->prli_word3); - isp_prt(isp, ISP_LOGTINFO|ISP_LOGCONFIG, "Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x new PRLI Word 3 params %s", chan, - (unsigned long long) lp->port_wwn, lp->handle, lp->portid, buf); + isp_prt(isp, ISP_LOGTINFO|ISP_LOGCONFIG, + "Chan %d IID 0x%016llx N-Port Handle 0x%04x " + "Port ID 0x%06x changes PRLI Word 3 %s", + chan, (unsigned long long) lp->port_wwn, + lp->handle, lp->portid, buf); something++; } if (!something) { - isp_prt(isp, ISP_LOGWARN, "Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x reentered", chan, - (unsigned long long) lp->port_wwn, lp->handle, lp->portid); - } - if (fcp->isp_tgt_map[nphdl] == 0) { - fcp->isp_tgt_map[nphdl] = i + 1; - goto notify; + isp_prt(isp, ISP_LOGTINFO, + "Chan %d IID 0x%016llx N-Port Handle 0x%04x " + "Port ID 0x%06x reentered", + chan, (unsigned long long) lp->port_wwn, + lp->handle, lp->portid); } - return; - } + } else + take = taken = -1; /* - * Find a new spot + * Search for records colliding on handler, Port ID or WWN. + * Remove any found collisions, logging suspicious cases of + * still valid records. */ - for (i = MAX_FC_TARG - 1; i >= 0; i--) { - if (fcp->portdb[i].target_mode == 1) { + for (i = 0; i < MAX_FC_TARG; i++) { + lp = &fcp->portdb[i]; + if (lp->target_mode == 0 || i == take) continue; + if (lp->handle != nphdl && lp->portid != s_id && + lp->port_wwn != ini) + continue; + if (lp->state == FC_PORTDB_STATE_VALID) { + isp_prt(isp, ISP_LOGTINFO|ISP_LOGWARN, + "Chan %d IID 0x%016llx N-Port Handle 0x%04x " + "Port ID 0x%06x is conflicting", + chan, (unsigned long long) lp->port_wwn, + lp->handle, lp->portid); + if (isp->isp_dblev & (ISP_LOGTINFO|ISP_LOGWARN)) + isp_dump_portdb(isp, chan); + isp_del_wwn_entry(isp, chan, + lp->port_wwn, lp->handle, lp->portid); } - if (fcp->portdb[i].state == FC_PORTDB_STATE_NIL) { - break; + ISP_MEMZERO(lp, sizeof (fcportdb_t)); + take = i; + } + + /* If valid record already exists -- we are done. */ + if (taken >= 0) + return; + + /* Search for room to insert new record. */ + if (take < 0) { + for (i = MAX_FC_TARG - 1; i >= 0; i--) { + if (fcp->portdb[i].state == FC_PORTDB_STATE_NIL) { + take = i; + break; + } } } - if (i < 0) { - isp_prt(isp, ISP_LOGWARN, "Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x- no room in port database", + if (take < 0) { + isp_prt(isp, ISP_LOGTINFO|ISP_LOGWARN, + "Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x " + "-- no room in port database", chan, (unsigned long long) ini, nphdl, s_id); + if (isp->isp_dblev & (ISP_LOGTINFO|ISP_LOGWARN)) + isp_dump_portdb(isp, chan); return; } - lp = &fcp->portdb[i]; + /* Insert new record and mark it valid. */ + lp = &fcp->portdb[take]; ISP_MEMZERO(lp, sizeof (fcportdb_t)); lp->target_mode = 1; lp->handle = nphdl; lp->portid = s_id; lp->port_wwn = ini; lp->prli_word3 = prli_params; - isp_gen_role_str(buf, sizeof (buf), lp->prli_word3); - fcp->isp_tgt_map[nphdl] = i + 1; + lp->state = FC_PORTDB_STATE_VALID; + fcp->isp_tgt_map[nphdl] = take + 1; - isp_prt(isp, ISP_LOGTINFO, "Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x vtgt %d %s added", chan, - (unsigned long long) ini, nphdl, s_id, fcp->isp_tgt_map[nphdl] - 1, buf); + isp_gen_role_str(buf, sizeof (buf), lp->prli_word3); + isp_prt(isp, ISP_LOGTINFO, "Chan %d IID 0x%016llx N-Port Handle 0x%04x" + " Port ID 0x%06x vtgt %d %s added", chan, + (unsigned long long) ini, nphdl, s_id, take, buf); -notify: + /* Notify above levels about new initiator arrival. */ ISP_MEMZERO(&nt, sizeof (nt)); nt.nt_hba = isp; nt.nt_wwn = ini; @@ -2617,14 +2632,15 @@ isp_del_wwn_entry(ispsoftc_t *isp, int chan, uint64_t ini, uint16_t nphdl, uint3 } } if (lp == NULL) { - isp_prt(isp, ISP_LOGWARN, "Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x cannot be found to be cleared", + isp_prt(isp, ISP_LOGWARN, "Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x cannot be found to be deleted", chan, (unsigned long long) ini, nphdl, s_id); isp_dump_portdb(isp, chan); return; } - isp_prt(isp, ISP_LOGTINFO, "Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x vtgt %d cleared", + isp_prt(isp, ISP_LOGTINFO, "Chan %d IID 0x%016llx N-Port Handle 0x%04x Port ID 0x%06x vtgt %d deleted", chan, (unsigned long long) lp->port_wwn, nphdl, lp->portid, fcp->isp_tgt_map[nphdl] - 1); fcp->isp_tgt_map[nphdl] = 0; + lp->state = FC_PORTDB_STATE_DEAD; ISP_MEMZERO(&nt, sizeof (nt)); nt.nt_hba = isp; -- 2.45.0