diff options
author | David Hollister <David.Hollister@Sun.COM> | 2010-01-14 18:36:25 -0700 |
---|---|---|
committer | David Hollister <David.Hollister@Sun.COM> | 2010-01-14 18:36:25 -0700 |
commit | 73a3eccd27d9673a6407274ea0de350699562fd9 (patch) | |
tree | a647759228ad8b0be75c1408710bab9c618be937 | |
parent | aef83d42faaccf25ad8bd8dc892c2fb6fa7efdad (diff) | |
download | illumos-joyent-73a3eccd27d9673a6407274ea0de350699562fd9.tar.gz |
6906811 assertion failed: pptr->children == NULL
6914773 assertion failed !MDI_PI_LOCKED(pip), file: ../../common/os/sunmdi.c
5 files changed, 135 insertions, 73 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 24d7c0df77..673124c6bd 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 @@ -72,7 +72,7 @@ __func__, (void *)x, ci, w0, n) #define EVT_PRT(hwp, msg, phy) \ - pmcs_prt(hwp, PMCS_PRT_INFO, NULL, NULL, "Phy 0x%x: %s", phy, # msg) + pmcs_prt(hwp, PMCS_PRT_DEBUG, NULL, NULL, "Phy 0x%x: %s", phy, # msg) /* diff --git a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_scsa.c b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_scsa.c index 180feb2498..472885c7fd 100644 --- a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_scsa.c +++ b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_scsa.c @@ -317,7 +317,8 @@ pmcs_scsa_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip, } tgt->dip = sd->sd_dev; - tgt->sd = sd; + lun->sd = sd; + list_insert_tail(&tgt->lun_list, lun); if (!pmcs_assign_device(pwp, tgt)) { pmcs_release_scratch(pwp); @@ -357,20 +358,24 @@ pmcs_scsa_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip, * By passing in 0s, we're not actually updating any values, but * the properties should now get updated on the node. */ - pmcs_update_phy_pm_props(phyp, 0, 0, B_TRUE); mutex_exit(&tgt->statlock); + pmcs_update_phy_pm_props(phyp, 0, 0, B_TRUE); pmcs_unlock_phy(phyp); mutex_exit(&pwp->lock); scsi_device_prop_free(sd, SCSI_DEVICE_PROP_PATH, tgt_port); return (DDI_SUCCESS); tgt_init_fail: + pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, phyp, tgt, "%s: failed for " + "@%s tgt 0x%p phy 0x%p", __func__, ua, (void *)tgt, (void *)phyp); + scsi_device_hba_private_set(sd, NULL); if (got_scratch) { pmcs_release_scratch(pwp); } if (lun) { + list_remove(&tgt->lun_list, lun); ddi_soft_state_bystr_free(tgt->lun_sstate, ua); } if (phyp) { @@ -421,9 +426,8 @@ pmcs_scsa_tran_tgt_free(dev_info_t *hba_dip, dev_info_t *tgt_dip, ASSERT(lun->target->ref_count > 0); target = lun->target; - unit_address = lun->unit_address; - ddi_soft_state_bystr_free(lun->target->lun_sstate, unit_address); + list_remove(&target->lun_list, lun); pwp = ITRAN2PMC(tran); mutex_enter(&pwp->lock); @@ -431,6 +435,11 @@ pmcs_scsa_tran_tgt_free(dev_info_t *hba_dip, dev_info_t *tgt_dip, ASSERT(target->phy); phyp = target->phy; + pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, phyp, target, + "%s: for @%s tgt 0x%p phy 0x%p", __func__, unit_address, + (void *)target, (void *)phyp); + ddi_soft_state_bystr_free(lun->target->lun_sstate, unit_address); + if (target->recover_wait) { mutex_exit(&target->statlock); mutex_exit(&pwp->lock); @@ -1161,8 +1170,6 @@ pmcs_smp_init(dev_info_t *self, dev_info_t *child, ASSERT(pwp); if (pwp == NULL) return (DDI_FAILURE); - pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL, "%s: %s", __func__, - ddi_get_name(child)); /* Get "target-port" prop from devinfo node */ if (ddi_prop_lookup_string(DDI_DEV_T_ANY, child, @@ -1196,6 +1203,10 @@ pmcs_smp_init(dev_info_t *self, dev_info_t *child, return (DDI_FAILURE); } + pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, tgt, "%s: %s (%s)", + __func__, ddi_get_name(child), tgt_port); + + mutex_enter(&tgt->statlock); phy = tgt->phy; ASSERT(mutex_owned(&phy->phy_lock)); @@ -1211,11 +1222,13 @@ pmcs_smp_init(dev_info_t *self, dev_info_t *child, * to drop the lock so we can acquire the parent's lock. */ pphy = phy->parent; + mutex_exit(&tgt->statlock); pmcs_unlock_phy(phy); pmcs_lock_phy(pphy); wwn = pmcs_barray2wwn(pphy->sas_address); pmcs_unlock_phy(pphy); pmcs_lock_phy(phy); + mutex_enter(&tgt->statlock); } /* @@ -1254,13 +1267,15 @@ pmcs_smp_init(dev_info_t *self, dev_info_t *child, * Update the attached port and target port pm properties */ tgt->smpd = smp_sd; - pmcs_update_phy_pm_props(phy, 0, 0, B_TRUE); pmcs_unlock_phy(phy); mutex_exit(&pwp->lock); tgt->ref_count++; tgt->dtype = phy->dtype; + mutex_exit(&tgt->statlock); + + pmcs_update_phy_pm_props(phy, 0, 0, B_TRUE); addr = scsi_wwn_to_wwnstr(wwn, ua_form, NULL); if (smp_device_prop_update_string(smp_sd, SCSI_ADDR_PROP_ATTACHED_PORT, @@ -1279,6 +1294,7 @@ smp_init_fail: if (!IS_ROOT_PHY(phy)) { pmcs_dec_phy_ref_count(phy); } + mutex_exit(&tgt->statlock); pmcs_unlock_phy(phy); mutex_exit(&pwp->lock); ddi_soft_state_bystr_free(iport->tgt_sstate, tgt->unit_address); @@ -1306,8 +1322,6 @@ pmcs_smp_free(dev_info_t *self, dev_info_t *child, if (pwp == NULL) return; ASSERT(pwp); - pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL, "%s: %s", __func__, - ddi_get_name(child)); /* Get "target-port" prop from devinfo node */ if (ddi_prop_lookup_string(DDI_DEV_T_ANY, child, @@ -1327,6 +1341,9 @@ pmcs_smp_free(dev_info_t *self, dev_info_t *child, return; } + pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, tgt, "%s: %s (%s)", __func__, + ddi_get_name(child), tgt_port); + mutex_enter(&pwp->lock); mutex_enter(&tgt->statlock); if (tgt->phy) { @@ -3022,6 +3039,8 @@ pmcs_get_target(pmcs_iport_t *iport, char *tgt_port) DDI_INTR_PRI(pwp->intr_pri)); cv_init(&tgt->reset_cv, NULL, CV_DRIVER, NULL); cv_init(&tgt->abort_cv, NULL, CV_DRIVER, NULL); + list_create(&tgt->lun_list, sizeof (pmcs_lun_t), + offsetof(pmcs_lun_t, lun_list_next)); tgt->qdepth = 1; tgt->target_num = PMCS_INVALID_TARGET_NUM; bcopy(unit_address, tgt->unit_address, PMCS_MAX_UA_SIZE); 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 7996c0a95b..3752048fe5 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 @@ -40,7 +40,7 @@ static int tgtmap_usec = MICROSEC; static void pmcs_new_tport(pmcs_hw_t *, pmcs_phy_t *); static void pmcs_configure_expander(pmcs_hw_t *, pmcs_phy_t *, pmcs_iport_t *); -static boolean_t pmcs_check_expanders(pmcs_hw_t *, pmcs_phy_t *); +static void pmcs_check_expanders(pmcs_hw_t *, pmcs_phy_t *); static void pmcs_check_expander(pmcs_hw_t *, pmcs_phy_t *); static void pmcs_clear_expander(pmcs_hw_t *, pmcs_phy_t *, int); @@ -2305,7 +2305,6 @@ pmcs_discover(pmcs_hw_t *pwp) { pmcs_phy_t *pptr; pmcs_phy_t *root_phy; - boolean_t config_changed; DTRACE_PROBE2(pmcs__discover__entry, ulong_t, pwp->work_flags, boolean_t, pwp->config_changed); @@ -2396,14 +2395,15 @@ pmcs_discover(pmcs_hw_t *pwp) * changed until *after* we run pmcs_kill_devices. */ root_phy = pwp->root_phys; - config_changed = pmcs_check_expanders(pwp, root_phy); + pmcs_check_expanders(pwp, root_phy); /* * 2. Descend the tree looking for dead devices and kill them * by aborting all active commands and then deregistering them. */ - if (pmcs_kill_devices(pwp, root_phy) || config_changed) { - goto out; + if (pmcs_kill_devices(pwp, root_phy)) { + pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, NULL, NULL, + "%s: pmcs_kill_devices failed!", __func__); } /* @@ -3061,6 +3061,7 @@ pmcs_clear_phy(pmcs_hw_t *pwp, pmcs_phy_t *pptr) /* keep ref_count */ /* Don't clear iport on root PHYs - they are handled in pmcs_intr.c */ if (!IS_ROOT_PHY(pptr)) { + pptr->last_iport = pptr->iport; pptr->iport = NULL; } /* keep target */ @@ -3094,11 +3095,47 @@ pmcs_new_tport(pmcs_hw_t *pwp, pmcs_phy_t *pptr) pptr->changed = 0; /* - * If the PHY has no target pointer, see if there's a dead PHY that - * matches. + * If the PHY has no target pointer: + * + * If it's a root PHY, see if another PHY in the iport holds the + * target pointer (primary PHY changed). If so, move it over. + * + * If it's not a root PHY, see if there's a PHY on the dead_phys + * list that matches. */ if (pptr->target == NULL) { - pmcs_reap_dead_phy(pptr); + if (IS_ROOT_PHY(pptr)) { + pmcs_phy_t *rphy = pwp->root_phys; + + while (rphy) { + if (rphy == pptr) { + rphy = rphy->sibling; + continue; + } + + mutex_enter(&rphy->phy_lock); + if ((rphy->iport == pptr->iport) && + (rphy->target != NULL)) { + mutex_enter(&rphy->target->statlock); + pptr->target = rphy->target; + rphy->target = NULL; + pptr->target->phy = pptr; + /* The target is now on pptr */ + mutex_exit(&pptr->target->statlock); + mutex_exit(&rphy->phy_lock); + pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, + pptr, pptr->target, + "%s: Moved target from %s to %s", + __func__, rphy->path, pptr->path); + break; + } + mutex_exit(&rphy->phy_lock); + + rphy = rphy->sibling; + } + } else { + pmcs_reap_dead_phy(pptr); + } } /* @@ -3636,6 +3673,12 @@ pmcs_check_expander(pmcs_hw_t *pwp, pmcs_phy_t *pptr) pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, ctmp, NULL, "%s: %s type changed from NOTHING to %s", __func__, ctmp->path, PHY_TYPE(local)); + /* + * Since this PHY was nothing and is now + * something, reset the config_stop timer. + */ + ctmp->config_stop = ddi_get_lbolt() + + drv_usectohz(PMCS_MAX_CONFIG_TIME); } } else if (ctmp->atdt != local->atdt) { @@ -3773,11 +3816,10 @@ pmcs_check_expander(pmcs_hw_t *pwp, pmcs_phy_t *pptr) * each expander. Since we're not doing any configuration right now, it * doesn't matter if this is breadth-first. */ -static boolean_t +static void pmcs_check_expanders(pmcs_hw_t *pwp, pmcs_phy_t *pptr) { pmcs_phy_t *phyp, *pnext, *pchild; - boolean_t config_changed = B_FALSE; pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, pptr, NULL, "%s: %s", __func__, pptr->path); @@ -3786,7 +3828,7 @@ pmcs_check_expanders(pmcs_hw_t *pwp, pmcs_phy_t *pptr) * Check each expander at this level */ phyp = pptr; - while (phyp && !config_changed) { + while (phyp) { pmcs_lock_phy(phyp); if ((phyp->dtype == EXPANDER) && phyp->changed && @@ -3797,43 +3839,25 @@ pmcs_check_expanders(pmcs_hw_t *pwp, pmcs_phy_t *pptr) pnext = phyp->sibling; pmcs_unlock_phy(phyp); - - mutex_enter(&pwp->config_lock); - config_changed = pwp->config_changed; - mutex_exit(&pwp->config_lock); - phyp = pnext; } - if (config_changed) { - return (config_changed); - } - /* * Now check the children */ phyp = pptr; - while (phyp && !config_changed) { + while (phyp) { pmcs_lock_phy(phyp); pnext = phyp->sibling; pchild = phyp->children; pmcs_unlock_phy(phyp); if (pchild) { - (void) pmcs_check_expanders(pwp, pchild); + pmcs_check_expanders(pwp, pchild); } - mutex_enter(&pwp->config_lock); - config_changed = pwp->config_changed; - mutex_exit(&pwp->config_lock); - phyp = pnext; } - - /* - * We're done - */ - return (config_changed); } /* @@ -6609,7 +6633,6 @@ pmcs_clear_xp(pmcs_hw_t *pwp, pmcs_xscsi_t *xp) * but this device is going away anyway, so no matter. */ xp->dip = NULL; - xp->sd = NULL; xp->smpd = NULL; xp->special_running = 0; xp->recovering = 0; @@ -7529,6 +7552,7 @@ pmcs_reap_dead_phy(pmcs_phy_t *phyp) { pmcs_hw_t *pwp = phyp->pwp; pmcs_phy_t *ctmp; + pmcs_iport_t *iport_cmp; ASSERT(mutex_owned(&phyp->phy_lock)); @@ -7538,7 +7562,16 @@ pmcs_reap_dead_phy(pmcs_phy_t *phyp) mutex_enter(&pwp->dead_phylist_lock); ctmp = pwp->dead_phys; while (ctmp) { - if ((ctmp->iport != phyp->iport) || + /* + * If the iport is NULL, compare against last_iport. + */ + if (ctmp->iport) { + iport_cmp = ctmp->iport; + } else { + iport_cmp = ctmp->last_iport; + } + + if ((iport_cmp != phyp->iport) || (memcmp((void *)&ctmp->sas_address[0], (void *)&phyp->sas_address[0], 8))) { ctmp = ctmp->dead_next; @@ -7571,30 +7604,27 @@ pmcs_reap_dead_phy(pmcs_phy_t *phyp) */ if (ctmp) { pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, ctmp, NULL, - "%s: Found match in dead PHY list for new PHY %s", - __func__, phyp->path); + "%s: Found match in dead PHY list (0x%p) for new PHY %s", + __func__, (void *)ctmp, phyp->path); + /* + * If there is a pointer to the target in the dead PHY, move + * all reference counts to the new PHY. + */ if (ctmp->target) { - /* - * If there is a pointer to the target in the dead - * PHY, and that PHY's ref_count drops to 0, we can - * clear the target linkage now. If the PHY's - * ref_count is > 1, then there may be multiple - * LUNs still remaining, so leave the linkage. - */ - pmcs_inc_phy_ref_count(phyp); - pmcs_dec_phy_ref_count(ctmp); + mutex_enter(&ctmp->target->statlock); phyp->target = ctmp->target; + + while (ctmp->ref_count != 0) { + pmcs_inc_phy_ref_count(phyp); + pmcs_dec_phy_ref_count(ctmp); + } /* * Update the target's linkage as well */ - mutex_enter(&phyp->target->statlock); phyp->target->phy = phyp; phyp->target->dtype = phyp->dtype; + ctmp->target = NULL; mutex_exit(&phyp->target->statlock); - - if (ctmp->ref_count == 0) { - ctmp->target = NULL; - } } } } @@ -7806,13 +7836,22 @@ pmcs_update_phy_pm_props(pmcs_phy_t *phyp, uint64_t att_bv, uint64_t tgt_bv, return; } - if (phyp->target->sd) { - (void) scsi_device_prop_update_string(phyp->target->sd, - SCSI_DEVICE_PROP_PATH, SCSI_ADDR_PROP_ATTACHED_PORT_PM, - phyp->att_port_pm_str); - (void) scsi_device_prop_update_string(phyp->target->sd, - SCSI_DEVICE_PROP_PATH, SCSI_ADDR_PROP_TARGET_PORT_PM, - phyp->tgt_port_pm_str); + mutex_enter(&phyp->target->statlock); + if (!list_is_empty(&phyp->target->lun_list)) { + pmcs_lun_t *lunp; + + lunp = list_head(&phyp->target->lun_list); + while (lunp) { + (void) scsi_device_prop_update_string(lunp->sd, + SCSI_DEVICE_PROP_PATH, + SCSI_ADDR_PROP_ATTACHED_PORT_PM, + phyp->att_port_pm_str); + (void) scsi_device_prop_update_string(lunp->sd, + SCSI_DEVICE_PROP_PATH, + SCSI_ADDR_PROP_TARGET_PORT_PM, + phyp->tgt_port_pm_str); + lunp = list_next(&phyp->target->lun_list, lunp); + } } else if (phyp->target->smpd) { (void) smp_device_prop_update_string(phyp->target->smpd, SCSI_ADDR_PROP_ATTACHED_PORT_PM, @@ -7821,6 +7860,7 @@ pmcs_update_phy_pm_props(pmcs_phy_t *phyp, uint64_t att_bv, uint64_t tgt_bv, SCSI_ADDR_PROP_TARGET_PORT_PM, phyp->tgt_port_pm_str); } + mutex_exit(&phyp->target->statlock); } /* ARGSUSED */ diff --git a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs.h b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs.h index 556b7e05a0..c656e7f117 100644 --- a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs.h +++ b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs.h @@ -19,7 +19,7 @@ * CDDL HEADER END * * - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* @@ -130,7 +130,7 @@ struct pmcs_xscsi { kcondvar_t abort_cv; char *ua; pmcs_dtype_t dtype; - struct scsi_device *sd; /* Ptr to scsi_device */ + list_t lun_list; /* list of LUNs */ struct smp_device *smpd; /* Ptr to smp_device */ }; @@ -155,10 +155,12 @@ struct pmcs_xscsi { */ struct pmcs_lun { - pmcs_xscsi_t *target; - uint64_t lun_num; /* lun64 */ - scsi_lun_t scsi_lun; /* Wire format */ - char unit_address[PMCS_MAX_UA_SIZE]; + list_node_t lun_list_next; + pmcs_xscsi_t *target; + struct scsi_device *sd; + uint64_t lun_num; /* lun64 */ + scsi_lun_t scsi_lun; /* Wire format */ + char unit_address[PMCS_MAX_UA_SIZE]; }; /* diff --git a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_def.h b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_def.h index 507e27dee3..a9baf2e10e 100644 --- a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_def.h +++ b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_def.h @@ -19,7 +19,7 @@ * CDDL HEADER END * * - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _PMCS_DEF_H @@ -114,6 +114,7 @@ struct pmcs_phy { char path[32]; /* path name for this phy */ pmcs_hw_t *pwp; /* back ptr to hba struct */ pmcs_iport_t *iport; /* back ptr to the iport handle */ + pmcs_iport_t *last_iport; /* last iport this PHY was on */ pmcs_xscsi_t *target; /* back ptr to current target */ kstat_t *phy_stats; /* kstats for this phy */ /* |