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