Mercurial > illumos > illumos-gate
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