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