1*03831d35Sstevel /*
2*03831d35Sstevel  * CDDL HEADER START
3*03831d35Sstevel  *
4*03831d35Sstevel  * The contents of this file are subject to the terms of the
5*03831d35Sstevel  * Common Development and Distribution License (the "License").
6*03831d35Sstevel  * You may not use this file except in compliance with the License.
7*03831d35Sstevel  *
8*03831d35Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*03831d35Sstevel  * or http://www.opensolaris.org/os/licensing.
10*03831d35Sstevel  * See the License for the specific language governing permissions
11*03831d35Sstevel  * and limitations under the License.
12*03831d35Sstevel  *
13*03831d35Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
14*03831d35Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*03831d35Sstevel  * If applicable, add the following below this CDDL HEADER, with the
16*03831d35Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
17*03831d35Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
18*03831d35Sstevel  *
19*03831d35Sstevel  * CDDL HEADER END
20*03831d35Sstevel  */
22*03831d35Sstevel /*
23*03831d35Sstevel  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*03831d35Sstevel  * Use is subject to license terms.
25*03831d35Sstevel  */
27*03831d35Sstevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
29*03831d35Sstevel #include <sys/cpuvar.h>
30*03831d35Sstevel #include <sys/cpu_module.h>
31*03831d35Sstevel #include <sys/kmem.h>
32*03831d35Sstevel #include <sys/sunddi.h>
33*03831d35Sstevel #include <sys/param.h>
34*03831d35Sstevel #include <sys/obpdefs.h>
35*03831d35Sstevel #include <sys/prom_plat.h>
36*03831d35Sstevel #include <sys/sgsbbc_mailbox.h>
37*03831d35Sstevel #include <sys/sbd_ioctl.h>
38*03831d35Sstevel #include <sys/sbdp_priv.h>
39*03831d35Sstevel #include <sys/sbdp_mbox.h>
40*03831d35Sstevel #include <sys/promif.h>
41*03831d35Sstevel #include <sys/plat_ecc_dimm.h>
43*03831d35Sstevel #define	UNKNOWN "unknown"
44*03831d35Sstevel #define	INITL_STATUS	0xdead
46*03831d35Sstevel int sbdp_mbox_wait = 86400;	/* in seconds */
47*03831d35Sstevel int sbdp_shw_bd_wait = 5;	/* in seconds */
49*03831d35Sstevel int sbdp_sc_err_translation(int);
50*03831d35Sstevel int sbdp_poweroff_wkaround = 1;
52*03831d35Sstevel /*
53*03831d35Sstevel  * By default, DR of non-Panther procs is not allowed into a Panther
54*03831d35Sstevel  * domain with large page sizes enabled.  Setting this to 0 will remove
55*03831d35Sstevel  * the restriction.
56*03831d35Sstevel  */
57*03831d35Sstevel static int sbdp_large_page_restriction = 1;
59*03831d35Sstevel /*
60*03831d35Sstevel  * Initialize the data structs for the common part of the pkts
61*03831d35Sstevel  */
62*03831d35Sstevel void
sbdp_init_msg_pkt(sbbc_msg_t * msg,uint16_t sub_type,int len,caddr_t buf)63*03831d35Sstevel sbdp_init_msg_pkt(sbbc_msg_t *msg, uint16_t sub_type, int len, caddr_t buf)
64*03831d35Sstevel {
65*03831d35Sstevel 	msg->msg_type.type = DR_MBOX;
66*03831d35Sstevel 	msg->msg_type.sub_type = sub_type;
67*03831d35Sstevel 	msg->msg_status = INITL_STATUS;
68*03831d35Sstevel 	msg->msg_len = len;
69*03831d35Sstevel 	msg->msg_buf = buf;
70*03831d35Sstevel 	msg->msg_data[0] = 0;
71*03831d35Sstevel 	msg->msg_data[1] = 0;
73*03831d35Sstevel }
75*03831d35Sstevel /*
76*03831d35Sstevel  * Convert a showboard data structure to the board structure shared
77*03831d35Sstevel  * between sbd and sbdp
78*03831d35Sstevel  */
79*03831d35Sstevel void
sbdp_showbd_2_sbd_stat(show_board_t * shbp,sbd_stat_t * stp,int board)80*03831d35Sstevel sbdp_showbd_2_sbd_stat(show_board_t *shbp, sbd_stat_t *stp, int board)
81*03831d35Sstevel {
82*03831d35Sstevel 	static fn_t	f = "sbdp_showbd_2_sbd_stat";
84*03831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
86*03831d35Sstevel 	stp->s_board = board;
87*03831d35Sstevel 	(void) strcpy(stp->s_info, shbp->s_info);
88*03831d35Sstevel 	stp->s_power = shbp->s_power;
90*03831d35Sstevel 	(void) strcpy(stp->s_type, shbp->s_type);
92*03831d35Sstevel 	if (shbp->s_present == 0) {
93*03831d35Sstevel 		/*
94*03831d35Sstevel 		 * This should go away since the SC should put the unknown
95*03831d35Sstevel 		 * We leave this here so Symon and other scripts don't have
96*03831d35Sstevel 		 * a problem
97*03831d35Sstevel 		 */
98*03831d35Sstevel 		(void) strcpy(stp->s_type, UNKNOWN);
99*03831d35Sstevel 		stp->s_rstate = SBD_STAT_EMPTY;
100*03831d35Sstevel 	} else if (shbp->s_claimed == 0)
101*03831d35Sstevel 		stp->s_rstate = SBD_STAT_DISCONNECTED;
102*03831d35Sstevel 	else
103*03831d35Sstevel 		stp->s_rstate = SBD_STAT_CONNECTED;
106*03831d35Sstevel 	stp->s_assigned = shbp->s_assigned;
107*03831d35Sstevel 	stp->s_cond = shbp->s_cond;
108*03831d35Sstevel }
110*03831d35Sstevel /*
111*03831d35Sstevel  * Entry point from sbd.  Get the status from the SC and then convert
112*03831d35Sstevel  * the info returned into something that sbd understands
113*03831d35Sstevel  * If the request times out or fails other than an illegal transaction
114*03831d35Sstevel  * copy the info from our inventory
115*03831d35Sstevel  */
116*03831d35Sstevel int
sbdp_get_board_status(sbdp_handle_t * hp,sbd_stat_t * stp)117*03831d35Sstevel sbdp_get_board_status(sbdp_handle_t *hp, sbd_stat_t *stp)
118*03831d35Sstevel {
119*03831d35Sstevel 	int		board = hp->h_board;
120*03831d35Sstevel 	int		node = hp->h_wnode;
121*03831d35Sstevel 	sbbc_msg_t	request, *reqp = &request;
122*03831d35Sstevel 	sbbc_msg_t	response, *resp = &response;
123*03831d35Sstevel 	info_t		inform, *informp = &inform;
124*03831d35Sstevel 	show_board_t	show_bd, *shbp = &show_bd;
125*03831d35Sstevel 	int		rv = 0;
126*03831d35Sstevel 	sbd_error_t	*sep = hp->h_err;
127*03831d35Sstevel 	int		len;
128*03831d35Sstevel 	sbdp_bd_t	*bdp;
129*03831d35Sstevel 	static fn_t	f = "sbdp_get_board_status";
131*03831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
133*03831d35Sstevel 	/*
134*03831d35Sstevel 	 * Check for options.  If there are any, fail the operation
135*03831d35Sstevel 	 */
136*03831d35Sstevel 	if (hp->h_opts != NULL && hp->h_opts->copts != NULL) {
137*03831d35Sstevel 		sbdp_set_err(sep, ESBD_INVAL_OPT, hp->h_opts->copts);
138*03831d35Sstevel 		return (-1);
139*03831d35Sstevel 	}
141*03831d35Sstevel 	bdp = sbdp_get_bd_info(node, board);
143*03831d35Sstevel 	informp->board = board;
144*03831d35Sstevel 	informp->node = node;
145*03831d35Sstevel 	informp->revision = 0xdead;
146*03831d35Sstevel 	len = sizeof (info_t);
148*03831d35Sstevel 	sbdp_init_msg_pkt(reqp, DR_MBOX_SHOW_BOARD, len, (caddr_t)informp);
150*03831d35Sstevel 	bzero(shbp, sizeof (show_board_t));
151*03831d35Sstevel 	shbp->s_cond = -1;
152*03831d35Sstevel 	shbp->s_power = -1;
153*03831d35Sstevel 	shbp->s_assigned = -1;
154*03831d35Sstevel 	shbp->s_claimed = -1;
155*03831d35Sstevel 	shbp->s_present = -1;
156*03831d35Sstevel 	len = sizeof (show_board_t);
158*03831d35Sstevel 	sbdp_init_msg_pkt(resp, DR_MBOX_SHOW_BOARD, len, (caddr_t)shbp);
160*03831d35Sstevel 	rv = sbbc_mbox_request_response(reqp, resp, sbdp_shw_bd_wait);
162*03831d35Sstevel 	SBDP_DBG_MISC("show board completed: rv = %d\n", rv);
164*03831d35Sstevel 	/*
165*03831d35Sstevel 	 * This domain has no access to this board. Return failure
166*03831d35Sstevel 	 */
167*03831d35Sstevel 	if ((resp->msg_status == SG_MBOX_STATUS_BOARD_ACCESS_DENIED) ||
168*03831d35Sstevel 		(resp->msg_status == SG_MBOX_STATUS_ILLEGAL_SLOT) ||
169*03831d35Sstevel 		(resp->msg_status == SG_MBOX_STATUS_ILLEGAL_NODE)) {
171*03831d35Sstevel 		/*
172*03831d35Sstevel 		 * invalidate cached copy.
173*03831d35Sstevel 		 */
174*03831d35Sstevel 		bdp->valid_cp = -1;
176*03831d35Sstevel 		sbdp_set_err(sep, ESGT_GET_BOARD_STAT, NULL);
177*03831d35Sstevel 		return (EIO);
178*03831d35Sstevel 	}
180*03831d35Sstevel 	/*
181*03831d35Sstevel 	 * If we get any error see if we can return a cached copy of the
182*03831d35Sstevel 	 * board info.  If one exists turn the busy flag on
183*03831d35Sstevel 	 */
184*03831d35Sstevel 	if (rv != 0) {
185*03831d35Sstevel 		mutex_enter(&bdp->bd_mutex);
186*03831d35Sstevel 		if (bdp->valid_cp == -1) {
187*03831d35Sstevel 			sbdp_set_err(sep, ESGT_GET_BOARD_STAT,
188*03831d35Sstevel 			    NULL);
189*03831d35Sstevel 			mutex_exit(&bdp->bd_mutex);
190*03831d35Sstevel 			return (EIO);
191*03831d35Sstevel 		}
193*03831d35Sstevel 		/*
194*03831d35Sstevel 		 * we have a valid copy.  Return it and set the
195*03831d35Sstevel 		 * busy flag on so the user know this is not the most
196*03831d35Sstevel 		 * recent copy
197*03831d35Sstevel 		 */
198*03831d35Sstevel 		bcopy(bdp->bd_sc, shbp, sizeof (show_board_t));
199*03831d35Sstevel 		mutex_exit(&bdp->bd_mutex);
200*03831d35Sstevel 		stp->s_busy = 1;
201*03831d35Sstevel 		/*
202*03831d35Sstevel 		 * The sbbc returns the error in both parts (i.e rv and status)
203*03831d35Sstevel 		 * so since we just took care of it reset rv
204*03831d35Sstevel 		 */
205*03831d35Sstevel 		rv = 0;
206*03831d35Sstevel 	} else {
207*03831d35Sstevel 		/*
208*03831d35Sstevel 		 * revalidate our copy of the returned data
209*03831d35Sstevel 		 */
210*03831d35Sstevel 		if (bdp == NULL) {
211*03831d35Sstevel 			SBDP_DBG_MBOX("HUGE ERROR\n");
212*03831d35Sstevel 		} else {
213*03831d35Sstevel 			mutex_enter(&bdp->bd_mutex);
214*03831d35Sstevel 			bcopy(shbp, bdp->bd_sc, sizeof (show_board_t));
215*03831d35Sstevel 			bdp->valid_cp = 1;
216*03831d35Sstevel 			mutex_exit(&bdp->bd_mutex);
217*03831d35Sstevel 		}
218*03831d35Sstevel 	}
221*03831d35Sstevel 	SBDP_DBG_MBOX("Showboard: board\t%d\n\trevision\t%d\n\ts_cond\t%d\n\t"
222*03831d35Sstevel 		"s_power\t%d\n\ts_assigned\t%d\n\ts_claimed\t%d\n\t"
223*03831d35Sstevel 		"s_present\t%d\n\ts_ledstatus\t%d\n\ts_type\t%s\n\t"
224*03831d35Sstevel 		"s_info\t%s\n",
225*03831d35Sstevel 			board, shbp->revision, shbp->s_cond, shbp->s_power,
226*03831d35Sstevel 			shbp->s_assigned, shbp->s_claimed, shbp->s_present,
227*03831d35Sstevel 			shbp->s_ledstatus, shbp->s_type, shbp->s_info);
229*03831d35Sstevel 	/*
230*03831d35Sstevel 	 * Now that we got the info run through the sbd-sbdp translator
231*03831d35Sstevel 	 */
232*03831d35Sstevel 	sbdp_showbd_2_sbd_stat(shbp, stp, board);
234*03831d35Sstevel 	/*
235*03831d35Sstevel 	 * Last add the platform options
236*03831d35Sstevel 	 */
237*03831d35Sstevel 	SBDP_PLATFORM_OPTS(stp->s_platopts);
239*03831d35Sstevel 	return (rv);
240*03831d35Sstevel }
242*03831d35Sstevel /*
243*03831d35Sstevel  * Entry point from sbd.  Call down to the SC to assign the board
244*03831d35Sstevel  * We simply return the status the SC told us
245*03831d35Sstevel  */
246*03831d35Sstevel int
sbdp_assign_board(sbdp_handle_t * hp)247*03831d35Sstevel sbdp_assign_board(sbdp_handle_t *hp)
248*03831d35Sstevel {
249*03831d35Sstevel 	int		board = hp->h_board;
250*03831d35Sstevel 	int		node = hp->h_wnode;
251*03831d35Sstevel 	sbbc_msg_t	request, *reqp = &request;
252*03831d35Sstevel 	sbbc_msg_t	response, *resp = &response;
253*03831d35Sstevel 	int		cmd_rev = -1;
254*03831d35Sstevel 	info2_t		inform, *informp = &inform;
255*03831d35Sstevel 	int		rv = 0;
256*03831d35Sstevel 	sbd_error_t	*sep;
257*03831d35Sstevel 	int		len;
258*03831d35Sstevel 	static fn_t	f = "sbdp_assign_board";
260*03831d35Sstevel 	SBDP_DBG_FUNC("%s\n", f);
262*03831d35Sstevel 	sep = hp->h_err;
263*03831d35Sstevel 	/*
264*03831d35Sstevel 	 * Check for options.  If there are any, fail the operation
265*03831d35Sstevel 	 */
266*03831d35Sstevel 	if (hp->h_opts != NULL && hp->h_opts->copts != NULL) {
267*03831d35Sstevel 		sbdp_set_err(sep, ESBD_INVAL_OPT, hp->h_opts->copts);