#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "librsc.h"
static int rsc_fd = -1;
static uchar_t rsc_rx_buffer[RSC_MAX_RX_BUFFER];
static int rsc_rx_resp_len = 0;
static int rsc_rx_error = 0;
static rsci8 rsc_rx_resp_type = 0;
static rscp_bpmsg_cb_t *bpmsg_cb;
static req_resp_table_t rr_table[] = {
{ DP_GET_DATE_TIME, DP_GET_DATE_TIME_R,
sizeof (dp_get_date_time_r_t), RR_TIMEOUT },
{ DP_SET_DATE_TIME, DP_SET_DATE_TIME_R,
sizeof (dp_set_date_time_r_t), RR_TIMEOUT },
{ DP_GET_EVENT_LOG, DP_GET_EVENT_LOG_R,
sizeof (dp_get_event_log_r_t), RR_TIMEOUT },
{ DP_MODEM_CONNECT, DP_MODEM_CONNECT_R,
sizeof (dp_modem_connect_r_t), RR_TIMEOUT },
{ DP_MODEM_DISCONNECT, DP_MODEM_DISCONNECT_R,
sizeof (dp_modem_disconnect_r_t), RR_TIMEOUT },
{ DP_SEND_ALERT, DP_SEND_ALERT_R,
sizeof (dp_send_alert_r_t), RR_TIMEOUT },
{ DP_SET_CFGVAR, DP_SET_CFGVAR_R,
sizeof (dp_set_cfgvar_r_t), RR_TIMEOUT },
{ DP_GET_CFGVAR, DP_GET_CFGVAR_R,
sizeof (dp_get_cfgvar_r_t), RR_TIMEOUT },
{ DP_GET_CFGVAR_NAME, DP_GET_CFGVAR_NAME_R,
sizeof (dp_get_cfgvar_name_r_t), RR_TIMEOUT },
{ DP_GET_NETWORK_CFG, DP_GET_NETWORK_CFG_R,
sizeof (dp_get_network_cfg_r_t), RR_TIMEOUT },
{ DP_RSC_STATUS, DP_RSC_STATUS_R,
sizeof (dp_rsc_status_r_t), RR_TIMEOUT },
{ DP_USER_ADM, DP_USER_ADM_R,
sizeof (dp_user_adm_r_t), RR_SEPROM_TIMEOUT},
{ DP_RESET_RSC, DP_NULL_MSG,
0, 1 },
{ DP_GET_CONSOLE_LOG, DP_GET_CONSOLE_LOG_R,
sizeof (dp_get_console_log_r_t), RR_TIMEOUT },
{ DP_GET_CONFIG_LOG, DP_GET_CONFIG_LOG_R,
sizeof (dp_get_config_log_r_t), RR_TIMEOUT },
{ DP_GET_EVENT_LOG2, DP_GET_EVENT_LOG2_R,
sizeof (dp_get_event_log2_r_t), RR_TIMEOUT },
};
static const int rr_table_cnt = sizeof (rr_table) / sizeof (rr_table[0]);
static req_resp_table_t rr_bp_table[] = {
{ BP_OBP_BOOTINIT, 0, sizeof (bp_msg_t),
RR_BOOT_INIT_TIMEOUT },
{ BP_OBP_RESET, 0, sizeof (bp_msg_t),
RR_BOOT_RESET_TIMEOUT }
};
static const int rr_bp_table_cnt =
sizeof (rr_bp_table) / sizeof (rr_bp_table[0]);
static rsci8 unsupported_cmds[] = { DP_SET_DATE_TIME };
static int unsupported_cmds_cnt = sizeof (unsupported_cmds) /
sizeof (unsupported_cmds[0]);
static int sdp_version = -1;
static req_resp_table_t *rsc_lookup_rr_table(req_resp_table_t *, int, rsci8);
static int rsc_check_unsupported_cmd(rsci8);
static int rsc_cmd_response_guaranteed(rsci8);
int
rscp_init(void)
{
rscp_msg_t request, response;
dp_get_sdp_version_r_t version_msg;
(void) memset(rsc_rx_buffer, 0, sizeof (rsc_rx_buffer));
rsc_rx_resp_len = 0;
rsc_rx_error = 0;
rsc_rx_resp_type = DP_NULL_MSG;
if ((rsc_fd = open(RSC_RMCADM_DRV, O_RDWR)) < 0) {
#ifdef DEBUG
printf("rscp_init: Error opening %s, error code = %d\n",
RSC_RMCADM_DRV, errno);
#endif
return (errno);
}
request.type = DP_GET_SDP_VERSION;
request.len = 0;
request.data = 0;
response.type = DP_GET_SDP_VERSION_R;
response.len = sizeof (version_msg);
response.data = (caddr_t)&version_msg;
if ((errno = rscp_send_recv(&request, &response, 0)) != 0)
return (errno);
sdp_version = version_msg.version;
#ifdef DEBUG
printf("rscp_init: sdp version number is %d\n", sdp_version);
#endif
return (0);
}
int
rscp_send_recv(rscp_msg_t *req, rscp_msg_t *resp, struct timespec *timeout)
{
rmcadm_request_response_t rr;
rmcadm_msg_t *rr_req = &rr.req;
rmcadm_msg_t *rr_resp = &rr.resp;
if (rsc_fd < 0)
return (EBADF);
if (req == NULL)
return (EINVAL);
if (rsc_check_unsupported_cmd(req->type) != 0)
return (ENOTSUP);
if (!rsc_cmd_response_guaranteed(req->type))
return (ENOTSUP);
rr_req->msg_type = req->type;
rr_req->msg_len = req->len;
rr_req->msg_buf = (caddr_t)req->data;
if (resp != NULL) {
rr_resp->msg_type = resp->type;
rr_resp->msg_len = resp->len;
rr_resp->msg_buf = (caddr_t)resp->data;
rr_resp->msg_bytes = 0;
} else {
rr_resp->msg_type = DP_NULL_MSG;
rr_resp->msg_buf = (caddr_t)NULL;
rr_resp->msg_len = 0;
rr_resp->msg_bytes = 0;
}
if (timeout == NULL) {
rr.wait_time = RR_TIMEOUT;
} else {
rr.wait_time = timeout->tv_sec * 1000 +
timeout->tv_nsec / 1000000;
}
rr.status = 0;
if (ioctl(rsc_fd, RMCADM_REQUEST_RESPONSE, &rr) < 0) {
#ifdef DEBUG
printf("rscp_send_recv: req. failed, status=%d errno=%d\n",
rr_req->msg_type, rr.status, errno);
#endif
return (errno);
}
return (0);
}
static req_resp_table_t *
rsc_lookup_rr_table(req_resp_table_t *rr_table, int cnt, rsci8 type)
{
int i;
#ifdef DEBUG
printf("lookup for type %x, count %d\n", type, cnt);
#endif
for (i = 0; i < cnt; i++)
if (rr_table[i].req_type == type) {
return (rr_table + i);
}
return (NULL);
}
static int
rsc_check_unsupported_cmd(rsci8 type)
{
int i;
for (i = 0; i < unsupported_cmds_cnt; i++)
if (unsupported_cmds[i] == type) {
return (1);
}
return (0);
}
static int
rsc_cmd_response_guaranteed(rsci8 type)
{
switch (type) {
case DP_GET_ALARM_STATE:
case DP_GET_CFGVAR:
case DP_GET_CFGVAR_NAME:
case DP_GET_CIRCUIT_BRKS:
case DP_GET_DATE_TIME:
case DP_GET_DEVICE:
case DP_GET_EVENT_LOG:
case DP_GET_FAN_STATUS:
case DP_GET_FRU_STATUS:
case DP_GET_HANDLE:
case DP_GET_HANDLE_NAME:
case DP_GET_LED_STATE:
case DP_GET_NETWORK_CFG:
case DP_GET_PCMCIA_INFO:
case DP_GET_PSU_STATUS:
case DP_GET_SDP_VERSION:
case DP_GET_SYSINFO:
case DP_GET_TEMP:
case DP_GET_TEMPERATURES:
case DP_GET_TICKCNT:
case DP_GET_TOD_CLOCK:
case DP_GET_USER_WATCHDOG:
case DP_GET_VOLTS:
case DP_MODEM_CONNECT:
case DP_MODEM_DATA:
case DP_MODEM_DISCONNECT:
case DP_RESET_RSC:
case DP_RMC_EVENTS:
case DP_RSC_STATUS:
case DP_RUN_TEST:
case DP_SEND_ALERT:
case DP_SET_ALARM_STATE:
case DP_SET_CFGVAR:
case DP_SET_CPU_SIGNATURE:
case DP_SET_DATE_TIME:
case DP_SET_DEFAULT_CFG:
case DP_SET_HOST_WATCHDOG:
case DP_SET_LED_STATE:
case DP_SET_USER_WATCHDOG:
case DP_UPDATE_FLASH:
case DP_USER_ADM:
return (1);
default:
return (sdp_version >= SDP_RESPONDS_TO_ALL_CMDS);
}
}
int
rsc_nmi(void)
{
if (rsc_fd < 0)
return (EBADF);
if (ioctl(rsc_fd, RMCADM_RESET_SP, NULL) < 0)
return (errno);
return (0);
}
int
rscp_register_bpmsg_cb(rscp_bpmsg_cb_t *cb)
{
if (rsc_fd < 0)
return (EBADF);
if (bpmsg_cb == NULL) {
bpmsg_cb = cb;
return (0);
} else {
return (EALREADY);
}
}
int
rscp_unregister_bpmsg_cb(rscp_bpmsg_cb_t *cb)
{
if (rsc_fd < 0)
return (EBADF);
if (bpmsg_cb == cb) {
bpmsg_cb = NULL;
return (0);
} else {
return (EINPROGRESS);
}
}
void
rscp_send_bpmsg(bp_msg_t *bpmsg)
{
rmcadm_request_response_t rr_bp;
rmcadm_msg_t *req_bp = &rr_bp.req;
rmcadm_msg_t *resp_bp = &rr_bp.resp;
req_resp_table_t *rr_bp_item;
bp_msg_t bpmsg_reply;
if (rsc_fd < 0 || bpmsg == NULL)
return;
if ((rr_bp_item = rsc_lookup_rr_table(rr_bp_table, rr_bp_table_cnt,
bpmsg->cmd)) != NULL) {
rr_bp.wait_time = rr_bp_item->timeout;
} else {
rr_bp.wait_time = RR_BP_TIMEOUT;
}
rr_bp.status = 0;
req_bp->msg_len = sizeof (bp_msg_t);
req_bp->msg_buf = (caddr_t)bpmsg;
if (rr_bp.wait_time == 0) {
resp_bp->msg_buf = (caddr_t)NULL;
} else {
resp_bp->msg_len = sizeof (bp_msg_t);
resp_bp->msg_buf = (caddr_t)&bpmsg_reply;
}
#ifdef DEBUG
printf("send BP cmd %x, expect reply %x/%d\n",
bpmsg->cmd, resp_bp->msg_buf, resp_bp->msg_len);
#endif
if (ioctl(rsc_fd, RMCADM_REQUEST_RESPONSE_BP, &rr_bp) < 0) {
#ifdef DEBUG
printf("rscp_send_bpmsg: BP cmd %x failed status=%d "
"errno=%d\n", bpmsg->cmd, rr_bp.status, errno);
#endif
return;
}
#ifdef DEBUG
printf("got BP reply type=%x,%x,%x\n",
bpmsg_reply.cmd, bpmsg_reply.dat1, bpmsg_reply.dat2);
#endif
if (bpmsg_cb != NULL && resp_bp->msg_buf != NULL)
bpmsg_cb(&bpmsg_reply);
}
int
rsc_raw_write(char *buf, int nbytes)
{
rmcadm_send_srecord_bp_t srec_bp;
bp_msg_t bpmsg_reply;
if (rsc_fd < 0)
return (EBADF);
srec_bp.data_len = (uint_t)nbytes;
srec_bp.data_buf = (caddr_t)buf;
srec_bp.resp_bp.msg_len = sizeof (bp_msg_t);
srec_bp.resp_bp.msg_buf = (caddr_t)&bpmsg_reply;
srec_bp.wait_time = RR_BOOT_LOAD_TIMEOUT;
srec_bp.status = 0;
#ifdef DEBUG
printf("send srecord BP len=%d\n", nbytes);
#endif
if (ioctl(rsc_fd, RMCADM_SEND_SRECORD_BP, &srec_bp) < 0) {
#ifdef DEBUG
printf("rsc_raw_write: failed. status=%d ioctl error=%d\n",
srec_bp.status, errno);
#endif
return (errno);
}
#ifdef DEBUG
printf("got BP reply type=%x\n", bpmsg_reply.cmd);
#endif
if (bpmsg_cb != NULL)
bpmsg_cb(&bpmsg_reply);
return (0);
}
int
rscp_start(void)
{
if (rsc_fd < 0)
return (EBADF);
return (0);
}
int
rscp_send(rscp_msg_t *msgp)
{
rmcadm_request_response_t rr;
rmcadm_msg_t *req = &rr.req;
rmcadm_msg_t *resp = &rr.resp;
req_resp_table_t *rr_item;
if (rsc_fd < 0)
return (EBADF);
if (msgp == NULL)
return (EINVAL);
if (rsc_check_unsupported_cmd(msgp->type) != 0)
return (ENOTSUP);
if (!rsc_cmd_response_guaranteed(msgp->type))
return (ENOTSUP);
rsc_rx_resp_len = 0;
rsc_rx_error = 0;
req->msg_type = msgp->type;
req->msg_len = msgp->len;
req->msg_buf = msgp->data;
if ((rr_item = rsc_lookup_rr_table(rr_table, rr_table_cnt,
msgp->type)) != NULL) {
resp->msg_type = rr_item->resp_type;
if (rr_item->resp_type == DP_NULL_MSG) {
resp->msg_len = 0;
resp->msg_buf = (caddr_t)NULL;
} else {
resp->msg_len = RSC_MAX_RX_BUFFER;
resp->msg_buf = (caddr_t)rsc_rx_buffer;
}
rr.wait_time = rr_item->timeout;
rsc_rx_resp_type = rr_item->resp_type;
} else {
return (ENOTSUP);
}
rr.status = 0;
#ifdef DEBUG
printf("request/response %x/%x\n", req->msg_type, resp->msg_type);
#endif
if (ioctl(rsc_fd, RMCADM_REQUEST_RESPONSE, &rr) < 0) {
#ifdef DEBUG
printf("rscp_send: req %x failed, status=%d errno=%d\n",
rr.req.msg_type, rr.status, errno);
#endif
rsc_rx_error = errno;
return (errno);
}
rsc_rx_resp_len = resp->msg_bytes;
rsc_rx_resp_type = resp->msg_type;
#ifdef DEBUG
printf("got reply type=%x len=%d\n", rsc_rx_resp_type, rsc_rx_resp_len);
#endif
return (0);
}
int
rscp_recv(rscp_msg_t *msgp, struct timespec *timeout)
{
int err = 0;
if (rsc_fd < 0)
return (EBADF);
if (msgp == NULL)
return (EINVAL);
if (rsc_rx_error < 0) {
msgp->type = DP_NULL_MSG;
msgp->len = 0;
msgp->data = NULL;
err = rsc_rx_error;
} else {
msgp->type = rsc_rx_resp_type;
msgp->len = rsc_rx_resp_len;
msgp->data = rsc_rx_buffer;
}
#ifdef DEBUG
printf("read reply. type=%x, err=%d\n", msgp->type, err);
#endif
rsc_rx_resp_len = 0;
rsc_rx_error = 0;
rsc_rx_resp_type = DP_NULL_MSG;
return (err);
}
int
rscp_free_msg(rscp_msg_t *msgp)
{
if (rsc_fd < 0)
return (EBADF);
return (0);
}