1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte  * CDDL HEADER START
3fcf3ce44SJohn Forte  *
4fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte  *
8fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte  * and limitations under the License.
12fcf3ce44SJohn Forte  *
13fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte  *
19fcf3ce44SJohn Forte  * CDDL HEADER END
20fcf3ce44SJohn Forte  */
21c4ddbbe1SDaniel Beauregard 
22c4ddbbe1SDaniel Beauregard /*
23c4ddbbe1SDaniel Beauregard  * Copyright 2009 QLogic Corporation.  All rights reserved.
24c4ddbbe1SDaniel Beauregard  * Use is subject to license terms.
25c4ddbbe1SDaniel Beauregard  */
26c4ddbbe1SDaniel Beauregard 
27fcf3ce44SJohn Forte /*
283fb517f7SJames Moore  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
29fcf3ce44SJohn Forte  */
30fcf3ce44SJohn Forte 
31fcf3ce44SJohn Forte #include <sys/conf.h>
32fcf3ce44SJohn Forte #include <sys/ddi.h>
33fcf3ce44SJohn Forte #include <sys/stat.h>
34fcf3ce44SJohn Forte #include <sys/pci.h>
35fcf3ce44SJohn Forte #include <sys/sunddi.h>
36fcf3ce44SJohn Forte #include <sys/modctl.h>
37fcf3ce44SJohn Forte #include <sys/file.h>
38fcf3ce44SJohn Forte #include <sys/cred.h>
39fcf3ce44SJohn Forte #include <sys/byteorder.h>
40fcf3ce44SJohn Forte #include <sys/atomic.h>
41fcf3ce44SJohn Forte #include <sys/scsi/scsi.h>
42fcf3ce44SJohn Forte 
434558d122SViswanathan Kannappan #include <sys/stmf_defines.h>
444558d122SViswanathan Kannappan #include <sys/fct_defines.h>
454558d122SViswanathan Kannappan #include <sys/stmf.h>
464558d122SViswanathan Kannappan #include <sys/stmf_ioctl.h>
474558d122SViswanathan Kannappan #include <sys/portif.h>
484558d122SViswanathan Kannappan #include <sys/fct.h>
494558d122SViswanathan Kannappan 
504558d122SViswanathan Kannappan #include "qlt.h"
514558d122SViswanathan Kannappan #include "qlt_dma.h"
524558d122SViswanathan Kannappan #include "qlt_ioctl.h"
534558d122SViswanathan Kannappan #include "qlt_open.h"
54fcf3ce44SJohn Forte 
55fcf3ce44SJohn Forte static int qlt_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
56fcf3ce44SJohn Forte static int qlt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
57a2255df3SDaniel Beauregard static void qlt_enable_intr(qlt_state_t *);
58a2255df3SDaniel Beauregard static void qlt_disable_intr(qlt_state_t *);
59a2255df3SDaniel Beauregard static fct_status_t qlt_reset_chip(qlt_state_t *qlt);
60a2255df3SDaniel Beauregard static fct_status_t qlt_download_fw(qlt_state_t *qlt);
61fcf3ce44SJohn Forte static fct_status_t qlt_load_risc_ram(qlt_state_t *qlt, uint32_t *host_addr,
62fcf3ce44SJohn Forte     uint32_t word_count, uint32_t risc_addr);
63fcf3ce44SJohn Forte static fct_status_t qlt_raw_mailbox_command(qlt_state_t *qlt);
64fcf3ce44SJohn Forte static mbox_cmd_t *qlt_alloc_mailbox_command(qlt_state_t *qlt,
65fcf3ce44SJohn Forte 					uint32_t dma_size);
66fcf3ce44SJohn Forte void qlt_free_mailbox_command(qlt_state_t *qlt, mbox_cmd_t *mcp);
67fcf3ce44SJohn Forte static fct_status_t qlt_mailbox_command(qlt_state_t *qlt, mbox_cmd_t *mcp);
68fcf3ce44SJohn Forte static uint_t qlt_isr(caddr_t arg, caddr_t arg2);
69fcf3ce44SJohn Forte static fct_status_t qlt_firmware_dump(fct_local_port_t *port,
70fcf3ce44SJohn Forte     stmf_state_change_info_t *ssci);
71fcf3ce44SJohn Forte static void qlt_handle_inot(qlt_state_t *qlt, uint8_t *inot);
72fcf3ce44SJohn Forte static void qlt_handle_purex(qlt_state_t *qlt, uint8_t *resp);
73fcf3ce44SJohn Forte static void qlt_handle_atio(qlt_state_t *qlt, uint8_t *atio);
74fcf3ce44SJohn Forte static void qlt_handle_ctio_completion(qlt_state_t *qlt, uint8_t *rsp);
75fcf3ce44SJohn Forte static void qlt_handle_sol_abort_completion(qlt_state_t *qlt, uint8_t *rsp);
76fcf3ce44SJohn Forte static void qlt_handle_dereg_completion(qlt_state_t *qlt, uint8_t *rsp);
77fcf3ce44SJohn Forte static void qlt_handle_unsol_els_completion(qlt_state_t *qlt, uint8_t *rsp);
78fcf3ce44SJohn Forte static void qlt_handle_unsol_els_abort_completion(qlt_state_t *qlt,
79fcf3ce44SJohn Forte     uint8_t *rsp);
80fcf3ce44SJohn Forte static void qlt_handle_sol_els_completion(qlt_state_t *qlt, uint8_t *rsp);
81fcf3ce44SJohn Forte static void qlt_handle_rcvd_abts(qlt_state_t *qlt, uint8_t *resp);
82fcf3ce44SJohn Forte static void qlt_handle_abts_completion(qlt_state_t *qlt, uint8_t *resp);
83fcf3ce44SJohn Forte static fct_status_t qlt_read_nvram(qlt_state_t *qlt);
84c4ddbbe1SDaniel Beauregard static void qlt_verify_fw(qlt_state_t *qlt);
85c4ddbbe1SDaniel Beauregard static void qlt_handle_verify_fw_completion(qlt_state_t *qlt, uint8_t *rsp);
86fcf3ce44SJohn Forte fct_status_t qlt_port_start(caddr_t arg);
87fcf3ce44SJohn Forte fct_status_t qlt_port_stop(caddr_t arg);
88fcf3ce44SJohn Forte fct_status_t qlt_port_online(qlt_state_t *qlt);
89fcf3ce44SJohn Forte fct_status_t qlt_port_offline(qlt_state_t *qlt);
90fcf3ce44SJohn Forte static fct_status_t qlt_get_link_info(fct_local_port_t *port,
91fcf3ce44SJohn Forte     fct_link_info_t *li);
92fcf3ce44SJohn Forte static void qlt_ctl(struct fct_local_port *port, int cmd, void *arg);
93a2255df3SDaniel Beauregard static fct_status_t qlt_force_lip(qlt_state_t *);
94fcf3ce44SJohn Forte static fct_status_t qlt_do_flogi(struct fct_local_port *port,
95fcf3ce44SJohn Forte 						fct_flogi_xchg_t *fx);
96fcf3ce44SJohn Forte void qlt_handle_atio_queue_update(qlt_state_t *qlt);
97fcf3ce44SJohn Forte void qlt_handle_resp_queue_update(qlt_state_t *qlt);
98fcf3ce44SJohn Forte fct_status_t qlt_register_remote_port(fct_local_port_t *port,
99fcf3ce44SJohn Forte     fct_remote_port_t *rp, fct_cmd_t *login);
100fcf3ce44SJohn Forte fct_status_t qlt_deregister_remote_port(fct_local_port_t *port,
101fcf3ce44SJohn Forte     fct_remote_port_t *rp);
102fcf3ce44SJohn Forte fct_status_t qlt_send_cmd_response(fct_cmd_t *cmd, uint32_t ioflags);
103fcf3ce44SJohn Forte fct_status_t qlt_send_els_response(qlt_state_t *qlt, fct_cmd_t *cmd);
104fcf3ce44SJohn Forte fct_status_t qlt_send_abts_response(qlt_state_t *qlt,
105fcf3ce44SJohn Forte     fct_cmd_t *cmd, int terminate);
106fcf3ce44SJohn Forte static void qlt_handle_inot(qlt_state_t *qlt, uint8_t *inot);
107fcf3ce44SJohn Forte int qlt_set_uniq_flag(uint16_t *ptr, uint16_t setf, uint16_t abortf);
108fcf3ce44SJohn Forte fct_status_t qlt_abort_cmd(struct fct_local_port *port,
109fcf3ce44SJohn Forte     fct_cmd_t *cmd, uint32_t flags);
110fcf3ce44SJohn Forte fct_status_t qlt_abort_sol_cmd(qlt_state_t *qlt, fct_cmd_t *cmd);
111fcf3ce44SJohn Forte fct_status_t qlt_abort_purex(qlt_state_t *qlt, fct_cmd_t *cmd);
112fcf3ce44SJohn Forte fct_status_t qlt_abort_unsol_scsi_cmd(qlt_state_t *qlt, fct_cmd_t *cmd);
113fcf3ce44SJohn Forte fct_status_t qlt_send_cmd(fct_cmd_t *cmd);
114fcf3ce44SJohn Forte fct_status_t qlt_send_els(qlt_state_t *qlt, fct_cmd_t *cmd);
115fcf3ce44SJohn Forte fct_status_t qlt_send_status(qlt_state_t *qlt, fct_cmd_t *cmd);
116fcf3ce44SJohn Forte fct_status_t qlt_xfer_scsi_data(fct_cmd_t *cmd,
117fcf3ce44SJohn Forte     stmf_data_buf_t *dbuf, uint32_t ioflags);
118fcf3ce44SJohn Forte fct_status_t qlt_send_ct(qlt_state_t *qlt, fct_cmd_t *cmd);
119fcf3ce44SJohn Forte static void qlt_handle_ct_completion(qlt_state_t *qlt, uint8_t *rsp);
120fcf3ce44SJohn Forte static void qlt_release_intr(qlt_state_t *qlt);
121fcf3ce44SJohn Forte static int qlt_setup_interrupts(qlt_state_t *qlt);
122fcf3ce44SJohn Forte static void qlt_destroy_mutex(qlt_state_t *qlt);
123fcf3ce44SJohn Forte 
124fcf3ce44SJohn Forte static fct_status_t qlt_read_risc_ram(qlt_state_t *qlt, uint32_t addr,
125fcf3ce44SJohn Forte     uint32_t words);
126fcf3ce44SJohn Forte static int qlt_dump_queue(qlt_state_t *qlt, caddr_t qadr, int entries,
127c4ddbbe1SDaniel Beauregard     caddr_t buf, uint_t size_left);
128fcf3ce44SJohn Forte static int qlt_dump_risc_ram(qlt_state_t *qlt, uint32_t addr, uint32_t words,
129c4ddbbe1SDaniel Beauregard     caddr_t buf, uint_t size_left);
130fcf3ce44SJohn Forte static int qlt_fwdump_dump_regs(qlt_state_t *qlt, caddr_t buf, int startaddr,
131c4ddbbe1SDaniel Beauregard     int count, uint_t size_left);
132fcf3ce44SJohn Forte static int qlt_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
133fcf3ce44SJohn Forte     cred_t *credp, int *rval);
134fcf3ce44SJohn Forte static int qlt_open(dev_t *devp, int flag, int otype, cred_t *credp);
135fcf3ce44SJohn Forte static int qlt_close(dev_t dev, int flag, int otype, cred_t *credp);
136fcf3ce44SJohn Forte 
137c4ddbbe1SDaniel Beauregard static int qlt_setup_msi(qlt_state_t *qlt);
138c4ddbbe1SDaniel Beauregard static int qlt_setup_msix(qlt_state_t *qlt);
139c4ddbbe1SDaniel Beauregard 
140c4ddbbe1SDaniel Beauregard static int qlt_el_trace_desc_ctor(qlt_state_t *qlt);
141c4ddbbe1SDaniel Beauregard static int qlt_el_trace_desc_dtor(qlt_state_t *qlt);
142c4ddbbe1SDaniel Beauregard static int qlt_validate_trace_desc(qlt_state_t *qlt);
143c4ddbbe1SDaniel Beauregard static char *qlt_find_trace_start(qlt_state_t *qlt);
144c4ddbbe1SDaniel Beauregard 
1450ff6bfafSDaniel Beauregard static int qlt_read_int_prop(qlt_state_t *qlt, char *prop, int defval);
1460ff6bfafSDaniel Beauregard static int qlt_read_string_prop(qlt_state_t *qlt, char *prop, char **prop_val);
1470ff6bfafSDaniel Beauregard static int qlt_read_string_instance_prop(qlt_state_t *qlt, char *prop,
1480ff6bfafSDaniel Beauregard     char **prop_val);
149a2255df3SDaniel Beauregard static int qlt_read_int_instance_prop(qlt_state_t *, char *, int);
1500ff6bfafSDaniel Beauregard static int qlt_convert_string_to_ull(char *prop, int radix,
1510ff6bfafSDaniel Beauregard     u_longlong_t *result);
1520ff6bfafSDaniel Beauregard static boolean_t qlt_wwn_overload_prop(qlt_state_t *qlt);
1530ff6bfafSDaniel Beauregard static int qlt_quiesce(dev_info_t *dip);
154a2255df3SDaniel Beauregard static fct_status_t qlt_raw_wrt_risc_ram_word(qlt_state_t *qlt, uint32_t,
155a2255df3SDaniel Beauregard     uint32_t);
156a2255df3SDaniel Beauregard static fct_status_t qlt_raw_rd_risc_ram_word(qlt_state_t *qlt, uint32_t,
157a2255df3SDaniel Beauregard     uint32_t *);
158a2255df3SDaniel Beauregard static void qlt_mps_reset(qlt_state_t *qlt);
159a2255df3SDaniel Beauregard static void qlt_properties(qlt_state_t *qlt);
160a2255df3SDaniel Beauregard 
1610ff6bfafSDaniel Beauregard 
162c4ddbbe1SDaniel Beauregard #define	SETELSBIT(bmp, els)	(bmp)[((els) >> 3) & 0x1F] = \
163c4ddbbe1SDaniel Beauregard 	(uint8_t)((bmp)[((els) >> 3) & 0x1F] | ((uint8_t)1) << ((els) & 7))
164fcf3ce44SJohn Forte 
165fcf3ce44SJohn Forte int qlt_enable_msix = 0;
166a2255df3SDaniel Beauregard int qlt_enable_msi = 1;
167a2255df3SDaniel Beauregard 
168fcf3ce44SJohn Forte 
1690ff6bfafSDaniel Beauregard string_table_t prop_status_tbl[] = DDI_PROP_STATUS();
1700ff6bfafSDaniel Beauregard 
171fcf3ce44SJohn Forte /* Array to quickly calculate next free buf index to use */
172c4ddbbe1SDaniel Beauregard #if 0
173fcf3ce44SJohn Forte static int qlt_nfb[] = { 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 0xff };
174c4ddbbe1SDaniel Beauregard #endif
175fcf3ce44SJohn Forte 
176fcf3ce44SJohn Forte static struct cb_ops qlt_cb_ops = {
177fcf3ce44SJohn Forte 	qlt_open,
178fcf3ce44SJohn Forte 	qlt_close,
179fcf3ce44SJohn Forte 	nodev,
180fcf3ce44SJohn Forte 	nodev,
181fcf3ce44SJohn Forte 	nodev,
182fcf3ce44SJohn Forte 	nodev,
183fcf3ce44SJohn Forte 	nodev,
184fcf3ce44SJohn Forte 	qlt_ioctl,
185fcf3ce44SJohn Forte 	nodev,
186fcf3ce44SJohn Forte 	nodev,
187fcf3ce44SJohn Forte 	nodev,
188fcf3ce44SJohn Forte 	nochpoll,
189fcf3ce44SJohn Forte 	ddi_prop_op,
190fcf3ce44SJohn Forte 	0,
191fcf3ce44SJohn Forte 	D_MP | D_NEW
192fcf3ce44SJohn Forte };
193fcf3ce44SJohn Forte 
194fcf3ce44SJohn Forte static struct dev_ops qlt_ops = {
195fcf3ce44SJohn Forte 	DEVO_REV,
196fcf3ce44SJohn Forte 	0,
197fcf3ce44SJohn Forte 	nodev,
198fcf3ce44SJohn Forte 	nulldev,
199fcf3ce44SJohn Forte 	nulldev,
200fcf3ce44SJohn Forte 	qlt_attach,
201fcf3ce44SJohn Forte 	qlt_detach,
202fcf3ce44SJohn Forte 	nodev,
203fcf3ce44SJohn Forte 	&qlt_cb_ops,
204fcf3ce44SJohn Forte 	NULL,
2050ff6bfafSDaniel Beauregard 	ddi_power,
2060ff6bfafSDaniel Beauregard 	qlt_quiesce
207fcf3ce44SJohn Forte };
208fcf3ce44SJohn Forte 
209c4ddbbe1SDaniel Beauregard #ifndef	PORT_SPEED_10G
210c4ddbbe1SDaniel Beauregard #define	PORT_SPEED_10G		16
211c4ddbbe1SDaniel Beauregard #endif
212fcf3ce44SJohn Forte 
213fcf3ce44SJohn Forte static struct modldrv modldrv = {
214fcf3ce44SJohn Forte 	&mod_driverops,
215c4ddbbe1SDaniel Beauregard 	QLT_NAME" "QLT_VERSION,
216fcf3ce44SJohn Forte 	&qlt_ops,
217fcf3ce44SJohn Forte };
218fcf3ce44SJohn Forte 
219fcf3ce44SJohn Forte static struct modlinkage modlinkage = {
220fcf3ce44SJohn Forte 	MODREV_1, &modldrv, NULL
221fcf3ce44SJohn Forte };
222fcf3ce44SJohn Forte 
223fcf3ce44SJohn Forte void *qlt_state = NULL;
224fcf3ce44SJohn Forte kmutex_t qlt_global_lock;
225fcf3ce44SJohn Forte static uint32_t qlt_loaded_counter = 0;
226fcf3ce44SJohn Forte 
227fcf3ce44SJohn Forte static char *pci_speeds[] = { " 33", "-X Mode 1 66", "-X Mode 1 100",
228fcf3ce44SJohn Forte 			"-X Mode 1 133", "--Invalid--",
229fcf3ce44SJohn Forte 			"-X Mode 2 66", "-X Mode 2 100",
230fcf3ce44SJohn Forte 			"-X Mode 2 133", " 66" };
231fcf3ce44SJohn Forte 
232fcf3ce44SJohn Forte /* Always use 64 bit DMA. */
233fcf3ce44SJohn Forte static ddi_dma_attr_t qlt_queue_dma_attr = {
234fcf3ce44SJohn Forte 	DMA_ATTR_V0,		/* dma_attr_version */
235fcf3ce44SJohn Forte 	0,			/* low DMA address range */
236fcf3ce44SJohn Forte 	0xffffffffffffffff,	/* high DMA address range */
237fcf3ce44SJohn Forte 	0xffffffff,		/* DMA counter register */
238fcf3ce44SJohn Forte 	64,			/* DMA address alignment */
239fcf3ce44SJohn Forte 	0xff,			/* DMA burstsizes */
240fcf3ce44SJohn Forte 	1,			/* min effective DMA size */
241fcf3ce44SJohn Forte 	0xffffffff,		/* max DMA xfer size */
242fcf3ce44SJohn Forte 	0xffffffff,		/* segment boundary */
243fcf3ce44SJohn Forte 	1,			/* s/g list length */
244fcf3ce44SJohn Forte 	1,			/* granularity of device */
245fcf3ce44SJohn Forte 	0			/* DMA transfer flags */
246fcf3ce44SJohn Forte };
247fcf3ce44SJohn Forte 
248fcf3ce44SJohn Forte /* qlogic logging */
249fcf3ce44SJohn Forte int enable_extended_logging = 0;
250fcf3ce44SJohn Forte 
251fcf3ce44SJohn Forte static char qlt_provider_name[] = "qlt";
252fcf3ce44SJohn Forte static struct stmf_port_provider *qlt_pp;
253fcf3ce44SJohn Forte 
254fcf3ce44SJohn Forte int
_init(void)255fcf3ce44SJohn Forte _init(void)
256fcf3ce44SJohn Forte {
257fcf3ce44SJohn Forte 	int ret;
258fcf3ce44SJohn Forte 
259fcf3ce44SJohn Forte 	ret = ddi_soft_state_init(&qlt_state, sizeof (qlt_state_t), 0);
260fcf3ce44SJohn Forte 	if (ret == 0) {
261fcf3ce44SJohn Forte 		mutex_init(&qlt_global_lock, 0, MUTEX_DRIVER, 0);
262fcf3ce44SJohn Forte 		qlt_pp = (stmf_port_provider_t *)stmf_alloc(
263d8c54e3dSSam Cramer 		    STMF_STRUCT_PORT_PROVIDER, 0, 0);
264fcf3ce44SJohn Forte 		qlt_pp->pp_portif_rev = PORTIF_REV_1;
265fcf3ce44SJohn Forte 		qlt_pp->pp_name = qlt_provider_name;
266fcf3ce44SJohn Forte 		if (stmf_register_port_provider(qlt_pp) != STMF_SUCCESS) {
267fcf3ce44SJohn Forte 			stmf_free(qlt_pp);
268fcf3ce44SJohn Forte 			mutex_destroy(&qlt_global_lock);
269fcf3ce44SJohn Forte 			ddi_soft_state_fini(&qlt_state);
270fcf3ce44SJohn Forte 			return (EIO);
271fcf3ce44SJohn Forte 		}
272fcf3ce44SJohn Forte 		ret = mod_install(&modlinkage);
273fcf3ce44SJohn Forte 		if (ret != 0) {
274fcf3ce44SJohn Forte 			(void) stmf_deregister_port_provider(qlt_pp);
275fcf3ce44SJohn Forte 			stmf_free(qlt_pp);
276fcf3ce44SJohn Forte 			mutex_destroy(&qlt_global_lock);
277fcf3ce44SJohn Forte 			ddi_soft_state_fini(&qlt_state);
278fcf3ce44SJohn Forte 		}
279fcf3ce44SJohn Forte 	}
280fcf3ce44SJohn Forte 	return (ret);
281fcf3ce44SJohn Forte }
282fcf3ce44SJohn Forte 
283fcf3ce44SJohn Forte int
_fini(void)284fcf3ce44SJohn Forte _fini(void)
285fcf3ce44SJohn Forte {
286fcf3ce44SJohn Forte 	int ret;
287fcf3ce44SJohn Forte 
288fcf3ce44SJohn Forte 	if (qlt_loaded_counter)
289fcf3ce44SJohn Forte 		return (EBUSY);
290fcf3ce44SJohn Forte 	ret = mod_remove(&modlinkage);
291fcf3ce44SJohn Forte 	if (ret == 0) {
292fcf3ce44SJohn Forte 		(void) stmf_deregister_port_provider(qlt_pp);
293fcf3ce44SJohn Forte 		stmf_free(qlt_pp);
294fcf3ce44SJohn Forte 		mutex_destroy(&qlt_global_lock);
295fcf3ce44SJohn Forte 		ddi_soft_state_fini(&qlt_state);
296fcf3ce44SJohn Forte 	}
297fcf3ce44SJohn Forte 	return (ret);
298fcf3ce44SJohn Forte }
299fcf3ce44SJohn Forte 
300fcf3ce44SJohn Forte int
_info(struct modinfo * modinfop)301fcf3ce44SJohn Forte _info(struct modinfo *modinfop)
302fcf3ce44SJohn Forte {
303fcf3ce44SJohn Forte 	return (mod_info(&modlinkage, modinfop));
304fcf3ce44SJohn Forte }
305fcf3ce44SJohn Forte 
306fcf3ce44SJohn Forte 
307fcf3ce44SJohn Forte static int
qlt_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)308fcf3ce44SJohn Forte qlt_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
309fcf3ce44SJohn Forte {
310fcf3ce44SJohn Forte 	int		instance;
311fcf3ce44SJohn Forte 	qlt_state_t	*qlt;
312fcf3ce44SJohn Forte 	ddi_device_acc_attr_t	dev_acc_attr;
313fcf3ce44SJohn Forte 	uint16_t	did;
314fcf3ce44SJohn Forte 	uint16_t	val;
315fcf3ce44SJohn Forte 	uint16_t	mr;
316fcf3ce44SJohn Forte 	size_t		discard;
317fcf3ce44SJohn Forte 	uint_t		ncookies;
318fcf3ce44SJohn Forte 	int		max_read_size;
319fcf3ce44SJohn Forte 	int		max_payload_size;
320fcf3ce44SJohn Forte 	fct_status_t	ret;
321fcf3ce44SJohn Forte 
322fcf3ce44SJohn Forte 	/* No support for suspend resume yet */
323fcf3ce44SJohn Forte 	if (cmd != DDI_ATTACH)
324fcf3ce44SJohn Forte 		return (DDI_FAILURE);
325fcf3ce44SJohn Forte 	instance = ddi_get_instance(dip);
326fcf3ce44SJohn Forte 
327fcf3ce44SJohn Forte 	if (ddi_soft_state_zalloc(qlt_state, instance) != DDI_SUCCESS) {
328fcf3ce44SJohn Forte 		return (DDI_FAILURE);
329fcf3ce44SJohn Forte 	}
330fcf3ce44SJohn Forte 
331c4ddbbe1SDaniel Beauregard 	if ((qlt = (qlt_state_t *)ddi_get_soft_state(qlt_state, instance)) ==
332c4ddbbe1SDaniel Beauregard 	    NULL) {
333fcf3ce44SJohn Forte 		goto attach_fail_1;
334fcf3ce44SJohn Forte 	}
335a2255df3SDaniel Beauregard 
336fcf3ce44SJohn Forte 	qlt->instance = instance;
337a2255df3SDaniel Beauregard 
338fcf3ce44SJohn Forte 	qlt->nvram = (qlt_nvram_t *)kmem_zalloc(sizeof (qlt_nvram_t), KM_SLEEP);
339fcf3ce44SJohn Forte 	qlt->dip = dip;
340c4ddbbe1SDaniel Beauregard 
341c4ddbbe1SDaniel Beauregard 	if (qlt_el_trace_desc_ctor(qlt) != DDI_SUCCESS) {
342c4ddbbe1SDaniel Beauregard 		cmn_err(CE_WARN, "qlt(%d): can't setup el tracing", instance);
343c4ddbbe1SDaniel Beauregard 		goto attach_fail_1;
344c4ddbbe1SDaniel Beauregard 	}
345c4ddbbe1SDaniel Beauregard 
346a2255df3SDaniel Beauregard 	EL(qlt, "instance=%d, ptr=%p\n", instance, (void *)qlt);
347c4ddbbe1SDaniel Beauregard 
348fcf3ce44SJohn Forte 	if (pci_config_setup(dip, &qlt->pcicfg_acc_handle) != DDI_SUCCESS) {
349fcf3ce44SJohn Forte 		goto attach_fail_2;
350fcf3ce44SJohn Forte 	}
351fcf3ce44SJohn Forte 	did = PCICFG_RD16(qlt, PCI_CONF_DEVID);
352fcf3ce44SJohn Forte 	if ((did != 0x2422) && (did != 0x2432) &&
353c4ddbbe1SDaniel Beauregard 	    (did != 0x8432) && (did != 0x2532) &&
354c4ddbbe1SDaniel Beauregard 	    (did != 0x8001)) {
355c4ddbbe1SDaniel Beauregard 		cmn_err(CE_WARN, "qlt(%d): unknown devid(%x), failing attach",
356fcf3ce44SJohn Forte 		    instance, did);
357fcf3ce44SJohn Forte 		goto attach_fail_4;
358fcf3ce44SJohn Forte 	}
359c4ddbbe1SDaniel Beauregard 
360c4ddbbe1SDaniel Beauregard 	if ((did & 0xFF00) == 0x8000)
361c4ddbbe1SDaniel Beauregard 		qlt->qlt_81xx_chip = 1;
362c4ddbbe1SDaniel Beauregard 	else if ((did & 0xFF00) == 0x2500)
363fcf3ce44SJohn Forte 		qlt->qlt_25xx_chip = 1;
364fcf3ce44SJohn Forte 
365fcf3ce44SJohn Forte 	dev_acc_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
366fcf3ce44SJohn Forte 	dev_acc_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
367fcf3ce44SJohn Forte 	dev_acc_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
368fcf3ce44SJohn Forte 	if (ddi_regs_map_setup(dip, 2, &qlt->regs, 0, 0x100,
369fcf3ce44SJohn Forte 	    &dev_acc_attr, &qlt->regs_acc_handle) != DDI_SUCCESS) {
370fcf3ce44SJohn Forte 		goto attach_fail_4;
371fcf3ce44SJohn Forte 	}
372fcf3ce44SJohn Forte 	if (did == 0x2422) {
373fcf3ce44SJohn Forte 		uint32_t pci_bits = REG_RD32(qlt, REG_CTRL_STATUS);
374fcf3ce44SJohn Forte 		uint32_t slot = pci_bits & PCI_64_BIT_SLOT;
375fcf3ce44SJohn Forte 		pci_bits >>= 8;
376fcf3ce44SJohn Forte 		pci_bits &= 0xf;
377fcf3ce44SJohn Forte 		if ((pci_bits == 3) || (pci_bits == 7)) {
378fcf3ce44SJohn Forte 			cmn_err(CE_NOTE,
379fcf3ce44SJohn Forte 			    "!qlt(%d): HBA running at PCI%sMHz (%d)",
380fcf3ce44SJohn Forte 			    instance, pci_speeds[pci_bits], pci_bits);
381fcf3ce44SJohn Forte 		} else {
382fcf3ce44SJohn Forte 			cmn_err(CE_WARN,
383fcf3ce44SJohn Forte 			    "qlt(%d): HBA running at PCI%sMHz %s(%d)",
384fcf3ce44SJohn Forte 			    instance, (pci_bits <= 8) ? pci_speeds[pci_bits] :
385fcf3ce44SJohn Forte 			    "(Invalid)", ((pci_bits == 0) ||
386fcf3ce44SJohn Forte 			    (pci_bits == 8)) ? (slot ? "64 bit slot " :
387fcf3ce44SJohn Forte 			    "32 bit slot ") : "", pci_bits);
388fcf3ce44SJohn Forte 		}
389fcf3ce44SJohn Forte 	}
390fcf3ce44SJohn Forte 	if ((ret = qlt_read_nvram(qlt)) != QLT_SUCCESS) {
391fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "qlt(%d): read nvram failure %llx", instance,
392fcf3ce44SJohn Forte 		    (unsigned long long)ret);
393fcf3ce44SJohn Forte 		goto attach_fail_5;
394fcf3ce44SJohn Forte 	}
395a2255df3SDaniel Beauregard 
396a2255df3SDaniel Beauregard 	qlt_properties(qlt);
397a2255df3SDaniel Beauregard 
398fcf3ce44SJohn Forte 	if (ddi_dma_alloc_handle(dip, &qlt_queue_dma_attr, DDI_DMA_SLEEP,
399fcf3ce44SJohn Forte 	    0, &qlt->queue_mem_dma_handle) != DDI_SUCCESS) {
400fcf3ce44SJohn Forte 		goto attach_fail_5;
401fcf3ce44SJohn Forte 	}
402fcf3ce44SJohn Forte 	if (ddi_dma_mem_alloc(qlt->queue_mem_dma_handle, TOTAL_DMA_MEM_SIZE,
403fcf3ce44SJohn Forte 	    &dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0,
404fcf3ce44SJohn Forte 	    &qlt->queue_mem_ptr, &discard, &qlt->queue_mem_acc_handle) !=
405fcf3ce44SJohn Forte 	    DDI_SUCCESS) {
406fcf3ce44SJohn Forte 		goto attach_fail_6;
407fcf3ce44SJohn Forte 	}
408fcf3ce44SJohn Forte 	if (ddi_dma_addr_bind_handle(qlt->queue_mem_dma_handle, NULL,
409fcf3ce44SJohn Forte 	    qlt->queue_mem_ptr, TOTAL_DMA_MEM_SIZE,
410fcf3ce44SJohn Forte 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0,
411fcf3ce44SJohn Forte 	    &qlt->queue_mem_cookie, &ncookies) != DDI_SUCCESS) {
412fcf3ce44SJohn Forte 		goto attach_fail_7;
413fcf3ce44SJohn Forte 	}
414fcf3ce44SJohn Forte 	if (ncookies != 1)
415fcf3ce44SJohn Forte 		goto attach_fail_8;
416fcf3ce44SJohn Forte 	qlt->req_ptr = qlt->queue_mem_ptr + REQUEST_QUEUE_OFFSET;
417fcf3ce44SJohn Forte 	qlt->resp_ptr = qlt->queue_mem_ptr + RESPONSE_QUEUE_OFFSET;
418fcf3ce44SJohn Forte 	qlt->preq_ptr = qlt->queue_mem_ptr + PRIORITY_QUEUE_OFFSET;
419fcf3ce44SJohn Forte 	qlt->atio_ptr = qlt->queue_mem_ptr + ATIO_QUEUE_OFFSET;
420fcf3ce44SJohn Forte 
421fcf3ce44SJohn Forte 	/* mutex are inited in this function */
422fcf3ce44SJohn Forte 	if (qlt_setup_interrupts(qlt) != DDI_SUCCESS)
423fcf3ce44SJohn Forte 		goto attach_fail_8;
424fcf3ce44SJohn Forte 
425fcf3ce44SJohn Forte 	(void) snprintf(qlt->qlt_minor_name, sizeof (qlt->qlt_minor_name),
426d8c54e3dSSam Cramer 	    "qlt%d", instance);
427fcf3ce44SJohn Forte 	(void) snprintf(qlt->qlt_port_alias, sizeof (qlt->qlt_port_alias),
428fcf3ce44SJohn Forte 	    "%s,0", qlt->qlt_minor_name);
429fcf3ce44SJohn Forte 
430fcf3ce44SJohn Forte 	if (ddi_create_minor_node(dip, qlt->qlt_minor_name, S_IFCHR,
431d8c54e3dSSam Cramer 	    instance, DDI_NT_STMF_PP, 0) != DDI_SUCCESS) {
432fcf3ce44SJohn Forte 		goto attach_fail_9;
433fcf3ce44SJohn Forte 	}
434fcf3ce44SJohn Forte 
435fcf3ce44SJohn Forte 	cv_init(&qlt->rp_dereg_cv, NULL, CV_DRIVER, NULL);
436fcf3ce44SJohn Forte 	cv_init(&qlt->mbox_cv, NULL, CV_DRIVER, NULL);
437fcf3ce44SJohn Forte 	mutex_init(&qlt->qlt_ioctl_lock, NULL, MUTEX_DRIVER, NULL);
438fcf3ce44SJohn Forte 
439fcf3ce44SJohn Forte 	/* Setup PCI cfg space registers */
440fcf3ce44SJohn Forte 	max_read_size = qlt_read_int_prop(qlt, "pci-max-read-request", 11);
441fcf3ce44SJohn Forte 	if (max_read_size == 11)
442fcf3ce44SJohn Forte 		goto over_max_read_xfer_setting;
443fcf3ce44SJohn Forte 	if (did == 0x2422) {
444fcf3ce44SJohn Forte 		if (max_read_size == 512)
445fcf3ce44SJohn Forte 			val = 0;
446fcf3ce44SJohn Forte 		else if (max_read_size == 1024)
447fcf3ce44SJohn Forte 			val = 1;
448fcf3ce44SJohn Forte 		else if (max_read_size == 2048)
449fcf3ce44SJohn Forte 			val = 2;
450fcf3ce44SJohn Forte 		else if (max_read_size == 4096)
451fcf3ce44SJohn Forte 			val = 3;
452fcf3ce44SJohn Forte 		else {
453fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "qlt(%d) malformed "
454fcf3ce44SJohn Forte 			    "pci-max-read-request in qlt.conf. Valid values "
455fcf3ce44SJohn Forte 			    "for this HBA are 512/1024/2048/4096", instance);
456fcf3ce44SJohn Forte 			goto over_max_read_xfer_setting;
457fcf3ce44SJohn Forte 		}
458c4ddbbe1SDaniel Beauregard 		mr = (uint16_t)PCICFG_RD16(qlt, 0x4E);
459c4ddbbe1SDaniel Beauregard 		mr = (uint16_t)(mr & 0xfff3);
460c4ddbbe1SDaniel Beauregard 		mr = (uint16_t)(mr | (val << 2));
461fcf3ce44SJohn Forte 		PCICFG_WR16(qlt, 0x4E, mr);
462c4ddbbe1SDaniel Beauregard 	} else if ((did == 0x2432) || (did == 0x8432) ||
463c4ddbbe1SDaniel Beauregard 	    (did == 0x2532) || (did == 0x8001)) {
464fcf3ce44SJohn Forte 		if (max_read_size == 128)
465fcf3ce44SJohn Forte 			val = 0;
466fcf3ce44SJohn Forte 		else if (max_read_size == 256)
467fcf3ce44SJohn Forte 			val = 1;
468fcf3ce44SJohn Forte 		else if (max_read_size == 512)
469fcf3ce44SJohn Forte 			val = 2;
470fcf3ce44SJohn Forte 		else if (max_read_size == 1024)
471fcf3ce44SJohn Forte 			val = 3;
472fcf3ce44SJohn Forte 		else if (max_read_size == 2048)
473fcf3ce44SJohn Forte 			val = 4;
474fcf3ce44SJohn Forte 		else if (max_read_size == 4096)
475fcf3ce44SJohn Forte 			val = 5;
476fcf3ce44SJohn Forte 		else {
477fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "qlt(%d) malformed "
478fcf3ce44SJohn Forte 			    "pci-max-read-request in qlt.conf. Valid values "
479fcf3ce44SJohn Forte 			    "for this HBA are 128/256/512/1024/2048/4096",
480d8c54e3dSSam Cramer 			    instance);
481fcf3ce44SJohn Forte 			goto over_max_read_xfer_setting;
482fcf3ce44SJohn Forte 		}
483c4ddbbe1SDaniel Beauregard 		mr = (uint16_t)PCICFG_RD16(qlt, 0x54);
484c4ddbbe1SDaniel Beauregard 		mr = (uint16_t)(mr & 0x8fff);
485c4ddbbe1SDaniel Beauregard 		mr = (uint16_t)(mr | (val << 12));
486fcf3ce44SJohn Forte 		PCICFG_WR16(qlt, 0x54, mr);
487fcf3ce44SJohn Forte 	} else {
488fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "qlt(%d): dont know how to set "
489fcf3ce44SJohn Forte 		    "pci-max-read-request for this device (%x)",
490fcf3ce44SJohn Forte 		    instance, did);
491fcf3ce44SJohn Forte 	}
492fcf3ce44SJohn Forte over_max_read_xfer_setting:;
493fcf3ce44SJohn Forte 
494fcf3ce44SJohn Forte 	max_payload_size = qlt_read_int_prop(qlt, "pcie-max-payload-size", 11);
495fcf3ce44SJohn Forte 	if (max_payload_size == 11)
496fcf3ce44SJohn Forte 		goto over_max_payload_setting;
497c4ddbbe1SDaniel Beauregard 	if ((did == 0x2432) || (did == 0x8432) ||
498c4ddbbe1SDaniel Beauregard 	    (did == 0x2532) || (did == 0x8001)) {
499fcf3ce44SJohn Forte 		if (max_payload_size == 128)
500fcf3ce44SJohn Forte 			val = 0;
501fcf3ce44SJohn Forte 		else if (max_payload_size == 256)
502fcf3ce44SJohn Forte 			val = 1;
503fcf3ce44SJohn Forte 		else if (max_payload_size == 512)
504fcf3ce44SJohn Forte 			val = 2;
505fcf3ce44SJohn Forte 		else if (max_payload_size == 1024)
506fcf3ce44SJohn Forte 			val = 3;
507fcf3ce44SJohn Forte 		else {
508fcf3ce44SJohn Forte 			cmn_err(CE_WARN, "qlt(%d) malformed "
509fcf3ce44SJohn Forte 			    "pcie-max-payload-size in qlt.conf. Valid values "
510fcf3ce44SJohn Forte 			    "for this HBA are 128/256/512/1024",
511d8c54e3dSSam Cramer 			    instance);
512fcf3ce44SJohn Forte 			goto over_max_payload_setting;
513fcf3ce44SJohn Forte 		}
514c4ddbbe1SDaniel Beauregard 		mr = (uint16_t)PCICFG_RD16(qlt, 0x54);
515c4ddbbe1SDaniel Beauregard 		mr = (uint16_t)(mr & 0xff1f);
516c4ddbbe1SDaniel Beauregard 		mr = (uint16_t)(mr | (val << 5));
517fcf3ce44SJohn Forte 		PCICFG_WR16(qlt, 0x54, mr);
518fcf3ce44SJohn Forte 	} else {
519fcf3ce44SJohn Forte 		cmn_err(CE_WARN, "qlt(%d): dont know how to set "
520fcf3ce44SJohn Forte 		    "pcie-max-payload-size for this device (%x)",
521fcf3ce44SJohn Forte 		    instance, did);
522fcf3ce44SJohn Forte 	}
523fcf3ce44SJohn Forte 
524fcf3ce44SJohn Forte over_max_payload_setting:;
525fcf3ce44SJohn Forte 
526a2255df3SDaniel Beauregard 	qlt_enable_intr(qlt);
527a2255df3SDaniel Beauregard 
528fcf3ce44SJohn Forte 	if (qlt_port_start((caddr_t)qlt) != QLT_SUCCESS)
529fcf3ce44SJohn Forte 		goto attach_fail_10;
530fcf3ce44SJohn Forte 
531fcf3ce44SJohn Forte 	ddi_report_dev(dip);
532fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
533fcf3ce44SJohn Forte 
534fcf3ce44SJohn Forte attach_fail_10:;
535fcf3ce44SJohn Forte 	mutex_destroy(&qlt->qlt_ioctl_lock);
536fcf3ce44SJohn Forte 	cv_destroy(&qlt->mbox_cv);
537fcf3ce44SJohn Forte 	cv_destroy(&qlt->rp_dereg_cv);
538fcf3ce44SJohn Forte 	ddi_remove_minor_node(dip, qlt->qlt_minor_name);
539fcf3ce44SJohn Forte attach_fail_9:;
540fcf3ce44SJohn Forte 	qlt_destroy_mutex(qlt);
541fcf3ce44SJohn Forte 	qlt_release_intr(qlt);
542fcf3ce44SJohn Forte attach_fail_8:;
543fcf3ce44SJohn Forte 	(void) ddi_dma_unbind_handle(qlt->queue_mem_dma_handle);
544fcf3ce44SJohn Forte attach_fail_7:;
545fcf3ce44SJohn Forte 	ddi_dma_mem_free(&qlt->queue_mem_acc_handle);
546fcf3ce44SJohn Forte attach_fail_6:;
547fcf3ce44SJohn Forte 	ddi_dma_free_handle(&qlt->queue_mem_dma_handle);
548fcf3ce44SJohn Forte attach_fail_5:;
549fcf3ce44SJohn Forte 	ddi_regs_map_free(&qlt->regs_acc_handle);
550fcf3ce44SJohn Forte attach_fail_4:;
551fcf3ce44SJohn Forte 	pci_config_teardown(&qlt->pcicfg_acc_handle);
552fcf3ce44SJohn Forte 	kmem_free(qlt->nvram, sizeof (qlt_nvram_t));
553c4ddbbe1SDaniel Beauregard 	(void) qlt_el_trace_desc_dtor(qlt);
554fcf3ce44SJohn Forte attach_fail_2:;
555fcf3ce44SJohn Forte attach_fail_1:;
556fcf3ce44SJohn Forte 	ddi_soft_state_free(qlt_state, instance);
557fcf3ce44SJohn Forte 	return (DDI_FAILURE);
558fcf3ce44SJohn Forte }
559fcf3ce44SJohn Forte 
560fcf3ce44SJohn Forte #define	FCT_I_EVENT_BRING_PORT_OFFLINE	0x83
561fcf3ce44SJohn Forte 
562fcf3ce44SJohn Forte /* ARGSUSED */
563fcf3ce44SJohn Forte static int
qlt_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)564fcf3ce44SJohn Forte qlt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
565fcf3ce44SJohn Forte {
566fcf3ce44SJohn Forte 	qlt_state_t *qlt;
567fcf3ce44SJohn Forte 
568fcf3ce44SJohn Forte 	int instance;
569fcf3ce44SJohn Forte 
570fcf3ce44SJohn Forte 	instance = ddi_get_instance(dip);
571c4ddbbe1SDaniel Beauregard 	if ((qlt = (qlt_state_t *)ddi_get_soft_state(qlt_state, instance)) ==
572c4ddbbe1SDaniel Beauregard 	    NULL) {
573fcf3ce44SJohn Forte 		return (DDI_FAILURE);
574fcf3ce44SJohn Forte 	}
575fcf3ce44SJohn Forte 
576fcf3ce44SJohn Forte 	if (qlt->fw_code01) {
577fcf3ce44SJohn Forte 		return (DDI_FAILURE);
578fcf3ce44SJohn Forte 	}
579fcf3ce44SJohn Forte 
580fcf3ce44SJohn Forte 	if ((qlt->qlt_state != FCT_STATE_OFFLINE) ||
581d8c54e3dSSam Cramer 	    qlt->qlt_state_not_acked) {
582fcf3ce44SJohn Forte 		return (DDI_FAILURE);
583fcf3ce44SJohn Forte 	}
584a2255df3SDaniel Beauregard 	if (qlt_port_stop((caddr_t)qlt) != FCT_SUCCESS) {
585fcf3ce44SJohn Forte 		return (DDI_FAILURE);
586a2255df3SDaniel Beauregard 	}
587a2255df3SDaniel Beauregard 
588a2255df3SDaniel Beauregard 	qlt_disable_intr(qlt);
589a2255df3SDaniel Beauregard 
590fcf3ce44SJohn Forte 	ddi_remove_minor_node(dip, qlt->qlt_minor_name);
591fcf3ce44SJohn Forte 	qlt_destroy_mutex(qlt);
592fcf3ce44SJohn Forte 	qlt_release_intr(qlt);
593fcf3ce44SJohn Forte 	(void) ddi_dma_unbind_handle(qlt->queue_mem_dma_handle);
594fcf3ce44SJohn Forte 	ddi_dma_mem_free(&qlt->queue_mem_acc_handle);
595fcf3ce44SJohn Forte 	ddi_dma_free_handle(&qlt->queue_mem_dma_handle);
596fcf3ce44SJohn Forte 	ddi_regs_map_free(&qlt->regs_acc_handle);
597fcf3ce44SJohn Forte 	pci_config_teardown(&qlt->pcicfg_acc_handle);
598fcf3ce44SJohn Forte 	kmem_free(qlt->nvram, sizeof (qlt_nvram_t));
599fcf3ce44SJohn Forte 	cv_destroy(&qlt->mbox_cv);
600fcf3ce44SJohn Forte 	cv_destroy(&qlt->rp_dereg_cv);
601c4ddbbe1SDaniel Beauregard 	(void) qlt_el_trace_desc_dtor(qlt);
602fcf3ce44SJohn Forte 	ddi_soft_state_free(qlt_state, instance);
603fcf3ce44SJohn Forte 
604fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
605fcf3ce44SJohn Forte }
606fcf3ce44SJohn Forte 
6070ff6bfafSDaniel Beauregard /*
6080ff6bfafSDaniel Beauregard  * qlt_quiesce	quiesce a device attached to the system.
6090ff6bfafSDaniel Beauregard  */
6100ff6bfafSDaniel Beauregard static int
qlt_quiesce(dev_info_t * dip)6110ff6bfafSDaniel Beauregard qlt_quiesce(dev_info_t *dip)
6120ff6bfafSDaniel Beauregard {
6130ff6bfafSDaniel Beauregard 	qlt_state_t	*qlt;
6140ff6bfafSDaniel Beauregard 	uint32_t	timer;
6150ff6bfafSDaniel Beauregard 	uint32_t	stat;
6160ff6bfafSDaniel Beauregard 
6170ff6bfafSDaniel Beauregard 	qlt = ddi_get_soft_state(qlt_state, ddi_get_instance(dip));
6180ff6bfafSDaniel Beauregard 	if (qlt == NULL) {
6190ff6bfafSDaniel Beauregard 		/* Oh well.... */
6200ff6bfafSDaniel Beauregard 		return (DDI_SUCCESS);
6210ff6bfafSDaniel Beauregard 	}
6220ff6bfafSDaniel Beauregard 
623a2255df3SDaniel Beauregard 	REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_HOST_TO_RISC_INTR));
6240ff6bfafSDaniel Beauregard 	REG_WR16(qlt, REG_MBOX0, MBC_STOP_FIRMWARE);
625a2255df3SDaniel Beauregard 	REG_WR32(qlt, REG_HCCR, HCCR_CMD(SET_HOST_TO_RISC_INTR));
6260ff6bfafSDaniel Beauregard 	for (timer = 0; timer < 30000; timer++) {
6270ff6bfafSDaniel Beauregard 		stat = REG_RD32(qlt, REG_RISC_STATUS);
6280ff6bfafSDaniel Beauregard 		if (stat & RISC_HOST_INTR_REQUEST) {
6290ff6bfafSDaniel Beauregard 			if ((stat & FW_INTR_STATUS_MASK) < 0x12) {
6300ff6bfafSDaniel Beauregard 				REG_WR32(qlt, REG_HCCR,
631a2255df3SDaniel Beauregard 				    HCCR_CMD(CLEAR_RISC_PAUSE));
6320ff6bfafSDaniel Beauregard 				break;
6330ff6bfafSDaniel Beauregard 			}
6340ff6bfafSDaniel Beauregard 			REG_WR32(qlt, REG_HCCR,
635a2255df3SDaniel Beauregard 			    HCCR_CMD(CLEAR_HOST_TO_RISC_INTR));
6360ff6bfafSDaniel Beauregard 		}
6370ff6bfafSDaniel Beauregard 		drv_usecwait(100);
6380ff6bfafSDaniel Beauregard 	}
6390ff6bfafSDaniel Beauregard 	/* Reset the chip. */
6400ff6bfafSDaniel Beauregard 	REG_WR32(qlt, REG_CTRL_STATUS, CHIP_SOFT_RESET | DMA_SHUTDOWN_CTRL |
6410ff6bfafSDaniel Beauregard 	    PCI_X_XFER_CTRL);
6420ff6bfafSDaniel Beauregard 	drv_usecwait(100);
6430ff6bfafSDaniel Beauregard 
644a2255df3SDaniel Beauregard 	qlt_disable_intr(qlt);
645a2255df3SDaniel Beauregard 
6460ff6bfafSDaniel Beauregard 	return (DDI_SUCCESS);
6470ff6bfafSDaniel Beauregard }
6480ff6bfafSDaniel Beauregard 
649fcf3ce44SJohn Forte static void
qlt_enable_intr(qlt_state_t * qlt)650fcf3ce44SJohn Forte qlt_enable_intr(qlt_state_t *qlt)
651fcf3ce44SJohn Forte {
652fcf3ce44SJohn Forte 	if (qlt->intr_cap & DDI_INTR_FLAG_BLOCK) {
653fcf3ce44SJohn Forte 		(void) ddi_intr_block_enable(qlt->htable, qlt->intr_cnt);
654fcf3ce44SJohn Forte 	} else {
655fcf3ce44SJohn Forte 		int i;
656fcf3ce44SJohn Forte 		for (i = 0; i < qlt->intr_cnt; i++)
657fcf3ce44SJohn Forte 			(void) ddi_intr_enable(qlt->htable[i]);
658fcf3ce44SJohn Forte 	}
659a2255df3SDaniel Beauregard 	qlt->qlt_intr_enabled = 1;
660fcf3ce44SJohn Forte }
661fcf3ce44SJohn Forte 
662fcf3ce44SJohn Forte static void
qlt_disable_intr(qlt_state_t * qlt)663fcf3ce44SJohn Forte qlt_disable_intr(qlt_state_t *qlt)
664fcf3ce44SJohn Forte {
665fcf3ce44SJohn Forte 	if (qlt->intr_cap & DDI_INTR_FLAG_BLOCK) {
666fcf3ce44SJohn Forte 		(void) ddi_intr_block_disable(qlt->htable, qlt->intr_cnt);
667fcf3ce44SJohn Forte 	} else {
668fcf3ce44SJohn Forte 		int i;
669fcf3ce44SJohn Forte 		for (i = 0; i < qlt->intr_cnt; i++)
670fcf3ce44SJohn Forte 			(void) ddi_intr_disable(qlt->htable[i]);
671fcf3ce44SJohn Forte 	}
672a2255df3SDaniel Beauregard 	qlt->qlt_intr_enabled = 0;
673fcf3ce44SJohn Forte }
674fcf3ce44SJohn Forte 
675fcf3ce44SJohn Forte static void
qlt_release_intr(qlt_state_t * qlt)676fcf3ce44SJohn Forte qlt_release_intr(qlt_state_t *qlt)
677fcf3ce44SJohn Forte {
678fcf3ce44SJohn Forte 	if (qlt->htable) {
679fcf3ce44SJohn Forte 		int i;
680fcf3ce44SJohn Forte 		for (i = 0; i < qlt->intr_cnt; i++) {
681fcf3ce44SJohn Forte 			(void) ddi_intr_remove_handler(qlt->htable[i]);
682fcf3ce44SJohn Forte 			(void) ddi_intr_free(qlt->htable[i]);
683fcf3ce44SJohn Forte 		}
684c4ddbbe1SDaniel Beauregard 		kmem_free(qlt->htable, (uint_t)qlt->intr_size);
685fcf3ce44SJohn Forte 	}
686fcf3ce44SJohn Forte 	qlt->htable = NULL;
687fcf3ce44SJohn Forte 	qlt->intr_pri = 0;
688fcf3ce44SJohn Forte 	qlt->intr_cnt = 0;
689fcf3ce44SJohn Forte 	qlt->intr_size = 0;
690fcf3ce44SJohn Forte 	qlt->intr_cap = 0;
691fcf3ce44SJohn Forte }
692fcf3ce44SJohn Forte 
693fcf3ce44SJohn Forte 
694fcf3ce44SJohn Forte static void
qlt_init_mutex(qlt_state_t * qlt)695fcf3ce44SJohn Forte qlt_init_mutex(qlt_state_t *qlt)
696fcf3ce44SJohn Forte {
697fcf3ce44SJohn Forte 	mutex_init(&qlt->req_lock, 0, MUTEX_DRIVER,
698fcf3ce44SJohn Forte 	    INT2PTR(qlt->intr_pri, void *));
699fcf3ce44SJohn Forte 	mutex_init(&qlt->preq_lock, 0, MUTEX_DRIVER,
700fcf3ce44SJohn Forte 	    INT2PTR(qlt->intr_pri, void *));
701fcf3ce44SJohn Forte 	mutex_init(&qlt->mbox_lock, NULL, MUTEX_DRIVER,
702fcf3ce44SJohn Forte 	    INT2PTR(qlt->intr_pri, void *));
703fcf3ce44SJohn Forte 	mutex_init(&qlt->intr_lock, NULL, MUTEX_DRIVER,
704fcf3ce44SJohn Forte 	    INT2PTR(qlt->intr_pri, void *));
705fcf3ce44SJohn Forte }
706fcf3ce44SJohn Forte 
707fcf3ce44SJohn Forte static void
qlt_destroy_mutex(qlt_state_t * qlt)708fcf3ce44SJohn Forte qlt_destroy_mutex(qlt_state_t *qlt)
709fcf3ce44SJohn Forte {
710fcf3ce44SJohn Forte 	mutex_destroy(&qlt->req_lock);
711fcf3ce44SJohn Forte 	mutex_destroy(&qlt->preq_lock);
712fcf3ce44SJohn Forte 	mutex_destroy(&qlt->mbox_lock);
713fcf3ce44SJohn Forte 	mutex_destroy(&qlt->intr_lock);
714fcf3ce44SJohn Forte }
715fcf3ce44SJohn Forte 
716fcf3ce44SJohn Forte 
717fcf3ce44SJohn Forte static int
qlt_setup_msix(qlt_state_t * qlt)718fcf3ce44SJohn Forte qlt_setup_msix(qlt_state_t *qlt)
719fcf3ce44SJohn Forte {
720fcf3ce44SJohn Forte 	int count, avail, actual;
721fcf3ce44SJohn Forte 	int ret;
722fcf3ce44SJohn Forte 	int itype = DDI_INTR_TYPE_MSIX;
723fcf3ce44SJohn Forte 	int i;
724fcf3ce44SJohn Forte 
725fcf3ce44SJohn Forte 	ret = ddi_intr_get_nintrs(qlt->dip, itype, &count);
726fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS || count == 0) {
727c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_get_nintrs status=%xh, count=%d\n", ret,
728c4ddbbe1SDaniel Beauregard 		    count);
729fcf3ce44SJohn Forte 		return (DDI_FAILURE);
730fcf3ce44SJohn Forte 	}
731fcf3ce44SJohn Forte 	ret = ddi_intr_get_navail(qlt->dip, itype, &avail);
732fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS || avail == 0) {
733c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_get_navail status=%xh, avail=%d\n", ret,
734c4ddbbe1SDaniel Beauregard 		    avail);
735fcf3ce44SJohn Forte 		return (DDI_FAILURE);
736fcf3ce44SJohn Forte 	}
737fcf3ce44SJohn Forte 	if (avail < count) {
738fcf3ce44SJohn Forte 		stmf_trace(qlt->qlt_port_alias,
739fcf3ce44SJohn Forte 		    "qlt_setup_msix: nintrs=%d,avail=%d", count, avail);
740fcf3ce44SJohn Forte 	}
741fcf3ce44SJohn Forte 
742c4ddbbe1SDaniel Beauregard 	qlt->intr_size = (int)(count * (int)sizeof (ddi_intr_handle_t));
743c4ddbbe1SDaniel Beauregard 	qlt->htable = kmem_zalloc((uint_t)qlt->intr_size, KM_SLEEP);
744fcf3ce44SJohn Forte 	ret = ddi_intr_alloc(qlt->dip, qlt->htable, itype,
745fcf3ce44SJohn Forte 	    DDI_INTR_ALLOC_NORMAL, count, &actual, 0);
746fcf3ce44SJohn Forte 	/* we need at least 2 interrupt vectors */
747fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS || actual < 2) {
748c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_alloc status=%xh, actual=%d\n", ret,
749c4ddbbe1SDaniel Beauregard 		    actual);
750fcf3ce44SJohn Forte 		ret = DDI_FAILURE;
751fcf3ce44SJohn Forte 		goto release_intr;
752fcf3ce44SJohn Forte 	}
753fcf3ce44SJohn Forte 	if (actual < count) {
754c4ddbbe1SDaniel Beauregard 		EL(qlt, "requested: %d, received: %d\n", count, actual);
755fcf3ce44SJohn Forte 	}
756fcf3ce44SJohn Forte 
757fcf3ce44SJohn Forte 	qlt->intr_cnt = actual;
758fcf3ce44SJohn Forte 	ret =  ddi_intr_get_pri(qlt->htable[0], &qlt->intr_pri);
759fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS) {
760c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_get_pri status=%xh\n", ret);
761fcf3ce44SJohn Forte 		ret = DDI_FAILURE;
762fcf3ce44SJohn Forte 		goto release_intr;
763fcf3ce44SJohn Forte 	}
764fcf3ce44SJohn Forte 	qlt_init_mutex(qlt);
765fcf3ce44SJohn Forte 	for (i = 0; i < actual; i++) {
766fcf3ce44SJohn Forte 		ret = ddi_intr_add_handler(qlt->htable[i], qlt_isr,
767c4ddbbe1SDaniel Beauregard 		    qlt, INT2PTR((uint_t)i, void *));
768c4ddbbe1SDaniel Beauregard 		if (ret != DDI_SUCCESS) {
769c4ddbbe1SDaniel Beauregard 			EL(qlt, "ddi_intr_add_handler status=%xh\n", ret);
770fcf3ce44SJohn Forte 			goto release_mutex;
771c4ddbbe1SDaniel Beauregard 		}
772fcf3ce44SJohn Forte 	}
773fcf3ce44SJohn Forte 
774fcf3ce44SJohn Forte 	(void) ddi_intr_get_cap(qlt->htable[0], &qlt->intr_cap);
775fcf3ce44SJohn Forte 	qlt->intr_flags |= QLT_INTR_MSIX;
776fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
777fcf3ce44SJohn Forte 
778fcf3ce44SJohn Forte release_mutex:
779fcf3ce44SJohn Forte 	qlt_destroy_mutex(qlt);
780fcf3ce44SJohn Forte release_intr:
781fcf3ce44SJohn Forte 	for (i = 0; i < actual; i++)
782fcf3ce44SJohn Forte 		(void) ddi_intr_free(qlt->htable[i]);
783c4ddbbe1SDaniel Beauregard #if 0
784fcf3ce44SJohn Forte free_mem:
785c4ddbbe1SDaniel Beauregard #endif
786c4ddbbe1SDaniel Beauregard 	kmem_free(qlt->htable, (uint_t)qlt->intr_size);
787fcf3ce44SJohn Forte 	qlt->htable = NULL;
788fcf3ce44SJohn Forte 	qlt_release_intr(qlt);
789fcf3ce44SJohn Forte 	return (ret);
790fcf3ce44SJohn Forte }
791fcf3ce44SJohn Forte 
792fcf3ce44SJohn Forte 
793fcf3ce44SJohn Forte static int
qlt_setup_msi(qlt_state_t * qlt)794fcf3ce44SJohn Forte qlt_setup_msi(qlt_state_t *qlt)
795fcf3ce44SJohn Forte {
796fcf3ce44SJohn Forte 	int count, avail, actual;
797fcf3ce44SJohn Forte 	int itype = DDI_INTR_TYPE_MSI;
798fcf3ce44SJohn Forte 	int ret;
799fcf3ce44SJohn Forte 	int i;
800fcf3ce44SJohn Forte 
801fcf3ce44SJohn Forte 	/* get the # of interrupts */
802fcf3ce44SJohn Forte 	ret = ddi_intr_get_nintrs(qlt->dip, itype, &count);
803fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS || count == 0) {
804c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_get_nintrs status=%xh, count=%d\n", ret,
805c4ddbbe1SDaniel Beauregard 		    count);
806fcf3ce44SJohn Forte 		return (DDI_FAILURE);
807fcf3ce44SJohn Forte 	}
808fcf3ce44SJohn Forte 	ret = ddi_intr_get_navail(qlt->dip, itype, &avail);
809fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS || avail == 0) {
810c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_get_navail status=%xh, avail=%d\n", ret,
811c4ddbbe1SDaniel Beauregard 		    avail);
812fcf3ce44SJohn Forte 		return (DDI_FAILURE);
813fcf3ce44SJohn Forte 	}
814fcf3ce44SJohn Forte 	if (avail < count) {
815c4ddbbe1SDaniel Beauregard 		EL(qlt, "nintrs=%d, avail=%d\n", count, avail);
816fcf3ce44SJohn Forte 	}
817fcf3ce44SJohn Forte 	/* MSI requires only 1 interrupt. */
818fcf3ce44SJohn Forte 	count = 1;
819fcf3ce44SJohn Forte 
820fcf3ce44SJohn Forte 	/* allocate interrupt */
821c4ddbbe1SDaniel Beauregard 	qlt->intr_size = (int)(count * (int)sizeof (ddi_intr_handle_t));
822c4ddbbe1SDaniel Beauregard 	qlt->htable = kmem_zalloc((uint_t)qlt->intr_size, KM_SLEEP);
823fcf3ce44SJohn Forte 	ret = ddi_intr_alloc(qlt->dip, qlt->htable, itype,
824fcf3ce44SJohn Forte 	    0, count, &actual, DDI_INTR_ALLOC_NORMAL);
825fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS || actual == 0) {
826c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_alloc status=%xh, actual=%d\n", ret,
827c4ddbbe1SDaniel Beauregard 		    actual);
828fcf3ce44SJohn Forte 		ret = DDI_FAILURE;
829fcf3ce44SJohn Forte 		goto free_mem;
830fcf3ce44SJohn Forte 	}
831fcf3ce44SJohn Forte 	if (actual < count) {
832c4ddbbe1SDaniel Beauregard 		EL(qlt, "requested: %d, received: %d\n", count, actual);
833fcf3ce44SJohn Forte 	}
834fcf3ce44SJohn Forte 	qlt->intr_cnt = actual;
835fcf3ce44SJohn Forte 
836fcf3ce44SJohn Forte 	/*
837fcf3ce44SJohn Forte 	 * Get priority for first msi, assume remaining are all the same.
838fcf3ce44SJohn Forte 	 */
839fcf3ce44SJohn Forte 	ret =  ddi_intr_get_pri(qlt->htable[0], &qlt->intr_pri);
840fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS) {
841c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_get_pri status=%xh\n", ret);
842fcf3ce44SJohn Forte 		ret = DDI_FAILURE;
843fcf3ce44SJohn Forte 		goto release_intr;
844fcf3ce44SJohn Forte 	}
845fcf3ce44SJohn Forte 	qlt_init_mutex(qlt);
846fcf3ce44SJohn Forte 
847fcf3ce44SJohn Forte 	/* add handler */
848fcf3ce44SJohn Forte 	for (i = 0; i < actual; i++) {
849fcf3ce44SJohn Forte 		ret = ddi_intr_add_handler(qlt->htable[i], qlt_isr,
850c4ddbbe1SDaniel Beauregard 		    qlt, INT2PTR((uint_t)i, void *));
851c4ddbbe1SDaniel Beauregard 		if (ret != DDI_SUCCESS) {
852c4ddbbe1SDaniel Beauregard 			EL(qlt, "ddi_intr_add_handler status=%xh\n", ret);
853fcf3ce44SJohn Forte 			goto release_mutex;
854c4ddbbe1SDaniel Beauregard 		}
855fcf3ce44SJohn Forte 	}
856fcf3ce44SJohn Forte 
857fcf3ce44SJohn Forte 	(void) ddi_intr_get_cap(qlt->htable[0], &qlt->intr_cap);
858fcf3ce44SJohn Forte 	qlt->intr_flags |= QLT_INTR_MSI;
859fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
860fcf3ce44SJohn Forte 
861fcf3ce44SJohn Forte release_mutex:
862fcf3ce44SJohn Forte 	qlt_destroy_mutex(qlt);
863fcf3ce44SJohn Forte release_intr:
864fcf3ce44SJohn Forte 	for (i = 0; i < actual; i++)
865fcf3ce44SJohn Forte 		(void) ddi_intr_free(qlt->htable[i]);
866fcf3ce44SJohn Forte free_mem:
867c4ddbbe1SDaniel Beauregard 	kmem_free(qlt->htable, (uint_t)qlt->intr_size);
868fcf3ce44SJohn Forte 	qlt->htable = NULL;
869fcf3ce44SJohn Forte 	qlt_release_intr(qlt);
870fcf3ce44SJohn Forte 	return (ret);
871fcf3ce44SJohn Forte }
872fcf3ce44SJohn Forte 
873fcf3ce44SJohn Forte static int
qlt_setup_fixed(qlt_state_t * qlt)874fcf3ce44SJohn Forte qlt_setup_fixed(qlt_state_t *qlt)
875fcf3ce44SJohn Forte {
876fcf3ce44SJohn Forte 	int count;
877fcf3ce44SJohn Forte 	int actual;
878fcf3ce44SJohn Forte 	int ret;
879fcf3ce44SJohn Forte 	int itype = DDI_INTR_TYPE_FIXED;
880fcf3ce44SJohn Forte 
881fcf3ce44SJohn Forte 	ret = ddi_intr_get_nintrs(qlt->dip, itype, &count);
882fcf3ce44SJohn Forte 	/* Fixed interrupts can only have one interrupt. */
883fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS || count != 1) {
884c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_get_nintrs status=%xh, count=%d\n", ret,
885c4ddbbe1SDaniel Beauregard 		    count);
886fcf3ce44SJohn Forte 		return (DDI_FAILURE);
887fcf3ce44SJohn Forte 	}
888fcf3ce44SJohn Forte 
889fcf3ce44SJohn Forte 	qlt->intr_size = sizeof (ddi_intr_handle_t);
890c4ddbbe1SDaniel Beauregard 	qlt->htable = kmem_zalloc((uint_t)qlt->intr_size, KM_SLEEP);
891fcf3ce44SJohn Forte 	ret = ddi_intr_alloc(qlt->dip, qlt->htable, itype,
892fcf3ce44SJohn Forte 	    DDI_INTR_ALLOC_NORMAL, count, &actual, 0);
893fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS || actual != 1) {
894c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_alloc status=%xh, actual=%d\n", ret,
895c4ddbbe1SDaniel Beauregard 		    actual);
896fcf3ce44SJohn Forte 		ret = DDI_FAILURE;
897fcf3ce44SJohn Forte 		goto free_mem;
898fcf3ce44SJohn Forte 	}
899fcf3ce44SJohn Forte 
900fcf3ce44SJohn Forte 	qlt->intr_cnt = actual;
901fcf3ce44SJohn Forte 	ret =  ddi_intr_get_pri(qlt->htable[0], &qlt->intr_pri);
902fcf3ce44SJohn Forte 	if (ret != DDI_SUCCESS) {
903c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_get_pri status=%xh\n", ret);
904fcf3ce44SJohn Forte 		ret = DDI_FAILURE;
905fcf3ce44SJohn Forte 		goto release_intr;
906fcf3ce44SJohn Forte 	}
907fcf3ce44SJohn Forte 	qlt_init_mutex(qlt);
908fcf3ce44SJohn Forte 	ret = ddi_intr_add_handler(qlt->htable[0], qlt_isr, qlt, 0);
909c4ddbbe1SDaniel Beauregard 	if (ret != DDI_SUCCESS) {
910c4ddbbe1SDaniel Beauregard 		EL(qlt, "ddi_intr_add_handler status=%xh\n", ret);
911fcf3ce44SJohn Forte 		goto release_mutex;
912c4ddbbe1SDaniel Beauregard 	}
913fcf3ce44SJohn Forte 
914fcf3ce44SJohn Forte 	qlt->intr_flags |= QLT_INTR_FIXED;
915fcf3ce44SJohn Forte 	return (DDI_SUCCESS);
916fcf3ce44SJohn Forte 
917fcf3ce44SJohn Forte release_mutex:
918fcf3ce44SJohn Forte 	qlt_destroy_mutex(qlt);
919fcf3ce44SJohn Forte release_intr:
920fcf3ce44SJohn Forte 	(void) ddi_intr_free(qlt->htable[0]);
921fcf3ce44SJohn Forte free_mem:
922c4ddbbe1SDaniel Beauregard 	kmem_free(qlt->htable, (uint_t)qlt->intr_size);
923fcf3ce44SJohn Forte 	qlt->htable = NULL;
924fcf3ce44SJohn Forte 	qlt_release_intr(qlt);
925fcf3ce44SJohn Forte 	return (ret);
926fcf3ce44SJohn Forte }
927fcf3ce44SJohn Forte 
928fcf3ce44SJohn Forte static int
qlt_setup_interrupts(qlt_state_t * qlt)929fcf3ce44SJohn Forte qlt_setup_interrupts(qlt_state_t *qlt)
930fcf3ce44SJohn Forte {
931fcf3ce44SJohn Forte 	int itypes = 0;
932fcf3ce44SJohn Forte 
933fcf3ce44SJohn Forte /*
934a2255df3SDaniel Beauregard  * x86 has a bug in the ddi_intr_block_enable/disable area (6562198).
935fcf3ce44SJohn Forte  */
936a2255df3SDaniel Beauregard #ifndef __sparc
937a2255df3SDaniel Beauregard 	if (qlt_enable_msi != 0) {
938a2255df3SDaniel Beauregard #endif
939fcf3ce44SJohn Forte 	if (ddi_intr_get_supported_types(qlt->dip, &itypes) != DDI_SUCCESS) {
940fcf3ce44SJohn Forte 		itypes = DDI_INTR_TYPE_FIXED;
941fcf3ce44SJohn Forte 	}
942fcf3ce44SJohn Forte 
943fcf3ce44SJohn Forte 	if (qlt_enable_msix && (itypes & DDI_INTR_TYPE_MSIX)) {
944fcf3ce44SJohn Forte 		if (qlt_setup_msix(qlt) == DDI_SUCCESS)
945fcf3ce44SJohn Forte 			return (DDI_SUCCESS);
946fcf3ce44SJohn Forte 	}
947a2255df3SDaniel Beauregard 
948fcf3ce44SJohn Forte 	if (itypes & DDI_INTR_TYPE_MSI) {
949fcf3ce44SJohn Forte 		if (qlt_setup_msi(qlt) == DDI_SUCCESS)
950fcf3ce44SJohn Forte 			return (DDI_SUCCESS);
951fcf3ce44SJohn Forte 	}
952a2255df3SDaniel Beauregard #ifndef __sparc
953a2255df3SDaniel Beauregard 	}
954fcf3ce44SJohn Forte #endif
955fcf3ce44SJohn Forte 	return (qlt_setup_fixed(qlt));
956fcf3ce44SJohn Forte }
957fcf3ce44SJohn Forte 
958fcf3ce44SJohn Forte /*
959fcf3ce44SJohn Forte  * Filling the hba attributes
960fcf3ce44SJohn Forte  */
961fcf3ce44SJohn Forte void
qlt_populate_hba_fru_details(struct fct_local_port * port,struct fct_port_attrs * port_attrs)962fcf3ce44SJohn Forte qlt_populate_hba_fru_details(struct fct_local_port *port,
963fcf3ce44SJohn Forte     struct fct_port_attrs *port_attrs)
964fcf3ce44SJohn Forte {
965fcf3ce44SJohn Forte 	caddr_t	bufp;
966fcf3ce44SJohn Forte 	int len;
967fcf3ce44SJohn Forte 	qlt_state_t *qlt = (qlt_state_t *)port->port_fca_private;
968fcf3ce44SJohn Forte 
969fcf3ce44SJohn Forte 	(void) snprintf(port_attrs->manufacturer, FCHBA_MANUFACTURER_LEN,
970fcf3ce44SJohn Forte 	    "QLogic Corp.");
971fcf3ce44SJohn Forte 	(void) snprintf(port_attrs->driver_name, FCHBA_DRIVER_NAME_LEN,
972fcf3ce44SJohn Forte 	    "%s", QLT_NAME);
973fcf3ce44SJohn Forte 	(void) snprintf(port_attrs->driver_version, FCHBA_DRIVER_VERSION_LEN,
974fcf3ce44SJohn Forte 	    "%s", QLT_VERSION);
975fcf3ce44SJohn Forte 	port_attrs->serial_number[0] = '\0';
976fcf3ce44SJohn Forte 	port_attrs->hardware_version[0] = '\0';
977fcf3ce44SJohn Forte 
978fcf3ce44SJohn Forte 	(void) snprintf(port_attrs->firmware_version,
979fcf3ce44SJohn Forte 	    FCHBA_FIRMWARE_VERSION_LEN, "%d.%d.%d", qlt->fw_major,
980fcf3ce44SJohn Forte