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*023e71deSHaik Aftandilian * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 241ae08745Sheppo * Use is subject to license terms. 251ae08745Sheppo */ 261ae08745Sheppo 271ae08745Sheppo /* 281ae08745Sheppo * sun4v Platform Services Module 291ae08745Sheppo */ 301ae08745Sheppo 311ae08745Sheppo #include <sys/modctl.h> 321ae08745Sheppo #include <sys/cmn_err.h> 331ae08745Sheppo #include <sys/machsystm.h> 341ae08745Sheppo #include <sys/note.h> 351ae08745Sheppo #include <sys/uadmin.h> 361ae08745Sheppo #include <sys/ds.h> 371ae08745Sheppo #include <sys/platsvc.h> 38*023e71deSHaik Aftandilian #include <sys/ddi.h> 39*023e71deSHaik Aftandilian #include <sys/suspend.h> 40*023e71deSHaik Aftandilian #include <sys/proc.h> 41*023e71deSHaik Aftandilian #include <sys/disp.h> 421ae08745Sheppo 431ae08745Sheppo /* 441ae08745Sheppo * Debugging routines 451ae08745Sheppo */ 461ae08745Sheppo #ifdef DEBUG 471ae08745Sheppo uint_t ps_debug = 0x0; 481ae08745Sheppo #define DBG if (ps_debug) printf 491ae08745Sheppo #else /* DEBUG */ 501ae08745Sheppo #define DBG _NOTE(CONSTCOND) if (0) printf 511ae08745Sheppo #endif /* DEBUG */ 521ae08745Sheppo 531ae08745Sheppo /* 541ae08745Sheppo * Time resolution conversions. 551ae08745Sheppo */ 561ae08745Sheppo #define MS2NANO(x) ((x) * MICROSEC) 571ae08745Sheppo #define MS2SEC(x) ((x) / MILLISEC) 581ae08745Sheppo #define MS2MIN(x) (MS2SEC(x) / 60) 59*023e71deSHaik Aftandilian #define SEC2HZ(x) (drv_usectohz((x) * MICROSEC)) 601ae08745Sheppo 611ae08745Sheppo /* 621ae08745Sheppo * Domains Services interaction 631ae08745Sheppo */ 641ae08745Sheppo static ds_svc_hdl_t ds_md_handle; 651ae08745Sheppo static ds_svc_hdl_t ds_shutdown_handle; 661ae08745Sheppo static ds_svc_hdl_t ds_panic_handle; 67*023e71deSHaik Aftandilian static ds_svc_hdl_t ds_suspend_handle; 681ae08745Sheppo 691ae08745Sheppo static ds_ver_t ps_vers[] = {{ 1, 0 }}; 701ae08745Sheppo #define PS_NVERS (sizeof (ps_vers) / sizeof (ps_vers[0])) 711ae08745Sheppo 721ae08745Sheppo static ds_capability_t ps_md_cap = { 731ae08745Sheppo "md-update", /* svc_id */ 741ae08745Sheppo ps_vers, /* vers */ 751ae08745Sheppo PS_NVERS /* nvers */ 761ae08745Sheppo }; 771ae08745Sheppo 781ae08745Sheppo static ds_capability_t ps_shutdown_cap = { 791ae08745Sheppo "domain-shutdown", /* svc_id */ 801ae08745Sheppo ps_vers, /* vers */ 811ae08745Sheppo PS_NVERS /* nvers */ 821ae08745Sheppo }; 831ae08745Sheppo 841ae08745Sheppo static ds_capability_t ps_panic_cap = { 851ae08745Sheppo "domain-panic", /* svc_id */ 861ae08745Sheppo ps_vers, /* vers */ 871ae08745Sheppo PS_NVERS /* nvers */ 881ae08745Sheppo }; 891ae08745Sheppo 90*023e71deSHaik Aftandilian static ds_capability_t ps_suspend_cap = { 91*023e71deSHaik Aftandilian "domain-suspend", /* svc_id */ 92*023e71deSHaik Aftandilian ps_vers, /* vers */ 93*023e71deSHaik Aftandilian PS_NVERS /* nvers */ 94*023e71deSHaik Aftandilian }; 95*023e71deSHaik Aftandilian 961ae08745Sheppo static void ps_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl); 971ae08745Sheppo static void ps_unreg_handler(ds_cb_arg_t arg); 981ae08745Sheppo 991ae08745Sheppo static void ps_md_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen); 1001ae08745Sheppo static void ps_shutdown_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen); 1011ae08745Sheppo static void ps_panic_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen); 102*023e71deSHaik Aftandilian static void ps_suspend_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen); 1031ae08745Sheppo 1041ae08745Sheppo static ds_clnt_ops_t ps_md_ops = { 1051ae08745Sheppo ps_reg_handler, /* ds_reg_cb */ 1061ae08745Sheppo ps_unreg_handler, /* ds_unreg_cb */ 1071ae08745Sheppo ps_md_data_handler, /* ds_data_cb */ 1081ae08745Sheppo &ds_md_handle /* cb_arg */ 1091ae08745Sheppo }; 1101ae08745Sheppo 1111ae08745Sheppo static ds_clnt_ops_t ps_shutdown_ops = { 1121ae08745Sheppo ps_reg_handler, /* ds_reg_cb */ 1131ae08745Sheppo ps_unreg_handler, /* ds_unreg_cb */ 1141ae08745Sheppo ps_shutdown_data_handler, /* ds_data_cb */ 1151ae08745Sheppo &ds_shutdown_handle /* cb_arg */ 1161ae08745Sheppo }; 1171ae08745Sheppo 1181ae08745Sheppo static ds_clnt_ops_t ps_panic_ops = { 1191ae08745Sheppo ps_reg_handler, /* ds_reg_cb */ 1201ae08745Sheppo ps_unreg_handler, /* ds_unreg_cb */ 1211ae08745Sheppo ps_panic_data_handler, /* ds_data_cb */ 1221ae08745Sheppo &ds_panic_handle /* cb_arg */ 1231ae08745Sheppo }; 1241ae08745Sheppo 125*023e71deSHaik Aftandilian static ds_clnt_ops_t ps_suspend_ops = { 126*023e71deSHaik Aftandilian ps_reg_handler, /* ds_reg_cb */ 127*023e71deSHaik Aftandilian ps_unreg_handler, /* ds_unreg_cb */ 128*023e71deSHaik Aftandilian ps_suspend_data_handler, /* ds_data_cb */ 129*023e71deSHaik Aftandilian &ds_suspend_handle /* cb_arg */ 130*023e71deSHaik Aftandilian }; 131*023e71deSHaik Aftandilian 1321ae08745Sheppo static int ps_init(void); 1331ae08745Sheppo static void ps_fini(void); 1341ae08745Sheppo 1351ae08745Sheppo /* 1361ae08745Sheppo * Power down timeout value of 5 minutes. 1371ae08745Sheppo */ 1381ae08745Sheppo #define PLATSVC_POWERDOWN_DELAY 1200 1391ae08745Sheppo 140*023e71deSHaik Aftandilian /* 141*023e71deSHaik Aftandilian * Set to true if OS suspend is supported. If OS suspend is not 142*023e71deSHaik Aftandilian * supported, the suspend service will not be started. 143*023e71deSHaik Aftandilian */ 144*023e71deSHaik Aftandilian static boolean_t ps_suspend_enabled = B_FALSE; 145*023e71deSHaik Aftandilian 146*023e71deSHaik Aftandilian /* 147*023e71deSHaik Aftandilian * Suspend service request handling 148*023e71deSHaik Aftandilian */ 149*023e71deSHaik Aftandilian typedef struct ps_suspend_data { 150*023e71deSHaik Aftandilian void *buf; 151*023e71deSHaik Aftandilian size_t buflen; 152*023e71deSHaik Aftandilian } ps_suspend_data_t; 153*023e71deSHaik Aftandilian 154*023e71deSHaik Aftandilian static kmutex_t ps_suspend_mutex; 155*023e71deSHaik Aftandilian static kcondvar_t ps_suspend_cv; 156*023e71deSHaik Aftandilian 157*023e71deSHaik Aftandilian static ps_suspend_data_t *ps_suspend_data = NULL; 158*023e71deSHaik Aftandilian static boolean_t ps_suspend_thread_exit = B_FALSE; 159*023e71deSHaik Aftandilian static kthread_t *ps_suspend_thread = NULL; 160*023e71deSHaik Aftandilian 161*023e71deSHaik Aftandilian static void ps_suspend_sequence(ps_suspend_data_t *data); 162*023e71deSHaik Aftandilian static void ps_suspend_thread_func(void); 163*023e71deSHaik Aftandilian 164*023e71deSHaik Aftandilian /* 165*023e71deSHaik Aftandilian * The DELAY timeout is the time (in seconds) to wait for the 166*023e71deSHaik Aftandilian * suspend service to be re-registered after a suspend/resume 167*023e71deSHaik Aftandilian * operation. The INTVAL time is the time (in seconds) to wait 168*023e71deSHaik Aftandilian * between retry attempts when sending the post-suspend message 169*023e71deSHaik Aftandilian * after a suspend/resume operation. 170*023e71deSHaik Aftandilian */ 171*023e71deSHaik Aftandilian #define PLATSVC_SUSPEND_REREG_DELAY 60 172*023e71deSHaik Aftandilian #define PLATSVC_SUSPEND_RETRY_INTVAL 1 173*023e71deSHaik Aftandilian static int ps_suspend_rereg_delay = PLATSVC_SUSPEND_REREG_DELAY; 174*023e71deSHaik Aftandilian static int ps_suspend_retry_intval = PLATSVC_SUSPEND_RETRY_INTVAL; 175*023e71deSHaik Aftandilian 176*023e71deSHaik Aftandilian 1771ae08745Sheppo static struct modlmisc modlmisc = { 1781ae08745Sheppo &mod_miscops, 179f500b196SRichard Bean "sun4v Platform Services" 1801ae08745Sheppo }; 1811ae08745Sheppo 1821ae08745Sheppo static struct modlinkage modlinkage = { 1831ae08745Sheppo MODREV_1, 1841ae08745Sheppo (void *)&modlmisc, 1851ae08745Sheppo NULL 1861ae08745Sheppo }; 1871ae08745Sheppo 1881ae08745Sheppo int 1891ae08745Sheppo _init(void) 1901ae08745Sheppo { 1911ae08745Sheppo int rv; 1921ae08745Sheppo 1931ae08745Sheppo if ((rv = ps_init()) != 0) 1941ae08745Sheppo return (rv); 1951ae08745Sheppo 1961ae08745Sheppo if ((rv = mod_install(&modlinkage)) != 0) 1971ae08745Sheppo ps_fini(); 1981ae08745Sheppo 1991ae08745Sheppo return (rv); 2001ae08745Sheppo } 2011ae08745Sheppo 2021ae08745Sheppo int 2031ae08745Sheppo _info(struct modinfo *modinfop) 2041ae08745Sheppo { 2051ae08745Sheppo return (mod_info(&modlinkage, modinfop)); 2061ae08745Sheppo } 2071ae08745Sheppo 2081ae08745Sheppo int platsvc_allow_unload; 2091ae08745Sheppo 2101ae08745Sheppo int 2111ae08745Sheppo _fini(void) 2121ae08745Sheppo { 2131ae08745Sheppo int status; 2141ae08745Sheppo 2151ae08745Sheppo if (platsvc_allow_unload == 0) 2161ae08745Sheppo return (EBUSY); 2171ae08745Sheppo 2181ae08745Sheppo if ((status = mod_remove(&modlinkage)) == 0) 2191ae08745Sheppo ps_fini(); 2201ae08745Sheppo 2211ae08745Sheppo return (status); 2221ae08745Sheppo } 2231ae08745Sheppo 2241ae08745Sheppo static int 2251ae08745Sheppo ps_init(void) 2261ae08745Sheppo { 2271ae08745Sheppo int rv; 2281ae08745Sheppo extern int mdeg_init(void); 229*023e71deSHaik Aftandilian extern void mdeg_fini(void); 2301ae08745Sheppo 2311ae08745Sheppo /* register with domain services framework */ 2321ae08745Sheppo rv = ds_cap_init(&ps_md_cap, &ps_md_ops); 2331ae08745Sheppo if (rv != 0) { 2341ae08745Sheppo cmn_err(CE_WARN, "ds_cap_init md-update failed: %d", rv); 2351ae08745Sheppo return (rv); 2361ae08745Sheppo } 2371ae08745Sheppo 238*023e71deSHaik Aftandilian rv = mdeg_init(); 239*023e71deSHaik Aftandilian if (rv != 0) { 240*023e71deSHaik Aftandilian (void) ds_cap_fini(&ps_md_cap); 241*023e71deSHaik Aftandilian return (rv); 242*023e71deSHaik Aftandilian } 243*023e71deSHaik Aftandilian 2441ae08745Sheppo rv = ds_cap_init(&ps_shutdown_cap, &ps_shutdown_ops); 2451ae08745Sheppo if (rv != 0) { 2461ae08745Sheppo cmn_err(CE_WARN, "ds_cap_init domain-shutdown failed: %d", rv); 247*023e71deSHaik Aftandilian mdeg_fini(); 2481ae08745Sheppo (void) ds_cap_fini(&ps_md_cap); 2491ae08745Sheppo return (rv); 2501ae08745Sheppo } 2511ae08745Sheppo 2521ae08745Sheppo rv = ds_cap_init(&ps_panic_cap, &ps_panic_ops); 2531ae08745Sheppo if (rv != 0) { 2541ae08745Sheppo cmn_err(CE_WARN, "ds_cap_init domain-panic failed: %d", rv); 2551ae08745Sheppo (void) ds_cap_fini(&ps_md_cap); 256*023e71deSHaik Aftandilian mdeg_fini(); 2571ae08745Sheppo (void) ds_cap_fini(&ps_shutdown_cap); 2581ae08745Sheppo return (rv); 2591ae08745Sheppo } 2601ae08745Sheppo 261*023e71deSHaik Aftandilian ps_suspend_enabled = suspend_supported(); 2621ae08745Sheppo 263*023e71deSHaik Aftandilian if (ps_suspend_enabled) { 264*023e71deSHaik Aftandilian mutex_init(&ps_suspend_mutex, NULL, MUTEX_DEFAULT, NULL); 265*023e71deSHaik Aftandilian cv_init(&ps_suspend_cv, NULL, CV_DEFAULT, NULL); 266*023e71deSHaik Aftandilian ps_suspend_thread_exit = B_FALSE; 267*023e71deSHaik Aftandilian 268*023e71deSHaik Aftandilian rv = ds_cap_init(&ps_suspend_cap, &ps_suspend_ops); 269*023e71deSHaik Aftandilian if (rv != 0) { 270*023e71deSHaik Aftandilian cmn_err(CE_WARN, "ds_cap_init domain-suspend failed: " 271*023e71deSHaik Aftandilian "%d", rv); 272*023e71deSHaik Aftandilian (void) ds_cap_fini(&ps_md_cap); 273*023e71deSHaik Aftandilian mdeg_fini(); 274*023e71deSHaik Aftandilian (void) ds_cap_fini(&ps_shutdown_cap); 275*023e71deSHaik Aftandilian (void) ds_cap_fini(&ps_panic_cap); 276*023e71deSHaik Aftandilian mutex_destroy(&ps_suspend_mutex); 277*023e71deSHaik Aftandilian cv_destroy(&ps_suspend_cv); 2781ae08745Sheppo return (rv); 2791ae08745Sheppo } 2801ae08745Sheppo 281*023e71deSHaik Aftandilian ps_suspend_thread = thread_create(NULL, 2 * DEFAULTSTKSZ, 282*023e71deSHaik Aftandilian ps_suspend_thread_func, NULL, 0, &p0, TS_RUN, minclsyspri); 283*023e71deSHaik Aftandilian } 284*023e71deSHaik Aftandilian 285*023e71deSHaik Aftandilian return (0); 286*023e71deSHaik Aftandilian } 287*023e71deSHaik Aftandilian 2881ae08745Sheppo static void 2891ae08745Sheppo ps_fini(void) 2901ae08745Sheppo { 2911ae08745Sheppo extern void mdeg_fini(void); 2921ae08745Sheppo 2931ae08745Sheppo /* 2941ae08745Sheppo * Stop incoming requests from Zeus 2951ae08745Sheppo */ 2961ae08745Sheppo (void) ds_cap_fini(&ps_md_cap); 2971ae08745Sheppo (void) ds_cap_fini(&ps_shutdown_cap); 2981ae08745Sheppo (void) ds_cap_fini(&ps_panic_cap); 2991ae08745Sheppo 300*023e71deSHaik Aftandilian if (ps_suspend_enabled) { 301*023e71deSHaik Aftandilian (void) ds_cap_fini(&ps_suspend_cap); 302*023e71deSHaik Aftandilian if (ps_suspend_thread != NULL) { 303*023e71deSHaik Aftandilian mutex_enter(&ps_suspend_mutex); 304*023e71deSHaik Aftandilian ps_suspend_thread_exit = B_TRUE; 305*023e71deSHaik Aftandilian cv_signal(&ps_suspend_cv); 306*023e71deSHaik Aftandilian mutex_exit(&ps_suspend_mutex); 307*023e71deSHaik Aftandilian 308*023e71deSHaik Aftandilian thread_join(ps_suspend_thread->t_did); 309*023e71deSHaik Aftandilian ps_suspend_thread = NULL; 310*023e71deSHaik Aftandilian 311*023e71deSHaik Aftandilian mutex_destroy(&ps_suspend_mutex); 312*023e71deSHaik Aftandilian cv_destroy(&ps_suspend_cv); 313*023e71deSHaik Aftandilian } 314*023e71deSHaik Aftandilian } 315*023e71deSHaik Aftandilian 3161ae08745Sheppo mdeg_fini(); 3171ae08745Sheppo } 3181ae08745Sheppo 3191ae08745Sheppo static void 3201ae08745Sheppo ps_md_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen) 3211ae08745Sheppo { 3221ae08745Sheppo extern int mach_descrip_update(void); 3231ae08745Sheppo extern void mdeg_notify_clients(void); 324f273041fSjm22469 extern void recalc_xc_timeouts(void); 3251ae08745Sheppo 3264e476149Srsmaeda ds_svc_hdl_t ds_handle = ds_md_handle; 3271ae08745Sheppo platsvc_md_update_req_t *msg = buf; 3281ae08745Sheppo platsvc_md_update_resp_t resp_msg; 3291ae08745Sheppo uint_t rv; 3301ae08745Sheppo 3311ae08745Sheppo if (arg == NULL) 3321ae08745Sheppo return; 3331ae08745Sheppo 3344e476149Srsmaeda if (ds_handle == DS_INVALID_HDL) { 3354e476149Srsmaeda DBG("ps_md_data_handler: DS handle no longer valid\n"); 3364e476149Srsmaeda return; 3374e476149Srsmaeda } 3381ae08745Sheppo 3391ae08745Sheppo if (msg == NULL || buflen != sizeof (platsvc_md_update_req_t)) { 3401ae08745Sheppo resp_msg.req_num = 0; 3411ae08745Sheppo resp_msg.result = MD_UPDATE_INVALID_MSG; 3421ae08745Sheppo if ((rv = ds_cap_send(ds_handle, &resp_msg, 3431ae08745Sheppo sizeof (resp_msg))) != 0) { 3441ae08745Sheppo cmn_err(CE_NOTE, "md ds_cap_send failed (%d)", rv); 3451ae08745Sheppo } 3461ae08745Sheppo return; 3471ae08745Sheppo } 3481ae08745Sheppo 3491ae08745Sheppo DBG("MD Reload...\n"); 3501ae08745Sheppo if (mach_descrip_update()) { 3511ae08745Sheppo cmn_err(CE_WARN, "MD reload failed\n"); 3521ae08745Sheppo return; 3531ae08745Sheppo } 3541ae08745Sheppo 355f273041fSjm22469 recalc_xc_timeouts(); 356f273041fSjm22469 3571ae08745Sheppo /* 3581ae08745Sheppo * notify registered clients that MD has 3591ae08745Sheppo * been updated 3601ae08745Sheppo */ 3611ae08745Sheppo mdeg_notify_clients(); 3621ae08745Sheppo 3631ae08745Sheppo resp_msg.req_num = msg->req_num; 3641ae08745Sheppo resp_msg.result = MD_UPDATE_SUCCESS; 3651ae08745Sheppo if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) { 3661ae08745Sheppo cmn_err(CE_NOTE, "md ds_cap_send resp failed (%d)", rv); 3671ae08745Sheppo } 3681ae08745Sheppo } 3691ae08745Sheppo 3701ae08745Sheppo static void 3711ae08745Sheppo ps_shutdown_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen) 3721ae08745Sheppo { 3734e476149Srsmaeda ds_svc_hdl_t ds_handle = ds_shutdown_handle; 3741ae08745Sheppo platsvc_shutdown_req_t *msg = buf; 3751ae08745Sheppo platsvc_shutdown_resp_t resp_msg; 3761ae08745Sheppo uint_t rv; 3771ae08745Sheppo hrtime_t start; 3781ae08745Sheppo 3791ae08745Sheppo if (arg == NULL) 3801ae08745Sheppo return; 3811ae08745Sheppo 3824e476149Srsmaeda if (ds_handle == DS_INVALID_HDL) { 3834e476149Srsmaeda DBG("ps_shutdown_data_handler: DS handle no longer valid\n"); 3844e476149Srsmaeda return; 3854e476149Srsmaeda } 3861ae08745Sheppo 3871ae08745Sheppo if (msg == NULL || buflen != sizeof (platsvc_shutdown_req_t)) { 3881ae08745Sheppo resp_msg.req_num = 0; 3891ae08745Sheppo resp_msg.result = DOMAIN_SHUTDOWN_INVALID_MSG; 3901ae08745Sheppo resp_msg.reason[0] = '\0'; 3911ae08745Sheppo if ((rv = ds_cap_send(ds_handle, &resp_msg, 3921ae08745Sheppo sizeof (resp_msg))) != 0) { 3931ae08745Sheppo cmn_err(CE_NOTE, "shutdown ds_cap_send failed (%d)", 3941ae08745Sheppo rv); 3951ae08745Sheppo } 3961ae08745Sheppo return; 3971ae08745Sheppo } 3981ae08745Sheppo 3991ae08745Sheppo resp_msg.req_num = msg->req_num; 4001ae08745Sheppo resp_msg.result = DOMAIN_SHUTDOWN_SUCCESS; 4011ae08745Sheppo resp_msg.reason[0] = '\0'; 4021ae08745Sheppo 4031ae08745Sheppo if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) { 4041ae08745Sheppo cmn_err(CE_NOTE, "shutdown ds_cap_send resp failed (%d)", rv); 4051ae08745Sheppo } 4061ae08745Sheppo 4071ae08745Sheppo /* 4081ae08745Sheppo * Honor the ldoms manager's shutdown delay requirement. 4091ae08745Sheppo */ 4101ae08745Sheppo cmn_err(CE_NOTE, "shutdown requested by ldom manager, " 4111ae08745Sheppo "system shutdown in %d minutes", MS2MIN(msg->delay)); 4121ae08745Sheppo 4131ae08745Sheppo start = gethrtime(); 4141ae08745Sheppo while (gethrtime() - start < MS2NANO(msg->delay)) 4151ae08745Sheppo ; 4161ae08745Sheppo 4171ae08745Sheppo (void) kadmin(A_SHUTDOWN, AD_POWEROFF, NULL, kcred); 4181ae08745Sheppo } 4191ae08745Sheppo 4201ae08745Sheppo 4211ae08745Sheppo static void 4221ae08745Sheppo ps_panic_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen) 4231ae08745Sheppo { 4244e476149Srsmaeda ds_svc_hdl_t ds_handle = ds_panic_handle; 4251ae08745Sheppo platsvc_panic_req_t *msg = buf; 4261ae08745Sheppo platsvc_panic_resp_t resp_msg; 4271ae08745Sheppo uint_t rv; 4281ae08745Sheppo 4291ae08745Sheppo if (arg == NULL) 4301ae08745Sheppo return; 4311ae08745Sheppo 4324e476149Srsmaeda if (ds_handle == DS_INVALID_HDL) { 4334e476149Srsmaeda DBG("ps_panic_data_handler: DS handle no longer valid\n"); 4344e476149Srsmaeda return; 4354e476149Srsmaeda } 4361ae08745Sheppo 4371ae08745Sheppo if (msg == NULL || buflen != sizeof (platsvc_panic_req_t)) { 4381ae08745Sheppo resp_msg.req_num = 0; 4391ae08745Sheppo resp_msg.result = DOMAIN_PANIC_INVALID_MSG; 4401ae08745Sheppo resp_msg.reason[0] = '\0'; 4411ae08745Sheppo if ((rv = ds_cap_send(ds_handle, &resp_msg, 4421ae08745Sheppo sizeof (resp_msg))) != 0) { 4431ae08745Sheppo cmn_err(CE_NOTE, "panic ds_cap_send resp failed (%d)", 4441ae08745Sheppo rv); 4451ae08745Sheppo } 4461ae08745Sheppo return; 4471ae08745Sheppo } 4481ae08745Sheppo 4491ae08745Sheppo resp_msg.req_num = msg->req_num; 4501ae08745Sheppo resp_msg.result = DOMAIN_PANIC_SUCCESS; 4511ae08745Sheppo resp_msg.reason[0] = '\0'; 4521ae08745Sheppo if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) { 4531ae08745Sheppo cmn_err(CE_NOTE, "panic ds_cap_send resp failed (%d)", rv); 4541ae08745Sheppo } 4551ae08745Sheppo 4561ae08745Sheppo cmn_err(CE_PANIC, "Panic forced by ldom manager"); 4571ae08745Sheppo _NOTE(NOTREACHED) 4581ae08745Sheppo } 4591ae08745Sheppo 460*023e71deSHaik Aftandilian /* 461*023e71deSHaik Aftandilian * Send a suspend response message. If a timeout is specified, wait 462*023e71deSHaik Aftandilian * intval seconds between attempts to send the message. The timeout 463*023e71deSHaik Aftandilian * and intval arguments are in seconds. 464*023e71deSHaik Aftandilian */ 465*023e71deSHaik Aftandilian static void 466*023e71deSHaik Aftandilian ps_suspend_send_response(ds_svc_hdl_t *ds_handle, uint64_t req_num, 467*023e71deSHaik Aftandilian uint32_t result, uint32_t rec_result, char *reason, int timeout, 468*023e71deSHaik Aftandilian int intval) 469*023e71deSHaik Aftandilian { 470*023e71deSHaik Aftandilian platsvc_suspend_resp_t *resp; 471*023e71deSHaik Aftandilian size_t reason_length; 472*023e71deSHaik Aftandilian int tries = 0; 473*023e71deSHaik Aftandilian int rv = -1; 474*023e71deSHaik Aftandilian time_t deadline; 475*023e71deSHaik Aftandilian 476*023e71deSHaik Aftandilian if (reason == NULL) { 477*023e71deSHaik Aftandilian reason_length = 0; 478*023e71deSHaik Aftandilian } else { 479*023e71deSHaik Aftandilian /* Get number of non-NULL bytes */ 480*023e71deSHaik Aftandilian reason_length = strnlen(reason, SUSPEND_MAX_REASON_SIZE - 1); 481*023e71deSHaik Aftandilian ASSERT(reason[reason_length] == '\0'); 482*023e71deSHaik Aftandilian /* Account for NULL terminator */ 483*023e71deSHaik Aftandilian reason_length++; 484*023e71deSHaik Aftandilian } 485*023e71deSHaik Aftandilian 486*023e71deSHaik Aftandilian resp = (platsvc_suspend_resp_t *) 487*023e71deSHaik Aftandilian kmem_zalloc(sizeof (platsvc_suspend_resp_t) + reason_length, 488*023e71deSHaik Aftandilian KM_SLEEP); 489*023e71deSHaik Aftandilian 490*023e71deSHaik Aftandilian resp->req_num = req_num; 491*023e71deSHaik Aftandilian resp->result = result; 492*023e71deSHaik Aftandilian resp->rec_result = rec_result; 493*023e71deSHaik Aftandilian if (reason_length > 0) { 494*023e71deSHaik Aftandilian bcopy(reason, &resp->reason, reason_length - 1); 495*023e71deSHaik Aftandilian /* Ensure NULL terminator is present */ 496*023e71deSHaik Aftandilian resp->reason[reason_length] = '\0'; 497*023e71deSHaik Aftandilian } 498*023e71deSHaik Aftandilian 499*023e71deSHaik Aftandilian if (timeout == 0) { 500*023e71deSHaik Aftandilian tries++; 501*023e71deSHaik Aftandilian rv = ds_cap_send(*ds_handle, resp, 502*023e71deSHaik Aftandilian sizeof (platsvc_suspend_resp_t) + reason_length); 503*023e71deSHaik Aftandilian } else { 504*023e71deSHaik Aftandilian deadline = gethrestime_sec() + timeout; 505*023e71deSHaik Aftandilian do { 506*023e71deSHaik Aftandilian ds_svc_hdl_t hdl; 507*023e71deSHaik Aftandilian /* 508*023e71deSHaik Aftandilian * Copy the handle so we can ensure we never pass 509*023e71deSHaik Aftandilian * an invalid handle to ds_cap_send. We don't want 510*023e71deSHaik Aftandilian * to trigger warning messages just because the 511*023e71deSHaik Aftandilian * service was temporarily unregistered. 512*023e71deSHaik Aftandilian */ 513*023e71deSHaik Aftandilian if ((hdl = *ds_handle) == DS_INVALID_HDL) { 514*023e71deSHaik Aftandilian delay(SEC2HZ(intval)); 515*023e71deSHaik Aftandilian } else if ((rv = ds_cap_send(hdl, resp, 516*023e71deSHaik Aftandilian sizeof (platsvc_suspend_resp_t) + 517*023e71deSHaik Aftandilian reason_length)) != 0) { 518*023e71deSHaik Aftandilian tries++; 519*023e71deSHaik Aftandilian delay(SEC2HZ(intval)); 520*023e71deSHaik Aftandilian } 521*023e71deSHaik Aftandilian } while ((rv != 0) && (gethrestime_sec() < deadline)); 522*023e71deSHaik Aftandilian } 523*023e71deSHaik Aftandilian 524*023e71deSHaik Aftandilian if (rv != 0) { 525*023e71deSHaik Aftandilian cmn_err(CE_NOTE, "suspend ds_cap_send resp failed (%d) " 526*023e71deSHaik Aftandilian "sending message: %d, attempts: %d", rv, resp->result, 527*023e71deSHaik Aftandilian tries); 528*023e71deSHaik Aftandilian } 529*023e71deSHaik Aftandilian 530*023e71deSHaik Aftandilian kmem_free(resp, sizeof (platsvc_suspend_resp_t) + reason_length); 531*023e71deSHaik Aftandilian } 532*023e71deSHaik Aftandilian 533*023e71deSHaik Aftandilian /* 534*023e71deSHaik Aftandilian * Handle data coming in for the suspend service. The suspend is 535*023e71deSHaik Aftandilian * sequenced by the ps_suspend_thread, but perform some checks here 536*023e71deSHaik Aftandilian * to make sure that the request is a valid request message and that 537*023e71deSHaik Aftandilian * a suspend operation is not already in progress. 538*023e71deSHaik Aftandilian */ 539*023e71deSHaik Aftandilian /*ARGSUSED*/ 540*023e71deSHaik Aftandilian static void 541*023e71deSHaik Aftandilian ps_suspend_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen) 542*023e71deSHaik Aftandilian { 543*023e71deSHaik Aftandilian platsvc_suspend_req_t *msg = buf; 544*023e71deSHaik Aftandilian 545*023e71deSHaik Aftandilian if (arg == NULL) 546*023e71deSHaik Aftandilian return; 547*023e71deSHaik Aftandilian 548*023e71deSHaik Aftandilian if (ds_suspend_handle == DS_INVALID_HDL) { 549*023e71deSHaik Aftandilian DBG("ps_suspend_data_handler: DS handle no longer valid\n"); 550*023e71deSHaik Aftandilian return; 551*023e71deSHaik Aftandilian } 552*023e71deSHaik Aftandilian 553*023e71deSHaik Aftandilian /* Handle invalid requests */ 554*023e71deSHaik Aftandilian if (msg == NULL || buflen != sizeof (platsvc_suspend_req_t) || 555*023e71deSHaik Aftandilian msg->type != DOMAIN_SUSPEND_SUSPEND) { 556*023e71deSHaik Aftandilian ps_suspend_send_response(&ds_suspend_handle, msg->req_num, 557*023e71deSHaik Aftandilian DOMAIN_SUSPEND_INVALID_MSG, DOMAIN_SUSPEND_REC_SUCCESS, 558*023e71deSHaik Aftandilian NULL, 0, 0); 559*023e71deSHaik Aftandilian return; 560*023e71deSHaik Aftandilian } 561*023e71deSHaik Aftandilian 562*023e71deSHaik Aftandilian /* 563*023e71deSHaik Aftandilian * If ps_suspend_thread_exit is set, ds_cap_fini has been 564*023e71deSHaik Aftandilian * called and we shouldn't be receving data. Handle this unexpected 565*023e71deSHaik Aftandilian * case by returning without sending a response. 566*023e71deSHaik Aftandilian */ 567*023e71deSHaik Aftandilian if (ps_suspend_thread_exit) { 568*023e71deSHaik Aftandilian DBG("ps_suspend_data_handler: ps_suspend_thread is exiting\n"); 569*023e71deSHaik Aftandilian return; 570*023e71deSHaik Aftandilian } 571*023e71deSHaik Aftandilian 572*023e71deSHaik Aftandilian mutex_enter(&ps_suspend_mutex); 573*023e71deSHaik Aftandilian 574*023e71deSHaik Aftandilian /* If a suspend operation is in progress, abort now */ 575*023e71deSHaik Aftandilian if (ps_suspend_data != NULL) { 576*023e71deSHaik Aftandilian mutex_exit(&ps_suspend_mutex); 577*023e71deSHaik Aftandilian ps_suspend_send_response(&ds_suspend_handle, msg->req_num, 578*023e71deSHaik Aftandilian DOMAIN_SUSPEND_INPROGRESS, DOMAIN_SUSPEND_REC_SUCCESS, 579*023e71deSHaik Aftandilian NULL, 0, 0); 580*023e71deSHaik Aftandilian return; 581*023e71deSHaik Aftandilian } 582*023e71deSHaik Aftandilian 583*023e71deSHaik Aftandilian ps_suspend_data = kmem_alloc(sizeof (ps_suspend_data_t), KM_SLEEP); 584*023e71deSHaik Aftandilian ps_suspend_data->buf = kmem_alloc(buflen, KM_SLEEP); 585*023e71deSHaik Aftandilian ps_suspend_data->buflen = buflen; 586*023e71deSHaik Aftandilian bcopy(buf, ps_suspend_data->buf, buflen); 587*023e71deSHaik Aftandilian 588*023e71deSHaik Aftandilian cv_signal(&ps_suspend_cv); 589*023e71deSHaik Aftandilian mutex_exit(&ps_suspend_mutex); 590*023e71deSHaik Aftandilian } 591*023e71deSHaik Aftandilian 592*023e71deSHaik Aftandilian /* 593*023e71deSHaik Aftandilian * Schedule the suspend operation by calling the pre-suspend, suspend, 594*023e71deSHaik Aftandilian * and post-suspend functions. When sending back response messages, we 595*023e71deSHaik Aftandilian * only use a timeout for the post-suspend response because after 596*023e71deSHaik Aftandilian * a resume, domain services will be re-registered and we may not 597*023e71deSHaik Aftandilian * be able to send the response immediately. 598*023e71deSHaik Aftandilian */ 599*023e71deSHaik Aftandilian static void 600*023e71deSHaik Aftandilian ps_suspend_sequence(ps_suspend_data_t *data) 601*023e71deSHaik Aftandilian { 602*023e71deSHaik Aftandilian platsvc_suspend_req_t *msg; 603*023e71deSHaik Aftandilian uint32_t rec_result; 604*023e71deSHaik Aftandilian char *error_reason; 605*023e71deSHaik Aftandilian boolean_t recovered = B_TRUE; 606*023e71deSHaik Aftandilian uint_t rv; 607*023e71deSHaik Aftandilian 608*023e71deSHaik Aftandilian ASSERT(data != NULL); 609*023e71deSHaik Aftandilian 610*023e71deSHaik Aftandilian msg = data->buf; 611*023e71deSHaik Aftandilian error_reason = (char *)kmem_zalloc(SUSPEND_MAX_REASON_SIZE, KM_SLEEP); 612*023e71deSHaik Aftandilian 613*023e71deSHaik Aftandilian /* Pre-suspend */ 614*023e71deSHaik Aftandilian rv = suspend_pre(error_reason, SUSPEND_MAX_REASON_SIZE, &recovered); 615*023e71deSHaik Aftandilian if (rv != 0) { 616*023e71deSHaik Aftandilian rec_result = (recovered ? DOMAIN_SUSPEND_REC_SUCCESS : 617*023e71deSHaik Aftandilian DOMAIN_SUSPEND_REC_FAILURE); 618*023e71deSHaik Aftandilian 619*023e71deSHaik Aftandilian ps_suspend_send_response(&ds_suspend_handle, msg->req_num, 620*023e71deSHaik Aftandilian DOMAIN_SUSPEND_PRE_FAILURE, rec_result, error_reason, 0, 0); 621*023e71deSHaik Aftandilian 622*023e71deSHaik Aftandilian kmem_free(error_reason, SUSPEND_MAX_REASON_SIZE); 623*023e71deSHaik Aftandilian return; 624*023e71deSHaik Aftandilian } 625*023e71deSHaik Aftandilian 626*023e71deSHaik Aftandilian ps_suspend_send_response(&ds_suspend_handle, msg->req_num, 627*023e71deSHaik Aftandilian DOMAIN_SUSPEND_PRE_SUCCESS, 0, NULL, 0, 0); 628*023e71deSHaik Aftandilian 629*023e71deSHaik Aftandilian /* Suspend */ 630*023e71deSHaik Aftandilian rv = suspend_start(error_reason, SUSPEND_MAX_REASON_SIZE); 631*023e71deSHaik Aftandilian if (rv != 0) { 632*023e71deSHaik Aftandilian rec_result = (suspend_post(NULL, 0) == 0 ? 633*023e71deSHaik Aftandilian DOMAIN_SUSPEND_REC_SUCCESS : DOMAIN_SUSPEND_REC_FAILURE); 634*023e71deSHaik Aftandilian 635*023e71deSHaik Aftandilian ps_suspend_send_response(&ds_suspend_handle, msg->req_num, 636*023e71deSHaik Aftandilian DOMAIN_SUSPEND_SUSPEND_FAILURE, rec_result, error_reason, 637*023e71deSHaik Aftandilian 0, 0); 638*023e71deSHaik Aftandilian 639*023e71deSHaik Aftandilian kmem_free(error_reason, SUSPEND_MAX_REASON_SIZE); 640*023e71deSHaik Aftandilian return; 641*023e71deSHaik Aftandilian } 642*023e71deSHaik Aftandilian 643*023e71deSHaik Aftandilian /* Post-suspend */ 644*023e71deSHaik Aftandilian rv = suspend_post(error_reason, SUSPEND_MAX_REASON_SIZE); 645*023e71deSHaik Aftandilian if (rv != 0) { 646*023e71deSHaik Aftandilian ps_suspend_send_response(&ds_suspend_handle, msg->req_num, 647*023e71deSHaik Aftandilian DOMAIN_SUSPEND_POST_FAILURE, 0, error_reason, 648*023e71deSHaik Aftandilian ps_suspend_rereg_delay, ps_suspend_retry_intval); 649*023e71deSHaik Aftandilian } else { 650*023e71deSHaik Aftandilian ps_suspend_send_response(&ds_suspend_handle, msg->req_num, 651*023e71deSHaik Aftandilian DOMAIN_SUSPEND_POST_SUCCESS, 0, error_reason, 652*023e71deSHaik Aftandilian ps_suspend_rereg_delay, ps_suspend_retry_intval); 653*023e71deSHaik Aftandilian } 654*023e71deSHaik Aftandilian 655*023e71deSHaik Aftandilian kmem_free(error_reason, SUSPEND_MAX_REASON_SIZE); 656*023e71deSHaik Aftandilian } 657*023e71deSHaik Aftandilian 658*023e71deSHaik Aftandilian /* 659*023e71deSHaik Aftandilian * Wait for a suspend request or for ps_suspend_thread_exit to be set. 660*023e71deSHaik Aftandilian */ 661*023e71deSHaik Aftandilian static void 662*023e71deSHaik Aftandilian ps_suspend_thread_func(void) 663*023e71deSHaik Aftandilian { 664*023e71deSHaik Aftandilian mutex_enter(&ps_suspend_mutex); 665*023e71deSHaik Aftandilian 666*023e71deSHaik Aftandilian while (ps_suspend_thread_exit == B_FALSE) { 667*023e71deSHaik Aftandilian 668*023e71deSHaik Aftandilian if (ps_suspend_data == NULL) { 669*023e71deSHaik Aftandilian cv_wait(&ps_suspend_cv, &ps_suspend_mutex); 670*023e71deSHaik Aftandilian continue; 671*023e71deSHaik Aftandilian } 672*023e71deSHaik Aftandilian 673*023e71deSHaik Aftandilian mutex_exit(&ps_suspend_mutex); 674*023e71deSHaik Aftandilian ps_suspend_sequence(ps_suspend_data); 675*023e71deSHaik Aftandilian mutex_enter(&ps_suspend_mutex); 676*023e71deSHaik Aftandilian 677*023e71deSHaik Aftandilian kmem_free(ps_suspend_data->buf, ps_suspend_data->buflen); 678*023e71deSHaik Aftandilian kmem_free(ps_suspend_data, sizeof (ps_suspend_data_t)); 679*023e71deSHaik Aftandilian ps_suspend_data = NULL; 680*023e71deSHaik Aftandilian } 681*023e71deSHaik Aftandilian 682*023e71deSHaik Aftandilian mutex_exit(&ps_suspend_mutex); 683*023e71deSHaik Aftandilian 684*023e71deSHaik Aftandilian thread_exit(); 685*023e71deSHaik Aftandilian } 686*023e71deSHaik Aftandilian 6871ae08745Sheppo static void 6881ae08745Sheppo ps_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl) 6891ae08745Sheppo { 6901ae08745Sheppo DBG("ps_reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n", 6911ae08745Sheppo arg, ver->major, ver->minor, hdl); 6921ae08745Sheppo 6931ae08745Sheppo if ((ds_svc_hdl_t *)arg == &ds_md_handle) 6941ae08745Sheppo ds_md_handle = hdl; 6951ae08745Sheppo if ((ds_svc_hdl_t *)arg == &ds_shutdown_handle) 6961ae08745Sheppo ds_shutdown_handle = hdl; 6971ae08745Sheppo if ((ds_svc_hdl_t *)arg == &ds_panic_handle) 6981ae08745Sheppo ds_panic_handle = hdl; 699*023e71deSHaik Aftandilian if ((ds_svc_hdl_t *)arg == &ds_suspend_handle) 700*023e71deSHaik Aftandilian ds_suspend_handle = hdl; 7011ae08745Sheppo } 7021ae08745Sheppo 7031ae08745Sheppo static void 7041ae08745Sheppo ps_unreg_handler(ds_cb_arg_t arg) 7051ae08745Sheppo { 7061ae08745Sheppo DBG("ps_unreg_handler: arg=0x%p\n", arg); 7071ae08745Sheppo 7081ae08745Sheppo if ((ds_svc_hdl_t *)arg == &ds_md_handle) 7091ae08745Sheppo ds_md_handle = DS_INVALID_HDL; 7101ae08745Sheppo if ((ds_svc_hdl_t *)arg == &ds_shutdown_handle) 7111ae08745Sheppo ds_shutdown_handle = DS_INVALID_HDL; 7121ae08745Sheppo if ((ds_svc_hdl_t *)arg == &ds_panic_handle) 7131ae08745Sheppo ds_panic_handle = DS_INVALID_HDL; 714*023e71deSHaik Aftandilian if ((ds_svc_hdl_t *)arg == &ds_suspend_handle) 715*023e71deSHaik Aftandilian ds_suspend_handle = DS_INVALID_HDL; 7161ae08745Sheppo } 717