summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorjmcp <James.McPherson@Sun.COM>2009-08-17 22:28:08 -0700
committerjmcp <James.McPherson@Sun.COM>2009-08-17 22:28:08 -0700
commite958170623715627b654652bc5d495b46d01f0f1 (patch)
tree7c467bc593e07528068993d027e332524213f584 /usr/src
parentb693132f48f19b8c1bd613e914faf3589565cb57 (diff)
downloadillumos-joyent-e958170623715627b654652bc5d495b46d01f0f1.tar.gz
backout 6746823: causes 6872746
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/io/sata/adapters/nv_sata/nv_sata.c320
-rw-r--r--usr/src/uts/common/sys/sata/adapters/nv_sata/nv_sata.h13
-rw-r--r--usr/src/uts/common/sys/sata/adapters/nv_sata/nv_sgpio.h6
3 files changed, 150 insertions, 189 deletions
diff --git a/usr/src/uts/common/io/sata/adapters/nv_sata/nv_sata.c b/usr/src/uts/common/io/sata/adapters/nv_sata/nv_sata.c
index 528b4aca85..1a1cdf93d9 100644
--- a/usr/src/uts/common/io/sata/adapters/nv_sata/nv_sata.c
+++ b/usr/src/uts/common/io/sata/adapters/nv_sata/nv_sata.c
@@ -171,6 +171,8 @@ static void nv_sgp_led_init(nv_ctl_t *nvc, ddi_acc_handle_t pci_conf_handle);
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 @@ int non_ncq_commands = 0;
*/
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 @@ int
_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 @@ _init(void)
}
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 @@ _fini(void)
* 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 @@ nv_sgp_led_init(nv_ctl_t *nvc, ddi_acc_handle_t pci_conf_handle)
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 @@ nv_sgp_led_init(nv_ctl_t *nvc, ddi_acc_handle_t pci_conf_handle)
/* 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 @@ nv_sgp_led_init(nv_ctl_t *nvc, ddi_acc_handle_t pci_conf_handle)
"!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) {
- /*
- * 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) {
+ if (nvc->nvc_ctlr_num == 0) {
/*
- * 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 @@ nv_sgp_led_init(nv_ctl_t *nvc, ddi_acc_handle_t pci_conf_handle)
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 @@ nv_sgp_led_init(nv_ctl_t *nvc, ddi_acc_handle_t pci_conf_handle)
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 @@ nv_sgp_led_init(nv_ctl_t *nvc, ddi_acc_handle_t pci_conf_handle)
(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_detect(ddi_acc_handle_t pci_conf_handle, uint16_t *csrpp,
/*
* 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 @@ nv_sgp_init(nv_ctl_t *nvc)
"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;
+ nv_sgp_cmn_t *cmn;
- if (cmn == NULL)
+ 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);
+ /* 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;
- return (NV_SUCCESS);
+ 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_csr_write(nv_ctl_t *nvc, uint32_t val)
/*
* 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_drive_active(nv_ctl_t *nvc, int drive)
/*
* 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_locate(nv_ctl_t *nvc, int drive, int value)
/*
* 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 @@ nv_sgp_error(nv_ctl_t *nvc, int drive, int value)
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 @@ nv_sgp_cleanup(nv_ctl_t *nvc)
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 @@ nv_sgp_cleanup(nv_ctl_t *nvc)
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 @@ nv_sgp_cleanup(nv_ctl_t *nvc)
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 */
diff --git a/usr/src/uts/common/sys/sata/adapters/nv_sata/nv_sata.h b/usr/src/uts/common/sys/sata/adapters/nv_sata/nv_sata.h
index 06247b41cd..855753516f 100644
--- a/usr/src/uts/common/sys/sata/adapters/nv_sata/nv_sata.h
+++ b/usr/src/uts/common/sys/sata/adapters/nv_sata/nv_sata.h
@@ -103,7 +103,7 @@ typedef struct nv_ctl {
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 @@ typedef struct nv_slot {
#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 @@ typedef struct prde {
#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
diff --git a/usr/src/uts/common/sys/sata/adapters/nv_sata/nv_sgpio.h b/usr/src/uts/common/sys/sata/adapters/nv_sata/nv_sgpio.h
index 4ec5daf321..8727a974db 100644
--- a/usr/src/uts/common/sys/sata/adapters/nv_sata/nv_sgpio.h
+++ b/usr/src/uts/common/sys/sata/adapters/nv_sata/nv_sgpio.h
@@ -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 @@ extern "C" {
#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