xref: /illumos-gate/usr/src/uts/sun4u/serengeti/io/sbdp_mbox.c (revision 1cb875ae88fb9463b368e725c2444776595895cb)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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