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.
29 * generic character driver
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/errno.h>
36 #include <sys/modctl.h>
40 #include <sys/cmn_err.h>
43 #include <sys/sunddi.h>
44 #include <sys/sunndi.h>
49 #define COMP_0_MAXPWR 3
50 #define COMP_1_MAXPWR 2
52 static int maxpwr
[] = { COMP_0_MAXPWR
, COMP_1_MAXPWR
};
55 * The state for each generic device.
56 * NOTE: We save the node_type in the state structure. The node_type string
57 * (and not a copy) is stashed in a minor node by ddi_create_minor_node(),
58 * so ddi_remove_minor_node() must occur prior to state free.
60 typedef struct dstate
{
62 dev_info_t
*dip
; /* my devinfo handle */
63 char *node_type
; /* stable node_type copy */
64 ddi_callback_id_t gen_cb_ids
[NUMEVENTS
];
67 int level
[COMPONENTS
]; /* pm level */
68 int busy
[COMPONENTS
]; /* busy state */
74 static int gen_debug
= 0;
77 #define gen_debug gen_debug_on
78 static int gen_debug_on
= 0;
79 #define GEN_DEBUG(args) if (gen_debug) cmn_err args
81 #define GEN_DEBUG(args)
84 extern void prom_printf(const char *fmt
, ...);
86 static int gen_open(dev_t
*devp
, int flag
, int otyp
, cred_t
*cred
);
87 static int gen_close(dev_t devp
, int flag
, int otyp
, cred_t
*cred
);
88 static int gen_read(dev_t dev
, struct uio
*uiop
, cred_t
*credp
);
89 static int gen_write(dev_t dev
, struct uio
*uiop
, cred_t
*credp
);
90 static int gen_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
,
91 cred_t
*credp
, int *rvalp
);
92 static int gen_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
);
93 static int gen_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
);
94 static void gen_event_cb(dev_info_t
*dip
, ddi_eventcookie_t cookie
,
95 void *arg
, void *impl_data
);
97 static int gen_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
,
99 static int gen_create_minor_nodes(dev_info_t
*, struct dstate
*);
100 static int gen_power(dev_info_t
*, int, int);
102 static struct cb_ops gen_cb_ops
= {
104 gen_close
, /* close */
105 nodev
, /* strategy */
109 gen_write
, /* write */
110 gen_ioctl
, /* ioctl */
115 ddi_prop_op
, /* prop_op */
116 NULL
, /* streamtab */
117 D_NEW
| D_MP
| D_HOTPLUG
, /* flag */
124 static struct dev_ops gen_ops
= {
125 DEVO_REV
, /* devo_rev */
127 gen_info
, /* getinfo */
128 nulldev
, /* identify */
130 gen_attach
, /* attach */
131 gen_detach
, /* detach */
133 &gen_cb_ops
, /* driver ops */
135 gen_power
, /* power */
136 ddi_quiesce_not_supported
, /* devo_quiesce */
140 * INST_TO_MINOR() gives the starting minor number for a given gen_drv driver
141 * instance. A shift left by 6 bits allows for each instance to have upto
142 * 64 (2^6) minor numbers. The maximum minor number allowed by the system
143 * is L_MAXMIN32 (0x3ffff). This effectively limits the gen_drv instance
144 * numbers from 0 to 0xfff for a total of 4096 instances.
146 #define INST_TO_MINOR(i) (i << 6)
147 #define MINOR_TO_INST(mn) (mn >> 6)
149 static char *mnodetypes
[] = {
151 "ddi_nt:device_type",
152 "ddi_nt:device_class:bus_class",
154 "ddi_nt2:device_type",
155 "ddi_nt2:device_type:bus_class",
157 #define N_NTYPES (sizeof (mnodetypes) / sizeof (char *))
159 static struct modldrv modldrv
= {
161 "generic test driver",
165 static struct modlinkage modlinkage
= {
166 MODREV_1
, &modldrv
, NULL
173 #define OPEN_FLAG 0x001
174 #define PWR_HAS_CHANGED_ON_RESUME_FLAG 0x002
175 #define FAIL_SUSPEND_FLAG 0x004
176 #define PUP_WITH_PWR_HAS_CHANGED_FLAG 0x008
177 #define POWER_FLAG 0x010
178 #define LOWER_POWER_FLAG 0x020
179 #define NO_INVOL_FLAG 0x040
180 #define PM_SUPPORTED_FLAG 0x080
183 * ioctl commands (non-devctl ioctl commands)
185 #define GENDRV_IOCTL ('P' << 8)
186 #define GENDRV_IOFAULT_SIMULATE (GENDRV_IOCTL | 0)
187 #define GENDRV_NDI_EVENT_TEST (GENDRV_IOCTL | 1)
194 if ((e
= ddi_soft_state_init(&dstates
,
195 sizeof (struct dstate
), 0)) != 0) {
199 if ((e
= mod_install(&modlinkage
)) != 0) {
200 ddi_soft_state_fini(&dstates
);
211 if ((e
= mod_remove(&modlinkage
)) != 0) {
214 ddi_soft_state_fini(&dstates
);
219 _info(struct modinfo
*modinfop
)
221 return (mod_info(&modlinkage
, modinfop
));
225 gen_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
227 int instance
= ddi_get_instance(devi
);
228 struct dstate
*dstatep
;
233 ddi_eventcookie_t dev_offline_cookie
, dev_reset_cookie
;
234 ddi_eventcookie_t bus_reset_cookie
, bus_quiesce_cookie
;
235 ddi_eventcookie_t bus_unquiesce_cookie
, bus_test_post_cookie
;
250 char *pm_hw_state
= {"needs-suspend-resume"};
256 if (ddi_soft_state_zalloc(dstates
, instance
) !=
258 cmn_err(CE_CONT
, "%s%d: can't allocate state\n",
259 ddi_get_name(devi
), instance
);
261 return (DDI_FAILURE
);
264 dstatep
= ddi_get_soft_state(dstates
, instance
);
266 mutex_init(&dstatep
->lock
, NULL
, MUTEX_DRIVER
, NULL
);
268 n_devs
= ddi_prop_get_int(DDI_DEV_T_ANY
, devi
, 0,
271 isclone
= ddi_prop_get_int(DDI_DEV_T_ANY
, devi
, 0,
274 n_minorcomps
= ddi_prop_get_int(DDI_DEV_T_ANY
, devi
, 0,
278 "%s%d attaching: n_devs=%d n_minorcomps=%d isclone=%d",
279 ddi_get_name(devi
), ddi_get_instance(devi
),
280 n_devs
, n_minorcomps
, isclone
));
283 if (ddi_create_minor_node(devi
, "gen", S_IFCHR
,
284 INST_TO_MINOR(instance
), mnodetypes
[0],
285 isclone
) != DDI_SUCCESS
) {
286 ddi_remove_minor_node(devi
, NULL
);
287 ddi_soft_state_free(dstates
, instance
);
288 cmn_err(CE_WARN
, "%s%d: can't create minor "
289 "node", ddi_get_name(devi
), instance
);
291 return (DDI_FAILURE
);
295 rval
= gen_create_minor_nodes(devi
, dstatep
);
296 if (rval
!= DDI_SUCCESS
) {
297 ddi_prop_remove_all(devi
);
298 ddi_remove_minor_node(devi
, NULL
);
299 ddi_soft_state_free(dstates
, instance
);
300 cmn_err(CE_WARN
, "%s%d: can't create minor "
301 "nodes", ddi_get_name(devi
), instance
);
303 return (DDI_FAILURE
);
307 if (ddi_get_eventcookie(devi
, "pshot_dev_offline",
308 &dev_offline_cookie
) == DDI_SUCCESS
) {
309 (void) ddi_add_event_handler(devi
, dev_offline_cookie
,
310 gen_event_cb
, NULL
, &(dstatep
->gen_cb_ids
[0]));
313 if (ddi_get_eventcookie(devi
, "pshot_dev_reset",
314 &dev_reset_cookie
) == DDI_SUCCESS
) {
315 (void) ddi_add_event_handler(devi
, dev_reset_cookie
,
316 gen_event_cb
, NULL
, &(dstatep
->gen_cb_ids
[1]));
319 if (ddi_get_eventcookie(devi
, "pshot_bus_reset",
320 &bus_reset_cookie
) == DDI_SUCCESS
) {
321 (void) ddi_add_event_handler(devi
, bus_reset_cookie
,
322 gen_event_cb
, NULL
, &(dstatep
->gen_cb_ids
[2]));
325 if (ddi_get_eventcookie(devi
, "pshot_bus_quiesce",
326 &bus_quiesce_cookie
) == DDI_SUCCESS
) {
327 (void) ddi_add_event_handler(devi
, bus_quiesce_cookie
,
328 gen_event_cb
, NULL
, &(dstatep
->gen_cb_ids
[3]));
331 if (ddi_get_eventcookie(devi
, "pshot_bus_unquiesce",
332 &bus_unquiesce_cookie
) == DDI_SUCCESS
) {
333 (void) ddi_add_event_handler(devi
,
334 bus_unquiesce_cookie
, gen_event_cb
,
335 NULL
, &(dstatep
->gen_cb_ids
[4]));
338 if (ddi_get_eventcookie(devi
, "pshot_bus_test_post",
339 &bus_test_post_cookie
) == DDI_SUCCESS
) {
340 (void) ddi_add_event_handler(devi
,
341 bus_test_post_cookie
, gen_event_cb
,
342 NULL
, &(dstatep
->gen_cb_ids
[5]));
346 * initialize the devices' pm state
348 mutex_enter(&dstatep
->lock
);
349 dstatep
->flag
&= ~OPEN_FLAG
;
350 dstatep
->flag
&= ~PWR_HAS_CHANGED_ON_RESUME_FLAG
;
351 dstatep
->flag
&= ~FAIL_SUSPEND_FLAG
;
352 dstatep
->flag
&= ~PUP_WITH_PWR_HAS_CHANGED_FLAG
;
353 dstatep
->flag
|= LOWER_POWER_FLAG
;
354 dstatep
->flag
&= ~NO_INVOL_FLAG
;
355 dstatep
->flag
|= PM_SUPPORTED_FLAG
;
356 dstatep
->busy
[0] = 0;
357 dstatep
->busy
[1] = 0;
358 dstatep
->level
[0] = -1;
359 dstatep
->level
[1] = -1;
360 mutex_exit(&dstatep
->lock
);
365 dstatep
->nodename
= ddi_node_name(devi
);
368 * Check if the no-involuntary-power-cycles property
369 * was created. Set NO_INVOL_FLAG if so.
371 if (ddi_prop_exists(DDI_DEV_T_ANY
, dstatep
->dip
,
372 (DDI_PROP_DONTPASS
| DDI_PROP_NOTPROM
),
373 "no-involuntary-power-cycles") == 1) {
375 "%s%d: DDI_ATTACH:\n\tno-involuntary-power-cycles"
376 " property was created",
377 ddi_node_name(devi
), ddi_get_instance(devi
)));
378 mutex_enter(&dstatep
->lock
);
379 dstatep
->flag
|= NO_INVOL_FLAG
;
380 mutex_exit(&dstatep
->lock
);
384 * Check if the dependency-property property
387 if (ddi_prop_exists(DDI_DEV_T_ANY
, dstatep
->dip
,
388 (DDI_PROP_DONTPASS
| DDI_PROP_NOTPROM
),
389 "dependency-property") == 1) {
391 "%s%d: DDI_ATTACH:\n\tdependency-property"
392 " property was created",
393 ddi_node_name(devi
), ddi_get_instance(devi
)));
397 * create the pm-components property. two comps:
398 * 4 levels on comp0, 3 on comp 1.
399 * - skip for a "tape" device, clear PM_SUPPORTED_FLAG
401 if (strcmp(ddi_node_name(devi
), "tape") != 0) {
402 if (ddi_prop_update_string_array(DDI_DEV_T_NONE
, devi
,
403 "pm-components", pm_comp
, 9) != DDI_PROP_SUCCESS
) {
404 cmn_err(CE_WARN
, "%s%d: %s\n",
406 ddi_get_instance(devi
),
407 "unable to create \"pm-components\" "
410 return (DDI_FAILURE
);
413 mutex_enter(&dstatep
->lock
);
414 dstatep
->flag
&= ~PM_SUPPORTED_FLAG
;
415 mutex_exit(&dstatep
->lock
);
419 * Check if the pm-components property was created
421 if (dstatep
->flag
& PM_SUPPORTED_FLAG
) {
422 if (ddi_prop_exists(DDI_DEV_T_ANY
, dstatep
->dip
,
423 (DDI_PROP_DONTPASS
| DDI_PROP_NOTPROM
),
424 "pm-components") != 1) {
425 cmn_err(CE_WARN
, "%s%d: DDI_ATTACH:\n\t%s",
427 ddi_get_instance(devi
),
428 "\"pm-components\" property does"
431 return (DDI_FAILURE
);
434 GEN_DEBUG((CE_CONT
, "%s%d: DDI_ATTACH:"
435 " created pm-components property",
437 ddi_get_instance(devi
)));
442 * create the pm-hardware-state property.
443 * needed to get DDI_SUSPEND and DDI_RESUME calls
445 if (ddi_prop_update_string(DDI_DEV_T_NONE
, devi
,
446 "pm-hardware-state", pm_hw_state
) != DDI_PROP_SUCCESS
) {
447 cmn_err(CE_WARN
, "%s%d: DDI_ATTACH:\n\t%s\n",
448 ddi_node_name(devi
), ddi_get_instance(devi
),
449 "unable to create \"pm-hardware-state\" "
452 return (DDI_FAILURE
);
456 * set power levels to max via pm_raise_power(),
458 mutex_enter(&dstatep
->lock
);
459 i_init
= (dstatep
->flag
& PM_SUPPORTED_FLAG
) ? 0 : COMPONENTS
;
460 mutex_exit(&dstatep
->lock
);
461 for (i
= i_init
; i
< COMPONENTS
; i
++) {
463 "%s%d: DDI_ATTACH: pm_raise_power comp %d "
464 "to level %d", ddi_node_name(devi
),
465 ddi_get_instance(devi
), i
, maxpwr
[i
]));
466 if (pm_raise_power(dstatep
->dip
, i
, maxpwr
[i
]) !=
469 "%s%d: DDI_ATTACH: pm_raise_power failed\n",
471 ddi_get_instance(devi
));
472 dstatep
->level
[i
] = -1;
474 return (DDI_FAILURE
);
478 if (rval
== DDI_SUCCESS
) {
479 ddi_report_dev(devi
);
485 GEN_DEBUG((CE_CONT
, "%s%d: DDI_RESUME", ddi_node_name(devi
),
486 ddi_get_instance(devi
)));
488 dstatep
= ddi_get_soft_state(dstates
, ddi_get_instance(devi
));
489 if (dstatep
== NULL
) {
491 return (DDI_FAILURE
);
495 * Call pm_power_has_changed() if flag
496 * PWR_HAS_CHANGED_ON_RESUME_FLAG is set,
497 * then clear the flag
499 mutex_enter(&dstatep
->lock
);
500 i_init
= (dstatep
->flag
& PM_SUPPORTED_FLAG
) ? 0 : COMPONENTS
;
501 mutex_exit(&dstatep
->lock
);
502 if (dstatep
->flag
& PWR_HAS_CHANGED_ON_RESUME_FLAG
) {
503 for (i
= i_init
; i
< COMPONENTS
; i
++) {
505 "%s%d: DDI_RESUME: pm_power_has_changed "
506 "comp %d to level %d", ddi_node_name(devi
),
507 ddi_get_instance(devi
), i
, maxpwr
[i
]));
508 mutex_enter(&dstatep
->lock
);
509 level_tmp
= dstatep
->level
[i
];
510 dstatep
->level
[i
] = maxpwr
[i
];
511 if (pm_power_has_changed(dstatep
->dip
, i
,
512 maxpwr
[i
]) != DDI_SUCCESS
) {
514 "%s%d: DDI_RESUME:\n\t"
515 " pm_power_has_changed"
516 " failed: comp %d to level %d\n",
518 ddi_get_instance(devi
),
520 dstatep
->level
[i
] = level_tmp
;
522 mutex_exit(&dstatep
->lock
);
526 * Call pm_raise_power() instead
528 for (i
= i_init
; i
< COMPONENTS
; i
++) {
530 "%s%d: DDI_RESUME: pm_raise_power"
531 " comp %d to level %d",
532 ddi_node_name(devi
), ddi_get_instance(devi
),
534 if (pm_raise_power(dstatep
->dip
, i
, maxpwr
[i
])
539 "failed: comp %d to level %d\n",
541 ddi_get_instance(devi
),
547 return (DDI_SUCCESS
);
550 GEN_DEBUG((CE_WARN
, "attach: default"));
551 return (DDI_FAILURE
);
556 gen_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
)
558 struct dstate
*dstatep
;
573 GEN_DEBUG((CE_CONT
, "%s%d: DDI_DETACH", ddi_node_name(devi
),
574 ddi_get_instance(devi
)));
576 instance
= ddi_get_instance(devi
);
577 dstatep
= ddi_get_soft_state(dstates
, instance
);
578 if (dstatep
== NULL
) {
580 return (DDI_FAILURE
);
584 n_devs
= ddi_prop_get_int(DDI_DEV_T_ANY
, devi
, 0,
587 isclone
= ddi_prop_get_int(DDI_DEV_T_ANY
, devi
, 0,
590 n_minorcomps
= ddi_prop_get_int(DDI_DEV_T_ANY
, devi
, 0,
595 * power off component 1.
597 if (dstatep
->flag
& PM_SUPPORTED_FLAG
) {
599 "%s%d: DDI_DETACH: pm_lower_power comp 1 level %d",
600 ddi_node_name(devi
), ddi_get_instance(devi
),
602 if (pm_lower_power(dstatep
->dip
, 1, MINPWR
)
604 cmn_err(CE_WARN
, "%s%d: DDI_DETACH:\n\t"
605 "pm_lower_power failed for comp 1 to"
606 " level %d\n", ddi_node_name(devi
),
607 ddi_get_instance(devi
), MINPWR
);
609 return (DDI_FAILURE
);
613 * check power level. Issue pm_power_has_changed
616 mutex_enter(&dstatep
->lock
);
617 level_tmp
= dstatep
->level
[1];
618 dstatep
->level
[1] = MINPWR
;
619 if (dstatep
->level
[1] != MINPWR
) {
620 GEN_DEBUG((CE_NOTE
, "%s%d: DDI_DETACH:"
621 " power off via pm_power_has_changed"
622 " instead", ddi_node_name(devi
),
623 ddi_get_instance(devi
)));
624 if (pm_power_has_changed(dstatep
->dip
,
625 1, MINPWR
) != DDI_SUCCESS
) {
626 GEN_DEBUG((CE_NOTE
, "%s%d: DDI_DETACH:"
627 " pm_power_has_changed failed for"
628 " comp 1 to level %d",
630 ddi_get_instance(devi
),
632 dstatep
->level
[1] = level_tmp
;
633 mutex_exit(&dstatep
->lock
);
635 return (DDI_FAILURE
);
638 mutex_exit(&dstatep
->lock
);
642 * If the LOWER_POWER_FLAG flag is not set,
643 * don't call pm_lowr_power() for comp 0.
644 * This should be used only for the XXXXX@XX,no_invol
645 * devices that export the
646 * no-involuntary-power-cycles property
648 if (!(dstatep
->flag
& LOWER_POWER_FLAG
) &&
649 dstatep
->flag
& PM_SUPPORTED_FLAG
) {
650 cmn_err(CE_NOTE
, "%s%d: DDI_DETACH:\n\t"
651 " NOT CALLING PM_LOWER_POWER():"
652 " LOWER_POWER_FLAG NOT SET\n",
653 ddi_node_name(devi
), ddi_get_instance(devi
));
654 } else if (dstatep
->flag
& PM_SUPPORTED_FLAG
) {
656 "%s%d: DDI_DETACH: pm_lower_power comp 0 level %d",
657 ddi_node_name(devi
), ddi_get_instance(devi
),
659 if (pm_lower_power(dstatep
->dip
, 0, MINPWR
)
661 cmn_err(CE_WARN
, "%s%d: DDI_DETACH:\n\t"
662 "pm_lower_power failed for comp 0 to"
663 " level %d\n", ddi_node_name(devi
),
664 ddi_get_instance(devi
), MINPWR
);
666 return (DDI_FAILURE
);
670 * check power level. Issue pm_power_has_changed
673 mutex_enter(&dstatep
->lock
);
674 level_tmp
= dstatep
->level
[0];
675 dstatep
->level
[0] = MINPWR
;
676 if (dstatep
->level
[0] != MINPWR
) {
677 GEN_DEBUG((CE_NOTE
, "%s%d: DDI_DETACH:"
678 " power off via pm_power_has_changed"
679 " instead", ddi_node_name(devi
),
680 ddi_get_instance(devi
)));
681 if (pm_power_has_changed(dstatep
->dip
,
682 0, MINPWR
) != DDI_SUCCESS
) {
683 GEN_DEBUG((CE_NOTE
, "%s%d: DDI_DETACH:"
684 " pm_power_has_changed failed for"
685 " comp 0 to level %d",
687 ddi_get_instance(devi
),
689 dstatep
->level
[0] = level_tmp
;
690 mutex_exit(&dstatep
->lock
);
692 return (DDI_FAILURE
);
695 mutex_exit(&dstatep
->lock
);
699 "%s%d detaching: n_devs=%d n_minorcomps=%d isclone=%d",
700 ddi_node_name(devi
), ddi_get_instance(devi
),
701 n_devs
, n_minorcomps
, isclone
));
703 for (i
= 0; i
< NUMEVENTS
; i
++) {
704 if (dstatep
->gen_cb_ids
[i
]) {
705 (void) ddi_remove_event_handler(dstatep
->gen_cb_ids
[i
]);
706 dstatep
->gen_cb_ids
[i
] = NULL
;
710 ddi_prop_remove_all(devi
);
711 ddi_remove_minor_node(devi
, NULL
);
712 if (dstatep
->node_type
)
713 kmem_free(dstatep
->node_type
,
714 strlen(dstatep
->node_type
) + 1);
715 ddi_soft_state_free(dstates
, instance
);
716 return (DDI_SUCCESS
);
719 GEN_DEBUG((CE_CONT
, "%s%d: DDI_SUSPEND",
720 ddi_node_name(devi
), ddi_get_instance(devi
)));
722 instance
= ddi_get_instance(devi
);
723 dstatep
= ddi_get_soft_state(dstates
, instance
);
724 if (dstatep
== NULL
) {
726 return (DDI_FAILURE
);
730 * fail the suspend if FAIL_SUSPEND_FLAG is set.
731 * clear the FAIL_SUSPEND_FLAG flag
733 mutex_enter(&dstatep
->lock
);
734 if (dstatep
->flag
& FAIL_SUSPEND_FLAG
) {
735 GEN_DEBUG((CE_CONT
, "%s%d: DDI_SUSPEND:"
736 " FAIL_SUSPEND_FLAG is set,"
738 ddi_node_name(devi
), ddi_get_instance(devi
)));
739 dstatep
->flag
&= ~FAIL_SUSPEND_FLAG
;
744 mutex_exit(&dstatep
->lock
);
747 * Issue ddi_removing_power() to determine if the suspend
748 * was initiated by either CPR or DR. If CPR, the system
749 * will be powered OFF; if this driver has set the
750 * NO_INVOL_FLAG, then refuse to suspend. If DR, power
751 * will not be removed, thus allow the suspend.
753 if (dstatep
->flag
& NO_INVOL_FLAG
&&
754 dstatep
->flag
& PM_SUPPORTED_FLAG
) {
755 GEN_DEBUG((CE_CONT
, "%s%d: DDI_SUSPEND:"
756 " check via ddi_removing_power()",
757 ddi_node_name(devi
), ddi_get_instance(devi
)));
759 rm_power
= ddi_removing_power(dstatep
->dip
);
762 cmn_err(CE_WARN
, "%s%d: DDI_SUSPEND:"
763 " ddi_removing_power() failed\n",
765 ddi_get_instance(devi
));
766 } else if (rm_power
== 1) {
768 * CPR: power will be removed
770 GEN_DEBUG((CE_CONT
, "%s%d: DDI_SUSPEND:\n\t"
771 " CPR: POWER WILL BE REMOVED, THEREFORE"
772 " REFUSE TO SUSPEND", ddi_node_name(devi
),
773 ddi_get_instance(devi
)));
775 } else if (rm_power
== 0) {
777 * DR: power will not be removed
779 GEN_DEBUG((CE_CONT
, "%s%d: DDI_SUSPEND:\n\t"
780 " DR: POWER WILL NOT BE REMOVED, THEREFORE"
781 " ALLOW THE SUSPEND", ddi_node_name(devi
),
782 ddi_get_instance(devi
)));
788 * power OFF via pm_power_has_changed()
790 mutex_enter(&dstatep
->lock
);
791 if (dstatep
->flag
& PM_SUPPORTED_FLAG
&&
792 !(dstatep
->flag
& NO_INVOL_FLAG
)) {
793 level_tmp
= dstatep
->level
[0];
794 dstatep
->level
[0] = MINPWR
;
796 "%s%d: DDI_SUSPEND: pm_power_has_changed comp 0"
797 " level %d", ddi_node_name(devi
),
798 ddi_get_instance(devi
), MINPWR
));
799 if (pm_power_has_changed(dstatep
->dip
, 0, MINPWR
)
801 cmn_err(CE_WARN
, "%s%d: DDI_SUSPEND:\n\t"
802 "pm_power_has_changed failed for comp 0 to"
803 " level %d\n", ddi_node_name(devi
),
804 ddi_get_instance(devi
), MINPWR
);
805 dstatep
->level
[0] = level_tmp
;
806 mutex_exit(&dstatep
->lock
);
808 return (DDI_FAILURE
);
811 mutex_exit(&dstatep
->lock
);
817 return (DDI_FAILURE
);
823 gen_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
, void **result
)
828 if (infocmd
!= DDI_INFO_DEVT2INSTANCE
)
829 return (DDI_FAILURE
);
832 instance
= MINOR_TO_INST(getminor(dev
));
833 *result
= (void *)(uintptr_t)instance
;
834 return (DDI_SUCCESS
);
840 gen_open(dev_t
*devp
, int flag
, int otyp
, cred_t
*cred
)
843 struct dstate
*dstatep
;
845 if (otyp
!= OTYP_BLK
&& otyp
!= OTYP_CHR
)
848 minor
= getminor(*devp
);
849 if ((dstatep
= ddi_get_soft_state(dstates
,
850 MINOR_TO_INST(minor
))) == NULL
)
853 mutex_enter(&dstatep
->lock
);
854 dstatep
->flag
|= OPEN_FLAG
;
855 mutex_exit(&dstatep
->lock
);
859 dstatep
->nodename
, MINOR_TO_INST(minor
)));
866 gen_close(dev_t dev
, int flag
, int otyp
, cred_t
*cred
)
868 struct dstate
*dstatep
;
869 minor_t minor
= getminor(dev
);
871 if (otyp
!= OTYP_BLK
&& otyp
!= OTYP_CHR
)
874 dstatep
= ddi_get_soft_state(dstates
, MINOR_TO_INST(minor
));
879 mutex_enter(&dstatep
->lock
);
880 dstatep
->flag
&= ~OPEN_FLAG
;
881 mutex_exit(&dstatep
->lock
);
885 dstatep
->nodename
, MINOR_TO_INST(minor
)));
892 gen_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
, cred_t
*credp
, int *rvalp
)
894 struct dstate
*dstatep
;
895 ddi_eventcookie_t cookie
;
900 struct devctl_iocdata
*dcp
;
905 instance
= MINOR_TO_INST(getminor(dev
));
906 dstatep
= ddi_get_soft_state(dstates
, instance
);
907 nodename
= dstatep
->nodename
;
913 * read devctl ioctl data
915 if (ndi_dc_allochdl((void *)arg
, &dcp
) != NDI_SUCCESS
)
919 case GENDRV_IOFAULT_SIMULATE
:
920 if (ddi_get_eventcookie(dstatep
->dip
, DDI_DEVI_FAULT_EVENT
,
921 &(cookie
)) != NDI_SUCCESS
)
922 return (DDI_FAILURE
);
924 return (ndi_post_event(dstatep
->dip
, dstatep
->dip
, cookie
,
927 case GENDRV_NDI_EVENT_TEST
:
928 if (ddi_get_eventcookie(dstatep
->dip
, "pshot_dev_offline",
929 &cookie
) == NDI_SUCCESS
) {
930 (void) ndi_post_event(dstatep
->dip
, dstatep
->dip
,
934 if (ddi_get_eventcookie(dstatep
->dip
, "pshot_dev_reset",
935 &cookie
) == NDI_SUCCESS
) {
936 (void) ndi_post_event(dstatep
->dip
, dstatep
->dip
,
940 if (ddi_get_eventcookie(dstatep
->dip
, "pshot_bus_reset",
941 &cookie
) == NDI_SUCCESS
) {
942 (void) ndi_post_event(dstatep
->dip
, dstatep
->dip
,
946 if (ddi_get_eventcookie(dstatep
->dip
, "pshot_bus_quiesce",
947 &cookie
) == NDI_SUCCESS
) {
948 (void) ndi_post_event(dstatep
->dip
, dstatep
->dip
,
952 if (ddi_get_eventcookie(dstatep
->dip
, "pshot_bus_unquiesce",
953 &cookie
) == NDI_SUCCESS
) {
954 (void) ndi_post_event(dstatep
->dip
, dstatep
->dip
,
958 if (ddi_get_eventcookie(dstatep
->dip
, "pshot_bus_test_post",
959 &cookie
) == NDI_SUCCESS
) {
960 (void) ndi_post_event(dstatep
->dip
, dstatep
->dip
,
966 case DEVCTL_PM_PWR_HAS_CHANGED_ON_RESUME
:
968 * Issue pm_power_has_changed() call on DDI_RESUME
970 mutex_enter(&dstatep
->lock
);
971 dstatep
->flag
|= PWR_HAS_CHANGED_ON_RESUME_FLAG
;
972 mutex_exit(&dstatep
->lock
);
973 GEN_DEBUG((CE_CONT
, "%s%d:"
974 " DEVCTL_PM_PWR_HAS_CHANGED_ON_RESUME", nodename
,
979 case DEVCTL_PM_FAIL_SUSPEND
:
981 * Fail the suspend attempt in DDI_SUSPEND
983 mutex_enter(&dstatep
->lock
);
984 dstatep
->flag
|= FAIL_SUSPEND_FLAG
;
985 mutex_exit(&dstatep
->lock
);
986 GEN_DEBUG((CE_CONT
, "%s%d: DEVCTL_PM_FAIL_SUSPEND",
987 nodename
, instance
));
991 case DEVCTL_PM_PUP_WITH_PWR_HAS_CHANGED
:
993 * Use pm_power_has_changed() to power up comp 0 when
994 * enforcing the comp 0 vs comp-not 0 dependency:
995 * Power up comp 0 first, if request for comp-not-0
997 * Else, default to pm_raise_power().
999 mutex_enter(&dstatep
->lock
);
1000 dstatep
->flag
|= PUP_WITH_PWR_HAS_CHANGED_FLAG
;
1001 mutex_exit(&dstatep
->lock
);
1002 GEN_DEBUG((CE_CONT
, "%s%d: DEVCTL_PM_PUP_WITH_PWR_HAS_CHANGED",
1003 nodename
, instance
));
1007 case DEVCTL_PM_BUSY_COMP
:
1009 * mark component 0 busy via a pm_busy_component() call.
1010 * update the busy[] array.
1012 mutex_enter(&dstatep
->lock
);
1014 GEN_DEBUG((CE_CONT
, "%s%d: DEVCTL_PM_BUSY_COMP: comp 0:"
1015 " busy=%d", nodename
, instance
, dstatep
->busy
[0]));
1016 mutex_exit(&dstatep
->lock
);
1017 ret
= pm_busy_component(dstatep
->dip
, 0);
1018 ASSERT(ret
== DDI_SUCCESS
);
1022 case DEVCTL_PM_BUSY_COMP_TEST
:
1024 * test busy state on component 0
1026 mutex_enter(&dstatep
->lock
);
1027 state
= dstatep
->busy
[0];
1028 if (copyout(&state
, dcp
->cpyout_buf
,
1029 sizeof (uint_t
)) != 0) {
1030 cmn_err(CE_WARN
, "%s%d:"
1031 " DEVCTL_PM_BUSY_COMP_TEST: copyout failed\n",
1032 nodename
, instance
);
1035 GEN_DEBUG((CE_CONT
, "%s%d: DEVCTL_PM_BUSY_COMP_TEST:"
1037 nodename
, instance
, state
));
1038 mutex_exit(&dstatep
->lock
);
1042 case DEVCTL_PM_IDLE_COMP
:
1044 * mark component 0 idle via a pm_idle_component() call.
1045 * NOP if dstatep->busy[0] == 0.
1047 mutex_enter(&dstatep
->lock
);
1048 if (dstatep
->busy
[0] > 0) {
1050 GEN_DEBUG((CE_CONT
, "%s%d: DEVCTL_PM_IDLE_COMP:"
1051 " comp 0: busy=%d", nodename
, instance
,
1053 mutex_exit(&dstatep
->lock
);
1054 ret
= pm_idle_component(dstatep
->dip
, 0);
1055 ASSERT(ret
== DDI_SUCCESS
);
1057 mutex_exit(&dstatep
->lock
);
1062 case DEVCTL_PM_PROM_PRINTF
:
1063 (void) prom_printf("%s%d: PROM_PRINTF FROM GEN_DRV\n",
1064 nodename
, instance
);
1068 case DEVCTL_PM_RAISE_PWR
:
1070 * power up both components to MAXPWR via
1071 * pm_raise_power() calls. this ioctl() cmd
1072 * assumes that the current level is 0
1074 for (i
= 0; i
< COMPONENTS
; i
++) {
1075 GEN_DEBUG((CE_CONT
, "%s%d: DEVCTL_PM_RAISE_PWR:"
1076 " comp %d old 0 new %d",
1077 nodename
, instance
, i
, maxpwr
[i
]));
1078 if (pm_raise_power(dstatep
->dip
, 0, maxpwr
[i
])
1086 case DEVCTL_PM_CHANGE_PWR_LOW
:
1088 * power off both components via pm_power_has_changed() calls
1090 for (i
= (COMPONENTS
- 1); i
>= 0; --i
) {
1091 GEN_DEBUG((CE_CONT
, "%s%d: DEVCTL_PM_CHANGE_PWR_LOW:"
1093 nodename
, instance
, i
));
1094 mutex_enter(&dstatep
->lock
);
1095 level_tmp
= dstatep
->level
[i
];
1096 dstatep
->level
[i
] = 0;
1097 if (pm_power_has_changed(dstatep
->dip
, i
, 0)
1099 dstatep
->level
[i
] = level_tmp
;
1102 mutex_exit(&dstatep
->lock
);
1107 case DEVCTL_PM_CHANGE_PWR_HIGH
:
1109 * power up both components to MAXPWR via
1110 * pm_power_has_changed() calls
1112 for (i
= 0; i
< COMPONENTS
; i
++) {
1113 GEN_DEBUG((CE_CONT
, "%s%d: DEVCTL_PM_CHANGE_PWR_HIGH:"
1115 nodename
, instance
, i
, maxpwr
[i
]));
1116 mutex_enter(&dstatep
->lock
);
1117 level_tmp
= dstatep
->level
[i
];
1118 dstatep
->level
[i
] = maxpwr
[i
];
1119 if (pm_power_has_changed(dstatep
->dip
, i
, maxpwr
[i
])
1121 dstatep
->level
[i
] = level_tmp
;
1124 mutex_exit(&dstatep
->lock
);
1129 case DEVCTL_PM_POWER
:
1131 * test if the gen_drv_power() routine has been called,
1134 mutex_enter(&dstatep
->lock
);
1135 state
= (dstatep
->flag
& POWER_FLAG
) ? 1 : 0;
1136 if (copyout(&state
, dcp
->cpyout_buf
,
1137 sizeof (uint_t
)) != 0) {
1138 cmn_err(CE_WARN
, "%s%d: DEVCTL_PM_POWER:"
1139 " copyout failed\n", nodename
, instance
);
1142 GEN_DEBUG((CE_CONT
, "%s%d: %s POWER_FLAG: %d",
1143 nodename
, instance
, "DEVCTL_PM_POWER", state
));
1144 dstatep
->flag
&= ~POWER_FLAG
;
1145 mutex_exit(&dstatep
->lock
);
1148 case DEVCTL_PM_NO_LOWER_POWER
:
1150 * issue to not invoke pm_lower_power() on detach
1152 mutex_enter(&dstatep
->lock
);
1153 dstatep
->flag
&= ~LOWER_POWER_FLAG
;
1154 mutex_exit(&dstatep
->lock
);
1155 GEN_DEBUG((CE_CONT
, "%s%d: DEVCTL_PM_NO_LOWER_POWER",
1156 nodename
, instance
));
1168 gen_read(dev_t dev
, struct uio
*uiop
, cred_t
*credp
)
1175 gen_write(dev_t dev
, struct uio
*uiop
, cred_t
*credp
)
1182 gen_power(dev_info_t
*dip
, int cmpt
, int level
)
1184 struct dstate
*dstatep
;
1185 int instance
= ddi_get_instance(dip
);
1186 char *nodename
= ddi_node_name(dip
);
1189 GEN_DEBUG((CE_CONT
, "%s%d: power: cmpt %d to level %d",
1190 nodename
, instance
, cmpt
, level
));
1192 dstatep
= ddi_get_soft_state(dstates
, instance
);
1193 if (dstatep
== NULL
) {
1195 return (DDI_FAILURE
);
1199 * Keep track of the power levels for both components
1200 * in the dstatep->comp[] array.
1201 * Set comp 0 to full level if non-zero comps
1202 * are being set to a higher, non-zero level.
1205 mutex_enter(&dstatep
->lock
);
1206 dstatep
->level
[cmpt
] = level
;
1207 mutex_exit(&dstatep
->lock
);
1208 } else if (level
> dstatep
->level
[cmpt
] && level
!= 0 &&
1209 dstatep
->level
[0] != COMP_0_MAXPWR
) {
1211 * If component 0 is not at COMP_0_MAXPWR, and component 1
1212 * is being powered ON, invoke pm_raise_power() or
1213 * pm_power_has_changed() based on the
1214 * PUP_WITH_PWR_HAS_CHANGED_FLAG flag.
1215 * PUP_WITH_PWR_HAS_CHANGED_FLAG = FALSE by default, invoking
1218 if (!(dstatep
->flag
& PUP_WITH_PWR_HAS_CHANGED_FLAG
)) {
1220 * first set comp 0 to level COMP_0_MAXPWR
1222 GEN_DEBUG((CE_CONT
, "%s%d: power: "
1223 "pm_raise_power: comp 0 to level %d",
1224 nodename
, instance
, COMP_0_MAXPWR
));
1225 if (pm_raise_power(dip
, 0, COMP_0_MAXPWR
) !=
1228 "%s%d: power: pm_raise_power() "
1229 "failed: comp 0 to level %d\n",
1230 nodename
, instance
, COMP_0_MAXPWR
);
1232 return (DDI_FAILURE
);
1235 mutex_enter(&dstatep
->lock
);
1236 dstatep
->level
[0] = COMP_0_MAXPWR
;
1238 * now set the level on the non-zero comp
1240 dstatep
->level
[cmpt
] = level
;
1241 mutex_exit(&dstatep
->lock
);
1242 GEN_DEBUG((CE_CONT
, "%s%d: power: "
1243 "comp %d to level %d",
1244 nodename
, instance
, cmpt
, level
));
1247 GEN_DEBUG((CE_CONT
, "%s%d: power: "
1248 "pm_power_has_changed: comp 0 to level %d",
1249 nodename
, instance
, COMP_0_MAXPWR
));
1250 mutex_enter(&dstatep
->lock
);
1251 level_tmp
= dstatep
->level
[0];
1252 dstatep
->level
[0] = COMP_0_MAXPWR
;
1253 if (pm_power_has_changed(dip
, 0, COMP_0_MAXPWR
) !=
1256 "%s%d: power: pm_power_has_changed() "
1257 "failed: comp 0 to level %d\n",
1258 nodename
, instance
, COMP_0_MAXPWR
);
1259 dstatep
->level
[0] = level_tmp
;
1262 * now set the level on the non-zero comp
1264 GEN_DEBUG((CE_CONT
, "%s%d: power:"
1265 " pm_power_has_changed: comp %d"
1266 " to level %d", nodename
, instance
,
1268 dstatep
->level
[cmpt
] = level
;
1270 mutex_exit(&dstatep
->lock
);
1273 mutex_enter(&dstatep
->lock
);
1274 dstatep
->level
[cmpt
] = level
;
1275 mutex_exit(&dstatep
->lock
);
1278 return (DDI_SUCCESS
);
1283 * Create properties of various data types for testing devfs events.
1286 gen_create_properties(dev_info_t
*devi
)
1289 int int_array
[] = { 3, 10, 304, 230, 4};
1290 int64_t int64_val
= 20;
1291 int64_t int64_array
[] = { 12, 24, 36, 48};
1292 char *string_val
= "Dev_node_prop";
1293 char *string_array
[] = {"Dev_node_prop:0",
1294 "Dev_node_prop:1", "Dev_node_prop:2", "Dev_node_prop:3"};
1295 uchar_t byte_array
[] = { (uchar_t
)0xaa, (uchar_t
)0x55,
1296 (uchar_t
)0x12, (uchar_t
)0xcd };
1297 char bytes
[] = { (char)0x00, (char)0xef, (char)0xff };
1299 if (ddi_prop_update_int(DDI_DEV_T_NONE
, devi
, "int", int_val
)
1300 != DDI_PROP_SUCCESS
)
1301 return (DDI_FAILURE
);
1303 if (ddi_prop_update_int_array(DDI_DEV_T_NONE
, devi
, "int-array",
1304 int_array
, sizeof (int_array
) / sizeof (int)) != DDI_PROP_SUCCESS
)
1305 return (DDI_FAILURE
);
1307 if (ddi_prop_update_int64(DDI_DEV_T_NONE
, devi
, "int64", int64_val
)
1308 != DDI_PROP_SUCCESS
)
1309 return (DDI_FAILURE
);
1311 if (ddi_prop_update_int64_array(DDI_DEV_T_NONE
, devi
, "int64-array",
1312 int64_array
, sizeof (int64_array
) / sizeof (int64_t))
1313 != DDI_PROP_SUCCESS
)
1314 return (DDI_FAILURE
);
1316 if (ddi_prop_update_string(DDI_DEV_T_NONE
, devi
, "string", string_val
)
1317 != DDI_PROP_SUCCESS
)
1318 return (DDI_FAILURE
);
1320 if (ddi_prop_update_string_array(DDI_DEV_T_NONE
, devi
, "string-array",
1321 string_array
, sizeof (string_array
) / sizeof (char *))
1322 != DDI_PROP_SUCCESS
)
1323 return (DDI_FAILURE
);
1325 if (ddi_prop_create(DDI_DEV_T_NONE
, devi
, DDI_PROP_CANSLEEP
,
1326 "boolean", NULL
, 0) != DDI_PROP_SUCCESS
)
1327 return (DDI_FAILURE
);
1329 if (ddi_prop_update_byte_array(DDI_DEV_T_NONE
, devi
, "byte-array",
1330 byte_array
, sizeof (byte_array
)) != DDI_PROP_SUCCESS
)
1331 return (DDI_FAILURE
);
1333 /* untyped property */
1334 if (ddi_prop_create(DDI_DEV_T_NONE
, devi
, DDI_PROP_CANSLEEP
, "untyped",
1335 (caddr_t
)bytes
, sizeof (bytes
)) != DDI_PROP_SUCCESS
)
1336 return (DDI_FAILURE
);
1338 return (DDI_SUCCESS
);
1341 static struct driver_minor_data
{
1345 } disk_minor_data
[] = {
1354 {"a,raw", 0, S_IFCHR
},
1355 {"b,raw", 1, S_IFCHR
},
1356 {"c,raw", 2, S_IFCHR
},
1357 {"d,raw", 3, S_IFCHR
},
1358 {"e,raw", 4, S_IFCHR
},
1359 {"f,raw", 5, S_IFCHR
},
1360 {"g,raw", 6, S_IFCHR
},
1361 {"h,raw", 7, S_IFCHR
},
1366 static struct driver_serial_minor_data
{
1371 } serial_minor_data
[] = {
1372 {"0", 0, S_IFCHR
, "ddi_serial"},
1373 {"1", 1, S_IFCHR
, "ddi_serial"},
1374 {"0,cu", 2, S_IFCHR
, "ddi_serial:dialout"},
1375 {"1,cu", 3, S_IFCHR
, "ddi_serial:dialout"},
1381 gen_create_display(dev_info_t
*devi
)
1384 int instance
= ddi_get_instance(devi
);
1385 char minor_name
[15];
1387 (void) sprintf(minor_name
, "cgtwenty%d", instance
);
1389 return (ddi_create_minor_node(devi
, minor_name
, S_IFCHR
,
1390 INST_TO_MINOR(instance
), DDI_NT_DISPLAY
, 0));
1394 gen_create_mn_disk_chan(dev_info_t
*devi
)
1396 struct driver_minor_data
*dmdp
;
1397 int instance
= ddi_get_instance(devi
);
1399 if (gen_create_properties(devi
) != DDI_SUCCESS
)
1400 return (DDI_FAILURE
);
1402 for (dmdp
= disk_minor_data
; dmdp
->name
!= NULL
; dmdp
++) {
1403 if (ddi_create_minor_node(devi
, dmdp
->name
, dmdp
->type
,
1404 (INST_TO_MINOR(instance
)) | dmdp
->minor
,
1405 DDI_NT_BLOCK_CHAN
, 0) != DDI_SUCCESS
) {
1407 return (DDI_FAILURE
);
1410 return (DDI_SUCCESS
);
1420 if (*s
>= '0' && *s
<= '9')
1424 val
= (val
* 10) + digit
;
1431 gen_create_mn_disk_wwn(dev_info_t
*devi
)
1433 struct driver_minor_data
*dmdp
;
1434 int instance
= ddi_get_instance(devi
);
1435 char *address
= ddi_get_name_addr(devi
);
1438 if (address
[0] >= '0' && address
[0] <= '9' &&
1439 strchr(address
, ',')) {
1440 target
= atod(address
);
1441 address
= strchr(address
, ',');
1442 lun
= atod(++address
);
1443 } else { /* this hack is for rm_stale_link() testing */
1448 if (ddi_prop_create(DDI_DEV_T_NONE
, devi
, DDI_PROP_CANSLEEP
,
1449 "target", (caddr_t
)&target
, sizeof (int))
1450 != DDI_PROP_SUCCESS
) {
1451 return (DDI_FAILURE
);
1453 if (ddi_prop_create(DDI_DEV_T_NONE
, devi
, DDI_PROP_CANSLEEP
,
1454 "lun", (caddr_t
)&lun
, sizeof (int))
1455 != DDI_PROP_SUCCESS
) {
1456 return (DDI_FAILURE
);
1459 for (dmdp
= disk_minor_data
; dmdp
->name
!= NULL
; dmdp
++) {
1460 if (ddi_create_minor_node(devi
, dmdp
->name
, dmdp
->type
,
1461 (INST_TO_MINOR(instance
)) | dmdp
->minor
,
1462 DDI_NT_BLOCK_WWN
, 0) != DDI_SUCCESS
) {
1464 return (DDI_FAILURE
);
1467 return (DDI_SUCCESS
);
1471 gen_create_mn_disk_cdrom(dev_info_t
*devi
)
1473 struct driver_minor_data
*dmdp
;
1474 int instance
= ddi_get_instance(devi
);
1476 for (dmdp
= disk_minor_data
; dmdp
->name
!= NULL
; dmdp
++) {
1477 if (ddi_create_minor_node(devi
, dmdp
->name
, dmdp
->type
,
1478 (INST_TO_MINOR(instance
)) | dmdp
->minor
,
1479 DDI_NT_CD_CHAN
, 0) != DDI_SUCCESS
) {
1481 return (DDI_FAILURE
);
1484 return (DDI_SUCCESS
);
1488 gen_create_mn_disk_fd(dev_info_t
*devi
)
1490 struct driver_minor_data
*dmdp
;
1491 int instance
= ddi_get_instance(devi
);
1493 for (dmdp
= disk_minor_data
; dmdp
->name
!= NULL
; dmdp
++) {
1494 if (ddi_create_minor_node(devi
, dmdp
->name
, dmdp
->type
,
1495 (INST_TO_MINOR(instance
)) | dmdp
->minor
,
1496 DDI_NT_BLOCK_CHAN
, 0) != DDI_SUCCESS
) {
1498 return (DDI_FAILURE
);
1501 return (DDI_SUCCESS
);
1505 gen_create_serial(dev_info_t
*devi
)
1507 struct driver_serial_minor_data
*dmdp
;
1508 int instance
= ddi_get_instance(devi
);
1510 for (dmdp
= serial_minor_data
; dmdp
->name
!= NULL
; dmdp
++) {
1511 if (ddi_create_minor_node(devi
, dmdp
->name
, dmdp
->type
,
1512 (INST_TO_MINOR(instance
)) | dmdp
->minor
,
1513 dmdp
->node_type
, 0) != DDI_SUCCESS
) {
1515 return (DDI_FAILURE
);
1518 return (DDI_SUCCESS
);
1522 gen_create_net(dev_info_t
*devi
)
1524 int instance
= ddi_get_instance(devi
);
1527 if (gen_create_properties(devi
) != DDI_SUCCESS
)
1528 return (DDI_FAILURE
);
1530 (void) snprintf(minorname
, sizeof (minorname
), "gen_drv%d", instance
);
1531 return (ddi_create_minor_node(devi
, minorname
, S_IFCHR
,
1532 INST_TO_MINOR(instance
), DDI_NT_NET
, 0));
1536 gen_create_minor_nodes(dev_info_t
*devi
, struct dstate
*dstatep
)
1538 int rval
= DDI_SUCCESS
;
1541 node_name
= ddi_node_name(devi
);
1543 if (strcmp(node_name
, "disk_chan") == 0) {
1544 rval
= gen_create_mn_disk_chan(devi
);
1545 } else if (strcmp(node_name
, "disk_wwn") == 0) {
1546 rval
= gen_create_mn_disk_wwn(devi
);
1547 } else if (strcmp(node_name
, "disk_cdrom") == 0) {
1548 rval
= gen_create_mn_disk_cdrom(devi
);
1549 } else if (strcmp(node_name
, "disk_fd") == 0) {
1550 rval
= gen_create_mn_disk_fd(devi
);
1551 } else if (strcmp(node_name
, "cgtwenty") == 0) {
1552 rval
= gen_create_display(devi
);
1553 } else if (strcmp(node_name
, "genzs") == 0) {
1554 rval
= gen_create_serial(devi
);
1555 } else if (strcmp(node_name
, "net") == 0) {
1556 rval
= gen_create_net(devi
);
1558 int instance
= ddi_get_instance(devi
);
1562 * Solaris may directly hang the node_type off the minor node
1563 * (without making a copy). Since we free the node_type
1564 * property below we need to make a private copy to pass
1565 * to ddi_create_minor_node to avoid devinfo snapshot panics.
1566 * We store a pointer to our copy in dstate and free it in
1567 * gen_detach after the minor nodes have been deleted by
1568 * ddi_remove_minor_node.
1570 if (ddi_prop_lookup_string(DDI_DEV_T_ANY
, devi
,
1571 DDI_PROP_DONTPASS
, "node-type", &node_type
) != 0) {
1572 cmn_err(CE_WARN
, "couldn't get node-type\n");
1573 return (DDI_FAILURE
);
1576 dstatep
->node_type
= kmem_alloc(
1577 strlen(node_type
) + 1, KM_SLEEP
);
1578 (void) strcpy(dstatep
->node_type
, node_type
);
1580 ddi_prop_free(node_type
);
1582 /* the minor name is the same as the node name */
1583 if (ddi_create_minor_node(devi
, node_name
, S_IFCHR
,
1584 (INST_TO_MINOR(instance
)), dstatep
->node_type
, 0) !=
1586 if (dstatep
->node_type
) {
1587 kmem_free(dstatep
->node_type
,
1588 strlen(dstatep
->node_type
) + 1);
1589 dstatep
->node_type
= NULL
;
1591 return (DDI_FAILURE
);
1593 return (DDI_SUCCESS
);
1596 if (rval
!= DDI_SUCCESS
) {
1597 ddi_prop_remove_all(devi
);
1598 ddi_remove_minor_node(devi
, NULL
);
1606 gen_event_cb(dev_info_t
*dip
, ddi_eventcookie_t cookie
, void *arg
,
1610 cmn_err(CE_NOTE
, "gen_event_cb invoked");