Heitor Ricardo Alves de Siqueira <hal...@linux.vnet.ibm.com> writes: > Hello, > > This commit implements a new iprdumpfmt command that extracts driver > information > from ipr dump files. It strips out driver version and IOA location, prints the > driver trace in the correct order and displays information from the smart dump > tables. It should be working correctly on both LE and BE dump formats. > > I would greatly appreciate any feedback on the code, especially on output > formatting.
Hi Heitor, Thanks a lot for following through with this. The patch is getting pretty good and I only have a few comments. Some of them are regarding C style but I also left some comments on the logic and the output formatting. Feel free to ping me if you have questions about the comments I've made. Thanks! > > Thanks. > > Signed-off-by: Heitor Ricardo Alves de Siqueira <hal...@linux.vnet.ibm.com> > --- > Makefile.am | 5 +- > iprdumpfmt.c | 683 > +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 687 insertions(+), 1 deletion(-) > create mode 100644 iprdumpfmt.c > > diff --git a/Makefile.am b/Makefile.am > index 4636ecbaf8ce..96b0cd2a5c4c 100644 > --- a/Makefile.am > +++ b/Makefile.am > @@ -10,7 +10,7 @@ > noinst_LTLIBRARIES = libipr.la > libipr_la_SOURCES = iprlib.c iprlib.h > > -sbin_PROGRAMS = iprconfig iprdump iprupdate iprinit iprdbg > +sbin_PROGRAMS = iprconfig iprdump iprupdate iprinit iprdbg iprdumpfmt > dist_sbin_SCRIPTS = iprsos > > iprconfig_SOURCES = iprconfig.c iprconfig.h > @@ -28,6 +28,9 @@ iprinit_LDADD= libipr.la > iprdbg_SOURCES = iprdbg.c > iprdbg_LDADD= libipr.la > > +iprdumpfmt_SOURCES = iprdumpfmt.c > +iprdumpfmt_LDADD = libipr.la > + Build system looks good. > if STATIC_BUILD > sbin_PROGRAMS += iprconfig-static > > diff --git a/iprdumpfmt.c b/iprdumpfmt.c > new file mode 100644 > index 000000000000..e5dc10a292c5 > --- /dev/null > +++ b/iprdumpfmt.c > @@ -0,0 +1,683 @@ > +#include <endian.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; > +}; > + > +struct ipr_sdt { > + struct ipr_sdt_header hdr; > + struct ipr_sdt_entry *entry; > +}; > + > +struct dump_node { > + u32 pos; > + struct ipr_dump_entry_header hdr; > + struct dump_node *next; > +}; > + > +struct trace_node { > + struct ipr_trace_entry t; > + struct trace_node *next; > +}; > + > +void *dump_map; > +FILE *out_fp; Add some comments for these global variables. > + > +/** > + * 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 "UNKNOWN"; > +} Suggest returning NULL instead of UNKNOWN.. > + > +/** > + * read_dump_header - > + * @fd: dump file descriptor > + * > + * Returns: > + * ipr dump header structure > + **/ > +static struct ipr_dump_header read_dump_header(int fd) > +{ > + struct ipr_dump_header hdr; > + > + read(fd, &hdr, sizeof(hdr)); No need to read the main header separately. Just mmap the entire file at once. > + hdr.eye_catcher = htobe32(hdr.eye_catcher); > + > + /* convert to correct endianness */ > + if (hdr.eye_catcher == EYE_CATCHER_BE) { > + hdr.len = be32toh(hdr.len); > + hdr.num_entries = be32toh(hdr.num_entries); > + hdr.first_entry_offset = be32toh(hdr.first_entry_offset); > + hdr.status = be32toh(hdr.status); > + hdr.os = be32toh(hdr.os); > + hdr.driver_name = be32toh(hdr.driver_name); > + } else { > + hdr.len = le32toh(hdr.len); > + hdr.num_entries = le32toh(hdr.num_entries); > + hdr.first_entry_offset = le32toh(hdr.first_entry_offset); > + hdr.status = le32toh(hdr.status); > + hdr.os = le32toh(hdr.os); > + hdr.driver_name = le32toh(hdr.driver_name); > + } > + > + return hdr; > +} > + > +/** > + * print_dump_header - > + * @hdr: ipr dump header > + * > + * 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 > + * @offset: offset to entry data > + * > + * Returns: > + * offset to next entry header > + **/ > +static u32 read_entry_header(struct ipr_dump_entry_header *hdr, u32 offset) > +{ > + memcpy(hdr, dump_map+offset, sizeof(*hdr)); > + hdr->eye_catcher = htobe32(hdr->eye_catcher); hmm, instead of memcpying the values and them updating them, just cast ipr_dump_entry_header on the dump+map structure and do your endianness conversion to your hdr using the cast as source. What do you think? struct ipr_dump_entry_header *raw_hdr = (struct ipr_dump_entry_header *) (dump_map+offset); then you can just do: hdr->len = target_to_host32(raw++hdr->len); And avoid the explicit memcpy. > + > + /* convert to correct endianness */ > + if (hdr->eye_catcher == EYE_CATCHER_BE) { > + hdr->len = be32toh(hdr->len); > + hdr->num_elems = be32toh(hdr->num_elems); > + hdr->offset = be32toh(hdr->offset); > + hdr->data_type = be32toh(hdr->data_type); > + hdr->id = be32toh(hdr->id); > + hdr->status = be32toh(hdr->status); > + } else if (hdr->eye_catcher == EYE_CATCHER_LE) { > + hdr->len = le32toh(hdr->len); > + hdr->num_elems = le32toh(hdr->num_elems); > + hdr->offset = le32toh(hdr->offset); > + hdr->data_type = le32toh(hdr->data_type); > + hdr->id = le32toh(hdr->id); > + hdr->status = le32toh(hdr->status); > + } Don't wanna keep pushing with the endiannes stuff, but I think you could make things much easier by just creating something like #define target_to_host32(val) \ (target_endiannes == host_endianness) ? val : convert32(val); Then, hunks like this will be much simpler: hdr->len = target_to_host32(hdr->len); hdr->num_elems = target_to_host32(hdr->num_elems); hdr->offset = target_to_host32(hdr->offset); hdr->data_type = target_to_host32(hdr->data_type); hdr->id = target_to_host32(hdr->id); hdr->status = target_to_host32(hdr->status); My point being that we can reduce the size of the code and the number of places where we might introduce endianness bugs. > + 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; > + memcpy(&trace, dump_map+offset, sizeof(trace)); > + > + /* always stored as BE */ > + trace.res_handle = htobe32(trace.res_handle); > + > + /* convert to correct endianness */ > + if (eye_catcher == EYE_CATCHER_BE) { > + trace.time = be32toh(trace.time); > + trace.u.add_data = be32toh(trace.u.add_data); > + } else { > + trace.time = le32toh(trace.time); > + trace.u.add_data = le32toh(trace.u.add_data); > + } > + return trace; > +} > + > +/** > + * print_trace_data - > + * @trace: ipr trace entry > + * > + * Returns: > + * Nothing > + **/ > +static void print_trace_data(struct ipr_trace_entry trace) pass trace as a reference instead of copying the structure. > +{ > + fprintf(out_fp, "\t Timestamp: %d (%lld us)\n", trace.time, > + (long long unsigned)trace.time*1000*1000/sysconf(_SC_CLK_TCK)); > + fprintf(out_fp, "\t SCSI Opcode: 0x%02X ", trace.op_code); > + fprintf(out_fp, "\t (%s)\n", get_scsi_command_literal(trace.op_code)); > + fprintf(out_fp, "\t ATA Opcode: 0x%02X\n", trace.ata_op_code); > + fprintf(out_fp, "\t Type: 0x%02X ", trace.type); > + switch (trace.type) { > + case IPR_TRACE_START: > + fprintf(out_fp, "(IPR_TRACE_START)\n"); > + break; > + case IPR_TRACE_FINISH: > + fprintf(out_fp, "(IPR_TRACE_FINISH)\n"); > + break; > + default: > + fprintf(out_fp, "(UNKNOWN)\n"); > + } > + fprintf(out_fp, "\t Command index: 0x02%X\n", trace.cmd_index); > + fprintf(out_fp, "\t Res Handle: 0x%08X\n", trace.res_handle); > + fprintf(out_fp, "\t Additional Data: 0x08%X\n", trace.u.add_data); Regarding the output format. Since we are going to print several trace entries, maybe we want to print each entry in a single line, more similar to the old version of this tool, in a tabular fashion. What do you think? I think it might be easier to analyze the dump later. Are trace.ata_op_code and trace.op_code valid at the same time? I recall we discussed these fields some time ago, but I don't remember the outcome. > +} > + > +/** > + * build_sdt - > + * @hdr: ipr dump entry header > + * > + * Returns: > + * ipr sdt structure > + **/ > +static struct ipr_sdt build_sdt(struct ipr_dump_entry_header hdr) Pass hdr as a const reference instead of by value here. > +{ > + u32 i, offset; > + struct ipr_sdt sdt; > + struct ipr_sdt_entry *entry; > + > + memcpy(&sdt.hdr, dump_map+hdr.offset, sizeof(sdt.hdr)); > + offset = hdr.offset + sizeof(sdt.hdr); > + > + /* values below are always stored as BE */ > + sdt.hdr.state = htobe32(sdt.hdr.state); > + sdt.hdr.num_entries = htobe32(sdt.hdr.num_entries); > + sdt.hdr.entries_used = htobe32(sdt.hdr.entries_used); > + sdt.hdr.dump_size = htobe32(sdt.hdr.dump_size); > + > + sdt.entry = malloc(sdt.hdr.entries_used * sizeof(*sdt.entry)); > + for (i=0; i<sdt.hdr.entries_used; ++i) { > + entry = &sdt.entry[i]; > + > + memcpy(entry, dump_map+offset+i*sizeof(*entry), sizeof(*entry)); > + /* values below are always stored as BE */ > + entry->bar_str_offset = htobe32(entry->bar_str_offset); > + entry->end_offset = htobe32(entry->end_offset); > + entry->priority = htobe16(entry->priority); > + } > + > + return sdt; > +} > + > +/** > + * build_trace_list - > + * @hdr: ipr dump entry header > + * > + * Returns: > + * circular list of ipr trace entries > + **/ > +static struct trace_node* build_trace_list(struct ipr_dump_entry_header hdr) Pass hdr by const reference instead of by value here. > +{ > + u32 i, min_time, min_pos = 0; > + struct trace_node *head = malloc(sizeof(*head)); > + struct trace_node *aux = head; > + > + head->t = read_trace_data(hdr.offset, hdr.eye_catcher); > + min_time = head->t.time; > + for (i=1; i<hdr.len/sizeof(head->t); ++i) { > + aux->next = malloc(sizeof(*aux->next)); > + aux = aux->next; > + aux->t = read_trace_data(hdr.offset+i*sizeof(head->t), > + hdr.eye_catcher); > + if (min_time > aux->t.time) { > + min_time = aux->t.time; > + min_pos = i; > + } > + } > + aux->next = head; > + while (min_pos--) > + head = head->next; > + return head; > +} > + > +/** > + * clean_trace_list - > + * @head: circular list of ipr trace entries > + * > + * Returns: > + * nothing > + **/ > +static void clean_trace_list(struct trace_node* head) > +{ > + struct trace_node* aux = head->next; > + struct trace_node* del; > + while (aux != head) { > + del = aux; > + aux = aux->next; > + free(del); > + } > + free(head); > +} > + > +/** > + * print_sdt - > + * @sdt: ipr sdt structure > + * > + * Returns: > + * nothing > + **/ > +static void print_sdt(struct ipr_sdt sdt) > +{ > + u32 i; > + struct ipr_sdt_entry *entry; > + > + fprintf(out_fp, "Smart Dump Table Data:\n"); > + fprintf(out_fp, "\t state: 0x%X ", sdt.hdr.state); > + switch(sdt.hdr.state) { > + case IPR_FMT2_SDT_READY_TO_USE: > + case IPR_FMT3_SDT_READY_TO_USE: > + fprintf(out_fp, "(READY_TO_USE)\n"); > + break; > + default: > + fprintf(out_fp, "(UNKNOWN)\n"); > + } If sdt.hdr.state is UNKNOWN, is it worth printing? > + fprintf(out_fp, "\t entries found: %d\n\n", sdt.hdr.entries_used); > + > + for (i=0; i<sdt.hdr.entries_used; ++i) { > + entry = &sdt.entry[i]; > + fprintf(out_fp, "\t start offset: 0x%08X\n", > + entry->bar_str_offset); > + fprintf(out_fp, "\t end offset: 0x%08X\n", entry->end_offset); > + fprintf(out_fp, "\t entry byte: 0x%02X\n", entry->entry_byte); > + fprintf(out_fp, "\t endian: 0x%X\n", entry->endian); > + fprintf(out_fp, "\t valid entry: 0x%X\n", entry->valid_entry); > + fprintf(out_fp, "\t resv: %d\n", entry->resv); > + fprintf(out_fp, "\t priority: 0x%04X\n", entry->priority); > + fprintf(out_fp, "\n"); > + } > +} > + > +/** > + * build_trace_list - > + * @hdr: ipr dump entry header > + * > + * Returns: > + * nothing > + **/ > +static void dump_entry_data(struct ipr_dump_entry_header hdr) > +{ > + u32 i; > + char *s; > + struct trace_node *tn, *tn_aux; > + struct ipr_sdt sdt; > + > + switch (hdr.id) { > + case ID_IOA_DUMP: > + sdt = build_sdt(hdr); > + print_sdt(sdt); > + free(sdt.entry); > + break; Can't we put sdt in the stack and avoid the malloc ? > + case ID_IOA_LOC: > + fprintf(out_fp, "IOA Location:\n"); > + s = dump_map+hdr.offset; > + fprintf(out_fp, "\t %.*s\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", hdr.len, s); > + break; > + case ID_DRV_TRACE: > + fprintf(out_fp, "Driver Trace Entries:\n"); > + tn = build_trace_list(hdr); > + tn_aux = tn; > + print_trace_data(tn->t); > + tn = tn->next; > + while (tn != tn_aux) { > + fprintf(out_fp, "\n"); > + print_trace_data(tn->t); > + tn = tn->next; > + } > + clean_trace_list(tn); Can't we find and print the trace entries at once to avoid malloc-ing and freeing the list all the time? Since this is a ring buffer of trace entries, we might be able to cast them to a list of headers, find the head using the timestamp and them iterate from there. What do you think? Let's put all of this logic into a separate print_trace_data function. This way we eliminate build_trace_list and clean_trace_list. > + break; > + case ID_DRV_TYPE: > + fprintf(out_fp, "Driver Type:\n"); > + memcpy(&i, dump_map+hdr.offset, sizeof(i)); > + if (hdr.eye_catcher == EYE_CATCHER_BE) > + i = be32toh(i); > + else > + i = le32toh(i); No need to memcpy. Just cast from dump_map+hdr.offset straight into the be32toh. Something like this could replace this hunk: i = target_to_host(*((u32*) dump_map+hdr.offset)); > + fprintf(out_fp, "\t CCIN: 0x%04X\n", i); > + memcpy(&i, dump_map+hdr.offset+sizeof(i), sizeof(i)); > + if (hdr.eye_catcher == EYE_CATCHER_BE) > + i = be32toh(i); > + else > + i = le32toh(i); Likewise. > + fprintf(out_fp, "\t Adapter firmware Version: "); > + fprintf(out_fp, " %02X:%02X:%02X:%02X\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 "); > + fprintf(stderr, "IPR Pending Ops structure!\n"); > + fprintf(stderr, "These are not implemented > yet. Skipping...\n"); Join these fprintf calls into a single statement. > + break; > + default: > + fprintf(stderr, > + "Warning: did not recognize data identification "); > + fprintf(stderr, "(id 0x%08X). Skipping...\n", hdr.id); Likewise. > + } > + fprintf(out_fp, "\n"); Suggest putting the \n with the fprintf calls so we don't have it here alone here. > +} > + > +int main(int argc, char *argv[]) > +{ > + u32 i, offset; > + int in_fd; > + struct ipr_dump_header hdr; > + struct ipr_dump_entry_header entry_hdr; > + > + if (argc != 3) { > + fprintf(stderr, "Usage: %s <dump_file> <report_file>\n", > + argv[0]); > + return 1; > + } > + > + in_fd = open(argv[1], O_RDONLY); > + out_fp = fopen(argv[2], "w"); > + > + if (in_fd < 0) { > + fprintf(stderr, "Error: could not open dump file %s\n", > + argv[1]); > + fprintf(stderr, "Aborting...\n"); Suggest printing errno here. Much more helpful. See strerror(3). > + return 1; > + } > + if (out_fp == NULL) { > + fprintf(stderr, "Error: could not open report file %s\n", > + argv[2]); > + fprintf(stderr, "Aborting...\n"); Likewise. > + return 1; > + } > + > + hdr = read_dump_header(in_fd); > + print_dump_header(hdr); > + fprintf(out_fp, "\n"); > + > + dump_map = mmap(NULL, hdr.len, PROT_READ, MAP_SHARED, in_fd, 0); Don't use MAP_SHARED. > + if (dump_map == MAP_FAILED) { > + fprintf(stderr, "Error: could not map dump file to memory\n"); > + fprintf(stderr, "Aborting...\n"); > + return 1; errno. > + } > + > + offset = hdr.first_entry_offset; > + for (i=0; i<hdr.num_entries; ++i) { ^^ missing spaces. > + offset = read_entry_header(&entry_hdr, offset); > + dump_entry_data(entry_hdr); > + } > + > + return 0; > +} Thanks! -- Gabriel Krisman Bertazi ------------------------------------------------------------------------------ _______________________________________________ Iprdd-devel mailing list Iprdd-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/iprdd-devel