changeset 10336:d12a11a8c2b8 onnv_122

backout 6746823: causes 6872746
author jmcp <James.McPherson@Sun.COM>
date Mon, 17 Aug 2009 22:28:08 -0700
parents bebd52b78199
children 75ffadc191c9
files usr/src/uts/common/io/sata/adapters/nv_sata/nv_sata.c usr/src/uts/common/sys/sata/adapters/nv_sata/nv_sata.h usr/src/uts/common/sys/sata/adapters/nv_sata/nv_sgpio.h
diffstat 3 files changed, 153 insertions(+), 192 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/io/sata/adapters/nv_sata/nv_sata.c	Mon Aug 17 22:18:44 2009 -0700
+++ b/usr/src/uts/common/io/sata/adapters/nv_sata/nv_sata.c	Mon Aug 17 22:28:08 2009 -0700
@@ -171,6 +171,8 @@
 static int nv_sgp_detect(ddi_acc_handle_t pci_conf_handle, uint16_t *csrpp,
     uint32_t *cbpp);
 static int nv_sgp_init(nv_ctl_t *nvc);
+static void nv_sgp_reset(nv_ctl_t *nvc);
+static int nv_sgp_init_cmd(nv_ctl_t *nvc);
 static int nv_sgp_check_set_cmn(nv_ctl_t *nvc);
 static int nv_sgp_csr_read(nv_ctl_t *nvc);
 static void nv_sgp_csr_write(nv_ctl_t *nvc, uint32_t val);
@@ -350,34 +352,6 @@
  */
 static void *nv_statep	= NULL;
 
-/*
- * Map from CBP to shared space
- *
- * When a MCP55/IO55 parts supports SGPIO, there is a single CBP (SGPIO
- * Control Block Pointer as well as the corresponding Control Block) that
- * is shared across all driver instances associated with that part.  The
- * Control Block is used to update and query the LED state for the devices
- * on the controllers associated with those instances.  There is also some
- * driver state (called the 'common' area here) associated with each SGPIO
- * Control Block.  The nv_sgp_cpb2cmn is used to map a given CBP to its
- * control area.
- *
- * The driver can also use this mapping array to determine whether the
- * common area for a given CBP has been initialized, and, if it isn't
- * initialized, initialize it.
- *
- * When a driver instance with a CBP value that is already in the array is
- * initialized, it will use the pointer to the previously initialized common
- * area associated with that SGPIO CBP value, rather than initialize it
- * itself.
- *
- * nv_sgp_c2c_mutex is used to synchronize access to this mapping array.
- */
-#ifdef SGPIO_SUPPORT
-static kmutex_t nv_sgp_c2c_mutex;
-static struct nv_sgp_cbp2cmn nv_sgp_cbp2cmn[NV_MAX_CBPS];
-#endif
-
 /* We still have problems in 40-bit DMA support, so disable it by default */
 int nv_sata_40bit_dma = B_FALSE;
 
@@ -395,9 +369,6 @@
 _init(void)
 {
 	int	error;
-#ifdef SGPIO_SUPPORT
-	int	i;
-#endif
 
 	error = ddi_soft_state_init(&nv_statep, sizeof (nv_ctl_t), 0);
 
@@ -407,14 +378,6 @@
 	}
 
 	mutex_init(&nv_log_mutex, NULL, MUTEX_DRIVER, NULL);
-#ifdef SGPIO_SUPPORT
-	mutex_init(&nv_sgp_c2c_mutex, NULL, MUTEX_DRIVER, NULL);
-
-	for (i = 0; i < NV_MAX_CBPS; i++) {
-		nv_sgp_cbp2cmn[i].c2cm_cbp = 0;
-		nv_sgp_cbp2cmn[i].c2cm_cmn = NULL;
-	}
-#endif
 
 	if ((error = sata_hba_init(&modlinkage)) != 0) {
 		ddi_soft_state_fini(&nv_statep);
@@ -454,9 +417,6 @@
 	 * remove the resources allocated in _init()
 	 */
 	mutex_destroy(&nv_log_mutex);
-#ifdef SGPIO_SUPPORT
-	mutex_destroy(&nv_sgp_c2c_mutex);
-#endif
 	sata_hba_fini(&modlinkage);
 	ddi_soft_state_fini(&nv_statep);
 
@@ -5782,7 +5742,6 @@
 	uint16_t csrp;		/* SGPIO_CSRP from PCI config space */
 	uint32_t cbp;		/* SGPIO_CBP from PCI config space */
 	nv_sgp_cmn_t *cmn;	/* shared data structure */
-	int i;
 	char tqname[SGPIO_TQ_NAME_LEN];
 	extern caddr_t psm_map_phys_new(paddr_t, size_t, int);
 
@@ -5828,7 +5787,7 @@
 	/* save off the SGPIO_CSR I/O address */
 	nvc->nvc_sgp_csr = csrp;
 
-	/* map in Control Block */
+	/* map in Command Block */
 	nvc->nvc_sgp_cbp = (nv_sgp_cb_t *)psm_map_phys_new(cbp,
 	    sizeof (nv_sgp_cb_t), PROT_READ | PROT_WRITE);
 
@@ -5838,39 +5797,14 @@
 		    "!Unable to initialize SGPIO");
 	}
 
-	/*
-	 * Initialize the shared space for this instance.  This could
-	 * involve allocating the space, saving a pointer to the space
-	 * and starting the taskq that actually turns the LEDs on and off.
-	 * Or, it could involve just getting the pointer to the already
-	 * allocated space.
-	 */
-
-	mutex_enter(&nv_sgp_c2c_mutex);
-
-	/* try and find our CBP in the mapping table */
-	cmn = NULL;
-	for (i = 0; i < NV_MAX_CBPS; i++) {
-		if (nv_sgp_cbp2cmn[i].c2cm_cbp == cbp) {
-			cmn = nv_sgp_cbp2cmn[i].c2cm_cmn;
-			break;
-		}
-
-		if (nv_sgp_cbp2cmn[i].c2cm_cbp == 0)
-			break;
-	}
-
-	if (i >= NV_MAX_CBPS) {
+	if (nvc->nvc_ctlr_num == 0) {
 		/*
-		 * CBP to shared space mapping table is full
-		 */
-		nvc->nvc_sgp_cmn = NULL;
-		nv_cmn_err(CE_WARN, nvc, NULL,
-		    "!LED handling not initialized - too many controllers");
-	} else if (cmn == NULL) {
-		/*
-		 * Allocate the shared space, point the SGPIO scratch register
-		 * at it and start the led update taskq.
+		 * Controller 0 on the MCP5X/IO55 initialized the SGPIO
+		 * and the data that is shared between the controllers.
+		 * The clever thing to do would be to let the first controller
+		 * that comes up be the one that initializes all this.
+		 * However, SGPIO state is not necessarily zeroed between
+		 * between OS reboots, so there might be old data there.
 		 */
 
 		/* allocate shared space */
@@ -5885,10 +5819,10 @@
 		nvc->nvc_sgp_cmn = cmn;
 
 		/* initialize the shared data structure */
+		cmn->nvs_magic = SGPIO_MAGIC;
 		cmn->nvs_in_use = (1 << nvc->nvc_ctlr_num);
 		cmn->nvs_connected = 0;
 		cmn->nvs_activity = 0;
-		cmn->nvs_cbp = cbp;
 
 		mutex_init(&cmn->nvs_slock, NULL, MUTEX_DRIVER, NULL);
 		mutex_init(&cmn->nvs_tlock, NULL, MUTEX_DRIVER, NULL);
@@ -5901,12 +5835,6 @@
 		nvc->nvc_sgp_cbp->sgpio_sr = (uint32_t)cmn;
 #endif
 
-		/* add an entry to the cbp to cmn mapping table */
-
-		/* i should be the next available table position */
-		nv_sgp_cbp2cmn[i].c2cm_cbp = cbp;
-		nv_sgp_cbp2cmn[i].c2cm_cmn = cmn;
-
 		/* start the activity LED taskq */
 
 		/*
@@ -5925,12 +5853,27 @@
 			(void) ddi_taskq_dispatch(cmn->nvs_taskq,
 			    nv_sgp_activity_led_ctl, nvc, DDI_SLEEP);
 		}
-	} else {
-		nvc->nvc_sgp_cmn = cmn;
-		cmn->nvs_in_use |= (1 << nvc->nvc_ctlr_num);
-	}
-
-	mutex_exit(&nv_sgp_c2c_mutex);
+
+	} else if (nvc->nvc_ctlr_num == 1) {
+		/*
+		 * Controller 1 confirms that SGPIO has been initialized
+		 * and, if so, try to get the shared data pointer, otherwise
+		 * get the shared data pointer when accessing the data.
+		 */
+
+		if (nvc->nvc_sgp_cbp->sgpio_sr != 0) {
+			cmn = (nv_sgp_cmn_t *)nvc->nvc_sgp_cbp->sgpio_sr;
+
+			/*
+			 * It looks like a pointer, but is it the shared data?
+			 */
+			if (cmn->nvs_magic == SGPIO_MAGIC) {
+				nvc->nvc_sgp_cmn = cmn;
+
+				cmn->nvs_in_use |= (1 << nvc->nvc_ctlr_num);
+			}
+		}
+	}
 }
 
 /*
@@ -5960,89 +5903,38 @@
 
 /*
  * nv_sgp_init
- * Initialize SGPIO.
- * The initialization process is described by NVIDIA, but the hardware does
- * not always behave as documented, so several steps have been changed and/or
- * omitted.
+ * Initialize SGPIO.  The process is specified by NVIDIA.
  */
 static int
 nv_sgp_init(nv_ctl_t *nvc)
 {
-	int seq;
-	int rval = NV_SUCCESS;
-	hrtime_t start, end;
-	uint32_t cmd;
 	uint32_t status;
 	int drive_count;
 
+	/*
+	 * if SGPIO status set to SGPIO_STATE_RESET, logic has been
+	 * reset and needs to be initialized.
+	 */
 	status = nv_sgp_csr_read(nvc);
 	if (SGPIO_CSR_SSTAT(status) == SGPIO_STATE_RESET) {
-		/* SGPIO logic is in reset state and requires initialization */
-
-		/* noting the Sequence field value */
-		seq = SGPIO_CSR_SEQ(status);
-
-		/* issue SGPIO_CMD_READ_PARAMS command */
-		cmd = SGPIO_CSR_CMD_SET(SGPIO_CMD_READ_PARAMS);
-		nv_sgp_csr_write(nvc, cmd);
-
-		DTRACE_PROBE2(sgpio__cmd, int, cmd, int, status);
-
-		/* poll for command completion */
-		start = gethrtime();
-		end = start + NV_SGP_CMD_TIMEOUT;
-		for (;;) {
-			status = nv_sgp_csr_read(nvc);
-
-			/* break on error */
-			if (SGPIO_CSR_CSTAT(status) == SGPIO_CMD_ERROR) {
+		if (nv_sgp_init_cmd(nvc) == NV_FAILURE) {
+			/* reset and try again */
+			nv_sgp_reset(nvc);
+			if (nv_sgp_init_cmd(nvc) == NV_FAILURE) {
 				NVLOG((NVDBG_ALWAYS, nvc, NULL,
-				    "Command error during initialization"));
-				rval = NV_FAILURE;
-				break;
+				    "SGPIO init failed"));
+				return (NV_FAILURE);
 			}
-
-			/* command processing is taking place */
-			if (SGPIO_CSR_CSTAT(status) == SGPIO_CMD_OK) {
-				if (SGPIO_CSR_SEQ(status) != seq) {
-					NVLOG((NVDBG_ALWAYS, nvc, NULL,
-					    "Sequence number change error"));
-				}
-
-				break;
-			}
-
-			/* if completion not detected in 2000ms ... */
-
-			if (gethrtime() > end)
-				break;
-
-			/* wait 400 ns before checking again */
-			NV_DELAY_NSEC(400);
 		}
 	}
 
-	if (rval == NV_FAILURE)
-		return (rval);
-
-	if (SGPIO_CSR_SSTAT(status) != SGPIO_STATE_OPERATIONAL) {
-		NVLOG((NVDBG_ALWAYS, nvc, NULL,
-		    "SGPIO logic not operational after init - state %d",
-		    SGPIO_CSR_SSTAT(status)));
-		/*
-		 * Should return (NV_FAILURE) but the hardware can be
-		 * operational even if the SGPIO Status does not indicate
-		 * this.
-		 */
-	}
-
 	/*
 	 * NVIDIA recommends reading the supported drive count even
-	 * though they also indicate that it is always 4 at this time.
+	 * though they also indicate that it is 4 at this time.
 	 */
 	drive_count = SGP_CR0_DRV_CNT(nvc->nvc_sgp_cbp->sgpio_cr0);
 	if (drive_count != SGPIO_DRV_CNT_VALUE) {
-		NVLOG((NVDBG_INIT, nvc, NULL,
+		NVLOG((NVDBG_ALWAYS, nvc, NULL,
 		    "SGPIO reported undocumented drive count - %d",
 		    drive_count));
 	}
@@ -6051,22 +5943,109 @@
 	    "initialized ctlr: %d csr: 0x%08x",
 	    nvc->nvc_ctlr_num, nvc->nvc_sgp_csr));
 
-	return (rval);
+	return (NV_SUCCESS);
+}
+
+static void
+nv_sgp_reset(nv_ctl_t *nvc)
+{
+	uint32_t cmd;
+	uint32_t status;
+
+	cmd = SGPIO_CMD_RESET;
+	nv_sgp_csr_write(nvc, cmd);
+
+	status = nv_sgp_csr_read(nvc);
+
+	if (SGPIO_CSR_CSTAT(status) != SGPIO_CMD_OK) {
+		NVLOG((NVDBG_ALWAYS, nvc, NULL,
+		    "SGPIO reset failed: CSR - 0x%x", status));
+	}
+}
+
+static int
+nv_sgp_init_cmd(nv_ctl_t *nvc)
+{
+	int seq;
+	hrtime_t start, end;
+	uint32_t status;
+	uint32_t cmd;
+
+	/* get the old sequence value */
+	status = nv_sgp_csr_read(nvc);
+	seq = SGPIO_CSR_SEQ(status);
+
+	/* check the state since we have the info anyway */
+	if (SGPIO_CSR_SSTAT(status) != SGPIO_STATE_OPERATIONAL) {
+		NVLOG((NVDBG_ALWAYS, nvc, NULL,
+		    "SGPIO init_cmd: state not operational"));
+	}
+
+	/* issue command */
+	cmd = SGPIO_CSR_CMD_SET(SGPIO_CMD_READ_PARAMS);
+	nv_sgp_csr_write(nvc, cmd);
+
+	DTRACE_PROBE2(sgpio__cmd, int, cmd, int, status);
+
+	/* poll for completion */
+	start = gethrtime();
+	end = start + NV_SGP_CMD_TIMEOUT;
+	for (;;) {
+		status = nv_sgp_csr_read(nvc);
+
+		/* break on error */
+		if (SGPIO_CSR_CSTAT(status) == SGPIO_CMD_ERROR)
+			break;
+
+		/* break on command completion (seq changed) */
+		if (SGPIO_CSR_SEQ(status) != seq) {
+			if (SGPIO_CSR_CSTAT(status) == SGPIO_CMD_ACTIVE) {
+				NVLOG((NVDBG_ALWAYS, nvc, NULL,
+				    "Seq changed but command still active"));
+			}
+
+			break;
+		}
+
+		/* Wait 400 ns and try again */
+		NV_DELAY_NSEC(400);
+
+		if (gethrtime() > end)
+			break;
+	}
+
+	if (SGPIO_CSR_CSTAT(status) == SGPIO_CMD_OK)
+		return (NV_SUCCESS);
+
+	return (NV_FAILURE);
 }
 
 static int
 nv_sgp_check_set_cmn(nv_ctl_t *nvc)
 {
-	nv_sgp_cmn_t *cmn = nvc->nvc_sgp_cmn;
-
-	if (cmn == NULL)
+	nv_sgp_cmn_t *cmn;
+
+	if (nvc->nvc_sgp_cbp == NULL)
 		return (NV_FAILURE);
 
-	mutex_enter(&cmn->nvs_slock);
-	cmn->nvs_in_use |= (1 << nvc->nvc_ctlr_num);
-	mutex_exit(&cmn->nvs_slock);
-
-	return (NV_SUCCESS);
+	/* check to see if Scratch Register is set */
+	if (nvc->nvc_sgp_cbp->sgpio_sr != 0) {
+		nvc->nvc_sgp_cmn =
+		    (nv_sgp_cmn_t *)nvc->nvc_sgp_cbp->sgpio_sr;
+
+		if (nvc->nvc_sgp_cmn->nvs_magic != SGPIO_MAGIC)
+			return (NV_FAILURE);
+
+		cmn = nvc->nvc_sgp_cmn;
+
+		mutex_enter(&cmn->nvs_slock);
+		cmn->nvs_in_use |= (1 << nvc->nvc_ctlr_num);
+		mutex_exit(&cmn->nvs_slock);
+
+		return (NV_SUCCESS);
+	}
+
+	return (NV_FAILURE);
 }
 
 /*
@@ -6099,7 +6078,7 @@
 
 /*
  * nv_sgp_write_data
- * Cause SGPIO to send Control Block data
+ * Cause SGPIO to send Command Block data
  */
 static int
 nv_sgp_write_data(nv_ctl_t *nvc)
@@ -6327,7 +6306,7 @@
 /*
  * nv_sgp_locate
  * Turns the Locate/OK2RM LED off or on for a particular drive.  State is
- * maintained in the SGPIO Control Block.
+ * maintained in the SGPIO Command Block.
  */
 static void
 nv_sgp_locate(nv_ctl_t *nvc, int drive, int value)
@@ -6368,7 +6347,7 @@
 /*
  * nv_sgp_error
  * Turns the Error/Failure LED off or on for a particular drive.  State is
- * maintained in the SGPIO Control Block.
+ * maintained in the SGPIO Command Block.
  */
 static void
 nv_sgp_error(nv_ctl_t *nvc, int drive, int value)
@@ -6409,7 +6388,7 @@
 static void
 nv_sgp_cleanup(nv_ctl_t *nvc)
 {
-	int drive, i;
+	int drive;
 	uint8_t drv_leds;
 	uint32_t led_state;
 	volatile nv_sgp_cb_t *cb = nvc->nvc_sgp_cbp;
@@ -6417,7 +6396,7 @@
 	extern void psm_unmap_phys(caddr_t, size_t);
 
 	/*
-	 * If the SGPIO Control Block isn't mapped or the shared data
+	 * If the SGPIO command block isn't mapped or the shared data
 	 * structure isn't present in this instance, there isn't much that
 	 * can be cleaned up.
 	 */
@@ -6468,17 +6447,6 @@
 
 		cb->sgpio_sr = NULL;
 
-		/* zero out the CBP to cmn mapping */
-		for (i = 0; i < NV_MAX_CBPS; i++) {
-			if (nv_sgp_cbp2cmn[i].c2cm_cbp == cmn->nvs_cbp) {
-				nv_sgp_cbp2cmn[i].c2cm_cmn = NULL;
-				break;
-			}
-
-			if (nv_sgp_cbp2cmn[i].c2cm_cbp == 0)
-				break;
-		}
-
 		/* free resources */
 		cv_destroy(&cmn->nvs_cv);
 		mutex_destroy(&cmn->nvs_tlock);
@@ -6489,7 +6457,7 @@
 
 	nvc->nvc_sgp_cmn = NULL;
 
-	/* unmap the SGPIO Control Block */
+	/* unmap the SGPIO Command Block */
 	psm_unmap_phys((caddr_t)nvc->nvc_sgp_cbp, sizeof (nv_sgp_cb_t));
 }
 #endif	/* SGPIO_SUPPORT */
--- a/usr/src/uts/common/sys/sata/adapters/nv_sata/nv_sata.h	Mon Aug 17 22:18:44 2009 -0700
+++ b/usr/src/uts/common/sys/sata/adapters/nv_sata/nv_sata.h	Mon Aug 17 22:28:08 2009 -0700
@@ -103,7 +103,7 @@
 	int		nvc_mcp5x_flag;	/* is the controller MCP51/MCP55 */
 	uint8_t		nvc_ctlr_num;	/* controller number within the part */
 	uint32_t	nvc_sgp_csr;	/* SGPIO CSR i/o address */
-	volatile nv_sgp_cb_t *nvc_sgp_cbp; /* SGPIO Control Block */
+	volatile nv_sgp_cb_t *nvc_sgp_cbp; /* SGPIO Command Block */
 	nv_sgp_cmn_t	*nvc_sgp_cmn;	/* SGPIO shared data */
 #endif
 } nv_ctl_t;
@@ -208,21 +208,16 @@
 
 #ifdef SGPIO_SUPPORT
 struct nv_sgp_cmn {
+	uint16_t	nvs_magic;	/* verification of valid structure */
 	uint8_t		nvs_in_use;	/* bit-field of active ctlrs */
 	uint8_t		nvs_connected;	/* port connected bit-field flag */
 	uint8_t		nvs_activity;	/* port usage bit-field flag */
-	int		nvs_cbp;	/* SGPIO Control Block Pointer */
 	int		nvs_taskq_delay; /* rest time for activity LED taskq */
 	kmutex_t	nvs_slock;	/* lock for shared data */
 	kmutex_t	nvs_tlock;	/* lock for taskq */
 	kcondvar_t	nvs_cv;		/* condition variable for taskq wait */
 	ddi_taskq_t	*nvs_taskq;	/* activity LED taskq */
 };
-
-struct nv_sgp_cbp2cmn {
-	uint32_t	c2cm_cbp;	/* ctlr block ptr from pci cfg space */
-	nv_sgp_cmn_t	*c2cm_cmn;	/* point to common space */
-};
 #endif
 
 
@@ -682,9 +677,7 @@
 #define	NV_COPY_SSREGS   0x04	/* SS port registers */
 
 #ifdef SGPIO_SUPPORT
-#define	NV_MAX_CBPS	16		/* Maximum # of Control Block */
-					/* Pointers.  Corresponds to */
-					/* each MCP55 and IO55 */
+#define	SGPIO_MAGIC		0x39da	/* verifies good sgpio struct */
 #define	SGPIO_LOOP_WAIT_USECS	62500	/* 1/16 second (in usecs) */
 #define	SGPIO_TQ_NAME_LEN	32
 
--- a/usr/src/uts/common/sys/sata/adapters/nv_sata/nv_sgpio.h	Mon Aug 17 22:18:44 2009 -0700
+++ b/usr/src/uts/common/sys/sata/adapters/nv_sata/nv_sgpio.h	Mon Aug 17 22:28:08 2009 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -33,9 +33,9 @@
 #endif
 
 /*
- * SGPIO Command Timeout (2000ms, in nsecs)
+ * SGPIO Command Timeout (2000ms, in usecs)
  */
-#define	NV_SGP_CMD_TIMEOUT	2000000000
+#define	NV_SGP_CMD_TIMEOUT	2000000
 
 /*
  * SGPIO Configuration Space Offsets