#include #include #include #include #include #include /* Create MTMS section for sapphire log */ static void create_mtms_section(struct errorlog *elog_data, char *pel_buffer, int *pel_offset) { const struct dt_property *p; struct opal_mtms_section *mtms = (struct opal_mtms_section *) (pel_buffer + *pel_offset); mtms->v6header.id = ELOG_SID_MACHINE_TYPE; mtms->v6header.length = MTMS_SECTION_SIZE; mtms->v6header.version = OPAL_EXT_HRD_VER; mtms->v6header.subtype = 0; mtms->v6header.component_id = elog_data->component_id; memset(mtms->model, 0x00, sizeof(mtms->model)); memcpy(mtms->model, dt_prop_get(dt_root, "model"), OPAL_SYS_MODEL_LEN); memset(mtms->serial_no, 0x00, sizeof(mtms->serial_no)); p = dt_find_property(dt_root, "system-id"); if (p) memcpy(mtms->serial_no, p->prop, OPAL_SYS_SERIAL_LEN); else memset(mtms->serial_no, 0, OPAL_SYS_SERIAL_LEN); *pel_offset += MTMS_SECTION_SIZE; } /* Create extended header section */ static void create_extended_header_section(struct errorlog *elog_data, char *pel_buffer, int *pel_offset) { const char *opalmodel = NULL; const struct dt_property *p; uint64_t extd_time; struct opal_extended_header_section *extdhdr = (struct opal_extended_header_section *) (pel_buffer + *pel_offset); extdhdr->v6header.id = ELOG_SID_EXTENDED_HEADER; extdhdr->v6header.length = EXTENDED_HEADER_SECTION_SIZE; extdhdr->v6header.version = OPAL_EXT_HRD_VER; extdhdr->v6header.subtype = 0; extdhdr->v6header.component_id = elog_data->component_id; memset(extdhdr->model, 0x00, sizeof(extdhdr->model)); opalmodel = dt_prop_get(dt_root, "model"); memcpy(extdhdr->model, opalmodel, OPAL_SYS_MODEL_LEN); memset(extdhdr->serial_no, 0x00, sizeof(extdhdr->serial_no)); p = dt_find_property(dt_root, "system-id"); if (p) memcpy(extdhdr->serial_no, p->prop, OPAL_SYS_SERIAL_LEN); else memset(extdhdr->serial_no, 0, OPAL_SYS_SERIAL_LEN); memset(extdhdr->opal_release_version, 0x00, sizeof(extdhdr->opal_release_version)); memset(extdhdr->opal_subsys_version, 0x00, sizeof(extdhdr->opal_subsys_version)); rtc_cache_get_datetime(&extdhdr->extended_header_date, &extd_time); extdhdr->extended_header_time = extd_time >> 32; extdhdr->opal_symid_len = 0; *pel_offset += EXTENDED_HEADER_SECTION_SIZE; } /* set src type */ static void settype(struct opal_src_section *src, uint8_t src_type) { char type[4]; snprintf(type, sizeof(type), "%02X", src_type); memcpy(src->srcstring, type, 2); } /* set SRC subsystem type */ static void setsubsys(struct opal_src_section *src, uint8_t src_subsys) { char subsys[4]; snprintf(subsys, sizeof(subsys), "%02X", src_subsys); memcpy(src->srcstring+2, subsys, 2); } /* Ser reason code of SRC */ static void setrefcode(struct opal_src_section *src, uint16_t src_refcode) { char refcode[8]; snprintf(refcode, sizeof(refcode), "%04X", src_refcode); memcpy(src->srcstring+4, refcode, 4); } /* Create SRC section of OPAL log */ static void create_src_section(struct errorlog *elog_data, char *pel_buffer, int *pel_offset) { struct opal_src_section *src = (struct opal_src_section *) (pel_buffer + *pel_offset); src->v6header.id = ELOG_SID_PRIMARY_SRC; src->v6header.length = SRC_SECTION_SIZE; src->v6header.version = OPAL_ELOG_VERSION; src->v6header.subtype = OPAL_ELOG_SST; src->v6header.component_id = elog_data->component_id; src->version = OPAL_SRC_SEC_VER; src->flags = 0; src->wordcount = OPAL_SRC_MAX_WORD_COUNT; src->srclength = SRC_LENGTH; settype(src, OPAL_SRC_TYPE_ERROR); setsubsys(src, OPAL_FAILING_SUBSYSTEM); setrefcode(src, elog_data->reason_code); memset(src->hexwords, 0 , (8 * 4)); src->hexwords[0] = OPAL_SRC_FORMAT; src->hexwords[4] = elog_data->additional_info[0]; src->hexwords[5] = elog_data->additional_info[1]; src->hexwords[6] = elog_data->additional_info[2]; src->hexwords[7] = elog_data->additional_info[3]; *pel_offset += SRC_SECTION_SIZE; } /* Create user header section */ static void create_user_header_section(struct errorlog *elog_data, char *pel_buffer, int *pel_offset) { struct opal_user_header_section *usrhdr = (struct opal_user_header_section *) (pel_buffer + *pel_offset); usrhdr->v6header.id = ELOG_SID_USER_HEADER; usrhdr->v6header.length = USER_HEADER_SECTION_SIZE; usrhdr->v6header.version = OPAL_ELOG_VERSION; usrhdr->v6header.subtype = OPAL_ELOG_SST; usrhdr->v6header.component_id = elog_data->component_id; usrhdr->subsystem_id = elog_data->subsystem_id; usrhdr->event_scope = 0; usrhdr->event_severity = elog_data->event_severity; usrhdr->event_type = elog_data->event_subtype; if (elog_data->elog_origin == ORG_SAPPHIRE) usrhdr->action_flags = ERRL_ACTION_REPORT; else usrhdr->action_flags = ERRL_ACTION_NONE; *pel_offset += USER_HEADER_SECTION_SIZE; } /* Create private header section */ static void create_private_header_section(struct errorlog *elog_data, char *pel_buffer, int *pel_offset) { uint64_t ctime; struct opal_private_header_section *privhdr = (struct opal_private_header_section *) pel_buffer; privhdr->v6header.id = ELOG_SID_PRIVATE_HEADER; privhdr->v6header.length = PRIVATE_HEADER_SECTION_SIZE; privhdr->v6header.version = OPAL_ELOG_VERSION; privhdr->v6header.subtype = OPAL_ELOG_SST; privhdr->v6header.component_id = elog_data->component_id; privhdr->plid = elog_data->plid; rtc_cache_get_datetime(&privhdr->create_date, &ctime); privhdr->create_time = ctime >> 32; privhdr->section_count = 5; privhdr->creator_subid_hi = 0x00; privhdr->creator_subid_lo = 0x00; if (elog_data->elog_origin == ORG_SAPPHIRE) privhdr->creator_id = OPAL_CID_SAPPHIRE; else privhdr->creator_id = OPAL_CID_POWERNV; privhdr->log_entry_id = elog_data->plid; /*entry id is updated by FSP*/ *pel_offset += PRIVATE_HEADER_SECTION_SIZE; } static void create_user_defined_section(struct errorlog *elog_data, char *pel_buffer, int *pel_offset) { char *dump = (char *)pel_buffer + *pel_offset; char *opal_buf = (char *)elog_data->user_data_dump; struct opal_user_section *usrhdr; struct elog_user_data_section *opal_usr_data; struct opal_private_header_section *privhdr = (struct opal_private_header_section *)pel_buffer; int i; for (i = 0; i < elog_data->user_section_count; i++) { usrhdr = (struct opal_user_section *)dump; opal_usr_data = (struct elog_user_data_section *)opal_buf; usrhdr->v6header.id = ELOG_SID_USER_DEFINED; usrhdr->v6header.version = OPAL_ELOG_VERSION; usrhdr->v6header.length = sizeof(struct opal_v6_header) + opal_usr_data->size; usrhdr->v6header.subtype = OPAL_ELOG_SST; usrhdr->v6header.component_id = elog_data->component_id; memcpy(usrhdr->dump, opal_buf, opal_usr_data->size); *pel_offset += usrhdr->v6header.length; dump += usrhdr->v6header.length; opal_buf += opal_usr_data->size; privhdr->section_count++; } } static size_t pel_user_section_size(struct errorlog *elog_data) { int i; size_t total = 0; char *opal_buf = (char *)elog_data->user_data_dump; struct elog_user_data_section *opal_usr_data; for (i = 0; i < elog_data->user_section_count; i++) { opal_usr_data = (struct elog_user_data_section *)opal_buf; total += sizeof(struct opal_v6_header) + opal_usr_data->size; opal_buf += opal_usr_data->size; } return total; } size_t pel_size(struct errorlog *elog_data) { return PEL_MIN_SIZE + pel_user_section_size(elog_data); } /* Converts an OPAL errorlog into a PEL formatted log */ int create_pel_log(struct errorlog *elog_data, char *pel_buffer, size_t pel_buffer_size) { int pel_offset = 0; if (pel_buffer_size < pel_size(elog_data)) { prerror("PEL buffer too small to create record\n"); return 0; } memset(pel_buffer, 0, pel_buffer_size); create_private_header_section(elog_data, pel_buffer, &pel_offset); create_user_header_section(elog_data, pel_buffer, &pel_offset); create_src_section(elog_data, pel_buffer, &pel_offset); create_extended_header_section(elog_data, pel_buffer, &pel_offset); create_mtms_section(elog_data, pel_buffer, &pel_offset); if (elog_data->user_section_count) create_user_defined_section(elog_data, pel_buffer, &pel_offset); return pel_offset; }