xref: /illumos-gate/usr/src/uts/sun4v/io/platsvc.c (revision 02b4e56c)
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*02b4e56cSHaik Aftandilian  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
241ae08745Sheppo  */
251ae08745Sheppo 
261ae08745Sheppo /*
271ae08745Sheppo  * sun4v Platform Services Module
281ae08745Sheppo  */
291ae08745Sheppo 
301ae08745Sheppo #include <sys/modctl.h>
311ae08745Sheppo #include <sys/cmn_err.h>
321ae08745Sheppo #include <sys/machsystm.h>
331ae08745Sheppo #include <sys/note.h>
341ae08745Sheppo #include <sys/uadmin.h>
351ae08745Sheppo #include <sys/ds.h>
361ae08745Sheppo #include <sys/platsvc.h>
37023e71deSHaik Aftandilian #include <sys/ddi.h>
38023e71deSHaik Aftandilian #include <sys/suspend.h>
39023e71deSHaik Aftandilian #include <sys/proc.h>
40023e71deSHaik Aftandilian #include <sys/disp.h>
41*02b4e56cSHaik Aftandilian #include <sys/drctl.h>
421ae08745Sheppo 
431ae08745Sheppo /*
441ae08745Sheppo  * Debugging routines
451ae08745Sheppo  */
461ae08745Sheppo #ifdef DEBUG
471ae08745Sheppo uint_t ps_debug = 0x0;
481ae08745Sheppo #define	DBG	if (ps_debug) printf
491ae08745Sheppo #else /* DEBUG */
501ae08745Sheppo #define	DBG	_NOTE(CONSTCOND) if (0) printf
511ae08745Sheppo #endif /* DEBUG */
521ae08745Sheppo 
531ae08745Sheppo /*
541ae08745Sheppo  * Time resolution conversions.
551ae08745Sheppo  */
561ae08745Sheppo #define	MS2NANO(x)	((x) * MICROSEC)
571ae08745Sheppo #define	MS2SEC(x)	((x) / MILLISEC)
581ae08745Sheppo #define	MS2MIN(x)	(MS2SEC(x) / 60)
59023e71deSHaik Aftandilian #define	SEC2HZ(x)	(drv_usectohz((x) * MICROSEC))
601ae08745Sheppo 
611ae08745Sheppo /*
621ae08745Sheppo  * Domains Services interaction
631ae08745Sheppo  */
641ae08745Sheppo static ds_svc_hdl_t	ds_md_handle;
651ae08745Sheppo static ds_svc_hdl_t	ds_shutdown_handle;
661ae08745Sheppo static ds_svc_hdl_t	ds_panic_handle;
67023e71deSHaik Aftandilian static ds_svc_hdl_t	ds_suspend_handle;
681ae08745Sheppo 
691ae08745Sheppo static ds_ver_t		ps_vers[] = {{ 1, 0 }};
701ae08745Sheppo #define	PS_NVERS	(sizeof (ps_vers) / sizeof (ps_vers[0]))
711ae08745Sheppo 
721ae08745Sheppo static ds_capability_t ps_md_cap = {
731ae08745Sheppo 	"md-update",		/* svc_id */
741ae08745Sheppo 	ps_vers,		/* vers */
751ae08745Sheppo 	PS_NVERS		/* nvers */
761ae08745Sheppo };
771ae08745Sheppo 
781ae08745Sheppo static ds_capability_t ps_shutdown_cap = {
791ae08745Sheppo 	"domain-shutdown",	/* svc_id */
801ae08745Sheppo 	ps_vers,		/* vers */
811ae08745Sheppo 	PS_NVERS		/* nvers */
821ae08745Sheppo };
831ae08745Sheppo 
841ae08745Sheppo static ds_capability_t ps_panic_cap = {
851ae08745Sheppo 	"domain-panic",		/* svc_id */
861ae08745Sheppo 	ps_vers,		/* vers */
871ae08745Sheppo 	PS_NVERS		/* nvers */
881ae08745Sheppo };
891ae08745Sheppo 
90023e71deSHaik Aftandilian static ds_capability_t ps_suspend_cap = {
91023e71deSHaik Aftandilian 	"domain-suspend",	/* svc_id */
92023e71deSHaik Aftandilian 	ps_vers,		/* vers */
93023e71deSHaik Aftandilian 	PS_NVERS		/* nvers */
94023e71deSHaik Aftandilian };
95023e71deSHaik Aftandilian 
961ae08745Sheppo static void ps_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl);
971ae08745Sheppo static void ps_unreg_handler(ds_cb_arg_t arg);
981ae08745Sheppo 
99023e71deSHaik Aftandilian static void ps_md_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
1001ae08745Sheppo static void ps_shutdown_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
101023e71deSHaik Aftandilian static void ps_panic_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
102023e71deSHaik Aftandilian static void ps_suspend_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
1031ae08745Sheppo 
1041ae08745Sheppo static ds_clnt_ops_t ps_md_ops = {
1051ae08745Sheppo 	ps_reg_handler,			/* ds_reg_cb */
1061ae08745Sheppo 	ps_unreg_handler,		/* ds_unreg_cb */
1071ae08745Sheppo 	ps_md_data_handler,		/* ds_data_cb */
1081ae08745Sheppo 	&ds_md_handle			/* cb_arg */
1091ae08745Sheppo };
1101ae08745Sheppo 
1111ae08745Sheppo static ds_clnt_ops_t ps_shutdown_ops = {
1121ae08745Sheppo 	ps_reg_handler,			/* ds_reg_cb */
1131ae08745Sheppo 	ps_unreg_handler,		/* ds_unreg_cb */
1141ae08745Sheppo 	ps_shutdown_data_handler,	/* ds_data_cb */
1151ae08745Sheppo 	&ds_shutdown_handle		/* cb_arg */
1161ae08745Sheppo };
1171ae08745Sheppo 
1181ae08745Sheppo static ds_clnt_ops_t ps_panic_ops = {
1191ae08745Sheppo 	ps_reg_handler,			/* ds_reg_cb */
1201ae08745Sheppo 	ps_unreg_handler,		/* ds_unreg_cb */
1211ae08745Sheppo 	ps_panic_data_handler,		/* ds_data_cb */
1221ae08745Sheppo 	&ds_panic_handle		/* cb_arg */
1231ae08745Sheppo };
1241ae08745Sheppo 
125023e71deSHaik Aftandilian static ds_clnt_ops_t ps_suspend_ops = {
126023e71deSHaik Aftandilian 	ps_reg_handler,			/* ds_reg_cb */
127023e71deSHaik Aftandilian 	ps_unreg_handler,		/* ds_unreg_cb */
128023e71deSHaik Aftandilian 	ps_suspend_data_handler,	/* ds_data_cb */
129023e71deSHaik Aftandilian 	&ds_suspend_handle		/* cb_arg */
130023e71deSHaik Aftandilian };
131023e71deSHaik Aftandilian 
1321ae08745Sheppo static int ps_init(void);
1331ae08745Sheppo static void ps_fini(void);
1341ae08745Sheppo 
1351ae08745Sheppo /*
1364e476149Srsmaeda  * Power down timeout value of 5 minutes.
1371ae08745Sheppo  */
1381ae08745Sheppo #define	PLATSVC_POWERDOWN_DELAY		1200
1391ae08745Sheppo 
140023e71deSHaik Aftandilian /*
141023e71deSHaik Aftandilian  * Set to true if OS suspend is supported. If OS suspend is not
142023e71deSHaik Aftandilian  * supported, the suspend service will not be started.
143023e71deSHaik Aftandilian  */
144023e71deSHaik Aftandilian static boolean_t ps_suspend_enabled = B_FALSE;
145023e71deSHaik Aftandilian 
146023e71deSHaik Aftandilian /*
147023e71deSHaik Aftandilian  * Suspend service request handling
148023e71deSHaik Aftandilian  */
149023e71deSHaik Aftandilian typedef struct ps_suspend_data {
150023e71deSHaik Aftandilian 	void		*buf;
151023e71deSHaik Aftandilian 	size_t		buflen;
152023e71deSHaik Aftandilian } ps_suspend_data_t;
153023e71deSHaik Aftandilian 
154023e71deSHaik Aftandilian static kmutex_t ps_suspend_mutex;
155023e71deSHaik Aftandilian static kcondvar_t ps_suspend_cv;
156023e71deSHaik Aftandilian 
157023e71deSHaik Aftandilian static ps_suspend_data_t *ps_suspend_data = NULL;
158023e71deSHaik Aftandilian static boolean_t ps_suspend_thread_exit = B_FALSE;
159023e71deSHaik Aftandilian static kthread_t *ps_suspend_thread = NULL;
160023e71deSHaik Aftandilian 
161023e71deSHaik Aftandilian static void ps_suspend_sequence(ps_suspend_data_t *data);
162023e71deSHaik Aftandilian static void ps_suspend_thread_func(void);
163023e71deSHaik Aftandilian 
164023e71deSHaik Aftandilian /*
165023e71deSHaik Aftandilian  * The DELAY timeout is the time (in seconds) to wait for the
166023e71deSHaik Aftandilian  * suspend service to be re-registered after a suspend/resume
167023e71deSHaik Aftandilian  * operation. The INTVAL time is the time (in seconds) to wait
168023e71deSHaik Aftandilian  * between retry attempts when sending the post-suspend message
169023e71deSHaik Aftandilian  * after a suspend/resume operation.
170023e71deSHaik Aftandilian  */
171023e71deSHaik Aftandilian #define	PLATSVC_SUSPEND_REREG_DELAY	60
172023e71deSHaik Aftandilian #define	PLATSVC_SUSPEND_RETRY_INTVAL	1
173023e71deSHaik Aftandilian static int ps_suspend_rereg_delay = PLATSVC_SUSPEND_REREG_DELAY;
174023e71deSHaik Aftandilian static int ps_suspend_retry_intval = PLATSVC_SUSPEND_RETRY_INTVAL;
175023e71deSHaik Aftandilian 
176023e71deSHaik Aftandilian 
1771ae08745Sheppo static struct modlmisc modlmisc = {
1781ae08745Sheppo 	&mod_miscops,
179f500b196SRichard Bean 	"sun4v Platform Services"
1801ae08745Sheppo };
1811ae08745Sheppo 
1821ae08745Sheppo static struct modlinkage modlinkage = {
1831ae08745Sheppo 	MODREV_1,
1841ae08745Sheppo 	(void *)&modlmisc,
1851ae08745Sheppo 	NULL
1861ae08745Sheppo };
1871ae08745Sheppo 
1881ae08745Sheppo int
_init(void)1891ae08745Sheppo _init(void)
1901ae08745Sheppo {
1911ae08745Sheppo 	int	rv;
1921ae08745Sheppo 
1931ae08745Sheppo 	if ((rv = ps_init()) != 0)
1941ae08745Sheppo 		return (rv);
1951ae08745Sheppo 
1961ae08745Sheppo 	if ((rv = mod_install(&modlinkage)) != 0)
1971ae08745Sheppo 		ps_fini();
1981ae08745Sheppo 
1991ae08745Sheppo 	return (rv);
2001ae08745Sheppo }
2011ae08745Sheppo 
2021ae08745Sheppo int
_info(struct modinfo * modinfop)2031ae08745Sheppo _info(struct modinfo *modinfop)
2041ae08745Sheppo {
2051ae08745Sheppo 	return (mod_info(&modlinkage, modinfop));
2061ae08745Sheppo }
2071ae08745Sheppo 
2081ae08745Sheppo int platsvc_allow_unload;
2091ae08745Sheppo 
2101ae08745Sheppo int
_fini(void)2111ae08745Sheppo _fini(void)
2121ae08745Sheppo {
2131ae08745Sheppo 	int	status;
2141ae08745Sheppo 
2151ae08745Sheppo 	if (platsvc_allow_unload == 0)
2161ae08745Sheppo 		return (EBUSY);
2171ae08745Sheppo 
2181ae08745Sheppo 	if ((status = mod_remove(&modlinkage)) == 0)
2191ae08745Sheppo 		ps_fini();
2201ae08745Sheppo 
2211ae08745Sheppo 	return (status);
2221ae08745Sheppo }
2231ae08745Sheppo 
2241ae08745Sheppo static int
ps_init(void)2251ae08745Sheppo ps_init(void)
2261ae08745Sheppo {
2271ae08745Sheppo 	int	rv;
2281ae08745Sheppo 	extern int mdeg_init(void);
229023e71deSHaik Aftandilian 	extern void mdeg_fini(void);
2301ae08745Sheppo 
2311ae08745Sheppo 	/* register with domain services framework */
2321ae08745Sheppo 	rv = ds_cap_init(&ps_md_cap, &ps_md_ops);
2331ae08745Sheppo 	if (rv != 0) {
2341ae08745Sheppo 		cmn_err(CE_WARN, "ds_cap_init md-update failed: %d", rv);
2351ae08745Sheppo 		return (rv);
2361ae08745Sheppo 	}
2371ae08745Sheppo 
238023e71deSHaik Aftandilian 	rv = mdeg_init();
239023e71deSHaik Aftandilian 	if (rv != 0) {
240023e71deSHaik Aftandilian 		(void) ds_cap_fini(&ps_md_cap);
241023e71deSHaik Aftandilian 		return (rv);
242023e71deSHaik Aftandilian 	}
243023e71deSHaik Aftandilian 
2441ae08745Sheppo 	rv = ds_cap_init(&ps_shutdown_cap, &ps_shutdown_ops);
2451ae08745Sheppo 	if (rv != 0) {
2461ae08745Sheppo 		cmn_err(CE_WARN, "ds_cap_init domain-shutdown failed: %d", rv);
247023e71deSHaik Aftandilian 		mdeg_fini();
2481ae08745Sheppo 		(void) ds_cap_fini(&ps_md_cap);
2491ae08745Sheppo 		return (rv);
2501ae08745Sheppo 	}
2511ae08745Sheppo 
2521ae08745Sheppo 	rv = ds_cap_init(&ps_panic_cap, &ps_panic_ops);
2531ae08745Sheppo 	if (rv != 0) {
2541ae08745Sheppo 		cmn_err(CE_WARN, "ds_cap_init domain-panic failed: %d", rv);
2551ae08745Sheppo 		(void) ds_cap_fini(&ps_md_cap);
256023e71deSHaik Aftandilian 		mdeg_fini();
2571ae08745Sheppo 		(void) ds_cap_fini(&ps_shutdown_cap);
2581ae08745Sheppo 		return (rv);
2591ae08745Sheppo 	}
2601ae08745Sheppo 
261023e71deSHaik Aftandilian 	ps_suspend_enabled = suspend_supported();
262023e71deSHaik Aftandilian 
263023e71deSHaik Aftandilian 	if (ps_suspend_enabled) {
264023e71deSHaik Aftandilian 		mutex_init(&ps_suspend_mutex, NULL, MUTEX_DEFAULT, NULL);
265023e71deSHaik Aftandilian 		cv_init(&ps_suspend_cv, NULL, CV_DEFAULT, NULL);
266023e71deSHaik Aftandilian 		ps_suspend_thread_exit = B_FALSE;
267023e71deSHaik Aftandilian 
268023e71deSHaik Aftandilian 		rv = ds_cap_init(&ps_suspend_cap, &ps_suspend_ops);
269023e71deSHaik Aftandilian 		if (rv != 0) {
270023e71deSHaik Aftandilian 			cmn_err(CE_WARN, "ds_cap_init domain-suspend failed: "
271023e71deSHaik Aftandilian 			    "%d", rv);
272023e71deSHaik Aftandilian 			(void) ds_cap_fini(&ps_md_cap);
273023e71deSHaik Aftandilian 			mdeg_fini();
274023e71deSHaik Aftandilian 			(void) ds_cap_fini(&ps_shutdown_cap);
275023e71deSHaik Aftandilian 			(void) ds_cap_fini(&ps_panic_cap);
276023e71deSHaik Aftandilian 			mutex_destroy(&ps_suspend_mutex);
277023e71deSHaik Aftandilian 			cv_destroy(&ps_suspend_cv);
278023e71deSHaik Aftandilian 			return (rv);
279023e71deSHaik Aftandilian 		}
2801ae08745Sheppo 
281023e71deSHaik Aftandilian 		ps_suspend_thread = thread_create(NULL, 2 * DEFAULTSTKSZ,
282023e71deSHaik Aftandilian 		    ps_suspend_thread_func, NULL, 0, &p0, TS_RUN, minclsyspri);
283023e71deSHaik Aftandilian 	}
284023e71deSHaik Aftandilian 
285023e71deSHaik Aftandilian 	return (0);
2861ae08745Sheppo }
2871ae08745Sheppo 
2881ae08745Sheppo static void
ps_fini(void)2891ae08745Sheppo ps_fini(void)
2901ae08745Sheppo {
2911ae08745Sheppo 	extern void mdeg_fini(void);
2921ae08745Sheppo 
2931ae08745Sheppo 	/*
2941ae08745Sheppo 	 * Stop incoming requests from Zeus
2951ae08745Sheppo 	 */
2961ae08745Sheppo 	(void) ds_cap_fini(&ps_md_cap);
2971ae08745Sheppo 	(void) ds_cap_fini(&ps_shutdown_cap);
2981ae08745Sheppo 	(void) ds_cap_fini(&ps_panic_cap);
2991ae08745Sheppo 
300023e71deSHaik Aftandilian 	if (ps_suspend_enabled) {
301023e71deSHaik Aftandilian 		(void) ds_cap_fini(&ps_suspend_cap);
302023e71deSHaik Aftandilian 		if (ps_suspend_thread != NULL) {
303023e71deSHaik Aftandilian 			mutex_enter(&ps_suspend_mutex);
304023e71deSHaik Aftandilian 			ps_suspend_thread_exit = B_TRUE;
305023e71deSHaik Aftandilian 			cv_signal(&ps_suspend_cv);
306023e71deSHaik Aftandilian 			mutex_exit(&ps_suspend_mutex);
307023e71deSHaik Aftandilian 
308023e71deSHaik Aftandilian 			thread_join(ps_suspend_thread->t_did);
309023e71deSHaik Aftandilian 			ps_suspend_thread = NULL;
310023e71deSHaik Aftandilian 
311023e71deSHaik Aftandilian 			mutex_destroy(&ps_suspend_mutex);
312023e71deSHaik Aftandilian 			cv_destroy(&ps_suspend_cv);
313023e71deSHaik Aftandilian 		}
314023e71deSHaik Aftandilian 	}
315023e71deSHaik Aftandilian 
3161ae08745Sheppo 	mdeg_fini();
3171ae08745Sheppo }
3181ae08745Sheppo 
3191ae08745Sheppo static void
ps_md_data_handler(ds_cb_arg_t arg,void * buf,size_t buflen)3201ae08745Sheppo ps_md_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
3211ae08745Sheppo {
3221ae08745Sheppo 	extern int mach_descrip_update(void);
3231ae08745Sheppo 	extern void mdeg_notify_clients(void);
324f273041fSjm 	extern void recalc_xc_timeouts(void);
3251ae08745Sheppo 
3264e476149Srsmaeda 	ds_svc_hdl_t		 ds_handle = ds_md_handle;
3271ae08745Sheppo 	platsvc_md_update_req_t	 *msg = buf;
3281ae08745Sheppo 	platsvc_md_update_resp_t resp_msg;
3291ae08745Sheppo 	uint_t			 rv;
3301ae08745Sheppo 
3311ae08745Sheppo 	if (arg == NULL)
3321ae08745Sheppo 		return;
3331ae08745Sheppo 
3344e476149Srsmaeda 	if (ds_handle == DS_INVALID_HDL) {
3354e476149Srsmaeda 		DBG("ps_md_data_handler: DS handle no longer valid\n");
3364e476149Srsmaeda 		return;
3374e476149Srsmaeda 	}
3381ae08745Sheppo 
3391ae08745Sheppo 	if (msg == NULL || buflen != sizeof (platsvc_md_update_req_t)) {
3401ae08745Sheppo 		resp_msg.req_num = 0;
3411ae08745Sheppo 		resp_msg.result = MD_UPDATE_INVALID_MSG;
3421ae08745Sheppo 		if ((rv = ds_cap_send(ds_handle, &resp_msg,
3431ae08745Sheppo 		    sizeof (resp_msg))) != 0) {
3441ae08745Sheppo 			cmn_err(CE_NOTE, "md ds_cap_send failed (%d)", rv);
3451ae08745Sheppo 		}
3461ae08745Sheppo 		return;
3471ae08745Sheppo 	}
3481ae08745Sheppo 
3491ae08745Sheppo 	DBG("MD Reload...\n");
3501ae08745Sheppo 	if (mach_descrip_update()) {
3511ae08745Sheppo 		cmn_err(CE_WARN, "MD reload failed\n");
3521ae08745Sheppo 		return;
3531ae08745Sheppo 	}
3541ae08745Sheppo 
355f273041fSjm 	recalc_xc_timeouts();
356f273041fSjm 
3571ae08745Sheppo 	/*
3581ae08745Sheppo 	 * notify registered clients that MD has
3591ae08745Sheppo 	 * been updated
3601ae08745Sheppo 	 */
3611ae08745Sheppo 	mdeg_notify_clients();
3621ae08745Sheppo 
3631ae08745Sheppo 	resp_msg.req_num = msg->req_num;
3641ae08745Sheppo 	resp_msg.result = MD_UPDATE_SUCCESS;
3651ae08745Sheppo 	if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) {
3661ae08745Sheppo 		cmn_err(CE_NOTE, "md ds_cap_send resp failed (%d)", rv);
3671ae08745Sheppo 	}
3681ae08745Sheppo }
3691ae08745Sheppo 
3701ae08745Sheppo static void
ps_shutdown_data_handler(ds_cb_arg_t arg,void * buf,size_t buflen)3711ae08745Sheppo ps_shutdown_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
3721ae08745Sheppo {
3734e476149Srsmaeda 	ds_svc_hdl_t		ds_handle = ds_shutdown_handle;
3741ae08745Sheppo 	platsvc_shutdown_req_t	*msg = buf;
3751ae08745Sheppo 	platsvc_shutdown_resp_t	resp_msg;
3761ae08745Sheppo 	uint_t			rv;
3771ae08745Sheppo 	hrtime_t		start;
3781ae08745Sheppo 
3791ae08745Sheppo 	if (arg == NULL)
3801ae08745Sheppo 		return;
3811ae08745Sheppo 
3824e476149Srsmaeda 	if (ds_handle == DS_INVALID_HDL) {
3834e476149Srsmaeda 		DBG("ps_shutdown_data_handler: DS handle no longer valid\n");
3844e476149Srsmaeda 		return;
3854e476149Srsmaeda 	}
3861ae08745Sheppo 
3871ae08745Sheppo 	if (msg == NULL || buflen != sizeof (platsvc_shutdown_req_t)) {
3881ae08745Sheppo 		resp_msg.req_num = 0;
3891ae08745Sheppo 		resp_msg.result = DOMAIN_SHUTDOWN_INVALID_MSG;
3901ae08745Sheppo 		resp_msg.reason[0] = '\0';
3911ae08745Sheppo 		if ((rv = ds_cap_send(ds_handle, &resp_msg,
3921ae08745Sheppo 		    sizeof (resp_msg))) != 0) {
3931ae08745Sheppo 			cmn_err(CE_NOTE, "shutdown ds_cap_send failed (%d)",
3941ae08745Sheppo 			    rv);
3951ae08745Sheppo 		}
3961ae08745Sheppo 		return;
3971ae08745Sheppo 	}
3981ae08745Sheppo 
3991ae08745Sheppo 	resp_msg.req_num = msg->req_num;
4001ae08745Sheppo 	resp_msg.result = DOMAIN_SHUTDOWN_SUCCESS;
4011ae08745Sheppo 	resp_msg.reason[0] = '\0';
4021ae08745Sheppo 
4031ae08745Sheppo 	if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) {
4041ae08745Sheppo 		cmn_err(CE_NOTE, "shutdown ds_cap_send resp failed (%d)", rv);
4051ae08745Sheppo 	}
4061ae08745Sheppo 
4071ae08745Sheppo 	/*
4081ae08745Sheppo 	 * Honor the ldoms manager's shutdown delay requirement.
4091ae08745Sheppo 	 */
4101ae08745Sheppo 	cmn_err(CE_NOTE, "shutdown requested by ldom manager, "
4111ae08745Sheppo 	    "system shutdown in %d minutes", MS2MIN(msg->delay));
4121ae08745Sheppo 
4131ae08745Sheppo 	start = gethrtime();
4141ae08745Sheppo 	while (gethrtime() - start < MS2NANO(msg->delay))
4151ae08745Sheppo 		;
4161ae08745Sheppo 
4171ae08745Sheppo 	(void) kadmin(A_SHUTDOWN, AD_POWEROFF, NULL, kcred);
4181ae08745Sheppo }
4191ae08745Sheppo 
4201ae08745Sheppo 
4211ae08745Sheppo static void
ps_panic_data_handler(ds_cb_arg_t arg,void * buf,size_t buflen)4221ae08745Sheppo ps_panic_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
4231ae08745Sheppo {
4244e476149Srsmaeda 	ds_svc_hdl_t		ds_handle = ds_panic_handle;
4251ae08745Sheppo 	platsvc_panic_req_t	*msg = buf;
4261ae08745Sheppo 	platsvc_panic_resp_t	resp_msg;
4271ae08745Sheppo 	uint_t			rv;
4281ae08745Sheppo 
4291ae08745Sheppo 	if (arg == NULL)
4301ae08745Sheppo 		return;
4311ae08745Sheppo 
4324e476149Srsmaeda 	if (ds_handle == DS_INVALID_HDL) {
4334e476149Srsmaeda 		DBG("ps_panic_data_handler: DS handle no longer valid\n");
4344e476149Srsmaeda 		return;
4354e476149Srsmaeda 	}
4361ae08745Sheppo 
4371ae08745Sheppo 	if (msg == NULL || buflen != sizeof (platsvc_panic_req_t)) {
4381ae08745Sheppo 		resp_msg.req_num = 0;
4391ae08745Sheppo 		resp_msg.result = DOMAIN_PANIC_INVALID_MSG;
4401ae08745Sheppo 		resp_msg.reason[0] = '\0';
4411ae08745Sheppo 		if ((rv = ds_cap_send(ds_handle, &resp_msg,
4421ae08745Sheppo 		    sizeof (resp_msg))) != 0) {
4431ae08745Sheppo 			cmn_err(CE_NOTE, "panic ds_cap_send resp failed (%d)",
4441ae08745Sheppo 			    rv);
4451ae08745Sheppo 		}
4461ae08745Sheppo 		return;
4471ae08745Sheppo 	}
4481ae08745Sheppo 
4491ae08745Sheppo 	resp_msg.req_num = msg->req_num;
4501ae08745Sheppo 	resp_msg.result = DOMAIN_PANIC_SUCCESS;
4511ae08745Sheppo 	resp_msg.reason[0] = '\0';
4521ae08745Sheppo 	if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) {
4531ae08745Sheppo 		cmn_err(CE_NOTE, "panic ds_cap_send resp failed (%d)", rv);
4541ae08745Sheppo 	}
4551ae08745Sheppo 
4561ae08745Sheppo 	cmn_err(CE_PANIC, "Panic forced by ldom manager");
4571ae08745Sheppo 	_NOTE(NOTREACHED)
4581ae08745Sheppo }
4591ae08745Sheppo 
460023e71deSHaik Aftandilian /*
461023e71deSHaik Aftandilian  * Send a suspend response message. If a timeout is specified, wait
462023e71deSHaik Aftandilian  * intval seconds between attempts to send the message. The timeout
463023e71deSHaik Aftandilian  * and intval arguments are in seconds.
464023e71deSHaik Aftandilian  */
465023e71deSHaik Aftandilian static void
ps_suspend_send_response(ds_svc_hdl_t * ds_handle,uint64_t req_num,uint32_t result,uint32_t rec_result,char * reason,int timeout,int intval)466023e71deSHaik Aftandilian ps_suspend_send_response(ds_svc_hdl_t *ds_handle, uint64_t req_num,
467023e71deSHaik Aftandilian     uint32_t result, uint32_t rec_result, char *reason, int timeout,
468023e71deSHaik Aftandilian     int intval)
469023e71deSHaik Aftandilian {
470023e71deSHaik Aftandilian 	platsvc_suspend_resp_t	*resp;
471023e71deSHaik Aftandilian 	size_t			reason_length;
472023e71deSHaik Aftandilian 	int			tries = 0;
473023e71deSHaik Aftandilian 	int			rv = -1;
474023e71deSHaik Aftandilian 	time_t			deadline;
475023e71deSHaik Aftandilian 
476023e71deSHaik Aftandilian 	if (reason == NULL) {
477023e71deSHaik Aftandilian 		reason_length = 0;
478023e71deSHaik Aftandilian 	} else {
479023e71deSHaik Aftandilian 		/* Get number of non-NULL bytes */
480023e71deSHaik Aftandilian 		reason_length = strnlen(reason, SUSPEND_MAX_REASON_SIZE - 1);
481023e71deSHaik Aftandilian 		ASSERT(reason[reason_length] == '\0');
482023e71deSHaik Aftandilian 		/* Account for NULL terminator */
483023e71deSHaik Aftandilian 		reason_length++;
484023e71deSHaik Aftandilian 	}
485023e71deSHaik Aftandilian 
486023e71deSHaik Aftandilian 	resp = (platsvc_suspend_resp_t *)
487023e71deSHaik Aftandilian 	    kmem_zalloc(sizeof (platsvc_suspend_resp_t) + reason_length,
488023e71deSHaik Aftandilian 	    KM_SLEEP);
489023e71deSHaik Aftandilian 
490023e71deSHaik Aftandilian 	resp->req_num = req_num;
491023e71deSHaik Aftandilian 	resp->result = result;
492023e71deSHaik Aftandilian 	resp->rec_result = rec_result;
493023e71deSHaik Aftandilian 	if (reason_length > 0) {
494023e71deSHaik Aftandilian 		bcopy(reason, &resp->reason, reason_length - 1);
495023e71deSHaik Aftandilian 		/* Ensure NULL terminator is present */
496023e71deSHaik Aftandilian 		resp->reason[reason_length] = '\0';
497023e71deSHaik Aftandilian 	}
498023e71deSHaik Aftandilian 
499023e71deSHaik Aftandilian 	if (timeout == 0) {
500023e71deSHaik Aftandilian 		tries++;
501023e71deSHaik Aftandilian 		rv = ds_cap_send(*ds_handle, resp,
502023e71deSHaik Aftandilian 		    sizeof (platsvc_suspend_resp_t) + reason_length);
503023e71deSHaik Aftandilian 	} else {
504023e71deSHaik Aftandilian 		deadline = gethrestime_sec() + timeout;
505023e71deSHaik Aftandilian 		do {
506023e71deSHaik Aftandilian 			ds_svc_hdl_t hdl;
507023e71deSHaik Aftandilian 			/*
508023e71deSHaik Aftandilian 			 * Copy the handle so we can ensure we never pass
509023e71deSHaik Aftandilian 			 * an invalid handle to ds_cap_send. We don't want
510023e71deSHaik Aftandilian 			 * to trigger warning messages just because the
511023e71deSHaik Aftandilian 			 * service was temporarily unregistered.
512023e71deSHaik Aftandilian 			 */
513023e71deSHaik Aftandilian 			if ((hdl = *ds_handle) == DS_INVALID_HDL) {
514023e71deSHaik Aftandilian 				delay(SEC2HZ(intval));
515023e71deSHaik Aftandilian 			} else if ((rv = ds_cap_send(hdl, resp,
516023e71deSHaik Aftandilian 			    sizeof (platsvc_suspend_resp_t) +
517023e71deSHaik Aftandilian 			    reason_length)) != 0) {
518023e71deSHaik Aftandilian 				tries++;
519023e71deSHaik Aftandilian 				delay(SEC2HZ(intval));
520023e71deSHaik Aftandilian 			}
521023e71deSHaik Aftandilian 		} while ((rv != 0) && (gethrestime_sec() < deadline));
522023e71deSHaik Aftandilian 	}
523023e71deSHaik Aftandilian 
524023e71deSHaik Aftandilian 	if (rv != 0) {
525023e71deSHaik Aftandilian 		cmn_err(CE_NOTE, "suspend ds_cap_send resp failed (%d) "
526023e71deSHaik Aftandilian 		    "sending message: %d, attempts: %d", rv, resp->result,
527023e71deSHaik Aftandilian 		    tries);
528023e71deSHaik Aftandilian 	}
529023e71deSHaik Aftandilian 
530023e71deSHaik Aftandilian 	kmem_free(resp, sizeof (platsvc_suspend_resp_t) + reason_length);
531023e71deSHaik Aftandilian }
532023e71deSHaik Aftandilian 
533023e71deSHaik Aftandilian /*
534023e71deSHaik Aftandilian  * Handle data coming in for the suspend service. The suspend is
535023e71deSHaik Aftandilian  * sequenced by the ps_suspend_thread, but perform some checks here
536023e71deSHaik Aftandilian  * to make sure that the request is a valid request message and that
537023e71deSHaik Aftandilian  * a suspend operation is not already in progress.
538023e71deSHaik Aftandilian  */
539023e71deSHaik Aftandilian /*ARGSUSED*/
540023e71deSHaik Aftandilian static void
ps_suspend_data_handler(ds_cb_arg_t arg,void * buf,size_t buflen)541023e71deSHaik Aftandilian ps_suspend_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
542023e71deSHaik Aftandilian {
543023e71deSHaik Aftandilian 	platsvc_suspend_req_t	*msg = buf;
544023e71deSHaik Aftandilian 
545023e71deSHaik Aftandilian 	if (arg == NULL)
546023e71deSHaik Aftandilian 		return;
547023e71deSHaik Aftandilian 
548023e71deSHaik Aftandilian 	if (ds_suspend_handle == DS_INVALID_HDL) {
549023e71deSHaik Aftandilian 		DBG("ps_suspend_data_handler: DS handle no longer valid\n");
550023e71deSHaik Aftandilian 		return;
551023e71deSHaik Aftandilian 	}
552023e71deSHaik Aftandilian 
553023e71deSHaik Aftandilian 	/* Handle invalid requests */
554023e71deSHaik Aftandilian 	if (msg == NULL || buflen != sizeof (platsvc_suspend_req_t) ||
555023e71deSHaik Aftandilian 	    msg->type != DOMAIN_SUSPEND_SUSPEND) {
556023e71deSHaik Aftandilian 		ps_suspend_send_response(&ds_suspend_handle, msg->req_num,
557023e71deSHaik Aftandilian 		    DOMAIN_SUSPEND_INVALID_MSG, DOMAIN_SUSPEND_REC_SUCCESS,
558023e71deSHaik Aftandilian 		    NULL, 0, 0);
559023e71deSHaik Aftandilian 		return;
560023e71deSHaik Aftandilian 	}
561023e71deSHaik Aftandilian 
562023e71deSHaik Aftandilian 	/*
563023e71deSHaik Aftandilian 	 * If ps_suspend_thread_exit is set, ds_cap_fini has been
564023e71deSHaik Aftandilian 	 * called and we shouldn't be receving data. Handle this unexpected
565023e71deSHaik Aftandilian 	 * case by returning without sending a response.
566023e71deSHaik Aftandilian 	 */
567023e71deSHaik Aftandilian 	if (ps_suspend_thread_exit) {
568023e71deSHaik Aftandilian 		DBG("ps_suspend_data_handler: ps_suspend_thread is exiting\n");
569023e71deSHaik Aftandilian 		return;
570023e71deSHaik Aftandilian 	}
571023e71deSHaik Aftandilian 
572023e71deSHaik Aftandilian 	mutex_enter(&ps_suspend_mutex);
573023e71deSHaik Aftandilian 
574023e71deSHaik Aftandilian 	/* If a suspend operation is in progress, abort now */
575023e71deSHaik Aftandilian 	if (ps_suspend_data != NULL) {
576023e71deSHaik Aftandilian 		mutex_exit(&ps_suspend_mutex);
577023e71deSHaik Aftandilian 		ps_suspend_send_response(&ds_suspend_handle, msg->req_num,
578023e71deSHaik Aftandilian 		    DOMAIN_SUSPEND_INPROGRESS, DOMAIN_SUSPEND_REC_SUCCESS,
579023e71deSHaik Aftandilian 		    NULL, 0, 0);
580023e71deSHaik Aftandilian 		return;
581023e71deSHaik Aftandilian 	}
582023e71deSHaik Aftandilian 
583023e71deSHaik Aftandilian 	ps_suspend_data = kmem_alloc(sizeof (ps_suspend_data_t), KM_SLEEP);
584023e71deSHaik Aftandilian 	ps_suspend_data->buf = kmem_alloc(buflen, KM_SLEEP);
585023e71deSHaik Aftandilian 	ps_suspend_data->buflen = buflen;
586023e71deSHaik Aftandilian 	bcopy(buf, ps_suspend_data->buf, buflen);
587023e71deSHaik Aftandilian 
588023e71deSHaik Aftandilian 	cv_signal(&ps_suspend_cv);
589023e71deSHaik Aftandilian 	mutex_exit(&ps_suspend_mutex);
590023e71deSHaik Aftandilian }
591023e71deSHaik Aftandilian 
592023e71deSHaik Aftandilian /*
593023e71deSHaik Aftandilian  * Schedule the suspend operation by calling the pre-suspend, suspend,
594023e71deSHaik Aftandilian  * and post-suspend functions. When sending back response messages, we
595023e71deSHaik Aftandilian  * only use a timeout for the post-suspend response because after
596023e71deSHaik Aftandilian  * a resume, domain services will be re-registered and we may not
597023e71deSHaik Aftandilian  * be able to send the response immediately.
598023e71deSHaik Aftandilian  */
599023e71deSHaik Aftandilian static void
ps_suspend_sequence(ps_suspend_data_t * data)600023e71deSHaik Aftandilian ps_suspend_sequence(ps_suspend_data_t *data)
601023e71deSHaik Aftandilian {
602023e71deSHaik Aftandilian 	platsvc_suspend_req_t	*msg;
603023e71deSHaik Aftandilian 	uint32_t		rec_result;
604023e71deSHaik Aftandilian 	char			*error_reason;
605023e71deSHaik Aftandilian 	boolean_t		recovered = B_TRUE;
606*02b4e56cSHaik Aftandilian 	uint_t			rv = 0;
607*02b4e56cSHaik Aftandilian 	int			dr_block;
608023e71deSHaik Aftandilian 
609023e71deSHaik Aftandilian 	ASSERT(data != NULL);
610023e71deSHaik Aftandilian 
611023e71deSHaik Aftandilian 	msg = data->buf;
612023e71deSHaik Aftandilian 	error_reason = (char *)kmem_zalloc(SUSPEND_MAX_REASON_SIZE, KM_SLEEP);
613023e71deSHaik Aftandilian 
614*02b4e56cSHaik Aftandilian 	/*
615*02b4e56cSHaik Aftandilian 	 * Abort the suspend if a DR operation is in progress. Otherwise,
616*02b4e56cSHaik Aftandilian 	 * continue whilst blocking any new DR operations.
617*02b4e56cSHaik Aftandilian 	 */
618*02b4e56cSHaik Aftandilian 	if ((dr_block = drctl_tryblock()) == 0) {
619*02b4e56cSHaik Aftandilian 		/* Pre-suspend */
620*02b4e56cSHaik Aftandilian 		rv = suspend_pre(error_reason, SUSPEND_MAX_REASON_SIZE,
621*02b4e56cSHaik Aftandilian 		    &recovered);
622*02b4e56cSHaik Aftandilian 	} else {
623*02b4e56cSHaik Aftandilian 		/* A DR operation is in progress */
624*02b4e56cSHaik Aftandilian 		(void) strncpy(error_reason, DOMAIN_SUSPEND_DR_ERROR_STR,
625*02b4e56cSHaik Aftandilian 		    SUSPEND_MAX_REASON_SIZE);
626*02b4e56cSHaik Aftandilian 	}
627*02b4e56cSHaik Aftandilian 
628*02b4e56cSHaik Aftandilian 	if (dr_block != 0 || rv != 0) {
629023e71deSHaik Aftandilian 		rec_result = (recovered ? DOMAIN_SUSPEND_REC_SUCCESS :
630023e71deSHaik Aftandilian 		    DOMAIN_SUSPEND_REC_FAILURE);
631023e71deSHaik Aftandilian 
632023e71deSHaik Aftandilian 		ps_suspend_send_response(&ds_suspend_handle, msg->req_num,
633023e71deSHaik Aftandilian 		    DOMAIN_SUSPEND_PRE_FAILURE, rec_result, error_reason, 0, 0);
634023e71deSHaik Aftandilian 
635*02b4e56cSHaik Aftandilian 		if (dr_block == 0)
636*02b4e56cSHaik Aftandilian 			drctl_unblock();
637023e71deSHaik Aftandilian 		kmem_free(error_reason, SUSPEND_MAX_REASON_SIZE);
638023e71deSHaik Aftandilian 		return;
639023e71deSHaik Aftandilian 	}
640023e71deSHaik Aftandilian 
641023e71deSHaik Aftandilian 	ps_suspend_send_response(&ds_suspend_handle, msg->req_num,
642023e71deSHaik Aftandilian 	    DOMAIN_SUSPEND_PRE_SUCCESS, 0, NULL, 0, 0);
643023e71deSHaik Aftandilian 
644023e71deSHaik Aftandilian 	/* Suspend */
645023e71deSHaik Aftandilian 	rv = suspend_start(error_reason, SUSPEND_MAX_REASON_SIZE);
646023e71deSHaik Aftandilian 	if (rv != 0) {
647023e71deSHaik Aftandilian 		rec_result = (suspend_post(NULL, 0) == 0 ?
648023e71deSHaik Aftandilian 		    DOMAIN_SUSPEND_REC_SUCCESS : DOMAIN_SUSPEND_REC_FAILURE);
649023e71deSHaik Aftandilian 
650023e71deSHaik Aftandilian 		ps_suspend_send_response(&ds_suspend_handle, msg->req_num,
651023e71deSHaik Aftandilian 		    DOMAIN_SUSPEND_SUSPEND_FAILURE, rec_result, error_reason,
652023e71deSHaik Aftandilian 		    0, 0);
653023e71deSHaik Aftandilian 
654*02b4e56cSHaik Aftandilian 		drctl_unblock();
655023e71deSHaik Aftandilian 		kmem_free(error_reason, SUSPEND_MAX_REASON_SIZE);
656023e71deSHaik Aftandilian 		return;
657023e71deSHaik Aftandilian 	}
658023e71deSHaik Aftandilian 
659023e71deSHaik Aftandilian 	/* Post-suspend */
660023e71deSHaik Aftandilian 	rv = suspend_post(error_reason, SUSPEND_MAX_REASON_SIZE);
661023e71deSHaik Aftandilian 	if (rv != 0) {
662023e71deSHaik Aftandilian 		ps_suspend_send_response(&ds_suspend_handle, msg->req_num,
663023e71deSHaik Aftandilian 		    DOMAIN_SUSPEND_POST_FAILURE, 0, error_reason,
664023e71deSHaik Aftandilian 		    ps_suspend_rereg_delay, ps_suspend_retry_intval);
665023e71deSHaik Aftandilian 	} else {
666023e71deSHaik Aftandilian 		ps_suspend_send_response(&ds_suspend_handle, msg->req_num,
667023e71deSHaik Aftandilian 		    DOMAIN_SUSPEND_POST_SUCCESS, 0, error_reason,
668023e71deSHaik Aftandilian 		    ps_suspend_rereg_delay, ps_suspend_retry_intval);
669023e71deSHaik Aftandilian 	}
670023e71deSHaik Aftandilian 
671*02b4e56cSHaik Aftandilian 	drctl_unblock();
672023e71deSHaik Aftandilian 	kmem_free(error_reason, SUSPEND_MAX_REASON_SIZE);
673023e71deSHaik Aftandilian }
674023e71deSHaik Aftandilian 
675023e71deSHaik Aftandilian /*
676023e71deSHaik Aftandilian  * Wait for a suspend request or for ps_suspend_thread_exit to be set.
677023e71deSHaik Aftandilian  */
678023e71deSHaik Aftandilian static void
ps_suspend_thread_func(void)679023e71deSHaik Aftandilian ps_suspend_thread_func(void)
680023e71deSHaik Aftandilian {
681023e71deSHaik Aftandilian 	mutex_enter(&ps_suspend_mutex);
682023e71deSHaik Aftandilian 
683023e71deSHaik Aftandilian 	while (ps_suspend_thread_exit == B_FALSE) {
684023e71deSHaik Aftandilian 
685023e71deSHaik Aftandilian 		if (ps_suspend_data == NULL) {
686023e71deSHaik Aftandilian 			cv_wait(&ps_suspend_cv, &ps_suspend_mutex);
687023e71deSHaik Aftandilian 			continue;
688023e71deSHaik Aftandilian 		}
689023e71deSHaik Aftandilian 
690023e71deSHaik Aftandilian 		mutex_exit(&ps_suspend_mutex);
691023e71deSHaik Aftandilian 		ps_suspend_sequence(ps_suspend_data);
692023e71deSHaik Aftandilian 		mutex_enter(&ps_suspend_mutex);
693023e71deSHaik Aftandilian 
694023e71deSHaik Aftandilian 		kmem_free(ps_suspend_data->buf, ps_suspend_data->buflen);
695023e71deSHaik Aftandilian 		kmem_free(ps_suspend_data, sizeof (ps_suspend_data_t));
696023e71deSHaik Aftandilian 		ps_suspend_data = NULL;
697023e71deSHaik Aftandilian 	}
698023e71deSHaik Aftandilian 
699023e71deSHaik Aftandilian 	mutex_exit(&ps_suspend_mutex);
700023e71deSHaik Aftandilian 
701023e71deSHaik Aftandilian 	thread_exit();
702023e71deSHaik Aftandilian }
703023e71deSHaik Aftandilian 
7041ae08745Sheppo static void
ps_reg_handler(ds_cb_arg_t arg,ds_ver_t * ver,ds_svc_hdl_t hdl)7051ae08745Sheppo ps_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
7061ae08745Sheppo {
7071ae08745Sheppo 	DBG("ps_reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n",
7081ae08745Sheppo 	    arg, ver->major, ver->minor, hdl);
7091ae08745Sheppo 
7101ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_md_handle)
7111ae08745Sheppo 		ds_md_handle = hdl;
7121ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_shutdown_handle)
7131ae08745Sheppo 		ds_shutdown_handle = hdl;
7141ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_panic_handle)
7151ae08745Sheppo 		ds_panic_handle = hdl;
716023e71deSHaik Aftandilian 	if ((ds_svc_hdl_t *)arg == &ds_suspend_handle)
717023e71deSHaik Aftandilian 		ds_suspend_handle = hdl;
7181ae08745Sheppo }
7191ae08745Sheppo 
7201ae08745Sheppo static void
ps_unreg_handler(ds_cb_arg_t arg)7211ae08745Sheppo ps_unreg_handler(ds_cb_arg_t arg)
7221ae08745Sheppo {
7231ae08745Sheppo 	DBG("ps_unreg_handler: arg=0x%p\n", arg);
7241ae08745Sheppo 
7251ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_md_handle)
7261ae08745Sheppo 		ds_md_handle = DS_INVALID_HDL;
7271ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_shutdown_handle)
7281ae08745Sheppo 		ds_shutdown_handle = DS_INVALID_HDL;
7291ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_panic_handle)
7301ae08745Sheppo 		ds_panic_handle = DS_INVALID_HDL;
731023e71deSHaik Aftandilian 	if ((ds_svc_hdl_t *)arg == &ds_suspend_handle)
732023e71deSHaik Aftandilian 		ds_suspend_handle = DS_INVALID_HDL;
7331ae08745Sheppo }
734