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