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 2006 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 * Powerdown 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 223 ds_svc_hdl_t ds_handle; 224 platsvc_md_update_req_t *msg = buf; 225 platsvc_md_update_resp_t resp_msg; 226 uint_t rv; 227 228 if (arg == NULL) 229 return; 230 231 ds_handle = ds_md_handle; 232 233 if (msg == NULL || buflen != sizeof (platsvc_md_update_req_t)) { 234 resp_msg.req_num = 0; 235 resp_msg.result = MD_UPDATE_INVALID_MSG; 236 if ((rv = ds_cap_send(ds_handle, &resp_msg, 237 sizeof (resp_msg))) != 0) { 238 cmn_err(CE_NOTE, "md ds_cap_send failed (%d)", rv); 239 } 240 return; 241 } 242 243 DBG("MD Reload...\n"); 244 if (mach_descrip_update()) { 245 cmn_err(CE_WARN, "MD reload failed\n"); 246 return; 247 } 248 249 /* 250 * notify registered clients that MD has 251 * been updated 252 */ 253 mdeg_notify_clients(); 254 255 resp_msg.req_num = msg->req_num; 256 resp_msg.result = MD_UPDATE_SUCCESS; 257 if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) { 258 cmn_err(CE_NOTE, "md ds_cap_send resp failed (%d)", rv); 259 } 260 } 261 262 static void 263 ps_shutdown_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen) 264 { 265 ds_svc_hdl_t ds_handle; 266 platsvc_shutdown_req_t *msg = buf; 267 platsvc_shutdown_resp_t resp_msg; 268 uint_t rv; 269 hrtime_t start; 270 271 if (arg == NULL) 272 return; 273 274 ds_handle = ds_shutdown_handle; 275 276 if (msg == NULL || buflen != sizeof (platsvc_shutdown_req_t)) { 277 resp_msg.req_num = 0; 278 resp_msg.result = DOMAIN_SHUTDOWN_INVALID_MSG; 279 resp_msg.reason[0] = '\0'; 280 if ((rv = ds_cap_send(ds_handle, &resp_msg, 281 sizeof (resp_msg))) != 0) { 282 cmn_err(CE_NOTE, "shutdown ds_cap_send failed (%d)", 283 rv); 284 } 285 return; 286 } 287 288 resp_msg.req_num = msg->req_num; 289 resp_msg.result = DOMAIN_SHUTDOWN_SUCCESS; 290 resp_msg.reason[0] = '\0'; 291 292 if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) { 293 cmn_err(CE_NOTE, "shutdown ds_cap_send resp failed (%d)", rv); 294 } 295 296 /* 297 * Honor the ldoms manager's shutdown delay requirement. 298 */ 299 cmn_err(CE_NOTE, "shutdown requested by ldom manager, " 300 "system shutdown in %d minutes", MS2MIN(msg->delay)); 301 302 start = gethrtime(); 303 while (gethrtime() - start < MS2NANO(msg->delay)) 304 ; 305 306 (void) kadmin(A_SHUTDOWN, AD_POWEROFF, NULL, kcred); 307 } 308 309 310 static void 311 ps_panic_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen) 312 { 313 ds_svc_hdl_t ds_handle; 314 platsvc_panic_req_t *msg = buf; 315 platsvc_panic_resp_t resp_msg; 316 uint_t rv; 317 318 if (arg == NULL) 319 return; 320 321 ds_handle = ds_panic_handle; 322 323 if (msg == NULL || buflen != sizeof (platsvc_panic_req_t)) { 324 resp_msg.req_num = 0; 325 resp_msg.result = DOMAIN_PANIC_INVALID_MSG; 326 resp_msg.reason[0] = '\0'; 327 if ((rv = ds_cap_send(ds_handle, &resp_msg, 328 sizeof (resp_msg))) != 0) { 329 cmn_err(CE_NOTE, "panic ds_cap_send resp failed (%d)", 330 rv); 331 } 332 return; 333 } 334 335 resp_msg.req_num = msg->req_num; 336 resp_msg.result = DOMAIN_PANIC_SUCCESS; 337 resp_msg.reason[0] = '\0'; 338 if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) { 339 cmn_err(CE_NOTE, "panic ds_cap_send resp failed (%d)", rv); 340 } 341 342 cmn_err(CE_PANIC, "Panic forced by ldom manager"); 343 _NOTE(NOTREACHED) 344 } 345 346 static void 347 ps_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl) 348 { 349 DBG("ps_reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n", 350 arg, ver->major, ver->minor, hdl); 351 352 if ((ds_svc_hdl_t *)arg == &ds_md_handle) 353 ds_md_handle = hdl; 354 if ((ds_svc_hdl_t *)arg == &ds_shutdown_handle) 355 ds_shutdown_handle = hdl; 356 if ((ds_svc_hdl_t *)arg == &ds_panic_handle) 357 ds_panic_handle = hdl; 358 } 359 360 static void 361 ps_unreg_handler(ds_cb_arg_t arg) 362 { 363 DBG("ps_unreg_handler: arg=0x%p\n", arg); 364 365 if ((ds_svc_hdl_t *)arg == &ds_md_handle) 366 ds_md_handle = DS_INVALID_HDL; 367 if ((ds_svc_hdl_t *)arg == &ds_shutdown_handle) 368 ds_shutdown_handle = DS_INVALID_HDL; 369 if ((ds_svc_hdl_t *)arg == &ds_panic_handle) 370 ds_panic_handle = DS_INVALID_HDL; 371 } 372