Mercurial > illumos > illumos-gate
changeset 11133:e9413f8762c3
6897780 assertion failed: !list_link_active(&phyp->list_node), file: ...pmcs_subr.c, line: 7363
6895290 missing phy after enumeration failure during tran_tgt_init
author | Jesse Butler <Jesse.Butler@Sun.COM> |
---|---|
date | Fri, 20 Nov 2009 10:24:27 -0700 |
parents | 56dcfb8bf4f8 |
children | 8aa0c4ca6639 |
files | usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_intr.c usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_subr.c usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_proto.h |
diffstat | 3 files changed, 144 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_intr.c Fri Nov 20 10:19:25 2009 -0700 +++ b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_intr.c Fri Nov 20 10:24:27 2009 -0700 @@ -676,6 +676,16 @@ pmcs_prt(pwp, PMCS_PRT_INFO, NULL, NULL, "PortID 0x%x: PHY 0x%x IN RESET", portid, phynum); + /* Entire port is down due to a host-initiated reset */ + mutex_enter(&pptr->phy_lock); + iport = pptr->iport; + mutex_exit(&pptr->phy_lock); + if (iport) { + mutex_enter(&iport->lock); + pmcs_iport_teardown_phys(iport); + mutex_exit(&iport->lock); + } + break; } if (IOP_EVENT_PORT_STATE(w3) == IOP_EVENT_PS_LOSTCOMM) { @@ -688,6 +698,33 @@ if (IOP_EVENT_PORT_STATE(w3) == IOP_EVENT_PS_VALID) { /* + * This is not the last phy in the port, so if this + * is the primary PHY, promote another PHY to primary. + */ + if (pptr == subphy) { + primary = !subphy->subsidiary; + ASSERT(primary); + + tphyp = pptr; + pptr = pmcs_promote_next_phy(tphyp); + + if (pptr) { + /* Update primary pptr in ports */ + pwp->ports[portid] = pptr; + pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, + NULL, "PortID 0x%x: PHY 0x%x " + "promoted to primary", portid, + pptr->phynum); + } else { + /* This should not happen */ + pmcs_prt(pwp, PMCS_PRT_DEBUG, pptr, + NULL, "PortID 0x%x: PHY 0x%x: " + "unable to promote phy", portid, + phynum); + } + } + + /* * Drop port width on the primary phy handle * No need to lock the entire tree for this */
--- a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_subr.c Fri Nov 20 10:19:25 2009 -0700 +++ b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_subr.c Fri Nov 20 10:24:27 2009 -0700 @@ -1917,6 +1917,38 @@ } /* + * Remove all phys from an iport's phymap and empty it's phylist. + * Called when a port has been reset by the host (see pmcs_intr.c). + */ +void +pmcs_iport_teardown_phys(pmcs_iport_t *iport) +{ + pmcs_hw_t *pwp; + sas_phymap_phys_t *phys; + int phynum; + + ASSERT(iport); + ASSERT(mutex_owned(&iport->lock)); + pwp = iport->pwp; + ASSERT(pwp); + + /* + * Remove all phys from the iport handle's phy list, unset its + * primary phy and update its state. + */ + pmcs_remove_phy_from_iport(iport, NULL); + iport->pptr = NULL; + iport->ua_state = UA_PEND_DEACTIVATE; + + /* Remove all phys from the phymap */ + phys = sas_phymap_ua2phys(pwp->hss_phymap, iport->ua); + while ((phynum = sas_phymap_phys_next(phys)) != -1) { + sas_phymap_phy_rem(pwp->hss_phymap, phynum); + } + sas_phymap_phys_free(phys); +} + +/* * Query the phymap and populate the iport handle passed in. * Called with iport lock held. */ @@ -2038,6 +2070,79 @@ return (iport); } +/* + * Promote the next phy on this iport to primary, and return it. + * Called when the primary PHY on a port is going down, but the port + * remains up (see pmcs_intr.c). + */ +pmcs_phy_t * +pmcs_promote_next_phy(pmcs_phy_t *prev_primary) +{ + pmcs_iport_t *iport; + pmcs_phy_t *pptr, *next_pptr, *child; + + mutex_enter(&prev_primary->phy_lock); + iport = prev_primary->iport; + mutex_exit(&prev_primary->phy_lock); + ASSERT(iport); + + mutex_enter(&iport->lock); + for (pptr = list_head(&iport->phys); pptr != NULL; pptr = next_pptr) { + next_pptr = list_next(&iport->phys, pptr); + + /* Use the first PHY in the list that is not the primary */ + if (pptr != prev_primary) { + break; + } + } + iport->pptr = pptr; + mutex_exit(&iport->lock); + + if (pptr == NULL) { + pmcs_prt(iport->pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL, + "%s: unable to promote to new primary phy on iport [0x%p]", + __func__, (void *)iport); + return (NULL); + } + + /* Update the phy handle with the data from the previous primary */ + mutex_enter(&pptr->phy_lock); + pmcs_lock_phy(prev_primary); + + ASSERT(pptr->subsidiary); + + pptr->children = prev_primary->children; + child = pptr->children; + while (child) { + child->parent = pptr; + child = child->sibling; + } + pptr->ncphy = prev_primary->ncphy; + pptr->width = prev_primary->width; + pptr->dtype = prev_primary->dtype; + pptr->pend_dtype = prev_primary->pend_dtype; + pptr->tolerates_sas2 = prev_primary->tolerates_sas2; + pptr->atdt = prev_primary->atdt; + pptr->portid = prev_primary->portid; + pptr->link_rate = prev_primary->link_rate; + pptr->configured = prev_primary->configured; + pptr->iport = prev_primary->iport; + pptr->target = prev_primary->target; + pptr->subsidiary = 0; + + prev_primary->subsidiary = 1; + prev_primary->children = NULL; + pmcs_unlock_phy(prev_primary); + + /* + * We call pmcs_unlock_phy() on pptr because it now contains the + * list of children. + */ + pmcs_unlock_phy(pptr); + + return (pptr); +} + void pmcs_rele_iport(pmcs_iport_t *iport) {
--- a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_proto.h Fri Nov 20 10:19:25 2009 -0700 +++ b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_proto.h Fri Nov 20 10:24:27 2009 -0700 @@ -313,8 +313,10 @@ void pmcs_ssp_event_recovery(pmcs_hw_t *); pmcs_iport_t *pmcs_get_iport_by_phy(pmcs_hw_t *pwp, pmcs_phy_t *pptr); +pmcs_phy_t *pmcs_promote_next_phy(pmcs_phy_t *pptr); void pmcs_rele_iport(pmcs_iport_t *iport); int pmcs_iport_configure_phys(pmcs_iport_t *iport); +void pmcs_iport_teardown_phys(pmcs_iport_t *iport); void pmcs_lock_phy(pmcs_phy_t *); void pmcs_unlock_phy(pmcs_phy_t *);