xref: /titanic_50/usr/src/uts/i86pc/io/dr/dr_quiesce.c (revision ed1ea272e98909be8d058acbc225bfdd017be142)
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 /*
23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * A CPR derivative specifically for starfire/starcat
29  * X86 doesn't make use of the quiesce interfaces, it's kept for simplicity.
30  */
31 
32 #include <sys/types.h>
33 #include <sys/systm.h>
34 #include <sys/machparam.h>
35 #include <sys/machsystm.h>
36 #include <sys/ddi.h>
37 #define	SUNDDI_IMPL
38 #include <sys/sunddi.h>
39 #include <sys/sunndi.h>
40 #include <sys/devctl.h>
41 #include <sys/time.h>
42 #include <sys/kmem.h>
43 #include <nfs/lm.h>
44 #include <sys/ddi_impldefs.h>
45 #include <sys/ndi_impldefs.h>
46 #include <sys/obpdefs.h>
47 #include <sys/cmn_err.h>
48 #include <sys/debug.h>
49 #include <sys/errno.h>
50 #include <sys/callb.h>
51 #include <sys/clock.h>
52 #include <sys/x_call.h>
53 #include <sys/cpuvar.h>
54 #include <sys/epm.h>
55 #include <sys/vfs.h>
56 #include <sys/promif.h>
57 #include <sys/conf.h>
58 #include <sys/cyclic.h>
59 
60 #include <sys/dr.h>
61 #include <sys/dr_util.h>
62 
63 extern void	e_ddi_enter_driver_list(struct devnames *dnp, int *listcnt);
64 extern void	e_ddi_exit_driver_list(struct devnames *dnp, int listcnt);
65 extern int	is_pseudo_device(dev_info_t *dip);
66 
67 extern kmutex_t	cpu_lock;
68 extern dr_unsafe_devs_t dr_unsafe_devs;
69 
70 static int		dr_is_real_device(dev_info_t *dip);
71 static int		dr_is_unsafe_major(major_t major);
72 static int		dr_bypass_device(char *dname);
73 static int		dr_check_dip(dev_info_t *dip, void *arg, uint_t ref);
74 static int		dr_resolve_devname(dev_info_t *dip, char *buffer,
75 				char *alias);
76 static sbd_error_t	*drerr_int(int e_code, uint64_t *arr, int idx,
77 				int majors);
78 static int		dr_add_int(uint64_t *arr, int idx, int len,
79 				uint64_t val);
80 
81 int dr_pt_test_suspend(dr_handle_t *hp);
82 
83 /*
84  * dr_quiesce.c interface
85  * NOTE: states used internally by dr_suspend and dr_resume
86  */
87 typedef enum dr_suspend_state {
88 	DR_SRSTATE_BEGIN = 0,
89 	DR_SRSTATE_USER,
90 	DR_SRSTATE_DRIVER,
91 	DR_SRSTATE_FULL
92 } suspend_state_t;
93 
94 struct dr_sr_handle {
95 	dr_handle_t		*sr_dr_handlep;
96 	dev_info_t		*sr_failed_dip;
97 	suspend_state_t		sr_suspend_state;
98 	uint_t			sr_flags;
99 	uint64_t		sr_err_ints[DR_MAX_ERR_INT];
100 	int			sr_err_idx;
101 };
102 
103 #define	SR_FLAG_WATCHDOG	0x1
104 
105 /*
106  * XXX
107  * This hack will go away before RTI.  Just for testing.
108  * List of drivers to bypass when performing a suspend.
109  */
110 static char *dr_bypass_list[] = {
111 	""
112 };
113 
114 
115 #define		SKIP_SYNC	/* bypass sync ops in dr_suspend */
116 
117 /*
118  * dr_skip_user_threads is used to control if user threads should
119  * be suspended.  If dr_skip_user_threads is true, the rest of the
120  * flags are not used; if it is false, dr_check_user_stop_result
121  * will be used to control whether or not we need to check suspend
122  * result, and dr_allow_blocked_threads will be used to control
123  * whether or not we allow suspend to continue if there are blocked
124  * threads.  We allow all combinations of dr_check_user_stop_result
125  * and dr_allow_block_threads, even though it might not make much
126  * sense to not allow block threads when we don't even check stop
127  * result.
128  */
129 static int	dr_skip_user_threads = 0;	/* default to FALSE */
130 static int	dr_check_user_stop_result = 1;	/* default to TRUE */
131 static int	dr_allow_blocked_threads = 1;	/* default to TRUE */
132 
133 #define	DR_CPU_LOOP_MSEC	1000
134 
135 static void
136 dr_stop_intr(void)
137 {
138 	ASSERT(MUTEX_HELD(&cpu_lock));
139 
140 	kpreempt_disable();
141 	cyclic_suspend();
142 }
143 
144 static void
145 dr_enable_intr(void)
146 {
147 	ASSERT(MUTEX_HELD(&cpu_lock));
148 
149 	cyclic_resume();
150 	kpreempt_enable();
151 }
152 
153 dr_sr_handle_t *
154 dr_get_sr_handle(dr_handle_t *hp)
155 {
156 	dr_sr_handle_t *srh;
157 
158 	srh = GETSTRUCT(dr_sr_handle_t, 1);
159 	srh->sr_dr_handlep = hp;
160 
161 	return (srh);
162 }
163 
164 void
165 dr_release_sr_handle(dr_sr_handle_t *srh)
166 {
167 	ASSERT(srh->sr_failed_dip == NULL);
168 	FREESTRUCT(srh, dr_sr_handle_t, 1);
169 }
170 
171 static int
172 dr_is_real_device(dev_info_t *dip)
173 {
174 	struct regspec *regbuf = NULL;
175 	int length = 0;
176 	int rc;
177 
178 	if (ddi_get_driver(dip) == NULL)
179 		return (0);
180 
181 	if (DEVI(dip)->devi_pm_flags & (PMC_NEEDS_SR|PMC_PARENTAL_SR))
182 		return (1);
183 	if (DEVI(dip)->devi_pm_flags & PMC_NO_SR)
184 		return (0);
185 
186 	/*
187 	 * now the general case
188 	 */
189 	rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
190 	    (caddr_t)&regbuf, &length);
191 	ASSERT(rc != DDI_PROP_NO_MEMORY);
192 	if (rc != DDI_PROP_SUCCESS) {
193 		return (0);
194 	} else {
195 		if ((length > 0) && (regbuf != NULL))
196 			kmem_free(regbuf, length);
197 		return (1);
198 	}
199 }
200 
201 static int
202 dr_is_unsafe_major(major_t major)
203 {
204 	char    *dname, **cpp;
205 	int	i, ndevs;
206 
207 	if ((dname = ddi_major_to_name(major)) == NULL) {
208 		PR_QR("dr_is_unsafe_major: invalid major # %d\n", major);
209 		return (0);
210 	}
211 
212 	ndevs = dr_unsafe_devs.ndevs;
213 	for (i = 0, cpp = dr_unsafe_devs.devnames; i < ndevs; i++) {
214 		if (strcmp(dname, *cpp++) == 0)
215 			return (1);
216 	}
217 	return (0);
218 }
219 
220 static int
221 dr_bypass_device(char *dname)
222 {
223 	int i;
224 	char **lname;
225 	/* check the bypass list */
226 	for (i = 0, lname = &dr_bypass_list[i]; **lname != '\0'; lname++) {
227 		if (strcmp(dname, dr_bypass_list[i++]) == 0)
228 			return (1);
229 	}
230 	return (0);
231 }
232 
233 static int
234 dr_resolve_devname(dev_info_t *dip, char *buffer, char *alias)
235 {
236 	major_t	devmajor;
237 	char	*aka, *name;
238 
239 	*buffer = *alias = 0;
240 
241 	if (dip == NULL)
242 		return (-1);
243 
244 	if ((name = ddi_get_name(dip)) == NULL)
245 		name = "<null name>";
246 
247 	aka = name;
248 
249 	if ((devmajor = ddi_name_to_major(aka)) != DDI_MAJOR_T_NONE)
250 		aka = ddi_major_to_name(devmajor);
251 
252 	(void) strcpy(buffer, name);
253 
254 	if (strcmp(name, aka))
255 		(void) strcpy(alias, aka);
256 	else
257 		*alias = 0;
258 
259 	return (0);
260 }
261 
262 struct dr_ref {
263 	int		*refcount;
264 	int		*refcount_non_gldv3;
265 	uint64_t	*arr;
266 	int		*idx;
267 	int		len;
268 };
269 
270 /* ARGSUSED */
271 static int
272 dr_check_dip(dev_info_t *dip, void *arg, uint_t ref)
273 {
274 	major_t		major;
275 	char		*dname;
276 	struct dr_ref	*rp = (struct dr_ref *)arg;
277 
278 	if (dip == NULL)
279 		return (DDI_WALK_CONTINUE);
280 
281 	if (!dr_is_real_device(dip))
282 		return (DDI_WALK_CONTINUE);
283 
284 	dname = ddi_binding_name(dip);
285 
286 	if (dr_bypass_device(dname))
287 		return (DDI_WALK_CONTINUE);
288 
289 	if (dname && ((major = ddi_name_to_major(dname)) != (major_t)-1)) {
290 		if (ref && rp->refcount) {
291 			*rp->refcount += ref;
292 			PR_QR("\n  %s (major# %d) is referenced(%u)\n", dname,
293 			    major, ref);
294 		}
295 		if (ref && rp->refcount_non_gldv3) {
296 			if (NETWORK_PHYSDRV(major) && !GLDV3_DRV(major))
297 				*rp->refcount_non_gldv3 += ref;
298 		}
299 		if (dr_is_unsafe_major(major) && i_ddi_devi_attached(dip)) {
300 			PR_QR("\n  %s (major# %d) not hotpluggable\n", dname,
301 			    major);
302 			if (rp->arr != NULL && rp->idx != NULL)
303 				*rp->idx = dr_add_int(rp->arr, *rp->idx,
304 				    rp->len, (uint64_t)major);
305 		}
306 	}
307 	return (DDI_WALK_CONTINUE);
308 }
309 
310 static int
311 dr_check_unsafe_major(dev_info_t *dip, void *arg)
312 {
313 	return (dr_check_dip(dip, arg, 0));
314 }
315 
316 
317 /*ARGSUSED*/
318 void
319 dr_check_devices(dev_info_t *dip, int *refcount, dr_handle_t *handle,
320     uint64_t *arr, int *idx, int len, int *refcount_non_gldv3)
321 {
322 	struct dr_ref bref = {0};
323 
324 	if (dip == NULL)
325 		return;
326 
327 	bref.refcount = refcount;
328 	bref.refcount_non_gldv3 = refcount_non_gldv3;
329 	bref.arr = arr;
330 	bref.idx = idx;
331 	bref.len = len;
332 
333 	ASSERT(e_ddi_branch_held(dip));
334 	(void) e_ddi_branch_referenced(dip, dr_check_dip, &bref);
335 }
336 
337 /*
338  * The "dip" argument's parent (if it exists) must be held busy.
339  */
340 static int
341 dr_suspend_devices(dev_info_t *dip, dr_sr_handle_t *srh)
342 {
343 	dr_handle_t	*handle;
344 	major_t		major;
345 	char		*dname;
346 	int		circ;
347 
348 	/*
349 	 * If dip is the root node, it has no siblings and it is
350 	 * always held. If dip is not the root node, dr_suspend_devices()
351 	 * will be invoked with the parent held busy.
352 	 */
353 	for (; dip != NULL; dip = ddi_get_next_sibling(dip)) {
354 		char	d_name[40], d_alias[40], *d_info;
355 
356 		ndi_devi_enter(dip, &circ);
357 		if (dr_suspend_devices(ddi_get_child(dip), srh)) {
358 			ndi_devi_exit(dip, circ);
359 			return (ENXIO);
360 		}
361 		ndi_devi_exit(dip, circ);
362 
363 		if (!dr_is_real_device(dip))
364 			continue;
365 
366 		major = (major_t)-1;
367 		if ((dname = ddi_binding_name(dip)) != NULL)
368 			major = ddi_name_to_major(dname);
369 
370 		if (dr_bypass_device(dname)) {
371 			PR_QR(" bypassed suspend of %s (major# %d)\n", dname,
372 			    major);
373 			continue;
374 		}
375 
376 		if (drmach_verify_sr(dip, 1)) {
377 			PR_QR(" bypassed suspend of %s (major# %d)\n", dname,
378 			    major);
379 			continue;
380 		}
381 
382 		if ((d_info = ddi_get_name_addr(dip)) == NULL)
383 			d_info = "<null>";
384 
385 		d_name[0] = 0;
386 		if (dr_resolve_devname(dip, d_name, d_alias) == 0) {
387 			if (d_alias[0] != 0) {
388 				prom_printf("\tsuspending %s@%s (aka %s)\n",
389 				    d_name, d_info, d_alias);
390 			} else {
391 				prom_printf("\tsuspending %s@%s\n", d_name,
392 				    d_info);
393 			}
394 		} else {
395 			prom_printf("\tsuspending %s@%s\n", dname, d_info);
396 		}
397 
398 		if (devi_detach(dip, DDI_SUSPEND) != DDI_SUCCESS) {
399 			prom_printf("\tFAILED to suspend %s@%s\n",
400 			    d_name[0] ? d_name : dname, d_info);
401 
402 			srh->sr_err_idx = dr_add_int(srh->sr_err_ints,
403 			    srh->sr_err_idx, DR_MAX_ERR_INT, (uint64_t)major);
404 
405 			ndi_hold_devi(dip);
406 			srh->sr_failed_dip = dip;
407 
408 			handle = srh->sr_dr_handlep;
409 			dr_op_err(CE_IGNORE, handle, ESBD_SUSPEND, "%s@%s",
410 			    d_name[0] ? d_name : dname, d_info);
411 
412 			return (DDI_FAILURE);
413 		}
414 	}
415 
416 	return (DDI_SUCCESS);
417 }
418 
419 static void
420 dr_resume_devices(dev_info_t *start, dr_sr_handle_t *srh)
421 {
422 	dr_handle_t	*handle;
423 	dev_info_t	*dip, *next, *last = NULL;
424 	major_t		major;
425 	char		*bn;
426 	int		circ;
427 
428 	major = (major_t)-1;
429 
430 	/* attach in reverse device tree order */
431 	while (last != start) {
432 		dip = start;
433 		next = ddi_get_next_sibling(dip);
434 		while (next != last && dip != srh->sr_failed_dip) {
435 			dip = next;
436 			next = ddi_get_next_sibling(dip);
437 		}
438 		if (dip == srh->sr_failed_dip) {
439 			/* release hold acquired in dr_suspend_devices() */
440 			srh->sr_failed_dip = NULL;
441 			ndi_rele_devi(dip);
442 		} else if (dr_is_real_device(dip) &&
443 		    srh->sr_failed_dip == NULL) {
444 
445 			if ((bn = ddi_binding_name(dip)) != NULL) {
446 				major = ddi_name_to_major(bn);
447 			} else {
448 				bn = "<null>";
449 			}
450 			if (!dr_bypass_device(bn) &&
451 			    !drmach_verify_sr(dip, 0)) {
452 				char	d_name[40], d_alias[40], *d_info;
453 
454 				d_name[0] = 0;
455 				d_info = ddi_get_name_addr(dip);
456 				if (d_info == NULL)
457 					d_info = "<null>";
458 
459 				if (!dr_resolve_devname(dip, d_name, d_alias)) {
460 					if (d_alias[0] != 0) {
461 						prom_printf("\tresuming "
462 						    "%s@%s (aka %s)\n", d_name,
463 						    d_info, d_alias);
464 					} else {
465 						prom_printf("\tresuming "
466 						    "%s@%s\n", d_name, d_info);
467 					}
468 				} else {
469 					prom_printf("\tresuming %s@%s\n", bn,
470 					    d_info);
471 				}
472 
473 				if (devi_attach(dip, DDI_RESUME) !=
474 				    DDI_SUCCESS) {
475 					/*
476 					 * Print a console warning,
477 					 * set an e_code of ESBD_RESUME,
478 					 * and save the driver major
479 					 * number in the e_rsc.
480 					 */
481 					prom_printf("\tFAILED to resume %s@%s",
482 					    d_name[0] ? d_name : bn, d_info);
483 
484 					srh->sr_err_idx =
485 					    dr_add_int(srh->sr_err_ints,
486 					    srh->sr_err_idx, DR_MAX_ERR_INT,
487 					    (uint64_t)major);
488 
489 					handle = srh->sr_dr_handlep;
490 
491 					dr_op_err(CE_IGNORE, handle,
492 					    ESBD_RESUME, "%s@%s",
493 					    d_name[0] ? d_name : bn, d_info);
494 				}
495 			}
496 		}
497 
498 		/* Hold parent busy while walking its children */
499 		ndi_devi_enter(dip, &circ);
500 		dr_resume_devices(ddi_get_child(dip), srh);
501 		ndi_devi_exit(dip, circ);
502 		last = dip;
503 	}
504 }
505 
506 /*
507  * True if thread is virtually stopped.  Similar to CPR_VSTOPPED
508  * but from DR point of view.  These user threads are waiting in
509  * the kernel.  Once they complete in the kernel, they will process
510  * the stop signal and stop.
511  */
512 #define	DR_VSTOPPED(t)			\
513 	((t)->t_state == TS_SLEEP &&	\
514 	(t)->t_wchan != NULL &&		\
515 	(t)->t_astflag &&		\
516 	((t)->t_proc_flag & TP_CHKPT))
517 
518 /* ARGSUSED */
519 static int
520 dr_stop_user_threads(dr_sr_handle_t *srh)
521 {
522 	int		count;
523 	int		bailout;
524 	dr_handle_t	*handle = srh->sr_dr_handlep;
525 	static fn_t	f = "dr_stop_user_threads";
526 	kthread_id_t 	tp;
527 
528 	extern void add_one_utstop();
529 	extern void utstop_timedwait(clock_t);
530 	extern void utstop_init(void);
531 
532 #define	DR_UTSTOP_RETRY	4
533 #define	DR_UTSTOP_WAIT	hz
534 
535 	if (dr_skip_user_threads)
536 		return (DDI_SUCCESS);
537 
538 	utstop_init();
539 
540 	/* we need to try a few times to get past fork, etc. */
541 	srh->sr_err_idx = 0;
542 	for (count = 0; count < DR_UTSTOP_RETRY; count++) {
543 		/* walk the entire threadlist */
544 		mutex_enter(&pidlock);
545 		for (tp = curthread->t_next; tp != curthread; tp = tp->t_next) {
546 			proc_t *p = ttoproc(tp);
547 
548 			/* handle kernel threads separately */
549 			if (p->p_as == &kas || p->p_stat == SZOMB)
550 				continue;
551 
552 			mutex_enter(&p->p_lock);
553 			thread_lock(tp);
554 
555 			if (tp->t_state == TS_STOPPED) {
556 				/* add another reason to stop this thread */
557 				tp->t_schedflag &= ~TS_RESUME;
558 			} else {
559 				tp->t_proc_flag |= TP_CHKPT;
560 
561 				thread_unlock(tp);
562 				mutex_exit(&p->p_lock);
563 				add_one_utstop();
564 				mutex_enter(&p->p_lock);
565 				thread_lock(tp);
566 
567 				aston(tp);
568 
569 				if (ISWAKEABLE(tp) || ISWAITING(tp)) {
570 					setrun_locked(tp);
571 				}
572 
573 			}
574 
575 			/* grab thread if needed */
576 			if (tp->t_state == TS_ONPROC && tp->t_cpu != CPU)
577 				poke_cpu(tp->t_cpu->cpu_id);
578 
579 
580 			thread_unlock(tp);
581 			mutex_exit(&p->p_lock);
582 		}
583 		mutex_exit(&pidlock);
584 
585 
586 		/* let everything catch up */
587 		utstop_timedwait(count * count * DR_UTSTOP_WAIT);
588 
589 
590 		/* now, walk the threadlist again to see if we are done */
591 		mutex_enter(&pidlock);
592 		for (tp = curthread->t_next, bailout = 0;
593 		    tp != curthread; tp = tp->t_next) {
594 			proc_t *p = ttoproc(tp);
595 
596 			/* handle kernel threads separately */
597 			if (p->p_as == &kas || p->p_stat == SZOMB)
598 				continue;
599 
600 			/*
601 			 * If this thread didn't stop, and we don't allow
602 			 * unstopped blocked threads, bail.
603 			 */
604 			thread_lock(tp);
605 			if (!CPR_ISTOPPED(tp) &&
606 			    !(dr_allow_blocked_threads &&
607 			    DR_VSTOPPED(tp))) {
608 				bailout = 1;
609 				if (count == DR_UTSTOP_RETRY - 1) {
610 					/*
611 					 * save the pid for later reporting
612 					 */
613 					srh->sr_err_idx =
614 					    dr_add_int(srh->sr_err_ints,
615 					    srh->sr_err_idx, DR_MAX_ERR_INT,
616 					    (uint64_t)p->p_pid);
617 
618 					cmn_err(CE_WARN, "%s: "
619 					    "failed to stop thread: "
620 					    "process=%s, pid=%d",
621 					    f, p->p_user.u_psargs, p->p_pid);
622 
623 					PR_QR("%s: failed to stop thread: "
624 					    "process=%s, pid=%d, t_id=0x%p, "
625 					    "t_state=0x%x, t_proc_flag=0x%x, "
626 					    "t_schedflag=0x%x\n",
627 					    f, p->p_user.u_psargs, p->p_pid,
628 					    (void *)tp, tp->t_state,
629 					    tp->t_proc_flag, tp->t_schedflag);
630 				}
631 
632 			}
633 			thread_unlock(tp);
634 		}
635 		mutex_exit(&pidlock);
636 
637 		/* were all the threads stopped? */
638 		if (!bailout)
639 			break;
640 	}
641 
642 	/* were we unable to stop all threads after a few tries? */
643 	if (bailout) {
644 		handle->h_err = drerr_int(ESBD_UTHREAD, srh->sr_err_ints,
645 		    srh->sr_err_idx, 0);
646 		return (ESRCH);
647 	}
648 
649 	return (DDI_SUCCESS);
650 }
651 
652 static void
653 dr_start_user_threads(void)
654 {
655 	kthread_id_t tp;
656 
657 	mutex_enter(&pidlock);
658 
659 	/* walk all threads and release them */
660 	for (tp = curthread->t_next; tp != curthread; tp = tp->t_next) {
661 		proc_t *p = ttoproc(tp);
662 
663 		/* skip kernel threads */
664 		if (ttoproc(tp)->p_as == &kas)
665 			continue;
666 
667 		mutex_enter(&p->p_lock);
668 		tp->t_proc_flag &= ~TP_CHKPT;
669 		mutex_exit(&p->p_lock);
670 
671 		thread_lock(tp);
672 		if (CPR_ISTOPPED(tp)) {
673 			/* back on the runq */
674 			tp->t_schedflag |= TS_RESUME;
675 			setrun_locked(tp);
676 		}
677 		thread_unlock(tp);
678 	}
679 
680 	mutex_exit(&pidlock);
681 }
682 
683 static void
684 dr_signal_user(int sig)
685 {
686 	struct proc *p;
687 
688 	mutex_enter(&pidlock);
689 
690 	for (p = practive; p != NULL; p = p->p_next) {
691 		/* only user threads */
692 		if (p->p_exec == NULL || p->p_stat == SZOMB ||
693 		    p == proc_init || p == ttoproc(curthread))
694 			continue;
695 
696 		mutex_enter(&p->p_lock);
697 		sigtoproc(p, NULL, sig);
698 		mutex_exit(&p->p_lock);
699 	}
700 
701 	mutex_exit(&pidlock);
702 
703 	/* add a bit of delay */
704 	delay(hz);
705 }
706 
707 void
708 dr_resume(dr_sr_handle_t *srh)
709 {
710 	dr_handle_t	*handle;
711 
712 	handle = srh->sr_dr_handlep;
713 
714 	switch (srh->sr_suspend_state) {
715 	case DR_SRSTATE_FULL:
716 
717 		ASSERT(MUTEX_HELD(&cpu_lock));
718 
719 		/*
720 		 * Prevent false alarm in tod_validate() due to tod
721 		 * value change between suspend and resume
722 		 */
723 		mutex_enter(&tod_lock);
724 		tod_status_set(TOD_DR_RESUME_DONE);
725 		mutex_exit(&tod_lock);
726 
727 		dr_enable_intr(); 	/* enable intr & clock */
728 
729 		start_cpus();
730 		mutex_exit(&cpu_lock);
731 
732 		/*
733 		 * This should only be called if drmach_suspend_last()
734 		 * was called and state transitioned to DR_SRSTATE_FULL
735 		 * to prevent resume attempts on device instances that
736 		 * were not previously suspended.
737 		 */
738 		drmach_resume_first();
739 
740 		/* FALLTHROUGH */
741 
742 	case DR_SRSTATE_DRIVER:
743 		/*
744 		 * resume drivers
745 		 */
746 		srh->sr_err_idx = 0;
747 
748 		/* no parent dip to hold busy */
749 		dr_resume_devices(ddi_root_node(), srh);
750 
751 		if (srh->sr_err_idx && srh->sr_dr_handlep) {
752 			(srh->sr_dr_handlep)->h_err = drerr_int(ESBD_RESUME,
753 			    srh->sr_err_ints, srh->sr_err_idx, 1);
754 		}
755 
756 		/*
757 		 * resume the lock manager
758 		 */
759 		lm_cprresume();
760 
761 		/* FALLTHROUGH */
762 
763 	case DR_SRSTATE_USER:
764 		/*
765 		 * finally, resume user threads
766 		 */
767 		if (!dr_skip_user_threads) {
768 			prom_printf("DR: resuming user threads...\n");
769 			dr_start_user_threads();
770 		}
771 		/* FALLTHROUGH */
772 
773 	case DR_SRSTATE_BEGIN:
774 	default:
775 		/*
776 		 * let those who care know that we've just resumed
777 		 */
778 		PR_QR("sending SIGTHAW...\n");
779 		dr_signal_user(SIGTHAW);
780 		break;
781 	}
782 
783 	i_ndi_allow_device_tree_changes(handle->h_ndi);
784 
785 	prom_printf("DR: resume COMPLETED\n");
786 }
787 
788 int
789 dr_suspend(dr_sr_handle_t *srh)
790 {
791 	dr_handle_t	*handle;
792 	int		force;
793 	int		dev_errs_idx;
794 	uint64_t	dev_errs[DR_MAX_ERR_INT];
795 	int		rc = DDI_SUCCESS;
796 
797 	handle = srh->sr_dr_handlep;
798 
799 	force = dr_cmd_flags(handle) & SBD_FLAG_FORCE;
800 
801 	i_ndi_block_device_tree_changes(&handle->h_ndi);
802 
803 	prom_printf("\nDR: suspending user threads...\n");
804 	srh->sr_suspend_state = DR_SRSTATE_USER;
805 	if (((rc = dr_stop_user_threads(srh)) != DDI_SUCCESS) &&
806 	    dr_check_user_stop_result) {
807 		dr_resume(srh);
808 		return (rc);
809 	}
810 
811 	if (!force) {
812 		struct dr_ref drc = {0};
813 
814 		prom_printf("\nDR: checking devices...\n");
815 		dev_errs_idx = 0;
816 
817 		drc.arr = dev_errs;
818 		drc.idx = &dev_errs_idx;
819 		drc.len = DR_MAX_ERR_INT;
820 
821 		/*
822 		 * Since the root node can never go away, it
823 		 * doesn't have to be held.
824 		 */
825 		ddi_walk_devs(ddi_root_node(), dr_check_unsafe_major, &drc);
826 		if (dev_errs_idx) {
827 			handle->h_err = drerr_int(ESBD_UNSAFE, dev_errs,
828 			    dev_errs_idx, 1);
829 			dr_resume(srh);
830 			return (DDI_FAILURE);
831 		}
832 		PR_QR("done\n");
833 	} else {
834 		prom_printf("\nDR: dr_suspend invoked with force flag\n");
835 	}
836 
837 #ifndef	SKIP_SYNC
838 	/*
839 	 * This sync swap out all user pages
840 	 */
841 	vfs_sync(SYNC_ALL);
842 #endif
843 
844 	/*
845 	 * special treatment for lock manager
846 	 */
847 	lm_cprsuspend();
848 
849 #ifndef	SKIP_SYNC
850 	/*
851 	 * sync the file system in case we never make it back
852 	 */
853 	sync();
854 #endif
855 
856 	/*
857 	 * now suspend drivers
858 	 */
859 	prom_printf("DR: suspending drivers...\n");
860 	srh->sr_suspend_state = DR_SRSTATE_DRIVER;
861 	srh->sr_err_idx = 0;
862 	/* No parent to hold busy */
863 	if ((rc = dr_suspend_devices(ddi_root_node(), srh)) != DDI_SUCCESS) {
864 		if (srh->sr_err_idx && srh->sr_dr_handlep) {
865 			(srh->sr_dr_handlep)->h_err = drerr_int(ESBD_SUSPEND,
866 			    srh->sr_err_ints, srh->sr_err_idx, 1);
867 		}
868 		dr_resume(srh);
869 		return (rc);
870 	}
871 
872 	drmach_suspend_last();
873 
874 	/*
875 	 * finally, grab all cpus
876 	 */
877 	srh->sr_suspend_state = DR_SRSTATE_FULL;
878 
879 	mutex_enter(&cpu_lock);
880 	pause_cpus(NULL);
881 	dr_stop_intr();
882 
883 	return (rc);
884 }
885 
886 int
887 dr_pt_test_suspend(dr_handle_t *hp)
888 {
889 	dr_sr_handle_t *srh;
890 	int		err;
891 	uint_t		psmerr;
892 	static fn_t	f = "dr_pt_test_suspend";
893 
894 	PR_QR("%s...\n", f);
895 
896 	srh = dr_get_sr_handle(hp);
897 	if ((err = dr_suspend(srh)) == DDI_SUCCESS) {
898 		dr_resume(srh);
899 		if ((hp->h_err) && ((psmerr = hp->h_err->e_code) != 0)) {
900 			PR_QR("%s: error on dr_resume()", f);
901 			switch (psmerr) {
902 			case ESBD_RESUME:
903 				PR_QR("Couldn't resume devices: %s\n",
904 				    DR_GET_E_RSC(hp->h_err));
905 				break;
906 
907 			case ESBD_KTHREAD:
908 				PR_ALL("psmerr is ESBD_KTHREAD\n");
909 				break;
910 			default:
911 				PR_ALL("Resume error unknown = %d\n", psmerr);
912 				break;
913 			}
914 		}
915 	} else {
916 		PR_ALL("%s: dr_suspend() failed, err = 0x%x\n", f, err);
917 		psmerr = hp->h_err ? hp->h_err->e_code : ESBD_NOERROR;
918 		switch (psmerr) {
919 		case ESBD_UNSAFE:
920 			PR_ALL("Unsafe devices (major #): %s\n",
921 			    DR_GET_E_RSC(hp->h_err));
922 			break;
923 
924 		case ESBD_RTTHREAD:
925 			PR_ALL("RT threads (PIDs): %s\n",
926 			    DR_GET_E_RSC(hp->h_err));
927 			break;
928 
929 		case ESBD_UTHREAD:
930 			PR_ALL("User threads (PIDs): %s\n",
931 			    DR_GET_E_RSC(hp->h_err));
932 			break;
933 
934 		case ESBD_SUSPEND:
935 			PR_ALL("Non-suspendable devices (major #): %s\n",
936 			    DR_GET_E_RSC(hp->h_err));
937 			break;
938 
939 		case ESBD_RESUME:
940 			PR_ALL("Could not resume devices (major #): %s\n",
941 			    DR_GET_E_RSC(hp->h_err));
942 			break;
943 
944 		case ESBD_KTHREAD:
945 			PR_ALL("psmerr is ESBD_KTHREAD\n");
946 			break;
947 
948 		case ESBD_NOERROR:
949 			PR_ALL("sbd_error_t error code not set\n");
950 			break;
951 
952 		default:
953 			PR_ALL("Unknown error psmerr = %d\n", psmerr);
954 			break;
955 		}
956 	}
957 	dr_release_sr_handle(srh);
958 
959 	return (0);
960 }
961 
962 /*
963  * Add a new integer value to the end of an array.  Don't allow duplicates to
964  * appear in the array, and don't allow the array to overflow.  Return the new
965  * total number of entries in the array.
966  */
967 static int
968 dr_add_int(uint64_t *arr, int idx, int len, uint64_t val)
969 {
970 	int i;
971 
972 	if (arr == NULL)
973 		return (0);
974 
975 	if (idx >= len)
976 		return (idx);
977 
978 	for (i = 0; i < idx; i++) {
979 		if (arr[i] == val)
980 			return (idx);
981 	}
982 
983 	arr[idx++] = val;
984 
985 	return (idx);
986 }
987 
988 /*
989  * Construct an sbd_error_t featuring a string representation of an array of
990  * integers as its e_rsc.
991  */
992 static sbd_error_t *
993 drerr_int(int e_code, uint64_t *arr, int idx, int majors)
994 {
995 	int		i, n, buf_len, buf_idx, buf_avail;
996 	char		*dname;
997 	char		*buf;
998 	sbd_error_t	*new_sbd_err;
999 	static char	s_ellipsis[] = "...";
1000 
1001 	if (arr == NULL || idx <= 0)
1002 		return (NULL);
1003 
1004 	/* MAXPATHLEN is the size of the e_rsc field in sbd_error_t. */
1005 	buf = (char *)kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1006 
1007 	/*
1008 	 * This is the total working area of the buffer.  It must be computed
1009 	 * as the size of 'buf', minus reserved space for the null terminator
1010 	 * and the ellipsis string.
1011 	 */
1012 	buf_len = MAXPATHLEN - (strlen(s_ellipsis) + 1);
1013 
1014 	/* Construct a string representation of the array values */
1015 	for (buf_idx = 0, i = 0; i < idx; i++) {
1016 		buf_avail = buf_len - buf_idx;
1017 		if (majors) {
1018 			dname = ddi_major_to_name(arr[i]);
1019 			if (dname) {
1020 				n = snprintf(&buf[buf_idx], buf_avail, "%s, ",
1021 				    dname);
1022 			} else {
1023 				n = snprintf(&buf[buf_idx], buf_avail,
1024 				    "major %" PRIu64 ", ", arr[i]);
1025 			}
1026 		} else {
1027 			n = snprintf(&buf[buf_idx], buf_avail, "%" PRIu64 ", ",
1028 			    arr[i]);
1029 		}
1030 
1031 		/* An ellipsis gets appended when no more values fit */
1032 		if (n >= buf_avail) {
1033 			(void) strcpy(&buf[buf_idx], s_ellipsis);
1034 			break;
1035 		}
1036 
1037 		buf_idx += n;
1038 	}
1039 
1040 	/* If all the contents fit, remove the trailing comma */
1041 	if (n < buf_avail) {
1042 		buf[--buf_idx] = '\0';
1043 		buf[--buf_idx] = '\0';
1044 	}
1045 
1046 	/* Return an sbd_error_t with the buffer and e_code */
1047 	new_sbd_err = drerr_new(1, e_code, buf);
1048 	kmem_free(buf, MAXPATHLEN);
1049 	return (new_sbd_err);
1050 }
1051