1fcf3ce4John Forte/*
2fcf3ce4John Forte * CDDL HEADER START
3fcf3ce4John Forte *
4fcf3ce4John Forte * The contents of this file are subject to the terms of the
5fcf3ce4John Forte * Common Development and Distribution License (the "License").
6fcf3ce4John Forte * You may not use this file except in compliance with the License.
7fcf3ce4John Forte *
8fcf3ce4John Forte * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce4John Forte * or http://www.opensolaris.org/os/licensing.
10fcf3ce4John Forte * See the License for the specific language governing permissions
11fcf3ce4John Forte * and limitations under the License.
12fcf3ce4John Forte *
13fcf3ce4John Forte * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce4John Forte * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce4John Forte * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce4John Forte * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce4John Forte * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce4John Forte *
19fcf3ce4John Forte * CDDL HEADER END
20fcf3ce4John Forte */
21c4ddbbeDaniel Beauregard
22c4ddbbeDaniel Beauregard/*
23c4ddbbeDaniel Beauregard * Copyright 2009 QLogic Corporation.  All rights reserved.
24c4ddbbeDaniel Beauregard * Use is subject to license terms.
25c4ddbbeDaniel Beauregard */
26c4ddbbeDaniel Beauregard
27fcf3ce4John Forte/*
283fb517fJames Moore * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
29fcf3ce4John Forte */
30fcf3ce4John Forte
31fcf3ce4John Forte#include <sys/conf.h>
32fcf3ce4John Forte#include <sys/ddi.h>
33fcf3ce4John Forte#include <sys/stat.h>
34fcf3ce4John Forte#include <sys/pci.h>
35fcf3ce4John Forte#include <sys/sunddi.h>
36fcf3ce4John Forte#include <sys/modctl.h>
37fcf3ce4John Forte#include <sys/file.h>
38fcf3ce4John Forte#include <sys/cred.h>
39fcf3ce4John Forte#include <sys/byteorder.h>
40fcf3ce4John Forte#include <sys/atomic.h>
41fcf3ce4John Forte#include <sys/scsi/scsi.h>
42fcf3ce4John Forte
434558d12Viswanathan Kannappan#include <sys/stmf_defines.h>
444558d12Viswanathan Kannappan#include <sys/fct_defines.h>
454558d12Viswanathan Kannappan#include <sys/stmf.h>
464558d12Viswanathan Kannappan#include <sys/stmf_ioctl.h>
474558d12Viswanathan Kannappan#include <sys/portif.h>
484558d12Viswanathan Kannappan#include <sys/fct.h>
494558d12Viswanathan Kannappan
504558d12Viswanathan Kannappan#include "qlt.h"
514558d12Viswanathan Kannappan#include "qlt_dma.h"
524558d12Viswanathan Kannappan#include "qlt_ioctl.h"
534558d12Viswanathan Kannappan#include "qlt_open.h"
54fcf3ce4John Forte
55fcf3ce4John Fortestatic int qlt_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
56fcf3ce4John Fortestatic int qlt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
57a2255dfDaniel Beauregardstatic void qlt_enable_intr(qlt_state_t *);
58a2255dfDaniel Beauregardstatic void qlt_disable_intr(qlt_state_t *);
59a2255dfDaniel Beauregardstatic fct_status_t qlt_reset_chip(qlt_state_t *qlt);
60a2255dfDaniel Beauregardstatic fct_status_t qlt_download_fw(qlt_state_t *qlt);
61fcf3ce4John Fortestatic fct_status_t qlt_load_risc_ram(qlt_state_t *qlt, uint32_t *host_addr,
62fcf3ce4John Forte    uint32_t word_count, uint32_t risc_addr);
63fcf3ce4John Fortestatic fct_status_t qlt_raw_mailbox_command(qlt_state_t *qlt);
64fcf3ce4John Fortestatic mbox_cmd_t *qlt_alloc_mailbox_command(qlt_state_t *qlt,
65fcf3ce4John Forte					uint32_t dma_size);
66fcf3ce4John Fortevoid qlt_free_mailbox_command(qlt_state_t *qlt, mbox_cmd_t *mcp);
67fcf3ce4John Fortestatic fct_status_t qlt_mailbox_command(qlt_state_t *qlt, mbox_cmd_t *mcp);
68fcf3ce4John Fortestatic uint_t qlt_isr(caddr_t arg, caddr_t arg2);
69fcf3ce4John Fortestatic fct_status_t qlt_firmware_dump(fct_local_port_t *port,
70fcf3ce4John Forte    stmf_state_change_info_t *ssci);
71fcf3ce4John Fortestatic void qlt_handle_inot(qlt_state_t *qlt, uint8_t *inot);
72fcf3ce4John Fortestatic void qlt_handle_purex(qlt_state_t *qlt, uint8_t *resp);
73fcf3ce4John Fortestatic void qlt_handle_atio(qlt_state_t *qlt, uint8_t *atio);
74fcf3ce4John Fortestatic void qlt_handle_ctio_completion(qlt_state_t *qlt, uint8_t *rsp);
75fcf3ce4John Fortestatic void qlt_handle_sol_abort_completion(qlt_state_t *qlt, uint8_t *rsp);
76fcf3ce4John Fortestatic void qlt_handle_dereg_completion(qlt_state_t *qlt, uint8_t *rsp);
77fcf3ce4John Fortestatic void qlt_handle_unsol_els_completion(qlt_state_t *qlt, uint8_t *rsp);
78fcf3ce4John Fortestatic void qlt_handle_unsol_els_abort_completion(qlt_state_t *qlt,
79fcf3ce4John Forte    uint8_t *rsp);
80fcf3ce4John Fortestatic void qlt_handle_sol_els_completion(qlt_state_t *qlt, uint8_t *rsp);
81fcf3ce4John Fortestatic void qlt_handle_rcvd_abts(qlt_state_t *qlt, uint8_t *resp);
82fcf3ce4John Fortestatic void qlt_handle_abts_completion(qlt_state_t *qlt, uint8_t *resp);
83fcf3ce4John Fortestatic fct_status_t qlt_read_nvram(qlt_state_t *qlt);
84c4ddbbeDaniel Beauregardstatic void qlt_verify_fw(qlt_state_t *qlt);
85c4ddbbeDaniel Beauregardstatic void qlt_handle_verify_fw_completion(qlt_state_t *qlt, uint8_t *rsp);
86fcf3ce4John Fortefct_status_t qlt_port_start(caddr_t arg);
87fcf3ce4John Fortefct_status_t qlt_port_stop(caddr_t arg);
88fcf3ce4John Fortefct_status_t qlt_port_online(qlt_state_t *qlt);
89fcf3ce4John Fortefct_status_t qlt_port_offline(qlt_state_t *qlt);
90fcf3ce4John Fortestatic fct_status_t qlt_get_link_info(fct_local_port_t *port,
91fcf3ce4John Forte    fct_link_info_t *li);
92fcf3ce4John Fortestatic void qlt_ctl(struct fct_local_port *port, int cmd, void *arg);
93a2255dfDaniel Beauregardstatic fct_status_t qlt_force_lip(qlt_state_t *);
94fcf3ce4John Fortestatic fct_status_t qlt_do_flogi(struct fct_local_port *port,
95fcf3ce4John Forte						fct_flogi_xchg_t *fx);
96fcf3ce4John Fortevoid qlt_handle_atio_queue_update(qlt_state_t *qlt);
97fcf3ce4John Fortevoid qlt_handle_resp_queue_update(qlt_state_t *qlt);
98fcf3ce4John Fortefct_status_t qlt_register_remote_port(fct_local_port_t *port,
99fcf3ce4John Forte    fct_remote_port_t *rp, fct_cmd_t *login);
100fcf3ce4John Fortefct_status_t qlt_deregister_remote_port(fct_local_port_t *port,
101fcf3ce4John Forte    fct_remote_port_t *rp);
102fcf3ce4John Fortefct_status_t qlt_send_cmd_response(fct_cmd_t *cmd, uint32_t ioflags);
103fcf3ce4John Fortefct_status_t qlt_send_els_response(qlt_state_t *qlt, fct_cmd_t *cmd);
104fcf3ce4John Fortefct_status_t qlt_send_abts_response(qlt_state_t *qlt,
105fcf3ce4John Forte    fct_cmd_t *cmd, int terminate);
106fcf3ce4John Fortestatic void qlt_handle_inot(qlt_state_t *qlt, uint8_t *inot);
107fcf3ce4John Forteint qlt_set_uniq_flag(uint16_t *ptr, uint16_t setf, uint16_t abortf);
108fcf3ce4John Fortefct_status_t qlt_abort_cmd(struct fct_local_port *port,
109fcf3ce4John Forte    fct_cmd_t *cmd, uint32_t flags);
110fcf3ce4John Fortefct_status_t qlt_abort_sol_cmd(qlt_state_t *qlt, fct_cmd_t *cmd);
111fcf3ce4John Fortefct_status_t qlt_abort_purex(qlt_state_t *qlt, fct_cmd_t *cmd);
112fcf3ce4John Fortefct_status_t qlt_abort_unsol_scsi_cmd(qlt_state_t *qlt, fct_cmd_t *cmd);
113fcf3ce4John Fortefct_status_t qlt_send_cmd(fct_cmd_t *cmd);
114fcf3ce4John Fortefct_status_t qlt_send_els(qlt_state_t *qlt, fct_cmd_t *cmd);
115fcf3ce4John Fortefct_status_t qlt_send_status(qlt_state_t *qlt, fct_cmd_t *cmd);
116fcf3ce4John Fortefct_status_t qlt_xfer_scsi_data(fct_cmd_t *cmd,
117fcf3ce4John Forte    stmf_data_buf_t *dbuf, uint32_t ioflags);
118fcf3ce4John Fortefct_status_t qlt_send_ct(qlt_state_t *qlt, fct_cmd_t *cmd);
119fcf3ce4John Fortestatic void qlt_handle_ct_completion(qlt_state_t *qlt, uint8_t *rsp);
120fcf3ce4John Fortestatic void qlt_release_intr(qlt_state_t *qlt);
121fcf3ce4John Fortestatic int qlt_setup_interrupts(qlt_state_t *qlt);
122fcf3ce4John Fortestatic void qlt_destroy_mutex(qlt_state_t *qlt);
123fcf3ce4John Forte
124fcf3ce4John Fortestatic fct_status_t qlt_read_risc_ram(qlt_state_t *qlt, uint32_t addr,
125fcf3ce4John Forte    uint32_t words);
126fcf3ce4John Fortestatic int qlt_dump_queue(qlt_state_t *qlt, caddr_t qadr, int entries,
127c4ddbbeDaniel Beauregard    caddr_t buf, uint_t size_left);
128fcf3ce4John Fortestatic int qlt_dump_risc_ram(qlt_state_t *qlt, uint32_t addr, uint32_t words,
129c4ddbbeDaniel Beauregard    caddr_t buf, uint_t size_left);
130fcf3ce4John Fortestatic int qlt_fwdump_dump_regs(qlt_state_t *qlt, caddr_t buf, int startaddr,
131c4ddbbeDaniel Beauregard    int count, uint_t size_left);
132fcf3ce4John Fortestatic int qlt_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
133fcf3ce4John Forte    cred_t *credp, int *rval);
134fcf3ce4John Fortestatic int qlt_open(dev_t *devp, int flag, int otype, cred_t *credp);
135fcf3ce4John Fortestatic int qlt_close(dev_t dev, int flag, int otype, cred_t *credp);
136fcf3ce4John Forte
137c4ddbbeDaniel Beauregardstatic int qlt_setup_msi(qlt_state_t *qlt);
138c4ddbbeDaniel Beauregardstatic int qlt_setup_msix(qlt_state_t *qlt);
139c4ddbbeDaniel Beauregard
140c4ddbbeDaniel Beauregardstatic int qlt_el_trace_desc_ctor(qlt_state_t *qlt);
141c4ddbbeDaniel Beauregardstatic int qlt_el_trace_desc_dtor(qlt_state_t *qlt);
142c4ddbbeDaniel Beauregardstatic int qlt_validate_trace_desc(qlt_state_t *qlt);
143c4ddbbeDaniel Beauregardstatic char *qlt_find_trace_start(qlt_state_t *qlt);
144c4ddbbeDaniel Beauregard
1450ff6bfaDaniel Beauregardstatic int qlt_read_int_prop(qlt_state_t *qlt, char *prop, int defval);
1460ff6bfaDaniel Beauregardstatic int qlt_read_string_prop(qlt_state_t *qlt, char *prop, char **prop_val);
1470ff6bfaDaniel Beauregardstatic int qlt_read_string_instance_prop(qlt_state_t *qlt, char *prop,
1480ff6bfaDaniel Beauregard    char **prop_val);
149a2255dfDaniel Beauregardstatic int qlt_read_int_instance_prop(qlt_state_t *, char *, int);
1500ff6bfaDaniel Beauregardstatic int qlt_convert_string_to_ull(char *prop, int radix,
1510ff6bfaDaniel Beauregard    u_longlong_t *result);
1520ff6bfaDaniel Beauregardstatic boolean_t qlt_wwn_overload_prop(qlt_state_t *qlt);
1530ff6bfaDaniel Beauregardstatic int qlt_quiesce(dev_info_t *dip);
154a2255dfDaniel Beauregardstatic fct_status_t qlt_raw_wrt_risc_ram_word(qlt_state_t *qlt, uint32_t,
155a2255dfDaniel Beauregard    uint32_t);
156a2255dfDaniel Beauregardstatic fct_status_t qlt_raw_rd_risc_ram_word(qlt_state_t *qlt, uint32_t,
157a2255dfDaniel Beauregard    uint32_t *);
158a2255dfDaniel Beauregardstatic void qlt_mps_reset(qlt_state_t *qlt);
159a2255dfDaniel Beauregardstatic void qlt_properties(qlt_state_t *qlt);
160a2255dfDaniel Beauregard
1610ff6bfaDaniel Beauregard
162c4ddbbeDaniel Beauregard#define	SETELSBIT(bmp, els)	(bmp)[((els) >> 3) & 0x1F] = \
163c4ddbbeDaniel Beauregard	(uint8_t)((bmp)[((els) >> 3) & 0x1F] | ((uint8_t)1) << ((els) & 7))
164fcf3ce4John Forte
165fcf3ce4John Forteint qlt_enable_msix = 0;
166a2255dfDaniel Beauregardint qlt_enable_msi = 1;
167a2255dfDaniel Beauregard
168fcf3ce4John Forte
1690ff6bfaDaniel Beauregardstring_table_t prop_status_tbl[] = DDI_PROP_STATUS();
1700ff6bfaDaniel Beauregard
171fcf3ce4John Forte/* Array to quickly calculate next free buf index to use */
172c4ddbbeDaniel Beauregard#if 0
173fcf3ce4John Fortestatic int qlt_nfb[] = { 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 0xff };
174c4ddbbeDaniel Beauregard#endif
175fcf3ce4John Forte
176fcf3ce4John Fortestatic struct cb_ops qlt_cb_ops = {
177fcf3ce4John Forte	qlt_open,
178fcf3ce4John Forte	qlt_close,
179fcf3ce4John Forte	nodev,
180fcf3ce4John Forte	nodev,
181fcf3ce4John Forte	nodev,
182fcf3ce4John Forte	nodev,
183fcf3ce4John Forte	nodev,
184fcf3ce4John Forte	qlt_ioctl,
185fcf3ce4John Forte	nodev,
186fcf3ce4John Forte	nodev,
187fcf3ce4John Forte	nodev,
188fcf3ce4John Forte	nochpoll,
189fcf3ce4John Forte	ddi_prop_op,
190fcf3ce4John Forte	0,
191fcf3ce4John Forte	D_MP | D_NEW
192fcf3ce4John Forte};
193fcf3ce4John Forte
194fcf3ce4John Fortestatic struct dev_ops qlt_ops = {
195fcf3ce4John Forte	DEVO_REV,
196fcf3ce4John Forte	0,
197fcf3ce4John Forte	nodev,
198fcf3ce4John Forte	nulldev,
199fcf3ce4John Forte	nulldev,
200fcf3ce4John Forte	qlt_attach,
201fcf3ce4John Forte	qlt_detach,
202fcf3ce4John Forte	nodev,
203fcf3ce4John Forte	&qlt_cb_ops,
204fcf3ce4John Forte	NULL,
2050ff6bfaDaniel Beauregard	ddi_power,
2060ff6bfaDaniel Beauregard	qlt_quiesce
207fcf3ce4John Forte};
208fcf3ce4John Forte
209c4ddbbeDaniel Beauregard#ifndef	PORT_SPEED_10G
210c4ddbbeDaniel Beauregard#define	PORT_SPEED_10G		16
211c4ddbbeDaniel Beauregard#endif
212fcf3ce4John Forte
213fcf3ce4John Fortestatic struct modldrv modldrv = {
214fcf3ce4John Forte	&mod_driverops,
215c4ddbbeDaniel Beauregard	QLT_NAME" "QLT_VERSION,
216fcf3ce4John Forte	&qlt_ops,
217fcf3ce4John Forte};
218fcf3ce4John Forte
219fcf3ce4John Fortestatic struct modlinkage modlinkage = {
220fcf3ce4John Forte	MODREV_1, &modldrv, NULL
221fcf3ce4John Forte};
222fcf3ce4John Forte
223fcf3ce4John Fortevoid *qlt_state = NULL;
224fcf3ce4John Fortekmutex_t qlt_global_lock;
225fcf3ce4John Fortestatic uint32_t qlt_loaded_counter = 0;
226fcf3ce4John Forte
227fcf3ce4John Fortestatic char *pci_speeds[] = { " 33", "-X Mode 1 66", "-X Mode 1 100",
228fcf3ce4John Forte			"-X Mode 1 133", "--Invalid--",
229fcf3ce4John Forte			"-X Mode 2 66", "-X Mode 2 100",
230fcf3ce4John Forte			"-X Mode 2 133", " 66" };
231fcf3ce4John Forte
232fcf3ce4John Forte/* Always use 64 bit DMA. */
233fcf3ce4John Fortestatic ddi_dma_attr_t qlt_queue_dma_attr = {
234fcf3ce4John Forte	DMA_ATTR_V0,		/* dma_attr_version */
235fcf3ce4John Forte	0,			/* low DMA address range */
236fcf3ce4John Forte	0xffffffffffffffff,	/* high DMA address range */
237fcf3ce4John Forte	0xffffffff,		/* DMA counter register */
238fcf3ce4John Forte	64,			/* DMA address alignment */
239fcf3ce4John Forte	0xff,			/* DMA burstsizes */
240fcf3ce4John Forte	1,			/* min effective DMA size */
241fcf3ce4John Forte	0xffffffff,		/* max DMA xfer size */
242fcf3ce4John Forte	0xffffffff,		/* segment boundary */
243fcf3ce4John Forte	1,			/* s/g list length */
244fcf3ce4John Forte	1,			/* granularity of device */
245fcf3ce4John Forte	0			/* DMA transfer flags */
246fcf3ce4John Forte};
247fcf3ce4John Forte
248fcf3ce4John Forte/* qlogic logging */
249fcf3ce4John Forteint enable_extended_logging = 0;
250fcf3ce4John Forte
251fcf3ce4John Fortestatic char qlt_provider_name[] = "qlt";
252fcf3ce4John Fortestatic struct stmf_port_provider *qlt_pp;
253fcf3ce4John Forte
254fcf3ce4John Forteint
255fcf3ce4John Forte_init(void)
256fcf3ce4John Forte{
257fcf3ce4John Forte	int ret;
258fcf3ce4John Forte
259fcf3ce4John Forte	ret = ddi_soft_state_init(&qlt_state, sizeof (qlt_state_t), 0);
260fcf3ce4John Forte	if (ret == 0) {
261fcf3ce4John Forte		mutex_init(&qlt_global_lock, 0, MUTEX_DRIVER, 0);
262fcf3ce4John Forte		qlt_pp = (stmf_port_provider_t *)stmf_alloc(
263d8c54e3Sam Cramer		    STMF_STRUCT_PORT_PROVIDER, 0, 0);
264fcf3ce4John Forte		qlt_pp->pp_portif_rev = PORTIF_REV_1;
265fcf3ce4John Forte		qlt_pp->pp_name = qlt_provider_name;
266fcf3ce4John Forte		if (stmf_register_port_provider(qlt_pp) != STMF_SUCCESS) {
267fcf3ce4John Forte			stmf_free(qlt_pp);
268fcf3ce4John Forte			mutex_destroy(&qlt_global_lock);
269fcf3ce4John Forte			ddi_soft_state_fini(&qlt_state);
270fcf3ce4John Forte			return (EIO);
271fcf3ce4John Forte		}
272fcf3ce4John Forte		ret = mod_install(&modlinkage);
273fcf3ce4John Forte		if (ret != 0) {
274fcf3ce4John Forte			(void) stmf_deregister_port_provider(qlt_pp);
275fcf3ce4John Forte			stmf_free(qlt_pp);
276fcf3ce4John Forte			mutex_destroy(&qlt_global_lock);
277fcf3ce4John Forte			ddi_soft_state_fini(&qlt_state);
278fcf3ce4John Forte		}
279fcf3ce4John Forte	}
280fcf3ce4John Forte	return (ret);
281fcf3ce4John Forte}
282fcf3ce4John Forte
283fcf3ce4John Forteint
284fcf3ce4John Forte_fini(void)
285fcf3ce4John Forte{
286fcf3ce4John Forte	int ret;
287fcf3ce4John Forte
288fcf3ce4John Forte	if (qlt_loaded_counter)
289fcf3ce4John Forte		return (EBUSY);
290fcf3ce4John Forte	ret = mod_remove(&modlinkage);
291fcf3ce4John Forte	if (ret == 0) {
292fcf3ce4John Forte		(void) stmf_deregister_port_provider(qlt_pp);
293fcf3ce4John Forte		stmf_free(qlt_pp);
294fcf3ce4John Forte		mutex_destroy(&qlt_global_lock);
295fcf3ce4John Forte		ddi_soft_state_fini(&qlt_state);
296fcf3ce4John Forte	}
297fcf3ce4John Forte	return (ret);
298fcf3ce4John Forte}
299fcf3ce4John Forte
300fcf3ce4John Forteint
301fcf3ce4John Forte_info(struct modinfo *modinfop)
302fcf3ce4John Forte{
303fcf3ce4John Forte	return (mod_info(&modlinkage, modinfop));
304fcf3ce4John Forte}
305fcf3ce4John Forte
306fcf3ce4John Forte
307fcf3ce4John Fortestatic int
308fcf3ce4John Forteqlt_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
309fcf3ce4John Forte{
310fcf3ce4John Forte	int		instance;
311fcf3ce4John Forte	qlt_state_t	*qlt;
312fcf3ce4John Forte	ddi_device_acc_attr_t	dev_acc_attr;
313fcf3ce4John Forte	uint16_t	did;
314fcf3ce4John Forte	uint16_t	val;
315fcf3ce4John Forte	uint16_t	mr;
316fcf3ce4John Forte	size_t		discard;
317fcf3ce4John Forte	uint_t		ncookies;
318fcf3ce4John Forte	int		max_read_size;
319fcf3ce4John Forte	int		max_payload_size;
320fcf3ce4John Forte	fct_status_t	ret;
321fcf3ce4John Forte
322fcf3ce4John Forte	/* No support for suspend resume yet */
323fcf3ce4John Forte	if (cmd != DDI_ATTACH)
324fcf3ce4John Forte		return (DDI_FAILURE);
325fcf3ce4John Forte	instance = ddi_get_instance(dip);
326fcf3ce4John Forte
327fcf3ce4John Forte	if (ddi_soft_state_zalloc(qlt_state, instance) != DDI_SUCCESS) {
328fcf3ce4John Forte		return (DDI_FAILURE);
329fcf3ce4John Forte	}
330fcf3ce4John Forte
331c4ddbbeDaniel Beauregard	if ((qlt = (qlt_state_t *)ddi_get_soft_state(qlt_state, instance)) ==
332c4ddbbeDaniel Beauregard	    NULL) {
333fcf3ce4John Forte		goto attach_fail_1;
334fcf3ce4John Forte	}
335a2255dfDaniel Beauregard
336fcf3ce4John Forte	qlt->instance = instance;
337a2255dfDaniel Beauregard
338fcf3ce4John Forte	qlt->nvram = (qlt_nvram_t *)kmem_zalloc(sizeof (qlt_nvram_t), KM_SLEEP);
339fcf3ce4John Forte	qlt->dip = dip;
340c4ddbbeDaniel Beauregard
341c4ddbbeDaniel Beauregard	if (qlt_el_trace_desc_ctor(qlt) != DDI_SUCCESS) {
342c4ddbbeDaniel Beauregard		cmn_err(CE_WARN, "qlt(%d): can't setup el tracing", instance);
343c4ddbbeDaniel Beauregard		goto attach_fail_1;
344c4ddbbeDaniel Beauregard	}
345c4ddbbeDaniel Beauregard
346a2255dfDaniel Beauregard	EL(qlt, "instance=%d, ptr=%p\n", instance, (void *)qlt);
347c4ddbbeDaniel Beauregard
348fcf3ce4John Forte	if (pci_config_setup(dip, &qlt->pcicfg_acc_handle) != DDI_SUCCESS) {
349fcf3ce4John Forte		goto attach_fail_2;
350fcf3ce4John Forte	}
351fcf3ce4John Forte	did = PCICFG_RD16(qlt, PCI_CONF_DEVID);
352fcf3ce4John Forte	if ((did != 0x2422) && (did != 0x2432) &&
353c4ddbbeDaniel Beauregard	    (did != 0x8432) && (did != 0x2532) &&
354c4ddbbeDaniel Beauregard	    (did != 0x8001)) {
355c4ddbbeDaniel Beauregard		cmn_err(CE_WARN, "qlt(%d): unknown devid(%x), failing attach",
356fcf3ce4John Forte		    instance, did);
357fcf3ce4John Forte		goto attach_fail_4;
358fcf3ce4John Forte	}
359c4ddbbeDaniel Beauregard
360c4ddbbeDaniel Beauregard	if ((did & 0xFF00) == 0x8000)
361c4ddbbeDaniel Beauregard		qlt->qlt_81xx_chip = 1;
362c4ddbbeDaniel Beauregard	else if ((did & 0xFF00) == 0x2500)
363fcf3ce4John Forte		qlt->qlt_25xx_chip = 1;
364fcf3ce4John Forte
365fcf3ce4John Forte	dev_acc_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
366fcf3ce4John Forte	dev_acc_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
367fcf3ce4John Forte	dev_acc_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
368fcf3ce4John Forte	if (ddi_regs_map_setup(dip, 2, &qlt->regs, 0, 0x100,
369fcf3ce4John Forte	    &dev_acc_attr, &qlt->regs_acc_handle) != DDI_SUCCESS) {
370fcf3ce4John Forte		goto attach_fail_4;
371fcf3ce4John Forte	}
372fcf3ce4John Forte	if (did == 0x2422) {
373fcf3ce4John Forte		uint32_t pci_bits = REG_RD32(qlt, REG_CTRL_STATUS);
374fcf3ce4John Forte		uint32_t slot = pci_bits & PCI_64_BIT_SLOT;
375fcf3ce4John Forte		pci_bits >>= 8;
376fcf3ce4John Forte		pci_bits &= 0xf;
377fcf3ce4John Forte		if ((pci_bits == 3) || (pci_bits == 7)) {
378fcf3ce4John Forte			cmn_err(CE_NOTE,
379fcf3ce4John Forte			    "!qlt(%d): HBA running at PCI%sMHz (%d)",
380fcf3ce4John Forte			    instance, pci_speeds[pci_bits], pci_bits);
381fcf3ce4John Forte		} else {
382fcf3ce4John Forte			cmn_err(CE_WARN,
383fcf3ce4John Forte			    "qlt(%d): HBA running at PCI%sMHz %s(%d)",
384fcf3ce4John Forte			    instance, (pci_bits <= 8) ? pci_speeds[pci_bits] :
385fcf3ce4John Forte			    "(Invalid)", ((pci_bits == 0) ||
386fcf3ce4John Forte			    (pci_bits == 8)) ? (slot ? "64 bit slot " :
387fcf3ce4John Forte			    "32 bit slot ") : "", pci_bits);
388fcf3ce4John Forte		}
389fcf3ce4John Forte	}
390fcf3ce4John Forte	if ((ret = qlt_read_nvram(qlt)) != QLT_SUCCESS) {
391fcf3ce4John Forte		cmn_err(CE_WARN, "qlt(%d): read nvram failure %llx", instance,
392fcf3ce4John Forte		    (unsigned long long)ret);
393fcf3ce4John Forte		goto attach_fail_5;
394fcf3ce4John Forte	}
395a2255dfDaniel Beauregard
396a2255dfDaniel Beauregard	qlt_properties(qlt);
397a2255dfDaniel Beauregard
398fcf3ce4John Forte	if (ddi_dma_alloc_handle(dip, &qlt_queue_dma_attr, DDI_DMA_SLEEP,
399fcf3ce4John Forte	    0, &qlt->queue_mem_dma_handle) != DDI_SUCCESS) {
400fcf3ce4John Forte		goto attach_fail_5;
401fcf3ce4John Forte	}
402fcf3ce4John Forte	if (ddi_dma_mem_alloc(qlt->queue_mem_dma_handle, TOTAL_DMA_MEM_SIZE,
403fcf3ce4John Forte	    &dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0,
404fcf3ce4John Forte	    &qlt->queue_mem_ptr, &discard, &qlt->queue_mem_acc_handle) !=
405fcf3ce4John Forte	    DDI_SUCCESS) {
406fcf3ce4John Forte		goto attach_fail_6;
407fcf3ce4John Forte	}
408fcf3ce4John Forte	if (ddi_dma_addr_bind_handle(qlt->queue_mem_dma_handle, NULL,
409fcf3ce4John Forte	    qlt->queue_mem_ptr, TOTAL_DMA_MEM_SIZE,
410fcf3ce4John Forte	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0,
411fcf3ce4John Forte	    &qlt->queue_mem_cookie, &ncookies) != DDI_SUCCESS) {
412fcf3ce4John Forte		goto attach_fail_7;
413fcf3ce4John Forte	}
414fcf3ce4John Forte	if (ncookies != 1)
415fcf3ce4John Forte		goto attach_fail_8;
416fcf3ce4John Forte	qlt->req_ptr = qlt->queue_mem_ptr + REQUEST_QUEUE_OFFSET;
417fcf3ce4John Forte	qlt->resp_ptr = qlt->queue_mem_ptr + RESPONSE_QUEUE_OFFSET;
418fcf3ce4John Forte	qlt->preq_ptr = qlt->queue_mem_ptr + PRIORITY_QUEUE_OFFSET;
419fcf3ce4John Forte	qlt->atio_ptr = qlt->queue_mem_ptr + ATIO_QUEUE_OFFSET;
420fcf3ce4John Forte
421fcf3ce4John Forte	/* mutex are inited in this function */
422fcf3ce4John Forte	if (qlt_setup_interrupts(qlt) != DDI_SUCCESS)
423fcf3ce4John Forte		goto attach_fail_8;
424fcf3ce4John Forte
425fcf3ce4John Forte	(void) snprintf(qlt->qlt_minor_name, sizeof (qlt->qlt_minor_name),
426d8c54e3Sam Cramer	    "qlt%d", instance);
427fcf3ce4John Forte	(void) snprintf(qlt->qlt_port_alias, sizeof (qlt->qlt_port_alias),
428fcf3ce4John Forte	    "%s,0", qlt->qlt_minor_name);
429fcf3ce4John Forte
430fcf3ce4John Forte	if (ddi_create_minor_node(dip, qlt->qlt_minor_name, S_IFCHR,
431d8c54e3Sam Cramer	    instance, DDI_NT_STMF_PP, 0) != DDI_SUCCESS) {
432fcf3ce4John Forte		goto attach_fail_9;
433fcf3ce4John Forte	}
434fcf3ce4John Forte
435fcf3ce4John Forte	cv_init(&qlt->rp_dereg_cv, NULL, CV_DRIVER, NULL);
436fcf3ce4John Forte	cv_init(&qlt->mbox_cv, NULL, CV_DRIVER, NULL);
437fcf3ce4John Forte	mutex_init(&qlt->qlt_ioctl_lock, NULL, MUTEX_DRIVER, NULL);
438fcf3ce4John Forte
439fcf3ce4John Forte	/* Setup PCI cfg space registers */
440fcf3ce4John Forte	max_read_size = qlt_read_int_prop(qlt, "pci-max-read-request", 11);
441fcf3ce4John Forte	if (max_read_size == 11)
442fcf3ce4John Forte		goto over_max_read_xfer_setting;
443fcf3ce4John Forte	if (did == 0x2422) {
444fcf3ce4John Forte		if (max_read_size == 512)
445fcf3ce4John Forte			val = 0;
446fcf3ce4John Forte		else if (max_read_size == 1024)
447fcf3ce4John Forte			val = 1;
448fcf3ce4John Forte		else if (max_read_size == 2048)
449fcf3ce4John Forte			val = 2;
450fcf3ce4John Forte		else if (max_read_size == 4096)
451fcf3ce4John Forte			val = 3;
452fcf3ce4John Forte		else {
453fcf3ce4John Forte			cmn_err(CE_WARN, "qlt(%d) malformed "
454fcf3ce4John Forte			    "pci-max-read-request in qlt.conf. Valid values "
455fcf3ce4John Forte			    "for this HBA are 512/1024/2048/4096", instance);
456fcf3ce4John Forte			goto over_max_read_xfer_setting;
457fcf3ce4John Forte		}
458c4ddbbeDaniel Beauregard		mr = (uint16_t)PCICFG_RD16(qlt, 0x4E);
459c4ddbbeDaniel Beauregard		mr = (uint16_t)(mr & 0xfff3);
460c4ddbbeDaniel Beauregard		mr = (uint16_t)(mr | (val << 2));
461fcf3ce4John Forte		PCICFG_WR16(qlt, 0x4E, mr);
462c4ddbbeDaniel Beauregard	} else if ((did == 0x2432) || (did == 0x8432) ||
463c4ddbbeDaniel Beauregard	    (did == 0x2532) || (did == 0x8001)) {
464fcf3ce4John Forte		if (max_read_size == 128)
465fcf3ce4John Forte			val = 0;
466fcf3ce4John Forte		else if (max_read_size == 256)
467fcf3ce4John Forte			val = 1;
468fcf3ce4John Forte		else if (max_read_size == 512)
469fcf3ce4John Forte			val = 2;
470fcf3ce4John Forte		else if (max_read_size == 1024)
471fcf3ce4John Forte			val = 3;
472fcf3ce4John Forte		else if (max_read_size == 2048)
473fcf3ce4John Forte			val = 4;
474fcf3ce4John Forte		else if (max_read_size == 4096)
475fcf3ce4John Forte			val = 5;
476fcf3ce4John Forte		else {
477fcf3ce4John Forte			cmn_err(CE_WARN, "qlt(%d) malformed "
478fcf3ce4John Forte			    "pci-max-read-request in qlt.conf. Valid values "
479fcf3ce4John Forte			    "for this HBA are 128/256/512/1024/2048/4096",
480d8c54e3Sam Cramer			    instance);
481fcf3ce4John Forte			goto over_max_read_xfer_setting;
482fcf3ce4John Forte		}
483c4ddbbeDaniel Beauregard		mr = (uint16_t)PCICFG_RD16(qlt, 0x54);
484c4ddbbeDaniel Beauregard		mr = (uint16_t)(mr & 0x8fff);
485c4ddbbeDaniel Beauregard		mr = (uint16_t)(mr | (val << 12));
486fcf3ce4John Forte		PCICFG_WR16(qlt, 0x54, mr);
487fcf3ce4John Forte	} else {
488fcf3ce4John Forte		cmn_err(CE_WARN, "qlt(%d): dont know how to set "
489fcf3ce4John Forte		    "pci-max-read-request for this device (%x)",
490fcf3ce4John Forte		    instance, did);
491fcf3ce4John Forte	}
492fcf3ce4John Forteover_max_read_xfer_setting:;
493fcf3ce4John Forte
494fcf3ce4John Forte	max_payload_size = qlt_read_int_prop(qlt, "pcie-max-payload-size", 11);
495fcf3ce4John Forte	if (max_payload_size == 11)
496fcf3ce4John Forte		goto over_max_payload_setting;
497c4ddbbeDaniel Beauregard	if ((did == 0x2432) || (did == 0x8432) ||
498c4ddbbeDaniel Beauregard	    (did == 0x2532) || (did == 0x8001)) {
499fcf3ce4John Forte		if (max_payload_size == 128)
500fcf3ce4John Forte			val = 0;
501fcf3ce4John Forte		else if (max_payload_size == 256)
502fcf3ce4John Forte			val = 1;
503fcf3ce4John Forte		else if (max_payload_size == 512)
504fcf3ce4John Forte			val = 2;
505fcf3ce4John Forte		else if (max_payload_size == 1024)
506fcf3ce4John Forte			val = 3;
507fcf3ce4John Forte		else {
508fcf3ce4John Forte			cmn_err(CE_WARN, "qlt(%d) malformed "
509fcf3ce4John Forte			    "pcie-max-payload-size in qlt.conf. Valid values "
510fcf3ce4John Forte			    "for this HBA are 128/256/512/1024",
511d8c54e3Sam Cramer			    instance);
512fcf3ce4John Forte			goto over_max_payload_setting;
513fcf3ce4John Forte		}
514c4ddbbeDaniel Beauregard		mr = (uint16_t)PCICFG_RD16(qlt, 0x54);
515c4ddbbeDaniel Beauregard		mr = (uint16_t)(mr & 0xff1f);
516c4ddbbeDaniel Beauregard		mr = (uint16_t)(mr | (val << 5));
517fcf3ce4John Forte		PCICFG_WR16(qlt, 0x54, mr);
518fcf3ce4John Forte	} else {
519fcf3ce4John Forte		cmn_err(CE_WARN, "qlt(%d): dont know how to set "
520fcf3ce4John Forte		    "pcie-max-payload-size for this device (%x)",
521fcf3ce4John Forte		    instance, did);
522fcf3ce4John Forte	}
523fcf3ce4John Forte
524fcf3ce4John Forteover_max_payload_setting:;
525fcf3ce4John Forte
526a2255dfDaniel Beauregard	qlt_enable_intr(qlt);
527a2255dfDaniel Beauregard
528fcf3ce4John Forte	if (qlt_port_start((caddr_t)qlt) != QLT_SUCCESS)
529fcf3ce4John Forte		goto attach_fail_10;
530fcf3ce4John Forte
531fcf3ce4John Forte	ddi_report_dev(dip);
532fcf3ce4John Forte	return (DDI_SUCCESS);
533fcf3ce4John Forte
534fcf3ce4John Forteattach_fail_10:;
535fcf3ce4John Forte	mutex_destroy(&qlt->qlt_ioctl_lock);
536fcf3ce4John Forte	cv_destroy(&qlt->mbox_cv);
537fcf3ce4John Forte	cv_destroy(&qlt->rp_dereg_cv);
538fcf3ce4John Forte	ddi_remove_minor_node(dip, qlt->qlt_minor_name);
539fcf3ce4John Forteattach_fail_9:;
540fcf3ce4John Forte	qlt_destroy_mutex(qlt);
541fcf3ce4John Forte	qlt_release_intr(qlt);
542fcf3ce4John Forteattach_fail_8:;
543fcf3ce4John Forte	(void) ddi_dma_unbind_handle(qlt->queue_mem_dma_handle);
544fcf3ce4John Forteattach_fail_7:;
545fcf3ce4John Forte	ddi_dma_mem_free(&qlt->queue_mem_acc_handle);
546fcf3ce4John Forteattach_fail_6:;
547fcf3ce4John Forte	ddi_dma_free_handle(&qlt->queue_mem_dma_handle);
548fcf3ce4John Forteattach_fail_5:;
549fcf3ce4John Forte	ddi_regs_map_free(&qlt->regs_acc_handle);
550fcf3ce4John Forteattach_fail_4:;
551fcf3ce4John Forte	pci_config_teardown(&qlt->pcicfg_acc_handle);
552fcf3ce4John Forte	kmem_free(qlt->nvram, sizeof (qlt_nvram_t));
553c4ddbbeDaniel Beauregard	(void) qlt_el_trace_desc_dtor(qlt);
554fcf3ce4John Forteattach_fail_2:;
555fcf3ce4John Forteattach_fail_1:;
556fcf3ce4John Forte	ddi_soft_state_free(qlt_state, instance);
557fcf3ce4John Forte	return (DDI_FAILURE);
558fcf3ce4John Forte}
559fcf3ce4John Forte
560fcf3ce4John Forte#define	FCT_I_EVENT_BRING_PORT_OFFLINE	0x83
561fcf3ce4John Forte
562fcf3ce4John Forte/* ARGSUSED */
563fcf3ce4John Fortestatic int
564fcf3ce4John Forteqlt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
565fcf3ce4John Forte{
566fcf3ce4John Forte	qlt_state_t *qlt;
567fcf3ce4John Forte
568fcf3ce4John Forte	int instance;
569fcf3ce4John Forte
570fcf3ce4John Forte	instance = ddi_get_instance(dip);
571c4ddbbeDaniel Beauregard	if ((qlt = (qlt_state_t *)ddi_get_soft_state(qlt_state, instance)) ==
572c4ddbbeDaniel Beauregard	    NULL) {
573fcf3ce4John Forte		return (DDI_FAILURE);
574fcf3ce4John Forte	}
575fcf3ce4John Forte
576fcf3ce4John Forte	if (qlt->fw_code01) {
577fcf3ce4John Forte		return (DDI_FAILURE);
578fcf3ce4John Forte	}
579fcf3ce4John Forte
580fcf3ce4John Forte	if ((qlt->qlt_state != FCT_STATE_OFFLINE) ||
581d8c54e3Sam Cramer	    qlt->qlt_state_not_acked) {
582fcf3ce4John Forte		return (DDI_FAILURE);
583fcf3ce4John Forte	}
584a2255dfDaniel Beauregard	if (qlt_port_stop((caddr_t)qlt) != FCT_SUCCESS) {
585fcf3ce4John Forte		return (DDI_FAILURE);
586a2255dfDaniel Beauregard	}
587a2255dfDaniel Beauregard
588a2255dfDaniel Beauregard	qlt_disable_intr(qlt);
589a2255dfDaniel Beauregard
590fcf3ce4John Forte	ddi_remove_minor_node(dip, qlt->qlt_minor_name);
591fcf3ce4John Forte	qlt_destroy_mutex(qlt);
592fcf3ce4John Forte	qlt_release_intr(qlt);
593fcf3ce4John Forte	(void) ddi_dma_unbind_handle(qlt->queue_mem_dma_handle);
594fcf3ce4John Forte	ddi_dma_mem_free(&qlt->queue_mem_acc_handle);
595fcf3ce4John Forte	ddi_dma_free_handle(&qlt->queue_mem_dma_handle);
596fcf3ce4John Forte	ddi_regs_map_free(&qlt->regs_acc_handle);
597fcf3ce4John Forte	pci_config_teardown(&qlt->pcicfg_acc_handle);
598fcf3ce4John Forte	kmem_free(qlt->nvram, sizeof (qlt_nvram_t));
599fcf3ce4John Forte	cv_destroy(&qlt->mbox_cv);
600fcf3ce4John Forte	cv_destroy(&qlt->rp_dereg_cv);
601c4ddbbeDaniel Beauregard	(void) qlt_el_trace_desc_dtor(qlt);
602fcf3ce4John Forte	ddi_soft_state_free(qlt_state, instance);
603fcf3ce4John Forte
604fcf3ce4John Forte	return (DDI_SUCCESS);
605fcf3ce4John Forte}
606fcf3ce4John Forte
6070ff6bfaDaniel Beauregard/*
6080ff6bfaDaniel Beauregard * qlt_quiesce	quiesce a device attached to the system.
6090ff6bfaDaniel Beauregard */
6100ff6bfaDaniel Beauregardstatic int
6110ff6bfaDaniel Beauregardqlt_quiesce(dev_info_t *dip)
6120ff6bfaDaniel Beauregard{
6130ff6bfaDaniel Beauregard	qlt_state_t	*qlt;
6140ff6bfaDaniel Beauregard	uint32_t	timer;
6150ff6bfaDaniel Beauregard	uint32_t	stat;
6160ff6bfaDaniel Beauregard
6170ff6bfaDaniel Beauregard	qlt = ddi_get_soft_state(qlt_state, ddi_get_instance(dip));
6180ff6bfaDaniel Beauregard	if (qlt == NULL) {
6190ff6bfaDaniel Beauregard		/* Oh well.... */
6200ff6bfaDaniel Beauregard		return (DDI_SUCCESS);
6210ff6bfaDaniel Beauregard	}
6220ff6bfaDaniel Beauregard
623a2255dfDaniel Beauregard	REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_HOST_TO_RISC_INTR));
6240ff6bfaDaniel Beauregard	REG_WR16(qlt, REG_MBOX0, MBC_STOP_FIRMWARE);
625a2255dfDaniel Beauregard	REG_WR32(qlt, REG_HCCR, HCCR_CMD(SET_HOST_TO_RISC_INTR));
6260ff6bfaDaniel Beauregard	for (timer = 0; timer < 30000; timer++) {
6270ff6bfaDaniel Beauregard		stat = REG_RD32(qlt, REG_RISC_STATUS);
6280ff6bfaDaniel Beauregard		if (stat & RISC_HOST_INTR_REQUEST) {
6290ff6bfaDaniel Beauregard			if ((stat & FW_INTR_STATUS_MASK) < 0x12) {
6300ff6bfaDaniel Beauregard				REG_WR32(qlt, REG_HCCR,
631a2255dfDaniel Beauregard				    HCCR_CMD(CLEAR_RISC_PAUSE));
6320ff6bfaDaniel Beauregard				break;
6330ff6bfaDaniel Beauregard			}
6340ff6bfaDaniel Beauregard			REG_WR32(qlt, REG_HCCR,
635a2255dfDaniel Beauregard			    HCCR_CMD(CLEAR_HOST_TO_RISC_INTR));
6360ff6bfaDaniel Beauregard		}
6370ff6bfaDaniel Beauregard		drv_usecwait(100);
6380ff6bfaDaniel Beauregard	}
6390ff6bfaDaniel Beauregard	/* Reset the chip. */
6400ff6bfaDaniel Beauregard	REG_WR32(qlt, REG_CTRL_STATUS, CHIP_SOFT_RESET | DMA_SHUTDOWN_CTRL |
6410ff6bfaDaniel Beauregard	    PCI_X_XFER_CTRL);
6420ff6bfaDaniel Beauregard	drv_usecwait(100);
6430ff6bfaDaniel Beauregard
644a2255dfDaniel Beauregard	qlt_disable_intr(qlt);
645a2255dfDaniel Beauregard
6460ff6bfaDaniel Beauregard	return (DDI_SUCCESS);
6470ff6bfaDaniel Beauregard}
6480ff6bfaDaniel Beauregard
649fcf3ce4John Fortestatic void
650fcf3ce4John Forteqlt_enable_intr(qlt_state_t *qlt)
651fcf3ce4John Forte{
652fcf3ce4John Forte	if (qlt->intr_cap & DDI_INTR_FLAG_BLOCK) {
653fcf3ce4John Forte		(void) ddi_intr_block_enable(qlt->htable, qlt->intr_cnt);
654fcf3ce4John Forte	} else {
655fcf3ce4John Forte		int i;
656fcf3ce4John Forte		for (i = 0; i < qlt->intr_cnt; i++)
657fcf3ce4John Forte			(void) ddi_intr_enable(qlt->htable[i]);
658fcf3ce4John Forte	}
659a2255dfDaniel Beauregard	qlt->qlt_intr_enabled = 1;
660fcf3ce4John Forte}
661fcf3ce4John Forte
662fcf3ce4John Fortestatic void
663fcf3ce4John Forteqlt_disable_intr(qlt_state_t *qlt)
664fcf3ce4John Forte{
665fcf3ce4John Forte	if (qlt->intr_cap & DDI_INTR_FLAG_BLOCK) {
666fcf3ce4John Forte		(void) ddi_intr_block_disable(qlt->htable, qlt->intr_cnt);
667fcf3ce4John Forte	} else {
668fcf3ce4John Forte		int i;
669fcf3ce4John Forte		for (i = 0; i < qlt->intr_cnt; i++)
670fcf3ce4John Forte			(void) ddi_intr_disable(qlt->htable[i]);
671fcf3ce4John Forte	}
672a2255dfDaniel Beauregard	qlt->qlt_intr_enabled = 0;
673fcf3ce4John Forte}
674fcf3ce4John Forte
675fcf3ce4John Fortestatic void
676fcf3ce4John Forteqlt_release_intr(qlt_state_t *qlt)
677fcf3ce4John Forte{
678fcf3ce4John Forte	if (qlt->htable) {
679fcf3ce4John Forte		int i;
680fcf3ce4John Forte		for (i = 0; i < qlt->intr_cnt; i++) {
681fcf3ce4John Forte			(void) ddi_intr_remove_handler(qlt->htable[i]);
682fcf3ce4John Forte			(void) ddi_intr_free(qlt->htable[i]);
683fcf3ce4John Forte		}
684c4ddbbeDaniel Beauregard		kmem_free(qlt->htable, (uint_t)qlt->intr_size);
685fcf3ce4John Forte	}
686fcf3ce4John Forte	qlt->htable = NULL;
687fcf3ce4John Forte	qlt->intr_pri = 0;
688fcf3ce4John Forte	qlt->intr_cnt = 0;
689fcf3ce4John Forte	qlt->intr_size = 0;
690fcf3ce4John Forte	qlt->intr_cap = 0;
691fcf3ce4John Forte}
692fcf3ce4John Forte
693fcf3ce4John Forte
694fcf3ce4John Fortestatic void
695fcf3ce4John Forteqlt_init_mutex(qlt_state_t *qlt)
696fcf3ce4John Forte{
697fcf3ce4John Forte	mutex_init(&qlt->req_lock, 0, MUTEX_DRIVER,
698fcf3ce4John Forte	    INT2PTR(qlt->intr_pri, void *));
699fcf3ce4John Forte	mutex_init(&qlt->preq_lock, 0, MUTEX_DRIVER,
700fcf3ce4John Forte	    INT2PTR(qlt->intr_pri, void *));
701fcf3ce4John Forte	mutex_init(&qlt->mbox_lock, NULL, MUTEX_DRIVER,
702fcf3ce4John Forte	    INT2PTR(qlt->intr_pri, void *));
703fcf3ce4John Forte	mutex_init(&qlt->intr_lock, NULL, MUTEX_DRIVER,
704fcf3ce4John Forte	    INT2PTR(qlt->intr_pri, void *));
705fcf3ce4John Forte}
706fcf3ce4John Forte
707fcf3ce4John Fortestatic void
708fcf3ce4John Forteqlt_destroy_mutex(qlt_state_t *qlt)
709fcf3ce4John Forte{
710fcf3ce4John Forte	mutex_destroy(&qlt->req_lock);
711fcf3ce4John Forte	mutex_destroy(&qlt->preq_lock);
712fcf3ce4John Forte	mutex_destroy(&qlt->mbox_lock);
713fcf3ce4John Forte	mutex_destroy(&qlt->intr_lock);
714fcf3ce4John Forte}
715fcf3ce4John Forte
716fcf3ce4John Forte
717fcf3ce4John Fortestatic int
718fcf3ce4John Forteqlt_setup_msix(qlt_state_t *qlt)
719fcf3ce4John Forte{
720fcf3ce4John Forte	int count, avail, actual;
721fcf3ce4John Forte	int ret;
722fcf3ce4John Forte	int itype = DDI_INTR_TYPE_MSIX;
723fcf3ce4John Forte	int i;
724fcf3ce4John Forte
725fcf3ce4John Forte	ret = ddi_intr_get_nintrs(qlt->dip, itype, &count);
726fcf3ce4John Forte	if (ret != DDI_SUCCESS || count == 0) {
727c4ddbbeDaniel Beauregard		EL(qlt, "ddi_intr_get_nintrs status=%xh, count=%d\n", ret,
728c4ddbbeDaniel Beauregard		    count);
729fcf3ce4John Forte		return (DDI_FAILURE);
730fcf3ce4John Forte	}
731fcf3ce4John Forte	ret = ddi_intr_get_navail(qlt->dip, itype, &avail);
732fcf3ce4John Forte	if (ret != DDI_SUCCESS || avail == 0) {
733c4ddbbeDaniel Beauregard		EL(qlt, "ddi_intr_get_navail status=%xh, avail=%d\n", ret,
734c4ddbbeDaniel Beauregard		    avail);
735fcf3ce4John Forte		return (DDI_FAILURE);
736fcf3ce4John Forte	}
737fcf3ce4John Forte	if (avail < count) {
738fcf3ce4John Forte		stmf_trace(qlt->qlt_port_alias,
739fcf3ce4John Forte		    "qlt_setup_msix: nintrs=%d,avail=%d", count, avail);
740fcf3ce4John Forte	}
741fcf3ce4John Forte
742c4ddbbeDaniel Beauregard	qlt->intr_size = (int)(count * (int)sizeof (ddi_intr_handle_t));
743c4ddbbeDaniel Beauregard	qlt->htable = kmem_zalloc((uint_t)qlt->intr_size, KM_SLEEP);
744fcf3ce4John Forte	ret = ddi_intr_alloc(qlt->dip, qlt->htable, itype,
745fcf3ce4John Forte	    DDI_INTR_ALLOC_NORMAL, count, &actual, 0);
746fcf3ce4John Forte	/* we need at least 2 interrupt vectors */
747fcf3ce4John Forte	if (ret != DDI_SUCCESS || actual < 2) {
748c4ddbbeDaniel Beauregard		EL(qlt, "ddi_intr_alloc status=%xh, actual=%d\n", ret,
749c4ddbbeDaniel Beauregard		    actual);
750fcf3ce4John Forte		ret = DDI_FAILURE;
751fcf3ce4John Forte		goto release_intr;
752fcf3ce4John Forte	}
753fcf3ce4John Forte	if (actual < count) {
754c4ddbbeDaniel Beauregard		EL(qlt, "requested: %d, received: %d\n", count, actual);
755fcf3ce4John Forte	}
756fcf3ce4John Forte
757fcf3ce4John Forte	qlt->intr_cnt = actual;
758fcf3ce4John Forte	ret =  ddi_intr_get_pri(qlt->htable[0], &qlt->intr_pri);
759fcf3ce4John Forte	if (ret != DDI_SUCCESS) {
760c4ddbbeDaniel Beauregard		EL(qlt, "ddi_intr_get_pri status=%xh\n", ret);
761fcf3ce4John Forte		ret = DDI_FAILURE;
762fcf3ce4John Forte		goto release_intr;
763fcf3ce4John Forte	}
764fcf3ce4John Forte	qlt_init_mutex(qlt);
765fcf3ce4John Forte	for (i = 0; i < actual; i++) {
766fcf3ce4John Forte		ret = ddi_intr_add_handler(qlt->htable[i], qlt_isr,
767c4ddbbeDaniel Beauregard		    qlt, INT2PTR((uint_t)i, void *));
768c4ddbbeDaniel Beauregard		if (ret != DDI_SUCCESS) {
769c4ddbbeDaniel Beauregard			EL(qlt, "ddi_intr_add_handler status=%xh\n", ret);
770fcf3ce4John Forte			goto release_mutex;
771c4ddbbeDaniel Beauregard		}
772fcf3ce4John Forte	}
773fcf3ce4John Forte
774fcf3ce4John Forte	(void) ddi_intr_get_cap(qlt->htable[0], &qlt->intr_cap);
775fcf3ce4John Forte	qlt->intr_flags |= QLT_INTR_MSIX;
776fcf3ce4John Forte	return (DDI_SUCCESS);
777fcf3ce4John Forte
778fcf3ce4John Forterelease_mutex:
779fcf3ce4John Forte	qlt_destroy_mutex(qlt);
780fcf3ce4John Forterelease_intr:
781fcf3ce4John Forte	for (i = 0; i < actual; i++)
782fcf3ce4John Forte		(void) ddi_intr_free(qlt->htable[i]);
783c4ddbbeDaniel Beauregard#if 0
784fcf3ce4John Fortefree_mem:
785c4ddbbeDaniel Beauregard#endif
786c4ddbbeDaniel Beauregard	kmem_free(qlt->htable, (uint_t)qlt->intr_size);
787fcf3ce4John Forte	qlt->htable = NULL;
788fcf3ce4John Forte	qlt_release_intr(qlt);
789fcf3ce4John Forte	return (ret);
790fcf3ce4John Forte}
791fcf3ce4John Forte
792fcf3ce4John Forte
793fcf3ce4John Fortestatic int
794fcf3ce4John Forteqlt_setup_msi(qlt_state_t *qlt)
795fcf3ce4John Forte{
796fcf3ce4John Forte	int count, avail, actual;
797fcf3ce4John Forte	int itype = DDI_INTR_TYPE_MSI;
798fcf3ce4John Forte	int ret;
799fcf3ce4John Forte	int i;
800fcf3ce4John Forte
801fcf3ce4John Forte	/* get the # of interrupts */
802fcf3ce4John Forte	ret = ddi_intr_get_nintrs(qlt->dip, itype, &count);
803fcf3ce4John Forte	if (ret != DDI_SUCCESS || count == 0) {
804c4ddbbeDaniel Beauregard		EL(qlt, "ddi_intr_get_nintrs status=%xh, count=%d\n", ret,
805c4ddbbeDaniel Beauregard		    count);
806fcf3ce4John Forte		return (DDI_FAILURE);
807fcf3ce4John Forte	}
808fcf3ce4John Forte	ret = ddi_intr_get_navail(qlt->dip, itype, &avail);
809fcf3ce4John Forte	if (ret != DDI_SUCCESS || avail == 0) {
810c4ddbbeDaniel Beauregard		EL(qlt, "ddi_intr_get_navail status=%xh, avail=%d\n", ret,
811c4ddbbeDaniel Beauregard		    avail);
812fcf3ce4John Forte		return (DDI_FAILURE);
813fcf3ce4John Forte	}
814fcf3ce4John Forte	if (avail < count) {
815c4ddbbeDaniel Beauregard		EL(qlt, "nintrs=%d, avail=%d\n", count, avail);
816fcf3ce4John Forte	}
817fcf3ce4John Forte	/* MSI requires only 1 interrupt. */
818fcf3ce4John Forte	count = 1;
819fcf3ce4John Forte
820fcf3ce4John Forte	/* allocate interrupt */
821c4ddbbeDaniel Beauregard	qlt->intr_size = (int)(count * (int)sizeof (ddi_intr_handle_t));
822c4ddbbeDaniel Beauregard	qlt->htable = kmem_zalloc((uint_t)qlt->intr_size, KM_SLEEP);
823fcf3ce4John Forte	ret = ddi_intr_alloc(qlt->dip, qlt->htable, itype,
824fcf3ce4John Forte	    0, count, &actual, DDI_INTR_ALLOC_NORMAL);
825fcf3ce4John Forte	if (ret != DDI_SUCCESS || actual == 0) {
826c4ddbbeDaniel Beauregard		EL(qlt, "ddi_intr_alloc status=%xh, actual=%d\n", ret,
827c4ddbbeDaniel Beauregard		    actual);
828fcf3ce4John Forte		ret = DDI_FAILURE;
829fcf3ce4John Forte		goto free_mem;
830fcf3ce4John Forte	}
831fcf3ce4John Forte	if (actual < count) {
832c4ddbbeDaniel Beauregard		EL(qlt, "requested: %d, received: %d\n", count, actual);
833fcf3ce4John Forte	}
834fcf3ce4John Forte	qlt->intr_cnt = actual;
835fcf3ce4John Forte
836fcf3ce4John Forte	/*
837fcf3ce4John Forte	 * Get priority for first msi, assume remaining are all the same.
838fcf3ce4John Forte	 */
839fcf3ce4John Forte	ret =  ddi_intr_get_pri(qlt->htable[0], &qlt->intr_pri);
840fcf3ce4John Forte	if (ret != DDI_SUCCESS) {
841c4ddbbeDaniel Beauregard		EL(qlt, "ddi_intr_get_pri status=%xh\n", ret);
842fcf3ce4John Forte		ret = DDI_FAILURE;
843fcf3ce4John Forte		goto release_intr;
844fcf3ce4John Forte	}
845fcf3ce4John Forte	qlt_init_mutex(qlt);
846fcf3ce4John Forte
847fcf3ce4John Forte	/* add handler */
848fcf3ce4John Forte	for (i = 0; i < actual; i++) {
849fcf3ce4John Forte		ret = ddi_intr_add_handler(qlt->htable[i], qlt_isr,
850c4ddbbeDaniel Beauregard		    qlt, INT2PTR((uint_t)i, void *));
851c4ddbbeDaniel Beauregard		if (ret != DDI_SUCCESS) {
852c4ddbbeDaniel Beauregard			EL(qlt, "ddi_intr_add_handler status=%xh\n", ret);
853fcf3ce4John Forte			goto release_mutex;
854c4ddbbeDaniel Beauregard		}
855fcf3ce4John Forte	}
856fcf3ce4John Forte
857fcf3ce4John Forte	(void) ddi_intr_get_cap(qlt->htable[0], &qlt->intr_cap);
858fcf3ce4John Forte	qlt->intr_flags |= QLT_INTR_MSI;
859fcf3ce4John Forte	return (DDI_SUCCESS);
860fcf3ce4John Forte
861fcf3ce4John Forterelease_mutex:
862fcf3ce4John Forte	qlt_destroy_mutex(qlt);
863fcf3ce4John Forterelease_intr:
864fcf3ce4John Forte	for (i = 0; i < actual; i++)
865fcf3ce4John Forte		(void) ddi_intr_free(qlt->htable[i]);
866fcf3ce4John Fortefree_mem:
867c4ddbbeDaniel Beauregard	kmem_free(qlt->htable, (uint_t)qlt->intr_size);
868fcf3ce4John Forte	qlt->htable = NULL;
869fcf3ce4John Forte	qlt_release_intr(qlt);
870fcf3ce4John Forte	return (ret);
871fcf3ce4John Forte}
872fcf3ce4John Forte
873fcf3ce4John Fortestatic int
874fcf3ce4John Forteqlt_setup_fixed(qlt_state_t *qlt)
875fcf3ce4John Forte{
876fcf3ce4John Forte	int count;
877fcf3ce4John Forte	int actual;
878fcf3ce4John Forte	int ret;
879fcf3ce4John Forte	int itype = DDI_INTR_TYPE_FIXED;
880fcf3ce4John Forte
881fcf3ce4John Forte	ret = ddi_intr_get_nintrs(qlt->dip, itype, &count);
882fcf3ce4John Forte	/* Fixed interrupts can only have one interrupt. */
883fcf3ce4John Forte	if (ret != DDI_SUCCESS || count != 1) {
884c4ddbbeDaniel Beauregard		EL(qlt, "ddi_intr_get_nintrs status=%xh, count=%d\n", ret,
885c4ddbbeDaniel Beauregard		    count);
886fcf3ce4John Forte		return (DDI_FAILURE);
887fcf3ce4John Forte	}
888fcf3ce4John Forte
889fcf3ce4John Forte	qlt->intr_size = sizeof (ddi_intr_handle_t);
890c4ddbbeDaniel Beauregard	qlt->htable = kmem_zalloc((uint_t)qlt->intr_size, KM_SLEEP);
891fcf3ce4John Forte	ret = ddi_intr_alloc(qlt->dip, qlt->htable, itype,
892fcf3ce4John Forte	    DDI_INTR_ALLOC_NORMAL, count, &actual, 0);
893fcf3ce4John Forte	if (ret != DDI_SUCCESS || actual != 1) {
894c4ddbbeDaniel Beauregard		EL(qlt, "ddi_intr_alloc status=%xh, actual=%d\n", ret,
895c4ddbbeDaniel Beauregard		    actual);
896fcf3ce4John Forte		ret = DDI_FAILURE;
897fcf3ce4John Forte		goto free_mem;
898fcf3ce4John Forte	}
899fcf3ce4John Forte
900fcf3ce4John Forte	qlt->intr_cnt = actual;
901fcf3ce4John Forte	ret =  ddi_intr_get_pri(qlt->htable[0], &qlt->intr_pri);
902fcf3ce4John Forte	if (ret != DDI_SUCCESS) {
903c4ddbbeDaniel Beauregard		EL(qlt, "ddi_intr_get_pri status=%xh\n", ret);
904fcf3ce4John Forte		ret = DDI_FAILURE;
905fcf3ce4John Forte		goto release_intr;
906fcf3ce4John Forte	}
907fcf3ce4John Forte	qlt_init_mutex(qlt);
908fcf3ce4John Forte	ret = ddi_intr_add_handler(qlt->htable[0], qlt_isr, qlt, 0);
909c4ddbbeDaniel Beauregard	if (ret != DDI_SUCCESS) {
910c4ddbbeDaniel Beauregard		EL(qlt, "ddi_intr_add_handler status=%xh\n", ret);
911fcf3ce4John Forte		goto release_mutex;
912c4ddbbeDaniel Beauregard	}
913fcf3ce4John Forte
914fcf3ce4John Forte	qlt->intr_flags |= QLT_INTR_FIXED;
915fcf3ce4John Forte	return (DDI_SUCCESS);
916fcf3ce4John Forte
917fcf3ce4John Forterelease_mutex:
918fcf3ce4John Forte	qlt_destroy_mutex(qlt);
919fcf3ce4John Forterelease_intr:
920fcf3ce4John Forte	(void) ddi_intr_free(qlt->htable[0]);
921fcf3ce4John Fortefree_mem:
922c4ddbbeDaniel Beauregard	kmem_free(qlt->htable, (uint_t)qlt->intr_size);
923fcf3ce4John Forte	qlt->htable = NULL;
924fcf3ce4John Forte	qlt_release_intr(qlt);
925fcf3ce4John Forte	return (ret);
926fcf3ce4John Forte}
927fcf3ce4John Forte
928fcf3ce4John Fortestatic int
929fcf3ce4John Forteqlt_setup_interrupts(qlt_state_t *qlt)
930fcf3ce4John Forte{
931fcf3ce4John Forte	int itypes = 0;
932fcf3ce4John Forte
933fcf3ce4John Forte/*
934a2255dfDaniel Beauregard * x86 has a bug in the ddi_intr_block_enable/disable area (6562198).
935fcf3ce4John Forte */
936a2255dfDaniel Beauregard#ifndef __sparc
937a2255dfDaniel Beauregard	if (qlt_enable_msi != 0) {
938a2255dfDaniel Beauregard#endif
939fcf3ce4John Forte	if (ddi_intr_get_supported_types(qlt->dip, &itypes) != DDI_SUCCESS) {
940fcf3ce4John Forte		itypes = DDI_INTR_TYPE_FIXED;
941fcf3ce4John Forte	}
942fcf3ce4John Forte
943fcf3ce4John Forte	if (qlt_enable_msix && (itypes & DDI_INTR_TYPE_MSIX)) {
944fcf3ce4John Forte		if (qlt_setup_msix(qlt) == DDI_SUCCESS)
945fcf3ce4John Forte			return (DDI_SUCCESS);
946fcf3ce4John Forte	}
947a2255dfDaniel Beauregard
948fcf3ce4John Forte	if (itypes & DDI_INTR_TYPE_MSI) {
949fcf3ce4John Forte		if (qlt_setup_msi(qlt) == DDI_SUCCESS)
950fcf3ce4John Forte			return (DDI_SUCCESS);
951fcf3ce4John Forte	}
952a2255dfDaniel Beauregard#ifndef __sparc
953a2255dfDaniel Beauregard	}
954fcf3ce4John Forte#endif
955fcf3ce4John Forte	return (qlt_setup_fixed(qlt));
956fcf3ce4John Forte}
957fcf3ce4John Forte
958fcf3ce4John Forte/*
959fcf3ce4John Forte * Filling the hba attributes
960fcf3ce4John Forte */
961fcf3ce4John Fortevoid
962fcf3ce4John Forteqlt_populate_hba_fru_details(struct fct_local_port *port,
963fcf3ce4John Forte    struct fct_port_attrs *port_attrs)
964fcf3ce4John Forte{
965fcf3ce4John Forte	caddr_t	bufp;
966fcf3ce4John Forte	int len;
967fcf3ce4John Forte	qlt_state_t *qlt = (qlt_state_t *)port->port_fca_private;
968fcf3ce4John Forte
969fcf3ce4John Forte	(void) snprintf(port_attrs->manufacturer, FCHBA_MANUFACTURER_LEN,
970fcf3ce4John Forte	    "QLogic Corp.");
971fcf3ce4John Forte	(void) snprintf(port_attrs->driver_name, FCHBA_DRIVER_NAME_LEN,
972fcf3ce4John Forte	    "%s", QLT_NAME);
973fcf3ce4John Forte	(void) snprintf(port_attrs->driver_version, FCHBA_DRIVER_VERSION_LEN,
974fcf3ce4John Forte	    "%s", QLT_VERSION);
975fcf3ce4John Forte	port_attrs->serial_number[0] = '\0';
976fcf3ce4John Forte	port_attrs->hardware_version[0] = '\0';
977fcf3ce4John Forte
978fcf3ce4John Forte	(void) snprintf(port_attrs->firmware_version,
979fcf3ce4John Forte	    FCHBA_FIRMWARE_VERSION_LEN, "%d.%d.%d", qlt->fw_major,
980fcf3ce4John Forte	    qlt->fw_minor, qlt->fw_subminor);
981fcf3ce4John Forte
982fcf3ce4John Forte	/* Get FCode version */
983fcf3ce4John Forte	if (ddi_getlongprop(DDI_DEV_T_ANY, qlt->dip, PROP_LEN_AND_VAL_ALLOC |
984fcf3ce4John Forte	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "version", (caddr_t)&bufp,
985fcf3ce4John Forte	    (int *)&len) == DDI_PROP_SUCCESS) {
986fcf3ce4John Forte		(void) snprintf(port_attrs->option_rom_version,
987fcf3ce4John Forte		    FCHBA_OPTION_ROM_VERSION_LEN, "%s", bufp);
988c4ddbbeDaniel Beauregard		kmem_free(bufp, (uint_t)len);
989fcf3ce4John Forte		bufp = NULL;
990fcf3ce4John Forte	} else {
991fcf3ce4John Forte#ifdef __sparc
992c4ddbbeDaniel Beauregard		(void) snprintf(port_attrs->option_rom_version,
993c4ddbbeDaniel Beauregard		    FCHBA_OPTION_ROM_VERSION_LEN, "No Fcode found");
994fcf3ce4John Forte#else
995564a03cjmcp		(void) snprintf(port_attrs->option_rom_version,
996c4ddbbeDaniel Beauregard		    FCHBA_OPTION_ROM_VERSION_LEN, "N/A");
997c4ddbbeDaniel Beauregard#endif
998fcf3ce4John Forte	}
999fcf3ce4John Forte	port_attrs->vendor_specific_id = qlt->nvram->subsystem_vendor_id[0] |
1000fcf3ce4John Forte	    qlt->nvram->subsystem_vendor_id[1] << 8;
1001fcf3ce4John Forte
1002fcf3ce4John Forte	port_attrs->max_frame_size = qlt->nvram->max_frame_length[1] << 8 |
1003fcf3ce4John Forte	    qlt->nvram->max_frame_length[0];
1004fcf3ce4John Forte
1005fcf3ce4John Forte	port_attrs->supported_cos = 0x10000000;
1006fcf3ce4John Forte	port_attrs->supported_speed = PORT_SPEED_1G |
1007fcf3ce4John Forte	    PORT_SPEED_2G | PORT_SPEED_4G;
1008fcf3ce4John Forte	if (qlt->qlt_25xx_chip)
10093fb517fJames Moore		port_attrs->supported_speed = PORT_SPEED_2G | PORT_SPEED_4G |
10103fb517fJames Moore		    PORT_SPEED_8G;
1011c4ddbbeDaniel Beauregard	if (qlt->qlt_81xx_chip)
1012c4ddbbeDaniel Beauregard		port_attrs->supported_speed = PORT_SPEED_10G;
1013c4ddbbeDaniel Beauregard
1014c4ddbbeDaniel Beauregard	/* limit string length to nvr model_name length */
1015c4ddbbeDaniel Beauregard	len = (qlt->qlt_81xx_chip) ? 16 : 8;
1016c4ddbbeDaniel Beauregard	(void) snprintf(port_attrs->model,
1017c4ddbbeDaniel Beauregard	    (uint_t)(len < FCHBA_MODEL_LEN ? len : FCHBA_MODEL_LEN),
1018c4ddbbeDaniel Beauregard	    "%s", qlt->nvram->model_name);
1019fcf3ce4John Forte
1020fcf3ce4John Forte	(void) snprintf(port_attrs->model_description,
1021c4ddbbeDaniel Beauregard	    (uint_t)(len < FCHBA_MODEL_DESCRIPTION_LEN ? len :
1022c4ddbbeDaniel Beauregard	    FCHBA_MODEL_DESCRIPTION_LEN),
1023c4ddbbeDaniel Beauregard	    "%s", qlt->nvram->model_name);
1024fcf3ce4John Forte}
1025fcf3ce4John Forte
1026c946facallan/* ARGSUSED */
1027c946facallanfct_status_t
1028c946facallanqlt_info(uint32_t cmd, fct_local_port_t *port,
1029c946facallan    void *arg, uint8_t *buf, uint32_t *bufsizep)
1030c946facallan{
1031c946facallan	qlt_state_t	*qlt = (qlt_state_t *)port->port_fca_private;
1032c946facallan	mbox_cmd_t	*mcp;
1033c946facallan	fct_status_t	ret = FCT_SUCCESS;
1034c946facallan	uint8_t		*p;
1035c946facallan	fct_port_link_status_t	*link_status;
1036c946facallan
1037c946facallan	switch (cmd) {
1038c946facallan	case FC_TGT_PORT_RLS:
1039c946facallan		if ((*bufsizep) < sizeof (fct_port_link_status_t)) {
1040c4ddbbeDaniel Beauregard			EL(qlt, "FC_TGT_PORT_RLS bufsizep=%xh < "
1041c4ddbbeDaniel Beauregard			    "fct_port_link_status_t=%xh\n", *bufsizep,
1042c4ddbbeDaniel Beauregard			    sizeof (fct_port_link_status_t));
1043c946facallan			ret = FCT_FAILURE;
1044c946facallan			break;
1045c946facallan		}
1046c946facallan		/* send mailbox command to get link status */
1047c946facallan		mcp = qlt_alloc_mailbox_command(qlt, 156);
1048c946facallan		if (mcp == NULL) {
1049c4ddbbeDaniel Beauregard			EL(qlt, "qlt_alloc_mailbox_command mcp=null\n");
1050c946facallan			ret = FCT_ALLOC_FAILURE;
1051c946facallan			break;
1052c946facallan		}
1053c946facallan
1054c946facallan		/* GET LINK STATUS count */
1055a2255dfDaniel Beauregard		mcp->to_fw[0] = MBC_GET_STATUS_COUNTS;
1056c946facallan		mcp->to_fw[8] = 156/4;
1057c946facallan		mcp->to_fw_mask |= BIT_1 | BIT_8;
1058c946facallan		mcp->from_fw_mask |= BIT_1 | BIT_2;
1059c946facallan
1060c946facallan		ret = qlt_mailbox_command(qlt, mcp);
1061c946facallan		if (ret != QLT_SUCCESS) {
1062c4ddbbeDaniel Beauregard			EL(qlt, "qlt_mailbox_command=6dh status=%llxh\n", ret);
1063c946facallan			qlt_free_mailbox_command(qlt, mcp);
1064c946facallan			break;
1065c946facallan		}
1066c946facallan		qlt_dmem_dma_sync(mcp->dbuf, DDI_DMA_SYNC_FORCPU);
1067c946facallan
1068c946facallan		p = mcp->dbuf->db_sglist[0].seg_addr;
1069c946facallan		link_status = (fct_port_link_status_t *)buf;
1070c946facallan		link_status->LinkFailureCount = LE_32(*((uint32_t *)p));
1071c946facallan		link_status->LossOfSyncCount = LE_32(*((uint32_t *)(p + 4)));
1072c946facallan		link_status->LossOfSignalsCount = LE_32(*((uint32_t *)(p + 8)));
1073c946facallan		link_status->PrimitiveSeqProtocolErrorCount =
1074c946facallan		    LE_32(*((uint32_t *)(p + 12)));
1075c946facallan		link_status->InvalidTransmissionWordCount =
1076c946facallan		    LE_32(*((uint32_t *)(p + 16)));
1077c946facallan		link_status->InvalidCRCCount =
1078c946facallan		    LE_32(*((uint32_t *)(p + 20)));
1079c946facallan
1080c946facallan		qlt_free_mailbox_command(qlt, mcp);
1081c946facallan		break;
1082c946facallan	default:
1083c4ddbbeDaniel Beauregard		EL(qlt, "Unknown cmd=%xh\n", cmd);
1084c946facallan		ret = FCT_FAILURE;
1085c946facallan		break;
1086c946facallan	}
1087c946facallan	return (ret);
1088c946facallan}
1089c946facallan
1090fcf3ce4John Fortefct_status_t
1091fcf3ce4John Forteqlt_port_start(caddr_t arg)
1092fcf3ce4John Forte{
1093fcf3ce4John Forte	qlt_state_t *qlt = (qlt_state_t *)arg;
1094fcf3ce4John Forte	fct_local_port_t *port;
1095fcf3ce4John Forte	fct_dbuf_store_t *fds;
1096c4ddbbeDaniel Beauregard	fct_status_t ret;
1097fcf3ce4John Forte
1098fcf3ce4John Forte	if (qlt_dmem_init(qlt) != QLT_SUCCESS) {
1099fcf3ce4John Forte		return (FCT_FAILURE);
1100fcf3ce4John Forte	}
11013fb517fJames Moore	/* Initialize the ddi_dma_handle free pool */
11023fb517fJames Moore	qlt_dma_handle_pool_init(qlt);
11033fb517fJames Moore
1104fcf3ce4John Forte	port = (fct_local_port_t *)fct_alloc(FCT_STRUCT_LOCAL_PORT, 0, 0);
1105fcf3ce4John Forte	if (port == NULL) {
1106fcf3ce4John Forte		goto qlt_pstart_fail_1;
1107fcf3ce4John Forte	}
1108fcf3ce4John Forte	fds = (fct_dbuf_store_t *)fct_alloc(FCT_STRUCT_DBUF_STORE, 0, 0);
1109fcf3ce4John Forte	if (fds == NULL) {
1110fcf3ce4John Forte		goto qlt_pstart_fail_2;
1111fcf3ce4John Forte	}
1112fcf3ce4John Forte	qlt->qlt_port = port;
1113fcf3ce4John Forte	fds->fds_alloc_data_buf = qlt_dmem_alloc;
1114fcf3ce4John Forte	fds->fds_free_data_buf = qlt_dmem_free;
11153fb517fJames Moore	fds->fds_setup_dbuf = qlt_dma_setup_dbuf;
11163fb517fJames Moore	fds->fds_teardown_dbuf = qlt_dma_teardown_dbuf;
11173fb517fJames Moore	fds->fds_max_sgl_xfer_len = QLT_DMA_SG_LIST_LENGTH * MMU_PAGESIZE;
11183fb517fJames Moore	fds->fds_copy_threshold = MMU_PAGESIZE;
1119fcf3ce4John Forte	fds->fds_fca_private = (void *)qlt;
1120fcf3ce4John Forte	/*
1121fcf3ce4John Forte	 * Since we keep everything in the state struct and dont allocate any
1122fcf3ce4John Forte	 * port private area, just use that pointer to point to the
1123fcf3ce4John Forte	 * state struct.
1124fcf3ce4John Forte	 */
1125fcf3ce4John Forte	port->port_fca_private = qlt;
1126fcf3ce4John Forte	port->port_fca_abort_timeout = 5 * 1000;	/* 5 seconds */
1127fcf3ce4John Forte	bcopy(qlt->nvram->node_name, port->port_nwwn, 8);
1128fcf3ce4John Forte	bcopy(qlt->nvram->port_name, port->port_pwwn, 8);
1129d8c54e3Sam Cramer	fct_wwn_to_str(port->port_nwwn_str, port->port_nwwn);
1130d8c54e3Sam Cramer	fct_wwn_to_str(port->port_pwwn_str, port->port_pwwn);
1131fcf3ce4John Forte	port->port_default_alias = qlt->qlt_port_alias;
1132fcf3ce4John Forte	port->port_pp = qlt_pp;
1133fcf3ce4John Forte	port->port_fds = fds;
1134fcf3ce4John Forte	port->port_max_logins = QLT_MAX_LOGINS;
1135fcf3ce4John Forte	port->port_max_xchges = QLT_MAX_XCHGES;
1136fcf3ce4John Forte	port->port_fca_fcp_cmd_size = sizeof (qlt_cmd_t);
1137fcf3ce4John Forte	port->port_fca_rp_private_size = sizeof (qlt_remote_port_t);
1138fcf3ce4John Forte	port->port_fca_sol_els_private_size = sizeof (qlt_cmd_t);
1139fcf3ce4John Forte	port->port_fca_sol_ct_private_size = sizeof (qlt_cmd_t);
1140fcf3ce4John Forte	port->port_get_link_info = qlt_get_link_info;
1141fcf3ce4John Forte	port->port_register_remote_port = qlt_register_remote_port;
1142fcf3ce4John Forte	port->port_deregister_remote_port = qlt_deregister_remote_port;
1143fcf3ce4John Forte	port->port_send_cmd = qlt_send_cmd;
1144fcf3ce4John Forte	port->port_xfer_scsi_data = qlt_xfer_scsi_data;
1145fcf3ce4John Forte	port->port_send_cmd_response = qlt_send_cmd_response;
1146fcf3ce4John Forte	port->port_abort_cmd = qlt_abort_cmd;
1147fcf3ce4John Forte	port->port_ctl = qlt_ctl;
1148fcf3ce4John Forte	port->port_flogi_xchg = qlt_do_flogi;
1149fcf3ce4John Forte	port->port_populate_hba_details = qlt_populate_hba_fru_details;
1150c946facallan	port->port_info = qlt_info;
1151a2255dfDaniel Beauregard	port->port_fca_version = FCT_FCA_MODREV_1;
1152fcf3ce4John Forte
1153c4ddbbeDaniel Beauregard	if ((ret = fct_register_local_port(port)) != FCT_SUCCESS) {
1154c4ddbbeDaniel Beauregard		EL(qlt, "fct_register_local_port status=%llxh\n", ret);
1155fcf3ce4John Forte		goto qlt_pstart_fail_2_5;
1156fcf3ce4John Forte	}
1157fcf3ce4John Forte
1158fcf3ce4John Forte	return (QLT_SUCCESS);
1159c4ddbbeDaniel Beauregard#if 0
1160fcf3ce4John Forteqlt_pstart_fail_3:
1161fcf3ce4John Forte	(void) fct_deregister_local_port(port);
1162c4ddbbeDaniel Beauregard#endif
1163fcf3ce4John Forteqlt_pstart_fail_2_5:
1164fcf3ce4John Forte	fct_free(fds);
1165fcf3ce4John Forteqlt_pstart_fail_2:
1166fcf3ce4John Forte	fct_free(port);
1167fcf3ce4John Forte	qlt->qlt_port = NULL;
1168fcf3ce4John Forteqlt_pstart_fail_1:
11693fb517fJames Moore	qlt_dma_handle_pool_fini(qlt);
1170fcf3ce4John Forte	qlt_dmem_fini(qlt);
1171fcf3ce4John Forte	return (QLT_FAILURE);
1172fcf3ce4John Forte}
1173fcf3ce4John Forte
1174fcf3ce4John Fortefct_status_t
1175fcf3ce4John Forteqlt_port_stop(caddr_t arg)
1176fcf3ce4John Forte{
1177fcf3ce4John Forte	qlt_state_t *qlt = (qlt_state_t *)arg;
1178c4ddbbeDaniel Beauregard	fct_status_t ret;
1179fcf3ce4John Forte
1180c4ddbbeDaniel Beauregard	if ((ret = fct_deregister_local_port(qlt->qlt_port)) != FCT_SUCCESS) {
1181c4ddbbeDaniel Beauregard		EL(qlt, "fct_register_local_port status=%llxh\n", ret);
1182fcf3ce4John Forte		return (QLT_FAILURE);
1183c4ddbbeDaniel Beauregard	}
1184fcf3ce4John Forte	fct_free(qlt->qlt_port->port_fds);
1185fcf3ce4John Forte	fct_free(qlt->qlt_port);
1186fcf3ce4John Forte	qlt->qlt_port = NULL;
11873fb517fJames Moore	qlt_dma_handle_pool_fini(qlt);
1188fcf3ce4John Forte	qlt_dmem_fini(qlt);
1189fcf3ce4John Forte	return (QLT_SUCCESS);
1190fcf3ce4John Forte}
1191fcf3ce4John Forte
1192fcf3ce4John Forte/*
1193fcf3ce4John Forte * Called by framework to init the HBA.
1194fcf3ce4John Forte * Can be called in the middle of I/O. (Why ??)
1195fcf3ce4John Forte * Should make sure sane state both before and after the initialization
1196fcf3ce4John Forte */
1197fcf3ce4John Fortefct_status_t
1198fcf3ce4John Forteqlt_port_online(qlt_state_t *qlt)
1199fcf3ce4John Forte{
1200fcf3ce4John Forte	uint64_t	da;
1201a2255dfDaniel Beauregard	int		instance, i;
1202fcf3ce4John Forte	fct_status_t	ret;
1203fcf3ce4John Forte	uint16_t	rcount;
1204fcf3ce4John Forte	caddr_t		icb;
1205fcf3ce4John Forte	mbox_cmd_t	*mcp;
1206fcf3ce4John Forte	uint8_t		*elsbmp;
1207fcf3ce4John Forte
1208fcf3ce4John Forte	instance = ddi_get_instance(qlt->dip);
1209fcf3ce4John Forte
1210fcf3ce4John Forte	/* XXX Make sure a sane state */
1211fcf3ce4John Forte
1212a2255dfDaniel Beauregard	if ((ret = qlt_download_fw(qlt)) != QLT_SUCCESS) {
1213fcf3ce4John Forte		cmn_err(CE_NOTE, "reset chip failed %llx", (long long)ret);
1214fcf3ce4John Forte		return (ret);
1215fcf3ce4John Forte	}
1216fcf3ce4John Forte
1217fcf3ce4John Forte	bzero(qlt->queue_mem_ptr, TOTAL_DMA_MEM_SIZE);
1218fcf3ce4John Forte
1219fcf3ce4John Forte	/* Get resource count */
1220a2255dfDaniel Beauregard	REG_WR16(qlt, REG_MBOX(0), MBC_GET_RESOURCE_COUNTS);
1221fcf3ce4John Forte	ret = qlt_raw_mailbox_command(qlt);
1222fcf3ce4John Forte	rcount = REG_RD16(qlt, REG_MBOX(3));
1223a2255dfDaniel Beauregard	REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
1224c4ddbbeDaniel Beauregard	if (ret != QLT_SUCCESS) {
1225c4ddbbeDaniel Beauregard		EL(qlt, "qlt_raw_mailbox_command=42h status=%llxh\n", ret);
1226fcf3ce4John Forte		return (ret);
1227c4ddbbeDaniel Beauregard	}
1228fcf3ce4John Forte
1229fcf3ce4John Forte	/* Enable PUREX */
1230a2255dfDaniel Beauregard	REG_WR16(qlt, REG_MBOX(0), MBC_SET_ADDITIONAL_FIRMWARE_OPT);
1231a2255dfDaniel Beauregard	REG_WR16(qlt, REG_MBOX(1), OPT_PUREX_ENABLE);
1232fcf3ce4John Forte	REG_WR16(qlt, REG_MBOX(2), 0x0);
1233fcf3ce4John Forte	REG_WR16(qlt, REG_MBOX(3), 0x0);
1234fcf3ce4John Forte	ret = qlt_raw_mailbox_command(qlt);
1235a2255dfDaniel Beauregard	REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
1236fcf3ce4John Forte	if (ret != QLT_SUCCESS) {
1237c4ddbbeDaniel Beauregard		EL(qlt, "qlt_raw_mailbox_command=38h status=%llxh\n", ret);
1238fcf3ce4John Forte		cmn_err(CE_NOTE, "Enable PUREX failed");
1239fcf3ce4John Forte		return (ret);
1240fcf3ce4John Forte	}
1241fcf3ce4John Forte
1242fcf3ce4John Forte	/* Pass ELS bitmap to fw */
1243a2255dfDaniel Beauregard	REG_WR16(qlt, REG_MBOX(0), MBC_SET_PARAMETERS);
1244a2255dfDaniel Beauregard	REG_WR16(qlt, REG_MBOX(1), PARAM_TYPE(PUREX_ELS_CMDS));
1245fcf3ce4John Forte	elsbmp = (uint8_t *)qlt->queue_mem_ptr + MBOX_DMA_MEM_OFFSET;
1246fcf3ce4John Forte	bzero(elsbmp, 32);
1247fcf3ce4John Forte	da = qlt->queue_mem_cookie.dmac_laddress;
1248fcf3ce4John Forte	da += MBOX_DMA_MEM_OFFSET;
1249a2255dfDaniel Beauregard	REG_WR16(qlt, REG_MBOX(3), LSW(LSD(da)));
1250a2255dfDaniel Beauregard	REG_WR16(qlt, REG_MBOX(2), MSW(LSD(da)));
1251a2255dfDaniel Beauregard	REG_WR16(qlt, REG_MBOX(7), LSW(MSD(da)));
1252a2255dfDaniel Beauregard	REG_WR16(qlt, REG_MBOX(6), MSW(MSD(da)));
1253fcf3ce4John Forte	SETELSBIT(elsbmp, ELS_OP_PLOGI);
1254fcf3ce4John Forte	SETELSBIT(elsbmp, ELS_OP_LOGO);
1255fcf3ce4John Forte	SETELSBIT(elsbmp, ELS_OP_ABTX);
1256fcf3ce4John Forte	SETELSBIT(elsbmp, ELS_OP_ECHO);
1257fcf3ce4John Forte	SETELSBIT(elsbmp, ELS_OP_PRLI);
1258fcf3ce4John Forte	SETELSBIT(elsbmp, ELS_OP_PRLO);
1259fcf3ce4John Forte	SETELSBIT(elsbmp, ELS_OP_SCN);
1260fcf3ce4John Forte	SETELSBIT(elsbmp, ELS_OP_TPRLO);
1261fcf3ce4John Forte	SETELSBIT(elsbmp, ELS_OP_PDISC);
1262fcf3ce4John Forte	SETELSBIT(elsbmp, ELS_OP_ADISC);
1263fcf3ce4John Forte	SETELSBIT(elsbmp, ELS_OP_RSCN);
1264fcf3ce4John Forte	SETELSBIT(elsbmp, ELS_OP_RNID);
1265fcf3ce4John Forte	(void) ddi_dma_sync(qlt->queue_mem_dma_handle, MBOX_DMA_MEM_OFFSET, 32,
1266d8c54e3Sam Cramer	    DDI_DMA_SYNC_FORDEV);
1267fcf3ce4John Forte	ret = qlt_raw_mailbox_command(qlt);
1268a2255dfDaniel Beauregard	REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
1269fcf3ce4John Forte	if (ret != QLT_SUCCESS) {
1270c4ddbbeDaniel Beauregard		EL(qlt, "qlt_raw_mailbox_command=59h status=llxh\n", ret);
1271fcf3ce4John Forte		cmn_err(CE_NOTE, "Set ELS Bitmap failed ret=%llx, "
1272fcf3ce4John Forte		    "elsbmp0=%x elabmp1=%x", (long long)ret, elsbmp[0],
1273fcf3ce4John Forte		    elsbmp[1]);
1274fcf3ce4John Forte		return (ret);
1275fcf3ce4John Forte	}
1276fcf3ce4John Forte
1277fcf3ce4John Forte	/* Init queue pointers */
1278fcf3ce4John Forte	REG_WR32(qlt, REG_REQ_IN_PTR, 0);
1279fcf3ce4John Forte	REG_WR32(qlt, REG_REQ_OUT_PTR, 0);
1280fcf3ce4John Forte	REG_WR32(qlt, REG_RESP_IN_PTR, 0);
1281fcf3ce4John Forte	REG_WR32(qlt, REG_RESP_OUT_PTR, 0);
1282fcf3ce4John Forte	REG_WR32(qlt, REG_PREQ_IN_PTR, 0);
1283fcf3ce4John Forte	REG_WR32(qlt, REG_PREQ_OUT_PTR, 0);
1284fcf3ce4John Forte	REG_WR32(qlt, REG_ATIO_IN_PTR, 0);
1285fcf3ce4John Forte	REG_WR32(qlt, REG_ATIO_OUT_PTR, 0);
1286fcf3ce4John Forte	qlt->req_ndx_to_fw = qlt->req_ndx_from_fw = 0;
1287fcf3ce4John Forte	qlt->req_available = REQUEST_QUEUE_ENTRIES - 1;
1288fcf3ce4John Forte	qlt->resp_ndx_to_fw = qlt->resp_ndx_from_fw = 0;
1289fcf3ce4John Forte	qlt->preq_ndx_to_fw = qlt->preq_ndx_from_fw = 0;
1290fcf3ce4John Forte	qlt->atio_ndx_to_fw = qlt->atio_ndx_from_fw = 0;
1291fcf3ce4John Forte
1292fcf3ce4John Forte	/*
1293fcf3ce4John Forte	 * XXX support for tunables. Also should we cache icb ?
1294fcf3ce4John Forte	 */
1295c4ddbbeDaniel Beauregard	if (qlt->qlt_81xx_chip) {
1296c4ddbbeDaniel Beauregard	    /* allocate extra 64 bytes for Extended init control block */
1297c4ddbbeDaniel Beauregard		mcp = qlt_alloc_mailbox_command(qlt, 0xC0);
1298c4ddbbeDaniel Beauregard	} else {
1299c4ddbbeDaniel Beauregard		mcp = qlt_alloc_mailbox_command(qlt, 0x80);
1300c4ddbbeDaniel Beauregard	}
1301fcf3ce4John Forte	if (mcp == NULL) {
1302c4ddbbeDaniel Beauregard		EL(qlt, "qlt_alloc_mailbox_command mcp=null\n");
1303fcf3ce4John Forte		return (STMF_ALLOC_FAILURE);
1304fcf3ce4John Forte	}
1305fcf3ce4John Forte	icb = (caddr_t)mcp->dbuf->db_sglist[0].seg_addr;
1306c4ddbbeDaniel Beauregard	if (qlt->qlt_81xx_chip) {
1307c4ddbbeDaniel Beauregard		bzero(icb, 0xC0);
1308c4ddbbeDaniel Beauregard	} else {
1309c4ddbbeDaniel Beauregard		bzero(icb, 0x80);
1310c4ddbbeDaniel Beauregard	}
1311fcf3ce4John Forte	da = qlt->queue_mem_cookie.dmac_laddress;
1312fcf3ce4John Forte	DMEM_WR16(qlt, icb, 1);		/* Version */
1313fcf3ce4John Forte	DMEM_WR16(qlt, icb+4, 2112);	/* Max frame length */
1314fcf3ce4John Forte	DMEM_WR16(qlt, icb+6, 16);	/* Execution throttle */
1315fcf3ce4John Forte	DMEM_WR16(qlt, icb+8, rcount);	/* Xchg count */
1316fcf3ce4John Forte	DMEM_WR16(qlt, icb+0x0a, 0x00);	/* Hard address (not used) */
1317fcf3ce4John Forte	bcopy(qlt->qlt_port->port_pwwn, icb+0x0c, 8);
1318