xref: /illumos-gate/usr/src/uts/common/io/nulldriver.c (revision 62a24de03df1f2399ceda704cb3874dabc98bbbd)
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