summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorJesse Butler <Jesse.Butler@Sun.COM>2009-11-20 10:24:27 -0700
committerJesse Butler <Jesse.Butler@Sun.COM>2009-11-20 10:24:27 -0700
commitf73ae3db72a91f9f8759931a1c643c7dad785881 (patch)
treec1a88a28b388cd8c9d0d5860489247c5a5417a6e /usr/src
parente617f2142235c62bb299718a60e6d2f79b6f472f (diff)
downloadillumos-joyent-f73ae3db72a91f9f8759931a1c643c7dad785881.tar.gz
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
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_intr.c37
-rw-r--r--usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_subr.c105
-rw-r--r--usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_proto.h2
3 files changed, 144 insertions, 0 deletions
diff --git a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_intr.c b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_intr.c
index 895d4311e2..86a87f87a3 100644
--- a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_intr.c
+++ b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_intr.c
@@ -676,6 +676,16 @@ pmcs_process_sas_hw_event(pmcs_hw_t *pwp, void *iomb, size_t amt)
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 @@ pmcs_process_sas_hw_event(pmcs_hw_t *pwp, void *iomb, size_t amt)
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
*/
diff --git a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_subr.c b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_subr.c
index 0d7f5e12d9..2be7e09eca 100644
--- a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_subr.c
+++ b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_subr.c
@@ -1917,6 +1917,38 @@ pmcs_iport_tgtmap_destroy(pmcs_iport_t *iport)
}
/*
+ * 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 @@ pmcs_get_iport_by_phy(pmcs_hw_t *pwp, pmcs_phy_t *pptr)
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)
{
diff --git a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_proto.h b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_proto.h
index 1321471b6d..272095a62f 100644
--- a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_proto.h
+++ b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_proto.h
@@ -313,8 +313,10 @@ void pmcs_start_ssp_event_recovery(pmcs_hw_t *pwp, pmcwork_t *pwrk,
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 *);