[Accton] Check TX_DISABLE support before access in onlp_sfpi_control_…#194
[Accton] Check TX_DISABLE support before access in onlp_sfpi_control_…#194eric271110 wants to merge 6 commits into
Conversation
087b196 to
08284d2
Compare
…get/set platform: as7535_28xb as7926-40xfb as7946-30xb as7946-74xkb as9716_32d as9736_64d as9737-32db as9817-64nb as9817-64 as9926-24 merge from [Accton][as9726-32d] Check TX_DISABLE support before access in onlp_sfpi_control_get/set (accton#191) 1. Flat-memory CMIS modules (typically passive DACs / simple AOCs) only have lower memory + page 00h. The page select register is silently discarded, so a request for page 01h or 10h actually still reads page 00h vendor info, returning plausible-looking but meaningless bytes. 2. control_get previously did not check the TX Disable Supported advertising bit at all; it walked straight to page 10h and read byte 0x82. control_set checked the advertising bit but missed the flat-memory case. Both paths now: - Read lower-memory byte 0x02 bit 7 (Flat_mem) first. Flat-memory modules return ONLP_STATUS_E_UNSUPPORTED immediately, without touching the page select registers. - For paged modules, check the TX Disable Supported advertising bit on page 01h byte 0x9B bit 1, mirroring the existing set path. - control_get's restore block preserves E_UNSUPPORTED instead of overwriting it with E_INTERNAL. Verified on a real switch via libonlp.onlp_sfp_control_get(): an unsupported / flat-memory module now returns -10 (E_UNSUPPORTED) instead of a stale lane-mask byte. Signed-off-by: Eric Yang <eric_yang@accton.com>
platform: as7535_28xb as7926-40xfb as7946-30xb as7946-74xkb as9716_32d as9736_64d as9737-32db as9817-64nb as9817-64 as9726-32d as9926-24 Signed-off-by: Eric Yang <eric_yang@accton.com>
platform: as9926-24db Signed-off-by: Eric Yang <eric_yang@accton.com>
Page 01h (Advertising) is unbanked, so writing the bank-select register before switching to it has no effect. Page 10h (Lane Control) is banked, so the bank-select must be set before switching to it. Move the QSFP_DD_EEPROM_OFFSET_BANK_SELECT write into the TX_DISABLE-supported branch, immediately before the page-select to QSFP_DD_PAGE_LANE_CTRL, in both the set and get paths. platform: as7535-28xb as7926-40xfb as7946-30xb as7946-74xkb as9716_32d as9726-32d as9736-64d as9737-32db as9817-64 as9817-64-nb as9926-24d as9926-24db Signed-off-by: Eric Yang <eric_yang@accton.com>
b1fd057 to
1756289
Compare
…sary error logs merge from [Accton][as9726-32d] Route SFP errors to syslog, drop unsupported-state logs accton#197 platform: as7535-28xb as7926-40xfb as7946-30xb as7946-74xkb as9716_32d as9736-64d as9737-32db as9817-64-nb as9817-64 as9926-24d as9926-24db Changes: - Replace AIM_LOG_ERROR with syslog(LOG_ERR, ...) for consistent logging - Remove flat-memory module unsupported log messages - Remove tx_disable not supported log messages - Add #include <syslog.h> Signed-off-by: Eric Yang <eric_yang@accton.com>
vincentchiang-ec
left a comment
There was a problem hiding this comment.
Nice port overall — flat_mem detection, advertising-bit gating, bank-select order and the syslog cleanup all landed cleanly on most platforms. Two systematic issues showed up during review, and I've left inline notes at each site.
1. Restore-write clobbers E_UNSUPPORTED / OK (5 platforms × set+get = 10 sites). The final writeb(page_select, ADMIN_INFO) in the QSFP-DD block sets rv = E_INTERNAL on failure, which overwrites the rv = E_UNSUPPORTED we just carefully set for flat-memory / non-advertising modules (and also flips a successful write to E_INTERNAL). Regresses the exact behaviour PR #191 was written to introduce. Reference fix pattern is in as9726-32d sfpi.c (restore: label + rv = (rv == E_UNSUPPORTED) ? rv : E_INTERNAL) — please mirror it. Affected: as9716_32d, as9736-64d, as9926-24d, as9926-24db, as7926-40xfb.
2. as9817-64 / as9817-64-nb early-return pattern (2 platforms × set+get = 4 sites). These files use return E_INTERNAL inline in each error branch instead of the restore: label. The E_UNSUPPORTED paths (return E_UNSUPPORTED after restore) are fine — but the final "success" restore does return E_INTERNAL on restore failure, so a successful set/get becomes E_INTERNAL if only the ADMIN_INFO write itself fails. Same fix idea: either preserve the pre-restore return value or drop the failure-→ E_INTERNAL on the restore-only branch.
3. Missing & 0xff mask on *value = tx_disable (as9817-64 / as9817-64-nb only). Everywhere else the port applies *value = (tx_dis & 0xff) to avoid the sign-extension from dev_readb's int return; these two platforms still assign the raw signed int, so a byte with bit7 set will surface as a negative value in value. Trivial mask fix.
Nothing else looks off — flat-mem check offsets, page 01h advertising bit, bank-select-before-page-10h all match the reference on every platform.
| AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", | ||
| syslog(LOG_ERR, "Unable to write tx_disable status to port(%d): write page to eeprom fail", | ||
| port); | ||
| rv = ONLP_STATUS_E_INTERNAL; |
There was a problem hiding this comment.
Restore write clobbers E_UNSUPPORTED (control_set path). When the TX_DISABLE_SUPPORT advertising bit is clear a few lines above, rv is set to E_UNSUPPORTED; this block then unconditionally overwrites it to E_INTERNAL if the ADMIN_INFO restore itself fails. Same thing happens on the successful write path (turns rv = OK into E_INTERNAL).
Suggested fix — mirror the as9726-32d pattern in this repo:
restore:
if ((onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR,
QSFP_DD_EEPROM_OFFSET_PAGE_SELECT,
QSFP_DD_PAGE_ADMIN_INFO)) < 0) {
syslog(LOG_ERR, "Failed to restore Page Select to Admin Info on port(%d)!", port);
}
if (rv < 0) {
rv = (rv == ONLP_STATUS_E_UNSUPPORTED) ? rv : ONLP_STATUS_E_INTERNAL;
}Fork missed this platform — same pattern as the four flagged in the other comments.
| AIM_LOG_ERROR("Unable to read tx_disable status from port(%d): write page to eeprom fail\r\n", | ||
| syslog(LOG_ERR, "Unable to read tx_disable status from port(%d): write page to eeprom fail", | ||
| port); | ||
| rv = ONLP_STATUS_E_INTERNAL; |
There was a problem hiding this comment.
Same restore-clobber issue on the control_get path — see the control_set comment above for the reference fix.
| AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", | ||
| syslog(LOG_ERR, "Unable to write tx_disable status to port(%d): write page to eeprom fail", | ||
| port); | ||
| rv = ONLP_STATUS_E_INTERNAL; |
There was a problem hiding this comment.
Restore write clobbers E_UNSUPPORTED (control_set path). When the earlier else { rv = ONLP_STATUS_E_UNSUPPORTED; } fires (advertising bit clear), this block promotes it to E_INTERNAL if the ADMIN_INFO restore itself fails. Also flips a successful write path (rv = OK) to E_INTERNAL.
Suggested fix — mirror the as9726-32d reference:
restore:
if ((onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR,
QSFP_DD_EEPROM_OFFSET_PAGE_SELECT,
QSFP_DD_PAGE_ADMIN_INFO)) < 0) {
syslog(LOG_ERR, "Failed to restore Page Select to Admin Info on port(%d)!", port);
}
if (rv < 0) {
rv = (rv == ONLP_STATUS_E_UNSUPPORTED) ? rv : ONLP_STATUS_E_INTERNAL;
}| AIM_LOG_ERROR("Unable to read tx_disable status from port(%d): write page to eeprom fail\r\n", | ||
| syslog(LOG_ERR, "Unable to read tx_disable status from port(%d): write page to eeprom fail", | ||
| port); | ||
| rv = ONLP_STATUS_E_INTERNAL; |
There was a problem hiding this comment.
Same restore-clobber issue on the control_get path — see the control_set comment above.
| AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", | ||
| syslog(LOG_ERR, "Unable to write tx_disable status to port(%d): write page to eeprom fail", | ||
| port); | ||
| rv = ONLP_STATUS_E_INTERNAL; |
There was a problem hiding this comment.
Restore write clobbers E_UNSUPPORTED (control_set). Please mirror the as9726-32d restore: label + rv = (rv == E_UNSUPPORTED) ? rv : E_INTERNAL pattern — same story as the as9716_32d comment.
| AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d) : write page to eeprom fail\r\n", | ||
| syslog(LOG_ERR, "Unable to read tx_disabled status from port(%d) : write page to eeprom fail", | ||
| port); | ||
| return ONLP_STATUS_E_INTERNAL; |
There was a problem hiding this comment.
Successful control_get reported as E_INTERNAL when the restore write fails — same pattern as line 332 on the set side. Same fix suggestion.
| if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) <0){ | ||
| AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", port); | ||
| syslog(LOG_ERR, "Unable to write tx_disable status to port(%d): write page to eeprom fail", port); | ||
| return ONLP_STATUS_E_INTERNAL; |
There was a problem hiding this comment.
Successful control_set reported as E_INTERNAL when the restore write fails. Every earlier error branch already return E_INTERNAL after its own restore, so this final restore only runs on the OK path — returning E_INTERNAL here turns a real success into a caller-visible failure. Same fix idea as the as9817-64 comment: either drop the return E_INTERNAL here or adopt the restore: label pattern from as9726-32d.
| syslog(LOG_ERR, "Unable to read tx_disabled status from port(%d) : read TX disable from eeprom fail", port); | ||
| return ONLP_STATUS_E_INTERNAL; | ||
| } | ||
| *value = tx_disable; |
There was a problem hiding this comment.
Missing & 0xff mask on *value = tx_disable. Sign-extension bug — dev_readb returns int and a byte with bit 7 set surfaces as a negative value. Please apply the *value = (tx_disable & 0xff) mask used elsewhere in this PR.
| if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) <0){ | ||
| AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d) : write page to eeprom fail\r\n", port); | ||
| syslog(LOG_ERR, "Unable to read tx_disabled status from port(%d) : write page to eeprom fail", port); | ||
| return ONLP_STATUS_E_INTERNAL; |
There was a problem hiding this comment.
Successful control_get reported as E_INTERNAL when the restore write fails — same pattern as line 314. Same fix suggestion.
| syslog(LOG_ERR, "Unable to read tx_disabled status from port(%d) : read TX disable from eeprom fail", port); | ||
| return ONLP_STATUS_E_INTERNAL; | ||
| } | ||
| *value = tx_disable; |
There was a problem hiding this comment.
Same missing & 0xff mask on *value = tx_disable (QSFP+ path).
|
Follow-up context on the review above — I want to be fair about how much of this bug PR #194 actually introduced, since re-reading the pre-PR code changed my picture: as9726-32d was already safe before PR #191 landed. It has used the The other 11 platforms use a different structure (inline
So the practical takeaway isn't "PR #194 introduced all these bugs" — it's more that porting the flat-memory check via the (as9817-64 / as9817-64-nb are separate — their early-return structure is fine for |
42814f4 to
9e430f2
Compare
…tten by page restore failure The final ADMIN_INFO page restore write could previously mask a successful or E_UNSUPPORTED result. This fix ensures the real result is preserved by refactoring the QSFP-DD TX_DISABLE control_set/get flow to the goto restore pattern. Also added value masks to prevent sign extension (QSFP-DD & 0xff, QSFP/QSFP+ & 0xf). Affected platforms: - as7926-40xfb - as9716_32d - as9736-64d - as9737-32db - as9817-64 - as9817-64-nb - as9926-24d - as9926-24db Signed-off-by: Eric Yang <eric_yang@accton.com>
9e430f2 to
096e616
Compare
|
I've addressed the issues you pointed out above. I also noticed that the missing & 0xff mask on tx_disable is a common issue rather than being limited to the originally flagged platforms, so I've added the mask across all platforms. The following platforms have been refactored to use the goto restore structure: as7926-40xfb Thanks! |
|
|
||
| restore: | ||
| if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) < 0) { | ||
| syslog(LOG_ERR, "Unable to read tx_disable status from port(%d): write page to eeprom fail", |
There was a problem hiding this comment.
this action is not "Unable to read tx_disable status from port(%d)"
|
|
||
| restore: | ||
| if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) < 0) { | ||
| syslog(LOG_ERR, "Unable to write tx_disable status to port(%d): write page to eeprom fail", |
There was a problem hiding this comment.
this action is not "Unable to read tx_disable status from port(%d)"
| } | ||
| if (rv < 0) { | ||
| AIM_LOG_ERROR("Unable to write tx_disable status to port(%d)\r\n", port); | ||
| syslog(LOG_ERR, "Unable to write tx_disable status to port(%d)", port); |
There was a problem hiding this comment.
Do we need this error log?
We already have another error log before "goto restore"
…get/set
platform:
as7535_28xb
as7926-40xfb
as7946-30xb
as7946-74xkb
as9716_32d
as9736_64d
as9737-32db
as9817-64nb
as9817-64
as9926-24
merge from [Accton][as9726-32d] Check TX_DISABLE support before access in onlp_sfpi_control_get/set (#191)
Flat-memory CMIS modules (typically passive DACs / simple AOCs) only have lower memory + page 00h. The page select register is silently discarded, so a request for page 01h or 10h actually still reads page 00h vendor info, returning plausible-looking but meaningless bytes.
control_get previously did not check the TX Disable Supported advertising bit at all; it walked straight to page 10h and read byte 0x82. control_set checked the advertising bit but missed the flat-memory case.
Both paths now:
Verified on a real switch via libonlp.onlp_sfp_control_get(): an unsupported / flat-memory module now returns -10 (E_UNSUPPORTED) instead of a stale lane-mask byte.