1*62a24de0SChris Horne /* 2*62a24de0SChris Horne * CDDL HEADER START 3*62a24de0SChris Horne * 4*62a24de0SChris Horne * The contents of this file are subject to the terms of the 5*62a24de0SChris Horne * Common Development and Distribution License (the "License"). 6*62a24de0SChris Horne * You may not use this file except in compliance with the License. 7*62a24de0SChris Horne * 8*62a24de0SChris Horne * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*62a24de0SChris Horne * or http://www.opensolaris.org/os/licensing. 10*62a24de0SChris Horne * See the License for the specific language governing permissions 11*62a24de0SChris Horne * and limitations under the License. 12*62a24de0SChris Horne * 13*62a24de0SChris Horne * When distributing Covered Code, include this CDDL HEADER in each 14*62a24de0SChris Horne * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*62a24de0SChris Horne * If applicable, add the following below this CDDL HEADER, with the 16*62a24de0SChris Horne * fields enclosed by brackets "[]" replaced with your own identifying 17*62a24de0SChris Horne * information: Portions Copyright [yyyy] [name of copyright owner] 18*62a24de0SChris Horne * 19*62a24de0SChris Horne * CDDL HEADER END 20*62a24de0SChris Horne */ 21*62a24de0SChris Horne /* 22*62a24de0SChris Horne * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*62a24de0SChris Horne * Use is subject to license terms. 24*62a24de0SChris Horne */ 25*62a24de0SChris Horne 26*62a24de0SChris Horne /* 27*62a24de0SChris Horne * nulldriver - null device driver 28*62a24de0SChris Horne * 29*62a24de0SChris Horne * The nulldriver is used to associate a solaris driver with a specific 30*62a24de0SChris Horne * device without enabling external device access. 31*62a24de0SChris Horne * 32*62a24de0SChris Horne * The driver can be used to: 33*62a24de0SChris Horne * 34*62a24de0SChris Horne * o Prevent external access to specific devices/hardware by associating a 35*62a24de0SChris Horne * high-precedence 'compatible' binding, including a path-oriented alias, 36*62a24de0SChris Horne * with nulldriver. 37*62a24de0SChris Horne * 38*62a24de0SChris Horne * o Enable a nexus bus_config implementation to perform dynamic child 39*62a24de0SChris Horne * discovery by creating a child 'probe' devinfo node, bound to 40*62a24de0SChris Horne * nulldriver, at the specific child @unit-addresses associated with 41*62a24de0SChris Horne * discovery. With a nulldriver bound 'probe' node, nexus driver 42*62a24de0SChris Horne * bus_config discovery code can use the same devinfo node oriented 43*62a24de0SChris Horne * transport services for both discovery and normal-operation: which 44*62a24de0SChris Horne * is a significant simplification. While nulldriver prevents external 45*62a24de0SChris Horne * device access, a nexus driver can still internally use the transport 46*62a24de0SChris Horne * services. 47*62a24de0SChris Horne * 48*62a24de0SChris Horne * A scsi(4) example of this type of use is SCSA enumeration services 49*62a24de0SChris Horne * issuing a scsi REPORT_LUN command to a lun-0 'probe' node bound to 50*62a24de0SChris Horne * nulldriver in order to discover all luns supported by a target. 51*62a24de0SChris Horne */ 52*62a24de0SChris Horne 53*62a24de0SChris Horne #include <sys/modctl.h> 54*62a24de0SChris Horne #include <sys/conf.h> 55*62a24de0SChris Horne #include <sys/ddi.h> 56*62a24de0SChris Horne #include <sys/sunddi.h> 57*62a24de0SChris Horne #include <sys/cmn_err.h> 58*62a24de0SChris Horne 59*62a24de0SChris Horne static int nulldriver_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 60*62a24de0SChris Horne static int nulldriver_probe(dev_info_t *); 61*62a24de0SChris Horne static int nulldriver_attach(dev_info_t *, ddi_attach_cmd_t); 62*62a24de0SChris Horne static int nulldriver_detach(dev_info_t *, ddi_detach_cmd_t); 63*62a24de0SChris Horne 64*62a24de0SChris Horne static struct cb_ops nulldriver_cb_ops = { 65*62a24de0SChris Horne nodev, /* open */ 66*62a24de0SChris Horne nodev, /* close */ 67*62a24de0SChris Horne nodev, /* strategy */ 68*62a24de0SChris Horne nodev, /* print */ 69*62a24de0SChris Horne nodev, /* dump */ 70*62a24de0SChris Horne nodev, /* read */ 71*62a24de0SChris Horne nodev, /* write */ 72*62a24de0SChris Horne nodev, /* ioctl */ 73*62a24de0SChris Horne nodev, /* devmap */ 74*62a24de0SChris Horne nodev, /* mmap */ 75*62a24de0SChris Horne nodev, /* segmap */ 76*62a24de0SChris Horne nochpoll, /* poll */ 77*62a24de0SChris Horne ddi_prop_op, /* cb_prop_op */ 78*62a24de0SChris Horne 0, /* streamtab */ 79*62a24de0SChris Horne D_MP | D_NEW | D_HOTPLUG /* Driver compatibility flag */ 80*62a24de0SChris Horne }; 81*62a24de0SChris Horne 82*62a24de0SChris Horne static struct dev_ops nulldriver_dev_ops = { 83*62a24de0SChris Horne DEVO_REV, /* devo_rev, */ 84*62a24de0SChris Horne 0, /* refcnt */ 85*62a24de0SChris Horne nulldriver_getinfo, /* info */ 86*62a24de0SChris Horne nodev, /* identify */ 87*62a24de0SChris Horne nulldriver_probe, /* probe */ 88*62a24de0SChris Horne nulldriver_attach, /* attach */ 89*62a24de0SChris Horne nulldriver_detach, /* detach */ 90*62a24de0SChris Horne nodev, /* reset */ 91*62a24de0SChris Horne &nulldriver_cb_ops, /* driver operations */ 92*62a24de0SChris Horne (struct bus_ops *)0, /* bus operations */ 93*62a24de0SChris Horne NULL, /* power */ 94*62a24de0SChris Horne ddi_quiesce_not_needed, /* quiesce */ 95*62a24de0SChris Horne }; 96*62a24de0SChris Horne 97*62a24de0SChris Horne static struct modldrv modldrv = { 98*62a24de0SChris Horne &mod_driverops, "nulldriver 1.1", &nulldriver_dev_ops 99*62a24de0SChris Horne }; 100*62a24de0SChris Horne 101*62a24de0SChris Horne static struct modlinkage modlinkage = { 102*62a24de0SChris Horne MODREV_1, &modldrv, NULL 103*62a24de0SChris Horne }; 104*62a24de0SChris Horne 105*62a24de0SChris Horne int 106*62a24de0SChris Horne _init(void) 107*62a24de0SChris Horne { 108*62a24de0SChris Horne return (mod_install(&modlinkage)); 109*62a24de0SChris Horne } 110*62a24de0SChris Horne 111*62a24de0SChris Horne int 112*62a24de0SChris Horne _fini(void) 113*62a24de0SChris Horne { 114*62a24de0SChris Horne return (mod_remove(&modlinkage)); 115*62a24de0SChris Horne } 116*62a24de0SChris Horne 117*62a24de0SChris Horne int 118*62a24de0SChris Horne _info(struct modinfo *modinfop) 119*62a24de0SChris Horne { 120*62a24de0SChris Horne return (mod_info(&modlinkage, modinfop)); 121*62a24de0SChris Horne } 122*62a24de0SChris Horne 123*62a24de0SChris Horne /*ARGSUSED*/ 124*62a24de0SChris Horne static int 125*62a24de0SChris Horne nulldriver_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, 126*62a24de0SChris Horne void *arg, void **result) 127*62a24de0SChris Horne { 128*62a24de0SChris Horne return (DDI_FAILURE); 129*62a24de0SChris Horne } 130*62a24de0SChris Horne 131*62a24de0SChris Horne /*ARGSUSED*/ 132*62a24de0SChris Horne static int 133*62a24de0SChris Horne nulldriver_probe(dev_info_t *dip) 134*62a24de0SChris Horne { 135*62a24de0SChris Horne /* 136*62a24de0SChris Horne * We want to succeed probe so that the node gets assigned a unit 137*62a24de0SChris Horne * address "@addr". 138*62a24de0SChris Horne */ 139*62a24de0SChris Horne if (ddi_dev_is_sid(dip) == DDI_SUCCESS) 140*62a24de0SChris Horne return (DDI_PROBE_DONTCARE); 141*62a24de0SChris Horne return (DDI_PROBE_DONTCARE); 142*62a24de0SChris Horne } 143*62a24de0SChris Horne 144*62a24de0SChris Horne /* 145*62a24de0SChris Horne * nulldriver_attach() 146*62a24de0SChris Horne * attach(9e) entrypoint. 147*62a24de0SChris Horne */ 148*62a24de0SChris Horne /* ARGSUSED */ 149*62a24de0SChris Horne static int 150*62a24de0SChris Horne nulldriver_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 151*62a24de0SChris Horne { 152*62a24de0SChris Horne switch (cmd) { 153*62a24de0SChris Horne case DDI_ATTACH: 154*62a24de0SChris Horne case DDI_RESUME: 155*62a24de0SChris Horne return (DDI_SUCCESS); 156*62a24de0SChris Horne 157*62a24de0SChris Horne case DDI_PM_RESUME: 158*62a24de0SChris Horne default: 159*62a24de0SChris Horne return (DDI_FAILURE); 160*62a24de0SChris Horne } 161*62a24de0SChris Horne } 162*62a24de0SChris Horne 163*62a24de0SChris Horne /* 164*62a24de0SChris Horne * nulldriver_detach() 165*62a24de0SChris Horne * detach(9E) entrypoint 166*62a24de0SChris Horne */ 167*62a24de0SChris Horne /* ARGSUSED */ 168*62a24de0SChris Horne static int 169*62a24de0SChris Horne nulldriver_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 170*62a24de0SChris Horne { 171*62a24de0SChris Horne switch (cmd) { 172*62a24de0SChris Horne case DDI_DETACH: 173*62a24de0SChris Horne case DDI_SUSPEND: 174*62a24de0SChris Horne return (DDI_SUCCESS); 175*62a24de0SChris Horne 176*62a24de0SChris Horne case DDI_PM_SUSPEND: 177*62a24de0SChris Horne default: 178*62a24de0SChris Horne return (DDI_FAILURE); 179*62a24de0SChris Horne } 180*62a24de0SChris Horne } 181