xref: /illumos-gate/usr/src/uts/sun4u/serengeti/io/ssm.c (revision 35e1ee58)
103831d35Sstevel /*
203831d35Sstevel  * CDDL HEADER START
303831d35Sstevel  *
403831d35Sstevel  * The contents of this file are subject to the terms of the
503831d35Sstevel  * Common Development and Distribution License (the "License").
603831d35Sstevel  * You may not use this file except in compliance with the License.
703831d35Sstevel  *
803831d35Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
903831d35Sstevel  * or http://www.opensolaris.org/os/licensing.
1003831d35Sstevel  * See the License for the specific language governing permissions
1103831d35Sstevel  * and limitations under the License.
1203831d35Sstevel  *
1303831d35Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
1403831d35Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1503831d35Sstevel  * If applicable, add the following below this CDDL HEADER, with the
1603831d35Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
1703831d35Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
1803831d35Sstevel  *
1903831d35Sstevel  * CDDL HEADER END
2003831d35Sstevel  */
2103831d35Sstevel 
2203831d35Sstevel /*
2307d06da5SSurya Prakki  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2403831d35Sstevel  * Use is subject to license terms.
2503831d35Sstevel  */
26cd21e7c5SGarrett D'Amore /*
27cd21e7c5SGarrett D'Amore  * Copyright 2012 Garrett D'Amore <garrett@damore.org>.  All rights reserved.
28cd21e7c5SGarrett D'Amore  */
2903831d35Sstevel #include <sys/types.h>
3003831d35Sstevel #include <sys/conf.h>
3103831d35Sstevel #include <sys/ddi.h>
3203831d35Sstevel #include <sys/sunddi.h>
3303831d35Sstevel #include <sys/modctl.h>
3403831d35Sstevel #include <sys/sunndi.h>
3503831d35Sstevel #include <sys/ddi_impldefs.h>
3603831d35Sstevel #include <sys/obpdefs.h>
3703831d35Sstevel #include <sys/cmn_err.h>
3803831d35Sstevel #include <sys/errno.h>
3903831d35Sstevel #include <sys/kmem.h>
4003831d35Sstevel #include <sys/debug.h>
4103831d35Sstevel #include <sys/sysmacros.h>
4203831d35Sstevel #include <sys/autoconf.h>
4303831d35Sstevel #include <sys/stat.h>
4403831d35Sstevel #include <sys/serengeti.h>
4503831d35Sstevel #include <sys/ssm.h>
4603831d35Sstevel #include <sys/sgsbbc_mailbox.h>
4703831d35Sstevel #include <sys/sgevents.h>
4803831d35Sstevel #include <sys/sysevent.h>
4903831d35Sstevel #include <sys/sysevent/dr.h>
5003831d35Sstevel #include <sys/sysevent/eventdefs.h>
5103831d35Sstevel #include <sys/ndi_impldefs.h>
5203831d35Sstevel #include <sys/ddifm.h>
5303831d35Sstevel #include <sys/ndifm.h>
5403831d35Sstevel #include <sys/sbd_ioctl.h>
5503831d35Sstevel 
5603831d35Sstevel /* Useful debugging Stuff */
5703831d35Sstevel #include <sys/nexusdebug.h>
5803831d35Sstevel 
5903831d35Sstevel /*
6003831d35Sstevel  * module ssm.c
6103831d35Sstevel  *
6203831d35Sstevel  * This module is a nexus driver designed to support the ssm nexus driver
6303831d35Sstevel  * and all children below it. This driver does not handle any of the
6403831d35Sstevel  * DDI functions passed up to it by the ssm driver, but instead allows
6503831d35Sstevel  * them to bubble up to the root node.
6603831d35Sstevel  */
6703831d35Sstevel 
6803831d35Sstevel 
6903831d35Sstevel /*
7003831d35Sstevel  * Function prototypes
7103831d35Sstevel  */
7203831d35Sstevel extern int plat_max_boards();
7303831d35Sstevel 
7403831d35Sstevel static int
7503831d35Sstevel ssm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result);
7603831d35Sstevel 
7703831d35Sstevel static int
7803831d35Sstevel ssm_attach(dev_info_t *, ddi_attach_cmd_t);
7903831d35Sstevel 
8003831d35Sstevel static int
8103831d35Sstevel ssm_detach(dev_info_t *, ddi_detach_cmd_t);
8203831d35Sstevel 
8303831d35Sstevel static int
8403831d35Sstevel ssm_open(dev_t *, int, int, cred_t *);
8503831d35Sstevel 
8603831d35Sstevel static int
8703831d35Sstevel ssm_close(dev_t, int, int, cred_t *);
8803831d35Sstevel 
8903831d35Sstevel static int
9003831d35Sstevel ssm_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
9103831d35Sstevel 
9203831d35Sstevel static int
9303831d35Sstevel ssm_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *);
9403831d35Sstevel 
9503831d35Sstevel static int
9603831d35Sstevel ssm_make_nodes(dev_info_t *dip, int instance, int ssm_nodeid);
9703831d35Sstevel 
9803831d35Sstevel static int
9903831d35Sstevel ssm_generate_event(int node, int board, int hint);
10003831d35Sstevel 
10103831d35Sstevel /*
10203831d35Sstevel  * FMA error callback
10303831d35Sstevel  * Register error handling callback with our parent. We will just call
10403831d35Sstevel  * our children's error callbacks and return their status.
10503831d35Sstevel  */
10603831d35Sstevel static int
10703831d35Sstevel ssm_err_callback(dev_info_t *dip, ddi_fm_error_t *derr, const void *impl_data);
10803831d35Sstevel 
10903831d35Sstevel /*
11003831d35Sstevel  * fm_init busop to initialize our children
11103831d35Sstevel  */
11203831d35Sstevel static int
11303831d35Sstevel ssm_fm_init_child(dev_info_t *dip, dev_info_t *tdip, int cap,
114*35e1ee58SToomas Soome     ddi_iblock_cookie_t *ibc);
11503831d35Sstevel 
11603831d35Sstevel /*
11703831d35Sstevel  * init/fini routines to alloc/dealloc fm structures and
11803831d35Sstevel  * register/unregister our callback.
11903831d35Sstevel  */
12003831d35Sstevel static void
12103831d35Sstevel ssm_fm_init(struct ssm_soft_state *softsp);
12203831d35Sstevel 
12303831d35Sstevel static void
12403831d35Sstevel ssm_fm_fini(struct ssm_soft_state *softsp);
12503831d35Sstevel 
12603831d35Sstevel /*
12703831d35Sstevel  * DR event handlers
12803831d35Sstevel  * We want to register the event handlers once for all instances. In the
12903831d35Sstevel  * other hand we have register them after the sbbc has been attached.
13003831d35Sstevel  * event_initialize gives us the logic of only registering the events only
13103831d35Sstevel  * once
13203831d35Sstevel  */
13303831d35Sstevel int event_initialized = 0;
13403831d35Sstevel uint_t ssm_dr_event_handler(char *);
13503831d35Sstevel 
13603831d35Sstevel /*
13703831d35Sstevel  * Event lock and state
13803831d35Sstevel  */
13903831d35Sstevel static kmutex_t ssm_event_lock;
14003831d35Sstevel int ssm_event_state;
14103831d35Sstevel 
14203831d35Sstevel /*
14303831d35Sstevel  * DR event msg and payload
14403831d35Sstevel  */
14503831d35Sstevel static sbbc_msg_t event_msg;
14603831d35Sstevel static sg_system_fru_descriptor_t payload;
14703831d35Sstevel 
14803831d35Sstevel struct ssm_node2inst {
14903831d35Sstevel 	int	nodeid;		/* serengeti node #, NOT prom nodeid */
15003831d35Sstevel 	int	inst;
15103831d35Sstevel 	struct ssm_node2inst *next;
15203831d35Sstevel };
15303831d35Sstevel static kmutex_t ssm_node2inst_lock;
15403831d35Sstevel static struct ssm_node2inst ssm_node2inst_map = {-1, -1, NULL};
15503831d35Sstevel 
15603831d35Sstevel 
15703831d35Sstevel /*
15803831d35Sstevel  * Configuration data structures
15903831d35Sstevel  */
16003831d35Sstevel static struct bus_ops ssm_bus_ops = {
16103831d35Sstevel 	BUSO_REV,
16203831d35Sstevel 	ddi_bus_map,		/* map */
16303831d35Sstevel 	0,			/* get_intrspec */
16403831d35Sstevel 	0,			/* add_intrspec */
16503831d35Sstevel 	0,			/* remove_intrspec */
16603831d35Sstevel 	i_ddi_map_fault,	/* map_fault */
167cd21e7c5SGarrett D'Amore 	0,			/* dma_map */
16803831d35Sstevel 	ddi_dma_allochdl,
16903831d35Sstevel 	ddi_dma_freehdl,
17003831d35Sstevel 	ddi_dma_bindhdl,
17103831d35Sstevel 	ddi_dma_unbindhdl,
17203831d35Sstevel 	ddi_dma_flush,
17303831d35Sstevel 	ddi_dma_win,
17403831d35Sstevel 	ddi_dma_mctl,		/* dma_ctl */
17503831d35Sstevel 	ssm_ctlops,		/* ctl */
17603831d35Sstevel 	ddi_bus_prop_op,	/* prop_op */
17703831d35Sstevel 	ndi_busop_get_eventcookie,
17803831d35Sstevel 	ndi_busop_add_eventcall,
17903831d35Sstevel 	ndi_busop_remove_eventcall,
18003831d35Sstevel 	ndi_post_event,
18103831d35Sstevel 	0,
18203831d35Sstevel 	0,
18303831d35Sstevel 	0,
18403831d35Sstevel 	ssm_fm_init_child,
18503831d35Sstevel 	NULL,
18603831d35Sstevel 	NULL,
18703831d35Sstevel 	NULL,
18803831d35Sstevel 	0,
18903831d35Sstevel 	i_ddi_intr_ops
19003831d35Sstevel };
19103831d35Sstevel 
19203831d35Sstevel static struct cb_ops ssm_cb_ops = {
19303831d35Sstevel 	ssm_open,			/* open */
19403831d35Sstevel 	ssm_close,			/* close */
19503831d35Sstevel 	nodev,				/* strategy */
19603831d35Sstevel 	nodev,				/* print */
19703831d35Sstevel 	nodev,				/* dump */
19803831d35Sstevel 	nodev,				/* read */
19903831d35Sstevel 	nodev,				/* write */
20003831d35Sstevel 	ssm_ioctl,			/* ioctl */
20103831d35Sstevel 	nodev,				/* devmap */
20203831d35Sstevel 	nodev,				/* mmap */
20303831d35Sstevel 	nodev,				/* segmap */
20403831d35Sstevel 	nochpoll,			/* poll */
20503831d35Sstevel 	ddi_prop_op,			/* cb_prop_op */
20603831d35Sstevel 	NULL,				/* streamtab */
20703831d35Sstevel 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
20803831d35Sstevel 	CB_REV,				/* rev */
20903831d35Sstevel 	nodev,				/* int (*cb_aread)() */
21003831d35Sstevel 	nodev				/* int (*cb_awrite)() */
21103831d35Sstevel };
21203831d35Sstevel 
21303831d35Sstevel static struct dev_ops ssm_ops = {
21403831d35Sstevel 	DEVO_REV,		/* devo_rev, */
21503831d35Sstevel 	0,			/* refcnt */
21603831d35Sstevel 	ssm_info,		/* getinfo */
21703831d35Sstevel 	nulldev,		/* identify */
21803831d35Sstevel 	nulldev,		/* probe */
21903831d35Sstevel 	ssm_attach,		/* attach */
22003831d35Sstevel 	ssm_detach,		/* detach */
22103831d35Sstevel 	nulldev,		/* reset */
22203831d35Sstevel 	&ssm_cb_ops,		/* driver operations */
22303831d35Sstevel 	&ssm_bus_ops,		/* bus_ops */
22419397407SSherry Moore 	nulldev,		/* power */
22519397407SSherry Moore 	ddi_quiesce_not_needed,		/* quiesce */
22603831d35Sstevel };
22703831d35Sstevel 
22803831d35Sstevel /*
22903831d35Sstevel  * Driver globals
23003831d35Sstevel  */
23103831d35Sstevel static void *ssm_softstates;		/* ssm soft state hook */
23203831d35Sstevel 
23303831d35Sstevel extern struct mod_ops mod_driverops;
23403831d35Sstevel 
23503831d35Sstevel static struct modldrv modldrv = {
23603831d35Sstevel 	&mod_driverops,		/* Type of module.  This one is a driver */
23719397407SSherry Moore 	"SSM Nexus",		/* name of module */
23803831d35Sstevel 	&ssm_ops,		/* driver ops */
23903831d35Sstevel };
24003831d35Sstevel 
24103831d35Sstevel static struct modlinkage modlinkage = {
24203831d35Sstevel 	MODREV_1,		/* rev */
24303831d35Sstevel 	(void *)&modldrv,
24403831d35Sstevel 	NULL
24503831d35Sstevel };
24603831d35Sstevel 
24703831d35Sstevel static int ssm_loaded_sbd = FALSE;
24803831d35Sstevel kmutex_t ssm_lock;
24903831d35Sstevel static int init_child(dev_info_t *child);
25003831d35Sstevel 
25103831d35Sstevel /*
25203831d35Sstevel  * These are the module initialization routines.
25303831d35Sstevel  */
25403831d35Sstevel 
25503831d35Sstevel int
_init(void)25603831d35Sstevel _init(void)
25703831d35Sstevel {
25803831d35Sstevel 	int error;
25903831d35Sstevel 
26003831d35Sstevel #if defined(DEBUG)
26103831d35Sstevel 	debug_print_level = 0x0;
26203831d35Sstevel #endif
26303831d35Sstevel 
26403831d35Sstevel 	/* Initialize soft state pointer. */
26503831d35Sstevel 	if ((error = ddi_soft_state_init(&ssm_softstates,
266447a706eSVijay Balakrishna, SG-RPE 	    sizeof (struct ssm_soft_state), SSM_MAX_INSTANCES)) != 0)
26703831d35Sstevel 		return (error);
26803831d35Sstevel 
26903831d35Sstevel 	/* Install the module. */
27003831d35Sstevel 	error = mod_install(&modlinkage);
27103831d35Sstevel 	if (error != 0)
27203831d35Sstevel 		ddi_soft_state_fini(&ssm_softstates);
27303831d35Sstevel 
27403831d35Sstevel 	mutex_init(&ssm_lock, NULL, MUTEX_DRIVER, NULL);
27503831d35Sstevel 
27603831d35Sstevel 	return (error);
27703831d35Sstevel }
27803831d35Sstevel 
27903831d35Sstevel int
_fini(void)28003831d35Sstevel _fini(void)
28103831d35Sstevel {
28203831d35Sstevel 	int error;
283