Date: Sun, 21 Jun 2015 14:18:55 +0000 (UTC) From: Alexander Motin <mav@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r284681 - head/sys/dev/isp Message-ID: <201506211418.t5LEItGT080693@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: mav Date: Sun Jun 21 14:18:54 2015 New Revision: 284681 URL: https://svnweb.freebsd.org/changeset/base/284681 Log: 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. MFC after: 1 week Sponsored by: iXsystems, Inc. Modified: head/sys/dev/isp/isp_freebsd.c head/sys/dev/isp/isp_library.c Modified: head/sys/dev/isp/isp_freebsd.c ============================================================================== --- head/sys/dev/isp/isp_freebsd.c Sun Jun 21 14:01:26 2015 (r284680) +++ head/sys/dev/isp/isp_freebsd.c Sun Jun 21 14:18:54 2015 (r284681) @@ -2452,18 +2452,11 @@ isp_handle_platform_atio2(ispsoftc_t *is * 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; Modified: head/sys/dev/isp/isp_library.c ============================================================================== --- head/sys/dev/isp/isp_library.c Sun Jun 21 14:01:26 2015 (r284680) +++ head/sys/dev/isp/isp_library.c Sun Jun 21 14:18:54 2015 (r284681) @@ -2367,18 +2367,17 @@ isp_find_pdb_by_wwn(ispsoftc_t *isp, int 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, 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 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 c 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); + 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); } - if (fcp->isp_tgt_map[nphdl] == 0) { - fcp->isp_tgt_map[nphdl] = i + 1; - goto notify; - } - 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 c } } 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;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201506211418.t5LEItGT080693>