xref: /titanic_53/usr/src/uts/sun4v/io/platsvc.c (revision f500b19684bd0346ac05bec02a50af07f369da1a)
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*f500b196SRichard Bean  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
241ae08745Sheppo  * Use is subject to license terms.
251ae08745Sheppo  */
261ae08745Sheppo 
271ae08745Sheppo /*
281ae08745Sheppo  * sun4v Platform Services Module
291ae08745Sheppo  */
301ae08745Sheppo 
311ae08745Sheppo #include <sys/modctl.h>
321ae08745Sheppo #include <sys/cmn_err.h>
331ae08745Sheppo #include <sys/machsystm.h>
341ae08745Sheppo #include <sys/note.h>
351ae08745Sheppo #include <sys/uadmin.h>
361ae08745Sheppo #include <sys/ds.h>
371ae08745Sheppo #include <sys/platsvc.h>
381ae08745Sheppo 
391ae08745Sheppo /*
401ae08745Sheppo  * Debugging routines
411ae08745Sheppo  */
421ae08745Sheppo #ifdef DEBUG
431ae08745Sheppo uint_t ps_debug = 0x0;
441ae08745Sheppo #define	DBG	if (ps_debug) printf
451ae08745Sheppo #else /* DEBUG */
461ae08745Sheppo #define	DBG	_NOTE(CONSTCOND) if (0) printf
471ae08745Sheppo #endif /* DEBUG */
481ae08745Sheppo 
491ae08745Sheppo /*
501ae08745Sheppo  * Time resolution conversions.
511ae08745Sheppo  */
521ae08745Sheppo #define	MS2NANO(x)	((x) * MICROSEC)
531ae08745Sheppo #define	MS2SEC(x)	((x) / MILLISEC)
541ae08745Sheppo #define	MS2MIN(x)	(MS2SEC(x) / 60)
551ae08745Sheppo 
561ae08745Sheppo /*
571ae08745Sheppo  * Domains Services interaction
581ae08745Sheppo  */
591ae08745Sheppo static ds_svc_hdl_t	ds_md_handle;
601ae08745Sheppo static ds_svc_hdl_t	ds_shutdown_handle;
611ae08745Sheppo static ds_svc_hdl_t	ds_panic_handle;
621ae08745Sheppo 
631ae08745Sheppo static ds_ver_t		ps_vers[] = {{ 1, 0 }};
641ae08745Sheppo #define	PS_NVERS	(sizeof (ps_vers) / sizeof (ps_vers[0]))
651ae08745Sheppo 
661ae08745Sheppo static ds_capability_t ps_md_cap = {
671ae08745Sheppo 	"md-update",		/* svc_id */
681ae08745Sheppo 	ps_vers,		/* vers */
691ae08745Sheppo 	PS_NVERS		/* nvers */
701ae08745Sheppo };
711ae08745Sheppo 
721ae08745Sheppo static ds_capability_t ps_shutdown_cap = {
731ae08745Sheppo 	"domain-shutdown",	/* svc_id */
741ae08745Sheppo 	ps_vers,		/* vers */
751ae08745Sheppo 	PS_NVERS		/* nvers */
761ae08745Sheppo };
771ae08745Sheppo 
781ae08745Sheppo static ds_capability_t ps_panic_cap = {
791ae08745Sheppo 	"domain-panic",		/* svc_id */
801ae08745Sheppo 	ps_vers,		/* vers */
811ae08745Sheppo 	PS_NVERS		/* nvers */
821ae08745Sheppo };
831ae08745Sheppo 
841ae08745Sheppo static void ps_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl);
851ae08745Sheppo static void ps_unreg_handler(ds_cb_arg_t arg);
861ae08745Sheppo 
871ae08745Sheppo static void ps_md_data_handler(ds_cb_arg_t arg, void * buf, size_t buflen);
881ae08745Sheppo static void ps_shutdown_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
891ae08745Sheppo static void ps_panic_data_handler(ds_cb_arg_t arg, void * buf, size_t buflen);
901ae08745Sheppo 
911ae08745Sheppo static ds_clnt_ops_t ps_md_ops = {
921ae08745Sheppo 	ps_reg_handler,			/* ds_reg_cb */
931ae08745Sheppo 	ps_unreg_handler,		/* ds_unreg_cb */
941ae08745Sheppo 	ps_md_data_handler,		/* ds_data_cb */
951ae08745Sheppo 	&ds_md_handle			/* cb_arg */
961ae08745Sheppo };
971ae08745Sheppo 
981ae08745Sheppo static ds_clnt_ops_t ps_shutdown_ops = {
991ae08745Sheppo 	ps_reg_handler,			/* ds_reg_cb */
1001ae08745Sheppo 	ps_unreg_handler,		/* ds_unreg_cb */
1011ae08745Sheppo 	ps_shutdown_data_handler,	/* ds_data_cb */
1021ae08745Sheppo 	&ds_shutdown_handle		/* cb_arg */
1031ae08745Sheppo };
1041ae08745Sheppo 
1051ae08745Sheppo static ds_clnt_ops_t ps_panic_ops = {
1061ae08745Sheppo 	ps_reg_handler,			/* ds_reg_cb */
1071ae08745Sheppo 	ps_unreg_handler,		/* ds_unreg_cb */
1081ae08745Sheppo 	ps_panic_data_handler,		/* ds_data_cb */
1091ae08745Sheppo 	&ds_panic_handle		/* cb_arg */
1101ae08745Sheppo };
1111ae08745Sheppo 
1121ae08745Sheppo static int ps_init(void);
1131ae08745Sheppo static void ps_fini(void);
1141ae08745Sheppo 
1151ae08745Sheppo /*
1161ae08745Sheppo  * Power down timeout value of 5 minutes.
1171ae08745Sheppo  */
1181ae08745Sheppo #define	PLATSVC_POWERDOWN_DELAY		1200
1191ae08745Sheppo 
1201ae08745Sheppo static struct modlmisc modlmisc = {
1211ae08745Sheppo 	&mod_miscops,
122*f500b196SRichard Bean 	"sun4v Platform Services"
1231ae08745Sheppo };
1241ae08745Sheppo 
1251ae08745Sheppo static struct modlinkage modlinkage = {
1261ae08745Sheppo 	MODREV_1,
1271ae08745Sheppo 	(void *)&modlmisc,
1281ae08745Sheppo 	NULL
1291ae08745Sheppo };
1301ae08745Sheppo 
1311ae08745Sheppo int
1321ae08745Sheppo _init(void)
1331ae08745Sheppo {
1341ae08745Sheppo 	int	rv;
1351ae08745Sheppo 
1361ae08745Sheppo 	if ((rv = ps_init()) != 0)
1371ae08745Sheppo 		return (rv);
1381ae08745Sheppo 
1391ae08745Sheppo 	if ((rv = mod_install(&modlinkage)) != 0)
1401ae08745Sheppo 		ps_fini();
1411ae08745Sheppo 
1421ae08745Sheppo 	return (rv);
1431ae08745Sheppo }
1441ae08745Sheppo 
1451ae08745Sheppo int
1461ae08745Sheppo _info(struct modinfo *modinfop)
1471ae08745Sheppo {
1481ae08745Sheppo 	return (mod_info(&modlinkage, modinfop));
1491ae08745Sheppo }
1501ae08745Sheppo 
1511ae08745Sheppo int platsvc_allow_unload;
1521ae08745Sheppo 
1531ae08745Sheppo int
1541ae08745Sheppo _fini(void)
1551ae08745Sheppo {
1561ae08745Sheppo 	int	status;
1571ae08745Sheppo 
1581ae08745Sheppo 	if (platsvc_allow_unload == 0)
1591ae08745Sheppo 		return (EBUSY);
1601ae08745Sheppo 
1611ae08745Sheppo 	if ((status = mod_remove(&modlinkage)) == 0)
1621ae08745Sheppo 		ps_fini();
1631ae08745Sheppo 
1641ae08745Sheppo 	return (status);
1651ae08745Sheppo }
1661ae08745Sheppo 
1671ae08745Sheppo static int
1681ae08745Sheppo ps_init(void)
1691ae08745Sheppo {
1701ae08745Sheppo 	int	rv;
1711ae08745Sheppo 	extern int mdeg_init(void);
1721ae08745Sheppo 
1731ae08745Sheppo 	/* register with domain services framework */
1741ae08745Sheppo 	rv = ds_cap_init(&ps_md_cap, &ps_md_ops);
1751ae08745Sheppo 	if (rv != 0) {
1761ae08745Sheppo 		cmn_err(CE_WARN, "ds_cap_init md-update failed: %d", rv);
1771ae08745Sheppo 		return (rv);
1781ae08745Sheppo 	}
1791ae08745Sheppo 
1801ae08745Sheppo 	rv = ds_cap_init(&ps_shutdown_cap, &ps_shutdown_ops);
1811ae08745Sheppo 	if (rv != 0) {
1821ae08745Sheppo 		cmn_err(CE_WARN, "ds_cap_init domain-shutdown failed: %d", rv);
1831ae08745Sheppo 		(void) ds_cap_fini(&ps_md_cap);
1841ae08745Sheppo 		return (rv);
1851ae08745Sheppo 	}
1861ae08745Sheppo 
1871ae08745Sheppo 	rv = ds_cap_init(&ps_panic_cap, &ps_panic_ops);
1881ae08745Sheppo 	if (rv != 0) {
1891ae08745Sheppo 		cmn_err(CE_WARN, "ds_cap_init domain-panic failed: %d", rv);
1901ae08745Sheppo 		(void) ds_cap_fini(&ps_md_cap);
1911ae08745Sheppo 		(void) ds_cap_fini(&ps_shutdown_cap);
1921ae08745Sheppo 		return (rv);
1931ae08745Sheppo 	}
1941ae08745Sheppo 
1951ae08745Sheppo 	rv = mdeg_init();
1961ae08745Sheppo 
1971ae08745Sheppo 	return (rv);
1981ae08745Sheppo }
1991ae08745Sheppo 
2001ae08745Sheppo static void
2011ae08745Sheppo ps_fini(void)
2021ae08745Sheppo {
2031ae08745Sheppo 	extern void mdeg_fini(void);
2041ae08745Sheppo 
2051ae08745Sheppo 	/*
2061ae08745Sheppo 	 * Stop incoming requests from Zeus
2071ae08745Sheppo 	 */
2081ae08745Sheppo 	(void) ds_cap_fini(&ps_md_cap);
2091ae08745Sheppo 	(void) ds_cap_fini(&ps_shutdown_cap);
2101ae08745Sheppo 	(void) ds_cap_fini(&ps_panic_cap);
2111ae08745Sheppo 
2121ae08745Sheppo 	mdeg_fini();
2131ae08745Sheppo }
2141ae08745Sheppo 
2151ae08745Sheppo static void
2161ae08745Sheppo ps_md_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
2171ae08745Sheppo {
2181ae08745Sheppo 	extern int mach_descrip_update(void);
2191ae08745Sheppo 	extern void mdeg_notify_clients(void);
220f273041fSjm22469 	extern void recalc_xc_timeouts(void);
2211ae08745Sheppo 
2224e476149Srsmaeda 	ds_svc_hdl_t		 ds_handle = ds_md_handle;
2231ae08745Sheppo 	platsvc_md_update_req_t	 *msg = buf;
2241ae08745Sheppo 	platsvc_md_update_resp_t resp_msg;
2251ae08745Sheppo 	uint_t			 rv;
2261ae08745Sheppo 
2271ae08745Sheppo 	if (arg == NULL)
2281ae08745Sheppo 		return;
2291ae08745Sheppo 
2304e476149Srsmaeda 	if (ds_handle == DS_INVALID_HDL) {
2314e476149Srsmaeda 		DBG("ps_md_data_handler: DS handle no longer valid\n");
2324e476149Srsmaeda 		return;
2334e476149Srsmaeda 	}
2341ae08745Sheppo 
2351ae08745Sheppo 	if (msg == NULL || buflen != sizeof (platsvc_md_update_req_t)) {
2361ae08745Sheppo 		resp_msg.req_num = 0;
2371ae08745Sheppo 		resp_msg.result = MD_UPDATE_INVALID_MSG;
2381ae08745Sheppo 		if ((rv = ds_cap_send(ds_handle, &resp_msg,
2391ae08745Sheppo 		    sizeof (resp_msg))) != 0) {
2401ae08745Sheppo 			cmn_err(CE_NOTE, "md ds_cap_send failed (%d)", rv);
2411ae08745Sheppo 		}
2421ae08745Sheppo 		return;
2431ae08745Sheppo 	}
2441ae08745Sheppo 
2451ae08745Sheppo 	DBG("MD Reload...\n");
2461ae08745Sheppo 	if (mach_descrip_update()) {
2471ae08745Sheppo 		cmn_err(CE_WARN, "MD reload failed\n");
2481ae08745Sheppo 		return;
2491ae08745Sheppo 	}
2501ae08745Sheppo 
251f273041fSjm22469 	recalc_xc_timeouts();
252f273041fSjm22469 
2531ae08745Sheppo 	/*
2541ae08745Sheppo 	 * notify registered clients that MD has
2551ae08745Sheppo 	 * been updated
2561ae08745Sheppo 	 */
2571ae08745Sheppo 	mdeg_notify_clients();
2581ae08745Sheppo 
2591ae08745Sheppo 	resp_msg.req_num = msg->req_num;
2601ae08745Sheppo 	resp_msg.result = MD_UPDATE_SUCCESS;
2611ae08745Sheppo 	if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) {
2621ae08745Sheppo 		cmn_err(CE_NOTE, "md ds_cap_send resp failed (%d)", rv);
2631ae08745Sheppo 	}
2641ae08745Sheppo }
2651ae08745Sheppo 
2661ae08745Sheppo static void
2671ae08745Sheppo ps_shutdown_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
2681ae08745Sheppo {
2694e476149Srsmaeda 	ds_svc_hdl_t		ds_handle = ds_shutdown_handle;
2701ae08745Sheppo 	platsvc_shutdown_req_t	*msg = buf;
2711ae08745Sheppo 	platsvc_shutdown_resp_t	resp_msg;
2721ae08745Sheppo 	uint_t			rv;
2731ae08745Sheppo 	hrtime_t		start;
2741ae08745Sheppo 
2751ae08745Sheppo 	if (arg == NULL)
2761ae08745Sheppo 		return;
2771ae08745Sheppo 
2784e476149Srsmaeda 	if (ds_handle == DS_INVALID_HDL) {
2794e476149Srsmaeda 		DBG("ps_shutdown_data_handler: DS handle no longer valid\n");
2804e476149Srsmaeda 		return;
2814e476149Srsmaeda 	}
2821ae08745Sheppo 
2831ae08745Sheppo 	if (msg == NULL || buflen != sizeof (platsvc_shutdown_req_t)) {
2841ae08745Sheppo 		resp_msg.req_num = 0;
2851ae08745Sheppo 		resp_msg.result = DOMAIN_SHUTDOWN_INVALID_MSG;
2861ae08745Sheppo 		resp_msg.reason[0] = '\0';
2871ae08745Sheppo 		if ((rv = ds_cap_send(ds_handle, &resp_msg,
2881ae08745Sheppo 		    sizeof (resp_msg))) != 0) {
2891ae08745Sheppo 			cmn_err(CE_NOTE, "shutdown ds_cap_send failed (%d)",
2901ae08745Sheppo 			    rv);
2911ae08745Sheppo 		}
2921ae08745Sheppo 		return;
2931ae08745Sheppo 	}
2941ae08745Sheppo 
2951ae08745Sheppo 	resp_msg.req_num = msg->req_num;
2961ae08745Sheppo 	resp_msg.result = DOMAIN_SHUTDOWN_SUCCESS;
2971ae08745Sheppo 	resp_msg.reason[0] = '\0';
2981ae08745Sheppo 
2991ae08745Sheppo 	if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) {
3001ae08745Sheppo 		cmn_err(CE_NOTE, "shutdown ds_cap_send resp failed (%d)", rv);
3011ae08745Sheppo 	}
3021ae08745Sheppo 
3031ae08745Sheppo 	/*
3041ae08745Sheppo 	 * Honor the ldoms manager's shutdown delay requirement.
3051ae08745Sheppo 	 */
3061ae08745Sheppo 	cmn_err(CE_NOTE, "shutdown requested by ldom manager, "
3071ae08745Sheppo 	    "system shutdown in %d minutes", MS2MIN(msg->delay));
3081ae08745Sheppo 
3091ae08745Sheppo 	start = gethrtime();
3101ae08745Sheppo 	while (gethrtime() - start < MS2NANO(msg->delay))
3111ae08745Sheppo 		;
3121ae08745Sheppo 
3131ae08745Sheppo 	(void) kadmin(A_SHUTDOWN, AD_POWEROFF, NULL, kcred);
3141ae08745Sheppo }
3151ae08745Sheppo 
3161ae08745Sheppo 
3171ae08745Sheppo static void
3181ae08745Sheppo ps_panic_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
3191ae08745Sheppo {
3204e476149Srsmaeda 	ds_svc_hdl_t		ds_handle = ds_panic_handle;
3211ae08745Sheppo 	platsvc_panic_req_t	*msg = buf;
3221ae08745Sheppo 	platsvc_panic_resp_t	resp_msg;
3231ae08745Sheppo 	uint_t			rv;
3241ae08745Sheppo 
3251ae08745Sheppo 	if (arg == NULL)
3261ae08745Sheppo 		return;
3271ae08745Sheppo 
3284e476149Srsmaeda 	if (ds_handle == DS_INVALID_HDL) {
3294e476149Srsmaeda 		DBG("ps_panic_data_handler: DS handle no longer valid\n");
3304e476149Srsmaeda 		return;
3314e476149Srsmaeda 	}
3321ae08745Sheppo 
3331ae08745Sheppo 	if (msg == NULL || buflen != sizeof (platsvc_panic_req_t)) {
3341ae08745Sheppo 		resp_msg.req_num = 0;
3351ae08745Sheppo 		resp_msg.result = DOMAIN_PANIC_INVALID_MSG;
3361ae08745Sheppo 		resp_msg.reason[0] = '\0';
3371ae08745Sheppo 		if ((rv = ds_cap_send(ds_handle, &resp_msg,
3381ae08745Sheppo 		    sizeof (resp_msg))) != 0) {
3391ae08745Sheppo 			cmn_err(CE_NOTE, "panic ds_cap_send resp failed (%d)",
3401ae08745Sheppo 			    rv);
3411ae08745Sheppo 		}
3421ae08745Sheppo 		return;
3431ae08745Sheppo 	}
3441ae08745Sheppo 
3451ae08745Sheppo 	resp_msg.req_num = msg->req_num;
3461ae08745Sheppo 	resp_msg.result = DOMAIN_PANIC_SUCCESS;
3471ae08745Sheppo 	resp_msg.reason[0] = '\0';
3481ae08745Sheppo 	if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) {
3491ae08745Sheppo 		cmn_err(CE_NOTE, "panic ds_cap_send resp failed (%d)", rv);
3501ae08745Sheppo 	}
3511ae08745Sheppo 
3521ae08745Sheppo 	cmn_err(CE_PANIC, "Panic forced by ldom manager");
3531ae08745Sheppo 	_NOTE(NOTREACHED)
3541ae08745Sheppo }
3551ae08745Sheppo 
3561ae08745Sheppo static void
3571ae08745Sheppo ps_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
3581ae08745Sheppo {
3591ae08745Sheppo 	DBG("ps_reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n",
3601ae08745Sheppo 	    arg, ver->major, ver->minor, hdl);
3611ae08745Sheppo 
3621ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_md_handle)
3631ae08745Sheppo 		ds_md_handle = hdl;
3641ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_shutdown_handle)
3651ae08745Sheppo 		ds_shutdown_handle = hdl;
3661ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_panic_handle)
3671ae08745Sheppo 		ds_panic_handle = hdl;
3681ae08745Sheppo }
3691ae08745Sheppo 
3701ae08745Sheppo static void
3711ae08745Sheppo ps_unreg_handler(ds_cb_arg_t arg)
3721ae08745Sheppo {
3731ae08745Sheppo 	DBG("ps_unreg_handler: arg=0x%p\n", arg);
3741ae08745Sheppo 
3751ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_md_handle)
3761ae08745Sheppo 		ds_md_handle = DS_INVALID_HDL;
3771ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_shutdown_handle)
3781ae08745Sheppo 		ds_shutdown_handle = DS_INVALID_HDL;
3791ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_panic_handle)
3801ae08745Sheppo 		ds_panic_handle = DS_INVALID_HDL;
3811ae08745Sheppo }
382