2026-09-27 在 macOS 上打通外置 USB 存储的 SMART 读取:接入与实机验证进展
把一块硬盘装进 USB 硬盘盒、接到 Mac 上,文件可以正常读写,健康信息却未必能读出来。温度、通电时间、介质错误和剩余寿命等信息需要通过设备管理命令获取;系统能够挂载文件系统,只说明普通数据访问已经接通。
smartmontools 是读取这类信息的开源工具集,其中的 smartctl 可以查询硬盘的身份、SMART 健康状态和日志。它已经理解许多硬盘与 USB 桥接芯片的协议,但在 macOS 上,还缺少一条适用于这些外置设备的通用命令传输路径。
我们为 smartmontools 补上了 macOS 用户态 USB 传输层,让现有的健康诊断能力能够到达外置 USB-SATA 和 USB-NVMe 设备。 这条路径已经在多款硬盘盒上完成真实读取与释放验证,部分 USB-SATA 组合还验证了已挂载卷的自动卸载和恢复。下面从这个访问缺口讲起,介绍实现方式、实际效果,以及它如何进一步服务于存储工具。
为什么能访问文件,却读不到健康信息
USB 硬盘盒中的桥接芯片负责把主机命令转交给 SATA 或 NVMe 硬盘。普通文件访问走操作系统已经提供的存储路径;读取 SMART 等管理信息,则需要工具把相应命令穿过操作系统和桥接芯片,送到硬盘。
我最初在梳理一套跨平台存储研究工具,希望统一读取 ATA/SATA、SCSI/SAS 和 NVMe 的身份、健康状态与日志,再逐步承接更完整的诊断界面。Linux 和 Windows 已有较成熟的底层透传路径;macOS 对部分设备提供原生 SMART 接口,但外置 USB 设备的桥接命令仍缺少合适的入口。
smartmontools 已经具备 ATA/NVMe 数据解析、SAT(SCSI/ATA Translation)和多种 USB-NVMe SNT 封装。我们需要在 macOS 上将这些 SCSI 命令实际送到 USB 设备,因此工作集中在平台传输层,继续复用已有的桥接协议与健康信息解析。
历史上的 OS X SAT SMART Driver 通过内核扩展提供 SAT SMART 访问。我们的路线使用 Apple 的公开 IOUSBHost API,在用户态临时接管设备、执行读取,再把设备交还给系统。接管范围限定为可确认身份与拓扑的外置 USB 存储设备。
怎样打通:复用解析器,补上 macOS 的 USB 传输层
我们把平台差异限制在 Darwin 后端。Darwin 是 macOS 的底层系统;新增的 transport(传输层)负责把命令送到设备,并将数据和完成状态交回。一次读取经过以下层次:
flowchart LR CLI["smartctl<br/>参数、文本与 JSON"] --> Bridge["SAT / SNT<br/>桥接命令封装"] Bridge --> Darwin["Darwin scsi_device<br/>统一 SCSI CDB 接口"] Darwin --> USB["BOT / UASP QD1<br/>命令、数据、完成状态"] USB --> Capture["IOUSBHost DeviceCapture<br/>接管与释放"] Capture --> Enclosure["USB-SATA / USB-NVMe bridge"] Enclosure --> Media["ATA / NVMe 介质"]
USB-SATA 将 ATA 请求装入 SAT 命令;USB-NVMe 则使用 JMicron、ASMedia 和 Realtek 各自的 SNT 封装。现有 SAT 实现和 SNT 实现继续负责这些语义,Darwin 层提供可靠的 scsi_pass_through()。
1. Objective-C++ 留在平台 adapter
lib/os_darwin_usb.h 与 lib/os_darwin_usb.mm 封装设备打开关闭、BOT/UASP transport 和 SCSI 命令执行。C++ 侧只面对窄接口,Apple framework 对象留在 .mm 中。
构建系统已补充 Objective-C++ 编译与 C++ 链接规则、libtool tag 兼容、IOUSBHost API 检测和弱链接。历史构建记录覆盖 Linux 生成源码包、Darwin universal 构建、SDK 11.3 交叉构建及产物启动;平台依赖没有扩散到其他操作系统的设备实现。
2. 接管与卷恢复成为完整生命周期
DeviceCapture 会临时接管整台 USB 设备。当前实现先确认单存储接口、单整盘和 LUN 0,排除复合设备;对已挂载卷执行非强制卸载,无法确认可用于恢复的卷身份时拒绝接管。
关闭后,后端释放设备,按 USB 设备身份和卷 UUID 找回原卷,并等待原挂载路径恢复。9 月 14 日的修复补上了关键细节:IOMedia 出现时,Disk Arbitration 可能尚未发布挂载路径;需要同时观察设备出现与路径变化,再决定是否发起恢复请求。挂载恢复提交
恢复失败会报告错误并设置退出状态,调用方能区分 SMART 读取结果和设备归还结果。每次读取包含临时卸载与设备复位,因此这条路径适合按需诊断,持续轮询已挂载存储的 smartd 场景仍不合适。
3. BOT:完整事务、真实长度和有界恢复
USB-IF BOT 规范定义了 CBW、可选 data、CSW 的顺序。实现检查 signature、tag、residue、短传输、STALL 与 phase error,并在初始化时建立一致的命令状态。
后续实机工作处理了两类问题。JMS583 的 NVMe 路径需要同步 START UNIT 唤醒;该唤醒被限定为明确的启动动作。某些 BOT 状态读取遇到 STALL 时,后端按规范清除状态并重读一次 CSW,原命令与数据不会因此重发。
ASM1153E 的测试固件只有唯一且已生效的默认 BOT 设置,重复发送 SET_INTERFACE 会收到 STALL。当前代码按接口描述符识别这种布局,跳过冗余设置,同时保留 BOT Reset Recovery。默认 BOT 修复
4. UASP:按真实 pipe 与会话状态工作
UASP 分别管理 command、status、data-in 和 data-out pipe,使用自己的 IU 与 stream 语义。当前实现保持 queue depth 1,解析 pipe-usage descriptor,分别处理支持 streams 与不支持 streams 的路径;参考依据包括 T10 UAS 与 Linux UAS driver。
实机接管后,接口描述符显示正确的 alternate,并不保证旧会话已经清理完成。代码会等待 IOKit 服务树稳定,再按接口布局选择传输。RTL9210 的修复进一步在打开接口前重建 USB configuration,避免保留的旧 UASP 会话导致 Identify 超时。
异常路径保留超时与取消处理,异步请求在回调结束前持有相关资源。完整 UAS task-management、USB 2 无 streams 路径和复杂异常恢复仍需继续验证。
5. 只读命令策略与完整结果一起执行
transport 继续限制为读取导向的命令集合,包括设备身份、健康状态、必要日志,以及精确限定的桥接信封和唤醒动作。写介质、擦除、固件更新与任意 NVMe 管理命令不在当前接口范围内。
读取完整性同样影响结果是否可用。ASM2362 曾对 1024 字节日志请求只返回 512 字节;SNT 层现在依据实际 residue 计算进度,使用日志偏移继续读取剩余部分。零进度、未对齐进度、异常 residue 或不完整 Identify 均会报错。ASMedia 读取与自动识别提交
实际效果:读取健康信息,并把设备正常交还给系统
验证覆盖两个环节:读取是否得到完整、可信的结果,以及结束后设备能否回到系统;对原来已经挂载的卷,还要检查身份和挂载路径是否恢复。以下各组对应当时修复版本与硬件。USB-NVMe 三组使用 Micron MTFDHBL256TDQ / MU05.1;各次验收均检查实际传输协议、返回数据和释放后的设备状态。
| 日期与设备 | 实际覆盖 | 已取得结果 | 挂载恢复范围 |
|---|---|---|---|
09-12:JMS583,152d:0583,bcdDevice 0209 | system、显式 UASP、显式 BOT 各 5 次,另加 1 次自动识别 | 16/16 完成 Identify、SMART、错误/自检日志读取与释放 | 无已挂载文件系统;验证整盘重新枚举 |
09-12:ASM2362,174c:2362,bcdDevice 0100 | 普通整盘路径自动识别、显式 UASP、显式 BOT 各 5 次 | 15/15 完成读取与释放,错误日志短返回得到补全 | 无已挂载文件系统;验证整盘重新枚举 |
09-14:Seagate USB-SATA,0bc2:2300 | 自动识别与显式 SAT/BOT 各 5 次 | 10/10 完成 Identify、SMART、日志与释放,退出码 0 | 四个 NTFS 卷恢复原身份、路径和只读状态 |
| 09-17:ASM1153E USB-SATA | 自动识别与显式 BOT 各 5 次 | 10/10 完成 SMART、释放与恢复;该固件未提供 UASP | 每次四个卷均恢复;不可用 UASP 请求也能结束并恢复卷 |
09-21:HIKSEMI MS201,已确认的 RTL9210B,0bda:9210,bcdDevice 2001 | 自动 UASP、显式 UASP、显式 BOT 各 5 次 | 15/15 完成 SMART、8 条错误记录、预期日志限制报告和释放 | 无已挂载文件系统;释放后恢复系统 UASP |
USB-NVMe 的接入与验收摘要见硬件验证文档;两组 USB-SATA 的次数与挂载恢复结果也写入对应维护提交。USB 的 bcdDevice 在这里作为设备版本描述值记录,SSD 固件版本单独列出。
RTL9210B:SMART 已读通,长日志保留明确限制
最新提交 1bb7cc68 解决了 RTL9210 接管后残留会话的问题,也修正了日志截断却以零填充尾部并报告成功的行为。当前 Realtek SNT 路径仍保留 512 字节日志上限,可读取完整的前 8 条错误记录;超出范围的日志请求会明确失败。
因此,本次 RTL9210B 矩阵中的 smartctl -a 返回 4:SMART 已读出,但请求的部分日志不完整。验收脚本检查的正是这项如实报告行为。只读取当前支持的集合时,以下命令在该设备上返回 0:
sh
sudo ./src/smartctl -i -H -A -l error,8 /dev/diskN后续针对同一设备的诊断探针曾在 UASP 和 BOT 下取得完整的 564 字节自检日志与 4096 字节错误日志响应,自检日志第 536 字节处也有实际状态数据。这说明 512 字节是当前软件兼容策略,尚不能据此认定该硬件只能返回 512 字节。生产路径仍保留限制;第八条之后的非空错误记录和其他桥固件需要独立验证。
软件回归覆盖哪些内容
实机验证之外,构建与回归测试用于检查协议处理和平台接入。9 月 5 日的工作覆盖了源码包生成、Darwin universal 构建、SDK 11.3 交叉构建、distcheck、产物双架构启动,以及针对 transport 的 ASan/UBSan 测试。
后续桥接与恢复修复都包含维护测试。最新的 1bb7cc68 提交对应构建成功,make check 的 SNT、Darwin 扫描和 USB transport 三项测试全部通过。各阶段的实机记录和软件回归共同界定当前已验证的范围。
怎样使用:继续使用熟悉的 smartctl 命令
使用包含这项实现的开发分支构建后,对于 drive database 已识别的桥,普通整盘路径可以完成自动识别:
sh
sudo ./src/smartctl -a /dev/diskN这里的 diskN 必须是当次枚举确认的目标外置整盘。已知 USB-NVMe 桥优先走数据库指定的 SNT 类型;原生 ATA SMART 驱动、其他 NVMe 设备及显式 -d nvme 保留各自的原生访问路径。未知 USB 桥使用 sat,auto 检测,未知 USB-NVMe 桥需要显式选择已经确认适用的 snt* 类型。
ASM2362 的实测说明了这项路由调整的必要性:系统原生 NVMe API 可以返回 Identify,却拒绝 SMART Get Log Page。按桥类型进入 SNT 后,普通 /dev/diskN 命令才完整走通。相关接入行为已写入当前分支手册。
BOT 与 UASP 是两种 USB 存储传输协议,与 SAT/SNT 这样的桥接命令类型分别选择。默认沿用 macOS 接管前正在使用的传输协议,也可以显式指定:
sh
sudo ./src/smartctl -a -d sntjmicron+usb,uasp /dev/diskN
sudo ./src/smartctl -a -d sntjmicron+usb,bot /dev/diskNsat、sntasmedia、sntrealtek 和 scsi 同样接受传输后缀。指定协议不可用时返回错误,后端不自动切换协议。usbraw:diskN 和 usbraw:REGISTRY_ID 仍保留为显式 raw USB 入口;每次释放后注册表 ID 可能改变,下一次访问需要重新发现设备。
默认扫描继续排除 raw USB。需要查看这些设备时,使用被动扫描:
sh
./src/smartctl --scan -d usb--scan-open -d usb 则会实际打开设备,进入卸载、接管、命令与恢复流程。raw USB 当前要求 macOS 10.15 或以上,以及当前登录用户会话中的 root 权限;已完成的实机验证来自记录中的 arm64 环境,旧版系统兼容性仍需相应环境验证。
这层能力还能用在哪里
这条路线已经让 macOS 上的外置设备可以复用 smartmontools 的健康解析和桥接知识。使用者继续通过命令行或 JSON 消费结果,桥的差异留在 SAT/SNT 层,设备接管、传输和挂载恢复留在 Darwin 后端。
目前已有下游 fork 和项目开始集成这项工作。ENB 跨平台 NVMe 基础设施是其中一个明确案例:其 macOS USB 接管、BOT/UASP 和释放恢复实现迁自这条开发线,并在来源声明中记录了迁入快照。ENB 在此基础上提供设备生命周期、原始执行结果与 RPC,服务于研究、诊断、恢复和 Agent 应用。
下游集成让这套传输实现进入更多实际工作流,也能为后续兼容性修复提供反馈。两个项目各自维护能力和验证矩阵:smartmontools 继续围绕健康读取工作,ENB 在自己的执行合同下扩展设备访问场景。这为平台传输与上层工具分别演进提供了共同基础。
上游进展与下一步
前面介绍的实现和验证来自 PeratX/smartmontools 的 darwin-usb-smart-poc 开发分支。截至 2026-09-27,提交给 smartmontools 官方仓库的 PR #639 仍为 Open / Draft,尚未合入。分支最新提交与 PR head 均为 1bb7cc68,包含本文介绍的桥接与生命周期修复。
已经完成的构建、回归和实机验证为这项改动提供了依据,下游也已开始采用。上游可见的 SonarCloud、CodeRabbit、GitGuardian 与 SonarCloud Code Analysis 四项检查均成功;GitHub 合并状态仍为 UNSTABLE,当前返回的检查清单未覆盖完整构建矩阵。
我们的目标是推动这项能力进入 smartmontools 的下一个大版本更新,并持续推进。 后续会响应维护者审查、维护兼容性与测试,扩展桥固件和文件系统组合,并补齐拔插、超时、拒绝卸载、进程异常和恢复失败等场景。具体合入与发布安排由上游审查决定。