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