/** * Find the data portion of an IO Event section from event log. * @elog: RTAS error/event log. * * Return: * pointer to a valid IO event section data. NULL if not found. */ static struct pseries_io_event * ioei_find_event(struct rtas_error_log *elog) { struct pseries_errorlog *sect; /* We should only ever get called for io-event interrupts, but if * we do get called for another type then something went wrong so * make some noise about it. * RTAS_TYPE_IO only exists in extended event log version 6 or later. * No need to check event log version. */ if (unlikely(rtas_error_type(elog) != RTAS_TYPE_IO)) { printk_once(KERN_WARNING"io_event_irq: Unexpected event type %d", rtas_error_type(elog)); return NULL; } sect = get_pseries_errorlog(elog, PSERIES_ELOG_SECT_ID_IO_EVENT); if (unlikely(!sect)) { printk_once(KERN_WARNING "io_event_irq: RTAS extended event " "log does not contain an IO Event section. " "Could be a bug in system firmware!\n"); return NULL; } return (struct pseries_io_event *) §->data; }
/* Yeah, the output here is ugly, but we want a CE to be * able to grep RTAS /var/log/messages and see all the info * collected together with obvious begin/end. */ static void printk_log_rtas(char *buf) { struct rtas_error_log *err = (struct rtas_error_log *)buf; printk(RTAS_ERR "-------- event-scan begin --------\n"); if (strcmp(buf+8+40, "IBM") == 0) { /* Location code follows */ char *loc = buf+8+40+4; int len = strlen(loc); if (len < 64) { /* Sanity check */ printk(RTAS_ERR "Location Code: %s\n", loc); printk_log_debug(loc+len+1); } } printk(RTAS_ERR "%s: (%s) type: %s\n", severity_names[err->severity], rtas_disposition_names[err->disposition], rtas_error_type(err->type)); printk(RTAS_ERR "initiator: %s target: %s\n", entity_names[err->initiator], entity_names[err->target]); if (err->extended_log_length) printk_ext_log_data(err->version, buf+8); printk(RTAS_ERR "-------- event-scan end ----------\n"); }
static void handle_rtas_event(const struct rtas_error_log *log) { if (rtas_error_type(log) != RTAS_TYPE_PRRN || !prrn_is_enabled()) return; /* For PRRN Events the extended log length is used to denote * the scope for calling rtas update-nodes. */ prrn_schedule_update(rtas_error_extended_log_length(log)); }
/* To see this info, grep RTAS /var/log/messages and each entry * will be collected together with obvious begin/end. * There will be a unique identifier on the begin and end lines. * This will persist across reboots. * * format of error logs returned from RTAS: * bytes (size) : contents * -------------------------------------------------------- * 0-7 (8) : rtas_error_log * 8-47 (40) : extended info * 48-51 (4) : vendor id * 52-1023 (vendor specific) : location code and debug data */ static void printk_log_rtas(char *buf, int len) { int i,j,n = 0; int perline = 16; char buffer[64]; char * str = "RTAS event"; if (full_rtas_msgs) { printk(RTAS_DEBUG "%d -------- %s begin --------\n", error_log_cnt, str); /* * Print perline bytes on each line, each line will start * with RTAS and a changing number, so syslogd will * print lines that are otherwise the same. Separate every * 4 bytes with a space. */ for (i = 0; i < len; i++) { j = i % perline; if (j == 0) { memset(buffer, 0, sizeof(buffer)); n = sprintf(buffer, "RTAS %d:", i/perline); } if ((i % 4) == 0) n += sprintf(buffer+n, " "); n += sprintf(buffer+n, "%02x", (unsigned char)buf[i]); if (j == (perline-1)) printk(KERN_DEBUG "%s\n", buffer); } if ((i % perline) != 0) printk(KERN_DEBUG "%s\n", buffer); printk(RTAS_DEBUG "%d -------- %s end ----------\n", error_log_cnt, str); } else { struct rtas_error_log *errlog = (struct rtas_error_log *)buf; printk(RTAS_DEBUG "event: %d, Type: %s, Severity: %d\n", error_log_cnt, rtas_event_type(rtas_error_type(errlog)), rtas_error_severity(errlog)); } }
/** * print_re_hdr_scn * @brief Print the contents of an RTAS main event header * * @param res rtas_event_scn pointer for main RTAS event header * @param verbosity verbose level for output * @return number of bytes written */ int print_re_hdr_scn(struct scn_header *shdr, int verbosity) { struct rtas_event_hdr *re_hdr; int len = 0; if (shdr->scn_id != RTAS_EVENT_HDR) { errno = EFAULT; return 0; } re_hdr = (struct rtas_event_hdr *)shdr; len += rtas_print(PRNT_FMT" ", "Version:", re_hdr->version); len += rtas_print(PRNT_FMT" (%s)\n", "Severity:", re_hdr->severity, rtas_severity_names[re_hdr->severity]); if (re_hdr->disposition || (verbosity >= 2)) { len += rtas_print(PRNT_FMT" (%s)\n", "Disposition:", re_hdr->disposition, rtas_disposition_names[re_hdr->disposition]); } if (verbosity >= 2) { len += rtas_print(PRNT_FMT" ", "Extended:", re_hdr->extended); len += rtas_print(PRNT_FMT"\n", "Log Length:", re_hdr->ext_log_length); } if (re_hdr->initiator || verbosity >=2) { len += rtas_print(PRNT_FMT" (%s)\n", "Initiator", re_hdr->initiator, rtas_entity_names[re_hdr->initiator]); } if (re_hdr->target || (verbosity >= 2)) { len += rtas_print(PRNT_FMT" (%s)\n", "Target", re_hdr->target, rtas_entity_names[re_hdr->target]); } len += rtas_print(PRNT_FMT" (%s)\n", "Type", re_hdr->type, rtas_error_type(re_hdr->type)); return len; }
static void do_event_scan(void) { int error; do { memset(logdata, 0, rtas_error_log_max); error = rtas_call(event_scan, 4, 1, NULL, RTAS_EVENT_SCAN_ALL_EVENTS, 0, __pa(logdata), rtas_error_log_max); if (error == -1) { printk(KERN_ERR "event-scan failed\n"); break; } if (error == 0) { if (rtas_error_type((struct rtas_error_log *)logdata) != RTAS_TYPE_PRRN) pSeries_log_error(logdata, ERR_TYPE_RTAS_LOG, 0); handle_rtas_event((struct rtas_error_log *)logdata); } } while(error == 0); }