目录
[0. 文档用途与口径](#0. 文档用途与口径)
[1. 现网拓扑(可定死)](#1. 现网拓扑(可定死))
[1.1 槽位 ↔ Root Port ↔ Endpoint ↔ 控制器实例](#1.1 槽位 ↔ Root Port ↔ Endpoint ↔ 控制器实例)
[1.2 双口为何被排除](#1.2 双口为何被排除)
[2. 失败链(建议按此顺序对外讲述)](#2. 失败链(建议按此顺序对外讲述))
[3. pciehp 在干什么(物理层入口)](#3. pciehp 在干什么(物理层入口))
[3.1 典型片段(Slot 40 / 32 / 42 形态相同)](#3.1 典型片段(Slot 40 / 32 / 42 形态相同))
[3.2 与 -ENODEV 的关系](#3.2 与 -ENODEV 的关系)
[3.3 现场需一并核对](#3.3 现场需一并核对)
[4. 两类 I/O:必须拆开,禁止写成「盘坏了」](#4. 两类 I/O:必须拆开,禁止写成「盘坏了」)
[4.1 僵尸 gendisk 被 udev / blkid 戳(容量已废)](#4.1 僵尸 gendisk 被 udev / blkid 戳(容量已废))
[4.2 活着或半活路径上的介质 / PI 完成错](#4.2 活着或半活路径上的介质 / PI 完成错)
[4.3 最危险的时序:新实例已活,旧 n1 无人释放](#4.3 最危险的时序:新实例已活,旧 n1 无人释放)
[5. 与 CLR / CSTS=0x1 如何衔接(改口径,不推翻旧事实)](#5. 与 CLR / CSTS=0x1 如何衔接(改口径,不推翻旧事实))
[6. 证据分级(对外时不要把推断写成事实)](#6. 证据分级(对外时不要把推断写成事实))
[7. 立即处置(只读 + 止血)](#7. 立即处置(只读 + 止血))
[7.1 止血](#7.1 止血)
[7.2 链路 / 槽位 / AER(只读)](#7.2 链路 / 槽位 / AER(只读))
[7.3 盘侧只读(禁止 reset / NSSR / FLR)](#7.3 盘侧只读(禁止 reset / NSSR / FLR))
[8. 对外话术(可直接转发)](#8. 对外话术(可直接转发))
[8.1 平台 / 现场](#8.1 平台 / 现场)
[8.2 盘厂 / 固件](#8.2 盘厂 / 固件)
[9. 后续决策树(避免现场即兴)](#9. 后续决策树(避免现场即兴))
[10. 一句话结论](#10. 一句话结论)
0. 文档用途与口径
本文把现网日志、PCI 拓扑、Identify 信息和块层错误压成一条可对外、可复盘的因果链。结论用于:
- 现场止血(停旧节点、禁 reset、禁槽位 power cycle)
- 平台侧查 U.2 / 背板 / 供电 / 带外
- 盘厂侧查 CC 状态机、未开 PI 时报 Guard Check、残留 NS 完成路径
口径必须同时写两头,缺一不可:
| 责任面 | 已坐实的现象 | 不能单独解释的部分 |
|---|---|---|
| 平台 / 物理链路 | pciehp Surprise:Card present + No link,约 30s 后再 Link Up;槽位反复重新枚举 |
掉链之前 盘已对 4K Read 回 0x281;CLR 后 CSTS.RDY 不落 |
| 盘固件 / NVMe 状态机 | Controller Reset 后 RDY 卡在 0x1 → -ENODEV;Identify CMIC=0 |
槽位 Presence 仍在、链路自己掉;pciehp 风暴先于多数 -19 |
只骂固件或只骂槽位,都会漏掉一半证据。
明确排除:
- 不是「双端口对端」故事。全机 NVMe 均为
xx:00.0单功能,无.1第二 PF。 - 不只是「
CC.EN清不掉RDY」单点。那是失败链中段,入口在链路 Surprise,出口在残留 gendisk 仍被 udev / 巡检打 I/O。
硬禁令(已在现网验证会恶化):
nvme reset/ FLR / 写 NSSRecho 0 > /sys/bus/pci/slots/*/power
Slot(40)/(42) 已在断电级循环。在循环上再 reset,会把「链路不稳」升级为「CLR 卡死、CSTS=0x1、最终 -ENODEV」。
1. 现网拓扑(可定死)
1.1 槽位 ↔ Root Port ↔ Endpoint ↔ 控制器实例
| 热插拔槽 | Root Port | Endpoint | 现 ctrl | 旧 ctrl | 本次是否进 surprise 风暴 |
|---|---|---|---|---|---|
| Slot(40) | e0:03.1 |
e1:00.0 |
nvme0 | nvme3 | 是,反复 enabling device |
| Slot(42) | e0:03.3 |
e3:00.0 |
nvme8 | nvme5 | 是,至少两次完整回来并建队列 |
| Slot(32) | 80:01.1 |
很大概率 81:00.0 |
nvme7 | --- | 抖动最密;本段 grep 未见 配套 81:00.0 增删 |
| 其他槽 | --- | 含另一厂商一块、以及同系列另外两颗 | 若干 | --- | 未进入同一套风暴 |
readlink 即使未贴全也不影响:内核已把 Slot(40)→e1:00.0→nvme0、Slot(42)→e3:00.0→nvme8 打进 dmesg。
1.2 双口为何被排除
lspci -d ::0108(NVM Express 类代码)全部是xx:00.0,无第二功能。- 对
0000:e1:00.0/0000:e1:00.*的列举路径本身错误:那是找「该设备下的子设备」,不是找同槽第二 PF。 - 故障后再枚举的 ctrl Identify:
CMIC=0、CNTLID=0,与单控制器一致。
实例号从 nvme3→nvme0、nvme5→nvme8,是 PCI remove/add 后 nvme 核心按空闲最小号重分配,不是对端口换身份。
2. 失败链(建议按此顺序对外讲述)
U.2 / 背板 / 供电 / 线序 / 带外 power
│
▼
pciehp: Card present, No link (~3s PD 断言, LTSSM 未起来)
│ ~30s 等链路
▼
Card present + Link Up → pci enabling device
│ 上电过程中再次 Surprise
▼
Endpoint 从 PCI 消失 / 再出现
│
├─ 用户可见:ctrl 号漂移(nvme3→0, nvme5→8)
├─ 驱动可见:旧 gendisk 未释放(nvme3n1 / nvme5n1 仍在)
└─ 若此时再 nvme reset / FLR
│
▼
CC.EN 置位或 CLR,CSTS.RDY 不落(保持 0x1)
│
▼
超时 → -ENODEV (-19) ← 链路已没设备时也会直接 -19
并行、独立的一条盘侧错误(发生在部分 Link Down 之前):
周期性 4K Read(opcode 0x2, 8 blocks, ~2s, LBA 散落)
│
▼
完成状态 SCT=2 SC=81 (0x281 Guard Check) + MORE + DNR
│
▼ (随后才)
Slot Link Down → 未完成命令被 host abort → SCT=3 SC=71 (0x371)
因此:0x281 不是掉链的结果 ,是掉链前 盘已经在报 PI/介质类错误;0x371 才是掉链瞬间的 host 侧取消。
3. pciehp 在干什么(物理层入口)
3.1 典型片段(Slot 40 / 32 / 42 形态相同)
Card present
No link ← Presence Detect 仍断言,链路未训练
... ~30s(热插拔驱动等 Link Up)...
Card present + Link Up
pci ... enabling device
Already in powering on state ← 上电未完成又来一次 surprise
叠加:
| 日志 | 含义 |
|---|---|
Already disabled |
槽位已被软件关掉(pciehp 自己,或有人写了 slots/*/power) |
Slot(40) 反复 enabling device |
同一 BDF e1:00.0 被拆掉再枚举成同一个名字 nvme0,是循环不是一次 hang |
| Slot(42) 建队列成功 | Shutdown timeout 15s、128/0/0 default/read/poll queues、rescanning namespaces → 新实例曾经 Ready 且有 NS |
Slot(32) 最密但缺 81:00.0 增删 |
更像 LTSSM 抖、尚未完整 remove,或 remove/add 打在别的 BDF。必须单独确认下游 |
3.2 与 -ENODEV 的关系
-19 / -ENODEV 在这条链上有两种充分条件,不必互斥:
- PCI 设备已从总线消失(Surprise remove)→ 任何后续 admin/io 都是
-ENODEV。 - 设备还在,但 CLR 后
CSTS.RDY不置位,驱动放弃 → 同样-ENODEV。
现网两种都出现过。实例号空洞大量可用 Surprise 直接解释,不必先假设双口。
3.3 现场需一并核对
- MPS 被抬到 512:是否符合 Root Port / 交换机 / 盘的协商设计,避免当成「无关配置」。
- BMC / 带外是否对 slot 做 power cycle(会与
pciehp抢状态,出现Already disabled/Already in powering on state)。
4. 两类 I/O:必须拆开,禁止写成「盘坏了」
4.1 僵尸 gendisk 被 udev / blkid 戳(容量已废)
I/O error, dev nvme3n1, sector 0
unable to read RDB block 0
unable to read partition table
partition table beyond EOD, truncated
| 项 | 说明 |
|---|---|
| 谁在打 | systemd-udevd / blkid / 监控扫残节点 |
| 打什么 | sector 0、RDB、分区表 |
| 块层状态 | gendisk 还在,容量已是 EOD 或队列已死 |
| 是不是业务 | 不是 |
4.2 活着或半活路径上的介质 / PI 完成错
nvmeXn1: I/O Cmd(0x2) @ LBA ..., 8 blocks, I/O Error (sct 0x2 / sc 0x81) MORE DNR
critical medium error
| 字段 | 规格含义 | 现场解读 |
|---|---|---|
Opcode 0x2 |
Read | 读路径 |
| 8 blocks | 典型 512B×8 = 4KB | 对齐一次页面/一次 scrub 单元 |
| LBA 散落 + 间隔 ~2s | --- | scrub / 巡检 / 用户态扫盘,不是随机业务 |
| SCT=2 SC=81 | 0x281 End-to-end Guard Check(PI/DIF CRC) |
厂商也可能把 0x81 当通用 media error;必须以 Identify 的 dps/ms 核对是否真开了 PI |
| MORE | 后续还有错 | 不要当单点 ECC |
| DNR | Do Not Retry | 固件禁止 host 重试;再打也是同一条错 |
对照样本:
Slot(40): Link Down
nvme3n1: ... (sct 0x3 / sc 0x71) ← 0x371 HOST_ABORTED_CMD
时序:先 0x281 完成,后 Link Down,再 0x371。
掉链不能用来「洗掉」掉链前的 Guard Check。
4.3 最危险的时序:新实例已活,旧 n1 无人释放
| Endpoint | 新绑定 | 旧节点仍在 completion |
|---|---|---|
e1:00.0 |
已是 nvme0 | nvme3n1 仍出 I/O 完成 |
e3:00.0 |
已是 nvme8,128 队列 | nvme5n1 仍报 0x281 |
内核 nvme 驱动在 Surprise remove 时:
- PCI 功能没了 → 分配新的
nvmeX次序号; - 若用户态 / udev / multipath 仍持有旧
/dev/nvmeXn1的打开文件或 gendisk 引用 ,旧节点不会消失,I/O 会继续下到已经无效或半死的请求队列。
谁还握着 /dev/nvme3n1、/dev/nvme5n1(OSD、qemu、multipath、监控、厂商工具),谁就在给死路径喂 I/O,并把固件从「偶发 PI 错」推向「再 reset / 再掉链」。
数据面只认现实例: nvme0n1 / nvme8n1(且 list-ns 非空)。
旧节点只许停、不许修、不许再 blkid。
5. 与 CLR / CSTS=0x1 如何衔接(改口径,不推翻旧事实)
仍成立:
- 两颗问题盘都经历过 Controller Reset 后 RDY 不落 →
-ENODEV。 - 现网没有第二 PF。
nvme8是故障后再枚举、「看起来 Ready」的实例(曾建 128 队列并 rescan NS)。
必须改的口径:
-19与实例空洞,优先用 Slot(40)/Slot(42) Surprise 解释,CLR 卡死是叠加动作的结果。- Slot(40) 两日内反复
enabling device= 链路/热插拔循环,不是单次固件 hang。 - 在循环上打
nvme reset:链路窗口内 admin 超时 → 驱动见CSTS停在0x1→ 放弃设备。
规格对照(便于盘厂对接,无需厂商名):
| 寄存器/状态 | 期望 | 现网 |
|---|---|---|
CC.EN 0→1 或 Controller Reset |
CSTS.RDY 在 CAP.TO 内置 1 |
保持 0x1 或不可读 |
| 设备从 PCI 消失 | 驱动应 teardown 并释放旧 NS | 旧 n1 残留 |
| Identify CMIC | 双口应有多控制器/多口标志 | CMIC=0 |
6. 证据分级(对外时不要把推断写成事实)
| 级别 | 内容 |
|---|---|
| 已坐实 | 三槽 pciehp Surprise;e1:00.0↔nvme0↔旧 nvme3;e3:00.0↔nvme8↔旧 nvme5;无第二 PF;0x281 出现在部分 Link Down 之前;旧 n1 在新 ctrl 存活后仍 completion;CLR 后 RDY 不落曾导致 -ENODEV |
| 高置信推断 | Slot(32) 下游为 81:00.0;4K/~2s 为 scrub/巡检;僵尸 sector 0 为 udev/blkid |
| 待取证 | Slot(32) 下游 BDF 实锤;AER/Uncorrectable 是否伴随;BMC 是否 cycle power;id-ns 的 dps/ms(PI 是否真开);谁持有旧 fd;数据现在在 nvme0n1/nvme8n1 还是空 ctrl |
7. 立即处置(只读 + 止血)
原则:先切断旧节点 I/O,再采集只读信息,全程禁止 reset 与槽位下电。
7.1 止血
lsof /dev/nvme3n1 /dev/nvme5n1 /dev/nvme3 /dev/nvme5 2>/dev/null
lsblk -o NAME,SIZE,TYPE,MOUNTPOINT,PKNAME | grep -E 'nvme[0358]'
multipath -ll 2>/dev/null | grep -A2 -E 'nvme[0358]'
# 若 OSD/文件系统/qemu 仍挂在 nvme3n1、nvme5n1 → 先停业务再卸设备
ls -l /dev/nvme{0,3,5,8}* 2>/dev/null
nvme list
nvme list-ns /dev/nvme0
nvme list-ns /dev/nvme8
判定:
list-ns对 nvme0/nvme8 有 NS 且存在nvme0n1/nvme8n1→ 数据面在新节点,旧节点一律停。- 只有空 ctrl、无
n1→ 不要对旧n1做任何「修复」;先固定链路再谈数据。
7.2 链路 / 槽位 / AER(只读)
ls -l /sys/bus/pci/devices/0000:80:01.1/
find /sys/bus/pci/devices/0000:80:01.1 -name address -o -name devicetype 2>/dev/null | head
ls /sys/bus/pci/slots
for s in /sys/bus/pci/slots/*; do echo "== $s"; cat $s/address $s/power 2>/dev/null; done
for d in 0000:e1:00.0 0000:e3:00.0; do
echo "== $d"
cat /sys/bus/pci/devices/$d/current_link_speed
cat /sys/bus/pci/devices/$d/current_link_width
done
dmesg -T | grep -iE 'AER|PCIe Bus Error|Uncorrectable|e1:00|e3:00|81:00'
核对待外/BMC 是否对上述 slot 做 cycle;不要在此时手动写 slots/*/power
7.3 盘侧只读(禁止 reset / NSSR / FLR)
nvme smart-log /dev/nvme0
nvme smart-log /dev/nvme8
nvme error-log /dev/nvme0 -e 16
nvme error-log /dev/nvme8 -e 16
nvme id-ns /dev/nvme0n1 2>/dev/null | egrep 'nsze|ncap|dps|lbaf|ms '
nvme id-ns /dev/nvme8n1 2>/dev/null | egrep 'nsze|ncap|dps|lbaf|ms '
若 dps/ms 显示 PI 未开 却大量 0x281:固件乱报或内部映射/RAID 损坏,直接作为盘厂缺陷单,而不是「开 PI 后的 CRC」。
禁止: nvme reset、FLR、写 NSSR、echo 0 > slots/*/power。
建议回收给分析侧:nvme list、旧 n1 的 lsof、nvme0/8 的 list-ns、Slot(32) 下游 BDF、id-ns 的 PI 字段、当前 link speed/width。
8. 对外话术(可直接转发)
8.1 平台 / 现场
80:01.1 Slot(32)、e0:03.1 Slot(40)、e0:03.3 Slot(42) 发生 PCIe 热插拔 Surprise:Presence 仍在(Card present),链路未训练(No link),约 30s 后再 Link Up。Slot(40)/(42) 伴随 NVMe Endpoint 反复重新枚举;Slot(40) 在两日内多次 enabling device。请检查:
- U.2 连接器、背板、线序、槽位供电;
- 带外/BMC 是否对上述 slot 做 power 操作(日志中有
Already disabled/Already in powering on state); - MPS 被协商到 512,是否符合该槽位设计。
在链路未稳定前,不要 对槽位软件下电,不要对盘做 Controller Reset / FLR。
8.2 盘厂 / 固件
- 盘 A (现
nvme0@e1:00.0,Slot 40;内核旧名nvme3):掉链前 Read 返回 SCT=2 SC=81(Guard Check)DNR ,随后 Link Down,host 侧 SCT=3 SC=71(HOST_ABORTED_CMD) 。历史 CLR 时CSTS保持0x1,随后-ENODEV。 - 盘 B (现
nvme8@e3:00.0,Slot 42;内核旧名nvme5):IdentifyCMIC=0。同样出现过 CLR 后 RDY 不落;再枚举后能建 128 队列并 rescan NS,但旧nvme5n1仍报0x281。
请书面回复:
- 链路 Surprise(PD 仍在、LTSSM 掉)后
CC.EN/CSTS.RDY的状态机与超时; - Namespace 未启用 PI 时为何完成
0x281Guard Check(或确认内部是否误用该 status); - PCI remove 后残留 NS / 旧块设备上 I/O 的完成与 abort 路径,以及为何 DNR。
9. 后续决策树(避免现场即兴)
链路是否仍在 Surprise 循环?
├─ 是 → 只做物理排查;禁 reset / 禁 slot power;停旧 n1 I/O
└─ 否 → nvme0 / nvme8 是否仍在且 list-ns 非空?
├─ 有 n1 → 业务切到新节点;销毁旧 udev 规则/残留 dm;再观察 smart/error-log
└─ 无 n1 → 不要扫描旧 n1;保留现场,提交盘厂(RDY/NS 残留)+ 平台(槽位)
PI 未开却 0x281?
└─ 是 → 固件缺陷单,不要用「开 PI」去圆
谁还在打开 nvme3n1/nvme5n1?
└─ 有 → 先杀/停该进程,再谈任何「修复」
10. 一句话结论
三条线同时成立:槽位 Surprise 掉链、PCI 重枚举导致 ctrl 号漂移、旧 gendisk 被 udev/巡检继续打 4K 读。
掉链前已有 0x281,CLR 后曾 RDY 不落;双口不成立。
止血是停旧节点、禁 reset、禁槽位下电;根因由平台链路与盘侧 CC/PI 完成路径共同承担。
你在现网遇到过类似的 pciehp Surprise 掉链 + 旧 gendisk 残留的组合吗?当时是怎么定位和止血的?欢迎在评论区分享你的排查思路,一起把这条失败链补得更完整。