11ae08745Sheppo /* 21ae08745Sheppo * CDDL HEADER START 31ae08745Sheppo * 41ae08745Sheppo * The contents of this file are subject to the terms of the 51ae08745Sheppo * Common Development and Distribution License (the "License"). 61ae08745Sheppo * You may not use this file except in compliance with the License. 71ae08745Sheppo * 81ae08745Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91ae08745Sheppo * or http://www.opensolaris.org/os/licensing. 101ae08745Sheppo * See the License for the specific language governing permissions 111ae08745Sheppo * and limitations under the License. 121ae08745Sheppo * 131ae08745Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141ae08745Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151ae08745Sheppo * If applicable, add the following below this CDDL HEADER, with the 161ae08745Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171ae08745Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181ae08745Sheppo * 191ae08745Sheppo * CDDL HEADER END 201ae08745Sheppo */ 211ae08745Sheppo 221ae08745Sheppo /* 23*4e476149Srsmaeda * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 241ae08745Sheppo * Use is subject to license terms. 251ae08745Sheppo */ 261ae08745Sheppo 271ae08745Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 281ae08745Sheppo 291ae08745Sheppo /* 301ae08745Sheppo * sun4v Platform Services Module 311ae08745Sheppo */ 321ae08745Sheppo 331ae08745Sheppo #include <sys/modctl.h> 341ae08745Sheppo #include <sys/cmn_err.h> 351ae08745Sheppo #include <sys/machsystm.h> 361ae08745Sheppo #include <sys/note.h> 371ae08745Sheppo #include <sys/uadmin.h> 381ae08745Sheppo #include <sys/ds.h> 391ae08745Sheppo #include <sys/platsvc.h> 401ae08745Sheppo 411ae08745Sheppo /* 421ae08745Sheppo * Debugging routines 431ae08745Sheppo */ 441ae08745Sheppo #ifdef DEBUG 451ae08745Sheppo uint_t ps_debug = 0x0; 461ae08745Sheppo #define DBG if (ps_debug) printf 471ae08745Sheppo #else /* DEBUG */ 481ae08745Sheppo #define DBG _NOTE(CONSTCOND) if (0) printf 491ae08745Sheppo #endif /* DEBUG */ 501ae08745Sheppo 511ae08745Sheppo /* 521ae08745Sheppo * Time resolution conversions. 531ae08745Sheppo */ 541ae08745Sheppo #define MS2NANO(x) ((x) * MICROSEC) 551ae08745Sheppo #define MS2SEC(x) ((x) / MILLISEC) 561ae08745Sheppo #define MS2MIN(x) (MS2SEC(x) / 60) 571ae08745Sheppo 581ae08745Sheppo /* 591ae08745Sheppo * Domains Services interaction 601ae08745Sheppo */ 611ae08745Sheppo static ds_svc_hdl_t ds_md_handle; 621ae08745Sheppo static ds_svc_hdl_t ds_shutdown_handle; 631ae08745Sheppo static ds_svc_hdl_t ds_panic_handle; 641ae08745Sheppo 651ae08745Sheppo static ds_ver_t ps_vers[] = {{ 1, 0 }}; 661ae08745Sheppo #define PS_NVERS (sizeof (ps_vers) / sizeof (ps_vers[0])) 671ae08745Sheppo 681ae08745Sheppo static ds_capability_t ps_md_cap = { 691ae08745Sheppo "md-update", /* svc_id */ 701ae08745Sheppo ps_vers, /* vers */ 711ae08745Sheppo PS_NVERS /* nvers */ 721ae08745Sheppo }; 731ae08745Sheppo 741ae08745Sheppo static ds_capability_t ps_shutdown_cap = { 751ae08745Sheppo "domain-shutdown", /* svc_id */ 761ae08745Sheppo ps_vers, /* vers */ 771ae08745Sheppo PS_NVERS /* nvers */ 781ae08745Sheppo }; 791ae08745Sheppo 801ae08745Sheppo static ds_capability_t ps_panic_cap = { 811ae08745Sheppo "domain-panic", /* svc_id */ 821ae08745Sheppo ps_vers, /* vers */ 831ae08745Sheppo PS_NVERS /* nvers */ 841ae08745Sheppo }; 851ae08745Sheppo 861ae08745Sheppo static void ps_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl); 871ae08745Sheppo static void ps_unreg_handler(ds_cb_arg_t arg); 881ae08745Sheppo 891ae08745Sheppo static void ps_md_data_handler(ds_cb_arg_t arg, void * buf, size_t buflen); 901ae08745Sheppo static void ps_shutdown_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen); 911ae08745Sheppo static void ps_panic_data_handler(ds_cb_arg_t arg, void * buf, size_t buflen); 921ae08745Sheppo 931ae08745Sheppo static ds_clnt_ops_t ps_md_ops = { 941ae08745Sheppo ps_reg_handler, /* ds_reg_cb */ 951ae08745Sheppo ps_unreg_handler, /* ds_unreg_cb */ 961ae08745Sheppo ps_md_data_handler, /* ds_data_cb */ 971ae08745Sheppo &ds_md_handle /* cb_arg */ 981ae08745Sheppo }; 991ae08745Sheppo 1001ae08745Sheppo static ds_clnt_ops_t ps_shutdown_ops = { 1011ae08745Sheppo ps_reg_handler, /* ds_reg_cb */ 1021ae08745Sheppo ps_unreg_handler, /* ds_unreg_cb */ 1031ae08745Sheppo ps_shutdown_data_handler, /* ds_data_cb */ 1041ae08745Sheppo &ds_shutdown_handle /* cb_arg */ 1051ae08745Sheppo }; 1061ae08745Sheppo 1071ae08745Sheppo static ds_clnt_ops_t ps_panic_ops = { 1081ae08745Sheppo ps_reg_handler, /* ds_reg_cb */ 1091ae08745Sheppo ps_unreg_handler, /* ds_unreg_cb */ 1101ae08745Sheppo ps_panic_data_handler, /* ds_data_cb */ 1111ae08745Sheppo &ds_panic_handle /* cb_arg */ 1121ae08745Sheppo }; 1131ae08745Sheppo 1141ae08745Sheppo static int ps_init(void); 1151ae08745Sheppo static void ps_fini(void); 1161ae08745Sheppo 1171ae08745Sheppo /* 1181ae08745Sheppo * Power down timeout value of 5 minutes. 1191ae08745Sheppo */ 1201ae08745Sheppo #define PLATSVC_POWERDOWN_DELAY 1200 1211ae08745Sheppo 1221ae08745Sheppo static struct modlmisc modlmisc = { 1231ae08745Sheppo &mod_miscops, 1241ae08745Sheppo "sun4v Platform Services %I%" 1251ae08745Sheppo }; 1261ae08745Sheppo 1271ae08745Sheppo static struct modlinkage modlinkage = { 1281ae08745Sheppo MODREV_1, 1291ae08745Sheppo (void *)&modlmisc, 1301ae08745Sheppo NULL 1311ae08745Sheppo }; 1321ae08745Sheppo 1331ae08745Sheppo int 1341ae08745Sheppo _init(void) 1351ae08745Sheppo { 1361ae08745Sheppo int rv; 1371ae08745Sheppo 1381ae08745Sheppo if ((rv = ps_init()) != 0) 1391ae08745Sheppo return (rv); 1401ae08745Sheppo 1411ae08745Sheppo if ((rv = mod_install(&modlinkage)) != 0) 1421ae08745Sheppo ps_fini(); 1431ae08745Sheppo 1441ae08745Sheppo return (rv); 1451ae08745Sheppo } 1461ae08745Sheppo 1471ae08745Sheppo int 1481ae08745Sheppo _info(struct modinfo *modinfop) 1491ae08745Sheppo { 1501ae08745Sheppo return (mod_info(&modlinkage, modinfop)); 1511ae08745Sheppo } 1521ae08745Sheppo 1531ae08745Sheppo int platsvc_allow_unload; 1541ae08745Sheppo 1551ae08745Sheppo int 1561ae08745Sheppo _fini(void) 1571ae08745Sheppo { 1581ae08745Sheppo int status; 1591ae08745Sheppo 1601ae08745Sheppo if (platsvc_allow_unload == 0) 1611ae08745Sheppo return (EBUSY); 1621ae08745Sheppo 1631ae08745Sheppo if ((status = mod_remove(&modlinkage)) == 0) 1641ae08745Sheppo ps_fini(); 1651ae08745Sheppo 1661ae08745Sheppo return (status); 1671ae08745Sheppo } 1681ae08745Sheppo 1691ae08745Sheppo static int 1701ae08745Sheppo ps_init(void) 1711ae08745Sheppo { 1721ae08745Sheppo int rv; 1731ae08745Sheppo extern int mdeg_init(void); 1741ae08745Sheppo 1751ae08745Sheppo /* register with domain services framework */ 1761ae08745Sheppo rv = ds_cap_init(&ps_md_cap, &ps_md_ops); 1771ae08745Sheppo if (rv != 0) { 1781ae08745Sheppo cmn_err(CE_WARN, "ds_cap_init md-update failed: %d", rv); 1791ae08745Sheppo return (rv); 1801ae08745Sheppo } 1811ae08745Sheppo 1821ae08745Sheppo rv = ds_cap_init(&ps_shutdown_cap, &ps_shutdown_ops); 1831ae08745Sheppo if (rv != 0) { 1841ae08745Sheppo cmn_err(CE_WARN, "ds_cap_init domain-shutdown failed: %d", rv); 1851ae08745Sheppo (void) ds_cap_fini(&ps_md_cap); 1861ae08745Sheppo return (rv); 1871ae08745Sheppo } 1881ae08745Sheppo 1891ae08745Sheppo rv = ds_cap_init(&ps_panic_cap, &ps_panic_ops); 1901ae08745Sheppo if (rv != 0) { 1911ae08745Sheppo cmn_err(CE_WARN, "ds_cap_init domain-panic failed: %d", rv); 1921ae08745Sheppo (void) ds_cap_fini(&ps_md_cap); 1931ae08745Sheppo (void) ds_cap_fini(&ps_shutdown_cap); 1941ae08745Sheppo return (rv); 1951ae08745Sheppo } 1961ae08745Sheppo 1971ae08745Sheppo rv = mdeg_init(); 1981ae08745Sheppo 1991ae08745Sheppo return (rv); 2001ae08745Sheppo } 2011ae08745Sheppo 2021ae08745Sheppo static void 2031ae08745Sheppo ps_fini(void) 2041ae08745Sheppo { 2051ae08745Sheppo extern void mdeg_fini(void); 2061ae08745Sheppo 2071ae08745Sheppo /* 2081ae08745Sheppo * Stop incoming requests from Zeus 2091ae08745Sheppo */ 2101ae08745Sheppo (void) ds_cap_fini(&ps_md_cap); 2111ae08745Sheppo (void) ds_cap_fini(&ps_shutdown_cap); 2121ae08745Sheppo (void) ds_cap_fini(&ps_panic_cap); 2131ae08745Sheppo 2141ae08745Sheppo mdeg_fini(); 2151ae08745Sheppo } 2161ae08745Sheppo 2171ae08745Sheppo static void 2181ae08745Sheppo ps_md_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen) 2191ae08745Sheppo { 2201ae08745Sheppo extern int mach_descrip_update(void); 2211ae08745Sheppo extern void mdeg_notify_clients(void); 222f273041fSjm22469 extern void recalc_xc_timeouts(void); 2231ae08745Sheppo 224*4e476149Srsmaeda ds_svc_hdl_t ds_handle = ds_md_handle; 2251ae08745Sheppo platsvc_md_update_req_t *msg = buf; 2261ae08745Sheppo platsvc_md_update_resp_t resp_msg; 2271ae08745Sheppo uint_t rv; 2281ae08745Sheppo 2291ae08745Sheppo if (arg == NULL) 2301ae08745Sheppo return; 2311ae08745Sheppo 232*4e476149Srsmaeda if (ds_handle == DS_INVALID_HDL) { 233*4e476149Srsmaeda DBG("ps_md_data_handler: DS handle no longer valid\n"); 234*4e476149Srsmaeda return; 235*4e476149Srsmaeda } 2361ae08745Sheppo 2371ae08745Sheppo if (msg == NULL || buflen != sizeof (platsvc_md_update_req_t)) { 2381ae08745Sheppo resp_msg.req_num = 0; 2391ae08745Sheppo resp_msg.result = MD_UPDATE_INVALID_MSG; 2401ae08745Sheppo if ((rv = ds_cap_send(ds_handle, &resp_msg, 2411ae08745Sheppo sizeof (resp_msg))) != 0) { 2421ae08745Sheppo cmn_err(CE_NOTE, "md ds_cap_send failed (%d)", rv); 2431ae08745Sheppo } 2441ae08745Sheppo return; 2451ae08745Sheppo } 2461ae08745Sheppo 2471ae08745Sheppo DBG("MD Reload...\n"); 2481ae08745Sheppo if (mach_descrip_update()) { 2491ae08745Sheppo cmn_err(CE_WARN, "MD reload failed\n"); 2501ae08745Sheppo return; 2511ae08745Sheppo } 2521ae08745Sheppo 253f273041fSjm22469 recalc_xc_timeouts(); 254f273041fSjm22469 2551ae08745Sheppo /* 2561ae08745Sheppo * notify registered clients that MD has 2571ae08745Sheppo * been updated 2581ae08745Sheppo */ 2591ae08745Sheppo mdeg_notify_clients(); 2601ae08745Sheppo 2611ae08745Sheppo resp_msg.req_num = msg->req_num; 2621ae08745Sheppo resp_msg.result = MD_UPDATE_SUCCESS; 2631ae08745Sheppo if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) { 2641ae08745Sheppo cmn_err(CE_NOTE, "md ds_cap_send resp failed (%d)", rv); 2651ae08745Sheppo } 2661ae08745Sheppo } 2671ae08745Sheppo 2681ae08745Sheppo static void 2691ae08745Sheppo ps_shutdown_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen) 2701ae08745Sheppo { 271*4e476149Srsmaeda ds_svc_hdl_t ds_handle = ds_shutdown_handle; 2721ae08745Sheppo platsvc_shutdown_req_t *msg = buf; 2731ae08745Sheppo platsvc_shutdown_resp_t resp_msg; 2741ae08745Sheppo uint_t rv; 2751ae08745Sheppo hrtime_t start; 2761ae08745Sheppo 2771ae08745Sheppo if (arg == NULL) 2781ae08745Sheppo return; 2791ae08745Sheppo 280*4e476149Srsmaeda if (ds_handle == DS_INVALID_HDL) { 281*4e476149Srsmaeda DBG("ps_shutdown_data_handler: DS handle no longer valid\n"); 282*4e476149Srsmaeda return; 283*4e476149Srsmaeda } 2841ae08745Sheppo 2851ae08745Sheppo if (msg == NULL || buflen != sizeof (platsvc_shutdown_req_t)) { 2861ae08745Sheppo resp_msg.req_num = 0; 2871ae08745Sheppo resp_msg.result = DOMAIN_SHUTDOWN_INVALID_MSG; 2881ae08745Sheppo resp_msg.reason[0] = '\0'; 2891ae08745Sheppo if ((rv = ds_cap_send(ds_handle, &resp_msg, 2901ae08745Sheppo sizeof (resp_msg))) != 0) { 2911ae08745Sheppo cmn_err(CE_NOTE, "shutdown ds_cap_send failed (%d)", 2921ae08745Sheppo rv); 2931ae08745Sheppo } 2941ae08745Sheppo return; 2951ae08745Sheppo } 2961ae08745Sheppo 2971ae08745Sheppo resp_msg.req_num = msg->req_num; 2981ae08745Sheppo resp_msg.result = DOMAIN_SHUTDOWN_SUCCESS; 2991ae08745Sheppo resp_msg.reason[0] = '\0'; 3001ae08745Sheppo 3011ae08745Sheppo if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) { 3021ae08745Sheppo cmn_err(CE_NOTE, "shutdown ds_cap_send resp failed (%d)", rv); 3031ae08745Sheppo } 3041ae08745Sheppo 3051ae08745Sheppo /* 3061ae08745Sheppo * Honor the ldoms manager's shutdown delay requirement. 3071ae08745Sheppo */ 3081ae08745Sheppo cmn_err(CE_NOTE, "shutdown requested by ldom manager, " 3091ae08745Sheppo "system shutdown in %d minutes", MS2MIN(msg->delay)); 3101ae08745Sheppo 3111ae08745Sheppo start = gethrtime(); 3121ae08745Sheppo while (gethrtime() - start < MS2NANO(msg->delay)) 3131ae08745Sheppo ; 3141ae08745Sheppo 3151ae08745Sheppo (void) kadmin(A_SHUTDOWN, AD_POWEROFF, NULL, kcred); 3161ae08745Sheppo } 3171ae08745Sheppo 3181ae08745Sheppo 3191ae08745Sheppo static void 3201ae08745Sheppo ps_panic_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen) 3211ae08745Sheppo { 322*4e476149Srsmaeda ds_svc_hdl_t ds_handle = ds_panic_handle; 3231ae08745Sheppo platsvc_panic_req_t *msg = buf; 3241ae08745Sheppo platsvc_panic_resp_t resp_msg; 3251ae08745Sheppo uint_t rv; 3261ae08745Sheppo 3271ae08745Sheppo if (arg == NULL) 3281ae08745Sheppo return; 3291ae08745Sheppo 330*4e476149Srsmaeda if (ds_handle == DS_INVALID_HDL) { 331*4e476149Srsmaeda DBG("ps_panic_data_handler: DS handle no longer valid\n"); 332*4e476149Srsmaeda return; 333*4e476149Srsmaeda } 3341ae08745Sheppo 3351ae08745Sheppo if (msg == NULL || buflen != sizeof (platsvc_panic_req_t)) { 3361ae08745Sheppo resp_msg.req_num = 0; 3371ae08745Sheppo resp_msg.result = DOMAIN_PANIC_INVALID_MSG; 3381ae08745Sheppo resp_msg.reason[0] = '\0'; 3391ae08745Sheppo if ((rv = ds_cap_send(ds_handle, &resp_msg, 3401ae08745Sheppo sizeof (resp_msg))) != 0) { 3411ae08745Sheppo cmn_err(CE_NOTE, "panic ds_cap_send resp failed (%d)", 3421ae08745Sheppo rv); 3431ae08745Sheppo } 3441ae08745Sheppo return; 3451ae08745Sheppo } 3461ae08745Sheppo 3471ae08745Sheppo resp_msg.req_num = msg->req_num; 3481ae08745Sheppo resp_msg.result = DOMAIN_PANIC_SUCCESS; 3491ae08745Sheppo resp_msg.reason[0] = '\0'; 3501ae08745Sheppo if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) { 3511ae08745Sheppo cmn_err(CE_NOTE, "panic ds_cap_send resp failed (%d)", rv); 3521ae08745Sheppo } 3531ae08745Sheppo 3541ae08745Sheppo cmn_err(CE_PANIC, "Panic forced by ldom manager"); 3551ae08745Sheppo _NOTE(NOTREACHED) 3561ae08745Sheppo } 3571ae08745Sheppo 3581ae08745Sheppo static void 3591ae08745Sheppo ps_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl) 3601ae08745Sheppo { 3611ae08745Sheppo DBG("ps_reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n", 3621ae08745Sheppo arg, ver->major, ver->minor, hdl); 3631ae08745Sheppo 3641ae08745Sheppo if ((ds_svc_hdl_t *)arg == &ds_md_handle) 3651ae08745Sheppo ds_md_handle = hdl; 3661ae08745Sheppo if ((ds_svc_hdl_t *)arg == &ds_shutdown_handle) 3671ae08745Sheppo ds_shutdown_handle = hdl; 3681ae08745Sheppo if ((ds_svc_hdl_t *)arg == &ds_panic_handle) 3691ae08745Sheppo ds_panic_handle = hdl; 3701ae08745Sheppo } 3711ae08745Sheppo 3721ae08745Sheppo static void 3731ae08745Sheppo ps_unreg_handler(ds_cb_arg_t arg) 3741ae08745Sheppo { 3751ae08745Sheppo DBG("ps_unreg_handler: arg=0x%p\n", arg); 3761ae08745Sheppo 3771ae08745Sheppo if ((ds_svc_hdl_t *)arg == &ds_md_handle) 3781ae08745Sheppo ds_md_handle = DS_INVALID_HDL; 3791ae08745Sheppo if ((ds_svc_hdl_t *)arg == &ds_shutdown_handle) 3801ae08745Sheppo ds_shutdown_handle = DS_INVALID_HDL; 3811ae08745Sheppo if ((ds_svc_hdl_t *)arg == &ds_panic_handle) 3821ae08745Sheppo ds_panic_handle = DS_INVALID_HDL; 3831ae08745Sheppo } 384