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