diff options
-rw-r--r-- | usr/src/uts/common/io/cpqary3/cpqary3.c | 4 | ||||
-rw-r--r-- | usr/src/uts/common/io/cpqary3/cpqary3.h | 2 | ||||
-rw-r--r-- | usr/src/uts/common/io/cpqary3/cpqary3_ciss.h | 57 | ||||
-rw-r--r-- | usr/src/uts/common/io/cpqary3/cpqary3_isr.c | 30 | ||||
-rw-r--r-- | usr/src/uts/common/io/cpqary3/cpqary3_talk2ctlr.c | 456 | ||||
-rw-r--r-- | usr/src/uts/common/io/cpqary3/cpqary3_transport.c | 20 | ||||
-rw-r--r-- | usr/src/uts/common/io/cpqary3/cpqary3_util.c | 5 |
7 files changed, 272 insertions, 302 deletions
diff --git a/usr/src/uts/common/io/cpqary3/cpqary3.c b/usr/src/uts/common/io/cpqary3/cpqary3.c index 622f0dcf68..ff4aada92c 100644 --- a/usr/src/uts/common/io/cpqary3/cpqary3.c +++ b/usr/src/uts/common/io/cpqary3/cpqary3.c @@ -879,7 +879,7 @@ cpqary3_update_ctlrdetails(cpqary3_t *cpqary3p, uint32_t *cleanstatus) */ retvalue = ddi_regs_map_setup(cpqary3p->dip, mem_bar0, /* INDEX_PCI_BASE0, */ - (caddr_t *)&cpqary3p->idr, (offset_t)I2O_IBDB_SET, map_len, + (caddr_t *)&cpqary3p->idr, (offset_t)I2O_INBOUND_DOORBELL, map_len, &cpqary3_dev_attributes, &cpqary3p->idr_handle); if (retvalue != DDI_SUCCESS) { @@ -926,7 +926,7 @@ cpqary3_update_ctlrdetails(cpqary3_t *cpqary3p, uint32_t *cleanstatus) /* LOCKUP CODE */ retvalue = ddi_regs_map_setup(cpqary3p->dip, mem_bar0, /* INDEX_PCI_BASE0, */ - (caddr_t *)&cpqary3p->spr0, (offset_t)I2O_CTLR_INIT, map_len, + (caddr_t *)&cpqary3p->spr0, (offset_t)I2O_SCRATCHPAD, map_len, &cpqary3_dev_attributes, &cpqary3p->spr0_handle); if (retvalue != DDI_SUCCESS) { diff --git a/usr/src/uts/common/io/cpqary3/cpqary3.h b/usr/src/uts/common/io/cpqary3/cpqary3.h index 0c56d3b356..f7c229eb69 100644 --- a/usr/src/uts/common/io/cpqary3/cpqary3.h +++ b/usr/src/uts/common/io/cpqary3/cpqary3.h @@ -467,7 +467,7 @@ int32_t cpqary3_ioctl_bmic_pass(uintptr_t, cpqary3_t *, int); int32_t cpqary3_ioctl_scsi_pass(uintptr_t, cpqary3_t *, int); uint8_t cpqary3_probe4targets(cpqary3_t *); void cpqary3_cmdlist_release(cpqary3_cmdpvt_t *, uint8_t); -int32_t cpqary3_submit(cpqary3_t *, uint32_t); +int cpqary3_submit(cpqary3_t *, uint32_t); void cpqary3_free_phyctgs_mem(cpqary3_phyctg_t *, uint8_t); caddr_t cpqary3_alloc_phyctgs_mem(cpqary3_t *, size_t, uint32_t *, cpqary3_phyctg_t *); diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_ciss.h b/usr/src/uts/common/io/cpqary3/cpqary3_ciss.h index 88b772391c..46f6c5e006 100644 --- a/usr/src/uts/common/io/cpqary3/cpqary3_ciss.h +++ b/usr/src/uts/common/io/cpqary3/cpqary3_ciss.h @@ -68,33 +68,56 @@ extern "C" { #define CFG_MEM1BAR 0x14 /* I2O Space Register Offsets */ -#define I2O_IBDB_SET 0x20 -#define I2O_IBDB_CLEAR 0x70 +#define I2O_INBOUND_DOORBELL 0x20 #define I2O_INT_STATUS 0x30 #define I2O_INT_MASK 0x34 #define I2O_IBPOST_Q 0x40 #define I2O_OBPOST_Q 0x44 #define I2O_OBDB_STATUS 0x9C #define I2O_OBDB_CLEAR 0xA0 -#define I2O_CTLR_INIT 0xB0 /* not available in CISS specs */ +#define I2O_SCRATCHPAD 0xB0 -/* Configuration Table */ -#define CFGTBL_CHANGE_REQ 0x00000001l -#define CFGTBL_ACC_CMDS 0x00000001l +/* + * The Scratchpad Register (I2O_SCRATCHPAD) is not mentioned in the CISS + * specification. It serves at least two known functions: + * - Signalling controller readiness + * - Exposing a debugging code when the controller firmware locks up + */ +#define CISS_SCRATCHPAD_INITIALISED 0xffff0000 -/* Transport Method */ -#define CFGTBL_XPORT_SIMPLE 0x00000002l -#define CFGTBL_XPORT_PERFORMANT 0x00000004l -#define CFGTBL_XPORT_MEMQ 0x00000008l +/* + * Outbound Doorbell Register Values. + * + * These are read from the Outbound Doorbell Set/Status Register + * (I2O_OBDB_STATUS), but cleared by writing to the Clear + * Register (I2O_OBDB_CLEAR). + */ +#define CISS_ODR_BIT_INTERRUPT (1UL << 0) +#define CISS_ODR_BIT_LOCKUP (1UL << 1) -#define CPQARY3_SIMPLE CFGTBL_XPORT_SIMPLE -#define CPQARY3_PERFORMANT CFGTBL_XPORT_PERFORMANT +/* + * Inbound Doorbell Register Values. + * + * These are written to and read from the Inbound Doorbell Register + * (I2O_INBOUND_DOORBELL). + */ +#define CISS_IDR_BIT_CFGTBL_CHANGE (1UL << 0) -/* not being used currently */ -#define CFGTBL_BusType_Ultra2 0x00000001l -#define CFGTBL_BusType_Ultra3 0x00000002l -#define CFGTBL_BusType_Fibre1G 0x00000100l -#define CFGTBL_BusType_Fibre2G 0x00000200l +/* + * Transport Methods. + * + * These bit positions are used in the Configuration Table to detect controller + * support for a particular method, via "TransportSupport"; to request that the + * controller enable a particular method, via "HostWrite.TransportRequest"; and + * to detect whether the controller has acknowledged the request and enabled + * the desired method, via "TransportActive". + * + * See: "9.1 Configuration Table" in the CISS Specification. + */ +#define CISS_CFGTBL_READY_FOR_COMMANDS (1UL << 0) +#define CISS_CFGTBL_XPORT_SIMPLE (1UL << 1) +#define CISS_CFGTBL_XPORT_PERFORMANT (1UL << 2) +#define CISS_CFGTBL_XPORT_MEMQ (1UL << 4) /* for hard reset of the controller */ #define CISS_POWER_OFF 0x03 /* Self Defined */ diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_isr.c b/usr/src/uts/common/io/cpqary3/cpqary3_isr.c index 5a8b3f46f4..d62e93159d 100644 --- a/usr/src/uts/common/io/cpqary3/cpqary3_isr.c +++ b/usr/src/uts/common/io/cpqary3/cpqary3_isr.c @@ -33,18 +33,29 @@ uint_t cpqary3_hw_isr(caddr_t per_ctlr) { - uint8_t need_swintr; - cpqary3_t *cpqary3p; + boolean_t need_swintr; + cpqary3_t *cpqary3p = (cpqary3_t *)per_ctlr; cpqary3_drvr_replyq_t *replyq_ptr; - volatile CfgTable_t *ctp; + volatile CfgTable_t *ctp = cpqary3p->ct; uint32_t spr0; uint32_t doorbell_status; uint32_t tag; - cpqary3p = (void *)per_ctlr; - ctp = (CfgTable_t *)cpqary3p->ct; replyq_ptr = (cpqary3_drvr_replyq_t *)cpqary3p->drvr_replyq; + + /* + * Check the Interrupt Status Register to see if the Outbound + * Post List FIFO is not empty. + */ + if (cpqary3p->check_ctlr_intr(cpqary3p) != CPQARY3_SUCCESS) { + /* + * The Outbound Post List FIFO is not empty, so we must + * service this interrupt. + */ + goto service; + } + if (CPQARY3_FAILURE == cpqary3p->check_ctlr_intr(cpqary3p)) { if (cpqary3p->heartbeat == DDI_GET32(cpqary3p, &ctp->HeartBeat)) { @@ -73,6 +84,8 @@ cpqary3_hw_isr(caddr_t per_ctlr) return (DDI_INTR_UNCLAIMED); } +service: + /* PERF */ /* @@ -133,16 +146,17 @@ cpqary3_hw_isr(caddr_t per_ctlr) mutex_enter(&cpqary3p->hw_mutex); if (cpqary3p->swintr_flag == CPQARY3_TRUE) { - need_swintr = CPQARY3_FALSE; + need_swintr = B_FALSE; } else { - need_swintr = CPQARY3_TRUE; + need_swintr = B_TRUE; cpqary3p->swintr_flag = CPQARY3_TRUE; } mutex_exit(&cpqary3p->hw_mutex); - if (CPQARY3_TRUE == need_swintr) + if (need_swintr) { ddi_trigger_softintr(cpqary3p->cpqary3_softintr_id); + } return (DDI_INTR_CLAIMED); } diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_talk2ctlr.c b/usr/src/uts/common/io/cpqary3/cpqary3_talk2ctlr.c index f0cca1d38b..2382ac22c5 100644 --- a/usr/src/uts/common/io/cpqary3/cpqary3_talk2ctlr.c +++ b/usr/src/uts/common/io/cpqary3/cpqary3_talk2ctlr.c @@ -11,6 +11,7 @@ /* * Copyright (C) 2013 Hewlett-Packard Development Company, L.P. + * Copyright 2016 Joyent, Inc. */ /* @@ -284,53 +285,32 @@ cpqary3_poll_retrieve(cpqary3_t *cpqary3p, uint32_t poll_tag) * Calls : None * Return Values: None */ -int32_t +int cpqary3_submit(cpqary3_t *cpqary3p, uint32_t cmd_phyaddr) { - uint32_t phys_addr = 0; - uint8_t retval = 0; + ASSERT(cpqary3p != NULL); + ASSERT(MUTEX_HELD(&cpqary3p->hw_mutex)); /* - * Write the Physical Address of the command-to-be-submitted - * into the Controller's Inbound Post Q. + * If a controller lockup has been detected, reject new command + * submissions. */ - - ASSERT(cpqary3p != NULL); - -#ifdef AMD64_DEBUG - { - char debug_char; - uint32_t tmp_cmd_phyaddr; - - tmp_cmd_phyaddr = (uint32_t)(cmd_phyaddr & 0XFFFFFFFF); - - cmn_err(CE_WARN, "CPQary3: cmd_phyaddr = %lX\n tmp_cmd_phyaddr = %lX", - cmd_phyaddr, tmp_cmd_phyaddr); - - debug_enter(&debug_char); - ddi_put32(cpqary3p->ipq_handle, (uint32_t *)cpqary3p->ipq, cmd_phyaddr); - } -#endif - - - /* CONTROLLER_LOCKUP */ if (cpqary3p->controller_lockup == CPQARY3_TRUE) { - retval = EIO; - return (retval); + return (EIO); } - /* CONTROLLER_LOCKUP */ + /* + * Write the Physical Address of the command-to-be-submitted + * into the Controller's Inbound Post Q. + */ if (!(cpqary3p->bddef->bd_flags & SA_BD_SAS)) { - ddi_put32(cpqary3p->ipq_handle, - (uint32_t *)cpqary3p->ipq, cmd_phyaddr); + ddi_put32(cpqary3p->ipq_handle, cpqary3p->ipq, cmd_phyaddr); } else { /* The driver always uses the 0th block fetch count always */ - phys_addr = cmd_phyaddr | 0 | 0x1; - ddi_put32(cpqary3p->ipq_handle, - (uint32_t *)cpqary3p->ipq, phys_addr); - } + uint32_t phys_addr = cmd_phyaddr | 0 | 0x1; - /* PERF */ + ddi_put32(cpqary3p->ipq_handle, cpqary3p->ipq, phys_addr); + } /* * Command submission can NEVER FAIL since the number of commands that @@ -338,11 +318,7 @@ cpqary3_submit(cpqary3_t *cpqary3p, uint32_t cmd_phyaddr) * allocation is for 225 commands ONLY. Thus, at any given time the * maximum number of commands in the controller is 225. */ - - /* CONTROLLER_LOCKUP */ - return (retval); - /* CONTROLLER_LOCKUP */ - + return (0); } @@ -358,29 +334,24 @@ cpqary3_submit(cpqary3_t *cpqary3p, uint32_t cmd_phyaddr) void cpqary3_intr_onoff(cpqary3_t *cpqary3p, uint8_t flag) { - uint32_t intr = 0; - uint32_t intr_mask = 0; - /* - * Enable or disable the interrupt based on the flag - * Read the Interrupt Mask Register first and then update it - * accordingly + * Read the Interrupt Mask Register. */ + uint32_t imr = ddi_get32(cpqary3p->imr_handle, cpqary3p->imr); - ASSERT(cpqary3p != NULL); - - intr = ddi_get32(cpqary3p->imr_handle, (uint32_t *)cpqary3p->imr); - intr_mask = cpqary3p->bddef->bd_intrmask; - + /* + * Enable or disable interrupts from the controller based on the flag. + */ if (flag == CPQARY3_INTR_ENABLE) { - ddi_put32(cpqary3p->imr_handle, - (uint32_t *)cpqary3p->imr, intr & ~(intr_mask)); + imr &= ~cpqary3p->bddef->bd_intrmask; } else { - ddi_put32(cpqary3p->imr_handle, - (uint32_t *)cpqary3p->imr, (intr | intr_mask)); + VERIFY(flag == CPQARY3_INTR_DISABLE); + + imr |= cpqary3p->bddef->bd_intrmask; } -} + ddi_put32(cpqary3p->imr_handle, cpqary3p->imr, imr); +} /* * Function : cpqary3_lockup_intr_onoff @@ -395,27 +366,139 @@ cpqary3_intr_onoff(cpqary3_t *cpqary3p, uint8_t flag) void cpqary3_lockup_intr_onoff(cpqary3_t *cpqary3p, uint8_t flag) { - uint32_t intr = 0; - uint32_t intr_lockup_mask = 0; + /* + * Read the Interrupt Mask Register. + */ + uint32_t imr = ddi_get32(cpqary3p->imr_handle, cpqary3p->imr); /* - * Enable or disable the interrupt based on the flag - * Read the Interrupt Mask Register first and then update it - * accordingly + * Enable or disable firmware lockup interrupts from the controller + * based on the flag. */ + if (flag == CPQARY3_LOCKUP_INTR_ENABLE) { + imr &= ~cpqary3p->bddef->bd_lockup_intrmask; + } else { + VERIFY(flag == CPQARY3_LOCKUP_INTR_DISABLE); - ASSERT(cpqary3p != NULL); + imr |= cpqary3p->bddef->bd_lockup_intrmask; + } - intr = ddi_get32(cpqary3p->imr_handle, (uint32_t *)cpqary3p->imr); - intr_lockup_mask = cpqary3p->bddef->bd_lockup_intrmask; + ddi_put32(cpqary3p->imr_handle, cpqary3p->imr, imr); +} - if (flag == CPQARY3_INTR_ENABLE) { - ddi_put32(cpqary3p->imr_handle, - (uint32_t *)cpqary3p->imr, intr & ~(intr_lockup_mask)); - } else { - ddi_put32(cpqary3p->imr_handle, - (uint32_t *)cpqary3p->imr, (intr | intr_lockup_mask)); +/* + * Signal to the controller that we have updated the Configuration Table by + * writing to the Inbound Doorbell Register. The controller will, after some + * number of seconds, acknowledge this by clearing the bit. + * + * If successful, return CPQARY3_SUCCESS. If the controller takes too long to + * acknowledge, return CPQARY3_FAILURE. + */ +static int +cpqary3_cfgtbl_flush(cpqary3_t *cpqary3p) +{ + /* + * Read the current value of the Inbound Doorbell Register. + */ + uint32_t idr = ddi_get32(cpqary3p->idr_handle, cpqary3p->idr); + + /* + * Signal the Configuration Table change to the controller. + */ + idr |= CISS_IDR_BIT_CFGTBL_CHANGE; + ddi_put32(cpqary3p->idr_handle, cpqary3p->idr, idr); + + /* + * Wait for the controller to acknowledge the change. + */ + for (unsigned i = 0; i < CISS_INIT_TIME; i++) { + idr = ddi_get32(cpqary3p->idr_handle, cpqary3p->idr); + + if ((idr & CISS_IDR_BIT_CFGTBL_CHANGE) == 0) { + return (CPQARY3_SUCCESS); + } + + /* + * Wait for one second before trying again. + */ + delay(drv_usectohz(1000000)); + } + + dev_err(cpqary3p->dip, CE_WARN, "time out expired before controller " + "configuration completed"); + return (CPQARY3_FAILURE); +} + +static int +cpqary3_cfgtbl_transport_has_support(cpqary3_t *cpqary3p, int xport) +{ + VERIFY(xport == CISS_CFGTBL_XPORT_SIMPLE || + xport == CISS_CFGTBL_XPORT_PERFORMANT); + + /* + * Read the current value of the TransportSupport field in the + * Configuration Table. + */ + uint32_t xport_active = ddi_get32(cpqary3p->ct_handle, + &cpqary3p->ct->TransportSupport); + + /* + * Check that the desired transport method is supported by the + * controller: + */ + if ((xport_active & xport) == 0) { + dev_err(cpqary3p->dip, CE_WARN, "controller does not support " + "method \"%s\"", xport == CISS_CFGTBL_XPORT_SIMPLE ? + "simple" : "performant"); + return (CPQARY3_FAILURE); } + + return (CPQARY3_SUCCESS); +} + +static void +cpqary3_cfgtbl_transport_set(cpqary3_t *cpqary3p, int xport) +{ + VERIFY(xport == CISS_CFGTBL_XPORT_SIMPLE || + xport == CISS_CFGTBL_XPORT_PERFORMANT); + + ddi_put32(cpqary3p->ct_handle, + &cpqary3p->ct->HostWrite.TransportRequest, xport); +} + +static int +cpqary3_cfgtbl_transport_confirm(cpqary3_t *cpqary3p, int xport) +{ + VERIFY(xport == CISS_CFGTBL_XPORT_SIMPLE || + xport == CISS_CFGTBL_XPORT_PERFORMANT); + + /* + * Read the current value of the TransportActive field in the + * Configuration Table. + */ + uint32_t xport_active = ddi_get32(cpqary3p->ct_handle, + &cpqary3p->ct->TransportActive); + + /* + * Check that the desired transport method is now active: + */ + if ((xport_active & xport) == 0) { + dev_err(cpqary3p->dip, CE_WARN, "failed to enable transport " + "method \"%s\"", xport == CISS_CFGTBL_XPORT_SIMPLE ? + "simple" : "performant"); + return (CPQARY3_FAILURE); + } + + /* + * Ensure that the controller is now ready to accept commands. + */ + if ((xport_active & CISS_CFGTBL_READY_FOR_COMMANDS) == 0) { + dev_err(cpqary3p->dip, CE_WARN, "controller not ready to " + "accept commands"); + return (CPQARY3_FAILURE); + } + + return (CPQARY3_SUCCESS); } /* @@ -433,9 +516,8 @@ cpqary3_lockup_intr_onoff(cpqary3_t *cpqary3p, uint8_t flag) uint8_t cpqary3_init_ctlr(cpqary3_t *cpqary3p) { - uint8_t cntr; uint8_t signature[4] = { 'C', 'I', 'S', 'S' }; - volatile CfgTable_t *ctp; + CfgTable_t *ctp; volatile CfgTrans_Perf_t *perf_cfg; cpqary3_phyctg_t *cpqary3_phyctgp; uint32_t phy_addr; @@ -469,22 +551,19 @@ cpqary3_init_ctlr(cpqary3_t *cpqary3p) DTRACE_PROBE1(ctlr_init_start, CfgTable_t *, ctp); /* - * Validate the signature - should be "CISS" - * Use of cntr in the for loop does not suggest a counter - it just - * saves declaration of another variable. + * The configuration table contains an ASCII signature ("CISS") which + * should be checked as we initialise the controller. + * See: "9.1 Configuration Table" in CISS Specification. */ - - for (cntr = 0; cntr < 4; cntr++) { - if (DDI_GET8(cpqary3p, &ctp->Signature[cntr]) != - signature[cntr]) { - cmn_err(CE_WARN, "CPQary3 : Controller NOT ready"); - cmn_err(CE_WARN, "CPQary3 : _cpqary3_init_ctlr : " - "Signature not stamped"); + for (unsigned i = 0; i < 4; i++) { + if (ddi_get8(cpqary3p->ct_handle, &ctp->Signature[i]) != + signature[i]) { + dev_err(cpqary3p->dip, CE_WARN, "invalid signature " + "detected"); return (CPQARY3_FAILURE); } } - if (!(cpqary3p->bddef->bd_flags & SA_BD_SAS)) { CmdsOutMax = DDI_GET32(cpqary3p, &ctp->CmdsOutMax); @@ -520,91 +599,30 @@ cpqary3_init_ctlr(cpqary3_t *cpqary3p) /* PERF */ - /* - * Check for support of SIMPLE Transport Method - */ - if (!(DDI_GET32(cpqary3p, &ctp->TransportSupport) & - CFGTBL_XPORT_SIMPLE)) { - cmn_err(CE_WARN, "CPQary3 : Controller " - "NOT YET INITIALIZED"); - cmn_err(CE_CONT, "CPQary3 : For Hot Plug Operations, " - "try again later \n"); + if (cpqary3_cfgtbl_transport_has_support(cpqary3p, + CISS_CFGTBL_XPORT_SIMPLE) != CPQARY3_SUCCESS) { return (CPQARY3_FAILURE); } /* - * Configuration Table Initialization - * Set bit 0 of InBound Door Bell Reg to inform the controller - * about the changes related to the Configuration table + * Set the Transport Method and flush the changes to the + * Configuration Table. */ - DTRACE_PROBE(cfgtable_init_start); - - DDI_PUT32(cpqary3p, &ctp->HostWrite.TransportRequest, - CFGTBL_XPORT_SIMPLE); - ddi_put32(cpqary3p->idr_handle, (uint32_t *)cpqary3p->idr, - ddi_get32(cpqary3p->idr_handle, (uint32_t *)cpqary3p->idr) | - CFGTBL_CHANGE_REQ); - - /* - * Check whether the controller is ready - */ - - cntr = 0; - while (ddi_get32(cpqary3p->idr_handle, - (uint32_t *)cpqary3p->idr) & CFGTBL_ACC_CMDS) { - drv_usecwait(1000000); /* Wait for 1 Sec. */ - cntr++; - - /* - * Wait for a maximum of 90 seconds. No f/w should take - * more than 90 secs to initialize. If the controller - * is not ready even after 90 secs, it suggests that - * something is wrong - * (wrt the controller, what else) !!! - */ - - if (cntr > CISS_INIT_TIME) /* 1.30 Mins */ { - cmn_err(CE_CONT, "CPQary3 : Controller " - "Initialization Failed \n"); - return (CPQARY3_FAILURE); - } - } - - DTRACE_PROBE(cfgtable_init_done); - - /* - * Check whether controller accepts the requested method of - * transport - */ - if (!(DDI_GET32(cpqary3p, &ctp->TransportActive) & - CFGTBL_XPORT_SIMPLE)) { - cmn_err(CE_CONT, "CPQary3 : Failed to Initialize " - "Controller \n"); - cmn_err(CE_CONT, "CPQary3 : For Hot Plug Operations, " - "try again later\n"); + cpqary3_cfgtbl_transport_set(cpqary3p, + CISS_CFGTBL_XPORT_SIMPLE); + if (cpqary3_cfgtbl_flush(cpqary3p) != CPQARY3_SUCCESS) { return (CPQARY3_FAILURE); } - DTRACE_PROBE(ctlr_init_simple); - - /* - * Check if Controller is ready to accept Commands - */ - - if (!(DDI_GET32(cpqary3p, &ctp->TransportActive) & - CFGTBL_ACC_CMDS)) { - cmn_err(CE_CONT, "CPQary3: Controller NOT ready to " - "accept Commands \n"); + if (cpqary3_cfgtbl_transport_confirm(cpqary3p, + CISS_CFGTBL_XPORT_SIMPLE) != CPQARY3_SUCCESS) { return (CPQARY3_FAILURE); } - DTRACE_PROBE(ctlr_init_ready); - /* * Check if the maximum number of oustanding commands for the * initialized controller is something greater than Zero. */ - CmdsOutMax = DDI_GET32(cpqary3p, &ctp->CmdsOutMax); if (CmdsOutMax == 0) { @@ -619,7 +637,6 @@ cpqary3_init_ctlr(cpqary3_t *cpqary3p) /* * Zero the Upper 32 Address in the Controller */ - DDI_PUT32(cpqary3p, &ctp->HostWrite.Upper32Addr, 0x00000000); cpqary3p->heartbeat = DDI_GET32(cpqary3p, &ctp->HeartBeat); @@ -632,20 +649,11 @@ cpqary3_init_ctlr(cpqary3_t *cpqary3p) (cpqary3p->host_support | 0x4)); cpqary3p->host_support = DDI_GET32(cpqary3p, &ctp->HostDrvrSupport); - - cpqary3p->lockup_logged = CPQARY3_FALSE; } else { /* PERF */ - /* - * Check for support of PERF Transport Method - */ - if (!(DDI_GET32(cpqary3p, &ctp->TransportSupport) - & CFGTBL_XPORT_PERFORMANT)) { - cmn_err(CE_WARN, "CPQary3 : Controller " - "NOT YET INITIALIZED"); - cmn_err(CE_CONT, "CPQary3 : For Hot Plug Operations, " - "try again later \n"); + if (cpqary3_cfgtbl_transport_has_support(cpqary3p, + CISS_CFGTBL_XPORT_PERFORMANT) != CPQARY3_SUCCESS) { return (CPQARY3_FAILURE); } @@ -731,63 +739,19 @@ cpqary3_init_ctlr(cpqary3_t *cpqary3p) DDI_PUT32_CP(cpqary3p, &perf_cfg->BlockFetchCnt[0], BlockFetchCnt[0]); - DDI_PUT32(cpqary3p, &ctp->HostWrite.TransportRequest, - CFGTBL_XPORT_PERFORMANT); - ddi_put32(cpqary3p->idr_handle, (uint32_t *)cpqary3p->idr, - ddi_get32(cpqary3p->idr_handle, (uint32_t *)cpqary3p->idr) | - CFGTBL_CHANGE_REQ); - - /* - * Check whether the controller is ready - */ - - cntr = 0; - while (ddi_get32(cpqary3p->idr_handle, - (uint32_t *)cpqary3p->idr) & CFGTBL_ACC_CMDS) { - drv_usecwait(1000000); /* Wait for 1 Sec. */ - cntr++; - - - /* - * Wait for a maximum of 90 seconds. No f/w should take - * more than 90 secs to initialize. If the controller - * is not ready even after 90 secs, it suggests that - * something is wrong - * (wrt the controller, what else) !!! - */ - - if (cntr > CISS_INIT_TIME) /* 1.30 Mins */ { - cmn_err(CE_CONT, "CPQary3 : Controller " - "Initialization Failed \n"); - return (CPQARY3_FAILURE); - } - } /* - * Check whether controller accepts the requested method of - * transport + * Set the Transport Method and flush the changes to the + * Configuration Table. */ - - if (!(DDI_GET32(cpqary3p, &ctp->TransportActive) & - CFGTBL_XPORT_PERFORMANT)) { - cmn_err(CE_NOTE, "CPQary3 : Failed to Initialize " - "Controller"); - cmn_err(CE_CONT, "CPQary3 : For Hot Plug Operations, " - "try again later\n"); - DTRACE_PROBE1(ctlr_init_perf_fail, CfgTable_t *, ctp); + cpqary3_cfgtbl_transport_set(cpqary3p, + CISS_CFGTBL_XPORT_PERFORMANT); + if (cpqary3_cfgtbl_flush(cpqary3p) != CPQARY3_SUCCESS) { return (CPQARY3_FAILURE); } - DTRACE_PROBE(ctlr_init_simple); - - /* - * Check if Controller is ready to accept Commands - */ - - if (!(DDI_GET32(cpqary3p, &ctp->TransportActive) & - CFGTBL_ACC_CMDS)) { - cmn_err(CE_NOTE, "CPQary3: Controller NOT ready to " - "accept Commands"); + if (cpqary3_cfgtbl_transport_confirm(cpqary3p, + CISS_CFGTBL_XPORT_PERFORMANT) != CPQARY3_SUCCESS) { return (CPQARY3_FAILURE); } @@ -795,7 +759,6 @@ cpqary3_init_ctlr(cpqary3_t *cpqary3p) * Check if the maximum number of oustanding commands for the * initialized controller is something greater than Zero. */ - CmdsOutMax = DDI_GET32(cpqary3p, &ctp->MaxPerfModeCmdsOutMax); if (CmdsOutMax == 0) CmdsOutMax = DDI_GET32(cpqary3p, &ctp->CmdsOutMax); @@ -873,7 +836,6 @@ cpqary3_init_ctlr(cpqary3_t *cpqary3p) } cpqary3p->host_support = DDI_GET32(cpqary3p, &ctp->HostDrvrSupport); - cpqary3p->lockup_logged = CPQARY3_FALSE; } return (CPQARY3_SUCCESS); @@ -890,53 +852,25 @@ cpqary3_init_ctlr(cpqary3_t *cpqary3p) uint8_t cpqary3_check_ctlr_init(cpqary3_t *cpqary3p) { - int8_t retvalue; - uint16_t i; - uint32_t *ctlr_init; - ddi_acc_handle_t ctlr_init_handle; - extern ddi_device_acc_attr_t cpqary3_dev_attributes; - - RETURN_FAILURE_IF_NULL(cpqary3p); - /* - * Set up the mapping for a Register at offset 0xB0 from I2O Bar - * The value 0xB0 taken from the CONFIGM utility. - * It should read 0xffff0000 if the controller is initialized. - * if not yet initialized, read it every second for 300 secs. - * If not set even after 300 secs, return FAILURE. - * If set, free the mapping and continue + * Read from the Scratchpad Register until the expected ready + * signature is detected. This behaviour is not described in + * the CISS specification. + * + * If the device is not ready immediate, sleep for a second and + * try again. If the device has not become ready in 300 seconds, + * give up. */ - retvalue = ddi_regs_map_setup(cpqary3p->dip, INDEX_PCI_BASE0, - (caddr_t *)&ctlr_init, (offset_t)I2O_CTLR_INIT, 4, - &cpqary3_dev_attributes, &ctlr_init_handle); + for (unsigned i = 0; i < 300; i++) { + uint32_t spr = ddi_get32(cpqary3p->spr0_handle, + cpqary3p->spr0); - if (retvalue != DDI_SUCCESS) { - if (DDI_REGS_ACC_CONFLICT == retvalue) - cmn_err(CE_WARN, - "CPQary3 : HBA Init Register Mapping Conflict"); - cmn_err(CE_WARN, - "CPQary3 : HBA Init Regsiter Mapping Failed"); - return (CPQARY3_FAILURE); - } - - for (i = 0; i < 300; i++) { /* loop for 300 seconds */ - if (CISS_CTLR_INIT == ddi_get32(ctlr_init_handle, ctlr_init)) { - DTRACE_PROBE(ctlr_init_check_ready); - ddi_regs_map_free(&ctlr_init_handle); - break; - } else { - DTRACE_PROBE(ctlr_init_check_notready); - delay(drv_usectohz(1000000)); + if (spr == CISS_SCRATCHPAD_INITIALISED) { + return (CPQARY3_SUCCESS); } } - if (i >= 300) { /* HBA not initialized even after 300 seconds !!! */ - ddi_regs_map_free(&ctlr_init_handle); - cmn_err(CE_WARN, "CPQary3 : %s NOT initialized !!! HBA may not " - "function properly. Please replace the hardware or check " - "the connections", cpqary3p->hba_name); - return (CPQARY3_FAILURE); - } - - return (CPQARY3_SUCCESS); + dev_err(cpqary3p->dip, CE_WARN, "time out waiting for controller " + "to become ready"); + return (CPQARY3_FAILURE); } diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_transport.c b/usr/src/uts/common/io/cpqary3/cpqary3_transport.c index 1880bba69b..939a5dfa31 100644 --- a/usr/src/uts/common/io/cpqary3/cpqary3_transport.c +++ b/usr/src/uts/common/io/cpqary3/cpqary3_transport.c @@ -628,31 +628,25 @@ cpqary3_transport(struct scsi_address *sa, struct scsi_pkt *scsi_pktp) memp->complete = cpqary3_oscmd_complete; /* PERF */ - switch (cpqary3_build_cmdlist(memp, SA2TGT(sa))) { - case CPQARY3_SUCCESS : + if (cpqary3_build_cmdlist(memp, SA2TGT(sa)) == CPQARY3_SUCCESS) { if (scsi_pktp->pkt_flags & FLAG_NOINTR) { return (cpqary3_handle_flag_nointr(memp, scsi_pktp)); } cpqary3_pktp->cmd_start_time = ddi_get_lbolt(); + mutex_enter(&ctlr->hw_mutex); - /* CONTROLLER_LOCKUP */ - if (EIO == cpqary3_submit(ctlr, memp->cmdlist_phyaddr)) { + if (cpqary3_submit(ctlr, memp->cmdlist_phyaddr) != 0) { mutex_exit(&ctlr->hw_mutex); cpqary3_cmdlist_release(memp, CPQARY3_HOLD_SW_MUTEX); return (TRAN_FATAL_ERROR); } - /* CONTROLLER_LOCKUP */ mutex_exit(&ctlr->hw_mutex); - break; - case CPQARY3_FAILURE : - cpqary3_cmdlist_release(memp, CPQARY3_HOLD_SW_MUTEX); - return (TRAN_FATAL_ERROR); - default: /* Never occurs */ - cmn_err(CE_NOTE, "CPQary3 : Transport : Unexpected Error"); - return (TRAN_FATAL_ERROR); + + return (TRAN_ACCEPT); } - return (TRAN_ACCEPT); + cpqary3_cmdlist_release(memp, CPQARY3_HOLD_SW_MUTEX); + return (TRAN_FATAL_ERROR); } /* diff --git a/usr/src/uts/common/io/cpqary3/cpqary3_util.c b/usr/src/uts/common/io/cpqary3/cpqary3_util.c index 5ba61be8d4..b4a017d5ce 100644 --- a/usr/src/uts/common/io/cpqary3/cpqary3_util.c +++ b/usr/src/uts/common/io/cpqary3/cpqary3_util.c @@ -83,6 +83,11 @@ cpqary3_read_conf_file(dev_info_t *dip, cpqary3_t *cpqary3p) } } +void +cpqary3_lockup_check(cpqary3_t *cpq) +{ +} + /* * Function : cpqary3_tick_hdlr * Description : This routine is called once in 60 seconds to detect any |