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