#include <sys/types.h>
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/modctl.h>
#include <sys/sunndi.h>
#include <sys/ddi_impldefs.h>
#include <sys/obpdefs.h>
#include <sys/cmn_err.h>
#include <sys/errno.h>
#include <sys/kmem.h>
#include <sys/debug.h>
#include <sys/sysmacros.h>
#include <sys/autoconf.h>
#include <sys/stat.h>
#include <sys/serengeti.h>
#include <sys/ssm.h>
#include <sys/sgsbbc_mailbox.h>
#include <sys/sgevents.h>
#include <sys/sysevent.h>
#include <sys/sysevent/dr.h>
#include <sys/sysevent/eventdefs.h>
#include <sys/ndi_impldefs.h>
#include <sys/ddifm.h>
#include <sys/ndifm.h>
#include <sys/sbd_ioctl.h>
#include <sys/nexusdebug.h>
extern int plat_max_boards();
static int
ssm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result);
static int
ssm_attach(dev_info_t *, ddi_attach_cmd_t);
static int
ssm_detach(dev_info_t *, ddi_detach_cmd_t);
static int
ssm_open(dev_t *, int, int, cred_t *);
static int
ssm_close(dev_t, int, int, cred_t *);
static int
ssm_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
static int
ssm_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *);
static int
ssm_make_nodes(dev_info_t *dip, int instance, int ssm_nodeid);
static int
ssm_generate_event(int node, int board, int hint);
static int
ssm_err_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *impl_data);
static int
ssm_fm_init_child(dev_info_t *dip, dev_info_t *tdip, int cap,
ddi_iblock_cookie_t *ibc);
static void
ssm_fm_init(struct ssm_soft_state *softsp);
static void
ssm_fm_fini(struct ssm_soft_state *softsp);
int event_initialized = 0;
uint_t ssm_dr_event_handler(char *);
static kmutex_t ssm_event_lock;
int ssm_event_state;
static sbbc_msg_t event_msg;
static sg_system_fru_descriptor_t payload;
struct ssm_node2inst {
int nodeid;
int inst;
struct ssm_node2inst *next;
};
static kmutex_t ssm_node2inst_lock;
static struct ssm_node2inst ssm_node2inst_map = {-1, -1, NULL};
static struct bus_ops ssm_bus_ops = {
BUSO_REV,
ddi_bus_map,
0,
0,
0,
i_ddi_map_fault,
0,
ddi_dma_allochdl,
ddi_dma_freehdl,
ddi_dma_bindhdl,
ddi_dma_unbindhdl,
ddi_dma_flush,
ddi_dma_win,
ddi_dma_mctl,
ssm_ctlops,
ddi_bus_prop_op,
ndi_busop_get_eventcookie,
ndi_busop_add_eventcall,
ndi_busop_remove_eventcall,
ndi_post_event,
0,
0,
0,
ssm_fm_init_child,
NULL,
NULL,
NULL,
0,
i_ddi_intr_ops
};
static struct cb_ops ssm_cb_ops = {
ssm_open,
ssm_close,
nodev,
nodev,
nodev,
nodev,
nodev,
ssm_ioctl,
nodev,
nodev,
nodev,
nochpoll,
ddi_prop_op,
NULL,
D_NEW | D_MP | D_HOTPLUG,
CB_REV,
nodev,
nodev
};
static struct dev_ops ssm_ops = {
DEVO_REV,
0,
ssm_info,
nulldev,
nulldev,
ssm_attach,
ssm_detach,
nulldev,
&ssm_cb_ops,
&ssm_bus_ops,
nulldev,
ddi_quiesce_not_needed,
};
static void *ssm_softstates;
extern struct mod_ops mod_driverops;
static struct modldrv modldrv = {
&mod_driverops,
"SSM Nexus",
&ssm_ops,
};
static struct modlinkage modlinkage = {
MODREV_1,
(void *)&modldrv,
NULL
};
static int ssm_loaded_sbd = FALSE;
kmutex_t ssm_lock;
static int init_child(dev_info_t *child);
int
_init(void)
{
int error;
#if defined(DEBUG)
debug_print_level = 0x0;
#endif
if ((error = ddi_soft_state_init(&ssm_softstates,
sizeof (struct ssm_soft_state), SSM_MAX_INSTANCES)) != 0)
return (error);
error = mod_install(&modlinkage);
if (error != 0)
ddi_soft_state_fini(&ssm_softstates);
mutex_init(&ssm_lock, NULL, MUTEX_DRIVER, NULL);
return (error);
}
int
_fini(void)
{
int error;
if ((error = mod_remove(&modlinkage)) != 0)
return (error);
(void) sbbc_mbox_unreg_intr(MBOX_EVENT_GENERIC, ssm_dr_event_handler);
mutex_destroy(&ssm_event_lock);
ddi_soft_state_fini(&ssm_softstates);
mutex_destroy(&ssm_lock);
return (0);
}
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
static int
ssm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
{
dev_t dev;
int instance;
if (infocmd == DDI_INFO_DEVT2INSTANCE) {
dev = (dev_t)arg;
instance = (getminor(dev) >> SSM_INSTANCE_SHIFT);
*result = (void *)(uintptr_t)instance;
return (DDI_SUCCESS);
}
return (DDI_FAILURE);
}
static int
ssm_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
{
int instance;
struct ssm_soft_state *softsp;
struct ssm_node2inst *prev, *sp, *tsp;
DPRINTF(SSM_ATTACH_DEBUG, ("ssm_attach\n"));
switch (cmd) {
case DDI_ATTACH:
break;
case DDI_RESUME:
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
instance = ddi_get_instance(devi);
if (ddi_soft_state_zalloc(ssm_softstates, instance) != DDI_SUCCESS)
return (DDI_FAILURE);
softsp = ddi_get_soft_state(ssm_softstates, instance);
softsp->dip = devi;
softsp->top_node = devi;
mutex_init(&softsp->ssm_sft_lock, NULL, MUTEX_DRIVER, NULL);
DPRINTF(SSM_ATTACH_DEBUG, ("ssm-%d: devi= 0x%p, softsp=0x%p\n",
instance, (void *)devi, (void *)softsp));
if ((softsp->ssm_nodeid = (int)ddi_getprop(DDI_DEV_T_ANY, softsp->dip,
DDI_PROP_DONTPASS, "nodeid", -1)) == -1) {
cmn_err(CE_WARN, "ssm%d: unable to retrieve %s property",
instance, "nodeid");
ddi_soft_state_free(ssm_softstates, instance);
return (DDI_FAILURE);
}
(void) ddi_prop_create(DDI_DEV_T_NONE, devi, DDI_PROP_CANSLEEP,
"pm-hardware-state", (caddr_t)"no-suspend-resume",
strlen("no-suspend-resume") + 1);
#if DEBUG
if (ddi_create_minor_node(devi, "debug", S_IFCHR, instance,
DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
ddi_soft_state_free(ssm_softstates, instance);
return (DDI_FAILURE);
}
#endif
if (ssm_make_nodes(devi, instance, softsp->ssm_nodeid)) {
cmn_err(CE_WARN, "ssm:%s:%d: failed to make nodes",
ddi_driver_name(devi), instance);
ddi_remove_minor_node(devi, NULL);
ddi_soft_state_free(ssm_softstates, instance);
return (DDI_FAILURE);
}
ssm_fm_init(softsp);
ddi_report_dev(devi);
if (event_initialized == 0) {
int rv;
mutex_init(&ssm_event_lock, NULL, MUTEX_DRIVER, NULL);
event_msg.msg_buf = (caddr_t)&payload;
event_msg.msg_len = sizeof (payload);
rv = sbbc_mbox_reg_intr(MBOX_EVENT_GENERIC,
ssm_dr_event_handler, &event_msg,
(uint_t *)&ssm_event_state, &ssm_event_lock);
if (rv == EINVAL)
event_initialized = 1;
}
tsp = kmem_zalloc(sizeof (struct ssm_node2inst), KM_SLEEP);
mutex_enter(&ssm_node2inst_lock);
for (prev = NULL, sp = &ssm_node2inst_map; sp != NULL;
prev = sp, sp = sp->next) {
ASSERT(sp->inst != instance);
ASSERT(sp->nodeid != softsp->ssm_nodeid);
if (sp->inst == -1)
break;
}
if (sp == NULL) {
ASSERT(prev->next == NULL);
sp = prev->next = tsp;
tsp = NULL;
sp->next = NULL;
}
sp->inst = instance;
sp->nodeid = softsp->ssm_nodeid;
mutex_exit(&ssm_node2inst_lock);
if (tsp != NULL)
kmem_free(tsp, sizeof (struct ssm_node2inst));
return (DDI_SUCCESS);
}
static int
ssm_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
{
int instance, rv;
int (*sbd_teardown_instance) (int, caddr_t);
ssm_sbdp_info_t sbdp_info;
struct ssm_soft_state *softsp;
struct ssm_node2inst *prev, *sp;
instance = ddi_get_instance(devi);
softsp = ddi_get_soft_state(ssm_softstates, instance);
if (softsp == NULL) {
cmn_err(CE_WARN,
"ssm_open bad instance number %d", instance);
return (ENXIO);
}
instance = ddi_get_instance(devi);
switch (cmd) {
case DDI_DETACH:
ddi_remove_minor_node(devi, NULL);
sbd_teardown_instance = (int (*) (int, caddr_t))
modlookup("misc/sbd", "sbd_teardown_instance");
if (!sbd_teardown_instance) {
cmn_err(CE_WARN, "cannot find sbd_teardown_instance");
return (DDI_FAILURE);
}
sbdp_info.instance = instance;
sbdp_info.wnode = softsp->ssm_nodeid;
rv = (*sbd_teardown_instance)(instance, (caddr_t)&sbdp_info);
if (rv != DDI_SUCCESS) {
cmn_err(CE_WARN, "cannot run sbd_teardown_instance");
return (DDI_FAILURE);
}
ssm_fm_fini(softsp);
mutex_destroy(&softsp->ssm_sft_lock);
ddi_soft_state_free(ssm_softstates, instance);
mutex_enter(&ssm_node2inst_lock);
for (prev = NULL, sp = &ssm_node2inst_map; sp != NULL;
prev = sp, sp = sp->next) {
ASSERT(prev == NULL || sp->inst != -1);
if (sp->inst == instance)
break;
}
ASSERT(sp != NULL);
if (sp != &ssm_node2inst_map) {
prev->next = sp->next;
kmem_free(sp, sizeof (struct ssm_node2inst));
} else {
sp->nodeid = -1;
sp->inst = -1;
}
mutex_exit(&ssm_node2inst_lock);
return (DDI_SUCCESS);
case DDI_SUSPEND:
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
}
extern void make_ddi_ppd(dev_info_t *, struct ddi_parent_private_data **);
extern struct ddi_parent_private_data *init_regspec_64(dev_info_t *);
static int
name_child(dev_info_t *child, char *name, int namelen)
{
struct regspec *rp;
struct ddi_parent_private_data *pdptr;
int portid = 0;
int regbase = -1;
extern uint_t root_phys_addr_lo_mask;
make_ddi_ppd(child, &pdptr);
ddi_set_parent_data(child, pdptr);
name[0] = '\0';
if (sparc_pd_getnreg(child) == 0)
return (DDI_SUCCESS);
rp = sparc_pd_getreg(child, 0);
portid = ddi_prop_get_int(DDI_DEV_T_ANY, child,
DDI_PROP_DONTPASS, "portid", -1);
if (portid == -1) {
cmn_err(CE_WARN, "could not find portid property in %s",
DEVI(child)->devi_node_name);
} else {
regbase = rp->regspec_addr & root_phys_addr_lo_mask;
}
(void) snprintf(name, namelen, "%x,%x", portid, regbase);
return (DDI_SUCCESS);
}
static int
init_child(dev_info_t *child)
{
char name[MAXNAMELEN];
(void) name_child(child, name, MAXNAMELEN);
ddi_set_name_addr(child, name);
if ((ndi_dev_is_persistent_node(child) == 0) &&
(ndi_merge_node(child, name_child) == DDI_SUCCESS)) {
impl_ddi_sunbus_removechild(child);
return (DDI_FAILURE);
}
(void) init_regspec_64(child);
return (DDI_SUCCESS);
}
static int
ssm_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, void *arg,
void *result)
{
int rval;
switch (op) {
case DDI_CTLOPS_INITCHILD: {
DPRINTF(SSM_CTLOPS_DEBUG, ("DDI_CTLOPS_INITCHILD\n"));
return (init_child((dev_info_t *)arg));
}
case DDI_CTLOPS_UNINITCHILD: {
DPRINTF(SSM_CTLOPS_DEBUG, ("DDI_CTLOPS_UNINITCHILD\n"));
impl_ddi_sunbus_removechild((dev_info_t *)arg);
return (DDI_SUCCESS);
}
case DDI_CTLOPS_REPORTDEV: {
char buf[80];
char *p = buf;
dev_info_t *parent;
int portid;
DPRINTF(SSM_CTLOPS_DEBUG, ("DDI_CTLOPS_REPORTDEV\n"));
parent = ddi_get_parent(rdip);
(void) sprintf(p, "%s%d at %s%d", DEVI(rdip)->devi_name,
DEVI(rdip)->devi_instance, ddi_get_name(parent),
ddi_get_instance(parent));
p += strlen(p);
portid = (int)ddi_getprop(DDI_DEV_T_ANY, rdip,
DDI_PROP_DONTPASS, "portid", -1);
if (portid != -1 &&
strcmp("ssm", ddi_get_name(parent)) == 0) {
struct regspec *rp;
int node;
int safid;
int n;
rp = sparc_pd_getreg(rdip, 0);
n = sparc_pd_getnreg(rdip);
ASSERT(n > 0);
node = SG_PORTID_TO_NODEID(portid);
safid = SG_PORTID_TO_SAFARI_ID(portid);
(void) strcpy(p, ": ");
p += strlen(p);
(void) sprintf(p, "Node %d Safari id %d 0x%x%s",
node, safid,
rp->regspec_addr,
(n > 1 ? "" : " ..."));
p += strlen(p);
}
cmn_err(CE_CONT, "?%s\n", buf);
rval = DDI_SUCCESS;
break;
}
default:
rval = ddi_ctlops(dip, rdip, op, arg, result);
break;
}
return (rval);
}
static int
ssm_make_nodes(dev_info_t *dip, int instance, int ssm_nodeid)
{
int rv;
minor_t minor_num, bd;
auto char filename[20];
for (bd = 0; bd < plat_max_boards(); bd++) {
if (SG_BOARD_IS_CPU_TYPE(bd))
(void) sprintf(filename, "N%d.SB%d", ssm_nodeid, bd);
else
(void) sprintf(filename, "N%d.IB%d", ssm_nodeid, bd);
minor_num = (instance << SSM_INSTANCE_SHIFT) | bd;
rv = ddi_create_minor_node(dip, filename, S_IFCHR,
minor_num, DDI_NT_SBD_ATTACHMENT_POINT, 0);
if (rv == DDI_FAILURE) {
cmn_err(CE_WARN,
"ssm_make_nodes:%d: failed to create "
"minor node (%s, 0x%x)",
instance, filename, minor_num);
return (-1);
}
}
return (0);
}
static int
ssm_open(dev_t *devi, int flags, int otyp, cred_t *credp)
{
struct ssm_soft_state *softsp;
minor_t board, instance;
int (*sbd_setup_instance)(int, dev_info_t *, int, int, caddr_t);
ssm_sbdp_info_t sbdp_info;
int rv;
instance = (getminor(*devi) >> SSM_INSTANCE_SHIFT);
softsp = ddi_get_soft_state(ssm_softstates, instance);
if (softsp == NULL) {
cmn_err(CE_WARN, "ssm_open bad instance number %d", instance);
return (ENXIO);
}
board = (getminor(*devi) & SSM_BOARD_MASK);
if (board < 0 || board > plat_max_boards()) {
return (ENXIO);
}
mutex_enter(&ssm_lock);
if (instance == 0 && ssm_loaded_sbd == FALSE) {
if (modload("misc", "sbd") == -1) {
cmn_err(CE_WARN, "ssm_open: cannot load sbd");
mutex_exit(&ssm_lock);
return (EIO);
}
ssm_loaded_sbd = TRUE;
}
mutex_exit(&ssm_lock);
mutex_enter(&softsp->ssm_sft_lock);
if (softsp->initialized == FALSE) {
if (softsp->top_node == NULL) {
cmn_err(CE_WARN, "cannot find ssm top dnode");
mutex_exit(&softsp->ssm_sft_lock);
return (EIO);
}
sbd_setup_instance = (int (*)(int, dev_info_t *, int, int,
caddr_t))modlookup("misc/sbd", "sbd_setup_instance");
if (!sbd_setup_instance) {
cmn_err(CE_WARN, "cannot find sbd_setup_instance");
mutex_exit(&softsp->ssm_sft_lock);
return (EIO);
}
sbdp_info.instance = instance;
sbdp_info.wnode = softsp->ssm_nodeid;
rv = (*sbd_setup_instance)(instance, softsp->top_node,
plat_max_boards(), softsp->ssm_nodeid,
(caddr_t)&sbdp_info);
if (rv != DDI_SUCCESS) {
cmn_err(CE_WARN, "cannot run sbd_setup_instance");
mutex_exit(&softsp->ssm_sft_lock);
return (EIO);
}
softsp->initialized = TRUE;
}
mutex_exit(&softsp->ssm_sft_lock);
return (DDI_SUCCESS);
}
static int
ssm_close(dev_t dev, int flags, int otyp, cred_t *credp)
{
struct ssm_soft_state *softsp;
minor_t board, instance;
instance = (getminor(dev) >> SSM_INSTANCE_SHIFT);
softsp = ddi_get_soft_state(ssm_softstates, instance);
if (softsp == NULL)
return (ENXIO);
board = (getminor(dev) & SSM_BOARD_MASK);
if (board < 0 || board > plat_max_boards())
return (ENXIO);
return (DDI_SUCCESS);
}
static int
ssm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
int *rvalp)
{
struct ssm_soft_state *softsp;
char *addr;
struct devctl_iocdata *dcp;
int instance, rv = 0;
int (*sbd_ioctl) (dev_t, int, intptr_t, int, char *);
instance = (getminor(dev) >> SSM_INSTANCE_SHIFT);
softsp = ddi_get_soft_state(ssm_softstates, instance);
if (softsp == NULL)
return (ENXIO);
switch (cmd) {
case DEVCTL_BUS_CONFIGURE:
if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
return (EFAULT);
addr = ndi_dc_getaddr(dcp);
cmn_err(CE_NOTE,
"DEVCTL_BUS_CONFIGURE: device id is %s\n", addr);
ndi_dc_freehdl(dcp);
break;
case DEVCTL_BUS_UNCONFIGURE:
if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
return (EFAULT);
addr = ndi_dc_getaddr(dcp);
cmn_err(CE_NOTE,
"DEVCTL_BUS_UNCONFIGURE: device id is %s\n", addr);
ndi_dc_freehdl(dcp);
break;
#ifdef DEBUG
case SSM_TEARDOWN_SBD: {
ssm_sbdp_info_t sbdp_info;
int (*sbd_teardown_instance) (int, caddr_t);
sbd_teardown_instance = (int (*) (int, caddr_t))
modlookup("misc/sbd", "sbd_teardown_instance");
if (!sbd_teardown_instance) {
cmn_err(CE_WARN, "cannot find sbd_teardown_instance");
return (EFAULT);
}
sbdp_info.instance = instance;
sbdp_info.wnode = softsp->ssm_nodeid;
rv = (*sbd_teardown_instance)(instance, (caddr_t)&sbdp_info);
if (rv != DDI_SUCCESS) {
cmn_err(CE_WARN, "cannot run sbd_teardown_instance");
return (EFAULT);
}
ssm_loaded_sbd = FALSE;
softsp->initialized = FALSE;
}
#endif
default: {
char event = 0;
sbd_ioctl = (int (*) (dev_t, int, intptr_t, int, char *))
modlookup("misc/sbd", "sbd_ioctl");
if (sbd_ioctl)
rv = (*sbd_ioctl) (dev, cmd, arg, mode, &event);
else {
cmn_err(CE_WARN, "cannot find sbd_ioctl");
return (ENXIO);
}
if (event == 1) {
int slot;
int hint = SE_NO_HINT;
if (rv == 0) {
if (cmd == SBD_CMD_CONNECT ||
cmd == SBD_CMD_CONFIGURE)
hint = SE_HINT_INSERT;
else if (cmd == SBD_CMD_UNCONFIGURE ||
cmd == SBD_CMD_DISCONNECT)
hint = SE_HINT_REMOVE;
}
slot = (getminor(dev) & SSM_BOARD_MASK);
(void) ssm_generate_event(softsp->ssm_nodeid, slot,
hint);
}
break;
}
}
return (rv);
}
void
ssm_get_attch_pnt(int node, int board, char *attach_pnt)
{
struct ssm_node2inst *sp;
mutex_enter(&ssm_node2inst_lock);
for (sp = &ssm_node2inst_map; sp != NULL; sp = sp->next) {
if (sp->inst == -1)
continue;
if (sp->nodeid == node)
break;
}
if (sp == NULL) {
attach_pnt[0] = '\0';
mutex_exit(&ssm_node2inst_lock);
return;
}
if (SG_BOARD_IS_CPU_TYPE(board))
(void) sprintf(attach_pnt, "ssm%d:N%d.SB%d",
sp->inst, node, board);
else
(void) sprintf(attach_pnt, "ssm%d:N%d.IB%d",
sp->inst, node, board);
mutex_exit(&ssm_node2inst_lock);
}
static int
ssm_generate_event(int node, int board, int hint)
{
sysevent_t *ev;
sysevent_id_t eid;
int rv = 0;
sysevent_value_t evnt_val;
sysevent_attr_list_t *evnt_attr_list = NULL;
char attach_pnt[MAXPATHLEN];
attach_pnt[0] = '\0';
ssm_get_attch_pnt(node, board, attach_pnt);
if (attach_pnt[0] == '\0')
return (-1);
ev = sysevent_alloc(EC_DR, ESC_DR_AP_STATE_CHANGE, EP_DDI,
KM_SLEEP);
evnt_val.value_type = SE_DATA_TYPE_STRING;
evnt_val.value.sv_string = attach_pnt;
rv = sysevent_add_attr(&evnt_attr_list, DR_AP_ID, &evnt_val, KM_SLEEP);
if (rv != 0) {
cmn_err(CE_WARN, "Failed to add attr [%s] for %s event",
DR_AP_ID, EC_DR);
sysevent_free(ev);
return (rv);
}
evnt_val.value_type = SE_DATA_TYPE_STRING;
evnt_val.value.sv_string = SE_HINT2STR(hint);
rv = sysevent_add_attr(&evnt_attr_list, DR_HINT, &evnt_val, KM_SLEEP);
if (rv != 0) {
cmn_err(CE_WARN, "Failed to add attr [%s] for %s event",
DR_HINT, EC_DR);
sysevent_free_attr(evnt_attr_list);
sysevent_free(ev);
return (-1);
}
if (sysevent_attach_attributes(ev, evnt_attr_list) != 0) {
cmn_err(CE_WARN, "Failed to attach attr list for %s event",
EC_DR);
sysevent_free_attr(evnt_attr_list);
sysevent_free(ev);
return (-1);
}
rv = log_sysevent(ev, KM_NOSLEEP, &eid);
if (rv != 0) {
cmn_err(CE_WARN, "ssm_dr_event_handler: failed to log event");
}
sysevent_free(ev);
return (rv);
}
uint_t
ssm_dr_event_handler(char *arg)
{
sg_system_fru_descriptor_t *fdp;
int hint;
fdp = (sg_system_fru_descriptor_t *)(((sbbc_msg_t *)arg)->msg_buf);
if (fdp == NULL) {
DPRINTF(SSM_EVENT_DEBUG,
("ssm_dr_event_handler: ARG is null\n"));
return (DDI_INTR_CLAIMED);
}
#ifdef DEBUG
DPRINTF(SSM_EVENT_DEBUG, ("ssm_dr_event_handler called\n"));
DPRINTF(SSM_EVENT_DEBUG, ("\tnode\t%d\n", fdp->node));
DPRINTF(SSM_EVENT_DEBUG, ("\tslot\t%d\n", fdp->slot));
DPRINTF(SSM_EVENT_DEBUG, ("\tparent_hdl\t0x%lx\n", fdp->parent_hdl));
DPRINTF(SSM_EVENT_DEBUG, ("\tchild_hdl\t0x%lx\n", fdp->child_hdl));
DPRINTF(SSM_EVENT_DEBUG, ("\tevent_details\t%s\n",
EVNT2STR(fdp->event_details)));
#endif
switch (fdp->event_details) {
case SG_EVT_BOARD_ABSENT:
hint = SE_HINT_REMOVE;
break;
case SG_EVT_BOARD_PRESENT:
hint = SE_HINT_INSERT;
break;
default:
hint = SE_NO_HINT;
break;
}
(void) ssm_generate_event(fdp->node, fdp->slot, hint);
return (DDI_INTR_CLAIMED);
}
static void
ssm_fm_init(struct ssm_soft_state *softsp)
{
softsp->ssm_fm_cap = DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE |
DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE;
ddi_fm_init(softsp->dip, &softsp->ssm_fm_cap, &softsp->ssm_fm_ibc);
ASSERT((softsp->ssm_fm_cap & DDI_FM_EREPORT_CAPABLE) &&
(softsp->ssm_fm_cap & DDI_FM_ERRCB_CAPABLE));
ddi_fm_handler_register(softsp->dip, ssm_err_callback, NULL);
}
static void
ssm_fm_fini(struct ssm_soft_state *softsp)
{
ASSERT(softsp->ssm_fm_cap & DDI_FM_EREPORT_CAPABLE);
ddi_fm_handler_unregister(softsp->dip);
ddi_fm_fini(softsp->dip);
}
static int
ssm_fm_init_child(dev_info_t *dip, dev_info_t *tdip, int cap,
ddi_iblock_cookie_t *ibc)
{
struct ssm_soft_state *softsp = ddi_get_soft_state(ssm_softstates,
ddi_get_instance(dip));
*ibc = softsp->ssm_fm_ibc;
return (softsp->ssm_fm_cap);
}
static int
ssm_err_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *impl_data)
{
return (ndi_fm_handler_dispatch(dip, NULL, derr));
}