Skip to content

drivers/nutdrv_qx.c, drivers/blazer_usb.c: cypress_command()/phoenix_command(): clear endpoint halt and retry on LIBUSB_ERROR_OVERFLOW [#598]#3448

Draft
Pyker wants to merge 1 commit into
networkupstools:masterfrom
Pyker:issue-598-cypress-overflow-clear-halt
Draft

drivers/nutdrv_qx.c, drivers/blazer_usb.c: cypress_command()/phoenix_command(): clear endpoint halt and retry on LIBUSB_ERROR_OVERFLOW [#598]#3448
Pyker wants to merge 1 commit into
networkupstools:masterfrom
Pyker:issue-598-cypress-overflow-clear-halt

Conversation

@Pyker
Copy link
Copy Markdown

@Pyker Pyker commented May 18, 2026

Summary

Adds a usb_clear_halt() + retry on LIBUSB_ERROR_OVERFLOW for the EP 0x81 interrupt read in both cypress_command() and phoenix_command() in nutdrv_qx.c and blazer_usb.c, addressing the long-running #598 hang on the 0665:5161 Cypress USB-Serial bridge family (Salicru SPS ONE, Ippon, Belkin F6C1200-UNV, ViewPower, various Voltronic Power UPSes).

The byte-level root cause analysis, captured via usbmon + tshark on a Salicru SPS 1500 ONE BL, is in this comment on #598. Short version: firmware in this bridge family occasionally emits an interrupt-IN frame larger than the declared wMaxPacketSize=8, the kernel xHCI driver returns LIBUSB_ERROR_OVERFLOW and discards the data, and every subsequent read on the endpoint also returns OVERFLOW until a USB-level reset. Locally observed rate on a steady-state Salicru: 1-3 hangs/day with pollinterval=2; once stuck, only a port reset (or usb_resetter --reset-device) recovers it.

The patch issues a single usb_clear_halt(udev, 0x81) on OVERFLOW and re-reads the same 8-byte slice once. CLEAR_FEATURE(HALT) reliably unsticks both the kernel-side endpoint state and (empirically) the firmware's TX FIFO, so the next read returns the next clean frame and the protocol layer resumes without entering the existing MAXTRIES failure cluster. If the retry also overflows, the existing error path is taken unchanged.

The same fix is applied to cypress_command() and phoenix_command() in both drivers because the read loops are byte-identical and the bug is at the USB transport layer, below either subdriver's protocol logic.

Why draft

Marking as draft until I have a few days of post-patch uptime data from the affected hardware (currently mitigated by a local watchdog that triggers usb_resetter --reset-device on stale status). I will convert to ready-for-review once I have soak data showing the OVERFLOW retries are being hit and absorbed without escalating into the existing MAXTRIES failure cluster.

Test plan

  • Build nutdrv_qx and blazer_usb with the patch (verified locally: make -C drivers nutdrv_qx blazer_usb succeeds on Linux x86_64, libusb-1.0)
  • Run nut-driver@salicru for at least 48h with debug_min = 2 and confirm:
    • At least one LIBUSB_ERROR_OVERFLOW on EP 0x81, clearing halt and retrying debug log line appears
    • Per-cycle failure rate stays at the pre-patch baseline (~0.6-0.9 events/hr) without escalating to MAXTRIES clusters
    • Watchdog at nut-salicru-watchdog.timer does not fire over the soak window
  • Report soak results in a comment; convert this PR to ready-for-review

Related issues

…command(): clear endpoint halt and retry on LIBUSB_ERROR_OVERFLOW [networkupstools#598]

Some firmware in the 0665:5161 Cypress USB-Serial bridge family
(Salicru SPS ONE, Ippon, Belkin F6C1200-UNV, ViewPower, various
Voltronic Power UPSes) occasionally emits an interrupt-IN frame
larger than the declared wMaxPacketSize=8, mid-reply. The kernel
xHCI driver flags this as LIBUSB_ERROR_OVERFLOW and discards the
data; from that point on, every subsequent read on the endpoint
also returns OVERFLOW until a USB-level reset is performed, which
results in "Data stale" from upsd until the driver is restarted.

Issue an immediate CLEAR_FEATURE(HALT) on EP 0x81 and retry the
read once. CLEAR_FEATURE(HALT) unsticks the kernel-side endpoint
state, and in the observed cases the firmware's TX FIFO state as
well, so the next read returns a clean frame. If the retry also
overflows, the existing error path is taken unchanged.

Captured at byte level on a Salicru SPS 1500 ONE BL (Voltronic-QS
H-protocol over 0665:5161, host xHCI on Linux 6.14): firmware
emits chunks 3..6 of the QS reply collapsed into a single frame
that exceeds wMaxPacketSize, kernel reports LIBUSB_ERROR_OVERFLOW,
and all subsequent reads on EP 0x81 return OVERFLOW until a port
reset.

The same fix is applied to cypress_command() and phoenix_command()
in both drivers because the read loops are byte-identical and the
bug is at the USB transport layer, below either subdriver's
protocol logic.

Signed-off-by: Pedro Cunha <pedroagracio+nut@gmail.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 18, 2026

A ZIP file with standard source tarball and another tarball with pre-built docs for commit 9eefcfd is temporarily available: NUT-tarballs-PR-3448.zip.

@AppVeyorBot
Copy link
Copy Markdown

Build nut 2.8.5.4740-master completed (commit ca38a9e7d6 by @Pyker)

@AppVeyorBot
Copy link
Copy Markdown

@jimklimov jimklimov added USB Qx protocol driver Driver based on Megatec Q<number> such as new nutdrv_qx, or obsoleted blazer and some others Connection stability issues Issues about driver<->device and/or networked connections (upsd<->upsmon...) going AWOL over time labels May 18, 2026
@jimklimov jimklimov added this to the 2.8.6 milestone May 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Connection stability issues Issues about driver<->device and/or networked connections (upsd<->upsmon...) going AWOL over time Qx protocol driver Driver based on Megatec Q<number> such as new nutdrv_qx, or obsoleted blazer and some others USB

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants