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