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