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
46int sbdp_mbox_wait = 86400;	/* in seconds */
47int sbdp_shw_bd_wait = 5;	/* in seconds */
48
49int sbdp_sc_err_translation(int);
50int 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 */
57static int sbdp_large_page_restriction = 1;
58
59/*
60 * Initialize the data structs for the common part of the pkts
61 */
62void
63sbdp_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 */
79void
80sbdp_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 */
116int
117sbdp_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 */
246int
247sbdp_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 */
297int
298sbdp_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
344static int
345sg_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
364static int
365sg_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 */
393int
394sbdp_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 */
492int
493sbdp_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 */
573int
574sbdp_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 */
627int
628sbdp_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
680int
681sbdp_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 */
729int
730sbdp_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 */
804int
805sbdp_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
837int
838sbdp_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
881int
882sbdp_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
906int
907sbdp_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 */
935int
936sbdp_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