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  */
21c4ddbbe1SDaniel Beauregard 
22c4ddbbe1SDaniel Beauregard /*
23c4ddbbe1SDaniel Beauregard  * Copyright 2009 QLogic Corporation.  All rights reserved.
24c4ddbbe1SDaniel Beauregard  * Use is subject to license terms.
25c4ddbbe1SDaniel Beauregard  */
26c4ddbbe1SDaniel Beauregard 
27fcf3ce44SJohn Forte /*
28d8c54e3dSSam Cramer  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
29fcf3ce44SJohn Forte  * Use is subject to license terms.
30fcf3ce44SJohn Forte  */
31fcf3ce44SJohn Forte 
32fcf3ce44SJohn Forte #include <sys/conf.h>
33fcf3ce44SJohn Forte #include <sys/ddi.h>
34fcf3ce44SJohn Forte #include <sys/stat.h>
35fcf3ce44SJohn Forte #include <sys/pci.h>
36fcf3ce44SJohn Forte #include <sys/sunddi.h>
37fcf3ce44SJohn Forte #include <sys/modctl.h>
38fcf3ce44SJohn Forte #include <sys/file.h>
39fcf3ce44SJohn Forte #include <sys/cred.h>
40fcf3ce44SJohn Forte #include <sys/byteorder.h>
41fcf3ce44SJohn Forte #include <sys/atomic.h>
42fcf3ce44SJohn Forte #include <sys/scsi/scsi.h>
43fcf3ce44SJohn Forte 
44fcf3ce44SJohn Forte #include <stmf_defines.h>
45fcf3ce44SJohn Forte #include <fct_defines.h>
46fcf3ce44SJohn Forte #include <stmf.h>
47fcf3ce44SJohn Forte #include <portif.h>
48fcf3ce44SJohn Forte #include <fct.h>
49fcf3ce44SJohn Forte #include <qlt.h>
50fcf3ce44SJohn Forte #include <qlt_dma.h>
51fcf3ce44SJohn Forte #include <qlt_ioctl.h>
52c4ddbbe1SDaniel Beauregard #include <qlt_open.h>
53fcf3ce44SJohn Forte #include <stmf_ioctl.h>
54fcf3ce44SJohn Forte 
55fcf3ce44SJohn Forte static int qlt_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
56fcf3ce44SJohn Forte static int qlt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
57*a2255df3SDaniel Beauregard static void qlt_enable_intr(qlt_state_t *);
58*a2255df3SDaniel Beauregard static void qlt_disable_intr(qlt_state_t *);
59*a2255df3SDaniel Beauregard static fct_status_t qlt_reset_chip(qlt_state_t *qlt);
60*a2255df3SDaniel Beauregard static fct_status_t qlt_download_fw(qlt_state_t *qlt);
61fcf3ce44SJohn Forte static fct_status_t qlt_load_risc_ram(qlt_state_t *qlt, uint32_t *host_addr,
62fcf3ce44SJohn Forte     uint32_t word_count, uint32_t risc_addr);
63fcf3ce44SJohn Forte static fct_status_t qlt_raw_mailbox_command(qlt_state_t *qlt);
64fcf3ce44SJohn Forte static mbox_cmd_t *qlt_alloc_mailbox_command(qlt_state_t *qlt,
65fcf3ce44SJohn Forte 					uint32_t dma_size);
66fcf3ce44SJohn Forte void qlt_free_mailbox_command(qlt_state_t *qlt, mbox_cmd_t *mcp);
67fcf3ce44SJohn Forte static fct_status_t qlt_mailbox_command(qlt_state_t *qlt, mbox_cmd_t *mcp);
68fcf3ce44SJohn Forte static uint_t qlt_isr(caddr_t arg, caddr_t arg2);
69fcf3ce44SJohn Forte static fct_status_t qlt_firmware_dump(fct_local_port_t *port,
70fcf3ce44SJohn Forte     stmf_state_change_info_t *ssci);
71fcf3ce44SJohn Forte static void qlt_handle_inot(qlt_state_t *qlt, uint8_t *inot);
72fcf3ce44SJohn Forte static void qlt_handle_purex(qlt_state_t *qlt, uint8_t *resp);
73fcf3ce44SJohn Forte static void qlt_handle_atio(qlt_state_t *qlt, uint8_t *atio);
74fcf3ce44SJohn Forte static void qlt_handle_ctio_completion(qlt_state_t *qlt, uint8_t *rsp);
75fcf3ce44SJohn Forte static void qlt_handle_sol_abort_completion(qlt_state_t *qlt, uint8_t *rsp);
76fcf3ce44SJohn Forte static void qlt_handle_dereg_completion(qlt_state_t *qlt, uint8_t *rsp);
77fcf3ce44SJohn Forte static void qlt_handle_unsol_els_completion(qlt_state_t *qlt, uint8_t *rsp);
78fcf3ce44SJohn Forte static void qlt_handle_unsol_els_abort_completion(qlt_state_t *qlt,
79fcf3ce44SJohn Forte     uint8_t *rsp);
80fcf3ce44SJohn Forte static void qlt_handle_sol_els_completion(qlt_state_t *qlt, uint8_t *rsp);
81fcf3ce44SJohn Forte static void qlt_handle_rcvd_abts(qlt_state_t *qlt, uint8_t *resp);
82fcf3ce44SJohn Forte static void qlt_handle_abts_completion(qlt_state_t *qlt, uint8_t *resp);
83fcf3ce44SJohn Forte static fct_status_t qlt_read_nvram(qlt_state_t *qlt);
84c4ddbbe1SDaniel Beauregard static void qlt_verify_fw(qlt_state_t *qlt);
85c4ddbbe1SDaniel Beauregard static void qlt_handle_verify_fw_completion(qlt_state_t *qlt, uint8_t *rsp);
86fcf3ce44SJohn Forte fct_status_t qlt_port_start(caddr_t arg);
87fcf3ce44SJohn Forte fct_status_t qlt_port_stop(caddr_t arg);
88fcf3ce44SJohn Forte fct_status_t qlt_port_online(qlt_state_t *qlt);
89fcf3ce44SJohn Forte fct_status_t qlt_port_offline(qlt_state_t *qlt);
90fcf3ce44SJohn Forte static fct_status_t qlt_get_link_info(fct_local_port_t *port,
91fcf3ce44SJohn Forte     fct_link_info_t *li);
92fcf3ce44SJohn Forte static void qlt_ctl(struct fct_local_port *port, int cmd, void *arg);
93*a2255df3SDaniel Beauregard static fct_status_t qlt_force_lip(qlt_state_t *);
94fcf3ce44SJohn Forte static fct_status_t qlt_do_flogi(struct fct_local_port *port,
95fcf3ce44SJohn Forte 						fct_flogi_xchg_t *fx);
96fcf3ce44SJohn Forte void qlt_handle_atio_queue_update(qlt_state_t *qlt);
97fcf3ce44SJohn Forte void qlt_handle_resp_queue_update(qlt_state_t *qlt);
98fcf3ce44SJohn Forte fct_status_t qlt_register_remote_port(fct_local_port_t *port,
99fcf3ce44SJohn Forte     fct_remote_port_t *rp, fct_cmd_t *login);
100fcf3ce44SJohn Forte fct_status_t qlt_deregister_remote_port(fct_local_port_t *port,
101fcf3ce44SJohn Forte     fct_remote_port_t *rp);
102fcf3ce44SJohn Forte fct_status_t qlt_send_cmd_response(fct_cmd_t *cmd, uint32_t ioflags);
103fcf3ce44SJohn Forte fct_status_t qlt_send_els_response(qlt_state_t *qlt, fct_cmd_t *cmd);
104fcf3ce44SJohn Forte fct_status_t qlt_send_abts_response(qlt_state_t *qlt,
105fcf3ce44SJohn Forte     fct_cmd_t *cmd, int terminate);
106fcf3ce44SJohn Forte static void qlt_handle_inot(qlt_state_t *qlt, uint8_t *inot);
107fcf3ce44SJohn Forte int qlt_set_uniq_flag(uint16_t *ptr, uint16_t setf, uint16_t abortf);
108fcf3ce44SJohn Forte fct_status_t qlt_abort_cmd(struct fct_local_port *port,
109fcf3ce44SJohn Forte     fct_cmd_t *cmd, uint32_t flags);
110fcf3ce44SJohn Forte fct_status_t qlt_abort_sol_cmd(qlt_state_t *qlt, fct_cmd_t *cmd);
111fcf3ce44SJohn Forte fct_status_t qlt_abort_purex(qlt_state_t *qlt, fct_cmd_t *cmd);
112fcf3ce44SJohn Forte fct_status_t qlt_abort_unsol_scsi_cmd(qlt_state_t *qlt, fct_cmd_t *cmd);
113fcf3ce44SJohn Forte fct_status_t qlt_send_cmd(fct_cmd_t *cmd);
114fcf3ce44SJohn Forte fct_status_t qlt_send_els(qlt_state_t *qlt, fct_cmd_t *cmd);
115fcf3ce44SJohn Forte fct_status_t qlt_send_status(qlt_state_t *qlt, fct_cmd_t *cmd);
116fcf3ce44SJohn Forte fct_status_t qlt_xfer_scsi_data(fct_cmd_t *cmd,
117fcf3ce44SJohn Forte     stmf_data_buf_t *dbuf, uint32_t ioflags);
118fcf3ce44SJohn Forte fct_status_t qlt_send_ct(qlt_state_t *qlt, fct_cmd_t *cmd);
119fcf3ce44SJohn Forte static void qlt_handle_ct_completion(qlt_state_t *qlt, uint8_t *rsp);
120fcf3ce44SJohn Forte static void qlt_release_intr(qlt_state_t *qlt);
121fcf3ce44SJohn Forte static int qlt_setup_interrupts(qlt_state_t *qlt);
122fcf3ce44SJohn Forte static void qlt_destroy_mutex(qlt_state_t *qlt);
123fcf3ce44SJohn Forte 
124fcf3ce44SJohn Forte static fct_status_t qlt_read_risc_ram(qlt_state_t *qlt, uint32_t addr,
125fcf3ce44SJohn Forte     uint32_t words);
126fcf3ce44SJohn Forte static int qlt_dump_queue(qlt_state_t *qlt, caddr_t qadr, int entries,
127c4ddbbe1SDaniel Beauregard     caddr_t buf, uint_t size_left);
128fcf3ce44SJohn Forte static int qlt_dump_risc_ram(qlt_state_t *qlt, uint32_t addr, uint32_t words,
129c4ddbbe1SDaniel Beauregard     caddr_t buf, uint_t size_left);
130fcf3ce44SJohn Forte static int qlt_fwdump_dump_regs(qlt_state_t *qlt, caddr_t buf, int startaddr,
131c4ddbbe1SDaniel Beauregard     int count, uint_t size_left);
132fcf3ce44SJohn Forte static int qlt_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
133fcf3ce44SJohn Forte     cred_t *credp, int *rval);
134fcf3ce44SJohn Forte static int qlt_open(dev_t *devp, int flag, int otype, cred_t *credp);
135fcf3ce44SJohn Forte static int qlt_close(dev_t dev, int flag, int otype, cred_t *credp);
136fcf3ce44SJohn Forte 
137c4ddbbe1SDaniel Beauregard static int qlt_setup_msi(qlt_state_t *qlt);
138c4ddbbe1SDaniel Beauregard static int qlt_setup_msix(qlt_state_t *qlt);
139c4ddbbe1SDaniel Beauregard 
140c4ddbbe1SDaniel Beauregard static int qlt_el_trace_desc_ctor(qlt_state_t *qlt);
141c4ddbbe1SDaniel Beauregard static int qlt_el_trace_desc_dtor(qlt_state_t *qlt);
142c4ddbbe1SDaniel Beauregard static int qlt_validate_trace_desc(qlt_state_t *qlt);
143c4ddbbe1SDaniel Beauregard static char *qlt_find_trace_start(qlt_state_t *qlt);
144c4ddbbe1SDaniel Beauregard 
1450ff6bfafSDaniel Beauregard static int qlt_read_int_prop(qlt_state_t *qlt, char *prop, int defval);
1460ff6bfafSDaniel Beauregard static int qlt_read_string_prop(qlt_state_t *qlt, char *prop, char **prop_val);
1470ff6bfafSDaniel Beauregard static int qlt_read_string_instance_prop(qlt_state_t *qlt, char *prop,
1480ff6bfafSDaniel Beauregard     char **prop_val);
149*a2255df3SDaniel Beauregard static int qlt_read_int_instance_prop(qlt_state_t *, char *, int);
1500ff6bfafSDaniel Beauregard static int qlt_convert_string_to_ull(char *prop, int radix,
1510ff6bfafSDaniel Beauregard     u_longlong_t *result);
1520ff6bfafSDaniel Beauregard static boolean_t qlt_wwn_overload_prop(qlt_state_t *qlt);
1530ff6bfafSDaniel Beauregard static int qlt_quiesce(dev_info_t *dip);
154*a2255df3SDaniel Beauregard static fct_status_t qlt_raw_wrt_risc_ram_word(qlt_state_t *qlt, uint32_t,
155*a2255df3SDaniel Beauregard     uint32_t);
156*a2255df3SDaniel Beauregard static fct_status_t qlt_raw_rd_risc_ram_word(qlt_state_t *qlt, uint32_t,
157*a2255df3SDaniel Beauregard     uint32_t *);
158*a2255df3SDaniel Beauregard static void qlt_mps_reset(qlt_state_t *qlt);
159*a2255df3SDaniel Beauregard static void qlt_properties(qlt_state_t *qlt);
160*a2255df3SDaniel Beauregard 
1610ff6bfafSDaniel Beauregard 
162c4ddbbe1SDaniel Beauregard #define	SETELSBIT(bmp, els)	(bmp)[((els) >> 3) & 0x1F] = \
163c4ddbbe1SDaniel Beauregard 	(uint8_t)((bmp)[((els) >> 3) & 0x1F] | ((uint8_t)1) << ((els) & 7))
164fcf3ce44SJohn Forte 
165fcf3ce44SJohn Forte int qlt_enable_msix = 0;
166*a2255df3SDaniel Beauregard int qlt_enable_msi = 1;
167*a2255df3SDaniel Beauregard 
168fcf3ce44SJohn Forte 
1690ff6bfafSDaniel Beauregard string_table_t prop_status_tbl[] = DDI_PROP_STATUS();
1700ff6bfafSDaniel Beauregard 
171fcf3ce44SJohn Forte /* Array to quickly calculate next free buf index to use */
172c4ddbbe1SDaniel Beauregard #if 0
173fcf3ce44SJohn Forte static int qlt_nfb[] = { 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 0xff };
174c4ddbbe1SDaniel Beauregard #endif
175fcf3ce44SJohn Forte 
176fcf3ce44SJohn Forte static struct cb_ops qlt_cb_ops = {
177fcf3ce44SJohn Forte 	qlt_open,
178fcf3ce44SJohn Forte 	qlt_close,
179fcf3ce44SJohn Forte 	nodev,
180fcf3ce44SJohn Forte 	nodev,
181fcf3ce44SJohn Forte 	nodev,
182fcf3ce44SJohn Forte 	nodev,
183fcf3ce44SJohn Forte 	nodev,
184fcf3ce44SJohn Forte 	qlt_ioctl,
185fcf3ce44SJohn Forte 	nodev,
186fcf3ce44SJohn Forte 	nodev,
187fcf3ce44SJohn Forte 	nodev,
188fcf3ce44SJohn Forte 	nochpoll,
189fcf3ce44SJohn Forte 	ddi_prop_op,
190fcf3ce44SJohn Forte 	0,
191fcf3ce44SJohn Forte 	D_MP | D_NEW
192fcf3ce44SJohn Forte };
193fcf3ce44SJohn Forte 
194fcf3ce44SJohn Forte static struct dev_ops qlt_ops = {
195fcf3ce44SJohn Forte 	DEVO_REV,
196fcf3ce44SJohn Forte 	0,
197fcf3ce44SJohn Forte 	nodev,
198fcf3ce44SJohn Forte 	nulldev,
199fcf3ce44SJohn Forte 	nulldev,
200fcf3ce44SJohn Forte 	qlt_attach,
201fcf3ce44SJohn Forte 	qlt_detach,
202fcf3ce44SJohn Forte 	nodev,
203fcf3ce44SJohn Forte 	&qlt_cb_ops,
204fcf3ce44SJohn Forte 	NULL,
2050ff6bfafSDaniel Beauregard 	ddi_power,
2060ff6bfafSDaniel Beauregard 	qlt_quiesce
207fcf3ce44SJohn Forte };
208fcf3ce44SJohn Forte 
209c4ddbbe1SDaniel Beauregard #ifndef	PORT_SPEED_10G
210c4ddbbe1SDaniel Beauregard #define	PORT_SPEED_10G		16
211c4ddbbe1SDaniel Beauregard #endif
212fcf3ce44SJohn Forte 
213fcf3ce44SJohn Forte static struct modldrv modldrv = {
214fcf3ce44SJohn Forte 	&mod_driverops,
215c4ddbbe1SDaniel Beauregard 	QLT_NAME" "QLT_VERSION,
216fcf3ce44SJohn Forte 	&qlt_ops,
217fcf3ce44SJohn Forte };
218fcf3ce44SJohn Forte 
219fcf3ce44SJohn Forte static struct modlinkage modlinkage = {
220fcf3ce44SJohn Forte 	MODREV_1, &modldrv, NULL
221fcf3ce44SJohn Forte };
222fcf3ce44SJohn Forte 
223fcf3ce44SJohn Forte void *qlt_state = NULL;
224fcf3ce44SJohn Forte kmutex_t qlt_global_lock;
225fcf3ce44SJohn Forte static uint32_t qlt_loaded_counter = 0;
226fcf3ce44SJohn Forte 
227fcf3ce44SJohn Forte static char *pci_speeds[] = { " 33", "-X Mode 1 66", "-X Mode 1 100",
228fcf3ce44SJohn Forte 			"-X Mode 1 133", "--Invalid--",
229fcf3ce44SJohn Forte 			"-X Mode 2 66", "-X Mode 2 100",
230fcf3ce44SJohn Forte 			"-X Mode 2 133", " 66" };
231fcf3ce44SJohn Forte 
232fcf3ce44SJohn Forte /* Always use 64 bit DMA. */
233fcf3ce44SJohn Forte static ddi_dma_attr_t qlt_queue_dma_attr = {
234fcf3ce44SJohn Forte 	DMA_ATTR_V0,		/* dma_attr_version */
235fcf3ce44SJohn Forte 	0,			/* low DMA address range */
236fcf3ce44SJohn Forte 	0xffffffffffffffff,	/* high DMA address range */
237fcf3ce44SJohn Forte 	0xffffffff,		/* DMA counter register */
238fcf3ce44SJohn Forte 	64,			/* DMA address alignment */
239fcf3ce44SJohn Forte 	0xff,			/* DMA burstsizes */
240fcf3ce44SJohn Forte 	1,			/* min effective DMA size */
241fcf3ce44SJohn Forte 	0xffffffff,		/* max DMA xfer size */
242fcf3ce44SJohn Forte 	0xffffffff,		/* segment boundary */
243fcf3ce44SJohn Forte 	1,			/* s/g list length */
244fcf3ce44SJohn Forte 	1,			/* granularity of device */
245fcf3ce44SJohn Forte 	0			/* DMA transfer flags */
246fcf3ce44SJohn Forte };
247fcf3ce44SJohn Forte 
248fcf3ce44SJohn Forte /* qlogic logging */
249fcf3ce44SJohn Forte int enable_extended_logging = 0;
250fcf3ce44SJohn Forte 
251fcf3ce44SJohn Forte static char qlt_provider_name[] = "qlt";
252fcf3ce44SJohn Forte static struct stmf_port_provider *qlt_pp;
253fcf3ce44SJohn Forte 
254fcf3ce44SJohn Forte int
255fcf3ce44SJohn Forte _init(void)
256fcf3ce44SJohn Forte {
257fcf3ce44SJohn Forte 	int ret;
258fcf3ce44SJohn Forte 
259fcf3ce44SJohn Forte 	ret = ddi_soft_state_init(&qlt_state, sizeof (qlt_state_t), 0);
260fcf3ce44SJohn Forte 	if (ret == 0) {
261fcf3ce44SJohn Forte 		mutex_init(&qlt_global_lock, 0, MUTEX_DRIVER, 0);
262fcf3ce44SJohn Forte 		qlt_pp = (stmf_port_provider_t *)stmf_alloc(
263d8c54e3dSSam Cramer 		    STMF_STRUCT_PORT_PROVIDER, 0, 0);
264fcf3ce44SJohn Forte 		qlt_pp->pp_portif_rev = PORTIF_REV_1;
265fcf3ce44SJohn Forte 		qlt_pp->pp_name = qlt_provider_name;
266fcf3ce44SJohn Forte 		if (stmf_register_port_provider(qlt_pp) != STMF_SUCCESS) {
267fcf3ce44SJohn Forte 			stmf_free(qlt_pp);
268fcf3ce44SJohn Forte 			mutex_destroy(&qlt_global_lock);
269fcf3ce44SJohn Forte 			ddi_soft_state_fini(&qlt_state);
270fcf3ce44SJohn Forte 			return (EIO);
271fcf3ce44SJohn Forte 		}
272fcf3ce44SJohn Forte 		ret = mod_install(&modlinkage);
273fcf3ce44SJohn Forte 		if (ret != 0) {
274fcf3ce44SJohn Forte 			(void) stmf_deregister_port_provider(qlt_pp);
275fcf3ce44SJohn Forte 			stmf_free(qlt_pp);
276fcf3ce44SJohn Forte 			mutex_destroy(&qlt_global_lock);
277fcf3ce44SJohn Forte 			ddi_soft_state_fini(&qlt_state);
278fcf3ce44SJohn Forte 		}
279fcf3ce44SJohn Forte 	}
280fcf3ce44SJohn Forte 	return (ret);
281fcf3ce44SJohn Forte }
282fcf3ce44SJohn Forte 
283fcf3ce44SJohn Forte int
284fcf3ce44SJohn Forte _fini(void)
285fcf3ce44SJohn Forte {
286fcf3ce44SJohn Forte 	int ret;
287fcf3ce44SJohn Forte 
288fcf3ce44SJohn Forte 	if (qlt_loaded_counter)
289fcf3ce44SJohn Forte 		return (EBUSY);
290fcf3ce44SJohn Forte 	ret = mod_remove(&modlinkage);
291fcf3ce44SJohn Forte 	if (ret == 0) {
292fcf3ce44SJohn Forte 		(void) stmf_deregister_port_provider(qlt_pp);
293fcf3ce44SJohn Forte 		stmf_free(qlt_pp);
294fcf3ce44SJohn Forte 		mutex_destroy(&qlt_global_lock);
295fcf3ce44SJohn Forte 		ddi_soft_state_fini(&qlt_state);
296fcf3ce44SJohn Forte 	}
297fcf3ce44SJohn Forte 	return (ret);
298fcf3ce44SJohn Forte }
299fcf3ce44SJohn Forte 
300fcf3ce44SJohn Forte int
301fcf3ce44SJohn Forte _info(struct modinfo *modinfop)
302fcf3ce44SJohn Forte {
303fcf3ce44SJohn Forte 	return (mod_info(&modlinkage, modinfop));
304fcf3ce44SJohn Forte }
305fcf3ce44SJohn Forte 
306fcf3ce44SJohn Forte 
307fcf3ce44SJohn Forte static int
308fcf3ce44SJohn Forte qlt_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
309fcf3ce44SJohn Forte {
310fcf3ce44SJohn Forte 	int		instance;
311fcf3ce44SJohn Forte 	qlt_state_t	*qlt;
312fcf3ce44SJohn Forte 	ddi_device_acc_attr_t	dev_acc_attr;
313fcf3ce44SJohn Forte 	uint16_t	did;
314fcf3ce44SJohn Forte 	uint16_t	val;
315fcf3ce44SJohn Forte 	uint16_t	mr;
316fcf3ce44SJohn Forte 	size_t		discard;
317fcf3ce44SJohn Forte 	uint_t		ncookies;
318fcf3ce44SJohn Forte 	int		max_read_size;
319fcf3ce44SJohn Forte 	int		max_payload_size;
320fcf3ce44SJohn Forte 	fct_status_t	ret;
321fcf3ce44SJohn Forte 
322fcf3ce44SJohn Forte 	/* No support for suspend resume yet */
323fcf3ce44SJohn Forte 	if (cmd != DDI_ATTACH)
324fcf3ce44SJohn Forte 		return (DDI_FAILURE);
325fcf3ce44SJohn Forte 	instance = ddi_get_instance(dip);
326fcf3ce44SJohn Forte 
327fcf3ce44SJohn Forte 	if (ddi_soft_state_zalloc(qlt_state, instance) != DDI_SUCCESS) {
328fcf3ce44SJohn Forte 		return (DDI_FAILURE);
329fcf3ce44SJohn Forte 	}
330fcf3ce44SJohn Forte 
331c4ddbbe1SDaniel Beauregard 	if ((qlt = (qlt_state_t *)ddi_get_soft_state(qlt_state, instance)) ==
332c4ddbbe1SDaniel Beauregard 	    NULL) {
333fcf3ce44SJohn Forte 		goto attach_fail_1;
334fcf3ce44SJohn Forte 	}
335*a2255df3SDaniel Beauregard 
336fcf3ce44SJohn Forte 	qlt->instance = instance;
337*a2255df3SDaniel Beauregard 
338fcf3ce44SJohn Forte 	qlt->nvram = (qlt_nvram_t *)kmem_zalloc(sizeof (qlt_nvram_t), KM_SLEEP);
339fcf3ce44SJohn Forte 	qlt->dip = dip;
340c4ddbbe1SDaniel Beauregard 
341c4ddbbe1SDaniel Beauregard 	if (qlt_el_trace_desc_ctor(qlt) != DDI_SUCCESS) {
342c4ddbbe1SDaniel Beauregard 		cmn_err(CE_WARN, "qlt(%d): can't setup el tracing", instance);
343c4ddbbe1SDaniel Beauregard 		goto attach_fail_1;
344c4ddbbe1SDaniel Beauregard 	}
345c4ddbbe1SDaniel Beauregard 
346*a2255df3SDaniel Beauregard 	EL(qlt, "instance=%d, ptr=%p\n", instance, (void *)qlt);
347c4ddbbe1SDaniel Beauregard 
348fcf3ce44SJohn Forte 	if (pci_config_setup(dip, &qlt->pcicfg_acc_handle) != DDI_SUCCESS) {
349fcf3ce44SJohn Forte 		goto attach_fail_2;
350fcf3ce44SJohn Forte 	}
351fcf3ce44SJohn Forte 	did = PCICFG_RD16(qlt, PCI_CONF_DEVID);
352fcf3ce44SJohn Forte 	if ((did != 0x2422) && (did != 0x2432) &&
353c4ddbbe1SDaniel Beauregard 	    (did != 0x8432) && (did != 0x2532) &&
354c4ddbbe1SDaniel Beauregard 	    (did != 0x8001)) {
355c4ddbbe1SDaniel Beauregard 		cmn_err(CE_WARN, "qlt(%d): unknown devid(%x), failing attach",
356fcf3ce44SJohn Forte 		    instance, did);
357fcf3ce44SJohn Forte 		goto attach_fail_4;
358fcf3ce44SJohn Forte 	}
359c4ddbbe1SDaniel Beauregard 
360c4ddbbe1SDaniel Beauregard 	if ((did & 0xFF00) == 0x8000)
361c4ddbbe1SDaniel Beauregard 		qlt->qlt_81xx_chip = 1;
362c4ddbbe1SDaniel Beauregard 	else if ((did & 0xFF00) == 0x2500)
363fcf3ce44SJohn Forte 		qlt->qlt_25xx_chip = 1;
364fcf3ce44SJohn Forte 
365fcf3ce44SJohn Forte 	dev_acc_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
366fcf3ce44SJohn Forte 	dev_acc_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
367fcf3ce44SJohn Forte 	dev_acc_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
368fcf3ce44SJohn Forte 	if (ddi_regs_map_setup(dip, 2, &qlt->regs, 0, 0x100,
369fcf3ce44SJohn Forte 	    &dev_acc_attr, &qlt->regs_acc_handle) != DDI_SUCCESS) {
370fcf3ce44SJohn Forte 		goto attach_fail_4;
371fcf3ce44SJohn Forte 	}
372fcf3ce44SJohn Forte 	if (did == 0x2422) {
373fcf3ce44SJohn Forte 		uint32_t pci_bits = REG_RD32(qlt, REG_CTRL_STATUS);
374fcf3ce44SJohn Forte 		uint32_t slot = pci_bits & PCI_64_BIT_SLOT;
375fcf3ce44SJohn Forte 		pci_bits >>= 8;
376fcf3ce44SJohn Forte 		pci_bits &= 0xf;
377fcf3ce44SJohn Forte 		if ((pci_bits == 3) || (pci_bits == 7)) {
378fcf3ce44SJohn Forte 			cmn_err(CE_NOTE,
379fcf3ce44SJohn Forte 			    "!qlt(%d): HBA running at PCI%sMHz (%d)",
380fcf3ce44SJohn Forte 			    instance, pci_speeds[pci_bits], pci_bits);
381fcf3ce44SJohn Forte 		} else {
382fcf3ce44SJohn Forte 			cmn_err(CE_WARN,
383fcf3ce44SJohn Forte 			    "qlt(%d): HBA running at PCI%sMHz %s(%d)",
384fcf3ce44SJohn Forte 			    instance, (pci_bits <= 8) ? pci_speeds[pci_bits] :
385fcf3ce44SJohn Forte 			    "(Invalid)", ((pci_bits == 0) ||
386fcf3ce44SJohn Forte 			    (pci_bits == 8)) ? (slot ? "64 bit slot " :
387fcf3ce44SJohn Forte 			    "32 bit slot ") : "", pci_bits);
388fcf3ce44SJohn Forte 		}
389fcf3ce44SJohn Forte 	}
390fcf3ce44SJohn Forte 	if ((ret = qlt_read_nvram(qlt)) != QLT_SUCCESS) {
391fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "qlt(%d): read nvram failure %llx", instance,
392fcf3ce44SJohn Forte 		    (unsigned long long)ret);
393fcf3ce44SJohn Forte 		goto attach_fail_5;
394fcf3ce44SJohn Forte 	}
395*a2255df3SDaniel Beauregard 
396*a2255df3SDaniel Beauregard 	qlt_properties(qlt);
397*a2255df3SDaniel Beauregard 
398fcf3ce44SJohn Forte 	if (ddi_dma_alloc_handle(dip, &qlt_queue_dma_attr, DDI_DMA_SLEEP,
399fcf3ce44SJohn Forte 	    0, &qlt->queue_mem_dma_handle) != DDI_SUCCESS) {
400fcf3ce44SJohn Forte 		goto attach_fail_5;
401fcf3ce44SJohn Forte 	}
402fcf3ce44SJohn Forte 	if (ddi_dma_mem_alloc(qlt->queue_mem_dma_handle, TOTAL_DMA_MEM_SIZE,
403fcf3ce44SJohn Forte 	    &dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0,
404fcf3ce44SJohn Forte 	    &qlt->queue_mem_ptr, &discard, &qlt->queue_mem_acc_handle) !=
405fcf3ce44SJohn Forte 	    DDI_SUCCESS) {
406fcf3ce44SJohn Forte 		goto attach_fail_6;
407fcf3ce44SJohn Forte 	}
408fcf3ce44SJohn Forte 	if (ddi_dma_addr_bind_handle(qlt->queue_mem_dma_handle, NULL,
409fcf3ce44SJohn Forte 	    qlt->queue_mem_ptr, TOTAL_DMA_MEM_SIZE,
410fcf3ce44SJohn Forte 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0,
411fcf3ce44SJohn Forte 	    &qlt->queue_mem_cookie, &ncookies) != DDI_SUCCESS) {
412fcf3ce44SJohn Forte 		goto attach_fail_7;
413fcf3ce44SJohn Forte 	}
414fcf3ce44SJohn Forte 	if (ncookies != 1)
415fcf3ce44SJohn Forte 		goto attach_fail_8;
416fcf3ce44SJohn Forte 	qlt->req_ptr = qlt->queue_mem_ptr + REQUEST_QUEUE_OFFSET;
417fcf3ce44SJohn Forte 	qlt->resp_ptr = qlt->queue_mem_ptr + RESPONSE_QUEUE_OFFSET;
418fcf3ce44SJohn Forte 	qlt->preq_ptr = qlt->queue_mem_ptr + PRIORITY_QUEUE_OFFSET;
419fcf3ce44SJohn Forte 	qlt->atio_ptr = qlt->queue_mem_ptr + ATIO_QUEUE_OFFSET;
420fcf3ce44SJohn Forte 
421fcf3ce44SJohn Forte 	/* mutex are inited in this function */
422fcf3ce44SJohn Forte 	if (qlt_setup_interrupts(qlt) != DDI_SUCCESS)
423fcf3ce44SJohn Forte 		goto attach_fail_8;
424fcf3ce44SJohn Forte 
425fcf3ce44SJohn Forte 	(void) snprintf(qlt->qlt_minor_name, sizeof (qlt->qlt_minor_name),
426d8c54e3dSSam Cramer 	    "qlt%d", instance);
427fcf3ce44SJohn Forte 	(void) snprintf(qlt->qlt_port_alias, sizeof (qlt->qlt_port_alias),
428fcf3ce44SJohn Forte 	    "%s,0", qlt->qlt_minor_name);
429fcf3ce44SJohn Forte 
430fcf3ce44SJohn Forte 	if (ddi_create_minor_node(dip, qlt->qlt_minor_name, S_IFCHR,
431d8c54e3dSSam Cramer 	    instance, DDI_NT_STMF_PP, 0) != DDI_SUCCESS) {
432fcf3ce44SJohn Forte 		goto attach_fail_9;
433fcf3ce44SJohn Forte 	}
434fcf3ce44SJohn Forte 
435fcf3ce44SJohn Forte 	cv_init(&qlt->rp_dereg_cv, NULL, CV_DRIVER, NULL);
436fcf3ce44SJohn Forte 	cv_init(&qlt->mbox_cv, NULL, CV_DRIVER, NULL);
437fcf3ce44SJohn Forte 	mutex_init(&qlt->qlt_ioctl_lock, NULL, MUTEX_DRIVER, NULL);
438fcf3ce44SJohn Forte 
439fcf3ce44SJohn Forte 	/* Setup PCI cfg space registers */
440fcf3ce44SJohn Forte 	max_read_size = qlt_read_int_prop(qlt, "pci-max-read-request", 11);
441fcf3ce44SJohn Forte 	if (max_read_size == 11)
442fcf3ce44SJohn Forte 		goto over_max_read_xfer_setting;
443fcf3ce44SJohn Forte 	if (did == 0x2422) {
444fcf3ce44SJohn Forte 		if (max_read_size == 512)
445fcf3ce44SJohn Forte 			val = 0;
446fcf3ce44SJohn Forte 		else if (max_read_size == 1024)
447fcf3ce44SJohn Forte 			val = 1;
448fcf3ce44SJohn Forte 		else if (max_read_size == 2048)
449fcf3ce44SJohn Forte 			val = 2;
450fcf3ce44SJohn Forte 		else if (max_read_size == 4096)
451fcf3ce44SJohn Forte 			val = 3;
452fcf3ce44SJohn Forte 		else {
453fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "qlt(%d) malformed "
454fcf3ce44SJohn Forte 			    "pci-max-read-request in qlt.conf. Valid values "
455fcf3ce44SJohn Forte 			    "for this HBA are 512/1024/2048/4096", instance);
456fcf3ce44SJohn Forte 			goto over_max_read_xfer_setting;
457fcf3ce44SJohn Forte 		}
458c4ddbbe1SDaniel Beauregard 		mr = (uint16_t)PCICFG_RD16(qlt, 0x4E);
459c4ddbbe1SDaniel Beauregard 		mr = (uint16_t)(mr & 0xfff3);
460c4ddbbe1SDaniel Beauregard 		mr = (uint16_t)(mr | (val << 2));
461fcf3ce44SJohn Forte 		PCICFG_WR16(qlt, 0x4E, mr);
462c4ddbbe1SDaniel Beauregard 	} else if ((did == 0x2432) || (did == 0x8432) ||
463c4ddbbe1SDaniel Beauregard 	    (did == 0x2532) || (did == 0x8001)) {
464fcf3ce44SJohn Forte 		if (max_read_size == 128)
465fcf3ce44SJohn Forte 			val = 0;
466fcf3ce44SJohn Forte 		else if (max_read_size == 256)
467fcf3ce44SJohn Forte 			val = 1;
468fcf3ce44SJohn Forte 		else if (max_read_size == 512)
469fcf3ce44SJohn Forte 			val = 2;
470fcf3ce44SJohn Forte 		else if (max_read_size == 1024)
471fcf3ce44SJohn Forte 			val = 3;
472fcf3ce44SJohn Forte 		else if (max_read_size == 2048)
473fcf3ce44SJohn Forte 			val = 4;
474fcf3ce44SJohn Forte 		else if (max_read_size == 4096)
475fcf3ce44SJohn Forte 			val = 5;
476fcf3ce44SJohn Forte 		else {
477fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "qlt(%d) malformed "
478fcf3ce44SJohn Forte 			    "pci-max-read-request in qlt.conf. Valid values "
479fcf3ce44SJohn Forte 			    "for this HBA are 128/256/512/1024/2048/4096",
480d8c54e3dSSam Cramer 			    instance);
481fcf3ce44SJohn Forte 			goto over_max_read_xfer_setting;
482fcf3ce44SJohn Forte 		}
483c4ddbbe1SDaniel Beauregard 		mr = (uint16_t)PCICFG_RD16(qlt, 0x54);
484c4ddbbe1SDaniel Beauregard 		mr = (uint16_t)(mr & 0x8fff);
485c4ddbbe1SDaniel Beauregard 		mr = (uint16_t)(mr | (val << 12));
486fcf3ce44SJohn Forte 		PCICFG_WR16(qlt, 0x54, mr);
487fcf3ce44SJohn Forte 	} else {
488fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "qlt(%d): dont know how to set "
489fcf3ce44SJohn Forte 		    "pci-max-read-request for this device (%x)",
490fcf3ce44SJohn Forte 		    instance, did);
491fcf3ce44SJohn Forte 	}
492fcf3ce44SJohn Forte over_max_read_xfer_setting:;
493fcf3ce44SJohn Forte 
494fcf3ce44SJohn Forte 	max_payload_size = qlt_read_int_prop(qlt, "pcie-max-payload-size", 11);
495fcf3ce44SJohn Forte 	if (max_payload_size == 11)
496fcf3ce44SJohn Forte 		goto over_max_payload_setting;
497c4ddbbe1SDaniel Beauregard 	if ((did == 0x2432) || (did == 0x8432) ||
498c4ddbbe1SDaniel Beauregard 	    (did == 0x2532) || (did == 0x8001)) {
499fcf3ce44SJohn Forte 		if (max_payload_size == 128)
500fcf3ce44SJohn Forte 			val = 0;
501fcf3ce44SJohn Forte 		else if (max_payload_size == 256)
502fcf3ce44SJohn Forte 			val = 1;
503fcf3ce44SJohn Forte 		else if (max_payload_size == 512)
504fcf3ce44SJohn Forte 			val = 2;
505fcf3ce44SJohn Forte 		else if (max_payload_size == 1024)
506fcf3ce44SJohn Forte 			val = 3;
507fcf3ce44SJohn Forte 		else {
508fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "qlt(%d) malformed "
509fcf3ce44SJohn Forte 			    "pcie-max-payload-size in qlt.conf. Valid values "
510fcf3ce44SJohn Forte 			    "for this HBA are 128/256/512/1024",
511d8c54e3dSSam Cramer 			    instance);
512fcf3ce44SJohn Forte 			goto over_max_payload_setting;
513fcf3ce44SJohn Forte 		}
514c4ddbbe1SDaniel Beauregard 		mr = (uint16_t)PCICFG_RD16(qlt, 0x54);
515c4ddbbe1SDaniel Beauregard 		mr = (uint16_t)(mr & 0xff1f);
516c4ddbbe1SDaniel Beauregard 		mr = (uint16_t)(mr | (val << 5));
517fcf3ce44SJohn Forte 		PCICFG_WR16(qlt, 0x54, mr);
518fcf3ce44SJohn Forte 	} else {
519fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "qlt(%d): dont know how to set "
520fcf3ce44SJohn Forte 		    "pcie-max-payload-size for this device (%x)",
521fcf3ce44SJohn Forte 		    instance, did);
522fcf3ce44SJohn Forte 	}
523fcf3ce44SJohn Forte 
524fcf3ce44SJohn Forte over_max_payload_setting:;
525fcf3ce44SJohn Forte 
526*a2255df3SDaniel Beauregard 	qlt_enable_intr(qlt);
527*a2255df3SDaniel Beauregard 
528fcf3ce44SJohn Forte 	if (qlt_port_start((caddr_t)qlt) != QLT_SUCCESS)
529fcf3ce44SJohn Forte 		goto attach_fail_10;
530fcf3ce44SJohn Forte 
531fcf3ce44SJohn Forte 	ddi_report_dev(dip);
532fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
533fcf3ce44SJohn Forte 
534fcf3ce44SJohn Forte attach_fail_10:;
535fcf3ce44SJohn Forte 	mutex_destroy(&qlt->qlt_ioctl_lock);
536fcf3ce44SJohn Forte 	cv_destroy(&qlt->mbox_cv);
537fcf3ce44SJohn Forte 	cv_destroy(&qlt->rp_dereg_cv);
538fcf3ce44SJohn Forte 	ddi_remove_minor_node(dip, qlt->qlt_minor_name);
539fcf3ce44SJohn Forte attach_fail_9:;
540fcf3ce44SJohn Forte 	qlt_destroy_mutex(qlt);
541fcf3ce44SJohn Forte 	qlt_release_intr(qlt);
542fcf3ce44SJohn Forte attach_fail_8:;
543fcf3ce44SJohn Forte 	(void) ddi_dma_unbind_handle(qlt->queue_mem_dma_handle);
544fcf3ce44SJohn Forte attach_fail_7:;
545fcf3ce44SJohn Forte 	ddi_dma_mem_free(&qlt->queue_mem_acc_handle);
546fcf3ce44SJohn Forte attach_fail_6:;
547fcf3ce44SJohn Forte 	ddi_dma_free_handle(&qlt->queue_mem_dma_handle);
548fcf3ce44SJohn Forte attach_fail_5:;
549fcf3ce44SJohn Forte 	ddi_regs_map_free(&qlt->regs_acc_handle);
550fcf3ce44SJohn Forte attach_fail_4:;
551fcf3ce44SJohn Forte 	pci_config_teardown(&qlt->pcicfg_acc_handle);
552fcf3ce44SJohn Forte 	kmem_free(qlt->nvram, sizeof (qlt_nvram_t));
553c4ddbbe1SDaniel Beauregard 	(void) qlt_el_trace_desc_dtor(qlt);
554fcf3ce44SJohn Forte attach_fail_2:;
555fcf3ce44SJohn Forte attach_fail_1:;
556fcf3ce44SJohn Forte 	ddi_soft_state_free(qlt_state, instance);
557fcf3ce44SJohn Forte 	return (DDI_FAILURE);
558fcf3ce44SJohn Forte }
559fcf3ce44SJohn Forte 
560fcf3ce44SJohn Forte #define	FCT_I_EVENT_BRING_PORT_OFFLINE	0x83
561fcf3ce44SJohn Forte 
562fcf3ce44SJohn Forte /* ARGSUSED */
563fcf3ce44SJohn Forte static int
564fcf3ce44SJohn Forte qlt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
565fcf3ce44SJohn Forte {
566fcf3ce44SJohn Forte 	qlt_state_t *qlt;
567fcf3ce44SJohn Forte 
568fcf3ce44SJohn Forte 	int instance;
569fcf3ce44SJohn Forte 
570fcf3ce44SJohn Forte 	instance = ddi_get_instance(dip);
571c4ddbbe1SDaniel Beauregard 	if ((qlt = (qlt_state_t *)ddi_get_soft_state(qlt_state, instance)) ==
572c4ddbbe1SDaniel Beauregard 	    NULL) {
573fcf3ce44SJohn Forte 		return (DDI_FAILURE);
574fcf3ce44SJohn Forte 	}
575fcf3ce44SJohn Forte 
576fcf3ce44SJohn Forte 	if (qlt->fw_code01) {
577fcf3ce44SJohn Forte 		return (DDI_FAILURE);
578fcf3ce44SJohn Forte 	}
579fcf3ce44SJohn Forte 
580fcf3ce44SJohn Forte 	if ((qlt->qlt_state != FCT_STATE_OFFLINE) ||
581d8c54e3dSSam Cramer 	    qlt->qlt_state_not_acked) {
582fcf3ce44SJohn Forte 		return (DDI_FAILURE);
583fcf3ce44SJohn Forte 	}
584*a2255df3SDaniel Beauregard 	if (qlt_port_stop((caddr_t)qlt) != FCT_SUCCESS) {
585fcf3ce44SJohn Forte 		return (DDI_FAILURE);
586*a2255df3SDaniel Beauregard 	}
587*a2255df3SDaniel Beauregard 
588*a2255df3SDaniel Beauregard 	qlt_disable_intr(qlt);
589*a2255df3SDaniel Beauregard 
590fcf3ce44SJohn Forte 	ddi_remove_minor_node(dip, qlt->qlt_minor_name);
591fcf3ce44SJohn Forte 	qlt_destroy_mutex(qlt);
592fcf3ce44SJohn Forte 	qlt_release_intr(qlt);
593fcf3ce44SJohn Forte 	(void) ddi_dma_unbind_handle(qlt->queue_mem_dma_handle);
594fcf3ce44SJohn Forte 	ddi_dma_mem_free(&qlt->queue_mem_acc_handle);
595fcf3ce44SJohn Forte 	ddi_dma_free_handle(&qlt->queue_mem_dma_handle);
596fcf3ce44SJohn Forte 	ddi_regs_map_free(&qlt->regs_acc_handle);
597fcf3ce44SJohn Forte 	pci_config_teardown(&qlt->pcicfg_acc_handle);
598fcf3ce44SJohn Forte 	kmem_free(qlt->nvram, sizeof (qlt_nvram_t));
599fcf3ce44SJohn Forte 	cv_destroy(&qlt->mbox_cv);
600fcf3ce44SJohn Forte 	cv_destroy(&qlt->rp_dereg_cv);
601c4ddbbe1SDaniel Beauregard 	(void) qlt_el_trace_desc_dtor(qlt);
602fcf3ce44SJohn Forte 	ddi_soft_state_free(qlt_state, instance);
603fcf3ce44SJohn Forte 
604fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
605fcf3ce44SJohn Forte }
606fcf3ce44SJohn Forte 
6070ff6bfafSDaniel Beauregard /*
6080ff6bfafSDaniel Beauregard  * qlt_quiesce	quiesce a device attached to the system.
6090ff6bfafSDaniel Beauregard  */
6100ff6bfafSDaniel Beauregard static int
6110ff6bfafSDaniel Beauregard qlt_quiesce(dev_info_t *dip)
6120ff6bfafSDaniel Beauregard {
6130ff6bfafSDaniel Beauregard 	qlt_state_t	*qlt;
6140ff6bfafSDaniel Beauregard 	uint32_t	timer;
6150ff6bfafSDaniel Beauregard 	uint32_t	stat;
6160ff6bfafSDaniel Beauregard 
6170ff6bfafSDaniel Beauregard 	qlt = ddi_get_soft_state(qlt_state, ddi_get_instance(dip));
6180ff6bfafSDaniel Beauregard 	if (qlt == NULL) {
6190ff6bfafSDaniel Beauregard 		/* Oh well.... */
6200ff6bfafSDaniel Beauregard 		return (DDI_SUCCESS);
6210ff6bfafSDaniel Beauregard 	}
6220ff6bfafSDaniel Beauregard 
623*a2255df3SDaniel Beauregard 	REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_HOST_TO_RISC_INTR));
6240ff6bfafSDaniel Beauregard 	REG_WR16(qlt, REG_MBOX0, MBC_STOP_FIRMWARE);
625*a2255df3SDaniel Beauregard 	REG_WR32(qlt, REG_HCCR, HCCR_CMD(SET_HOST_TO_RISC_INTR));
6260ff6bfafSDaniel Beauregard 	for (timer = 0; timer < 30000; timer++) {
6270ff6bfafSDaniel Beauregard 		stat = REG_RD32(qlt, REG_RISC_STATUS);
6280ff6bfafSDaniel Beauregard 		if (stat & RISC_HOST_INTR_REQUEST) {
6290ff6bfafSDaniel Beauregard 			if ((stat & FW_INTR_STATUS_MASK) < 0x12) {
6300ff6bfafSDaniel Beauregard 				REG_WR32(qlt, REG_HCCR,
631*a2255df3SDaniel Beauregard 				    HCCR_CMD(CLEAR_RISC_PAUSE));
6320ff6bfafSDaniel Beauregard 				break;
6330ff6bfafSDaniel Beauregard 			}
6340ff6bfafSDaniel Beauregard 			REG_WR32(qlt, REG_HCCR,
635*a2255df3SDaniel Beauregard 			    HCCR_CMD(CLEAR_HOST_TO_RISC_INTR));
6360ff6bfafSDaniel Beauregard 		}
6370ff6bfafSDaniel Beauregard 		drv_usecwait(100);
6380ff6bfafSDaniel Beauregard 	}
6390ff6bfafSDaniel Beauregard 	/* Reset the chip. */
6400ff6bfafSDaniel Beauregard 	REG_WR32(qlt, REG_CTRL_STATUS, CHIP_SOFT_RESET | DMA_SHUTDOWN_CTRL |
6410ff6bfafSDaniel Beauregard 	    PCI_X_XFER_CTRL);
6420ff6bfafSDaniel Beauregard 	drv_usecwait(100);
6430ff6bfafSDaniel Beauregard 
644*a2255df3SDaniel Beauregard 	qlt_disable_intr(qlt);
645*a2255df3SDaniel Beauregard 
6460ff6bfafSDaniel Beauregard 	return (DDI_SUCCESS);
6470ff6bfafSDaniel Beauregard }
6480ff6bfafSDaniel Beauregard 
649fcf3ce44SJohn Forte static void
650fcf3ce44SJohn Forte qlt_enable_intr(qlt_state_t *qlt)
651fcf3ce44SJohn Forte {
652fcf3ce44SJohn Forte 	if (qlt->intr_cap & DDI_INTR_FLAG_BLOCK) {
653fcf3ce44SJohn Forte 		(void) ddi_intr_block_enable(qlt->htable, qlt->intr_cnt);
654fcf3ce44SJohn Forte 	} else {
655fcf3ce44SJohn Forte 		int i;
656fcf3ce44SJohn Forte 		for (i = 0; i < qlt->intr_cnt; i++)
657fcf3ce44SJohn Forte 			(void) ddi_intr_enable(qlt->htable[i]);
658fcf3ce44SJohn Forte 	}
659*a2255df3SDaniel Beauregard 	qlt->qlt_intr_enabled = 1;
660fcf3ce44SJohn Forte }
661fcf3ce44SJohn Forte 
662fcf3ce44SJohn Forte static void
663fcf3ce44SJohn Forte qlt_disable_intr(qlt_state_t *qlt)
664fcf3ce44SJohn Forte {
665fcf3ce44SJohn Forte 	if (qlt->intr_cap & DDI_INTR_FLAG_BLOCK) {
666fcf3ce44SJohn Forte 		(void) ddi_intr_block_disable(qlt->htable, qlt->intr_cnt);
667fcf3ce44SJohn Forte 	} else {
668fcf3ce44SJohn Forte 		int i;
669fcf3ce44SJohn Forte 		for (i = 0; i < qlt->intr_cnt; i++)
670fcf3ce44SJohn Forte 			(void) ddi_intr_disable(qlt->htable[i]);
671fcf3ce44SJohn Forte 	}
672*a2255df3SDaniel Beauregard 	qlt->qlt_intr_enabled = 0;
673fcf3ce44SJohn Forte }
674fcf3ce44SJohn Forte 
675fcf3ce44SJohn Forte static void
676fcf3ce44SJohn Forte qlt_release_intr(qlt_state_t *qlt)
677fcf3ce44SJohn Forte {
678fcf3ce44SJohn Forte 	if (qlt->htable) {
679fcf3ce44SJohn Forte 		int i;
680fcf3ce44SJohn Forte 		for (i = 0; i < qlt->intr_cnt; i++) {
681fcf3ce44SJohn Forte 			(void) ddi_intr_remove_handler(qlt->htable[i]);
682fcf3ce44SJohn Forte 			(void) ddi_intr_free(qlt->htable[i]);
683fcf3ce44SJohn Forte 		}
684c4ddbbe1SDaniel Beauregard 		kmem_free(qlt->htable, (uint_t)qlt->intr_size);
685fcf3ce44SJohn Forte 	}
686fcf3ce44SJohn Forte 	qlt->htable = NULL;
687fcf3ce44SJohn Forte 	qlt->intr_pri = 0;
688fcf3ce44SJohn Forte 	qlt->intr_cnt = 0;
689fcf3ce44SJohn Forte 	qlt->intr_size = 0;
690fcf3ce44SJohn Forte 	qlt->intr_cap = 0;
691fcf3ce44SJohn Forte }
692fcf3ce44SJohn Forte 
693fcf3ce44SJohn Forte 
694fcf3ce44SJohn Forte static void
695fcf3ce44SJohn Forte qlt_init_mutex(qlt_state_t *qlt)
696fcf3ce44SJohn Forte {
697fcf3ce44SJohn Forte 	mutex_init(&qlt->req_lock, 0, MUTEX_DRIVER,
698fcf3ce44SJohn Forte 	    INT2PTR(qlt->intr_pri, void *));
699fcf3ce44SJohn Forte 	mutex_init(&qlt->preq_lock, 0, MUTEX_DRIVER,
700fcf3ce44SJohn Forte 	    INT2PTR(qlt->intr_pri, void *));
701fcf3ce44SJohn Forte 	mutex_init(&qlt->mbox_lock, NULL, MUTEX_DRIVER,
702fcf3ce44SJohn Forte 	    INT2PTR(qlt->intr_pri, void *));
703fcf3ce44SJohn Forte 	mutex_init(&qlt->intr_lock, NULL, MUTEX_DRIVER,
704fcf3ce44SJohn Forte 	    INT2PTR(qlt->intr_pri, void *));
705fcf3ce44SJohn Forte }
706fcf3ce44SJohn Forte 
707fcf3ce44SJohn Forte static void
708fcf3ce44SJohn Forte qlt_destroy_mutex(qlt_state_t *qlt)
709fcf3ce44SJohn Forte {
710fcf3ce44SJohn Forte 	mutex_destroy(&qlt->req_lock);
711fcf3ce44SJohn Forte 	mutex_destroy(&qlt->preq_lock);
712fcf3ce44SJohn Forte 	mutex_destroy(&qlt->mbox_lock);
713fcf3ce44SJohn Forte 	mutex_destroy(&qlt->intr_lock);
714fcf3ce44SJohn Forte }
715fcf3ce44SJohn Forte 
716fcf3ce44SJohn Forte 
717fcf3ce44SJohn Forte static int
718fcf3ce44SJohn Forte qlt_setup_msix(qlt_state_t *qlt)
719fcf3ce44SJohn Forte {
720fcf3ce44SJohn Forte 	int count, avail, actual;
721fcf3ce44SJohn Forte 	int ret;
722fcf3ce44SJohn Forte 	int itype = DDI_INTR_TYPE_MSIX;
723fcf3ce44SJohn Forte 	int i;
724fcf3ce44SJohn Forte 
725fcf3ce44SJohn Forte 	ret = ddi_intr_get_nintrs(qlt->dip, itype, &count);
726fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS || count == 0) {
727c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_get_nintrs status=%xh, count=%d\n", ret,
728c4ddbbe1SDaniel Beauregard 		    count);
729fcf3ce44SJohn Forte 		return (DDI_FAILURE);
730fcf3ce44SJohn Forte 	}
731fcf3ce44SJohn Forte 	ret = ddi_intr_get_navail(qlt->dip, itype, &avail);
732fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS || avail == 0) {
733c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_get_navail status=%xh, avail=%d\n", ret,
734c4ddbbe1SDaniel Beauregard 		    avail);
735fcf3ce44SJohn Forte 		return (DDI_FAILURE);
736fcf3ce44SJohn Forte 	}
737fcf3ce44SJohn Forte 	if (avail < count) {
738fcf3ce44SJohn Forte 		stmf_trace(qlt->qlt_port_alias,
739fcf3ce44SJohn Forte 		    "qlt_setup_msix: nintrs=%d,avail=%d", count, avail);
740fcf3ce44SJohn Forte 	}
741fcf3ce44SJohn Forte 
742c4ddbbe1SDaniel Beauregard 	qlt->intr_size = (int)(count * (int)sizeof (ddi_intr_handle_t));
743c4ddbbe1SDaniel Beauregard 	qlt->htable = kmem_zalloc((uint_t)qlt->intr_size, KM_SLEEP);
744fcf3ce44SJohn Forte 	ret = ddi_intr_alloc(qlt->dip, qlt->htable, itype,
745fcf3ce44SJohn Forte 	    DDI_INTR_ALLOC_NORMAL, count, &actual, 0);
746fcf3ce44SJohn Forte 	/* we need at least 2 interrupt vectors */
747fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS || actual < 2) {
748c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_alloc status=%xh, actual=%d\n", ret,
749c4ddbbe1SDaniel Beauregard 		    actual);
750fcf3ce44SJohn Forte 		ret = DDI_FAILURE;
751fcf3ce44SJohn Forte 		goto release_intr;
752fcf3ce44SJohn Forte 	}
753fcf3ce44SJohn Forte 	if (actual < count) {
754c4ddbbe1SDaniel Beauregard 		EL(qlt, "requested: %d, received: %d\n", count, actual);
755fcf3ce44SJohn Forte 	}
756fcf3ce44SJohn Forte 
757fcf3ce44SJohn Forte 	qlt->intr_cnt = actual;
758fcf3ce44SJohn Forte 	ret =  ddi_intr_get_pri(qlt->htable[0], &qlt->intr_pri);
759fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS) {
760c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_get_pri status=%xh\n", ret);
761fcf3ce44SJohn Forte 		ret = DDI_FAILURE;
762fcf3ce44SJohn Forte 		goto release_intr;
763fcf3ce44SJohn Forte 	}
764fcf3ce44SJohn Forte 	qlt_init_mutex(qlt);
765fcf3ce44SJohn Forte 	for (i = 0; i < actual; i++) {
766fcf3ce44SJohn Forte 		ret = ddi_intr_add_handler(qlt->htable[i], qlt_isr,
767c4ddbbe1SDaniel Beauregard 		    qlt, INT2PTR((uint_t)i, void *));
768c4ddbbe1SDaniel Beauregard 		if (ret != DDI_SUCCESS) {
769c4ddbbe1SDaniel Beauregard 			EL(qlt, "ddi_intr_add_handler status=%xh\n", ret);
770fcf3ce44SJohn Forte 			goto release_mutex;
771c4ddbbe1SDaniel Beauregard 		}
772fcf3ce44SJohn Forte 	}
773fcf3ce44SJohn Forte 
774fcf3ce44SJohn Forte 	(void) ddi_intr_get_cap(qlt->htable[0], &qlt->intr_cap);
775fcf3ce44SJohn Forte 	qlt->intr_flags |= QLT_INTR_MSIX;
776fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
777fcf3ce44SJohn Forte 
778fcf3ce44SJohn Forte release_mutex:
779fcf3ce44SJohn Forte 	qlt_destroy_mutex(qlt);
780fcf3ce44SJohn Forte release_intr:
781fcf3ce44SJohn Forte 	for (i = 0; i < actual; i++)
782fcf3ce44SJohn Forte 		(void) ddi_intr_free(qlt->htable[i]);
783c4ddbbe1SDaniel Beauregard #if 0
784fcf3ce44SJohn Forte free_mem:
785c4ddbbe1SDaniel Beauregard #endif
786c4ddbbe1SDaniel Beauregard 	kmem_free(qlt->htable, (uint_t)qlt->intr_size);
787fcf3ce44SJohn Forte 	qlt->htable = NULL;
788fcf3ce44SJohn Forte 	qlt_release_intr(qlt);
789fcf3ce44SJohn Forte 	return (ret);
790fcf3ce44SJohn Forte }
791fcf3ce44SJohn Forte 
792fcf3ce44SJohn Forte 
793fcf3ce44SJohn Forte static int
794fcf3ce44SJohn Forte qlt_setup_msi(qlt_state_t *qlt)
795fcf3ce44SJohn Forte {
796fcf3ce44SJohn Forte 	int count, avail, actual;
797fcf3ce44SJohn Forte 	int itype = DDI_INTR_TYPE_MSI;
798fcf3ce44SJohn Forte 	int ret;
799fcf3ce44SJohn Forte 	int i;
800fcf3ce44SJohn Forte 
801fcf3ce44SJohn Forte 	/* get the # of interrupts */
802fcf3ce44SJohn Forte 	ret = ddi_intr_get_nintrs(qlt->dip, itype, &count);
803fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS || count == 0) {
804c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_get_nintrs status=%xh, count=%d\n", ret,
805c4ddbbe1SDaniel Beauregard 		    count);
806fcf3ce44SJohn Forte 		return (DDI_FAILURE);
807fcf3ce44SJohn Forte 	}
808fcf3ce44SJohn Forte 	ret = ddi_intr_get_navail(qlt->dip, itype, &avail);
809fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS || avail == 0) {
810c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_get_navail status=%xh, avail=%d\n", ret,
811c4ddbbe1SDaniel Beauregard 		    avail);
812fcf3ce44SJohn Forte 		return (DDI_FAILURE);
813fcf3ce44SJohn Forte 	}
814fcf3ce44SJohn Forte 	if (avail < count) {
815c4ddbbe1SDaniel Beauregard 		EL(qlt, "nintrs=%d, avail=%d\n", count, avail);
816fcf3ce44SJohn Forte 	}
817fcf3ce44SJohn Forte 	/* MSI requires only 1 interrupt. */
818fcf3ce44SJohn Forte 	count = 1;
819fcf3ce44SJohn Forte 
820fcf3ce44SJohn Forte 	/* allocate interrupt */
821c4ddbbe1SDaniel Beauregard 	qlt->intr_size = (int)(count * (int)sizeof (ddi_intr_handle_t));
822c4ddbbe1SDaniel Beauregard 	qlt->htable = kmem_zalloc((uint_t)qlt->intr_size, KM_SLEEP);
823fcf3ce44SJohn Forte 	ret = ddi_intr_alloc(qlt->dip, qlt->htable, itype,
824fcf3ce44SJohn Forte 	    0, count, &actual, DDI_INTR_ALLOC_NORMAL);
825fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS || actual == 0) {
826c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_alloc status=%xh, actual=%d\n", ret,
827c4ddbbe1SDaniel Beauregard 		    actual);
828fcf3ce44SJohn Forte 		ret = DDI_FAILURE;
829fcf3ce44SJohn Forte 		goto free_mem;
830fcf3ce44SJohn Forte 	}
831fcf3ce44SJohn Forte 	if (actual < count) {
832c4ddbbe1SDaniel Beauregard 		EL(qlt, "requested: %d, received: %d\n", count, actual);
833fcf3ce44SJohn Forte 	}
834fcf3ce44SJohn Forte 	qlt->intr_cnt = actual;
835fcf3ce44SJohn Forte 
836fcf3ce44SJohn Forte 	/*
837fcf3ce44SJohn Forte 	 * Get priority for first msi, assume remaining are all the same.
838fcf3ce44SJohn Forte 	 */
839fcf3ce44SJohn Forte 	ret =  ddi_intr_get_pri(qlt->htable[0], &qlt->intr_pri);
840fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS) {
841c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_get_pri status=%xh\n", ret);
842fcf3ce44SJohn Forte 		ret = DDI_FAILURE;
843fcf3ce44SJohn Forte 		goto release_intr;
844fcf3ce44SJohn Forte 	}
845fcf3ce44SJohn Forte 	qlt_init_mutex(qlt);
846fcf3ce44SJohn Forte 
847fcf3ce44SJohn Forte 	/* add handler */
848fcf3ce44SJohn Forte 	for (i = 0; i < actual; i++) {
849fcf3ce44SJohn Forte 		ret = ddi_intr_add_handler(qlt->htable[i], qlt_isr,
850c4ddbbe1SDaniel Beauregard 		    qlt, INT2PTR((uint_t)i, void *));
851c4ddbbe1SDaniel Beauregard 		if (ret != DDI_SUCCESS) {
852c4ddbbe1SDaniel Beauregard 			EL(qlt, "ddi_intr_add_handler status=%xh\n", ret);
853fcf3ce44SJohn Forte 			goto release_mutex;
854c4ddbbe1SDaniel Beauregard 		}
855fcf3ce44SJohn Forte 	}
856fcf3ce44SJohn Forte 
857fcf3ce44SJohn Forte 	(void) ddi_intr_get_cap(qlt->htable[0], &qlt->intr_cap);
858fcf3ce44SJohn Forte 	qlt->intr_flags |= QLT_INTR_MSI;
859fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
860fcf3ce44SJohn Forte 
861fcf3ce44SJohn Forte release_mutex:
862fcf3ce44SJohn Forte 	qlt_destroy_mutex(qlt);
863fcf3ce44SJohn Forte release_intr:
864fcf3ce44SJohn Forte 	for (i = 0; i < actual; i++)
865fcf3ce44SJohn Forte 		(void) ddi_intr_free(qlt->htable[i]);
866fcf3ce44SJohn Forte free_mem:
867c4ddbbe1SDaniel Beauregard 	kmem_free(qlt->htable, (uint_t)qlt->intr_size);
868fcf3ce44SJohn Forte 	qlt->htable = NULL;
869fcf3ce44SJohn Forte 	qlt_release_intr(qlt);
870fcf3ce44SJohn Forte 	return (ret);
871fcf3ce44SJohn Forte }
872fcf3ce44SJohn Forte 
873fcf3ce44SJohn Forte static int
874fcf3ce44SJohn Forte qlt_setup_fixed(qlt_state_t *qlt)
875fcf3ce44SJohn Forte {
876fcf3ce44SJohn Forte 	int count;
877fcf3ce44SJohn Forte 	int actual;
878fcf3ce44SJohn Forte 	int ret;
879fcf3ce44SJohn Forte 	int itype = DDI_INTR_TYPE_FIXED;
880fcf3ce44SJohn Forte 
881fcf3ce44SJohn Forte 	ret = ddi_intr_get_nintrs(qlt->dip, itype, &count);
882fcf3ce44SJohn Forte 	/* Fixed interrupts can only have one interrupt. */
883fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS || count != 1) {
884c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_get_nintrs status=%xh, count=%d\n", ret,
885c4ddbbe1SDaniel Beauregard 		    count);
886fcf3ce44SJohn Forte 		return (DDI_FAILURE);
887fcf3ce44SJohn Forte 	}
888fcf3ce44SJohn Forte 
889fcf3ce44SJohn Forte 	qlt->intr_size = sizeof (ddi_intr_handle_t);
890c4ddbbe1SDaniel Beauregard 	qlt->htable = kmem_zalloc((uint_t)qlt->intr_size, KM_SLEEP);
891fcf3ce44SJohn Forte 	ret = ddi_intr_alloc(qlt->dip, qlt->htable, itype,
892fcf3ce44SJohn Forte 	    DDI_INTR_ALLOC_NORMAL, count, &actual, 0);
893fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS || actual != 1) {
894c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_alloc status=%xh, actual=%d\n", ret,
895c4ddbbe1SDaniel Beauregard 		    actual);
896fcf3ce44SJohn Forte 		ret = DDI_FAILURE;
897fcf3ce44SJohn Forte 		goto free_mem;
898fcf3ce44SJohn Forte 	}
899fcf3ce44SJohn Forte 
900fcf3ce44SJohn Forte 	qlt->intr_cnt = actual;
901fcf3ce44SJohn Forte 	ret =  ddi_intr_get_pri(qlt->htable[0], &qlt->intr_pri);
902fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS) {
903c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_get_pri status=%xh\n", ret);
904fcf3ce44SJohn Forte 		ret = DDI_FAILURE;
905fcf3ce44SJohn Forte 		goto release_intr;
906fcf3ce44SJohn Forte 	}
907fcf3ce44SJohn Forte 	qlt_init_mutex(qlt);
908fcf3ce44SJohn Forte 	ret = ddi_intr_add_handler(qlt->htable[0], qlt_isr, qlt, 0);
909c4ddbbe1SDaniel Beauregard 	if (ret != DDI_SUCCESS) {
910c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_add_handler status=%xh\n", ret);
911fcf3ce44SJohn Forte 		goto release_mutex;
912c4ddbbe1SDaniel Beauregard 	}
913fcf3ce44SJohn Forte 
914fcf3ce44SJohn Forte 	qlt->intr_flags |= QLT_INTR_FIXED;
915fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
916fcf3ce44SJohn Forte 
917fcf3ce44SJohn Forte release_mutex:
918fcf3ce44SJohn Forte 	qlt_destroy_mutex(qlt);
919fcf3ce44SJohn Forte release_intr:
920fcf3ce44SJohn Forte 	(void) ddi_intr_free(qlt->htable[0]);
921fcf3ce44SJohn Forte free_mem:
922c4ddbbe1SDaniel Beauregard 	kmem_free(qlt->htable, (uint_t)qlt->intr_size);
923fcf3ce44SJohn Forte 	qlt->htable = NULL;
924fcf3ce44SJohn Forte 	qlt_release_intr(qlt);
925fcf3ce44SJohn Forte 	return (ret);
926fcf3ce44SJohn Forte }
927fcf3ce44SJohn Forte 
928fcf3ce44SJohn Forte static int
929fcf3ce44SJohn Forte qlt_setup_interrupts(qlt_state_t *qlt)
930fcf3ce44SJohn Forte {
931fcf3ce44SJohn Forte 	int itypes = 0;
932fcf3ce44SJohn Forte 
933fcf3ce44SJohn Forte /*
934*a2255df3SDaniel Beauregard  * x86 has a bug in the ddi_intr_block_enable/disable area (6562198).
935fcf3ce44SJohn Forte  */
936*a2255df3SDaniel Beauregard #ifndef __sparc
937*a2255df3SDaniel Beauregard 	if (qlt_enable_msi != 0) {
938*a2255df3SDaniel Beauregard #endif
939fcf3ce44SJohn Forte 	if (ddi_intr_get_supported_types(qlt->dip, &itypes) != DDI_SUCCESS) {
940fcf3ce44SJohn Forte 		itypes = DDI_INTR_TYPE_FIXED;
941fcf3ce44SJohn Forte 	}
942fcf3ce44SJohn Forte 
943fcf3ce44SJohn Forte 	if (qlt_enable_msix && (itypes & DDI_INTR_TYPE_MSIX)) {
944fcf3ce44SJohn Forte 		if (qlt_setup_msix(qlt) == DDI_SUCCESS)
945fcf3ce44SJohn Forte 			return (DDI_SUCCESS);
946fcf3ce44SJohn Forte 	}
947*a2255df3SDaniel Beauregard 
948fcf3ce44SJohn Forte 	if (itypes & DDI_INTR_TYPE_MSI) {
949fcf3ce44SJohn Forte 		if (qlt_setup_msi(qlt) == DDI_SUCCESS)
950fcf3ce44SJohn Forte 			return (DDI_SUCCESS);
951fcf3ce44SJohn Forte 	}
952*a2255df3SDaniel Beauregard #ifndef __sparc
953*a2255df3SDaniel Beauregard 	}
954fcf3ce44SJohn Forte #endif
955fcf3ce44SJohn Forte 	return (qlt_setup_fixed(qlt));
956fcf3ce44SJohn Forte }
957fcf3ce44SJohn Forte 
958fcf3ce44SJohn Forte /*
959fcf3ce44SJohn Forte  * Filling the hba attributes
960fcf3ce44SJohn Forte  */
961fcf3ce44SJohn Forte void
962fcf3ce44SJohn Forte qlt_populate_hba_fru_details(struct fct_local_port *port,
963fcf3ce44SJohn Forte     struct fct_port_attrs *port_attrs)
964fcf3ce44SJohn Forte {
965fcf3ce44SJohn Forte 	caddr_t	bufp;
966fcf3ce44SJohn Forte 	int len;
967fcf3ce44SJohn Forte 	qlt_state_t *qlt = (qlt_state_t *)port->port_fca_private;
968fcf3ce44SJohn Forte 
969fcf3ce44SJohn Forte 	(void) snprintf(port_attrs->manufacturer, FCHBA_MANUFACTURER_LEN,
970fcf3ce44SJohn Forte 	    "QLogic Corp.");
971fcf3ce44SJohn Forte 	(void) snprintf(port_attrs->driver_name, FCHBA_DRIVER_NAME_LEN,
972fcf3ce44SJohn Forte 	    "%s", QLT_NAME);
973fcf3ce44SJohn Forte 	(void) snprintf(port_attrs->driver_version, FCHBA_DRIVER_VERSION_LEN,
974fcf3ce44SJohn Forte 	    "%s", QLT_VERSION);
975fcf3ce44SJohn Forte 	port_attrs->serial_number[0] = '\0';
976fcf3ce44SJohn Forte 	port_attrs->hardware_version[0] = '\0';
977fcf3ce44SJohn Forte 
978fcf3ce44SJohn Forte 	(void) snprintf(port_attrs->firmware_version,
979fcf3ce44SJohn Forte 	    FCHBA_FIRMWARE_VERSION_LEN, "%d.%d.%d", qlt->fw_major,
980fcf3ce44SJohn Forte 	    qlt->fw_minor, qlt->fw_subminor);
981fcf3ce44SJohn Forte 
982fcf3ce44SJohn Forte 	/* Get FCode version */
983fcf3ce44SJohn Forte 	if (ddi_getlongprop(DDI_DEV_T_ANY, qlt->dip, PROP_LEN_AND_VAL_ALLOC |
984fcf3ce44SJohn Forte 	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "version", (caddr_t)&bufp,
985fcf3ce44SJohn Forte 	    (int *)&len) == DDI_PROP_SUCCESS) {
986fcf3ce44SJohn Forte 		(void) snprintf(port_attrs->option_rom_version,
987fcf3ce44SJohn Forte 		    FCHBA_OPTION_ROM_VERSION_LEN, "%s", bufp);
988c4ddbbe1SDaniel Beauregard 		kmem_free(bufp, (uint_t)len);
989fcf3ce44SJohn Forte 		bufp = NULL;
990fcf3ce44SJohn Forte 	} else {
991fcf3ce44SJohn Forte #ifdef __sparc
992c4ddbbe1SDaniel Beauregard 		(void) snprintf(port_attrs->option_rom_version,
993c4ddbbe1SDaniel Beauregard 		    FCHBA_OPTION_ROM_VERSION_LEN, "No Fcode found");
994fcf3ce44SJohn Forte #else
995564a03c8Sjmcp 		(void) snprintf(port_attrs->option_rom_version,
996c4ddbbe1SDaniel Beauregard 		    FCHBA_OPTION_ROM_VERSION_LEN, "N/A");
997c4ddbbe1SDaniel Beauregard #endif
998fcf3ce44SJohn Forte 	}
999fcf3ce44SJohn Forte 	port_attrs->vendor_specific_id = qlt->nvram->subsystem_vendor_id[0] |
1000fcf3ce44SJohn Forte 	    qlt->nvram->subsystem_vendor_id[1] << 8;
1001fcf3ce44SJohn Forte 
1002fcf3ce44SJohn Forte 	port_attrs->max_frame_size = qlt->nvram->max_frame_length[1] << 8 |
1003fcf3ce44SJohn Forte 	    qlt->nvram->max_frame_length[0];
1004fcf3ce44SJohn Forte 
1005fcf3ce44SJohn Forte 	port_attrs->supported_cos = 0x10000000;
1006fcf3ce44SJohn Forte 	port_attrs->supported_speed = PORT_SPEED_1G |
1007fcf3ce44SJohn Forte 	    PORT_SPEED_2G | PORT_SPEED_4G;
1008fcf3ce44SJohn Forte 	if (qlt->qlt_25xx_chip)
1009fcf3ce44SJohn Forte 		port_attrs->supported_speed |= PORT_SPEED_8G;
1010c4ddbbe1SDaniel Beauregard 	if (qlt->qlt_81xx_chip)
1011c4ddbbe1SDaniel Beauregard 		port_attrs->supported_speed = PORT_SPEED_10G;
1012c4ddbbe1SDaniel Beauregard 
1013c4ddbbe1SDaniel Beauregard 	/* limit string length to nvr model_name length */
1014c4ddbbe1SDaniel Beauregard 	len = (qlt->qlt_81xx_chip) ? 16 : 8;
1015c4ddbbe1SDaniel Beauregard 	(void) snprintf(port_attrs->model,
1016c4ddbbe1SDaniel Beauregard 	    (uint_t)(len < FCHBA_MODEL_LEN ? len : FCHBA_MODEL_LEN),
1017c4ddbbe1SDaniel Beauregard 	    "%s", qlt->nvram->model_name);
1018fcf3ce44SJohn Forte 
1019fcf3ce44SJohn Forte 	(void) snprintf(port_attrs->model_description,
1020c4ddbbe1SDaniel Beauregard 	    (uint_t)(len < FCHBA_MODEL_DESCRIPTION_LEN ? len :
1021c4ddbbe1SDaniel Beauregard 	    FCHBA_MODEL_DESCRIPTION_LEN),
1022c4ddbbe1SDaniel Beauregard 	    "%s", qlt->nvram->model_name);
1023fcf3ce44SJohn Forte }
1024fcf3ce44SJohn Forte 
1025c946facaSallan /* ARGSUSED */
1026c946facaSallan fct_status_t
1027c946facaSallan qlt_info(uint32_t cmd, fct_local_port_t *port,
1028c946facaSallan     void *arg, uint8_t *buf, uint32_t *bufsizep)
1029c946facaSallan {
1030c946facaSallan 	qlt_state_t	*qlt = (qlt_state_t *)port->port_fca_private;
1031c946facaSallan 	mbox_cmd_t	*mcp;
1032c946facaSallan 	fct_status_t	ret = FCT_SUCCESS;
1033c946facaSallan 	uint8_t		*p;
1034c946facaSallan 	fct_port_link_status_t	*link_status;
1035c946facaSallan 
1036c946facaSallan 	switch (cmd) {
1037c946facaSallan 	case FC_TGT_PORT_RLS:
1038c946facaSallan 		if ((*bufsizep) < sizeof (fct_port_link_status_t)) {
1039c4ddbbe1SDaniel Beauregard 			EL(qlt, "FC_TGT_PORT_RLS bufsizep=%xh < "
1040c4ddbbe1SDaniel Beauregard 			    "fct_port_link_status_t=%xh\n", *bufsizep,
1041c4ddbbe1SDaniel Beauregard 			    sizeof (fct_port_link_status_t));
1042c946facaSallan 			ret = FCT_FAILURE;
1043c946facaSallan 			break;
1044c946facaSallan 		}
1045c946facaSallan 		/* send mailbox command to get link status */
1046c946facaSallan 		mcp = qlt_alloc_mailbox_command(qlt, 156);
1047c946facaSallan 		if (mcp == NULL) {
1048c4ddbbe1SDaniel Beauregard 			EL(qlt, "qlt_alloc_mailbox_command mcp=null\n");
1049c946facaSallan 			ret = FCT_ALLOC_FAILURE;
1050c946facaSallan 			break;
1051c946facaSallan 		}
1052c946facaSallan 
1053c946facaSallan 		/* GET LINK STATUS count */
1054*a2255df3SDaniel Beauregard 		mcp->to_fw[0] = MBC_GET_STATUS_COUNTS;
1055c946facaSallan 		mcp->to_fw[8] = 156/4;
1056c946facaSallan 		mcp->to_fw_mask |= BIT_1 | BIT_8;
1057c946facaSallan 		mcp->from_fw_mask |= BIT_1 | BIT_2;
1058c946facaSallan 
1059c946facaSallan 		ret = qlt_mailbox_command(qlt, mcp);
1060c946facaSallan 		if (ret != QLT_SUCCESS) {
1061c4ddbbe1SDaniel Beauregard 			EL(qlt, "qlt_mailbox_command=6dh status=%llxh\n", ret);
1062c946facaSallan 			qlt_free_mailbox_command(qlt, mcp);
1063c946facaSallan 			break;
1064c946facaSallan 		}
1065c946facaSallan 		qlt_dmem_dma_sync(mcp->dbuf, DDI_DMA_SYNC_FORCPU);
1066c946facaSallan 
1067c946facaSallan 		p = mcp->dbuf->db_sglist[0].seg_addr;
1068c946facaSallan 		link_status = (fct_port_link_status_t *)buf;
1069c946facaSallan 		link_status->LinkFailureCount = LE_32(*((uint32_t *)p));
1070c946facaSallan 		link_status->LossOfSyncCount = LE_32(*((uint32_t *)(p + 4)));
1071c946facaSallan 		link_status->LossOfSignalsCount = LE_32(*((uint32_t *)(p + 8)));
1072c946facaSallan 		link_status->PrimitiveSeqProtocolErrorCount =
1073c946facaSallan 		    LE_32(*((uint32_t *)(p + 12)));
1074c946facaSallan 		link_status->InvalidTransmissionWordCount =
1075c946facaSallan 		    LE_32(*((uint32_t *)(p + 16)));
1076c946facaSallan 		link_status->InvalidCRCCount =
1077c946facaSallan 		    LE_32(*((uint32_t *)(p + 20)));
1078c946facaSallan 
1079c946facaSallan 		qlt_free_mailbox_command(qlt, mcp);
1080c946facaSallan 		break;
1081c946facaSallan 	default:
1082c4ddbbe1SDaniel Beauregard 		EL(qlt, "Unknown cmd=%xh\n", cmd);
1083c946facaSallan 		ret = FCT_FAILURE;
1084c946facaSallan 		break;
1085c946facaSallan 	}
1086c946facaSallan 	return (ret);
1087c946facaSallan }
1088c946facaSallan 
1089fcf3ce44SJohn Forte fct_status_t
1090fcf3ce44SJohn Forte qlt_port_start(caddr_t arg)
1091fcf3ce44SJohn Forte {
1092fcf3ce44SJohn Forte 	qlt_state_t *qlt = (qlt_state_t *)arg;
1093fcf3ce44SJohn Forte 	fct_local_port_t *port;
1094fcf3ce44SJohn Forte 	fct_dbuf_store_t *fds;
1095c4ddbbe1SDaniel Beauregard 	fct_status_t ret;
1096fcf3ce44SJohn Forte 
1097fcf3ce44SJohn Forte 	if (qlt_dmem_init(qlt) != QLT_SUCCESS) {
1098fcf3ce44SJohn Forte 		return (FCT_FAILURE);
1099fcf3ce44SJohn Forte 	}
1100fcf3ce44SJohn Forte 	port = (fct_local_port_t *)fct_alloc(FCT_STRUCT_LOCAL_PORT, 0, 0);
1101fcf3ce44SJohn Forte 	if (port == NULL) {
1102fcf3ce44SJohn Forte 		goto qlt_pstart_fail_1;
1103fcf3ce44SJohn Forte 	}
1104fcf3ce44SJohn Forte 	fds = (fct_dbuf_store_t *)fct_alloc(FCT_STRUCT_DBUF_STORE, 0, 0);
1105fcf3ce44SJohn Forte 	if (fds == NULL) {
1106fcf3ce44SJohn Forte 		goto qlt_pstart_fail_2;
1107fcf3ce44SJohn Forte 	}
1108fcf3ce44SJohn Forte 	qlt->qlt_port = port;
1109fcf3ce44SJohn Forte 	fds->fds_alloc_data_buf = qlt_dmem_alloc;
1110fcf3ce44SJohn Forte 	fds->fds_free_data_buf = qlt_dmem_free;
1111fcf3ce44SJohn Forte 	fds->fds_fca_private = (void *)qlt;
1112fcf3ce44SJohn Forte 	/*
1113fcf3ce44SJohn Forte 	 * Since we keep everything in the state struct and dont allocate any
1114fcf3ce44SJohn Forte 	 * port private area, just use that pointer to point to the
1115fcf3ce44SJohn Forte 	 * state struct.
1116fcf3ce44SJohn Forte 	 */
1117fcf3ce44SJohn Forte 	port->port_fca_private = qlt;
1118fcf3ce44SJohn Forte 	port->port_fca_abort_timeout = 5 * 1000;	/* 5 seconds */
1119fcf3ce44SJohn Forte 	bcopy(qlt->nvram->node_name, port->port_nwwn, 8);
1120fcf3ce44SJohn Forte 	bcopy(qlt->nvram->port_name, port->port_pwwn, 8);
1121d8c54e3dSSam Cramer 	fct_wwn_to_str(port->port_nwwn_str, port->port_nwwn);
1122d8c54e3dSSam Cramer 	fct_wwn_to_str(port->port_pwwn_str, port->port_pwwn);
1123fcf3ce44SJohn Forte 	port->port_default_alias = qlt->qlt_port_alias;
1124fcf3ce44SJohn Forte 	port->port_pp = qlt_pp;
1125fcf3ce44SJohn Forte 	port->port_fds = fds;
1126fcf3ce44SJohn Forte 	port->port_max_logins = QLT_MAX_LOGINS;
1127fcf3ce44SJohn Forte 	port->port_max_xchges = QLT_MAX_XCHGES;
1128fcf3ce44SJohn Forte 	port->port_fca_fcp_cmd_size = sizeof (qlt_cmd_t);
1129fcf3ce44SJohn Forte 	port->port_fca_rp_private_size = sizeof (qlt_remote_port_t);
1130fcf3ce44SJohn Forte 	port->port_fca_sol_els_private_size = sizeof (qlt_cmd_t);
1131fcf3ce44SJohn Forte 	port->port_fca_sol_ct_private_size = sizeof (qlt_cmd_t);
1132fcf3ce44SJohn Forte 	port->port_get_link_info = qlt_get_link_info;
1133fcf3ce44SJohn Forte 	port->port_register_remote_port = qlt_register_remote_port;
1134fcf3ce44SJohn Forte 	port->port_deregister_remote_port = qlt_deregister_remote_port;
1135fcf3ce44SJohn Forte 	port->port_send_cmd = qlt_send_cmd;
1136fcf3ce44SJohn Forte 	port->port_xfer_scsi_data = qlt_xfer_scsi_data;
1137fcf3ce44SJohn Forte 	port->port_send_cmd_response = qlt_send_cmd_response;
1138fcf3ce44SJohn Forte 	port->port_abort_cmd = qlt_abort_cmd;
1139fcf3ce44SJohn Forte 	port->port_ctl = qlt_ctl;
1140fcf3ce44SJohn Forte 	port->port_flogi_xchg = qlt_do_flogi;
1141fcf3ce44SJohn Forte 	port->port_populate_hba_details = qlt_populate_hba_fru_details;
1142c946facaSallan 	port->port_info = qlt_info;
1143*a2255df3SDaniel Beauregard 	port->port_fca_version = FCT_FCA_MODREV_1;
1144fcf3ce44SJohn Forte 
1145c4ddbbe1SDaniel Beauregard 	if ((ret = fct_register_local_port(port)) != FCT_SUCCESS) {
1146c4ddbbe1SDaniel Beauregard 		EL(qlt, "fct_register_local_port status=%llxh\n", ret);
1147fcf3ce44SJohn Forte 		goto qlt_pstart_fail_2_5;
1148fcf3ce44SJohn Forte 	}
1149fcf3ce44SJohn Forte 
1150fcf3ce44SJohn Forte 	return (QLT_SUCCESS);
1151c4ddbbe1SDaniel Beauregard #if 0
1152fcf3ce44SJohn Forte qlt_pstart_fail_3:
1153fcf3ce44SJohn Forte 	(void) fct_deregister_local_port(port);
1154c4ddbbe1SDaniel Beauregard #endif
1155fcf3ce44SJohn Forte qlt_pstart_fail_2_5:
1156fcf3ce44SJohn Forte 	fct_free(fds);
1157fcf3ce44SJohn Forte qlt_pstart_fail_2:
1158fcf3ce44SJohn Forte 	fct_free(port);
1159fcf3ce44SJohn Forte 	qlt->qlt_port = NULL;
1160fcf3ce44SJohn Forte qlt_pstart_fail_1:
1161fcf3ce44SJohn Forte 	qlt_dmem_fini(qlt);
1162fcf3ce44SJohn Forte 	return (QLT_FAILURE);
1163fcf3ce44SJohn Forte }
1164fcf3ce44SJohn Forte 
1165fcf3ce44SJohn Forte fct_status_t
1166fcf3ce44SJohn Forte qlt_port_stop(caddr_t arg)
1167fcf3ce44SJohn Forte {
1168fcf3ce44SJohn Forte 	qlt_state_t *qlt = (qlt_state_t *)arg;
1169c4ddbbe1SDaniel Beauregard 	fct_status_t ret;
1170fcf3ce44SJohn Forte 
1171c4ddbbe1SDaniel Beauregard 	if ((ret = fct_deregister_local_port(qlt->qlt_port)) != FCT_SUCCESS) {
1172c4ddbbe1SDaniel Beauregard 		EL(qlt, "fct_register_local_port status=%llxh\n", ret);
1173fcf3ce44SJohn Forte 		return (QLT_FAILURE);
1174c4ddbbe1SDaniel Beauregard 	}
1175fcf3ce44SJohn Forte 	fct_free(qlt->qlt_port->port_fds);
1176fcf3ce44SJohn Forte 	fct_free(qlt->qlt_port);
1177fcf3ce44SJohn Forte 	qlt->qlt_port = NULL;
1178fcf3ce44SJohn Forte 	qlt_dmem_fini(qlt);
1179fcf3ce44SJohn Forte 	return (QLT_SUCCESS);
1180fcf3ce44SJohn Forte }
1181fcf3ce44SJohn Forte 
1182fcf3ce44SJohn Forte /*
1183fcf3ce44SJohn Forte  * Called by framework to init the HBA.
1184fcf3ce44SJohn Forte  * Can be called in the middle of I/O. (Why ??)
1185fcf3ce44SJohn Forte  * Should make sure sane state both before and after the initialization
1186fcf3ce44SJohn Forte  */
1187fcf3ce44SJohn Forte fct_status_t
1188fcf3ce44SJohn Forte qlt_port_online(qlt_state_t *qlt)
1189fcf3ce44SJohn Forte {
1190fcf3ce44SJohn Forte 	uint64_t	da;
1191*a2255df3SDaniel Beauregard 	int		instance, i;
1192fcf3ce44SJohn Forte 	fct_status_t	ret;
1193fcf3ce44SJohn Forte 	uint16_t	rcount;
1194fcf3ce44SJohn Forte 	caddr_t		icb;
1195fcf3ce44SJohn Forte 	mbox_cmd_t	*mcp;
1196fcf3ce44SJohn Forte 	uint8_t		*elsbmp;
1197fcf3ce44SJohn Forte 
1198fcf3ce44SJohn Forte 	instance = ddi_get_instance(qlt->dip);
1199fcf3ce44SJohn Forte 
1200fcf3ce44SJohn Forte 	/* XXX Make sure a sane state */
1201fcf3ce44SJohn Forte 
1202*a2255df3SDaniel Beauregard 	if ((ret = qlt_download_fw(qlt)) != QLT_SUCCESS) {
1203fcf3ce44SJohn Forte 		cmn_err(CE_NOTE, "reset chip failed %llx", (long long)ret);
1204fcf3ce44SJohn Forte 		return (ret);
1205fcf3ce44SJohn Forte 	}
1206fcf3ce44SJohn Forte 
1207fcf3ce44SJohn Forte 	bzero(qlt->queue_mem_ptr, TOTAL_DMA_MEM_SIZE);
1208fcf3ce44SJohn Forte 
1209fcf3ce44SJohn Forte 	/* Get resource count */
1210*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(0), MBC_GET_RESOURCE_COUNTS);
1211fcf3ce44SJohn Forte 	ret = qlt_raw_mailbox_command(qlt);
1212fcf3ce44SJohn Forte 	rcount = REG_RD16(qlt, REG_MBOX(3));
1213*a2255df3SDaniel Beauregard 	REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
1214c4ddbbe1SDaniel Beauregard 	if (ret != QLT_SUCCESS) {
1215c4ddbbe1SDaniel Beauregard 		EL(qlt, "qlt_raw_mailbox_command=42h status=%llxh\n", ret);
1216fcf3ce44SJohn Forte 		return (ret);
1217c4ddbbe1SDaniel Beauregard 	}
1218fcf3ce44SJohn Forte 
1219fcf3ce44SJohn Forte 	/* Enable PUREX */
1220*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(0), MBC_SET_ADDITIONAL_FIRMWARE_OPT);
1221*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(1), OPT_PUREX_ENABLE);
1222fcf3ce44SJohn Forte 	REG_WR16(qlt, REG_MBOX(2), 0x0);
1223fcf3ce44SJohn Forte 	REG_WR16(qlt, REG_MBOX(3), 0x0);
1224fcf3ce44SJohn Forte 	ret = qlt_raw_mailbox_command(qlt);
1225*a2255df3SDaniel Beauregard 	REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
1226fcf3ce44SJohn Forte 	if (ret != QLT_SUCCESS) {
1227c4ddbbe1SDaniel Beauregard 		EL(qlt, "qlt_raw_mailbox_command=38h status=%llxh\n", ret);
1228fcf3ce44SJohn Forte 		cmn_err(CE_NOTE, "Enable PUREX failed");
1229fcf3ce44SJohn Forte 		return (ret);
1230fcf3ce44SJohn Forte 	}
1231fcf3ce44SJohn Forte 
1232fcf3ce44SJohn Forte 	/* Pass ELS bitmap to fw */
1233*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(0), MBC_SET_PARAMETERS);
1234*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(1), PARAM_TYPE(PUREX_ELS_CMDS));
1235fcf3ce44SJohn Forte 	elsbmp = (uint8_t *)qlt->queue_mem_ptr + MBOX_DMA_MEM_OFFSET;
1236fcf3ce44SJohn Forte 	bzero(elsbmp, 32);
1237fcf3ce44SJohn Forte 	da = qlt->queue_mem_cookie.dmac_laddress;
1238fcf3ce44SJohn Forte 	da += MBOX_DMA_MEM_OFFSET;
1239*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(3), LSW(LSD(da)));
1240*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(2), MSW(LSD(da)));
1241*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(7), LSW(MSD(da)));
1242*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(6), MSW(MSD(da)));
1243fcf3ce44SJohn Forte 	SETELSBIT(elsbmp, ELS_OP_PLOGI);
1244fcf3ce44SJohn Forte 	SETELSBIT(elsbmp, ELS_OP_LOGO);
1245fcf3ce44SJohn Forte 	SETELSBIT(elsbmp, ELS_OP_ABTX);
1246fcf3ce44SJohn Forte 	SETELSBIT(elsbmp, ELS_OP_ECHO);
1247fcf3ce44SJohn Forte 	SETELSBIT(elsbmp, ELS_OP_PRLI);
1248fcf3ce44SJohn Forte 	SETELSBIT(elsbmp, ELS_OP_PRLO);
1249fcf3ce44SJohn Forte 	SETELSBIT(elsbmp, ELS_OP_SCN);
1250fcf3ce44SJohn Forte 	SETELSBIT(elsbmp, ELS_OP_TPRLO);
1251fcf3ce44SJohn Forte 	SETELSBIT(elsbmp, ELS_OP_PDISC);
1252fcf3ce44SJohn Forte 	SETELSBIT(elsbmp, ELS_OP_ADISC);
1253fcf3ce44SJohn Forte 	SETELSBIT(elsbmp, ELS_OP_RSCN);
1254fcf3ce44SJohn Forte 	SETELSBIT(elsbmp, ELS_OP_RNID);
1255fcf3ce44SJohn Forte 	(void) ddi_dma_sync(qlt->queue_mem_dma_handle, MBOX_DMA_MEM_OFFSET, 32,
1256d8c54e3dSSam Cramer 	    DDI_DMA_SYNC_FORDEV);
1257fcf3ce44SJohn Forte 	ret = qlt_raw_mailbox_command(qlt);
1258*a2255df3SDaniel Beauregard 	REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
1259fcf3ce44SJohn Forte 	if (ret != QLT_SUCCESS) {
1260c4ddbbe1SDaniel Beauregard 		EL(qlt, "qlt_raw_mailbox_command=59h status=llxh\n", ret);
1261fcf3ce44SJohn Forte 		cmn_err(CE_NOTE, "Set ELS Bitmap failed ret=%llx, "
1262fcf3ce44SJohn Forte 		    "elsbmp0=%x elabmp1=%x", (long long)ret, elsbmp[0],
1263fcf3ce44SJohn Forte 		    elsbmp[1]);
1264fcf3ce44SJohn Forte 		return (ret);
1265fcf3ce44SJohn Forte 	}
1266fcf3ce44SJohn Forte 
1267fcf3ce44SJohn Forte 	/* Init queue pointers */
1268fcf3ce44SJohn Forte 	REG_WR32(qlt, REG_REQ_IN_PTR, 0);
1269fcf3ce44SJohn Forte 	REG_WR32(qlt, REG_REQ_OUT_PTR, 0);
1270fcf3ce44SJohn Forte 	REG_WR32(qlt, REG_RESP_IN_PTR, 0);
1271fcf3ce44SJohn Forte 	REG_WR32(qlt, REG_RESP_OUT_PTR, 0);
1272fcf3ce44SJohn Forte 	REG_WR32(qlt, REG_PREQ_IN_PTR, 0);
1273fcf3ce44SJohn Forte 	REG_WR32(qlt, REG_PREQ_OUT_PTR, 0);
1274fcf3ce44SJohn Forte 	REG_WR32(qlt, REG_ATIO_IN_PTR, 0);
1275fcf3ce44SJohn Forte 	REG_WR32(qlt, REG_ATIO_OUT_PTR, 0);
1276fcf3ce44SJohn Forte 	qlt->req_ndx_to_fw = qlt->req_ndx_from_fw = 0;
1277fcf3ce44SJohn Forte 	qlt->req_available = REQUEST_QUEUE_ENTRIES - 1;
1278fcf3ce44SJohn Forte 	qlt->resp_ndx_to_fw = qlt->resp_ndx_from_fw = 0;
1279fcf3ce44SJohn Forte 	qlt->preq_ndx_to_fw = qlt->preq_ndx_from_fw = 0;
1280fcf3ce44SJohn Forte 	qlt->atio_ndx_to_fw = qlt->atio_ndx_from_fw = 0;
1281fcf3ce44SJohn Forte 
1282fcf3ce44SJohn Forte 	/*
1283fcf3ce44SJohn Forte 	 * XXX support for tunables. Also should we cache icb ?
1284fcf3ce44SJohn Forte 	 */
1285c4ddbbe1SDaniel Beauregard 	if (qlt->qlt_81xx_chip) {
1286c4ddbbe1SDaniel Beauregard 	    /* allocate extra 64 bytes for Extended init control block */
1287c4ddbbe1SDaniel Beauregard 		mcp = qlt_alloc_mailbox_command(qlt, 0xC0);
1288c4ddbbe1SDaniel Beauregard 	} else {
1289c4ddbbe1SDaniel Beauregard 		mcp = qlt_alloc_mailbox_command(qlt, 0x80);
1290c4ddbbe1SDaniel Beauregard 	}
1291fcf3ce44SJohn Forte 	if (mcp == NULL) {
1292c4ddbbe1SDaniel Beauregard 		EL(qlt, "qlt_alloc_mailbox_command mcp=null\n");
1293fcf3ce44SJohn Forte 		return (STMF_ALLOC_FAILURE);
1294fcf3ce44SJohn Forte 	}
1295fcf3ce44SJohn Forte 	icb = (caddr_t)mcp->dbuf->db_sglist[0].seg_addr;
1296c4ddbbe1SDaniel Beauregard 	if (qlt->qlt_81xx_chip) {
1297c4ddbbe1SDaniel Beauregard 		bzero(icb, 0xC0);
1298c4ddbbe1SDaniel Beauregard 	} else {
1299c4ddbbe1SDaniel Beauregard 		bzero(icb, 0x80);
1300c4ddbbe1SDaniel Beauregard 	}
1301fcf3ce44SJohn Forte 	da = qlt->queue_mem_cookie.dmac_laddress;
1302fcf3ce44SJohn Forte 	DMEM_WR16(qlt, icb, 1);		/* Version */
1303fcf3ce44SJohn Forte 	DMEM_WR16(qlt, icb+4, 2112);	/* Max frame length */
1304fcf3ce44SJohn Forte 	DMEM_WR16(qlt, icb+6, 16);	/* Execution throttle */
1305fcf3ce44SJohn Forte 	DMEM_WR16(qlt, icb+8, rcount);	/* Xchg count */
1306fcf3ce44SJohn Forte 	DMEM_WR16(qlt, icb+0x0a, 0x00);	/* Hard address (not used) */
1307fcf3ce44SJohn Forte 	bcopy(qlt->qlt_port->port_pwwn, icb+0x0c, 8);
1308fcf3ce44SJohn Forte 	bcopy(qlt->qlt_port->port_nwwn, icb+0x14, 8);
1309fcf3ce44SJohn Forte 	DMEM_WR16(qlt, icb+0x20, 3);	/* Login retry count */
1310fcf3ce44SJohn Forte 	DMEM_WR16(qlt, icb+0x24, RESPONSE_QUEUE_ENTRIES);
1311fcf3ce44SJohn Forte 	DMEM_WR16(qlt, icb+0x26, REQUEST_QUEUE_ENTRIES);
1312c4ddbbe1SDaniel Beauregard 	if (!qlt->qlt_81xx_chip) {
1313c4ddbbe1SDaniel Beauregard 		DMEM_WR16(qlt, icb+0x28, 100); /* ms of NOS/OLS for Link down */
1314c4ddbbe1SDaniel Beauregard 	}
1315fcf3ce44SJohn Forte 	DMEM_WR16(qlt, icb+0x2a, PRIORITY_QUEUE_ENTRIES);
1316c4ddbbe1SDaniel Beauregard 	DMEM_WR64(qlt, icb+0x2c, (da+REQUEST_QUEUE_OFFSET));
1317c4ddbbe1SDaniel Beauregard 	DMEM_WR64(qlt, icb+0x34, (da+RESPONSE_QUEUE_OFFSET));
1318c4ddbbe1SDaniel Beauregard 	DMEM_WR64(qlt, icb+0x3c, (da+PRIORITY_QUEUE_OFFSET));
1319fcf3ce44SJohn Forte 	DMEM_WR16(qlt, icb+0x4e, ATIO_QUEUE_ENTRIES);
1320c4ddbbe1SDaniel Beauregard 	DMEM_WR64(qlt, icb+0x50, (da+ATIO_QUEUE_OFFSET));
1321fcf3ce44SJohn Forte 	DMEM_WR16(qlt, icb+0x58, 2);	/* Interrupt delay Timer */
1322fcf3ce44SJohn Forte 	DMEM_WR16(qlt, icb+0x5a, 4);	/* Login timeout (secs) */
1323c4ddbbe1SDaniel Beauregard 	if (qlt->qlt_81xx_chip) {
1324c4ddbbe1SDaniel Beauregard 		qlt_nvram_81xx_t *qlt81nvr = (qlt_nvram_81xx_t *)qlt->nvram;
1325c4ddbbe1SDaniel Beauregard 
1326c4ddbbe1SDaniel Beauregard 		DMEM_WR32(qlt, icb+0x5c, BIT_5 | BIT_4); /* fw options 1 */
1327c4ddbbe1SDaniel Beauregard 		DMEM_WR32(qlt, icb+0x64, BIT_20 | BIT_4); /* fw options 3 */
1328c4ddbbe1SDaniel Beauregard 		DMEM_WR32(qlt, icb+0x70,
1329c4ddbbe1SDaniel Beauregard 		    qlt81nvr->enode_mac[0] |
1330c4ddbbe1SDaniel Beauregard 		    (qlt81nvr->enode_mac[1] << 8) |
1331c4ddbbe1SDaniel Beauregard 		    (qlt81nvr->enode_mac[2] << 16) |
1332c4ddbbe1SDaniel Beauregard 		    (qlt81nvr->enode_mac[3] << 24));
1333c4ddbbe1SDaniel Beauregard 		DMEM_WR16(qlt, icb+0x74,
1334c4ddbbe1SDaniel Beauregard 		    qlt81nvr->enode_mac[4] |
1335c4ddbbe1SDaniel Beauregard 		    (qlt81nvr->enode_mac[5] << 8));
1336c4ddbbe1SDaniel Beauregard 	} else {
1337c4ddbbe1SDaniel Beauregard 		DMEM_WR32(qlt, icb+0x5c, BIT_11 | BIT_5 | BIT_4 |
1338c4ddbbe1SDaniel Beauregard 		    BIT_2 | BIT_1 | BIT_0);
1339c4ddbbe1SDaniel Beauregard 		DMEM_WR32(qlt, icb+0x60, BIT_5);
1340c4ddbbe1SDaniel Beauregard 		DMEM_WR32(qlt, icb+0x64, BIT_14 | BIT_8 | BIT_7 |
1341c4ddbbe1SDaniel Beauregard 		    BIT_4);
1342c4ddbbe1SDaniel Beauregard 	}
1343c4ddbbe1SDaniel Beauregard 
1344c4ddbbe1SDaniel Beauregard 	if (qlt->qlt_81xx_chip) {
1345c4ddbbe1SDaniel Beauregard 		qlt_dmem_bctl_t		*bctl;
1346c4ddbbe1SDaniel Beauregard 		uint32_t		index;
1347c4ddbbe1SDaniel Beauregard 		caddr_t			src;
1348c4ddbbe1SDaniel Beauregard 		caddr_t			dst;
1349c4ddbbe1SDaniel Beauregard 		qlt_nvram_81xx_t	*qlt81nvr;
1350c4ddbbe1SDaniel Beauregard 
1351c4ddbbe1SDaniel Beauregard 		dst = icb+0x80;
1352c4ddbbe1SDaniel Beauregard 		qlt81nvr = (qlt_nvram_81xx_t *)qlt->nvram;
1353c4ddbbe1SDaniel Beauregard 		src = (caddr_t)&qlt81nvr->ext_blk;
1354c4ddbbe1SDaniel Beauregard 		index = sizeof (qlt_ext_icb_81xx_t);
1355c4ddbbe1SDaniel Beauregard 
1356c4ddbbe1SDaniel Beauregard 		/* Use defaults for cases where we find nothing in NVR */
1357c4ddbbe1SDaniel Beauregard 		if (*src == 0) {
1358c4ddbbe1SDaniel Beauregard 			EL(qlt, "nvram eicb=null\n");
1359c4ddbbe1SDaniel Beauregard 			cmn_err(CE_NOTE, "qlt(%d) NVR eicb is zeroed",
1360c4ddbbe1SDaniel Beauregard 			    instance);
1361c4ddbbe1SDaniel Beauregard 			qlt81nvr->ext_blk.version[0] = 1;
1362c4ddbbe1SDaniel Beauregard /*
1363c4ddbbe1SDaniel Beauregard  * not yet, for !FIP firmware at least
1364c4ddbbe1SDaniel Beauregard  *
1365c4ddbbe1SDaniel Beauregard  *                qlt81nvr->ext_blk.fcf_vlan_match = 0x81;
1366c4ddbbe1SDaniel Beauregard  */
1367c4ddbbe1SDaniel Beauregard #ifdef _LITTLE_ENDIAN
1368c4ddbbe1SDaniel Beauregard 			qlt81nvr->ext_blk.fcf_vlan_id[0] = 0xEA;
1369c4ddbbe1SDaniel Beauregard 			qlt81nvr->ext_blk.fcf_vlan_id[1] = 0x03;
1370c4ddbbe1SDaniel Beauregard #else
1371c4ddbbe1SDaniel Beauregard 			qlt81nvr->ext_blk.fcf_vlan_id[1] = 0xEA;
1372c4ddbbe1SDaniel Beauregard 			qlt81nvr->ext_blk.fcf_vlan_id[0] = 0x03;
1373c4ddbbe1SDaniel Beauregard #endif
1374c4ddbbe1SDaniel Beauregard 		}
1375c4ddbbe1SDaniel Beauregard 
1376c4ddbbe1SDaniel Beauregard 		while (index--) {
1377c4ddbbe1SDaniel Beauregard 			*dst++ = *src++;
1378c4ddbbe1SDaniel Beauregard 		}
1379c4ddbbe1SDaniel Beauregard 
1380c4ddbbe1SDaniel Beauregard 		bctl = (qlt_dmem_bctl_t *)mcp->dbuf->db_port_private;
1381c4ddbbe1SDaniel Beauregard 		da = bctl->bctl_dev_addr + 0x80; /* base addr of eicb (phys) */
1382c4ddbbe1SDaniel Beauregard 
1383*a2255df3SDaniel Beauregard 		mcp->to_fw[11] = LSW(LSD(da));
1384*a2255df3SDaniel Beauregard 		mcp->to_fw[10] = MSW(LSD(da));
1385*a2255df3SDaniel Beauregard 		mcp->to_fw[13] = LSW(MSD(da));
1386*a2255df3SDaniel Beauregard 		mcp->to_fw[12] = MSW(MSD(da));
1387c4ddbbe1SDaniel Beauregard 		mcp->to_fw[14] = (uint16_t)(sizeof (qlt_ext_icb_81xx_t) &
1388c4ddbbe1SDaniel Beauregard 		    0xffff);
1389c4ddbbe1SDaniel Beauregard 
1390c4ddbbe1SDaniel Beauregard 		/* eicb enable */
1391c4ddbbe1SDaniel Beauregard 		mcp->to_fw[1] = (uint16_t)(mcp->to_fw[1] | BIT_0);
1392c4ddbbe1SDaniel Beauregard 		mcp->to_fw_mask |= BIT_14 | BIT_13 | BIT_12 | BIT_11 | BIT_10 |
1393c4ddbbe1SDaniel Beauregard 		    BIT_1;
1394c4ddbbe1SDaniel Beauregard 	}
1395c4ddbbe1SDaniel Beauregard 
1396fcf3ce44SJohn Forte 	qlt_dmem_dma_sync(mcp->dbuf, DDI_DMA_SYNC_FORDEV);
1397*a2255df3SDaniel Beauregard 	mcp->to_fw[0] = MBC_INITIALIZE_FIRMWARE;
1398fcf3ce44SJohn Forte 
1399fcf3ce44SJohn Forte 	/*
1400c4ddbbe1SDaniel Beauregard 	 * This is the 1st command after adapter initialize which will
1401fcf3ce44SJohn Forte 	 * use interrupts and regular mailbox interface.
1402fcf3ce44SJohn Forte 	 */
1403fcf3ce44SJohn Forte 	qlt->mbox_io_state = MBOX_STATE_READY;
1404fcf3ce44SJohn Forte 	REG_WR32(qlt, REG_INTR_CTRL, ENABLE_RISC_INTR);
1405fcf3ce44SJohn Forte 	/* Issue mailbox to firmware */
1406fcf3ce44SJohn Forte 	ret = qlt_mailbox_command(qlt, mcp);
1407fcf3ce44SJohn Forte 	if (ret != QLT_SUCCESS) {
1408c4ddbbe1SDaniel Beauregard 		EL(qlt, "qlt_mailbox_command=60h status=%llxh\n", ret);
1409fcf3ce44SJohn Forte 		cmn_err(CE_NOTE, "qlt(%d) init fw failed %llx, intr status %x",
1410fcf3ce44SJohn Forte 		    instance, (long long)ret, REG_RD32(qlt, REG_INTR_STATUS));
1411fcf3ce44SJohn Forte 	}
1412fcf3ce44SJohn Forte 
1413fcf3ce44SJohn Forte 	mcp->to_fw_mask = BIT_0;
1414fcf3ce44SJohn Forte 	mcp->from_fw_mask = BIT_0 | BIT_1;
1415fcf3ce44SJohn Forte 	mcp->to_fw[0] = 0x28;
1416fcf3ce44SJohn Forte 	ret = qlt_mailbox_command(qlt, mcp);
1417fcf3ce44SJohn Forte 	if (ret != QLT_SUCCESS) {
1418c4ddbbe1SDaniel Beauregard 		EL(qlt, "qlt_mailbox_command=28h status=%llxh\n", ret);
1419fcf3ce44SJohn Forte 		cmn_err(CE_NOTE, "qlt(%d) get_fw_options %llx", instance,
1420fcf3ce44SJohn Forte 		    (long long)ret);
1421fcf3ce44SJohn Forte 	}
1422fcf3ce44SJohn Forte 
1423c4ddbbe1SDaniel Beauregard 	/*
1424c4ddbbe1SDaniel Beauregard 	 * Report FW versions for 81xx - MPI rev is useful
1425c4ddbbe1SDaniel Beauregard 	 */
1426c4ddbbe1SDaniel Beauregard 	if (qlt->qlt_81xx_chip) {
1427c4ddbbe1SDaniel Beauregard 		mcp->to_fw_mask = BIT_0;
1428c4ddbbe1SDaniel Beauregard 		mcp->from_fw_mask = BIT_11 | BIT_10 | BIT_3 | BIT_2 | BIT_1 |
1429c4ddbbe1SDaniel Beauregard 		    BIT_0;
1430c4ddbbe1SDaniel Beauregard 		mcp->to_fw[0] = 0x8;
1431c4ddbbe1SDaniel Beauregard 		ret = qlt_mailbox_command(qlt, mcp);
1432c4ddbbe1SDaniel Beauregard 		if (ret != QLT_SUCCESS) {
1433c4ddbbe1SDaniel Beauregard 			EL(qlt, "about fw failed: %llx\n", (long long)ret);
1434c4ddbbe1SDaniel Beauregard 		} else {
1435c4ddbbe1SDaniel Beauregard 			EL(qlt, "Firmware version %d.%d.%d, MPI: %d.%d.%d\n",
1436c4ddbbe1SDaniel Beauregard 			    mcp->from_fw[1], mcp->from_fw[2], mcp->from_fw[3],
1437c4ddbbe1SDaniel Beauregard 			    mcp->from_fw[10] & 0xff, mcp->from_fw[11] >> 8,
1438c4ddbbe1SDaniel Beauregard 			    mcp->from_fw[11] & 0xff);
1439c4ddbbe1SDaniel Beauregard 		}
1440c4ddbbe1SDaniel Beauregard 	}
1441c4ddbbe1SDaniel Beauregard 
1442fcf3ce44SJohn Forte 	qlt_free_mailbox_command(qlt, mcp);
1443*a2255df3SDaniel Beauregard 
1444*a2255df3SDaniel Beauregard 	for (i = 0; i < 5; i++) {
1445*a2255df3SDaniel Beauregard 		qlt->qlt_bufref[i] = 0;
1446*a2255df3SDaniel Beauregard 		qlt->qlt_nullbufref[i] = 0;
1447*a2255df3SDaniel Beauregard 	}
1448*a2255df3SDaniel Beauregard 	qlt->qlt_bumpbucket = 0;
1449*a2255df3SDaniel Beauregard 
1450fcf3ce44SJohn Forte 	if (ret != QLT_SUCCESS)
1451fcf3ce44SJohn Forte 		return (ret);
1452fcf3ce44SJohn Forte 	return (FCT_SUCCESS);
1453fcf3ce44SJohn Forte }
1454fcf3ce44SJohn Forte 
1455fcf3ce44SJohn Forte fct_status_t
1456fcf3ce44SJohn Forte qlt_port_offline(qlt_state_t *qlt)
1457fcf3ce44SJohn Forte {
1458fcf3ce44SJohn Forte 	int		retries;
1459fcf3ce44SJohn Forte 
1460fcf3ce44SJohn Forte 	mutex_enter(&qlt->mbox_lock);
1461fcf3ce44SJohn Forte 
1462fcf3ce44SJohn Forte 	if (qlt->mbox_io_state == MBOX_STATE_UNKNOWN) {
1463fcf3ce44SJohn Forte 		mutex_exit(&qlt->mbox_lock);
1464fcf3ce44SJohn Forte 		goto poff_mbox_done;
1465fcf3ce44SJohn Forte 	}
1466fcf3ce44SJohn Forte 
1467fcf3ce44SJohn Forte 	/* Wait to grab the mailboxes */
1468fcf3ce44SJohn Forte 	for (retries = 0; qlt->mbox_io_state != MBOX_STATE_READY;
1469d8c54e3dSSam Cramer 	    retries++) {
1470fcf3ce44SJohn Forte 		cv_wait(&qlt->mbox_cv, &qlt->mbox_lock);
1471fcf3ce44SJohn Forte 		if ((retries > 5) ||
1472fcf3ce44SJohn Forte 		    (qlt->mbox_io_state == MBOX_STATE_UNKNOWN)) {
1473fcf3ce44SJohn Forte 			qlt->mbox_io_state = MBOX_STATE_UNKNOWN;
1474fcf3ce44SJohn Forte 			mutex_exit(&qlt->mbox_lock);
1475fcf3ce44SJohn Forte 			goto poff_mbox_done;
1476fcf3ce44SJohn Forte 		}
1477fcf3ce44SJohn Forte 	}
1478fcf3ce44SJohn Forte 	qlt->mbox_io_state = MBOX_STATE_UNKNOWN;
1479fcf3ce44SJohn Forte 	mutex_exit(&qlt->mbox_lock);
1480fcf3ce44SJohn Forte poff_mbox_done:;
1481fcf3ce44SJohn Forte 	qlt->intr_sneak_counter = 10;
1482fcf3ce44SJohn Forte 	mutex_enter(&qlt->intr_lock);
1483*a2255df3SDaniel Beauregard 	(void) qlt_reset_chip(qlt);
1484fcf3ce44SJohn Forte 	drv_usecwait(20);
1485fcf3ce44SJohn Forte 	qlt->intr_sneak_counter = 0;
1486fcf3ce44SJohn Forte 	mutex_exit(&qlt->intr_lock);
1487fcf3ce44SJohn Forte 
1488fcf3ce44SJohn Forte 	return (FCT_SUCCESS);
1489fcf3ce44SJohn Forte }
1490fcf3ce44SJohn Forte 
1491fcf3ce44SJohn Forte static fct_status_t
1492fcf3ce44SJohn Forte qlt_get_link_info(fct_local_port_t *port, fct_link_info_t *li)
1493fcf3ce44SJohn Forte {
1494fcf3ce44SJohn Forte 	qlt_state_t *qlt = (qlt_state_t *)port->port_fca_private;
1495fcf3ce44SJohn Forte 	mbox_cmd_t *mcp;
1496fcf3ce44SJohn Forte 	fct_status_t fc_ret;
1497fcf3ce44SJohn Forte 	fct_status_t ret;
1498fcf3ce44SJohn Forte 	clock_t et;
1499fcf3ce44SJohn Forte 
1500fcf3ce44SJohn Forte 	et = ddi_get_lbolt() + drv_usectohz(5000000);
1501fcf3ce44SJohn Forte 	mcp = qlt_alloc_mailbox_command(qlt, 0);
1502fcf3ce44SJohn Forte link_info_retry:
1503*a2255df3SDaniel Beauregard 	mcp->to_fw[0] = MBC_GET_ID;
1504c4ddbbe1SDaniel Beauregard 	mcp->to_fw[9] = 0;
1505c4ddbbe1SDaniel Beauregard 	mcp->to_fw_mask |= BIT_0 | BIT_9;
1506fcf3ce44SJohn Forte 	mcp->from_fw_mask |= BIT_0 | BIT_1 | BIT_2 | BIT_3 | BIT_6 | BIT_7;
1507fcf3ce44SJohn Forte 	/* Issue mailbox to firmware */
1508fcf3ce44SJohn Forte 	ret = qlt_mailbox_command(qlt, mcp);
1509fcf3ce44SJohn Forte 	if (ret != QLT_SUCCESS) {
1510c4ddbbe1SDaniel Beauregard 		EL(qlt, "qlt_mailbox_command=20h status=%llxh\n", ret);
1511fcf3ce44SJohn Forte 		if ((mcp->from_fw[0] == 0x4005) && (mcp->from_fw[1] == 7)) {
1512fcf3ce44SJohn Forte 			/* Firmware is not ready */
1513fcf3ce44SJohn Forte 			if (ddi_get_lbolt() < et) {
1514fcf3ce44SJohn Forte 				delay(drv_usectohz(50000));
1515fcf3ce44SJohn Forte 				goto link_info_retry;
1516fcf3ce44SJohn Forte 			}
1517fcf3ce44SJohn Forte 		}
1518fcf3ce44SJohn Forte 		stmf_trace(qlt->qlt_port_alias, "GET ID mbox failed, ret=%llx "
1519fcf3ce44SJohn Forte 		    "mb0=%x mb1=%x", ret, mcp->from_fw[0], mcp->from_fw[1]);
1520fcf3ce44SJohn Forte 		fc_ret = FCT_FAILURE;
1521fcf3ce44SJohn Forte 	} else {
1522fcf3ce44SJohn Forte 		li->portid = ((uint32_t)(mcp->from_fw[2])) |
1523d8c54e3dSSam Cramer 		    (((uint32_t)(mcp->from_fw[3])) << 16);
1524fcf3ce44SJohn Forte 
1525fcf3ce44SJohn Forte 		li->port_speed = qlt->link_speed;
1526fcf3ce44SJohn Forte 		switch (mcp->from_fw[6]) {
1527fcf3ce44SJohn Forte 		case 1:
1528fcf3ce44SJohn Forte 			li->port_topology = PORT_TOPOLOGY_PUBLIC_LOOP;
1529fcf3ce44SJohn Forte 			li->port_fca_flogi_done = 1;
1530fcf3ce44SJohn Forte 			break;
1531fcf3ce44SJohn Forte 		case 0:
1532fcf3ce44SJohn Forte 			li->port_topology = PORT_TOPOLOGY_PRIVATE_LOOP;
1533fcf3ce44SJohn Forte 			li->port_no_fct_flogi = 1;
1534fcf3ce44SJohn Forte 			break;
1535fcf3ce44SJohn Forte 		case 3:
1536fcf3ce44SJohn Forte 			li->port_topology = PORT_TOPOLOGY_FABRIC_PT_TO_PT;
1537fcf3ce44SJohn Forte 			li->port_fca_flogi_done = 1;
1538fcf3ce44SJohn Forte 			break;
1539fcf3ce44SJohn Forte 		case 2: /*FALLTHROUGH*/
1540fcf3ce44SJohn Forte 		case 4:
1541fcf3ce44SJohn Forte 			li->port_topology = PORT_TOPOLOGY_PT_TO_PT;
1542fcf3ce44SJohn Forte 			li->port_fca_flogi_done = 1;
1543fcf3ce44SJohn Forte 			break;
1544fcf3ce44SJohn Forte 		default:
1545fcf3ce44SJohn Forte 			li->port_topology = PORT_TOPOLOGY_UNKNOWN;
1546c4ddbbe1SDaniel Beauregard 			EL(qlt, "Unknown topology=%xh\n", mcp->from_fw[6]);
1547fcf3ce44SJohn Forte 		}
1548fcf3ce44SJohn Forte 		qlt->cur_topology = li->port_topology;
1549fcf3ce44SJohn Forte 		fc_ret = FCT_SUCCESS;
1550fcf3ce44SJohn Forte 	}
1551fcf3ce44SJohn Forte 	qlt_free_mailbox_command(qlt, mcp);
1552fcf3ce44SJohn Forte 
1553fcf3ce44SJohn Forte 	if ((fc_ret == FCT_SUCCESS) && (li->port_fca_flogi_done)) {
1554fcf3ce44SJohn Forte 		mcp = qlt_alloc_mailbox_command(qlt, 64);
1555*a2255df3SDaniel Beauregard 		mcp->to_fw[0] = MBC_GET_PORT_DATABASE;
1556fcf3ce44SJohn Forte 		mcp->to_fw[1] = 0x7FE;
1557c4ddbbe1SDaniel Beauregard 		mcp->to_fw[9] = 0;
1558fcf3ce44SJohn Forte 		mcp->to_fw[10] = 0;
1559c4ddbbe1SDaniel Beauregard 		mcp->to_fw_mask |= BIT_0 | BIT_1 | BIT_9 | BIT_10;
1560fcf3ce44SJohn Forte 		fc_ret = qlt_mailbox_command(qlt, mcp);
1561fcf3ce44SJohn Forte 		if (fc_ret != QLT_SUCCESS) {
1562c4ddbbe1SDaniel Beauregard 			EL(qlt, "qlt_mailbox_command=64h status=%llxh\n",
1563c4ddbbe1SDaniel Beauregard 			    fc_ret);
1564fcf3ce44SJohn Forte 			stmf_trace(qlt->qlt_port_alias, "Attempt to get port "
1565fcf3ce44SJohn Forte 			    "database for F_port failed, ret = %llx", fc_ret);
1566fcf3ce44SJohn Forte 		} else {
1567fcf3ce44SJohn Forte 			uint8_t *p;
1568fcf3ce44SJohn Forte 
1569fcf3ce44SJohn Forte 			qlt_dmem_dma_sync(mcp->dbuf, DDI_DMA_SYNC_FORCPU);
1570fcf3ce44SJohn Forte 			p = mcp->dbuf->db_sglist[0].seg_addr;
1571fcf3ce44SJohn Forte 			bcopy(p + 0x18, li->port_rpwwn, 8);
1572fcf3ce44SJohn Forte 			bcopy(p + 0x20, li->port_rnwwn, 8);
1573fcf3ce44SJohn Forte 		}
1574fcf3ce44SJohn Forte 		qlt_free_mailbox_command(qlt, mcp);
1575fcf3ce44SJohn Forte 	}
1576fcf3ce44SJohn Forte 	return (fc_ret);
1577fcf3ce44SJohn Forte }
1578fcf3ce44SJohn Forte 
1579fcf3ce44SJohn Forte static int
1580fcf3ce44SJohn Forte qlt_open(dev_t *devp, int flag, int otype, cred_t *credp)
1581fcf3ce44SJohn Forte {
1582fcf3ce44SJohn Forte 	int		instance;
1583fcf3ce44SJohn Forte 	qlt_state_t	*qlt;
1584fcf3ce44SJohn Forte 
1585fcf3ce44SJohn Forte 	if (otype != OTYP_CHR) {
1586fcf3ce44SJohn Forte 		return (EINVAL);
1587fcf3ce44SJohn Forte 	}
1588fcf3ce44SJohn Forte 
1589fcf3ce44SJohn Forte 	/*
1590fcf3ce44SJohn Forte 	 * Since this is for debugging only, only allow root to issue ioctl now
1591fcf3ce44SJohn Forte 	 */
1592fcf3ce44SJohn Forte 	if (drv_priv(credp)) {
1593fcf3ce44SJohn Forte 		return (EPERM);
1594fcf3ce44SJohn Forte 	}
1595fcf3ce44SJohn Forte 
1596fcf3ce44SJohn Forte 	instance = (int)getminor(*devp);
1597fcf3ce44SJohn Forte 	qlt = ddi_get_soft_state(qlt_state, instance);
1598fcf3ce44SJohn Forte 	if (qlt == NULL) {
1599fcf3ce44SJohn Forte 		return (ENXIO);
1600fcf3ce44SJohn Forte 	}
1601fcf3ce44SJohn Forte 
1602fcf3ce44SJohn Forte 	mutex_enter(&qlt->qlt_ioctl_lock);
1603fcf3ce44SJohn Forte 	if (qlt->qlt_ioctl_flags & QLT_IOCTL_FLAG_EXCL) {
1604fcf3ce44SJohn Forte 		/*
1605fcf3ce44SJohn Forte 		 * It is already open for exclusive access.
1606fcf3ce44SJohn Forte 		 * So shut the door on this caller.
1607fcf3ce44SJohn Forte 		 */
1608fcf3ce44SJohn Forte 		mutex_exit(&qlt->qlt_ioctl_lock);
1609fcf3ce44SJohn Forte 		return (EBUSY);
1610fcf3ce44SJohn Forte 	}
1611fcf3ce44SJohn Forte 
1612fcf3ce44SJohn Forte 	if (flag & FEXCL) {
1613fcf3ce44SJohn Forte 		if (qlt->qlt_ioctl_flags & QLT_IOCTL_FLAG_OPEN) {
1614fcf3ce44SJohn Forte 			/*
1615fcf3ce44SJohn Forte 			 * Exclusive operation not possible
1616fcf3ce44SJohn Forte 			 * as it is already opened
1617fcf3ce44SJohn Forte 			 */
1618fcf3ce44SJohn Forte 			mutex_exit(&qlt->qlt_ioctl_lock);
1619fcf3ce44SJohn Forte 			return (EBUSY);
1620fcf3ce44SJohn Forte 		}
1621fcf3ce44SJohn Forte 		qlt->qlt_ioctl_flags |= QLT_IOCTL_FLAG_EXCL;
1622fcf3ce44SJohn Forte 	}
1623fcf3ce44SJohn Forte 	qlt->qlt_ioctl_flags |= QLT_IOCTL_FLAG_OPEN;
1624fcf3ce44SJohn Forte 	mutex_exit(&qlt->qlt_ioctl_lock);
1625fcf3ce44SJohn Forte 
1626fcf3ce44SJohn Forte 	return (0);
1627fcf3ce44SJohn Forte }
1628fcf3ce44SJohn Forte 
1629fcf3ce44SJohn Forte /* ARGSUSED */
1630fcf3ce44SJohn Forte static int
1631fcf3ce44SJohn Forte qlt_close(dev_t dev, int flag, int otype, cred_t *credp)
1632fcf3ce44SJohn Forte {
1633fcf3ce44SJohn Forte 	int		instance;
1634fcf3ce44SJohn Forte 	qlt_state_t	*qlt;
1635fcf3ce44SJohn Forte 
1636fcf3ce44SJohn Forte 	if (otype != OTYP_CHR) {
1637fcf3ce44SJohn Forte 		return (EINVAL);
1638fcf3ce44SJohn Forte 	}
1639fcf3ce44SJohn Forte 
1640fcf3ce44SJohn Forte 	instance = (int)getminor(dev);
1641fcf3ce44SJohn Forte 	qlt = ddi_get_soft_state(qlt_state, instance);
1642fcf3ce44SJohn Forte 	if (qlt == NULL) {
1643fcf3ce44SJohn Forte 		return (ENXIO);
1644fcf3ce44SJohn Forte 	}
1645fcf3ce44SJohn Forte 
1646fcf3ce44SJohn Forte 	mutex_enter(&qlt->qlt_ioctl_lock);
1647fcf3ce44SJohn Forte 	if ((qlt->qlt_ioctl_flags & QLT_IOCTL_FLAG_OPEN) == 0) {
1648fcf3ce44SJohn Forte 		mutex_exit(&qlt->qlt_ioctl_lock);
1649fcf3ce44SJohn Forte 		return (ENODEV);
1650fcf3ce44SJohn Forte 	}
1651fcf3ce44SJohn Forte 
1652fcf3ce44SJohn Forte 	/*
1653fcf3ce44SJohn Forte 	 * It looks there's one hole here, maybe there could several concurrent
1654fcf3ce44SJohn Forte 	 * shareed open session, but we never check this case.
1655fcf3ce44SJohn Forte 	 * But it will not hurt too much, disregard it now.
1656fcf3ce44SJohn Forte 	 */
1657fcf3ce44SJohn Forte 	qlt->qlt_ioctl_flags &= ~QLT_IOCTL_FLAG_MASK;
1658fcf3ce44SJohn Forte 	mutex_exit(&qlt->qlt_ioctl_lock);
1659fcf3ce44SJohn Forte 
1660fcf3ce44SJohn Forte 	return (0);
1661fcf3ce44SJohn Forte }
1662fcf3ce44SJohn Forte 
1663fcf3ce44SJohn Forte /*
1664fcf3ce44SJohn Forte  * All of these ioctls are unstable interfaces which are meant to be used
1665fcf3ce44SJohn Forte  * in a controlled lab env. No formal testing will be (or needs to be) done
1666fcf3ce44SJohn Forte  * for these ioctls. Specially note that running with an additional
1667fcf3ce44SJohn Forte  * uploaded firmware is not supported and is provided here for test
1668fcf3ce44SJohn Forte  * purposes only.
1669fcf3ce44SJohn Forte  */
1670fcf3ce44SJohn Forte /* ARGSUSED */
1671fcf3ce44SJohn Forte static int
1672fcf3ce44SJohn Forte qlt_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
1673fcf3ce44SJohn Forte     cred_t *credp, int *rval)
1674fcf3ce44SJohn Forte {
1675fcf3ce44SJohn Forte 	qlt_state_t	*qlt;
1676fcf3ce44SJohn Forte 	int		ret = 0;
1677fcf3ce44SJohn Forte #ifdef _LITTLE_ENDIAN
1678fcf3ce44SJohn Forte 	int		i;
1679fcf3ce44SJohn Forte #endif
1680fcf3ce44SJohn Forte 	stmf_iocdata_t	*iocd;
1681fcf3ce44SJohn Forte 	void		*ibuf = NULL;
1682fcf3ce44SJohn Forte 	void		*obuf = NULL;
1683fcf3ce44SJohn Forte 	uint32_t	*intp;
1684fcf3ce44SJohn Forte 	qlt_fw_info_t	*fwi;
1685fcf3ce44SJohn Forte 	mbox_cmd_t	*mcp;
1686fcf3ce44SJohn Forte 	fct_status_t	st;
1687fcf3ce44SJohn Forte 	char		info[80];
1688c4ddbbe1SDaniel Beauregard 	fct_status_t	ret2;
1689fcf3ce44SJohn Forte 
1690fcf3ce44SJohn Forte 	if (drv_priv(credp) != 0)
1691fcf3ce44SJohn Forte 		return (EPERM);
1692fcf3ce44SJohn Forte 
1693fcf3ce44SJohn Forte 	qlt = ddi_get_soft_state(qlt_state, (int32_t)getminor(dev));
1694fcf3ce44SJohn Forte 	ret = stmf_copyin_iocdata(data, mode, &iocd, &ibuf, &obuf);
1695fcf3ce44SJohn Forte 	if (ret)
1696fcf3ce44SJohn Forte 		return (ret);
1697fcf3ce44SJohn Forte 	iocd->stmf_error = 0;
1698fcf3ce44SJohn Forte 
1699fcf3ce44SJohn Forte 	switch (cmd) {
1700fcf3ce44SJohn Forte 	case QLT_IOCTL_FETCH_FWDUMP:
1701fcf3ce44SJohn Forte 		if (iocd->stmf_obuf_size < QLT_FWDUMP_BUFSIZE) {
1702c4ddbbe1SDaniel Beauregard 			EL(qlt, "FETCH_FWDUMP obuf_size=%d < %d\n",
1703c4ddbbe1SDaniel Beauregard 			    iocd->stmf_obuf_size, QLT_FWDUMP_BUFSIZE);
1704fcf3ce44SJohn Forte 			ret = EINVAL;
1705fcf3ce44SJohn Forte 			break;
1706fcf3ce44SJohn Forte 		}
1707fcf3ce44SJohn Forte 		mutex_enter(&qlt->qlt_ioctl_lock);
1708fcf3ce44SJohn Forte 		if (!(qlt->qlt_ioctl_flags & QLT_FWDUMP_ISVALID)) {
1709fcf3ce44SJohn Forte 			mutex_exit(&qlt->qlt_ioctl_lock);
1710fcf3ce44SJohn Forte 			ret = ENODATA;
1711c4ddbbe1SDaniel Beauregard 			EL(qlt, "no fwdump\n");
1712fcf3ce44SJohn Forte 			iocd->stmf_error = QLTIO_NO_DUMP;
1713fcf3ce44SJohn Forte 			break;
1714fcf3ce44SJohn Forte 		}
1715fcf3ce44SJohn Forte 		if (qlt->qlt_ioctl_flags & QLT_FWDUMP_INPROGRESS) {
1716fcf3ce44SJohn Forte 			mutex_exit(&qlt->qlt_ioctl_lock);
1717fcf3ce44SJohn Forte 			ret = EBUSY;
1718c4ddbbe1SDaniel Beauregard 			EL(qlt, "fwdump inprogress\n");
1719fcf3ce44SJohn Forte 			iocd->stmf_error = QLTIO_DUMP_INPROGRESS;
1720fcf3ce44SJohn Forte 			break;
1721fcf3ce44SJohn Forte 		}
1722fcf3ce44SJohn Forte 		if (qlt->qlt_ioctl_flags & QLT_FWDUMP_FETCHED_BY_USER) {
1723fcf3ce44SJohn Forte 			mutex_exit(&qlt->qlt_ioctl_lock);
1724fcf3ce44SJohn Forte 			ret = EEXIST;
1725c4ddbbe1SDaniel Beauregard 			EL(qlt, "fwdump already fetched\n");
1726fcf3ce44SJohn Forte 			iocd->stmf_error = QLTIO_ALREADY_FETCHED;
1727fcf3ce44SJohn Forte 			break;
1728fcf3ce44SJohn Forte 		}
1729fcf3ce44SJohn Forte 		bcopy(qlt->qlt_fwdump_buf, obuf, QLT_FWDUMP_BUFSIZE);
1730fcf3ce44SJohn Forte 		qlt->qlt_ioctl_flags |= QLT_FWDUMP_FETCHED_BY_USER;
1731fcf3ce44SJohn Forte 		mutex_exit(&qlt->qlt_ioctl_lock);
1732fcf3ce44SJohn Forte 
1733fcf3ce44SJohn Forte 		break;
1734fcf3ce44SJohn Forte 
1735fcf3ce44SJohn Forte 	case QLT_IOCTL_TRIGGER_FWDUMP:
1736fcf3ce44SJohn Forte 		if (qlt->qlt_state != FCT_STATE_ONLINE) {
1737fcf3ce44SJohn Forte 			ret = EACCES;
1738fcf3ce44SJohn Forte 			iocd->stmf_error = QLTIO_NOT_ONLINE;
1739fcf3ce44SJohn Forte 			break;
1740fcf3ce44SJohn Forte 		}
1741fcf3ce44SJohn Forte 		(void) snprintf(info, 80, "qlt_ioctl: qlt-%p, "
1742fcf3ce44SJohn Forte 		    "user triggered FWDUMP with RFLAG_RESET", (void *)qlt);
1743fcf3ce44SJohn Forte 		info[79] = 0;
1744c4ddbbe1SDaniel Beauregard 		if ((ret2 = fct_port_shutdown(qlt->qlt_port,
1745c4ddbbe1SDaniel Beauregard 		    STMF_RFLAG_USER_REQUEST | STMF_RFLAG_RESET |
1746c4ddbbe1SDaniel Beauregard 		    STMF_RFLAG_COLLECT_DEBUG_DUMP, info)) != FCT_SUCCESS) {
1747c4ddbbe1SDaniel Beauregard 			EL(qlt, "TRIGGER_FWDUMP fct_port_shutdown status="
1748c4ddbbe1SDaniel Beauregard 			    "%llxh\n", ret2);
1749fcf3ce44SJohn Forte 			ret = EIO;
1750fcf3ce44SJohn Forte 		}
1751fcf3ce44SJohn Forte 		break;
1752fcf3ce44SJohn Forte 	case QLT_IOCTL_UPLOAD_FW:
1753fcf3ce44SJohn Forte 		if ((iocd->stmf_ibuf_size < 1024) ||
1754fcf3ce44SJohn Forte 		    (iocd->stmf_ibuf_size & 3)) {
1755c4ddbbe1SDaniel Beauregard 			EL(qlt, "UPLOAD_FW ibuf_size=%d < 1024\n",
1756c4ddbbe1SDaniel Beauregard 			    iocd->stmf_ibuf_size);
1757fcf3ce44SJohn Forte 			ret = EINVAL;
1758fcf3ce44SJohn Forte 			iocd->stmf_error = QLTIO_INVALID_FW_SIZE;
1759fcf3ce44SJohn Forte 			break;
1760fcf3ce44SJohn Forte 		}
1761fcf3ce44SJohn Forte 		intp = (uint32_t *)ibuf;
1762fcf3ce44SJohn Forte #ifdef _LITTLE_ENDIAN
1763fcf3ce44SJohn Forte 		for (i = 0; (i << 2) < iocd->stmf_ibuf_size; i++) {
1764fcf3ce44SJohn Forte 			intp[i] = BSWAP_32(intp[i]);
1765fcf3ce44SJohn Forte 		}
1766fcf3ce44SJohn Forte #endif
1767fcf3ce44SJohn Forte 		if (((intp[3] << 2) >= iocd->stmf_ibuf_size) ||
1768fcf3ce44SJohn Forte 		    (((intp[intp[3] + 3] + intp[3]) << 2) !=
1769fcf3ce44SJohn Forte 		    iocd->stmf_ibuf_size)) {
1770c4ddbbe1SDaniel Beauregard 			EL(qlt, "UPLOAD_FW fw_size=%d >= %d\n", intp[3] << 2,
1771c4ddbbe1SDaniel Beauregard 			    iocd->stmf_ibuf_size);
1772fcf3ce44SJohn Forte 			ret = EINVAL;
1773fcf3ce44SJohn Forte 			iocd->stmf_error = QLTIO_INVALID_FW_SIZE;
1774fcf3ce44SJohn Forte 			break;
1775fcf3ce44SJohn Forte 		}
1776c4ddbbe1SDaniel Beauregard 		if ((qlt->qlt_81xx_chip && ((intp[8] & 8) == 0)) ||
1777c4ddbbe1SDaniel Beauregard 		    (qlt->qlt_25xx_chip && ((intp[8] & 4) == 0)) ||
1778c4ddbbe1SDaniel Beauregard 		    (!qlt->qlt_25xx_chip && !qlt->qlt_81xx_chip &&
1779c4ddbbe1SDaniel Beauregard 		    ((intp[8] & 3) == 0))) {
1780c4ddbbe1SDaniel Beauregard 			EL(qlt, "UPLOAD_FW fw_type=%d\n", intp[8]);
1781fcf3ce44SJohn Forte 			ret = EACCES;
1782fcf3ce44SJohn Forte 			iocd->stmf_error = QLTIO_INVALID_FW_TYPE;
1783fcf3ce44SJohn Forte 			break;
1784fcf3ce44SJohn Forte 		}
1785fcf3ce44SJohn Forte 
1786fcf3ce44SJohn Forte 		/* Everything looks ok, lets copy this firmware */
1787fcf3ce44SJohn Forte 		if (qlt->fw_code01) {
1788fcf3ce44SJohn Forte 			kmem_free(qlt->fw_code01, (qlt->fw_length01 +
1789fcf3ce44SJohn Forte 			    qlt->fw_length02) << 2);
1790fcf3ce44SJohn Forte 			qlt->fw_code01 = NULL;
1791fcf3ce44SJohn Forte 		} else {
1792fcf3ce44SJohn Forte 			atomic_add_32(&qlt_loaded_counter, 1);
1793fcf3ce44SJohn Forte 		}
1794fcf3ce44SJohn Forte 		qlt->fw_length01 = intp[3];
1795fcf3ce44SJohn Forte 		qlt->fw_code01 = (uint32_t *)kmem_alloc(iocd->stmf_ibuf_size,
1796d8c54e3dSSam Cramer 		    KM_SLEEP);
1797fcf3ce44SJohn Forte 		bcopy(intp, qlt->fw_code01, iocd->stmf_ibuf_size);
1798fcf3ce44SJohn Forte 		qlt->fw_addr01 = intp[2];
1799fcf3ce44SJohn Forte 		qlt->fw_code02 = &qlt->fw_code01[intp[3]];
1800fcf3ce44SJohn Forte 		qlt->fw_addr02 = qlt->fw_code02[2];
1801fcf3ce44SJohn Forte 		qlt->fw_length02 = qlt->fw_code02[3];
1802fcf3ce44SJohn Forte 		break;
1803fcf3ce44SJohn Forte 
1804fcf3ce44SJohn Forte 	case QLT_IOCTL_CLEAR_FW:
1805fcf3ce44SJohn Forte 		if (qlt->fw_code01) {
1806fcf3ce44SJohn Forte 			kmem_free(qlt->fw_code01, (qlt->fw_length01 +
1807fcf3ce44SJohn Forte 			    qlt->fw_length02) << 2);
1808fcf3ce44SJohn Forte 			qlt->fw_code01 = NULL;
1809fcf3ce44SJohn Forte 			atomic_add_32(&qlt_loaded_counter, -1);
1810fcf3ce44SJohn Forte 		}
1811fcf3ce44SJohn Forte 		break;
1812fcf3ce44SJohn Forte 
1813fcf3ce44SJohn Forte 	case QLT_IOCTL_GET_FW_INFO:
1814fcf3ce44SJohn Forte 		if (iocd->stmf_obuf_size != sizeof (qlt_fw_info_t)) {
1815c4ddbbe1SDaniel Beauregard 			EL(qlt, "GET_FW_INFO obuf_size=%d != %d\n",
1816c4ddbbe1SDaniel Beauregard 			    iocd->stmf_obuf_size, sizeof (qlt_fw_info_t));
1817fcf3ce44SJohn Forte 			ret = EINVAL;
1818fcf3ce44SJohn Forte 			break;
1819fcf3ce44SJohn Forte 		}
1820fcf3ce44SJohn Forte 		fwi = (qlt_fw_info_t *)obuf;
1821fcf3ce44SJohn Forte 		if (qlt->qlt_stay_offline) {
1822fcf3ce44SJohn Forte 			fwi->fwi_stay_offline = 1;
1823fcf3ce44SJohn Forte 		}
1824fcf3ce44SJohn Forte 		if (qlt->qlt_state == FCT_STATE_ONLINE) {
1825fcf3ce44SJohn Forte 			fwi->fwi_port_active = 1;
1826fcf3ce44SJohn Forte 		}
1827fcf3ce44SJohn Forte 		fwi->fwi_active_major = qlt->fw_major;
1828fcf3ce44SJohn Forte 		fwi->fwi_active_minor = qlt->fw_minor;
1829fcf3ce44SJohn Forte 		fwi->fwi_active_subminor = qlt->fw_subminor;
1830fcf3ce44SJohn Forte 		fwi->fwi_active_attr = qlt->fw_attr;
1831fcf3ce44SJohn Forte 		if (qlt->fw_code01) {
1832fcf3ce44SJohn Forte 			fwi->fwi_fw_uploaded = 1;
1833fcf3ce44SJohn Forte 			fwi->fwi_loaded_major = (uint16_t)qlt->fw_code01[4];
1834fcf3ce44SJohn Forte 			fwi->fwi_loaded_minor = (uint16_t)qlt->fw_code01[5];
1835fcf3ce44SJohn Forte 			fwi->fwi_loaded_subminor = (uint16_t)qlt->fw_code01[6];
1836fcf3ce44SJohn Forte 			fwi->fwi_loaded_attr = (uint16_t)qlt->fw_code01[7];
1837fcf3ce44SJohn Forte 		}
1838c4ddbbe1SDaniel Beauregard 		if (qlt->qlt_81xx_chip) {
1839c4ddbbe1SDaniel Beauregard 			fwi->fwi_default_major = (uint16_t)fw8100_code01[4];
1840c4ddbbe1SDaniel Beauregard 			fwi->fwi_default_minor = (uint16_t)fw8100_code01[5];
1841c4ddbbe1SDaniel Beauregard 			fwi->fwi_default_subminor = (uint16_t)fw8100_code01[6];
1842c4ddbbe1SDaniel Beauregard 			fwi->fwi_default_attr = (uint16_t)fw8100_code01[7];
1843c4ddbbe1SDaniel Beauregard 		} else if (qlt->qlt_25xx_chip) {
1844fcf3ce44SJohn Forte 			fwi->fwi_default_major = (uint16_t)fw2500_code01[4];
1845fcf3ce44SJohn Forte 			fwi->fwi_default_minor = (uint16_t)fw2500_code01[5];
1846fcf3ce44SJohn Forte 			fwi->fwi_default_subminor = (uint16_t)fw2500_code01[6];
1847fcf3ce44SJohn Forte 			fwi->fwi_default_attr = (uint16_t)fw2500_code01[7];
1848fcf3ce44SJohn Forte 		} else {
1849fcf3ce44SJohn Forte 			fwi->fwi_default_major = (uint16_t)fw2400_code01[4];
1850fcf3ce44SJohn Forte 			fwi->fwi_default_minor = (uint16_t)fw2400_code01[5];
1851fcf3ce44SJohn Forte 			fwi->fwi_default_subminor = (uint16_t)fw2400_code01[6];
1852fcf3ce44SJohn Forte 			fwi->fwi_default_attr = (uint16_t)fw2400_code01[7];
1853fcf3ce44SJohn Forte 		}
1854fcf3ce44SJohn Forte 		break;
1855fcf3ce44SJohn Forte 
1856fcf3ce44SJohn Forte 	case QLT_IOCTL_STAY_OFFLINE:
1857fcf3ce44SJohn Forte 		if (!iocd->stmf_ibuf_size) {
1858c4ddbbe1SDaniel Beauregard 			EL(qlt, "STAY_OFFLINE ibuf_size=%d\n",
1859c4ddbbe1SDaniel Beauregard 			    iocd->stmf_ibuf_size);
1860fcf3ce44SJohn Forte 			ret = EINVAL;
1861fcf3ce44SJohn Forte 			break;
1862fcf3ce44SJohn Forte 		}
1863fcf3ce44SJohn Forte 		if (*((char *)ibuf)) {
1864fcf3ce44SJohn Forte 			qlt->qlt_stay_offline = 1;
1865fcf3ce44SJohn Forte 		} else {
1866fcf3ce44SJohn Forte 			qlt->qlt_stay_offline = 0;
1867fcf3ce44SJohn Forte 		}
1868fcf3ce44SJohn Forte 		break;
1869fcf3ce44SJohn Forte 
1870fcf3ce44SJohn Forte 	case QLT_IOCTL_MBOX:
1871fcf3ce44SJohn Forte 		if ((iocd->stmf_ibuf_size < sizeof (qlt_ioctl_mbox_t)) ||
1872fcf3ce44SJohn Forte 		    (iocd->stmf_obuf_size < sizeof (qlt_ioctl_mbox_t))) {
1873c4ddbbe1SDaniel Beauregard 			EL(qlt, "IOCTL_MBOX ibuf_size=%d, obuf_size=%d\n",
1874c4ddbbe1SDaniel Beauregard 			    iocd->stmf_ibuf_size, iocd->stmf_obuf_size);
1875fcf3ce44SJohn Forte 			ret = EINVAL;
1876fcf3ce44SJohn Forte 			break;
1877fcf3ce44SJohn Forte 		}
1878fcf3ce44SJohn Forte 		mcp = qlt_alloc_mailbox_command(qlt, 0);
1879fcf3ce44SJohn Forte 		if (mcp == NULL) {
1880c4ddbbe1SDaniel Beauregard 			EL(qlt, "IOCTL_MBOX mcp == NULL\n");
1881fcf3ce44SJohn Forte 			ret = ENOMEM;
1882fcf3ce44SJohn Forte 			break;
1883fcf3ce44SJohn Forte 		}
1884fcf3ce44SJohn Forte 		bcopy(ibuf, mcp, sizeof (qlt_ioctl_mbox_t));
1885fcf3ce44SJohn Forte 		st = qlt_mailbox_command(qlt, mcp);
1886fcf3ce44SJohn Forte 		bcopy(mcp, obuf, sizeof (qlt_ioctl_mbox_t));
1887fcf3ce44SJohn Forte 		qlt_free_mailbox_command(qlt, mcp);
1888fcf3ce44SJohn Forte 		if (st != QLT_SUCCESS) {
1889fcf3ce44SJohn Forte 			if ((st & (~((uint64_t)(0xFFFF)))) == QLT_MBOX_FAILED)
1890fcf3ce44SJohn Forte 				st = QLT_SUCCESS;
1891fcf3ce44SJohn Forte 		}
1892fcf3ce44SJohn Forte 		if (st != QLT_SUCCESS) {
1893c4ddbbe1SDaniel Beauregard 			EL(qlt, "IOCTL_MBOX status=%xh\n", st);
1894fcf3ce44SJohn Forte 			ret = EIO;
1895fcf3ce44SJohn Forte 			switch (st) {
1896fcf3ce44SJohn Forte 			case QLT_MBOX_NOT_INITIALIZED:
1897fcf3ce44SJohn Forte 				iocd->stmf_error = QLTIO_MBOX_NOT_INITIALIZED;
1898fcf3ce44SJohn Forte 				break;
1899fcf3ce44SJohn Forte 			case QLT_MBOX_BUSY:
1900fcf3ce44SJohn Forte 				iocd->stmf_error = QLTIO_CANT_GET_MBOXES;
1901fcf3ce44SJohn Forte 				break;
1902fcf3ce44SJohn Forte 			case QLT_MBOX_TIMEOUT:
1903fcf3ce44SJohn Forte 				iocd->stmf_error = QLTIO_MBOX_TIMED_OUT;
1904fcf3ce44SJohn Forte 				break;
1905fcf3ce44SJohn Forte 			case QLT_MBOX_ABORTED:
1906fcf3ce44SJohn Forte 				iocd->stmf_error = QLTIO_MBOX_ABORTED;
1907fcf3ce44SJohn Forte 				break;
1908fcf3ce44SJohn Forte 			}
1909fcf3ce44SJohn Forte 		}
1910fcf3ce44SJohn Forte 		break;
1911fcf3ce44SJohn Forte 
1912c4ddbbe1SDaniel Beauregard 	case QLT_IOCTL_ELOG:
1913c4ddbbe1SDaniel Beauregard 		qlt_dump_el_trace_buffer(qlt);
1914c4ddbbe1SDaniel Beauregard 		break;
1915c4ddbbe1SDaniel Beauregard 
1916fcf3ce44SJohn Forte 	default:
1917c4ddbbe1SDaniel Beauregard 		EL(qlt, "Unknown ioctl-%xh\n", cmd);
1918fcf3ce44SJohn Forte 		ret = ENOTTY;
1919fcf3ce44SJohn Forte 	}
1920fcf3ce44SJohn Forte 
1921fcf3ce44SJohn Forte 	if (ret == 0) {
1922fcf3ce44SJohn Forte 		ret = stmf_copyout_iocdata(data, mode, iocd, obuf);
1923fcf3ce44SJohn Forte 	} else if (iocd->stmf_error) {
1924fcf3ce44SJohn Forte 		(void) stmf_copyout_iocdata(data, mode, iocd, obuf);
1925fcf3ce44SJohn Forte 	}
1926fcf3ce44SJohn Forte 	if (obuf) {
1927fcf3ce44SJohn Forte 		kmem_free(obuf, iocd->stmf_obuf_size);
1928fcf3ce44SJohn Forte 		obuf = NULL;
1929fcf3ce44SJohn Forte 	}
1930fcf3ce44SJohn Forte 	if (ibuf) {
1931fcf3ce44SJohn Forte 		kmem_free(ibuf, iocd->stmf_ibuf_size);
1932fcf3ce44SJohn Forte 		ibuf = NULL;
1933fcf3ce44SJohn Forte 	}
1934fcf3ce44SJohn Forte 	kmem_free(iocd, sizeof (stmf_iocdata_t));
1935fcf3ce44SJohn Forte 	return (ret);
1936fcf3ce44SJohn Forte }
1937fcf3ce44SJohn Forte 
1938*a2255df3SDaniel Beauregard static fct_status_t
1939*a2255df3SDaniel Beauregard qlt_force_lip(qlt_state_t *qlt)
1940*a2255df3SDaniel Beauregard {
1941*a2255df3SDaniel Beauregard 	mbox_cmd_t	*mcp;
1942*a2255df3SDaniel Beauregard 	fct_status_t	 rval;
1943*a2255df3SDaniel Beauregard 
1944*a2255df3SDaniel Beauregard 	mcp = qlt_alloc_mailbox_command(qlt, 0);
1945*a2255df3SDaniel Beauregard 	mcp->to_fw[0] = 0x0072;
1946*a2255df3SDaniel Beauregard 	mcp->to_fw[1] = BIT_4;
1947*a2255df3SDaniel Beauregard 	mcp->to_fw[3] = 1;
1948*a2255df3SDaniel Beauregard 	mcp->to_fw_mask |= BIT_1 | BIT_3;
1949*a2255df3SDaniel Beauregard 	rval = qlt_mailbox_command(qlt, mcp);
1950*a2255df3SDaniel Beauregard 	if (rval != FCT_SUCCESS) {
1951*a2255df3SDaniel Beauregard 		EL(qlt, "qlt force lip MB failed: rval=%x", rval);
1952*a2255df3SDaniel Beauregard 	} else {
1953*a2255df3SDaniel Beauregard 		if (mcp->from_fw[0] != 0x4000) {
1954*a2255df3SDaniel Beauregard 			QLT_LOG(qlt->qlt_port_alias, "qlt FLIP: fw[0]=%x",
1955*a2255df3SDaniel Beauregard 			    mcp->from_fw[0]);
1956*a2255df3SDaniel Beauregard 			rval = FCT_FAILURE;
1957*a2255df3SDaniel Beauregard 		}
1958*a2255df3SDaniel Beauregard 	}
1959*a2255df3SDaniel Beauregard 	qlt_free_mailbox_command(qlt, mcp);
1960*a2255df3SDaniel Beauregard 	return (rval);
1961*a2255df3SDaniel Beauregard }
1962*a2255df3SDaniel Beauregard 
1963fcf3ce44SJohn Forte static void
1964fcf3ce44SJohn Forte qlt_ctl(struct fct_local_port *port, int cmd, void *arg)
1965fcf3ce44SJohn Forte {
1966c4ddbbe1SDaniel Beauregard 	stmf_change_status_t		st;
1967fcf3ce44SJohn Forte 	stmf_state_change_info_t	*ssci = (stmf_state_change_info_t *)arg;
1968fcf3ce44SJohn Forte 	qlt_state_t			*qlt;
1969c4ddbbe1SDaniel Beauregard 	fct_status_t			ret;
1970c4ddbbe1SDaniel Beauregard 
1971c4ddbbe1SDaniel Beauregard 	ASSERT((cmd == FCT_CMD_PORT_ONLINE) ||
1972c4ddbbe1SDaniel Beauregard 	    (cmd == FCT_CMD_PORT_OFFLINE) ||
1973*a2255df3SDaniel Beauregard 	    (cmd == FCT_CMD_FORCE_LIP) ||
1974c4ddbbe1SDaniel Beauregard 	    (cmd == FCT_ACK_PORT_ONLINE_COMPLETE) ||
1975c4ddbbe1SDaniel Beauregard 	    (cmd == FCT_ACK_PORT_OFFLINE_COMPLETE));
1976fcf3ce44SJohn Forte 
1977fcf3ce44SJohn Forte 	qlt = (qlt_state_t *)port->port_fca_private;
1978fcf3ce44SJohn Forte 	st.st_completion_status = FCT_SUCCESS;
1979fcf3ce44SJohn Forte 	st.st_additional_info = NULL;
1980fcf3ce44SJohn Forte 
1981fcf3ce44SJohn Forte 	switch (cmd) {
1982fcf3ce44SJohn Forte 	case FCT_CMD_PORT_ONLINE:
1983fcf3ce44SJohn Forte 		if (qlt->qlt_state == FCT_STATE_ONLINE)
1984fcf3ce44SJohn Forte 			st.st_completion_status = STMF_ALREADY;
1985fcf3ce44SJohn Forte 		else if (qlt->qlt_state != FCT_STATE_OFFLINE)
1986fcf3ce44SJohn Forte 			st.st_completion_status = FCT_FAILURE;
1987fcf3ce44SJohn Forte 		if (st.st_completion_status == FCT_SUCCESS) {
1988fcf3ce44SJohn Forte 			qlt->qlt_state = FCT_STATE_ONLINING;
1989fcf3ce44SJohn Forte 			qlt->qlt_state_not_acked = 1;
1990fcf3ce44SJohn Forte 			st.st_completion_status = qlt_port_online(qlt);
1991fcf3ce44SJohn Forte 			if (st.st_completion_status != STMF_SUCCESS) {
1992c4ddbbe1SDaniel Beauregard 				EL(qlt, "PORT_ONLINE status=%xh\n",
1993c4ddbbe1SDaniel Beauregard 				    st.st_completion_status);
1994fcf3ce44SJohn Forte 				qlt->qlt_state = FCT_STATE_OFFLINE;
1995fcf3ce44SJohn Forte 				qlt->qlt_state_not_acked = 0;
1996fcf3ce44SJohn Forte 			} else {
1997fcf3ce44SJohn Forte 				qlt->qlt_state = FCT_STATE_ONLINE;
1998fcf3ce44SJohn Forte 			}
1999fcf3ce44SJohn Forte 		}
2000fcf3ce44SJohn Forte 		fct_ctl(port->port_lport, FCT_CMD_PORT_ONLINE_COMPLETE, &st);
2001fcf3ce44SJohn Forte 		qlt->qlt_change_state_flags = 0;
2002fcf3ce44SJohn Forte 		break;
2003fcf3ce44SJohn Forte 
2004fcf3ce44SJohn Forte 	case FCT_CMD_PORT_OFFLINE:
2005fcf3ce44SJohn Forte 		if (qlt->qlt_state == FCT_STATE_OFFLINE) {
2006fcf3ce44SJohn Forte 			st.st_completion_status = STMF_ALREADY;
2007fcf3ce44SJohn Forte 		} else if (qlt->qlt_state != FCT_STATE_ONLINE) {
2008fcf3ce44SJohn Forte 			st.st_completion_status = FCT_FAILURE;
2009fcf3ce44SJohn Forte 		}
2010fcf3ce44SJohn Forte 		if (st.st_completion_status == FCT_SUCCESS) {
2011fcf3ce44SJohn Forte 			qlt->qlt_state = FCT_STATE_OFFLINING;
2012fcf3ce44SJohn Forte 			qlt->qlt_state_not_acked = 1;
2013fcf3ce44SJohn Forte 
2014fcf3ce44SJohn Forte 			if (ssci->st_rflags & STMF_RFLAG_COLLECT_DEBUG_DUMP) {
2015fcf3ce44SJohn Forte 				(void) qlt_firmware_dump(port, ssci);
2016fcf3ce44SJohn Forte 			}
2017c4ddbbe1SDaniel Beauregard 			qlt->qlt_change_state_flags = (uint32_t)ssci->st_rflags;
2018fcf3ce44SJohn Forte 			st.st_completion_status = qlt_port_offline(qlt);
2019fcf3ce44SJohn Forte 			if (st.st_completion_status != STMF_SUCCESS) {
2020c4ddbbe1SDaniel Beauregard 				EL(qlt, "PORT_OFFLINE status=%xh\n",
2021c4ddbbe1SDaniel Beauregard 				    st.st_completion_status);
2022fcf3ce44SJohn Forte 				qlt->qlt_state = FCT_STATE_ONLINE;
2023fcf3ce44SJohn Forte 				qlt->qlt_state_not_acked = 0;
2024fcf3ce44SJohn Forte 			} else {
2025fcf3ce44SJohn Forte 				qlt->qlt_state = FCT_STATE_OFFLINE;
2026fcf3ce44SJohn Forte 			}
2027fcf3ce44SJohn Forte 		}
2028fcf3ce44SJohn Forte 		fct_ctl(port->port_lport, FCT_CMD_PORT_OFFLINE_COMPLETE, &st);
2029fcf3ce44SJohn Forte 		break;
2030fcf3ce44SJohn Forte 
2031fcf3ce44SJohn Forte 	case FCT_ACK_PORT_ONLINE_COMPLETE:
2032fcf3ce44SJohn Forte 		qlt->qlt_state_not_acked = 0;
2033fcf3ce44SJohn Forte 		break;
2034fcf3ce44SJohn Forte 
2035fcf3ce44SJohn Forte 	case FCT_ACK_PORT_OFFLINE_COMPLETE:
2036fcf3ce44SJohn Forte 		qlt->qlt_state_not_acked = 0;
2037fcf3ce44SJohn Forte 		if ((qlt->qlt_change_state_flags & STMF_RFLAG_RESET) &&
2038fcf3ce44SJohn Forte 		    (qlt->qlt_stay_offline == 0)) {
2039c4ddbbe1SDaniel Beauregard 			if ((ret = fct_port_initialize(port,
2040fcf3ce44SJohn Forte 			    qlt->qlt_change_state_flags,
2041fcf3ce44SJohn Forte 			    "qlt_ctl FCT_ACK_PORT_OFFLINE_COMPLETE "
2042c4ddbbe1SDaniel Beauregard 			    "with RLFLAG_RESET")) != FCT_SUCCESS) {
2043c4ddbbe1SDaniel Beauregard 				EL(qlt, "fct_port_initialize status=%llxh\n",
2044c4ddbbe1SDaniel Beauregard 				    ret);
2045fcf3ce44SJohn Forte 				cmn_err(CE_WARN, "qlt_ctl: "
2046fcf3ce44SJohn Forte 				    "fct_port_initialize failed, please use "
2047fcf3ce44SJohn Forte 				    "stmfstate to start the port-%s manualy",
2048fcf3ce44SJohn Forte 				    qlt->qlt_port_alias);
2049fcf3ce44SJohn Forte 			}
2050fcf3ce44SJohn Forte 		}
2051fcf3ce44SJohn Forte 		break;
2052*a2255df3SDaniel Beauregard 
2053*a2255df3SDaniel Beauregard 	case FCT_CMD_FORCE_LIP:
2054*a2255df3SDaniel Beauregard 		if (qlt->qlt_81xx_chip) {
2055*a2255df3SDaniel Beauregard 			EL(qlt, "force lip is an unsupported command "
2056*a2255df3SDaniel Beauregard 			    "for this adapter type\n");
2057*a2255df3SDaniel Beauregard 		} else {
2058*a2255df3SDaniel Beauregard 			*((fct_status_t *)arg) = qlt_force_lip(qlt);
2059*a2255df3SDaniel Beauregard 			EL(qlt, "forcelip done\n");
2060*a2255df3SDaniel Beauregard 		}
2061*a2255df3SDaniel Beauregard 		break;
2062*a2255df3SDaniel Beauregard 
2063*a2255df3SDaniel Beauregard 	default:
2064*a2255df3SDaniel Beauregard 		EL(qlt, "unsupport cmd - 0x%02X", cmd);
2065*a2255df3SDaniel Beauregard 		break;
2066fcf3ce44SJohn Forte 	}
2067fcf3ce44SJohn Forte }
2068fcf3ce44SJohn Forte 
2069fcf3ce44SJohn Forte /* ARGSUSED */
2070fcf3ce44SJohn Forte static fct_status_t
2071fcf3ce44SJohn Forte qlt_do_flogi(fct_local_port_t *port, fct_flogi_xchg_t *fx)
2072fcf3ce44SJohn Forte {
2073c4ddbbe1SDaniel Beauregard 	qlt_state_t	*qlt = (qlt_state_t *)port->port_fca_private;
2074c4ddbbe1SDaniel Beauregard 
2075c4ddbbe1SDaniel Beauregard 	EL(qlt, "FLOGI requested not supported\n");
2076fcf3ce44SJohn Forte 	cmn_err(CE_WARN, "qlt: FLOGI requested (not supported)");
2077fcf3ce44SJohn Forte 	return (FCT_FAILURE);
2078fcf3ce44SJohn Forte }
2079fcf3ce44SJohn Forte 
2080fcf3ce44SJohn Forte /*
2081fcf3ce44SJohn Forte  * Return a pointer to n entries in the request queue. Assumes that
2082fcf3ce44SJohn Forte  * request queue lock is held. Does a very short busy wait if
2083fcf3ce44SJohn Forte  * less/zero entries are available. Retuns NULL if it still cannot
2084fcf3ce44SJohn Forte  * fullfill the request.
2085fcf3ce44SJohn Forte  * **CALL qlt_submit_req_entries() BEFORE DROPPING THE LOCK**
2086fcf3ce44SJohn Forte  */
2087fcf3ce44SJohn Forte caddr_t
2088fcf3ce44SJohn Forte qlt_get_req_entries(qlt_state_t *qlt, uint32_t n)
2089fcf3ce44SJohn Forte {
2090fcf3ce44SJohn Forte 	int try = 0;
2091fcf3ce44SJohn Forte 
2092fcf3ce44SJohn Forte 	while (qlt->req_available < n) {
2093fcf3ce44SJohn Forte 		uint32_t val1, val2, val3;
2094fcf3ce44SJohn Forte 		val1 = REG_RD32(qlt, REG_REQ_OUT_PTR);
2095fcf3ce44SJohn Forte 		val2 = REG_RD32(qlt, REG_REQ_OUT_PTR);
2096fcf3ce44SJohn Forte 		val3 = REG_RD32(qlt, REG_REQ_OUT_PTR);
2097fcf3ce44SJohn Forte 		if ((val1 != val2) || (val2 != val3))
2098fcf3ce44SJohn Forte 			continue;
2099fcf3ce44SJohn Forte 
2100fcf3ce44SJohn Forte 		qlt->req_ndx_from_fw = val1;
2101fcf3ce44SJohn Forte 		qlt->req_available = REQUEST_QUEUE_ENTRIES - 1 -
2102d8c54e3dSSam Cramer 		    ((qlt->req_ndx_to_fw - qlt->req_ndx_from_fw) &
2103d8c54e3dSSam Cramer 		    (REQUEST_QUEUE_ENTRIES - 1));
2104fcf3ce44SJohn Forte 		if (qlt->req_available < n) {
2105fcf3ce44SJohn Forte 			if (try < 2) {
2106fcf3ce44SJohn Forte 				drv_usecwait(100);
2107fcf3ce44SJohn Forte 				try++;
2108fcf3ce44SJohn Forte 				continue;
2109fcf3ce44SJohn Forte 			} else {
2110fcf3ce44SJohn Forte 				stmf_trace(qlt->qlt_port_alias,
2111fcf3ce44SJohn Forte 				    "Req Q is full");
2112fcf3ce44SJohn Forte 				return (NULL);
2113fcf3ce44SJohn Forte 			}
2114fcf3ce44SJohn Forte 		}
2115fcf3ce44SJohn Forte 		break;
2116fcf3ce44SJohn Forte 	}
2117fcf3ce44SJohn Forte 	/* We dont change anything until the entries are sumitted */
2118fcf3ce44SJohn Forte 	return (&qlt->req_ptr[qlt->req_ndx_to_fw << 6]);
2119fcf3ce44SJohn Forte }
2120fcf3ce44SJohn Forte 
2121fcf3ce44SJohn Forte /*
2122fcf3ce44SJohn Forte  * updates the req in ptr to fw. Assumes that req lock is held.
2123fcf3ce44SJohn Forte  */
2124fcf3ce44SJohn Forte void
2125fcf3ce44SJohn Forte qlt_submit_req_entries(qlt_state_t *qlt, uint32_t n)
2126fcf3ce44SJohn Forte {
2127fcf3ce44SJohn Forte 	ASSERT(n >= 1);
2128fcf3ce44SJohn Forte 	qlt->req_ndx_to_fw += n;
2129fcf3ce44SJohn Forte 	qlt->req_ndx_to_fw &= REQUEST_QUEUE_ENTRIES - 1;
2130fcf3ce44SJohn Forte 	qlt->req_available -= n;
2131fcf3ce44SJohn Forte 	REG_WR32(qlt, REG_REQ_IN_PTR, qlt->req_ndx_to_fw);
2132fcf3ce44SJohn Forte }
2133fcf3ce44SJohn Forte 
2134fcf3ce44SJohn Forte 
2135fcf3ce44SJohn Forte /*
2136fcf3ce44SJohn Forte  * Return a pointer to n entries in the priority request queue. Assumes that
2137fcf3ce44SJohn Forte  * priority request queue lock is held. Does a very short busy wait if
2138fcf3ce44SJohn Forte  * less/zero entries are available. Retuns NULL if it still cannot
2139fcf3ce44SJohn Forte  * fullfill the request.
2140fcf3ce44SJohn Forte  * **CALL qlt_submit_preq_entries() BEFORE DROPPING THE LOCK**
2141fcf3ce44SJohn Forte  */
2142fcf3ce44SJohn Forte caddr_t
2143fcf3ce44SJohn Forte qlt_get_preq_entries(qlt_state_t *qlt, uint32_t n)
2144fcf3ce44SJohn Forte {
2145fcf3ce44SJohn Forte 	int try = 0;
2146fcf3ce44SJohn Forte 	uint32_t req_available = PRIORITY_QUEUE_ENTRIES - 1 -
2147d8c54e3dSSam Cramer 	    ((qlt->preq_ndx_to_fw - qlt->preq_ndx_from_fw) &
2148d8c54e3dSSam Cramer 	    (PRIORITY_QUEUE_ENTRIES - 1));
2149fcf3ce44SJohn Forte 
2150fcf3ce44SJohn Forte 	while (req_available < n) {
2151fcf3ce44SJohn Forte 		uint32_t val1, val2, val3;
2152fcf3ce44SJohn Forte 		val1 = REG_RD32(qlt, REG_PREQ_OUT_PTR);
2153fcf3ce44SJohn Forte 		val2 = REG_RD32(qlt, REG_PREQ_OUT_PTR);
2154fcf3ce44SJohn Forte 		val3 = REG_RD32(qlt, REG_PREQ_OUT_PTR);
2155fcf3ce44SJohn Forte 		if ((val1 != val2) || (val2 != val3))
2156fcf3ce44SJohn Forte 			continue;
2157fcf3ce44SJohn Forte 
2158fcf3ce44SJohn Forte 		qlt->preq_ndx_from_fw = val1;
2159fcf3ce44SJohn Forte 		req_available = PRIORITY_QUEUE_ENTRIES - 1 -
2160d8c54e3dSSam Cramer 		    ((qlt->preq_ndx_to_fw - qlt->preq_ndx_from_fw) &
2161d8c54e3dSSam Cramer 		    (PRIORITY_QUEUE_ENTRIES - 1));
2162fcf3ce44SJohn Forte 		if (req_available < n) {
2163fcf3ce44SJohn Forte 			if (try < 2) {
2164fcf3ce44SJohn Forte 				drv_usecwait(100);
2165fcf3ce44SJohn Forte 				try++;
2166fcf3ce44SJohn Forte 				continue;
2167fcf3ce44SJohn Forte 			} else {
2168fcf3ce44SJohn Forte 				return (NULL);
2169fcf3ce44SJohn Forte 			}
2170fcf3ce44SJohn Forte 		}
2171fcf3ce44SJohn Forte 		break;
2172fcf3ce44SJohn Forte 	}
2173fcf3ce44SJohn Forte 	/* We dont change anything until the entries are sumitted */
2174fcf3ce44SJohn Forte 	return (&qlt->preq_ptr[qlt->preq_ndx_to_fw << 6]);
2175fcf3ce44SJohn Forte }
2176fcf3ce44SJohn Forte 
2177fcf3ce44SJohn Forte /*
2178fcf3ce44SJohn Forte  * updates the req in ptr to fw. Assumes that req lock is held.
2179fcf3ce44SJohn Forte  */
2180fcf3ce44SJohn Forte void
2181fcf3ce44SJohn Forte qlt_submit_preq_entries(qlt_state_t *qlt, uint32_t n)
2182fcf3ce44SJohn Forte {
2183fcf3ce44SJohn Forte 	ASSERT(n >= 1);
2184fcf3ce44SJohn Forte 	qlt->preq_ndx_to_fw += n;
2185fcf3ce44SJohn Forte 	qlt->preq_ndx_to_fw &= PRIORITY_QUEUE_ENTRIES - 1;
2186fcf3ce44SJohn Forte 	REG_WR32(qlt, REG_PREQ_IN_PTR, qlt->preq_ndx_to_fw);
2187fcf3ce44SJohn Forte }
2188fcf3ce44SJohn Forte 
2189fcf3ce44SJohn Forte /*
2190fcf3ce44SJohn Forte  * - Should not be called from Interrupt.
2191fcf3ce44SJohn Forte  * - A very hardware specific function. Does not touch driver state.
2192fcf3ce44SJohn Forte  * - Assumes that interrupts are disabled or not there.
2193fcf3ce44SJohn Forte  * - Expects that the caller makes sure that all activity has stopped
2194fcf3ce44SJohn Forte  *   and its ok now to go ahead and reset the chip. Also the caller
2195fcf3ce44SJohn Forte  *   takes care of post reset damage control.
2196fcf3ce44SJohn Forte  * - called by initialize adapter() and dump_fw(for reset only).
2197fcf3ce44SJohn Forte  * - During attach() nothing much is happening and during initialize_adapter()
2198fcf3ce44SJohn Forte  *   the function (caller) does all the housekeeping so that this function
2199fcf3ce44SJohn Forte  *   can execute in peace.
2200fcf3ce44SJohn Forte  * - Returns 0 on success.
2201fcf3ce44SJohn Forte  */
2202fcf3ce44SJohn Forte static fct_status_t
2203*a2255df3SDaniel Beauregard qlt_reset_chip(qlt_state_t *qlt)
2204fcf3ce44SJohn Forte {
2205fcf3ce44SJohn Forte 	int cntr;
2206fcf3ce44SJohn Forte 
2207*a2255df3SDaniel Beauregard 	EL(qlt, "initiated\n");
2208c4ddbbe1SDaniel Beauregard 
2209fcf3ce44SJohn Forte 	/* XXX: Switch off LEDs */
2210fcf3ce44SJohn Forte 
2211fcf3ce44SJohn Forte 	/* Disable Interrupts */
2212fcf3ce44SJohn Forte 	REG_WR32(qlt, REG_INTR_CTRL, 0);
2213fcf3ce44SJohn Forte 	(void) REG_RD32(qlt, REG_INTR_CTRL);
2214fcf3ce44SJohn Forte 	/* Stop DMA */
2215fcf3ce44SJohn Forte 	REG_WR32(qlt, REG_CTRL_STATUS, DMA_SHUTDOWN_CTRL | PCI_X_XFER_CTRL);
2216fcf3ce44SJohn Forte 
2217fcf3ce44SJohn Forte 	/* Wait for DMA to be stopped */
2218fcf3ce44SJohn Forte 	cntr = 0;
2219fcf3ce44SJohn Forte 	while (REG_RD32(qlt, REG_CTRL_STATUS) & DMA_ACTIVE_STATUS) {
2220fcf3ce44SJohn Forte 		delay(drv_usectohz(10000)); /* mostly 10ms is 1 tick */
2221fcf3ce44SJohn Forte 		cntr++;
2222fcf3ce44SJohn Forte 		/* 3 sec should be more than enough */
2223fcf3ce44SJohn Forte 		if (cntr == 300)
2224fcf3ce44SJohn Forte 			return (QLT_DMA_STUCK);
2225fcf3ce44SJohn Forte 	}
2226fcf3ce44SJohn Forte 
2227fcf3ce44SJohn Forte 	/* Reset the Chip */
2228fcf3ce44SJohn Forte 	REG_WR32(qlt, REG_CTRL_STATUS,
2229d8c54e3dSSam Cramer 	    DMA_SHUTDOWN_CTRL | PCI_X_XFER_CTRL | CHIP_SOFT_RESET);
2230fcf3ce44SJohn Forte 
2231fcf3ce44SJohn Forte 	qlt->qlt_link_up = 0;
2232fcf3ce44SJohn Forte 
2233fcf3ce44SJohn Forte 	drv_usecwait(100);
2234fcf3ce44SJohn Forte 
2235fcf3ce44SJohn Forte 	/* Wait for ROM firmware to initialize (0x0000) in mailbox 0 */
2236fcf3ce44SJohn Forte 	cntr = 0;
2237fcf3ce44SJohn Forte 	while (REG_RD16(qlt, REG_MBOX(0)) != 0) {
2238fcf3ce44SJohn Forte 		delay(drv_usectohz(10000));
2239fcf3ce44SJohn Forte 		cntr++;
2240fcf3ce44SJohn Forte 		/* 3 sec should be more than enough */
2241fcf3ce44SJohn Forte 		if (cntr == 300)
2242fcf3ce44SJohn Forte 			return (QLT_ROM_STUCK);
2243fcf3ce44SJohn Forte 	}
2244fcf3ce44SJohn Forte 	/* Disable Interrupts (Probably not needed) */
2245fcf3ce44SJohn Forte 	REG_WR32(qlt, REG_INTR_CTRL, 0);
2246*a2255df3SDaniel Beauregard 
2247*a2255df3SDaniel Beauregard 	return (QLT_SUCCESS);
2248*a2255df3SDaniel Beauregard }
2249*a2255df3SDaniel Beauregard /*
2250*a2255df3SDaniel Beauregard  * - Should not be called from Interrupt.
2251*a2255df3SDaniel Beauregard  * - A very hardware specific function. Does not touch driver state.
2252*a2255df3SDaniel Beauregard  * - Assumes that interrupts are disabled or not there.
2253*a2255df3SDaniel Beauregard  * - Expects that the caller makes sure that all activity has stopped
2254*a2255df3SDaniel Beauregard  *   and its ok now to go ahead and reset the chip. Also the caller
2255*a2255df3SDaniel Beauregard  *   takes care of post reset damage control.
2256*a2255df3SDaniel Beauregard  * - called by initialize adapter() and dump_fw(for reset only).
2257*a2255df3SDaniel Beauregard  * - During attach() nothing much is happening and during initialize_adapter()
2258*a2255df3SDaniel Beauregard  *   the function (caller) does all the housekeeping so that this function
2259*a2255df3SDaniel Beauregard  *   can execute in peace.
2260*a2255df3SDaniel Beauregard  * - Returns 0 on success.
2261*a2255df3SDaniel Beauregard  */
2262*a2255df3SDaniel Beauregard static fct_status_t
2263*a2255df3SDaniel Beauregard qlt_download_fw(qlt_state_t *qlt)
2264*a2255df3SDaniel Beauregard {
2265*a2255df3SDaniel Beauregard 	uint32_t start_addr;
2266*a2255df3SDaniel Beauregard 	fct_status_t ret;
2267*a2255df3SDaniel Beauregard 
2268*a2255df3SDaniel Beauregard 	EL(qlt, "initiated\n");
2269*a2255df3SDaniel Beauregard 
2270*a2255df3SDaniel Beauregard 	(void) qlt_reset_chip(qlt);
2271*a2255df3SDaniel Beauregard 
2272*a2255df3SDaniel Beauregard 	if (qlt->qlt_81xx_chip) {
2273*a2255df3SDaniel Beauregard 		qlt_mps_reset(qlt);
2274*a2255df3SDaniel Beauregard 	}
2275fcf3ce44SJohn Forte 
2276fcf3ce44SJohn Forte 	/* Load the two segments */
2277fcf3ce44SJohn Forte 	if (qlt->fw_code01 != NULL) {
2278fcf3ce44SJohn Forte 		ret = qlt_load_risc_ram(qlt, qlt->fw_code01, qlt->fw_length01,
2279d8c54e3dSSam Cramer 		    qlt->fw_addr01);
2280fcf3ce44SJohn Forte 		if (ret == QLT_SUCCESS) {
2281fcf3ce44SJohn Forte 			ret = qlt_load_risc_ram(qlt, qlt->fw_code02,
2282fcf3ce44SJohn Forte 			    qlt->fw_length02, qlt->fw_addr02);
2283fcf3ce44SJohn Forte 		}
2284fcf3ce44SJohn Forte 		start_addr = qlt->fw_addr01;
2285c4ddbbe1SDaniel Beauregard 	} else if (qlt->qlt_81xx_chip) {
2286c4ddbbe1SDaniel Beauregard 		ret = qlt_load_risc_ram(qlt, fw8100_code01, fw8100_length01,
2287c4ddbbe1SDaniel Beauregard 		    fw8100_addr01);
2288c4ddbbe1SDaniel Beauregard 		if (ret == QLT_SUCCESS) {
2289c4ddbbe1SDaniel Beauregard 			ret = qlt_load_risc_ram(qlt, fw8100_code02,
2290c4ddbbe1SDaniel Beauregard 			    fw8100_length02, fw8100_addr02);
2291c4ddbbe1SDaniel Beauregard 		}
2292c4ddbbe1SDaniel Beauregard 		start_addr = fw8100_addr01;
2293fcf3ce44SJohn Forte 	} else if (qlt->qlt_25xx_chip) {
2294fcf3ce44SJohn Forte 		ret = qlt_load_risc_ram(qlt, fw2500_code01, fw2500_length01,
2295d8c54e3dSSam Cramer 		    fw2500_addr01);
2296fcf3ce44SJohn Forte 		if (ret == QLT_SUCCESS) {
2297fcf3ce44SJohn Forte 			ret = qlt_load_risc_ram(qlt, fw2500_code02,
2298d8c54e3dSSam Cramer 			    fw2500_length02, fw2500_addr02);
2299fcf3ce44SJohn Forte 		}
2300fcf3ce44SJohn Forte 		start_addr = fw2500_addr01;
2301fcf3ce44SJohn Forte 	} else {
2302fcf3ce44SJohn Forte 		ret = qlt_load_risc_ram(qlt, fw2400_code01, fw2400_length01,
2303d8c54e3dSSam Cramer 		    fw2400_addr01);
2304fcf3ce44SJohn Forte 		if (ret == QLT_SUCCESS) {
2305fcf3ce44SJohn Forte 			ret = qlt_load_risc_ram(qlt, fw2400_code02,
2306d8c54e3dSSam Cramer 			    fw2400_length02, fw2400_addr02);
2307fcf3ce44SJohn Forte 		}
2308fcf3ce44SJohn Forte 		start_addr = fw2400_addr01;
2309fcf3ce44SJohn Forte 	}
2310c4ddbbe1SDaniel Beauregard 	if (ret != QLT_SUCCESS) {
2311c4ddbbe1SDaniel Beauregard 		EL(qlt, "qlt_load_risc_ram status=%llxh\n", ret);
2312fcf3ce44SJohn Forte 		return (ret);
2313c4ddbbe1SDaniel Beauregard 	}
2314fcf3ce44SJohn Forte 
2315fcf3ce44SJohn Forte 	/* Verify Checksum */
2316*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(0), MBC_VERIFY_CHECKSUM);
2317*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(1), MSW(start_addr));
2318*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(2), LSW(start_addr));
2319fcf3ce44SJohn Forte 	ret = qlt_raw_mailbox_command(qlt);
2320*a2255df3SDaniel Beauregard 	REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
2321c4ddbbe1SDaniel Beauregard 	if (ret != QLT_SUCCESS) {
2322c4ddbbe1SDaniel Beauregard 		EL(qlt, "qlt_raw_mailbox_command=7h status=%llxh\n", ret);
2323fcf3ce44SJohn Forte 		return (ret);
2324c4ddbbe1SDaniel Beauregard 	}
2325fcf3ce44SJohn Forte 
2326fcf3ce44SJohn Forte 	/* Execute firmware */
2327*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(0), MBC_EXECUTE_FIRMWARE);
2328*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(1), MSW(start_addr));
2329*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(2), LSW(start_addr));
2330fcf3ce44SJohn Forte 	REG_WR16(qlt, REG_MBOX(3), 0);
2331fcf3ce44SJohn Forte 	REG_WR16(qlt, REG_MBOX(4), 1);	/* 25xx enable additional credits */
2332fcf3ce44SJohn Forte 	ret = qlt_raw_mailbox_command(qlt);
2333*a2255df3SDaniel Beauregard 	REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
2334c4ddbbe1SDaniel Beauregard 	if (ret != QLT_SUCCESS) {
2335c4ddbbe1SDaniel Beauregard 		EL(qlt, "qlt_raw_mailbox_command=2h status=%llxh\n", ret);
2336fcf3ce44SJohn Forte 		return (ret);
2337c4ddbbe1SDaniel Beauregard 	}
2338fcf3ce44SJohn Forte 
2339fcf3ce44SJohn Forte 	/* Get revisions (About Firmware) */
2340*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(0), MBC_ABOUT_FIRMWARE);
2341fcf3ce44SJohn Forte 	ret = qlt_raw_mailbox_command(qlt);
2342fcf3ce44SJohn Forte 	qlt->fw_major = REG_RD16(qlt, REG_MBOX(1));
2343fcf3ce44SJohn Forte 	qlt->fw_minor = REG_RD16(qlt, REG_MBOX(2));
2344fcf3ce44SJohn Forte 	qlt->fw_subminor = REG_RD16(qlt, REG_MBOX(3));
2345fcf3ce44SJohn Forte 	qlt->fw_endaddrlo = REG_RD16(qlt, REG_MBOX(4));
2346fcf3ce44SJohn Forte 	qlt->fw_endaddrhi = REG_RD16(qlt, REG_MBOX(5));
2347fcf3ce44SJohn Forte 	qlt->fw_attr = REG_RD16(qlt, REG_MBOX(6));
2348*a2255df3SDaniel Beauregard 	REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
2349c4ddbbe1SDaniel Beauregard 	if (ret != QLT_SUCCESS) {
2350c4ddbbe1SDaniel Beauregard 		EL(qlt, "qlt_raw_mailbox_command=8h status=%llxh\n", ret);
2351fcf3ce44SJohn Forte 		return (ret);
2352c4ddbbe1SDaniel Beauregard 	}
2353fcf3ce44SJohn Forte 
2354fcf3ce44SJohn Forte 	return (QLT_SUCCESS);
2355fcf3ce44SJohn Forte }
2356fcf3ce44SJohn Forte 
2357fcf3ce44SJohn Forte /*
2358*a2255df3SDaniel Beauregard  * Used only from qlt_download_fw().
2359fcf3ce44SJohn Forte  */
2360fcf3ce44SJohn Forte static fct_status_t
2361fcf3ce44SJohn Forte qlt_load_risc_ram(qlt_state_t *qlt, uint32_t *host_addr,
2362fcf3ce44SJohn Forte 				uint32_t word_count, uint32_t risc_addr)
2363fcf3ce44SJohn Forte {
2364fcf3ce44SJohn Forte 	uint32_t words_sent = 0;
2365fcf3ce44SJohn Forte 	uint32_t words_being_sent;
2366fcf3ce44SJohn Forte 	uint32_t *cur_host_addr;
2367fcf3ce44SJohn Forte 	uint32_t cur_risc_addr;
2368fcf3ce44SJohn Forte 	uint64_t da;
2369fcf3ce44SJohn Forte 	fct_status_t ret;
2370fcf3ce44SJohn Forte 
2371fcf3ce44SJohn Forte 	while (words_sent < word_count) {
2372fcf3ce44SJohn Forte 		cur_host_addr = &(host_addr[words_sent]);
2373fcf3ce44SJohn Forte 		cur_risc_addr = risc_addr + (words_sent << 2);
2374fcf3ce44SJohn Forte 		words_being_sent = min(word_count - words_sent,
2375d8c54e3dSSam Cramer 		    TOTAL_DMA_MEM_SIZE >> 2);
2376fcf3ce44SJohn Forte 		ddi_rep_put32(qlt->queue_mem_acc_handle, cur_host_addr,
2377fcf3ce44SJohn Forte 		    (uint32_t *)qlt->queue_mem_ptr, words_being_sent,
2378fcf3ce44SJohn Forte 		    DDI_DEV_AUTOINCR);
2379fcf3ce44SJohn Forte 		(void) ddi_dma_sync(qlt->queue_mem_dma_handle, 0,
2380d8c54e3dSSam Cramer 		    words_being_sent << 2, DDI_DMA_SYNC_FORDEV);
2381fcf3ce44SJohn Forte 		da = qlt->queue_mem_cookie.dmac_laddress;
2382*a2255df3SDaniel Beauregard 		REG_WR16(qlt, REG_MBOX(0), MBC_LOAD_RAM_EXTENDED);
2383*a2255df3SDaniel Beauregard 		REG_WR16(qlt, REG_MBOX(1), LSW(risc_addr));
2384*a2255df3SDaniel Beauregard 		REG_WR16(qlt, REG_MBOX(8), MSW(cur_risc_addr));
2385*a2255df3SDaniel Beauregard 		REG_WR16(qlt, REG_MBOX(3), LSW(LSD(da)));
2386*a2255df3SDaniel Beauregard 		REG_WR16(qlt, REG_MBOX(2), MSW(LSD(da)));
2387*a2255df3SDaniel Beauregard 		REG_WR16(qlt, REG_MBOX(7), LSW(MSD(da)));
2388*a2255df3SDaniel Beauregard 		REG_WR16(qlt, REG_MBOX(6), MSW(MSD(da)));
2389*a2255df3SDaniel Beauregard 		REG_WR16(qlt, REG_MBOX(5), LSW(words_being_sent));
2390*a2255df3SDaniel Beauregard 		REG_WR16(qlt, REG_MBOX(4), MSW(words_being_sent));
2391fcf3ce44SJohn Forte 		ret = qlt_raw_mailbox_command(qlt);
2392*a2255df3SDaniel Beauregard 		REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
2393c4ddbbe1SDaniel Beauregard 		if (ret != QLT_SUCCESS) {
2394c4ddbbe1SDaniel Beauregard 			EL(qlt, "qlt_raw_mailbox_command=0Bh status=%llxh\n",
2395c4ddbbe1SDaniel Beauregard 			    ret);
2396fcf3ce44SJohn Forte 			return (ret);
2397c4ddbbe1SDaniel Beauregard 		}
2398fcf3ce44SJohn Forte 		words_sent += words_being_sent;
2399fcf3ce44SJohn Forte 	}
2400fcf3ce44SJohn Forte 	return (QLT_SUCCESS);
2401fcf3ce44SJohn Forte }
2402fcf3ce44SJohn Forte 
2403fcf3ce44SJohn Forte /*
2404fcf3ce44SJohn Forte  * Not used during normal operation. Only during driver init.
2405fcf3ce44SJohn Forte  * Assumes that interrupts are disabled and mailboxes are loaded.
2406fcf3ce44SJohn Forte  * Just triggers the mailbox command an waits for the completion.
2407fcf3ce44SJohn Forte  * Also expects that There is nothing else going on and we will only
2408fcf3ce44SJohn Forte  * get back a mailbox completion from firmware.
2409fcf3ce44SJohn Forte  * ---DOES NOT CLEAR INTERRUPT---
2410fcf3ce44SJohn Forte  * Used only from the code path originating from
2411fcf3ce44SJohn Forte  * qlt_reset_chip_and_download_fw()
2412fcf3ce44SJohn Forte  */
2413fcf3ce44SJohn Forte static fct_status_t
2414fcf3ce44SJohn Forte qlt_raw_mailbox_command(qlt_state_t *qlt)
2415fcf3ce44SJohn Forte {
2416fcf3ce44SJohn Forte 	int cntr = 0;
2417fcf3ce44SJohn Forte 	uint32_t status;
2418fcf3ce44SJohn Forte 
2419*a2255df3SDaniel Beauregard 	REG_WR32(qlt, REG_HCCR, HCCR_CMD(SET_HOST_TO_RISC_INTR));
2420*a2255df3SDaniel Beauregard 	while ((REG_RD32(qlt, REG_INTR_STATUS) & RISC_PCI_INTR_REQUEST) == 0) {
2421fcf3ce44SJohn Forte 		cntr++;
2422*a2255df3SDaniel Beauregard 		if (cntr == 100) {
2423fcf3ce44SJohn Forte 			return (QLT_MAILBOX_STUCK);
2424*a2255df3SDaniel Beauregard 		}
2425fcf3ce44SJohn Forte 		delay(drv_usectohz(10000));
2426fcf3ce44SJohn Forte 	}
2427*a2255df3SDaniel Beauregard 	status = (REG_RD32(qlt, REG_RISC_STATUS) & FW_INTR_STATUS_MASK);
2428*a2255df3SDaniel Beauregard 
2429*a2255df3SDaniel Beauregard 	if ((status == ROM_MBX_CMD_SUCCESSFUL) ||
2430*a2255df3SDaniel Beauregard 	    (status == ROM_MBX_CMD_NOT_SUCCESSFUL) ||
2431*a2255df3SDaniel Beauregard 	    (status == MBX_CMD_SUCCESSFUL) ||
2432*a2255df3SDaniel Beauregard 	    (status == MBX_CMD_NOT_SUCCESSFUL)) {
2433fcf3ce44SJohn Forte 		uint16_t mbox0 = REG_RD16(qlt, REG_MBOX(0));
2434*a2255df3SDaniel Beauregard 		if (mbox0 == QLT_MBX_CMD_SUCCESS) {
2435fcf3ce44SJohn Forte 			return (QLT_SUCCESS);
2436*a2255df3SDaniel Beauregard 		} else {
2437fcf3ce44SJohn Forte 			return (QLT_MBOX_FAILED | mbox0);
2438*a2255df3SDaniel Beauregard 		}
2439fcf3ce44SJohn Forte 	}
2440fcf3ce44SJohn Forte 	/* This is unexpected, dump a message */
2441fcf3ce44SJohn Forte 	cmn_err(CE_WARN, "qlt(%d): Unexpect intr status %llx",
2442fcf3ce44SJohn Forte 	    ddi_get_instance(qlt->dip), (unsigned long long)status);
2443fcf3ce44SJohn Forte 	return (QLT_UNEXPECTED_RESPONSE);
2444fcf3ce44SJohn Forte }
2445fcf3ce44SJohn Forte 
2446fcf3ce44SJohn Forte static mbox_cmd_t *
2447fcf3ce44SJohn Forte qlt_alloc_mailbox_command(qlt_state_t *qlt, uint32_t dma_size)
2448fcf3ce44SJohn Forte {
2449fcf3ce44SJohn Forte 	mbox_cmd_t *mcp;
2450fcf3ce44SJohn Forte 
2451fcf3ce44SJohn Forte 	mcp = (mbox_cmd_t *)kmem_zalloc(sizeof (mbox_cmd_t), KM_SLEEP);
2452fcf3ce44SJohn Forte 	if (dma_size) {
2453fcf3ce44SJohn Forte 		qlt_dmem_bctl_t *bctl;
2454fcf3ce44SJohn Forte 		uint64_t da;
2455fcf3ce44SJohn Forte 
2456fcf3ce44SJohn Forte 		mcp->dbuf = qlt_i_dmem_alloc(qlt, dma_size, &dma_size, 0);
2457fcf3ce44SJohn Forte 		if (mcp->dbuf == NULL) {
2458fcf3ce44SJohn Forte 			kmem_free(mcp, sizeof (*mcp));
2459fcf3ce44SJohn Forte 			return (NULL);
2460fcf3ce44SJohn Forte 		}
2461fcf3ce44SJohn Forte 		mcp->dbuf->db_data_size = dma_size;
2462fcf3ce44SJohn Forte 		ASSERT(mcp->dbuf->db_sglist_length == 1);
2463fcf3ce44SJohn Forte 
2464fcf3ce44SJohn Forte 		bctl = (qlt_dmem_bctl_t *)mcp->dbuf->db_port_private;
2465fcf3ce44SJohn Forte 		da = bctl->bctl_dev_addr;
2466fcf3ce44SJohn Forte 		/* This is the most common initialization of dma ptrs */
2467*a2255df3SDaniel Beauregard 		mcp->to_fw[3] = LSW(LSD(da));
2468*a2255df3SDaniel Beauregard 		mcp->to_fw[2] = MSW(LSD(da));
2469*a2255df3SDaniel Beauregard 		mcp->to_fw[7] = LSW(MSD(da));
2470*a2255df3SDaniel Beauregard 		mcp->to_fw[6] = MSW(MSD(da));
2471fcf3ce44SJohn Forte 		mcp->to_fw_mask |= BIT_2 | BIT_3 | BIT_7 | BIT_6;
2472fcf3ce44SJohn Forte 	}
2473fcf3ce44SJohn Forte 	mcp->to_fw_mask |= BIT_0;
2474fcf3ce44SJohn Forte 	mcp->from_fw_mask |= BIT_0;
2475fcf3ce44SJohn Forte 	return (mcp);
2476fcf3ce44SJohn Forte }
2477fcf3ce44SJohn Forte 
2478fcf3ce44SJohn Forte void
2479fcf3ce44SJohn Forte qlt_free_mailbox_command(qlt_state_t *qlt, mbox_cmd_t *mcp)
2480fcf3ce44SJohn Forte {
2481fcf3ce44SJohn Forte 	if (mcp->dbuf)
2482fcf3ce44SJohn Forte 		qlt_i_dmem_free(qlt, mcp->dbuf);
2483fcf3ce44SJohn Forte 	kmem_free(mcp, sizeof (*mcp));
2484fcf3ce44SJohn Forte }
2485fcf3ce44SJohn Forte 
2486fcf3ce44SJohn Forte /*
2487fcf3ce44SJohn Forte  * This can sleep. Should never be called from interrupt context.
2488fcf3ce44SJohn Forte  */
2489fcf3ce44SJohn Forte static fct_status_t
2490fcf3ce44SJohn Forte qlt_mailbox_command(qlt_state_t *qlt, mbox_cmd_t *mcp)
2491fcf3ce44SJohn Forte {
2492fcf3ce44SJohn Forte 	int	retries;
2493fcf3ce44SJohn Forte 	int	i;
2494fcf3ce44SJohn Forte 	char	info[80];
2495fcf3ce44SJohn Forte 
2496fcf3ce44SJohn Forte 	if (curthread->t_flag & T_INTR_THREAD) {
2497fcf3ce44SJohn Forte 		ASSERT(0);
2498fcf3ce44SJohn Forte 		return (QLT_MBOX_FAILED);
2499fcf3ce44SJohn Forte 	}
2500fcf3ce44SJohn Forte 
2501fcf3ce44SJohn Forte 	mutex_enter(&qlt->mbox_lock);
2502fcf3ce44SJohn Forte 	/* See if mailboxes are still uninitialized */
2503fcf3ce44SJohn Forte 	if (qlt->mbox_io_state == MBOX_STATE_UNKNOWN) {
2504fcf3ce44SJohn Forte 		mutex_exit(&qlt->mbox_lock);
2505fcf3ce44SJohn Forte 		return (QLT_MBOX_NOT_INITIALIZED);
2506fcf3ce44SJohn Forte 	}
2507fcf3ce44SJohn Forte 
2508fcf3ce44SJohn Forte 	/* Wait to grab the mailboxes */
2509fcf3ce44SJohn Forte 	for (retries = 0; qlt->mbox_io_state != MBOX_STATE_READY;
2510d8c54e3dSSam Cramer 	    retries++) {
2511fcf3ce44SJohn Forte 		cv_wait(&qlt->mbox_cv, &qlt->mbox_lock);
2512fcf3ce44SJohn Forte 		if ((retries > 5) ||
2513fcf3ce44SJohn Forte 		    (qlt->mbox_io_state == MBOX_STATE_UNKNOWN)) {
2514fcf3ce44SJohn Forte 			mutex_exit(&qlt->mbox_lock);
2515fcf3ce44SJohn Forte 			return (QLT_MBOX_BUSY);
2516fcf3ce44SJohn Forte 		}
2517fcf3ce44SJohn Forte 	}
2518fcf3ce44SJohn Forte 	/* Make sure we always ask for mailbox 0 */
2519fcf3ce44SJohn Forte 	mcp->from_fw_mask |= BIT_0;
2520fcf3ce44SJohn Forte 
2521fcf3ce44SJohn Forte 	/* Load mailboxes, set state and generate RISC interrupt */
2522fcf3ce44SJohn Forte 	qlt->mbox_io_state = MBOX_STATE_CMD_RUNNING;
2523fcf3ce44SJohn Forte 	qlt->mcp = mcp;
2524fcf3ce44SJohn Forte 	for (i = 0; i < MAX_MBOXES; i++) {
2525fcf3ce44SJohn Forte 		if (mcp->to_fw_mask & ((uint32_t)1 << i))
2526fcf3ce44SJohn Forte 			REG_WR16(qlt, REG_MBOX(i), mcp->to_fw[i]);
2527fcf3ce44SJohn Forte 	}
2528*a2255df3SDaniel Beauregard 	REG_WR32(qlt, REG_HCCR, HCCR_CMD(SET_HOST_TO_RISC_INTR));
2529fcf3ce44SJohn Forte 
2530fcf3ce44SJohn Forte qlt_mbox_wait_loop:;
2531fcf3ce44SJohn Forte 	/* Wait for mailbox command completion */
2532*a2255df3SDaniel Beauregard 	if (cv_timedwait(&qlt->mbox_cv, &qlt->mbox_lock, ddi_get_lbolt()
2533*a2255df3SDaniel Beauregard 	    + drv_usectohz(MBOX_TIMEOUT)) < 0) {
2534fcf3ce44SJohn Forte 		(void) snprintf(info, 80, "qlt_mailbox_command: qlt-%p, "
2535fcf3ce44SJohn Forte 		    "cmd-0x%02X timed out", (void *)qlt, qlt->mcp->to_fw[0]);
2536fcf3ce44SJohn Forte 		info[79] = 0;
2537fcf3ce44SJohn Forte 		qlt->mcp = NULL;
2538fcf3ce44SJohn Forte 		qlt->mbox_io_state = MBOX_STATE_UNKNOWN;
2539fcf3ce44SJohn Forte 		mutex_exit(&qlt->mbox_lock);
2540fcf3ce44SJohn Forte 
2541fcf3ce44SJohn Forte 		/*
2542fcf3ce44SJohn Forte 		 * XXX Throw HBA fatal error event
2543fcf3ce44SJohn Forte 		 */
2544fcf3ce44SJohn Forte 		(void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR |
2545fcf3ce44SJohn Forte 		    STMF_RFLAG_RESET | STMF_RFLAG_COLLECT_DEBUG_DUMP, info);
2546fcf3ce44SJohn Forte 		return (QLT_MBOX_TIMEOUT);
2547fcf3ce44SJohn Forte 	}
2548fcf3ce44SJohn Forte 	if (qlt->mbox_io_state == MBOX_STATE_CMD_RUNNING)
2549fcf3ce44SJohn Forte 		goto qlt_mbox_wait_loop;
2550fcf3ce44SJohn Forte 
2551fcf3ce44SJohn Forte 	qlt->mcp = NULL;
2552fcf3ce44SJohn Forte 
2553fcf3ce44SJohn Forte 	/* Make sure its a completion */
2554fcf3ce44SJohn Forte 	if (qlt->mbox_io_state != MBOX_STATE_CMD_DONE) {
2555fcf3ce44SJohn Forte 		ASSERT(qlt->mbox_io_state == MBOX_STATE_UNKNOWN);
2556fcf3ce44SJohn Forte 		mutex_exit(&qlt->mbox_lock);
2557fcf3ce44SJohn Forte 		return (QLT_MBOX_ABORTED);
2558fcf3ce44SJohn Forte 	}
2559fcf3ce44SJohn Forte 
2560fcf3ce44SJohn Forte 	/* MBox command completed. Clear state, retuen based on mbox 0 */
2561fcf3ce44SJohn Forte 	/* Mailboxes are already loaded by interrupt routine */
2562fcf3ce44SJohn Forte 	qlt->mbox_io_state = MBOX_STATE_READY;
2563fcf3ce44SJohn Forte 	mutex_exit(&qlt->mbox_lock);
2564*a2255df3SDaniel Beauregard 	if (mcp->from_fw[0] != QLT_MBX_CMD_SUCCESS)
2565fcf3ce44SJohn Forte 		return (QLT_MBOX_FAILED | mcp->from_fw[0]);
2566fcf3ce44SJohn Forte 
2567fcf3ce44SJohn Forte 	return (QLT_SUCCESS);
2568fcf3ce44SJohn Forte }
2569fcf3ce44SJohn Forte 
2570fcf3ce44SJohn Forte /*
2571fcf3ce44SJohn Forte  * **SHOULD ONLY BE CALLED FROM INTERRUPT CONTEXT. DO NOT CALL ELSEWHERE**
2572fcf3ce44SJohn Forte  */
2573fcf3ce44SJohn Forte /* ARGSUSED */
2574fcf3ce44SJohn Forte static uint_t
2575fcf3ce44SJohn Forte qlt_isr(caddr_t arg, caddr_t arg2)
2576fcf3ce44SJohn Forte {
2577fcf3ce44SJohn Forte 	qlt_state_t	*qlt = (qlt_state_t *)arg;
2578fcf3ce44SJohn Forte 	uint32_t	risc_status, intr_type;
2579fcf3ce44SJohn Forte 	int		i;
2580fcf3ce44SJohn Forte 	int		intr_loop_count;
2581fcf3ce44SJohn Forte 	char		info[80];
2582fcf3ce44SJohn Forte 
2583fcf3ce44SJohn Forte 	risc_status = REG_RD32(qlt, REG_RISC_STATUS);
2584fcf3ce44SJohn Forte 	if (!mutex_tryenter(&qlt->intr_lock)) {
2585fcf3ce44SJohn Forte 		/*
2586fcf3ce44SJohn Forte 		 * Normally we will always get this lock. If tryenter is
2587fcf3ce44SJohn Forte 		 * failing then it means that driver is trying to do
2588fcf3ce44SJohn Forte 		 * some cleanup and is masking the intr but some intr
2589fcf3ce44SJohn Forte 		 * has sneaked in between. See if our device has generated
2590fcf3ce44SJohn Forte 		 * this intr. If so then wait a bit and return claimed.
2591fcf3ce44SJohn Forte 		 * If not then return claimed if this is the 1st instance
2592fcf3ce44SJohn Forte 		 * of a interrupt after driver has grabbed the lock.
2593fcf3ce44SJohn Forte 		 */
2594fcf3ce44SJohn Forte 		if (risc_status & BIT_15) {
2595fcf3ce44SJohn Forte 			drv_usecwait(10);
2596fcf3ce44SJohn Forte 			return (DDI_INTR_CLAIMED);
2597fcf3ce44SJohn Forte 		} else if (qlt->intr_sneak_counter) {
2598fcf3ce44SJohn Forte 			qlt->intr_sneak_counter--;
2599fcf3ce44SJohn Forte 			return (DDI_INTR_CLAIMED);
2600fcf3ce44SJohn Forte 		} else {
2601fcf3ce44SJohn Forte 			return (DDI_INTR_UNCLAIMED);
2602fcf3ce44SJohn Forte 		}
2603fcf3ce44SJohn Forte 	}
2604fcf3ce44SJohn Forte 	if (((risc_status & BIT_15) == 0) ||
2605fcf3ce44SJohn Forte 	    (qlt->qlt_intr_enabled == 0)) {
2606fcf3ce44SJohn Forte 		/*
2607fcf3ce44SJohn Forte 		 * This might be a pure coincedence that we are operating
2608fcf3ce44SJohn Forte 		 * in a interrupt disabled mode and another device
2609fcf3ce44SJohn Forte 		 * sharing the interrupt line has generated an interrupt
2610fcf3ce44SJohn Forte 		 * while an interrupt from our device might be pending. Just
2611fcf3ce44SJohn Forte 		 * ignore it and let the code handling the interrupt
2612fcf3ce44SJohn Forte 		 * disabled mode handle it.
2613fcf3ce44SJohn Forte 		 */
2614fcf3ce44SJohn Forte 		mutex_exit(&qlt->intr_lock);
2615fcf3ce44SJohn Forte 		return (DDI_INTR_UNCLAIMED);
2616fcf3ce44SJohn Forte 	}
2617fcf3ce44SJohn Forte 
2618fcf3ce44SJohn Forte 	/*
2619fcf3ce44SJohn Forte 	 * XXX take care for MSI case. disable intrs
2620c4ddbbe1SDaniel Beauregard 	 * Its gonna be complicated because of the max iterations.
2621fcf3ce44SJohn Forte 	 * as hba will have posted the intr which did not go on PCI
2622c4ddbbe1SDaniel Beauregard 	 * but we did not service it either because of max iterations.
2623fcf3ce44SJohn Forte 	 * Maybe offload the intr on a different thread.
2624fcf3ce44SJohn Forte 	 */
2625fcf3ce44SJohn Forte 	intr_loop_count = 0;
2626fcf3ce44SJohn Forte 
2627fcf3ce44SJohn Forte 	REG_WR32(qlt, REG_INTR_CTRL, 0);
2628fcf3ce44SJohn Forte 
2629fcf3ce44SJohn Forte intr_again:;
2630c4ddbbe1SDaniel Beauregard 
2631c4ddbbe1SDaniel Beauregard 	/* check for risc pause */
2632c4ddbbe1SDaniel Beauregard 	if (risc_status & BIT_8) {
2633c4ddbbe1SDaniel Beauregard 		EL(qlt, "Risc Pause status=%xh\n", risc_status);
2634c4ddbbe1SDaniel Beauregard 		cmn_err(CE_WARN, "qlt(%d): Risc Pause %08x",
26350ff6bfafSDaniel Beauregard 		    qlt->instance, risc_status);
2636c4ddbbe1SDaniel Beauregard 		(void) snprintf(info, 80, "Risc Pause %08x", risc_status);
2637c4ddbbe1SDaniel Beauregard 		info[79] = 0;
2638c4ddbbe1SDaniel Beauregard 		(void) fct_port_shutdown(qlt->qlt_port,
2639c4ddbbe1SDaniel Beauregard 		    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET |
2640c4ddbbe1SDaniel Beauregard 		    STMF_RFLAG_COLLECT_DEBUG_DUMP, info);
2641c4ddbbe1SDaniel Beauregard 	}
2642c4ddbbe1SDaniel Beauregard 
2643fcf3ce44SJohn Forte 	/* First check for high performance path */
2644fcf3ce44SJohn Forte 	intr_type = risc_status & 0xff;
26450ff6bfafSDaniel Beauregard 	if (intr_type == 0x1D) {
26460ff6bfafSDaniel Beauregard 		qlt->atio_ndx_from_fw = (uint16_t)
26470ff6bfafSDaniel Beauregard 		    REG_RD32(qlt, REG_ATIO_IN_PTR);
2648*a2255df3SDaniel Beauregard 		REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
26490ff6bfafSDaniel Beauregard 		qlt->resp_ndx_from_fw = risc_status >> 16;
26500ff6bfafSDaniel Beauregard 		qlt_handle_atio_queue_update(qlt);
26510ff6bfafSDaniel Beauregard 		qlt_handle_resp_queue_update(qlt);
26520ff6bfafSDaniel Beauregard 	} else if (intr_type == 0x1C) {
2653*a2255df3SDaniel Beauregard 		REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
2654c4ddbbe1SDaniel Beauregard 		qlt->atio_ndx_from_fw = (uint16_t)(risc_status >> 16);
2655fcf3ce44SJohn Forte 		qlt_handle_atio_queue_update(qlt);
2656fcf3ce44SJohn Forte 	} else if (intr_type == 0x13) {
2657*a2255df3SDaniel Beauregard 		REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
2658fcf3ce44SJohn Forte 		qlt->resp_ndx_from_fw = risc_status >> 16;
2659fcf3ce44SJohn Forte 		qlt_handle_resp_queue_update(qlt);
2660fcf3ce44SJohn Forte 	} else if (intr_type == 0x12) {
2661c4ddbbe1SDaniel Beauregard 		uint16_t code = (uint16_t)(risc_status >> 16);
2662fcf3ce44SJohn Forte 		uint16_t mbox1 = REG_RD16(qlt, REG_MBOX(1));
2663fcf3ce44SJohn Forte 		uint16_t mbox2 = REG_RD16(qlt, REG_MBOX(2));
2664c4ddbbe1SDaniel Beauregard 		uint16_t mbox3 = REG_RD16(qlt, REG_MBOX(3));
2665c4ddbbe1SDaniel Beauregard 		uint16_t mbox4 = REG_RD16(qlt, REG_MBOX(4));
2666fcf3ce44SJohn Forte 		uint16_t mbox5 = REG_RD16(qlt, REG_MBOX(5));
2667fcf3ce44SJohn Forte 		uint16_t mbox6 = REG_RD16(qlt, REG_MBOX(6));
2668fcf3ce44SJohn Forte 
2669*a2255df3SDaniel Beauregard 		REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
2670fcf3ce44SJohn Forte 		stmf_trace(qlt->qlt_port_alias, "Async event %x mb1=%x mb2=%x,"
2671c4ddbbe1SDaniel Beauregard 		    " mb3=%x, mb5=%x, mb6=%x", code, mbox1, mbox2, mbox3,
2672c4ddbbe1SDaniel Beauregard 		    mbox5, mbox6);
2673*a2255df3SDaniel Beauregard 		EL(qlt, "Async event %x mb1=%x mb2=%x, mb3=%x, mb5=%x, mb6=%x",
2674*a2255df3SDaniel Beauregard 		    code, mbox1, mbox2, mbox3, mbox5, mbox6);
2675fcf3ce44SJohn Forte 
2676fcf3ce44SJohn Forte 		if ((code == 0x8030) || (code == 0x8010) || (code == 0x8013)) {
2677fcf3ce44SJohn Forte 			if (qlt->qlt_link_up) {
2678fcf3ce44SJohn Forte 				fct_handle_event(qlt->qlt_port,
2679fcf3ce44SJohn Forte 				    FCT_EVENT_LINK_RESET, 0, 0);
2680fcf3ce44SJohn Forte 			}
2681fcf3ce44SJohn Forte 		} else if (code == 0x8012) {
2682fcf3ce44SJohn Forte 			qlt->qlt_link_up = 0;
2683fcf3ce44SJohn Forte 			fct_handle_event(qlt->qlt_port, FCT_EVENT_LINK_DOWN,
2684d8c54e3dSSam Cramer 			    0, 0);
2685fcf3ce44SJohn Forte 		} else if (code == 0x8011) {
2686fcf3ce44SJohn Forte 			switch (mbox1) {
2687fcf3ce44SJohn Forte 			case 0: qlt->link_speed = PORT_SPEED_1G;
2688fcf3ce44SJohn Forte 				break;
2689fcf3ce44SJohn Forte 			case 1: qlt->link_speed = PORT_SPEED_2G;
2690fcf3ce44SJohn Forte 				break;
2691fcf3ce44SJohn Forte 			case 3: qlt->link_speed = PORT_SPEED_4G;
2692fcf3ce44SJohn Forte 				break;
2693fcf3ce44SJohn Forte 			case 4: qlt->link_speed = PORT_SPEED_8G;
2694fcf3ce44SJohn Forte 				break;
2695c4ddbbe1SDaniel Beauregard 			case 0x13: qlt->link_speed = PORT_SPEED_10G;
2696c4ddbbe1SDaniel Beauregard 				break;
2697fcf3ce44SJohn Forte 			default:
2698fcf3ce44SJohn Forte 				qlt->link_speed = PORT_SPEED_UNKNOWN;
2699fcf3ce44SJohn Forte 			}
2700fcf3ce44SJohn Forte 			qlt->qlt_link_up = 1;
2701fcf3ce44SJohn Forte 			fct_handle_event(qlt->qlt_port, FCT_EVENT_LINK_UP,
2702d8c54e3dSSam Cramer 			    0, 0);
2703c4ddbbe1SDaniel Beauregard 		} else if ((code == 0x8002) || (code == 0x8003) ||
2704c4ddbbe1SDaniel Beauregard 		    (code == 0x8004) || (code == 0x8005)) {
2705fcf3ce44SJohn Forte 			(void) snprintf(info, 80,
2706c4ddbbe1SDaniel Beauregard 			    "Got %04x, mb1=%x mb2=%x mb5=%x mb6=%x",
2707c4ddbbe1SDaniel Beauregard 			    code, mbox1, mbox2, mbox5, mbox6);
2708fcf3ce44SJohn Forte 			info[79] = 0;
2709fcf3ce44SJohn Forte 			(void) fct_port_shutdown(qlt->qlt_port,
2710fcf3ce44SJohn Forte 			    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET |
2711fcf3ce44SJohn Forte 			    STMF_RFLAG_COLLECT_DEBUG_DUMP, info);
2712c4ddbbe1SDaniel Beauregard 		} else if (code == 0x800F) {
2713c4ddbbe1SDaniel Beauregard 			(void) snprintf(info, 80,
2714c4ddbbe1SDaniel Beauregard 			    "Got 800F, mb1=%x mb2=%x mb3=%x",
2715c4ddbbe1SDaniel Beauregard 			    mbox1, mbox2, mbox3);
2716c4ddbbe1SDaniel Beauregard 
2717c4ddbbe1SDaniel Beauregard 			if (mbox1 != 1) {
2718c4ddbbe1SDaniel Beauregard 				/* issue "verify fw" */
2719c4ddbbe1SDaniel Beauregard 				qlt_verify_fw(qlt);
2720c4ddbbe1SDaniel Beauregard 			}
2721c4ddbbe1SDaniel Beauregard 		} else if (code == 0x8101) {
2722c4ddbbe1SDaniel Beauregard 			(void) snprintf(info, 80,
2723c4ddbbe1SDaniel Beauregard 			    "IDC Req Rcvd:%04x, mb1=%x mb2=%x mb3=%x",
2724c4ddbbe1SDaniel Beauregard 			    code, mbox1, mbox2, mbox3);
2725c4ddbbe1SDaniel Beauregard 			info[79] = 0;
2726c4ddbbe1SDaniel Beauregard 
2727c4ddbbe1SDaniel Beauregard 			/* check if "ACK" is required (timeout != 0) */
2728c4ddbbe1SDaniel Beauregard 			if (mbox1 & 0x0f00) {
2729c4ddbbe1SDaniel Beauregard 				caddr_t	req;
2730c4ddbbe1SDaniel Beauregard 
2731c4ddbbe1SDaniel Beauregard 				/*
2732c4ddbbe1SDaniel Beauregard 				 * Ack the request (queue work to do it?)
2733c4ddbbe1SDaniel Beauregard 				 * using a mailbox iocb
2734c4ddbbe1SDaniel Beauregard 				 */
2735c4ddbbe1SDaniel Beauregard 				mutex_enter(&qlt->req_lock);
2736c4ddbbe1SDaniel Beauregard 				req = qlt_get_req_entries(qlt, 1);
2737c4ddbbe1SDaniel Beauregard 				if (req) {
2738c4ddbbe1SDaniel Beauregard 					bzero(req, IOCB_SIZE);
2739c4ddbbe1SDaniel Beauregard 					req[0] = 0x39; req[1] = 1;
2740c4ddbbe1SDaniel Beauregard 					QMEM_WR16(qlt, req+8, 0x101);
2741c4ddbbe1SDaniel Beauregard 					QMEM_WR16(qlt, req+10, mbox1);
2742c4ddbbe1SDaniel Beauregard 					QMEM_WR16(qlt, req+12, mbox2);
2743c4ddbbe1SDaniel Beauregard 					QMEM_WR16(qlt, req+14, mbox3);
2744c4ddbbe1SDaniel Beauregard 					QMEM_WR16(qlt, req+16, mbox4);
2745c4ddbbe1SDaniel Beauregard 					QMEM_WR16(qlt, req+18, mbox5);
2746c4ddbbe1SDaniel Beauregard 					QMEM_WR16(qlt, req+20, mbox6);
2747c4ddbbe1SDaniel Beauregard 					qlt_submit_req_entries(qlt, 1);
2748c4ddbbe1SDaniel Beauregard 				} else {
2749c4ddbbe1SDaniel Beauregard 					(void) snprintf(info, 80,
2750c4ddbbe1SDaniel Beauregard 					    "IDC ACK failed");
2751c4ddbbe1SDaniel Beauregard 					info[79] = 0;
2752c4ddbbe1SDaniel Beauregard 				}
2753c4ddbbe1SDaniel Beauregard 				mutex_exit(&qlt->req_lock);
2754c4ddbbe1SDaniel Beauregard 			}
2755fcf3ce44SJohn Forte 		}
2756fcf3ce44SJohn Forte 	} else if ((intr_type == 0x10) || (intr_type == 0x11)) {
2757fcf3ce44SJohn Forte 		/* Handle mailbox completion */
2758fcf3ce44SJohn Forte 		mutex_enter(&qlt->mbox_lock);
2759fcf3ce44SJohn Forte 		if (qlt->mbox_io_state != MBOX_STATE_CMD_RUNNING) {
2760fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "qlt(%d): mailbox completion received"
2761fcf3ce44SJohn Forte 			    " when driver wasn't waiting for it %d",
27620ff6bfafSDaniel Beauregard 			    qlt->instance, qlt->mbox_io_state);
2763fcf3ce44SJohn Forte 		} else {
2764fcf3ce44SJohn Forte 			for (i = 0; i < MAX_MBOXES; i++) {
2765fcf3ce44SJohn Forte 				if (qlt->mcp->from_fw_mask &
2766fcf3ce44SJohn Forte 				    (((uint32_t)1) << i)) {
2767fcf3ce44SJohn Forte 					qlt->mcp->from_fw[i] =
2768d8c54e3dSSam Cramer 					    REG_RD16(qlt, REG_MBOX(i));
2769fcf3ce44SJohn Forte 				}
2770fcf3ce44SJohn Forte 			}
2771fcf3ce44SJohn Forte 			qlt->mbox_io_state = MBOX_STATE_CMD_DONE;
2772fcf3ce44SJohn Forte 		}
2773*a2255df3SDaniel Beauregard 		REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
2774fcf3ce44SJohn Forte 		cv_broadcast(&qlt->mbox_cv);
2775fcf3ce44SJohn Forte 		mutex_exit(&qlt->mbox_lock);
2776fcf3ce44SJohn Forte 	} else {
2777fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "qlt(%d): Unknown intr type 0x%x",
27780ff6bfafSDaniel Beauregard 		    qlt->instance, intr_type);
2779*a2255df3SDaniel Beauregard 		REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
2780fcf3ce44SJohn Forte 	}
2781fcf3ce44SJohn Forte 
2782fcf3ce44SJohn Forte 	(void) REG_RD32(qlt, REG_HCCR);	/* PCI Posting */
2783fcf3ce44SJohn Forte 	risc_status = REG_RD32(qlt, REG_RISC_STATUS);
2784fcf3ce44SJohn Forte 	if ((risc_status & BIT_15) &&
2785fcf3ce44SJohn Forte 	    (++intr_loop_count < QLT_MAX_ITERATIONS_PER_INTR)) {
2786fcf3ce44SJohn Forte 		goto intr_again;
2787fcf3ce44SJohn Forte 	}
2788fcf3ce44SJohn Forte 
2789fcf3ce44SJohn Forte 	REG_WR32(qlt, REG_INTR_CTRL, ENABLE_RISC_INTR);
2790fcf3ce44SJohn Forte 
2791fcf3ce44SJohn Forte 	mutex_exit(&qlt->intr_lock);
2792fcf3ce44SJohn Forte 	return (DDI_INTR_CLAIMED);
2793fcf3ce44SJohn Forte }
2794fcf3ce44SJohn Forte 
2795fcf3ce44SJohn Forte /* **************** NVRAM Functions ********************** */
2796fcf3ce44SJohn Forte 
2797fcf3ce44SJohn Forte fct_status_t
2798fcf3ce44SJohn Forte qlt_read_flash_word(qlt_state_t *qlt, uint32_t faddr, uint32_t *bp)
2799fcf3ce44SJohn Forte {
2800fcf3ce44SJohn Forte 	uint32_t	timer;
2801fcf3ce44SJohn Forte 
2802fcf3ce44SJohn Forte 	/* Clear access error flag */
2803fcf3ce44SJohn Forte 	REG_WR32(qlt, REG_CTRL_STATUS,
2804fcf3ce44SJohn Forte 	    REG_RD32(qlt, REG_CTRL_STATUS) | FLASH_ERROR);
2805fcf3ce44SJohn Forte 
2806fcf3ce44SJohn Forte 	REG_WR32(qlt, REG_FLASH_ADDR, faddr & ~BIT_31);
2807fcf3ce44SJohn Forte 
2808fcf3ce44SJohn Forte 	/* Wait for READ cycle to complete. */
2809fcf3ce44SJohn Forte 	for (timer = 3000; timer; timer--) {
2810fcf3ce44SJohn Forte 		if (REG_RD32(qlt, REG_FLASH_ADDR) & BIT_31) {
2811fcf3ce44SJohn Forte 			break;
2812fcf3ce44SJohn Forte 		}
2813fcf3ce44SJohn Forte 		drv_usecwait(10);
2814fcf3ce44SJohn Forte 	}
2815fcf3ce44SJohn Forte 	if (timer == 0) {
2816c4ddbbe1SDaniel Beauregard 		EL(qlt, "flash timeout\n");
2817fcf3ce44SJohn Forte 		return (QLT_FLASH_TIMEOUT);
2818fcf3ce44SJohn Forte 	} else if (REG_RD32(qlt, REG_CTRL_STATUS) & FLASH_ERROR) {
2819c4ddbbe1SDaniel Beauregard 		EL(qlt, "flash access error\n");
2820fcf3ce44SJohn Forte 		return (QLT_FLASH_ACCESS_ERROR);
2821fcf3ce44SJohn Forte 	}
2822fcf3ce44SJohn Forte 
2823fcf3ce44SJohn Forte 	*bp = REG_RD32(qlt, REG_FLASH_DATA);
2824fcf3ce44SJohn Forte 
2825fcf3ce44SJohn Forte 	return (QLT_SUCCESS);
2826fcf3ce44SJohn Forte }
2827fcf3ce44SJohn Forte 
2828fcf3ce44SJohn Forte fct_status_t
2829fcf3ce44SJohn Forte qlt_read_nvram(qlt_state_t *qlt)
2830fcf3ce44SJohn Forte {
2831fcf3ce44SJohn Forte 	uint32_t		index, addr, chksum;
2832fcf3ce44SJohn Forte 	uint32_t		val, *ptr;
2833fcf3ce44SJohn Forte 	fct_status_t		ret;
2834fcf3ce44SJohn Forte 	qlt_nvram_t		*nv;
2835fcf3ce44SJohn Forte 	uint64_t		empty_node_name = 0;
2836fcf3ce44SJohn Forte 
2837c4ddbbe1SDaniel Beauregard 	if (qlt->qlt_81xx_chip) {
2838c4ddbbe1SDaniel Beauregard 		addr = REG_RD32(qlt, REG_CTRL_STATUS) & BIT_12 ?
2839c4ddbbe1SDaniel Beauregard 		    QLT81_NVRAM_FUNC1_ADDR : QLT81_NVRAM_FUNC0_ADDR;
2840c4ddbbe1SDaniel Beauregard 	} else if (qlt->qlt_25xx_chip) {
2841fcf3ce44SJohn Forte 		addr = REG_RD32(qlt, REG_CTRL_STATUS) & FUNCTION_NUMBER ?
2842d8c54e3dSSam Cramer 		    QLT25_NVRAM_FUNC1_ADDR : QLT25_NVRAM_FUNC0_ADDR;
2843fcf3ce44SJohn Forte 	} else {
2844fcf3ce44SJohn Forte 		addr = REG_RD32(qlt, REG_CTRL_STATUS) & FUNCTION_NUMBER ?
2845d8c54e3dSSam Cramer 		    NVRAM_FUNC1_ADDR : NVRAM_FUNC0_ADDR;
2846fcf3ce44SJohn Forte 	}
2847fcf3ce44SJohn Forte 	mutex_enter(&qlt_global_lock);
2848fcf3ce44SJohn Forte 
2849fcf3ce44SJohn Forte 	/* Pause RISC. */
2850*a2255df3SDaniel Beauregard 	REG_WR32(qlt, REG_HCCR, HCCR_CMD(SET_RISC_PAUSE));
2851fcf3ce44SJohn Forte 	(void) REG_RD32(qlt, REG_HCCR);	/* PCI Posting. */
2852fcf3ce44SJohn Forte 
2853fcf3ce44SJohn Forte 	/* Get NVRAM data and calculate checksum. */
2854fcf3ce44SJohn Forte 	ptr = (uint32_t *)qlt->nvram;
2855fcf3ce44SJohn Forte 	chksum = 0;
2856fcf3ce44SJohn Forte 	for (index = 0; index < sizeof (qlt_nvram_t) / 4; index++) {
2857fcf3ce44SJohn Forte 		ret = qlt_read_flash_word(qlt, addr++, &val);
2858fcf3ce44SJohn Forte 		if (ret != QLT_SUCCESS) {
2859c4ddbbe1SDaniel Beauregard 			EL(qlt, "qlt_read_flash_word, status=%llxh\n", ret);
2860fcf3ce44SJohn Forte 			mutex_exit(&qlt_global_lock);
2861fcf3ce44SJohn Forte 			return (ret);
2862fcf3ce44SJohn Forte 		}
2863fcf3ce44SJohn Forte 		chksum += val;
2864fcf3ce44SJohn Forte 		*ptr = LE_32(val);
2865fcf3ce44SJohn Forte 		ptr++;
2866fcf3ce44SJohn Forte 	}
2867fcf3ce44SJohn Forte 
2868fcf3ce44SJohn Forte 	/* Release RISC Pause */
2869*a2255df3SDaniel Beauregard 	REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_PAUSE));
2870fcf3ce44SJohn Forte 	(void) REG_RD32(qlt, REG_HCCR);	/* PCI Posting. */
2871fcf3ce44SJohn Forte 
2872fcf3ce44SJohn Forte 	mutex_exit(&qlt_global_lock);
2873fcf3ce44SJohn Forte 
2874fcf3ce44SJohn Forte 	/* Sanity check NVRAM Data */
2875fcf3ce44SJohn Forte 	nv = qlt->nvram;
2876fcf3ce44SJohn Forte 	if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' ||
2877fcf3ce44SJohn Forte 	    nv->id[2] != 'P' || nv->id[3] != ' ' ||
2878fcf3ce44SJohn Forte 	    (nv->nvram_version[0] | nv->nvram_version[1]) == 0) {
2879c4ddbbe1SDaniel Beauregard 		EL(qlt, "chksum=%xh, id=%c%c%c%c, ver=%02d%02d\n", chksum,
2880c4ddbbe1SDaniel Beauregard 		    nv->id[0], nv->id[1], nv->id[2], nv->id[3],
2881c4ddbbe1SDaniel Beauregard 		    nv->nvram_version[1], nv->nvram_version[0]);
2882fcf3ce44SJohn Forte 		return (QLT_BAD_NVRAM_DATA);
2883fcf3ce44SJohn Forte 	}
2884fcf3ce44SJohn Forte 
2885fcf3ce44SJohn Forte 	/* If node name is zero, hand craft it from port name */
2886fcf3ce44SJohn Forte 	if (bcmp(nv->node_name, &empty_node_name, 8) == 0) {
2887fcf3ce44SJohn Forte 		bcopy(nv->port_name, nv->node_name, 8);
2888c4ddbbe1SDaniel Beauregard 		nv->node_name[0] = (uint8_t)(nv->node_name[0] & ~BIT_0);
2889c4ddbbe1SDaniel Beauregard 		nv->port_name[0] = (uint8_t)(nv->node_name[0] | BIT_0);
2890fcf3ce44SJohn Forte 	}
2891fcf3ce44SJohn Forte 
2892fcf3ce44SJohn Forte 	return (QLT_SUCCESS);
2893fcf3ce44SJohn Forte }
2894fcf3ce44SJohn Forte 
2895fcf3ce44SJohn Forte uint32_t
2896fcf3ce44SJohn Forte qlt_sync_atio_queue(qlt_state_t *qlt)
2897fcf3ce44SJohn Forte {
2898fcf3ce44SJohn Forte 	uint32_t total_ent;
2899fcf3ce44SJohn Forte 
2900fcf3ce44SJohn Forte 	if (qlt->atio_ndx_from_fw > qlt->atio_ndx_to_fw) {
2901fcf3ce44SJohn Forte 		total_ent = qlt->atio_ndx_from_fw - qlt->atio_ndx_to_fw;
2902fcf3ce44SJohn Forte 		(void) ddi_dma_sync(qlt->queue_mem_dma_handle, ATIO_QUEUE_OFFSET
2903fcf3ce44SJohn Forte 		    + (qlt->atio_ndx_to_fw << 6), total_ent << 6,
2904fcf3ce44SJohn Forte 		    DDI_DMA_SYNC_FORCPU);
2905fcf3ce44SJohn Forte 	} else {
2906fcf3ce44SJohn Forte 		total_ent = ATIO_QUEUE_ENTRIES - qlt->atio_ndx_to_fw +
2907d8c54e3dSSam Cramer 		    qlt->atio_ndx_from_fw;
2908fcf3ce44SJohn Forte 		(void) ddi_dma_sync(qlt->queue_mem_dma_handle, ATIO_QUEUE_OFFSET
2909c4ddbbe1SDaniel Beauregard 		    + (qlt->atio_ndx_to_fw << 6), (uint_t)(ATIO_QUEUE_ENTRIES -
2910fcf3ce44SJohn Forte 		    qlt->atio_ndx_to_fw) << 6, DDI_DMA_SYNC_FORCPU);
2911fcf3ce44SJohn Forte 		(void) ddi_dma_sync(qlt->queue_mem_dma_handle,
2912c4ddbbe1SDaniel Beauregard 		    ATIO_QUEUE_OFFSET, (uint_t)(qlt->atio_ndx_from_fw << 6),
2913c4ddbbe1SDaniel Beauregard 		    DDI_DMA_SYNC_FORCPU);
2914fcf3ce44SJohn Forte 	}
2915fcf3ce44SJohn Forte 	return (total_ent);
2916fcf3ce44SJohn Forte }
2917fcf3ce44SJohn Forte 
2918fcf3ce44SJohn Forte void
2919fcf3ce44SJohn Forte qlt_handle_atio_queue_update(qlt_state_t *qlt)
2920fcf3ce44SJohn Forte {
2921fcf3ce44SJohn Forte 	uint32_t total_ent;
2922fcf3ce44SJohn Forte 
2923fcf3ce44SJohn Forte 	if (qlt->atio_ndx_to_fw == qlt->atio_ndx_from_fw)
2924fcf3ce44SJohn Forte 		return;
2925fcf3ce44SJohn Forte 
2926fcf3ce44SJohn Forte 	total_ent = qlt_sync_atio_queue(qlt);
2927fcf3ce44SJohn Forte 
2928fcf3ce44SJohn Forte 	do {
2929fcf3ce44SJohn Forte 		uint8_t *atio = (uint8_t *)&qlt->atio_ptr[
2930d8c54e3dSSam Cramer 		    qlt->atio_ndx_to_fw << 6];
2931fcf3ce44SJohn Forte 		uint32_t ent_cnt;
2932fcf3ce44SJohn Forte 
2933fcf3ce44SJohn Forte 		ent_cnt = (uint32_t)(atio[1]);
2934fcf3ce44SJohn Forte 		if (ent_cnt > total_ent) {
2935fcf3ce44SJohn Forte 			break;
2936fcf3ce44SJohn Forte 		}
2937fcf3ce44SJohn Forte 		switch ((uint8_t)(atio[0])) {
2938fcf3ce44SJohn Forte 		case 0x0d:	/* INOT */
2939fcf3ce44SJohn Forte 			qlt_handle_inot(qlt, atio);
2940fcf3ce44SJohn Forte 			break;
2941fcf3ce44SJohn Forte 		case 0x06:	/* ATIO */
2942fcf3ce44SJohn Forte 			qlt_handle_atio(qlt, atio);
2943fcf3ce44SJohn Forte 			break;
2944fcf3ce44SJohn Forte 		default:
2945c4ddbbe1SDaniel Beauregard 			EL(qlt, "atio_queue_update atio[0]=%xh\n", atio[0]);
2946fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "qlt_handle_atio_queue_update: "
2947fcf3ce44SJohn Forte 			    "atio[0] is %x, qlt-%p", atio[0], (void *)qlt);
2948fcf3ce44SJohn Forte 			break;
2949fcf3ce44SJohn Forte 		}
2950c4ddbbe1SDaniel Beauregard 		qlt->atio_ndx_to_fw = (uint16_t)(
2951c4ddbbe1SDaniel Beauregard 		    (qlt->atio_ndx_to_fw + ent_cnt) & (ATIO_QUEUE_ENTRIES - 1));
2952fcf3ce44SJohn Forte 		total_ent -= ent_cnt;
2953fcf3ce44SJohn Forte 	} while (total_ent > 0);
2954fcf3ce44SJohn Forte 	REG_WR32(qlt, REG_ATIO_OUT_PTR, qlt->atio_ndx_to_fw);
2955fcf3ce44SJohn Forte }
2956fcf3ce44SJohn Forte 
2957fcf3ce44SJohn Forte uint32_t
2958fcf3ce44SJohn Forte qlt_sync_resp_queue(qlt_state_t *qlt)
2959fcf3ce44SJohn Forte {
2960fcf3ce44SJohn Forte 	uint32_t total_ent;
2961fcf3ce44SJohn Forte 
2962fcf3ce44SJohn Forte 	if (qlt->resp_ndx_from_fw > qlt->resp_ndx_to_fw) {
2963fcf3ce44SJohn Forte 		total_ent = qlt->resp_ndx_from_fw - qlt->resp_ndx_to_fw;
2964fcf3ce44SJohn Forte 		(void) ddi_dma_sync(qlt->queue_mem_dma_handle,
2965fcf3ce44SJohn Forte 		    RESPONSE_QUEUE_OFFSET
2966fcf3ce44SJohn Forte 		    + (qlt->resp_ndx_to_fw << 6), total_ent << 6,
2967fcf3ce44SJohn Forte 		    DDI_DMA_SYNC_FORCPU);
2968fcf3ce44SJohn Forte 	} else {
2969fcf3ce44SJohn Forte 		total_ent = RESPONSE_QUEUE_ENTRIES - qlt->resp_ndx_to_fw +
2970d8c54e3dSSam Cramer 		    qlt->resp_ndx_from_fw;
2971fcf3ce44SJohn Forte 		(void) ddi_dma_sync(qlt->queue_mem_dma_handle,
2972fcf3ce44SJohn Forte 		    RESPONSE_QUEUE_OFFSET
2973fcf3ce44SJohn Forte 		    + (qlt->resp_ndx_to_fw << 6), (RESPONSE_QUEUE_ENTRIES -
2974fcf3ce44SJohn Forte 		    qlt->resp_ndx_to_fw) << 6, DDI_DMA_SYNC_FORCPU);
2975fcf3ce44SJohn Forte 		(void) ddi_dma_sync(qlt->queue_mem_dma_handle,
2976fcf3ce44SJohn Forte 		    RESPONSE_QUEUE_OFFSET,
2977fcf3ce44SJohn Forte 		    qlt->resp_ndx_from_fw << 6, DDI_DMA_SYNC_FORCPU);
2978fcf3ce44SJohn Forte 	}
2979fcf3ce44SJohn Forte 	return (total_ent);
2980fcf3ce44SJohn Forte }
2981fcf3ce44SJohn Forte 
2982fcf3ce44SJohn Forte void
2983fcf3ce44SJohn Forte qlt_handle_resp_queue_update(qlt_state_t *qlt)
2984fcf3ce44SJohn Forte {
2985fcf3ce44SJohn Forte 	uint32_t total_ent;
2986fcf3ce44SJohn Forte 	uint8_t c;
2987fcf3ce44SJohn Forte 
2988fcf3ce44SJohn Forte 	if (qlt->resp_ndx_to_fw == qlt->resp_ndx_from_fw)
2989fcf3ce44SJohn Forte 		return;
2990fcf3ce44SJohn Forte 
2991fcf3ce44SJohn Forte 	total_ent = qlt_sync_resp_queue(qlt);
2992fcf3ce44SJohn Forte 
2993fcf3ce44SJohn Forte 	do {
2994fcf3ce44SJohn Forte 		caddr_t resp = &qlt->resp_ptr[qlt->resp_ndx_to_fw << 6];
2995fcf3ce44SJohn Forte 		uint32_t ent_cnt;
2996fcf3ce44SJohn Forte 
2997fcf3ce44SJohn Forte 		ent_cnt = (uint32_t)(resp[1]);
2998fcf3ce44SJohn Forte 		if (ent_cnt > total_ent) {
2999fcf3ce44SJohn Forte 			break;
3000fcf3ce44SJohn Forte 		}
3001fcf3ce44SJohn Forte 		switch ((uint8_t)(resp[0])) {
3002fcf3ce44SJohn Forte 		case 0x12:	/* CTIO completion */
3003fcf3ce44SJohn Forte 			qlt_handle_ctio_completion(qlt, (uint8_t *)resp);
3004fcf3ce44SJohn Forte 			break;
3005fcf3ce44SJohn Forte 		case 0x0e:	/* NACK */
3006fcf3ce44SJohn Forte 			/* Do Nothing */
3007fcf3ce44SJohn Forte 			break;
3008c4ddbbe1SDaniel Beauregard 		case 0x1b:	/* Verify FW */
3009c4ddbbe1SDaniel Beauregard 			qlt_handle_verify_fw_completion(qlt, (uint8_t *)resp);
3010c4ddbbe1SDaniel Beauregard 			break;
3011fcf3ce44SJohn Forte 		case 0x29:	/* CT PassThrough */
3012fcf3ce44SJohn Forte 			qlt_handle_ct_completion(qlt, (uint8_t *)resp);
3013fcf3ce44SJohn Forte 			break;
3014fcf3ce44SJohn Forte 		case 0x33:	/* Abort IO IOCB completion */
3015fcf3ce44SJohn Forte 			qlt_handle_sol_abort_completion(qlt, (uint8_t *)resp);
3016fcf3ce44SJohn Forte 			break;
3017fcf3ce44SJohn Forte 		case 0x51:	/* PUREX */
3018fcf3ce44SJohn Forte 			qlt_handle_purex(qlt, (uint8_t *)resp);
3019fcf3ce44SJohn Forte 			break;
3020fcf3ce44SJohn Forte 		case 0x52:
3021fcf3ce44SJohn Forte 			qlt_handle_dereg_completion(qlt, (uint8_t *)resp);
3022fcf3ce44SJohn Forte 			break;
3023fcf3ce44SJohn Forte 		case 0x53:	/* ELS passthrough */
3024c4ddbbe1SDaniel Beauregard 			c = (uint8_t)(((uint8_t)resp[0x1f]) >> 5);
3025fcf3ce44SJohn Forte 			if (c == 0) {
3026fcf3ce44SJohn Forte 				qlt_handle_sol_els_completion(qlt,
3027fcf3ce44SJohn Forte 				    (uint8_t *)resp);
3028fcf3ce44SJohn Forte 			} else if (c == 3) {
3029fcf3ce44SJohn Forte 				qlt_handle_unsol_els_abort_completion(qlt,
3030fcf3ce44SJohn Forte 				    (uint8_t *)resp);
3031fcf3ce44SJohn Forte 			} else {
3032fcf3ce44SJohn Forte 				qlt_handle_unsol_els_completion(qlt,
3033fcf3ce44SJohn Forte 				    (uint8_t *)resp);
3034fcf3ce44SJohn Forte 			}
3035fcf3ce44SJohn Forte 			break;
3036fcf3ce44SJohn Forte 		case 0x54:	/* ABTS received */
3037fcf3ce44SJohn Forte 			qlt_handle_rcvd_abts(qlt, (uint8_t *)resp);
3038fcf3ce44SJohn Forte 			break;
3039fcf3ce44SJohn Forte 		case 0x55:	/* ABTS completion */
3040fcf3ce44SJohn Forte 			qlt_handle_abts_completion(qlt, (uint8_t *)resp);
3041fcf3ce44SJohn Forte 			break;
3042c4ddbbe1SDaniel Beauregard 		default:
3043c4ddbbe1SDaniel Beauregard 			EL(qlt, "response entry=%xh\n", resp[0]);
3044c4ddbbe1SDaniel Beauregard 			break;
3045fcf3ce44SJohn Forte 		}
3046fcf3ce44SJohn Forte 		qlt->resp_ndx_to_fw = (qlt->resp_ndx_to_fw + ent_cnt) &
3047d8c54e3dSSam Cramer 		    (RESPONSE_QUEUE_ENTRIES - 1);
3048fcf3ce44SJohn Forte 		total_ent -= ent_cnt;
3049fcf3ce44SJohn Forte 	} while (total_ent > 0);
3050fcf3ce44SJohn Forte 	REG_WR32(qlt, REG_RESP_OUT_PTR, qlt->resp_ndx_to_fw);
3051fcf3ce44SJohn Forte }
3052fcf3ce44SJohn Forte 
3053fcf3ce44SJohn Forte fct_status_t
3054fcf3ce44SJohn Forte qlt_portid_to_handle(qlt_state_t *qlt, uint32_t id, uint16_t cmd_handle,
3055fcf3ce44SJohn Forte 				uint16_t *ret_handle)
3056fcf3ce44SJohn Forte {
3057fcf3ce44SJohn Forte 	fct_status_t ret;
3058fcf3ce44SJohn Forte 	mbox_cmd_t *mcp;
3059fcf3ce44SJohn Forte 	uint16_t n;
3060fcf3ce44SJohn Forte 	uint16_t h;
3061fcf3ce44SJohn Forte 	uint32_t ent_id;
3062fcf3ce44SJohn Forte 	uint8_t *p;
3063fcf3ce44SJohn Forte 	int found = 0;
3064fcf3ce44SJohn Forte 
3065fcf3ce44SJohn Forte 	mcp = qlt_alloc_mailbox_command(qlt, 2048 * 8);
3066fcf3ce44SJohn Forte 	if (mcp == NULL) {
3067fcf3ce44SJohn Forte 		return (STMF_ALLOC_FAILURE);
3068fcf3ce44SJohn Forte 	}
3069*a2255df3SDaniel Beauregard 	mcp->to_fw[0] = MBC_GET_ID_LIST;
3070fcf3ce44SJohn Forte 	mcp->to_fw[8] = 2048 * 8;
3071c4ddbbe1SDaniel Beauregard 	mcp->to_fw[9] = 0;
3072c4ddbbe1SDaniel Beauregard 	mcp->to_fw_mask |= BIT_9 | BIT_8;
3073fcf3ce44SJohn Forte 	mcp->from_fw_mask |= BIT_1 | BIT_2;
3074fcf3ce44SJohn Forte 
3075fcf3ce44SJohn Forte 	ret = qlt_mailbox_command(qlt, mcp);
3076fcf3ce44SJohn Forte 	if (ret != QLT_SUCCESS) {
3077c4ddbbe1SDaniel Beauregard 		EL(qlt, "qlt_mailbox_command=7Ch status=%llxh\n", ret);
3078fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "GET ID list failed, ret = %llx, mb0=%x, "
3079fcf3ce44SJohn Forte 		    "mb1=%x, mb2=%x", (long long)ret, mcp->from_fw[0],
3080fcf3ce44SJohn Forte 		    mcp->from_fw[1], mcp->from_fw[2]);
3081fcf3ce44SJohn Forte 		qlt_free_mailbox_command(qlt, mcp);
3082fcf3ce44SJohn Forte 		return (ret);
3083fcf3ce44SJohn Forte 	}
3084fcf3ce44SJohn Forte 	qlt_dmem_dma_sync(mcp->dbuf, DDI_DMA_SYNC_FORCPU);
3085fcf3ce44SJohn Forte 	p = mcp->dbuf->db_sglist[0].seg_addr;
3086fcf3ce44SJohn Forte 	for (n = 0; n < mcp->from_fw[1]; n++) {
3087fcf3ce44SJohn Forte 		ent_id = LE_32(*((uint32_t *)p)) & 0xFFFFFF;
3088c4ddbbe1SDaniel Beauregard 		h = (uint16_t)((uint16_t)p[4] | (((uint16_t)p[5]) << 8));
3089fcf3ce44SJohn Forte 		if (ent_id == id) {
3090fcf3ce44SJohn Forte 			found = 1;
3091fcf3ce44SJohn Forte 			*ret_handle = h;
3092fcf3ce44SJohn Forte 			if ((cmd_handle != FCT_HANDLE_NONE) &&
3093fcf3ce44SJohn Forte 			    (cmd_handle != h)) {
3094fcf3ce44SJohn Forte 				cmn_err(CE_WARN, "login for portid %x came in "
3095fcf3ce44SJohn Forte 				    "with handle %x, while the portid was "
3096fcf3ce44SJohn Forte 				    "already using a different handle %x",
3097d8c54e3dSSam Cramer 				    id, cmd_handle, h);
3098fcf3ce44SJohn Forte 				qlt_free_mailbox_command(qlt, mcp);
3099fcf3ce44SJohn Forte 				return (QLT_FAILURE);
3100fcf3ce44SJohn Forte 			}
3101fcf3ce44SJohn Forte 			break;
3102fcf3ce44SJohn Forte 		}
3103fcf3ce44SJohn Forte 		if ((cmd_handle != FCT_HANDLE_NONE) && (h == cmd_handle)) {
3104fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "login for portid %x came in with "
3105fcf3ce44SJohn Forte 			    "handle %x, while the handle was already in use "
3106fcf3ce44SJohn Forte 			    "for portid %x", id, cmd_handle, ent_id);
3107fcf3ce44SJohn Forte 			qlt_free_mailbox_command(qlt, mcp);
3108fcf3ce44SJohn Forte 			return (QLT_FAILURE);
3109fcf3ce44SJohn Forte 		}
3110fcf3ce44SJohn Forte 		p += 8;
3111fcf3ce44SJohn Forte 	}
3112fcf3ce44SJohn Forte 	if (!found) {
3113fcf3ce44SJohn Forte 		*ret_handle = cmd_handle;
3114fcf3ce44SJohn Forte 	}
3115fcf3ce44SJohn Forte 	qlt_free_mailbox_command(qlt, mcp);
3116fcf3ce44SJohn Forte 	return (FCT_SUCCESS);
3117fcf3ce44SJohn Forte }
3118fcf3ce44SJohn Forte 
3119fcf3ce44SJohn Forte /* ARGSUSED */
3120fcf3ce44SJohn Forte fct_status_t
3121fcf3ce44SJohn Forte qlt_fill_plogi_req(fct_local_port_t *port, fct_remote_port_t *rp,
3122fcf3ce44SJohn Forte 				fct_cmd_t *login)
3123fcf3ce44SJohn Forte {
3124fcf3ce44SJohn Forte 	uint8_t *p;
3125fcf3ce44SJohn Forte 
3126fcf3ce44SJohn Forte 	p = ((fct_els_t *)login->cmd_specific)->els_req_payload;
3127fcf3ce44SJohn Forte 	p[0] = ELS_OP_PLOGI;
3128fcf3ce44SJohn Forte 	*((uint16_t *)(&p[4])) = 0x2020;
3129fcf3ce44SJohn Forte 	p[7] = 3;
3130fcf3ce44SJohn Forte 	p[8] = 0x88;
3131fcf3ce44SJohn Forte 	p[10] = 8;
3132fcf3ce44SJohn Forte 	p[13] = 0xff; p[15] = 0x1f;
3133fcf3ce44SJohn Forte 	p[18] = 7; p[19] = 0xd0;
3134fcf3ce44SJohn Forte 
3135fcf3ce44SJohn Forte 	bcopy(port->port_pwwn, p + 20, 8);
3136fcf3ce44SJohn Forte 	bcopy(port->port_nwwn, p + 28, 8);
3137fcf3ce44SJohn Forte 
3138fcf3ce44SJohn Forte 	p[68] = 0x80;
3139fcf3ce44SJohn Forte 	p[74] = 8;
3140fcf3ce44SJohn Forte 	p[77] = 0xff;
3141fcf3ce44SJohn Forte 	p[81] = 1;
3142fcf3ce44SJohn Forte 
3143fcf3ce44SJohn Forte 	return (FCT_SUCCESS);
3144fcf3ce44SJohn Forte }
3145fcf3ce44SJohn Forte 
3146fcf3ce44SJohn Forte /* ARGSUSED */
3147fcf3ce44SJohn Forte fct_status_t
3148fcf3ce44SJohn Forte qlt_fill_plogi_resp(fct_local_port_t *port, fct_remote_port_t *rp,
3149fcf3ce44SJohn Forte 				fct_cmd_t *login)
3150fcf3ce44SJohn Forte {
3151fcf3ce44SJohn Forte 	return (FCT_SUCCESS);
3152fcf3ce44SJohn Forte }
3153fcf3ce44SJohn Forte 
3154fcf3ce44SJohn Forte fct_status_t
3155fcf3ce44SJohn Forte qlt_register_remote_port(fct_local_port_t *port, fct_remote_port_t *rp,
3156c4ddbbe1SDaniel Beauregard     fct_cmd_t *login)
3157fcf3ce44SJohn Forte {
3158fcf3ce44SJohn Forte 	uint16_t h;
3159fcf3ce44SJohn Forte 	fct_status_t ret;
3160c4ddbbe1SDaniel Beauregard 	qlt_state_t *qlt = (qlt_state_t *)port->port_fca_private;
3161fcf3ce44SJohn Forte 
3162fcf3ce44SJohn Forte 	switch (rp->rp_id) {
3163fcf3ce44SJohn Forte 	case 0xFFFFFC:	h = 0x7FC; break;
3164fcf3ce44SJohn Forte 	case 0xFFFFFD:	h = 0x7FD; break;
3165fcf3ce44SJohn Forte 	case 0xFFFFFE:	h = 0x7FE; break;
3166fcf3ce44SJohn Forte 	case 0xFFFFFF:	h = 0x7FF; break;
3167fcf3ce44SJohn Forte 	default:
3168c4ddbbe1SDaniel Beauregard 		ret = qlt_portid_to_handle(qlt, rp->rp_id,
3169d8c54e3dSSam Cramer 		    login->cmd_rp_handle, &h);
3170c4ddbbe1SDaniel Beauregard 		if (ret != FCT_SUCCESS) {
3171c4ddbbe1SDaniel Beauregard 			EL(qlt, "qlt_portid_to_handle, status=%llxh\n", ret);
3172fcf3ce44SJohn Forte 			return (ret);
3173c4ddbbe1SDaniel Beauregard 		}
3174fcf3ce44SJohn Forte 	}
3175fcf3ce44SJohn Forte 
3176fcf3ce44SJohn Forte 	if (login->cmd_type == FCT_CMD_SOL_ELS) {
3177fcf3ce44SJohn Forte 		ret = qlt_fill_plogi_req(port, rp, login);
3178fcf3ce44SJohn Forte 	} else {
3179fcf3ce44SJohn Forte 		ret = qlt_fill_plogi_resp(port, rp, login);
3180fcf3ce44SJohn Forte 	}
3181fcf3ce44SJohn Forte 
3182c4ddbbe1SDaniel Beauregard 	if (ret != FCT_SUCCESS) {
3183c4ddbbe1SDaniel Beauregard 		EL(qlt, "qlt_fill_plogi, status=%llxh\n", ret);
3184fcf3ce44SJohn Forte 		return (ret);
3185c4ddbbe1SDaniel Beauregard 	}
3186fcf3ce44SJohn Forte 
3187fcf3ce44SJohn Forte 	if (h == FCT_HANDLE_NONE)
3188fcf3ce44SJohn Forte 		return (FCT_SUCCESS);
3189fcf3ce44SJohn Forte 
3190fcf3ce44SJohn Forte 	if (rp->rp_handle == FCT_HANDLE_NONE) {
3191fcf3ce44SJohn Forte 		rp->rp_handle = h;
3192fcf3ce44SJohn Forte 		return (FCT_SUCCESS);
3193fcf3ce44SJohn Forte 	}
3194fcf3ce44SJohn Forte 
3195fcf3ce44SJohn Forte 	if (rp->rp_handle == h)
3196fcf3ce44SJohn Forte 		return (FCT_SUCCESS);
3197fcf3ce44SJohn Forte 
3198c4ddbbe1SDaniel Beauregard 	EL(qlt, "rp_handle=%xh != h=%xh\n", rp->rp_handle, h);
3199fcf3ce44SJohn Forte 	return (FCT_FAILURE);
3200fcf3ce44SJohn Forte }
3201fcf3ce44SJohn Forte /* invoked in single thread */
3202fcf3ce44SJohn Forte fct_status_t
3203fcf3ce44SJohn Forte qlt_deregister_remote_port(fct_local_port_t *port, fct_remote_port_t *rp)
3204fcf3ce44SJohn Forte {
3205fcf3ce44SJohn Forte 	uint8_t *req;
3206fcf3ce44SJohn Forte 	qlt_state_t *qlt;
3207fcf3ce44SJohn Forte 	clock_t	dereg_req_timer;
3208fcf3ce44SJohn Forte 	fct_status_t ret;
3209fcf3ce44SJohn Forte 
3210fcf3ce44SJohn Forte 	qlt = (qlt_state_t *)port->port_fca_private;
3211fcf3ce44SJohn Forte 
3212fcf3ce44SJohn Forte 	if ((qlt->qlt_state == FCT_STATE_OFFLINE) ||
3213fcf3ce44SJohn Forte 	    (qlt->qlt_state == FCT_STATE_OFFLINING))
3214fcf3ce44SJohn Forte 		return (FCT_SUCCESS);
3215fcf3ce44SJohn Forte 	ASSERT(qlt->rp_id_in_dereg == 0);
3216fcf3ce44SJohn Forte 
3217fcf3ce44SJohn Forte 	mutex_enter(&qlt->preq_lock);
3218fcf3ce44SJohn Forte 	req = (uint8_t *)qlt_get_preq_entries(qlt, 1);
3219fcf3ce44SJohn Forte 	if (req == NULL) {
3220fcf3ce44SJohn Forte 		mutex_exit(&qlt->preq_lock);
3221fcf3ce44SJohn Forte 		return (FCT_BUSY);
3222fcf3ce44SJohn Forte 	}
3223fcf3ce44SJohn Forte 	bzero(req, IOCB_SIZE);
3224fcf3ce44SJohn Forte 	req[0] = 0x52; req[1] = 1;
3225fcf3ce44SJohn Forte 	/* QMEM_WR32(qlt, (&req[4]), 0xffffffff);  */
3226fcf3ce44SJohn Forte 	QMEM_WR16(qlt, (&req[0xA]), rp->rp_handle);
3227fcf3ce44SJohn Forte 	QMEM_WR16(qlt, (&req[0xC]), 0x98); /* implicit logo */
3228fcf3ce44SJohn Forte 	QMEM_WR32(qlt, (&req[0x10]), rp->rp_id);
3229fcf3ce44SJohn Forte 	qlt->rp_id_in_dereg = rp->rp_id;
3230fcf3ce44SJohn Forte 	qlt_submit_preq_entries(qlt, 1);
3231fcf3ce44SJohn Forte 
3232*a2255df3SDaniel Beauregard 	dereg_req_timer = ddi_get_lbolt() + drv_usectohz(DEREG_RP_TIMEOUT);
3233*a2255df3SDaniel Beauregard 	if (cv_timedwait(&qlt->rp_dereg_cv,
3234*a2255df3SDaniel Beauregard 	    &qlt->preq_lock, dereg_req_timer) > 0) {
3235fcf3ce44SJohn Forte 		ret = qlt->rp_dereg_status;
3236fcf3ce44SJohn Forte 	} else {
3237fcf3ce44SJohn Forte 		ret = FCT_BUSY;
3238fcf3ce44SJohn Forte 	}
3239fcf3ce44SJohn Forte 	qlt->rp_dereg_status = 0;
3240fcf3ce44SJohn Forte 	qlt->rp_id_in_dereg = 0;
3241fcf3ce44SJohn Forte 	mutex_exit(&qlt->preq_lock);
3242fcf3ce44SJohn Forte 	return (ret);
3243fcf3ce44SJohn Forte }
3244fcf3ce44SJohn Forte 
3245fcf3ce44SJohn Forte /*
3246fcf3ce44SJohn Forte  * Pass received ELS up to framework.
3247fcf3ce44SJohn Forte  */
3248fcf3ce44SJohn Forte static void
3249fcf3ce44SJohn Forte qlt_handle_purex(qlt_state_t *qlt, uint8_t *resp)
3250fcf3ce44SJohn Forte {
3251fcf3ce44SJohn Forte 	fct_cmd_t		*cmd;
3252fcf3ce44SJohn Forte 	fct_els_t		*els;
3253fcf3ce44SJohn Forte 	qlt_cmd_t		*qcmd;
3254fcf3ce44SJohn Forte 	uint32_t		payload_size;
3255fcf3ce44SJohn Forte 	uint32_t		remote_portid;
3256fcf3ce44SJohn Forte 	uint8_t			*pldptr, *bndrptr;
3257fcf3ce44SJohn Forte 	int			i, off;
3258fcf3ce44SJohn Forte 	uint16_t		iocb_flags;
3259fcf3ce44SJohn Forte 	char			info[160];
3260fcf3ce44SJohn Forte 
3261fcf3ce44SJohn Forte 	remote_portid = ((uint32_t)(QMEM_RD16(qlt, (&resp[0x18])))) |
3262fcf3ce44SJohn Forte 	    ((uint32_t)(resp[0x1A])) << 16;
3263fcf3ce44SJohn Forte 	iocb_flags = QMEM_RD16(qlt, (&resp[8]));
3264fcf3ce44SJohn Forte 	if (iocb_flags & BIT_15) {
3265fcf3ce44SJohn Forte 		payload_size = (QMEM_RD16(qlt, (&resp[0x0e])) & 0xfff) - 24;
3266fcf3ce44SJohn Forte 	} else {
3267fcf3ce44SJohn Forte 		payload_size = QMEM_RD16(qlt, (&resp[0x0c])) - 24;
3268fcf3ce44SJohn Forte 	}
3269fcf3ce44SJohn Forte 
3270fcf3ce44SJohn Forte 	if (payload_size > ((uint32_t)resp[1] * IOCB_SIZE - 0x2C)) {
3271c4ddbbe1SDaniel Beauregard 		EL(qlt, "payload is too large = %xh\n", payload_size);
3272fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "handle_purex: payload is too large");
3273fcf3ce44SJohn Forte 		goto cmd_null;
3274fcf3ce44SJohn Forte 	}
3275fcf3ce44SJohn Forte 
3276c4ddbbe1SDaniel Beauregard 	cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_RCVD_ELS,
3277c4ddbbe1SDaniel Beauregard 	    (int)(payload_size + GET_STRUCT_SIZE(qlt_cmd_t)), 0);
3278fcf3ce44SJohn Forte 	if (cmd == NULL) {
3279c4ddbbe1SDaniel Beauregard 		EL(qlt, "fct_alloc cmd==NULL\n");
3280fcf3ce44SJohn Forte cmd_null:;
3281fcf3ce44SJohn Forte 		(void) snprintf(info, 160, "qlt_handle_purex: qlt-%p, can't "
3282fcf3ce44SJohn Forte 		    "allocate space for fct_cmd", (void *)qlt);
3283fcf3ce44SJohn Forte 		info[159] = 0;
3284fcf3ce44SJohn Forte 		(void) fct_port_shutdown(qlt->qlt_port,
3285fcf3ce44SJohn Forte 		    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
3286fcf3ce44SJohn Forte 		return;
3287fcf3ce44SJohn Forte 	}
3288fcf3ce44SJohn Forte 
3289fcf3ce44SJohn Forte 	cmd->cmd_port = qlt->qlt_port;
3290fcf3ce44SJohn Forte 	cmd->cmd_rp_handle = QMEM_RD16(qlt, resp+0xa);
3291fcf3ce44SJohn Forte 	if (cmd->cmd_rp_handle == 0xFFFF) {
3292fcf3ce44SJohn Forte 		cmd->cmd_rp_handle = FCT_HANDLE_NONE;
3293fcf3ce44SJohn Forte 	}
3294fcf3ce44SJohn Forte 
3295fcf3ce44SJohn Forte 	els = (fct_els_t *)cmd->cmd_specific;
3296fcf3ce44SJohn Forte 	qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
3297c4ddbbe1SDaniel Beauregard 	els->els_req_size = (uint16_t)payload_size;
3298fcf3ce44SJohn Forte 	els->els_req_payload = GET_BYTE_OFFSET(qcmd,
3299fcf3ce44SJohn Forte 	    GET_STRUCT_SIZE(qlt_cmd_t));
3300fcf3ce44SJohn Forte 	qcmd->fw_xchg_addr = QMEM_RD32(qlt, (&resp[0x10]));
3301fcf3ce44SJohn Forte 	cmd->cmd_rportid = remote_portid;
3302fcf3ce44SJohn Forte 	cmd->cmd_lportid = ((uint32_t)(QMEM_RD16(qlt, (&resp[0x14])))) |
3303fcf3ce44SJohn Forte 	    ((uint32_t)(resp[0x16])) << 16;
3304fcf3ce44SJohn Forte 	cmd->cmd_oxid = QMEM_RD16(qlt, (&resp[0x26]));
3305fcf3ce44SJohn Forte 	cmd->cmd_rxid = QMEM_RD16(qlt, (&resp[0x24]));
3306fcf3ce44SJohn Forte 	pldptr = &resp[0x2C];
3307fcf3ce44SJohn Forte 	bndrptr = (uint8_t *)(qlt->resp_ptr + (RESPONSE_QUEUE_ENTRIES << 6));
3308fcf3ce44SJohn Forte 	for (i = 0, off = 0x2c; i < payload_size; i += 4) {
3309fcf3ce44SJohn Forte 		/* Take care of fw's swapping of payload */
3310fcf3ce44SJohn Forte 		els->els_req_payload[i] = pldptr[3];
3311fcf3ce44SJohn Forte 		els->els_req_payload[i+1] = pldptr[2];
3312fcf3ce44SJohn Forte 		els->els_req_payload[i+2] = pldptr[1];
3313fcf3ce44SJohn Forte 		els->els_req_payload[i+3] = pldptr[0];
3314fcf3ce44SJohn Forte 		pldptr += 4;
3315fcf3ce44SJohn Forte 		if (pldptr == bndrptr)
3316fcf3ce44SJohn Forte 			pldptr = (uint8_t *)qlt->resp_ptr;
3317fcf3ce44SJohn Forte 		off += 4;
3318fcf3ce44SJohn Forte 		if (off >= IOCB_SIZE) {
3319fcf3ce44SJohn Forte 			off = 4;
3320fcf3ce44SJohn Forte 			pldptr += 4;
3321fcf3ce44SJohn Forte 		}
3322fcf3ce44SJohn Forte 	}
3323fcf3ce44SJohn Forte 	fct_post_rcvd_cmd(cmd, 0);
3324fcf3ce44SJohn Forte }
3325fcf3ce44SJohn Forte 
3326fcf3ce44SJohn Forte fct_status_t
3327fcf3ce44SJohn Forte qlt_send_cmd_response(fct_cmd_t *cmd, uint32_t ioflags)
3328fcf3ce44SJohn Forte {
3329fcf3ce44SJohn Forte 	qlt_state_t	*qlt;
3330fcf3ce44SJohn Forte 	char		info[160];
3331fcf3ce44SJohn Forte 
3332fcf3ce44SJohn Forte 	qlt = (qlt_state_t *)cmd->cmd_port->port_fca_private;
3333fcf3ce44SJohn Forte 
3334fcf3ce44SJohn Forte 	if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
3335fcf3ce44SJohn Forte 		if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
3336c4ddbbe1SDaniel Beauregard 			EL(qlt, "ioflags = %xh\n", ioflags);
3337fcf3ce44SJohn Forte 			goto fatal_panic;
3338fcf3ce44SJohn Forte 		} else {
3339fcf3ce44SJohn Forte 			return (qlt_send_status(qlt, cmd));
3340fcf3ce44SJohn Forte 		}
3341fcf3ce44SJohn Forte 	}
3342fcf3ce44SJohn Forte 
3343fcf3ce44SJohn Forte 	if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
3344fcf3ce44SJohn Forte 		if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
3345fcf3ce44SJohn Forte 			goto fatal_panic;
3346fcf3ce44SJohn Forte 		} else {
3347fcf3ce44SJohn Forte 			return (qlt_send_els_response(qlt, cmd));
3348fcf3ce44SJohn Forte 		}
3349fcf3ce44SJohn Forte 	}
3350fcf3ce44SJohn Forte 
3351fcf3ce44SJohn Forte 	if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
3352fcf3ce44SJohn Forte 		cmd->cmd_handle = 0;
3353fcf3ce44SJohn Forte 	}
3354fcf3ce44SJohn Forte 
3355fcf3ce44SJohn Forte 	if (cmd->cmd_type == FCT_CMD_RCVD_ABTS) {
3356fcf3ce44SJohn Forte 		return (qlt_send_abts_response(qlt, cmd, 0));
3357fcf3ce44SJohn Forte 	} else {
3358c4ddbbe1SDaniel Beauregard 		EL(qlt, "cmd->cmd_type=%xh\n", cmd->cmd_type);
3359fcf3ce44SJohn Forte 		ASSERT(0);
3360fcf3ce44SJohn Forte 		return (FCT_FAILURE);
3361fcf3ce44SJohn Forte 	}
3362fcf3ce44SJohn Forte 
3363fcf3ce44SJohn Forte fatal_panic:;
3364fcf3ce44SJohn Forte 	(void) snprintf(info, 160, "qlt_send_cmd_response: can not handle "
3365fcf3ce44SJohn Forte 	    "FCT_IOF_FORCE_FCA_DONE for cmd %p, ioflags-%x", (void *)cmd,
3366fcf3ce44SJohn Forte 	    ioflags);
3367fcf3ce44SJohn Forte 	info[159] = 0;
3368fcf3ce44SJohn Forte 	(void) fct_port_shutdown(qlt->qlt_port,
3369fcf3ce44SJohn Forte 	    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
3370fcf3ce44SJohn Forte 	return (FCT_FAILURE);
3371fcf3ce44SJohn Forte }
3372fcf3ce44SJohn Forte 
3373fcf3ce44SJohn Forte /* ARGSUSED */
3374fcf3ce44SJohn Forte fct_status_t
3375fcf3ce44SJohn Forte qlt_xfer_scsi_data(fct_cmd_t *cmd, stmf_data_buf_t *dbuf, uint32_t ioflags)
3376fcf3ce44SJohn Forte {
3377fcf3ce44SJohn Forte 	qlt_dmem_bctl_t *bctl = (qlt_dmem_bctl_t *)dbuf->db_port_private;
3378fcf3ce44SJohn Forte 	qlt_state_t *qlt = (qlt_state_t *)cmd->cmd_port->port_fca_private;
3379fcf3ce44SJohn Forte 	qlt_cmd_t *qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
3380fcf3ce44SJohn Forte 	uint8_t *req;
3381fcf3ce44SJohn Forte 	uint16_t flags;
3382fcf3ce44SJohn Forte 
3383fcf3ce44SJohn Forte 	if (dbuf->db_handle == 0)
3384fcf3ce44SJohn Forte 		qcmd->dbuf = dbuf;
3385c4ddbbe1SDaniel Beauregard 	flags = (uint16_t)(((uint16_t)qcmd->param.atio_byte3 & 0xf0) << 5);
3386fcf3ce44SJohn Forte 	if (dbuf->db_flags & DB_DIRECTION_TO_RPORT) {
3387c4ddbbe1SDaniel Beauregard 		flags = (uint16_t)(flags | 2);
3388fcf3ce44SJohn Forte 		qlt_dmem_dma_sync(dbuf, DDI_DMA_SYNC_FORDEV);
3389fcf3ce44SJohn Forte 	} else {
3390c4ddbbe1SDaniel Beauregard 		flags = (uint16_t)(flags | 1);
3391fcf3ce44SJohn Forte 	}
3392fcf3ce44SJohn Forte 
3393fcf3ce44SJohn Forte 	if (dbuf->db_flags & DB_SEND_STATUS_GOOD)
3394c4ddbbe1SDaniel Beauregard 		flags = (uint16_t)(flags | BIT_15);
3395fcf3ce44SJohn Forte 
3396fcf3ce44SJohn Forte 	mutex_enter(&qlt->req_lock);
3397fcf3ce44SJohn Forte 	req = (uint8_t *)qlt_get_req_entries(qlt, 1);
3398fcf3ce44SJohn Forte 	if (req == NULL) {
3399fcf3ce44SJohn Forte 		mutex_exit(&qlt->req_lock);
3400fcf3ce44SJohn Forte 		return (FCT_BUSY);
3401fcf3ce44SJohn Forte 	}
3402fcf3ce44SJohn Forte 	bzero(req, IOCB_SIZE);
3403fcf3ce44SJohn Forte 	req[0] = 0x12; req[1] = 0x1;
3404fcf3ce44SJohn Forte 	req[2] = dbuf->db_handle;
3405fcf3ce44SJohn Forte 	QMEM_WR32(qlt, req+4, cmd->cmd_handle);
3406fcf3ce44SJohn Forte 	QMEM_WR16(qlt, req+8, cmd->cmd_rp->rp_handle);
3407fcf3ce44SJohn Forte 	QMEM_WR16(qlt, req+10, 60);	/* 60 seconds timeout */
3408fcf3ce44SJohn Forte 	req[12] = 1;
3409fcf3ce44SJohn Forte 	QMEM_WR32(qlt, req+0x10, cmd->cmd_rportid);
3410fcf3ce44SJohn Forte 	QMEM_WR32(qlt, req+0x14, qcmd->fw_xchg_addr);
3411fcf3ce44SJohn Forte 	QMEM_WR16(qlt, req+0x1A, flags);
3412fcf3ce44SJohn Forte 	QMEM_WR16(qlt, req+0x20, cmd->cmd_oxid);
3413fcf3ce44SJohn Forte 	QMEM_WR32(qlt, req+0x24, dbuf->db_relative_offset);
3414fcf3ce44SJohn Forte 	QMEM_WR32(qlt, req+0x2C, dbuf->db_data_size);
3415fcf3ce44SJohn Forte 	QMEM_WR64(qlt, req+0x34, bctl->bctl_dev_addr);
3416fcf3ce44SJohn Forte 	QMEM_WR32(qlt, req+0x34+8, dbuf->db_data_size);
3417fcf3ce44SJohn Forte 	qlt_submit_req_entries(qlt, 1);
3418fcf3ce44SJohn Forte 	mutex_exit(&qlt->req_lock);
3419fcf3ce44SJohn Forte 
3420fcf3ce44SJohn Forte 	return (STMF_SUCCESS);
3421fcf3ce44SJohn Forte }
3422fcf3ce44SJohn Forte 
3423fcf3ce44SJohn Forte /*
3424fcf3ce44SJohn Forte  * We must construct proper FCP_RSP_IU now. Here we only focus on
3425fcf3ce44SJohn Forte  * the handling of FCP_SNS_INFO. If there's protocol failures (FCP_RSP_INFO),
3426fcf3ce44SJohn Forte  * we could have catched them before we enter here.
3427fcf3ce44SJohn Forte  */
3428fcf3ce44SJohn Forte fct_status_t
3429fcf3ce44SJohn Forte qlt_send_status(qlt_state_t *qlt, fct_cmd_t *cmd)
3430fcf3ce44SJohn Forte {
3431fcf3ce44SJohn Forte 	qlt_cmd_t *qcmd		= (qlt_cmd_t *)cmd->cmd_fca_private;
3432fcf3ce44SJohn Forte 	scsi_task_t *task	= (scsi_task_t *)cmd->cmd_specific;
3433fcf3ce44SJohn Forte 	qlt_dmem_bctl_t *bctl;
3434fcf3ce44SJohn Forte 	uint32_t size;
3435fcf3ce44SJohn Forte 	uint8_t *req, *fcp_rsp_iu;
3436fcf3ce44SJohn Forte 	uint8_t *psd, sensbuf[24];		/* sense data */
3437fcf3ce44SJohn Forte 	uint16_t flags;
3438fcf3ce44SJohn Forte 	uint16_t scsi_status;
3439fcf3ce44SJohn Forte 	int use_mode2;
3440fcf3ce44SJohn Forte 	int ndx;
3441fcf3ce44SJohn Forte 
3442fcf3ce44SJohn Forte 	/*
3443fcf3ce44SJohn Forte 	 * Enter fast channel for non check condition
3444fcf3ce44SJohn Forte 	 */
3445fcf3ce44SJohn Forte 	if (task->task_scsi_status != STATUS_CHECK) {
3446fcf3ce44SJohn Forte 		/*
3447fcf3ce44SJohn Forte 		 * We will use mode1
3448fcf3ce44SJohn Forte 		 */
3449c4ddbbe1SDaniel Beauregard 		flags = (uint16_t)(BIT_6 | BIT_15 |
3450c4ddbbe1SDaniel Beauregard 		    (((uint16_t)qcmd->param.atio_byte3 & 0xf0) << 5));
3451fcf3ce44SJohn Forte 		scsi_status = (uint16_t)task->task_scsi_status;
3452fcf3ce44SJohn Forte 		if (task->task_status_ctrl == TASK_SCTRL_OVER) {
3453c4ddbbe1SDaniel Beauregard 			scsi_status = (uint16_t)(scsi_status | BIT_10);
3454fcf3ce44SJohn Forte 		} else if (task->task_status_ctrl == TASK_SCTRL_UNDER) {
3455c4ddbbe1SDaniel Beauregard 			scsi_status = (uint16_t)(scsi_status | BIT_11);
3456fcf3ce44SJohn Forte 		}
3457fcf3ce44SJohn Forte 		qcmd->dbuf_rsp_iu = NULL;
3458fcf3ce44SJohn Forte 
3459fcf3ce44SJohn Forte 		/*
3460fcf3ce44SJohn Forte 		 * Fillout CTIO type 7 IOCB
3461fcf3ce44SJohn Forte 		 */
3462fcf3ce44SJohn Forte 		mutex_enter(&qlt->req_lock);
3463fcf3ce44SJohn Forte 		req = (uint8_t *)qlt_get_req_entries(qlt, 1);
3464fcf3ce44SJohn Forte 		if (req == NULL) {
3465fcf3ce44SJohn Forte 			mutex_exit(&qlt->req_lock);
3466fcf3ce44SJohn Forte 			return (FCT_BUSY);
3467fcf3ce44SJohn Forte 		}
3468fcf3ce44SJohn Forte 
3469fcf3ce44SJohn Forte 		/*
3470fcf3ce44SJohn Forte 		 * Common fields
3471fcf3ce44SJohn Forte 		 */
3472fcf3ce44SJohn Forte 		bzero(req, IOCB_SIZE);
3473fcf3ce44SJohn Forte 		req[0x00] = 0x12;
3474fcf3ce44SJohn Forte 		req[0x01] = 0x1;
3475fcf3ce44SJohn Forte 		req[0x02] = BIT_7;	/* indicate if it's a pure status req */
3476fcf3ce44SJohn Forte 		QMEM_WR32(qlt, req + 0x04, cmd->cmd_handle);
3477fcf3ce44SJohn Forte 		QMEM_WR16(qlt, req + 0x08, cmd->cmd_rp->rp_handle);
3478fcf3ce44SJohn Forte 		QMEM_WR32(qlt, req + 0x10, cmd->cmd_rportid);
3479fcf3ce44SJohn Forte 		QMEM_WR32(qlt, req + 0x14, qcmd->fw_xchg_addr);
3480fcf3ce44SJohn Forte 
3481fcf3ce44SJohn Forte 		/*
3482fcf3ce44SJohn Forte 		 * Mode-specific fields
3483fcf3ce44SJohn Forte 		 */
3484fcf3ce44SJohn Forte 		QMEM_WR16(qlt, req + 0x1A, flags);
3485fcf3ce44SJohn Forte 		QMEM_WR32(qlt, req + 0x1C, task->task_resid);
3486fcf3ce44SJohn Forte 		QMEM_WR16(qlt, req + 0x20, cmd->cmd_oxid);
3487fcf3ce44SJohn Forte 		QMEM_WR16(qlt, req + 0x22, scsi_status);
3488fcf3ce44SJohn Forte 
3489fcf3ce44SJohn Forte 		/*
3490fcf3ce44SJohn Forte 		 * Trigger FW to send SCSI status out
3491fcf3ce44SJohn Forte 		 */
3492fcf3ce44SJohn Forte 		qlt_submit_req_entries(qlt, 1);
3493fcf3ce44SJohn Forte 		mutex_exit(&qlt->req_lock);
3494fcf3ce44SJohn Forte 		return (STMF_SUCCESS);
3495fcf3ce44SJohn Forte 	}
3496fcf3ce44SJohn Forte 
3497fcf3ce44SJohn Forte 	ASSERT(task->task_scsi_status == STATUS_CHECK);
3498fcf3ce44SJohn Forte 	/*
3499fcf3ce44SJohn Forte 	 * Decide the SCSI status mode, that should be used
3500fcf3ce44SJohn Forte 	 */
3501fcf3ce44SJohn Forte 	use_mode2 = (task->task_sense_length > 24);
3502fcf3ce44SJohn Forte 
3503fcf3ce44SJohn Forte 	/*
3504fcf3ce44SJohn Forte 	 * Prepare required information per the SCSI status mode
3505fcf3ce44SJohn Forte 	 */
3506c4ddbbe1SDaniel Beauregard 	flags = (uint16_t)(BIT_15 |
3507c4ddbbe1SDaniel Beauregard 	    (((uint16_t)qcmd->param.atio_byte3 & 0xf0) << 5));
3508fcf3ce44SJohn Forte 	if (use_mode2) {
3509c4ddbbe1SDaniel Beauregard 		flags = (uint16_t)(flags | BIT_7);
3510fcf3ce44SJohn Forte 
3511fcf3ce44SJohn Forte 		size = task->task_sense_length;
3512fcf3ce44SJohn Forte 		qcmd->dbuf_rsp_iu = qlt_i_dmem_alloc(qlt,
3513fcf3ce44SJohn Forte 		    task->task_sense_length, &size, 0);
3514fcf3ce44SJohn Forte 		if (!qcmd->dbuf_rsp_iu) {
3515fcf3ce44SJohn Forte 			return (FCT_ALLOC_FAILURE);
3516fcf3ce44SJohn Forte 		}
3517fcf3ce44SJohn Forte 
3518fcf3ce44SJohn Forte 		/*
3519fcf3ce44SJohn Forte 		 * Start to construct FCP_RSP IU
3520fcf3ce44SJohn Forte 		 */
3521fcf3ce44SJohn Forte 		fcp_rsp_iu = qcmd->dbuf_rsp_iu->db_sglist[0].seg_addr;
3522fcf3ce44SJohn Forte 		bzero(fcp_rsp_iu, 24);
3523fcf3ce44SJohn Forte 
3524fcf3ce44SJohn Forte 		/*
3525fcf3ce44SJohn Forte 		 * FCP_RSP IU flags, byte10
3526fcf3ce44SJohn Forte 		 */
3527c4ddbbe1SDaniel Beauregard 		fcp_rsp_iu[10] = (uint8_t)(fcp_rsp_iu[10] | BIT_1);
3528fcf3ce44SJohn Forte 		if (task->task_status_ctrl == TASK_SCTRL_OVER) {
3529c4ddbbe1SDaniel Beauregard 			fcp_rsp_iu[10] = (uint8_t)(fcp_rsp_iu[10] | BIT_2);
3530fcf3ce44SJohn Forte 		} else if (task->task_status_ctrl == TASK_SCTRL_UNDER) {
3531c4ddbbe1SDaniel Beauregard 			fcp_rsp_iu[10] = (uint8_t)(fcp_rsp_iu[10] | BIT_3);
3532fcf3ce44SJohn Forte 		}
3533fcf3ce44SJohn Forte 
3534fcf3ce44SJohn Forte 		/*
3535fcf3ce44SJohn Forte 		 * SCSI status code, byte11
3536fcf3ce44SJohn Forte 		 */
3537fcf3ce44SJohn Forte 		fcp_rsp_iu[11] = task->task_scsi_status;
3538fcf3ce44SJohn Forte 
3539fcf3ce44SJohn Forte 		/*
3540fcf3ce44SJohn Forte 		 * FCP_RESID (Overrun or underrun)
3541fcf3ce44SJohn Forte 		 */
3542c4ddbbe1SDaniel Beauregard 		fcp_rsp_iu[12] = (uint8_t)((task->task_resid >> 24) & 0xFF);
3543c4ddbbe1SDaniel Beauregard 		fcp_rsp_iu[13] = (uint8_t)((task->task_resid >> 16) & 0xFF);
3544c4ddbbe1SDaniel Beauregard 		fcp_rsp_iu[14] = (uint8_t)((task->task_resid >>  8) & 0xFF);
3545c4ddbbe1SDaniel Beauregard 		fcp_rsp_iu[15] = (uint8_t)((task->task_resid >>  0) & 0xFF);
3546fcf3ce44SJohn Forte 
3547fcf3ce44SJohn Forte 		/*
3548fcf3ce44SJohn Forte 		 * FCP_SNS_LEN
3549fcf3ce44SJohn Forte 		 */
3550c4ddbbe1SDaniel Beauregard 		fcp_rsp_iu[18] = (uint8_t)((task->task_sense_length >> 8) &
3551c4ddbbe1SDaniel Beauregard 		    0xFF);
3552c4ddbbe1SDaniel Beauregard 		fcp_rsp_iu[19] = (uint8_t)((task->task_sense_length >> 0) &
3553c4ddbbe1SDaniel Beauregard 		    0xFF);
3554fcf3ce44SJohn Forte 
3555fcf3ce44SJohn Forte 		/*
3556fcf3ce44SJohn Forte 		 * FCP_RSP_LEN
3557fcf3ce44SJohn Forte 		 */
3558fcf3ce44SJohn Forte 		/*
3559fcf3ce44SJohn Forte 		 * no FCP_RSP_INFO
3560fcf3ce44SJohn Forte 		 */
3561fcf3ce44SJohn Forte 		/*
3562fcf3ce44SJohn Forte 		 * FCP_SNS_INFO
3563fcf3ce44SJohn Forte 		 */
3564fcf3ce44SJohn Forte 		bcopy(task->task_sense_data, fcp_rsp_iu + 24,
3565fcf3ce44SJohn Forte 		    task->task_sense_length);
3566fcf3ce44SJohn Forte 
3567fcf3ce44SJohn Forte 		/*
3568fcf3ce44SJohn Forte 		 * Ensure dma data consistency
3569fcf3ce44SJohn Forte 		 */
3570fcf3ce44SJohn Forte 		qlt_dmem_dma_sync(qcmd->dbuf_rsp_iu, DDI_DMA_SYNC_FORDEV);
3571fcf3ce44SJohn Forte 	} else {
3572c4ddbbe1SDaniel Beauregard 		flags = (uint16_t)(flags | BIT_6);
3573fcf3ce44SJohn Forte 
3574fcf3ce44SJohn Forte 		scsi_status = (uint16_t)task->task_scsi_status;
3575fcf3ce44SJohn Forte 		if (task->task_status_ctrl == TASK_SCTRL_OVER) {
3576c4ddbbe1SDaniel Beauregard 			scsi_status = (uint16_t)(scsi_status | BIT_10);
3577fcf3ce44SJohn Forte 		} else if (task->task_status_ctrl == TASK_SCTRL_UNDER) {
3578c4ddbbe1SDaniel Beauregard 			scsi_status = (uint16_t)(scsi_status | BIT_11);
3579fcf3ce44SJohn Forte 		}
3580fcf3ce44SJohn Forte 		if (task->task_sense_length) {
3581c4ddbbe1SDaniel Beauregard 			scsi_status = (uint16_t)(scsi_status | BIT_9);
3582fcf3ce44SJohn Forte 		}
3583fcf3ce44SJohn Forte 		bcopy(task->task_sense_data, sensbuf, task->task_sense_length);
3584fcf3ce44SJohn Forte 		qcmd->dbuf_rsp_iu = NULL;
3585fcf3ce44SJohn Forte 	}
3586fcf3ce44SJohn Forte 
3587fcf3ce44SJohn Forte 	/*
3588fcf3ce44SJohn Forte 	 * Fillout CTIO type 7 IOCB
3589fcf3ce44SJohn Forte 	 */
3590fcf3ce44SJohn Forte 	mutex_enter(&qlt->req_lock);
3591fcf3ce44SJohn Forte 	req = (uint8_t *)qlt_get_req_entries(qlt, 1);
3592fcf3ce44SJohn Forte 	if (req == NULL) {
3593fcf3ce44SJohn Forte 		mutex_exit(&qlt->req_lock);
3594fcf3ce44SJohn Forte 		if (use_mode2) {
3595fcf3ce44SJohn Forte 			qlt_dmem_free(cmd->cmd_port->port_fds,
3596d8c54e3dSSam Cramer 			    qcmd->dbuf_rsp_iu);
3597fcf3ce44SJohn Forte 			qcmd->dbuf_rsp_iu = NULL;
3598fcf3ce44SJohn Forte 		}
3599fcf3ce44SJohn Forte 		return (FCT_BUSY);
3600fcf3ce44SJohn Forte 	}
3601fcf3ce44SJohn Forte 
3602fcf3ce44SJohn Forte 	/*
3603fcf3ce44SJohn Forte 	 * Common fields
3604fcf3ce44SJohn Forte 	 */
3605fcf3ce44SJohn Forte 	bzero(req, IOCB_SIZE);
3606fcf3ce44SJohn Forte 	req[0x00] = 0x12;
3607fcf3ce44SJohn Forte 	req[0x01] = 0x1;
3608fcf3ce44SJohn Forte 	req[0x02] = BIT_7;	/* to indicate if it's a pure status req */
3609fcf3ce44SJohn Forte 	QMEM_WR32(qlt, req + 0x04, cmd->cmd_handle);
3610fcf3ce44SJohn Forte 	QMEM_WR16(qlt, req + 0x08, cmd->cmd_rp->rp_handle);
3611fcf3ce44SJohn Forte 	QMEM_WR16(qlt, req + 0x0A, 0);	/* not timed by FW */
3612fcf3ce44SJohn Forte 	if (use_mode2) {
3613fcf3ce44SJohn Forte 		QMEM_WR16(qlt, req+0x0C, 1);	/* FCP RSP IU data field */
3614fcf3ce44SJohn Forte 	}
3615fcf3ce44SJohn Forte 	QMEM_WR32(qlt, req + 0x10, cmd->cmd_rportid);
3616fcf3ce44SJohn Forte 	QMEM_WR32(qlt, req + 0x14, qcmd->fw_xchg_addr);
3617fcf3ce44SJohn Forte 
3618fcf3ce44SJohn Forte 	/*
3619fcf3ce44SJohn Forte 	 * Mode-specific fields
3620fcf3ce44SJohn Forte 	 */
3621fcf3ce44SJohn Forte 	if (!use_mode2) {
3622fcf3ce44SJohn Forte 		QMEM_WR16(qlt, req + 0x18, task->task_sense_length);
3623fcf3ce44SJohn Forte 	}
3624fcf3ce44SJohn Forte 	QMEM_WR16(qlt, req + 0x1A, flags);
3625fcf3ce44SJohn Forte 	QMEM_WR32(qlt, req + 0x1C, task->task_resid);
3626fcf3ce44SJohn Forte 	QMEM_WR16(qlt, req + 0x20, cmd->cmd_oxid);
3627fcf3ce44SJohn Forte 	if (use_mode2) {
3628fcf3ce44SJohn Forte 		bctl = (qlt_dmem_bctl_t *)qcmd->dbuf_rsp_iu->db_port_private;
3629fcf3ce44SJohn Forte 		QMEM_WR32(qlt, req + 0x2C, 24 + task->task_sense_length);
3630fcf3ce44SJohn Forte 		QMEM_WR64(qlt, req + 0x34, bctl->bctl_dev_addr);
3631fcf3ce44SJohn Forte 		QMEM_WR32(qlt, req + 0x3C, 24 + task->task_sense_length);
3632fcf3ce44SJohn Forte 	} else {
3633fcf3ce44SJohn Forte 		QMEM_WR16(qlt, req + 0x22, scsi_status);
3634fcf3ce44SJohn Forte 		psd = req+0x28;
3635fcf3ce44SJohn Forte 
3636fcf3ce44SJohn Forte 		/*
3637fcf3ce44SJohn Forte 		 * Data in sense buf is always big-endian, data in IOCB
3638fcf3ce44SJohn Forte 		 * should always be little-endian, so we must do swapping.
3639fcf3ce44SJohn Forte 		 */
3640fcf3ce44SJohn Forte 		size = ((task->task_sense_length + 3) & (~3));
3641fcf3ce44SJohn Forte 		for (ndx = 0; ndx < size; ndx += 4) {
3642fcf3ce44SJohn Forte 			psd[ndx + 0] = sensbuf[ndx + 3];
3643fcf3ce44SJohn Forte 			psd[ndx + 1] = sensbuf[ndx + 2];
3644fcf3ce44SJohn Forte 			psd[ndx + 2] = sensbuf[ndx + 1];
3645fcf3ce44SJohn Forte 			psd[ndx + 3] = sensbuf[ndx + 0];
3646fcf3ce44SJohn Forte 		}
3647fcf3ce44SJohn Forte 	}
3648fcf3ce44SJohn Forte 
3649fcf3ce44SJohn Forte 	/*
3650fcf3ce44SJohn Forte 	 * Trigger FW to send SCSI status out
3651fcf3ce44SJohn Forte 	 */
3652fcf3ce44SJohn Forte 	qlt_submit_req_entries(qlt, 1);
3653fcf3ce44SJohn Forte 	mutex_exit(&qlt->req_lock);
3654fcf3ce44SJohn Forte 
3655fcf3ce44SJohn Forte 	return (STMF_SUCCESS);
3656fcf3ce44SJohn Forte }
3657fcf3ce44SJohn Forte 
3658fcf3ce44SJohn Forte fct_status_t
3659fcf3ce44SJohn Forte qlt_send_els_response(qlt_state_t *qlt, fct_cmd_t *cmd)
3660fcf3ce44SJohn Forte {
3661fcf3ce44SJohn Forte 	qlt_cmd_t	*qcmd;
3662fcf3ce44SJohn Forte 	fct_els_t *els = (fct_els_t *)cmd->cmd_specific;
3663fcf3ce44SJohn Forte 	uint8_t *req, *addr;
3664fcf3ce44SJohn Forte 	qlt_dmem_bctl_t *bctl;
3665fcf3ce44SJohn Forte 	uint32_t minsize;
3666fcf3ce44SJohn Forte 	uint8_t elsop, req1f;
3667fcf3ce44SJohn Forte 
3668fcf3ce44SJohn Forte 	addr = els->els_resp_payload;
3669fcf3ce44SJohn Forte 	qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
3670fcf3ce44SJohn Forte 
3671fcf3ce44SJohn Forte 	minsize = els->els_resp_size;
3672fcf3ce44SJohn Forte 	qcmd->dbuf = qlt_i_dmem_alloc(qlt, els->els_resp_size, &minsize, 0);
3673fcf3ce44SJohn Forte 	if (qcmd->dbuf == NULL)
3674fcf3ce44SJohn Forte 		return (FCT_BUSY);
3675fcf3ce44SJohn Forte 
3676fcf3ce44SJohn Forte 	bctl = (qlt_dmem_bctl_t *)qcmd->dbuf->db_port_private;
3677fcf3ce44SJohn Forte 
3678fcf3ce44SJohn Forte 	bcopy(addr, qcmd->dbuf->db_sglist[0].seg_addr, els->els_resp_size);
3679fcf3ce44SJohn Forte 	qlt_dmem_dma_sync(qcmd->dbuf, DDI_DMA_SYNC_FORDEV);
3680fcf3ce44SJohn Forte 
3681fcf3ce44SJohn Forte 	if (addr[0] == 0x02) {	/* ACC */
3682fcf3ce44SJohn Forte 		req1f = BIT_5;
3683fcf3ce44SJohn Forte 	} else {
3684fcf3ce44SJohn Forte 		req1f = BIT_6;
3685fcf3ce44SJohn Forte 	}
3686fcf3ce44SJohn Forte 	elsop = els->els_req_payload[0];
3687fcf3ce44SJohn Forte 	if ((elsop == ELS_OP_PRLI) || (elsop == ELS_OP_PRLO) ||
3688fcf3ce44SJohn Forte 	    (elsop == ELS_OP_TPRLO) || (elsop == ELS_OP_LOGO)) {
3689c4ddbbe1SDaniel Beauregard 		req1f = (uint8_t)(req1f | BIT_4);
3690fcf3ce44SJohn Forte 	}
3691fcf3ce44SJohn Forte 
3692fcf3ce44SJohn Forte 	mutex_enter(&qlt->req_lock);
3693fcf3ce44SJohn Forte 	req = (uint8_t *)qlt_get_req_entries(qlt, 1);
3694fcf3ce44SJohn Forte 	if (req == NULL) {
3695fcf3ce44SJohn Forte 		mutex_exit(&qlt->req_lock);
3696fcf3ce44SJohn Forte 		qlt_dmem_free(NULL, qcmd->dbuf);
3697fcf3ce44SJohn Forte 		qcmd->dbuf = NULL;
3698fcf3ce44SJohn Forte 		return (FCT_BUSY);
3699fcf3ce44SJohn Forte 	}
3700fcf3ce44SJohn Forte 	bzero(req, IOCB_SIZE);
3701fcf3ce44SJohn Forte 	req[0] = 0x53; req[1] = 1; req[0xf] = 0x10;
3702fcf3ce44SJohn Forte 	req[0x16] = elsop; req[0x1f] = req1f;
3703fcf3ce44SJohn Forte 	QMEM_WR32(qlt, (&req[4]), cmd->cmd_handle);
3704fcf3ce44SJohn Forte 	QMEM_WR16(qlt, (&req[0xA]), cmd->cmd_rp->rp_handle);
3705fcf3ce44SJohn Forte 	QMEM_WR16(qlt, (&req[0xC]), 1);
3706fcf3ce44SJohn Forte 	QMEM_WR32(qlt, (&req[0x10]), qcmd->fw_xchg_addr);
3707fcf3ce44SJohn Forte 	QMEM_WR32(qlt, (&req[0x18]), cmd->cmd_rportid);
3708fcf3ce44SJohn Forte 	if (qlt->cur_topology == PORT_TOPOLOGY_PT_TO_PT) {
3709c4ddbbe1SDaniel Beauregard 		req[0x1b] = (uint8_t)((cmd->cmd_lportid >> 16) & 0xff);
3710c4ddbbe1SDaniel Beauregard 		req[0x1c] = (uint8_t)(cmd->cmd_lportid & 0xff);
3711c4ddbbe1SDaniel Beauregard 		req[0x1d] = (uint8_t)((cmd->cmd_lportid >> 8) & 0xff);
3712fcf3ce44SJohn Forte 	}
3713fcf3ce44SJohn Forte 	QMEM_WR32(qlt, (&req[0x24]), els->els_resp_size);
3714fcf3ce44SJohn Forte 	QMEM_WR64(qlt, (&req[0x28]), bctl->bctl_dev_addr);
3715fcf3ce44SJohn Forte 	QMEM_WR32(qlt, (&req[0x30]), els->els_resp_size);
3716fcf3ce44SJohn Forte 	qlt_submit_req_entries(qlt, 1);
3717fcf3ce44SJohn Forte 	mutex_exit(&qlt->req_lock);
3718fcf3ce44SJohn Forte 
3719fcf3ce44SJohn Forte 	return (FCT_SUCCESS);
3720fcf3ce44SJohn Forte }
3721fcf3ce44SJohn Forte 
3722fcf3ce44SJohn Forte fct_status_t
3723fcf3ce44SJohn Forte qlt_send_abts_response(qlt_state_t *qlt, fct_cmd_t *cmd, int terminate)
3724fcf3ce44SJohn Forte {
3725fcf3ce44SJohn Forte 	qlt_abts_cmd_t *qcmd;
3726fcf3ce44SJohn Forte 	fct_rcvd_abts_t *abts = (fct_rcvd_abts_t *)cmd->cmd_specific;
3727fcf3ce44SJohn Forte 	uint8_t *req;
3728fcf3ce44SJohn Forte 	uint32_t lportid;
3729fcf3ce44SJohn Forte 	uint32_t fctl;
3730fcf3ce44SJohn Forte 	int i;
3731fcf3ce44SJohn Forte 
3732fcf3ce44SJohn Forte 	qcmd = (qlt_abts_cmd_t *)cmd->cmd_fca_private;
3733fcf3ce44SJohn Forte 
3734fcf3ce44SJohn Forte 	mutex_enter(&qlt->req_lock);
3735fcf3ce44SJohn Forte 	req = (uint8_t *)qlt_get_req_entries(qlt, 1);
3736fcf3ce44SJohn Forte 	if (req == NULL) {
3737fcf3ce44SJohn Forte 		mutex_exit(&qlt->req_lock);
3738fcf3ce44SJohn Forte 		return (FCT_BUSY);
3739fcf3ce44SJohn Forte 	}
3740fcf3ce44SJohn Forte 	bcopy(qcmd->buf, req, IOCB_SIZE);
3741fcf3ce44SJohn Forte 	lportid = QMEM_RD32(qlt, req+0x14) & 0xFFFFFF;
3742fcf3ce44SJohn Forte 	fctl = QMEM_RD32(qlt, req+0x1C);
3743fcf3ce44SJohn Forte 	fctl = ((fctl ^ BIT_23) & ~BIT_22) | (BIT_19 | BIT_16);
3744fcf3ce44SJohn Forte 	req[0] = 0x55; req[1] = 1; req[2] = (uint8_t)terminate;
3745fcf3ce44SJohn Forte 	QMEM_WR32(qlt, (&req[4]), cmd->cmd_handle);
3746fcf3ce44SJohn Forte 	if (cmd->cmd_rp)
3747fcf3ce44SJohn Forte 		QMEM_WR16(qlt, (&req[0xA]), cmd->cmd_rp->rp_handle);
3748fcf3ce44SJohn Forte 	else
3749fcf3ce44SJohn Forte 		QMEM_WR16(qlt, (&req[0xA]), cmd->cmd_rp_handle);
3750fcf3ce44SJohn Forte 	if (terminate) {
3751fcf3ce44SJohn Forte 		QMEM_WR16(qlt, (&req[0xC]), 1);
3752fcf3ce44SJohn Forte 	}
3753fcf3ce44SJohn Forte 	QMEM_WR32(qlt, req+0x14, cmd->cmd_rportid);
3754fcf3ce44SJohn Forte 	req[0x17] = abts->abts_resp_rctl;
3755fcf3ce44SJohn Forte 	QMEM_WR32(qlt, req+0x18, lportid);
3756fcf3ce44SJohn Forte 	QMEM_WR32(qlt, req+0x1C, fctl);
3757fcf3ce44SJohn Forte 	req[0x23]++;
3758fcf3ce44SJohn Forte 	for (i = 0; i < 12; i += 4) {
3759fcf3ce44SJohn Forte 		/* Take care of firmware's LE requirement */
3760fcf3ce44SJohn Forte 		req[0x2C+i] = abts->abts_resp_payload[i+3];
3761fcf3ce44SJohn Forte 		req[0x2C+i+1] = abts->abts_resp_payload[i+2];
3762fcf3ce44SJohn Forte 		req[0x2C+i+2] = abts->abts_resp_payload[i+1];
3763fcf3ce44SJohn Forte 		req[0x2C+i+3] = abts->abts_resp_payload[i];
3764fcf3ce44SJohn Forte 	}
3765fcf3ce44SJohn Forte 	qlt_submit_req_entries(qlt, 1);
3766fcf3ce44SJohn Forte 	mutex_exit(&qlt->req_lock);
3767fcf3ce44SJohn Forte 
3768fcf3ce44SJohn Forte 	return (FCT_SUCCESS);
3769fcf3ce44SJohn Forte }
3770fcf3ce44SJohn Forte 
3771fcf3ce44SJohn Forte static void
3772fcf3ce44SJohn Forte qlt_handle_inot(qlt_state_t *qlt, uint8_t *inot)
3773fcf3ce44SJohn Forte {
3774fcf3ce44SJohn Forte 	int i;
3775fcf3ce44SJohn Forte 	uint32_t d;
3776fcf3ce44SJohn Forte 	caddr_t req;
3777fcf3ce44SJohn Forte 	/* Just put it on the request queue */
3778fcf3ce44SJohn Forte 	mutex_enter(&qlt->req_lock);
3779fcf3ce44SJohn Forte 	req = qlt_get_req_entries(qlt, 1);
3780fcf3ce44SJohn Forte 	if (req == NULL) {
3781fcf3ce44SJohn Forte 		mutex_exit(&qlt->req_lock);
3782fcf3ce44SJohn Forte 		/* XXX handle this */
3783fcf3ce44SJohn Forte 		return;
3784fcf3ce44SJohn Forte 	}
3785fcf3ce44SJohn Forte 	for (i = 0; i < 16; i++) {
3786fcf3ce44SJohn Forte 		d = QMEM_RD32(qlt, inot);
3787fcf3ce44SJohn Forte 		inot += 4;
3788fcf3ce44SJohn Forte 		QMEM_WR32(qlt, req, d);
3789fcf3ce44SJohn Forte 		req += 4;
3790fcf3ce44SJohn Forte 	}
3791fcf3ce44SJohn Forte 	req -= 64;
3792fcf3ce44SJohn Forte 	req[0] = 0x0e;
3793fcf3ce44SJohn Forte 	qlt_submit_req_entries(qlt, 1);
3794fcf3ce44SJohn Forte 	mutex_exit(&qlt->req_lock);
3795fcf3ce44SJohn Forte }
3796fcf3ce44SJohn Forte 
3797fcf3ce44SJohn Forte uint8_t qlt_task_flags[] = { 1, 3, 2, 1, 4, 0, 1, 1 };
3798fcf3ce44SJohn Forte static void
3799fcf3ce44SJohn Forte qlt_handle_atio(qlt_state_t *qlt, uint8_t *atio)
3800fcf3ce44SJohn Forte {
3801fcf3ce44SJohn Forte 	fct_cmd_t	*cmd;
3802fcf3ce44SJohn Forte 	scsi_task_t	*task;
3803fcf3ce44SJohn Forte 	qlt_cmd_t	*qcmd;
3804fcf3ce44SJohn Forte 	uint32_t	rportid, fw_xchg_addr;
3805fcf3ce44SJohn Forte 	uint8_t		*p, *q, *req, tm;
3806fcf3ce44SJohn Forte 	uint16_t	cdb_size, flags, oxid;
3807fcf3ce44SJohn Forte 	char		info[160];
3808fcf3ce44SJohn Forte 
3809fcf3ce44SJohn Forte 	/*
3810fcf3ce44SJohn Forte 	 * If either bidirection xfer is requested of there is extended
3811fcf3ce44SJohn Forte 	 * CDB, atio[0x20 + 11] will be greater than or equal to 3.
3812fcf3ce44SJohn Forte 	 */
3813fcf3ce44SJohn Forte 	cdb_size = 16;
3814fcf3ce44SJohn Forte 	if (atio[0x20 + 11] >= 3) {
3815fcf3ce44SJohn Forte 		uint8_t b = atio[0x20 + 11];
3816fcf3ce44SJohn Forte 		uint16_t b1;
3817fcf3ce44SJohn Forte 		if ((b & 3) == 3) {
3818c4ddbbe1SDaniel Beauregard 			EL(qlt, "bidirectional I/O not supported\n");
3819fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "qlt(%d) CMD with bidirectional I/O "
3820fcf3ce44SJohn Forte 			    "received, dropping the cmd as bidirectional "
3821fcf3ce44SJohn Forte 			    " transfers are not yet supported", qlt->instance);
3822fcf3ce44SJohn Forte 			/* XXX abort the I/O */
3823fcf3ce44SJohn Forte 			return;
3824fcf3ce44SJohn Forte 		}
3825c4ddbbe1SDaniel Beauregard 		cdb_size = (uint16_t)(cdb_size + (b & 0xfc));
3826fcf3ce44SJohn Forte 		/*
3827fcf3ce44SJohn Forte 		 * Verify that we have enough entries. Without additional CDB
3828fcf3ce44SJohn Forte 		 * Everything will fit nicely within the same 64 bytes. So the
3829fcf3ce44SJohn Forte 		 * additional cdb size is essentially the # of additional bytes
3830fcf3ce44SJohn Forte 		 * we need.
3831fcf3ce44SJohn Forte 		 */
3832fcf3ce44SJohn Forte 		b1 = (uint16_t)b;
3833fcf3ce44SJohn Forte 		if (((((b1 & 0xfc) + 63) >> 6) + 1) > ((uint16_t)atio[1])) {
3834c4ddbbe1SDaniel Beauregard 			EL(qlt, "extended cdb received\n");
3835fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "qlt(%d): cmd received with extended "
3836fcf3ce44SJohn Forte 			    " cdb (cdb size = %d bytes), however the firmware "
3837fcf3ce44SJohn Forte 			    " did not DMAed the entire FCP_CMD IU, entry count "
3838fcf3ce44SJohn Forte 			    " is %d while it should be %d", qlt->instance,
3839fcf3ce44SJohn Forte 			    cdb_size, atio[1], ((((b1 & 0xfc) + 63) >> 6) + 1));
3840fcf3ce44SJohn Forte 			/* XXX abort the I/O */
3841fcf3ce44SJohn Forte 			return;
3842fcf3ce44SJohn Forte 		}
3843fcf3ce44SJohn Forte 	}
3844fcf3ce44SJohn Forte 
3845fcf3ce44SJohn Forte 	rportid = (((uint32_t)atio[8 + 5]) << 16) |
3846fcf3ce44SJohn Forte 	    (((uint32_t)atio[8 + 6]) << 8) | atio[8+7];
3847fcf3ce44SJohn Forte 	fw_xchg_addr = QMEM_RD32(qlt, atio+4);
3848c4ddbbe1SDaniel Beauregard 	oxid = (uint16_t)((((uint16_t)atio[8 + 16]) << 8) | atio[8+17]);
3849fcf3ce44SJohn Forte 
3850fcf3ce44SJohn Forte 	if (fw_xchg_addr == 0xFFFFFFFF) {
3851c4ddbbe1SDaniel Beauregard 		EL(qlt, "fw_xchg_addr==0xFFFFFFFF\n");
3852fcf3ce44SJohn Forte 		cmd = NULL;
3853fcf3ce44SJohn Forte 	} else {
3854fcf3ce44SJohn Forte 		cmd = fct_scsi_task_alloc(qlt->qlt_port, FCT_HANDLE_NONE,
3855fcf3ce44SJohn Forte 		    rportid, atio+0x20, cdb_size, STMF_TASK_EXT_NONE);
3856c4ddbbe1SDaniel Beauregard 		if (cmd == NULL) {
3857c4ddbbe1SDaniel Beauregard 			EL(qlt, "fct_scsi_task_alloc cmd==NULL\n");
3858c4ddbbe1SDaniel Beauregard 		}
3859fcf3ce44SJohn Forte 	}
3860fcf3ce44SJohn Forte 	if (cmd == NULL) {
3861c4ddbbe1SDaniel Beauregard 		EL(qlt, "fct_scsi_task_alloc cmd==NULL\n");
3862fcf3ce44SJohn Forte 		/* Abort this IO */
3863c4ddbbe1SDaniel Beauregard 		flags = (uint16_t)(BIT_14 | ((atio[3] & 0xF0) << 5));
3864fcf3ce44SJohn Forte 
3865fcf3ce44SJohn Forte 		mutex_enter(&qlt->req_lock);
3866fcf3ce44SJohn Forte 		req = (uint8_t *)qlt_get_req_entries(qlt, 1);
3867fcf3ce44SJohn Forte 		if (req == NULL) {
3868fcf3ce44SJohn Forte 			mutex_exit(&qlt->req_lock);
3869fcf3ce44SJohn Forte 
3870fcf3ce44SJohn Forte 			(void) snprintf(info, 160,
3871fcf3ce44SJohn Forte 			    "qlt_handle_atio: qlt-%p, can't "
3872fcf3ce44SJohn Forte 			    "allocate space for scsi_task", (void *)qlt);
3873fcf3ce44SJohn Forte 			info[159] = 0;
3874fcf3ce44SJohn Forte 			(void) fct_port_shutdown(qlt->qlt_port,
3875fcf3ce44SJohn Forte 			    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
3876fcf3ce44SJohn Forte 			return;
3877fcf3ce44SJohn Forte 		}
3878fcf3ce44SJohn Forte 		bzero(req, IOCB_SIZE);
3879fcf3ce44SJohn Forte 		req[0] = 0x12; req[1] = 0x1;
3880fcf3ce44SJohn Forte 		QMEM_WR32(qlt, req+4, 0);
3881fcf3ce44SJohn Forte 		QMEM_WR16(qlt, req+8, fct_get_rp_handle(qlt->qlt_port,
3882fcf3ce44SJohn Forte 		    rportid));
3883fcf3ce44SJohn Forte 		QMEM_WR16(qlt, req+10, 60);
3884fcf3ce44SJohn Forte 		QMEM_WR32(qlt, req+0x10, rportid);
3885fcf3ce44SJohn Forte 		QMEM_WR32(qlt, req+0x14, fw_xchg_addr);
3886fcf3ce44SJohn Forte 		QMEM_WR16(qlt, req+0x1A, flags);
3887fcf3ce44SJohn Forte 		QMEM_WR16(qlt, req+0x20, oxid);
3888fcf3ce44SJohn Forte 		qlt_submit_req_entries(qlt, 1);
3889fcf3ce44SJohn Forte 		mutex_exit(&qlt->req_lock);
3890fcf3ce44SJohn Forte 
3891fcf3ce44SJohn Forte 		return;
3892fcf3ce44SJohn Forte 	}
3893fcf3ce44SJohn Forte 
3894fcf3ce44SJohn Forte 	task = (scsi_task_t *)cmd->cmd_specific;
3895fcf3ce44SJohn Forte 	qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
3896fcf3ce44SJohn Forte 	qcmd->fw_xchg_addr = fw_xchg_addr;
3897fcf3ce44SJohn Forte 	qcmd->param.atio_byte3 = atio[3];
3898fcf3ce44SJohn Forte 	cmd->cmd_oxid = oxid;
3899c4ddbbe1SDaniel Beauregard 	cmd->cmd_rxid = (uint16_t)((((uint16_t)atio[8 + 18]) << 8) |
3900c4ddbbe1SDaniel Beauregard 	    atio[8+19]);
3901fcf3ce44SJohn Forte 	cmd->cmd_rportid = rportid;
3902fcf3ce44SJohn Forte 	cmd->cmd_lportid = (((uint32_t)atio[8 + 1]) << 16) |
3903fcf3ce44SJohn Forte 	    (((uint32_t)atio[8 + 2]) << 8) | atio[8 + 3];
3904fcf3ce44SJohn Forte 	cmd->cmd_rp_handle = FCT_HANDLE_NONE;
3905fcf3ce44SJohn Forte 	/* Dont do a 64 byte read as this is IOMMU */
3906fcf3ce44SJohn Forte 	q = atio+0x28;
3907fcf3ce44SJohn Forte 	/* XXX Handle fcp_cntl */
3908fcf3ce44SJohn Forte 	task->task_cmd_seq_no = (uint32_t)(*q++);
3909fcf3ce44SJohn Forte 	task->task_csn_size = 8;
3910fcf3ce44SJohn Forte 	task->task_flags = qlt_task_flags[(*q++) & 7];
3911fcf3ce44SJohn Forte 	tm = *q++;
3912fcf3ce44SJohn Forte 	if (tm) {
3913fcf3ce44SJohn Forte 		if (tm & BIT_1)
3914fcf3ce44SJohn Forte 			task->task_mgmt_function = TM_ABORT_TASK_SET;
3915fcf3ce44SJohn Forte 		else if (tm & BIT_2)
3916fcf3ce44SJohn Forte 			task->task_mgmt_function = TM_CLEAR_TASK_SET;
3917fcf3ce44SJohn Forte 		else if (tm & BIT_4)
3918fcf3ce44SJohn Forte 			task->task_mgmt_function = TM_LUN_RESET;
3919fcf3ce44SJohn Forte 		else if (tm & BIT_5)
3920fcf3ce44SJohn Forte 			task->task_mgmt_function = TM_TARGET_COLD_RESET;
3921fcf3ce44SJohn Forte 		else if (tm & BIT_6)
3922fcf3ce44SJohn Forte 			task->task_mgmt_function = TM_CLEAR_ACA;
3923fcf3ce44SJohn Forte 		else
3924fcf3ce44SJohn Forte 			task->task_mgmt_function = TM_ABORT_TASK;
3925fcf3ce44SJohn Forte 	}
3926fcf3ce44SJohn Forte 	task->task_max_nbufs = STMF_BUFS_MAX;
3927fcf3ce44SJohn Forte 	task->task_csn_size = 8;
3928c4ddbbe1SDaniel Beauregard 	task->task_flags = (uint8_t)(task->task_flags | (((*q++) & 3) << 5));
3929fcf3ce44SJohn Forte 	p = task->task_cdb;
3930fcf3ce44SJohn Forte 	*p++ = *q++; *p++ = *q++; *p++ = *q++; *p++ = *q++;
3931fcf3ce44SJohn Forte 	*p++ = *q++; *p++ = *q++; *p++ = *q++; *p++ = *q++;
3932fcf3ce44SJohn Forte 	*p++ = *q++; *p++ = *q++; *p++ = *q++; *p++ = *q++;
3933fcf3ce44SJohn Forte 	*p++ = *q++; *p++ = *q++; *p++ = *q++; *p++ = *q++;
3934fcf3ce44SJohn Forte 	if (cdb_size > 16) {
3935c4ddbbe1SDaniel Beauregard 		uint16_t xtra = (uint16_t)(cdb_size - 16);
3936fcf3ce44SJohn Forte 		uint16_t i;
3937fcf3ce44SJohn Forte 		uint8_t cb[4];
3938fcf3ce44SJohn Forte 
3939fcf3ce44SJohn Forte 		while (xtra) {
3940fcf3ce44SJohn Forte 			*p++ = *q++;
3941fcf3ce44SJohn Forte 			xtra--;
3942fcf3ce44SJohn Forte 			if (q == ((uint8_t *)qlt->queue_mem_ptr +
3943fcf3ce44SJohn Forte 			    ATIO_QUEUE_OFFSET + (ATIO_QUEUE_ENTRIES * 64))) {
3944fcf3ce44SJohn Forte 				q = (uint8_t *)qlt->queue_mem_ptr +
3945d8c54e3dSSam Cramer 				    ATIO_QUEUE_OFFSET;
3946fcf3ce44SJohn Forte 			}
3947fcf3ce44SJohn Forte 		}
3948fcf3ce44SJohn Forte 		for (i = 0; i < 4; i++) {
3949fcf3ce44SJohn Forte 			cb[i] = *q++;
3950fcf3ce44SJohn Forte 			if (q == ((uint8_t *)qlt->queue_mem_ptr +
3951fcf3ce44SJohn Forte 			    ATIO_QUEUE_OFFSET + (ATIO_QUEUE_ENTRIES * 64))) {
3952fcf3ce44SJohn Forte 				q = (uint8_t *)qlt->queue_mem_ptr +
3953d8c54e3dSSam Cramer 				    ATIO_QUEUE_OFFSET;
3954fcf3ce44SJohn Forte 			}
3955fcf3ce44SJohn Forte 		}
3956fcf3ce44SJohn Forte 		task->task_expected_xfer_length = (((uint32_t)cb[0]) << 24) |
3957d8c54e3dSSam Cramer 		    (((uint32_t)cb[1]) << 16) |
3958d8c54e3dSSam Cramer 		    (((uint32_t)cb[2]) << 8) | cb[3];
3959fcf3ce44SJohn Forte 	} else {
3960fcf3ce44SJohn Forte 		task->task_expected_xfer_length = (((uint32_t)q[0]) << 24) |
3961d8c54e3dSSam Cramer 		    (((uint32_t)q[1]) << 16) |
3962d8c54e3dSSam Cramer 		    (((uint32_t)q[2]) << 8) | q[3];
3963fcf3ce44SJohn Forte 	}
3964fcf3ce44SJohn Forte 	fct_post_rcvd_cmd(cmd, 0);
3965fcf3ce44SJohn Forte }
3966fcf3ce44SJohn Forte 
3967fcf3ce44SJohn Forte static void
3968fcf3ce44SJohn Forte qlt_handle_dereg_completion(qlt_state_t *qlt, uint8_t *rsp)
3969fcf3ce44SJohn Forte {
3970fcf3ce44SJohn Forte 	uint16_t status;
3971fcf3ce44SJohn Forte 	uint32_t portid;
3972fcf3ce44SJohn Forte 	uint32_t subcode1, subcode2;
3973fcf3ce44SJohn Forte 
3974fcf3ce44SJohn Forte 	status = QMEM_RD16(qlt, rsp+8);
3975fcf3ce44SJohn Forte 	portid = QMEM_RD32(qlt, rsp+0x10) & 0xffffff;
3976fcf3ce44SJohn Forte 	subcode1 = QMEM_RD32(qlt, rsp+0x14);
3977fcf3ce44SJohn Forte 	subcode2 = QMEM_RD32(qlt, rsp+0x18);
3978fcf3ce44SJohn Forte 
3979fcf3ce44SJohn Forte 	mutex_enter(&qlt->preq_lock);
3980fcf3ce44SJohn Forte 	if (portid != qlt->rp_id_in_dereg) {
3981fcf3ce44SJohn Forte 		int instance = ddi_get_instance(qlt->dip);
3982c4ddbbe1SDaniel Beauregard 
3983c4ddbbe1SDaniel Beauregard 		EL(qlt, "implicit logout reveived portid = %xh\n", portid);
3984fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "qlt(%d): implicit logout completion for 0x%x"
3985fcf3ce44SJohn Forte 		    " received when driver wasn't waiting for it",
3986fcf3ce44SJohn Forte 		    instance, portid);
3987fcf3ce44SJohn Forte 		mutex_exit(&qlt->preq_lock);
3988fcf3ce44SJohn Forte 		return;
3989fcf3ce44SJohn Forte 	}
3990fcf3ce44SJohn Forte 
3991fcf3ce44SJohn Forte 	if (status != 0) {
3992c4ddbbe1SDaniel Beauregard 		EL(qlt, "implicit logout completed for %xh with status %xh, "
3993c4ddbbe1SDaniel Beauregard 		    "subcode1 %xh subcode2 %xh\n", portid, status, subcode1,
3994c4ddbbe1SDaniel Beauregard 		    subcode2);
3995c4ddbbe1SDaniel Beauregard 		if (status == 0x31 && subcode1 == 0x0a) {
3996fcf3ce44SJohn Forte 			qlt->rp_dereg_status = FCT_SUCCESS;
3997c4ddbbe1SDaniel Beauregard 		} else {
3998c4ddbbe1SDaniel Beauregard 			EL(qlt, "implicit logout portid=%xh, status=%xh, "
3999c4ddbbe1SDaniel Beauregard 			    "subcode1=%xh, subcode2=%xh\n", portid, status,
4000c4ddbbe1SDaniel Beauregard 			    subcode1, subcode2);
4001fcf3ce44SJohn Forte 			qlt->rp_dereg_status =
4002fcf3ce44SJohn Forte 			    QLT_FIRMWARE_ERROR(status, subcode1, subcode2);
4003c4ddbbe1SDaniel Beauregard 		}
4004fcf3ce44SJohn Forte 	} else {
4005fcf3ce44SJohn Forte 		qlt->rp_dereg_status = FCT_SUCCESS;
4006fcf3ce44SJohn Forte 	}
4007fcf3ce44SJohn Forte 	cv_signal(&qlt->rp_dereg_cv);
4008fcf3ce44SJohn Forte 	mutex_exit(&qlt->preq_lock);
4009fcf3ce44SJohn Forte }
4010fcf3ce44SJohn Forte 
4011fcf3ce44SJohn Forte /*
4012fcf3ce44SJohn Forte  * Note that when an ELS is aborted, the regular or aborted completion
4013fcf3ce44SJohn Forte  * (if any) gets posted before the abort IOCB comes back on response queue.
4014fcf3ce44SJohn Forte  */
4015fcf3ce44SJohn Forte static void
4016fcf3ce44SJohn Forte qlt_handle_unsol_els_completion(qlt_state_t *qlt, uint8_t *rsp)
4017fcf3ce44SJohn Forte {
4018fcf3ce44SJohn Forte 	char		info[160];
4019fcf3ce44SJohn Forte 	fct_cmd_t	*cmd;
4020fcf3ce44SJohn Forte 	qlt_cmd_t	*qcmd;
4021fcf3ce44SJohn Forte 	uint32_t	hndl;
4022fcf3ce44SJohn Forte 	uint32_t	subcode1, subcode2;
4023fcf3ce44SJohn Forte 	uint16_t	status;
4024fcf3ce44SJohn Forte 
4025fcf3ce44SJohn Forte 	hndl = QMEM_RD32(qlt, rsp+4);
4026fcf3ce44SJohn Forte 	status = QMEM_RD16(qlt, rsp+8);
4027fcf3ce44SJohn Forte 	subcode1 = QMEM_RD32(qlt, rsp+0x24);
4028fcf3ce44SJohn Forte 	subcode2 = QMEM_RD32(qlt, rsp+0x28);
4029fcf3ce44SJohn Forte 
4030fcf3ce44SJohn Forte 	if (!CMD_HANDLE_VALID(hndl)) {
4031c4ddbbe1SDaniel Beauregard 		EL(qlt, "handle = %xh\n", hndl);
4032fcf3ce44SJohn Forte 		/*
4033fcf3ce44SJohn Forte 		 * This cannot happen for unsol els completion. This can
4034fcf3ce44SJohn Forte 		 * only happen when abort for an unsol els completes.
4035fcf3ce44SJohn Forte 		 * This condition indicates a firmware bug.
4036fcf3ce44SJohn Forte 		 */
4037fcf3ce44SJohn Forte 		(void) snprintf(info, 160, "qlt_handle_unsol_els_completion: "
4038fcf3ce44SJohn Forte 		    "Invalid handle: hndl-%x, status-%x/%x/%x, rsp-%p",
4039fcf3ce44SJohn Forte 		    hndl, status, subcode1, subcode2, (void *)rsp);
4040fcf3ce44SJohn Forte 		info[159] = 0;
4041fcf3ce44SJohn Forte 		(void) fct_port_shutdown(qlt->qlt_port,
4042fcf3ce44SJohn Forte 		    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET |
4043fcf3ce44SJohn Forte 		    STMF_RFLAG_COLLECT_DEBUG_DUMP, info);
4044fcf3ce44SJohn Forte 		return;
4045fcf3ce44SJohn Forte 	}
4046fcf3ce44SJohn Forte 
4047fcf3ce44SJohn Forte 	if (status == 5) {
4048fcf3ce44SJohn Forte 		/*
4049fcf3ce44SJohn Forte 		 * When an unsolicited els is aborted, the abort is done
4050fcf3ce44SJohn Forte 		 * by a ELSPT iocb with abort control. This is the aborted IOCB
4051fcf3ce44SJohn Forte 		 * and not the abortee. We will do the cleanup when the
4052fcf3ce44SJohn Forte 		 * IOCB which caused the abort, returns.
4053fcf3ce44SJohn Forte 		 */
4054c4ddbbe1SDaniel Beauregard 		EL(qlt, "status = %xh\n", status);
4055fcf3ce44SJohn Forte 		stmf_trace(0, "--UNSOL ELS returned with status 5 --");
4056fcf3ce44SJohn Forte 		return;
4057fcf3ce44SJohn Forte 	}
4058fcf3ce44SJohn Forte 
4059fcf3ce44SJohn Forte 	cmd = fct_handle_to_cmd(qlt->qlt_port, hndl);
4060fcf3ce44SJohn Forte 	if (cmd == NULL) {
4061c4ddbbe1SDaniel Beauregard 		EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", hndl);
4062fcf3ce44SJohn Forte 		/*
4063fcf3ce44SJohn Forte 		 * Now why would this happen ???
4064fcf3ce44SJohn Forte 		 */
4065fcf3ce44SJohn Forte 		(void) snprintf(info, 160,
4066fcf3ce44SJohn Forte 		    "qlt_handle_unsol_els_completion: can not "
4067fcf3ce44SJohn Forte 		    "get cmd, hndl-%x, status-%x, rsp-%p", hndl, status,
4068fcf3ce44SJohn Forte 		    (void *)rsp);
4069fcf3ce44SJohn Forte 		info[159] = 0;
4070fcf3ce44SJohn Forte 		(void) fct_port_shutdown(qlt->qlt_port,
4071fcf3ce44SJohn Forte 		    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
4072fcf3ce44SJohn Forte 
4073fcf3ce44SJohn Forte 		return;
4074fcf3ce44SJohn Forte 	}
4075fcf3ce44SJohn Forte 
4076fcf3ce44SJohn Forte 	ASSERT(cmd->cmd_type == FCT_CMD_RCVD_ELS);
4077fcf3ce44SJohn Forte 	qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
4078fcf3ce44SJohn Forte 	if (qcmd->flags & QLT_CMD_ABORTING) {
4079fcf3ce44SJohn Forte 		/*
4080fcf3ce44SJohn Forte 		 * This is the same case as "if (status == 5)" above. The
4081fcf3ce44SJohn Forte 		 * only difference is that in this case the firmware actually
4082fcf3ce44SJohn Forte 		 * finished sending the response. So the abort attempt will
4083fcf3ce44SJohn Forte 		 * come back with status ?. We will handle it there.
4084fcf3ce44SJohn Forte 		 */
4085fcf3ce44SJohn Forte 		stmf_trace(0, "--UNSOL ELS finished while we are trying to "
4086fcf3ce44SJohn Forte 		    "abort it");
4087fcf3ce44SJohn Forte 		return;
4088fcf3ce44SJohn Forte 	}
4089fcf3ce44SJohn Forte 
4090fcf3ce44SJohn Forte 	if (qcmd->dbuf != NULL) {
4091fcf3ce44SJohn Forte 		qlt_dmem_free(NULL, qcmd->dbuf);
4092fcf3ce44SJohn Forte 		qcmd->dbuf = NULL;
4093fcf3ce44SJohn Forte 	}
4094fcf3ce44SJohn Forte 
4095fcf3ce44SJohn Forte 	if (status == 0) {
4096fcf3ce44SJohn Forte 		fct_send_response_done(cmd, FCT_SUCCESS, FCT_IOF_FCA_DONE);
4097fcf3ce44SJohn Forte 	} else {
4098fcf3ce44SJohn Forte 		fct_send_response_done(cmd,
4099fcf3ce44SJohn Forte 		    QLT_FIRMWARE_ERROR(status, subcode1, subcode2), 0);
4100fcf3ce44SJohn Forte 	}
4101fcf3ce44SJohn Forte }
4102fcf3ce44SJohn Forte 
4103fcf3ce44SJohn Forte static void
4104fcf3ce44SJohn Forte qlt_handle_unsol_els_abort_completion(qlt_state_t *qlt, uint8_t *rsp)
4105fcf3ce44SJohn Forte {
4106fcf3ce44SJohn Forte 	char		info[160];
4107fcf3ce44SJohn Forte 	fct_cmd_t	*cmd;
4108fcf3ce44SJohn Forte 	qlt_cmd_t	*qcmd;
4109fcf3ce44SJohn Forte 	uint32_t	hndl;
4110fcf3ce44SJohn Forte 	uint32_t	subcode1, subcode2;
4111fcf3ce44SJohn Forte 	uint16_t	status;
4112fcf3ce44SJohn Forte 
4113fcf3ce44SJohn Forte 	hndl = QMEM_RD32(qlt, rsp+4);
4114fcf3ce44SJohn Forte 	status = QMEM_RD16(qlt, rsp+8);
4115fcf3ce44SJohn Forte 	subcode1 = QMEM_RD32(qlt, rsp+0x24);
4116fcf3ce44SJohn Forte 	subcode2 = QMEM_RD32(qlt, rsp+0x28);
4117fcf3ce44SJohn Forte 
4118fcf3ce44SJohn Forte 	if (!CMD_HANDLE_VALID(hndl)) {
4119c4ddbbe1SDaniel Beauregard 		EL(qlt, "handle = %xh\n", hndl);
4120fcf3ce44SJohn Forte 		ASSERT(hndl == 0);
4121fcf3ce44SJohn Forte 		/*
4122fcf3ce44SJohn Forte 		 * Someone has requested to abort it, but no one is waiting for
4123fcf3ce44SJohn Forte 		 * this completion.
4124fcf3ce44SJohn Forte 		 */
4125fcf3ce44SJohn Forte 		if ((status != 0) && (status != 8)) {
4126c4ddbbe1SDaniel Beauregard 			EL(qlt, "status = %xh\n", status);
4127fcf3ce44SJohn Forte 			/*
4128fcf3ce44SJohn Forte 			 * There could be exchange resource leakage, so
4129fcf3ce44SJohn Forte 			 * throw HBA fatal error event now
4130fcf3ce44SJohn Forte 			 */
4131fcf3ce44SJohn Forte 			(void) snprintf(info, 160,
4132fcf3ce44SJohn Forte 			    "qlt_handle_unsol_els_abort_completion: "
4133fcf3ce44SJohn Forte 			    "Invalid handle: hndl-%x, status-%x/%x/%x, rsp-%p",
4134fcf3ce44SJohn Forte 			    hndl, status, subcode1, subcode2, (void *)rsp);
4135fcf3ce44SJohn Forte 			info[159] = 0;
4136fcf3ce44SJohn Forte 			(void) fct_port_shutdown(qlt->qlt_port,
4137fcf3ce44SJohn Forte 			    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET |
4138fcf3ce44SJohn Forte 			    STMF_RFLAG_COLLECT_DEBUG_DUMP, info);
4139fcf3ce44SJohn Forte 			return;
4140fcf3ce44SJohn Forte 		}
4141fcf3ce44SJohn Forte 
4142fcf3ce44SJohn Forte 		return;
4143fcf3ce44SJohn Forte 	}
4144fcf3ce44SJohn Forte 
4145fcf3ce44SJohn Forte 	cmd = fct_handle_to_cmd(qlt->qlt_port, hndl);
4146fcf3ce44SJohn Forte 	if (cmd == NULL) {
4147c4ddbbe1SDaniel Beauregard 		EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", hndl);
4148fcf3ce44SJohn Forte 		/*
4149fcf3ce44SJohn Forte 		 * Why would this happen ??
4150fcf3ce44SJohn Forte 		 */
4151fcf3ce44SJohn Forte 		(void) snprintf(info, 160,
4152fcf3ce44SJohn Forte 		    "qlt_handle_unsol_els_abort_completion: can not get "
4153fcf3ce44SJohn Forte 		    "cmd, hndl-%x, status-%x, rsp-%p", hndl, status,
4154fcf3ce44SJohn Forte 		    (void *)rsp);
4155fcf3ce44SJohn Forte 		info[159] = 0;
4156fcf3ce44SJohn Forte 		(void) fct_port_shutdown(qlt->qlt_port,
4157fcf3ce44SJohn Forte 		    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
4158fcf3ce44SJohn Forte 
4159fcf3ce44SJohn Forte 		return;
4160fcf3ce44SJohn Forte 	}
4161fcf3ce44SJohn Forte 
4162fcf3ce44SJohn Forte 	ASSERT(cmd->cmd_type == FCT_CMD_RCVD_ELS);
4163fcf3ce44SJohn Forte 	qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
4164fcf3ce44SJohn Forte 	ASSERT(qcmd->flags & QLT_CMD_ABORTING);
4165fcf3ce44SJohn Forte 
4166fcf3ce44SJohn Forte 	if (qcmd->dbuf != NULL) {
4167fcf3ce44SJohn Forte 		qlt_dmem_free(NULL, qcmd->dbuf);
4168fcf3ce44SJohn Forte 		qcmd->dbuf = NULL;
4169fcf3ce44SJohn Forte 	}
4170fcf3ce44SJohn Forte 
4171fcf3ce44SJohn Forte 	if (status == 0) {
4172fcf3ce44SJohn Forte 		fct_cmd_fca_aborted(cmd, FCT_ABORT_SUCCESS, FCT_IOF_FCA_DONE);
4173fcf3ce44SJohn Forte 	} else if (status == 8) {
4174fcf3ce44SJohn Forte 		fct_cmd_fca_aborted(cmd, FCT_NOT_FOUND, FCT_IOF_FCA_DONE);
4175fcf3ce44SJohn Forte 	} else {
4176fcf3ce44SJohn Forte 		fct_cmd_fca_aborted(cmd,
4177fcf3ce44SJohn Forte 		    QLT_FIRMWARE_ERROR(status, subcode1, subcode2), 0);
4178fcf3ce44SJohn Forte 	}
4179fcf3ce44SJohn Forte }
4180fcf3ce44SJohn Forte 
4181fcf3ce44SJohn Forte static void
4182fcf3ce44SJohn Forte qlt_handle_sol_els_completion(qlt_state_t *qlt, uint8_t *rsp)
4183fcf3ce44SJohn Forte {
4184fcf3ce44SJohn Forte 	char		info[160];
4185fcf3ce44SJohn Forte 	fct_cmd_t	*cmd;
4186fcf3ce44SJohn Forte 	fct_els_t	*els;
4187fcf3ce44SJohn Forte 	qlt_cmd_t	*qcmd;
4188fcf3ce44SJohn Forte 	uint32_t	hndl;
4189fcf3ce44SJohn Forte 	uint32_t	subcode1, subcode2;
4190fcf3ce44SJohn Forte 	uint16_t	status;
4191fcf3ce44SJohn Forte 
4192fcf3ce44SJohn Forte 	hndl = QMEM_RD32(qlt, rsp+4);
4193fcf3ce44SJohn Forte 	status = QMEM_RD16(qlt, rsp+8);
4194fcf3ce44SJohn Forte 	subcode1 = QMEM_RD32(qlt, rsp+0x24);
4195fcf3ce44SJohn Forte 	subcode2 = QMEM_RD32(qlt, rsp+0x28);
4196fcf3ce44SJohn Forte 
4197fcf3ce44SJohn Forte 	if (!CMD_HANDLE_VALID(hndl)) {
4198c4ddbbe1SDaniel Beauregard 		EL(qlt, "handle = %xh\n", hndl);
4199fcf3ce44SJohn Forte 		/*
4200fcf3ce44SJohn Forte 		 * This cannot happen for sol els completion.
4201fcf3ce44SJohn Forte 		 */
4202fcf3ce44SJohn Forte 		(void) snprintf(info, 160, "qlt_handle_sol_els_completion: "
4203fcf3ce44SJohn Forte 		    "Invalid handle: hndl-%x, status-%x/%x/%x, rsp-%p",
4204fcf3ce44SJohn Forte 		    hndl, status, subcode1, subcode2, (void *)rsp);
4205fcf3ce44SJohn Forte 		info[159] = 0;
4206fcf3ce44SJohn Forte 		(void) fct_port_shutdown(qlt->qlt_port,
4207fcf3ce44SJohn Forte 		    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET |
4208fcf3ce44SJohn Forte 		    STMF_RFLAG_COLLECT_DEBUG_DUMP, info);
4209fcf3ce44SJohn Forte 		return;
4210fcf3ce44SJohn Forte 	}
4211fcf3ce44SJohn Forte 
4212fcf3ce44SJohn Forte 	cmd = fct_handle_to_cmd(qlt->qlt_port, hndl);
4213fcf3ce44SJohn Forte 	if (cmd == NULL) {
4214c4ddbbe1SDaniel Beauregard 		EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", hndl);
4215fcf3ce44SJohn Forte 		(void) snprintf(info, 160,
4216fcf3ce44SJohn Forte 		    "qlt_handle_sol_els_completion: can not "
4217fcf3ce44SJohn Forte 		    "get cmd, hndl-%x, status-%x, rsp-%p", hndl, status,
4218fcf3ce44SJohn Forte 		    (void *)rsp);
4219fcf3ce44SJohn Forte 		info[159] = 0;
4220fcf3ce44SJohn Forte 		(void) fct_port_shutdown(qlt->qlt_port,
4221fcf3ce44SJohn Forte 		    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
4222fcf3ce44SJohn Forte 
4223fcf3ce44SJohn Forte 		return;
4224fcf3ce44SJohn Forte 	}
4225fcf3ce44SJohn Forte 
4226fcf3ce44SJohn Forte 	ASSERT(cmd->cmd_type == FCT_CMD_SOL_ELS);
4227fcf3ce44SJohn Forte 	els = (fct_els_t *)cmd->cmd_specific;
4228fcf3ce44SJohn Forte 	qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
4229fcf3ce44SJohn Forte 	qcmd->fw_xchg_addr = QMEM_RD32(qlt, (&rsp[0x10]));
4230fcf3ce44SJohn Forte 
4231fcf3ce44SJohn Forte 	if (qcmd->flags & QLT_CMD_ABORTING) {
4232fcf3ce44SJohn Forte 		/*
4233fcf3ce44SJohn Forte 		 * We will handle it when the ABORT IO IOCB returns.
4234fcf3ce44SJohn Forte 		 */
4235fcf3ce44SJohn Forte 		return;
4236fcf3ce44SJohn Forte 	}
4237fcf3ce44SJohn Forte 
4238fcf3ce44SJohn Forte 	if (qcmd->dbuf != NULL) {
4239fcf3ce44SJohn Forte 		if (status == 0) {
4240fcf3ce44SJohn Forte 			qlt_dmem_dma_sync(qcmd->dbuf, DDI_DMA_SYNC_FORKERNEL);
4241fcf3ce44SJohn Forte 			bcopy(qcmd->dbuf->db_sglist[0].seg_addr +
4242fcf3ce44SJohn Forte 			    qcmd->param.resp_offset,
4243d8c54e3dSSam Cramer 			    els->els_resp_payload, els->els_resp_size);
4244fcf3ce44SJohn Forte 		}
4245fcf3ce44SJohn Forte 		qlt_dmem_free(NULL, qcmd->dbuf);
4246fcf3ce44SJohn Forte 		qcmd->dbuf = NULL;
4247fcf3ce44SJohn Forte 	}
4248fcf3ce44SJohn Forte 
4249fcf3ce44SJohn Forte 	if (status == 0) {
4250fcf3ce44SJohn Forte 		fct_send_cmd_done(cmd, FCT_SUCCESS, FCT_IOF_FCA_DONE);
4251fcf3ce44SJohn Forte 	} else {
4252fcf3ce44SJohn Forte 		fct_send_cmd_done(cmd,
4253fcf3ce44SJohn Forte 		    QLT_FIRMWARE_ERROR(status, subcode1, subcode2), 0);
4254fcf3ce44SJohn Forte 	}
4255fcf3ce44SJohn Forte }
4256fcf3ce44SJohn Forte 
4257fcf3ce44SJohn Forte static void
4258fcf3ce44SJohn Forte qlt_handle_ct_completion(qlt_state_t *qlt, uint8_t *rsp)
4259fcf3ce44SJohn Forte {
4260fcf3ce44SJohn Forte 	fct_cmd_t	*cmd;
4261fcf3ce44SJohn Forte 	fct_sol_ct_t	*ct;
4262fcf3ce44SJohn Forte 	qlt_cmd_t	*qcmd;
4263fcf3ce44SJohn Forte 	uint32_t	 hndl;
4264fcf3ce44SJohn Forte 	uint16_t	 status;
4265fcf3ce44SJohn Forte 	char		 info[160];
4266fcf3ce44SJohn Forte 
4267fcf3ce44SJohn Forte 	hndl = QMEM_RD32(qlt, rsp+4);
4268fcf3ce44SJohn Forte 	status = QMEM_RD16(qlt, rsp+8);
4269fcf3ce44SJohn Forte 
4270fcf3ce44SJohn Forte 	if (!CMD_HANDLE_VALID(hndl)) {
4271c4ddbbe1SDaniel Beauregard 		EL(qlt, "handle = %xh\n", hndl);
4272fcf3ce44SJohn Forte 		/*
4273fcf3ce44SJohn Forte 		 * Solicited commands will always have a valid handle.
4274fcf3ce44SJohn Forte 		 */
4275fcf3ce44SJohn Forte 		(void) snprintf(info, 160, "qlt_handle_ct_completion: hndl-"
4276fcf3ce44SJohn Forte 		    "%x, status-%x, rsp-%p", hndl, status, (void *)rsp);
4277fcf3ce44SJohn Forte 		info[159] = 0;
4278fcf3ce44SJohn Forte 		(void) fct_port_shutdown(qlt->qlt_port,
4279fcf3ce44SJohn Forte 		    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET |
4280fcf3ce44SJohn Forte 		    STMF_RFLAG_COLLECT_DEBUG_DUMP, info);
4281fcf3ce44SJohn Forte 		return;
4282fcf3ce44SJohn Forte 	}
4283fcf3ce44SJohn Forte 
4284fcf3ce44SJohn Forte 	cmd = fct_handle_to_cmd(qlt->qlt_port, hndl);
4285fcf3ce44SJohn Forte 	if (cmd == NULL) {
4286c4ddbbe1SDaniel Beauregard 		EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", hndl);
4287fcf3ce44SJohn Forte 		(void) snprintf(info, 160,
4288fcf3ce44SJohn Forte 		    "qlt_handle_ct_completion: cannot find "
4289fcf3ce44SJohn Forte 		    "cmd, hndl-%x, status-%x, rsp-%p", hndl, status,
4290fcf3ce44SJohn Forte 		    (void *)rsp);
4291fcf3ce44SJohn Forte 		info[159] = 0;
4292fcf3ce44SJohn Forte 		(void) fct_port_shutdown(qlt->qlt_port,
4293fcf3ce44SJohn Forte 		    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
4294fcf3ce44SJohn Forte 
4295fcf3ce44SJohn Forte 		return;
4296fcf3ce44SJohn Forte 	}
4297fcf3ce44SJohn Forte 
4298fcf3ce44SJohn Forte 	ct = (fct_sol_ct_t *)cmd->cmd_specific;
4299fcf3ce44SJohn Forte 	qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
4300fcf3ce44SJohn Forte 	ASSERT(cmd->cmd_type == FCT_CMD_SOL_CT);
4301fcf3ce44SJohn Forte 
4302fcf3ce44SJohn Forte 	if (qcmd->flags & QLT_CMD_ABORTING) {
4303fcf3ce44SJohn Forte 		/*
4304fcf3ce44SJohn Forte 		 * We will handle it when ABORT IO IOCB returns;
4305fcf3ce44SJohn Forte 		 */
4306fcf3ce44SJohn Forte 		return;
4307fcf3ce44SJohn Forte 	}
4308fcf3ce44SJohn Forte 
4309fcf3ce44SJohn Forte 	ASSERT(qcmd->dbuf);
4310fcf3ce44SJohn Forte 	if (status == 0) {
4311fcf3ce44SJohn Forte 		qlt_dmem_dma_sync(qcmd->dbuf, DDI_DMA_SYNC_FORKERNEL);
4312fcf3ce44SJohn Forte 		bcopy(qcmd->dbuf->db_sglist[0].seg_addr +
4313fcf3ce44SJohn Forte 		    qcmd->param.resp_offset,
4314fcf3ce44SJohn Forte 		    ct->ct_resp_payload, ct->ct_resp_size);
4315fcf3ce44SJohn Forte 	}
4316fcf3ce44SJohn Forte 	qlt_dmem_free(NULL, qcmd->dbuf);
4317fcf3ce44SJohn Forte 	qcmd->dbuf = NULL;
4318fcf3ce44SJohn Forte 
4319fcf3ce44SJohn Forte 	if (status == 0) {
4320fcf3ce44SJohn Forte 		fct_send_cmd_done(cmd, FCT_SUCCESS, FCT_IOF_FCA_DONE);
4321fcf3ce44SJohn Forte 	} else {
4322fcf3ce44SJohn Forte 		fct_send_cmd_done(cmd, QLT_FIRMWARE_ERROR(status, 0, 0), 0);
4323fcf3ce44SJohn Forte 	}
4324fcf3ce44SJohn Forte }
4325fcf3ce44SJohn Forte 
4326fcf3ce44SJohn Forte static void
4327fcf3ce44SJohn Forte qlt_handle_ctio_completion(qlt_state_t *qlt, uint8_t *rsp)
4328fcf3ce44SJohn Forte {
4329fcf3ce44SJohn Forte 	fct_cmd_t	*cmd;
4330fcf3ce44SJohn Forte 	scsi_task_t	*task;
4331fcf3ce44SJohn Forte 	qlt_cmd_t	*qcmd;
4332fcf3ce44SJohn Forte 	stmf_data_buf_t	*dbuf;
4333fcf3ce44SJohn Forte 	fct_status_t	fc_st;
4334fcf3ce44SJohn Forte 	uint32_t	iof = 0;
4335fcf3ce44SJohn Forte 	uint32_t	hndl;
4336fcf3ce44SJohn Forte 	uint16_t	status;
4337fcf3ce44SJohn Forte 	uint16_t	flags;
4338fcf3ce44SJohn Forte 	uint8_t		abort_req;
4339fcf3ce44SJohn Forte 	uint8_t		n;
4340fcf3ce44SJohn Forte 	char		info[160];
4341fcf3ce44SJohn Forte 
4342fcf3ce44SJohn Forte 	/* XXX: Check validity of the IOCB by checking 4th byte. */
4343fcf3ce44SJohn Forte 	hndl = QMEM_RD32(qlt, rsp+4);
4344fcf3ce44SJohn Forte 	status = QMEM_RD16(qlt, rsp+8);
4345fcf3ce44SJohn Forte 	flags = QMEM_RD16(qlt, rsp+0x1a);
4346fcf3ce44SJohn Forte 	n = rsp[2];
4347fcf3ce44SJohn Forte 
4348fcf3ce44SJohn Forte 	if (!CMD_HANDLE_VALID(hndl)) {
4349c4ddbbe1SDaniel Beauregard 		EL(qlt, "handle = %xh\n", hndl);
4350fcf3ce44SJohn Forte 		ASSERT(hndl == 0);
4351fcf3ce44SJohn Forte 		/*
4352fcf3ce44SJohn Forte 		 * Someone has requested to abort it, but no one is waiting for
4353fcf3ce44SJohn Forte 		 * this completion.
4354fcf3ce44SJohn Forte 		 */
4355c4ddbbe1SDaniel Beauregard 		EL(qlt, "hndl-%xh, status-%xh, rsp-%p\n", hndl, status,
4356c4ddbbe1SDaniel Beauregard 		    (void *)rsp);
4357fcf3ce44SJohn Forte 		if ((status != 1) && (status != 2)) {
4358c4ddbbe1SDaniel Beauregard 			EL(qlt, "status = %xh\n", status);
4359fcf3ce44SJohn Forte 			/*
4360fcf3ce44SJohn Forte 			 * There could be exchange resource leakage, so
4361fcf3ce44SJohn Forte 			 * throw HBA fatal error event now
4362fcf3ce44SJohn Forte 			 */
4363fcf3ce44SJohn Forte 			(void) snprintf(info, 160,
4364fcf3ce44SJohn Forte 			    "qlt_handle_ctio_completion: hndl-"
4365fcf3ce44SJohn Forte 			    "%x, status-%x, rsp-%p", hndl, status, (void *)rsp);
4366fcf3ce44SJohn Forte 			info[159] = 0;
4367fcf3ce44SJohn Forte 			(void) fct_port_shutdown(qlt->qlt_port,
4368fcf3ce44SJohn Forte 			    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
4369fcf3ce44SJohn Forte 
4370fcf3ce44SJohn Forte 		}
4371fcf3ce44SJohn Forte 
4372fcf3ce44SJohn Forte 		return;
4373fcf3ce44SJohn Forte 	}
4374fcf3ce44SJohn Forte 
4375fcf3ce44SJohn Forte 	if (flags & BIT_14) {
4376fcf3ce44SJohn Forte 		abort_req = 1;
4377c4ddbbe1SDaniel Beauregard 		EL(qlt, "abort: hndl-%x, status-%x, rsp-%p\n", hndl, status,
4378fcf3ce44SJohn Forte 		    (void *)rsp);
4379fcf3ce44SJohn Forte 	} else {
4380fcf3ce44SJohn Forte 		abort_req = 0;
4381fcf3ce44SJohn Forte 	}
4382fcf3ce44SJohn Forte 
4383fcf3ce44SJohn Forte 	cmd = fct_handle_to_cmd(qlt->qlt_port, hndl);
4384fcf3ce44SJohn Forte 	if (cmd == NULL) {
4385c4ddbbe1SDaniel Beauregard 		EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", hndl);
4386fcf3ce44SJohn Forte 		(void) snprintf(info, 160,
4387fcf3ce44SJohn Forte 		    "qlt_handle_ctio_completion: cannot find "
4388fcf3ce44SJohn Forte 		    "cmd, hndl-%x, status-%x, rsp-%p", hndl, status,
4389fcf3ce44SJohn Forte 		    (void *)rsp);
4390fcf3ce44SJohn Forte 		info[159] = 0;
4391fcf3ce44SJohn Forte 		(void) fct_port_shutdown(qlt->qlt_port,
4392fcf3ce44SJohn Forte 		    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
4393fcf3ce44SJohn Forte 
4394fcf3ce44SJohn Forte 		return;
4395fcf3ce44SJohn Forte 	}
4396fcf3ce44SJohn Forte 
4397fcf3ce44SJohn Forte 	task = (scsi_task_t *)cmd->cmd_specific;
4398fcf3ce44SJohn Forte 	qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
4399fcf3ce44SJohn Forte 	if (qcmd->dbuf_rsp_iu) {
4400fcf3ce44SJohn Forte 		ASSERT((flags & (BIT_6 | BIT_7)) == BIT_7);
4401fcf3ce44SJohn Forte 		qlt_dmem_free(NULL, qcmd->dbuf_rsp_iu);
4402fcf3ce44SJohn Forte 		qcmd->dbuf_rsp_iu = NULL;
4403fcf3ce44SJohn Forte 	}
4404fcf3ce44SJohn Forte 
4405fcf3ce44SJohn Forte 	if ((status == 1) || (status == 2)) {
4406fcf3ce44SJohn Forte 		if (abort_req) {
4407fcf3ce44SJohn Forte 			fc_st = FCT_ABORT_SUCCESS;
4408fcf3ce44SJohn Forte 			iof = FCT_IOF_FCA_DONE;
4409fcf3ce44SJohn Forte 		} else {
4410fcf3ce44SJohn Forte 			fc_st = FCT_SUCCESS;
4411fcf3ce44SJohn Forte 			if (flags & BIT_15) {
4412fcf3ce44SJohn Forte 				iof = FCT_IOF_FCA_DONE;
4413fcf3ce44SJohn Forte 			}
4414fcf3ce44SJohn Forte 		}
4415fcf3ce44SJohn Forte 	} else {
4416c4ddbbe1SDaniel Beauregard 		EL(qlt, "status = %xh\n", status);
4417fcf3ce44SJohn Forte 		if ((status == 8) && abort_req) {
4418fcf3ce44SJohn Forte 			fc_st = FCT_NOT_FOUND;
4419fcf3ce44SJohn Forte 			iof = FCT_IOF_FCA_DONE;
4420fcf3ce44SJohn Forte 		} else {
4421fcf3ce44SJohn Forte 			fc_st = QLT_FIRMWARE_ERROR(status, 0, 0);
4422fcf3ce44SJohn Forte 		}
4423fcf3ce44SJohn Forte 	}
4424fcf3ce44SJohn Forte 	dbuf = NULL;
4425fcf3ce44SJohn Forte 	if (((n & BIT_7) == 0) && (!abort_req)) {
4426fcf3ce44SJohn Forte 		/* A completion of data xfer */
4427fcf3ce44SJohn Forte 		if (n == 0) {
4428fcf3ce44SJohn Forte 			dbuf = qcmd->dbuf;
4429fcf3ce44SJohn Forte 		} else {
4430fcf3ce44SJohn Forte 			dbuf = stmf_handle_to_buf(task, n);
4431fcf3ce44SJohn Forte 		}
4432fcf3ce44SJohn Forte 
4433fcf3ce44SJohn Forte 		ASSERT(dbuf != NULL);
4434fcf3ce44SJohn Forte 		if (dbuf->db_flags & DB_DIRECTION_FROM_RPORT)
4435fcf3ce44SJohn Forte 			qlt_dmem_dma_sync(dbuf, DDI_DMA_SYNC_FORCPU);
4436fcf3ce44SJohn Forte 		if (flags & BIT_15) {
4437c4ddbbe1SDaniel Beauregard 			dbuf->db_flags = (uint16_t)(dbuf->db_flags |
4438c4ddbbe1SDaniel Beauregard 			    DB_STATUS_GOOD_SENT);
4439fcf3ce44SJohn Forte 		}
4440fcf3ce44SJohn Forte 
4441fcf3ce44SJohn Forte 		dbuf->db_xfer_status = fc_st;
4442fcf3ce44SJohn Forte 		fct_scsi_data_xfer_done(cmd, dbuf, iof);
4443fcf3ce44SJohn Forte 		return;
4444fcf3ce44SJohn Forte 	}
4445fcf3ce44SJohn Forte 	if (!abort_req) {
4446fcf3ce44SJohn Forte 		/*
4447fcf3ce44SJohn Forte 		 * This was just a pure status xfer.
4448fcf3ce44SJohn Forte 		 */
4449fcf3ce44SJohn Forte 		fct_send_response_done(cmd, fc_st, iof);
4450fcf3ce44SJohn Forte 		return;
4451fcf3ce44SJohn Forte 	}
4452fcf3ce44SJohn Forte 
4453fcf3ce44SJohn Forte 	fct_cmd_fca_aborted(cmd, fc_st, iof);
4454fcf3ce44SJohn Forte }
4455fcf3ce44SJohn Forte 
4456fcf3ce44SJohn Forte static void
4457fcf3ce44SJohn Forte qlt_handle_sol_abort_completion(qlt_state_t *qlt, uint8_t *rsp)
4458fcf3ce44SJohn Forte {
4459fcf3ce44SJohn Forte 	char		info[80];
4460fcf3ce44SJohn Forte 	fct_cmd_t	*cmd;
4461fcf3ce44SJohn Forte 	qlt_cmd_t	*qcmd;
4462fcf3ce44SJohn Forte 	uint32_t	h;
4463fcf3ce44SJohn Forte 	uint16_t	status;
4464fcf3ce44SJohn Forte 
4465fcf3ce44SJohn Forte 	h = QMEM_RD32(qlt, rsp+4);
4466fcf3ce44SJohn Forte 	status = QMEM_RD16(qlt, rsp+8);
4467fcf3ce44SJohn Forte 
4468fcf3ce44SJohn Forte 	if (!CMD_HANDLE_VALID(h)) {
4469c4ddbbe1SDaniel Beauregard 		EL(qlt, "handle = %xh\n", h);
4470fcf3ce44SJohn Forte 		/*
4471fcf3ce44SJohn Forte 		 * Solicited commands always have a valid handle.
4472fcf3ce44SJohn Forte 		 */
4473fcf3ce44SJohn Forte 		(void) snprintf(info, 80,
4474fcf3ce44SJohn Forte 		    "qlt_handle_sol_abort_completion: hndl-"
4475fcf3ce44SJohn Forte 		    "%x, status-%x, rsp-%p", h, status, (void *)rsp);
4476fcf3ce44SJohn Forte 		info[79] = 0;
4477fcf3ce44SJohn Forte 		(void) fct_port_shutdown(qlt->qlt_port,
4478fcf3ce44SJohn Forte 		    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET |
4479fcf3ce44SJohn Forte 		    STMF_RFLAG_COLLECT_DEBUG_DUMP, info);
4480fcf3ce44SJohn Forte 		return;
4481fcf3ce44SJohn Forte 	}
4482fcf3ce44SJohn Forte 	cmd = fct_handle_to_cmd(qlt->qlt_port, h);
4483fcf3ce44SJohn Forte 	if (cmd == NULL) {
4484c4ddbbe1SDaniel Beauregard 		EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", h);
4485fcf3ce44SJohn Forte 		/*
4486fcf3ce44SJohn Forte 		 * What happened to the cmd ??
4487fcf3ce44SJohn Forte 		 */
4488fcf3ce44SJohn Forte 		(void) snprintf(info, 80,
4489fcf3ce44SJohn Forte 		    "qlt_handle_sol_abort_completion: cannot "
4490fcf3ce44SJohn Forte 		    "find cmd, hndl-%x, status-%x, rsp-%p", h, status,
4491fcf3ce44SJohn Forte 		    (void *)rsp);
4492fcf3ce44SJohn Forte 		info[79] = 0;
4493fcf3ce44SJohn Forte 		(void) fct_port_shutdown(qlt->qlt_port,
4494fcf3ce44SJohn Forte 		    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
4495fcf3ce44SJohn Forte 
4496fcf3ce44SJohn Forte 		return;
4497fcf3ce44SJohn Forte 	}
4498fcf3ce44SJohn Forte 
4499fcf3ce44SJohn Forte 	ASSERT((cmd->cmd_type == FCT_CMD_SOL_ELS) ||
4500fcf3ce44SJohn Forte 	    (cmd->cmd_type == FCT_CMD_SOL_CT));
4501fcf3ce44SJohn Forte 	qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
4502fcf3ce44SJohn Forte 	if (qcmd->dbuf != NULL) {
4503fcf3ce44SJohn Forte 		qlt_dmem_free(NULL, qcmd->dbuf);
4504fcf3ce44SJohn Forte 		qcmd->dbuf = NULL;
4505fcf3ce44SJohn Forte 	}
4506fcf3ce44SJohn Forte 	ASSERT(qcmd->flags & QLT_CMD_ABORTING);
4507fcf3ce44SJohn Forte 	if (status == 0) {
4508fcf3ce44SJohn Forte 		fct_cmd_fca_aborted(cmd, FCT_ABORT_SUCCESS, FCT_IOF_FCA_DONE);
4509fcf3ce44SJohn Forte 	} else if (status == 0x31) {
4510fcf3ce44SJohn Forte 		fct_cmd_fca_aborted(cmd, FCT_NOT_FOUND, FCT_IOF_FCA_DONE);
4511fcf3ce44SJohn Forte 	} else {
4512fcf3ce44SJohn Forte 		fct_cmd_fca_aborted(cmd, QLT_FIRMWARE_ERROR(status, 0, 0), 0);
4513fcf3ce44SJohn Forte 	}
4514fcf3ce44SJohn Forte }
4515fcf3ce44SJohn Forte 
4516fcf3ce44SJohn Forte static void
4517fcf3ce44SJohn Forte qlt_handle_rcvd_abts(qlt_state_t *qlt, uint8_t *resp)
4518fcf3ce44SJohn Forte {
4519fcf3ce44SJohn Forte 	qlt_abts_cmd_t	*qcmd;
4520fcf3ce44SJohn Forte 	fct_cmd_t	*cmd;
4521fcf3ce44SJohn Forte 	uint32_t	remote_portid;
4522fcf3ce44SJohn Forte 	char		info[160];
4523fcf3ce44SJohn Forte 
4524fcf3ce44SJohn Forte 	remote_portid = ((uint32_t)(QMEM_RD16(qlt, (&resp[0x18])))) |
4525fcf3ce44SJohn Forte 	    ((uint32_t)(resp[0x1A])) << 16;
4526fcf3ce44SJohn Forte 	cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_RCVD_ABTS,
4527fcf3ce44SJohn Forte 	    sizeof (qlt_abts_cmd_t), 0);
4528fcf3ce44SJohn Forte 	if (cmd == NULL) {
4529c4ddbbe1SDaniel Beauregard 		EL(qlt, "fct_alloc cmd==NULL\n");
4530fcf3ce44SJohn Forte 		(void) snprintf(info, 160,
4531fcf3ce44SJohn Forte 		    "qlt_handle_rcvd_abts: qlt-%p, can't "
4532fcf3ce44SJohn Forte 		    "allocate space for fct_cmd", (void *)qlt);
4533fcf3ce44SJohn Forte 		info[159] = 0;
4534fcf3ce44SJohn Forte 		(void) fct_port_shutdown(qlt->qlt_port,
4535fcf3ce44SJohn Forte 		    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
4536fcf3ce44SJohn Forte 		return;
4537fcf3ce44SJohn Forte 	}
4538fcf3ce44SJohn Forte 
4539fcf3ce44SJohn Forte 	resp[0xC] = resp[0xD] = resp[0xE] = 0;
4540fcf3ce44SJohn Forte 	qcmd = (qlt_abts_cmd_t *)cmd->cmd_fca_private;
4541fcf3ce44SJohn Forte 	bcopy(resp, qcmd->buf, IOCB_SIZE);
4542fcf3ce44SJohn Forte 	cmd->cmd_port = qlt->qlt_port;
4543fcf3ce44SJohn Forte 	cmd->cmd_rp_handle = QMEM_RD16(qlt, resp+0xA);
4544fcf3ce44SJohn Forte 	if (cmd->cmd_rp_handle == 0xFFFF)
4545fcf3ce44SJohn Forte 		cmd->cmd_rp_handle = FCT_HANDLE_NONE;
4546fcf3ce44SJohn Forte 
4547fcf3ce44SJohn Forte 	cmd->cmd_rportid = remote_portid;
4548fcf3ce44SJohn Forte 	cmd->cmd_lportid = ((uint32_t)(QMEM_RD16(qlt, (&resp[0x14])))) |
4549fcf3ce44SJohn Forte 	    ((uint32_t)(resp[0x16])) << 16;
4550fcf3ce44SJohn Forte 	cmd->cmd_oxid = QMEM_RD16(qlt, (&resp[0x26]));
4551fcf3ce44SJohn Forte 	cmd->cmd_rxid = QMEM_RD16(qlt, (&resp[0x24]));
4552fcf3ce44SJohn Forte 	fct_post_rcvd_cmd(cmd, 0);
4553fcf3ce44SJohn Forte }
4554fcf3ce44SJohn Forte 
4555fcf3ce44SJohn Forte static void
4556fcf3ce44SJohn Forte qlt_handle_abts_completion(qlt_state_t *qlt, uint8_t *resp)
4557fcf3ce44SJohn Forte {
4558fcf3ce44SJohn Forte 	uint16_t status;
4559fcf3ce44SJohn Forte 	char	info[80];
4560fcf3ce44SJohn Forte 
4561fcf3ce44SJohn Forte 	status = QMEM_RD16(qlt, resp+8);
4562fcf3ce44SJohn Forte 
4563fcf3ce44SJohn Forte 	if ((status == 0) || (status == 5)) {
4564fcf3ce44SJohn Forte 		return;
4565fcf3ce44SJohn Forte 	}
4566c4ddbbe1SDaniel Beauregard 	EL(qlt, "status = %xh\n", status);
4567fcf3ce44SJohn Forte 	(void) snprintf(info, 80, "ABTS completion failed %x/%x/%x resp_off %x",
4568fcf3ce44SJohn Forte 	    status, QMEM_RD32(qlt, resp+0x34), QMEM_RD32(qlt, resp+0x38),
4569fcf3ce44SJohn Forte 	    ((uint32_t)(qlt->resp_ndx_to_fw)) << 6);
4570fcf3ce44SJohn Forte 	info[79] = 0;
4571fcf3ce44SJohn Forte 	(void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR |
4572fcf3ce44SJohn Forte 	    STMF_RFLAG_RESET | STMF_RFLAG_COLLECT_DEBUG_DUMP, info);
4573fcf3ce44SJohn Forte }
4574fcf3ce44SJohn Forte 
4575fcf3ce44SJohn Forte #ifdef	DEBUG
4576fcf3ce44SJohn Forte uint32_t qlt_drop_abort_counter = 0;
4577fcf3ce44SJohn Forte #endif
4578fcf3ce44SJohn Forte 
4579fcf3ce44SJohn Forte fct_status_t
4580fcf3ce44SJohn Forte qlt_abort_cmd(struct fct_local_port *port, fct_cmd_t *cmd, uint32_t flags)
4581fcf3ce44SJohn Forte {
4582fcf3ce44SJohn Forte 	qlt_state_t *qlt = (qlt_state_t *)port->port_fca_private;
4583fcf3ce44SJohn Forte 
4584fcf3ce44SJohn Forte 	if ((qlt->qlt_state == FCT_STATE_OFFLINE) ||
4585fcf3ce44SJohn Forte 	    (qlt->qlt_state == FCT_STATE_OFFLINING)) {
4586fcf3ce44SJohn Forte 		return (FCT_NOT_FOUND);
4587fcf3ce44SJohn Forte 	}
4588fcf3ce44SJohn Forte 
4589fcf3ce44SJohn Forte #ifdef DEBUG
4590fcf3ce44SJohn Forte 	if (qlt_drop_abort_counter > 0) {
4591fcf3ce44SJohn Forte 		if (atomic_add_32_nv(&qlt_drop_abort_counter, -1) == 1)
4592fcf3ce44SJohn Forte 			return (FCT_SUCCESS);
4593fcf3ce44SJohn Forte 	}
4594fcf3ce44SJohn Forte #endif
4595fcf3ce44SJohn Forte 
4596fcf3ce44SJohn Forte 	if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
4597fcf3ce44SJohn Forte 		return (qlt_abort_unsol_scsi_cmd(qlt, cmd));
4598fcf3ce44SJohn Forte 	}
4599fcf3ce44SJohn Forte 
4600fcf3ce44SJohn Forte 	if (flags & FCT_IOF_FORCE_FCA_DONE) {
4601fcf3ce44SJohn Forte 		cmd->cmd_handle = 0;
4602fcf3ce44SJohn Forte 	}
4603fcf3ce44SJohn Forte 
4604fcf3ce44SJohn Forte 	if (cmd->cmd_type == FCT_CMD_RCVD_ABTS) {
4605fcf3ce44SJohn Forte 		return (qlt_send_abts_response(qlt, cmd, 1));
4606fcf3ce44SJohn Forte 	}
4607fcf3ce44SJohn Forte 
4608fcf3ce44SJohn Forte 	if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
4609fcf3ce44SJohn Forte 		return (qlt_abort_purex(qlt, cmd));
4610fcf3ce44SJohn Forte 	}
4611fcf3ce44SJohn Forte 
4612fcf3ce44SJohn Forte 	if ((cmd->cmd_type == FCT_CMD_SOL_ELS) ||
4613fcf3ce44SJohn Forte 	    (cmd->cmd_type == FCT_CMD_SOL_CT)) {
4614fcf3ce44SJohn Forte 		return (qlt_abort_sol_cmd(qlt, cmd));
4615fcf3ce44SJohn Forte 	}
4616c4ddbbe1SDaniel Beauregard 	EL(qlt, "cmd->cmd_type = %xh\n", cmd->cmd_type);
4617fcf3ce44SJohn Forte 
4618fcf3ce44SJohn Forte 	ASSERT(0);
4619fcf3ce44SJohn Forte 	return (FCT_FAILURE);
4620fcf3ce44SJohn Forte }
4621fcf3ce44SJohn Forte 
4622fcf3ce44SJohn Forte fct_status_t
4623fcf3ce44SJohn Forte qlt_abort_sol_cmd(qlt_state_t *qlt, fct_cmd_t *cmd)
4624fcf3ce44SJohn Forte {
4625fcf3ce44SJohn Forte 	uint8_t *req;
4626fcf3ce44SJohn Forte 	qlt_cmd_t *qcmd;
4627fcf3ce44SJohn Forte 
4628fcf3ce44SJohn Forte 	qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
4629c4ddbbe1SDaniel Beauregard 	qcmd->flags = (uint16_t)(qcmd->flags | QLT_CMD_ABORTING);
4630c4ddbbe1SDaniel Beauregard 	EL(qlt, "fctcmd-%p, cmd_handle-%xh\n", cmd, cmd->cmd_handle);
4631fcf3ce44SJohn Forte 
4632fcf3ce44SJohn Forte 	mutex_enter(&qlt->req_lock);
4633fcf3ce44SJohn Forte 	req = (uint8_t *)qlt_get_req_entries(qlt, 1);
4634fcf3ce44SJohn Forte 	if (req == NULL) {
4635fcf3ce44SJohn Forte 		mutex_exit(&qlt->req_lock);
4636fcf3ce44SJohn Forte 
4637fcf3ce44SJohn Forte 		return (FCT_BUSY);
4638fcf3ce44SJohn Forte 	}
4639fcf3ce44SJohn Forte 	bzero(req, IOCB_SIZE);
4640fcf3ce44SJohn Forte 	req[0] = 0x33; req[1] = 1;
4641fcf3ce44SJohn Forte 	QMEM_WR32(qlt, req+4, cmd->cmd_handle);
4642fcf3ce44SJohn Forte 	if (cmd->cmd_rp) {
4643fcf3ce44SJohn Forte 		QMEM_WR16(qlt, req+8, cmd->cmd_rp->rp_handle);
4644fcf3ce44SJohn Forte 	} else {
4645fcf3ce44SJohn Forte 		QMEM_WR16(qlt, req+8, 0xFFFF);
4646fcf3ce44SJohn Forte 	}
4647fcf3ce44SJohn Forte 
4648fcf3ce44SJohn Forte 	QMEM_WR32(qlt, req+0xc, cmd->cmd_handle);
4649fcf3ce44SJohn Forte 	QMEM_WR32(qlt, req+0x30, cmd->cmd_rportid);
4650fcf3ce44SJohn Forte 	qlt_submit_req_entries(qlt, 1);
4651fcf3ce44SJohn Forte 	mutex_exit(&qlt->req_lock);
4652fcf3ce44SJohn Forte 
4653fcf3ce44SJohn Forte 	return (FCT_SUCCESS);
4654fcf3ce44SJohn Forte }
4655fcf3ce44SJohn Forte 
4656fcf3ce44SJohn Forte fct_status_t
4657fcf3ce44SJohn Forte qlt_abort_purex(qlt_state_t *qlt, fct_cmd_t *cmd)
4658fcf3ce44SJohn Forte {
4659fcf3ce44SJohn Forte 	uint8_t *req;
4660fcf3ce44SJohn Forte 	qlt_cmd_t *qcmd;
4661fcf3ce44SJohn Forte 	fct_els_t *els;
4662fcf3ce44SJohn Forte 	uint8_t elsop, req1f;
4663fcf3ce44SJohn Forte 
4664fcf3ce44SJohn Forte 	els = (fct_els_t *)cmd->cmd_specific;
4665fcf3ce44SJohn Forte 	qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
4666fcf3ce44SJohn Forte 	elsop = els->els_req_payload[0];
4667c4ddbbe1SDaniel Beauregard 	EL(qlt, "fctcmd-%p, cmd_handle-%xh, elsop-%xh\n", cmd, cmd->cmd_handle,
4668c4ddbbe1SDaniel Beauregard 	    elsop);
4669fcf3ce44SJohn Forte 	req1f = 0x60;	/* Terminate xchg */
4670fcf3ce44SJohn Forte 	if ((elsop == ELS_OP_PRLI) || (elsop == ELS_OP_PRLO) ||
4671fcf3ce44SJohn Forte 	    (elsop == ELS_OP_TPRLO) || (elsop == ELS_OP_LOGO)) {
4672c4ddbbe1SDaniel Beauregard 		req1f = (uint8_t)(req1f | BIT_4);
4673fcf3ce44SJohn Forte 	}
4674fcf3ce44SJohn Forte 
4675fcf3ce44SJohn Forte 	mutex_enter(&qlt->req_lock);
4676fcf3ce44SJohn Forte 	req = (uint8_t *)qlt_get_req_entries(qlt, 1);
4677fcf3ce44SJohn Forte 	if (req == NULL) {
4678fcf3ce44SJohn Forte 		mutex_exit(&qlt->req_lock);
4679fcf3ce44SJohn Forte 
4680fcf3ce44SJohn Forte 		return (FCT_BUSY);
4681fcf3ce44SJohn Forte 	}
4682fcf3ce44SJohn Forte 
4683c4ddbbe1SDaniel Beauregard 	qcmd->flags = (uint16_t)(qcmd->flags | QLT_CMD_ABORTING);
4684fcf3ce44SJohn Forte 	bzero(req, IOCB_SIZE);
4685fcf3ce44SJohn Forte 	req[0] = 0x53; req[1] = 1; req[0xf] = 0x10;
4686fcf3ce44SJohn Forte 	req[0x16] = elsop; req[0x1f] = req1f;
4687fcf3ce44SJohn Forte 	QMEM_WR32(qlt, (&req[4]), cmd->cmd_handle);
4688fcf3ce44SJohn Forte 	if (cmd->cmd_rp) {
4689fcf3ce44SJohn Forte 		QMEM_WR16(qlt, (&req[0xA]), cmd->cmd_rp->rp_handle);
4690c4ddbbe1SDaniel Beauregard 		EL(qlt, "rp_handle-%x\n", cmd->cmd_rp->rp_handle);
4691fcf3ce44SJohn Forte 	} else {
4692fcf3ce44SJohn Forte 		QMEM_WR16(qlt, (&req[0xA]), cmd->cmd_rp_handle);
4693c4ddbbe1SDaniel Beauregard 		EL(qlt, "cmd_rp_handle-%x\n", cmd->cmd_rp_handle);
4694fcf3ce44SJohn Forte 	}
4695fcf3ce44SJohn Forte 
4696fcf3ce44SJohn Forte 	QMEM_WR32(qlt, (&req[0x10]), qcmd->fw_xchg_addr);
4697fcf3ce44SJohn Forte 	QMEM_WR32(qlt, (&req[0x18]), cmd->cmd_rportid);
4698fcf3ce44SJohn Forte 	qlt_submit_req_entries(qlt, 1);
4699fcf3ce44SJohn Forte 	mutex_exit(&qlt->req_lock);
4700fcf3ce44SJohn Forte 
4701fcf3ce44SJohn Forte 	return (FCT_SUCCESS);
4702fcf3ce44SJohn Forte }
4703fcf3ce44SJohn Forte 
4704fcf3ce44SJohn Forte fct_status_t
4705fcf3ce44SJohn Forte qlt_abort_unsol_scsi_cmd(qlt_state_t *qlt, fct_cmd_t *cmd)
4706fcf3ce44SJohn Forte {
4707fcf3ce44SJohn Forte 	qlt_cmd_t *qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
4708fcf3ce44SJohn Forte 	uint8_t *req;
4709fcf3ce44SJohn Forte 	uint16_t flags;
4710fcf3ce44SJohn Forte 
4711c4ddbbe1SDaniel Beauregard 	flags = (uint16_t)(BIT_14 |
4712c4ddbbe1SDaniel Beauregard 	    (((uint16_t)qcmd->param.atio_byte3 & 0xf0) << 5));
4713c4ddbbe1SDaniel Beauregard 	EL(qlt, "fctcmd-%p, cmd_handle-%x\n", cmd, cmd->cmd_handle);
4714fcf3ce44SJohn Forte 
4715fcf3ce44SJohn Forte 	mutex_enter(&qlt->req_lock);
4716fcf3ce44SJohn Forte 	req = (uint8_t *)qlt_get_req_entries(qlt, 1);
4717fcf3ce44SJohn Forte 	if (req == NULL) {
4718fcf3ce44SJohn Forte 		mutex_exit(&qlt->req_lock);
4719fcf3ce44SJohn Forte 
4720fcf3ce44SJohn Forte 		return (FCT_BUSY);
4721fcf3ce44SJohn Forte 	}
4722fcf3ce44SJohn Forte 
4723c4ddbbe1SDaniel Beauregard 	qcmd->flags = (uint16_t)(qcmd->flags | QLT_CMD_ABORTING);
4724fcf3ce44SJohn Forte 	bzero(req, IOCB_SIZE);
4725fcf3ce44SJohn Forte 	req[0] = 0x12; req[1] = 0x1;
4726fcf3ce44SJohn Forte 	QMEM_WR32(qlt, req+4, cmd->cmd_handle);
4727fcf3ce44SJohn Forte 	QMEM_WR16(qlt, req+8, cmd->cmd_rp->rp_handle);
4728fcf3ce44SJohn Forte 	QMEM_WR16(qlt, req+10, 60);	/* 60 seconds timeout */
4729fcf3ce44SJohn Forte 	QMEM_WR32(qlt, req+0x10, cmd->cmd_rportid);
4730fcf3ce44SJohn Forte 	QMEM_WR32(qlt, req+0x14, qcmd->fw_xchg_addr);
4731fcf3ce44SJohn Forte 	QMEM_WR16(qlt, req+0x1A, flags);
4732fcf3ce44SJohn Forte 	QMEM_WR16(qlt, req+0x20, cmd->cmd_oxid);
4733fcf3ce44SJohn Forte 	qlt_submit_req_entries(qlt, 1);
4734fcf3ce44SJohn Forte 	mutex_exit(&qlt->req_lock);
4735fcf3ce44SJohn Forte 
4736fcf3ce44SJohn Forte 	return (FCT_SUCCESS);
4737fcf3ce44SJohn Forte }
4738fcf3ce44SJohn Forte 
4739fcf3ce44SJohn Forte fct_status_t
4740fcf3ce44SJohn Forte qlt_send_cmd(fct_cmd_t *cmd)
4741fcf3ce44SJohn Forte {
4742fcf3ce44SJohn Forte 	qlt_state_t *qlt;
4743fcf3ce44SJohn Forte 
4744fcf3ce44SJohn Forte 	qlt = (qlt_state_t *)cmd->cmd_port->port_fca_private;
4745fcf3ce44SJohn Forte 	if (cmd->cmd_type == FCT_CMD_SOL_ELS) {
4746fcf3ce44SJohn Forte 		return (qlt_send_els(qlt, cmd));
4747fcf3ce44SJohn Forte 	} else if (cmd->cmd_type == FCT_CMD_SOL_CT) {
4748fcf3ce44SJohn Forte 		return (qlt_send_ct(qlt, cmd));
4749fcf3ce44SJohn Forte 	}
4750c4ddbbe1SDaniel Beauregard 	EL(qlt, "cmd->cmd_type = %xh\n", cmd->cmd_type);
4751fcf3ce44SJohn Forte 
4752fcf3ce44SJohn Forte 	ASSERT(0);
4753fcf3ce44SJohn Forte 	return (FCT_FAILURE);
4754fcf3ce44SJohn Forte }
4755fcf3ce44SJohn Forte 
4756fcf3ce44SJohn Forte fct_status_t
4757fcf3ce44SJohn Forte qlt_send_els(qlt_state_t *qlt, fct_cmd_t *cmd)
4758fcf3ce44SJohn Forte {
4759fcf3ce44SJohn Forte 	uint8_t *req;
4760fcf3ce44SJohn Forte 	fct_els_t *els;
4761fcf3ce44SJohn Forte 	qlt_cmd_t *qcmd;
4762fcf3ce44SJohn Forte 	stmf_data_buf_t *buf;
4763fcf3ce44SJohn Forte 	qlt_dmem_bctl_t *bctl;
4764fcf3ce44SJohn Forte 	uint32_t sz, minsz;
4765fcf3ce44SJohn Forte 
4766fcf3ce44SJohn Forte 	els = (fct_els_t *)cmd->cmd_specific;
4767fcf3ce44SJohn Forte 	qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
4768fcf3ce44SJohn Forte 	qcmd->flags = QLT_CMD_TYPE_SOLICITED;
4769c4ddbbe1SDaniel Beauregard 	qcmd->param.resp_offset = (uint16_t)((els->els_req_size + 7) & ~7);
4770fcf3ce44SJohn Forte 	sz = minsz = qcmd->param.resp_offset + els->els_resp_size;
4771fcf3ce44SJohn Forte 	buf = qlt_i_dmem_alloc(qlt, sz, &minsz, 0);
4772fcf3ce44SJohn Forte 	if (buf == NULL) {
4773fcf3ce44SJohn Forte 		return (FCT_BUSY);
4774fcf3ce44SJohn Forte 	}
4775fcf3ce44SJohn Forte 	bctl = (qlt_dmem_bctl_t *)buf->db_port_private;
4776fcf3ce44SJohn Forte 
4777fcf3ce44SJohn Forte 	qcmd->dbuf = buf;
4778fcf3ce44SJohn Forte 	bcopy(els->els_req_payload, buf->db_sglist[0].seg_addr,
4779d8c54e3dSSam Cramer 	    els->els_req_size);
4780fcf3ce44SJohn Forte 	qlt_dmem_dma_sync(buf, DDI_DMA_SYNC_FORDEV);
4781fcf3ce44SJohn Forte 
4782fcf3ce44SJohn Forte 	mutex_enter(&qlt->req_lock);
4783fcf3ce44SJohn Forte 	req = (uint8_t *)qlt_get_req_entries(qlt, 1);
4784fcf3ce44SJohn Forte 	if (req == NULL) {
4785fcf3ce44SJohn Forte 		qlt_dmem_free(NULL, buf);
4786fcf3ce44SJohn Forte 		mutex_exit(&qlt->req_lock);
4787fcf3ce44SJohn Forte 		return (FCT_BUSY);
4788fcf3ce44SJohn Forte 	}
4789fcf3ce44SJohn Forte 	bzero(req, IOCB_SIZE);
4790fcf3ce44SJohn Forte 	req[0] = 0x53; req[1] = 1;
4791fcf3ce44SJohn Forte 	QMEM_WR32(qlt, (&req[4]), cmd->cmd_handle);
4792fcf3ce44SJohn Forte 	QMEM_WR16(qlt, (&req[0xA]), cmd->cmd_rp->rp_handle);
4793fcf3ce44SJohn Forte 	QMEM_WR16(qlt, (&req[0xC]), 1);
4794fcf3ce44SJohn Forte 	QMEM_WR16(qlt, (&req[0xE]), 0x1000);
4795fcf3ce44SJohn Forte 	QMEM_WR16(qlt, (&req[0x14]), 1);
4796fcf3ce44SJohn Forte 	req[0x16] = els->els_req_payload[0];
4797fcf3ce44SJohn Forte 	if (qlt->cur_topology == PORT_TOPOLOGY_PT_TO_PT) {
4798c4ddbbe1SDaniel Beauregard 		req[0x1b] = (uint8_t)((cmd->cmd_lportid >> 16) & 0xff);
4799c4ddbbe1SDaniel Beauregard 		req[0x1c] = (uint8_t)(cmd->cmd_lportid & 0xff);
4800c4ddbbe1SDaniel Beauregard 		req[0x1d] = (uint8_t)((cmd->cmd_lportid >> 8) & 0xff);
4801fcf3ce44SJohn Forte 	}
4802fcf3ce44SJohn Forte 	QMEM_WR32(qlt, (&req[0x18]), cmd->cmd_rp->rp_id);
4803fcf3ce44SJohn Forte 	QMEM_WR32(qlt, (&req[0x20]), els->els_resp_size);
4804fcf3ce44SJohn Forte 	QMEM_WR32(qlt, (&req[0x24]), els->els_req_size);
4805fcf3ce44SJohn Forte 	QMEM_WR64(qlt, (&req[0x28]), bctl->bctl_dev_addr);
4806fcf3ce44SJohn Forte 	QMEM_WR32(qlt, (&req[0x30]), els->els_req_size);
4807c4ddbbe1SDaniel Beauregard 	QMEM_WR64(qlt, (&req[0x34]), (bctl->bctl_dev_addr +
4808c4ddbbe1SDaniel Beauregard 	    qcmd->param.resp_offset));
4809fcf3ce44SJohn Forte 	QMEM_WR32(qlt, (&req[0x3C]), els->els_resp_size);
4810fcf3ce44SJohn Forte 	qlt_submit_req_entries(qlt, 1);
4811fcf3ce44SJohn Forte 	mutex_exit(&qlt->req_lock);
4812fcf3ce44SJohn Forte 
4813fcf3ce44SJohn Forte 	return (FCT_SUCCESS);
4814fcf3ce44SJohn Forte }
4815fcf3ce44SJohn Forte 
4816fcf3ce44SJohn Forte fct_status_t
4817fcf3ce44SJohn Forte qlt_send_ct(qlt_state_t *qlt, fct_cmd_t *cmd)
4818fcf3ce44SJohn Forte {
4819fcf3ce44SJohn Forte 	uint8_t *req;
4820fcf3ce44SJohn Forte 	fct_sol_ct_t *ct;
4821fcf3ce44SJohn Forte 	qlt_cmd_t *qcmd;
4822fcf3ce44SJohn Forte 	stmf_data_buf_t *buf;
4823fcf3ce44SJohn Forte 	qlt_dmem_bctl_t *bctl;
4824fcf3ce44SJohn Forte 	uint32_t sz, minsz;
4825fcf3ce44SJohn Forte 
4826fcf3ce44SJohn Forte 	ct = (fct_sol_ct_t *)cmd->cmd_specific;
4827fcf3ce44SJohn Forte 	qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
4828fcf3ce44SJohn Forte 	qcmd->flags = QLT_CMD_TYPE_SOLICITED;
4829c4ddbbe1SDaniel Beauregard 	qcmd->param.resp_offset = (uint16_t)((ct->ct_req_size + 7) & ~7);
4830fcf3ce44SJohn Forte 	sz = minsz = qcmd->param.resp_offset + ct->ct_resp_size;
4831fcf3ce44SJohn Forte 	buf = qlt_i_dmem_alloc(qlt, sz, &minsz, 0);
4832fcf3ce44SJohn Forte 	if (buf == NULL) {
4833fcf3ce44SJohn Forte 		return (FCT_BUSY);
4834fcf3ce44SJohn Forte 	}
4835fcf3ce44SJohn Forte 	bctl = (qlt_dmem_bctl_t *)buf->db_port_private;
4836fcf3ce44SJohn Forte 
4837fcf3ce44SJohn Forte 	qcmd->dbuf = buf;
4838fcf3ce44SJohn Forte 	bcopy(ct->ct_req_payload, buf->db_sglist[0].seg_addr,
4839d8c54e3dSSam Cramer 	    ct->ct_req_size);
4840fcf3ce44SJohn Forte 	qlt_dmem_dma_sync(buf, DDI_DMA_SYNC_FORDEV);
4841fcf3ce44SJohn Forte 
4842fcf3ce44SJohn Forte 	mutex_enter(&qlt->req_lock);
4843fcf3ce44SJohn Forte 	req = (uint8_t *)qlt_get_req_entries(qlt, 1);
4844fcf3ce44SJohn Forte 	if (req == NULL) {
4845fcf3ce44SJohn Forte 		qlt_dmem_free(NULL, buf);
4846fcf3ce44SJohn Forte 		mutex_exit(&qlt->req_lock);
4847fcf3ce44SJohn Forte 		return (FCT_BUSY);
4848fcf3ce44SJohn Forte 	}
4849fcf3ce44SJohn Forte 	bzero(req, IOCB_SIZE);
4850fcf3ce44SJohn Forte 	req[0] = 0x29; req[1] = 1;
4851fcf3ce44SJohn Forte 	QMEM_WR32(qlt, (&req[4]), cmd->cmd_handle);
4852fcf3ce44SJohn Forte 	QMEM_WR16(qlt, (&req[0xA]), cmd->cmd_rp->rp_handle);
4853fcf3ce44SJohn Forte 	QMEM_WR16(qlt, (&req[0xC]), 1);
4854fcf3ce44SJohn Forte 	QMEM_WR16(qlt, (&req[0x10]), 0x20);	/* > (2 * RA_TOV) */
4855fcf3ce44SJohn Forte 	QMEM_WR16(qlt, (&req[0x14]), 1);
4856fcf3ce44SJohn Forte 
4857fcf3ce44SJohn Forte 	QMEM_WR32(qlt, (&req[0x20]), ct->ct_resp_size);
4858fcf3ce44SJohn Forte 	QMEM_WR32(qlt, (&req[0x24]), ct->ct_req_size);
4859fcf3ce44SJohn Forte 
4860fcf3ce44SJohn Forte 	QMEM_WR64(qlt, (&req[0x28]), bctl->bctl_dev_addr); /* COMMAND DSD */
4861fcf3ce44SJohn Forte 	QMEM_WR32(qlt, (&req[0x30]), ct->ct_req_size);
4862c4ddbbe1SDaniel Beauregard 	QMEM_WR64(qlt, (&req[0x34]), (bctl->bctl_dev_addr +
4863c4ddbbe1SDaniel Beauregard 	    qcmd->param.resp_offset));		/* RESPONSE DSD */
4864fcf3ce44SJohn Forte 	QMEM_WR32(qlt, (&req[0x3C]), ct->ct_resp_size);
4865fcf3ce44SJohn Forte 
4866fcf3ce44SJohn Forte 	qlt_submit_req_entries(qlt, 1);
4867fcf3ce44SJohn Forte 	mutex_exit(&qlt->req_lock);
4868fcf3ce44SJohn Forte 
4869fcf3ce44SJohn Forte 	return (FCT_SUCCESS);
4870fcf3ce44SJohn Forte }
4871fcf3ce44SJohn Forte 
4872fcf3ce44SJohn Forte 
4873fcf3ce44SJohn Forte /*
4874fcf3ce44SJohn Forte  * All QLT_FIRMWARE_* will mainly be handled in this function
4875fcf3ce44SJohn Forte  * It can not be called in interrupt context
4876fcf3ce44SJohn Forte  *
4877fcf3ce44SJohn Forte  * FWDUMP's purpose is to serve ioctl, so we will use qlt_ioctl_flags
4878fcf3ce44SJohn Forte  * and qlt_ioctl_lock
4879fcf3ce44SJohn Forte  */
4880fcf3ce44SJohn Forte static fct_status_t
4881fcf3ce44SJohn Forte qlt_firmware_dump(fct_local_port_t *port, stmf_state_change_info_t *ssci)
4882fcf3ce44SJohn Forte {
4883fcf3ce44SJohn Forte 	qlt_state_t	*qlt = (qlt_state_t *)port->port_fca_private;
4884fcf3ce44SJohn Forte 	int		i;
4885c4ddbbe1SDaniel Beauregard 	int		retries, n;
4886c4ddbbe1SDaniel Beauregard 	uint_t		size_left;
4887fcf3ce44SJohn Forte 	char		c = ' ';
4888fcf3ce44SJohn Forte 	uint32_t	addr, endaddr, words_to_read;
4889fcf3ce44SJohn Forte 	caddr_t		buf;
4890c4ddbbe1SDaniel Beauregard 	fct_status_t	ret;
4891fcf3ce44SJohn Forte 
4892fcf3ce44SJohn Forte 	mutex_enter(&qlt->qlt_ioctl_lock);
4893fcf3ce44SJohn Forte 	/*
4894fcf3ce44SJohn Forte 	 * To make sure that there's no outstanding dumping task
4895fcf3ce44SJohn Forte 	 */
4896fcf3ce44SJohn Forte 	if (qlt->qlt_ioctl_flags & QLT_FWDUMP_INPROGRESS) {
4897fcf3ce44SJohn Forte 		mutex_exit(&qlt->qlt_ioctl_lock);
4898c4ddbbe1SDaniel Beauregard 		EL(qlt, "qlt_ioctl_flags=%xh, inprogress\n",
4899c4ddbbe1SDaniel Beauregard 		    qlt->qlt_ioctl_flags);
4900c4ddbbe1SDaniel Beauregard 		EL(qlt, "outstanding\n");
4901fcf3ce44SJohn Forte 		return (FCT_FAILURE);
4902fcf3ce44SJohn Forte 	}
4903fcf3ce44SJohn Forte 
4904fcf3ce44SJohn Forte 	/*
4905fcf3ce44SJohn Forte 	 * To make sure not to overwrite existing dump
4906fcf3ce44SJohn Forte 	 */
4907fcf3ce44SJohn Forte 	if ((qlt->qlt_ioctl_flags & QLT_FWDUMP_ISVALID) &&
4908fcf3ce44SJohn Forte 	    !(qlt->qlt_ioctl_flags & QLT_FWDUMP_TRIGGERED_BY_USER) &&
4909fcf3ce44SJohn Forte 	    !(qlt->qlt_ioctl_flags & QLT_FWDUMP_FETCHED_BY_USER)) {
4910fcf3ce44SJohn Forte 		/*
4911fcf3ce44SJohn Forte 		 * If we have alreay one dump, but it's not triggered by user
4912fcf3ce44SJohn Forte 		 * and the user hasn't fetched it, we shouldn't dump again.
4913fcf3ce44SJohn Forte 		 */
4914fcf3ce44SJohn Forte 		mutex_exit(&qlt->qlt_ioctl_lock);
4915c4ddbbe1SDaniel Beauregard 		EL(qlt, "qlt_ioctl_flags=%xh, already done\n",
4916c4ddbbe1SDaniel Beauregard 		    qlt->qlt_ioctl_flags);
4917fcf3ce44SJohn Forte 		cmn_err(CE_NOTE, "qlt(%d): Skipping firmware dump as there "
4918fcf3ce44SJohn Forte 		    "is one already outstanding.", qlt->instance);
4919fcf3ce44SJohn Forte 		return (FCT_FAILURE);
4920fcf3ce44SJohn Forte 	}
4921fcf3ce44SJohn Forte 	qlt->qlt_ioctl_flags |= QLT_FWDUMP_INPROGRESS;
4922fcf3ce44SJohn Forte 	if (ssci->st_rflags & STMF_RFLAG_USER_REQUEST) {
4923fcf3ce44SJohn Forte 		qlt->qlt_ioctl_flags |= QLT_FWDUMP_TRIGGERED_BY_USER;
4924fcf3ce44SJohn Forte 	} else {
4925fcf3ce44SJohn Forte 		qlt->qlt_ioctl_flags &= ~QLT_FWDUMP_TRIGGERED_BY_USER;
4926fcf3ce44SJohn Forte 	}
4927fcf3ce44SJohn Forte 	mutex_exit(&qlt->qlt_ioctl_lock);
4928fcf3ce44SJohn Forte 
4929fcf3ce44SJohn Forte 	size_left = QLT_FWDUMP_BUFSIZE;
4930fcf3ce44SJohn Forte 	if (!qlt->qlt_fwdump_buf) {
4931fcf3ce44SJohn Forte 		ASSERT(!(qlt->qlt_ioctl_flags & QLT_FWDUMP_ISVALID));
4932fcf3ce44SJohn Forte 		/*
4933fcf3ce44SJohn Forte 		 * It's the only place that we allocate buf for dumping. After
4934fcf3ce44SJohn Forte 		 * it's allocated, we will use it until the port is detached.
4935fcf3ce44SJohn Forte 		 */
4936fcf3ce44SJohn Forte 		qlt->qlt_fwdump_buf = kmem_zalloc(size_left, KM_SLEEP);
4937fcf3ce44SJohn Forte 	}
4938fcf3ce44SJohn Forte 
4939fcf3ce44SJohn Forte 	/*
4940fcf3ce44SJohn Forte 	 * Start to dump firmware
4941fcf3ce44SJohn Forte 	 */
4942fcf3ce44SJohn Forte 	buf = (caddr_t)qlt->qlt_fwdump_buf;
4943fcf3ce44SJohn Forte 
4944fcf3ce44SJohn Forte 	/*
4945fcf3ce44SJohn Forte 	 * Print the ISP firmware revision number and attributes information
4946fcf3ce44SJohn Forte 	 * Read the RISC to Host Status register
4947fcf3ce44SJohn Forte 	 */
4948c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "ISP FW Version %d.%02d.%02d "
4949fcf3ce44SJohn Forte 	    "Attributes %04x\n\nR2H Status Register\n%08x",
4950fcf3ce44SJohn Forte 	    qlt->fw_major, qlt->fw_minor,
4951c4ddbbe1SDaniel Beauregard 	    qlt->fw_subminor, qlt->fw_attr, REG_RD32(qlt, REG_RISC_STATUS));
4952fcf3ce44SJohn Forte 	buf += n; size_left -= n;
4953fcf3ce44SJohn Forte 
4954fcf3ce44SJohn Forte 	/*
4955fcf3ce44SJohn Forte 	 * Before pausing the RISC, make sure no mailbox can execute
4956fcf3ce44SJohn Forte 	 */
4957fcf3ce44SJohn Forte 	mutex_enter(&qlt->mbox_lock);
4958fcf3ce44SJohn Forte 	if (qlt->mbox_io_state != MBOX_STATE_UNKNOWN) {
4959fcf3ce44SJohn Forte 		/*
4960fcf3ce44SJohn Forte 		 * Wait to grab the mailboxes
4961fcf3ce44SJohn Forte 		 */
4962fcf3ce44SJohn Forte 		for (retries = 0; (qlt->mbox_io_state != MBOX_STATE_READY) &&
4963fcf3ce44SJohn Forte 		    (qlt->mbox_io_state != MBOX_STATE_UNKNOWN); retries++) {
4964*a2255df3SDaniel Beauregard 			(void) cv_timedwait(&qlt->mbox_cv, &qlt->mbox_lock,
4965*a2255df3SDaniel Beauregard 			    ddi_get_lbolt() + drv_usectohz(1000000));
4966fcf3ce44SJohn Forte 			if (retries > 5) {
4967fcf3ce44SJohn Forte 				mutex_exit(&qlt->mbox_lock);
4968c4ddbbe1SDaniel Beauregard 				EL(qlt, "can't drain out mailbox commands\n");
4969fcf3ce44SJohn Forte 				goto dump_fail;
4970fcf3ce44SJohn Forte 			}
4971fcf3ce44SJohn Forte 		}
4972fcf3ce44SJohn Forte 		qlt->mbox_io_state = MBOX_STATE_UNKNOWN;
4973fcf3ce44SJohn Forte 		cv_broadcast(&qlt->mbox_cv);
4974fcf3ce44SJohn Forte 	}
4975fcf3ce44SJohn Forte 	mutex_exit(&qlt->mbox_lock);
4976fcf3ce44SJohn Forte 
4977fcf3ce44SJohn Forte 	/*
4978fcf3ce44SJohn Forte 	 * Pause the RISC processor
4979fcf3ce44SJohn Forte 	 */
4980*a2255df3SDaniel Beauregard 	REG_WR32(qlt, REG_HCCR, HCCR_CMD(SET_RISC_PAUSE));
4981fcf3ce44SJohn Forte 
4982fcf3ce44SJohn Forte 	/*
4983fcf3ce44SJohn Forte 	 * Wait for the RISC processor to pause
4984fcf3ce44SJohn Forte 	 */
4985fcf3ce44SJohn Forte 	for (i = 0; i < 200; i++) {
4986c4ddbbe1SDaniel Beauregard 		if (REG_RD32(qlt, REG_RISC_STATUS) & 0x100) {
4987fcf3ce44SJohn Forte 			break;
4988fcf3ce44SJohn Forte 		}
4989fcf3ce44SJohn Forte 		drv_usecwait(1000);
4990fcf3ce44SJohn Forte 	}
4991fcf3ce44SJohn Forte 	if (i == 200) {
4992c4ddbbe1SDaniel Beauregard 		EL(qlt, "can't pause\n");
4993fcf3ce44SJohn Forte 		return (FCT_FAILURE);
4994fcf3ce44SJohn Forte 	}
4995fcf3ce44SJohn Forte 
4996c4ddbbe1SDaniel Beauregard 	if ((!qlt->qlt_25xx_chip) && (!qlt->qlt_81xx_chip)) {
4997fcf3ce44SJohn Forte 		goto over_25xx_specific_dump;
4998fcf3ce44SJohn Forte 	}
4999c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\n\nHostRisc registers\n");
5000fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5001fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x7000);
5002fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5003fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5004fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x7010);
5005fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5006fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5007fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x7C00);
5008fcf3ce44SJohn Forte 
5009c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nPCIe registers\n");
5010fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5011fcf3ce44SJohn Forte 	REG_WR32(qlt, 0xC0, 0x1);
5012fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc4, 3, size_left);
5013fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5014fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 1, size_left);
5015fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5016fcf3ce44SJohn Forte 	REG_WR32(qlt, 0xC0, 0x0);
5017fcf3ce44SJohn Forte 
5018fcf3ce44SJohn Forte over_25xx_specific_dump:;
5019c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\n\nHost Interface Registers\n");
5020fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5021fcf3ce44SJohn Forte 	/*
5022fcf3ce44SJohn Forte 	 * Capture data from 32 regsiters
5023fcf3ce44SJohn Forte 	 */
5024fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0, 32, size_left);
5025fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5026fcf3ce44SJohn Forte 
5027fcf3ce44SJohn Forte 	/*
5028fcf3ce44SJohn Forte 	 * Disable interrupts
5029fcf3ce44SJohn Forte 	 */
5030fcf3ce44SJohn Forte 	REG_WR32(qlt, 0xc, 0);
5031fcf3ce44SJohn Forte 
5032fcf3ce44SJohn Forte 	/*
5033fcf3ce44SJohn Forte 	 * Shadow registers
5034fcf3ce44SJohn Forte 	 */
5035c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nShadow Registers\n");
5036fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5037fcf3ce44SJohn Forte 
5038fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xF70);
5039fcf3ce44SJohn Forte 	addr = 0xb0000000;
5040fcf3ce44SJohn Forte 	for (i = 0; i < 0xb; i++) {
5041c4ddbbe1SDaniel Beauregard 		if ((!qlt->qlt_25xx_chip) &&
5042c4ddbbe1SDaniel Beauregard 		    (!qlt->qlt_81xx_chip) &&
5043c4ddbbe1SDaniel Beauregard 		    (i >= 7)) {
5044fcf3ce44SJohn Forte 			break;
5045fcf3ce44SJohn Forte 		}
5046fcf3ce44SJohn Forte 		if (i && ((i & 7) == 0)) {
5047c4ddbbe1SDaniel Beauregard 			n = (int)snprintf(buf, size_left, "\n");
5048fcf3ce44SJohn Forte 			buf += n; size_left -= n;
5049fcf3ce44SJohn Forte 		}
5050fcf3ce44SJohn Forte 		REG_WR32(qlt, 0xF0, addr);
5051c4ddbbe1SDaniel Beauregard 		n = (int)snprintf(buf, size_left, "%08x ", REG_RD32(qlt, 0xFC));
5052fcf3ce44SJohn Forte 		buf += n; size_left -= n;
5053fcf3ce44SJohn Forte 		addr += 0x100000;
5054fcf3ce44SJohn Forte 	}
5055fcf3ce44SJohn Forte 
5056c4ddbbe1SDaniel Beauregard 	if ((qlt->qlt_25xx_chip) || (qlt->qlt_81xx_chip)) {
5057fcf3ce44SJohn Forte 		REG_WR32(qlt, 0x54, 0x10);
5058c4ddbbe1SDaniel Beauregard 		n = (int)snprintf(buf, size_left,
5059c4ddbbe1SDaniel Beauregard 		    "\n\nRISC IO Register\n%08x", REG_RD32(qlt, 0xC0));
5060fcf3ce44SJohn Forte 		buf += n; size_left -= n;
5061fcf3ce44SJohn Forte 	}
5062fcf3ce44SJohn Forte 
5063fcf3ce44SJohn Forte 	/*
5064fcf3ce44SJohn Forte 	 * Mailbox registers
5065fcf3ce44SJohn Forte 	 */
5066c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\n\nMailbox Registers\n");
5067fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5068fcf3ce44SJohn Forte 	for (i = 0; i < 32; i += 2) {
5069fcf3ce44SJohn Forte 		if ((i + 2) & 15) {
5070fcf3ce44SJohn Forte 			c = ' ';
5071fcf3ce44SJohn Forte 		} else {
5072fcf3ce44SJohn Forte 			c = '\n';
5073fcf3ce44SJohn Forte 		}
5074c4ddbbe1SDaniel Beauregard 		n = (int)snprintf(buf, size_left, "%04x %04x%c",
5075fcf3ce44SJohn Forte 		    REG_RD16(qlt, 0x80 + (i << 1)),
5076fcf3ce44SJohn Forte 		    REG_RD16(qlt, 0x80 + ((i+1) << 1)), c);
5077fcf3ce44SJohn Forte 		buf += n; size_left -= n;
5078fcf3ce44SJohn Forte 	}
5079fcf3ce44SJohn Forte 
5080fcf3ce44SJohn Forte 	/*
5081fcf3ce44SJohn Forte 	 * Transfer sequence registers
5082fcf3ce44SJohn Forte 	 */
5083c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nXSEQ GP Registers\n");
5084fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5085fcf3ce44SJohn Forte 
5086fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xBF00);
5087fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5088fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5089fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xBF10);
5090fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5091fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5092fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xBF20);
5093fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5094fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5095fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xBF30);
5096fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5097fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5098fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xBF40);
5099fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5100fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5101fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xBF50);
5102fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5103fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5104fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xBF60);
5105fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5106fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5107fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xBF70);
5108fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5109fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5110c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nXSEQ-0 registers\n");
5111fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5112c4ddbbe1SDaniel Beauregard 	if ((qlt->qlt_25xx_chip) || (qlt->qlt_81xx_chip)) {
5113c4ddbbe1SDaniel Beauregard 		REG_WR32(qlt, 0x54, 0xBFC0);
5114c4ddbbe1SDaniel Beauregard 		n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5115c4ddbbe1SDaniel Beauregard 		buf += n; size_left -= n;
5116c4ddbbe1SDaniel Beauregard 		REG_WR32(qlt, 0x54, 0xBFD0);
5117c4ddbbe1SDaniel Beauregard 		n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5118c4ddbbe1SDaniel Beauregard 		buf += n; size_left -= n;
5119c4ddbbe1SDaniel Beauregard 	}
5120fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xBFE0);
5121fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5122fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5123c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nXSEQ-1 registers\n");
5124fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5125fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xBFF0);
5126fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5127fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5128fcf3ce44SJohn Forte 
5129fcf3ce44SJohn Forte 	/*
5130fcf3ce44SJohn Forte 	 * Receive sequence registers
5131fcf3ce44SJohn Forte 	 */
5132c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nRSEQ GP Registers\n");
5133fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5134fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xFF00);
5135fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5136fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5137fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xFF10);
5138fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5139fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5140fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xFF20);
5141fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5142fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5143fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xFF30);
5144fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5145fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5146fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xFF40);
5147fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5148fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5149fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xFF50);
5150fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5151fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5152fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xFF60);
5153fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5154fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5155fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xFF70);
5156fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5157fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5158c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nRSEQ-0 registers\n");
5159fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5160c4ddbbe1SDaniel Beauregard 	if ((qlt->qlt_25xx_chip) || (qlt->qlt_81xx_chip)) {
5161c4ddbbe1SDaniel Beauregard 		REG_WR32(qlt, 0x54, 0xFFC0);
5162c4ddbbe1SDaniel Beauregard 		n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5163c4ddbbe1SDaniel Beauregard 		buf += n; size_left -= n;
5164c4ddbbe1SDaniel Beauregard 	}
5165fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xFFD0);
5166fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5167fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5168c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nRSEQ-1 registers\n");
5169fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5170fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xFFE0);
5171fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5172fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5173c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nRSEQ-2 registers\n");
5174fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5175fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xFFF0);
5176fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5177fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5178fcf3ce44SJohn Forte 
5179c4ddbbe1SDaniel Beauregard 	if ((!qlt->qlt_25xx_chip) && (!qlt->qlt_81xx_chip))
5180fcf3ce44SJohn Forte 		goto over_aseq_regs;
5181fcf3ce44SJohn Forte 
5182fcf3ce44SJohn Forte 	/*
5183fcf3ce44SJohn Forte 	 * Auxiliary sequencer registers
5184fcf3ce44SJohn Forte 	 */
5185c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nASEQ GP Registers\n");
5186fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5187fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xB000);
5188fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5189fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5190fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xB010);
5191fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5192fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5193fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xB020);
5194fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5195fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5196fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xB030);
5197fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5198fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5199fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xB040);
5200fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5201fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5202fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xB050);
5203fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5204fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5205fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xB060);
5206fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5207fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5208fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xB070);
5209fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5210fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5211c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nASEQ-0 registers\n");
5212fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5213fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xB0C0);
5214fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5215fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5216fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xB0D0);
5217fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5218fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5219c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nASEQ-1 registers\n");
5220fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5221fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xB0E0);
5222fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5223fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5224c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nASEQ-2 registers\n");
5225fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5226fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0xB0F0);
5227fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5228fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5229fcf3ce44SJohn Forte 
5230fcf3ce44SJohn Forte over_aseq_regs:;
5231fcf3ce44SJohn Forte 
5232fcf3ce44SJohn Forte 	/*
5233fcf3ce44SJohn Forte 	 * Command DMA registers
5234fcf3ce44SJohn Forte 	 */
5235c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nCommand DMA registers\n");
5236fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5237fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x7100);
5238fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5239fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5240fcf3ce44SJohn Forte 
5241fcf3ce44SJohn Forte 	/*
5242fcf3ce44SJohn Forte 	 * Queues
5243fcf3ce44SJohn Forte 	 */
5244c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left,
5245d8c54e3dSSam Cramer 	    "\nRequest0 Queue DMA Channel registers\n");
5246fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5247fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x7200);
5248fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 8, size_left);
5249fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5250fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xe4, 7, size_left);
5251fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5252fcf3ce44SJohn Forte 
5253c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left,
5254d8c54e3dSSam Cramer 	    "\n\nResponse0 Queue DMA Channel registers\n");
5255fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5256fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x7300);
5257fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 8, size_left);
5258fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5259fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xe4, 7, size_left);
5260fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5261fcf3ce44SJohn Forte 
5262c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left,
5263d8c54e3dSSam Cramer 	    "\n\nRequest1 Queue DMA Channel registers\n");
5264fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5265fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x7400);
5266fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 8, size_left);
5267fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5268fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xe4, 7, size_left);
5269fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5270fcf3ce44SJohn Forte 
5271fcf3ce44SJohn Forte 	/*
5272fcf3ce44SJohn Forte 	 * Transmit DMA registers
5273fcf3ce44SJohn Forte 	 */
5274c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\n\nXMT0 Data DMA registers\n");
5275fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5276fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x7600);
5277fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5278fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5279fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x7610);
5280fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5281fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5282c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nXMT1 Data DMA registers\n");
5283fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5284fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x7620);
5285fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5286fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5287fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x7630);
5288fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5289fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5290c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nXMT2 Data DMA registers\n");
5291fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5292fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x7640);
5293fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5294fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5295fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x7650);
5296fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5297fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5298c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nXMT3 Data DMA registers\n");
5299fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5300fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x7660);
5301fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5302fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5303fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x7670);
5304fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5305fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5306c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nXMT4 Data DMA registers\n");
5307fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5308fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x7680);
5309fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5310fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5311fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x7690);
5312fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5313fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5314c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nXMT Data DMA Common registers\n");
5315fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5316fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x76A0);
5317fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5318fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5319fcf3ce44SJohn Forte 
5320fcf3ce44SJohn Forte 	/*
5321fcf3ce44SJohn Forte 	 * Receive DMA registers
5322fcf3ce44SJohn Forte 	 */
5323c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left,
5324c4ddbbe1SDaniel Beauregard 	    "\nRCV Thread 0 Data DMA registers\n");
5325fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5326fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x7700);
5327fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5328fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5329fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x7710);
5330fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5331fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5332c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left,
5333c4ddbbe1SDaniel Beauregard 	    "\nRCV Thread 1 Data DMA registers\n");
5334fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5335fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x7720);
5336fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5337fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5338fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x7730);
5339fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5340fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5341fcf3ce44SJohn Forte 
5342fcf3ce44SJohn Forte 	/*
5343fcf3ce44SJohn Forte 	 * RISC registers
5344fcf3ce44SJohn Forte 	 */
5345c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nRISC GP registers\n");
5346fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5347fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x0F00);
5348fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5349fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5350fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x0F10);
5351fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5352fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5353fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x0F20);
5354fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5355fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5356fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x0F30);
5357fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5358fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5359fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x0F40);
5360fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5361fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5362fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x0F50);
5363fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5364fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5365fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x0F60);
5366fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5367fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5368fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x0F70);
5369fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5370fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5371fcf3ce44SJohn Forte 
5372fcf3ce44SJohn Forte 	/*
5373fcf3ce44SJohn Forte 	 * Local memory controller registers
5374fcf3ce44SJohn Forte 	 */
5375c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nLMC registers\n");
5376fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5377fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x3000);
5378fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5379fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5380fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x3010);
5381fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5382fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5383fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x3020);
5384fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5385fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5386fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x3030);
5387fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5388fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5389fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x3040);
5390fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5391fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5392fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x3050);
5393fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5394fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5395fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x3060);
5396fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5397fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5398fcf3ce44SJohn Forte 
5399c4ddbbe1SDaniel Beauregard 	if ((qlt->qlt_25xx_chip) || (qlt->qlt_81xx_chip)) {
5400fcf3ce44SJohn Forte 		REG_WR32(qlt, 0x54, 0x3070);
5401fcf3ce44SJohn Forte 		n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5402fcf3ce44SJohn Forte 		buf += n; size_left -= n;
5403fcf3ce44SJohn Forte 	}
5404fcf3ce44SJohn Forte 
5405fcf3ce44SJohn Forte 	/*
5406fcf3ce44SJohn Forte 	 * Fibre protocol module regsiters
5407fcf3ce44SJohn Forte 	 */
5408c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nFPM hardware registers\n");
5409fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5410fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x4000);
5411fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5412fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5413fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x4010);
5414fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5415fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5416fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x4020);
5417fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5418fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5419fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x4030);
5420fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5421fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5422fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x4040);
5423fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5424fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5425fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x4050);
5426fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5427fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5428fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x4060);
5429fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5430fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5431fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x4070);
5432fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5433fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5434fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x4080);
5435fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5436fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5437fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x4090);
5438fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5439fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5440fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x40A0);
5441fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5442fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5443fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x40B0);
5444fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5445fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5446c4ddbbe1SDaniel Beauregard 	if (qlt->qlt_81xx_chip) {
5447c4ddbbe1SDaniel Beauregard 		REG_WR32(qlt, 0x54, 0x40C0);
5448c4ddbbe1SDaniel Beauregard 		n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5449c4ddbbe1SDaniel Beauregard 		buf += n; size_left -= n;
5450c4ddbbe1SDaniel Beauregard 		REG_WR32(qlt, 0x54, 0x40D0);
5451c4ddbbe1SDaniel Beauregard 		n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5452c4ddbbe1SDaniel Beauregard 		buf += n; size_left -= n;
5453c4ddbbe1SDaniel Beauregard 	}
5454fcf3ce44SJohn Forte 
5455fcf3ce44SJohn Forte 	/*
5456fcf3ce44SJohn Forte 	 * Fibre buffer registers
5457fcf3ce44SJohn Forte 	 */
5458c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nFB hardware registers\n");
5459fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5460fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x6000);
5461fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5462fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5463fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x6010);
5464fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5465fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5466fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x6020);
5467fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5468fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5469fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x6030);
5470fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5471fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5472fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x6040);
5473fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5474fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5475fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x6100);
5476fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5477fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5478fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x6130);
5479fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5480fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5481fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x6150);
5482fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5483fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5484fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x6170);
5485fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5486fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5487fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x6190);
5488fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5489fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5490fcf3ce44SJohn Forte 	REG_WR32(qlt, 0x54, 0x61B0);
5491fcf3ce44SJohn Forte 	n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5492fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5493c4ddbbe1SDaniel Beauregard 	if (qlt->qlt_81xx_chip) {
5494c4ddbbe1SDaniel Beauregard 		REG_WR32(qlt, 0x54, 0x61C0);
5495c4ddbbe1SDaniel Beauregard 		n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5496c4ddbbe1SDaniel Beauregard 		buf += n; size_left -= n;
5497c4ddbbe1SDaniel Beauregard 	}
5498c4ddbbe1SDaniel Beauregard 	if ((qlt->qlt_25xx_chip) || (qlt->qlt_81xx_chip)) {
5499fcf3ce44SJohn Forte 		REG_WR32(qlt, 0x54, 0x6F00);
5500fcf3ce44SJohn Forte 		n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5501fcf3ce44SJohn Forte 		buf += n; size_left -= n;
5502fcf3ce44SJohn Forte 	}
5503fcf3ce44SJohn Forte 
5504fcf3ce44SJohn Forte 	qlt->intr_sneak_counter = 10;
5505fcf3ce44SJohn Forte 	mutex_enter(&qlt->intr_lock);
5506*a2255df3SDaniel Beauregard 	(void) qlt_reset_chip(qlt);
5507fcf3ce44SJohn Forte 	drv_usecwait(20);
5508fcf3ce44SJohn Forte 	qlt->intr_sneak_counter = 0;
5509fcf3ce44SJohn Forte 	mutex_exit(&qlt->intr_lock);
5510fcf3ce44SJohn Forte 
5511fcf3ce44SJohn Forte 	/*
5512fcf3ce44SJohn Forte 	 * Memory
5513fcf3ce44SJohn Forte 	 */
5514c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nCode RAM\n");
5515fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5516fcf3ce44SJohn Forte 
5517fcf3ce44SJohn Forte 	addr = 0x20000;
5518fcf3ce44SJohn Forte 	endaddr = 0x22000;
5519fcf3ce44SJohn Forte 	words_to_read = 0;
5520fcf3ce44SJohn Forte 	while (addr < endaddr) {
5521fcf3ce44SJohn Forte 		words_to_read = MBOX_DMA_MEM_SIZE >> 2;
5522fcf3ce44SJohn Forte 		if ((words_to_read + addr) > endaddr) {
5523fcf3ce44SJohn Forte 			words_to_read = endaddr - addr;
5524fcf3ce44SJohn Forte 		}
5525c4ddbbe1SDaniel Beauregard 		if ((ret = qlt_read_risc_ram(qlt, addr, words_to_read)) !=
5526fcf3ce44SJohn Forte 		    QLT_SUCCESS) {
5527c4ddbbe1SDaniel Beauregard 			EL(qlt, "Error reading risc ram - CODE RAM status="
5528c4ddbbe1SDaniel Beauregard 			    "%llxh\n", ret);
5529fcf3ce44SJohn Forte 			goto dump_fail;
5530fcf3ce44SJohn Forte 		}
5531fcf3ce44SJohn Forte 
5532fcf3ce44SJohn Forte 		n = qlt_dump_risc_ram(qlt, addr, words_to_read, buf, size_left);
5533fcf3ce44SJohn Forte 		buf += n; size_left -= n;
5534fcf3ce44SJohn Forte 
5535fcf3ce44SJohn Forte 		if (size_left < 100000) {
5536c4ddbbe1SDaniel Beauregard 			EL(qlt, "run out of space - CODE RAM size_left=%d\n",
5537c4ddbbe1SDaniel Beauregard 			    size_left);
5538fcf3ce44SJohn Forte 			goto dump_ok;
5539fcf3ce44SJohn Forte 		}
5540fcf3ce44SJohn Forte 		addr += words_to_read;
5541fcf3ce44SJohn Forte 	}
5542fcf3ce44SJohn Forte 
5543c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nExternal Memory\n");
5544fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5545fcf3ce44SJohn Forte 
5546fcf3ce44SJohn Forte 	addr = 0x100000;
5547fcf3ce44SJohn Forte 	endaddr = (((uint32_t)(qlt->fw_endaddrhi)) << 16) | qlt->fw_endaddrlo;
5548fcf3ce44SJohn Forte 	endaddr++;
5549fcf3ce44SJohn Forte 	if (endaddr & 7) {
5550fcf3ce44SJohn Forte 		endaddr = (endaddr + 7) & 0xFFFFFFF8;
5551fcf3ce44SJohn Forte 	}
5552fcf3ce44SJohn Forte 
5553fcf3ce44SJohn Forte 	words_to_read = 0;
5554fcf3ce44SJohn Forte 	while (addr < endaddr) {
5555fcf3ce44SJohn Forte 		words_to_read = MBOX_DMA_MEM_SIZE >> 2;
5556fcf3ce44SJohn Forte 		if ((words_to_read + addr) > endaddr) {
5557fcf3ce44SJohn Forte 			words_to_read = endaddr - addr;
5558fcf3ce44SJohn Forte 		}
5559c4ddbbe1SDaniel Beauregard 		if ((ret = qlt_read_risc_ram(qlt, addr, words_to_read)) !=
5560fcf3ce44SJohn Forte 		    QLT_SUCCESS) {
5561c4ddbbe1SDaniel Beauregard 			EL(qlt, "Error reading risc ram - EXT RAM status="
5562c4ddbbe1SDaniel Beauregard 			    "%llxh\n", ret);
5563fcf3ce44SJohn Forte 			goto dump_fail;
5564fcf3ce44SJohn Forte 		}
5565fcf3ce44SJohn Forte 		n = qlt_dump_risc_ram(qlt, addr, words_to_read, buf, size_left);
5566fcf3ce44SJohn Forte 		buf += n; size_left -= n;
5567fcf3ce44SJohn Forte 		if (size_left < 100000) {
5568c4ddbbe1SDaniel Beauregard 			EL(qlt, "run out of space - EXT RAM\n");
5569fcf3ce44SJohn Forte 			goto dump_ok;
5570fcf3ce44SJohn Forte 		}
5571fcf3ce44SJohn Forte 		addr += words_to_read;
5572fcf3ce44SJohn Forte 	}
5573fcf3ce44SJohn Forte 
5574fcf3ce44SJohn Forte 	/*
5575fcf3ce44SJohn Forte 	 * Label the end tag
5576fcf3ce44SJohn Forte 	 */
5577c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "[<==END] ISP Debug Dump\n");
5578fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5579fcf3ce44SJohn Forte 
5580fcf3ce44SJohn Forte 	/*
5581fcf3ce44SJohn Forte 	 * Queue dumping
5582fcf3ce44SJohn Forte 	 */
5583c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nRequest Queue\n");
5584fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5585fcf3ce44SJohn Forte 	n = qlt_dump_queue(qlt, qlt->queue_mem_ptr + REQUEST_QUEUE_OFFSET,
5586fcf3ce44SJohn Forte 	    REQUEST_QUEUE_ENTRIES, buf, size_left);
5587fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5588fcf3ce44SJohn Forte 
5589c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nPriority Queue\n");
5590fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5591fcf3ce44SJohn Forte 	n = qlt_dump_queue(qlt, qlt->queue_mem_ptr + PRIORITY_QUEUE_OFFSET,
5592fcf3ce44SJohn Forte 	    PRIORITY_QUEUE_ENTRIES, buf, size_left);
5593fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5594fcf3ce44SJohn Forte 
5595c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nResponse Queue\n");
5596fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5597fcf3ce44SJohn Forte 	n = qlt_dump_queue(qlt, qlt->queue_mem_ptr + RESPONSE_QUEUE_OFFSET,
5598fcf3ce44SJohn Forte 	    RESPONSE_QUEUE_ENTRIES, buf, size_left);
5599fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5600fcf3ce44SJohn Forte 
5601c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nATIO queue\n");
5602fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5603fcf3ce44SJohn Forte 	n = qlt_dump_queue(qlt, qlt->queue_mem_ptr + ATIO_QUEUE_OFFSET,
5604fcf3ce44SJohn Forte 	    ATIO_QUEUE_ENTRIES, buf, size_left);
5605fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5606fcf3ce44SJohn Forte 
5607fcf3ce44SJohn Forte 	/*
5608c4ddbbe1SDaniel Beauregard 	 * Label dump reason
5609fcf3ce44SJohn Forte 	 */
5610c4ddbbe1SDaniel Beauregard 	n = (int)snprintf(buf, size_left, "\nFirmware dump reason: %s-%s\n",
5611fcf3ce44SJohn Forte 	    qlt->qlt_port_alias, ssci->st_additional_info);
5612fcf3ce44SJohn Forte 	buf += n; size_left -= n;
5613fcf3ce44SJohn Forte 
5614fcf3ce44SJohn Forte dump_ok:
5615c4ddbbe1SDaniel Beauregard 	EL(qlt, "left-%d\n", size_left);
5616fcf3ce44SJohn Forte 
5617fcf3ce44SJohn Forte 	mutex_enter(&qlt->qlt_ioctl_lock);
5618fcf3ce44SJohn Forte 	qlt->qlt_ioctl_flags &=
5619d8c54e3dSSam Cramer 	    ~(QLT_FWDUMP_INPROGRESS | QLT_FWDUMP_FETCHED_BY_USER);
5620fcf3ce44SJohn Forte 	qlt->qlt_ioctl_flags |= QLT_FWDUMP_ISVALID;
5621fcf3ce44SJohn Forte 	mutex_exit(&qlt->qlt_ioctl_lock);
5622fcf3ce44SJohn Forte 	return (FCT_SUCCESS);
5623fcf3ce44SJohn Forte 
5624fcf3ce44SJohn Forte dump_fail:
5625c4ddbbe1SDaniel Beauregard 	EL(qlt, "dump not done\n");
5626fcf3ce44SJohn Forte 	mutex_enter(&qlt->qlt_ioctl_lock);
5627fcf3ce44SJohn Forte 	qlt->qlt_ioctl_flags &= QLT_IOCTL_FLAG_MASK;
5628fcf3ce44SJohn Forte 	mutex_exit(&qlt->qlt_ioctl_lock);
5629fcf3ce44SJohn Forte 	return (FCT_FAILURE);
5630fcf3ce44SJohn Forte }
5631fcf3ce44SJohn Forte 
5632fcf3ce44SJohn Forte static int
5633fcf3ce44SJohn Forte qlt_fwdump_dump_regs(qlt_state_t *qlt, caddr_t buf, int startaddr, int count,
5634c4ddbbe1SDaniel Beauregard     uint_t size_left)
5635fcf3ce44SJohn Forte {
5636fcf3ce44SJohn Forte 	int		i;
5637fcf3ce44SJohn Forte 	int		n;
5638fcf3ce44SJohn Forte 	char		c = ' ';
5639fcf3ce44SJohn Forte 
5640fcf3ce44SJohn Forte 	for (i = 0, n = 0; i < count; i++) {
5641fcf3ce44SJohn Forte 		if ((i + 1) & 7) {
5642fcf3ce44SJohn Forte 			c = ' ';
5643fcf3ce44SJohn Forte 		} else {
5644fcf3ce44SJohn Forte 			c = '\n';
5645fcf3ce44SJohn Forte 		}
5646c4ddbbe1SDaniel Beauregard 		n = (int)(n + (int)snprintf(&buf[n], (uint_t)(size_left - n),
5647c4ddbbe1SDaniel Beauregard 		    "%08x%c", REG_RD32(qlt, startaddr + (i << 2)), c));
5648fcf3ce44SJohn Forte 	}
5649fcf3ce44SJohn Forte 	return (n);
5650fcf3ce44SJohn Forte }
5651fcf3ce44SJohn Forte 
5652fcf3ce44SJohn Forte static int
5653fcf3ce44SJohn Forte qlt_dump_risc_ram(qlt_state_t *qlt, uint32_t addr, uint32_t words,
5654c4ddbbe1SDaniel Beauregard     caddr_t buf, uint_t size_left)
5655fcf3ce44SJohn Forte {
5656fcf3ce44SJohn Forte 	int		i;
5657fcf3ce44SJohn Forte 	int		n;
5658fcf3ce44SJohn Forte 	char		c = ' ';
5659fcf3ce44SJohn Forte 	uint32_t	*ptr;
5660fcf3ce44SJohn Forte 
5661fcf3ce44SJohn Forte 	ptr = (uint32_t *)((caddr_t)qlt->queue_mem_ptr + MBOX_DMA_MEM_OFFSET);
5662fcf3ce44SJohn Forte 	for (i = 0, n = 0; i < words; i++) {
5663fcf3ce44SJohn Forte 		if ((i & 7) == 0) {
5664c4ddbbe1SDaniel Beauregard 			n = (int)(n + (int)snprintf(&buf[n],
5665c4ddbbe1SDaniel Beauregard 			    (uint_t)(size_left - n), "%08x: ", addr + i));
5666fcf3ce44SJohn Forte 		}
5667fcf3ce44SJohn Forte 		if ((i + 1) & 7) {
5668fcf3ce44SJohn Forte 			c = ' ';
5669fcf3ce44SJohn Forte 		} else {
5670fcf3ce44SJohn Forte 			c = '\n';
5671fcf3ce44SJohn Forte 		}
5672c4ddbbe1SDaniel Beauregard 		n = (int)(n + (int)snprintf(&buf[n], (uint_t)(size_left - n),
5673c4ddbbe1SDaniel Beauregard 		    "%08x%c", ptr[i], c));
5674fcf3ce44SJohn Forte 	}
5675fcf3ce44SJohn Forte 	return (n);
5676fcf3ce44SJohn Forte }
5677fcf3ce44SJohn Forte 
5678fcf3ce44SJohn Forte static int
5679fcf3ce44SJohn Forte qlt_dump_queue(qlt_state_t *qlt, caddr_t qadr, int entries, caddr_t buf,
5680c4ddbbe1SDaniel Beauregard     uint_t size_left)
5681fcf3ce44SJohn Forte {
5682fcf3ce44SJohn Forte 	int		i;
5683fcf3ce44SJohn Forte 	int		n;
5684fcf3ce44SJohn Forte 	char		c = ' ';
5685fcf3ce44SJohn Forte 	int		words;
5686fcf3ce44SJohn Forte 	uint16_t	*ptr;
5687fcf3ce44SJohn Forte 	uint16_t	w;
5688fcf3ce44SJohn Forte 
5689fcf3ce44SJohn Forte 	words = entries * 32;
5690fcf3ce44SJohn Forte 	ptr = (uint16_t *)qadr;
5691fcf3ce44SJohn Forte 	for (i = 0, n = 0; i < words; i++) {
5692fcf3ce44SJohn Forte 		if ((i & 7) == 0) {
5693c4ddbbe1SDaniel Beauregard 			n = (int)(n + (int)snprintf(&buf[n],
5694c4ddbbe1SDaniel Beauregard 			    (uint_t)(size_left - n), "%05x: ", i));
5695fcf3ce44SJohn Forte 		}
5696fcf3ce44SJohn Forte 		if ((i + 1) & 7) {
5697fcf3ce44SJohn Forte 			c = ' ';
5698fcf3ce44SJohn Forte 		} else {
5699fcf3ce44SJohn Forte 			c = '\n';
5700fcf3ce44SJohn Forte 		}
5701fcf3ce44SJohn Forte 		w = QMEM_RD16(qlt, &ptr[i]);
5702c4ddbbe1SDaniel Beauregard 		n = (int)(n + (int)snprintf(&buf[n], (size_left - n), "%04x%c",
5703c4ddbbe1SDaniel Beauregard 		    w, c));
5704fcf3ce44SJohn Forte 	}
5705fcf3ce44SJohn Forte 	return (n);
5706fcf3ce44SJohn Forte }
5707fcf3ce44SJohn Forte 
5708fcf3ce44SJohn Forte /*
5709fcf3ce44SJohn Forte  * Only called by debug dump. Interrupts are disabled and mailboxes alongwith
5710fcf3ce44SJohn Forte  * mailbox ram is available.
5711fcf3ce44SJohn Forte  * Copy data from RISC RAM to system memory
5712fcf3ce44SJohn Forte  */
5713fcf3ce44SJohn Forte static fct_status_t
5714fcf3ce44SJohn Forte qlt_read_risc_ram(qlt_state_t *qlt, uint32_t addr, uint32_t words)
5715fcf3ce44SJohn Forte {
5716fcf3ce44SJohn Forte 	uint64_t	da;
5717fcf3ce44SJohn Forte 	fct_status_t	ret;
5718fcf3ce44SJohn Forte 
5719*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(0), MBC_DUMP_RAM_EXTENDED);
5720fcf3ce44SJohn Forte 	da = qlt->queue_mem_cookie.dmac_laddress;
5721fcf3ce44SJohn Forte 	da += MBOX_DMA_MEM_OFFSET;
5722fcf3ce44SJohn Forte 
5723*a2255df3SDaniel Beauregard 	/* System destination address */
5724*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(3), LSW(LSD(da)));
5725*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(2), MSW(LSD(da)));
5726*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(7), LSW(MSD(da)));
5727*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(6), MSW(MSD(da)));
5728fcf3ce44SJohn Forte 
5729*a2255df3SDaniel Beauregard 	/* Length */
5730*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(5), LSW(words));
5731*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(4), MSW(words));
5732fcf3ce44SJohn Forte 
5733*a2255df3SDaniel Beauregard 	/* RISC source address */
5734*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(1), LSW(addr));
5735*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(8), MSW(addr));
5736fcf3ce44SJohn Forte 
5737fcf3ce44SJohn Forte 	ret = qlt_raw_mailbox_command(qlt);
5738*a2255df3SDaniel Beauregard 	REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
5739fcf3ce44SJohn Forte 	if (ret == QLT_SUCCESS) {
5740fcf3ce44SJohn Forte 		(void) ddi_dma_sync(qlt->queue_mem_dma_handle,
5741fcf3ce44SJohn Forte 		    MBOX_DMA_MEM_OFFSET, words << 2, DDI_DMA_SYNC_FORCPU);
5742fcf3ce44SJohn Forte 	} else {
5743c4ddbbe1SDaniel Beauregard 		EL(qlt, "qlt_raw_mailbox_command=ch status=%llxh\n", ret);
5744fcf3ce44SJohn Forte 	}
5745fcf3ce44SJohn Forte 	return (ret);
5746fcf3ce44SJohn Forte }
5747c4ddbbe1SDaniel Beauregard 
5748c4ddbbe1SDaniel Beauregard static void
5749c4ddbbe1SDaniel Beauregard qlt_verify_fw(qlt_state_t *qlt)
5750c4ddbbe1SDaniel Beauregard {
5751c4ddbbe1SDaniel Beauregard 	caddr_t req;
5752c4ddbbe1SDaniel Beauregard 	/* Just put it on the request queue */
5753c4ddbbe1SDaniel Beauregard 	mutex_enter(&qlt->req_lock);
5754c4ddbbe1SDaniel Beauregard 	req = qlt_get_req_entries(qlt, 1);
5755c4ddbbe1SDaniel Beauregard 	if (req == NULL) {
5756c4ddbbe1SDaniel Beauregard 		mutex_exit(&qlt->req_lock);
5757c4ddbbe1SDaniel Beauregard 		/* XXX handle this */
5758c4ddbbe1SDaniel Beauregard 		return;
5759c4ddbbe1SDaniel Beauregard 	}
5760c4ddbbe1SDaniel Beauregard 
5761c4ddbbe1SDaniel Beauregard 	bzero(req, IOCB_SIZE);
5762c4ddbbe1SDaniel Beauregard 
5763c4ddbbe1SDaniel Beauregard 	req[0] = 0x1b;
5764c4ddbbe1SDaniel Beauregard 	req[1] = 1;
5765c4ddbbe1SDaniel Beauregard 
5766c4ddbbe1SDaniel Beauregard 	QMEM_WR32(qlt, (&req[4]), 0xffffffff);
5767c4ddbbe1SDaniel Beauregard 	QMEM_WR16(qlt, (&req[0x8]), 1);    /*  options - don't update */
5768c4ddbbe1SDaniel Beauregard 	QMEM_WR32(qlt, (&req[0x14]), 0x80010300);
5769c4ddbbe1SDaniel Beauregard 
5770c4ddbbe1SDaniel Beauregard 	qlt_submit_req_entries(qlt, 1);
5771c4ddbbe1SDaniel Beauregard 	mutex_exit(&qlt->req_lock);
5772c4ddbbe1SDaniel Beauregard }
5773c4ddbbe1SDaniel Beauregard 
5774c4ddbbe1SDaniel Beauregard static void
5775c4ddbbe1SDaniel Beauregard qlt_handle_verify_fw_completion(qlt_state_t *qlt, uint8_t *rsp)
5776c4ddbbe1SDaniel Beauregard {
5777c4ddbbe1SDaniel Beauregard 	uint16_t	status;
5778c4ddbbe1SDaniel Beauregard 	char		info[80];
5779c4ddbbe1SDaniel Beauregard 
5780c4ddbbe1SDaniel Beauregard 	status = QMEM_RD16(qlt, rsp+8);
5781c4ddbbe1SDaniel Beauregard 	if (status != 0) {
5782c4ddbbe1SDaniel Beauregard 		(void) snprintf(info, 80, "qlt_handle_verify_fw_completion: "
5783c4ddbbe1SDaniel Beauregard 		    "status:%x, rsp:%p", status, (void *)rsp);
5784c4ddbbe1SDaniel Beauregard 		if (status == 3) {
5785c4ddbbe1SDaniel Beauregard 			uint16_t error_code;
5786c4ddbbe1SDaniel Beauregard 
5787c4ddbbe1SDaniel Beauregard 			error_code = QMEM_RD16(qlt, rsp+0xA);
5788c4ddbbe1SDaniel Beauregard 			(void) snprintf(info, 80, "qlt_handle_verify_fw_"
5789c4ddbbe1SDaniel Beauregard 			    "completion: error code:%x", error_code);
5790c4ddbbe1SDaniel Beauregard 		}
5791c4ddbbe1SDaniel Beauregard 	}
5792c4ddbbe1SDaniel Beauregard }
5793c4ddbbe1SDaniel Beauregard 
5794c4ddbbe1SDaniel Beauregard /*
5795c4ddbbe1SDaniel Beauregard  * qlt_el_trace_desc_ctor - Construct an extended logging trace descriptor.
5796c4ddbbe1SDaniel Beauregard  *
5797c4ddbbe1SDaniel Beauregard  * Input:	Pointer to the adapter state structure.
5798c4ddbbe1SDaniel Beauregard  * Returns:	Success or Failure.
5799c4ddbbe1SDaniel Beauregard  * Context:	Kernel context.
5800c4ddbbe1SDaniel Beauregard  */
5801c4ddbbe1SDaniel Beauregard static int
5802c4ddbbe1SDaniel Beauregard qlt_el_trace_desc_ctor(qlt_state_t *qlt)
5803c4ddbbe1SDaniel Beauregard {
5804c4ddbbe1SDaniel Beauregard 	int	rval = DDI_SUCCESS;
5805c4ddbbe1SDaniel Beauregard 
5806c4ddbbe1SDaniel Beauregard 	qlt->el_trace_desc = (qlt_el_trace_desc_t *)
5807c4ddbbe1SDaniel Beauregard 	    kmem_zalloc(sizeof (qlt_el_trace_desc_t), KM_SLEEP);
5808c4ddbbe1SDaniel Beauregard 
5809c4ddbbe1SDaniel Beauregard 	if (qlt->el_trace_desc == NULL) {
5810c4ddbbe1SDaniel Beauregard 		cmn_err(CE_WARN, "qlt(%d): can't construct trace descriptor",
5811c4ddbbe1SDaniel Beauregard 		    qlt->instance);
5812c4ddbbe1SDaniel Beauregard 		rval = DDI_FAILURE;
5813c4ddbbe1SDaniel Beauregard 	} else {
5814c4ddbbe1SDaniel Beauregard 		qlt->el_trace_desc->next = 0;
5815c4ddbbe1SDaniel Beauregard 		qlt->el_trace_desc->trace_buffer =
5816c4ddbbe1SDaniel Beauregard 		    (char *)kmem_zalloc(EL_TRACE_BUF_SIZE, KM_SLEEP);
5817c4ddbbe1SDaniel Beauregard 
5818c4ddbbe1SDaniel Beauregard 		if (qlt->el_trace_desc->trace_buffer == NULL) {
5819c4ddbbe1SDaniel Beauregard 			cmn_err(CE_WARN, "qlt(%d): can't get trace buffer",
5820c4ddbbe1SDaniel Beauregard 			    qlt->instance);
5821c4ddbbe1SDaniel Beauregard 			kmem_free(qlt->el_trace_desc,
5822c4ddbbe1SDaniel Beauregard 			    sizeof (qlt_el_trace_desc_t));
5823c4ddbbe1SDaniel Beauregard 			qlt->el_trace_desc = NULL;
5824c4ddbbe1SDaniel Beauregard 			rval = DDI_FAILURE;
5825c4ddbbe1SDaniel Beauregard 		} else {
5826c4ddbbe1SDaniel Beauregard 			qlt->el_trace_desc->trace_buffer_size =
5827c4ddbbe1SDaniel Beauregard 			    EL_TRACE_BUF_SIZE;
5828c4ddbbe1SDaniel Beauregard 			mutex_init(&qlt->el_trace_desc->mutex, NULL,
5829c4ddbbe1SDaniel Beauregard 			    MUTEX_DRIVER, NULL);
5830c4ddbbe1SDaniel Beauregard 		}
5831c4ddbbe1SDaniel Beauregard 	}
5832c4ddbbe1SDaniel Beauregard 
5833c4ddbbe1SDaniel Beauregard 	return (rval);
5834c4ddbbe1SDaniel Beauregard }
5835c4ddbbe1SDaniel Beauregard 
5836c4ddbbe1SDaniel Beauregard /*
5837c4ddbbe1SDaniel Beauregard  * qlt_el_trace_desc_dtor - Destroy an extended logging trace descriptor.
5838c4ddbbe1SDaniel Beauregard  *
5839c4ddbbe1SDaniel Beauregard  * Input:	Pointer to the adapter state structure.
5840c4ddbbe1SDaniel Beauregard  * Returns:	Success or Failure.
5841c4ddbbe1SDaniel Beauregard  * Context:	Kernel context.
5842c4ddbbe1SDaniel Beauregard  */
5843c4ddbbe1SDaniel Beauregard static int
5844c4ddbbe1SDaniel Beauregard qlt_el_trace_desc_dtor(qlt_state_t *qlt)
5845c4ddbbe1SDaniel Beauregard {
5846c4ddbbe1SDaniel Beauregard 	int	rval = DDI_SUCCESS;
5847c4ddbbe1SDaniel Beauregard 
5848c4ddbbe1SDaniel Beauregard 	if (qlt->el_trace_desc == NULL) {
5849c4ddbbe1SDaniel Beauregard 		cmn_err(CE_WARN, "qlt(%d): can't destroy el trace descriptor",
5850c4ddbbe1SDaniel Beauregard 		    qlt->instance);
5851c4ddbbe1SDaniel Beauregard 		rval = DDI_FAILURE;
5852c4ddbbe1SDaniel Beauregard 	} else {
5853c4ddbbe1SDaniel Beauregard 		if (qlt->el_trace_desc->trace_buffer != NULL) {
5854c4ddbbe1SDaniel Beauregard 			kmem_free(qlt->el_trace_desc->trace_buffer,
5855c4ddbbe1SDaniel Beauregard 			    qlt->el_trace_desc->trace_buffer_size);
5856c4ddbbe1SDaniel Beauregard 		}
5857c4ddbbe1SDaniel Beauregard 		mutex_destroy(&qlt->el_trace_desc->mutex);
5858c4ddbbe1SDaniel Beauregard 		kmem_free(qlt->el_trace_desc, sizeof (qlt_el_trace_desc_t));
5859c4ddbbe1SDaniel Beauregard 		qlt->el_trace_desc = NULL;
5860c4ddbbe1SDaniel Beauregard 	}
5861c4ddbbe1SDaniel Beauregard 
5862c4ddbbe1SDaniel Beauregard 	return (rval);
5863c4ddbbe1SDaniel Beauregard }
5864c4ddbbe1SDaniel Beauregard 
5865c4ddbbe1SDaniel Beauregard /*
5866c4ddbbe1SDaniel Beauregard  * qlt_el_msg
5867c4ddbbe1SDaniel Beauregard  *	Extended logging message
5868c4ddbbe1SDaniel Beauregard  *
5869c4ddbbe1SDaniel Beauregard  * Input:
5870c4ddbbe1SDaniel Beauregard  *	qlt:	adapter state pointer.
5871c4ddbbe1SDaniel Beauregard  *	fn:	function name.
5872c4ddbbe1SDaniel Beauregard  *	ce:	level
5873c4ddbbe1SDaniel Beauregard  *	...:	Variable argument list.
5874c4ddbbe1SDaniel Beauregard  *
5875c4ddbbe1SDaniel Beauregard  * Context:
5876c4ddbbe1SDaniel Beauregard  *	Kernel/Interrupt context.
5877c4ddbbe1SDaniel Beauregard  */
5878c4ddbbe1SDaniel Beauregard void
5879c4ddbbe1SDaniel Beauregard qlt_el_msg(qlt_state_t *qlt, const char *fn, int ce, ...)
5880c4ddbbe1SDaniel Beauregard {
5881c4ddbbe1SDaniel Beauregard 	char		*s, *fmt = 0, *fmt1 = 0;
5882c4ddbbe1SDaniel Beauregard 	char		fmt2[EL_BUFFER_RESERVE];
5883c4ddbbe1SDaniel Beauregard 	int		rval, tmp;
5884c4ddbbe1SDaniel Beauregard 	int		tracing = 0;
5885c4ddbbe1SDaniel Beauregard 	va_list		vl;
5886c4ddbbe1SDaniel Beauregard 
5887c4ddbbe1SDaniel Beauregard 	/* Tracing is the default but it can be disabled. */
5888c4ddbbe1SDaniel Beauregard 	if ((rval = qlt_validate_trace_desc(qlt)) == DDI_SUCCESS) {
5889c4ddbbe1SDaniel Beauregard 		tracing = 1;
5890c4ddbbe1SDaniel Beauregard 
5891c4ddbbe1SDaniel Beauregard 		mutex_enter(&qlt->el_trace_desc->mutex);
5892c4ddbbe1SDaniel Beauregard 
5893c4ddbbe1SDaniel Beauregard 		/*
5894c4ddbbe1SDaniel Beauregard 		 * Ensure enough space for the string. Wrap to
5895c4ddbbe1SDaniel Beauregard 		 * start when default message allocation size
5896c4ddbbe1SDaniel Beauregard 		 * would overrun the end.
5897c4ddbbe1SDaniel Beauregard 		 */
5898c4ddbbe1SDaniel Beauregard 		if ((qlt->el_trace_desc->next + EL_BUFFER_RESERVE) >=
5899c4ddbbe1SDaniel Beauregard 		    qlt->el_trace_desc->trace_buffer_size) {
5900c4ddbbe1SDaniel Beauregard 			fmt = qlt->el_trace_desc->trace_buffer;
5901c4ddbbe1SDaniel Beauregard 			qlt->el_trace_desc->next = 0;
5902c4ddbbe1SDaniel Beauregard 		} else {
5903c4ddbbe1SDaniel Beauregard 			fmt = qlt->el_trace_desc->trace_buffer +
5904c4ddbbe1SDaniel Beauregard 			    qlt->el_trace_desc->next;
5905c4ddbbe1SDaniel Beauregard 		}
5906c4ddbbe1SDaniel Beauregard 	}
5907c4ddbbe1SDaniel Beauregard 
5908c4ddbbe1SDaniel Beauregard 	/* if no buffer use the stack */
5909c4ddbbe1SDaniel Beauregard 	if (fmt == NULL) {
5910c4ddbbe1SDaniel Beauregard 		fmt = fmt2;
5911c4ddbbe1SDaniel Beauregard 	}
5912c4ddbbe1SDaniel Beauregard 
5913c4ddbbe1SDaniel Beauregard 	va_start(vl, ce);
5914c4ddbbe1SDaniel Beauregard 
5915c4ddbbe1SDaniel Beauregard 	s = va_arg(vl, char *);
5916c4ddbbe1SDaniel Beauregard 
5917c4ddbbe1SDaniel Beauregard 	rval = (int)snprintf(fmt, (size_t)EL_BUFFER_RESERVE,
5918c4ddbbe1SDaniel Beauregard 	    "QEL qlt(%d): %s, ", qlt->instance, fn);
5919c4ddbbe1SDaniel Beauregard 	fmt1 = fmt + rval;
5920c4ddbbe1SDaniel Beauregard 	tmp = (int)vsnprintf(fmt1,
5921c4ddbbe1SDaniel Beauregard 	    (size_t)(uint32_t)((int)EL_BUFFER_RESERVE - rval), s, vl);
5922c4ddbbe1SDaniel Beauregard 	rval += tmp;
5923c4ddbbe1SDaniel Beauregard 
5924c4ddbbe1SDaniel Beauregard 	/*
5925c4ddbbe1SDaniel Beauregard 	 * Calculate the offset where the next message will go,
5926c4ddbbe1SDaniel Beauregard 	 * skipping the NULL.
5927c4ddbbe1SDaniel Beauregard 	 */
5928c4ddbbe1SDaniel Beauregard 	if (tracing) {
5929c4ddbbe1SDaniel Beauregard 		uint16_t next = (uint16_t)(rval += 1);
5930c4ddbbe1SDaniel Beauregard 		qlt->el_trace_desc->next += next;
5931c4ddbbe1SDaniel Beauregard 		mutex_exit(&qlt->el_trace_desc->mutex);
5932c4ddbbe1SDaniel Beauregard 	}
5933c4ddbbe1SDaniel Beauregard 
5934*a2255df3SDaniel Beauregard 	if (enable_extended_logging) {
5935*a2255df3SDaniel Beauregard 		cmn_err(ce, fmt);
5936*a2255df3SDaniel Beauregard 	}
5937*a2255df3SDaniel Beauregard 
5938c4ddbbe1SDaniel Beauregard 	va_end(vl);
5939c4ddbbe1SDaniel Beauregard }
5940c4ddbbe1SDaniel Beauregard 
5941c4ddbbe1SDaniel Beauregard /*
5942c4ddbbe1SDaniel Beauregard  * qlt_dump_el_trace_buffer
5943c4ddbbe1SDaniel Beauregard  *	 Outputs extended logging trace buffer.
5944c4ddbbe1SDaniel Beauregard  *
5945c4ddbbe1SDaniel Beauregard  * Input:
5946c4ddbbe1SDaniel Beauregard  *	qlt:	adapter state pointer.
5947c4ddbbe1SDaniel Beauregard  */
5948c4ddbbe1SDaniel Beauregard void
5949c4ddbbe1SDaniel Beauregard qlt_dump_el_trace_buffer(qlt_state_t *qlt)
5950c4ddbbe1SDaniel Beauregard {
5951c4ddbbe1SDaniel Beauregard 	char		*dump_start = NULL;
5952c4ddbbe1SDaniel Beauregard 	char		*dump_current = NULL;
5953c4ddbbe1SDaniel Beauregard 	char		*trace_start;
5954c4ddbbe1SDaniel Beauregard 	char		*trace_end;
5955c4ddbbe1SDaniel Beauregard 	int		wrapped = 0;
5956c4ddbbe1SDaniel Beauregard 	int		rval;
5957c4ddbbe1SDaniel Beauregard 
5958c4ddbbe1SDaniel Beauregard 	mutex_enter(&qlt->el_trace_desc->mutex);
5959c4ddbbe1SDaniel Beauregard 
5960c4ddbbe1SDaniel Beauregard 	rval = qlt_validate_trace_desc(qlt);
5961c4ddbbe1SDaniel Beauregard 	if (rval != NULL) {
5962c4ddbbe1SDaniel Beauregard 		cmn_err(CE_CONT, "qlt(%d) Dump EL trace - invalid desc\n",
5963c4ddbbe1SDaniel Beauregard 		    qlt->instance);
5964c4ddbbe1SDaniel Beauregard 	} else if ((dump_start = qlt_find_trace_start(qlt)) != NULL) {
5965c4ddbbe1SDaniel Beauregard 		dump_current = dump_start;
5966c4ddbbe1SDaniel Beauregard 		trace_start = qlt->el_trace_desc->trace_buffer;
5967c4ddbbe1SDaniel Beauregard 		trace_end = trace_start +
5968c4ddbbe1SDaniel Beauregard 		    qlt->el_trace_desc->trace_buffer_size;
5969c4ddbbe1SDaniel Beauregard 
5970c4ddbbe1SDaniel Beauregard 		cmn_err(CE_CONT, "qlt(%d) Dump EL trace - start %p %p\n",
5971c4ddbbe1SDaniel Beauregard 		    qlt->instance,
5972c4ddbbe1SDaniel Beauregard 		    (void *)dump_start, (void *)trace_start);
5973c4ddbbe1SDaniel Beauregard 
5974c4ddbbe1SDaniel Beauregard 		while (((uintptr_t)dump_current - (uintptr_t)trace_start) <=
5975c4ddbbe1SDaniel Beauregard 		    (uintptr_t)qlt->el_trace_desc->trace_buffer_size) {
5976c4ddbbe1SDaniel Beauregard 			/* Show it... */
5977c4ddbbe1SDaniel Beauregard 			cmn_err(CE_CONT, "%p - %s", (void *)dump_current,
5978c4ddbbe1SDaniel Beauregard 			    dump_current);
5979c4ddbbe1SDaniel Beauregard 			/* Make the next the current */
5980c4ddbbe1SDaniel Beauregard 			dump_current += (strlen(dump_current) + 1);
5981c4ddbbe1SDaniel Beauregard 			/* check for wrap */
5982c4ddbbe1SDaniel Beauregard 			if ((dump_current + EL_BUFFER_RESERVE) >= trace_end) {
5983c4ddbbe1SDaniel Beauregard 				dump_current = trace_start;
5984c4ddbbe1SDaniel Beauregard 				wrapped = 1;
5985c4ddbbe1SDaniel Beauregard 			} else if (wrapped) {
5986c4ddbbe1SDaniel Beauregard 				/* Don't go past next. */
5987c4ddbbe1SDaniel Beauregard 				if ((trace_start + qlt->el_trace_desc->next) <=
5988c4ddbbe1SDaniel Beauregard 				    dump_current) {
5989c4ddbbe1SDaniel Beauregard 					break;
5990c4ddbbe1SDaniel Beauregard 				}
5991c4ddbbe1SDaniel Beauregard 			} else if (*dump_current == NULL) {
5992c4ddbbe1SDaniel Beauregard 				break;
5993c4ddbbe1SDaniel Beauregard 			}
5994c4ddbbe1SDaniel Beauregard 		}
5995c4ddbbe1SDaniel Beauregard 	}
5996c4ddbbe1SDaniel Beauregard 	mutex_exit(&qlt->el_trace_desc->mutex);
5997c4ddbbe1SDaniel Beauregard }
5998c4ddbbe1SDaniel Beauregard 
5999c4ddbbe1SDaniel Beauregard /*
6000c4ddbbe1SDaniel Beauregard  * qlt_validate_trace_desc
6001*a2255df3SDaniel Beauregard  *	 Ensures the extended logging trace descriptor is good.
6002c4ddbbe1SDaniel Beauregard  *
6003c4ddbbe1SDaniel Beauregard  * Input:
6004c4ddbbe1SDaniel Beauregard  *	qlt:	adapter state pointer.
6005c4ddbbe1SDaniel Beauregard  *
6006c4ddbbe1SDaniel Beauregard  * Returns:
6007c4ddbbe1SDaniel Beauregard  *	ql local function return status code.
6008c4ddbbe1SDaniel Beauregard  */
6009c4ddbbe1SDaniel Beauregard static int
6010c4ddbbe1SDaniel Beauregard qlt_validate_trace_desc(qlt_state_t *qlt)
6011c4ddbbe1SDaniel Beauregard {
6012c4ddbbe1SDaniel Beauregard 	int	rval = DDI_SUCCESS;
6013c4ddbbe1SDaniel Beauregard 
6014c4ddbbe1SDaniel Beauregard 	if (qlt->el_trace_desc == NULL) {
6015c4ddbbe1SDaniel Beauregard 		rval = DDI_FAILURE;
6016c4ddbbe1SDaniel Beauregard 	} else if (qlt->el_trace_desc->trace_buffer == NULL) {
6017c4ddbbe1SDaniel Beauregard 		rval = DDI_FAILURE;
6018c4ddbbe1SDaniel Beauregard 	}
6019c4ddbbe1SDaniel Beauregard 	return (rval);
6020c4ddbbe1SDaniel Beauregard }
6021c4ddbbe1SDaniel Beauregard 
6022c4ddbbe1SDaniel Beauregard /*
6023c4ddbbe1SDaniel Beauregard  * qlt_find_trace_start
6024c4ddbbe1SDaniel Beauregard  *	 Locate the oldest extended logging trace entry.
6025c4ddbbe1SDaniel Beauregard  *
6026c4ddbbe1SDaniel Beauregard  * Input:
6027c4ddbbe1SDaniel Beauregard  *	qlt:	adapter state pointer.
6028c4ddbbe1SDaniel Beauregard  *
6029c4ddbbe1SDaniel Beauregard  * Returns:
6030c4ddbbe1SDaniel Beauregard  *	Pointer to a string.
6031c4ddbbe1SDaniel Beauregard  *
6032c4ddbbe1SDaniel Beauregard  * Context:
6033c4ddbbe1SDaniel Beauregard  *	Kernel/Interrupt context.
6034c4ddbbe1SDaniel Beauregard  */
6035c4ddbbe1SDaniel Beauregard static char *
6036c4ddbbe1SDaniel Beauregard qlt_find_trace_start(qlt_state_t *qlt)
6037c4ddbbe1SDaniel Beauregard {
6038c4ddbbe1SDaniel Beauregard 	char	*trace_start = 0;
6039c4ddbbe1SDaniel Beauregard 	char	*trace_next  = 0;
6040c4ddbbe1SDaniel Beauregard 
6041c4ddbbe1SDaniel Beauregard 	trace_next = qlt->el_trace_desc->trace_buffer +
6042c4ddbbe1SDaniel Beauregard 	    qlt->el_trace_desc->next;
6043c4ddbbe1SDaniel Beauregard 
6044c4ddbbe1SDaniel Beauregard 	/*
60450ff6bfafSDaniel Beauregard 	 * If the buffer has not wrapped next will point at a null so
60460ff6bfafSDaniel Beauregard 	 * start is the beginning of the buffer.  If next points at a char
6047c4ddbbe1SDaniel Beauregard 	 * then we must traverse the buffer until a null is detected and
6048c4ddbbe1SDaniel Beauregard 	 * that will be the beginning of the oldest whole object in the buffer
6049c4ddbbe1SDaniel Beauregard 	 * which is the start.
6050c4ddbbe1SDaniel Beauregard 	 */
6051c4ddbbe1SDaniel Beauregard 
6052c4ddbbe1SDaniel Beauregard 	if ((trace_next + EL_BUFFER_RESERVE) >=
6053c4ddbbe1SDaniel Beauregard 	    (qlt->el_trace_desc->trace_buffer +
6054c4ddbbe1SDaniel Beauregard 	    qlt->el_trace_desc->trace_buffer_size)) {
6055c4ddbbe1SDaniel Beauregard 		trace_start = qlt->el_trace_desc->trace_buffer;
6056c4ddbbe1SDaniel Beauregard 	} else if (*trace_next != NULL) {
6057c4ddbbe1SDaniel Beauregard 		trace_start = trace_next + (strlen(trace_next) + 1);
6058c4ddbbe1SDaniel Beauregard 	} else {
6059c4ddbbe1SDaniel Beauregard 		trace_start = qlt->el_trace_desc->trace_buffer;
6060c4ddbbe1SDaniel Beauregard 	}
6061c4ddbbe1SDaniel Beauregard 	return (trace_start);
6062c4ddbbe1SDaniel Beauregard }
60630ff6bfafSDaniel Beauregard 
60640ff6bfafSDaniel Beauregard 
60650ff6bfafSDaniel Beauregard static int
60660ff6bfafSDaniel Beauregard qlt_read_int_prop(qlt_state_t *qlt, char *prop, int defval)
60670ff6bfafSDaniel Beauregard {
60680ff6bfafSDaniel Beauregard 	return (ddi_getprop(DDI_DEV_T_ANY, qlt->dip,
60690ff6bfafSDaniel Beauregard 	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, prop, defval));
60700ff6bfafSDaniel Beauregard }
60710ff6bfafSDaniel Beauregard 
60720ff6bfafSDaniel Beauregard static int
60730ff6bfafSDaniel Beauregard qlt_read_string_prop(qlt_state_t *qlt, char *prop, char **prop_val)
60740ff6bfafSDaniel Beauregard {
60750ff6bfafSDaniel Beauregard 	return (ddi_prop_lookup_string(DDI_DEV_T_ANY, qlt->dip,
60760ff6bfafSDaniel Beauregard 	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, prop, prop_val));
60770ff6bfafSDaniel Beauregard }
60780ff6bfafSDaniel Beauregard 
6079*a2255df3SDaniel Beauregard static int
6080*a2255df3SDaniel Beauregard qlt_read_int_instance_prop(qlt_state_t *qlt, char *prop, int defval)
6081*a2255df3SDaniel Beauregard {
6082*a2255df3SDaniel Beauregard 	char		inst_prop[256];
6083*a2255df3SDaniel Beauregard 	int		val;
6084*a2255df3SDaniel Beauregard 
6085*a2255df3SDaniel Beauregard 	/*
6086*a2255df3SDaniel Beauregard 	 * Get adapter instance specific parameters. If the instance
6087*a2255df3SDaniel Beauregard 	 * specific parameter isn't there, try the global parameter.
6088*a2255df3SDaniel Beauregard 	 */
6089*a2255df3SDaniel Beauregard 
6090*a2255df3SDaniel Beauregard 	(void) sprintf(inst_prop, "hba%d-%s", qlt->instance, prop);
6091*a2255df3SDaniel Beauregard 
6092*a2255df3SDaniel Beauregard 	if ((val = qlt_read_int_prop(qlt, inst_prop, defval)) == defval) {
6093*a2255df3SDaniel Beauregard 		val = qlt_read_int_prop(qlt, prop, defval);
6094*a2255df3SDaniel Beauregard 	}
6095*a2255df3SDaniel Beauregard 
6096*a2255df3SDaniel Beauregard 	return (val);
6097*a2255df3SDaniel Beauregard }
6098*a2255df3SDaniel Beauregard 
60990ff6bfafSDaniel Beauregard static int
61000ff6bfafSDaniel Beauregard qlt_read_string_instance_prop(qlt_state_t *qlt, char *prop, char **prop_val)
61010ff6bfafSDaniel Beauregard {
61020ff6bfafSDaniel Beauregard 	char		instance_prop[256];
61030ff6bfafSDaniel Beauregard 
61040ff6bfafSDaniel Beauregard 	/* Get adapter instance specific parameter. */
61050ff6bfafSDaniel Beauregard 	(void) sprintf(instance_prop, "hba%d-%s", qlt->instance, prop);
61060ff6bfafSDaniel Beauregard 	return (qlt_read_string_prop(qlt, instance_prop, prop_val));
61070ff6bfafSDaniel Beauregard }
61080ff6bfafSDaniel Beauregard 
61090ff6bfafSDaniel Beauregard static int
61100ff6bfafSDaniel Beauregard qlt_convert_string_to_ull(char *prop, int radix,
61110ff6bfafSDaniel Beauregard     u_longlong_t *result)
61120ff6bfafSDaniel Beauregard {
61130ff6bfafSDaniel Beauregard 	return (ddi_strtoull((const char *)prop, 0, radix, result));
61140ff6bfafSDaniel Beauregard }
61150ff6bfafSDaniel Beauregard 
61160ff6bfafSDaniel Beauregard static boolean_t
61170ff6bfafSDaniel Beauregard qlt_wwn_overload_prop(qlt_state_t *qlt)
61180ff6bfafSDaniel Beauregard {
61190ff6bfafSDaniel Beauregard 	char		*prop_val = 0;
61200ff6bfafSDaniel Beauregard 	int		rval;
61210ff6bfafSDaniel Beauregard 	int		radix;
61220ff6bfafSDaniel Beauregard 	u_longlong_t	wwnn = 0, wwpn = 0;
61230ff6bfafSDaniel Beauregard 	boolean_t	overloaded = FALSE;
61240ff6bfafSDaniel Beauregard 
61250ff6bfafSDaniel Beauregard 	radix = 16;
61260ff6bfafSDaniel Beauregard 
61270ff6bfafSDaniel Beauregard 	rval = qlt_read_string_instance_prop(qlt, "adapter-wwnn", &prop_val);
61280ff6bfafSDaniel Beauregard 	if (rval == DDI_PROP_SUCCESS) {
61290ff6bfafSDaniel Beauregard 		rval = qlt_convert_string_to_ull(prop_val, radix, &wwnn);
61300ff6bfafSDaniel Beauregard 	}
61310ff6bfafSDaniel Beauregard 	if (rval == DDI_PROP_SUCCESS) {
61320ff6bfafSDaniel Beauregard 		rval = qlt_read_string_instance_prop(qlt, "adapter-wwpn",
61330ff6bfafSDaniel Beauregard 		    &prop_val);
61340ff6bfafSDaniel Beauregard 		if (rval == DDI_PROP_SUCCESS) {
61350ff6bfafSDaniel Beauregard 			rval = qlt_convert_string_to_ull(prop_val, radix,
61360ff6bfafSDaniel Beauregard 			    &wwpn);
61370ff6bfafSDaniel Beauregard 		}
61380ff6bfafSDaniel Beauregard 	}
61390ff6bfafSDaniel Beauregard 	if (rval == DDI_PROP_SUCCESS) {
61400ff6bfafSDaniel Beauregard 		overloaded = TRUE;
61410ff6bfafSDaniel Beauregard 		/* Overload the current node/port name nvram copy */
61420ff6bfafSDaniel Beauregard 		bcopy((char *)&wwnn, qlt->nvram->node_name, 8);
61430ff6bfafSDaniel Beauregard 		BIG_ENDIAN_64(qlt->nvram->node_name);
61440ff6bfafSDaniel Beauregard 		bcopy((char *)&wwpn, qlt->nvram->port_name, 8);
61450ff6bfafSDaniel Beauregard 		BIG_ENDIAN_64(qlt->nvram->port_name);
61460ff6bfafSDaniel Beauregard 	}
61470ff6bfafSDaniel Beauregard 	return (overloaded);
61480ff6bfafSDaniel Beauregard }
61490ff6bfafSDaniel Beauregard 
61500ff6bfafSDaniel Beauregard /*
61510ff6bfafSDaniel Beauregard  * prop_text - Return a pointer to a string describing the status
61520ff6bfafSDaniel Beauregard  *
61530ff6bfafSDaniel Beauregard  * Input:	prop_status = the return status from a property function.
61540ff6bfafSDaniel Beauregard  * Returns:	pointer to a string.
61550ff6bfafSDaniel Beauregard  * Context:	Kernel context.
61560ff6bfafSDaniel Beauregard  */
61570ff6bfafSDaniel Beauregard char *
61580ff6bfafSDaniel Beauregard prop_text(int prop_status)
61590ff6bfafSDaniel Beauregard {
61600ff6bfafSDaniel Beauregard 	string_table_t *entry = &prop_status_tbl[0];
61610ff6bfafSDaniel Beauregard 
61620ff6bfafSDaniel Beauregard 	return (value2string(entry, prop_status, 0xFFFF));
61630ff6bfafSDaniel Beauregard }
61640ff6bfafSDaniel Beauregard 
61650ff6bfafSDaniel Beauregard /*
61660ff6bfafSDaniel Beauregard  * value2string	Return a pointer to a string associated with the value
61670ff6bfafSDaniel Beauregard  *
61680ff6bfafSDaniel Beauregard  * Input:	entry = the value to string table
61690ff6bfafSDaniel Beauregard  *		value = the value
61700ff6bfafSDaniel Beauregard  * Returns:	pointer to a string.
61710ff6bfafSDaniel Beauregard  * Context:	Kernel context.
61720ff6bfafSDaniel Beauregard  */
61730ff6bfafSDaniel Beauregard char *
61740ff6bfafSDaniel Beauregard value2string(string_table_t *entry, int value, int delimiter)
61750ff6bfafSDaniel Beauregard {
61760ff6bfafSDaniel Beauregard 	for (; entry->value != delimiter; entry++) {
61770ff6bfafSDaniel Beauregard 		if (entry->value == value) {
61780ff6bfafSDaniel Beauregard 			break;
61790ff6bfafSDaniel Beauregard 		}
61800ff6bfafSDaniel Beauregard 	}
61810ff6bfafSDaniel Beauregard 	return (entry->string);
61820ff6bfafSDaniel Beauregard }
61830ff6bfafSDaniel Beauregard 
61840ff6bfafSDaniel Beauregard /*
61850ff6bfafSDaniel Beauregard  * qlt_chg_endian Change endianess of byte array.
61860ff6bfafSDaniel Beauregard  *
61870ff6bfafSDaniel Beauregard  * Input:	buf = array pointer.
61880ff6bfafSDaniel Beauregard  *		size = size of array in bytes.
61890ff6bfafSDaniel Beauregard  *
61900ff6bfafSDaniel Beauregard  * Context:	Interrupt or Kernel context.
61910ff6bfafSDaniel Beauregard  */
61920ff6bfafSDaniel Beauregard void
61930ff6bfafSDaniel Beauregard qlt_chg_endian(uint8_t buf[], size_t size)
61940ff6bfafSDaniel Beauregard {
61950ff6bfafSDaniel Beauregard 	uint8_t byte;
61960ff6bfafSDaniel Beauregard 	size_t  cnt1;
61970ff6bfafSDaniel Beauregard 	size_t  cnt;
61980ff6bfafSDaniel Beauregard 
61990ff6bfafSDaniel Beauregard 	cnt1 = size - 1;
62000ff6bfafSDaniel Beauregard 	for (cnt = 0; cnt < size / 2; cnt++) {
62010ff6bfafSDaniel Beauregard 		byte = buf[cnt1];
62020ff6bfafSDaniel Beauregard 		buf[cnt1] = buf[cnt];
62030ff6bfafSDaniel Beauregard 		buf[cnt] = byte;
62040ff6bfafSDaniel Beauregard 		cnt1--;
62050ff6bfafSDaniel Beauregard 	}
62060ff6bfafSDaniel Beauregard }
6207*a2255df3SDaniel Beauregard 
6208*a2255df3SDaniel Beauregard /*
6209*a2255df3SDaniel Beauregard  * ql_mps_reset
6210*a2255df3SDaniel Beauregard  *	Reset MPS for FCoE functions.
6211*a2255df3SDaniel Beauregard  *
6212*a2255df3SDaniel Beauregard  * Input:
6213*a2255df3SDaniel Beauregard  *	ha = virtual adapter state pointer.
6214*a2255df3SDaniel Beauregard  *
6215*a2255df3SDaniel Beauregard  * Context:
6216*a2255df3SDaniel Beauregard  *	Kernel context.
6217*a2255df3SDaniel Beauregard  */
6218*a2255df3SDaniel Beauregard static void
6219*a2255df3SDaniel Beauregard qlt_mps_reset(qlt_state_t *qlt)
6220*a2255df3SDaniel Beauregard {
6221*a2255df3SDaniel Beauregard 	uint32_t	data, dctl = 1000;
6222*a2255df3SDaniel Beauregard 
6223*a2255df3SDaniel Beauregard 	do {
6224*a2255df3SDaniel Beauregard 		if (dctl-- == 0 || qlt_raw_wrt_risc_ram_word(qlt, 0x7c00, 1) !=
6225*a2255df3SDaniel Beauregard 		    QLT_SUCCESS) {
6226*a2255df3SDaniel Beauregard 			return;
6227*a2255df3SDaniel Beauregard 		}
6228*a2255df3SDaniel Beauregard 		if (qlt_raw_rd_risc_ram_word(qlt, 0x7c00, &data) !=
6229*a2255df3SDaniel Beauregard 		    QLT_SUCCESS) {
6230*a2255df3SDaniel Beauregard 			qlt_raw_wrt_risc_ram_word(qlt, 0x7c00, 0);
6231*a2255df3SDaniel Beauregard 			return;
6232*a2255df3SDaniel Beauregard 		}
6233*a2255df3SDaniel Beauregard 	} while (!(data & BIT_0));
6234*a2255df3SDaniel Beauregard 
6235*a2255df3SDaniel Beauregard 	if (qlt_raw_rd_risc_ram_word(qlt, 0x7A15, &data) == QLT_SUCCESS) {
6236*a2255df3SDaniel Beauregard 		dctl = (uint16_t)PCICFG_RD16(qlt, 0x54);
6237*a2255df3SDaniel Beauregard 		if ((data & 0xe0) != (dctl & 0xe0)) {
6238*a2255df3SDaniel Beauregard 			data &= 0xff1f;
6239*a2255df3SDaniel Beauregard 			data |= dctl & 0xe0;
6240*a2255df3SDaniel Beauregard 			qlt_raw_wrt_risc_ram_word(qlt, 0x7A15, data);
6241*a2255df3SDaniel Beauregard 		}
6242*a2255df3SDaniel Beauregard 	}
6243*a2255df3SDaniel Beauregard 	qlt_raw_wrt_risc_ram_word(qlt, 0x7c00, 0);
6244*a2255df3SDaniel Beauregard }
6245*a2255df3SDaniel Beauregard 
6246*a2255df3SDaniel Beauregard /*
6247*a2255df3SDaniel Beauregard  * qlt_raw_wrt_risc_ram_word
6248*a2255df3SDaniel Beauregard  *	Write RISC RAM word.
6249*a2255df3SDaniel Beauregard  *
6250*a2255df3SDaniel Beauregard  * Input:	qlt:		adapter state pointer.
6251*a2255df3SDaniel Beauregard  *		risc_address:	risc ram word address.
6252*a2255df3SDaniel Beauregard  *		data:		data.
6253*a2255df3SDaniel Beauregard  *
6254*a2255df3SDaniel Beauregard  * Returns:	qlt local function return status code.
6255*a2255df3SDaniel Beauregard  *
6256*a2255df3SDaniel Beauregard  * Context:	Kernel context.
6257*a2255df3SDaniel Beauregard  */
6258*a2255df3SDaniel Beauregard static fct_status_t
6259*a2255df3SDaniel Beauregard qlt_raw_wrt_risc_ram_word(qlt_state_t *qlt, uint32_t risc_address,
6260*a2255df3SDaniel Beauregard     uint32_t data)
6261*a2255df3SDaniel Beauregard {
6262*a2255df3SDaniel Beauregard 	fct_status_t	ret;
6263*a2255df3SDaniel Beauregard 
6264*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(0), MBC_WRITE_RAM_EXTENDED);
6265*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(1), LSW(risc_address));
6266*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(2), LSW(data));
6267*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(3), MSW(data));
6268*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(8), MSW(risc_address));
6269*a2255df3SDaniel Beauregard 	ret = qlt_raw_mailbox_command(qlt);
6270*a2255df3SDaniel Beauregard 	REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
6271*a2255df3SDaniel Beauregard 	if (ret != QLT_SUCCESS) {
6272*a2255df3SDaniel Beauregard 		EL(qlt, "qlt_raw_mailbox_command=MBC_WRITE_RAM_EXTENDED status"
6273*a2255df3SDaniel Beauregard 		    "=%llxh\n", ret);
6274*a2255df3SDaniel Beauregard 	}
6275*a2255df3SDaniel Beauregard 	return (ret);
6276*a2255df3SDaniel Beauregard }
6277*a2255df3SDaniel Beauregard 
6278*a2255df3SDaniel Beauregard /*
6279*a2255df3SDaniel Beauregard  * ql_raw_rd_risc_ram_word
6280*a2255df3SDaniel Beauregard  *	Read RISC RAM word.
6281*a2255df3SDaniel Beauregard  *
6282*a2255df3SDaniel Beauregard  * Input:	qlt:		adapter state pointer.
6283*a2255df3SDaniel Beauregard  *		risc_address:	risc ram word address.
6284*a2255df3SDaniel Beauregard  *		data:		data pointer.
6285*a2255df3SDaniel Beauregard  *
6286*a2255df3SDaniel Beauregard  * Returns:	ql local function return status code.
6287*a2255df3SDaniel Beauregard  *
6288*a2255df3SDaniel Beauregard  * Context:	Kernel context.
6289*a2255df3SDaniel Beauregard  */
6290*a2255df3SDaniel Beauregard static fct_status_t
6291*a2255df3SDaniel Beauregard qlt_raw_rd_risc_ram_word(qlt_state_t *qlt, uint32_t risc_address,
6292*a2255df3SDaniel Beauregard     uint32_t *data)
6293*a2255df3SDaniel Beauregard {
6294*a2255df3SDaniel Beauregard 	fct_status_t	ret;
6295*a2255df3SDaniel Beauregard 
6296*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(0), MBC_READ_RAM_EXTENDED);
6297*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(1), LSW(risc_address));
6298*a2255df3SDaniel Beauregard 	REG_WR16(qlt, REG_MBOX(2), MSW(risc_address));
6299*a2255df3SDaniel Beauregard 	ret = qlt_raw_mailbox_command(qlt);
6300*a2255df3SDaniel Beauregard 	*data = REG_RD16(qlt, REG_MBOX(2));
6301*a2255df3SDaniel Beauregard 	*data |= (REG_RD16(qlt, REG_MBOX(3)) << 16);
6302*a2255df3SDaniel Beauregard 	REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
6303*a2255df3SDaniel Beauregard 	if (ret != QLT_SUCCESS) {
6304*a2255df3SDaniel Beauregard 		EL(qlt, "qlt_raw_mailbox_command=MBC_READ_RAM_EXTENDED status"
6305*a2255df3SDaniel Beauregard 		    "=%llxh\n", ret);
6306*a2255df3SDaniel Beauregard 	}
6307*a2255df3SDaniel Beauregard 	return (ret);
6308*a2255df3SDaniel Beauregard }
6309*a2255df3SDaniel Beauregard 
6310*a2255df3SDaniel Beauregard static void
6311*a2255df3SDaniel Beauregard qlt_properties(qlt_state_t *qlt)
6312*a2255df3SDaniel Beauregard {
6313*a2255df3SDaniel Beauregard 	int32_t		cnt = 0;
6314*a2255df3SDaniel Beauregard 	int32_t		defval = 0xffff;
6315*a2255df3SDaniel Beauregard 
6316*a2255df3SDaniel Beauregard 	if (qlt_wwn_overload_prop(qlt) == TRUE) {
6317*a2255df3SDaniel Beauregard 		EL(qlt, "wwnn overloaded.\n");
6318*a2255df3SDaniel Beauregard 	}
6319*a2255df3SDaniel Beauregard 
6320*a2255df3SDaniel Beauregard 	if ((cnt = qlt_read_int_instance_prop(qlt, "bucketcnt2k", defval)) !=
6321*a2255df3SDaniel Beauregard 	    defval) {
6322*a2255df3SDaniel Beauregard 		qlt->qlt_bucketcnt[0] = cnt;
6323*a2255df3SDaniel Beauregard 		EL(qlt, "2k bucket o/l=%d\n", cnt);
6324*a2255df3SDaniel Beauregard 	}
6325*a2255df3SDaniel Beauregard 
6326*a2255df3SDaniel Beauregard 	if ((cnt = qlt_read_int_instance_prop(qlt, "bucketcnt8k", defval)) !=
6327*a2255df3SDaniel Beauregard 	    defval) {
6328*a2255df3SDaniel Beauregard 		qlt->qlt_bucketcnt[1] = cnt;
6329*a2255df3SDaniel Beauregard 		EL(qlt, "8k bucket o/l=%d\n", cnt);
6330*a2255df3SDaniel Beauregard 	}
6331*a2255df3SDaniel Beauregard 
6332*a2255df3SDaniel Beauregard 	if ((cnt = qlt_read_int_instance_prop(qlt, "bucketcnt64k", defval)) !=
6333*a2255df3SDaniel Beauregard 	    defval) {
6334*a2255df3SDaniel Beauregard 		qlt->qlt_bucketcnt[2] = cnt;
6335*a2255df3SDaniel Beauregard 		EL(qlt, "64k bucket o/l=%d\n", cnt);
6336*a2255df3SDaniel Beauregard 	}
6337*a2255df3SDaniel Beauregard 
6338*a2255df3SDaniel Beauregard 	if ((cnt = qlt_read_int_instance_prop(qlt, "bucketcnt128k", defval)) !=
6339*a2255df3SDaniel Beauregard 	    defval) {
6340*a2255df3SDaniel Beauregard 		qlt->qlt_bucketcnt[3] = cnt;
6341*a2255df3SDaniel Beauregard 		EL(qlt, "128k bucket o/l=%d\n", cnt);
6342*a2255df3SDaniel Beauregard 	}
6343*a2255df3SDaniel Beauregard 
6344*a2255df3SDaniel Beauregard 	if ((cnt = qlt_read_int_instance_prop(qlt, "bucketcnt256", defval)) !=
6345*a2255df3SDaniel Beauregard 	    defval) {
6346*a2255df3SDaniel Beauregard 		qlt->qlt_bucketcnt[4] = cnt;
6347*a2255df3SDaniel Beauregard 		EL(qlt, "256k bucket o/l=%d\n", cnt);
6348*a2255df3SDaniel Beauregard 	}
6349*a2255df3SDaniel Beauregard }
6350