1*80c94ecdSKeith M Wesolowski /* 2*80c94ecdSKeith M Wesolowski * This file and its contents are supplied under the terms of the 3*80c94ecdSKeith M Wesolowski * Common Development and Distribution License ("CDDL"), version 1.0. 4*80c94ecdSKeith M Wesolowski * You may only use this file in accordance with the terms of version 5*80c94ecdSKeith M Wesolowski * 1.0 of the CDDL. 6*80c94ecdSKeith M Wesolowski * 7*80c94ecdSKeith M Wesolowski * A full copy of the text of the CDDL should have accompanied this 8*80c94ecdSKeith M Wesolowski * source. A copy of the CDDL is also available via the Internet at 9*80c94ecdSKeith M Wesolowski * http://www.illumos.org/license/CDDL. 10*80c94ecdSKeith M Wesolowski */ 11*80c94ecdSKeith M Wesolowski 12*80c94ecdSKeith M Wesolowski /* 13*80c94ecdSKeith M Wesolowski * Copyright (C) 2013 Hewlett-Packard Development Company, L.P. 14*80c94ecdSKeith M Wesolowski */ 15*80c94ecdSKeith M Wesolowski 16*80c94ecdSKeith M Wesolowski #include "cpqary3.h" 17*80c94ecdSKeith M Wesolowski 18*80c94ecdSKeith M Wesolowski /* 19*80c94ecdSKeith M Wesolowski * Function : cpqary3_hw_isr 20*80c94ecdSKeith M Wesolowski * Description : This routine determines if this instance of the 21*80c94ecdSKeith M Wesolowski * HBA interrupted and if positive triggers a software 22*80c94ecdSKeith M Wesolowski * interrupt. 23*80c94ecdSKeith M Wesolowski * For SAS controllers which operate in performant mode 24*80c94ecdSKeith M Wesolowski * we clear the interrupt. 25*80c94ecdSKeith M Wesolowski * For CISS controllers which operate in simple mode 26*80c94ecdSKeith M Wesolowski * we get the tag value. 27*80c94ecdSKeith M Wesolowski * Called By : kernel 28*80c94ecdSKeith M Wesolowski * Parameters : per-controller 29*80c94ecdSKeith M Wesolowski * Calls : cpqary3_check_ctlr_intr() 30*80c94ecdSKeith M Wesolowski * Return Values: DDI_INTR_CLAIMED/UNCLAIMED 31*80c94ecdSKeith M Wesolowski * [We either CLAIM the interrupt or Discard it] 32*80c94ecdSKeith M Wesolowski */ 33*80c94ecdSKeith M Wesolowski uint_t 34*80c94ecdSKeith M Wesolowski cpqary3_hw_isr(caddr_t per_ctlr) 35*80c94ecdSKeith M Wesolowski { 36*80c94ecdSKeith M Wesolowski uint8_t need_swintr; 37*80c94ecdSKeith M Wesolowski cpqary3_t *cpqary3p; 38*80c94ecdSKeith M Wesolowski cpqary3_drvr_replyq_t *replyq_ptr; 39*80c94ecdSKeith M Wesolowski volatile CfgTable_t *ctp; 40*80c94ecdSKeith M Wesolowski uint32_t spr0; 41*80c94ecdSKeith M Wesolowski uint32_t doorbell_status; 42*80c94ecdSKeith M Wesolowski uint32_t tag; 43*80c94ecdSKeith M Wesolowski 44*80c94ecdSKeith M Wesolowski cpqary3p = (void *)per_ctlr; 45*80c94ecdSKeith M Wesolowski ctp = (CfgTable_t *)cpqary3p->ct; 46*80c94ecdSKeith M Wesolowski replyq_ptr = (cpqary3_drvr_replyq_t *)cpqary3p->drvr_replyq; 47*80c94ecdSKeith M Wesolowski 48*80c94ecdSKeith M Wesolowski if (CPQARY3_FAILURE == cpqary3p->check_ctlr_intr(cpqary3p)) { 49*80c94ecdSKeith M Wesolowski if (cpqary3p->heartbeat == 50*80c94ecdSKeith M Wesolowski DDI_GET32(cpqary3p, &ctp->HeartBeat)) { 51*80c94ecdSKeith M Wesolowski if (0x2 & ddi_get32(cpqary3p->odr_handle, 52*80c94ecdSKeith M Wesolowski (uint32_t *)cpqary3p->odr)) { 53*80c94ecdSKeith M Wesolowski spr0 = ddi_get32(cpqary3p->spr0_handle, 54*80c94ecdSKeith M Wesolowski (uint32_t *)cpqary3p->spr0); 55*80c94ecdSKeith M Wesolowski spr0 = spr0 >> 16; 56*80c94ecdSKeith M Wesolowski cmn_err(CE_WARN, "CPQary3 : %s HBA firmware " 57*80c94ecdSKeith M Wesolowski "Locked !!! Lockup Code: 0x%x", 58*80c94ecdSKeith M Wesolowski cpqary3p->hba_name, spr0); 59*80c94ecdSKeith M Wesolowski cmn_err(CE_WARN, "CPQary3 : Please reboot " 60*80c94ecdSKeith M Wesolowski "the system"); 61*80c94ecdSKeith M Wesolowski ddi_put32(cpqary3p->odr_cl_handle, 62*80c94ecdSKeith M Wesolowski (uint32_t *)cpqary3p->odr_cl, 0x2); 63*80c94ecdSKeith M Wesolowski cpqary3_intr_onoff(cpqary3p, 64*80c94ecdSKeith M Wesolowski CPQARY3_INTR_DISABLE); 65*80c94ecdSKeith M Wesolowski if (cpqary3p->host_support & 0x4) { 66*80c94ecdSKeith M Wesolowski cpqary3_lockup_intr_onoff(cpqary3p, 67*80c94ecdSKeith M Wesolowski CPQARY3_LOCKUP_INTR_DISABLE); 68*80c94ecdSKeith M Wesolowski } 69*80c94ecdSKeith M Wesolowski cpqary3p->controller_lockup = CPQARY3_TRUE; 70*80c94ecdSKeith M Wesolowski } 71*80c94ecdSKeith M Wesolowski return (DDI_INTR_CLAIMED); 72*80c94ecdSKeith M Wesolowski } 73*80c94ecdSKeith M Wesolowski return (DDI_INTR_UNCLAIMED); 74*80c94ecdSKeith M Wesolowski } 75*80c94ecdSKeith M Wesolowski 76*80c94ecdSKeith M Wesolowski /* PERF */ 77*80c94ecdSKeith M Wesolowski 78*80c94ecdSKeith M Wesolowski /* 79*80c94ecdSKeith M Wesolowski * We decided that we will have only one retrieve function for 80*80c94ecdSKeith M Wesolowski * both simple and performant mode. To achieve this we have to mimic 81*80c94ecdSKeith M Wesolowski * what controller does for performant mode in simple mode. 82*80c94ecdSKeith M Wesolowski * For simple mode we are making replq_simple_ptr and 83*80c94ecdSKeith M Wesolowski * replq_headptr of performant 84*80c94ecdSKeith M Wesolowski * mode point to the same location in the reply queue. 85*80c94ecdSKeith M Wesolowski * For the performant mode, we clear the interrupt 86*80c94ecdSKeith M Wesolowski */ 87*80c94ecdSKeith M Wesolowski 88*80c94ecdSKeith M Wesolowski if (!(cpqary3p->bddef->bd_flags & SA_BD_SAS)) { 89*80c94ecdSKeith M Wesolowski while ((tag = ddi_get32(cpqary3p->opq_handle, 90*80c94ecdSKeith M Wesolowski (uint32_t *)cpqary3p->opq)) != 0xFFFFFFFF) { 91*80c94ecdSKeith M Wesolowski replyq_ptr->replyq_simple_ptr[0] = tag; 92*80c94ecdSKeith M Wesolowski replyq_ptr->replyq_simple_ptr[0] |= 93*80c94ecdSKeith M Wesolowski replyq_ptr->simple_cyclic_indicator; 94*80c94ecdSKeith M Wesolowski ++replyq_ptr->simple_index; 95*80c94ecdSKeith M Wesolowski 96*80c94ecdSKeith M Wesolowski if (replyq_ptr->simple_index == replyq_ptr->max_index) { 97*80c94ecdSKeith M Wesolowski replyq_ptr->simple_index = 0; 98*80c94ecdSKeith M Wesolowski /* Toggle at wraparound */ 99*80c94ecdSKeith M Wesolowski replyq_ptr->simple_cyclic_indicator = 100*80c94ecdSKeith M Wesolowski (replyq_ptr->simple_cyclic_indicator == 0) ? 101*80c94ecdSKeith M Wesolowski 1 : 0; 102*80c94ecdSKeith M Wesolowski replyq_ptr->replyq_simple_ptr = 103*80c94ecdSKeith M Wesolowski /* LINTED: alignment */ 104*80c94ecdSKeith M Wesolowski (uint32_t *)(replyq_ptr->replyq_start_addr); 105*80c94ecdSKeith M Wesolowski } else { 106*80c94ecdSKeith M Wesolowski replyq_ptr->replyq_simple_ptr += 2; 107*80c94ecdSKeith M Wesolowski } 108*80c94ecdSKeith M Wesolowski } 109*80c94ecdSKeith M Wesolowski } else { 110*80c94ecdSKeith M Wesolowski doorbell_status = ddi_get32(cpqary3p->odr_handle, 111*80c94ecdSKeith M Wesolowski (uint32_t *)cpqary3p->odr); 112*80c94ecdSKeith M Wesolowski if (doorbell_status & 0x1) { 113*80c94ecdSKeith M Wesolowski ddi_put32(cpqary3p->odr_cl_handle, 114*80c94ecdSKeith M Wesolowski (uint32_t *)cpqary3p->odr_cl, 115*80c94ecdSKeith M Wesolowski (ddi_get32(cpqary3p->odr_cl_handle, 116*80c94ecdSKeith M Wesolowski (uint32_t *)cpqary3p->odr_cl) | 0x1)); 117*80c94ecdSKeith M Wesolowski doorbell_status = ddi_get32(cpqary3p->odr_handle, 118*80c94ecdSKeith M Wesolowski (uint32_t *)cpqary3p->odr); 119*80c94ecdSKeith M Wesolowski } 120*80c94ecdSKeith M Wesolowski } 121*80c94ecdSKeith M Wesolowski 122*80c94ecdSKeith M Wesolowski /* PERF */ 123*80c94ecdSKeith M Wesolowski 124*80c94ecdSKeith M Wesolowski /* 125*80c94ecdSKeith M Wesolowski * If s/w interrupt handler is already running, do not trigger another 126*80c94ecdSKeith M Wesolowski * since packets have already been transferred to Retrieved Q. 127*80c94ecdSKeith M Wesolowski * Else, Set swintr_flag to state to the s/w interrupt handler 128*80c94ecdSKeith M Wesolowski * that it has a job to do. 129*80c94ecdSKeith M Wesolowski * trigger the s/w interrupt handler 130*80c94ecdSKeith M Wesolowski * Claim the interrupt 131*80c94ecdSKeith M Wesolowski */ 132*80c94ecdSKeith M Wesolowski 133*80c94ecdSKeith M Wesolowski mutex_enter(&cpqary3p->hw_mutex); 134*80c94ecdSKeith M Wesolowski 135*80c94ecdSKeith M Wesolowski if (cpqary3p->swintr_flag == CPQARY3_TRUE) { 136*80c94ecdSKeith M Wesolowski need_swintr = CPQARY3_FALSE; 137*80c94ecdSKeith M Wesolowski } else { 138*80c94ecdSKeith M Wesolowski need_swintr = CPQARY3_TRUE; 139*80c94ecdSKeith M Wesolowski cpqary3p->swintr_flag = CPQARY3_TRUE; 140*80c94ecdSKeith M Wesolowski } 141*80c94ecdSKeith M Wesolowski 142*80c94ecdSKeith M Wesolowski mutex_exit(&cpqary3p->hw_mutex); 143*80c94ecdSKeith M Wesolowski 144*80c94ecdSKeith M Wesolowski if (CPQARY3_TRUE == need_swintr) 145*80c94ecdSKeith M Wesolowski ddi_trigger_softintr(cpqary3p->cpqary3_softintr_id); 146*80c94ecdSKeith M Wesolowski 147*80c94ecdSKeith M Wesolowski return (DDI_INTR_CLAIMED); 148*80c94ecdSKeith M Wesolowski } 149*80c94ecdSKeith M Wesolowski 150*80c94ecdSKeith M Wesolowski /* 151*80c94ecdSKeith M Wesolowski * Function : cpqary3_sw_isr 152*80c94ecdSKeith M Wesolowski * Description : This routine determines if this instance of the 153*80c94ecdSKeith M Wesolowski * software interrupt handler was triggered by its 154*80c94ecdSKeith M Wesolowski * respective h/w interrupt handler and if affermative 155*80c94ecdSKeith M Wesolowski * processes the completed commands. 156*80c94ecdSKeith M Wesolowski * Called By : kernel (Triggered by : cpqary3_hw_isr) 157*80c94ecdSKeith M Wesolowski * Parameters : per-controller 158*80c94ecdSKeith M Wesolowski * Calls : cpqary3_retrieve() 159*80c94ecdSKeith M Wesolowski * Return Values: DDI_INTR_CLAIMED/UNCLAIMED 160*80c94ecdSKeith M Wesolowski * [We either CLAIM the interrupr or DON'T] 161*80c94ecdSKeith M Wesolowski */ 162*80c94ecdSKeith M Wesolowski uint_t 163*80c94ecdSKeith M Wesolowski cpqary3_sw_isr(caddr_t per_ctlr) 164*80c94ecdSKeith M Wesolowski { 165*80c94ecdSKeith M Wesolowski cpqary3_t *cpqary3p; 166*80c94ecdSKeith M Wesolowski 167*80c94ecdSKeith M Wesolowski cpqary3p = (void *)per_ctlr; 168*80c94ecdSKeith M Wesolowski if (!cpqary3p) { 169*80c94ecdSKeith M Wesolowski cmn_err(CE_PANIC, "CPQary3 : Software Interrupt Service " 170*80c94ecdSKeith M Wesolowski "Routine invoked with NULL pointer argument \n"); 171*80c94ecdSKeith M Wesolowski } 172*80c94ecdSKeith M Wesolowski 173*80c94ecdSKeith M Wesolowski /* 174*80c94ecdSKeith M Wesolowski * Ensure that our hardware routine actually triggered this routine. 175*80c94ecdSKeith M Wesolowski * If it was not the case, do NOT CLAIM the interrupt 176*80c94ecdSKeith M Wesolowski */ 177*80c94ecdSKeith M Wesolowski 178*80c94ecdSKeith M Wesolowski mutex_enter(&cpqary3p->hw_mutex); 179*80c94ecdSKeith M Wesolowski if (CPQARY3_TRUE != cpqary3p->swintr_flag) { 180*80c94ecdSKeith M Wesolowski mutex_exit(&cpqary3p->hw_mutex); 181*80c94ecdSKeith M Wesolowski return (DDI_INTR_UNCLAIMED); 182*80c94ecdSKeith M Wesolowski } 183*80c94ecdSKeith M Wesolowski 184*80c94ecdSKeith M Wesolowski cpqary3p->swintr_flag = CPQARY3_FALSE; 185*80c94ecdSKeith M Wesolowski 186*80c94ecdSKeith M Wesolowski /* PERF */ 187*80c94ecdSKeith M Wesolowski mutex_exit(&cpqary3p->hw_mutex); 188*80c94ecdSKeith M Wesolowski (void) cpqary3_retrieve(cpqary3p); 189*80c94ecdSKeith M Wesolowski /* PERF */ 190*80c94ecdSKeith M Wesolowski 191*80c94ecdSKeith M Wesolowski return (DDI_INTR_CLAIMED); 192*80c94ecdSKeith M Wesolowski } 193