Extend sff8079_show_all_nl(), cmis_show_all_nl() and sff8636_show_all_nl() with a bool dump_pages parameter to support hex dump output alongside their existing pretty-print output. Each function first retrieves all the necessary pages and then either pretty-prints them or performs a hex dump according to the argument. The hex dump and pretty-print logic is extracted into dedicated static functions for each parser type: - cmis_hex_dump() / cmis_pretty_print() - sff8636_hex_dump() / sff8636_pretty_print() - sff8079_hex_dump() / sff8079_pretty_print() Each function dumps the same pages as the corresponding pretty-printer: - CMIS: uses cmis_memory_map_init_pages() to read the lower memory and relevant upper pages across all supported banks, using generic iteration over the memory map. Each block is labeled with "Bank: 0xN" followed by "Page: 0xM". - SFF-8636: uses sff8636_memory_map_init_pages() to read the lower memory and relevant upper pages, using generic iteration over the memory map. Each block is labeled "Page: 0xN". - SFF-8079: uses sff8079_get_eeprom_page() to read A0h lower and optional A2h lower. Each block is labeled with "I2C Address: 0xN" followed by "Page: 0xM". In JSON context (--json), each function emits a "pages" array with one object per page containing bank, page, offset, length, i2c_address and data. Consumers that need a stable, machine-parseable form of the hex dump can use this output instead of the text format. Assisted-by: Claude:claude-sonnet-4.6 Reviewed-by: Petr Machata Reviewed-by: Ido Schimmel Signed-off-by: Danielle Ratson --- cmis.c | 70 ++++++++++++++++++++++++++++++++++++----- cmis.h | 2 +- internal.h | 4 +-- netlink/module-eeprom.c | 6 ++-- qsfp.c | 67 ++++++++++++++++++++++++++++++++++----- sfpid.c | 60 +++++++++++++++++++++++++++++------ 6 files changed, 179 insertions(+), 30 deletions(-) diff --git a/cmis.c b/cmis.c index 996e9eb..f494268 100644 --- a/cmis.c +++ b/cmis.c @@ -1022,6 +1022,64 @@ void cmis_show_all_ioctl(const __u8 *id) cmis_show_all_common(&map); } +static void cmis_hex_dump(struct cmd_context *ctx, + const struct cmis_memory_map *map) +{ + struct module_eeprom_dump dump = { + .length = CMIS_PAGE_SIZE, + .i2c_address = CMIS_I2C_ADDRESS, + .print_bank = true, + }; + u8 bank, page; + + new_json_obj(ctx->json); + if (is_json_context()) { + open_json_object(NULL); + open_json_array("pages", ""); + } + + dump.data = map->lower_memory; + module_dump_eeprom_hex(&dump); + + for (bank = 0; bank < CMIS_MAX_BANKS; bank++) { + for (page = 0; page < CMIS_MAX_PAGES; page++) { + const __u8 *buf = map->upper_memory[bank][page]; + + if (!buf) + continue; + + /* Upper memory starts at one page size into + * the buffer, since pages are accessed at + * offset between page size and twice the + * page size. + */ + dump.offset = CMIS_PAGE_SIZE; + dump.page = page; + dump.bank = bank; + dump.data = buf + CMIS_PAGE_SIZE; + module_dump_eeprom_hex(&dump); + } + } + + if (is_json_context()) { + close_json_array(""); + close_json_object(); + } + delete_json_obj(); +} + +static void cmis_pretty_print(struct cmd_context *ctx, + const struct cmis_memory_map *map) +{ + new_json_obj(ctx->json); + open_json_object(NULL); + + cmis_show_all_common(map); + + close_json_object(); + delete_json_obj(); +} + static void cmis_request_init(struct ethtool_module_eeprom *request, u8 bank, u8 page, u32 offset) { @@ -1117,21 +1175,19 @@ cmis_memory_map_init_pages(struct cmd_context *ctx, return 0; } -int cmis_show_all_nl(struct cmd_context *ctx) +int cmis_show_all_nl(struct cmd_context *ctx, bool dump_pages) { struct cmis_memory_map map = {}; int ret; - new_json_obj(ctx->json); - open_json_object(NULL); - ret = cmis_memory_map_init_pages(ctx, &map); if (ret < 0) return ret; - cmis_show_all_common(&map); - close_json_object(); - delete_json_obj(); + if (dump_pages) + cmis_hex_dump(ctx, &map); + else + cmis_pretty_print(ctx, &map); return 0; } diff --git a/cmis.h b/cmis.h index 007632a..82fd245 100644 --- a/cmis.h +++ b/cmis.h @@ -201,6 +201,6 @@ void cmis_show_all_ioctl(const __u8 *id); -int cmis_show_all_nl(struct cmd_context *ctx); +int cmis_show_all_nl(struct cmd_context *ctx, bool dump_pages); #endif /* CMIS_H__ */ diff --git a/internal.h b/internal.h index cbf3c09..19fff41 100644 --- a/internal.h +++ b/internal.h @@ -381,14 +381,14 @@ int rxclass_rule_del(struct cmd_context *ctx, __u32 loc); /* Module EEPROM parsing code */ void sff8079_show_all_ioctl(const __u8 *id); -int sff8079_show_all_nl(struct cmd_context *ctx); +int sff8079_show_all_nl(struct cmd_context *ctx, bool dump_pages); /* Optics diagnostics */ void sff8472_show_all(const __u8 *id); /* QSFP Optics diagnostics */ void sff8636_show_all_ioctl(const __u8 *id, __u32 eeprom_len); -int sff8636_show_all_nl(struct cmd_context *ctx); +int sff8636_show_all_nl(struct cmd_context *ctx, bool dump_pages); /* FUJITSU Extended Socket network device */ int fjes_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs); diff --git a/netlink/module-eeprom.c b/netlink/module-eeprom.c index ce6a7d9..7e4e6ac 100644 --- a/netlink/module-eeprom.c +++ b/netlink/module-eeprom.c @@ -228,18 +228,18 @@ static int eeprom_parse(struct cmd_context *ctx) case MODULE_ID_GBIC: case MODULE_ID_SOLDERED_MODULE: case MODULE_ID_SFP: - return sff8079_show_all_nl(ctx); + return sff8079_show_all_nl(ctx, false); case MODULE_ID_QSFP: case MODULE_ID_QSFP28: case MODULE_ID_QSFP_PLUS: - return sff8636_show_all_nl(ctx); + return sff8636_show_all_nl(ctx, false); case MODULE_ID_QSFP_DD: case MODULE_ID_OSFP: case MODULE_ID_DSFP: case MODULE_ID_QSFP_PLUS_CMIS: case MODULE_ID_SFP_DD_CMIS: case MODULE_ID_SFP_PLUS_CMIS: - return cmis_show_all_nl(ctx); + return cmis_show_all_nl(ctx, false); #endif default: /* If we cannot recognize the memory map, default to dumping diff --git a/qsfp.c b/qsfp.c index 09d9ace..383d234 100644 --- a/qsfp.c +++ b/qsfp.c @@ -62,9 +62,11 @@ #include "cmis.h" #include "netlink/extapi.h" +#define SFF8636_MAX_PAGES 4 + struct sff8636_memory_map { const __u8 *lower_memory; - const __u8 *upper_memory[4]; + const __u8 *upper_memory[SFF8636_MAX_PAGES]; #define page_00h upper_memory[0x0] #define page_03h upper_memory[0x3] }; @@ -1078,21 +1080,72 @@ sff8636_memory_map_init_pages(struct cmd_context *ctx, return 0; } -int sff8636_show_all_nl(struct cmd_context *ctx) +static void sff8636_hex_dump(struct cmd_context *ctx, + const struct sff8636_memory_map *map) { - struct sff8636_memory_map map = {}; - int ret; + struct module_eeprom_dump dump = { + .length = SFF8636_PAGE_SIZE, + .i2c_address = SFF8636_I2C_ADDRESS, + }; + u8 page; + new_json_obj(ctx->json); + if (is_json_context()) { + open_json_object(NULL); + open_json_array("pages", ""); + } + + dump.data = map->lower_memory; + module_dump_eeprom_hex(&dump); + + for (page = 0; page < SFF8636_MAX_PAGES; page++) { + const __u8 *buf = map->upper_memory[page]; + + if (!buf) + continue; + + /* Upper memory starts at one page size into the + * buffer, since pages are accessed at offset between + * page size and twice the page size. + */ + dump.offset = SFF8636_PAGE_SIZE; + dump.page = page; + dump.data = buf + SFF8636_PAGE_SIZE; + module_dump_eeprom_hex(&dump); + } + + if (is_json_context()) { + close_json_array(""); + close_json_object(); + } + delete_json_obj(); +} + +static void sff8636_pretty_print(struct cmd_context *ctx, + const struct sff8636_memory_map *map) +{ new_json_obj(ctx->json); open_json_object(NULL); + sff8636_show_all_common(map); + + close_json_object(); + delete_json_obj(); +} + +int sff8636_show_all_nl(struct cmd_context *ctx, bool dump_pages) +{ + struct sff8636_memory_map map = {}; + int ret; + ret = sff8636_memory_map_init_pages(ctx, &map); if (ret < 0) return ret; - sff8636_show_all_common(&map); - close_json_object(); - delete_json_obj(); + if (dump_pages) + sff8636_hex_dump(ctx, &map); + else + sff8636_pretty_print(ctx, &map); return 0; } diff --git a/sfpid.c b/sfpid.c index f753917..9a7f927 100644 --- a/sfpid.c +++ b/sfpid.c @@ -498,7 +498,52 @@ static int sff8079_get_eeprom_page(struct cmd_context *ctx, u8 i2c_address, return ret; } -int sff8079_show_all_nl(struct cmd_context *ctx) +static void sff8079_hex_dump(struct cmd_context *ctx, const u8 *buf, + bool a2h_present) +{ + struct module_eeprom_dump dump = { + .length = SFF8079_PAGE_SIZE, + .print_i2c = true, + }; + + new_json_obj(ctx->json); + if (is_json_context()) { + open_json_object(NULL); + open_json_array("pages", ""); + } + + dump.i2c_address = SFF8079_I2C_ADDRESS_LOW; + dump.data = buf; + module_dump_eeprom_hex(&dump); + + if (a2h_present) { + dump.i2c_address = SFF8079_I2C_ADDRESS_HIGH; + dump.data = buf + ETH_MODULE_SFF_8079_LEN; + module_dump_eeprom_hex(&dump); + } + + if (is_json_context()) { + close_json_array(""); + close_json_object(); + } + delete_json_obj(); +} + +static void sff8079_pretty_print(struct cmd_context *ctx, const u8 *buf, + bool a2h_present) +{ + new_json_obj(ctx->json); + open_json_object(NULL); + sff8079_show_all_common(buf); + + if (a2h_present) + sff8472_show_all(buf); + + close_json_object(); + delete_json_obj(); +} + +int sff8079_show_all_nl(struct cmd_context *ctx, bool dump_pages) { bool a2h_present; u8 *buf; @@ -530,15 +575,10 @@ int sff8079_show_all_nl(struct cmd_context *ctx) } } - new_json_obj(ctx->json); - open_json_object(NULL); - sff8079_show_all_common(buf); - - if (a2h_present) - sff8472_show_all(buf); - - close_json_object(); - delete_json_obj(); + if (dump_pages) + sff8079_hex_dump(ctx, buf, a2h_present); + else + sff8079_pretty_print(ctx, buf, a2h_present); out: free(buf); -- 2.51.0