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