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",然后就没有然后了。
排查步骤一般是这样:
- 检查硬件检测引脚——SD 卡的 CD(Card Detect)引脚有没有正确连接到 SoC?我曾经在一个项目里发现,CD 引脚虚焊,导致内核认为卡一直没插入。
- 确认 MMC 控制器驱动已编译——在
make menuconfig里检查:Device Drivers → MMC/SD/SDIO card support,确保你的控制器驱动(如 dw_mmc、omap_hsmmc、sdhci)被选为y或m。 - 检查设备树(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 平台也有,但少一些。
排查要点:
- USB 主机控制器驱动——EHCI、OHCI、UHCI、xHCI,你的 SoC 用的是哪种?在
dmesg里搜ehci或xhci,确认控制器被识别。我见过一个 case,内核编译时忘了选USB_EHCI_HCD,结果 USB 口完全没电。 - USB 存储驱动——
USB Mass Storage support(CONFIG_USB_STORAGE)必须开启。这个驱动负责把 USB 协议翻译成 SCSI 命令。 - 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 知识体系总览
下面这张图总结了四种存储设备驱动的排查路径,我平时排查问题时基本就按这个思路走:
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 |
cat /proc/mtd |
列出 MTD 设备(NAND/NOR) | dev: size erasesize name |
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 挂载问题就解决了一半。接下来才是文件系统本身的事——但那是后面章节的内容了。