1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte  * CDDL HEADER START
3fcf3ce44SJohn Forte  *
4fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte  *
8fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte  * and limitations under the License.
12fcf3ce44SJohn Forte  *
13fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte  *
19fcf3ce44SJohn Forte  * CDDL HEADER END
20fcf3ce44SJohn Forte  */
21fcf3ce44SJohn Forte 
22c1fad183SDaniel Beauregard /* Copyright 2010 QLogic Corporation */
23fcf3ce44SJohn Forte 
24fcf3ce44SJohn Forte /*
25*f885d00fSDaniel Beauregard  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
26fcf3ce44SJohn Forte  */
27fcf3ce44SJohn Forte 
28c1fad183SDaniel Beauregard #pragma ident	"Copyright 2010 QLogic Corporation; ql_isr.c"
29fcf3ce44SJohn Forte 
30fcf3ce44SJohn Forte /*
31fcf3ce44SJohn Forte  * ISP2xxx Solaris Fibre Channel Adapter (FCA) driver source file.
32fcf3ce44SJohn Forte  *
33fcf3ce44SJohn Forte  * ***********************************************************************
34fcf3ce44SJohn Forte  * *									**
35fcf3ce44SJohn Forte  * *				NOTICE					**
36c1fad183SDaniel Beauregard  * *		COPYRIGHT (C) 1996-2010 QLOGIC CORPORATION		**
37fcf3ce44SJohn Forte  * *			ALL RIGHTS RESERVED				**
38fcf3ce44SJohn Forte  * *									**
39fcf3ce44SJohn Forte  * ***********************************************************************
40fcf3ce44SJohn Forte  *
41fcf3ce44SJohn Forte  */
42fcf3ce44SJohn Forte 
43fcf3ce44SJohn Forte #include <ql_apps.h>
44fcf3ce44SJohn Forte #include <ql_api.h>
45fcf3ce44SJohn Forte #include <ql_debug.h>
46fcf3ce44SJohn Forte #include <ql_iocb.h>
47fcf3ce44SJohn Forte #include <ql_isr.h>
48fcf3ce44SJohn Forte #include <ql_init.h>
49fcf3ce44SJohn Forte #include <ql_mbx.h>
50eb82ff87SDaniel Beauregard #include <ql_nx.h>
51fcf3ce44SJohn Forte #include <ql_xioctl.h>
52fcf3ce44SJohn Forte 
53fcf3ce44SJohn Forte /*
54fcf3ce44SJohn Forte  * Local Function Prototypes.
55fcf3ce44SJohn Forte  */
5616dd44c2SDaniel Beauregard static void ql_handle_uncommon_risc_intr(ql_adapter_state_t *, uint32_t,
5716dd44c2SDaniel Beauregard     uint32_t *);
58fcf3ce44SJohn Forte static void ql_spurious_intr(ql_adapter_state_t *, int);
59fcf3ce44SJohn Forte static void ql_mbx_completion(ql_adapter_state_t *, uint16_t, uint32_t *,
60fcf3ce44SJohn Forte     uint32_t *, int);
61fcf3ce44SJohn Forte static void ql_async_event(ql_adapter_state_t *, uint32_t, ql_head_t *,
62fcf3ce44SJohn Forte     uint32_t *, uint32_t *, int);
63fcf3ce44SJohn Forte static void ql_fast_fcp_post(ql_srb_t *);
64fcf3ce44SJohn Forte static void ql_response_pkt(ql_adapter_state_t *, ql_head_t *, uint32_t *,
65fcf3ce44SJohn Forte     uint32_t *, int);
66fcf3ce44SJohn Forte static void ql_error_entry(ql_adapter_state_t *, response_t *, ql_head_t *,
67fcf3ce44SJohn Forte     uint32_t *, uint32_t *);
68fcf3ce44SJohn Forte static int ql_status_entry(ql_adapter_state_t *, sts_entry_t *, ql_head_t *,
69fcf3ce44SJohn Forte     uint32_t *, uint32_t *);
70fcf3ce44SJohn Forte static int ql_24xx_status_entry(ql_adapter_state_t *, sts_24xx_entry_t *,
71fcf3ce44SJohn Forte     ql_head_t *, uint32_t *, uint32_t *);
72fcf3ce44SJohn Forte static int ql_status_error(ql_adapter_state_t *, ql_srb_t *, sts_entry_t *,
73fcf3ce44SJohn Forte     ql_head_t *, uint32_t *, uint32_t *);
74fcf3ce44SJohn Forte static void ql_status_cont_entry(ql_adapter_state_t *, sts_cont_entry_t *,
75fcf3ce44SJohn Forte     ql_head_t *, uint32_t *, uint32_t *);
76fcf3ce44SJohn Forte static void ql_ip_entry(ql_adapter_state_t *, ip_entry_t *, ql_head_t *,
77fcf3ce44SJohn Forte     uint32_t *, uint32_t *);
78fcf3ce44SJohn Forte static void ql_ip_rcv_entry(ql_adapter_state_t *, ip_rcv_entry_t *,
79fcf3ce44SJohn Forte     ql_head_t *, uint32_t *, uint32_t *);
80fcf3ce44SJohn Forte static void ql_ip_rcv_cont_entry(ql_adapter_state_t *,
81fcf3ce44SJohn Forte     ip_rcv_cont_entry_t *, ql_head_t *, uint32_t *, uint32_t *);
82fcf3ce44SJohn Forte static void ql_ip_24xx_rcv_entry(ql_adapter_state_t *, ip_rcv_24xx_entry_t *,
83fcf3ce44SJohn Forte     ql_head_t *, uint32_t *, uint32_t *);
84fcf3ce44SJohn Forte static void ql_ms_entry(ql_adapter_state_t *, ms_entry_t *, ql_head_t *,
85fcf3ce44SJohn Forte     uint32_t *, uint32_t *);
86fcf3ce44SJohn Forte static void ql_report_id_entry(ql_adapter_state_t *, report_id_1_t *,
87fcf3ce44SJohn Forte     ql_head_t *, uint32_t *, uint32_t *);
885dfd244aSDaniel Beauregard static void ql_els_passthru_entry(ql_adapter_state_t *,
895dfd244aSDaniel Beauregard     els_passthru_entry_rsp_t *, ql_head_t *, uint32_t *, uint32_t *);
90a2b3ff35SDaniel Beauregard static ql_srb_t *ql_verify_preprocessed_cmd(ql_adapter_state_t *, uint32_t *,
91a2b3ff35SDaniel Beauregard     uint32_t *, uint32_t *);
92a2b3ff35SDaniel Beauregard static void ql_signal_abort(ql_adapter_state_t *ha, uint32_t *set_flags);
93fcf3ce44SJohn Forte 
94*f885d00fSDaniel Beauregard /*
95*f885d00fSDaniel Beauregard  * Spurious interrupt counter
96*f885d00fSDaniel Beauregard  */
97*f885d00fSDaniel Beauregard uint32_t	ql_spurious_cnt = 4;
98*f885d00fSDaniel Beauregard uint32_t	ql_max_intr_loop = 16;
99*f885d00fSDaniel Beauregard 
100fcf3ce44SJohn Forte /*
101fcf3ce44SJohn Forte  * ql_isr
102fcf3ce44SJohn Forte  *	Process all INTX intr types.
103fcf3ce44SJohn Forte  *
104fcf3ce44SJohn Forte  * Input:
105fcf3ce44SJohn Forte  *	arg1:	adapter state pointer.
106fcf3ce44SJohn Forte  *
107fcf3ce44SJohn Forte  * Returns:
109fcf3ce44SJohn Forte  *
110fcf3ce44SJohn Forte  * Context:
111fcf3ce44SJohn Forte  *	Interrupt or Kernel context, no mailbox commands allowed.
112fcf3ce44SJohn Forte  */
113fcf3ce44SJohn Forte /* ARGSUSED */
114fcf3ce44SJohn Forte uint_t
ql_isr(caddr_t arg1)115fcf3ce44SJohn Forte ql_isr(caddr_t arg1)
116fcf3ce44SJohn Forte {
117fcf3ce44SJohn Forte 	return (ql_isr_aif(arg1, 0));
118fcf3ce44SJohn Forte }
119fcf3ce44SJohn Forte 
120fcf3ce44SJohn Forte /*
121fcf3ce44SJohn Forte  * ql_isr_default
122fcf3ce44SJohn Forte  *	Process unknown/unvectored intr types
123fcf3ce44SJohn Forte  *
124fcf3ce44SJohn Forte  * Input:
125fcf3ce44SJohn Forte  *	arg1:	adapter state pointer.
126fcf3ce44SJohn Forte  *	arg2:	interrupt vector.
127fcf3ce44SJohn Forte  *
128fcf3ce44SJohn Forte  * Returns:
130fcf3ce44SJohn Forte  *
131fcf3ce44SJohn Forte  * Context:
132fcf3ce44SJohn Forte  *	Interrupt or Kernel context, no mailbox commands allowed.
133fcf3ce44SJohn Forte  */
134fcf3ce44SJohn Forte /* ARGSUSED */
135fcf3ce44SJohn Forte uint_t
ql_isr_default(caddr_t arg1,caddr_t arg2)136fcf3ce44SJohn Forte ql_isr_default(caddr_t arg1, caddr_t arg2)
137fcf3ce44SJohn Forte {
138fcf3ce44SJohn Forte 	ql_adapter_state_t	*ha = (void *)arg1;
139fcf3ce44SJohn Forte 
140fcf3ce44SJohn Forte 	EL(ha, "isr_default called: idx=%x\n", arg2);
141fcf3ce44SJohn Forte 	return (ql_isr_aif(arg1, arg2));
142fcf3ce44SJohn Forte }
143fcf3ce44SJohn Forte 
144fcf3ce44SJohn Forte /*
145fcf3ce44SJohn Forte  * ql_isr_aif
146fcf3ce44SJohn Forte  *	Process mailbox and I/O command completions.
147fcf3ce44SJohn Forte  *
148fcf3ce44SJohn Forte  * Input:
149fcf3ce44SJohn Forte  *	arg:	adapter state pointer.
150fcf3ce44SJohn Forte  *	intvec:	interrupt vector.
151fcf3ce44SJohn Forte  *
152fcf3ce44SJohn Forte  * Returns:
154fcf3ce44SJohn Forte  *
155fcf3ce44SJohn Forte  * Context:
156fcf3ce44SJohn Forte  *	Interrupt or Kernel context, no mailbox commands allowed.
157fcf3ce44SJohn Forte  */
158fcf3ce44SJohn Forte /* ARGSUSED */
159fcf3ce44SJohn Forte uint_t
ql_isr_aif(caddr_t arg,caddr_t intvec)160fcf3ce44SJohn Forte ql_isr_aif(caddr_t arg, caddr_t intvec)
161fcf3ce44SJohn Forte {
162fcf3ce44SJohn Forte 	uint16_t		mbx;
163fcf3ce44SJohn Forte 	uint32_t		stat;
164fcf3ce44SJohn Forte 	ql_adapter_state_t	*ha = (void *)arg;
165fcf3ce44SJohn Forte 	uint32_t		set_flags = 0;
166fcf3ce44SJohn Forte 	uint32_t		reset_flags = 0;
167fcf3ce44SJohn Forte 	ql_head_t		isr_done_q = {NULL, NULL};
168fcf3ce44SJohn Forte 	uint_t			rval = DDI_INTR_UNCLAIMED;
169fcf3ce44SJohn Forte 	int			spurious_intr = 0;
170fcf3ce44SJohn Forte 	boolean_t		intr = B_FALSE, daemon = B_FALSE;
171fcf3ce44SJohn Forte 	int			intr_loop = 4;
172*f885d00fSDaniel Beauregard 	boolean_t		clear_spurious = B_TRUE;
173fcf3ce44SJohn Forte 
174fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
175fcf3ce44SJohn Forte 
176fcf3ce44SJohn Forte 	QL_PM_LOCK(ha);
177fcf3ce44SJohn Forte 	if (ha->power_level != PM_LEVEL_D0) {
178fcf3ce44SJohn Forte 		/*
179fcf3ce44SJohn Forte 		 * Looks like we are about to go down soon, exit early.
180fcf3ce44SJohn Forte 		 */
181fcf3ce44SJohn Forte 		QL_PM_UNLOCK(ha);
182fcf3ce44SJohn Forte 		QL_PRINT_3(CE_CONT, "(%d): power down exit\n", ha->instance);
183fcf3ce44SJohn Forte 		return (DDI_INTR_UNCLAIMED);
184fcf3ce44SJohn Forte 	}
185fcf3ce44SJohn Forte 	ha->busy++;
186fcf3ce44SJohn Forte 	QL_PM_UNLOCK(ha);
187fcf3ce44SJohn Forte 
188fcf3ce44SJohn Forte 	/* Acquire interrupt lock. */
189fcf3ce44SJohn Forte 	INTR_LOCK(ha);
190fcf3ce44SJohn Forte 
191fcf3ce44SJohn Forte 	if (CFG_IST(ha, CFG_CTRL_2200)) {
192fcf3ce44SJohn Forte 		while (RD16_IO_REG(ha, istatus) & RISC_INT) {
193fcf3ce44SJohn Forte 			/* Reset idle timer. */
194fcf3ce44SJohn Forte 			ha->idle_timer = 0;
195fcf3ce44SJohn Forte 			rval = DDI_INTR_CLAIMED;
196fcf3ce44SJohn Forte 			if (intr_loop) {
197fcf3ce44SJohn Forte 				intr_loop--;
198fcf3ce44SJohn Forte 			}
199fcf3ce44SJohn Forte 
200fcf3ce44SJohn Forte 			/* Special Fast Post 2200. */
201fcf3ce44SJohn Forte 			stat = 0;
202fcf3ce44SJohn Forte 			if (ha->task_daemon_flags & FIRMWARE_LOADED &&
203fcf3ce44SJohn Forte 			    ha->flags & ONLINE) {
204fcf3ce44SJohn Forte 				ql_srb_t	*sp;
205fcf3ce44SJohn Forte 
206eb82ff87SDaniel Beauregard 				mbx = RD16_IO_REG(ha, mailbox_out[23]);
207fcf3ce44SJohn Forte 
208fcf3ce44SJohn Forte 				if ((mbx & 3) == MBX23_SCSI_COMPLETION) {
209fcf3ce44SJohn Forte 					/* Release mailbox registers. */
210fcf3ce44SJohn Forte 					WRT16_IO_REG(ha, semaphore, 0);
211fcf3ce44SJohn Forte 
212fcf3ce44SJohn Forte 					if (intr_loop) {
213fcf3ce44SJohn Forte 						WRT16_IO_REG(ha, hccr,
214fcf3ce44SJohn Forte 						    HC_CLR_RISC_INT);
215fcf3ce44SJohn Forte 					}
216fcf3ce44SJohn Forte 
217fcf3ce44SJohn Forte 					/* Get handle. */
218fcf3ce44SJohn Forte 					mbx >>= 4;
219fcf3ce44SJohn Forte 					stat = mbx & OSC_INDEX_MASK;
220fcf3ce44SJohn Forte 
221fcf3ce44SJohn Forte 					/* Validate handle. */
222fcf3ce44SJohn Forte 					sp = stat < MAX_OUTSTANDING_COMMANDS ?
223fcf3ce44SJohn Forte 					    ha->outstanding_cmds[stat] : NULL;
224fcf3ce44SJohn Forte 
225fcf3ce44SJohn Forte 					if (sp != NULL && (sp->handle & 0xfff)
226fcf3ce44SJohn Forte 					    == mbx) {
227fcf3ce44SJohn Forte 						ha->outstanding_cmds[stat] =
228fcf3ce44SJohn Forte 						    NULL;
229fcf3ce44SJohn Forte 						sp->handle = 0;
230fcf3ce44SJohn Forte 						sp->flags &=
231fcf3ce44SJohn Forte 						    ~SRB_IN_TOKEN_ARRAY;
232fcf3ce44SJohn Forte 
233fcf3ce44SJohn Forte 						/* Set completed status. */
234fcf3ce44SJohn Forte 						sp->flags |= SRB_ISP_COMPLETED;
235fcf3ce44SJohn Forte 
236fcf3ce44SJohn Forte 						/* Set completion status */
237fcf3ce44SJohn Forte 						sp->pkt->pkt_reason =
238fcf3ce44SJohn Forte 						    CS_COMPLETE;
239fcf3ce44SJohn Forte 
240fcf3ce44SJohn Forte 						ql_fast_fcp_post(sp);
241fcf3ce44SJohn Forte 					} else if (mbx !=
242fcf3ce44SJohn Forte 					    (QL_FCA_BRAND & 0xfff)) {
243fcf3ce44SJohn Forte 						if (sp == NULL) {
244fcf3ce44SJohn Forte 							EL(ha, "unknown IOCB"
245fcf3ce44SJohn Forte 							    " handle=%xh\n",
246fcf3ce44SJohn Forte 							    mbx);
247fcf3ce44SJohn Forte 						} else {
248fcf3ce44SJohn Forte 							EL(ha, "mismatch IOCB"
249fcf3ce44SJohn Forte 							    " handle pkt=%xh, "
250fcf3ce44SJohn Forte 							    "sp=%xh\n", mbx,
251fcf3ce44SJohn Forte 							    sp->handle & 0xfff);
252fcf3ce44SJohn Forte 						}
253fcf3ce44SJohn Forte 
254fcf3ce44SJohn Forte 						(void) ql_binary_fw_dump(ha,
255fcf3ce44SJohn Forte 						    FALSE);
256fcf3ce44SJohn Forte 
257fcf3ce44SJohn Forte 						if (!(ha->task_daemon_flags &
258fcf3ce44SJohn Forte 						    (ISP_ABORT_NEEDED |
259fcf3ce44SJohn Forte 						    ABORT_ISP_ACTIVE))) {
260fcf3ce44SJohn Forte 							EL(ha, "ISP Invalid "
261fcf3ce44SJohn Forte 							    "handle, "
262fcf3ce44SJohn Forte 							    "isp_abort_needed"
263fcf3ce44SJohn Forte 							    "\n");
264fcf3ce44SJohn Forte 							set_flags |=
265fcf3ce44SJohn Forte 							    ISP_ABORT_NEEDED;
266fcf3ce44SJohn Forte 						}
267fcf3ce44SJohn Forte 					}
268fcf3ce44SJohn Forte 				}
269fcf3ce44SJohn Forte 			}
270fcf3ce44SJohn Forte 
271fcf3ce44SJohn Forte 			if (stat == 0) {
272fcf3ce44SJohn Forte 				/* Check for mailbox interrupt. */
273fcf3ce44SJohn Forte 				mbx = RD16_IO_REG(ha, semaphore);
274fcf3ce44SJohn Forte 				if (mbx & BIT_0) {
275fcf3ce44SJohn Forte 					/* Release mailbox registers. */
276fcf3ce44SJohn Forte 					WRT16_IO_REG(ha, semaphore, 0);
277fcf3ce44SJohn Forte 
278fcf3ce44SJohn Forte 					/* Get mailbox data. */
279eb82ff87SDaniel Beauregard 					mbx = RD16_IO_REG(ha, mailbox_out[0]);
280fcf3ce44SJohn Forte 					if (mbx > 0x3fff && mbx < 0x8000) {
281fcf3ce44SJohn Forte 						ql_mbx_completion(ha, mbx,
282fcf3ce44SJohn Forte 						    &set_flags, &reset_flags,
283fcf3ce44SJohn Forte 						    intr_loop);
284fcf3ce44SJohn Forte 					} else if (mbx > 0x7fff &&
285fcf3ce44SJohn Forte 					    mbx < 0xc000) {
286fcf3ce44SJohn Forte 						ql_async_event(ha, mbx,
287fcf3ce44SJohn Forte 						    &isr_done_q, &set_flags,
288fcf3ce44SJohn Forte 						    &reset_flags, intr_loop);
289fcf3ce44SJohn Forte 					} else {
290fcf3ce44SJohn Forte 						EL(ha, "UNKNOWN interrupt "
291fcf3ce44SJohn Forte 						    "type\n");
292fcf3ce44SJohn Forte 						intr = B_TRUE;
293fcf3ce44SJohn Forte 					}
294fcf3ce44SJohn Forte 				} else {
295fcf3ce44SJohn Forte 					ha->isp_rsp_index = RD16_IO_REG(ha,
296fcf3ce44SJohn Forte 					    resp_in);
297fcf3ce44SJohn Forte 
298fcf3ce44SJohn Forte 					if (ha->isp_rsp_index !=
299fcf3ce44SJohn Forte 					    ha->rsp_ring_index) {
300fcf3ce44SJohn Forte 						ql_response_pkt(ha,
301fcf3ce44SJohn Forte 						    &isr_done_q, &set_flags,
302fcf3ce44SJohn Forte 						    &reset_flags, intr_loop);
303fcf3ce44SJohn Forte 					} else if (++spurious_intr ==
304fcf3ce44SJohn Forte 					    MAX_SPURIOUS_INTR) {
305fcf3ce44SJohn Forte 						/*
306fcf3ce44SJohn Forte 						 * Process excessive
307fcf3ce44SJohn Forte 						 * spurious intrrupts
308fcf3ce44SJohn Forte 						 */
309fcf3ce44SJohn Forte 						ql_spurious_intr(ha,
310fcf3ce44SJohn Forte 						    intr_loop);
311fcf3ce44SJohn Forte 						EL(ha, "excessive spurious "
312fcf3ce44SJohn Forte 						    "interrupts, "
313fcf3ce44SJohn Forte 						    "isp_abort_needed\n");
314fcf3ce44SJohn Forte 						set_flags |= ISP_ABORT_NEEDED;
315fcf3ce44SJohn Forte 					} else {
316fcf3ce44SJohn Forte 						intr = B_TRUE;
317fcf3ce44SJohn Forte 					}
318fcf3ce44SJohn Forte 				}
319fcf3ce44SJohn Forte 			}
320fcf3ce44SJohn Forte 
321fcf3ce44SJohn Forte 			/* Clear RISC interrupt */
322fcf3ce44SJohn Forte 			if (intr || intr_loop == 0) {
323fcf3ce44SJohn Forte 				intr = B_FALSE;
324fcf3ce44SJohn Forte 				WRT16_IO_REG(ha, hccr, HC_CLR_RISC_INT);
325fcf3ce44SJohn Forte 			}
326fcf3ce44SJohn Forte 
327fcf3ce44SJohn Forte 			if (set_flags != 0 || reset_flags != 0) {
328fcf3ce44SJohn Forte 				TASK_DAEMON_LOCK(ha);
329fcf3ce44SJohn Forte 				ha->task_daemon_flags |= set_flags;
330fcf3ce44SJohn Forte 				ha->task_daemon_flags &= ~reset_flags;
331fcf3ce44SJohn Forte 				TASK_DAEMON_UNLOCK(ha);
332fcf3ce44SJohn Forte 				set_flags = 0;
333fcf3ce44SJohn Forte 				reset_flags = 0;
334fcf3ce44SJohn Forte 				daemon = B_TRUE;
335fcf3ce44SJohn Forte 			}
336fcf3ce44SJohn Forte 		}
337fcf3ce44SJohn Forte 	} else {
338*f885d00fSDaniel Beauregard 		uint32_t	ql_max_intr_loop_cnt = 0;
339*f885d00fSDaniel Beauregard 
340eb82ff87SDaniel Beauregard 		if (CFG_IST(ha, CFG_CTRL_8021)) {
341eb82ff87SDaniel Beauregard 			ql_8021_clr_hw_intr(ha);
342*f885d00fSDaniel Beauregard 			intr_loop = 1;
343eb82ff87SDaniel Beauregard 		}
344*f885d00fSDaniel Beauregard 		while (((stat = RD32_IO_REG(ha, risc2host)) & RH_RISC_INT) &&
345*f885d00fSDaniel Beauregard 		    (++ql_max_intr_loop_cnt < ql_max_intr_loop)) {
346*f885d00fSDaniel Beauregard 
347*f885d00fSDaniel Beauregard 			clear_spurious = B_TRUE;	/* assume ok */
348*f885d00fSDaniel Beauregard 
34916dd44c2SDaniel Beauregard 			/* Capture FW defined interrupt info */
350fcf3ce44SJohn Forte 			mbx = MSW(stat);
351fcf3ce44SJohn Forte 
352fcf3ce44SJohn Forte 			/* Reset idle timer. */
353fcf3ce44SJohn Forte 			ha->idle_timer = 0;
354fcf3ce44SJohn Forte 			rval = DDI_INTR_CLAIMED;
355eb82ff87SDaniel Beauregard 
356eb82ff87SDaniel Beauregard 			if (CFG_IST(ha, CFG_CTRL_8021) &&
357*f885d00fSDaniel Beauregard 			    (RD32_IO_REG(ha, nx_risc_int) == 0 ||
358*f885d00fSDaniel Beauregard 			    intr_loop == 0)) {
359eb82ff87SDaniel Beauregard 				break;
360eb82ff87SDaniel Beauregard 			}
361eb82ff87SDaniel Beauregard 
362fcf3ce44SJohn Forte 			if (intr_loop) {
363fcf3ce44SJohn Forte 				intr_loop--;
364fcf3ce44SJohn Forte 			}
365fcf3ce44SJohn Forte 
366fcf3ce44SJohn Forte 			switch (stat & 0x1ff) {
367fcf3ce44SJohn Forte 			case ROM_MBX_SUCCESS:
368fcf3ce44SJohn Forte 			case ROM_MBX_ERR:
369fcf3ce44SJohn Forte 				ql_mbx_completion(ha, mbx, &set_flags,
370fcf3ce44SJohn Forte 				    &reset_flags, intr_loop);
371fcf3ce44SJohn Forte 
372fcf3ce44SJohn Forte 				/* Release mailbox registers. */
373eb82ff87SDaniel Beauregard 				if ((CFG_IST(ha, CFG_CTRL_24258081)) == 0) {
374fcf3ce44SJohn Forte 					WRT16_IO_REG(ha, semaphore, 0);
375fcf3ce44SJohn Forte 				}
376fcf3ce44SJohn Forte 				break;
377fcf3ce44SJohn Forte 
378fcf3ce44SJohn Forte 			case MBX_SUCCESS:
379fcf3ce44SJohn Forte 			case MBX_ERR:
380fcf3ce44SJohn Forte 				/* Sun FW, Release mailbox registers. */
381eb82ff87SDaniel Beauregard 				if ((CFG_IST(ha, CFG_CTRL_24258081)) == 0) {
382fcf3ce44SJohn Forte 					WRT16_IO_REG(ha, semaphore, 0);
383fcf3ce44SJohn Forte 				}
384fcf3ce44SJohn Forte 				ql_mbx_completion(ha, mbx, &set_flags,
385fcf3ce44SJohn Forte 				    &reset_flags, intr_loop);
386fcf3ce44SJohn Forte 				break;
387fcf3ce44SJohn Forte 
388fcf3ce44SJohn Forte 			case ASYNC_EVENT:
389fcf3ce44SJohn Forte 				/* Sun FW, Release mailbox registers. */
390eb82ff87SDaniel Beauregard 				if ((CFG_IST(ha, CFG_CTRL_24258081)) == 0) {
391fcf3ce44SJohn Forte 					WRT16_IO_REG(ha, semaphore, 0);
392fcf3ce44SJohn Forte 				}
393fcf3ce44SJohn Forte 				ql_async_event(ha, (uint32_t)mbx, &isr_done_q,
394fcf3ce44SJohn Forte 				    &set_flags, &reset_flags, intr_loop);
395fcf3ce44SJohn Forte 				break;
396fcf3ce44SJohn Forte 
397fcf3ce44SJohn Forte 			case RESP_UPDATE:
398fcf3ce44SJohn Forte 				if (mbx != ha->rsp_ring_index) {
399fcf3ce44SJohn Forte 					ha->isp_rsp_index = mbx;
400fcf3ce44SJohn Forte 					ql_response_pkt(ha, &isr_done_q,
401fcf3ce44SJohn Forte 					    &set_flags, &reset_flags,
402fcf3ce44SJohn Forte 					    intr_loop);
403fcf3ce44SJohn Forte 				} else if (++spurious_intr ==
404*f885d00fSDaniel Beauregard 				    ql_spurious_cnt) {
405fcf3ce44SJohn Forte 					/* Process excessive spurious intr. */
406fcf3ce44SJohn Forte 					ql_spurious_intr(ha, intr_loop);
407fcf3ce44SJohn Forte 					EL(ha, "excessive spurious "
408fcf3ce44SJohn Forte 					    "interrupts, isp_abort_needed\n");
409fcf3ce44SJohn Forte 					set_flags |= ISP_ABORT_NEEDED;
410*f885d00fSDaniel Beauregard 					clear_spurious = B_FALSE;
411fcf3ce44SJohn Forte 				} else {
412*f885d00fSDaniel Beauregard 					QL_PRINT_10(CE_CONT, "(%d): response "
413*f885d00fSDaniel Beauregard 					    "ring index same as before\n",
414*f885d00fSDaniel Beauregard 					    ha->instance);
415fcf3ce44SJohn Forte 					intr = B_TRUE;
416*f885d00fSDaniel Beauregard 					clear_spurious = B_FALSE;
417fcf3ce44SJohn Forte 				}
418fcf3ce44SJohn Forte 				break;
419fcf3ce44SJohn Forte 
420fcf3ce44SJohn Forte 			case SCSI_FAST_POST_16:
421fcf3ce44SJohn Forte 				stat = (stat & 0xffff0000) | MBA_CMPLT_1_16BIT;
422fcf3ce44SJohn Forte 				ql_async_event(ha, stat, &isr_done_q,
423fcf3ce44SJohn Forte 				    &set_flags, &reset_flags, intr_loop);
424fcf3ce44SJohn Forte 				break;
425fcf3ce44SJohn Forte 
426fcf3ce44SJohn Forte 			case SCSI_FAST_POST_32:
427fcf3ce44SJohn Forte 				stat = (stat & 0xffff0000) | MBA_CMPLT_1_32BIT;
428fcf3ce44SJohn Forte 				ql_async_event(ha, stat, &isr_done_q,
429fcf3ce44SJohn Forte 				    &set_flags, &reset_flags, intr_loop);
430fcf3ce44SJohn Forte 				break;
431fcf3ce44SJohn Forte 
432fcf3ce44SJohn Forte 			case CTIO_FAST_POST:
433fcf3ce44SJohn Forte 				stat = (stat & 0xffff0000) |
434fcf3ce44SJohn Forte 				    MBA_CTIO_COMPLETION;
435fcf3ce44SJohn Forte 				ql_async_event(ha, stat, &isr_done_q,
436fcf3ce44SJohn Forte 				    &set_flags, &reset_flags, intr_loop);
437fcf3ce44SJohn Forte 				break;
438fcf3ce44SJohn Forte 
439fcf3ce44SJohn Forte 			case IP_FAST_POST_XMT:
440fcf3ce44SJohn Forte 				stat = (stat & 0xffff0000) | MBA_IP_COMPLETION;
441fcf3ce44SJohn Forte 				ql_async_event(ha, stat, &isr_done_q,
442fcf3ce44SJohn Forte 				    &set_flags, &reset_flags, intr_loop);
443fcf3ce44SJohn Forte 				break;
444fcf3ce44SJohn Forte 
445fcf3ce44SJohn Forte 			case IP_FAST_POST_RCV:
446fcf3ce44SJohn Forte 				stat = (stat & 0xffff0000) | MBA_IP_RECEIVE;
447fcf3ce44SJohn Forte 				ql_async_event(ha, stat, &isr_done_q,
448fcf3ce44SJohn Forte 				    &set_flags, &reset_flags, intr_loop);
449fcf3ce44SJohn Forte 				break;
450fcf3ce44SJohn Forte 
451fcf3ce44SJohn Forte 			case IP_FAST_POST_BRD:
452fcf3ce44SJohn Forte 				stat = (stat & 0xffff0000) | MBA_IP_BROADCAST;
453fcf3ce44SJohn Forte 				ql_async_event(ha, stat, &isr_done_q,
454fcf3ce44SJohn Forte 				    &set_flags, &reset_flags, intr_loop);
455fcf3ce44SJohn Forte 				break;
456fcf3ce44SJohn Forte 
457fcf3ce44SJohn Forte 			case IP_FAST_POST_RCV_ALN:
458fcf3ce44SJohn Forte 				stat = (stat & 0xffff0000) |
459fcf3ce44SJohn Forte 				    MBA_IP_HDR_DATA_SPLIT;
460fcf3ce44SJohn Forte 				ql_async_event(ha, stat, &isr_done_q,
461fcf3ce44SJohn Forte 				    &set_flags, &reset_flags, intr_loop);
462fcf3ce44SJohn Forte 				break;
463fcf3ce44SJohn Forte 
464fcf3ce44SJohn Forte 			case ATIO_UPDATE:
465fcf3ce44SJohn Forte 				EL(ha, "unsupported ATIO queue update"
466fcf3ce44SJohn Forte 				    " interrupt, status=%xh\n", stat);
467fcf3ce44SJohn Forte 				intr = B_TRUE;
468fcf3ce44SJohn Forte 				break;
469fcf3ce44SJohn Forte 
470fcf3ce44SJohn Forte 			case ATIO_RESP_UPDATE:
471fcf3ce44SJohn Forte 				EL(ha, "unsupported ATIO response queue "
472fcf3ce44SJohn Forte 				    "update interrupt, status=%xh\n", stat);
473fcf3ce44SJohn Forte 				intr = B_TRUE;
474fcf3ce44SJohn Forte 				break;
475fcf3ce44SJohn Forte 
476fcf3ce44SJohn Forte 			default:
47716dd44c2SDaniel Beauregard 				ql_handle_uncommon_risc_intr(ha, stat,
47816dd44c2SDaniel Beauregard 				    &set_flags);
479fcf3ce44SJohn Forte 				intr = B_TRUE;
480fcf3ce44SJohn Forte 				break;
481fcf3ce44SJohn Forte 			}
482fcf3ce44SJohn Forte 
483fcf3ce44SJohn Forte 			/* Clear RISC interrupt */
484fcf3ce44SJohn Forte 			if (intr || intr_loop == 0) {
485fcf3ce44SJohn Forte 				intr = B_FALSE;
486eb82ff87SDaniel Beauregard 				if (CFG_IST(ha, CFG_CTRL_8021)) {
487eb82ff87SDaniel Beauregard 					ql_8021_clr_fw_intr(ha);
488eb82ff87SDaniel Beauregard 				} else if (CFG_IST(ha, CFG_CTRL_242581)) {
489eb82ff87SDaniel Beauregard 					WRT32_IO_REG(ha, hccr,
490eb82ff87SDaniel Beauregard 					    HC24_CLR_RISC_INT);
491eb82ff87SDaniel Beauregard 				} else {
492eb82ff87SDaniel Beauregard 					WRT16_IO_REG(ha, hccr, HC_CLR_RISC_INT);
493eb82ff87SDaniel Beauregard 				}
494fcf3ce44SJohn Forte 			}
495fcf3ce44SJohn Forte 
496fcf3ce44SJohn Forte 			if (set_flags != 0 || reset_flags != 0) {
497fcf3ce44SJohn Forte 				TASK_DAEMON_LOCK(ha);
498fcf3ce44SJohn Forte 				ha->task_daemon_flags |= set_flags;
499fcf3ce44SJohn Forte 				ha->task_daemon_flags &= ~reset_flags;
500fcf3ce44SJohn Forte 				TASK_DAEMON_UNLOCK(ha);
501fcf3ce44SJohn Forte 				set_flags = 0;
502fcf3ce44SJohn Forte 				reset_flags = 0;
503fcf3ce44SJohn Forte 				daemon = B_TRUE;
504fcf3ce44SJohn Forte 			}
505fcf3ce44SJohn Forte 
506fcf3ce44SJohn Forte 			if (ha->flags & PARITY_ERROR) {
507fcf3ce44SJohn Forte 				EL(ha, "parity/pause exit\n");
508fcf3ce44SJohn Forte 				mbx = RD16_IO_REG(ha, hccr); /* PCI posting */
509fcf3ce44SJohn Forte 				break;
510fcf3ce44SJohn Forte 			}
511*f885d00fSDaniel Beauregard 
512*f885d00fSDaniel Beauregard 			if (clear_spurious) {
513*f885d00fSDaniel Beauregard 				spurious_intr = 0;
514*f885d00fSDaniel Beauregard 			}
515fcf3ce44SJohn Forte 		}
516fcf3ce44SJohn Forte 	}
517fcf3ce44SJohn Forte 
518fcf3ce44SJohn Forte 	/* Process claimed interrupts during polls. */
519fcf3ce44SJohn Forte 	if (rval == DDI_INTR_UNCLAIMED && ha->intr_claimed == B_TRUE) {
520fcf3ce44SJohn Forte 		ha->intr_claimed = B_FALSE;
521fcf3ce44SJohn Forte 		rval = DDI_INTR_CLAIMED;
522fcf3ce44SJohn Forte 	}
523fcf3ce44SJohn Forte 
524fcf3ce44SJohn Forte 	/* Release interrupt lock. */
525fcf3ce44SJohn Forte 	INTR_UNLOCK(ha);
526fcf3ce44SJohn Forte 
527fcf3ce44SJohn Forte 	if (daemon) {
528fcf3ce44SJohn Forte 		ql_awaken_task_daemon(ha, NULL, 0, 0);
529fcf3ce44SJohn Forte 	}
530fcf3ce44SJohn Forte 
531fcf3ce44SJohn Forte 	if (isr_done_q.first != NULL) {
532fcf3ce44SJohn Forte 		ql_done(isr_done_q.first);
533fcf3ce44SJohn Forte 	}
534fcf3ce44SJohn Forte 
535fcf3ce44SJohn Forte 	if (rval == DDI_INTR_CLAIMED) {
536fcf3ce44SJohn Forte 		QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
537fcf3ce44SJohn Forte 		ha->xioctl->TotalInterrupts++;
538fcf3ce44SJohn Forte 	} else {
539fcf3ce44SJohn Forte 		/*EMPTY*/
540fcf3ce44SJohn Forte 		QL_PRINT_3(CE_CONT, "(%d): interrupt not claimed\n",
541fcf3ce44SJohn Forte 		    ha->instance);
542fcf3ce44SJohn Forte 	}
543fcf3ce44SJohn Forte 
544fcf3ce44SJohn Forte 	QL_PM_LOCK(ha);
545fcf3ce44SJohn Forte 	ha->busy--;
546fcf3ce44SJohn Forte 	QL_PM_UNLOCK(ha);
547fcf3ce44SJohn Forte 
548fcf3ce44SJohn Forte 	return (rval);
549fcf3ce44SJohn Forte }
550fcf3ce44SJohn Forte 
55116dd44c2SDaniel Beauregard /*
55216dd44c2SDaniel Beauregard  * ql_handle_uncommon_risc_intr
55316dd44c2SDaniel Beauregard  *	Handle an uncommon RISC interrupt.
55416dd44c2SDaniel Beauregard  *
55516dd44c2SDaniel Beauregard  * Input:
55616dd44c2SDaniel Beauregard  *	ha:		adapter state pointer.
55716dd44c2SDaniel Beauregard  *	stat:		interrupt status
55816dd44c2SDaniel Beauregard  *
55916dd44c2SDaniel Beauregard  * Context:
56016dd44c2SDaniel Beauregard  *	Interrupt or Kernel context, no mailbox commands allowed.
56116dd44c2SDaniel Beauregard  */
56216dd44c2SDaniel Beauregard static void
ql_handle_uncommon_risc_intr(ql_adapter_state_t * ha,uint32_t stat,uint32_t * set_flags)56316dd44c2SDaniel Beauregard ql_handle_uncommon_risc_intr(ql_adapter_state_t *ha, uint32_t stat,
56416dd44c2SDaniel Beauregard     uint32_t *set_flags)
56516dd44c2SDaniel Beauregard {
56616dd44c2SDaniel Beauregard 	uint16_t	hccr_reg;
56716dd44c2SDaniel Beauregard 
56816dd44c2SDaniel Beauregard 	hccr_reg = RD16_IO_REG(ha, hccr);
56916dd44c2SDaniel Beauregard 
57016dd44c2SDaniel Beauregard 	if (stat & RH_RISC_PAUSED ||
57116dd44c2SDaniel Beauregard 	    (hccr_reg & (BIT_15 | BIT_13 | BIT_11 | BIT_8))) {
57216dd44c2SDaniel Beauregard 
57316dd44c2SDaniel Beauregard 		ADAPTER_STATE_LOCK(ha);
57416dd44c2SDaniel Beauregard 		ha->flags |= PARITY_ERROR;
57516dd44c2SDaniel Beauregard 		ADAPTER_STATE_UNLOCK(ha);
57616dd44c2SDaniel Beauregard 
57716dd44c2SDaniel Beauregard 		if (ha->parity_pause_errors == 0 ||
57816dd44c2SDaniel Beauregard 		    ha->parity_hccr_err != hccr_reg ||
57916dd44c2SDaniel Beauregard 		    ha->parity_stat_err != stat) {
58016dd44c2SDaniel Beauregard 			cmn_err(CE_WARN, "qlc(%d): isr, Internal Parity/"
58116dd44c2SDaniel Beauregard 			    "Pause Error - hccr=%xh, stat=%xh, count=%d",
58216dd44c2SDaniel Beauregard 			    ha->instance, hccr_reg, stat,
58316dd44c2SDaniel Beauregard 			    ha->parity_pause_errors);
58416dd44c2SDaniel Beauregard 			ha->parity_hccr_err = hccr_reg;
58516dd44c2SDaniel Beauregard 			ha->parity_stat_err = stat;
58616dd44c2SDaniel Beauregard 		}
58716dd44c2SDaniel Beauregard 
58816dd44c2SDaniel Beauregard 		EL(ha, "parity/pause error, isp_abort_needed\n");
58916dd44c2SDaniel Beauregard 
59016dd44c2SDaniel Beauregard 		if (ql_binary_fw_dump(ha, FALSE) != QL_SUCCESS) {
59116dd44c2SDaniel Beauregard 			ql_reset_chip(ha);
59216dd44c2SDaniel Beauregard 		}
59316dd44c2SDaniel Beauregard 
59416dd44c2SDaniel Beauregard 		if (ha->parity_pause_errors == 0) {
595eb82ff87SDaniel Beauregard 			ha->log_parity_pause = B_TRUE;
59616dd44c2SDaniel Beauregard 		}
59716dd44c2SDaniel Beauregard 
59816dd44c2SDaniel Beauregard 		if (ha->parity_pause_errors < 0xffffffff) {
59916dd44c2SDaniel Beauregard 			ha->parity_pause_errors++;
60016dd44c2SDaniel Beauregard 		}
60116dd44c2SDaniel Beauregard 
60216dd44c2SDaniel Beauregard 		*set_flags |= ISP_ABORT_NEEDED;
60316dd44c2SDaniel Beauregard 
60416dd44c2SDaniel Beauregard 		/* Disable ISP interrupts. */
605eb82ff87SDaniel Beauregard 		CFG_IST(ha, CFG_CTRL_8021) ? ql_8021_disable_intrs(ha) :
606eb82ff87SDaniel Beauregard 		    WRT16_IO_REG(ha, ictrl, 0);
60716dd44c2SDaniel Beauregard 		ADAPTER_STATE_LOCK(ha);
60816dd44c2SDaniel Beauregard 		ha->flags &= ~INTERRUPTS_ENABLED;
60916dd44c2SDaniel Beauregard 		ADAPTER_STATE_UNLOCK(ha);
61016dd44c2SDaniel Beauregard 	} else {
61116dd44c2SDaniel Beauregard 		EL(ha, "UNKNOWN interrupt status=%xh, hccr=%xh\n",
61216dd44c2SDaniel Beauregard 		    stat, hccr_reg);
61316dd44c2SDaniel Beauregard 	}
61416dd44c2SDaniel Beauregard }
61516dd44c2SDaniel Beauregard 
616fcf3ce44SJohn Forte /*
617fcf3ce44SJohn Forte  * ql_spurious_intr
618fcf3ce44SJohn Forte  *	Inform Solaris of spurious interrupts.
619fcf3ce44SJohn Forte  *
620fcf3ce44SJohn Forte  * Input:
621fcf3ce44SJohn Forte  *	ha:		adapter state pointer.
622fcf3ce44SJohn Forte  *	intr_clr:	early interrupt clear
623fcf3ce44SJohn Forte  *
624fcf3ce44SJohn Forte  * Context:
625fcf3ce44SJohn Forte  *	Interrupt or Kernel context, no mailbox commands allowed.
626fcf3ce44SJohn Forte  */
627fcf3ce44SJohn Forte static void
ql_spurious_intr(ql_adapter_state_t * ha,int intr_clr)628fcf3ce44SJohn Forte ql_spurious_intr(ql_adapter_state_t *ha, int intr_clr)
629fcf3ce44SJohn Forte {
630fcf3ce44SJohn Forte 	ddi_devstate_t	state;
631fcf3ce44SJohn Forte 
632fcf3ce44SJohn Forte 	EL(ha, "Spurious interrupt\n");
633fcf3ce44SJohn Forte 
634fcf3ce44SJohn Forte 	/* Disable ISP interrupts. */
635fcf3ce44SJohn Forte 	WRT16_IO_REG(ha, ictrl, 0);
636fcf3ce44SJohn Forte 	ADAPTER_STATE_LOCK(ha);
637fcf3ce44SJohn Forte 	ha->flags &= ~INTERRUPTS_ENABLED;
638fcf3ce44SJohn Forte 	ADAPTER_STATE_UNLOCK(ha);
639fcf3ce44SJohn Forte 
640fcf3ce44SJohn Forte 	/* Clear RISC interrupt */
641fcf3ce44SJohn Forte 	if (intr_clr) {
642eb82ff87SDaniel Beauregard 		if (CFG_IST(ha, CFG_CTRL_8021)) {
643eb82ff87SDaniel Beauregard 			ql_8021_clr_fw_intr(ha);
644eb82ff87SDaniel Beauregard 		} else if (CFG_IST(ha, CFG_CTRL_242581)) {
645eb82ff87SDaniel Beauregard 			WRT32_IO_REG(ha, hccr, HC24_CLR_RISC_INT);
646eb82ff87SDaniel Beauregard 		} else {
647eb82ff87SDaniel Beauregard 			WRT16_IO_REG(ha, hccr, HC_CLR_RISC_INT);
648eb82ff87SDaniel Beauregard 		}
649fcf3ce44SJohn Forte 	}
650fcf3ce44SJohn Forte 
651fcf3ce44SJohn Forte 	state = ddi_get_devstate(ha->dip);
652fcf3ce44SJohn Forte 	if (state == DDI_DEVSTATE_UP) {
653fcf3ce44SJohn Forte 		/*EMPTY*/
654fcf3ce44SJohn Forte 		ddi_dev_report_fault(ha->dip, DDI_SERVICE_DEGRADED,
655fcf3ce44SJohn Forte 		    DDI_DEVICE_FAULT, "spurious interrupts");
656fcf3ce44SJohn Forte 	}
657fcf3ce44SJohn Forte }
658fcf3ce44SJohn Forte 
659fcf3ce44SJohn Forte /*
660fcf3ce44SJohn Forte  * ql_mbx_completion
661fcf3ce44SJohn Forte  *	Processes mailbox completions.
662fcf3ce44SJohn Forte  *
663fcf3ce44SJohn Forte  * Input:
664fcf3ce44SJohn Forte  *	ha:		adapter state pointer.
665fcf3ce44SJohn Forte  *	mb0:		Mailbox 0 contents.
666fcf3ce44SJohn Forte  *	set_flags:	task daemon flags to set.
667fcf3ce44SJohn Forte  *	reset_flags:	task daemon flags to reset.
668fcf3ce44SJohn Forte  *	intr_clr:	early interrupt clear
669fcf3ce44SJohn Forte  *
670fcf3ce44SJohn Forte  * Context:
671fcf3ce44SJohn Forte  *	Interrupt context.
672fcf3ce44SJohn Forte  */
673fcf3ce44SJohn Forte /* ARGSUSED */
674fcf3ce44SJohn Forte static void
ql_mbx_completion(ql_adapter_state_t * ha,uint16_t mb0,uint32_t * set_flags,uint32_t * reset_flags,int intr_clr)675fcf3ce44SJohn Forte ql_mbx_completion(ql_adapter_state_t *ha, uint16_t mb0, uint32_t *set_flags,
676fcf3ce44SJohn Forte     uint32_t *reset_flags, int intr_clr)
677fcf3ce44SJohn Forte {
678fcf3ce44SJohn Forte 	uint32_t	index;
679fcf3ce44SJohn Forte 	uint16_t	cnt;
680fcf3ce44SJohn Forte 
681fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
682fcf3ce44SJohn Forte 
683fcf3ce44SJohn Forte 	/* Load return mailbox registers. */
684fcf3ce44SJohn Forte 	MBX_REGISTER_LOCK(ha);
685fcf3ce44SJohn Forte 
686fcf3ce44SJohn Forte 	if (ha->mcp != NULL) {
687fcf3ce44SJohn Forte 		ha->mcp->mb[0] = mb0;
688fcf3ce44SJohn Forte 		index = ha->mcp->in_mb & ~MBX_0;
689fcf3ce44SJohn Forte 
690fcf3ce44SJohn Forte 		for (cnt = 1; cnt < MAX_MBOX_COUNT && index != 0; cnt++) {
691fcf3ce44SJohn Forte 			index >>= 1;
692fcf3ce44SJohn Forte 			if (index & MBX_0) {
693fcf3ce44SJohn Forte 				ha->mcp->mb[cnt] = RD16_IO_REG(ha,
694eb82ff87SDaniel Beauregard 				    mailbox_out[cnt]);
695fcf3ce44SJohn Forte 			}
696fcf3ce44SJohn Forte 		}
697fcf3ce44SJohn Forte 
698fcf3ce44SJohn Forte 	} else {
699fcf3ce44SJohn Forte 		EL(ha, "mcp == NULL\n");
700fcf3ce44SJohn Forte 	}
701fcf3ce44SJohn Forte 
702fcf3ce44SJohn Forte 	if (intr_clr) {
703fcf3ce44SJohn Forte 		/* Clear RISC interrupt. */
704eb82ff87SDaniel Beauregard 		if (CFG_IST(ha, CFG_CTRL_8021)) {
705eb82ff87SDaniel Beauregard 			ql_8021_clr_fw_intr(ha);
706eb82ff87SDaniel Beauregard 		} else if (CFG_IST(ha, CFG_CTRL_242581)) {
707eb82ff87SDaniel Beauregard 			WRT32_IO_REG(ha, hccr, HC24_CLR_RISC_INT);
708eb82ff87SDaniel Beauregard 		} else {
709eb82ff87SDaniel Beauregard 			WRT16_IO_REG(ha, hccr, HC_CLR_RISC_INT);
710eb82ff87SDaniel Beauregard 		}
711fcf3ce44SJohn Forte 	}
712fcf3ce44SJohn Forte 
713fcf3ce44SJohn Forte 	ha->mailbox_flags = (uint8_t)(ha->mailbox_flags | MBX_INTERRUPT);
714fcf3ce44SJohn Forte 	if (ha->flags & INTERRUPTS_ENABLED) {
715fcf3ce44SJohn Forte 		cv_broadcast(&ha->cv_mbx_intr);
716fcf3ce44SJohn Forte 	}
717fcf3ce44SJohn Forte 
718fcf3ce44SJohn Forte 	MBX_REGISTER_UNLOCK(ha);
719fcf3ce44SJohn Forte 
720fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
721fcf3ce44SJohn Forte }
722fcf3ce44SJohn Forte 
723fcf3ce44SJohn Forte /*
724fcf3ce44SJohn Forte  * ql_async_event
725fcf3ce44SJohn Forte  *	Processes asynchronous events.
726fcf3ce44SJohn Forte  *
727fcf3ce44SJohn Forte  * Input:
728fcf3ce44SJohn Forte  *	ha:		adapter state pointer.
729fcf3ce44SJohn Forte  *	mbx:		Mailbox 0 register.
730fcf3ce44SJohn Forte  *	done_q:		head pointer to done queue.
731fcf3ce44SJohn Forte  *	set_flags:	task daemon flags to set.
732fcf3ce44SJohn Forte  *	reset_flags:	task daemon flags to reset.
733fcf3ce44SJohn Forte  *	intr_clr:	early interrupt clear
734fcf3ce44SJohn Forte  *
735fcf3ce44SJohn Forte  * Context:
736fcf3ce44SJohn Forte  *	Interrupt or Kernel context, no mailbox commands allowed.
737fcf3ce44SJohn Forte  */
738fcf3ce44SJohn Forte static void
ql_async_event(ql_adapter_state_t * ha,uint32_t mbx,ql_head_t * done_q,uint32_t * set_flags,uint32_t * reset_flags,int intr_clr)739fcf3ce44SJohn Forte ql_async_event(ql_adapter_state_t *ha, uint32_t mbx, ql_head_t *done_q,
740fcf3ce44SJohn Forte     uint32_t *set_flags, uint32_t *reset_flags, int intr_clr)
741fcf3ce44SJohn Forte {
742fcf3ce44SJohn Forte 	uint32_t		handle;
743fcf3ce44SJohn Forte 	uint32_t		index;
744fcf3ce44SJohn Forte 	uint16_t		cnt;
745fcf3ce44SJohn Forte 	uint16_t		mb[MAX_MBOX_COUNT];
746fcf3ce44SJohn Forte 	ql_srb_t		*sp;
747fcf3ce44SJohn Forte 	port_id_t		s_id;
748fcf3ce44SJohn Forte 	ql_tgt_t		*tq;
749fcf3ce44SJohn Forte 	boolean_t		intr = B_TRUE;
750fcf3ce44SJohn Forte 	ql_adapter_state_t	*vha;
751fcf3ce44SJohn Forte 
752fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
753fcf3ce44SJohn Forte 
754fcf3ce44SJohn Forte 	/* Setup to process fast completion. */
755fcf3ce44SJohn Forte 	mb[0] = LSW(mbx);
756fcf3ce44SJohn Forte 	switch (mb[0]) {
757fcf3ce44SJohn Forte 	case MBA_SCSI_COMPLETION:
758eb82ff87SDaniel Beauregard 		handle = SHORT_TO_LONG(RD16_IO_REG(ha, mailbox_out[1]),
759eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[2]));
760fcf3ce44SJohn Forte 		break;
761fcf3ce44SJohn Forte 
762fcf3ce44SJohn Forte 	case MBA_CMPLT_1_16BIT:
763fcf3ce44SJohn Forte 		handle = MSW(mbx);
764fcf3ce44SJohn Forte 		mb[0] = MBA_SCSI_COMPLETION;
765fcf3ce44SJohn Forte 		break;
766fcf3ce44SJohn Forte 
767fcf3ce44SJohn Forte 	case MBA_CMPLT_1_32BIT:
768eb82ff87SDaniel Beauregard 		handle = SHORT_TO_LONG(MSW(mbx),
769eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[2]));
770fcf3ce44SJohn Forte 		mb[0] = MBA_SCSI_COMPLETION;
771fcf3ce44SJohn Forte 		break;
772fcf3ce44SJohn Forte 
773fcf3ce44SJohn Forte 	case MBA_CTIO_COMPLETION:
774fcf3ce44SJohn Forte 	case MBA_IP_COMPLETION:
775fcf3ce44SJohn Forte 		handle = CFG_IST(ha, CFG_CTRL_2200) ? SHORT_TO_LONG(
776eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[1]),
777eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[2])) :
778eb82ff87SDaniel Beauregard 		    SHORT_TO_LONG(MSW(mbx), RD16_IO_REG(ha, mailbox_out[2]));
779fcf3ce44SJohn Forte 		mb[0] = MBA_SCSI_COMPLETION;
780fcf3ce44SJohn Forte 		break;
781fcf3ce44SJohn Forte 
782fcf3ce44SJohn Forte 	default:
783fcf3ce44SJohn Forte 		break;
784fcf3ce44SJohn Forte 	}
785fcf3ce44SJohn Forte 
786fcf3ce44SJohn Forte 	/* Handle asynchronous event */
787fcf3ce44SJohn Forte 	switch (mb[0]) {
788fcf3ce44SJohn Forte 	case MBA_SCSI_COMPLETION:
789fcf3ce44SJohn Forte 		QL_PRINT_5(CE_CONT, "(%d): Fast post completion\n",
790fcf3ce44SJohn Forte 		    ha->instance);
791fcf3ce44SJohn Forte 
792fcf3ce44SJohn Forte 		if (intr_clr) {
793fcf3ce44SJohn Forte 			/* Clear RISC interrupt */
794eb82ff87SDaniel Beauregard 			if (CFG_IST(ha, CFG_CTRL_8021)) {
795eb82ff87SDaniel Beauregard 				ql_8021_clr_fw_intr(ha);
796eb82ff87SDaniel Beauregard 			} else if (CFG_IST(ha, CFG_CTRL_242581)) {
797eb82ff87SDaniel Beauregard 				WRT32_IO_REG(ha, hccr, HC24_CLR_RISC_INT);
798eb82ff87SDaniel Beauregard 			} else {
799eb82ff87SDaniel Beauregard 				WRT16_IO_REG(ha, hccr, HC_CLR_RISC_INT);
800eb82ff87SDaniel Beauregard 			}
801fcf3ce44SJohn Forte 			intr = B_FALSE;
802fcf3ce44SJohn Forte 		}
803fcf3ce44SJohn Forte 
804fcf3ce44SJohn Forte 		if ((ha->flags & ONLINE) == 0) {
805fcf3ce44SJohn Forte 			break;
806fcf3ce44SJohn Forte 		}
807fcf3ce44SJohn Forte 
808fcf3ce44SJohn Forte 		/* Get handle. */
809fcf3ce44SJohn Forte 		index = handle & OSC_INDEX_MASK;
810fcf3ce44SJohn Forte 
811fcf3ce44SJohn Forte 		/* Validate handle. */
812fcf3ce44SJohn Forte 		sp = index < MAX_OUTSTANDING_COMMANDS ?
813fcf3ce44SJohn Forte 		    ha->outstanding_cmds[index] : NULL;
814fcf3ce44SJohn Forte 
815fcf3ce44SJohn Forte 		if (sp != NULL && sp->handle == handle) {
816fcf3ce44SJohn Forte 			ha->outstanding_cmds[index] = NULL;
817fcf3ce44SJohn Forte 			sp->handle = 0;
818fcf3ce44SJohn Forte 			sp->flags &= ~SRB_IN_TOKEN_ARRAY;
819fcf3ce44SJohn Forte 
820fcf3ce44SJohn Forte 			/* Set completed status. */
821fcf3ce44SJohn Forte 			sp->flags |= SRB_ISP_COMPLETED;
822fcf3ce44SJohn Forte 
823fcf3ce44SJohn Forte 			/* Set completion status */
824fcf3ce44SJohn Forte 			sp->pkt->pkt_reason = CS_COMPLETE;
825fcf3ce44SJohn Forte 
826fcf3ce44SJohn Forte 			if (!(sp->flags & SRB_FCP_CMD_PKT)) {
827fcf3ce44SJohn Forte 				/* Place block on done queue */
828fcf3ce44SJohn Forte 				ql_add_link_b(done_q, &sp->cmd);
829fcf3ce44SJohn Forte 			} else {
830fcf3ce44SJohn Forte 				ql_fast_fcp_post(sp);
831fcf3ce44SJohn Forte 			}
832fcf3ce44SJohn Forte 		} else if (handle != QL_FCA_BRAND) {
833fcf3ce44SJohn Forte 			if (sp == NULL) {
834fcf3ce44SJohn Forte 				EL(ha, "%xh unknown IOCB handle=%xh\n",
835fcf3ce44SJohn Forte 				    mb[0], handle);
836fcf3ce44SJohn Forte 			} else {
837fcf3ce44SJohn Forte 				EL(ha, "%xh mismatch IOCB handle pkt=%xh, "
838fcf3ce44SJohn Forte 				    "sp=%xh\n", mb[0], handle, sp->handle);
839fcf3ce44SJohn Forte 			}
840fcf3ce44SJohn Forte 
841fcf3ce44SJohn Forte 			EL(ha, "%xh Fast post, mbx1=%xh, mbx2=%xh, mbx3=%xh,"
842fcf3ce44SJohn Forte 			    "mbx6=%xh, mbx7=%xh\n", mb[0],
843eb82ff87SDaniel Beauregard 			    RD16_IO_REG(ha, mailbox_out[1]),
844eb82ff87SDaniel Beauregard 			    RD16_IO_REG(ha, mailbox_out[2]),
845eb82ff87SDaniel Beauregard 			    RD16_IO_REG(ha, mailbox_out[3]),
846eb82ff87SDaniel Beauregard 			    RD16_IO_REG(ha, mailbox_out[6]),
847eb82ff87SDaniel Beauregard 			    RD16_IO_REG(ha, mailbox_out[7]));
848fcf3ce44SJohn Forte 
849fcf3ce44SJohn Forte 			(void) ql_binary_fw_dump(ha, FALSE);
850fcf3ce44SJohn Forte 
851fcf3ce44SJohn Forte 			if (!(ha->task_daemon_flags &
852fcf3ce44SJohn Forte 			    (ISP_ABORT_NEEDED | ABORT_ISP_ACTIVE))) {
853fcf3ce44SJohn Forte 				EL(ha, "%xh ISP Invalid handle, "
854fcf3ce44SJohn Forte 				    "isp_abort_needed\n", mb[0]);
855fcf3ce44SJohn Forte 				*set_flags |= ISP_ABORT_NEEDED;
856fcf3ce44SJohn Forte 			}
857fcf3ce44SJohn Forte 		}
858fcf3ce44SJohn Forte 		break;
859fcf3ce44SJohn Forte 
860fcf3ce44SJohn Forte 	case MBA_RESET:		/* Reset */
861fcf3ce44SJohn Forte 		EL(ha, "%xh Reset received\n", mb[0]);
862fcf3ce44SJohn Forte 		*set_flags |= RESET_MARKER_NEEDED;
863fcf3ce44SJohn Forte 		break;
864fcf3ce44SJohn Forte 
865fcf3ce44SJohn Forte 	case MBA_SYSTEM_ERR:		/* System Error */
866eb82ff87SDaniel Beauregard 		mb[1] = RD16_IO_REG(ha, mailbox_out[1]);
867eb82ff87SDaniel Beauregard 		mb[2] = RD16_IO_REG(ha, mailbox_out[2]);
868eb82ff87SDaniel Beauregard 		mb[3] = RD16_IO_REG(ha, mailbox_out[3]);
869eb82ff87SDaniel Beauregard 		mb[7] = RD16_IO_REG(ha, mailbox_out[7]);
870fcf3ce44SJohn Forte 
871fcf3ce44SJohn Forte 		EL(ha, "%xh ISP System Error, isp_abort_needed\n mbx1=%xh, "
872fcf3ce44SJohn Forte 		    "mbx2=%xh, mbx3=%xh, mbx4=%xh, mbx5=%xh, mbx6=%xh,\n "
873fcf3ce44SJohn Forte 		    "mbx7=%xh, mbx8=%xh, mbx9=%xh, mbx10=%xh, mbx11=%xh, "
874fcf3ce44SJohn Forte 		    "mbx12=%xh,\n", mb[0], mb[1], mb[2], mb[3],
875eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[4]),
876eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[5]),
877eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[6]), mb[7],
878eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[8]),
879eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[9]),
880eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[10]),
881eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[11]),
882eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[12]));
883fcf3ce44SJohn Forte 
884fcf3ce44SJohn Forte 		EL(ha, "%xh ISP System Error, isp_abort_needed\n mbx13=%xh, "
885fcf3ce44SJohn Forte 		    "mbx14=%xh, mbx15=%xh, mbx16=%xh, mbx17=%xh, mbx18=%xh,\n"
886fcf3ce44SJohn Forte 		    "mbx19=%xh, mbx20=%xh, mbx21=%xh, mbx22=%xh, mbx23=%xh\n",
887eb82ff87SDaniel Beauregard 		    mb[0], RD16_IO_REG(ha, mailbox_out[13]),
888eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[14]),
889eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[15]),
890eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[16]),
891eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[17]),
892eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[18]),
893eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[19]),
894eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[20]),
895eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[21]),
896eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[22]),
897eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[23]));
898fcf3ce44SJohn Forte 
899fcf3ce44SJohn Forte 		if (ha->reg_off->mbox_cnt > 24) {
900fcf3ce44SJohn Forte 			EL(ha, "%xh ISP System Error, mbx24=%xh, mbx25=%xh, "
901fcf3ce44SJohn Forte 			    "mbx26=%xh,\n mbx27=%xh, mbx28=%xh, mbx29=%xh, "
902fcf3ce44SJohn Forte 			    "mbx30=%xh, mbx31=%xh\n", mb[0],
903eb82ff87SDaniel Beauregard 			    RD16_IO_REG(ha, mailbox_out[24]),
904eb82ff87SDaniel Beauregard 			    RD16_IO_REG(ha, mailbox_out[25]),
905eb82ff87SDaniel Beauregard 			    RD16_IO_REG(ha, mailbox_out[26]),
906eb82ff87SDaniel Beauregard 			    RD16_IO_REG(ha, mailbox_out[27]),
907eb82ff87SDaniel Beauregard 			    RD16_IO_REG(ha, mailbox_out[28]),
908eb82ff87SDaniel Beauregard 			    RD16_IO_REG(ha, mailbox_out[29]),
909eb82ff87SDaniel Beauregard 			    RD16_IO_REG(ha, mailbox_out[30]),
910eb82ff87SDaniel Beauregard 			    RD16_IO_REG(ha, mailbox_out[31]));
911fcf3ce44SJohn Forte 		}
912fcf3ce44SJohn Forte 
913fcf3ce44SJohn Forte 		(void) ql_binary_fw_dump(ha, FALSE);
914fcf3ce44SJohn Forte 
915fcf3ce44SJohn Forte 		(void) ql_flash_errlog(ha, FLASH_ERRLOG_AEN_8002, mb[1],
916fcf3ce44SJohn Forte 		    mb[2], mb[3]);
917fcf3ce44SJohn Forte 
9184f8b8adcSDaniel Beauregard 		if (CFG_IST(ha, CFG_CTRL_81XX) && mb[7] & SE_MPI_RISC) {
9194f8b8adcSDaniel Beauregard 			ADAPTER_STATE_LOCK(ha);
9204f8b8adcSDaniel Beauregard 			ha->flags |= MPI_RESET_NEEDED;
9214f8b8adcSDaniel Beauregard 			ADAPTER_STATE_UNLOCK(ha);
9224f8b8adcSDaniel Beauregard 		}
9234f8b8adcSDaniel Beauregard 
924fcf3ce44SJohn Forte 		*set_flags |= ISP_ABORT_NEEDED;
925fcf3ce44SJohn Forte 		ha->xioctl->ControllerErrorCount++;
926fcf3ce44SJohn Forte 		break;
927fcf3ce44SJohn Forte 
928fcf3ce44SJohn Forte 	case MBA_REQ_TRANSFER_ERR:  /* Request Transfer Error */
929fcf3ce44SJohn Forte 		EL(ha, "%xh Request Transfer Error received, "
930fcf3ce44SJohn Forte 		    "isp_abort_needed\n", mb[0]);
931fcf3ce44SJohn Forte 
932fcf3ce44SJohn Forte 		(void) ql_flash_errlog(ha, FLASH_ERRLOG_AEN_8003,
933eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[1]),
934eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[2]),
935eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[3]));
936fcf3ce44SJohn Forte 
937fcf3ce44SJohn Forte 		*set_flags |= ISP_ABORT_NEEDED;
938fcf3ce44SJohn Forte 		ha->xioctl->ControllerErrorCount++;
939fcf3ce44SJohn Forte 		break;
940fcf3ce44SJohn Forte 
941fcf3ce44SJohn Forte 	case MBA_RSP_TRANSFER_ERR:  /* Response Xfer Err */
942fcf3ce44SJohn Forte 		EL(ha, "%xh Response Transfer Error received,"
943fcf3ce44SJohn Forte 		    " isp_abort_needed\n", mb[0]);