diff options
Diffstat (limited to 'usr/src/uts/common/io/nulldriver.c')
-rw-r--r-- | usr/src/uts/common/io/nulldriver.c | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/usr/src/uts/common/io/nulldriver.c b/usr/src/uts/common/io/nulldriver.c new file mode 100644 index 0000000000..04e8d86b22 --- /dev/null +++ b/usr/src/uts/common/io/nulldriver.c @@ -0,0 +1,180 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * nulldriver - null device driver + * + * The nulldriver is used to associate a solaris driver with a specific + * device without enabling external device access. + * + * The driver can be used to: + * + * o Prevent external access to specific devices/hardware by associating a + * high-precedence 'compatible' binding, including a path-oriented alias, + * with nulldriver. + * + * o Enable a nexus bus_config implementation to perform dynamic child + * discovery by creating a child 'probe' devinfo node, bound to + * nulldriver, at the specific child @unit-addresses associated with + * discovery. With a nulldriver bound 'probe' node, nexus driver + * bus_config discovery code can use the same devinfo node oriented + * transport services for both discovery and normal-operation: which + * is a significant simplification. While nulldriver prevents external + * device access, a nexus driver can still internally use the transport + * services. + * + * A scsi(4) example of this type of use is SCSA enumeration services + * issuing a scsi REPORT_LUN command to a lun-0 'probe' node bound to + * nulldriver in order to discover all luns supported by a target. + */ + +#include <sys/modctl.h> +#include <sys/conf.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/cmn_err.h> + +static int nulldriver_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); +static int nulldriver_probe(dev_info_t *); +static int nulldriver_attach(dev_info_t *, ddi_attach_cmd_t); +static int nulldriver_detach(dev_info_t *, ddi_detach_cmd_t); + +static struct cb_ops nulldriver_cb_ops = { + nodev, /* open */ + nodev, /* close */ + nodev, /* strategy */ + nodev, /* print */ + nodev, /* dump */ + nodev, /* read */ + nodev, /* write */ + nodev, /* ioctl */ + nodev, /* devmap */ + nodev, /* mmap */ + nodev, /* segmap */ + nochpoll, /* poll */ + ddi_prop_op, /* cb_prop_op */ + 0, /* streamtab */ + D_MP | D_NEW | D_HOTPLUG /* Driver compatibility flag */ +}; + +static struct dev_ops nulldriver_dev_ops = { + DEVO_REV, /* devo_rev, */ + 0, /* refcnt */ + nulldriver_getinfo, /* info */ + nodev, /* identify */ + nulldriver_probe, /* probe */ + nulldriver_attach, /* attach */ + nulldriver_detach, /* detach */ + nodev, /* reset */ + &nulldriver_cb_ops, /* driver operations */ + (struct bus_ops *)0, /* bus operations */ + NULL, /* power */ + ddi_quiesce_not_needed, /* quiesce */ +}; + +static struct modldrv modldrv = { + &mod_driverops, "nulldriver 1.1", &nulldriver_dev_ops +}; + +static struct modlinkage modlinkage = { + MODREV_1, &modldrv, NULL +}; + +int +_init(void) +{ + return (mod_install(&modlinkage)); +} + +int +_fini(void) +{ + return (mod_remove(&modlinkage)); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + +/*ARGSUSED*/ +static int +nulldriver_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, + void *arg, void **result) +{ + return (DDI_FAILURE); +} + +/*ARGSUSED*/ +static int +nulldriver_probe(dev_info_t *dip) +{ + /* + * We want to succeed probe so that the node gets assigned a unit + * address "@addr". + */ + if (ddi_dev_is_sid(dip) == DDI_SUCCESS) + return (DDI_PROBE_DONTCARE); + return (DDI_PROBE_DONTCARE); +} + +/* + * nulldriver_attach() + * attach(9e) entrypoint. + */ +/* ARGSUSED */ +static int +nulldriver_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ + switch (cmd) { + case DDI_ATTACH: + case DDI_RESUME: + return (DDI_SUCCESS); + + case DDI_PM_RESUME: + default: + return (DDI_FAILURE); + } +} + +/* + * nulldriver_detach() + * detach(9E) entrypoint + */ +/* ARGSUSED */ +static int +nulldriver_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + switch (cmd) { + case DDI_DETACH: + case DDI_SUSPEND: + return (DDI_SUCCESS); + + case DDI_PM_SUSPEND: + default: + return (DDI_FAILURE); + } +} |