Merge commit '4ec4134be29a3b00791f6d70074168a6a3ff4fb3'
[unleashed.git] / kernel / comstar / port / qlt / qlt.c
blob9719d2d24a226277770932106d0a94cd6a8796d5
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2009 QLogic Corporation. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
31 #include <sys/conf.h>
32 #include <sys/ddi.h>
33 #include <sys/stat.h>
34 #include <sys/pci.h>
35 #include <sys/sunddi.h>
36 #include <sys/modctl.h>
37 #include <sys/file.h>
38 #include <sys/cred.h>
39 #include <sys/byteorder.h>
40 #include <sys/atomic.h>
41 #include <sys/scsi/scsi.h>
43 #include <sys/stmf_defines.h>
44 #include <sys/fct_defines.h>
45 #include <sys/stmf.h>
46 #include <sys/stmf_ioctl.h>
47 #include <sys/portif.h>
48 #include <sys/fct.h>
50 #include "qlt.h"
51 #include "qlt_dma.h"
52 #include "qlt_ioctl.h"
53 #include "qlt_open.h"
55 static int qlt_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
56 static int qlt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
57 static void qlt_enable_intr(qlt_state_t *);
58 static void qlt_disable_intr(qlt_state_t *);
59 static fct_status_t qlt_reset_chip(qlt_state_t *qlt);
60 static fct_status_t qlt_download_fw(qlt_state_t *qlt);
61 static fct_status_t qlt_load_risc_ram(qlt_state_t *qlt, uint32_t *host_addr,
62 uint32_t word_count, uint32_t risc_addr);
63 static fct_status_t qlt_raw_mailbox_command(qlt_state_t *qlt);
64 static mbox_cmd_t *qlt_alloc_mailbox_command(qlt_state_t *qlt,
65 uint32_t dma_size);
66 void qlt_free_mailbox_command(qlt_state_t *qlt, mbox_cmd_t *mcp);
67 static fct_status_t qlt_mailbox_command(qlt_state_t *qlt, mbox_cmd_t *mcp);
68 static uint_t qlt_isr(caddr_t arg, caddr_t arg2);
69 static fct_status_t qlt_firmware_dump(fct_local_port_t *port,
70 stmf_state_change_info_t *ssci);
71 static void qlt_handle_inot(qlt_state_t *qlt, uint8_t *inot);
72 static void qlt_handle_purex(qlt_state_t *qlt, uint8_t *resp);
73 static void qlt_handle_atio(qlt_state_t *qlt, uint8_t *atio);
74 static void qlt_handle_ctio_completion(qlt_state_t *qlt, uint8_t *rsp);
75 static void qlt_handle_sol_abort_completion(qlt_state_t *qlt, uint8_t *rsp);
76 static void qlt_handle_dereg_completion(qlt_state_t *qlt, uint8_t *rsp);
77 static void qlt_handle_unsol_els_completion(qlt_state_t *qlt, uint8_t *rsp);
78 static void qlt_handle_unsol_els_abort_completion(qlt_state_t *qlt,
79 uint8_t *rsp);
80 static void qlt_handle_sol_els_completion(qlt_state_t *qlt, uint8_t *rsp);
81 static void qlt_handle_rcvd_abts(qlt_state_t *qlt, uint8_t *resp);
82 static void qlt_handle_abts_completion(qlt_state_t *qlt, uint8_t *resp);
83 static fct_status_t qlt_read_nvram(qlt_state_t *qlt);
84 static void qlt_verify_fw(qlt_state_t *qlt);
85 static void qlt_handle_verify_fw_completion(qlt_state_t *qlt, uint8_t *rsp);
86 fct_status_t qlt_port_start(caddr_t arg);
87 fct_status_t qlt_port_stop(caddr_t arg);
88 fct_status_t qlt_port_online(qlt_state_t *qlt);
89 fct_status_t qlt_port_offline(qlt_state_t *qlt);
90 static fct_status_t qlt_get_link_info(fct_local_port_t *port,
91 fct_link_info_t *li);
92 static void qlt_ctl(struct fct_local_port *port, int cmd, void *arg);
93 static fct_status_t qlt_force_lip(qlt_state_t *);
94 static fct_status_t qlt_do_flogi(struct fct_local_port *port,
95 fct_flogi_xchg_t *fx);
96 void qlt_handle_atio_queue_update(qlt_state_t *qlt);
97 void qlt_handle_resp_queue_update(qlt_state_t *qlt);
98 fct_status_t qlt_register_remote_port(fct_local_port_t *port,
99 fct_remote_port_t *rp, fct_cmd_t *login);
100 fct_status_t qlt_deregister_remote_port(fct_local_port_t *port,
101 fct_remote_port_t *rp);
102 fct_status_t qlt_send_cmd_response(fct_cmd_t *cmd, uint32_t ioflags);
103 fct_status_t qlt_send_els_response(qlt_state_t *qlt, fct_cmd_t *cmd);
104 fct_status_t qlt_send_abts_response(qlt_state_t *qlt,
105 fct_cmd_t *cmd, int terminate);
106 static void qlt_handle_inot(qlt_state_t *qlt, uint8_t *inot);
107 int qlt_set_uniq_flag(uint16_t *ptr, uint16_t setf, uint16_t abortf);
108 fct_status_t qlt_abort_cmd(struct fct_local_port *port,
109 fct_cmd_t *cmd, uint32_t flags);
110 fct_status_t qlt_abort_sol_cmd(qlt_state_t *qlt, fct_cmd_t *cmd);
111 fct_status_t qlt_abort_purex(qlt_state_t *qlt, fct_cmd_t *cmd);
112 fct_status_t qlt_abort_unsol_scsi_cmd(qlt_state_t *qlt, fct_cmd_t *cmd);
113 fct_status_t qlt_send_cmd(fct_cmd_t *cmd);
114 fct_status_t qlt_send_els(qlt_state_t *qlt, fct_cmd_t *cmd);
115 fct_status_t qlt_send_status(qlt_state_t *qlt, fct_cmd_t *cmd);
116 fct_status_t qlt_xfer_scsi_data(fct_cmd_t *cmd,
117 stmf_data_buf_t *dbuf, uint32_t ioflags);
118 fct_status_t qlt_send_ct(qlt_state_t *qlt, fct_cmd_t *cmd);
119 static void qlt_handle_ct_completion(qlt_state_t *qlt, uint8_t *rsp);
120 static void qlt_release_intr(qlt_state_t *qlt);
121 static int qlt_setup_interrupts(qlt_state_t *qlt);
122 static void qlt_destroy_mutex(qlt_state_t *qlt);
124 static fct_status_t qlt_read_risc_ram(qlt_state_t *qlt, uint32_t addr,
125 uint32_t words);
126 static int qlt_dump_queue(qlt_state_t *qlt, caddr_t qadr, int entries,
127 caddr_t buf, uint_t size_left);
128 static int qlt_dump_risc_ram(qlt_state_t *qlt, uint32_t addr, uint32_t words,
129 caddr_t buf, uint_t size_left);
130 static int qlt_fwdump_dump_regs(qlt_state_t *qlt, caddr_t buf, int startaddr,
131 int count, uint_t size_left);
132 static int qlt_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
133 cred_t *credp, int *rval);
134 static int qlt_open(dev_t *devp, int flag, int otype, cred_t *credp);
135 static int qlt_close(dev_t dev, int flag, int otype, cred_t *credp);
137 static int qlt_setup_msi(qlt_state_t *qlt);
138 static int qlt_setup_msix(qlt_state_t *qlt);
140 static int qlt_el_trace_desc_ctor(qlt_state_t *qlt);
141 static int qlt_el_trace_desc_dtor(qlt_state_t *qlt);
142 static int qlt_validate_trace_desc(qlt_state_t *qlt);
143 static char *qlt_find_trace_start(qlt_state_t *qlt);
145 static int qlt_read_int_prop(qlt_state_t *qlt, char *prop, int defval);
146 static int qlt_read_string_prop(qlt_state_t *qlt, char *prop, char **prop_val);
147 static int qlt_read_string_instance_prop(qlt_state_t *qlt, char *prop,
148 char **prop_val);
149 static int qlt_read_int_instance_prop(qlt_state_t *, char *, int);
150 static int qlt_convert_string_to_ull(char *prop, int radix,
151 u_longlong_t *result);
152 static boolean_t qlt_wwn_overload_prop(qlt_state_t *qlt);
153 static int qlt_quiesce(dev_info_t *dip);
154 static fct_status_t qlt_raw_wrt_risc_ram_word(qlt_state_t *qlt, uint32_t,
155 uint32_t);
156 static fct_status_t qlt_raw_rd_risc_ram_word(qlt_state_t *qlt, uint32_t,
157 uint32_t *);
158 static void qlt_mps_reset(qlt_state_t *qlt);
159 static void qlt_properties(qlt_state_t *qlt);
162 #define SETELSBIT(bmp, els) (bmp)[((els) >> 3) & 0x1F] = \
163 (uint8_t)((bmp)[((els) >> 3) & 0x1F] | ((uint8_t)1) << ((els) & 7))
165 int qlt_enable_msix = 0;
166 int qlt_enable_msi = 1;
169 string_table_t prop_status_tbl[] = DDI_PROP_STATUS();
171 /* Array to quickly calculate next free buf index to use */
172 #if 0
173 static int qlt_nfb[] = { 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 0xff };
174 #endif
176 static struct cb_ops qlt_cb_ops = {
177 qlt_open,
178 qlt_close,
179 nodev,
180 nodev,
181 nodev,
182 nodev,
183 nodev,
184 qlt_ioctl,
185 nodev,
186 nodev,
187 nodev,
188 nochpoll,
189 ddi_prop_op,
191 D_MP | D_NEW
194 static struct dev_ops qlt_ops = {
195 DEVO_REV,
197 nodev,
198 nulldev,
199 nulldev,
200 qlt_attach,
201 qlt_detach,
202 nodev,
203 &qlt_cb_ops,
204 NULL,
205 ddi_power,
206 qlt_quiesce
209 #ifndef PORT_SPEED_10G
210 #define PORT_SPEED_10G 16
211 #endif
213 static struct modldrv modldrv = {
214 &mod_driverops,
215 QLT_NAME" "QLT_VERSION,
216 &qlt_ops,
219 static struct modlinkage modlinkage = {
220 MODREV_1, &modldrv, NULL
223 void *qlt_state = NULL;
224 kmutex_t qlt_global_lock;
225 static uint32_t qlt_loaded_counter = 0;
227 static char *pci_speeds[] = { " 33", "-X Mode 1 66", "-X Mode 1 100",
228 "-X Mode 1 133", "--Invalid--",
229 "-X Mode 2 66", "-X Mode 2 100",
230 "-X Mode 2 133", " 66" };
232 /* Always use 64 bit DMA. */
233 static ddi_dma_attr_t qlt_queue_dma_attr = {
234 DMA_ATTR_V0, /* dma_attr_version */
235 0, /* low DMA address range */
236 0xffffffffffffffff, /* high DMA address range */
237 0xffffffff, /* DMA counter register */
238 64, /* DMA address alignment */
239 0xff, /* DMA burstsizes */
240 1, /* min effective DMA size */
241 0xffffffff, /* max DMA xfer size */
242 0xffffffff, /* segment boundary */
243 1, /* s/g list length */
244 1, /* granularity of device */
245 0 /* DMA transfer flags */
248 /* qlogic logging */
249 int enable_extended_logging = 0;
251 static char qlt_provider_name[] = "qlt";
252 static struct stmf_port_provider *qlt_pp;
255 _init(void)
257 int ret;
259 ret = ddi_soft_state_init(&qlt_state, sizeof (qlt_state_t), 0);
260 if (ret == 0) {
261 mutex_init(&qlt_global_lock, 0, MUTEX_DRIVER, 0);
262 qlt_pp = (stmf_port_provider_t *)stmf_alloc(
263 STMF_STRUCT_PORT_PROVIDER, 0, 0);
264 qlt_pp->pp_portif_rev = PORTIF_REV_1;
265 qlt_pp->pp_name = qlt_provider_name;
266 if (stmf_register_port_provider(qlt_pp) != STMF_SUCCESS) {
267 stmf_free(qlt_pp);
268 mutex_destroy(&qlt_global_lock);
269 ddi_soft_state_fini(&qlt_state);
270 return (EIO);
272 ret = mod_install(&modlinkage);
273 if (ret != 0) {
274 (void) stmf_deregister_port_provider(qlt_pp);
275 stmf_free(qlt_pp);
276 mutex_destroy(&qlt_global_lock);
277 ddi_soft_state_fini(&qlt_state);
280 return (ret);
284 _fini(void)
286 int ret;
288 if (qlt_loaded_counter)
289 return (EBUSY);
290 ret = mod_remove(&modlinkage);
291 if (ret == 0) {
292 (void) stmf_deregister_port_provider(qlt_pp);
293 stmf_free(qlt_pp);
294 mutex_destroy(&qlt_global_lock);
295 ddi_soft_state_fini(&qlt_state);
297 return (ret);
301 _info(struct modinfo *modinfop)
303 return (mod_info(&modlinkage, modinfop));
307 static int
308 qlt_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
310 int instance;
311 qlt_state_t *qlt;
312 ddi_device_acc_attr_t dev_acc_attr;
313 uint16_t did;
314 uint16_t val;
315 uint16_t mr;
316 size_t discard;
317 uint_t ncookies;
318 int max_read_size;
319 int max_payload_size;
320 fct_status_t ret;
322 /* No support for suspend resume yet */
323 if (cmd != DDI_ATTACH)
324 return (DDI_FAILURE);
325 instance = ddi_get_instance(dip);
327 if (ddi_soft_state_zalloc(qlt_state, instance) != DDI_SUCCESS) {
328 return (DDI_FAILURE);
331 if ((qlt = (qlt_state_t *)ddi_get_soft_state(qlt_state, instance)) ==
332 NULL) {
333 goto attach_fail_1;
336 qlt->instance = instance;
338 qlt->nvram = (qlt_nvram_t *)kmem_zalloc(sizeof (qlt_nvram_t), KM_SLEEP);
339 qlt->dip = dip;
341 if (qlt_el_trace_desc_ctor(qlt) != DDI_SUCCESS) {
342 cmn_err(CE_WARN, "qlt(%d): can't setup el tracing", instance);
343 goto attach_fail_1;
346 EL(qlt, "instance=%d, ptr=%p\n", instance, (void *)qlt);
348 if (pci_config_setup(dip, &qlt->pcicfg_acc_handle) != DDI_SUCCESS) {
349 goto attach_fail_2;
351 did = PCICFG_RD16(qlt, PCI_CONF_DEVID);
352 if ((did != 0x2422) && (did != 0x2432) &&
353 (did != 0x8432) && (did != 0x2532) &&
354 (did != 0x8001)) {
355 cmn_err(CE_WARN, "qlt(%d): unknown devid(%x), failing attach",
356 instance, did);
357 goto attach_fail_4;
360 if ((did & 0xFF00) == 0x8000)
361 qlt->qlt_81xx_chip = 1;
362 else if ((did & 0xFF00) == 0x2500)
363 qlt->qlt_25xx_chip = 1;
365 dev_acc_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
366 dev_acc_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
367 dev_acc_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
368 if (ddi_regs_map_setup(dip, 2, &qlt->regs, 0, 0x100,
369 &dev_acc_attr, &qlt->regs_acc_handle) != DDI_SUCCESS) {
370 goto attach_fail_4;
372 if (did == 0x2422) {
373 uint32_t pci_bits = REG_RD32(qlt, REG_CTRL_STATUS);
374 uint32_t slot = pci_bits & PCI_64_BIT_SLOT;
375 pci_bits >>= 8;
376 pci_bits &= 0xf;
377 if ((pci_bits == 3) || (pci_bits == 7)) {
378 cmn_err(CE_NOTE,
379 "!qlt(%d): HBA running at PCI%sMHz (%d)",
380 instance, pci_speeds[pci_bits], pci_bits);
381 } else {
382 cmn_err(CE_WARN,
383 "qlt(%d): HBA running at PCI%sMHz %s(%d)",
384 instance, (pci_bits <= 8) ? pci_speeds[pci_bits] :
385 "(Invalid)", ((pci_bits == 0) ||
386 (pci_bits == 8)) ? (slot ? "64 bit slot " :
387 "32 bit slot ") : "", pci_bits);
390 if ((ret = qlt_read_nvram(qlt)) != QLT_SUCCESS) {
391 cmn_err(CE_WARN, "qlt(%d): read nvram failure %llx", instance,
392 (unsigned long long)ret);
393 goto attach_fail_5;
396 qlt_properties(qlt);
398 if (ddi_dma_alloc_handle(dip, &qlt_queue_dma_attr, DDI_DMA_SLEEP,
399 0, &qlt->queue_mem_dma_handle) != DDI_SUCCESS) {
400 goto attach_fail_5;
402 if (ddi_dma_mem_alloc(qlt->queue_mem_dma_handle, TOTAL_DMA_MEM_SIZE,
403 &dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0,
404 &qlt->queue_mem_ptr, &discard, &qlt->queue_mem_acc_handle) !=
405 DDI_SUCCESS) {
406 goto attach_fail_6;
408 if (ddi_dma_addr_bind_handle(qlt->queue_mem_dma_handle, NULL,
409 qlt->queue_mem_ptr, TOTAL_DMA_MEM_SIZE,
410 DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0,
411 &qlt->queue_mem_cookie, &ncookies) != DDI_SUCCESS) {
412 goto attach_fail_7;
414 if (ncookies != 1)
415 goto attach_fail_8;
416 qlt->req_ptr = qlt->queue_mem_ptr + REQUEST_QUEUE_OFFSET;
417 qlt->resp_ptr = qlt->queue_mem_ptr + RESPONSE_QUEUE_OFFSET;
418 qlt->preq_ptr = qlt->queue_mem_ptr + PRIORITY_QUEUE_OFFSET;
419 qlt->atio_ptr = qlt->queue_mem_ptr + ATIO_QUEUE_OFFSET;
421 /* mutex are inited in this function */
422 if (qlt_setup_interrupts(qlt) != DDI_SUCCESS)
423 goto attach_fail_8;
425 (void) snprintf(qlt->qlt_minor_name, sizeof (qlt->qlt_minor_name),
426 "qlt%d", instance);
427 (void) snprintf(qlt->qlt_port_alias, sizeof (qlt->qlt_port_alias),
428 "%s,0", qlt->qlt_minor_name);
430 if (ddi_create_minor_node(dip, qlt->qlt_minor_name, S_IFCHR,
431 instance, DDI_NT_STMF_PP, 0) != DDI_SUCCESS) {
432 goto attach_fail_9;
435 cv_init(&qlt->rp_dereg_cv, NULL, CV_DRIVER, NULL);
436 cv_init(&qlt->mbox_cv, NULL, CV_DRIVER, NULL);
437 mutex_init(&qlt->qlt_ioctl_lock, NULL, MUTEX_DRIVER, NULL);
439 /* Setup PCI cfg space registers */
440 max_read_size = qlt_read_int_prop(qlt, "pci-max-read-request", 11);
441 if (max_read_size == 11)
442 goto over_max_read_xfer_setting;
443 if (did == 0x2422) {
444 if (max_read_size == 512)
445 val = 0;
446 else if (max_read_size == 1024)
447 val = 1;
448 else if (max_read_size == 2048)
449 val = 2;
450 else if (max_read_size == 4096)
451 val = 3;
452 else {
453 cmn_err(CE_WARN, "qlt(%d) malformed "
454 "pci-max-read-request in qlt.conf. Valid values "
455 "for this HBA are 512/1024/2048/4096", instance);
456 goto over_max_read_xfer_setting;
458 mr = (uint16_t)PCICFG_RD16(qlt, 0x4E);
459 mr = (uint16_t)(mr & 0xfff3);
460 mr = (uint16_t)(mr | (val << 2));
461 PCICFG_WR16(qlt, 0x4E, mr);
462 } else if ((did == 0x2432) || (did == 0x8432) ||
463 (did == 0x2532) || (did == 0x8001)) {
464 if (max_read_size == 128)
465 val = 0;
466 else if (max_read_size == 256)
467 val = 1;
468 else if (max_read_size == 512)
469 val = 2;
470 else if (max_read_size == 1024)
471 val = 3;
472 else if (max_read_size == 2048)
473 val = 4;
474 else if (max_read_size == 4096)
475 val = 5;
476 else {
477 cmn_err(CE_WARN, "qlt(%d) malformed "
478 "pci-max-read-request in qlt.conf. Valid values "
479 "for this HBA are 128/256/512/1024/2048/4096",
480 instance);
481 goto over_max_read_xfer_setting;
483 mr = (uint16_t)PCICFG_RD16(qlt, 0x54);
484 mr = (uint16_t)(mr & 0x8fff);
485 mr = (uint16_t)(mr | (val << 12));
486 PCICFG_WR16(qlt, 0x54, mr);
487 } else {
488 cmn_err(CE_WARN, "qlt(%d): dont know how to set "
489 "pci-max-read-request for this device (%x)",
490 instance, did);
492 over_max_read_xfer_setting:;
494 max_payload_size = qlt_read_int_prop(qlt, "pcie-max-payload-size", 11);
495 if (max_payload_size == 11)
496 goto over_max_payload_setting;
497 if ((did == 0x2432) || (did == 0x8432) ||
498 (did == 0x2532) || (did == 0x8001)) {
499 if (max_payload_size == 128)
500 val = 0;
501 else if (max_payload_size == 256)
502 val = 1;
503 else if (max_payload_size == 512)
504 val = 2;
505 else if (max_payload_size == 1024)
506 val = 3;
507 else {
508 cmn_err(CE_WARN, "qlt(%d) malformed "
509 "pcie-max-payload-size in qlt.conf. Valid values "
510 "for this HBA are 128/256/512/1024",
511 instance);
512 goto over_max_payload_setting;
514 mr = (uint16_t)PCICFG_RD16(qlt, 0x54);
515 mr = (uint16_t)(mr & 0xff1f);
516 mr = (uint16_t)(mr | (val << 5));
517 PCICFG_WR16(qlt, 0x54, mr);
518 } else {
519 cmn_err(CE_WARN, "qlt(%d): dont know how to set "
520 "pcie-max-payload-size for this device (%x)",
521 instance, did);
524 over_max_payload_setting:;
526 qlt_enable_intr(qlt);
528 if (qlt_port_start((caddr_t)qlt) != QLT_SUCCESS)
529 goto attach_fail_10;
531 ddi_report_dev(dip);
532 return (DDI_SUCCESS);
534 attach_fail_10:;
535 mutex_destroy(&qlt->qlt_ioctl_lock);
536 cv_destroy(&qlt->mbox_cv);
537 cv_destroy(&qlt->rp_dereg_cv);
538 ddi_remove_minor_node(dip, qlt->qlt_minor_name);
539 attach_fail_9:;
540 qlt_destroy_mutex(qlt);
541 qlt_release_intr(qlt);
542 attach_fail_8:;
543 (void) ddi_dma_unbind_handle(qlt->queue_mem_dma_handle);
544 attach_fail_7:;
545 ddi_dma_mem_free(&qlt->queue_mem_acc_handle);
546 attach_fail_6:;
547 ddi_dma_free_handle(&qlt->queue_mem_dma_handle);
548 attach_fail_5:;
549 ddi_regs_map_free(&qlt->regs_acc_handle);
550 attach_fail_4:;
551 pci_config_teardown(&qlt->pcicfg_acc_handle);
552 kmem_free(qlt->nvram, sizeof (qlt_nvram_t));
553 (void) qlt_el_trace_desc_dtor(qlt);
554 attach_fail_2:;
555 attach_fail_1:;
556 ddi_soft_state_free(qlt_state, instance);
557 return (DDI_FAILURE);
560 #define FCT_I_EVENT_BRING_PORT_OFFLINE 0x83
562 /* ARGSUSED */
563 static int
564 qlt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
566 qlt_state_t *qlt;
568 int instance;
570 instance = ddi_get_instance(dip);
571 if ((qlt = (qlt_state_t *)ddi_get_soft_state(qlt_state, instance)) ==
572 NULL) {
573 return (DDI_FAILURE);
576 if (qlt->fw_code01) {
577 return (DDI_FAILURE);
580 if ((qlt->qlt_state != FCT_STATE_OFFLINE) ||
581 qlt->qlt_state_not_acked) {
582 return (DDI_FAILURE);
584 if (qlt_port_stop((caddr_t)qlt) != FCT_SUCCESS) {
585 return (DDI_FAILURE);
588 qlt_disable_intr(qlt);
590 ddi_remove_minor_node(dip, qlt->qlt_minor_name);
591 qlt_destroy_mutex(qlt);
592 qlt_release_intr(qlt);
593 (void) ddi_dma_unbind_handle(qlt->queue_mem_dma_handle);
594 ddi_dma_mem_free(&qlt->queue_mem_acc_handle);
595 ddi_dma_free_handle(&qlt->queue_mem_dma_handle);
596 ddi_regs_map_free(&qlt->regs_acc_handle);
597 pci_config_teardown(&qlt->pcicfg_acc_handle);
598 kmem_free(qlt->nvram, sizeof (qlt_nvram_t));
599 cv_destroy(&qlt->mbox_cv);
600 cv_destroy(&qlt->rp_dereg_cv);
601 (void) qlt_el_trace_desc_dtor(qlt);
602 ddi_soft_state_free(qlt_state, instance);
604 return (DDI_SUCCESS);
608 * qlt_quiesce quiesce a device attached to the system.
610 static int
611 qlt_quiesce(dev_info_t *dip)
613 qlt_state_t *qlt;
614 uint32_t timer;
615 uint32_t stat;
617 qlt = ddi_get_soft_state(qlt_state, ddi_get_instance(dip));
618 if (qlt == NULL) {
619 /* Oh well.... */
620 return (DDI_SUCCESS);
623 REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_HOST_TO_RISC_INTR));
624 REG_WR16(qlt, REG_MBOX0, MBC_STOP_FIRMWARE);
625 REG_WR32(qlt, REG_HCCR, HCCR_CMD(SET_HOST_TO_RISC_INTR));
626 for (timer = 0; timer < 30000; timer++) {
627 stat = REG_RD32(qlt, REG_RISC_STATUS);
628 if (stat & RISC_HOST_INTR_REQUEST) {
629 if ((stat & FW_INTR_STATUS_MASK) < 0x12) {
630 REG_WR32(qlt, REG_HCCR,
631 HCCR_CMD(CLEAR_RISC_PAUSE));
632 break;
634 REG_WR32(qlt, REG_HCCR,
635 HCCR_CMD(CLEAR_HOST_TO_RISC_INTR));
637 drv_usecwait(100);
639 /* Reset the chip. */
640 REG_WR32(qlt, REG_CTRL_STATUS, CHIP_SOFT_RESET | DMA_SHUTDOWN_CTRL |
641 PCI_X_XFER_CTRL);
642 drv_usecwait(100);
644 qlt_disable_intr(qlt);
646 return (DDI_SUCCESS);
649 static void
650 qlt_enable_intr(qlt_state_t *qlt)
652 if (qlt->intr_cap & DDI_INTR_FLAG_BLOCK) {
653 (void) ddi_intr_block_enable(qlt->htable, qlt->intr_cnt);
654 } else {
655 int i;
656 for (i = 0; i < qlt->intr_cnt; i++)
657 (void) ddi_intr_enable(qlt->htable[i]);
659 qlt->qlt_intr_enabled = 1;
662 static void
663 qlt_disable_intr(qlt_state_t *qlt)
665 if (qlt->intr_cap & DDI_INTR_FLAG_BLOCK) {
666 (void) ddi_intr_block_disable(qlt->htable, qlt->intr_cnt);
667 } else {
668 int i;
669 for (i = 0; i < qlt->intr_cnt; i++)
670 (void) ddi_intr_disable(qlt->htable[i]);
672 qlt->qlt_intr_enabled = 0;
675 static void
676 qlt_release_intr(qlt_state_t *qlt)
678 if (qlt->htable) {
679 int i;
680 for (i = 0; i < qlt->intr_cnt; i++) {
681 (void) ddi_intr_remove_handler(qlt->htable[i]);
682 (void) ddi_intr_free(qlt->htable[i]);
684 kmem_free(qlt->htable, (uint_t)qlt->intr_size);
686 qlt->htable = NULL;
687 qlt->intr_pri = 0;
688 qlt->intr_cnt = 0;
689 qlt->intr_size = 0;
690 qlt->intr_cap = 0;
694 static void
695 qlt_init_mutex(qlt_state_t *qlt)
697 mutex_init(&qlt->req_lock, 0, MUTEX_DRIVER,
698 INT2PTR(qlt->intr_pri, void *));
699 mutex_init(&qlt->preq_lock, 0, MUTEX_DRIVER,
700 INT2PTR(qlt->intr_pri, void *));
701 mutex_init(&qlt->mbox_lock, NULL, MUTEX_DRIVER,
702 INT2PTR(qlt->intr_pri, void *));
703 mutex_init(&qlt->intr_lock, NULL, MUTEX_DRIVER,
704 INT2PTR(qlt->intr_pri, void *));
707 static void
708 qlt_destroy_mutex(qlt_state_t *qlt)
710 mutex_destroy(&qlt->req_lock);
711 mutex_destroy(&qlt->preq_lock);
712 mutex_destroy(&qlt->mbox_lock);
713 mutex_destroy(&qlt->intr_lock);
717 static int
718 qlt_setup_msix(qlt_state_t *qlt)
720 int count, avail, actual;
721 int ret;
722 int itype = DDI_INTR_TYPE_MSIX;
723 int i;
725 ret = ddi_intr_get_nintrs(qlt->dip, itype, &count);
726 if (ret != DDI_SUCCESS || count == 0) {
727 EL(qlt, "ddi_intr_get_nintrs status=%xh, count=%d\n", ret,
728 count);
729 return (DDI_FAILURE);
731 ret = ddi_intr_get_navail(qlt->dip, itype, &avail);
732 if (ret != DDI_SUCCESS || avail == 0) {
733 EL(qlt, "ddi_intr_get_navail status=%xh, avail=%d\n", ret,
734 avail);
735 return (DDI_FAILURE);
737 if (avail < count) {
738 stmf_trace(qlt->qlt_port_alias,
739 "qlt_setup_msix: nintrs=%d,avail=%d", count, avail);
742 qlt->intr_size = (int)(count * (int)sizeof (ddi_intr_handle_t));
743 qlt->htable = kmem_zalloc((uint_t)qlt->intr_size, KM_SLEEP);
744 ret = ddi_intr_alloc(qlt->dip, qlt->htable, itype,
745 DDI_INTR_ALLOC_NORMAL, count, &actual, 0);
746 /* we need at least 2 interrupt vectors */
747 if (ret != DDI_SUCCESS || actual < 2) {
748 EL(qlt, "ddi_intr_alloc status=%xh, actual=%d\n", ret,
749 actual);
750 ret = DDI_FAILURE;
751 goto release_intr;
753 if (actual < count) {
754 EL(qlt, "requested: %d, received: %d\n", count, actual);
757 qlt->intr_cnt = actual;
758 ret = ddi_intr_get_pri(qlt->htable[0], &qlt->intr_pri);
759 if (ret != DDI_SUCCESS) {
760 EL(qlt, "ddi_intr_get_pri status=%xh\n", ret);
761 ret = DDI_FAILURE;
762 goto release_intr;
764 qlt_init_mutex(qlt);
765 for (i = 0; i < actual; i++) {
766 ret = ddi_intr_add_handler(qlt->htable[i], qlt_isr,
767 qlt, INT2PTR((uint_t)i, void *));
768 if (ret != DDI_SUCCESS) {
769 EL(qlt, "ddi_intr_add_handler status=%xh\n", ret);
770 goto release_mutex;
774 (void) ddi_intr_get_cap(qlt->htable[0], &qlt->intr_cap);
775 qlt->intr_flags |= QLT_INTR_MSIX;
776 return (DDI_SUCCESS);
778 release_mutex:
779 qlt_destroy_mutex(qlt);
780 release_intr:
781 for (i = 0; i < actual; i++)
782 (void) ddi_intr_free(qlt->htable[i]);
783 #if 0
784 free_mem:
785 #endif
786 kmem_free(qlt->htable, (uint_t)qlt->intr_size);
787 qlt->htable = NULL;
788 qlt_release_intr(qlt);
789 return (ret);
793 static int
794 qlt_setup_msi(qlt_state_t *qlt)
796 int count, avail, actual;
797 int itype = DDI_INTR_TYPE_MSI;
798 int ret;
799 int i;
801 /* get the # of interrupts */
802 ret = ddi_intr_get_nintrs(qlt->dip, itype, &count);
803 if (ret != DDI_SUCCESS || count == 0) {
804 EL(qlt, "ddi_intr_get_nintrs status=%xh, count=%d\n", ret,
805 count);
806 return (DDI_FAILURE);
808 ret = ddi_intr_get_navail(qlt->dip, itype, &avail);
809 if (ret != DDI_SUCCESS || avail == 0) {
810 EL(qlt, "ddi_intr_get_navail status=%xh, avail=%d\n", ret,
811 avail);
812 return (DDI_FAILURE);
814 if (avail < count) {
815 EL(qlt, "nintrs=%d, avail=%d\n", count, avail);
817 /* MSI requires only 1 interrupt. */
818 count = 1;
820 /* allocate interrupt */
821 qlt->intr_size = (int)(count * (int)sizeof (ddi_intr_handle_t));
822 qlt->htable = kmem_zalloc((uint_t)qlt->intr_size, KM_SLEEP);
823 ret = ddi_intr_alloc(qlt->dip, qlt->htable, itype,
824 0, count, &actual, DDI_INTR_ALLOC_NORMAL);
825 if (ret != DDI_SUCCESS || actual == 0) {
826 EL(qlt, "ddi_intr_alloc status=%xh, actual=%d\n", ret,
827 actual);
828 ret = DDI_FAILURE;
829 goto free_mem;
831 if (actual < count) {
832 EL(qlt, "requested: %d, received: %d\n", count, actual);
834 qlt->intr_cnt = actual;
837 * Get priority for first msi, assume remaining are all the same.
839 ret = ddi_intr_get_pri(qlt->htable[0], &qlt->intr_pri);
840 if (ret != DDI_SUCCESS) {
841 EL(qlt, "ddi_intr_get_pri status=%xh\n", ret);
842 ret = DDI_FAILURE;
843 goto release_intr;
845 qlt_init_mutex(qlt);
847 /* add handler */
848 for (i = 0; i < actual; i++) {
849 ret = ddi_intr_add_handler(qlt->htable[i], qlt_isr,
850 qlt, INT2PTR((uint_t)i, void *));
851 if (ret != DDI_SUCCESS) {
852 EL(qlt, "ddi_intr_add_handler status=%xh\n", ret);
853 goto release_mutex;
857 (void) ddi_intr_get_cap(qlt->htable[0], &qlt->intr_cap);
858 qlt->intr_flags |= QLT_INTR_MSI;
859 return (DDI_SUCCESS);
861 release_mutex:
862 qlt_destroy_mutex(qlt);
863 release_intr:
864 for (i = 0; i < actual; i++)
865 (void) ddi_intr_free(qlt->htable[i]);
866 free_mem:
867 kmem_free(qlt->htable, (uint_t)qlt->intr_size);
868 qlt->htable = NULL;
869 qlt_release_intr(qlt);
870 return (ret);
873 static int
874 qlt_setup_fixed(qlt_state_t *qlt)
876 int count;
877 int actual;
878 int ret;
879 int itype = DDI_INTR_TYPE_FIXED;
881 ret = ddi_intr_get_nintrs(qlt->dip, itype, &count);
882 /* Fixed interrupts can only have one interrupt. */
883 if (ret != DDI_SUCCESS || count != 1) {
884 EL(qlt, "ddi_intr_get_nintrs status=%xh, count=%d\n", ret,
885 count);
886 return (DDI_FAILURE);
889 qlt->intr_size = sizeof (ddi_intr_handle_t);
890 qlt->htable = kmem_zalloc((uint_t)qlt->intr_size, KM_SLEEP);
891 ret = ddi_intr_alloc(qlt->dip, qlt->htable, itype,
892 DDI_INTR_ALLOC_NORMAL, count, &actual, 0);
893 if (ret != DDI_SUCCESS || actual != 1) {
894 EL(qlt, "ddi_intr_alloc status=%xh, actual=%d\n", ret,
895 actual);
896 ret = DDI_FAILURE;
897 goto free_mem;
900 qlt->intr_cnt = actual;
901 ret = ddi_intr_get_pri(qlt->htable[0], &qlt->intr_pri);
902 if (ret != DDI_SUCCESS) {
903 EL(qlt, "ddi_intr_get_pri status=%xh\n", ret);
904 ret = DDI_FAILURE;
905 goto release_intr;
907 qlt_init_mutex(qlt);
908 ret = ddi_intr_add_handler(qlt->htable[0], qlt_isr, qlt, 0);
909 if (ret != DDI_SUCCESS) {
910 EL(qlt, "ddi_intr_add_handler status=%xh\n", ret);
911 goto release_mutex;
914 qlt->intr_flags |= QLT_INTR_FIXED;
915 return (DDI_SUCCESS);
917 release_mutex:
918 qlt_destroy_mutex(qlt);
919 release_intr:
920 (void) ddi_intr_free(qlt->htable[0]);
921 free_mem:
922 kmem_free(qlt->htable, (uint_t)qlt->intr_size);
923 qlt->htable = NULL;
924 qlt_release_intr(qlt);
925 return (ret);
928 static int
929 qlt_setup_interrupts(qlt_state_t *qlt)
931 int itypes = 0;
934 * x86 has a bug in the ddi_intr_block_enable/disable area (6562198).
936 if (qlt_enable_msi != 0) {
937 if (ddi_intr_get_supported_types(qlt->dip, &itypes) != DDI_SUCCESS) {
938 itypes = DDI_INTR_TYPE_FIXED;
941 if (qlt_enable_msix && (itypes & DDI_INTR_TYPE_MSIX)) {
942 if (qlt_setup_msix(qlt) == DDI_SUCCESS)
943 return (DDI_SUCCESS);
946 if (itypes & DDI_INTR_TYPE_MSI) {
947 if (qlt_setup_msi(qlt) == DDI_SUCCESS)
948 return (DDI_SUCCESS);
951 return (qlt_setup_fixed(qlt));
955 * Filling the hba attributes
957 void
958 qlt_populate_hba_fru_details(struct fct_local_port *port,
959 struct fct_port_attrs *port_attrs)
961 caddr_t bufp;
962 int len;
963 qlt_state_t *qlt = (qlt_state_t *)port->port_fca_private;
965 (void) snprintf(port_attrs->manufacturer, FCHBA_MANUFACTURER_LEN,
966 "QLogic Corp.");
967 (void) snprintf(port_attrs->driver_name, FCHBA_DRIVER_NAME_LEN,
968 "%s", QLT_NAME);
969 (void) snprintf(port_attrs->driver_version, FCHBA_DRIVER_VERSION_LEN,
970 "%s", QLT_VERSION);
971 port_attrs->serial_number[0] = '\0';
972 port_attrs->hardware_version[0] = '\0';
974 (void) snprintf(port_attrs->firmware_version,
975 FCHBA_FIRMWARE_VERSION_LEN, "%d.%d.%d", qlt->fw_major,
976 qlt->fw_minor, qlt->fw_subminor);
978 /* Get FCode version */
979 if (ddi_getlongprop(DDI_DEV_T_ANY, qlt->dip, PROP_LEN_AND_VAL_ALLOC |
980 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "version", (caddr_t)&bufp,
981 (int *)&len) == DDI_PROP_SUCCESS) {
982 (void) snprintf(port_attrs->option_rom_version,
983 FCHBA_OPTION_ROM_VERSION_LEN, "%s", bufp);
984 kmem_free(bufp, (uint_t)len);
985 bufp = NULL;
986 } else {
987 (void) snprintf(port_attrs->option_rom_version,
988 FCHBA_OPTION_ROM_VERSION_LEN, "N/A");
990 port_attrs->vendor_specific_id = qlt->nvram->subsystem_vendor_id[0] |
991 qlt->nvram->subsystem_vendor_id[1] << 8;
993 port_attrs->max_frame_size = qlt->nvram->max_frame_length[1] << 8 |
994 qlt->nvram->max_frame_length[0];
996 port_attrs->supported_cos = 0x10000000;
997 port_attrs->supported_speed = PORT_SPEED_1G |
998 PORT_SPEED_2G | PORT_SPEED_4G;
999 if (qlt->qlt_25xx_chip)
1000 port_attrs->supported_speed = PORT_SPEED_2G | PORT_SPEED_4G |
1001 PORT_SPEED_8G;
1002 if (qlt->qlt_81xx_chip)
1003 port_attrs->supported_speed = PORT_SPEED_10G;
1005 /* limit string length to nvr model_name length */
1006 len = (qlt->qlt_81xx_chip) ? 16 : 8;
1007 (void) snprintf(port_attrs->model,
1008 (uint_t)(len < FCHBA_MODEL_LEN ? len : FCHBA_MODEL_LEN),
1009 "%s", qlt->nvram->model_name);
1011 (void) snprintf(port_attrs->model_description,
1012 (uint_t)(len < FCHBA_MODEL_DESCRIPTION_LEN ? len :
1013 FCHBA_MODEL_DESCRIPTION_LEN),
1014 "%s", qlt->nvram->model_name);
1017 /* ARGSUSED */
1018 fct_status_t
1019 qlt_info(uint32_t cmd, fct_local_port_t *port,
1020 void *arg, uint8_t *buf, uint32_t *bufsizep)
1022 qlt_state_t *qlt = (qlt_state_t *)port->port_fca_private;
1023 mbox_cmd_t *mcp;
1024 fct_status_t ret = FCT_SUCCESS;
1025 uint8_t *p;
1026 fct_port_link_status_t *link_status;
1028 switch (cmd) {
1029 case FC_TGT_PORT_RLS:
1030 if ((*bufsizep) < sizeof (fct_port_link_status_t)) {
1031 EL(qlt, "FC_TGT_PORT_RLS bufsizep=%xh < "
1032 "fct_port_link_status_t=%xh\n", *bufsizep,
1033 sizeof (fct_port_link_status_t));
1034 ret = FCT_FAILURE;
1035 break;
1037 /* send mailbox command to get link status */
1038 mcp = qlt_alloc_mailbox_command(qlt, 156);
1039 if (mcp == NULL) {
1040 EL(qlt, "qlt_alloc_mailbox_command mcp=null\n");
1041 ret = FCT_ALLOC_FAILURE;
1042 break;
1045 /* GET LINK STATUS count */
1046 mcp->to_fw[0] = MBC_GET_STATUS_COUNTS;
1047 mcp->to_fw[8] = 156/4;
1048 mcp->to_fw_mask |= BIT_1 | BIT_8;
1049 mcp->from_fw_mask |= BIT_1 | BIT_2;
1051 ret = qlt_mailbox_command(qlt, mcp);
1052 if (ret != QLT_SUCCESS) {
1053 EL(qlt, "qlt_mailbox_command=6dh status=%llxh\n", ret);
1054 qlt_free_mailbox_command(qlt, mcp);
1055 break;
1057 qlt_dmem_dma_sync(mcp->dbuf, DDI_DMA_SYNC_FORCPU);
1059 p = mcp->dbuf->db_sglist[0].seg_addr;
1060 link_status = (fct_port_link_status_t *)buf;
1061 link_status->LinkFailureCount = LE_32(*((uint32_t *)p));
1062 link_status->LossOfSyncCount = LE_32(*((uint32_t *)(p + 4)));
1063 link_status->LossOfSignalsCount = LE_32(*((uint32_t *)(p + 8)));
1064 link_status->PrimitiveSeqProtocolErrorCount =
1065 LE_32(*((uint32_t *)(p + 12)));
1066 link_status->InvalidTransmissionWordCount =
1067 LE_32(*((uint32_t *)(p + 16)));
1068 link_status->InvalidCRCCount =
1069 LE_32(*((uint32_t *)(p + 20)));
1071 qlt_free_mailbox_command(qlt, mcp);
1072 break;
1073 default:
1074 EL(qlt, "Unknown cmd=%xh\n", cmd);
1075 ret = FCT_FAILURE;
1076 break;
1078 return (ret);
1081 fct_status_t
1082 qlt_port_start(caddr_t arg)
1084 qlt_state_t *qlt = (qlt_state_t *)arg;
1085 fct_local_port_t *port;
1086 fct_dbuf_store_t *fds;
1087 fct_status_t ret;
1089 if (qlt_dmem_init(qlt) != QLT_SUCCESS) {
1090 return (FCT_FAILURE);
1092 /* Initialize the ddi_dma_handle free pool */
1093 qlt_dma_handle_pool_init(qlt);
1095 port = (fct_local_port_t *)fct_alloc(FCT_STRUCT_LOCAL_PORT, 0, 0);
1096 if (port == NULL) {
1097 goto qlt_pstart_fail_1;
1099 fds = (fct_dbuf_store_t *)fct_alloc(FCT_STRUCT_DBUF_STORE, 0, 0);
1100 if (fds == NULL) {
1101 goto qlt_pstart_fail_2;
1103 qlt->qlt_port = port;
1104 fds->fds_alloc_data_buf = qlt_dmem_alloc;
1105 fds->fds_free_data_buf = qlt_dmem_free;
1106 fds->fds_setup_dbuf = qlt_dma_setup_dbuf;
1107 fds->fds_teardown_dbuf = qlt_dma_teardown_dbuf;
1108 fds->fds_max_sgl_xfer_len = QLT_DMA_SG_LIST_LENGTH * MMU_PAGESIZE;
1109 fds->fds_copy_threshold = MMU_PAGESIZE;
1110 fds->fds_fca_private = (void *)qlt;
1112 * Since we keep everything in the state struct and dont allocate any
1113 * port private area, just use that pointer to point to the
1114 * state struct.
1116 port->port_fca_private = qlt;
1117 port->port_fca_abort_timeout = 5 * 1000; /* 5 seconds */
1118 bcopy(qlt->nvram->node_name, port->port_nwwn, 8);
1119 bcopy(qlt->nvram->port_name, port->port_pwwn, 8);
1120 fct_wwn_to_str(port->port_nwwn_str, port->port_nwwn);
1121 fct_wwn_to_str(port->port_pwwn_str, port->port_pwwn);
1122 port->port_default_alias = qlt->qlt_port_alias;
1123 port->port_pp = qlt_pp;
1124 port->port_fds = fds;
1125 port->port_max_logins = QLT_MAX_LOGINS;
1126 port->port_max_xchges = QLT_MAX_XCHGES;
1127 port->port_fca_fcp_cmd_size = sizeof (qlt_cmd_t);
1128 port->port_fca_rp_private_size = sizeof (qlt_remote_port_t);
1129 port->port_fca_sol_els_private_size = sizeof (qlt_cmd_t);
1130 port->port_fca_sol_ct_private_size = sizeof (qlt_cmd_t);
1131 port->port_get_link_info = qlt_get_link_info;
1132 port->port_register_remote_port = qlt_register_remote_port;
1133 port->port_deregister_remote_port = qlt_deregister_remote_port;
1134 port->port_send_cmd = qlt_send_cmd;
1135 port->port_xfer_scsi_data = qlt_xfer_scsi_data;
1136 port->port_send_cmd_response = qlt_send_cmd_response;
1137 port->port_abort_cmd = qlt_abort_cmd;
1138 port->port_ctl = qlt_ctl;
1139 port->port_flogi_xchg = qlt_do_flogi;
1140 port->port_populate_hba_details = qlt_populate_hba_fru_details;
1141 port->port_info = qlt_info;
1142 port->port_fca_version = FCT_FCA_MODREV_1;
1144 if ((ret = fct_register_local_port(port)) != FCT_SUCCESS) {
1145 EL(qlt, "fct_register_local_port status=%llxh\n", ret);
1146 goto qlt_pstart_fail_2_5;
1149 return (QLT_SUCCESS);
1150 #if 0
1151 qlt_pstart_fail_3:
1152 (void) fct_deregister_local_port(port);
1153 #endif
1154 qlt_pstart_fail_2_5:
1155 fct_free(fds);
1156 qlt_pstart_fail_2:
1157 fct_free(port);
1158 qlt->qlt_port = NULL;
1159 qlt_pstart_fail_1:
1160 qlt_dma_handle_pool_fini(qlt);
1161 qlt_dmem_fini(qlt);
1162 return (QLT_FAILURE);
1165 fct_status_t
1166 qlt_port_stop(caddr_t arg)
1168 qlt_state_t *qlt = (qlt_state_t *)arg;
1169 fct_status_t ret;
1171 if ((ret = fct_deregister_local_port(qlt->qlt_port)) != FCT_SUCCESS) {
1172 EL(qlt, "fct_register_local_port status=%llxh\n", ret);
1173 return (QLT_FAILURE);
1175 fct_free(qlt->qlt_port->port_fds);
1176 fct_free(qlt->qlt_port);
1177 qlt->qlt_port = NULL;
1178 qlt_dma_handle_pool_fini(qlt);
1179 qlt_dmem_fini(qlt);
1180 return (QLT_SUCCESS);
1184 * Called by framework to init the HBA.
1185 * Can be called in the middle of I/O. (Why ??)
1186 * Should make sure sane state both before and after the initialization
1188 fct_status_t
1189 qlt_port_online(qlt_state_t *qlt)
1191 uint64_t da;
1192 int instance, i;
1193 fct_status_t ret;
1194 uint16_t rcount;
1195 caddr_t icb;
1196 mbox_cmd_t *mcp;
1197 uint8_t *elsbmp;
1199 instance = ddi_get_instance(qlt->dip);
1201 /* XXX Make sure a sane state */
1203 if ((ret = qlt_download_fw(qlt)) != QLT_SUCCESS) {
1204 cmn_err(CE_NOTE, "reset chip failed %llx", (long long)ret);
1205 return (ret);
1208 bzero(qlt->queue_mem_ptr, TOTAL_DMA_MEM_SIZE);
1210 /* Get resource count */
1211 REG_WR16(qlt, REG_MBOX(0), MBC_GET_RESOURCE_COUNTS);
1212 ret = qlt_raw_mailbox_command(qlt);
1213 rcount = REG_RD16(qlt, REG_MBOX(3));
1214 REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
1215 if (ret != QLT_SUCCESS) {
1216 EL(qlt, "qlt_raw_mailbox_command=42h status=%llxh\n", ret);
1217 return (ret);
1220 /* Enable PUREX */
1221 REG_WR16(qlt, REG_MBOX(0), MBC_SET_ADDITIONAL_FIRMWARE_OPT);
1222 REG_WR16(qlt, REG_MBOX(1), OPT_PUREX_ENABLE);
1223 REG_WR16(qlt, REG_MBOX(2), 0x0);
1224 REG_WR16(qlt, REG_MBOX(3), 0x0);
1225 ret = qlt_raw_mailbox_command(qlt);
1226 REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
1227 if (ret != QLT_SUCCESS) {
1228 EL(qlt, "qlt_raw_mailbox_command=38h status=%llxh\n", ret);
1229 cmn_err(CE_NOTE, "Enable PUREX failed");
1230 return (ret);
1233 /* Pass ELS bitmap to fw */
1234 REG_WR16(qlt, REG_MBOX(0), MBC_SET_PARAMETERS);
1235 REG_WR16(qlt, REG_MBOX(1), PARAM_TYPE(PUREX_ELS_CMDS));
1236 elsbmp = (uint8_t *)qlt->queue_mem_ptr + MBOX_DMA_MEM_OFFSET;
1237 bzero(elsbmp, 32);
1238 da = qlt->queue_mem_cookie.dmac_laddress;
1239 da += MBOX_DMA_MEM_OFFSET;
1240 REG_WR16(qlt, REG_MBOX(3), LSW(LSD(da)));
1241 REG_WR16(qlt, REG_MBOX(2), MSW(LSD(da)));
1242 REG_WR16(qlt, REG_MBOX(7), LSW(MSD(da)));
1243 REG_WR16(qlt, REG_MBOX(6), MSW(MSD(da)));
1244 SETELSBIT(elsbmp, ELS_OP_PLOGI);
1245 SETELSBIT(elsbmp, ELS_OP_LOGO);
1246 SETELSBIT(elsbmp, ELS_OP_ABTX);
1247 SETELSBIT(elsbmp, ELS_OP_ECHO);
1248 SETELSBIT(elsbmp, ELS_OP_PRLI);
1249 SETELSBIT(elsbmp, ELS_OP_PRLO);
1250 SETELSBIT(elsbmp, ELS_OP_SCN);
1251 SETELSBIT(elsbmp, ELS_OP_TPRLO);
1252 SETELSBIT(elsbmp, ELS_OP_PDISC);
1253 SETELSBIT(elsbmp, ELS_OP_ADISC);
1254 SETELSBIT(elsbmp, ELS_OP_RSCN);
1255 SETELSBIT(elsbmp, ELS_OP_RNID);
1256 (void) ddi_dma_sync(qlt->queue_mem_dma_handle, MBOX_DMA_MEM_OFFSET, 32,
1257 DDI_DMA_SYNC_FORDEV);
1258 ret = qlt_raw_mailbox_command(qlt);
1259 REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
1260 if (ret != QLT_SUCCESS) {
1261 EL(qlt, "qlt_raw_mailbox_command=59h status=llxh\n", ret);
1262 cmn_err(CE_NOTE, "Set ELS Bitmap failed ret=%llx, "
1263 "elsbmp0=%x elabmp1=%x", (long long)ret, elsbmp[0],
1264 elsbmp[1]);
1265 return (ret);
1268 /* Init queue pointers */
1269 REG_WR32(qlt, REG_REQ_IN_PTR, 0);
1270 REG_WR32(qlt, REG_REQ_OUT_PTR, 0);
1271 REG_WR32(qlt, REG_RESP_IN_PTR, 0);
1272 REG_WR32(qlt, REG_RESP_OUT_PTR, 0);
1273 REG_WR32(qlt, REG_PREQ_IN_PTR, 0);
1274 REG_WR32(qlt, REG_PREQ_OUT_PTR, 0);
1275 REG_WR32(qlt, REG_ATIO_IN_PTR, 0);
1276 REG_WR32(qlt, REG_ATIO_OUT_PTR, 0);
1277 qlt->req_ndx_to_fw = qlt->req_ndx_from_fw = 0;
1278 qlt->req_available = REQUEST_QUEUE_ENTRIES - 1;
1279 qlt->resp_ndx_to_fw = qlt->resp_ndx_from_fw = 0;
1280 qlt->preq_ndx_to_fw = qlt->preq_ndx_from_fw = 0;
1281 qlt->atio_ndx_to_fw = qlt->atio_ndx_from_fw = 0;
1284 * XXX support for tunables. Also should we cache icb ?
1286 if (qlt->qlt_81xx_chip) {
1287 /* allocate extra 64 bytes for Extended init control block */
1288 mcp = qlt_alloc_mailbox_command(qlt, 0xC0);
1289 } else {
1290 mcp = qlt_alloc_mailbox_command(qlt, 0x80);
1292 if (mcp == NULL) {
1293 EL(qlt, "qlt_alloc_mailbox_command mcp=null\n");
1294 return (STMF_ALLOC_FAILURE);
1296 icb = (caddr_t)mcp->dbuf->db_sglist[0].seg_addr;
1297 if (qlt->qlt_81xx_chip) {
1298 bzero(icb, 0xC0);
1299 } else {
1300 bzero(icb, 0x80);
1302 da = qlt->queue_mem_cookie.dmac_laddress;
1303 DMEM_WR16(qlt, icb, 1); /* Version */
1304 DMEM_WR16(qlt, icb+4, 2112); /* Max frame length */
1305 DMEM_WR16(qlt, icb+6, 16); /* Execution throttle */
1306 DMEM_WR16(qlt, icb+8, rcount); /* Xchg count */
1307 DMEM_WR16(qlt, icb+0x0a, 0x00); /* Hard address (not used) */
1308 bcopy(qlt->qlt_port->port_pwwn, icb+0x0c, 8);
1309 bcopy(qlt->qlt_port->port_nwwn, icb+0x14, 8);
1310 DMEM_WR16(qlt, icb+0x20, 3); /* Login retry count */
1311 DMEM_WR16(qlt, icb+0x24, RESPONSE_QUEUE_ENTRIES);
1312 DMEM_WR16(qlt, icb+0x26, REQUEST_QUEUE_ENTRIES);
1313 if (!qlt->qlt_81xx_chip) {
1314 DMEM_WR16(qlt, icb+0x28, 100); /* ms of NOS/OLS for Link down */
1316 DMEM_WR16(qlt, icb+0x2a, PRIORITY_QUEUE_ENTRIES);
1317 DMEM_WR64(qlt, icb+0x2c, (da+REQUEST_QUEUE_OFFSET));
1318 DMEM_WR64(qlt, icb+0x34, (da+RESPONSE_QUEUE_OFFSET));
1319 DMEM_WR64(qlt, icb+0x3c, (da+PRIORITY_QUEUE_OFFSET));
1320 DMEM_WR16(qlt, icb+0x4e, ATIO_QUEUE_ENTRIES);
1321 DMEM_WR64(qlt, icb+0x50, (da+ATIO_QUEUE_OFFSET));
1322 DMEM_WR16(qlt, icb+0x58, 2); /* Interrupt delay Timer */
1323 DMEM_WR16(qlt, icb+0x5a, 4); /* Login timeout (secs) */
1324 if (qlt->qlt_81xx_chip) {
1325 qlt_nvram_81xx_t *qlt81nvr = (qlt_nvram_81xx_t *)qlt->nvram;
1327 DMEM_WR32(qlt, icb+0x5c, BIT_5 | BIT_4); /* fw options 1 */
1328 DMEM_WR32(qlt, icb+0x64, BIT_20 | BIT_4); /* fw options 3 */
1329 DMEM_WR32(qlt, icb+0x70,
1330 qlt81nvr->enode_mac[0] |
1331 (qlt81nvr->enode_mac[1] << 8) |
1332 (qlt81nvr->enode_mac[2] << 16) |
1333 (qlt81nvr->enode_mac[3] << 24));
1334 DMEM_WR16(qlt, icb+0x74,
1335 qlt81nvr->enode_mac[4] |
1336 (qlt81nvr->enode_mac[5] << 8));
1337 } else {
1338 DMEM_WR32(qlt, icb+0x5c, BIT_11 | BIT_5 | BIT_4 |
1339 BIT_2 | BIT_1 | BIT_0);
1340 DMEM_WR32(qlt, icb+0x60, BIT_5);
1341 DMEM_WR32(qlt, icb+0x64, BIT_14 | BIT_8 | BIT_7 |
1342 BIT_4);
1345 if (qlt->qlt_81xx_chip) {
1346 qlt_dmem_bctl_t *bctl;
1347 uint32_t index;
1348 caddr_t src;
1349 caddr_t dst;
1350 qlt_nvram_81xx_t *qlt81nvr;
1352 dst = icb+0x80;
1353 qlt81nvr = (qlt_nvram_81xx_t *)qlt->nvram;
1354 src = (caddr_t)&qlt81nvr->ext_blk;
1355 index = sizeof (qlt_ext_icb_81xx_t);
1357 /* Use defaults for cases where we find nothing in NVR */
1358 if (*src == 0) {
1359 EL(qlt, "nvram eicb=null\n");
1360 cmn_err(CE_NOTE, "qlt(%d) NVR eicb is zeroed",
1361 instance);
1362 qlt81nvr->ext_blk.version[0] = 1;
1364 * not yet, for !FIP firmware at least
1366 * qlt81nvr->ext_blk.fcf_vlan_match = 0x81;
1368 #ifdef _LITTLE_ENDIAN
1369 qlt81nvr->ext_blk.fcf_vlan_id[0] = 0xEA;
1370 qlt81nvr->ext_blk.fcf_vlan_id[1] = 0x03;
1371 #else
1372 qlt81nvr->ext_blk.fcf_vlan_id[1] = 0xEA;
1373 qlt81nvr->ext_blk.fcf_vlan_id[0] = 0x03;
1374 #endif
1377 while (index--) {
1378 *dst++ = *src++;
1381 bctl = (qlt_dmem_bctl_t *)mcp->dbuf->db_port_private;
1382 da = bctl->bctl_dev_addr + 0x80; /* base addr of eicb (phys) */
1384 mcp->to_fw[11] = LSW(LSD(da));
1385 mcp->to_fw[10] = MSW(LSD(da));
1386 mcp->to_fw[13] = LSW(MSD(da));
1387 mcp->to_fw[12] = MSW(MSD(da));
1388 mcp->to_fw[14] = (uint16_t)(sizeof (qlt_ext_icb_81xx_t) &
1389 0xffff);
1391 /* eicb enable */
1392 mcp->to_fw[1] = (uint16_t)(mcp->to_fw[1] | BIT_0);
1393 mcp->to_fw_mask |= BIT_14 | BIT_13 | BIT_12 | BIT_11 | BIT_10 |
1394 BIT_1;
1397 qlt_dmem_dma_sync(mcp->dbuf, DDI_DMA_SYNC_FORDEV);
1398 mcp->to_fw[0] = MBC_INITIALIZE_FIRMWARE;
1401 * This is the 1st command after adapter initialize which will
1402 * use interrupts and regular mailbox interface.
1404 qlt->mbox_io_state = MBOX_STATE_READY;
1405 REG_WR32(qlt, REG_INTR_CTRL, ENABLE_RISC_INTR);
1406 /* Issue mailbox to firmware */
1407 ret = qlt_mailbox_command(qlt, mcp);
1408 if (ret != QLT_SUCCESS) {
1409 EL(qlt, "qlt_mailbox_command=60h status=%llxh\n", ret);
1410 cmn_err(CE_NOTE, "qlt(%d) init fw failed %llx, intr status %x",
1411 instance, (long long)ret, REG_RD32(qlt, REG_INTR_STATUS));
1414 mcp->to_fw_mask = BIT_0;
1415 mcp->from_fw_mask = BIT_0 | BIT_1;
1416 mcp->to_fw[0] = 0x28;
1417 ret = qlt_mailbox_command(qlt, mcp);
1418 if (ret != QLT_SUCCESS) {
1419 EL(qlt, "qlt_mailbox_command=28h status=%llxh\n", ret);
1420 cmn_err(CE_NOTE, "qlt(%d) get_fw_options %llx", instance,
1421 (long long)ret);
1425 * Report FW versions for 81xx - MPI rev is useful
1427 if (qlt->qlt_81xx_chip) {
1428 mcp->to_fw_mask = BIT_0;
1429 mcp->from_fw_mask = BIT_11 | BIT_10 | BIT_3 | BIT_2 | BIT_1 |
1430 BIT_0;
1431 mcp->to_fw[0] = 0x8;
1432 ret = qlt_mailbox_command(qlt, mcp);
1433 if (ret != QLT_SUCCESS) {
1434 EL(qlt, "about fw failed: %llx\n", (long long)ret);
1435 } else {
1436 EL(qlt, "Firmware version %d.%d.%d, MPI: %d.%d.%d\n",
1437 mcp->from_fw[1], mcp->from_fw[2], mcp->from_fw[3],
1438 mcp->from_fw[10] & 0xff, mcp->from_fw[11] >> 8,
1439 mcp->from_fw[11] & 0xff);
1443 qlt_free_mailbox_command(qlt, mcp);
1445 for (i = 0; i < 5; i++) {
1446 qlt->qlt_bufref[i] = 0;
1448 qlt->qlt_bumpbucket = 0;
1449 qlt->qlt_pmintry = 0;
1450 qlt->qlt_pmin_ok = 0;
1452 if (ret != QLT_SUCCESS)
1453 return (ret);
1454 return (FCT_SUCCESS);
1457 fct_status_t
1458 qlt_port_offline(qlt_state_t *qlt)
1460 int retries;
1462 mutex_enter(&qlt->mbox_lock);
1464 if (qlt->mbox_io_state == MBOX_STATE_UNKNOWN) {
1465 mutex_exit(&qlt->mbox_lock);
1466 goto poff_mbox_done;
1469 /* Wait to grab the mailboxes */
1470 for (retries = 0; qlt->mbox_io_state != MBOX_STATE_READY;
1471 retries++) {
1472 cv_wait(&qlt->mbox_cv, &qlt->mbox_lock);
1473 if ((retries > 5) ||
1474 (qlt->mbox_io_state == MBOX_STATE_UNKNOWN)) {
1475 qlt->mbox_io_state = MBOX_STATE_UNKNOWN;
1476 mutex_exit(&qlt->mbox_lock);
1477 goto poff_mbox_done;
1480 qlt->mbox_io_state = MBOX_STATE_UNKNOWN;
1481 mutex_exit(&qlt->mbox_lock);
1482 poff_mbox_done:;
1483 qlt->intr_sneak_counter = 10;
1484 mutex_enter(&qlt->intr_lock);
1485 (void) qlt_reset_chip(qlt);
1486 drv_usecwait(20);
1487 qlt->intr_sneak_counter = 0;
1488 mutex_exit(&qlt->intr_lock);
1490 return (FCT_SUCCESS);
1493 static fct_status_t
1494 qlt_get_link_info(fct_local_port_t *port, fct_link_info_t *li)
1496 qlt_state_t *qlt = (qlt_state_t *)port->port_fca_private;
1497 mbox_cmd_t *mcp;
1498 fct_status_t fc_ret;
1499 fct_status_t ret;
1500 clock_t et;
1502 et = ddi_get_lbolt() + drv_usectohz(5000000);
1503 mcp = qlt_alloc_mailbox_command(qlt, 0);
1504 link_info_retry:
1505 mcp->to_fw[0] = MBC_GET_ID;
1506 mcp->to_fw[9] = 0;
1507 mcp->to_fw_mask |= BIT_0 | BIT_9;
1508 mcp->from_fw_mask |= BIT_0 | BIT_1 | BIT_2 | BIT_3 | BIT_6 | BIT_7;
1509 /* Issue mailbox to firmware */
1510 ret = qlt_mailbox_command(qlt, mcp);
1511 if (ret != QLT_SUCCESS) {
1512 EL(qlt, "qlt_mailbox_command=20h status=%llxh\n", ret);
1513 if ((mcp->from_fw[0] == 0x4005) && (mcp->from_fw[1] == 7)) {
1514 /* Firmware is not ready */
1515 if (ddi_get_lbolt() < et) {
1516 delay(drv_usectohz(50000));
1517 goto link_info_retry;
1520 stmf_trace(qlt->qlt_port_alias, "GET ID mbox failed, ret=%llx "
1521 "mb0=%x mb1=%x", ret, mcp->from_fw[0], mcp->from_fw[1]);
1522 fc_ret = FCT_FAILURE;
1523 } else {
1524 li->portid = ((uint32_t)(mcp->from_fw[2])) |
1525 (((uint32_t)(mcp->from_fw[3])) << 16);
1527 li->port_speed = qlt->link_speed;
1528 switch (mcp->from_fw[6]) {
1529 case 1:
1530 li->port_topology = PORT_TOPOLOGY_PUBLIC_LOOP;
1531 li->port_fca_flogi_done = 1;
1532 break;
1533 case 0:
1534 li->port_topology = PORT_TOPOLOGY_PRIVATE_LOOP;
1535 li->port_no_fct_flogi = 1;
1536 break;
1537 case 3:
1538 li->port_topology = PORT_TOPOLOGY_FABRIC_PT_TO_PT;
1539 li->port_fca_flogi_done = 1;
1540 break;
1541 case 2: /*FALLTHROUGH*/
1542 case 4:
1543 li->port_topology = PORT_TOPOLOGY_PT_TO_PT;
1544 li->port_fca_flogi_done = 1;
1545 break;
1546 default:
1547 li->port_topology = PORT_TOPOLOGY_UNKNOWN;
1548 EL(qlt, "Unknown topology=%xh\n", mcp->from_fw[6]);
1550 qlt->cur_topology = li->port_topology;
1551 fc_ret = FCT_SUCCESS;
1553 qlt_free_mailbox_command(qlt, mcp);
1555 if ((fc_ret == FCT_SUCCESS) && (li->port_fca_flogi_done)) {
1556 mcp = qlt_alloc_mailbox_command(qlt, 64);
1557 mcp->to_fw[0] = MBC_GET_PORT_DATABASE;
1558 mcp->to_fw[1] = 0x7FE;
1559 mcp->to_fw[9] = 0;
1560 mcp->to_fw[10] = 0;
1561 mcp->to_fw_mask |= BIT_0 | BIT_1 | BIT_9 | BIT_10;
1562 fc_ret = qlt_mailbox_command(qlt, mcp);
1563 if (fc_ret != QLT_SUCCESS) {
1564 EL(qlt, "qlt_mailbox_command=64h status=%llxh\n",
1565 fc_ret);
1566 stmf_trace(qlt->qlt_port_alias, "Attempt to get port "
1567 "database for F_port failed, ret = %llx", fc_ret);
1568 } else {
1569 uint8_t *p;
1571 qlt_dmem_dma_sync(mcp->dbuf, DDI_DMA_SYNC_FORCPU);
1572 p = mcp->dbuf->db_sglist[0].seg_addr;
1573 bcopy(p + 0x18, li->port_rpwwn, 8);
1574 bcopy(p + 0x20, li->port_rnwwn, 8);
1576 qlt_free_mailbox_command(qlt, mcp);
1578 return (fc_ret);
1581 static int
1582 qlt_open(dev_t *devp, int flag, int otype, cred_t *credp)
1584 int instance;
1585 qlt_state_t *qlt;
1587 if (otype != OTYP_CHR) {
1588 return (EINVAL);
1592 * Since this is for debugging only, only allow root to issue ioctl now
1594 if (drv_priv(credp)) {
1595 return (EPERM);
1598 instance = (int)getminor(*devp);
1599 qlt = ddi_get_soft_state(qlt_state, instance);
1600 if (qlt == NULL) {
1601 return (ENXIO);
1604 mutex_enter(&qlt->qlt_ioctl_lock);
1605 if (qlt->qlt_ioctl_flags & QLT_IOCTL_FLAG_EXCL) {
1607 * It is already open for exclusive access.
1608 * So shut the door on this caller.
1610 mutex_exit(&qlt->qlt_ioctl_lock);
1611 return (EBUSY);
1614 if (flag & FEXCL) {
1615 if (qlt->qlt_ioctl_flags & QLT_IOCTL_FLAG_OPEN) {
1617 * Exclusive operation not possible
1618 * as it is already opened
1620 mutex_exit(&qlt->qlt_ioctl_lock);
1621 return (EBUSY);
1623 qlt->qlt_ioctl_flags |= QLT_IOCTL_FLAG_EXCL;
1625 qlt->qlt_ioctl_flags |= QLT_IOCTL_FLAG_OPEN;
1626 mutex_exit(&qlt->qlt_ioctl_lock);
1628 return (0);
1631 /* ARGSUSED */
1632 static int
1633 qlt_close(dev_t dev, int flag, int otype, cred_t *credp)
1635 int instance;
1636 qlt_state_t *qlt;
1638 if (otype != OTYP_CHR) {
1639 return (EINVAL);
1642 instance = (int)getminor(dev);
1643 qlt = ddi_get_soft_state(qlt_state, instance);
1644 if (qlt == NULL) {
1645 return (ENXIO);
1648 mutex_enter(&qlt->qlt_ioctl_lock);
1649 if ((qlt->qlt_ioctl_flags & QLT_IOCTL_FLAG_OPEN) == 0) {
1650 mutex_exit(&qlt->qlt_ioctl_lock);
1651 return (ENODEV);
1655 * It looks there's one hole here, maybe there could several concurrent
1656 * shareed open session, but we never check this case.
1657 * But it will not hurt too much, disregard it now.
1659 qlt->qlt_ioctl_flags &= ~QLT_IOCTL_FLAG_MASK;
1660 mutex_exit(&qlt->qlt_ioctl_lock);
1662 return (0);
1666 * All of these ioctls are unstable interfaces which are meant to be used
1667 * in a controlled lab env. No formal testing will be (or needs to be) done
1668 * for these ioctls. Specially note that running with an additional
1669 * uploaded firmware is not supported and is provided here for test
1670 * purposes only.
1672 /* ARGSUSED */
1673 static int
1674 qlt_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
1675 cred_t *credp, int *rval)
1677 qlt_state_t *qlt;
1678 int ret = 0;
1679 #ifdef _LITTLE_ENDIAN
1680 int i;
1681 #endif
1682 stmf_iocdata_t *iocd;
1683 void *ibuf = NULL;
1684 void *obuf = NULL;
1685 uint32_t *intp;
1686 qlt_fw_info_t *fwi;
1687 mbox_cmd_t *mcp;
1688 fct_status_t st;
1689 char info[QLT_INFO_LEN];
1690 fct_status_t ret2;
1692 if (drv_priv(credp) != 0)
1693 return (EPERM);
1695 qlt = ddi_get_soft_state(qlt_state, (int32_t)getminor(dev));
1696 ret = stmf_copyin_iocdata(data, mode, &iocd, &ibuf, &obuf);
1697 if (ret)
1698 return (ret);
1699 iocd->stmf_error = 0;
1701 switch (cmd) {
1702 case QLT_IOCTL_FETCH_FWDUMP:
1703 if (iocd->stmf_obuf_size < QLT_FWDUMP_BUFSIZE) {
1704 EL(qlt, "FETCH_FWDUMP obuf_size=%d < %d\n",
1705 iocd->stmf_obuf_size, QLT_FWDUMP_BUFSIZE);
1706 ret = EINVAL;
1707 break;
1709 mutex_enter(&qlt->qlt_ioctl_lock);
1710 if (!(qlt->qlt_ioctl_flags & QLT_FWDUMP_ISVALID)) {
1711 mutex_exit(&qlt->qlt_ioctl_lock);
1712 ret = ENODATA;
1713 EL(qlt, "no fwdump\n");
1714 iocd->stmf_error = QLTIO_NO_DUMP;
1715 break;
1717 if (qlt->qlt_ioctl_flags & QLT_FWDUMP_INPROGRESS) {
1718 mutex_exit(&qlt->qlt_ioctl_lock);
1719 ret = EBUSY;
1720 EL(qlt, "fwdump inprogress\n");
1721 iocd->stmf_error = QLTIO_DUMP_INPROGRESS;
1722 break;
1724 if (qlt->qlt_ioctl_flags & QLT_FWDUMP_FETCHED_BY_USER) {
1725 mutex_exit(&qlt->qlt_ioctl_lock);
1726 ret = EEXIST;
1727 EL(qlt, "fwdump already fetched\n");
1728 iocd->stmf_error = QLTIO_ALREADY_FETCHED;
1729 break;
1731 bcopy(qlt->qlt_fwdump_buf, obuf, QLT_FWDUMP_BUFSIZE);
1732 qlt->qlt_ioctl_flags |= QLT_FWDUMP_FETCHED_BY_USER;
1733 mutex_exit(&qlt->qlt_ioctl_lock);
1735 break;
1737 case QLT_IOCTL_TRIGGER_FWDUMP:
1738 if (qlt->qlt_state != FCT_STATE_ONLINE) {
1739 ret = EACCES;
1740 iocd->stmf_error = QLTIO_NOT_ONLINE;
1741 break;
1743 (void) snprintf(info, sizeof (info), "qlt_ioctl: qlt-%p, "
1744 "user triggered FWDUMP with RFLAG_RESET", (void *)qlt);
1745 if ((ret2 = fct_port_shutdown(qlt->qlt_port,
1746 STMF_RFLAG_USER_REQUEST | STMF_RFLAG_RESET |
1747 STMF_RFLAG_COLLECT_DEBUG_DUMP, info)) != FCT_SUCCESS) {
1748 EL(qlt, "TRIGGER_FWDUMP fct_port_shutdown status="
1749 "%llxh\n", ret2);
1750 ret = EIO;
1752 break;
1753 case QLT_IOCTL_UPLOAD_FW:
1754 if ((iocd->stmf_ibuf_size < 1024) ||
1755 (iocd->stmf_ibuf_size & 3)) {
1756 EL(qlt, "UPLOAD_FW ibuf_size=%d < 1024\n",
1757 iocd->stmf_ibuf_size);
1758 ret = EINVAL;
1759 iocd->stmf_error = QLTIO_INVALID_FW_SIZE;
1760 break;
1762 intp = (uint32_t *)ibuf;
1763 #ifdef _LITTLE_ENDIAN
1764 for (i = 0; (i << 2) < iocd->stmf_ibuf_size; i++) {
1765 intp[i] = BSWAP_32(intp[i]);
1767 #endif
1768 if (((intp[3] << 2) >= iocd->stmf_ibuf_size) ||
1769 (((intp[intp[3] + 3] + intp[3]) << 2) !=
1770 iocd->stmf_ibuf_size)) {
1771 EL(qlt, "UPLOAD_FW fw_size=%d >= %d\n", intp[3] << 2,
1772 iocd->stmf_ibuf_size);
1773 ret = EINVAL;
1774 iocd->stmf_error = QLTIO_INVALID_FW_SIZE;
1775 break;
1777 if ((qlt->qlt_81xx_chip && ((intp[8] & 8) == 0)) ||
1778 (qlt->qlt_25xx_chip && ((intp[8] & 4) == 0)) ||
1779 (!qlt->qlt_25xx_chip && !qlt->qlt_81xx_chip &&
1780 ((intp[8] & 3) == 0))) {
1781 EL(qlt, "UPLOAD_FW fw_type=%d\n", intp[8]);
1782 ret = EACCES;
1783 iocd->stmf_error = QLTIO_INVALID_FW_TYPE;
1784 break;
1787 /* Everything looks ok, lets copy this firmware */
1788 if (qlt->fw_code01) {
1789 kmem_free(qlt->fw_code01, (qlt->fw_length01 +
1790 qlt->fw_length02) << 2);
1791 qlt->fw_code01 = NULL;
1792 } else {
1793 atomic_inc_32(&qlt_loaded_counter);
1795 qlt->fw_length01 = intp[3];
1796 qlt->fw_code01 = kmem_alloc(iocd->stmf_ibuf_size, KM_SLEEP);
1797 bcopy(intp, qlt->fw_code01, iocd->stmf_ibuf_size);
1798 qlt->fw_addr01 = intp[2];
1799 qlt->fw_code02 = &qlt->fw_code01[intp[3]];
1800 qlt->fw_addr02 = qlt->fw_code02[2];
1801 qlt->fw_length02 = qlt->fw_code02[3];
1802 break;
1804 case QLT_IOCTL_CLEAR_FW:
1805 if (qlt->fw_code01) {
1806 kmem_free(qlt->fw_code01, (qlt->fw_length01 +
1807 qlt->fw_length02) << 2);
1808 qlt->fw_code01 = NULL;
1809 atomic_dec_32(&qlt_loaded_counter);
1811 break;
1813 case QLT_IOCTL_GET_FW_INFO:
1814 if (iocd->stmf_obuf_size != sizeof (qlt_fw_info_t)) {
1815 EL(qlt, "GET_FW_INFO obuf_size=%d != %d\n",
1816 iocd->stmf_obuf_size, sizeof (qlt_fw_info_t));
1817 ret = EINVAL;
1818 break;
1820 fwi = (qlt_fw_info_t *)obuf;
1821 if (qlt->qlt_stay_offline) {
1822 fwi->fwi_stay_offline = 1;
1824 if (qlt->qlt_state == FCT_STATE_ONLINE) {
1825 fwi->fwi_port_active = 1;
1827 fwi->fwi_active_major = qlt->fw_major;
1828 fwi->fwi_active_minor = qlt->fw_minor;
1829 fwi->fwi_active_subminor = qlt->fw_subminor;
1830 fwi->fwi_active_attr = qlt->fw_attr;
1831 if (qlt->fw_code01) {
1832 fwi->fwi_fw_uploaded = 1;
1833 fwi->fwi_loaded_major = (uint16_t)qlt->fw_code01[4];
1834 fwi->fwi_loaded_minor = (uint16_t)qlt->fw_code01[5];
1835 fwi->fwi_loaded_subminor = (uint16_t)qlt->fw_code01[6];
1836 fwi->fwi_loaded_attr = (uint16_t)qlt->fw_code01[7];
1838 if (qlt->qlt_81xx_chip) {
1839 fwi->fwi_default_major = (uint16_t)fw8100_code01[4];
1840 fwi->fwi_default_minor = (uint16_t)fw8100_code01[5];
1841 fwi->fwi_default_subminor = (uint16_t)fw8100_code01[6];
1842 fwi->fwi_default_attr = (uint16_t)fw8100_code01[7];
1843 } else if (qlt->qlt_25xx_chip) {
1844 fwi->fwi_default_major = (uint16_t)fw2500_code01[4];
1845 fwi->fwi_default_minor = (uint16_t)fw2500_code01[5];
1846 fwi->fwi_default_subminor = (uint16_t)fw2500_code01[6];
1847 fwi->fwi_default_attr = (uint16_t)fw2500_code01[7];
1848 } else {
1849 fwi->fwi_default_major = (uint16_t)fw2400_code01[4];
1850 fwi->fwi_default_minor = (uint16_t)fw2400_code01[5];
1851 fwi->fwi_default_subminor = (uint16_t)fw2400_code01[6];
1852 fwi->fwi_default_attr = (uint16_t)fw2400_code01[7];
1854 break;
1856 case QLT_IOCTL_STAY_OFFLINE:
1857 if (!iocd->stmf_ibuf_size) {
1858 EL(qlt, "STAY_OFFLINE ibuf_size=%d\n",
1859 iocd->stmf_ibuf_size);
1860 ret = EINVAL;
1861 break;
1863 if (*((char *)ibuf)) {
1864 qlt->qlt_stay_offline = 1;
1865 } else {
1866 qlt->qlt_stay_offline = 0;
1868 break;
1870 case QLT_IOCTL_MBOX:
1871 if ((iocd->stmf_ibuf_size < sizeof (qlt_ioctl_mbox_t)) ||
1872 (iocd->stmf_obuf_size < sizeof (qlt_ioctl_mbox_t))) {
1873 EL(qlt, "IOCTL_MBOX ibuf_size=%d, obuf_size=%d\n",
1874 iocd->stmf_ibuf_size, iocd->stmf_obuf_size);
1875 ret = EINVAL;
1876 break;
1878 mcp = qlt_alloc_mailbox_command(qlt, 0);
1879 if (mcp == NULL) {
1880 EL(qlt, "IOCTL_MBOX mcp == NULL\n");
1881 ret = ENOMEM;
1882 break;
1884 bcopy(ibuf, mcp, sizeof (qlt_ioctl_mbox_t));
1885 st = qlt_mailbox_command(qlt, mcp);
1886 bcopy(mcp, obuf, sizeof (qlt_ioctl_mbox_t));
1887 qlt_free_mailbox_command(qlt, mcp);
1888 if (st != QLT_SUCCESS) {
1889 if ((st & (~((uint64_t)(0xFFFF)))) == QLT_MBOX_FAILED)
1890 st = QLT_SUCCESS;
1892 if (st != QLT_SUCCESS) {
1893 EL(qlt, "IOCTL_MBOX status=%xh\n", st);
1894 ret = EIO;
1895 switch (st) {
1896 case QLT_MBOX_NOT_INITIALIZED:
1897 iocd->stmf_error = QLTIO_MBOX_NOT_INITIALIZED;
1898 break;
1899 case QLT_MBOX_BUSY:
1900 iocd->stmf_error = QLTIO_CANT_GET_MBOXES;
1901 break;
1902 case QLT_MBOX_TIMEOUT:
1903 iocd->stmf_error = QLTIO_MBOX_TIMED_OUT;
1904 break;
1905 case QLT_MBOX_ABORTED:
1906 iocd->stmf_error = QLTIO_MBOX_ABORTED;
1907 break;
1910 break;
1912 case QLT_IOCTL_ELOG:
1913 qlt_dump_el_trace_buffer(qlt);
1914 break;
1916 default:
1917 EL(qlt, "Unknown ioctl-%xh\n", cmd);
1918 ret = ENOTTY;
1921 if (ret == 0) {
1922 ret = stmf_copyout_iocdata(data, mode, iocd, obuf);
1923 } else if (iocd->stmf_error) {
1924 (void) stmf_copyout_iocdata(data, mode, iocd, obuf);
1926 if (obuf) {
1927 kmem_free(obuf, iocd->stmf_obuf_size);
1928 obuf = NULL;
1930 if (ibuf) {
1931 kmem_free(ibuf, iocd->stmf_ibuf_size);
1932 ibuf = NULL;
1934 kmem_free(iocd, sizeof (stmf_iocdata_t));
1935 return (ret);
1938 static fct_status_t
1939 qlt_force_lip(qlt_state_t *qlt)
1941 mbox_cmd_t *mcp;
1942 fct_status_t rval;
1944 mcp = qlt_alloc_mailbox_command(qlt, 0);
1945 mcp->to_fw[0] = 0x0072;
1946 mcp->to_fw[1] = BIT_4;
1947 mcp->to_fw[3] = 1;
1948 mcp->to_fw_mask |= BIT_1 | BIT_3;
1949 rval = qlt_mailbox_command(qlt, mcp);
1950 if (rval != FCT_SUCCESS) {
1951 EL(qlt, "qlt force lip MB failed: rval=%x", rval);
1952 } else {
1953 if (mcp->from_fw[0] != 0x4000) {
1954 QLT_LOG(qlt->qlt_port_alias, "qlt FLIP: fw[0]=%x",
1955 mcp->from_fw[0]);
1956 rval = FCT_FAILURE;
1959 qlt_free_mailbox_command(qlt, mcp);
1960 return (rval);
1963 static void
1964 qlt_ctl(struct fct_local_port *port, int cmd, void *arg)
1966 stmf_change_status_t st;
1967 stmf_state_change_info_t *ssci = (stmf_state_change_info_t *)arg;
1968 qlt_state_t *qlt;
1969 fct_status_t ret;
1971 ASSERT((cmd == FCT_CMD_PORT_ONLINE) ||
1972 (cmd == FCT_CMD_PORT_OFFLINE) ||
1973 (cmd == FCT_CMD_FORCE_LIP) ||
1974 (cmd == FCT_ACK_PORT_ONLINE_COMPLETE) ||
1975 (cmd == FCT_ACK_PORT_OFFLINE_COMPLETE));
1977 qlt = (qlt_state_t *)port->port_fca_private;
1978 st.st_completion_status = FCT_SUCCESS;
1979 st.st_additional_info = NULL;
1981 switch (cmd) {
1982 case FCT_CMD_PORT_ONLINE:
1983 if (qlt->qlt_state == FCT_STATE_ONLINE)
1984 st.st_completion_status = STMF_ALREADY;
1985 else if (qlt->qlt_state != FCT_STATE_OFFLINE)
1986 st.st_completion_status = FCT_FAILURE;
1987 if (st.st_completion_status == FCT_SUCCESS) {
1988 qlt->qlt_state = FCT_STATE_ONLINING;
1989 qlt->qlt_state_not_acked = 1;
1990 st.st_completion_status = qlt_port_online(qlt);
1991 if (st.st_completion_status != STMF_SUCCESS) {
1992 EL(qlt, "PORT_ONLINE status=%xh\n",
1993 st.st_completion_status);
1994 qlt->qlt_state = FCT_STATE_OFFLINE;
1995 qlt->qlt_state_not_acked = 0;
1996 } else {
1997 qlt->qlt_state = FCT_STATE_ONLINE;
2000 fct_ctl(port->port_lport, FCT_CMD_PORT_ONLINE_COMPLETE, &st);
2001 qlt->qlt_change_state_flags = 0;
2002 break;
2004 case FCT_CMD_PORT_OFFLINE:
2005 if (qlt->qlt_state == FCT_STATE_OFFLINE) {
2006 st.st_completion_status = STMF_ALREADY;
2007 } else if (qlt->qlt_state != FCT_STATE_ONLINE) {
2008 st.st_completion_status = FCT_FAILURE;
2010 if (st.st_completion_status == FCT_SUCCESS) {
2011 qlt->qlt_state = FCT_STATE_OFFLINING;
2012 qlt->qlt_state_not_acked = 1;
2014 if (ssci->st_rflags & STMF_RFLAG_COLLECT_DEBUG_DUMP) {
2015 (void) qlt_firmware_dump(port, ssci);
2017 qlt->qlt_change_state_flags = (uint32_t)ssci->st_rflags;
2018 st.st_completion_status = qlt_port_offline(qlt);
2019 if (st.st_completion_status != STMF_SUCCESS) {
2020 EL(qlt, "PORT_OFFLINE status=%xh\n",
2021 st.st_completion_status);
2022 qlt->qlt_state = FCT_STATE_ONLINE;
2023 qlt->qlt_state_not_acked = 0;
2024 } else {
2025 qlt->qlt_state = FCT_STATE_OFFLINE;
2028 fct_ctl(port->port_lport, FCT_CMD_PORT_OFFLINE_COMPLETE, &st);
2029 break;
2031 case FCT_ACK_PORT_ONLINE_COMPLETE:
2032 qlt->qlt_state_not_acked = 0;
2033 break;
2035 case FCT_ACK_PORT_OFFLINE_COMPLETE:
2036 qlt->qlt_state_not_acked = 0;
2037 if ((qlt->qlt_change_state_flags & STMF_RFLAG_RESET) &&
2038 (qlt->qlt_stay_offline == 0)) {
2039 if ((ret = fct_port_initialize(port,
2040 qlt->qlt_change_state_flags,
2041 "qlt_ctl FCT_ACK_PORT_OFFLINE_COMPLETE "
2042 "with RLFLAG_RESET")) != FCT_SUCCESS) {
2043 EL(qlt, "fct_port_initialize status=%llxh\n",
2044 ret);
2045 cmn_err(CE_WARN, "qlt_ctl: "
2046 "fct_port_initialize failed, please use "
2047 "stmfstate to start the port-%s manualy",
2048 qlt->qlt_port_alias);
2051 break;
2053 case FCT_CMD_FORCE_LIP:
2054 if (qlt->qlt_81xx_chip) {
2055 EL(qlt, "force lip is an unsupported command "
2056 "for this adapter type\n");
2057 } else {
2058 *((fct_status_t *)arg) = qlt_force_lip(qlt);
2059 EL(qlt, "forcelip done\n");
2061 break;
2063 default:
2064 EL(qlt, "unsupport cmd - 0x%02X", cmd);
2065 break;
2069 /* ARGSUSED */
2070 static fct_status_t
2071 qlt_do_flogi(fct_local_port_t *port, fct_flogi_xchg_t *fx)
2073 qlt_state_t *qlt = (qlt_state_t *)port->port_fca_private;
2075 EL(qlt, "FLOGI requested not supported\n");
2076 cmn_err(CE_WARN, "qlt: FLOGI requested (not supported)");
2077 return (FCT_FAILURE);
2081 * Return a pointer to n entries in the request queue. Assumes that
2082 * request queue lock is held. Does a very short busy wait if
2083 * less/zero entries are available. Retuns NULL if it still cannot
2084 * fullfill the request.
2085 * **CALL qlt_submit_req_entries() BEFORE DROPPING THE LOCK**
2087 caddr_t
2088 qlt_get_req_entries(qlt_state_t *qlt, uint32_t n)
2090 int try = 0;
2092 while (qlt->req_available < n) {
2093 uint32_t val1, val2, val3;
2094 val1 = REG_RD32(qlt, REG_REQ_OUT_PTR);
2095 val2 = REG_RD32(qlt, REG_REQ_OUT_PTR);
2096 val3 = REG_RD32(qlt, REG_REQ_OUT_PTR);
2097 if ((val1 != val2) || (val2 != val3))
2098 continue;
2100 qlt->req_ndx_from_fw = val1;
2101 qlt->req_available = REQUEST_QUEUE_ENTRIES - 1 -
2102 ((qlt->req_ndx_to_fw - qlt->req_ndx_from_fw) &
2103 (REQUEST_QUEUE_ENTRIES - 1));
2104 if (qlt->req_available < n) {
2105 if (try < 2) {
2106 drv_usecwait(100);
2107 try++;
2108 continue;
2109 } else {
2110 stmf_trace(qlt->qlt_port_alias,
2111 "Req Q is full");
2112 return (NULL);
2115 break;
2117 /* We dont change anything until the entries are sumitted */
2118 return (&qlt->req_ptr[qlt->req_ndx_to_fw << 6]);
2122 * updates the req in ptr to fw. Assumes that req lock is held.
2124 void
2125 qlt_submit_req_entries(qlt_state_t *qlt, uint32_t n)
2127 ASSERT(n >= 1);
2128 qlt->req_ndx_to_fw += n;
2129 qlt->req_ndx_to_fw &= REQUEST_QUEUE_ENTRIES - 1;
2130 qlt->req_available -= n;
2131 REG_WR32(qlt, REG_REQ_IN_PTR, qlt->req_ndx_to_fw);
2136 * Return a pointer to n entries in the priority request queue. Assumes that
2137 * priority request queue lock is held. Does a very short busy wait if
2138 * less/zero entries are available. Retuns NULL if it still cannot
2139 * fullfill the request.
2140 * **CALL qlt_submit_preq_entries() BEFORE DROPPING THE LOCK**
2142 caddr_t
2143 qlt_get_preq_entries(qlt_state_t *qlt, uint32_t n)
2145 int try = 0;
2146 uint32_t req_available = PRIORITY_QUEUE_ENTRIES - 1 -
2147 ((qlt->preq_ndx_to_fw - qlt->preq_ndx_from_fw) &
2148 (PRIORITY_QUEUE_ENTRIES - 1));
2150 while (req_available < n) {
2151 uint32_t val1, val2, val3;
2152 val1 = REG_RD32(qlt, REG_PREQ_OUT_PTR);
2153 val2 = REG_RD32(qlt, REG_PREQ_OUT_PTR);
2154 val3 = REG_RD32(qlt, REG_PREQ_OUT_PTR);
2155 if ((val1 != val2) || (val2 != val3))
2156 continue;
2158 qlt->preq_ndx_from_fw = val1;
2159 req_available = PRIORITY_QUEUE_ENTRIES - 1 -
2160 ((qlt->preq_ndx_to_fw - qlt->preq_ndx_from_fw) &
2161 (PRIORITY_QUEUE_ENTRIES - 1));
2162 if (req_available < n) {
2163 if (try < 2) {
2164 drv_usecwait(100);
2165 try++;
2166 continue;
2167 } else {
2168 return (NULL);
2171 break;
2173 /* We dont change anything until the entries are sumitted */
2174 return (&qlt->preq_ptr[qlt->preq_ndx_to_fw << 6]);
2178 * updates the req in ptr to fw. Assumes that req lock is held.
2180 void
2181 qlt_submit_preq_entries(qlt_state_t *qlt, uint32_t n)
2183 ASSERT(n >= 1);
2184 qlt->preq_ndx_to_fw += n;
2185 qlt->preq_ndx_to_fw &= PRIORITY_QUEUE_ENTRIES - 1;
2186 REG_WR32(qlt, REG_PREQ_IN_PTR, qlt->preq_ndx_to_fw);
2190 * - Should not be called from Interrupt.
2191 * - A very hardware specific function. Does not touch driver state.
2192 * - Assumes that interrupts are disabled or not there.
2193 * - Expects that the caller makes sure that all activity has stopped
2194 * and its ok now to go ahead and reset the chip. Also the caller
2195 * takes care of post reset damage control.
2196 * - called by initialize adapter() and dump_fw(for reset only).
2197 * - During attach() nothing much is happening and during initialize_adapter()
2198 * the function (caller) does all the housekeeping so that this function
2199 * can execute in peace.
2200 * - Returns 0 on success.
2202 static fct_status_t
2203 qlt_reset_chip(qlt_state_t *qlt)
2205 int cntr;
2207 EL(qlt, "initiated\n");
2209 /* XXX: Switch off LEDs */
2211 /* Disable Interrupts */
2212 REG_WR32(qlt, REG_INTR_CTRL, 0);
2213 (void) REG_RD32(qlt, REG_INTR_CTRL);
2214 /* Stop DMA */
2215 REG_WR32(qlt, REG_CTRL_STATUS, DMA_SHUTDOWN_CTRL | PCI_X_XFER_CTRL);
2217 /* Wait for DMA to be stopped */
2218 cntr = 0;
2219 while (REG_RD32(qlt, REG_CTRL_STATUS) & DMA_ACTIVE_STATUS) {
2220 delay(drv_usectohz(10000)); /* mostly 10ms is 1 tick */
2221 cntr++;
2222 /* 3 sec should be more than enough */
2223 if (cntr == 300)
2224 return (QLT_DMA_STUCK);
2227 /* Reset the Chip */
2228 REG_WR32(qlt, REG_CTRL_STATUS,
2229 DMA_SHUTDOWN_CTRL | PCI_X_XFER_CTRL | CHIP_SOFT_RESET);
2231 qlt->qlt_link_up = 0;
2233 drv_usecwait(100);
2235 /* Wait for ROM firmware to initialize (0x0000) in mailbox 0 */
2236 cntr = 0;
2237 while (REG_RD16(qlt, REG_MBOX(0)) != 0) {
2238 delay(drv_usectohz(10000));
2239 cntr++;
2240 /* 3 sec should be more than enough */
2241 if (cntr == 300)
2242 return (QLT_ROM_STUCK);
2244 /* Disable Interrupts (Probably not needed) */
2245 REG_WR32(qlt, REG_INTR_CTRL, 0);
2247 return (QLT_SUCCESS);
2250 * - Should not be called from Interrupt.
2251 * - A very hardware specific function. Does not touch driver state.
2252 * - Assumes that interrupts are disabled or not there.
2253 * - Expects that the caller makes sure that all activity has stopped
2254 * and its ok now to go ahead and reset the chip. Also the caller
2255 * takes care of post reset damage control.
2256 * - called by initialize adapter() and dump_fw(for reset only).
2257 * - During attach() nothing much is happening and during initialize_adapter()
2258 * the function (caller) does all the housekeeping so that this function
2259 * can execute in peace.
2260 * - Returns 0 on success.
2262 static fct_status_t
2263 qlt_download_fw(qlt_state_t *qlt)
2265 uint32_t start_addr;
2266 fct_status_t ret;
2268 EL(qlt, "initiated\n");
2270 (void) qlt_reset_chip(qlt);
2272 if (qlt->qlt_81xx_chip) {
2273 qlt_mps_reset(qlt);
2276 /* Load the two segments */
2277 if (qlt->fw_code01 != NULL) {
2278 ret = qlt_load_risc_ram(qlt, qlt->fw_code01, qlt->fw_length01,
2279 qlt->fw_addr01);
2280 if (ret == QLT_SUCCESS) {
2281 ret = qlt_load_risc_ram(qlt, qlt->fw_code02,
2282 qlt->fw_length02, qlt->fw_addr02);
2284 start_addr = qlt->fw_addr01;
2285 } else if (qlt->qlt_81xx_chip) {
2286 ret = qlt_load_risc_ram(qlt, fw8100_code01, fw8100_length01,
2287 fw8100_addr01);
2288 if (ret == QLT_SUCCESS) {
2289 ret = qlt_load_risc_ram(qlt, fw8100_code02,
2290 fw8100_length02, fw8100_addr02);
2292 start_addr = fw8100_addr01;
2293 } else if (qlt->qlt_25xx_chip) {
2294 ret = qlt_load_risc_ram(qlt, fw2500_code01, fw2500_length01,
2295 fw2500_addr01);
2296 if (ret == QLT_SUCCESS) {
2297 ret = qlt_load_risc_ram(qlt, fw2500_code02,
2298 fw2500_length02, fw2500_addr02);
2300 start_addr = fw2500_addr01;
2301 } else {
2302 ret = qlt_load_risc_ram(qlt, fw2400_code01, fw2400_length01,
2303 fw2400_addr01);
2304 if (ret == QLT_SUCCESS) {
2305 ret = qlt_load_risc_ram(qlt, fw2400_code02,
2306 fw2400_length02, fw2400_addr02);
2308 start_addr = fw2400_addr01;
2310 if (ret != QLT_SUCCESS) {
2311 EL(qlt, "qlt_load_risc_ram status=%llxh\n", ret);
2312 return (ret);
2315 /* Verify Checksum */
2316 REG_WR16(qlt, REG_MBOX(0), MBC_VERIFY_CHECKSUM);
2317 REG_WR16(qlt, REG_MBOX(1), MSW(start_addr));
2318 REG_WR16(qlt, REG_MBOX(2), LSW(start_addr));
2319 ret = qlt_raw_mailbox_command(qlt);
2320 REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
2321 if (ret != QLT_SUCCESS) {
2322 EL(qlt, "qlt_raw_mailbox_command=7h status=%llxh\n", ret);
2323 return (ret);
2326 /* Execute firmware */
2327 REG_WR16(qlt, REG_MBOX(0), MBC_EXECUTE_FIRMWARE);
2328 REG_WR16(qlt, REG_MBOX(1), MSW(start_addr));
2329 REG_WR16(qlt, REG_MBOX(2), LSW(start_addr));
2330 REG_WR16(qlt, REG_MBOX(3), 0);
2331 REG_WR16(qlt, REG_MBOX(4), 1); /* 25xx enable additional credits */
2332 ret = qlt_raw_mailbox_command(qlt);
2333 REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
2334 if (ret != QLT_SUCCESS) {
2335 EL(qlt, "qlt_raw_mailbox_command=2h status=%llxh\n", ret);
2336 return (ret);
2339 /* Get revisions (About Firmware) */
2340 REG_WR16(qlt, REG_MBOX(0), MBC_ABOUT_FIRMWARE);
2341 ret = qlt_raw_mailbox_command(qlt);
2342 qlt->fw_major = REG_RD16(qlt, REG_MBOX(1));
2343 qlt->fw_minor = REG_RD16(qlt, REG_MBOX(2));
2344 qlt->fw_subminor = REG_RD16(qlt, REG_MBOX(3));
2345 qlt->fw_endaddrlo = REG_RD16(qlt, REG_MBOX(4));
2346 qlt->fw_endaddrhi = REG_RD16(qlt, REG_MBOX(5));
2347 qlt->fw_attr = REG_RD16(qlt, REG_MBOX(6));
2348 REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
2349 if (ret != QLT_SUCCESS) {
2350 EL(qlt, "qlt_raw_mailbox_command=8h status=%llxh\n", ret);
2351 return (ret);
2354 return (QLT_SUCCESS);
2358 * Used only from qlt_download_fw().
2360 static fct_status_t
2361 qlt_load_risc_ram(qlt_state_t *qlt, uint32_t *host_addr,
2362 uint32_t word_count, uint32_t risc_addr)
2364 uint32_t words_sent = 0;
2365 uint32_t words_being_sent;
2366 uint32_t *cur_host_addr;
2367 uint32_t cur_risc_addr;
2368 uint64_t da;
2369 fct_status_t ret;
2371 while (words_sent < word_count) {
2372 cur_host_addr = &(host_addr[words_sent]);
2373 cur_risc_addr = risc_addr + (words_sent << 2);
2374 words_being_sent = min(word_count - words_sent,
2375 TOTAL_DMA_MEM_SIZE >> 2);
2376 ddi_rep_put32(qlt->queue_mem_acc_handle, cur_host_addr,
2377 (uint32_t *)qlt->queue_mem_ptr, words_being_sent,
2378 DDI_DEV_AUTOINCR);
2379 (void) ddi_dma_sync(qlt->queue_mem_dma_handle, 0,
2380 words_being_sent << 2, DDI_DMA_SYNC_FORDEV);
2381 da = qlt->queue_mem_cookie.dmac_laddress;
2382 REG_WR16(qlt, REG_MBOX(0), MBC_LOAD_RAM_EXTENDED);
2383 REG_WR16(qlt, REG_MBOX(1), LSW(risc_addr));
2384 REG_WR16(qlt, REG_MBOX(8), MSW(cur_risc_addr));
2385 REG_WR16(qlt, REG_MBOX(3), LSW(LSD(da)));
2386 REG_WR16(qlt, REG_MBOX(2), MSW(LSD(da)));
2387 REG_WR16(qlt, REG_MBOX(7), LSW(MSD(da)));
2388 REG_WR16(qlt, REG_MBOX(6), MSW(MSD(da)));
2389 REG_WR16(qlt, REG_MBOX(5), LSW(words_being_sent));
2390 REG_WR16(qlt, REG_MBOX(4), MSW(words_being_sent));
2391 ret = qlt_raw_mailbox_command(qlt);
2392 REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
2393 if (ret != QLT_SUCCESS) {
2394 EL(qlt, "qlt_raw_mailbox_command=0Bh status=%llxh\n",
2395 ret);
2396 return (ret);
2398 words_sent += words_being_sent;
2400 return (QLT_SUCCESS);
2404 * Not used during normal operation. Only during driver init.
2405 * Assumes that interrupts are disabled and mailboxes are loaded.
2406 * Just triggers the mailbox command an waits for the completion.
2407 * Also expects that There is nothing else going on and we will only
2408 * get back a mailbox completion from firmware.
2409 * ---DOES NOT CLEAR INTERRUPT---
2410 * Used only from the code path originating from
2411 * qlt_reset_chip_and_download_fw()
2413 static fct_status_t
2414 qlt_raw_mailbox_command(qlt_state_t *qlt)
2416 int cntr = 0;
2417 uint32_t status;
2419 REG_WR32(qlt, REG_HCCR, HCCR_CMD(SET_HOST_TO_RISC_INTR));
2420 while ((REG_RD32(qlt, REG_INTR_STATUS) & RISC_PCI_INTR_REQUEST) == 0) {
2421 cntr++;
2422 if (cntr == 100) {
2423 return (QLT_MAILBOX_STUCK);
2425 delay(drv_usectohz(10000));
2427 status = (REG_RD32(qlt, REG_RISC_STATUS) & FW_INTR_STATUS_MASK);
2429 if ((status == ROM_MBX_CMD_SUCCESSFUL) ||
2430 (status == ROM_MBX_CMD_NOT_SUCCESSFUL) ||
2431 (status == MBX_CMD_SUCCESSFUL) ||
2432 (status == MBX_CMD_NOT_SUCCESSFUL)) {
2433 uint16_t mbox0 = REG_RD16(qlt, REG_MBOX(0));
2434 if (mbox0 == QLT_MBX_CMD_SUCCESS) {
2435 return (QLT_SUCCESS);
2436 } else {
2437 return (QLT_MBOX_FAILED | mbox0);
2440 /* This is unexpected, dump a message */
2441 cmn_err(CE_WARN, "qlt(%d): Unexpect intr status %llx",
2442 ddi_get_instance(qlt->dip), (unsigned long long)status);
2443 return (QLT_UNEXPECTED_RESPONSE);
2446 static mbox_cmd_t *
2447 qlt_alloc_mailbox_command(qlt_state_t *qlt, uint32_t dma_size)
2449 mbox_cmd_t *mcp;
2451 mcp = (mbox_cmd_t *)kmem_zalloc(sizeof (mbox_cmd_t), KM_SLEEP);
2452 if (dma_size) {
2453 qlt_dmem_bctl_t *bctl;
2454 uint64_t da;
2456 mcp->dbuf = qlt_i_dmem_alloc(qlt, dma_size, &dma_size, 0);
2457 if (mcp->dbuf == NULL) {
2458 kmem_free(mcp, sizeof (*mcp));
2459 return (NULL);
2461 mcp->dbuf->db_data_size = dma_size;
2462 ASSERT(mcp->dbuf->db_sglist_length == 1);
2464 bctl = (qlt_dmem_bctl_t *)mcp->dbuf->db_port_private;
2465 da = bctl->bctl_dev_addr;
2466 /* This is the most common initialization of dma ptrs */
2467 mcp->to_fw[3] = LSW(LSD(da));
2468 mcp->to_fw[2] = MSW(LSD(da));
2469 mcp->to_fw[7] = LSW(MSD(da));
2470 mcp->to_fw[6] = MSW(MSD(da));
2471 mcp->to_fw_mask |= BIT_2 | BIT_3 | BIT_7 | BIT_6;
2473 mcp->to_fw_mask |= BIT_0;
2474 mcp->from_fw_mask |= BIT_0;
2475 return (mcp);
2478 void
2479 qlt_free_mailbox_command(qlt_state_t *qlt, mbox_cmd_t *mcp)
2481 if (mcp->dbuf)
2482 qlt_i_dmem_free(qlt, mcp->dbuf);
2483 kmem_free(mcp, sizeof (*mcp));
2487 * This can sleep. Should never be called from interrupt context.
2489 static fct_status_t
2490 qlt_mailbox_command(qlt_state_t *qlt, mbox_cmd_t *mcp)
2492 int retries;
2493 int i;
2494 char info[QLT_INFO_LEN];
2496 if (curthread->t_flag & T_INTR_THREAD) {
2497 ASSERT(0);
2498 return (QLT_MBOX_FAILED);
2501 mutex_enter(&qlt->mbox_lock);
2502 /* See if mailboxes are still uninitialized */
2503 if (qlt->mbox_io_state == MBOX_STATE_UNKNOWN) {
2504 mutex_exit(&qlt->mbox_lock);
2505 return (QLT_MBOX_NOT_INITIALIZED);
2508 /* Wait to grab the mailboxes */
2509 for (retries = 0; qlt->mbox_io_state != MBOX_STATE_READY;
2510 retries++) {
2511 cv_wait(&qlt->mbox_cv, &qlt->mbox_lock);
2512 if ((retries > 5) ||
2513 (qlt->mbox_io_state == MBOX_STATE_UNKNOWN)) {
2514 mutex_exit(&qlt->mbox_lock);
2515 return (QLT_MBOX_BUSY);
2518 /* Make sure we always ask for mailbox 0 */
2519 mcp->from_fw_mask |= BIT_0;
2521 /* Load mailboxes, set state and generate RISC interrupt */
2522 qlt->mbox_io_state = MBOX_STATE_CMD_RUNNING;
2523 qlt->mcp = mcp;
2524 for (i = 0; i < MAX_MBOXES; i++) {
2525 if (mcp->to_fw_mask & ((uint32_t)1 << i))
2526 REG_WR16(qlt, REG_MBOX(i), mcp->to_fw[i]);
2528 REG_WR32(qlt, REG_HCCR, HCCR_CMD(SET_HOST_TO_RISC_INTR));
2530 qlt_mbox_wait_loop:;
2531 /* Wait for mailbox command completion */
2532 if (cv_timedwait(&qlt->mbox_cv, &qlt->mbox_lock, ddi_get_lbolt()
2533 + drv_usectohz(MBOX_TIMEOUT)) < 0) {
2534 (void) snprintf(info, sizeof (info),
2535 "qlt_mailbox_command: qlt-%p, "
2536 "cmd-0x%02X timed out", (void *)qlt, qlt->mcp->to_fw[0]);
2537 qlt->mcp = NULL;
2538 qlt->mbox_io_state = MBOX_STATE_UNKNOWN;
2539 mutex_exit(&qlt->mbox_lock);
2542 * XXX Throw HBA fatal error event
2544 (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR |
2545 STMF_RFLAG_RESET | STMF_RFLAG_COLLECT_DEBUG_DUMP, info);
2546 return (QLT_MBOX_TIMEOUT);
2548 if (qlt->mbox_io_state == MBOX_STATE_CMD_RUNNING)
2549 goto qlt_mbox_wait_loop;
2551 qlt->mcp = NULL;
2553 /* Make sure its a completion */
2554 if (qlt->mbox_io_state != MBOX_STATE_CMD_DONE) {
2555 ASSERT(qlt->mbox_io_state == MBOX_STATE_UNKNOWN);
2556 mutex_exit(&qlt->mbox_lock);
2557 return (QLT_MBOX_ABORTED);
2560 /* MBox command completed. Clear state, retuen based on mbox 0 */
2561 /* Mailboxes are already loaded by interrupt routine */
2562 qlt->mbox_io_state = MBOX_STATE_READY;
2563 mutex_exit(&qlt->mbox_lock);
2564 if (mcp->from_fw[0] != QLT_MBX_CMD_SUCCESS)
2565 return (QLT_MBOX_FAILED | mcp->from_fw[0]);
2567 return (QLT_SUCCESS);
2571 * **SHOULD ONLY BE CALLED FROM INTERRUPT CONTEXT. DO NOT CALL ELSEWHERE**
2573 /* ARGSUSED */
2574 static uint_t
2575 qlt_isr(caddr_t arg, caddr_t arg2)
2577 qlt_state_t *qlt = (qlt_state_t *)arg;
2578 uint32_t risc_status, intr_type;
2579 int i;
2580 int intr_loop_count;
2581 char info[QLT_INFO_LEN];
2583 risc_status = REG_RD32(qlt, REG_RISC_STATUS);
2584 if (!mutex_tryenter(&qlt->intr_lock)) {
2586 * Normally we will always get this lock. If tryenter is
2587 * failing then it means that driver is trying to do
2588 * some cleanup and is masking the intr but some intr
2589 * has sneaked in between. See if our device has generated
2590 * this intr. If so then wait a bit and return claimed.
2591 * If not then return claimed if this is the 1st instance
2592 * of a interrupt after driver has grabbed the lock.
2594 if (risc_status & BIT_15) {
2595 drv_usecwait(10);
2596 return (DDI_INTR_CLAIMED);
2597 } else if (qlt->intr_sneak_counter) {
2598 qlt->intr_sneak_counter--;
2599 return (DDI_INTR_CLAIMED);
2600 } else {
2601 return (DDI_INTR_UNCLAIMED);
2604 if (((risc_status & BIT_15) == 0) ||
2605 (qlt->qlt_intr_enabled == 0)) {
2607 * This might be a pure coincedence that we are operating
2608 * in a interrupt disabled mode and another device
2609 * sharing the interrupt line has generated an interrupt
2610 * while an interrupt from our device might be pending. Just
2611 * ignore it and let the code handling the interrupt
2612 * disabled mode handle it.
2614 mutex_exit(&qlt->intr_lock);
2615 return (DDI_INTR_UNCLAIMED);
2619 * XXX take care for MSI case. disable intrs
2620 * Its gonna be complicated because of the max iterations.
2621 * as hba will have posted the intr which did not go on PCI
2622 * but we did not service it either because of max iterations.
2623 * Maybe offload the intr on a different thread.
2625 intr_loop_count = 0;
2627 REG_WR32(qlt, REG_INTR_CTRL, 0);
2629 intr_again:;
2631 /* check for risc pause */
2632 if (risc_status & BIT_8) {
2633 EL(qlt, "Risc Pause status=%xh\n", risc_status);
2634 cmn_err(CE_WARN, "qlt(%d): Risc Pause %08x",
2635 qlt->instance, risc_status);
2636 (void) snprintf(info, sizeof (info), "Risc Pause %08x",
2637 risc_status);
2638 (void) fct_port_shutdown(qlt->qlt_port,
2639 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET |
2640 STMF_RFLAG_COLLECT_DEBUG_DUMP, info);
2643 /* First check for high performance path */
2644 intr_type = risc_status & 0xff;
2645 if (intr_type == 0x1D) {
2646 qlt->atio_ndx_from_fw = (uint16_t)
2647 REG_RD32(qlt, REG_ATIO_IN_PTR);
2648 REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
2649 qlt->resp_ndx_from_fw = risc_status >> 16;
2650 qlt_handle_atio_queue_update(qlt);
2651 qlt_handle_resp_queue_update(qlt);
2652 } else if (intr_type == 0x1C) {
2653 REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
2654 qlt->atio_ndx_from_fw = (uint16_t)(risc_status >> 16);
2655 qlt_handle_atio_queue_update(qlt);
2656 } else if (intr_type == 0x13) {
2657 REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
2658 qlt->resp_ndx_from_fw = risc_status >> 16;
2659 qlt_handle_resp_queue_update(qlt);
2660 } else if (intr_type == 0x12) {
2661 uint16_t code = (uint16_t)(risc_status >> 16);
2662 uint16_t mbox1 = REG_RD16(qlt, REG_MBOX(1));
2663 uint16_t mbox2 = REG_RD16(qlt, REG_MBOX(2));
2664 uint16_t mbox3 = REG_RD16(qlt, REG_MBOX(3));
2665 uint16_t mbox4 = REG_RD16(qlt, REG_MBOX(4));
2666 uint16_t mbox5 = REG_RD16(qlt, REG_MBOX(5));
2667 uint16_t mbox6 = REG_RD16(qlt, REG_MBOX(6));
2669 REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
2670 stmf_trace(qlt->qlt_port_alias, "Async event %x mb1=%x mb2=%x,"
2671 " mb3=%x, mb5=%x, mb6=%x", code, mbox1, mbox2, mbox3,
2672 mbox5, mbox6);
2673 EL(qlt, "Async event %x mb1=%x mb2=%x, mb3=%x, mb5=%x, mb6=%x",
2674 code, mbox1, mbox2, mbox3, mbox5, mbox6);
2676 if ((code == 0x8030) || (code == 0x8010) || (code == 0x8013)) {
2677 if (qlt->qlt_link_up) {
2678 fct_handle_event(qlt->qlt_port,
2679 FCT_EVENT_LINK_RESET, 0, 0);
2681 } else if (code == 0x8012) {
2682 qlt->qlt_link_up = 0;
2683 fct_handle_event(qlt->qlt_port, FCT_EVENT_LINK_DOWN,
2684 0, 0);
2685 } else if (code == 0x8011) {
2686 switch (mbox1) {
2687 case 0: qlt->link_speed = PORT_SPEED_1G;
2688 break;
2689 case 1: qlt->link_speed = PORT_SPEED_2G;
2690 break;
2691 case 3: qlt->link_speed = PORT_SPEED_4G;
2692 break;
2693 case 4: qlt->link_speed = PORT_SPEED_8G;
2694 break;
2695 case 0x13: qlt->link_speed = PORT_SPEED_10G;
2696 break;
2697 default:
2698 qlt->link_speed = PORT_SPEED_UNKNOWN;
2700 qlt->qlt_link_up = 1;
2701 fct_handle_event(qlt->qlt_port, FCT_EVENT_LINK_UP,
2702 0, 0);
2703 } else if ((code == 0x8002) || (code == 0x8003) ||
2704 (code == 0x8004) || (code == 0x8005)) {
2705 (void) snprintf(info, sizeof (info),
2706 "Got %04x, mb1=%x mb2=%x mb5=%x mb6=%x",
2707 code, mbox1, mbox2, mbox5, mbox6);
2708 (void) fct_port_shutdown(qlt->qlt_port,
2709 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET |
2710 STMF_RFLAG_COLLECT_DEBUG_DUMP, info);
2711 } else if (code == 0x800F) {
2712 (void) snprintf(info, sizeof (info),
2713 "Got 800F, mb1=%x mb2=%x mb3=%x",
2714 mbox1, mbox2, mbox3);
2716 if (mbox1 != 1) {
2717 /* issue "verify fw" */
2718 qlt_verify_fw(qlt);
2720 } else if (code == 0x8101) {
2721 (void) snprintf(info, sizeof (info),
2722 "IDC Req Rcvd:%04x, mb1=%x mb2=%x mb3=%x",
2723 code, mbox1, mbox2, mbox3);
2725 /* check if "ACK" is required (timeout != 0) */
2726 if (mbox1 & 0x0f00) {
2727 caddr_t req;
2730 * Ack the request (queue work to do it?)
2731 * using a mailbox iocb
2733 mutex_enter(&qlt->req_lock);
2734 req = qlt_get_req_entries(qlt, 1);
2735 if (req) {
2736 bzero(req, IOCB_SIZE);
2737 req[0] = 0x39; req[1] = 1;
2738 QMEM_WR16(qlt, req+8, 0x101);
2739 QMEM_WR16(qlt, req+10, mbox1);
2740 QMEM_WR16(qlt, req+12, mbox2);
2741 QMEM_WR16(qlt, req+14, mbox3);
2742 QMEM_WR16(qlt, req+16, mbox4);
2743 QMEM_WR16(qlt, req+18, mbox5);
2744 QMEM_WR16(qlt, req+20, mbox6);
2745 qlt_submit_req_entries(qlt, 1);
2746 } else {
2747 (void) snprintf(info, sizeof (info),
2748 "IDC ACK failed");
2750 mutex_exit(&qlt->req_lock);
2753 } else if ((intr_type == 0x10) || (intr_type == 0x11)) {
2754 /* Handle mailbox completion */
2755 mutex_enter(&qlt->mbox_lock);
2756 if (qlt->mbox_io_state != MBOX_STATE_CMD_RUNNING) {
2757 cmn_err(CE_WARN, "qlt(%d): mailbox completion received"
2758 " when driver wasn't waiting for it %d",
2759 qlt->instance, qlt->mbox_io_state);
2760 } else {
2761 for (i = 0; i < MAX_MBOXES; i++) {
2762 if (qlt->mcp->from_fw_mask &
2763 (((uint32_t)1) << i)) {
2764 qlt->mcp->from_fw[i] =
2765 REG_RD16(qlt, REG_MBOX(i));
2768 qlt->mbox_io_state = MBOX_STATE_CMD_DONE;
2770 REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
2771 cv_broadcast(&qlt->mbox_cv);
2772 mutex_exit(&qlt->mbox_lock);
2773 } else {
2774 cmn_err(CE_WARN, "qlt(%d): Unknown intr type 0x%x",
2775 qlt->instance, intr_type);
2776 REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
2779 (void) REG_RD32(qlt, REG_HCCR); /* PCI Posting */
2780 risc_status = REG_RD32(qlt, REG_RISC_STATUS);
2781 if ((risc_status & BIT_15) &&
2782 (++intr_loop_count < QLT_MAX_ITERATIONS_PER_INTR)) {
2783 goto intr_again;
2786 REG_WR32(qlt, REG_INTR_CTRL, ENABLE_RISC_INTR);
2788 mutex_exit(&qlt->intr_lock);
2789 return (DDI_INTR_CLAIMED);
2792 /* **************** NVRAM Functions ********************** */
2794 fct_status_t
2795 qlt_read_flash_word(qlt_state_t *qlt, uint32_t faddr, uint32_t *bp)
2797 uint32_t timer;
2799 /* Clear access error flag */
2800 REG_WR32(qlt, REG_CTRL_STATUS,
2801 REG_RD32(qlt, REG_CTRL_STATUS) | FLASH_ERROR);
2803 REG_WR32(qlt, REG_FLASH_ADDR, faddr & ~BIT_31);
2805 /* Wait for READ cycle to complete. */
2806 for (timer = 3000; timer; timer--) {
2807 if (REG_RD32(qlt, REG_FLASH_ADDR) & BIT_31) {
2808 break;
2810 drv_usecwait(10);
2812 if (timer == 0) {
2813 EL(qlt, "flash timeout\n");
2814 return (QLT_FLASH_TIMEOUT);
2815 } else if (REG_RD32(qlt, REG_CTRL_STATUS) & FLASH_ERROR) {
2816 EL(qlt, "flash access error\n");
2817 return (QLT_FLASH_ACCESS_ERROR);
2820 *bp = REG_RD32(qlt, REG_FLASH_DATA);
2822 return (QLT_SUCCESS);
2825 fct_status_t
2826 qlt_read_nvram(qlt_state_t *qlt)
2828 uint32_t index, addr, chksum;
2829 uint32_t val, *ptr;
2830 fct_status_t ret;
2831 qlt_nvram_t *nv;
2832 uint64_t empty_node_name = 0;
2834 if (qlt->qlt_81xx_chip) {
2835 addr = REG_RD32(qlt, REG_CTRL_STATUS) & BIT_12 ?
2836 QLT81_NVRAM_FUNC1_ADDR : QLT81_NVRAM_FUNC0_ADDR;
2837 } else if (qlt->qlt_25xx_chip) {
2838 addr = REG_RD32(qlt, REG_CTRL_STATUS) & FUNCTION_NUMBER ?
2839 QLT25_NVRAM_FUNC1_ADDR : QLT25_NVRAM_FUNC0_ADDR;
2840 } else {
2841 addr = REG_RD32(qlt, REG_CTRL_STATUS) & FUNCTION_NUMBER ?
2842 NVRAM_FUNC1_ADDR : NVRAM_FUNC0_ADDR;
2844 mutex_enter(&qlt_global_lock);
2846 /* Pause RISC. */
2847 REG_WR32(qlt, REG_HCCR, HCCR_CMD(SET_RISC_PAUSE));
2848 (void) REG_RD32(qlt, REG_HCCR); /* PCI Posting. */
2850 /* Get NVRAM data and calculate checksum. */
2851 ptr = (uint32_t *)qlt->nvram;
2852 chksum = 0;
2853 for (index = 0; index < sizeof (qlt_nvram_t) / 4; index++) {
2854 ret = qlt_read_flash_word(qlt, addr++, &val);
2855 if (ret != QLT_SUCCESS) {
2856 EL(qlt, "qlt_read_flash_word, status=%llxh\n", ret);
2857 mutex_exit(&qlt_global_lock);
2858 return (ret);
2860 chksum += val;
2861 *ptr = LE_32(val);
2862 ptr++;
2865 /* Release RISC Pause */
2866 REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_PAUSE));
2867 (void) REG_RD32(qlt, REG_HCCR); /* PCI Posting. */
2869 mutex_exit(&qlt_global_lock);
2871 /* Sanity check NVRAM Data */
2872 nv = qlt->nvram;
2873 if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' ||
2874 nv->id[2] != 'P' || nv->id[3] != ' ' ||
2875 (nv->nvram_version[0] | nv->nvram_version[1]) == 0) {
2876 EL(qlt, "chksum=%xh, id=%c%c%c%c, ver=%02d%02d\n", chksum,
2877 nv->id[0], nv->id[1], nv->id[2], nv->id[3],
2878 nv->nvram_version[1], nv->nvram_version[0]);
2879 return (QLT_BAD_NVRAM_DATA);
2882 /* If node name is zero, hand craft it from port name */
2883 if (bcmp(nv->node_name, &empty_node_name, 8) == 0) {
2884 bcopy(nv->port_name, nv->node_name, 8);
2885 nv->node_name[0] = (uint8_t)(nv->node_name[0] & ~BIT_0);
2886 nv->port_name[0] = (uint8_t)(nv->node_name[0] | BIT_0);
2889 return (QLT_SUCCESS);
2892 uint32_t
2893 qlt_sync_atio_queue(qlt_state_t *qlt)
2895 uint32_t total_ent;
2897 if (qlt->atio_ndx_from_fw > qlt->atio_ndx_to_fw) {
2898 total_ent = qlt->atio_ndx_from_fw - qlt->atio_ndx_to_fw;
2899 (void) ddi_dma_sync(qlt->queue_mem_dma_handle, ATIO_QUEUE_OFFSET
2900 + (qlt->atio_ndx_to_fw << 6), total_ent << 6,
2901 DDI_DMA_SYNC_FORCPU);
2902 } else {
2903 total_ent = ATIO_QUEUE_ENTRIES - qlt->atio_ndx_to_fw +
2904 qlt->atio_ndx_from_fw;
2905 (void) ddi_dma_sync(qlt->queue_mem_dma_handle, ATIO_QUEUE_OFFSET
2906 + (qlt->atio_ndx_to_fw << 6), (uint_t)(ATIO_QUEUE_ENTRIES -
2907 qlt->atio_ndx_to_fw) << 6, DDI_DMA_SYNC_FORCPU);
2908 (void) ddi_dma_sync(qlt->queue_mem_dma_handle,
2909 ATIO_QUEUE_OFFSET, (uint_t)(qlt->atio_ndx_from_fw << 6),
2910 DDI_DMA_SYNC_FORCPU);
2912 return (total_ent);
2915 void
2916 qlt_handle_atio_queue_update(qlt_state_t *qlt)
2918 uint32_t total_ent;
2920 if (qlt->atio_ndx_to_fw == qlt->atio_ndx_from_fw)
2921 return;
2923 total_ent = qlt_sync_atio_queue(qlt);
2925 do {
2926 uint8_t *atio = (uint8_t *)&qlt->atio_ptr[
2927 qlt->atio_ndx_to_fw << 6];
2928 uint32_t ent_cnt;
2930 ent_cnt = (uint32_t)(atio[1]);
2931 if (ent_cnt > total_ent) {
2932 break;
2934 switch ((uint8_t)(atio[0])) {
2935 case 0x0d: /* INOT */
2936 qlt_handle_inot(qlt, atio);
2937 break;
2938 case 0x06: /* ATIO */
2939 qlt_handle_atio(qlt, atio);
2940 break;
2941 default:
2942 EL(qlt, "atio_queue_update atio[0]=%xh\n", atio[0]);
2943 cmn_err(CE_WARN, "qlt_handle_atio_queue_update: "
2944 "atio[0] is %x, qlt-%p", atio[0], (void *)qlt);
2945 break;
2947 qlt->atio_ndx_to_fw = (uint16_t)(
2948 (qlt->atio_ndx_to_fw + ent_cnt) & (ATIO_QUEUE_ENTRIES - 1));
2949 total_ent -= ent_cnt;
2950 } while (total_ent > 0);
2951 REG_WR32(qlt, REG_ATIO_OUT_PTR, qlt->atio_ndx_to_fw);
2954 uint32_t
2955 qlt_sync_resp_queue(qlt_state_t *qlt)
2957 uint32_t total_ent;
2959 if (qlt->resp_ndx_from_fw > qlt->resp_ndx_to_fw) {
2960 total_ent = qlt->resp_ndx_from_fw - qlt->resp_ndx_to_fw;
2961 (void) ddi_dma_sync(qlt->queue_mem_dma_handle,
2962 RESPONSE_QUEUE_OFFSET
2963 + (qlt->resp_ndx_to_fw << 6), total_ent << 6,
2964 DDI_DMA_SYNC_FORCPU);
2965 } else {
2966 total_ent = RESPONSE_QUEUE_ENTRIES - qlt->resp_ndx_to_fw +
2967 qlt->resp_ndx_from_fw;
2968 (void) ddi_dma_sync(qlt->queue_mem_dma_handle,
2969 RESPONSE_QUEUE_OFFSET
2970 + (qlt->resp_ndx_to_fw << 6), (RESPONSE_QUEUE_ENTRIES -
2971 qlt->resp_ndx_to_fw) << 6, DDI_DMA_SYNC_FORCPU);
2972 (void) ddi_dma_sync(qlt->queue_mem_dma_handle,
2973 RESPONSE_QUEUE_OFFSET,
2974 qlt->resp_ndx_from_fw << 6, DDI_DMA_SYNC_FORCPU);
2976 return (total_ent);
2979 void
2980 qlt_handle_resp_queue_update(qlt_state_t *qlt)
2982 uint32_t total_ent;
2983 uint8_t c;
2985 if (qlt->resp_ndx_to_fw == qlt->resp_ndx_from_fw)
2986 return;
2988 total_ent = qlt_sync_resp_queue(qlt);
2990 do {
2991 caddr_t resp = &qlt->resp_ptr[qlt->resp_ndx_to_fw << 6];
2992 uint32_t ent_cnt;
2994 ent_cnt = (uint32_t)(resp[0] == 0x51 ? resp[1] : 1);
2995 if (ent_cnt > total_ent) {
2996 break;
2998 switch ((uint8_t)(resp[0])) {
2999 case 0x12: /* CTIO completion */
3000 qlt_handle_ctio_completion(qlt, (uint8_t *)resp);
3001 break;
3002 case 0x0e: /* NACK */
3003 /* Do Nothing */
3004 break;
3005 case 0x1b: /* Verify FW */
3006 qlt_handle_verify_fw_completion(qlt, (uint8_t *)resp);
3007 break;
3008 case 0x29: /* CT PassThrough */
3009 qlt_handle_ct_completion(qlt, (uint8_t *)resp);
3010 break;
3011 case 0x33: /* Abort IO IOCB completion */
3012 qlt_handle_sol_abort_completion(qlt, (uint8_t *)resp);
3013 break;
3014 case 0x51: /* PUREX */
3015 qlt_handle_purex(qlt, (uint8_t *)resp);
3016 break;
3017 case 0x52:
3018 qlt_handle_dereg_completion(qlt, (uint8_t *)resp);
3019 break;
3020 case 0x53: /* ELS passthrough */
3021 c = (uint8_t)(((uint8_t)resp[0x1f]) >> 5);
3022 if (c == 0) {
3023 qlt_handle_sol_els_completion(qlt,
3024 (uint8_t *)resp);
3025 } else if (c == 3) {
3026 qlt_handle_unsol_els_abort_completion(qlt,
3027 (uint8_t *)resp);
3028 } else {
3029 qlt_handle_unsol_els_completion(qlt,
3030 (uint8_t *)resp);
3032 break;
3033 case 0x54: /* ABTS received */
3034 qlt_handle_rcvd_abts(qlt, (uint8_t *)resp);
3035 break;
3036 case 0x55: /* ABTS completion */
3037 qlt_handle_abts_completion(qlt, (uint8_t *)resp);
3038 break;
3039 default:
3040 EL(qlt, "response entry=%xh\n", resp[0]);
3041 break;
3043 qlt->resp_ndx_to_fw = (qlt->resp_ndx_to_fw + ent_cnt) &
3044 (RESPONSE_QUEUE_ENTRIES - 1);
3045 total_ent -= ent_cnt;
3046 } while (total_ent > 0);
3047 REG_WR32(qlt, REG_RESP_OUT_PTR, qlt->resp_ndx_to_fw);
3050 fct_status_t
3051 qlt_portid_to_handle(qlt_state_t *qlt, uint32_t id, uint16_t cmd_handle,
3052 uint16_t *ret_handle)
3054 fct_status_t ret;
3055 mbox_cmd_t *mcp;
3056 uint16_t n;
3057 uint16_t h;
3058 uint32_t ent_id;
3059 uint8_t *p;
3060 int found = 0;
3062 mcp = qlt_alloc_mailbox_command(qlt, 2048 * 8);
3063 if (mcp == NULL) {
3064 return (STMF_ALLOC_FAILURE);
3066 mcp->to_fw[0] = MBC_GET_ID_LIST;
3067 mcp->to_fw[8] = 2048 * 8;
3068 mcp->to_fw[9] = 0;
3069 mcp->to_fw_mask |= BIT_9 | BIT_8;
3070 mcp->from_fw_mask |= BIT_1 | BIT_2;
3072 ret = qlt_mailbox_command(qlt, mcp);
3073 if (ret != QLT_SUCCESS) {
3074 EL(qlt, "qlt_mailbox_command=7Ch status=%llxh\n", ret);
3075 cmn_err(CE_WARN, "GET ID list failed, ret = %llx, mb0=%x, "
3076 "mb1=%x, mb2=%x", (long long)ret, mcp->from_fw[0],
3077 mcp->from_fw[1], mcp->from_fw[2]);
3078 qlt_free_mailbox_command(qlt, mcp);
3079 return (ret);
3081 qlt_dmem_dma_sync(mcp->dbuf, DDI_DMA_SYNC_FORCPU);
3082 p = mcp->dbuf->db_sglist[0].seg_addr;
3083 for (n = 0; n < mcp->from_fw[1]; n++) {
3084 ent_id = LE_32(*((uint32_t *)p)) & 0xFFFFFF;
3085 h = (uint16_t)((uint16_t)p[4] | (((uint16_t)p[5]) << 8));
3086 if (ent_id == id) {
3087 found = 1;
3088 *ret_handle = h;
3089 if ((cmd_handle != FCT_HANDLE_NONE) &&
3090 (cmd_handle != h)) {
3091 cmn_err(CE_WARN, "login for portid %x came in "
3092 "with handle %x, while the portid was "
3093 "already using a different handle %x",
3094 id, cmd_handle, h);
3095 qlt_free_mailbox_command(qlt, mcp);
3096 return (QLT_FAILURE);
3098 break;
3100 if ((cmd_handle != FCT_HANDLE_NONE) && (h == cmd_handle)) {
3101 cmn_err(CE_WARN, "login for portid %x came in with "
3102 "handle %x, while the handle was already in use "
3103 "for portid %x", id, cmd_handle, ent_id);
3104 qlt_free_mailbox_command(qlt, mcp);
3105 return (QLT_FAILURE);
3107 p += 8;
3109 if (!found) {
3110 *ret_handle = cmd_handle;
3112 qlt_free_mailbox_command(qlt, mcp);
3113 return (FCT_SUCCESS);
3116 /* ARGSUSED */
3117 fct_status_t
3118 qlt_fill_plogi_req(fct_local_port_t *port, fct_remote_port_t *rp,
3119 fct_cmd_t *login)
3121 uint8_t *p;
3123 p = ((fct_els_t *)login->cmd_specific)->els_req_payload;
3124 p[0] = ELS_OP_PLOGI;
3125 *((uint16_t *)(&p[4])) = 0x2020;
3126 p[7] = 3;
3127 p[8] = 0x88;
3128 p[10] = 8;
3129 p[13] = 0xff; p[15] = 0x1f;
3130 p[18] = 7; p[19] = 0xd0;
3132 bcopy(port->port_pwwn, p + 20, 8);
3133 bcopy(port->port_nwwn, p + 28, 8);
3135 p[68] = 0x80;
3136 p[74] = 8;
3137 p[77] = 0xff;
3138 p[81] = 1;
3140 return (FCT_SUCCESS);
3143 /* ARGSUSED */
3144 fct_status_t
3145 qlt_fill_plogi_resp(fct_local_port_t *port, fct_remote_port_t *rp,
3146 fct_cmd_t *login)
3148 return (FCT_SUCCESS);
3151 fct_status_t
3152 qlt_register_remote_port(fct_local_port_t *port, fct_remote_port_t *rp,
3153 fct_cmd_t *login)
3155 uint16_t h;
3156 fct_status_t ret;
3157 qlt_state_t *qlt = (qlt_state_t *)port->port_fca_private;
3159 switch (rp->rp_id) {
3160 case 0xFFFFFC: h = 0x7FC; break;
3161 case 0xFFFFFD: h = 0x7FD; break;
3162 case 0xFFFFFE: h = 0x7FE; break;
3163 case 0xFFFFFF: h = 0x7FF; break;
3164 default:
3165 ret = qlt_portid_to_handle(qlt, rp->rp_id,
3166 login->cmd_rp_handle, &h);
3167 if (ret != FCT_SUCCESS) {
3168 EL(qlt, "qlt_portid_to_handle, status=%llxh\n", ret);
3169 return (ret);
3173 if (login->cmd_type == FCT_CMD_SOL_ELS) {
3174 ret = qlt_fill_plogi_req(port, rp, login);
3175 } else {
3176 ret = qlt_fill_plogi_resp(port, rp, login);
3179 if (ret != FCT_SUCCESS) {
3180 EL(qlt, "qlt_fill_plogi, status=%llxh\n", ret);
3181 return (ret);
3184 if (h == FCT_HANDLE_NONE)
3185 return (FCT_SUCCESS);
3187 if (rp->rp_handle == FCT_HANDLE_NONE) {
3188 rp->rp_handle = h;
3189 return (FCT_SUCCESS);
3192 if (rp->rp_handle == h)
3193 return (FCT_SUCCESS);
3195 EL(qlt, "rp_handle=%xh != h=%xh\n", rp->rp_handle, h);
3196 return (FCT_FAILURE);
3198 /* invoked in single thread */
3199 fct_status_t
3200 qlt_deregister_remote_port(fct_local_port_t *port, fct_remote_port_t *rp)
3202 uint8_t *req;
3203 qlt_state_t *qlt;
3204 clock_t dereg_req_timer;
3205 fct_status_t ret;
3207 qlt = (qlt_state_t *)port->port_fca_private;
3209 if ((qlt->qlt_state == FCT_STATE_OFFLINE) ||
3210 (qlt->qlt_state == FCT_STATE_OFFLINING))
3211 return (FCT_SUCCESS);
3212 ASSERT(qlt->rp_id_in_dereg == 0);
3214 mutex_enter(&qlt->preq_lock);
3215 req = (uint8_t *)qlt_get_preq_entries(qlt, 1);
3216 if (req == NULL) {
3217 mutex_exit(&qlt->preq_lock);
3218 return (FCT_BUSY);
3220 bzero(req, IOCB_SIZE);
3221 req[0] = 0x52; req[1] = 1;
3222 /* QMEM_WR32(qlt, (&req[4]), 0xffffffff); */
3223 QMEM_WR16(qlt, (&req[0xA]), rp->rp_handle);
3224 QMEM_WR16(qlt, (&req[0xC]), 0x98); /* implicit logo */
3225 QMEM_WR32(qlt, (&req[0x10]), rp->rp_id);
3226 qlt->rp_id_in_dereg = rp->rp_id;
3227 qlt_submit_preq_entries(qlt, 1);
3229 dereg_req_timer = ddi_get_lbolt() + drv_usectohz(DEREG_RP_TIMEOUT);
3230 if (cv_timedwait(&qlt->rp_dereg_cv,
3231 &qlt->preq_lock, dereg_req_timer) > 0) {
3232 ret = qlt->rp_dereg_status;
3233 } else {
3234 ret = FCT_BUSY;
3236 qlt->rp_dereg_status = 0;
3237 qlt->rp_id_in_dereg = 0;
3238 mutex_exit(&qlt->preq_lock);
3239 return (ret);
3243 * Pass received ELS up to framework.
3245 static void
3246 qlt_handle_purex(qlt_state_t *qlt, uint8_t *resp)
3248 fct_cmd_t *cmd;
3249 fct_els_t *els;
3250 qlt_cmd_t *qcmd;
3251 uint32_t payload_size;
3252 uint32_t remote_portid;
3253 uint8_t *pldptr, *bndrptr;
3254 int i, off;
3255 uint16_t iocb_flags;
3256 char info[QLT_INFO_LEN];
3258 remote_portid = ((uint32_t)(QMEM_RD16(qlt, (&resp[0x18])))) |
3259 ((uint32_t)(resp[0x1A])) << 16;
3260 iocb_flags = QMEM_RD16(qlt, (&resp[8]));
3261 if (iocb_flags & BIT_15) {
3262 payload_size = (QMEM_RD16(qlt, (&resp[0x0e])) & 0xfff) - 24;
3263 } else {
3264 payload_size = QMEM_RD16(qlt, (&resp[0x0c])) - 24;
3267 if (payload_size > ((uint32_t)resp[1] * IOCB_SIZE - 0x2C)) {
3268 EL(qlt, "payload is too large = %xh\n", payload_size);
3269 cmn_err(CE_WARN, "handle_purex: payload is too large");
3270 goto cmd_null;
3273 cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_RCVD_ELS,
3274 (int)(payload_size + GET_STRUCT_SIZE(qlt_cmd_t)), 0);
3275 if (cmd == NULL) {
3276 EL(qlt, "fct_alloc cmd==NULL\n");
3277 cmd_null:;
3278 (void) snprintf(info, sizeof (info),
3279 "qlt_handle_purex: qlt-%p, "
3280 "can't allocate space for fct_cmd", (void *)qlt);
3281 (void) fct_port_shutdown(qlt->qlt_port,
3282 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
3283 return;
3286 cmd->cmd_port = qlt->qlt_port;
3287 cmd->cmd_rp_handle = QMEM_RD16(qlt, resp+0xa);
3288 if (cmd->cmd_rp_handle == 0xFFFF) {
3289 cmd->cmd_rp_handle = FCT_HANDLE_NONE;
3292 els = (fct_els_t *)cmd->cmd_specific;
3293 qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
3294 els->els_req_size = (uint16_t)payload_size;
3295 els->els_req_payload = GET_BYTE_OFFSET(qcmd,
3296 GET_STRUCT_SIZE(qlt_cmd_t));
3297 qcmd->fw_xchg_addr = QMEM_RD32(qlt, (&resp[0x10]));
3298 cmd->cmd_rportid = remote_portid;
3299 cmd->cmd_lportid = ((uint32_t)(QMEM_RD16(qlt, (&resp[0x14])))) |
3300 ((uint32_t)(resp[0x16])) << 16;
3301 cmd->cmd_oxid = QMEM_RD16(qlt, (&resp[0x26]));
3302 cmd->cmd_rxid = QMEM_RD16(qlt, (&resp[0x24]));
3303 pldptr = &resp[0x2C];
3304 bndrptr = (uint8_t *)(qlt->resp_ptr + (RESPONSE_QUEUE_ENTRIES << 6));
3305 for (i = 0, off = 0x2c; i < payload_size; i += 4) {
3306 /* Take care of fw's swapping of payload */
3307 els->els_req_payload[i] = pldptr[3];
3308 els->els_req_payload[i+1] = pldptr[2];
3309 els->els_req_payload[i+2] = pldptr[1];
3310 els->els_req_payload[i+3] = pldptr[0];
3311 pldptr += 4;
3312 if (pldptr == bndrptr)
3313 pldptr = (uint8_t *)qlt->resp_ptr;
3314 off += 4;
3315 if (off >= IOCB_SIZE) {
3316 off = 4;
3317 pldptr += 4;
3320 fct_post_rcvd_cmd(cmd, 0);
3323 fct_status_t
3324 qlt_send_cmd_response(fct_cmd_t *cmd, uint32_t ioflags)
3326 qlt_state_t *qlt;
3327 char info[QLT_INFO_LEN];
3329 qlt = (qlt_state_t *)cmd->cmd_port->port_fca_private;
3331 if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
3332 if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
3333 EL(qlt, "ioflags = %xh\n", ioflags);
3334 goto fatal_panic;
3335 } else {
3336 return (qlt_send_status(qlt, cmd));
3340 if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
3341 if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
3342 goto fatal_panic;
3343 } else {
3344 return (qlt_send_els_response(qlt, cmd));
3348 if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
3349 cmd->cmd_handle = 0;
3352 if (cmd->cmd_type == FCT_CMD_RCVD_ABTS) {
3353 return (qlt_send_abts_response(qlt, cmd, 0));
3354 } else {
3355 EL(qlt, "cmd->cmd_type=%xh\n", cmd->cmd_type);
3356 ASSERT(0);
3357 return (FCT_FAILURE);
3360 fatal_panic:;
3361 (void) snprintf(info, sizeof (info),
3362 "qlt_send_cmd_response: can not handle "
3363 "FCT_IOF_FORCE_FCA_DONE for cmd %p, ioflags-%x", (void *)cmd,
3364 ioflags);
3365 (void) fct_port_shutdown(qlt->qlt_port,
3366 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
3367 return (FCT_FAILURE);
3370 /* ARGSUSED */
3371 fct_status_t
3372 qlt_xfer_scsi_data(fct_cmd_t *cmd, stmf_data_buf_t *dbuf, uint32_t ioflags)
3374 qlt_dmem_bctl_t *bctl = (qlt_dmem_bctl_t *)dbuf->db_port_private;
3375 qlt_state_t *qlt = (qlt_state_t *)cmd->cmd_port->port_fca_private;
3376 qlt_cmd_t *qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
3377 uint8_t *req, rcnt;
3378 uint16_t flags;
3379 uint16_t cookie_count;
3381 if (dbuf->db_handle == 0)
3382 qcmd->dbuf = dbuf;
3383 flags = (uint16_t)(((uint16_t)qcmd->param.atio_byte3 & 0xf0) << 5);
3384 if (dbuf->db_flags & DB_DIRECTION_TO_RPORT) {
3385 flags = (uint16_t)(flags | 2);
3386 qlt_dmem_dma_sync(dbuf, DDI_DMA_SYNC_FORDEV);
3387 } else {
3388 flags = (uint16_t)(flags | 1);
3391 if (dbuf->db_flags & DB_SEND_STATUS_GOOD)
3392 flags = (uint16_t)(flags | BIT_15);
3394 if (dbuf->db_flags & DB_LU_DATA_BUF) {
3396 * Data bufs from LU are in scatter/gather list format.
3398 cookie_count = qlt_get_cookie_count(dbuf);
3399 rcnt = qlt_get_iocb_count(cookie_count);
3400 } else {
3401 cookie_count = 1;
3402 rcnt = 1;
3404 mutex_enter(&qlt->req_lock);
3405 req = (uint8_t *)qlt_get_req_entries(qlt, rcnt);
3406 if (req == NULL) {
3407 mutex_exit(&qlt->req_lock);
3408 return (FCT_BUSY);
3410 bzero(req, IOCB_SIZE); /* XXX needed ? */
3411 req[0] = 0x12;
3412 req[1] = rcnt;
3413 req[2] = dbuf->db_handle;
3414 QMEM_WR32(qlt, req+4, cmd->cmd_handle);
3415 QMEM_WR16(qlt, req+8, cmd->cmd_rp->rp_handle);
3416 QMEM_WR16(qlt, req+10, 60); /* 60 seconds timeout */
3417 QMEM_WR16(qlt, req+12, cookie_count);
3418 QMEM_WR32(qlt, req+0x10, cmd->cmd_rportid);
3419 QMEM_WR32(qlt, req+0x14, qcmd->fw_xchg_addr);
3420 QMEM_WR16(qlt, req+0x1A, flags);
3421 QMEM_WR16(qlt, req+0x20, cmd->cmd_oxid);
3422 QMEM_WR32(qlt, req+0x24, dbuf->db_relative_offset);
3423 QMEM_WR32(qlt, req+0x2C, dbuf->db_data_size);
3424 if (dbuf->db_flags & DB_LU_DATA_BUF) {
3425 uint8_t *qptr; /* qlt continuation segs */
3426 uint16_t cookie_resid;
3427 uint16_t cont_segs;
3428 ddi_dma_cookie_t cookie, *ckp;
3431 * See if the dma cookies are in simple array format.
3433 ckp = qlt_get_cookie_array(dbuf);
3436 * Program the first segment into main record.
3438 if (ckp) {
3439 ASSERT(ckp->dmac_size);
3440 QMEM_WR64(qlt, req+0x34, ckp->dmac_laddress);
3441 QMEM_WR32(qlt, req+0x3c, ckp->dmac_size);
3442 } else {
3443 qlt_ddi_dma_nextcookie(dbuf, &cookie);
3444 ASSERT(cookie.dmac_size);
3445 QMEM_WR64(qlt, req+0x34, cookie.dmac_laddress);
3446 QMEM_WR32(qlt, req+0x3c, cookie.dmac_size);
3448 cookie_resid = cookie_count-1;
3451 * Program remaining segments into continuation records.
3453 while (cookie_resid) {
3454 req += IOCB_SIZE;
3455 if (req >= (uint8_t *)qlt->resp_ptr) {
3456 req = (uint8_t *)qlt->req_ptr;
3458 req[0] = 0x0a;
3459 req[1] = 1;
3460 req[2] = req[3] = 0; /* tidy */
3461 qptr = &req[4];
3462 for (cont_segs = CONT_A64_DATA_SEGMENTS;
3463 cont_segs && cookie_resid; cont_segs--) {
3465 if (ckp) {
3466 ++ckp; /* next cookie */
3467 ASSERT(ckp->dmac_size != 0);
3468 QMEM_WR64(qlt, qptr,
3469 ckp->dmac_laddress);
3470 qptr += 8; /* skip over laddress */
3471 QMEM_WR32(qlt, qptr, ckp->dmac_size);
3472 qptr += 4; /* skip over size */
3473 } else {
3474 qlt_ddi_dma_nextcookie(dbuf, &cookie);
3475 ASSERT(cookie.dmac_size != 0);
3476 QMEM_WR64(qlt, qptr,
3477 cookie.dmac_laddress);
3478 qptr += 8; /* skip over laddress */
3479 QMEM_WR32(qlt, qptr, cookie.dmac_size);
3480 qptr += 4; /* skip over size */
3482 cookie_resid--;
3485 * zero unused remainder of IOCB
3487 if (cont_segs) {
3488 size_t resid;
3489 resid = (size_t)((uintptr_t)(req+IOCB_SIZE) -
3490 (uintptr_t)qptr);
3491 ASSERT(resid < IOCB_SIZE);
3492 bzero(qptr, resid);
3495 } else {
3496 /* Single, contiguous buffer */
3497 QMEM_WR64(qlt, req+0x34, bctl->bctl_dev_addr);
3498 QMEM_WR32(qlt, req+0x34+8, dbuf->db_data_size);
3501 qlt_submit_req_entries(qlt, rcnt);
3502 mutex_exit(&qlt->req_lock);
3504 return (STMF_SUCCESS);
3508 * We must construct proper FCP_RSP_IU now. Here we only focus on
3509 * the handling of FCP_SNS_INFO. If there's protocol failures (FCP_RSP_INFO),
3510 * we could have catched them before we enter here.
3512 fct_status_t
3513 qlt_send_status(qlt_state_t *qlt, fct_cmd_t *cmd)
3515 qlt_cmd_t *qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
3516 scsi_task_t *task = (scsi_task_t *)cmd->cmd_specific;
3517 qlt_dmem_bctl_t *bctl;
3518 uint32_t size;
3519 uint8_t *req, *fcp_rsp_iu;
3520 uint8_t *psd, sensbuf[24]; /* sense data */
3521 uint16_t flags;
3522 uint16_t scsi_status;
3523 int use_mode2;
3524 int ndx;
3527 * Enter fast channel for non check condition
3529 if (task->task_scsi_status != STATUS_CHECK) {
3531 * We will use mode1
3533 flags = (uint16_t)(BIT_6 | BIT_15 |
3534 (((uint16_t)qcmd->param.atio_byte3 & 0xf0) << 5));
3535 scsi_status = (uint16_t)task->task_scsi_status;
3536 if (task->task_status_ctrl == TASK_SCTRL_OVER) {
3537 scsi_status = (uint16_t)(scsi_status | BIT_10);
3538 } else if (task->task_status_ctrl == TASK_SCTRL_UNDER) {
3539 scsi_status = (uint16_t)(scsi_status | BIT_11);
3541 qcmd->dbuf_rsp_iu = NULL;
3544 * Fillout CTIO type 7 IOCB
3546 mutex_enter(&qlt->req_lock);
3547 req = (uint8_t *)qlt_get_req_entries(qlt, 1);
3548 if (req == NULL) {
3549 mutex_exit(&qlt->req_lock);
3550 return (FCT_BUSY);
3554 * Common fields
3556 bzero(req, IOCB_SIZE);
3557 req[0x00] = 0x12;
3558 req[0x01] = 0x1;
3559 req[0x02] = BIT_7; /* indicate if it's a pure status req */
3560 QMEM_WR32(qlt, req + 0x04, cmd->cmd_handle);
3561 QMEM_WR16(qlt, req + 0x08, cmd->cmd_rp->rp_handle);
3562 QMEM_WR32(qlt, req + 0x10, cmd->cmd_rportid);
3563 QMEM_WR32(qlt, req + 0x14, qcmd->fw_xchg_addr);
3566 * Mode-specific fields
3568 QMEM_WR16(qlt, req + 0x1A, flags);
3569 QMEM_WR32(qlt, req + 0x1C, task->task_resid);
3570 QMEM_WR16(qlt, req + 0x20, cmd->cmd_oxid);
3571 QMEM_WR16(qlt, req + 0x22, scsi_status);
3574 * Trigger FW to send SCSI status out
3576 qlt_submit_req_entries(qlt, 1);
3577 mutex_exit(&qlt->req_lock);
3578 return (STMF_SUCCESS);
3581 ASSERT(task->task_scsi_status == STATUS_CHECK);
3583 * Decide the SCSI status mode, that should be used
3585 use_mode2 = (task->task_sense_length > 24);
3588 * Prepare required information per the SCSI status mode
3590 flags = (uint16_t)(BIT_15 |
3591 (((uint16_t)qcmd->param.atio_byte3 & 0xf0) << 5));
3592 if (use_mode2) {
3593 flags = (uint16_t)(flags | BIT_7);
3595 size = task->task_sense_length;
3596 qcmd->dbuf_rsp_iu = qlt_i_dmem_alloc(qlt,
3597 task->task_sense_length, &size, 0);
3598 if (!qcmd->dbuf_rsp_iu) {
3599 return (FCT_ALLOC_FAILURE);
3603 * Start to construct FCP_RSP IU
3605 fcp_rsp_iu = qcmd->dbuf_rsp_iu->db_sglist[0].seg_addr;
3606 bzero(fcp_rsp_iu, 24);
3609 * FCP_RSP IU flags, byte10
3611 fcp_rsp_iu[10] = (uint8_t)(fcp_rsp_iu[10] | BIT_1);
3612 if (task->task_status_ctrl == TASK_SCTRL_OVER) {
3613 fcp_rsp_iu[10] = (uint8_t)(fcp_rsp_iu[10] | BIT_2);
3614 } else if (task->task_status_ctrl == TASK_SCTRL_UNDER) {
3615 fcp_rsp_iu[10] = (uint8_t)(fcp_rsp_iu[10] | BIT_3);
3619 * SCSI status code, byte11
3621 fcp_rsp_iu[11] = task->task_scsi_status;
3624 * FCP_RESID (Overrun or underrun)
3626 fcp_rsp_iu[12] = (uint8_t)((task->task_resid >> 24) & 0xFF);
3627 fcp_rsp_iu[13] = (uint8_t)((task->task_resid >> 16) & 0xFF);
3628 fcp_rsp_iu[14] = (uint8_t)((task->task_resid >> 8) & 0xFF);
3629 fcp_rsp_iu[15] = (uint8_t)((task->task_resid >> 0) & 0xFF);
3632 * FCP_SNS_LEN
3634 fcp_rsp_iu[18] = (uint8_t)((task->task_sense_length >> 8) &
3635 0xFF);
3636 fcp_rsp_iu[19] = (uint8_t)((task->task_sense_length >> 0) &
3637 0xFF);
3640 * FCP_RSP_LEN
3643 * no FCP_RSP_INFO
3646 * FCP_SNS_INFO
3648 bcopy(task->task_sense_data, fcp_rsp_iu + 24,
3649 task->task_sense_length);
3652 * Ensure dma data consistency
3654 qlt_dmem_dma_sync(qcmd->dbuf_rsp_iu, DDI_DMA_SYNC_FORDEV);
3655 } else {
3656 flags = (uint16_t)(flags | BIT_6);
3658 scsi_status = (uint16_t)task->task_scsi_status;
3659 if (task->task_status_ctrl == TASK_SCTRL_OVER) {
3660 scsi_status = (uint16_t)(scsi_status | BIT_10);
3661 } else if (task->task_status_ctrl == TASK_SCTRL_UNDER) {
3662 scsi_status = (uint16_t)(scsi_status | BIT_11);
3664 if (task->task_sense_length) {
3665 scsi_status = (uint16_t)(scsi_status | BIT_9);
3667 bcopy(task->task_sense_data, sensbuf, task->task_sense_length);
3668 qcmd->dbuf_rsp_iu = NULL;
3672 * Fillout CTIO type 7 IOCB
3674 mutex_enter(&qlt->req_lock);
3675 req = (uint8_t *)qlt_get_req_entries(qlt, 1);
3676 if (req == NULL) {
3677 mutex_exit(&qlt->req_lock);
3678 if (use_mode2) {
3679 qlt_dmem_free(cmd->cmd_port->port_fds,
3680 qcmd->dbuf_rsp_iu);
3681 qcmd->dbuf_rsp_iu = NULL;
3683 return (FCT_BUSY);
3687 * Common fields
3689 bzero(req, IOCB_SIZE);
3690 req[0x00] = 0x12;
3691 req[0x01] = 0x1;
3692 req[0x02] = BIT_7; /* to indicate if it's a pure status req */
3693 QMEM_WR32(qlt, req + 0x04, cmd->cmd_handle);
3694 QMEM_WR16(qlt, req + 0x08, cmd->cmd_rp->rp_handle);
3695 QMEM_WR16(qlt, req + 0x0A, 0); /* not timed by FW */
3696 if (use_mode2) {
3697 QMEM_WR16(qlt, req+0x0C, 1); /* FCP RSP IU data field */
3699 QMEM_WR32(qlt, req + 0x10, cmd->cmd_rportid);
3700 QMEM_WR32(qlt, req + 0x14, qcmd->fw_xchg_addr);
3703 * Mode-specific fields
3705 if (!use_mode2) {
3706 QMEM_WR16(qlt, req + 0x18, task->task_sense_length);
3708 QMEM_WR16(qlt, req + 0x1A, flags);
3709 QMEM_WR32(qlt, req + 0x1C, task->task_resid);
3710 QMEM_WR16(qlt, req + 0x20, cmd->cmd_oxid);
3711 if (use_mode2) {
3712 bctl = (qlt_dmem_bctl_t *)qcmd->dbuf_rsp_iu->db_port_private;
3713 QMEM_WR32(qlt, req + 0x2C, 24 + task->task_sense_length);
3714 QMEM_WR64(qlt, req + 0x34, bctl->bctl_dev_addr);
3715 QMEM_WR32(qlt, req + 0x3C, 24 + task->task_sense_length);
3716 } else {
3717 QMEM_WR16(qlt, req + 0x22, scsi_status);
3718 psd = req+0x28;
3721 * Data in sense buf is always big-endian, data in IOCB
3722 * should always be little-endian, so we must do swapping.
3724 size = ((task->task_sense_length + 3) & (~3));
3725 for (ndx = 0; ndx < size; ndx += 4) {
3726 psd[ndx + 0] = sensbuf[ndx + 3];
3727 psd[ndx + 1] = sensbuf[ndx + 2];
3728 psd[ndx + 2] = sensbuf[ndx + 1];
3729 psd[ndx + 3] = sensbuf[ndx + 0];
3734 * Trigger FW to send SCSI status out
3736 qlt_submit_req_entries(qlt, 1);
3737 mutex_exit(&qlt->req_lock);
3739 return (STMF_SUCCESS);
3742 fct_status_t
3743 qlt_send_els_response(qlt_state_t *qlt, fct_cmd_t *cmd)
3745 qlt_cmd_t *qcmd;
3746 fct_els_t *els = (fct_els_t *)cmd->cmd_specific;
3747 uint8_t *req, *addr;
3748 qlt_dmem_bctl_t *bctl;
3749 uint32_t minsize;
3750 uint8_t elsop, req1f;
3752 addr = els->els_resp_payload;
3753 qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
3755 minsize = els->els_resp_size;
3756 qcmd->dbuf = qlt_i_dmem_alloc(qlt, els->els_resp_size, &minsize, 0);
3757 if (qcmd->dbuf == NULL)
3758 return (FCT_BUSY);
3760 bctl = (qlt_dmem_bctl_t *)qcmd->dbuf->db_port_private;
3762 bcopy(addr, qcmd->dbuf->db_sglist[0].seg_addr, els->els_resp_size);
3763 qlt_dmem_dma_sync(qcmd->dbuf, DDI_DMA_SYNC_FORDEV);
3765 if (addr[0] == 0x02) { /* ACC */
3766 req1f = BIT_5;
3767 } else {
3768 req1f = BIT_6;
3770 elsop = els->els_req_payload[0];
3771 if ((elsop == ELS_OP_PRLI) || (elsop == ELS_OP_PRLO) ||
3772 (elsop == ELS_OP_TPRLO) || (elsop == ELS_OP_LOGO)) {
3773 req1f = (uint8_t)(req1f | BIT_4);
3776 mutex_enter(&qlt->req_lock);
3777 req = (uint8_t *)qlt_get_req_entries(qlt, 1);
3778 if (req == NULL) {
3779 mutex_exit(&qlt->req_lock);
3780 qlt_dmem_free(NULL, qcmd->dbuf);
3781 qcmd->dbuf = NULL;
3782 return (FCT_BUSY);
3784 bzero(req, IOCB_SIZE);
3785 req[0] = 0x53; req[1] = 1; req[0xf] = 0x10;
3786 req[0x16] = elsop; req[0x1f] = req1f;
3787 QMEM_WR32(qlt, (&req[4]), cmd->cmd_handle);
3788 QMEM_WR16(qlt, (&req[0xA]), cmd->cmd_rp->rp_handle);
3789 QMEM_WR16(qlt, (&req[0xC]), 1);
3790 QMEM_WR32(qlt, (&req[0x10]), qcmd->fw_xchg_addr);
3791 QMEM_WR32(qlt, (&req[0x18]), cmd->cmd_rportid);
3792 if (qlt->cur_topology == PORT_TOPOLOGY_PT_TO_PT) {
3793 req[0x1b] = (uint8_t)((cmd->cmd_lportid >> 16) & 0xff);
3794 req[0x1c] = (uint8_t)(cmd->cmd_lportid & 0xff);
3795 req[0x1d] = (uint8_t)((cmd->cmd_lportid >> 8) & 0xff);
3797 QMEM_WR32(qlt, (&req[0x24]), els->els_resp_size);
3798 QMEM_WR64(qlt, (&req[0x28]), bctl->bctl_dev_addr);
3799 QMEM_WR32(qlt, (&req[0x30]), els->els_resp_size);
3800 qlt_submit_req_entries(qlt, 1);
3801 mutex_exit(&qlt->req_lock);
3803 return (FCT_SUCCESS);
3806 fct_status_t
3807 qlt_send_abts_response(qlt_state_t *qlt, fct_cmd_t *cmd, int terminate)
3809 qlt_abts_cmd_t *qcmd;
3810 fct_rcvd_abts_t *abts = (fct_rcvd_abts_t *)cmd->cmd_specific;
3811 uint8_t *req;
3812 uint32_t lportid;
3813 uint32_t fctl;
3814 int i;
3816 qcmd = (qlt_abts_cmd_t *)cmd->cmd_fca_private;
3818 mutex_enter(&qlt->req_lock);
3819 req = (uint8_t *)qlt_get_req_entries(qlt, 1);
3820 if (req == NULL) {
3821 mutex_exit(&qlt->req_lock);
3822 return (FCT_BUSY);
3824 bcopy(qcmd->buf, req, IOCB_SIZE);
3825 lportid = QMEM_RD32(qlt, req+0x14) & 0xFFFFFF;
3826 fctl = QMEM_RD32(qlt, req+0x1C);
3827 fctl = ((fctl ^ BIT_23) & ~BIT_22) | (BIT_19 | BIT_16);
3828 req[0] = 0x55; req[1] = 1; req[2] = (uint8_t)terminate;
3829 QMEM_WR32(qlt, (&req[4]), cmd->cmd_handle);
3830 if (cmd->cmd_rp)
3831 QMEM_WR16(qlt, (&req[0xA]), cmd->cmd_rp->rp_handle);
3832 else
3833 QMEM_WR16(qlt, (&req[0xA]), cmd->cmd_rp_handle);
3834 if (terminate) {
3835 QMEM_WR16(qlt, (&req[0xC]), 1);
3837 QMEM_WR32(qlt, req+0x14, cmd->cmd_rportid);
3838 req[0x17] = abts->abts_resp_rctl;
3839 QMEM_WR32(qlt, req+0x18, lportid);
3840 QMEM_WR32(qlt, req+0x1C, fctl);
3841 req[0x23]++;
3842 for (i = 0; i < 12; i += 4) {
3843 /* Take care of firmware's LE requirement */
3844 req[0x2C+i] = abts->abts_resp_payload[i+3];
3845 req[0x2C+i+1] = abts->abts_resp_payload[i+2];
3846 req[0x2C+i+2] = abts->abts_resp_payload[i+1];
3847 req[0x2C+i+3] = abts->abts_resp_payload[i];
3849 qlt_submit_req_entries(qlt, 1);
3850 mutex_exit(&qlt->req_lock);
3852 return (FCT_SUCCESS);
3855 static void
3856 qlt_handle_inot(qlt_state_t *qlt, uint8_t *inot)
3858 int i;
3859 uint32_t d;
3860 caddr_t req;
3861 /* Just put it on the request queue */
3862 mutex_enter(&qlt->req_lock);
3863 req = qlt_get_req_entries(qlt, 1);
3864 if (req == NULL) {
3865 mutex_exit(&qlt->req_lock);
3866 /* XXX handle this */
3867 return;
3869 for (i = 0; i < 16; i++) {
3870 d = QMEM_RD32(qlt, inot);
3871 inot += 4;
3872 QMEM_WR32(qlt, req, d);
3873 req += 4;
3875 req -= 64;
3876 req[0] = 0x0e;
3877 qlt_submit_req_entries(qlt, 1);
3878 mutex_exit(&qlt->req_lock);
3881 uint8_t qlt_task_flags[] = { 1, 3, 2, 1, 4, 0, 1, 1 };
3882 static void
3883 qlt_handle_atio(qlt_state_t *qlt, uint8_t *atio)
3885 fct_cmd_t *cmd;
3886 scsi_task_t *task;
3887 qlt_cmd_t *qcmd;
3888 uint32_t rportid, fw_xchg_addr;
3889 uint8_t *p, *q, *req, tm;
3890 uint16_t cdb_size, flags, oxid;
3891 char info[QLT_INFO_LEN];
3894 * If either bidirection xfer is requested of there is extended
3895 * CDB, atio[0x20 + 11] will be greater than or equal to 3.
3897 cdb_size = 16;
3898 if (atio[0x20 + 11] >= 3) {
3899 uint8_t b = atio[0x20 + 11];
3900 uint16_t b1;
3901 if ((b & 3) == 3) {
3902 EL(qlt, "bidirectional I/O not supported\n");
3903 cmn_err(CE_WARN, "qlt(%d) CMD with bidirectional I/O "
3904 "received, dropping the cmd as bidirectional "
3905 " transfers are not yet supported", qlt->instance);
3906 /* XXX abort the I/O */
3907 return;
3909 cdb_size = (uint16_t)(cdb_size + (b & 0xfc));
3911 * Verify that we have enough entries. Without additional CDB
3912 * Everything will fit nicely within the same 64 bytes. So the
3913 * additional cdb size is essentially the # of additional bytes
3914 * we need.
3916 b1 = (uint16_t)b;
3917 if (((((b1 & 0xfc) + 63) >> 6) + 1) > ((uint16_t)atio[1])) {
3918 EL(qlt, "extended cdb received\n");
3919 cmn_err(CE_WARN, "qlt(%d): cmd received with extended "
3920 " cdb (cdb size = %d bytes), however the firmware "
3921 " did not DMAed the entire FCP_CMD IU, entry count "
3922 " is %d while it should be %d", qlt->instance,
3923 cdb_size, atio[1], ((((b1 & 0xfc) + 63) >> 6) + 1));
3924 /* XXX abort the I/O */
3925 return;
3929 rportid = (((uint32_t)atio[8 + 5]) << 16) |
3930 (((uint32_t)atio[8 + 6]) << 8) | atio[8+7];
3931 fw_xchg_addr = QMEM_RD32(qlt, atio+4);
3932 oxid = (uint16_t)((((uint16_t)atio[8 + 16]) << 8) | atio[8+17]);
3934 if (fw_xchg_addr == 0xFFFFFFFF) {
3935 EL(qlt, "fw_xchg_addr==0xFFFFFFFF\n");
3936 cmd = NULL;
3937 } else {
3938 cmd = fct_scsi_task_alloc(qlt->qlt_port, FCT_HANDLE_NONE,
3939 rportid, atio+0x20, cdb_size, STMF_TASK_EXT_NONE);
3940 if (cmd == NULL) {
3941 EL(qlt, "fct_scsi_task_alloc cmd==NULL\n");
3944 if (cmd == NULL) {
3945 EL(qlt, "fct_scsi_task_alloc cmd==NULL\n");
3946 /* Abort this IO */
3947 flags = (uint16_t)(BIT_14 | ((atio[3] & 0xF0) << 5));
3949 mutex_enter(&qlt->req_lock);
3950 req = (uint8_t *)qlt_get_req_entries(qlt, 1);
3951 if (req == NULL) {
3952 mutex_exit(&qlt->req_lock);
3954 (void) snprintf(info, sizeof (info),
3955 "qlt_handle_atio: qlt-%p, can't "
3956 "allocate space for scsi_task", (void *)qlt);
3957 (void) fct_port_shutdown(qlt->qlt_port,
3958 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
3959 return;
3961 bzero(req, IOCB_SIZE);
3962 req[0] = 0x12; req[1] = 0x1;
3963 QMEM_WR32(qlt, req+4, 0);
3964 QMEM_WR16(qlt, req+8, fct_get_rp_handle(qlt->qlt_port,
3965 rportid));
3966 QMEM_WR16(qlt, req+10, 60);
3967 QMEM_WR32(qlt, req+0x10, rportid);
3968 QMEM_WR32(qlt, req+0x14, fw_xchg_addr);
3969 QMEM_WR16(qlt, req+0x1A, flags);
3970 QMEM_WR16(qlt, req+0x20, oxid);
3971 qlt_submit_req_entries(qlt, 1);
3972 mutex_exit(&qlt->req_lock);
3974 return;
3977 task = (scsi_task_t *)cmd->cmd_specific;
3978 qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
3979 qcmd->fw_xchg_addr = fw_xchg_addr;
3980 qcmd->param.atio_byte3 = atio[3];
3981 cmd->cmd_oxid = oxid;
3982 cmd->cmd_rxid = (uint16_t)((((uint16_t)atio[8 + 18]) << 8) |
3983 atio[8+19]);
3984 cmd->cmd_rportid = rportid;
3985 cmd->cmd_lportid = (((uint32_t)atio[8 + 1]) << 16) |
3986 (((uint32_t)atio[8 + 2]) << 8) | atio[8 + 3];
3987 cmd->cmd_rp_handle = FCT_HANDLE_NONE;
3988 /* Dont do a 64 byte read as this is IOMMU */
3989 q = atio+0x28;
3990 /* XXX Handle fcp_cntl */
3991 task->task_cmd_seq_no = (uint32_t)(*q++);
3992 task->task_csn_size = 8;
3993 task->task_flags = qlt_task_flags[(*q++) & 7];
3994 tm = *q++;
3995 if (tm) {
3996 if (tm & BIT_1)
3997 task->task_mgmt_function = TM_ABORT_TASK_SET;
3998 else if (tm & BIT_2)
3999 task->task_mgmt_function = TM_CLEAR_TASK_SET;
4000 else if (tm & BIT_4)
4001 task->task_mgmt_function = TM_LUN_RESET;
4002 else if (tm & BIT_5)
4003 task->task_mgmt_function = TM_TARGET_COLD_RESET;
4004 else if (tm & BIT_6)
4005 task->task_mgmt_function = TM_CLEAR_ACA;
4006 else
4007 task->task_mgmt_function = TM_ABORT_TASK;
4009 task->task_max_nbufs = STMF_BUFS_MAX;
4010 task->task_csn_size = 8;
4011 task->task_flags = (uint8_t)(task->task_flags | (((*q++) & 3) << 5));
4012 p = task->task_cdb;
4013 *p++ = *q++; *p++ = *q++; *p++ = *q++; *p++ = *q++;
4014 *p++ = *q++; *p++ = *q++; *p++ = *q++; *p++ = *q++;
4015 *p++ = *q++; *p++ = *q++; *p++ = *q++; *p++ = *q++;
4016 *p++ = *q++; *p++ = *q++; *p++ = *q++; *p++ = *q++;
4017 if (cdb_size > 16) {
4018 uint16_t xtra = (uint16_t)(cdb_size - 16);
4019 uint16_t i;
4020 uint8_t cb[4];
4022 while (xtra) {
4023 *p++ = *q++;
4024 xtra--;
4025 if (q == ((uint8_t *)qlt->queue_mem_ptr +
4026 ATIO_QUEUE_OFFSET + (ATIO_QUEUE_ENTRIES * 64))) {
4027 q = (uint8_t *)qlt->queue_mem_ptr +
4028 ATIO_QUEUE_OFFSET;
4031 for (i = 0; i < 4; i++) {
4032 cb[i] = *q++;
4033 if (q == ((uint8_t *)qlt->queue_mem_ptr +
4034 ATIO_QUEUE_OFFSET + (ATIO_QUEUE_ENTRIES * 64))) {
4035 q = (uint8_t *)qlt->queue_mem_ptr +
4036 ATIO_QUEUE_OFFSET;
4039 task->task_expected_xfer_length = (((uint32_t)cb[0]) << 24) |
4040 (((uint32_t)cb[1]) << 16) |
4041 (((uint32_t)cb[2]) << 8) | cb[3];
4042 } else {
4043 task->task_expected_xfer_length = (((uint32_t)q[0]) << 24) |
4044 (((uint32_t)q[1]) << 16) |
4045 (((uint32_t)q[2]) << 8) | q[3];
4047 fct_post_rcvd_cmd(cmd, 0);
4050 static void
4051 qlt_handle_dereg_completion(qlt_state_t *qlt, uint8_t *rsp)
4053 uint16_t status;
4054 uint32_t portid;
4055 uint32_t subcode1, subcode2;
4057 status = QMEM_RD16(qlt, rsp+8);
4058 portid = QMEM_RD32(qlt, rsp+0x10) & 0xffffff;
4059 subcode1 = QMEM_RD32(qlt, rsp+0x14);
4060 subcode2 = QMEM_RD32(qlt, rsp+0x18);
4062 mutex_enter(&qlt->preq_lock);
4063 if (portid != qlt->rp_id_in_dereg) {
4064 int instance = ddi_get_instance(qlt->dip);
4066 EL(qlt, "implicit logout reveived portid = %xh\n", portid);
4067 cmn_err(CE_WARN, "qlt(%d): implicit logout completion for 0x%x"
4068 " received when driver wasn't waiting for it",
4069 instance, portid);
4070 mutex_exit(&qlt->preq_lock);
4071 return;
4074 if (status != 0) {
4075 EL(qlt, "implicit logout completed for %xh with status %xh, "
4076 "subcode1 %xh subcode2 %xh\n", portid, status, subcode1,
4077 subcode2);
4078 if (status == 0x31 && subcode1 == 0x0a) {
4079 qlt->rp_dereg_status = FCT_SUCCESS;
4080 } else {
4081 EL(qlt, "implicit logout portid=%xh, status=%xh, "
4082 "subcode1=%xh, subcode2=%xh\n", portid, status,
4083 subcode1, subcode2);
4084 qlt->rp_dereg_status =
4085 QLT_FIRMWARE_ERROR(status, subcode1, subcode2);
4087 } else {
4088 qlt->rp_dereg_status = FCT_SUCCESS;
4090 cv_signal(&qlt->rp_dereg_cv);
4091 mutex_exit(&qlt->preq_lock);
4095 * Note that when an ELS is aborted, the regular or aborted completion
4096 * (if any) gets posted before the abort IOCB comes back on response queue.
4098 static void
4099 qlt_handle_unsol_els_completion(qlt_state_t *qlt, uint8_t *rsp)
4101 char info[QLT_INFO_LEN];
4102 fct_cmd_t *cmd;
4103 qlt_cmd_t *qcmd;
4104 uint32_t hndl;
4105 uint32_t subcode1, subcode2;
4106 uint16_t status;
4108 hndl = QMEM_RD32(qlt, rsp+4);
4109 status = QMEM_RD16(qlt, rsp+8);
4110 subcode1 = QMEM_RD32(qlt, rsp+0x24);
4111 subcode2 = QMEM_RD32(qlt, rsp+0x28);
4113 if (!CMD_HANDLE_VALID(hndl)) {
4114 EL(qlt, "handle = %xh\n", hndl);
4116 * This cannot happen for unsol els completion. This can
4117 * only happen when abort for an unsol els completes.
4118 * This condition indicates a firmware bug.
4120 (void) snprintf(info, sizeof (info),
4121 "qlt_handle_unsol_els_completion: "
4122 "Invalid handle: hndl-%x, status-%x/%x/%x, rsp-%p",
4123 hndl, status, subcode1, subcode2, (void *)rsp);
4124 (void) fct_port_shutdown(qlt->qlt_port,
4125 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET |
4126 STMF_RFLAG_COLLECT_DEBUG_DUMP, info);
4127 return;
4130 if (status == 5) {
4132 * When an unsolicited els is aborted, the abort is done
4133 * by a ELSPT iocb with abort control. This is the aborted IOCB
4134 * and not the abortee. We will do the cleanup when the
4135 * IOCB which caused the abort, returns.
4137 EL(qlt, "status = %xh\n", status);
4138 stmf_trace(0, "--UNSOL ELS returned with status 5 --");
4139 return;
4142 cmd = fct_handle_to_cmd(qlt->qlt_port, hndl);
4143 if (cmd == NULL) {
4144 EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", hndl);
4146 * Now why would this happen ???
4148 (void) snprintf(info, sizeof (info),
4149 "qlt_handle_unsol_els_completion: can not "
4150 "get cmd, hndl-%x, status-%x, rsp-%p", hndl, status,
4151 (void *)rsp);
4152 (void) fct_port_shutdown(qlt->qlt_port,
4153 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
4155 return;
4158 ASSERT(cmd->cmd_type == FCT_CMD_RCVD_ELS);
4159 qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
4160 if (qcmd->flags & QLT_CMD_ABORTING) {
4162 * This is the same case as "if (status == 5)" above. The
4163 * only difference is that in this case the firmware actually
4164 * finished sending the response. So the abort attempt will
4165 * come back with status ?. We will handle it there.
4167 stmf_trace(0, "--UNSOL ELS finished while we are trying to "
4168 "abort it");
4169 return;
4172 if (qcmd->dbuf != NULL) {
4173 qlt_dmem_free(NULL, qcmd->dbuf);
4174 qcmd->dbuf = NULL;
4177 if (status == 0) {
4178 fct_send_response_done(cmd, FCT_SUCCESS, FCT_IOF_FCA_DONE);
4179 } else {
4180 fct_send_response_done(cmd,
4181 QLT_FIRMWARE_ERROR(status, subcode1, subcode2), 0);
4185 static void
4186 qlt_handle_unsol_els_abort_completion(qlt_state_t *qlt, uint8_t *rsp)
4188 char info[QLT_INFO_LEN];
4189 fct_cmd_t *cmd;
4190 qlt_cmd_t *qcmd;
4191 uint32_t hndl;
4192 uint32_t subcode1, subcode2;
4193 uint16_t status;
4195 hndl = QMEM_RD32(qlt, rsp+4);
4196 status = QMEM_RD16(qlt, rsp+8);
4197 subcode1 = QMEM_RD32(qlt, rsp+0x24);
4198 subcode2 = QMEM_RD32(qlt, rsp+0x28);
4200 if (!CMD_HANDLE_VALID(hndl)) {
4201 EL(qlt, "handle = %xh\n", hndl);
4202 ASSERT(hndl == 0);
4204 * Someone has requested to abort it, but no one is waiting for
4205 * this completion.
4207 if ((status != 0) && (status != 8)) {
4208 EL(qlt, "status = %xh\n", status);
4210 * There could be exchange resource leakage, so
4211 * throw HBA fatal error event now
4213 (void) snprintf(info, sizeof (info),
4214 "qlt_handle_unsol_els_abort_completion: "
4215 "Invalid handle: hndl-%x, status-%x/%x/%x, rsp-%p",
4216 hndl, status, subcode1, subcode2, (void *)rsp);
4217 (void) fct_port_shutdown(qlt->qlt_port,
4218 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET |
4219 STMF_RFLAG_COLLECT_DEBUG_DUMP, info);
4220 return;
4223 return;
4226 cmd = fct_handle_to_cmd(qlt->qlt_port, hndl);
4227 if (cmd == NULL) {
4228 EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", hndl);
4230 * Why would this happen ??
4232 (void) snprintf(info, sizeof (info),
4233 "qlt_handle_unsol_els_abort_completion: can not get "
4234 "cmd, hndl-%x, status-%x, rsp-%p", hndl, status,
4235 (void *)rsp);
4236 (void) fct_port_shutdown(qlt->qlt_port,
4237 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
4239 return;
4242 ASSERT(cmd->cmd_type == FCT_CMD_RCVD_ELS);
4243 qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
4244 ASSERT(qcmd->flags & QLT_CMD_ABORTING);
4246 if (qcmd->dbuf != NULL) {
4247 qlt_dmem_free(NULL, qcmd->dbuf);
4248 qcmd->dbuf = NULL;
4251 if (status == 0) {
4252 fct_cmd_fca_aborted(cmd, FCT_ABORT_SUCCESS, FCT_IOF_FCA_DONE);
4253 } else if (status == 8) {
4254 fct_cmd_fca_aborted(cmd, FCT_NOT_FOUND, FCT_IOF_FCA_DONE);
4255 } else {
4256 fct_cmd_fca_aborted(cmd,
4257 QLT_FIRMWARE_ERROR(status, subcode1, subcode2), 0);
4261 static void
4262 qlt_handle_sol_els_completion(qlt_state_t *qlt, uint8_t *rsp)
4264 char info[QLT_INFO_LEN];
4265 fct_cmd_t *cmd;
4266 fct_els_t *els;
4267 qlt_cmd_t *qcmd;
4268 uint32_t hndl;
4269 uint32_t subcode1, subcode2;
4270 uint16_t status;
4272 hndl = QMEM_RD32(qlt, rsp+4);
4273 status = QMEM_RD16(qlt, rsp+8);
4274 subcode1 = QMEM_RD32(qlt, rsp+0x24);
4275 subcode2 = QMEM_RD32(qlt, rsp+0x28);
4277 if (!CMD_HANDLE_VALID(hndl)) {
4278 EL(qlt, "handle = %xh\n", hndl);
4280 * This cannot happen for sol els completion.
4282 (void) snprintf(info, sizeof (info),
4283 "qlt_handle_sol_els_completion: "
4284 "Invalid handle: hndl-%x, status-%x/%x/%x, rsp-%p",
4285 hndl, status, subcode1, subcode2, (void *)rsp);
4286 (void) fct_port_shutdown(qlt->qlt_port,
4287 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET |
4288 STMF_RFLAG_COLLECT_DEBUG_DUMP, info);
4289 return;
4292 cmd = fct_handle_to_cmd(qlt->qlt_port, hndl);
4293 if (cmd == NULL) {
4294 EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", hndl);
4295 (void) snprintf(info, sizeof (info),
4296 "qlt_handle_sol_els_completion: can not "
4297 "get cmd, hndl-%x, status-%x, rsp-%p", hndl, status,
4298 (void *)rsp);
4299 (void) fct_port_shutdown(qlt->qlt_port,
4300 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
4302 return;
4305 ASSERT(cmd->cmd_type == FCT_CMD_SOL_ELS);
4306 els = (fct_els_t *)cmd->cmd_specific;
4307 qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
4308 qcmd->fw_xchg_addr = QMEM_RD32(qlt, (&rsp[0x10]));
4310 if (qcmd->flags & QLT_CMD_ABORTING) {
4312 * We will handle it when the ABORT IO IOCB returns.
4314 return;
4317 if (qcmd->dbuf != NULL) {
4318 if (status == 0) {
4319 qlt_dmem_dma_sync(qcmd->dbuf, DDI_DMA_SYNC_FORKERNEL);
4320 bcopy(qcmd->dbuf->db_sglist[0].seg_addr +
4321 qcmd->param.resp_offset,
4322 els->els_resp_payload, els->els_resp_size);
4324 qlt_dmem_free(NULL, qcmd->dbuf);
4325 qcmd->dbuf = NULL;
4328 if (status == 0) {
4329 fct_send_cmd_done(cmd, FCT_SUCCESS, FCT_IOF_FCA_DONE);
4330 } else {
4331 fct_send_cmd_done(cmd,
4332 QLT_FIRMWARE_ERROR(status, subcode1, subcode2), 0);
4336 static void
4337 qlt_handle_ct_completion(qlt_state_t *qlt, uint8_t *rsp)
4339 fct_cmd_t *cmd;
4340 fct_sol_ct_t *ct;
4341 qlt_cmd_t *qcmd;
4342 uint32_t hndl;
4343 uint16_t status;
4344 char info[QLT_INFO_LEN];
4346 hndl = QMEM_RD32(qlt, rsp+4);
4347 status = QMEM_RD16(qlt, rsp+8);
4349 if (!CMD_HANDLE_VALID(hndl)) {
4350 EL(qlt, "handle = %xh\n", hndl);
4352 * Solicited commands will always have a valid handle.
4354 (void) snprintf(info, sizeof (info),
4355 "qlt_handle_ct_completion: "
4356 "hndl-%x, status-%x, rsp-%p", hndl, status, (void *)rsp);
4357 (void) fct_port_shutdown(qlt->qlt_port,
4358 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET |
4359 STMF_RFLAG_COLLECT_DEBUG_DUMP, info);
4360 return;
4363 cmd = fct_handle_to_cmd(qlt->qlt_port, hndl);
4364 if (cmd == NULL) {
4365 EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", hndl);
4366 (void) snprintf(info, sizeof (info),
4367 "qlt_handle_ct_completion: cannot find "
4368 "cmd, hndl-%x, status-%x, rsp-%p", hndl, status,
4369 (void *)rsp);
4370 (void) fct_port_shutdown(qlt->qlt_port,
4371 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
4373 return;
4376 ct = (fct_sol_ct_t *)cmd->cmd_specific;
4377 qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
4378 ASSERT(cmd->cmd_type == FCT_CMD_SOL_CT);
4380 if (qcmd->flags & QLT_CMD_ABORTING) {
4382 * We will handle it when ABORT IO IOCB returns;
4384 return;
4387 ASSERT(qcmd->dbuf);
4388 if (status == 0) {
4389 qlt_dmem_dma_sync(qcmd->dbuf, DDI_DMA_SYNC_FORKERNEL);
4390 bcopy(qcmd->dbuf->db_sglist[0].seg_addr +
4391 qcmd->param.resp_offset,
4392 ct->ct_resp_payload, ct->ct_resp_size);
4394 qlt_dmem_free(NULL, qcmd->dbuf);
4395 qcmd->dbuf = NULL;
4397 if (status == 0) {
4398 fct_send_cmd_done(cmd, FCT_SUCCESS, FCT_IOF_FCA_DONE);
4399 } else {
4400 fct_send_cmd_done(cmd, QLT_FIRMWARE_ERROR(status, 0, 0), 0);
4404 static void
4405 qlt_handle_ctio_completion(qlt_state_t *qlt, uint8_t *rsp)
4407 fct_cmd_t *cmd;
4408 scsi_task_t *task;
4409 qlt_cmd_t *qcmd;
4410 stmf_data_buf_t *dbuf;
4411 fct_status_t fc_st;
4412 uint32_t iof = 0;
4413 uint32_t hndl;
4414 uint16_t status;
4415 uint16_t flags;
4416 uint8_t abort_req;
4417 uint8_t n;
4418 char info[QLT_INFO_LEN];
4420 /* XXX: Check validity of the IOCB by checking 4th byte. */
4421 hndl = QMEM_RD32(qlt, rsp+4);
4422 status = QMEM_RD16(qlt, rsp+8);
4423 flags = QMEM_RD16(qlt, rsp+0x1a);
4424 n = rsp[2];
4426 if (!CMD_HANDLE_VALID(hndl)) {
4427 EL(qlt, "handle = %xh\n", hndl);
4428 ASSERT(hndl == 0);
4430 * Someone has requested to abort it, but no one is waiting for
4431 * this completion.
4433 EL(qlt, "hndl-%xh, status-%xh, rsp-%p\n", hndl, status,
4434 (void *)rsp);
4435 if ((status != 1) && (status != 2)) {
4436 EL(qlt, "status = %xh\n", status);
4438 * There could be exchange resource leakage, so
4439 * throw HBA fatal error event now
4441 (void) snprintf(info, sizeof (info),
4442 "qlt_handle_ctio_completion: hndl-"
4443 "%x, status-%x, rsp-%p", hndl, status, (void *)rsp);
4444 (void) fct_port_shutdown(qlt->qlt_port,
4445 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
4449 return;
4452 if (flags & BIT_14) {
4453 abort_req = 1;
4454 EL(qlt, "abort: hndl-%x, status-%x, rsp-%p\n", hndl, status,
4455 (void *)rsp);
4456 } else {
4457 abort_req = 0;
4460 cmd = fct_handle_to_cmd(qlt->qlt_port, hndl);
4461 if (cmd == NULL) {
4462 EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", hndl);
4463 (void) snprintf(info, sizeof (info),
4464 "qlt_handle_ctio_completion: cannot find "
4465 "cmd, hndl-%x, status-%x, rsp-%p", hndl, status,
4466 (void *)rsp);
4467 (void) fct_port_shutdown(qlt->qlt_port,
4468 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
4470 return;
4473 task = (scsi_task_t *)cmd->cmd_specific;
4474 qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
4475 if (qcmd->dbuf_rsp_iu) {
4476 ASSERT((flags & (BIT_6 | BIT_7)) == BIT_7);
4477 qlt_dmem_free(NULL, qcmd->dbuf_rsp_iu);
4478 qcmd->dbuf_rsp_iu = NULL;
4481 if ((status == 1) || (status == 2)) {
4482 if (abort_req) {
4483 fc_st = FCT_ABORT_SUCCESS;
4484 iof = FCT_IOF_FCA_DONE;
4485 } else {
4486 fc_st = FCT_SUCCESS;
4487 if (flags & BIT_15) {
4488 iof = FCT_IOF_FCA_DONE;
4491 } else {
4492 EL(qlt, "status = %xh\n", status);
4493 if ((status == 8) && abort_req) {
4494 fc_st = FCT_NOT_FOUND;
4495 iof = FCT_IOF_FCA_DONE;
4496 } else {
4497 fc_st = QLT_FIRMWARE_ERROR(status, 0, 0);
4500 dbuf = NULL;
4501 if (((n & BIT_7) == 0) && (!abort_req)) {
4502 /* A completion of data xfer */
4503 if (n == 0) {
4504 dbuf = qcmd->dbuf;
4505 } else {
4506 dbuf = stmf_handle_to_buf(task, n);
4509 ASSERT(dbuf != NULL);
4510 if (dbuf->db_flags & DB_DIRECTION_FROM_RPORT)
4511 qlt_dmem_dma_sync(dbuf, DDI_DMA_SYNC_FORCPU);
4512 if (flags & BIT_15) {
4513 dbuf->db_flags = (uint16_t)(dbuf->db_flags |
4514 DB_STATUS_GOOD_SENT);
4517 dbuf->db_xfer_status = fc_st;
4518 fct_scsi_data_xfer_done(cmd, dbuf, iof);
4519 return;
4521 if (!abort_req) {
4523 * This was just a pure status xfer.
4525 fct_send_response_done(cmd, fc_st, iof);
4526 return;
4529 fct_cmd_fca_aborted(cmd, fc_st, iof);
4532 static void
4533 qlt_handle_sol_abort_completion(qlt_state_t *qlt, uint8_t *rsp)
4535 char info[QLT_INFO_LEN];
4536 fct_cmd_t *cmd;
4537 qlt_cmd_t *qcmd;
4538 uint32_t h;
4539 uint16_t status;
4541 h = QMEM_RD32(qlt, rsp+4);
4542 status = QMEM_RD16(qlt, rsp+8);
4544 if (!CMD_HANDLE_VALID(h)) {
4545 EL(qlt, "handle = %xh\n", h);
4547 * Solicited commands always have a valid handle.
4549 (void) snprintf(info, sizeof (info),
4550 "qlt_handle_sol_abort_completion: hndl-"
4551 "%x, status-%x, rsp-%p", h, status, (void *)rsp);
4552 (void) fct_port_shutdown(qlt->qlt_port,
4553 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET |
4554 STMF_RFLAG_COLLECT_DEBUG_DUMP, info);
4555 return;
4557 cmd = fct_handle_to_cmd(qlt->qlt_port, h);
4558 if (cmd == NULL) {
4559 EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", h);
4561 * What happened to the cmd ??
4563 (void) snprintf(info, sizeof (info),
4564 "qlt_handle_sol_abort_completion: cannot "
4565 "find cmd, hndl-%x, status-%x, rsp-%p", h, status,
4566 (void *)rsp);
4567 (void) fct_port_shutdown(qlt->qlt_port,
4568 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
4570 return;
4573 ASSERT((cmd->cmd_type == FCT_CMD_SOL_ELS) ||
4574 (cmd->cmd_type == FCT_CMD_SOL_CT));
4575 qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
4576 if (qcmd->dbuf != NULL) {
4577 qlt_dmem_free(NULL, qcmd->dbuf);
4578 qcmd->dbuf = NULL;
4580 ASSERT(qcmd->flags & QLT_CMD_ABORTING);
4581 if (status == 0) {
4582 fct_cmd_fca_aborted(cmd, FCT_ABORT_SUCCESS, FCT_IOF_FCA_DONE);
4583 } else if (status == 0x31) {
4584 fct_cmd_fca_aborted(cmd, FCT_NOT_FOUND, FCT_IOF_FCA_DONE);
4585 } else {
4586 fct_cmd_fca_aborted(cmd, QLT_FIRMWARE_ERROR(status, 0, 0), 0);
4590 static void
4591 qlt_handle_rcvd_abts(qlt_state_t *qlt, uint8_t *resp)
4593 qlt_abts_cmd_t *qcmd;
4594 fct_cmd_t *cmd;
4595 uint32_t remote_portid;
4596 char info[QLT_INFO_LEN];
4598 remote_portid = ((uint32_t)(QMEM_RD16(qlt, (&resp[0x18])))) |
4599 ((uint32_t)(resp[0x1A])) << 16;
4600 cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_RCVD_ABTS,
4601 sizeof (qlt_abts_cmd_t), 0);
4602 if (cmd == NULL) {
4603 EL(qlt, "fct_alloc cmd==NULL\n");
4604 (void) snprintf(info, sizeof (info),
4605 "qlt_handle_rcvd_abts: qlt-%p, can't "
4606 "allocate space for fct_cmd", (void *)qlt);
4607 (void) fct_port_shutdown(qlt->qlt_port,
4608 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
4609 return;
4612 resp[0xC] = resp[0xD] = resp[0xE] = 0;
4613 qcmd = (qlt_abts_cmd_t *)cmd->cmd_fca_private;
4614 bcopy(resp, qcmd->buf, IOCB_SIZE);
4615 cmd->cmd_port = qlt->qlt_port;
4616 cmd->cmd_rp_handle = QMEM_RD16(qlt, resp+0xA);
4617 if (cmd->cmd_rp_handle == 0xFFFF)
4618 cmd->cmd_rp_handle = FCT_HANDLE_NONE;
4620 cmd->cmd_rportid = remote_portid;
4621 cmd->cmd_lportid = ((uint32_t)(QMEM_RD16(qlt, (&resp[0x14])))) |
4622 ((uint32_t)(resp[0x16])) << 16;
4623 cmd->cmd_oxid = QMEM_RD16(qlt, (&resp[0x26]));
4624 cmd->cmd_rxid = QMEM_RD16(qlt, (&resp[0x24]));
4625 fct_post_rcvd_cmd(cmd, 0);
4628 static void
4629 qlt_handle_abts_completion(qlt_state_t *qlt, uint8_t *resp)
4631 uint16_t status;
4632 char info[QLT_INFO_LEN];
4634 status = QMEM_RD16(qlt, resp+8);
4636 if ((status == 0) || (status == 5)) {
4637 return;
4639 EL(qlt, "status = %xh\n", status);
4640 (void) snprintf(info, sizeof (info),
4641 "ABTS completion failed %x/%x/%x resp_off %x",
4642 status, QMEM_RD32(qlt, resp+0x34), QMEM_RD32(qlt, resp+0x38),
4643 ((uint32_t)(qlt->resp_ndx_to_fw)) << 6);
4644 (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR |
4645 STMF_RFLAG_RESET | STMF_RFLAG_COLLECT_DEBUG_DUMP, info);
4648 #ifdef DEBUG
4649 uint32_t qlt_drop_abort_counter = 0;
4650 #endif
4652 fct_status_t
4653 qlt_abort_cmd(struct fct_local_port *port, fct_cmd_t *cmd, uint32_t flags)
4655 qlt_state_t *qlt = (qlt_state_t *)port->port_fca_private;
4657 if ((qlt->qlt_state == FCT_STATE_OFFLINE) ||
4658 (qlt->qlt_state == FCT_STATE_OFFLINING)) {
4659 return (FCT_NOT_FOUND);
4662 #ifdef DEBUG
4663 if (qlt_drop_abort_counter > 0) {
4664 if (atomic_dec_32_nv(&qlt_drop_abort_counter) == 1)
4665 return (FCT_SUCCESS);
4667 #endif
4669 if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
4670 return (qlt_abort_unsol_scsi_cmd(qlt, cmd));
4673 if (flags & FCT_IOF_FORCE_FCA_DONE) {
4674 cmd->cmd_handle = 0;
4677 if (cmd->cmd_type == FCT_CMD_RCVD_ABTS) {
4678 return (qlt_send_abts_response(qlt, cmd, 1));
4681 if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
4682 return (qlt_abort_purex(qlt, cmd));
4685 if ((cmd->cmd_type == FCT_CMD_SOL_ELS) ||
4686 (cmd->cmd_type == FCT_CMD_SOL_CT)) {
4687 return (qlt_abort_sol_cmd(qlt, cmd));
4689 EL(qlt, "cmd->cmd_type = %xh\n", cmd->cmd_type);
4691 ASSERT(0);
4692 return (FCT_FAILURE);
4695 fct_status_t
4696 qlt_abort_sol_cmd(qlt_state_t *qlt, fct_cmd_t *cmd)
4698 uint8_t *req;
4699 qlt_cmd_t *qcmd;
4701 qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
4702 qcmd->flags = (uint16_t)(qcmd->flags | QLT_CMD_ABORTING);
4703 EL(qlt, "fctcmd-%p, cmd_handle-%xh\n", cmd, cmd->cmd_handle);
4705 mutex_enter(&qlt->req_lock);
4706 req = (uint8_t *)qlt_get_req_entries(qlt, 1);
4707 if (req == NULL) {
4708 mutex_exit(&qlt->req_lock);
4710 return (FCT_BUSY);
4712 bzero(req, IOCB_SIZE);
4713 req[0] = 0x33; req[1] = 1;
4714 QMEM_WR32(qlt, req+4, cmd->cmd_handle);
4715 if (cmd->cmd_rp) {
4716 QMEM_WR16(qlt, req+8, cmd->cmd_rp->rp_handle);
4717 } else {
4718 QMEM_WR16(qlt, req+8, 0xFFFF);
4721 QMEM_WR32(qlt, req+0xc, cmd->cmd_handle);
4722 QMEM_WR32(qlt, req+0x30, cmd->cmd_rportid);
4723 qlt_submit_req_entries(qlt, 1);
4724 mutex_exit(&qlt->req_lock);
4726 return (FCT_SUCCESS);
4729 fct_status_t
4730 qlt_abort_purex(qlt_state_t *qlt, fct_cmd_t *cmd)
4732 uint8_t *req;
4733 qlt_cmd_t *qcmd;
4734 fct_els_t *els;
4735 uint8_t elsop, req1f;
4737 els = (fct_els_t *)cmd->cmd_specific;
4738 qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
4739 elsop = els->els_req_payload[0];
4740 EL(qlt, "fctcmd-%p, cmd_handle-%xh, elsop-%xh\n", cmd, cmd->cmd_handle,
4741 elsop);
4742 req1f = 0x60; /* Terminate xchg */
4743 if ((elsop == ELS_OP_PRLI) || (elsop == ELS_OP_PRLO) ||
4744 (elsop == ELS_OP_TPRLO) || (elsop == ELS_OP_LOGO)) {
4745 req1f = (uint8_t)(req1f | BIT_4);
4748 mutex_enter(&qlt->req_lock);
4749 req = (uint8_t *)qlt_get_req_entries(qlt, 1);
4750 if (req == NULL) {
4751 mutex_exit(&qlt->req_lock);
4753 return (FCT_BUSY);
4756 qcmd->flags = (uint16_t)(qcmd->flags | QLT_CMD_ABORTING);
4757 bzero(req, IOCB_SIZE);
4758 req[0] = 0x53; req[1] = 1; req[0xf] = 0x10;
4759 req[0x16] = elsop; req[0x1f] = req1f;
4760 QMEM_WR32(qlt, (&req[4]), cmd->cmd_handle);
4761 if (cmd->cmd_rp) {
4762 QMEM_WR16(qlt, (&req[0xA]), cmd->cmd_rp->rp_handle);
4763 EL(qlt, "rp_handle-%x\n", cmd->cmd_rp->rp_handle);
4764 } else {
4765 QMEM_WR16(qlt, (&req[0xA]), cmd->cmd_rp_handle);
4766 EL(qlt, "cmd_rp_handle-%x\n", cmd->cmd_rp_handle);
4769 QMEM_WR32(qlt, (&req[0x10]), qcmd->fw_xchg_addr);
4770 QMEM_WR32(qlt, (&req[0x18]), cmd->cmd_rportid);
4771 qlt_submit_req_entries(qlt, 1);
4772 mutex_exit(&qlt->req_lock);
4774 return (FCT_SUCCESS);
4777 fct_status_t
4778 qlt_abort_unsol_scsi_cmd(qlt_state_t *qlt, fct_cmd_t *cmd)
4780 qlt_cmd_t *qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
4781 uint8_t *req;
4782 uint16_t flags;
4784 flags = (uint16_t)(BIT_14 |
4785 (((uint16_t)qcmd->param.atio_byte3 & 0xf0) << 5));
4786 EL(qlt, "fctcmd-%p, cmd_handle-%x\n", cmd, cmd->cmd_handle);
4788 mutex_enter(&qlt->req_lock);
4789 req = (uint8_t *)qlt_get_req_entries(qlt, 1);
4790 if (req == NULL) {
4791 mutex_exit(&qlt->req_lock);
4793 return (FCT_BUSY);
4796 qcmd->flags = (uint16_t)(qcmd->flags | QLT_CMD_ABORTING);
4797 bzero(req, IOCB_SIZE);
4798 req[0] = 0x12; req[1] = 0x1;
4799 QMEM_WR32(qlt, req+4, cmd->cmd_handle);
4800 QMEM_WR16(qlt, req+8, cmd->cmd_rp->rp_handle);
4801 QMEM_WR16(qlt, req+10, 60); /* 60 seconds timeout */
4802 QMEM_WR32(qlt, req+0x10, cmd->cmd_rportid);
4803 QMEM_WR32(qlt, req+0x14, qcmd->fw_xchg_addr);
4804 QMEM_WR16(qlt, req+0x1A, flags);
4805 QMEM_WR16(qlt, req+0x20, cmd->cmd_oxid);
4806 qlt_submit_req_entries(qlt, 1);
4807 mutex_exit(&qlt->req_lock);
4809 return (FCT_SUCCESS);
4812 fct_status_t
4813 qlt_send_cmd(fct_cmd_t *cmd)
4815 qlt_state_t *qlt;
4817 qlt = (qlt_state_t *)cmd->cmd_port->port_fca_private;
4818 if (cmd->cmd_type == FCT_CMD_SOL_ELS) {
4819 return (qlt_send_els(qlt, cmd));
4820 } else if (cmd->cmd_type == FCT_CMD_SOL_CT) {
4821 return (qlt_send_ct(qlt, cmd));
4823 EL(qlt, "cmd->cmd_type = %xh\n", cmd->cmd_type);
4825 ASSERT(0);
4826 return (FCT_FAILURE);
4829 fct_status_t
4830 qlt_send_els(qlt_state_t *qlt, fct_cmd_t *cmd)
4832 uint8_t *req;
4833 fct_els_t *els;
4834 qlt_cmd_t *qcmd;
4835 stmf_data_buf_t *buf;
4836 qlt_dmem_bctl_t *bctl;
4837 uint32_t sz, minsz;
4839 els = (fct_els_t *)cmd->cmd_specific;
4840 qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
4841 qcmd->flags = QLT_CMD_TYPE_SOLICITED;
4842 qcmd->param.resp_offset = (uint16_t)((els->els_req_size + 7) & ~7);
4843 sz = minsz = qcmd->param.resp_offset + els->els_resp_size;
4844 buf = qlt_i_dmem_alloc(qlt, sz, &minsz, 0);
4845 if (buf == NULL) {
4846 return (FCT_BUSY);
4848 bctl = (qlt_dmem_bctl_t *)buf->db_port_private;
4850 qcmd->dbuf = buf;
4851 bcopy(els->els_req_payload, buf->db_sglist[0].seg_addr,
4852 els->els_req_size);
4853 qlt_dmem_dma_sync(buf, DDI_DMA_SYNC_FORDEV);
4855 mutex_enter(&qlt->req_lock);
4856 req = (uint8_t *)qlt_get_req_entries(qlt, 1);
4857 if (req == NULL) {
4858 qlt_dmem_free(NULL, buf);
4859 mutex_exit(&qlt->req_lock);
4860 return (FCT_BUSY);
4862 bzero(req, IOCB_SIZE);
4863 req[0] = 0x53; req[1] = 1;
4864 QMEM_WR32(qlt, (&req[4]), cmd->cmd_handle);
4865 QMEM_WR16(qlt, (&req[0xA]), cmd->cmd_rp->rp_handle);
4866 QMEM_WR16(qlt, (&req[0xC]), 1);
4867 QMEM_WR16(qlt, (&req[0xE]), 0x1000);
4868 QMEM_WR16(qlt, (&req[0x14]), 1);
4869 req[0x16] = els->els_req_payload[0];
4870 if (qlt->cur_topology == PORT_TOPOLOGY_PT_TO_PT) {
4871 req[0x1b] = (uint8_t)((cmd->cmd_lportid >> 16) & 0xff);
4872 req[0x1c] = (uint8_t)(cmd->cmd_lportid & 0xff);
4873 req[0x1d] = (uint8_t)((cmd->cmd_lportid >> 8) & 0xff);
4875 QMEM_WR32(qlt, (&req[0x18]), cmd->cmd_rp->rp_id);
4876 QMEM_WR32(qlt, (&req[0x20]), els->els_resp_size);
4877 QMEM_WR32(qlt, (&req[0x24]), els->els_req_size);
4878 QMEM_WR64(qlt, (&req[0x28]), bctl->bctl_dev_addr);
4879 QMEM_WR32(qlt, (&req[0x30]), els->els_req_size);
4880 QMEM_WR64(qlt, (&req[0x34]), (bctl->bctl_dev_addr +
4881 qcmd->param.resp_offset));
4882 QMEM_WR32(qlt, (&req[0x3C]), els->els_resp_size);
4883 qlt_submit_req_entries(qlt, 1);
4884 mutex_exit(&qlt->req_lock);
4886 return (FCT_SUCCESS);
4889 fct_status_t
4890 qlt_send_ct(qlt_state_t *qlt, fct_cmd_t *cmd)
4892 uint8_t *req;
4893 fct_sol_ct_t *ct;
4894 qlt_cmd_t *qcmd;
4895 stmf_data_buf_t *buf;
4896 qlt_dmem_bctl_t *bctl;
4897 uint32_t sz, minsz;
4899 ct = (fct_sol_ct_t *)cmd->cmd_specific;
4900 qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
4901 qcmd->flags = QLT_CMD_TYPE_SOLICITED;
4902 qcmd->param.resp_offset = (uint16_t)((ct->ct_req_size + 7) & ~7);
4903 sz = minsz = qcmd->param.resp_offset + ct->ct_resp_size;
4904 buf = qlt_i_dmem_alloc(qlt, sz, &minsz, 0);
4905 if (buf == NULL) {
4906 return (FCT_BUSY);
4908 bctl = (qlt_dmem_bctl_t *)buf->db_port_private;
4910 qcmd->dbuf = buf;
4911 bcopy(ct->ct_req_payload, buf->db_sglist[0].seg_addr,
4912 ct->ct_req_size);
4913 qlt_dmem_dma_sync(buf, DDI_DMA_SYNC_FORDEV);
4915 mutex_enter(&qlt->req_lock);
4916 req = (uint8_t *)qlt_get_req_entries(qlt, 1);
4917 if (req == NULL) {
4918 qlt_dmem_free(NULL, buf);
4919 mutex_exit(&qlt->req_lock);
4920 return (FCT_BUSY);
4922 bzero(req, IOCB_SIZE);
4923 req[0] = 0x29; req[1] = 1;
4924 QMEM_WR32(qlt, (&req[4]), cmd->cmd_handle);
4925 QMEM_WR16(qlt, (&req[0xA]), cmd->cmd_rp->rp_handle);
4926 QMEM_WR16(qlt, (&req[0xC]), 1);
4927 QMEM_WR16(qlt, (&req[0x10]), 0x20); /* > (2 * RA_TOV) */
4928 QMEM_WR16(qlt, (&req[0x14]), 1);
4930 QMEM_WR32(qlt, (&req[0x20]), ct->ct_resp_size);
4931 QMEM_WR32(qlt, (&req[0x24]), ct->ct_req_size);
4933 QMEM_WR64(qlt, (&req[0x28]), bctl->bctl_dev_addr); /* COMMAND DSD */
4934 QMEM_WR32(qlt, (&req[0x30]), ct->ct_req_size);
4935 QMEM_WR64(qlt, (&req[0x34]), (bctl->bctl_dev_addr +
4936 qcmd->param.resp_offset)); /* RESPONSE DSD */
4937 QMEM_WR32(qlt, (&req[0x3C]), ct->ct_resp_size);
4939 qlt_submit_req_entries(qlt, 1);
4940 mutex_exit(&qlt->req_lock);
4942 return (FCT_SUCCESS);
4947 * All QLT_FIRMWARE_* will mainly be handled in this function
4948 * It can not be called in interrupt context
4950 * FWDUMP's purpose is to serve ioctl, so we will use qlt_ioctl_flags
4951 * and qlt_ioctl_lock
4953 static fct_status_t
4954 qlt_firmware_dump(fct_local_port_t *port, stmf_state_change_info_t *ssci)
4956 qlt_state_t *qlt = (qlt_state_t *)port->port_fca_private;
4957 int i;
4958 int retries, n;
4959 uint_t size_left;
4960 char c = ' ';
4961 uint32_t addr, endaddr, words_to_read;
4962 caddr_t buf;
4963 fct_status_t ret;
4965 mutex_enter(&qlt->qlt_ioctl_lock);
4967 * To make sure that there's no outstanding dumping task
4969 if (qlt->qlt_ioctl_flags & QLT_FWDUMP_INPROGRESS) {
4970 mutex_exit(&qlt->qlt_ioctl_lock);
4971 EL(qlt, "qlt_ioctl_flags=%xh, inprogress\n",
4972 qlt->qlt_ioctl_flags);
4973 EL(qlt, "outstanding\n");
4974 return (FCT_FAILURE);
4978 * To make sure not to overwrite existing dump
4980 if ((qlt->qlt_ioctl_flags & QLT_FWDUMP_ISVALID) &&
4981 !(qlt->qlt_ioctl_flags & QLT_FWDUMP_TRIGGERED_BY_USER) &&
4982 !(qlt->qlt_ioctl_flags & QLT_FWDUMP_FETCHED_BY_USER)) {
4984 * If we have alreay one dump, but it's not triggered by user
4985 * and the user hasn't fetched it, we shouldn't dump again.
4987 mutex_exit(&qlt->qlt_ioctl_lock);
4988 EL(qlt, "qlt_ioctl_flags=%xh, already done\n",
4989 qlt->qlt_ioctl_flags);
4990 cmn_err(CE_NOTE, "qlt(%d): Skipping firmware dump as there "
4991 "is one already outstanding.", qlt->instance);
4992 return (FCT_FAILURE);
4994 qlt->qlt_ioctl_flags |= QLT_FWDUMP_INPROGRESS;
4995 if (ssci->st_rflags & STMF_RFLAG_USER_REQUEST) {
4996 qlt->qlt_ioctl_flags |= QLT_FWDUMP_TRIGGERED_BY_USER;
4997 } else {
4998 qlt->qlt_ioctl_flags &= ~QLT_FWDUMP_TRIGGERED_BY_USER;
5000 mutex_exit(&qlt->qlt_ioctl_lock);
5002 size_left = QLT_FWDUMP_BUFSIZE;
5003 if (!qlt->qlt_fwdump_buf) {
5004 ASSERT(!(qlt->qlt_ioctl_flags & QLT_FWDUMP_ISVALID));
5006 * It's the only place that we allocate buf for dumping. After
5007 * it's allocated, we will use it until the port is detached.
5009 qlt->qlt_fwdump_buf = kmem_zalloc(size_left, KM_SLEEP);
5013 * Start to dump firmware
5015 buf = (caddr_t)qlt->qlt_fwdump_buf;
5018 * Print the ISP firmware revision number and attributes information
5019 * Read the RISC to Host Status register
5021 n = (int)snprintf(buf, size_left, "ISP FW Version %d.%02d.%02d "
5022 "Attributes %04x\n\nR2H Status Register\n%08x",
5023 qlt->fw_major, qlt->fw_minor,
5024 qlt->fw_subminor, qlt->fw_attr, REG_RD32(qlt, REG_RISC_STATUS));
5025 buf += n; size_left -= n;
5028 * Before pausing the RISC, make sure no mailbox can execute
5030 mutex_enter(&qlt->mbox_lock);
5031 if (qlt->mbox_io_state != MBOX_STATE_UNKNOWN) {
5033 * Wait to grab the mailboxes
5035 for (retries = 0; (qlt->mbox_io_state != MBOX_STATE_READY) &&
5036 (qlt->mbox_io_state != MBOX_STATE_UNKNOWN); retries++) {
5037 (void) cv_timedwait(&qlt->mbox_cv, &qlt->mbox_lock,
5038 ddi_get_lbolt() + drv_usectohz(1000000));
5039 if (retries > 5) {
5040 mutex_exit(&qlt->mbox_lock);
5041 EL(qlt, "can't drain out mailbox commands\n");
5042 goto dump_fail;
5045 qlt->mbox_io_state = MBOX_STATE_UNKNOWN;
5046 cv_broadcast(&qlt->mbox_cv);
5048 mutex_exit(&qlt->mbox_lock);
5051 * Pause the RISC processor
5053 REG_WR32(qlt, REG_HCCR, HCCR_CMD(SET_RISC_PAUSE));
5056 * Wait for the RISC processor to pause
5058 for (i = 0; i < 200; i++) {
5059 if (REG_RD32(qlt, REG_RISC_STATUS) & 0x100) {
5060 break;
5062 drv_usecwait(1000);
5064 if (i == 200) {
5065 EL(qlt, "can't pause\n");
5066 return (FCT_FAILURE);
5069 if ((!qlt->qlt_25xx_chip) && (!qlt->qlt_81xx_chip)) {
5070 goto over_25xx_specific_dump;
5072 n = (int)snprintf(buf, size_left, "\n\nHostRisc registers\n");
5073 buf += n; size_left -= n;
5074 REG_WR32(qlt, 0x54, 0x7000);
5075 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5076 buf += n; size_left -= n;
5077 REG_WR32(qlt, 0x54, 0x7010);
5078 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5079 buf += n; size_left -= n;
5080 REG_WR32(qlt, 0x54, 0x7C00);
5082 n = (int)snprintf(buf, size_left, "\nPCIe registers\n");
5083 buf += n; size_left -= n;
5084 REG_WR32(qlt, 0xC0, 0x1);
5085 n = qlt_fwdump_dump_regs(qlt, buf, 0xc4, 3, size_left);
5086 buf += n; size_left -= n;
5087 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 1, size_left);
5088 buf += n; size_left -= n;
5089 REG_WR32(qlt, 0xC0, 0x0);
5091 over_25xx_specific_dump:;
5092 n = (int)snprintf(buf, size_left, "\n\nHost Interface Registers\n");
5093 buf += n; size_left -= n;
5095 * Capture data from 32 regsiters
5097 n = qlt_fwdump_dump_regs(qlt, buf, 0, 32, size_left);
5098 buf += n; size_left -= n;
5101 * Disable interrupts
5103 REG_WR32(qlt, 0xc, 0);
5106 * Shadow registers
5108 n = (int)snprintf(buf, size_left, "\nShadow Registers\n");
5109 buf += n; size_left -= n;
5111 REG_WR32(qlt, 0x54, 0xF70);
5112 addr = 0xb0000000;
5113 for (i = 0; i < 0xb; i++) {
5114 if ((!qlt->qlt_25xx_chip) &&
5115 (!qlt->qlt_81xx_chip) &&
5116 (i >= 7)) {
5117 break;
5119 if (i && ((i & 7) == 0)) {
5120 n = (int)snprintf(buf, size_left, "\n");
5121 buf += n; size_left -= n;
5123 REG_WR32(qlt, 0xF0, addr);
5124 n = (int)snprintf(buf, size_left, "%08x ", REG_RD32(qlt, 0xFC));
5125 buf += n; size_left -= n;
5126 addr += 0x100000;
5129 if ((qlt->qlt_25xx_chip) || (qlt->qlt_81xx_chip)) {
5130 REG_WR32(qlt, 0x54, 0x10);
5131 n = (int)snprintf(buf, size_left,
5132 "\n\nRISC IO Register\n%08x", REG_RD32(qlt, 0xC0));
5133 buf += n; size_left -= n;
5137 * Mailbox registers
5139 n = (int)snprintf(buf, size_left, "\n\nMailbox Registers\n");
5140 buf += n; size_left -= n;
5141 for (i = 0; i < 32; i += 2) {
5142 if ((i + 2) & 15) {
5143 c = ' ';
5144 } else {
5145 c = '\n';
5147 n = (int)snprintf(buf, size_left, "%04x %04x%c",
5148 REG_RD16(qlt, 0x80 + (i << 1)),
5149 REG_RD16(qlt, 0x80 + ((i+1) << 1)), c);
5150 buf += n; size_left -= n;
5154 * Transfer sequence registers
5156 n = (int)snprintf(buf, size_left, "\nXSEQ GP Registers\n");
5157 buf += n; size_left -= n;
5159 REG_WR32(qlt, 0x54, 0xBF00);
5160 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5161 buf += n; size_left -= n;
5162 REG_WR32(qlt, 0x54, 0xBF10);
5163 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5164 buf += n; size_left -= n;
5165 REG_WR32(qlt, 0x54, 0xBF20);
5166 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5167 buf += n; size_left -= n;
5168 REG_WR32(qlt, 0x54, 0xBF30);
5169 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5170 buf += n; size_left -= n;
5171 REG_WR32(qlt, 0x54, 0xBF40);
5172 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5173 buf += n; size_left -= n;
5174 REG_WR32(qlt, 0x54, 0xBF50);
5175 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5176 buf += n; size_left -= n;
5177 REG_WR32(qlt, 0x54, 0xBF60);
5178 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5179 buf += n; size_left -= n;
5180 REG_WR32(qlt, 0x54, 0xBF70);
5181 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5182 buf += n; size_left -= n;
5183 n = (int)snprintf(buf, size_left, "\nXSEQ-0 registers\n");
5184 buf += n; size_left -= n;
5185 if ((qlt->qlt_25xx_chip) || (qlt->qlt_81xx_chip)) {
5186 REG_WR32(qlt, 0x54, 0xBFC0);
5187 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5188 buf += n; size_left -= n;
5189 REG_WR32(qlt, 0x54, 0xBFD0);
5190 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5191 buf += n; size_left -= n;
5193 REG_WR32(qlt, 0x54, 0xBFE0);
5194 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5195 buf += n; size_left -= n;
5196 n = (int)snprintf(buf, size_left, "\nXSEQ-1 registers\n");
5197 buf += n; size_left -= n;
5198 REG_WR32(qlt, 0x54, 0xBFF0);
5199 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5200 buf += n; size_left -= n;
5203 * Receive sequence registers
5205 n = (int)snprintf(buf, size_left, "\nRSEQ GP Registers\n");
5206 buf += n; size_left -= n;
5207 REG_WR32(qlt, 0x54, 0xFF00);
5208 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5209 buf += n; size_left -= n;
5210 REG_WR32(qlt, 0x54, 0xFF10);
5211 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5212 buf += n; size_left -= n;
5213 REG_WR32(qlt, 0x54, 0xFF20);
5214 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5215 buf += n; size_left -= n;
5216 REG_WR32(qlt, 0x54, 0xFF30);
5217 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5218 buf += n; size_left -= n;
5219 REG_WR32(qlt, 0x54, 0xFF40);
5220 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5221 buf += n; size_left -= n;
5222 REG_WR32(qlt, 0x54, 0xFF50);
5223 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5224 buf += n; size_left -= n;
5225 REG_WR32(qlt, 0x54, 0xFF60);
5226 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5227 buf += n; size_left -= n;
5228 REG_WR32(qlt, 0x54, 0xFF70);
5229 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5230 buf += n; size_left -= n;
5231 n = (int)snprintf(buf, size_left, "\nRSEQ-0 registers\n");
5232 buf += n; size_left -= n;
5233 if ((qlt->qlt_25xx_chip) || (qlt->qlt_81xx_chip)) {
5234 REG_WR32(qlt, 0x54, 0xFFC0);
5235 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5236 buf += n; size_left -= n;
5238 REG_WR32(qlt, 0x54, 0xFFD0);
5239 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5240 buf += n; size_left -= n;
5241 n = (int)snprintf(buf, size_left, "\nRSEQ-1 registers\n");
5242 buf += n; size_left -= n;
5243 REG_WR32(qlt, 0x54, 0xFFE0);
5244 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5245 buf += n; size_left -= n;
5246 n = (int)snprintf(buf, size_left, "\nRSEQ-2 registers\n");
5247 buf += n; size_left -= n;
5248 REG_WR32(qlt, 0x54, 0xFFF0);
5249 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5250 buf += n; size_left -= n;
5252 if ((!qlt->qlt_25xx_chip) && (!qlt->qlt_81xx_chip))
5253 goto over_aseq_regs;
5256 * Auxiliary sequencer registers
5258 n = (int)snprintf(buf, size_left, "\nASEQ GP Registers\n");
5259 buf += n; size_left -= n;
5260 REG_WR32(qlt, 0x54, 0xB000);
5261 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5262 buf += n; size_left -= n;
5263 REG_WR32(qlt, 0x54, 0xB010);
5264 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5265 buf += n; size_left -= n;
5266 REG_WR32(qlt, 0x54, 0xB020);
5267 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5268 buf += n; size_left -= n;
5269 REG_WR32(qlt, 0x54, 0xB030);
5270 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5271 buf += n; size_left -= n;
5272 REG_WR32(qlt, 0x54, 0xB040);
5273 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5274 buf += n; size_left -= n;
5275 REG_WR32(qlt, 0x54, 0xB050);
5276 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5277 buf += n; size_left -= n;
5278 REG_WR32(qlt, 0x54, 0xB060);
5279 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5280 buf += n; size_left -= n;
5281 REG_WR32(qlt, 0x54, 0xB070);
5282 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5283 buf += n; size_left -= n;
5284 n = (int)snprintf(buf, size_left, "\nASEQ-0 registers\n");
5285 buf += n; size_left -= n;
5286 REG_WR32(qlt, 0x54, 0xB0C0);
5287 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5288 buf += n; size_left -= n;
5289 REG_WR32(qlt, 0x54, 0xB0D0);
5290 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5291 buf += n; size_left -= n;
5292 n = (int)snprintf(buf, size_left, "\nASEQ-1 registers\n");
5293 buf += n; size_left -= n;
5294 REG_WR32(qlt, 0x54, 0xB0E0);
5295 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5296 buf += n; size_left -= n;
5297 n = (int)snprintf(buf, size_left, "\nASEQ-2 registers\n");
5298 buf += n; size_left -= n;
5299 REG_WR32(qlt, 0x54, 0xB0F0);
5300 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5301 buf += n; size_left -= n;
5303 over_aseq_regs:;
5306 * Command DMA registers
5308 n = (int)snprintf(buf, size_left, "\nCommand DMA registers\n");
5309 buf += n; size_left -= n;
5310 REG_WR32(qlt, 0x54, 0x7100);
5311 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5312 buf += n; size_left -= n;
5315 * Queues
5317 n = (int)snprintf(buf, size_left,
5318 "\nRequest0 Queue DMA Channel registers\n");
5319 buf += n; size_left -= n;
5320 REG_WR32(qlt, 0x54, 0x7200);
5321 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 8, size_left);
5322 buf += n; size_left -= n;
5323 n = qlt_fwdump_dump_regs(qlt, buf, 0xe4, 7, size_left);
5324 buf += n; size_left -= n;
5326 n = (int)snprintf(buf, size_left,
5327 "\n\nResponse0 Queue DMA Channel registers\n");
5328 buf += n; size_left -= n;
5329 REG_WR32(qlt, 0x54, 0x7300);
5330 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 8, size_left);
5331 buf += n; size_left -= n;
5332 n = qlt_fwdump_dump_regs(qlt, buf, 0xe4, 7, size_left);
5333 buf += n; size_left -= n;
5335 n = (int)snprintf(buf, size_left,
5336 "\n\nRequest1 Queue DMA Channel registers\n");
5337 buf += n; size_left -= n;
5338 REG_WR32(qlt, 0x54, 0x7400);
5339 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 8, size_left);
5340 buf += n; size_left -= n;
5341 n = qlt_fwdump_dump_regs(qlt, buf, 0xe4, 7, size_left);
5342 buf += n; size_left -= n;
5345 * Transmit DMA registers
5347 n = (int)snprintf(buf, size_left, "\n\nXMT0 Data DMA registers\n");
5348 buf += n; size_left -= n;
5349 REG_WR32(qlt, 0x54, 0x7600);
5350 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5351 buf += n; size_left -= n;
5352 REG_WR32(qlt, 0x54, 0x7610);
5353 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5354 buf += n; size_left -= n;
5355 n = (int)snprintf(buf, size_left, "\nXMT1 Data DMA registers\n");
5356 buf += n; size_left -= n;
5357 REG_WR32(qlt, 0x54, 0x7620);
5358 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5359 buf += n; size_left -= n;
5360 REG_WR32(qlt, 0x54, 0x7630);
5361 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5362 buf += n; size_left -= n;
5363 n = (int)snprintf(buf, size_left, "\nXMT2 Data DMA registers\n");
5364 buf += n; size_left -= n;
5365 REG_WR32(qlt, 0x54, 0x7640);
5366 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5367 buf += n; size_left -= n;
5368 REG_WR32(qlt, 0x54, 0x7650);
5369 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5370 buf += n; size_left -= n;
5371 n = (int)snprintf(buf, size_left, "\nXMT3 Data DMA registers\n");
5372 buf += n; size_left -= n;
5373 REG_WR32(qlt, 0x54, 0x7660);
5374 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5375 buf += n; size_left -= n;
5376 REG_WR32(qlt, 0x54, 0x7670);
5377 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5378 buf += n; size_left -= n;
5379 n = (int)snprintf(buf, size_left, "\nXMT4 Data DMA registers\n");
5380 buf += n; size_left -= n;
5381 REG_WR32(qlt, 0x54, 0x7680);
5382 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5383 buf += n; size_left -= n;
5384 REG_WR32(qlt, 0x54, 0x7690);
5385 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5386 buf += n; size_left -= n;
5387 n = (int)snprintf(buf, size_left, "\nXMT Data DMA Common registers\n");
5388 buf += n; size_left -= n;
5389 REG_WR32(qlt, 0x54, 0x76A0);
5390 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5391 buf += n; size_left -= n;
5394 * Receive DMA registers
5396 n = (int)snprintf(buf, size_left,
5397 "\nRCV Thread 0 Data DMA registers\n");
5398 buf += n; size_left -= n;
5399 REG_WR32(qlt, 0x54, 0x7700);
5400 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5401 buf += n; size_left -= n;
5402 REG_WR32(qlt, 0x54, 0x7710);
5403 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5404 buf += n; size_left -= n;
5405 n = (int)snprintf(buf, size_left,
5406 "\nRCV Thread 1 Data DMA registers\n");
5407 buf += n; size_left -= n;
5408 REG_WR32(qlt, 0x54, 0x7720);
5409 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5410 buf += n; size_left -= n;
5411 REG_WR32(qlt, 0x54, 0x7730);
5412 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5413 buf += n; size_left -= n;
5416 * RISC registers
5418 n = (int)snprintf(buf, size_left, "\nRISC GP registers\n");
5419 buf += n; size_left -= n;
5420 REG_WR32(qlt, 0x54, 0x0F00);
5421 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5422 buf += n; size_left -= n;
5423 REG_WR32(qlt, 0x54, 0x0F10);
5424 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5425 buf += n; size_left -= n;
5426 REG_WR32(qlt, 0x54, 0x0F20);
5427 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5428 buf += n; size_left -= n;
5429 REG_WR32(qlt, 0x54, 0x0F30);
5430 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5431 buf += n; size_left -= n;
5432 REG_WR32(qlt, 0x54, 0x0F40);
5433 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5434 buf += n; size_left -= n;
5435 REG_WR32(qlt, 0x54, 0x0F50);
5436 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5437 buf += n; size_left -= n;
5438 REG_WR32(qlt, 0x54, 0x0F60);
5439 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5440 buf += n; size_left -= n;
5441 REG_WR32(qlt, 0x54, 0x0F70);
5442 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5443 buf += n; size_left -= n;
5446 * Local memory controller registers
5448 n = (int)snprintf(buf, size_left, "\nLMC registers\n");
5449 buf += n; size_left -= n;
5450 REG_WR32(qlt, 0x54, 0x3000);
5451 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5452 buf += n; size_left -= n;
5453 REG_WR32(qlt, 0x54, 0x3010);
5454 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5455 buf += n; size_left -= n;
5456 REG_WR32(qlt, 0x54, 0x3020);
5457 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5458 buf += n; size_left -= n;
5459 REG_WR32(qlt, 0x54, 0x3030);
5460 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5461 buf += n; size_left -= n;
5462 REG_WR32(qlt, 0x54, 0x3040);
5463 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5464 buf += n; size_left -= n;
5465 REG_WR32(qlt, 0x54, 0x3050);
5466 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5467 buf += n; size_left -= n;
5468 REG_WR32(qlt, 0x54, 0x3060);
5469 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5470 buf += n; size_left -= n;
5472 if ((qlt->qlt_25xx_chip) || (qlt->qlt_81xx_chip)) {
5473 REG_WR32(qlt, 0x54, 0x3070);
5474 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5475 buf += n; size_left -= n;
5479 * Fibre protocol module regsiters
5481 n = (int)snprintf(buf, size_left, "\nFPM hardware registers\n");
5482 buf += n; size_left -= n;
5483 REG_WR32(qlt, 0x54, 0x4000);
5484 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5485 buf += n; size_left -= n;
5486 REG_WR32(qlt, 0x54, 0x4010);
5487 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5488 buf += n; size_left -= n;
5489 REG_WR32(qlt, 0x54, 0x4020);
5490 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5491 buf += n; size_left -= n;
5492 REG_WR32(qlt, 0x54, 0x4030);
5493 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5494 buf += n; size_left -= n;
5495 REG_WR32(qlt, 0x54, 0x4040);
5496 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5497 buf += n; size_left -= n;
5498 REG_WR32(qlt, 0x54, 0x4050);
5499 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5500 buf += n; size_left -= n;
5501 REG_WR32(qlt, 0x54, 0x4060);
5502 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5503 buf += n; size_left -= n;
5504 REG_WR32(qlt, 0x54, 0x4070);
5505 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5506 buf += n; size_left -= n;
5507 REG_WR32(qlt, 0x54, 0x4080);
5508 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5509 buf += n; size_left -= n;
5510 REG_WR32(qlt, 0x54, 0x4090);
5511 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5512 buf += n; size_left -= n;
5513 REG_WR32(qlt, 0x54, 0x40A0);
5514 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5515 buf += n; size_left -= n;
5516 REG_WR32(qlt, 0x54, 0x40B0);
5517 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5518 buf += n; size_left -= n;
5519 if (qlt->qlt_81xx_chip) {
5520 REG_WR32(qlt, 0x54, 0x40C0);
5521 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5522 buf += n; size_left -= n;
5523 REG_WR32(qlt, 0x54, 0x40D0);
5524 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5525 buf += n; size_left -= n;
5529 * Fibre buffer registers
5531 n = (int)snprintf(buf, size_left, "\nFB hardware registers\n");
5532 buf += n; size_left -= n;
5533 REG_WR32(qlt, 0x54, 0x6000);
5534 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5535 buf += n; size_left -= n;
5536 REG_WR32(qlt, 0x54, 0x6010);
5537 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5538 buf += n; size_left -= n;
5539 REG_WR32(qlt, 0x54, 0x6020);
5540 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5541 buf += n; size_left -= n;
5542 REG_WR32(qlt, 0x54, 0x6030);
5543 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5544 buf += n; size_left -= n;
5545 REG_WR32(qlt, 0x54, 0x6040);
5546 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5547 buf += n; size_left -= n;
5548 REG_WR32(qlt, 0x54, 0x6100);
5549 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5550 buf += n; size_left -= n;
5551 REG_WR32(qlt, 0x54, 0x6130);
5552 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5553 buf += n; size_left -= n;
5554 REG_WR32(qlt, 0x54, 0x6150);
5555 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5556 buf += n; size_left -= n;
5557 REG_WR32(qlt, 0x54, 0x6170);
5558 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5559 buf += n; size_left -= n;
5560 REG_WR32(qlt, 0x54, 0x6190);
5561 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5562 buf += n; size_left -= n;
5563 REG_WR32(qlt, 0x54, 0x61B0);
5564 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5565 buf += n; size_left -= n;
5566 if (qlt->qlt_81xx_chip) {
5567 REG_WR32(qlt, 0x54, 0x61C0);
5568 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5569 buf += n; size_left -= n;
5571 if ((qlt->qlt_25xx_chip) || (qlt->qlt_81xx_chip)) {
5572 REG_WR32(qlt, 0x54, 0x6F00);
5573 n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
5574 buf += n; size_left -= n;
5577 qlt->intr_sneak_counter = 10;
5578 mutex_enter(&qlt->intr_lock);
5579 (void) qlt_reset_chip(qlt);
5580 drv_usecwait(20);
5581 qlt->intr_sneak_counter = 0;
5582 mutex_exit(&qlt->intr_lock);
5585 * Memory
5587 n = (int)snprintf(buf, size_left, "\nCode RAM\n");
5588 buf += n; size_left -= n;
5590 addr = 0x20000;
5591 endaddr = 0x22000;
5592 words_to_read = 0;
5593 while (addr < endaddr) {
5594 words_to_read = MBOX_DMA_MEM_SIZE >> 2;
5595 if ((words_to_read + addr) > endaddr) {
5596 words_to_read = endaddr - addr;
5598 if ((ret = qlt_read_risc_ram(qlt, addr, words_to_read)) !=
5599 QLT_SUCCESS) {
5600 EL(qlt, "Error reading risc ram - CODE RAM status="
5601 "%llxh\n", ret);
5602 goto dump_fail;
5605 n = qlt_dump_risc_ram(qlt, addr, words_to_read, buf, size_left);
5606 buf += n; size_left -= n;
5608 if (size_left < 100000) {
5609 EL(qlt, "run out of space - CODE RAM size_left=%d\n",
5610 size_left);
5611 goto dump_ok;
5613 addr += words_to_read;
5616 n = (int)snprintf(buf, size_left, "\nExternal Memory\n");
5617 buf += n; size_left -= n;
5619 addr = 0x100000;
5620 endaddr = (((uint32_t)(qlt->fw_endaddrhi)) << 16) | qlt->fw_endaddrlo;
5621 endaddr++;
5622 if (endaddr & 7) {
5623 endaddr = (endaddr + 7) & 0xFFFFFFF8;
5626 words_to_read = 0;
5627 while (addr < endaddr) {
5628 words_to_read = MBOX_DMA_MEM_SIZE >> 2;
5629 if ((words_to_read + addr) > endaddr) {
5630 words_to_read = endaddr - addr;
5632 if ((ret = qlt_read_risc_ram(qlt, addr, words_to_read)) !=
5633 QLT_SUCCESS) {
5634 EL(qlt, "Error reading risc ram - EXT RAM status="
5635 "%llxh\n", ret);
5636 goto dump_fail;
5638 n = qlt_dump_risc_ram(qlt, addr, words_to_read, buf, size_left);
5639 buf += n; size_left -= n;
5640 if (size_left < 100000) {
5641 EL(qlt, "run out of space - EXT RAM\n");
5642 goto dump_ok;
5644 addr += words_to_read;
5648 * Label the end tag
5650 n = (int)snprintf(buf, size_left, "[<==END] ISP Debug Dump\n");
5651 buf += n; size_left -= n;
5654 * Queue dumping
5656 n = (int)snprintf(buf, size_left, "\nRequest Queue\n");
5657 buf += n; size_left -= n;
5658 n = qlt_dump_queue(qlt, qlt->queue_mem_ptr + REQUEST_QUEUE_OFFSET,
5659 REQUEST_QUEUE_ENTRIES, buf, size_left);
5660 buf += n; size_left -= n;
5662 n = (int)snprintf(buf, size_left, "\nPriority Queue\n");
5663 buf += n; size_left -= n;
5664 n = qlt_dump_queue(qlt, qlt->queue_mem_ptr + PRIORITY_QUEUE_OFFSET,
5665 PRIORITY_QUEUE_ENTRIES, buf, size_left);
5666 buf += n; size_left -= n;
5668 n = (int)snprintf(buf, size_left, "\nResponse Queue\n");
5669 buf += n; size_left -= n;
5670 n = qlt_dump_queue(qlt, qlt->queue_mem_ptr + RESPONSE_QUEUE_OFFSET,
5671 RESPONSE_QUEUE_ENTRIES, buf, size_left);
5672 buf += n; size_left -= n;
5674 n = (int)snprintf(buf, size_left, "\nATIO queue\n");
5675 buf += n; size_left -= n;
5676 n = qlt_dump_queue(qlt, qlt->queue_mem_ptr + ATIO_QUEUE_OFFSET,
5677 ATIO_QUEUE_ENTRIES, buf, size_left);
5678 buf += n; size_left -= n;
5681 * Label dump reason
5683 n = (int)snprintf(buf, size_left, "\nFirmware dump reason: %s-%s\n",
5684 qlt->qlt_port_alias, ssci->st_additional_info);
5685 buf += n; size_left -= n;
5687 dump_ok:
5688 EL(qlt, "left-%d\n", size_left);
5690 mutex_enter(&qlt->qlt_ioctl_lock);
5691 qlt->qlt_ioctl_flags &=
5692 ~(QLT_FWDUMP_INPROGRESS | QLT_FWDUMP_FETCHED_BY_USER);
5693 qlt->qlt_ioctl_flags |= QLT_FWDUMP_ISVALID;
5694 mutex_exit(&qlt->qlt_ioctl_lock);
5695 return (FCT_SUCCESS);
5697 dump_fail:
5698 EL(qlt, "dump not done\n");
5699 mutex_enter(&qlt->qlt_ioctl_lock);
5700 qlt->qlt_ioctl_flags &= QLT_IOCTL_FLAG_MASK;
5701 mutex_exit(&qlt->qlt_ioctl_lock);
5702 return (FCT_FAILURE);
5705 static int
5706 qlt_fwdump_dump_regs(qlt_state_t *qlt, caddr_t buf, int startaddr, int count,
5707 uint_t size_left)
5709 int i;
5710 int n;
5711 char c = ' ';
5713 for (i = 0, n = 0; i < count; i++) {
5714 if ((i + 1) & 7) {
5715 c = ' ';
5716 } else {
5717 c = '\n';
5719 n = (int)(n + (int)snprintf(&buf[n], (uint_t)(size_left - n),
5720 "%08x%c", REG_RD32(qlt, startaddr + (i << 2)), c));
5722 return (n);
5725 static int
5726 qlt_dump_risc_ram(qlt_state_t *qlt, uint32_t addr, uint32_t words,
5727 caddr_t buf, uint_t size_left)
5729 int i;
5730 int n;
5731 char c = ' ';
5732 uint32_t *ptr;
5734 ptr = (uint32_t *)((caddr_t)qlt->queue_mem_ptr + MBOX_DMA_MEM_OFFSET);
5735 for (i = 0, n = 0; i < words; i++) {
5736 if ((i & 7) == 0) {
5737 n = (int)(n + (int)snprintf(&buf[n],
5738 (uint_t)(size_left - n), "%08x: ", addr + i));
5740 if ((i + 1) & 7) {
5741 c = ' ';
5742 } else {
5743 c = '\n';
5745 n = (int)(n + (int)snprintf(&buf[n], (uint_t)(size_left - n),
5746 "%08x%c", ptr[i], c));
5748 return (n);
5751 static int
5752 qlt_dump_queue(qlt_state_t *qlt, caddr_t qadr, int entries, caddr_t buf,
5753 uint_t size_left)
5755 int i;
5756 int n;
5757 char c = ' ';
5758 int words;
5759 uint16_t *ptr;
5760 uint16_t w;
5762 words = entries * 32;
5763 ptr = (uint16_t *)qadr;
5764 for (i = 0, n = 0; i < words; i++) {
5765 if ((i & 7) == 0) {
5766 n = (int)(n + (int)snprintf(&buf[n],
5767 (uint_t)(size_left - n), "%05x: ", i));
5769 if ((i + 1) & 7) {
5770 c = ' ';
5771 } else {
5772 c = '\n';
5774 w = QMEM_RD16(qlt, &ptr[i]);
5775 n = (int)(n + (int)snprintf(&buf[n], (size_left - n), "%04x%c",
5776 w, c));
5778 return (n);
5782 * Only called by debug dump. Interrupts are disabled and mailboxes alongwith
5783 * mailbox ram is available.
5784 * Copy data from RISC RAM to system memory
5786 static fct_status_t
5787 qlt_read_risc_ram(qlt_state_t *qlt, uint32_t addr, uint32_t words)
5789 uint64_t da;
5790 fct_status_t ret;
5792 REG_WR16(qlt, REG_MBOX(0), MBC_DUMP_RAM_EXTENDED);
5793 da = qlt->queue_mem_cookie.dmac_laddress;
5794 da += MBOX_DMA_MEM_OFFSET;
5796 /* System destination address */
5797 REG_WR16(qlt, REG_MBOX(3), LSW(LSD(da)));
5798 REG_WR16(qlt, REG_MBOX(2), MSW(LSD(da)));
5799 REG_WR16(qlt, REG_MBOX(7), LSW(MSD(da)));
5800 REG_WR16(qlt, REG_MBOX(6), MSW(MSD(da)));
5802 /* Length */
5803 REG_WR16(qlt, REG_MBOX(5), LSW(words));
5804 REG_WR16(qlt, REG_MBOX(4), MSW(words));
5806 /* RISC source address */
5807 REG_WR16(qlt, REG_MBOX(1), LSW(addr));
5808 REG_WR16(qlt, REG_MBOX(8), MSW(addr));
5810 ret = qlt_raw_mailbox_command(qlt);
5811 REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
5812 if (ret == QLT_SUCCESS) {
5813 (void) ddi_dma_sync(qlt->queue_mem_dma_handle,
5814 MBOX_DMA_MEM_OFFSET, words << 2, DDI_DMA_SYNC_FORCPU);
5815 } else {
5816 EL(qlt, "qlt_raw_mailbox_command=ch status=%llxh\n", ret);
5818 return (ret);
5821 static void
5822 qlt_verify_fw(qlt_state_t *qlt)
5824 caddr_t req;
5825 /* Just put it on the request queue */
5826 mutex_enter(&qlt->req_lock);
5827 req = qlt_get_req_entries(qlt, 1);
5828 if (req == NULL) {
5829 mutex_exit(&qlt->req_lock);
5830 /* XXX handle this */
5831 return;
5834 bzero(req, IOCB_SIZE);
5836 req[0] = 0x1b;
5837 req[1] = 1;
5839 QMEM_WR32(qlt, (&req[4]), 0xffffffff);
5840 QMEM_WR16(qlt, (&req[0x8]), 1); /* options - don't update */
5841 QMEM_WR32(qlt, (&req[0x14]), 0x80010300);
5843 qlt_submit_req_entries(qlt, 1);
5844 mutex_exit(&qlt->req_lock);
5847 static void
5848 qlt_handle_verify_fw_completion(qlt_state_t *qlt, uint8_t *rsp)
5850 uint16_t status;
5851 char info[QLT_INFO_LEN];
5853 status = QMEM_RD16(qlt, rsp+8);
5854 if (status != 0) {
5855 (void) snprintf(info, sizeof (info),
5856 "qlt_handle_verify_fw_completion: "
5857 "status:%x, rsp:%p", status, (void *)rsp);
5858 if (status == 3) {
5859 uint16_t error_code;
5861 error_code = QMEM_RD16(qlt, rsp+0xA);
5862 (void) snprintf(info, sizeof (info),
5863 "qlt_handle_verify_fw_completion: error code:%x",
5864 error_code);
5870 * qlt_el_trace_desc_ctor - Construct an extended logging trace descriptor.
5872 * Input: Pointer to the adapter state structure.
5873 * Returns: Success or Failure.
5874 * Context: Kernel context.
5876 static int
5877 qlt_el_trace_desc_ctor(qlt_state_t *qlt)
5879 int rval = DDI_SUCCESS;
5881 qlt->el_trace_desc = (qlt_el_trace_desc_t *)
5882 kmem_zalloc(sizeof (qlt_el_trace_desc_t), KM_SLEEP);
5884 if (qlt->el_trace_desc == NULL) {
5885 cmn_err(CE_WARN, "qlt(%d): can't construct trace descriptor",
5886 qlt->instance);
5887 rval = DDI_FAILURE;
5888 } else {
5889 qlt->el_trace_desc->next = 0;
5890 qlt->el_trace_desc->trace_buffer =
5891 kmem_zalloc(EL_TRACE_BUF_SIZE, KM_SLEEP);
5893 if (qlt->el_trace_desc->trace_buffer == NULL) {
5894 cmn_err(CE_WARN, "qlt(%d): can't get trace buffer",
5895 qlt->instance);
5896 kmem_free(qlt->el_trace_desc,
5897 sizeof (qlt_el_trace_desc_t));
5898 qlt->el_trace_desc = NULL;
5899 rval = DDI_FAILURE;
5900 } else {
5901 qlt->el_trace_desc->trace_buffer_size =
5902 EL_TRACE_BUF_SIZE;
5903 mutex_init(&qlt->el_trace_desc->mutex, NULL,
5904 MUTEX_DRIVER, NULL);
5908 return (rval);
5912 * qlt_el_trace_desc_dtor - Destroy an extended logging trace descriptor.
5914 * Input: Pointer to the adapter state structure.
5915 * Returns: Success or Failure.
5916 * Context: Kernel context.
5918 static int
5919 qlt_el_trace_desc_dtor(qlt_state_t *qlt)
5921 int rval = DDI_SUCCESS;
5923 if (qlt->el_trace_desc == NULL) {
5924 cmn_err(CE_WARN, "qlt(%d): can't destroy el trace descriptor",
5925 qlt->instance);
5926 rval = DDI_FAILURE;
5927 } else {
5928 if (qlt->el_trace_desc->trace_buffer != NULL) {
5929 kmem_free(qlt->el_trace_desc->trace_buffer,
5930 qlt->el_trace_desc->trace_buffer_size);
5932 mutex_destroy(&qlt->el_trace_desc->mutex);
5933 kmem_free(qlt->el_trace_desc, sizeof (qlt_el_trace_desc_t));
5934 qlt->el_trace_desc = NULL;
5937 return (rval);
5941 * qlt_el_msg
5942 * Extended logging message
5944 * Input:
5945 * qlt: adapter state pointer.
5946 * fn: function name.
5947 * ce: level
5948 * ...: Variable argument list.
5950 * Context:
5951 * Kernel/Interrupt context.
5953 void
5954 qlt_el_msg(qlt_state_t *qlt, const char *fn, int ce, ...)
5956 char *s, *fmt = 0, *fmt1 = 0;
5957 char fmt2[EL_BUFFER_RESERVE];
5958 int rval, tmp;
5959 int tracing = 0;
5960 va_list vl;
5962 /* Tracing is the default but it can be disabled. */
5963 if ((rval = qlt_validate_trace_desc(qlt)) == DDI_SUCCESS) {
5964 tracing = 1;
5966 mutex_enter(&qlt->el_trace_desc->mutex);
5969 * Ensure enough space for the string. Wrap to
5970 * start when default message allocation size
5971 * would overrun the end.
5973 if ((qlt->el_trace_desc->next + EL_BUFFER_RESERVE) >=
5974 qlt->el_trace_desc->trace_buffer_size) {
5975 fmt = qlt->el_trace_desc->trace_buffer;
5976 qlt->el_trace_desc->next = 0;
5977 } else {
5978 fmt = qlt->el_trace_desc->trace_buffer +
5979 qlt->el_trace_desc->next;
5983 /* if no buffer use the stack */
5984 if (fmt == NULL) {
5985 fmt = fmt2;
5988 va_start(vl, ce);
5990 s = va_arg(vl, char *);
5992 rval = (int)snprintf(fmt, (size_t)EL_BUFFER_RESERVE,
5993 "QEL qlt(%d): %s, ", qlt->instance, fn);
5994 fmt1 = fmt + rval;
5995 tmp = (int)vsnprintf(fmt1,
5996 (size_t)(uint32_t)((int)EL_BUFFER_RESERVE - rval), s, vl);
5997 rval += tmp;
6000 * Calculate the offset where the next message will go,
6001 * skipping the NULL.
6003 if (tracing) {
6004 uint16_t next = (uint16_t)(rval += 1);
6005 qlt->el_trace_desc->next += next;
6006 mutex_exit(&qlt->el_trace_desc->mutex);
6009 if (enable_extended_logging) {
6010 cmn_err(ce, fmt);
6013 va_end(vl);
6017 * qlt_dump_el_trace_buffer
6018 * Outputs extended logging trace buffer.
6020 * Input:
6021 * qlt: adapter state pointer.
6023 void
6024 qlt_dump_el_trace_buffer(qlt_state_t *qlt)
6026 char *dump_start = NULL;
6027 char *dump_current = NULL;
6028 char *trace_start;
6029 char *trace_end;
6030 int wrapped = 0;
6031 int rval;
6033 mutex_enter(&qlt->el_trace_desc->mutex);
6035 rval = qlt_validate_trace_desc(qlt);
6036 if (rval != 0) {
6037 cmn_err(CE_CONT, "qlt(%d) Dump EL trace - invalid desc\n",
6038 qlt->instance);
6039 } else if ((dump_start = qlt_find_trace_start(qlt)) != NULL) {
6040 dump_current = dump_start;
6041 trace_start = qlt->el_trace_desc->trace_buffer;
6042 trace_end = trace_start +
6043 qlt->el_trace_desc->trace_buffer_size;
6045 cmn_err(CE_CONT, "qlt(%d) Dump EL trace - start %p %p\n",
6046 qlt->instance,
6047 (void *)dump_start, (void *)trace_start);
6049 while (((uintptr_t)dump_current - (uintptr_t)trace_start) <=
6050 (uintptr_t)qlt->el_trace_desc->trace_buffer_size) {
6051 /* Show it... */
6052 cmn_err(CE_CONT, "%p - %s", (void *)dump_current,
6053 dump_current);
6054 /* Make the next the current */
6055 dump_current += (strlen(dump_current) + 1);
6056 /* check for wrap */
6057 if ((dump_current + EL_BUFFER_RESERVE) >= trace_end) {
6058 dump_current = trace_start;
6059 wrapped = 1;
6060 } else if (wrapped) {
6061 /* Don't go past next. */
6062 if ((trace_start + qlt->el_trace_desc->next) <=
6063 dump_current) {
6064 break;
6066 } else if (*dump_current == '\0') {
6067 break;
6071 mutex_exit(&qlt->el_trace_desc->mutex);
6075 * qlt_validate_trace_desc
6076 * Ensures the extended logging trace descriptor is good.
6078 * Input:
6079 * qlt: adapter state pointer.
6081 * Returns:
6082 * ql local function return status code.
6084 static int
6085 qlt_validate_trace_desc(qlt_state_t *qlt)
6087 int rval = DDI_SUCCESS;
6089 if (qlt->el_trace_desc == NULL) {
6090 rval = DDI_FAILURE;
6091 } else if (qlt->el_trace_desc->trace_buffer == NULL) {
6092 rval = DDI_FAILURE;
6094 return (rval);
6098 * qlt_find_trace_start
6099 * Locate the oldest extended logging trace entry.
6101 * Input:
6102 * qlt: adapter state pointer.
6104 * Returns:
6105 * Pointer to a string.
6107 * Context:
6108 * Kernel/Interrupt context.
6110 static char *
6111 qlt_find_trace_start(qlt_state_t *qlt)
6113 char *trace_start = 0;
6114 char *trace_next = 0;
6116 trace_next = qlt->el_trace_desc->trace_buffer +
6117 qlt->el_trace_desc->next;
6120 * If the buffer has not wrapped next will point at a null so
6121 * start is the beginning of the buffer. If next points at a char
6122 * then we must traverse the buffer until a null is detected and
6123 * that will be the beginning of the oldest whole object in the buffer
6124 * which is the start.
6127 if ((trace_next + EL_BUFFER_RESERVE) >=
6128 (qlt->el_trace_desc->trace_buffer +
6129 qlt->el_trace_desc->trace_buffer_size)) {
6130 trace_start = qlt->el_trace_desc->trace_buffer;
6131 } else if (*trace_next != '\0') {
6132 trace_start = trace_next + (strlen(trace_next) + 1);
6133 } else {
6134 trace_start = qlt->el_trace_desc->trace_buffer;
6136 return (trace_start);
6140 static int
6141 qlt_read_int_prop(qlt_state_t *qlt, char *prop, int defval)
6143 return (ddi_getprop(DDI_DEV_T_ANY, qlt->dip,
6144 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, prop, defval));
6147 static int
6148 qlt_read_string_prop(qlt_state_t *qlt, char *prop, char **prop_val)
6150 return (ddi_prop_lookup_string(DDI_DEV_T_ANY, qlt->dip,
6151 DDI_PROP_DONTPASS, prop, prop_val));
6154 static int
6155 qlt_read_int_instance_prop(qlt_state_t *qlt, char *prop, int defval)
6157 char inst_prop[256];
6158 int val;
6161 * Get adapter instance specific parameters. If the instance
6162 * specific parameter isn't there, try the global parameter.
6165 (void) sprintf(inst_prop, "hba%d-%s", qlt->instance, prop);
6167 if ((val = qlt_read_int_prop(qlt, inst_prop, defval)) == defval) {
6168 val = qlt_read_int_prop(qlt, prop, defval);
6171 return (val);
6174 static int
6175 qlt_read_string_instance_prop(qlt_state_t *qlt, char *prop, char **prop_val)
6177 char instance_prop[256];
6179 /* Get adapter instance specific parameter. */
6180 (void) sprintf(instance_prop, "hba%d-%s", qlt->instance, prop);
6181 return (qlt_read_string_prop(qlt, instance_prop, prop_val));
6184 static int
6185 qlt_convert_string_to_ull(char *prop, int radix,
6186 u_longlong_t *result)
6188 return (ddi_strtoull((const char *)prop, 0, radix, result));
6191 static boolean_t
6192 qlt_wwn_overload_prop(qlt_state_t *qlt)
6194 char *prop_val = 0;
6195 int rval;
6196 int radix;
6197 u_longlong_t wwnn = 0, wwpn = 0;
6198 boolean_t overloaded = FALSE;
6200 radix = 16;
6202 rval = qlt_read_string_instance_prop(qlt, "adapter-wwnn", &prop_val);
6203 if (rval == DDI_PROP_SUCCESS) {
6204 rval = qlt_convert_string_to_ull(prop_val, radix, &wwnn);
6206 if (rval == DDI_PROP_SUCCESS) {
6207 rval = qlt_read_string_instance_prop(qlt, "adapter-wwpn",
6208 &prop_val);
6209 if (rval == DDI_PROP_SUCCESS) {
6210 rval = qlt_convert_string_to_ull(prop_val, radix,
6211 &wwpn);
6214 if (rval == DDI_PROP_SUCCESS) {
6215 overloaded = TRUE;
6216 /* Overload the current node/port name nvram copy */
6217 bcopy((char *)&wwnn, qlt->nvram->node_name, 8);
6218 BIG_ENDIAN_64(qlt->nvram->node_name);
6219 bcopy((char *)&wwpn, qlt->nvram->port_name, 8);
6220 BIG_ENDIAN_64(qlt->nvram->port_name);
6222 return (overloaded);
6226 * prop_text - Return a pointer to a string describing the status
6228 * Input: prop_status = the return status from a property function.
6229 * Returns: pointer to a string.
6230 * Context: Kernel context.
6232 char *
6233 prop_text(int prop_status)
6235 string_table_t *entry = &prop_status_tbl[0];
6237 return (value2string(entry, prop_status, 0xFFFF));
6241 * value2string Return a pointer to a string associated with the value
6243 * Input: entry = the value to string table
6244 * value = the value
6245 * Returns: pointer to a string.
6246 * Context: Kernel context.
6248 char *
6249 value2string(string_table_t *entry, int value, int delimiter)
6251 for (; entry->value != delimiter; entry++) {
6252 if (entry->value == value) {
6253 break;
6256 return (entry->string);
6260 * qlt_chg_endian Change endianess of byte array.
6262 * Input: buf = array pointer.
6263 * size = size of array in bytes.
6265 * Context: Interrupt or Kernel context.
6267 void
6268 qlt_chg_endian(uint8_t buf[], size_t size)
6270 uint8_t byte;
6271 size_t cnt1;
6272 size_t cnt;
6274 cnt1 = size - 1;
6275 for (cnt = 0; cnt < size / 2; cnt++) {
6276 byte = buf[cnt1];
6277 buf[cnt1] = buf[cnt];
6278 buf[cnt] = byte;
6279 cnt1--;
6284 * ql_mps_reset
6285 * Reset MPS for FCoE functions.
6287 * Input:
6288 * ha = virtual adapter state pointer.
6290 * Context:
6291 * Kernel context.
6293 static void
6294 qlt_mps_reset(qlt_state_t *qlt)
6296 uint32_t data, dctl = 1000;
6298 do {
6299 if (dctl-- == 0 || qlt_raw_wrt_risc_ram_word(qlt, 0x7c00, 1) !=
6300 QLT_SUCCESS) {
6301 return;
6303 if (qlt_raw_rd_risc_ram_word(qlt, 0x7c00, &data) !=
6304 QLT_SUCCESS) {
6305 (void) qlt_raw_wrt_risc_ram_word(qlt, 0x7c00, 0);
6306 return;
6308 } while (!(data & BIT_0));
6310 if (qlt_raw_rd_risc_ram_word(qlt, 0x7A15, &data) == QLT_SUCCESS) {
6311 dctl = (uint16_t)PCICFG_RD16(qlt, 0x54);
6312 if ((data & 0xe0) != (dctl & 0xe0)) {
6313 data &= 0xff1f;
6314 data |= dctl & 0xe0;
6315 (void) qlt_raw_wrt_risc_ram_word(qlt, 0x7A15, data);
6318 (void) qlt_raw_wrt_risc_ram_word(qlt, 0x7c00, 0);
6322 * qlt_raw_wrt_risc_ram_word
6323 * Write RISC RAM word.
6325 * Input: qlt: adapter state pointer.
6326 * risc_address: risc ram word address.
6327 * data: data.
6329 * Returns: qlt local function return status code.
6331 * Context: Kernel context.
6333 static fct_status_t
6334 qlt_raw_wrt_risc_ram_word(qlt_state_t *qlt, uint32_t risc_address,
6335 uint32_t data)
6337 fct_status_t ret;
6339 REG_WR16(qlt, REG_MBOX(0), MBC_WRITE_RAM_EXTENDED);
6340 REG_WR16(qlt, REG_MBOX(1), LSW(risc_address));
6341 REG_WR16(qlt, REG_MBOX(2), LSW(data));
6342 REG_WR16(qlt, REG_MBOX(3), MSW(data));
6343 REG_WR16(qlt, REG_MBOX(8), MSW(risc_address));
6344 ret = qlt_raw_mailbox_command(qlt);
6345 REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
6346 if (ret != QLT_SUCCESS) {
6347 EL(qlt, "qlt_raw_mailbox_command=MBC_WRITE_RAM_EXTENDED status"
6348 "=%llxh\n", ret);
6350 return (ret);
6354 * ql_raw_rd_risc_ram_word
6355 * Read RISC RAM word.
6357 * Input: qlt: adapter state pointer.
6358 * risc_address: risc ram word address.
6359 * data: data pointer.
6361 * Returns: ql local function return status code.
6363 * Context: Kernel context.
6365 static fct_status_t
6366 qlt_raw_rd_risc_ram_word(qlt_state_t *qlt, uint32_t risc_address,
6367 uint32_t *data)
6369 fct_status_t ret;
6371 REG_WR16(qlt, REG_MBOX(0), MBC_READ_RAM_EXTENDED);
6372 REG_WR16(qlt, REG_MBOX(1), LSW(risc_address));
6373 REG_WR16(qlt, REG_MBOX(2), MSW(risc_address));
6374 ret = qlt_raw_mailbox_command(qlt);
6375 *data = REG_RD16(qlt, REG_MBOX(2));
6376 *data |= (REG_RD16(qlt, REG_MBOX(3)) << 16);
6377 REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR));
6378 if (ret != QLT_SUCCESS) {
6379 EL(qlt, "qlt_raw_mailbox_command=MBC_READ_RAM_EXTENDED status"
6380 "=%llxh\n", ret);
6382 return (ret);
6385 static void
6386 qlt_properties(qlt_state_t *qlt)
6388 int32_t cnt = 0;
6389 int32_t defval = 0xffff;
6391 if (qlt_wwn_overload_prop(qlt) == TRUE) {
6392 EL(qlt, "wwnn overloaded.\n");
6395 if ((cnt = qlt_read_int_instance_prop(qlt, "bucketcnt2k", defval)) !=
6396 defval) {
6397 qlt->qlt_bucketcnt[0] = cnt;
6398 EL(qlt, "2k bucket o/l=%d\n", cnt);
6401 if ((cnt = qlt_read_int_instance_prop(qlt, "bucketcnt8k", defval)) !=
6402 defval) {
6403 qlt->qlt_bucketcnt[1] = cnt;
6404 EL(qlt, "8k bucket o/l=%d\n", cnt);
6407 if ((cnt = qlt_read_int_instance_prop(qlt, "bucketcnt64k", defval)) !=
6408 defval) {
6409 qlt->qlt_bucketcnt[2] = cnt;
6410 EL(qlt, "64k bucket o/l=%d\n", cnt);
6413 if ((cnt = qlt_read_int_instance_prop(qlt, "bucketcnt128k", defval)) !=
6414 defval) {
6415 qlt->qlt_bucketcnt[3] = cnt;
6416 EL(qlt, "128k bucket o/l=%d\n", cnt);
6419 if ((cnt = qlt_read_int_instance_prop(qlt, "bucketcnt256", defval)) !=
6420 defval) {
6421 qlt->qlt_bucketcnt[4] = cnt;
6422 EL(qlt, "256k bucket o/l=%d\n", cnt);