static int prd_init(struct opal_prd_ctx *ctx) { int rc; ctx->page_size = sysconf(_SC_PAGE_SIZE); /* set up the device, and do our get_info ioctl */ ctx->fd = open(opal_prd_devnode, O_RDWR); if (ctx->fd < 0) { pr_log(LOG_ERR, "FW: Can't open PRD device %s: %m", opal_prd_devnode); return -1; } rc = ioctl(ctx->fd, OPAL_PRD_GET_INFO, &ctx->info); if (rc) { pr_log(LOG_ERR, "FW: Can't query PRD information: %m"); return -1; } rc = prd_init_ranges(ctx); if (rc) { pr_log(LOG_ERR, "FW: can't parse PRD memory information"); return -1; } return 0; }
static int is_prd_supported(void) { char *path; int rc; int len; char *buf; rc = asprintf(&path, "%s/ibm,opal/diagnostics/compatible", devicetree_base); if (rc < 0) { pr_log(LOG_ERR, "FW: error creating 'compatible' node path: %m"); return -1; } rc = open_and_read(path, (void *) &buf, &len); if (rc) goto out_free; if (buf[len - 1] != '\0') pr_log(LOG_INFO, "FW: node %s is not nul-terminated", path); rc = find_string(buf, len, "ibm,opal-prd") ? 0 : -1; free(buf); out_free: free(path); return rc; }
static int run_attn_loop(struct opal_prd_ctx *ctx) { struct pollfd pollfds[2]; struct opal_prd_msg msg; int rc, fd; if (hservice_runtime->enable_attns) { pr_debug("HBRT: calling enable_attns"); rc = call_enable_attns(); if (rc) { pr_log(LOG_ERR, "HBRT: enable_attns() failed, " "aborting"); return -1; } } /* send init message, to unmask interrupts */ msg.hdr.type = OPAL_PRD_MSG_TYPE_INIT; msg.hdr.size = htobe16(sizeof(msg)); msg.init.version = htobe64(opal_prd_version); msg.init.ipoll = htobe64(opal_prd_ipoll); pr_debug("FW: writing init message"); rc = write(ctx->fd, &msg, sizeof(msg)); if (rc != sizeof(msg)) { pr_log(LOG_ERR, "FW: Init message failed: %m. Aborting."); return -1; } pollfds[0].fd = ctx->fd; pollfds[0].events = POLLIN | POLLERR; pollfds[1].fd = ctx->socket; pollfds[1].events = POLLIN | POLLERR; for (;;) { rc = poll(pollfds, 2, -1); if (rc < 0) { pr_log(LOG_ERR, "FW: event poll failed: %m"); exit(EXIT_FAILURE); } if (!rc) continue; if (pollfds[0].revents & POLLIN) handle_prd_msg(ctx); if (pollfds[1].revents & POLLIN) { fd = accept(ctx->socket, NULL, NULL); if (fd < 0) { pr_log(LOG_NOTICE, "CTRL: accept failed: %m"); continue; } handle_prd_control(ctx, fd); close(fd); } } return 0; }
static void print_ranges(struct opal_prd_ctx *ctx) { int i; if (ctx->n_ranges == 0) pr_log(LOG_INFO, "FW: No PRD ranges"); pr_log(LOG_DEBUG, "FW: %d PRD ranges, instances assigned by %s", ctx->n_ranges, ctx->fw_range_instances ? "firmware" : "userspace"); for (i = 0; i < ctx->n_ranges; i++) { struct prd_range *range = &ctx->ranges[i]; char instance_str[20]; if (range->multiple) snprintf(instance_str, sizeof(instance_str), " [%d]", range->instance); else instance_str[0] = '\0'; pr_log(LOG_DEBUG, "FW: %016lx-%016lx %s%s", range->physaddr, range->physaddr + range->size - 1, range->name, instance_str); } }
static int map_hbrt_file(struct opal_prd_ctx *ctx, const char *name) { struct stat statbuf; int fd, rc; void *buf; fd = open(name, O_RDONLY); if (fd < 0) { pr_log(LOG_ERR, "IMAGE: HBRT file open(%s) failed: %m", name); return -1; } rc = fstat(fd, &statbuf); if (rc < 0) { pr_log(LOG_ERR, "IMAGE: HBRT file fstat(%s) failed: %m", name); close(fd); return -1; } buf = mmap(NULL, statbuf.st_size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0); close(fd); if (buf == MAP_FAILED) { pr_log(LOG_ERR, "IMAGE: HBRT file mmap(%s, 0x%zx) failed: %m", name, statbuf.st_size); return -1; } ctx->code_addr = buf; ctx->code_size = statbuf.st_size; return -0; }
static int handle_msg_attn(struct opal_prd_ctx *ctx, struct opal_prd_msg *msg) { uint64_t proc, ipoll_mask, ipoll_status; int rc; proc = be64toh(msg->attn.proc); ipoll_status = be64toh(msg->attn.ipoll_status); ipoll_mask = be64toh(msg->attn.ipoll_mask); if (!hservice_runtime->handle_attns) { pr_log_nocall("handle_attns"); return -1; } rc = call_handle_attns(proc, ipoll_status, ipoll_mask); if (rc) { pr_log(LOG_ERR, "HBRT: handle_attns(%lx,%lx,%lx) failed, rc %d", proc, ipoll_status, ipoll_mask, rc); return -1; } /* send the response */ msg->hdr.type = OPAL_PRD_MSG_TYPE_ATTN_ACK; msg->hdr.size = htobe16(sizeof(*msg)); msg->attn_ack.proc = htobe64(proc); msg->attn_ack.ipoll_ack = htobe64(ipoll_status); rc = write(ctx->fd, msg, sizeof(*msg)); if (rc != sizeof(*msg)) { pr_log(LOG_WARNING, "FW: Failed to send ATTN_ACK message: %m"); return -1; } return 0; }
void hservices_init(struct opal_prd_ctx *ctx, void *code) { uint64_t *s, *d; int i, sz; pr_debug("IMAGE: code address: %p", code); /* We enter at 0x100 into the image. */ /* Load func desc in BE since we reverse it in thunk */ hbrt_entry.addr = (void *)htobe64((unsigned long)code + 0x100); hbrt_entry.toc = 0; /* No toc for init entry point */ if (memcmp(code, "HBRTVERS", 8) != 0) pr_log(LOG_ERR, "IMAGE: Bad signature for " "ibm,hbrt-code-image! exiting"); pr_debug("IMAGE: calling ibm,hbrt_init()"); hservice_runtime = call_hbrt_init(&hinterface); pr_log(LOG_NOTICE, "IMAGE: hbrt_init complete, version %016lx", hservice_runtime->interface_version); sz = sizeof(struct runtime_interfaces)/sizeof(uint64_t); s = (uint64_t *)hservice_runtime; d = (uint64_t *)&hservice_runtime_fixed; /* Byte swap the function pointers */ for (i = 0; i < sz; i++) d[i] = be64toh(s[i]); }
static int ipmi_recv(int fd, uint8_t *netfn, uint8_t *cmd, long *seq, uint8_t *buf, size_t *len) { struct ipmi_recv recv; struct ipmi_addr addr; int rc; recv.addr = (unsigned char *)&addr; recv.addr_len = sizeof(addr); recv.msg.data = buf; recv.msg.data_len = *len; rc = ioctl(fd, IPMICTL_RECEIVE_MSG_TRUNC, &recv); if (rc < 0 && errno != EMSGSIZE) { pr_log(LOG_WARNING, "IPMI: recv (%zd bytes) failed: %m", *len); return -1; } else if (rc < 0 && errno == EMSGSIZE) { pr_log(LOG_NOTICE, "IPMI: truncated message (netfn %d, cmd %d, " "size %zd), continuing anyway", recv.msg.netfn, recv.msg.cmd, *len); } *netfn = recv.msg.netfn; *cmd = recv.msg.cmd; *seq = recv.msgid; *len = recv.msg.data_len; return 0; }
static void dump_hbrt_map(struct opal_prd_ctx *ctx) { const char *dump_name = "hbrt.bin"; int fd, rc; if (!ctx->debug) return; fd = open(dump_name, O_WRONLY | O_CREAT, 0644); if (fd < 0) { pr_log(LOG_NOTICE, "IMAGE: couldn't debug image %s for writing", dump_name); return; } rc = ftruncate(fd, 0); if (rc < 0) { pr_log(LOG_NOTICE, "IMAGE: couldn't truncate image %s for writing", dump_name); return; } rc = write(fd, ctx->code_addr, ctx->code_size); close(fd); if (rc != ctx->code_size) pr_log(LOG_NOTICE, "IMAGE: write to %s failed: %m", dump_name); else pr_debug("IMAGE: dumped HBRT binary to %s", dump_name); }
static int send_attr_override(struct opal_prd_ctx *ctx, uint32_t argc, char *argv[]) { struct control_msg *send_msg, *recv_msg = NULL; struct stat statbuf; size_t sz; FILE *fd; int rc; rc = stat(argv[0], &statbuf); if (rc) { pr_log(LOG_ERR, "CTRL: stat() failed on the file: %m"); return -1; } send_msg = malloc(sizeof(*send_msg) + statbuf.st_size); if (!send_msg) { pr_log(LOG_ERR, "CTRL: msg buffer malloc failed: %m"); return -1; } send_msg->type = CONTROL_MSG_ATTR_OVERRIDE; send_msg->data_len = statbuf.st_size; fd = fopen(argv[0], "r"); if (!fd) { pr_log(LOG_NOTICE, "CTRL: can't open %s: %m", argv[0]); rc = -1; goto out_free; } sz = fread(send_msg->data, 1, send_msg->data_len, fd); fclose(fd); if (sz != statbuf.st_size) { pr_log(LOG_ERR, "CTRL: short read from the file"); rc = -1; goto out_free; } rc = send_prd_control(send_msg, &recv_msg); if (recv_msg) { if (recv_msg->response || ctx->debug) pr_debug("CTRL: attribute override returned status %d", recv_msg->response); free(recv_msg); } out_free: free(send_msg); return rc; }
static int send_run_command(struct opal_prd_ctx *ctx, int argc, char *argv[]) { struct control_msg *send_msg, *recv_msg = NULL; uint32_t size = 0; int rc, i; char *s; if (!ctx->expert_mode) { pr_log(LOG_WARNING, "CTRL: need to be in expert mode"); return -1; } if (ctx->debug) { pr_debug("CTRL: run command arguments:"); for (i=0; i < argc; i++) pr_debug("argv[%d] = %s", i, argv[i]); } for (i = 0; i < argc; i++) size += (strlen(argv[i]) + 1); send_msg = malloc(sizeof(*send_msg) + size); if (!send_msg) { pr_log(LOG_ERR, "CTRL: msg buffer malloc failed: %m"); return -1; } /* Setup message */ send_msg->type = CONTROL_MSG_RUN_CMD; send_msg->argc = argc; send_msg->data_len = size; s = (char *)send_msg->data; for (i = 0; i < argc; i++) { strcpy(s, argv[i]); s = s + strlen(argv[i]) + 1; } rc = send_prd_control(send_msg, &recv_msg); free(send_msg); if (recv_msg) { if (!rc) pr_log(LOG_INFO, "Received: %s", recv_msg->data); if (recv_msg->response || ctx->debug) pr_debug("CTRL: run command returned status %d", recv_msg->response); free(recv_msg); } return rc; }
static void handle_prd_control_run_cmd(struct control_msg *send_msg, struct control_msg *recv_msg) { char *runcmd_output, *s; const char **argv; int i, argc; size_t size; if (!hservice_runtime->run_command) { pr_log_nocall("run_command"); return; } argc = recv_msg->argc; pr_debug("CTRL: run_command, argc:%d\n", argc); argv = malloc(argc * sizeof(*argv)); if (!argv) { pr_log(LOG_ERR, "CTRL: argv buffer malloc failed: %m"); return; } s = (char *)recv_msg->data; size = 0; for (i = 0; i < argc; i++) { argv[i] = (char *)htobe64((uint64_t)&s[size]); size += (strlen(&s[size]) + 1); } /* Call HBRT */ send_msg->response = call_run_command(argc, argv, &runcmd_output); runcmd_output = (char *)be64toh((uint64_t)runcmd_output); free(argv); s = (char *)send_msg->data; if (runcmd_output) { size = strlen(runcmd_output); if (size >= MAX_CONTROL_MSG_BUF) { pr_log(LOG_WARNING, "CTRL: output message truncated"); runcmd_output[MAX_CONTROL_MSG_BUF] = '\0'; size = MAX_CONTROL_MSG_BUF; } strcpy(s, runcmd_output); send_msg->data_len = size + 1; free(runcmd_output); } else { strcpy(s, "Null"); send_msg->data_len = strlen("Null") + 1; } }
static int parse_action(const char *str, enum action *action) { int rc; if (!strcmp(str, "occ")) { *action = ACTION_OCC_CONTROL; rc = 0; } else if (!strcmp(str, "daemon")) { *action = ACTION_RUN_DAEMON; rc = 0; } else if (!strcmp(str, "override")) { *action = ACTION_ATTR_OVERRIDE; rc = 0; } else if (!strcmp(str, "htmgt-passthru")) { *action = ACTION_HTMGT_PASSTHRU; rc = 0; } else if (!strcmp(str, "run")) { *action = ACTION_RUN_COMMAND; return 0; } else { pr_log(LOG_ERR, "CTRL: unknown argument '%s'", str); rc = -1; } return rc; }
static int send_occ_control(struct opal_prd_ctx *ctx, const char *str) { struct control_msg send_msg, *recv_msg = NULL; int rc; memset(&send_msg, 0, sizeof(send_msg)); if (!strcmp(str, "enable")) send_msg.type = CONTROL_MSG_ENABLE_OCCS; else if (!strcmp(str, "disable")) send_msg.type = CONTROL_MSG_DISABLE_OCCS; else if (!strcmp(str, "reset")) send_msg.type = CONTROL_MSG_TEMP_OCC_RESET; else if (!strcmp(str, "process-error")) send_msg.type = CONTROL_MSG_TEMP_OCC_ERROR; else { pr_log(LOG_ERR, "CTRL: Invalid OCC action '%s'", str); return -1; } rc = send_prd_control(&send_msg, &recv_msg); if (recv_msg) { if (recv_msg->response || ctx->debug) pr_debug("CTRL: OCC action %s returned status %d", str, recv_msg->response); free(recv_msg); } return rc; }
uint64_t hservice_get_reserved_mem(const char *name, uint32_t instance) { struct prd_range *range; pr_debug("IMAGE: hservice_get_reserved_mem: %s, %d", name, instance); range = find_range(name, instance); if (!range) { pr_log(LOG_WARNING, "IMAGE: get_reserved_mem: " "no such range %s", name); return 0; } if (!range->buf) { uint64_t align_physaddr, offset; pr_debug("IMAGE: Mapping 0x%016lx 0x%08lx %s[%d]", range->physaddr, range->size, range->name, range->instance); align_physaddr = range->physaddr & ~(ctx->page_size-1); offset = range->physaddr & (ctx->page_size-1); range->buf = mmap(NULL, range->size, PROT_WRITE | PROT_READ, MAP_SHARED, ctx->fd, align_physaddr); if (range->buf == MAP_FAILED) pr_log(LOG_ERR, "IMAGE: mmap of %s[%d](0x%016lx) failed: %m", name, instance, range->physaddr); else range->buf += offset; } if (range->buf == MAP_FAILED) { pr_log(LOG_WARNING, "IMAGE: get_reserved_mem: %s[%d] has no vaddr", name, instance); return 0; } pr_debug( "IMAGE: hservice_get_reserved_mem: %s[%d](0x%016lx) address %p", name, range->instance, range->physaddr, range->buf); return (uint64_t)range->buf; }
int hservice_memory_error(uint64_t i_start_addr, uint64_t i_endAddr, enum MemoryError_t i_errorType) { const char *sysfsfile, *typestr; char buf[ADDR_STRING_SZ]; int memfd, rc, n; uint64_t addr; switch(i_errorType) { case MEMORY_ERROR_CE: sysfsfile = mem_offline_soft; typestr = "correctable"; break; case MEMORY_ERROR_UE: sysfsfile = mem_offline_hard; typestr = "uncorrectable"; break; default: pr_log(LOG_WARNING, "MEM: Invalid memory error type %d", i_errorType); return -1; } pr_log(LOG_ERR, "MEM: Memory error: range %016lx-%016lx, type: %s", i_start_addr, i_endAddr, typestr); memfd = open(sysfsfile, O_WRONLY); if (memfd < 0) { pr_log(LOG_CRIT, "MEM: Failed to offline memory! " "Unable to open sysfs node %s: %m", sysfsfile); return -1; } for (addr = i_start_addr; addr <= i_endAddr; addr += ctx->page_size) { n = snprintf(buf, ADDR_STRING_SZ, "0x%lx", addr); rc = write(memfd, buf, n); if (rc != n) { pr_log(LOG_CRIT, "MEM: Failed to offline memory! " "page addr: %016lx type: %d: %m", addr, i_errorType); return rc; } } return 0; }
static int prd_init_ranges(struct opal_prd_ctx *ctx) { struct dirent *dirent; char *path; DIR *dir; int rc; rc = asprintf(&path, "%s/reserved-memory", devicetree_base); if (rc < 0) { pr_log(LOG_ERR, "FW: error creating 'reserved-memory' path " "node: %m"); return -1; } rc = -1; dir = opendir(path); if (!dir) { pr_log(LOG_ERR, "FW: can't open reserved-memory device-tree " "node: %m"); goto out_free; } for (;;) { dirent = readdir(dir); if (!dirent) break; prd_init_one_range(ctx, path, dirent); } rc = 0; /* sort ranges and assign instance numbers for duplicates (if the * firmware doesn't number instances for us) */ qsort(ctx->ranges, ctx->n_ranges, sizeof(struct prd_range), compare_ranges); if (!ctx->fw_range_instances) assign_range_instances(ctx); print_ranges(ctx); out_free: free(path); closedir(dir); return rc; }
static int send_htmgt_passthru(struct opal_prd_ctx *ctx, int argc, char *argv[]) { struct control_msg *send_msg, *recv_msg = NULL; int rc, i; if (!ctx->expert_mode) { pr_log(LOG_WARNING, "CTRL: need to be in expert mode"); return -1; } send_msg = malloc(sizeof(*send_msg) + argc); if (!send_msg) { pr_log(LOG_ERR, "CTRL: message buffer malloc failed: %m"); return -1; } send_msg->type = CONTROL_MSG_HTMGT_PASSTHRU; send_msg->data_len = argc; if (ctx->debug) pr_debug("CTRL: HTMGT passthru arguments:"); for (i = 0; i < argc; i++) { if (ctx->debug) pr_debug("argv[%d] = %s", i, argv[i]); sscanf(argv[i], "%hhx", &send_msg->data[i]); } rc = send_prd_control(send_msg, &recv_msg); free(send_msg); if (recv_msg) { if (recv_msg->response || ctx->debug) pr_debug("CTRL: HTMGT passthru returned status %d", recv_msg->response); if (recv_msg->response == 0 && recv_msg->data_len) hexdump(recv_msg->data, recv_msg->data_len); free(recv_msg); } return rc; }
static int handle_prd_msg(struct opal_prd_ctx *ctx) { struct opal_prd_msg msg; int size; int rc; rc = read(ctx->fd, &msg, sizeof(msg)); if (rc < 0 && errno == EAGAIN) return -1; if (rc != sizeof(msg)) { pr_log(LOG_WARNING, "FW: Error reading events from OPAL: %m"); return -1; } size = htobe16(msg.hdr.size); if (size < sizeof(msg)) { pr_log(LOG_ERR, "FW: Mismatched message size " "between opal-prd and firmware " "(%d from FW, %zd expected)", size, sizeof(msg)); return -1; } switch (msg.hdr.type) { case OPAL_PRD_MSG_TYPE_ATTN: rc = handle_msg_attn(ctx, &msg); break; case OPAL_PRD_MSG_TYPE_OCC_RESET: rc = handle_msg_occ_reset(ctx, &msg); break; case OPAL_PRD_MSG_TYPE_OCC_ERROR: rc = handle_msg_occ_error(ctx, &msg); break; default: pr_log(LOG_WARNING, "Invalid incoming message type 0x%x", msg.hdr.type); return -1; } return 0; }
static int init_control_socket(struct opal_prd_ctx *ctx) { struct sockaddr_un addr; int fd, rc; unlink(opal_prd_socket); addr.sun_family = AF_UNIX; strcpy(addr.sun_path, opal_prd_socket); fd = socket(AF_LOCAL, SOCK_STREAM, 0); if (fd < 0) { pr_log(LOG_WARNING, "CTRL: Can't open control socket %s: %m", opal_prd_socket); return -1; } rc = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); if (rc) { pr_log(LOG_WARNING, "CTRL: Can't bind control socket %s: %m", opal_prd_socket); close(fd); return -1; } rc = listen(fd, 0); if (rc) { pr_log(LOG_WARNING, "CTRL: Can't listen on " "control socket %s: %m", opal_prd_socket); close(fd); return -1; } pr_log(LOG_INFO, "CTRL: Listening on control socket %s", opal_prd_socket); ctx->socket = fd; return 0; }
static int send_prd_control(struct control_msg *send_msg, struct control_msg **recv_msg) { struct sockaddr_un addr; struct control_msg *msg; int sd, rc, size; sd = socket(AF_UNIX, SOCK_STREAM, 0); if (!sd) { pr_log(LOG_ERR, "CTRL: Failed to create control socket: %m"); return -1; } addr.sun_family = AF_UNIX; strcpy(addr.sun_path, opal_prd_socket); rc = connect(sd, (struct sockaddr *)&addr, sizeof(addr)); if (rc) { pr_log(LOG_ERR, "CTRL: Failed to connect to prd daemon: %m"); goto out_close; } size = sizeof(*send_msg) + send_msg->data_len; rc = send(sd, send_msg, size, 0); if (rc != size) { pr_log(LOG_ERR, "CTRL: Failed to send control message: %m"); rc = -1; goto out_close; } size = sizeof(*msg) + MAX_CONTROL_MSG_BUF; msg = malloc(size); if (!msg) { pr_log(LOG_ERR, "CTRL: msg buffer malloc failed: %m"); rc = -1; goto out_close; } *recv_msg = msg; /* wait for our reply */ rc = recv(sd, msg, size, 0); if (rc < 0) { pr_log(LOG_ERR, "CTRL: Failed to receive control message: %m"); goto out_close; } else if (rc != (sizeof(*msg) + msg->data_len)) { pr_log(LOG_WARNING, "CTRL: Short read from control socket"); rc = -1; goto out_close; } rc = msg->response; out_close: close(sd); return rc; }
static int map_hbrt_physmem(struct opal_prd_ctx *ctx, const char *name) { struct prd_range *range; void *buf; range = find_range(name, 0); if (!range) { pr_log(LOG_ERR, "IMAGE: can't find code region %s", name); return -1; } buf = mmap(NULL, range->size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, ctx->fd, range->physaddr); if (buf == MAP_FAILED) { pr_log(LOG_ERR, "IMAGE: mmap(range:%s, " "phys:0x%016lx, size:0x%016lx) failed: %m", name, range->physaddr, range->size); return -1; } ctx->code_addr = buf; ctx->code_size = range->size; return 0; }
static int parse_action(const char *str, enum action *action) { if (!strcmp(str, "occ")) { *action = ACTION_OCC_CONTROL; return 0; } if (!strcmp(str, "daemon")) { *action = ACTION_RUN_DAEMON; return 0; } pr_log(LOG_ERR, "CTRL: unknown argument '%s'", str); return -1; }
static void handle_prd_control_htmgt_passthru(struct control_msg *send_msg, struct control_msg *recv_msg) { uint16_t rsp_len; if (!hservice_runtime->mfg_htmgt_pass_thru) { pr_log_nocall("mfg_htmgt_pass_thru"); return; } pr_debug("CTRL: calling mfg_htmgt_pass_thru"); send_msg->response = call_mfg_htmgt_pass_thru(recv_msg->data_len, recv_msg->data, &rsp_len, send_msg->data); send_msg->data_len = be16toh(rsp_len); if (send_msg->data_len > MAX_CONTROL_MSG_BUF) { pr_log(LOG_ERR, "CTRL: response buffer overrun, data len: %d", send_msg->data_len); send_msg->data_len = MAX_CONTROL_MSG_BUF; } }
int hservice_scom_write(uint64_t chip_id, uint64_t addr, const void *buf) { int rc; struct opal_prd_scom scom; scom.chip = chip_id; scom.addr = addr; scom.data = be64toh(*(uint64_t *)buf); rc = ioctl(ctx->fd, OPAL_PRD_SCOM_WRITE, &scom); if (rc) { pr_log(LOG_ERR, "SCOM: ioctl write(chip 0x%lx, addr 0x%lx) " "failed: %m", chip_id, addr); return 0; } pr_debug("SCOM: write: chip 0x%lx, addr 0x%lx, val 0x%lx", chip_id, addr, scom.data); return 0; }
int hservice_scom_read(uint64_t chip_id, uint64_t addr, void *buf) { int rc; struct opal_prd_scom scom; scom.chip = chip_id; scom.addr = addr; rc = ioctl(ctx->fd, OPAL_PRD_SCOM_READ, &scom); if (rc) { pr_log(LOG_ERR, "SCOM: ioctl read(chip 0x%lx, addr 0x%lx) " "failed: %m", chip_id, addr); return 0; } pr_debug("SCOM: read: chip 0x%lx, addr 0x%lx, val 0x%lx", chip_id, addr, scom.data); *(uint64_t *)buf = htobe64(scom.data); return 0; }
void hservice_assert(void) { pr_log(LOG_ERR, "HBRT: Failed assertion! exiting."); exit(EXIT_FAILURE); }
int hservice_ipmi_msg(uint8_t netfn, uint8_t cmd, void *tx_buf, size_t tx_size, void *rx_buf, size_t *rx_size) { struct timeval start, now, delta; struct pollfd pollfds[1]; static long seq; size_t size; int rc, fd; size = be64toh(*rx_size); fd = open(ipmi_devnode, O_RDWR); if (fd < 0) { pr_log(LOG_WARNING, "IPMI: Failed to open IPMI device %s: %m", ipmi_devnode); return -1; } seq++; pr_debug("IPMI: sending %zd bytes (netfn 0x%02x, cmd 0x%02x)", tx_size, netfn, cmd); rc = ipmi_send(fd, netfn, cmd, seq, tx_buf, tx_size); if (rc) { pr_log(LOG_WARNING, "IPMI: send failed"); goto out; } gettimeofday(&start, NULL); pollfds[0].fd = fd; pollfds[0].events = POLLIN; for (;;) { long rx_seq; int timeout; gettimeofday(&now, NULL); timersub(&now, &start, &delta); timeout = ipmi_timeout_ms - ((delta.tv_sec * 1000) + (delta.tv_usec / 1000)); if (timeout < 0) timeout = 0; rc = poll(pollfds, 1, timeout); if (rc < 0) { pr_log(LOG_ERR, "IPMI: poll(%s) failed: %m", ipmi_devnode); break; } if (rc == 0) { pr_log(LOG_WARNING, "IPMI: response timeout (>%dms)", ipmi_timeout_ms); rc = -1; break; } rc = ipmi_recv(fd, &netfn, &cmd, &rx_seq, rx_buf, &size); if (rc) break; if (seq != rx_seq) { pr_log(LOG_NOTICE, "IPMI: out-of-sequence reply: %ld, " "expected %ld. Dropping message.", rx_seq, seq); continue; } pr_debug("IPMI: received %zd bytes", tx_size); *rx_size = be64toh(size); rc = 0; break; } out: close(fd); return rc; }
void hservice_puts(const char *str) { pr_log(LOG_INFO, "HBRT: %s", str); }
static int prd_init_one_range(struct opal_prd_ctx *ctx, const char *path, struct dirent *dirent) { char *label_path, *reg_path, *instance_path; struct prd_range *range; int label_len, len, rc; __be64 *reg; char *label; void *buf; rc = asprintf(&label_path, "%s/%s/ibm,prd-label", path, dirent->d_name); if (rc < 0) { pr_log(LOG_ERR, "FW: error creating 'ibm,prd-label' path " "node: %m"); return -1; } rc = asprintf(&instance_path, "%s/%s/ibm,prd-instance", path, dirent->d_name); if (rc < 0) { pr_log(LOG_ERR, "FW: error creating 'ibm,prd-instance' path " "node: %m"); return -1; } rc = asprintf(®_path, "%s/%s/reg", path, dirent->d_name); if (rc < 0) { pr_log(LOG_ERR, "FW: error creating 'reg' path " " node: %m"); return -1; } reg = NULL; label = NULL; rc = -1; rc = open_and_read(label_path, &buf, &label_len); if (rc) goto out_free; label = buf; if (label[label_len-1] != '\0') pr_log(LOG_INFO, "FW: node %s has invalid ibm,prd-label - " "not nul-terminated", dirent->d_name); rc = open_and_read(reg_path, &buf, &len); if (rc) goto out_free; reg = buf; if (len != 2 * sizeof(*reg)) { pr_log(LOG_ERR, "FW: node %s has invalid 'reg' size: %d", dirent->d_name, len); goto out_free; } ctx->ranges = realloc(ctx->ranges, ++ctx->n_ranges * sizeof(*range)); range = &ctx->ranges[ctx->n_ranges - 1]; range->name = strndup(label, label_len); range->physaddr = be64toh(reg[0]); range->size = be64toh(reg[1]); range->buf = NULL; range->multiple = false; range->instance = 0; /* optional instance */ rc = open_and_read(instance_path, &buf, &len); if (!rc && len == sizeof(uint32_t)) { range->multiple = true; range->instance = be32toh(*(uint32_t *)buf); ctx->fw_range_instances = true; } rc = 0; out_free: free(reg); free(label); free(instance_path); free(reg_path); free(label_path); return rc; }