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 2007 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 /* 194 * if MP then do not support suspend to RAM, however override 195 * the MP restriction if cpr_mp_enable has been set 196 */ 197 if (ncpus > 1 && cpr_mp_enable == 0) 198 return (ENOTSUP); 199 else 200 cpr_sleeptype = CPR_TORAM; 201 break; 202 #endif 203 } 204 #if defined(__sparc) 205 /* 206 * Need to know if we're in reusable mode, but we will likely have 207 * rebooted since REUSEINIT, so we have to get the info from the 208 * file system 209 */ 210 if (!cpr_reusable_mode) 211 cpr_reusable_mode = cpr_get_reusable_mode(); 212 213 cpr_forget_cprconfig(); 214 #endif 215 216 switch (fcn) { 217 218 #if defined(__sparc) 219 case AD_CPR_REUSEINIT: 220 if (!i_cpr_reusable_supported()) 221 return (ENOTSUP); 222 if (!cpr_statefile_is_spec()) { 223 cpr_err(CE_CONT, blockstr); 224 return (EINVAL); 225 } 226 if ((rc = cpr_check_spec_statefile()) != 0) 227 return (rc); 228 if (swapinfo) { 229 cpr_err(CE_CONT, noswapstr); 230 return (EINVAL); 231 } 232 cpr_test_mode = 0; 233 break; 234 235 case AD_CPR_NOCOMPRESS: 236 case AD_CPR_COMPRESS: 237 case AD_CPR_FORCE: 238 if (cpr_reusable_mode) { 239 cpr_err(CE_CONT, normalfmt, A_FREEZE, AD_REUSEFINI); 240 return (ENOTSUP); 241 } 242 cpr_test_mode = 0; 243 break; 244 245 case AD_CPR_REUSABLE: 246 if (!i_cpr_reusable_supported()) 247 return (ENOTSUP); 248 if (!cpr_statefile_is_spec()) { 249 cpr_err(CE_CONT, blockstr); 250 return (EINVAL); 251 } 252 if ((rc = cpr_check_spec_statefile()) != 0) 253 return (rc); 254 if (swapinfo) { 255 cpr_err(CE_CONT, noswapstr); 256 return (EINVAL); 257 } 258 if ((rc = cpr_reusable_mount_check()) != 0) 259 return (rc); 260 cpr_test_mode = 0; 261 break; 262 263 case AD_CPR_REUSEFINI: 264 if (!i_cpr_reusable_supported()) 265 return (ENOTSUP); 266 cpr_test_mode = 0; 267 break; 268 269 case AD_CPR_TESTZ: 270 case AD_CPR_TESTNOZ: 271 case AD_CPR_TESTHALT: 272 if (cpr_reusable_mode) { 273 cpr_err(CE_CONT, normalfmt, A_FREEZE, AD_REUSEFINI); 274 return (ENOTSUP); 275 } 276 cpr_test_mode = 1; 277 break; 278 279 case AD_CPR_CHECK: 280 if (!i_cpr_is_supported(cpr_sleeptype) || cpr_reusable_mode) 281 return (ENOTSUP); 282 return (0); 283 284 case AD_CPR_PRINT: 285 CPR_STAT_EVENT_END("POST CPR DELAY"); 286 cpr_stat_event_print(); 287 return (0); 288 #endif 289 290 case AD_CPR_DEBUG0: 291 cpr_debug = 0; 292 return (0); 293 294 case AD_CPR_DEBUG1: 295 case AD_CPR_DEBUG2: 296 case AD_CPR_DEBUG3: 297 case AD_CPR_DEBUG4: 298 case AD_CPR_DEBUG5: 299 case AD_CPR_DEBUG7: 300 case AD_CPR_DEBUG8: 301 cpr_debug |= CPR_DEBUG_BIT(fcn); 302 return (0); 303 304 case AD_CPR_DEBUG9: 305 cpr_debug |= CPR_DEBUG6; 306 return (0); 307 308 /* The DEV_* values need to be removed after sys-syspend is fixed */ 309 case DEV_CHECK_SUSPEND_TO_RAM: 310 case DEV_SUSPEND_TO_RAM: 311 case AD_CHECK_SUSPEND_TO_RAM: 312 case AD_SUSPEND_TO_RAM: 313 cpr_test_point = LOOP_BACK_NONE; 314 break; 315 316 case AD_LOOPBACK_SUSPEND_TO_RAM_PASS: 317 cpr_test_point = LOOP_BACK_PASS; 318 break; 319 320 case AD_LOOPBACK_SUSPEND_TO_RAM_FAIL: 321 cpr_test_point = LOOP_BACK_FAIL; 322 break; 323 324 case AD_FORCE_SUSPEND_TO_RAM: 325 cpr_test_point = FORCE_SUSPEND_TO_RAM; 326 break; 327 328 case AD_DEVICE_SUSPEND_TO_RAM: 329 cpr_test_point = DEVICE_SUSPEND_TO_RAM; 330 cpr_device = (major_t)atoi((char *)mdep); 331 break; 332 333 case AD_CPR_SUSP_DEVICES: 334 cpr_test_point = FORCE_SUSPEND_TO_RAM; 335 if (cpr_suspend_devices(ddi_root_node()) != DDI_SUCCESS) 336 cmn_err(CE_WARN, 337 "Some devices did not suspend " 338 "and may be unusable"); 339 (void) cpr_resume_devices(ddi_root_node(), 0); 340 return (0); 341 342 default: 343 return (ENOTSUP); 344 } 345 346 if (!i_cpr_is_supported(cpr_sleeptype) || 347 (cpr_sleeptype == CPR_TODISK && !cpr_is_ufs(rootvfs))) 348 return (ENOTSUP); 349 350 if (fcn == AD_CHECK_SUSPEND_TO_RAM || 351 fcn == DEV_CHECK_SUSPEND_TO_RAM) { 352 ASSERT(i_cpr_is_supported(cpr_sleeptype)); 353 return (0); 354 } 355 356 #if defined(__sparc) 357 if (fcn == AD_CPR_REUSEINIT) { 358 if (mutex_tryenter(&cpr_slock) == 0) 359 return (EBUSY); 360 if (cpr_reusable_mode) { 361 cpr_err(CE_CONT, modefmt, "already"); 362 mutex_exit(&cpr_slock); 363 return (EBUSY); 364 } 365 rc = i_cpr_reuseinit(); 366 mutex_exit(&cpr_slock); 367 return (rc); 368 } 369 370 if (fcn == AD_CPR_REUSEFINI) { 371 if (mutex_tryenter(&cpr_slock) == 0) 372 return (EBUSY); 373 if (!cpr_reusable_mode) { 374 cpr_err(CE_CONT, modefmt, "not"); 375 mutex_exit(&cpr_slock); 376 return (EINVAL); 377 } 378 rc = i_cpr_reusefini(); 379 mutex_exit(&cpr_slock); 380 return (rc); 381 } 382 #endif 383 384 /* 385 * acquire cpr serial lock and init cpr state structure. 386 */ 387 if (rc = cpr_init(fcn)) 388 return (rc); 389 390 #if defined(__sparc) 391 if (fcn == AD_CPR_REUSABLE) { 392 if ((rc = i_cpr_check_cprinfo()) != 0) { 393 mutex_exit(&cpr_slock); 394 return (rc); 395 } 396 } 397 #endif 398 399 /* 400 * Call the main cpr routine. If we are successful, we will be coming 401 * down from the resume side, otherwise we are still in suspend. 402 */ 403 cpr_err(CE_CONT, "System is being suspended"); 404 if (rc = cpr_main(cpr_sleeptype)) { 405 CPR->c_flags |= C_ERROR; 406 PMD(PMD_SX, ("cpr: Suspend operation failed.\n")) 407 cpr_err(CE_NOTE, "Suspend operation failed."); 408 } else if (CPR->c_flags & C_SUSPENDING) { 409 410 /* 411 * In the suspend to RAM case, by the time we get 412 * control back we're already resumed 413 */ 414 if (cpr_sleeptype == CPR_TORAM) { 415 PMD(PMD_SX, ("cpr: cpr CPR_TORAM done\n")) 416 cpr_done(); 417 return (rc); 418 } 419 420 #if defined(__sparc) 421 422 PMD(PMD_SX, ("cpr: Suspend operation succeeded.\n")) 423 /* 424 * Back from a successful checkpoint 425 */ 426 if (fcn == AD_CPR_TESTZ || fcn == AD_CPR_TESTNOZ) { 427 mdboot(0, AD_BOOT, "", B_FALSE); 428 /* NOTREACHED */ 429 } 430 431 /* make sure there are no more changes to the device tree */ 432 PMD(PMD_SX, ("cpr: dev tree freeze\n")) 433 devtree_freeze(); 434 435 /* 436 * stop other cpus and raise our priority. since there is only 437 * one active cpu after this, and our priority will be too high 438 * for us to be preempted, we're essentially single threaded 439 * from here on out. 440 */ 441 PMD(PMD_SX, ("cpr: stop other cpus\n")) 442 i_cpr_stop_other_cpus(); 443 PMD(PMD_SX, ("cpr: spl6\n")) 444 (void) spl6(); 445 446 /* 447 * try and reset leaf devices. reset_leaves() should only 448 * be called when there are no other threads that could be 449 * accessing devices 450 */ 451 PMD(PMD_SX, ("cpr: reset leaves\n")) 452 reset_leaves(); 453 454 /* 455 * If i_cpr_power_down() succeeds, it'll not return 456 * 457 * Drives with write-cache enabled need to flush 458 * their cache. 459 */ 460 if (fcn != AD_CPR_TESTHALT) { 461 PMD(PMD_SX, ("cpr: power down\n")) 462 (void) i_cpr_power_down(cpr_sleeptype); 463 } 464 ASSERT(cpr_sleeptype == CPR_TODISK); 465 /* currently CPR_TODISK comes back via a boot path */ 466 CPR_DEBUG(CPR_DEBUG1, "(Done. Please Switch Off)\n"); 467 halt(NULL); 468 /* NOTREACHED */ 469 #endif 470 } 471 PMD(PMD_SX, ("cpr: cpr done\n")) 472 cpr_done(); 473 return (rc); 474 } 475