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:
108fcf3ce44SJohn Forte  *	DDI_INTR_CLAIMED or DDI_INTR_UNCLAIMED
109fcf3ce44SJohn Forte  *
110fcf3ce44SJohn Forte  * Context:
111fcf3ce44SJohn Forte  *	Interrupt or Kernel context, no mailbox commands allowed.
112fcf3ce44SJohn Forte  */
113fcf3ce44SJohn Forte /* ARGSUSED */
114fcf3ce44SJohn Forte uint_t
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:
129fcf3ce44SJohn Forte  *	DDI_INTR_CLAIMED or DDI_INTR_UNCLAIMED
130fcf3ce44SJohn Forte  *
131fcf3ce44SJohn Forte  * Context:
132fcf3ce44SJohn Forte  *	Interrupt or Kernel context, no mailbox commands allowed.
133fcf3ce44SJohn Forte  */
134fcf3ce44SJohn Forte /* ARGSUSED */
135fcf3ce44SJohn Forte uint_t
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:
153fcf3ce44SJohn Forte  *	DDI_INTR_CLAIMED or DDI_INTR_UNCLAIMED
154fcf3ce44SJohn Forte  *
155fcf3ce44SJohn Forte  * Context:
156fcf3ce44SJohn Forte  *	Interrupt or Kernel context, no mailbox commands allowed.
157fcf3ce44SJohn Forte  */
158fcf3ce44SJohn Forte /* ARGSUSED */
159fcf3ce44SJohn Forte uint_t
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
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
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
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
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]);
944fcf3ce44SJohn Forte 
945fcf3ce44SJohn Forte 		(void) ql_flash_errlog(ha, FLASH_ERRLOG_AEN_8004,
946eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[1]),
947eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[2]),
948eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[3]));
949fcf3ce44SJohn Forte 
950fcf3ce44SJohn Forte 		*set_flags |= ISP_ABORT_NEEDED;
951fcf3ce44SJohn Forte 		ha->xioctl->ControllerErrorCount++;
952fcf3ce44SJohn Forte 		break;
953fcf3ce44SJohn Forte 
954fcf3ce44SJohn Forte 	case MBA_WAKEUP_THRES: /* Request Queue Wake-up */
955fcf3ce44SJohn Forte 		EL(ha, "%xh Request Queue Wake-up received\n",
956fcf3ce44SJohn Forte 		    mb[0]);
957fcf3ce44SJohn Forte 		break;
958fcf3ce44SJohn Forte 
959fcf3ce44SJohn Forte 	case MBA_MENLO_ALERT:	/* Menlo Alert Notification */
960eb82ff87SDaniel Beauregard 		mb[1] = RD16_IO_REG(ha, mailbox_out[1]);
961eb82ff87SDaniel Beauregard 		mb[2] = RD16_IO_REG(ha, mailbox_out[2]);
962eb82ff87SDaniel Beauregard 		mb[3] = RD16_IO_REG(ha, mailbox_out[3]);
963fcf3ce44SJohn Forte 
964fcf3ce44SJohn Forte 		EL(ha, "%xh Menlo Alert Notification received, mbx1=%xh,"
965fcf3ce44SJohn Forte 		    " mbx2=%xh, mbx3=%xh\n", mb[0], mb[1], mb[2], mb[3]);
966fcf3ce44SJohn Forte 
967fcf3ce44SJohn Forte 		switch (mb[1]) {
968fcf3ce44SJohn Forte 		case MLA_LOGIN_OPERATIONAL_FW:
969fcf3ce44SJohn Forte 			ADAPTER_STATE_LOCK(ha);
970fcf3ce44SJohn Forte 			ha->flags |= MENLO_LOGIN_OPERATIONAL;
971fcf3ce44SJohn Forte 			ADAPTER_STATE_UNLOCK(ha);
972fcf3ce44SJohn Forte 			break;
973fcf3ce44SJohn Forte 		case MLA_PANIC_RECOVERY:
974fcf3ce44SJohn Forte 		case MLA_LOGIN_DIAGNOSTIC_FW:
975fcf3ce44SJohn Forte 		case MLA_LOGIN_GOLDEN_FW:
976fcf3ce44SJohn Forte 		case MLA_REJECT_RESPONSE:
977fcf3ce44SJohn Forte 		default:
978fcf3ce44SJohn Forte 			break;
979fcf3ce44SJohn Forte 		}
980fcf3ce44SJohn Forte 		break;
981fcf3ce44SJohn Forte 
982fcf3ce44SJohn Forte 	case MBA_LIP_F8:	/* Received a LIP F8. */
983fcf3ce44SJohn Forte 	case MBA_LIP_RESET:	/* LIP reset occurred. */
984fcf3ce44SJohn Forte 	case MBA_LIP_OCCURRED:	/* Loop Initialization Procedure */
985eb82ff87SDaniel Beauregard 		if (CFG_IST(ha, CFG_CTRL_8081)) {
9865dfd244aSDaniel Beauregard 			EL(ha, "%xh DCBX_STARTED received, mbx1=%xh, mbx2=%xh"
987eb82ff87SDaniel Beauregard 			    "\n", mb[0], RD16_IO_REG(ha, mailbox_out[1]),
988eb82ff87SDaniel Beauregard 			    RD16_IO_REG(ha, mailbox_out[2]));
9895dfd244aSDaniel Beauregard 		} else {
9905dfd244aSDaniel Beauregard 			EL(ha, "%xh LIP received\n", mb[0]);
9915dfd244aSDaniel Beauregard 		}
992fcf3ce44SJohn Forte 
993fcf3ce44SJohn Forte 		ADAPTER_STATE_LOCK(ha);
994fcf3ce44SJohn Forte 		ha->flags &= ~POINT_TO_POINT;
995fcf3ce44SJohn Forte 		ADAPTER_STATE_UNLOCK(ha);
996fcf3ce44SJohn Forte 
997fcf3ce44SJohn Forte 		if (!(ha->task_daemon_flags & LOOP_DOWN)) {
998fcf3ce44SJohn Forte 			*set_flags |= LOOP_DOWN;
999fcf3ce44SJohn Forte 		}
1000fcf3ce44SJohn Forte 		ql_port_state(ha, FC_STATE_OFFLINE,
1001fcf3ce44SJohn Forte 		    FC_STATE_CHANGE | COMMAND_WAIT_NEEDED | LOOP_DOWN);
1002fcf3ce44SJohn Forte 
1003fcf3ce44SJohn Forte 		if (ha->loop_down_timer == LOOP_DOWN_TIMER_OFF) {
1004fcf3ce44SJohn Forte 			ha->loop_down_timer = LOOP_DOWN_TIMER_START;
1005fcf3ce44SJohn Forte 		}
1006fcf3ce44SJohn Forte 
1007fcf3ce44SJohn Forte 		ha->adapter_stats->lip_count++;
1008fcf3ce44SJohn Forte 
1009fcf3ce44SJohn Forte 		/* Update AEN queue. */
1010fcf3ce44SJohn Forte 		ha->xioctl->TotalLipResets++;
1011fcf3ce44SJohn Forte 		if (ha->xioctl->flags & QL_AEN_TRACKING_ENABLE) {
1012fcf3ce44SJohn Forte 			ql_enqueue_aen(ha, mb[0], NULL);
1013fcf3ce44SJohn Forte 		}
1014fcf3ce44SJohn Forte 		break;
1015fcf3ce44SJohn Forte 
1016fcf3ce44SJohn Forte 	case MBA_LOOP_UP:
10175dfd244aSDaniel Beauregard 		if (CFG_IST(ha, (CFG_CTRL_2300 | CFG_CTRL_6322 |
1018eb82ff87SDaniel Beauregard 		    CFG_CTRL_24258081))) {
1019*f885d00fSDaniel Beauregard 			ha->iidma_rate = RD16_IO_REG(ha, mailbox_out[1]);
1020*f885d00fSDaniel Beauregard 			if (ha->iidma_rate == IIDMA_RATE_1GB) {
1021fcf3ce44SJohn Forte 				ha->state = FC_PORT_STATE_MASK(
1022fcf3ce44SJohn Forte 				    ha->state) | FC_STATE_1GBIT_SPEED;
1023fcf3ce44SJohn Forte 				index = 1;
1024*f885d00fSDaniel Beauregard 			} else if (ha->iidma_rate == IIDMA_RATE_2GB) {
1025fcf3ce44SJohn Forte 				ha->state = FC_PORT_STATE_MASK(
1026fcf3ce44SJohn Forte 				    ha->state) | FC_STATE_2GBIT_SPEED;
1027fcf3ce44SJohn Forte 				index = 2;
1028*f885d00fSDaniel Beauregard 			} else if (ha->iidma_rate == IIDMA_RATE_4GB) {
1029fcf3ce44SJohn Forte 				ha->state = FC_PORT_STATE_MASK(
1030fcf3ce44SJohn Forte 				    ha->state) | FC_STATE_4GBIT_SPEED;
1031fcf3ce44SJohn Forte 				index = 4;
1032*f885d00fSDaniel Beauregard 			} else if (ha->iidma_rate == IIDMA_RATE_8GB) {
1033fcf3ce44SJohn Forte 				ha->state = FC_PORT_STATE_MASK(
1034fcf3ce44SJohn Forte 				    ha->state) | FC_STATE_8GBIT_SPEED;
1035fcf3ce44SJohn Forte 				index = 8;
1036*f885d00fSDaniel Beauregard 			} else if (ha->iidma_rate == IIDMA_RATE_10GB) {
10375dfd244aSDaniel Beauregard 				ha->state = FC_PORT_STATE_MASK(
10385dfd244aSDaniel Beauregard 				    ha->state) | FC_STATE_10GBIT_SPEED;
10395dfd244aSDaniel Beauregard 				index = 10;
1040fcf3ce44SJohn Forte 			} else {
1041fcf3ce44SJohn Forte 				ha->state = FC_PORT_STATE_MASK(
1042fcf3ce44SJohn Forte 				    ha->state);
1043fcf3ce44SJohn Forte 				index = 0;
1044fcf3ce44SJohn Forte 			}
1045fcf3ce44SJohn Forte 		} else {
1046*f885d00fSDaniel Beauregard 			ha->iidma_rate = IIDMA_RATE_1GB;
1047fcf3ce44SJohn Forte 			ha->state = FC_PORT_STATE_MASK(ha->state) |
1048fcf3ce44SJohn Forte 			    FC_STATE_FULL_SPEED;
1049fcf3ce44SJohn Forte 			index = 1;
1050fcf3ce44SJohn Forte 		}
1051fcf3ce44SJohn Forte 
1052fcf3ce44SJohn Forte 		for (vha = ha; vha != NULL; vha = vha->vp_next) {
1053fcf3ce44SJohn Forte 			vha->state = FC_PORT_STATE_MASK(vha->state) |
1054fcf3ce44SJohn Forte 			    FC_PORT_SPEED_MASK(ha->state);
1055fcf3ce44SJohn Forte 		}
1056fcf3ce44SJohn Forte 		EL(ha, "%d GB %xh Loop Up received\n", index, mb[0]);
1057fcf3ce44SJohn Forte 
1058fcf3ce44SJohn Forte 		/* Update AEN queue. */
1059fcf3ce44SJohn Forte 		if (ha->xioctl->flags & QL_AEN_TRACKING_ENABLE) {
1060fcf3ce44SJohn Forte 			ql_enqueue_aen(ha, mb[0], NULL);
1061fcf3ce44SJohn Forte 		}
1062fcf3ce44SJohn Forte 		break;
1063fcf3ce44SJohn Forte 
1064fcf3ce44SJohn Forte 	case MBA_LOOP_DOWN:
10654f8b8adcSDaniel Beauregard 		EL(ha, "%xh Loop Down received, mbx1=%xh, mbx2=%xh, mbx3=%xh, "
1066eb82ff87SDaniel Beauregard 		    "mbx4=%xh\n", mb[0], RD16_IO_REG(ha, mailbox_out[1]),
1067eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[2]),
1068eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[3]),
1069eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[4]));
1070fcf3ce44SJohn Forte 
1071fcf3ce44SJohn Forte 		if (!(ha->task_daemon_flags & LOOP_DOWN)) {
1072fcf3ce44SJohn Forte 			*set_flags |= LOOP_DOWN;
1073fcf3ce44SJohn Forte 		}
1074fcf3ce44SJohn Forte 		ql_port_state(ha, FC_STATE_OFFLINE,
1075fcf3ce44SJohn Forte 		    FC_STATE_CHANGE | COMMAND_WAIT_NEEDED | LOOP_DOWN);
1076fcf3ce44SJohn Forte 
1077fcf3ce44SJohn Forte 		if (ha->loop_down_timer == LOOP_DOWN_TIMER_OFF) {
1078fcf3ce44SJohn Forte 			ha->loop_down_timer = LOOP_DOWN_TIMER_START;
1079fcf3ce44SJohn Forte 		}
1080fcf3ce44SJohn Forte 
1081eb82ff87SDaniel Beauregard 		if (CFG_IST(ha, CFG_CTRL_258081)) {
1082eb82ff87SDaniel Beauregard 			ha->sfp_stat = RD16_IO_REG(ha, mailbox_out[2]);
1083fcf3ce44SJohn Forte 		}
1084fcf3ce44SJohn Forte 
1085fcf3ce44SJohn Forte 		/* Update AEN queue. */
1086fcf3ce44SJohn Forte 		if (ha->xioctl->flags & QL_AEN_TRACKING_ENABLE) {
1087fcf3ce44SJohn Forte 			ql_enqueue_aen(ha, mb[0], NULL);
1088fcf3ce44SJohn Forte 		}
1089fcf3ce44SJohn Forte 		break;
1090fcf3ce44SJohn Forte 
1091fcf3ce44SJohn Forte 	case MBA_PORT_UPDATE:
1092eb82ff87SDaniel Beauregard 		mb[1] = RD16_IO_REG(ha, mailbox_out[1]);
1093eb82ff87SDaniel Beauregard 		mb[2] = RD16_IO_REG(ha, mailbox_out[2]);
1094fcf3ce44SJohn Forte 		mb[3] = (uint16_t)(ha->flags & VP_ENABLED ?
1095eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[3]) : 0);
1096fcf3ce44SJohn Forte 
1097fcf3ce44SJohn Forte 		/* Locate port state structure. */
1098fcf3ce44SJohn Forte 		for (vha = ha; vha != NULL; vha = vha->vp_next) {
1099fcf3ce44SJohn Forte 			if (vha->vp_index == LSB(mb[3])) {
1100fcf3ce44SJohn Forte 				break;
1101fcf3ce44SJohn Forte 			}
1102fcf3ce44SJohn Forte 		}
1103fcf3ce44SJohn Forte 		if (vha == NULL) {
1104fcf3ce44SJohn Forte 			break;
1105fcf3ce44SJohn Forte 		}
1106eb82ff87SDaniel Beauregard 
1107eb82ff87SDaniel Beauregard 		if (CFG_IST(ha, CFG_CTRL_8081) && mb[1] == 0xffff &&
1108eb82ff87SDaniel Beauregard 		    mb[2] == 7 && (MSB(mb[3]) == 0xe || MSB(mb[3]) == 0x1a ||
1109eb82ff87SDaniel Beauregard 		    MSB(mb[3]) == 0x1c || MSB(mb[3]) == 0x1d ||
1110eb82ff87SDaniel Beauregard 		    MSB(mb[3]) == 0x1e)) {
1111eb82ff87SDaniel Beauregard 			/*
1112eb82ff87SDaniel Beauregard 			 * received FLOGI reject
1113eb82ff87SDaniel Beauregard 			 * received FLOGO
1114eb82ff87SDaniel Beauregard 			 * FCF configuration changed
1115eb82ff87SDaniel Beauregard 			 * FIP Clear Virtual Link received
1116eb82ff87SDaniel Beauregard 			 * FKA timeout
1117eb82ff87SDaniel Beauregard 			 */
1118eb82ff87SDaniel Beauregard 			if (!(ha->task_daemon_flags & LOOP_DOWN)) {
1119eb82ff87SDaniel Beauregard 				*set_flags |= LOOP_DOWN;
1120eb82ff87SDaniel Beauregard 			}
1121eb82ff87SDaniel Beauregard 			ql_port_state(ha, FC_STATE_OFFLINE, FC_STATE_CHANGE |
1122eb82ff87SDaniel Beauregard 			    COMMAND_WAIT_NEEDED | LOOP_DOWN);
1123eb82ff87SDaniel Beauregard 			if (ha->loop_down_timer == LOOP_DOWN_TIMER_OFF) {
1124eb82ff87SDaniel Beauregard 				ha->loop_down_timer = LOOP_DOWN_TIMER_START;
1125eb82ff87SDaniel Beauregard 			}
11265dfd244aSDaniel Beauregard 		/*
11275dfd244aSDaniel Beauregard 		 * In N port 2 N port topology the FW provides a port
11285dfd244aSDaniel Beauregard 		 * database entry at loop_id 0x7fe which we use to
11295dfd244aSDaniel Beauregard 		 * acquire the Ports WWPN.
11305dfd244aSDaniel Beauregard 		 */
1131eb82ff87SDaniel Beauregard 		} else if ((mb[1] != 0x7fe) &&
11325dfd244aSDaniel Beauregard 		    ((FC_PORT_STATE_MASK(vha->state) != FC_STATE_OFFLINE ||
1133eb82ff87SDaniel Beauregard 		    (CFG_IST(ha, CFG_CTRL_24258081) &&
11345dfd244aSDaniel Beauregard 		    (mb[1] != 0xffff || mb[2] != 6 || mb[3] != 0))))) {
1135fcf3ce44SJohn Forte 			EL(ha, "%xh Port Database Update, Login/Logout "
1136fcf3ce44SJohn Forte 			    "received, mbx1=%xh, mbx2=%xh, mbx3=%xh\n",
1137fcf3ce44SJohn Forte 			    mb[0], mb[1], mb[2], mb[3]);
1138fcf3ce44SJohn Forte 		} else {
1139fcf3ce44SJohn Forte 			EL(ha, "%xh Port Database Update received, mbx1=%xh,"
1140fcf3ce44SJohn Forte 			    " mbx2=%xh, mbx3=%xh\n", mb[0], mb[1], mb[2],
1141fcf3ce44SJohn Forte 			    mb[3]);
1142fcf3ce44SJohn Forte 			*set_flags |= LOOP_RESYNC_NEEDED;
1143fcf3ce44SJohn Forte 			*set_flags &= ~LOOP_DOWN;
1144fcf3ce44SJohn Forte 			*reset_flags |= LOOP_DOWN;
1145fcf3ce44SJohn Forte 			*reset_flags &= ~LOOP_RESYNC_NEEDED;
1146fcf3ce44SJohn Forte 			vha->loop_down_timer = LOOP_DOWN_TIMER_OFF;
1147fcf3ce44SJohn Forte 			TASK_DAEMON_LOCK(ha);
1148fcf3ce44SJohn Forte 			vha->task_daemon_flags |= LOOP_RESYNC_NEEDED;
1149fcf3ce44SJohn Forte 			vha->task_daemon_flags &= ~LOOP_DOWN;
1150fcf3ce44SJohn Forte 			TASK_DAEMON_UNLOCK(ha);
1151fcf3ce44SJohn Forte 			ADAPTER_STATE_LOCK(ha);
115216dd44c2SDaniel Beauregard 			vha->flags &= ~ABORT_CMDS_LOOP_DOWN_TMO;
1153fcf3ce44SJohn Forte 			ADAPTER_STATE_UNLOCK(ha);
1154fcf3ce44SJohn Forte 		}
1155fcf3ce44SJohn Forte 
1156fcf3ce44SJohn Forte 		/* Update AEN queue. */
1157fcf3ce44SJohn Forte 		if (ha->xioctl->flags & QL_AEN_TRACKING_ENABLE) {
1158fcf3ce44SJohn Forte 			ql_enqueue_aen(ha, mb[0], NULL);
1159fcf3ce44SJohn Forte 		}
1160fcf3ce44SJohn Forte 		break;
1161fcf3ce44SJohn Forte 
1162fcf3ce44SJohn Forte 	case MBA_RSCN_UPDATE:
1163eb82ff87SDaniel Beauregard 		mb[1] = RD16_IO_REG(ha, mailbox_out[1]);
1164eb82ff87SDaniel Beauregard 		mb[2] = RD16_IO_REG(ha, mailbox_out[2]);
1165fcf3ce44SJohn Forte 		mb[3] = (uint16_t)(ha->flags & VP_ENABLED ?
1166eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[3]) : 0);
1167fcf3ce44SJohn Forte 
1168fcf3ce44SJohn Forte 		/* Locate port state structure. */
1169fcf3ce44SJohn Forte 		for (vha = ha; vha != NULL; vha = vha->vp_next) {
1170fcf3ce44SJohn Forte 			if (vha->vp_index == LSB(mb[3])) {
1171fcf3ce44SJohn Forte 				break;
1172fcf3ce44SJohn Forte 			}
1173fcf3ce44SJohn Forte 		}
1174fcf3ce44SJohn Forte 
1175fcf3ce44SJohn Forte 		if (vha == NULL) {
1176fcf3ce44SJohn Forte 			break;
1177fcf3ce44SJohn Forte 		}
1178fcf3ce44SJohn Forte 
1179fcf3ce44SJohn Forte 		if (LSB(mb[1]) == vha->d_id.b.domain &&
1180fcf3ce44SJohn Forte 		    MSB(mb[2]) == vha->d_id.b.area &&
1181fcf3ce44SJohn Forte 		    LSB(mb[2]) == vha->d_id.b.al_pa) {
1182fcf3ce44SJohn Forte 			EL(ha, "%xh RSCN match adapter, mbx1=%xh, mbx2=%xh, "
1183fcf3ce44SJohn Forte 			    "mbx3=%xh\n", mb[0], mb[1], mb[2], mb[3]);
1184fcf3ce44SJohn Forte 		} else {
1185fcf3ce44SJohn Forte 			EL(ha, "%xh RSCN received, mbx1=%xh, mbx2=%xh, "
1186fcf3ce44SJohn Forte 			    "mbx3=%xh\n", mb[0], mb[1], mb[2], mb[3]);
1187fcf3ce44SJohn Forte 			if (FC_PORT_STATE_MASK(vha->state) !=
1188fcf3ce44SJohn Forte 			    FC_STATE_OFFLINE) {
1189fcf3ce44SJohn Forte 				ql_rcv_rscn_els(vha, &mb[0], done_q);
1190fcf3ce44SJohn Forte 				TASK_DAEMON_LOCK(ha);
1191fcf3ce44SJohn Forte 				vha->task_daemon_flags |= RSCN_UPDATE_NEEDED;
1192fcf3ce44SJohn Forte 				TASK_DAEMON_UNLOCK(ha);
1193fcf3ce44SJohn Forte 				*set_flags |= RSCN_UPDATE_NEEDED;
1194fcf3ce44SJohn Forte 			}
1195fcf3ce44SJohn Forte 		}
1196fcf3ce44SJohn Forte 
1197fcf3ce44SJohn Forte 		/* Update AEN queue. */
1198fcf3ce44SJohn Forte 		if (ha->xioctl->flags & QL_AEN_TRACKING_ENABLE) {
1199fcf3ce44SJohn Forte 			ql_enqueue_aen(ha, mb[0], NULL);
1200fcf3ce44SJohn Forte 		}
1201fcf3ce44SJohn Forte 		break;
1202fcf3ce44SJohn Forte 
1203fcf3ce44SJohn Forte 	case MBA_LIP_ERROR:	/* Loop initialization errors. */
1204fcf3ce44SJohn Forte 		EL(ha, "%xh LIP error received, mbx1=%xh\n", mb[0],
1205eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[1]));
1206fcf3ce44SJohn Forte 		break;
1207fcf3ce44SJohn Forte 
1208fcf3ce44SJohn Forte 	case MBA_IP_RECEIVE:
1209fcf3ce44SJohn Forte 	case MBA_IP_BROADCAST:
1210eb82ff87SDaniel Beauregard 		mb[1] = RD16_IO_REG(ha, mailbox_out[1]);
1211eb82ff87SDaniel Beauregard 		mb[2] = RD16_IO_REG(ha, mailbox_out[2]);
1212eb82ff87SDaniel Beauregard 		mb[3] = RD16_IO_REG(ha, mailbox_out[3]);
1213fcf3ce44SJohn Forte 
1214fcf3ce44SJohn Forte 		EL(ha, "%xh IP packet/broadcast received, mbx1=%xh, "
1215fcf3ce44SJohn Forte 		    "mbx2=%xh, mbx3=%xh\n", mb[0], mb[1], mb[2], mb[3]);
1216fcf3ce44SJohn Forte 
1217fcf3ce44SJohn Forte 		/* Locate device queue. */
1218fcf3ce44SJohn Forte 		s_id.b.al_pa = LSB(mb[2]);
1219fcf3ce44SJohn Forte 		s_id.b.area = MSB(mb[2]);
1220fcf3ce44SJohn Forte 		s_id.b.domain = LSB(mb[1]);
1221fcf3ce44SJohn Forte 		if ((tq = ql_d_id_to_queue(ha, s_id)) == NULL) {
1222fcf3ce44SJohn Forte 			EL(ha, "Unknown IP device=%xh\n", s_id.b24);
1223fcf3ce44SJohn Forte 			break;
1224fcf3ce44SJohn Forte 		}
1225fcf3ce44SJohn Forte 
1226eb82ff87SDaniel Beauregard 		cnt = (uint16_t)(CFG_IST(ha, CFG_CTRL_24258081) ?
1227fcf3ce44SJohn Forte 		    CHAR_TO_SHORT(ha->ip_init_ctrl_blk.cb24.buf_size[0],
1228fcf3ce44SJohn Forte 		    ha->ip_init_ctrl_blk.cb24.buf_size[1]) :
1229fcf3ce44SJohn Forte 		    CHAR_TO_SHORT(ha->ip_init_ctrl_blk.cb.buf_size[0],
1230fcf3ce44SJohn Forte 		    ha->ip_init_ctrl_blk.cb.buf_size[1]));
1231fcf3ce44SJohn Forte 
1232fcf3ce44SJohn Forte 		tq->ub_sequence_length = mb[3];
1233fcf3ce44SJohn Forte 		tq->ub_total_seg_cnt = (uint8_t)(mb[3] / cnt);
1234fcf3ce44SJohn Forte 		if (mb[3] % cnt) {
1235fcf3ce44SJohn Forte 			tq->ub_total_seg_cnt++;
1236fcf3ce44SJohn Forte 		}
1237fcf3ce44SJohn Forte 		cnt = (uint16_t)(tq->ub_total_seg_cnt + 10);
1238fcf3ce44SJohn Forte 
1239fcf3ce44SJohn Forte 		for (index = 10; index < ha->reg_off->mbox_cnt && index < cnt;
1240fcf3ce44SJohn Forte 		    index++) {
1241eb82ff87SDaniel Beauregard 			mb[index] = RD16_IO_REG(ha, mailbox_out[index]);
1242fcf3ce44SJohn Forte 		}
1243fcf3ce44SJohn Forte 
1244fcf3ce44SJohn Forte 		tq->ub_seq_id = ++ha->ub_seq_id;
1245fcf3ce44SJohn Forte 		tq->ub_seq_cnt = 0;
1246fcf3ce44SJohn Forte 		tq->ub_frame_ro = 0;
1247fcf3ce44SJohn Forte 		tq->ub_loop_id = (uint16_t)(mb[0] == MBA_IP_BROADCAST ?
1248eb82ff87SDaniel Beauregard 		    (CFG_IST(ha, CFG_CTRL_24258081) ? BROADCAST_24XX_HDL :
1249fcf3ce44SJohn Forte 		    IP_BROADCAST_LOOP_ID) : tq->loop_id);
1250fcf3ce44SJohn Forte 		ha->rcv_dev_q = tq;
1251fcf3ce44SJohn Forte 
1252fcf3ce44SJohn Forte 		for (cnt = 10; cnt < ha->reg_off->mbox_cnt &&
1253fcf3ce44SJohn Forte 		    tq->ub_seq_cnt < tq->ub_total_seg_cnt; cnt++) {
1254fcf3ce44SJohn Forte 			if (ql_ub_frame_hdr(ha, tq, mb[cnt], done_q) !=
1255fcf3ce44SJohn Forte 			    QL_SUCCESS) {
1256fcf3ce44SJohn Forte 				EL(ha, "ql_ub_frame_hdr failed, "
1257fcf3ce44SJohn Forte 				    "isp_abort_needed\n");
1258fcf3ce44SJohn Forte 				*set_flags |= ISP_ABORT_NEEDED;
1259fcf3ce44SJohn Forte 				break;
1260fcf3ce44SJohn Forte 			}
1261fcf3ce44SJohn Forte 		}
1262fcf3ce44SJohn Forte 		break;
1263fcf3ce44SJohn Forte 
1264fcf3ce44SJohn Forte 	case MBA_IP_LOW_WATER_MARK:
1265fcf3ce44SJohn Forte 	case MBA_IP_RCV_BUFFER_EMPTY:
1266fcf3ce44SJohn Forte 		EL(ha, "%xh IP low water mark / RCV buffer empty received\n",
1267fcf3ce44SJohn Forte 		    mb[0]);
1268fcf3ce44SJohn Forte 		*set_flags |= NEED_UNSOLICITED_BUFFERS;
1269fcf3ce44SJohn Forte 		break;
1270fcf3ce44SJohn Forte 
1271fcf3ce44SJohn Forte 	case MBA_IP_HDR_DATA_SPLIT:
1272fcf3ce44SJohn Forte 		EL(ha, "%xh IP HDR data split received\n", mb[0]);
1273fcf3ce44SJohn Forte 		break;
1274fcf3ce44SJohn Forte 
12754f8b8adcSDaniel Beauregard 	case MBA_ERROR_LOGGING_DISABLED:
12764f8b8adcSDaniel Beauregard 		EL(ha, "%xh error logging disabled received, "
1277eb82ff87SDaniel Beauregard 		    "mbx1=%xh\n", mb[0], RD16_IO_REG(ha, mailbox_out[1]));
12784f8b8adcSDaniel Beauregard 		break;
12794f8b8adcSDaniel Beauregard 
1280fcf3ce44SJohn Forte 	case MBA_POINT_TO_POINT:
12815dfd244aSDaniel Beauregard 	/* case MBA_DCBX_COMPLETED: */
1282eb82ff87SDaniel Beauregard 		if (CFG_IST(ha, CFG_CTRL_8081)) {
12835dfd244aSDaniel Beauregard 			EL(ha, "%xh DCBX completed received\n", mb[0]);
12845dfd244aSDaniel Beauregard 		} else {
12855dfd244aSDaniel Beauregard 			EL(ha, "%xh Point to Point Mode received\n", mb[0]);
12865dfd244aSDaniel Beauregard 		}
1287fcf3ce44SJohn Forte 		ADAPTER_STATE_LOCK(ha);
1288fcf3ce44SJohn Forte 		ha->flags |= POINT_TO_POINT;
1289fcf3ce44SJohn Forte 		ADAPTER_STATE_UNLOCK(ha);
12905dfd244aSDaniel Beauregard 		break;
1291fcf3ce44SJohn Forte 
12925dfd244aSDaniel Beauregard 	case MBA_FCF_CONFIG_ERROR:
12934f8b8adcSDaniel Beauregard 		EL(ha, "%xh FCF configuration Error received, mbx1=%xh\n",
1294eb82ff87SDaniel Beauregard 		    mb[0], RD16_IO_REG(ha, mailbox_out[1]));
12955dfd244aSDaniel Beauregard 		break;
1296fcf3ce44SJohn Forte 
12974f8b8adcSDaniel Beauregard 	case MBA_DCBX_PARAM_CHANGED:
12984f8b8adcSDaniel Beauregard 		EL(ha, "%xh DCBX parameters changed received, mbx1=%xh\n",
1299eb82ff87SDaniel Beauregard 		    mb[0], RD16_IO_REG(ha, mailbox_out[1]));
1300fcf3ce44SJohn Forte 		break;
1301fcf3ce44SJohn Forte 
1302fcf3ce44SJohn Forte 	case MBA_CHG_IN_CONNECTION:
1303eb82ff87SDaniel Beauregard 		mb[1] = RD16_IO_REG(ha, mailbox_out[1]);
1304fcf3ce44SJohn Forte 		if (mb[1] == 2) {
1305fcf3ce44SJohn Forte 			EL(ha, "%xh Change In Connection received, "
1306fcf3ce44SJohn Forte 			    "mbx1=%xh\n",  mb[0], mb[1]);
1307fcf3ce44SJohn Forte 			ADAPTER_STATE_LOCK(ha);
1308fcf3ce44SJohn Forte 			ha->flags &= ~POINT_TO_POINT;
1309fcf3ce44SJohn Forte 			ADAPTER_STATE_UNLOCK(ha);
1310fcf3ce44SJohn Forte 			if (ha->topology & QL_N_PORT) {
1311fcf3ce44SJohn Forte 				ha->topology = (uint8_t)(ha->topology &
1312fcf3ce44SJohn Forte 				    ~QL_N_PORT);
1313fcf3ce44SJohn Forte 				ha->topology = (uint8_t)(ha->topology |
1314fcf3ce44SJohn Forte 				    QL_NL_PORT);
1315fcf3ce44SJohn Forte 			}
1316fcf3ce44SJohn Forte 		} else {
1317fcf3ce44SJohn Forte 			EL(ha, "%xh Change In Connection received, "
1318fcf3ce44SJohn Forte 			    "mbx1=%xh, isp_abort_needed\n", mb[0], mb[1]);
1319fcf3ce44SJohn Forte 			*set_flags |= ISP_ABORT_NEEDED;
1320fcf3ce44SJohn Forte 		}
1321fcf3ce44SJohn Forte 		break;
1322fcf3ce44SJohn Forte 
1323fcf3ce44SJohn Forte 	case MBA_ZIO_UPDATE:
1324fcf3ce44SJohn Forte 		EL(ha, "%xh ZIO response received\n", mb[0]);
1325fcf3ce44SJohn Forte 
1326fcf3ce44SJohn Forte 		ha->isp_rsp_index = RD16_IO_REG(ha, resp_in);
1327fcf3ce44SJohn Forte 		ql_response_pkt(ha, done_q, set_flags, reset_flags, intr_clr);
1328fcf3ce44SJohn Forte 		intr = B_FALSE;
1329fcf3ce44SJohn Forte 		break;
1330fcf3ce44SJohn Forte 
1331fcf3ce44SJohn Forte 	case MBA_PORT_BYPASS_CHANGED:
1332fcf3ce44SJohn Forte 		EL(ha, "%xh Port Bypass Changed received, mbx1=%xh\n",
1333eb82ff87SDaniel Beauregard 		    mb[0], RD16_IO_REG(ha, mailbox_out[1]));
1334fcf3ce44SJohn Forte 		/*
1335fcf3ce44SJohn Forte 		 * Event generated when there is a transition on
1336fcf3ce44SJohn Forte 		 * port bypass of crystal+.
1337fcf3ce44SJohn Forte 		 * Mailbox 1:	Bit 0 - External.
1338fcf3ce44SJohn Forte 		 *		Bit 2 - Internal.
1339fcf3ce44SJohn Forte 		 * When the bit is 0, the port is bypassed.
1340fcf3ce44SJohn Forte 		 *
1341fcf3ce44SJohn Forte 		 * For now we will generate a LIP for all cases.
1342fcf3ce44SJohn Forte 		 */
1343fcf3ce44SJohn Forte 		*set_flags |= HANDLE_PORT_BYPASS_CHANGE;
1344fcf3ce44SJohn Forte 		break;
1345fcf3ce44SJohn Forte 
1346fcf3ce44SJohn Forte 	case MBA_RECEIVE_ERROR:
1347fcf3ce44SJohn Forte 		EL(ha, "%xh Receive Error received, mbx1=%xh, mbx2=%xh\n",
1348eb82ff87SDaniel Beauregard 		    mb[0], RD16_IO_REG(ha, mailbox_out[1]),
1349eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[2]));
1350fcf3ce44SJohn Forte 		break;
1351fcf3ce44SJohn Forte 
1352fcf3ce44SJohn Forte 	case MBA_LS_RJT_SENT:
1353fcf3ce44SJohn Forte 		EL(ha, "%xh LS_RJT Response Sent ELS=%xh\n", mb[0],
1354eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[1]));
1355fcf3ce44SJohn Forte 		break;
1356fcf3ce44SJohn Forte 
1357fcf3ce44SJohn Forte 	case MBA_FW_RESTART_COMP:
1358fcf3ce44SJohn Forte 		EL(ha, "%xh firmware restart complete received mb1=%xh\n",
1359eb82ff87SDaniel Beauregard 		    mb[0], RD16_IO_REG(ha, mailbox_out[1]));
1360fcf3ce44SJohn Forte 		break;
1361fcf3ce44SJohn Forte 
1362*f885d00fSDaniel Beauregard 	/*
1363*f885d00fSDaniel Beauregard 	 * MBA_IDC_COMPLETE &  MBA_IDC_NOTIFICATION: We won't get another
1364*f885d00fSDaniel Beauregard 	 * IDC async event until we ACK the current one.
1365*f885d00fSDaniel Beauregard 	 */
13665dfd244aSDaniel Beauregard 	case MBA_IDC_COMPLETE:
1367*f885d00fSDaniel Beauregard 		ha->idc_mb[0] = mb[0];
1368*f885d00fSDaniel Beauregard 		ha->idc_mb[1] = RD16_IO_REG(ha, mailbox_out[1]);
1369*f885d00fSDaniel Beauregard 		ha->idc_mb[2] = RD16_IO_REG(ha, mailbox_out[2]);
1370*f885d00fSDaniel Beauregard 		ha->idc_mb[3] = RD16_IO_REG(ha, mailbox_out[3]);
1371*f885d00fSDaniel Beauregard 		ha->idc_mb[4] = RD16_IO_REG(ha, mailbox_out[4]);
1372*f885d00fSDaniel Beauregard 		ha->idc_mb[5] = RD16_IO_REG(ha, mailbox_out[5]);
1373*f885d00fSDaniel Beauregard 		ha->idc_mb[6] = RD16_IO_REG(ha, mailbox_out[6]);
1374*f885d00fSDaniel Beauregard 		ha->idc_mb[7] = RD16_IO_REG(ha, mailbox_out[7]);
13755dfd244aSDaniel Beauregard 		EL(ha, "%xh Inter-driver communication complete received, "
1376eb82ff87SDaniel Beauregard 		    " mbx1=%xh, mbx2=%xh, mbx3=%xh, mbx4=%xh, mbx5=%xh,"
1377*f885d00fSDaniel Beauregard 		    " mbx6=%xh, mbx7=%xh\n", mb[0], ha->idc_mb[1],
1378*f885d00fSDaniel Beauregard 		    ha->idc_mb[2], ha->idc_mb[3], ha->idc_mb[4], ha->idc_mb[5],
1379*f885d00fSDaniel Beauregard 		    ha->idc_mb[6], ha->idc_mb[7]);
1380*f885d00fSDaniel Beauregard 		*set_flags |= IDC_EVENT;
13815dfd244aSDaniel Beauregard 		break;
13825dfd244aSDaniel Beauregard 
13835dfd244aSDaniel Beauregard 	case MBA_IDC_NOTIFICATION:
1384*f885d00fSDaniel Beauregard 		ha->idc_mb[0] = mb[0];
1385eb82ff87SDaniel Beauregard 		ha->idc_mb[1] = RD16_IO_REG(ha, mailbox_out[1]);
1386eb82ff87SDaniel Beauregard 		ha->idc_mb[2] = RD16_IO_REG(ha, mailbox_out[2]);
1387eb82ff87SDaniel Beauregard 		ha->idc_mb[3] = RD16_IO_REG(ha, mailbox_out[3]);
1388eb82ff87SDaniel Beauregard 		ha->idc_mb[4] = RD16_IO_REG(ha, mailbox_out[4]);
1389eb82ff87SDaniel Beauregard 		ha->idc_mb[5] = RD16_IO_REG(ha, mailbox_out[5]);
1390eb82ff87SDaniel Beauregard 		ha->idc_mb[6] = RD16_IO_REG(ha, mailbox_out[6]);
1391eb82ff87SDaniel Beauregard 		ha->idc_mb[7] = RD16_IO_REG(ha, mailbox_out[7]);
13925dfd244aSDaniel Beauregard 		EL(ha, "%xh Inter-driver communication request notification "
13935dfd244aSDaniel Beauregard 		    "received, mbx1=%xh, mbx2=%xh, mbx3=%xh, mbx4=%xh, "
13945dfd244aSDaniel Beauregard 		    "mbx5=%xh, mbx6=%xh, mbx7=%xh\n", mb[0], ha->idc_mb[1],
13955dfd244aSDaniel Beauregard 		    ha->idc_mb[2], ha->idc_mb[3], ha->idc_mb[4], ha->idc_mb[5],
13965dfd244aSDaniel Beauregard 		    ha->idc_mb[6], ha->idc_mb[7]);
1397*f885d00fSDaniel Beauregard 		*set_flags |= IDC_EVENT;
13985dfd244aSDaniel Beauregard 		break;
13995dfd244aSDaniel Beauregard 
14005dfd244aSDaniel Beauregard 	case MBA_IDC_TIME_EXTENDED:
14015dfd244aSDaniel Beauregard 		EL(ha, "%xh Inter-driver communication time extended received,"
14025dfd244aSDaniel Beauregard 		    " mbx1=%xh, mbx2=%xh\n", mb[0],
1403eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[1]),
1404eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[2]));
14055dfd244aSDaniel Beauregard 		break;
14065dfd244aSDaniel Beauregard 
1407fcf3ce44SJohn Forte 	default:
1408fcf3ce44SJohn Forte 		EL(ha, "%xh UNKNOWN event received, mbx1=%xh, mbx2=%xh, "
1409eb82ff87SDaniel Beauregard 		    "mbx3=%xh\n", mb[0], RD16_IO_REG(ha, mailbox_out[1]),
1410eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[2]),
1411eb82ff87SDaniel Beauregard 		    RD16_IO_REG(ha, mailbox_out[3]));
1412fcf3ce44SJohn Forte 		break;
1413fcf3ce44SJohn Forte 	}
1414fcf3ce44SJohn Forte 
1415fcf3ce44SJohn Forte 	/* Clear RISC interrupt */
1416fcf3ce44SJohn Forte 	if (intr && intr_clr) {
1417eb82ff87SDaniel Beauregard 		if (CFG_IST(ha, CFG_CTRL_8021)) {
1418eb82ff87SDaniel Beauregard 			ql_8021_clr_fw_intr(ha);
1419eb82ff87SDaniel Beauregard 		} else if (CFG_IST(ha, CFG_CTRL_242581)) {
1420eb82ff87SDaniel Beauregard 			WRT32_IO_REG(ha, hccr, HC24_CLR_RISC_INT);
1421eb82ff87SDaniel Beauregard 		} else {
1422eb82ff87SDaniel Beauregard 			WRT16_IO_REG(ha, hccr, HC_CLR_RISC_INT);
1423eb82ff87SDaniel Beauregard 		}
1424fcf3ce44SJohn Forte 	}
1425fcf3ce44SJohn Forte 
1426fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
1427fcf3ce44SJohn Forte }
1428fcf3ce44SJohn Forte 
1429fcf3ce44SJohn Forte /*
1430fcf3ce44SJohn Forte  * ql_fast_fcp_post
1431fcf3ce44SJohn Forte  *	Fast path for good SCSI I/O completion.
1432fcf3ce44SJohn Forte  *
1433fcf3ce44SJohn Forte  * Input:
1434fcf3ce44SJohn Forte  *	sp:	SRB pointer.
1435fcf3ce44SJohn Forte  *
1436fcf3ce44SJohn Forte  * Context:
1437fcf3ce44SJohn Forte  *	Interrupt or Kernel context, no mailbox commands allowed.
1438fcf3ce44SJohn Forte  */
1439fcf3ce44SJohn Forte static void
1440fcf3ce44SJohn Forte ql_fast_fcp_post(ql_srb_t *sp)
1441fcf3ce44SJohn Forte {
1442fcf3ce44SJohn Forte 	ql_adapter_state_t	*ha = sp->ha;
1443fcf3ce44SJohn Forte 	ql_lun_t		*lq = sp->lun_queue;
1444fcf3ce44SJohn Forte 	ql_tgt_t		*tq = lq->target_queue;
1445fcf3ce44SJohn Forte 
1446fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
1447fcf3ce44SJohn Forte 
1448fcf3ce44SJohn Forte 	/* Acquire device queue lock. */
1449fcf3ce44SJohn Forte 	DEVICE_QUEUE_LOCK(tq);
1450fcf3ce44SJohn Forte 
1451fcf3ce44SJohn Forte 	/* Decrement outstanding commands on device. */
1452fcf3ce44SJohn Forte 	if (tq->outcnt != 0) {
1453fcf3ce44SJohn Forte 		tq->outcnt--;
1454fcf3ce44SJohn Forte 	}
1455fcf3ce44SJohn Forte 
1456fcf3ce44SJohn Forte 	if (sp->flags & SRB_FCP_CMD_PKT) {
1457fcf3ce44SJohn Forte 		if (sp->fcp->fcp_cntl.cntl_qtype == FCP_QTYPE_UNTAGGED) {
1458fcf3ce44SJohn Forte 			/*
1459fcf3ce44SJohn Forte 			 * Clear the flag for this LUN so that
1460fcf3ce44SJohn Forte 			 * untagged commands can be submitted
1461fcf3ce44SJohn Forte 			 * for it.
1462fcf3ce44SJohn Forte 			 */
1463fcf3ce44SJohn Forte 			lq->flags &= ~LQF_UNTAGGED_PENDING;
1464fcf3ce44SJohn Forte 		}
1465fcf3ce44SJohn Forte 
1466fcf3ce44SJohn Forte 		if (lq->lun_outcnt != 0) {
1467fcf3ce44SJohn Forte 			lq->lun_outcnt--;
1468fcf3ce44SJohn Forte 		}
1469fcf3ce44SJohn Forte 	}
1470fcf3ce44SJohn Forte 
1471fcf3ce44SJohn Forte 	/* Reset port down retry count on good completion. */
1472fcf3ce44SJohn Forte 	tq->port_down_retry_count = ha->port_down_retry_count;
1473fcf3ce44SJohn Forte 	tq->qfull_retry_count = ha->qfull_retry_count;
1474*f885d00fSDaniel Beauregard 	ha->pha->timeout_cnt = 0;
1475fcf3ce44SJohn Forte 
1476fcf3ce44SJohn Forte 	/* Remove command from watchdog queue. */
1477fcf3ce44SJohn Forte 	if (sp->flags & SRB_WATCHDOG_ENABLED) {
1478fcf3ce44SJohn Forte 		ql_remove_link(&tq->wdg, &sp->wdg);
1479fcf3ce44SJohn Forte 		sp->flags &= ~SRB_WATCHDOG_ENABLED;
1480fcf3ce44SJohn Forte 	}
1481fcf3ce44SJohn Forte 
1482fcf3ce44SJohn Forte 	if (lq->cmd.first != NULL) {
1483fcf3ce44SJohn Forte 		ql_next(ha, lq);
1484fcf3ce44SJohn Forte 	} else {
1485fcf3ce44SJohn Forte 		/* Release LU queue specific lock. */
1486fcf3ce44SJohn Forte 		DEVICE_QUEUE_UNLOCK(tq);
1487fcf3ce44SJohn Forte 		if (ha->pha->pending_cmds.first != NULL) {
1488fcf3ce44SJohn Forte 			ql_start_iocb(ha, NULL);
1489fcf3ce44SJohn Forte 		}
1490fcf3ce44SJohn Forte 	}
1491fcf3ce44SJohn Forte 
1492fcf3ce44SJohn Forte 	/* Sync buffers if required.  */
1493fcf3ce44SJohn Forte 	if (sp->flags & SRB_MS_PKT) {
1494fcf3ce44SJohn Forte 		(void) ddi_dma_sync(sp->pkt->pkt_resp_dma, 0, 0,
1495fcf3ce44SJohn Forte 		    DDI_DMA_SYNC_FORCPU);
1496fcf3ce44SJohn Forte 	}
1497fcf3ce44SJohn Forte 
1498fcf3ce44SJohn Forte 	/* Map ISP completion codes. */
1499fcf3ce44SJohn Forte 	sp->pkt->pkt_expln = FC_EXPLN_NONE;
1500fcf3ce44SJohn Forte 	sp->pkt->pkt_action = FC_ACTION_RETRYABLE;
1501fcf3ce44SJohn Forte 	sp->pkt->pkt_state = FC_PKT_SUCCESS;
1502fcf3ce44SJohn Forte 
1503fcf3ce44SJohn Forte 	/* Now call the pkt completion callback */
1504fcf3ce44SJohn Forte 	if (sp->flags & SRB_POLL) {
1505fcf3ce44SJohn Forte 		sp->flags &= ~SRB_POLL;
1506fcf3ce44SJohn Forte 	} else if (sp->pkt->pkt_comp) {
1507fcf3ce44SJohn Forte 		INTR_UNLOCK(ha);
1508fcf3ce44SJohn Forte 		(*sp->pkt->pkt_comp)(sp->pkt);
1509fcf3ce44SJohn Forte 		INTR_LOCK(ha);
1510fcf3ce44SJohn Forte 	}
1511fcf3ce44SJohn Forte 
1512fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
1513fcf3ce44SJohn Forte }
1514fcf3ce44SJohn Forte 
1515fcf3ce44SJohn Forte /*
1516fcf3ce44SJohn Forte  * ql_response_pkt
1517fcf3ce44SJohn Forte  *	Processes response entry.
1518fcf3ce44SJohn Forte  *
1519fcf3ce44SJohn Forte  * Input:
1520fcf3ce44SJohn Forte  *	ha:		adapter state pointer.
1521fcf3ce44SJohn Forte  *	done_q:		head pointer to done queue.
1522fcf3ce44SJohn Forte  *	set_flags:	task daemon flags to set.
1523fcf3ce44SJohn Forte  *	reset_flags:	task daemon flags to reset.
1524fcf3ce44SJohn Forte  *	intr_clr:	early interrupt clear
1525fcf3ce44SJohn Forte  *
1526fcf3ce44SJohn Forte  * Context:
1527fcf3ce44SJohn Forte  *	Interrupt or Kernel context, no mailbox commands allowed.
1528fcf3ce44SJohn Forte  */
1529fcf3ce44SJohn Forte static void
1530fcf3ce44SJohn Forte ql_response_pkt(ql_adapter_state_t *ha, ql_head_t *done_q, uint32_t *set_flags,
1531fcf3ce44SJohn Forte     uint32_t *reset_flags, int intr_clr)
1532fcf3ce44SJohn Forte {
1533fcf3ce44SJohn Forte 	response_t	*pkt;
1534fcf3ce44SJohn Forte 	uint32_t	dma_sync_size_1 = 0;
1535fcf3ce44SJohn Forte 	uint32_t	dma_sync_size_2 = 0;
1536fcf3ce44SJohn Forte 	int		status = 0;
1537fcf3ce44SJohn Forte 
1538fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
1539fcf3ce44SJohn Forte 
1540fcf3ce44SJohn Forte 	/* Clear RISC interrupt */
1541fcf3ce44SJohn Forte 	if (intr_clr) {
1542eb82ff87SDaniel Beauregard 		if (CFG_IST(ha, CFG_CTRL_8021)) {
1543eb82ff87SDaniel Beauregard 			ql_8021_clr_fw_intr(ha);
1544eb82ff87SDaniel Beauregard 		} else if (CFG_IST(ha, CFG_CTRL_242581)) {
1545eb82ff87SDaniel Beauregard 			WRT32_IO_REG(ha, hccr, HC24_CLR_RISC_INT);
1546eb82ff87SDaniel Beauregard 		} else {
1547eb82ff87SDaniel Beauregard 			WRT16_IO_REG(ha, hccr, HC_CLR_RISC_INT);
1548eb82ff87SDaniel Beauregard 		}
1549fcf3ce44SJohn Forte 	}
1550fcf3ce44SJohn Forte 
1551fcf3ce44SJohn Forte 	if (ha->isp_rsp_index >= RESPONSE_ENTRY_CNT) {
1552fcf3ce44SJohn Forte 		EL(ha, "index error = %xh, isp_abort_needed",
1553fcf3ce44SJohn Forte 		    ha->isp_rsp_index);
1554fcf3ce44SJohn Forte 		*set_flags |= ISP_ABORT_NEEDED;
1555fcf3ce44SJohn Forte 		return;
1556fcf3ce44SJohn Forte 	}
1557fcf3ce44SJohn Forte 
1558fcf3ce44SJohn Forte 	if ((ha->flags & ONLINE) == 0) {
1559fcf3ce44SJohn Forte 		QL_PRINT_3(CE_CONT, "(%d): not onlne, done\n", ha->instance);
1560fcf3ce44SJohn Forte 		return;
1561fcf3ce44SJohn Forte 	}
1562fcf3ce44SJohn Forte 
1563fcf3ce44SJohn Forte 	/* Calculate size of response queue entries to sync. */
1564fcf3ce44SJohn Forte 	if (ha->isp_rsp_index > ha->rsp_ring_index) {
1565fcf3ce44SJohn Forte 		dma_sync_size_1 = (uint32_t)
1566fcf3ce44SJohn Forte 		    ((uint32_t)(ha->isp_rsp_index - ha->rsp_ring_index) *
1567fcf3ce44SJohn Forte 		    RESPONSE_ENTRY_SIZE);
1568fcf3ce44SJohn Forte 	} else if (ha->isp_rsp_index == 0) {
1569fcf3ce44SJohn Forte 		dma_sync_size_1 = (uint32_t)
1570fcf3ce44SJohn Forte 		    ((uint32_t)(RESPONSE_ENTRY_CNT - ha->rsp_ring_index) *
1571fcf3ce44SJohn Forte 		    RESPONSE_ENTRY_SIZE);
1572fcf3ce44SJohn Forte 	} else {
1573fcf3ce44SJohn Forte 		/* Responses wrap around the Q */
1574fcf3ce44SJohn Forte 		dma_sync_size_1 = (uint32_t)
1575fcf3ce44SJohn Forte 		    ((uint32_t)(RESPONSE_ENTRY_CNT - ha->rsp_ring_index) *
1576fcf3ce44SJohn Forte 		    RESPONSE_ENTRY_SIZE);
1577fcf3ce44SJohn Forte 		dma_sync_size_2 = (uint32_t)
1578fcf3ce44SJohn Forte 		    (ha->isp_rsp_index * RESPONSE_ENTRY_SIZE);
1579fcf3ce44SJohn Forte 	}
1580fcf3ce44SJohn Forte 
1581fcf3ce44SJohn Forte 	/* Sync DMA buffer. */
1582fcf3ce44SJohn Forte 	(void) ddi_dma_sync(ha->hba_buf.dma_handle,
1583fcf3ce44SJohn Forte 	    (off_t)(ha->rsp_ring_index * RESPONSE_ENTRY_SIZE +
1584fcf3ce44SJohn Forte 	    RESPONSE_Q_BUFFER_OFFSET), dma_sync_size_1,
1585fcf3ce44SJohn Forte 	    DDI_DMA_SYNC_FORKERNEL);
1586fcf3ce44SJohn Forte 	if (dma_sync_size_2) {
1587fcf3ce44SJohn Forte 		(void) ddi_dma_sync(ha->hba_buf.dma_handle,
1588fcf3ce44SJohn Forte 		    RESPONSE_Q_BUFFER_OFFSET, dma_sync_size_2,
1589fcf3ce44SJohn Forte 		    DDI_DMA_SYNC_FORKERNEL);
1590fcf3ce44SJohn Forte 	}
1591fcf3ce44SJohn Forte 
1592fcf3ce44SJohn Forte 	while (ha->rsp_ring_index != ha->isp_rsp_index) {
1593fcf3ce44SJohn Forte 		pkt = ha->response_ring_ptr;
1594fcf3ce44SJohn Forte 
1595fcf3ce44SJohn Forte 		QL_PRINT_5(CE_CONT, "(%d): ha->rsp_rg_idx=%xh, mbx[5]=%xh\n",
1596fcf3ce44SJohn Forte 		    ha->instance, ha->rsp_ring_index, ha->isp_rsp_index);
1597fcf3ce44SJohn Forte 		QL_DUMP_5((uint8_t *)ha->response_ring_ptr, 8,
1598fcf3ce44SJohn Forte 		    RESPONSE_ENTRY_SIZE);
1599fcf3ce44SJohn Forte 
1600fcf3ce44SJohn Forte 		/* Adjust ring index. */
1601fcf3ce44SJohn Forte 		ha->rsp_ring_index++;
1602fcf3ce44SJohn Forte 		if (ha->rsp_ring_index == RESPONSE_ENTRY_CNT) {
1603fcf3ce44SJohn Forte 			ha->rsp_ring_index = 0;
1604fcf3ce44SJohn Forte 			ha->response_ring_ptr = ha->response_ring_bp;
1605fcf3ce44SJohn Forte 		} else {
1606fcf3ce44SJohn Forte 			ha->response_ring_ptr++;
1607fcf3ce44SJohn Forte 		}
1608fcf3ce44SJohn Forte 
1609fcf3ce44SJohn Forte 		/* Process packet. */
1610fcf3ce44SJohn Forte 		if (ha->status_srb != NULL && pkt->entry_type !=
1611fcf3ce44SJohn Forte 		    STATUS_CONT_TYPE) {
1612fcf3ce44SJohn Forte 			ql_add_link_b(done_q, &ha->status_srb->cmd);
1613fcf3ce44SJohn Forte 			ha->status_srb = NULL;
1614fcf3ce44SJohn Forte 		}
1615fcf3ce44SJohn Forte 
1616eb82ff87SDaniel Beauregard 		pkt->entry_status = (uint8_t)(CFG_IST(ha, CFG_CTRL_24258081) ?
1617fcf3ce44SJohn Forte 		    pkt->entry_status & 0x3c : pkt->entry_status & 0x7e);
1618fcf3ce44SJohn Forte 
1619fcf3ce44SJohn Forte 		if (pkt->entry_status != 0) {
1620fcf3ce44SJohn Forte 			ql_error_entry(ha, pkt, done_q, set_flags,
1621fcf3ce44SJohn Forte 			    reset_flags);
1622fcf3ce44SJohn Forte 		} else {
1623fcf3ce44SJohn Forte 			switch (pkt->entry_type) {
1624fcf3ce44SJohn Forte 			case STATUS_TYPE:
1625eb82ff87SDaniel Beauregard 				status |= CFG_IST(ha, CFG_CTRL_24258081) ?
1626fcf3ce44SJohn Forte 				    ql_24xx_status_entry(ha,
1627fcf3ce44SJohn Forte 				    (sts_24xx_entry_t *)pkt, done_q, set_flags,
1628fcf3ce44SJohn Forte 				    reset_flags) :
1629fcf3ce44SJohn Forte 				    ql_status_entry(ha, (sts_entry_t *)pkt,
1630fcf3ce44SJohn Forte 				    done_q, set_flags, reset_flags);
1631fcf3ce44SJohn Forte 				break;
1632fcf3ce44SJohn Forte 			case STATUS_CONT_TYPE:
1633fcf3ce44SJohn Forte 				ql_status_cont_entry(ha,
1634fcf3ce44SJohn Forte 				    (sts_cont_entry_t *)pkt, done_q, set_flags,
1635fcf3ce44SJohn Forte 				    reset_flags);
1636fcf3ce44SJohn Forte 				break;
1637fcf3ce44SJohn Forte 			case IP_TYPE:
1638fcf3ce44SJohn Forte 			case IP_A64_TYPE:
1639fcf3ce44SJohn Forte 			case IP_CMD_TYPE:
1640fcf3ce44SJohn Forte 				ql_ip_entry(ha, (ip_entry_t *)pkt, done_q,
1641fcf3ce44SJohn Forte 				    set_flags, reset_flags);
1642fcf3ce44SJohn Forte 				break;
1643fcf3ce44SJohn Forte 			case IP_RECEIVE_TYPE:
1644fcf3ce44SJohn Forte 				ql_ip_rcv_entry(ha,
1645fcf3ce44SJohn Forte 				    (ip_rcv_entry_t *)pkt, done_q, set_flags,
1646fcf3ce44SJohn Forte 				    reset_flags);
1647fcf3ce44SJohn Forte 				break;
1648fcf3ce44SJohn Forte 			case IP_RECEIVE_CONT_TYPE:
1649fcf3ce44SJohn Forte 				ql_ip_rcv_cont_entry(ha,
1650fcf3ce44SJohn Forte 				    (ip_rcv_cont_entry_t *)pkt,	done_q,
1651fcf3ce44SJohn Forte 				    set_flags, reset_flags);
1652fcf3ce44SJohn Forte 				break;
1653fcf3ce44SJohn Forte 			case IP_24XX_RECEIVE_TYPE:
1654fcf3ce44SJohn Forte 				ql_ip_24xx_rcv_entry(ha,
1655fcf3ce44SJohn Forte 				    (ip_rcv_24xx_entry_t *)pkt, done_q,
1656fcf3ce44SJohn Forte 				    set_flags, reset_flags);
1657fcf3ce44SJohn Forte 				break;
1658fcf3ce44SJohn Forte 			case MS_TYPE:
1659fcf3ce44SJohn Forte 				ql_ms_entry(ha, (ms_entry_t *)pkt, done_q,
1660fcf3ce44SJohn Forte 				    set_flags, reset_flags);
1661fcf3ce44SJohn Forte 				break;
1662fcf3ce44SJohn Forte 			case REPORT_ID_TYPE:
1663fcf3ce44SJohn Forte 				ql_report_id_entry(ha, (report_id_1_t *)pkt,
1664fcf3ce44SJohn Forte 				    done_q, set_flags, reset_flags);
1665fcf3ce44SJohn Forte 				break;
16665dfd244aSDaniel Beauregard 			case ELS_PASSTHRU_TYPE:
16675dfd244aSDaniel Beauregard 				ql_els_passthru_entry(ha,
16685dfd244aSDaniel Beauregard 				    (els_passthru_entry_rsp_t *)pkt,
16695dfd244aSDaniel Beauregard 				    done_q, set_flags, reset_flags);
16705dfd244aSDaniel Beauregard 				break;
1671fcf3ce44SJohn Forte 			case IP_BUF_POOL_TYPE:
1672fcf3ce44SJohn Forte 			case MARKER_TYPE:
1673fcf3ce44SJohn Forte 			case VP_MODIFY_TYPE:
1674fcf3ce44SJohn Forte 			case VP_CONTROL_TYPE:
1675fcf3ce44SJohn Forte 				break;
1676fcf3ce44SJohn Forte 			default:
1677fcf3ce44SJohn Forte 				EL(ha, "Unknown IOCB entry type=%xh\n",
1678fcf3ce44SJohn Forte 				    pkt->entry_type);
1679fcf3ce44SJohn Forte 				break;
1680fcf3ce44SJohn Forte 			}
1681fcf3ce44SJohn Forte 		}
1682fcf3ce44SJohn Forte 	}
1683fcf3ce44SJohn Forte 
1684fcf3ce44SJohn Forte 	/* Inform RISC of processed responses. */
1685fcf3ce44SJohn Forte 	WRT16_IO_REG(ha, resp_out, ha->rsp_ring_index);
1686fcf3ce44SJohn Forte 
1687fcf3ce44SJohn Forte 	/* RESET packet received delay for possible async event. */
1688fcf3ce44SJohn Forte 	if (status & BIT_0) {
1689fcf3ce44SJohn Forte 		drv_usecwait(500000);
1690fcf3ce44SJohn Forte 	}
1691fcf3ce44SJohn Forte 
1692fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
1693fcf3ce44SJohn Forte }
1694fcf3ce44SJohn Forte 
1695fcf3ce44SJohn Forte /*
1696fcf3ce44SJohn Forte  * ql_error_entry
1697fcf3ce44SJohn Forte  *	Processes error entry.
1698fcf3ce44SJohn Forte  *
1699fcf3ce44SJohn Forte  * Input:
1700fcf3ce44SJohn Forte  *	ha = adapter state pointer.
1701fcf3ce44SJohn Forte  *	pkt = entry pointer.
1702fcf3ce44SJohn Forte  *	done_q = head pointer to done queue.
1703fcf3ce44SJohn Forte  *	set_flags = task daemon flags to set.
1704fcf3ce44SJohn Forte  *	reset_flags = task daemon flags to reset.
1705fcf3ce44SJohn Forte  *
1706fcf3ce44SJohn Forte  * Context:
1707fcf3ce44SJohn Forte  *	Interrupt or Kernel context, no mailbox commands allowed.
1708fcf3ce44SJohn Forte  */
1709fcf3ce44SJohn Forte /* ARGSUSED */
1710fcf3ce44SJohn Forte static void
1711fcf3ce44SJohn Forte ql_error_entry(ql_adapter_state_t *ha, response_t *pkt, ql_head_t *done_q,
1712fcf3ce44SJohn Forte     uint32_t *set_flags, uint32_t *reset_flags)
1713fcf3ce44SJohn Forte {
1714fcf3ce44SJohn Forte 	ql_srb_t	*sp;
1715a2b3ff35SDaniel Beauregard 	uint32_t	index, resp_identifier;
1716fcf3ce44SJohn Forte 
1717fcf3ce44SJohn Forte 	if (pkt->entry_type == INVALID_ENTRY_TYPE) {
1718fcf3ce44SJohn Forte 		EL(ha, "Aborted command\n");
1719fcf3ce44SJohn Forte 		return;
1720fcf3ce44SJohn Forte 	}
1721fcf3ce44SJohn Forte 
1722fcf3ce44SJohn Forte 	QL_PRINT_2(CE_CONT, "(%d): started, packet:\n", ha->instance);
1723fcf3ce44SJohn Forte 	QL_DUMP_2((uint8_t *)pkt, 8, RESPONSE_ENTRY_SIZE);
1724fcf3ce44SJohn Forte 
1725fcf3ce44SJohn Forte 	if (pkt->entry_status & BIT_6) {
1726fcf3ce44SJohn Forte 		EL(ha, "Request Queue DMA error\n");
1727fcf3ce44SJohn Forte 	} else if (pkt->entry_status & BIT_5) {
1728fcf3ce44SJohn Forte 		EL(ha, "Invalid Entry Order\n");
1729fcf3ce44SJohn Forte 	} else if (pkt->entry_status & BIT_4) {
1730fcf3ce44SJohn Forte 		EL(ha, "Invalid Entry Count\n");
1731fcf3ce44SJohn Forte 	} else if (pkt->entry_status & BIT_3) {
1732fcf3ce44SJohn Forte 		EL(ha, "Invalid Entry Parameter\n");
1733fcf3ce44SJohn Forte 	} else if (pkt->entry_status & BIT_2) {
1734fcf3ce44SJohn Forte 		EL(ha, "Invalid Entry Type\n");
1735fcf3ce44SJohn Forte 	} else if (pkt->entry_status & BIT_1) {
1736fcf3ce44SJohn Forte 		EL(ha, "Busy\n");
1737fcf3ce44SJohn Forte 	} else {
1738fcf3ce44SJohn Forte 		EL(ha, "UNKNOWN flag = %xh error\n", pkt->entry_status);
1739fcf3ce44SJohn Forte 	}
1740fcf3ce44SJohn Forte 
1741a2b3ff35SDaniel Beauregard 	/* Validate the response entry handle. */
1742a2b3ff35SDaniel Beauregard 	resp_identifier = ddi_get32(ha->hba_buf.acc_handle, &pkt->handle);
1743a2b3ff35SDaniel Beauregard 	index = resp_identifier & OSC_INDEX_MASK;
1744a2b3ff35SDaniel Beauregard 	if (index < MAX_OUTSTANDING_COMMANDS) {
1745a2b3ff35SDaniel Beauregard 		/* the index seems reasonable */
1746a2b3ff35SDaniel Beauregard 		sp = ha->outstanding_cmds[index];
1747a2b3ff35SDaniel Beauregard 		if (sp != NULL) {
1748a2b3ff35SDaniel Beauregard 			if (sp->handle == resp_identifier) {
1749a2b3ff35SDaniel Beauregard 				/* Neo, you're the one... */
1750a2b3ff35SDaniel Beauregard 				ha->outstanding_cmds[index] = NULL;
1751a2b3ff35SDaniel Beauregard 				sp->handle = 0;
1752a2b3ff35SDaniel Beauregard 				sp->flags &= ~SRB_IN_TOKEN_ARRAY;
1753a2b3ff35SDaniel Beauregard 			} else {
1754a2b3ff35SDaniel Beauregard 				EL(ha, "IOCB handle mismatch pkt=%xh, sp=%xh\n",
1755a2b3ff35SDaniel Beauregard 				    resp_identifier, sp->handle);
1756a2b3ff35SDaniel Beauregard 				sp = NULL;
1757a2b3ff35SDaniel Beauregard 				ql_signal_abort(ha, set_flags);
1758a2b3ff35SDaniel Beauregard 			}
1759a2b3ff35SDaniel Beauregard 		} else {
1760a2b3ff35SDaniel Beauregard 			sp = ql_verify_preprocessed_cmd(ha,
1761a2b3ff35SDaniel Beauregard 			    (uint32_t *)&pkt->handle, set_flags, reset_flags);
1762a2b3ff35SDaniel Beauregard 		}
1763a2b3ff35SDaniel Beauregard 	} else {
1764a2b3ff35SDaniel Beauregard 		EL(ha, "osc index out of range, index=%xh, handle=%xh\n",
1765a2b3ff35SDaniel Beauregard 		    index, resp_identifier);
1766a2b3ff35SDaniel Beauregard 		ql_signal_abort(ha, set_flags);
1767a2b3ff35SDaniel Beauregard 	}
1768fcf3ce44SJohn Forte 
1769a2b3ff35SDaniel Beauregard 	if (sp != NULL) {
1770fcf3ce44SJohn Forte 		/* Bad payload or header */
1771fcf3ce44SJohn Forte 		if (pkt->entry_status & (BIT_5 + BIT_4 + BIT_3 + BIT_2)) {
1772fcf3ce44SJohn Forte 			/* Bad payload or header, set error status. */
1773fcf3ce44SJohn Forte 			sp->pkt->pkt_reason = CS_BAD_PAYLOAD;
1774fcf3ce44SJohn Forte 		} else if (pkt->entry_status & BIT_1) /* FULL flag */ {
1775fcf3ce44SJohn Forte 			sp->pkt->pkt_reason = CS_QUEUE_FULL;
1776fcf3ce44SJohn Forte 		} else {
1777fcf3ce44SJohn Forte 			/* Set error status. */
1778fcf3ce44SJohn Forte 			sp->pkt->pkt_reason = CS_UNKNOWN;
1779fcf3ce44SJohn Forte 		}
1780fcf3ce44SJohn Forte 
1781fcf3ce44SJohn Forte 		/* Set completed status. */
1782fcf3ce44SJohn Forte 		sp->flags |= SRB_ISP_COMPLETED;
1783fcf3ce44SJohn Forte 
1784fcf3ce44SJohn Forte 		/* Place command on done queue. */
1785fcf3ce44SJohn Forte 		ql_add_link_b(done_q, &sp->cmd);
1786fcf3ce44SJohn Forte 
1787fcf3ce44SJohn Forte 	}
1788fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
1789fcf3ce44SJohn Forte }
1790fcf3ce44SJohn Forte 
1791fcf3ce44SJohn Forte /*
1792fcf3ce44SJohn Forte  * ql_status_entry
1793fcf3ce44SJohn Forte  *	Processes received ISP2200-2300 status entry.
1794fcf3ce44SJohn Forte  *
1795fcf3ce44SJohn Forte  * Input:
1796fcf3ce44SJohn Forte  *	ha:		adapter state pointer.
1797fcf3ce44SJohn Forte  *	pkt:		entry pointer.
1798fcf3ce44SJohn Forte  *	done_q:		done queue pointer.
1799fcf3ce44SJohn Forte  *	set_flags:	task daemon flags to set.
1800fcf3ce44SJohn Forte  *	reset_flags:	task daemon flags to reset.
1801fcf3ce44SJohn Forte  *
1802fcf3ce44SJohn Forte  * Returns:
1803fcf3ce44SJohn Forte  *	BIT_0 = CS_RESET status received.
1804fcf3ce44SJohn Forte  *
1805fcf3ce44SJohn Forte  * Context:
1806fcf3ce44SJohn Forte  *	Interrupt or Kernel context, no mailbox commands allowed.
1807fcf3ce44SJohn Forte  */
1808fcf3ce44SJohn Forte /* ARGSUSED */
1809fcf3ce44SJohn Forte static int
1810fcf3ce44SJohn Forte ql_status_entry(ql_adapter_state_t *ha, sts_entry_t *pkt,
1811fcf3ce44SJohn Forte     ql_head_t *done_q, uint32_t *set_flags, uint32_t *reset_flags)
1812fcf3ce44SJohn Forte {
1813fcf3ce44SJohn Forte 	ql_srb_t		*sp;
1814a2b3ff35SDaniel Beauregard 	uint32_t		index, resp_identifier;
1815fcf3ce44SJohn Forte 	uint16_t		comp_status;
1816fcf3ce44SJohn Forte 	int			rval = 0;
1817fcf3ce44SJohn Forte 
1818fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
1819fcf3ce44SJohn Forte 
1820a2b3ff35SDaniel Beauregard 	/* Validate the response entry handle. */
1821a2b3ff35SDaniel Beauregard 	resp_identifier = ddi_get32(ha->hba_buf.acc_handle, &pkt->handle);
1822a2b3ff35SDaniel Beauregard 	index = resp_identifier & OSC_INDEX_MASK;
1823a2b3ff35SDaniel Beauregard 	if (index < MAX_OUTSTANDING_COMMANDS) {
1824a2b3ff35SDaniel Beauregard 		/* the index seems reasonable */
1825a2b3ff35SDaniel Beauregard 		sp = ha->outstanding_cmds[index];
1826a2b3ff35SDaniel Beauregard 		if (sp != NULL) {
1827a2b3ff35SDaniel Beauregard 			if (sp->handle == resp_identifier) {
1828a2b3ff35SDaniel Beauregard 				/* Neo, you're the one... */
1829a2b3ff35SDaniel Beauregard 				ha->outstanding_cmds[index] = NULL;
1830a2b3ff35SDaniel Beauregard 				sp->handle = 0;
1831a2b3ff35SDaniel Beauregard 				sp->flags &= ~SRB_IN_TOKEN_ARRAY;
1832a2b3ff35SDaniel Beauregard 			} else {
1833a2b3ff35SDaniel Beauregard 				EL(ha, "IOCB handle mismatch pkt=%xh, sp=%xh\n",
1834a2b3ff35SDaniel Beauregard 				    resp_identifier, sp->handle);
1835a2b3ff35SDaniel Beauregard 				sp = NULL;
1836a2b3ff35SDaniel Beauregard 				ql_signal_abort(ha, set_flags);
1837a2b3ff35SDaniel Beauregard 			}
1838a2b3ff35SDaniel Beauregard 		} else {
1839a2b3ff35SDaniel Beauregard 			sp = ql_verify_preprocessed_cmd(ha,
1840a2b3ff35SDaniel Beauregard 			    (uint32_t *)&pkt->handle, set_flags, reset_flags);
1841a2b3ff35SDaniel Beauregard 		}
1842a2b3ff35SDaniel Beauregard 	} else {
1843a2b3ff35SDaniel Beauregard 		EL(ha, "osc index out of range, index=%xh, handle=%xh\n",
1844a2b3ff35SDaniel Beauregard 		    index, resp_identifier);
1845a2b3ff35SDaniel Beauregard 		ql_signal_abort(ha, set_flags);
1846a2b3ff35SDaniel Beauregard 	}
1847fcf3ce44SJohn Forte 
1848a2b3ff35SDaniel Beauregard 	if (sp != NULL) {
1849fcf3ce44SJohn Forte 		comp_status = (uint16_t)ddi_get16(ha->hba_buf.acc_handle,
1850fcf3ce44SJohn Forte 		    &pkt->comp_status);
1851fcf3ce44SJohn Forte 
1852fcf3ce44SJohn Forte 		/*
1853fcf3ce44SJohn Forte 		 * We dont care about SCSI QFULLs.
1854fcf3ce44SJohn Forte 		 */
1855fcf3ce44SJohn Forte 		if (comp_status == CS_QUEUE_FULL) {
1856fcf3ce44SJohn Forte 			EL(ha, "CS_QUEUE_FULL, d_id=%xh, lun=%xh\n",
1857fcf3ce44SJohn Forte 			    sp->lun_queue->target_queue->d_id.b24,
1858fcf3ce44SJohn Forte 			    sp->lun_queue->lun_no);
1859fcf3ce44SJohn Forte 			comp_status = CS_COMPLETE;
1860fcf3ce44SJohn Forte 		}
1861fcf3ce44SJohn Forte 
1862fcf3ce44SJohn Forte 		/*
1863fcf3ce44SJohn Forte 		 * 2300 firmware marks completion status as data underrun
1864fcf3ce44SJohn Forte 		 * for scsi qfulls. Make it transport complete.
1865fcf3ce44SJohn Forte 		 */
1866fcf3ce44SJohn Forte 		if ((CFG_IST(ha, (CFG_CTRL_2300 | CFG_CTRL_6322))) &&
1867fcf3ce44SJohn Forte 		    (comp_status == CS_DATA_UNDERRUN) &&
1868fcf3ce44SJohn Forte 		    (pkt->scsi_status_l != 0)) {
1869fcf3ce44SJohn Forte 			comp_status = CS_COMPLETE;
1870fcf3ce44SJohn Forte 		}
1871fcf3ce44SJohn Forte 
1872fcf3ce44SJohn Forte 		/*
1873fcf3ce44SJohn Forte 		 * Workaround T3 issue where we do not get any data xferred
1874fcf3ce44SJohn Forte 		 * but get back a good status.
1875fcf3ce44SJohn Forte 		 */
1876fcf3ce44SJohn Forte 		if ((pkt->state_flags_h & SF_XFERRED_DATA) == 0 &&
1877fcf3ce44SJohn Forte 		    comp_status == CS_COMPLETE &&
1878fcf3ce44SJohn Forte 		    pkt->scsi_status_l == 0 &&
1879fcf3ce44SJohn Forte 		    (pkt->scsi_status_h & FCP_RSP_MASK) == 0 &&
1880fcf3ce44SJohn Forte 		    pkt->residual_length == 0 &&
1881fcf3ce44SJohn Forte 		    sp->fcp &&
1882fcf3ce44SJohn Forte 		    sp->fcp->fcp_data_len != 0 &&
1883fcf3ce44SJohn Forte 		    (pkt->state_flags_l & (SF_DATA_OUT | SF_DATA_IN)) ==
1884fcf3ce44SJohn Forte 		    SF_DATA_OUT) {
1885fcf3ce44SJohn Forte 			comp_status = CS_ABORTED;
1886fcf3ce44SJohn Forte 		}
1887fcf3ce44SJohn Forte 
1888fcf3ce44SJohn Forte 		if (sp->flags & SRB_MS_PKT) {
1889fcf3ce44SJohn Forte 			/*
1890fcf3ce44SJohn Forte 			 * Ideally it should never be true. But there
1891fcf3ce44SJohn Forte 			 * is a bug in FW which upon receiving invalid
1892fcf3ce44SJohn Forte 			 * parameters in MS IOCB returns it as
1893fcf3ce44SJohn Forte 			 * status entry and not as ms entry type.
1894fcf3ce44SJohn Forte 			 */
1895fcf3ce44SJohn Forte 			ql_ms_entry(ha, (ms_entry_t *)pkt, done_q,
1896fcf3ce44SJohn Forte 			    set_flags, reset_flags);
1897fcf3ce44SJohn Forte 			QL_PRINT_3(CE_CONT, "(%d): ql_ms_entry done\n",
1898fcf3ce44SJohn Forte 			    ha->instance);
1899fcf3ce44SJohn Forte 			return (0);
1900fcf3ce44SJohn Forte 		}
1901fcf3ce44SJohn Forte 
1902fcf3ce44SJohn Forte 		/*
1903fcf3ce44SJohn Forte 		 * Fast path to good SCSI I/O completion
1904fcf3ce44SJohn Forte 		 */
1905fcf3ce44SJohn Forte 		if ((comp_status == CS_COMPLETE) &
1906fcf3ce44SJohn Forte 		    (!pkt->scsi_status_l) &
1907fcf3ce44SJohn Forte 		    (!(pkt->scsi_status_h & FCP_RSP_MASK))) {
1908fcf3ce44SJohn Forte 			/* Set completed status. */
1909fcf3ce44SJohn Forte 			sp->flags |= SRB_ISP_COMPLETED;
1910fcf3ce44SJohn Forte 			sp->pkt->pkt_reason = comp_status;
1911fcf3ce44SJohn Forte 			ql_fast_fcp_post(sp);
1912fcf3ce44SJohn Forte 			QL_PRINT_3(CE_CONT, "(%d): ql_fast_fcp_post done\n",
1913fcf3ce44SJohn Forte 			    ha->instance);
1914fcf3ce44SJohn Forte 			return (0);
1915fcf3ce44SJohn Forte 		}
1916fcf3ce44SJohn Forte 		rval = ql_status_error(ha, sp, pkt, done_q, set_flags,
1917fcf3ce44SJohn Forte 		    reset_flags);
1918fcf3ce44SJohn Forte 	}
1919fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
1920fcf3ce44SJohn Forte 
1921fcf3ce44SJohn Forte 	return (rval);
1922fcf3ce44SJohn Forte }
1923fcf3ce44SJohn Forte 
1924fcf3ce44SJohn Forte /*
1925fcf3ce44SJohn Forte  * ql_24xx_status_entry
1926fcf3ce44SJohn Forte  *	Processes received ISP24xx status entry.
1927fcf3ce44SJohn Forte  *
1928fcf3ce44SJohn Forte  * Input:
1929fcf3ce44SJohn Forte  *	ha:		adapter state pointer.
1930fcf3ce44SJohn Forte  *	pkt:		entry pointer.
1931fcf3ce44SJohn Forte  *	done_q:		done queue pointer.
1932fcf3ce44SJohn Forte  *	set_flags:	task daemon flags to set.
1933fcf3ce44SJohn Forte  *	reset_flags:	task daemon flags to reset.
1934fcf3ce44SJohn Forte  *
1935fcf3ce44SJohn Forte  * Returns:
1936fcf3ce44SJohn Forte  *	BIT_0 = CS_RESET status received.
1937fcf3ce44SJohn Forte  *
1938fcf3ce44SJohn Forte  * Context:
1939fcf3ce44SJohn Forte  *	Interrupt or Kernel context, no mailbox commands allowed.
1940fcf3ce44SJohn Forte  */
1941fcf3ce44SJohn Forte /* ARGSUSED */
1942fcf3ce44SJohn Forte static int
1943fcf3ce44SJohn Forte ql_24xx_status_entry(ql_adapter_state_t *ha, sts_24xx_entry_t *pkt,
1944fcf3ce44SJohn Forte     ql_head_t *done_q, uint32_t *set_flags, uint32_t *reset_flags)
1945fcf3ce44SJohn Forte {
1946a2b3ff35SDaniel Beauregard 	ql_srb_t		*sp = NULL;
1947fcf3ce44SJohn Forte 	uint16_t		comp_status;
1948a2b3ff35SDaniel Beauregard 	uint32_t		index, resp_identifier;
1949fcf3ce44SJohn Forte 	int			rval = 0;
1950fcf3ce44SJohn Forte 
1951fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
1952fcf3ce44SJohn Forte 
1953a2b3ff35SDaniel Beauregard 	/* Validate the response entry handle. */
195416dd44c2SDaniel Beauregard 	resp_identifier = ddi_get32(ha->hba_buf.acc_handle, &pkt->handle);
195516dd44c2SDaniel Beauregard 	index = resp_identifier & OSC_INDEX_MASK;
1956a2b3ff35SDaniel Beauregard 	if (index < MAX_OUTSTANDING_COMMANDS) {
1957a2b3ff35SDaniel Beauregard 		/* the index seems reasonable */
1958a2b3ff35SDaniel Beauregard 		sp = ha->outstanding_cmds[index];
1959a2b3ff35SDaniel Beauregard 		if (sp != NULL) {
1960a2b3ff35SDaniel Beauregard 			if (sp->handle == resp_identifier) {
1961a2b3ff35SDaniel Beauregard 				/* Neo, you're the one... */
1962a2b3ff35SDaniel Beauregard 				ha->outstanding_cmds[index] = NULL;
1963a2b3ff35SDaniel Beauregard 				sp->handle = 0;
1964a2b3ff35SDaniel Beauregard 				sp->flags &= ~SRB_IN_TOKEN_ARRAY;
1965a2b3ff35SDaniel Beauregard 			} else {
1966a2b3ff35SDaniel Beauregard 				EL(ha, "IOCB handle mismatch pkt=%xh, sp=%xh\n",
1967a2b3ff35SDaniel Beauregard 				    resp_identifier, sp->handle);
1968a2b3ff35SDaniel Beauregard 				sp = NULL;
1969a2b3ff35SDaniel Beauregard 				ql_signal_abort(ha, set_flags);
1970a2b3ff35SDaniel Beauregard 			}
1971a2b3ff35SDaniel Beauregard 		} else {
1972a2b3ff35SDaniel Beauregard 			sp = ql_verify_preprocessed_cmd(ha,
1973a2b3ff35SDaniel Beauregard 			    (uint32_t *)&pkt->handle, set_flags, reset_flags);
1974a2b3ff35SDaniel Beauregard 		}
1975a2b3ff35SDaniel Beauregard 	} else {
1976a2b3ff35SDaniel Beauregard 		EL(ha, "osc index out of range, index=%xh, handle=%xh\n",
1977a2b3ff35SDaniel Beauregard 		    index, resp_identifier);
1978a2b3ff35SDaniel Beauregard 		ql_signal_abort(ha, set_flags);
1979a2b3ff35SDaniel Beauregard 	}
198016dd44c2SDaniel Beauregard 
1981a2b3ff35SDaniel Beauregard 	if (sp != NULL) {
1982fcf3ce44SJohn Forte 		comp_status = (uint16_t)ddi_get16(ha->hba_buf.acc_handle,
1983fcf3ce44SJohn Forte 		    &pkt->comp_status);
1984fcf3ce44SJohn Forte 
1985a2b3ff35SDaniel Beauregard 		/* We dont care about SCSI QFULLs. */
1986fcf3ce44SJohn Forte 		if (comp_status == CS_QUEUE_FULL) {
1987fcf3ce44SJohn Forte 			EL(sp->ha, "CS_QUEUE_FULL, d_id=%xh, lun=%xh\n",
1988fcf3ce44SJohn Forte 			    sp->lun_queue->target_queue->d_id.b24,
1989fcf3ce44SJohn Forte 			    sp->lun_queue->lun_no);
1990fcf3ce44SJohn Forte 			comp_status = CS_COMPLETE;
1991fcf3ce44SJohn Forte 		}
1992fcf3ce44SJohn Forte 
1993fcf3ce44SJohn Forte 		/*
1994fcf3ce44SJohn Forte 		 * 2300 firmware marks completion status as data underrun
1995fcf3ce44SJohn Forte 		 * for scsi qfulls. Make it transport complete.
1996fcf3ce44SJohn Forte 		 */
1997fcf3ce44SJohn Forte 		if ((comp_status == CS_DATA_UNDERRUN) &&
1998fcf3ce44SJohn Forte 		    (pkt->scsi_status_l != 0)) {
1999fcf3ce44SJohn Forte 			comp_status = CS_COMPLETE;
2000fcf3ce44SJohn Forte 		}
2001fcf3ce44SJohn Forte 
2002fcf3ce44SJohn Forte 		/*
2003fcf3ce44SJohn Forte 		 * Workaround T3 issue where we do not get any data xferred
2004fcf3ce44SJohn Forte 		 * but get back a good status.
2005fcf3ce44SJohn Forte 		 */
2006fcf3ce44SJohn Forte 		if (comp_status == CS_COMPLETE &&
2007fcf3ce44SJohn Forte 		    pkt->scsi_status_l == 0 &&
2008fcf3ce44SJohn Forte 		    (pkt->scsi_status_h & FCP_RSP_MASK) == 0 &&
2009fcf3ce44SJohn Forte 		    pkt->residual_length != 0 &&
2010fcf3ce44SJohn Forte 		    sp->fcp &&
2011fcf3ce44SJohn Forte 		    sp->fcp->fcp_data_len != 0 &&
2012fcf3ce44SJohn Forte 		    sp->fcp->fcp_cntl.cntl_write_data) {
2013fcf3ce44SJohn Forte 			comp_status = CS_ABORTED;
2014fcf3ce44SJohn Forte 		}
2015fcf3ce44SJohn Forte 
2016fcf3ce44SJohn Forte 		/*
2017fcf3ce44SJohn Forte 		 * Fast path to good SCSI I/O completion
2018fcf3ce44SJohn Forte 		 */
2019fcf3ce44SJohn Forte 		if ((comp_status == CS_COMPLETE) &
2020fcf3ce44SJohn Forte 		    (!pkt->scsi_status_l) &
2021fcf3ce44SJohn Forte 		    (!(pkt->scsi_status_h & FCP_RSP_MASK))) {
2022fcf3ce44SJohn Forte 			/* Set completed status. */
2023fcf3ce44SJohn Forte 			sp->flags |= SRB_ISP_COMPLETED;
2024fcf3ce44SJohn Forte 			sp->pkt->pkt_reason = comp_status;
2025fcf3ce44SJohn Forte 			ql_fast_fcp_post(sp);
2026fcf3ce44SJohn Forte 			QL_PRINT_3(CE_CONT, "(%d): ql_fast_fcp_post done\n",
2027fcf3ce44SJohn Forte 			    ha->instance);
2028fcf3ce44SJohn Forte 			return (0);
2029fcf3ce44SJohn Forte 		}
2030fcf3ce44SJohn Forte 		rval = ql_status_error(ha, sp, (sts_entry_t *)pkt, done_q,
2031fcf3ce44SJohn Forte 		    set_flags, reset_flags);
2032a2b3ff35SDaniel Beauregard 	}
2033a2b3ff35SDaniel Beauregard 	QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
2034fcf3ce44SJohn Forte 
2035a2b3ff35SDaniel Beauregard 	return (rval);
2036a2b3ff35SDaniel Beauregard }
2037fcf3ce44SJohn Forte 
2038a2b3ff35SDaniel Beauregard /*
2039a2b3ff35SDaniel Beauregard  * ql_verify_preprocessed_cmd
2040a2b3ff35SDaniel Beauregard  *	Handles preprocessed cmds..
2041a2b3ff35SDaniel Beauregard  *
2042a2b3ff35SDaniel Beauregard  * Input:
2043a2b3ff35SDaniel Beauregard  *	ha:		adapter state pointer.
2044a2b3ff35SDaniel Beauregard  *	pkt_handle:	handle pointer.
2045a2b3ff35SDaniel Beauregard  *	set_flags:	task daemon flags to set.
2046a2b3ff35SDaniel Beauregard  *	reset_flags:	task daemon flags to reset.
2047a2b3ff35SDaniel Beauregard  *
2048a2b3ff35SDaniel Beauregard  * Returns:
2049a2b3ff35SDaniel Beauregard  *	srb pointer or NULL
2050a2b3ff35SDaniel Beauregard  *
2051a2b3ff35SDaniel Beauregard  * Context:
2052a2b3ff35SDaniel Beauregard  *	Interrupt or Kernel context, no mailbox commands allowed.
2053a2b3ff35SDaniel Beauregard  */
2054a2b3ff35SDaniel Beauregard /* ARGSUSED */
2055a2b3ff35SDaniel Beauregard ql_srb_t *
2056a2b3ff35SDaniel Beauregard ql_verify_preprocessed_cmd(ql_adapter_state_t *ha, uint32_t *pkt_handle,
2057a2b3ff35SDaniel Beauregard     uint32_t *set_flags, uint32_t *reset_flags)
2058a2b3ff35SDaniel Beauregard {
2059a2b3ff35SDaniel Beauregard 	ql_srb_t		*sp = NULL;
2060a2b3ff35SDaniel Beauregard 	uint32_t		index, resp_identifier;
2061a2b3ff35SDaniel Beauregard 	uint32_t		get_handle = 10;
2062a2b3ff35SDaniel Beauregard 
2063a2b3ff35SDaniel Beauregard 	while (get_handle) {
2064a2b3ff35SDaniel Beauregard 		/* Get handle. */
2065a2b3ff35SDaniel Beauregard 		resp_identifier = ddi_get32(ha->hba_buf.acc_handle, pkt_handle);
2066a2b3ff35SDaniel Beauregard 		index = resp_identifier & OSC_INDEX_MASK;
2067a2b3ff35SDaniel Beauregard 		/* Validate handle. */
2068a2b3ff35SDaniel Beauregard 		if (index < MAX_OUTSTANDING_COMMANDS) {
2069a2b3ff35SDaniel Beauregard 			sp = ha->outstanding_cmds[index];
2070fcf3ce44SJohn Forte 		}
2071fcf3ce44SJohn Forte 
2072a2b3ff35SDaniel Beauregard 		if (sp != NULL) {
2073f33c1cdbSDaniel Beauregard 			EL(ha, "sp=%xh, resp_id=%xh, get=%d, index=%xh\n", sp,
2074f33c1cdbSDaniel Beauregard 			    resp_identifier, get_handle, index);
2075a2b3ff35SDaniel Beauregard 			break;
2076a2b3ff35SDaniel Beauregard 		} else {
2077a2b3ff35SDaniel Beauregard 			get_handle -= 1;
2078a2b3ff35SDaniel Beauregard 			drv_usecwait(10000);
2079a2b3ff35SDaniel Beauregard 			if (get_handle == 1) {
2080a2b3ff35SDaniel Beauregard 				/* Last chance, Sync whole DMA buffer. */
2081a2b3ff35SDaniel Beauregard 				(void) ddi_dma_sync(ha->hba_buf.dma_handle,
2082a2b3ff35SDaniel Beauregard 				    RESPONSE_Q_BUFFER_OFFSET,
2083a2b3ff35SDaniel Beauregard 				    RESPONSE_QUEUE_SIZE,
2084a2b3ff35SDaniel Beauregard 				    DDI_DMA_SYNC_FORKERNEL);
2085f33c1cdbSDaniel Beauregard 				EL(ha, "last chance DMA sync, index=%xh\n",
2086f33c1cdbSDaniel Beauregard 				    index);
2087a2b3ff35SDaniel Beauregard 			}
2088a2b3ff35SDaniel Beauregard 		}
2089a2b3ff35SDaniel Beauregard 	}
2090fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
2091fcf3ce44SJohn Forte 
2092a2b3ff35SDaniel Beauregard 	return (sp);
2093fcf3ce44SJohn Forte }
2094fcf3ce44SJohn Forte 
2095a2b3ff35SDaniel Beauregard 
2096fcf3ce44SJohn Forte /*
2097fcf3ce44SJohn Forte  * ql_status_error
2098fcf3ce44SJohn Forte  *	Processes received ISP status entry error.
2099fcf3ce44SJohn Forte  *
2100fcf3ce44SJohn Forte  * Input:
2101fcf3ce44SJohn Forte  *	ha:		adapter state pointer.
2102fcf3ce44SJohn Forte  *	sp:		SRB pointer.
2103fcf3ce44SJohn Forte  *	pkt:		entry pointer.
2104fcf3ce44SJohn Forte  *	done_q:		done queue pointer.
2105fcf3ce44SJohn Forte  *	set_flags:	task daemon flags to set.
2106fcf3ce44SJohn Forte  *	reset_flags:	task daemon flags to reset.
2107fcf3ce44SJohn Forte  *
2108fcf3ce44SJohn Forte  * Returns:
2109fcf3ce44SJohn Forte  *	BIT_0 = CS_RESET status received.
2110fcf3ce44SJohn Forte  *
2111fcf3ce44SJohn Forte  * Context:
2112fcf3ce44SJohn Forte  *	Interrupt or Kernel context, no mailbox commands allowed.
2113fcf3ce44SJohn Forte  */
2114fcf3ce44SJohn Forte /* ARGSUSED */
2115fcf3ce44SJohn Forte static int
2116fcf3ce44SJohn Forte ql_status_error(ql_adapter_state_t *ha, ql_srb_t *sp, sts_entry_t *pkt23,
2117fcf3ce44SJohn Forte     ql_head_t *done_q, uint32_t *set_flags, uint32_t *reset_flags)
2118fcf3ce44SJohn Forte {
2119fcf3ce44SJohn Forte 	uint32_t		sense_sz = 0;
2120fcf3ce44SJohn Forte 	uint32_t		cnt;
2121fcf3ce44SJohn Forte 	ql_tgt_t		*tq;
2122fcf3ce44SJohn Forte 	fcp_rsp_t		*fcpr;
2123fcf3ce44SJohn Forte 	struct fcp_rsp_info	*rsp;
2124fcf3ce44SJohn Forte 	int			rval = 0;
2125fcf3ce44SJohn Forte 
2126fcf3ce44SJohn Forte 	struct {
2127fcf3ce44SJohn Forte 		uint8_t		*rsp_info;
2128fcf3ce44SJohn Forte 		uint8_t		*req_sense_data;
2129fcf3ce44SJohn Forte 		uint32_t	residual_length;
2130fcf3ce44SJohn Forte 		uint32_t	fcp_residual_length;
2131fcf3ce44SJohn Forte 		uint32_t	rsp_info_length;
2132fcf3ce44SJohn Forte 		uint32_t	req_sense_length;
2133fcf3ce44SJohn Forte 		uint16_t	comp_status;
2134fcf3ce44SJohn Forte 		uint8_t		state_flags_l;
2135fcf3ce44SJohn Forte 		uint8_t		state_flags_h;
2136fcf3ce44SJohn Forte 		uint8_t		scsi_status_l;
2137fcf3ce44SJohn Forte 		uint8_t		scsi_status_h;
2138fcf3ce44SJohn Forte 	} sts;
2139fcf3ce44SJohn Forte 
2140fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
2141fcf3ce44SJohn Forte 
2142eb82ff87SDaniel Beauregard 	if (CFG_IST(ha, CFG_CTRL_24258081)) {
2143fcf3ce44SJohn Forte 		sts_24xx_entry_t *pkt24 = (sts_24xx_entry_t *)pkt23;
2144fcf3ce44SJohn Forte 
2145fcf3ce44SJohn Forte 		/* Setup status. */
2146fcf3ce44SJohn Forte 		sts.comp_status = (uint16_t)ddi_get16(ha->hba_buf.acc_handle,
2147fcf3ce44SJohn Forte 		    &pkt24->comp_status);
2148fcf3ce44SJohn Forte 		sts.scsi_status_l = pkt24->scsi_status_l;
2149fcf3ce44SJohn Forte 		sts.scsi_status_h = pkt24->scsi_status_h;
2150fcf3ce44SJohn Forte 
2151fcf3ce44SJohn Forte 		/* Setup firmware residuals. */
2152fcf3ce44SJohn Forte 		sts.residual_length = sts.comp_status == CS_DATA_UNDERRUN ?
2153fcf3ce44SJohn Forte 		    ddi_get32(ha->hba_buf.acc_handle,
2154fcf3ce44SJohn Forte 		    (uint32_t *)&pkt24->residual_length) : 0;
2155fcf3ce44SJohn Forte 
2156fcf3ce44SJohn Forte 		/* Setup FCP residuals. */
2157fcf3ce44SJohn Forte 		sts.fcp_residual_length = sts.scsi_status_h &
2158fcf3ce44SJohn Forte 		    (FCP_RESID_UNDER | FCP_RESID_OVER) ?
2159fcf3ce44SJohn Forte 		    ddi_get32(ha->hba_buf.acc_handle,
2160fcf3ce44SJohn Forte 		    (uint32_t *)&pkt24->fcp_rsp_residual_count) : 0;
2161fcf3ce44SJohn Forte 
2162fcf3ce44SJohn Forte 		if ((sts.comp_status == CS_DATA_UNDERRUN) &&
2163fcf3ce44SJohn Forte 		    (sts.scsi_status_h & FCP_RESID_UNDER) &&
2164fcf3ce44SJohn Forte 		    (sts.residual_length != pkt24->fcp_rsp_residual_count)) {
2165fcf3ce44SJohn Forte 
2166fcf3ce44SJohn Forte 			EL(sp->ha, "mismatch resid's: fw=%xh, pkt=%xh\n",
2167fcf3ce44SJohn Forte 			    sts.residual_length,
2168fcf3ce44SJohn Forte 			    pkt24->fcp_rsp_residual_count);
2169fcf3ce44SJohn Forte 			sts.scsi_status_h = (uint8_t)
2170fcf3ce44SJohn Forte 			    (sts.scsi_status_h & ~FCP_RESID_UNDER);
2171fcf3ce44SJohn Forte 		}
2172fcf3ce44SJohn Forte 
2173fcf3ce44SJohn Forte 		/* Setup state flags. */
2174fcf3ce44SJohn Forte 		sts.state_flags_l = pkt24->state_flags_l;
2175fcf3ce44SJohn Forte 		sts.state_flags_h = pkt24->state_flags_h;
2176fcf3ce44SJohn Forte 
2177fcf3ce44SJohn Forte 		if (sp->fcp->fcp_data_len &&
2178fcf3ce44SJohn Forte 		    (sts.comp_status != CS_DATA_UNDERRUN ||
2179fcf3ce44SJohn Forte 		    sts.residual_length != sp->fcp->fcp_data_len)) {
2180fcf3ce44SJohn Forte 			sts.state_flags_h = (uint8_t)
2181fcf3ce44SJohn Forte 			    (sts.state_flags_h | SF_GOT_BUS |
2182fcf3ce44SJohn Forte 			    SF_GOT_TARGET | SF_SENT_CMD |
2183fcf3ce44SJohn Forte 			    SF_XFERRED_DATA | SF_GOT_STATUS);
2184fcf3ce44SJohn Forte 		} else {
2185fcf3ce44SJohn Forte 			sts.state_flags_h = (uint8_t)
2186fcf3ce44SJohn Forte 			    (sts.state_flags_h | SF_GOT_BUS |
2187fcf3ce44SJohn Forte 			    SF_GOT_TARGET | SF_SENT_CMD |
2188fcf3ce44SJohn Forte 			    SF_GOT_STATUS);
2189fcf3ce44SJohn Forte 		}
2190fcf3ce44SJohn Forte 		if (sp->fcp->fcp_cntl.cntl_write_data) {
2191fcf3ce44SJohn Forte 			sts.state_flags_l = (uint8_t)
2192fcf3ce44SJohn Forte 			    (sts.state_flags_l | SF_DATA_OUT);
2193fcf3ce44SJohn Forte 		} else if (sp->fcp->fcp_cntl.cntl_read_data) {
2194fcf3ce44SJohn Forte 			sts.state_flags_l = (uint8_t)
2195fcf3ce44SJohn Forte 			    (sts.state_flags_l | SF_DATA_IN);
2196fcf3ce44SJohn Forte 		}
2197fcf3ce44SJohn Forte 		if (sp->fcp->fcp_cntl.cntl_qtype == FCP_QTYPE_HEAD_OF_Q) {
2198fcf3ce44SJohn Forte 			sts.state_flags_l = (uint8_t)
2199fcf3ce44SJohn Forte 			    (sts.state_flags_l | SF_HEAD_OF_Q);
2200fcf3ce44SJohn Forte 		} else if (sp->fcp->fcp_cntl.cntl_qtype == FCP_QTYPE_ORDERED) {
2201fcf3ce44SJohn Forte 			sts.state_flags_l = (uint8_t)
2202fcf3ce44SJohn Forte 			    (sts.state_flags_l | SF_ORDERED_Q);
2203fcf3ce44SJohn Forte 		} else if (sp->fcp->fcp_cntl.cntl_qtype == FCP_QTYPE_SIMPLE) {
2204fcf3ce44SJohn Forte 			sts.state_flags_l = (uint8_t)
2205fcf3ce44SJohn Forte 			    (sts.state_flags_l | SF_SIMPLE_Q);
2206fcf3ce44SJohn Forte 		}
2207fcf3ce44SJohn Forte 
2208fcf3ce44SJohn Forte 		/* Setup FCP response info. */
2209fcf3ce44SJohn Forte 		sts.rsp_info = &pkt24->rsp_sense_data[0];
2210fcf3ce44SJohn Forte 		if ((sts.scsi_status_h & FCP_RSP_LEN_VALID) != 0) {
2211fcf3ce44SJohn Forte 			sts.rsp_info_length = ddi_get32(ha->hba_buf.acc_handle,
2212fcf3ce44SJohn Forte 			    (uint32_t *)&pkt24->fcp_rsp_data_length);
2213fcf3ce44SJohn Forte 			if (sts.rsp_info_length >
2214fcf3ce44SJohn Forte 			    sizeof (struct fcp_rsp_info)) {
2215fcf3ce44SJohn Forte 				sts.rsp_info_length =
2216fcf3ce44SJohn Forte 				    sizeof (struct fcp_rsp_info);
2217fcf3ce44SJohn Forte 			}
2218fcf3ce44SJohn Forte 			for (cnt = 0; cnt < sts.rsp_info_length; cnt += 4) {
2219fcf3ce44SJohn Forte 				ql_chg_endian(sts.rsp_info + cnt, 4);
2220fcf3ce44SJohn Forte 			}
2221fcf3ce44SJohn Forte 		} else {
2222fcf3ce44SJohn Forte 			sts.rsp_info_length = 0;
2223fcf3ce44SJohn Forte 		}
2224fcf3ce44SJohn Forte 
2225fcf3ce44SJohn Forte 		/* Setup sense data. */
2226fcf3ce44SJohn Forte 		sts.req_sense_data =
2227fcf3ce44SJohn Forte 		    &pkt24->rsp_sense_data[sts.rsp_info_length];
2228fcf3ce44SJohn Forte 		if (sts.scsi_status_h & FCP_SNS_LEN_VALID) {
2229fcf3ce44SJohn Forte 			sts.req_sense_length =
2230fcf3ce44SJohn Forte 			    ddi_get32(ha->hba_buf.acc_handle,
2231fcf3ce44SJohn Forte 			    (uint32_t *)&pkt24->fcp_sense_length);
2232fcf3ce44SJohn Forte 			sts.state_flags_h = (uint8_t)
2233fcf3ce44SJohn Forte 			    (sts.state_flags_h | SF_ARQ_DONE);
2234fcf3ce44SJohn Forte 			sense_sz = (uint32_t)
2235fcf3ce44SJohn Forte 			    (((uintptr_t)pkt24 + sizeof (sts_24xx_entry_t)) -
2236fcf3ce44SJohn Forte 			    (uintptr_t)sts.req_sense_data);
2237fcf3ce44SJohn Forte 			for (cnt = 0; cnt < sense_sz; cnt += 4) {
2238fcf3ce44SJohn Forte 				ql_chg_endian(sts.req_sense_data + cnt, 4);
2239fcf3ce44SJohn Forte 			}
2240fcf3ce44SJohn Forte 		} else {
2241fcf3ce44SJohn Forte 			sts.req_sense_length = 0;
2242fcf3ce44SJohn Forte 		}
2243fcf3ce44SJohn Forte 	} else {
2244fcf3ce44SJohn Forte 		/* Setup status. */
2245fcf3ce44SJohn Forte 		sts.comp_status = (uint16_t)ddi_get16(
2246fcf3ce44SJohn Forte 		    ha->hba_buf.acc_handle, &pkt23->comp_status);
2247fcf3ce44SJohn Forte 		sts.scsi_status_l = pkt23->scsi_status_l;
2248fcf3ce44SJohn Forte 		sts.scsi_status_h = pkt23->scsi_status_h;
2249fcf3ce44SJohn Forte 
2250fcf3ce44SJohn Forte 		/* Setup firmware residuals. */
2251fcf3ce44SJohn Forte 		sts.residual_length = sts.comp_status == CS_DATA_UNDERRUN ?
2252fcf3ce44SJohn Forte 		    ddi_get32(ha->hba_buf.acc_handle,
2253fcf3ce44SJohn Forte 		    (uint32_t *)&pkt23->residual_length) : 0;
2254fcf3ce44SJohn Forte 
2255fcf3ce44SJohn Forte 		/* Setup FCP residuals. */
2256fcf3ce44SJohn Forte 		sts.fcp_residual_length = sts.scsi_status_h &
2257fcf3ce44SJohn Forte 		    (FCP_RESID_UNDER | FCP_RESID_OVER) ?
2258fcf3ce44SJohn Forte 		    sts.residual_length : 0;
2259fcf3ce44SJohn Forte 
2260fcf3ce44SJohn Forte 		/* Setup state flags. */
2261fcf3ce44SJohn Forte 		sts.state_flags_l = pkt23->state_flags_l;
2262fcf3ce44SJohn Forte 		sts.state_flags_h = pkt23->state_flags_h;
2263fcf3ce44SJohn Forte 
2264fcf3ce44SJohn Forte 		/* Setup FCP response info. */
2265fcf3ce44SJohn Forte 		sts.rsp_info = &pkt23->rsp_info[0];
2266fcf3ce44SJohn Forte 		if ((sts.scsi_status_h & FCP_RSP_LEN_VALID) != 0) {
2267fcf3ce44SJohn Forte 			sts.rsp_info_length = ddi_get16(
2268fcf3ce44SJohn Forte 			    ha->hba_buf.acc_handle,
2269fcf3ce44SJohn Forte 			    (uint16_t *)&pkt23->rsp_info_length);
2270fcf3ce44SJohn Forte 			if (sts.rsp_info_length >
2271fcf3ce44SJohn Forte 			    sizeof (struct fcp_rsp_info)) {
2272fcf3ce44SJohn Forte 				sts.rsp_info_length =
2273fcf3ce44SJohn Forte 				    sizeof (struct fcp_rsp_info);
2274fcf3ce44SJohn Forte 			}
2275fcf3ce44SJohn Forte 		} else {
2276fcf3ce44SJohn Forte 			sts.rsp_info_length = 0;
2277fcf3ce44SJohn Forte 		}
2278fcf3ce44SJohn Forte 
2279fcf3ce44SJohn Forte 		/* Setup sense data. */
2280fcf3ce44SJohn Forte 		sts.req_sense_data = &pkt23->req_sense_data[0];
2281fcf3ce44SJohn Forte 		sts.req_sense_length = sts.scsi_status_h & FCP_SNS_LEN_VALID ?
2282fcf3ce44SJohn Forte 		    ddi_get16(ha->hba_buf.acc_handle,
2283fcf3ce44SJohn Forte 		    (uint16_t *)&pkt23->req_sense_length) : 0;
2284fcf3ce44SJohn Forte 	}
2285fcf3ce44SJohn Forte 
2286fcf3ce44SJohn Forte 	bzero(sp->pkt->pkt_resp, sp->pkt->pkt_rsplen);
2287fcf3ce44SJohn Forte 
2288fcf3ce44SJohn Forte 	fcpr = (fcp_rsp_t *)sp->pkt->pkt_resp;
2289fcf3ce44SJohn Forte 	rsp = (struct fcp_rsp_info *)(sp->pkt->pkt_resp +
2290fcf3ce44SJohn Forte 	    sizeof (fcp_rsp_t));
2291fcf3ce44SJohn Forte 
2292fcf3ce44SJohn Forte 	tq = sp->lun_queue->target_queue;
2293fcf3ce44SJohn Forte 
2294fcf3ce44SJohn Forte 	fcpr->fcp_u.fcp_status.scsi_status = sts.scsi_status_l;
2295fcf3ce44SJohn Forte 	if (sts.scsi_status_h & FCP_RSP_LEN_VALID) {
2296fcf3ce44SJohn Forte 		fcpr->fcp_u.fcp_status.rsp_len_set = 1;
2297fcf3ce44SJohn Forte 	}
2298fcf3ce44SJohn Forte 	if (sts.scsi_status_h & FCP_SNS_LEN_VALID) {
2299fcf3ce44SJohn Forte 		fcpr->fcp_u.fcp_status.sense_len_set = 1;
2300fcf3ce44SJohn Forte 	}
2301fcf3ce44SJohn Forte 	if (sts.scsi_status_h & FCP_RESID_OVER) {
2302fcf3ce44SJohn Forte 		fcpr->fcp_u.fcp_status.resid_over = 1;
2303fcf3ce44SJohn Forte 	}
2304fcf3ce44SJohn Forte 	if (sts.scsi_status_h & FCP_RESID_UNDER) {
2305fcf3ce44SJohn Forte 		fcpr->fcp_u.fcp_status.resid_under = 1;
2306fcf3ce44SJohn Forte 	}
2307fcf3ce44SJohn Forte 	fcpr->fcp_u.fcp_status.reserved_1 = 0;
2308fcf3ce44SJohn Forte 
2309fcf3ce44SJohn Forte 	/* Set ISP completion status */
2310fcf3ce44SJohn Forte 	sp->pkt->pkt_reason = sts.comp_status;
2311fcf3ce44SJohn Forte 
2312fcf3ce44SJohn Forte 	/* Update statistics. */
2313fcf3ce44SJohn Forte 	if ((sts.scsi_status_h & FCP_RSP_LEN_VALID) &&
2314fcf3ce44SJohn Forte 	    (sp->pkt->pkt_rsplen > sizeof (fcp_rsp_t))) {
2315fcf3ce44SJohn Forte 
2316fcf3ce44SJohn Forte 		sense_sz = sp->pkt->pkt_rsplen - (uint32_t)sizeof (fcp_rsp_t);
2317fcf3ce44SJohn Forte 		if (sense_sz > sts.rsp_info_length) {
2318fcf3ce44SJohn Forte 			sense_sz = sts.rsp_info_length;
2319fcf3ce44SJohn Forte 		}
2320fcf3ce44SJohn Forte 
2321fcf3ce44SJohn Forte 		/* copy response information data. */
2322fcf3ce44SJohn Forte 		if (sense_sz) {
2323fcf3ce44SJohn Forte 			ddi_rep_get8(ha->hba_buf.acc_handle, (uint8_t *)rsp,
2324fcf3ce44SJohn Forte 			    sts.rsp_info, sense_sz, DDI_DEV_AUTOINCR);
2325fcf3ce44SJohn Forte 		}
2326fcf3ce44SJohn Forte 		fcpr->fcp_response_len = sense_sz;
2327fcf3ce44SJohn Forte 
2328fcf3ce44SJohn Forte 		rsp = (struct fcp_rsp_info *)((caddr_t)rsp +
2329fcf3ce44SJohn Forte 		    fcpr->fcp_response_len);
2330fcf3ce44SJohn Forte 
2331fcf3ce44SJohn Forte 		switch (*(sts.rsp_info + 3)) {
2332fcf3ce44SJohn Forte 		case FCP_NO_FAILURE:
2333fcf3ce44SJohn Forte 			break;
2334fcf3ce44SJohn Forte 		case FCP_DL_LEN_MISMATCH:
2335fcf3ce44SJohn Forte 			ha->adapter_stats->d_stats[lobyte(
2336fcf3ce44SJohn Forte 			    tq->loop_id)].dl_len_mismatches++;
2337fcf3ce44SJohn Forte 			break;
2338fcf3ce44SJohn Forte 		case FCP_CMND_INVALID:
2339fcf3ce44SJohn Forte 			break;
2340fcf3ce44SJohn Forte 		case FCP_DATA_RO_MISMATCH:
2341fcf3ce44SJohn Forte 			ha->adapter_stats->d_stats[lobyte(
2342fcf3ce44SJohn Forte 			    tq->loop_id)].data_ro_mismatches++;
2343fcf3ce44SJohn Forte 			break;
2344fcf3ce44SJohn Forte 		case FCP_TASK_MGMT_NOT_SUPPTD:
2345fcf3ce44SJohn Forte 			break;
2346fcf3ce44SJohn Forte 		case FCP_TASK_MGMT_FAILED:
2347fcf3ce44SJohn Forte 			ha->adapter_stats->d_stats[lobyte(
2348fcf3ce44SJohn Forte 			    tq->loop_id)].task_mgmt_failures++;
2349fcf3ce44SJohn Forte 			break;
2350fcf3ce44SJohn Forte 		default:
2351fcf3ce44SJohn Forte 			break;
2352fcf3ce44SJohn Forte 		}
2353fcf3ce44SJohn Forte 	} else {
2354fcf3ce44SJohn Forte 		/*
2355fcf3ce44SJohn Forte 		 * EL(sp->ha, "scsi_h=%xh, pkt_rsplen=%xh\n",
2356fcf3ce44SJohn Forte 		 *   sts.scsi_status_h, sp->pkt->pkt_rsplen);
2357fcf3ce44SJohn Forte 		 */
2358fcf3ce44SJohn Forte 		fcpr->fcp_response_len = 0;
2359fcf3ce44SJohn Forte 	}
2360fcf3ce44SJohn Forte 
2361fcf3ce44SJohn Forte 	/* Set reset status received. */
2362fcf3ce44SJohn Forte 	if (sts.comp_status == CS_RESET && LOOP_READY(ha)) {
2363fcf3ce44SJohn Forte 		rval |= BIT_0;
2364fcf3ce44SJohn Forte 	}
2365fcf3ce44SJohn Forte 
2366fcf3ce44SJohn Forte 	if (!(tq->flags & TQF_TAPE_DEVICE) &&
2367fcf3ce44SJohn Forte 	    (!(CFG_IST(ha, CFG_ENABLE_LINK_DOWN_REPORTING)) ||
2368fcf3ce44SJohn Forte 	    ha->loop_down_abort_time < LOOP_DOWN_TIMER_START) &&
2369fcf3ce44SJohn Forte 	    ha->task_daemon_flags & LOOP_DOWN) {
2370fcf3ce44SJohn Forte 		EL(sp->ha, "Loop Not Ready Retry, d_id=%xh, lun=%xh\n",
2371fcf3ce44SJohn Forte 		    tq->d_id.b24, sp->lun_queue->lun_no);
2372fcf3ce44SJohn Forte 
2373fcf3ce44SJohn Forte 		/* Set retry status. */
2374fcf3ce44SJohn Forte 		sp->flags |= SRB_RETRY;
2375fcf3ce44SJohn Forte 	} else if (!(tq->flags & TQF_TAPE_DEVICE) &&
2376fcf3ce44SJohn Forte 	    tq->port_down_retry_count != 0 &&
2377fcf3ce44SJohn Forte 	    (sts.comp_status == CS_INCOMPLETE ||
2378fcf3ce44SJohn Forte 	    sts.comp_status == CS_PORT_UNAVAILABLE ||
2379fcf3ce44SJohn Forte 	    sts.comp_status == CS_PORT_LOGGED_OUT ||
2380fcf3ce44SJohn Forte 	    sts.comp_status == CS_PORT_CONFIG_CHG ||
2381fcf3ce44SJohn Forte 	    sts.comp_status == CS_PORT_BUSY)) {
2382fcf3ce44SJohn Forte 		EL(sp->ha, "Port Down Retry=%xh, d_id=%xh, lun=%xh, count=%d"
2383fcf3ce44SJohn Forte 		    "\n", sts.comp_status, tq->d_id.b24, sp->lun_queue->lun_no,
2384fcf3ce44SJohn Forte 		    tq->port_down_retry_count);
2385fcf3ce44SJohn Forte 
2386fcf3ce44SJohn Forte 		/* Set retry status. */
2387fcf3ce44SJohn Forte 		sp->flags |= SRB_RETRY;
2388fcf3ce44SJohn Forte 
2389fcf3ce44SJohn Forte 		if ((tq->flags & TQF_QUEUE_SUSPENDED) == 0) {
2390fcf3ce44SJohn Forte 			/* Acquire device queue lock. */
2391fcf3ce44SJohn Forte 			DEVICE_QUEUE_LOCK(tq);
2392fcf3ce44SJohn Forte 
2393fcf3ce44SJohn Forte 			tq->flags |= TQF_QUEUE_SUSPENDED;
2394fcf3ce44SJohn Forte 
2395fcf3ce44SJohn Forte 			/* Decrement port down count. */
2396fcf3ce44SJohn Forte 			if (CFG_IST(ha, CFG_ENABLE_LINK_DOWN_REPORTING)) {
2397fcf3ce44SJohn Forte 				tq->port_down_retry_count--;
2398fcf3ce44SJohn Forte 			}
2399fcf3ce44SJohn Forte 
2400fcf3ce44SJohn Forte 			DEVICE_QUEUE_UNLOCK(tq);
2401fcf3ce44SJohn Forte 
2402fcf3ce44SJohn Forte 			if ((ha->task_daemon_flags & ABORT_ISP_ACTIVE)
2403fcf3ce44SJohn Forte 			    == 0 &&
2404fcf3ce44SJohn Forte 			    (sts.comp_status == CS_PORT_LOGGED_OUT ||
2405fcf3ce44SJohn Forte 			    sts.comp_status == CS_PORT_UNAVAILABLE)) {
2406fcf3ce44SJohn Forte 				sp->ha->adapter_stats->d_stats[lobyte(
2407fcf3ce44SJohn Forte 				    tq->loop_id)].logouts_recvd++;
2408fcf3ce44SJohn Forte 				ql_send_logo(sp->ha, tq, done_q);
2409fcf3ce44SJohn Forte 			}
2410fcf3ce44SJohn Forte 
2411fcf3ce44SJohn Forte 			ADAPTER_STATE_LOCK(ha);
2412fcf3ce44SJohn Forte 			if (ha->port_retry_timer == 0) {
2413fcf3ce44SJohn Forte 				if ((ha->port_retry_timer =
2414fcf3ce44SJohn Forte 				    ha->port_down_retry_delay) == 0) {
2415fcf3ce44SJohn Forte 					*set_flags |=
2416fcf3ce44SJohn Forte 					    PORT_RETRY_NEEDED;
2417fcf3ce44SJohn Forte 				}
2418fcf3ce44SJohn Forte 			}
2419fcf3ce44SJohn Forte 			ADAPTER_STATE_UNLOCK(ha);
2420fcf3ce44SJohn Forte 		}
2421fcf3ce44SJohn Forte 	} else if (!(tq->flags & TQF_TAPE_DEVICE) &&
2422fcf3ce44SJohn Forte 	    (sts.comp_status == CS_RESET ||
2423fcf3ce44SJohn Forte 	    (sts.comp_status == CS_QUEUE_FULL && tq->qfull_retry_count != 0) ||
2424fcf3ce44SJohn Forte 	    (sts.comp_status == CS_ABORTED && !(sp->flags & SRB_ABORTING)))) {
2425fcf3ce44SJohn Forte 		if (sts.comp_status == CS_RESET) {
2426fcf3ce44SJohn Forte 			EL(sp->ha, "Reset Retry, d_id=%xh, lun=%xh\n",
2427fcf3ce44SJohn Forte 			    tq->d_id.b24, sp->lun_queue->lun_no);
2428fcf3ce44SJohn Forte 		} else if (sts.comp_status == CS_QUEUE_FULL) {
2429fcf3ce44SJohn Forte 			EL(sp->ha, "Queue Full Retry, d_id=%xh, lun=%xh, "
2430fcf3ce44SJohn Forte 			    "cnt=%d\n", tq->d_id.b24, sp->lun_queue->lun_no,
2431fcf3ce44SJohn Forte 			    tq->qfull_retry_count);
2432fcf3ce44SJohn Forte 			if ((tq->flags & TQF_QUEUE_SUSPENDED) == 0) {
2433fcf3ce44SJohn Forte 				tq->flags |= TQF_QUEUE_SUSPENDED;
2434fcf3ce44SJohn Forte 
2435fcf3ce44SJohn Forte 				tq->qfull_retry_count--;
2436fcf3ce44SJohn Forte 
2437fcf3ce44SJohn Forte 				ADAPTER_STATE_LOCK(ha);
2438fcf3ce44SJohn Forte 				if (ha->port_retry_timer == 0) {
2439fcf3ce44SJohn Forte 					if ((ha->port_retry_timer =
2440fcf3ce44SJohn Forte 					    ha->qfull_retry_delay) ==
2441fcf3ce44SJohn Forte 					    0) {
2442fcf3ce44SJohn Forte 						*set_flags |=
2443fcf3ce44SJohn Forte 						    PORT_RETRY_NEEDED;
2444fcf3ce44SJohn Forte 					}
2445fcf3ce44SJohn Forte 				}
2446fcf3ce44SJohn Forte 				ADAPTER_STATE_UNLOCK(ha);
2447fcf3ce44SJohn Forte 			}
2448fcf3ce44SJohn Forte 		} else {
2449fcf3ce44SJohn Forte 			EL(sp->ha, "Abort Retry, d_id=%xh, lun=%xh\n",
2450fcf3ce44SJohn Forte 			    tq->d_id.b24, sp->lun_queue->lun_no);
2451fcf3ce44SJohn Forte 		}
2452fcf3ce44SJohn Forte 
2453fcf3ce44SJohn Forte 		/* Set retry status. */
2454fcf3ce44SJohn Forte 		sp->flags |= SRB_RETRY;
2455fcf3ce44SJohn Forte 	} else {
2456fcf3ce44SJohn Forte 		fcpr->fcp_resid =
2457fcf3ce44SJohn Forte 		    sts.fcp_residual_length > sp->fcp->fcp_data_len ?
2458fcf3ce44SJohn Forte 		    sp->fcp->fcp_data_len : sts.fcp_residual_length;
2459fcf3ce44SJohn Forte 
2460fcf3ce44SJohn Forte 		if ((sts.comp_status == CS_DATA_UNDERRUN) &&
2461fcf3ce44SJohn Forte 		    (sts.scsi_status_h & FCP_RESID_UNDER) == 0) {
2462fcf3ce44SJohn Forte 
2463fcf3ce44SJohn Forte 			if (sts.scsi_status_l == STATUS_CHECK) {
2464fcf3ce44SJohn Forte 				sp->pkt->pkt_reason = CS_COMPLETE;
2465fcf3ce44SJohn Forte 			} else {
2466fcf3ce44SJohn Forte 				EL(ha, "transport error - "
2467fcf3ce44SJohn Forte 				    "underrun & invalid resid\n");
2468fcf3ce44SJohn Forte 				EL(ha, "ssh=%xh, ssl=%xh\n",
2469fcf3ce44SJohn Forte 				    sts.scsi_status_h, sts.scsi_status_l);
2470fcf3ce44SJohn Forte 				sp->pkt->pkt_reason = CS_FCP_RESPONSE_ERROR;
2471fcf3ce44SJohn Forte 			}
2472fcf3ce44SJohn Forte 		}
2473fcf3ce44SJohn Forte 
2474fcf3ce44SJohn Forte 		/* Ignore firmware underrun error. */
2475fcf3ce44SJohn Forte 		if (sts.comp_status == CS_DATA_UNDERRUN &&
2476fcf3ce44SJohn Forte 		    (sts.scsi_status_h & FCP_RESID_UNDER ||
2477fcf3ce44SJohn Forte 		    (sts.scsi_status_l != STATUS_CHECK &&
2478fcf3ce44SJohn Forte 		    sts.scsi_status_l != STATUS_GOOD))) {
2479fcf3ce44SJohn Forte 			sp->pkt->pkt_reason = CS_COMPLETE;
2480fcf3ce44SJohn Forte 		}
2481fcf3ce44SJohn Forte 
2482fcf3ce44SJohn Forte 		if (sp->pkt->pkt_reason != CS_COMPLETE) {
2483fcf3ce44SJohn Forte 			ha->xioctl->DeviceErrorCount++;
2484fcf3ce44SJohn Forte 			EL(sp->ha, "Cmplt status err = %xh, d_id=%xh, lun=%xh"
2485fcf3ce44SJohn Forte 			    "\n", sts.comp_status, tq->d_id.b24,
2486fcf3ce44SJohn Forte 			    sp->lun_queue->lun_no);
2487fcf3ce44SJohn Forte 		}
2488fcf3ce44SJohn Forte 
2489fcf3ce44SJohn Forte 		/* Set target request sense data. */
2490fcf3ce44SJohn Forte 		if (sts.scsi_status_l == STATUS_CHECK) {
2491fcf3ce44SJohn Forte 			if (sts.scsi_status_h & FCP_SNS_LEN_VALID) {
2492fcf3ce44SJohn Forte 
2493fcf3ce44SJohn Forte 				if (sp->pkt->pkt_reason == CS_COMPLETE &&
2494fcf3ce44SJohn Forte 				    sts.req_sense_data[2] != KEY_NO_SENSE &&
2495fcf3ce44SJohn Forte 				    sts.req_sense_data[2] !=
2496fcf3ce44SJohn Forte 				    KEY_UNIT_ATTENTION) {
2497fcf3ce44SJohn Forte 					ha->xioctl->DeviceErrorCount++;
2498fcf3ce44SJohn Forte 				}
2499fcf3ce44SJohn Forte 
2500fcf3ce44SJohn Forte 				sense_sz = sts.req_sense_length;
2501fcf3ce44SJohn Forte 
2502fcf3ce44SJohn Forte 				/* Insure data does not exceed buf. */
2503fcf3ce44SJohn Forte 				if (sp->pkt->pkt_rsplen <=
2504fcf3ce44SJohn Forte 				    (uint32_t)sizeof (fcp_rsp_t) +
2505fcf3ce44SJohn Forte 				    fcpr->fcp_response_len) {
2506fcf3ce44SJohn Forte 					sp->request_sense_length = 0;
2507fcf3ce44SJohn Forte 				} else {
2508fcf3ce44SJohn Forte 					sp->request_sense_length = (uint32_t)
2509fcf3ce44SJohn Forte 					    (sp->pkt->pkt_rsplen -
2510fcf3ce44SJohn Forte 					    sizeof (fcp_rsp_t) -
2511fcf3ce44SJohn Forte 					    fcpr->fcp_response_len);
2512fcf3ce44SJohn Forte 				}
2513fcf3ce44SJohn Forte 
2514fcf3ce44SJohn Forte 				if (sense_sz <
2515fcf3ce44SJohn Forte 				    sp->request_sense_length) {
2516fcf3ce44SJohn Forte 					sp->request_sense_length =
2517fcf3ce44SJohn Forte 					    sense_sz;
2518fcf3ce44SJohn Forte 				}
2519fcf3ce44SJohn Forte 
2520fcf3ce44SJohn Forte 				sp->request_sense_ptr = (caddr_t)rsp;
2521fcf3ce44SJohn Forte 
2522fcf3ce44SJohn Forte 				sense_sz = (uint32_t)
2523fcf3ce44SJohn Forte 				    (((uintptr_t)pkt23 +
2524fcf3ce44SJohn Forte 				    sizeof (sts_entry_t)) -
2525fcf3ce44SJohn Forte 				    (uintptr_t)sts.req_sense_data);
2526fcf3ce44SJohn Forte 				if (sp->request_sense_length <
2527fcf3ce44SJohn Forte 				    sense_sz) {
2528fcf3ce44SJohn Forte 					sense_sz =
2529fcf3ce44SJohn Forte 					    sp->request_sense_length;
2530fcf3ce44SJohn Forte 				}
2531fcf3ce44SJohn Forte 
2532fcf3ce44SJohn Forte 				fcpr->fcp_sense_len = sense_sz;
2533fcf3ce44SJohn Forte 
2534fcf3ce44SJohn Forte 				/* Move sense data. */
2535fcf3ce44SJohn Forte 				ddi_rep_get8(ha->hba_buf.acc_handle,
2536fcf3ce44SJohn Forte 				    (uint8_t *)sp->request_sense_ptr,
2537fcf3ce44SJohn Forte 				    sts.req_sense_data,
2538fcf3ce44SJohn Forte 				    (size_t)sense_sz,
2539fcf3ce44SJohn Forte 				    DDI_DEV_AUTOINCR);
2540fcf3ce44SJohn Forte 
2541fcf3ce44SJohn Forte 				sp->request_sense_ptr += sense_sz;
2542fcf3ce44SJohn Forte 				sp->request_sense_length -= sense_sz;
2543eb82ff87SDaniel Beauregard 				if (sp->request_sense_length != 0 &&
2544eb82ff87SDaniel Beauregard 				    !(CFG_IST(ha, CFG_CTRL_8021))) {
2545fcf3ce44SJohn Forte 					ha->status_srb = sp;
2546fcf3ce44SJohn Forte 				}
2547fcf3ce44SJohn Forte 			}
2548fcf3ce44SJohn Forte 
2549fcf3ce44SJohn Forte 			if (sense_sz != 0) {
2550fcf3ce44SJohn Forte 				EL(sp->ha, "check condition sense data, "
2551fcf3ce44SJohn Forte 				    "d_id=%xh, lun=%xh\n%2xh%3xh%3xh%3xh"
2552fcf3ce44SJohn Forte 				    "%3xh%3xh%3xh%3xh%3xh%3xh%3xh%3xh%3xh"
2553fcf3ce44SJohn Forte 				    "%3xh%3xh%3xh%3xh%3xh\n", tq->d_id.b24,
2554fcf3ce44SJohn Forte 				    sp->lun_queue->lun_no,
2555fcf3ce44SJohn Forte 				    sts.req_sense_data[0],
2556fcf3ce44SJohn Forte 				    sts.req_sense_data[1],
2557fcf3ce44SJohn Forte 				    sts.req_sense_data[2],
2558fcf3ce44SJohn Forte 				    sts.req_sense_data[3],
2559fcf3ce44SJohn Forte 				    sts.req_sense_data[4],
2560fcf3ce44SJohn Forte 				    sts.req_sense_data[5],
2561fcf3ce44SJohn Forte 				    sts.req_sense_data[6],
2562fcf3ce44SJohn Forte 				    sts.req_sense_data[7],
2563fcf3ce44SJohn Forte 				    sts.req_sense_data[8],
2564fcf3ce44SJohn Forte 				    sts.req_sense_data[9],
2565fcf3ce44SJohn Forte 				    sts.req_sense_data[10],
2566fcf3ce44SJohn Forte 				    sts.req_sense_data[11],
2567fcf3ce44SJohn Forte 				    sts.req_sense_data[12],
2568fcf3ce44SJohn Forte 				    sts.req_sense_data[13],
2569fcf3ce44SJohn Forte 				    sts.req_sense_data[14],
2570fcf3ce44SJohn Forte 				    sts.req_sense_data[15],
2571fcf3ce44SJohn Forte 				    sts.req_sense_data[16],
2572fcf3ce44SJohn Forte 				    sts.req_sense_data[17]);
2573fcf3ce44SJohn Forte 			} else {
2574fcf3ce44SJohn Forte 				EL(sp->ha, "check condition, d_id=%xh, lun=%xh"
2575fcf3ce44SJohn Forte 				    "\n", tq->d_id.b24, sp->lun_queue->lun_no);
2576fcf3ce44SJohn Forte 			}
2577fcf3ce44SJohn Forte 		}
2578fcf3ce44SJohn Forte 	}
2579fcf3ce44SJohn Forte 
2580fcf3ce44SJohn Forte 	/* Set completed status. */
2581fcf3ce44SJohn Forte 	sp->flags |= SRB_ISP_COMPLETED;
2582fcf3ce44SJohn Forte 
2583fcf3ce44SJohn Forte 	/* Place command on done queue. */
2584fcf3ce44SJohn Forte 	if (ha->status_srb == NULL) {
2585fcf3ce44SJohn Forte 		ql_add_link_b(done_q, &sp->cmd);
2586fcf3ce44SJohn Forte 	}
2587fcf3ce44SJohn Forte 
2588fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
2589fcf3ce44SJohn Forte 
2590fcf3ce44SJohn Forte 	return (rval);
2591fcf3ce44SJohn Forte }
2592fcf3ce44SJohn Forte 
2593fcf3ce44SJohn Forte /*
2594fcf3ce44SJohn Forte  * ql_status_cont_entry
2595fcf3ce44SJohn Forte  *	Processes status continuation entry.
2596fcf3ce44SJohn Forte  *
2597fcf3ce44SJohn Forte  * Input:
2598fcf3ce44SJohn Forte  *	ha:		adapter state pointer.
2599fcf3ce44SJohn Forte  *	pkt:		entry pointer.
2600fcf3ce44SJohn Forte  *	done_q:		done queue pointer.
2601fcf3ce44SJohn Forte  *	set_flags:	task daemon flags to set.
2602fcf3ce44SJohn Forte  *	reset_flags:	task daemon flags to reset.
2603fcf3ce44SJohn Forte  *
2604fcf3ce44SJohn Forte  * Context:
2605fcf3ce44SJohn Forte  *	Interrupt or Kernel context, no mailbox commands allowed.
2606fcf3ce44SJohn Forte  */
2607fcf3ce44SJohn Forte /* ARGSUSED */
2608fcf3ce44SJohn Forte static void
2609fcf3ce44SJohn Forte ql_status_cont_entry(ql_adapter_state_t *ha, sts_cont_entry_t *pkt,
2610fcf3ce44SJohn Forte     ql_head_t *done_q, uint32_t *set_flags, uint32_t *reset_flags)
2611fcf3ce44SJohn Forte {
2612fcf3ce44SJohn Forte 	uint32_t	sense_sz, index;
2613fcf3ce44SJohn Forte 	ql_srb_t	*sp = ha->status_srb;
2614fcf3ce44SJohn Forte 
2615fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
2616fcf3ce44SJohn Forte 
2617fcf3ce44SJohn Forte 	if (sp != NULL && sp->request_sense_length) {
2618fcf3ce44SJohn Forte 		if (sp->request_sense_length > sizeof (pkt->req_sense_data)) {
2619fcf3ce44SJohn Forte 			sense_sz = sizeof (pkt->req_sense_data);
2620fcf3ce44SJohn Forte 		} else {
2621fcf3ce44SJohn Forte 			sense_sz = sp->request_sense_length;
2622fcf3ce44SJohn Forte 		}
2623fcf3ce44SJohn Forte 
2624eb82ff87SDaniel Beauregard 		if (CFG_IST(ha, CFG_CTRL_24258081)) {
2625fcf3ce44SJohn Forte 			for (index = 0; index < sense_sz; index += 4) {
2626fcf3ce44SJohn Forte 				ql_chg_endian((uint8_t *)
2627fcf3ce44SJohn Forte 				    &pkt->req_sense_data[0] + index, 4);
2628fcf3ce44SJohn Forte 			}
2629fcf3ce44SJohn Forte 		}
2630fcf3ce44SJohn Forte 
2631fcf3ce44SJohn Forte 		/* Move sense data. */
2632fcf3ce44SJohn Forte 		ddi_rep_get8(ha->hba_buf.acc_handle,
2633fcf3ce44SJohn Forte 		    (uint8_t *)sp->request_sense_ptr,
2634fcf3ce44SJohn Forte 		    (uint8_t *)&pkt->req_sense_data[0], (size_t)sense_sz,
2635fcf3ce44SJohn Forte 		    DDI_DEV_AUTOINCR);
2636fcf3ce44SJohn Forte 
2637fcf3ce44SJohn Forte 		sp->request_sense_ptr += sense_sz;
2638fcf3ce44SJohn Forte 		sp->request_sense_length -= sense_sz;
2639fcf3ce44SJohn Forte 
2640fcf3ce44SJohn Forte 		/* Place command on done queue. */
2641fcf3ce44SJohn Forte 		if (sp->request_sense_length == 0) {
2642fcf3ce44SJohn Forte 			ql_add_link_b(done_q, &sp->cmd);
2643fcf3ce44SJohn Forte 			ha->status_srb = NULL;
2644fcf3ce44SJohn Forte 		}
2645fcf3ce44SJohn Forte 	}
2646fcf3ce44SJohn Forte 
2647fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
2648fcf3ce44SJohn Forte }
2649fcf3ce44SJohn Forte 
2650fcf3ce44SJohn Forte /*
2651fcf3ce44SJohn Forte  * ql_ip_entry
2652fcf3ce44SJohn Forte  *	Processes received ISP IP entry.
2653fcf3ce44SJohn Forte  *
2654fcf3ce44SJohn Forte  * Input:
2655fcf3ce44SJohn Forte  *	ha:		adapter state pointer.
2656fcf3ce44SJohn Forte  *	pkt:		entry pointer.
2657fcf3ce44SJohn Forte  *	done_q:		done queue pointer.
2658fcf3ce44SJohn Forte  *	set_flags:	task daemon flags to set.
2659fcf3ce44SJohn Forte  *	reset_flags:	task daemon flags to reset.
2660fcf3ce44SJohn Forte  *
2661fcf3ce44SJohn Forte  * Context:
2662fcf3ce44SJohn Forte  *	Interrupt or Kernel context, no mailbox commands allowed.
2663fcf3ce44SJohn Forte  */
2664fcf3ce44SJohn Forte /* ARGSUSED */
2665fcf3ce44SJohn Forte static void
2666fcf3ce44SJohn Forte ql_ip_entry(ql_adapter_state_t *ha, ip_entry_t *pkt23, ql_head_t *done_q,
2667fcf3ce44SJohn Forte     uint32_t *set_flags, uint32_t *reset_flags)
2668fcf3ce44SJohn Forte {
2669fcf3ce44SJohn Forte 	ql_srb_t	*sp;
2670a2b3ff35SDaniel Beauregard 	uint32_t	index, resp_identifier;
2671fcf3ce44SJohn Forte 	ql_tgt_t	*tq;
2672fcf3ce44SJohn Forte 
2673fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
2674fcf3ce44SJohn Forte 
2675a2b3ff35SDaniel Beauregard 	/* Validate the response entry handle. */
2676a2b3ff35SDaniel Beauregard 	resp_identifier = ddi_get32(ha->hba_buf.acc_handle, &pkt23->handle);
2677a2b3ff35SDaniel Beauregard 	index = resp_identifier & OSC_INDEX_MASK;
2678a2b3ff35SDaniel Beauregard 	if (index < MAX_OUTSTANDING_COMMANDS) {
2679a2b3ff35SDaniel Beauregard 		/* the index seems reasonable */
2680a2b3ff35SDaniel Beauregard 		sp = ha->outstanding_cmds[index];
2681a2b3ff35SDaniel Beauregard 		if (sp != NULL) {
2682a2b3ff35SDaniel Beauregard 			if (sp->handle == resp_identifier) {
2683a2b3ff35SDaniel Beauregard 				/* Neo, you're the one... */
2684a2b3ff35SDaniel Beauregard 				ha->outstanding_cmds[index] = NULL;
2685a2b3ff35SDaniel Beauregard 				sp->handle = 0;
2686a2b3ff35SDaniel Beauregard 				sp->flags &= ~SRB_IN_TOKEN_ARRAY;
2687a2b3ff35SDaniel Beauregard 			} else {
2688a2b3ff35SDaniel Beauregard 				EL(ha, "IOCB handle mismatch pkt=%xh, sp=%xh\n",
2689a2b3ff35SDaniel Beauregard 				    resp_identifier, sp->handle);
2690a2b3ff35SDaniel Beauregard 				sp = NULL;
2691a2b3ff35SDaniel Beauregard 				ql_signal_abort(ha, set_flags);
2692a2b3ff35SDaniel Beauregard 			}
2693a2b3ff35SDaniel Beauregard 		} else {
2694a2b3ff35SDaniel Beauregard 			sp = ql_verify_preprocessed_cmd(ha,
2695a2b3ff35SDaniel Beauregard 			    (uint32_t *)&pkt23->handle, set_flags, reset_flags);
2696a2b3ff35SDaniel Beauregard 		}
2697a2b3ff35SDaniel Beauregard 	} else {
2698a2b3ff35SDaniel Beauregard 		EL(ha, "osc index out of range, index=%xh, handle=%xh\n",
2699a2b3ff35SDaniel Beauregard 		    index, resp_identifier);
2700a2b3ff35SDaniel Beauregard 		ql_signal_abort(ha, set_flags);
2701a2b3ff35SDaniel Beauregard 	}
2702fcf3ce44SJohn Forte 
2703a2b3ff35SDaniel Beauregard 	if (sp != NULL) {
2704fcf3ce44SJohn Forte 		tq = sp->lun_queue->target_queue;
2705fcf3ce44SJohn Forte 
2706fcf3ce44SJohn Forte 		/* Set ISP completion status */
2707eb82ff87SDaniel Beauregard 		if (CFG_IST(ha, CFG_CTRL_24258081)) {
2708fcf3ce44SJohn Forte 			ip_cmd_entry_t	*pkt24 = (ip_cmd_entry_t *)pkt23;
2709fcf3ce44SJohn Forte 
2710fcf3ce44SJohn Forte 			sp->pkt->pkt_reason = ddi_get16(
2711fcf3ce44SJohn Forte 			    ha->hba_buf.acc_handle, &pkt24->hdl_status);
2712fcf3ce44SJohn Forte 		} else {
2713fcf3ce44SJohn Forte 			sp->pkt->pkt_reason = ddi_get16(
2714fcf3ce44SJohn Forte 			    ha->hba_buf.acc_handle, &pkt23->comp_status);
2715fcf3ce44SJohn Forte 		}
2716fcf3ce44SJohn Forte 
2717fcf3ce44SJohn Forte 		if (ha->task_daemon_flags & LOOP_DOWN) {
2718fcf3ce44SJohn Forte 			EL(ha, "Loop Not Ready Retry, d_id=%xh\n",
2719fcf3ce44SJohn Forte 			    tq->d_id.b24);
2720fcf3ce44SJohn Forte 
2721fcf3ce44SJohn Forte 			/* Set retry status. */
2722fcf3ce44SJohn Forte 			sp->flags |= SRB_RETRY;
2723fcf3ce44SJohn Forte 
2724fcf3ce44SJohn Forte 		} else if (tq->port_down_retry_count &&
2725fcf3ce44SJohn Forte 		    (sp->pkt->pkt_reason == CS_INCOMPLETE ||
2726fcf3ce44SJohn Forte 		    sp->pkt->pkt_reason == CS_PORT_UNAVAILABLE ||
2727fcf3ce44SJohn Forte 		    sp->pkt->pkt_reason == CS_PORT_LOGGED_OUT ||
2728fcf3ce44SJohn Forte 		    sp->pkt->pkt_reason == CS_PORT_CONFIG_CHG ||
2729fcf3ce44SJohn Forte 		    sp->pkt->pkt_reason == CS_PORT_BUSY)) {
2730fcf3ce44SJohn Forte 			EL(ha, "Port Down Retry=%xh, d_id=%xh, count=%d\n",
2731fcf3ce44SJohn Forte 			    sp->pkt->pkt_reason, tq->d_id.b24,
2732fcf3ce44SJohn Forte 			    tq->port_down_retry_count);
2733fcf3ce44SJohn Forte 
2734fcf3ce44SJohn Forte 			/* Set retry status. */
2735fcf3ce44SJohn Forte 			sp->flags |= SRB_RETRY;
2736fcf3ce44SJohn Forte 
2737fcf3ce44SJohn Forte 			if (sp->pkt->pkt_reason == CS_PORT_LOGGED_OUT ||
2738fcf3ce44SJohn Forte 			    sp->pkt->pkt_reason == CS_PORT_UNAVAILABLE) {
2739fcf3ce44SJohn Forte 				ha->adapter_stats->d_stats[lobyte(
2740fcf3ce44SJohn Forte 				    tq->loop_id)].logouts_recvd++;
2741fcf3ce44SJohn Forte 				ql_send_logo(ha, tq, done_q);
2742fcf3ce44SJohn Forte 			}
2743fcf3ce44SJohn Forte 
2744fcf3ce44SJohn Forte 			/* Acquire device queue lock. */
2745fcf3ce44SJohn Forte 			DEVICE_QUEUE_LOCK(tq);
2746fcf3ce44SJohn Forte 
2747fcf3ce44SJohn Forte 			if ((tq->flags & TQF_QUEUE_SUSPENDED) == 0) {
2748fcf3ce44SJohn Forte 				tq->flags |= TQF_QUEUE_SUSPENDED;
2749fcf3ce44SJohn Forte 
2750fcf3ce44SJohn Forte 				tq->port_down_retry_count--;
2751fcf3ce44SJohn Forte 
2752fcf3ce44SJohn Forte 				ADAPTER_STATE_LOCK(ha);
2753fcf3ce44SJohn Forte 				if (ha->port_retry_timer == 0) {
2754fcf3ce44SJohn Forte 					if ((ha->port_retry_timer =
2755fcf3ce44SJohn Forte 					    ha->port_down_retry_delay) == 0) {
2756fcf3ce44SJohn Forte 						*set_flags |=
2757fcf3ce44SJohn Forte 						    PORT_RETRY_NEEDED;
2758fcf3ce44SJohn Forte 					}
2759fcf3ce44SJohn Forte 				}
2760fcf3ce44SJohn Forte 				ADAPTER_STATE_UNLOCK(ha);
2761fcf3ce44SJohn Forte 			}
2762fcf3ce44SJohn Forte 
2763fcf3ce44SJohn Forte 			/* Release device queue specific lock. */
2764fcf3ce44SJohn Forte 			DEVICE_QUEUE_UNLOCK(tq);
2765fcf3ce44SJohn Forte 
2766fcf3ce44SJohn Forte 		} else if (sp->pkt->pkt_reason == CS_RESET) {
2767fcf3ce44SJohn Forte 			EL(ha, "Reset Retry, d_id=%xh\n", tq->d_id.b24);
2768fcf3ce44SJohn Forte 
2769fcf3ce44SJohn Forte 			/* Set retry status. */
2770fcf3ce44SJohn Forte 			sp->flags |= SRB_RETRY;
2771fcf3ce44SJohn Forte 		} else {
2772fcf3ce44SJohn Forte 			if (sp->pkt->pkt_reason != CS_COMPLETE) {
2773fcf3ce44SJohn Forte 				EL(ha, "Cmplt status err=%xh, d_id=%xh\n",
2774fcf3ce44SJohn Forte 				    sp->pkt->pkt_reason, tq->d_id.b24);
2775fcf3ce44SJohn Forte 			}
2776fcf3ce44SJohn Forte 		}
2777fcf3ce44SJohn Forte 
2778fcf3ce44SJohn Forte 		/* Set completed status. */
2779fcf3ce44SJohn Forte 		sp->flags |= SRB_ISP_COMPLETED;
2780fcf3ce44SJohn Forte 
2781fcf3ce44SJohn Forte 		ql_add_link_b(done_q, &sp->cmd);
2782fcf3ce44SJohn Forte 
2783fcf3ce44SJohn Forte 	}
2784fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
2785fcf3ce44SJohn Forte }
2786fcf3ce44SJohn Forte 
2787fcf3ce44SJohn Forte /*
2788fcf3ce44SJohn Forte  * ql_ip_rcv_entry
2789fcf3ce44SJohn Forte  *	Processes received ISP IP buffers entry.
2790fcf3ce44SJohn Forte  *
2791fcf3ce44SJohn Forte  * Input:
2792fcf3ce44SJohn Forte  *	ha:		adapter state pointer.
2793fcf3ce44SJohn Forte  *	pkt:		entry pointer.
2794fcf3ce44SJohn Forte  *	done_q:		done queue pointer.
2795fcf3ce44SJohn Forte  *	set_flags:	task daemon flags to set.
2796fcf3ce44SJohn Forte  *	reset_flags:	task daemon flags to reset.
2797fcf3ce44SJohn Forte  *
2798fcf3ce44SJohn Forte  * Context:
2799fcf3ce44SJohn Forte  *	Interrupt or Kernel context, no mailbox commands allowed.
2800fcf3ce44SJohn Forte  */
2801fcf3ce44SJohn Forte /* ARGSUSED */
2802fcf3ce44SJohn Forte static void
2803fcf3ce44SJohn Forte ql_ip_rcv_entry(ql_adapter_state_t *ha, ip_rcv_entry_t *pkt,
2804fcf3ce44SJohn Forte     ql_head_t *done_q, uint32_t *set_flags, uint32_t *reset_flags)
2805fcf3ce44SJohn Forte {
2806fcf3ce44SJohn Forte 	port_id_t	s_id;
2807fcf3ce44SJohn Forte 	uint16_t	index;
2808fcf3ce44SJohn Forte 	uint8_t		cnt;
2809fcf3ce44SJohn Forte 	ql_tgt_t	*tq;
2810fcf3ce44SJohn Forte 
2811fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
2812fcf3ce44SJohn Forte 
2813fcf3ce44SJohn Forte 	/* Locate device queue. */
2814fcf3ce44SJohn Forte 	s_id.b.al_pa = pkt->s_id[0];
2815fcf3ce44SJohn Forte 	s_id.b.area = pkt->s_id[1];
2816fcf3ce44SJohn Forte 	s_id.b.domain = pkt->s_id[2];
2817fcf3ce44SJohn Forte 	if ((tq = ql_d_id_to_queue(ha, s_id)) == NULL) {
2818fcf3ce44SJohn Forte 		EL(ha, "Unknown IP device ID=%xh\n", s_id.b24);
2819fcf3ce44SJohn Forte 		return;
2820fcf3ce44SJohn Forte 	}
2821fcf3ce44SJohn Forte 
2822fcf3ce44SJohn Forte 	tq->ub_sequence_length = (uint16_t)ddi_get16(ha->hba_buf.acc_handle,
2823fcf3ce44SJohn Forte 	    &pkt->seq_length);
2824fcf3ce44SJohn Forte 	tq->ub_total_seg_cnt = pkt->segment_count;
2825fcf3ce44SJohn Forte 	tq->ub_seq_id = ++ha->ub_seq_id;
2826fcf3ce44SJohn Forte 	tq->ub_seq_cnt = 0;
2827fcf3ce44SJohn Forte 	tq->ub_frame_ro = 0;
2828fcf3ce44SJohn Forte 	tq->ub_loop_id = pkt->loop_id;
2829fcf3ce44SJohn Forte 	ha->rcv_dev_q = tq;
2830fcf3ce44SJohn Forte 
2831fcf3ce44SJohn Forte 	for (cnt = 0; cnt < IP_RCVBUF_HANDLES && tq->ub_seq_cnt <
2832fcf3ce44SJohn Forte 	    tq->ub_total_seg_cnt; cnt++) {
2833fcf3ce44SJohn Forte 
2834fcf3ce44SJohn Forte 		index = (uint16_t)ddi_get16(ha->hba_buf.acc_handle,
2835fcf3ce44SJohn Forte 		    &pkt->buffer_handle[cnt]);
2836fcf3ce44SJohn Forte 
2837fcf3ce44SJohn Forte 		if (ql_ub_frame_hdr(ha, tq, index, done_q) != QL_SUCCESS) {
2838fcf3ce44SJohn Forte 			EL(ha, "ql_ub_frame_hdr failed, isp_abort_needed\n");
2839fcf3ce44SJohn Forte 			*set_flags |= ISP_ABORT_NEEDED;
2840fcf3ce44SJohn Forte 			break;
2841fcf3ce44SJohn Forte 		}
2842fcf3ce44SJohn Forte 	}
2843fcf3ce44SJohn Forte 
2844fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
2845fcf3ce44SJohn Forte }
2846fcf3ce44SJohn Forte 
2847fcf3ce44SJohn Forte /*
2848fcf3ce44SJohn Forte  * ql_ip_rcv_cont_entry
2849fcf3ce44SJohn Forte  *	Processes received ISP IP buffers continuation entry.
2850fcf3ce44SJohn Forte  *
2851fcf3ce44SJohn Forte  * Input:
2852fcf3ce44SJohn Forte  *	ha:		adapter state pointer.
2853fcf3ce44SJohn Forte  *	pkt:		entry pointer.
2854fcf3ce44SJohn Forte  *	done_q:		done queue pointer.
2855fcf3ce44SJohn Forte  *	set_flags:	task daemon flags to set.
2856fcf3ce44SJohn Forte  *	reset_flags:	task daemon flags to reset.
2857fcf3ce44SJohn Forte  *
2858fcf3ce44SJohn Forte  * Context:
2859fcf3ce44SJohn Forte  *	Interrupt or Kernel context, no mailbox commands allowed.
2860fcf3ce44SJohn Forte  */
2861fcf3ce44SJohn Forte /* ARGSUSED */
2862fcf3ce44SJohn Forte static void
2863fcf3ce44SJohn Forte ql_ip_rcv_cont_entry(ql_adapter_state_t *ha, ip_rcv_cont_entry_t *pkt,
2864fcf3ce44SJohn Forte     ql_head_t *done_q, uint32_t *set_flags, uint32_t *reset_flags)
2865fcf3ce44SJohn Forte {
2866fcf3ce44SJohn Forte 	uint16_t	index;
2867fcf3ce44SJohn Forte 	uint8_t		cnt;
2868fcf3ce44SJohn Forte 	ql_tgt_t	*tq;
2869fcf3ce44SJohn Forte 
2870fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
2871fcf3ce44SJohn Forte 
2872fcf3ce44SJohn Forte 	if ((tq = ha->rcv_dev_q) == NULL) {
2873fcf3ce44SJohn Forte 		EL(ha, "No IP receive device\n");
2874fcf3ce44SJohn Forte 		return;
2875fcf3ce44SJohn Forte 	}
2876fcf3ce44SJohn Forte 
2877fcf3ce44SJohn Forte 	for (cnt = 0; cnt < IP_RCVBUF_CONT_HANDLES &&
2878fcf3ce44SJohn Forte 	    tq->ub_seq_cnt < tq->ub_total_seg_cnt; cnt++) {
2879fcf3ce44SJohn Forte 
2880fcf3ce44SJohn Forte 		index = (uint16_t)ddi_get16(ha->hba_buf.acc_handle,
2881fcf3ce44SJohn Forte 		    &pkt->buffer_handle[cnt]);
2882fcf3ce44SJohn Forte 
2883fcf3ce44SJohn Forte 		if (ql_ub_frame_hdr(ha, tq, index, done_q) != QL_SUCCESS) {
2884fcf3ce44SJohn Forte 			EL(ha, "ql_ub_frame_hdr failed, isp_abort_needed\n");
2885fcf3ce44SJohn Forte 			*set_flags |= ISP_ABORT_NEEDED;
2886fcf3ce44SJohn Forte 			break;
2887fcf3ce44SJohn Forte 		}
2888fcf3ce44SJohn Forte 	}
2889fcf3ce44SJohn Forte 
2890fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
2891fcf3ce44SJohn Forte }
2892fcf3ce44SJohn Forte 
2893fcf3ce44SJohn Forte /*
2894fcf3ce44SJohn Forte  * ip_rcv_24xx_entry_t
2895fcf3ce44SJohn Forte  *	Processes received ISP24xx IP buffers entry.
2896fcf3ce44SJohn Forte  *
2897fcf3ce44SJohn Forte  * Input:
2898fcf3ce44SJohn Forte  *	ha:		adapter state pointer.
2899fcf3ce44SJohn Forte  *	pkt:		entry pointer.
2900fcf3ce44SJohn Forte  *	done_q:		done queue pointer.
2901fcf3ce44SJohn Forte  *	set_flags:	task daemon flags to set.
2902fcf3ce44SJohn Forte  *	reset_flags:	task daemon flags to reset.
2903fcf3ce44SJohn Forte  *
2904fcf3ce44SJohn Forte  * Context:
2905fcf3ce44SJohn Forte  *	Interrupt or Kernel context, no mailbox commands allowed.
2906fcf3ce44SJohn Forte  */
2907fcf3ce44SJohn Forte /* ARGSUSED */
2908fcf3ce44SJohn Forte static void
2909fcf3ce44SJohn Forte ql_ip_24xx_rcv_entry(ql_adapter_state_t *ha, ip_rcv_24xx_entry_t *pkt,
2910fcf3ce44SJohn Forte     ql_head_t *done_q, uint32_t *set_flags, uint32_t *reset_flags)
2911fcf3ce44SJohn Forte {
2912fcf3ce44SJohn Forte 	port_id_t	s_id;
2913fcf3ce44SJohn Forte 	uint16_t	index;
2914fcf3ce44SJohn Forte 	uint8_t		cnt;
2915fcf3ce44SJohn Forte 	ql_tgt_t	*tq;
2916fcf3ce44SJohn Forte 
2917fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
2918fcf3ce44SJohn Forte 
2919fcf3ce44SJohn Forte 	/* Locate device queue. */
2920fcf3ce44SJohn Forte 	s_id.b.al_pa = pkt->s_id[0];
2921fcf3ce44SJohn Forte 	s_id.b.area = pkt->s_id[1];
2922fcf3ce44SJohn Forte 	s_id.b.domain = pkt->s_id[2];
2923fcf3ce44SJohn Forte 	if ((tq = ql_d_id_to_queue(ha, s_id)) == NULL) {
2924fcf3ce44SJohn Forte 		EL(ha, "Unknown IP device ID=%xh\n", s_id.b24);
2925fcf3ce44SJohn Forte 		return;
2926fcf3ce44SJohn Forte 	}
2927fcf3ce44SJohn Forte 
2928fcf3ce44SJohn Forte 	if (tq->ub_total_seg_cnt == 0) {
2929fcf3ce44SJohn Forte 		tq->ub_sequence_length = (uint16_t)ddi_get16(
2930fcf3ce44SJohn Forte 		    ha->hba_buf.acc_handle, &pkt->seq_length);
2931fcf3ce44SJohn Forte 		tq->ub_total_seg_cnt = pkt->segment_count;
2932fcf3ce44SJohn Forte 		tq->ub_seq_id = ++ha->ub_seq_id;
2933fcf3ce44SJohn Forte 		tq->ub_seq_cnt = 0;
2934fcf3ce44SJohn Forte 		tq->ub_frame_ro = 0;
2935fcf3ce44SJohn Forte 		tq->ub_loop_id = (uint16_t)ddi_get16(
2936fcf3ce44SJohn Forte 		    ha->hba_buf.acc_handle, &pkt->n_port_hdl);
2937fcf3ce44SJohn Forte 	}
2938fcf3ce44SJohn Forte 
2939fcf3ce44SJohn Forte 	for (cnt = 0; cnt < IP_24XX_RCVBUF_HANDLES && tq->ub_seq_cnt <
2940fcf3ce44SJohn Forte 	    tq->ub_total_seg_cnt; cnt++) {
2941fcf3ce44SJohn Forte 
2942fcf3ce44SJohn Forte 		index = (uint16_t)ddi_get16(ha->hba_buf.acc_handle,
2943fcf3ce44SJohn Forte 		    &pkt->buffer_handle[cnt]);
2944fcf3ce44SJohn Forte 
2945fcf3ce44SJohn Forte 		if (ql_ub_frame_hdr(ha, tq, index, done_q) != QL_SUCCESS) {
2946fcf3ce44SJohn Forte 			EL(ha, "ql_ub_frame_hdr failed, isp_abort_needed\n");
2947fcf3ce44SJohn Forte 			*set_flags |= ISP_ABORT_NEEDED;
2948fcf3ce44SJohn Forte 			break;
2949fcf3ce44SJohn Forte 		}
2950fcf3ce44SJohn Forte 	}
2951fcf3ce44SJohn Forte 
2952fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
2953fcf3ce44SJohn Forte }
2954fcf3ce44SJohn Forte 
2955fcf3ce44SJohn Forte /*
2956fcf3ce44SJohn Forte  * ql_ms_entry
2957fcf3ce44SJohn Forte  *	Processes received Name/Management/CT Pass-Through entry.
2958fcf3ce44SJohn Forte  *
2959fcf3ce44SJohn Forte  * Input:
2960fcf3ce44SJohn Forte  *	ha:		adapter state pointer.
2961fcf3ce44SJohn Forte  *	pkt23:		entry pointer.
2962fcf3ce44SJohn Forte  *	done_q:		done queue pointer.
2963fcf3ce44SJohn Forte  *	set_flags:	task daemon flags to set.
2964fcf3ce44SJohn Forte  *	reset_flags:	task daemon flags to reset.
2965fcf3ce44SJohn Forte  *
2966fcf3ce44SJohn Forte  * Context:
2967fcf3ce44SJohn Forte  *	Interrupt or Kernel context, no mailbox commands allowed.
2968fcf3ce44SJohn Forte  */
2969fcf3ce44SJohn Forte /* ARGSUSED */
2970fcf3ce44SJohn Forte static void
2971fcf3ce44SJohn Forte ql_ms_entry(ql_adapter_state_t *ha, ms_entry_t *pkt23, ql_head_t *done_q,
2972fcf3ce44SJohn Forte     uint32_t *set_flags, uint32_t *reset_flags)
2973fcf3ce44SJohn Forte {
2974fcf3ce44SJohn Forte 	ql_srb_t		*sp;
2975a2b3ff35SDaniel Beauregard 	uint32_t		index, cnt, resp_identifier;
2976fcf3ce44SJohn Forte 	ql_tgt_t		*tq;
2977fcf3ce44SJohn Forte 	ct_passthru_entry_t	*pkt24 = (ct_passthru_entry_t *)pkt23;
2978fcf3ce44SJohn Forte 
2979fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
2980fcf3ce44SJohn Forte 
2981a2b3ff35SDaniel Beauregard 	/* Validate the response entry handle. */
2982a2b3ff35SDaniel Beauregard 	resp_identifier = ddi_get32(ha->hba_buf.acc_handle, &pkt23->handle);
2983a2b3ff35SDaniel Beauregard 	index = resp_identifier & OSC_INDEX_MASK;
2984a2b3ff35SDaniel Beauregard 	if (index < MAX_OUTSTANDING_COMMANDS) {
2985a2b3ff35SDaniel Beauregard 		/* the index seems reasonable */
2986a2b3ff35SDaniel Beauregard 		sp = ha->outstanding_cmds[index];
2987a2b3ff35SDaniel Beauregard 		if (sp != NULL) {
2988a2b3ff35SDaniel Beauregard 			if (sp->handle == resp_identifier) {
2989a2b3ff35SDaniel Beauregard 				/* Neo, you're the one... */
2990a2b3ff35SDaniel Beauregard 				ha->outstanding_cmds[index] = NULL;
2991a2b3ff35SDaniel Beauregard 				sp->handle = 0;
2992a2b3ff35SDaniel Beauregard 				sp->flags &= ~SRB_IN_TOKEN_ARRAY;
2993a2b3ff35SDaniel Beauregard 			} else {
2994a2b3ff35SDaniel Beauregard 				EL(ha, "IOCB handle mismatch pkt=%xh, sp=%xh\n",
2995a2b3ff35SDaniel Beauregard 				    resp_identifier, sp->handle);
2996a2b3ff35SDaniel Beauregard 				sp = NULL;
2997a2b3ff35SDaniel Beauregard 				ql_signal_abort(ha, set_flags);
2998a2b3ff35SDaniel Beauregard 			}
2999a2b3ff35SDaniel Beauregard 		} else {
3000a2b3ff35SDaniel Beauregard 			sp = ql_verify_preprocessed_cmd(ha,
3001a2b3ff35SDaniel Beauregard 			    (uint32_t *)&pkt23->handle, set_flags, reset_flags);
3002a2b3ff35SDaniel Beauregard 		}
3003a2b3ff35SDaniel Beauregard 	} else {
3004a2b3ff35SDaniel Beauregard 		EL(ha, "osc index out of range, index=%xh, handle=%xh\n",
3005a2b3ff35SDaniel Beauregard 		    index, resp_identifier);
3006a2b3ff35SDaniel Beauregard 		ql_signal_abort(ha, set_flags);
3007a2b3ff35SDaniel Beauregard 	}
3008fcf3ce44SJohn Forte 
3009a2b3ff35SDaniel Beauregard 	if (sp != NULL) {
3010fcf3ce44SJohn Forte 		if (!(sp->flags & SRB_MS_PKT)) {
3011fcf3ce44SJohn Forte 			EL(ha, "Not SRB_MS_PKT flags=%xh, isp_abort_needed",
3012fcf3ce44SJohn Forte 			    sp->flags);
3013fcf3ce44SJohn Forte 			*set_flags |= ISP_ABORT_NEEDED;
3014fcf3ce44SJohn Forte 			return;
3015fcf3ce44SJohn Forte 		}
3016fcf3ce44SJohn Forte 
3017fcf3ce44SJohn Forte 		tq = sp->lun_queue->target_queue;
3018fcf3ce44SJohn Forte 
3019fcf3ce44SJohn Forte 		/* Set ISP completion status */
3020eb82ff87SDaniel Beauregard 		if (CFG_IST(ha, CFG_CTRL_24258081)) {
3021fcf3ce44SJohn Forte 			sp->pkt->pkt_reason = ddi_get16(
3022fcf3ce44SJohn Forte 			    ha->hba_buf.acc_handle, &pkt24->status);
3023fcf3ce44SJohn Forte 		} else {
3024fcf3ce44SJohn Forte 			sp->pkt->pkt_reason = ddi_get16(
3025fcf3ce44SJohn Forte 			    ha->hba_buf.acc_handle, &pkt23->comp_status);
3026fcf3ce44SJohn Forte 		}
3027fcf3ce44SJohn Forte 
3028fcf3ce44SJohn Forte 		if (sp->pkt->pkt_reason == CS_RESOUCE_UNAVAILABLE &&
3029fcf3ce44SJohn Forte 		    sp->retry_count) {
3030fcf3ce44SJohn Forte 			EL(ha, "Resouce Unavailable Retry = %d\n",
3031fcf3ce44SJohn Forte 			    sp->retry_count);
3032fcf3ce44SJohn Forte 
3033fcf3ce44SJohn Forte 			/* Set retry status. */
3034fcf3ce44SJohn Forte 			sp->retry_count--;
3035fcf3ce44SJohn Forte 			sp->flags |= SRB_RETRY;
3036fcf3ce44SJohn Forte 
3037fcf3ce44SJohn Forte 			/* Acquire device queue lock. */
3038fcf3ce44SJohn Forte 			DEVICE_QUEUE_LOCK(tq);
3039fcf3ce44SJohn Forte 
3040fcf3ce44SJohn Forte 			if (!(tq->flags & TQF_QUEUE_SUSPENDED)) {
3041fcf3ce44SJohn Forte 				tq->flags |= TQF_QUEUE_SUSPENDED;
3042fcf3ce44SJohn Forte 
3043fcf3ce44SJohn Forte 				ADAPTER_STATE_LOCK(ha);
3044fcf3ce44SJohn Forte 				if (ha->port_retry_timer == 0) {
3045fcf3ce44SJohn Forte 					ha->port_retry_timer = 2;
3046fcf3ce44SJohn Forte 				}
3047fcf3ce44SJohn Forte 				ADAPTER_STATE_UNLOCK(ha);
3048fcf3ce44SJohn Forte 			}
3049fcf3ce44SJohn Forte 
3050fcf3ce44SJohn Forte 			/* Release device queue specific lock. */
3051fcf3ce44SJohn Forte 			DEVICE_QUEUE_UNLOCK(tq);
3052fcf3ce44SJohn Forte 
3053fcf3ce44SJohn Forte 		} else if (tq->port_down_retry_count &&
3054fcf3ce44SJohn Forte 		    (sp->pkt->pkt_reason == CS_PORT_CONFIG_CHG ||
3055fcf3ce44SJohn Forte 		    sp->pkt->pkt_reason == CS_PORT_BUSY)) {
3056fcf3ce44SJohn Forte 			EL(ha, "Port Down Retry\n");
3057fcf3ce44SJohn Forte 
3058fcf3ce44SJohn Forte 			/* Set retry status. */
3059fcf3ce44SJohn Forte 			sp->flags |= SRB_RETRY;
3060fcf3ce44SJohn Forte 
3061fcf3ce44SJohn Forte 			/* Acquire device queue lock. */
3062fcf3ce44SJohn Forte 			DEVICE_QUEUE_LOCK(tq);
3063fcf3ce44SJohn Forte 
3064fcf3ce44SJohn Forte 			if ((tq->flags & TQF_QUEUE_SUSPENDED) == 0) {
3065fcf3ce44SJohn Forte 				tq->flags |= TQF_QUEUE_SUSPENDED;
3066fcf3ce44SJohn Forte 
3067fcf3ce44SJohn Forte 				tq->port_down_retry_count--;
3068fcf3ce44SJohn Forte 
3069fcf3ce44SJohn Forte 				ADAPTER_STATE_LOCK(ha);
3070fcf3ce44SJohn Forte 				if (ha->port_retry_timer == 0) {
3071fcf3ce44SJohn Forte 					if ((ha->port_retry_timer =
3072fcf3ce44SJohn Forte 					    ha->port_down_retry_delay) == 0) {
3073fcf3ce44SJohn Forte 						*set_flags |=
3074fcf3ce44SJohn Forte 						    PORT_RETRY_NEEDED;
3075fcf3ce44SJohn Forte 					}
3076fcf3ce44SJohn Forte 				}
3077fcf3ce44SJohn Forte 				ADAPTER_STATE_UNLOCK(ha);
3078fcf3ce44SJohn Forte 			}
3079fcf3ce44SJohn Forte 			/* Release device queue specific lock. */
3080fcf3ce44SJohn Forte 			DEVICE_QUEUE_UNLOCK(tq);
3081fcf3ce44SJohn Forte 
3082fcf3ce44SJohn Forte 		} else if (sp->pkt->pkt_reason == CS_RESET) {
3083fcf3ce44SJohn Forte 			EL(ha, "Reset Retry\n");
3084fcf3ce44SJohn Forte 
3085fcf3ce44SJohn Forte 			/* Set retry status. */
3086fcf3ce44SJohn Forte 			sp->flags |= SRB_RETRY;
3087fcf3ce44SJohn Forte 
3088eb82ff87SDaniel Beauregard 		} else if (CFG_IST(ha, CFG_CTRL_24258081) &&
3089fcf3ce44SJohn Forte 		    sp->pkt->pkt_reason == CS_DATA_UNDERRUN) {
3090fcf3ce44SJohn Forte 			cnt = ddi_get32(ha->hba_buf.acc_handle,
3091fcf3ce44SJohn Forte 			    &pkt24->resp_byte_count);
3092fcf3ce44SJohn Forte 			if (cnt < sizeof (fc_ct_header_t)) {
309316dd44c2SDaniel Beauregard 				EL(ha, "Data underrun\n");
3094fcf3ce44SJohn Forte 			} else {
3095fcf3ce44SJohn Forte 				sp->pkt->pkt_reason = CS_COMPLETE;
3096fcf3ce44SJohn Forte 			}
3097fcf3ce44SJohn Forte 
3098fcf3ce44SJohn Forte 		} else if (sp->pkt->pkt_reason != CS_COMPLETE) {
3099fcf3ce44SJohn Forte 			EL(ha, "status err=%xh\n", sp->pkt->pkt_reason);
3100fcf3ce44SJohn Forte 		}
3101fcf3ce44SJohn Forte 
3102fcf3ce44SJohn Forte 		if (sp->pkt->pkt_reason == CS_COMPLETE) {
3103fcf3ce44SJohn Forte 			/*EMPTY*/
31045dfd244aSDaniel Beauregard 			QL_PRINT_3(CE_CONT, "(%d): ct_cmdrsp=%x%02xh resp\n",
31055dfd244aSDaniel Beauregard 			    ha->instance, sp->pkt->pkt_cmd[8],
31065dfd244aSDaniel Beauregard 			    sp->pkt->pkt_cmd[9]);
3107fcf3ce44SJohn Forte 			QL_DUMP_3(sp->pkt->pkt_resp, 8, sp->pkt->pkt_rsplen);
3108fcf3ce44SJohn Forte 		}
3109fcf3ce44SJohn Forte 
3110fcf3ce44SJohn Forte 		/* For nameserver restore command, management change header. */
3111fcf3ce44SJohn Forte 		if ((sp->flags & SRB_RETRY) == 0) {
3112fcf3ce44SJohn Forte 			tq->d_id.b24 == 0xfffffc ?
3113fcf3ce44SJohn Forte 			    ql_cthdr_endian(sp->pkt->pkt_cmd_acc,
3114fcf3ce44SJohn Forte 			    sp->pkt->pkt_cmd, B_TRUE) :
3115fcf3ce44SJohn Forte 			    ql_cthdr_endian(sp->pkt->pkt_resp_acc,
3116fcf3ce44SJohn Forte 			    sp->pkt->pkt_resp, B_TRUE);
3117fcf3ce44SJohn Forte 		}
3118fcf3ce44SJohn Forte 
3119fcf3ce44SJohn Forte 		/* Set completed status. */
3120fcf3ce44SJohn Forte 		sp->flags |= SRB_ISP_COMPLETED;
3121fcf3ce44SJohn Forte 
3122fcf3ce44SJohn Forte 		/* Place command on done queue. */
3123fcf3ce44SJohn Forte 		ql_add_link_b(done_q, &sp->cmd);
3124fcf3ce44SJohn Forte 
3125fcf3ce44SJohn Forte 	}
3126fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
3127fcf3ce44SJohn Forte }
3128fcf3ce44SJohn Forte 
3129fcf3ce44SJohn Forte /*
3130fcf3ce44SJohn Forte  * ql_report_id_entry
3131fcf3ce44SJohn Forte  *	Processes received Name/Management/CT Pass-Through entry.
3132fcf3ce44SJohn Forte  *
3133fcf3ce44SJohn Forte  * Input:
3134fcf3ce44SJohn Forte  *	ha:		adapter state pointer.
3135eb82ff87SDaniel Beauregard  *	pkt:		entry pointer.
3136fcf3ce44SJohn Forte  *	done_q:		done queue pointer.
3137fcf3ce44SJohn Forte  *	set_flags:	task daemon flags to set.
3138fcf3ce44SJohn Forte  *	reset_flags:	task daemon flags to reset.
3139fcf3ce44SJohn Forte  *
3140fcf3ce44SJohn Forte  * Context:
3141fcf3ce44SJohn Forte  *	Interrupt or Kernel context, no mailbox commands allowed.
3142fcf3ce44SJohn Forte  */
3143fcf3ce44SJohn Forte /* ARGSUSED */
3144fcf3ce44SJohn Forte static void
3145fcf3ce44SJohn Forte ql_report_id_entry(ql_adapter_state_t *ha, report_id_1_t *pkt,
3146fcf3ce44SJohn Forte     ql_head_t *done_q, uint32_t *set_flags, uint32_t *reset_flags)
3147fcf3ce44SJohn Forte {
3148fcf3ce44SJohn Forte 	ql_adapter_state_t	*vha;
3149fcf3ce44SJohn Forte 
3150fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
3151fcf3ce44SJohn Forte 
3152fcf3ce44SJohn Forte 	EL(ha, "format=%d, vp=%d, status=%d\n",
3153fcf3ce44SJohn Forte 	    pkt->format, pkt->vp_index, pkt->status);
3154fcf3ce44SJohn Forte 
3155fcf3ce44SJohn Forte 	if (pkt->format == 1) {
3156fcf3ce44SJohn Forte 		/* Locate port state structure. */
3157fcf3ce44SJohn Forte 		for (vha = ha; vha != NULL; vha = vha->vp_next) {
3158fcf3ce44SJohn Forte 			if (vha->vp_index == pkt->vp_index) {
3159fcf3ce44SJohn Forte 				break;
3160fcf3ce44SJohn Forte 			}
3161fcf3ce44SJohn Forte 		}
31625dfd244aSDaniel Beauregard 		if (vha != NULL && vha->vp_index != 0 &&
31635dfd244aSDaniel Beauregard 		    (pkt->status == CS_COMPLETE ||
3164fcf3ce44SJohn Forte 		    pkt->status == CS_PORT_ID_CHANGE)) {
3165fcf3ce44SJohn Forte 			*set_flags |= LOOP_RESYNC_NEEDED;
3166fcf3ce44SJohn Forte 			*reset_flags &= ~LOOP_RESYNC_NEEDED;
3167fcf3ce44SJohn Forte 			vha->loop_down_timer = LOOP_DOWN_TIMER_OFF;
3168fcf3ce44SJohn Forte 			TASK_DAEMON_LOCK(ha);
3169fcf3ce44SJohn Forte 			vha->task_daemon_flags |= LOOP_RESYNC_NEEDED;
3170fcf3ce44SJohn Forte 			vha->task_daemon_flags &= ~LOOP_DOWN;
3171fcf3ce44SJohn Forte 			TASK_DAEMON_UNLOCK(ha);
3172fcf3ce44SJohn Forte 		}
3173fcf3ce44SJohn Forte 	}
3174fcf3ce44SJohn Forte 
3175fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
3176fcf3ce44SJohn Forte }
31775dfd244aSDaniel Beauregard 
31785dfd244aSDaniel Beauregard /*
31795dfd244aSDaniel Beauregard  * ql_els_entry
31805dfd244aSDaniel Beauregard  *	Processes received ELS Pass-Through entry.
31815dfd244aSDaniel Beauregard  *
31825dfd244aSDaniel Beauregard  * Input:
31835dfd244aSDaniel Beauregard  *	ha:		adapter state pointer.
31845dfd244aSDaniel Beauregard  *	pkt23:		entry pointer.
31855dfd244aSDaniel Beauregard  *	done_q:		done queue pointer.
31865dfd244aSDaniel Beauregard  *	set_flags:	task daemon flags to set.
31875dfd244aSDaniel Beauregard  *	reset_flags:	task daemon flags to reset.
31885dfd244aSDaniel Beauregard  *
31895dfd244aSDaniel Beauregard  * Context:
31905dfd244aSDaniel Beauregard  *	Interrupt or Kernel context, no mailbox commands allowed.
31915dfd244aSDaniel Beauregard  */
31925dfd244aSDaniel Beauregard /* ARGSUSED */
31935dfd244aSDaniel Beauregard static void
31945dfd244aSDaniel Beauregard ql_els_passthru_entry(ql_adapter_state_t *ha, els_passthru_entry_rsp_t *rsp,
31955dfd244aSDaniel Beauregard     ql_head_t *done_q, uint32_t *set_flags, uint32_t *reset_flags)
31965dfd244aSDaniel Beauregard {
31975dfd244aSDaniel Beauregard 	ql_tgt_t	*tq;
31985dfd244aSDaniel Beauregard 	port_id_t	d_id, s_id;
31995dfd244aSDaniel Beauregard 	ql_srb_t	*srb;
3200a2b3ff35SDaniel Beauregard 	uint32_t	index, resp_identifier;
32015dfd244aSDaniel Beauregard 
32025dfd244aSDaniel Beauregard 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
32035dfd244aSDaniel Beauregard 
3204a2b3ff35SDaniel Beauregard 	/* Validate the response entry handle. */
3205a2b3ff35SDaniel Beauregard 	resp_identifier = ddi_get32(ha->hba_buf.acc_handle, &rsp->handle);
3206a2b3ff35SDaniel Beauregard 	index = resp_identifier & OSC_INDEX_MASK;
3207a2b3ff35SDaniel Beauregard 	if (index < MAX_OUTSTANDING_COMMANDS) {
3208a2b3ff35SDaniel Beauregard 		/* the index seems reasonable */
3209a2b3ff35SDaniel Beauregard 		srb = ha->outstanding_cmds[index];
3210a2b3ff35SDaniel Beauregard 		if (srb != NULL) {
3211a2b3ff35SDaniel Beauregard 			if (srb->handle == resp_identifier) {
3212a2b3ff35SDaniel Beauregard 				/* Neo, you're the one... */
3213a2b3ff35SDaniel Beauregard 				ha->outstanding_cmds[index] = NULL;
3214a2b3ff35SDaniel Beauregard 				srb->handle = 0;
3215a2b3ff35SDaniel Beauregard 				srb->flags &= ~SRB_IN_TOKEN_ARRAY;
3216a2b3ff35SDaniel Beauregard 			} else {
3217a2b3ff35SDaniel Beauregard 				EL(ha, "IOCB handle mismatch pkt=%xh, sp=%xh\n",
3218a2b3ff35SDaniel Beauregard 				    resp_identifier, srb->handle);
3219a2b3ff35SDaniel Beauregard 				srb = NULL;
3220a2b3ff35SDaniel Beauregard 				ql_signal_abort(ha, set_flags);
3221a2b3ff35SDaniel Beauregard 			}
3222a2b3ff35SDaniel Beauregard 		} else {
3223a2b3ff35SDaniel Beauregard 			srb = ql_verify_preprocessed_cmd(ha,
3224a2b3ff35SDaniel Beauregard 			    (uint32_t *)&rsp->handle, set_flags, reset_flags);
3225a2b3ff35SDaniel Beauregard 		}
3226a2b3ff35SDaniel Beauregard 	} else {
3227a2b3ff35SDaniel Beauregard 		EL(ha, "osc index out of range, index=%xh, handle=%xh\n",
3228a2b3ff35SDaniel Beauregard 		    index, resp_identifier);
3229a2b3ff35SDaniel Beauregard 		ql_signal_abort(ha, set_flags);
3230a2b3ff35SDaniel Beauregard 	}
32315dfd244aSDaniel Beauregard 
3232a2b3ff35SDaniel Beauregard 	if (srb != NULL) {
32335dfd244aSDaniel Beauregard 		if (!(srb->flags & SRB_ELS_PKT)) {
32345dfd244aSDaniel Beauregard 			EL(ha, "Not SRB_ELS_PKT flags=%xh, isp_abort_needed",
32355dfd244aSDaniel Beauregard 			    srb->flags);
32365dfd244aSDaniel Beauregard 			*set_flags |= ISP_ABORT_NEEDED;
32375dfd244aSDaniel Beauregard 			return;
32385dfd244aSDaniel Beauregard 		}
3239a2b3ff35SDaniel Beauregard 
3240a2b3ff35SDaniel Beauregard 		(void) ddi_dma_sync(srb->pkt->pkt_resp_dma, 0, 0,
3241a2b3ff35SDaniel Beauregard 		    DDI_DMA_SYNC_FORKERNEL);
32425dfd244aSDaniel Beauregard 
32435dfd244aSDaniel Beauregard 		/* Set ISP completion status */
32445dfd244aSDaniel Beauregard 		srb->pkt->pkt_reason = ddi_get16(
32455dfd244aSDaniel Beauregard 		    ha->hba_buf.acc_handle, &rsp->comp_status);
32465dfd244aSDaniel Beauregard 
32475dfd244aSDaniel Beauregard 		if (srb->pkt->pkt_reason != CS_COMPLETE) {
32485dfd244aSDaniel Beauregard 			la_els_rjt_t	rjt;
32495dfd244aSDaniel Beauregard 			EL(ha, "status err=%xh\n", srb->pkt->pkt_reason);
32505dfd244aSDaniel Beauregard 
32515dfd244aSDaniel Beauregard 			if (srb->pkt->pkt_reason == CS_LOGIN_LOGOUT_ERROR) {
32525dfd244aSDaniel Beauregard 				EL(ha, "e1=%xh e2=%xh\n",
32535dfd244aSDaniel Beauregard 				    rsp->error_subcode1, rsp->error_subcode2);
32545dfd244aSDaniel Beauregard 			}
32555dfd244aSDaniel Beauregard 
32565dfd244aSDaniel Beauregard 			srb->pkt->pkt_state = FC_PKT_TRAN_ERROR;
32575dfd244aSDaniel Beauregard 
32585dfd244aSDaniel Beauregard 			/* Build RJT in the response. */
32595dfd244aSDaniel Beauregard 			rjt.ls_code.ls_code = LA_ELS_RJT;
32605dfd244aSDaniel Beauregard 			rjt.reason = FC_REASON_NO_CONNECTION;
32615dfd244aSDaniel Beauregard 
32625dfd244aSDaniel Beauregard 			ddi_rep_put8(srb->pkt->pkt_resp_acc, (uint8_t *)&rjt,
32635dfd244aSDaniel Beauregard 			    (uint8_t *)srb->pkt->pkt_resp,
32645dfd244aSDaniel Beauregard 			    sizeof (rjt), DDI_DEV_AUTOINCR);
32655dfd244aSDaniel Beauregard 
32665dfd244aSDaniel Beauregard 			srb->pkt->pkt_state = FC_PKT_TRAN_ERROR;
32675dfd244aSDaniel Beauregard 			srb->pkt->pkt_reason = FC_REASON_NO_CONNECTION;
32685dfd244aSDaniel Beauregard 		}
32695dfd244aSDaniel Beauregard 
32705dfd244aSDaniel Beauregard 		if (srb->pkt->pkt_reason == CS_COMPLETE) {
32715dfd244aSDaniel Beauregard 			uint8_t		opcode;
32725dfd244aSDaniel Beauregard 			uint16_t	loop_id;
32735dfd244aSDaniel Beauregard 
32745dfd244aSDaniel Beauregard 			/* Indicate ISP completion */
32755dfd244aSDaniel Beauregard 			srb->flags |= SRB_ISP_COMPLETED;
32765dfd244aSDaniel Beauregard 
32775dfd244aSDaniel Beauregard 			loop_id = ddi_get16(ha->hba_buf.acc_handle,
32785dfd244aSDaniel Beauregard 			    &rsp->n_port_hdl);
32795dfd244aSDaniel Beauregard 
32805dfd244aSDaniel Beauregard 			if (ha->topology & QL_N_PORT) {
32815dfd244aSDaniel Beauregard 				/* create a target Q if there isn't one */
32825dfd244aSDaniel Beauregard 				tq = ql_loop_id_to_queue(ha, loop_id);
32835dfd244aSDaniel Beauregard 				if (tq == NULL) {
32845dfd244aSDaniel Beauregard 					d_id.b.al_pa = rsp->d_id_7_0;
32855dfd244aSDaniel Beauregard 					d_id.b.area = rsp->d_id_15_8;
32865dfd244aSDaniel Beauregard 					d_id.b.domain = rsp->d_id_23_16;
32875dfd244aSDaniel Beauregard 					/* Acquire adapter state lock. */
32885dfd244aSDaniel Beauregard 					ADAPTER_STATE_LOCK(ha);
32895dfd244aSDaniel Beauregard 
32905dfd244aSDaniel Beauregard 					tq = ql_dev_init(ha, d_id, loop_id);
32915dfd244aSDaniel Beauregard 					EL(ha, " tq = %x\n", tq);
32925dfd244aSDaniel Beauregard 
32935dfd244aSDaniel Beauregard 					ADAPTER_STATE_UNLOCK(ha);
32945dfd244aSDaniel Beauregard 				}
32955dfd244aSDaniel Beauregard 
32965dfd244aSDaniel Beauregard 				/* on plogi success assume the chosen s_id */
32975dfd244aSDaniel Beauregard 				opcode = ddi_get8(ha->hba_buf.acc_handle,
32985dfd244aSDaniel Beauregard 				    &rsp->els_cmd_opcode);
32995dfd244aSDaniel Beauregard 
33005dfd244aSDaniel Beauregard 				EL(ha, "els_cmd_opcode=%x srb->pkt=%x\n",
33015dfd244aSDaniel Beauregard 				    opcode, srb->pkt);
33025dfd244aSDaniel Beauregard 
33035dfd244aSDaniel Beauregard 				if (opcode == LA_ELS_PLOGI) {
33045dfd244aSDaniel Beauregard 					s_id.b.al_pa = rsp->s_id_7_0;
33055dfd244aSDaniel Beauregard 					s_id.b.area = rsp->s_id_15_8;
33065dfd244aSDaniel Beauregard 					s_id.b.domain = rsp->s_id_23_16;
33075dfd244aSDaniel Beauregard 
33085dfd244aSDaniel Beauregard 					ha->d_id.b24 = s_id.b24;
33095dfd244aSDaniel Beauregard 					EL(ha, "Set port's source ID %xh\n",
33105dfd244aSDaniel Beauregard 					    ha->d_id.b24);
33115dfd244aSDaniel Beauregard 				}
33125dfd244aSDaniel Beauregard 			}
33135dfd244aSDaniel Beauregard 			ql_isp_els_handle_rsp_endian(ha, srb);
33145dfd244aSDaniel Beauregard 
33155dfd244aSDaniel Beauregard 			if (ha != srb->ha) {
33165dfd244aSDaniel Beauregard 				EL(ha, "ha=%x srb->ha=%x\n", ha, srb->ha);
33175dfd244aSDaniel Beauregard 			}
33185dfd244aSDaniel Beauregard 
33195dfd244aSDaniel Beauregard 			if (tq != NULL) {
33205dfd244aSDaniel Beauregard 				tq->logout_sent = 0;
33215dfd244aSDaniel Beauregard 				tq->flags &= ~TQF_NEED_AUTHENTICATION;
33225dfd244aSDaniel Beauregard 
3323eb82ff87SDaniel Beauregard 				if (CFG_IST(ha, CFG_CTRL_24258081)) {
33245dfd244aSDaniel Beauregard 					tq->flags |= TQF_IIDMA_NEEDED;
33255dfd244aSDaniel Beauregard 				}
33265dfd244aSDaniel Beauregard 			srb->pkt->pkt_state = FC_PKT_SUCCESS;
33275dfd244aSDaniel Beauregard 			}
33285dfd244aSDaniel Beauregard 		}
33295dfd244aSDaniel Beauregard 		/* invoke the callback */
33305dfd244aSDaniel Beauregard 		ql_awaken_task_daemon(ha, srb, 0, 0);
33315dfd244aSDaniel Beauregard 	}
33325dfd244aSDaniel Beauregard 	QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
33335dfd244aSDaniel Beauregard }
3334a2b3ff35SDaniel Beauregard 
3335a2b3ff35SDaniel Beauregard /*
3336a2b3ff35SDaniel Beauregard  * ql_signal_abort
3337a2b3ff35SDaniel Beauregard  *	Signal to the task daemon that a condition warranting an
3338a2b3ff35SDaniel Beauregard  *	isp reset has been detected.
3339a2b3ff35SDaniel Beauregard  *
3340a2b3ff35SDaniel Beauregard  * Input:
3341a2b3ff35SDaniel Beauregard  *	ha:		adapter state pointer.
3342a2b3ff35SDaniel Beauregard  *	set_flags:	task daemon flags to set.
3343a2b3ff35SDaniel Beauregard  *
3344a2b3ff35SDaniel Beauregard  * Context:
3345a2b3ff35SDaniel Beauregard  *	Interrupt or Kernel context, no mailbox commands allowed.
3346a2b3ff35SDaniel Beauregard  */
3347a2b3ff35SDaniel Beauregard static void
3348a2b3ff35SDaniel Beauregard ql_signal_abort(ql_adapter_state_t *ha, uint32_t *set_flags)
3349a2b3ff35SDaniel Beauregard {
3350*f885d00fSDaniel Beauregard 	if (!CFG_IST(ha, CFG_CTRL_8021) &&
3351*f885d00fSDaniel Beauregard 	    !(ha->task_daemon_flags & (ISP_ABORT_NEEDED | ABORT_ISP_ACTIVE))) {
3352a2b3ff35SDaniel Beauregard 		*set_flags |= ISP_ABORT_NEEDED;
3353a2b3ff35SDaniel Beauregard 	}
3354a2b3ff35SDaniel Beauregard }
3355