Print this page
NEX-18318 qlt needs to disable MSI-X if running passthrough under ESXi
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-14413 Bad trap in module "apix" due to a NULL pointer dereference
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
NEX-10267 BAD TRAP: type=d (#gp General protection) in qlt_msix_resp_handler()
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
NEX-5733 cleanup qlt/qlc
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
NEX-5717 import QLogic 16G FC drivers
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>

*** 18,33 **** * * CDDL HEADER END */ /* ! * Copyright 2009 QLogic Corporation. All rights reserved. * Use is subject to license terms. */ /* ! * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <sys/conf.h> #include <sys/ddi.h> #include <sys/stat.h> --- 18,33 ---- * * CDDL HEADER END */ /* ! * Copyright 2009-2015 QLogic Corporation. All rights reserved. * Use is subject to license terms. */ /* ! * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. */ #include <sys/conf.h> #include <sys/ddi.h> #include <sys/stat.h>
*** 37,51 **** #include <sys/file.h> #include <sys/cred.h> #include <sys/byteorder.h> #include <sys/atomic.h> #include <sys/scsi/scsi.h> #include <sys/stmf_defines.h> #include <sys/fct_defines.h> #include <sys/stmf.h> - #include <sys/stmf_ioctl.h> #include <sys/portif.h> #include <sys/fct.h> #include "qlt.h" #include "qlt_dma.h" --- 37,55 ---- #include <sys/file.h> #include <sys/cred.h> #include <sys/byteorder.h> #include <sys/atomic.h> #include <sys/scsi/scsi.h> + #include <sys/time.h> + #ifdef __x86 + #include <sys/x86_archext.h> + #endif #include <sys/stmf_defines.h> + #include <sys/stmf_ioctl.h> #include <sys/fct_defines.h> #include <sys/stmf.h> #include <sys/portif.h> #include <sys/fct.h> #include "qlt.h" #include "qlt_dma.h"
*** 52,61 **** --- 56,69 ---- #include "qlt_ioctl.h" #include "qlt_open.h" static int qlt_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); static int qlt_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); + static uint8_t *qlt_vpd_findtag(qlt_state_t *qlt, uint8_t *vpdbuf, + int8_t *opcode); + static int qlt_vpd_lookup(qlt_state_t *qlt, uint8_t *opcode, uint8_t *bp, + int32_t bplen); static void qlt_enable_intr(qlt_state_t *); static void qlt_disable_intr(qlt_state_t *); static fct_status_t qlt_reset_chip(qlt_state_t *qlt); static fct_status_t qlt_download_fw(qlt_state_t *qlt); static fct_status_t qlt_load_risc_ram(qlt_state_t *qlt, uint32_t *host_addr,
*** 64,88 **** static mbox_cmd_t *qlt_alloc_mailbox_command(qlt_state_t *qlt, uint32_t dma_size); void qlt_free_mailbox_command(qlt_state_t *qlt, mbox_cmd_t *mcp); static fct_status_t qlt_mailbox_command(qlt_state_t *qlt, mbox_cmd_t *mcp); static uint_t qlt_isr(caddr_t arg, caddr_t arg2); static fct_status_t qlt_firmware_dump(fct_local_port_t *port, stmf_state_change_info_t *ssci); static void qlt_handle_inot(qlt_state_t *qlt, uint8_t *inot); static void qlt_handle_purex(qlt_state_t *qlt, uint8_t *resp); static void qlt_handle_atio(qlt_state_t *qlt, uint8_t *atio); ! static void qlt_handle_ctio_completion(qlt_state_t *qlt, uint8_t *rsp); static void qlt_handle_sol_abort_completion(qlt_state_t *qlt, uint8_t *rsp); static void qlt_handle_dereg_completion(qlt_state_t *qlt, uint8_t *rsp); static void qlt_handle_unsol_els_completion(qlt_state_t *qlt, uint8_t *rsp); static void qlt_handle_unsol_els_abort_completion(qlt_state_t *qlt, uint8_t *rsp); static void qlt_handle_sol_els_completion(qlt_state_t *qlt, uint8_t *rsp); ! static void qlt_handle_rcvd_abts(qlt_state_t *qlt, uint8_t *resp); ! static void qlt_handle_abts_completion(qlt_state_t *qlt, uint8_t *resp); static fct_status_t qlt_read_nvram(qlt_state_t *qlt); static void qlt_verify_fw(qlt_state_t *qlt); static void qlt_handle_verify_fw_completion(qlt_state_t *qlt, uint8_t *rsp); fct_status_t qlt_port_start(caddr_t arg); fct_status_t qlt_port_stop(caddr_t arg); fct_status_t qlt_port_online(qlt_state_t *qlt); --- 72,102 ---- static mbox_cmd_t *qlt_alloc_mailbox_command(qlt_state_t *qlt, uint32_t dma_size); void qlt_free_mailbox_command(qlt_state_t *qlt, mbox_cmd_t *mcp); static fct_status_t qlt_mailbox_command(qlt_state_t *qlt, mbox_cmd_t *mcp); static uint_t qlt_isr(caddr_t arg, caddr_t arg2); + static uint_t qlt_msix_resp_handler(caddr_t arg, caddr_t arg2); + static uint_t qlt_msix_default_handler(caddr_t arg, caddr_t arg2); static fct_status_t qlt_firmware_dump(fct_local_port_t *port, stmf_state_change_info_t *ssci); static void qlt_handle_inot(qlt_state_t *qlt, uint8_t *inot); static void qlt_handle_purex(qlt_state_t *qlt, uint8_t *resp); static void qlt_handle_atio(qlt_state_t *qlt, uint8_t *atio); ! static void qlt_handle_ctio_completion(qlt_state_t *qlt, uint8_t *rsp, ! uint16_t qi); static void qlt_handle_sol_abort_completion(qlt_state_t *qlt, uint8_t *rsp); static void qlt_handle_dereg_completion(qlt_state_t *qlt, uint8_t *rsp); static void qlt_handle_unsol_els_completion(qlt_state_t *qlt, uint8_t *rsp); static void qlt_handle_unsol_els_abort_completion(qlt_state_t *qlt, uint8_t *rsp); static void qlt_handle_sol_els_completion(qlt_state_t *qlt, uint8_t *rsp); ! static void qlt_handle_rcvd_abts(qlt_state_t *qlt, uint8_t *resp, uint16_t qi); ! static void qlt_handle_abts_completion(qlt_state_t *qlt, uint8_t *resp, ! uint16_t qi); static fct_status_t qlt_read_nvram(qlt_state_t *qlt); + static fct_status_t qlt_read_vpd(qlt_state_t *qlt); + static fct_status_t qlt_read_rom_image(qlt_state_t *qlt); static void qlt_verify_fw(qlt_state_t *qlt); static void qlt_handle_verify_fw_completion(qlt_state_t *qlt, uint8_t *rsp); fct_status_t qlt_port_start(caddr_t arg); fct_status_t qlt_port_stop(caddr_t arg); fct_status_t qlt_port_online(qlt_state_t *qlt);
*** 92,102 **** static void qlt_ctl(struct fct_local_port *port, int cmd, void *arg); static fct_status_t qlt_force_lip(qlt_state_t *); static fct_status_t qlt_do_flogi(struct fct_local_port *port, fct_flogi_xchg_t *fx); void qlt_handle_atio_queue_update(qlt_state_t *qlt); ! void qlt_handle_resp_queue_update(qlt_state_t *qlt); fct_status_t qlt_register_remote_port(fct_local_port_t *port, fct_remote_port_t *rp, fct_cmd_t *login); fct_status_t qlt_deregister_remote_port(fct_local_port_t *port, fct_remote_port_t *rp); fct_status_t qlt_send_cmd_response(fct_cmd_t *cmd, uint32_t ioflags); --- 106,116 ---- static void qlt_ctl(struct fct_local_port *port, int cmd, void *arg); static fct_status_t qlt_force_lip(qlt_state_t *); static fct_status_t qlt_do_flogi(struct fct_local_port *port, fct_flogi_xchg_t *fx); void qlt_handle_atio_queue_update(qlt_state_t *qlt); ! void qlt_handle_resp_queue_update(qlt_state_t *qlt, uint16_t qi); fct_status_t qlt_register_remote_port(fct_local_port_t *port, fct_remote_port_t *rp, fct_cmd_t *login); fct_status_t qlt_deregister_remote_port(fct_local_port_t *port, fct_remote_port_t *rp); fct_status_t qlt_send_cmd_response(fct_cmd_t *cmd, uint32_t ioflags);
*** 121,130 **** --- 135,146 ---- static int qlt_setup_interrupts(qlt_state_t *qlt); static void qlt_destroy_mutex(qlt_state_t *qlt); static fct_status_t qlt_read_risc_ram(qlt_state_t *qlt, uint32_t addr, uint32_t words); + static fct_status_t qlt_mbx_mpi_ram(qlt_state_t *qlt, uint32_t addr, + uint32_t words, uint16_t direction); static int qlt_dump_queue(qlt_state_t *qlt, caddr_t qadr, int entries, caddr_t buf, uint_t size_left); static int qlt_dump_risc_ram(qlt_state_t *qlt, uint32_t addr, uint32_t words, caddr_t buf, uint_t size_left); static int qlt_fwdump_dump_regs(qlt_state_t *qlt, caddr_t buf, int startaddr,
*** 137,148 **** static int qlt_setup_msi(qlt_state_t *qlt); static int qlt_setup_msix(qlt_state_t *qlt); static int qlt_el_trace_desc_ctor(qlt_state_t *qlt); static int qlt_el_trace_desc_dtor(qlt_state_t *qlt); - static int qlt_validate_trace_desc(qlt_state_t *qlt); - static char *qlt_find_trace_start(qlt_state_t *qlt); static int qlt_read_int_prop(qlt_state_t *qlt, char *prop, int defval); static int qlt_read_string_prop(qlt_state_t *qlt, char *prop, char **prop_val); static int qlt_read_string_instance_prop(qlt_state_t *qlt, char *prop, char **prop_val); --- 153,162 ----
*** 149,170 **** static int qlt_read_int_instance_prop(qlt_state_t *, char *, int); static int qlt_convert_string_to_ull(char *prop, int radix, u_longlong_t *result); static boolean_t qlt_wwn_overload_prop(qlt_state_t *qlt); static int qlt_quiesce(dev_info_t *dip); static fct_status_t qlt_raw_wrt_risc_ram_word(qlt_state_t *qlt, uint32_t, uint32_t); static fct_status_t qlt_raw_rd_risc_ram_word(qlt_state_t *qlt, uint32_t, uint32_t *); static void qlt_mps_reset(qlt_state_t *qlt); static void qlt_properties(qlt_state_t *qlt); #define SETELSBIT(bmp, els) (bmp)[((els) >> 3) & 0x1F] = \ (uint8_t)((bmp)[((els) >> 3) & 0x1F] | ((uint8_t)1) << ((els) & 7)) ! int qlt_enable_msix = 0; int qlt_enable_msi = 1; string_table_t prop_status_tbl[] = DDI_PROP_STATUS(); --- 163,193 ---- static int qlt_read_int_instance_prop(qlt_state_t *, char *, int); static int qlt_convert_string_to_ull(char *prop, int radix, u_longlong_t *result); static boolean_t qlt_wwn_overload_prop(qlt_state_t *qlt); static int qlt_quiesce(dev_info_t *dip); + static void qlt_disable_intr(qlt_state_t *qlt); static fct_status_t qlt_raw_wrt_risc_ram_word(qlt_state_t *qlt, uint32_t, uint32_t); static fct_status_t qlt_raw_rd_risc_ram_word(qlt_state_t *qlt, uint32_t, uint32_t *); static void qlt_mps_reset(qlt_state_t *qlt); static void qlt_properties(qlt_state_t *qlt); + static fct_status_t qlt_mq_create(qlt_state_t *qlt, int idx); + static fct_status_t qlt_mq_destroy(qlt_state_t *qlt); + static fct_status_t qlt_27xx_get_dmp_template(qlt_state_t *); + static uint32_t qlt_27xx_dmp_parse_template(qlt_state_t *, qlt_dt_hdr_t *, + uint8_t *, uint32_t); + static int qlt_27xx_dump_ram(qlt_state_t *, uint16_t, uint32_t, + uint32_t, uint8_t *); + #define SETELSBIT(bmp, els) (bmp)[((els) >> 3) & 0x1F] = \ (uint8_t)((bmp)[((els) >> 3) & 0x1F] | ((uint8_t)1) << ((els) & 7)) ! int qlt_enable_msix = 1; int qlt_enable_msi = 1; string_table_t prop_status_tbl[] = DDI_PROP_STATUS();
*** 204,217 **** NULL, ddi_power, qlt_quiesce }; ! #ifndef PORT_SPEED_10G ! #define PORT_SPEED_10G 16 #endif static struct modldrv modldrv = { &mod_driverops, QLT_NAME" "QLT_VERSION, &qlt_ops, }; --- 227,248 ---- NULL, ddi_power, qlt_quiesce }; ! #ifndef PORT_SPEED_16G ! #define PORT_SPEED_16G 32 #endif + #ifndef PORT_SPEED_32G + #define PORT_SPEED_32G 64 + #endif + + #ifndef QL_NAME + #define QL_NAME "qlt" + #endif + static struct modldrv modldrv = { &mod_driverops, QLT_NAME" "QLT_VERSION, &qlt_ops, };
*** 221,230 **** --- 252,263 ---- }; void *qlt_state = NULL; kmutex_t qlt_global_lock; static uint32_t qlt_loaded_counter = 0; + uint8_t qlt_reprocess_attempt_cnt = 5; + uint32_t qlt_reprocess_delay = 75; /* default 75 microseconds */ static char *pci_speeds[] = { " 33", "-X Mode 1 66", "-X Mode 1 100", "-X Mode 1 133", "--Invalid--", "-X Mode 2 66", "-X Mode 2 100", "-X Mode 2 133", " 66" };
*** 243,255 **** 1, /* s/g list length */ 1, /* granularity of device */ 0 /* DMA transfer flags */ }; /* qlogic logging */ int enable_extended_logging = 0; - static char qlt_provider_name[] = "qlt"; static struct stmf_port_provider *qlt_pp; int _init(void) --- 276,321 ---- 1, /* s/g list length */ 1, /* granularity of device */ 0 /* DMA transfer flags */ }; + + /* Always use 64 bit DMA. */ + static ddi_dma_attr_t qlt_queue_dma_attr_mq_req1 = { + DMA_ATTR_V0, /* dma_attr_version */ + 0, /* low DMA address range */ + 0xffffffffffffffff, /* high DMA address range */ + 0xffffffff, /* DMA counter register */ + 64, /* DMA address alignment */ + 0xff, /* DMA burstsizes */ + 1, /* min effective DMA size */ + 0xffffffff, /* max DMA xfer size */ + 0xffffffff, /* segment boundary */ + 1, /* s/g list length */ + 1, /* granularity of device */ + 0 /* DMA transfer flags */ + }; + + /* Always use 64 bit DMA. */ + static ddi_dma_attr_t qlt_queue_dma_attr_mq_rsp1 = { + DMA_ATTR_V0, /* dma_attr_version */ + 0, /* low DMA address range */ + 0xffffffffffffffff, /* high DMA address range */ + 0xffffffff, /* DMA counter register */ + 64, /* DMA address alignment */ + 0xff, /* DMA burstsizes */ + 1, /* min effective DMA size */ + 0xffffffff, /* max DMA xfer size */ + 0xffffffff, /* segment boundary */ + 1, /* s/g list length */ + 1, /* granularity of device */ + 0 /* DMA transfer flags */ + }; + + /* qlogic logging */ int enable_extended_logging = 0; static char qlt_provider_name[] = "qlt"; static struct stmf_port_provider *qlt_pp; int _init(void)
*** 301,311 **** _info(struct modinfo *modinfop) { return (mod_info(&modlinkage, modinfop)); } - static int qlt_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { int instance; qlt_state_t *qlt; --- 367,376 ----
*** 322,376 **** /* No support for suspend resume yet */ if (cmd != DDI_ATTACH) return (DDI_FAILURE); instance = ddi_get_instance(dip); if (ddi_soft_state_zalloc(qlt_state, instance) != DDI_SUCCESS) { return (DDI_FAILURE); } if ((qlt = (qlt_state_t *)ddi_get_soft_state(qlt_state, instance)) == NULL) { goto attach_fail_1; } qlt->instance = instance; qlt->nvram = (qlt_nvram_t *)kmem_zalloc(sizeof (qlt_nvram_t), KM_SLEEP); qlt->dip = dip; if (qlt_el_trace_desc_ctor(qlt) != DDI_SUCCESS) { cmn_err(CE_WARN, "qlt(%d): can't setup el tracing", instance); ! goto attach_fail_1; } EL(qlt, "instance=%d, ptr=%p\n", instance, (void *)qlt); if (pci_config_setup(dip, &qlt->pcicfg_acc_handle) != DDI_SUCCESS) { ! goto attach_fail_2; } did = PCICFG_RD16(qlt, PCI_CONF_DEVID); if ((did != 0x2422) && (did != 0x2432) && (did != 0x8432) && (did != 0x2532) && ! (did != 0x8001)) { cmn_err(CE_WARN, "qlt(%d): unknown devid(%x), failing attach", instance, did); goto attach_fail_4; } ! if ((did & 0xFF00) == 0x8000) qlt->qlt_81xx_chip = 1; ! else if ((did & 0xFF00) == 0x2500) qlt->qlt_25xx_chip = 1; dev_acc_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; dev_acc_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; dev_acc_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; if (ddi_regs_map_setup(dip, 2, &qlt->regs, 0, 0x100, &dev_acc_attr, &qlt->regs_acc_handle) != DDI_SUCCESS) { goto attach_fail_4; } if (did == 0x2422) { uint32_t pci_bits = REG_RD32(qlt, REG_CTRL_STATUS); uint32_t slot = pci_bits & PCI_64_BIT_SLOT; pci_bits >>= 8; pci_bits &= 0xf; --- 387,689 ---- /* No support for suspend resume yet */ if (cmd != DDI_ATTACH) return (DDI_FAILURE); instance = ddi_get_instance(dip); + cmn_err(CE_CONT, "!Qlogic %s(%d) FCA Driver v%s\n", + QLT_NAME, instance, QLT_VERSION); + if (ddi_soft_state_zalloc(qlt_state, instance) != DDI_SUCCESS) { + cmn_err(CE_WARN, "qlt(%d): soft state alloc failed", instance); return (DDI_FAILURE); } if ((qlt = (qlt_state_t *)ddi_get_soft_state(qlt_state, instance)) == NULL) { + cmn_err(CE_WARN, "qlt(%d): can't get soft state", instance); goto attach_fail_1; } qlt->instance = instance; qlt->nvram = (qlt_nvram_t *)kmem_zalloc(sizeof (qlt_nvram_t), KM_SLEEP); + qlt->vpd = (uint32_t *)kmem_zalloc(QL_24XX_VPD_SIZE, KM_SLEEP); qlt->dip = dip; if (qlt_el_trace_desc_ctor(qlt) != DDI_SUCCESS) { cmn_err(CE_WARN, "qlt(%d): can't setup el tracing", instance); ! goto attach_fail_2; } EL(qlt, "instance=%d, ptr=%p\n", instance, (void *)qlt); if (pci_config_setup(dip, &qlt->pcicfg_acc_handle) != DDI_SUCCESS) { ! cmn_err(CE_WARN, "qlt(%d): pci_config_setup failed", instance); ! goto attach_fail_3; } + did = PCICFG_RD16(qlt, PCI_CONF_DEVID); if ((did != 0x2422) && (did != 0x2432) && (did != 0x8432) && (did != 0x2532) && ! (did != 0x8001) && (did != 0x2031) && ! (did != 0x2071) && (did != 0x2261)) { cmn_err(CE_WARN, "qlt(%d): unknown devid(%x), failing attach", instance, did); goto attach_fail_4; } ! if ((did & 0xFFFF) == 0x2071) { ! qlt->qlt_27xx_chip = 1; ! qlt->qlt_fcoe_enabled = 0; ! } else if ((did & 0xFFFF) == 0x2261) { ! qlt->qlt_27xx_chip = 1; ! qlt->qlt_fcoe_enabled = 0; ! } else if ((did & 0xFFFF) == 0x2031) { ! qlt->qlt_83xx_chip = 1; ! qlt->qlt_fcoe_enabled = 0; ! } else if ((did & 0xFFF0) == 0x8000) { qlt->qlt_81xx_chip = 1; ! qlt->qlt_fcoe_enabled = 1; ! } else if ((did & 0xFF00) == 0x2500) qlt->qlt_25xx_chip = 1; dev_acc_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; dev_acc_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; dev_acc_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; + + if ((qlt->qlt_83xx_chip) || (qlt->qlt_27xx_chip)) { + int stat_1; + off_t regsize_1; + + stat_1 = ddi_dev_regsize(dip, 1, &regsize_1); + if (stat_1 != DDI_SUCCESS) { + stmf_trace(qlt->qlt_port_alias, + "instance=%d, reg 1 regsize failed," + " stat %x", instance, stat_1); + goto attach_fail_4; + } + + if (ddi_regs_map_setup(dip, 1, &qlt->regs, 0, regsize_1, + &dev_acc_attr, &qlt->regs_acc_handle) != DDI_SUCCESS) { + cmn_err(CE_NOTE, "qlt(%d) ddi_regs_map_setup failed\n", + instance); + goto attach_fail_4; + } + } else { + /* + * 24xx and 25xx: rnumber 0 is config space + * rnumber 1 is for IO space + * rnumber 2 is for MBAR0: ISP, MSIX, PBA + */ if (ddi_regs_map_setup(dip, 2, &qlt->regs, 0, 0x100, &dev_acc_attr, &qlt->regs_acc_handle) != DDI_SUCCESS) { goto attach_fail_4; } + } + + if ((qlt->qlt_83xx_chip) || (qlt->qlt_27xx_chip)) { + + uint32_t w32h; + uint32_t w32l; + int stat; + off_t regsize; + + w32l = PCICFG_RD32(qlt, PCI_CONF_BASE2); + w32h = PCICFG_RD32(qlt, PCI_CONF_BASE3); + + if ((w32h > 0) || w32l > 0) { + stat = ddi_dev_regsize(dip, 2, &regsize); + if (stat != DDI_SUCCESS) { + stmf_trace(qlt->qlt_port_alias, + "instance=%d, MSI-X regsize failed," + " stat %x", instance, stat); + } + stmf_trace(qlt->qlt_port_alias, + "instance=%d, MSI-X MEM Bar size %x", + instance, regsize); + + stat = ddi_regs_map_setup(dip, 2, &qlt->msix_base, 0, + /* ((MQ_MAX_QUEUES * 2) +1) << 2, */ + regsize, + &dev_acc_attr, &qlt->msix_acc_handle); + + if (stat != DDI_SUCCESS || qlt->msix_base == NULL || + qlt->msix_acc_handle == NULL) { + + cmn_err(CE_WARN, + "qlt(%d): can't map MBar for MSI-X", + instance); + stmf_trace(qlt->qlt_port_alias, + "instance=%d, MSI-X MEM Bar map fail", + instance); + + if (qlt->msix_acc_handle != NULL) { + ddi_regs_map_free( + &qlt->msix_acc_handle); + } + goto attach_fail_5; + } + } else { + cmn_err(CE_WARN, "qlt(%d): can't setup MBar for MSI-X", + instance); + stmf_trace(qlt->qlt_port_alias, + "instance=%d, No MSI-X MEM Bar", instance); + goto attach_fail_5; + } + + w32l = PCICFG_RD32(qlt, PCI_CONF_BASE4); + w32h = PCICFG_RD32(qlt, PCI_CONF_BASE5); + + if ((w32h > 0) || w32l > 0) { + stat = ddi_dev_regsize(dip, 3, &regsize); + if (stat != DDI_SUCCESS) { + stmf_trace(qlt->qlt_port_alias, + "instance=%d, MQ regsize failed, stat %x", + instance, stat); + } + stmf_trace(qlt->qlt_port_alias, + "instance=%d, MQ MEM Bar size %x", + instance, regsize); + + /* for 83xx the QP pointers are in the 3rd MBar */ + stat = ddi_regs_map_setup(dip, 3, &qlt->mq_reg_base, 0, + (MQ_MAX_QUEUES * MQBAR_REG_OFFSET), + &dev_acc_attr, &qlt->mq_reg_acc_handle); + + if (stat != DDI_SUCCESS || qlt->mq_reg_base == NULL || + qlt->mq_reg_acc_handle == NULL) { + + cmn_err(CE_WARN, "qlt(%d): can't map QP MBar", + instance); + stmf_trace(qlt->qlt_port_alias, + "instance=%d, QP MEM Bar map fail st:%x", + instance, stat); + + if (qlt->msix_acc_handle != NULL) { + ddi_regs_map_free( + &qlt->msix_acc_handle); + } + if (qlt->mq_reg_acc_handle != NULL) { + ddi_regs_map_free( + &qlt->mq_reg_acc_handle); + } + goto attach_fail_5; + } else { + qlt->qlt_mq_enabled = 1; + } + } else { + cmn_err(CE_WARN, "qlt(%d): can't setup MBar for QPs", + instance); + stmf_trace(qlt->qlt_port_alias, + "instance=%d, No QPs MEM Bar", instance); + + if (qlt->msix_acc_handle != NULL) { + ddi_regs_map_free( + &qlt->msix_acc_handle); + } + goto attach_fail_5; + } + } else if (qlt->qlt_81xx_chip) { + + uint32_t w32; + int stat; + + w32 = PCICFG_RD32(qlt, PCI_CONF_BASE3); + if (w32 == 0) { + + cmn_err(CE_WARN, "qlt(%d): can't setup MBar2", + instance); + stmf_trace(qlt->qlt_port_alias, + "instance=%d, No MEM Bar2", instance); + goto attach_fail_5; + } + + stat = ddi_regs_map_setup(dip, 3, &qlt->mq_reg_base, 0, + (MQ_MAX_QUEUES * MQBAR_REG_OFFSET), + &dev_acc_attr, &qlt->mq_reg_acc_handle); + + if (stat != DDI_SUCCESS || qlt->mq_reg_base == NULL || + qlt->mq_reg_acc_handle == NULL) { + + cmn_err(CE_WARN, "qlt(%d): can't map MBar2", + instance); + stmf_trace(qlt->qlt_port_alias, + "instance=%d, MEM Bar2 map fail", instance); + + if (qlt->mq_reg_acc_handle != NULL) { + ddi_regs_map_free(&qlt->mq_reg_acc_handle); + } + goto attach_fail_5; + } else { + qlt->qlt_mq_enabled = 1; + } + } else if (qlt->qlt_25xx_chip) { + uint32_t w32h; + uint32_t w32l; + int stat; + off_t regsize; + + /* MBAR2 rnumber 3 */ + w32l = PCICFG_RD32(qlt, PCI_CONF_BASE3); + w32h = PCICFG_RD32(qlt, PCI_CONF_BASE4); + + if ((w32h > 0) || (w32l > 0)) { + stat = ddi_dev_regsize(dip, 3, &regsize); + if (stat != DDI_SUCCESS) { + stmf_trace(qlt->qlt_port_alias, + "ISP25xx inst=%d, MQ regsize failed, stat %x", + instance, stat); + EL(qlt, "ISP25xx MQ regsize failed, stat %x\n", + stat); + + } + stmf_trace(qlt->qlt_port_alias, + "ISP25xx instance=%d, MQ MEM Bar size %lx", + instance, regsize); + EL(qlt, "ISP25xx MQ MEM Bar (MBAR2) size: %x\n", + regsize); + + stat = ddi_regs_map_setup(dip, 3, &qlt->mq_reg_base, 0, + (MQ_MAX_QUEUES * MQBAR_REG_OFFSET), + &dev_acc_attr, &qlt->mq_reg_acc_handle); + if (stat != DDI_SUCCESS || qlt->mq_reg_base == NULL || + qlt->mq_reg_acc_handle == NULL) { + cmn_err(CE_WARN, + "qlt(%d): ISP25xx can't map QP MBar", + instance); + stmf_trace(qlt->qlt_port_alias, + "instance=%d, QP MEM Bar map fail st:%x", + instance, stat); + if (qlt->mq_reg_acc_handle != NULL) { + ddi_regs_map_free( + &qlt->mq_reg_acc_handle); + } + } else { + qlt->qlt_mq_enabled = 1; + } + } else { + stmf_trace(qlt->qlt_port_alias, + "instance=%d, No QPs MEM Bar", instance); + EL(qlt, + "ISP25xx can't setup MBar QPs, use baseq\n"); + } + } + + if (qlt->qlt_mq_enabled) { + qlt->mq_req = kmem_zalloc( + ((sizeof (qlt_mq_req_ptr_blk_t)) * MQ_MAX_QUEUES), + KM_SLEEP); + qlt->mq_resp = kmem_zalloc( + ((sizeof (qlt_mq_rsp_ptr_blk_t)) * MQ_MAX_QUEUES), + KM_SLEEP); + } else { + qlt->mq_req = kmem_zalloc( + (sizeof (qlt_mq_req_ptr_blk_t)), KM_SLEEP); + qlt->mq_resp = kmem_zalloc( + (sizeof (qlt_mq_rsp_ptr_blk_t)), KM_SLEEP); + } + if (did == 0x2422) { uint32_t pci_bits = REG_RD32(qlt, REG_CTRL_STATUS); uint32_t slot = pci_bits & PCI_64_BIT_SLOT; pci_bits >>= 8; pci_bits &= 0xf;
*** 390,399 **** --- 703,722 ---- if ((ret = qlt_read_nvram(qlt)) != QLT_SUCCESS) { cmn_err(CE_WARN, "qlt(%d): read nvram failure %llx", instance, (unsigned long long)ret); goto attach_fail_5; } + if ((ret = qlt_read_vpd(qlt)) != QLT_SUCCESS) { + cmn_err(CE_WARN, "qlt(%d): read vpd failure %llx", instance, + (unsigned long long)ret); + goto attach_fail_5; + } + if ((ret = qlt_read_rom_image(qlt)) != QLT_SUCCESS) { + cmn_err(CE_WARN, "qlt(%d): read rom image failure %llx", + instance, (unsigned long long)ret); + goto attach_fail_5; + } qlt_properties(qlt); if (ddi_dma_alloc_handle(dip, &qlt_queue_dma_attr, DDI_DMA_SLEEP, 0, &qlt->queue_mem_dma_handle) != DDI_SUCCESS) {
*** 411,429 **** &qlt->queue_mem_cookie, &ncookies) != DDI_SUCCESS) { goto attach_fail_7; } if (ncookies != 1) goto attach_fail_8; ! qlt->req_ptr = qlt->queue_mem_ptr + REQUEST_QUEUE_OFFSET; ! qlt->resp_ptr = qlt->queue_mem_ptr + RESPONSE_QUEUE_OFFSET; qlt->preq_ptr = qlt->queue_mem_ptr + PRIORITY_QUEUE_OFFSET; qlt->atio_ptr = qlt->queue_mem_ptr + ATIO_QUEUE_OFFSET; /* mutex are inited in this function */ if (qlt_setup_interrupts(qlt) != DDI_SUCCESS) goto attach_fail_8; (void) snprintf(qlt->qlt_minor_name, sizeof (qlt->qlt_minor_name), "qlt%d", instance); (void) snprintf(qlt->qlt_port_alias, sizeof (qlt->qlt_port_alias), "%s,0", qlt->qlt_minor_name); --- 734,778 ---- &qlt->queue_mem_cookie, &ncookies) != DDI_SUCCESS) { goto attach_fail_7; } if (ncookies != 1) goto attach_fail_8; ! ! /* ! * Base queue (0), alwasy available ! */ ! qlt->mq_req[0].queue_mem_mq_base_addr = ! qlt->mq_req[0].mq_ptr = ! qlt->queue_mem_ptr + REQUEST_QUEUE_OFFSET; ! qlt->mq_resp[0].queue_mem_mq_base_addr = ! qlt->mq_resp[0].mq_ptr = ! qlt->queue_mem_ptr + RESPONSE_QUEUE_OFFSET; ! qlt->preq_ptr = qlt->queue_mem_ptr + PRIORITY_QUEUE_OFFSET; qlt->atio_ptr = qlt->queue_mem_ptr + ATIO_QUEUE_OFFSET; /* mutex are inited in this function */ if (qlt_setup_interrupts(qlt) != DDI_SUCCESS) goto attach_fail_8; + qlt->qlt_queue_cnt = 1; + if ((qlt->qlt_mq_enabled) && (qlt->intr_cnt > 1)) { + int i; + + for (i = 1; i < qlt->intr_cnt; i++) { + if (qlt_mq_create(qlt, i) != QLT_SUCCESS) { + cmn_err(CE_WARN, "qlt(%d) mq create (%d) " + "failed\n", qlt->instance, i); + break; + } + qlt->qlt_queue_cnt++; + if (qlt->qlt_queue_cnt >= MQ_MAX_QUEUES) + break; + } + } + EL(qlt, "Queue count = %d\n", qlt->qlt_queue_cnt); + (void) snprintf(qlt->qlt_minor_name, sizeof (qlt->qlt_minor_name), "qlt%d", instance); (void) snprintf(qlt->qlt_port_alias, sizeof (qlt->qlt_port_alias), "%s,0", qlt->qlt_minor_name);
*** 458,468 **** mr = (uint16_t)PCICFG_RD16(qlt, 0x4E); mr = (uint16_t)(mr & 0xfff3); mr = (uint16_t)(mr | (val << 2)); PCICFG_WR16(qlt, 0x4E, mr); } else if ((did == 0x2432) || (did == 0x8432) || ! (did == 0x2532) || (did == 0x8001)) { if (max_read_size == 128) val = 0; else if (max_read_size == 256) val = 1; else if (max_read_size == 512) --- 807,819 ---- mr = (uint16_t)PCICFG_RD16(qlt, 0x4E); mr = (uint16_t)(mr & 0xfff3); mr = (uint16_t)(mr | (val << 2)); PCICFG_WR16(qlt, 0x4E, mr); } else if ((did == 0x2432) || (did == 0x8432) || ! (did == 0x2532) || (did == 0x8001) || ! (did == 0x2031) || (did == 0x2071) || ! (did == 0x2261)) { if (max_read_size == 128) val = 0; else if (max_read_size == 256) val = 1; else if (max_read_size == 512)
*** 493,503 **** max_payload_size = qlt_read_int_prop(qlt, "pcie-max-payload-size", 11); if (max_payload_size == 11) goto over_max_payload_setting; if ((did == 0x2432) || (did == 0x8432) || ! (did == 0x2532) || (did == 0x8001)) { if (max_payload_size == 128) val = 0; else if (max_payload_size == 256) val = 1; else if (max_payload_size == 512) --- 844,856 ---- max_payload_size = qlt_read_int_prop(qlt, "pcie-max-payload-size", 11); if (max_payload_size == 11) goto over_max_payload_setting; if ((did == 0x2432) || (did == 0x8432) || ! (did == 0x2532) || (did == 0x8001) || ! (did == 0x2031) || (did == 0x2071) || ! (did == 0x2261)) { if (max_payload_size == 128) val = 0; else if (max_payload_size == 256) val = 1; else if (max_payload_size == 512)
*** 523,534 **** over_max_payload_setting:; qlt_enable_intr(qlt); ! if (qlt_port_start((caddr_t)qlt) != QLT_SUCCESS) goto attach_fail_10; ddi_report_dev(dip); return (DDI_SUCCESS); attach_fail_10:; --- 876,890 ---- over_max_payload_setting:; qlt_enable_intr(qlt); ! if (qlt_port_start((caddr_t)qlt) != QLT_SUCCESS) { ! EL(qlt, "qlt_port_start failed, tear down\n"); ! qlt_disable_intr(qlt); goto attach_fail_10; + } ddi_report_dev(dip); return (DDI_SUCCESS); attach_fail_10:;
*** 537,559 **** cv_destroy(&qlt->rp_dereg_cv); ddi_remove_minor_node(dip, qlt->qlt_minor_name); attach_fail_9:; qlt_destroy_mutex(qlt); qlt_release_intr(qlt); attach_fail_8:; (void) ddi_dma_unbind_handle(qlt->queue_mem_dma_handle); attach_fail_7:; ddi_dma_mem_free(&qlt->queue_mem_acc_handle); attach_fail_6:; ddi_dma_free_handle(&qlt->queue_mem_dma_handle); attach_fail_5:; ddi_regs_map_free(&qlt->regs_acc_handle); attach_fail_4:; pci_config_teardown(&qlt->pcicfg_acc_handle); ! kmem_free(qlt->nvram, sizeof (qlt_nvram_t)); (void) qlt_el_trace_desc_dtor(qlt); attach_fail_2:; attach_fail_1:; ddi_soft_state_free(qlt_state, instance); return (DDI_FAILURE); } --- 893,934 ---- cv_destroy(&qlt->rp_dereg_cv); ddi_remove_minor_node(dip, qlt->qlt_minor_name); attach_fail_9:; qlt_destroy_mutex(qlt); qlt_release_intr(qlt); + (void) qlt_mq_destroy(qlt); + attach_fail_8:; (void) ddi_dma_unbind_handle(qlt->queue_mem_dma_handle); attach_fail_7:; ddi_dma_mem_free(&qlt->queue_mem_acc_handle); attach_fail_6:; ddi_dma_free_handle(&qlt->queue_mem_dma_handle); attach_fail_5:; + if (qlt->mq_resp) { + kmem_free(qlt->mq_resp, + (qlt->qlt_mq_enabled ? + (sizeof (qlt_mq_rsp_ptr_blk_t) * MQ_MAX_QUEUES) : + (sizeof (qlt_mq_rsp_ptr_blk_t)))); + } + qlt->mq_resp = NULL; + if (qlt->mq_req) { + kmem_free(qlt->mq_req, + (qlt->qlt_mq_enabled ? + (sizeof (qlt_mq_req_ptr_blk_t) * MQ_MAX_QUEUES) : + (sizeof (qlt_mq_req_ptr_blk_t)))); + } + qlt->mq_req = NULL; + ddi_regs_map_free(&qlt->regs_acc_handle); attach_fail_4:; pci_config_teardown(&qlt->pcicfg_acc_handle); ! attach_fail_3:; (void) qlt_el_trace_desc_dtor(qlt); attach_fail_2:; + kmem_free(qlt->vpd, QL_24XX_VPD_SIZE); + kmem_free(qlt->nvram, sizeof (qlt_nvram_t)); attach_fail_1:; ddi_soft_state_free(qlt_state, instance); return (DDI_FAILURE); }
*** 585,601 **** --- 960,1022 ---- return (DDI_FAILURE); } qlt_disable_intr(qlt); + if (qlt->dmp_template_addr != NULL) { + (void) ddi_dma_unbind_handle(qlt->dmp_template_dma_handle); + ddi_dma_mem_free(&qlt->dmp_template_acc_handle); + ddi_dma_free_handle(&qlt->dmp_template_dma_handle); + } + + if (qlt->fw_bin_dump_buf != NULL) { + kmem_free(qlt->fw_bin_dump_buf, qlt->fw_bin_dump_size); + qlt->fw_bin_dump_buf = NULL; + qlt->fw_bin_dump_size = 0; + qlt->fw_ascii_dump_size = 0; + } + + if (qlt->qlt_fwdump_buf) { + kmem_free(qlt->qlt_fwdump_buf, qlt->fw_dump_size); + qlt->qlt_fwdump_buf = NULL; + } + ddi_remove_minor_node(dip, qlt->qlt_minor_name); qlt_destroy_mutex(qlt); qlt_release_intr(qlt); + if (qlt->qlt_mq_enabled == 1) { + (void) qlt_mq_destroy(qlt); + } + (void) ddi_dma_unbind_handle(qlt->queue_mem_dma_handle); ddi_dma_mem_free(&qlt->queue_mem_acc_handle); ddi_dma_free_handle(&qlt->queue_mem_dma_handle); ddi_regs_map_free(&qlt->regs_acc_handle); + + if (qlt->mq_resp) { + kmem_free(qlt->mq_resp, + (qlt->qlt_mq_enabled ? + (sizeof (qlt_mq_rsp_ptr_blk_t) * MQ_MAX_QUEUES) : + (sizeof (qlt_mq_rsp_ptr_blk_t)))); + } + qlt->mq_resp = NULL; + if (qlt->mq_req) { + kmem_free(qlt->mq_req, + (qlt->qlt_mq_enabled ? + (sizeof (qlt_mq_req_ptr_blk_t) * MQ_MAX_QUEUES) : + (sizeof (qlt_mq_req_ptr_blk_t)))); + } + qlt->mq_req = NULL; + + if (qlt->qlt_mq_enabled == 1) { + if ((qlt->msix_acc_handle != NULL) && + ((qlt->qlt_83xx_chip == 1) || + (qlt->qlt_27xx_chip == 1))) { + ddi_regs_map_free(&qlt->msix_acc_handle); + } + ddi_regs_map_free(&qlt->mq_reg_acc_handle); + } pci_config_teardown(&qlt->pcicfg_acc_handle); kmem_free(qlt->nvram, sizeof (qlt_nvram_t)); cv_destroy(&qlt->mbox_cv); cv_destroy(&qlt->rp_dereg_cv); (void) qlt_el_trace_desc_dtor(qlt);
*** 620,669 **** return (DDI_SUCCESS); } REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_HOST_TO_RISC_INTR)); REG_WR16(qlt, REG_MBOX0, MBC_STOP_FIRMWARE); REG_WR32(qlt, REG_HCCR, HCCR_CMD(SET_HOST_TO_RISC_INTR)); for (timer = 0; timer < 30000; timer++) { stat = REG_RD32(qlt, REG_RISC_STATUS); if (stat & RISC_HOST_INTR_REQUEST) { if ((stat & FW_INTR_STATUS_MASK) < 0x12) { REG_WR32(qlt, REG_HCCR, ! HCCR_CMD(CLEAR_RISC_PAUSE)); break; } REG_WR32(qlt, REG_HCCR, ! HCCR_CMD(CLEAR_HOST_TO_RISC_INTR)); } drv_usecwait(100); } /* Reset the chip. */ REG_WR32(qlt, REG_CTRL_STATUS, CHIP_SOFT_RESET | DMA_SHUTDOWN_CTRL | PCI_X_XFER_CTRL); drv_usecwait(100); qlt_disable_intr(qlt); return (DDI_SUCCESS); } static void qlt_enable_intr(qlt_state_t *qlt) { if (qlt->intr_cap & DDI_INTR_FLAG_BLOCK) { ! (void) ddi_intr_block_enable(qlt->htable, qlt->intr_cnt); } else { int i; ! for (i = 0; i < qlt->intr_cnt; i++) ! (void) ddi_intr_enable(qlt->htable[i]); } ! qlt->qlt_intr_enabled = 1; } static void qlt_disable_intr(qlt_state_t *qlt) { if (qlt->intr_cap & DDI_INTR_FLAG_BLOCK) { (void) ddi_intr_block_disable(qlt->htable, qlt->intr_cnt); } else { int i; for (i = 0; i < qlt->intr_cnt; i++) --- 1041,1199 ---- return (DDI_SUCCESS); } REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_HOST_TO_RISC_INTR)); REG_WR16(qlt, REG_MBOX0, MBC_STOP_FIRMWARE); + REG_WR16(qlt, REG_MBOX(1), 0); + REG_WR16(qlt, REG_MBOX(2), 0); + REG_WR16(qlt, REG_MBOX(3), 0); + REG_WR16(qlt, REG_MBOX(4), 0); + REG_WR16(qlt, REG_MBOX(5), 0); + REG_WR16(qlt, REG_MBOX(6), 0); + REG_WR16(qlt, REG_MBOX(7), 0); + REG_WR16(qlt, REG_MBOX(8), 0); REG_WR32(qlt, REG_HCCR, HCCR_CMD(SET_HOST_TO_RISC_INTR)); for (timer = 0; timer < 30000; timer++) { stat = REG_RD32(qlt, REG_RISC_STATUS); if (stat & RISC_HOST_INTR_REQUEST) { if ((stat & FW_INTR_STATUS_MASK) < 0x12) { REG_WR32(qlt, REG_HCCR, ! HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); break; } REG_WR32(qlt, REG_HCCR, ! HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); } drv_usecwait(100); } + + + /* need to ensure no one accesses the hw during the reset 100us */ + if ((qlt->qlt_83xx_chip) || (qlt->qlt_27xx_chip)) { + REG_WR32(qlt, REG_INTR_CTRL, 0); + mutex_enter(&qlt->mbox_lock); + if (qlt->qlt_mq_enabled == 1) { + int i; + for (i = 1; i < qlt->qlt_queue_cnt; i++) { + mutex_enter(&qlt->mq_req[i].mq_lock); + } + } + mutex_enter(&qlt->mq_req[0].mq_lock); + drv_usecwait(40); + } + /* Reset the chip. */ REG_WR32(qlt, REG_CTRL_STATUS, CHIP_SOFT_RESET | DMA_SHUTDOWN_CTRL | PCI_X_XFER_CTRL); drv_usecwait(100); + if ((qlt->qlt_83xx_chip) || (qlt->qlt_27xx_chip)) { + mutex_exit(&qlt->mq_req[0].mq_lock); + if (qlt->qlt_mq_enabled == 1) { + int i; + for (i = 1; i < qlt->qlt_queue_cnt; i++) { + mutex_exit(&qlt->mq_req[i].mq_lock); + } + } + mutex_exit(&qlt->mbox_lock); + } + qlt_disable_intr(qlt); return (DDI_SUCCESS); } static void qlt_enable_intr(qlt_state_t *qlt) { if (qlt->intr_cap & DDI_INTR_FLAG_BLOCK) { ! int stat; ! ! stat = ddi_intr_block_enable(qlt->htable, qlt->intr_cnt); ! if (stat != DDI_SUCCESS) { ! stmf_trace(qlt->qlt_port_alias, ! "qlt_enable_intr: ddi_intr_block_enable failed:%x", ! stat); ! ! cmn_err(CE_WARN, "!qlt(%d): qlt_enable_intr: " ! "ddi_intr_block_enable failed:%x", ! qlt->instance, stat); ! } ! ! #ifndef __sparc ! else { ! /* Please see CR6840537, MSI isn't re-enabled x86 */ ! off_t offset; ! uint8_t val8; ! ddi_intr_handle_impl_t *hdlp; ! ! if (qlt->qlt_81xx_chip || qlt->qlt_25xx_chip) { ! offset = (off_t)0x8a; } else { + offset = (off_t)0x66; + } + + hdlp = (ddi_intr_handle_impl_t *)qlt->htable[0]; + if ((hdlp->ih_state == DDI_IHDL_STATE_ENABLE) && + (hdlp->ih_type == DDI_INTR_TYPE_MSI)) { + + /* get MSI control */ + val8 = pci_config_get8(qlt->pcicfg_acc_handle, + offset); + + if ((val8 & 1) == 0) { + stmf_trace(qlt->qlt_port_alias, + "qlt(%d): qlt_enable_intr: " + "MSI enable failed (%x)", + qlt->instance, val8); + + /* write enable to MSI control */ + val8 = (uint8_t)(val8 | 1); + pci_config_put8(qlt->pcicfg_acc_handle, + offset, val8); + + /* read back to veriy */ + val8 = pci_config_get8 + (qlt->pcicfg_acc_handle, offset); + + if (val8 & 1) { + stmf_trace(qlt->qlt_port_alias, + "qlt(%d): qlt_enable_intr: " + "MSI enabled kludge!(%x)", + qlt->instance, val8); + } + } + } + } + #endif /* x86 specific hack */ + } else { int i; ! int stat = DDI_SUCCESS; ! ! for (i = 0; ! ((i < qlt->intr_cnt) && (stat == DDI_SUCCESS)); i++) { ! stat = ddi_intr_enable(qlt->htable[i]); } ! if (stat != DDI_SUCCESS) { ! stmf_trace(qlt->qlt_port_alias, ! "qlt_enable_intr: ddi_intr_enable failed:%x", ! stat); ! ! cmn_err(CE_WARN, "!qlt(%d): qlt_enable_intr: " ! "ddi_intr_enable failed:%x", qlt->instance, stat); ! } ! } } static void qlt_disable_intr(qlt_state_t *qlt) { + if (qlt->qlt_intr_enabled == 0) { + /* ---- If we've disabled it once, just return ---- */ + return; + } + if (qlt->intr_cap & DDI_INTR_FLAG_BLOCK) { (void) ddi_intr_block_disable(qlt->htable, qlt->intr_cnt); } else { int i; for (i = 0; i < qlt->intr_cnt; i++)
*** 688,703 **** qlt->intr_cnt = 0; qlt->intr_size = 0; qlt->intr_cap = 0; } - static void qlt_init_mutex(qlt_state_t *qlt) { ! mutex_init(&qlt->req_lock, 0, MUTEX_DRIVER, INT2PTR(qlt->intr_pri, void *)); mutex_init(&qlt->preq_lock, 0, MUTEX_DRIVER, INT2PTR(qlt->intr_pri, void *)); mutex_init(&qlt->mbox_lock, NULL, MUTEX_DRIVER, INT2PTR(qlt->intr_pri, void *)); mutex_init(&qlt->intr_lock, NULL, MUTEX_DRIVER, --- 1218,1242 ---- qlt->intr_cnt = 0; qlt->intr_size = 0; qlt->intr_cap = 0; } static void qlt_init_mutex(qlt_state_t *qlt) { ! if (qlt->qlt_mq_enabled == 1) { ! int i; ! ! for (i = 1; i < MQ_MAX_QUEUES; i++) { ! mutex_init(&qlt->mq_req[i].mq_lock, 0, MUTEX_DRIVER, INT2PTR(qlt->intr_pri, void *)); + mutex_init(&qlt->mq_resp[i].mq_lock, 0, MUTEX_DRIVER, + INT2PTR(qlt->intr_pri, void *)); + } + } + mutex_init(&qlt->mq_req[0].mq_lock, 0, MUTEX_DRIVER, + INT2PTR(qlt->intr_pri, void *)); mutex_init(&qlt->preq_lock, 0, MUTEX_DRIVER, INT2PTR(qlt->intr_pri, void *)); mutex_init(&qlt->mbox_lock, NULL, MUTEX_DRIVER, INT2PTR(qlt->intr_pri, void *)); mutex_init(&qlt->intr_lock, NULL, MUTEX_DRIVER,
*** 705,729 **** } static void qlt_destroy_mutex(qlt_state_t *qlt) { ! mutex_destroy(&qlt->req_lock); mutex_destroy(&qlt->preq_lock); mutex_destroy(&qlt->mbox_lock); mutex_destroy(&qlt->intr_lock); } - static int qlt_setup_msix(qlt_state_t *qlt) { int count, avail, actual; int ret; int itype = DDI_INTR_TYPE_MSIX; int i; ret = ddi_intr_get_nintrs(qlt->dip, itype, &count); if (ret != DDI_SUCCESS || count == 0) { EL(qlt, "ddi_intr_get_nintrs status=%xh, count=%d\n", ret, count); return (DDI_FAILURE); --- 1244,1293 ---- } static void qlt_destroy_mutex(qlt_state_t *qlt) { ! if (qlt->qlt_mq_enabled == 1) { ! int i; ! ! for (i = 1; i < MQ_MAX_QUEUES; i++) { ! mutex_destroy(&qlt->mq_req[i].mq_lock); ! mutex_destroy(&qlt->mq_resp[i].mq_lock); ! } ! } ! mutex_destroy(&qlt->mq_req[0].mq_lock); mutex_destroy(&qlt->preq_lock); mutex_destroy(&qlt->mbox_lock); mutex_destroy(&qlt->intr_lock); } static int qlt_setup_msix(qlt_state_t *qlt) { int count, avail, actual; int ret; int itype = DDI_INTR_TYPE_MSIX; int i; + #ifdef __x86 + if (get_hwenv() == HW_VMWARE) { + EL(qlt, "running under hypervisor, disabling MSI-X\n"); + return (DDI_FAILURE); + } + #endif + + /* check 24xx revision */ + if ((!qlt->qlt_25xx_chip) && (!qlt->qlt_81xx_chip) && + (!qlt->qlt_83xx_chip) && (!qlt->qlt_27xx_chip)) { + uint8_t rev_id; + rev_id = (uint8_t) + pci_config_get8(qlt->pcicfg_acc_handle, PCI_CONF_REVID); + if (rev_id < 3) { + return (DDI_FAILURE); + } + } + ret = ddi_intr_get_nintrs(qlt->dip, itype, &count); if (ret != DDI_SUCCESS || count == 0) { EL(qlt, "ddi_intr_get_nintrs status=%xh, count=%d\n", ret, count); return (DDI_FAILURE);
*** 737,756 **** if (avail < count) { stmf_trace(qlt->qlt_port_alias, "qlt_setup_msix: nintrs=%d,avail=%d", count, avail); } qlt->intr_size = (int)(count * (int)sizeof (ddi_intr_handle_t)); qlt->htable = kmem_zalloc((uint_t)qlt->intr_size, KM_SLEEP); ret = ddi_intr_alloc(qlt->dip, qlt->htable, itype, DDI_INTR_ALLOC_NORMAL, count, &actual, 0); /* we need at least 2 interrupt vectors */ ! if (ret != DDI_SUCCESS || actual < 2) { EL(qlt, "ddi_intr_alloc status=%xh, actual=%d\n", ret, actual); ret = DDI_FAILURE; goto release_intr; } if (actual < count) { EL(qlt, "requested: %d, received: %d\n", count, actual); } --- 1301,1339 ---- if (avail < count) { stmf_trace(qlt->qlt_port_alias, "qlt_setup_msix: nintrs=%d,avail=%d", count, avail); } + if ((qlt->qlt_25xx_chip) && (qlt->qlt_mq_enabled == 0)) { + count = 2; + } + qlt->intr_size = (int)(count * (int)sizeof (ddi_intr_handle_t)); qlt->htable = kmem_zalloc((uint_t)qlt->intr_size, KM_SLEEP); ret = ddi_intr_alloc(qlt->dip, qlt->htable, itype, DDI_INTR_ALLOC_NORMAL, count, &actual, 0); + + EL(qlt, "qlt_setup_msix: count=%d,avail=%d,actual=%d\n", count, + avail, actual); + /* we need at least 2 interrupt vectors */ ! if (((qlt->qlt_83xx_chip) || (qlt->qlt_27xx_chip)) && ! (ret != DDI_SUCCESS || actual < 2)) { EL(qlt, "ddi_intr_alloc status=%xh, actual=%d\n", ret, actual); ret = DDI_FAILURE; goto release_intr; + } else if ((qlt->qlt_81xx_chip) && (ret != DDI_SUCCESS || actual < 3)) { + EL(qlt, "ddi_intr_alloc status=%xh, actual=%d\n", ret, + actual); + ret = DDI_FAILURE; + goto release_intr; + } else if (ret != DDI_SUCCESS || actual < 2) { + EL(qlt, "ddi_intr_alloc status=%xh, actual=%d\n", ret, + actual); + ret = DDI_FAILURE; + goto release_intr; } if (actual < count) { EL(qlt, "requested: %d, received: %d\n", count, actual); }
*** 760,771 **** EL(qlt, "ddi_intr_get_pri status=%xh\n", ret); ret = DDI_FAILURE; goto release_intr; } qlt_init_mutex(qlt); ! for (i = 0; i < actual; i++) { ! ret = ddi_intr_add_handler(qlt->htable[i], qlt_isr, qlt, INT2PTR((uint_t)i, void *)); if (ret != DDI_SUCCESS) { EL(qlt, "ddi_intr_add_handler status=%xh\n", ret); goto release_mutex; } --- 1343,1356 ---- EL(qlt, "ddi_intr_get_pri status=%xh\n", ret); ret = DDI_FAILURE; goto release_intr; } qlt_init_mutex(qlt); ! for (i = 0; i < qlt->intr_cnt; i++) { ! ret = ddi_intr_add_handler(qlt->htable[i], ! (i != 0) ? qlt_msix_resp_handler : ! qlt_msix_default_handler, qlt, INT2PTR((uint_t)i, void *)); if (ret != DDI_SUCCESS) { EL(qlt, "ddi_intr_add_handler status=%xh\n", ret); goto release_mutex; }
*** 778,805 **** release_mutex: qlt_destroy_mutex(qlt); release_intr: for (i = 0; i < actual; i++) (void) ddi_intr_free(qlt->htable[i]); ! #if 0 ! free_mem: ! #endif kmem_free(qlt->htable, (uint_t)qlt->intr_size); qlt->htable = NULL; qlt_release_intr(qlt); return (ret); } - static int qlt_setup_msi(qlt_state_t *qlt) { int count, avail, actual; int itype = DDI_INTR_TYPE_MSI; int ret; int i; /* get the # of interrupts */ ret = ddi_intr_get_nintrs(qlt->dip, itype, &count); if (ret != DDI_SUCCESS || count == 0) { EL(qlt, "ddi_intr_get_nintrs status=%xh, count=%d\n", ret, count); --- 1363,1392 ---- release_mutex: qlt_destroy_mutex(qlt); release_intr: for (i = 0; i < actual; i++) (void) ddi_intr_free(qlt->htable[i]); ! kmem_free(qlt->htable, (uint_t)qlt->intr_size); qlt->htable = NULL; qlt_release_intr(qlt); return (ret); } static int qlt_setup_msi(qlt_state_t *qlt) { int count, avail, actual; int itype = DDI_INTR_TYPE_MSI; int ret; int i; + /* 83xx and 27xx doesn't do MSI - don't even bother? */ + if ((qlt->qlt_83xx_chip) || (qlt->qlt_27xx_chip)) { + return (DDI_FAILURE); + } + /* get the # of interrupts */ ret = ddi_intr_get_nintrs(qlt->dip, itype, &count); if (ret != DDI_SUCCESS || count == 0) { EL(qlt, "ddi_intr_get_nintrs status=%xh, count=%d\n", ret, count);
*** 932,1020 **** /* * x86 has a bug in the ddi_intr_block_enable/disable area (6562198). */ #ifndef __sparc ! if (qlt_enable_msi != 0) { #endif if (ddi_intr_get_supported_types(qlt->dip, &itypes) != DDI_SUCCESS) { itypes = DDI_INTR_TYPE_FIXED; } - if (qlt_enable_msix && (itypes & DDI_INTR_TYPE_MSIX)) { if (qlt_setup_msix(qlt) == DDI_SUCCESS) return (DDI_SUCCESS); } ! ! if (itypes & DDI_INTR_TYPE_MSI) { if (qlt_setup_msi(qlt) == DDI_SUCCESS) return (DDI_SUCCESS); } #ifndef __sparc } #endif return (qlt_setup_fixed(qlt)); } /* * Filling the hba attributes */ void qlt_populate_hba_fru_details(struct fct_local_port *port, struct fct_port_attrs *port_attrs) { - caddr_t bufp; int len; qlt_state_t *qlt = (qlt_state_t *)port->port_fca_private; (void) snprintf(port_attrs->manufacturer, FCHBA_MANUFACTURER_LEN, "QLogic Corp."); (void) snprintf(port_attrs->driver_name, FCHBA_DRIVER_NAME_LEN, "%s", QLT_NAME); (void) snprintf(port_attrs->driver_version, FCHBA_DRIVER_VERSION_LEN, "%s", QLT_VERSION); port_attrs->serial_number[0] = '\0'; port_attrs->hardware_version[0] = '\0'; (void) snprintf(port_attrs->firmware_version, FCHBA_FIRMWARE_VERSION_LEN, "%d.%d.%d", qlt->fw_major, qlt->fw_minor, qlt->fw_subminor); /* Get FCode version */ ! if (ddi_getlongprop(DDI_DEV_T_ANY, qlt->dip, PROP_LEN_AND_VAL_ALLOC | ! DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "version", (caddr_t)&bufp, ! (int *)&len) == DDI_PROP_SUCCESS) { ! (void) snprintf(port_attrs->option_rom_version, ! FCHBA_OPTION_ROM_VERSION_LEN, "%s", bufp); ! kmem_free(bufp, (uint_t)len); ! bufp = NULL; ! } else { ! #ifdef __sparc ! (void) snprintf(port_attrs->option_rom_version, ! FCHBA_OPTION_ROM_VERSION_LEN, "No Fcode found"); ! #else ! (void) snprintf(port_attrs->option_rom_version, ! FCHBA_OPTION_ROM_VERSION_LEN, "N/A"); ! #endif ! } port_attrs->vendor_specific_id = qlt->nvram->subsystem_vendor_id[0] | qlt->nvram->subsystem_vendor_id[1] << 8; port_attrs->max_frame_size = qlt->nvram->max_frame_length[1] << 8 | qlt->nvram->max_frame_length[0]; port_attrs->supported_cos = 0x10000000; ! port_attrs->supported_speed = PORT_SPEED_1G | ! PORT_SPEED_2G | PORT_SPEED_4G; ! if (qlt->qlt_25xx_chip) port_attrs->supported_speed = PORT_SPEED_2G | PORT_SPEED_4G | PORT_SPEED_8G; ! if (qlt->qlt_81xx_chip) ! port_attrs->supported_speed = PORT_SPEED_10G; /* limit string length to nvr model_name length */ ! len = (qlt->qlt_81xx_chip) ? 16 : 8; (void) snprintf(port_attrs->model, (uint_t)(len < FCHBA_MODEL_LEN ? len : FCHBA_MODEL_LEN), "%s", qlt->nvram->model_name); (void) snprintf(port_attrs->model_description, --- 1519,1828 ---- /* * x86 has a bug in the ddi_intr_block_enable/disable area (6562198). */ #ifndef __sparc ! if ((qlt_enable_msi != 0) || (qlt_enable_msix != 0)) { #endif if (ddi_intr_get_supported_types(qlt->dip, &itypes) != DDI_SUCCESS) { itypes = DDI_INTR_TYPE_FIXED; } if (qlt_enable_msix && (itypes & DDI_INTR_TYPE_MSIX)) { if (qlt_setup_msix(qlt) == DDI_SUCCESS) return (DDI_SUCCESS); } ! if (qlt_enable_msi && (itypes & DDI_INTR_TYPE_MSI)) { if (qlt_setup_msi(qlt) == DDI_SUCCESS) return (DDI_SUCCESS); } #ifndef __sparc } #endif return (qlt_setup_fixed(qlt)); } + static uint8_t * + qlt_vpd_findtag(qlt_state_t *qlt, uint8_t *vpdbuf, int8_t *opcode) + { + uint8_t *vpd = vpdbuf; + uint8_t *end = vpdbuf + QL_24XX_VPD_SIZE; + uint32_t found = 0; + + if (vpdbuf == NULL || opcode == NULL) { + EL(qlt, "null parameter passed!\n"); + return (NULL); + } + + while (vpd < end) { + if (vpd[0] == VPD_TAG_END) { + if (opcode[0] == VPD_TAG_END) { + found = 1; + } else { + found = 0; + } + break; + } + + if (bcmp(opcode, vpd, strlen(opcode)) == 0) { + found = 1; + break; + } + + if (!(strncmp((char *)vpd, (char *)VPD_TAG_PRODID, 1))) { + vpd += (vpd[2] << 8) + vpd[1] + 3; + } else if (*vpd == VPD_TAG_LRT || *vpd == VPD_TAG_LRTC) { + vpd += 3; + } else { + vpd += vpd[2] +3; + } + } + return (found == 1 ? vpd : NULL); + } + /* + * qlt_vpd_lookup + * Return the VPD data for the request VPD tag + * + * Input: + * qlt = adapter state pointer. + * opcode = VPD opcode to find (must be NULL terminated). + * bp = Pointer to returned data buffer. + * bplen = Length of returned data buffer. + * + * Returns: + * Length of data copied into returned data buffer. + * >0 = VPD data field (NULL terminated) + * 0 = no data. + * -1 = Could not find opcode in vpd buffer / error. + * + * Context: + * Kernel context. + * + * NB: The opcode buffer and the bp buffer *could* be the same buffer! + * + */ + static int + qlt_vpd_lookup(qlt_state_t *qlt, uint8_t *opcode, uint8_t *bp, + int32_t bplen) + { + uint8_t *vpd = NULL; + uint8_t *vpdbuf = NULL; + int32_t len = -1; + + if (opcode == NULL || bp == NULL || bplen < 1) { + EL(qlt, "invalid parameter passed: opcode=%ph, " + "bp=%ph, bplen=%xh\n", opcode, bp, bplen); + return (len); + } + + vpdbuf = (uint8_t *)qlt->vpd; + if ((vpd = qlt_vpd_findtag(qlt, vpdbuf, (int8_t *)opcode)) != NULL) { + /* + * Found the tag + */ + if (*opcode == VPD_TAG_END || *opcode == VPD_TAG_LRT || + *opcode == VPD_TAG_LRTC) { + /* + * We found it, but the tag doesn't have a data + * field. + */ + len = 0; + } else if (!(strncmp((char *)vpd, (char *) + VPD_TAG_PRODID, 1))) { + len = vpd[2] << 8; + len += vpd[1]; + } else { + len = vpd[2]; + } + + /* + * Make sure that the vpd len does not exceed the + * vpd end + */ + if (vpd+len > vpdbuf + QL_24XX_VPD_SIZE) { + EL(qlt, "vpd tag len (%xh) exceeds vpd buffer " + "length\n", len); + len = -1; + } + } else { + EL(qlt, "Cna't find vpd tag \n"); + return (-1); + } + + if (len >= 0) { + /* + * make sure we don't exceed callers buffer space len + */ + if (len > bplen) { + len = bplen - 1; + } + /* copy the data back */ + (void) strncpy((int8_t *)bp, (int8_t *)(vpd+3), (int64_t)len); + bp[len] = NULL; + } else { + /* error -- couldn't find tag */ + bp[0] = NULL; + if (opcode[1] != NULL) { + EL(qlt, "unable to find tag '%s'\n", opcode); + } else { + EL(qlt, "unable to find tag '%xh'\n", opcode[0]); + } + } + return (len); + } + + void + qlt_get_rom_version(qlt_state_t *qlt, caddr_t orv) + { + int i; + char bios0_str[32]; + char fcode_str[32]; + char efi_str[32]; + char hppa_str[32]; + char tmp[80]; + uint32_t bios_cnt = 0; + uint32_t fcode_cnt = 0; + boolean_t last_image = FALSE; + + /* collect right rom_version from image[] */ + i = 0; + do { + if (qlt->rimage[0].header.signature[0] != PCI_HEADER0) { + break; + } + + if (qlt->rimage[i].data.codetype == PCI_CODE_X86PC) { + /* BIOS */ + if (bios_cnt == 0) { + (void) snprintf(bios0_str, + 32, + "%d.%02d", + qlt->rimage[i].data. + revisionlevel[1], + qlt->rimage[i].data. + revisionlevel[0]); + (void) snprintf(tmp, 80, + " BIOS: %s;", bios0_str); + (void) strcat(orv, tmp); + } + bios_cnt++; + } else if (qlt->rimage[i].data.codetype == PCI_CODE_FCODE) { + /* FCode */ + if (fcode_cnt == 0) { + (void) snprintf(fcode_str, + 32, + "%d.%02d", + qlt->rimage[i].data.revisionlevel[1], + qlt->rimage[i].data.revisionlevel[0]); + (void) snprintf(tmp, 80, + " FCode: %s;", fcode_str); + (void) strcat(orv, tmp); + } + fcode_cnt++; + } else if (qlt->rimage[i].data.codetype == PCI_CODE_EFI) { + /* EFI */ + (void) snprintf(efi_str, + 32, + "%d.%02d", + qlt->rimage[i].data.revisionlevel[1], + qlt->rimage[i].data.revisionlevel[0]); + (void) snprintf(tmp, 80, " EFI: %s;", efi_str); + (void) strcat(orv, tmp); + } else if (qlt->rimage[i].data.codetype == PCI_CODE_HPPA) { + /* HPPA */ + (void) snprintf(hppa_str, + 32, + "%d.%02d", + qlt->rimage[i].data.revisionlevel[1], + qlt->rimage[i].data.revisionlevel[0]); + (void) snprintf(orv, 80, " HPPA: %s;", hppa_str); + (void) strcat(orv, tmp); + } else if (qlt->rimage[i].data.codetype == PCI_CODE_FW) { + EL(qlt, "fw infor skip\n"); + } else { + /* Unknown */ + EL(qlt, "unknown image\n"); + break; + } + + if (qlt->rimage[i].data.indicator == PCI_IND_LAST_IMAGE) { + last_image = TRUE; + break; + } + + i ++; + } while ((last_image != TRUE) && (i < 6)); + + if (last_image != TRUE) { + /* No boot image detected */ + (void) snprintf(orv, FCHBA_OPTION_ROM_VERSION_LEN, "%s", + "No boot image detected"); + } + } + + /* * Filling the hba attributes */ void qlt_populate_hba_fru_details(struct fct_local_port *port, struct fct_port_attrs *port_attrs) { int len; qlt_state_t *qlt = (qlt_state_t *)port->port_fca_private; (void) snprintf(port_attrs->manufacturer, FCHBA_MANUFACTURER_LEN, "QLogic Corp."); (void) snprintf(port_attrs->driver_name, FCHBA_DRIVER_NAME_LEN, "%s", QLT_NAME); (void) snprintf(port_attrs->driver_version, FCHBA_DRIVER_VERSION_LEN, "%s", QLT_VERSION); + /* get serial_number from vpd data */ + if (qlt_vpd_lookup(qlt, (uint8_t *)VPD_TAG_SN, (uint8_t *) + port_attrs->serial_number, FCHBA_SERIAL_NUMBER_LEN) == -1) { port_attrs->serial_number[0] = '\0'; + } port_attrs->hardware_version[0] = '\0'; (void) snprintf(port_attrs->firmware_version, FCHBA_FIRMWARE_VERSION_LEN, "%d.%d.%d", qlt->fw_major, qlt->fw_minor, qlt->fw_subminor); /* Get FCode version */ ! qlt_get_rom_version(qlt, (caddr_t)&port_attrs->option_rom_version[0]); ! port_attrs->vendor_specific_id = qlt->nvram->subsystem_vendor_id[0] | qlt->nvram->subsystem_vendor_id[1] << 8; port_attrs->max_frame_size = qlt->nvram->max_frame_length[1] << 8 | qlt->nvram->max_frame_length[0]; port_attrs->supported_cos = 0x10000000; ! ! if (qlt->qlt_fcoe_enabled) { ! port_attrs->supported_speed = PORT_SPEED_10G; ! } else if (qlt->qlt_27xx_chip) { ! if ((qlt->qlt_27xx_speed & MAX_SPEED_MASK) == MAX_SPEED_32G) { ! port_attrs->supported_speed = PORT_SPEED_8G | ! PORT_SPEED_16G | PORT_SPEED_32G; ! } else { ! port_attrs->supported_speed = PORT_SPEED_4G | ! PORT_SPEED_8G | PORT_SPEED_16G; ! } ! } else if ((qlt->qlt_83xx_chip) || (qlt->qlt_27xx_chip)) { ! port_attrs->supported_speed = PORT_SPEED_4G | ! PORT_SPEED_8G | PORT_SPEED_16G; ! } else if (qlt->qlt_25xx_chip) { port_attrs->supported_speed = PORT_SPEED_2G | PORT_SPEED_4G | PORT_SPEED_8G; ! } else { ! port_attrs->supported_speed = PORT_SPEED_1G | ! PORT_SPEED_2G | PORT_SPEED_4G; ! } /* limit string length to nvr model_name length */ ! len = ((qlt->qlt_81xx_chip) || (qlt->qlt_83xx_chip) || ! (qlt->qlt_27xx_chip)) ? 16 : 8; (void) snprintf(port_attrs->model, (uint_t)(len < FCHBA_MODEL_LEN ? len : FCHBA_MODEL_LEN), "%s", qlt->nvram->model_name); (void) snprintf(port_attrs->model_description,
*** 1034,1043 **** --- 1842,1854 ---- uint8_t *p; fct_port_link_status_t *link_status; switch (cmd) { case FC_TGT_PORT_RLS: + if (qlt->qlt_state != FCT_STATE_ONLINE) { + break; + } if ((*bufsizep) < sizeof (fct_port_link_status_t)) { EL(qlt, "FC_TGT_PORT_RLS bufsizep=%xh < " "fct_port_link_status_t=%xh\n", *bufsizep, sizeof (fct_port_link_status_t)); ret = FCT_FAILURE;
*** 1057,1067 **** mcp->to_fw_mask |= BIT_1 | BIT_8; mcp->from_fw_mask |= BIT_1 | BIT_2; ret = qlt_mailbox_command(qlt, mcp); if (ret != QLT_SUCCESS) { ! EL(qlt, "qlt_mailbox_command=6dh status=%llxh\n", ret); qlt_free_mailbox_command(qlt, mcp); break; } qlt_dmem_dma_sync(mcp->dbuf, DDI_DMA_SYNC_FORCPU); --- 1868,1878 ---- mcp->to_fw_mask |= BIT_1 | BIT_8; mcp->from_fw_mask |= BIT_1 | BIT_2; ret = qlt_mailbox_command(qlt, mcp); if (ret != QLT_SUCCESS) { ! EL(qlt, "qlt_mbox_command=6dh status=%llxh\n", ret); qlt_free_mailbox_command(qlt, mcp); break; } qlt_dmem_dma_sync(mcp->dbuf, DDI_DMA_SYNC_FORCPU);
*** 1096,1105 **** --- 1907,1917 ---- fct_status_t ret; if (qlt_dmem_init(qlt) != QLT_SUCCESS) { return (FCT_FAILURE); } + /* Initialize the ddi_dma_handle free pool */ qlt_dma_handle_pool_init(qlt); port = (fct_local_port_t *)fct_alloc(FCT_STRUCT_LOCAL_PORT, 0, 0); if (port == NULL) {
*** 1113,1123 **** fds->fds_alloc_data_buf = qlt_dmem_alloc; fds->fds_free_data_buf = qlt_dmem_free; fds->fds_setup_dbuf = qlt_dma_setup_dbuf; fds->fds_teardown_dbuf = qlt_dma_teardown_dbuf; fds->fds_max_sgl_xfer_len = QLT_DMA_SG_LIST_LENGTH * MMU_PAGESIZE; ! fds->fds_copy_threshold = MMU_PAGESIZE; fds->fds_fca_private = (void *)qlt; /* * Since we keep everything in the state struct and dont allocate any * port private area, just use that pointer to point to the * state struct. --- 1925,1935 ---- fds->fds_alloc_data_buf = qlt_dmem_alloc; fds->fds_free_data_buf = qlt_dmem_free; fds->fds_setup_dbuf = qlt_dma_setup_dbuf; fds->fds_teardown_dbuf = qlt_dma_teardown_dbuf; fds->fds_max_sgl_xfer_len = QLT_DMA_SG_LIST_LENGTH * MMU_PAGESIZE; ! fds->fds_copy_threshold = (uint32_t)MMU_PAGESIZE; fds->fds_fca_private = (void *)qlt; /* * Since we keep everything in the state struct and dont allocate any * port private area, just use that pointer to point to the * state struct.
*** 1153,1162 **** --- 1965,1995 ---- if ((ret = fct_register_local_port(port)) != FCT_SUCCESS) { EL(qlt, "fct_register_local_port status=%llxh\n", ret); goto qlt_pstart_fail_2_5; } + EL(qlt, "Qlogic qlt(%d) " + "WWPN=%02x%02x%02x%02x%02x%02x%02x%02x:" + "WWNN=%02x%02x%02x%02x%02x%02x%02x%02x\n", + qlt->instance, + qlt->nvram->port_name[0], + qlt->nvram->port_name[1], + qlt->nvram->port_name[2], + qlt->nvram->port_name[3], + qlt->nvram->port_name[4], + qlt->nvram->port_name[5], + qlt->nvram->port_name[6], + qlt->nvram->port_name[7], + qlt->nvram->node_name[0], + qlt->nvram->node_name[1], + qlt->nvram->node_name[2], + qlt->nvram->node_name[3], + qlt->nvram->node_name[4], + qlt->nvram->node_name[5], + qlt->nvram->node_name[6], + qlt->nvram->node_name[7]); + return (QLT_SUCCESS); #if 0 qlt_pstart_fail_3: (void) fct_deregister_local_port(port); #endif
*** 1181,1192 **** EL(qlt, "fct_register_local_port status=%llxh\n", ret); return (QLT_FAILURE); } fct_free(qlt->qlt_port->port_fds); fct_free(qlt->qlt_port); - qlt->qlt_port = NULL; qlt_dma_handle_pool_fini(qlt); qlt_dmem_fini(qlt); return (QLT_SUCCESS); } /* --- 2014,2025 ---- EL(qlt, "fct_register_local_port status=%llxh\n", ret); return (QLT_FAILURE); } fct_free(qlt->qlt_port->port_fds); fct_free(qlt->qlt_port); qlt_dma_handle_pool_fini(qlt); + qlt->qlt_port = NULL; qlt_dmem_fini(qlt); return (QLT_SUCCESS); } /*
*** 1196,1206 **** */ fct_status_t qlt_port_online(qlt_state_t *qlt) { uint64_t da; ! int instance, i; fct_status_t ret; uint16_t rcount; caddr_t icb; mbox_cmd_t *mcp; uint8_t *elsbmp; --- 2029,2039 ---- */ fct_status_t qlt_port_online(qlt_state_t *qlt) { uint64_t da; ! int instance, i, j; fct_status_t ret; uint16_t rcount; caddr_t icb; mbox_cmd_t *mcp; uint8_t *elsbmp;
*** 1208,1218 **** instance = ddi_get_instance(qlt->dip); /* XXX Make sure a sane state */ if ((ret = qlt_download_fw(qlt)) != QLT_SUCCESS) { ! cmn_err(CE_NOTE, "reset chip failed %llx", (long long)ret); return (ret); } bzero(qlt->queue_mem_ptr, TOTAL_DMA_MEM_SIZE); --- 2041,2052 ---- instance = ddi_get_instance(qlt->dip); /* XXX Make sure a sane state */ if ((ret = qlt_download_fw(qlt)) != QLT_SUCCESS) { ! cmn_err(CE_NOTE, "qlt(%d): reset chip failed %llx", ! qlt->instance, (long long)ret); return (ret); } bzero(qlt->queue_mem_ptr, TOTAL_DMA_MEM_SIZE);
*** 1251,1261 **** REG_WR16(qlt, REG_MBOX(7), LSW(MSD(da))); REG_WR16(qlt, REG_MBOX(6), MSW(MSD(da))); SETELSBIT(elsbmp, ELS_OP_PLOGI); SETELSBIT(elsbmp, ELS_OP_LOGO); SETELSBIT(elsbmp, ELS_OP_ABTX); ! SETELSBIT(elsbmp, ELS_OP_ECHO); SETELSBIT(elsbmp, ELS_OP_PRLI); SETELSBIT(elsbmp, ELS_OP_PRLO); SETELSBIT(elsbmp, ELS_OP_SCN); SETELSBIT(elsbmp, ELS_OP_TPRLO); SETELSBIT(elsbmp, ELS_OP_PDISC); --- 2085,2095 ---- REG_WR16(qlt, REG_MBOX(7), LSW(MSD(da))); REG_WR16(qlt, REG_MBOX(6), MSW(MSD(da))); SETELSBIT(elsbmp, ELS_OP_PLOGI); SETELSBIT(elsbmp, ELS_OP_LOGO); SETELSBIT(elsbmp, ELS_OP_ABTX); ! /* SETELSBIT(elsbmp, ELS_OP_ECHO); till fct handles it */ SETELSBIT(elsbmp, ELS_OP_PRLI); SETELSBIT(elsbmp, ELS_OP_PRLO); SETELSBIT(elsbmp, ELS_OP_SCN); SETELSBIT(elsbmp, ELS_OP_TPRLO); SETELSBIT(elsbmp, ELS_OP_PDISC);
*** 1273,1312 **** elsbmp[1]); return (ret); } /* Init queue pointers */ REG_WR32(qlt, REG_REQ_IN_PTR, 0); REG_WR32(qlt, REG_REQ_OUT_PTR, 0); REG_WR32(qlt, REG_RESP_IN_PTR, 0); REG_WR32(qlt, REG_RESP_OUT_PTR, 0); REG_WR32(qlt, REG_PREQ_IN_PTR, 0); REG_WR32(qlt, REG_PREQ_OUT_PTR, 0); REG_WR32(qlt, REG_ATIO_IN_PTR, 0); REG_WR32(qlt, REG_ATIO_OUT_PTR, 0); ! qlt->req_ndx_to_fw = qlt->req_ndx_from_fw = 0; ! qlt->req_available = REQUEST_QUEUE_ENTRIES - 1; ! qlt->resp_ndx_to_fw = qlt->resp_ndx_from_fw = 0; qlt->preq_ndx_to_fw = qlt->preq_ndx_from_fw = 0; qlt->atio_ndx_to_fw = qlt->atio_ndx_from_fw = 0; /* * XXX support for tunables. Also should we cache icb ? */ ! if (qlt->qlt_81xx_chip) { ! /* allocate extra 64 bytes for Extended init control block */ ! mcp = qlt_alloc_mailbox_command(qlt, 0xC0); } else { mcp = qlt_alloc_mailbox_command(qlt, 0x80); } if (mcp == NULL) { EL(qlt, "qlt_alloc_mailbox_command mcp=null\n"); return (STMF_ALLOC_FAILURE); } icb = (caddr_t)mcp->dbuf->db_sglist[0].seg_addr; ! if (qlt->qlt_81xx_chip) { ! bzero(icb, 0xC0); } else { bzero(icb, 0x80); } da = qlt->queue_mem_cookie.dmac_laddress; DMEM_WR16(qlt, icb, 1); /* Version */ --- 2107,2202 ---- elsbmp[1]); return (ret); } /* Init queue pointers */ + if (qlt->qlt_mq_enabled == 1) { + uint16_t qi; + + for (qi = 0; qi < MQ_MAX_QUEUES; qi++) { + MQBAR_WR32(qlt, + (qi * MQBAR_REG_OFFSET) + MQBAR_REQ_IN, 0); + MQBAR_WR32(qlt, + (qi * MQBAR_REG_OFFSET) + MQBAR_REQ_OUT, 0); + MQBAR_WR32(qlt, + (qi * MQBAR_REG_OFFSET) + MQBAR_RESP_IN, 0); + MQBAR_WR32(qlt, + (qi * MQBAR_REG_OFFSET) + + MQBAR_RESP_OUT, 0); + } + } else { REG_WR32(qlt, REG_REQ_IN_PTR, 0); REG_WR32(qlt, REG_REQ_OUT_PTR, 0); REG_WR32(qlt, REG_RESP_IN_PTR, 0); REG_WR32(qlt, REG_RESP_OUT_PTR, 0); + } + + if ((qlt->qlt_83xx_chip) || (qlt->qlt_27xx_chip)) { REG_WR32(qlt, REG_PREQ_IN_PTR, 0); REG_WR32(qlt, REG_PREQ_OUT_PTR, 0); REG_WR32(qlt, REG_ATIO_IN_PTR, 0); REG_WR32(qlt, REG_ATIO_OUT_PTR, 0); ! } ! qlt->mq_req[0].mq_ndx_to_fw = qlt->mq_req[0].mq_ndx_from_fw = 0; ! qlt->mq_req[0].mq_available = REQUEST_QUEUE_ENTRIES - 1; ! ! if (qlt->qlt_mq_enabled == 1) { ! for (i = 1; i < qlt->qlt_queue_cnt; i++) { ! qlt->mq_req[i].mq_ndx_to_fw = 0; ! qlt->mq_req[i].mq_ndx_from_fw = 0; ! qlt->mq_req[i].mq_available = ! REQUEST_QUEUE_MQ_ENTRIES - 1; ! } ! } ! qlt->mq_resp[0].mq_ndx_to_fw = qlt->mq_resp[0].mq_ndx_from_fw = 0; ! ! if (qlt->qlt_mq_enabled == 1) { ! caddr_t resp; ! ! for (i = 1; i < qlt->qlt_queue_cnt; i++) { ! qlt->mq_resp[i].mq_ndx_to_fw = 0; ! qlt->mq_resp[i].mq_ndx_from_fw = 0; ! for (j = 0; j < RESPONSE_QUEUE_MQ_ENTRIES; j++) { ! resp = &qlt->mq_resp[i].mq_ptr[j << 6]; ! QMEM_WR32_RSPQ(qlt, i, resp+0x3c, 0xdeadbeef); ! } ! } ! } ! ! for (i = 0; i < ATIO_QUEUE_ENTRIES; i++) { ! caddr_t atio; ! ! atio = &qlt->atio_ptr[i << 6]; ! QMEM_WR32(qlt, atio+0x3c, 0xdeadbeef); ! } ! qlt->preq_ndx_to_fw = qlt->preq_ndx_from_fw = 0; qlt->atio_ndx_to_fw = qlt->atio_ndx_from_fw = 0; /* * XXX support for tunables. Also should we cache icb ? */ ! if ((qlt->qlt_83xx_chip) || (qlt->qlt_81xx_chip) || ! (qlt->qlt_27xx_chip) || ((qlt->qlt_25xx_chip) && ! (qlt->qlt_mq_enabled))) { ! /* ! * allocate extra 64 bytes for Extended init control block, ! * with separation to allow for a minimal MID section. ! */ ! mcp = qlt_alloc_mailbox_command(qlt, 0xE0); } else { mcp = qlt_alloc_mailbox_command(qlt, 0x80); } if (mcp == NULL) { EL(qlt, "qlt_alloc_mailbox_command mcp=null\n"); return (STMF_ALLOC_FAILURE); } icb = (caddr_t)mcp->dbuf->db_sglist[0].seg_addr; ! if ((qlt->qlt_83xx_chip) || (qlt->qlt_81xx_chip) || ! (qlt->qlt_27xx_chip) || ((qlt->qlt_25xx_chip) && ! (qlt->qlt_mq_enabled))) { ! bzero(icb, 0xE0); } else { bzero(icb, 0x80); } da = qlt->queue_mem_cookie.dmac_laddress; DMEM_WR16(qlt, icb, 1); /* Version */
*** 1317,1342 **** bcopy(qlt->qlt_port->port_pwwn, icb+0x0c, 8); bcopy(qlt->qlt_port->port_nwwn, icb+0x14, 8); DMEM_WR16(qlt, icb+0x20, 3); /* Login retry count */ DMEM_WR16(qlt, icb+0x24, RESPONSE_QUEUE_ENTRIES); DMEM_WR16(qlt, icb+0x26, REQUEST_QUEUE_ENTRIES); ! if (!qlt->qlt_81xx_chip) { DMEM_WR16(qlt, icb+0x28, 100); /* ms of NOS/OLS for Link down */ } DMEM_WR16(qlt, icb+0x2a, PRIORITY_QUEUE_ENTRIES); DMEM_WR64(qlt, icb+0x2c, (da+REQUEST_QUEUE_OFFSET)); DMEM_WR64(qlt, icb+0x34, (da+RESPONSE_QUEUE_OFFSET)); DMEM_WR64(qlt, icb+0x3c, (da+PRIORITY_QUEUE_OFFSET)); DMEM_WR16(qlt, icb+0x4e, ATIO_QUEUE_ENTRIES); DMEM_WR64(qlt, icb+0x50, (da+ATIO_QUEUE_OFFSET)); DMEM_WR16(qlt, icb+0x58, 2); /* Interrupt delay Timer */ DMEM_WR16(qlt, icb+0x5a, 4); /* Login timeout (secs) */ ! if (qlt->qlt_81xx_chip) { qlt_nvram_81xx_t *qlt81nvr = (qlt_nvram_81xx_t *)qlt->nvram; ! DMEM_WR32(qlt, icb+0x5c, BIT_5 | BIT_4); /* fw options 1 */ ! DMEM_WR32(qlt, icb+0x64, BIT_20 | BIT_4); /* fw options 3 */ DMEM_WR32(qlt, icb+0x70, qlt81nvr->enode_mac[0] | (qlt81nvr->enode_mac[1] << 8) | (qlt81nvr->enode_mac[2] << 16) | (qlt81nvr->enode_mac[3] << 24)); --- 2207,2273 ---- bcopy(qlt->qlt_port->port_pwwn, icb+0x0c, 8); bcopy(qlt->qlt_port->port_nwwn, icb+0x14, 8); DMEM_WR16(qlt, icb+0x20, 3); /* Login retry count */ DMEM_WR16(qlt, icb+0x24, RESPONSE_QUEUE_ENTRIES); DMEM_WR16(qlt, icb+0x26, REQUEST_QUEUE_ENTRIES); ! if ((!qlt->qlt_83xx_chip) && (!qlt->qlt_81xx_chip) && ! (!qlt->qlt_27xx_chip)) { DMEM_WR16(qlt, icb+0x28, 100); /* ms of NOS/OLS for Link down */ } + if ((!qlt->qlt_83xx_chip) || (!qlt->qlt_27xx_chip)) { DMEM_WR16(qlt, icb+0x2a, PRIORITY_QUEUE_ENTRIES); + } DMEM_WR64(qlt, icb+0x2c, (da+REQUEST_QUEUE_OFFSET)); DMEM_WR64(qlt, icb+0x34, (da+RESPONSE_QUEUE_OFFSET)); + if ((!qlt->qlt_83xx_chip) || (!qlt->qlt_27xx_chip)) { DMEM_WR64(qlt, icb+0x3c, (da+PRIORITY_QUEUE_OFFSET)); + } + /* XXX: all hba model atio/resp 0 use vector 0 */ DMEM_WR16(qlt, icb+0x4e, ATIO_QUEUE_ENTRIES); DMEM_WR64(qlt, icb+0x50, (da+ATIO_QUEUE_OFFSET)); DMEM_WR16(qlt, icb+0x58, 2); /* Interrupt delay Timer */ DMEM_WR16(qlt, icb+0x5a, 4); /* Login timeout (secs) */ ! if ((qlt->qlt_83xx_chip) || (qlt->qlt_81xx_chip) || ! (qlt->qlt_27xx_chip) || ((qlt->qlt_25xx_chip) && ! (qlt->qlt_mq_enabled))) { qlt_nvram_81xx_t *qlt81nvr = (qlt_nvram_81xx_t *)qlt->nvram; ! /* fw options 1 */ ! if (qlt->qlt_fcoe_enabled) { ! DMEM_WR32(qlt, icb+0x5c, BIT_5 | BIT_4); ! } else { ! DMEM_WR32(qlt, icb+0x5c, ! BIT_11 | BIT_5 | BIT_4 | BIT_2 | BIT_1 | BIT_0); ! } ! /* fw options 2 */ ! if (qlt->qlt_mq_enabled) { ! if ((qlt->qlt_83xx_chip) || (qlt->qlt_27xx_chip)) { ! if (qlt->qlt_fcoe_enabled) { ! DMEM_WR32(qlt, icb+0x60, ! BIT_26 | BIT_23 | BIT_22); ! } else { ! DMEM_WR32(qlt, icb+0x60, ! BIT_26 | BIT_23 | BIT_22 | BIT_5); ! } ! } else { ! DMEM_WR32(qlt, ! icb+0x60, BIT_26 | BIT_23 | BIT_22 | BIT_5); ! } ! } ! ! /* fw options 3 */ ! if (qlt->qlt_fcoe_enabled) { ! DMEM_WR32(qlt, icb+0x64, BIT_4); ! } else { ! DMEM_WR32(qlt, icb+0x64, ! BIT_14 | BIT_8 | BIT_7 | BIT_4); ! } ! ! if (qlt->qlt_mq_enabled) { ! DMEM_WR16(qlt, icb+0x68, 5); /* QoS priority = 5 */ ! } ! DMEM_WR32(qlt, icb+0x70, qlt81nvr->enode_mac[0] | (qlt81nvr->enode_mac[1] << 8) | (qlt81nvr->enode_mac[2] << 16) | (qlt81nvr->enode_mac[3] << 24));
*** 1347,1375 **** DMEM_WR32(qlt, icb+0x5c, BIT_11 | BIT_5 | BIT_4 | BIT_2 | BIT_1 | BIT_0); DMEM_WR32(qlt, icb+0x60, BIT_5); DMEM_WR32(qlt, icb+0x64, BIT_14 | BIT_8 | BIT_7 | BIT_4); } ! if (qlt->qlt_81xx_chip) { qlt_dmem_bctl_t *bctl; uint32_t index; caddr_t src; caddr_t dst; qlt_nvram_81xx_t *qlt81nvr; ! dst = icb+0x80; qlt81nvr = (qlt_nvram_81xx_t *)qlt->nvram; src = (caddr_t)&qlt81nvr->ext_blk; index = sizeof (qlt_ext_icb_81xx_t); /* Use defaults for cases where we find nothing in NVR */ if (*src == 0) { EL(qlt, "nvram eicb=null\n"); cmn_err(CE_NOTE, "qlt(%d) NVR eicb is zeroed", instance); qlt81nvr->ext_blk.version[0] = 1; /* * not yet, for !FIP firmware at least * * qlt81nvr->ext_blk.fcf_vlan_match = 0x81; --- 2278,2311 ---- DMEM_WR32(qlt, icb+0x5c, BIT_11 | BIT_5 | BIT_4 | BIT_2 | BIT_1 | BIT_0); DMEM_WR32(qlt, icb+0x60, BIT_5); DMEM_WR32(qlt, icb+0x64, BIT_14 | BIT_8 | BIT_7 | BIT_4); + + /* null MID setup */ + DMEM_WR16(qlt, icb+0x80, 1); /* VP count 1 */ } ! if (qlt->qlt_fcoe_enabled) { qlt_dmem_bctl_t *bctl; uint32_t index; caddr_t src; caddr_t dst; qlt_nvram_81xx_t *qlt81nvr; ! dst = icb+0xA0; qlt81nvr = (qlt_nvram_81xx_t *)qlt->nvram; src = (caddr_t)&qlt81nvr->ext_blk; index = sizeof (qlt_ext_icb_81xx_t); /* Use defaults for cases where we find nothing in NVR */ + if ((qlt->qlt_83xx_chip) || (*src == 0)) { if (*src == 0) { EL(qlt, "nvram eicb=null\n"); cmn_err(CE_NOTE, "qlt(%d) NVR eicb is zeroed", instance); + } qlt81nvr->ext_blk.version[0] = 1; /* * not yet, for !FIP firmware at least * * qlt81nvr->ext_blk.fcf_vlan_match = 0x81;
*** 1386,1396 **** while (index--) { *dst++ = *src++; } bctl = (qlt_dmem_bctl_t *)mcp->dbuf->db_port_private; ! da = bctl->bctl_dev_addr + 0x80; /* base addr of eicb (phys) */ mcp->to_fw[11] = LSW(LSD(da)); mcp->to_fw[10] = MSW(LSD(da)); mcp->to_fw[13] = LSW(MSD(da)); mcp->to_fw[12] = MSW(MSD(da)); --- 2322,2332 ---- while (index--) { *dst++ = *src++; } bctl = (qlt_dmem_bctl_t *)mcp->dbuf->db_port_private; ! da = bctl->bctl_dev_addr + 0xA0; /* base addr of eicb (phys) */ mcp->to_fw[11] = LSW(LSD(da)); mcp->to_fw[10] = MSW(LSD(da)); mcp->to_fw[13] = LSW(MSD(da)); mcp->to_fw[12] = MSW(MSD(da));
*** 1402,1453 **** mcp->to_fw_mask |= BIT_14 | BIT_13 | BIT_12 | BIT_11 | BIT_10 | BIT_1; } qlt_dmem_dma_sync(mcp->dbuf, DDI_DMA_SYNC_FORDEV); mcp->to_fw[0] = MBC_INITIALIZE_FIRMWARE; /* * This is the 1st command after adapter initialize which will * use interrupts and regular mailbox interface. */ qlt->mbox_io_state = MBOX_STATE_READY; REG_WR32(qlt, REG_INTR_CTRL, ENABLE_RISC_INTR); /* Issue mailbox to firmware */ ret = qlt_mailbox_command(qlt, mcp); if (ret != QLT_SUCCESS) { ! EL(qlt, "qlt_mailbox_command=60h status=%llxh\n", ret); cmn_err(CE_NOTE, "qlt(%d) init fw failed %llx, intr status %x", instance, (long long)ret, REG_RD32(qlt, REG_INTR_STATUS)); } mcp->to_fw_mask = BIT_0; mcp->from_fw_mask = BIT_0 | BIT_1; mcp->to_fw[0] = 0x28; ret = qlt_mailbox_command(qlt, mcp); if (ret != QLT_SUCCESS) { ! EL(qlt, "qlt_mailbox_command=28h status=%llxh\n", ret); cmn_err(CE_NOTE, "qlt(%d) get_fw_options %llx", instance, (long long)ret); } /* * Report FW versions for 81xx - MPI rev is useful */ ! if (qlt->qlt_81xx_chip) { mcp->to_fw_mask = BIT_0; ! mcp->from_fw_mask = BIT_11 | BIT_10 | BIT_3 | BIT_2 | BIT_1 | ! BIT_0; ! mcp->to_fw[0] = 0x8; ret = qlt_mailbox_command(qlt, mcp); if (ret != QLT_SUCCESS) { EL(qlt, "about fw failed: %llx\n", (long long)ret); } else { EL(qlt, "Firmware version %d.%d.%d, MPI: %d.%d.%d\n", mcp->from_fw[1], mcp->from_fw[2], mcp->from_fw[3], mcp->from_fw[10] & 0xff, mcp->from_fw[11] >> 8, mcp->from_fw[11] & 0xff); } } qlt_free_mailbox_command(qlt, mcp); --- 2338,2480 ---- mcp->to_fw_mask |= BIT_14 | BIT_13 | BIT_12 | BIT_11 | BIT_10 | BIT_1; } qlt_dmem_dma_sync(mcp->dbuf, DDI_DMA_SYNC_FORDEV); + if (((qlt->qlt_83xx_chip) || (qlt->qlt_81xx_chip) || + (qlt->qlt_27xx_chip) || ((qlt->qlt_25xx_chip) && + (qlt->qlt_mq_enabled))) && (qlt->fw_attr & BIT_6)) { + mcp->to_fw[0] = MBC_INITIALIZE_MULTI_ID_FW; + } else { mcp->to_fw[0] = MBC_INITIALIZE_FIRMWARE; + } /* * This is the 1st command after adapter initialize which will * use interrupts and regular mailbox interface. */ + qlt->qlt_intr_enabled = 1; qlt->mbox_io_state = MBOX_STATE_READY; REG_WR32(qlt, REG_INTR_CTRL, ENABLE_RISC_INTR); /* Issue mailbox to firmware */ ret = qlt_mailbox_command(qlt, mcp); if (ret != QLT_SUCCESS) { ! EL(qlt, "qlt_mbox_command=48h/60h status=%llxh\n", ret); cmn_err(CE_NOTE, "qlt(%d) init fw failed %llx, intr status %x", instance, (long long)ret, REG_RD32(qlt, REG_INTR_STATUS)); + qlt_free_mailbox_command(qlt, mcp); + return (ret); } mcp->to_fw_mask = BIT_0; mcp->from_fw_mask = BIT_0 | BIT_1; mcp->to_fw[0] = 0x28; ret = qlt_mailbox_command(qlt, mcp); if (ret != QLT_SUCCESS) { ! EL(qlt, "qlt_mbox_command=28h status=%llxh\n", ret); cmn_err(CE_NOTE, "qlt(%d) get_fw_options %llx", instance, (long long)ret); + qlt_free_mailbox_command(qlt, mcp); + return (ret); } + if (qlt->qlt_mq_enabled == 1) { + + for (i = 1; i < qlt->qlt_queue_cnt; i++) { + da = qlt->mq_resp[i].queue_mem_mq_cookie.dmac_laddress; + + mcp->to_fw_mask = BIT_14 | BIT_13 | BIT_12 | BIT_11 | + BIT_10 | BIT_9 | BIT_8 | BIT_7 | BIT_6 | BIT_5 | + BIT_4 | BIT_3 | BIT_2 | BIT_1 | BIT_0; + mcp->from_fw_mask = BIT_0 | BIT_1; + + /* msix vector setup */ + mcp->to_fw[14] = (uint16_t)(i); + + mcp->to_fw[13] = 0; + mcp->to_fw[12] = 0; + mcp->to_fw[11] = 0; + mcp->to_fw[10] = 0; + mcp->to_fw[9] = 0; + mcp->to_fw[8] = 0; + mcp->to_fw[7] = LSW(MSD(da)); + mcp->to_fw[6] = MSW(MSD(da)); + mcp->to_fw[5] = RESPONSE_QUEUE_MQ_ENTRIES; + mcp->to_fw[4] = (uint16_t)(i); + mcp->to_fw[3] = LSW(LSD(da)); + mcp->to_fw[2] = MSW(LSD(da)); + mcp->to_fw[1] = BIT_6 | BIT_1; + mcp->to_fw[0] = 0x1F; + ret = qlt_mailbox_command(qlt, mcp); + + if (ret != QLT_SUCCESS) { + EL(qlt, "qlt_mbox_command=1fh status=%llxh\n", + ret); + cmn_err(CE_NOTE, "qlt(%d) queue manage %llx", + instance, (long long)ret); + qlt_free_mailbox_command(qlt, mcp); + return (ret); + } + + da = qlt->mq_req[i].queue_mem_mq_cookie.dmac_laddress; + + mcp->to_fw_mask = BIT_14 | BIT_13 | BIT_12 | BIT_11 | + BIT_10 | BIT_9 | BIT_8 | BIT_7 | BIT_6 | BIT_5 | + BIT_4 | BIT_3 | BIT_2 | BIT_1 | BIT_0; + mcp->from_fw_mask = BIT_0 | BIT_1; + /* + * msix vector does not apply for request queue create + */ + mcp->to_fw[14] = 2; + mcp->to_fw[13] = 0; + mcp->to_fw[12] = 4; + mcp->to_fw[11] = 0; + mcp->to_fw[10] = (uint16_t)(i); + mcp->to_fw[9] = 0; + mcp->to_fw[8] = 0; + mcp->to_fw[7] = LSW(MSD(da)); + mcp->to_fw[6] = MSW(MSD(da)); + mcp->to_fw[5] = REQUEST_QUEUE_MQ_ENTRIES; + mcp->to_fw[4] = (uint16_t)(i); + mcp->to_fw[3] = LSW(LSD(da)); + mcp->to_fw[2] = MSW(LSD(da)); + mcp->to_fw[1] = BIT_6; + mcp->to_fw[0] = 0x1F; + ret = qlt_mailbox_command(qlt, mcp); + + if (ret != QLT_SUCCESS) { + EL(qlt, "qlt_mbox_command=1fh status=%llxh\n", + ret); + cmn_err(CE_NOTE, "qlt(%d) queue manage %llx", + instance, (long long)ret); + qlt_free_mailbox_command(qlt, mcp); + return (ret); + } + } + } + + /* * Report FW versions for 81xx - MPI rev is useful */ ! /* if ((qlt->qlt_83xx_chip) || (qlt->qlt_81xx_chip)) { */ ! if (qlt->qlt_fcoe_enabled) { mcp->to_fw_mask = BIT_0; ! mcp->from_fw_mask = BIT_11 | BIT_10 | BIT_6 | BIT_3 | BIT_2 | ! BIT_1 | BIT_0; ! ! mcp->to_fw[0] = MBC_ABOUT_FIRMWARE; ret = qlt_mailbox_command(qlt, mcp); if (ret != QLT_SUCCESS) { EL(qlt, "about fw failed: %llx\n", (long long)ret); } else { EL(qlt, "Firmware version %d.%d.%d, MPI: %d.%d.%d\n", mcp->from_fw[1], mcp->from_fw[2], mcp->from_fw[3], mcp->from_fw[10] & 0xff, mcp->from_fw[11] >> 8, mcp->from_fw[11] & 0xff); + EL(qlt, "Firmware Attributes %x[h]\n", + mcp->from_fw[6]); } } qlt_free_mailbox_command(qlt, mcp);
*** 1458,1474 **** --- 2485,2503 ---- qlt->qlt_pmintry = 0; qlt->qlt_pmin_ok = 0; if (ret != QLT_SUCCESS) return (ret); + return (FCT_SUCCESS); } fct_status_t qlt_port_offline(qlt_state_t *qlt) { int retries; + int i; mutex_enter(&qlt->mbox_lock); if (qlt->mbox_io_state == MBOX_STATE_UNKNOWN) { mutex_exit(&qlt->mbox_lock);
*** 1489,1501 **** --- 2518,2540 ---- qlt->mbox_io_state = MBOX_STATE_UNKNOWN; mutex_exit(&qlt->mbox_lock); poff_mbox_done:; qlt->intr_sneak_counter = 10; mutex_enter(&qlt->intr_lock); + if (qlt->qlt_mq_enabled == 1) { + for (i = 1; i < qlt->qlt_queue_cnt; i++) { + mutex_enter(&qlt->mq_resp[i].mq_lock); + } + } (void) qlt_reset_chip(qlt); drv_usecwait(20); qlt->intr_sneak_counter = 0; + if (qlt->qlt_mq_enabled == 1) { + for (i = 1; i < qlt->qlt_queue_cnt; i++) { + mutex_exit(&qlt->mq_resp[i].mq_lock); + } + } mutex_exit(&qlt->intr_lock); return (FCT_SUCCESS); }
*** 1516,1533 **** mcp->to_fw_mask |= BIT_0 | BIT_9; mcp->from_fw_mask |= BIT_0 | BIT_1 | BIT_2 | BIT_3 | BIT_6 | BIT_7; /* Issue mailbox to firmware */ ret = qlt_mailbox_command(qlt, mcp); if (ret != QLT_SUCCESS) { ! EL(qlt, "qlt_mailbox_command=20h status=%llxh\n", ret); ! if ((mcp->from_fw[0] == 0x4005) && (mcp->from_fw[1] == 7)) { /* Firmware is not ready */ if (ddi_get_lbolt() < et) { delay(drv_usectohz(50000)); goto link_info_retry; } } stmf_trace(qlt->qlt_port_alias, "GET ID mbox failed, ret=%llx " "mb0=%x mb1=%x", ret, mcp->from_fw[0], mcp->from_fw[1]); fc_ret = FCT_FAILURE; } else { li->portid = ((uint32_t)(mcp->from_fw[2])) | --- 2555,2575 ---- mcp->to_fw_mask |= BIT_0 | BIT_9; mcp->from_fw_mask |= BIT_0 | BIT_1 | BIT_2 | BIT_3 | BIT_6 | BIT_7; /* Issue mailbox to firmware */ ret = qlt_mailbox_command(qlt, mcp); if (ret != QLT_SUCCESS) { ! EL(qlt, "qlt_mbox_command=20h status=%llxh\n", ret); ! if ((mcp->from_fw[0] == 0x4005) && ! ((mcp->from_fw[1] == 7) || (mcp->from_fw[1] == 0x1b))) { /* Firmware is not ready */ if (ddi_get_lbolt() < et) { delay(drv_usectohz(50000)); goto link_info_retry; } } + EL(qlt, "GET ID mbox failed, ret=%llx mb0=%x mb1=%x", + ret, mcp->from_fw[0], mcp->from_fw[1]); stmf_trace(qlt->qlt_port_alias, "GET ID mbox failed, ret=%llx " "mb0=%x mb1=%x", ret, mcp->from_fw[0], mcp->from_fw[1]); fc_ret = FCT_FAILURE; } else { li->portid = ((uint32_t)(mcp->from_fw[2])) |
*** 1556,1565 **** --- 2598,2611 ---- li->port_topology = PORT_TOPOLOGY_UNKNOWN; EL(qlt, "Unknown topology=%xh\n", mcp->from_fw[6]); } qlt->cur_topology = li->port_topology; fc_ret = FCT_SUCCESS; + + EL(qlt, "MBC_GET_ID done, Topology=%x, portid=%xh, " + "port speed=%xh\n", li->port_topology, li->portid, + li->port_speed); } qlt_free_mailbox_command(qlt, mcp); if ((fc_ret == FCT_SUCCESS) && (li->port_fca_flogi_done)) { mcp = qlt_alloc_mailbox_command(qlt, 64);
*** 1568,1578 **** mcp->to_fw[9] = 0; mcp->to_fw[10] = 0; mcp->to_fw_mask |= BIT_0 | BIT_1 | BIT_9 | BIT_10; fc_ret = qlt_mailbox_command(qlt, mcp); if (fc_ret != QLT_SUCCESS) { ! EL(qlt, "qlt_mailbox_command=64h status=%llxh\n", fc_ret); stmf_trace(qlt->qlt_port_alias, "Attempt to get port " "database for F_port failed, ret = %llx", fc_ret); } else { uint8_t *p; --- 2614,2624 ---- mcp->to_fw[9] = 0; mcp->to_fw[10] = 0; mcp->to_fw_mask |= BIT_0 | BIT_1 | BIT_9 | BIT_10; fc_ret = qlt_mailbox_command(qlt, mcp); if (fc_ret != QLT_SUCCESS) { ! EL(qlt, "qlt_mbox_command=64h status=%llxh\n", fc_ret); stmf_trace(qlt->qlt_port_alias, "Attempt to get port " "database for F_port failed, ret = %llx", fc_ret); } else { uint8_t *p;
*** 1579,1588 **** --- 2625,2636 ---- qlt_dmem_dma_sync(mcp->dbuf, DDI_DMA_SYNC_FORCPU); p = mcp->dbuf->db_sglist[0].seg_addr; bcopy(p + 0x18, li->port_rpwwn, 8); bcopy(p + 0x20, li->port_rnwwn, 8); + EL(qlt, "qlt_mbox_command=64h, GET_PORT_DATABASE " + "complete\n"); } qlt_free_mailbox_command(qlt, mcp); } return (fc_ret); }
*** 1693,1703 **** void *obuf = NULL; uint32_t *intp; qlt_fw_info_t *fwi; mbox_cmd_t *mcp; fct_status_t st; ! char info[QLT_INFO_LEN]; fct_status_t ret2; if (drv_priv(credp) != 0) return (EPERM); --- 2741,2751 ---- void *obuf = NULL; uint32_t *intp; qlt_fw_info_t *fwi; mbox_cmd_t *mcp; fct_status_t st; ! char info[80]; fct_status_t ret2; if (drv_priv(credp) != 0) return (EPERM);
*** 1747,1758 **** if (qlt->qlt_state != FCT_STATE_ONLINE) { ret = EACCES; iocd->stmf_error = QLTIO_NOT_ONLINE; break; } ! (void) snprintf(info, sizeof (info), "qlt_ioctl: qlt-%p, " "user triggered FWDUMP with RFLAG_RESET", (void *)qlt); if ((ret2 = fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_USER_REQUEST | STMF_RFLAG_RESET | STMF_RFLAG_COLLECT_DEBUG_DUMP, info)) != FCT_SUCCESS) { EL(qlt, "TRIGGER_FWDUMP fct_port_shutdown status=" "%llxh\n", ret2); --- 2795,2807 ---- if (qlt->qlt_state != FCT_STATE_ONLINE) { ret = EACCES; iocd->stmf_error = QLTIO_NOT_ONLINE; break; } ! (void) snprintf(info, 80, "qlt_ioctl: qlt-%p, " "user triggered FWDUMP with RFLAG_RESET", (void *)qlt); + info[79] = 0; if ((ret2 = fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_USER_REQUEST | STMF_RFLAG_RESET | STMF_RFLAG_COLLECT_DEBUG_DUMP, info)) != FCT_SUCCESS) { EL(qlt, "TRIGGER_FWDUMP fct_port_shutdown status=" "%llxh\n", ret2);
*** 1784,1793 **** --- 2833,2843 ---- break; } if ((qlt->qlt_81xx_chip && ((intp[8] & 8) == 0)) || (qlt->qlt_25xx_chip && ((intp[8] & 4) == 0)) || (!qlt->qlt_25xx_chip && !qlt->qlt_81xx_chip && + !qlt->qlt_83xx_chip && !qlt->qlt_27xx_chip && ((intp[8] & 3) == 0))) { EL(qlt, "UPLOAD_FW fw_type=%d\n", intp[8]); ret = EACCES; iocd->stmf_error = QLTIO_INVALID_FW_TYPE; break;
*** 1843,1853 **** fwi->fwi_loaded_major = (uint16_t)qlt->fw_code01[4]; fwi->fwi_loaded_minor = (uint16_t)qlt->fw_code01[5]; fwi->fwi_loaded_subminor = (uint16_t)qlt->fw_code01[6]; fwi->fwi_loaded_attr = (uint16_t)qlt->fw_code01[7]; } ! if (qlt->qlt_81xx_chip) { fwi->fwi_default_major = (uint16_t)fw8100_code01[4]; fwi->fwi_default_minor = (uint16_t)fw8100_code01[5]; fwi->fwi_default_subminor = (uint16_t)fw8100_code01[6]; fwi->fwi_default_attr = (uint16_t)fw8100_code01[7]; } else if (qlt->qlt_25xx_chip) { --- 2893,2914 ---- fwi->fwi_loaded_major = (uint16_t)qlt->fw_code01[4]; fwi->fwi_loaded_minor = (uint16_t)qlt->fw_code01[5]; fwi->fwi_loaded_subminor = (uint16_t)qlt->fw_code01[6]; fwi->fwi_loaded_attr = (uint16_t)qlt->fw_code01[7]; } ! if (qlt->qlt_27xx_chip) { ! fwi->fwi_default_major = (uint16_t)fw2700_code01[4]; ! fwi->fwi_default_minor = (uint16_t)fw2700_code01[5]; ! fwi->fwi_default_subminor = (uint16_t)fw2700_code01[6]; ! fwi->fwi_default_attr = (uint16_t)fw2700_code01[7]; ! } else if (qlt->qlt_83xx_chip) { ! fwi->fwi_default_major = (uint16_t)fw8300fc_code01[4]; ! fwi->fwi_default_minor = (uint16_t)fw8300fc_code01[5]; ! fwi->fwi_default_subminor = ! (uint16_t)fw8300fc_code01[6]; ! fwi->fwi_default_attr = (uint16_t)fw8300fc_code01[7]; ! } else if (qlt->qlt_81xx_chip) { fwi->fwi_default_major = (uint16_t)fw8100_code01[4]; fwi->fwi_default_minor = (uint16_t)fw8100_code01[5]; fwi->fwi_default_subminor = (uint16_t)fw8100_code01[6]; fwi->fwi_default_attr = (uint16_t)fw8100_code01[7]; } else if (qlt->qlt_25xx_chip) {
*** 1918,1928 **** } } break; case QLT_IOCTL_ELOG: ! qlt_dump_el_trace_buffer(qlt); break; default: EL(qlt, "Unknown ioctl-%xh\n", cmd); ret = ENOTTY; --- 2979,2989 ---- } } break; case QLT_IOCTL_ELOG: ! EL(qlt, "Not support yet, ioctl-%xh\n", cmd); break; default: EL(qlt, "Unknown ioctl-%xh\n", cmd); ret = ENOTTY;
*** 1950,1968 **** { mbox_cmd_t *mcp; fct_status_t rval; mcp = qlt_alloc_mailbox_command(qlt, 0); ! mcp->to_fw[0] = 0x0072; mcp->to_fw[1] = BIT_4; mcp->to_fw[3] = 1; mcp->to_fw_mask |= BIT_1 | BIT_3; rval = qlt_mailbox_command(qlt, mcp); if (rval != FCT_SUCCESS) { ! EL(qlt, "qlt force lip MB failed: rval=%x", rval); } else { ! if (mcp->from_fw[0] != 0x4000) { QLT_LOG(qlt->qlt_port_alias, "qlt FLIP: fw[0]=%x", mcp->from_fw[0]); rval = FCT_FAILURE; } } --- 3011,3033 ---- { mbox_cmd_t *mcp; fct_status_t rval; mcp = qlt_alloc_mailbox_command(qlt, 0); ! if (qlt->qlt_fcoe_enabled) { ! mcp->to_fw[0] = MBC_PORT_RESET; ! } else { ! mcp->to_fw[0] = MBC_LIP_FULL_LOGIN; mcp->to_fw[1] = BIT_4; mcp->to_fw[3] = 1; mcp->to_fw_mask |= BIT_1 | BIT_3; + } rval = qlt_mailbox_command(qlt, mcp); if (rval != FCT_SUCCESS) { ! EL(qlt, "qlt force lip MB failed: rval=%x\n", rval); } else { ! if (mcp->from_fw[0] != QLT_MBX_CMD_SUCCESS) { QLT_LOG(qlt->qlt_port_alias, "qlt FLIP: fw[0]=%x", mcp->from_fw[0]); rval = FCT_FAILURE; } }
*** 1986,1995 **** --- 3051,3063 ---- qlt = (qlt_state_t *)port->port_fca_private; st.st_completion_status = FCT_SUCCESS; st.st_additional_info = NULL; + EL(qlt, "port (%p) qlt_state (%xh) cmd (%xh) arg (%p)\n", + port, qlt->qlt_state, cmd, arg); + switch (cmd) { case FCT_CMD_PORT_ONLINE: if (qlt->qlt_state == FCT_STATE_ONLINE) st.st_completion_status = STMF_ALREADY; else if (qlt->qlt_state != FCT_STATE_OFFLINE)
*** 2059,2079 **** } } break; case FCT_CMD_FORCE_LIP: ! if (qlt->qlt_81xx_chip) { EL(qlt, "force lip is an unsupported command " "for this adapter type\n"); } else { *((fct_status_t *)arg) = qlt_force_lip(qlt); EL(qlt, "forcelip done\n"); } break; default: ! EL(qlt, "unsupport cmd - 0x%02X", cmd); break; } } /* ARGSUSED */ --- 3127,3149 ---- } } break; case FCT_CMD_FORCE_LIP: ! if (qlt->qlt_fcoe_enabled) { EL(qlt, "force lip is an unsupported command " "for this adapter type\n"); } else { + if (qlt->qlt_state == FCT_STATE_ONLINE) { *((fct_status_t *)arg) = qlt_force_lip(qlt); EL(qlt, "forcelip done\n"); } + } break; default: ! EL(qlt, "unsupport cmd - 0x%02X\n", cmd); break; } } /* ARGSUSED */
*** 2093,2149 **** * less/zero entries are available. Retuns NULL if it still cannot * fullfill the request. * **CALL qlt_submit_req_entries() BEFORE DROPPING THE LOCK** */ caddr_t ! qlt_get_req_entries(qlt_state_t *qlt, uint32_t n) { int try = 0; ! while (qlt->req_available < n) { uint32_t val1, val2, val3; val1 = REG_RD32(qlt, REG_REQ_OUT_PTR); val2 = REG_RD32(qlt, REG_REQ_OUT_PTR); val3 = REG_RD32(qlt, REG_REQ_OUT_PTR); if ((val1 != val2) || (val2 != val3)) continue; ! qlt->req_ndx_from_fw = val1; ! qlt->req_available = REQUEST_QUEUE_ENTRIES - 1 - ! ((qlt->req_ndx_to_fw - qlt->req_ndx_from_fw) & (REQUEST_QUEUE_ENTRIES - 1)); ! if (qlt->req_available < n) { if (try < 2) { drv_usecwait(100); try++; continue; } else { stmf_trace(qlt->qlt_port_alias, ! "Req Q is full"); return (NULL); } } break; } /* We dont change anything until the entries are sumitted */ ! return (&qlt->req_ptr[qlt->req_ndx_to_fw << 6]); } /* * updates the req in ptr to fw. Assumes that req lock is held. */ void ! qlt_submit_req_entries(qlt_state_t *qlt, uint32_t n) { ASSERT(n >= 1); - qlt->req_ndx_to_fw += n; - qlt->req_ndx_to_fw &= REQUEST_QUEUE_ENTRIES - 1; - qlt->req_available -= n; - REG_WR32(qlt, REG_REQ_IN_PTR, qlt->req_ndx_to_fw); - } /* * Return a pointer to n entries in the priority request queue. Assumes that * priority request queue lock is held. Does a very short busy wait if * less/zero entries are available. Retuns NULL if it still cannot * fullfill the request. --- 3163,3255 ---- * less/zero entries are available. Retuns NULL if it still cannot * fullfill the request. * **CALL qlt_submit_req_entries() BEFORE DROPPING THE LOCK** */ caddr_t ! qlt_get_req_entries(qlt_state_t *qlt, uint32_t n, uint16_t qi) { int try = 0; ! while (qlt->mq_req[qi].mq_available < n) { uint32_t val1, val2, val3; + + if (qlt->qlt_mq_enabled) { + /* debounce */ + val1 = MQBAR_RD32(qlt, + (qi * MQBAR_REG_OFFSET) + MQBAR_REQ_OUT); + val2 = MQBAR_RD32(qlt, + (qi * MQBAR_REG_OFFSET) + MQBAR_REQ_OUT); + val3 = MQBAR_RD32(qlt, + (qi * MQBAR_REG_OFFSET) + MQBAR_REQ_OUT); + } else { val1 = REG_RD32(qlt, REG_REQ_OUT_PTR); val2 = REG_RD32(qlt, REG_REQ_OUT_PTR); val3 = REG_RD32(qlt, REG_REQ_OUT_PTR); + } if ((val1 != val2) || (val2 != val3)) continue; ! qlt->mq_req[qi].mq_ndx_from_fw = val1; ! if (qi != 0) { ! qlt->mq_req[qi].mq_available = ! REQUEST_QUEUE_MQ_ENTRIES - 1 - ! ((qlt->mq_req[qi].mq_ndx_to_fw - ! qlt->mq_req[qi].mq_ndx_from_fw) & ! (REQUEST_QUEUE_MQ_ENTRIES - 1)); ! } else { ! qlt->mq_req[qi].mq_available = ! REQUEST_QUEUE_ENTRIES - 1 - ! ((qlt->mq_req[qi].mq_ndx_to_fw - ! qlt->mq_req[qi].mq_ndx_from_fw) & (REQUEST_QUEUE_ENTRIES - 1)); ! } ! if (qlt->mq_req[qi].mq_available < n) { if (try < 2) { drv_usecwait(100); try++; continue; } else { stmf_trace(qlt->qlt_port_alias, ! "Req Q# %xh is full", qi); ! EL(qlt, "Req %xh is full (%d,%d) (%d,%d)\n", ! qi, qlt->mq_req[qi].mq_ndx_to_fw, ! qlt->mq_req[qi].mq_ndx_from_fw, ! n, qlt->mq_req[qi].mq_available); return (NULL); } } break; } /* We dont change anything until the entries are sumitted */ ! return (&qlt->mq_req[qi].mq_ptr[qlt->mq_req[qi].mq_ndx_to_fw << 6]); } /* * updates the req in ptr to fw. Assumes that req lock is held. */ void ! qlt_submit_req_entries(qlt_state_t *qlt, uint32_t n, uint16_t qi) { + ASSERT(n >= 1); + qlt->mq_req[qi].mq_ndx_to_fw += n; + if (qi != 0) { + qlt->mq_req[qi].mq_ndx_to_fw &= REQUEST_QUEUE_MQ_ENTRIES - 1; + } else { + qlt->mq_req[qi].mq_ndx_to_fw &= REQUEST_QUEUE_ENTRIES - 1; + } + qlt->mq_req[qi].mq_available -= n; + if (qlt->qlt_mq_enabled) { + MQBAR_WR32(qlt, (qi * MQBAR_REG_OFFSET) + MQBAR_REQ_IN, + qlt->mq_req[qi].mq_ndx_to_fw); + } else { + REG_WR32(qlt, REG_REQ_IN_PTR, qlt->mq_req[0].mq_ndx_to_fw); + } + } + /* * Return a pointer to n entries in the priority request queue. Assumes that * priority request queue lock is held. Does a very short busy wait if * less/zero entries are available. Retuns NULL if it still cannot * fullfill the request.
*** 2216,2225 **** --- 3322,3332 ---- EL(qlt, "initiated\n"); /* XXX: Switch off LEDs */ + qlt->qlt_intr_enabled = 0; /* Disable Interrupts */ REG_WR32(qlt, REG_INTR_CTRL, 0); (void) REG_RD32(qlt, REG_INTR_CTRL); /* Stop DMA */ REG_WR32(qlt, REG_CTRL_STATUS, DMA_SHUTDOWN_CTRL | PCI_X_XFER_CTRL);
*** 2232,2249 **** --- 3339,3386 ---- /* 3 sec should be more than enough */ if (cntr == 300) return (QLT_DMA_STUCK); } + /* need to ensure no one accesses the hw during the reset 100us */ + if ((qlt->qlt_83xx_chip) || (qlt->qlt_27xx_chip)) { + mutex_enter(&qlt->mbox_lock); + if (qlt->qlt_mq_enabled == 1) { + int i; + + for (i = 1; i < qlt->qlt_queue_cnt; i++) { + mutex_enter(&qlt->mq_req[i].mq_lock); + } + } + mutex_enter(&qlt->mq_req[0].mq_lock); + /* + * We need to give time for other threads to finsh their + * interupts (or we need another lock) + */ + drv_usecwait(40); + } + /* Reset the Chip */ REG_WR32(qlt, REG_CTRL_STATUS, DMA_SHUTDOWN_CTRL | PCI_X_XFER_CTRL | CHIP_SOFT_RESET); qlt->qlt_link_up = 0; drv_usecwait(100); + if ((qlt->qlt_83xx_chip) || (qlt->qlt_27xx_chip)) { + mutex_exit(&qlt->mq_req[0].mq_lock); + if (qlt->qlt_mq_enabled == 1) { + int i; + + for (i = 1; i < qlt->qlt_queue_cnt; i++) { + mutex_exit(&qlt->mq_req[i].mq_lock); + } + } + mutex_exit(&qlt->mbox_lock); + } + /* Wait for ROM firmware to initialize (0x0000) in mailbox 0 */ cntr = 0; while (REG_RD16(qlt, REG_MBOX(0)) != 0) { delay(drv_usectohz(10000)); cntr++;
*** 2254,2263 **** --- 3391,3401 ---- /* Disable Interrupts (Probably not needed) */ REG_WR32(qlt, REG_INTR_CTRL, 0); return (QLT_SUCCESS); } + /* * - Should not be called from Interrupt. * - A very hardware specific function. Does not touch driver state. * - Assumes that interrupts are disabled or not there. * - Expects that the caller makes sure that all activity has stopped
*** 2290,2299 **** --- 3428,3454 ---- if (ret == QLT_SUCCESS) { ret = qlt_load_risc_ram(qlt, qlt->fw_code02, qlt->fw_length02, qlt->fw_addr02); } start_addr = qlt->fw_addr01; + } else if (qlt->qlt_27xx_chip) { + (void) qlt_27xx_get_dmp_template(qlt); + ret = qlt_load_risc_ram(qlt, fw2700_code01, + fw2700_length01, fw2700_addr01); + if (ret == QLT_SUCCESS) { + ret = qlt_load_risc_ram(qlt, fw2700_code02, + fw2700_length02, fw2700_addr02); + } + start_addr = fw2700_addr01; + } else if (qlt->qlt_83xx_chip) { + ret = qlt_load_risc_ram(qlt, fw8300fc_code01, + fw8300fc_length01, fw8300fc_addr01); + if (ret == QLT_SUCCESS) { + ret = qlt_load_risc_ram(qlt, fw8300fc_code02, + fw8300fc_length02, fw8300fc_addr02); + } + start_addr = fw8300fc_addr01; } else if (qlt->qlt_81xx_chip) { ret = qlt_load_risc_ram(qlt, fw8100_code01, fw8100_length01, fw8100_addr01); if (ret == QLT_SUCCESS) { ret = qlt_load_risc_ram(qlt, fw8100_code02,
*** 2336,2352 **** /* Execute firmware */ REG_WR16(qlt, REG_MBOX(0), MBC_EXECUTE_FIRMWARE); REG_WR16(qlt, REG_MBOX(1), MSW(start_addr)); REG_WR16(qlt, REG_MBOX(2), LSW(start_addr)); REG_WR16(qlt, REG_MBOX(3), 0); ! REG_WR16(qlt, REG_MBOX(4), 1); /* 25xx enable additional credits */ ret = qlt_raw_mailbox_command(qlt); REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); if (ret != QLT_SUCCESS) { EL(qlt, "qlt_raw_mailbox_command=2h status=%llxh\n", ret); return (ret); } /* Get revisions (About Firmware) */ REG_WR16(qlt, REG_MBOX(0), MBC_ABOUT_FIRMWARE); ret = qlt_raw_mailbox_command(qlt); qlt->fw_major = REG_RD16(qlt, REG_MBOX(1)); --- 3491,3524 ---- /* Execute firmware */ REG_WR16(qlt, REG_MBOX(0), MBC_EXECUTE_FIRMWARE); REG_WR16(qlt, REG_MBOX(1), MSW(start_addr)); REG_WR16(qlt, REG_MBOX(2), LSW(start_addr)); REG_WR16(qlt, REG_MBOX(3), 0); ! #ifdef EXTRA_CREDIT ! /* enable extra credits (reduces available buffers) */ ! if ((qlt->qlt_25xx_chip) || (qlt->qlt_81xx_chip) || ! (qlt->qlt_83xx_chip) || (qlt->qlt_27xx_chip)) { ! REG_WR16(qlt, REG_MBOX(4), 1); ! } else { ! REG_WR16(qlt, REG_MBOX(4), 0); ! } ! #else ! REG_WR16(qlt, REG_MBOX(4), 0); ! #endif ret = qlt_raw_mailbox_command(qlt); REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); if (ret != QLT_SUCCESS) { EL(qlt, "qlt_raw_mailbox_command=2h status=%llxh\n", ret); return (ret); + } else { + if (qlt->qlt_27xx_chip) { + qlt->qlt_27xx_speed = (uint32_t) + (REG_RD16(qlt, REG_MBOX(3)) << 16 | + REG_RD16(qlt, REG_MBOX(2))); + } + } /* Get revisions (About Firmware) */ REG_WR16(qlt, REG_MBOX(0), MBC_ABOUT_FIRMWARE); ret = qlt_raw_mailbox_command(qlt); qlt->fw_major = REG_RD16(qlt, REG_MBOX(1));
*** 2359,2368 **** --- 3531,3559 ---- if (ret != QLT_SUCCESS) { EL(qlt, "qlt_raw_mailbox_command=8h status=%llxh\n", ret); return (ret); } + if (qlt->qlt_27xx_chip) { + qlt->fw_ext_memory_end = SHORT_TO_LONG( + REG_RD16(qlt, REG_MBOX(4)), + REG_RD16(qlt, REG_MBOX(5))); + qlt->fw_shared_ram_start = SHORT_TO_LONG( + REG_RD16(qlt, REG_MBOX(18)), + REG_RD16(qlt, REG_MBOX(19))); + qlt->fw_shared_ram_end = SHORT_TO_LONG( + REG_RD16(qlt, REG_MBOX(20)), + REG_RD16(qlt, REG_MBOX(21))); + qlt->fw_ddr_ram_start = SHORT_TO_LONG( + REG_RD16(qlt, REG_MBOX(22)), + REG_RD16(qlt, REG_MBOX(23))); + qlt->fw_ddr_ram_end = SHORT_TO_LONG( + REG_RD16(qlt, REG_MBOX(24)), + REG_RD16(qlt, REG_MBOX(25))); + } + + return (QLT_SUCCESS); } /* * Used only from qlt_download_fw().
*** 2405,2414 **** --- 3596,3606 ---- ret); return (ret); } words_sent += words_being_sent; } + EL(qlt, "qlt_raw_mailbox_command=0Bh, LOAD_RAM_EXTENDED complete\n"); return (QLT_SUCCESS); } /* * Not used during normal operation. Only during driver init.
*** 2416,2437 **** * Just triggers the mailbox command an waits for the completion. * Also expects that There is nothing else going on and we will only * get back a mailbox completion from firmware. * ---DOES NOT CLEAR INTERRUPT--- * Used only from the code path originating from ! * qlt_reset_chip_and_download_fw() */ static fct_status_t qlt_raw_mailbox_command(qlt_state_t *qlt) { int cntr = 0; uint32_t status; REG_WR32(qlt, REG_HCCR, HCCR_CMD(SET_HOST_TO_RISC_INTR)); while ((REG_RD32(qlt, REG_INTR_STATUS) & RISC_PCI_INTR_REQUEST) == 0) { cntr++; ! if (cntr == 100) { return (QLT_MAILBOX_STUCK); } delay(drv_usectohz(10000)); } status = (REG_RD32(qlt, REG_RISC_STATUS) & FW_INTR_STATUS_MASK); --- 3608,3634 ---- * Just triggers the mailbox command an waits for the completion. * Also expects that There is nothing else going on and we will only * get back a mailbox completion from firmware. * ---DOES NOT CLEAR INTERRUPT--- * Used only from the code path originating from ! * qlt_reset_chip() */ static fct_status_t qlt_raw_mailbox_command(qlt_state_t *qlt) { int cntr = 0; uint32_t status; + fct_local_port_t *port = qlt->qlt_port; REG_WR32(qlt, REG_HCCR, HCCR_CMD(SET_HOST_TO_RISC_INTR)); + retry_raw:; while ((REG_RD32(qlt, REG_INTR_STATUS) & RISC_PCI_INTR_REQUEST) == 0) { cntr++; ! if (cntr == 3000) { ! EL(qlt, "polling exhausted, dump fw now..\n"); ! (void) qlt_firmware_dump(port, ! (stmf_state_change_info_t *)NULL); return (QLT_MAILBOX_STUCK); } delay(drv_usectohz(10000)); } status = (REG_RD32(qlt, REG_RISC_STATUS) & FW_INTR_STATUS_MASK);
*** 2442,2454 **** --- 3639,3682 ---- (status == MBX_CMD_NOT_SUCCESSFUL)) { uint16_t mbox0 = REG_RD16(qlt, REG_MBOX(0)); if (mbox0 == QLT_MBX_CMD_SUCCESS) { return (QLT_SUCCESS); } else { + EL(qlt, "mbx cmd failed, dump fw now..\n"); + (void) qlt_firmware_dump(port, + (stmf_state_change_info_t *)NULL); return (QLT_MBOX_FAILED | mbox0); } + } else if (status == ASYNC_EVENT) { + uint16_t mbox0, mbox1, mbox2, mbox3; + uint16_t mbox4, mbox5, mbox6, mbox7; + + mbox0 = REG_RD16(qlt, REG_MBOX(0)); + mbox1 = REG_RD16(qlt, REG_MBOX(1)); + mbox2 = REG_RD16(qlt, REG_MBOX(2)); + mbox3 = REG_RD16(qlt, REG_MBOX(3)); + mbox4 = REG_RD16(qlt, REG_MBOX(4)); + mbox5 = REG_RD16(qlt, REG_MBOX(5)); + mbox6 = REG_RD16(qlt, REG_MBOX(6)); + mbox7 = REG_RD16(qlt, REG_MBOX(7)); + + cmn_err(CE_NOTE, "!qlt(%d): Async event %x mb1=%x mb2=%x" + "mb3=%x mb4=%x mb5=%x mb6=%x mb7=%x", + qlt->instance, mbox0, mbox1, mbox2, mbox3, + mbox4, mbox5, mbox6, mbox7); + if (mbox0 == 0x8002) { + (void) qlt_firmware_dump(port, + (stmf_state_change_info_t *)NULL); + return (QLT_UNEXPECTED_RESPONSE); + } else { + REG_WR32(qlt, + REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); + cntr = 0; + goto retry_raw; } + } + /* This is unexpected, dump a message */ cmn_err(CE_WARN, "qlt(%d): Unexpect intr status %llx", ddi_get_instance(qlt->dip), (unsigned long long)status); return (QLT_UNEXPECTED_RESPONSE); }
*** 2499,2515 **** static fct_status_t qlt_mailbox_command(qlt_state_t *qlt, mbox_cmd_t *mcp) { int retries; int i; ! char info[QLT_INFO_LEN]; if (curthread->t_flag & T_INTR_THREAD) { ASSERT(0); return (QLT_MBOX_FAILED); } mutex_enter(&qlt->mbox_lock); /* See if mailboxes are still uninitialized */ if (qlt->mbox_io_state == MBOX_STATE_UNKNOWN) { mutex_exit(&qlt->mbox_lock); return (QLT_MBOX_NOT_INITIALIZED); --- 3727,3746 ---- static fct_status_t qlt_mailbox_command(qlt_state_t *qlt, mbox_cmd_t *mcp) { int retries; int i; ! char info[80]; if (curthread->t_flag & T_INTR_THREAD) { ASSERT(0); return (QLT_MBOX_FAILED); } + EL(qlt, "mailbox:[0]=%xh [1]=%xh\n", + mcp->to_fw[0], mcp->to_fw[1]); + mutex_enter(&qlt->mbox_lock); /* See if mailboxes are still uninitialized */ if (qlt->mbox_io_state == MBOX_STATE_UNKNOWN) { mutex_exit(&qlt->mbox_lock); return (QLT_MBOX_NOT_INITIALIZED);
*** 2539,2551 **** qlt_mbox_wait_loop:; /* Wait for mailbox command completion */ if (cv_timedwait(&qlt->mbox_cv, &qlt->mbox_lock, ddi_get_lbolt() + drv_usectohz(MBOX_TIMEOUT)) < 0) { ! (void) snprintf(info, sizeof (info), ! "qlt_mailbox_command: qlt-%p, " "cmd-0x%02X timed out", (void *)qlt, qlt->mcp->to_fw[0]); qlt->mcp = NULL; qlt->mbox_io_state = MBOX_STATE_UNKNOWN; mutex_exit(&qlt->mbox_lock); /* --- 3770,3782 ---- qlt_mbox_wait_loop:; /* Wait for mailbox command completion */ if (cv_timedwait(&qlt->mbox_cv, &qlt->mbox_lock, ddi_get_lbolt() + drv_usectohz(MBOX_TIMEOUT)) < 0) { ! (void) snprintf(info, 80, "qlt_mailbox_command: qlt-%p, " "cmd-0x%02X timed out", (void *)qlt, qlt->mcp->to_fw[0]); + info[79] = 0; qlt->mcp = NULL; qlt->mbox_io_state = MBOX_STATE_UNKNOWN; mutex_exit(&qlt->mbox_lock); /*
*** 2569,2596 **** /* MBox command completed. Clear state, retuen based on mbox 0 */ /* Mailboxes are already loaded by interrupt routine */ qlt->mbox_io_state = MBOX_STATE_READY; mutex_exit(&qlt->mbox_lock); ! if (mcp->from_fw[0] != QLT_MBX_CMD_SUCCESS) return (QLT_MBOX_FAILED | mcp->from_fw[0]); return (QLT_SUCCESS); } /* * **SHOULD ONLY BE CALLED FROM INTERRUPT CONTEXT. DO NOT CALL ELSEWHERE** */ /* ARGSUSED */ static uint_t qlt_isr(caddr_t arg, caddr_t arg2) { qlt_state_t *qlt = (qlt_state_t *)arg; uint32_t risc_status, intr_type; int i; int intr_loop_count; ! char info[QLT_INFO_LEN]; risc_status = REG_RD32(qlt, REG_RISC_STATUS); if (!mutex_tryenter(&qlt->intr_lock)) { /* * Normally we will always get this lock. If tryenter is --- 3800,4244 ---- /* MBox command completed. Clear state, retuen based on mbox 0 */ /* Mailboxes are already loaded by interrupt routine */ qlt->mbox_io_state = MBOX_STATE_READY; mutex_exit(&qlt->mbox_lock); ! if (mcp->from_fw[0] != QLT_MBX_CMD_SUCCESS) { ! EL(qlt, "fw[0] = %xh\n", mcp->from_fw[0]); ! if ((mcp->from_fw[0] != 0x4005) && ! (mcp->from_fw[1] != 0x7)) { ! (void) qlt_firmware_dump(qlt->qlt_port, ! (stmf_state_change_info_t *)NULL); ! } return (QLT_MBOX_FAILED | mcp->from_fw[0]); + } return (QLT_SUCCESS); } + clock_t qlt_next_invalid_msg = 0; + int qlt_invalid_idx_cnt = 0; + /* * **SHOULD ONLY BE CALLED FROM INTERRUPT CONTEXT. DO NOT CALL ELSEWHERE** */ /* ARGSUSED */ static uint_t + qlt_msix_resp_handler(caddr_t arg, caddr_t arg2) + { + qlt_state_t *qlt = (qlt_state_t *)arg; + uint32_t risc_status; + uint16_t qi = 0; + clock_t now; + + risc_status = REG_RD32(qlt, REG_RISC_STATUS); + if (qlt->qlt_mq_enabled) { + /* XXX: */ + /* qi = (uint16_t)((unsigned long)arg2); */ + qi = (uint16_t)(risc_status >> 16); + if (qi >= MQ_MAX_QUEUES) { + /* + * Two customers have reported panics in the call to + * mutex_enter below. Analysis showed the address passed + * in could only occur if 'qi' had a value of 0x4000. + * We'll ignore the upper bits and see if an index which + * at least within the range of possible produces some + * sane results. + */ + now = ddi_get_lbolt(); + if (now > qlt_next_invalid_msg) { + /* + * Since this issue has never been seen in the + * lab it's unknown if once this bit gets set + * does it remain until the next hardware reset? + * If so, we don't want to flood the message + * buffer or make it difficult to reboot the + * system. + */ + qlt_next_invalid_msg = now + + drv_usectohz(MICROSEC * 10); + cmn_err(CE_NOTE, "QLT: hardware reporting " + "invalid index: 0x%x", qi); + } + qi &= MQ_MAX_QUEUES_MASK; + qlt_invalid_idx_cnt++; + } + + mutex_enter(&qlt->mq_resp[qi].mq_lock); + if (!qlt->qlt_intr_enabled) { + /* + * No further interrupt since intr disabled. + */ + REG_WR32(qlt, REG_HCCR, + HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); + mutex_exit(&qlt->mq_resp[qi].mq_lock); + return (DDI_INTR_UNCLAIMED); + } + + qlt->mq_resp[qi].mq_ndx_from_fw = + (uint16_t)MQBAR_RD32(qlt, + (qi * MQBAR_REG_OFFSET) + MQBAR_RESP_IN); + + qlt_handle_resp_queue_update(qlt, qi); + mutex_exit(&qlt->mq_resp[qi].mq_lock); + } else { + mutex_enter(&qlt->intr_lock); + if (!qlt->qlt_intr_enabled) { + /* + * No further interrupt since intr disabled. + */ + REG_WR32(qlt, REG_HCCR, + HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); + mutex_exit(&qlt->intr_lock); + return (DDI_INTR_UNCLAIMED); + } + + qlt->atio_ndx_from_fw = + (uint16_t)REG_RD32(qlt, REG_ATIO_IN_PTR); + qlt_handle_atio_queue_update(qlt); + + qlt->mq_resp[qi].mq_ndx_from_fw = risc_status >> 16; + qlt_handle_resp_queue_update(qlt, qi); + mutex_exit(&qlt->intr_lock); + } + + if (risc_status & BIT_15) { + REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); + } + return (DDI_INTR_CLAIMED); + } + + + /* + * **SHOULD ONLY BE CALLED FROM INTERRUPT CONTEXT. DO NOT CALL ELSEWHERE** + */ + /* ARGSUSED */ + static uint_t + qlt_msix_default_handler(caddr_t arg, caddr_t arg2) + { + qlt_state_t *qlt = (qlt_state_t *)arg; + uint32_t risc_status, intr_type; + int i; + char info[80]; + + risc_status = REG_RD32(qlt, REG_RISC_STATUS); + if (!mutex_tryenter(&qlt->intr_lock)) { + /* + * Normally we will always get this lock. If tryenter is + * failing then it means that driver is trying to do + * some cleanup and is masking the intr but some intr + * has sneaked in between. See if our device has generated + * this intr. If so then wait a bit and return claimed. + * If not then return claimed if this is the 1st instance + * of a interrupt after driver has grabbed the lock. + */ + if ((risc_status & BIT_15) == 0) { + return (DDI_INTR_UNCLAIMED); + } else { + /* try again */ + drv_usecwait(10); + if (!mutex_tryenter(&qlt->intr_lock)) { + /* really bad! */ + return (DDI_INTR_CLAIMED); + } + } + } + if (((risc_status & BIT_15) == 0) || + (qlt->qlt_intr_enabled == 0)) { + /* + * This might be a pure coincedence that we are operating + * in a interrupt disabled mode and another device + * sharing the interrupt line has generated an interrupt + * while an interrupt from our device might be pending. Just + * ignore it and let the code handling the interrupt + * disabled mode handle it. + */ + mutex_exit(&qlt->intr_lock); + return (DDI_INTR_UNCLAIMED); + } + + /* REG_WR32(qlt, REG_INTR_CTRL, 0); */ + + /* check for risc pause - unlikely */ + if (risc_status & BIT_8) { + uint32_t hccsr; + + hccsr = REG_RD32(qlt, REG_HCCR); + EL(qlt, "Risc Pause status=%xh hccsr=%x\n", + risc_status, hccsr); + cmn_err(CE_WARN, "qlt(%d): Risc Pause %08x hccsr:%x", + qlt->instance, risc_status, hccsr); + (void) snprintf(info, 80, "Risc Pause %08x hccsr:%x", + risc_status, hccsr); + info[79] = 0; + (void) fct_port_shutdown(qlt->qlt_port, + STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET | + STMF_RFLAG_COLLECT_DEBUG_DUMP, info); + } + + /* check most likely types first */ + intr_type = risc_status & 0xff; + if (intr_type == 0x1D) { + qlt->atio_ndx_from_fw = + (uint16_t)REG_RD32(qlt, REG_ATIO_IN_PTR); + qlt_handle_atio_queue_update(qlt); + qlt->mq_resp[0].mq_ndx_from_fw = risc_status >> 16; + qlt_handle_resp_queue_update(qlt, 0); + REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); + } else if (intr_type == 0x1C) { + qlt->atio_ndx_from_fw = (uint16_t)(risc_status >> 16); + qlt_handle_atio_queue_update(qlt); + REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); + } else if (intr_type == 0x1E) { + /* 83xx */ + qlt->atio_ndx_from_fw = + (uint16_t)MQBAR_RD32(qlt, MQBAR_ATIO_IN); + qlt_handle_atio_queue_update(qlt); + REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); + } else if (intr_type == 0x13) { + uint16_t qi; + + qlt->atio_ndx_from_fw = + (uint16_t)REG_RD32(qlt, REG_ATIO_IN_PTR); + qlt_handle_atio_queue_update(qlt); + + if (qlt->qlt_mq_enabled) { + qi = (uint16_t)(risc_status >> 16); + qlt->mq_resp[qi].mq_ndx_from_fw = + (uint16_t)MQBAR_RD32(qlt, + (qi * MQBAR_REG_OFFSET) + MQBAR_RESP_IN); + /* FIX THIS to be optional */ + REG_WR32(qlt, REG_HCCR, + HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); + } else { + qi = 0; + REG_WR32(qlt, REG_HCCR, + HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); + qlt->mq_resp[qi].mq_ndx_from_fw = risc_status >> 16; + } + qlt_handle_resp_queue_update(qlt, qi); + + } else if (intr_type == 0x14) { + uint16_t qi = (uint16_t)(risc_status >> 16); + + if ((qlt->qlt_83xx_chip) || (qlt->qlt_27xx_chip)) { + qlt->atio_ndx_from_fw = + (uint16_t)MQBAR_RD32(qlt, MQBAR_ATIO_IN); + } else { + qlt->atio_ndx_from_fw = (uint16_t) + REG_RD32(qlt, REG_ATIO_IN_PTR); + } + qlt_handle_atio_queue_update(qlt); + + qlt->mq_resp[qi].mq_ndx_from_fw = + (uint16_t)MQBAR_RD32(qlt, + (qi * MQBAR_REG_OFFSET) + MQBAR_RESP_IN); + qlt_handle_resp_queue_update(qlt, qi); + + REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); + + } else if (intr_type == 0x12) { + uint16_t code, mbox1, mbox2, mbox3, mbox4, mbox5, mbox6; + + REG_WR32(qlt, REG_INTR_CTRL, 0); + + code = (uint16_t)(risc_status >> 16); + mbox1 = REG_RD16(qlt, REG_MBOX(1)); + mbox2 = REG_RD16(qlt, REG_MBOX(2)); + mbox3 = REG_RD16(qlt, REG_MBOX(3)); + mbox4 = REG_RD16(qlt, REG_MBOX(4)); + mbox5 = REG_RD16(qlt, REG_MBOX(5)); + mbox6 = REG_RD16(qlt, REG_MBOX(6)); + + REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); + EL(qlt, "Async event: %x mb1=%x mb2=%x," + " mb3=%x, mb4=%x, mb5=%x, mb6=%x", code, mbox1, mbox2, + mbox3, mbox4, mbox5, mbox6); + stmf_trace(qlt->qlt_port_alias, "Async event: %x mb1=%x mb2=%x," + " mb3=%x, mb4=%x, mb5=%x, mb6=%x", code, mbox1, mbox2, + mbox3, mbox4, mbox5, mbox6); + cmn_err(CE_NOTE, "!qlt(%d): Async event %x mb1=%x mb2=%x," + " mb3=%x, mb4=%x, mb5=%x, mb6=%x", qlt->instance, code, + mbox1, mbox2, mbox3, mbox4, mbox5, mbox6); + + if ((code == 0x8030) || (code == 0x8010) || (code == 0x8013)) { + if (qlt->qlt_link_up) { + fct_handle_event(qlt->qlt_port, + FCT_EVENT_LINK_RESET, 0, 0); + } + } else if (code == 0x8012) { + qlt->qlt_link_up = 0; + fct_handle_event(qlt->qlt_port, FCT_EVENT_LINK_DOWN, + 0, 0); + } else if (code == 0x8014) { + if (mbox1 == 0xffff) { /* global event */ + uint8_t reason_code; + + reason_code = (uint8_t)(mbox3 >> 8); + + switch (reason_code) { + case 0x1d: /* FIP Clear Virtual Link received */ + case 0x1a: /* received FLOGO */ + case 0x1c: /* FCF configuration changed */ + case 0x1e: /* FKA timeout */ + if (mbox2 == 7) { + qlt->qlt_link_up = 0; + fct_handle_event(qlt->qlt_port, + FCT_EVENT_LINK_DOWN, 0, 0); + } + break; + case 0x12: + if (mbox2 == 4) { + qlt->qlt_link_up = 1; + fct_handle_event(qlt->qlt_port, + FCT_EVENT_LINK_UP, 0, 0); + stmf_trace(qlt->qlt_port_alias, + "SNS login and SCR done"); + } + break; + case 0: + if ((mbox2 == 6) && + (!qlt->qlt_link_up)) { + qlt->qlt_link_up = 1; + fct_handle_event(qlt->qlt_port, + FCT_EVENT_LINK_UP, 0, 0); + stmf_trace(qlt->qlt_port_alias, + "Link reinitialised"); + } + break; + default: + stmf_trace(qlt->qlt_port_alias, + "AEN ignored"); + break; + } + } + } else if (code == 0x8011) { + switch (mbox1) { + case 0: qlt->link_speed = PORT_SPEED_1G; + break; + case 1: qlt->link_speed = PORT_SPEED_2G; + break; + case 3: qlt->link_speed = PORT_SPEED_4G; + break; + case 4: qlt->link_speed = PORT_SPEED_8G; + break; + case 5: qlt->link_speed = PORT_SPEED_16G; + break; + case 0x13: qlt->link_speed = PORT_SPEED_10G; + break; + default: + qlt->link_speed = PORT_SPEED_UNKNOWN; + } + qlt->qlt_link_up = 1; + fct_handle_event(qlt->qlt_port, FCT_EVENT_LINK_UP, + 0, 0); + } else if ((code == 0x8002) || (code == 0x8003) || + (code == 0x8004) || (code == 0x8005)) { + (void) snprintf(info, 80, + "Got %04x, mb1=%x mb2=%x mb5=%x mb6=%x", + code, mbox1, mbox2, mbox5, mbox6); + info[79] = 0; + (void) fct_port_shutdown(qlt->qlt_port, + STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET | + STMF_RFLAG_COLLECT_DEBUG_DUMP, info); + } else if (code == 0x800F) { + (void) snprintf(info, 80, + "Got 800F, mb1=%x mb2=%x mb3=%x", + mbox1, mbox2, mbox3); + + if (mbox1 != 1) { + /* issue "verify fw" */ + qlt_verify_fw(qlt); + } + } else if (code == 0x8101) { + (void) snprintf(info, 80, + "IDC Req Rcvd:%04x, mb1=%x mb2=%x mb3=%x", + code, mbox1, mbox2, mbox3); + info[79] = 0; + + /* check if "ACK" is required (timeout != 0) */ + if (mbox1 & 0x0f00) { + caddr_t req; + + /* + * Ack the request (queue work to do it?) + * using a mailbox iocb + * (Only Queue #0 allowed) + */ + mutex_enter(&qlt->mq_req[0].mq_lock); + req = qlt_get_req_entries(qlt, 1, 0); + if (req) { + bzero(req, IOCB_SIZE); + req[0] = 0x39; req[1] = 1; + QMEM_WR16(qlt, req+8, 0x101); + QMEM_WR16(qlt, req+10, mbox1); + QMEM_WR16(qlt, req+12, mbox2); + QMEM_WR16(qlt, req+14, mbox3); + QMEM_WR16(qlt, req+16, mbox4); + QMEM_WR16(qlt, req+18, mbox5); + QMEM_WR16(qlt, req+20, mbox6); + qlt_submit_req_entries(qlt, 1, 0); + } else { + (void) snprintf(info, 80, + "IDC ACK failed"); + info[79] = 0; + } + mutex_exit(&qlt->mq_req[0].mq_lock); + } + } else { + stmf_trace(qlt->qlt_port_alias, + "Async event: 0x%x ignored", + code); + } + REG_WR32(qlt, REG_INTR_CTRL, ENABLE_RISC_INTR); + } else if ((intr_type == 0x10) || (intr_type == 0x11)) { + /* Handle mailbox completion */ + mutex_enter(&qlt->mbox_lock); + if (qlt->mbox_io_state != MBOX_STATE_CMD_RUNNING) { + cmn_err(CE_WARN, "qlt(%d): mailbox completion received" + " when driver wasn't waiting for it %d", + qlt->instance, qlt->mbox_io_state); + } else { + for (i = 0; i < MAX_MBOXES; i++) { + if (qlt->mcp->from_fw_mask & + (((uint32_t)1) << i)) { + qlt->mcp->from_fw[i] = + REG_RD16(qlt, REG_MBOX(i)); + } + } + qlt->mbox_io_state = MBOX_STATE_CMD_DONE; + } + REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); + cv_broadcast(&qlt->mbox_cv); + mutex_exit(&qlt->mbox_lock); + } else { + cmn_err(CE_WARN, "qlt(%d): Unknown intr type 0x%x", + qlt->instance, intr_type); + stmf_trace(qlt->qlt_port_alias, + "%s: Unknown intr type 0x%x [%x]", + __func__, intr_type, risc_status); + REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); + } + + /* REG_WR32(qlt, REG_INTR_CTRL, ENABLE_RISC_INTR); */ + mutex_exit(&qlt->intr_lock); + + return (DDI_INTR_CLAIMED); + } + + /* + * **SHOULD ONLY BE CALLED FROM INTERRUPT CONTEXT. DO NOT CALL ELSEWHERE** + */ + /* ARGSUSED */ + static uint_t qlt_isr(caddr_t arg, caddr_t arg2) { qlt_state_t *qlt = (qlt_state_t *)arg; uint32_t risc_status, intr_type; int i; int intr_loop_count; ! char info[80]; risc_status = REG_RD32(qlt, REG_RISC_STATUS); if (!mutex_tryenter(&qlt->intr_lock)) { /* * Normally we will always get this lock. If tryenter is
*** 2624,2634 **** mutex_exit(&qlt->intr_lock); return (DDI_INTR_UNCLAIMED); } /* ! * XXX take care for MSI case. disable intrs * Its gonna be complicated because of the max iterations. * as hba will have posted the intr which did not go on PCI * but we did not service it either because of max iterations. * Maybe offload the intr on a different thread. */ --- 4272,4282 ---- mutex_exit(&qlt->intr_lock); return (DDI_INTR_UNCLAIMED); } /* ! * XXX take care for MSI-X case. disable intrs * Its gonna be complicated because of the max iterations. * as hba will have posted the intr which did not go on PCI * but we did not service it either because of max iterations. * Maybe offload the intr on a different thread. */
*** 2641,2674 **** /* check for risc pause */ if (risc_status & BIT_8) { EL(qlt, "Risc Pause status=%xh\n", risc_status); cmn_err(CE_WARN, "qlt(%d): Risc Pause %08x", qlt->instance, risc_status); ! (void) snprintf(info, sizeof (info), "Risc Pause %08x", ! risc_status); (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET | STMF_RFLAG_COLLECT_DEBUG_DUMP, info); } /* First check for high performance path */ intr_type = risc_status & 0xff; if (intr_type == 0x1D) { ! qlt->atio_ndx_from_fw = (uint16_t) ! REG_RD32(qlt, REG_ATIO_IN_PTR); ! REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); ! qlt->resp_ndx_from_fw = risc_status >> 16; qlt_handle_atio_queue_update(qlt); ! qlt_handle_resp_queue_update(qlt); } else if (intr_type == 0x1C) { REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); qlt->atio_ndx_from_fw = (uint16_t)(risc_status >> 16); qlt_handle_atio_queue_update(qlt); } else if (intr_type == 0x13) { REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); ! qlt->resp_ndx_from_fw = risc_status >> 16; ! qlt_handle_resp_queue_update(qlt); } else if (intr_type == 0x12) { uint16_t code = (uint16_t)(risc_status >> 16); uint16_t mbox1 = REG_RD16(qlt, REG_MBOX(1)); uint16_t mbox2 = REG_RD16(qlt, REG_MBOX(2)); uint16_t mbox3 = REG_RD16(qlt, REG_MBOX(3)); --- 4289,4375 ---- /* check for risc pause */ if (risc_status & BIT_8) { EL(qlt, "Risc Pause status=%xh\n", risc_status); cmn_err(CE_WARN, "qlt(%d): Risc Pause %08x", qlt->instance, risc_status); ! (void) snprintf(info, 80, "Risc Pause %08x", risc_status); ! info[79] = 0; (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET | STMF_RFLAG_COLLECT_DEBUG_DUMP, info); } /* First check for high performance path */ intr_type = risc_status & 0xff; if (intr_type == 0x1D) { ! ! /* process the atio queue first */ ! qlt->atio_ndx_from_fw = ! (uint16_t)REG_RD32(qlt, REG_ATIO_IN_PTR); qlt_handle_atio_queue_update(qlt); ! ! /* process the response queue next */ ! qlt->mq_resp[0].mq_ndx_from_fw = ! (uint16_t)REG_RD32(qlt, REG_RESP_IN_PTR); ! qlt_handle_resp_queue_update(qlt, 0); ! REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); ! } else if (intr_type == 0x1C) { REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); qlt->atio_ndx_from_fw = (uint16_t)(risc_status >> 16); qlt_handle_atio_queue_update(qlt); + } else if (intr_type == 0x1E) { + /* 83xx Atio Queue update */ + qlt->atio_ndx_from_fw = + (uint16_t)MQBAR_RD32(qlt, MQBAR_ATIO_IN); + qlt_handle_atio_queue_update(qlt); + REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); } else if (intr_type == 0x13) { + uint16_t qi; + + qlt->atio_ndx_from_fw = + (uint16_t)REG_RD32(qlt, REG_ATIO_IN_PTR); + qlt_handle_atio_queue_update(qlt); + + if (qlt->qlt_mq_enabled) { + qi = (uint16_t)(risc_status >> 16); + qlt->mq_resp[0].mq_ndx_from_fw = + (uint16_t)MQBAR_RD32(qlt, + (qi * MQBAR_REG_OFFSET) + MQBAR_RESP_IN); + /* FIX THIS to be optional */ + REG_WR32(qlt, REG_HCCR, + HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); + } else { + qi = 0; + REG_WR32(qlt, REG_HCCR, + HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); + qlt->mq_resp[qi].mq_ndx_from_fw = risc_status >> 16; + REG_WR32(qlt, REG_HCCR, + HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); + } + qlt_handle_resp_queue_update(qlt, qi); + + } else if (intr_type == 0x14) { + /* MQ */ + uint16_t qi = 0; + + if ((qlt->qlt_83xx_chip) || (qlt->qlt_27xx_chip)) { + qlt->atio_ndx_from_fw = + (uint16_t)MQBAR_RD32(qlt, MQBAR_ATIO_IN); + } else { + qi = (uint16_t)(risc_status >> 16); + qlt->atio_ndx_from_fw = (uint16_t) + REG_RD32(qlt, REG_ATIO_IN_PTR); + } + qlt_handle_atio_queue_update(qlt); + + qlt->mq_resp[qi].mq_ndx_from_fw = + (uint16_t)MQBAR_RD32(qlt, + (qi * MQBAR_REG_OFFSET) + MQBAR_RESP_IN); + qlt_handle_resp_queue_update(qlt, qi); REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); ! } else if (intr_type == 0x12) { uint16_t code = (uint16_t)(risc_status >> 16); uint16_t mbox1 = REG_RD16(qlt, REG_MBOX(1)); uint16_t mbox2 = REG_RD16(qlt, REG_MBOX(2)); uint16_t mbox3 = REG_RD16(qlt, REG_MBOX(3));
*** 2675,2689 **** uint16_t mbox4 = REG_RD16(qlt, REG_MBOX(4)); uint16_t mbox5 = REG_RD16(qlt, REG_MBOX(5)); uint16_t mbox6 = REG_RD16(qlt, REG_MBOX(6)); REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); ! stmf_trace(qlt->qlt_port_alias, "Async event %x mb1=%x mb2=%x," ! " mb3=%x, mb5=%x, mb6=%x", code, mbox1, mbox2, mbox3, mbox5, mbox6); ! EL(qlt, "Async event %x mb1=%x mb2=%x, mb3=%x, mb5=%x, mb6=%x", ! code, mbox1, mbox2, mbox3, mbox5, mbox6); if ((code == 0x8030) || (code == 0x8010) || (code == 0x8013)) { if (qlt->qlt_link_up) { fct_handle_event(qlt->qlt_port, FCT_EVENT_LINK_RESET, 0, 0); --- 4376,4394 ---- uint16_t mbox4 = REG_RD16(qlt, REG_MBOX(4)); uint16_t mbox5 = REG_RD16(qlt, REG_MBOX(5)); uint16_t mbox6 = REG_RD16(qlt, REG_MBOX(6)); REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); ! EL(qlt, "Async event %x mb1=%x, mb2=%x, mb3=%x, mb4=%x, " ! "mb5=%x, mb6=%x\n", code, mbox1, mbox2, mbox3, mbox4, mbox5, mbox6); ! stmf_trace(qlt->qlt_port_alias, "Async event %x mb1=%x mb2=%x," ! " mb3=%x, mb4=%x, mb5=%x, mb6=%x", code, mbox1, mbox2, ! mbox3, mbox4, mbox5, mbox6); ! cmn_err(CE_NOTE, "!qlt(%d): Async event %x mb1=%x mb2=%x," ! " mb3=%x, mb4=%x, mb5=%x, mb6=%x", qlt->instance, code, ! mbox1, mbox2, mbox3, mbox4, mbox5, mbox6); if ((code == 0x8030) || (code == 0x8010) || (code == 0x8013)) { if (qlt->qlt_link_up) { fct_handle_event(qlt->qlt_port, FCT_EVENT_LINK_RESET, 0, 0);
*** 2690,2699 **** --- 4395,4446 ---- } } else if (code == 0x8012) { qlt->qlt_link_up = 0; fct_handle_event(qlt->qlt_port, FCT_EVENT_LINK_DOWN, 0, 0); + } else if (code == 0x8014) { + if (mbox1 == 0xffff) { /* global event */ + uint8_t reason_code; + + reason_code = (uint8_t)(mbox3 >> 8); + + switch (reason_code) { + case 0x1d: /* FIP Clear Virtual Link received */ + case 0x1a: /* received FLOGO */ + case 0x1c: /* FCF configuration changed */ + case 0x1e: /* FKA timeout */ + if (mbox2 == 7) { + qlt->qlt_link_up = 0; + fct_handle_event(qlt->qlt_port, + FCT_EVENT_LINK_DOWN, 0, 0); + } + break; + case 0x12: + if (mbox2 == 4) { + qlt->qlt_link_up = 1; + fct_handle_event(qlt->qlt_port, + FCT_EVENT_LINK_UP, 0, 0); + stmf_trace(qlt->qlt_port_alias, + "SNS login and SCR done"); + } + break; + case 0: + if ((mbox2 == 6) && + (!qlt->qlt_link_up)) { + qlt->qlt_link_up = 1; + fct_handle_event(qlt->qlt_port, + FCT_EVENT_LINK_UP, 0, 0); + stmf_trace(qlt->qlt_port_alias, + "Link reinitialised"); + } + break; + default: + stmf_trace(qlt->qlt_port_alias, + "AEN ignored"); + break; + } + } } else if (code == 0x8011) { switch (mbox1) { case 0: qlt->link_speed = PORT_SPEED_1G; break; case 1: qlt->link_speed = PORT_SPEED_2G;
*** 2700,2709 **** --- 4447,4460 ---- break; case 3: qlt->link_speed = PORT_SPEED_4G; break; case 4: qlt->link_speed = PORT_SPEED_8G; break; + case 5: qlt->link_speed = PORT_SPEED_16G; + break; + case 6: qlt->link_speed = PORT_SPEED_32G; + break; case 0x13: qlt->link_speed = PORT_SPEED_10G; break; default: qlt->link_speed = PORT_SPEED_UNKNOWN; }
*** 2710,2749 **** qlt->qlt_link_up = 1; fct_handle_event(qlt->qlt_port, FCT_EVENT_LINK_UP, 0, 0); } else if ((code == 0x8002) || (code == 0x8003) || (code == 0x8004) || (code == 0x8005)) { ! (void) snprintf(info, sizeof (info), "Got %04x, mb1=%x mb2=%x mb5=%x mb6=%x", code, mbox1, mbox2, mbox5, mbox6); (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET | STMF_RFLAG_COLLECT_DEBUG_DUMP, info); } else if (code == 0x800F) { ! (void) snprintf(info, sizeof (info), "Got 800F, mb1=%x mb2=%x mb3=%x", mbox1, mbox2, mbox3); if (mbox1 != 1) { /* issue "verify fw" */ qlt_verify_fw(qlt); } } else if (code == 0x8101) { ! (void) snprintf(info, sizeof (info), "IDC Req Rcvd:%04x, mb1=%x mb2=%x mb3=%x", code, mbox1, mbox2, mbox3); /* check if "ACK" is required (timeout != 0) */ if (mbox1 & 0x0f00) { caddr_t req; /* * Ack the request (queue work to do it?) ! * using a mailbox iocb */ ! mutex_enter(&qlt->req_lock); ! req = qlt_get_req_entries(qlt, 1); if (req) { bzero(req, IOCB_SIZE); req[0] = 0x39; req[1] = 1; QMEM_WR16(qlt, req+8, 0x101); QMEM_WR16(qlt, req+10, mbox1); --- 4461,4502 ---- qlt->qlt_link_up = 1; fct_handle_event(qlt->qlt_port, FCT_EVENT_LINK_UP, 0, 0); } else if ((code == 0x8002) || (code == 0x8003) || (code == 0x8004) || (code == 0x8005)) { ! (void) snprintf(info, 80, "Got %04x, mb1=%x mb2=%x mb5=%x mb6=%x", code, mbox1, mbox2, mbox5, mbox6); + info[79] = 0; (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET | STMF_RFLAG_COLLECT_DEBUG_DUMP, info); } else if (code == 0x800F) { ! (void) snprintf(info, 80, "Got 800F, mb1=%x mb2=%x mb3=%x", mbox1, mbox2, mbox3); if (mbox1 != 1) { /* issue "verify fw" */ qlt_verify_fw(qlt); } } else if (code == 0x8101) { ! (void) snprintf(info, 80, "IDC Req Rcvd:%04x, mb1=%x mb2=%x mb3=%x", code, mbox1, mbox2, mbox3); + info[79] = 0; /* check if "ACK" is required (timeout != 0) */ if (mbox1 & 0x0f00) { caddr_t req; /* * Ack the request (queue work to do it?) ! * using a mailbox iocb (only Queue 0 allowed) */ ! mutex_enter(&qlt->mq_req[0].mq_lock); ! req = qlt_get_req_entries(qlt, 1, 0); if (req) { bzero(req, IOCB_SIZE); req[0] = 0x39; req[1] = 1; QMEM_WR16(qlt, req+8, 0x101); QMEM_WR16(qlt, req+10, mbox1);
*** 2750,2765 **** QMEM_WR16(qlt, req+12, mbox2); QMEM_WR16(qlt, req+14, mbox3); QMEM_WR16(qlt, req+16, mbox4); QMEM_WR16(qlt, req+18, mbox5); QMEM_WR16(qlt, req+20, mbox6); ! qlt_submit_req_entries(qlt, 1); } else { ! (void) snprintf(info, sizeof (info), "IDC ACK failed"); } ! mutex_exit(&qlt->req_lock); } } } else if ((intr_type == 0x10) || (intr_type == 0x11)) { /* Handle mailbox completion */ mutex_enter(&qlt->mbox_lock); --- 4503,4519 ---- QMEM_WR16(qlt, req+12, mbox2); QMEM_WR16(qlt, req+14, mbox3); QMEM_WR16(qlt, req+16, mbox4); QMEM_WR16(qlt, req+18, mbox5); QMEM_WR16(qlt, req+20, mbox6); ! qlt_submit_req_entries(qlt, 1, 0); } else { ! (void) snprintf(info, 80, "IDC ACK failed"); + info[79] = 0; } ! mutex_exit(&qlt->mq_req[0].mq_lock); } } } else if ((intr_type == 0x10) || (intr_type == 0x11)) { /* Handle mailbox completion */ mutex_enter(&qlt->mbox_lock);
*** 2781,2803 **** cv_broadcast(&qlt->mbox_cv); mutex_exit(&qlt->mbox_lock); } else { cmn_err(CE_WARN, "qlt(%d): Unknown intr type 0x%x", qlt->instance, intr_type); REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); } (void) REG_RD32(qlt, REG_HCCR); /* PCI Posting */ risc_status = REG_RD32(qlt, REG_RISC_STATUS); if ((risc_status & BIT_15) && (++intr_loop_count < QLT_MAX_ITERATIONS_PER_INTR)) { goto intr_again; } - REG_WR32(qlt, REG_INTR_CTRL, ENABLE_RISC_INTR); - mutex_exit(&qlt->intr_lock); return (DDI_INTR_CLAIMED); } /* **************** NVRAM Functions ********************** */ --- 4535,4565 ---- cv_broadcast(&qlt->mbox_cv); mutex_exit(&qlt->mbox_lock); } else { cmn_err(CE_WARN, "qlt(%d): Unknown intr type 0x%x", qlt->instance, intr_type); + stmf_trace(qlt->qlt_port_alias, + "%s: Unknown intr type 0x%x [%x]", + __func__, intr_type, risc_status); REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); } (void) REG_RD32(qlt, REG_HCCR); /* PCI Posting */ + + if ((qlt->intr_flags & QLT_INTR_MSIX) == 0) { risc_status = REG_RD32(qlt, REG_RISC_STATUS); if ((risc_status & BIT_15) && (++intr_loop_count < QLT_MAX_ITERATIONS_PER_INTR)) { goto intr_again; } REG_WR32(qlt, REG_INTR_CTRL, ENABLE_RISC_INTR); mutex_exit(&qlt->intr_lock); + } else { + mutex_exit(&qlt->intr_lock); + REG_WR32(qlt, REG_INTR_CTRL, ENABLE_RISC_INTR); + } + return (DDI_INTR_CLAIMED); } /* **************** NVRAM Functions ********************** */
*** 2839,2850 **** uint32_t val, *ptr; fct_status_t ret; qlt_nvram_t *nv; uint64_t empty_node_name = 0; ! if (qlt->qlt_81xx_chip) { addr = REG_RD32(qlt, REG_CTRL_STATUS) & BIT_12 ? QLT81_NVRAM_FUNC1_ADDR : QLT81_NVRAM_FUNC0_ADDR; } else if (qlt->qlt_25xx_chip) { addr = REG_RD32(qlt, REG_CTRL_STATUS) & FUNCTION_NUMBER ? QLT25_NVRAM_FUNC1_ADDR : QLT25_NVRAM_FUNC0_ADDR; } else { --- 4601,4632 ---- uint32_t val, *ptr; fct_status_t ret; qlt_nvram_t *nv; uint64_t empty_node_name = 0; ! if (qlt->qlt_27xx_chip) { ! int func; ! ! func = ((REG_RD32(qlt, REG_CTRL_STATUS) & 0x0000f000) >> 12); ! switch (func) { ! case 0: addr = QLT27_NVRAM_FUNC0_ADDR; break; ! case 1: addr = QLT27_NVRAM_FUNC1_ADDR; break; ! case 2: addr = QLT27_NVRAM_FUNC2_ADDR; break; ! case 3: addr = QLT27_NVRAM_FUNC3_ADDR; break; ! } ! } else if (qlt->qlt_83xx_chip) { ! if (qlt->qlt_fcoe_enabled) { addr = REG_RD32(qlt, REG_CTRL_STATUS) & BIT_12 ? + QLT83FCOE_NVRAM_FUNC1_ADDR : + QLT83FCOE_NVRAM_FUNC0_ADDR; + } else { + addr = REG_RD32(qlt, REG_CTRL_STATUS) & BIT_12 ? + QLT83FC_NVRAM_FUNC1_ADDR : + QLT83FC_NVRAM_FUNC0_ADDR; + } + } else if (qlt->qlt_81xx_chip) { + addr = REG_RD32(qlt, REG_CTRL_STATUS) & BIT_12 ? QLT81_NVRAM_FUNC1_ADDR : QLT81_NVRAM_FUNC0_ADDR; } else if (qlt->qlt_25xx_chip) { addr = REG_RD32(qlt, REG_CTRL_STATUS) & FUNCTION_NUMBER ? QLT25_NVRAM_FUNC1_ADDR : QLT25_NVRAM_FUNC0_ADDR; } else {
*** 2897,2906 **** --- 4679,4909 ---- } return (QLT_SUCCESS); } + fct_status_t + qlt_read_vpd(qlt_state_t *qlt) + { + uint32_t index, addr, chksum; + uint32_t val, *ptr; + fct_status_t ret; + + if (qlt->qlt_27xx_chip) { + int func; + + func = ((REG_RD32(qlt, REG_CTRL_STATUS) & 0x0000f000) >> 12); + switch (func) { + case 0: addr = QLT27_VPD_FUNC0_ADDR; break; + case 1: addr = QLT27_VPD_FUNC1_ADDR; break; + case 2: addr = QLT27_VPD_FUNC2_ADDR; break; + case 3: addr = QLT27_VPD_FUNC3_ADDR; break; + } + } else if (qlt->qlt_83xx_chip) { + if (qlt->qlt_fcoe_enabled) { + addr = REG_RD32(qlt, REG_CTRL_STATUS) & BIT_12 ? + QLT83FCOE_VPD_FUNC1_ADDR : + QLT83FCOE_VPD_FUNC0_ADDR; + } else { + addr = REG_RD32(qlt, REG_CTRL_STATUS) & BIT_12 ? + QLT83FC_VPD_FUNC1_ADDR : + QLT83FC_VPD_FUNC0_ADDR; + } + } else if (qlt->qlt_81xx_chip) { + addr = REG_RD32(qlt, REG_CTRL_STATUS) & BIT_12 ? + QLT81_VPD_FUNC1_ADDR : QLT81_VPD_FUNC0_ADDR; + } else if (qlt->qlt_25xx_chip) { + addr = REG_RD32(qlt, REG_CTRL_STATUS) & FUNCTION_NUMBER ? + QLT25_VPD_FUNC1_ADDR : QLT25_VPD_FUNC0_ADDR; + } else { + addr = REG_RD32(qlt, REG_CTRL_STATUS) & FUNCTION_NUMBER ? + QLT24_VPD_FUNC1_ADDR : QLT24_VPD_FUNC0_ADDR; + } + mutex_enter(&qlt_global_lock); + + /* Pause RISC. */ + REG_WR32(qlt, REG_HCCR, HCCR_CMD(SET_RISC_PAUSE)); + (void) REG_RD32(qlt, REG_HCCR); /* PCI Posting. */ + + /* Get VPD data and calculate checksum. */ + ptr = (uint32_t *)qlt->vpd; + chksum = 0; + for (index = 0; index < QL_24XX_VPD_SIZE / 4; index++) { + ret = qlt_read_flash_word(qlt, addr++, &val); + if (ret != QLT_SUCCESS) { + EL(qlt, "qlt_read_flash_word, status=%llxh\n", ret); + mutex_exit(&qlt_global_lock); + return (ret); + } + chksum += val; + *ptr = LE_32(val); + ptr++; + } + + /* Release RISC Pause */ + REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_PAUSE)); + (void) REG_RD32(qlt, REG_HCCR); /* PCI Posting. */ + + mutex_exit(&qlt_global_lock); + + return (QLT_SUCCESS); + } + + fct_status_t + qlt_read_bfe(qlt_state_t *qlt, uint32_t in_addr, uint32_t *out_addr, uint32_t i) + { + uint32_t index; + uint32_t chksum; + fct_status_t ret = QLT_SUCCESS; + uint32_t val; + uint16_t dataoffset; + uint32_t *ptr; + uint32_t addr, addr0; + uint16_t length; + + val = chksum = 0; + ptr = (uint32_t *)&qlt->rimage[i].header; + + addr = in_addr; + addr0 = addr; + + /* read rom header first */ + for (index = 0; index < sizeof (qlt_rom_header_t)/4; + index ++) { + ret = qlt_read_flash_word(qlt, addr++, &val); + if (ret != QLT_SUCCESS) { + EL(qlt, "read flash, status=%llxh\n", ret); + return (ret); + } + chksum += val; + *ptr = LE_32(val); + ptr++; + } + + /* check the signature */ + if (qlt->rimage[i].header.signature[0] != PCI_HEADER0) { + EL(qlt, "hdr[%d] sig[1] [0] (%xh) (%xh) is wrong.\n", + i, qlt->rimage[i].header.signature[1], + qlt->rimage[i].header.signature[0]); + return (QLT_SUCCESS); + } + + if ((qlt->rimage[i].header.signature[0] == PCI_HEADER0) && + (qlt->rimage[i].header.signature[1] == PCI_HEADER1)) { + /* get dataoffset */ + dataoffset = (qlt->rimage[i].header.dataoffset[1] | + qlt->rimage[i].header.dataoffset[0]); + EL(qlt, "dataoffset[0] = %xh\n", dataoffset); + + ptr = (uint32_t *)&qlt->rimage[i].data; + + /* adjust addr */ + addr = addr0 + (dataoffset/4); + for (index = 0; index < sizeof (qlt_rom_data_t)/4; + index ++) { + ret = qlt_read_flash_word(qlt, addr++, &val); + if (ret != QLT_SUCCESS) { + EL(qlt, "read flash, status=%llxh\n", ret); + return (ret); + } + chksum += val; + *ptr = LE_32(val); + ptr++; + } + + /* check signature */ + if ((qlt->rimage[i].data.signature[0] != 0x50) && + (qlt->rimage[i].data.signature[1] != 0x43) && + (qlt->rimage[i].data.signature[2] != 0x49) && + (qlt->rimage[i].data.signature[3] != 0x52)) { + EL(qlt, + "data sig[3] [2] [1] [0] (%xh)(%xh)(%xh)(%xh)\n", + qlt->rimage[i].data.signature[3], + qlt->rimage[i].data.signature[2], + qlt->rimage[i].data.signature[1], + qlt->rimage[i].data.signature[0]); + return (QLT_SUCCESS); + } + + EL(qlt, "codetype (%xh) revisionlevel[1][0] (%xh)(%xh)\n", + qlt->rimage[i].data.codetype, + qlt->rimage[i].data.revisionlevel[1], + qlt->rimage[i].data.revisionlevel[0]); + + /* check if this is the last image */ + if (qlt->rimage[i].data.indicator == PCI_IND_LAST_IMAGE) { + EL(qlt, "last image (%xh)\n", + qlt->rimage[i].data.indicator); + return (QLT_SUCCESS); + + } + + /* Get the image length and adjust the addr according */ + length = (qlt->rimage[i].data.imagelength[1] | + qlt->rimage[i].data.imagelength[0]); + + EL(qlt, "image[%d] length[1][0] (%xh) (%xh) in sectors\n", + i, length); + + /* the starting addr of the next image */ + addr = addr0 + ((length * 512)/4); + *out_addr = addr; + } + + return (QLT_SUCCESS); + } + + fct_status_t + qlt_read_rom_image(qlt_state_t *qlt) + { + uint32_t addr; + uint32_t out_addr = 0; + uint32_t count = 0; + boolean_t last_image = FALSE; + fct_status_t ret; + + if (qlt->qlt_27xx_chip) { + addr = FLASH_2700_DATA_ADDR + FLASH_2700_BOOT_CODE_ADDR; + } else if (qlt->qlt_83xx_chip) { + addr = FLASH_8300_DATA_ADDR + FLASH_8300_BOOT_CODE_ADDR; + } else if (qlt->qlt_81xx_chip) { + addr = FLASH_8100_DATA_ADDR + FLASH_8100_BOOT_CODE_ADDR; + } else if (qlt->qlt_25xx_chip) { + addr = FLASH_2500_DATA_ADDR + FLASH_2500_BOOT_CODE_ADDR; + } else { + addr = FLASH_2400_DATA_ADDR + FLASH_2400_BOOT_CODE_ADDR; + } + mutex_enter(&qlt_global_lock); + + /* Pause RISC. */ + REG_WR32(qlt, REG_HCCR, HCCR_CMD(SET_RISC_PAUSE)); + (void) REG_RD32(qlt, REG_HCCR); /* PCI Posting. */ + + do { + ret = qlt_read_bfe(qlt, addr, &out_addr, count); + if (ret != QLT_SUCCESS) { + EL(qlt, "qlt_read_bfe, status=%llxh\n", ret); + break; + } + if (qlt->rimage[count].data.indicator == + PCI_IND_LAST_IMAGE) { + last_image = TRUE; + } else { + addr = out_addr; + } + count ++; + } while ((last_image != TRUE) && (count < 6)); + + /* Release RISC Pause */ + REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_PAUSE)); + (void) REG_RD32(qlt, REG_HCCR); /* PCI Posting. */ + + mutex_exit(&qlt_global_lock); + + return (QLT_SUCCESS); + } + uint32_t qlt_sync_atio_queue(qlt_state_t *qlt) { uint32_t total_ent;
*** 2940,2955 **** ent_cnt = (uint32_t)(atio[1]); if (ent_cnt > total_ent) { break; } switch ((uint8_t)(atio[0])) { case 0x0d: /* INOT */ qlt_handle_inot(qlt, atio); break; - case 0x06: /* ATIO */ - qlt_handle_atio(qlt, atio); - break; default: EL(qlt, "atio_queue_update atio[0]=%xh\n", atio[0]); cmn_err(CE_WARN, "qlt_handle_atio_queue_update: " "atio[0] is %x, qlt-%p", atio[0], (void *)qlt); break; --- 4943,4958 ---- ent_cnt = (uint32_t)(atio[1]); if (ent_cnt > total_ent) { break; } switch ((uint8_t)(atio[0])) { + case 0x06: /* ATIO, make performance case the 1st test */ + qlt_handle_atio(qlt, atio); + break; case 0x0d: /* INOT */ qlt_handle_inot(qlt, atio); break; default: EL(qlt, "atio_queue_update atio[0]=%xh\n", atio[0]); cmn_err(CE_WARN, "qlt_handle_atio_queue_update: " "atio[0] is %x, qlt-%p", atio[0], (void *)qlt); break;
*** 2956,3015 **** } qlt->atio_ndx_to_fw = (uint16_t)( (qlt->atio_ndx_to_fw + ent_cnt) & (ATIO_QUEUE_ENTRIES - 1)); total_ent -= ent_cnt; } while (total_ent > 0); REG_WR32(qlt, REG_ATIO_OUT_PTR, qlt->atio_ndx_to_fw); } uint32_t ! qlt_sync_resp_queue(qlt_state_t *qlt) { uint32_t total_ent; ! if (qlt->resp_ndx_from_fw > qlt->resp_ndx_to_fw) { ! total_ent = qlt->resp_ndx_from_fw - qlt->resp_ndx_to_fw; ! (void) ddi_dma_sync(qlt->queue_mem_dma_handle, ! RESPONSE_QUEUE_OFFSET ! + (qlt->resp_ndx_to_fw << 6), total_ent << 6, DDI_DMA_SYNC_FORCPU); } else { ! total_ent = RESPONSE_QUEUE_ENTRIES - qlt->resp_ndx_to_fw + ! qlt->resp_ndx_from_fw; (void) ddi_dma_sync(qlt->queue_mem_dma_handle, ! RESPONSE_QUEUE_OFFSET ! + (qlt->resp_ndx_to_fw << 6), (RESPONSE_QUEUE_ENTRIES - ! qlt->resp_ndx_to_fw) << 6, DDI_DMA_SYNC_FORCPU); (void) ddi_dma_sync(qlt->queue_mem_dma_handle, RESPONSE_QUEUE_OFFSET, ! qlt->resp_ndx_from_fw << 6, DDI_DMA_SYNC_FORCPU); } return (total_ent); } void ! qlt_handle_resp_queue_update(qlt_state_t *qlt) { uint32_t total_ent; uint8_t c; ! if (qlt->resp_ndx_to_fw == qlt->resp_ndx_from_fw) return; ! total_ent = qlt_sync_resp_queue(qlt); do { ! caddr_t resp = &qlt->resp_ptr[qlt->resp_ndx_to_fw << 6]; uint32_t ent_cnt; ent_cnt = (uint32_t)(resp[0] == 0x51 ? resp[1] : 1); if (ent_cnt > total_ent) { break; } switch ((uint8_t)(resp[0])) { case 0x12: /* CTIO completion */ ! qlt_handle_ctio_completion(qlt, (uint8_t *)resp); break; case 0x0e: /* NACK */ /* Do Nothing */ break; case 0x1b: /* Verify FW */ --- 4959,5057 ---- } qlt->atio_ndx_to_fw = (uint16_t)( (qlt->atio_ndx_to_fw + ent_cnt) & (ATIO_QUEUE_ENTRIES - 1)); total_ent -= ent_cnt; } while (total_ent > 0); + + if ((qlt->qlt_83xx_chip) || (qlt->qlt_27xx_chip)) { + MQBAR_WR32(qlt, MQBAR_ATIO_OUT, qlt->atio_ndx_to_fw); + } else { REG_WR32(qlt, REG_ATIO_OUT_PTR, qlt->atio_ndx_to_fw); + } } uint32_t ! qlt_sync_resp_queue(qlt_state_t *qlt, uint16_t qi) { uint32_t total_ent; ! if (qlt->mq_resp[qi].mq_ndx_from_fw > qlt->mq_resp[qi].mq_ndx_to_fw) { ! total_ent = qlt->mq_resp[qi].mq_ndx_from_fw - ! qlt->mq_resp[qi].mq_ndx_to_fw; ! if (qi) { ! (void) ddi_dma_sync( ! qlt->mq_resp[qi].queue_mem_mq_dma_handle, ! (qlt->mq_resp[qi].mq_ndx_to_fw << 6), ! total_ent << 6, DDI_DMA_SYNC_FORCPU); } else { ! (void) ddi_dma_sync( ! qlt->queue_mem_dma_handle, ! RESPONSE_QUEUE_OFFSET + ! (qlt->mq_resp[qi].mq_ndx_to_fw << 6), ! total_ent << 6, ! DDI_DMA_SYNC_FORCPU); ! } ! } else { ! total_ent = ! (qi ? RESPONSE_QUEUE_MQ_ENTRIES : RESPONSE_QUEUE_ENTRIES) - ! qlt->mq_resp[qi].mq_ndx_to_fw + ! qlt->mq_resp[qi].mq_ndx_from_fw; ! ! if (qi) { ! ! (void) ddi_dma_sync( ! qlt->mq_resp[qi].queue_mem_mq_dma_handle, ! qlt->mq_resp[qi].mq_ndx_to_fw << 6, ! (RESPONSE_QUEUE_MQ_ENTRIES - ! qlt->mq_resp[qi].mq_ndx_to_fw) << 6, ! DDI_DMA_SYNC_FORCPU); ! (void) ddi_dma_sync( ! qlt->mq_resp[qi].queue_mem_mq_dma_handle, 0, ! qlt->mq_resp[qi].mq_ndx_from_fw << 6, ! DDI_DMA_SYNC_FORCPU); ! } else { (void) ddi_dma_sync(qlt->queue_mem_dma_handle, ! RESPONSE_QUEUE_OFFSET + ! (qlt->mq_resp[qi].mq_ndx_to_fw << 6), ! (RESPONSE_QUEUE_ENTRIES - ! qlt->mq_resp[qi].mq_ndx_to_fw) << 6, ! DDI_DMA_SYNC_FORCPU); (void) ddi_dma_sync(qlt->queue_mem_dma_handle, RESPONSE_QUEUE_OFFSET, ! qlt->mq_resp[qi].mq_ndx_from_fw << 6, ! DDI_DMA_SYNC_FORCPU); } + } + return (total_ent); } void ! qlt_handle_resp_queue_update(qlt_state_t *qlt, uint16_t qi) { uint32_t total_ent; uint8_t c; ! if (qlt->mq_resp[qi].mq_ndx_to_fw == qlt->mq_resp[qi].mq_ndx_from_fw) return; ! total_ent = qlt_sync_resp_queue(qlt, qi); do { ! uint32_t qe = qlt->mq_resp[qi].mq_ndx_to_fw; ! caddr_t resp = &qlt->mq_resp[qi].mq_ptr[qe << 6]; ! uint32_t ent_cnt; ent_cnt = (uint32_t)(resp[0] == 0x51 ? resp[1] : 1); if (ent_cnt > total_ent) { break; } switch ((uint8_t)(resp[0])) { case 0x12: /* CTIO completion */ ! qlt_handle_ctio_completion(qlt, (uint8_t *)resp, qi); break; case 0x0e: /* NACK */ /* Do Nothing */ break; case 0x1b: /* Verify FW */
*** 3016,3025 **** --- 5058,5070 ---- qlt_handle_verify_fw_completion(qlt, (uint8_t *)resp); break; case 0x29: /* CT PassThrough */ qlt_handle_ct_completion(qlt, (uint8_t *)resp); break; + case 0x32: /* Report ID */ + EL(qlt, "report Id received [type %xh]\n", resp[0]); + break; case 0x33: /* Abort IO IOCB completion */ qlt_handle_sol_abort_completion(qlt, (uint8_t *)resp); break; case 0x51: /* PUREX */ qlt_handle_purex(qlt, (uint8_t *)resp);
*** 3039,3062 **** qlt_handle_unsol_els_completion(qlt, (uint8_t *)resp); } break; case 0x54: /* ABTS received */ ! qlt_handle_rcvd_abts(qlt, (uint8_t *)resp); break; case 0x55: /* ABTS completion */ ! qlt_handle_abts_completion(qlt, (uint8_t *)resp); break; default: EL(qlt, "response entry=%xh\n", resp[0]); break; } ! qlt->resp_ndx_to_fw = (qlt->resp_ndx_to_fw + ent_cnt) & (RESPONSE_QUEUE_ENTRIES - 1); total_ent -= ent_cnt; } while (total_ent > 0); ! REG_WR32(qlt, REG_RESP_OUT_PTR, qlt->resp_ndx_to_fw); } fct_status_t qlt_portid_to_handle(qlt_state_t *qlt, uint32_t id, uint16_t cmd_handle, uint16_t *ret_handle) --- 5084,5119 ---- qlt_handle_unsol_els_completion(qlt, (uint8_t *)resp); } break; case 0x54: /* ABTS received */ ! qlt_handle_rcvd_abts(qlt, (uint8_t *)resp, qi); break; case 0x55: /* ABTS completion */ ! qlt_handle_abts_completion(qlt, (uint8_t *)resp, qi); break; default: EL(qlt, "response entry=%xh\n", resp[0]); break; } ! if (qi != 0) { ! qlt->mq_resp[qi].mq_ndx_to_fw = ! (qlt->mq_resp[qi].mq_ndx_to_fw + ent_cnt) & ! (RESPONSE_QUEUE_MQ_ENTRIES - 1); ! } else { ! qlt->mq_resp[qi].mq_ndx_to_fw = ! (qlt->mq_resp[qi].mq_ndx_to_fw + ent_cnt) & (RESPONSE_QUEUE_ENTRIES - 1); + } total_ent -= ent_cnt; } while (total_ent > 0); ! if (qlt->qlt_mq_enabled) { ! MQBAR_WR32(qlt, (qi * MQBAR_REG_OFFSET) + MQBAR_RESP_OUT, ! qlt->mq_resp[qi].mq_ndx_to_fw); ! } else { ! REG_WR32(qlt, REG_RESP_OUT_PTR, qlt->mq_resp[qi].mq_ndx_to_fw); ! } } fct_status_t qlt_portid_to_handle(qlt_state_t *qlt, uint32_t id, uint16_t cmd_handle, uint16_t *ret_handle)
*** 3079,3095 **** mcp->to_fw_mask |= BIT_9 | BIT_8; mcp->from_fw_mask |= BIT_1 | BIT_2; ret = qlt_mailbox_command(qlt, mcp); if (ret != QLT_SUCCESS) { ! EL(qlt, "qlt_mailbox_command=7Ch status=%llxh\n", ret); ! cmn_err(CE_WARN, "GET ID list failed, ret = %llx, mb0=%x, " ! "mb1=%x, mb2=%x", (long long)ret, mcp->from_fw[0], ! mcp->from_fw[1], mcp->from_fw[2]); qlt_free_mailbox_command(qlt, mcp); return (ret); } qlt_dmem_dma_sync(mcp->dbuf, DDI_DMA_SYNC_FORCPU); p = mcp->dbuf->db_sglist[0].seg_addr; for (n = 0; n < mcp->from_fw[1]; n++) { ent_id = LE_32(*((uint32_t *)p)) & 0xFFFFFF; h = (uint16_t)((uint16_t)p[4] | (((uint16_t)p[5]) << 8)); --- 5136,5156 ---- mcp->to_fw_mask |= BIT_9 | BIT_8; mcp->from_fw_mask |= BIT_1 | BIT_2; ret = qlt_mailbox_command(qlt, mcp); if (ret != QLT_SUCCESS) { ! EL(qlt, "qlt_mbox_command=7Ch status=%llxh\n", ret); ! cmn_err(CE_WARN, "qlt(%d) GET ID list failed, ret = %llx, " ! "mb0=%x, mb1=%x, mb2=%x", qlt->instance, (long long)ret, ! mcp->from_fw[0], mcp->from_fw[1], mcp->from_fw[2]); qlt_free_mailbox_command(qlt, mcp); return (ret); } + + EL(qlt, "mbx cmd=7Ch, GET_ID_LIST id=%x fw[1]=%x\n", + id, mcp->from_fw[1]); + qlt_dmem_dma_sync(mcp->dbuf, DDI_DMA_SYNC_FORCPU); p = mcp->dbuf->db_sglist[0].seg_addr; for (n = 0; n < mcp->from_fw[1]; n++) { ent_id = LE_32(*((uint32_t *)p)) & 0xFFFFFF; h = (uint16_t)((uint16_t)p[4] | (((uint16_t)p[5]) << 8));
*** 3096,3118 **** if (ent_id == id) { found = 1; *ret_handle = h; if ((cmd_handle != FCT_HANDLE_NONE) && (cmd_handle != h)) { ! cmn_err(CE_WARN, "login for portid %x came in " ! "with handle %x, while the portid was " ! "already using a different handle %x", ! id, cmd_handle, h); qlt_free_mailbox_command(qlt, mcp); return (QLT_FAILURE); } break; } if ((cmd_handle != FCT_HANDLE_NONE) && (h == cmd_handle)) { ! cmn_err(CE_WARN, "login for portid %x came in with " ! "handle %x, while the handle was already in use " ! "for portid %x", id, cmd_handle, ent_id); qlt_free_mailbox_command(qlt, mcp); return (QLT_FAILURE); } p += 8; } --- 5157,5180 ---- if (ent_id == id) { found = 1; *ret_handle = h; if ((cmd_handle != FCT_HANDLE_NONE) && (cmd_handle != h)) { ! cmn_err(CE_WARN, "qlt(%d) login for portid %x " ! "came in with handle %x, while the portid " ! "was already using a different handle %x", ! qlt->instance, id, cmd_handle, h); qlt_free_mailbox_command(qlt, mcp); return (QLT_FAILURE); } break; } if ((cmd_handle != FCT_HANDLE_NONE) && (h == cmd_handle)) { ! cmn_err(CE_WARN, "qlt(%d) login for portid %x came in " ! "with handle %x, while the handle was already in " ! "use for portid %x", ! qlt->instance, id, cmd_handle, ent_id); qlt_free_mailbox_command(qlt, mcp); return (QLT_FAILURE); } p += 8; }
*** 3189,3198 **** --- 5251,5263 ---- if (ret != FCT_SUCCESS) { EL(qlt, "qlt_fill_plogi, status=%llxh\n", ret); return (ret); } + EL(qlt, "rport id=%xh cmd_type=%xh handle=%xh(%xh)\n", + rp->rp_id, login->cmd_type, h, rp->rp_handle); + if (h == FCT_HANDLE_NONE) return (FCT_SUCCESS); if (rp->rp_handle == FCT_HANDLE_NONE) { rp->rp_handle = h;
*** 3200,3212 **** } if (rp->rp_handle == h) return (FCT_SUCCESS); ! EL(qlt, "rp_handle=%xh != h=%xh\n", rp->rp_handle, h); return (FCT_FAILURE); } /* invoked in single thread */ fct_status_t qlt_deregister_remote_port(fct_local_port_t *port, fct_remote_port_t *rp) { uint8_t *req; --- 5265,5278 ---- } if (rp->rp_handle == h) return (FCT_SUCCESS); ! EL(qlt, "failed, rp_handle=%xh != h=%xh\n", rp->rp_handle, h); return (FCT_FAILURE); } + /* invoked in single thread */ fct_status_t qlt_deregister_remote_port(fct_local_port_t *port, fct_remote_port_t *rp) { uint8_t *req;
*** 3219,3253 **** if ((qlt->qlt_state == FCT_STATE_OFFLINE) || (qlt->qlt_state == FCT_STATE_OFFLINING)) return (FCT_SUCCESS); ASSERT(qlt->rp_id_in_dereg == 0); mutex_enter(&qlt->preq_lock); req = (uint8_t *)qlt_get_preq_entries(qlt, 1); if (req == NULL) { mutex_exit(&qlt->preq_lock); return (FCT_BUSY); } bzero(req, IOCB_SIZE); req[0] = 0x52; req[1] = 1; /* QMEM_WR32(qlt, (&req[4]), 0xffffffff); */ QMEM_WR16(qlt, (&req[0xA]), rp->rp_handle); QMEM_WR16(qlt, (&req[0xC]), 0x98); /* implicit logo */ QMEM_WR32(qlt, (&req[0x10]), rp->rp_id); qlt->rp_id_in_dereg = rp->rp_id; qlt_submit_preq_entries(qlt, 1); dereg_req_timer = ddi_get_lbolt() + drv_usectohz(DEREG_RP_TIMEOUT); if (cv_timedwait(&qlt->rp_dereg_cv, ! &qlt->preq_lock, dereg_req_timer) > 0) { ret = qlt->rp_dereg_status; } else { ret = FCT_BUSY; } qlt->rp_dereg_status = 0; qlt->rp_id_in_dereg = 0; mutex_exit(&qlt->preq_lock); return (ret); } /* * Pass received ELS up to framework. --- 5285,5344 ---- if ((qlt->qlt_state == FCT_STATE_OFFLINE) || (qlt->qlt_state == FCT_STATE_OFFLINING)) return (FCT_SUCCESS); ASSERT(qlt->rp_id_in_dereg == 0); + if ((qlt->qlt_83xx_chip) || (qlt->qlt_27xx_chip)) { + mutex_enter(&qlt->mq_req[0].mq_lock); + req = (uint8_t *)qlt_get_req_entries(qlt, 1, 0); + if (req == NULL) { + EL(qlt, "req = NULL\n"); + mutex_exit(&qlt->mq_req[0].mq_lock); + return (FCT_BUSY); + } + } else { mutex_enter(&qlt->preq_lock); req = (uint8_t *)qlt_get_preq_entries(qlt, 1); if (req == NULL) { + EL(qlt, "req = NULL\n"); mutex_exit(&qlt->preq_lock); return (FCT_BUSY); } + } bzero(req, IOCB_SIZE); req[0] = 0x52; req[1] = 1; /* QMEM_WR32(qlt, (&req[4]), 0xffffffff); */ QMEM_WR16(qlt, (&req[0xA]), rp->rp_handle); QMEM_WR16(qlt, (&req[0xC]), 0x98); /* implicit logo */ QMEM_WR32(qlt, (&req[0x10]), rp->rp_id); qlt->rp_id_in_dereg = rp->rp_id; + if ((qlt->qlt_83xx_chip) || (qlt->qlt_27xx_chip)) { + qlt_submit_req_entries(qlt, 1, 0); + } else { qlt_submit_preq_entries(qlt, 1); + } dereg_req_timer = ddi_get_lbolt() + drv_usectohz(DEREG_RP_TIMEOUT); if (cv_timedwait(&qlt->rp_dereg_cv, ! (((qlt->qlt_83xx_chip) || (qlt->qlt_27xx_chip)) ? ! &qlt->mq_req[0].mq_lock : &qlt->preq_lock), ! dereg_req_timer) > 0) { ret = qlt->rp_dereg_status; } else { ret = FCT_BUSY; } qlt->rp_dereg_status = 0; qlt->rp_id_in_dereg = 0; + if ((qlt->qlt_83xx_chip) || (qlt->qlt_27xx_chip)) { + mutex_exit(&qlt->mq_req[0].mq_lock); + } else { mutex_exit(&qlt->preq_lock); + } + + EL(qlt, "Dereg remote port(%Xh), ret=%llxh\n", + rp->rp_id, ret); + return (ret); } /* * Pass received ELS up to framework.
*** 3261,3271 **** uint32_t payload_size; uint32_t remote_portid; uint8_t *pldptr, *bndrptr; int i, off; uint16_t iocb_flags; ! char info[QLT_INFO_LEN]; remote_portid = ((uint32_t)(QMEM_RD16(qlt, (&resp[0x18])))) | ((uint32_t)(resp[0x1A])) << 16; iocb_flags = QMEM_RD16(qlt, (&resp[8])); if (iocb_flags & BIT_15) { --- 5352,5362 ---- uint32_t payload_size; uint32_t remote_portid; uint8_t *pldptr, *bndrptr; int i, off; uint16_t iocb_flags; ! char info[160]; remote_portid = ((uint32_t)(QMEM_RD16(qlt, (&resp[0x18])))) | ((uint32_t)(resp[0x1A])) << 16; iocb_flags = QMEM_RD16(qlt, (&resp[8])); if (iocb_flags & BIT_15) {
*** 3283,3295 **** cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_RCVD_ELS, (int)(payload_size + GET_STRUCT_SIZE(qlt_cmd_t)), 0); if (cmd == NULL) { EL(qlt, "fct_alloc cmd==NULL\n"); cmd_null:; ! (void) snprintf(info, sizeof (info), ! "qlt_handle_purex: qlt-%p, " ! "can't allocate space for fct_cmd", (void *)qlt); (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); return; } --- 5374,5386 ---- cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_RCVD_ELS, (int)(payload_size + GET_STRUCT_SIZE(qlt_cmd_t)), 0); if (cmd == NULL) { EL(qlt, "fct_alloc cmd==NULL\n"); cmd_null:; ! (void) snprintf(info, 160, "qlt_handle_purex: qlt-%p, can't " ! "allocate space for fct_cmd", (void *)qlt); ! info[159] = 0; (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); return; }
*** 3309,3342 **** cmd->cmd_lportid = ((uint32_t)(QMEM_RD16(qlt, (&resp[0x14])))) | ((uint32_t)(resp[0x16])) << 16; cmd->cmd_oxid = QMEM_RD16(qlt, (&resp[0x26])); cmd->cmd_rxid = QMEM_RD16(qlt, (&resp[0x24])); pldptr = &resp[0x2C]; ! bndrptr = (uint8_t *)(qlt->resp_ptr + (RESPONSE_QUEUE_ENTRIES << 6)); for (i = 0, off = 0x2c; i < payload_size; i += 4) { /* Take care of fw's swapping of payload */ els->els_req_payload[i] = pldptr[3]; els->els_req_payload[i+1] = pldptr[2]; els->els_req_payload[i+2] = pldptr[1]; els->els_req_payload[i+3] = pldptr[0]; pldptr += 4; if (pldptr == bndrptr) ! pldptr = (uint8_t *)qlt->resp_ptr; off += 4; if (off >= IOCB_SIZE) { off = 4; pldptr += 4; } } fct_post_rcvd_cmd(cmd, 0); } fct_status_t qlt_send_cmd_response(fct_cmd_t *cmd, uint32_t ioflags) { qlt_state_t *qlt; ! char info[QLT_INFO_LEN]; qlt = (qlt_state_t *)cmd->cmd_port->port_fca_private; if (cmd->cmd_type == FCT_CMD_FCP_XCHG) { if (ioflags & FCT_IOF_FORCE_FCA_DONE) { --- 5400,5438 ---- cmd->cmd_lportid = ((uint32_t)(QMEM_RD16(qlt, (&resp[0x14])))) | ((uint32_t)(resp[0x16])) << 16; cmd->cmd_oxid = QMEM_RD16(qlt, (&resp[0x26])); cmd->cmd_rxid = QMEM_RD16(qlt, (&resp[0x24])); pldptr = &resp[0x2C]; ! bndrptr = (uint8_t *)(qlt->mq_resp[0].mq_ptr ! + (RESPONSE_QUEUE_ENTRIES << 6)); for (i = 0, off = 0x2c; i < payload_size; i += 4) { /* Take care of fw's swapping of payload */ els->els_req_payload[i] = pldptr[3]; els->els_req_payload[i+1] = pldptr[2]; els->els_req_payload[i+2] = pldptr[1]; els->els_req_payload[i+3] = pldptr[0]; pldptr += 4; if (pldptr == bndrptr) ! pldptr = (uint8_t *)qlt->mq_resp[0].mq_ptr; off += 4; if (off >= IOCB_SIZE) { off = 4; pldptr += 4; } } + + EL(qlt, "remote portid = %xh logi/o(%xh) to us revd rex1=%xh\n", + remote_portid, els->els_req_payload[0], qcmd->fw_xchg_addr); + fct_post_rcvd_cmd(cmd, 0); } fct_status_t qlt_send_cmd_response(fct_cmd_t *cmd, uint32_t ioflags) { qlt_state_t *qlt; ! char info[160]; qlt = (qlt_state_t *)cmd->cmd_port->port_fca_private; if (cmd->cmd_type == FCT_CMD_FCP_XCHG) { if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
*** 3366,3379 **** ASSERT(0); return (FCT_FAILURE); } fatal_panic:; ! (void) snprintf(info, sizeof (info), ! "qlt_send_cmd_response: can not handle " "FCT_IOF_FORCE_FCA_DONE for cmd %p, ioflags-%x", (void *)cmd, ioflags); (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); return (FCT_FAILURE); } --- 5462,5475 ---- ASSERT(0); return (FCT_FAILURE); } fatal_panic:; ! (void) snprintf(info, 160, "qlt_send_cmd_response: can not handle " "FCT_IOF_FORCE_FCA_DONE for cmd %p, ioflags-%x", (void *)cmd, ioflags); + info[159] = 0; (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); return (FCT_FAILURE); }
*** 3385,3395 **** --- 5481,5495 ---- qlt_state_t *qlt = (qlt_state_t *)cmd->cmd_port->port_fca_private; qlt_cmd_t *qcmd = (qlt_cmd_t *)cmd->cmd_fca_private; uint8_t *req, rcnt; uint16_t flags; uint16_t cookie_count; + uint32_t ent_cnt; + uint16_t qi; + qi = qcmd->qid; + if (dbuf->db_handle == 0) qcmd->dbuf = dbuf; flags = (uint16_t)(((uint16_t)qcmd->param.atio_byte3 & 0xf0) << 5); if (dbuf->db_flags & DB_DIRECTION_TO_RPORT) { flags = (uint16_t)(flags | 2);
*** 3409,3438 **** rcnt = qlt_get_iocb_count(cookie_count); } else { cookie_count = 1; rcnt = 1; } ! mutex_enter(&qlt->req_lock); ! req = (uint8_t *)qlt_get_req_entries(qlt, rcnt); if (req == NULL) { ! mutex_exit(&qlt->req_lock); return (FCT_BUSY); } ! bzero(req, IOCB_SIZE); /* XXX needed ? */ req[0] = 0x12; req[1] = rcnt; req[2] = dbuf->db_handle; ! QMEM_WR32(qlt, req+4, cmd->cmd_handle); ! QMEM_WR16(qlt, req+8, cmd->cmd_rp->rp_handle); ! QMEM_WR16(qlt, req+10, 60); /* 60 seconds timeout */ ! QMEM_WR16(qlt, req+12, cookie_count); ! QMEM_WR32(qlt, req+0x10, cmd->cmd_rportid); ! QMEM_WR32(qlt, req+0x14, qcmd->fw_xchg_addr); ! QMEM_WR16(qlt, req+0x1A, flags); ! QMEM_WR16(qlt, req+0x20, cmd->cmd_oxid); ! QMEM_WR32(qlt, req+0x24, dbuf->db_relative_offset); ! QMEM_WR32(qlt, req+0x2C, dbuf->db_data_size); if (dbuf->db_flags & DB_LU_DATA_BUF) { uint8_t *qptr; /* qlt continuation segs */ uint16_t cookie_resid; uint16_t cont_segs; ddi_dma_cookie_t cookie, *ckp; --- 5509,5538 ---- rcnt = qlt_get_iocb_count(cookie_count); } else { cookie_count = 1; rcnt = 1; } ! mutex_enter(&qlt->mq_req[qi].mq_lock); ! req = (uint8_t *)qlt_get_req_entries(qlt, 1, qi); if (req == NULL) { ! mutex_exit(&qlt->mq_req[qi].mq_lock); return (FCT_BUSY); } ! bzero(req, IOCB_SIZE); req[0] = 0x12; req[1] = rcnt; req[2] = dbuf->db_handle; ! QMEM_WR32_REQ(qlt, qi, req+4, cmd->cmd_handle); ! QMEM_WR16_REQ(qlt, qi, req+8, cmd->cmd_rp->rp_handle); ! QMEM_WR16_REQ(qlt, qi, req+10, 60); /* 60 seconds timeout */ ! QMEM_WR16_REQ(qlt, qi, req+12, cookie_count); ! QMEM_WR32_REQ(qlt, qi, req+0x10, cmd->cmd_rportid); ! QMEM_WR32_REQ(qlt, qi, req+0x14, qcmd->fw_xchg_addr); ! QMEM_WR16_REQ(qlt, qi, req+0x1A, flags); ! QMEM_WR16_REQ(qlt, qi, req+0x20, cmd->cmd_oxid); ! QMEM_WR32_REQ(qlt, qi, req+0x24, dbuf->db_relative_offset); ! QMEM_WR32_REQ(qlt, qi, req+0x2C, dbuf->db_data_size); if (dbuf->db_flags & DB_LU_DATA_BUF) { uint8_t *qptr; /* qlt continuation segs */ uint16_t cookie_resid; uint16_t cont_segs; ddi_dma_cookie_t cookie, *ckp;
*** 3445,3472 **** /* * Program the first segment into main record. */ if (ckp) { ASSERT(ckp->dmac_size); ! QMEM_WR64(qlt, req+0x34, ckp->dmac_laddress); ! QMEM_WR32(qlt, req+0x3c, ckp->dmac_size); } else { qlt_ddi_dma_nextcookie(dbuf, &cookie); ASSERT(cookie.dmac_size); ! QMEM_WR64(qlt, req+0x34, cookie.dmac_laddress); ! QMEM_WR32(qlt, req+0x3c, cookie.dmac_size); } cookie_resid = cookie_count-1; /* * Program remaining segments into continuation records. */ while (cookie_resid) { req += IOCB_SIZE; ! if (req >= (uint8_t *)qlt->resp_ptr) { ! req = (uint8_t *)qlt->req_ptr; } req[0] = 0x0a; req[1] = 1; req[2] = req[3] = 0; /* tidy */ qptr = &req[4]; for (cont_segs = CONT_A64_DATA_SEGMENTS; --- 5545,5576 ---- /* * Program the first segment into main record. */ if (ckp) { ASSERT(ckp->dmac_size); ! QMEM_WR64_REQ(qlt, qi, req+0x34, ckp->dmac_laddress); ! QMEM_WR32_REQ(qlt, qi, req+0x3c, ckp->dmac_size); } else { qlt_ddi_dma_nextcookie(dbuf, &cookie); ASSERT(cookie.dmac_size); ! QMEM_WR64_REQ(qlt, qi, req+0x34, cookie.dmac_laddress); ! QMEM_WR32_REQ(qlt, qi, req+0x3c, cookie.dmac_size); } cookie_resid = cookie_count-1; + ent_cnt = (qi == 0) ? REQUEST_QUEUE_ENTRIES : + REQUEST_QUEUE_MQ_ENTRIES; /* * Program remaining segments into continuation records. */ while (cookie_resid) { req += IOCB_SIZE; ! if (req >= (uint8_t *)(qlt->mq_req[qi].mq_ptr + ! (ent_cnt * IOCB_SIZE))) { ! req = (uint8_t *)(qlt->mq_req[qi].mq_ptr); } + req[0] = 0x0a; req[1] = 1; req[2] = req[3] = 0; /* tidy */ qptr = &req[4]; for (cont_segs = CONT_A64_DATA_SEGMENTS;
*** 3473,3494 **** cont_segs && cookie_resid; cont_segs--) { if (ckp) { ++ckp; /* next cookie */ ASSERT(ckp->dmac_size != 0); ! QMEM_WR64(qlt, qptr, ckp->dmac_laddress); qptr += 8; /* skip over laddress */ ! QMEM_WR32(qlt, qptr, ckp->dmac_size); qptr += 4; /* skip over size */ } else { qlt_ddi_dma_nextcookie(dbuf, &cookie); ASSERT(cookie.dmac_size != 0); ! QMEM_WR64(qlt, qptr, cookie.dmac_laddress); qptr += 8; /* skip over laddress */ ! QMEM_WR32(qlt, qptr, cookie.dmac_size); qptr += 4; /* skip over size */ } cookie_resid--; } /* --- 5577,5600 ---- cont_segs && cookie_resid; cont_segs--) { if (ckp) { ++ckp; /* next cookie */ ASSERT(ckp->dmac_size != 0); ! QMEM_WR64_REQ(qlt, qi, qptr, ckp->dmac_laddress); qptr += 8; /* skip over laddress */ ! QMEM_WR32_REQ(qlt, qi, qptr, ! ckp->dmac_size); qptr += 4; /* skip over size */ } else { qlt_ddi_dma_nextcookie(dbuf, &cookie); ASSERT(cookie.dmac_size != 0); ! QMEM_WR64_REQ(qlt, qi, qptr, cookie.dmac_laddress); qptr += 8; /* skip over laddress */ ! QMEM_WR32_REQ(qlt, qi, qptr, ! cookie.dmac_size); qptr += 4; /* skip over size */ } cookie_resid--; } /*
*** 3502,3525 **** bzero(qptr, resid); } } } else { /* Single, contiguous buffer */ ! QMEM_WR64(qlt, req+0x34, bctl->bctl_dev_addr); ! QMEM_WR32(qlt, req+0x34+8, dbuf->db_data_size); } ! qlt_submit_req_entries(qlt, rcnt); ! mutex_exit(&qlt->req_lock); return (STMF_SUCCESS); } /* * We must construct proper FCP_RSP_IU now. Here we only focus on * the handling of FCP_SNS_INFO. If there's protocol failures (FCP_RSP_INFO), ! * we could have catched them before we enter here. */ fct_status_t qlt_send_status(qlt_state_t *qlt, fct_cmd_t *cmd) { qlt_cmd_t *qcmd = (qlt_cmd_t *)cmd->cmd_fca_private; --- 5608,5631 ---- bzero(qptr, resid); } } } else { /* Single, contiguous buffer */ ! QMEM_WR64_REQ(qlt, qi, req+0x34, bctl->bctl_dev_addr); ! QMEM_WR32_REQ(qlt, qi, req+0x34+8, dbuf->db_data_size); } ! qlt_submit_req_entries(qlt, rcnt, qi); ! mutex_exit(&qlt->mq_req[qi].mq_lock); return (STMF_SUCCESS); } /* * We must construct proper FCP_RSP_IU now. Here we only focus on * the handling of FCP_SNS_INFO. If there's protocol failures (FCP_RSP_INFO), ! * we could have caught them before we enter here. */ fct_status_t qlt_send_status(qlt_state_t *qlt, fct_cmd_t *cmd) { qlt_cmd_t *qcmd = (qlt_cmd_t *)cmd->cmd_fca_private;
*** 3530,3540 **** --- 5636,5649 ---- uint8_t *psd, sensbuf[24]; /* sense data */ uint16_t flags; uint16_t scsi_status; int use_mode2; int ndx; + uint16_t qi; + qi = qcmd->qid; + /* * Enter fast channel for non check condition */ if (task->task_scsi_status != STATUS_CHECK) { /*
*** 3542,3564 **** */ flags = (uint16_t)(BIT_6 | BIT_15 | (((uint16_t)qcmd->param.atio_byte3 & 0xf0) << 5)); scsi_status = (uint16_t)task->task_scsi_status; if (task->task_status_ctrl == TASK_SCTRL_OVER) { ! scsi_status = (uint16_t)(scsi_status | BIT_10); } else if (task->task_status_ctrl == TASK_SCTRL_UNDER) { ! scsi_status = (uint16_t)(scsi_status | BIT_11); } qcmd->dbuf_rsp_iu = NULL; /* * Fillout CTIO type 7 IOCB */ ! mutex_enter(&qlt->req_lock); ! req = (uint8_t *)qlt_get_req_entries(qlt, 1); if (req == NULL) { ! mutex_exit(&qlt->req_lock); return (FCT_BUSY); } /* * Common fields --- 5651,5673 ---- */ flags = (uint16_t)(BIT_6 | BIT_15 | (((uint16_t)qcmd->param.atio_byte3 & 0xf0) << 5)); scsi_status = (uint16_t)task->task_scsi_status; if (task->task_status_ctrl == TASK_SCTRL_OVER) { ! scsi_status = (uint16_t)(scsi_status | FCP_RESID_OVER); } else if (task->task_status_ctrl == TASK_SCTRL_UNDER) { ! scsi_status = (uint16_t)(scsi_status | FCP_RESID_UNDER); } qcmd->dbuf_rsp_iu = NULL; /* * Fillout CTIO type 7 IOCB */ ! mutex_enter(&qlt->mq_req[qi].mq_lock); ! req = (uint8_t *)qlt_get_req_entries(qlt, 1, qi); if (req == NULL) { ! mutex_exit(&qlt->mq_req[qi].mq_lock); return (FCT_BUSY); } /* * Common fields
*** 3565,3592 **** */ bzero(req, IOCB_SIZE); req[0x00] = 0x12; req[0x01] = 0x1; req[0x02] = BIT_7; /* indicate if it's a pure status req */ ! QMEM_WR32(qlt, req + 0x04, cmd->cmd_handle); ! QMEM_WR16(qlt, req + 0x08, cmd->cmd_rp->rp_handle); ! QMEM_WR32(qlt, req + 0x10, cmd->cmd_rportid); ! QMEM_WR32(qlt, req + 0x14, qcmd->fw_xchg_addr); /* * Mode-specific fields */ ! QMEM_WR16(qlt, req + 0x1A, flags); ! QMEM_WR32(qlt, req + 0x1C, task->task_resid); ! QMEM_WR16(qlt, req + 0x20, cmd->cmd_oxid); ! QMEM_WR16(qlt, req + 0x22, scsi_status); /* * Trigger FW to send SCSI status out */ ! qlt_submit_req_entries(qlt, 1); ! mutex_exit(&qlt->req_lock); return (STMF_SUCCESS); } ASSERT(task->task_scsi_status == STATUS_CHECK); /* --- 5674,5710 ---- */ bzero(req, IOCB_SIZE); req[0x00] = 0x12; req[0x01] = 0x1; req[0x02] = BIT_7; /* indicate if it's a pure status req */ ! QMEM_WR32_REQ(qlt, qi, req + 0x04, cmd->cmd_handle); ! QMEM_WR16_REQ(qlt, qi, req + 0x08, cmd->cmd_rp->rp_handle); ! QMEM_WR32_REQ(qlt, qi, req + 0x10, cmd->cmd_rportid); ! QMEM_WR32_REQ(qlt, qi, req + 0x14, qcmd->fw_xchg_addr); + /* handle TMF completion - !!! Important FIX */ + if (task->task_mgmt_function) { + scsi_status = + (uint16_t)(scsi_status | FCP_RESP_LEN_VALID); + + /* no sense length, 4 bytes of resp info */ + QMEM_WR16_REQ(qlt, qi, req + 0x24, 4); + } + /* * Mode-specific fields */ ! QMEM_WR16_REQ(qlt, qi, req + 0x1A, flags); ! QMEM_WR32_REQ(qlt, qi, req + 0x1C, task->task_resid); ! QMEM_WR16_REQ(qlt, qi, req + 0x20, cmd->cmd_oxid); ! QMEM_WR16_REQ(qlt, qi, req + 0x22, scsi_status); /* * Trigger FW to send SCSI status out */ ! qlt_submit_req_entries(qlt, 1, qi); ! mutex_exit(&qlt->mq_req[qi].mq_lock); return (STMF_SUCCESS); } ASSERT(task->task_scsi_status == STATUS_CHECK); /*
*** 3679,3692 **** } /* * Fillout CTIO type 7 IOCB */ ! mutex_enter(&qlt->req_lock); ! req = (uint8_t *)qlt_get_req_entries(qlt, 1); if (req == NULL) { ! mutex_exit(&qlt->req_lock); if (use_mode2) { qlt_dmem_free(cmd->cmd_port->port_fds, qcmd->dbuf_rsp_iu); qcmd->dbuf_rsp_iu = NULL; } --- 5797,5810 ---- } /* * Fillout CTIO type 7 IOCB */ ! mutex_enter(&qlt->mq_req[qi].mq_lock); ! req = (uint8_t *)qlt_get_req_entries(qlt, 1, qi); if (req == NULL) { ! mutex_exit(&qlt->mq_req[qi].mq_lock); if (use_mode2) { qlt_dmem_free(cmd->cmd_port->port_fds, qcmd->dbuf_rsp_iu); qcmd->dbuf_rsp_iu = NULL; }
*** 3698,3732 **** */ bzero(req, IOCB_SIZE); req[0x00] = 0x12; req[0x01] = 0x1; req[0x02] = BIT_7; /* to indicate if it's a pure status req */ ! QMEM_WR32(qlt, req + 0x04, cmd->cmd_handle); ! QMEM_WR16(qlt, req + 0x08, cmd->cmd_rp->rp_handle); ! QMEM_WR16(qlt, req + 0x0A, 0); /* not timed by FW */ if (use_mode2) { ! QMEM_WR16(qlt, req+0x0C, 1); /* FCP RSP IU data field */ } ! QMEM_WR32(qlt, req + 0x10, cmd->cmd_rportid); ! QMEM_WR32(qlt, req + 0x14, qcmd->fw_xchg_addr); /* * Mode-specific fields */ if (!use_mode2) { ! QMEM_WR16(qlt, req + 0x18, task->task_sense_length); } ! QMEM_WR16(qlt, req + 0x1A, flags); ! QMEM_WR32(qlt, req + 0x1C, task->task_resid); ! QMEM_WR16(qlt, req + 0x20, cmd->cmd_oxid); if (use_mode2) { bctl = (qlt_dmem_bctl_t *)qcmd->dbuf_rsp_iu->db_port_private; ! QMEM_WR32(qlt, req + 0x2C, 24 + task->task_sense_length); ! QMEM_WR64(qlt, req + 0x34, bctl->bctl_dev_addr); ! QMEM_WR32(qlt, req + 0x3C, 24 + task->task_sense_length); } else { ! QMEM_WR16(qlt, req + 0x22, scsi_status); psd = req+0x28; /* * Data in sense buf is always big-endian, data in IOCB * should always be little-endian, so we must do swapping. --- 5816,5853 ---- */ bzero(req, IOCB_SIZE); req[0x00] = 0x12; req[0x01] = 0x1; req[0x02] = BIT_7; /* to indicate if it's a pure status req */ ! QMEM_WR32_REQ(qlt, qi, req + 0x04, cmd->cmd_handle); ! QMEM_WR16_REQ(qlt, qi, req + 0x08, cmd->cmd_rp->rp_handle); ! QMEM_WR16_REQ(qlt, qi, req + 0x0A, 0); /* not timed by FW */ if (use_mode2) { ! /* FCP RSP IU data field */ ! QMEM_WR16_REQ(qlt, qi, req+0x0C, 1); } ! QMEM_WR32_REQ(qlt, qi, req + 0x10, cmd->cmd_rportid); ! QMEM_WR32_REQ(qlt, qi, req + 0x14, qcmd->fw_xchg_addr); /* * Mode-specific fields */ if (!use_mode2) { ! QMEM_WR16_REQ(qlt, qi, req + 0x18, task->task_sense_length); } ! QMEM_WR16_REQ(qlt, qi, req + 0x1A, flags); ! QMEM_WR32_REQ(qlt, qi, req + 0x1C, task->task_resid); ! QMEM_WR16_REQ(qlt, qi, req + 0x20, cmd->cmd_oxid); if (use_mode2) { bctl = (qlt_dmem_bctl_t *)qcmd->dbuf_rsp_iu->db_port_private; ! QMEM_WR32_REQ(qlt, qi, req + 0x2C, ! 24 + task->task_sense_length); ! QMEM_WR64_REQ(qlt, qi, req + 0x34, bctl->bctl_dev_addr); ! QMEM_WR32_REQ(qlt, qi, req + 0x3C, ! 24 + task->task_sense_length); } else { ! QMEM_WR16_REQ(qlt, qi, req + 0x22, scsi_status); psd = req+0x28; /* * Data in sense buf is always big-endian, data in IOCB * should always be little-endian, so we must do swapping.
*** 3741,3752 **** } /* * Trigger FW to send SCSI status out */ ! qlt_submit_req_entries(qlt, 1); ! mutex_exit(&qlt->req_lock); return (STMF_SUCCESS); } fct_status_t --- 5862,5873 ---- } /* * Trigger FW to send SCSI status out */ ! qlt_submit_req_entries(qlt, 1, qi); ! mutex_exit(&qlt->mq_req[qi].mq_lock); return (STMF_SUCCESS); } fct_status_t
*** 3756,3765 **** --- 5877,5887 ---- fct_els_t *els = (fct_els_t *)cmd->cmd_specific; uint8_t *req, *addr; qlt_dmem_bctl_t *bctl; uint32_t minsize; uint8_t elsop, req1f; + uint16_t qi = 0; addr = els->els_resp_payload; qcmd = (qlt_cmd_t *)cmd->cmd_fca_private; minsize = els->els_resp_size;
*** 3781,3794 **** if ((elsop == ELS_OP_PRLI) || (elsop == ELS_OP_PRLO) || (elsop == ELS_OP_TPRLO) || (elsop == ELS_OP_LOGO)) { req1f = (uint8_t)(req1f | BIT_4); } ! mutex_enter(&qlt->req_lock); ! req = (uint8_t *)qlt_get_req_entries(qlt, 1); if (req == NULL) { ! mutex_exit(&qlt->req_lock); qlt_dmem_free(NULL, qcmd->dbuf); qcmd->dbuf = NULL; return (FCT_BUSY); } bzero(req, IOCB_SIZE); --- 5903,5918 ---- if ((elsop == ELS_OP_PRLI) || (elsop == ELS_OP_PRLO) || (elsop == ELS_OP_TPRLO) || (elsop == ELS_OP_LOGO)) { req1f = (uint8_t)(req1f | BIT_4); } ! mutex_enter(&qlt->mq_req[qi].mq_lock); ! req = (uint8_t *)qlt_get_req_entries(qlt, 1, qi); if (req == NULL) { ! EL(qlt, "req = NULL, %xh %xh %p %xh\n", cmd->cmd_oxid, ! cmd->cmd_rportid, cmd, qcmd->fw_xchg_addr); ! mutex_exit(&qlt->mq_req[qi].mq_lock); qlt_dmem_free(NULL, qcmd->dbuf); qcmd->dbuf = NULL; return (FCT_BUSY); } bzero(req, IOCB_SIZE);
*** 3805,3817 **** req[0x1d] = (uint8_t)((cmd->cmd_lportid >> 8) & 0xff); } QMEM_WR32(qlt, (&req[0x24]), els->els_resp_size); QMEM_WR64(qlt, (&req[0x28]), bctl->bctl_dev_addr); QMEM_WR32(qlt, (&req[0x30]), els->els_resp_size); - qlt_submit_req_entries(qlt, 1); - mutex_exit(&qlt->req_lock); return (FCT_SUCCESS); } fct_status_t qlt_send_abts_response(qlt_state_t *qlt, fct_cmd_t *cmd, int terminate) --- 5929,5945 ---- req[0x1d] = (uint8_t)((cmd->cmd_lportid >> 8) & 0xff); } QMEM_WR32(qlt, (&req[0x24]), els->els_resp_size); QMEM_WR64(qlt, (&req[0x28]), bctl->bctl_dev_addr); QMEM_WR32(qlt, (&req[0x30]), els->els_resp_size); + EL(qlt, "elsop=%xh req1f=%xh IOCB_TYPE_ELSPASS: rex1=%xh\n", + elsop, req1f, qcmd->fw_xchg_addr); + + qlt_submit_req_entries(qlt, 1, qi); + mutex_exit(&qlt->mq_req[qi].mq_lock); + return (FCT_SUCCESS); } fct_status_t qlt_send_abts_response(qlt_state_t *qlt, fct_cmd_t *cmd, int terminate)
*** 3820,3836 **** fct_rcvd_abts_t *abts = (fct_rcvd_abts_t *)cmd->cmd_specific; uint8_t *req; uint32_t lportid; uint32_t fctl; int i; qcmd = (qlt_abts_cmd_t *)cmd->cmd_fca_private; ! mutex_enter(&qlt->req_lock); ! req = (uint8_t *)qlt_get_req_entries(qlt, 1); if (req == NULL) { ! mutex_exit(&qlt->req_lock); return (FCT_BUSY); } bcopy(qcmd->buf, req, IOCB_SIZE); lportid = QMEM_RD32(qlt, req+0x14) & 0xFFFFFF; fctl = QMEM_RD32(qlt, req+0x1C); --- 5948,5983 ---- fct_rcvd_abts_t *abts = (fct_rcvd_abts_t *)cmd->cmd_specific; uint8_t *req; uint32_t lportid; uint32_t fctl; int i; + uint16_t qi; + uint32_t rex1, rex2; + uint8_t temp[64]; + qi = 0; + qcmd = (qlt_abts_cmd_t *)cmd->cmd_fca_private; ! mutex_enter(&qlt->mq_req[qi].mq_lock); ! req = (uint8_t *)qlt_get_req_entries(qlt, 1, qi); if (req == NULL) { ! bcopy(qcmd->buf, &temp, IOCB_SIZE); ! for (i = 0; i < 12; i += 4) { ! /* Take care of firmware's LE requirement */ ! temp[0x2C+i] = abts->abts_resp_payload[i+3]; ! temp[0x2C+i+1] = abts->abts_resp_payload[i+2]; ! temp[0x2C+i+2] = abts->abts_resp_payload[i+1]; ! temp[0x2C+i+3] = abts->abts_resp_payload[i]; ! } ! rex1 = QMEM_RD32(qlt, &temp[0x10]); ! rex2 = QMEM_RD32(qlt, &temp[0x3C]); ! ! EL(qlt, "req = NULL, %xh %xh %p %xh %xh\n", cmd->cmd_oxid, ! cmd->cmd_rportid, cmd, rex1, rex2); ! ! mutex_exit(&qlt->mq_req[qi].mq_lock); return (FCT_BUSY); } bcopy(qcmd->buf, req, IOCB_SIZE); lportid = QMEM_RD32(qlt, req+0x14) & 0xFFFFFF; fctl = QMEM_RD32(qlt, req+0x1C);
*** 3854,3881 **** req[0x2C+i] = abts->abts_resp_payload[i+3]; req[0x2C+i+1] = abts->abts_resp_payload[i+2]; req[0x2C+i+2] = abts->abts_resp_payload[i+1]; req[0x2C+i+3] = abts->abts_resp_payload[i]; } - qlt_submit_req_entries(qlt, 1); - mutex_exit(&qlt->req_lock); return (FCT_SUCCESS); } static void qlt_handle_inot(qlt_state_t *qlt, uint8_t *inot) { int i; uint32_t d; caddr_t req; /* Just put it on the request queue */ ! mutex_enter(&qlt->req_lock); ! req = qlt_get_req_entries(qlt, 1); if (req == NULL) { ! mutex_exit(&qlt->req_lock); ! /* XXX handle this */ return; } for (i = 0; i < 16; i++) { d = QMEM_RD32(qlt, inot); inot += 4; --- 6001,6043 ---- req[0x2C+i] = abts->abts_resp_payload[i+3]; req[0x2C+i+1] = abts->abts_resp_payload[i+2]; req[0x2C+i+2] = abts->abts_resp_payload[i+1]; req[0x2C+i+3] = abts->abts_resp_payload[i]; } + rex1 = QMEM_RD32(qlt, &req[0x10]); + rex2 = QMEM_RD32(qlt, &req[0x3C]); + + EL(qlt, "%xh %xh %d %p %xh %xh\n", + QMEM_RD16(qlt, req+0x26), QMEM_RD16(qlt, req+0x24), + terminate, cmd, rex1, rex2); + + qlt_submit_req_entries(qlt, 1, qi); + mutex_exit(&qlt->mq_req[qi].mq_lock); + return (FCT_SUCCESS); } static void qlt_handle_inot(qlt_state_t *qlt, uint8_t *inot) { int i; uint32_t d; caddr_t req; + uint16_t qi; + uint8_t *entry = inot; + + qi = 0; + /* Just put it on the request queue */ ! mutex_enter(&qlt->mq_req[qi].mq_lock); ! req = qlt_get_req_entries(qlt, 1, qi); if (req == NULL) { ! mutex_exit(&qlt->mq_req[qi].mq_lock); ! stmf_trace(qlt->qlt_port_alias, ! "qlt_handle_inot: can't get a ReqQ entry"); ! EL(qlt, "req = NULL\n"); return; } for (i = 0; i < 16; i++) { d = QMEM_RD32(qlt, inot); inot += 4;
*** 3882,3895 **** QMEM_WR32(qlt, req, d); req += 4; } req -= 64; req[0] = 0x0e; ! qlt_submit_req_entries(qlt, 1); ! mutex_exit(&qlt->req_lock); } uint8_t qlt_task_flags[] = { 1, 3, 2, 1, 4, 0, 1, 1 }; static void qlt_handle_atio(qlt_state_t *qlt, uint8_t *atio) { fct_cmd_t *cmd; --- 6044,6131 ---- QMEM_WR32(qlt, req, d); req += 4; } req -= 64; req[0] = 0x0e; ! ! QMEM_WR32(qlt, entry+0x3c, 0xdeadbeef); ! EL(qlt, "Issue inot ack\n"); ! ! qlt_submit_req_entries(qlt, 1, qi); ! mutex_exit(&qlt->mq_req[qi].mq_lock); } + static uint16_t + qlt_get_queue_id(qlt_state_t *qlt, int id) + { + uint16_t qid; + + if ((!qlt->qlt_mq_enabled) || (qlt->qlt_queue_cnt == 1)) { + return (0); + } + + mutex_enter(&qlt->qlock); + if ((id == 0) && (qlt->last_qi == 0)) { + qlt->last_qi++; + } + qid = qlt->last_qi; + qlt->last_qi++; + + if (qlt->last_qi >= qlt->qlt_queue_cnt) { + qlt->last_qi -= qlt->qlt_queue_cnt; + } + mutex_exit(&qlt->qlock); + + return (qid); + } + + static fct_status_t + qlt_verify_atio_entry(qlt_state_t *qlt, uint8_t *atio) + { + uint32_t sig; + int i; + char info[160]; + + + sig = QMEM_RD32(qlt, atio+0x3c); + for (i = 0; ((sig == 0xdeadbeef) && + (i < qlt_reprocess_attempt_cnt)); i++) { + (void) ddi_dma_sync( + qlt->queue_mem_dma_handle, + ATIO_QUEUE_OFFSET + (qlt->atio_ndx_to_fw << 6), + IOCB_SIZE, DDI_DMA_SYNC_FORCPU); + + qlt->qlt_atio_reproc_cnt++; + drv_usecwait(qlt_reprocess_delay); + sig = QMEM_RD32(qlt, atio+0x3c); + } + + if (i) { + if (i >= qlt_reprocess_attempt_cnt) { + EL(qlt, "atio entry reprocess failed, %x\n", + qlt->qlt_atio_reproc_cnt); + cmn_err(CE_WARN, "qlt%d: atio entry reprocess" + " failed %x\n", + qlt->instance, qlt->qlt_atio_reproc_cnt); + (void) snprintf(info, 160, + "qlt_handle_ctio_completion: atio entry reprocess" + " failed, %x rsp-%p", + qlt->qlt_atio_reproc_cnt, (void *)atio); + info[159] = 0; + (void) fct_port_shutdown(qlt->qlt_port, + STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET | + STMF_RFLAG_COLLECT_DEBUG_DUMP, info); + return (QLT_FAILURE); + } else { + EL(qlt, "atio entry reprocess succeeded, %x %x\n", + i, qlt->qlt_atio_reproc_cnt); + } + } + + return (QLT_SUCCESS); + } + uint8_t qlt_task_flags[] = { 1, 3, 2, 1, 4, 0, 1, 1 }; static void qlt_handle_atio(qlt_state_t *qlt, uint8_t *atio) { fct_cmd_t *cmd;
*** 3896,3907 **** scsi_task_t *task; qlt_cmd_t *qcmd; uint32_t rportid, fw_xchg_addr; uint8_t *p, *q, *req, tm; uint16_t cdb_size, flags, oxid; ! char info[QLT_INFO_LEN]; /* * If either bidirection xfer is requested of there is extended * CDB, atio[0x20 + 11] will be greater than or equal to 3. */ cdb_size = 16; --- 6132,6147 ---- scsi_task_t *task; qlt_cmd_t *qcmd; uint32_t rportid, fw_xchg_addr; uint8_t *p, *q, *req, tm; uint16_t cdb_size, flags, oxid; ! char info[160]; ! uint16_t qi; + if (qlt_verify_atio_entry(qlt, atio) != QLT_SUCCESS) + return; + /* * If either bidirection xfer is requested of there is extended * CDB, atio[0x20 + 11] will be greater than or equal to 3. */ cdb_size = 16;
*** 3950,3971 **** if (cmd == NULL) { EL(qlt, "fct_scsi_task_alloc cmd==NULL\n"); } } if (cmd == NULL) { EL(qlt, "fct_scsi_task_alloc cmd==NULL\n"); /* Abort this IO */ flags = (uint16_t)(BIT_14 | ((atio[3] & 0xF0) << 5)); ! mutex_enter(&qlt->req_lock); ! req = (uint8_t *)qlt_get_req_entries(qlt, 1); if (req == NULL) { ! mutex_exit(&qlt->req_lock); ! (void) snprintf(info, sizeof (info), "qlt_handle_atio: qlt-%p, can't " "allocate space for scsi_task", (void *)qlt); (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); return; } bzero(req, IOCB_SIZE); --- 6190,6214 ---- if (cmd == NULL) { EL(qlt, "fct_scsi_task_alloc cmd==NULL\n"); } } if (cmd == NULL) { + qi = 0; /* just use request queue 0 */ + EL(qlt, "fct_scsi_task_alloc cmd==NULL\n"); /* Abort this IO */ flags = (uint16_t)(BIT_14 | ((atio[3] & 0xF0) << 5)); ! mutex_enter(&qlt->mq_req[qi].mq_lock); ! req = (uint8_t *)qlt_get_req_entries(qlt, 1, qi); if (req == NULL) { ! mutex_exit(&qlt->mq_req[0].mq_lock); ! (void) snprintf(info, 160, "qlt_handle_atio: qlt-%p, can't " "allocate space for scsi_task", (void *)qlt); + info[159] = 0; (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); return; } bzero(req, IOCB_SIZE);
*** 3976,3995 **** QMEM_WR16(qlt, req+10, 60); QMEM_WR32(qlt, req+0x10, rportid); QMEM_WR32(qlt, req+0x14, fw_xchg_addr); QMEM_WR16(qlt, req+0x1A, flags); QMEM_WR16(qlt, req+0x20, oxid); ! qlt_submit_req_entries(qlt, 1); ! mutex_exit(&qlt->req_lock); return; } task = (scsi_task_t *)cmd->cmd_specific; qcmd = (qlt_cmd_t *)cmd->cmd_fca_private; qcmd->fw_xchg_addr = fw_xchg_addr; qcmd->param.atio_byte3 = atio[3]; cmd->cmd_oxid = oxid; cmd->cmd_rxid = (uint16_t)((((uint16_t)atio[8 + 18]) << 8) | atio[8+19]); cmd->cmd_rportid = rportid; cmd->cmd_lportid = (((uint32_t)atio[8 + 1]) << 16) | --- 6219,6333 ---- QMEM_WR16(qlt, req+10, 60); QMEM_WR32(qlt, req+0x10, rportid); QMEM_WR32(qlt, req+0x14, fw_xchg_addr); QMEM_WR16(qlt, req+0x1A, flags); QMEM_WR16(qlt, req+0x20, oxid); ! qlt_submit_req_entries(qlt, 1, qi); ! mutex_exit(&qlt->mq_req[qi].mq_lock); return; } + if (cmd == NULL) { + uint32_t res; + uint16_t scsi_status = 0; + uint16_t rphdl = 0; + qi = 0; /* always use request queue 0 */ + + rphdl = fct_get_rp_handle(qlt->qlt_port, rportid); + if ((rphdl != 0xFFFF) && + (rphdl >= qlt->qlt_port->port_max_logins)) { + rphdl = 0xFFFF; + } + + mutex_enter(&qlt->mq_req[qi].mq_lock); + req = (uint8_t *)qlt_get_req_entries(qlt, 1, qi); + if (req == NULL) { + EL(qlt, "cannot get reqq\n"); + mutex_exit(&qlt->mq_req[qi].mq_lock); + (void) snprintf(info, 160, + "qlt_handle_atio: qlt-%p, can't " + "allocate space for termi-excg", (void *)qlt); + info[159] = 0; + (void) fct_port_shutdown(qlt->qlt_port, + STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); + return; + } + + if (rphdl != 0xFFFF) { + /* Driver send scsi qfull status now */ + flags = (uint16_t)(BIT_15 | + ((uint16_t)(atio[0x3] & 0xF0) << 5)); + /* always use SCSI status mode 1 */ + flags = (uint16_t)(flags | BIT_6); + + scsi_status |= (uint16_t)(0x28); + + /* Build SCSI Status Mode 1, FCP_RSP IU 24-48 byte */ + bzero(req, IOCB_SIZE); + req[0] = 0x12; + req[1] = 0x1; + + /* allocate a special IOCB handle? or donot care */ + QMEM_WR32(qlt, req+4, 0); + QMEM_WR16(qlt, req+8, rphdl); + QMEM_WR16(qlt, req+10, 60); + QMEM_WR32(qlt, req+0x10, rportid); + QMEM_WR32(qlt, req+0x14, fw_xchg_addr); + + /* sense_length set to 0 */ + QMEM_WR16(qlt, req+0x18, 0); + + QMEM_WR16(qlt, req+0x1A, flags); + + /* Residual transfer length */ + res = QMEM_RD32(qlt, atio+0x3C); + BIG_ENDIAN_32(&res); + if (res != 0) { + scsi_status |= FCP_RESID_UNDER; + } + QMEM_WR32_REQ(qlt, qi, req + 0x1C, res); + + QMEM_WR16(qlt, req+0x20, oxid); + QMEM_WR16_REQ(qlt, qi, req + 0x22, scsi_status); + + EL(qlt, "Send qfull (%Xh) (%Xh)(%Xh)(%Xh) from port " + "(%Xh:%Xh)\n", scsi_status, fw_xchg_addr, flags, + oxid, rportid, rphdl); + } else { + /* Terminate exchange because no remote port context */ + flags = (uint16_t)(BIT_14 | ((atio[3] & 0xF0) << 5)); + + bzero(req, IOCB_SIZE); + req[0] = 0x12; + req[1] = 0x1; + + QMEM_WR32(qlt, req+4, 0); + QMEM_WR16(qlt, req+8, rphdl); + QMEM_WR16(qlt, req+10, 60); + QMEM_WR32(qlt, req+0x10, rportid); + QMEM_WR32(qlt, req+0x14, fw_xchg_addr); + QMEM_WR16(qlt, req+0x1A, flags); + QMEM_WR16(qlt, req+0x20, oxid); + + EL(qlt, "Termi excg (%Xh)(%Xh)(%Xh) from port (%Xh)\n", + fw_xchg_addr, flags, oxid, rportid); + + EL(qlt, "Termi rp_handle (%Xh)\n", rphdl); + } + + qlt_submit_req_entries(qlt, 1, qi); + mutex_exit(&qlt->mq_req[qi].mq_lock); + return; + } + + qi = qlt_get_queue_id(qlt, 0); task = (scsi_task_t *)cmd->cmd_specific; qcmd = (qlt_cmd_t *)cmd->cmd_fca_private; qcmd->fw_xchg_addr = fw_xchg_addr; qcmd->param.atio_byte3 = atio[3]; + qcmd->qid = qi; cmd->cmd_oxid = oxid; cmd->cmd_rxid = (uint16_t)((((uint16_t)atio[8 + 18]) << 8) | atio[8+19]); cmd->cmd_rportid = rportid; cmd->cmd_lportid = (((uint32_t)atio[8 + 1]) << 16) |
*** 4052,4061 **** --- 6390,6401 ---- } else { task->task_expected_xfer_length = (((uint32_t)q[0]) << 24) | (((uint32_t)q[1]) << 16) | (((uint32_t)q[2]) << 8) | q[3]; } + + QMEM_WR32(qlt, atio+0x3c, 0xdeadbeef); fct_post_rcvd_cmd(cmd, 0); } static void qlt_handle_dereg_completion(qlt_state_t *qlt, uint8_t *rsp)
*** 4067,4085 **** --- 6407,6433 ---- status = QMEM_RD16(qlt, rsp+8); portid = QMEM_RD32(qlt, rsp+0x10) & 0xffffff; subcode1 = QMEM_RD32(qlt, rsp+0x14); subcode2 = QMEM_RD32(qlt, rsp+0x18); + if ((qlt->qlt_83xx_chip) || (qlt->qlt_27xx_chip)) { + mutex_enter(&qlt->mq_req[0].mq_lock); + } else { mutex_enter(&qlt->preq_lock); + } if (portid != qlt->rp_id_in_dereg) { int instance = ddi_get_instance(qlt->dip); EL(qlt, "implicit logout reveived portid = %xh\n", portid); cmn_err(CE_WARN, "qlt(%d): implicit logout completion for 0x%x" " received when driver wasn't waiting for it", instance, portid); + if ((qlt->qlt_83xx_chip) || (qlt->qlt_27xx_chip)) { + mutex_exit(&qlt->mq_req[0].mq_lock); + } else { mutex_exit(&qlt->preq_lock); + } return; } if (status != 0) { EL(qlt, "implicit logout completed for %xh with status %xh, "
*** 4096,4138 **** } } else { qlt->rp_dereg_status = FCT_SUCCESS; } cv_signal(&qlt->rp_dereg_cv); mutex_exit(&qlt->preq_lock); } /* * Note that when an ELS is aborted, the regular or aborted completion * (if any) gets posted before the abort IOCB comes back on response queue. */ static void qlt_handle_unsol_els_completion(qlt_state_t *qlt, uint8_t *rsp) { ! char info[QLT_INFO_LEN]; fct_cmd_t *cmd; qlt_cmd_t *qcmd; uint32_t hndl; uint32_t subcode1, subcode2; uint16_t status; hndl = QMEM_RD32(qlt, rsp+4); status = QMEM_RD16(qlt, rsp+8); subcode1 = QMEM_RD32(qlt, rsp+0x24); subcode2 = QMEM_RD32(qlt, rsp+0x28); if (!CMD_HANDLE_VALID(hndl)) { EL(qlt, "handle = %xh\n", hndl); /* * This cannot happen for unsol els completion. This can * only happen when abort for an unsol els completes. * This condition indicates a firmware bug. */ ! (void) snprintf(info, sizeof (info), ! "qlt_handle_unsol_els_completion: " "Invalid handle: hndl-%x, status-%x/%x/%x, rsp-%p", hndl, status, subcode1, subcode2, (void *)rsp); (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET | STMF_RFLAG_COLLECT_DEBUG_DUMP, info); return; } --- 6444,6492 ---- } } else { qlt->rp_dereg_status = FCT_SUCCESS; } cv_signal(&qlt->rp_dereg_cv); + if ((qlt->qlt_83xx_chip) || (qlt->qlt_27xx_chip)) { + mutex_exit(&qlt->mq_req[0].mq_lock); + } else { mutex_exit(&qlt->preq_lock); + } } /* * Note that when an ELS is aborted, the regular or aborted completion * (if any) gets posted before the abort IOCB comes back on response queue. */ static void qlt_handle_unsol_els_completion(qlt_state_t *qlt, uint8_t *rsp) { ! char info[160]; fct_cmd_t *cmd; qlt_cmd_t *qcmd; uint32_t hndl; uint32_t subcode1, subcode2; uint16_t status; + uint8_t elsop; hndl = QMEM_RD32(qlt, rsp+4); status = QMEM_RD16(qlt, rsp+8); subcode1 = QMEM_RD32(qlt, rsp+0x24); subcode2 = QMEM_RD32(qlt, rsp+0x28); + elsop = rsp[0x16]; if (!CMD_HANDLE_VALID(hndl)) { EL(qlt, "handle = %xh\n", hndl); /* * This cannot happen for unsol els completion. This can * only happen when abort for an unsol els completes. * This condition indicates a firmware bug. */ ! (void) snprintf(info, 160, "qlt_handle_unsol_els_completion: " "Invalid handle: hndl-%x, status-%x/%x/%x, rsp-%p", hndl, status, subcode1, subcode2, (void *)rsp); + info[159] = 0; (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET | STMF_RFLAG_COLLECT_DEBUG_DUMP, info); return; }
*** 4153,4166 **** if (cmd == NULL) { EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", hndl); /* * Now why would this happen ??? */ ! (void) snprintf(info, sizeof (info), "qlt_handle_unsol_els_completion: can not " "get cmd, hndl-%x, status-%x, rsp-%p", hndl, status, (void *)rsp); (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); return; } --- 6507,6521 ---- if (cmd == NULL) { EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", hndl); /* * Now why would this happen ??? */ ! (void) snprintf(info, 160, "qlt_handle_unsol_els_completion: can not " "get cmd, hndl-%x, status-%x, rsp-%p", hndl, status, (void *)rsp); + info[159] = 0; (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); return; }
*** 4184,4203 **** qcmd->dbuf = NULL; } if (status == 0) { fct_send_response_done(cmd, FCT_SUCCESS, FCT_IOF_FCA_DONE); } else { fct_send_response_done(cmd, QLT_FIRMWARE_ERROR(status, subcode1, subcode2), 0); } } static void qlt_handle_unsol_els_abort_completion(qlt_state_t *qlt, uint8_t *rsp) { ! char info[QLT_INFO_LEN]; fct_cmd_t *cmd; qlt_cmd_t *qcmd; uint32_t hndl; uint32_t subcode1, subcode2; uint16_t status; --- 6539,6574 ---- qcmd->dbuf = NULL; } if (status == 0) { fct_send_response_done(cmd, FCT_SUCCESS, FCT_IOF_FCA_DONE); + + if ((elsop == ELS_OP_LOGO) && + (qlt->cur_topology == PORT_TOPOLOGY_PT_TO_PT)) { + EL(qlt, "reset link since this is LOGO and N2N\n"); + (void) snprintf(info, 80, + "qlt_handle_unsol_els_completion: qlt-%p, " + "trigger RFLAG_RESET to recover", + (void *)qlt); + + info[79] = 0; + (void) fct_port_shutdown(qlt->qlt_port, + STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, + info); + } } else { + EL(qlt, "status (0xh) sucode1=%xh subconde2=%xh\n", + status, subcode1, subcode2); fct_send_response_done(cmd, QLT_FIRMWARE_ERROR(status, subcode1, subcode2), 0); } } static void qlt_handle_unsol_els_abort_completion(qlt_state_t *qlt, uint8_t *rsp) { ! char info[160]; fct_cmd_t *cmd; qlt_cmd_t *qcmd; uint32_t hndl; uint32_t subcode1, subcode2; uint16_t status;
*** 4218,4231 **** EL(qlt, "status = %xh\n", status); /* * There could be exchange resource leakage, so * throw HBA fatal error event now */ ! (void) snprintf(info, sizeof (info), "qlt_handle_unsol_els_abort_completion: " "Invalid handle: hndl-%x, status-%x/%x/%x, rsp-%p", hndl, status, subcode1, subcode2, (void *)rsp); (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET | STMF_RFLAG_COLLECT_DEBUG_DUMP, info); return; } --- 6589,6603 ---- EL(qlt, "status = %xh\n", status); /* * There could be exchange resource leakage, so * throw HBA fatal error event now */ ! (void) snprintf(info, 160, "qlt_handle_unsol_els_abort_completion: " "Invalid handle: hndl-%x, status-%x/%x/%x, rsp-%p", hndl, status, subcode1, subcode2, (void *)rsp); + info[159] = 0; (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET | STMF_RFLAG_COLLECT_DEBUG_DUMP, info); return; }
*** 4237,4250 **** if (cmd == NULL) { EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", hndl); /* * Why would this happen ?? */ ! (void) snprintf(info, sizeof (info), "qlt_handle_unsol_els_abort_completion: can not get " "cmd, hndl-%x, status-%x, rsp-%p", hndl, status, (void *)rsp); (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); return; } --- 6609,6623 ---- if (cmd == NULL) { EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", hndl); /* * Why would this happen ?? */ ! (void) snprintf(info, 160, "qlt_handle_unsol_els_abort_completion: can not get " "cmd, hndl-%x, status-%x, rsp-%p", hndl, status, (void *)rsp); + info[159] = 0; (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); return; }
*** 4269,4279 **** } static void qlt_handle_sol_els_completion(qlt_state_t *qlt, uint8_t *rsp) { ! char info[QLT_INFO_LEN]; fct_cmd_t *cmd; fct_els_t *els; qlt_cmd_t *qcmd; uint32_t hndl; uint32_t subcode1, subcode2; --- 6642,6652 ---- } static void qlt_handle_sol_els_completion(qlt_state_t *qlt, uint8_t *rsp) { ! char info[160]; fct_cmd_t *cmd; fct_els_t *els; qlt_cmd_t *qcmd; uint32_t hndl; uint32_t subcode1, subcode2;
*** 4287,4313 **** if (!CMD_HANDLE_VALID(hndl)) { EL(qlt, "handle = %xh\n", hndl); /* * This cannot happen for sol els completion. */ ! (void) snprintf(info, sizeof (info), ! "qlt_handle_sol_els_completion: " "Invalid handle: hndl-%x, status-%x/%x/%x, rsp-%p", hndl, status, subcode1, subcode2, (void *)rsp); (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET | STMF_RFLAG_COLLECT_DEBUG_DUMP, info); return; } cmd = fct_handle_to_cmd(qlt->qlt_port, hndl); if (cmd == NULL) { EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", hndl); ! (void) snprintf(info, sizeof (info), "qlt_handle_sol_els_completion: can not " "get cmd, hndl-%x, status-%x, rsp-%p", hndl, status, (void *)rsp); (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); return; } --- 6660,6687 ---- if (!CMD_HANDLE_VALID(hndl)) { EL(qlt, "handle = %xh\n", hndl); /* * This cannot happen for sol els completion. */ ! (void) snprintf(info, 160, "qlt_handle_sol_els_completion: " "Invalid handle: hndl-%x, status-%x/%x/%x, rsp-%p", hndl, status, subcode1, subcode2, (void *)rsp); + info[159] = 0; (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET | STMF_RFLAG_COLLECT_DEBUG_DUMP, info); return; } cmd = fct_handle_to_cmd(qlt->qlt_port, hndl); if (cmd == NULL) { EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", hndl); ! (void) snprintf(info, 160, "qlt_handle_sol_els_completion: can not " "get cmd, hndl-%x, status-%x, rsp-%p", hndl, status, (void *)rsp); + info[159] = 0; (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); return; }
*** 4349,4384 **** fct_cmd_t *cmd; fct_sol_ct_t *ct; qlt_cmd_t *qcmd; uint32_t hndl; uint16_t status; ! char info[QLT_INFO_LEN]; hndl = QMEM_RD32(qlt, rsp+4); status = QMEM_RD16(qlt, rsp+8); if (!CMD_HANDLE_VALID(hndl)) { EL(qlt, "handle = %xh\n", hndl); /* * Solicited commands will always have a valid handle. */ ! (void) snprintf(info, sizeof (info), ! "qlt_handle_ct_completion: " ! "hndl-%x, status-%x, rsp-%p", hndl, status, (void *)rsp); (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET | STMF_RFLAG_COLLECT_DEBUG_DUMP, info); return; } cmd = fct_handle_to_cmd(qlt->qlt_port, hndl); if (cmd == NULL) { EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", hndl); ! (void) snprintf(info, sizeof (info), "qlt_handle_ct_completion: cannot find " "cmd, hndl-%x, status-%x, rsp-%p", hndl, status, (void *)rsp); (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); return; } --- 6723,6760 ---- fct_cmd_t *cmd; fct_sol_ct_t *ct; qlt_cmd_t *qcmd; uint32_t hndl; uint16_t status; ! char info[160]; hndl = QMEM_RD32(qlt, rsp+4); status = QMEM_RD16(qlt, rsp+8); if (!CMD_HANDLE_VALID(hndl)) { EL(qlt, "handle = %xh\n", hndl); /* * Solicited commands will always have a valid handle. */ ! (void) snprintf(info, 160, "qlt_handle_ct_completion: hndl-" ! "%x, status-%x, rsp-%p", hndl, status, (void *)rsp); ! info[159] = 0; (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET | STMF_RFLAG_COLLECT_DEBUG_DUMP, info); return; } cmd = fct_handle_to_cmd(qlt->qlt_port, hndl); + EL(qlt, "cmd=%ph hndl=%xh status=%xh\n", cmd, hndl, status); if (cmd == NULL) { EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", hndl); ! (void) snprintf(info, 160, "qlt_handle_ct_completion: cannot find " "cmd, hndl-%x, status-%x, rsp-%p", hndl, status, (void *)rsp); + info[159] = 0; (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); return; }
*** 4393,4438 **** */ return; } ASSERT(qcmd->dbuf); ! if (status == 0) { qlt_dmem_dma_sync(qcmd->dbuf, DDI_DMA_SYNC_FORKERNEL); bcopy(qcmd->dbuf->db_sglist[0].seg_addr + qcmd->param.resp_offset, ct->ct_resp_payload, ct->ct_resp_size); } qlt_dmem_free(NULL, qcmd->dbuf); qcmd->dbuf = NULL; ! if (status == 0) { fct_send_cmd_done(cmd, FCT_SUCCESS, FCT_IOF_FCA_DONE); } else { fct_send_cmd_done(cmd, QLT_FIRMWARE_ERROR(status, 0, 0), 0); } } static void ! qlt_handle_ctio_completion(qlt_state_t *qlt, uint8_t *rsp) { fct_cmd_t *cmd; scsi_task_t *task; qlt_cmd_t *qcmd; stmf_data_buf_t *dbuf; fct_status_t fc_st; uint32_t iof = 0; uint32_t hndl; uint16_t status; uint16_t flags; uint8_t abort_req; uint8_t n; ! char info[QLT_INFO_LEN]; /* XXX: Check validity of the IOCB by checking 4th byte. */ ! hndl = QMEM_RD32(qlt, rsp+4); ! status = QMEM_RD16(qlt, rsp+8); ! flags = QMEM_RD16(qlt, rsp+0x1a); n = rsp[2]; if (!CMD_HANDLE_VALID(hndl)) { EL(qlt, "handle = %xh\n", hndl); ASSERT(hndl == 0); --- 6769,6869 ---- */ return; } ASSERT(qcmd->dbuf); ! if ((status == 0) || (status == 0x15)) { qlt_dmem_dma_sync(qcmd->dbuf, DDI_DMA_SYNC_FORKERNEL); bcopy(qcmd->dbuf->db_sglist[0].seg_addr + qcmd->param.resp_offset, ct->ct_resp_payload, ct->ct_resp_size); } qlt_dmem_free(NULL, qcmd->dbuf); qcmd->dbuf = NULL; ! if ((status == 0) || (status == 0x15)) { fct_send_cmd_done(cmd, FCT_SUCCESS, FCT_IOF_FCA_DONE); } else { fct_send_cmd_done(cmd, QLT_FIRMWARE_ERROR(status, 0, 0), 0); } } + static fct_status_t + qlt_verify_resp_entry(qlt_state_t *qlt, uint8_t *rsp, uint16_t qi) + { + uint32_t sig; + int i; + char info[160]; + + sig = QMEM_RD32_RSPQ(qlt, qi, rsp+0x3c); + for (i = 0; ((sig == 0xdeadbeef) && + (i < qlt_reprocess_attempt_cnt)); i++) { + (void) ddi_dma_sync( + qlt->mq_resp[qi].queue_mem_mq_dma_handle, + (qlt->mq_resp[qi].mq_ndx_to_fw << 6), + IOCB_SIZE, DDI_DMA_SYNC_FORCPU); + + qlt->qlt_resp_reproc_cnt++; + drv_usecwait(qlt_reprocess_delay); + sig = QMEM_RD32_RSPQ(qlt, qi, rsp+0x3c); + } + + if (i) { + if (i >= qlt_reprocess_attempt_cnt) { + EL(qlt, "resp entry reprocess failed, %x\n", + qlt->qlt_resp_reproc_cnt); + cmn_err(CE_WARN, "qlt%d: resp entry reprocess" + " failed %x\n", + qlt->instance, qlt->qlt_resp_reproc_cnt); + (void) snprintf(info, 160, + "qlt_handle_ctio_completion: resp entry reprocess" + " failed, %x rsp-%p", + qlt->qlt_resp_reproc_cnt, (void *)rsp); + info[159] = 0; + (void) fct_port_shutdown(qlt->qlt_port, + STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, + info); + return (QLT_FAILURE); + } else { + EL(qlt, "resp entry reprocess succeeded, %x %x\n", + i, qlt->qlt_resp_reproc_cnt); + } + } + + return (QLT_SUCCESS); + } + static void ! qlt_handle_ctio_completion(qlt_state_t *qlt, uint8_t *rsp, uint16_t qi) { fct_cmd_t *cmd; scsi_task_t *task; qlt_cmd_t *qcmd; stmf_data_buf_t *dbuf; fct_status_t fc_st; uint32_t iof = 0; uint32_t hndl; + uint32_t rex1; + uint16_t oxid; uint16_t status; uint16_t flags; uint8_t abort_req; uint8_t n; ! char info[160]; + if (qlt_verify_resp_entry(qlt, rsp, qi) != QLT_SUCCESS) + return; + + /* write a deadbeef in the last 4 bytes of the IOCB */ + QMEM_WR32_RSPQ(qlt, qi, rsp+0x3c, 0xdeadbeef); + /* XXX: Check validity of the IOCB by checking 4th byte. */ ! hndl = QMEM_RD32_RSPQ(qlt, qi, rsp+4); ! status = QMEM_RD16_RSPQ(qlt, qi, rsp+8); ! flags = QMEM_RD16_RSPQ(qlt, qi, rsp+0x1a); ! oxid = QMEM_RD16_RSPQ(qlt, qi, rsp+0x20); ! rex1 = QMEM_RD32_RSPQ(qlt, qi, rsp+0x14); n = rsp[2]; if (!CMD_HANDLE_VALID(hndl)) { EL(qlt, "handle = %xh\n", hndl); ASSERT(hndl == 0);
*** 4442,4463 **** */ EL(qlt, "hndl-%xh, status-%xh, rsp-%p\n", hndl, status, (void *)rsp); if ((status != 1) && (status != 2)) { EL(qlt, "status = %xh\n", status); /* ! * There could be exchange resource leakage, so ! * throw HBA fatal error event now */ ! (void) snprintf(info, sizeof (info), ! "qlt_handle_ctio_completion: hndl-" ! "%x, status-%x, rsp-%p", hndl, status, (void *)rsp); (void) fct_port_shutdown(qlt->qlt_port, ! STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); } return; } if (flags & BIT_14) { abort_req = 1; --- 6873,6956 ---- */ EL(qlt, "hndl-%xh, status-%xh, rsp-%p\n", hndl, status, (void *)rsp); if ((status != 1) && (status != 2)) { EL(qlt, "status = %xh\n", status); + if (status == 0x29) { + uint8_t *req; + /* ! * The qlt port received an ATIO request from ! * remote port before it issued a plogi. ! * The qlt fw returned the CTIO completion ! * status 0x29 to inform driver to do cleanup ! * (terminate the IO exchange). The subsequent ! * ABTS from the initiator can be handled ! * cleanly. */ ! qi = 0; ! mutex_enter(&qlt->mq_req[qi].mq_lock); ! req = (uint8_t *) ! qlt_get_req_entries(qlt, 1, qi); ! ! if (req == NULL) { ! EL(qlt, "No reqq entry available to " ! "termi exchg\n"); ! mutex_exit(&qlt->mq_req[qi].mq_lock); ! ! (void) snprintf(info, 160, ! "qlt_handle_ctio_completion: no " ! "reqq entry available, status-%x," ! "rsp-%p", status, (void *)rsp); ! ! info[159] = 0; ! (void) fct_port_shutdown(qlt->qlt_port, ! STMF_RFLAG_FATAL_ERROR | ! STMF_RFLAG_RESET, ! info); + return; } + flags &= 0x1E00; + flags |= BIT_14; + + bzero(req, IOCB_SIZE); + req[0] = 0x12; + req[1] = 0x1; + + QMEM_WR32(qlt, req+4, 0); + QMEM_WR16(qlt, req+8, 0xFFFF); + QMEM_WR16(qlt, req+10, 60); + QMEM_WR32(qlt, req+0x14, rex1); + QMEM_WR16(qlt, req+0x1A, flags); + QMEM_WR16(qlt, req+0x20, oxid); + + EL(qlt, "Termi exchg (%Xh)(%Xh)(%Xh) " + "rphdl=0xFFFF\n", rex1, flags, oxid); + + qlt_submit_req_entries(qlt, 1, qi); + mutex_exit(&qlt->mq_req[qi].mq_lock); + } else { + /* + * There could be exchange resource leakage, + * so throw HBA fatal error event now + */ + (void) snprintf(info, 160, + "qlt_handle_ctio_completion: hndl-%x, " + "status-%x, rsp-%p", hndl, status, + (void *)rsp); + + info[159] = 0; + + (void) fct_port_shutdown(qlt->qlt_port, + STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, + info); + } + } + return; } if (flags & BIT_14) { abort_req = 1;
*** 4468,4483 **** } cmd = fct_handle_to_cmd(qlt->qlt_port, hndl); if (cmd == NULL) { EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", hndl); ! (void) snprintf(info, sizeof (info), "qlt_handle_ctio_completion: cannot find " "cmd, hndl-%x, status-%x, rsp-%p", hndl, status, (void *)rsp); (void) fct_port_shutdown(qlt->qlt_port, ! STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); return; } task = (scsi_task_t *)cmd->cmd_specific; --- 6961,6979 ---- } cmd = fct_handle_to_cmd(qlt->qlt_port, hndl); if (cmd == NULL) { EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", hndl); ! (void) snprintf(info, 160, "qlt_handle_ctio_completion: cannot find " "cmd, hndl-%x, status-%x, rsp-%p", hndl, status, (void *)rsp); + info[159] = 0; (void) fct_port_shutdown(qlt->qlt_port, ! /* STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); */ ! STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET | ! STMF_RFLAG_COLLECT_DEBUG_DUMP, info); return; } task = (scsi_task_t *)cmd->cmd_specific;
*** 4535,4550 **** fct_send_response_done(cmd, fc_st, iof); return; } fct_cmd_fca_aborted(cmd, fc_st, iof); } static void qlt_handle_sol_abort_completion(qlt_state_t *qlt, uint8_t *rsp) { ! char info[QLT_INFO_LEN]; fct_cmd_t *cmd; qlt_cmd_t *qcmd; uint32_t h; uint16_t status; --- 7031,7051 ---- fct_send_response_done(cmd, fc_st, iof); return; } fct_cmd_fca_aborted(cmd, fc_st, iof); + + EL(qlt, "(%d) (%p)(%xh,%xh),%x %x %x\n", + qi, cmd, cmd->cmd_oxid, cmd->cmd_rxid, + cmd->cmd_handle, qcmd->fw_xchg_addr, + fc_st); } static void qlt_handle_sol_abort_completion(qlt_state_t *qlt, uint8_t *rsp) { ! char info[80]; fct_cmd_t *cmd; qlt_cmd_t *qcmd; uint32_t h; uint16_t status;
*** 4554,4566 **** if (!CMD_HANDLE_VALID(h)) { EL(qlt, "handle = %xh\n", h); /* * Solicited commands always have a valid handle. */ ! (void) snprintf(info, sizeof (info), "qlt_handle_sol_abort_completion: hndl-" "%x, status-%x, rsp-%p", h, status, (void *)rsp); (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET | STMF_RFLAG_COLLECT_DEBUG_DUMP, info); return; } --- 7055,7068 ---- if (!CMD_HANDLE_VALID(h)) { EL(qlt, "handle = %xh\n", h); /* * Solicited commands always have a valid handle. */ ! (void) snprintf(info, 80, "qlt_handle_sol_abort_completion: hndl-" "%x, status-%x, rsp-%p", h, status, (void *)rsp); + info[79] = 0; (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET | STMF_RFLAG_COLLECT_DEBUG_DUMP, info); return; }
*** 4568,4581 **** if (cmd == NULL) { EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", h); /* * What happened to the cmd ?? */ ! (void) snprintf(info, sizeof (info), "qlt_handle_sol_abort_completion: cannot " "find cmd, hndl-%x, status-%x, rsp-%p", h, status, (void *)rsp); (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); return; } --- 7070,7084 ---- if (cmd == NULL) { EL(qlt, "fct_handle_to_cmd cmd==NULL, hndl=%xh\n", h); /* * What happened to the cmd ?? */ ! (void) snprintf(info, 80, "qlt_handle_sol_abort_completion: cannot " "find cmd, hndl-%x, status-%x, rsp-%p", h, status, (void *)rsp); + info[79] = 0; (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); return; }
*** 4586,4595 **** --- 7089,7099 ---- if (qcmd->dbuf != NULL) { qlt_dmem_free(NULL, qcmd->dbuf); qcmd->dbuf = NULL; } ASSERT(qcmd->flags & QLT_CMD_ABORTING); + EL(qlt, "status=%xh\n", status); if (status == 0) { fct_cmd_fca_aborted(cmd, FCT_ABORT_SUCCESS, FCT_IOF_FCA_DONE); } else if (status == 0x31) { fct_cmd_fca_aborted(cmd, FCT_NOT_FOUND, FCT_IOF_FCA_DONE); } else {
*** 4596,4628 **** fct_cmd_fca_aborted(cmd, QLT_FIRMWARE_ERROR(status, 0, 0), 0); } } static void ! qlt_handle_rcvd_abts(qlt_state_t *qlt, uint8_t *resp) { qlt_abts_cmd_t *qcmd; fct_cmd_t *cmd; uint32_t remote_portid; ! char info[QLT_INFO_LEN]; remote_portid = ((uint32_t)(QMEM_RD16(qlt, (&resp[0x18])))) | ((uint32_t)(resp[0x1A])) << 16; cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_RCVD_ABTS, sizeof (qlt_abts_cmd_t), 0); if (cmd == NULL) { EL(qlt, "fct_alloc cmd==NULL\n"); ! (void) snprintf(info, sizeof (info), "qlt_handle_rcvd_abts: qlt-%p, can't " "allocate space for fct_cmd", (void *)qlt); (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); return; } resp[0xC] = resp[0xD] = resp[0xE] = 0; qcmd = (qlt_abts_cmd_t *)cmd->cmd_fca_private; bcopy(resp, qcmd->buf, IOCB_SIZE); cmd->cmd_port = qlt->qlt_port; cmd->cmd_rp_handle = QMEM_RD16(qlt, resp+0xA); if (cmd->cmd_rp_handle == 0xFFFF) cmd->cmd_rp_handle = FCT_HANDLE_NONE; --- 7100,7136 ---- fct_cmd_fca_aborted(cmd, QLT_FIRMWARE_ERROR(status, 0, 0), 0); } } static void ! qlt_handle_rcvd_abts(qlt_state_t *qlt, uint8_t *resp, uint16_t qi) { qlt_abts_cmd_t *qcmd; fct_cmd_t *cmd; uint32_t remote_portid; ! uint32_t rex1; ! uint32_t rex2; ! char info[160]; remote_portid = ((uint32_t)(QMEM_RD16(qlt, (&resp[0x18])))) | ((uint32_t)(resp[0x1A])) << 16; cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_RCVD_ABTS, sizeof (qlt_abts_cmd_t), 0); if (cmd == NULL) { EL(qlt, "fct_alloc cmd==NULL\n"); ! (void) snprintf(info, 160, "qlt_handle_rcvd_abts: qlt-%p, can't " "allocate space for fct_cmd", (void *)qlt); + info[159] = 0; (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); return; } resp[0xC] = resp[0xD] = resp[0xE] = 0; qcmd = (qlt_abts_cmd_t *)cmd->cmd_fca_private; + qcmd->qid = qi; bcopy(resp, qcmd->buf, IOCB_SIZE); cmd->cmd_port = qlt->qlt_port; cmd->cmd_rp_handle = QMEM_RD16(qlt, resp+0xA); if (cmd->cmd_rp_handle == 0xFFFF) cmd->cmd_rp_handle = FCT_HANDLE_NONE;
*** 4630,4658 **** cmd->cmd_rportid = remote_portid; cmd->cmd_lportid = ((uint32_t)(QMEM_RD16(qlt, (&resp[0x14])))) | ((uint32_t)(resp[0x16])) << 16; cmd->cmd_oxid = QMEM_RD16(qlt, (&resp[0x26])); cmd->cmd_rxid = QMEM_RD16(qlt, (&resp[0x24])); fct_post_rcvd_cmd(cmd, 0); } static void ! qlt_handle_abts_completion(qlt_state_t *qlt, uint8_t *resp) { uint16_t status; ! char info[QLT_INFO_LEN]; status = QMEM_RD16(qlt, resp+8); if ((status == 0) || (status == 5)) { return; } ! EL(qlt, "status = %xh\n", status); ! (void) snprintf(info, sizeof (info), ! "ABTS completion failed %x/%x/%x resp_off %x", status, QMEM_RD32(qlt, resp+0x34), QMEM_RD32(qlt, resp+0x38), ! ((uint32_t)(qlt->resp_ndx_to_fw)) << 6); (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET | STMF_RFLAG_COLLECT_DEBUG_DUMP, info); } #ifdef DEBUG --- 7138,7182 ---- cmd->cmd_rportid = remote_portid; cmd->cmd_lportid = ((uint32_t)(QMEM_RD16(qlt, (&resp[0x14])))) | ((uint32_t)(resp[0x16])) << 16; cmd->cmd_oxid = QMEM_RD16(qlt, (&resp[0x26])); cmd->cmd_rxid = QMEM_RD16(qlt, (&resp[0x24])); + + rex1 = QMEM_RD32(qlt, resp+0x10); + rex2 = QMEM_RD32(qlt, resp+0x3C); + + EL(qlt, "(%d)(%xh %xh) (%xh)(%p) (%xh %xh) (%x)\n", + qi, cmd->cmd_oxid, cmd->cmd_rxid, remote_portid, + cmd, rex1, rex2, cmd->cmd_handle); + fct_post_rcvd_cmd(cmd, 0); } static void ! qlt_handle_abts_completion(qlt_state_t *qlt, uint8_t *resp, uint16_t qi) { uint16_t status; ! char info[80]; status = QMEM_RD16(qlt, resp+8); if ((status == 0) || (status == 5)) { + EL(qlt, "qi(%d) status =%xh,(%xh %xh)\n", + qi, status, QMEM_RD16(qlt, resp+0x26), + QMEM_RD16(qlt, resp+0x24)); return; } ! ! EL(qlt, "ABTS status=%x/%x/%x resp_off %x", ! status, QMEM_RD32(qlt, resp+0x34), ! QMEM_RD32(qlt, resp+0x38), ! ((uint32_t)(qlt->mq_resp[0].mq_ndx_to_fw)) << 6); ! ! (void) snprintf(info, 80, "ABTS completion failed %x/%x/%x resp_off %x", status, QMEM_RD32(qlt, resp+0x34), QMEM_RD32(qlt, resp+0x38), ! ((uint32_t)(qlt->mq_resp[0].mq_ndx_to_fw)) << 6); ! info[79] = 0; (void) fct_port_shutdown(qlt->qlt_port, STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET | STMF_RFLAG_COLLECT_DEBUG_DUMP, info); } #ifdef DEBUG
*** 4674,4692 **** --- 7198,7218 ---- if (atomic_dec_32_nv(&qlt_drop_abort_counter) == 1) return (FCT_SUCCESS); } #endif + EL(qlt, "cmd_type = %x\n", cmd->cmd_type); if (cmd->cmd_type == FCT_CMD_FCP_XCHG) { return (qlt_abort_unsol_scsi_cmd(qlt, cmd)); } if (flags & FCT_IOF_FORCE_FCA_DONE) { cmd->cmd_handle = 0; } if (cmd->cmd_type == FCT_CMD_RCVD_ABTS) { + /* this is retried ABTS, terminate it now */ return (qlt_send_abts_response(qlt, cmd, 1)); } if (cmd->cmd_type == FCT_CMD_RCVD_ELS) { return (qlt_abort_purex(qlt, cmd));
*** 4694,4704 **** if ((cmd->cmd_type == FCT_CMD_SOL_ELS) || (cmd->cmd_type == FCT_CMD_SOL_CT)) { return (qlt_abort_sol_cmd(qlt, cmd)); } ! EL(qlt, "cmd->cmd_type = %xh\n", cmd->cmd_type); ASSERT(0); return (FCT_FAILURE); } --- 7220,7230 ---- if ((cmd->cmd_type == FCT_CMD_SOL_ELS) || (cmd->cmd_type == FCT_CMD_SOL_CT)) { return (qlt_abort_sol_cmd(qlt, cmd)); } ! EL(qlt, "cmd->cmd_type = %x\n", cmd->cmd_type); ASSERT(0); return (FCT_FAILURE); }
*** 4705,4723 **** fct_status_t qlt_abort_sol_cmd(qlt_state_t *qlt, fct_cmd_t *cmd) { uint8_t *req; qlt_cmd_t *qcmd; qcmd = (qlt_cmd_t *)cmd->cmd_fca_private; qcmd->flags = (uint16_t)(qcmd->flags | QLT_CMD_ABORTING); ! EL(qlt, "fctcmd-%p, cmd_handle-%xh\n", cmd, cmd->cmd_handle); ! mutex_enter(&qlt->req_lock); ! req = (uint8_t *)qlt_get_req_entries(qlt, 1); if (req == NULL) { ! mutex_exit(&qlt->req_lock); return (FCT_BUSY); } bzero(req, IOCB_SIZE); req[0] = 0x33; req[1] = 1; --- 7231,7254 ---- fct_status_t qlt_abort_sol_cmd(qlt_state_t *qlt, fct_cmd_t *cmd) { uint8_t *req; qlt_cmd_t *qcmd; + uint16_t qi; qcmd = (qlt_cmd_t *)cmd->cmd_fca_private; qcmd->flags = (uint16_t)(qcmd->flags | QLT_CMD_ABORTING); ! qi = qcmd->qid; ! EL(qlt, "fctcmd-%p, cmd_handle-%xh rportid=%xh\n", ! cmd, cmd->cmd_handle, cmd->cmd_rportid); ! ! mutex_enter(&qlt->mq_req[qi].mq_lock); ! req = (uint8_t *)qlt_get_req_entries(qlt, 1, qi); if (req == NULL) { ! EL(qlt, "req == NULL\n"); ! mutex_exit(&qlt->mq_req[qi].mq_lock); return (FCT_BUSY); } bzero(req, IOCB_SIZE); req[0] = 0x33; req[1] = 1;
*** 4728,4739 **** QMEM_WR16(qlt, req+8, 0xFFFF); } QMEM_WR32(qlt, req+0xc, cmd->cmd_handle); QMEM_WR32(qlt, req+0x30, cmd->cmd_rportid); ! qlt_submit_req_entries(qlt, 1); ! mutex_exit(&qlt->req_lock); return (FCT_SUCCESS); } fct_status_t --- 7259,7270 ---- QMEM_WR16(qlt, req+8, 0xFFFF); } QMEM_WR32(qlt, req+0xc, cmd->cmd_handle); QMEM_WR32(qlt, req+0x30, cmd->cmd_rportid); ! qlt_submit_req_entries(qlt, 1, qi); ! mutex_exit(&qlt->mq_req[qi].mq_lock); return (FCT_SUCCESS); } fct_status_t
*** 4741,4767 **** { uint8_t *req; qlt_cmd_t *qcmd; fct_els_t *els; uint8_t elsop, req1f; els = (fct_els_t *)cmd->cmd_specific; qcmd = (qlt_cmd_t *)cmd->cmd_fca_private; elsop = els->els_req_payload[0]; ! EL(qlt, "fctcmd-%p, cmd_handle-%xh, elsop-%xh\n", cmd, cmd->cmd_handle, ! elsop); req1f = 0x60; /* Terminate xchg */ if ((elsop == ELS_OP_PRLI) || (elsop == ELS_OP_PRLO) || (elsop == ELS_OP_TPRLO) || (elsop == ELS_OP_LOGO)) { req1f = (uint8_t)(req1f | BIT_4); } ! mutex_enter(&qlt->req_lock); ! req = (uint8_t *)qlt_get_req_entries(qlt, 1); if (req == NULL) { ! mutex_exit(&qlt->req_lock); ! return (FCT_BUSY); } qcmd->flags = (uint16_t)(qcmd->flags | QLT_CMD_ABORTING); bzero(req, IOCB_SIZE); --- 7272,7300 ---- { uint8_t *req; qlt_cmd_t *qcmd; fct_els_t *els; uint8_t elsop, req1f; + uint16_t qi; els = (fct_els_t *)cmd->cmd_specific; qcmd = (qlt_cmd_t *)cmd->cmd_fca_private; + qi = qcmd->qid; elsop = els->els_req_payload[0]; ! EL(qlt, "fctcmd-%p, cmd_handle-%xh, elsop-%xh\n", cmd, ! cmd->cmd_handle, elsop); req1f = 0x60; /* Terminate xchg */ if ((elsop == ELS_OP_PRLI) || (elsop == ELS_OP_PRLO) || (elsop == ELS_OP_TPRLO) || (elsop == ELS_OP_LOGO)) { req1f = (uint8_t)(req1f | BIT_4); } ! mutex_enter(&qlt->mq_req[qi].mq_lock); ! req = (uint8_t *)qlt_get_req_entries(qlt, 1, qi); if (req == NULL) { ! EL(qlt, "req == NULL\n"); ! mutex_exit(&qlt->mq_req[qi].mq_lock); return (FCT_BUSY); } qcmd->flags = (uint16_t)(qcmd->flags | QLT_CMD_ABORTING); bzero(req, IOCB_SIZE);
*** 4776,4787 **** EL(qlt, "cmd_rp_handle-%x\n", cmd->cmd_rp_handle); } QMEM_WR32(qlt, (&req[0x10]), qcmd->fw_xchg_addr); QMEM_WR32(qlt, (&req[0x18]), cmd->cmd_rportid); ! qlt_submit_req_entries(qlt, 1); ! mutex_exit(&qlt->req_lock); return (FCT_SUCCESS); } fct_status_t --- 7309,7320 ---- EL(qlt, "cmd_rp_handle-%x\n", cmd->cmd_rp_handle); } QMEM_WR32(qlt, (&req[0x10]), qcmd->fw_xchg_addr); QMEM_WR32(qlt, (&req[0x18]), cmd->cmd_rportid); ! qlt_submit_req_entries(qlt, 1, qi); ! mutex_exit(&qlt->mq_req[qi].mq_lock); return (FCT_SUCCESS); } fct_status_t
*** 4788,4822 **** qlt_abort_unsol_scsi_cmd(qlt_state_t *qlt, fct_cmd_t *cmd) { qlt_cmd_t *qcmd = (qlt_cmd_t *)cmd->cmd_fca_private; uint8_t *req; uint16_t flags; flags = (uint16_t)(BIT_14 | (((uint16_t)qcmd->param.atio_byte3 & 0xf0) << 5)); - EL(qlt, "fctcmd-%p, cmd_handle-%x\n", cmd, cmd->cmd_handle); ! mutex_enter(&qlt->req_lock); ! req = (uint8_t *)qlt_get_req_entries(qlt, 1); ! if (req == NULL) { ! mutex_exit(&qlt->req_lock); return (FCT_BUSY); } qcmd->flags = (uint16_t)(qcmd->flags | QLT_CMD_ABORTING); bzero(req, IOCB_SIZE); req[0] = 0x12; req[1] = 0x1; ! QMEM_WR32(qlt, req+4, cmd->cmd_handle); ! QMEM_WR16(qlt, req+8, cmd->cmd_rp->rp_handle); ! QMEM_WR16(qlt, req+10, 60); /* 60 seconds timeout */ ! QMEM_WR32(qlt, req+0x10, cmd->cmd_rportid); ! QMEM_WR32(qlt, req+0x14, qcmd->fw_xchg_addr); ! QMEM_WR16(qlt, req+0x1A, flags); ! QMEM_WR16(qlt, req+0x20, cmd->cmd_oxid); ! qlt_submit_req_entries(qlt, 1); ! mutex_exit(&qlt->req_lock); return (FCT_SUCCESS); } fct_status_t --- 7321,7360 ---- qlt_abort_unsol_scsi_cmd(qlt_state_t *qlt, fct_cmd_t *cmd) { qlt_cmd_t *qcmd = (qlt_cmd_t *)cmd->cmd_fca_private; uint8_t *req; uint16_t flags; + uint16_t qi; + qi = qcmd->qid; + flags = (uint16_t)(BIT_14 | (((uint16_t)qcmd->param.atio_byte3 & 0xf0) << 5)); ! EL(qlt, "(%d) (%x) (%p) (%x)\n", qi, cmd->cmd_oxid, ! cmd, qcmd->fw_xchg_addr); + mutex_enter(&qlt->mq_req[qi].mq_lock); + req = (uint8_t *)qlt_get_req_entries(qlt, 1, qi); + if (req == NULL) { + EL(qlt, "req == NULL\n"); + mutex_exit(&qlt->mq_req[qi].mq_lock); return (FCT_BUSY); } qcmd->flags = (uint16_t)(qcmd->flags | QLT_CMD_ABORTING); bzero(req, IOCB_SIZE); req[0] = 0x12; req[1] = 0x1; ! QMEM_WR32_REQ(qlt, qi, req+4, cmd->cmd_handle); ! QMEM_WR16_REQ(qlt, qi, req+8, cmd->cmd_rp->rp_handle); ! QMEM_WR16_REQ(qlt, qi, req+10, 60); /* 60 seconds timeout */ ! QMEM_WR32_REQ(qlt, qi, req+0x10, cmd->cmd_rportid); ! QMEM_WR32_REQ(qlt, qi, req+0x14, qcmd->fw_xchg_addr); ! QMEM_WR16_REQ(qlt, qi, req+0x1A, flags); ! QMEM_WR16_REQ(qlt, qi, req+0x20, cmd->cmd_oxid); ! qlt_submit_req_entries(qlt, 1, qi); ! mutex_exit(&qlt->mq_req[qi].mq_lock); return (FCT_SUCCESS); } fct_status_t
*** 4823,4838 **** qlt_send_cmd(fct_cmd_t *cmd) { qlt_state_t *qlt; qlt = (qlt_state_t *)cmd->cmd_port->port_fca_private; if (cmd->cmd_type == FCT_CMD_SOL_ELS) { return (qlt_send_els(qlt, cmd)); } else if (cmd->cmd_type == FCT_CMD_SOL_CT) { return (qlt_send_ct(qlt, cmd)); } ! EL(qlt, "cmd->cmd_type = %xh\n", cmd->cmd_type); ASSERT(0); return (FCT_FAILURE); } --- 7361,7377 ---- qlt_send_cmd(fct_cmd_t *cmd) { qlt_state_t *qlt; qlt = (qlt_state_t *)cmd->cmd_port->port_fca_private; + EL(qlt, "cmd->cmd_type = %xh\n", cmd->cmd_type); if (cmd->cmd_type == FCT_CMD_SOL_ELS) { return (qlt_send_els(qlt, cmd)); } else if (cmd->cmd_type == FCT_CMD_SOL_CT) { return (qlt_send_ct(qlt, cmd)); } ! EL(qlt, "Unknown cmd->cmd_type = %xh\n", cmd->cmd_type); ASSERT(0); return (FCT_FAILURE); }
*** 4843,4853 **** --- 7382,7395 ---- fct_els_t *els; qlt_cmd_t *qcmd; stmf_data_buf_t *buf; qlt_dmem_bctl_t *bctl; uint32_t sz, minsz; + uint16_t qi; + qi = 0; + els = (fct_els_t *)cmd->cmd_specific; qcmd = (qlt_cmd_t *)cmd->cmd_fca_private; qcmd->flags = QLT_CMD_TYPE_SOLICITED; qcmd->param.resp_offset = (uint16_t)((els->els_req_size + 7) & ~7); sz = minsz = qcmd->param.resp_offset + els->els_resp_size;
*** 4860,4874 **** qcmd->dbuf = buf; bcopy(els->els_req_payload, buf->db_sglist[0].seg_addr, els->els_req_size); qlt_dmem_dma_sync(buf, DDI_DMA_SYNC_FORDEV); ! mutex_enter(&qlt->req_lock); ! req = (uint8_t *)qlt_get_req_entries(qlt, 1); if (req == NULL) { qlt_dmem_free(NULL, buf); ! mutex_exit(&qlt->req_lock); return (FCT_BUSY); } bzero(req, IOCB_SIZE); req[0] = 0x53; req[1] = 1; QMEM_WR32(qlt, (&req[4]), cmd->cmd_handle); --- 7402,7418 ---- qcmd->dbuf = buf; bcopy(els->els_req_payload, buf->db_sglist[0].seg_addr, els->els_req_size); qlt_dmem_dma_sync(buf, DDI_DMA_SYNC_FORDEV); ! mutex_enter(&qlt->mq_req[qi].mq_lock); ! req = (uint8_t *)qlt_get_req_entries(qlt, 1, qi); if (req == NULL) { + EL(qlt, "req = NULL, %xh %xh %p %xh\n", cmd->cmd_oxid, + cmd->cmd_rportid, cmd, qcmd->fw_xchg_addr); qlt_dmem_free(NULL, buf); ! mutex_exit(&qlt->mq_req[qi].mq_lock); return (FCT_BUSY); } bzero(req, IOCB_SIZE); req[0] = 0x53; req[1] = 1; QMEM_WR32(qlt, (&req[4]), cmd->cmd_handle);
*** 4888,4900 **** QMEM_WR64(qlt, (&req[0x28]), bctl->bctl_dev_addr); QMEM_WR32(qlt, (&req[0x30]), els->els_req_size); QMEM_WR64(qlt, (&req[0x34]), (bctl->bctl_dev_addr + qcmd->param.resp_offset)); QMEM_WR32(qlt, (&req[0x3C]), els->els_resp_size); - qlt_submit_req_entries(qlt, 1); - mutex_exit(&qlt->req_lock); return (FCT_SUCCESS); } fct_status_t qlt_send_ct(qlt_state_t *qlt, fct_cmd_t *cmd) --- 7432,7448 ---- QMEM_WR64(qlt, (&req[0x28]), bctl->bctl_dev_addr); QMEM_WR32(qlt, (&req[0x30]), els->els_req_size); QMEM_WR64(qlt, (&req[0x34]), (bctl->bctl_dev_addr + qcmd->param.resp_offset)); QMEM_WR32(qlt, (&req[0x3C]), els->els_resp_size); + EL(qlt, "ELS opcode %xh to %xh\n", + req[0x16], cmd->cmd_rp->rp_id); + + qlt_submit_req_entries(qlt, 1, qi); + mutex_exit(&qlt->mq_req[qi].mq_lock); + return (FCT_SUCCESS); } fct_status_t qlt_send_ct(qlt_state_t *qlt, fct_cmd_t *cmd)
*** 4903,4913 **** --- 7451,7464 ---- fct_sol_ct_t *ct; qlt_cmd_t *qcmd; stmf_data_buf_t *buf; qlt_dmem_bctl_t *bctl; uint32_t sz, minsz; + uint16_t qi; + qi = 0; + ct = (fct_sol_ct_t *)cmd->cmd_specific; qcmd = (qlt_cmd_t *)cmd->cmd_fca_private; qcmd->flags = QLT_CMD_TYPE_SOLICITED; qcmd->param.resp_offset = (uint16_t)((ct->ct_req_size + 7) & ~7); sz = minsz = qcmd->param.resp_offset + ct->ct_resp_size;
*** 4920,4934 **** qcmd->dbuf = buf; bcopy(ct->ct_req_payload, buf->db_sglist[0].seg_addr, ct->ct_req_size); qlt_dmem_dma_sync(buf, DDI_DMA_SYNC_FORDEV); ! mutex_enter(&qlt->req_lock); ! req = (uint8_t *)qlt_get_req_entries(qlt, 1); if (req == NULL) { qlt_dmem_free(NULL, buf); ! mutex_exit(&qlt->req_lock); return (FCT_BUSY); } bzero(req, IOCB_SIZE); req[0] = 0x29; req[1] = 1; QMEM_WR32(qlt, (&req[4]), cmd->cmd_handle); --- 7471,7487 ---- qcmd->dbuf = buf; bcopy(ct->ct_req_payload, buf->db_sglist[0].seg_addr, ct->ct_req_size); qlt_dmem_dma_sync(buf, DDI_DMA_SYNC_FORDEV); ! mutex_enter(&qlt->mq_req[qi].mq_lock); ! req = (uint8_t *)qlt_get_req_entries(qlt, 1, qi); if (req == NULL) { + EL(qlt, "req = NULL, %xh %xh %p %xh\n", cmd->cmd_oxid, + cmd->cmd_rportid, cmd, qcmd->fw_xchg_addr); qlt_dmem_free(NULL, buf); ! mutex_exit(&qlt->mq_req[qi].mq_lock); return (FCT_BUSY); } bzero(req, IOCB_SIZE); req[0] = 0x29; req[1] = 1; QMEM_WR32(qlt, (&req[4]), cmd->cmd_handle);
*** 4944,4960 **** QMEM_WR32(qlt, (&req[0x30]), ct->ct_req_size); QMEM_WR64(qlt, (&req[0x34]), (bctl->bctl_dev_addr + qcmd->param.resp_offset)); /* RESPONSE DSD */ QMEM_WR32(qlt, (&req[0x3C]), ct->ct_resp_size); ! qlt_submit_req_entries(qlt, 1); ! mutex_exit(&qlt->req_lock); return (FCT_SUCCESS); } /* * All QLT_FIRMWARE_* will mainly be handled in this function * It can not be called in interrupt context * * FWDUMP's purpose is to serve ioctl, so we will use qlt_ioctl_flags --- 7497,7729 ---- QMEM_WR32(qlt, (&req[0x30]), ct->ct_req_size); QMEM_WR64(qlt, (&req[0x34]), (bctl->bctl_dev_addr + qcmd->param.resp_offset)); /* RESPONSE DSD */ QMEM_WR32(qlt, (&req[0x3C]), ct->ct_resp_size); ! EL(qlt, "%p cmd_hdl=%xh %xh %xh\n", ! cmd, cmd->cmd_handle, ct->ct_req_size, ct->ct_resp_size); + qlt_submit_req_entries(qlt, 1, qi); + mutex_exit(&qlt->mq_req[qi].mq_lock); + return (FCT_SUCCESS); } + /*ARGSUSED*/ + caddr_t + qlt_str_ptr(qlt_state_t *qlt, caddr_t bp, uint32_t *len) + { + caddr_t sp; + uint32_t i = 0; + sp = bp; + while (*sp++ != 0) i++; + if (i > *len || !(*len -= i)) { + EL(qlt, "full buffer\n"); + return (NULL); + } + return (bp += i); + } + + static fct_status_t + qlt_27xx_fw_dump(fct_local_port_t *port, stmf_state_change_info_t *ssci) + { + qlt_state_t *qlt = (qlt_state_t *)port->port_fca_private; + qlt_dmp_template_t *template_buff; + uint32_t tsize, dsize, len; + uint32_t cnt, *dp, *bp; + uint8_t *fw; + caddr_t sp; + + EL(qlt, "enter...\n"); + + mutex_enter(&qlt->qlt_ioctl_lock); + /* + * To make sure that there's no outstanding dumping task + */ + if (qlt->qlt_ioctl_flags & QLT_FWDUMP_INPROGRESS) { + mutex_exit(&qlt->qlt_ioctl_lock); + EL(qlt, "qlt_ioctl_flags=%xh, inprogress\n", + qlt->qlt_ioctl_flags); + return (FCT_FAILURE); + } + + /* + * To make sure not to overwrite existing dump + */ + if ((qlt->qlt_ioctl_flags & QLT_FWDUMP_ISVALID) && + !(qlt->qlt_ioctl_flags & QLT_FWDUMP_TRIGGERED_BY_USER) && + !(qlt->qlt_ioctl_flags & QLT_FWDUMP_FETCHED_BY_USER)) { + /* + * If we have already one dump, but it's not triggered by user + * and the user hasn't fetched it, we shouldn't dump again. + * But if qlt force a fw dump, then we need to overwrite the + * previous one anyway. + */ + mutex_exit(&qlt->qlt_ioctl_lock); + EL(qlt, "qlt_ioctl_flags=%xh, already done\n", + qlt->qlt_ioctl_flags); + cmn_err(CE_NOTE, "qlt(%d): Skipping firmware dump as there " + "is one already outstanding.", qlt->instance); + return (FCT_FAILURE); + } + + if (qlt->dmp_template_addr == NULL) { + mutex_exit(&qlt->qlt_ioctl_lock); + EL(qlt, "dmp_template_addr is NULL, can't " + "perform firmware dump\n"); + cmn_err(CE_WARN, "!qlt(%d) dmp_template_addr is NULL, can't " + "perform firmware dump", qlt->instance); + return (FCT_FAILURE); + } + + qlt->qlt_ioctl_flags |= QLT_FWDUMP_INPROGRESS; + if (ssci != NULL && (ssci->st_rflags & STMF_RFLAG_USER_REQUEST)) { + qlt->qlt_ioctl_flags |= QLT_FWDUMP_TRIGGERED_BY_USER; + } else { + qlt->qlt_ioctl_flags &= ~QLT_FWDUMP_TRIGGERED_BY_USER; + } + mutex_exit(&qlt->qlt_ioctl_lock); + + template_buff = (qlt_dmp_template_t *)qlt->dmp_template_addr; + tsize = template_buff->hdr.size_of_template; + + if (qlt->fw_bin_dump_size == 0) { + qlt->fw_bin_dump_buf = kmem_zalloc(tsize, KM_NOSLEEP); + if (qlt->fw_bin_dump_buf == NULL) { + cmn_err(CE_WARN, "!qlt(%d) cannot alloc bin dump buf", + qlt->instance); + return (FCT_FAILURE); + } + cnt = (uint32_t)(tsize / sizeof (uint32_t)); + dp = (uint32_t *)qlt->fw_bin_dump_buf; + bp = (uint32_t *)&template_buff->hdr; + while (cnt--) { + *dp++ = ddi_get32(qlt->dmp_template_acc_handle, bp++); + } + qlt->fw_bin_dump_size = qlt_27xx_dmp_parse_template(qlt, + (qlt_dt_hdr_t *)qlt->fw_bin_dump_buf, NULL, 0); + kmem_free(qlt->fw_bin_dump_buf, tsize); + qlt->fw_bin_dump_buf = NULL; + + if (qlt->fw_bin_dump_size == 0) { + return (FCT_FAILURE); + } + + /* + * Determine ascii dump file size + * 2 ascii bytes per binary byte + a space and + * a newline every 16 binary bytes + */ + qlt->fw_ascii_dump_size = qlt->fw_bin_dump_size << 1; + qlt->fw_ascii_dump_size += qlt->fw_bin_dump_size; + qlt->fw_ascii_dump_size += qlt->fw_bin_dump_size / 16 + 1; + + EL(qlt, "fw_bin_dump_size=%xh, " + "fw_acsii_dump_size=%xh\n", qlt->fw_bin_dump_size, + qlt->fw_ascii_dump_size); + } + + if (qlt->fw_bin_dump_buf != NULL) { + /* overwrite the previous fw dump by qlt forced fw dump */ + bzero((void *) qlt->fw_bin_dump_buf, qlt->fw_bin_dump_size); + } else { + qlt->fw_bin_dump_buf = kmem_zalloc(qlt->fw_bin_dump_size, + KM_NOSLEEP); + if (qlt->fw_bin_dump_buf == NULL) { + qlt->fw_bin_dump_size = 0; + EL(qlt, "done, failed alloc bin dump buf\n"); + return (FCT_FAILURE); + } + } + + if ((qlt->fw_dump_size != 0) && + (qlt->fw_dump_size != qlt->fw_ascii_dump_size)) { + if (qlt->qlt_fwdump_buf != NULL) { + /* Release previously allocated buffer */ + kmem_free(qlt->qlt_fwdump_buf, qlt->fw_dump_size); + qlt->qlt_fwdump_buf = NULL; + } + } + + if (qlt->qlt_fwdump_buf == NULL) { + qlt->qlt_fwdump_buf = kmem_zalloc(qlt->fw_ascii_dump_size, + KM_NOSLEEP); + if (qlt->qlt_fwdump_buf == NULL) { + EL(qlt, "done, failed alloc ascii fw dump buf\n"); + return (FCT_FAILURE); + } + qlt->fw_dump_size = qlt->fw_ascii_dump_size; + } + + /* Disable ISP interrupts. */ + REG_WR32(qlt, 0xc, 0); + + cnt = (uint32_t)(tsize / sizeof (uint32_t)); + dp = (uint32_t *)qlt->fw_bin_dump_buf; + bp = (uint32_t *)&template_buff->hdr; + while (cnt--) { + *dp++ = ddi_get32(qlt->dmp_template_acc_handle, bp++); + } + + (void) qlt_27xx_dmp_parse_template(qlt, + (qlt_dt_hdr_t *)qlt->fw_bin_dump_buf, + (uint8_t *)dp, qlt->fw_bin_dump_size); + + #ifdef _BIG_ENDIAN + cnt = (uint32_t)(tsize / sizeof (uint32_t)); + dp = (uint32_t *)qlt->fw_bin_dump_buf; + while (cnt--) { + qlt_chg_endian((uint8_t *)dp, 4); + dp++; + } + #endif + + /* + * Build ascii dump + */ + len = qlt->fw_ascii_dump_size; + dsize = qlt->fw_bin_dump_size; + fw = (uint8_t *)qlt->fw_bin_dump_buf; + sp = qlt->qlt_fwdump_buf; + + EL(qlt, "fw_dump_buffer=%ph, fw=%ph, fw_ascii_dump_size=%xh, " + "dsize=%xh\n", (void *)qlt->qlt_fwdump_buf, (void *)fw, + len, dsize); + + /* + * 2 ascii bytes per binary byte + a space and + * a newline every 16 binary bytes + */ + cnt = 0; + while (cnt < dsize) { + (void) snprintf(sp, len, "%02x ", *fw++); + if ((sp = qlt_str_ptr(qlt, sp, &len)) == NULL) { + break; + } + if (++cnt % 16 == 0) { + (void) snprintf(sp, len, "\n"); + if ((sp = qlt_str_ptr(qlt, sp, &len)) == NULL) { + break; + } + } + } + if (cnt % 16 != 0) { + (void) snprintf(sp, len, "\n"); + sp = qlt_str_ptr(qlt, sp, &len); + } + + mutex_enter(&qlt->qlt_ioctl_lock); + qlt->qlt_ioctl_flags &= + ~(QLT_FWDUMP_INPROGRESS | QLT_FWDUMP_FETCHED_BY_USER); + qlt->qlt_ioctl_flags |= QLT_FWDUMP_ISVALID; + mutex_exit(&qlt->qlt_ioctl_lock); + + EL(qlt, "done...\n"); + return (FCT_SUCCESS); + } + /* * All QLT_FIRMWARE_* will mainly be handled in this function * It can not be called in interrupt context * * FWDUMP's purpose is to serve ioctl, so we will use qlt_ioctl_flags
*** 4970,4988 **** char c = ' '; uint32_t addr, endaddr, words_to_read; caddr_t buf; fct_status_t ret; mutex_enter(&qlt->qlt_ioctl_lock); /* * To make sure that there's no outstanding dumping task */ if (qlt->qlt_ioctl_flags & QLT_FWDUMP_INPROGRESS) { mutex_exit(&qlt->qlt_ioctl_lock); EL(qlt, "qlt_ioctl_flags=%xh, inprogress\n", qlt->qlt_ioctl_flags); - EL(qlt, "outstanding\n"); return (FCT_FAILURE); } /* * To make sure not to overwrite existing dump --- 7739,7759 ---- char c = ' '; uint32_t addr, endaddr, words_to_read; caddr_t buf; fct_status_t ret; + if (qlt->qlt_27xx_chip) { + return (qlt_27xx_fw_dump(port, ssci)); + } mutex_enter(&qlt->qlt_ioctl_lock); /* * To make sure that there's no outstanding dumping task */ if (qlt->qlt_ioctl_flags & QLT_FWDUMP_INPROGRESS) { mutex_exit(&qlt->qlt_ioctl_lock); EL(qlt, "qlt_ioctl_flags=%xh, inprogress\n", qlt->qlt_ioctl_flags); return (FCT_FAILURE); } /* * To make sure not to overwrite existing dump
*** 4989,4999 **** */ if ((qlt->qlt_ioctl_flags & QLT_FWDUMP_ISVALID) && !(qlt->qlt_ioctl_flags & QLT_FWDUMP_TRIGGERED_BY_USER) && !(qlt->qlt_ioctl_flags & QLT_FWDUMP_FETCHED_BY_USER)) { /* ! * If we have alreay one dump, but it's not triggered by user * and the user hasn't fetched it, we shouldn't dump again. */ mutex_exit(&qlt->qlt_ioctl_lock); EL(qlt, "qlt_ioctl_flags=%xh, already done\n", qlt->qlt_ioctl_flags); --- 7760,7770 ---- */ if ((qlt->qlt_ioctl_flags & QLT_FWDUMP_ISVALID) && !(qlt->qlt_ioctl_flags & QLT_FWDUMP_TRIGGERED_BY_USER) && !(qlt->qlt_ioctl_flags & QLT_FWDUMP_FETCHED_BY_USER)) { /* ! * If we have already one dump, but it's not triggered by user * and the user hasn't fetched it, we shouldn't dump again. */ mutex_exit(&qlt->qlt_ioctl_lock); EL(qlt, "qlt_ioctl_flags=%xh, already done\n", qlt->qlt_ioctl_flags);
*** 5000,5026 **** cmn_err(CE_NOTE, "qlt(%d): Skipping firmware dump as there " "is one already outstanding.", qlt->instance); return (FCT_FAILURE); } qlt->qlt_ioctl_flags |= QLT_FWDUMP_INPROGRESS; ! if (ssci->st_rflags & STMF_RFLAG_USER_REQUEST) { qlt->qlt_ioctl_flags |= QLT_FWDUMP_TRIGGERED_BY_USER; } else { qlt->qlt_ioctl_flags &= ~QLT_FWDUMP_TRIGGERED_BY_USER; } mutex_exit(&qlt->qlt_ioctl_lock); size_left = QLT_FWDUMP_BUFSIZE; if (!qlt->qlt_fwdump_buf) { ASSERT(!(qlt->qlt_ioctl_flags & QLT_FWDUMP_ISVALID)); /* * It's the only place that we allocate buf for dumping. After * it's allocated, we will use it until the port is detached. */ ! qlt->qlt_fwdump_buf = kmem_zalloc(size_left, KM_SLEEP); } /* * Start to dump firmware */ buf = (caddr_t)qlt->qlt_fwdump_buf; --- 7771,7811 ---- cmn_err(CE_NOTE, "qlt(%d): Skipping firmware dump as there " "is one already outstanding.", qlt->instance); return (FCT_FAILURE); } qlt->qlt_ioctl_flags |= QLT_FWDUMP_INPROGRESS; ! if ((ssci != NULL) && (ssci->st_rflags & STMF_RFLAG_USER_REQUEST)) { qlt->qlt_ioctl_flags |= QLT_FWDUMP_TRIGGERED_BY_USER; } else { qlt->qlt_ioctl_flags &= ~QLT_FWDUMP_TRIGGERED_BY_USER; } mutex_exit(&qlt->qlt_ioctl_lock); size_left = QLT_FWDUMP_BUFSIZE; + if (qlt->qlt_mq_enabled && qlt->qlt_queue_cnt >= 8) { + size_left += 512 * 1024; + } + qlt->fw_dump_size = size_left; if (!qlt->qlt_fwdump_buf) { ASSERT(!(qlt->qlt_ioctl_flags & QLT_FWDUMP_ISVALID)); /* * It's the only place that we allocate buf for dumping. After * it's allocated, we will use it until the port is detached. */ ! qlt->qlt_fwdump_buf = kmem_zalloc(size_left, KM_NOSLEEP); ! if (qlt->qlt_fwdump_buf == NULL) { ! EL(qlt, "cannot alloc fwdump buffer\n"); ! cmn_err(CE_WARN, "!qlt(%d): cannot alloc fwdump buf", ! qlt->instance); ! return (FCT_FAILURE); } + } + EL(qlt, "starting firmware dump...\n"); + cmn_err(CE_WARN, "!qlt(%d) starting firmware dump...", + qlt->instance); + /* * Start to dump firmware */ buf = (caddr_t)qlt->qlt_fwdump_buf;
*** 5027,5046 **** /* * Print the ISP firmware revision number and attributes information * Read the RISC to Host Status register */ n = (int)snprintf(buf, size_left, "ISP FW Version %d.%02d.%02d " ! "Attributes %04x\n\nR2H Status Register\n%08x", qlt->fw_major, qlt->fw_minor, qlt->fw_subminor, qlt->fw_attr, REG_RD32(qlt, REG_RISC_STATUS)); buf += n; size_left -= n; /* * Before pausing the RISC, make sure no mailbox can execute */ mutex_enter(&qlt->mbox_lock); ! if (qlt->mbox_io_state != MBOX_STATE_UNKNOWN) { /* * Wait to grab the mailboxes */ for (retries = 0; (qlt->mbox_io_state != MBOX_STATE_READY) && (qlt->mbox_io_state != MBOX_STATE_UNKNOWN); retries++) { --- 7812,7832 ---- /* * Print the ISP firmware revision number and attributes information * Read the RISC to Host Status register */ n = (int)snprintf(buf, size_left, "ISP FW Version %d.%02d.%02d " ! "Attributes %04x\n\nR2H Status register\n%08x", qlt->fw_major, qlt->fw_minor, qlt->fw_subminor, qlt->fw_attr, REG_RD32(qlt, REG_RISC_STATUS)); buf += n; size_left -= n; /* * Before pausing the RISC, make sure no mailbox can execute */ mutex_enter(&qlt->mbox_lock); ! if ((qlt->mbox_io_state != MBOX_STATE_UNKNOWN) && ! (qlt->qlt_intr_enabled)) { /* * Wait to grab the mailboxes */ for (retries = 0; (qlt->mbox_io_state != MBOX_STATE_READY) && (qlt->mbox_io_state != MBOX_STATE_UNKNOWN); retries++) {
*** 5074,5084 **** if (i == 200) { EL(qlt, "can't pause\n"); return (FCT_FAILURE); } ! if ((!qlt->qlt_25xx_chip) && (!qlt->qlt_81xx_chip)) { goto over_25xx_specific_dump; } n = (int)snprintf(buf, size_left, "\n\nHostRisc registers\n"); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0x7000); --- 7860,7884 ---- if (i == 200) { EL(qlt, "can't pause\n"); return (FCT_FAILURE); } ! if (qlt->qlt_83xx_chip) { ! /* Disable ECC checks in FB registers */ ! REG_WR32(qlt, 0x54, 0x6000); ! REG_WR32(qlt, 0xC0, 0); /* 6000h */ ! REG_WR32(qlt, 0xCC, 0); /* 6003h */ ! REG_WR32(qlt, 0x54, 0x6010); ! REG_WR32(qlt, 0xD4, 0); /* 6015h */ ! ! /* disable ECC detection in PCR whilst dumping */ ! REG_WR32(qlt, 0x54, 0xF70); ! REG_WR32(qlt, 0xF0, 0x60000000); ! } ! ! if ((!qlt->qlt_25xx_chip) && (!qlt->qlt_81xx_chip) && ! (!qlt->qlt_83xx_chip) && (!qlt->qlt_27xx_chip)) { goto over_25xx_specific_dump; } n = (int)snprintf(buf, size_left, "\n\nHostRisc registers\n"); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0x7000);
*** 5085,5094 **** --- 7885,7899 ---- n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0x7010); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; + if (qlt->qlt_83xx_chip) { + REG_WR32(qlt, 0x54, 0x7040); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + } REG_WR32(qlt, 0x54, 0x7C00); n = (int)snprintf(buf, size_left, "\nPCIe registers\n"); buf += n; size_left -= n; REG_WR32(qlt, 0xC0, 0x1);
*** 5096,5130 **** buf += n; size_left -= n; n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 1, size_left); buf += n; size_left -= n; REG_WR32(qlt, 0xC0, 0x0); over_25xx_specific_dump:; ! n = (int)snprintf(buf, size_left, "\n\nHost Interface Registers\n"); buf += n; size_left -= n; /* ! * Capture data from 32 regsiters */ n = qlt_fwdump_dump_regs(qlt, buf, 0, 32, size_left); buf += n; size_left -= n; /* * Disable interrupts */ REG_WR32(qlt, 0xc, 0); /* * Shadow registers */ ! n = (int)snprintf(buf, size_left, "\nShadow Registers\n"); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0xF70); addr = 0xb0000000; for (i = 0; i < 0xb; i++) { if ((!qlt->qlt_25xx_chip) && (!qlt->qlt_81xx_chip) && (i >= 7)) { break; } if (i && ((i & 7) == 0)) { n = (int)snprintf(buf, size_left, "\n"); --- 7901,7966 ---- buf += n; size_left -= n; n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 1, size_left); buf += n; size_left -= n; REG_WR32(qlt, 0xC0, 0x0); + /* don't need to do this for 83xx */ + if ((!qlt->qlt_83xx_chip) && (qlt->qlt_mq_enabled)) { + uint16_t qi; + + for (qi = 0; qi < qlt->qlt_queue_cnt; qi++) { + + n = (int)snprintf(buf, size_left, + "\n\nQueue Pointers #%x\n", qi); + buf += n; size_left -= n; + + n = (int)snprintf(buf, size_left, "%08x ", + MQBAR_RD32(qlt, + (qi * MQBAR_REG_OFFSET) + MQBAR_REQ_IN)); + buf += n; size_left -= n; + n = (int)snprintf(buf, size_left, "%08x ", + MQBAR_RD32(qlt, + (qi * MQBAR_REG_OFFSET) + MQBAR_REQ_OUT)); + buf += n; size_left -= n; + n = (int)snprintf(buf, size_left, "%08x ", + MQBAR_RD32(qlt, + (qi * MQBAR_REG_OFFSET) + MQBAR_RESP_IN)); + buf += n; size_left -= n; + n = (int)snprintf(buf, size_left, "%08x", + MQBAR_RD32(qlt, + (qi * MQBAR_REG_OFFSET) + MQBAR_RESP_OUT)); + buf += n; size_left -= n; + } + } + over_25xx_specific_dump:; ! n = (int)snprintf(buf, size_left, "\n\nHost Interface registers\n"); buf += n; size_left -= n; /* ! * Capture data from 32 registers */ n = qlt_fwdump_dump_regs(qlt, buf, 0, 32, size_left); buf += n; size_left -= n; /* * Disable interrupts */ REG_WR32(qlt, 0xc, 0); + EL(qlt, "Disable interrupt\n"); /* * Shadow registers */ ! n = (int)snprintf(buf, size_left, "\nShadow registers\n"); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0xF70); addr = 0xb0000000; for (i = 0; i < 0xb; i++) { if ((!qlt->qlt_25xx_chip) && (!qlt->qlt_81xx_chip) && + (!qlt->qlt_83xx_chip) && (i >= 7)) { break; } if (i && ((i & 7) == 0)) { n = (int)snprintf(buf, size_left, "\n");
*** 5134,5154 **** n = (int)snprintf(buf, size_left, "%08x ", REG_RD32(qlt, 0xFC)); buf += n; size_left -= n; addr += 0x100000; } ! if ((qlt->qlt_25xx_chip) || (qlt->qlt_81xx_chip)) { REG_WR32(qlt, 0x54, 0x10); n = (int)snprintf(buf, size_left, ! "\n\nRISC IO Register\n%08x", REG_RD32(qlt, 0xC0)); buf += n; size_left -= n; } /* * Mailbox registers */ ! n = (int)snprintf(buf, size_left, "\n\nMailbox Registers\n"); buf += n; size_left -= n; for (i = 0; i < 32; i += 2) { if ((i + 2) & 15) { c = ' '; } else { --- 7970,7991 ---- n = (int)snprintf(buf, size_left, "%08x ", REG_RD32(qlt, 0xFC)); buf += n; size_left -= n; addr += 0x100000; } ! if ((qlt->qlt_25xx_chip) || (qlt->qlt_81xx_chip) || ! (qlt->qlt_83xx_chip)) { REG_WR32(qlt, 0x54, 0x10); n = (int)snprintf(buf, size_left, ! "\n\nRISC IO register\n%08x", REG_RD32(qlt, 0xC0)); buf += n; size_left -= n; } /* * Mailbox registers */ ! n = (int)snprintf(buf, size_left, "\n\nMailbox registers\n"); buf += n; size_left -= n; for (i = 0; i < 32; i += 2) { if ((i + 2) & 15) { c = ' '; } else {
*** 5161,5173 **** } /* * Transfer sequence registers */ ! n = (int)snprintf(buf, size_left, "\nXSEQ GP Registers\n"); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0xBF00); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0xBF10); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); --- 7998,8036 ---- } /* * Transfer sequence registers */ ! n = (int)snprintf(buf, size_left, "\nXSEQ GP registers\n"); buf += n; size_left -= n; + if (qlt->qlt_83xx_chip) { + REG_WR32(qlt, 0x54, 0xBE00); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xBE10); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xBE20); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xBE30); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xBE40); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xBE50); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xBE60); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xBE70); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + } REG_WR32(qlt, 0x54, 0xBF00); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0xBF10); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
*** 5190,5200 **** REG_WR32(qlt, 0x54, 0xBF70); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; n = (int)snprintf(buf, size_left, "\nXSEQ-0 registers\n"); buf += n; size_left -= n; ! if ((qlt->qlt_25xx_chip) || (qlt->qlt_81xx_chip)) { REG_WR32(qlt, 0x54, 0xBFC0); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0xBFD0); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); --- 8053,8064 ---- REG_WR32(qlt, 0x54, 0xBF70); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; n = (int)snprintf(buf, size_left, "\nXSEQ-0 registers\n"); buf += n; size_left -= n; ! if ((qlt->qlt_25xx_chip) || (qlt->qlt_81xx_chip) || ! (qlt->qlt_83xx_chip)) { REG_WR32(qlt, 0x54, 0xBFC0); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0xBFD0); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
*** 5207,5221 **** buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0xBFF0); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; /* * Receive sequence registers */ ! n = (int)snprintf(buf, size_left, "\nRSEQ GP Registers\n"); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0xFF00); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0xFF10); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); --- 8071,8119 ---- buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0xBFF0); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; + if (qlt->qlt_83xx_chip) { + n = (int)snprintf(buf, size_left, "\nXSEQ-2 registers\n"); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xBEF0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + } + /* * Receive sequence registers */ ! n = (int)snprintf(buf, size_left, "\nRSEQ GP registers\n"); buf += n; size_left -= n; + if (qlt->qlt_83xx_chip) { + REG_WR32(qlt, 0x54, 0xFE00); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xFE10); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xFE20); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xFE30); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xFE40); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xFE50); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xFE60); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xFE70); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + } REG_WR32(qlt, 0x54, 0xFF00); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0xFF10); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
*** 5238,5248 **** REG_WR32(qlt, 0x54, 0xFF70); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; n = (int)snprintf(buf, size_left, "\nRSEQ-0 registers\n"); buf += n; size_left -= n; ! if ((qlt->qlt_25xx_chip) || (qlt->qlt_81xx_chip)) { REG_WR32(qlt, 0x54, 0xFFC0); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; } REG_WR32(qlt, 0x54, 0xFFD0); --- 8136,8147 ---- REG_WR32(qlt, 0x54, 0xFF70); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; n = (int)snprintf(buf, size_left, "\nRSEQ-0 registers\n"); buf += n; size_left -= n; ! if ((qlt->qlt_25xx_chip) || (qlt->qlt_81xx_chip) || ! (qlt->qlt_83xx_chip)) { REG_WR32(qlt, 0x54, 0xFFC0); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; } REG_WR32(qlt, 0x54, 0xFFD0);
*** 5256,5273 **** n = (int)snprintf(buf, size_left, "\nRSEQ-2 registers\n"); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0xFFF0); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; ! if ((!qlt->qlt_25xx_chip) && (!qlt->qlt_81xx_chip)) goto over_aseq_regs; /* * Auxiliary sequencer registers */ ! n = (int)snprintf(buf, size_left, "\nASEQ GP Registers\n"); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0xB000); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0xB010); --- 8155,8180 ---- n = (int)snprintf(buf, size_left, "\nRSEQ-2 registers\n"); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0xFFF0); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; + if (qlt->qlt_83xx_chip) { + n = (int)snprintf(buf, size_left, "\nRSEQ-3 registers\n"); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xFEF0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + } ! if ((!qlt->qlt_25xx_chip) && (!qlt->qlt_81xx_chip) && ! (!qlt->qlt_83xx_chip)) goto over_aseq_regs; /* * Auxiliary sequencer registers */ ! n = (int)snprintf(buf, size_left, "\nASEQ GP registers\n"); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0xB000); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0xB010);
*** 5289,5298 **** --- 8196,8231 ---- n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0xB070); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; + if (qlt->qlt_83xx_chip) { + REG_WR32(qlt, 0x54, 0xB100); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xB110); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xB120); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xB130); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xB140); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xB150); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xB160); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xB170); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + } n = (int)snprintf(buf, size_left, "\nASEQ-0 registers\n"); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0xB0C0); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n;
*** 5307,5316 **** --- 8240,8256 ---- n = (int)snprintf(buf, size_left, "\nASEQ-2 registers\n"); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0xB0F0); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; + if (qlt->qlt_83xx_chip) { + n = (int)snprintf(buf, size_left, "\nASEQ-3 registers\n"); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0xB1F0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + } over_aseq_regs:; /* * Command DMA registers
*** 5318,5327 **** --- 8258,8278 ---- n = (int)snprintf(buf, size_left, "\nCommand DMA registers\n"); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0x7100); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; + if (qlt->qlt_83xx_chip) { + REG_WR32(qlt, 0x54, 0x7120); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x7130); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x71F0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + } /* * Queues */ n = (int)snprintf(buf, size_left,
*** 5477,5494 **** buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0x3060); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; ! if ((qlt->qlt_25xx_chip) || (qlt->qlt_81xx_chip)) { REG_WR32(qlt, 0x54, 0x3070); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; } /* ! * Fibre protocol module regsiters */ n = (int)snprintf(buf, size_left, "\nFPM hardware registers\n"); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0x4000); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); --- 8428,8446 ---- buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0x3060); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; ! if ((qlt->qlt_25xx_chip) || (qlt->qlt_81xx_chip) || ! (qlt->qlt_83xx_chip)) { REG_WR32(qlt, 0x54, 0x3070); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; } /* ! * Fibre protocol module registers */ n = (int)snprintf(buf, size_left, "\nFPM hardware registers\n"); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0x4000); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
*** 5524,5542 **** n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0x40B0); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; ! if (qlt->qlt_81xx_chip) { REG_WR32(qlt, 0x54, 0x40C0); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0x40D0); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; } /* * Fibre buffer registers */ n = (int)snprintf(buf, size_left, "\nFB hardware registers\n"); buf += n; size_left -= n; --- 8476,8713 ---- n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0x40B0); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; ! if ((qlt->qlt_83xx_chip) || (qlt->qlt_81xx_chip)) { REG_WR32(qlt, 0x54, 0x40C0); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0x40D0); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; } + if (qlt->qlt_83xx_chip) { + REG_WR32(qlt, 0x54, 0x40E0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x40F0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + n = (int)snprintf(buf, size_left, "\nRQ0 Array registers\n"); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5C00); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5C10); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5C20); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5C30); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5C40); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5C50); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5C60); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5C70); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5C80); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5C90); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5CA0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5CB0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5CC0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5CD0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5CE0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5CF0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + + n = (int)snprintf(buf, size_left, "\nRQ1 Array registers\n"); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5D00); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5D10); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5D20); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5D30); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5D40); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5D50); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5D60); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5D70); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5D80); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5D90); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5DA0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5DB0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5DC0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5DD0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5DE0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5DF0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + + n = (int)snprintf(buf, size_left, "\nRP0 Array registers\n"); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5E00); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5E10); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5E20); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5E30); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5E40); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5E50); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5E60); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5E70); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5E80); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5E90); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5EA0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5EB0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5EC0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5ED0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5EE0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5EF0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + + n = (int)snprintf(buf, size_left, "\nRP1 Array registers\n"); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5F00); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5F10); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5F20); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5F30); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5F40); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5F50); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5F60); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5F70); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5F80); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5F90); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5FA0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5FB0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5FC0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5FD0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5FE0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x5FF0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + + n = (int)snprintf(buf, + size_left, "\nQueue Control Registers\n"); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x7800); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + } + /* * Fibre buffer registers */ n = (int)snprintf(buf, size_left, "\nFB hardware registers\n"); buf += n; size_left -= n;
*** 5553,5562 **** --- 8724,8741 ---- n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0x6040); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; + if (qlt->qlt_83xx_chip) { + REG_WR32(qlt, 0x54, 0x6060); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x6070); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + } REG_WR32(qlt, 0x54, 0x6100); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0x6130); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left);
*** 5571,5606 **** n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0x61B0); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; ! if (qlt->qlt_81xx_chip) { REG_WR32(qlt, 0x54, 0x61C0); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; } ! if ((qlt->qlt_25xx_chip) || (qlt->qlt_81xx_chip)) { REG_WR32(qlt, 0x54, 0x6F00); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; } qlt->intr_sneak_counter = 10; mutex_enter(&qlt->intr_lock); (void) qlt_reset_chip(qlt); drv_usecwait(20); qlt->intr_sneak_counter = 0; mutex_exit(&qlt->intr_lock); /* * Memory */ n = (int)snprintf(buf, size_left, "\nCode RAM\n"); buf += n; size_left -= n; addr = 0x20000; ! endaddr = 0x22000; words_to_read = 0; while (addr < endaddr) { words_to_read = MBOX_DMA_MEM_SIZE >> 2; if ((words_to_read + addr) > endaddr) { words_to_read = endaddr - addr; --- 8750,8865 ---- n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; REG_WR32(qlt, 0x54, 0x61B0); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; ! if ((qlt->qlt_83xx_chip) || (qlt->qlt_81xx_chip)) { REG_WR32(qlt, 0x54, 0x61C0); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; } ! if (qlt->qlt_83xx_chip) { ! REG_WR32(qlt, 0x54, 0x6530); ! n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); ! buf += n; size_left -= n; ! REG_WR32(qlt, 0x54, 0x6540); ! n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); ! buf += n; size_left -= n; ! REG_WR32(qlt, 0x54, 0x6550); ! n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); ! buf += n; size_left -= n; ! REG_WR32(qlt, 0x54, 0x6560); ! n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); ! buf += n; size_left -= n; ! REG_WR32(qlt, 0x54, 0x6570); ! n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); ! buf += n; size_left -= n; ! REG_WR32(qlt, 0x54, 0x6580); ! n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); ! buf += n; size_left -= n; ! REG_WR32(qlt, 0x54, 0x6590); ! n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); ! buf += n; size_left -= n; ! REG_WR32(qlt, 0x54, 0x65A0); ! n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); ! buf += n; size_left -= n; ! REG_WR32(qlt, 0x54, 0x65B0); ! n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); ! buf += n; size_left -= n; ! REG_WR32(qlt, 0x54, 0x65C0); ! n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); ! buf += n; size_left -= n; ! REG_WR32(qlt, 0x54, 0x65D0); ! n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); ! buf += n; size_left -= n; ! REG_WR32(qlt, 0x54, 0x65E0); ! n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); ! buf += n; size_left -= n; ! } ! if ((qlt->qlt_25xx_chip) || (qlt->qlt_81xx_chip) || ! (qlt->qlt_83xx_chip)) { REG_WR32(qlt, 0x54, 0x6F00); n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); buf += n; size_left -= n; } + if (qlt->qlt_83xx_chip) { + n = (int)snprintf(buf, size_left, "\nAT0 Array registers\n"); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x7080); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x7090); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x70A0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x70B0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x70C0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x70D0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x70E0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + REG_WR32(qlt, 0x54, 0x70F0); + n = qlt_fwdump_dump_regs(qlt, buf, 0xc0, 16, size_left); + buf += n; size_left -= n; + } + + EL(qlt, "reset chip\n"); qlt->intr_sneak_counter = 10; mutex_enter(&qlt->intr_lock); + if (qlt->qlt_mq_enabled) { + for (i = 1; i < qlt->qlt_queue_cnt; i++) { + mutex_enter(&qlt->mq_resp[i].mq_lock); + } + } (void) qlt_reset_chip(qlt); drv_usecwait(20); qlt->intr_sneak_counter = 0; + if (qlt->qlt_mq_enabled) { + for (i = 1; i < qlt->qlt_queue_cnt; i++) { + mutex_exit(&qlt->mq_resp[i].mq_lock); + } + } mutex_exit(&qlt->intr_lock); + EL(qlt, "reset chip, done\n"); /* * Memory */ n = (int)snprintf(buf, size_left, "\nCode RAM\n"); buf += n; size_left -= n; addr = 0x20000; ! endaddr = (qlt->qlt_83xx_chip) ? 0x22400 : 0x22000; words_to_read = 0; while (addr < endaddr) { words_to_read = MBOX_DMA_MEM_SIZE >> 2; if ((words_to_read + addr) > endaddr) { words_to_read = endaddr - addr;
*** 5663,5704 **** /* * Queue dumping */ n = (int)snprintf(buf, size_left, "\nRequest Queue\n"); buf += n; size_left -= n; ! n = qlt_dump_queue(qlt, qlt->queue_mem_ptr + REQUEST_QUEUE_OFFSET, REQUEST_QUEUE_ENTRIES, buf, size_left); buf += n; size_left -= n; n = (int)snprintf(buf, size_left, "\nPriority Queue\n"); buf += n; size_left -= n; ! n = qlt_dump_queue(qlt, qlt->queue_mem_ptr + PRIORITY_QUEUE_OFFSET, PRIORITY_QUEUE_ENTRIES, buf, size_left); buf += n; size_left -= n; n = (int)snprintf(buf, size_left, "\nResponse Queue\n"); buf += n; size_left -= n; ! n = qlt_dump_queue(qlt, qlt->queue_mem_ptr + RESPONSE_QUEUE_OFFSET, RESPONSE_QUEUE_ENTRIES, buf, size_left); buf += n; size_left -= n; ! n = (int)snprintf(buf, size_left, "\nATIO queue\n"); buf += n; size_left -= n; n = qlt_dump_queue(qlt, qlt->queue_mem_ptr + ATIO_QUEUE_OFFSET, ATIO_QUEUE_ENTRIES, buf, size_left); buf += n; size_left -= n; /* * Label dump reason */ ! n = (int)snprintf(buf, size_left, "\nFirmware dump reason: %s-%s\n", qlt->qlt_port_alias, ssci->st_additional_info); buf += n; size_left -= n; dump_ok: EL(qlt, "left-%d\n", size_left); - mutex_enter(&qlt->qlt_ioctl_lock); qlt->qlt_ioctl_flags &= ~(QLT_FWDUMP_INPROGRESS | QLT_FWDUMP_FETCHED_BY_USER); qlt->qlt_ioctl_flags |= QLT_FWDUMP_ISVALID; mutex_exit(&qlt->qlt_ioctl_lock); --- 8922,9010 ---- /* * Queue dumping */ n = (int)snprintf(buf, size_left, "\nRequest Queue\n"); buf += n; size_left -= n; ! ! if (qlt->qlt_mq_enabled) { ! for (i = 0; i < qlt->qlt_queue_cnt; i++) { ! if (qlt->mq_req[i].queue_mem_mq_base_addr) { ! n = (int)snprintf(buf, size_left, ! "\nQueue %d:\n", i); ! buf += n; size_left -= n; ! n = qlt_dump_queue(qlt, ! qlt->mq_req[i].queue_mem_mq_base_addr, ! REQUEST_QUEUE_MQ_ENTRIES, ! buf, size_left); ! buf += n; size_left -= n; ! } ! } ! } else { ! n = (int)snprintf(buf, size_left, "\nQueue 0:\n"); ! buf += n; size_left -= n; ! n = qlt_dump_queue(qlt, ! qlt->queue_mem_ptr + REQUEST_QUEUE_OFFSET, REQUEST_QUEUE_ENTRIES, buf, size_left); buf += n; size_left -= n; + } + if (!qlt->qlt_83xx_chip) { n = (int)snprintf(buf, size_left, "\nPriority Queue\n"); buf += n; size_left -= n; ! n = qlt_dump_queue(qlt, ! qlt->queue_mem_ptr + PRIORITY_QUEUE_OFFSET, PRIORITY_QUEUE_ENTRIES, buf, size_left); buf += n; size_left -= n; + } n = (int)snprintf(buf, size_left, "\nResponse Queue\n"); buf += n; size_left -= n; ! ! if (qlt->qlt_mq_enabled) { ! for (i = 0; i < qlt->qlt_queue_cnt; i++) { ! if (qlt->mq_resp[i].queue_mem_mq_base_addr) { ! n = (int)snprintf(buf, size_left, ! "\nQueue %d:\n", i); ! buf += n; size_left -= n; ! n = qlt_dump_queue(qlt, ! qlt->mq_resp[i].queue_mem_mq_base_addr, ! RESPONSE_QUEUE_MQ_ENTRIES, ! buf, size_left); ! buf += n; size_left -= n; ! } ! } ! } else { ! n = (int)snprintf(buf, size_left, "\nQueue 0:\n"); ! buf += n; size_left -= n; ! n = qlt_dump_queue(qlt, ! qlt->queue_mem_ptr + RESPONSE_QUEUE_OFFSET, RESPONSE_QUEUE_ENTRIES, buf, size_left); buf += n; size_left -= n; + } ! n = (int)snprintf(buf, size_left, "\nATIO Queue\nQueue 0:\n"); buf += n; size_left -= n; n = qlt_dump_queue(qlt, qlt->queue_mem_ptr + ATIO_QUEUE_OFFSET, ATIO_QUEUE_ENTRIES, buf, size_left); buf += n; size_left -= n; /* * Label dump reason */ ! if (ssci != NULL) { ! n = (int)snprintf(buf, size_left, ! "\nFirmware dump reason: %s-%s\n", qlt->qlt_port_alias, ssci->st_additional_info); + } else { + n = (int)snprintf(buf, size_left, + "\nFirmware dump reason: %s-%s\n", + qlt->qlt_port_alias, "no additional infor"); + } buf += n; size_left -= n; dump_ok: EL(qlt, "left-%d\n", size_left); mutex_enter(&qlt->qlt_ioctl_lock); qlt->qlt_ioctl_flags &= ~(QLT_FWDUMP_INPROGRESS | QLT_FWDUMP_FETCHED_BY_USER); qlt->qlt_ioctl_flags |= QLT_FWDUMP_ISVALID; mutex_exit(&qlt->qlt_ioctl_lock);
*** 5764,5778 **** { int i; int n; char c = ' '; int words; ! uint16_t *ptr; ! uint16_t w; ! words = entries * 32; ! ptr = (uint16_t *)qadr; for (i = 0, n = 0; i < words; i++) { if ((i & 7) == 0) { n = (int)(n + (int)snprintf(&buf[n], (uint_t)(size_left - n), "%05x: ", i)); } --- 9070,9084 ---- { int i; int n; char c = ' '; int words; ! uint32_t *ptr; ! uint32_t w; ! words = entries * 16; ! ptr = (uint32_t *)qadr; for (i = 0, n = 0; i < words; i++) { if ((i & 7) == 0) { n = (int)(n + (int)snprintf(&buf[n], (uint_t)(size_left - n), "%05x: ", i)); }
*** 5779,5790 **** if ((i + 1) & 7) { c = ' '; } else { c = '\n'; } ! w = QMEM_RD16(qlt, &ptr[i]); ! n = (int)(n + (int)snprintf(&buf[n], (size_left - n), "%04x%c", w, c)); } return (n); } --- 9085,9096 ---- if ((i + 1) & 7) { c = ' '; } else { c = '\n'; } ! w = QMEM_RD32(qlt, &ptr[i]); ! n = (int)(n + (int)snprintf(&buf[n], (size_left - n), "%08x%c", w, c)); } return (n); }
*** 5821,5845 **** REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); if (ret == QLT_SUCCESS) { (void) ddi_dma_sync(qlt->queue_mem_dma_handle, MBOX_DMA_MEM_OFFSET, words << 2, DDI_DMA_SYNC_FORCPU); } else { ! EL(qlt, "qlt_raw_mailbox_command=ch status=%llxh\n", ret); } return (ret); } static void qlt_verify_fw(qlt_state_t *qlt) { caddr_t req; /* Just put it on the request queue */ ! mutex_enter(&qlt->req_lock); ! req = qlt_get_req_entries(qlt, 1); if (req == NULL) { ! mutex_exit(&qlt->req_lock); ! /* XXX handle this */ return; } bzero(req, IOCB_SIZE); --- 9127,9190 ---- REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); if (ret == QLT_SUCCESS) { (void) ddi_dma_sync(qlt->queue_mem_dma_handle, MBOX_DMA_MEM_OFFSET, words << 2, DDI_DMA_SYNC_FORCPU); } else { ! EL(qlt, "qlt_raw_mailbox_command=0x0ch status=%llxh\n", ret); } return (ret); } + static fct_status_t + qlt_mbx_mpi_ram(qlt_state_t *qlt, uint32_t addr, uint32_t words, + uint16_t direction) + { + uint64_t da; + fct_status_t ret; + + REG_WR16(qlt, REG_MBOX(0), MBC_MPI_RAM); + da = qlt->queue_mem_cookie.dmac_laddress; + da += MBOX_DMA_MEM_OFFSET; + + /* System destination address */ + REG_WR16(qlt, REG_MBOX(3), LSW(LSD(da))); + REG_WR16(qlt, REG_MBOX(2), MSW(LSD(da))); + REG_WR16(qlt, REG_MBOX(7), LSW(MSD(da))); + REG_WR16(qlt, REG_MBOX(6), MSW(MSD(da))); + + /* Length */ + REG_WR16(qlt, REG_MBOX(5), LSW(words)); + REG_WR16(qlt, REG_MBOX(4), MSW(words)); + + /* RISC source address */ + REG_WR16(qlt, REG_MBOX(1), LSW(addr)); + REG_WR16(qlt, REG_MBOX(8), MSW(addr)); + + REG_WR16(qlt, REG_MBOX(9), direction); + ret = qlt_raw_mailbox_command(qlt); + REG_WR32(qlt, REG_HCCR, HCCR_CMD(CLEAR_RISC_TO_PCI_INTR)); + if (ret == QLT_SUCCESS) { + (void) ddi_dma_sync(qlt->queue_mem_dma_handle, + MBOX_DMA_MEM_OFFSET, words << 2, DDI_DMA_SYNC_FORCPU); + } else { + EL(qlt, "qlt_raw_mailbox_command=0x05h status=%llxh\n", ret); + } + return (ret); + } + static void qlt_verify_fw(qlt_state_t *qlt) { caddr_t req; + uint16_t qi = 0; + /* Just put it on the request queue */ ! mutex_enter(&qlt->mq_req[qi].mq_lock); ! req = qlt_get_req_entries(qlt, 1, qi); if (req == NULL) { ! EL(qlt, "req = NULL\n"); ! mutex_exit(&qlt->mq_req[qi].mq_lock); return; } bzero(req, IOCB_SIZE);
*** 5848,5879 **** QMEM_WR32(qlt, (&req[4]), 0xffffffff); QMEM_WR16(qlt, (&req[0x8]), 1); /* options - don't update */ QMEM_WR32(qlt, (&req[0x14]), 0x80010300); ! qlt_submit_req_entries(qlt, 1); ! mutex_exit(&qlt->req_lock); } static void qlt_handle_verify_fw_completion(qlt_state_t *qlt, uint8_t *rsp) { uint16_t status; ! char info[QLT_INFO_LEN]; status = QMEM_RD16(qlt, rsp+8); if (status != 0) { ! (void) snprintf(info, sizeof (info), ! "qlt_handle_verify_fw_completion: " "status:%x, rsp:%p", status, (void *)rsp); if (status == 3) { uint16_t error_code; error_code = QMEM_RD16(qlt, rsp+0xA); ! (void) snprintf(info, sizeof (info), ! "qlt_handle_verify_fw_completion: error code:%x", ! error_code); } } } /* --- 9193,9349 ---- QMEM_WR32(qlt, (&req[4]), 0xffffffff); QMEM_WR16(qlt, (&req[0x8]), 1); /* options - don't update */ QMEM_WR32(qlt, (&req[0x14]), 0x80010300); ! qlt_submit_req_entries(qlt, 1, qi); ! mutex_exit(&qlt->mq_req[qi].mq_lock); } + static fct_status_t + qlt_mq_destroy(qlt_state_t *qlt) + { + int idx; + + for (idx = 1; idx < qlt->qlt_queue_cnt; idx++) { + (void) ddi_dma_unbind_handle( + qlt->mq_req[idx].queue_mem_mq_dma_handle); + ddi_dma_mem_free(&qlt->mq_req[idx].queue_mem_mq_acc_handle); + ddi_dma_free_handle(&qlt->mq_req[idx].queue_mem_mq_dma_handle); + (void) ddi_dma_unbind_handle( + qlt->mq_resp[idx].queue_mem_mq_dma_handle); + ddi_dma_mem_free(&qlt->mq_resp[idx].queue_mem_mq_acc_handle); + ddi_dma_free_handle(&qlt->mq_resp[idx].queue_mem_mq_dma_handle); + } + return (QLT_SUCCESS); + } + + static fct_status_t + qlt_mq_create(qlt_state_t *qlt, int idx) + { + ddi_device_acc_attr_t dev_acc_attr; + size_t discard; + uint_t ncookies; + + dev_acc_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; + dev_acc_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; + dev_acc_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; + + /* + * MQ Request queue + */ + if (ddi_dma_alloc_handle(qlt->dip, &qlt_queue_dma_attr_mq_req1, + DDI_DMA_SLEEP, 0, + &qlt->mq_req[idx].queue_mem_mq_dma_handle) != DDI_SUCCESS) { + return (QLT_FAILURE); + } + if (ddi_dma_mem_alloc(qlt->mq_req[idx].queue_mem_mq_dma_handle, + REQUEST_QUEUE_MQ_SIZE, + &dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0, + &qlt->mq_req[idx].queue_mem_mq_base_addr, &discard, + &qlt->mq_req[idx].queue_mem_mq_acc_handle) != DDI_SUCCESS) { + ddi_dma_free_handle(&qlt->mq_req[idx].queue_mem_mq_dma_handle); + return (QLT_FAILURE); + } + if (ddi_dma_addr_bind_handle( + qlt->mq_req[idx].queue_mem_mq_dma_handle, + NULL, qlt->mq_req[idx].queue_mem_mq_base_addr, + REQUEST_QUEUE_MQ_SIZE, + DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0, + &qlt->mq_req[idx].queue_mem_mq_cookie, + &ncookies) != DDI_SUCCESS) { + ddi_dma_mem_free(&qlt->mq_req[idx].queue_mem_mq_acc_handle); + ddi_dma_free_handle(&qlt->mq_req[idx].queue_mem_mq_dma_handle); + return (QLT_FAILURE); + } + if (ncookies != 1) { + (void) ddi_dma_unbind_handle( + qlt->mq_req[idx].queue_mem_mq_dma_handle); + ddi_dma_mem_free(&qlt->mq_req[idx].queue_mem_mq_acc_handle); + ddi_dma_free_handle(&qlt->mq_req[idx].queue_mem_mq_dma_handle); + return (QLT_FAILURE); + } + + /* + * MQ Response queue + */ + if (ddi_dma_alloc_handle(qlt->dip, &qlt_queue_dma_attr_mq_rsp1, + DDI_DMA_SLEEP, 0, + &qlt->mq_resp[idx].queue_mem_mq_dma_handle) != DDI_SUCCESS) { + (void) ddi_dma_unbind_handle( + qlt->mq_req[idx].queue_mem_mq_dma_handle); + ddi_dma_mem_free(&qlt->mq_req[idx].queue_mem_mq_acc_handle); + ddi_dma_free_handle(&qlt->mq_req[idx].queue_mem_mq_dma_handle); + return (QLT_FAILURE); + } + if (ddi_dma_mem_alloc(qlt->mq_resp[idx].queue_mem_mq_dma_handle, + RESPONSE_QUEUE_MQ_SIZE, + &dev_acc_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0, + &qlt->mq_resp[idx].queue_mem_mq_base_addr, &discard, + &qlt->mq_resp[idx].queue_mem_mq_acc_handle) != DDI_SUCCESS) { + (void) ddi_dma_unbind_handle( + qlt->mq_req[idx].queue_mem_mq_dma_handle); + ddi_dma_mem_free(&qlt->mq_req[idx].queue_mem_mq_acc_handle); + ddi_dma_free_handle(&qlt->mq_req[idx].queue_mem_mq_dma_handle); + ddi_dma_free_handle(&qlt->mq_resp[idx].queue_mem_mq_dma_handle); + return (QLT_FAILURE); + } + if (ddi_dma_addr_bind_handle( + qlt->mq_resp[idx].queue_mem_mq_dma_handle, + NULL, qlt->mq_resp[idx].queue_mem_mq_base_addr, + RESPONSE_QUEUE_MQ_SIZE, + DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0, + &qlt->mq_resp[idx].queue_mem_mq_cookie, + &ncookies) != DDI_SUCCESS) { + (void) ddi_dma_unbind_handle( + qlt->mq_req[idx].queue_mem_mq_dma_handle); + ddi_dma_mem_free(&qlt->mq_req[idx].queue_mem_mq_acc_handle); + ddi_dma_free_handle(&qlt->mq_req[idx].queue_mem_mq_dma_handle); + ddi_dma_mem_free(&qlt->mq_resp[idx].queue_mem_mq_acc_handle); + ddi_dma_free_handle(&qlt->mq_resp[idx].queue_mem_mq_dma_handle); + return (QLT_FAILURE); + } + if (ncookies != 1) { + (void) ddi_dma_unbind_handle( + qlt->mq_req[idx].queue_mem_mq_dma_handle); + ddi_dma_mem_free(&qlt->mq_req[idx].queue_mem_mq_acc_handle); + ddi_dma_free_handle(&qlt->mq_req[idx].queue_mem_mq_dma_handle); + (void) ddi_dma_unbind_handle( + qlt->mq_resp[idx].queue_mem_mq_dma_handle); + ddi_dma_mem_free(&qlt->mq_resp[idx].queue_mem_mq_acc_handle); + ddi_dma_free_handle(&qlt->mq_resp[idx].queue_mem_mq_dma_handle); + return (QLT_FAILURE); + } + + qlt->mq_req[idx].mq_ptr = qlt->mq_req[idx].queue_mem_mq_base_addr; + qlt->mq_req[idx].mq_ndx_to_fw = qlt->mq_req[idx].mq_ndx_from_fw = 0; + qlt->mq_req[idx].mq_available = REQUEST_QUEUE_MQ_ENTRIES - 1; + bzero(qlt->mq_req[idx].mq_ptr, REQUEST_QUEUE_MQ_SIZE); + + qlt->mq_resp[idx].mq_ptr = qlt->mq_resp[idx].queue_mem_mq_base_addr; + qlt->mq_resp[idx].mq_ndx_to_fw = qlt->mq_resp[idx].mq_ndx_from_fw = 0; + bzero(qlt->mq_resp[idx].mq_ptr, RESPONSE_QUEUE_MQ_SIZE); + + return (QLT_SUCCESS); + } + static void qlt_handle_verify_fw_completion(qlt_state_t *qlt, uint8_t *rsp) { uint16_t status; ! char info[80]; status = QMEM_RD16(qlt, rsp+8); if (status != 0) { ! (void) snprintf(info, 80, "qlt_handle_verify_fw_completion: " "status:%x, rsp:%p", status, (void *)rsp); if (status == 3) { uint16_t error_code; error_code = QMEM_RD16(qlt, rsp+0xA); ! (void) snprintf(info, 80, "qlt_handle_verify_fw_" ! "completion: error code:%x", error_code); } } } /*
*** 5884,5923 **** * Context: Kernel context. */ static int qlt_el_trace_desc_ctor(qlt_state_t *qlt) { ! int rval = DDI_SUCCESS; ! qlt->el_trace_desc = (qlt_el_trace_desc_t *) ! kmem_zalloc(sizeof (qlt_el_trace_desc_t), KM_SLEEP); ! if (qlt->el_trace_desc == NULL) { ! cmn_err(CE_WARN, "qlt(%d): can't construct trace descriptor", ! qlt->instance); ! rval = DDI_FAILURE; ! } else { ! qlt->el_trace_desc->next = 0; ! qlt->el_trace_desc->trace_buffer = ! (char *)kmem_zalloc(EL_TRACE_BUF_SIZE, KM_SLEEP); ! if (qlt->el_trace_desc->trace_buffer == NULL) { ! cmn_err(CE_WARN, "qlt(%d): can't get trace buffer", ! qlt->instance); ! kmem_free(qlt->el_trace_desc, ! sizeof (qlt_el_trace_desc_t)); ! qlt->el_trace_desc = NULL; ! rval = DDI_FAILURE; ! } else { ! qlt->el_trace_desc->trace_buffer_size = ! EL_TRACE_BUF_SIZE; ! mutex_init(&qlt->el_trace_desc->mutex, NULL, MUTEX_DRIVER, NULL); - } - } ! return (rval); } /* * qlt_el_trace_desc_dtor - Destroy an extended logging trace descriptor. * --- 9354,9387 ---- * Context: Kernel context. */ static int qlt_el_trace_desc_ctor(qlt_state_t *qlt) { ! qlt_trace_entry_t *entry; ! size_t maxsize; ! qlt->qlt_trace_desc = ! (qlt_trace_desc_t *)kmem_zalloc( ! sizeof (qlt_trace_desc_t), KM_SLEEP); ! qlt->qlt_log_entries = QL_LOG_ENTRIES; ! maxsize = qlt->qlt_log_entries * sizeof (qlt_trace_entry_t); ! entry = kmem_zalloc(maxsize, KM_SLEEP); ! mutex_init(&qlt->qlt_trace_desc->mutex, NULL, MUTEX_DRIVER, NULL); ! qlt->qlt_trace_desc->trace_buffer = entry; ! qlt->qlt_trace_desc->trace_buffer_size = maxsize; ! qlt->qlt_trace_desc->nindex = 0; ! ! qlt->qlt_trace_desc->nentries = qlt->qlt_log_entries; ! qlt->qlt_trace_desc->start = qlt->qlt_trace_desc->end = 0; ! qlt->qlt_trace_desc->csize = 0; ! qlt->qlt_trace_desc->count = 0; ! ! return (DDI_SUCCESS); } /* * qlt_el_trace_desc_dtor - Destroy an extended logging trace descriptor. *
*** 5928,5949 **** static int qlt_el_trace_desc_dtor(qlt_state_t *qlt) { int rval = DDI_SUCCESS; ! if (qlt->el_trace_desc == NULL) { ! cmn_err(CE_WARN, "qlt(%d): can't destroy el trace descriptor", ! qlt->instance); ! rval = DDI_FAILURE; ! } else { ! if (qlt->el_trace_desc->trace_buffer != NULL) { ! kmem_free(qlt->el_trace_desc->trace_buffer, ! qlt->el_trace_desc->trace_buffer_size); } ! mutex_destroy(&qlt->el_trace_desc->mutex); ! kmem_free(qlt->el_trace_desc, sizeof (qlt_el_trace_desc_t)); ! qlt->el_trace_desc = NULL; } return (rval); } --- 9392,9408 ---- static int qlt_el_trace_desc_dtor(qlt_state_t *qlt) { int rval = DDI_SUCCESS; ! if (qlt->qlt_trace_desc != NULL) { ! if (qlt->qlt_trace_desc->trace_buffer != NULL) { ! kmem_free(qlt->qlt_trace_desc->trace_buffer, ! qlt->qlt_trace_desc->trace_buffer_size); } ! mutex_destroy(&qlt->qlt_trace_desc->mutex); ! kmem_free(qlt->qlt_trace_desc, sizeof (qlt_trace_desc_t)); } return (rval); }
*** 5962,6154 **** */ void qlt_el_msg(qlt_state_t *qlt, const char *fn, int ce, ...) { char *s, *fmt = 0, *fmt1 = 0; ! char fmt2[EL_BUFFER_RESERVE]; ! int rval, tmp; ! int tracing = 0; va_list vl; ! /* Tracing is the default but it can be disabled. */ ! if ((rval = qlt_validate_trace_desc(qlt)) == DDI_SUCCESS) { ! tracing = 1; ! mutex_enter(&qlt->el_trace_desc->mutex); /* ! * Ensure enough space for the string. Wrap to ! * start when default message allocation size ! * would overrun the end. */ ! if ((qlt->el_trace_desc->next + EL_BUFFER_RESERVE) >= ! qlt->el_trace_desc->trace_buffer_size) { ! fmt = qlt->el_trace_desc->trace_buffer; ! qlt->el_trace_desc->next = 0; ! } else { ! fmt = qlt->el_trace_desc->trace_buffer + ! qlt->el_trace_desc->next; } - } ! /* if no buffer use the stack */ ! if (fmt == NULL) { ! fmt = fmt2; ! } ! va_start(vl, ce); ! s = va_arg(vl, char *); ! rval = (int)snprintf(fmt, (size_t)EL_BUFFER_RESERVE, ! "QEL qlt(%d): %s, ", qlt->instance, fn); ! fmt1 = fmt + rval; ! tmp = (int)vsnprintf(fmt1, (size_t)(uint32_t)((int)EL_BUFFER_RESERVE - rval), s, vl); rval += tmp; /* ! * Calculate the offset where the next message will go, ! * skipping the NULL. */ ! if (tracing) { ! uint16_t next = (uint16_t)(rval += 1); ! qlt->el_trace_desc->next += next; ! mutex_exit(&qlt->el_trace_desc->mutex); } ! if (enable_extended_logging) { ! cmn_err(ce, fmt); } ! va_end(vl); ! } ! /* ! * qlt_dump_el_trace_buffer ! * Outputs extended logging trace buffer. ! * ! * Input: ! * qlt: adapter state pointer. ! */ ! void ! qlt_dump_el_trace_buffer(qlt_state_t *qlt) ! { ! char *dump_start = NULL; ! char *dump_current = NULL; ! char *trace_start; ! char *trace_end; ! int wrapped = 0; ! int rval; ! mutex_enter(&qlt->el_trace_desc->mutex); ! ! rval = qlt_validate_trace_desc(qlt); ! if (rval != NULL) { ! cmn_err(CE_CONT, "qlt(%d) Dump EL trace - invalid desc\n", ! qlt->instance); ! } else if ((dump_start = qlt_find_trace_start(qlt)) != NULL) { ! dump_current = dump_start; ! trace_start = qlt->el_trace_desc->trace_buffer; ! trace_end = trace_start + ! qlt->el_trace_desc->trace_buffer_size; ! ! cmn_err(CE_CONT, "qlt(%d) Dump EL trace - start %p %p\n", ! qlt->instance, ! (void *)dump_start, (void *)trace_start); ! ! while (((uintptr_t)dump_current - (uintptr_t)trace_start) <= ! (uintptr_t)qlt->el_trace_desc->trace_buffer_size) { ! /* Show it... */ ! cmn_err(CE_CONT, "%p - %s", (void *)dump_current, ! dump_current); ! /* Make the next the current */ ! dump_current += (strlen(dump_current) + 1); ! /* check for wrap */ ! if ((dump_current + EL_BUFFER_RESERVE) >= trace_end) { ! dump_current = trace_start; ! wrapped = 1; ! } else if (wrapped) { ! /* Don't go past next. */ ! if ((trace_start + qlt->el_trace_desc->next) <= ! dump_current) { ! break; } - } else if (*dump_current == NULL) { - break; - } - } - } - mutex_exit(&qlt->el_trace_desc->mutex); - } ! /* ! * qlt_validate_trace_desc ! * Ensures the extended logging trace descriptor is good. ! * ! * Input: ! * qlt: adapter state pointer. ! * ! * Returns: ! * ql local function return status code. ! */ ! static int ! qlt_validate_trace_desc(qlt_state_t *qlt) ! { ! int rval = DDI_SUCCESS; ! if (qlt->el_trace_desc == NULL) { ! rval = DDI_FAILURE; ! } else if (qlt->el_trace_desc->trace_buffer == NULL) { ! rval = DDI_FAILURE; } - return (rval); - } ! /* ! * qlt_find_trace_start ! * Locate the oldest extended logging trace entry. ! * ! * Input: ! * qlt: adapter state pointer. ! * ! * Returns: ! * Pointer to a string. ! * ! * Context: ! * Kernel/Interrupt context. ! */ ! static char * ! qlt_find_trace_start(qlt_state_t *qlt) ! { ! char *trace_start = 0; ! char *trace_next = 0; ! trace_next = qlt->el_trace_desc->trace_buffer + ! qlt->el_trace_desc->next; ! /* ! * If the buffer has not wrapped next will point at a null so ! * start is the beginning of the buffer. If next points at a char ! * then we must traverse the buffer until a null is detected and ! * that will be the beginning of the oldest whole object in the buffer ! * which is the start. ! */ ! if ((trace_next + EL_BUFFER_RESERVE) >= ! (qlt->el_trace_desc->trace_buffer + ! qlt->el_trace_desc->trace_buffer_size)) { ! trace_start = qlt->el_trace_desc->trace_buffer; ! } else if (*trace_next != NULL) { ! trace_start = trace_next + (strlen(trace_next) + 1); ! } else { ! trace_start = qlt->el_trace_desc->trace_buffer; } - return (trace_start); } - static int qlt_read_int_prop(qlt_state_t *qlt, char *prop, int defval) { return (ddi_getprop(DDI_DEV_T_ANY, qlt->dip, DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, prop, defval)); --- 9421,9552 ---- */ void qlt_el_msg(qlt_state_t *qlt, const char *fn, int ce, ...) { char *s, *fmt = 0, *fmt1 = 0; ! ! /* ! * EL_BUFFER_RESERVE 256 is the max # of bytes ! * that driver's log could be collected. ! * add 3 more buytes for safely maniplulation. ! */ ! char buf[EL_BUFFER_RESERVE + 3]; ! char buf1[QL_LOG_LENGTH]; ! size_t tmp; ! size_t rval, rval1; va_list vl; + qlt_trace_desc_t *desc = qlt->qlt_trace_desc; + qlt_trace_entry_t *entry; + uint32_t cindex; + timespec_t time; + uint32_t count; + size_t left; ! (void) bzero((void *)&buf[0], EL_BUFFER_RESERVE + 3); ! fmt1 = &buf[0]; ! TRACE_BUFFER_LOCK(qlt); + /* locate the entry to be filled out */ + cindex = desc->nindex; + entry = &desc->trace_buffer[cindex]; + + count = desc->count; + + desc->end = desc->nindex; + desc->nindex++; + if (desc->nindex == desc->nentries) { + desc->nindex = 0; + } + + if (desc->csize < desc->nentries) { + desc->csize ++; + } else { /* ! * once wrapped, csize is fixed. ! * so we have to adjust start point */ ! desc->start = desc->nindex; } ! gethrestime(&time); ! rval = snprintf(fmt1, (size_t)EL_BUFFER_RESERVE, ! QL_BANG "%d=>QEL %s(%d,%d):: %s, ", count, QL_NAME, ! qlt->instance, 0, fn); ! rval1 = rval; ! va_start(vl, ce); ! s = va_arg(vl, char *); ! fmt = fmt1 + rval; ! tmp = vsnprintf(fmt, (size_t)(uint32_t)((int)EL_BUFFER_RESERVE - rval), s, vl); + va_end(vl); + rval += tmp; + if (rval > QL_LOG_LENGTH - 1) { + left = rval - (QL_LOG_LENGTH - 1); + /* store the remaining string */ + (void) strncpy(buf1, fmt1 + (QL_LOG_LENGTH - 1), left); + (void) strncpy(entry->buf, fmt1, (QL_LOG_LENGTH - 1)); + entry->buf[QL_LOG_LENGTH - 1] = '\n'; + + bcopy((void *)&time, (void *)&entry->hs_time, + sizeof (timespec_t)); + /* ! * remaining msg will be stored in the nex entry ! * with same timestamp and same sequence number */ ! cindex = desc->nindex; ! entry = &desc->trace_buffer[cindex]; ! ! desc->end = desc->nindex; ! desc->nindex++; ! if (desc->nindex == desc->nentries) { ! desc->nindex = 0; } ! if (desc->csize < desc->nentries) { ! desc->csize ++; ! } else { ! desc->start = desc->nindex; } ! (void) strncpy(&entry->buf[0], fmt1, rval1); ! (void) strncpy(&entry->buf[rval1], &buf1[0], left); ! entry->buf[rval1 + left] = 0; ! bcopy((void *)&time, (void *)&entry->hs_time, ! sizeof (timespec_t)); ! if (qlt->qlt_eel_level == 1) { ! cmn_err(ce, fmt1); } ! desc->count++; ! TRACE_BUFFER_UNLOCK(qlt); ! return; } ! desc->count ++; ! bcopy((void *)&time, (void *)&entry->hs_time, ! sizeof (timespec_t)); ! (void) strcpy(entry->buf, fmt1); ! entry->buf[rval] = 0; ! TRACE_BUFFER_UNLOCK(qlt); ! if (qlt->qlt_eel_level == 1) { ! cmn_err(ce, fmt1); } } static int qlt_read_int_prop(qlt_state_t *qlt, char *prop, int defval) { return (ddi_getprop(DDI_DEV_T_ANY, qlt->dip, DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, prop, defval));
*** 6306,6320 **** --- 9704,9722 ---- uint32_t data, dctl = 1000; do { if (dctl-- == 0 || qlt_raw_wrt_risc_ram_word(qlt, 0x7c00, 1) != QLT_SUCCESS) { + EL(qlt, "qlt_mps_reset: semaphore request fail," + " cnt=%d\n", dctl); return; } if (qlt_raw_rd_risc_ram_word(qlt, 0x7c00, &data) != QLT_SUCCESS) { (void) qlt_raw_wrt_risc_ram_word(qlt, 0x7c00, 0); + EL(qlt, "qlt_mps_reset: semaphore read fail," + " cnt=%d\n", dctl); return; } } while (!(data & BIT_0)); if (qlt_raw_rd_risc_ram_word(qlt, 0x7A15, &data) == QLT_SUCCESS) {
*** 6322,6331 **** --- 9724,9735 ---- if ((data & 0xe0) != (dctl & 0xe0)) { data &= 0xff1f; data |= dctl & 0xe0; (void) qlt_raw_wrt_risc_ram_word(qlt, 0x7A15, data); } + } else { + EL(qlt, "qlt_mps_reset: read 0x7a15 failed.\n"); } (void) qlt_raw_wrt_risc_ram_word(qlt, 0x7c00, 0); } /*
*** 6400,6409 **** --- 9804,9820 ---- if (qlt_wwn_overload_prop(qlt) == TRUE) { EL(qlt, "wwnn overloaded.\n"); } + /* configure extended logging from conf file */ + if ((cnt = qlt_read_int_instance_prop(qlt, "extended-logging", + defval)) != defval) { + qlt->qlt_eel_level = (uint8_t)(cnt & 0xff); + EL(qlt, "extended error logging=%d\n", cnt); + } + if ((cnt = qlt_read_int_instance_prop(qlt, "bucketcnt2k", defval)) != defval) { qlt->qlt_bucketcnt[0] = cnt; EL(qlt, "2k bucket o/l=%d\n", cnt); }
*** 6429,6434 **** --- 9840,10840 ---- if ((cnt = qlt_read_int_instance_prop(qlt, "bucketcnt256", defval)) != defval) { qlt->qlt_bucketcnt[4] = cnt; EL(qlt, "256k bucket o/l=%d\n", cnt); } + } + + /* ******************************************************************* */ + /* ****************** 27xx Dump Template Functions ******************* */ + /* ******************************************************************* */ + + /* + * qlt_get_dmp_template + * Get dump template from firmware module + * + * Input: + * qlt: qlt_state_t pointer. + * + * Returns: + * qlt local function return status code. + * + * Context: + * Kernel context. + */ + static fct_status_t + qlt_27xx_get_dmp_template(qlt_state_t *qlt) + { + ddi_device_acc_attr_t dev_acc_attr; + dev_info_t *dip = qlt->dip; + uint_t ncookies; + size_t discard; + uint32_t word_count, cnt, *bp, *dp; + + if (qlt->dmp_template_dma_handle != NULL) { + (void) ddi_dma_unbind_handle(qlt->dmp_template_dma_handle); + if (qlt->dmp_template_acc_handle != NULL) { + ddi_dma_mem_free(&qlt->dmp_template_acc_handle); + } + ddi_dma_free_handle(&qlt->dmp_template_dma_handle); + } + + if ((word_count = tmplt2700_length01) == 0) { + EL(qlt, "No dump template, length=0\n"); + return (QLT_FAILURE); + } + + dev_acc_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; + dev_acc_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; + dev_acc_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; + + if (ddi_dma_alloc_handle(dip, &qlt_queue_dma_attr, + DDI_DMA_SLEEP, 0, &qlt->dmp_template_dma_handle) != + DDI_SUCCESS) { + EL(qlt, "Unable to allocate template handle"); + return (QLT_FAILURE); + } + + if (ddi_dma_mem_alloc(qlt->dmp_template_dma_handle, + (word_count << 2), &dev_acc_attr, DDI_DMA_CONSISTENT, + DDI_DMA_SLEEP, 0, &qlt->dmp_template_addr, &discard, + &qlt->dmp_template_acc_handle) != DDI_SUCCESS) { + ddi_dma_free_handle(&qlt->dmp_template_dma_handle); + EL(qlt, "Unable to allocate template buffer"); + return (QLT_FAILURE); + } + + if (ddi_dma_addr_bind_handle(qlt->dmp_template_dma_handle, NULL, + qlt->dmp_template_addr, (word_count << 2), + DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0, + &qlt->dmp_template_cookie, &ncookies) != DDI_SUCCESS) { + ddi_dma_mem_free(&qlt->dmp_template_acc_handle); + ddi_dma_free_handle(&qlt->dmp_template_dma_handle); + EL(qlt, "Unable to bind template handle"); + return (QLT_FAILURE); + } + + if (ncookies != 1) { + (void) ddi_dma_unbind_handle(qlt->dmp_template_dma_handle); + ddi_dma_mem_free(&qlt->dmp_template_acc_handle); + ddi_dma_free_handle(&qlt->dmp_template_dma_handle); + EL(qlt, "cookies (%d) > 1.\n", ncookies); + return (QLT_FAILURE); + } + + /* Get big endian template. */ + bp = (uint32_t *)qlt->dmp_template_addr; + dp = (uint32_t *)tmplt2700_code01; + for (cnt = 0; cnt < word_count; cnt++) { + ddi_put32(qlt->dmp_template_acc_handle, bp, *dp++); + if (cnt > 6) { + qlt_chg_endian((uint8_t *)bp, 4); + } + bp++; + } + + return (QLT_SUCCESS); + } + + static int + qlt_27xx_dt_riob1(qlt_state_t *qlt, qlt_dt_riob1_t *entry, + uint8_t *dbuff, uint8_t *dbuff_end) + { + int esize; + uint32_t i, cnt; + uint8_t *bp = dbuff; + uint32_t addr = entry->addr; + uint32_t reg = entry->pci_offset; + + cnt = CHAR_TO_SHORT(entry->reg_count_l, entry->reg_count_h); + esize = cnt * 4; /* addr */ + esize += cnt * entry->reg_size; /* data */ + + if (dbuff == NULL) { + return (esize); + } + if (esize + dbuff >= dbuff_end) { + EL(qlt, "skipped, no buffer space, needed=%xh\n", esize); + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + return (0); + } + + REG_WR32(qlt, REG_IOBUS_BASE_ADDR, addr); + while (cnt--) { + *bp++ = LSB(LSW(addr)); + *bp++ = MSB(LSW(addr)); + *bp++ = LSB(MSW(addr)); + *bp++ = MSB(MSW(addr)); + for (i = 0; i < entry->reg_size; i++) { + *bp++ = REG_RD8(qlt, reg++); + } + addr++; + } + + return (esize); + } + + static void + qlt_27xx_dt_wiob1(qlt_state_t *qlt, qlt_dt_wiob1_t *entry, + uint8_t *dbuff, uint8_t *dbuff_end) + { + uint32_t reg = entry->pci_offset; + + if (dbuff == NULL) { + return; + } + if (dbuff >= dbuff_end) { + EL(qlt, "skipped, no buffer space, needed=0\n"); + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + return; + } + + REG_WR32(qlt, REG_IOBUS_BASE_ADDR, entry->addr); + REG_WR32(qlt, reg, entry->data); + } + + static int + qlt_27xx_dt_riob2(qlt_state_t *qlt, qlt_dt_riob2_t *entry, + uint8_t *dbuff, uint8_t *dbuff_end) + { + int esize; + uint32_t i, cnt; + uint8_t *bp = dbuff; + uint32_t reg = entry->pci_offset; + uint32_t addr = entry->addr; + + cnt = CHAR_TO_SHORT(entry->reg_count_l, entry->reg_count_h); + esize = cnt * 4; /* addr */ + esize += cnt * entry->reg_size; /* data */ + + if (dbuff == NULL) { + return (esize); + } + if (esize + dbuff >= dbuff_end) { + EL(qlt, "skipped, no buffer space, needed=%xh\n", esize); + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + return (0); + } + + REG_WR32(qlt, REG_IOBUS_BASE_ADDR, addr); + REG_WR32(qlt, entry->bank_sel_offset, entry->reg_bank); + while (cnt--) { + *bp++ = LSB(LSW(addr)); + *bp++ = MSB(LSW(addr)); + *bp++ = LSB(MSW(addr)); + *bp++ = MSB(MSW(addr)); + for (i = 0; i < entry->reg_size; i++) { + *bp++ = REG_RD8(qlt, reg++); + } + addr++; + } + + return (esize); + } + + static void + qlt_27xx_dt_wiob2(qlt_state_t *qlt, qlt_dt_wiob2_t *entry, + uint8_t *dbuff, uint8_t *dbuff_end) + { + uint16_t data; + uint32_t reg = entry->pci_offset; + + if (dbuff == NULL) { + return; + } + if (dbuff >= dbuff_end) { + EL(qlt, "skipped, no buffer space, needed=0\n"); + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + return; + } + + data = CHAR_TO_SHORT(entry->data_l, entry->data_h); + + REG_WR32(qlt, REG_IOBUS_BASE_ADDR, entry->addr); + REG_WR32(qlt, entry->bank_sel_offset, entry->reg_bank); + REG_WR16(qlt, reg, data); + } + + static int + qlt_27xx_dt_rpci(qlt_state_t *qlt, qlt_dt_rpci_t *entry, uint8_t *dbuff, + uint8_t *dbuff_end) + { + int esize; + uint32_t i; + uint8_t *bp = dbuff; + uint32_t reg = entry->addr; + + esize = 4; /* addr */ + esize += 4; /* data */ + + if (dbuff == NULL) { + return (esize); + } + if (esize + dbuff >= dbuff_end) { + EL(qlt, "skipped, no buffer space, needed=%xh\n", esize); + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + return (0); + } + + *bp++ = LSB(LSW(entry->addr)); + *bp++ = MSB(LSW(entry->addr)); + *bp++ = LSB(MSW(entry->addr)); + *bp++ = MSB(MSW(entry->addr)); + for (i = 0; i < 4; i++) { + *bp++ = REG_RD8(qlt, reg++); + } + + return (esize); + } + + static void + qlt_27xx_dt_wpci(qlt_state_t *qlt, qlt_dt_wpci_t *entry, + uint8_t *dbuff, uint8_t *dbuff_end) + { + uint32_t reg = entry->addr; + + if (dbuff == NULL) { + return; + } + if (dbuff >= dbuff_end) { + EL(qlt, "skipped, no buffer space, needed=0\n"); + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + return; + } + + REG_WR32(qlt, reg, entry->data); + } + + static int + qlt_27xx_dt_rram(qlt_state_t *qlt, qlt_dt_rram_t *entry, + uint8_t *dbuff, uint8_t *dbuff_end) + { + int esize, rval; + uint32_t start = entry->start_addr; + uint32_t end = entry->end_addr; + + if (entry->ram_area == 2) { + end = qlt->fw_ext_memory_end; + } else if (entry->ram_area == 3) { + start = qlt->fw_shared_ram_start; + end = qlt->fw_shared_ram_end; + } else if (entry->ram_area == 4) { + start = qlt->fw_ddr_ram_start; + end = qlt->fw_ddr_ram_end; + } else if (entry->ram_area != 1) { + EL(qlt, "skipped, unknown RAM_AREA %d\n", entry->ram_area); + start = 0; + end = 0; + } + esize = end > start ? end - start : 0; + if (esize) { + esize = (esize + 1) * 4; + } + + if (dbuff == NULL) { + return (esize); + } + if (esize == 0 || esize + dbuff >= dbuff_end) { + if (esize != 0) { + EL(qlt, "skipped, no buffer space, needed=%xh\n", + esize); + } else { + EL(qlt, "skipped, no ram_area=%xh, start=%xh " + "end=%xh\n", entry->ram_area, start, end); + } + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + return (0); + } + entry->end_addr = end; + entry->start_addr = start; + + if ((rval = qlt_27xx_dump_ram(qlt, MBC_DUMP_RAM_EXTENDED, + start, esize / 4, dbuff)) != QLT_SUCCESS) { + EL(qlt, "dump_ram failed, rval=%xh, addr=%xh, len=%xh, " + "esize=0\n", rval, start, esize / 4); + return (0); + } + + return (esize); + } + + static int + qlt_27xx_dt_gque(qlt_state_t *qlt, qlt_dt_gque_t *entry, + uint8_t *dbuff, uint8_t *dbuff_end) + { + int esize; + uint32_t cnt, q_cnt, e_cnt, i; + uint8_t *bp = dbuff, *dp; + + if (entry->queue_type == 1) { + e_cnt = qlt->qlt_queue_cnt; + esize = e_cnt * 2; /* queue number */ + esize += e_cnt * 2; /* queue entries */ + + /* queue size */ + esize += REQUEST_QUEUE_ENTRIES * IOCB_SIZE; + for (q_cnt = 1; q_cnt < qlt->qlt_queue_cnt; q_cnt++) { + esize += REQUEST_QUEUE_MQ_ENTRIES * IOCB_SIZE; + } + + if (dbuff == NULL) { + return (esize); + } + if (esize + dbuff >= dbuff_end) { + EL(qlt, "skipped, no buffer space, needed=%xh\n", + esize); + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + return (0); + } + entry->num_queues = e_cnt; + + for (q_cnt = 0; q_cnt < entry->num_queues; q_cnt++) { + e_cnt = q_cnt == 0 ? + REQUEST_QUEUE_ENTRIES : REQUEST_QUEUE_MQ_ENTRIES; + dp = (uint8_t *)qlt->mq_req[q_cnt].mq_ptr; + *bp++ = LSB(q_cnt); + *bp++ = MSB(q_cnt); + *bp++ = LSB(e_cnt); + *bp++ = MSB(e_cnt); + for (cnt = 0; cnt < e_cnt; cnt++) { + for (i = 0; i < IOCB_SIZE; i++) { + *bp++ = *dp++; + } + } + } + } else if (entry->queue_type == 2) { + + e_cnt = qlt->qlt_queue_cnt; + esize = e_cnt * 2; /* queue number */ + esize += e_cnt * 2; /* queue entries */ + + /* queue size */ + esize += RESPONSE_QUEUE_ENTRIES * IOCB_SIZE; + for (q_cnt = 1; q_cnt < qlt->qlt_queue_cnt; q_cnt++) { + esize += RESPONSE_QUEUE_MQ_ENTRIES * IOCB_SIZE; + } + + if (dbuff == NULL) { + return (esize); + } + if (esize + dbuff >= dbuff_end) { + EL(qlt, "skipped2, no buffer space, needed=%xh\n", + esize); + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + return (0); + } + entry->num_queues = e_cnt; + + for (q_cnt = 0; q_cnt < entry->num_queues; q_cnt++) { + e_cnt = q_cnt == 0 ? + RESPONSE_QUEUE_ENTRIES : RESPONSE_QUEUE_MQ_ENTRIES; + dp = (uint8_t *)qlt->mq_resp[q_cnt].mq_ptr; + *bp++ = LSB(q_cnt); + *bp++ = MSB(q_cnt); + *bp++ = LSB(e_cnt); + *bp++ = MSB(e_cnt); + for (cnt = 0; cnt < e_cnt; cnt++) { + for (i = 0; i < IOCB_SIZE; i++) { + *bp++ = *dp++; + } + } + } + } else if (entry->queue_type == 3) { + e_cnt = 1; + esize = e_cnt * 2; /* queue number */ + esize += e_cnt * 2; /* queue entries */ + + /* queue size */ + esize += RESPONSE_QUEUE_ENTRIES * IOCB_SIZE; + + if (dbuff == NULL) { + return (esize); + } + if (esize + dbuff >= dbuff_end) { + EL(qlt, "skipped2, no buffer space, needed=%xh\n", + esize); + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + return (0); + } + entry->num_queues = e_cnt; + + for (q_cnt = 0; q_cnt < entry->num_queues; q_cnt++) { + e_cnt = ATIO_QUEUE_ENTRIES; + dp = (uint8_t *)qlt->atio_ptr; + *bp++ = LSB(q_cnt); + *bp++ = MSB(q_cnt); + *bp++ = LSB(e_cnt); + *bp++ = MSB(e_cnt); + for (cnt = 0; cnt < e_cnt; cnt++) { + for (i = 0; i < IOCB_SIZE; i++) { + *bp++ = *dp++; + } + } + } + } else { + EL(qlt, "skipped, unknown queue_type %d, esize=0\n", + entry->queue_type); + if (dbuff != NULL) { + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + } + return (0); + } + + return (esize); + } + + /*ARGSUSED*/ + static int + qlt_27xx_dt_gfce(qlt_state_t *qlt, qlt_dt_gfce_t *entry, + uint8_t *dbuff, uint8_t *dbuff_end) + { + if (dbuff != NULL) { + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + } + + return (0); + } + + static void + qlt_27xx_dt_prisc(qlt_state_t *qlt, qlt_dt_prisc_t *entry, + uint8_t *dbuff, uint8_t *dbuff_end) + { + clock_t timer; + + if (dbuff == NULL) { + return; + } + if (dbuff >= dbuff_end) { + EL(qlt, "skipped, no buffer space, needed=0\n"); + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + return; + } + + /* Pause RISC. */ + if ((REG_RD32(qlt, REG_RISC_STATUS) & BIT_8) == 0) { + REG_WR32(qlt, REG_HCCR, 0x30000000); + for (timer = 30000; + (REG_RD32(qlt, REG_RISC_STATUS) & BIT_8) == 0; + timer--) { + if (timer) { + drv_usecwait(100); + if (timer % 10000 == 0) { + EL(qlt, "risc pause %d\n", timer); + } + } else { + EL(qlt, "risc pause timeout\n"); + break; + } + } + } + } + + static void + qlt_27xx_dt_rrisc(qlt_state_t *qlt, qlt_dt_rrisc_t *entry, + uint8_t *dbuff, uint8_t *dbuff_end) + { + clock_t timer; + uint16_t rom_status; + + if (dbuff == NULL) { + return; + } + if (dbuff >= dbuff_end) { + EL(qlt, "skipped, no buffer space, needed=0\n"); + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + return; + } + + /* Shutdown DMA. */ + REG_WR32(qlt, REG_CTRL_STATUS, DMA_SHUTDOWN_CTRL); + + /* Wait for DMA to stop. */ + for (timer = 0; timer < 30000; timer++) { + if (!(REG_RD32(qlt, REG_CTRL_STATUS) & DMA_ACTIVE_STATUS)) { + break; + } + drv_usecwait(100); + } + + /* Reset the chip. */ + REG_WR32(qlt, REG_CTRL_STATUS, CHIP_SOFT_RESET); + drv_usecwait(200); + + /* Wait for RISC to recover from reset. */ + for (timer = 30000; timer; timer--) { + rom_status = REG_RD16(qlt, REG_MBOX0); + if ((rom_status & MBS_ROM_STATUS_MASK) != MBS_ROM_BUSY) { + break; + } + drv_usecwait(100); + } + + /* Wait for reset to finish. */ + for (timer = 30000; timer; timer--) { + if (!(REG_RD32(qlt, REG_CTRL_STATUS) & CHIP_SOFT_RESET)) { + break; + } + drv_usecwait(100); + } + + /* XXX: Disable Interrupts (Probably not needed) */ + REG_WR32(qlt, REG_INTR_CTRL, 0); + + qlt->qlt_intr_enabled = 0; + } + + static void + qlt_27xx_dt_dint(qlt_state_t *qlt, qlt_dt_dint_t *entry, + uint8_t *dbuff, uint8_t *dbuff_end) + { + if (dbuff == NULL) { + return; + } + if (dbuff >= dbuff_end) { + EL(qlt, "skipped, no buffer space, needed=0\n"); + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + return; + } + + PCICFG_WR32(qlt, entry->pci_offset, entry->data); + } + + /*ARGSUSED*/ + static int + qlt_27xx_dt_ghbd(qlt_state_t *qlt, qlt_dt_ghbd_t *entry, + uint8_t *dbuff, uint8_t *dbuff_end) + { + if (dbuff != NULL) { + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + } + + return (0); + } + + /*ARGSUSED*/ + static int + qlt_27xx_dt_scra(qlt_state_t *qlt, qlt_dt_scra_t *entry, + uint8_t *dbuff, uint8_t *dbuff_end) + { + if (dbuff != NULL) { + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + } + + return (0); + } + + static int + qlt_27xx_dt_rrreg(qlt_state_t *qlt, qlt_dt_rrreg_t *entry, + uint8_t *dbuff, uint8_t *dbuff_end) + { + int esize; + uint32_t i; + uint8_t *bp = dbuff; + uint32_t addr = entry->addr; + uint32_t cnt = entry->count; + + esize = cnt * 4; /* addr */ + esize += cnt * 4; /* data */ + + if (dbuff == NULL) { + return (esize); + } + if (esize + dbuff >= dbuff_end) { + EL(qlt, "skipped, no buffer space, needed=%xh\n", esize); + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + return (0); + } + + REG_WR32(qlt, REG_IOBUS_BASE_ADDR, 0x40); + while (cnt--) { + REG_WR32(qlt, 0xc0, addr | 0x80000000); + *bp++ = LSB(LSW(addr)); + *bp++ = MSB(LSW(addr)); + *bp++ = LSB(MSW(addr)); + *bp++ = MSB(MSW(addr)); + for (i = 0; i < 4; i++) { + *bp++ = REG_RD8(qlt, i); + } + addr += 4; + } + + return (esize); + } + + static void + qlt_27xx_dt_wrreg(qlt_state_t *qlt, qlt_dt_wrreg_t *entry, + uint8_t *dbuff, uint8_t *dbuff_end) + { + if (dbuff == NULL) { + return; + } + if (dbuff >= dbuff_end) { + EL(qlt, "skipped, no buffer space, needed=0\n"); + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + return; + } + + REG_WR32(qlt, REG_IOBUS_BASE_ADDR, 0x40); + REG_WR32(qlt, 0xc4, entry->data); + REG_WR32(qlt, 0xc0, entry->addr); + } + + static int + qlt_27xx_dt_rrram(qlt_state_t *qlt, qlt_dt_rrram_t *entry, + uint8_t *dbuff, uint8_t *dbuff_end) + { + int rval, esize; + + esize = entry->count * 4; /* data */ + + if (dbuff == NULL) { + return (esize); + } + if (esize + dbuff >= dbuff_end) { + EL(qlt, "skipped, no buffer space, needed=%xh\n", esize); + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + return (0); + } + + if ((rval = qlt_27xx_dump_ram(qlt, MBC_MPI_RAM, entry->addr, + entry->count, dbuff)) != QLT_SUCCESS) { + EL(qlt, "dump_ram failed, rval=%xh, addr=%xh, len=%xh, " + "esize=0\n", rval, entry->addr, entry->count); + return (0); + } + + return (esize); + } + + static int + qlt_27xx_dt_rpcic(qlt_state_t *qlt, qlt_dt_rpcic_t *entry, + uint8_t *dbuff, uint8_t *dbuff_end) + { + int esize; + uint32_t i; + uint8_t *bp = dbuff; + uint32_t addr = entry->addr; + uint32_t cnt = entry->count; + + esize = cnt * 4; /* addr */ + esize += cnt * 4; /* data */ + + if (dbuff == NULL) { + return (esize); + } + if (esize + dbuff >= dbuff_end) { + EL(qlt, "skipped, no buffer space, needed=%xh\n", esize); + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + return (0); + } + + while (cnt--) { + *bp++ = LSB(LSW(addr)); + *bp++ = MSB(LSW(addr)); + *bp++ = LSB(MSW(addr)); + *bp++ = MSB(MSW(addr)); + for (i = 0; i < 4; i++) { + *bp++ = PCICFG_RD8(qlt, addr++); + } + } + + return (esize); + } + + /*ARGSUSED*/ + static int + qlt_27xx_dt_gques(qlt_state_t *qlt, qlt_dt_gques_t *entry, + uint8_t *dbuff, uint8_t *dbuff_end) + { + if (entry->queue_type == 1) { + EL(qlt, "skipped, no request queue shadowing, esize=0\n"); + if (dbuff != NULL) { + entry->num_queues = 0; + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + } + return (0); + } else if (entry->queue_type == 2) { + EL(qlt, "skipped, no response queue shadowing, esize=0\n"); + if (dbuff != NULL) { + entry->num_queues = 0; + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + } + return (0); + } else if (entry->queue_type == 3) { + EL(qlt, "skipped, no ATIO queue, esize=0\n"); + if (dbuff != NULL) { + entry->num_queues = 0; + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + } + return (0); + } else { + EL(qlt, "skipped, unknown queue_type %d, esize=0\n", + entry->queue_type); + if (dbuff != NULL) { + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + } + return (0); + } + } + + static int + qlt_27xx_dt_wdmp(qlt_state_t *qlt, qlt_dt_wdmp_t *entry, + uint8_t *dbuff, uint8_t *dbuff_end) + { + int esize; + uint8_t *bp = dbuff; + uint32_t data, cnt = entry->length, *dp = entry->data; + + esize = cnt; + if (dbuff == NULL) { + return (esize); + } + if (esize + dbuff >= dbuff_end) { + EL(qlt, "skipped, no buffer space, needed=%xh\n", esize); + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + return (0); + } + + while (cnt--) { + data = *dp++; + *bp++ = LSB(LSW(data)); + *bp++ = MSB(LSW(data)); + *bp++ = LSB(MSW(data)); + *bp++ = MSB(MSW(data)); + } + + return (esize); + } + + /* + * qlt_27xx_dump_ram + * Dumps RAM. + * Risc interrupts must be disabled when this routine is called. + * + * Input: + * pi: port info pointer. + * cmd: MBC_DUMP_RAM_EXTENDED/MBC_MPI_RAM. + * risc_address: RISC code start address. + * len: Number of words. + * bp: buffer pointer. + * + * Returns: + * qlt local function return status code. + * + * Context: + * Interrupt or Kernel context, no mailbox commands allowed. + */ + /*ARGSUSED*/ + static int + qlt_27xx_dump_ram(qlt_state_t *qlt, uint16_t cmd, uint32_t risc_address, + uint32_t len, uint8_t *bp) + { + uint8_t *dp; + uint32_t words_to_read, endaddr; + uint32_t i; + int rval = QLT_SUCCESS; + + endaddr = risc_address + len; + words_to_read = 0; + while (risc_address < endaddr) { + words_to_read = MBOX_DMA_MEM_SIZE >> 2; + if ((words_to_read + risc_address) > endaddr) { + words_to_read = endaddr - risc_address; + } + + if (cmd == MBC_DUMP_RAM_EXTENDED) { + rval = qlt_read_risc_ram(qlt, risc_address, + words_to_read); + } else { + rval = qlt_mbx_mpi_ram(qlt, risc_address, + words_to_read, 0); + } + + if (rval != QLT_SUCCESS) { + EL(qlt, "Error reading risc ram = %xh len = %x\n", + risc_address, words_to_read); + return (rval); + } + + dp = (uint8_t *)(qlt->queue_mem_ptr + MBOX_DMA_MEM_OFFSET); + for (i = 0; i < (words_to_read * 4); i++) { + *bp++ = *dp++; + } + risc_address += words_to_read; + } + + return (rval); + } + + static uint32_t + qlt_27xx_dmp_parse_template(qlt_state_t *qlt, qlt_dt_hdr_t *template_hdr, + uint8_t *dump_buff, uint32_t buff_size) + { + int e_cnt, esize, num_of_entries; + uint32_t bsize; + time_t time; + uint8_t *dbuff, *dbuff_end; + qlt_dt_entry_t *entry; + int sane_end = 0; + + dbuff = dump_buff; /* dbuff = NULL size determination. */ + dbuff_end = dump_buff + buff_size; + + if (template_hdr->type != DT_THDR) { + EL(qlt, "Template header not found\n"); + return (0); + } + if (dbuff != NULL) { + (void) drv_getparm(TIME, &time); + template_hdr->driver_timestamp = LSD(time); + } + + num_of_entries = template_hdr->num_of_entries; + entry = (qlt_dt_entry_t *)((caddr_t)template_hdr + + template_hdr->first_entry_offset); + + bsize = template_hdr->size_of_template; + for (e_cnt = 0; e_cnt < num_of_entries; e_cnt++) { + /* + * Decode the entry type and process it accordingly + */ + esize = 0; + switch (entry->h.type) { + case DT_NOP: + if (dbuff != NULL) { + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + } + break; + case DT_TEND: + if (dbuff != NULL) { + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + } + sane_end++; + break; + case DT_RIOB1: + esize = qlt_27xx_dt_riob1(qlt, (qlt_dt_riob1_t *)entry, + dbuff, dbuff_end); + break; + case DT_WIOB1: + qlt_27xx_dt_wiob1(qlt, (qlt_dt_wiob1_t *)entry, + dbuff, dbuff_end); + break; + case DT_RIOB2: + esize = qlt_27xx_dt_riob2(qlt, (qlt_dt_riob2_t *)entry, + dbuff, dbuff_end); + break; + case DT_WIOB2: + qlt_27xx_dt_wiob2(qlt, (qlt_dt_wiob2_t *)entry, + dbuff, dbuff_end); + break; + case DT_RPCI: + esize = qlt_27xx_dt_rpci(qlt, (qlt_dt_rpci_t *)entry, + dbuff, dbuff_end); + break; + case DT_WPCI: + qlt_27xx_dt_wpci(qlt, (qlt_dt_wpci_t *)entry, + dbuff, dbuff_end); + break; + case DT_RRAM: + esize = qlt_27xx_dt_rram(qlt, (qlt_dt_rram_t *)entry, + dbuff, dbuff_end); + break; + case DT_GQUE: + esize = qlt_27xx_dt_gque(qlt, (qlt_dt_gque_t *)entry, + dbuff, dbuff_end); + break; + case DT_GFCE: + esize = qlt_27xx_dt_gfce(qlt, (qlt_dt_gfce_t *)entry, + dbuff, dbuff_end); + break; + case DT_PRISC: + qlt_27xx_dt_prisc(qlt, (qlt_dt_prisc_t *)entry, + dbuff, dbuff_end); + break; + case DT_RRISC: + qlt_27xx_dt_rrisc(qlt, (qlt_dt_rrisc_t *)entry, + dbuff, dbuff_end); + break; + case DT_DINT: + qlt_27xx_dt_dint(qlt, (qlt_dt_dint_t *)entry, + dbuff, dbuff_end); + break; + case DT_GHBD: + esize = qlt_27xx_dt_ghbd(qlt, (qlt_dt_ghbd_t *)entry, + dbuff, dbuff_end); + break; + case DT_SCRA: + esize = qlt_27xx_dt_scra(qlt, (qlt_dt_scra_t *)entry, + dbuff, dbuff_end); + break; + case DT_RRREG: + esize = qlt_27xx_dt_rrreg(qlt, (qlt_dt_rrreg_t *)entry, + dbuff, dbuff_end); + break; + case DT_WRREG: + qlt_27xx_dt_wrreg(qlt, (qlt_dt_wrreg_t *)entry, + dbuff, dbuff_end); + break; + case DT_RRRAM: + esize = qlt_27xx_dt_rrram(qlt, (qlt_dt_rrram_t *)entry, + dbuff, dbuff_end); + break; + case DT_RPCIC: + esize = qlt_27xx_dt_rpcic(qlt, (qlt_dt_rpcic_t *)entry, + dbuff, dbuff_end); + break; + case DT_GQUES: + esize = qlt_27xx_dt_gques(qlt, (qlt_dt_gques_t *)entry, + dbuff, dbuff_end); + break; + case DT_WDMP: + esize = qlt_27xx_dt_wdmp(qlt, (qlt_dt_wdmp_t *)entry, + dbuff, dbuff_end); + break; + default: + entry->h.driver_flags = (uint8_t) + (entry->h.driver_flags | SKIPPED_FLAG); + EL(qlt, "Entry ID=%d, type=%d unknown\n", e_cnt, + entry->h.type); + break; + } + if (dbuff != NULL && esize) { + dbuff += esize; + } + bsize += esize; + /* next entry in the template */ + entry = (qlt_dt_entry_t *)((caddr_t)entry + entry->h.size); + } + if (sane_end > 1) { + EL(qlt, "Template configuration error. Check Template\n"); + } + + return (bsize); }