1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * The tphci driver can be used to exercise the mpxio framework together 31*0Sstevel@tonic-gate * with tvhci/tclient. 32*0Sstevel@tonic-gate */ 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate #include <sys/conf.h> 35*0Sstevel@tonic-gate #include <sys/file.h> 36*0Sstevel@tonic-gate #include <sys/open.h> 37*0Sstevel@tonic-gate #include <sys/stat.h> 38*0Sstevel@tonic-gate #include <sys/modctl.h> 39*0Sstevel@tonic-gate #include <sys/ddi.h> 40*0Sstevel@tonic-gate #include <sys/sunddi.h> 41*0Sstevel@tonic-gate #include <sys/sunndi.h> 42*0Sstevel@tonic-gate #include <sys/sunmdi.h> 43*0Sstevel@tonic-gate #include <sys/mdi_impldefs.h> 44*0Sstevel@tonic-gate #include <sys/disp.h> 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate /* cb_ops entry points */ 47*0Sstevel@tonic-gate static int tphci_open(dev_t *, int, int, cred_t *); 48*0Sstevel@tonic-gate static int tphci_close(dev_t, int, int, cred_t *); 49*0Sstevel@tonic-gate static int tphci_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 50*0Sstevel@tonic-gate static int tphci_attach(dev_info_t *, ddi_attach_cmd_t); 51*0Sstevel@tonic-gate static int tphci_detach(dev_info_t *, ddi_detach_cmd_t); 52*0Sstevel@tonic-gate static int tphci_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gate /* bus_ops entry points */ 55*0Sstevel@tonic-gate static int tphci_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, 56*0Sstevel@tonic-gate void *); 57*0Sstevel@tonic-gate static int tphci_initchild(dev_info_t *, dev_info_t *); 58*0Sstevel@tonic-gate static int tphci_uninitchild(dev_info_t *, dev_info_t *); 59*0Sstevel@tonic-gate static int tphci_bus_config(dev_info_t *, uint_t, ddi_bus_config_op_t, void *, 60*0Sstevel@tonic-gate dev_info_t **); 61*0Sstevel@tonic-gate static int tphci_bus_unconfig(dev_info_t *, uint_t, ddi_bus_config_op_t, 62*0Sstevel@tonic-gate void *); 63*0Sstevel@tonic-gate static int tphci_intr_op(dev_info_t *dip, dev_info_t *rdip, 64*0Sstevel@tonic-gate ddi_intr_op_t op, ddi_intr_handle_impl_t *hdlp, void *result); 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate static void *tphci_state; 68*0Sstevel@tonic-gate struct tphci_state { 69*0Sstevel@tonic-gate dev_info_t *dip; 70*0Sstevel@tonic-gate }; 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate static struct cb_ops tphci_cb_ops = { 73*0Sstevel@tonic-gate tphci_open, /* open */ 74*0Sstevel@tonic-gate tphci_close, /* close */ 75*0Sstevel@tonic-gate nodev, /* strategy */ 76*0Sstevel@tonic-gate nodev, /* print */ 77*0Sstevel@tonic-gate nodev, /* dump */ 78*0Sstevel@tonic-gate nodev, /* read */ 79*0Sstevel@tonic-gate nodev, /* write */ 80*0Sstevel@tonic-gate tphci_ioctl, /* ioctl */ 81*0Sstevel@tonic-gate nodev, /* devmap */ 82*0Sstevel@tonic-gate nodev, /* mmap */ 83*0Sstevel@tonic-gate nodev, /* segmap */ 84*0Sstevel@tonic-gate nochpoll, /* chpoll */ 85*0Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 86*0Sstevel@tonic-gate 0, /* streamtab */ 87*0Sstevel@tonic-gate D_NEW | D_MP, /* cb_flag */ 88*0Sstevel@tonic-gate CB_REV, /* rev */ 89*0Sstevel@tonic-gate nodev, /* aread */ 90*0Sstevel@tonic-gate nodev /* awrite */ 91*0Sstevel@tonic-gate }; 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate static struct bus_ops tphci_bus_ops = { 94*0Sstevel@tonic-gate BUSO_REV, /* busops_rev */ 95*0Sstevel@tonic-gate nullbusmap, /* bus_map */ 96*0Sstevel@tonic-gate NULL, /* bus_get_intrspec */ 97*0Sstevel@tonic-gate NULL, /* bus_add_interspec */ 98*0Sstevel@tonic-gate NULL, /* bus_remove_interspec */ 99*0Sstevel@tonic-gate i_ddi_map_fault, /* bus_map_fault */ 100*0Sstevel@tonic-gate ddi_no_dma_map, /* bus_dma_map */ 101*0Sstevel@tonic-gate ddi_no_dma_allochdl, /* bus_dma_allochdl */ 102*0Sstevel@tonic-gate NULL, /* bus_dma_freehdl */ 103*0Sstevel@tonic-gate NULL, /* bus_dma_bindhdl */ 104*0Sstevel@tonic-gate NULL, /* bus_dma_unbindhdl */ 105*0Sstevel@tonic-gate NULL, /* bus_dma_flush */ 106*0Sstevel@tonic-gate NULL, /* bus_dma_win */ 107*0Sstevel@tonic-gate NULL, /* bus_dma_ctl */ 108*0Sstevel@tonic-gate tphci_ctl, /* bus_ctl */ 109*0Sstevel@tonic-gate ddi_bus_prop_op, /* bus_prop_op */ 110*0Sstevel@tonic-gate NULL, /* bus_get_eventcookie */ 111*0Sstevel@tonic-gate NULL, /* bus_add_eventcall */ 112*0Sstevel@tonic-gate NULL, /* bus_remove_event */ 113*0Sstevel@tonic-gate NULL, /* bus_post_event */ 114*0Sstevel@tonic-gate NULL, /* bus_intr_ctl */ 115*0Sstevel@tonic-gate tphci_bus_config, /* bus_config */ 116*0Sstevel@tonic-gate tphci_bus_unconfig, /* bus_unconfig */ 117*0Sstevel@tonic-gate NULL, /* bus_fm_init */ 118*0Sstevel@tonic-gate NULL, /* bus_fm_fini */ 119*0Sstevel@tonic-gate NULL, /* bus_fm_access_enter */ 120*0Sstevel@tonic-gate NULL, /* bus_fm_access_exit */ 121*0Sstevel@tonic-gate NULL, /* bus_power */ 122*0Sstevel@tonic-gate tphci_intr_op /* bus_intr_op */ 123*0Sstevel@tonic-gate }; 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate static struct dev_ops tphci_ops = { 126*0Sstevel@tonic-gate DEVO_REV, 127*0Sstevel@tonic-gate 0, 128*0Sstevel@tonic-gate tphci_getinfo, 129*0Sstevel@tonic-gate nulldev, /* identify */ 130*0Sstevel@tonic-gate nulldev, /* probe */ 131*0Sstevel@tonic-gate tphci_attach, /* attach and detach are mandatory */ 132*0Sstevel@tonic-gate tphci_detach, 133*0Sstevel@tonic-gate nodev, /* reset */ 134*0Sstevel@tonic-gate &tphci_cb_ops, /* cb_ops */ 135*0Sstevel@tonic-gate &tphci_bus_ops, /* bus_ops */ 136*0Sstevel@tonic-gate NULL /* power */ 137*0Sstevel@tonic-gate }; 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate extern struct mod_ops mod_driverops; 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate static struct modldrv modldrv = { 142*0Sstevel@tonic-gate &mod_driverops, 143*0Sstevel@tonic-gate "test phci driver %I%", 144*0Sstevel@tonic-gate &tphci_ops 145*0Sstevel@tonic-gate }; 146*0Sstevel@tonic-gate 147*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 148*0Sstevel@tonic-gate MODREV_1, 149*0Sstevel@tonic-gate &modldrv, 150*0Sstevel@tonic-gate NULL 151*0Sstevel@tonic-gate }; 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate int 154*0Sstevel@tonic-gate _init(void) 155*0Sstevel@tonic-gate { 156*0Sstevel@tonic-gate int rval; 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate if ((rval = ddi_soft_state_init(&tphci_state, 159*0Sstevel@tonic-gate sizeof (struct tphci_state), 2)) != 0) { 160*0Sstevel@tonic-gate return (rval); 161*0Sstevel@tonic-gate } 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate if ((rval = mod_install(&modlinkage)) != 0) { 164*0Sstevel@tonic-gate ddi_soft_state_fini(&tphci_state); 165*0Sstevel@tonic-gate } 166*0Sstevel@tonic-gate return (rval); 167*0Sstevel@tonic-gate } 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate int 171*0Sstevel@tonic-gate _fini(void) 172*0Sstevel@tonic-gate { 173*0Sstevel@tonic-gate int rval; 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gate /* 176*0Sstevel@tonic-gate * don't start cleaning up until we know that the module remove 177*0Sstevel@tonic-gate * has worked -- if this works, then we know that each instance 178*0Sstevel@tonic-gate * has successfully been detached 179*0Sstevel@tonic-gate */ 180*0Sstevel@tonic-gate if ((rval = mod_remove(&modlinkage)) != 0) { 181*0Sstevel@tonic-gate return (rval); 182*0Sstevel@tonic-gate } 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate ddi_soft_state_fini(&tphci_state); 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate return (rval); 187*0Sstevel@tonic-gate } 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gate int 190*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 191*0Sstevel@tonic-gate { 192*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 193*0Sstevel@tonic-gate } 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate /* ARGSUSED */ 196*0Sstevel@tonic-gate static int 197*0Sstevel@tonic-gate tphci_open(dev_t *devp, int flag, int otype, cred_t *credp) 198*0Sstevel@tonic-gate { 199*0Sstevel@tonic-gate struct tphci_state *phci; 200*0Sstevel@tonic-gate 201*0Sstevel@tonic-gate if (otype != OTYP_CHR) { 202*0Sstevel@tonic-gate return (EINVAL); 203*0Sstevel@tonic-gate } 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate phci = ddi_get_soft_state(tphci_state, getminor(*devp)); 206*0Sstevel@tonic-gate if (phci == NULL) { 207*0Sstevel@tonic-gate return (ENXIO); 208*0Sstevel@tonic-gate } 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate return (0); 211*0Sstevel@tonic-gate } 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate /* ARGSUSED */ 215*0Sstevel@tonic-gate static int 216*0Sstevel@tonic-gate tphci_close(dev_t dev, int flag, int otype, cred_t *credp) 217*0Sstevel@tonic-gate { 218*0Sstevel@tonic-gate struct tphci_state *phci; 219*0Sstevel@tonic-gate if (otype != OTYP_CHR) { 220*0Sstevel@tonic-gate return (EINVAL); 221*0Sstevel@tonic-gate } 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate phci = ddi_get_soft_state(tphci_state, getminor(dev)); 224*0Sstevel@tonic-gate if (phci == NULL) { 225*0Sstevel@tonic-gate return (ENXIO); 226*0Sstevel@tonic-gate } 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate return (0); 229*0Sstevel@tonic-gate } 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gate /* ARGSUSED */ 232*0Sstevel@tonic-gate static int 233*0Sstevel@tonic-gate tphci_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 234*0Sstevel@tonic-gate cred_t *credp, int *rval) 235*0Sstevel@tonic-gate { 236*0Sstevel@tonic-gate return (0); 237*0Sstevel@tonic-gate } 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gate /* 240*0Sstevel@tonic-gate * attach the module 241*0Sstevel@tonic-gate */ 242*0Sstevel@tonic-gate static int 243*0Sstevel@tonic-gate tphci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 244*0Sstevel@tonic-gate { 245*0Sstevel@tonic-gate char *vclass; 246*0Sstevel@tonic-gate int instance, phci_regis = 0; 247*0Sstevel@tonic-gate struct tphci_state *phci = NULL; 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate instance = ddi_get_instance(dip); 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate switch (cmd) { 252*0Sstevel@tonic-gate case DDI_ATTACH: 253*0Sstevel@tonic-gate break; 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate case DDI_RESUME: 256*0Sstevel@tonic-gate case DDI_PM_RESUME: 257*0Sstevel@tonic-gate return (0); /* nothing to do */ 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate default: 260*0Sstevel@tonic-gate return (DDI_FAILURE); 261*0Sstevel@tonic-gate } 262*0Sstevel@tonic-gate 263*0Sstevel@tonic-gate /* 264*0Sstevel@tonic-gate * Allocate phci data structure. 265*0Sstevel@tonic-gate */ 266*0Sstevel@tonic-gate if (ddi_soft_state_zalloc(tphci_state, instance) != DDI_SUCCESS) { 267*0Sstevel@tonic-gate return (DDI_FAILURE); 268*0Sstevel@tonic-gate } 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate phci = ddi_get_soft_state(tphci_state, instance); 271*0Sstevel@tonic-gate ASSERT(phci != NULL); 272*0Sstevel@tonic-gate phci->dip = dip; 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gate /* bus_addr has the form #,<vhci_class> */ 275*0Sstevel@tonic-gate vclass = strchr(ddi_get_name_addr(dip), ','); 276*0Sstevel@tonic-gate if (vclass == NULL || vclass[1] == '\0') { 277*0Sstevel@tonic-gate cmn_err(CE_NOTE, "tphci invalid bus_addr %s", 278*0Sstevel@tonic-gate ddi_get_name_addr(dip)); 279*0Sstevel@tonic-gate goto attach_fail; 280*0Sstevel@tonic-gate } 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate /* 283*0Sstevel@tonic-gate * Attach this instance with the mpxio framework 284*0Sstevel@tonic-gate */ 285*0Sstevel@tonic-gate if (mdi_phci_register(vclass + 1, dip, 0) != MDI_SUCCESS) { 286*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s mdi_phci_register failed", 287*0Sstevel@tonic-gate ddi_node_name(dip)); 288*0Sstevel@tonic-gate goto attach_fail; 289*0Sstevel@tonic-gate } 290*0Sstevel@tonic-gate phci_regis++; 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate if (ddi_create_minor_node(dip, "devctl", S_IFCHR, 293*0Sstevel@tonic-gate instance, DDI_NT_SCSI_NEXUS, 0) != DDI_SUCCESS) { 294*0Sstevel@tonic-gate cmn_err(CE_NOTE, "%s ddi_create_minor_node failed", 295*0Sstevel@tonic-gate ddi_node_name(dip)); 296*0Sstevel@tonic-gate goto attach_fail; 297*0Sstevel@tonic-gate } 298*0Sstevel@tonic-gate 299*0Sstevel@tonic-gate (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, DDI_NO_AUTODETACH, 1); 300*0Sstevel@tonic-gate ddi_report_dev(dip); 301*0Sstevel@tonic-gate return (DDI_SUCCESS); 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gate attach_fail: 304*0Sstevel@tonic-gate if (phci_regis) 305*0Sstevel@tonic-gate (void) mdi_phci_unregister(dip, 0); 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gate ddi_soft_state_free(tphci_state, instance); 308*0Sstevel@tonic-gate return (DDI_FAILURE); 309*0Sstevel@tonic-gate } 310*0Sstevel@tonic-gate 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate /*ARGSUSED*/ 313*0Sstevel@tonic-gate static int 314*0Sstevel@tonic-gate tphci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 315*0Sstevel@tonic-gate { 316*0Sstevel@tonic-gate int instance = ddi_get_instance(dip); 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate switch (cmd) { 319*0Sstevel@tonic-gate case DDI_DETACH: 320*0Sstevel@tonic-gate break; 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate case DDI_SUSPEND: 323*0Sstevel@tonic-gate case DDI_PM_SUSPEND: 324*0Sstevel@tonic-gate return (0); /* nothing to do */ 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate default: 327*0Sstevel@tonic-gate return (DDI_FAILURE); 328*0Sstevel@tonic-gate } 329*0Sstevel@tonic-gate 330*0Sstevel@tonic-gate if (mdi_phci_unregister(dip, 0) != MDI_SUCCESS) 331*0Sstevel@tonic-gate return (DDI_FAILURE); 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 334*0Sstevel@tonic-gate ddi_soft_state_free(tphci_state, instance); 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate return (DDI_SUCCESS); 337*0Sstevel@tonic-gate } 338*0Sstevel@tonic-gate 339*0Sstevel@tonic-gate /* 340*0Sstevel@tonic-gate * tphci_getinfo() 341*0Sstevel@tonic-gate * Given the device number, return the devinfo pointer or the 342*0Sstevel@tonic-gate * instance number. 343*0Sstevel@tonic-gate * Note: always succeed DDI_INFO_DEVT2INSTANCE, even before attach. 344*0Sstevel@tonic-gate */ 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate /*ARGSUSED*/ 347*0Sstevel@tonic-gate static int 348*0Sstevel@tonic-gate tphci_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 349*0Sstevel@tonic-gate { 350*0Sstevel@tonic-gate struct tphci_state *phci; 351*0Sstevel@tonic-gate int instance = getminor((dev_t)arg); 352*0Sstevel@tonic-gate 353*0Sstevel@tonic-gate switch (cmd) { 354*0Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 355*0Sstevel@tonic-gate phci = ddi_get_soft_state(tphci_state, instance); 356*0Sstevel@tonic-gate if (phci != NULL) 357*0Sstevel@tonic-gate *result = phci->dip; 358*0Sstevel@tonic-gate else { 359*0Sstevel@tonic-gate *result = NULL; 360*0Sstevel@tonic-gate return (DDI_FAILURE); 361*0Sstevel@tonic-gate } 362*0Sstevel@tonic-gate break; 363*0Sstevel@tonic-gate 364*0Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 365*0Sstevel@tonic-gate *result = (void *)(uintptr_t)instance; 366*0Sstevel@tonic-gate break; 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate default: 369*0Sstevel@tonic-gate return (DDI_FAILURE); 370*0Sstevel@tonic-gate } 371*0Sstevel@tonic-gate 372*0Sstevel@tonic-gate return (DDI_SUCCESS); 373*0Sstevel@tonic-gate } 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate /* 376*0Sstevel@tonic-gate * Interrupt stuff. NO OP for pseudo drivers. 377*0Sstevel@tonic-gate */ 378*0Sstevel@tonic-gate /*ARGSUSED*/ 379*0Sstevel@tonic-gate static int 380*0Sstevel@tonic-gate tphci_intr_op(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op, 381*0Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 382*0Sstevel@tonic-gate { 383*0Sstevel@tonic-gate return (DDI_FAILURE); 384*0Sstevel@tonic-gate } 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate static int 387*0Sstevel@tonic-gate tphci_ctl(dev_info_t *dip, dev_info_t *rdip, 388*0Sstevel@tonic-gate ddi_ctl_enum_t ctlop, void *arg, void *result) 389*0Sstevel@tonic-gate { 390*0Sstevel@tonic-gate switch (ctlop) { 391*0Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV: 392*0Sstevel@tonic-gate if (rdip == (dev_info_t *)0) 393*0Sstevel@tonic-gate return (DDI_FAILURE); 394*0Sstevel@tonic-gate cmn_err(CE_CONT, "?tphci-device: %s%d\n", 395*0Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip)); 396*0Sstevel@tonic-gate return (DDI_SUCCESS); 397*0Sstevel@tonic-gate 398*0Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 399*0Sstevel@tonic-gate { 400*0Sstevel@tonic-gate dev_info_t *child = (dev_info_t *)arg; 401*0Sstevel@tonic-gate return (tphci_initchild(dip, child)); 402*0Sstevel@tonic-gate } 403*0Sstevel@tonic-gate 404*0Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 405*0Sstevel@tonic-gate { 406*0Sstevel@tonic-gate dev_info_t *child = (dev_info_t *)arg; 407*0Sstevel@tonic-gate return (tphci_uninitchild(dip, child)); 408*0Sstevel@tonic-gate } 409*0Sstevel@tonic-gate 410*0Sstevel@tonic-gate case DDI_CTLOPS_DMAPMAPC: 411*0Sstevel@tonic-gate case DDI_CTLOPS_REPORTINT: 412*0Sstevel@tonic-gate case DDI_CTLOPS_REGSIZE: 413*0Sstevel@tonic-gate case DDI_CTLOPS_NREGS: 414*0Sstevel@tonic-gate case DDI_CTLOPS_NINTRS: 415*0Sstevel@tonic-gate case DDI_CTLOPS_SIDDEV: 416*0Sstevel@tonic-gate case DDI_CTLOPS_SLAVEONLY: 417*0Sstevel@tonic-gate case DDI_CTLOPS_AFFINITY: 418*0Sstevel@tonic-gate case DDI_CTLOPS_INTR_HILEVEL: 419*0Sstevel@tonic-gate case DDI_CTLOPS_XLATE_INTRS: 420*0Sstevel@tonic-gate case DDI_CTLOPS_POKE: 421*0Sstevel@tonic-gate case DDI_CTLOPS_PEEK: 422*0Sstevel@tonic-gate /* 423*0Sstevel@tonic-gate * These ops correspond to functions that "shouldn't" be called 424*0Sstevel@tonic-gate * by a pseudo driver. So we whine when we're called. 425*0Sstevel@tonic-gate */ 426*0Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d: invalid op (%d) from %s%d\n", 427*0Sstevel@tonic-gate ddi_get_name(dip), ddi_get_instance(dip), 428*0Sstevel@tonic-gate ctlop, ddi_get_name(rdip), ddi_get_instance(rdip)); 429*0Sstevel@tonic-gate return (DDI_FAILURE); 430*0Sstevel@tonic-gate 431*0Sstevel@tonic-gate case DDI_CTLOPS_ATTACH: 432*0Sstevel@tonic-gate case DDI_CTLOPS_BTOP: 433*0Sstevel@tonic-gate case DDI_CTLOPS_BTOPR: 434*0Sstevel@tonic-gate case DDI_CTLOPS_DETACH: 435*0Sstevel@tonic-gate case DDI_CTLOPS_DVMAPAGESIZE: 436*0Sstevel@tonic-gate case DDI_CTLOPS_IOMIN: 437*0Sstevel@tonic-gate case DDI_CTLOPS_POWER: 438*0Sstevel@tonic-gate case DDI_CTLOPS_PTOB: 439*0Sstevel@tonic-gate default: 440*0Sstevel@tonic-gate /* 441*0Sstevel@tonic-gate * The ops that we pass up (default). We pass up memory 442*0Sstevel@tonic-gate * allocation oriented ops that we receive - these may be 443*0Sstevel@tonic-gate * associated with pseudo HBA drivers below us with target 444*0Sstevel@tonic-gate * drivers below them that use ddi memory allocation 445*0Sstevel@tonic-gate * interfaces like scsi_alloc_consistent_buf. 446*0Sstevel@tonic-gate */ 447*0Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 448*0Sstevel@tonic-gate } 449*0Sstevel@tonic-gate } 450*0Sstevel@tonic-gate 451*0Sstevel@tonic-gate static int 452*0Sstevel@tonic-gate tphci_initchild(dev_info_t *dip, dev_info_t *child) 453*0Sstevel@tonic-gate { 454*0Sstevel@tonic-gate _NOTE(ARGUNUSED(dip)) 455*0Sstevel@tonic-gate ddi_set_name_addr(child, "0"); 456*0Sstevel@tonic-gate return (DDI_SUCCESS); 457*0Sstevel@tonic-gate } 458*0Sstevel@tonic-gate 459*0Sstevel@tonic-gate /*ARGSUSED*/ 460*0Sstevel@tonic-gate static int 461*0Sstevel@tonic-gate tphci_uninitchild(dev_info_t *dip, dev_info_t *child) 462*0Sstevel@tonic-gate { 463*0Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 464*0Sstevel@tonic-gate return (DDI_SUCCESS); 465*0Sstevel@tonic-gate } 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gate static int 468*0Sstevel@tonic-gate tp_decode_name(char *devnm, char **cname, char **paddr, char **guid) 469*0Sstevel@tonic-gate { 470*0Sstevel@tonic-gate char *tmp; 471*0Sstevel@tonic-gate 472*0Sstevel@tonic-gate i_ddi_parse_name(devnm, cname, paddr, NULL); 473*0Sstevel@tonic-gate if ((strcmp(*cname, "tclient") != 0) && 474*0Sstevel@tonic-gate (strcmp(*cname, "tphci") != 0) || *paddr == NULL) 475*0Sstevel@tonic-gate return (-1); 476*0Sstevel@tonic-gate 477*0Sstevel@tonic-gate tmp = strchr(*paddr, ','); 478*0Sstevel@tonic-gate if (tmp == NULL || tmp[1] == '\0') 479*0Sstevel@tonic-gate return (-1); 480*0Sstevel@tonic-gate 481*0Sstevel@tonic-gate *guid = tmp + 1; 482*0Sstevel@tonic-gate return (0); 483*0Sstevel@tonic-gate } 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate static int 486*0Sstevel@tonic-gate tphci_bus_config(dev_info_t *parent, uint_t flags, 487*0Sstevel@tonic-gate ddi_bus_config_op_t op, void *arg, dev_info_t **childp) 488*0Sstevel@tonic-gate { 489*0Sstevel@tonic-gate _NOTE(ARGUNUSED(flags)) 490*0Sstevel@tonic-gate char *cname, *paddr, *guid, *devnm; 491*0Sstevel@tonic-gate mdi_pathinfo_t *pip; 492*0Sstevel@tonic-gate int len; 493*0Sstevel@tonic-gate 494*0Sstevel@tonic-gate switch (op) { 495*0Sstevel@tonic-gate case BUS_CONFIG_ONE: 496*0Sstevel@tonic-gate break; 497*0Sstevel@tonic-gate case BUS_CONFIG_DRIVER: /* no direct children to configure */ 498*0Sstevel@tonic-gate case BUS_CONFIG_ALL: 499*0Sstevel@tonic-gate return (DDI_SUCCESS); 500*0Sstevel@tonic-gate default: 501*0Sstevel@tonic-gate return (DDI_FAILURE); 502*0Sstevel@tonic-gate } 503*0Sstevel@tonic-gate 504*0Sstevel@tonic-gate /* only implement BUS_CONFIG_ONE */ 505*0Sstevel@tonic-gate devnm = i_ddi_strdup((char *)arg, KM_SLEEP); 506*0Sstevel@tonic-gate len = strlen(devnm) + 1; 507*0Sstevel@tonic-gate 508*0Sstevel@tonic-gate /* caddr is hardcoded in the form *,<guid> */ 509*0Sstevel@tonic-gate if (tp_decode_name(devnm, &cname, &paddr, &guid) != 0) { 510*0Sstevel@tonic-gate cmn_err(CE_NOTE, "tphci_bus_config -- invalid device %s", 511*0Sstevel@tonic-gate (char *)arg); 512*0Sstevel@tonic-gate kmem_free(devnm, len); 513*0Sstevel@tonic-gate return (DDI_FAILURE); 514*0Sstevel@tonic-gate } 515*0Sstevel@tonic-gate 516*0Sstevel@tonic-gate if (mdi_pi_alloc(parent, cname, guid, paddr, 0, &pip) 517*0Sstevel@tonic-gate != MDI_SUCCESS) { 518*0Sstevel@tonic-gate cmn_err(CE_NOTE, "tphci_bus_config -- mdi_pi_alloc failed"); 519*0Sstevel@tonic-gate kmem_free(devnm, len); 520*0Sstevel@tonic-gate return (DDI_FAILURE); 521*0Sstevel@tonic-gate } 522*0Sstevel@tonic-gate kmem_free(devnm, len); 523*0Sstevel@tonic-gate 524*0Sstevel@tonic-gate if (mdi_pi_online(pip, 0) != MDI_SUCCESS) { 525*0Sstevel@tonic-gate cmn_err(CE_NOTE, "tphci_bus_config -- mdi_pi_online failed"); 526*0Sstevel@tonic-gate (void) mdi_pi_free(pip, 0); 527*0Sstevel@tonic-gate return (DDI_FAILURE); 528*0Sstevel@tonic-gate } 529*0Sstevel@tonic-gate 530*0Sstevel@tonic-gate if (childp) { 531*0Sstevel@tonic-gate *childp = MDI_PI(pip)->pi_client->ct_dip; 532*0Sstevel@tonic-gate ndi_hold_devi(*childp); 533*0Sstevel@tonic-gate } 534*0Sstevel@tonic-gate return (DDI_SUCCESS); 535*0Sstevel@tonic-gate } 536*0Sstevel@tonic-gate 537*0Sstevel@tonic-gate static int 538*0Sstevel@tonic-gate tphci_bus_unconfig(dev_info_t *parent, uint_t flags, 539*0Sstevel@tonic-gate ddi_bus_config_op_t op, void *arg) 540*0Sstevel@tonic-gate { 541*0Sstevel@tonic-gate int rval, circ; 542*0Sstevel@tonic-gate mdi_pathinfo_t *pip; 543*0Sstevel@tonic-gate mdi_phci_t *ph; 544*0Sstevel@tonic-gate char *devnm, *cname, *caddr; 545*0Sstevel@tonic-gate 546*0Sstevel@tonic-gate switch (op) { 547*0Sstevel@tonic-gate case BUS_UNCONFIG_ONE: 548*0Sstevel@tonic-gate devnm = (char *)arg; 549*0Sstevel@tonic-gate i_ddi_parse_name(devnm, &cname, &caddr, NULL); 550*0Sstevel@tonic-gate if (strcmp(cname, "tclient") != 0) 551*0Sstevel@tonic-gate return (DDI_SUCCESS); /* no such device */ 552*0Sstevel@tonic-gate pip = mdi_pi_find(parent, NULL, caddr); 553*0Sstevel@tonic-gate if (pip == NULL) 554*0Sstevel@tonic-gate return (DDI_SUCCESS); 555*0Sstevel@tonic-gate rval = mdi_pi_offline(pip, NDI_DEVI_REMOVE); 556*0Sstevel@tonic-gate return (rval == MDI_SUCCESS ? NDI_SUCCESS : NDI_FAILURE); 557*0Sstevel@tonic-gate 558*0Sstevel@tonic-gate case BUS_UNCONFIG_ALL: 559*0Sstevel@tonic-gate if (flags & NDI_AUTODETACH) 560*0Sstevel@tonic-gate return (DDI_FAILURE); 561*0Sstevel@tonic-gate 562*0Sstevel@tonic-gate ph = DEVI(parent)->devi_mdi_xhci; 563*0Sstevel@tonic-gate ASSERT(ph != NULL); 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate rval = MDI_SUCCESS; 566*0Sstevel@tonic-gate ndi_devi_enter(parent, &circ); 567*0Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ph->ph_path_head; 568*0Sstevel@tonic-gate while (pip) { 569*0Sstevel@tonic-gate rval = mdi_pi_offline(pip, NDI_DEVI_REMOVE); 570*0Sstevel@tonic-gate if (rval != MDI_SUCCESS) { 571*0Sstevel@tonic-gate break; 572*0Sstevel@tonic-gate } 573*0Sstevel@tonic-gate pip = (mdi_pathinfo_t *)ph->ph_path_head; 574*0Sstevel@tonic-gate } 575*0Sstevel@tonic-gate ndi_devi_exit(parent, circ); 576*0Sstevel@tonic-gate return (rval == MDI_SUCCESS ? NDI_SUCCESS : NDI_FAILURE); 577*0Sstevel@tonic-gate 578*0Sstevel@tonic-gate case BUS_UNCONFIG_DRIVER: /* nothing to do */ 579*0Sstevel@tonic-gate return (DDI_SUCCESS); 580*0Sstevel@tonic-gate default: 581*0Sstevel@tonic-gate return (DDI_FAILURE); 582*0Sstevel@tonic-gate } 583*0Sstevel@tonic-gate /*NOTREACHED*/ 584*0Sstevel@tonic-gate } 585