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