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