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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 * Pseudo devices are devices implemented entirely in software; pseudonex
29 * (pseudo) is the traditional nexus for pseudodevices. Instances are
30 * typically specified via driver.conf files; e.g. a leaf device which
31 * should be attached below pseudonex will have an entry like:
33 * name="foo" parent="/pseudo" instance=0;
35 * pseudonex also supports the devctl (see <sys/devctl.h>) interface via
36 * its :devctl minor node. This allows priveleged userland applications to
37 * online/offline children of pseudo as needed.
39 * In general, we discourage widespread use of this tactic, as it may lead to a
40 * proliferation of nodes in /pseudo. It is preferred that implementors update
41 * pseudo.conf, adding another 'pseudo' nexus child of /pseudo, and then use
42 * that for their collection of device nodes. To do so, add a driver alias
43 * for the name of the nexus child and a line in pseudo.conf such as:
45 * name="foo" parent="/pseudo" instance=<n> valid-children="bar","baz";
47 * Setting 'valid-children' is important because we have an annoying problem;
48 * we need to prevent pseudo devices with 'parent="pseudo"' set from binding
49 * to our new pseudonex child node. A better way might be to teach the
50 * spec-node code to understand that parent="pseudo" really means
53 * At some point in the future, it would be desirable to extend the instance
54 * database to include nexus children of pseudo. Then we could use devctl
55 * or devfs to online nexus children of pseudo, auto-selecting an instance #,
56 * and the instance number selected would be preserved across reboot in
60 #include <sys/types.h>
61 #include <sys/cmn_err.h>
64 #include <sys/ddi_impldefs.h>
65 #include <sys/devops.h>
66 #include <sys/instance.h>
67 #include <sys/modctl.h>
70 #include <sys/sunddi.h>
71 #include <sys/sunndi.h>
72 #include <sys/systm.h>
73 #include <sys/mkdev.h>
78 static int pseudonex_intr_op(dev_info_t
*dip
, dev_info_t
*rdip
,
79 ddi_intr_op_t op
, ddi_intr_handle_impl_t
*hdlp
, void *result
);
81 static int pseudonex_attach(dev_info_t
*, ddi_attach_cmd_t
);
82 static int pseudonex_detach(dev_info_t
*, ddi_detach_cmd_t
);
83 static int pseudonex_open(dev_t
*, int, int, cred_t
*);
84 static int pseudonex_close(dev_t
, int, int, cred_t
*);
85 static int pseudonex_ioctl(dev_t
, int, intptr_t, int, cred_t
*, int *);
86 static int pseudonex_ctl(dev_info_t
*, dev_info_t
*, ddi_ctl_enum_t
, void *,
89 static void *pseudonex_state
;
91 typedef struct pseudonex_state
{
95 static struct bus_ops pseudonex_bus_ops
= {
97 nullbusmap
, /* bus_map */
98 NULL
, /* bus_get_intrspec */
99 NULL
, /* bus_add_intrspec */
100 NULL
, /* bus_remove_intrspec */
101 i_ddi_map_fault
, /* bus_map_fault */
102 ddi_no_dma_map
, /* bus_dma_map */
103 ddi_no_dma_allochdl
, /* bus_dma_allochdl */
104 NULL
, /* bus_dma_freehdl */
105 NULL
, /* bus_dma_bindhdl */
106 NULL
, /* bus_dma_unbindhdl */
107 NULL
, /* bus_dma_flush */
108 NULL
, /* bus_dma_win */
109 NULL
, /* bus_dma_ctl */
110 pseudonex_ctl
, /* bus_ctl */
111 ddi_bus_prop_op
, /* bus_prop_op */
112 0, /* bus_get_eventcookie */
113 0, /* bus_add_eventcall */
114 0, /* bus_remove_eventcall */
115 0, /* bus_post_event */
116 NULL
, /* bus_intr_ctl */
117 NULL
, /* bus_config */
118 NULL
, /* bus_unconfig */
119 NULL
, /* bus_fm_init */
120 NULL
, /* bus_fm_fini */
121 NULL
, /* bus_fm_access_enter */
122 NULL
, /* bus_fm_access_exit */
123 NULL
, /* bus_power */
124 pseudonex_intr_op
/* bus_intr_op */
127 static struct cb_ops pseudonex_cb_ops
= {
128 pseudonex_open
, /* open */
129 pseudonex_close
, /* close */
130 nodev
, /* strategy */
135 pseudonex_ioctl
, /* ioctl */
140 ddi_prop_op
, /* cb_prop_op */
142 D_MP
| D_NEW
| D_HOTPLUG
/* Driver compatibility flag */
145 static struct dev_ops pseudo_ops
= {
146 DEVO_REV
, /* devo_rev, */
148 ddi_getinfo_1to1
, /* info */
149 nulldev
, /* identify */
151 pseudonex_attach
, /* attach */
152 pseudonex_detach
, /* detach */
154 &pseudonex_cb_ops
, /* driver operations */
155 &pseudonex_bus_ops
, /* bus operations */
157 ddi_quiesce_not_needed
, /* quiesce */
161 * Module linkage information for the kernel.
163 static struct modldrv modldrv
= {
165 "nexus driver for 'pseudo' 1.31",
169 static struct modlinkage modlinkage
= {
170 MODREV_1
, (void *)&modldrv
, NULL
178 if ((err
= ddi_soft_state_init(&pseudonex_state
,
179 sizeof (pseudonex_state_t
), 0)) != 0) {
182 if ((err
= mod_install(&modlinkage
)) != 0) {
183 ddi_soft_state_fini(&pseudonex_state
);
194 if ((err
= mod_remove(&modlinkage
)) != 0)
196 ddi_soft_state_fini(&pseudonex_state
);
201 _info(struct modinfo
*modinfop
)
203 return (mod_info(&modlinkage
, modinfop
));
208 pseudonex_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
211 pseudonex_state_t
*pnx_state
;
217 return (DDI_SUCCESS
);
219 return (DDI_FAILURE
);
223 * Save the devi for this instance in the soft_state data.
225 instance
= ddi_get_instance(devi
);
226 if (ddi_soft_state_zalloc(pseudonex_state
, instance
) != DDI_SUCCESS
)
227 return (DDI_FAILURE
);
228 pnx_state
= ddi_get_soft_state(pseudonex_state
, instance
);
229 pnx_state
->pnx_devi
= devi
;
231 if (ddi_create_minor_node(devi
, "devctl", S_IFCHR
, instance
,
232 DDI_NT_NEXUS
, 0) != DDI_SUCCESS
) {
233 ddi_remove_minor_node(devi
, NULL
);
234 ddi_soft_state_free(pseudonex_state
, instance
);
235 return (DDI_FAILURE
);
237 ddi_report_dev(devi
);
238 return (DDI_SUCCESS
);
243 pseudonex_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
)
245 int instance
= ddi_get_instance(devi
);
247 if (cmd
== DDI_SUSPEND
)
248 return (DDI_SUCCESS
);
250 ddi_remove_minor_node(devi
, NULL
);
251 ddi_soft_state_free(pseudonex_state
, instance
);
252 return (DDI_SUCCESS
);
257 pseudonex_open(dev_t
*devp
, int flags
, int otyp
, cred_t
*credp
)
261 if (otyp
!= OTYP_CHR
)
264 instance
= getminor(*devp
);
265 if (ddi_get_soft_state(pseudonex_state
, instance
) == NULL
)
273 pseudonex_close(dev_t dev
, int flags
, int otyp
, cred_t
*credp
)
277 if (otyp
!= OTYP_CHR
)
280 instance
= getminor(dev
);
281 if (ddi_get_soft_state(pseudonex_state
, instance
) == NULL
)
289 pseudonex_ioctl(dev_t dev
,
290 int cmd
, intptr_t arg
, int mode
, cred_t
*cred_p
, int *rval_p
)
293 pseudonex_state_t
*pnx_state
;
295 instance
= getminor(dev
);
296 if ((pnx_state
= ddi_get_soft_state(pseudonex_state
, instance
)) == NULL
)
298 ASSERT(pnx_state
->pnx_devi
);
299 return (ndi_devctl_ioctl(pnx_state
->pnx_devi
, cmd
, arg
, mode
, 0));
303 * pseudonex_intr_op: pseudonex convert an interrupt number to an
304 * interrupt. NO OP for pseudo drivers.
308 pseudonex_intr_op(dev_info_t
*dip
, dev_info_t
*rdip
, ddi_intr_op_t op
,
309 ddi_intr_handle_impl_t
*hdlp
, void *result
)
311 return (DDI_FAILURE
);
315 pseudonex_check_assignment(dev_info_t
*child
, int test_inst
)
319 const char *childname
= ddi_driver_name(child
);
320 major_t childmaj
= ddi_name_to_major((char *)childname
);
322 dmp
= &devnamesp
[childmaj
].dn_lock
;
324 for (tdip
= devnamesp
[childmaj
].dn_head
;
325 tdip
!= NULL
; tdip
= ddi_get_next(tdip
)) {
326 /* is this the current node? */
329 /* is this a duplicate instance? */
330 if (test_inst
== ddi_get_instance(tdip
)) {
332 return (DDI_FAILURE
);
336 return (DDI_SUCCESS
);
340 * This is a nasty, slow hack. But we're stuck with it until we do some
341 * major surgery on the instance assignment subsystem, to allow pseudonode
342 * instance assignment to be tracked there.
344 * To auto-assign an instance number, we exhaustively search the instance
345 * list for each possible instance number until we find one which is unused.
348 pseudonex_auto_assign(dev_info_t
*child
)
352 const char *childname
= ddi_driver_name(child
);
353 major_t childmaj
= ddi_name_to_major((char *)childname
);
356 dmp
= &devnamesp
[childmaj
].dn_lock
;
358 for (inst
= 0; inst
<= MAXMIN32
; inst
++) {
359 for (tdip
= devnamesp
[childmaj
].dn_head
; tdip
!= NULL
;
360 tdip
= ddi_get_next(tdip
)) {
361 /* is this the current node? */
364 if (inst
== ddi_get_instance(tdip
)) {
378 pseudonex_ctl(dev_info_t
*dip
, dev_info_t
*rdip
, ddi_ctl_enum_t ctlop
,
379 void *arg
, void *result
)
382 case DDI_CTLOPS_REPORTDEV
:
384 return (DDI_FAILURE
);
385 cmn_err(CE_CONT
, "?pseudo-device: %s%d\n",
386 ddi_driver_name(rdip
), ddi_get_instance(rdip
));
387 return (DDI_SUCCESS
);
389 case DDI_CTLOPS_INITCHILD
:
391 char name
[12]; /* enough for a decimal integer */
393 dev_info_t
*child
= (dev_info_t
*)arg
;
394 const char *childname
= ddi_driver_name(child
);
400 * If this pseudonex node has a valid-children property,
401 * then that acts as an access control list for children
402 * allowed to attach beneath this node. Honor it.
404 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY
, dip
,
405 DDI_PROP_DONTPASS
, "valid-children", &childlist
,
406 &nelems
) == DDI_PROP_SUCCESS
) {
408 for (i
= 0; i
< nelems
; i
++) {
409 if (strcmp(childlist
[i
], childname
) == 0) {
414 ddi_prop_free(childlist
);
416 return (DDI_FAILURE
);
420 * Look up the "instance" property. If it does not exist,
421 * check to see if the "auto-assign-instance" property is set.
422 * If not, default to using instance 0; while not ideal, this
423 * is a legacy behavior we must continue to support.
425 instance
= ddi_prop_get_int(DDI_DEV_T_ANY
, child
,
426 DDI_PROP_DONTPASS
, "instance", -1);
427 auto_assign
= ddi_prop_exists(DDI_DEV_T_ANY
, child
,
428 DDI_PROP_DONTPASS
, "auto-assign-instance");
429 NDI_CONFIG_DEBUG((CE_NOTE
,
430 "pseudonex: DDI_CTLOPS_INITCHILD(instance=%d, "
431 "auto-assign=%d)", instance
, auto_assign
));
433 if (instance
!= -1 && auto_assign
!= 0) {
434 NDI_CONFIG_DEBUG((CE_NOTE
, "both instance and "
435 "auto-assign-instance properties specified. "
437 return (DDI_FAILURE
);
440 if (instance
== -1 && auto_assign
== 0) {
441 /* default to instance 0 if not specified */
442 NDI_CONFIG_DEBUG((CE_NOTE
, "defaulting to 0"));
447 * If an instance has been specified, determine if this
448 * instance is already in use; if we need to pick an instance,
452 if ((instance
= pseudonex_auto_assign(child
)) == -1) {
453 NDI_CONFIG_DEBUG((CE_NOTE
, "failed to "
454 "auto-select instance for %s", childname
));
455 return (DDI_FAILURE
);
457 NDI_CONFIG_DEBUG((CE_NOTE
,
458 "auto-selected instance for %s: %d",
459 childname
, instance
));
461 if (pseudonex_check_assignment(child
, instance
) ==
463 NDI_CONFIG_DEBUG((CE_WARN
,
464 "Duplicate instance %d of node \"%s\" "
465 "ignored.", instance
, childname
));
466 return (DDI_FAILURE
);
468 NDI_CONFIG_DEBUG((CE_NOTE
,
469 "using fixed-assignment instance for %s: %d",
470 childname
, instance
));
474 * Attach the instance number to the node. This allows
475 * us to have multiple instances of the same pseudo
476 * device, they will be named 'device@instance'. If this
477 * breaks programs, we may need to special-case instance 0
478 * into 'device'. Ick. devlinks appears to handle the
479 * new names ok, so if only names in /dev are used
480 * this may not be necessary.
482 (void) snprintf(name
, sizeof (name
), "%d", instance
);
483 DEVI(child
)->devi_instance
= instance
;
484 ddi_set_name_addr(child
, name
);
485 return (DDI_SUCCESS
);
488 case DDI_CTLOPS_UNINITCHILD
:
490 dev_info_t
*child
= (dev_info_t
*)arg
;
492 NDI_CONFIG_DEBUG((CE_NOTE
,
493 "DDI_CTLOPS_UNINITCHILD(%s, instance=%d)",
494 ddi_driver_name(child
), DEVI(child
)->devi_instance
));
496 ddi_set_name_addr(child
, NULL
);
498 return (DDI_SUCCESS
);
501 case DDI_CTLOPS_DMAPMAPC
:
502 case DDI_CTLOPS_REPORTINT
:
503 case DDI_CTLOPS_REGSIZE
:
504 case DDI_CTLOPS_NREGS
:
505 case DDI_CTLOPS_SIDDEV
:
506 case DDI_CTLOPS_SLAVEONLY
:
507 case DDI_CTLOPS_AFFINITY
:
508 case DDI_CTLOPS_POKE
:
509 case DDI_CTLOPS_PEEK
:
511 * These ops correspond to functions that "shouldn't" be called
512 * by a pseudo driver. So we whine when we're called.
514 cmn_err(CE_CONT
, "%s%d: invalid op (%d) from %s%d\n",
515 ddi_driver_name(dip
), ddi_get_instance(dip
), ctlop
,
516 ddi_driver_name(rdip
), ddi_get_instance(rdip
));
517 return (DDI_FAILURE
);
519 case DDI_CTLOPS_ATTACH
:
520 case DDI_CTLOPS_BTOP
:
521 case DDI_CTLOPS_BTOPR
:
522 case DDI_CTLOPS_DETACH
:
523 case DDI_CTLOPS_DVMAPAGESIZE
:
524 case DDI_CTLOPS_IOMIN
:
525 case DDI_CTLOPS_POWER
:
526 case DDI_CTLOPS_PTOB
:
529 * The ops that we pass up (default). We pass up memory
530 * allocation oriented ops that we receive - these may be
531 * associated with pseudo HBA drivers below us with target
532 * drivers below them that use ddi memory allocation
533 * interfaces like scsi_alloc_consistent_buf.
535 return (ddi_ctlops(dip
, rdip
, ctlop
, arg
, result
));