Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/pseudonex.c
+++ new/usr/src/uts/common/io/pseudonex.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26
27 27 /*
28 28 * Pseudo devices are devices implemented entirely in software; pseudonex
29 29 * (pseudo) is the traditional nexus for pseudodevices. Instances are
30 30 * typically specified via driver.conf files; e.g. a leaf device which
31 31 * should be attached below pseudonex will have an entry like:
32 32 *
33 33 * name="foo" parent="/pseudo" instance=0;
34 34 *
35 35 * pseudonex also supports the devctl (see <sys/devctl.h>) interface via
36 36 * its :devctl minor node. This allows priveleged userland applications to
37 37 * online/offline children of pseudo as needed.
38 38 *
39 39 * In general, we discourage widespread use of this tactic, as it may lead to a
40 40 * proliferation of nodes in /pseudo. It is preferred that implementors update
41 41 * pseudo.conf, adding another 'pseudo' nexus child of /pseudo, and then use
42 42 * that for their collection of device nodes. To do so, add a driver alias
43 43 * for the name of the nexus child and a line in pseudo.conf such as:
44 44 *
45 45 * name="foo" parent="/pseudo" instance=<n> valid-children="bar","baz";
46 46 *
47 47 * Setting 'valid-children' is important because we have an annoying problem;
48 48 * we need to prevent pseudo devices with 'parent="pseudo"' set from binding
49 49 * to our new pseudonex child node. A better way might be to teach the
50 50 * spec-node code to understand that parent="pseudo" really means
51 51 * parent="/pseudo".
52 52 *
53 53 * At some point in the future, it would be desirable to extend the instance
54 54 * database to include nexus children of pseudo. Then we could use devctl
55 55 * or devfs to online nexus children of pseudo, auto-selecting an instance #,
56 56 * and the instance number selected would be preserved across reboot in
57 57 * path_to_inst.
58 58 */
59 59
60 60 #include <sys/types.h>
61 61 #include <sys/cmn_err.h>
62 62 #include <sys/conf.h>
63 63 #include <sys/ddi.h>
64 64 #include <sys/ddi_impldefs.h>
65 65 #include <sys/devops.h>
66 66 #include <sys/instance.h>
67 67 #include <sys/modctl.h>
68 68 #include <sys/open.h>
69 69 #include <sys/stat.h>
70 70 #include <sys/sunddi.h>
71 71 #include <sys/sunndi.h>
72 72 #include <sys/systm.h>
73 73 #include <sys/mkdev.h>
74 74
75 75 /*
76 76 * Config information
77 77 */
78 78 static int pseudonex_intr_op(dev_info_t *dip, dev_info_t *rdip,
79 79 ddi_intr_op_t op, ddi_intr_handle_impl_t *hdlp, void *result);
80 80
81 81 static int pseudonex_attach(dev_info_t *, ddi_attach_cmd_t);
82 82 static int pseudonex_detach(dev_info_t *, ddi_detach_cmd_t);
83 83 static int pseudonex_open(dev_t *, int, int, cred_t *);
84 84 static int pseudonex_close(dev_t, int, int, cred_t *);
85 85 static int pseudonex_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
86 86 static int pseudonex_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *,
87 87 void *);
88 88
89 89 static void *pseudonex_state;
90 90
91 91 typedef struct pseudonex_state {
92 92 dev_info_t *pnx_devi;
93 93 } pseudonex_state_t;
94 94
95 95 static struct bus_ops pseudonex_bus_ops = {
96 96 BUSO_REV,
97 97 nullbusmap, /* bus_map */
98 98 NULL, /* bus_get_intrspec */
99 99 NULL, /* bus_add_intrspec */
100 100 NULL, /* bus_remove_intrspec */
101 101 i_ddi_map_fault, /* bus_map_fault */
102 102 ddi_no_dma_map, /* bus_dma_map */
103 103 ddi_no_dma_allochdl, /* bus_dma_allochdl */
104 104 NULL, /* bus_dma_freehdl */
105 105 NULL, /* bus_dma_bindhdl */
106 106 NULL, /* bus_dma_unbindhdl */
107 107 NULL, /* bus_dma_flush */
108 108 NULL, /* bus_dma_win */
109 109 NULL, /* bus_dma_ctl */
110 110 pseudonex_ctl, /* bus_ctl */
111 111 ddi_bus_prop_op, /* bus_prop_op */
112 112 0, /* bus_get_eventcookie */
113 113 0, /* bus_add_eventcall */
114 114 0, /* bus_remove_eventcall */
115 115 0, /* bus_post_event */
116 116 NULL, /* bus_intr_ctl */
117 117 NULL, /* bus_config */
118 118 NULL, /* bus_unconfig */
119 119 NULL, /* bus_fm_init */
120 120 NULL, /* bus_fm_fini */
121 121 NULL, /* bus_fm_access_enter */
122 122 NULL, /* bus_fm_access_exit */
123 123 NULL, /* bus_power */
124 124 pseudonex_intr_op /* bus_intr_op */
125 125 };
126 126
127 127 static struct cb_ops pseudonex_cb_ops = {
128 128 pseudonex_open, /* open */
129 129 pseudonex_close, /* close */
130 130 nodev, /* strategy */
131 131 nodev, /* print */
132 132 nodev, /* dump */
133 133 nodev, /* read */
134 134 nodev, /* write */
135 135 pseudonex_ioctl, /* ioctl */
136 136 nodev, /* devmap */
137 137 nodev, /* mmap */
138 138 nodev, /* segmap */
139 139 nochpoll, /* poll */
140 140 ddi_prop_op, /* cb_prop_op */
141 141 0, /* streamtab */
142 142 D_MP | D_NEW | D_HOTPLUG /* Driver compatibility flag */
143 143 };
144 144
145 145 static struct dev_ops pseudo_ops = {
146 146 DEVO_REV, /* devo_rev, */
147 147 0, /* refcnt */
148 148 ddi_getinfo_1to1, /* info */
149 149 nulldev, /* identify */
150 150 nulldev, /* probe */
151 151 pseudonex_attach, /* attach */
152 152 pseudonex_detach, /* detach */
153 153 nodev, /* reset */
154 154 &pseudonex_cb_ops, /* driver operations */
155 155 &pseudonex_bus_ops, /* bus operations */
156 156 nulldev, /* power */
157 157 ddi_quiesce_not_needed, /* quiesce */
158 158 };
159 159
↓ open down ↓ |
159 lines elided |
↑ open up ↑ |
160 160 /*
161 161 * Module linkage information for the kernel.
162 162 */
163 163 static struct modldrv modldrv = {
164 164 &mod_driverops,
165 165 "nexus driver for 'pseudo' 1.31",
166 166 &pseudo_ops,
167 167 };
168 168
169 169 static struct modlinkage modlinkage = {
170 - MODREV_1, (void *)&modldrv, NULL
170 + MODREV_1, { (void *)&modldrv, NULL }
171 171 };
172 172
173 173 int
174 174 _init(void)
175 175 {
176 176 int err;
177 177
178 178 if ((err = ddi_soft_state_init(&pseudonex_state,
179 179 sizeof (pseudonex_state_t), 0)) != 0) {
180 180 return (err);
181 181 }
182 182 if ((err = mod_install(&modlinkage)) != 0) {
183 183 ddi_soft_state_fini(&pseudonex_state);
184 184 return (err);
185 185 }
186 186 return (0);
187 187 }
188 188
189 189 int
190 190 _fini(void)
191 191 {
192 192 int err;
193 193
194 194 if ((err = mod_remove(&modlinkage)) != 0)
195 195 return (err);
196 196 ddi_soft_state_fini(&pseudonex_state);
197 197 return (0);
198 198 }
199 199
200 200 int
201 201 _info(struct modinfo *modinfop)
202 202 {
203 203 return (mod_info(&modlinkage, modinfop));
204 204 }
205 205
206 206 /*ARGSUSED*/
207 207 static int
208 208 pseudonex_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
209 209 {
210 210 int instance;
211 211 pseudonex_state_t *pnx_state;
212 212
213 213 switch (cmd) {
214 214 case DDI_ATTACH:
215 215 break;
216 216 case DDI_RESUME:
217 217 return (DDI_SUCCESS);
218 218 default:
219 219 return (DDI_FAILURE);
220 220 }
221 221
222 222 /*
223 223 * Save the devi for this instance in the soft_state data.
224 224 */
225 225 instance = ddi_get_instance(devi);
226 226 if (ddi_soft_state_zalloc(pseudonex_state, instance) != DDI_SUCCESS)
227 227 return (DDI_FAILURE);
228 228 pnx_state = ddi_get_soft_state(pseudonex_state, instance);
229 229 pnx_state->pnx_devi = devi;
230 230
231 231 if (ddi_create_minor_node(devi, "devctl", S_IFCHR, instance,
232 232 DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
233 233 ddi_remove_minor_node(devi, NULL);
234 234 ddi_soft_state_free(pseudonex_state, instance);
235 235 return (DDI_FAILURE);
236 236 }
237 237 ddi_report_dev(devi);
238 238 return (DDI_SUCCESS);
239 239 }
240 240
241 241 /*ARGSUSED*/
242 242 static int
243 243 pseudonex_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
244 244 {
245 245 int instance = ddi_get_instance(devi);
246 246
247 247 if (cmd == DDI_SUSPEND)
248 248 return (DDI_SUCCESS);
249 249
250 250 ddi_remove_minor_node(devi, NULL);
251 251 ddi_soft_state_free(pseudonex_state, instance);
252 252 return (DDI_SUCCESS);
253 253 }
254 254
255 255 /*ARGSUSED*/
256 256 static int
257 257 pseudonex_open(dev_t *devp, int flags, int otyp, cred_t *credp)
258 258 {
259 259 int instance;
260 260
261 261 if (otyp != OTYP_CHR)
262 262 return (EINVAL);
263 263
264 264 instance = getminor(*devp);
265 265 if (ddi_get_soft_state(pseudonex_state, instance) == NULL)
266 266 return (ENXIO);
267 267
268 268 return (0);
269 269 }
270 270
271 271 /*ARGSUSED*/
272 272 static int
273 273 pseudonex_close(dev_t dev, int flags, int otyp, cred_t *credp)
274 274 {
275 275 int instance;
276 276
277 277 if (otyp != OTYP_CHR)
278 278 return (EINVAL);
279 279
280 280 instance = getminor(dev);
281 281 if (ddi_get_soft_state(pseudonex_state, instance) == NULL)
282 282 return (ENXIO);
283 283
284 284 return (0);
285 285 }
286 286
287 287 /*ARGSUSED*/
288 288 static int
289 289 pseudonex_ioctl(dev_t dev,
290 290 int cmd, intptr_t arg, int mode, cred_t *cred_p, int *rval_p)
291 291 {
292 292 int instance;
293 293 pseudonex_state_t *pnx_state;
294 294
295 295 instance = getminor(dev);
296 296 if ((pnx_state = ddi_get_soft_state(pseudonex_state, instance)) == NULL)
297 297 return (ENXIO);
298 298 ASSERT(pnx_state->pnx_devi);
299 299 return (ndi_devctl_ioctl(pnx_state->pnx_devi, cmd, arg, mode, 0));
300 300 }
301 301
302 302 /*
303 303 * pseudonex_intr_op: pseudonex convert an interrupt number to an
304 304 * interrupt. NO OP for pseudo drivers.
305 305 */
306 306 /*ARGSUSED*/
307 307 static int
308 308 pseudonex_intr_op(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t op,
309 309 ddi_intr_handle_impl_t *hdlp, void *result)
310 310 {
311 311 return (DDI_FAILURE);
312 312 }
313 313
314 314 static int
315 315 pseudonex_check_assignment(dev_info_t *child, int test_inst)
316 316 {
317 317 dev_info_t *tdip;
318 318 kmutex_t *dmp;
319 319 const char *childname = ddi_driver_name(child);
320 320 major_t childmaj = ddi_name_to_major((char *)childname);
321 321
322 322 dmp = &devnamesp[childmaj].dn_lock;
323 323 LOCK_DEV_OPS(dmp);
324 324 for (tdip = devnamesp[childmaj].dn_head;
325 325 tdip != NULL; tdip = ddi_get_next(tdip)) {
326 326 /* is this the current node? */
327 327 if (tdip == child)
328 328 continue;
329 329 /* is this a duplicate instance? */
330 330 if (test_inst == ddi_get_instance(tdip)) {
331 331 UNLOCK_DEV_OPS(dmp);
332 332 return (DDI_FAILURE);
333 333 }
334 334 }
335 335 UNLOCK_DEV_OPS(dmp);
336 336 return (DDI_SUCCESS);
337 337 }
338 338
339 339 /*
340 340 * This is a nasty, slow hack. But we're stuck with it until we do some
341 341 * major surgery on the instance assignment subsystem, to allow pseudonode
342 342 * instance assignment to be tracked there.
343 343 *
344 344 * To auto-assign an instance number, we exhaustively search the instance
345 345 * list for each possible instance number until we find one which is unused.
346 346 */
347 347 static int
348 348 pseudonex_auto_assign(dev_info_t *child)
349 349 {
350 350 dev_info_t *tdip;
351 351 kmutex_t *dmp;
352 352 const char *childname = ddi_driver_name(child);
353 353 major_t childmaj = ddi_name_to_major((char *)childname);
354 354 int inst = 0;
355 355
356 356 dmp = &devnamesp[childmaj].dn_lock;
357 357 LOCK_DEV_OPS(dmp);
358 358 for (inst = 0; inst <= MAXMIN32; inst++) {
359 359 for (tdip = devnamesp[childmaj].dn_head; tdip != NULL;
360 360 tdip = ddi_get_next(tdip)) {
361 361 /* is this the current node? */
362 362 if (tdip == child)
363 363 continue;
364 364 if (inst == ddi_get_instance(tdip)) {
365 365 break;
366 366 }
367 367 }
368 368 if (tdip == NULL) {
369 369 UNLOCK_DEV_OPS(dmp);
370 370 return (inst);
371 371 }
372 372 }
373 373 UNLOCK_DEV_OPS(dmp);
374 374 return (-1);
375 375 }
376 376
377 377 static int
378 378 pseudonex_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
379 379 void *arg, void *result)
380 380 {
381 381 switch (ctlop) {
382 382 case DDI_CTLOPS_REPORTDEV:
383 383 if (rdip == NULL)
384 384 return (DDI_FAILURE);
385 385 cmn_err(CE_CONT, "?pseudo-device: %s%d\n",
386 386 ddi_driver_name(rdip), ddi_get_instance(rdip));
387 387 return (DDI_SUCCESS);
388 388
389 389 case DDI_CTLOPS_INITCHILD:
390 390 {
391 391 char name[12]; /* enough for a decimal integer */
392 392 int instance = -1;
393 393 dev_info_t *child = (dev_info_t *)arg;
394 394 const char *childname = ddi_driver_name(child);
395 395 char **childlist;
396 396 uint_t nelems;
397 397 int auto_assign = 0;
398 398
399 399 /*
400 400 * If this pseudonex node has a valid-children property,
401 401 * then that acts as an access control list for children
402 402 * allowed to attach beneath this node. Honor it.
403 403 */
404 404 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip,
405 405 DDI_PROP_DONTPASS, "valid-children", &childlist,
406 406 &nelems) == DDI_PROP_SUCCESS) {
407 407 int i, ok = 0;
408 408 for (i = 0; i < nelems; i++) {
409 409 if (strcmp(childlist[i], childname) == 0) {
410 410 ok = 1;
411 411 break;
412 412 }
413 413 }
414 414 ddi_prop_free(childlist);
415 415 if (!ok)
416 416 return (DDI_FAILURE);
417 417 }
418 418
419 419 /*
420 420 * Look up the "instance" property. If it does not exist,
421 421 * check to see if the "auto-assign-instance" property is set.
422 422 * If not, default to using instance 0; while not ideal, this
423 423 * is a legacy behavior we must continue to support.
424 424 */
425 425 instance = ddi_prop_get_int(DDI_DEV_T_ANY, child,
426 426 DDI_PROP_DONTPASS, "instance", -1);
427 427 auto_assign = ddi_prop_exists(DDI_DEV_T_ANY, child,
428 428 DDI_PROP_DONTPASS, "auto-assign-instance");
429 429 NDI_CONFIG_DEBUG((CE_NOTE,
430 430 "pseudonex: DDI_CTLOPS_INITCHILD(instance=%d, "
431 431 "auto-assign=%d)", instance, auto_assign));
432 432
433 433 if (instance != -1 && auto_assign != 0) {
434 434 NDI_CONFIG_DEBUG((CE_NOTE, "both instance and "
435 435 "auto-assign-instance properties specified. "
436 436 "Node rejected."));
437 437 return (DDI_FAILURE);
438 438 }
439 439
440 440 if (instance == -1 && auto_assign == 0) {
441 441 /* default to instance 0 if not specified */
442 442 NDI_CONFIG_DEBUG((CE_NOTE, "defaulting to 0"));
443 443 instance = 0;
444 444 }
445 445
446 446 /*
447 447 * If an instance has been specified, determine if this
448 448 * instance is already in use; if we need to pick an instance,
449 449 * we do it here.
450 450 */
451 451 if (auto_assign) {
452 452 if ((instance = pseudonex_auto_assign(child)) == -1) {
453 453 NDI_CONFIG_DEBUG((CE_NOTE, "failed to "
454 454 "auto-select instance for %s", childname));
455 455 return (DDI_FAILURE);
456 456 }
457 457 NDI_CONFIG_DEBUG((CE_NOTE,
458 458 "auto-selected instance for %s: %d",
459 459 childname, instance));
460 460 } else {
461 461 if (pseudonex_check_assignment(child, instance) ==
462 462 DDI_FAILURE) {
463 463 NDI_CONFIG_DEBUG((CE_WARN,
464 464 "Duplicate instance %d of node \"%s\" "
465 465 "ignored.", instance, childname));
466 466 return (DDI_FAILURE);
467 467 }
468 468 NDI_CONFIG_DEBUG((CE_NOTE,
469 469 "using fixed-assignment instance for %s: %d",
470 470 childname, instance));
471 471 }
472 472
473 473 /*
474 474 * Attach the instance number to the node. This allows
475 475 * us to have multiple instances of the same pseudo
476 476 * device, they will be named 'device@instance'. If this
477 477 * breaks programs, we may need to special-case instance 0
478 478 * into 'device'. Ick. devlinks appears to handle the
479 479 * new names ok, so if only names in /dev are used
480 480 * this may not be necessary.
481 481 */
482 482 (void) snprintf(name, sizeof (name), "%d", instance);
483 483 DEVI(child)->devi_instance = instance;
484 484 ddi_set_name_addr(child, name);
485 485 return (DDI_SUCCESS);
486 486 }
487 487
488 488 case DDI_CTLOPS_UNINITCHILD:
489 489 {
490 490 dev_info_t *child = (dev_info_t *)arg;
491 491
492 492 NDI_CONFIG_DEBUG((CE_NOTE,
493 493 "DDI_CTLOPS_UNINITCHILD(%s, instance=%d)",
494 494 ddi_driver_name(child), DEVI(child)->devi_instance));
495 495
496 496 ddi_set_name_addr(child, NULL);
497 497
498 498 return (DDI_SUCCESS);
499 499 }
500 500
501 501 case DDI_CTLOPS_DMAPMAPC:
502 502 case DDI_CTLOPS_REPORTINT:
503 503 case DDI_CTLOPS_REGSIZE:
504 504 case DDI_CTLOPS_NREGS:
505 505 case DDI_CTLOPS_SIDDEV:
506 506 case DDI_CTLOPS_SLAVEONLY:
507 507 case DDI_CTLOPS_AFFINITY:
508 508 case DDI_CTLOPS_POKE:
509 509 case DDI_CTLOPS_PEEK:
510 510 /*
511 511 * These ops correspond to functions that "shouldn't" be called
512 512 * by a pseudo driver. So we whine when we're called.
513 513 */
514 514 cmn_err(CE_CONT, "%s%d: invalid op (%d) from %s%d\n",
515 515 ddi_driver_name(dip), ddi_get_instance(dip), ctlop,
516 516 ddi_driver_name(rdip), ddi_get_instance(rdip));
517 517 return (DDI_FAILURE);
518 518
519 519 case DDI_CTLOPS_ATTACH:
520 520 case DDI_CTLOPS_BTOP:
521 521 case DDI_CTLOPS_BTOPR:
522 522 case DDI_CTLOPS_DETACH:
523 523 case DDI_CTLOPS_DVMAPAGESIZE:
524 524 case DDI_CTLOPS_IOMIN:
525 525 case DDI_CTLOPS_POWER:
526 526 case DDI_CTLOPS_PTOB:
527 527 default:
528 528 /*
529 529 * The ops that we pass up (default). We pass up memory
530 530 * allocation oriented ops that we receive - these may be
531 531 * associated with pseudo HBA drivers below us with target
532 532 * drivers below them that use ddi memory allocation
533 533 * interfaces like scsi_alloc_consistent_buf.
534 534 */
535 535 return (ddi_ctlops(dip, rdip, ctlop, arg, result));
536 536 }
537 537 }
↓ open down ↓ |
357 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX