xref: /titanic_51/usr/src/uts/sun4v/io/platsvc.c (revision 1ae0874509b6811fdde1dfd46f0d93fd09867a3f)
1*1ae08745Sheppo /*
2*1ae08745Sheppo  * CDDL HEADER START
3*1ae08745Sheppo  *
4*1ae08745Sheppo  * The contents of this file are subject to the terms of the
5*1ae08745Sheppo  * Common Development and Distribution License (the "License").
6*1ae08745Sheppo  * You may not use this file except in compliance with the License.
7*1ae08745Sheppo  *
8*1ae08745Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1ae08745Sheppo  * or http://www.opensolaris.org/os/licensing.
10*1ae08745Sheppo  * See the License for the specific language governing permissions
11*1ae08745Sheppo  * and limitations under the License.
12*1ae08745Sheppo  *
13*1ae08745Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
14*1ae08745Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1ae08745Sheppo  * If applicable, add the following below this CDDL HEADER, with the
16*1ae08745Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
17*1ae08745Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
18*1ae08745Sheppo  *
19*1ae08745Sheppo  * CDDL HEADER END
20*1ae08745Sheppo  */
21*1ae08745Sheppo 
22*1ae08745Sheppo /*
23*1ae08745Sheppo  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*1ae08745Sheppo  * Use is subject to license terms.
25*1ae08745Sheppo  */
26*1ae08745Sheppo 
27*1ae08745Sheppo #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*1ae08745Sheppo 
29*1ae08745Sheppo /*
30*1ae08745Sheppo  * sun4v Platform Services Module
31*1ae08745Sheppo  */
32*1ae08745Sheppo 
33*1ae08745Sheppo #include <sys/modctl.h>
34*1ae08745Sheppo #include <sys/cmn_err.h>
35*1ae08745Sheppo #include <sys/machsystm.h>
36*1ae08745Sheppo #include <sys/note.h>
37*1ae08745Sheppo #include <sys/uadmin.h>
38*1ae08745Sheppo #include <sys/ds.h>
39*1ae08745Sheppo #include <sys/platsvc.h>
40*1ae08745Sheppo 
41*1ae08745Sheppo /*
42*1ae08745Sheppo  * Debugging routines
43*1ae08745Sheppo  */
44*1ae08745Sheppo #ifdef DEBUG
45*1ae08745Sheppo uint_t ps_debug = 0x0;
46*1ae08745Sheppo #define	DBG	if (ps_debug) printf
47*1ae08745Sheppo #else /* DEBUG */
48*1ae08745Sheppo #define	DBG	_NOTE(CONSTCOND) if (0) printf
49*1ae08745Sheppo #endif /* DEBUG */
50*1ae08745Sheppo 
51*1ae08745Sheppo /*
52*1ae08745Sheppo  * Time resolution conversions.
53*1ae08745Sheppo  */
54*1ae08745Sheppo #define	MS2NANO(x)	((x) * MICROSEC)
55*1ae08745Sheppo #define	MS2SEC(x)	((x) / MILLISEC)
56*1ae08745Sheppo #define	MS2MIN(x)	(MS2SEC(x) / 60)
57*1ae08745Sheppo 
58*1ae08745Sheppo /*
59*1ae08745Sheppo  * Domains Services interaction
60*1ae08745Sheppo  */
61*1ae08745Sheppo static ds_svc_hdl_t	ds_md_handle;
62*1ae08745Sheppo static ds_svc_hdl_t	ds_shutdown_handle;
63*1ae08745Sheppo static ds_svc_hdl_t	ds_panic_handle;
64*1ae08745Sheppo 
65*1ae08745Sheppo static ds_ver_t		ps_vers[] = {{ 1, 0 }};
66*1ae08745Sheppo #define	PS_NVERS	(sizeof (ps_vers) / sizeof (ps_vers[0]))
67*1ae08745Sheppo 
68*1ae08745Sheppo static ds_capability_t ps_md_cap = {
69*1ae08745Sheppo 	"md-update",		/* svc_id */
70*1ae08745Sheppo 	ps_vers,		/* vers */
71*1ae08745Sheppo 	PS_NVERS		/* nvers */
72*1ae08745Sheppo };
73*1ae08745Sheppo 
74*1ae08745Sheppo static ds_capability_t ps_shutdown_cap = {
75*1ae08745Sheppo 	"domain-shutdown",	/* svc_id */
76*1ae08745Sheppo 	ps_vers,		/* vers */
77*1ae08745Sheppo 	PS_NVERS		/* nvers */
78*1ae08745Sheppo };
79*1ae08745Sheppo 
80*1ae08745Sheppo static ds_capability_t ps_panic_cap = {
81*1ae08745Sheppo 	"domain-panic",		/* svc_id */
82*1ae08745Sheppo 	ps_vers,		/* vers */
83*1ae08745Sheppo 	PS_NVERS		/* nvers */
84*1ae08745Sheppo };
85*1ae08745Sheppo 
86*1ae08745Sheppo static void ps_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl);
87*1ae08745Sheppo static void ps_unreg_handler(ds_cb_arg_t arg);
88*1ae08745Sheppo 
89*1ae08745Sheppo static void ps_md_data_handler(ds_cb_arg_t arg, void * buf, size_t buflen);
90*1ae08745Sheppo static void ps_shutdown_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
91*1ae08745Sheppo static void ps_panic_data_handler(ds_cb_arg_t arg, void * buf, size_t buflen);
92*1ae08745Sheppo 
93*1ae08745Sheppo static ds_clnt_ops_t ps_md_ops = {
94*1ae08745Sheppo 	ps_reg_handler,			/* ds_reg_cb */
95*1ae08745Sheppo 	ps_unreg_handler,		/* ds_unreg_cb */
96*1ae08745Sheppo 	ps_md_data_handler,		/* ds_data_cb */
97*1ae08745Sheppo 	&ds_md_handle			/* cb_arg */
98*1ae08745Sheppo };
99*1ae08745Sheppo 
100*1ae08745Sheppo static ds_clnt_ops_t ps_shutdown_ops = {
101*1ae08745Sheppo 	ps_reg_handler,			/* ds_reg_cb */
102*1ae08745Sheppo 	ps_unreg_handler,		/* ds_unreg_cb */
103*1ae08745Sheppo 	ps_shutdown_data_handler,	/* ds_data_cb */
104*1ae08745Sheppo 	&ds_shutdown_handle		/* cb_arg */
105*1ae08745Sheppo };
106*1ae08745Sheppo 
107*1ae08745Sheppo static ds_clnt_ops_t ps_panic_ops = {
108*1ae08745Sheppo 	ps_reg_handler,			/* ds_reg_cb */
109*1ae08745Sheppo 	ps_unreg_handler,		/* ds_unreg_cb */
110*1ae08745Sheppo 	ps_panic_data_handler,		/* ds_data_cb */
111*1ae08745Sheppo 	&ds_panic_handle		/* cb_arg */
112*1ae08745Sheppo };
113*1ae08745Sheppo 
114*1ae08745Sheppo static int ps_init(void);
115*1ae08745Sheppo static void ps_fini(void);
116*1ae08745Sheppo 
117*1ae08745Sheppo /*
118*1ae08745Sheppo  * Powerdown timeout value of 5 minutes.
119*1ae08745Sheppo  */
120*1ae08745Sheppo #define	PLATSVC_POWERDOWN_DELAY		1200
121*1ae08745Sheppo 
122*1ae08745Sheppo static struct modlmisc modlmisc = {
123*1ae08745Sheppo 	&mod_miscops,
124*1ae08745Sheppo 	"sun4v Platform Services %I%"
125*1ae08745Sheppo };
126*1ae08745Sheppo 
127*1ae08745Sheppo static struct modlinkage modlinkage = {
128*1ae08745Sheppo 	MODREV_1,
129*1ae08745Sheppo 	(void *)&modlmisc,
130*1ae08745Sheppo 	NULL
131*1ae08745Sheppo };
132*1ae08745Sheppo 
133*1ae08745Sheppo int
134*1ae08745Sheppo _init(void)
135*1ae08745Sheppo {
136*1ae08745Sheppo 	int	rv;
137*1ae08745Sheppo 
138*1ae08745Sheppo 	if ((rv = ps_init()) != 0)
139*1ae08745Sheppo 		return (rv);
140*1ae08745Sheppo 
141*1ae08745Sheppo 	if ((rv = mod_install(&modlinkage)) != 0)
142*1ae08745Sheppo 		ps_fini();
143*1ae08745Sheppo 
144*1ae08745Sheppo 	return (rv);
145*1ae08745Sheppo }
146*1ae08745Sheppo 
147*1ae08745Sheppo int
148*1ae08745Sheppo _info(struct modinfo *modinfop)
149*1ae08745Sheppo {
150*1ae08745Sheppo 	return (mod_info(&modlinkage, modinfop));
151*1ae08745Sheppo }
152*1ae08745Sheppo 
153*1ae08745Sheppo int platsvc_allow_unload;
154*1ae08745Sheppo 
155*1ae08745Sheppo int
156*1ae08745Sheppo _fini(void)
157*1ae08745Sheppo {
158*1ae08745Sheppo 	int	status;
159*1ae08745Sheppo 
160*1ae08745Sheppo 	if (platsvc_allow_unload == 0)
161*1ae08745Sheppo 		return (EBUSY);
162*1ae08745Sheppo 
163*1ae08745Sheppo 	if ((status = mod_remove(&modlinkage)) == 0)
164*1ae08745Sheppo 		ps_fini();
165*1ae08745Sheppo 
166*1ae08745Sheppo 	return (status);
167*1ae08745Sheppo }
168*1ae08745Sheppo 
169*1ae08745Sheppo static int
170*1ae08745Sheppo ps_init(void)
171*1ae08745Sheppo {
172*1ae08745Sheppo 	int	rv;
173*1ae08745Sheppo 	extern int mdeg_init(void);
174*1ae08745Sheppo 
175*1ae08745Sheppo 	/* register with domain services framework */
176*1ae08745Sheppo 	rv = ds_cap_init(&ps_md_cap, &ps_md_ops);
177*1ae08745Sheppo 	if (rv != 0) {
178*1ae08745Sheppo 		cmn_err(CE_WARN, "ds_cap_init md-update failed: %d", rv);
179*1ae08745Sheppo 		return (rv);
180*1ae08745Sheppo 	}
181*1ae08745Sheppo 
182*1ae08745Sheppo 	rv = ds_cap_init(&ps_shutdown_cap, &ps_shutdown_ops);
183*1ae08745Sheppo 	if (rv != 0) {
184*1ae08745Sheppo 		cmn_err(CE_WARN, "ds_cap_init domain-shutdown failed: %d", rv);
185*1ae08745Sheppo 		(void) ds_cap_fini(&ps_md_cap);
186*1ae08745Sheppo 		return (rv);
187*1ae08745Sheppo 	}
188*1ae08745Sheppo 
189*1ae08745Sheppo 	rv = ds_cap_init(&ps_panic_cap, &ps_panic_ops);
190*1ae08745Sheppo 	if (rv != 0) {
191*1ae08745Sheppo 		cmn_err(CE_WARN, "ds_cap_init domain-panic failed: %d", rv);
192*1ae08745Sheppo 		(void) ds_cap_fini(&ps_md_cap);
193*1ae08745Sheppo 		(void) ds_cap_fini(&ps_shutdown_cap);
194*1ae08745Sheppo 		return (rv);
195*1ae08745Sheppo 	}
196*1ae08745Sheppo 
197*1ae08745Sheppo 	rv = mdeg_init();
198*1ae08745Sheppo 
199*1ae08745Sheppo 	return (rv);
200*1ae08745Sheppo }
201*1ae08745Sheppo 
202*1ae08745Sheppo static void
203*1ae08745Sheppo ps_fini(void)
204*1ae08745Sheppo {
205*1ae08745Sheppo 	extern void mdeg_fini(void);
206*1ae08745Sheppo 
207*1ae08745Sheppo 	/*
208*1ae08745Sheppo 	 * Stop incoming requests from Zeus
209*1ae08745Sheppo 	 */
210*1ae08745Sheppo 	(void) ds_cap_fini(&ps_md_cap);
211*1ae08745Sheppo 	(void) ds_cap_fini(&ps_shutdown_cap);
212*1ae08745Sheppo 	(void) ds_cap_fini(&ps_panic_cap);
213*1ae08745Sheppo 
214*1ae08745Sheppo 	mdeg_fini();
215*1ae08745Sheppo }
216*1ae08745Sheppo 
217*1ae08745Sheppo static void
218*1ae08745Sheppo ps_md_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
219*1ae08745Sheppo {
220*1ae08745Sheppo 	extern int mach_descrip_update(void);
221*1ae08745Sheppo 	extern void mdeg_notify_clients(void);
222*1ae08745Sheppo 
223*1ae08745Sheppo 	ds_svc_hdl_t		 ds_handle;
224*1ae08745Sheppo 	platsvc_md_update_req_t	 *msg = buf;
225*1ae08745Sheppo 	platsvc_md_update_resp_t resp_msg;
226*1ae08745Sheppo 	uint_t			 rv;
227*1ae08745Sheppo 
228*1ae08745Sheppo 	if (arg == NULL)
229*1ae08745Sheppo 		return;
230*1ae08745Sheppo 
231*1ae08745Sheppo 	ds_handle = ds_md_handle;
232*1ae08745Sheppo 
233*1ae08745Sheppo 	if (msg == NULL || buflen != sizeof (platsvc_md_update_req_t)) {
234*1ae08745Sheppo 		resp_msg.req_num = 0;
235*1ae08745Sheppo 		resp_msg.result = MD_UPDATE_INVALID_MSG;
236*1ae08745Sheppo 		if ((rv = ds_cap_send(ds_handle, &resp_msg,
237*1ae08745Sheppo 		    sizeof (resp_msg))) != 0) {
238*1ae08745Sheppo 			cmn_err(CE_NOTE, "md ds_cap_send failed (%d)", rv);
239*1ae08745Sheppo 		}
240*1ae08745Sheppo 		return;
241*1ae08745Sheppo 	}
242*1ae08745Sheppo 
243*1ae08745Sheppo 	DBG("MD Reload...\n");
244*1ae08745Sheppo 	if (mach_descrip_update()) {
245*1ae08745Sheppo 		cmn_err(CE_WARN, "MD reload failed\n");
246*1ae08745Sheppo 		return;
247*1ae08745Sheppo 	}
248*1ae08745Sheppo 
249*1ae08745Sheppo 	/*
250*1ae08745Sheppo 	 * notify registered clients that MD has
251*1ae08745Sheppo 	 * been updated
252*1ae08745Sheppo 	 */
253*1ae08745Sheppo 	mdeg_notify_clients();
254*1ae08745Sheppo 
255*1ae08745Sheppo 	resp_msg.req_num = msg->req_num;
256*1ae08745Sheppo 	resp_msg.result = MD_UPDATE_SUCCESS;
257*1ae08745Sheppo 	if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) {
258*1ae08745Sheppo 		cmn_err(CE_NOTE, "md ds_cap_send resp failed (%d)", rv);
259*1ae08745Sheppo 	}
260*1ae08745Sheppo }
261*1ae08745Sheppo 
262*1ae08745Sheppo static void
263*1ae08745Sheppo ps_shutdown_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
264*1ae08745Sheppo {
265*1ae08745Sheppo 	ds_svc_hdl_t		ds_handle;
266*1ae08745Sheppo 	platsvc_shutdown_req_t	*msg = buf;
267*1ae08745Sheppo 	platsvc_shutdown_resp_t	resp_msg;
268*1ae08745Sheppo 	uint_t			rv;
269*1ae08745Sheppo 	hrtime_t		start;
270*1ae08745Sheppo 
271*1ae08745Sheppo 	if (arg == NULL)
272*1ae08745Sheppo 		return;
273*1ae08745Sheppo 
274*1ae08745Sheppo 	ds_handle = ds_shutdown_handle;
275*1ae08745Sheppo 
276*1ae08745Sheppo 	if (msg == NULL || buflen != sizeof (platsvc_shutdown_req_t)) {
277*1ae08745Sheppo 		resp_msg.req_num = 0;
278*1ae08745Sheppo 		resp_msg.result = DOMAIN_SHUTDOWN_INVALID_MSG;
279*1ae08745Sheppo 		resp_msg.reason[0] = '\0';
280*1ae08745Sheppo 		if ((rv = ds_cap_send(ds_handle, &resp_msg,
281*1ae08745Sheppo 		    sizeof (resp_msg))) != 0) {
282*1ae08745Sheppo 			cmn_err(CE_NOTE, "shutdown ds_cap_send failed (%d)",
283*1ae08745Sheppo 			    rv);
284*1ae08745Sheppo 		}
285*1ae08745Sheppo 		return;
286*1ae08745Sheppo 	}
287*1ae08745Sheppo 
288*1ae08745Sheppo 	resp_msg.req_num = msg->req_num;
289*1ae08745Sheppo 	resp_msg.result = DOMAIN_SHUTDOWN_SUCCESS;
290*1ae08745Sheppo 	resp_msg.reason[0] = '\0';
291*1ae08745Sheppo 
292*1ae08745Sheppo 	if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) {
293*1ae08745Sheppo 		cmn_err(CE_NOTE, "shutdown ds_cap_send resp failed (%d)", rv);
294*1ae08745Sheppo 	}
295*1ae08745Sheppo 
296*1ae08745Sheppo 	/*
297*1ae08745Sheppo 	 * Honor the ldoms manager's shutdown delay requirement.
298*1ae08745Sheppo 	 */
299*1ae08745Sheppo 	cmn_err(CE_NOTE, "shutdown requested by ldom manager, "
300*1ae08745Sheppo 	    "system shutdown in %d minutes", MS2MIN(msg->delay));
301*1ae08745Sheppo 
302*1ae08745Sheppo 	start = gethrtime();
303*1ae08745Sheppo 	while (gethrtime() - start < MS2NANO(msg->delay))
304*1ae08745Sheppo 		;
305*1ae08745Sheppo 
306*1ae08745Sheppo 	(void) kadmin(A_SHUTDOWN, AD_POWEROFF, NULL, kcred);
307*1ae08745Sheppo }
308*1ae08745Sheppo 
309*1ae08745Sheppo 
310*1ae08745Sheppo static void
311*1ae08745Sheppo ps_panic_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
312*1ae08745Sheppo {
313*1ae08745Sheppo 	ds_svc_hdl_t		ds_handle;
314*1ae08745Sheppo 	platsvc_panic_req_t	*msg = buf;
315*1ae08745Sheppo 	platsvc_panic_resp_t	resp_msg;
316*1ae08745Sheppo 	uint_t			rv;
317*1ae08745Sheppo 
318*1ae08745Sheppo 	if (arg == NULL)
319*1ae08745Sheppo 		return;
320*1ae08745Sheppo 
321*1ae08745Sheppo 	ds_handle = ds_panic_handle;
322*1ae08745Sheppo 
323*1ae08745Sheppo 	if (msg == NULL || buflen != sizeof (platsvc_panic_req_t)) {
324*1ae08745Sheppo 		resp_msg.req_num = 0;
325*1ae08745Sheppo 		resp_msg.result = DOMAIN_PANIC_INVALID_MSG;
326*1ae08745Sheppo 		resp_msg.reason[0] = '\0';
327*1ae08745Sheppo 		if ((rv = ds_cap_send(ds_handle, &resp_msg,
328*1ae08745Sheppo 		    sizeof (resp_msg))) != 0) {
329*1ae08745Sheppo 			cmn_err(CE_NOTE, "panic ds_cap_send resp failed (%d)",
330*1ae08745Sheppo 			    rv);
331*1ae08745Sheppo 		}
332*1ae08745Sheppo 		return;
333*1ae08745Sheppo 	}
334*1ae08745Sheppo 
335*1ae08745Sheppo 	resp_msg.req_num = msg->req_num;
336*1ae08745Sheppo 	resp_msg.result = DOMAIN_PANIC_SUCCESS;
337*1ae08745Sheppo 	resp_msg.reason[0] = '\0';
338*1ae08745Sheppo 	if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) {
339*1ae08745Sheppo 		cmn_err(CE_NOTE, "panic ds_cap_send resp failed (%d)", rv);
340*1ae08745Sheppo 	}
341*1ae08745Sheppo 
342*1ae08745Sheppo 	cmn_err(CE_PANIC, "Panic forced by ldom manager");
343*1ae08745Sheppo 	_NOTE(NOTREACHED)
344*1ae08745Sheppo }
345*1ae08745Sheppo 
346*1ae08745Sheppo static void
347*1ae08745Sheppo ps_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
348*1ae08745Sheppo {
349*1ae08745Sheppo 	DBG("ps_reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n",
350*1ae08745Sheppo 	    arg, ver->major, ver->minor, hdl);
351*1ae08745Sheppo 
352*1ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_md_handle)
353*1ae08745Sheppo 		ds_md_handle = hdl;
354*1ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_shutdown_handle)
355*1ae08745Sheppo 		ds_shutdown_handle = hdl;
356*1ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_panic_handle)
357*1ae08745Sheppo 		ds_panic_handle = hdl;
358*1ae08745Sheppo }
359*1ae08745Sheppo 
360*1ae08745Sheppo static void
361*1ae08745Sheppo ps_unreg_handler(ds_cb_arg_t arg)
362*1ae08745Sheppo {
363*1ae08745Sheppo 	DBG("ps_unreg_handler: arg=0x%p\n", arg);
364*1ae08745Sheppo 
365*1ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_md_handle)
366*1ae08745Sheppo 		ds_md_handle = DS_INVALID_HDL;
367*1ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_shutdown_handle)
368*1ae08745Sheppo 		ds_shutdown_handle = DS_INVALID_HDL;
369*1ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_panic_handle)
370*1ae08745Sheppo 		ds_panic_handle = DS_INVALID_HDL;
371*1ae08745Sheppo }
372