1*4c06356bSdh /* 2*4c06356bSdh * CDDL HEADER START 3*4c06356bSdh * 4*4c06356bSdh * The contents of this file are subject to the terms of the 5*4c06356bSdh * Common Development and Distribution License (the "License"). 6*4c06356bSdh * You may not use this file except in compliance with the License. 7*4c06356bSdh * 8*4c06356bSdh * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*4c06356bSdh * or http://www.opensolaris.org/os/licensing. 10*4c06356bSdh * See the License for the specific language governing permissions 11*4c06356bSdh * and limitations under the License. 12*4c06356bSdh * 13*4c06356bSdh * When distributing Covered Code, include this CDDL HEADER in each 14*4c06356bSdh * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*4c06356bSdh * If applicable, add the following below this CDDL HEADER, with the 16*4c06356bSdh * fields enclosed by brackets "[]" replaced with your own identifying 17*4c06356bSdh * information: Portions Copyright [yyyy] [name of copyright owner] 18*4c06356bSdh * 19*4c06356bSdh * CDDL HEADER END 20*4c06356bSdh * 21*4c06356bSdh * 22*4c06356bSdh * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23*4c06356bSdh * Use is subject to license terms. 24*4c06356bSdh */ 25*4c06356bSdh #include <sys/scsi/adapters/pmcs/pmcs.h> 26*4c06356bSdh #include <sys/scsi/adapters/pmcs/pmcs_bldrev.h> 27*4c06356bSdh 28*4c06356bSdh #define PMCS_DRIVER_VERSION "PMC-Sierra HBA Driver "\ 29*4c06356bSdh PMCS_BUILD_VERSION 30*4c06356bSdh 31*4c06356bSdh static char *pmcs_driver_rev = PMCS_DRIVER_VERSION; 32*4c06356bSdh 33*4c06356bSdh /* 34*4c06356bSdh * Non-DDI Compliant stuff 35*4c06356bSdh */ 36*4c06356bSdh extern char hw_serial[]; 37*4c06356bSdh 38*4c06356bSdh /* 39*4c06356bSdh * Global driver data 40*4c06356bSdh */ 41*4c06356bSdh void *pmcs_softc_state = NULL; 42*4c06356bSdh void *pmcs_iport_softstate = NULL; 43*4c06356bSdh 44*4c06356bSdh /* 45*4c06356bSdh * Tracing and Logging info 46*4c06356bSdh */ 47*4c06356bSdh pmcs_tbuf_t *pmcs_tbuf = NULL; 48*4c06356bSdh uint32_t pmcs_tbuf_num_elems = 0; 49*4c06356bSdh pmcs_tbuf_t *pmcs_tbuf_ptr; 50*4c06356bSdh uint32_t pmcs_tbuf_idx = 0; 51*4c06356bSdh boolean_t pmcs_tbuf_wrap = B_FALSE; 52*4c06356bSdh static kmutex_t pmcs_trace_lock; 53*4c06356bSdh 54*4c06356bSdh /* 55*4c06356bSdh * If pmcs_force_syslog value is non-zero, all messages put in the trace log 56*4c06356bSdh * will also be sent to system log. 57*4c06356bSdh */ 58*4c06356bSdh int pmcs_force_syslog = 0; 59*4c06356bSdh int pmcs_console = 0; 60*4c06356bSdh 61*4c06356bSdh /* 62*4c06356bSdh * External References 63*4c06356bSdh */ 64*4c06356bSdh extern int ncpus_online; 65*4c06356bSdh 66*4c06356bSdh /* 67*4c06356bSdh * Local static data 68*4c06356bSdh */ 69*4c06356bSdh static int fwlog_level = 3; 70*4c06356bSdh static int physpeed = PHY_LINK_ALL; 71*4c06356bSdh static int phymode = PHY_LM_AUTO; 72*4c06356bSdh static int block_mask = 0; 73*4c06356bSdh static int phymap_usec = 3 * MICROSEC; 74*4c06356bSdh static int iportmap_usec = 2 * MICROSEC; 75*4c06356bSdh 76*4c06356bSdh #ifdef DEBUG 77*4c06356bSdh static int debug_mask = 1; 78*4c06356bSdh #else 79*4c06356bSdh static int debug_mask = 0; 80*4c06356bSdh #endif 81*4c06356bSdh 82*4c06356bSdh #ifdef DISABLE_MSIX 83*4c06356bSdh static int disable_msix = 1; 84*4c06356bSdh #else 85*4c06356bSdh static int disable_msix = 0; 86*4c06356bSdh #endif 87*4c06356bSdh 88*4c06356bSdh #ifdef DISABLE_MSI 89*4c06356bSdh static int disable_msi = 1; 90*4c06356bSdh #else 91*4c06356bSdh static int disable_msi = 0; 92*4c06356bSdh #endif 93*4c06356bSdh 94*4c06356bSdh static uint16_t maxqdepth = 0xfffe; 95*4c06356bSdh 96*4c06356bSdh /* 97*4c06356bSdh * Local prototypes 98*4c06356bSdh */ 99*4c06356bSdh static int pmcs_attach(dev_info_t *, ddi_attach_cmd_t); 100*4c06356bSdh static int pmcs_detach(dev_info_t *, ddi_detach_cmd_t); 101*4c06356bSdh static int pmcs_unattach(pmcs_hw_t *); 102*4c06356bSdh static int pmcs_iport_unattach(pmcs_iport_t *); 103*4c06356bSdh static int pmcs_add_more_chunks(pmcs_hw_t *, unsigned long); 104*4c06356bSdh static void pmcs_watchdog(void *); 105*4c06356bSdh static int pmcs_setup_intr(pmcs_hw_t *); 106*4c06356bSdh static int pmcs_teardown_intr(pmcs_hw_t *); 107*4c06356bSdh 108*4c06356bSdh static uint_t pmcs_nonio_ix(caddr_t, caddr_t); 109*4c06356bSdh static uint_t pmcs_general_ix(caddr_t, caddr_t); 110*4c06356bSdh static uint_t pmcs_event_ix(caddr_t, caddr_t); 111*4c06356bSdh static uint_t pmcs_iodone_ix(caddr_t, caddr_t); 112*4c06356bSdh static uint_t pmcs_fatal_ix(caddr_t, caddr_t); 113*4c06356bSdh static uint_t pmcs_all_intr(caddr_t, caddr_t); 114*4c06356bSdh static int pmcs_quiesce(dev_info_t *dip); 115*4c06356bSdh static boolean_t pmcs_fabricate_wwid(pmcs_hw_t *); 116*4c06356bSdh 117*4c06356bSdh static void pmcs_create_phy_stats(pmcs_iport_t *); 118*4c06356bSdh int pmcs_update_phy_stats(kstat_t *, int); 119*4c06356bSdh static void pmcs_destroy_phy_stats(pmcs_iport_t *); 120*4c06356bSdh 121*4c06356bSdh static void pmcs_fm_fini(pmcs_hw_t *pwp); 122*4c06356bSdh static void pmcs_fm_init(pmcs_hw_t *pwp); 123*4c06356bSdh static int pmcs_fm_error_cb(dev_info_t *dip, 124*4c06356bSdh ddi_fm_error_t *err, const void *impl_data); 125*4c06356bSdh 126*4c06356bSdh /* 127*4c06356bSdh * Local configuration data 128*4c06356bSdh */ 129*4c06356bSdh static struct dev_ops pmcs_ops = { 130*4c06356bSdh DEVO_REV, /* devo_rev, */ 131*4c06356bSdh 0, /* refcnt */ 132*4c06356bSdh ddi_no_info, /* info */ 133*4c06356bSdh nulldev, /* identify */ 134*4c06356bSdh nulldev, /* probe */ 135*4c06356bSdh pmcs_attach, /* attach */ 136*4c06356bSdh pmcs_detach, /* detach */ 137*4c06356bSdh nodev, /* reset */ 138*4c06356bSdh NULL, /* driver operations */ 139*4c06356bSdh NULL, /* bus operations */ 140*4c06356bSdh ddi_power, /* power management */ 141*4c06356bSdh pmcs_quiesce /* quiesce */ 142*4c06356bSdh }; 143*4c06356bSdh 144*4c06356bSdh static struct modldrv modldrv = { 145*4c06356bSdh &mod_driverops, 146*4c06356bSdh PMCS_DRIVER_VERSION, 147*4c06356bSdh &pmcs_ops, /* driver ops */ 148*4c06356bSdh }; 149*4c06356bSdh static struct modlinkage modlinkage = { 150*4c06356bSdh MODREV_1, &modldrv, NULL 151*4c06356bSdh }; 152*4c06356bSdh 153*4c06356bSdh const ddi_dma_attr_t pmcs_dattr = { 154*4c06356bSdh DMA_ATTR_V0, /* dma_attr version */ 155*4c06356bSdh 0x0000000000000000ull, /* dma_attr_addr_lo */ 156*4c06356bSdh 0xFFFFFFFFFFFFFFFFull, /* dma_attr_addr_hi */ 157*4c06356bSdh 0x00000000FFFFFFFFull, /* dma_attr_count_max */ 158*4c06356bSdh 0x0000000000000001ull, /* dma_attr_align */ 159*4c06356bSdh 0x00000078, /* dma_attr_burstsizes */ 160*4c06356bSdh 0x00000001, /* dma_attr_minxfer */ 161*4c06356bSdh 0x00000000FFFFFFFFull, /* dma_attr_maxxfer */ 162*4c06356bSdh 0x00000000FFFFFFFFull, /* dma_attr_seg */ 163*4c06356bSdh 1, /* dma_attr_sgllen */ 164*4c06356bSdh 512, /* dma_attr_granular */ 165*4c06356bSdh 0 /* dma_attr_flags */ 166*4c06356bSdh }; 167*4c06356bSdh 168*4c06356bSdh static ddi_device_acc_attr_t rattr = { 169*4c06356bSdh DDI_DEVICE_ATTR_V0, 170*4c06356bSdh DDI_STRUCTURE_LE_ACC, 171*4c06356bSdh DDI_STRICTORDER_ACC, 172*4c06356bSdh DDI_DEFAULT_ACC 173*4c06356bSdh }; 174*4c06356bSdh 175*4c06356bSdh 176*4c06356bSdh /* 177*4c06356bSdh * Attach/Detach functions 178*4c06356bSdh */ 179*4c06356bSdh 180*4c06356bSdh int 181*4c06356bSdh _init(void) 182*4c06356bSdh { 183*4c06356bSdh int ret; 184*4c06356bSdh 185*4c06356bSdh ret = ddi_soft_state_init(&pmcs_softc_state, sizeof (pmcs_hw_t), 1); 186*4c06356bSdh if (ret != 0) { 187*4c06356bSdh cmn_err(CE_WARN, "?soft state init failed for pmcs"); 188*4c06356bSdh return (ret); 189*4c06356bSdh } 190*4c06356bSdh 191*4c06356bSdh if ((ret = scsi_hba_init(&modlinkage)) != 0) { 192*4c06356bSdh cmn_err(CE_WARN, "?scsi_hba_init failed for pmcs"); 193*4c06356bSdh ddi_soft_state_fini(&pmcs_softc_state); 194*4c06356bSdh return (ret); 195*4c06356bSdh } 196*4c06356bSdh 197*4c06356bSdh /* 198*4c06356bSdh * Allocate soft state for iports 199*4c06356bSdh */ 200*4c06356bSdh ret = ddi_soft_state_init(&pmcs_iport_softstate, 201*4c06356bSdh sizeof (pmcs_iport_t), 2); 202*4c06356bSdh if (ret != 0) { 203*4c06356bSdh cmn_err(CE_WARN, "?iport soft state init failed for pmcs"); 204*4c06356bSdh ddi_soft_state_fini(&pmcs_softc_state); 205*4c06356bSdh return (ret); 206*4c06356bSdh } 207*4c06356bSdh 208*4c06356bSdh ret = mod_install(&modlinkage); 209*4c06356bSdh if (ret != 0) { 210*4c06356bSdh cmn_err(CE_WARN, "?mod_install failed for pmcs (%d)", ret); 211*4c06356bSdh scsi_hba_fini(&modlinkage); 212*4c06356bSdh ddi_soft_state_fini(&pmcs_iport_softstate); 213*4c06356bSdh ddi_soft_state_fini(&pmcs_softc_state); 214*4c06356bSdh return (ret); 215*4c06356bSdh } 216*4c06356bSdh 217*4c06356bSdh /* Initialize the global trace lock */ 218*4c06356bSdh mutex_init(&pmcs_trace_lock, NULL, MUTEX_DRIVER, NULL); 219*4c06356bSdh 220*4c06356bSdh return (0); 221*4c06356bSdh } 222*4c06356bSdh 223*4c06356bSdh int 224*4c06356bSdh _fini(void) 225*4c06356bSdh { 226*4c06356bSdh int ret; 227*4c06356bSdh if ((ret = mod_remove(&modlinkage)) != 0) { 228*4c06356bSdh return (ret); 229*4c06356bSdh } 230*4c06356bSdh scsi_hba_fini(&modlinkage); 231*4c06356bSdh 232*4c06356bSdh /* Free pmcs log buffer and destroy the global lock */ 233*4c06356bSdh if (pmcs_tbuf) { 234*4c06356bSdh kmem_free(pmcs_tbuf, 235*4c06356bSdh pmcs_tbuf_num_elems * sizeof (pmcs_tbuf_t)); 236*4c06356bSdh pmcs_tbuf = NULL; 237*4c06356bSdh } 238*4c06356bSdh mutex_destroy(&pmcs_trace_lock); 239*4c06356bSdh 240*4c06356bSdh ddi_soft_state_fini(&pmcs_iport_softstate); 241*4c06356bSdh ddi_soft_state_fini(&pmcs_softc_state); 242*4c06356bSdh return (0); 243*4c06356bSdh } 244*4c06356bSdh 245*4c06356bSdh int 246*4c06356bSdh _info(struct modinfo *modinfop) 247*4c06356bSdh { 248*4c06356bSdh return (mod_info(&modlinkage, modinfop)); 249*4c06356bSdh } 250*4c06356bSdh 251*4c06356bSdh static int 252*4c06356bSdh pmcs_iport_attach(dev_info_t *dip) 253*4c06356bSdh { 254*4c06356bSdh pmcs_iport_t *iport; 255*4c06356bSdh pmcs_hw_t *pwp; 256*4c06356bSdh scsi_hba_tran_t *tran; 257*4c06356bSdh void *ua_priv = NULL; 258*4c06356bSdh char *iport_ua; 259*4c06356bSdh char *init_port; 260*4c06356bSdh int hba_inst; 261*4c06356bSdh int inst; 262*4c06356bSdh 263*4c06356bSdh hba_inst = ddi_get_instance(ddi_get_parent(dip)); 264*4c06356bSdh inst = ddi_get_instance(dip); 265*4c06356bSdh 266*4c06356bSdh pwp = ddi_get_soft_state(pmcs_softc_state, hba_inst); 267*4c06356bSdh if (pwp == NULL) { 268*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 269*4c06356bSdh "%s: iport%d attach invoked with NULL parent (HBA) node)", 270*4c06356bSdh __func__, inst); 271*4c06356bSdh return (DDI_FAILURE); 272*4c06356bSdh } 273*4c06356bSdh 274*4c06356bSdh if ((pwp->state == STATE_UNPROBING) || (pwp->state == STATE_DEAD)) { 275*4c06356bSdh return (DDI_FAILURE); 276*4c06356bSdh } 277*4c06356bSdh 278*4c06356bSdh if ((iport_ua = scsi_hba_iport_unit_address(dip)) == NULL) { 279*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 280*4c06356bSdh "%s: invoked with NULL unit address, inst (%d)", 281*4c06356bSdh __func__, inst); 282*4c06356bSdh return (DDI_FAILURE); 283*4c06356bSdh } 284*4c06356bSdh 285*4c06356bSdh if (ddi_soft_state_zalloc(pmcs_iport_softstate, inst) != DDI_SUCCESS) { 286*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 287*4c06356bSdh "Failed to alloc soft state for iport %d", inst); 288*4c06356bSdh return (DDI_FAILURE); 289*4c06356bSdh } 290*4c06356bSdh 291*4c06356bSdh iport = ddi_get_soft_state(pmcs_iport_softstate, inst); 292*4c06356bSdh if (iport == NULL) { 293*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 294*4c06356bSdh "cannot get iport soft state"); 295*4c06356bSdh goto iport_attach_fail1; 296*4c06356bSdh } 297*4c06356bSdh 298*4c06356bSdh mutex_init(&iport->lock, NULL, MUTEX_DRIVER, 299*4c06356bSdh DDI_INTR_PRI(pwp->intr_pri)); 300*4c06356bSdh cv_init(&iport->refcnt_cv, NULL, CV_DEFAULT, NULL); 301*4c06356bSdh mutex_init(&iport->refcnt_lock, NULL, MUTEX_DRIVER, 302*4c06356bSdh DDI_INTR_PRI(pwp->intr_pri)); 303*4c06356bSdh 304*4c06356bSdh /* Set some data on the iport handle */ 305*4c06356bSdh iport->dip = dip; 306*4c06356bSdh iport->pwp = pwp; 307*4c06356bSdh 308*4c06356bSdh /* Dup the UA into the iport handle */ 309*4c06356bSdh iport->ua = strdup(iport_ua); 310*4c06356bSdh 311*4c06356bSdh tran = (scsi_hba_tran_t *)ddi_get_driver_private(dip); 312*4c06356bSdh tran->tran_hba_private = iport; 313*4c06356bSdh 314*4c06356bSdh list_create(&iport->phys, sizeof (pmcs_phy_t), 315*4c06356bSdh offsetof(pmcs_phy_t, list_node)); 316*4c06356bSdh 317*4c06356bSdh /* 318*4c06356bSdh * If our unit address is active in the phymap, configure our 319*4c06356bSdh * iport's phylist. 320*4c06356bSdh */ 321*4c06356bSdh mutex_enter(&iport->lock); 322*4c06356bSdh ua_priv = sas_phymap_lookup_uapriv(pwp->hss_phymap, iport->ua); 323*4c06356bSdh if (ua_priv) { 324*4c06356bSdh /* Non-NULL private data indicates the unit address is active */ 325*4c06356bSdh iport->ua_state = UA_ACTIVE; 326*4c06356bSdh if (pmcs_iport_configure_phys(iport) != DDI_SUCCESS) { 327*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, "%s: failed to " 328*4c06356bSdh "configure phys on iport handle (0x%p), " 329*4c06356bSdh " unit address [%s]", __func__, 330*4c06356bSdh (void *)iport, iport_ua); 331*4c06356bSdh mutex_exit(&iport->lock); 332*4c06356bSdh goto iport_attach_fail2; 333*4c06356bSdh } 334*4c06356bSdh } else { 335*4c06356bSdh iport->ua_state = UA_INACTIVE; 336*4c06356bSdh } 337*4c06356bSdh mutex_exit(&iport->lock); 338*4c06356bSdh 339*4c06356bSdh /* Allocate string-based soft state pool for targets */ 340*4c06356bSdh iport->tgt_sstate = NULL; 341*4c06356bSdh if (ddi_soft_state_bystr_init(&iport->tgt_sstate, 342*4c06356bSdh sizeof (pmcs_xscsi_t), PMCS_TGT_SSTATE_SZ) != 0) { 343*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 344*4c06356bSdh "cannot get iport tgt soft state"); 345*4c06356bSdh goto iport_attach_fail2; 346*4c06356bSdh } 347*4c06356bSdh 348*4c06356bSdh /* Create this iport's target map */ 349*4c06356bSdh if (pmcs_iport_tgtmap_create(iport) == B_FALSE) { 350*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 351*4c06356bSdh "Failed to create tgtmap on iport %d", inst); 352*4c06356bSdh goto iport_attach_fail3; 353*4c06356bSdh } 354*4c06356bSdh 355*4c06356bSdh /* Set up the 'initiator-port' DDI property on this iport */ 356*4c06356bSdh init_port = kmem_zalloc(PMCS_MAX_UA_SIZE, KM_SLEEP); 357*4c06356bSdh if (pwp->separate_ports) { 358*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, "%s: separate ports not " 359*4c06356bSdh "supported", __func__); 360*4c06356bSdh } else { 361*4c06356bSdh /* Set initiator-port value to the HBA's base WWN */ 362*4c06356bSdh (void) scsi_wwn_to_wwnstr(pwp->sas_wwns[0], 1, 363*4c06356bSdh init_port); 364*4c06356bSdh } 365*4c06356bSdh pmcs_smhba_add_iport_prop(iport, DATA_TYPE_STRING, 366*4c06356bSdh SCSI_ADDR_PROP_INITIATOR_PORT, init_port); 367*4c06356bSdh kmem_free(init_port, PMCS_MAX_UA_SIZE); 368*4c06356bSdh 369*4c06356bSdh /* Set up a 'num-phys' DDI property for the iport node */ 370*4c06356bSdh pmcs_smhba_add_iport_prop(iport, DATA_TYPE_INT32, PMCS_NUM_PHYS, 371*4c06356bSdh &iport->nphy); 372*4c06356bSdh 373*4c06356bSdh /* Create kstats for each of the phys in this port */ 374*4c06356bSdh pmcs_create_phy_stats(iport); 375*4c06356bSdh 376*4c06356bSdh /* 377*4c06356bSdh * Insert this iport handle into our list and set 378*4c06356bSdh * iports_attached on the HBA node. 379*4c06356bSdh */ 380*4c06356bSdh rw_enter(&pwp->iports_lock, RW_WRITER); 381*4c06356bSdh ASSERT(!list_link_active(&iport->list_node)); 382*4c06356bSdh list_insert_tail(&pwp->iports, iport); 383*4c06356bSdh pwp->iports_attached = 1; 384*4c06356bSdh pwp->num_iports++; 385*4c06356bSdh rw_exit(&pwp->iports_lock); 386*4c06356bSdh 387*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG_IPORT, "iport%d attached", inst); 388*4c06356bSdh ddi_report_dev(dip); 389*4c06356bSdh return (DDI_SUCCESS); 390*4c06356bSdh 391*4c06356bSdh /* teardown and fail */ 392*4c06356bSdh iport_attach_fail3: 393*4c06356bSdh ddi_soft_state_bystr_fini(&iport->tgt_sstate); 394*4c06356bSdh iport_attach_fail2: 395*4c06356bSdh list_destroy(&iport->phys); 396*4c06356bSdh strfree(iport->ua); 397*4c06356bSdh mutex_destroy(&iport->refcnt_lock); 398*4c06356bSdh cv_destroy(&iport->refcnt_cv); 399*4c06356bSdh mutex_destroy(&iport->lock); 400*4c06356bSdh iport_attach_fail1: 401*4c06356bSdh ddi_soft_state_free(pmcs_iport_softstate, inst); 402*4c06356bSdh return (DDI_FAILURE); 403*4c06356bSdh } 404*4c06356bSdh 405*4c06356bSdh static int 406*4c06356bSdh pmcs_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 407*4c06356bSdh { 408*4c06356bSdh scsi_hba_tran_t *tran; 409*4c06356bSdh char chiprev, *fwsupport, hw_rev[24], fw_rev[24]; 410*4c06356bSdh off_t set3size; 411*4c06356bSdh int inst, i; 412*4c06356bSdh int sm_hba = 1; 413*4c06356bSdh int protocol = 0; 414*4c06356bSdh int num_phys = 0; 415*4c06356bSdh pmcs_hw_t *pwp; 416*4c06356bSdh pmcs_phy_t *phyp; 417*4c06356bSdh uint32_t num_threads; 418*4c06356bSdh char buf[64]; 419*4c06356bSdh 420*4c06356bSdh switch (cmd) { 421*4c06356bSdh case DDI_ATTACH: 422*4c06356bSdh break; 423*4c06356bSdh 424*4c06356bSdh case DDI_PM_RESUME: 425*4c06356bSdh case DDI_RESUME: 426*4c06356bSdh tran = (scsi_hba_tran_t *)ddi_get_driver_private(dip); 427*4c06356bSdh if (!tran) { 428*4c06356bSdh return (DDI_FAILURE); 429*4c06356bSdh } 430*4c06356bSdh /* No DDI_?_RESUME on iport nodes */ 431*4c06356bSdh if (scsi_hba_iport_unit_address(dip) != NULL) { 432*4c06356bSdh return (DDI_SUCCESS); 433*4c06356bSdh } 434*4c06356bSdh pwp = TRAN2PMC(tran); 435*4c06356bSdh if (pwp == NULL) { 436*4c06356bSdh return (DDI_FAILURE); 437*4c06356bSdh } 438*4c06356bSdh 439*4c06356bSdh mutex_enter(&pwp->lock); 440*4c06356bSdh pwp->suspended = 0; 441*4c06356bSdh if (pwp->tq) { 442*4c06356bSdh ddi_taskq_resume(pwp->tq); 443*4c06356bSdh } 444*4c06356bSdh mutex_exit(&pwp->lock); 445*4c06356bSdh return (DDI_SUCCESS); 446*4c06356bSdh 447*4c06356bSdh default: 448*4c06356bSdh return (DDI_FAILURE); 449*4c06356bSdh } 450*4c06356bSdh 451*4c06356bSdh /* 452*4c06356bSdh * If this is an iport node, invoke iport attach. 453*4c06356bSdh */ 454*4c06356bSdh if (scsi_hba_iport_unit_address(dip) != NULL) { 455*4c06356bSdh return (pmcs_iport_attach(dip)); 456*4c06356bSdh } 457*4c06356bSdh 458*4c06356bSdh /* 459*4c06356bSdh * From here on is attach for the HBA node 460*4c06356bSdh */ 461*4c06356bSdh 462*4c06356bSdh #ifdef DEBUG 463*4c06356bSdh /* 464*4c06356bSdh * Check to see if this unit is to be disabled. We can't disable 465*4c06356bSdh * on a per-iport node. It's either the entire HBA or nothing. 466*4c06356bSdh */ 467*4c06356bSdh (void) snprintf(buf, sizeof (buf), 468*4c06356bSdh "disable-instance-%d", ddi_get_instance(dip)); 469*4c06356bSdh if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, 470*4c06356bSdh DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, buf, 0)) { 471*4c06356bSdh cmn_err(CE_NOTE, "pmcs%d: disabled by configuration", 472*4c06356bSdh ddi_get_instance(dip)); 473*4c06356bSdh return (DDI_FAILURE); 474*4c06356bSdh } 475*4c06356bSdh #endif 476*4c06356bSdh 477*4c06356bSdh /* 478*4c06356bSdh * Allocate softstate 479*4c06356bSdh */ 480*4c06356bSdh inst = ddi_get_instance(dip); 481*4c06356bSdh if (ddi_soft_state_zalloc(pmcs_softc_state, inst) != DDI_SUCCESS) { 482*4c06356bSdh cmn_err(CE_WARN, "pmcs%d: Failed to alloc soft state", inst); 483*4c06356bSdh return (DDI_FAILURE); 484*4c06356bSdh } 485*4c06356bSdh 486*4c06356bSdh pwp = ddi_get_soft_state(pmcs_softc_state, inst); 487*4c06356bSdh if (pwp == NULL) { 488*4c06356bSdh cmn_err(CE_WARN, "pmcs%d: cannot get soft state", inst); 489*4c06356bSdh ddi_soft_state_free(pmcs_softc_state, inst); 490*4c06356bSdh return (DDI_FAILURE); 491*4c06356bSdh } 492*4c06356bSdh pwp->dip = dip; 493*4c06356bSdh STAILQ_INIT(&pwp->dq); 494*4c06356bSdh STAILQ_INIT(&pwp->cq); 495*4c06356bSdh STAILQ_INIT(&pwp->wf); 496*4c06356bSdh STAILQ_INIT(&pwp->pf); 497*4c06356bSdh /* 498*4c06356bSdh * Create the list for iports 499*4c06356bSdh */ 500*4c06356bSdh list_create(&pwp->iports, sizeof (pmcs_iport_t), 501*4c06356bSdh offsetof(pmcs_iport_t, list_node)); 502*4c06356bSdh 503*4c06356bSdh pwp->state = STATE_PROBING; 504*4c06356bSdh 505*4c06356bSdh /* 506*4c06356bSdh * Get driver.conf properties 507*4c06356bSdh */ 508*4c06356bSdh pwp->debug_mask = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 509*4c06356bSdh DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "pmcs-debug-mask", 510*4c06356bSdh debug_mask); 511*4c06356bSdh pwp->phyid_block_mask = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 512*4c06356bSdh DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "pmcs-phyid-block-mask", 513*4c06356bSdh block_mask); 514*4c06356bSdh pwp->physpeed = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 515*4c06356bSdh DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "pmcs-physpeed", physpeed); 516*4c06356bSdh pwp->phymode = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 517*4c06356bSdh DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "pmcs-phymode", phymode); 518*4c06356bSdh pwp->fwlog = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 519*4c06356bSdh DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "pmcs-fwlog", fwlog_level); 520*4c06356bSdh if (pwp->fwlog > PMCS_FWLOG_MAX) { 521*4c06356bSdh pwp->fwlog = PMCS_FWLOG_MAX; 522*4c06356bSdh } 523*4c06356bSdh 524*4c06356bSdh mutex_enter(&pmcs_trace_lock); 525*4c06356bSdh if (pmcs_tbuf == NULL) { 526*4c06356bSdh /* Allocate trace buffer */ 527*4c06356bSdh pmcs_tbuf_num_elems = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 528*4c06356bSdh DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "pmcs-tbuf-num-elems", 529*4c06356bSdh PMCS_TBUF_NUM_ELEMS_DEF); 530*4c06356bSdh if ((pmcs_tbuf_num_elems == DDI_PROP_NOT_FOUND) || 531*4c06356bSdh (pmcs_tbuf_num_elems == 0)) { 532*4c06356bSdh pmcs_tbuf_num_elems = PMCS_TBUF_NUM_ELEMS_DEF; 533*4c06356bSdh } 534*4c06356bSdh 535*4c06356bSdh pmcs_tbuf = kmem_zalloc(pmcs_tbuf_num_elems * 536*4c06356bSdh sizeof (pmcs_tbuf_t), KM_SLEEP); 537*4c06356bSdh pmcs_tbuf_ptr = pmcs_tbuf; 538*4c06356bSdh pmcs_tbuf_idx = 0; 539*4c06356bSdh } 540*4c06356bSdh mutex_exit(&pmcs_trace_lock); 541*4c06356bSdh 542*4c06356bSdh disable_msix = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 543*4c06356bSdh DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "pmcs-disable-msix", 544*4c06356bSdh disable_msix); 545*4c06356bSdh disable_msi = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 546*4c06356bSdh DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "pmcs-disable-msi", 547*4c06356bSdh disable_msi); 548*4c06356bSdh maxqdepth = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 549*4c06356bSdh DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "pmcs-maxqdepth", maxqdepth); 550*4c06356bSdh pwp->fw_force_update = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 551*4c06356bSdh DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "pmcs-fw-force-update", 0); 552*4c06356bSdh if (pwp->fw_force_update == 0) { 553*4c06356bSdh pwp->fw_disable_update = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 554*4c06356bSdh DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 555*4c06356bSdh "pmcs-fw-disable-update", 0); 556*4c06356bSdh } 557*4c06356bSdh pwp->ioq_depth = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 558*4c06356bSdh DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "pmcs-num-io-qentries", 559*4c06356bSdh PMCS_NQENTRY); 560*4c06356bSdh 561*4c06356bSdh /* 562*4c06356bSdh * Initialize FMA 563*4c06356bSdh */ 564*4c06356bSdh pwp->dev_acc_attr = pwp->reg_acc_attr = rattr; 565*4c06356bSdh pwp->iqp_dma_attr = pwp->oqp_dma_attr = 566*4c06356bSdh pwp->regdump_dma_attr = pwp->cip_dma_attr = 567*4c06356bSdh pwp->fwlog_dma_attr = pmcs_dattr; 568*4c06356bSdh pwp->fm_capabilities = ddi_getprop(DDI_DEV_T_ANY, pwp->dip, 569*4c06356bSdh DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, "fm-capable", 570*4c06356bSdh DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE | 571*4c06356bSdh DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE); 572*4c06356bSdh pmcs_fm_init(pwp); 573*4c06356bSdh 574*4c06356bSdh /* 575*4c06356bSdh * Map registers 576*4c06356bSdh */ 577*4c06356bSdh if (pci_config_setup(dip, &pwp->pci_acc_handle)) { 578*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_WARN, "pci config setup failed"); 579*4c06356bSdh ddi_soft_state_free(pmcs_softc_state, inst); 580*4c06356bSdh return (DDI_FAILURE); 581*4c06356bSdh } 582*4c06356bSdh 583*4c06356bSdh /* 584*4c06356bSdh * Get the size of register set 3. 585*4c06356bSdh */ 586*4c06356bSdh if (ddi_dev_regsize(dip, PMCS_REGSET_3, &set3size) != DDI_SUCCESS) { 587*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 588*4c06356bSdh "unable to get size of register set %d", PMCS_REGSET_3); 589*4c06356bSdh pci_config_teardown(&pwp->pci_acc_handle); 590*4c06356bSdh ddi_soft_state_free(pmcs_softc_state, inst); 591*4c06356bSdh return (DDI_FAILURE); 592*4c06356bSdh } 593*4c06356bSdh 594*4c06356bSdh /* 595*4c06356bSdh * Map registers 596*4c06356bSdh */ 597*4c06356bSdh pwp->reg_acc_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; 598*4c06356bSdh 599*4c06356bSdh if (ddi_regs_map_setup(dip, PMCS_REGSET_0, (caddr_t *)&pwp->msg_regs, 600*4c06356bSdh 0, 0, &pwp->reg_acc_attr, &pwp->msg_acc_handle)) { 601*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 602*4c06356bSdh "failed to map Message Unit registers"); 603*4c06356bSdh pci_config_teardown(&pwp->pci_acc_handle); 604*4c06356bSdh ddi_soft_state_free(pmcs_softc_state, inst); 605*4c06356bSdh return (DDI_FAILURE); 606*4c06356bSdh } 607*4c06356bSdh 608*4c06356bSdh if (ddi_regs_map_setup(dip, PMCS_REGSET_1, (caddr_t *)&pwp->top_regs, 609*4c06356bSdh 0, 0, &pwp->reg_acc_attr, &pwp->top_acc_handle)) { 610*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, "failed to map TOP registers"); 611*4c06356bSdh ddi_regs_map_free(&pwp->msg_acc_handle); 612*4c06356bSdh pci_config_teardown(&pwp->pci_acc_handle); 613*4c06356bSdh ddi_soft_state_free(pmcs_softc_state, inst); 614*4c06356bSdh return (DDI_FAILURE); 615*4c06356bSdh } 616*4c06356bSdh 617*4c06356bSdh if (ddi_regs_map_setup(dip, PMCS_REGSET_2, (caddr_t *)&pwp->gsm_regs, 618*4c06356bSdh 0, 0, &pwp->reg_acc_attr, &pwp->gsm_acc_handle)) { 619*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, "failed to map GSM registers"); 620*4c06356bSdh ddi_regs_map_free(&pwp->top_acc_handle); 621*4c06356bSdh ddi_regs_map_free(&pwp->msg_acc_handle); 622*4c06356bSdh pci_config_teardown(&pwp->pci_acc_handle); 623*4c06356bSdh ddi_soft_state_free(pmcs_softc_state, inst); 624*4c06356bSdh return (DDI_FAILURE); 625*4c06356bSdh } 626*4c06356bSdh 627*4c06356bSdh if (ddi_regs_map_setup(dip, PMCS_REGSET_3, (caddr_t *)&pwp->mpi_regs, 628*4c06356bSdh 0, 0, &pwp->reg_acc_attr, &pwp->mpi_acc_handle)) { 629*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, "failed to map MPI registers"); 630*4c06356bSdh ddi_regs_map_free(&pwp->top_acc_handle); 631*4c06356bSdh ddi_regs_map_free(&pwp->gsm_acc_handle); 632*4c06356bSdh ddi_regs_map_free(&pwp->msg_acc_handle); 633*4c06356bSdh pci_config_teardown(&pwp->pci_acc_handle); 634*4c06356bSdh ddi_soft_state_free(pmcs_softc_state, inst); 635*4c06356bSdh return (DDI_FAILURE); 636*4c06356bSdh } 637*4c06356bSdh pwp->mpibar = 638*4c06356bSdh (((5U << 2) + 0x10) << PMCS_MSGU_MPI_BAR_SHIFT) | set3size; 639*4c06356bSdh 640*4c06356bSdh /* 641*4c06356bSdh * Make sure we can support this card. 642*4c06356bSdh */ 643*4c06356bSdh pwp->chiprev = pmcs_rd_topunit(pwp, PMCS_DEVICE_REVISION); 644*4c06356bSdh 645*4c06356bSdh switch (pwp->chiprev) { 646*4c06356bSdh case PMCS_PM8001_REV_A: 647*4c06356bSdh case PMCS_PM8001_REV_B: 648*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_ERR, 649*4c06356bSdh "Rev A/B Card no longer supported"); 650*4c06356bSdh goto failure; 651*4c06356bSdh case PMCS_PM8001_REV_C: 652*4c06356bSdh break; 653*4c06356bSdh default: 654*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_ERR, 655*4c06356bSdh "Unknown chip revision (%d)", pwp->chiprev); 656*4c06356bSdh goto failure; 657*4c06356bSdh } 658*4c06356bSdh 659*4c06356bSdh /* 660*4c06356bSdh * Allocate DMA addressable area for Inbound and Outbound Queue indices 661*4c06356bSdh * that the chip needs to access plus a space for scratch usage 662*4c06356bSdh */ 663*4c06356bSdh pwp->cip_dma_attr.dma_attr_align = sizeof (uint32_t); 664*4c06356bSdh if (pmcs_dma_setup(pwp, &pwp->cip_dma_attr, &pwp->cip_acchdls, 665*4c06356bSdh &pwp->cip_handles, ptob(1), (caddr_t *)&pwp->cip, 666*4c06356bSdh &pwp->ciaddr) == B_FALSE) { 667*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 668*4c06356bSdh "Failed to setup DMA for index/scratch"); 669*4c06356bSdh goto failure; 670*4c06356bSdh } 671*4c06356bSdh 672*4c06356bSdh bzero(pwp->cip, ptob(1)); 673*4c06356bSdh pwp->scratch = &pwp->cip[PMCS_INDICES_SIZE]; 674*4c06356bSdh pwp->scratch_dma = pwp->ciaddr + PMCS_INDICES_SIZE; 675*4c06356bSdh 676*4c06356bSdh /* 677*4c06356bSdh * Allocate DMA S/G list chunks 678*4c06356bSdh */ 679*4c06356bSdh (void) pmcs_add_more_chunks(pwp, ptob(1) * PMCS_MIN_CHUNK_PAGES); 680*4c06356bSdh 681*4c06356bSdh /* 682*4c06356bSdh * Allocate a DMA addressable area for the firmware log (if needed) 683*4c06356bSdh */ 684*4c06356bSdh if (pwp->fwlog) { 685*4c06356bSdh /* 686*4c06356bSdh * Align to event log header and entry size 687*4c06356bSdh */ 688*4c06356bSdh pwp->fwlog_dma_attr.dma_attr_align = 32; 689*4c06356bSdh if (pmcs_dma_setup(pwp, &pwp->fwlog_dma_attr, 690*4c06356bSdh &pwp->fwlog_acchdl, 691*4c06356bSdh &pwp->fwlog_hndl, PMCS_FWLOG_SIZE, 692*4c06356bSdh (caddr_t *)&pwp->fwlogp, 693*4c06356bSdh &pwp->fwaddr) == B_FALSE) { 694*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 695*4c06356bSdh "Failed to setup DMA for fwlog area"); 696*4c06356bSdh pwp->fwlog = 0; 697*4c06356bSdh } else { 698*4c06356bSdh bzero(pwp->fwlogp, PMCS_FWLOG_SIZE); 699*4c06356bSdh } 700*4c06356bSdh } 701*4c06356bSdh 702*4c06356bSdh if (pwp->flash_chunk_addr == NULL) { 703*4c06356bSdh pwp->regdump_dma_attr.dma_attr_align = PMCS_FLASH_CHUNK_SIZE; 704*4c06356bSdh if (pmcs_dma_setup(pwp, &pwp->regdump_dma_attr, 705*4c06356bSdh &pwp->regdump_acchdl, 706*4c06356bSdh &pwp->regdump_hndl, PMCS_FLASH_CHUNK_SIZE, 707*4c06356bSdh (caddr_t *)&pwp->flash_chunkp, &pwp->flash_chunk_addr) == 708*4c06356bSdh B_FALSE) { 709*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 710*4c06356bSdh "Failed to setup DMA for register dump area"); 711*4c06356bSdh goto failure; 712*4c06356bSdh } 713*4c06356bSdh bzero(pwp->flash_chunkp, PMCS_FLASH_CHUNK_SIZE); 714*4c06356bSdh } 715*4c06356bSdh 716*4c06356bSdh /* 717*4c06356bSdh * More bits of local initialization... 718*4c06356bSdh */ 719*4c06356bSdh pwp->tq = ddi_taskq_create(dip, "_tq", 4, TASKQ_DEFAULTPRI, 0); 720*4c06356bSdh if (pwp->tq == NULL) { 721*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, "unable to create worker taskq"); 722*4c06356bSdh goto failure; 723*4c06356bSdh } 724*4c06356bSdh 725*4c06356bSdh /* 726*4c06356bSdh * Cache of structures for dealing with I/O completion callbacks. 727*4c06356bSdh */ 728*4c06356bSdh (void) snprintf(buf, sizeof (buf), "pmcs_iocomp_cb_cache%d", inst); 729*4c06356bSdh pwp->iocomp_cb_cache = kmem_cache_create(buf, 730*4c06356bSdh sizeof (pmcs_iocomp_cb_t), 16, NULL, NULL, NULL, NULL, NULL, 0); 731*4c06356bSdh 732*4c06356bSdh /* 733*4c06356bSdh * Cache of PHY structures 734*4c06356bSdh */ 735*4c06356bSdh (void) snprintf(buf, sizeof (buf), "pmcs_phy_cache%d", inst); 736*4c06356bSdh pwp->phy_cache = kmem_cache_create(buf, sizeof (pmcs_phy_t), 8, 737*4c06356bSdh pmcs_phy_constructor, pmcs_phy_destructor, NULL, (void *)pwp, 738*4c06356bSdh NULL, 0); 739*4c06356bSdh 740*4c06356bSdh /* 741*4c06356bSdh * Allocate space for the I/O completion threads 742*4c06356bSdh */ 743*4c06356bSdh num_threads = ncpus_online; 744*4c06356bSdh if (num_threads > PMCS_MAX_CQ_THREADS) { 745*4c06356bSdh num_threads = PMCS_MAX_CQ_THREADS; 746*4c06356bSdh } 747*4c06356bSdh 748*4c06356bSdh pwp->cq_info.cq_thr_info = kmem_zalloc(sizeof (pmcs_cq_thr_info_t) * 749*4c06356bSdh num_threads, KM_SLEEP); 750*4c06356bSdh pwp->cq_info.cq_threads = num_threads; 751*4c06356bSdh pwp->cq_info.cq_next_disp_thr = 0; 752*4c06356bSdh pwp->cq_info.cq_stop = B_FALSE; 753*4c06356bSdh 754*4c06356bSdh /* 755*4c06356bSdh * Set the quantum value in clock ticks for the I/O interrupt 756*4c06356bSdh * coalescing timer. 757*4c06356bSdh */ 758*4c06356bSdh pwp->io_intr_coal.quantum = drv_usectohz(PMCS_QUANTUM_TIME_USECS); 759*4c06356bSdh 760*4c06356bSdh /* 761*4c06356bSdh * We have a delicate dance here. We need to set up 762*4c06356bSdh * interrupts so we know how to set up some OQC 763*4c06356bSdh * tables. However, while we're setting up table 764*4c06356bSdh * access, we may need to flash new firmware and 765*4c06356bSdh * reset the card, which will take some finessing. 766*4c06356bSdh */ 767*4c06356bSdh 768*4c06356bSdh /* 769*4c06356bSdh * Set up interrupts here. 770*4c06356bSdh */ 771*4c06356bSdh switch (pmcs_setup_intr(pwp)) { 772*4c06356bSdh case 0: 773*4c06356bSdh break; 774*4c06356bSdh case EIO: 775*4c06356bSdh pwp->stuck = 1; 776*4c06356bSdh /* FALLTHROUGH */ 777*4c06356bSdh default: 778*4c06356bSdh goto failure; 779*4c06356bSdh } 780*4c06356bSdh 781*4c06356bSdh /* 782*4c06356bSdh * Set these up now becuase they are used to initialize the OQC tables. 783*4c06356bSdh * 784*4c06356bSdh * If we have MSI or MSI-X interrupts set up and we have enough 785*4c06356bSdh * vectors for each OQ, the Outbound Queue vectors can all be the 786*4c06356bSdh * same as the appropriate interrupt routine will have been called 787*4c06356bSdh * and the doorbell register automatically cleared. 788*4c06356bSdh * This keeps us from having to check the Outbound Doorbell register 789*4c06356bSdh * when the routines for these interrupts are called. 790*4c06356bSdh * 791*4c06356bSdh * If we have Legacy INT-X interrupts set up or we didn't have enough 792*4c06356bSdh * MSI/MSI-X vectors to uniquely identify each OQ, we point these 793*4c06356bSdh * vectors to the bits we would like to have set in the Outbound 794*4c06356bSdh * Doorbell register because pmcs_all_intr will read the doorbell 795*4c06356bSdh * register to find out why we have an interrupt and write the 796*4c06356bSdh * corresponding 'clear' bit for that interrupt. 797*4c06356bSdh */ 798*4c06356bSdh 799*4c06356bSdh switch (pwp->intr_cnt) { 800*4c06356bSdh case 1: 801*4c06356bSdh /* 802*4c06356bSdh * Only one vector, so we must check all OQs for MSI. For 803*4c06356bSdh * INT-X, there's only one vector anyway, so we can just 804*4c06356bSdh * use the outbound queue bits to keep from having to 805*4c06356bSdh * check each queue for each interrupt. 806*4c06356bSdh */ 807*4c06356bSdh if (pwp->int_type == PMCS_INT_FIXED) { 808*4c06356bSdh pwp->oqvec[PMCS_OQ_IODONE] = PMCS_OQ_IODONE; 809*4c06356bSdh pwp->oqvec[PMCS_OQ_GENERAL] = PMCS_OQ_GENERAL; 810*4c06356bSdh pwp->oqvec[PMCS_OQ_EVENTS] = PMCS_OQ_EVENTS; 811*4c06356bSdh } else { 812*4c06356bSdh pwp->oqvec[PMCS_OQ_IODONE] = PMCS_OQ_IODONE; 813*4c06356bSdh pwp->oqvec[PMCS_OQ_GENERAL] = PMCS_OQ_IODONE; 814*4c06356bSdh pwp->oqvec[PMCS_OQ_EVENTS] = PMCS_OQ_IODONE; 815*4c06356bSdh } 816*4c06356bSdh break; 817*4c06356bSdh case 2: 818*4c06356bSdh /* With 2, we can at least isolate IODONE */ 819*4c06356bSdh pwp->oqvec[PMCS_OQ_IODONE] = PMCS_OQ_IODONE; 820*4c06356bSdh pwp->oqvec[PMCS_OQ_GENERAL] = PMCS_OQ_GENERAL; 821*4c06356bSdh pwp->oqvec[PMCS_OQ_EVENTS] = PMCS_OQ_GENERAL; 822*4c06356bSdh break; 823*4c06356bSdh case 4: 824*4c06356bSdh /* With 4 vectors, everybody gets one */ 825*4c06356bSdh pwp->oqvec[PMCS_OQ_IODONE] = PMCS_OQ_IODONE; 826*4c06356bSdh pwp->oqvec[PMCS_OQ_GENERAL] = PMCS_OQ_GENERAL; 827*4c06356bSdh pwp->oqvec[PMCS_OQ_EVENTS] = PMCS_OQ_EVENTS; 828*4c06356bSdh break; 829*4c06356bSdh } 830*4c06356bSdh 831*4c06356bSdh /* 832*4c06356bSdh * Do the first part of setup 833*4c06356bSdh */ 834*4c06356bSdh if (pmcs_setup(pwp)) { 835*4c06356bSdh goto failure; 836*4c06356bSdh } 837*4c06356bSdh pmcs_report_fwversion(pwp); 838*4c06356bSdh 839*4c06356bSdh /* 840*4c06356bSdh * Now do some additonal allocations based upon information 841*4c06356bSdh * gathered during MPI setup. 842*4c06356bSdh */ 843*4c06356bSdh pwp->root_phys = kmem_zalloc(pwp->nphy * sizeof (pmcs_phy_t), KM_SLEEP); 844*4c06356bSdh ASSERT(pwp->nphy < SAS2_PHYNUM_MAX); 845*4c06356bSdh phyp = pwp->root_phys; 846*4c06356bSdh for (i = 0; i < pwp->nphy; i++) { 847*4c06356bSdh if (i < pwp->nphy-1) { 848*4c06356bSdh phyp->sibling = (phyp + 1); 849*4c06356bSdh } 850*4c06356bSdh mutex_init(&phyp->phy_lock, NULL, MUTEX_DRIVER, 851*4c06356bSdh DDI_INTR_PRI(pwp->intr_pri)); 852*4c06356bSdh phyp->phynum = i & SAS2_PHYNUM_MASK; 853*4c06356bSdh pmcs_phy_name(pwp, phyp, phyp->path, sizeof (phyp->path)); 854*4c06356bSdh phyp->pwp = pwp; 855*4c06356bSdh phyp->device_id = PMCS_INVALID_DEVICE_ID; 856*4c06356bSdh phyp++; 857*4c06356bSdh } 858*4c06356bSdh 859*4c06356bSdh pwp->work = kmem_zalloc(pwp->max_cmd * sizeof (pmcwork_t), KM_SLEEP); 860*4c06356bSdh for (i = 0; i < pwp->max_cmd - 1; i++) { 861*4c06356bSdh pmcwork_t *pwrk = &pwp->work[i]; 862*4c06356bSdh mutex_init(&pwrk->lock, NULL, MUTEX_DRIVER, 863*4c06356bSdh DDI_INTR_PRI(pwp->intr_pri)); 864*4c06356bSdh cv_init(&pwrk->sleep_cv, NULL, CV_DRIVER, NULL); 865*4c06356bSdh STAILQ_INSERT_TAIL(&pwp->wf, pwrk, next); 866*4c06356bSdh 867*4c06356bSdh } 868*4c06356bSdh pwp->targets = (pmcs_xscsi_t **) 869*4c06356bSdh kmem_zalloc(pwp->max_dev * sizeof (pmcs_xscsi_t *), KM_SLEEP); 870*4c06356bSdh 871*4c06356bSdh pwp->iqpt = (pmcs_iqp_trace_t *) 872*4c06356bSdh kmem_zalloc(sizeof (pmcs_iqp_trace_t), KM_SLEEP); 873*4c06356bSdh pwp->iqpt->head = kmem_zalloc(PMCS_IQP_TRACE_BUFFER_SIZE, KM_SLEEP); 874*4c06356bSdh pwp->iqpt->curpos = pwp->iqpt->head; 875*4c06356bSdh pwp->iqpt->size_left = PMCS_IQP_TRACE_BUFFER_SIZE; 876*4c06356bSdh 877*4c06356bSdh /* 878*4c06356bSdh * Start MPI communication. 879*4c06356bSdh */ 880*4c06356bSdh if (pmcs_start_mpi(pwp)) { 881*4c06356bSdh if (pmcs_soft_reset(pwp, B_FALSE)) { 882*4c06356bSdh goto failure; 883*4c06356bSdh } 884*4c06356bSdh } 885*4c06356bSdh 886*4c06356bSdh /* 887*4c06356bSdh * Do some initial acceptance tests. 888*4c06356bSdh * This tests interrupts and queues. 889*4c06356bSdh */ 890*4c06356bSdh if (pmcs_echo_test(pwp)) { 891*4c06356bSdh goto failure; 892*4c06356bSdh } 893*4c06356bSdh 894*4c06356bSdh /* Read VPD - if it exists */ 895*4c06356bSdh if (pmcs_get_nvmd(pwp, PMCS_NVMD_VPD, PMCIN_NVMD_VPD, 0, NULL, 0)) { 896*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, "%s: Unable to read VPD: " 897*4c06356bSdh "attempting to fabricate", __func__); 898*4c06356bSdh /* 899*4c06356bSdh * When we release, this must goto failure and the call 900*4c06356bSdh * to pmcs_fabricate_wwid is removed. 901*4c06356bSdh */ 902*4c06356bSdh /* goto failure; */ 903*4c06356bSdh if (!pmcs_fabricate_wwid(pwp)) { 904*4c06356bSdh goto failure; 905*4c06356bSdh } 906*4c06356bSdh } 907*4c06356bSdh 908*4c06356bSdh /* 909*4c06356bSdh * We're now officially running 910*4c06356bSdh */ 911*4c06356bSdh pwp->state = STATE_RUNNING; 912*4c06356bSdh 913*4c06356bSdh /* 914*4c06356bSdh * Check firmware versions and load new firmware 915*4c06356bSdh * if needed and reset. 916*4c06356bSdh */ 917*4c06356bSdh if (pmcs_firmware_update(pwp)) { 918*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_WARN, "%s: Firmware update failed", 919*4c06356bSdh __func__); 920*4c06356bSdh goto failure; 921*4c06356bSdh } 922*4c06356bSdh 923*4c06356bSdh /* 924*4c06356bSdh * Create completion threads. 925*4c06356bSdh */ 926*4c06356bSdh for (i = 0; i < pwp->cq_info.cq_threads; i++) { 927*4c06356bSdh pwp->cq_info.cq_thr_info[i].cq_pwp = pwp; 928*4c06356bSdh pwp->cq_info.cq_thr_info[i].cq_thread = 929*4c06356bSdh thread_create(NULL, 0, pmcs_scsa_cq_run, 930*4c06356bSdh &pwp->cq_info.cq_thr_info[i], 0, &p0, TS_RUN, minclsyspri); 931*4c06356bSdh } 932*4c06356bSdh 933*4c06356bSdh /* 934*4c06356bSdh * Create one thread to deal with the updating of the interrupt 935*4c06356bSdh * coalescing timer. 936*4c06356bSdh */ 937*4c06356bSdh pwp->ict_thread = thread_create(NULL, 0, pmcs_check_intr_coal, 938*4c06356bSdh pwp, 0, &p0, TS_RUN, minclsyspri); 939*4c06356bSdh 940*4c06356bSdh /* 941*4c06356bSdh * Kick off the watchdog 942*4c06356bSdh */ 943*4c06356bSdh pwp->wdhandle = timeout(pmcs_watchdog, pwp, 944*4c06356bSdh drv_usectohz(PMCS_WATCH_INTERVAL)); 945*4c06356bSdh /* 946*4c06356bSdh * Do the SCSI attachment code (before starting phys) 947*4c06356bSdh */ 948*4c06356bSdh if (pmcs_scsa_init(pwp, &pmcs_dattr)) { 949*4c06356bSdh goto failure; 950*4c06356bSdh } 951*4c06356bSdh pwp->hba_attached = 1; 952*4c06356bSdh 953*4c06356bSdh /* 954*4c06356bSdh * Initialize the rwlock for the iport elements. 955*4c06356bSdh */ 956*4c06356bSdh rw_init(&pwp->iports_lock, NULL, RW_DRIVER, NULL); 957*4c06356bSdh 958*4c06356bSdh /* Check all acc & dma handles allocated in attach */ 959*4c06356bSdh if (pmcs_check_acc_dma_handle(pwp)) { 960*4c06356bSdh ddi_fm_service_impact(pwp->dip, DDI_SERVICE_LOST); 961*4c06356bSdh goto failure; 962*4c06356bSdh } 963*4c06356bSdh 964*4c06356bSdh /* 965*4c06356bSdh * Create the phymap for this HBA instance 966*4c06356bSdh */ 967*4c06356bSdh if (sas_phymap_create(dip, phymap_usec, PHYMAP_MODE_SIMPLE, NULL, 968*4c06356bSdh pwp, pmcs_phymap_activate, pmcs_phymap_deactivate, 969*4c06356bSdh &pwp->hss_phymap) != DDI_SUCCESS) { 970*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, "%s: pmcs%d phymap_create failed", 971*4c06356bSdh __func__, inst); 972*4c06356bSdh goto failure; 973*4c06356bSdh } 974*4c06356bSdh ASSERT(pwp->hss_phymap); 975*4c06356bSdh 976*4c06356bSdh /* 977*4c06356bSdh * Create the iportmap for this HBA instance 978*4c06356bSdh */ 979*4c06356bSdh if (scsi_hba_iportmap_create(dip, iportmap_usec, pwp->nphy, 980*4c06356bSdh &pwp->hss_iportmap) != DDI_SUCCESS) { 981*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, "%s: pmcs%d iportmap_create " 982*4c06356bSdh "failed", __func__, inst); 983*4c06356bSdh goto failure; 984*4c06356bSdh } 985*4c06356bSdh ASSERT(pwp->hss_iportmap); 986*4c06356bSdh 987*4c06356bSdh /* 988*4c06356bSdh * Start the PHYs. 989*4c06356bSdh */ 990*4c06356bSdh if (pmcs_start_phys(pwp)) { 991*4c06356bSdh goto failure; 992*4c06356bSdh } 993*4c06356bSdh 994*4c06356bSdh /* 995*4c06356bSdh * From this point on, we can't fail. 996*4c06356bSdh */ 997*4c06356bSdh ddi_report_dev(dip); 998*4c06356bSdh 999*4c06356bSdh /* SM-HBA */ 1000*4c06356bSdh pmcs_smhba_add_hba_prop(pwp, DATA_TYPE_INT32, PMCS_SMHBA_SUPPORTED, 1001*4c06356bSdh &sm_hba); 1002*4c06356bSdh 1003*4c06356bSdh /* SM-HBA */ 1004*4c06356bSdh pmcs_smhba_add_hba_prop(pwp, DATA_TYPE_STRING, PMCS_DRV_VERSION, 1005*4c06356bSdh pmcs_driver_rev); 1006*4c06356bSdh 1007*4c06356bSdh /* SM-HBA */ 1008*4c06356bSdh chiprev = 'A' + pwp->chiprev; 1009*4c06356bSdh (void) snprintf(hw_rev, 2, "%s", &chiprev); 1010*4c06356bSdh pmcs_smhba_add_hba_prop(pwp, DATA_TYPE_STRING, PMCS_HWARE_VERSION, 1011*4c06356bSdh hw_rev); 1012*4c06356bSdh 1013*4c06356bSdh /* SM-HBA */ 1014*4c06356bSdh switch (PMCS_FW_TYPE(pwp)) { 1015*4c06356bSdh case PMCS_FW_TYPE_RELEASED: 1016*4c06356bSdh fwsupport = "Released"; 1017*4c06356bSdh break; 1018*4c06356bSdh case PMCS_FW_TYPE_DEVELOPMENT: 1019*4c06356bSdh fwsupport = "Development"; 1020*4c06356bSdh break; 1021*4c06356bSdh case PMCS_FW_TYPE_ALPHA: 1022*4c06356bSdh fwsupport = "Alpha"; 1023*4c06356bSdh break; 1024*4c06356bSdh case PMCS_FW_TYPE_BETA: 1025*4c06356bSdh fwsupport = "Beta"; 1026*4c06356bSdh break; 1027*4c06356bSdh default: 1028*4c06356bSdh fwsupport = "Special"; 1029*4c06356bSdh break; 1030*4c06356bSdh } 1031*4c06356bSdh (void) snprintf(fw_rev, sizeof (fw_rev), "%x.%x.%x %s", 1032*4c06356bSdh PMCS_FW_MAJOR(pwp), PMCS_FW_MINOR(pwp), PMCS_FW_MICRO(pwp), 1033*4c06356bSdh fwsupport); 1034*4c06356bSdh pmcs_smhba_add_hba_prop(pwp, DATA_TYPE_STRING, PMCS_FWARE_VERSION, 1035*4c06356bSdh fw_rev); 1036*4c06356bSdh 1037*4c06356bSdh /* SM-HBA */ 1038*4c06356bSdh num_phys = pwp->nphy; 1039*4c06356bSdh pmcs_smhba_add_hba_prop(pwp, DATA_TYPE_INT32, PMCS_NUM_PHYS_HBA, 1040*4c06356bSdh &num_phys); 1041*4c06356bSdh 1042*4c06356bSdh /* SM-HBA */ 1043*4c06356bSdh protocol = SAS_SSP_SUPPORT | SAS_SATA_SUPPORT | SAS_SMP_SUPPORT; 1044*4c06356bSdh pmcs_smhba_add_hba_prop(pwp, DATA_TYPE_INT32, PMCS_SUPPORTED_PROTOCOL, 1045*4c06356bSdh &protocol); 1046*4c06356bSdh 1047*4c06356bSdh return (DDI_SUCCESS); 1048*4c06356bSdh 1049*4c06356bSdh failure: 1050*4c06356bSdh if (pmcs_unattach(pwp)) { 1051*4c06356bSdh pwp->stuck = 1; 1052*4c06356bSdh } 1053*4c06356bSdh return (DDI_FAILURE); 1054*4c06356bSdh } 1055*4c06356bSdh 1056*4c06356bSdh int 1057*4c06356bSdh pmcs_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 1058*4c06356bSdh { 1059*4c06356bSdh int inst = ddi_get_instance(dip); 1060*4c06356bSdh pmcs_iport_t *iport = NULL; 1061*4c06356bSdh pmcs_hw_t *pwp = NULL; 1062*4c06356bSdh scsi_hba_tran_t *tran; 1063*4c06356bSdh 1064*4c06356bSdh if (scsi_hba_iport_unit_address(dip) != NULL) { 1065*4c06356bSdh /* iport node */ 1066*4c06356bSdh iport = ddi_get_soft_state(pmcs_iport_softstate, inst); 1067*4c06356bSdh ASSERT(iport); 1068*4c06356bSdh if (iport == NULL) { 1069*4c06356bSdh return (DDI_FAILURE); 1070*4c06356bSdh } 1071*4c06356bSdh pwp = iport->pwp; 1072*4c06356bSdh } else { 1073*4c06356bSdh /* hba node */ 1074*4c06356bSdh pwp = (pmcs_hw_t *)ddi_get_soft_state(pmcs_softc_state, inst); 1075*4c06356bSdh ASSERT(pwp); 1076*4c06356bSdh if (pwp == NULL) { 1077*4c06356bSdh return (DDI_FAILURE); 1078*4c06356bSdh } 1079*4c06356bSdh } 1080*4c06356bSdh 1081*4c06356bSdh switch (cmd) { 1082*4c06356bSdh case DDI_DETACH: 1083*4c06356bSdh if (iport) { 1084*4c06356bSdh /* iport detach */ 1085*4c06356bSdh if (pmcs_iport_unattach(iport)) { 1086*4c06356bSdh return (DDI_FAILURE); 1087*4c06356bSdh } 1088*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, "iport%d detached", inst); 1089*4c06356bSdh return (DDI_SUCCESS); 1090*4c06356bSdh } else { 1091*4c06356bSdh /* HBA detach */ 1092*4c06356bSdh if (pmcs_unattach(pwp)) { 1093*4c06356bSdh return (DDI_FAILURE); 1094*4c06356bSdh } 1095*4c06356bSdh return (DDI_SUCCESS); 1096*4c06356bSdh } 1097*4c06356bSdh 1098*4c06356bSdh case DDI_SUSPEND: 1099*4c06356bSdh case DDI_PM_SUSPEND: 1100*4c06356bSdh /* No DDI_SUSPEND on iport nodes */ 1101*4c06356bSdh if (iport) { 1102*4c06356bSdh return (DDI_SUCCESS); 1103*4c06356bSdh } 1104*4c06356bSdh 1105*4c06356bSdh if (pwp->stuck) { 1106*4c06356bSdh return (DDI_FAILURE); 1107*4c06356bSdh } 1108*4c06356bSdh tran = (scsi_hba_tran_t *)ddi_get_driver_private(dip); 1109*4c06356bSdh if (!tran) { 1110*4c06356bSdh return (DDI_FAILURE); 1111*4c06356bSdh } 1112*4c06356bSdh 1113*4c06356bSdh pwp = TRAN2PMC(tran); 1114*4c06356bSdh if (pwp == NULL) { 1115*4c06356bSdh return (DDI_FAILURE); 1116*4c06356bSdh } 1117*4c06356bSdh mutex_enter(&pwp->lock); 1118*4c06356bSdh if (pwp->tq) { 1119*4c06356bSdh ddi_taskq_suspend(pwp->tq); 1120*4c06356bSdh } 1121*4c06356bSdh pwp->suspended = 1; 1122*4c06356bSdh mutex_exit(&pwp->lock); 1123*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_INFO, "PMC8X6G suspending"); 1124*4c06356bSdh return (DDI_SUCCESS); 1125*4c06356bSdh 1126*4c06356bSdh default: 1127*4c06356bSdh return (DDI_FAILURE); 1128*4c06356bSdh } 1129*4c06356bSdh } 1130*4c06356bSdh 1131*4c06356bSdh static int 1132*4c06356bSdh pmcs_iport_unattach(pmcs_iport_t *iport) 1133*4c06356bSdh { 1134*4c06356bSdh pmcs_hw_t *pwp = iport->pwp; 1135*4c06356bSdh 1136*4c06356bSdh /* 1137*4c06356bSdh * First, check if there are still any configured targets on this 1138*4c06356bSdh * iport. If so, we fail detach. 1139*4c06356bSdh */ 1140*4c06356bSdh if (pmcs_iport_has_targets(pwp, iport)) { 1141*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG_IPORT, "iport%d detach failure: " 1142*4c06356bSdh "iport has targets (luns)", ddi_get_instance(iport->dip)); 1143*4c06356bSdh return (DDI_FAILURE); 1144*4c06356bSdh } 1145*4c06356bSdh 1146*4c06356bSdh /* 1147*4c06356bSdh * Remove this iport from our list if it is inactive in the phymap. 1148*4c06356bSdh */ 1149*4c06356bSdh rw_enter(&pwp->iports_lock, RW_WRITER); 1150*4c06356bSdh mutex_enter(&iport->lock); 1151*4c06356bSdh 1152*4c06356bSdh if (iport->ua_state == UA_ACTIVE) { 1153*4c06356bSdh mutex_exit(&iport->lock); 1154*4c06356bSdh rw_exit(&pwp->iports_lock); 1155*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG_IPORT, "iport%d detach failure: " 1156*4c06356bSdh "iport unit address active in phymap", 1157*4c06356bSdh ddi_get_instance(iport->dip)); 1158*4c06356bSdh return (DDI_FAILURE); 1159*4c06356bSdh } 1160*4c06356bSdh 1161*4c06356bSdh /* If it's our only iport, clear iports_attached */ 1162*4c06356bSdh ASSERT(pwp->num_iports >= 1); 1163*4c06356bSdh if (--pwp->num_iports == 0) { 1164*4c06356bSdh pwp->iports_attached = 0; 1165*4c06356bSdh } 1166*4c06356bSdh 1167*4c06356bSdh ASSERT(list_link_active(&iport->list_node)); 1168*4c06356bSdh list_remove(&pwp->iports, iport); 1169*4c06356bSdh rw_exit(&pwp->iports_lock); 1170*4c06356bSdh 1171*4c06356bSdh /* 1172*4c06356bSdh * We have removed the iport handle from the HBA's iports list, 1173*4c06356bSdh * there will be no new references to it. Two things must be 1174*4c06356bSdh * guarded against here. First, we could have PHY up events, 1175*4c06356bSdh * adding themselves to the iport->phys list and grabbing ref's 1176*4c06356bSdh * on our iport handle. Second, we could have existing references 1177*4c06356bSdh * to this iport handle from a point in time prior to the list 1178*4c06356bSdh * removal above. 1179*4c06356bSdh * 1180*4c06356bSdh * So first, destroy the phys list. Remove any phys that have snuck 1181*4c06356bSdh * in after the phymap deactivate, dropping the refcnt accordingly. 1182*4c06356bSdh * If these PHYs are still up if and when the phymap reactivates 1183*4c06356bSdh * (i.e. when this iport reattaches), we'll populate the list with 1184*4c06356bSdh * them and bump the refcnt back up. 1185*4c06356bSdh */ 1186*4c06356bSdh pmcs_remove_phy_from_iport(iport, NULL); 1187*4c06356bSdh ASSERT(list_is_empty(&iport->phys)); 1188*4c06356bSdh list_destroy(&iport->phys); 1189*4c06356bSdh mutex_exit(&iport->lock); 1190*4c06356bSdh 1191*4c06356bSdh /* 1192*4c06356bSdh * Second, wait for any other references to this iport to be 1193*4c06356bSdh * dropped, then continue teardown. 1194*4c06356bSdh */ 1195*4c06356bSdh mutex_enter(&iport->refcnt_lock); 1196*4c06356bSdh while (iport->refcnt != 0) { 1197*4c06356bSdh cv_wait(&iport->refcnt_cv, &iport->refcnt_lock); 1198*4c06356bSdh } 1199*4c06356bSdh mutex_exit(&iport->refcnt_lock); 1200*4c06356bSdh 1201*4c06356bSdh /* Delete kstats */ 1202*4c06356bSdh pmcs_destroy_phy_stats(iport); 1203*4c06356bSdh 1204*4c06356bSdh /* Destroy the iport target map */ 1205*4c06356bSdh if (pmcs_iport_tgtmap_destroy(iport) == B_FALSE) { 1206*4c06356bSdh return (DDI_FAILURE); 1207*4c06356bSdh } 1208*4c06356bSdh 1209*4c06356bSdh /* Free the tgt soft state */ 1210*4c06356bSdh if (iport->tgt_sstate != NULL) { 1211*4c06356bSdh ddi_soft_state_bystr_fini(&iport->tgt_sstate); 1212*4c06356bSdh } 1213*4c06356bSdh 1214*4c06356bSdh /* Free our unit address string */ 1215*4c06356bSdh strfree(iport->ua); 1216*4c06356bSdh 1217*4c06356bSdh /* Finish teardown and free the softstate */ 1218*4c06356bSdh mutex_destroy(&iport->refcnt_lock); 1219*4c06356bSdh ASSERT(iport->refcnt == 0); 1220*4c06356bSdh cv_destroy(&iport->refcnt_cv); 1221*4c06356bSdh mutex_destroy(&iport->lock); 1222*4c06356bSdh ddi_soft_state_free(pmcs_iport_softstate, ddi_get_instance(iport->dip)); 1223*4c06356bSdh 1224*4c06356bSdh return (DDI_SUCCESS); 1225*4c06356bSdh } 1226*4c06356bSdh 1227*4c06356bSdh static int 1228*4c06356bSdh pmcs_unattach(pmcs_hw_t *pwp) 1229*4c06356bSdh { 1230*4c06356bSdh int i; 1231*4c06356bSdh enum pwpstate curstate; 1232*4c06356bSdh pmcs_cq_thr_info_t *cqti; 1233*4c06356bSdh 1234*4c06356bSdh /* 1235*4c06356bSdh * Tear down the interrupt infrastructure. 1236*4c06356bSdh */ 1237*4c06356bSdh if (pmcs_teardown_intr(pwp)) { 1238*4c06356bSdh pwp->stuck = 1; 1239*4c06356bSdh } 1240*4c06356bSdh pwp->intr_cnt = 0; 1241*4c06356bSdh 1242*4c06356bSdh /* 1243*4c06356bSdh * Grab a lock, if initted, to set state. 1244*4c06356bSdh */ 1245*4c06356bSdh if (pwp->locks_initted) { 1246*4c06356bSdh mutex_enter(&pwp->lock); 1247*4c06356bSdh if (pwp->state != STATE_DEAD) { 1248*4c06356bSdh pwp->state = STATE_UNPROBING; 1249*4c06356bSdh } 1250*4c06356bSdh curstate = pwp->state; 1251*4c06356bSdh mutex_exit(&pwp->lock); 1252*4c06356bSdh 1253*4c06356bSdh /* 1254*4c06356bSdh * Stop the I/O completion threads. 1255*4c06356bSdh */ 1256*4c06356bSdh mutex_enter(&pwp->cq_lock); 1257*4c06356bSdh pwp->cq_info.cq_stop = B_TRUE; 1258*4c06356bSdh for (i = 0; i < pwp->cq_info.cq_threads; i++) { 1259*4c06356bSdh if (pwp->cq_info.cq_thr_info[i].cq_thread) { 1260*4c06356bSdh cqti = &pwp->cq_info.cq_thr_info[i]; 1261*4c06356bSdh mutex_enter(&cqti->cq_thr_lock); 1262*4c06356bSdh cv_signal(&cqti->cq_cv); 1263*4c06356bSdh mutex_exit(&cqti->cq_thr_lock); 1264*4c06356bSdh mutex_exit(&pwp->cq_lock); 1265*4c06356bSdh thread_join(cqti->cq_thread->t_did); 1266*4c06356bSdh mutex_enter(&pwp->cq_lock); 1267*4c06356bSdh } 1268*4c06356bSdh } 1269*4c06356bSdh mutex_exit(&pwp->cq_lock); 1270*4c06356bSdh 1271*4c06356bSdh /* 1272*4c06356bSdh * Stop the interrupt coalescing timer thread 1273*4c06356bSdh */ 1274*4c06356bSdh if (pwp->ict_thread) { 1275*4c06356bSdh mutex_enter(&pwp->ict_lock); 1276*4c06356bSdh pwp->io_intr_coal.stop_thread = B_TRUE; 1277*4c06356bSdh cv_signal(&pwp->ict_cv); 1278*4c06356bSdh mutex_exit(&pwp->ict_lock); 1279*4c06356bSdh thread_join(pwp->ict_thread->t_did); 1280*4c06356bSdh } 1281*4c06356bSdh } else { 1282*4c06356bSdh if (pwp->state != STATE_DEAD) { 1283*4c06356bSdh pwp->state = STATE_UNPROBING; 1284*4c06356bSdh } 1285*4c06356bSdh curstate = pwp->state; 1286*4c06356bSdh } 1287*4c06356bSdh 1288*4c06356bSdh if (&pwp->iports != NULL) { 1289*4c06356bSdh /* Destroy the iports lock */ 1290*4c06356bSdh rw_destroy(&pwp->iports_lock); 1291*4c06356bSdh /* Destroy the iports list */ 1292*4c06356bSdh ASSERT(list_is_empty(&pwp->iports)); 1293*4c06356bSdh list_destroy(&pwp->iports); 1294*4c06356bSdh } 1295*4c06356bSdh 1296*4c06356bSdh if (pwp->hss_iportmap != NULL) { 1297*4c06356bSdh /* Destroy the iportmap */ 1298*4c06356bSdh scsi_hba_iportmap_destroy(pwp->hss_iportmap); 1299*4c06356bSdh } 1300*4c06356bSdh 1301*4c06356bSdh if (pwp->hss_phymap != NULL) { 1302*4c06356bSdh /* Destroy the phymap */ 1303*4c06356bSdh sas_phymap_destroy(pwp->hss_phymap); 1304*4c06356bSdh } 1305*4c06356bSdh 1306*4c06356bSdh /* 1307*4c06356bSdh * Make sure that any pending watchdog won't 1308*4c06356bSdh * be called from this point on out. 1309*4c06356bSdh */ 1310*4c06356bSdh (void) untimeout(pwp->wdhandle); 1311*4c06356bSdh /* 1312*4c06356bSdh * After the above action, the watchdog 1313*4c06356bSdh * timer that starts up the worker task 1314*4c06356bSdh * may trigger but will exit immediately 1315*4c06356bSdh * on triggering. 1316*4c06356bSdh * 1317*4c06356bSdh * Now that this is done, we can destroy 1318*4c06356bSdh * the task queue, which will wait if we're 1319*4c06356bSdh * running something on it. 1320*4c06356bSdh */ 1321*4c06356bSdh if (pwp->tq) { 1322*4c06356bSdh ddi_taskq_destroy(pwp->tq); 1323*4c06356bSdh pwp->tq = NULL; 1324*4c06356bSdh } 1325*4c06356bSdh 1326*4c06356bSdh pmcs_fm_fini(pwp); 1327*4c06356bSdh 1328*4c06356bSdh if (pwp->hba_attached) { 1329*4c06356bSdh (void) scsi_hba_detach(pwp->dip); 1330*4c06356bSdh pwp->hba_attached = 0; 1331*4c06356bSdh } 1332*4c06356bSdh 1333*4c06356bSdh /* 1334*4c06356bSdh * If the chip hasn't been marked dead, shut it down now 1335*4c06356bSdh * to bring it back to a known state without attempting 1336*4c06356bSdh * a soft reset. 1337*4c06356bSdh */ 1338*4c06356bSdh if (curstate != STATE_DEAD && pwp->locks_initted) { 1339*4c06356bSdh /* 1340*4c06356bSdh * De-register all registered devices 1341*4c06356bSdh */ 1342*4c06356bSdh pmcs_deregister_devices(pwp, pwp->root_phys); 1343*4c06356bSdh 1344*4c06356bSdh /* 1345*4c06356bSdh * Stop all the phys. 1346*4c06356bSdh */ 1347*4c06356bSdh pmcs_stop_phys(pwp); 1348*4c06356bSdh 1349*4c06356bSdh /* 1350*4c06356bSdh * Shut Down Message Passing 1351*4c06356bSdh */ 1352*4c06356bSdh (void) pmcs_stop_mpi(pwp); 1353*4c06356bSdh 1354*4c06356bSdh /* 1355*4c06356bSdh * Reset chip 1356*4c06356bSdh */ 1357*4c06356bSdh (void) pmcs_soft_reset(pwp, B_FALSE); 1358*4c06356bSdh } 1359*4c06356bSdh 1360*4c06356bSdh /* 1361*4c06356bSdh * Turn off interrupts on the chip 1362*4c06356bSdh */ 1363*4c06356bSdh if (pwp->mpi_acc_handle) { 1364*4c06356bSdh pmcs_wr_msgunit(pwp, PMCS_MSGU_OBDB_MASK, 0xffffffff); 1365*4c06356bSdh } 1366*4c06356bSdh 1367*4c06356bSdh /* Destroy pwp's lock */ 1368*4c06356bSdh if (pwp->locks_initted) { 1369*4c06356bSdh mutex_destroy(&pwp->lock); 1370*4c06356bSdh mutex_destroy(&pwp->dma_lock); 1371*4c06356bSdh mutex_destroy(&pwp->axil_lock); 1372*4c06356bSdh mutex_destroy(&pwp->cq_lock); 1373*4c06356bSdh mutex_destroy(&pwp->config_lock); 1374*4c06356bSdh mutex_destroy(&pwp->ict_lock); 1375*4c06356bSdh mutex_destroy(&pwp->wfree_lock); 1376*4c06356bSdh mutex_destroy(&pwp->pfree_lock); 1377*4c06356bSdh mutex_destroy(&pwp->dead_phylist_lock); 1378*4c06356bSdh #ifdef DEBUG 1379*4c06356bSdh mutex_destroy(&pwp->dbglock); 1380*4c06356bSdh #endif 1381*4c06356bSdh cv_destroy(&pwp->ict_cv); 1382*4c06356bSdh cv_destroy(&pwp->drain_cv); 1383*4c06356bSdh pwp->locks_initted = 0; 1384*4c06356bSdh } 1385*4c06356bSdh 1386*4c06356bSdh /* 1387*4c06356bSdh * Free DMA handles and associated consistent memory 1388*4c06356bSdh */ 1389*4c06356bSdh if (pwp->regdump_hndl) { 1390*4c06356bSdh if (ddi_dma_unbind_handle(pwp->regdump_hndl) != DDI_SUCCESS) { 1391*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, "Condition check failed " 1392*4c06356bSdh "at %s():%d", __func__, __LINE__); 1393*4c06356bSdh } 1394*4c06356bSdh ddi_dma_free_handle(&pwp->regdump_hndl); 1395*4c06356bSdh ddi_dma_mem_free(&pwp->regdump_acchdl); 1396*4c06356bSdh pwp->regdump_hndl = 0; 1397*4c06356bSdh } 1398*4c06356bSdh if (pwp->fwlog_hndl) { 1399*4c06356bSdh if (ddi_dma_unbind_handle(pwp->fwlog_hndl) != DDI_SUCCESS) { 1400*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, "Condition check failed " 1401*4c06356bSdh "at %s():%d", __func__, __LINE__); 1402*4c06356bSdh } 1403*4c06356bSdh ddi_dma_free_handle(&pwp->fwlog_hndl); 1404*4c06356bSdh ddi_dma_mem_free(&pwp->fwlog_acchdl); 1405*4c06356bSdh pwp->fwlog_hndl = 0; 1406*4c06356bSdh } 1407*4c06356bSdh if (pwp->cip_handles) { 1408*4c06356bSdh if (ddi_dma_unbind_handle(pwp->cip_handles) != DDI_SUCCESS) { 1409*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, "Condition check failed " 1410*4c06356bSdh "at %s():%d", __func__, __LINE__); 1411*4c06356bSdh } 1412*4c06356bSdh ddi_dma_free_handle(&pwp->cip_handles); 1413*4c06356bSdh ddi_dma_mem_free(&pwp->cip_acchdls); 1414*4c06356bSdh pwp->cip_handles = 0; 1415*4c06356bSdh } 1416*4c06356bSdh for (i = 0; i < PMCS_NOQ; i++) { 1417*4c06356bSdh if (pwp->oqp_handles[i]) { 1418*4c06356bSdh if (ddi_dma_unbind_handle(pwp->oqp_handles[i]) != 1419*4c06356bSdh DDI_SUCCESS) { 1420*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, "Condition check " 1421*4c06356bSdh "failed at %s():%d", __func__, __LINE__); 1422*4c06356bSdh } 1423*4c06356bSdh ddi_dma_free_handle(&pwp->oqp_handles[i]); 1424*4c06356bSdh ddi_dma_mem_free(&pwp->oqp_acchdls[i]); 1425*4c06356bSdh pwp->oqp_handles[i] = 0; 1426*4c06356bSdh } 1427*4c06356bSdh } 1428*4c06356bSdh for (i = 0; i < PMCS_NIQ; i++) { 1429*4c06356bSdh if (pwp->iqp_handles[i]) { 1430*4c06356bSdh if (ddi_dma_unbind_handle(pwp->iqp_handles[i]) != 1431*4c06356bSdh DDI_SUCCESS) { 1432*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, "Condition check " 1433*4c06356bSdh "failed at %s():%d", __func__, __LINE__); 1434*4c06356bSdh } 1435*4c06356bSdh ddi_dma_free_handle(&pwp->iqp_handles[i]); 1436*4c06356bSdh ddi_dma_mem_free(&pwp->iqp_acchdls[i]); 1437*4c06356bSdh pwp->iqp_handles[i] = 0; 1438*4c06356bSdh } 1439*4c06356bSdh } 1440*4c06356bSdh 1441*4c06356bSdh pmcs_free_dma_chunklist(pwp); 1442*4c06356bSdh 1443*4c06356bSdh /* 1444*4c06356bSdh * Unmap registers and destroy access handles 1445*4c06356bSdh */ 1446*4c06356bSdh if (pwp->mpi_acc_handle) { 1447*4c06356bSdh ddi_regs_map_free(&pwp->mpi_acc_handle); 1448*4c06356bSdh pwp->mpi_acc_handle = 0; 1449*4c06356bSdh } 1450*4c06356bSdh if (pwp->top_acc_handle) { 1451*4c06356bSdh ddi_regs_map_free(&pwp->top_acc_handle); 1452*4c06356bSdh pwp->top_acc_handle = 0; 1453*4c06356bSdh } 1454*4c06356bSdh if (pwp->gsm_acc_handle) { 1455*4c06356bSdh ddi_regs_map_free(&pwp->gsm_acc_handle); 1456*4c06356bSdh pwp->gsm_acc_handle = 0; 1457*4c06356bSdh } 1458*4c06356bSdh if (pwp->msg_acc_handle) { 1459*4c06356bSdh ddi_regs_map_free(&pwp->msg_acc_handle); 1460*4c06356bSdh pwp->msg_acc_handle = 0; 1461*4c06356bSdh } 1462*4c06356bSdh if (pwp->pci_acc_handle) { 1463*4c06356bSdh pci_config_teardown(&pwp->pci_acc_handle); 1464*4c06356bSdh pwp->pci_acc_handle = 0; 1465*4c06356bSdh } 1466*4c06356bSdh 1467*4c06356bSdh /* 1468*4c06356bSdh * Do memory allocation cleanup. 1469*4c06356bSdh */ 1470*4c06356bSdh while (pwp->dma_freelist) { 1471*4c06356bSdh pmcs_dmachunk_t *this = pwp->dma_freelist; 1472*4c06356bSdh pwp->dma_freelist = this->nxt; 1473*4c06356bSdh kmem_free(this, sizeof (pmcs_dmachunk_t)); 1474*4c06356bSdh } 1475*4c06356bSdh 1476*4c06356bSdh /* 1477*4c06356bSdh * Free pools 1478*4c06356bSdh */ 1479*4c06356bSdh if (pwp->iocomp_cb_cache) { 1480*4c06356bSdh kmem_cache_destroy(pwp->iocomp_cb_cache); 1481*4c06356bSdh } 1482*4c06356bSdh 1483*4c06356bSdh /* 1484*4c06356bSdh * Free all PHYs (at level > 0), then free the cache 1485*4c06356bSdh */ 1486*4c06356bSdh pmcs_free_all_phys(pwp, pwp->root_phys); 1487*4c06356bSdh if (pwp->phy_cache) { 1488*4c06356bSdh kmem_cache_destroy(pwp->phy_cache); 1489*4c06356bSdh } 1490*4c06356bSdh 1491*4c06356bSdh /* 1492*4c06356bSdh * Free root PHYs 1493*4c06356bSdh */ 1494*4c06356bSdh if (pwp->root_phys) { 1495*4c06356bSdh pmcs_phy_t *phyp = pwp->root_phys; 1496*4c06356bSdh for (i = 0; i < pwp->nphy; i++) { 1497*4c06356bSdh mutex_destroy(&phyp->phy_lock); 1498*4c06356bSdh phyp = phyp->sibling; 1499*4c06356bSdh } 1500*4c06356bSdh kmem_free(pwp->root_phys, pwp->nphy * sizeof (pmcs_phy_t)); 1501*4c06356bSdh pwp->root_phys = NULL; 1502*4c06356bSdh pwp->nphy = 0; 1503*4c06356bSdh } 1504*4c06356bSdh 1505*4c06356bSdh /* Free the targets list */ 1506*4c06356bSdh if (pwp->targets) { 1507*4c06356bSdh kmem_free(pwp->targets, 1508*4c06356bSdh sizeof (pmcs_xscsi_t *) * pwp->max_dev); 1509*4c06356bSdh } 1510*4c06356bSdh 1511*4c06356bSdh /* 1512*4c06356bSdh * Free work structures 1513*4c06356bSdh */ 1514*4c06356bSdh 1515*4c06356bSdh if (pwp->work && pwp->max_cmd) { 1516*4c06356bSdh for (i = 0; i < pwp->max_cmd - 1; i++) { 1517*4c06356bSdh pmcwork_t *pwrk = &pwp->work[i]; 1518*4c06356bSdh mutex_destroy(&pwrk->lock); 1519*4c06356bSdh cv_destroy(&pwrk->sleep_cv); 1520*4c06356bSdh } 1521*4c06356bSdh kmem_free(pwp->work, sizeof (pmcwork_t) * pwp->max_cmd); 1522*4c06356bSdh pwp->work = NULL; 1523*4c06356bSdh pwp->max_cmd = 0; 1524*4c06356bSdh } 1525*4c06356bSdh 1526*4c06356bSdh /* 1527*4c06356bSdh * Do last property and SCSA cleanup 1528*4c06356bSdh */ 1529*4c06356bSdh if (pwp->tran) { 1530*4c06356bSdh scsi_hba_tran_free(pwp->tran); 1531*4c06356bSdh pwp->tran = NULL; 1532*4c06356bSdh } 1533*4c06356bSdh if (pwp->reset_notify_listf) { 1534*4c06356bSdh scsi_hba_reset_notify_tear_down(pwp->reset_notify_listf); 1535*4c06356bSdh pwp->reset_notify_listf = NULL; 1536*4c06356bSdh } 1537*4c06356bSdh ddi_prop_remove_all(pwp->dip); 1538*4c06356bSdh if (pwp->stuck) { 1539*4c06356bSdh return (-1); 1540*4c06356bSdh } 1541*4c06356bSdh 1542*4c06356bSdh /* Free register dump area if allocated */ 1543*4c06356bSdh if (pwp->regdumpp) { 1544*4c06356bSdh kmem_free(pwp->regdumpp, PMCS_REG_DUMP_SIZE); 1545*4c06356bSdh pwp->regdumpp = NULL; 1546*4c06356bSdh } 1547*4c06356bSdh if (pwp->iqpt && pwp->iqpt->head) { 1548*4c06356bSdh kmem_free(pwp->iqpt->head, PMCS_IQP_TRACE_BUFFER_SIZE); 1549*4c06356bSdh pwp->iqpt->head = pwp->iqpt->curpos = NULL; 1550*4c06356bSdh } 1551*4c06356bSdh if (pwp->iqpt) { 1552*4c06356bSdh kmem_free(pwp->iqpt, sizeof (pmcs_iqp_trace_t)); 1553*4c06356bSdh pwp->iqpt = NULL; 1554*4c06356bSdh } 1555*4c06356bSdh 1556*4c06356bSdh ddi_soft_state_free(pmcs_softc_state, ddi_get_instance(pwp->dip)); 1557*4c06356bSdh return (0); 1558*4c06356bSdh } 1559*4c06356bSdh 1560*4c06356bSdh /* 1561*4c06356bSdh * quiesce (9E) entry point 1562*4c06356bSdh * 1563*4c06356bSdh * This function is called when the system is single-threaded at high PIL 1564*4c06356bSdh * with preemption disabled. Therefore, the function must not block/wait/sleep. 1565*4c06356bSdh * 1566*4c06356bSdh * Returns DDI_SUCCESS or DDI_FAILURE. 1567*4c06356bSdh * 1568*4c06356bSdh */ 1569*4c06356bSdh static int 1570*4c06356bSdh pmcs_quiesce(dev_info_t *dip) 1571*4c06356bSdh { 1572*4c06356bSdh pmcs_hw_t *pwp; 1573*4c06356bSdh scsi_hba_tran_t *tran; 1574*4c06356bSdh 1575*4c06356bSdh if ((tran = ddi_get_driver_private(dip)) == NULL) 1576*4c06356bSdh return (DDI_SUCCESS); 1577*4c06356bSdh 1578*4c06356bSdh /* No quiesce necessary on a per-iport basis */ 1579*4c06356bSdh if (scsi_hba_iport_unit_address(dip) != NULL) { 1580*4c06356bSdh return (DDI_SUCCESS); 1581*4c06356bSdh } 1582*4c06356bSdh 1583*4c06356bSdh if ((pwp = TRAN2PMC(tran)) == NULL) 1584*4c06356bSdh return (DDI_SUCCESS); 1585*4c06356bSdh 1586*4c06356bSdh /* Stop MPI & Reset chip (no need to re-initialize) */ 1587*4c06356bSdh (void) pmcs_stop_mpi(pwp); 1588*4c06356bSdh (void) pmcs_soft_reset(pwp, B_TRUE); 1589*4c06356bSdh 1590*4c06356bSdh return (DDI_SUCCESS); 1591*4c06356bSdh } 1592*4c06356bSdh 1593*4c06356bSdh /* 1594*4c06356bSdh * Called with xp->statlock and PHY lock and scratch acquired. 1595*4c06356bSdh */ 1596*4c06356bSdh static int 1597*4c06356bSdh pmcs_add_sata_device(pmcs_hw_t *pwp, pmcs_xscsi_t *xp) 1598*4c06356bSdh { 1599*4c06356bSdh ata_identify_t *ati; 1600*4c06356bSdh int result, i; 1601*4c06356bSdh pmcs_phy_t *pptr; 1602*4c06356bSdh uint16_t *a; 1603*4c06356bSdh union { 1604*4c06356bSdh uint8_t nsa[8]; 1605*4c06356bSdh uint16_t nsb[4]; 1606*4c06356bSdh } u; 1607*4c06356bSdh 1608*4c06356bSdh /* 1609*4c06356bSdh * Safe defaults - use only if this target is brand new (i.e. doesn't 1610*4c06356bSdh * already have these settings configured) 1611*4c06356bSdh */ 1612*4c06356bSdh if (xp->capacity == 0) { 1613*4c06356bSdh xp->capacity = (uint64_t)-1; 1614*4c06356bSdh xp->ca = 1; 1615*4c06356bSdh xp->qdepth = 1; 1616*4c06356bSdh xp->pio = 1; 1617*4c06356bSdh } 1618*4c06356bSdh 1619*4c06356bSdh pptr = xp->phy; 1620*4c06356bSdh 1621*4c06356bSdh /* 1622*4c06356bSdh * We only try and issue an IDENTIFY for first level 1623*4c06356bSdh * (direct attached) devices. We don't try and 1624*4c06356bSdh * set other quirks here (this will happen later, 1625*4c06356bSdh * if the device is fully configured) 1626*4c06356bSdh */ 1627*4c06356bSdh if (pptr->level) { 1628*4c06356bSdh return (0); 1629*4c06356bSdh } 1630*4c06356bSdh 1631*4c06356bSdh mutex_exit(&xp->statlock); 1632*4c06356bSdh result = pmcs_sata_identify(pwp, pptr); 1633*4c06356bSdh mutex_enter(&xp->statlock); 1634*4c06356bSdh 1635*4c06356bSdh if (result) { 1636*4c06356bSdh return (result); 1637*4c06356bSdh } 1638*4c06356bSdh ati = pwp->scratch; 1639*4c06356bSdh a = &ati->word108; 1640*4c06356bSdh for (i = 0; i < 4; i++) { 1641*4c06356bSdh u.nsb[i] = ddi_swap16(*a++); 1642*4c06356bSdh } 1643*4c06356bSdh 1644*4c06356bSdh /* 1645*4c06356bSdh * Check the returned data for being a valid (NAA=5) WWN. 1646*4c06356bSdh * If so, use that and override the SAS address we were 1647*4c06356bSdh * given at Link Up time. 1648*4c06356bSdh */ 1649*4c06356bSdh if ((u.nsa[0] >> 4) == 5) { 1650*4c06356bSdh (void) memcpy(pptr->sas_address, u.nsa, 8); 1651*4c06356bSdh } 1652*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, "%s: %s has SAS ADDRESS " SAS_ADDR_FMT, 1653*4c06356bSdh __func__, pptr->path, SAS_ADDR_PRT(pptr->sas_address)); 1654*4c06356bSdh return (0); 1655*4c06356bSdh } 1656*4c06356bSdh 1657*4c06356bSdh /* 1658*4c06356bSdh * Called with PHY lock and target statlock held and scratch acquired 1659*4c06356bSdh */ 1660*4c06356bSdh static boolean_t 1661*4c06356bSdh pmcs_add_new_device(pmcs_hw_t *pwp, pmcs_xscsi_t *target) 1662*4c06356bSdh { 1663*4c06356bSdh ASSERT(target != NULL); 1664*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, "%s: target = 0x%p", 1665*4c06356bSdh __func__, (void *) target); 1666*4c06356bSdh 1667*4c06356bSdh switch (target->phy->dtype) { 1668*4c06356bSdh case SATA: 1669*4c06356bSdh if (pmcs_add_sata_device(pwp, target) != 0) { 1670*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, 1671*4c06356bSdh "%s: add_sata_device failed for tgt 0x%p", 1672*4c06356bSdh __func__, (void *) target); 1673*4c06356bSdh return (B_FALSE); 1674*4c06356bSdh } 1675*4c06356bSdh break; 1676*4c06356bSdh case SAS: 1677*4c06356bSdh target->qdepth = maxqdepth; 1678*4c06356bSdh break; 1679*4c06356bSdh case EXPANDER: 1680*4c06356bSdh target->qdepth = 1; 1681*4c06356bSdh break; 1682*4c06356bSdh } 1683*4c06356bSdh 1684*4c06356bSdh target->new = 0; 1685*4c06356bSdh target->assigned = 1; 1686*4c06356bSdh target->dev_state = PMCS_DEVICE_STATE_OPERATIONAL; 1687*4c06356bSdh target->dtype = target->phy->dtype; 1688*4c06356bSdh 1689*4c06356bSdh /* 1690*4c06356bSdh * Set the PHY's config stop time to 0. This is one of the final 1691*4c06356bSdh * stops along the config path, so we're indicating that we 1692*4c06356bSdh * successfully configured the PHY. 1693*4c06356bSdh */ 1694*4c06356bSdh target->phy->config_stop = 0; 1695*4c06356bSdh 1696*4c06356bSdh return (B_TRUE); 1697*4c06356bSdh } 1698*4c06356bSdh 1699*4c06356bSdh 1700*4c06356bSdh static void 1701*4c06356bSdh pmcs_rem_old_devices(pmcs_hw_t *pwp) 1702*4c06356bSdh { 1703*4c06356bSdh pmcs_xscsi_t *xp; 1704*4c06356bSdh int i; 1705*4c06356bSdh 1706*4c06356bSdh mutex_enter(&pwp->lock); 1707*4c06356bSdh for (i = 0; i < pwp->max_dev; i++) { 1708*4c06356bSdh xp = pwp->targets[i]; 1709*4c06356bSdh if (xp == NULL) { 1710*4c06356bSdh continue; 1711*4c06356bSdh } 1712*4c06356bSdh mutex_exit(&pwp->lock); 1713*4c06356bSdh 1714*4c06356bSdh mutex_enter(&xp->statlock); 1715*4c06356bSdh if (xp->dying && (xp->dip != NULL)) { 1716*4c06356bSdh pmcs_clear_xp(pwp, xp); 1717*4c06356bSdh /* Target is now gone */ 1718*4c06356bSdh } 1719*4c06356bSdh mutex_exit(&xp->statlock); 1720*4c06356bSdh mutex_enter(&pwp->lock); 1721*4c06356bSdh } 1722*4c06356bSdh mutex_exit(&pwp->lock); 1723*4c06356bSdh } 1724*4c06356bSdh 1725*4c06356bSdh 1726*4c06356bSdh void 1727*4c06356bSdh pmcs_worker(void *arg) 1728*4c06356bSdh { 1729*4c06356bSdh pmcs_hw_t *pwp = arg; 1730*4c06356bSdh ulong_t work_flags; 1731*4c06356bSdh 1732*4c06356bSdh DTRACE_PROBE2(pmcs__worker, ulong_t, pwp->work_flags, boolean_t, 1733*4c06356bSdh pwp->config_changed); 1734*4c06356bSdh 1735*4c06356bSdh if (pwp->state != STATE_RUNNING) { 1736*4c06356bSdh return; 1737*4c06356bSdh } 1738*4c06356bSdh 1739*4c06356bSdh work_flags = atomic_swap_ulong(&pwp->work_flags, 0); 1740*4c06356bSdh 1741*4c06356bSdh if (work_flags & PMCS_WORK_FLAG_SAS_HW_ACK) { 1742*4c06356bSdh pmcs_ack_events(pwp); 1743*4c06356bSdh } 1744*4c06356bSdh 1745*4c06356bSdh if (work_flags & PMCS_WORK_FLAG_SPINUP_RELEASE) { 1746*4c06356bSdh mutex_enter(&pwp->lock); 1747*4c06356bSdh pmcs_spinup_release(pwp, NULL); 1748*4c06356bSdh mutex_exit(&pwp->lock); 1749*4c06356bSdh } 1750*4c06356bSdh 1751*4c06356bSdh if (work_flags & PMCS_WORK_FLAG_SSP_EVT_RECOVERY) { 1752*4c06356bSdh pmcs_ssp_event_recovery(pwp); 1753*4c06356bSdh } 1754*4c06356bSdh 1755*4c06356bSdh if (work_flags & PMCS_WORK_FLAG_DS_ERR_RECOVERY) { 1756*4c06356bSdh pmcs_dev_state_recovery(pwp, NULL); 1757*4c06356bSdh } 1758*4c06356bSdh 1759*4c06356bSdh if (work_flags & PMCS_WORK_FLAG_REM_DEVICES) { 1760*4c06356bSdh pmcs_rem_old_devices(pwp); 1761*4c06356bSdh } 1762*4c06356bSdh 1763*4c06356bSdh if (work_flags & PMCS_WORK_FLAG_DISCOVER) { 1764*4c06356bSdh pmcs_discover(pwp); 1765*4c06356bSdh } 1766*4c06356bSdh 1767*4c06356bSdh if (work_flags & PMCS_WORK_FLAG_ABORT_HANDLE) { 1768*4c06356bSdh if (pmcs_abort_handler(pwp)) { 1769*4c06356bSdh SCHEDULE_WORK(pwp, PMCS_WORK_ABORT_HANDLE); 1770*4c06356bSdh } 1771*4c06356bSdh } 1772*4c06356bSdh 1773*4c06356bSdh if (work_flags & PMCS_WORK_FLAG_SATA_RUN) { 1774*4c06356bSdh pmcs_sata_work(pwp); 1775*4c06356bSdh } 1776*4c06356bSdh 1777*4c06356bSdh if (work_flags & PMCS_WORK_FLAG_RUN_QUEUES) { 1778*4c06356bSdh pmcs_scsa_wq_run(pwp); 1779*4c06356bSdh mutex_enter(&pwp->lock); 1780*4c06356bSdh PMCS_CQ_RUN(pwp); 1781*4c06356bSdh mutex_exit(&pwp->lock); 1782*4c06356bSdh } 1783*4c06356bSdh 1784*4c06356bSdh if (work_flags & PMCS_WORK_FLAG_ADD_DMA_CHUNKS) { 1785*4c06356bSdh if (pmcs_add_more_chunks(pwp, 1786*4c06356bSdh ptob(1) * PMCS_ADDTL_CHUNK_PAGES)) { 1787*4c06356bSdh SCHEDULE_WORK(pwp, PMCS_WORK_ADD_DMA_CHUNKS); 1788*4c06356bSdh } else { 1789*4c06356bSdh SCHEDULE_WORK(pwp, PMCS_WORK_RUN_QUEUES); 1790*4c06356bSdh } 1791*4c06356bSdh } 1792*4c06356bSdh } 1793*4c06356bSdh 1794*4c06356bSdh static int 1795*4c06356bSdh pmcs_add_more_chunks(pmcs_hw_t *pwp, unsigned long nsize) 1796*4c06356bSdh { 1797*4c06356bSdh pmcs_dmachunk_t *dc; 1798*4c06356bSdh unsigned long dl; 1799*4c06356bSdh pmcs_chunk_t *pchunk = NULL; 1800*4c06356bSdh 1801*4c06356bSdh pwp->cip_dma_attr.dma_attr_align = sizeof (uint32_t); 1802*4c06356bSdh 1803*4c06356bSdh pchunk = kmem_zalloc(sizeof (pmcs_chunk_t), KM_SLEEP); 1804*4c06356bSdh if (pchunk == NULL) { 1805*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 1806*4c06356bSdh "Not enough memory for DMA chunks"); 1807*4c06356bSdh return (-1); 1808*4c06356bSdh } 1809*4c06356bSdh 1810*4c06356bSdh if (pmcs_dma_setup(pwp, &pwp->cip_dma_attr, &pchunk->acc_handle, 1811*4c06356bSdh &pchunk->dma_handle, nsize, (caddr_t *)&pchunk->addrp, 1812*4c06356bSdh &pchunk->dma_addr) == B_FALSE) { 1813*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, "Failed to setup DMA for chunks"); 1814*4c06356bSdh kmem_free(pchunk, sizeof (pmcs_chunk_t)); 1815*4c06356bSdh return (-1); 1816*4c06356bSdh } 1817*4c06356bSdh 1818*4c06356bSdh if ((pmcs_check_acc_handle(pchunk->acc_handle) != DDI_SUCCESS) || 1819*4c06356bSdh (pmcs_check_dma_handle(pchunk->dma_handle) != DDI_SUCCESS)) { 1820*4c06356bSdh ddi_fm_service_impact(pwp->dip, DDI_SERVICE_UNAFFECTED); 1821*4c06356bSdh return (-1); 1822*4c06356bSdh } 1823*4c06356bSdh 1824*4c06356bSdh bzero(pchunk->addrp, nsize); 1825*4c06356bSdh dc = NULL; 1826*4c06356bSdh for (dl = 0; dl < (nsize / PMCS_SGL_CHUNKSZ); dl++) { 1827*4c06356bSdh pmcs_dmachunk_t *tmp; 1828*4c06356bSdh tmp = kmem_alloc(sizeof (pmcs_dmachunk_t), KM_SLEEP); 1829*4c06356bSdh tmp->nxt = dc; 1830*4c06356bSdh dc = tmp; 1831*4c06356bSdh } 1832*4c06356bSdh mutex_enter(&pwp->dma_lock); 1833*4c06356bSdh pmcs_idma_chunks(pwp, dc, pchunk, nsize); 1834*4c06356bSdh pwp->nchunks++; 1835*4c06356bSdh mutex_exit(&pwp->dma_lock); 1836*4c06356bSdh return (0); 1837*4c06356bSdh } 1838*4c06356bSdh 1839*4c06356bSdh 1840*4c06356bSdh static void 1841*4c06356bSdh pmcs_check_commands(pmcs_hw_t *pwp) 1842*4c06356bSdh { 1843*4c06356bSdh pmcs_cmd_t *sp; 1844*4c06356bSdh size_t amt; 1845*4c06356bSdh char path[32]; 1846*4c06356bSdh pmcwork_t *pwrk; 1847*4c06356bSdh pmcs_xscsi_t *target; 1848*4c06356bSdh pmcs_phy_t *phyp; 1849*4c06356bSdh 1850*4c06356bSdh for (pwrk = pwp->work; pwrk < &pwp->work[pwp->max_cmd]; pwrk++) { 1851*4c06356bSdh mutex_enter(&pwrk->lock); 1852*4c06356bSdh 1853*4c06356bSdh /* 1854*4c06356bSdh * If the command isn't active, we can't be timing it still. 1855*4c06356bSdh * Active means the tag is not free and the state is "on chip". 1856*4c06356bSdh */ 1857*4c06356bSdh if (!PMCS_COMMAND_ACTIVE(pwrk)) { 1858*4c06356bSdh mutex_exit(&pwrk->lock); 1859*4c06356bSdh continue; 1860*4c06356bSdh } 1861*4c06356bSdh 1862*4c06356bSdh /* 1863*4c06356bSdh * No timer active for this command. 1864*4c06356bSdh */ 1865*4c06356bSdh if (pwrk->timer == 0) { 1866*4c06356bSdh mutex_exit(&pwrk->lock); 1867*4c06356bSdh continue; 1868*4c06356bSdh } 1869*4c06356bSdh 1870*4c06356bSdh /* 1871*4c06356bSdh * Knock off bits for the time interval. 1872*4c06356bSdh */ 1873*4c06356bSdh if (pwrk->timer >= US2WT(PMCS_WATCH_INTERVAL)) { 1874*4c06356bSdh pwrk->timer -= US2WT(PMCS_WATCH_INTERVAL); 1875*4c06356bSdh } else { 1876*4c06356bSdh pwrk->timer = 0; 1877*4c06356bSdh } 1878*4c06356bSdh if (pwrk->timer > 0) { 1879*4c06356bSdh mutex_exit(&pwrk->lock); 1880*4c06356bSdh continue; 1881*4c06356bSdh } 1882*4c06356bSdh 1883*4c06356bSdh /* 1884*4c06356bSdh * The command has now officially timed out. 1885*4c06356bSdh * Get the path for it. If it doesn't have 1886*4c06356bSdh * a phy pointer any more, it's really dead 1887*4c06356bSdh * and can just be put back on the free list. 1888*4c06356bSdh * There should *not* be any commands associated 1889*4c06356bSdh * with it any more. 1890*4c06356bSdh */ 1891*4c06356bSdh if (pwrk->phy == NULL) { 1892*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 1893*4c06356bSdh "dead command with gone phy being recycled"); 1894*4c06356bSdh ASSERT(pwrk->xp == NULL); 1895*4c06356bSdh pmcs_pwork(pwp, pwrk); 1896*4c06356bSdh continue; 1897*4c06356bSdh } 1898*4c06356bSdh amt = sizeof (path); 1899*4c06356bSdh amt = min(sizeof (pwrk->phy->path), amt); 1900*4c06356bSdh (void) memcpy(path, pwrk->phy->path, amt); 1901*4c06356bSdh 1902*4c06356bSdh /* 1903*4c06356bSdh * If this is a non-SCSA command, stop here. Eventually 1904*4c06356bSdh * we might do something with non-SCSA commands here- 1905*4c06356bSdh * but so far their timeout mechanisms are handled in 1906*4c06356bSdh * the WAIT_FOR macro. 1907*4c06356bSdh */ 1908*4c06356bSdh if (pwrk->xp == NULL) { 1909*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 1910*4c06356bSdh "%s: non-SCSA cmd tag 0x%x timed out", 1911*4c06356bSdh path, pwrk->htag); 1912*4c06356bSdh mutex_exit(&pwrk->lock); 1913*4c06356bSdh continue; 1914*4c06356bSdh } 1915*4c06356bSdh 1916*4c06356bSdh sp = pwrk->arg; 1917*4c06356bSdh ASSERT(sp != NULL); 1918*4c06356bSdh 1919*4c06356bSdh /* 1920*4c06356bSdh * Mark it as timed out. 1921*4c06356bSdh */ 1922*4c06356bSdh CMD2PKT(sp)->pkt_reason = CMD_TIMEOUT; 1923*4c06356bSdh CMD2PKT(sp)->pkt_statistics |= STAT_TIMEOUT; 1924*4c06356bSdh #ifdef DEBUG 1925*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 1926*4c06356bSdh "%s: SCSA cmd tag 0x%x timed out (state %x) onwire=%d", 1927*4c06356bSdh path, pwrk->htag, pwrk->state, pwrk->onwire); 1928*4c06356bSdh #else 1929*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 1930*4c06356bSdh "%s: SCSA cmd tag 0x%x timed out (state %x)", 1931*4c06356bSdh path, pwrk->htag, pwrk->state); 1932*4c06356bSdh #endif 1933*4c06356bSdh /* 1934*4c06356bSdh * Mark the work structure as timed out. 1935*4c06356bSdh */ 1936*4c06356bSdh pwrk->state = PMCS_WORK_STATE_TIMED_OUT; 1937*4c06356bSdh phyp = pwrk->phy; 1938*4c06356bSdh target = pwrk->xp; 1939*4c06356bSdh mutex_exit(&pwrk->lock); 1940*4c06356bSdh 1941*4c06356bSdh pmcs_lock_phy(phyp); 1942*4c06356bSdh mutex_enter(&target->statlock); 1943*4c06356bSdh 1944*4c06356bSdh /* 1945*4c06356bSdh * No point attempting recovery if the device is gone 1946*4c06356bSdh */ 1947*4c06356bSdh if (pwrk->xp->dev_gone) { 1948*4c06356bSdh mutex_exit(&target->statlock); 1949*4c06356bSdh pmcs_unlock_phy(phyp); 1950*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 1951*4c06356bSdh "%s: tgt(0x%p) is gone. Returning CMD_DEV_GONE " 1952*4c06356bSdh "for htag 0x%08x", __func__, 1953*4c06356bSdh (void *)pwrk->xp, pwrk->htag); 1954*4c06356bSdh mutex_enter(&pwrk->lock); 1955*4c06356bSdh if (!PMCS_COMMAND_DONE(pwrk)) { 1956*4c06356bSdh /* Complete this command here */ 1957*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, "%s: " 1958*4c06356bSdh "Completing cmd (htag 0x%08x) " 1959*4c06356bSdh "anyway", __func__, pwrk->htag); 1960*4c06356bSdh pwrk->dead = 1; 1961*4c06356bSdh CMD2PKT(sp)->pkt_reason = CMD_DEV_GONE; 1962*4c06356bSdh CMD2PKT(sp)->pkt_state = STATE_GOT_BUS; 1963*4c06356bSdh pmcs_complete_work_impl(pwp, pwrk, NULL, 0); 1964*4c06356bSdh } else { 1965*4c06356bSdh mutex_exit(&pwrk->lock); 1966*4c06356bSdh } 1967*4c06356bSdh continue; 1968*4c06356bSdh } 1969*4c06356bSdh 1970*4c06356bSdh /* 1971*4c06356bSdh * See if we're already waiting for device state recovery 1972*4c06356bSdh */ 1973*4c06356bSdh if (target->recover_wait) { 1974*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG_DEV_STATE, 1975*4c06356bSdh "%s: Target %p already in recovery", __func__, 1976*4c06356bSdh (void *)target); 1977*4c06356bSdh mutex_exit(&target->statlock); 1978*4c06356bSdh pmcs_unlock_phy(phyp); 1979*4c06356bSdh continue; 1980*4c06356bSdh } 1981*4c06356bSdh 1982*4c06356bSdh pmcs_start_dev_state_recovery(target, phyp); 1983*4c06356bSdh mutex_exit(&target->statlock); 1984*4c06356bSdh pmcs_unlock_phy(phyp); 1985*4c06356bSdh } 1986*4c06356bSdh /* 1987*4c06356bSdh * Run any completions that may have been queued up. 1988*4c06356bSdh */ 1989*4c06356bSdh PMCS_CQ_RUN(pwp); 1990*4c06356bSdh } 1991*4c06356bSdh 1992*4c06356bSdh static void 1993*4c06356bSdh pmcs_watchdog(void *arg) 1994*4c06356bSdh { 1995*4c06356bSdh pmcs_hw_t *pwp = arg; 1996*4c06356bSdh 1997*4c06356bSdh DTRACE_PROBE2(pmcs__watchdog, ulong_t, pwp->work_flags, boolean_t, 1998*4c06356bSdh pwp->config_changed); 1999*4c06356bSdh 2000*4c06356bSdh mutex_enter(&pwp->lock); 2001*4c06356bSdh 2002*4c06356bSdh if (pwp->state != STATE_RUNNING) { 2003*4c06356bSdh mutex_exit(&pwp->lock); 2004*4c06356bSdh return; 2005*4c06356bSdh } 2006*4c06356bSdh 2007*4c06356bSdh if (atomic_cas_ulong(&pwp->work_flags, 0, 0) != 0) { 2008*4c06356bSdh if (ddi_taskq_dispatch(pwp->tq, pmcs_worker, pwp, 2009*4c06356bSdh DDI_NOSLEEP) != DDI_SUCCESS) { 2010*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 2011*4c06356bSdh "Could not dispatch to worker thread"); 2012*4c06356bSdh } 2013*4c06356bSdh } 2014*4c06356bSdh pwp->wdhandle = timeout(pmcs_watchdog, pwp, 2015*4c06356bSdh drv_usectohz(PMCS_WATCH_INTERVAL)); 2016*4c06356bSdh mutex_exit(&pwp->lock); 2017*4c06356bSdh pmcs_check_commands(pwp); 2018*4c06356bSdh pmcs_handle_dead_phys(pwp); 2019*4c06356bSdh } 2020*4c06356bSdh 2021*4c06356bSdh static int 2022*4c06356bSdh pmcs_remove_ihandlers(pmcs_hw_t *pwp, int icnt) 2023*4c06356bSdh { 2024*4c06356bSdh int i, r, rslt = 0; 2025*4c06356bSdh for (i = 0; i < icnt; i++) { 2026*4c06356bSdh r = ddi_intr_remove_handler(pwp->ih_table[i]); 2027*4c06356bSdh if (r == DDI_SUCCESS) { 2028*4c06356bSdh continue; 2029*4c06356bSdh } 2030*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 2031*4c06356bSdh "%s: unable to remove interrupt handler %d", __func__, i); 2032*4c06356bSdh rslt = -1; 2033*4c06356bSdh break; 2034*4c06356bSdh } 2035*4c06356bSdh return (rslt); 2036*4c06356bSdh } 2037*4c06356bSdh 2038*4c06356bSdh static int 2039*4c06356bSdh pmcs_disable_intrs(pmcs_hw_t *pwp, int icnt) 2040*4c06356bSdh { 2041*4c06356bSdh if (pwp->intr_cap & DDI_INTR_FLAG_BLOCK) { 2042*4c06356bSdh int r = ddi_intr_block_disable(&pwp->ih_table[0], 2043*4c06356bSdh pwp->intr_cnt); 2044*4c06356bSdh if (r != DDI_SUCCESS) { 2045*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 2046*4c06356bSdh "unable to disable interrupt block"); 2047*4c06356bSdh return (-1); 2048*4c06356bSdh } 2049*4c06356bSdh } else { 2050*4c06356bSdh int i; 2051*4c06356bSdh for (i = 0; i < icnt; i++) { 2052*4c06356bSdh if (ddi_intr_disable(pwp->ih_table[i]) == DDI_SUCCESS) { 2053*4c06356bSdh continue; 2054*4c06356bSdh } 2055*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 2056*4c06356bSdh "unable to disable interrupt %d", i); 2057*4c06356bSdh return (-1); 2058*4c06356bSdh } 2059*4c06356bSdh } 2060*4c06356bSdh return (0); 2061*4c06356bSdh } 2062*4c06356bSdh 2063*4c06356bSdh static int 2064*4c06356bSdh pmcs_free_intrs(pmcs_hw_t *pwp, int icnt) 2065*4c06356bSdh { 2066*4c06356bSdh int i; 2067*4c06356bSdh for (i = 0; i < icnt; i++) { 2068*4c06356bSdh if (ddi_intr_free(pwp->ih_table[i]) == DDI_SUCCESS) { 2069*4c06356bSdh continue; 2070*4c06356bSdh } 2071*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, "unable to free interrupt %d", i); 2072*4c06356bSdh return (-1); 2073*4c06356bSdh } 2074*4c06356bSdh kmem_free(pwp->ih_table, pwp->ih_table_size); 2075*4c06356bSdh pwp->ih_table_size = 0; 2076*4c06356bSdh return (0); 2077*4c06356bSdh } 2078*4c06356bSdh 2079*4c06356bSdh /* 2080*4c06356bSdh * Try to set up interrupts of type "type" with a minimum number of interrupts 2081*4c06356bSdh * of "min". 2082*4c06356bSdh */ 2083*4c06356bSdh static void 2084*4c06356bSdh pmcs_setup_intr_impl(pmcs_hw_t *pwp, int type, int min) 2085*4c06356bSdh { 2086*4c06356bSdh int rval, avail, count, actual, max; 2087*4c06356bSdh 2088*4c06356bSdh rval = ddi_intr_get_nintrs(pwp->dip, type, &count); 2089*4c06356bSdh if ((rval != DDI_SUCCESS) || (count < min)) { 2090*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, 2091*4c06356bSdh "%s: get_nintrs failed; type: %d rc: %d count: %d min: %d", 2092*4c06356bSdh __func__, type, rval, count, min); 2093*4c06356bSdh return; 2094*4c06356bSdh } 2095*4c06356bSdh 2096*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, 2097*4c06356bSdh "%s: nintrs = %d for type: %d", __func__, count, type); 2098*4c06356bSdh 2099*4c06356bSdh rval = ddi_intr_get_navail(pwp->dip, type, &avail); 2100*4c06356bSdh if ((rval != DDI_SUCCESS) || (avail < min)) { 2101*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, 2102*4c06356bSdh "%s: get_navail failed; type: %d rc: %d avail: %d min: %d", 2103*4c06356bSdh __func__, type, rval, avail, min); 2104*4c06356bSdh return; 2105*4c06356bSdh } 2106*4c06356bSdh 2107*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, 2108*4c06356bSdh "%s: navail = %d for type: %d", __func__, avail, type); 2109*4c06356bSdh 2110*4c06356bSdh pwp->ih_table_size = avail * sizeof (ddi_intr_handle_t); 2111*4c06356bSdh pwp->ih_table = kmem_alloc(pwp->ih_table_size, KM_SLEEP); 2112*4c06356bSdh 2113*4c06356bSdh switch (type) { 2114*4c06356bSdh case DDI_INTR_TYPE_MSIX: 2115*4c06356bSdh pwp->int_type = PMCS_INT_MSIX; 2116*4c06356bSdh max = PMCS_MAX_MSIX; 2117*4c06356bSdh break; 2118*4c06356bSdh case DDI_INTR_TYPE_MSI: 2119*4c06356bSdh pwp->int_type = PMCS_INT_MSI; 2120*4c06356bSdh max = PMCS_MAX_MSI; 2121*4c06356bSdh break; 2122*4c06356bSdh case DDI_INTR_TYPE_FIXED: 2123*4c06356bSdh default: 2124*4c06356bSdh pwp->int_type = PMCS_INT_FIXED; 2125*4c06356bSdh max = PMCS_MAX_FIXED; 2126*4c06356bSdh break; 2127*4c06356bSdh } 2128*4c06356bSdh 2129*4c06356bSdh rval = ddi_intr_alloc(pwp->dip, pwp->ih_table, type, 0, max, &actual, 2130*4c06356bSdh DDI_INTR_ALLOC_NORMAL); 2131*4c06356bSdh if (rval != DDI_SUCCESS) { 2132*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, 2133*4c06356bSdh "%s: ddi_intr_alloc failed; type: %d rc: %d", 2134*4c06356bSdh __func__, type, rval); 2135*4c06356bSdh kmem_free(pwp->ih_table, pwp->ih_table_size); 2136*4c06356bSdh pwp->ih_table = NULL; 2137*4c06356bSdh pwp->ih_table_size = 0; 2138*4c06356bSdh pwp->intr_cnt = 0; 2139*4c06356bSdh pwp->int_type = PMCS_INT_NONE; 2140*4c06356bSdh return; 2141*4c06356bSdh } 2142*4c06356bSdh 2143*4c06356bSdh pwp->intr_cnt = actual; 2144*4c06356bSdh } 2145*4c06356bSdh 2146*4c06356bSdh /* 2147*4c06356bSdh * Set up interrupts. 2148*4c06356bSdh * We return one of three values: 2149*4c06356bSdh * 2150*4c06356bSdh * 0 - success 2151*4c06356bSdh * EAGAIN - failure to set up interrupts 2152*4c06356bSdh * EIO - "" + we're now stuck partly enabled 2153*4c06356bSdh * 2154*4c06356bSdh * If EIO is returned, we can't unload the driver. 2155*4c06356bSdh */ 2156*4c06356bSdh static int 2157*4c06356bSdh pmcs_setup_intr(pmcs_hw_t *pwp) 2158*4c06356bSdh { 2159*4c06356bSdh int i, r, itypes, oqv_count; 2160*4c06356bSdh ddi_intr_handler_t **iv_table; 2161*4c06356bSdh size_t iv_table_size; 2162*4c06356bSdh uint_t pri; 2163*4c06356bSdh 2164*4c06356bSdh if (ddi_intr_get_supported_types(pwp->dip, &itypes) != DDI_SUCCESS) { 2165*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, "cannot get interrupt types"); 2166*4c06356bSdh return (EAGAIN); 2167*4c06356bSdh } 2168*4c06356bSdh 2169*4c06356bSdh if (disable_msix) { 2170*4c06356bSdh itypes &= ~DDI_INTR_TYPE_MSIX; 2171*4c06356bSdh } 2172*4c06356bSdh if (disable_msi) { 2173*4c06356bSdh itypes &= ~DDI_INTR_TYPE_MSI; 2174*4c06356bSdh } 2175*4c06356bSdh 2176*4c06356bSdh /* 2177*4c06356bSdh * We won't know what firmware we're running until we call pmcs_setup, 2178*4c06356bSdh * and we can't call pmcs_setup until we establish interrupts. 2179*4c06356bSdh */ 2180*4c06356bSdh 2181*4c06356bSdh pwp->int_type = PMCS_INT_NONE; 2182*4c06356bSdh 2183*4c06356bSdh /* 2184*4c06356bSdh * We want PMCS_MAX_MSIX vectors for MSI-X. Anything less would be 2185*4c06356bSdh * uncivilized. 2186*4c06356bSdh */ 2187*4c06356bSdh if (itypes & DDI_INTR_TYPE_MSIX) { 2188*4c06356bSdh pmcs_setup_intr_impl(pwp, DDI_INTR_TYPE_MSIX, PMCS_MAX_MSIX); 2189*4c06356bSdh if (pwp->int_type == PMCS_INT_MSIX) { 2190*4c06356bSdh itypes = 0; 2191*4c06356bSdh } 2192*4c06356bSdh } 2193*4c06356bSdh 2194*4c06356bSdh if (itypes & DDI_INTR_TYPE_MSI) { 2195*4c06356bSdh pmcs_setup_intr_impl(pwp, DDI_INTR_TYPE_MSI, 1); 2196*4c06356bSdh if (pwp->int_type == PMCS_INT_MSI) { 2197*4c06356bSdh itypes = 0; 2198*4c06356bSdh } 2199*4c06356bSdh } 2200*4c06356bSdh 2201*4c06356bSdh if (itypes & DDI_INTR_TYPE_FIXED) { 2202*4c06356bSdh pmcs_setup_intr_impl(pwp, DDI_INTR_TYPE_FIXED, 1); 2203*4c06356bSdh if (pwp->int_type == PMCS_INT_FIXED) { 2204*4c06356bSdh itypes = 0; 2205*4c06356bSdh } 2206*4c06356bSdh } 2207*4c06356bSdh 2208*4c06356bSdh if (pwp->intr_cnt == 0) { 2209*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_ERR, "No interrupts available"); 2210*4c06356bSdh return (EAGAIN); 2211*4c06356bSdh } 2212*4c06356bSdh 2213*4c06356bSdh iv_table_size = sizeof (ddi_intr_handler_t *) * pwp->intr_cnt; 2214*4c06356bSdh iv_table = kmem_alloc(iv_table_size, KM_SLEEP); 2215*4c06356bSdh 2216*4c06356bSdh /* 2217*4c06356bSdh * Get iblock cookie and add handlers. 2218*4c06356bSdh */ 2219*4c06356bSdh switch (pwp->intr_cnt) { 2220*4c06356bSdh case 1: 2221*4c06356bSdh iv_table[0] = pmcs_all_intr; 2222*4c06356bSdh break; 2223*4c06356bSdh case 2: 2224*4c06356bSdh iv_table[0] = pmcs_iodone_ix; 2225*4c06356bSdh iv_table[1] = pmcs_nonio_ix; 2226*4c06356bSdh break; 2227*4c06356bSdh case 4: 2228*4c06356bSdh iv_table[PMCS_MSIX_GENERAL] = pmcs_general_ix; 2229*4c06356bSdh iv_table[PMCS_MSIX_IODONE] = pmcs_iodone_ix; 2230*4c06356bSdh iv_table[PMCS_MSIX_EVENTS] = pmcs_event_ix; 2231*4c06356bSdh iv_table[PMCS_MSIX_FATAL] = pmcs_fatal_ix; 2232*4c06356bSdh break; 2233*4c06356bSdh default: 2234*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 2235*4c06356bSdh "%s: intr_cnt = %d - unexpected", __func__, pwp->intr_cnt); 2236*4c06356bSdh kmem_free(iv_table, iv_table_size); 2237*4c06356bSdh return (EAGAIN); 2238*4c06356bSdh } 2239*4c06356bSdh 2240*4c06356bSdh for (i = 0; i < pwp->intr_cnt; i++) { 2241*4c06356bSdh r = ddi_intr_add_handler(pwp->ih_table[i], iv_table[i], 2242*4c06356bSdh (caddr_t)pwp, NULL); 2243*4c06356bSdh if (r != DDI_SUCCESS) { 2244*4c06356bSdh kmem_free(iv_table, iv_table_size); 2245*4c06356bSdh if (pmcs_remove_ihandlers(pwp, i)) { 2246*4c06356bSdh return (EIO); 2247*4c06356bSdh } 2248*4c06356bSdh if (pmcs_free_intrs(pwp, i)) { 2249*4c06356bSdh return (EIO); 2250*4c06356bSdh } 2251*4c06356bSdh pwp->intr_cnt = 0; 2252*4c06356bSdh return (EAGAIN); 2253*4c06356bSdh } 2254*4c06356bSdh } 2255*4c06356bSdh 2256*4c06356bSdh kmem_free(iv_table, iv_table_size); 2257*4c06356bSdh 2258*4c06356bSdh if (ddi_intr_get_cap(pwp->ih_table[0], &pwp->intr_cap) != DDI_SUCCESS) { 2259*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, "unable to get int capabilities"); 2260*4c06356bSdh if (pmcs_remove_ihandlers(pwp, pwp->intr_cnt)) { 2261*4c06356bSdh return (EIO); 2262*4c06356bSdh } 2263*4c06356bSdh if (pmcs_free_intrs(pwp, pwp->intr_cnt)) { 2264*4c06356bSdh return (EIO); 2265*4c06356bSdh } 2266*4c06356bSdh pwp->intr_cnt = 0; 2267*4c06356bSdh return (EAGAIN); 2268*4c06356bSdh } 2269*4c06356bSdh 2270*4c06356bSdh if (pwp->intr_cap & DDI_INTR_FLAG_BLOCK) { 2271*4c06356bSdh r = ddi_intr_block_enable(&pwp->ih_table[0], pwp->intr_cnt); 2272*4c06356bSdh if (r != DDI_SUCCESS) { 2273*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, "intr blk enable failed"); 2274*4c06356bSdh if (pmcs_remove_ihandlers(pwp, pwp->intr_cnt)) { 2275*4c06356bSdh return (EIO); 2276*4c06356bSdh } 2277*4c06356bSdh if (pmcs_free_intrs(pwp, pwp->intr_cnt)) { 2278*4c06356bSdh return (EIO); 2279*4c06356bSdh } 2280*4c06356bSdh pwp->intr_cnt = 0; 2281*4c06356bSdh return (EFAULT); 2282*4c06356bSdh } 2283*4c06356bSdh } else { 2284*4c06356bSdh for (i = 0; i < pwp->intr_cnt; i++) { 2285*4c06356bSdh r = ddi_intr_enable(pwp->ih_table[i]); 2286*4c06356bSdh if (r == DDI_SUCCESS) { 2287*4c06356bSdh continue; 2288*4c06356bSdh } 2289*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 2290*4c06356bSdh "unable to enable interrupt %d", i); 2291*4c06356bSdh if (pmcs_disable_intrs(pwp, i)) { 2292*4c06356bSdh return (EIO); 2293*4c06356bSdh } 2294*4c06356bSdh if (pmcs_remove_ihandlers(pwp, pwp->intr_cnt)) { 2295*4c06356bSdh return (EIO); 2296*4c06356bSdh } 2297*4c06356bSdh if (pmcs_free_intrs(pwp, pwp->intr_cnt)) { 2298*4c06356bSdh return (EIO); 2299*4c06356bSdh } 2300*4c06356bSdh pwp->intr_cnt = 0; 2301*4c06356bSdh return (EAGAIN); 2302*4c06356bSdh } 2303*4c06356bSdh } 2304*4c06356bSdh 2305*4c06356bSdh /* 2306*4c06356bSdh * Set up locks. 2307*4c06356bSdh */ 2308*4c06356bSdh if (ddi_intr_get_pri(pwp->ih_table[0], &pri) != DDI_SUCCESS) { 2309*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 2310*4c06356bSdh "unable to get interrupt priority"); 2311*4c06356bSdh if (pmcs_disable_intrs(pwp, pwp->intr_cnt)) { 2312*4c06356bSdh return (EIO); 2313*4c06356bSdh } 2314*4c06356bSdh if (pmcs_remove_ihandlers(pwp, pwp->intr_cnt)) { 2315*4c06356bSdh return (EIO); 2316*4c06356bSdh } 2317*4c06356bSdh if (pmcs_free_intrs(pwp, pwp->intr_cnt)) { 2318*4c06356bSdh return (EIO); 2319*4c06356bSdh } 2320*4c06356bSdh pwp->intr_cnt = 0; 2321*4c06356bSdh return (EAGAIN); 2322*4c06356bSdh } 2323*4c06356bSdh 2324*4c06356bSdh pwp->locks_initted = 1; 2325*4c06356bSdh pwp->intr_pri = pri; 2326*4c06356bSdh mutex_init(&pwp->lock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(pri)); 2327*4c06356bSdh mutex_init(&pwp->dma_lock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(pri)); 2328*4c06356bSdh mutex_init(&pwp->axil_lock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(pri)); 2329*4c06356bSdh mutex_init(&pwp->cq_lock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(pri)); 2330*4c06356bSdh mutex_init(&pwp->ict_lock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(pri)); 2331*4c06356bSdh mutex_init(&pwp->config_lock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(pri)); 2332*4c06356bSdh mutex_init(&pwp->wfree_lock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(pri)); 2333*4c06356bSdh mutex_init(&pwp->pfree_lock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(pri)); 2334*4c06356bSdh mutex_init(&pwp->dead_phylist_lock, NULL, MUTEX_DRIVER, 2335*4c06356bSdh DDI_INTR_PRI(pri)); 2336*4c06356bSdh #ifdef DEBUG 2337*4c06356bSdh mutex_init(&pwp->dbglock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(pri)); 2338*4c06356bSdh #endif 2339*4c06356bSdh cv_init(&pwp->ict_cv, NULL, CV_DRIVER, NULL); 2340*4c06356bSdh cv_init(&pwp->drain_cv, NULL, CV_DRIVER, NULL); 2341*4c06356bSdh for (i = 0; i < PMCS_NIQ; i++) { 2342*4c06356bSdh mutex_init(&pwp->iqp_lock[i], NULL, 2343*4c06356bSdh MUTEX_DRIVER, DDI_INTR_PRI(pwp->intr_pri)); 2344*4c06356bSdh } 2345*4c06356bSdh for (i = 0; i < pwp->cq_info.cq_threads; i++) { 2346*4c06356bSdh mutex_init(&pwp->cq_info.cq_thr_info[i].cq_thr_lock, NULL, 2347*4c06356bSdh MUTEX_DRIVER, DDI_INTR_PRI(pwp->intr_pri)); 2348*4c06356bSdh cv_init(&pwp->cq_info.cq_thr_info[i].cq_cv, NULL, 2349*4c06356bSdh CV_DRIVER, NULL); 2350*4c06356bSdh } 2351*4c06356bSdh 2352*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_INFO, "%d %s interrup%s configured", 2353*4c06356bSdh pwp->intr_cnt, (pwp->int_type == PMCS_INT_MSIX)? "MSI-X" : 2354*4c06356bSdh ((pwp->int_type == PMCS_INT_MSI)? "MSI" : "INT-X"), 2355*4c06356bSdh pwp->intr_cnt == 1? "t" : "ts"); 2356*4c06356bSdh 2357*4c06356bSdh 2358*4c06356bSdh /* 2359*4c06356bSdh * Enable Interrupts 2360*4c06356bSdh */ 2361*4c06356bSdh if (pwp->intr_cnt > PMCS_NOQ) { 2362*4c06356bSdh oqv_count = pwp->intr_cnt; 2363*4c06356bSdh } else { 2364*4c06356bSdh oqv_count = PMCS_NOQ; 2365*4c06356bSdh } 2366*4c06356bSdh for (pri = 0xffffffff, i = 0; i < oqv_count; i++) { 2367*4c06356bSdh pri ^= (1 << i); 2368*4c06356bSdh } 2369*4c06356bSdh 2370*4c06356bSdh mutex_enter(&pwp->lock); 2371*4c06356bSdh pwp->intr_mask = pri; 2372*4c06356bSdh pmcs_wr_msgunit(pwp, PMCS_MSGU_OBDB_MASK, pwp->intr_mask); 2373*4c06356bSdh pmcs_wr_msgunit(pwp, PMCS_MSGU_OBDB_CLEAR, 0xffffffff); 2374*4c06356bSdh mutex_exit(&pwp->lock); 2375*4c06356bSdh 2376*4c06356bSdh return (0); 2377*4c06356bSdh } 2378*4c06356bSdh 2379*4c06356bSdh static int 2380*4c06356bSdh pmcs_teardown_intr(pmcs_hw_t *pwp) 2381*4c06356bSdh { 2382*4c06356bSdh if (pwp->intr_cnt) { 2383*4c06356bSdh if (pmcs_disable_intrs(pwp, pwp->intr_cnt)) { 2384*4c06356bSdh return (EIO); 2385*4c06356bSdh } 2386*4c06356bSdh if (pmcs_remove_ihandlers(pwp, pwp->intr_cnt)) { 2387*4c06356bSdh return (EIO); 2388*4c06356bSdh } 2389*4c06356bSdh if (pmcs_free_intrs(pwp, pwp->intr_cnt)) { 2390*4c06356bSdh return (EIO); 2391*4c06356bSdh } 2392*4c06356bSdh pwp->intr_cnt = 0; 2393*4c06356bSdh } 2394*4c06356bSdh return (0); 2395*4c06356bSdh } 2396*4c06356bSdh 2397*4c06356bSdh static uint_t 2398*4c06356bSdh pmcs_general_ix(caddr_t arg1, caddr_t arg2) 2399*4c06356bSdh { 2400*4c06356bSdh pmcs_hw_t *pwp = (pmcs_hw_t *)((void *)arg1); 2401*4c06356bSdh _NOTE(ARGUNUSED(arg2)); 2402*4c06356bSdh pmcs_general_intr(pwp); 2403*4c06356bSdh return (DDI_INTR_CLAIMED); 2404*4c06356bSdh } 2405*4c06356bSdh 2406*4c06356bSdh static uint_t 2407*4c06356bSdh pmcs_event_ix(caddr_t arg1, caddr_t arg2) 2408*4c06356bSdh { 2409*4c06356bSdh pmcs_hw_t *pwp = (pmcs_hw_t *)((void *)arg1); 2410*4c06356bSdh _NOTE(ARGUNUSED(arg2)); 2411*4c06356bSdh pmcs_event_intr(pwp); 2412*4c06356bSdh return (DDI_INTR_CLAIMED); 2413*4c06356bSdh } 2414*4c06356bSdh 2415*4c06356bSdh static uint_t 2416*4c06356bSdh pmcs_iodone_ix(caddr_t arg1, caddr_t arg2) 2417*4c06356bSdh { 2418*4c06356bSdh _NOTE(ARGUNUSED(arg2)); 2419*4c06356bSdh pmcs_hw_t *pwp = (pmcs_hw_t *)((void *)arg1); 2420*4c06356bSdh 2421*4c06356bSdh /* 2422*4c06356bSdh * It's possible that if we just turned interrupt coalescing off 2423*4c06356bSdh * (and thus, re-enabled auto clear for interrupts on the I/O outbound 2424*4c06356bSdh * queue) that there was an interrupt already pending. We use 2425*4c06356bSdh * io_intr_coal.int_cleared to ensure that we still drop in here and 2426*4c06356bSdh * clear the appropriate interrupt bit one last time. 2427*4c06356bSdh */ 2428*4c06356bSdh mutex_enter(&pwp->ict_lock); 2429*4c06356bSdh if (pwp->io_intr_coal.timer_on || 2430*4c06356bSdh (pwp->io_intr_coal.int_cleared == B_FALSE)) { 2431*4c06356bSdh pmcs_wr_msgunit(pwp, PMCS_MSGU_OBDB_CLEAR, 2432*4c06356bSdh (1 << PMCS_OQ_IODONE)); 2433*4c06356bSdh pwp->io_intr_coal.int_cleared = B_TRUE; 2434*4c06356bSdh } 2435*4c06356bSdh mutex_exit(&pwp->ict_lock); 2436*4c06356bSdh 2437*4c06356bSdh pmcs_iodone_intr(pwp); 2438*4c06356bSdh 2439*4c06356bSdh return (DDI_INTR_CLAIMED); 2440*4c06356bSdh } 2441*4c06356bSdh 2442*4c06356bSdh static uint_t 2443*4c06356bSdh pmcs_fatal_ix(caddr_t arg1, caddr_t arg2) 2444*4c06356bSdh { 2445*4c06356bSdh pmcs_hw_t *pwp = (pmcs_hw_t *)((void *)arg1); 2446*4c06356bSdh _NOTE(ARGUNUSED(arg2)); 2447*4c06356bSdh pmcs_fatal_handler(pwp); 2448*4c06356bSdh return (DDI_INTR_CLAIMED); 2449*4c06356bSdh } 2450*4c06356bSdh 2451*4c06356bSdh static uint_t 2452*4c06356bSdh pmcs_nonio_ix(caddr_t arg1, caddr_t arg2) 2453*4c06356bSdh { 2454*4c06356bSdh _NOTE(ARGUNUSED(arg2)); 2455*4c06356bSdh pmcs_hw_t *pwp = (void *)arg1; 2456*4c06356bSdh uint32_t obdb = pmcs_rd_msgunit(pwp, PMCS_MSGU_OBDB); 2457*4c06356bSdh 2458*4c06356bSdh /* 2459*4c06356bSdh * Check for Fatal Interrupts 2460*4c06356bSdh */ 2461*4c06356bSdh if (obdb & (1 << PMCS_FATAL_INTERRUPT)) { 2462*4c06356bSdh pmcs_fatal_handler(pwp); 2463*4c06356bSdh return (DDI_INTR_CLAIMED); 2464*4c06356bSdh } 2465*4c06356bSdh 2466*4c06356bSdh if (obdb & (1 << PMCS_OQ_GENERAL)) { 2467*4c06356bSdh pmcs_wr_msgunit(pwp, PMCS_MSGU_OBDB_CLEAR, 2468*4c06356bSdh (1 << PMCS_OQ_GENERAL)); 2469*4c06356bSdh pmcs_general_intr(pwp); 2470*4c06356bSdh pmcs_event_intr(pwp); 2471*4c06356bSdh } 2472*4c06356bSdh 2473*4c06356bSdh return (DDI_INTR_CLAIMED); 2474*4c06356bSdh } 2475*4c06356bSdh 2476*4c06356bSdh static uint_t 2477*4c06356bSdh pmcs_all_intr(caddr_t arg1, caddr_t arg2) 2478*4c06356bSdh { 2479*4c06356bSdh _NOTE(ARGUNUSED(arg2)); 2480*4c06356bSdh pmcs_hw_t *pwp = (void *) arg1; 2481*4c06356bSdh uint32_t obdb; 2482*4c06356bSdh int handled = 0; 2483*4c06356bSdh 2484*4c06356bSdh obdb = pmcs_rd_msgunit(pwp, PMCS_MSGU_OBDB); 2485*4c06356bSdh 2486*4c06356bSdh /* 2487*4c06356bSdh * Check for Fatal Interrupts 2488*4c06356bSdh */ 2489*4c06356bSdh if (obdb & (1 << PMCS_FATAL_INTERRUPT)) { 2490*4c06356bSdh pmcs_fatal_handler(pwp); 2491*4c06356bSdh return (DDI_INTR_CLAIMED); 2492*4c06356bSdh } 2493*4c06356bSdh 2494*4c06356bSdh /* 2495*4c06356bSdh * Check for Outbound Queue service needed 2496*4c06356bSdh */ 2497*4c06356bSdh if (obdb & (1 << PMCS_OQ_IODONE)) { 2498*4c06356bSdh pmcs_wr_msgunit(pwp, PMCS_MSGU_OBDB_CLEAR, 2499*4c06356bSdh (1 << PMCS_OQ_IODONE)); 2500*4c06356bSdh obdb ^= (1 << PMCS_OQ_IODONE); 2501*4c06356bSdh handled++; 2502*4c06356bSdh pmcs_iodone_intr(pwp); 2503*4c06356bSdh } 2504*4c06356bSdh if (obdb & (1 << PMCS_OQ_GENERAL)) { 2505*4c06356bSdh pmcs_wr_msgunit(pwp, PMCS_MSGU_OBDB_CLEAR, 2506*4c06356bSdh (1 << PMCS_OQ_GENERAL)); 2507*4c06356bSdh obdb ^= (1 << PMCS_OQ_GENERAL); 2508*4c06356bSdh handled++; 2509*4c06356bSdh pmcs_general_intr(pwp); 2510*4c06356bSdh } 2511*4c06356bSdh if (obdb & (1 << PMCS_OQ_EVENTS)) { 2512*4c06356bSdh pmcs_wr_msgunit(pwp, PMCS_MSGU_OBDB_CLEAR, 2513*4c06356bSdh (1 << PMCS_OQ_EVENTS)); 2514*4c06356bSdh obdb ^= (1 << PMCS_OQ_EVENTS); 2515*4c06356bSdh handled++; 2516*4c06356bSdh pmcs_event_intr(pwp); 2517*4c06356bSdh } 2518*4c06356bSdh if (obdb) { 2519*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 2520*4c06356bSdh "interrupt bits not handled (0x%x)", obdb); 2521*4c06356bSdh pmcs_wr_msgunit(pwp, PMCS_MSGU_OBDB_CLEAR, obdb); 2522*4c06356bSdh handled++; 2523*4c06356bSdh } 2524*4c06356bSdh if (pwp->int_type == PMCS_INT_MSI) { 2525*4c06356bSdh handled++; 2526*4c06356bSdh } 2527*4c06356bSdh return (handled? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED); 2528*4c06356bSdh } 2529*4c06356bSdh 2530*4c06356bSdh void 2531*4c06356bSdh pmcs_fatal_handler(pmcs_hw_t *pwp) 2532*4c06356bSdh { 2533*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_ERR, "Fatal Interrupt caught"); 2534*4c06356bSdh mutex_enter(&pwp->lock); 2535*4c06356bSdh pwp->state = STATE_DEAD; 2536*4c06356bSdh pmcs_register_dump_int(pwp); 2537*4c06356bSdh pmcs_wr_msgunit(pwp, PMCS_MSGU_OBDB_MASK, 0xffffffff); 2538*4c06356bSdh pmcs_wr_msgunit(pwp, PMCS_MSGU_OBDB_CLEAR, 0xffffffff); 2539*4c06356bSdh mutex_exit(&pwp->lock); 2540*4c06356bSdh pmcs_fm_ereport(pwp, DDI_FM_DEVICE_NO_RESPONSE); 2541*4c06356bSdh ddi_fm_service_impact(pwp->dip, DDI_SERVICE_LOST); 2542*4c06356bSdh 2543*4c06356bSdh #ifdef DEBUG 2544*4c06356bSdh cmn_err(CE_PANIC, "PMCS Fatal Firmware Error"); 2545*4c06356bSdh #endif 2546*4c06356bSdh } 2547*4c06356bSdh 2548*4c06356bSdh /* 2549*4c06356bSdh * Called with PHY lock and target statlock held and scratch acquired. 2550*4c06356bSdh */ 2551*4c06356bSdh boolean_t 2552*4c06356bSdh pmcs_assign_device(pmcs_hw_t *pwp, pmcs_xscsi_t *tgt) 2553*4c06356bSdh { 2554*4c06356bSdh pmcs_phy_t *pptr = tgt->phy; 2555*4c06356bSdh 2556*4c06356bSdh switch (pptr->dtype) { 2557*4c06356bSdh case SAS: 2558*4c06356bSdh case EXPANDER: 2559*4c06356bSdh break; 2560*4c06356bSdh case SATA: 2561*4c06356bSdh tgt->ca = 1; 2562*4c06356bSdh break; 2563*4c06356bSdh default: 2564*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, 2565*4c06356bSdh "%s: Target %p has PHY %p with invalid dtype", 2566*4c06356bSdh __func__, (void *)tgt, (void *)pptr); 2567*4c06356bSdh return (B_FALSE); 2568*4c06356bSdh } 2569*4c06356bSdh 2570*4c06356bSdh tgt->new = 1; 2571*4c06356bSdh tgt->dev_gone = 0; 2572*4c06356bSdh tgt->dying = 0; 2573*4c06356bSdh tgt->recover_wait = 0; 2574*4c06356bSdh 2575*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, 2576*4c06356bSdh "%s: config %s vtgt %u for " SAS_ADDR_FMT, __func__, 2577*4c06356bSdh pptr->path, tgt->target_num, SAS_ADDR_PRT(pptr->sas_address)); 2578*4c06356bSdh 2579*4c06356bSdh if (pmcs_add_new_device(pwp, tgt) != B_TRUE) { 2580*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, 2581*4c06356bSdh "%s: Failed for vtgt %u / WWN " SAS_ADDR_FMT, __func__, 2582*4c06356bSdh tgt->target_num, SAS_ADDR_PRT(pptr->sas_address)); 2583*4c06356bSdh mutex_destroy(&tgt->statlock); 2584*4c06356bSdh mutex_destroy(&tgt->wqlock); 2585*4c06356bSdh mutex_destroy(&tgt->aqlock); 2586*4c06356bSdh return (B_FALSE); 2587*4c06356bSdh } 2588*4c06356bSdh 2589*4c06356bSdh return (B_TRUE); 2590*4c06356bSdh } 2591*4c06356bSdh 2592*4c06356bSdh /* 2593*4c06356bSdh * Called with softstate lock held 2594*4c06356bSdh */ 2595*4c06356bSdh void 2596*4c06356bSdh pmcs_remove_device(pmcs_hw_t *pwp, pmcs_phy_t *pptr) 2597*4c06356bSdh { 2598*4c06356bSdh pmcs_xscsi_t *xp; 2599*4c06356bSdh unsigned int vtgt; 2600*4c06356bSdh 2601*4c06356bSdh ASSERT(mutex_owned(&pwp->lock)); 2602*4c06356bSdh 2603*4c06356bSdh for (vtgt = 0; vtgt < pwp->max_dev; vtgt++) { 2604*4c06356bSdh xp = pwp->targets[vtgt]; 2605*4c06356bSdh if (xp == NULL) { 2606*4c06356bSdh continue; 2607*4c06356bSdh } 2608*4c06356bSdh 2609*4c06356bSdh mutex_enter(&xp->statlock); 2610*4c06356bSdh if (xp->phy == pptr) { 2611*4c06356bSdh if (xp->new) { 2612*4c06356bSdh xp->new = 0; 2613*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, 2614*4c06356bSdh "cancel config of vtgt %u", vtgt); 2615*4c06356bSdh } else { 2616*4c06356bSdh xp->assigned = 0; 2617*4c06356bSdh xp->dying = 1; 2618*4c06356bSdh SCHEDULE_WORK(pwp, PMCS_WORK_REM_DEVICES); 2619*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, 2620*4c06356bSdh "Scheduling removal of tgt 0x%p vtgt %u", 2621*4c06356bSdh (void *)xp, vtgt); 2622*4c06356bSdh } 2623*4c06356bSdh mutex_exit(&xp->statlock); 2624*4c06356bSdh break; 2625*4c06356bSdh } 2626*4c06356bSdh mutex_exit(&xp->statlock); 2627*4c06356bSdh } 2628*4c06356bSdh } 2629*4c06356bSdh 2630*4c06356bSdh void 2631*4c06356bSdh pmcs_prt_impl(pmcs_hw_t *pwp, pmcs_prt_level_t level, const char *fmt, ...) 2632*4c06356bSdh { 2633*4c06356bSdh va_list ap; 2634*4c06356bSdh int written = 0; 2635*4c06356bSdh char *ptr; 2636*4c06356bSdh uint32_t elem_size = PMCS_TBUF_ELEM_SIZE - 1; 2637*4c06356bSdh boolean_t system_log; 2638*4c06356bSdh int system_log_level; 2639*4c06356bSdh 2640*4c06356bSdh switch (level) { 2641*4c06356bSdh case PMCS_PRT_DEBUG_DEVEL: 2642*4c06356bSdh case PMCS_PRT_DEBUG_DEV_STATE: 2643*4c06356bSdh case PMCS_PRT_DEBUG_PHY_LOCKING: 2644*4c06356bSdh case PMCS_PRT_DEBUG_SCSI_STATUS: 2645*4c06356bSdh case PMCS_PRT_DEBUG_UNDERFLOW: 2646*4c06356bSdh case PMCS_PRT_DEBUG_CONFIG: 2647*4c06356bSdh case PMCS_PRT_DEBUG_IPORT: 2648*4c06356bSdh case PMCS_PRT_DEBUG_MAP: 2649*4c06356bSdh case PMCS_PRT_DEBUG3: 2650*4c06356bSdh case PMCS_PRT_DEBUG2: 2651*4c06356bSdh case PMCS_PRT_DEBUG1: 2652*4c06356bSdh case PMCS_PRT_DEBUG: 2653*4c06356bSdh system_log = B_FALSE; 2654*4c06356bSdh break; 2655*4c06356bSdh case PMCS_PRT_INFO: 2656*4c06356bSdh system_log = B_TRUE; 2657*4c06356bSdh system_log_level = CE_CONT; 2658*4c06356bSdh break; 2659*4c06356bSdh case PMCS_PRT_WARN: 2660*4c06356bSdh system_log = B_TRUE; 2661*4c06356bSdh system_log_level = CE_NOTE; 2662*4c06356bSdh break; 2663*4c06356bSdh case PMCS_PRT_ERR: 2664*4c06356bSdh system_log = B_TRUE; 2665*4c06356bSdh system_log_level = CE_WARN; 2666*4c06356bSdh break; 2667*4c06356bSdh default: 2668*4c06356bSdh return; 2669*4c06356bSdh } 2670*4c06356bSdh 2671*4c06356bSdh mutex_enter(&pmcs_trace_lock); 2672*4c06356bSdh gethrestime(&pmcs_tbuf_ptr->timestamp); 2673*4c06356bSdh ptr = pmcs_tbuf_ptr->buf; 2674*4c06356bSdh written += snprintf(ptr, elem_size, "pmcs%d:%d: ", 2675*4c06356bSdh ddi_get_instance(pwp->dip), level); 2676*4c06356bSdh ptr += strlen(ptr); 2677*4c06356bSdh va_start(ap, fmt); 2678*4c06356bSdh written += vsnprintf(ptr, elem_size - written, fmt, ap); 2679*4c06356bSdh va_end(ap); 2680*4c06356bSdh if (written > elem_size - 1) { 2681*4c06356bSdh /* Indicate truncation */ 2682*4c06356bSdh pmcs_tbuf_ptr->buf[elem_size - 1] = '+'; 2683*4c06356bSdh } 2684*4c06356bSdh if (++pmcs_tbuf_idx == pmcs_tbuf_num_elems) { 2685*4c06356bSdh pmcs_tbuf_ptr = pmcs_tbuf; 2686*4c06356bSdh pmcs_tbuf_wrap = B_TRUE; 2687*4c06356bSdh pmcs_tbuf_idx = 0; 2688*4c06356bSdh } else { 2689*4c06356bSdh ++pmcs_tbuf_ptr; 2690*4c06356bSdh } 2691*4c06356bSdh mutex_exit(&pmcs_trace_lock); 2692*4c06356bSdh 2693*4c06356bSdh /* 2694*4c06356bSdh * When pmcs_force_syslog in non-zero, everything goes also 2695*4c06356bSdh * to syslog, at CE_CONT level. 2696*4c06356bSdh */ 2697*4c06356bSdh if (pmcs_force_syslog) { 2698*4c06356bSdh system_log = B_TRUE; 2699*4c06356bSdh system_log_level = CE_CONT; 2700*4c06356bSdh } 2701*4c06356bSdh 2702*4c06356bSdh /* 2703*4c06356bSdh * Anything that comes in with PMCS_PRT_INFO, WARN, or ERR also 2704*4c06356bSdh * goes to syslog. 2705*4c06356bSdh */ 2706*4c06356bSdh if (system_log) { 2707*4c06356bSdh char local[196]; 2708*4c06356bSdh 2709*4c06356bSdh switch (system_log_level) { 2710*4c06356bSdh case CE_CONT: 2711*4c06356bSdh (void) snprintf(local, sizeof (local), "%sINFO: ", 2712*4c06356bSdh pmcs_console ? "" : "?"); 2713*4c06356bSdh break; 2714*4c06356bSdh case CE_NOTE: 2715*4c06356bSdh case CE_WARN: 2716*4c06356bSdh local[0] = 0; 2717*4c06356bSdh break; 2718*4c06356bSdh default: 2719*4c06356bSdh return; 2720*4c06356bSdh } 2721*4c06356bSdh 2722*4c06356bSdh ptr = local; 2723*4c06356bSdh ptr += strlen(local); 2724*4c06356bSdh (void) snprintf(ptr, (sizeof (local)) - 2725*4c06356bSdh ((size_t)ptr - (size_t)local), "pmcs%d: ", 2726*4c06356bSdh ddi_get_instance(pwp->dip)); 2727*4c06356bSdh ptr += strlen(ptr); 2728*4c06356bSdh va_start(ap, fmt); 2729*4c06356bSdh (void) vsnprintf(ptr, 2730*4c06356bSdh (sizeof (local)) - ((size_t)ptr - (size_t)local), fmt, ap); 2731*4c06356bSdh va_end(ap); 2732*4c06356bSdh if (level == CE_CONT) { 2733*4c06356bSdh (void) strlcat(local, "\n", sizeof (local)); 2734*4c06356bSdh } 2735*4c06356bSdh cmn_err(system_log_level, local); 2736*4c06356bSdh } 2737*4c06356bSdh 2738*4c06356bSdh } 2739*4c06356bSdh 2740*4c06356bSdh /* 2741*4c06356bSdh * pmcs_acquire_scratch 2742*4c06356bSdh * 2743*4c06356bSdh * If "wait" is true, the caller will wait until it can acquire the scratch. 2744*4c06356bSdh * This implies the caller needs to be in a context where spinning for an 2745*4c06356bSdh * indeterminate amount of time is acceptable. 2746*4c06356bSdh */ 2747*4c06356bSdh int 2748*4c06356bSdh pmcs_acquire_scratch(pmcs_hw_t *pwp, boolean_t wait) 2749*4c06356bSdh { 2750*4c06356bSdh int rval; 2751*4c06356bSdh 2752*4c06356bSdh if (!wait) { 2753*4c06356bSdh return (atomic_swap_8(&pwp->scratch_locked, 1)); 2754*4c06356bSdh } 2755*4c06356bSdh 2756*4c06356bSdh /* 2757*4c06356bSdh * Caller will wait for scratch. 2758*4c06356bSdh */ 2759*4c06356bSdh while ((rval = atomic_swap_8(&pwp->scratch_locked, 1)) != 0) { 2760*4c06356bSdh drv_usecwait(100); 2761*4c06356bSdh } 2762*4c06356bSdh 2763*4c06356bSdh return (rval); 2764*4c06356bSdh } 2765*4c06356bSdh 2766*4c06356bSdh void 2767*4c06356bSdh pmcs_release_scratch(pmcs_hw_t *pwp) 2768*4c06356bSdh { 2769*4c06356bSdh pwp->scratch_locked = 0; 2770*4c06356bSdh } 2771*4c06356bSdh 2772*4c06356bSdh static void 2773*4c06356bSdh pmcs_create_phy_stats(pmcs_iport_t *iport) 2774*4c06356bSdh { 2775*4c06356bSdh sas_phy_stats_t *ps; 2776*4c06356bSdh pmcs_hw_t *pwp; 2777*4c06356bSdh pmcs_phy_t *phyp; 2778*4c06356bSdh int ndata; 2779*4c06356bSdh char ks_name[KSTAT_STRLEN]; 2780*4c06356bSdh 2781*4c06356bSdh ASSERT(iport != NULL); 2782*4c06356bSdh pwp = iport->pwp; 2783*4c06356bSdh ASSERT(pwp != NULL); 2784*4c06356bSdh 2785*4c06356bSdh mutex_enter(&iport->lock); 2786*4c06356bSdh 2787*4c06356bSdh for (phyp = list_head(&iport->phys); 2788*4c06356bSdh phyp != NULL; 2789*4c06356bSdh phyp = list_next(&iport->phys, phyp)) { 2790*4c06356bSdh 2791*4c06356bSdh pmcs_lock_phy(phyp); 2792*4c06356bSdh 2793*4c06356bSdh if (phyp->phy_stats != NULL) { 2794*4c06356bSdh pmcs_unlock_phy(phyp); 2795*4c06356bSdh /* We've already created this kstat instance */ 2796*4c06356bSdh continue; 2797*4c06356bSdh } 2798*4c06356bSdh 2799*4c06356bSdh ndata = (sizeof (sas_phy_stats_t)/sizeof (kstat_named_t)); 2800*4c06356bSdh 2801*4c06356bSdh (void) snprintf(ks_name, sizeof (ks_name), 2802*4c06356bSdh "%s.%llx.%d.%d", ddi_driver_name(iport->dip), 2803*4c06356bSdh (longlong_t)pwp->sas_wwns[0], 2804*4c06356bSdh ddi_get_instance(iport->dip), phyp->phynum); 2805*4c06356bSdh 2806*4c06356bSdh phyp->phy_stats = kstat_create("pmcs", 2807*4c06356bSdh ddi_get_instance(iport->dip), ks_name, KSTAT_SAS_PHY_CLASS, 2808*4c06356bSdh KSTAT_TYPE_NAMED, ndata, 0); 2809*4c06356bSdh 2810*4c06356bSdh if (phyp->phy_stats == NULL) { 2811*4c06356bSdh pmcs_unlock_phy(phyp); 2812*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 2813*4c06356bSdh "%s: Failed to create %s kstats", __func__, 2814*4c06356bSdh ks_name); 2815*4c06356bSdh continue; 2816*4c06356bSdh } 2817*4c06356bSdh 2818*4c06356bSdh ps = (sas_phy_stats_t *)phyp->phy_stats->ks_data; 2819*4c06356bSdh 2820*4c06356bSdh kstat_named_init(&ps->seconds_since_last_reset, 2821*4c06356bSdh "SecondsSinceLastReset", KSTAT_DATA_ULONGLONG); 2822*4c06356bSdh kstat_named_init(&ps->tx_frames, 2823*4c06356bSdh "TxFrames", KSTAT_DATA_ULONGLONG); 2824*4c06356bSdh kstat_named_init(&ps->rx_frames, 2825*4c06356bSdh "RxFrames", KSTAT_DATA_ULONGLONG); 2826*4c06356bSdh kstat_named_init(&ps->tx_words, 2827*4c06356bSdh "TxWords", KSTAT_DATA_ULONGLONG); 2828*4c06356bSdh kstat_named_init(&ps->rx_words, 2829*4c06356bSdh "RxWords", KSTAT_DATA_ULONGLONG); 2830*4c06356bSdh kstat_named_init(&ps->invalid_dword_count, 2831*4c06356bSdh "InvalidDwordCount", KSTAT_DATA_ULONGLONG); 2832*4c06356bSdh kstat_named_init(&ps->running_disparity_error_count, 2833*4c06356bSdh "RunningDisparityErrorCount", KSTAT_DATA_ULONGLONG); 2834*4c06356bSdh kstat_named_init(&ps->loss_of_dword_sync_count, 2835*4c06356bSdh "LossofDwordSyncCount", KSTAT_DATA_ULONGLONG); 2836*4c06356bSdh kstat_named_init(&ps->phy_reset_problem_count, 2837*4c06356bSdh "PhyResetProblemCount", KSTAT_DATA_ULONGLONG); 2838*4c06356bSdh 2839*4c06356bSdh phyp->phy_stats->ks_private = phyp; 2840*4c06356bSdh phyp->phy_stats->ks_update = pmcs_update_phy_stats; 2841*4c06356bSdh kstat_install(phyp->phy_stats); 2842*4c06356bSdh pmcs_unlock_phy(phyp); 2843*4c06356bSdh } 2844*4c06356bSdh 2845*4c06356bSdh mutex_exit(&iport->lock); 2846*4c06356bSdh } 2847*4c06356bSdh 2848*4c06356bSdh int 2849*4c06356bSdh pmcs_update_phy_stats(kstat_t *ks, int rw) 2850*4c06356bSdh { 2851*4c06356bSdh int val, ret = DDI_FAILURE; 2852*4c06356bSdh pmcs_phy_t *pptr = (pmcs_phy_t *)ks->ks_private; 2853*4c06356bSdh pmcs_hw_t *pwp = pptr->pwp; 2854*4c06356bSdh sas_phy_stats_t *ps = ks->ks_data; 2855*4c06356bSdh 2856*4c06356bSdh _NOTE(ARGUNUSED(rw)); 2857*4c06356bSdh ASSERT((pptr != NULL) && (pwp != NULL)); 2858*4c06356bSdh 2859*4c06356bSdh /* 2860*4c06356bSdh * We just want to lock against other invocations of kstat; 2861*4c06356bSdh * we don't need to pmcs_lock_phy() for this. 2862*4c06356bSdh */ 2863*4c06356bSdh mutex_enter(&pptr->phy_lock); 2864*4c06356bSdh 2865*4c06356bSdh /* Get Stats from Chip */ 2866*4c06356bSdh val = pmcs_get_diag_report(pwp, PMCS_INVALID_DWORD_CNT, pptr->phynum); 2867*4c06356bSdh if (val == DDI_FAILURE) 2868*4c06356bSdh goto fail; 2869*4c06356bSdh ps->invalid_dword_count.value.ull = (unsigned long long)val; 2870*4c06356bSdh 2871*4c06356bSdh val = pmcs_get_diag_report(pwp, PMCS_DISPARITY_ERR_CNT, pptr->phynum); 2872*4c06356bSdh if (val == DDI_FAILURE) 2873*4c06356bSdh goto fail; 2874*4c06356bSdh ps->running_disparity_error_count.value.ull = (unsigned long long)val; 2875*4c06356bSdh 2876*4c06356bSdh val = pmcs_get_diag_report(pwp, PMCS_LOST_DWORD_SYNC_CNT, pptr->phynum); 2877*4c06356bSdh if (val == DDI_FAILURE) 2878*4c06356bSdh goto fail; 2879*4c06356bSdh ps->loss_of_dword_sync_count.value.ull = (unsigned long long)val; 2880*4c06356bSdh 2881*4c06356bSdh val = pmcs_get_diag_report(pwp, PMCS_RESET_FAILED_CNT, pptr->phynum); 2882*4c06356bSdh if (val == DDI_FAILURE) 2883*4c06356bSdh goto fail; 2884*4c06356bSdh ps->phy_reset_problem_count.value.ull = (unsigned long long)val; 2885*4c06356bSdh 2886*4c06356bSdh ret = DDI_SUCCESS; 2887*4c06356bSdh fail: 2888*4c06356bSdh mutex_exit(&pptr->phy_lock); 2889*4c06356bSdh return (ret); 2890*4c06356bSdh } 2891*4c06356bSdh 2892*4c06356bSdh static void 2893*4c06356bSdh pmcs_destroy_phy_stats(pmcs_iport_t *iport) 2894*4c06356bSdh { 2895*4c06356bSdh pmcs_phy_t *phyp; 2896*4c06356bSdh 2897*4c06356bSdh ASSERT(iport != NULL); 2898*4c06356bSdh mutex_enter(&iport->lock); 2899*4c06356bSdh phyp = iport->pptr; 2900*4c06356bSdh if (phyp == NULL) { 2901*4c06356bSdh mutex_exit(&iport->lock); 2902*4c06356bSdh return; 2903*4c06356bSdh } 2904*4c06356bSdh 2905*4c06356bSdh pmcs_lock_phy(phyp); 2906*4c06356bSdh if (phyp->phy_stats != NULL) { 2907*4c06356bSdh kstat_delete(phyp->phy_stats); 2908*4c06356bSdh phyp->phy_stats = NULL; 2909*4c06356bSdh } 2910*4c06356bSdh pmcs_unlock_phy(phyp); 2911*4c06356bSdh 2912*4c06356bSdh mutex_exit(&iport->lock); 2913*4c06356bSdh } 2914*4c06356bSdh 2915*4c06356bSdh /*ARGSUSED*/ 2916*4c06356bSdh static int 2917*4c06356bSdh pmcs_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data) 2918*4c06356bSdh { 2919*4c06356bSdh /* 2920*4c06356bSdh * as the driver can always deal with an error in any dma or 2921*4c06356bSdh * access handle, we can just return the fme_status value. 2922*4c06356bSdh */ 2923*4c06356bSdh pci_ereport_post(dip, err, NULL); 2924*4c06356bSdh return (err->fme_status); 2925*4c06356bSdh } 2926*4c06356bSdh 2927*4c06356bSdh static void 2928*4c06356bSdh pmcs_fm_init(pmcs_hw_t *pwp) 2929*4c06356bSdh { 2930*4c06356bSdh ddi_iblock_cookie_t fm_ibc; 2931*4c06356bSdh 2932*4c06356bSdh /* Only register with IO Fault Services if we have some capability */ 2933*4c06356bSdh if (pwp->fm_capabilities) { 2934*4c06356bSdh /* Adjust access and dma attributes for FMA */ 2935*4c06356bSdh pwp->reg_acc_attr.devacc_attr_access |= DDI_FLAGERR_ACC; 2936*4c06356bSdh pwp->dev_acc_attr.devacc_attr_access |= DDI_FLAGERR_ACC; 2937*4c06356bSdh pwp->iqp_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR; 2938*4c06356bSdh pwp->oqp_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR; 2939*4c06356bSdh pwp->cip_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR; 2940*4c06356bSdh pwp->fwlog_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR; 2941*4c06356bSdh 2942*4c06356bSdh /* 2943*4c06356bSdh * Register capabilities with IO Fault Services. 2944*4c06356bSdh */ 2945*4c06356bSdh ddi_fm_init(pwp->dip, &pwp->fm_capabilities, &fm_ibc); 2946*4c06356bSdh 2947*4c06356bSdh /* 2948*4c06356bSdh * Initialize pci ereport capabilities if ereport 2949*4c06356bSdh * capable (should always be.) 2950*4c06356bSdh */ 2951*4c06356bSdh if (DDI_FM_EREPORT_CAP(pwp->fm_capabilities) || 2952*4c06356bSdh DDI_FM_ERRCB_CAP(pwp->fm_capabilities)) { 2953*4c06356bSdh pci_ereport_setup(pwp->dip); 2954*4c06356bSdh } 2955*4c06356bSdh 2956*4c06356bSdh /* 2957*4c06356bSdh * Register error callback if error callback capable. 2958*4c06356bSdh */ 2959*4c06356bSdh if (DDI_FM_ERRCB_CAP(pwp->fm_capabilities)) { 2960*4c06356bSdh ddi_fm_handler_register(pwp->dip, 2961*4c06356bSdh pmcs_fm_error_cb, (void *) pwp); 2962*4c06356bSdh } 2963*4c06356bSdh } 2964*4c06356bSdh } 2965*4c06356bSdh 2966*4c06356bSdh static void 2967*4c06356bSdh pmcs_fm_fini(pmcs_hw_t *pwp) 2968*4c06356bSdh { 2969*4c06356bSdh /* Only unregister FMA capabilities if registered */ 2970*4c06356bSdh if (pwp->fm_capabilities) { 2971*4c06356bSdh /* 2972*4c06356bSdh * Un-register error callback if error callback capable. 2973*4c06356bSdh */ 2974*4c06356bSdh if (DDI_FM_ERRCB_CAP(pwp->fm_capabilities)) { 2975*4c06356bSdh ddi_fm_handler_unregister(pwp->dip); 2976*4c06356bSdh } 2977*4c06356bSdh 2978*4c06356bSdh /* 2979*4c06356bSdh * Release any resources allocated by pci_ereport_setup() 2980*4c06356bSdh */ 2981*4c06356bSdh if (DDI_FM_EREPORT_CAP(pwp->fm_capabilities) || 2982*4c06356bSdh DDI_FM_ERRCB_CAP(pwp->fm_capabilities)) { 2983*4c06356bSdh pci_ereport_teardown(pwp->dip); 2984*4c06356bSdh } 2985*4c06356bSdh 2986*4c06356bSdh /* Unregister from IO Fault Services */ 2987*4c06356bSdh ddi_fm_fini(pwp->dip); 2988*4c06356bSdh 2989*4c06356bSdh /* Adjust access and dma attributes for FMA */ 2990*4c06356bSdh pwp->reg_acc_attr.devacc_attr_access &= ~DDI_FLAGERR_ACC; 2991*4c06356bSdh pwp->dev_acc_attr.devacc_attr_access &= ~DDI_FLAGERR_ACC; 2992*4c06356bSdh pwp->iqp_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR; 2993*4c06356bSdh pwp->oqp_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR; 2994*4c06356bSdh pwp->cip_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR; 2995*4c06356bSdh pwp->fwlog_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR; 2996*4c06356bSdh } 2997*4c06356bSdh } 2998*4c06356bSdh 2999*4c06356bSdh static boolean_t 3000*4c06356bSdh pmcs_fabricate_wwid(pmcs_hw_t *pwp) 3001*4c06356bSdh { 3002*4c06356bSdh char *cp, c; 3003*4c06356bSdh uint64_t adr; 3004*4c06356bSdh int i; 3005*4c06356bSdh 3006*4c06356bSdh cp = &c; 3007*4c06356bSdh (void) ddi_strtoul(hw_serial, &cp, 10, (unsigned long *)&adr); 3008*4c06356bSdh if (adr == 0) { 3009*4c06356bSdh static const char foo[] = __DATE__ __TIME__; 3010*4c06356bSdh /* Oh, dear, we're toast */ 3011*4c06356bSdh pmcs_prt(pwp, PMCS_PRT_DEBUG, 3012*4c06356bSdh "%s: No serial number available to fabricate WWN", 3013*4c06356bSdh __func__); 3014*4c06356bSdh for (i = 0; foo[i]; i++) { 3015*4c06356bSdh adr += foo[i]; 3016*4c06356bSdh } 3017*4c06356bSdh } 3018*4c06356bSdh adr <<= 8; 3019*4c06356bSdh adr |= ((uint64_t)ddi_get_instance(pwp->dip) << 52); 3020*4c06356bSdh adr |= (5ULL << 60); 3021*4c06356bSdh for (i = 0; i < PMCS_MAX_PORTS; i++) { 3022*4c06356bSdh pwp->sas_wwns[i] = adr + i; 3023*4c06356bSdh } 3024*4c06356bSdh 3025*4c06356bSdh return (B_TRUE); 3026*4c06356bSdh } 3027