static int64_t opal_ipmi_recv(uint64_t interface, struct opal_ipmi_msg *opal_ipmi_msg, uint64_t *msg_len) { struct ipmi_msg *msg; int64_t rc; lock(&msgq_lock); msg = list_top(&msgq, struct ipmi_msg, link); if (!msg) { rc = OPAL_EMPTY; goto out_unlock; } if (opal_ipmi_msg->version != OPAL_IPMI_MSG_FORMAT_VERSION_1) { prerror("OPAL IPMI: Incorrect version\n"); rc = OPAL_UNSUPPORTED; goto out_del_msg; } if (interface != IPMI_DEFAULT_INTERFACE) { prerror("IPMI: Invalid interface 0x%llx in opal_ipmi_recv\n", interface); rc = OPAL_PARAMETER; goto out_del_msg; } if (*msg_len - sizeof(struct opal_ipmi_msg) < msg->resp_size + 1) { rc = OPAL_RESOURCE; goto out_del_msg; } list_del(&msg->link); if (list_empty(&msgq)) opal_update_pending_evt(ipmi_backend->opal_event_ipmi_recv, 0); unlock(&msgq_lock); opal_ipmi_msg->cmd = msg->cmd; opal_ipmi_msg->netfn = msg->netfn; opal_ipmi_msg->data[0] = msg->cc; memcpy(&opal_ipmi_msg->data[1], msg->data, msg->resp_size); prlog(PR_DEBUG, "opal_ipmi_recv(cmd: 0x%02x netfn: 0x%02x resp_size: 0x%02x)\n", msg->cmd, msg->netfn >> 2, msg->resp_size); /* Add one as the completion code is returned in the message data */ *msg_len = msg->resp_size + sizeof(struct opal_ipmi_msg) + 1; ipmi_free_msg(msg); return OPAL_SUCCESS; out_del_msg: list_del(&msg->link); if (list_empty(&msgq)) opal_update_pending_evt(ipmi_backend->opal_event_ipmi_recv, 0); ipmi_free_msg(msg); out_unlock: unlock(&msgq_lock); return rc; }
int ipmi_get_chassis_boot_opt_request(void) { int rc; struct ipmi_msg *msg; uint8_t req[] = { 0x62, /* OEM parameter (SBE Validation on astbmc) */ 0x00, /* no set selector */ 0x00, /* no block selector */ }; ipmi_sys_boot_opt = zalloc(sizeof(struct ipmi_sys_boot_opt)); assert(ipmi_sys_boot_opt); msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE, IPMI_CHASSIS_GET_BOOT_OPT, ipmi_get_chassis_boot_opt_resp, NULL, req, sizeof(req), sizeof(struct ipmi_sys_boot_opt)); if (!msg) { free(ipmi_sys_boot_opt); return OPAL_NO_MEM; } msg->error = ipmi_get_chassis_boot_opt_resp; prlog(PR_INFO, "IPMI: Requesting IPMI_CHASSIS_GET_BOOT_OPT\n"); rc = ipmi_queue_msg(msg); if (rc) { prlog(PR_ERR, "IPMI: Failed to queue IPMI_CHASSIS_GET_BOOT_OPT\n"); free(ipmi_sys_boot_opt); ipmi_free_msg(msg); return rc; } bmc_boot_opt_waiting = true; return rc; }
int ipmi_get_bmc_info_request(void) { int rc; struct ipmi_msg *msg; ipmi_dev_id = zalloc(sizeof(struct ipmi_dev_id)); assert(ipmi_dev_id); msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE, IPMI_BMC_GET_DEVICE_ID, ipmi_get_bmc_info_resp, NULL, NULL, 0, sizeof(struct ipmi_dev_id)); if (!msg) return OPAL_NO_MEM; msg->error = ipmi_get_bmc_info_resp; prlog(PR_INFO, "IPMI: Requesting IPMI_BMC_GET_DEVICE_ID\n"); rc = ipmi_queue_msg(msg); if (rc) { prlog(PR_ERR, "IPMI: Failed to queue IPMI_BMC_GET_DEVICE_ID\n"); ipmi_free_msg(msg); return rc; } bmc_info_waiting = true; return rc; }
static void ipmi_wdt_complete(struct ipmi_msg *msg) { if (msg->cmd == IPMI_CMD(IPMI_RESET_WDT) && !msg->user_data) schedule_timer(&wdt_timer, msecs_to_tb( (WDT_TIMEOUT - WDT_MARGIN)*100)); ipmi_free_msg(msg); }
static void ipmi_get_chassis_boot_opt_resp(struct ipmi_msg *msg) { bmc_boot_opt_waiting = false; if (msg->cc != IPMI_CC_NO_ERROR) { prlog(PR_INFO, "IPMI: IPMI_CHASSIS_GET_BOOT_OPT cmd returned error" " [rc : 0x%x]\n", msg->data[0]); ipmi_free_msg(msg); return; } if (msg->resp_size == sizeof(struct ipmi_sys_boot_opt)) { bmc_boot_opt_valid = true; memcpy(ipmi_sys_boot_opt, msg->data, msg->resp_size); } else { prlog(PR_WARNING, "IPMI: IPMI_CHASSIS_GET_BOOT_OPT unexpected response size\n"); } ipmi_free_msg(msg); }
static void ipmi_sel_free_msg(struct ipmi_msg *msg) { if (msg == ipmi_sel_panic_msg.msg) { lock(&ipmi_sel_panic_msg.lock); ipmi_sel_panic_msg.busy = false; unlock(&ipmi_sel_panic_msg.lock); } else { ipmi_free_msg(msg); } msg = NULL; }
static void get_sel_time_complete(struct ipmi_msg *msg) { struct tm tm; le32 result; time_t time; memcpy(&result, msg->data, 4); time = le32_to_cpu(result); gmtime_r(&time, &tm); rtc_cache_update(&tm); time_status = updated; ipmi_free_msg(msg); }
static void ipmi_get_bmc_info_resp(struct ipmi_msg *msg) { bmc_info_waiting = false; if (msg->cc != IPMI_CC_NO_ERROR) { prlog(PR_ERR, "IPMI: IPMI_BMC_GET_DEVICE_ID cmd returned error" " [rc : 0x%x]\n", msg->data[0]); return; } /* ipmi_dev_id has optional fields */ if (msg->resp_size <= sizeof(struct ipmi_dev_id)) { bmc_info_valid = true; memcpy(ipmi_dev_id, msg->data, msg->resp_size); } else { prlog(PR_WARNING, "IPMI: IPMI_BMC_GET_DEVICE_ID unexpected response size\n"); } ipmi_free_msg(msg); }
static void get_bt_caps_complete(struct ipmi_msg *msg) { /* Ignore errors, we'll fallback to using the defaults, no big deal */ if (msg->data[0] == 0) { prlog(PR_DEBUG, "Got illegal BMC BT capability\n"); goto out; } if (msg->data[1] != BT_FIFO_LEN) { prlog(PR_DEBUG, "Got a input buffer len (%u) cap which differs from the default\n", msg->data[1]); } if (msg->data[2] != BT_FIFO_LEN) { prlog(PR_DEBUG, "Got a output buffer len (%u) cap which differs from the default\n", msg->data[2]); } /* * IPMI Spec says that the value for buffer sizes are: * "the largest value allowed in first byte" * Therefore we want to add one to what we get */ bt.caps.num_requests = msg->data[0]; bt.caps.input_buf_len = msg->data[1] + 1; bt.caps.output_buf_len = msg->data[2] + 1; bt.caps.msg_timeout = msg->data[3]; bt.caps.max_retries = msg->data[4]; prlog(PR_DEBUG, "BMC BT capabilities received:\n"); prlog(PR_DEBUG, "buffer sizes: %d input %d output\n", bt.caps.input_buf_len, bt.caps.output_buf_len); prlog(PR_DEBUG, "number of requests: %d\n", bt.caps.num_requests); prlog(PR_DEBUG, "msg timeout: %d max retries: %d\n", bt.caps.msg_timeout, bt.caps.max_retries); out: ipmi_free_msg(msg); }
static int fru_add(u8 *buf, int size) { int len; char short_version[MAX_STR_LEN + 1]; struct common_header common_hdr; struct product_info info = { .manufacturer = (char *) "IBM", .product = (char *) "skiboot", .part_no = (char *) "", .serial_no = (char *) "", .asset_tag = (char *) "", }; if (size < sizeof(common_hdr)) return OPAL_PARAMETER; /* We currently only support adding the version number at the * product information offset. We choose an offset of 64 bytes * because that's what the standard recommends. */ common_hdr.version = 1; common_hdr.internal_offset = 0; common_hdr.chassis_offset = 0; common_hdr.board_offset = 0; common_hdr.product_offset = 64/8; common_hdr.multirecord_offset = 0; common_hdr.pad = 0; common_hdr.checksum = fru_checksum((u8 *) &common_hdr, sizeof(common_hdr) - 1); memcpy(buf, &common_hdr, sizeof(common_hdr)); info.version = short_version; if (!strncmp(version, "skiboot-", 8)) strncpy(info.version, &version[8], MAX_STR_LEN + 1); else strncpy(info.version, version, MAX_STR_LEN + 1); if (info.version[MAX_STR_LEN] != '\0') info.version[MAX_STR_LEN - 1] = '+'; info.version[MAX_STR_LEN] = '\0'; len = fru_fill_product_info(&buf[64], &info, size - 64); if (len < 0) return OPAL_PARAMETER; return len + 64; } static void fru_write_complete(struct ipmi_msg *msg) { u8 write_count = msg->data[0]; u16 offset; msg->data[WRITE_INDEX] += write_count; msg->data[REMAINING] -= write_count; if (msg->data[REMAINING] == 0) goto out; offset = msg->data[WRITE_INDEX]; ipmi_init_msg(msg, IPMI_DEFAULT_INTERFACE, IPMI_WRITE_FRU, fru_write_complete, NULL, MIN(msg->data[REMAINING] + 3, IPMI_MAX_REQ_SIZE), 2); memmove(&msg->data[3], &msg->data[offset + 3], msg->req_size - 3); msg->data[0] = fru_dev_id; /* FRU Device ID */ msg->data[1] = offset & 0xff; /* Offset LSB */ msg->data[2] = (offset >> 8) & 0xff; /* Offset MSB */ ipmi_queue_msg(msg); return; out: ipmi_free_msg(msg); }
static void get_sel_time_error(struct ipmi_msg *msg) { time_status = error; ipmi_free_msg(msg); }