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