int api_inteldcmi_cmd_ipmb (ipmi_ctx_t ctx, fiid_obj_t obj_cmd_rq, fiid_obj_t obj_cmd_rs) { assert (ctx && ctx->magic == IPMI_CTX_MAGIC && ctx->type == IPMI_DEVICE_INTELDCMI && fiid_obj_valid (obj_cmd_rq) && fiid_obj_packet_valid (obj_cmd_rq) == 1 && fiid_obj_valid (obj_cmd_rs)); if (ipmi_inteldcmi_cmd_ipmb (ctx->io.inband.inteldcmi_ctx, ctx->target.channel_number, ctx->target.rs_addr, ctx->target.lun, ctx->target.net_fn, obj_cmd_rq, obj_cmd_rs) < 0) { API_INTELDCMI_ERRNUM_TO_API_ERRNUM (ctx, ipmi_inteldcmi_ctx_errnum (ctx->io.inband.inteldcmi_ctx)); return (-1); } return (0); }
static int _api_ipmi_cmd_post (ipmi_ctx_t ctx, fiid_obj_t obj_cmd_rs) { int ret; assert (ctx && ctx->magic == IPMI_CTX_MAGIC && fiid_obj_valid (obj_cmd_rs)); if (ctx->flags & IPMI_FLAGS_NO_LEGAL_CHECK) { uint64_t val; /* Do not check completion code if data not available * (i.e. FIID_ERR_DATA_NOT_AVAILABLE completion code). * * Fallthrough to normal error if it's an alternate fiid error * (invalid packet, field not found, etc.) */ if (FIID_OBJ_GET (obj_cmd_rs, "comp_code", &val) < 0) { if (fiid_obj_errnum (obj_cmd_rs) == FIID_ERR_DATA_NOT_AVAILABLE) goto skip_comp_code_check; } } if ((ret = ipmi_check_completion_code_success (obj_cmd_rs)) < 0) { API_ERRNO_TO_API_ERRNUM (ctx, errno); return (-1); } if (!ret) { API_BAD_RESPONSE_TO_API_ERRNUM (ctx, obj_cmd_rs); return (-1); } skip_comp_code_check: if (!(ctx->flags & IPMI_FLAGS_NO_VALID_CHECK) && !(ctx->flags & IPMI_FLAGS_NO_LEGAL_CHECK)) { if ((ret = fiid_obj_packet_valid (obj_cmd_rs)) < 0) { API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs); return (-1); } if (!ret) { API_SET_ERRNUM (ctx, IPMI_ERR_IPMI_ERROR); return (-1); } } return (0); }
int ipmi_openipmi_cmd_ipmb (ipmi_openipmi_ctx_t ctx, uint8_t channel_number, uint8_t rs_addr, uint8_t lun, uint8_t net_fn, fiid_obj_t obj_cmd_rq, fiid_obj_t obj_cmd_rs) { if (!ctx || ctx->magic != IPMI_OPENIPMI_CTX_MAGIC) { ERR_TRACE (ipmi_openipmi_ctx_errormsg (ctx), ipmi_openipmi_ctx_errnum (ctx)); return (-1); } if (!IPMI_CHANNEL_NUMBER_VALID (channel_number) || !IPMI_BMC_LUN_VALID (lun) || !IPMI_NET_FN_RQ_VALID (net_fn) || !fiid_obj_valid (obj_cmd_rq) || !fiid_obj_valid (obj_cmd_rs) || fiid_obj_packet_valid (obj_cmd_rq) <= 0) { OPENIPMI_SET_ERRNUM (ctx, IPMI_OPENIPMI_ERR_PARAMETERS); return (-1); } if (!ctx->io_init) { OPENIPMI_SET_ERRNUM (ctx, IPMI_OPENIPMI_ERR_IO_NOT_INITIALIZED); return (-1); } if (_openipmi_write (ctx, channel_number, rs_addr, lun, net_fn, obj_cmd_rq, 1) < 0) return (-1); if (_openipmi_read (ctx, obj_cmd_rs) < 0) return (-1); return (0); }
int api_ssif_cmd (ipmi_ctx_t ctx, fiid_obj_t obj_cmd_rq, fiid_obj_t obj_cmd_rs) { uint8_t cmd = 0; /* used for debugging */ uint8_t group_extension = 0; /* used for debugging */ uint64_t val; assert (ctx && ctx->magic == IPMI_CTX_MAGIC && ctx->type == IPMI_DEVICE_SSIF && fiid_obj_valid (obj_cmd_rq) && fiid_obj_packet_valid (obj_cmd_rq) == 1 && fiid_obj_valid (obj_cmd_rs)); if (ctx->flags & IPMI_FLAGS_DEBUG_DUMP) { /* ignore error, continue on */ if (FIID_OBJ_GET (obj_cmd_rq, "cmd", &val) < 0) API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rq); else cmd = val; if (IPMI_NET_FN_GROUP_EXTENSION (ctx->target.net_fn)) { /* ignore error, continue on */ if (FIID_OBJ_GET (obj_cmd_rq, "group_extension_identification", &val) < 0) API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rq); else group_extension = val; } } if (_ssif_cmd_write (ctx, cmd, group_extension, obj_cmd_rq) < 0) return (-1); if (_ssif_cmd_read (ctx, cmd, group_extension, obj_cmd_rs) < 0) return (-1); return (0); }
int ipmiconsole_check_packet (ipmiconsole_ctx_t c, ipmiconsole_packet_type_t p) { fiid_obj_t obj_cmd; int rv; assert (c); assert (c->magic == IPMICONSOLE_CTX_MAGIC); assert (IPMICONSOLE_PACKET_TYPE_RESPONSE (p)); obj_cmd = ipmiconsole_packet_object (c, p); if ((rv = fiid_obj_packet_valid (obj_cmd)) < 0) { IPMICONSOLE_CTX_DEBUG (c, ("fiid_obj_packet_valid: %s", fiid_obj_errormsg (obj_cmd))); return (-1); } if (!rv) IPMICONSOLE_CTX_DEBUG (c, ("invalid packet received; p = %d", p)); return (rv); }
int ipmi_kcs_cmd (ipmi_kcs_ctx_t ctx, uint8_t lun, uint8_t net_fn, fiid_obj_t obj_cmd_rq, fiid_obj_t obj_cmd_rs) { if (!ctx || ctx->magic != IPMI_KCS_CTX_MAGIC) { ERR_TRACE (ipmi_kcs_ctx_errormsg (ctx), ipmi_kcs_ctx_errnum (ctx)); return (-1); } if (!IPMI_BMC_LUN_VALID (lun) || !IPMI_NET_FN_RQ_VALID (net_fn) || !fiid_obj_valid (obj_cmd_rq) || !fiid_obj_valid (obj_cmd_rs) || fiid_obj_packet_valid (obj_cmd_rq) <= 0) { KCS_SET_ERRNUM (ctx, IPMI_KCS_ERR_PARAMETERS); return (-1); } if (!ctx->io_init) { KCS_SET_ERRNUM (ctx, IPMI_KCS_ERR_IO_NOT_INITIALIZED); return (-1); } if (_ipmi_kcs_cmd_write (ctx, lun, net_fn, obj_cmd_rq) < 0) return (-1); if (_ipmi_kcs_cmd_read (ctx, obj_cmd_rs) < 0) return (-1); return (0); }
int api_openipmi_cmd (ipmi_ctx_t ctx, fiid_obj_t obj_cmd_rq, fiid_obj_t obj_cmd_rs) { assert (ctx && ctx->magic == IPMI_CTX_MAGIC && ctx->type == IPMI_DEVICE_OPENIPMI && fiid_obj_valid (obj_cmd_rq) && fiid_obj_packet_valid (obj_cmd_rq) == 1 && fiid_obj_valid (obj_cmd_rs)); if (ipmi_openipmi_cmd (ctx->io.inband.openipmi_ctx, ctx->target.lun, ctx->target.net_fn, obj_cmd_rq, obj_cmd_rs) < 0) { API_OPENIPMI_ERRNUM_TO_API_ERRNUM (ctx, ipmi_openipmi_ctx_errnum (ctx->io.inband.openipmi_ctx)); return (-1); } return (0); }
int ipmi_sunbmc_cmd (ipmi_sunbmc_ctx_t ctx, uint8_t lun, uint8_t net_fn, fiid_obj_t obj_cmd_rq, fiid_obj_t obj_cmd_rs) { if (!ctx || ctx->magic != IPMI_SUNBMC_CTX_MAGIC) { ERR_TRACE (ipmi_sunbmc_ctx_errormsg (ctx), ipmi_sunbmc_ctx_errnum (ctx)); return (-1); } if (!IPMI_BMC_LUN_VALID (lun) || !IPMI_NET_FN_RQ_VALID (net_fn) || !fiid_obj_valid (obj_cmd_rq) || !fiid_obj_valid (obj_cmd_rs) || fiid_obj_packet_valid (obj_cmd_rq) <= 0) { SUNBMC_SET_ERRNUM (ctx, IPMI_SUNBMC_ERR_PARAMETERS); return (-1); } if (!ctx->io_init) { SUNBMC_SET_ERRNUM (ctx, IPMI_SUNBMC_ERR_IO_NOT_INITIALIZED); return (-1); } if (ctx->putmsg_intf) { if (_sunbmc_write (ctx, lun, net_fn, obj_cmd_rq) < 0) return (-1); if (_sunbmc_read (ctx, obj_cmd_rs) < 0) return (-1); } else { #if defined(HAVE_SYS_STROPTS_H) struct strioctl istr; bmc_reqrsp_t reqrsp; uint8_t rq_buf_temp[IPMI_SUNBMC_BUFLEN]; uint8_t rq_buf[IPMI_SUNBMC_BUFLEN]; uint8_t rq_cmd; unsigned int rq_buf_len; uint8_t rs_buf[IPMI_SUNBMC_BUFLEN]; int len; memset (&istr, '\0', sizeof (struct strioctl)); memset (&reqrsp, '\0', sizeof (bmc_reqrsp_t)); /* Due to API differences, we need to extract the cmd out of the * request. */ memset (rq_buf_temp, '\0', IPMI_SUNBMC_BUFLEN); if ((len = fiid_obj_get_all (obj_cmd_rq, rq_buf_temp, IPMI_SUNBMC_BUFLEN)) <= 0) { SUNBMC_SET_ERRNUM (ctx, IPMI_SUNBMC_ERR_INTERNAL_ERROR); return (-1); } rq_cmd = rq_buf_temp[0]; if (len > 1) { /* -1 b/c of cmd */ memcpy (rq_buf, &rq_buf_temp[1], len - 1); rq_buf_len = len - 1; } else rq_buf_len = 0; reqrsp.req.fn = net_fn; reqrsp.req.lun = lun; reqrsp.req.cmd = rq_cmd; istr.ic_cmd = IOCTL_IPMI_KCS_ACTION; istr.ic_timout = 0; /* spelled 'timout', not a typo */ istr.ic_len = sizeof (struct bmc_reqrsp); istr.ic_dp = (char *)&reqrsp; if (ioctl (ctx->device_fd, I_STR, &istr) < 0) { SUNBMC_ERRNO_TO_SUNBMC_ERRNUM (ctx, errno); return (-1); } rs_buf[0] = reqrsp.rsp.cmd; rs_buf[1] = reqrsp.rsp.ccode; /* -2 b/c of cmd and ccode */ #if 0 /* achu: to remove warnings, IPMI_SUNBMC_BUFLEN > amount uint8_t can hold */ if (reqrsp.rsp.datalength >= (IPMI_SUNBMC_BUFLEN - 2)) reqrsp.rsp.datalength = IPMI_SUNBMC_BUFLEN - 2; #endif /* remove header data stuff in front we don't care about */ if (reqrsp.rsp.datalength > 3) reqrsp.rsp.datalength -= 3; else reqrsp.rsp.datalength = 0; memcpy (rs_buf + 2, reqrsp.rsp.data, reqrsp.rsp.datalength); if (fiid_obj_set_all (obj_cmd_rs, rs_buf, reqrsp.rsp.datalength + 2) < 0) { SUNBMC_SET_ERRNUM (ctx, IPMI_SUNBMC_ERR_INTERNAL_ERROR); return (-1); } #else /* !defined(HAVE_SYS_STROPTS_H) */ /* otherwise, device is not supported */ SUNBMC_SET_ERRNUM (ctx, IPMI_SUNBMC_ERR_DEVICE_NOT_SUPPORTED); return (-1); #endif /* !defined(HAVE_SYS_STROPTS_H) */ } return (0); }
static int _sunbmc_write (ipmi_sunbmc_ctx_t ctx, uint8_t lun, uint8_t net_fn, fiid_obj_t obj_cmd_rq) { #if defined(HAVE_SYS_STROPTS_H) struct strbuf sbuf; bmc_msg_t *msg = NULL; bmc_req_t *req = NULL; unsigned int msg_len; uint8_t rq_buf_temp[IPMI_SUNBMC_BUFLEN]; uint8_t rq_buf[IPMI_SUNBMC_BUFLEN]; uint8_t rq_cmd; unsigned int rq_buf_len; int len; #endif /* !defined(HAVE_SYS_STROPTS_H) */ int rv = -1; assert (ctx); assert (ctx->magic == IPMI_SUNBMC_CTX_MAGIC); assert (IPMI_BMC_LUN_VALID (lun)); assert (IPMI_NET_FN_RQ_VALID (net_fn)); assert (fiid_obj_valid (obj_cmd_rq)); assert (fiid_obj_packet_valid (obj_cmd_rq) == 1); assert (ctx->io_init); assert (ctx->putmsg_intf); #if defined(HAVE_SYS_STROPTS_H) memset (&sbuf, '\0', sizeof (struct strbuf)); /* Due to API differences, we need to extract the cmd out of the * request. */ memset (rq_buf_temp, '\0', IPMI_SUNBMC_BUFLEN); if ((len = fiid_obj_get_all (obj_cmd_rq, rq_buf_temp, IPMI_SUNBMC_BUFLEN)) <= 0) { SUNBMC_SET_ERRNUM (ctx, IPMI_SUNBMC_ERR_INTERNAL_ERROR); goto cleanup; } rq_cmd = rq_buf_temp[0]; if (len > 1) { memcpy (rq_buf, &rq_buf_temp[1], len - 1); rq_buf_len = len - 1; } else rq_buf_len = 0; /* achu: see header for for how this is calculated */ msg_len = offsetof (bmc_msg_t, msg); msg_len += sizeof (bmc_req_t); msg_len += (rq_buf_len > SEND_MAX_PAYLOAD_SIZE) ? (rq_buf_len - SEND_MAX_PAYLOAD_SIZE) : 0; if (!(msg = (bmc_msg_t *)malloc (msg_len))) { SUNBMC_SET_ERRNUM (ctx, IPMI_SUNBMC_ERR_OUT_OF_MEMORY); goto cleanup; } msg->m_type = BMC_MSG_REQUEST; msg->m_id = ctx->putmsg_intf_msg_id; req = (bmc_req_t *)&(msg->msg[0]); req->fn = net_fn; req->lun = lun; req->cmd = rq_cmd; req->datalength = rq_buf_len; memcpy (req->data, rq_buf, rq_buf_len); sbuf.len = msg_len; sbuf.buf = (char *)msg; if (putmsg (ctx->device_fd, NULL, &sbuf, 0) < 0) { SUNBMC_ERRNO_TO_SUNBMC_ERRNUM (ctx, errno); goto cleanup; } #else /* !defined(HAVE_SYS_STROPTS_H) */ /* otherwise, device is not supported */ SUNBMC_SET_ERRNUM (ctx, IPMI_SUNBMC_ERR_DEVICE_NOT_SUPPORTED); goto cleanup; #endif /* !(defined(HAVE_BMC_INTF_H) && defined(HAVE_SYS_STROPTS_H)) */ rv = 0; cleanup: #if defined(HAVE_SYS_STROPTS_H) free (msg); #endif /* !defined(HAVE_SYS_STROPTS_H) */ return (rv); }
static int _openipmi_write (ipmi_openipmi_ctx_t ctx, uint8_t channel_number, uint8_t rs_addr, uint8_t lun, uint8_t net_fn, fiid_obj_t obj_cmd_rq, unsigned int is_ipmb) { uint8_t rq_buf_temp[IPMI_OPENIPMI_BUFLEN]; uint8_t rq_buf[IPMI_OPENIPMI_BUFLEN]; uint8_t rq_cmd; unsigned int rq_buf_len; int len; struct ipmi_system_interface_addr system_interface_addr; struct ipmi_ipmb_addr ipmb_addr; struct ipmi_req rq_packet; assert (ctx); assert (ctx->magic == IPMI_OPENIPMI_CTX_MAGIC); assert (IPMI_CHANNEL_NUMBER_VALID (channel_number)); assert (IPMI_BMC_LUN_VALID (lun)); assert (IPMI_NET_FN_RQ_VALID (net_fn)); assert (fiid_obj_valid (obj_cmd_rq)); assert (fiid_obj_packet_valid (obj_cmd_rq) == 1); /* Due to API differences, we need to extract the cmd out of the * request. */ memset (rq_buf_temp, '\0', IPMI_OPENIPMI_BUFLEN); if ((len = fiid_obj_get_all (obj_cmd_rq, rq_buf_temp, IPMI_OPENIPMI_BUFLEN)) <= 0) { OPENIPMI_SET_ERRNUM (ctx, IPMI_OPENIPMI_ERR_INTERNAL_ERROR); return (-1); } rq_cmd = rq_buf_temp[0]; if (len > 1) { /* -1 b/c of cmd */ memcpy (rq_buf, &rq_buf_temp[1], len - 1); rq_buf_len = len - 1; } else rq_buf_len = 0; if (!is_ipmb) { system_interface_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; /* openipmi macro */ system_interface_addr.channel = IPMI_CHANNEL_NUMBER_SYSTEM_INTERFACE; /* freeipmi macro */ system_interface_addr.lun = lun; rq_packet.addr = (unsigned char *)&system_interface_addr; rq_packet.addr_len = sizeof (struct ipmi_system_interface_addr); } else { ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE; /* openipmi macro */ ipmb_addr.channel = channel_number; ipmb_addr.slave_addr = rs_addr; ipmb_addr.lun = lun; rq_packet.addr = (unsigned char *)&ipmb_addr; rq_packet.addr_len = sizeof (struct ipmi_ipmb_addr); } rq_packet.msgid = 0; rq_packet.msg.netfn = net_fn; rq_packet.msg.cmd = rq_cmd; rq_packet.msg.data_len = rq_buf_len; rq_packet.msg.data = rq_buf; if (ioctl (ctx->device_fd, IPMICTL_SEND_COMMAND, &rq_packet) < 0) { OPENIPMI_ERRNO_TO_OPENIPMI_ERRNUM (ctx, errno); return (-1); } return (0); }
int api_ssif_cmd_ipmb (ipmi_ctx_t ctx, fiid_obj_t obj_cmd_rq, fiid_obj_t obj_cmd_rs) { fiid_obj_t obj_ipmb_msg_hdr_rs = NULL; fiid_obj_t obj_ipmb_msg_trlr = NULL; unsigned retransmission_count = 0; unsigned reread_count = 0; int ret, rv = -1; assert (ctx && ctx->magic == IPMI_CTX_MAGIC && ctx->type == IPMI_DEVICE_SSIF && fiid_obj_valid (obj_cmd_rq) && fiid_obj_packet_valid (obj_cmd_rq) == 1 && fiid_obj_valid (obj_cmd_rs)); if (!(obj_ipmb_msg_hdr_rs = fiid_obj_create (tmpl_ipmb_msg_hdr_rs))) { API_ERRNO_TO_API_ERRNUM (ctx, errno); goto cleanup; } if (!(obj_ipmb_msg_trlr = fiid_obj_create (tmpl_ipmb_msg_trlr))) { API_ERRNO_TO_API_ERRNUM (ctx, errno); goto cleanup; } /* for debugging */ ctx->tmpl_ipmb_cmd_rq = fiid_obj_template (obj_cmd_rq); ctx->tmpl_ipmb_cmd_rs = fiid_obj_template (obj_cmd_rs); if (_api_ssif_ipmb_send (ctx, obj_cmd_rq) < 0) goto cleanup; while (1) { if (_api_ssif_ipmb_recv (ctx, obj_ipmb_msg_hdr_rs, obj_ipmb_msg_trlr, obj_cmd_rs) < 0) { if (ctx->errnum == IPMI_ERR_MESSAGE_TIMEOUT) { reread_count++; if (reread_count > IPMI_SSIF_IPMB_REREAD_COUNT) { API_SET_ERRNUM (ctx, IPMI_ERR_MESSAGE_TIMEOUT); goto cleanup; } /* Wait a little bit to avoid spinning */ usleep (IPMI_SSIF_IPMB_REREAD_WAIT); continue; } goto cleanup; } if ((ret = ipmi_ipmb_check_rq_seq (obj_ipmb_msg_hdr_rs, ctx->io.inband.rq_seq)) < 0) { API_ERRNO_TO_API_ERRNUM (ctx, errno); goto cleanup; } /* if it's the wrong rq_seq, get another packet */ if (!ret) continue; if ((ret = ipmi_ipmb_check_checksum (IPMI_SLAVE_ADDRESS_BMC, obj_ipmb_msg_hdr_rs, obj_cmd_rs, obj_ipmb_msg_trlr)) < 0) { API_ERRNO_TO_API_ERRNUM (ctx, errno); goto cleanup; } /* if the checksum is wrong, assume an error and resend */ if (!ret) { retransmission_count++; if (retransmission_count > IPMI_SSIF_IPMB_RETRANSMISSION_COUNT) { API_SET_ERRNUM (ctx, IPMI_ERR_MESSAGE_TIMEOUT); goto cleanup; } ctx->io.inband.rq_seq = ((ctx->io.inband.rq_seq) + 1) % (IPMI_IPMB_REQUESTER_SEQUENCE_NUMBER_MAX + 1); if (_api_ssif_ipmb_send (ctx, obj_cmd_rq) < 0) goto cleanup; continue; } break; } rv = 0; cleanup: ctx->io.inband.rq_seq = ((ctx->io.inband.rq_seq) + 1) % (IPMI_IPMB_REQUESTER_SEQUENCE_NUMBER_MAX + 1); fiid_obj_destroy (obj_ipmb_msg_hdr_rs); fiid_obj_destroy (obj_ipmb_msg_trlr); fiid_template_free (ctx->tmpl_ipmb_cmd_rq); ctx->tmpl_ipmb_cmd_rq = NULL; fiid_template_free (ctx->tmpl_ipmb_cmd_rs); ctx->tmpl_ipmb_cmd_rs = NULL; return (rv); }
static int _api_ssif_ipmb_send (ipmi_ctx_t ctx, fiid_obj_t obj_cmd_rq) { struct ipmi_ctx_target target_save; uint8_t buf[IPMI_MAX_PKT_LEN]; fiid_obj_t obj_ipmb_msg_hdr_rq = NULL; fiid_obj_t obj_ipmb_msg_rq = NULL; fiid_obj_t obj_send_cmd_rs = NULL; int len, ret, rv = -1; assert (ctx && ctx->magic == IPMI_CTX_MAGIC && ctx->type == IPMI_DEVICE_SSIF && fiid_obj_valid (obj_cmd_rq) && fiid_obj_packet_valid (obj_cmd_rq) == 1); if (!(obj_ipmb_msg_hdr_rq = fiid_obj_create (tmpl_ipmb_msg_hdr_rq))) { API_ERRNO_TO_API_ERRNUM (ctx, errno); goto cleanup; } if (!(obj_ipmb_msg_rq = fiid_obj_create (tmpl_ipmb_msg))) { API_ERRNO_TO_API_ERRNUM (ctx, errno); goto cleanup; } if (!(obj_send_cmd_rs = fiid_obj_create (tmpl_cmd_send_message_rs))) { API_ERRNO_TO_API_ERRNUM (ctx, errno); goto cleanup; } if (fill_ipmb_msg_hdr (ctx->target.rs_addr, ctx->target.net_fn, ctx->target.lun, IPMI_SLAVE_ADDRESS_BMC, IPMI_BMC_IPMB_LUN_SMS_MSG_LUN, ctx->io.inband.rq_seq, obj_ipmb_msg_hdr_rq) < 0) { API_ERRNO_TO_API_ERRNUM (ctx, errno); goto cleanup; } if (assemble_ipmi_ipmb_msg (obj_ipmb_msg_hdr_rq, obj_cmd_rq, obj_ipmb_msg_rq, IPMI_INTERFACE_FLAGS_DEFAULT) < 0) { API_ERRNO_TO_API_ERRNUM (ctx, errno); goto cleanup; } memset (buf, '\0', IPMI_MAX_PKT_LEN); if ((len = fiid_obj_get_all (obj_ipmb_msg_rq, buf, IPMI_MAX_PKT_LEN)) < 0) { API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_ipmb_msg_rq); goto cleanup; } /* send_message will send to the BMC, so clear out target information */ memcpy (&target_save, &ctx->target, sizeof (target_save)); ctx->target.channel_number_is_set = 0; ctx->target.rs_addr_is_set = 0; ret = ipmi_cmd_send_message (ctx, target_save.channel_number, IPMI_SEND_MESSAGE_AUTHENTICATION_NOT_REQUIRED, IPMI_SEND_MESSAGE_ENCRYPTION_NOT_REQUIRED, IPMI_SEND_MESSAGE_TRACKING_OPERATION_NO_TRACKING, buf, len, obj_send_cmd_rs); /* restore target info */ memcpy (&ctx->target, &target_save, sizeof (target_save)); if (ret < 0) { /* assume these mean can't send message, bad slave address, etc. */ if (ipmi_check_completion_code (obj_send_cmd_rs, IPMI_COMP_CODE_SEND_MESSAGE_LOST_ARBITRATION) == 1 || ipmi_check_completion_code (obj_send_cmd_rs, IPMI_COMP_CODE_SEND_MESSAGE_BUS_ERROR) == 1 || ipmi_check_completion_code (obj_send_cmd_rs, IPMI_COMP_CODE_SEND_MESSAGE_NAK_ON_WRITE) == 1) API_SET_ERRNUM (ctx, IPMI_ERR_MESSAGE_TIMEOUT); else API_BAD_RESPONSE_TO_API_ERRNUM (ctx, obj_send_cmd_rs); goto cleanup; } rv = 0; cleanup: fiid_obj_destroy (obj_ipmb_msg_hdr_rq); fiid_obj_destroy (obj_ipmb_msg_rq); fiid_obj_destroy (obj_send_cmd_rs); return (rv); }
int api_ssif_cmd (ipmi_ctx_t ctx, fiid_obj_t obj_cmd_rq, fiid_obj_t obj_cmd_rs) { uint8_t cmd = 0; /* used for debugging */ uint8_t group_extension = 0; /* used for debugging */ uint64_t val; struct timespec request, remain; uint8_t retry = IPMI_SSIF_RETRY_DEFAULT; assert (ctx && ctx->magic == IPMI_CTX_MAGIC && ctx->type == IPMI_DEVICE_SSIF && fiid_obj_valid (obj_cmd_rq) && fiid_obj_packet_valid (obj_cmd_rq) == 1 && fiid_obj_valid (obj_cmd_rs)); if (ctx->flags & IPMI_FLAGS_DEBUG_DUMP) { /* ignore error, continue on */ if (FIID_OBJ_GET (obj_cmd_rq, "cmd", &val) < 0) API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rq); else cmd = val; if (IPMI_NET_FN_GROUP_EXTENSION (ctx->target.net_fn)) { /* ignore error, continue on */ if (FIID_OBJ_GET (obj_cmd_rq, "group_extension_identification", &val) < 0) API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rq); else group_extension = val; } } if (_ssif_cmd_write (ctx, cmd, group_extension, obj_cmd_rq) < 0) return (-1); /****************************************************************************** 12.9 SMBus NACKs and Error Recovery: ==================================== The BMC can NACK the SMBus host controller if it is not ready to accept a new transaction. Typically, this will be exhibited by the BMC NACK'ing its slave address. If the BMC NACKs a single part transaction, software can simply retry it. If a 'middle' or 'end' transaction is NACK'd, software should not retry the particular but should restart the multi-part read or write from the beginning Start transaction for the transfer. *******************************************************************************/ if (_ssif_cmd_read (ctx, cmd, group_extension, obj_cmd_rs) < 0) { while (1) { request.tv_sec = 0; request.tv_nsec = IPMI_SSIF_TIMEOUT_DEFAULT; if (nanosleep (&request, &remain) < 0 ) return (-1); if (_ssif_cmd_read (ctx, cmd, group_extension, obj_cmd_rs) < 0) { if (retry == 0) return (-1); retry--; } else break; } } return (0); }
static int _ipmi_kcs_cmd_write (ipmi_kcs_ctx_t ctx, uint8_t lun, uint8_t net_fn, fiid_obj_t obj_cmd_rq) { uint8_t *pkt = NULL; unsigned int pkt_len; int hdr_len, cmd_len, rv = -1; fiid_obj_t obj_hdr = NULL; assert (ctx); assert (ctx->magic == IPMI_KCS_CTX_MAGIC); assert (IPMI_BMC_LUN_VALID (lun)); assert (IPMI_NET_FN_RQ_VALID (net_fn)); assert (fiid_obj_valid (obj_cmd_rq)); assert (fiid_obj_packet_valid (obj_cmd_rq) == 1); if ((hdr_len = fiid_template_len_bytes (tmpl_hdr_kcs)) < 0) { KCS_ERRNO_TO_KCS_ERRNUM (ctx, errno); goto cleanup; } if ((cmd_len = fiid_obj_len_bytes (obj_cmd_rq)) < 0) { KCS_FIID_OBJECT_ERROR_TO_KCS_ERRNUM (ctx, obj_cmd_rq); goto cleanup; } if (!(obj_hdr = fiid_obj_create (tmpl_hdr_kcs))) { KCS_ERRNO_TO_KCS_ERRNUM (ctx, errno); goto cleanup; } pkt_len = hdr_len + cmd_len; if (!(pkt = (uint8_t *)malloc (pkt_len))) { KCS_SET_ERRNUM (ctx, IPMI_KCS_ERR_OUT_OF_MEMORY); goto cleanup; } if (fill_hdr_ipmi_kcs (lun, net_fn, obj_hdr) < 0) { KCS_SET_ERRNUM (ctx, IPMI_KCS_ERR_INTERNAL_ERROR); goto cleanup; } if (assemble_ipmi_kcs_pkt (obj_hdr, obj_cmd_rq, pkt, pkt_len, IPMI_INTERFACE_FLAGS_DEFAULT) < 0) { KCS_SET_ERRNUM (ctx, IPMI_KCS_ERR_INTERNAL_ERROR); goto cleanup; } if (ipmi_kcs_write (ctx, pkt, pkt_len) < 0) goto cleanup; rv = 0; cleanup: fiid_obj_destroy (obj_hdr); free (pkt); return (rv); }