4. 存储设备驱动确认:MMC/SD驱动、NAND/NOR驱动、USB存储驱动、SATA驱动

rootfs 挂载失败,很多时候不是文件系统本身坏了,而是内核压根没认出你的存储设备。说白了,驱动没加载上,设备节点没生成,VFS 自然找不到地方挂。

我排查这类问题有个习惯——先问自己三个问题:设备注册了吗?分区表识别了吗?设备节点创建了吗? 这三个问题对应着驱动加载的三个阶段。下面我们逐个存储类型来拆解。

核心思路: 无论哪种存储介质,最终都要在 /dev/ 下看到对应的块设备节点,并且能通过 cat /proc/partitions 确认分区存在。否则 rootfs 挂载就是空中楼阁。

4.1 MMC/SD 卡驱动确认

MMC/SD 卡是嵌入式设备上最常见的 rootfs 载体。我遇到过好几次,板子启动后内核打印 "mmc0: error -110 whilst initialising SD card",然后就没有然后了。

排查步骤一般是这样:

  1. 检查硬件检测引脚——SD 卡的 CD(Card Detect)引脚有没有正确连接到 SoC?我曾经在一个项目里发现,CD 引脚虚焊,导致内核认为卡一直没插入。
  2. 确认 MMC 控制器驱动已编译——在 make menuconfig 里检查:Device Drivers → MMC/SD/SDIO card support,确保你的控制器驱动(如 dw_mmc、omap_hsmmc、sdhci)被选为 y 或 m。
  3. 检查设备树(DTS)——MMC 节点里的 bus-width、non-removable、cap-sd-highspeed 这些属性对不对。我见过有人把 bus-width = <4> 写成了 <8>,结果 4 线卡死活初始化失败。

小技巧: 启动时加 mmc_debug=1 内核参数,能看到 MMC 子系统的详细调试信息。如果看到 mmc0: new high speed SD card at address 1234,说明驱动层已经通了。

确认驱动正常后,/dev/mmcblk0 应该出现。用 fdisk -l /dev/mmcblk0 看看分区表,如果显示 "doesn't contain a valid partition table",那可能是分区表损坏或者引导程序没写对。

4.2 NAND/NOR Flash 驱动确认

NAND/NOR 的情况比 MMC 复杂一些,因为它不是标准的块设备,而是通过 MTD 子系统来管理的。rootfs 通常以 UBI/UBIFS 或 JFFS2 的形式放在上面。

我个人的排查流程:

  • 第一步:确认 MTD 驱动加载——cat /proc/mtd 能看到 dev: size erasesize name 列表。如果这个文件是空的,说明 NAND 控制器驱动没工作。
  • 第二步:检查 NAND 控制器驱动——常见的有 gpmi-nand、omap2-nand、sunxi-nand。在 dmesg 里搜 "NAND" 或 "nand",看有没有 NAND device: Manufacturer ID: 0x2c, Chip ID: 0xdc (Micron NAND 512MiB 3,3V 8-bit) 这样的信息。
  • 第三步:确认分区表——MTD 分区通常在设备树里定义,或者在 board 文件里硬编码。用 cat /proc/mtd 看到的分区名应该和你的设计一致。比如:mtd0: bootloader、mtd1: kernel、mtd2: rootfs。

注意: NAND Flash 有坏块问题。如果驱动没有正确实现坏块管理,或者你用的文件系统(如 JFFS2)不支持坏块跳过,rootfs 挂载会随机失败。我曾经在一个项目里被这个问题折腾了两天——同一批板子,有的能启动,有的不行,最后发现是 NAND 驱动里的 nand_scan() 没有使能 ECC。

对于 UBI/UBIFS 的情况,还需要确认 ubiattach 是否成功:

# 查看 UBI 设备
cat /sys/class/ubi/ubi0/volumes_count
# 或者
ubiinfo /dev/ubi0

如果 ubiattach 失败,常见原因是 VID header offset 或 logical eraseblock size 不匹配。嗯,这里要注意,不同厂家的 NAND 芯片,页大小和 OOB 大小可能不同,UBI 的配置必须跟着变。

4.3 USB 存储驱动确认

USB 存储设备(U 盘、USB 硬盘)作为 rootfs 载体,在 x86 工控机上很常见。ARM 平台也有,但少一些。

排查要点:

  1. USB 主机控制器驱动——EHCI、OHCI、UHCI、xHCI,你的 SoC 用的是哪种?在 dmesg 里搜 ehci 或 xhci,确认控制器被识别。我见过一个 case,内核编译时忘了选 USB_EHCI_HCD,结果 USB 口完全没电。
  2. USB 存储驱动——USB Mass Storage support(CONFIG_USB_STORAGE)必须开启。这个驱动负责把 USB 协议翻译成 SCSI 命令。
  3. SCSI 磁盘驱动——CONFIG_BLK_DEV_SD 要选上。USB 存储设备在内核里被模拟成 SCSI 磁盘,所以 /dev/sda 的出现依赖 SCSI 磁盘驱动。

启动后,用 lsusb 看 USB 设备列表:

Bus 001 Device 002: ID 0781:5583 SanDisk Corp. Ultra Fit
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

如果能看到你的 U 盘,但 /dev/sda 没出现,那问题大概率在 SCSI 层。检查 dmesg 里有没有 sd 0:0:0:0: [sda] No Caching mode page found 之类的警告。

个人经验: USB 存储作为 rootfs 时,有个坑是 USB 初始化比内核挂载 rootfs 慢。你需要在内核命令行里加 rootdelay=5,给 USB 子系统几秒钟时间来完成枚举。否则内核会报 VFS: Cannot open root device "sda1"。

4.4 SATA 驱动确认

SATA 硬盘在嵌入式里用得相对少,主要出现在高性能 ARM 服务器或 x86 平台上。但一旦用了,问题往往出在 AHCI 驱动上。

排查清单:

  • AHCI 控制器驱动——CONFIG_SATA_AHCI 或 CONFIG_SATA_AHCI_PLATFORM。在 dmesg 里搜 ahci,应该看到 ahci 0000:00:1f.2: AHCI 0001.0300 32 slots 6 ports 6 Gbps 0x3f impl SATA mode。
  • 设备树或 ACPI 表——SATA 控制器的寄存器基地址、中断号、时钟信息必须正确。我调试过一个 i.MX8 平台,SATA 死活不认盘,最后发现是设备树里 clocks 属性少了一个 reference clock。
  • SATA 链路训练——如果硬盘物理连接没问题,但 dmesg 里反复出现 ata1: SATA link down (SStatus 0 SControl 300),那可能是信号质量问题,或者 SATA 线缆太长。

确认驱动正常后,/dev/sda 会出现。用 hdparm -I /dev/sda 可以查看硬盘的详细信息,包括支持的传输模式。

4.5 知识体系总览

下面这张图总结了四种存储设备驱动的排查路径,我平时排查问题时基本就按这个思路走:

存储设备驱动排查路径总览 存储设备驱动排查路径总览 存储设备驱动 MMC/SD 卡 NAND/NOR Flash USB 存储 SATA 硬盘 排查要点 • CD 引脚检测 • MMC 控制器驱动 • 设备树 bus-width • /dev/mmcblk0 节点 排查要点 • /proc/mtd 列表 • NAND 控制器驱动 • MTD 分区表 • UBI/UBIFS 状态 排查要点 • USB 主机控制器 • USB Mass Storage • SCSI 磁盘驱动 • rootdelay 参数 排查要点 • AHCI 驱动 • 设备树/ACPI 表 • SATA 链路训练 • /dev/sda 节点 最终目标:/dev/ 下出现块设备节点,/proc/partitions 分区可见

4.6 通用排查命令速查表

不管你用哪种存储介质,下面这几个命令是排查驱动问题的利器。我每次接手一个新板子,都会先跑一遍:

命令 作用 预期输出示例
dmesg | grep -i "mmc\|nand\|usb\|ata\|sd\|sata" 查看存储相关内核日志 mmc0: new high speed SD card at address 1234
cat /proc/partitions 列出所有块设备分区 major minor #blocks name
179 0 30720 mmcblk0
cat /proc/mtd 列出 MTD 设备(NAND/NOR) dev: size erasesize name
mtd0: 00100000 00020000 "bootloader"
ls -l /dev/sd* /dev/mmcblk* /dev/mtd* 确认设备节点存在 brw-rw---- 1 root disk 179, 0 ... /dev/mmcblk0
lsusb 列出 USB 设备(USB 存储) Bus 001 Device 002: ID 0781:5583 SanDisk

重要提醒: 如果以上命令都看不到你的存储设备,先别急着怀疑文件系统。回头检查硬件原理图——供电、时钟、复位、数据线有没有接对。我见过最离谱的一次,是硬件工程师把 SD 卡的数据线 D0 和 D1 接反了,内核报了一堆 CRC 错误,折腾了三天才发现。

驱动确认这一步走通了,rootfs 挂载问题就解决了一半。接下来才是文件系统本身的事——但那是后面章节的内容了。