Print this page
XXXX introduce drv_sectohz
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/sun4v/io/platsvc.c
+++ new/usr/src/uts/sun4v/io/platsvc.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) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25
26 26 /*
27 27 * sun4v Platform Services Module
28 28 */
29 29
30 30 #include <sys/modctl.h>
31 31 #include <sys/cmn_err.h>
32 32 #include <sys/machsystm.h>
33 33 #include <sys/note.h>
34 34 #include <sys/uadmin.h>
35 35 #include <sys/ds.h>
36 36 #include <sys/platsvc.h>
37 37 #include <sys/ddi.h>
38 38 #include <sys/suspend.h>
39 39 #include <sys/proc.h>
40 40 #include <sys/disp.h>
41 41 #include <sys/drctl.h>
42 42
43 43 /*
44 44 * Debugging routines
45 45 */
46 46 #ifdef DEBUG
47 47 uint_t ps_debug = 0x0;
48 48 #define DBG if (ps_debug) printf
↓ open down ↓ |
48 lines elided |
↑ open up ↑ |
49 49 #else /* DEBUG */
50 50 #define DBG _NOTE(CONSTCOND) if (0) printf
51 51 #endif /* DEBUG */
52 52
53 53 /*
54 54 * Time resolution conversions.
55 55 */
56 56 #define MS2NANO(x) ((x) * MICROSEC)
57 57 #define MS2SEC(x) ((x) / MILLISEC)
58 58 #define MS2MIN(x) (MS2SEC(x) / 60)
59 -#define SEC2HZ(x) (drv_usectohz((x) * MICROSEC))
59 +#define SEC2HZ(x) drv_sectohz(x)
60 60
61 61 /*
62 62 * Domains Services interaction
63 63 */
64 64 static ds_svc_hdl_t ds_md_handle;
65 65 static ds_svc_hdl_t ds_shutdown_handle;
66 66 static ds_svc_hdl_t ds_panic_handle;
67 67 static ds_svc_hdl_t ds_suspend_handle;
68 68
69 69 static ds_ver_t ps_vers[] = {{ 1, 0 }};
70 70 #define PS_NVERS (sizeof (ps_vers) / sizeof (ps_vers[0]))
71 71
72 72 static ds_capability_t ps_md_cap = {
73 73 "md-update", /* svc_id */
74 74 ps_vers, /* vers */
75 75 PS_NVERS /* nvers */
76 76 };
77 77
78 78 static ds_capability_t ps_shutdown_cap = {
79 79 "domain-shutdown", /* svc_id */
80 80 ps_vers, /* vers */
81 81 PS_NVERS /* nvers */
82 82 };
83 83
84 84 static ds_capability_t ps_panic_cap = {
85 85 "domain-panic", /* svc_id */
86 86 ps_vers, /* vers */
87 87 PS_NVERS /* nvers */
88 88 };
89 89
90 90 static ds_capability_t ps_suspend_cap = {
91 91 "domain-suspend", /* svc_id */
92 92 ps_vers, /* vers */
93 93 PS_NVERS /* nvers */
94 94 };
95 95
96 96 static void ps_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl);
97 97 static void ps_unreg_handler(ds_cb_arg_t arg);
98 98
99 99 static void ps_md_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
100 100 static void ps_shutdown_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
101 101 static void ps_panic_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
102 102 static void ps_suspend_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
103 103
104 104 static ds_clnt_ops_t ps_md_ops = {
105 105 ps_reg_handler, /* ds_reg_cb */
106 106 ps_unreg_handler, /* ds_unreg_cb */
107 107 ps_md_data_handler, /* ds_data_cb */
108 108 &ds_md_handle /* cb_arg */
109 109 };
110 110
111 111 static ds_clnt_ops_t ps_shutdown_ops = {
112 112 ps_reg_handler, /* ds_reg_cb */
113 113 ps_unreg_handler, /* ds_unreg_cb */
114 114 ps_shutdown_data_handler, /* ds_data_cb */
115 115 &ds_shutdown_handle /* cb_arg */
116 116 };
117 117
118 118 static ds_clnt_ops_t ps_panic_ops = {
119 119 ps_reg_handler, /* ds_reg_cb */
120 120 ps_unreg_handler, /* ds_unreg_cb */
121 121 ps_panic_data_handler, /* ds_data_cb */
122 122 &ds_panic_handle /* cb_arg */
123 123 };
124 124
125 125 static ds_clnt_ops_t ps_suspend_ops = {
126 126 ps_reg_handler, /* ds_reg_cb */
127 127 ps_unreg_handler, /* ds_unreg_cb */
128 128 ps_suspend_data_handler, /* ds_data_cb */
129 129 &ds_suspend_handle /* cb_arg */
130 130 };
131 131
132 132 static int ps_init(void);
133 133 static void ps_fini(void);
134 134
135 135 /*
136 136 * Power down timeout value of 5 minutes.
137 137 */
138 138 #define PLATSVC_POWERDOWN_DELAY 1200
139 139
140 140 /*
141 141 * Set to true if OS suspend is supported. If OS suspend is not
142 142 * supported, the suspend service will not be started.
143 143 */
144 144 static boolean_t ps_suspend_enabled = B_FALSE;
145 145
146 146 /*
147 147 * Suspend service request handling
148 148 */
149 149 typedef struct ps_suspend_data {
150 150 void *buf;
151 151 size_t buflen;
152 152 } ps_suspend_data_t;
153 153
154 154 static kmutex_t ps_suspend_mutex;
155 155 static kcondvar_t ps_suspend_cv;
156 156
157 157 static ps_suspend_data_t *ps_suspend_data = NULL;
158 158 static boolean_t ps_suspend_thread_exit = B_FALSE;
159 159 static kthread_t *ps_suspend_thread = NULL;
160 160
161 161 static void ps_suspend_sequence(ps_suspend_data_t *data);
162 162 static void ps_suspend_thread_func(void);
163 163
164 164 /*
165 165 * The DELAY timeout is the time (in seconds) to wait for the
166 166 * suspend service to be re-registered after a suspend/resume
167 167 * operation. The INTVAL time is the time (in seconds) to wait
168 168 * between retry attempts when sending the post-suspend message
169 169 * after a suspend/resume operation.
170 170 */
171 171 #define PLATSVC_SUSPEND_REREG_DELAY 60
172 172 #define PLATSVC_SUSPEND_RETRY_INTVAL 1
173 173 static int ps_suspend_rereg_delay = PLATSVC_SUSPEND_REREG_DELAY;
174 174 static int ps_suspend_retry_intval = PLATSVC_SUSPEND_RETRY_INTVAL;
175 175
176 176
177 177 static struct modlmisc modlmisc = {
178 178 &mod_miscops,
179 179 "sun4v Platform Services"
180 180 };
181 181
182 182 static struct modlinkage modlinkage = {
183 183 MODREV_1,
184 184 (void *)&modlmisc,
185 185 NULL
186 186 };
187 187
188 188 int
189 189 _init(void)
190 190 {
191 191 int rv;
192 192
193 193 if ((rv = ps_init()) != 0)
194 194 return (rv);
195 195
196 196 if ((rv = mod_install(&modlinkage)) != 0)
197 197 ps_fini();
198 198
199 199 return (rv);
200 200 }
201 201
202 202 int
203 203 _info(struct modinfo *modinfop)
204 204 {
205 205 return (mod_info(&modlinkage, modinfop));
206 206 }
207 207
208 208 int platsvc_allow_unload;
209 209
210 210 int
211 211 _fini(void)
212 212 {
213 213 int status;
214 214
215 215 if (platsvc_allow_unload == 0)
216 216 return (EBUSY);
217 217
218 218 if ((status = mod_remove(&modlinkage)) == 0)
219 219 ps_fini();
220 220
221 221 return (status);
222 222 }
223 223
224 224 static int
225 225 ps_init(void)
226 226 {
227 227 int rv;
228 228 extern int mdeg_init(void);
229 229 extern void mdeg_fini(void);
230 230
231 231 /* register with domain services framework */
232 232 rv = ds_cap_init(&ps_md_cap, &ps_md_ops);
233 233 if (rv != 0) {
234 234 cmn_err(CE_WARN, "ds_cap_init md-update failed: %d", rv);
235 235 return (rv);
236 236 }
237 237
238 238 rv = mdeg_init();
239 239 if (rv != 0) {
240 240 (void) ds_cap_fini(&ps_md_cap);
241 241 return (rv);
242 242 }
243 243
244 244 rv = ds_cap_init(&ps_shutdown_cap, &ps_shutdown_ops);
245 245 if (rv != 0) {
246 246 cmn_err(CE_WARN, "ds_cap_init domain-shutdown failed: %d", rv);
247 247 mdeg_fini();
248 248 (void) ds_cap_fini(&ps_md_cap);
249 249 return (rv);
250 250 }
251 251
252 252 rv = ds_cap_init(&ps_panic_cap, &ps_panic_ops);
253 253 if (rv != 0) {
254 254 cmn_err(CE_WARN, "ds_cap_init domain-panic failed: %d", rv);
255 255 (void) ds_cap_fini(&ps_md_cap);
256 256 mdeg_fini();
257 257 (void) ds_cap_fini(&ps_shutdown_cap);
258 258 return (rv);
259 259 }
260 260
261 261 ps_suspend_enabled = suspend_supported();
262 262
263 263 if (ps_suspend_enabled) {
264 264 mutex_init(&ps_suspend_mutex, NULL, MUTEX_DEFAULT, NULL);
265 265 cv_init(&ps_suspend_cv, NULL, CV_DEFAULT, NULL);
266 266 ps_suspend_thread_exit = B_FALSE;
267 267
268 268 rv = ds_cap_init(&ps_suspend_cap, &ps_suspend_ops);
269 269 if (rv != 0) {
270 270 cmn_err(CE_WARN, "ds_cap_init domain-suspend failed: "
271 271 "%d", rv);
272 272 (void) ds_cap_fini(&ps_md_cap);
273 273 mdeg_fini();
274 274 (void) ds_cap_fini(&ps_shutdown_cap);
275 275 (void) ds_cap_fini(&ps_panic_cap);
276 276 mutex_destroy(&ps_suspend_mutex);
277 277 cv_destroy(&ps_suspend_cv);
278 278 return (rv);
279 279 }
280 280
281 281 ps_suspend_thread = thread_create(NULL, 2 * DEFAULTSTKSZ,
282 282 ps_suspend_thread_func, NULL, 0, &p0, TS_RUN, minclsyspri);
283 283 }
284 284
285 285 return (0);
286 286 }
287 287
288 288 static void
289 289 ps_fini(void)
290 290 {
291 291 extern void mdeg_fini(void);
292 292
293 293 /*
294 294 * Stop incoming requests from Zeus
295 295 */
296 296 (void) ds_cap_fini(&ps_md_cap);
297 297 (void) ds_cap_fini(&ps_shutdown_cap);
298 298 (void) ds_cap_fini(&ps_panic_cap);
299 299
300 300 if (ps_suspend_enabled) {
301 301 (void) ds_cap_fini(&ps_suspend_cap);
302 302 if (ps_suspend_thread != NULL) {
303 303 mutex_enter(&ps_suspend_mutex);
304 304 ps_suspend_thread_exit = B_TRUE;
305 305 cv_signal(&ps_suspend_cv);
306 306 mutex_exit(&ps_suspend_mutex);
307 307
308 308 thread_join(ps_suspend_thread->t_did);
309 309 ps_suspend_thread = NULL;
310 310
311 311 mutex_destroy(&ps_suspend_mutex);
312 312 cv_destroy(&ps_suspend_cv);
313 313 }
314 314 }
315 315
316 316 mdeg_fini();
317 317 }
318 318
319 319 static void
320 320 ps_md_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
321 321 {
322 322 extern int mach_descrip_update(void);
323 323 extern void mdeg_notify_clients(void);
324 324 extern void recalc_xc_timeouts(void);
325 325
326 326 ds_svc_hdl_t ds_handle = ds_md_handle;
327 327 platsvc_md_update_req_t *msg = buf;
328 328 platsvc_md_update_resp_t resp_msg;
329 329 uint_t rv;
330 330
331 331 if (arg == NULL)
332 332 return;
333 333
334 334 if (ds_handle == DS_INVALID_HDL) {
335 335 DBG("ps_md_data_handler: DS handle no longer valid\n");
336 336 return;
337 337 }
338 338
339 339 if (msg == NULL || buflen != sizeof (platsvc_md_update_req_t)) {
340 340 resp_msg.req_num = 0;
341 341 resp_msg.result = MD_UPDATE_INVALID_MSG;
342 342 if ((rv = ds_cap_send(ds_handle, &resp_msg,
343 343 sizeof (resp_msg))) != 0) {
344 344 cmn_err(CE_NOTE, "md ds_cap_send failed (%d)", rv);
345 345 }
346 346 return;
347 347 }
348 348
349 349 DBG("MD Reload...\n");
350 350 if (mach_descrip_update()) {
351 351 cmn_err(CE_WARN, "MD reload failed\n");
352 352 return;
353 353 }
354 354
355 355 recalc_xc_timeouts();
356 356
357 357 /*
358 358 * notify registered clients that MD has
359 359 * been updated
360 360 */
361 361 mdeg_notify_clients();
362 362
363 363 resp_msg.req_num = msg->req_num;
364 364 resp_msg.result = MD_UPDATE_SUCCESS;
365 365 if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) {
366 366 cmn_err(CE_NOTE, "md ds_cap_send resp failed (%d)", rv);
367 367 }
368 368 }
369 369
370 370 static void
371 371 ps_shutdown_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
372 372 {
373 373 ds_svc_hdl_t ds_handle = ds_shutdown_handle;
374 374 platsvc_shutdown_req_t *msg = buf;
375 375 platsvc_shutdown_resp_t resp_msg;
376 376 uint_t rv;
377 377 hrtime_t start;
378 378
379 379 if (arg == NULL)
380 380 return;
381 381
382 382 if (ds_handle == DS_INVALID_HDL) {
383 383 DBG("ps_shutdown_data_handler: DS handle no longer valid\n");
384 384 return;
385 385 }
386 386
387 387 if (msg == NULL || buflen != sizeof (platsvc_shutdown_req_t)) {
388 388 resp_msg.req_num = 0;
389 389 resp_msg.result = DOMAIN_SHUTDOWN_INVALID_MSG;
390 390 resp_msg.reason[0] = '\0';
391 391 if ((rv = ds_cap_send(ds_handle, &resp_msg,
392 392 sizeof (resp_msg))) != 0) {
393 393 cmn_err(CE_NOTE, "shutdown ds_cap_send failed (%d)",
394 394 rv);
395 395 }
396 396 return;
397 397 }
398 398
399 399 resp_msg.req_num = msg->req_num;
400 400 resp_msg.result = DOMAIN_SHUTDOWN_SUCCESS;
401 401 resp_msg.reason[0] = '\0';
402 402
403 403 if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) {
404 404 cmn_err(CE_NOTE, "shutdown ds_cap_send resp failed (%d)", rv);
405 405 }
406 406
407 407 /*
408 408 * Honor the ldoms manager's shutdown delay requirement.
409 409 */
410 410 cmn_err(CE_NOTE, "shutdown requested by ldom manager, "
411 411 "system shutdown in %d minutes", MS2MIN(msg->delay));
412 412
413 413 start = gethrtime();
414 414 while (gethrtime() - start < MS2NANO(msg->delay))
415 415 ;
416 416
417 417 (void) kadmin(A_SHUTDOWN, AD_POWEROFF, NULL, kcred);
418 418 }
419 419
420 420
421 421 static void
422 422 ps_panic_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
423 423 {
424 424 ds_svc_hdl_t ds_handle = ds_panic_handle;
425 425 platsvc_panic_req_t *msg = buf;
426 426 platsvc_panic_resp_t resp_msg;
427 427 uint_t rv;
428 428
429 429 if (arg == NULL)
430 430 return;
431 431
432 432 if (ds_handle == DS_INVALID_HDL) {
433 433 DBG("ps_panic_data_handler: DS handle no longer valid\n");
434 434 return;
435 435 }
436 436
437 437 if (msg == NULL || buflen != sizeof (platsvc_panic_req_t)) {
438 438 resp_msg.req_num = 0;
439 439 resp_msg.result = DOMAIN_PANIC_INVALID_MSG;
440 440 resp_msg.reason[0] = '\0';
441 441 if ((rv = ds_cap_send(ds_handle, &resp_msg,
442 442 sizeof (resp_msg))) != 0) {
443 443 cmn_err(CE_NOTE, "panic ds_cap_send resp failed (%d)",
444 444 rv);
445 445 }
446 446 return;
447 447 }
448 448
449 449 resp_msg.req_num = msg->req_num;
450 450 resp_msg.result = DOMAIN_PANIC_SUCCESS;
451 451 resp_msg.reason[0] = '\0';
452 452 if ((rv = ds_cap_send(ds_handle, &resp_msg, sizeof (resp_msg))) != 0) {
453 453 cmn_err(CE_NOTE, "panic ds_cap_send resp failed (%d)", rv);
454 454 }
455 455
456 456 cmn_err(CE_PANIC, "Panic forced by ldom manager");
457 457 _NOTE(NOTREACHED)
458 458 }
459 459
460 460 /*
461 461 * Send a suspend response message. If a timeout is specified, wait
462 462 * intval seconds between attempts to send the message. The timeout
463 463 * and intval arguments are in seconds.
464 464 */
465 465 static void
466 466 ps_suspend_send_response(ds_svc_hdl_t *ds_handle, uint64_t req_num,
467 467 uint32_t result, uint32_t rec_result, char *reason, int timeout,
468 468 int intval)
469 469 {
470 470 platsvc_suspend_resp_t *resp;
471 471 size_t reason_length;
472 472 int tries = 0;
473 473 int rv = -1;
474 474 time_t deadline;
475 475
476 476 if (reason == NULL) {
477 477 reason_length = 0;
478 478 } else {
479 479 /* Get number of non-NULL bytes */
480 480 reason_length = strnlen(reason, SUSPEND_MAX_REASON_SIZE - 1);
481 481 ASSERT(reason[reason_length] == '\0');
482 482 /* Account for NULL terminator */
483 483 reason_length++;
484 484 }
485 485
486 486 resp = (platsvc_suspend_resp_t *)
487 487 kmem_zalloc(sizeof (platsvc_suspend_resp_t) + reason_length,
488 488 KM_SLEEP);
489 489
490 490 resp->req_num = req_num;
491 491 resp->result = result;
492 492 resp->rec_result = rec_result;
493 493 if (reason_length > 0) {
494 494 bcopy(reason, &resp->reason, reason_length - 1);
495 495 /* Ensure NULL terminator is present */
496 496 resp->reason[reason_length] = '\0';
497 497 }
498 498
499 499 if (timeout == 0) {
500 500 tries++;
501 501 rv = ds_cap_send(*ds_handle, resp,
502 502 sizeof (platsvc_suspend_resp_t) + reason_length);
503 503 } else {
504 504 deadline = gethrestime_sec() + timeout;
505 505 do {
506 506 ds_svc_hdl_t hdl;
507 507 /*
508 508 * Copy the handle so we can ensure we never pass
509 509 * an invalid handle to ds_cap_send. We don't want
510 510 * to trigger warning messages just because the
511 511 * service was temporarily unregistered.
512 512 */
513 513 if ((hdl = *ds_handle) == DS_INVALID_HDL) {
514 514 delay(SEC2HZ(intval));
515 515 } else if ((rv = ds_cap_send(hdl, resp,
516 516 sizeof (platsvc_suspend_resp_t) +
517 517 reason_length)) != 0) {
518 518 tries++;
519 519 delay(SEC2HZ(intval));
520 520 }
521 521 } while ((rv != 0) && (gethrestime_sec() < deadline));
522 522 }
523 523
524 524 if (rv != 0) {
525 525 cmn_err(CE_NOTE, "suspend ds_cap_send resp failed (%d) "
526 526 "sending message: %d, attempts: %d", rv, resp->result,
527 527 tries);
528 528 }
529 529
530 530 kmem_free(resp, sizeof (platsvc_suspend_resp_t) + reason_length);
531 531 }
532 532
533 533 /*
534 534 * Handle data coming in for the suspend service. The suspend is
535 535 * sequenced by the ps_suspend_thread, but perform some checks here
536 536 * to make sure that the request is a valid request message and that
537 537 * a suspend operation is not already in progress.
538 538 */
539 539 /*ARGSUSED*/
540 540 static void
541 541 ps_suspend_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
542 542 {
543 543 platsvc_suspend_req_t *msg = buf;
544 544
545 545 if (arg == NULL)
546 546 return;
547 547
548 548 if (ds_suspend_handle == DS_INVALID_HDL) {
549 549 DBG("ps_suspend_data_handler: DS handle no longer valid\n");
550 550 return;
551 551 }
552 552
553 553 /* Handle invalid requests */
554 554 if (msg == NULL || buflen != sizeof (platsvc_suspend_req_t) ||
555 555 msg->type != DOMAIN_SUSPEND_SUSPEND) {
556 556 ps_suspend_send_response(&ds_suspend_handle, msg->req_num,
557 557 DOMAIN_SUSPEND_INVALID_MSG, DOMAIN_SUSPEND_REC_SUCCESS,
558 558 NULL, 0, 0);
559 559 return;
560 560 }
561 561
562 562 /*
563 563 * If ps_suspend_thread_exit is set, ds_cap_fini has been
564 564 * called and we shouldn't be receving data. Handle this unexpected
565 565 * case by returning without sending a response.
566 566 */
567 567 if (ps_suspend_thread_exit) {
568 568 DBG("ps_suspend_data_handler: ps_suspend_thread is exiting\n");
569 569 return;
570 570 }
571 571
572 572 mutex_enter(&ps_suspend_mutex);
573 573
574 574 /* If a suspend operation is in progress, abort now */
575 575 if (ps_suspend_data != NULL) {
576 576 mutex_exit(&ps_suspend_mutex);
577 577 ps_suspend_send_response(&ds_suspend_handle, msg->req_num,
578 578 DOMAIN_SUSPEND_INPROGRESS, DOMAIN_SUSPEND_REC_SUCCESS,
579 579 NULL, 0, 0);
580 580 return;
581 581 }
582 582
583 583 ps_suspend_data = kmem_alloc(sizeof (ps_suspend_data_t), KM_SLEEP);
584 584 ps_suspend_data->buf = kmem_alloc(buflen, KM_SLEEP);
585 585 ps_suspend_data->buflen = buflen;
586 586 bcopy(buf, ps_suspend_data->buf, buflen);
587 587
588 588 cv_signal(&ps_suspend_cv);
589 589 mutex_exit(&ps_suspend_mutex);
590 590 }
591 591
592 592 /*
593 593 * Schedule the suspend operation by calling the pre-suspend, suspend,
594 594 * and post-suspend functions. When sending back response messages, we
595 595 * only use a timeout for the post-suspend response because after
596 596 * a resume, domain services will be re-registered and we may not
597 597 * be able to send the response immediately.
598 598 */
599 599 static void
600 600 ps_suspend_sequence(ps_suspend_data_t *data)
601 601 {
602 602 platsvc_suspend_req_t *msg;
603 603 uint32_t rec_result;
604 604 char *error_reason;
605 605 boolean_t recovered = B_TRUE;
606 606 uint_t rv = 0;
607 607 int dr_block;
608 608
609 609 ASSERT(data != NULL);
610 610
611 611 msg = data->buf;
612 612 error_reason = (char *)kmem_zalloc(SUSPEND_MAX_REASON_SIZE, KM_SLEEP);
613 613
614 614 /*
615 615 * Abort the suspend if a DR operation is in progress. Otherwise,
616 616 * continue whilst blocking any new DR operations.
617 617 */
618 618 if ((dr_block = drctl_tryblock()) == 0) {
619 619 /* Pre-suspend */
620 620 rv = suspend_pre(error_reason, SUSPEND_MAX_REASON_SIZE,
621 621 &recovered);
622 622 } else {
623 623 /* A DR operation is in progress */
624 624 (void) strncpy(error_reason, DOMAIN_SUSPEND_DR_ERROR_STR,
625 625 SUSPEND_MAX_REASON_SIZE);
626 626 }
627 627
628 628 if (dr_block != 0 || rv != 0) {
629 629 rec_result = (recovered ? DOMAIN_SUSPEND_REC_SUCCESS :
630 630 DOMAIN_SUSPEND_REC_FAILURE);
631 631
632 632 ps_suspend_send_response(&ds_suspend_handle, msg->req_num,
633 633 DOMAIN_SUSPEND_PRE_FAILURE, rec_result, error_reason, 0, 0);
634 634
635 635 if (dr_block == 0)
636 636 drctl_unblock();
637 637 kmem_free(error_reason, SUSPEND_MAX_REASON_SIZE);
638 638 return;
639 639 }
640 640
641 641 ps_suspend_send_response(&ds_suspend_handle, msg->req_num,
642 642 DOMAIN_SUSPEND_PRE_SUCCESS, 0, NULL, 0, 0);
643 643
644 644 /* Suspend */
645 645 rv = suspend_start(error_reason, SUSPEND_MAX_REASON_SIZE);
646 646 if (rv != 0) {
647 647 rec_result = (suspend_post(NULL, 0) == 0 ?
648 648 DOMAIN_SUSPEND_REC_SUCCESS : DOMAIN_SUSPEND_REC_FAILURE);
649 649
650 650 ps_suspend_send_response(&ds_suspend_handle, msg->req_num,
651 651 DOMAIN_SUSPEND_SUSPEND_FAILURE, rec_result, error_reason,
652 652 0, 0);
653 653
654 654 drctl_unblock();
655 655 kmem_free(error_reason, SUSPEND_MAX_REASON_SIZE);
656 656 return;
657 657 }
658 658
659 659 /* Post-suspend */
660 660 rv = suspend_post(error_reason, SUSPEND_MAX_REASON_SIZE);
661 661 if (rv != 0) {
662 662 ps_suspend_send_response(&ds_suspend_handle, msg->req_num,
663 663 DOMAIN_SUSPEND_POST_FAILURE, 0, error_reason,
664 664 ps_suspend_rereg_delay, ps_suspend_retry_intval);
665 665 } else {
666 666 ps_suspend_send_response(&ds_suspend_handle, msg->req_num,
667 667 DOMAIN_SUSPEND_POST_SUCCESS, 0, error_reason,
668 668 ps_suspend_rereg_delay, ps_suspend_retry_intval);
669 669 }
670 670
671 671 drctl_unblock();
672 672 kmem_free(error_reason, SUSPEND_MAX_REASON_SIZE);
673 673 }
674 674
675 675 /*
676 676 * Wait for a suspend request or for ps_suspend_thread_exit to be set.
677 677 */
678 678 static void
679 679 ps_suspend_thread_func(void)
680 680 {
681 681 mutex_enter(&ps_suspend_mutex);
682 682
683 683 while (ps_suspend_thread_exit == B_FALSE) {
684 684
685 685 if (ps_suspend_data == NULL) {
686 686 cv_wait(&ps_suspend_cv, &ps_suspend_mutex);
687 687 continue;
688 688 }
689 689
690 690 mutex_exit(&ps_suspend_mutex);
691 691 ps_suspend_sequence(ps_suspend_data);
692 692 mutex_enter(&ps_suspend_mutex);
693 693
694 694 kmem_free(ps_suspend_data->buf, ps_suspend_data->buflen);
695 695 kmem_free(ps_suspend_data, sizeof (ps_suspend_data_t));
696 696 ps_suspend_data = NULL;
697 697 }
698 698
699 699 mutex_exit(&ps_suspend_mutex);
700 700
701 701 thread_exit();
702 702 }
703 703
704 704 static void
705 705 ps_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
706 706 {
707 707 DBG("ps_reg_handler: arg=0x%p, ver=%d.%d, hdl=0x%lx\n",
708 708 arg, ver->major, ver->minor, hdl);
709 709
710 710 if ((ds_svc_hdl_t *)arg == &ds_md_handle)
711 711 ds_md_handle = hdl;
712 712 if ((ds_svc_hdl_t *)arg == &ds_shutdown_handle)
713 713 ds_shutdown_handle = hdl;
714 714 if ((ds_svc_hdl_t *)arg == &ds_panic_handle)
715 715 ds_panic_handle = hdl;
716 716 if ((ds_svc_hdl_t *)arg == &ds_suspend_handle)
717 717 ds_suspend_handle = hdl;
718 718 }
719 719
720 720 static void
721 721 ps_unreg_handler(ds_cb_arg_t arg)
722 722 {
723 723 DBG("ps_unreg_handler: arg=0x%p\n", arg);
724 724
725 725 if ((ds_svc_hdl_t *)arg == &ds_md_handle)
726 726 ds_md_handle = DS_INVALID_HDL;
727 727 if ((ds_svc_hdl_t *)arg == &ds_shutdown_handle)
728 728 ds_shutdown_handle = DS_INVALID_HDL;
729 729 if ((ds_svc_hdl_t *)arg == &ds_panic_handle)
730 730 ds_panic_handle = DS_INVALID_HDL;
731 731 if ((ds_svc_hdl_t *)arg == &ds_suspend_handle)
732 732 ds_suspend_handle = DS_INVALID_HDL;
733 733 }
↓ open down ↓ |
664 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX