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 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <sys/cpuvar.h>
30 #include <sys/cpu_module.h>
31 #include <sys/kmem.h>
32 #include <sys/sunddi.h>
33 #include <sys/param.h>
34 #include <sys/obpdefs.h>
35 #include <sys/prom_plat.h>
36 #include <sys/sgsbbc_mailbox.h>
37 #include <sys/sbd_ioctl.h>
38 #include <sys/sbdp_priv.h>
39 #include <sys/sbdp_mbox.h>
40 #include <sys/promif.h>
41 #include <sys/plat_ecc_dimm.h>
42
43 #define UNKNOWN "unknown"
44 #define INITL_STATUS 0xdead
45
46 int sbdp_mbox_wait = 86400; /* in seconds */
47 int sbdp_shw_bd_wait = 5; /* in seconds */
48
49 int sbdp_sc_err_translation(int);
50 int sbdp_poweroff_wkaround = 1;
51
52 /*
53 * By default, DR of non-Panther procs is not allowed into a Panther
54 * domain with large page sizes enabled. Setting this to 0 will remove
55 * the restriction.
56 */
57 static int sbdp_large_page_restriction = 1;
58
59 /*
60 * Initialize the data structs for the common part of the pkts
61 */
62 void
sbdp_init_msg_pkt(sbbc_msg_t * msg,uint16_t sub_type,int len,caddr_t buf)63 sbdp_init_msg_pkt(sbbc_msg_t *msg, uint16_t sub_type, int len, caddr_t buf)
64 {
65 msg->msg_type.type = DR_MBOX;
66 msg->msg_type.sub_type = sub_type;
67 msg->msg_status = INITL_STATUS;
68 msg->msg_len = len;
69 msg->msg_buf = buf;
70 msg->msg_data[0] = 0;
71 msg->msg_data[1] = 0;
72
73 }
74
75 /*
76 * Convert a showboard data structure to the board structure shared
77 * between sbd and sbdp
78 */
79 void
sbdp_showbd_2_sbd_stat(show_board_t * shbp,sbd_stat_t * stp,int board)80 sbdp_showbd_2_sbd_stat(show_board_t *shbp, sbd_stat_t *stp, int board)
81 {
82 static fn_t f = "sbdp_showbd_2_sbd_stat";
83
84 SBDP_DBG_FUNC("%s\n", f);
85
86 stp->s_board = board;
87 (void) strcpy(stp->s_info, shbp->s_info);
88 stp->s_power = shbp->s_power;
89
90 (void) strcpy(stp->s_type, shbp->s_type);
91
92 if (shbp->s_present == 0) {
93 /*
94 * This should go away since the SC should put the unknown
95 * We leave this here so Symon and other scripts don't have
96 * a problem
97 */
98 (void) strcpy(stp->s_type, UNKNOWN);
99 stp->s_rstate = SBD_STAT_EMPTY;
100 } else if (shbp->s_claimed == 0)
101 stp->s_rstate = SBD_STAT_DISCONNECTED;
102 else
103 stp->s_rstate = SBD_STAT_CONNECTED;
104
105
106 stp->s_assigned = shbp->s_assigned;
107 stp->s_cond = shbp->s_cond;
108 }
109
110 /*
111 * Entry point from sbd. Get the status from the SC and then convert
112 * the info returned into something that sbd understands
113 * If the request times out or fails other than an illegal transaction
114 * copy the info from our inventory
115 */
116 int
sbdp_get_board_status(sbdp_handle_t * hp,sbd_stat_t * stp)117 sbdp_get_board_status(sbdp_handle_t *hp, sbd_stat_t *stp)
118 {
119 int board = hp->h_board;
120 int node = hp->h_wnode;
121 sbbc_msg_t request, *reqp = &request;
122 sbbc_msg_t response, *resp = &response;
123 info_t inform, *informp = &inform;
124 show_board_t show_bd, *shbp = &show_bd;
125 int rv = 0;
126 sbd_error_t *sep = hp->h_err;
127 int len;
128 sbdp_bd_t *bdp;
129 static fn_t f = "sbdp_get_board_status";
130
131 SBDP_DBG_FUNC("%s\n", f);
132
133 /*
134 * Check for options. If there are any, fail the operation
135 */
136 if (hp->h_opts != NULL && hp->h_opts->copts != NULL) {
137 sbdp_set_err(sep, ESBD_INVAL_OPT, hp->h_opts->copts);
138 return (-1);
139 }
140
141 bdp = sbdp_get_bd_info(node, board);
142
143 informp->board = board;
144 informp->node = node;
145 informp->revision = 0xdead;
146 len = sizeof (info_t);
147
148 sbdp_init_msg_pkt(reqp, DR_MBOX_SHOW_BOARD, len, (caddr_t)informp);
149
150 bzero(shbp, sizeof (show_board_t));
151 shbp->s_cond = -1;
152 shbp->s_power = -1;
153 shbp->s_assigned = -1;
154 shbp->s_claimed = -1;
155 shbp->s_present = -1;
156 len = sizeof (show_board_t);
157
158 sbdp_init_msg_pkt(resp, DR_MBOX_SHOW_BOARD, len, (caddr_t)shbp);
159
160 rv = sbbc_mbox_request_response(reqp, resp, sbdp_shw_bd_wait);
161
162 SBDP_DBG_MISC("show board completed: rv = %d\n", rv);
163
164 /*
165 * This domain has no access to this board. Return failure
166 */
167 if ((resp->msg_status == SG_MBOX_STATUS_BOARD_ACCESS_DENIED) ||
168 (resp->msg_status == SG_MBOX_STATUS_ILLEGAL_SLOT) ||
169 (resp->msg_status == SG_MBOX_STATUS_ILLEGAL_NODE)) {
170
171 /*
172 * invalidate cached copy.
173 */
174 bdp->valid_cp = -1;
175
176 sbdp_set_err(sep, ESGT_GET_BOARD_STAT, NULL);
177 return (EIO);
178 }
179
180 /*
181 * If we get any error see if we can return a cached copy of the
182 * board info. If one exists turn the busy flag on
183 */
184 if (rv != 0) {
185 mutex_enter(&bdp->bd_mutex);
186 if (bdp->valid_cp == -1) {
187 sbdp_set_err(sep, ESGT_GET_BOARD_STAT,
188 NULL);
189 mutex_exit(&bdp->bd_mutex);
190 return (EIO);
191 }
192
193 /*
194 * we have a valid copy. Return it and set the
195 * busy flag on so the user know this is not the most
196 * recent copy
197 */
198 bcopy(bdp->bd_sc, shbp, sizeof (show_board_t));
199 mutex_exit(&bdp->bd_mutex);
200 stp->s_busy = 1;
201 /*
202 * The sbbc returns the error in both parts (i.e rv and status)
203 * so since we just took care of it reset rv
204 */
205 rv = 0;
206 } else {
207 /*
208 * revalidate our copy of the returned data
209 */
210 if (bdp == NULL) {
211 SBDP_DBG_MBOX("HUGE ERROR\n");
212 } else {
213 mutex_enter(&bdp->bd_mutex);
214 bcopy(shbp, bdp->bd_sc, sizeof (show_board_t));
215 bdp->valid_cp = 1;
216 mutex_exit(&bdp->bd_mutex);
217 }
218 }
219
220
221 SBDP_DBG_MBOX("Showboard: board\t%d\n\trevision\t%d\n\ts_cond\t%d\n\t"
222 "s_power\t%d\n\ts_assigned\t%d\n\ts_claimed\t%d\n\t"
223 "s_present\t%d\n\ts_ledstatus\t%d\n\ts_type\t%s\n\t"
224 "s_info\t%s\n",
225 board, shbp->revision, shbp->s_cond, shbp->s_power,
226 shbp->s_assigned, shbp->s_claimed, shbp->s_present,
227 shbp->s_ledstatus, shbp->s_type, shbp->s_info);
228
229 /*
230 * Now that we got the info run through the sbd-sbdp translator
231 */
232 sbdp_showbd_2_sbd_stat(shbp, stp, board);
233
234 /*
235 * Last add the platform options
236 */
237 SBDP_PLATFORM_OPTS(stp->s_platopts);
238
239 return (rv);
240 }
241
242 /*
243 * Entry point from sbd. Call down to the SC to assign the board
244 * We simply return the status the SC told us
245 */
246 int
sbdp_assign_board(sbdp_handle_t * hp)247 sbdp_assign_board(sbdp_handle_t *hp)
248 {
249 int board = hp->h_board;
250 int node = hp->h_wnode;
251 sbbc_msg_t request, *reqp = &request;
252 sbbc_msg_t response, *resp = &response;
253 int cmd_rev = -1;
254 info2_t inform, *informp = &inform;
255 int rv = 0;
256 sbd_error_t *sep;
257 int len;
258 static fn_t f = "sbdp_assign_board";
259
260 SBDP_DBG_FUNC("%s\n", f);
261
262 sep = hp->h_err;
263 /*
264 * Check for options. If there are any, fail the operation
265 */
266 if (hp->h_opts != NULL && hp->h_opts->copts != NULL) {
267 sbdp_set_err(sep, ESBD_INVAL_OPT, hp->h_opts->copts);
268 return (-1);
269 }
270
271 informp->board = board;
272 informp->node = node;
273 informp->extra = SBDP_ASSIGN;
274 len = sizeof (info2_t);
275
276 sbdp_init_msg_pkt(reqp, DR_MBOX_ASSIGN, len, (caddr_t)informp);
277
278 len = sizeof (cmd_rev);
279
280 sbdp_init_msg_pkt(resp, DR_MBOX_ASSIGN, len, (caddr_t)&cmd_rev);
281
282 rv = sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait);
283
284 if (rv != 0 || (rv = resp->msg_status != SG_MBOX_STATUS_SUCCESS)) {
285 SBDP_DBG_MISC("failed to assign board: rv = %d\n", rv);
286 sbdp_set_err(sep, sbdp_sc_err_translation(resp->msg_status),
287 NULL);
288 }
289
290 return (rv);
291 }
292
293 /*
294 * Entry point from sbd. Call down to the SC to unassign the board
295 * We simply return the status the SC told us
296 */
297 int
sbdp_unassign_board(sbdp_handle_t * hp)298 sbdp_unassign_board(sbdp_handle_t *hp)
299 {
300 int board = hp->h_board;
301 int node = hp->h_wnode;
302 sbbc_msg_t request, *reqp = &request;
303 sbbc_msg_t response, *resp = &response;
304 int cmd_rev = -1;
305 info2_t inform, *informp = &inform;
306 int rv = 0;
307 sbd_error_t *sep;
308 int len;
309 static fn_t f = "sbdp_unassign_board";
310
311 SBDP_DBG_FUNC("%s\n", f);
312
313 sep = hp->h_err;
314 /*
315 * Check for options. If there are any, fail the operation
316 */
317 if (hp->h_opts != NULL && hp->h_opts->copts != NULL) {
318 sbdp_set_err(sep, ESBD_INVAL_OPT, hp->h_opts->copts);
319 return (-1);
320 }
321
322 informp->board = board;
323 informp->node = node;
324 informp->extra = SBDP_UNASSIGN;
325 len = sizeof (info2_t);
326
327 sbdp_init_msg_pkt(reqp, DR_MBOX_ASSIGN, len, (caddr_t)informp);
328
329 len = sizeof (cmd_rev);
330
331 sbdp_init_msg_pkt(resp, DR_MBOX_ASSIGN, len, (caddr_t)&cmd_rev);
332
333 rv = sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait);
334
335 if (rv != 0 || (rv = resp->msg_status != SG_MBOX_STATUS_SUCCESS)) {
336 SBDP_DBG_MISC("failed to unassign board: rv = %d\n", rv);
337 sbdp_set_err(sep, sbdp_sc_err_translation(resp->msg_status),
338 NULL);
339 }
340
341 return (rv);
342 }
343
344 static int
sg_attach_board(void * arg)345 sg_attach_board(void *arg)
346 {
347 sbdp_handle_t *hp;
348 cpuset_t cset;
349 int rv;
350 static fn_t f = "sg_attach_board";
351
352 SBDP_DBG_FUNC("%s\n", f);
353
354 hp = (sbdp_handle_t *)arg;
355
356 cset = cpu_ready_set;
357 promsafe_xc_attention(cset);
358 rv = prom_serengeti_attach_board(hp->h_wnode, hp->h_board);
359 xc_dismissed(cset);
360
361 return (rv);
362 }
363
364 static int
sg_detach_board(void * arg)365 sg_detach_board(void *arg)
366 {
367 sbdp_handle_t *hp;
368 cpuset_t cset;
369 int rv;
370 static fn_t f = "sg_detach_board";
371
372 SBDP_DBG_FUNC("%s\n", f);
373
374 hp = (sbdp_handle_t *)arg;
375
376 cset = cpu_ready_set;
377 promsafe_xc_attention(cset);
378 rv = prom_serengeti_detach_board(hp->h_wnode, hp->h_board);
379 xc_dismissed(cset);
380
381 return (rv);
382 }
383
384 /*
385 * Entry point from sbd. First we call down to the SC to "attach/claim" this
386 * board. As a side effect the SC updates the pda info so obp can create the
387 * device tree. If we are successful, we ask OBP to probe the board. OBP
388 * creates new nodes on its own obp tree
389 * As an added bonus, since we don't use the inkernel prober, we need to create
390 * the dev_info nodes but just to a point where they are created but
391 * Solaris can't use them (i.e BIND)
392 */
393 int
sbdp_connect_board(sbdp_handle_t * hp)394 sbdp_connect_board(sbdp_handle_t *hp)
395 {
396 sbbc_msg_t request, *reqp = &request;
397 sbbc_msg_t response, *resp = &response;
398 int rv = 0;
399 int board, node;
400 sbd_error_t *sep;
401 static fn_t f = "sbdp_connect_board";
402 int panther_pages_enabled;
403
404 SBDP_DBG_FUNC("%s\n", f);
405
406 board = hp->h_board;
407 node = hp->h_wnode;
408 sep = hp->h_err;
409
410 /*
411 * Check for options. If there are any, fail the operation
412 */
413 if (hp->h_opts != NULL && hp->h_opts->copts != NULL) {
414 sbdp_set_err(sep, ESBD_INVAL_OPT, hp->h_opts->copts);
415 return (-1);
416 }
417
418 /*
419 * Currently, we pass the info in the extra data fields.
420 * This may change in the SC. We need to change it then
421 */
422 sbdp_init_msg_pkt(reqp, DR_MBOX_CLAIM, 0, (caddr_t)NULL);
423 reqp->msg_data[0] = node;
424 reqp->msg_data[1] = board;
425
426 sbdp_init_msg_pkt(resp, DR_MBOX_CLAIM, 0, (caddr_t)NULL);
427
428 rv = sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait);
429
430 if (rv != 0 || (rv = resp->msg_status != SG_MBOX_STATUS_SUCCESS)) {
431 SBDP_DBG_MISC("failed to claim board: rv = %d\n", rv);
432 sbdp_set_err(sep, sbdp_sc_err_translation(resp->msg_status),
433 NULL);
434 return (rv);
435 }
436
437 rv = prom_tree_update(sg_attach_board, hp);
438 if (rv != 0) {
439 SBDP_DBG_MISC("failed to prom attach board: rv = %d\n", rv);
440 sbdp_set_err(sep, ESGT_PROM_ATTACH, NULL);
441 /*
442 * Clean up
443 */
444 sbdp_init_msg_pkt(reqp, DR_MBOX_UNCLAIM, 0, (caddr_t)NULL);
445 reqp->msg_data[0] = node;
446 reqp->msg_data[1] = board;
447
448 sbdp_init_msg_pkt(resp, DR_MBOX_UNCLAIM, 0, (caddr_t)NULL);
449
450 (void) sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait);
451
452 return (rv);
453 }
454
455 SBDP_DBG_MISC("prom attach worked\n");
456 sbdp_attach_bd(node, board);
457
458 /*
459 * XXX Until the Solaris large pages support heterogeneous cpu
460 * domains, DR needs to prevent the addition of non-Panther cpus
461 * to an all-Panther domain with large pages enabled.
462 */
463 panther_pages_enabled = (page_num_pagesizes() > DEFAULT_MMU_PAGE_SIZES);
464 if (sbdp_board_non_panther_cpus(node, board) > 0 &&
465 panther_pages_enabled && sbdp_large_page_restriction) {
466 cmn_err(CE_WARN, "Domain shutdown is required to add a non-"
467 "UltraSPARC-IV+ board into an all UltraSPARC-IV+ domain");
468 (void) sbdp_disconnect_board(hp);
469 sbdp_set_err(sep, ESGT_NOT_SUPP, NULL);
470 return (-1);
471 }
472
473 /*
474 * Now that the board has been successfully attached, obtain
475 * platform-specific DIMM serial id information for the board.
476 */
477 if (SG_BOARD_IS_CPU_TYPE(board) &&
478 plat_ecc_capability_sc_get(PLAT_ECC_DIMM_SID_MESSAGE)) {
479 (void) plat_request_mem_sids(board);
480 }
481
482 return (rv);
483 }
484
485 /*
486 * Entry point from sbd. Undo the connect call. We first need to remove
487 * the "dummy (i.e unusable)" nodes from solaris. We then call down to OBP
488 * to prune its tree. After all has been cleaned up from OBP and Solaris
489 * We call the SC to "detach/unclain" the board. A side effect is that the
490 * SC will clear the pda entries for this board
491 */
492 int
sbdp_disconnect_board(sbdp_handle_t * hp)493 sbdp_disconnect_board(sbdp_handle_t *hp)
494 {
495 sbbc_msg_t request, *reqp = &request;
496 sbbc_msg_t response, *resp = &response;
497 int rv = 0;
498 int board, node;
499 sbd_error_t *sep;
500 static fn_t f = "sbdp_disconnect_board";
501
502 SBDP_DBG_FUNC("%s\n", f);
503
504 board = hp->h_board;
505 node = hp->h_wnode;
506 sep = hp->h_err;
507
508 SBDP_DBG_MISC("sbdp_disconnect_board: board = %d node = %d\n",
509 board, node);
510
511 /*
512 * Check for options. If there are any, fail the operation
513 */
514 if (hp->h_opts != NULL && hp->h_opts->copts != NULL) {
515 sbdp_set_err(sep, ESBD_INVAL_OPT, hp->h_opts->copts);
516 return (-1);
517 }
518
519 if (sbdp_detach_bd(node, board, sep)) {
520 sbdp_attach_bd(node, board);
521 SBDP_DBG_ALL("failed to detach board %d\n", board);
522 return (-1);
523 }
524
525 rv = prom_tree_update(sg_detach_board, hp);
526 if (rv == -1) {
527 /*
528 * Clean up
529 */
530 sbdp_attach_bd(node, board);
531 SBDP_DBG_MISC("failed to prom detach board: rv = %d\n", rv);
532 sbdp_set_err(sep, ESGT_PROM_DETACH, NULL);
533 return (rv);
534 }
535
536 SBDP_DBG_MISC("prom detach worked\n");
537 /*
538 * Currently, we pass the info in the extra data fields.
539 * This may change in the SC. We need to change it then
540 */
541 sbdp_init_msg_pkt(reqp, DR_MBOX_UNCLAIM, 0, (caddr_t)NULL);
542 reqp->msg_data[0] = node;
543 reqp->msg_data[1] = board;
544
545 sbdp_init_msg_pkt(resp, DR_MBOX_UNCLAIM, 0, (caddr_t)NULL);
546
547 rv = sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait);
548
549 if (rv != 0 || (rv = resp->msg_status != SG_MBOX_STATUS_SUCCESS)) {
550 SBDP_DBG_MISC("failed to unclaim board: rv = %d\n", rv);
551 sbdp_set_err(sep, sbdp_sc_err_translation(resp->msg_status),
552 NULL);
553 /* bring back the obp tree to what it was */
554 (void) prom_tree_update(sg_attach_board, hp);
555 }
556
557 /*
558 * Now that the board has been successfully detached, discard
559 * platform-specific DIMM serial id information for the board.
560 */
561 if (!rv && SG_BOARD_IS_CPU_TYPE(board) &&
562 plat_ecc_capability_sc_get(PLAT_ECC_DIMM_SID_MESSAGE)) {
563 (void) plat_discard_mem_sids(board);
564 }
565
566 return (rv);
567 }
568
569 /*
570 * Entry point from sbd. Very simple. Just ask the SC to poweoff the board
571 * Return the status from the SC
572 */
573 int
sbdp_poweroff_board(sbdp_handle_t * hp)574 sbdp_poweroff_board(sbdp_handle_t *hp)
575 {
576 sbbc_msg_t request, *reqp = &request;
577 sbbc_msg_t response, *resp = &response;
578 int cmd_rev = -1;
579 info2_t inform, *informp;
580 int rv = 0;
581 sbd_error_t *sep;
582 int len;
583 static fn_t f = "sbdp_poweroff_board";
584
585 SBDP_DBG_FUNC("%s\n", f);
586
587 sep = hp->h_err;
588 /*
589 * Check for options. If there are any, fail the operation
590 */
591 if (hp->h_opts != NULL && hp->h_opts->copts != NULL) {
592 sbdp_set_err(sep, ESBD_INVAL_OPT, hp->h_opts->copts);
593 return (-1);
594 }
595
596 /*
597 * Can't check for bad options here since we use this for workaround
598 * on poweron.
599 */
600
601 informp = &inform;
602 informp->board = hp->h_board;
603 informp->node = hp->h_wnode;
604 informp->extra = SBDP_POWER_OFF;
605
606 len = sizeof (info2_t);
607 sbdp_init_msg_pkt(reqp, DR_MBOX_POWER, len, (caddr_t)informp);
608
609 len = sizeof (cmd_rev);
610 sbdp_init_msg_pkt(resp, DR_MBOX_POWER, len, (caddr_t)&cmd_rev);
611
612 rv = sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait);
613
614 if (rv != 0 || (rv = resp->msg_status != SG_MBOX_STATUS_SUCCESS)) {
615 SBDP_DBG_MISC("failed to poweroff board: rv = %d\n", rv);
616 sbdp_set_err(sep, sbdp_sc_err_translation(resp->msg_status),
617 NULL);
618 }
619
620 return (rv);
621 }
622
623 /*
624 * Entry point from sbd. Ask the SC to poweron the board
625 * Return the status from the SC
626 */
627 int
sbdp_poweron_board(sbdp_handle_t * hp)628 sbdp_poweron_board(sbdp_handle_t *hp)
629 {
630 sbbc_msg_t request, *reqp = &request;
631 sbbc_msg_t response, *resp = &response;
632 int cmd_rev = -1;
633 info2_t inform, *informp;
634 int rv = 0;
635 sbd_error_t *sep;
636 int len;
637 int board = hp->h_board;
638 static fn_t f = "sbdp_poweron_board";
639
640 SBDP_DBG_FUNC("%s\n", f);
641
642 sep = hp->h_err;
643 /*
644 * Check for options. If there are any, fail the operation
645 */
646 if (hp->h_opts != NULL && hp->h_opts->copts != NULL) {
647 sbdp_set_err(sep, ESBD_INVAL_OPT, hp->h_opts->copts);
648 return (-1);
649 }
650
651 if (sbdp_poweroff_wkaround)
652 if (SG_BOARD_IS_CPU_TYPE(board)) {
653
654 if ((rv = sbdp_poweroff_board(hp)) != 0)
655 return (rv);
656 }
657
658 informp = &inform;
659 informp->board = hp->h_board;
660 informp->node = hp->h_wnode;
661 informp->extra = SBDP_POWER_ON;
662
663 len = sizeof (info2_t);
664 sbdp_init_msg_pkt(reqp, DR_MBOX_POWER, len, (caddr_t)informp);
665
666 len = sizeof (cmd_rev);
667 sbdp_init_msg_pkt(resp, DR_MBOX_POWER, len, (caddr_t)&cmd_rev);
668
669 rv = sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait);
670
671 if (rv != 0 || (rv = resp->msg_status != SG_MBOX_STATUS_SUCCESS)) {
672 SBDP_DBG_MISC("failed to poweron board: rv = %d\n", rv);
673 sbdp_set_err(sep, sbdp_sc_err_translation(resp->msg_status),
674 NULL);
675 }
676
677 return (rv);
678 }
679
680 int
sbdp_get_diag(sbdp_opts_t * opts)681 sbdp_get_diag(sbdp_opts_t *opts)
682 {
683 char *cptr;
684 static fn_t f = "sbdp_get_diag";
685
686 SBDP_DBG_FUNC("%s\n", f);
687
688 if ((opts == NULL) || (opts->copts == NULL))
689 return (SBDP_DIAG_NVCI);
690
691 if ((cptr = strstr(opts->copts, "diag=")) != NULL) {
692 /*
693 * We have args and need to process them
694 */
695 cptr += strlen("diag=");
696
697 if (strncmp(cptr, "off", sizeof ("off")) == 0) {
698 return (SBDP_DIAG_OFF);
699 } else if (strncmp(cptr, "init", sizeof ("init")) == 0) {
700 return (SBDP_DIAG_INIT);
701 } else if (strncmp(cptr, "quick", sizeof ("quick")) == 0) {
702 return (SBDP_DIAG_QUICK);
703 } else if (strncmp(cptr, "min", sizeof ("min")) == 0) {
704 return (SBDP_DIAG_MIN);
705 } else if (strncmp(cptr, "default", sizeof ("default")) == 0 ||
706 strncmp(cptr, "max", sizeof ("max")) == 0) {
707 return (SBDP_DIAG_DEFAULT);
708 } else if (strncmp(cptr, "mem1", sizeof ("mem1")) == 0) {
709 return (SBDP_DIAG_MEM1);
710 } else if (strncmp(cptr, "mem2", sizeof ("mem2")) == 0) {
711 return (SBDP_DIAG_MEM2);
712 }
713 }
714 SBDP_DBG_MISC("error: unrecognized arg\n");
715 return (-1);
716 }
717
718
719 /*
720 * Entry point from sbd. Ask the SC to test the board. We still need to
721 * worry about the diag level. The user may have changed it
722 *
723 * NOTE: The flag field has 2 different meanings whether we are dealing
724 * with a cpu/mem board or an io board. In the case of a cpu/mem board it
725 * means retest the board to the diag level specified. In the case of an IO
726 * board, it means: Perform the necessary steps to prepare the board
727 * for the claim without running POST at the diag level specified.
728 */
729 int
sbdp_test_board(sbdp_handle_t * hp,sbdp_opts_t * opts)730 sbdp_test_board(sbdp_handle_t *hp, sbdp_opts_t *opts)
731 {
732 int board = hp->h_board;
733 int node = hp->h_wnode;
734 sbbc_msg_t request, *reqp = &request;
735 sbbc_msg_t response, *resp = &response;
736 int cmd_rev = -1;
737 testb_t inform, *informp = &inform;
738 int rv = 0;
739 sbd_error_t *sep;
740 int diag;
741 int len;
742 static fn_t f = "sbdp_test_board";
743
744 SBDP_DBG_FUNC("%s\n", f);
745
746 sep = hp->h_err;
747
748 diag = sbdp_get_diag(opts);
749
750 if (diag == -1) {
751 sbdp_set_err(sep, ESBD_INVAL_OPT, opts != NULL ?
752 opts->copts : NULL);
753 return (-1);
754 }
755
756 SBDP_DBG_MISC("Diag level is 0x%x\n", diag);
757
758 informp->info.board = board;
759 informp->info.node = node;
760
761 informp->info.extra = diag;
762
763 /*
764 * Only force retest on CPU boards
765 */
766 if (SG_BOARD_IS_CPU_TYPE(board))
767 informp->flag = 1;
768 else {
769 /*
770 * For CPULESS IO pass the force to the SC
771 */
772 if (hp->h_flags & SBDP_IOCTL_FLAG_FORCE)
773 informp->flag = 1;
774 else
775 informp->flag = 0;
776
777 }
778
779 len = sizeof (testb_t);
780 sbdp_init_msg_pkt(reqp, DR_MBOX_TEST_BD, len, (caddr_t)informp);
781
782
783 len = sizeof (cmd_rev);
784 sbdp_init_msg_pkt(resp, DR_MBOX_TEST_BD, len, (caddr_t)&cmd_rev);
785
786 rv = sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait);
787
788 if (rv != 0 || (resp->msg_status != SG_MBOX_STATUS_SUCCESS)) {
789 SBDP_DBG_MISC("failed to test board: rv = %d status = %d\n",
790 rv, resp->msg_status);
791 rv = resp->msg_status;
792 sbdp_set_err(sep, sbdp_sc_err_translation(resp->msg_status),
793 NULL);
794 }
795
796 return (rv);
797 }
798
799 /*
800 * Request the SC to update POST's memory slice table by swapping
801 * the entries for the two board numbers given
802 * This is used when performing a copy-rename operation.
803 */
804 int
sbdp_swap_slices(int bd1,int bd2)805 sbdp_swap_slices(int bd1, int bd2)
806 {
807 sbbc_msg_t request, *reqp = &request;
808 sbbc_msg_t response, *resp = &response;
809 int cmd_rev = -1;
810 swap_slices_t inform, *informp = &inform;
811 int rv;
812 int len;
813 static fn_t f = "sbdp_swap_slices";
814
815 SBDP_DBG_FUNC("%s\n", f);
816
817 informp->board1 = bd1;
818 informp->board2 = bd2;
819
820 len = sizeof (swap_slices_t);
821 sbdp_init_msg_pkt(reqp, DR_MBOX_SWAP_SLICES, len, (caddr_t)informp);
822
823 len = sizeof (cmd_rev);
824 sbdp_init_msg_pkt(resp, DR_MBOX_SWAP_SLICES, len, (caddr_t)&cmd_rev);
825
826 rv = sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait);
827
828 if (rv != 0 || (resp->msg_status != SG_MBOX_STATUS_SUCCESS)) {
829 SBDP_DBG_MISC("failed to swap slices %d<->%d: rv = %d "
830 "status = %d\n", bd1, bd2, rv, resp->msg_status);
831 rv = sbdp_sc_err_translation(resp->msg_status);
832 }
833
834 return (rv);
835 }
836
837 int
sbdp_sc_err_translation(int error)838 sbdp_sc_err_translation(int error)
839 {
840 int err;
841 static fn_t f = "sbdp_sc_err_translation";
842
843 SBDP_DBG_FUNC("%s\n", f);
844
845 switch (error) {
846 case SG_MBOX_STATUS_HARDWARE_FAILURE:
847 err = ESGT_HW_FAIL;
848 break;
849 case SG_MBOX_STATUS_ILLEGAL_PARAMETER:
850 case SG_MBOX_STATUS_ILLEGAL_NODE:
851 case SG_MBOX_STATUS_ILLEGAL_SLOT:
852 err = ESGT_INVAL;
853 break;
854 case SG_MBOX_STATUS_BOARD_ACCESS_DENIED:
855 err = ESGT_BD_ACCESS;
856 break;
857 case SG_MBOX_STATUS_STALE_CONTENTS:
858 err = ESGT_STALE_CMP;
859 break;
860 case SG_MBOX_STATUS_STALE_OBJECT:
861 err = ESGT_STALE_OBJ;
862 break;
863 case SG_MBOX_STATUS_NO_SEPROM_SPACE:
864 err = ESGT_NO_SEPROM_SPACE;
865 break;
866 case SG_MBOX_STATUS_NO_MEMORY:
867 err = ESGT_NO_MEM;
868 break;
869 case SG_MBOX_STATUS_NOT_SUPPORTED:
870 err = ESGT_NOT_SUPP;
871 break;
872 case SG_MBOX_STATUS_COMMAND_FAILURE:
873 default:
874 err = ESGT_INTERNAL;
875 break;
876 }
877
878 return (err);
879 }
880
881 int
sbdp_stop_cpu(processorid_t cpu)882 sbdp_stop_cpu(processorid_t cpu)
883 {
884 sbbc_msg_t request, *reqp = &request;
885 sbbc_msg_t response, *resp = &response;
886 int rv = 0;
887 int len;
888 static fn_t f = "sbdp_stop_cpu";
889
890 SBDP_DBG_FUNC("%s\n", f);
891
892 len = sizeof (processorid_t);
893 sbdp_init_msg_pkt(reqp, DR_MBOX_STOP_CPU, len, (caddr_t)&cpu);
894
895 sbdp_init_msg_pkt(resp, DR_MBOX_STOP_CPU, 0, (caddr_t)NULL);
896
897 rv = sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait);
898
899 if (rv != 0 || (rv = resp->msg_status != SG_MBOX_STATUS_SUCCESS)) {
900 SBDP_DBG_MISC("failed to stop cpu: rv = %d\n", rv);
901 }
902
903 return (rv);
904 }
905
906 int
sbdp_start_cpu(processorid_t cpu)907 sbdp_start_cpu(processorid_t cpu)
908 {
909 sbbc_msg_t request, *reqp = &request;
910 sbbc_msg_t response, *resp = &response;
911 int rv = 0;
912 int len;
913 static fn_t f = "sbdp_start_cpu";
914
915 SBDP_DBG_FUNC("%s\n", f);
916
917 len = sizeof (cpu);
918 sbdp_init_msg_pkt(reqp, DR_MBOX_START_CPU, len, (caddr_t)&cpu);
919
920 sbdp_init_msg_pkt(resp, DR_MBOX_START_CPU, 0, (caddr_t)NULL);
921
922 rv = sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait);
923
924 if (rv != 0 || (rv = resp->msg_status != SG_MBOX_STATUS_SUCCESS)) {
925 SBDP_DBG_MISC("failed to start cpu: rv = %d\n", rv);
926 }
927
928 return (rv);
929 }
930
931 /*
932 * With the SIR implementation for CPU unconfigure, this mailbox
933 * call is obsolete.
934 */
935 int
sbdp_start_cpu_pairs(processorid_t cpu)936 sbdp_start_cpu_pairs(processorid_t cpu)
937 {
938 sbbc_msg_t request, *reqp = &request;
939 sbbc_msg_t response, *resp = &response;
940 int rv = 0;
941 int len;
942 static fn_t f = "sbdp_start_cpu_pairs";
943
944 SBDP_DBG_FUNC("%s\n", f);
945
946 len = sizeof (cpu);
947 sbdp_init_msg_pkt(reqp, DR_MBOX_START_CPU_PAIRS, len, (caddr_t)&cpu);
948
949 sbdp_init_msg_pkt(resp, DR_MBOX_START_CPU_PAIRS, 0, (caddr_t)NULL);
950
951 rv = sbbc_mbox_request_response(reqp, resp, sbdp_mbox_wait);
952
953 if (rv != 0 || (rv = resp->msg_status != SG_MBOX_STATUS_SUCCESS)) {
954 SBDP_DBG_MISC("failed to start cpu pair: rv = %d\n", rv);
955 }
956
957 return (rv);
958 }
959