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