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]
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 * Copyright (c) 2010, Intel Corporation.
28 * All rights reserved.
32 * PIM-DR layer of DR driver. Provides interface between user
33 * level applications and the PSM-DR layer.
37 #include <sys/debug.h>
38 #include <sys/types.h>
39 #include <sys/errno.h>
41 #include <sys/dditypes.h>
42 #include <sys/devops.h>
43 #include <sys/modctl.h>
47 #include <sys/sunddi.h>
48 #include <sys/sunndi.h>
51 #include <sys/processor.h>
52 #include <sys/cpuvar.h>
53 #include <sys/mem_config.h>
55 #include <sys/autoconf.h>
56 #include <sys/cmn_err.h>
58 #include <sys/ddi_impldefs.h>
59 #include <sys/promif.h>
60 #include <sys/machsystm.h>
63 #include <sys/drmach.h>
64 #include <sys/dr_util.h>
68 extern struct memlist
*phys_install
;
71 uint_t dr_debug
= 0; /* dr.h for bit values */
74 static int dr_dev_type_to_nt(char *);
77 * NOTE: state_str, nt_str and SBD_CMD_STR are only used in a debug
78 * kernel. They are, however, referenced during both debug and non-debug
82 static char *state_str
[] = {
83 "EMPTY", "OCCUPIED", "CONNECTED", "UNCONFIGURED",
84 "PARTIAL", "CONFIGURED", "RELEASE", "UNREFERENCED",
88 #define SBD_CMD_STR(c) \
89 (((c) == SBD_CMD_ASSIGN) ? "ASSIGN" : \
90 ((c) == SBD_CMD_UNASSIGN) ? "UNASSIGN" : \
91 ((c) == SBD_CMD_POWERON) ? "POWERON" : \
92 ((c) == SBD_CMD_POWEROFF) ? "POWEROFF" : \
93 ((c) == SBD_CMD_TEST) ? "TEST" : \
94 ((c) == SBD_CMD_CONNECT) ? "CONNECT" : \
95 ((c) == SBD_CMD_DISCONNECT) ? "DISCONNECT" : \
96 ((c) == SBD_CMD_CONFIGURE) ? "CONFIGURE" : \
97 ((c) == SBD_CMD_UNCONFIGURE) ? "UNCONFIGURE" : \
98 ((c) == SBD_CMD_GETNCM) ? "GETNCM" : \
99 ((c) == SBD_CMD_PASSTHRU) ? "PASSTHRU" : \
100 ((c) == SBD_CMD_STATUS) ? "STATUS" : "unknown")
102 #define DR_GET_BOARD_DEVUNIT(sb, ut, un) (&((sb)->b_dev[DEVSET_NIX(ut)][un]))
104 #define DR_MAKE_MINOR(i, b) (((i) << 16) | (b))
105 #define DR_MINOR2INST(m) (((m) >> 16) & 0xffff)
106 #define DR_MINOR2BNUM(m) ((m) & 0xffff)
108 /* for the DR*INTERNAL_ERROR macros. see sys/dr.h. */
109 static char *dr_ie_fmt
= "dr.c %d";
111 /* struct for drmach device name to sbd_comp_type_t mapping */
114 sbd_comp_type_t s_nodetype
;
117 /* struct to map starfire device attributes - name:sbd_comp_type_t */
118 static dr_devname_t dr_devattr
[] = {
119 { DRMACH_DEVTYPE_MEM
, SBD_COMP_MEM
},
120 { DRMACH_DEVTYPE_CPU
, SBD_COMP_CPU
},
121 { DRMACH_DEVTYPE_PCI
, SBD_COMP_IO
},
122 #if defined(DRMACH_DEVTYPE_SBUS)
123 { DRMACH_DEVTYPE_SBUS
, SBD_COMP_IO
},
125 #if defined(DRMACH_DEVTYPE_WCI)
126 { DRMACH_DEVTYPE_WCI
, SBD_COMP_IO
},
128 /* last s_devtype must be NULL, s_nodetype must be SBD_COMP_UNKNOWN */
129 { NULL
, SBD_COMP_UNKNOWN
}
133 * Per instance soft-state structure.
135 typedef struct dr_softstate
{
143 * dr Global data elements
146 dr_softstate_t
*softsp
; /* pointer to initialize soft state */
150 dr_unsafe_devs_t dr_unsafe_devs
;
153 * Table of known passthru commands.
157 int (*pt_func
)(dr_handle_t
*);
159 "quiesce", dr_pt_test_suspend
,
162 int dr_modunload_okay
= 0; /* set to non-zero to allow unload */
165 * State transition table. States valid transitions for "board" state.
166 * Recall that non-zero return value terminates operation, however
167 * the herrno value is what really indicates an error , if any.
173 * Translate DR CMD to index into dr_state_transition.
176 case SBD_CMD_CONNECT
: return (0);
177 case SBD_CMD_DISCONNECT
: return (1);
178 case SBD_CMD_CONFIGURE
: return (2);
179 case SBD_CMD_UNCONFIGURE
: return (3);
180 case SBD_CMD_ASSIGN
: return (4);
181 case SBD_CMD_UNASSIGN
: return (5);
182 case SBD_CMD_POWERON
: return (6);
183 case SBD_CMD_POWEROFF
: return (7);
184 case SBD_CMD_TEST
: return (8);
185 default: return (-1);
189 #define CMD2INDEX(c) _cmd2index(c)
191 static struct dr_state_trans
{
194 int x_rv
; /* return value of pre_op */
195 int x_err
; /* error, if any */
196 } x_op
[DR_STATE_MAX
];
197 } dr_state_transition
[] = {
200 { 0, 0 }, /* empty */
201 { 0, 0 }, /* occupied */
202 { -1, ESBD_STATE
}, /* connected */
203 { -1, ESBD_STATE
}, /* unconfigured */
204 { -1, ESBD_STATE
}, /* partial */
205 { -1, ESBD_STATE
}, /* configured */
206 { -1, ESBD_STATE
}, /* release */
207 { -1, ESBD_STATE
}, /* unreferenced */
208 { -1, ESBD_FATAL_STATE
}, /* fatal */
211 { SBD_CMD_DISCONNECT
,
213 { -1, ESBD_STATE
}, /* empty */
214 { 0, 0 }, /* occupied */
215 { 0, 0 }, /* connected */
216 { 0, 0 }, /* unconfigured */
217 { -1, ESBD_STATE
}, /* partial */
218 { -1, ESBD_STATE
}, /* configured */
219 { -1, ESBD_STATE
}, /* release */
220 { -1, ESBD_STATE
}, /* unreferenced */
221 { -1, ESBD_FATAL_STATE
}, /* fatal */
226 { -1, ESBD_STATE
}, /* empty */
227 { -1, ESBD_STATE
}, /* occupied */
228 { 0, 0 }, /* connected */
229 { 0, 0 }, /* unconfigured */
230 { 0, 0 }, /* partial */
231 { 0, 0 }, /* configured */
232 { -1, ESBD_STATE
}, /* release */
233 { -1, ESBD_STATE
}, /* unreferenced */
234 { -1, ESBD_FATAL_STATE
}, /* fatal */
237 { SBD_CMD_UNCONFIGURE
,
239 { -1, ESBD_STATE
}, /* empty */
240 { -1, ESBD_STATE
}, /* occupied */
241 { -1, ESBD_STATE
}, /* connected */
242 { -1, ESBD_STATE
}, /* unconfigured */
243 { 0, 0 }, /* partial */
244 { 0, 0 }, /* configured */
245 { 0, 0 }, /* release */
246 { 0, 0 }, /* unreferenced */
247 { -1, ESBD_FATAL_STATE
}, /* fatal */
252 { 0, 0 }, /* empty */
253 { 0, 0 }, /* occupied */
254 { -1, ESBD_STATE
}, /* connected */
255 { -1, ESBD_STATE
}, /* unconfigured */
256 { -1, ESBD_STATE
}, /* partial */
257 { -1, ESBD_STATE
}, /* configured */
258 { -1, ESBD_STATE
}, /* release */
259 { -1, ESBD_STATE
}, /* unreferenced */
260 { -1, ESBD_FATAL_STATE
}, /* fatal */
265 { 0, 0 }, /* empty */
266 { 0, 0 }, /* occupied */
267 { -1, ESBD_STATE
}, /* connected */
268 { -1, ESBD_STATE
}, /* unconfigured */
269 { -1, ESBD_STATE
}, /* partial */
270 { -1, ESBD_STATE
}, /* configured */
271 { -1, ESBD_STATE
}, /* release */
272 { -1, ESBD_STATE
}, /* unreferenced */
273 { -1, ESBD_FATAL_STATE
}, /* fatal */
278 { 0, 0 }, /* empty */
279 { 0, 0 }, /* occupied */
280 { -1, ESBD_STATE
}, /* connected */
281 { -1, ESBD_STATE
}, /* unconfigured */
282 { -1, ESBD_STATE
}, /* partial */
283 { -1, ESBD_STATE
}, /* configured */
284 { -1, ESBD_STATE
}, /* release */
285 { -1, ESBD_STATE
}, /* unreferenced */
286 { -1, ESBD_FATAL_STATE
}, /* fatal */
291 { 0, 0 }, /* empty */
292 { 0, 0 }, /* occupied */
293 { -1, ESBD_STATE
}, /* connected */
294 { -1, ESBD_STATE
}, /* unconfigured */
295 { -1, ESBD_STATE
}, /* partial */
296 { -1, ESBD_STATE
}, /* configured */
297 { -1, ESBD_STATE
}, /* release */
298 { -1, ESBD_STATE
}, /* unreferenced */
299 { -1, ESBD_FATAL_STATE
}, /* fatal */
304 { 0, 0 }, /* empty */
305 { 0, 0 }, /* occupied */
306 { -1, ESBD_STATE
}, /* connected */
307 { -1, ESBD_STATE
}, /* unconfigured */
308 { -1, ESBD_STATE
}, /* partial */
309 { -1, ESBD_STATE
}, /* configured */
310 { -1, ESBD_STATE
}, /* release */
311 { -1, ESBD_STATE
}, /* unreferenced */
312 { -1, ESBD_FATAL_STATE
}, /* fatal */
318 * Global R/W lock to synchronize access across
319 * multiple boards. Users wanting multi-board access
320 * must grab WRITE lock, others must grab READ lock.
322 krwlock_t dr_grwlock
;
325 * Head of the boardlist used as a reference point for
326 * locating board structs.
327 * TODO: eliminate dr_boardlist
329 dr_board_t
*dr_boardlist
;
332 * DR support functions.
334 static dr_devset_t
dr_dev2devset(sbd_comp_id_t
*cid
);
335 static int dr_check_transition(dr_board_t
*bp
,
336 dr_devset_t
*devsetp
,
337 struct dr_state_trans
*transp
,
339 static int dr_check_unit_attached(dr_common_unit_t
*dp
);
340 static sbd_error_t
*dr_init_devlists(dr_board_t
*bp
);
341 static void dr_board_discovery(dr_board_t
*bp
);
342 static int dr_board_init(dr_board_t
*bp
, dev_info_t
*dip
, int bd
);
343 static void dr_board_destroy(dr_board_t
*bp
);
344 static void dr_board_transition(dr_board_t
*bp
, dr_state_t st
);
347 * DR driver (DDI) entry points.
349 static int dr_getinfo(dev_info_t
*dip
, ddi_info_cmd_t cmd
,
350 void *arg
, void **result
);
351 static int dr_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
);
352 static int dr_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
);
353 static int dr_probe(dev_info_t
*dip
);
354 static int dr_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
,
355 cred_t
*cred_p
, int *rval_p
);
356 static int dr_close(dev_t dev
, int flag
, int otyp
, cred_t
*cred_p
);
357 static int dr_open(dev_t
*dev
, int flag
, int otyp
, cred_t
*cred_p
);
360 * DR command processing operations.
362 static int dr_copyin_iocmd(dr_handle_t
*hp
);
363 static int dr_copyout_iocmd(dr_handle_t
*hp
);
364 static int dr_copyout_errs(dr_handle_t
*hp
);
365 static int dr_pre_op(dr_handle_t
*hp
);
366 static int dr_post_op(dr_handle_t
*hp
, int rv
);
367 static int dr_exec_op(dr_handle_t
*hp
);
368 static void dr_assign_board(dr_handle_t
*hp
);
369 static void dr_unassign_board(dr_handle_t
*hp
);
370 static void dr_connect(dr_handle_t
*hp
);
371 static int dr_disconnect(dr_handle_t
*hp
);
372 static void dr_dev_configure(dr_handle_t
*hp
);
373 static void dr_dev_release(dr_handle_t
*hp
);
374 static int dr_dev_unconfigure(dr_handle_t
*hp
);
375 static void dr_dev_cancel(dr_handle_t
*hp
);
376 static int dr_dev_status(dr_handle_t
*hp
);
377 static int dr_get_ncm(dr_handle_t
*hp
);
378 static int dr_pt_ioctl(dr_handle_t
*hp
);
379 static void dr_poweron_board(dr_handle_t
*hp
);
380 static void dr_poweroff_board(dr_handle_t
*hp
);
381 static void dr_test_board(dr_handle_t
*hp
);
384 * Autoconfiguration data structures
386 struct cb_ops dr_cb_ops
= {
388 dr_close
, /* close */
389 nodev
, /* strategy */
394 dr_ioctl
, /* ioctl */
398 nochpoll
, /* chpoll */
399 ddi_prop_op
, /* cb_prop_op */
400 NULL
, /* struct streamtab */
401 D_NEW
| D_MP
| D_MTSAFE
, /* compatibility flags */
403 nodev
, /* cb_aread */
404 nodev
/* cb_awrite */
407 struct dev_ops dr_dev_ops
= {
408 DEVO_REV
, /* build version */
409 0, /* dev ref count */
410 dr_getinfo
, /* getinfo */
411 nulldev
, /* identify */
412 dr_probe
, /* probe */
413 dr_attach
, /* attach */
414 dr_detach
, /* detach */
416 &dr_cb_ops
, /* cb_ops */
419 ddi_quiesce_not_needed
, /* quiesce */
422 extern struct mod_ops mod_driverops
;
424 static struct modldrv modldrv
= {
426 "Dynamic Reconfiguration",
430 static struct modlinkage modlinkage
= {
437 * Driver entry points.
445 * If you need to support multiple nodes (instances), then
446 * whatever the maximum number of supported nodes is would
447 * need to passed as the third parameter to ddi_soft_state_init().
448 * Alternative would be to dynamically fini and re-init the
449 * soft state structure each time a node is attached.
451 err
= ddi_soft_state_init((void **)&dr_g
.softsp
,
452 sizeof (dr_softstate_t
), 1);
456 mutex_init(&dr_g
.lock
, NULL
, MUTEX_DRIVER
, NULL
);
457 rw_init(&dr_grwlock
, NULL
, RW_DEFAULT
, NULL
);
459 return (mod_install(&modlinkage
));
467 if ((err
= mod_remove(&modlinkage
)) != 0)
470 mutex_destroy(&dr_g
.lock
);
471 rw_destroy(&dr_grwlock
);
473 ddi_soft_state_fini((void **)&dr_g
.softsp
);
479 _info(struct modinfo
*modinfop
)
481 return (mod_info(&modlinkage
, modinfop
));
486 dr_open(dev_t
*dev
, int flag
, int otyp
, cred_t
*cred_p
)
489 dr_softstate_t
*softsp
;
493 * Don't open unless we've attached.
495 instance
= DR_MINOR2INST(getminor(*dev
));
496 softsp
= ddi_get_soft_state(dr_g
.softsp
, instance
);
500 mutex_enter(&softsp
->i_lock
);
501 if (!softsp
->dr_initialized
) {
507 /* initialize each array element */
508 for (bd
= 0; bd
< MAX_BOARDS
; bd
++, bp
++) {
509 rv
= dr_board_init(bp
, softsp
->dip
, bd
);
515 softsp
->dr_initialized
= 1;
517 /* destroy elements initialized thus far */
518 while (--bp
>= softsp
->boards
)
519 dr_board_destroy(bp
);
521 /* TODO: should this be another errno val ? */
522 mutex_exit(&softsp
->i_lock
);
526 mutex_exit(&softsp
->i_lock
);
528 bp
= &softsp
->boards
[DR_MINOR2BNUM(getminor(*dev
))];
531 * prevent opening of a dyn-ap for a board
532 * that does not exist
534 if (!bp
->b_assigned
) {
535 if (drmach_board_lookup(bp
->b_num
, &bp
->b_id
) != 0)
544 dr_close(dev_t dev
, int flag
, int otyp
, cred_t
*cred_p
)
550 * Enable/disable DR features.
556 dr_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
,
557 cred_t
*cred_p
, int *rval_p
)
563 dr_softstate_t
*softsp
;
564 static fn_t f
= "dr_ioctl";
566 PR_ALL("%s...\n", f
);
568 instance
= DR_MINOR2INST(getminor(dev
));
569 softsp
= ddi_get_soft_state(dr_g
.softsp
, instance
);
570 if (softsp
== NULL
) {
571 cmn_err(CE_WARN
, "dr%d: module not yet attached", instance
);
579 case SBD_CMD_PASSTHRU
:
586 bd
= DR_MINOR2BNUM(getminor(dev
));
587 if (bd
>= MAX_BOARDS
)
590 /* get and initialize storage for new handle */
591 hp
= GETSTRUCT(dr_handle_t
, 1);
592 hp
->h_bd
= &softsp
->boards
[bd
];
594 hp
->h_dev
= getminor(dev
);
597 hp
->h_iap
= (sbd_ioctl_arg_t
*)arg
;
599 /* copy sbd command into handle */
600 rv
= dr_copyin_iocmd(hp
);
602 FREESTRUCT(hp
, dr_handle_t
, 1);
606 /* translate canonical name to component type */
607 if (hp
->h_sbdcmd
.cmd_cm
.c_id
.c_name
[0] != '\0') {
608 hp
->h_sbdcmd
.cmd_cm
.c_id
.c_type
=
609 dr_dev_type_to_nt(hp
->h_sbdcmd
.cmd_cm
.c_id
.c_name
);
611 PR_ALL("%s: c_name = %s, c_type = %d\n",
613 hp
->h_sbdcmd
.cmd_cm
.c_id
.c_name
,
614 hp
->h_sbdcmd
.cmd_cm
.c_id
.c_type
);
617 PR_ALL("%s: c_name is NULL\n", f
);
620 /* determine scope of operation */
621 hp
->h_devset
= dr_dev2devset(&hp
->h_sbdcmd
.cmd_cm
.c_id
);
626 /* no locks needed for these commands */
630 rw_enter(&dr_grwlock
, RW_WRITER
);
631 mutex_enter(&hp
->h_bd
->b_lock
);
634 * If we're dealing with memory at all, then we have
635 * to keep the "exclusive" global lock held. This is
636 * necessary since we will probably need to look at
637 * multiple board structs. Otherwise, we only have
638 * to deal with the board in question and so can drop
639 * the global lock to "shared".
641 rv
= DEVSET_IN_SET(hp
->h_devset
, SBD_COMP_MEM
, DEVSET_ANYUNIT
);
643 rw_downgrade(&dr_grwlock
);
652 rv
= dr_post_op(hp
, rv
);
658 if (hp
->h_err
!= NULL
)
659 if (!(rv
= dr_copyout_errs(hp
)))
662 /* undo locking, if any, done before dr_pre_op */
669 case SBD_CMD_UNASSIGN
:
670 case SBD_CMD_POWERON
:
671 case SBD_CMD_POWEROFF
:
672 case SBD_CMD_CONNECT
:
673 case SBD_CMD_CONFIGURE
:
674 case SBD_CMD_UNCONFIGURE
:
675 case SBD_CMD_DISCONNECT
:
676 /* Board changed state. Log a sysevent. */
678 (void) drmach_log_sysevent(hp
->h_bd
->b_num
, "",
683 mutex_exit(&hp
->h_bd
->b_lock
);
684 rw_exit(&dr_grwlock
);
687 if (hp
->h_opts
.size
!= 0)
688 FREESTRUCT(hp
->h_opts
.copts
, char, hp
->h_opts
.size
);
690 FREESTRUCT(hp
, dr_handle_t
, 1);
697 dr_probe(dev_info_t
*dip
)
699 return (DDI_PROBE_SUCCESS
);
703 dr_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
709 dr_softstate_t
*softsp
;
711 instance
= ddi_get_instance(dip
);
715 rw_enter(&dr_grwlock
, RW_WRITER
);
717 rv
= ddi_soft_state_zalloc(dr_g
.softsp
, instance
);
718 if (rv
!= DDI_SUCCESS
) {
719 cmn_err(CE_WARN
, "dr%d: failed to alloc soft-state",
721 return (DDI_FAILURE
);
724 /* initialize softstate structure */
725 softsp
= ddi_get_soft_state(dr_g
.softsp
, instance
);
728 mutex_init(&softsp
->i_lock
, NULL
, MUTEX_DRIVER
, NULL
);
730 /* allocate board array (aka boardlist) */
731 softsp
->boards
= GETSTRUCT(dr_board_t
, MAX_BOARDS
);
733 /* TODO: eliminate dr_boardlist */
734 dr_boardlist
= softsp
->boards
;
736 /* initialize each array element */
738 for (bd
= 0; bd
< MAX_BOARDS
; bd
++) {
739 dr_board_t
*bp
= &softsp
->boards
[bd
];
744 * initialized board attachment point path
745 * (relative to pseudo) in a form immediately
746 * reusable as an cfgadm command argument.
747 * TODO: clean this up
750 l
= sizeof (bp
->b_path
);
751 (void) snprintf(p
, l
, "dr@%d:", instance
);
758 err
= drmach_board_name(bd
, p
, l
);
765 minor_num
= DR_MAKE_MINOR(instance
, bd
);
766 rv
= ddi_create_minor_node(dip
, name
, S_IFCHR
,
767 minor_num
, DDI_NT_SBD_ATTACHMENT_POINT
, 0);
768 if (rv
!= DDI_SUCCESS
)
772 if (rv
== DDI_SUCCESS
) {
774 * Announce the node's presence.
778 ddi_remove_minor_node(dip
, NULL
);
781 * Init registered unsafe devs.
783 dr_unsafe_devs
.devnames
= NULL
;
784 rv2
= ddi_prop_lookup_string_array(DDI_DEV_T_ANY
, dip
,
785 DDI_PROP_DONTPASS
| DDI_PROP_NOTPROM
,
786 "unsupported-io-drivers", &dr_unsafe_devs
.devnames
,
787 &dr_unsafe_devs
.ndevs
);
789 if (rv2
!= DDI_PROP_SUCCESS
)
790 dr_unsafe_devs
.ndevs
= 0;
792 rw_exit(&dr_grwlock
);
796 return (DDI_FAILURE
);
803 dr_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
806 dr_softstate_t
*softsp
;
810 if (!dr_modunload_okay
)
811 return (DDI_FAILURE
);
813 rw_enter(&dr_grwlock
, RW_WRITER
);
815 instance
= ddi_get_instance(dip
);
816 softsp
= ddi_get_soft_state(dr_g
.softsp
, instance
);
818 /* TODO: eliminate dr_boardlist */
819 ASSERT(softsp
->boards
== dr_boardlist
);
821 /* remove all minor nodes */
822 ddi_remove_minor_node(dip
, NULL
);
824 if (softsp
->dr_initialized
) {
827 for (bd
= 0; bd
< MAX_BOARDS
; bd
++)
828 dr_board_destroy(&softsp
->boards
[bd
]);
831 FREESTRUCT(softsp
->boards
, dr_board_t
, MAX_BOARDS
);
832 mutex_destroy(&softsp
->i_lock
);
833 ddi_soft_state_free(dr_g
.softsp
, instance
);
835 rw_exit(&dr_grwlock
);
836 return (DDI_SUCCESS
);
839 return (DDI_FAILURE
);
845 dr_getinfo(dev_info_t
*dip
, ddi_info_cmd_t cmd
, void *arg
, void **result
)
847 _NOTE(ARGUNUSED(dip
))
849 dev_t dev
= (dev_t
)arg
;
851 dr_softstate_t
*softsp
;
855 instance
= DR_MINOR2INST(getminor(dev
));
858 case DDI_INFO_DEVT2DEVINFO
:
859 softsp
= ddi_get_soft_state(dr_g
.softsp
, instance
);
861 return (DDI_FAILURE
);
862 *result
= (void *)softsp
->dip
;
865 case DDI_INFO_DEVT2INSTANCE
:
866 *result
= (void *)(uintptr_t)instance
;
882 dr_copyin_iocmd(dr_handle_t
*hp
)
884 static fn_t f
= "dr_copyin_iocmd";
885 sbd_cmd_t
*scp
= &hp
->h_sbdcmd
;
887 if (hp
->h_iap
== NULL
)
890 bzero((caddr_t
)scp
, sizeof (sbd_cmd_t
));
892 #ifdef _MULTI_DATAMODEL
893 if (ddi_model_convert_from(hp
->h_mode
& FMODELS
) == DDI_MODEL_ILP32
) {
896 bzero((caddr_t
)&scmd32
, sizeof (sbd_cmd32_t
));
898 if (ddi_copyin((void *)hp
->h_iap
, (void *)&scmd32
,
899 sizeof (sbd_cmd32_t
), hp
->h_mode
)) {
901 "%s: (32bit) failed to copyin "
905 scp
->cmd_cm
.c_id
.c_type
= scmd32
.cmd_cm
.c_id
.c_type
;
906 scp
->cmd_cm
.c_id
.c_unit
= scmd32
.cmd_cm
.c_id
.c_unit
;
907 bcopy(&scmd32
.cmd_cm
.c_id
.c_name
[0],
908 &scp
->cmd_cm
.c_id
.c_name
[0], OBP_MAXPROPNAME
);
909 scp
->cmd_cm
.c_flags
= scmd32
.cmd_cm
.c_flags
;
910 scp
->cmd_cm
.c_len
= scmd32
.cmd_cm
.c_len
;
911 scp
->cmd_cm
.c_opts
= (caddr_t
)(uintptr_t)scmd32
.cmd_cm
.c_opts
;
915 scp
->cmd_stat
.s_nbytes
= scmd32
.cmd_stat
.s_nbytes
;
916 scp
->cmd_stat
.s_statp
=
917 (caddr_t
)(uintptr_t)scmd32
.cmd_stat
.s_statp
;
924 #endif /* _MULTI_DATAMODEL */
925 if (ddi_copyin((void *)hp
->h_iap
, (void *)scp
,
926 sizeof (sbd_cmd_t
), hp
->h_mode
) != 0) {
928 "%s: failed to copyin sbdcmd-struct", f
);
932 if ((hp
->h_opts
.size
= scp
->cmd_cm
.c_len
) != 0) {
933 hp
->h_opts
.copts
= GETSTRUCT(char, scp
->cmd_cm
.c_len
+ 1);
935 if (ddi_copyin((void *)scp
->cmd_cm
.c_opts
,
936 (void *)hp
->h_opts
.copts
,
937 scp
->cmd_cm
.c_len
, hp
->h_mode
) != 0) {
938 cmn_err(CE_WARN
, "%s: failed to copyin options", f
);
947 dr_copyout_iocmd(dr_handle_t
*hp
)
949 static fn_t f
= "dr_copyout_iocmd";
950 sbd_cmd_t
*scp
= &hp
->h_sbdcmd
;
952 if (hp
->h_iap
== NULL
)
955 #ifdef _MULTI_DATAMODEL
956 if (ddi_model_convert_from(hp
->h_mode
& FMODELS
) == DDI_MODEL_ILP32
) {
959 scmd32
.cmd_cm
.c_id
.c_type
= scp
->cmd_cm
.c_id
.c_type
;
960 scmd32
.cmd_cm
.c_id
.c_unit
= scp
->cmd_cm
.c_id
.c_unit
;
961 bcopy(&scp
->cmd_cm
.c_id
.c_name
[0],
962 &scmd32
.cmd_cm
.c_id
.c_name
[0], OBP_MAXPROPNAME
);
964 scmd32
.cmd_cm
.c_flags
= scp
->cmd_cm
.c_flags
;
965 scmd32
.cmd_cm
.c_len
= scp
->cmd_cm
.c_len
;
966 scmd32
.cmd_cm
.c_opts
= (caddr32_t
)(uintptr_t)scp
->cmd_cm
.c_opts
;
970 scmd32
.cmd_getncm
.g_ncm
= scp
->cmd_getncm
.g_ncm
;
976 if (ddi_copyout((void *)&scmd32
, (void *)hp
->h_iap
,
977 sizeof (sbd_cmd32_t
), hp
->h_mode
)) {
979 "%s: (32bit) failed to copyout "
984 #endif /* _MULTI_DATAMODEL */
985 if (ddi_copyout((void *)scp
, (void *)hp
->h_iap
,
986 sizeof (sbd_cmd_t
), hp
->h_mode
) != 0) {
988 "%s: failed to copyout sbdcmd-struct", f
);
996 dr_copyout_errs(dr_handle_t
*hp
)
998 static fn_t f
= "dr_copyout_errs";
1000 if (hp
->h_err
== NULL
)
1003 if (hp
->h_err
->e_code
) {
1004 PR_ALL("%s: error %d %s",
1005 f
, hp
->h_err
->e_code
, hp
->h_err
->e_rsc
);
1008 #ifdef _MULTI_DATAMODEL
1009 if (ddi_model_convert_from(hp
->h_mode
& FMODELS
) == DDI_MODEL_ILP32
) {
1010 sbd_error32_t
*serr32p
;
1012 serr32p
= GETSTRUCT(sbd_error32_t
, 1);
1014 serr32p
->e_code
= hp
->h_err
->e_code
;
1015 bcopy(&hp
->h_err
->e_rsc
[0], &serr32p
->e_rsc
[0],
1017 if (ddi_copyout((void *)serr32p
,
1018 (void *)&((sbd_ioctl_arg32_t
*)hp
->h_iap
)->i_err
,
1019 sizeof (sbd_error32_t
), hp
->h_mode
)) {
1021 "%s: (32bit) failed to copyout", f
);
1024 FREESTRUCT(serr32p
, sbd_error32_t
, 1);
1026 #endif /* _MULTI_DATAMODEL */
1027 if (ddi_copyout((void *)hp
->h_err
,
1028 (void *)&hp
->h_iap
->i_err
,
1029 sizeof (sbd_error_t
), hp
->h_mode
)) {
1031 "%s: failed to copyout", f
);
1035 sbd_err_clear(&hp
->h_err
);
1042 * pre-op entry point must sbd_err_set_c(), if needed.
1043 * Return value of non-zero indicates failure.
1046 dr_pre_op(dr_handle_t
*hp
)
1051 dr_board_t
*bp
= hp
->h_bd
;
1052 dr_handle_t
*shp
= hp
;
1053 static fn_t f
= "dr_pre_op";
1056 devset
= shp
->h_devset
;
1058 PR_ALL("%s (cmd = %s)...\n", f
, SBD_CMD_STR(cmd
));
1060 devset
= DEVSET_AND(devset
, DR_DEVS_PRESENT(bp
));
1061 hp
->h_err
= drmach_pre_op(cmd
, bp
->b_id
, &hp
->h_opts
, &devset
);
1062 if (hp
->h_err
!= NULL
) {
1063 PR_ALL("drmach_pre_op failed for cmd %s(%d)\n",
1064 SBD_CMD_STR(cmd
), cmd
);
1069 * Check for valid state transitions.
1071 if ((t
= CMD2INDEX(cmd
)) != -1) {
1072 struct dr_state_trans
*transp
;
1075 transp
= &dr_state_transition
[t
];
1076 ASSERT(transp
->x_cmd
== cmd
);
1078 state_err
= dr_check_transition(bp
, &devset
, transp
, cmd
);
1080 if (state_err
< 0) {
1082 * Invalidate device.
1084 dr_op_err(CE_IGNORE
, hp
, ESBD_INVAL
, NULL
);
1086 PR_ALL("%s: invalid devset (0x%x)\n",
1088 } else if (state_err
!= 0) {
1090 * State transition is not a valid one.
1092 dr_op_err(CE_IGNORE
, hp
,
1093 transp
->x_op
[state_err
].x_err
, NULL
);
1095 serr
= transp
->x_op
[state_err
].x_rv
;
1097 PR_ALL("%s: invalid state %s(%d) for cmd %s(%d)\n",
1098 f
, state_str
[state_err
], state_err
,
1099 SBD_CMD_STR(cmd
), cmd
);
1101 shp
->h_devset
= devset
;
1113 dr_post_op(dr_handle_t
*hp
, int rv
)
1117 dr_board_t
*bp
= hp
->h_bd
;
1118 static fn_t f
= "dr_post_op";
1122 PR_ALL("%s (cmd = %s)...\n", f
, SBD_CMD_STR(cmd
));
1124 err
= drmach_post_op(cmd
, bp
->b_id
, &hp
->h_opts
, rv
);
1126 PR_ALL("drmach_post_op failed for cmd %s(%d)\n",
1127 SBD_CMD_STR(cmd
), cmd
);
1129 ASSERT(hp
->h_err
== NULL
);
1132 } else if (hp
->h_err
== NULL
) {
1135 sbd_err_clear(&err
);
1143 dr_exec_op(dr_handle_t
*hp
)
1146 static fn_t f
= "dr_exec_op";
1148 /* errors should have been caught by now */
1149 ASSERT(hp
->h_err
== NULL
);
1151 switch (hp
->h_cmd
) {
1152 case SBD_CMD_ASSIGN
:
1153 dr_assign_board(hp
);
1156 case SBD_CMD_UNASSIGN
:
1157 dr_unassign_board(hp
);
1160 case SBD_CMD_POWEROFF
:
1161 dr_poweroff_board(hp
);
1164 case SBD_CMD_POWERON
:
1165 dr_poweron_board(hp
);
1172 case SBD_CMD_CONNECT
:
1176 case SBD_CMD_CONFIGURE
:
1177 dr_dev_configure(hp
);
1180 case SBD_CMD_UNCONFIGURE
:
1182 if (hp
->h_err
== NULL
)
1183 rv
= dr_dev_unconfigure(hp
);
1188 case SBD_CMD_DISCONNECT
:
1189 rv
= dr_disconnect(hp
);
1192 case SBD_CMD_STATUS
:
1193 rv
= dr_dev_status(hp
);
1196 case SBD_CMD_GETNCM
:
1197 hp
->h_sbdcmd
.cmd_getncm
.g_ncm
= dr_get_ncm(hp
);
1198 rv
= dr_copyout_iocmd(hp
);
1201 case SBD_CMD_PASSTHRU
:
1202 rv
= dr_pt_ioctl(hp
);
1207 "%s: unknown command (%d)",
1212 if (hp
->h_err
!= NULL
) {
1220 dr_assign_board(dr_handle_t
*hp
)
1222 dr_board_t
*bp
= hp
->h_bd
;
1224 hp
->h_err
= drmach_board_assign(bp
->b_num
, &bp
->b_id
);
1225 if (hp
->h_err
== NULL
) {
1231 dr_unassign_board(dr_handle_t
*hp
)
1233 dr_board_t
*bp
= hp
->h_bd
;
1236 * Block out status during unassign.
1237 * Not doing cv_wait_sig here as starfire SSP software
1238 * ignores unassign failure and removes board from
1239 * domain mask causing system panic.
1240 * TODO: Change cv_wait to cv_wait_sig when SSP software
1241 * handles unassign failure.
1245 hp
->h_err
= drmach_board_unassign(bp
->b_id
);
1246 if (hp
->h_err
== NULL
) {
1248 * clear drmachid_t handle; not valid after board unassign
1254 dr_unlock_status(bp
);
1258 dr_poweron_board(dr_handle_t
*hp
)
1260 dr_board_t
*bp
= hp
->h_bd
;
1262 hp
->h_err
= drmach_board_poweron(bp
->b_id
);
1266 dr_poweroff_board(dr_handle_t
*hp
)
1268 dr_board_t
*bp
= hp
->h_bd
;
1270 hp
->h_err
= drmach_board_poweroff(bp
->b_id
);
1274 dr_test_board(dr_handle_t
*hp
)
1276 dr_board_t
*bp
= hp
->h_bd
;
1277 hp
->h_err
= drmach_board_test(bp
->b_id
, &hp
->h_opts
,
1278 dr_cmd_flags(hp
) & SBD_FLAG_FORCE
);
1282 * Create and populate the component nodes for a board. Assumes that the
1283 * devlists for the board have been initialized.
1286 dr_make_comp_nodes(dr_board_t
*bp
)
1291 * Make nodes for the individual components on the board.
1292 * First we need to initialize memory unit data structures of board
1295 for (i
= 0; i
< MAX_MEM_UNITS_PER_BOARD
; i
++) {
1298 mp
= dr_get_mem_unit(bp
, i
);
1299 dr_init_mem_unit(mp
);
1303 * Initialize cpu unit data structures.
1305 for (i
= 0; i
< MAX_CPU_UNITS_PER_BOARD
; i
++) {
1308 cp
= dr_get_cpu_unit(bp
, i
);
1309 dr_init_cpu_unit(cp
);
1313 * Initialize io unit data structures.
1315 for (i
= 0; i
< MAX_IO_UNITS_PER_BOARD
; i
++) {
1318 ip
= dr_get_io_unit(bp
, i
);
1319 dr_init_io_unit(ip
);
1322 dr_board_transition(bp
, DR_STATE_CONNECTED
);
1324 bp
->b_rstate
= SBD_STAT_CONNECTED
;
1325 bp
->b_ostate
= SBD_STAT_UNCONFIGURED
;
1326 bp
->b_cond
= SBD_COND_OK
;
1327 (void) drv_getparm(TIME
, (void *)&bp
->b_time
);
1332 * Only do work if called to operate on an entire board
1333 * which doesn't already have components present.
1336 dr_connect(dr_handle_t
*hp
)
1338 dr_board_t
*bp
= hp
->h_bd
;
1339 static fn_t f
= "dr_connect";
1341 PR_ALL("%s...\n", f
);
1343 if (DR_DEVS_PRESENT(bp
)) {
1345 * Board already has devices present.
1347 PR_ALL("%s: devices already present (" DEVSET_FMT_STR
")\n",
1348 f
, DEVSET_FMT_ARG(DR_DEVS_PRESENT(bp
)));
1352 hp
->h_err
= drmach_board_connect(bp
->b_id
, &hp
->h_opts
);
1356 hp
->h_err
= dr_init_devlists(bp
);
1359 else if (bp
->b_ndev
== 0) {
1360 dr_op_err(CE_WARN
, hp
, ESBD_EMPTY_BD
, bp
->b_path
);
1363 dr_make_comp_nodes(bp
);
1370 dr_disconnect(dr_handle_t
*hp
)
1374 dr_board_t
*bp
= hp
->h_bd
;
1375 static fn_t f
= "dr_disconnect";
1377 PR_ALL("%s...\n", f
);
1380 * Only devices which are present, but
1381 * unattached can be disconnected.
1383 devset
= hp
->h_devset
& DR_DEVS_PRESENT(bp
) &
1384 DR_DEVS_UNATTACHED(bp
);
1386 if ((devset
== 0) && DR_DEVS_PRESENT(bp
)) {
1387 dr_op_err(CE_IGNORE
, hp
, ESBD_EMPTY_BD
, bp
->b_path
);
1392 * Block out status during disconnect.
1394 mutex_enter(&bp
->b_slock
);
1395 while (bp
->b_sflags
& DR_BSLOCK
) {
1396 if (cv_wait_sig(&bp
->b_scv
, &bp
->b_slock
) == 0) {
1397 mutex_exit(&bp
->b_slock
);
1401 bp
->b_sflags
|= DR_BSLOCK
;
1402 mutex_exit(&bp
->b_slock
);
1404 hp
->h_err
= drmach_board_disconnect(bp
->b_id
, &hp
->h_opts
);
1405 if (hp
->h_err
&& hp
->h_err
->e_code
== EX86_WALK_DEPENDENCY
) {
1407 * Other boards have dependency on this board. No device nodes
1408 * have been destroyed so keep current board status.
1410 goto disconnect_done
;
1413 DR_DEVS_DISCONNECT(bp
, devset
);
1415 ASSERT((DR_DEVS_ATTACHED(bp
) & devset
) == 0);
1418 * Update per-device state transitions.
1420 for (i
= 0; i
< MAX_CPU_UNITS_PER_BOARD
; i
++) {
1423 if (!DEVSET_IN_SET(devset
, SBD_COMP_CPU
, i
))
1426 cp
= dr_get_cpu_unit(bp
, i
);
1427 if (dr_disconnect_cpu(cp
) == 0)
1428 dr_device_transition(&cp
->sbc_cm
, DR_STATE_EMPTY
);
1429 else if (cp
->sbc_cm
.sbdev_error
!= NULL
)
1430 DRERR_SET_C(&hp
->h_err
, &cp
->sbc_cm
.sbdev_error
);
1432 ASSERT(cp
->sbc_cm
.sbdev_error
== NULL
);
1435 for (i
= 0; i
< MAX_MEM_UNITS_PER_BOARD
; i
++) {
1438 if (!DEVSET_IN_SET(devset
, SBD_COMP_MEM
, i
))
1441 mp
= dr_get_mem_unit(bp
, i
);
1442 if (dr_disconnect_mem(mp
) == 0)
1443 dr_device_transition(&mp
->sbm_cm
, DR_STATE_EMPTY
);
1444 else if (mp
->sbm_cm
.sbdev_error
!= NULL
)
1445 DRERR_SET_C(&hp
->h_err
, &mp
->sbm_cm
.sbdev_error
);
1447 ASSERT(mp
->sbm_cm
.sbdev_error
== NULL
);
1450 for (i
= 0; i
< MAX_IO_UNITS_PER_BOARD
; i
++) {
1453 if (!DEVSET_IN_SET(devset
, SBD_COMP_IO
, i
))
1456 ip
= dr_get_io_unit(bp
, i
);
1457 if (dr_disconnect_io(ip
) == 0)
1458 dr_device_transition(&ip
->sbi_cm
, DR_STATE_EMPTY
);
1459 else if (ip
->sbi_cm
.sbdev_error
!= NULL
)
1460 DRERR_SET_C(&hp
->h_err
, &ip
->sbi_cm
.sbdev_error
);
1462 ASSERT(ip
->sbi_cm
.sbdev_error
== NULL
);
1467 * For certain errors, drmach_board_disconnect will mark
1468 * the board as unusable; in these cases the devtree must
1469 * be purged so that status calls will succeed.
1471 * This implementation checks for discrete error codes -
1472 * someday, the i/f to drmach_board_disconnect should be
1473 * changed to avoid the e_code testing.
1475 if (hp
->h_err
->e_code
== EX86_DEPROBE
) {
1476 bp
->b_ostate
= SBD_STAT_UNCONFIGURED
;
1478 (void) drv_getparm(TIME
, (void *)&bp
->b_time
);
1480 if (drmach_board_deprobe(bp
->b_id
))
1481 goto disconnect_done
;
1488 * Once all the components on a board have been disconnect
1489 * the board's state can transition to disconnected and
1490 * we can allow the deprobe to take place.
1492 if (hp
->h_err
== NULL
&& DR_DEVS_PRESENT(bp
) == 0) {
1493 dr_board_transition(bp
, DR_STATE_OCCUPIED
);
1494 bp
->b_rstate
= SBD_STAT_DISCONNECTED
;
1495 bp
->b_ostate
= SBD_STAT_UNCONFIGURED
;
1497 (void) drv_getparm(TIME
, (void *)&bp
->b_time
);
1499 hp
->h_err
= drmach_board_deprobe(bp
->b_id
);
1501 if (hp
->h_err
== NULL
) {
1503 dr_board_transition(bp
, DR_STATE_EMPTY
);
1504 bp
->b_rstate
= SBD_STAT_EMPTY
;
1505 (void) drv_getparm(TIME
, (void *)&bp
->b_time
);
1510 dr_unlock_status(bp
);
1516 * Check if a particular device is a valid target of the current
1517 * operation. Return 1 if it is a valid target, and 0 otherwise.
1520 dr_dev_is_target(dr_dev_unit_t
*dp
, int present_only
, uint_t uset
)
1522 dr_common_unit_t
*cp
;
1526 cp
= &dp
->du_common
;
1528 /* check if the user requested this device */
1529 if ((uset
& (1 << cp
->sbdev_unum
)) == 0) {
1533 is_present
= DR_DEV_IS_PRESENT(cp
) ? 1 : 0;
1534 is_attached
= DR_DEV_IS_ATTACHED(cp
) ? 1 : 0;
1537 * If the present_only flag is set, a valid target
1538 * must be present but not attached. Otherwise, it
1539 * must be both present and attached.
1541 if (is_present
&& (present_only
^ is_attached
)) {
1543 ASSERT(cp
->sbdev_id
!= (drmachid_t
)0);
1552 dr_dev_make_list(dr_handle_t
*hp
, sbd_comp_type_t type
, int present_only
,
1553 dr_common_unit_t
***devlist
, int *devnum
)
1555 dr_board_t
*bp
= hp
->h_bd
;
1560 dr_common_unit_t
**list
, **wp
;
1564 nunits
= MAX_CPU_UNITS_PER_BOARD
;
1567 nunits
= MAX_MEM_UNITS_PER_BOARD
;
1570 nunits
= MAX_IO_UNITS_PER_BOARD
;
1573 /* catch this in debug kernels */
1578 /* allocate list storage. */
1579 len
= sizeof (dr_common_unit_t
*) * (nunits
+ 1);
1580 list
= kmem_zalloc(len
, KM_SLEEP
);
1582 /* record length of storage in first element */
1583 *list
++ = (dr_common_unit_t
*)(uintptr_t)len
;
1585 /* get bit array signifying which units are to be involved */
1586 uset
= DEVSET_GET_UNITSET(hp
->h_devset
, type
);
1589 * Adjust the loop count for CPU devices since all cores
1590 * in a CMP will be examined in a single iteration.
1592 if (type
== SBD_COMP_CPU
) {
1593 nunits
= MAX_CMP_UNITS_PER_BOARD
;
1597 for (wp
= list
, unum
= 0; unum
< nunits
; unum
++) {
1602 dp
= DR_GET_BOARD_DEVUNIT(bp
, type
, unum
);
1603 if (dr_dev_is_target(dp
, present_only
, uset
)) {
1604 *wp
++ = &dp
->du_common
;
1607 /* further processing is only required for CPUs */
1608 if (type
!= SBD_COMP_CPU
) {
1613 * Add any additional cores from the current CPU
1614 * device. This is to ensure that all the cores
1615 * are grouped together in the device list, and
1616 * consequently sequenced together during the actual
1619 for (core
= 1; core
< MAX_CORES_PER_CMP
; core
++) {
1620 cunum
= DR_CMP_CORE_UNUM(unum
, core
);
1621 dp
= DR_GET_BOARD_DEVUNIT(bp
, type
, cunum
);
1623 if (dr_dev_is_target(dp
, present_only
, uset
)) {
1624 *wp
++ = &dp
->du_common
;
1629 /* calculate number of units in list, return result and list pointer */
1630 *devnum
= wp
- list
;
1635 dr_dev_clean_up(dr_handle_t
*hp
, dr_common_unit_t
**list
, int devnum
)
1639 dr_common_unit_t
*cp
, **rp
= list
;
1642 * move first encountered unit error to handle if handle
1643 * does not yet have a recorded error.
1645 if (hp
->h_err
== NULL
) {
1646 while (n
++ < devnum
) {
1648 if (cp
->sbdev_error
!= NULL
) {
1649 hp
->h_err
= cp
->sbdev_error
;
1650 cp
->sbdev_error
= NULL
;
1656 /* free remaining unit errors */
1657 while (n
++ < devnum
) {
1659 if (cp
->sbdev_error
!= NULL
) {
1660 sbd_err_clear(&cp
->sbdev_error
);
1661 cp
->sbdev_error
= NULL
;
1667 len
= (int)(uintptr_t)list
[0];
1668 kmem_free(list
, len
);
1672 dr_dev_walk(dr_handle_t
*hp
, sbd_comp_type_t type
, int present_only
,
1673 int (*pre_op
)(dr_handle_t
*, dr_common_unit_t
**, int),
1674 void (*op
)(dr_handle_t
*, dr_common_unit_t
*),
1675 int (*post_op
)(dr_handle_t
*, dr_common_unit_t
**, int),
1676 void (*board_op
)(dr_handle_t
*, dr_common_unit_t
**, int))
1679 dr_common_unit_t
**devlist
;
1681 dr_dev_make_list(hp
, type
, present_only
, &devlist
, &devnum
);
1685 rv
= (*pre_op
)(hp
, devlist
, devnum
);
1689 for (n
= 0; n
< devnum
; n
++)
1690 (*op
)(hp
, devlist
[n
]);
1692 rv
= (*post_op
)(hp
, devlist
, devnum
);
1694 (*board_op
)(hp
, devlist
, devnum
);
1698 dr_dev_clean_up(hp
, devlist
, devnum
);
1704 dr_dev_noop(dr_handle_t
*hp
, dr_common_unit_t
**devlist
, int devnum
)
1710 dr_attach_update_state(dr_handle_t
*hp
, dr_common_unit_t
**devlist
, int devnum
)
1712 dr_board_t
*bp
= hp
->h_bd
;
1714 dr_devset_t devs_unattached
, devs_present
;
1715 static fn_t f
= "dr_attach_update_state";
1717 for (i
= 0; i
< devnum
; i
++) {
1718 dr_common_unit_t
*cp
= devlist
[i
];
1720 if (dr_check_unit_attached(cp
) == -1) {
1721 PR_ALL("%s: ERROR %s not attached\n",
1726 DR_DEV_SET_ATTACHED(cp
);
1728 dr_device_transition(cp
, DR_STATE_CONFIGURED
);
1729 cp
->sbdev_cond
= SBD_COND_OK
;
1732 devs_present
= DR_DEVS_PRESENT(bp
);
1733 devs_unattached
= DR_DEVS_UNATTACHED(bp
);
1735 switch (bp
->b_state
) {
1736 case DR_STATE_CONNECTED
:
1737 case DR_STATE_UNCONFIGURED
:
1738 ASSERT(devs_present
);
1740 if (devs_unattached
== 0) {
1742 * All devices finally attached.
1744 dr_board_transition(bp
, DR_STATE_CONFIGURED
);
1745 hp
->h_bd
->b_ostate
= SBD_STAT_CONFIGURED
;
1746 hp
->h_bd
->b_rstate
= SBD_STAT_CONNECTED
;
1747 hp
->h_bd
->b_cond
= SBD_COND_OK
;
1748 hp
->h_bd
->b_busy
= 0;
1749 (void) drv_getparm(TIME
, (void *)&hp
->h_bd
->b_time
);
1750 } else if (devs_present
!= devs_unattached
) {
1752 * Only some devices are fully attached.
1754 dr_board_transition(bp
, DR_STATE_PARTIAL
);
1755 hp
->h_bd
->b_rstate
= SBD_STAT_CONNECTED
;
1756 hp
->h_bd
->b_ostate
= SBD_STAT_CONFIGURED
;
1757 (void) drv_getparm(TIME
, (void *)&hp
->h_bd
->b_time
);
1761 case DR_STATE_PARTIAL
:
1762 ASSERT(devs_present
);
1764 * All devices finally attached.
1766 if (devs_unattached
== 0) {
1767 dr_board_transition(bp
, DR_STATE_CONFIGURED
);
1768 hp
->h_bd
->b_rstate
= SBD_STAT_CONNECTED
;
1769 hp
->h_bd
->b_ostate
= SBD_STAT_CONFIGURED
;
1770 hp
->h_bd
->b_cond
= SBD_COND_OK
;
1771 hp
->h_bd
->b_busy
= 0;
1772 (void) drv_getparm(TIME
, (void *)&hp
->h_bd
->b_time
);
1782 dr_dev_configure(dr_handle_t
*hp
)
1786 rv
= dr_dev_walk(hp
, SBD_COMP_CPU
, 1,
1790 dr_attach_update_state
);
1793 rv
= dr_dev_walk(hp
, SBD_COMP_MEM
, 1,
1797 dr_attach_update_state
);
1801 (void) dr_dev_walk(hp
, SBD_COMP_IO
, 1,
1805 dr_attach_update_state
);
1810 dr_release_update_state(dr_handle_t
*hp
,
1811 dr_common_unit_t
**devlist
, int devnum
)
1813 _NOTE(ARGUNUSED(devlist
))
1814 _NOTE(ARGUNUSED(devnum
))
1816 dr_board_t
*bp
= hp
->h_bd
;
1819 * If the entire board was released and all components
1820 * unreferenced then transfer it to the UNREFERENCED state.
1822 if ((bp
->b_state
!= DR_STATE_RELEASE
) &&
1823 (DR_DEVS_RELEASED(bp
) == DR_DEVS_ATTACHED(bp
))) {
1824 dr_board_transition(bp
, DR_STATE_RELEASE
);
1825 hp
->h_bd
->b_busy
= 1;
1829 /* called by dr_release_done [below] and dr_release_mem_done [dr_mem.c] */
1831 dr_release_dev_done(dr_common_unit_t
*cp
)
1833 if (cp
->sbdev_state
== DR_STATE_RELEASE
) {
1834 ASSERT(DR_DEV_IS_RELEASED(cp
));
1836 DR_DEV_SET_UNREFERENCED(cp
);
1838 dr_device_transition(cp
, DR_STATE_UNREFERENCED
);
1847 dr_release_done(dr_handle_t
*hp
, dr_common_unit_t
*cp
)
1849 _NOTE(ARGUNUSED(hp
))
1852 static fn_t f
= "dr_release_done";
1854 PR_ALL("%s...\n", f
);
1856 /* get board pointer & sanity check */
1858 ASSERT(bp
== hp
->h_bd
);
1861 * Transfer the device which just completed its release
1862 * to the UNREFERENCED state.
1864 switch (cp
->sbdev_type
) {
1866 dr_release_mem_done(cp
);
1870 DR_DEV_SET_RELEASED(cp
);
1872 dr_device_transition(cp
, DR_STATE_RELEASE
);
1874 (void) dr_release_dev_done(cp
);
1879 * If we're not already in the RELEASE state for this
1880 * board and we now have released all that were previously
1881 * attached, then transfer the board to the RELEASE state.
1883 if ((bp
->b_state
== DR_STATE_RELEASE
) &&
1884 (DR_DEVS_RELEASED(bp
) == DR_DEVS_UNREFERENCED(bp
))) {
1885 dr_board_transition(bp
, DR_STATE_UNREFERENCED
);
1887 (void) drv_getparm(TIME
, (void *)&bp
->b_time
);
1892 dr_dev_release_mem(dr_handle_t
*hp
, dr_common_unit_t
*dv
)
1895 dr_release_done(hp
, dv
);
1899 dr_dev_release(dr_handle_t
*hp
)
1903 hp
->h_bd
->b_busy
= 1;
1905 rv
= dr_dev_walk(hp
, SBD_COMP_CPU
, 0,
1909 dr_release_update_state
);
1912 rv
= dr_dev_walk(hp
, SBD_COMP_MEM
, 0,
1916 dr_release_update_state
);
1920 rv
= dr_dev_walk(hp
, SBD_COMP_IO
, 0,
1924 dr_release_update_state
);
1929 hp
->h_bd
->b_busy
= 0;
1930 /* else, b_busy will be cleared in dr_detach_update_state() */
1934 dr_detach_update_state(dr_handle_t
*hp
, dr_common_unit_t
**devlist
, int devnum
)
1936 dr_board_t
*bp
= hp
->h_bd
;
1939 static fn_t f
= "dr_detach_update_state";
1941 for (i
= 0; i
< devnum
; i
++) {
1942 dr_common_unit_t
*cp
= devlist
[i
];
1944 if (dr_check_unit_attached(cp
) >= 0) {
1946 * Device is still attached probably due
1947 * to an error. Need to keep track of it.
1949 PR_ALL("%s: ERROR %s not detached\n",
1955 DR_DEV_CLR_ATTACHED(cp
);
1956 DR_DEV_CLR_RELEASED(cp
);
1957 DR_DEV_CLR_UNREFERENCED(cp
);
1958 dr_device_transition(cp
, DR_STATE_UNCONFIGURED
);
1961 bstate
= bp
->b_state
;
1962 if (bstate
!= DR_STATE_UNCONFIGURED
) {
1963 if (DR_DEVS_PRESENT(bp
) == DR_DEVS_UNATTACHED(bp
)) {
1965 * All devices are finally detached.
1967 dr_board_transition(bp
, DR_STATE_UNCONFIGURED
);
1968 hp
->h_bd
->b_ostate
= SBD_STAT_UNCONFIGURED
;
1969 (void) drv_getparm(TIME
, (void *)&hp
->h_bd
->b_time
);
1970 } else if ((bp
->b_state
!= DR_STATE_PARTIAL
) &&
1971 (DR_DEVS_ATTACHED(bp
) !=
1972 DR_DEVS_PRESENT(bp
))) {
1974 * Some devices remain attached.
1976 dr_board_transition(bp
, DR_STATE_PARTIAL
);
1977 (void) drv_getparm(TIME
, (void *)&hp
->h_bd
->b_time
);
1980 if ((hp
->h_devset
& DR_DEVS_UNATTACHED(bp
)) == hp
->h_devset
)
1981 hp
->h_bd
->b_busy
= 0;
1986 dr_dev_unconfigure(dr_handle_t
*hp
)
1988 dr_board_t
*bp
= hp
->h_bd
;
1991 * Block out status during IO unconfig.
1993 mutex_enter(&bp
->b_slock
);
1994 while (bp
->b_sflags
& DR_BSLOCK
) {
1995 if (cv_wait_sig(&bp
->b_scv
, &bp
->b_slock
) == 0) {
1996 mutex_exit(&bp
->b_slock
);
2000 bp
->b_sflags
|= DR_BSLOCK
;
2001 mutex_exit(&bp
->b_slock
);
2003 (void) dr_dev_walk(hp
, SBD_COMP_IO
, 0,
2007 dr_detach_update_state
);
2009 dr_unlock_status(bp
);
2011 (void) dr_dev_walk(hp
, SBD_COMP_CPU
, 0,
2015 dr_detach_update_state
);
2017 (void) dr_dev_walk(hp
, SBD_COMP_MEM
, 0,
2021 dr_detach_update_state
);
2027 dr_dev_cancel(dr_handle_t
*hp
)
2031 dr_board_t
*bp
= hp
->h_bd
;
2032 static fn_t f
= "dr_dev_cancel";
2034 PR_ALL("%s...\n", f
);
2037 * Only devices which have been "released" are
2038 * subject to cancellation.
2040 devset
= hp
->h_devset
& DR_DEVS_RELEASED(bp
);
2043 * Nothing to do for CPUs or IO other than change back
2046 for (i
= 0; i
< MAX_CPU_UNITS_PER_BOARD
; i
++) {
2050 if (!DEVSET_IN_SET(devset
, SBD_COMP_CPU
, i
))
2053 cp
= dr_get_cpu_unit(bp
, i
);
2054 if (dr_cancel_cpu(cp
) == 0)
2055 nstate
= DR_STATE_CONFIGURED
;
2057 nstate
= DR_STATE_FATAL
;
2059 dr_device_transition(&cp
->sbc_cm
, nstate
);
2062 for (i
= 0; i
< MAX_IO_UNITS_PER_BOARD
; i
++) {
2065 if (!DEVSET_IN_SET(devset
, SBD_COMP_IO
, i
))
2067 ip
= dr_get_io_unit(bp
, i
);
2068 dr_device_transition(&ip
->sbi_cm
, DR_STATE_CONFIGURED
);
2070 for (i
= 0; i
< MAX_MEM_UNITS_PER_BOARD
; i
++) {
2074 if (!DEVSET_IN_SET(devset
, SBD_COMP_MEM
, i
))
2077 mp
= dr_get_mem_unit(bp
, i
);
2078 if (dr_cancel_mem(mp
) == 0)
2079 nstate
= DR_STATE_CONFIGURED
;
2081 nstate
= DR_STATE_FATAL
;
2083 dr_device_transition(&mp
->sbm_cm
, nstate
);
2086 PR_ALL("%s: unreleasing devset (0x%x)\n", f
, (uint_t
)devset
);
2088 DR_DEVS_CANCEL(bp
, devset
);
2090 if (DR_DEVS_RELEASED(bp
) == 0) {
2091 dr_state_t new_state
;
2093 * If the board no longer has any released devices
2094 * than transfer it back to the CONFIG/PARTIAL state.
2096 if (DR_DEVS_ATTACHED(bp
) == DR_DEVS_PRESENT(bp
))
2097 new_state
= DR_STATE_CONFIGURED
;
2099 new_state
= DR_STATE_PARTIAL
;
2100 if (bp
->b_state
!= new_state
) {
2101 dr_board_transition(bp
, new_state
);
2103 hp
->h_bd
->b_ostate
= SBD_STAT_CONFIGURED
;
2104 hp
->h_bd
->b_busy
= 0;
2105 (void) drv_getparm(TIME
, (void *)&hp
->h_bd
->b_time
);
2110 dr_dev_status(dr_handle_t
*hp
)
2112 int nstat
, mode
, ncm
, sz
, pbsz
, pnstat
;
2114 dr_devset_t devset
= 0;
2115 sbd_stat_t
*dstatp
= NULL
;
2116 sbd_dev_stat_t
*devstatp
;
2118 drmach_status_t pstat
;
2121 #ifdef _MULTI_DATAMODEL
2123 #endif /* _MULTI_DATAMODEL */
2125 static fn_t f
= "dr_dev_status";
2127 PR_ALL("%s...\n", f
);
2131 devset
= shp
->h_devset
;
2135 * Block out disconnect, unassign, IO unconfigure and
2136 * devinfo branch creation during status.
2138 mutex_enter(&bp
->b_slock
);
2139 while (bp
->b_sflags
& DR_BSLOCK
) {
2140 if (cv_wait_sig(&bp
->b_scv
, &bp
->b_slock
) == 0) {
2141 mutex_exit(&bp
->b_slock
);
2145 bp
->b_sflags
|= DR_BSLOCK
;
2146 mutex_exit(&bp
->b_slock
);
2149 if (hp
->h_sbdcmd
.cmd_cm
.c_id
.c_type
== SBD_COMP_NONE
) {
2150 if (dr_cmd_flags(hp
) & SBD_FLAG_ALLCMP
) {
2152 * Calculate the maximum number of components possible
2153 * for a board. This number will be used to size the
2154 * status scratch buffer used by board and component
2156 * This buffer may differ in size from what is provided
2157 * by the plugin, since the known component set on the
2158 * board may change between the plugin's GETNCM call, and
2159 * the status call. Sizing will be adjusted to the plugin's
2160 * receptacle buffer at copyout time.
2162 ncm
= MAX_CPU_UNITS_PER_BOARD
+
2163 MAX_MEM_UNITS_PER_BOARD
+
2164 MAX_IO_UNITS_PER_BOARD
;
2168 * In the case of c_type == SBD_COMP_NONE, and
2169 * SBD_FLAG_ALLCMP not specified, only the board
2170 * info is to be returned, no components.
2177 sz
= sizeof (sbd_stat_t
);
2179 sz
+= sizeof (sbd_dev_stat_t
) * (ncm
- 1);
2182 pbsz
= (int)hp
->h_sbdcmd
.cmd_stat
.s_nbytes
;
2183 pnstat
= (pbsz
- sizeof (sbd_stat_t
)) / sizeof (sbd_dev_stat_t
);
2186 * s_nbytes describes the size of the preallocated user
2187 * buffer into which the application is execting to
2188 * receive the sbd_stat_t and sbd_dev_stat_t structures.
2191 #ifdef _MULTI_DATAMODEL
2194 * More buffer space is required for the 64bit to 32bit
2195 * conversion of data structures.
2197 if (ddi_model_convert_from(mode
& FMODELS
) == DDI_MODEL_ILP32
) {
2198 sz32
= sizeof (sbd_stat32_t
);
2200 sz32
+= sizeof (sbd_dev_stat32_t
) * (ncm
- 1);
2201 pnstat
= (pbsz
- sizeof (sbd_stat32_t
))/
2202 sizeof (sbd_dev_stat32_t
);
2208 * Since one sbd_dev_stat_t is included in the sbd_stat_t,
2209 * increment the plugin's nstat count.
2213 if (bp
->b_id
== 0) {
2214 bzero(&pstat
, sizeof (pstat
));
2218 err
= drmach_status(bp
->b_id
, &pstat
);
2220 DRERR_SET_C(&hp
->h_err
, &err
);
2226 dstatp
= (sbd_stat_t
*)(void *)GETSTRUCT(char, sz
);
2228 devstatp
= &dstatp
->s_stat
[0];
2230 dstatp
->s_board
= bp
->b_num
;
2233 * Detect transitions between empty and disconnected.
2235 if (!pstat
.empty
&& (bp
->b_rstate
== SBD_STAT_EMPTY
))
2236 bp
->b_rstate
= SBD_STAT_DISCONNECTED
;
2237 else if (pstat
.empty
&& (bp
->b_rstate
== SBD_STAT_DISCONNECTED
))
2238 bp
->b_rstate
= SBD_STAT_EMPTY
;
2240 dstatp
->s_rstate
= bp
->b_rstate
;
2241 dstatp
->s_ostate
= bp
->b_ostate
;
2242 dstatp
->s_cond
= bp
->b_cond
= pstat
.cond
;
2243 dstatp
->s_busy
= bp
->b_busy
| pstat
.busy
;
2244 dstatp
->s_time
= bp
->b_time
;
2245 dstatp
->s_power
= pstat
.powered
;
2246 dstatp
->s_assigned
= bp
->b_assigned
= pstat
.assigned
;
2247 dstatp
->s_nstat
= nstat
= 0;
2248 bcopy(&pstat
.type
[0], &dstatp
->s_type
[0], SBD_TYPE_LEN
);
2249 bcopy(&pstat
.info
[0], &dstatp
->s_info
[0], SBD_MAX_INFO
);
2251 devset
&= DR_DEVS_PRESENT(bp
);
2256 PR_ALL("%s: no device present\n", f
);
2259 if (DEVSET_IN_SET(devset
, SBD_COMP_CPU
, DEVSET_ANYUNIT
))
2260 if ((nstat
= dr_cpu_status(hp
, devset
, devstatp
)) > 0) {
2261 dstatp
->s_nstat
+= nstat
;
2265 if (DEVSET_IN_SET(devset
, SBD_COMP_MEM
, DEVSET_ANYUNIT
))
2266 if ((nstat
= dr_mem_status(hp
, devset
, devstatp
)) > 0) {
2267 dstatp
->s_nstat
+= nstat
;
2271 if (DEVSET_IN_SET(devset
, SBD_COMP_IO
, DEVSET_ANYUNIT
))
2272 if ((nstat
= dr_io_status(hp
, devset
, devstatp
)) > 0) {
2273 dstatp
->s_nstat
+= nstat
;
2278 * Due to a possible change in number of components between
2279 * the time of plugin's GETNCM call and now, there may be
2280 * more or less components than the plugin's buffer can
2281 * hold. Adjust s_nstat accordingly.
2284 dstatp
->s_nstat
= dstatp
->s_nstat
> pnstat
? pnstat
: dstatp
->s_nstat
;
2286 #ifdef _MULTI_DATAMODEL
2287 if (ddi_model_convert_from(mode
& FMODELS
) == DDI_MODEL_ILP32
) {
2289 sbd_stat32_t
*dstat32p
;
2291 dstat32p
= (sbd_stat32_t
*)devstatp
;
2293 /* Alignment Paranoia */
2294 if ((ulong_t
)dstat32p
& 0x1) {
2295 PR_ALL("%s: alignment: sz=0x%lx dstat32p=0x%p\n",
2296 f
, sizeof (sbd_stat32_t
), (void *)dstat32p
);
2297 DR_OP_INTERNAL_ERROR(hp
);
2302 /* paranoia: detect buffer overrun */
2303 if ((caddr_t
)&dstat32p
->s_stat
[dstatp
->s_nstat
] >
2304 ((caddr_t
)dstatp
) + sz
) {
2305 DR_OP_INTERNAL_ERROR(hp
);
2310 /* copy sbd_stat_t structure members */
2311 #define _SBD_STAT(t, m) dstat32p->m = (t)dstatp->m
2312 _SBD_STAT(int32_t, s_board
);
2313 _SBD_STAT(int32_t, s_rstate
);
2314 _SBD_STAT(int32_t, s_ostate
);
2315 _SBD_STAT(int32_t, s_cond
);
2316 _SBD_STAT(int32_t, s_busy
);
2317 _SBD_STAT(time32_t
, s_time
);
2318 _SBD_STAT(uint32_t, s_power
);
2319 _SBD_STAT(uint32_t, s_assigned
);
2320 _SBD_STAT(int32_t, s_nstat
);
2321 bcopy(&dstatp
->s_type
[0], &dstat32p
->s_type
[0],
2323 bcopy(&dstatp
->s_info
[0], &dstat32p
->s_info
[0],
2327 for (i
= 0; i
< dstatp
->s_nstat
; i
++) {
2328 sbd_dev_stat_t
*dsp
= &dstatp
->s_stat
[i
];
2329 sbd_dev_stat32_t
*ds32p
= &dstat32p
->s_stat
[i
];
2330 #define _SBD_DEV_STAT(t, m) ds32p->m = (t)dsp->m
2332 /* copy sbd_cm_stat_t structure members */
2333 _SBD_DEV_STAT(int32_t, ds_type
);
2334 _SBD_DEV_STAT(int32_t, ds_unit
);
2335 _SBD_DEV_STAT(int32_t, ds_ostate
);
2336 _SBD_DEV_STAT(int32_t, ds_cond
);
2337 _SBD_DEV_STAT(int32_t, ds_busy
);
2338 _SBD_DEV_STAT(int32_t, ds_suspend
);
2339 _SBD_DEV_STAT(time32_t
, ds_time
);
2340 bcopy(&dsp
->ds_name
[0], &ds32p
->ds_name
[0],
2343 switch (dsp
->ds_type
) {
2345 /* copy sbd_cpu_stat_t structure members */
2346 _SBD_DEV_STAT(int32_t, d_cpu
.cs_isbootproc
);
2347 _SBD_DEV_STAT(int32_t, d_cpu
.cs_cpuid
);
2348 _SBD_DEV_STAT(int32_t, d_cpu
.cs_speed
);
2349 _SBD_DEV_STAT(int32_t, d_cpu
.cs_ecache
);
2353 /* copy sbd_mem_stat_t structure members */
2354 _SBD_DEV_STAT(int32_t, d_mem
.ms_interleave
);
2355 _SBD_DEV_STAT(uint32_t, d_mem
.ms_basepfn
);
2356 _SBD_DEV_STAT(uint32_t, d_mem
.ms_totpages
);
2357 _SBD_DEV_STAT(uint32_t, d_mem
.ms_detpages
);
2358 _SBD_DEV_STAT(int32_t, d_mem
.ms_pageslost
);
2359 _SBD_DEV_STAT(uint32_t, d_mem
.ms_managed_pages
);
2360 _SBD_DEV_STAT(uint32_t, d_mem
.ms_noreloc_pages
);
2361 _SBD_DEV_STAT(uint32_t, d_mem
.ms_noreloc_first
);
2362 _SBD_DEV_STAT(uint32_t, d_mem
.ms_noreloc_last
);
2363 _SBD_DEV_STAT(int32_t, d_mem
.ms_cage_enabled
);
2364 _SBD_DEV_STAT(int32_t, d_mem
.ms_peer_is_target
);
2365 bcopy(&dsp
->d_mem
.ms_peer_ap_id
[0],
2366 &ds32p
->d_mem
.ms_peer_ap_id
[0],
2367 sizeof (ds32p
->d_mem
.ms_peer_ap_id
));
2371 /* copy sbd_io_stat_t structure members */
2372 _SBD_DEV_STAT(int32_t, d_io
.is_referenced
);
2373 _SBD_DEV_STAT(int32_t, d_io
.is_unsafe_count
);
2375 for (j
= 0; j
< SBD_MAX_UNSAFE
; j
++)
2376 _SBD_DEV_STAT(int32_t,
2377 d_io
.is_unsafe_list
[j
]);
2379 bcopy(&dsp
->d_io
.is_pathname
[0],
2380 &ds32p
->d_io
.is_pathname
[0], MAXPATHLEN
);
2384 /* copy sbd_cmp_stat_t structure members */
2385 bcopy(&dsp
->d_cmp
.ps_cpuid
[0],
2386 &ds32p
->d_cmp
.ps_cpuid
[0],
2387 sizeof (ds32p
->d_cmp
.ps_cpuid
));
2388 _SBD_DEV_STAT(int32_t, d_cmp
.ps_ncores
);
2389 _SBD_DEV_STAT(int32_t, d_cmp
.ps_speed
);
2390 _SBD_DEV_STAT(int32_t, d_cmp
.ps_ecache
);
2394 cmn_err(CE_WARN
, "%s: unknown dev type (%d)",
2395 f
, (int)dsp
->ds_type
);
2399 #undef _SBD_DEV_STAT
2403 if (ddi_copyout((void *)dstat32p
,
2404 hp
->h_sbdcmd
.cmd_stat
.s_statp
, pbsz
, mode
) != 0) {
2406 "%s: failed to copyout status "
2407 "for board %d", f
, bp
->b_num
);
2412 #endif /* _MULTI_DATAMODEL */
2414 if (ddi_copyout((void *)dstatp
, hp
->h_sbdcmd
.cmd_stat
.s_statp
,
2417 "%s: failed to copyout status for board %d",
2425 FREESTRUCT(dstatp
, char, sz
);
2427 dr_unlock_status(bp
);
2433 dr_get_ncm(dr_handle_t
*hp
)
2439 devset
= DR_DEVS_PRESENT(hp
->h_bd
);
2440 if (hp
->h_sbdcmd
.cmd_cm
.c_id
.c_type
!= SBD_COMP_NONE
)
2441 devset
&= DEVSET(hp
->h_sbdcmd
.cmd_cm
.c_id
.c_type
,
2445 * Handle CPUs first to deal with possible CMP
2446 * devices. If the CPU is a CMP, we need to only
2447 * increment ncm once even if there are multiple
2448 * cores for that CMP present in the devset.
2450 for (i
= 0; i
< MAX_CMP_UNITS_PER_BOARD
; i
++) {
2451 if (devset
& DEVSET(SBD_COMP_CMP
, i
)) {
2456 /* eliminate the CPU information from the devset */
2457 devset
&= ~(DEVSET(SBD_COMP_CMP
, DEVSET_ANYUNIT
));
2459 for (i
= 0; i
< (sizeof (dr_devset_t
) * 8); i
++) {
2460 ncm
+= devset
& 0x1;
2467 /* used by dr_mem.c */
2468 /* TODO: eliminate dr_boardlist */
2470 dr_lookup_board(int board_num
)
2474 ASSERT(board_num
>= 0 && board_num
< MAX_BOARDS
);
2476 bp
= &dr_boardlist
[board_num
];
2477 ASSERT(bp
->b_num
== board_num
);
2482 static dr_dev_unit_t
*
2483 dr_get_dev_unit(dr_board_t
*bp
, sbd_comp_type_t nt
, int unit_num
)
2487 dp
= DR_GET_BOARD_DEVUNIT(bp
, nt
, unit_num
);
2488 ASSERT(dp
->du_common
.sbdev_bp
== bp
);
2489 ASSERT(dp
->du_common
.sbdev_unum
== unit_num
);
2490 ASSERT(dp
->du_common
.sbdev_type
== nt
);
2496 dr_get_cpu_unit(dr_board_t
*bp
, int unit_num
)
2500 ASSERT(unit_num
>= 0 && unit_num
< MAX_CPU_UNITS_PER_BOARD
);
2502 dp
= dr_get_dev_unit(bp
, SBD_COMP_CPU
, unit_num
);
2503 return (&dp
->du_cpu
);
2507 dr_get_mem_unit(dr_board_t
*bp
, int unit_num
)
2511 ASSERT(unit_num
>= 0 && unit_num
< MAX_MEM_UNITS_PER_BOARD
);
2513 dp
= dr_get_dev_unit(bp
, SBD_COMP_MEM
, unit_num
);
2514 return (&dp
->du_mem
);
2518 dr_get_io_unit(dr_board_t
*bp
, int unit_num
)
2522 ASSERT(unit_num
>= 0 && unit_num
< MAX_IO_UNITS_PER_BOARD
);
2524 dp
= dr_get_dev_unit(bp
, SBD_COMP_IO
, unit_num
);
2525 return (&dp
->du_io
);
2529 dr_get_common_unit(dr_board_t
*bp
, sbd_comp_type_t nt
, int unum
)
2533 dp
= dr_get_dev_unit(bp
, nt
, unum
);
2534 return (&dp
->du_common
);
2538 dr_dev2devset(sbd_comp_id_t
*cid
)
2540 static fn_t f
= "dr_dev2devset";
2543 int unit
= cid
->c_unit
;
2545 switch (cid
->c_type
) {
2547 devset
= DEVSET(SBD_COMP_CPU
, DEVSET_ANYUNIT
);
2548 devset
|= DEVSET(SBD_COMP_MEM
, DEVSET_ANYUNIT
);
2549 devset
|= DEVSET(SBD_COMP_IO
, DEVSET_ANYUNIT
);
2550 PR_ALL("%s: COMP_NONE devset = " DEVSET_FMT_STR
"\n",
2551 f
, DEVSET_FMT_ARG(devset
));
2555 if ((unit
> MAX_CPU_UNITS_PER_BOARD
) || (unit
< 0)) {
2557 "%s: invalid cpu unit# = %d",
2562 * Generate a devset that includes all the
2563 * cores of a CMP device. If this is not a
2564 * CMP, the extra cores will be eliminated
2565 * later since they are not present. This is
2566 * also true for CMP devices that do not have
2569 devset
= DEVSET(SBD_COMP_CMP
, unit
);
2572 PR_ALL("%s: CPU devset = " DEVSET_FMT_STR
"\n",
2573 f
, DEVSET_FMT_ARG(devset
));
2577 if (unit
== SBD_NULL_UNIT
) {
2582 if ((unit
> MAX_MEM_UNITS_PER_BOARD
) || (unit
< 0)) {
2584 "%s: invalid mem unit# = %d",
2588 devset
= DEVSET(cid
->c_type
, unit
);
2590 PR_ALL("%s: MEM devset = " DEVSET_FMT_STR
"\n",
2591 f
, DEVSET_FMT_ARG(devset
));
2595 if ((unit
> MAX_IO_UNITS_PER_BOARD
) || (unit
< 0)) {
2597 "%s: invalid io unit# = %d",
2601 devset
= DEVSET(cid
->c_type
, unit
);
2603 PR_ALL("%s: IO devset = " DEVSET_FMT_STR
"\n",
2604 f
, DEVSET_FMT_ARG(devset
));
2608 case SBD_COMP_UNKNOWN
:
2617 * Converts a dynamic attachment point name to a SBD_COMP_* type.
2618 * Returns SDB_COMP_UNKNOWN if name is not recognized.
2621 dr_dev_type_to_nt(char *type
)
2625 for (i
= 0; dr_devattr
[i
].s_nodetype
!= SBD_COMP_UNKNOWN
; i
++)
2626 if (strcmp(dr_devattr
[i
].s_devtype
, type
) == 0)
2629 return (dr_devattr
[i
].s_nodetype
);
2633 * Converts a SBD_COMP_* type to a dynamic attachment point name.
2634 * Return NULL if SBD_COMP_ type is not recognized.
2637 dr_nt_to_dev_type(int nt
)
2641 for (i
= 0; dr_devattr
[i
].s_nodetype
!= SBD_COMP_UNKNOWN
; i
++)
2642 if (dr_devattr
[i
].s_nodetype
== nt
)
2645 return (dr_devattr
[i
].s_devtype
);
2649 * State transition policy is that if there is some component for which
2650 * the state transition is valid, then let it through. The exception is
2651 * SBD_CMD_DISCONNECT. On disconnect, the state transition must be valid
2652 * for ALL components.
2653 * Returns the state that is in error, if any.
2656 dr_check_transition(dr_board_t
*bp
, dr_devset_t
*devsetp
,
2657 struct dr_state_trans
*transp
, int cmd
)
2662 dr_common_unit_t
*cp
;
2663 static fn_t f
= "dr_check_transition";
2667 if (DEVSET_IN_SET(devset
, SBD_COMP_CPU
, DEVSET_ANYUNIT
)) {
2668 for (ut
= 0; ut
< MAX_CPU_UNITS_PER_BOARD
; ut
++) {
2669 if (DEVSET_IN_SET(devset
, SBD_COMP_CPU
, ut
) == 0)
2672 cp
= dr_get_common_unit(bp
, SBD_COMP_CPU
, ut
);
2673 s
= (int)cp
->sbdev_state
;
2674 if (!DR_DEV_IS_PRESENT(cp
)) {
2675 DEVSET_DEL(devset
, SBD_COMP_CPU
, ut
);
2677 if (transp
->x_op
[s
].x_rv
) {
2680 DEVSET_DEL(devset
, SBD_COMP_CPU
, ut
);
2685 if (DEVSET_IN_SET(devset
, SBD_COMP_MEM
, DEVSET_ANYUNIT
)) {
2686 for (ut
= 0; ut
< MAX_MEM_UNITS_PER_BOARD
; ut
++) {
2687 if (DEVSET_IN_SET(devset
, SBD_COMP_MEM
, ut
) == 0)
2690 cp
= dr_get_common_unit(bp
, SBD_COMP_MEM
, ut
);
2691 s
= (int)cp
->sbdev_state
;
2692 if (!DR_DEV_IS_PRESENT(cp
)) {
2693 DEVSET_DEL(devset
, SBD_COMP_MEM
, ut
);
2695 if (transp
->x_op
[s
].x_rv
) {
2698 DEVSET_DEL(devset
, SBD_COMP_MEM
, ut
);
2703 if (DEVSET_IN_SET(devset
, SBD_COMP_IO
, DEVSET_ANYUNIT
)) {
2704 for (ut
= 0; ut
< MAX_IO_UNITS_PER_BOARD
; ut
++) {
2705 if (DEVSET_IN_SET(devset
, SBD_COMP_IO
, ut
) == 0)
2708 cp
= dr_get_common_unit(bp
, SBD_COMP_IO
, ut
);
2709 s
= (int)cp
->sbdev_state
;
2710 if (!DR_DEV_IS_PRESENT(cp
)) {
2711 DEVSET_DEL(devset
, SBD_COMP_IO
, ut
);
2713 if (transp
->x_op
[s
].x_rv
) {
2716 DEVSET_DEL(devset
, SBD_COMP_IO
, ut
);
2722 PR_ALL("%s: requested devset = 0x%x, final devset = 0x%x\n",
2723 f
, (uint_t
)*devsetp
, (uint_t
)devset
);
2727 * If there are some remaining components for which
2728 * this state transition is valid, then allow them
2729 * through, otherwise if none are left then return
2730 * the state error. The exception is SBD_CMD_DISCONNECT.
2731 * On disconnect, the state transition must be valid for ALL
2734 if (cmd
== SBD_CMD_DISCONNECT
)
2736 return (devset
? 0 : state_err
);
2740 dr_device_transition(dr_common_unit_t
*cp
, dr_state_t st
)
2742 PR_STATE("%s STATE %s(%d) -> %s(%d)\n",
2744 state_str
[cp
->sbdev_state
], cp
->sbdev_state
,
2747 cp
->sbdev_state
= st
;
2748 if (st
== DR_STATE_CONFIGURED
) {
2749 cp
->sbdev_ostate
= SBD_STAT_CONFIGURED
;
2750 if (cp
->sbdev_bp
->b_ostate
!= SBD_STAT_CONFIGURED
) {
2751 cp
->sbdev_bp
->b_ostate
= SBD_STAT_CONFIGURED
;
2752 (void) drv_getparm(TIME
,
2753 (void *) &cp
->sbdev_bp
->b_time
);
2756 cp
->sbdev_ostate
= SBD_STAT_UNCONFIGURED
;
2758 (void) drv_getparm(TIME
, (void *) &cp
->sbdev_time
);
2762 dr_board_transition(dr_board_t
*bp
, dr_state_t st
)
2764 PR_STATE("BOARD %d STATE: %s(%d) -> %s(%d)\n",
2766 state_str
[bp
->b_state
], bp
->b_state
,
2773 dr_op_err(int ce
, dr_handle_t
*hp
, int code
, char *fmt
, ...)
2778 va_start(args
, fmt
);
2779 err
= drerr_new_v(code
, fmt
, args
);
2782 if (ce
!= CE_IGNORE
)
2783 sbd_err_log(err
, ce
);
2785 DRERR_SET_C(&hp
->h_err
, &err
);
2789 dr_dev_err(int ce
, dr_common_unit_t
*cp
, int code
)
2793 err
= drerr_new(0, code
, cp
->sbdev_path
, NULL
);
2795 if (ce
!= CE_IGNORE
)
2796 sbd_err_log(err
, ce
);
2798 DRERR_SET_C(&cp
->sbdev_error
, &err
);
2802 * A callback routine. Called from the drmach layer as a result of
2803 * call to drmach_board_find_devices from dr_init_devlists.
2805 static sbd_error_t
*
2806 dr_dev_found(void *data
, const char *name
, int unum
, drmachid_t id
)
2808 dr_board_t
*bp
= data
;
2811 static fn_t f
= "dr_dev_found";
2813 PR_ALL("%s (board = %d, name = %s, unum = %d, id = %p)...\n",
2814 f
, bp
->b_num
, name
, unum
, id
);
2816 nt
= dr_dev_type_to_nt((char *)name
);
2817 if (nt
== SBD_COMP_UNKNOWN
) {
2819 * this should not happen. When it does, it indicates
2820 * a missmatch in devices supported by the drmach layer
2821 * vs devices supported by this layer.
2823 return (DR_INTERNAL_ERROR());
2826 dp
= DR_GET_BOARD_DEVUNIT(bp
, nt
, unum
);
2829 ASSERT(dp
->du_common
.sbdev_bp
== bp
);
2830 ASSERT(dp
->du_common
.sbdev_unum
== unum
);
2831 ASSERT(dp
->du_common
.sbdev_type
== nt
);
2833 /* render dynamic attachment point path of this unit */
2834 (void) snprintf(dp
->du_common
.sbdev_path
,
2835 sizeof (dp
->du_common
.sbdev_path
), "%s::%s%d",
2836 bp
->b_path
, name
, DR_UNUM2SBD_UNUM(unum
, nt
));
2838 dp
->du_common
.sbdev_id
= id
;
2839 DR_DEV_SET_PRESENT(&dp
->du_common
);
2846 static sbd_error_t
*
2847 dr_init_devlists(dr_board_t
*bp
)
2852 static fn_t f
= "dr_init_devlists";
2854 PR_ALL("%s (%s)...\n", f
, bp
->b_path
);
2857 ASSERT(bp
->b_ndev
== 0);
2859 DR_DEVS_DISCONNECT(bp
, (uint_t
)-1);
2862 * This routine builds the board's devlist and initializes
2863 * the common portion of the unit data structures.
2864 * Note: because the common portion is considered
2865 * uninitialized, the dr_get_*_unit() routines can not
2870 * Clear out old entries, if any.
2872 for (i
= 0; i
< MAX_CPU_UNITS_PER_BOARD
; i
++) {
2873 dp
= DR_GET_BOARD_DEVUNIT(bp
, SBD_COMP_CPU
, i
);
2875 bzero(dp
, sizeof (*dp
));
2876 dp
->du_common
.sbdev_bp
= bp
;
2877 dp
->du_common
.sbdev_unum
= i
;
2878 dp
->du_common
.sbdev_type
= SBD_COMP_CPU
;
2881 for (i
= 0; i
< MAX_MEM_UNITS_PER_BOARD
; i
++) {
2882 dp
= DR_GET_BOARD_DEVUNIT(bp
, SBD_COMP_MEM
, i
);
2884 bzero(dp
, sizeof (*dp
));
2885 dp
->du_common
.sbdev_bp
= bp
;
2886 dp
->du_common
.sbdev_unum
= i
;
2887 dp
->du_common
.sbdev_type
= SBD_COMP_MEM
;
2890 for (i
= 0; i
< MAX_IO_UNITS_PER_BOARD
; i
++) {
2891 dp
= DR_GET_BOARD_DEVUNIT(bp
, SBD_COMP_IO
, i
);
2893 bzero(dp
, sizeof (*dp
));
2894 dp
->du_common
.sbdev_bp
= bp
;
2895 dp
->du_common
.sbdev_unum
= i
;
2896 dp
->du_common
.sbdev_type
= SBD_COMP_IO
;
2901 /* find devices on this board */
2902 err
= drmach_board_find_devices(
2903 bp
->b_id
, bp
, dr_dev_found
);
2910 * Return the unit number of the respective drmachid if
2911 * it's found to be attached.
2914 dr_check_unit_attached(dr_common_unit_t
*cp
)
2917 processorid_t cpuid
;
2918 uint64_t basepa
, endpa
;
2920 extern struct memlist
*phys_install
;
2923 static fn_t f
= "dr_check_unit_attached";
2925 switch (cp
->sbdev_type
) {
2927 err
= drmach_cpu_get_id(cp
->sbdev_id
, &cpuid
);
2929 DRERR_SET_C(&cp
->sbdev_error
, &err
);
2933 mutex_enter(&cpu_lock
);
2934 if (cpu_get(cpuid
) == NULL
)
2936 mutex_exit(&cpu_lock
);
2940 err
= drmach_mem_get_slice_info(cp
->sbdev_id
,
2941 &basepa
, &endpa
, NULL
);
2943 DRERR_SET_C(&cp
->sbdev_error
, &err
);
2949 * Check if base address is in phys_install.
2951 memlist_read_lock();
2952 for (ml
= phys_install
; ml
; ml
= ml
->ml_next
)
2953 if ((endpa
<= ml
->ml_address
) ||
2954 (basepa
>= (ml
->ml_address
+ ml
->ml_size
)))
2958 memlist_read_unlock();
2964 err
= drmach_io_is_attached(cp
->sbdev_id
, &yes
);
2966 DRERR_SET_C(&cp
->sbdev_error
, &err
);
2974 PR_ALL("%s: unexpected nodetype(%d) for id 0x%p\n",
2975 f
, cp
->sbdev_type
, cp
->sbdev_id
);
2984 * See if drmach recognizes the passthru command. DRMACH expects the
2985 * id to identify the thing to which the command is being applied. Using
2986 * nonsense SBD terms, that information has been perversely encoded in the
2987 * c_id member of the sbd_cmd_t structure. This logic reads those tea
2988 * leaves, finds the associated drmach id, then calls drmach to process
2989 * the passthru command.
2992 dr_pt_try_drmach(dr_handle_t
*hp
)
2994 dr_board_t
*bp
= hp
->h_bd
;
2995 sbd_comp_id_t
*comp_id
= &hp
->h_sbdcmd
.cmd_cm
.c_id
;
2998 if (comp_id
->c_type
== SBD_COMP_NONE
) {
3003 nt
= dr_dev_type_to_nt(comp_id
->c_name
);
3004 if (nt
== SBD_COMP_UNKNOWN
) {
3005 dr_op_err(CE_IGNORE
, hp
, ESBD_INVAL
, comp_id
->c_name
);
3008 /* pt command applied to dynamic attachment point */
3009 dr_common_unit_t
*cp
;
3010 cp
= dr_get_common_unit(bp
, nt
, comp_id
->c_unit
);
3015 if (hp
->h_err
== NULL
)
3016 hp
->h_err
= drmach_passthru(id
, &hp
->h_opts
);
3018 return (hp
->h_err
== NULL
? 0 : -1);
3022 dr_pt_ioctl(dr_handle_t
*hp
)
3028 static fn_t f
= "dr_pt_ioctl";
3030 PR_ALL("%s...\n", f
);
3032 sz
= hp
->h_opts
.size
;
3033 copts
= hp
->h_opts
.copts
;
3035 if (sz
== 0 || copts
== NULL
) {
3036 cmn_err(CE_WARN
, "%s: invalid passthru args", f
);
3041 for (cmd
= 0; cmd
< (sizeof (pt_arr
) / sizeof (pt_arr
[0])); cmd
++) {
3042 len
= strlen(pt_arr
[cmd
].pt_name
);
3043 found
= (strncmp(pt_arr
[cmd
].pt_name
, copts
, len
) == 0);
3049 rv
= (*pt_arr
[cmd
].pt_func
)(hp
);
3051 rv
= dr_pt_try_drmach(hp
);
3057 * Called at driver load time to determine the state and condition
3058 * of an existing board in the system.
3061 dr_board_discovery(dr_board_t
*bp
)
3064 dr_devset_t devs_lost
, devs_attached
= 0;
3068 static fn_t f
= "dr_board_discovery";
3070 if (DR_DEVS_PRESENT(bp
) == 0) {
3071 PR_ALL("%s: board %d has no devices present\n",
3077 * Check for existence of cpus.
3079 for (i
= 0; i
< MAX_CPU_UNITS_PER_BOARD
; i
++) {
3080 cp
= dr_get_cpu_unit(bp
, i
);
3082 if (!DR_DEV_IS_PRESENT(&cp
->sbc_cm
))
3085 if (dr_check_unit_attached(&cp
->sbc_cm
) >= 0) {
3086 DR_DEV_SET_ATTACHED(&cp
->sbc_cm
);
3087 DEVSET_ADD(devs_attached
, SBD_COMP_CPU
, i
);
3088 PR_ALL("%s: board %d, cpu-unit %d - attached\n",
3091 dr_init_cpu_unit(cp
);
3095 * Check for existence of memory.
3097 for (i
= 0; i
< MAX_MEM_UNITS_PER_BOARD
; i
++) {
3098 mp
= dr_get_mem_unit(bp
, i
);
3100 if (!DR_DEV_IS_PRESENT(&mp
->sbm_cm
))
3103 if (dr_check_unit_attached(&mp
->sbm_cm
) >= 0) {
3104 DR_DEV_SET_ATTACHED(&mp
->sbm_cm
);
3105 DEVSET_ADD(devs_attached
, SBD_COMP_MEM
, i
);
3106 PR_ALL("%s: board %d, mem-unit %d - attached\n",
3109 dr_init_mem_unit(mp
);
3113 * Check for i/o state.
3115 for (i
= 0; i
< MAX_IO_UNITS_PER_BOARD
; i
++) {
3116 ip
= dr_get_io_unit(bp
, i
);
3118 if (!DR_DEV_IS_PRESENT(&ip
->sbi_cm
))
3121 if (dr_check_unit_attached(&ip
->sbi_cm
) >= 0) {
3125 DR_DEV_SET_ATTACHED(&ip
->sbi_cm
);
3126 DEVSET_ADD(devs_attached
, SBD_COMP_IO
, i
);
3127 PR_ALL("%s: board %d, io-unit %d - attached\n",
3130 dr_init_io_unit(ip
);
3133 DR_DEVS_CONFIGURE(bp
, devs_attached
);
3134 if (devs_attached
&& ((devs_lost
= DR_DEVS_UNATTACHED(bp
)) != 0)) {
3138 * It is not legal on board discovery to have a
3139 * board that is only partially attached. A board
3140 * is either all attached or all connected. If a
3141 * board has at least one attached device, then
3142 * the the remaining devices, if any, must have
3143 * been lost or disconnected. These devices can
3144 * only be recovered by a full attach from scratch.
3145 * Note that devices previously in the unreferenced
3146 * state are subsequently lost until the next full
3147 * attach. This is necessary since the driver unload
3148 * that must have occurred would have wiped out the
3149 * information necessary to re-configure the device
3150 * back online, e.g. memlist.
3152 PR_ALL("%s: some devices LOST (" DEVSET_FMT_STR
")...\n",
3153 f
, DEVSET_FMT_ARG(devs_lost
));
3155 for (ut
= 0; ut
< MAX_CPU_UNITS_PER_BOARD
; ut
++) {
3156 if (!DEVSET_IN_SET(devs_lost
, SBD_COMP_CPU
, ut
))
3159 cp
= dr_get_cpu_unit(bp
, ut
);
3160 dr_device_transition(&cp
->sbc_cm
, DR_STATE_EMPTY
);
3163 for (ut
= 0; ut
< MAX_MEM_UNITS_PER_BOARD
; ut
++) {
3164 if (!DEVSET_IN_SET(devs_lost
, SBD_COMP_MEM
, ut
))
3167 mp
= dr_get_mem_unit(bp
, ut
);
3168 dr_device_transition(&mp
->sbm_cm
, DR_STATE_EMPTY
);
3171 for (ut
= 0; ut
< MAX_IO_UNITS_PER_BOARD
; ut
++) {
3172 if (!DEVSET_IN_SET(devs_lost
, SBD_COMP_IO
, ut
))
3175 ip
= dr_get_io_unit(bp
, ut
);
3176 dr_device_transition(&ip
->sbi_cm
, DR_STATE_EMPTY
);
3179 DR_DEVS_DISCONNECT(bp
, devs_lost
);
3184 dr_board_init(dr_board_t
*bp
, dev_info_t
*dip
, int bd
)
3188 mutex_init(&bp
->b_lock
, NULL
, MUTEX_DRIVER
, NULL
);
3189 mutex_init(&bp
->b_slock
, NULL
, MUTEX_DRIVER
, NULL
);
3190 cv_init(&bp
->b_scv
, NULL
, CV_DRIVER
, NULL
);
3191 bp
->b_rstate
= SBD_STAT_EMPTY
;
3192 bp
->b_ostate
= SBD_STAT_UNCONFIGURED
;
3193 bp
->b_cond
= SBD_COND_UNKNOWN
;
3194 (void) drv_getparm(TIME
, (void *)&bp
->b_time
);
3196 (void) drmach_board_lookup(bd
, &bp
->b_id
);
3200 bp
->b_dev
[DEVSET_NIX(SBD_COMP_CPU
)] = GETSTRUCT(dr_dev_unit_t
,
3201 MAX_CPU_UNITS_PER_BOARD
);
3203 bp
->b_dev
[DEVSET_NIX(SBD_COMP_MEM
)] = GETSTRUCT(dr_dev_unit_t
,
3204 MAX_MEM_UNITS_PER_BOARD
);
3206 bp
->b_dev
[DEVSET_NIX(SBD_COMP_IO
)] = GETSTRUCT(dr_dev_unit_t
,
3207 MAX_IO_UNITS_PER_BOARD
);
3210 * Initialize the devlists
3212 err
= dr_init_devlists(bp
);
3214 sbd_err_clear(&err
);
3215 dr_board_destroy(bp
);
3217 } else if (bp
->b_ndev
== 0) {
3218 dr_board_transition(bp
, DR_STATE_EMPTY
);
3221 * Couldn't have made it down here without
3222 * having found at least one device.
3224 ASSERT(DR_DEVS_PRESENT(bp
) != 0);
3226 * Check the state of any possible devices on the
3229 dr_board_discovery(bp
);
3233 if (DR_DEVS_UNATTACHED(bp
) == 0) {
3235 * The board has no unattached devices, therefore
3236 * by reason of insanity it must be configured!
3238 dr_board_transition(bp
, DR_STATE_CONFIGURED
);
3239 bp
->b_ostate
= SBD_STAT_CONFIGURED
;
3240 bp
->b_rstate
= SBD_STAT_CONNECTED
;
3241 bp
->b_cond
= SBD_COND_OK
;
3242 (void) drv_getparm(TIME
, (void *)&bp
->b_time
);
3243 } else if (DR_DEVS_ATTACHED(bp
)) {
3244 dr_board_transition(bp
, DR_STATE_PARTIAL
);
3245 bp
->b_ostate
= SBD_STAT_CONFIGURED
;
3246 bp
->b_rstate
= SBD_STAT_CONNECTED
;
3247 bp
->b_cond
= SBD_COND_OK
;
3248 (void) drv_getparm(TIME
, (void *)&bp
->b_time
);
3250 dr_board_transition(bp
, DR_STATE_CONNECTED
);
3251 bp
->b_rstate
= SBD_STAT_CONNECTED
;
3252 (void) drv_getparm(TIME
, (void *)&bp
->b_time
);
3260 dr_board_destroy(dr_board_t
*bp
)
3262 PR_ALL("dr_board_destroy: num %d, path %s\n",
3263 bp
->b_num
, bp
->b_path
);
3265 dr_board_transition(bp
, DR_STATE_EMPTY
);
3266 bp
->b_rstate
= SBD_STAT_EMPTY
;
3267 (void) drv_getparm(TIME
, (void *)&bp
->b_time
);
3270 * Free up MEM unit structs.
3272 FREESTRUCT(bp
->b_dev
[DEVSET_NIX(SBD_COMP_MEM
)],
3273 dr_dev_unit_t
, MAX_MEM_UNITS_PER_BOARD
);
3274 bp
->b_dev
[DEVSET_NIX(SBD_COMP_MEM
)] = NULL
;
3276 * Free up CPU unit structs.
3278 FREESTRUCT(bp
->b_dev
[DEVSET_NIX(SBD_COMP_CPU
)],
3279 dr_dev_unit_t
, MAX_CPU_UNITS_PER_BOARD
);
3280 bp
->b_dev
[DEVSET_NIX(SBD_COMP_CPU
)] = NULL
;
3282 * Free up IO unit structs.
3284 FREESTRUCT(bp
->b_dev
[DEVSET_NIX(SBD_COMP_IO
)],
3285 dr_dev_unit_t
, MAX_IO_UNITS_PER_BOARD
);
3286 bp
->b_dev
[DEVSET_NIX(SBD_COMP_IO
)] = NULL
;
3288 mutex_destroy(&bp
->b_lock
);
3289 mutex_destroy(&bp
->b_slock
);
3290 cv_destroy(&bp
->b_scv
);
3293 * Reset the board structure to its initial state, otherwise it will
3294 * cause trouble on the next call to dr_board_init() for the same board.
3295 * dr_board_init() may be called multiple times for the same board
3296 * if DR driver fails to initialize some boards.
3298 bzero(bp
, sizeof (*bp
));
3302 dr_lock_status(dr_board_t
*bp
)
3304 mutex_enter(&bp
->b_slock
);
3305 while (bp
->b_sflags
& DR_BSLOCK
)
3306 cv_wait(&bp
->b_scv
, &bp
->b_slock
);
3307 bp
->b_sflags
|= DR_BSLOCK
;
3308 mutex_exit(&bp
->b_slock
);
3312 dr_unlock_status(dr_board_t
*bp
)
3314 mutex_enter(&bp
->b_slock
);
3315 bp
->b_sflags
&= ~DR_BSLOCK
;
3316 cv_signal(&bp
->b_scv
);
3317 mutex_exit(&bp
->b_slock
);
3321 * Extract flags passed via ioctl.
3324 dr_cmd_flags(dr_handle_t
*hp
)
3326 return (hp
->h_sbdcmd
.cmd_cm
.c_flags
);