9506 Want support for QLogic QL41000/45000 series devices
[unleashed.git] / usr / src / uts / common / io / pseudonex.c
blobf83b0abf399acd889385a1df699b5743e49b1de4
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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
51 * parent="/pseudo".
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
57 * path_to_inst.
60 #include <sys/types.h>
61 #include <sys/cmn_err.h>
62 #include <sys/conf.h>
63 #include <sys/ddi.h>
64 #include <sys/ddi_impldefs.h>
65 #include <sys/devops.h>
66 #include <sys/instance.h>
67 #include <sys/modctl.h>
68 #include <sys/open.h>
69 #include <sys/stat.h>
70 #include <sys/sunddi.h>
71 #include <sys/sunndi.h>
72 #include <sys/systm.h>
73 #include <sys/mkdev.h>
76 * Config information
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 *,
87 void *);
89 static void *pseudonex_state;
91 typedef struct pseudonex_state {
92 dev_info_t *pnx_devi;
93 } pseudonex_state_t;
95 static struct bus_ops pseudonex_bus_ops = {
96 BUSO_REV,
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 */
131 nodev, /* print */
132 nodev, /* dump */
133 nodev, /* read */
134 nodev, /* write */
135 pseudonex_ioctl, /* ioctl */
136 nodev, /* devmap */
137 nodev, /* mmap */
138 nodev, /* segmap */
139 nochpoll, /* poll */
140 ddi_prop_op, /* cb_prop_op */
141 0, /* streamtab */
142 D_MP | D_NEW | D_HOTPLUG /* Driver compatibility flag */
145 static struct dev_ops pseudo_ops = {
146 DEVO_REV, /* devo_rev, */
147 0, /* refcnt */
148 ddi_getinfo_1to1, /* info */
149 nulldev, /* identify */
150 nulldev, /* probe */
151 pseudonex_attach, /* attach */
152 pseudonex_detach, /* detach */
153 nodev, /* reset */
154 &pseudonex_cb_ops, /* driver operations */
155 &pseudonex_bus_ops, /* bus operations */
156 nulldev, /* power */
157 ddi_quiesce_not_needed, /* quiesce */
161 * Module linkage information for the kernel.
163 static struct modldrv modldrv = {
164 &mod_driverops,
165 "nexus driver for 'pseudo' 1.31",
166 &pseudo_ops,
169 static struct modlinkage modlinkage = {
170 MODREV_1, (void *)&modldrv, NULL
174 _init(void)
176 int err;
178 if ((err = ddi_soft_state_init(&pseudonex_state,
179 sizeof (pseudonex_state_t), 0)) != 0) {
180 return (err);
182 if ((err = mod_install(&modlinkage)) != 0) {
183 ddi_soft_state_fini(&pseudonex_state);
184 return (err);
186 return (0);
190 _fini(void)
192 int err;
194 if ((err = mod_remove(&modlinkage)) != 0)
195 return (err);
196 ddi_soft_state_fini(&pseudonex_state);
197 return (0);
201 _info(struct modinfo *modinfop)
203 return (mod_info(&modlinkage, modinfop));
206 /*ARGSUSED*/
207 static int
208 pseudonex_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
210 int instance;
211 pseudonex_state_t *pnx_state;
213 switch (cmd) {
214 case DDI_ATTACH:
215 break;
216 case DDI_RESUME:
217 return (DDI_SUCCESS);
218 default:
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);
241 /*ARGSUSED*/
242 static int
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);
255 /*ARGSUSED*/
256 static int
257 pseudonex_open(dev_t *devp, int flags, int otyp, cred_t *credp)
259 int instance;
261 if (otyp != OTYP_CHR)
262 return (EINVAL);
264 instance = getminor(*devp);
265 if (ddi_get_soft_state(pseudonex_state, instance) == NULL)
266 return (ENXIO);
268 return (0);
271 /*ARGSUSED*/
272 static int
273 pseudonex_close(dev_t dev, int flags, int otyp, cred_t *credp)
275 int instance;
277 if (otyp != OTYP_CHR)
278 return (EINVAL);
280 instance = getminor(dev);
281 if (ddi_get_soft_state(pseudonex_state, instance) == NULL)
282 return (ENXIO);
284 return (0);
287 /*ARGSUSED*/
288 static int
289 pseudonex_ioctl(dev_t dev,
290 int cmd, intptr_t arg, int mode, cred_t *cred_p, int *rval_p)
292 int instance;
293 pseudonex_state_t *pnx_state;
295 instance = getminor(dev);
296 if ((pnx_state = ddi_get_soft_state(pseudonex_state, instance)) == NULL)
297 return (ENXIO);
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.
306 /*ARGSUSED*/
307 static int
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);
314 static int
315 pseudonex_check_assignment(dev_info_t *child, int test_inst)
317 dev_info_t *tdip;
318 kmutex_t *dmp;
319 const char *childname = ddi_driver_name(child);
320 major_t childmaj = ddi_name_to_major((char *)childname);
322 dmp = &devnamesp[childmaj].dn_lock;
323 LOCK_DEV_OPS(dmp);
324 for (tdip = devnamesp[childmaj].dn_head;
325 tdip != NULL; tdip = ddi_get_next(tdip)) {
326 /* is this the current node? */
327 if (tdip == child)
328 continue;
329 /* is this a duplicate instance? */
330 if (test_inst == ddi_get_instance(tdip)) {
331 UNLOCK_DEV_OPS(dmp);
332 return (DDI_FAILURE);
335 UNLOCK_DEV_OPS(dmp);
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.
347 static int
348 pseudonex_auto_assign(dev_info_t *child)
350 dev_info_t *tdip;
351 kmutex_t *dmp;
352 const char *childname = ddi_driver_name(child);
353 major_t childmaj = ddi_name_to_major((char *)childname);
354 int inst = 0;
356 dmp = &devnamesp[childmaj].dn_lock;
357 LOCK_DEV_OPS(dmp);
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? */
362 if (tdip == child)
363 continue;
364 if (inst == ddi_get_instance(tdip)) {
365 break;
368 if (tdip == NULL) {
369 UNLOCK_DEV_OPS(dmp);
370 return (inst);
373 UNLOCK_DEV_OPS(dmp);
374 return (-1);
377 static int
378 pseudonex_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
379 void *arg, void *result)
381 switch (ctlop) {
382 case DDI_CTLOPS_REPORTDEV:
383 if (rdip == NULL)
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 */
392 int instance = -1;
393 dev_info_t *child = (dev_info_t *)arg;
394 const char *childname = ddi_driver_name(child);
395 char **childlist;
396 uint_t nelems;
397 int auto_assign = 0;
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) {
407 int i, ok = 0;
408 for (i = 0; i < nelems; i++) {
409 if (strcmp(childlist[i], childname) == 0) {
410 ok = 1;
411 break;
414 ddi_prop_free(childlist);
415 if (!ok)
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. "
436 "Node rejected."));
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"));
443 instance = 0;
447 * If an instance has been specified, determine if this
448 * instance is already in use; if we need to pick an instance,
449 * we do it here.
451 if (auto_assign) {
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));
460 } else {
461 if (pseudonex_check_assignment(child, instance) ==
462 DDI_FAILURE) {
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:
527 default:
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));