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 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
29 #include <sys/types.h>
32 #include <sys/sunddi.h>
33 #include <sys/modctl.h>
34 #include <sys/sunndi.h>
35 #include <sys/ddi_impldefs.h>
36 #include <sys/obpdefs.h>
37 #include <sys/cmn_err.h>
38 #include <sys/errno.h>
40 #include <sys/debug.h>
41 #include <sys/sysmacros.h>
42 #include <sys/autoconf.h>
44 #include <sys/serengeti.h>
46 #include <sys/sgsbbc_mailbox.h>
47 #include <sys/sgevents.h>
48 #include <sys/sysevent.h>
49 #include <sys/sysevent/dr.h>
50 #include <sys/sysevent/eventdefs.h>
51 #include <sys/ndi_impldefs.h>
52 #include <sys/ddifm.h>
53 #include <sys/ndifm.h>
54 #include <sys/sbd_ioctl.h>
56 /* Useful debugging Stuff */
57 #include <sys/nexusdebug.h>
62 * This module is a nexus driver designed to support the ssm nexus driver
63 * and all children below it. This driver does not handle any of the
64 * DDI functions passed up to it by the ssm driver, but instead allows
65 * them to bubble up to the root node.
72 extern int plat_max_boards();
75 ssm_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
, void **result
);
78 ssm_attach(dev_info_t
*, ddi_attach_cmd_t
);
81 ssm_detach(dev_info_t
*, ddi_detach_cmd_t
);
84 ssm_open(dev_t
*, int, int, cred_t
*);
87 ssm_close(dev_t
, int, int, cred_t
*);
90 ssm_ioctl(dev_t
, int, intptr_t, int, cred_t
*, int *);
93 ssm_ctlops(dev_info_t
*, dev_info_t
*, ddi_ctl_enum_t
, void *, void *);
96 ssm_make_nodes(dev_info_t
*dip
, int instance
, int ssm_nodeid
);
99 ssm_generate_event(int node
, int board
, int hint
);
103 * Register error handling callback with our parent. We will just call
104 * our children's error callbacks and return their status.
107 ssm_err_callback(dev_info_t
*dip
, ddi_fm_error_t
*derr
, const void *impl_data
);
110 * fm_init busop to initialize our children
113 ssm_fm_init_child(dev_info_t
*dip
, dev_info_t
*tdip
, int cap
,
114 ddi_iblock_cookie_t
*ibc
);
117 * init/fini routines to alloc/dealloc fm structures and
118 * register/unregister our callback.
121 ssm_fm_init(struct ssm_soft_state
*softsp
);
124 ssm_fm_fini(struct ssm_soft_state
*softsp
);
128 * We want to register the event handlers once for all instances. In the
129 * other hand we have register them after the sbbc has been attached.
130 * event_initialize gives us the logic of only registering the events only
133 int event_initialized
= 0;
134 uint_t
ssm_dr_event_handler(char *);
137 * Event lock and state
139 static kmutex_t ssm_event_lock
;
143 * DR event msg and payload
145 static sbbc_msg_t event_msg
;
146 static sg_system_fru_descriptor_t payload
;
148 struct ssm_node2inst
{
149 int nodeid
; /* serengeti node #, NOT prom nodeid */
151 struct ssm_node2inst
*next
;
153 static kmutex_t ssm_node2inst_lock
;
154 static struct ssm_node2inst ssm_node2inst_map
= {-1, -1, NULL
};
158 * Configuration data structures
160 static struct bus_ops ssm_bus_ops
= {
162 ddi_bus_map
, /* map */
163 0, /* get_intrspec */
164 0, /* add_intrspec */
165 0, /* remove_intrspec */
166 i_ddi_map_fault
, /* map_fault */
174 ddi_dma_mctl
, /* dma_ctl */
175 ssm_ctlops
, /* ctl */
176 ddi_bus_prop_op
, /* prop_op */
177 ndi_busop_get_eventcookie
,
178 ndi_busop_add_eventcall
,
179 ndi_busop_remove_eventcall
,
192 static struct cb_ops ssm_cb_ops
= {
194 ssm_close
, /* close */
195 nodev
, /* strategy */
200 ssm_ioctl
, /* ioctl */
205 ddi_prop_op
, /* cb_prop_op */
206 NULL
, /* streamtab */
207 D_NEW
| D_MP
| D_HOTPLUG
, /* Driver compatibility flag */
209 nodev
, /* int (*cb_aread)() */
210 nodev
/* int (*cb_awrite)() */
213 static struct dev_ops ssm_ops
= {
214 DEVO_REV
, /* devo_rev, */
216 ssm_info
, /* getinfo */
217 nulldev
, /* identify */
219 ssm_attach
, /* attach */
220 ssm_detach
, /* detach */
222 &ssm_cb_ops
, /* driver operations */
223 &ssm_bus_ops
, /* bus_ops */
225 ddi_quiesce_not_needed
, /* quiesce */
231 static void *ssm_softstates
; /* ssm soft state hook */
233 extern struct mod_ops mod_driverops
;
235 static struct modldrv modldrv
= {
236 &mod_driverops
, /* Type of module. This one is a driver */
237 "SSM Nexus", /* name of module */
238 &ssm_ops
, /* driver ops */
241 static struct modlinkage modlinkage
= {
247 static int ssm_loaded_sbd
= FALSE
;
249 static int init_child(dev_info_t
*child
);
252 * These are the module initialization routines.
261 debug_print_level
= 0x0;
264 /* Initialize soft state pointer. */
265 if ((error
= ddi_soft_state_init(&ssm_softstates
,
266 sizeof (struct ssm_soft_state
), SSM_MAX_INSTANCES
)) != 0)
269 /* Install the module. */
270 error
= mod_install(&modlinkage
);
272 ddi_soft_state_fini(&ssm_softstates
);
274 mutex_init(&ssm_lock
, NULL
, MUTEX_DRIVER
, NULL
);
284 /* Remove the module. */
285 if ((error
= mod_remove(&modlinkage
)) != 0)
289 * Unregister the event handler
291 (void) sbbc_mbox_unreg_intr(MBOX_EVENT_GENERIC
, ssm_dr_event_handler
);
292 mutex_destroy(&ssm_event_lock
);
294 /* Free the soft state info. */
295 ddi_soft_state_fini(&ssm_softstates
);
296 mutex_destroy(&ssm_lock
);
302 _info(struct modinfo
*modinfop
)
304 return (mod_info(&modlinkage
, modinfop
));
307 /* device driver entry points */
315 ssm_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
, void **result
)
320 if (infocmd
== DDI_INFO_DEVT2INSTANCE
) {
322 instance
= (getminor(dev
) >> SSM_INSTANCE_SHIFT
);
323 *result
= (void *)(uintptr_t)instance
;
324 return (DDI_SUCCESS
);
326 return (DDI_FAILURE
);
330 * attach entry point:
334 ssm_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
337 struct ssm_soft_state
*softsp
;
338 struct ssm_node2inst
*prev
, *sp
, *tsp
;
340 DPRINTF(SSM_ATTACH_DEBUG
, ("ssm_attach\n"));
347 return (DDI_SUCCESS
);
350 return (DDI_FAILURE
);
353 instance
= ddi_get_instance(devi
);
355 if (ddi_soft_state_zalloc(ssm_softstates
, instance
) != DDI_SUCCESS
)
356 return (DDI_FAILURE
);
358 softsp
= ddi_get_soft_state(ssm_softstates
, instance
);
360 /* Set the dip in the soft state */
362 softsp
->top_node
= devi
;
363 mutex_init(&softsp
->ssm_sft_lock
, NULL
, MUTEX_DRIVER
, NULL
);
365 DPRINTF(SSM_ATTACH_DEBUG
, ("ssm-%d: devi= 0x%p, softsp=0x%p\n",
366 instance
, (void *)devi
, (void *)softsp
));
368 if ((softsp
->ssm_nodeid
= (int)ddi_getprop(DDI_DEV_T_ANY
, softsp
->dip
,
369 DDI_PROP_DONTPASS
, "nodeid", -1)) == -1) {
370 cmn_err(CE_WARN
, "ssm%d: unable to retrieve %s property",
372 ddi_soft_state_free(ssm_softstates
, instance
);
373 return (DDI_FAILURE
);
376 /* nothing to suspend/resume here */
377 (void) ddi_prop_create(DDI_DEV_T_NONE
, devi
, DDI_PROP_CANSLEEP
,
378 "pm-hardware-state", (caddr_t
)"no-suspend-resume",
379 strlen("no-suspend-resume") + 1);
382 if (ddi_create_minor_node(devi
, "debug", S_IFCHR
, instance
,
383 DDI_NT_NEXUS
, 0) != DDI_SUCCESS
) {
384 ddi_soft_state_free(ssm_softstates
, instance
);
385 return (DDI_FAILURE
);
389 if (ssm_make_nodes(devi
, instance
, softsp
->ssm_nodeid
)) {
390 cmn_err(CE_WARN
, "ssm:%s:%d: failed to make nodes",
391 ddi_driver_name(devi
), instance
);
392 ddi_remove_minor_node(devi
, NULL
);
393 ddi_soft_state_free(ssm_softstates
, instance
);
394 return (DDI_FAILURE
);
397 ddi_report_dev(devi
);
399 if (event_initialized
== 0) {
402 * Register DR event handler
404 mutex_init(&ssm_event_lock
, NULL
, MUTEX_DRIVER
, NULL
);
405 event_msg
.msg_buf
= (caddr_t
)&payload
;
406 event_msg
.msg_len
= sizeof (payload
);
408 rv
= sbbc_mbox_reg_intr(MBOX_EVENT_GENERIC
,
409 ssm_dr_event_handler
, &event_msg
,
410 (uint_t
*)&ssm_event_state
, &ssm_event_lock
);
413 event_initialized
= 1;
417 * Preallocate to avoid sleeping with ssm_node2inst_lock held -
418 * low level interrupts use this mutex.
420 tsp
= kmem_zalloc(sizeof (struct ssm_node2inst
), KM_SLEEP
);
422 mutex_enter(&ssm_node2inst_lock
);
424 for (prev
= NULL
, sp
= &ssm_node2inst_map
; sp
!= NULL
;
425 prev
= sp
, sp
= sp
->next
) {
426 ASSERT(sp
->inst
!= instance
);
427 ASSERT(sp
->nodeid
!= softsp
->ssm_nodeid
);
433 ASSERT(prev
->next
== NULL
);
434 sp
= prev
->next
= tsp
;
440 sp
->nodeid
= softsp
->ssm_nodeid
;
442 mutex_exit(&ssm_node2inst_lock
);
445 kmem_free(tsp
, sizeof (struct ssm_node2inst
));
447 return (DDI_SUCCESS
);
451 * detach entry point:
455 ssm_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
)
458 int (*sbd_teardown_instance
) (int, caddr_t
);
459 ssm_sbdp_info_t sbdp_info
;
460 struct ssm_soft_state
*softsp
;
461 struct ssm_node2inst
*prev
, *sp
;
463 instance
= ddi_get_instance(devi
);
464 softsp
= ddi_get_soft_state(ssm_softstates
, instance
);
466 if (softsp
== NULL
) {
468 "ssm_open bad instance number %d", instance
);
472 instance
= ddi_get_instance(devi
);
476 ddi_remove_minor_node(devi
, NULL
);
478 sbd_teardown_instance
= (int (*) (int, caddr_t
))
479 modlookup("misc/sbd", "sbd_teardown_instance");
481 if (!sbd_teardown_instance
) {
482 cmn_err(CE_WARN
, "cannot find sbd_teardown_instance");
483 return (DDI_FAILURE
);
486 sbdp_info
.instance
= instance
;
487 sbdp_info
.wnode
= softsp
->ssm_nodeid
;
488 rv
= (*sbd_teardown_instance
)(instance
, (caddr_t
)&sbdp_info
);
490 if (rv
!= DDI_SUCCESS
) {
491 cmn_err(CE_WARN
, "cannot run sbd_teardown_instance");
492 return (DDI_FAILURE
);
495 mutex_destroy(&softsp
->ssm_sft_lock
);
496 ddi_soft_state_free(ssm_softstates
, instance
);
498 mutex_enter(&ssm_node2inst_lock
);
499 for (prev
= NULL
, sp
= &ssm_node2inst_map
; sp
!= NULL
;
500 prev
= sp
, sp
= sp
->next
) {
501 /* Only the head of the list can persist if unused */
502 ASSERT(prev
== NULL
|| sp
->inst
!= -1);
503 if (sp
->inst
== instance
)
508 if (sp
!= &ssm_node2inst_map
) {
509 prev
->next
= sp
->next
;
510 kmem_free(sp
, sizeof (struct ssm_node2inst
));
513 * Invalidate the head element, but retain the rest
514 * of the list - "next" is still valid.
520 mutex_exit(&ssm_node2inst_lock
);
522 return (DDI_SUCCESS
);
525 return (DDI_SUCCESS
);
528 return (DDI_FAILURE
);
532 extern void make_ddi_ppd(dev_info_t
*, struct ddi_parent_private_data
**);
533 extern struct ddi_parent_private_data
*init_regspec_64(dev_info_t
*);
536 name_child(dev_info_t
*child
, char *name
, int namelen
)
539 struct ddi_parent_private_data
*pdptr
;
542 extern uint_t root_phys_addr_lo_mask
;
544 make_ddi_ppd(child
, &pdptr
);
545 ddi_set_parent_data(child
, pdptr
);
548 if (sparc_pd_getnreg(child
) == 0)
549 return (DDI_SUCCESS
);
551 rp
= sparc_pd_getreg(child
, 0);
553 portid
= ddi_prop_get_int(DDI_DEV_T_ANY
, child
,
554 DDI_PROP_DONTPASS
, "portid", -1);
556 cmn_err(CE_WARN
, "could not find portid property in %s",
557 DEVI(child
)->devi_node_name
);
559 regbase
= rp
->regspec_addr
& root_phys_addr_lo_mask
;
561 (void) snprintf(name
, namelen
, "%x,%x", portid
, regbase
);
562 return (DDI_SUCCESS
);
566 init_child(dev_info_t
*child
)
568 char name
[MAXNAMELEN
];
570 (void) name_child(child
, name
, MAXNAMELEN
);
571 ddi_set_name_addr(child
, name
);
572 if ((ndi_dev_is_persistent_node(child
) == 0) &&
573 (ndi_merge_node(child
, name_child
) == DDI_SUCCESS
)) {
574 impl_ddi_sunbus_removechild(child
);
575 return (DDI_FAILURE
);
578 (void) init_regspec_64(child
);
579 return (DDI_SUCCESS
);
583 * Control ops entry point:
585 * Requests handled completely:
586 * DDI_CTLOPS_INITCHILD
587 * DDI_CTLOPS_UNINITCHILD
588 * DDI_CTLOPS_REPORTDEV
589 * All others are passed to the parent.
590 * The name of the ssm node is ssm@nodeid,0.
591 * ssm is the equivalent of rootnex.
594 ssm_ctlops(dev_info_t
*dip
, dev_info_t
*rdip
, ddi_ctl_enum_t op
, void *arg
,
600 case DDI_CTLOPS_INITCHILD
: {
601 DPRINTF(SSM_CTLOPS_DEBUG
, ("DDI_CTLOPS_INITCHILD\n"));
602 return (init_child((dev_info_t
*)arg
));
605 case DDI_CTLOPS_UNINITCHILD
: {
606 DPRINTF(SSM_CTLOPS_DEBUG
, ("DDI_CTLOPS_UNINITCHILD\n"));
607 impl_ddi_sunbus_removechild((dev_info_t
*)arg
);
608 return (DDI_SUCCESS
);
611 case DDI_CTLOPS_REPORTDEV
: {
617 DPRINTF(SSM_CTLOPS_DEBUG
, ("DDI_CTLOPS_REPORTDEV\n"));
618 parent
= ddi_get_parent(rdip
);
620 (void) sprintf(p
, "%s%d at %s%d", DEVI(rdip
)->devi_name
,
621 DEVI(rdip
)->devi_instance
, ddi_get_name(parent
),
622 ddi_get_instance(parent
));
625 /* Fetch Safari Extended Agent ID of this device. */
626 portid
= (int)ddi_getprop(DDI_DEV_T_ANY
, rdip
,
627 DDI_PROP_DONTPASS
, "portid", -1);
630 * If this is one of the ssm children it will have
631 * portid property and its parent will be ssm.
632 * In this case report Node number and Safari id.
635 strcmp("ssm", ddi_get_name(parent
)) == 0) {
641 rp
= sparc_pd_getreg(rdip
, 0);
642 n
= sparc_pd_getnreg(rdip
);
645 node
= SG_PORTID_TO_NODEID(portid
);
646 safid
= SG_PORTID_TO_SAFARI_ID(portid
);
648 (void) strcpy(p
, ": ");
651 (void) sprintf(p
, "Node %d Safari id %d 0x%x%s",
654 (n
> 1 ? "" : " ..."));
658 cmn_err(CE_CONT
, "?%s\n", buf
);
665 rval
= ddi_ctlops(dip
, rdip
, op
, arg
, result
);
675 ssm_make_nodes(dev_info_t
*dip
, int instance
, int ssm_nodeid
)
678 minor_t minor_num
, bd
;
679 auto char filename
[20];
681 for (bd
= 0; bd
< plat_max_boards(); bd
++) {
682 if (SG_BOARD_IS_CPU_TYPE(bd
))
683 (void) sprintf(filename
, "N%d.SB%d", ssm_nodeid
, bd
);
685 (void) sprintf(filename
, "N%d.IB%d", ssm_nodeid
, bd
);
687 minor_num
= (instance
<< SSM_INSTANCE_SHIFT
) | bd
;
689 rv
= ddi_create_minor_node(dip
, filename
, S_IFCHR
,
690 minor_num
, DDI_NT_SBD_ATTACHMENT_POINT
, NULL
);
691 if (rv
== DDI_FAILURE
) {
693 "ssm_make_nodes:%d: failed to create "
694 "minor node (%s, 0x%x)",
695 instance
, filename
, minor_num
);
706 ssm_open(dev_t
*devi
, int flags
, int otyp
, cred_t
*credp
)
708 struct ssm_soft_state
*softsp
;
709 minor_t board
, instance
;
710 int (*sbd_setup_instance
)(int, dev_info_t
*, int, int, caddr_t
);
711 ssm_sbdp_info_t sbdp_info
;
714 instance
= (getminor(*devi
) >> SSM_INSTANCE_SHIFT
);
716 softsp
= ddi_get_soft_state(ssm_softstates
, instance
);
717 if (softsp
== NULL
) {
718 cmn_err(CE_WARN
, "ssm_open bad instance number %d", instance
);
722 board
= (getminor(*devi
) & SSM_BOARD_MASK
);
724 if (board
< 0 || board
> plat_max_boards()) {
728 mutex_enter(&ssm_lock
);
729 if (instance
== 0 && ssm_loaded_sbd
== FALSE
) {
731 if (modload("misc", "sbd") == -1) {
732 cmn_err(CE_WARN
, "ssm_open: cannot load sbd");
733 mutex_exit(&ssm_lock
);
736 ssm_loaded_sbd
= TRUE
;
738 mutex_exit(&ssm_lock
);
740 mutex_enter(&softsp
->ssm_sft_lock
);
741 if (softsp
->initialized
== FALSE
) {
743 if (softsp
->top_node
== NULL
) {
744 cmn_err(CE_WARN
, "cannot find ssm top dnode");
745 mutex_exit(&softsp
->ssm_sft_lock
);
749 sbd_setup_instance
= (int (*)(int, dev_info_t
*, int, int,
750 caddr_t
))modlookup("misc/sbd", "sbd_setup_instance");
752 if (!sbd_setup_instance
) {
753 cmn_err(CE_WARN
, "cannot find sbd_setup_instance");
754 mutex_exit(&softsp
->ssm_sft_lock
);
758 sbdp_info
.instance
= instance
;
759 sbdp_info
.wnode
= softsp
->ssm_nodeid
;
761 rv
= (*sbd_setup_instance
)(instance
, softsp
->top_node
,
762 plat_max_boards(), softsp
->ssm_nodeid
,
763 (caddr_t
)&sbdp_info
);
764 if (rv
!= DDI_SUCCESS
) {
765 cmn_err(CE_WARN
, "cannot run sbd_setup_instance");
766 mutex_exit(&softsp
->ssm_sft_lock
);
769 softsp
->initialized
= TRUE
;
771 mutex_exit(&softsp
->ssm_sft_lock
);
773 return (DDI_SUCCESS
);
779 ssm_close(dev_t dev
, int flags
, int otyp
, cred_t
*credp
)
781 struct ssm_soft_state
*softsp
;
782 minor_t board
, instance
;
784 instance
= (getminor(dev
) >> SSM_INSTANCE_SHIFT
);
786 softsp
= ddi_get_soft_state(ssm_softstates
, instance
);
790 board
= (getminor(dev
) & SSM_BOARD_MASK
);
792 if (board
< 0 || board
> plat_max_boards())
795 return (DDI_SUCCESS
);
800 ssm_ioctl(dev_t dev
, int cmd
, intptr_t arg
, int mode
, cred_t
*credp
,
803 struct ssm_soft_state
*softsp
;
805 struct devctl_iocdata
*dcp
;
806 int instance
, rv
= 0;
807 int (*sbd_ioctl
) (dev_t
, int, intptr_t, int, char *);
809 instance
= (getminor(dev
) >> SSM_INSTANCE_SHIFT
);
810 softsp
= ddi_get_soft_state(ssm_softstates
, instance
);
816 case DEVCTL_BUS_CONFIGURE
:
818 * read devctl ioctl data
820 if (ndi_dc_allochdl((void *)arg
, &dcp
) != NDI_SUCCESS
)
823 addr
= ndi_dc_getaddr(dcp
);
825 "DEVCTL_BUS_CONFIGURE: device id is %s\n", addr
);
829 case DEVCTL_BUS_UNCONFIGURE
:
830 if (ndi_dc_allochdl((void *)arg
, &dcp
) != NDI_SUCCESS
)
833 addr
= ndi_dc_getaddr(dcp
);
835 "DEVCTL_BUS_UNCONFIGURE: device id is %s\n", addr
);
840 case SSM_TEARDOWN_SBD
: {
841 ssm_sbdp_info_t sbdp_info
;
842 int (*sbd_teardown_instance
) (int, caddr_t
);
843 sbd_teardown_instance
= (int (*) (int, caddr_t
))
844 modlookup("misc/sbd", "sbd_teardown_instance");
846 if (!sbd_teardown_instance
) {
847 cmn_err(CE_WARN
, "cannot find sbd_teardown_instance");
851 sbdp_info
.instance
= instance
;
852 sbdp_info
.wnode
= softsp
->ssm_nodeid
;
853 rv
= (*sbd_teardown_instance
)(instance
, (caddr_t
)&sbdp_info
);
854 if (rv
!= DDI_SUCCESS
) {
855 cmn_err(CE_WARN
, "cannot run sbd_teardown_instance");
859 ssm_loaded_sbd
= FALSE
;
860 softsp
->initialized
= FALSE
;
868 sbd_ioctl
= (int (*) (dev_t
, int, intptr_t, int, char *))
869 modlookup("misc/sbd", "sbd_ioctl");
872 rv
= (*sbd_ioctl
) (dev
, cmd
, arg
, mode
, &event
);
874 cmn_err(CE_WARN
, "cannot find sbd_ioctl");
878 * Check to see if we need to send an event
882 int hint
= SE_NO_HINT
;
885 if (cmd
== SBD_CMD_CONNECT
||
886 cmd
== SBD_CMD_CONFIGURE
)
887 hint
= SE_HINT_INSERT
;
888 else if (cmd
== SBD_CMD_UNCONFIGURE
||
889 cmd
== SBD_CMD_DISCONNECT
)
890 hint
= SE_HINT_REMOVE
;
893 slot
= (getminor(dev
) & SSM_BOARD_MASK
);
894 (void) ssm_generate_event(softsp
->ssm_nodeid
, slot
,
905 ssm_get_attch_pnt(int node
, int board
, char *attach_pnt
)
907 struct ssm_node2inst
*sp
;
910 * Hold this mutex, until we are done so that ssm dip
913 mutex_enter(&ssm_node2inst_lock
);
915 for (sp
= &ssm_node2inst_map
; sp
!= NULL
; sp
= sp
->next
) {
918 if (sp
->nodeid
== node
)
923 /* We didn't find the ssm dip, return failure */
924 attach_pnt
[0] = '\0';
925 mutex_exit(&ssm_node2inst_lock
);
930 * we have the instance, and the board, construct the attch pnt
932 if (SG_BOARD_IS_CPU_TYPE(board
))
933 (void) sprintf(attach_pnt
, "ssm%d:N%d.SB%d",
934 sp
->inst
, node
, board
);
936 (void) sprintf(attach_pnt
, "ssm%d:N%d.IB%d",
937 sp
->inst
, node
, board
);
939 mutex_exit(&ssm_node2inst_lock
);
943 * Generate an event to sysevent
946 ssm_generate_event(int node
, int board
, int hint
)
951 sysevent_value_t evnt_val
;
952 sysevent_attr_list_t
*evnt_attr_list
= NULL
;
953 char attach_pnt
[MAXPATHLEN
];
956 attach_pnt
[0] = '\0';
957 ssm_get_attch_pnt(node
, board
, attach_pnt
);
959 if (attach_pnt
[0] == '\0')
962 ev
= sysevent_alloc(EC_DR
, ESC_DR_AP_STATE_CHANGE
, EP_DDI
,
964 evnt_val
.value_type
= SE_DATA_TYPE_STRING
;
965 evnt_val
.value
.sv_string
= attach_pnt
;
967 rv
= sysevent_add_attr(&evnt_attr_list
, DR_AP_ID
, &evnt_val
, KM_SLEEP
);
969 cmn_err(CE_WARN
, "Failed to add attr [%s] for %s event",
978 evnt_val
.value_type
= SE_DATA_TYPE_STRING
;
979 evnt_val
.value
.sv_string
= SE_HINT2STR(hint
);
981 rv
= sysevent_add_attr(&evnt_attr_list
, DR_HINT
, &evnt_val
, KM_SLEEP
);
983 cmn_err(CE_WARN
, "Failed to add attr [%s] for %s event",
985 sysevent_free_attr(evnt_attr_list
);
990 if (sysevent_attach_attributes(ev
, evnt_attr_list
) != 0) {
991 cmn_err(CE_WARN
, "Failed to attach attr list for %s event",
993 sysevent_free_attr(evnt_attr_list
);
998 rv
= log_sysevent(ev
, KM_NOSLEEP
, &eid
);
1000 cmn_err(CE_WARN
, "ssm_dr_event_handler: failed to log event");
1012 ssm_dr_event_handler(char *arg
)
1014 sg_system_fru_descriptor_t
*fdp
;
1018 fdp
= (sg_system_fru_descriptor_t
*)(((sbbc_msg_t
*)arg
)->msg_buf
);
1020 DPRINTF(SSM_EVENT_DEBUG
,
1021 ("ssm_dr_event_handler: ARG is null\n"));
1022 return (DDI_INTR_CLAIMED
);
1025 DPRINTF(SSM_EVENT_DEBUG
, ("ssm_dr_event_handler called\n"));
1026 DPRINTF(SSM_EVENT_DEBUG
, ("\tnode\t%d\n", fdp
->node
));
1027 DPRINTF(SSM_EVENT_DEBUG
, ("\tslot\t%d\n", fdp
->slot
));
1028 DPRINTF(SSM_EVENT_DEBUG
, ("\tparent_hdl\t0x%lx\n", fdp
->parent_hdl
));
1029 DPRINTF(SSM_EVENT_DEBUG
, ("\tchild_hdl\t0x%lx\n", fdp
->child_hdl
));
1030 DPRINTF(SSM_EVENT_DEBUG
, ("\tevent_details\t%s\n",
1031 EVNT2STR(fdp
->event_details
)));
1034 switch (fdp
->event_details
) {
1035 case SG_EVT_BOARD_ABSENT
:
1036 hint
= SE_HINT_REMOVE
;
1038 case SG_EVT_BOARD_PRESENT
:
1039 hint
= SE_HINT_INSERT
;
1047 (void) ssm_generate_event(fdp
->node
, fdp
->slot
, hint
);
1049 return (DDI_INTR_CLAIMED
);
1053 * Initialize our FMA resources
1056 ssm_fm_init(struct ssm_soft_state
*softsp
)
1058 softsp
->ssm_fm_cap
= DDI_FM_EREPORT_CAPABLE
| DDI_FM_ERRCB_CAPABLE
|
1059 DDI_FM_ACCCHK_CAPABLE
| DDI_FM_DMACHK_CAPABLE
;
1062 * Request or capability level and get our parents capability
1065 ddi_fm_init(softsp
->dip
, &softsp
->ssm_fm_cap
, &softsp
->ssm_fm_ibc
);
1066 ASSERT((softsp
->ssm_fm_cap
& DDI_FM_EREPORT_CAPABLE
) &&
1067 (softsp
->ssm_fm_cap
& DDI_FM_ERRCB_CAPABLE
));
1069 * Register error callback with our parent.
1071 ddi_fm_handler_register(softsp
->dip
, ssm_err_callback
, NULL
);
1075 * Breakdown our FMA resources
1078 ssm_fm_fini(struct ssm_soft_state
*softsp
)
1081 * Clean up allocated fm structures
1083 ASSERT(softsp
->ssm_fm_cap
& DDI_FM_EREPORT_CAPABLE
);
1084 ddi_fm_handler_unregister(softsp
->dip
);
1085 ddi_fm_fini(softsp
->dip
);
1089 * Initialize FMA resources for children devices. Called when
1090 * child calls ddi_fm_init().
1094 ssm_fm_init_child(dev_info_t
*dip
, dev_info_t
*tdip
, int cap
,
1095 ddi_iblock_cookie_t
*ibc
)
1097 struct ssm_soft_state
*softsp
= ddi_get_soft_state(ssm_softstates
,
1098 ddi_get_instance(dip
));
1100 *ibc
= softsp
->ssm_fm_ibc
;
1101 return (softsp
->ssm_fm_cap
);
1105 * FMA registered error callback
1109 ssm_err_callback(dev_info_t
*dip
, ddi_fm_error_t
*derr
, const void *impl_data
)
1111 /* Call our children error handlers */
1112 return (ndi_fm_handler_dispatch(dip
, NULL
, derr
));