summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Hollister <David.Hollister@Sun.COM>2010-01-14 18:36:25 -0700
committerDavid Hollister <David.Hollister@Sun.COM>2010-01-14 18:36:25 -0700
commit73a3eccd27d9673a6407274ea0de350699562fd9 (patch)
treea647759228ad8b0be75c1408710bab9c618be937
parentaef83d42faaccf25ad8bd8dc892c2fb6fa7efdad (diff)
downloadillumos-joyent-73a3eccd27d9673a6407274ea0de350699562fd9.tar.gz
6906811 assertion failed: pptr->children == NULL
6914773 assertion failed !MDI_PI_LOCKED(pip), file: ../../common/os/sunmdi.c
-rw-r--r--usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_intr.c2
-rw-r--r--usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_scsa.c37
-rw-r--r--usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_subr.c152
-rw-r--r--usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs.h14
-rw-r--r--usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_def.h3
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 */
/*