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
cpqary3_hw_isr(caddr_t per_ctlr)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
cpqary3_sw_isr(caddr_t per_ctlr)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