changeset 12668:12abda5fe158

6957990 RCC hotplug causes panic - Deadlock: cycle in blocking chain 6962090 bad mutex panic in pmcs_update_phy_pm_props
author Srikanth Suravajhala <srikanth.suravajhala@oracle.com>
date Mon, 21 Jun 2010 17:58:51 -0400
parents 62bc4887874f
children d6e297b04d5d
files usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_scsa.c usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_subr.c usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_def.h
diffstat 3 files changed, 49 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_scsa.c	Mon Jun 21 14:10:34 2010 -0700
+++ b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_scsa.c	Mon Jun 21 17:58:51 2010 -0400
@@ -227,6 +227,8 @@
 	tgt = pmcs_get_target(iport, tgt_port, B_TRUE);
 
 	if (tgt == NULL) {
+		pmcs_prt(pwp, PMCS_PRT_DEBUG2, NULL, NULL, "%s: "
+		    "No tgt for tgt_port (%s)", __func__, tgt_port);
 		goto tgt_init_fail;
 	}
 
--- a/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_subr.c	Mon Jun 21 14:10:34 2010 -0700
+++ b/usr/src/uts/common/io/scsi/adapters/pmcs/pmcs_subr.c	Mon Jun 21 17:58:51 2010 -0400
@@ -3571,6 +3571,7 @@
 		 */
 		while (clist) {
 			ctmp = clist->sibling;
+			clist->target_addr = NULL;
 			kmem_cache_free(pwp->phy_cache, clist);
 			clist = ctmp;
 		}
@@ -3661,6 +3662,7 @@
 	while (clist) {
 		ctmp = clist->sibling;
 		pmcs_unlock_phy(clist);
+		clist->target_addr = NULL;
 		kmem_cache_free(pwp->phy_cache, clist);
 		clist = ctmp;
 	}
@@ -4822,6 +4824,7 @@
 pmcs_tag2wp(pmcs_hw_t *pwp, uint32_t htag, boolean_t lock_phy)
 {
 	pmcwork_t *p;
+	pmcs_phy_t *phyp;
 	uint32_t idx = PMCS_TAG_INDEX(htag);
 
 	p = &pwp->work[idx];
@@ -4829,9 +4832,28 @@
 	mutex_enter(&p->lock);
 	if (p->htag == htag) {
 		if (lock_phy) {
-			mutex_exit(&p->lock);
-			mutex_enter(&p->phy->phy_lock);
-			mutex_enter(&p->lock);
+			phyp = p->phy;
+			if (phyp != NULL) {
+				/* phy lock should be held before work lock */
+				mutex_exit(&p->lock);
+				mutex_enter(&phyp->phy_lock);
+				mutex_enter(&p->lock);
+			}
+			/*
+			 * Check htag again, in case the work got completed
+			 * while we dropped the work lock and got the phy lock
+			 */
+			if (p->htag != htag) {
+				if (phyp != NULL) {
+					mutex_exit(&p->lock);
+					mutex_exit(&phyp->phy_lock);
+				}
+				pmcs_prt(pwp, PMCS_PRT_DEBUG, phyp, NULL, "%s: "
+				    "HTAG (0x%x) found, but work (0x%p) "
+				    "is already complete", __func__, htag,
+				    (void *)p);
+				return (NULL);
+			}
 		}
 		return (p);
 	}
@@ -7502,6 +7524,7 @@
 		}
 
 		if (!IS_ROOT_PHY(tphyp)) {
+			tphyp->target_addr = NULL;
 			kmem_cache_free(pwp->phy_cache, tphyp);
 		}
 	}
@@ -7509,6 +7532,7 @@
 	mutex_enter(&pwp->dead_phylist_lock);
 	for (tphyp = pwp->dead_phys; tphyp; tphyp = nphyp) {
 		nphyp = tphyp->dead_next;
+		tphyp->target_addr = NULL;
 		kmem_cache_free(pwp->phy_cache, tphyp);
 	}
 	pwp->dead_phys = NULL;
@@ -7528,6 +7552,7 @@
 	while (phyp) {
 		next_phy = phyp->sibling;
 		ASSERT(!mutex_owned(&phyp->phy_lock));
+		phyp->target_addr = NULL;
 		kmem_cache_free(pwp->phy_cache, phyp);
 		phyp = next_phy;
 	}
@@ -7554,6 +7579,7 @@
 	 * Go ahead and just copy everything...
 	 */
 	*local = *orig_phy;
+	local->target_addr = &orig_phy->target;
 
 	/*
 	 * But the following must be set appropriately for this copy
@@ -7755,6 +7781,7 @@
 				mutex_exit(&phyp->target->statlock);
 			}
 			pmcs_unlock_phy(phyp);
+			phyp->target_addr = NULL;
 			kmem_cache_free(pwp->phy_cache, phyp);
 		}
 
@@ -8042,6 +8069,8 @@
 pmcs_update_phy_pm_props(pmcs_phy_t *phyp, uint64_t att_bv, uint64_t tgt_bv,
     boolean_t prop_add_val)
 {
+	pmcs_xscsi_t	*tgt;
+
 	if (prop_add_val) {
 		/*
 		 * If the values are currently 0, then we're setting the
@@ -8078,15 +8107,19 @@
 		}
 	}
 
-	if (phyp->target == NULL) {
+	if ((phyp->target_addr) && (*phyp->target_addr != NULL)) {
+		tgt = *phyp->target_addr;
+	} else if (phyp->target != NULL) {
+		tgt = phyp->target;
+	} else {
 		return;
 	}
 
-	mutex_enter(&phyp->target->statlock);
-	if (!list_is_empty(&phyp->target->lun_list)) {
+	mutex_enter(&tgt->statlock);
+	if (!list_is_empty(&tgt->lun_list)) {
 		pmcs_lun_t *lunp;
 
-		lunp = list_head(&phyp->target->lun_list);
+		lunp = list_head(&tgt->lun_list);
 		while (lunp) {
 			(void) scsi_device_prop_update_string(lunp->sd,
 			    SCSI_DEVICE_PROP_PATH,
@@ -8096,17 +8129,17 @@
 			    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,
+			lunp = list_next(&tgt->lun_list, lunp);
+		}
+	} else if (tgt->smpd) {
+		(void) smp_device_prop_update_string(tgt->smpd,
 		    SCSI_ADDR_PROP_ATTACHED_PORT_PM,
 		    phyp->att_port_pm_str);
-		(void) smp_device_prop_update_string(phyp->target->smpd,
+		(void) smp_device_prop_update_string(tgt->smpd,
 		    SCSI_ADDR_PROP_TARGET_PORT_PM,
 		    phyp->tgt_port_pm_str);
 	}
-	mutex_exit(&phyp->target->statlock);
+	mutex_exit(&tgt->statlock);
 }
 
 /* ARGSUSED */
--- a/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_def.h	Mon Jun 21 14:10:34 2010 -0700
+++ b/usr/src/uts/common/sys/scsi/adapters/pmcs/pmcs_def.h	Mon Jun 21 17:58:51 2010 -0400
@@ -125,6 +125,7 @@
 	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 */
+	pmcs_xscsi_t	**target_addr;	/* address of real target pointer */
 	kstat_t		*phy_stats;	/* kstats for this phy */
 	/*
 	 * Attached port phy mask and target port phymask.  With 16 bytes