Hi Gabriel, Thank you very much for your review. This is a list of important changes I made since the last version:
* global variables are now static * trace and sdt are printed in a table format * added a verbose option for trace formatting (this prints SCSI opcode and other verbose information) * created small macro for endianness conversion * removed linked list structures. now reading information directly through mmap * rewrote main() so that it handles usage flags correctly * error messages now use errno and strerror() I would appreciate it if you could take another look at this version of the code, when you have some time to spare. Thanks. --- iprdumpfmt.c | 641 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 641 insertions(+) create mode 100644 iprdumpfmt.c diff --git a/iprdumpfmt.c b/iprdumpfmt.c new file mode 100644 index 000000000000..599c0acae9f7 --- /dev/null +++ b/iprdumpfmt.c @@ -0,0 +1,641 @@ +#include <endian.h> +#include <getopt.h> +#include "iprlib.h" + +#define EYE_CATCHER_BE 0xC5D4E3F2 +#define EYE_CATCHER_LE 0xF2E3D4C5 + +#define OS_LINUX 0x4C4E5558 +#define OS_I5OS 0x69354F53 + +#define DRV_IPR2 0x49505232 +#define DRV_V5R4 0x56355234 + +#define TYPE_ASCII 0x41534349 +#define TYPE_BIN 0x42494E41 +#define TYPE_MR32 0x4D523332 +#define TYPE_MR64 0x4D523634 + +#define ID_IOA_DUMP 0x494F4131 +#define ID_IOA_LOC 0x4C4F4341 +#define ID_DRV_TRACE 0x54524143 +#define ID_DRV_VER 0x44525652 +#define ID_DRV_TYPE 0x54595045 +#define ID_DRV_CTRL_BLK 0x494F4342 +#define ID_DRV_PEND_OPS 0x414F5053 + +#define IPR_DUMP_STATUS_SUCCESS 0 +#define IPR_DUMP_STATUS_QUAL_SUCCESS 2 +#define IPR_DUMP_STATUS_FAILED 0xFFFFFFFF + +#define IPR_FMT2_SDT_READY_TO_USE 0xC4D4E3F2 +#define IPR_FMT3_SDT_READY_TO_USE 0xC4D4E3F3 + +static const struct { + const u8 op; + const char *name; +} scsi_cmnds[] = { + { 0xc1, "IPR_CANCEL_REQUEST" }, + { 0x01, "IPR_CANCEL_64BIT_IOARCB" }, + { 0xc2, "IPR_QUERY_RSRC_STATE" }, + { 0xc3, "IPR_RESET_DEVICE" }, + { 0x80, "IPR_RESET_TYPE_SELECT" }, + { 0x40, "IPR_LUN_RESET" }, + { 0x20, "IPR_TARGET_RESET" }, + { 0x10, "IPR_BUS_RESET" }, + { 0x80, "IPR_ATA_PHY_RESET" }, + { 0xc4, "IPR_ID_HOST_RR_Q" }, + { 0xc5, "IPR_QUERY_IOA_CONFIG" }, + { 0xce, "IPR_CANCEL_ALL_REQUESTS" }, + { 0xcf, "IPR_HOST_CONTROLLED_ASYNC" }, + { 0x01, "IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE" }, + { 0x02, "IPR_HCAM_CDB_OP_CODE_LOG_DATA" }, + { 0xfb, "IPR_SET_SUPPORTED_DEVICES" }, + { 0x80, "IPR_SET_ALL_SUPPORTED_DEVICES" }, + { 0xf7, "IPR_IOA_SHUTDOWN" }, + { 0x05, "IPR_WR_BUF_DOWNLOAD_AND_SAVE" }, + + { 0x00, "TEST_UNIT_READY" }, + { 0x01, "REZERO_UNIT" }, + { 0x03, "REQUEST_SENSE" }, + { 0x04, "FORMAT_UNIT" }, + { 0x05, "READ_BLOCK_LIMITS" }, + { 0x07, "REASSIGN_BLOCKS" }, + { 0x07, "INITIALIZE_ELEMENT_STATUS" }, + { 0x08, "READ_6" }, + { 0x0a, "WRITE_6" }, + { 0x0b, "SEEK_6" }, + { 0x0f, "READ_REVERSE" }, + { 0x10, "WRITE_FILEMARKS" }, + { 0x11, "SPACE" }, + { 0x12, "INQUIRY" }, + { 0x14, "RECOVER_BUFFERED_DATA" }, + { 0x15, "MODE_SELECT" }, + { 0x16, "RESERVE" }, + { 0x17, "RELEASE" }, + { 0x18, "COPY" }, + { 0x19, "ERASE" }, + { 0x1a, "MODE_SENSE" }, + { 0x1b, "START_STOP" }, + { 0x1c, "RECEIVE_DIAGNOSTIC" }, + { 0x1d, "SEND_DIAGNOSTIC" }, + { 0x1e, "ALLOW_MEDIUM_REMOVAL" }, + { 0x23, "READ_FORMAT_CAPACITIES" }, + { 0x24, "SET_WINDOW" }, + { 0x25, "READ_CAPACITY" }, + { 0x28, "READ_10" }, + { 0x2a, "WRITE_10" }, + { 0x2b, "SEEK_10" }, + { 0x2b, "POSITION_TO_ELEMENT" }, + { 0x2e, "WRITE_VERIFY" }, + { 0x2f, "VERIFY" }, + { 0x30, "SEARCH_HIGH" }, + { 0x31, "SEARCH_EQUAL" }, + { 0x32, "SEARCH_LOW" }, + { 0x33, "SET_LIMITS" }, + { 0x34, "PRE_FETCH" }, + { 0x34, "READ_POSITION" }, + { 0x35, "SYNCHRONIZE_CACHE" }, + { 0x36, "LOCK_UNLOCK_CACHE" }, + { 0x37, "READ_DEFECT_DATA" }, + { 0x38, "MEDIUM_SCAN" }, + { 0x39, "COMPARE" }, + { 0x3a, "COPY_VERIFY" }, + { 0x3b, "WRITE_BUFFER" }, + { 0x3c, "READ_BUFFER" }, + { 0x3d, "UPDATE_BLOCK" }, + { 0x3e, "READ_LONG" }, + { 0x3f, "WRITE_LONG" }, + { 0x40, "CHANGE_DEFINITION" }, + { 0x41, "WRITE_SAME" }, + { 0x42, "UNMAP" }, + { 0x43, "READ_TOC" }, + { 0x44, "READ_HEADER" }, + { 0x4a, "GET_EVENT_STATUS_NOTIFICATION" }, + { 0x4c, "LOG_SELECT" }, + { 0x4d, "LOG_SENSE" }, + { 0x53, "XDWRITEREAD_10" }, + { 0x55, "MODE_SELECT_10" }, + { 0x56, "RESERVE_10" }, + { 0x57, "RELEASE_10" }, + { 0x5a, "MODE_SENSE_10" }, + { 0x5e, "PERSISTENT_RESERVE_IN" }, + { 0x5f, "PERSISTENT_RESERVE_OUT" }, + { 0x7f, "VARIABLE_LENGTH_CMD" }, + { 0xa0, "REPORT_LUNS" }, + { 0xa2, "SECURITY_PROTOCOL_IN" }, + { 0xa3, "MAINTENANCE_IN" }, + { 0xa4, "MAINTENANCE_OUT" }, + { 0xa5, "MOVE_MEDIUM" }, + { 0xa6, "EXCHANGE_MEDIUM" }, + { 0xa8, "READ_12" }, + { 0xa9, "SERVICE_ACTION_OUT_12" }, + { 0xaa, "WRITE_12" }, + { 0xab, "SERVICE_ACTION_IN_12" }, + { 0xae, "WRITE_VERIFY_12" }, + { 0xaf, "VERIFY_12" }, + { 0xb0, "SEARCH_HIGH_12" }, + { 0xb1, "SEARCH_EQUAL_12" }, + { 0xb2, "SEARCH_LOW_12" }, + { 0xb5, "SECURITY_PROTOCOL_OUT" }, + { 0xb8, "READ_ELEMENT_STATUS" }, + { 0xb6, "SEND_VOLUME_TAG" }, + { 0xea, "WRITE_LONG_2" }, + { 0x83, "EXTENDED_COPY" }, + { 0x84, "RECEIVE_COPY_RESULTS" }, + { 0x86, "ACCESS_CONTROL_IN" }, + { 0x87, "ACCESS_CONTROL_OUT" }, + { 0x88, "READ_16" }, + { 0x89, "COMPARE_AND_WRITE" }, + { 0x8a, "WRITE_16" }, + { 0x8c, "READ_ATTRIBUTE" }, + { 0x8d, "WRITE_ATTRIBUTE" }, + { 0x8f, "VERIFY_16" }, + { 0x91, "SYNCHRONIZE_CACHE_16" }, + { 0x93, "WRITE_SAME_16" }, + { 0x9d, "SERVICE_ACTION_BIDIRECTIONAL" }, + { 0x9e, "SERVICE_ACTION_IN_16" }, + { 0x9f, "SERVICE_ACTION_OUT_16" } +}; + +struct ipr_dump_header { + u32 eye_catcher; + u32 len; + u32 num_entries; + u32 first_entry_offset; + u32 status; + u32 os; + u32 driver_name; +}; + +struct ipr_dump_entry_header { + u32 eye_catcher; + u32 len; /* does not include entry header */ + u32 num_elems; + u32 offset; /* offset to data from beginning of dump file */ + u32 data_type; + u32 id; + u32 status; +}; + +struct ipr_trace_entry { + u32 time; + + u8 op_code; /* SCSI opcode */ + u8 ata_op_code; + u8 type; +#define IPR_TRACE_START 0x00 +#define IPR_TRACE_FINISH 0xff + u8 cmd_index; + + u32 res_handle; /* stored as BE */ + union { + u32 ioasc; + u32 add_data; + u32 res_addr; + } u; +}; + +struct ipr_sdt_header { + /* all values in ipr_sdt_header are stored as BE */ + u32 state; + u32 num_entries; + u32 entries_used; + u32 dump_size; +}; + +static void *dump_map; /* ipr dump memory map */ +static FILE *out_fp; /* output report file pointer */ +static int verbose_trace; /* flag for verbose trace printing */ + +#define TARGET_TO_HOST32(value, eye_catcher) \ + (eye_catcher == EYE_CATCHER_BE ? \ + be32toh(value) : \ + le32toh(value)) + +/** + * get_scsi_command_literal - + * @value: SCSI opcode + * + * Returns: + * SCSI command string + **/ +static const char* get_scsi_command_literal(u32 value) +{ + u32 i = 0; + + for (i = 0; i < ARRAY_SIZE(scsi_cmnds); ++i) { + if (value == scsi_cmnds[i].op) + return scsi_cmnds[i].name; + } + return "NULL"; +} + +/** + * read_dump_header - + * @hdr: ipr dump header pointer + * + * Returns: + * nothing + **/ +static void read_dump_header(struct ipr_dump_header *hdr) +{ + struct ipr_dump_header *raw_hdr = dump_map; + + hdr->eye_catcher = htobe32(raw_hdr->eye_catcher); + + /* convert to correct endianness */ + hdr->len = TARGET_TO_HOST32(raw_hdr->len, hdr->eye_catcher); + hdr->num_entries = TARGET_TO_HOST32(raw_hdr->num_entries, + hdr->eye_catcher); + hdr->first_entry_offset = TARGET_TO_HOST32(raw_hdr->first_entry_offset, + hdr->eye_catcher); + hdr->status = TARGET_TO_HOST32(raw_hdr->status, hdr->eye_catcher); + hdr->os = TARGET_TO_HOST32(raw_hdr->os, hdr->eye_catcher); + hdr->driver_name = TARGET_TO_HOST32(raw_hdr->driver_name, + hdr->eye_catcher); +} + +/** + * print_dump_header - + * @hdr: ipr dump header pointer + * + * Returns: + * nothing + **/ +static void print_dump_header(struct ipr_dump_header *hdr) +{ + fprintf(out_fp, "IPR Adapter Dump Report\n\n"); + switch (hdr->eye_catcher) { + case EYE_CATCHER_BE: + fprintf(out_fp, "Big Endian format: "); + break; + case EYE_CATCHER_LE: + fprintf(out_fp, "Little Endian format: "); + break; + default: + fprintf(out_fp, "Unknown dump format: "); + } + fprintf(out_fp, "Eye Catcher is 0x%08X\n", hdr->eye_catcher); + + fprintf(out_fp, "Total length: %d bytes\n", hdr->len); + fprintf(out_fp, "Number of dump entries: %d\n", hdr->num_entries); + fprintf(out_fp, "Offset to first entry: 0x%08X bytes\n", + hdr->first_entry_offset); + fprintf(out_fp, "Dump status: 0x%08X ", hdr->status); + switch (hdr->status) { + case IPR_DUMP_STATUS_SUCCESS: + fprintf(out_fp, "(SUCCESS)\n"); + break; + case IPR_DUMP_STATUS_QUAL_SUCCESS: + fprintf(out_fp, "(QUAL_SUCCESS)\n"); + break; + case IPR_DUMP_STATUS_FAILED: + fprintf(out_fp, "(FAILED)\n"); + break; + default: + fprintf(out_fp, "(UNKNOWN)\n"); + } + + fprintf(out_fp, "Operating System: "); + switch (hdr->os) { + case OS_LINUX: + fprintf(out_fp, "Linux\n"); + break; + case OS_I5OS: + fprintf(out_fp, "i5OS\n"); + break; + default: + fprintf(out_fp, "unknown\n"); + } + + fprintf(out_fp, "Driver: "); + switch (hdr->driver_name) { + case DRV_IPR2: + fprintf(out_fp, "ipr2\n"); + break; + case DRV_V5R4: + fprintf(out_fp, "V5R4\n"); + break; + default: + fprintf(out_fp, "unknown\n"); + } +} + +/** + * read_entry_header - + * @hdr: ipr dump entry header pointer + * @offset: offset to entry data + * + * Returns: + * offset to next entry header + **/ +static u32 read_entry_header(struct ipr_dump_entry_header *hdr, u32 offset) +{ + struct ipr_dump_entry_header *raw_hdr = dump_map+offset; + hdr->eye_catcher = htobe32(raw_hdr->eye_catcher); + + /* convert to correct endianness */ + hdr->len = TARGET_TO_HOST32(raw_hdr->len, hdr->eye_catcher); + hdr->num_elems = TARGET_TO_HOST32(raw_hdr->num_elems, hdr->eye_catcher); + hdr->offset = TARGET_TO_HOST32(raw_hdr->offset, hdr->eye_catcher); + hdr->data_type = TARGET_TO_HOST32(raw_hdr->data_type, hdr->eye_catcher); + hdr->id = TARGET_TO_HOST32(raw_hdr->id, hdr->eye_catcher); + hdr->status = TARGET_TO_HOST32(raw_hdr->status, hdr->eye_catcher); + hdr->offset += offset; + + return (hdr->offset + hdr->len); +} + +/** + * read_trace_data - + * @offset: offset to entry data + * @eye_catcher: ipr entry eye catcher + * + * Returns: + * ipr trace entry structure + **/ +static struct ipr_trace_entry read_trace_data(u32 offset, u32 eye_catcher) +{ + struct ipr_trace_entry trace; + struct ipr_trace_entry *raw_trace = dump_map+offset; + + /* always stored as BE */ + trace.res_handle = htobe32(raw_trace->res_handle); + + /* convert to correct endianness */ + trace.time = TARGET_TO_HOST32(raw_trace->time, eye_catcher); + trace.u.add_data = TARGET_TO_HOST32(raw_trace->u.add_data, eye_catcher); + + /* copy remaining trace fields */ + trace.op_code = raw_trace->op_code; + trace.ata_op_code = raw_trace->ata_op_code; + trace.type = raw_trace->type; + trace.cmd_index = raw_trace->cmd_index; + + return trace; +} + +#define JIFF_TO_USEC(x) x * 1000 * 1000 / sysconf(_SC_CLK_TCK) +/** + * print_trace - + * @hdr: ipr entry header pointer + * + * Returns: + * nothing + **/ +static void print_trace(struct ipr_dump_entry_header *hdr) +{ + u32 i, min_pos, min_time, num_entries, offset; + struct ipr_trace_entry *raw_trace; + struct ipr_trace_entry t; + + num_entries = hdr->len / sizeof(*raw_trace); + raw_trace = dump_map + hdr->offset; + min_pos = 0; + min_time = TARGET_TO_HOST32(raw_trace->time, hdr->eye_catcher); + + fprintf(out_fp, "\t entries found: %d\n\n", num_entries); + for (i = 1; i < num_entries; ++i) { + raw_trace = dump_map + hdr->offset + i*sizeof(*raw_trace); + if (TARGET_TO_HOST32(raw_trace->time, hdr->eye_catcher) < + min_time) { + min_time = TARGET_TO_HOST32(raw_trace->time, + hdr->eye_catcher); + min_pos = i; + } + } + for (i = 0; i < num_entries; ++i) { + offset = hdr->offset + + ((min_pos+i)%num_entries) * sizeof(*raw_trace); + t = read_trace_data(offset, hdr->eye_catcher); + fprintf(out_fp, "\t %08X %02X%02X%02X%02X %08X %08X", + t.time, t.op_code, t.ata_op_code, t.type, t.cmd_index, + t.res_handle, t.u.add_data); + if (verbose_trace) { + fprintf(out_fp, "\t | \t%lld\xC2\xB5s\t", + (long long unsigned)JIFF_TO_USEC(t.time)); + switch(t.type) { + case IPR_TRACE_START: + fprintf(out_fp, "IPR_TRACE_START\t\t"); + break; + case IPR_TRACE_FINISH: + fprintf(out_fp, "IPR_TRACE_FINISH\t"); + break; + default: + fprintf(out_fp, "\t\t\t"); + } + fprintf(out_fp, "%s", get_scsi_command_literal(t.op_code)); + + } + fprintf(out_fp, "\n"); + } +} + +/** + * print_sdt - + * @data_offset: offset to sdt data + * + * Returns: + * nothing + **/ +static void print_sdt(u32 data_offset) +{ + u32 i; + struct ipr_sdt_header *raw_hdr; + struct ipr_sdt_entry *raw_entry; + + raw_hdr = dump_map + data_offset; + + fprintf(out_fp, "\t state: 0x%X", htobe32(raw_hdr->state)); + if (htobe32(raw_hdr->state) == IPR_FMT2_SDT_READY_TO_USE || + htobe32(raw_hdr->state) == IPR_FMT3_SDT_READY_TO_USE) + fprintf(out_fp, " (READY_TO_USE)\n"); + else + fprintf(out_fp, "\n"); + fprintf(out_fp, "\t entries found: %d\n\n", + htobe32(raw_hdr->entries_used)); + + for (i = 0; i < htobe32(raw_hdr->entries_used); ++i) { + raw_entry = dump_map + data_offset + sizeof(*raw_hdr) + + i * sizeof(*raw_entry); + fprintf(out_fp, "\t %08X %08X %02X%02X%02X%02X %04X\n", + htobe32(raw_entry->bar_str_offset), + htobe32(raw_entry->end_offset), + raw_entry->entry_byte, raw_entry->endian, + raw_entry->valid_entry, raw_entry->resv, + htobe16(raw_entry->priority)); + } +} + +/** + * dump_entry_data - + * @hdr: ipr dump entry header pointer + * + * Returns: + * nothing + **/ +static void dump_entry_data(struct ipr_dump_entry_header *hdr) +{ + u32 i; + char *s; + + switch (hdr->id) { + case ID_IOA_DUMP: + fprintf(out_fp, "Smart Dump Table Data:\n"); + print_sdt(hdr->offset); + break; + case ID_IOA_LOC: + fprintf(out_fp, "IOA Location:\n"); + s = dump_map+hdr->offset; + fprintf(out_fp, "\t %.*s\n\n", hdr->len, s); + break; + case ID_DRV_VER: + fprintf(out_fp, "Driver Version:\n"); + s = dump_map+hdr->offset; + fprintf(out_fp, "\t %.*s\n\n", hdr->len, s); + break; + case ID_DRV_TRACE: + fprintf(out_fp, "Driver Trace Entries:\n"); + print_trace(hdr); + fprintf(out_fp, "\n"); + break; + case ID_DRV_TYPE: + fprintf(out_fp, "Driver Type:\n"); + memcpy(&i, dump_map+hdr->offset, sizeof(i)); + i = TARGET_TO_HOST32(i, hdr->eye_catcher); + fprintf(out_fp, "\t CCIN: 0x%04X\n", i); + memcpy(&i, dump_map+hdr->offset+sizeof(i), sizeof(i)); + i = TARGET_TO_HOST32(i, hdr->eye_catcher); + fprintf(out_fp,"\t Adapter firmware Version: " + " %02X:%02X:%02X:%02X\n\n", + i >> 24, /* major release */ + (i & 0x00FF0000) >> 16, /* card type */ + (i & 0x0000FF00) >> 8, /* minor release 0 */ + i & 0x000000FF); /* minor release 1 */ + break; + case ID_DRV_CTRL_BLK: + case ID_DRV_PEND_OPS: + /* not implemented yet */ + fprintf(stderr, + "Warning: found IPR Control Block or IPR Pending Ops!\n" + "These are not implemented yet. Skipping...\n"); + break; + default: + fprintf(stderr, + "Warning: did not recognize data identification " + "(id 0x%08X). Skipping...\n\n", hdr->id); + } +} + +/** + * fsize - + * @filename: ipr dump file name + * + * Returns: + * ipr dump file size + **/ +off_t fsize(const char *filename) +{ + struct stat st; + + if (stat(filename, &st) == 0) + return st.st_size; + + fprintf(stderr, "Cannot determine size of %s: %s\n", + filename, strerror(errno)); + + return -1; +} + +/** + * print_usage - + * + * Returns: + * nothing + **/ +static void print_usage() +{ + fprintf(stdout, + "Usage: iprdumpfmt [options] <dump_file> <report_file>\n" + " Options:\n" + "\t-h --help\tPrint this message\n" + "\t-v --verbose\tPrint verbose trace data\n"); +} + +int main(int argc, char *argv[]) +{ + u32 i, offset; + int in_fd; + struct ipr_dump_header hdr; + struct ipr_dump_entry_header entry_hdr; + + while (1) { + static struct option long_options[] = { + {"verbose", no_argument, &verbose_trace, 1}, + {"brief", no_argument, &verbose_trace, 0}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + int c, option_index = 0; + + c = getopt_long(argc, argv, "hv", long_options, &option_index); + + if (c == -1) + break; + + switch (c) { + case 0: + break; + case '?': + case 'h': + print_usage(); + return 0; + case 'v': + verbose_trace = 1; + break; + default: + return -1; + } + } + + if (argc - optind < 2) { + /* need at least dump and report files */ + print_usage(); + return -1; + } + + in_fd = open(argv[optind], O_RDONLY); + out_fp = fopen(argv[optind+1], "w"); + + if (in_fd < 0) { + fprintf(stderr, "Could not open dump file %s: %s\n", + argv[optind], strerror(errno)); + return errno; + } + if (out_fp == NULL) { + fprintf(stderr, "Could not open report file %s: %s\n", + argv[optind+1], strerror(errno)); + return errno; + } + + dump_map = mmap(NULL, fsize(argv[optind]), PROT_READ, MAP_PRIVATE, in_fd, 0); + + read_dump_header(&hdr); + print_dump_header(&hdr); + fprintf(out_fp, "\n"); + + if (dump_map == MAP_FAILED) { + fprintf(stderr, "Could not map dump file to memory: %s\n", + strerror(errno)); + return errno; + } + + offset = hdr.first_entry_offset; + for (i = 0; i < hdr.num_entries; ++i) { + offset = read_entry_header(&entry_hdr, offset); + dump_entry_data(&entry_hdr); + } + + return 0; +} -- 2.4.3 ------------------------------------------------------------------------------ _______________________________________________ Iprdd-devel mailing list Iprdd-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/iprdd-devel