103831d35Sstevel /*
203831d35Sstevel  * CDDL HEADER START
303831d35Sstevel  *
403831d35Sstevel  * The contents of this file are subject to the terms of the
503831d35Sstevel  * Common Development and Distribution License (the "License").
603831d35Sstevel  * You may not use this file except in compliance with the License.
703831d35Sstevel  *
803831d35Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
903831d35Sstevel  * or http://www.opensolaris.org/os/licensing.
1003831d35Sstevel  * See the License for the specific language governing permissions
1103831d35Sstevel  * and limitations under the License.
1203831d35Sstevel  *
1303831d35Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
1403831d35Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1503831d35Sstevel  * If applicable, add the following below this CDDL HEADER, with the
1603831d35Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
1703831d35Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
1803831d35Sstevel  *
1903831d35Sstevel  * CDDL HEADER END
2003831d35Sstevel  */
2103831d35Sstevel 
2203831d35Sstevel /*
2303831d35Sstevel  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
2403831d35Sstevel  * Use is subject to license terms.
2503831d35Sstevel  */
2603831d35Sstevel 
2703831d35Sstevel /*
2803831d35Sstevel  * ENXS platform-specific functions
2903831d35Sstevel  */
3003831d35Sstevel 
3103831d35Sstevel #include <stdio.h>
3203831d35Sstevel #include <stdlib.h>
3303831d35Sstevel #include <unistd.h>
3403831d35Sstevel #include <string.h>
3503831d35Sstevel #include <assert.h>
3603831d35Sstevel #include <fcntl.h>
3703831d35Sstevel #include <errno.h>
3803831d35Sstevel #include <sys/types.h>
3903831d35Sstevel #include <sys/stat.h>
4003831d35Sstevel 
4103831d35Sstevel #include "librsc.h"
4203831d35Sstevel 
4303831d35Sstevel /* rmcadm driver file descriptor */
4403831d35Sstevel static int rsc_fd = -1;
4503831d35Sstevel 
4603831d35Sstevel /*
4703831d35Sstevel  * librsc receive buffer - it is used as temporary buffer to store replies
4803831d35Sstevel  * from the remote side
4903831d35Sstevel  */
5003831d35Sstevel 
5103831d35Sstevel static uchar_t rsc_rx_buffer[RSC_MAX_RX_BUFFER];
5203831d35Sstevel static int rsc_rx_resp_len = 0;
5303831d35Sstevel static int rsc_rx_error = 0;
5403831d35Sstevel static rsci8 rsc_rx_resp_type = 0;
5503831d35Sstevel 
5603831d35Sstevel /*
5703831d35Sstevel  * Registered boot-protocol message callback routine.  This routine will be
5803831d35Sstevel  * called whenever a boot protocol message is received.
5903831d35Sstevel  */
6003831d35Sstevel static rscp_bpmsg_cb_t *bpmsg_cb;
6103831d35Sstevel 
6203831d35Sstevel 
6303831d35Sstevel 
6403831d35Sstevel /* lookup table to match request and response . This is in order to support */
6503831d35Sstevel /* obsolete functions (rscp_send, rscp_recv) */
6603831d35Sstevel 
6703831d35Sstevel static req_resp_table_t rr_table[] = {
6803831d35Sstevel 
6903831d35Sstevel 	{ DP_GET_DATE_TIME,	DP_GET_DATE_TIME_R,
7003831d35Sstevel 	    sizeof (dp_get_date_time_r_t), RR_TIMEOUT },
7103831d35Sstevel 	{ DP_SET_DATE_TIME,	DP_SET_DATE_TIME_R,
7203831d35Sstevel 	    sizeof (dp_set_date_time_r_t), RR_TIMEOUT },
7303831d35Sstevel 	{ DP_GET_EVENT_LOG,	DP_GET_EVENT_LOG_R,
7403831d35Sstevel 	    sizeof (dp_get_event_log_r_t), RR_TIMEOUT },
7503831d35Sstevel 	{ DP_MODEM_CONNECT,	DP_MODEM_CONNECT_R,
7603831d35Sstevel 	    sizeof (dp_modem_connect_r_t), RR_TIMEOUT },
7703831d35Sstevel 	{ DP_MODEM_DISCONNECT,	DP_MODEM_DISCONNECT_R,
7803831d35Sstevel 	    sizeof (dp_modem_disconnect_r_t), RR_TIMEOUT },
7903831d35Sstevel 	{ DP_SEND_ALERT,	DP_SEND_ALERT_R,
8003831d35Sstevel 	    sizeof (dp_send_alert_r_t), RR_TIMEOUT },
8103831d35Sstevel 	{ DP_SET_CFGVAR,	DP_SET_CFGVAR_R,
8203831d35Sstevel 	    sizeof (dp_set_cfgvar_r_t), RR_TIMEOUT },
8303831d35Sstevel 	{ DP_GET_CFGVAR,	DP_GET_CFGVAR_R,
8403831d35Sstevel 	    sizeof (dp_get_cfgvar_r_t), RR_TIMEOUT },
8503831d35Sstevel 	{ DP_GET_CFGVAR_NAME,	DP_GET_CFGVAR_NAME_R,
8603831d35Sstevel 	    sizeof (dp_get_cfgvar_name_r_t), RR_TIMEOUT },
8703831d35Sstevel 	{ DP_GET_NETWORK_CFG,	DP_GET_NETWORK_CFG_R,
8803831d35Sstevel 	    sizeof (dp_get_network_cfg_r_t), RR_TIMEOUT },
8903831d35Sstevel 	{ DP_RSC_STATUS,	DP_RSC_STATUS_R,
9003831d35Sstevel 	    sizeof (dp_rsc_status_r_t), RR_TIMEOUT },
9103831d35Sstevel 	{ DP_USER_ADM,		DP_USER_ADM_R,
9203831d35Sstevel 	    sizeof (dp_user_adm_r_t), RR_SEPROM_TIMEOUT},
9303831d35Sstevel 	{ DP_RESET_RSC,		DP_NULL_MSG,
9403831d35Sstevel 	    0,			1 },
9503831d35Sstevel 	{ DP_GET_CONSOLE_LOG,	DP_GET_CONSOLE_LOG_R,
9603831d35Sstevel 	    sizeof (dp_get_console_log_r_t),	RR_TIMEOUT },
9703831d35Sstevel 	{ DP_GET_CONFIG_LOG,	DP_GET_CONFIG_LOG_R,
9803831d35Sstevel 	    sizeof (dp_get_config_log_r_t),	RR_TIMEOUT },
9903831d35Sstevel 	{ DP_GET_EVENT_LOG2,	DP_GET_EVENT_LOG2_R,
10003831d35Sstevel 	    sizeof (dp_get_event_log2_r_t),	RR_TIMEOUT },
10103831d35Sstevel };
10203831d35Sstevel 
10303831d35Sstevel static const int rr_table_cnt = sizeof (rr_table) / sizeof (rr_table[0]);
10403831d35Sstevel 
10503831d35Sstevel 
10603831d35Sstevel /* lookup table to get timeout value for BP cmd reply. This is in order to */
10703831d35Sstevel /* support obsolete functions (rscp_send_bpmsg, rsc_raw_write) */
10803831d35Sstevel 
10903831d35Sstevel static req_resp_table_t rr_bp_table[] = {
11003831d35Sstevel 
111*f9c7ecc9SToomas Soome 	{ BP_OBP_BOOTINIT,	0,	sizeof (bp_msg_t),
11203831d35Sstevel 	    RR_BOOT_INIT_TIMEOUT },
113*f9c7ecc9SToomas Soome 	{ BP_OBP_RESET,		0,	sizeof (bp_msg_t),
11403831d35Sstevel 	    RR_BOOT_RESET_TIMEOUT }
11503831d35Sstevel };
11603831d35Sstevel 
11703831d35Sstevel static const int rr_bp_table_cnt =
11803831d35Sstevel     sizeof (rr_bp_table) / sizeof (rr_bp_table[0]);
11903831d35Sstevel 
12003831d35Sstevel static rsci8 unsupported_cmds[] = { DP_SET_DATE_TIME };
12103831d35Sstevel 
12203831d35Sstevel static int unsupported_cmds_cnt = sizeof (unsupported_cmds) /
12303831d35Sstevel     sizeof (unsupported_cmds[0]);
12403831d35Sstevel 
12503831d35Sstevel /*
12603831d35Sstevel  * Protocol version number, used to determine whether ALOM will
12703831d35Sstevel  * time out on unknown commands.
12803831d35Sstevel  */
12903831d35Sstevel static int sdp_version = -1;
13003831d35Sstevel 
13103831d35Sstevel /* function prototypes */
13203831d35Sstevel 
13303831d35Sstevel static req_resp_table_t *rsc_lookup_rr_table(req_resp_table_t *, int, rsci8);
13403831d35Sstevel 
13503831d35Sstevel static int rsc_check_unsupported_cmd(rsci8);
13603831d35Sstevel 
13703831d35Sstevel static int rsc_cmd_response_guaranteed(rsci8);
13803831d35Sstevel 
13903831d35Sstevel /*
14003831d35Sstevel  * Initialize the generic librsc data protocol routines. basically, it
14103831d35Sstevel  * open the rmcadm (pseudo) device and initialize data
14203831d35Sstevel  */
14303831d35Sstevel int
rscp_init(void)14403831d35Sstevel rscp_init(void)
14503831d35Sstevel {
14603831d35Sstevel 	rscp_msg_t	request, response;
14703831d35Sstevel 	dp_get_sdp_version_r_t version_msg;
14803831d35Sstevel 
14903831d35Sstevel 	/*
15003831d35Sstevel 	 * 'erase' the rx buffer
15103831d35Sstevel 	 */
15213b136d3SToomas Soome 	(void) memset(rsc_rx_buffer, 0, sizeof (rsc_rx_buffer));
15303831d35Sstevel 	rsc_rx_resp_len = 0;
15403831d35Sstevel 	rsc_rx_error = 0;
15503831d35Sstevel 	rsc_rx_resp_type = DP_NULL_MSG;
15603831d35Sstevel 
15703831d35Sstevel 	/*
15803831d35Sstevel 	 * open rmcadm driver
15903831d35Sstevel 	 */
16003831d35Sstevel 	if ((rsc_fd = open(RSC_RMCADM_DRV, O_RDWR)) < 0) {
16103831d35Sstevel #ifdef DEBUG
16203831d35Sstevel 		printf("rscp_init: Error opening %s, error code = %d\n",
16303831d35Sstevel 		    RSC_RMCADM_DRV, errno);
16403831d35Sstevel #endif
16503831d35Sstevel 		return (errno);
16603831d35Sstevel 	}
16703831d35Sstevel 
16803831d35Sstevel 	/*
16903831d35Sstevel 	 * Fetch the protocol version number in use between the host
17003831d35Sstevel 	 * and ALOM.
17103831d35Sstevel 	 */
17203831d35Sstevel 	request.type = DP_GET_SDP_VERSION;
17303831d35Sstevel 	request.len = 0;
17403831d35Sstevel 	request.data = 0;
17503831d35Sstevel 
17603831d35Sstevel 	response.type = DP_GET_SDP_VERSION_R;
17703831d35Sstevel 	response.len = sizeof (version_msg);
17803831d35Sstevel 	response.data = (caddr_t)&version_msg;
17903831d35Sstevel 
18003831d35Sstevel 	if ((errno = rscp_send_recv(&request, &response, 0)) != 0)
18103831d35Sstevel 		return (errno);
18203831d35Sstevel 
18303831d35Sstevel 	sdp_version = version_msg.version;
18403831d35Sstevel 
18503831d35Sstevel #ifdef DEBUG
18603831d35Sstevel 	printf("rscp_init: sdp version number is %d\n", sdp_version);
18703831d35Sstevel #endif
18803831d35Sstevel 
18903831d35Sstevel 	return (0);
19003831d35Sstevel }
19103831d35Sstevel 
19203831d35Sstevel /*
19303831d35Sstevel  * send/receive interface: this is the new interface where application
19403831d35Sstevel  * (currently scadm, SunVTS) send a request and wait for a reply in a
19503831d35Sstevel  * single call. If a response is not required (resp=NULL), the function
19603831d35Sstevel  * will only return the status of the request (whether it has been successfully
19703831d35Sstevel  * or not).
19803831d35Sstevel  */
19903831d35Sstevel int
rscp_send_recv(rscp_msg_t * req,rscp_msg_t * resp,struct timespec * timeout)20003831d35Sstevel rscp_send_recv(rscp_msg_t *req, rscp_msg_t *resp, struct timespec *timeout)
20103831d35Sstevel {
20203831d35Sstevel 	rmcadm_request_response_t	rr;
20303831d35Sstevel 	rmcadm_msg_t			*rr_req = &rr.req;
20403831d35Sstevel 	rmcadm_msg_t			*rr_resp = &rr.resp;
20503831d35Sstevel 
20603831d35Sstevel 	if (rsc_fd < 0)
20703831d35Sstevel 		return (EBADF);
20803831d35Sstevel 
20903831d35Sstevel 	/*
21003831d35Sstevel 	 * the request is required, it should not be NULL!
21103831d35Sstevel 	 */
21203831d35Sstevel 	if (req == NULL)
21303831d35Sstevel 		return (EINVAL);
21403831d35Sstevel 
21503831d35Sstevel 	/*
21603831d35Sstevel 	 * Check if the command is actually supported
21703831d35Sstevel 	 * if not, return an error
21803831d35Sstevel 	 */
21903831d35Sstevel 	if (rsc_check_unsupported_cmd(req->type) != 0)
22003831d35Sstevel 		return (ENOTSUP);
22103831d35Sstevel 
22203831d35Sstevel 	/*
22303831d35Sstevel 	 * Check if this command will generate a response and if it will not,
22403831d35Sstevel 	 * return an error.
22503831d35Sstevel 	 */
22603831d35Sstevel 	if (!rsc_cmd_response_guaranteed(req->type))
22703831d35Sstevel 		return (ENOTSUP);
22803831d35Sstevel 
22903831d35Sstevel 	rr_req->msg_type = req->type;
23003831d35Sstevel 	rr_req->msg_len = req->len;
23103831d35Sstevel 	rr_req->msg_buf = (caddr_t)req->data;
23203831d35Sstevel 
23303831d35Sstevel 	if (resp != NULL) {
23403831d35Sstevel 		rr_resp->msg_type = resp->type;
23503831d35Sstevel 		rr_resp->msg_len = resp->len;
23603831d35Sstevel 		rr_resp->msg_buf = (caddr_t)resp->data;
23703831d35Sstevel 		rr_resp->msg_bytes = 0;
23803831d35Sstevel 	} else {
23903831d35Sstevel 		rr_resp->msg_type = DP_NULL_MSG;
24003831d35Sstevel 		rr_resp->msg_buf = (caddr_t)NULL;
24103831d35Sstevel 		rr_resp->msg_len = 0;
24203831d35Sstevel 		rr_resp->msg_bytes = 0;
24303831d35Sstevel 	}
24403831d35Sstevel 
24503831d35Sstevel 	if (timeout == NULL) {
24603831d35Sstevel 		rr.wait_time = RR_TIMEOUT;
24703831d35Sstevel 	} else {
24803831d35Sstevel 		rr.wait_time = timeout->tv_sec * 1000 +
24903831d35Sstevel 		    timeout->tv_nsec / 1000000;
25003831d35Sstevel 	}
25103831d35Sstevel 	rr.status = 0;
25203831d35Sstevel 
25303831d35Sstevel 	if (ioctl(rsc_fd, RMCADM_REQUEST_RESPONSE, &rr) < 0) {
25403831d35Sstevel #ifdef DEBUG
25503831d35Sstevel 		printf("rscp_send_recv: req. failed, status=%d errno=%d\n",
25603831d35Sstevel 		    rr_req->msg_type, rr.status, errno);
25703831d35Sstevel #endif
25803831d35Sstevel 		return (errno);
25903831d35Sstevel 	}
26003831d35Sstevel 
26103831d35Sstevel 	return (0);
26203831d35Sstevel }
26303831d35Sstevel 
26403831d35Sstevel /*
26503831d35Sstevel  * function used to look up at the request/response table. Given a request
26603831d35Sstevel  * type, will return a record which provides the following information:
26703831d35Sstevel  * response expected and a timeout value
26803831d35Sstevel  */
26903831d35Sstevel static req_resp_table_t *
rsc_lookup_rr_table(req_resp_table_t * rr_table,int cnt,rsci8 type)27003831d35Sstevel rsc_lookup_rr_table(req_resp_table_t *rr_table, int cnt, rsci8 type)
27103831d35Sstevel {
27203831d35Sstevel 	int	i;
27303831d35Sstevel 
27403831d35Sstevel #ifdef DEBUG
27503831d35Sstevel 	printf("lookup for type %x, count %d\n", type, cnt);
27603831d35Sstevel #endif
27703831d35Sstevel 
27803831d35Sstevel 	for (i = 0; i < cnt; i++)
27903831d35Sstevel 		if (rr_table[i].req_type == type) {
28003831d35Sstevel 			return (rr_table + i);
28103831d35Sstevel 		}
28203831d35Sstevel 
28303831d35Sstevel 	return (NULL);
28403831d35Sstevel }
28503831d35Sstevel 
28603831d35Sstevel /*
28703831d35Sstevel  * function to check if a message type is in the list of unsupported commands
28803831d35Sstevel  * If so, will return 1.
28903831d35Sstevel  */
29003831d35Sstevel static int
rsc_check_unsupported_cmd(rsci8 type)29103831d35Sstevel rsc_check_unsupported_cmd(rsci8 type)
29203831d35Sstevel {
29303831d35Sstevel 	int	i;
29403831d35Sstevel 
29503831d35Sstevel 	for (i = 0; i < unsupported_cmds_cnt; i++)
29603831d35Sstevel 		if (unsupported_cmds[i] == type) {
29703831d35Sstevel 			return (1);
29803831d35Sstevel 		}
29903831d35Sstevel 
30003831d35Sstevel 	return (0);
30103831d35Sstevel }
30203831d35Sstevel 
30303831d35Sstevel /*
30403831d35Sstevel  * Returns 1 if ALOM will generate a response to the given command code,
30503831d35Sstevel  * otherwise it returns 0.  If a command is not in the following list,
30603831d35Sstevel  * and the protocol version is 2 or less, then ALOM will not generate
30703831d35Sstevel  * a response to the command.  This causes the driver to time out,
30803831d35Sstevel  * and we want to avoid that situation.
30903831d35Sstevel  */
31003831d35Sstevel static int
rsc_cmd_response_guaranteed(rsci8 type)31103831d35Sstevel rsc_cmd_response_guaranteed(rsci8 type)
31203831d35Sstevel {
31303831d35Sstevel 	switch (type) {
31403831d35Sstevel 	case DP_GET_ALARM_STATE:
31503831d35Sstevel 	case DP_GET_CFGVAR:
31603831d35Sstevel 	case DP_GET_CFGVAR_NAME:
31703831d35Sstevel 	case DP_GET_CIRCUIT_BRKS:
31803831d35Sstevel 	case DP_GET_DATE_TIME:
31903831d35Sstevel 	case DP_GET_DEVICE:
32003831d35Sstevel 	case DP_GET_EVENT_LOG:
32103831d35Sstevel 	case DP_GET_FAN_STATUS:
32203831d35Sstevel 	case DP_GET_FRU_STATUS:
32303831d35Sstevel 	case DP_GET_HANDLE:
32403831d35Sstevel 	case DP_GET_HANDLE_NAME:
32503831d35Sstevel 	case DP_GET_LED_STATE:
32603831d35Sstevel 	case DP_GET_NETWORK_CFG:
32703831d35Sstevel 	case DP_GET_PCMCIA_INFO:
32803831d35Sstevel 	case DP_GET_PSU_STATUS:
32903831d35Sstevel 	case DP_GET_SDP_VERSION:
33003831d35Sstevel 	case DP_GET_SYSINFO:
33103831d35Sstevel 	case DP_GET_TEMP:
33203831d35Sstevel 	case DP_GET_TEMPERATURES:
33303831d35Sstevel 	case DP_GET_TICKCNT:
33403831d35Sstevel 	case DP_GET_TOD_CLOCK:
33503831d35Sstevel 	case DP_GET_USER_WATCHDOG:
33603831d35Sstevel 	case DP_GET_VOLTS:
33703831d35Sstevel 	case DP_MODEM_CONNECT:
33803831d35Sstevel 	case DP_MODEM_DATA:
33903831d35Sstevel 	case DP_MODEM_DISCONNECT:
34003831d35Sstevel 	case DP_RESET_RSC:
34103831d35Sstevel 	case DP_RMC_EVENTS:
34203831d35Sstevel 	case DP_RSC_STATUS:
34303831d35Sstevel 	case DP_RUN_TEST:
34403831d35Sstevel 	case DP_SEND_ALERT:
34503831d35Sstevel 	case DP_SET_ALARM_STATE:
34603831d35Sstevel 	case DP_SET_CFGVAR:
34703831d35Sstevel 	case DP_SET_CPU_SIGNATURE:
34803831d35Sstevel 	case DP_SET_DATE_TIME:
34903831d35Sstevel 	case DP_SET_DEFAULT_CFG:
35003831d35Sstevel 	case DP_SET_HOST_WATCHDOG:
35103831d35Sstevel 	case DP_SET_LED_STATE:
35203831d35Sstevel 	case DP_SET_USER_WATCHDOG:
35303831d35Sstevel 	case DP_UPDATE_FLASH:
35403831d35Sstevel 	case DP_USER_ADM:
35503831d35Sstevel 		return (1);
35603831d35Sstevel 	default:
35703831d35Sstevel 		return (sdp_version >= SDP_RESPONDS_TO_ALL_CMDS);
35803831d35Sstevel 	}
35903831d35Sstevel }
36003831d35Sstevel 
36103831d35Sstevel /*
36203831d35Sstevel  * RSC hard reset. Returns 0 on success, non-zero on error.
36303831d35Sstevel  */
36403831d35Sstevel int
rsc_nmi(void)36503831d35Sstevel rsc_nmi(void)
36603831d35Sstevel {
36703831d35Sstevel 	if (rsc_fd < 0)
36803831d35Sstevel 		return (EBADF);
36903831d35Sstevel 
37003831d35Sstevel 	if (ioctl(rsc_fd, RMCADM_RESET_SP, NULL) < 0)
37103831d35Sstevel 		return (errno);
37203831d35Sstevel 
37303831d35Sstevel 	return (0);
37403831d35Sstevel }
37503831d35Sstevel 
37603831d35Sstevel /*
37703831d35Sstevel  * functions used (exclusively) for the firmware download
37803831d35Sstevel  */
37903831d35Sstevel 
38003831d35Sstevel /*
38103831d35Sstevel  * Call this routine to register a callback that will be called by the
38203831d35Sstevel  * generic data protocol routines when a boot protocol message is
38303831d35Sstevel  * received.  Only one of these routines may be registered at a time.
38403831d35Sstevel  * Note that receiving a boot protocol message has the effect of
38503831d35Sstevel  * re-initializing the data protocol.  Returns 0 on success, or non-
38603831d35Sstevel  * zero on failure.
38703831d35Sstevel  */
38803831d35Sstevel int
rscp_register_bpmsg_cb(rscp_bpmsg_cb_t * cb)38903831d35Sstevel rscp_register_bpmsg_cb(rscp_bpmsg_cb_t *cb)
39003831d35Sstevel {
39103831d35Sstevel 	if (rsc_fd < 0)
39203831d35Sstevel 		return (EBADF);
39303831d35Sstevel 
39403831d35Sstevel 	if (bpmsg_cb == NULL) {
39503831d35Sstevel 		bpmsg_cb = cb;
39603831d35Sstevel 		return (0);
39703831d35Sstevel 	} else {
39803831d35Sstevel 		return (EALREADY);
39903831d35Sstevel 	}
40003831d35Sstevel }
40103831d35Sstevel 
40203831d35Sstevel /*
40303831d35Sstevel  * This routine un-registers a boot protocol message callback.
40403831d35Sstevel  */
40503831d35Sstevel int
rscp_unregister_bpmsg_cb(rscp_bpmsg_cb_t * cb)40603831d35Sstevel rscp_unregister_bpmsg_cb(rscp_bpmsg_cb_t *cb)
40703831d35Sstevel {
40803831d35Sstevel 	if (rsc_fd < 0)
40903831d35Sstevel 		return (EBADF);
41003831d35Sstevel 
41103831d35Sstevel 	if (bpmsg_cb == cb) {
41203831d35Sstevel 		bpmsg_cb = NULL;
41303831d35Sstevel 		return (0);
41403831d35Sstevel 	} else {
41503831d35Sstevel 		return (EINPROGRESS);
41603831d35Sstevel 	}
41703831d35Sstevel }
41803831d35Sstevel 
41903831d35Sstevel /*
42003831d35Sstevel  * Call this routine to send a boot protocol message.
42103831d35Sstevel  */
42203831d35Sstevel void
rscp_send_bpmsg(bp_msg_t * bpmsg)42303831d35Sstevel rscp_send_bpmsg(bp_msg_t *bpmsg)
42403831d35Sstevel {
42503831d35Sstevel 	rmcadm_request_response_t	rr_bp;
42603831d35Sstevel 	rmcadm_msg_t			*req_bp = &rr_bp.req;
42703831d35Sstevel 	rmcadm_msg_t			*resp_bp = &rr_bp.resp;
42803831d35Sstevel 	req_resp_table_t		*rr_bp_item;
42903831d35Sstevel 	bp_msg_t			bpmsg_reply;
43003831d35Sstevel 
43103831d35Sstevel 	if (rsc_fd < 0 || bpmsg == NULL)
43203831d35Sstevel 		return;
43303831d35Sstevel 
43403831d35Sstevel 	/*
43503831d35Sstevel 	 * get the timeout value
43603831d35Sstevel 	 */
43703831d35Sstevel 	if ((rr_bp_item = rsc_lookup_rr_table(rr_bp_table, rr_bp_table_cnt,
43803831d35Sstevel 	    bpmsg->cmd)) != NULL) {
43903831d35Sstevel 
44003831d35Sstevel 		rr_bp.wait_time = rr_bp_item->timeout;
44103831d35Sstevel 
44203831d35Sstevel 	} else {
44303831d35Sstevel 
44403831d35Sstevel 		rr_bp.wait_time = RR_BP_TIMEOUT;
44503831d35Sstevel 	}
44603831d35Sstevel 
44703831d35Sstevel 	rr_bp.status = 0;
44803831d35Sstevel 
44903831d35Sstevel 	req_bp->msg_len = sizeof (bp_msg_t);
45003831d35Sstevel 	req_bp->msg_buf = (caddr_t)bpmsg;
45103831d35Sstevel 
45203831d35Sstevel 	if (rr_bp.wait_time == 0) {
45303831d35Sstevel 		resp_bp->msg_buf = (caddr_t)NULL;
45403831d35Sstevel 	} else {
45503831d35Sstevel 		resp_bp->msg_len = sizeof (bp_msg_t);
45603831d35Sstevel 		resp_bp->msg_buf = (caddr_t)&bpmsg_reply;
45703831d35Sstevel 	}
45803831d35Sstevel 
45903831d35Sstevel #ifdef DEBUG
46003831d35Sstevel 	printf("send BP cmd %x, expect reply %x/%d\n",
46103831d35Sstevel 	    bpmsg->cmd, resp_bp->msg_buf, resp_bp->msg_len);
46203831d35Sstevel #endif
46303831d35Sstevel 	if (ioctl(rsc_fd, RMCADM_REQUEST_RESPONSE_BP, &rr_bp) < 0) {
46403831d35Sstevel #ifdef DEBUG
46503831d35Sstevel 		printf("rscp_send_bpmsg: BP cmd %x failed status=%d "
46603831d35Sstevel 		    "errno=%d\n", bpmsg->cmd, rr_bp.status, errno);
46703831d35Sstevel #endif
46803831d35Sstevel 		return;
46903831d35Sstevel 	}
47003831d35Sstevel 
47103831d35Sstevel #ifdef DEBUG
47203831d35Sstevel 	printf("got BP reply type=%x,%x,%x\n",
47303831d35Sstevel 	    bpmsg_reply.cmd, bpmsg_reply.dat1, bpmsg_reply.dat2);
47403831d35Sstevel #endif
47503831d35Sstevel 
47603831d35Sstevel 	/*
47703831d35Sstevel 	 * reply received. call the registered callback (if any)
47803831d35Sstevel 	 */
47903831d35Sstevel 	if (bpmsg_cb != NULL && resp_bp->msg_buf != NULL)
48003831d35Sstevel 		bpmsg_cb(&bpmsg_reply);
48103831d35Sstevel }
48203831d35Sstevel 
48303831d35Sstevel /*
48403831d35Sstevel  * Write raw characters to the RSC control device.  Returns 0 on success,
48503831d35Sstevel  * non-zero on error.
48603831d35Sstevel  */
48703831d35Sstevel int
rsc_raw_write(char * buf,int nbytes)48803831d35Sstevel rsc_raw_write(char *buf, int nbytes)
48903831d35Sstevel {
49003831d35Sstevel 	rmcadm_send_srecord_bp_t	srec_bp;
49103831d35Sstevel 	bp_msg_t			bpmsg_reply;
49203831d35Sstevel 
49303831d35Sstevel 	if (rsc_fd < 0)
49403831d35Sstevel 		return (EBADF);
49503831d35Sstevel 
49603831d35Sstevel 	srec_bp.data_len = (uint_t)nbytes;
49703831d35Sstevel 	srec_bp.data_buf = (caddr_t)buf;
49803831d35Sstevel 	srec_bp.resp_bp.msg_len = sizeof (bp_msg_t);
49903831d35Sstevel 	srec_bp.resp_bp.msg_buf = (caddr_t)&bpmsg_reply;
50003831d35Sstevel 	srec_bp.wait_time = RR_BOOT_LOAD_TIMEOUT;
50103831d35Sstevel 	srec_bp.status = 0;
50203831d35Sstevel 
50303831d35Sstevel #ifdef DEBUG
50403831d35Sstevel 	printf("send srecord BP len=%d\n", nbytes);
50503831d35Sstevel #endif
50603831d35Sstevel 	if (ioctl(rsc_fd, RMCADM_SEND_SRECORD_BP, &srec_bp) < 0) {
50703831d35Sstevel #ifdef DEBUG
50803831d35Sstevel 		printf("rsc_raw_write: failed. status=%d ioctl error=%d\n",
50903831d35Sstevel 		    srec_bp.status, errno);
51003831d35Sstevel #endif
51103831d35Sstevel 		return (errno);
51203831d35Sstevel 	}
51303831d35Sstevel 
51403831d35Sstevel #ifdef DEBUG
51503831d35Sstevel 	printf("got BP reply type=%x\n", bpmsg_reply.cmd);
51603831d35Sstevel #endif
51703831d35Sstevel 
51803831d35Sstevel 	/*
51903831d35Sstevel 	 * reply received. call the registered callback (if any)
52003831d35Sstevel 	 */
52103831d35Sstevel 	if (bpmsg_cb != NULL)
52203831d35Sstevel 		bpmsg_cb(&bpmsg_reply);
52303831d35Sstevel 
52403831d35Sstevel 	return (0);
52503831d35Sstevel }
52603831d35Sstevel 
52703831d35Sstevel /*
52803831d35Sstevel  * obsolete functions provided for backward compatibility
52903831d35Sstevel  */
53003831d35Sstevel 
53103831d35Sstevel /*
53203831d35Sstevel  * This function is obsolete and it is provided for backward compatibility.
53303831d35Sstevel  * (no-op function). It was used to start up the data protocol. low-level
53403831d35Sstevel  * protocol has moved to the kernel and the rmc_comm driver is responsible
53503831d35Sstevel  * for setting up the data protocol.
53603831d35Sstevel  * (obsolete)
53703831d35Sstevel  */
53803831d35Sstevel int
rscp_start(void)53903831d35Sstevel rscp_start(void)
54003831d35Sstevel {
54103831d35Sstevel 	if (rsc_fd < 0)
54203831d35Sstevel 		return (EBADF);
54303831d35Sstevel 
54403831d35Sstevel 	return (0);
54503831d35Sstevel }
54603831d35Sstevel 
54703831d35Sstevel /*
54803831d35Sstevel  * This function is obsolete and it is provided for backward compatibility.
54903831d35Sstevel  * Previously, rscp_send() and rscp_recv() where used to send a request and
55003831d35Sstevel  * read a reply respectively. Now, rscp_send_recv() should be used instead
55103831d35Sstevel  * (request/response in one call).
55203831d35Sstevel  *
55303831d35Sstevel  * This is used to send a message by making an RMCADM_REQUEST_RESPONSE ioctl
55403831d35Sstevel  * call. A lookup table (rr_table) is used to find out the expected reply
55503831d35Sstevel  * (if any) and the timeout value for a message to be sent. The reply is then
55603831d35Sstevel  * stored in a buffer (rsc_rx_buffer) to be returned by calling rscp_recv()
55703831d35Sstevel  */
55803831d35Sstevel int
rscp_send(rscp_msg_t * msgp)55903831d35Sstevel rscp_send(rscp_msg_t *msgp)
56003831d35Sstevel {
56103831d35Sstevel 	rmcadm_request_response_t	 rr;
56203831d35Sstevel 	rmcadm_msg_t			*req = &rr.req;
56303831d35Sstevel 	rmcadm_msg_t			*resp = &rr.resp;
56403831d35Sstevel 	req_resp_table_t		*rr_item;
56503831d35Sstevel 
56603831d35Sstevel 	if (rsc_fd < 0)
56703831d35Sstevel 		return (EBADF);
56803831d35Sstevel 
56903831d35Sstevel 	/*
57003831d35Sstevel 	 * sanity check
57103831d35Sstevel 	 */
57203831d35Sstevel 	if (msgp == NULL)
57303831d35Sstevel 		return (EINVAL);
57403831d35Sstevel 
57503831d35Sstevel 	/*
57603831d35Sstevel 	 * Check if the command is actually supported
57703831d35Sstevel 	 * if not, return an error
57803831d35Sstevel 	 */
57903831d35Sstevel 	if (rsc_check_unsupported_cmd(msgp->type) != 0)
58003831d35Sstevel 		return (ENOTSUP);
58103831d35Sstevel 
58203831d35Sstevel 	/*
58303831d35Sstevel 	 * Check if this command will generate a response and if it will not,
58403831d35Sstevel 	 * return an error.
58503831d35Sstevel 	 */
58603831d35Sstevel 	if (!rsc_cmd_response_guaranteed(msgp->type))
58703831d35Sstevel 		return (ENOTSUP);
58803831d35Sstevel 
58903831d35Sstevel 	/*
59003831d35Sstevel 	 * init rx buffer
59103831d35Sstevel 	 */
59203831d35Sstevel 	rsc_rx_resp_len = 0;
59303831d35Sstevel 	rsc_rx_error = 0;
59403831d35Sstevel 
59503831d35Sstevel 	req->msg_type = msgp->type;
59603831d35Sstevel 	req->msg_len = msgp->len;
59703831d35Sstevel 	req->msg_buf = msgp->data;
59803831d35Sstevel 
59903831d35Sstevel 	if ((rr_item = rsc_lookup_rr_table(rr_table, rr_table_cnt,
60003831d35Sstevel 	    msgp->type)) != NULL) {
60103831d35Sstevel 		resp->msg_type = rr_item->resp_type;
60203831d35Sstevel 		if (rr_item->resp_type == DP_NULL_MSG) {
60303831d35Sstevel 			/*
60403831d35Sstevel 			 * no reply expected. so, no reply buffer needed
60503831d35Sstevel 			 * (set to NULL)
60603831d35Sstevel 			 */
60703831d35Sstevel 			resp->msg_len = 0;
60803831d35Sstevel 			resp->msg_buf = (caddr_t)NULL;
60903831d35Sstevel 		} else {
61003831d35Sstevel 			resp->msg_len = RSC_MAX_RX_BUFFER;
61103831d35Sstevel 			resp->msg_buf = (caddr_t)rsc_rx_buffer;
61203831d35Sstevel 		}
61303831d35Sstevel 
61403831d35Sstevel 		rr.wait_time = rr_item->timeout;
61503831d35Sstevel 		rsc_rx_resp_type = rr_item->resp_type;
61603831d35Sstevel 	} else {
61703831d35Sstevel 		return (ENOTSUP);
61803831d35Sstevel 	}
61903831d35Sstevel 	rr.status = 0;
62003831d35Sstevel 
62103831d35Sstevel #ifdef DEBUG
62203831d35Sstevel 	printf("request/response %x/%x\n", req->msg_type, resp->msg_type);
62303831d35Sstevel #endif
62403831d35Sstevel 	if (ioctl(rsc_fd, RMCADM_REQUEST_RESPONSE, &rr) < 0) {
62503831d35Sstevel #ifdef DEBUG
62603831d35Sstevel 		printf("rscp_send: req %x failed, status=%d errno=%d\n",
62703831d35Sstevel 		    rr.req.msg_type, rr.status, errno);
62803831d35Sstevel #endif
62903831d35Sstevel 		rsc_rx_error = errno;
63003831d35Sstevel 
63103831d35Sstevel 		return (errno);
63203831d35Sstevel 	}
63303831d35Sstevel 
63403831d35Sstevel 	/*
63503831d35Sstevel 	 * reply received. get the number of bytes effectively returned
63603831d35Sstevel 	 */
63703831d35Sstevel 	rsc_rx_resp_len = resp->msg_bytes;
63803831d35Sstevel 	rsc_rx_resp_type = resp->msg_type;
63903831d35Sstevel 
64003831d35Sstevel #ifdef DEBUG
64103831d35Sstevel 	printf("got reply type=%x len=%d\n", rsc_rx_resp_type, rsc_rx_resp_len);
64203831d35Sstevel #endif
64303831d35Sstevel 
64403831d35Sstevel 	return (0);
64503831d35Sstevel }
64603831d35Sstevel 
64703831d35Sstevel /*
64803831d35Sstevel  * This function is obsolete and it is provided for backward compatibility
64903831d35Sstevel  * Previously, rscp_send() and rscp_recv() where used to send a request and
65003831d35Sstevel  * read a reply repectively. Now, rscp_send_recv() should be used instead
65103831d35Sstevel  * (request/response in one call).
65203831d35Sstevel  *
65303831d35Sstevel  * This function returns the reply received when a request was previously sent
65403831d35Sstevel  * using the rscp_send() function (stored in the rsc_rx_buffer buffer). If a
65503831d35Sstevel  * reply was not received, then an error is returned.
65603831d35Sstevel  *
65703831d35Sstevel  * timeout parameter is declared for backward compatibility but it is not used.
65803831d35Sstevel  */
65903831d35Sstevel /*ARGSUSED*/
66003831d35Sstevel int
rscp_recv(rscp_msg_t * msgp,struct timespec * timeout)66103831d35Sstevel rscp_recv(rscp_msg_t *msgp, struct timespec *timeout)
66203831d35Sstevel {
66303831d35Sstevel 	int err = 0;
66403831d35Sstevel 
66503831d35Sstevel 	if (rsc_fd < 0)
66603831d35Sstevel 		return (EBADF);
66703831d35Sstevel 
66803831d35Sstevel 	/*
66903831d35Sstevel 	 * sanity check
67003831d35Sstevel 	 */
67103831d35Sstevel 	if (msgp == NULL)
67203831d35Sstevel 		return (EINVAL);
67303831d35Sstevel 
67403831d35Sstevel 	if (rsc_rx_error < 0) {
67503831d35Sstevel 		msgp->type = DP_NULL_MSG;
67603831d35Sstevel 		msgp->len = 0;
67703831d35Sstevel 		msgp->data = NULL;
67803831d35Sstevel 
67903831d35Sstevel 		err = rsc_rx_error;
68003831d35Sstevel 
68103831d35Sstevel 	} else {
68203831d35Sstevel 		msgp->type = rsc_rx_resp_type;
68303831d35Sstevel 		msgp->len = rsc_rx_resp_len;
68403831d35Sstevel 		msgp->data = rsc_rx_buffer;
68503831d35Sstevel 	}
68603831d35Sstevel 
68703831d35Sstevel #ifdef DEBUG
68803831d35Sstevel 	printf("read reply. type=%x, err=%d\n", msgp->type, err);
68903831d35Sstevel #endif
69003831d35Sstevel 
69103831d35Sstevel 	rsc_rx_resp_len = 0;
69203831d35Sstevel 	rsc_rx_error = 0;
69303831d35Sstevel 	rsc_rx_resp_type = DP_NULL_MSG;
69403831d35Sstevel 
69503831d35Sstevel 	return (err);
69603831d35Sstevel }
69703831d35Sstevel 
69803831d35Sstevel /*
69903831d35Sstevel  * used to free up a (received) message. no-op function
70003831d35Sstevel  */
70103831d35Sstevel /*ARGSUSED*/
70203831d35Sstevel int
rscp_free_msg(rscp_msg_t * msgp)70303831d35Sstevel rscp_free_msg(rscp_msg_t *msgp)
70403831d35Sstevel {
70503831d35Sstevel 	if (rsc_fd < 0)
70603831d35Sstevel 		return (EBADF);
70703831d35Sstevel 
70803831d35Sstevel 	return (0);
70903831d35Sstevel }
710