xref: /titanic_50/usr/src/uts/sun4v/io/platsvc.c (revision 4e4761498aa6990539820cfc2ee7b1c7c53b6bc3)
11ae08745Sheppo /*
21ae08745Sheppo  * CDDL HEADER START
31ae08745Sheppo  *
41ae08745Sheppo  * The contents of this file are subject to the terms of the
51ae08745Sheppo  * Common Development and Distribution License (the "License").
61ae08745Sheppo  * You may not use this file except in compliance with the License.
71ae08745Sheppo  *
81ae08745Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91ae08745Sheppo  * or http://www.opensolaris.org/os/licensing.
101ae08745Sheppo  * See the License for the specific language governing permissions
111ae08745Sheppo  * and limitations under the License.
121ae08745Sheppo  *
131ae08745Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
141ae08745Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151ae08745Sheppo  * If applicable, add the following below this CDDL HEADER, with the
161ae08745Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
171ae08745Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
181ae08745Sheppo  *
191ae08745Sheppo  * CDDL HEADER END
201ae08745Sheppo  */
211ae08745Sheppo 
221ae08745Sheppo /*
23*4e476149Srsmaeda  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
241ae08745Sheppo  * Use is subject to license terms.
251ae08745Sheppo  */
261ae08745Sheppo 
271ae08745Sheppo #pragma ident	"%Z%%M%	%I%	%E% SMI"
281ae08745Sheppo 
291ae08745Sheppo /*
301ae08745Sheppo  * sun4v Platform Services Module
311ae08745Sheppo  */
321ae08745Sheppo 
331ae08745Sheppo #include <sys/modctl.h>
341ae08745Sheppo #include <sys/cmn_err.h>
351ae08745Sheppo #include <sys/machsystm.h>
361ae08745Sheppo #include <sys/note.h>
371ae08745Sheppo #include <sys/uadmin.h>
381ae08745Sheppo #include <sys/ds.h>
391ae08745Sheppo #include <sys/platsvc.h>
401ae08745Sheppo 
411ae08745Sheppo /*
421ae08745Sheppo  * Debugging routines
431ae08745Sheppo  */
441ae08745Sheppo #ifdef DEBUG
451ae08745Sheppo uint_t ps_debug = 0x0;
461ae08745Sheppo #define	DBG	if (ps_debug) printf
471ae08745Sheppo #else /* DEBUG */
481ae08745Sheppo #define	DBG	_NOTE(CONSTCOND) if (0) printf
491ae08745Sheppo #endif /* DEBUG */
501ae08745Sheppo 
511ae08745Sheppo /*
521ae08745Sheppo  * Time resolution conversions.
531ae08745Sheppo  */
541ae08745Sheppo #define	MS2NANO(x)	((x) * MICROSEC)
551ae08745Sheppo #define	MS2SEC(x)	((x) / MILLISEC)
561ae08745Sheppo #define	MS2MIN(x)	(MS2SEC(x) / 60)
571ae08745Sheppo 
581ae08745Sheppo /*
591ae08745Sheppo  * Domains Services interaction
601ae08745Sheppo  */
611ae08745Sheppo static ds_svc_hdl_t	ds_md_handle;
621ae08745Sheppo static ds_svc_hdl_t	ds_shutdown_handle;
631ae08745Sheppo static ds_svc_hdl_t	ds_panic_handle;
641ae08745Sheppo 
651ae08745Sheppo static ds_ver_t		ps_vers[] = {{ 1, 0 }};
661ae08745Sheppo #define	PS_NVERS	(sizeof (ps_vers) / sizeof (ps_vers[0]))
671ae08745Sheppo 
681ae08745Sheppo static ds_capability_t ps_md_cap = {
691ae08745Sheppo 	"md-update",		/* svc_id */
701ae08745Sheppo 	ps_vers,		/* vers */
711ae08745Sheppo 	PS_NVERS		/* nvers */
721ae08745Sheppo };
731ae08745Sheppo 
741ae08745Sheppo static ds_capability_t ps_shutdown_cap = {
751ae08745Sheppo 	"domain-shutdown",	/* svc_id */
761ae08745Sheppo 	ps_vers,		/* vers */
771ae08745Sheppo 	PS_NVERS		/* nvers */
781ae08745Sheppo };
791ae08745Sheppo 
801ae08745Sheppo static ds_capability_t ps_panic_cap = {
811ae08745Sheppo 	"domain-panic",		/* svc_id */
821ae08745Sheppo 	ps_vers,		/* vers */
831ae08745Sheppo 	PS_NVERS		/* nvers */
841ae08745Sheppo };
851ae08745Sheppo 
861ae08745Sheppo static void ps_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl);
871ae08745Sheppo static void ps_unreg_handler(ds_cb_arg_t arg);
881ae08745Sheppo 
891ae08745Sheppo static void ps_md_data_handler(ds_cb_arg_t arg, void * buf, size_t buflen);
901ae08745Sheppo static void ps_shutdown_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
911ae08745Sheppo static void ps_panic_data_handler(ds_cb_arg_t arg, void * buf, size_t buflen);
921ae08745Sheppo 
931ae08745Sheppo static ds_clnt_ops_t ps_md_ops = {
941ae08745Sheppo 	ps_reg_handler,			/* ds_reg_cb */
951ae08745Sheppo 	ps_unreg_handler,		/* ds_unreg_cb */
961ae08745Sheppo 	ps_md_data_handler,		/* ds_data_cb */
971ae08745Sheppo 	&ds_md_handle			/* cb_arg */
981ae08745Sheppo };
991ae08745Sheppo 
1001ae08745Sheppo static ds_clnt_ops_t ps_shutdown_ops = {
1011ae08745Sheppo 	ps_reg_handler,			/* ds_reg_cb */
1021ae08745Sheppo 	ps_unreg_handler,		/* ds_unreg_cb */
1031ae08745Sheppo 	ps_shutdown_data_handler,	/* ds_data_cb */
1041ae08745Sheppo 	&ds_shutdown_handle		/* cb_arg */
1051ae08745Sheppo };
1061ae08745Sheppo 
1071ae08745Sheppo static ds_clnt_ops_t ps_panic_ops = {
1081ae08745Sheppo 	ps_reg_handler,			/* ds_reg_cb */
1091ae08745Sheppo 	ps_unreg_handler,		/* ds_unreg_cb */
1101ae08745Sheppo 	ps_panic_data_handler,		/* ds_data_cb */
1111ae08745Sheppo 	&ds_panic_handle		/* cb_arg */
1121ae08745Sheppo };
1131ae08745Sheppo 
1141ae08745Sheppo static int ps_init(void);
1151ae08745Sheppo static void ps_fini(void);
1161ae08745Sheppo 
1171ae08745Sheppo /*
1181ae08745Sheppo  * Power down timeout value of 5 minutes.
1191ae08745Sheppo  */
1201ae08745Sheppo #define	PLATSVC_POWERDOWN_DELAY		1200
1211ae08745Sheppo 
1221ae08745Sheppo static struct modlmisc modlmisc = {
1231ae08745Sheppo 	&mod_miscops,
1241ae08745Sheppo 	"sun4v Platform Services %I%"
1251ae08745Sheppo };
1261ae08745Sheppo 
1271ae08745Sheppo static struct modlinkage modlinkage = {
1281ae08745Sheppo 	MODREV_1,
1291ae08745Sheppo 	(void *)&modlmisc,
1301ae08745Sheppo 	NULL
1311ae08745Sheppo };
1321ae08745Sheppo 
1331ae08745Sheppo int
1341ae08745Sheppo _init(void)
1351ae08745Sheppo {
1361ae08745Sheppo 	int	rv;
1371ae08745Sheppo 
1381ae08745Sheppo 	if ((rv = ps_init()) != 0)
1391ae08745Sheppo 		return (rv);
1401ae08745Sheppo 
1411ae08745Sheppo 	if ((rv = mod_install(&modlinkage)) != 0)
1421ae08745Sheppo 		ps_fini();
1431ae08745Sheppo 
1441ae08745Sheppo 	return (rv);
1451ae08745Sheppo }
1461ae08745Sheppo 
1471ae08745Sheppo int
1481ae08745Sheppo _info(struct modinfo *modinfop)
1491ae08745Sheppo {
1501ae08745Sheppo 	return (mod_info(&modlinkage, modinfop));
1511ae08745Sheppo }
1521ae08745Sheppo 
1531ae08745Sheppo int platsvc_allow_unload;
1541ae08745Sheppo 
1551ae08745Sheppo int
1561ae08745Sheppo _fini(void)
1571ae08745Sheppo {
1581ae08745Sheppo 	int	status;
1591ae08745Sheppo 
1601ae08745Sheppo 	if (platsvc_allow_unload == 0)
1611ae08745Sheppo 		return (EBUSY);
1621ae08745Sheppo 
1631ae08745Sheppo 	if ((status = mod_remove(&modlinkage)) == 0)
1641ae08745Sheppo 		ps_fini();
1651ae08745Sheppo 
1661ae08745Sheppo 	return (status);
1671ae08745Sheppo }
1681ae08745Sheppo 
1691ae08745Sheppo static int
1701ae08745Sheppo ps_init(void)
1711ae08745Sheppo {
1721ae08745Sheppo 	int	rv;
1731ae08745Sheppo 	extern int mdeg_init(void);
1741ae08745Sheppo 
1751ae08745Sheppo 	/* register with domain services framework */
1761ae08745Sheppo 	rv = ds_cap_init(&ps_md_cap, &ps_md_ops);
1771ae08745Sheppo 	if (rv != 0) {
1781ae08745Sheppo 		cmn_err(CE_WARN, "ds_cap_init md-update failed: %d", rv);
1791ae08745Sheppo 		return (rv);
1801ae08745Sheppo 	}
1811ae08745Sheppo 
1821ae08745Sheppo 	rv = ds_cap_init(&ps_shutdown_cap, &ps_shutdown_ops);
1831ae08745Sheppo 	if (rv != 0) {
1841ae08745Sheppo 		cmn_err(CE_WARN, "ds_cap_init domain-shutdown failed: %d", rv);
1851ae08745Sheppo 		(void) ds_cap_fini(&ps_md_cap);
1861ae08745Sheppo 		return (rv);
1871ae08745Sheppo 	}
1881ae08745Sheppo 
1891ae08745Sheppo 	rv = ds_cap_init(&ps_panic_cap, &ps_panic_ops);
1901ae08745Sheppo 	if (rv != 0) {
1911ae08745Sheppo 		cmn_err(CE_WARN, "ds_cap_init domain-panic failed: %d", rv);
1921ae08745Sheppo 		(void) ds_cap_fini(&ps_md_cap);
1931ae08745Sheppo 		(void) ds_cap_fini(&ps_shutdown_cap);
1941ae08745Sheppo 		return (rv);
1951ae08745Sheppo 	}
1961ae08745Sheppo 
1971ae08745Sheppo 	rv = mdeg_init();
1981ae08745Sheppo 
1991ae08745Sheppo 	return (rv);
2001ae08745Sheppo }
2011ae08745Sheppo 
2021ae08745Sheppo static void
2031ae08745Sheppo ps_fini(void)
2041ae08745Sheppo {
2051ae08745Sheppo 	extern void mdeg_fini(void);
2061ae08745Sheppo 
2071ae08745Sheppo 	/*
2081ae08745Sheppo 	 * Stop incoming requests from Zeus
2091ae08745Sheppo 	 */
2101ae08745Sheppo 	(void) ds_cap_fini(&ps_md_cap);
2111ae08745Sheppo 	(void) ds_cap_fini(&ps_shutdown_cap);
2121ae08745Sheppo 	(void) ds_cap_fini(&ps_panic_cap);
2131ae08745Sheppo 
2141ae08745Sheppo 	mdeg_fini();
2151ae08745Sheppo }
2161ae08745Sheppo 
2171ae08745Sheppo static void
2181ae08745Sheppo ps_md_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
2191ae08745Sheppo {
2201ae08745Sheppo 	extern int mach_descrip_update(void);
2211ae08745Sheppo 	extern void mdeg_notify_clients(void);
222f273041fSjm22469 	extern void recalc_xc_timeouts(void);
2231ae08745Sheppo 
224*4e476149Srsmaeda 	ds_svc_hdl_t		 ds_handle = ds_md_handle;
2251ae08745Sheppo 	platsvc_md_update_req_t	 *msg = buf;
2261ae08745Sheppo 	platsvc_md_update_resp_t resp_msg;
2271ae08745Sheppo 	uint_t			 rv;
2281ae08745Sheppo 
2291ae08745Sheppo 	if (arg == NULL)
2301ae08745Sheppo 		return;
2311ae08745Sheppo 
232*4e476149Srsmaeda 	if (ds_handle == DS_INVALID_HDL) {
233*4e476149Srsmaeda 		DBG("ps_md_data_handler: DS handle no longer valid\n");
234*4e476149Srsmaeda 		return;
235*4e476149Srsmaeda 	}
2361ae08745Sheppo 
2371ae08745Sheppo 	if (msg == NULL || buflen != sizeof (platsvc_md_update_req_t)) {
2381ae08745Sheppo 		resp_msg.req_num = 0;
2391ae08745Sheppo 		resp_msg.result = MD_UPDATE_INVALID_MSG;
2401ae08745Sheppo 		if ((rv = ds_cap_send(ds_handle, &resp_msg,
2411ae08745Sheppo 		    sizeof (resp_msg))) != 0) {
2421ae08745Sheppo 			cmn_err(CE_NOTE, "md ds_cap_send failed (%d)", rv);
2431ae08745Sheppo 		}
2441ae08745Sheppo 		return;
2451ae08745Sheppo 	}
2461ae08745Sheppo 
2471ae08745Sheppo 	DBG("MD Reload...\n");
2481ae08745Sheppo 	if (mach_descrip_update()) {
2491ae08745Sheppo 		cmn_err(CE_WARN, "MD reload failed\n");
2501ae08745Sheppo 		return;
2511ae08745Sheppo 	}
2521ae08745Sheppo 
253f273041fSjm22469 	recalc_xc_timeouts();
254f273041fSjm22469 
2551ae08745Sheppo 	/*
2561ae08745Sheppo 	 * notify registered clients that MD has
2571ae08745Sheppo 	 * been updated
2581ae08745Sheppo 	 */
2591ae08745Sheppo 	mdeg_notify_clients();
2601ae08745Sheppo 
2611ae08745Sheppo 	resp_msg.req_num = msg->req_num;
2621ae08745Sheppo 	resp_msg.result = MD_UPDATE_SUCCESS;
2631ae08745Sheppo 	if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) {
2641ae08745Sheppo 		cmn_err(CE_NOTE, "md ds_cap_send resp failed (%d)", rv);
2651ae08745Sheppo 	}
2661ae08745Sheppo }
2671ae08745Sheppo 
2681ae08745Sheppo static void
2691ae08745Sheppo ps_shutdown_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
2701ae08745Sheppo {
271*4e476149Srsmaeda 	ds_svc_hdl_t		ds_handle = ds_shutdown_handle;
2721ae08745Sheppo 	platsvc_shutdown_req_t	*msg = buf;
2731ae08745Sheppo 	platsvc_shutdown_resp_t	resp_msg;
2741ae08745Sheppo 	uint_t			rv;
2751ae08745Sheppo 	hrtime_t		start;
2761ae08745Sheppo 
2771ae08745Sheppo 	if (arg == NULL)
2781ae08745Sheppo 		return;
2791ae08745Sheppo 
280*4e476149Srsmaeda 	if (ds_handle == DS_INVALID_HDL) {
281*4e476149Srsmaeda 		DBG("ps_shutdown_data_handler: DS handle no longer valid\n");
282*4e476149Srsmaeda 		return;
283*4e476149Srsmaeda 	}
2841ae08745Sheppo 
2851ae08745Sheppo 	if (msg == NULL || buflen != sizeof (platsvc_shutdown_req_t)) {
2861ae08745Sheppo 		resp_msg.req_num = 0;
2871ae08745Sheppo 		resp_msg.result = DOMAIN_SHUTDOWN_INVALID_MSG;
2881ae08745Sheppo 		resp_msg.reason[0] = '\0';
2891ae08745Sheppo 		if ((rv = ds_cap_send(ds_handle, &resp_msg,
2901ae08745Sheppo 		    sizeof (resp_msg))) != 0) {
2911ae08745Sheppo 			cmn_err(CE_NOTE, "shutdown ds_cap_send failed (%d)",
2921ae08745Sheppo 			    rv);
2931ae08745Sheppo 		}
2941ae08745Sheppo 		return;
2951ae08745Sheppo 	}
2961ae08745Sheppo 
2971ae08745Sheppo 	resp_msg.req_num = msg->req_num;
2981ae08745Sheppo 	resp_msg.result = DOMAIN_SHUTDOWN_SUCCESS;
2991ae08745Sheppo 	resp_msg.reason[0] = '\0';
3001ae08745Sheppo 
3011ae08745Sheppo 	if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) {
3021ae08745Sheppo 		cmn_err(CE_NOTE, "shutdown ds_cap_send resp failed (%d)", rv);
3031ae08745Sheppo 	}
3041ae08745Sheppo 
3051ae08745Sheppo 	/*
3061ae08745Sheppo 	 * Honor the ldoms manager's shutdown delay requirement.
3071ae08745Sheppo 	 */
3081ae08745Sheppo 	cmn_err(CE_NOTE, "shutdown requested by ldom manager, "
3091ae08745Sheppo 	    "system shutdown in %d minutes", MS2MIN(msg->delay));
3101ae08745Sheppo 
3111ae08745Sheppo 	start = gethrtime();
3121ae08745Sheppo 	while (gethrtime() - start < MS2NANO(msg->delay))
3131ae08745Sheppo 		;
3141ae08745Sheppo 
3151ae08745Sheppo 	(void) kadmin(A_SHUTDOWN, AD_POWEROFF, NULL, kcred);
3161ae08745Sheppo }
3171ae08745Sheppo 
3181ae08745Sheppo 
3191ae08745Sheppo static void
3201ae08745Sheppo ps_panic_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
3211ae08745Sheppo {
322*4e476149Srsmaeda 	ds_svc_hdl_t		ds_handle = ds_panic_handle;
3231ae08745Sheppo 	platsvc_panic_req_t	*msg = buf;
3241ae08745Sheppo 	platsvc_panic_resp_t	resp_msg;
3251ae08745Sheppo 	uint_t			rv;
3261ae08745Sheppo 
3271ae08745Sheppo 	if (arg == NULL)
3281ae08745Sheppo 		return;
3291ae08745Sheppo 
330*4e476149Srsmaeda 	if (ds_handle == DS_INVALID_HDL) {
331*4e476149Srsmaeda 		DBG("ps_panic_data_handler: DS handle no longer valid\n");
332*4e476149Srsmaeda 		return;
333*4e476149Srsmaeda 	}
3341ae08745Sheppo 
3351ae08745Sheppo 	if (msg == NULL || buflen != sizeof (platsvc_panic_req_t)) {
3361ae08745Sheppo 		resp_msg.req_num = 0;
3371ae08745Sheppo 		resp_msg.result = DOMAIN_PANIC_INVALID_MSG;
3381ae08745Sheppo 		resp_msg.reason[0] = '\0';
3391ae08745Sheppo 		if ((rv = ds_cap_send(ds_handle, &resp_msg,
3401ae08745Sheppo 		    sizeof (resp_msg))) != 0) {
3411ae08745Sheppo 			cmn_err(CE_NOTE, "panic ds_cap_send resp failed (%d)",
3421ae08745Sheppo 			    rv);
3431ae08745Sheppo 		}
3441ae08745Sheppo 		return;
3451ae08745Sheppo 	}
3461ae08745Sheppo 
3471ae08745Sheppo 	resp_msg.req_num = msg->req_num;
3481ae08745Sheppo 	resp_msg.result = DOMAIN_PANIC_SUCCESS;
3491ae08745Sheppo 	resp_msg.reason[0] = '\0';
3501ae08745Sheppo 	if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) {
3511ae08745Sheppo 		cmn_err(CE_NOTE, "panic ds_cap_send resp failed (%d)", rv);
3521ae08745Sheppo 	}
3531ae08745Sheppo 
3541ae08745Sheppo 	cmn_err(CE_PANIC, "Panic forced by ldom manager");
3551ae08745Sheppo 	_NOTE(NOTREACHED)
3561ae08745Sheppo }
3571ae08745Sheppo 
3581ae08745Sheppo static void
3591ae08745Sheppo ps_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
3601ae08745Sheppo {
3611ae08745Sheppo 	DBG("ps_reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n",
3621ae08745Sheppo 	    arg, ver->major, ver->minor, hdl);
3631ae08745Sheppo 
3641ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_md_handle)
3651ae08745Sheppo 		ds_md_handle = hdl;
3661ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_shutdown_handle)
3671ae08745Sheppo 		ds_shutdown_handle = hdl;
3681ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_panic_handle)
3691ae08745Sheppo 		ds_panic_handle = hdl;
3701ae08745Sheppo }
3711ae08745Sheppo 
3721ae08745Sheppo static void
3731ae08745Sheppo ps_unreg_handler(ds_cb_arg_t arg)
3741ae08745Sheppo {
3751ae08745Sheppo 	DBG("ps_unreg_handler: arg=0x%p\n", arg);
3761ae08745Sheppo 
3771ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_md_handle)
3781ae08745Sheppo 		ds_md_handle = DS_INVALID_HDL;
3791ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_shutdown_handle)
3801ae08745Sheppo 		ds_shutdown_handle = DS_INVALID_HDL;
3811ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_panic_handle)
3821ae08745Sheppo 		ds_panic_handle = DS_INVALID_HDL;
3831ae08745Sheppo }
384