static int64_t opal_ipmi_send(uint64_t interface, struct opal_ipmi_msg *opal_ipmi_msg, uint64_t msg_len) { struct ipmi_msg *msg; if (opal_ipmi_msg->version != OPAL_IPMI_MSG_FORMAT_VERSION_1) { prerror("OPAL IPMI: Incorrect version\n"); return OPAL_UNSUPPORTED; } msg_len -= sizeof(struct opal_ipmi_msg); if (msg_len > IPMI_MAX_REQ_SIZE) { prerror("OPAL IPMI: Invalid request length\n"); return OPAL_PARAMETER; } prlog(PR_DEBUG, "opal_ipmi_send(cmd: 0x%02x netfn: 0x%02x len: 0x%02llx)\n", opal_ipmi_msg->cmd, opal_ipmi_msg->netfn >> 2, msg_len); msg = ipmi_mkmsg(interface, IPMI_CODE(opal_ipmi_msg->netfn >> 2, opal_ipmi_msg->cmd), opal_send_complete, NULL, opal_ipmi_msg->data, msg_len, IPMI_MAX_RESP_SIZE); if (!msg) return OPAL_RESOURCE; msg->complete = opal_send_complete; msg->error = opal_send_complete; return ipmi_queue_msg(msg); }
static int fru_write(void) { struct ipmi_msg *msg; int len; /* We allocate FRU_DATA_SIZE + 5 bytes for the message: * - 3 bytes for the the write FRU command header * - FRU_DATA_SIZE bytes for FRU data * - 2 bytes for offset & bytes remaining count */ msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE, IPMI_WRITE_FRU, fru_write_complete, NULL, NULL, FRU_DATA_SIZE + 5, 2); if (!msg) return OPAL_RESOURCE; msg->data[0] = fru_dev_id; /* FRU Device ID */ msg->data[1] = 0x0; /* Offset LSB (we always write a new common header) */ msg->data[2] = 0x0; /* Offset MSB */ len = fru_add(&msg->data[3], FRU_DATA_SIZE); if (len < 0) return len; /* Three bytes for the actual FRU Data Command */ msg->data[WRITE_INDEX] = 0; msg->data[REMAINING] = len; msg->req_size = min(len + 3, IPMI_MAX_REQ_SIZE); return ipmi_queue_msg(msg); }
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_elog_commit(struct errorlog *elog_buf) { struct ipmi_msg *msg; /* Only log events that needs attention */ if (elog_buf->event_severity < OPAL_PREDICTIVE_ERR_FAULT_RECTIFY_REBOOT || elog_buf->elog_origin != ORG_SAPPHIRE) { prlog(PR_INFO, "dropping non severe PEL event\n"); opal_elog_complete(elog_buf, true); return 0; } /* * We pass a large request size in to mkmsg so that we have a * large enough allocation to reuse the message to pass the * PEL data via a series of partial add commands. */ msg = ipmi_sel_alloc_msg(elog_buf); if (!msg) { opal_elog_complete(elog_buf, false); return OPAL_RESOURCE; } msg->error = ipmi_elog_error; msg->req_size = 0; if (elog_buf->event_severity == OPAL_ERROR_PANIC) ipmi_queue_msg_sync(msg); else ipmi_queue_msg(msg); return 0; }
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; }
int ipmi_set_power_state(uint8_t system, uint8_t device) { struct ipmi_msg *msg; struct { uint8_t system; uint8_t device; } power_state; if (!ipmi_present()) return OPAL_CLOSED; power_state.system = system; power_state.device = device; if (system != IPMI_PWR_NOCHANGE) power_state.system |= 0x80; if (device != IPMI_PWR_NOCHANGE) power_state.device |= 0x80; msg = ipmi_mkmsg_simple(IPMI_SET_POWER_STATE, &power_state, sizeof(power_state)); if (!msg) return OPAL_HARDWARE; prlog(PR_INFO, "IPMI: setting power state: sys %02x, dev %02x\n", power_state.system, power_state.device); return ipmi_queue_msg(msg); }
static void ipmi_elog_error(struct ipmi_msg *msg) { if (msg->cc == IPMI_LOST_ARBITRATION_ERR) /* Retry due to SEL erase */ ipmi_queue_msg(msg); else { opal_elog_complete(msg->user_data, false); ipmi_sel_free_msg(msg); } }
static int64_t ipmi_set_sel_time(uint32_t _tv) { struct ipmi_msg *msg; const le32 tv = cpu_to_le32(_tv); msg = ipmi_mkmsg_simple(IPMI_SET_SEL_TIME, (void*)&tv, sizeof(tv)); if (!msg) return OPAL_HARDWARE; return ipmi_queue_msg(msg); }
static int64_t ipmi_get_sel_time(void) { struct ipmi_msg *msg; msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE, IPMI_GET_SEL_TIME, get_sel_time_complete, NULL, NULL, 0, 4); if (!msg) return OPAL_HARDWARE; msg->error = get_sel_time_error; return ipmi_queue_msg(msg); }
static void get_bt_caps(void) { struct ipmi_msg *bmc_caps; /* * Didn't sent a message, now is a good time to ask the BMC for its * capabilities. */ bmc_caps = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE, IPMI_GET_BT_CAPS, get_bt_caps_complete, NULL, NULL, 0, sizeof(struct bt_caps)); if (!bmc_caps) prerror("Couldn't create BMC BT capabilities msg\n"); if (bmc_caps && ipmi_queue_msg(bmc_caps)) prerror("Couldn't enqueue request for BMC BT capabilities\n"); /* Ignore errors, we'll fallback to using the defaults, no big deal */ }
static void set_wdt(uint8_t action, uint16_t count, uint8_t pretimeout) { struct ipmi_msg *ipmi_msg; ipmi_msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE, IPMI_SET_WDT, ipmi_wdt_complete, NULL, NULL, 6, 0); if (!ipmi_msg) { prerror("Unable to allocate set wdt message\n"); return; } ipmi_msg->error = ipmi_wdt_complete; ipmi_msg->data[0] = TIMER_USE_POST | TIMER_USE_DONT_LOG; /* Timer Use */ ipmi_msg->data[1] = action; /* Timer Actions */ ipmi_msg->data[2] = pretimeout; /* Pre-timeout Interval */ ipmi_msg->data[3] = 0; /* Timer Use Flags */ ipmi_msg->data[4] = count & 0xff; /* Initial countdown (lsb) */ ipmi_msg->data[5] = (count >> 8) & 0xff; /* Initial countdown (msb) */ ipmi_queue_msg(ipmi_msg); }
int ipmi_chassis_control(uint8_t request) { struct ipmi_msg *msg; if (!ipmi_present()) return OPAL_CLOSED; if (request > IPMI_CHASSIS_SOFT_SHUTDOWN) return OPAL_PARAMETER; msg = ipmi_mkmsg_simple(IPMI_CHASSIS_CONTROL, &request, sizeof(request)); if (!msg) return OPAL_HARDWARE; prlog(PR_INFO, "IPMI: sending chassis control request 0x%02x\n", request); return ipmi_queue_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); }