xref: /onnv-gate/usr/src/uts/sun4v/io/platsvc.c (revision 12260:806de32452bd)
11991Sheppo /*
21991Sheppo  * CDDL HEADER START
31991Sheppo  *
41991Sheppo  * The contents of this file are subject to the terms of the
51991Sheppo  * Common Development and Distribution License (the "License").
61991Sheppo  * You may not use this file except in compliance with the License.
71991Sheppo  *
81991Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91991Sheppo  * or http://www.opensolaris.org/os/licensing.
101991Sheppo  * See the License for the specific language governing permissions
111991Sheppo  * and limitations under the License.
121991Sheppo  *
131991Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
141991Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151991Sheppo  * If applicable, add the following below this CDDL HEADER, with the
161991Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
171991Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
181991Sheppo  *
191991Sheppo  * CDDL HEADER END
201991Sheppo  */
211991Sheppo 
221991Sheppo /*
23*12260SHaik.Aftandilian@Sun.COM  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
241991Sheppo  */
251991Sheppo 
261991Sheppo /*
271991Sheppo  * sun4v Platform Services Module
281991Sheppo  */
291991Sheppo 
301991Sheppo #include <sys/modctl.h>
311991Sheppo #include <sys/cmn_err.h>
321991Sheppo #include <sys/machsystm.h>
331991Sheppo #include <sys/note.h>
341991Sheppo #include <sys/uadmin.h>
351991Sheppo #include <sys/ds.h>
361991Sheppo #include <sys/platsvc.h>
3711172SHaik.Aftandilian@Sun.COM #include <sys/ddi.h>
3811172SHaik.Aftandilian@Sun.COM #include <sys/suspend.h>
3911172SHaik.Aftandilian@Sun.COM #include <sys/proc.h>
4011172SHaik.Aftandilian@Sun.COM #include <sys/disp.h>
41*12260SHaik.Aftandilian@Sun.COM #include <sys/drctl.h>
421991Sheppo 
431991Sheppo /*
441991Sheppo  * Debugging routines
451991Sheppo  */
461991Sheppo #ifdef DEBUG
471991Sheppo uint_t ps_debug = 0x0;
481991Sheppo #define	DBG	if (ps_debug) printf
491991Sheppo #else /* DEBUG */
501991Sheppo #define	DBG	_NOTE(CONSTCOND) if (0) printf
511991Sheppo #endif /* DEBUG */
521991Sheppo 
531991Sheppo /*
541991Sheppo  * Time resolution conversions.
551991Sheppo  */
561991Sheppo #define	MS2NANO(x)	((x) * MICROSEC)
571991Sheppo #define	MS2SEC(x)	((x) / MILLISEC)
581991Sheppo #define	MS2MIN(x)	(MS2SEC(x) / 60)
5911172SHaik.Aftandilian@Sun.COM #define	SEC2HZ(x)	(drv_usectohz((x) * MICROSEC))
601991Sheppo 
611991Sheppo /*
621991Sheppo  * Domains Services interaction
631991Sheppo  */
641991Sheppo static ds_svc_hdl_t	ds_md_handle;
651991Sheppo static ds_svc_hdl_t	ds_shutdown_handle;
661991Sheppo static ds_svc_hdl_t	ds_panic_handle;
6711172SHaik.Aftandilian@Sun.COM static ds_svc_hdl_t	ds_suspend_handle;
681991Sheppo 
691991Sheppo static ds_ver_t		ps_vers[] = {{ 1, 0 }};
701991Sheppo #define	PS_NVERS	(sizeof (ps_vers) / sizeof (ps_vers[0]))
711991Sheppo 
721991Sheppo static ds_capability_t ps_md_cap = {
731991Sheppo 	"md-update",		/* svc_id */
741991Sheppo 	ps_vers,		/* vers */
751991Sheppo 	PS_NVERS		/* nvers */
761991Sheppo };
771991Sheppo 
781991Sheppo static ds_capability_t ps_shutdown_cap = {
791991Sheppo 	"domain-shutdown",	/* svc_id */
801991Sheppo 	ps_vers,		/* vers */
811991Sheppo 	PS_NVERS		/* nvers */
821991Sheppo };
831991Sheppo 
841991Sheppo static ds_capability_t ps_panic_cap = {
851991Sheppo 	"domain-panic",		/* svc_id */
861991Sheppo 	ps_vers,		/* vers */
871991Sheppo 	PS_NVERS		/* nvers */
881991Sheppo };
891991Sheppo 
9011172SHaik.Aftandilian@Sun.COM static ds_capability_t ps_suspend_cap = {
9111172SHaik.Aftandilian@Sun.COM 	"domain-suspend",	/* svc_id */
9211172SHaik.Aftandilian@Sun.COM 	ps_vers,		/* vers */
9311172SHaik.Aftandilian@Sun.COM 	PS_NVERS		/* nvers */
9411172SHaik.Aftandilian@Sun.COM };
9511172SHaik.Aftandilian@Sun.COM 
961991Sheppo static void ps_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl);
971991Sheppo static void ps_unreg_handler(ds_cb_arg_t arg);
981991Sheppo 
9911172SHaik.Aftandilian@Sun.COM static void ps_md_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
1001991Sheppo static void ps_shutdown_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
10111172SHaik.Aftandilian@Sun.COM static void ps_panic_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
10211172SHaik.Aftandilian@Sun.COM static void ps_suspend_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
1031991Sheppo 
1041991Sheppo static ds_clnt_ops_t ps_md_ops = {
1051991Sheppo 	ps_reg_handler,			/* ds_reg_cb */
1061991Sheppo 	ps_unreg_handler,		/* ds_unreg_cb */
1071991Sheppo 	ps_md_data_handler,		/* ds_data_cb */
1081991Sheppo 	&ds_md_handle			/* cb_arg */
1091991Sheppo };
1101991Sheppo 
1111991Sheppo static ds_clnt_ops_t ps_shutdown_ops = {
1121991Sheppo 	ps_reg_handler,			/* ds_reg_cb */
1131991Sheppo 	ps_unreg_handler,		/* ds_unreg_cb */
1141991Sheppo 	ps_shutdown_data_handler,	/* ds_data_cb */
1151991Sheppo 	&ds_shutdown_handle		/* cb_arg */
1161991Sheppo };
1171991Sheppo 
1181991Sheppo static ds_clnt_ops_t ps_panic_ops = {
1191991Sheppo 	ps_reg_handler,			/* ds_reg_cb */
1201991Sheppo 	ps_unreg_handler,		/* ds_unreg_cb */
1211991Sheppo 	ps_panic_data_handler,		/* ds_data_cb */
1221991Sheppo 	&ds_panic_handle		/* cb_arg */
1231991Sheppo };
1241991Sheppo 
12511172SHaik.Aftandilian@Sun.COM static ds_clnt_ops_t ps_suspend_ops = {
12611172SHaik.Aftandilian@Sun.COM 	ps_reg_handler,			/* ds_reg_cb */
12711172SHaik.Aftandilian@Sun.COM 	ps_unreg_handler,		/* ds_unreg_cb */
12811172SHaik.Aftandilian@Sun.COM 	ps_suspend_data_handler,	/* ds_data_cb */
12911172SHaik.Aftandilian@Sun.COM 	&ds_suspend_handle		/* cb_arg */
13011172SHaik.Aftandilian@Sun.COM };
13111172SHaik.Aftandilian@Sun.COM 
1321991Sheppo static int ps_init(void);
1331991Sheppo static void ps_fini(void);
1341991Sheppo 
1351991Sheppo /*
1363759Srsmaeda  * Power down timeout value of 5 minutes.
1371991Sheppo  */
1381991Sheppo #define	PLATSVC_POWERDOWN_DELAY		1200
1391991Sheppo 
14011172SHaik.Aftandilian@Sun.COM /*
14111172SHaik.Aftandilian@Sun.COM  * Set to true if OS suspend is supported. If OS suspend is not
14211172SHaik.Aftandilian@Sun.COM  * supported, the suspend service will not be started.
14311172SHaik.Aftandilian@Sun.COM  */
14411172SHaik.Aftandilian@Sun.COM static boolean_t ps_suspend_enabled = B_FALSE;
14511172SHaik.Aftandilian@Sun.COM 
14611172SHaik.Aftandilian@Sun.COM /*
14711172SHaik.Aftandilian@Sun.COM  * Suspend service request handling
14811172SHaik.Aftandilian@Sun.COM  */
14911172SHaik.Aftandilian@Sun.COM typedef struct ps_suspend_data {
15011172SHaik.Aftandilian@Sun.COM 	void		*buf;
15111172SHaik.Aftandilian@Sun.COM 	size_t		buflen;
15211172SHaik.Aftandilian@Sun.COM } ps_suspend_data_t;
15311172SHaik.Aftandilian@Sun.COM 
15411172SHaik.Aftandilian@Sun.COM static kmutex_t ps_suspend_mutex;
15511172SHaik.Aftandilian@Sun.COM static kcondvar_t ps_suspend_cv;
15611172SHaik.Aftandilian@Sun.COM 
15711172SHaik.Aftandilian@Sun.COM static ps_suspend_data_t *ps_suspend_data = NULL;
15811172SHaik.Aftandilian@Sun.COM static boolean_t ps_suspend_thread_exit = B_FALSE;
15911172SHaik.Aftandilian@Sun.COM static kthread_t *ps_suspend_thread = NULL;
16011172SHaik.Aftandilian@Sun.COM 
16111172SHaik.Aftandilian@Sun.COM static void ps_suspend_sequence(ps_suspend_data_t *data);
16211172SHaik.Aftandilian@Sun.COM static void ps_suspend_thread_func(void);
16311172SHaik.Aftandilian@Sun.COM 
16411172SHaik.Aftandilian@Sun.COM /*
16511172SHaik.Aftandilian@Sun.COM  * The DELAY timeout is the time (in seconds) to wait for the
16611172SHaik.Aftandilian@Sun.COM  * suspend service to be re-registered after a suspend/resume
16711172SHaik.Aftandilian@Sun.COM  * operation. The INTVAL time is the time (in seconds) to wait
16811172SHaik.Aftandilian@Sun.COM  * between retry attempts when sending the post-suspend message
16911172SHaik.Aftandilian@Sun.COM  * after a suspend/resume operation.
17011172SHaik.Aftandilian@Sun.COM  */
17111172SHaik.Aftandilian@Sun.COM #define	PLATSVC_SUSPEND_REREG_DELAY	60
17211172SHaik.Aftandilian@Sun.COM #define	PLATSVC_SUSPEND_RETRY_INTVAL	1
17311172SHaik.Aftandilian@Sun.COM static int ps_suspend_rereg_delay = PLATSVC_SUSPEND_REREG_DELAY;
17411172SHaik.Aftandilian@Sun.COM static int ps_suspend_retry_intval = PLATSVC_SUSPEND_RETRY_INTVAL;
17511172SHaik.Aftandilian@Sun.COM 
17611172SHaik.Aftandilian@Sun.COM 
1771991Sheppo static struct modlmisc modlmisc = {
1781991Sheppo 	&mod_miscops,
1797799SRichard.Bean@Sun.COM 	"sun4v Platform Services"
1801991Sheppo };
1811991Sheppo 
1821991Sheppo static struct modlinkage modlinkage = {
1831991Sheppo 	MODREV_1,
1841991Sheppo 	(void *)&modlmisc,
1851991Sheppo 	NULL
1861991Sheppo };
1871991Sheppo 
1881991Sheppo int
_init(void)1891991Sheppo _init(void)
1901991Sheppo {
1911991Sheppo 	int	rv;
1921991Sheppo 
1931991Sheppo 	if ((rv = ps_init()) != 0)
1941991Sheppo 		return (rv);
1951991Sheppo 
1961991Sheppo 	if ((rv = mod_install(&modlinkage)) != 0)
1971991Sheppo 		ps_fini();
1981991Sheppo 
1991991Sheppo 	return (rv);
2001991Sheppo }
2011991Sheppo 
2021991Sheppo int
_info(struct modinfo * modinfop)2031991Sheppo _info(struct modinfo *modinfop)
2041991Sheppo {
2051991Sheppo 	return (mod_info(&modlinkage, modinfop));
2061991Sheppo }
2071991Sheppo 
2081991Sheppo int platsvc_allow_unload;
2091991Sheppo 
2101991Sheppo int
_fini(void)2111991Sheppo _fini(void)
2121991Sheppo {
2131991Sheppo 	int	status;
2141991Sheppo 
2151991Sheppo 	if (platsvc_allow_unload == 0)
2161991Sheppo 		return (EBUSY);
2171991Sheppo 
2181991Sheppo 	if ((status = mod_remove(&modlinkage)) == 0)
2191991Sheppo 		ps_fini();
2201991Sheppo 
2211991Sheppo 	return (status);
2221991Sheppo }
2231991Sheppo 
2241991Sheppo static int
ps_init(void)2251991Sheppo ps_init(void)
2261991Sheppo {
2271991Sheppo 	int	rv;
2281991Sheppo 	extern int mdeg_init(void);
22911172SHaik.Aftandilian@Sun.COM 	extern void mdeg_fini(void);
2301991Sheppo 
2311991Sheppo 	/* register with domain services framework */
2321991Sheppo 	rv = ds_cap_init(&ps_md_cap, &ps_md_ops);
2331991Sheppo 	if (rv != 0) {
2341991Sheppo 		cmn_err(CE_WARN, "ds_cap_init md-update failed: %d", rv);
2351991Sheppo 		return (rv);
2361991Sheppo 	}
2371991Sheppo 
23811172SHaik.Aftandilian@Sun.COM 	rv = mdeg_init();
23911172SHaik.Aftandilian@Sun.COM 	if (rv != 0) {
24011172SHaik.Aftandilian@Sun.COM 		(void) ds_cap_fini(&ps_md_cap);
24111172SHaik.Aftandilian@Sun.COM 		return (rv);
24211172SHaik.Aftandilian@Sun.COM 	}
24311172SHaik.Aftandilian@Sun.COM 
2441991Sheppo 	rv = ds_cap_init(&ps_shutdown_cap, &ps_shutdown_ops);
2451991Sheppo 	if (rv != 0) {
2461991Sheppo 		cmn_err(CE_WARN, "ds_cap_init domain-shutdown failed: %d", rv);
24711172SHaik.Aftandilian@Sun.COM 		mdeg_fini();
2481991Sheppo 		(void) ds_cap_fini(&ps_md_cap);
2491991Sheppo 		return (rv);
2501991Sheppo 	}
2511991Sheppo 
2521991Sheppo 	rv = ds_cap_init(&ps_panic_cap, &ps_panic_ops);
2531991Sheppo 	if (rv != 0) {
2541991Sheppo 		cmn_err(CE_WARN, "ds_cap_init domain-panic failed: %d", rv);
2551991Sheppo 		(void) ds_cap_fini(&ps_md_cap);
25611172SHaik.Aftandilian@Sun.COM 		mdeg_fini();
2571991Sheppo 		(void) ds_cap_fini(&ps_shutdown_cap);
2581991Sheppo 		return (rv);
2591991Sheppo 	}
2601991Sheppo 
26111172SHaik.Aftandilian@Sun.COM 	ps_suspend_enabled = suspend_supported();
26211172SHaik.Aftandilian@Sun.COM 
26311172SHaik.Aftandilian@Sun.COM 	if (ps_suspend_enabled) {
26411172SHaik.Aftandilian@Sun.COM 		mutex_init(&ps_suspend_mutex, NULL, MUTEX_DEFAULT, NULL);
26511172SHaik.Aftandilian@Sun.COM 		cv_init(&ps_suspend_cv, NULL, CV_DEFAULT, NULL);
26611172SHaik.Aftandilian@Sun.COM 		ps_suspend_thread_exit = B_FALSE;
2671991Sheppo 
26811172SHaik.Aftandilian@Sun.COM 		rv = ds_cap_init(&ps_suspend_cap, &ps_suspend_ops);
26911172SHaik.Aftandilian@Sun.COM 		if (rv != 0) {
27011172SHaik.Aftandilian@Sun.COM 			cmn_err(CE_WARN, "ds_cap_init domain-suspend failed: "
27111172SHaik.Aftandilian@Sun.COM 			    "%d", rv);
27211172SHaik.Aftandilian@Sun.COM 			(void) ds_cap_fini(&ps_md_cap);
27311172SHaik.Aftandilian@Sun.COM 			mdeg_fini();
27411172SHaik.Aftandilian@Sun.COM 			(void) ds_cap_fini(&ps_shutdown_cap);
27511172SHaik.Aftandilian@Sun.COM 			(void) ds_cap_fini(&ps_panic_cap);
27611172SHaik.Aftandilian@Sun.COM 			mutex_destroy(&ps_suspend_mutex);
27711172SHaik.Aftandilian@Sun.COM 			cv_destroy(&ps_suspend_cv);
27811172SHaik.Aftandilian@Sun.COM 			return (rv);
27911172SHaik.Aftandilian@Sun.COM 		}
28011172SHaik.Aftandilian@Sun.COM 
28111172SHaik.Aftandilian@Sun.COM 		ps_suspend_thread = thread_create(NULL, 2 * DEFAULTSTKSZ,
28211172SHaik.Aftandilian@Sun.COM 		    ps_suspend_thread_func, NULL, 0, &p0, TS_RUN, minclsyspri);
28311172SHaik.Aftandilian@Sun.COM 	}
28411172SHaik.Aftandilian@Sun.COM 
28511172SHaik.Aftandilian@Sun.COM 	return (0);
2861991Sheppo }
2871991Sheppo 
2881991Sheppo static void
ps_fini(void)2891991Sheppo ps_fini(void)
2901991Sheppo {
2911991Sheppo 	extern void mdeg_fini(void);
2921991Sheppo 
2931991Sheppo 	/*
2941991Sheppo 	 * Stop incoming requests from Zeus
2951991Sheppo 	 */
2961991Sheppo 	(void) ds_cap_fini(&ps_md_cap);
2971991Sheppo 	(void) ds_cap_fini(&ps_shutdown_cap);
2981991Sheppo 	(void) ds_cap_fini(&ps_panic_cap);
2991991Sheppo 
30011172SHaik.Aftandilian@Sun.COM 	if (ps_suspend_enabled) {
30111172SHaik.Aftandilian@Sun.COM 		(void) ds_cap_fini(&ps_suspend_cap);
30211172SHaik.Aftandilian@Sun.COM 		if (ps_suspend_thread != NULL) {
30311172SHaik.Aftandilian@Sun.COM 			mutex_enter(&ps_suspend_mutex);
30411172SHaik.Aftandilian@Sun.COM 			ps_suspend_thread_exit = B_TRUE;
30511172SHaik.Aftandilian@Sun.COM 			cv_signal(&ps_suspend_cv);
30611172SHaik.Aftandilian@Sun.COM 			mutex_exit(&ps_suspend_mutex);
30711172SHaik.Aftandilian@Sun.COM 
30811172SHaik.Aftandilian@Sun.COM 			thread_join(ps_suspend_thread->t_did);
30911172SHaik.Aftandilian@Sun.COM 			ps_suspend_thread = NULL;
31011172SHaik.Aftandilian@Sun.COM 
31111172SHaik.Aftandilian@Sun.COM 			mutex_destroy(&ps_suspend_mutex);
31211172SHaik.Aftandilian@Sun.COM 			cv_destroy(&ps_suspend_cv);
31311172SHaik.Aftandilian@Sun.COM 		}
31411172SHaik.Aftandilian@Sun.COM 	}
31511172SHaik.Aftandilian@Sun.COM 
3161991Sheppo 	mdeg_fini();
3171991Sheppo }
3181991Sheppo 
3191991Sheppo static void
ps_md_data_handler(ds_cb_arg_t arg,void * buf,size_t buflen)3201991Sheppo ps_md_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
3211991Sheppo {
3221991Sheppo 	extern int mach_descrip_update(void);
3231991Sheppo 	extern void mdeg_notify_clients(void);
3242957Sjm22469 	extern void recalc_xc_timeouts(void);
3251991Sheppo 
3263759Srsmaeda 	ds_svc_hdl_t		 ds_handle = ds_md_handle;
3271991Sheppo 	platsvc_md_update_req_t	 *msg = buf;
3281991Sheppo 	platsvc_md_update_resp_t resp_msg;
3291991Sheppo 	uint_t			 rv;
3301991Sheppo 
3311991Sheppo 	if (arg == NULL)
3321991Sheppo 		return;
3331991Sheppo 
3343759Srsmaeda 	if (ds_handle == DS_INVALID_HDL) {
3353759Srsmaeda 		DBG("ps_md_data_handler: DS handle no longer valid\n");
3363759Srsmaeda 		return;
3373759Srsmaeda 	}
3381991Sheppo 
3391991Sheppo 	if (msg == NULL || buflen != sizeof (platsvc_md_update_req_t)) {
3401991Sheppo 		resp_msg.req_num = 0;
3411991Sheppo 		resp_msg.result = MD_UPDATE_INVALID_MSG;
3421991Sheppo 		if ((rv = ds_cap_send(ds_handle, &resp_msg,
3431991Sheppo 		    sizeof (resp_msg))) != 0) {
3441991Sheppo 			cmn_err(CE_NOTE, "md ds_cap_send failed (%d)", rv);
3451991Sheppo 		}
3461991Sheppo 		return;
3471991Sheppo 	}
3481991Sheppo 
3491991Sheppo 	DBG("MD Reload...\n");
3501991Sheppo 	if (mach_descrip_update()) {
3511991Sheppo 		cmn_err(CE_WARN, "MD reload failed\n");
3521991Sheppo 		return;
3531991Sheppo 	}
3541991Sheppo 
3552957Sjm22469 	recalc_xc_timeouts();
3562957Sjm22469 
3571991Sheppo 	/*
3581991Sheppo 	 * notify registered clients that MD has
3591991Sheppo 	 * been updated
3601991Sheppo 	 */
3611991Sheppo 	mdeg_notify_clients();
3621991Sheppo 
3631991Sheppo 	resp_msg.req_num = msg->req_num;
3641991Sheppo 	resp_msg.result = MD_UPDATE_SUCCESS;
3651991Sheppo 	if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) {
3661991Sheppo 		cmn_err(CE_NOTE, "md ds_cap_send resp failed (%d)", rv);
3671991Sheppo 	}
3681991Sheppo }
3691991Sheppo 
3701991Sheppo static void
ps_shutdown_data_handler(ds_cb_arg_t arg,void * buf,size_t buflen)3711991Sheppo ps_shutdown_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
3721991Sheppo {
3733759Srsmaeda 	ds_svc_hdl_t		ds_handle = ds_shutdown_handle;
3741991Sheppo 	platsvc_shutdown_req_t	*msg = buf;
3751991Sheppo 	platsvc_shutdown_resp_t	resp_msg;
3761991Sheppo 	uint_t			rv;
3771991Sheppo 	hrtime_t		start;
3781991Sheppo 
3791991Sheppo 	if (arg == NULL)
3801991Sheppo 		return;
3811991Sheppo 
3823759Srsmaeda 	if (ds_handle == DS_INVALID_HDL) {
3833759Srsmaeda 		DBG("ps_shutdown_data_handler: DS handle no longer valid\n");
3843759Srsmaeda 		return;
3853759Srsmaeda 	}
3861991Sheppo 
3871991Sheppo 	if (msg == NULL || buflen != sizeof (platsvc_shutdown_req_t)) {
3881991Sheppo 		resp_msg.req_num = 0;
3891991Sheppo 		resp_msg.result = DOMAIN_SHUTDOWN_INVALID_MSG;
3901991Sheppo 		resp_msg.reason[0] = '\0';
3911991Sheppo 		if ((rv = ds_cap_send(ds_handle, &resp_msg,
3921991Sheppo 		    sizeof (resp_msg))) != 0) {
3931991Sheppo 			cmn_err(CE_NOTE, "shutdown ds_cap_send failed (%d)",
3941991Sheppo 			    rv);
3951991Sheppo 		}
3961991Sheppo 		return;
3971991Sheppo 	}
3981991Sheppo 
3991991Sheppo 	resp_msg.req_num = msg->req_num;
4001991Sheppo 	resp_msg.result = DOMAIN_SHUTDOWN_SUCCESS;
4011991Sheppo 	resp_msg.reason[0] = '\0';
4021991Sheppo 
4031991Sheppo 	if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) {
4041991Sheppo 		cmn_err(CE_NOTE, "shutdown ds_cap_send resp failed (%d)", rv);
4051991Sheppo 	}
4061991Sheppo 
4071991Sheppo 	/*
4081991Sheppo 	 * Honor the ldoms manager's shutdown delay requirement.
4091991Sheppo 	 */
4101991Sheppo 	cmn_err(CE_NOTE, "shutdown requested by ldom manager, "
4111991Sheppo 	    "system shutdown in %d minutes", MS2MIN(msg->delay));
4121991Sheppo 
4131991Sheppo 	start = gethrtime();
4141991Sheppo 	while (gethrtime() - start < MS2NANO(msg->delay))
4151991Sheppo 		;
4161991Sheppo 
4171991Sheppo 	(void) kadmin(A_SHUTDOWN, AD_POWEROFF, NULL, kcred);
4181991Sheppo }
4191991Sheppo 
4201991Sheppo 
4211991Sheppo static void
ps_panic_data_handler(ds_cb_arg_t arg,void * buf,size_t buflen)4221991Sheppo ps_panic_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
4231991Sheppo {
4243759Srsmaeda 	ds_svc_hdl_t		ds_handle = ds_panic_handle;
4251991Sheppo 	platsvc_panic_req_t	*msg = buf;
4261991Sheppo 	platsvc_panic_resp_t	resp_msg;
4271991Sheppo 	uint_t			rv;
4281991Sheppo 
4291991Sheppo 	if (arg == NULL)
4301991Sheppo 		return;
4311991Sheppo 
4323759Srsmaeda 	if (ds_handle == DS_INVALID_HDL) {
4333759Srsmaeda 		DBG("ps_panic_data_handler: DS handle no longer valid\n");
4343759Srsmaeda 		return;
4353759Srsmaeda 	}
4361991Sheppo 
4371991Sheppo 	if (msg == NULL || buflen != sizeof (platsvc_panic_req_t)) {
4381991Sheppo 		resp_msg.req_num = 0;
4391991Sheppo 		resp_msg.result = DOMAIN_PANIC_INVALID_MSG;
4401991Sheppo 		resp_msg.reason[0] = '\0';
4411991Sheppo 		if ((rv = ds_cap_send(ds_handle, &resp_msg,
4421991Sheppo 		    sizeof (resp_msg))) != 0) {
4431991Sheppo 			cmn_err(CE_NOTE, "panic ds_cap_send resp failed (%d)",
4441991Sheppo 			    rv);
4451991Sheppo 		}
4461991Sheppo 		return;
4471991Sheppo 	}
4481991Sheppo 
4491991Sheppo 	resp_msg.req_num = msg->req_num;
4501991Sheppo 	resp_msg.result = DOMAIN_PANIC_SUCCESS;
4511991Sheppo 	resp_msg.reason[0] = '\0';
4521991Sheppo 	if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) {
4531991Sheppo 		cmn_err(CE_NOTE, "panic ds_cap_send resp failed (%d)", rv);
4541991Sheppo 	}
4551991Sheppo 
4561991Sheppo 	cmn_err(CE_PANIC, "Panic forced by ldom manager");
4571991Sheppo 	_NOTE(NOTREACHED)
4581991Sheppo }
4591991Sheppo 
46011172SHaik.Aftandilian@Sun.COM /*
46111172SHaik.Aftandilian@Sun.COM  * Send a suspend response message. If a timeout is specified, wait
46211172SHaik.Aftandilian@Sun.COM  * intval seconds between attempts to send the message. The timeout
46311172SHaik.Aftandilian@Sun.COM  * and intval arguments are in seconds.
46411172SHaik.Aftandilian@Sun.COM  */
46511172SHaik.Aftandilian@Sun.COM 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)46611172SHaik.Aftandilian@Sun.COM ps_suspend_send_response(ds_svc_hdl_t *ds_handle, uint64_t req_num,
46711172SHaik.Aftandilian@Sun.COM     uint32_t result, uint32_t rec_result, char *reason, int timeout,
46811172SHaik.Aftandilian@Sun.COM     int intval)
46911172SHaik.Aftandilian@Sun.COM {
47011172SHaik.Aftandilian@Sun.COM 	platsvc_suspend_resp_t	*resp;
47111172SHaik.Aftandilian@Sun.COM 	size_t			reason_length;
47211172SHaik.Aftandilian@Sun.COM 	int			tries = 0;
47311172SHaik.Aftandilian@Sun.COM 	int			rv = -1;
47411172SHaik.Aftandilian@Sun.COM 	time_t			deadline;
47511172SHaik.Aftandilian@Sun.COM 
47611172SHaik.Aftandilian@Sun.COM 	if (reason == NULL) {
47711172SHaik.Aftandilian@Sun.COM 		reason_length = 0;
47811172SHaik.Aftandilian@Sun.COM 	} else {
47911172SHaik.Aftandilian@Sun.COM 		/* Get number of non-NULL bytes */
48011172SHaik.Aftandilian@Sun.COM 		reason_length = strnlen(reason, SUSPEND_MAX_REASON_SIZE - 1);
48111172SHaik.Aftandilian@Sun.COM 		ASSERT(reason[reason_length] == '\0');
48211172SHaik.Aftandilian@Sun.COM 		/* Account for NULL terminator */
48311172SHaik.Aftandilian@Sun.COM 		reason_length++;
48411172SHaik.Aftandilian@Sun.COM 	}
48511172SHaik.Aftandilian@Sun.COM 
48611172SHaik.Aftandilian@Sun.COM 	resp = (platsvc_suspend_resp_t *)
48711172SHaik.Aftandilian@Sun.COM 	    kmem_zalloc(sizeof (platsvc_suspend_resp_t) + reason_length,
48811172SHaik.Aftandilian@Sun.COM 	    KM_SLEEP);
48911172SHaik.Aftandilian@Sun.COM 
49011172SHaik.Aftandilian@Sun.COM 	resp->req_num = req_num;
49111172SHaik.Aftandilian@Sun.COM 	resp->result = result;
49211172SHaik.Aftandilian@Sun.COM 	resp->rec_result = rec_result;
49311172SHaik.Aftandilian@Sun.COM 	if (reason_length > 0) {
49411172SHaik.Aftandilian@Sun.COM 		bcopy(reason, &resp->reason, reason_length - 1);
49511172SHaik.Aftandilian@Sun.COM 		/* Ensure NULL terminator is present */
49611172SHaik.Aftandilian@Sun.COM 		resp->reason[reason_length] = '\0';
49711172SHaik.Aftandilian@Sun.COM 	}
49811172SHaik.Aftandilian@Sun.COM 
49911172SHaik.Aftandilian@Sun.COM 	if (timeout == 0) {
50011172SHaik.Aftandilian@Sun.COM 		tries++;
50111172SHaik.Aftandilian@Sun.COM 		rv = ds_cap_send(*ds_handle, resp,
50211172SHaik.Aftandilian@Sun.COM 		    sizeof (platsvc_suspend_resp_t) + reason_length);
50311172SHaik.Aftandilian@Sun.COM 	} else {
50411172SHaik.Aftandilian@Sun.COM 		deadline = gethrestime_sec() + timeout;
50511172SHaik.Aftandilian@Sun.COM 		do {
50611172SHaik.Aftandilian@Sun.COM 			ds_svc_hdl_t hdl;
50711172SHaik.Aftandilian@Sun.COM 			/*
50811172SHaik.Aftandilian@Sun.COM 			 * Copy the handle so we can ensure we never pass
50911172SHaik.Aftandilian@Sun.COM 			 * an invalid handle to ds_cap_send. We don't want
51011172SHaik.Aftandilian@Sun.COM 			 * to trigger warning messages just because the
51111172SHaik.Aftandilian@Sun.COM 			 * service was temporarily unregistered.
51211172SHaik.Aftandilian@Sun.COM 			 */
51311172SHaik.Aftandilian@Sun.COM 			if ((hdl = *ds_handle) == DS_INVALID_HDL) {
51411172SHaik.Aftandilian@Sun.COM 				delay(SEC2HZ(intval));
51511172SHaik.Aftandilian@Sun.COM 			} else if ((rv = ds_cap_send(hdl, resp,
51611172SHaik.Aftandilian@Sun.COM 			    sizeof (platsvc_suspend_resp_t) +
51711172SHaik.Aftandilian@Sun.COM 			    reason_length)) != 0) {
51811172SHaik.Aftandilian@Sun.COM 				tries++;
51911172SHaik.Aftandilian@Sun.COM 				delay(SEC2HZ(intval));
52011172SHaik.Aftandilian@Sun.COM 			}
52111172SHaik.Aftandilian@Sun.COM 		} while ((rv != 0) && (gethrestime_sec() < deadline));
52211172SHaik.Aftandilian@Sun.COM 	}
52311172SHaik.Aftandilian@Sun.COM 
52411172SHaik.Aftandilian@Sun.COM 	if (rv != 0) {
52511172SHaik.Aftandilian@Sun.COM 		cmn_err(CE_NOTE, "suspend ds_cap_send resp failed (%d) "
52611172SHaik.Aftandilian@Sun.COM 		    "sending message: %d, attempts: %d", rv, resp->result,
52711172SHaik.Aftandilian@Sun.COM 		    tries);
52811172SHaik.Aftandilian@Sun.COM 	}
52911172SHaik.Aftandilian@Sun.COM 
53011172SHaik.Aftandilian@Sun.COM 	kmem_free(resp, sizeof (platsvc_suspend_resp_t) + reason_length);
53111172SHaik.Aftandilian@Sun.COM }
53211172SHaik.Aftandilian@Sun.COM 
53311172SHaik.Aftandilian@Sun.COM /*
53411172SHaik.Aftandilian@Sun.COM  * Handle data coming in for the suspend service. The suspend is
53511172SHaik.Aftandilian@Sun.COM  * sequenced by the ps_suspend_thread, but perform some checks here
53611172SHaik.Aftandilian@Sun.COM  * to make sure that the request is a valid request message and that
53711172SHaik.Aftandilian@Sun.COM  * a suspend operation is not already in progress.
53811172SHaik.Aftandilian@Sun.COM  */
53911172SHaik.Aftandilian@Sun.COM /*ARGSUSED*/
54011172SHaik.Aftandilian@Sun.COM static void
ps_suspend_data_handler(ds_cb_arg_t arg,void * buf,size_t buflen)54111172SHaik.Aftandilian@Sun.COM ps_suspend_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
54211172SHaik.Aftandilian@Sun.COM {
54311172SHaik.Aftandilian@Sun.COM 	platsvc_suspend_req_t	*msg = buf;
54411172SHaik.Aftandilian@Sun.COM 
54511172SHaik.Aftandilian@Sun.COM 	if (arg == NULL)
54611172SHaik.Aftandilian@Sun.COM 		return;
54711172SHaik.Aftandilian@Sun.COM 
54811172SHaik.Aftandilian@Sun.COM 	if (ds_suspend_handle == DS_INVALID_HDL) {
54911172SHaik.Aftandilian@Sun.COM 		DBG("ps_suspend_data_handler: DS handle no longer valid\n");
55011172SHaik.Aftandilian@Sun.COM 		return;
55111172SHaik.Aftandilian@Sun.COM 	}
55211172SHaik.Aftandilian@Sun.COM 
55311172SHaik.Aftandilian@Sun.COM 	/* Handle invalid requests */
55411172SHaik.Aftandilian@Sun.COM 	if (msg == NULL || buflen != sizeof (platsvc_suspend_req_t) ||
55511172SHaik.Aftandilian@Sun.COM 	    msg->type != DOMAIN_SUSPEND_SUSPEND) {
55611172SHaik.Aftandilian@Sun.COM 		ps_suspend_send_response(&ds_suspend_handle, msg->req_num,
55711172SHaik.Aftandilian@Sun.COM 		    DOMAIN_SUSPEND_INVALID_MSG, DOMAIN_SUSPEND_REC_SUCCESS,
55811172SHaik.Aftandilian@Sun.COM 		    NULL, 0, 0);
55911172SHaik.Aftandilian@Sun.COM 		return;
56011172SHaik.Aftandilian@Sun.COM 	}
56111172SHaik.Aftandilian@Sun.COM 
56211172SHaik.Aftandilian@Sun.COM 	/*
56311172SHaik.Aftandilian@Sun.COM 	 * If ps_suspend_thread_exit is set, ds_cap_fini has been
56411172SHaik.Aftandilian@Sun.COM 	 * called and we shouldn't be receving data. Handle this unexpected
56511172SHaik.Aftandilian@Sun.COM 	 * case by returning without sending a response.
56611172SHaik.Aftandilian@Sun.COM 	 */
56711172SHaik.Aftandilian@Sun.COM 	if (ps_suspend_thread_exit) {
56811172SHaik.Aftandilian@Sun.COM 		DBG("ps_suspend_data_handler: ps_suspend_thread is exiting\n");
56911172SHaik.Aftandilian@Sun.COM 		return;
57011172SHaik.Aftandilian@Sun.COM 	}
57111172SHaik.Aftandilian@Sun.COM 
57211172SHaik.Aftandilian@Sun.COM 	mutex_enter(&ps_suspend_mutex);
57311172SHaik.Aftandilian@Sun.COM 
57411172SHaik.Aftandilian@Sun.COM 	/* If a suspend operation is in progress, abort now */
57511172SHaik.Aftandilian@Sun.COM 	if (ps_suspend_data != NULL) {
57611172SHaik.Aftandilian@Sun.COM 		mutex_exit(&ps_suspend_mutex);
57711172SHaik.Aftandilian@Sun.COM 		ps_suspend_send_response(&ds_suspend_handle, msg->req_num,
57811172SHaik.Aftandilian@Sun.COM 		    DOMAIN_SUSPEND_INPROGRESS, DOMAIN_SUSPEND_REC_SUCCESS,
57911172SHaik.Aftandilian@Sun.COM 		    NULL, 0, 0);
58011172SHaik.Aftandilian@Sun.COM 		return;
58111172SHaik.Aftandilian@Sun.COM 	}
58211172SHaik.Aftandilian@Sun.COM 
58311172SHaik.Aftandilian@Sun.COM 	ps_suspend_data = kmem_alloc(sizeof (ps_suspend_data_t), KM_SLEEP);
58411172SHaik.Aftandilian@Sun.COM 	ps_suspend_data->buf = kmem_alloc(buflen, KM_SLEEP);
58511172SHaik.Aftandilian@Sun.COM 	ps_suspend_data->buflen = buflen;
58611172SHaik.Aftandilian@Sun.COM 	bcopy(buf, ps_suspend_data->buf, buflen);
58711172SHaik.Aftandilian@Sun.COM 
58811172SHaik.Aftandilian@Sun.COM 	cv_signal(&ps_suspend_cv);
58911172SHaik.Aftandilian@Sun.COM 	mutex_exit(&ps_suspend_mutex);
59011172SHaik.Aftandilian@Sun.COM }
59111172SHaik.Aftandilian@Sun.COM 
59211172SHaik.Aftandilian@Sun.COM /*
59311172SHaik.Aftandilian@Sun.COM  * Schedule the suspend operation by calling the pre-suspend, suspend,
59411172SHaik.Aftandilian@Sun.COM  * and post-suspend functions. When sending back response messages, we
59511172SHaik.Aftandilian@Sun.COM  * only use a timeout for the post-suspend response because after
59611172SHaik.Aftandilian@Sun.COM  * a resume, domain services will be re-registered and we may not
59711172SHaik.Aftandilian@Sun.COM  * be able to send the response immediately.
59811172SHaik.Aftandilian@Sun.COM  */
59911172SHaik.Aftandilian@Sun.COM static void
ps_suspend_sequence(ps_suspend_data_t * data)60011172SHaik.Aftandilian@Sun.COM ps_suspend_sequence(ps_suspend_data_t *data)
60111172SHaik.Aftandilian@Sun.COM {
60211172SHaik.Aftandilian@Sun.COM 	platsvc_suspend_req_t	*msg;
60311172SHaik.Aftandilian@Sun.COM 	uint32_t		rec_result;
60411172SHaik.Aftandilian@Sun.COM 	char			*error_reason;
60511172SHaik.Aftandilian@Sun.COM 	boolean_t		recovered = B_TRUE;
606*12260SHaik.Aftandilian@Sun.COM 	uint_t			rv = 0;
607*12260SHaik.Aftandilian@Sun.COM 	int			dr_block;
60811172SHaik.Aftandilian@Sun.COM 
60911172SHaik.Aftandilian@Sun.COM 	ASSERT(data != NULL);
61011172SHaik.Aftandilian@Sun.COM 
61111172SHaik.Aftandilian@Sun.COM 	msg = data->buf;
61211172SHaik.Aftandilian@Sun.COM 	error_reason = (char *)kmem_zalloc(SUSPEND_MAX_REASON_SIZE, KM_SLEEP);
61311172SHaik.Aftandilian@Sun.COM 
614*12260SHaik.Aftandilian@Sun.COM 	/*
615*12260SHaik.Aftandilian@Sun.COM 	 * Abort the suspend if a DR operation is in progress. Otherwise,
616*12260SHaik.Aftandilian@Sun.COM 	 * continue whilst blocking any new DR operations.
617*12260SHaik.Aftandilian@Sun.COM 	 */
618*12260SHaik.Aftandilian@Sun.COM 	if ((dr_block = drctl_tryblock()) == 0) {
619*12260SHaik.Aftandilian@Sun.COM 		/* Pre-suspend */
620*12260SHaik.Aftandilian@Sun.COM 		rv = suspend_pre(error_reason, SUSPEND_MAX_REASON_SIZE,
621*12260SHaik.Aftandilian@Sun.COM 		    &recovered);
622*12260SHaik.Aftandilian@Sun.COM 	} else {
623*12260SHaik.Aftandilian@Sun.COM 		/* A DR operation is in progress */
624*12260SHaik.Aftandilian@Sun.COM 		(void) strncpy(error_reason, DOMAIN_SUSPEND_DR_ERROR_STR,
625*12260SHaik.Aftandilian@Sun.COM 		    SUSPEND_MAX_REASON_SIZE);
626*12260SHaik.Aftandilian@Sun.COM 	}
627*12260SHaik.Aftandilian@Sun.COM 
628*12260SHaik.Aftandilian@Sun.COM 	if (dr_block != 0 || rv != 0) {
62911172SHaik.Aftandilian@Sun.COM 		rec_result = (recovered ? DOMAIN_SUSPEND_REC_SUCCESS :
63011172SHaik.Aftandilian@Sun.COM 		    DOMAIN_SUSPEND_REC_FAILURE);
63111172SHaik.Aftandilian@Sun.COM 
63211172SHaik.Aftandilian@Sun.COM 		ps_suspend_send_response(&ds_suspend_handle, msg->req_num,
63311172SHaik.Aftandilian@Sun.COM 		    DOMAIN_SUSPEND_PRE_FAILURE, rec_result, error_reason, 0, 0);
63411172SHaik.Aftandilian@Sun.COM 
635*12260SHaik.Aftandilian@Sun.COM 		if (dr_block == 0)
636*12260SHaik.Aftandilian@Sun.COM 			drctl_unblock();
63711172SHaik.Aftandilian@Sun.COM 		kmem_free(error_reason, SUSPEND_MAX_REASON_SIZE);
63811172SHaik.Aftandilian@Sun.COM 		return;
63911172SHaik.Aftandilian@Sun.COM 	}
64011172SHaik.Aftandilian@Sun.COM 
64111172SHaik.Aftandilian@Sun.COM 	ps_suspend_send_response(&ds_suspend_handle, msg->req_num,
64211172SHaik.Aftandilian@Sun.COM 	    DOMAIN_SUSPEND_PRE_SUCCESS, 0, NULL, 0, 0);
64311172SHaik.Aftandilian@Sun.COM 
64411172SHaik.Aftandilian@Sun.COM 	/* Suspend */
64511172SHaik.Aftandilian@Sun.COM 	rv = suspend_start(error_reason, SUSPEND_MAX_REASON_SIZE);
64611172SHaik.Aftandilian@Sun.COM 	if (rv != 0) {
64711172SHaik.Aftandilian@Sun.COM 		rec_result = (suspend_post(NULL, 0) == 0 ?
64811172SHaik.Aftandilian@Sun.COM 		    DOMAIN_SUSPEND_REC_SUCCESS : DOMAIN_SUSPEND_REC_FAILURE);
64911172SHaik.Aftandilian@Sun.COM 
65011172SHaik.Aftandilian@Sun.COM 		ps_suspend_send_response(&ds_suspend_handle, msg->req_num,
65111172SHaik.Aftandilian@Sun.COM 		    DOMAIN_SUSPEND_SUSPEND_FAILURE, rec_result, error_reason,
65211172SHaik.Aftandilian@Sun.COM 		    0, 0);
65311172SHaik.Aftandilian@Sun.COM 
654*12260SHaik.Aftandilian@Sun.COM 		drctl_unblock();
65511172SHaik.Aftandilian@Sun.COM 		kmem_free(error_reason, SUSPEND_MAX_REASON_SIZE);
65611172SHaik.Aftandilian@Sun.COM 		return;
65711172SHaik.Aftandilian@Sun.COM 	}
65811172SHaik.Aftandilian@Sun.COM 
65911172SHaik.Aftandilian@Sun.COM 	/* Post-suspend */
66011172SHaik.Aftandilian@Sun.COM 	rv = suspend_post(error_reason, SUSPEND_MAX_REASON_SIZE);
66111172SHaik.Aftandilian@Sun.COM 	if (rv != 0) {
66211172SHaik.Aftandilian@Sun.COM 		ps_suspend_send_response(&ds_suspend_handle, msg->req_num,
66311172SHaik.Aftandilian@Sun.COM 		    DOMAIN_SUSPEND_POST_FAILURE, 0, error_reason,
66411172SHaik.Aftandilian@Sun.COM 		    ps_suspend_rereg_delay, ps_suspend_retry_intval);
66511172SHaik.Aftandilian@Sun.COM 	} else {
66611172SHaik.Aftandilian@Sun.COM 		ps_suspend_send_response(&ds_suspend_handle, msg->req_num,
66711172SHaik.Aftandilian@Sun.COM 		    DOMAIN_SUSPEND_POST_SUCCESS, 0, error_reason,
66811172SHaik.Aftandilian@Sun.COM 		    ps_suspend_rereg_delay, ps_suspend_retry_intval);
66911172SHaik.Aftandilian@Sun.COM 	}
67011172SHaik.Aftandilian@Sun.COM 
671*12260SHaik.Aftandilian@Sun.COM 	drctl_unblock();
67211172SHaik.Aftandilian@Sun.COM 	kmem_free(error_reason, SUSPEND_MAX_REASON_SIZE);
67311172SHaik.Aftandilian@Sun.COM }
67411172SHaik.Aftandilian@Sun.COM 
67511172SHaik.Aftandilian@Sun.COM /*
67611172SHaik.Aftandilian@Sun.COM  * Wait for a suspend request or for ps_suspend_thread_exit to be set.
67711172SHaik.Aftandilian@Sun.COM  */
67811172SHaik.Aftandilian@Sun.COM static void
ps_suspend_thread_func(void)67911172SHaik.Aftandilian@Sun.COM ps_suspend_thread_func(void)
68011172SHaik.Aftandilian@Sun.COM {
68111172SHaik.Aftandilian@Sun.COM 	mutex_enter(&ps_suspend_mutex);
68211172SHaik.Aftandilian@Sun.COM 
68311172SHaik.Aftandilian@Sun.COM 	while (ps_suspend_thread_exit == B_FALSE) {
68411172SHaik.Aftandilian@Sun.COM 
68511172SHaik.Aftandilian@Sun.COM 		if (ps_suspend_data == NULL) {
68611172SHaik.Aftandilian@Sun.COM 			cv_wait(&ps_suspend_cv, &ps_suspend_mutex);
68711172SHaik.Aftandilian@Sun.COM 			continue;
68811172SHaik.Aftandilian@Sun.COM 		}
68911172SHaik.Aftandilian@Sun.COM 
69011172SHaik.Aftandilian@Sun.COM 		mutex_exit(&ps_suspend_mutex);
69111172SHaik.Aftandilian@Sun.COM 		ps_suspend_sequence(ps_suspend_data);
69211172SHaik.Aftandilian@Sun.COM 		mutex_enter(&ps_suspend_mutex);
69311172SHaik.Aftandilian@Sun.COM 
69411172SHaik.Aftandilian@Sun.COM 		kmem_free(ps_suspend_data->buf, ps_suspend_data->buflen);
69511172SHaik.Aftandilian@Sun.COM 		kmem_free(ps_suspend_data, sizeof (ps_suspend_data_t));
69611172SHaik.Aftandilian@Sun.COM 		ps_suspend_data = NULL;
69711172SHaik.Aftandilian@Sun.COM 	}
69811172SHaik.Aftandilian@Sun.COM 
69911172SHaik.Aftandilian@Sun.COM 	mutex_exit(&ps_suspend_mutex);
70011172SHaik.Aftandilian@Sun.COM 
70111172SHaik.Aftandilian@Sun.COM 	thread_exit();
70211172SHaik.Aftandilian@Sun.COM }
70311172SHaik.Aftandilian@Sun.COM 
7041991Sheppo static void
ps_reg_handler(ds_cb_arg_t arg,ds_ver_t * ver,ds_svc_hdl_t hdl)7051991Sheppo ps_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
7061991Sheppo {
7071991Sheppo 	DBG("ps_reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n",
7081991Sheppo 	    arg, ver->major, ver->minor, hdl);
7091991Sheppo 
7101991Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_md_handle)
7111991Sheppo 		ds_md_handle = hdl;
7121991Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_shutdown_handle)
7131991Sheppo 		ds_shutdown_handle = hdl;
7141991Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_panic_handle)
7151991Sheppo 		ds_panic_handle = hdl;
71611172SHaik.Aftandilian@Sun.COM 	if ((ds_svc_hdl_t *)arg == &ds_suspend_handle)
71711172SHaik.Aftandilian@Sun.COM 		ds_suspend_handle = hdl;
7181991Sheppo }
7191991Sheppo 
7201991Sheppo static void
ps_unreg_handler(ds_cb_arg_t arg)7211991Sheppo ps_unreg_handler(ds_cb_arg_t arg)
7221991Sheppo {
7231991Sheppo 	DBG("ps_unreg_handler: arg=0x%p\n", arg);
7241991Sheppo 
7251991Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_md_handle)
7261991Sheppo 		ds_md_handle = DS_INVALID_HDL;
7271991Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_shutdown_handle)
7281991Sheppo 		ds_shutdown_handle = DS_INVALID_HDL;
7291991Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_panic_handle)
7301991Sheppo 		ds_panic_handle = DS_INVALID_HDL;
73111172SHaik.Aftandilian@Sun.COM 	if ((ds_svc_hdl_t *)arg == &ds_suspend_handle)
73211172SHaik.Aftandilian@Sun.COM 		ds_suspend_handle = DS_INVALID_HDL;
7331991Sheppo }
734