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