Skip to content

[Accton] Check TX_DISABLE support before access in onlp_sfpi_control_…#194

Open
eric271110 wants to merge 6 commits into
accton:support_linux_6.1from
eric271110:add_sfp_functionality_linux6.1
Open

[Accton] Check TX_DISABLE support before access in onlp_sfpi_control_…#194
eric271110 wants to merge 6 commits into
accton:support_linux_6.1from
eric271110:add_sfp_functionality_linux6.1

Conversation

@eric271110

Copy link
Copy Markdown

…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)

  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.

@eric271110 eric271110 force-pushed the add_sfp_functionality_linux6.1 branch from 087b196 to 08284d2 Compare June 15, 2026 09:10
…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>
@eric271110 eric271110 force-pushed the add_sfp_functionality_linux6.1 branch from b1fd057 to 1756289 Compare July 2, 2026 10:03
…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 vincentchiang-ec left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test

@vincentchiang-ec vincentchiang-ec left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same missing & 0xff mask on *value = tx_disable (QSFP+ path).

@vincentchiang-ec

Copy link
Copy Markdown

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 goto restore + rv = (rv == E_UNSUPPORTED) ? rv : E_INTERNAL pattern for a long time. That's why it works as the reference here — PR #191 only added the flat-memory early-exit on top of an already-safe restore block.

The other 11 platforms use a different structure (inline writeb(ADMIN_INFO) with rv = E_INTERNAL on failure). Splitting the finding against that:

Path Introduced by PR #194?
set — advertising bit clear → E_UNSUPPORTED clobbered No, pre-existing. The 5 flagged platforms already had this bug on master; PR #194 didn't fix it (and I don't think it was expected to).
set — new flat-memory E_UNSUPPORTED clobbered Yes, because PR #194 adds this new path into the already-broken restore.
get — E_UNSUPPORTED clobbered Yes. control_get didn't produce E_UNSUPPORTED before, so this is fully a PR #194 introduction.
as9817-64 / as9817-64-nb — OK → E_INTERNAL on restore fail No, pre-existing early-return structure.

So the practical takeaway isn't "PR #194 introduced all these bugs" — it's more that porting the flat-memory check via the restore: label + preserve-E_UNSUPPORTED pattern (i.e. actually mirroring as9726-32d structurally, not just its offsets) would fix both the newly-introduced and the pre-existing cases in one shot. That's the real value of adopting the reference pattern here — the fix isn't scope-creep, it's the same edit that makes the port complete.

(as9817-64 / as9817-64-nb are separate — their early-return structure is fine for E_UNSUPPORTED; only the OK-path return E_INTERNAL on restore-failure needs adjusting.)

@eric271110 eric271110 force-pushed the add_sfp_functionality_linux6.1 branch 3 times, most recently from 85bbf91 to 42814f4 Compare July 10, 2026 08:53
…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.

Refactored to goto restore pattern:
- as7926-40xfb
- as9716_32d
- as9736-64d
- as9926-24d
- as9926-24db

Preserved rv on final restore (removed return E_INTERNAL on the
success-path restore failure, kept syslog):
- as9737-32db
- as9817-64
- as9817-64-nb

Also added value masks to prevent sign extension (QSFP-DD & 0xff,
QSFP/QSFP+ & 0xf):
- 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>
@eric271110 eric271110 force-pushed the add_sfp_functionality_linux6.1 branch from 42814f4 to 9e430f2 Compare July 10, 2026 09:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants