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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * System call to checkpoint and resume the currently running kernel 30 */ 31 #include <sys/types.h> 32 #include <sys/errno.h> 33 #include <sys/modctl.h> 34 #include <sys/syscall.h> 35 #include <sys/cred.h> 36 #include <sys/uadmin.h> 37 #include <sys/cmn_err.h> 38 #include <sys/systm.h> 39 #include <sys/cpr.h> 40 #include <sys/swap.h> 41 #include <sys/vfs.h> 42 #include <sys/autoconf.h> 43 #include <sys/machsystm.h> 44 45 extern int i_cpr_is_supported(int sleeptype); 46 extern int cpr_is_ufs(struct vfs *); 47 extern int cpr_check_spec_statefile(void); 48 extern int cpr_reusable_mount_check(void); 49 extern int i_cpr_reusable_supported(void); 50 extern int i_cpr_reusefini(void); 51 extern struct mod_ops mod_miscops; 52 53 extern int cpr_init(int); 54 extern void cpr_done(void); 55 extern void i_cpr_stop_other_cpus(void); 56 extern int i_cpr_power_down(); 57 58 #if defined(__sparc) 59 extern void cpr_forget_cprconfig(void); 60 #endif 61 62 static struct modlmisc modlmisc = { 63 &mod_miscops, "checkpoint resume" 64 }; 65 66 static struct modlinkage modlinkage = { 67 MODREV_1, (void *)&modlmisc, NULL 68 }; 69 70 char _depends_on[] = "misc/bootdev"; /* i_devname_to_promname() */ 71 72 int cpr_reusable_mode; 73 74 kmutex_t cpr_slock; /* cpr serial lock */ 75 cpr_t cpr_state; 76 int cpr_debug; 77 int cpr_test_mode; /* true if called via uadmin testmode */ 78 int cpr_test_point = LOOP_BACK_NONE; /* cpr test point */ 79 int cpr_mp_enable = 0; /* set to 1 to enable MP suspend */ 80 major_t cpr_device = 0; /* major number for S3 on one device */ 81 82 /* 83 * All the loadable module related code follows 84 */ 85 int 86 _init(void) 87 { 88 register int e; 89 90 if ((e = mod_install(&modlinkage)) == 0) { 91 mutex_init(&cpr_slock, NULL, MUTEX_DEFAULT, NULL); 92 } 93 return (e); 94 } 95 96 int 97 _fini(void) 98 { 99 register int e; 100 101 if ((e = mod_remove(&modlinkage)) == 0) { 102 mutex_destroy(&cpr_slock); 103 } 104 return (e); 105 } 106 107 int 108 _info(struct modinfo *modinfop) 109 { 110 return (mod_info(&modlinkage, modinfop)); 111 } 112 113 static 114 int 115 atoi(char *p) 116 { 117 int i; 118 119 i = (*p++ - '0'); 120 121 while (*p != '\0') 122 i = 10 * i + (*p++ - '0'); 123 124 return (i); 125 } 126 127 int 128 cpr(int fcn, void *mdep) 129 { 130 131 #if defined(__sparc) 132 static const char noswapstr[] = "reusable statefile requires " 133 "that no swap area be configured.\n"; 134 static const char blockstr[] = "reusable statefile must be " 135 "a block device. See power.conf(4) and pmconfig(1M).\n"; 136 static const char normalfmt[] = "cannot run normal " 137 "checkpoint/resume when in reusable statefile mode. " 138 "use uadmin A_FREEZE AD_REUSEFINI (uadmin %d %d) " 139 "to exit reusable statefile mode.\n"; 140 static const char modefmt[] = "%s in reusable mode.\n"; 141 #endif 142 register int rc = 0; 143 int cpr_sleeptype; 144 145 /* 146 * First, reject commands that we don't (yet) support on this arch. 147 * This is easier to understand broken out like this than grotting 148 * through the second switch below. 149 */ 150 151 switch (fcn) { 152 #if defined(__sparc) 153 case AD_CHECK_SUSPEND_TO_RAM: 154 case AD_SUSPEND_TO_RAM: 155 return (ENOTSUP); 156 case AD_CHECK_SUSPEND_TO_DISK: 157 case AD_SUSPEND_TO_DISK: 158 case AD_CPR_REUSEINIT: 159 case AD_CPR_NOCOMPRESS: 160 case AD_CPR_FORCE: 161 case AD_CPR_REUSABLE: 162 case AD_CPR_REUSEFINI: 163 case AD_CPR_TESTZ: 164 case AD_CPR_TESTNOZ: 165 case AD_CPR_TESTHALT: 166 case AD_CPR_SUSP_DEVICES: 167 cpr_sleeptype = CPR_TODISK; 168 break; 169 #endif 170 #if defined(__x86) 171 case AD_CHECK_SUSPEND_TO_DISK: 172 case AD_SUSPEND_TO_DISK: 173 case AD_CPR_REUSEINIT: 174 case AD_CPR_NOCOMPRESS: 175 case AD_CPR_FORCE: 176 case AD_CPR_REUSABLE: 177 case AD_CPR_REUSEFINI: 178 case AD_CPR_TESTZ: 179 case AD_CPR_TESTNOZ: 180 case AD_CPR_TESTHALT: 181 case AD_CPR_PRINT: 182 return (ENOTSUP); 183 /* The DEV_* values need to be removed after sys-syspend is fixed */ 184 case DEV_CHECK_SUSPEND_TO_RAM: 185 case DEV_SUSPEND_TO_RAM: 186 case AD_CPR_SUSP_DEVICES: 187 case AD_CHECK_SUSPEND_TO_RAM: 188 case AD_SUSPEND_TO_RAM: 189 case AD_LOOPBACK_SUSPEND_TO_RAM_PASS: 190 case AD_LOOPBACK_SUSPEND_TO_RAM_FAIL: 191 case AD_FORCE_SUSPEND_TO_RAM: 192 case AD_DEVICE_SUSPEND_TO_RAM: 193 cpr_sleeptype = CPR_TORAM; 194 break; 195 #endif 196 } 197 #if defined(__sparc) 198 /* 199 * Need to know if we're in reusable mode, but we will likely have 200 * rebooted since REUSEINIT, so we have to get the info from the 201 * file system 202 */ 203 if (!cpr_reusable_mode) 204 cpr_reusable_mode = cpr_get_reusable_mode(); 205 206 cpr_forget_cprconfig(); 207 #endif 208 209 switch (fcn) { 210 211 #if defined(__sparc) 212 case AD_CPR_REUSEINIT: 213 if (!i_cpr_reusable_supported()) 214 return (ENOTSUP); 215 if (!cpr_statefile_is_spec()) { 216 cpr_err(CE_CONT, blockstr); 217 return (EINVAL); 218 } 219 if ((rc = cpr_check_spec_statefile()) != 0) 220 return (rc); 221 if (swapinfo) { 222 cpr_err(CE_CONT, noswapstr); 223 return (EINVAL); 224 } 225 cpr_test_mode = 0; 226 break; 227 228 case AD_CPR_NOCOMPRESS: 229 case AD_CPR_COMPRESS: 230 case AD_CPR_FORCE: 231 if (cpr_reusable_mode) { 232 cpr_err(CE_CONT, normalfmt, A_FREEZE, AD_REUSEFINI); 233 return (ENOTSUP); 234 } 235 cpr_test_mode = 0; 236 break; 237 238 case AD_CPR_REUSABLE: 239 if (!i_cpr_reusable_supported()) 240 return (ENOTSUP); 241 if (!cpr_statefile_is_spec()) { 242 cpr_err(CE_CONT, blockstr); 243 return (EINVAL); 244 } 245 if ((rc = cpr_check_spec_statefile()) != 0) 246 return (rc); 247 if (swapinfo) { 248 cpr_err(CE_CONT, noswapstr); 249 return (EINVAL); 250 } 251 if ((rc = cpr_reusable_mount_check()) != 0) 252 return (rc); 253 cpr_test_mode = 0; 254 break; 255 256 case AD_CPR_REUSEFINI: 257 if (!i_cpr_reusable_supported()) 258 return (ENOTSUP); 259 cpr_test_mode = 0; 260 break; 261 262 case AD_CPR_TESTZ: 263 case AD_CPR_TESTNOZ: 264 case AD_CPR_TESTHALT: 265 if (cpr_reusable_mode) { 266 cpr_err(CE_CONT, normalfmt, A_FREEZE, AD_REUSEFINI); 267 return (ENOTSUP); 268 } 269 cpr_test_mode = 1; 270 break; 271 272 case AD_CPR_CHECK: 273 if (!i_cpr_is_supported(cpr_sleeptype) || cpr_reusable_mode) 274 return (ENOTSUP); 275 return (0); 276 277 case AD_CPR_PRINT: 278 CPR_STAT_EVENT_END("POST CPR DELAY"); 279 cpr_stat_event_print(); 280 return (0); 281 #endif 282 283 case AD_CPR_DEBUG0: 284 cpr_debug = 0; 285 return (0); 286 287 case AD_CPR_DEBUG1: 288 case AD_CPR_DEBUG2: 289 case AD_CPR_DEBUG3: 290 case AD_CPR_DEBUG4: 291 case AD_CPR_DEBUG5: 292 case AD_CPR_DEBUG7: 293 case AD_CPR_DEBUG8: 294 cpr_debug |= CPR_DEBUG_BIT(fcn); 295 return (0); 296 297 case AD_CPR_DEBUG9: 298 cpr_debug |= CPR_DEBUG6; 299 return (0); 300 301 /* The DEV_* values need to be removed after sys-syspend is fixed */ 302 case DEV_CHECK_SUSPEND_TO_RAM: 303 case DEV_SUSPEND_TO_RAM: 304 case AD_CHECK_SUSPEND_TO_RAM: 305 case AD_SUSPEND_TO_RAM: 306 cpr_test_point = LOOP_BACK_NONE; 307 break; 308 309 case AD_LOOPBACK_SUSPEND_TO_RAM_PASS: 310 cpr_test_point = LOOP_BACK_PASS; 311 break; 312 313 case AD_LOOPBACK_SUSPEND_TO_RAM_FAIL: 314 cpr_test_point = LOOP_BACK_FAIL; 315 break; 316 317 case AD_FORCE_SUSPEND_TO_RAM: 318 cpr_test_point = FORCE_SUSPEND_TO_RAM; 319 break; 320 321 case AD_DEVICE_SUSPEND_TO_RAM: 322 if (mdep == NULL) { 323 /* Didn't pass enough arguments */ 324 return (EINVAL); 325 } 326 cpr_test_point = DEVICE_SUSPEND_TO_RAM; 327 cpr_device = (major_t)atoi((char *)mdep); 328 break; 329 330 case AD_CPR_SUSP_DEVICES: 331 cpr_test_point = FORCE_SUSPEND_TO_RAM; 332 if (cpr_suspend_devices(ddi_root_node()) != DDI_SUCCESS) 333 cmn_err(CE_WARN, 334 "Some devices did not suspend " 335 "and may be unusable"); 336 (void) cpr_resume_devices(ddi_root_node(), 0); 337 return (0); 338 339 default: 340 return (ENOTSUP); 341 } 342 343 if (!i_cpr_is_supported(cpr_sleeptype) || 344 (cpr_sleeptype == CPR_TODISK && !cpr_is_ufs(rootvfs))) 345 return (ENOTSUP); 346 347 if (fcn == AD_CHECK_SUSPEND_TO_RAM || 348 fcn == DEV_CHECK_SUSPEND_TO_RAM) { 349 ASSERT(i_cpr_is_supported(cpr_sleeptype)); 350 return (0); 351 } 352 353 #if defined(__sparc) 354 if (fcn == AD_CPR_REUSEINIT) { 355 if (mutex_tryenter(&cpr_slock) == 0) 356 return (EBUSY); 357 if (cpr_reusable_mode) { 358 cpr_err(CE_CONT, modefmt, "already"); 359 mutex_exit(&cpr_slock); 360 return (EBUSY); 361 } 362 rc = i_cpr_reuseinit(); 363 mutex_exit(&cpr_slock); 364 return (rc); 365 } 366 367 if (fcn == AD_CPR_REUSEFINI) { 368 if (mutex_tryenter(&cpr_slock) == 0) 369 return (EBUSY); 370 if (!cpr_reusable_mode) { 371 cpr_err(CE_CONT, modefmt, "not"); 372 mutex_exit(&cpr_slock); 373 return (EINVAL); 374 } 375 rc = i_cpr_reusefini(); 376 mutex_exit(&cpr_slock); 377 return (rc); 378 } 379 #endif 380 381 /* 382 * acquire cpr serial lock and init cpr state structure. 383 */ 384 if (rc = cpr_init(fcn)) 385 return (rc); 386 387 #if defined(__sparc) 388 if (fcn == AD_CPR_REUSABLE) { 389 if ((rc = i_cpr_check_cprinfo()) != 0) { 390 mutex_exit(&cpr_slock); 391 return (rc); 392 } 393 } 394 #endif 395 396 /* 397 * Call the main cpr routine. If we are successful, we will be coming 398 * down from the resume side, otherwise we are still in suspend. 399 */ 400 cpr_err(CE_CONT, "System is being suspended"); 401 if (rc = cpr_main(cpr_sleeptype)) { 402 CPR->c_flags |= C_ERROR; 403 PMD(PMD_SX, ("cpr: Suspend operation failed.\n")) 404 cpr_err(CE_NOTE, "Suspend operation failed."); 405 } else if (CPR->c_flags & C_SUSPENDING) { 406 407 /* 408 * In the suspend to RAM case, by the time we get 409 * control back we're already resumed 410 */ 411 if (cpr_sleeptype == CPR_TORAM) { 412 PMD(PMD_SX, ("cpr: cpr CPR_TORAM done\n")) 413 cpr_done(); 414 return (rc); 415 } 416 417 #if defined(__sparc) 418 419 PMD(PMD_SX, ("cpr: Suspend operation succeeded.\n")) 420 /* 421 * Back from a successful checkpoint 422 */ 423 if (fcn == AD_CPR_TESTZ || fcn == AD_CPR_TESTNOZ) { 424 mdboot(0, AD_BOOT, "", B_FALSE); 425 /* NOTREACHED */ 426 } 427 428 /* make sure there are no more changes to the device tree */ 429 PMD(PMD_SX, ("cpr: dev tree freeze\n")) 430 devtree_freeze(); 431 432 /* 433 * stop other cpus and raise our priority. since there is only 434 * one active cpu after this, and our priority will be too high 435 * for us to be preempted, we're essentially single threaded 436 * from here on out. 437 */ 438 PMD(PMD_SX, ("cpr: stop other cpus\n")) 439 i_cpr_stop_other_cpus(); 440 PMD(PMD_SX, ("cpr: spl6\n")) 441 (void) spl6(); 442 443 /* 444 * try and reset leaf devices. reset_leaves() should only 445 * be called when there are no other threads that could be 446 * accessing devices 447 */ 448 PMD(PMD_SX, ("cpr: reset leaves\n")) 449 reset_leaves(); 450 451 /* 452 * If i_cpr_power_down() succeeds, it'll not return 453 * 454 * Drives with write-cache enabled need to flush 455 * their cache. 456 */ 457 if (fcn != AD_CPR_TESTHALT) { 458 PMD(PMD_SX, ("cpr: power down\n")) 459 (void) i_cpr_power_down(cpr_sleeptype); 460 } 461 ASSERT(cpr_sleeptype == CPR_TODISK); 462 /* currently CPR_TODISK comes back via a boot path */ 463 CPR_DEBUG(CPR_DEBUG1, "(Done. Please Switch Off)\n"); 464 halt(NULL); 465 /* NOTREACHED */ 466 #endif 467 } 468 PMD(PMD_SX, ("cpr: cpr done\n")) 469 cpr_done(); 470 return (rc); 471 } 472