最近发现嵌入式开发板上,有的SD卡(8G SDHC)可以mount,有的则失败(2G SD)。
仔细看log信息,发现有如下区别:
mount成功时,
mmc0: host does not support reading read-only switch. assuming write-enable.
mmc0: new high speed SDHC card at address e624
mmcblk0: mmc0:e624 SU08G 7.40 GiB
mmcblk0: p1
mmc1: Minimum clock frequency too high for identification mode
VFS: Mounted root (yaffs2 filesystem) on device 31:3.
mount失败时,
mmc0: host does not support reading read-only switch. assuming write-enable.
mmc0: new SD card at address ff24
mmcblk0: mmc0:ff24 SU02G 1.84 GiB
mmcblk0:
mmc1: Minimum clock frequency too high for identification mode
除了容量不一样,卡类型不一样,信息基本上一致,还有一处差异就是:
成功时多了一个p1,貌似识别到了一个分区,失败时没有发现分区信息。
于是,想在源代码中找到打印 mmcblk0: mmc0:xxxx的地方,看看什么情况导致
没有打印p1的。定位还真费了一番功夫:
首先找到了打印"mmc0: host does not support reading read-only switch. assuming write-enable"的地方,
drivers/mmc/core/sd.c的函数mmc_sd_init_card().
501 if (!host->ops->get_ro || host->ops->get_ro(host) < 0) {
502 printk(KERN_WARNING "%s: host does not "
503 "support reading read-only "
504 "switch. assuming write-enable.\n",
505 mmc_hostname(host));
mmc_sd_init_card()是在同文件的 mmc_attach_sd(struct mmc_host *host, u32 ocr)中调用的:
691 err = mmc_sd_init_card(host, host->ocr, NULL);
692 if (err)
693 goto err;
694
695 mmc_release_host(host);
696
697 err = mmc_add_card(host->card);
698 if (err)
699 goto remove_card;
而drivers/mmc/core/bus.c 文件中的mmc_add_card()函数中如下代码,
253 printk(KERN_INFO "%s: new %s%s card at address %04x\n",
254 mmc_hostname(card->host),
255 mmc_card_highspeed(card) ? "high speed " : "",
256 type, card->rca);
正是我们看到的后面的打印信息。即
mmc0: new high speed SDHC card at address e624和
mmc0: new SD card at address ff24
接着往下看,就很难找到下面的打印在哪里输出了。
偶然间发现,drivers/mmc/card/block.c文件中mmc_blk_probe()函数有搜索的打印输出:
614 printk(KERN_INFO "%s: %s %s %s %s\n",
615 md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
616 cap_str, md->read_only ? "(ro)" : "");
正是这个打印输出的
mmcblk0: mmc0:e624 SU08G 7.40 GiB 和
mmcblk0: mmc0:ff24 SU02G 1.84 GiB
本以为目标越来越近了,结果看吧:
drivers/mmc/card/block.c: 函数static int mmc_blk_probe(struct mmc_card *card)
614 printk(KERN_INFO "%s: %s %s %s %s\n",
615 md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
616 cap_str, md->read_only ? "(ro)" : "");
617
618 mmc_set_drvdata(card, md);
619 add_disk(md->disk); //这个函数
block/genhd.c: add_disk()函数中
544 blk_register_region(disk_devt(disk), disk->minors, NULL,
545 exact_match, exact_lock, disk);
546 register_disk(disk); //这个函数
547 blk_register_queue(disk);
fs/partitions/check.c的register_disk()中:
526 bdev->bd_invalidated = 1;
527 err = blkdev_get(bdev, FMODE_READ); //这个函数
528 if (err < 0)
529 goto exit;
fs/block_dev.c 的blkdev_get()调用__blkdev_get(), 而__blkdev_get()中:
1395 if (bdev->bd_invalidated)
1396 rescan_partitions(disk, bdev); //这个函数
fs/partitions/check.c的rescan_partitions()中:
586 bdev->bd_invalidated = 0;
587 if (!get_capacity(disk) || !(state = check_partition(disk, bdev))) //这个check_partition()
588 return 0;
fs/partitions/check.c的check_partition()中:
169 disk_name(hd, 0, state->name);
170 printk(KERN_INFO " %s:", state->name); //这里才打印 "mmcblk0:", p1在哪里输出的?
171 if (isdigit(state->name[strlen(state->name)-1]))
172 sprintf(state->name, "p");
173
174 state->limit = disk_max_parts(hd);
175 i = res = err = 0;
176 while (!res && check_part[i]) {
177 memset(&state->parts, 0, sizeof(state->parts));
178 res = check_part[i++](state); //这里将调用到msdos_partion()
179 if (res < 0) {
180 /* We have hit an I/O error which we don't report now.
181 * But record it, and let the others do their job.
182 */
183 err = res;
184 res = 0;
185 }
186
187 }
fs/partitions/msdos.c 中的msdos_partition()函数中:
432 /*
433 * Now that the 55aa signature is present, this is probably
434 * either the boot sector of a FAT filesystem or a DOS-type
435 * partition table. Reject this in case the boot indicator
436 * is not 0 or 0x80.
437 */
438 p = (struct partition *) (data + 0x1be);
439 for (slot = 1; slot <= 4; slot++, p++) {
440 if (p->boot_ind != 0 && p->boot_ind != 0x80) {
441 /*
442 * Even without a valid boot inidicator value
443 * its still possible this is valid FAT filesystem
444 * without a partition table.
445 */
446 fb = (struct fat_boot_sector *) data;
447 if (slot == 1 && fb->reserved && fb->fats
448 && fat_valid_media(fb->media)) {
449 printk("\n");
450 put_dev_sector(sect);
451 return 1; //对于2G卡,从这里退出,无打印p1
452 } else {
453 put_dev_sector(sect);
454 return 0;
455 }
456 }
457 }
477 state->next = 5;
478 for (slot = 1 ; slot <= 4 ; slot++, p++) {
479 sector_t start = start_sect(p)*sector_size;
480 sector_t size = nr_sects(p)*sector_size;
481 if (!size)
482 continue;
483 if (is_extended_partition(p)) {
484 /*
485 * prevent someone doing mkfs or mkswap on an
486 * extended partition, but leave room for LILO
487 * FIXME: this uses one logical sector for > 512b
488 * sector, although it may not be enough/proper.
489 */
490 sector_t n = 2;
491 n = min(size, max(sector_size, n));
492 put_partition(state, slot, start, n);
493
494 printk(" <");
495 parse_extended(state, start, size);
496 printk(" >");
497 continue;
498 }
499 put_partition(state, slot, start, size);
500 if (SYS_IND(p) == LINUX_RAID_PARTITION)
501 state->parts[slot].flags = ADDPART_FLAG_RAID;
502 if (SYS_IND(p) == DM6_PARTITION)
503 printk("[DM]");
504 if (SYS_IND(p) == EZD_PARTITION)
505 printk("[EZD]");
506 }
对于失败的2G卡,451退出,而mount成功的8G卡,在,会运行到499行,进入put_partition(),
fs/partitions/check.h中的put_partition()函数,打印了p1,如下所示:
31 static inline void
32 put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size)
33 {
34 if (n < p->limit) {
35 p->parts[n].from = from;
36 p->parts[n].size = size;
37 printk(" %s%d", p->name, n); //对于正常卡打印p1
38 }
39 }
原来,对于2G卡,mount 失败的原因就是该SD卡的分区表损坏。在Win7下重新格式化,也没能修复。
在linux下查看分区情况(cat /proc/partitions),正如上面结果所说,
2G卡(异常卡)结果如下:
----------------------------------------
major minor #blocks name
....
179 0 1931264 mmcblk0
---------------------------------------
8G卡(正常卡)结果如下:
----------------------------------------
major minor #blocks name
....
179 0 1931264 mmcblk0
179 1 1930240 mmcblk0p1
---------------------------------------
异常卡没能找到正确的分区,所以mount失败。
尝试在linux(Ubuntu)下用fdisk对异常卡进行分区,fdisk也提示找不到合法分区,有4个异常分区。
删除之,重新分区(FAT16)后,发现在windows下不能识别该卡的新分区,再在Win7下重新格式化,再上
板子上运行,竟然行了,该卡能正常工作了,执行“cat /proc/partitions”, mmcblk0p1有了。