xref: /titanic_53/usr/src/lib/librsc/sparc/mpxu/common/librsc.c (revision 03831d35f7499c87d51205817c93e9a8d42c4bae)
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  */
21*03831d35Sstevel 
22*03831d35Sstevel /*
23*03831d35Sstevel  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*03831d35Sstevel  * Use is subject to license terms.
25*03831d35Sstevel  */
26*03831d35Sstevel 
27*03831d35Sstevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*03831d35Sstevel 
29*03831d35Sstevel /*
30*03831d35Sstevel  * ENXS platform-specific functions
31*03831d35Sstevel  */
32*03831d35Sstevel 
33*03831d35Sstevel #include <stdio.h>
34*03831d35Sstevel #include <stdlib.h>
35*03831d35Sstevel #include <unistd.h>
36*03831d35Sstevel #include <string.h>
37*03831d35Sstevel #include <assert.h>
38*03831d35Sstevel #include <fcntl.h>
39*03831d35Sstevel #include <errno.h>
40*03831d35Sstevel #include <sys/types.h>
41*03831d35Sstevel #include <sys/stat.h>
42*03831d35Sstevel 
43*03831d35Sstevel #include "librsc.h"
44*03831d35Sstevel 
45*03831d35Sstevel /* rmcadm driver file descriptor */
46*03831d35Sstevel static int rsc_fd = -1;
47*03831d35Sstevel 
48*03831d35Sstevel /*
49*03831d35Sstevel  * librsc receive buffer - it is used as temporary buffer to store replies
50*03831d35Sstevel  * from the remote side
51*03831d35Sstevel  */
52*03831d35Sstevel 
53*03831d35Sstevel static uchar_t rsc_rx_buffer[RSC_MAX_RX_BUFFER];
54*03831d35Sstevel static int rsc_rx_resp_len = 0;
55*03831d35Sstevel static int rsc_rx_error = 0;
56*03831d35Sstevel static rsci8 rsc_rx_resp_type = 0;
57*03831d35Sstevel 
58*03831d35Sstevel /*
59*03831d35Sstevel  * Registered boot-protocol message callback routine.  This routine will be
60*03831d35Sstevel  * called whenever a boot protocol message is received.
61*03831d35Sstevel  */
62*03831d35Sstevel static rscp_bpmsg_cb_t *bpmsg_cb;
63*03831d35Sstevel 
64*03831d35Sstevel 
65*03831d35Sstevel 
66*03831d35Sstevel /* lookup table to match request and response . This is in order to support */
67*03831d35Sstevel /* obsolete functions (rscp_send, rscp_recv) */
68*03831d35Sstevel 
69*03831d35Sstevel static req_resp_table_t rr_table[] = {
70*03831d35Sstevel 
71*03831d35Sstevel 	{ DP_GET_DATE_TIME,	DP_GET_DATE_TIME_R,
72*03831d35Sstevel 	    sizeof (dp_get_date_time_r_t), RR_TIMEOUT },
73*03831d35Sstevel 	{ DP_SET_DATE_TIME,	DP_SET_DATE_TIME_R,
74*03831d35Sstevel 	    sizeof (dp_set_date_time_r_t), RR_TIMEOUT },
75*03831d35Sstevel 	{ DP_GET_EVENT_LOG,	DP_GET_EVENT_LOG_R,
76*03831d35Sstevel 	    sizeof (dp_get_event_log_r_t), RR_TIMEOUT },
77*03831d35Sstevel 	{ DP_MODEM_CONNECT,	DP_MODEM_CONNECT_R,
78*03831d35Sstevel 	    sizeof (dp_modem_connect_r_t), RR_TIMEOUT },
79*03831d35Sstevel 	{ DP_MODEM_DISCONNECT,	DP_MODEM_DISCONNECT_R,
80*03831d35Sstevel 	    sizeof (dp_modem_disconnect_r_t), RR_TIMEOUT },
81*03831d35Sstevel 	{ DP_SEND_ALERT,	DP_SEND_ALERT_R,
82*03831d35Sstevel 	    sizeof (dp_send_alert_r_t), RR_TIMEOUT },
83*03831d35Sstevel 	{ DP_SET_CFGVAR,	DP_SET_CFGVAR_R,
84*03831d35Sstevel 	    sizeof (dp_set_cfgvar_r_t), RR_TIMEOUT },
85*03831d35Sstevel 	{ DP_GET_CFGVAR,	DP_GET_CFGVAR_R,
86*03831d35Sstevel 	    sizeof (dp_get_cfgvar_r_t), RR_TIMEOUT },
87*03831d35Sstevel 	{ DP_GET_CFGVAR_NAME,	DP_GET_CFGVAR_NAME_R,
88*03831d35Sstevel 	    sizeof (dp_get_cfgvar_name_r_t), RR_TIMEOUT },
89*03831d35Sstevel 	{ DP_GET_NETWORK_CFG,	DP_GET_NETWORK_CFG_R,
90*03831d35Sstevel 	    sizeof (dp_get_network_cfg_r_t), RR_TIMEOUT },
91*03831d35Sstevel 	{ DP_RSC_STATUS,	DP_RSC_STATUS_R,
92*03831d35Sstevel 	    sizeof (dp_rsc_status_r_t), RR_TIMEOUT },
93*03831d35Sstevel 	{ DP_USER_ADM,		DP_USER_ADM_R,
94*03831d35Sstevel 	    sizeof (dp_user_adm_r_t), RR_SEPROM_TIMEOUT},
95*03831d35Sstevel 	{ DP_RESET_RSC,		DP_NULL_MSG,
96*03831d35Sstevel 	    0,			1 },
97*03831d35Sstevel 	{ DP_GET_CONSOLE_LOG,	DP_GET_CONSOLE_LOG_R,
98*03831d35Sstevel 	    sizeof (dp_get_console_log_r_t),	RR_TIMEOUT },
99*03831d35Sstevel 	{ DP_GET_CONFIG_LOG,	DP_GET_CONFIG_LOG_R,
100*03831d35Sstevel 	    sizeof (dp_get_config_log_r_t),	RR_TIMEOUT },
101*03831d35Sstevel 	{ DP_GET_EVENT_LOG2,	DP_GET_EVENT_LOG2_R,
102*03831d35Sstevel 	    sizeof (dp_get_event_log2_r_t),	RR_TIMEOUT },
103*03831d35Sstevel };
104*03831d35Sstevel 
105*03831d35Sstevel static const int rr_table_cnt = sizeof (rr_table) / sizeof (rr_table[0]);
106*03831d35Sstevel 
107*03831d35Sstevel 
108*03831d35Sstevel /* lookup table to get timeout value for BP cmd reply. This is in order to */
109*03831d35Sstevel /* support obsolete functions (rscp_send_bpmsg, rsc_raw_write) */
110*03831d35Sstevel 
111*03831d35Sstevel static req_resp_table_t rr_bp_table[] = {
112*03831d35Sstevel 
113*03831d35Sstevel 	{ BP_OBP_BOOTINIT,	NULL,	sizeof (bp_msg_t),
114*03831d35Sstevel 	    RR_BOOT_INIT_TIMEOUT },
115*03831d35Sstevel 	{ BP_OBP_RESET,		NULL,	sizeof (bp_msg_t),
116*03831d35Sstevel 	    RR_BOOT_RESET_TIMEOUT }
117*03831d35Sstevel };
118*03831d35Sstevel 
119*03831d35Sstevel static const int rr_bp_table_cnt =
120*03831d35Sstevel     sizeof (rr_bp_table) / sizeof (rr_bp_table[0]);
121*03831d35Sstevel 
122*03831d35Sstevel static rsci8 unsupported_cmds[] = { DP_SET_DATE_TIME };
123*03831d35Sstevel 
124*03831d35Sstevel static int unsupported_cmds_cnt = sizeof (unsupported_cmds) /
125*03831d35Sstevel     sizeof (unsupported_cmds[0]);
126*03831d35Sstevel 
127*03831d35Sstevel /*
128*03831d35Sstevel  * Protocol version number, used to determine whether ALOM will
129*03831d35Sstevel  * time out on unknown commands.
130*03831d35Sstevel  */
131*03831d35Sstevel static int sdp_version = -1;
132*03831d35Sstevel 
133*03831d35Sstevel /* function prototypes */
134*03831d35Sstevel 
135*03831d35Sstevel static req_resp_table_t *rsc_lookup_rr_table(req_resp_table_t *, int, rsci8);
136*03831d35Sstevel 
137*03831d35Sstevel static int rsc_check_unsupported_cmd(rsci8);
138*03831d35Sstevel 
139*03831d35Sstevel static int rsc_cmd_response_guaranteed(rsci8);
140*03831d35Sstevel 
141*03831d35Sstevel /*
142*03831d35Sstevel  * Initialize the generic librsc data protocol routines. basically, it
143*03831d35Sstevel  * open the rmcadm (pseudo) device and initialize data
144*03831d35Sstevel  */
145*03831d35Sstevel int
rscp_init(void)146*03831d35Sstevel rscp_init(void)
147*03831d35Sstevel {
148*03831d35Sstevel 	rscp_msg_t	request, response;
149*03831d35Sstevel 	dp_get_sdp_version_r_t version_msg;
150*03831d35Sstevel 
151*03831d35Sstevel 	/*
152*03831d35Sstevel 	 * 'erase' the rx buffer
153*03831d35Sstevel 	 */
154*03831d35Sstevel 	(void) memset(rsc_rx_buffer, 0, sizeof (RSC_MAX_RX_BUFFER));
155*03831d35Sstevel 	rsc_rx_resp_len = 0;
156*03831d35Sstevel 	rsc_rx_error = 0;
157*03831d35Sstevel 	rsc_rx_resp_type = DP_NULL_MSG;
158*03831d35Sstevel 
159*03831d35Sstevel 	/*
160*03831d35Sstevel 	 * open rmcadm driver
161*03831d35Sstevel 	 */
162*03831d35Sstevel 	if ((rsc_fd = open(RSC_RMCADM_DRV, O_RDWR)) < 0) {
163*03831d35Sstevel #ifdef DEBUG
164*03831d35Sstevel 		printf("rscp_init: Error opening %s, error code = %d\n",
165*03831d35Sstevel 		    RSC_RMCADM_DRV, errno);
166*03831d35Sstevel #endif
167*03831d35Sstevel 		return (errno);
168*03831d35Sstevel 	}
169*03831d35Sstevel 
170*03831d35Sstevel 	/*
171*03831d35Sstevel 	 * Fetch the protocol version number in use between the host
172*03831d35Sstevel 	 * and ALOM.
173*03831d35Sstevel 	 */
174*03831d35Sstevel 	request.type = DP_GET_SDP_VERSION;
175*03831d35Sstevel 	request.len = 0;
176*03831d35Sstevel 	request.data = 0;
177*03831d35Sstevel 
178*03831d35Sstevel 	response.type = DP_GET_SDP_VERSION_R;
179*03831d35Sstevel 	response.len = sizeof (version_msg);
180*03831d35Sstevel 	response.data = (caddr_t)&version_msg;
181*03831d35Sstevel 
182*03831d35Sstevel 	if ((errno = rscp_send_recv(&request, &response, 0)) != 0)
183*03831d35Sstevel 		return (errno);
184*03831d35Sstevel 
185*03831d35Sstevel 	sdp_version = version_msg.version;
186*03831d35Sstevel 
187*03831d35Sstevel #ifdef DEBUG
188*03831d35Sstevel 	printf("rscp_init: sdp version number is %d\n", sdp_version);
189*03831d35Sstevel #endif
190*03831d35Sstevel 
191*03831d35Sstevel 	return (0);
192*03831d35Sstevel }
193*03831d35Sstevel 
194*03831d35Sstevel /*
195*03831d35Sstevel  * send/receive interface: this is the new interface where application
196*03831d35Sstevel  * (currently scadm, SunVTS) send a request and wait for a reply in a
197*03831d35Sstevel  * single call. If a response is not required (resp=NULL), the function
198*03831d35Sstevel  * will only return the status of the request (whether it has been successfully
199*03831d35Sstevel  * or not).
200*03831d35Sstevel  */
201*03831d35Sstevel int
rscp_send_recv(rscp_msg_t * req,rscp_msg_t * resp,struct timespec * timeout)202*03831d35Sstevel rscp_send_recv(rscp_msg_t *req, rscp_msg_t *resp, struct timespec *timeout)
203*03831d35Sstevel {
204*03831d35Sstevel 	rmcadm_request_response_t	rr;
205*03831d35Sstevel 	rmcadm_msg_t			*rr_req = &rr.req;
206*03831d35Sstevel 	rmcadm_msg_t			*rr_resp = &rr.resp;
207*03831d35Sstevel 
208*03831d35Sstevel 	if (rsc_fd < 0)
209*03831d35Sstevel 		return (EBADF);
210*03831d35Sstevel 
211*03831d35Sstevel 	/*
212*03831d35Sstevel 	 * the request is required, it should not be NULL!
213*03831d35Sstevel 	 */
214*03831d35Sstevel 	if (req == NULL)
215*03831d35Sstevel 		return (EINVAL);
216*03831d35Sstevel 
217*03831d35Sstevel 	/*
218*03831d35Sstevel 	 * Check if the command is actually supported
219*03831d35Sstevel 	 * if not, return an error
220*03831d35Sstevel 	 */
221*03831d35Sstevel 	if (rsc_check_unsupported_cmd(req->type) != 0)
222*03831d35Sstevel 		return (ENOTSUP);
223*03831d35Sstevel 
224*03831d35Sstevel 	/*
225*03831d35Sstevel 	 * Check if this command will generate a response and if it will not,
226*03831d35Sstevel 	 * return an error.
227*03831d35Sstevel 	 */
228*03831d35Sstevel 	if (!rsc_cmd_response_guaranteed(req->type))
229*03831d35Sstevel 		return (ENOTSUP);
230*03831d35Sstevel 
231*03831d35Sstevel 	rr_req->msg_type = req->type;
232*03831d35Sstevel 	rr_req->msg_len = req->len;
233*03831d35Sstevel 	rr_req->msg_buf = (caddr_t)req->data;
234*03831d35Sstevel 
235*03831d35Sstevel 	if (resp != NULL) {
236*03831d35Sstevel 		rr_resp->msg_type = resp->type;
237*03831d35Sstevel 		rr_resp->msg_len = resp->len;
238*03831d35Sstevel 		rr_resp->msg_buf = (caddr_t)resp->data;
239*03831d35Sstevel 		rr_resp->msg_bytes = 0;
240*03831d35Sstevel 	} else {
241*03831d35Sstevel 		rr_resp->msg_type = DP_NULL_MSG;
242*03831d35Sstevel 		rr_resp->msg_buf = (caddr_t)NULL;
243*03831d35Sstevel 		rr_resp->msg_len = 0;
244*03831d35Sstevel 		rr_resp->msg_bytes = 0;
245*03831d35Sstevel 	}
246*03831d35Sstevel 
247*03831d35Sstevel 	if (timeout == NULL) {
248*03831d35Sstevel 		rr.wait_time = RR_TIMEOUT;
249*03831d35Sstevel 	} else {
250*03831d35Sstevel 		rr.wait_time = timeout->tv_sec * 1000 +
251*03831d35Sstevel 		    timeout->tv_nsec / 1000000;
252*03831d35Sstevel 	}
253*03831d35Sstevel 	rr.status = 0;
254*03831d35Sstevel 
255*03831d35Sstevel 	if (ioctl(rsc_fd, RMCADM_REQUEST_RESPONSE, &rr) < 0) {
256*03831d35Sstevel #ifdef DEBUG
257*03831d35Sstevel 		printf("rscp_send_recv: req. failed, status=%d errno=%d\n",
258*03831d35Sstevel 		    rr_req->msg_type, rr.status, errno);
259*03831d35Sstevel #endif
260*03831d35Sstevel 		return (errno);
261*03831d35Sstevel 	}
262*03831d35Sstevel 
263*03831d35Sstevel 	return (0);
264*03831d35Sstevel }
265*03831d35Sstevel 
266*03831d35Sstevel /*
267*03831d35Sstevel  * function used to look up at the request/response table. Given a request
268*03831d35Sstevel  * type, will return a record which provides the following information:
269*03831d35Sstevel  * response expected and a timeout value
270*03831d35Sstevel  */
271*03831d35Sstevel static req_resp_table_t *
rsc_lookup_rr_table(req_resp_table_t * rr_table,int cnt,rsci8 type)272*03831d35Sstevel rsc_lookup_rr_table(req_resp_table_t *rr_table, int cnt, rsci8 type)
273*03831d35Sstevel {
274*03831d35Sstevel 	int	i;
275*03831d35Sstevel 
276*03831d35Sstevel #ifdef DEBUG
277*03831d35Sstevel 	printf("lookup for type %x, count %d\n", type, cnt);
278*03831d35Sstevel #endif
279*03831d35Sstevel 
280*03831d35Sstevel 	for (i = 0; i < cnt; i++)
281*03831d35Sstevel 		if (rr_table[i].req_type == type) {
282*03831d35Sstevel 			return (rr_table + i);
283*03831d35Sstevel 		}
284*03831d35Sstevel 
285*03831d35Sstevel 	return (NULL);
286*03831d35Sstevel }
287*03831d35Sstevel 
288*03831d35Sstevel /*
289*03831d35Sstevel  * function to check if a message type is in the list of unsupported commands
290*03831d35Sstevel  * If so, will return 1.
291*03831d35Sstevel  */
292*03831d35Sstevel static int
rsc_check_unsupported_cmd(rsci8 type)293*03831d35Sstevel rsc_check_unsupported_cmd(rsci8 type)
294*03831d35Sstevel {
295*03831d35Sstevel 	int	i;
296*03831d35Sstevel 
297*03831d35Sstevel 	for (i = 0; i < unsupported_cmds_cnt; i++)
298*03831d35Sstevel 		if (unsupported_cmds[i] == type) {
299*03831d35Sstevel 			return (1);
300*03831d35Sstevel 		}
301*03831d35Sstevel 
302*03831d35Sstevel 	return (0);
303*03831d35Sstevel }
304*03831d35Sstevel 
305*03831d35Sstevel /*
306*03831d35Sstevel  * Returns 1 if ALOM will generate a response to the given command code,
307*03831d35Sstevel  * otherwise it returns 0.  If a command is not in the following list,
308*03831d35Sstevel  * and the protocol version is 2 or less, then ALOM will not generate
309*03831d35Sstevel  * a response to the command.  This causes the driver to time out,
310*03831d35Sstevel  * and we want to avoid that situation.
311*03831d35Sstevel  */
312*03831d35Sstevel static int
rsc_cmd_response_guaranteed(rsci8 type)313*03831d35Sstevel rsc_cmd_response_guaranteed(rsci8 type)
314*03831d35Sstevel {
315*03831d35Sstevel 	switch (type) {
316*03831d35Sstevel 	case DP_GET_ALARM_STATE:
317*03831d35Sstevel 	case DP_GET_CFGVAR:
318*03831d35Sstevel 	case DP_GET_CFGVAR_NAME:
319*03831d35Sstevel 	case DP_GET_CIRCUIT_BRKS:
320*03831d35Sstevel 	case DP_GET_DATE_TIME:
321*03831d35Sstevel 	case DP_GET_DEVICE:
322*03831d35Sstevel 	case DP_GET_EVENT_LOG:
323*03831d35Sstevel 	case DP_GET_FAN_STATUS:
324*03831d35Sstevel 	case DP_GET_FRU_STATUS:
325*03831d35Sstevel 	case DP_GET_HANDLE:
326*03831d35Sstevel 	case DP_GET_HANDLE_NAME:
327*03831d35Sstevel 	case DP_GET_LED_STATE:
328*03831d35Sstevel 	case DP_GET_NETWORK_CFG:
329*03831d35Sstevel 	case DP_GET_PCMCIA_INFO:
330*03831d35Sstevel 	case DP_GET_PSU_STATUS:
331*03831d35Sstevel 	case DP_GET_SDP_VERSION:
332*03831d35Sstevel 	case DP_GET_SYSINFO:
333*03831d35Sstevel 	case DP_GET_TEMP:
334*03831d35Sstevel 	case DP_GET_TEMPERATURES:
335*03831d35Sstevel 	case DP_GET_TICKCNT:
336*03831d35Sstevel 	case DP_GET_TOD_CLOCK:
337*03831d35Sstevel 	case DP_GET_USER_WATCHDOG:
338*03831d35Sstevel 	case DP_GET_VOLTS:
339*03831d35Sstevel 	case DP_MODEM_CONNECT:
340*03831d35Sstevel 	case DP_MODEM_DATA:
341*03831d35Sstevel 	case DP_MODEM_DISCONNECT:
342*03831d35Sstevel 	case DP_RESET_RSC:
343*03831d35Sstevel 	case DP_RMC_EVENTS:
344*03831d35Sstevel 	case DP_RSC_STATUS:
345*03831d35Sstevel 	case DP_RUN_TEST:
346*03831d35Sstevel 	case DP_SEND_ALERT:
347*03831d35Sstevel 	case DP_SET_ALARM_STATE:
348*03831d35Sstevel 	case DP_SET_CFGVAR:
349*03831d35Sstevel 	case DP_SET_CPU_SIGNATURE:
350*03831d35Sstevel 	case DP_SET_DATE_TIME:
351*03831d35Sstevel 	case DP_SET_DEFAULT_CFG:
352*03831d35Sstevel 	case DP_SET_HOST_WATCHDOG:
353*03831d35Sstevel 	case DP_SET_LED_STATE:
354*03831d35Sstevel 	case DP_SET_USER_WATCHDOG:
355*03831d35Sstevel 	case DP_UPDATE_FLASH:
356*03831d35Sstevel 	case DP_USER_ADM:
357*03831d35Sstevel 		return (1);
358*03831d35Sstevel 	default:
359*03831d35Sstevel 		return (sdp_version >= SDP_RESPONDS_TO_ALL_CMDS);
360*03831d35Sstevel 	}
361*03831d35Sstevel }
362*03831d35Sstevel 
363*03831d35Sstevel /*
364*03831d35Sstevel  * RSC hard reset. Returns 0 on success, non-zero on error.
365*03831d35Sstevel  */
366*03831d35Sstevel int
rsc_nmi(void)367*03831d35Sstevel rsc_nmi(void)
368*03831d35Sstevel {
369*03831d35Sstevel 	if (rsc_fd < 0)
370*03831d35Sstevel 		return (EBADF);
371*03831d35Sstevel 
372*03831d35Sstevel 	if (ioctl(rsc_fd, RMCADM_RESET_SP, NULL) < 0)
373*03831d35Sstevel 		return (errno);
374*03831d35Sstevel 
375*03831d35Sstevel 	return (0);
376*03831d35Sstevel }
377*03831d35Sstevel 
378*03831d35Sstevel /*
379*03831d35Sstevel  * functions used (exclusively) for the firmware download
380*03831d35Sstevel  */
381*03831d35Sstevel 
382*03831d35Sstevel /*
383*03831d35Sstevel  * Call this routine to register a callback that will be called by the
384*03831d35Sstevel  * generic data protocol routines when a boot protocol message is
385*03831d35Sstevel  * received.  Only one of these routines may be registered at a time.
386*03831d35Sstevel  * Note that receiving a boot protocol message has the effect of
387*03831d35Sstevel  * re-initializing the data protocol.  Returns 0 on success, or non-
388*03831d35Sstevel  * zero on failure.
389*03831d35Sstevel  */
390*03831d35Sstevel int
rscp_register_bpmsg_cb(rscp_bpmsg_cb_t * cb)391*03831d35Sstevel rscp_register_bpmsg_cb(rscp_bpmsg_cb_t *cb)
392*03831d35Sstevel {
393*03831d35Sstevel 	if (rsc_fd < 0)
394*03831d35Sstevel 		return (EBADF);
395*03831d35Sstevel 
396*03831d35Sstevel 	if (bpmsg_cb == NULL) {
397*03831d35Sstevel 		bpmsg_cb = cb;
398*03831d35Sstevel 		return (0);
399*03831d35Sstevel 	} else {
400*03831d35Sstevel 		return (EALREADY);
401*03831d35Sstevel 	}
402*03831d35Sstevel }
403*03831d35Sstevel 
404*03831d35Sstevel /*
405*03831d35Sstevel  * This routine un-registers a boot protocol message callback.
406*03831d35Sstevel  */
407*03831d35Sstevel int
rscp_unregister_bpmsg_cb(rscp_bpmsg_cb_t * cb)408*03831d35Sstevel rscp_unregister_bpmsg_cb(rscp_bpmsg_cb_t *cb)
409*03831d35Sstevel {
410*03831d35Sstevel 	if (rsc_fd < 0)
411*03831d35Sstevel 		return (EBADF);
412*03831d35Sstevel 
413*03831d35Sstevel 	if (bpmsg_cb == cb) {
414*03831d35Sstevel 		bpmsg_cb = NULL;
415*03831d35Sstevel 		return (0);
416*03831d35Sstevel 	} else {
417*03831d35Sstevel 		return (EINPROGRESS);
418*03831d35Sstevel 	}
419*03831d35Sstevel }
420*03831d35Sstevel 
421*03831d35Sstevel /*
422*03831d35Sstevel  * Call this routine to send a boot protocol message.
423*03831d35Sstevel  */
424*03831d35Sstevel void
rscp_send_bpmsg(bp_msg_t * bpmsg)425*03831d35Sstevel rscp_send_bpmsg(bp_msg_t *bpmsg)
426*03831d35Sstevel {
427*03831d35Sstevel 	rmcadm_request_response_t	rr_bp;
428*03831d35Sstevel 	rmcadm_msg_t			*req_bp = &rr_bp.req;
429*03831d35Sstevel 	rmcadm_msg_t			*resp_bp = &rr_bp.resp;
430*03831d35Sstevel 	req_resp_table_t		*rr_bp_item;
431*03831d35Sstevel 	bp_msg_t			bpmsg_reply;
432*03831d35Sstevel 
433*03831d35Sstevel 	if (rsc_fd < 0 || bpmsg == NULL)
434*03831d35Sstevel 		return;
435*03831d35Sstevel 
436*03831d35Sstevel 	/*
437*03831d35Sstevel 	 * get the timeout value
438*03831d35Sstevel 	 */
439*03831d35Sstevel 	if ((rr_bp_item = rsc_lookup_rr_table(rr_bp_table, rr_bp_table_cnt,
440*03831d35Sstevel 	    bpmsg->cmd)) != NULL) {
441*03831d35Sstevel 
442*03831d35Sstevel 		rr_bp.wait_time = rr_bp_item->timeout;
443*03831d35Sstevel 
444*03831d35Sstevel 	} else {
445*03831d35Sstevel 
446*03831d35Sstevel 		rr_bp.wait_time = RR_BP_TIMEOUT;
447*03831d35Sstevel 	}
448*03831d35Sstevel 
449*03831d35Sstevel 	rr_bp.status = 0;
450*03831d35Sstevel 
451*03831d35Sstevel 	req_bp->msg_len = sizeof (bp_msg_t);
452*03831d35Sstevel 	req_bp->msg_buf = (caddr_t)bpmsg;
453*03831d35Sstevel 
454*03831d35Sstevel 	if (rr_bp.wait_time == 0) {
455*03831d35Sstevel 		resp_bp->msg_buf = (caddr_t)NULL;
456*03831d35Sstevel 	} else {
457*03831d35Sstevel 		resp_bp->msg_len = sizeof (bp_msg_t);
458*03831d35Sstevel 		resp_bp->msg_buf = (caddr_t)&bpmsg_reply;
459*03831d35Sstevel 	}
460*03831d35Sstevel 
461*03831d35Sstevel #ifdef DEBUG
462*03831d35Sstevel 	printf("send BP cmd %x, expect reply %x/%d\n",
463*03831d35Sstevel 	    bpmsg->cmd, resp_bp->msg_buf, resp_bp->msg_len);
464*03831d35Sstevel #endif
465*03831d35Sstevel 	if (ioctl(rsc_fd, RMCADM_REQUEST_RESPONSE_BP, &rr_bp) < 0) {
466*03831d35Sstevel #ifdef DEBUG
467*03831d35Sstevel 		printf("rscp_send_bpmsg: BP cmd %x failed status=%d "
468*03831d35Sstevel 		    "errno=%d\n", bpmsg->cmd, rr_bp.status, errno);
469*03831d35Sstevel #endif
470*03831d35Sstevel 		return;
471*03831d35Sstevel 	}
472*03831d35Sstevel 
473*03831d35Sstevel #ifdef DEBUG
474*03831d35Sstevel 	printf("got BP reply type=%x,%x,%x\n",
475*03831d35Sstevel 	    bpmsg_reply.cmd, bpmsg_reply.dat1, bpmsg_reply.dat2);
476*03831d35Sstevel #endif
477*03831d35Sstevel 
478*03831d35Sstevel 	/*
479*03831d35Sstevel 	 * reply received. call the registered callback (if any)
480*03831d35Sstevel 	 */
481*03831d35Sstevel 	if (bpmsg_cb != NULL && resp_bp->msg_buf != NULL)
482*03831d35Sstevel 		bpmsg_cb(&bpmsg_reply);
483*03831d35Sstevel }
484*03831d35Sstevel 
485*03831d35Sstevel /*
486*03831d35Sstevel  * Write raw characters to the RSC control device.  Returns 0 on success,
487*03831d35Sstevel  * non-zero on error.
488*03831d35Sstevel  */
489*03831d35Sstevel int
rsc_raw_write(char * buf,int nbytes)490*03831d35Sstevel rsc_raw_write(char *buf, int nbytes)
491*03831d35Sstevel {
492*03831d35Sstevel 	rmcadm_send_srecord_bp_t	srec_bp;
493*03831d35Sstevel 	bp_msg_t			bpmsg_reply;
494*03831d35Sstevel 
495*03831d35Sstevel 	if (rsc_fd < 0)
496*03831d35Sstevel 		return (EBADF);
497*03831d35Sstevel 
498*03831d35Sstevel 	srec_bp.data_len = (uint_t)nbytes;
499*03831d35Sstevel 	srec_bp.data_buf = (caddr_t)buf;
500*03831d35Sstevel 	srec_bp.resp_bp.msg_len = sizeof (bp_msg_t);
501*03831d35Sstevel 	srec_bp.resp_bp.msg_buf = (caddr_t)&bpmsg_reply;
502*03831d35Sstevel 	srec_bp.wait_time = RR_BOOT_LOAD_TIMEOUT;
503*03831d35Sstevel 	srec_bp.status = 0;
504*03831d35Sstevel 
505*03831d35Sstevel #ifdef DEBUG
506*03831d35Sstevel 	printf("send srecord BP len=%d\n", nbytes);
507*03831d35Sstevel #endif
508*03831d35Sstevel 	if (ioctl(rsc_fd, RMCADM_SEND_SRECORD_BP, &srec_bp) < 0) {
509*03831d35Sstevel #ifdef DEBUG
510*03831d35Sstevel 		printf("rsc_raw_write: failed. status=%d ioctl error=%d\n",
511*03831d35Sstevel 		    srec_bp.status, errno);
512*03831d35Sstevel #endif
513*03831d35Sstevel 		return (errno);
514*03831d35Sstevel 	}
515*03831d35Sstevel 
516*03831d35Sstevel #ifdef DEBUG
517*03831d35Sstevel 	printf("got BP reply type=%x\n", bpmsg_reply.cmd);
518*03831d35Sstevel #endif
519*03831d35Sstevel 
520*03831d35Sstevel 	/*
521*03831d35Sstevel 	 * reply received. call the registered callback (if any)
522*03831d35Sstevel 	 */
523*03831d35Sstevel 	if (bpmsg_cb != NULL)
524*03831d35Sstevel 		bpmsg_cb(&bpmsg_reply);
525*03831d35Sstevel 
526*03831d35Sstevel 	return (0);
527*03831d35Sstevel }
528*03831d35Sstevel 
529*03831d35Sstevel /*
530*03831d35Sstevel  * obsolete functions provided for backward compatibility
531*03831d35Sstevel  */
532*03831d35Sstevel 
533*03831d35Sstevel /*
534*03831d35Sstevel  * This function is obsolete and it is provided for backward compatibility.
535*03831d35Sstevel  * (no-op function). It was used to start up the data protocol. low-level
536*03831d35Sstevel  * protocol has moved to the kernel and the rmc_comm driver is responsible
537*03831d35Sstevel  * for setting up the data protocol.
538*03831d35Sstevel  * (obsolete)
539*03831d35Sstevel  */
540*03831d35Sstevel int
rscp_start(void)541*03831d35Sstevel rscp_start(void)
542*03831d35Sstevel {
543*03831d35Sstevel 	if (rsc_fd < 0)
544*03831d35Sstevel 		return (EBADF);
545*03831d35Sstevel 
546*03831d35Sstevel 	return (0);
547*03831d35Sstevel }
548*03831d35Sstevel 
549*03831d35Sstevel /*
550*03831d35Sstevel  * This function is obsolete and it is provided for backward compatibility.
551*03831d35Sstevel  * Previously, rscp_send() and rscp_recv() where used to send a request and
552*03831d35Sstevel  * read a reply respectively. Now, rscp_send_recv() should be used instead
553*03831d35Sstevel  * (request/response in one call).
554*03831d35Sstevel  *
555*03831d35Sstevel  * This is used to send a message by making an RMCADM_REQUEST_RESPONSE ioctl
556*03831d35Sstevel  * call. A lookup table (rr_table) is used to find out the expected reply
557*03831d35Sstevel  * (if any) and the timeout value for a message to be sent. The reply is then
558*03831d35Sstevel  * stored in a buffer (rsc_rx_buffer) to be returned by calling rscp_recv()
559*03831d35Sstevel  */
560*03831d35Sstevel int
rscp_send(rscp_msg_t * msgp)561*03831d35Sstevel rscp_send(rscp_msg_t *msgp)
562*03831d35Sstevel {
563*03831d35Sstevel 	rmcadm_request_response_t	 rr;
564*03831d35Sstevel 	rmcadm_msg_t			*req = &rr.req;
565*03831d35Sstevel 	rmcadm_msg_t			*resp = &rr.resp;
566*03831d35Sstevel 	req_resp_table_t		*rr_item;
567*03831d35Sstevel 
568*03831d35Sstevel 	if (rsc_fd < 0)
569*03831d35Sstevel 		return (EBADF);
570*03831d35Sstevel 
571*03831d35Sstevel 	/*
572*03831d35Sstevel 	 * sanity check
573*03831d35Sstevel 	 */
574*03831d35Sstevel 	if (msgp == NULL)
575*03831d35Sstevel 		return (EINVAL);
576*03831d35Sstevel 
577*03831d35Sstevel 	/*
578*03831d35Sstevel 	 * Check if the command is actually supported
579*03831d35Sstevel 	 * if not, return an error
580*03831d35Sstevel 	 */
581*03831d35Sstevel 	if (rsc_check_unsupported_cmd(msgp->type) != 0)
582*03831d35Sstevel 		return (ENOTSUP);
583*03831d35Sstevel 
584*03831d35Sstevel 	/*
585*03831d35Sstevel 	 * Check if this command will generate a response and if it will not,
586*03831d35Sstevel 	 * return an error.
587*03831d35Sstevel 	 */
588*03831d35Sstevel 	if (!rsc_cmd_response_guaranteed(msgp->type))
589*03831d35Sstevel 		return (ENOTSUP);
590*03831d35Sstevel 
591*03831d35Sstevel 	/*
592*03831d35Sstevel 	 * init rx buffer
593*03831d35Sstevel 	 */
594*03831d35Sstevel 	rsc_rx_resp_len = 0;
595*03831d35Sstevel 	rsc_rx_error = 0;
596*03831d35Sstevel 
597*03831d35Sstevel 	req->msg_type = msgp->type;
598*03831d35Sstevel 	req->msg_len = msgp->len;
599*03831d35Sstevel 	req->msg_buf = msgp->data;
600*03831d35Sstevel 
601*03831d35Sstevel 	if ((rr_item = rsc_lookup_rr_table(rr_table, rr_table_cnt,
602*03831d35Sstevel 	    msgp->type)) != NULL) {
603*03831d35Sstevel 		resp->msg_type = rr_item->resp_type;
604*03831d35Sstevel 		if (rr_item->resp_type == DP_NULL_MSG) {
605*03831d35Sstevel 			/*
606*03831d35Sstevel 			 * no reply expected. so, no reply buffer needed
607*03831d35Sstevel 			 * (set to NULL)
608*03831d35Sstevel 			 */
609*03831d35Sstevel 			resp->msg_len = 0;
610*03831d35Sstevel 			resp->msg_buf = (caddr_t)NULL;
611*03831d35Sstevel 		} else {
612*03831d35Sstevel 			resp->msg_len = RSC_MAX_RX_BUFFER;
613*03831d35Sstevel 			resp->msg_buf = (caddr_t)rsc_rx_buffer;
614*03831d35Sstevel 		}
615*03831d35Sstevel 
616*03831d35Sstevel 		rr.wait_time = rr_item->timeout;
617*03831d35Sstevel 		rsc_rx_resp_type = rr_item->resp_type;
618*03831d35Sstevel 	} else {
619*03831d35Sstevel 		return (ENOTSUP);
620*03831d35Sstevel 	}
621*03831d35Sstevel 	rr.status = 0;
622*03831d35Sstevel 
623*03831d35Sstevel #ifdef DEBUG
624*03831d35Sstevel 	printf("request/response %x/%x\n", req->msg_type, resp->msg_type);
625*03831d35Sstevel #endif
626*03831d35Sstevel 	if (ioctl(rsc_fd, RMCADM_REQUEST_RESPONSE, &rr) < 0) {
627*03831d35Sstevel #ifdef DEBUG
628*03831d35Sstevel 		printf("rscp_send: req %x failed, status=%d errno=%d\n",
629*03831d35Sstevel 		    rr.req.msg_type, rr.status, errno);
630*03831d35Sstevel #endif
631*03831d35Sstevel 		rsc_rx_error = errno;
632*03831d35Sstevel 
633*03831d35Sstevel 		return (errno);
634*03831d35Sstevel 	}
635*03831d35Sstevel 
636*03831d35Sstevel 	/*
637*03831d35Sstevel 	 * reply received. get the number of bytes effectively returned
638*03831d35Sstevel 	 */
639*03831d35Sstevel 	rsc_rx_resp_len = resp->msg_bytes;
640*03831d35Sstevel 	rsc_rx_resp_type = resp->msg_type;
641*03831d35Sstevel 
642*03831d35Sstevel #ifdef DEBUG
643*03831d35Sstevel 	printf("got reply type=%x len=%d\n", rsc_rx_resp_type, rsc_rx_resp_len);
644*03831d35Sstevel #endif
645*03831d35Sstevel 
646*03831d35Sstevel 	return (0);
647*03831d35Sstevel }
648*03831d35Sstevel 
649*03831d35Sstevel /*
650*03831d35Sstevel  * This function is obsolete and it is provided for backward compatibility
651*03831d35Sstevel  * Previously, rscp_send() and rscp_recv() where used to send a request and
652*03831d35Sstevel  * read a reply repectively. Now, rscp_send_recv() should be used instead
653*03831d35Sstevel  * (request/response in one call).
654*03831d35Sstevel  *
655*03831d35Sstevel  * This function returns the reply received when a request was previously sent
656*03831d35Sstevel  * using the rscp_send() function (stored in the rsc_rx_buffer buffer). If a
657*03831d35Sstevel  * reply was not received, then an error is returned.
658*03831d35Sstevel  *
659*03831d35Sstevel  * timeout parameter is declared for backward compatibility but it is not used.
660*03831d35Sstevel  */
661*03831d35Sstevel /*ARGSUSED*/
662*03831d35Sstevel int
rscp_recv(rscp_msg_t * msgp,struct timespec * timeout)663*03831d35Sstevel rscp_recv(rscp_msg_t *msgp, struct timespec *timeout)
664*03831d35Sstevel {
665*03831d35Sstevel 	int err = 0;
666*03831d35Sstevel 
667*03831d35Sstevel 	if (rsc_fd < 0)
668*03831d35Sstevel 		return (EBADF);
669*03831d35Sstevel 
670*03831d35Sstevel 	/*
671*03831d35Sstevel 	 * sanity check
672*03831d35Sstevel 	 */
673*03831d35Sstevel 	if (msgp == NULL)
674*03831d35Sstevel 		return (EINVAL);
675*03831d35Sstevel 
676*03831d35Sstevel 	if (rsc_rx_error < 0) {
677*03831d35Sstevel 		msgp->type = DP_NULL_MSG;
678*03831d35Sstevel 		msgp->len = 0;
679*03831d35Sstevel 		msgp->data = NULL;
680*03831d35Sstevel 
681*03831d35Sstevel 		err = rsc_rx_error;
682*03831d35Sstevel 
683*03831d35Sstevel 	} else {
684*03831d35Sstevel 		msgp->type = rsc_rx_resp_type;
685*03831d35Sstevel 		msgp->len = rsc_rx_resp_len;
686*03831d35Sstevel 		msgp->data = rsc_rx_buffer;
687*03831d35Sstevel 	}
688*03831d35Sstevel 
689*03831d35Sstevel #ifdef DEBUG
690*03831d35Sstevel 	printf("read reply. type=%x, err=%d\n", msgp->type, err);
691*03831d35Sstevel #endif
692*03831d35Sstevel 
693*03831d35Sstevel 	rsc_rx_resp_len = 0;
694*03831d35Sstevel 	rsc_rx_error = 0;
695*03831d35Sstevel 	rsc_rx_resp_type = DP_NULL_MSG;
696*03831d35Sstevel 
697*03831d35Sstevel 	return (err);
698*03831d35Sstevel }
699*03831d35Sstevel 
700*03831d35Sstevel /*
701*03831d35Sstevel  * used to free up a (received) message. no-op function
702*03831d35Sstevel  */
703*03831d35Sstevel /*ARGSUSED*/
704*03831d35Sstevel int
rscp_free_msg(rscp_msg_t * msgp)705*03831d35Sstevel rscp_free_msg(rscp_msg_t *msgp)
706*03831d35Sstevel {
707*03831d35Sstevel 	if (rsc_fd < 0)
708*03831d35Sstevel 		return (EBADF);
709*03831d35Sstevel 
710*03831d35Sstevel 	return (0);
711*03831d35Sstevel }
712