mmc: Add MMC_QUIRK_ERASE_BROKEN for some cards
authorPhil Elwell <phil@raspberrypi.org>
Wed, 11 May 2016 11:50:33 +0000 (12:50 +0100)
committerpopcornmix <popcornmix@gmail.com>
Mon, 20 Feb 2017 12:17:52 +0000 (12:17 +0000)
Some SD cards have been found that corrupt data when small blocks
are erased. Add a quirk to indicate that ERASE should not be used,
and set it for cards of that type.

Signed-off-by: Phil Elwell <phil@raspberrypi.org>
mmc: Apply QUIRK_BROKEN_ERASE to other capacities

Signed-off-by: Phil Elwell <phil@raspberrypi.org>
mmc: Add card_quirks module parameter, log quirks

Use mmc_block.card_quirks to override the quirks for all SD or MMC
cards. The value is a bitfield using the bit positions defined in
include/linux/mmc/card.h. If the module parameter is placed in the
kernel command line (or bootargs) stored on the card then, assuming the
device only has one SD card interface, the override effectively becomes
card-specific.

Signed-off-by: Phil Elwell <phil@raspberrypi.org>
drivers/mmc/card/block.c
drivers/mmc/core/core.c
include/linux/mmc/card.h

index 709a872ed484a9da1ce620238c3222190c612f86..894c105be9ce7f83147a62c433c787b90a5e7c17 100644 (file)
@@ -135,6 +135,13 @@ enum {
 module_param(perdev_minors, int, 0444);
 MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
 
+/*
+ * Allow quirks to be overridden for the current card
+ */
+static char *card_quirks;
+module_param(card_quirks, charp, 0644);
+MODULE_PARM_DESC(card_quirks, "Force the use of the indicated quirks (a bitfield)");
+
 static inline int mmc_blk_part_switch(struct mmc_card *card,
                                      struct mmc_blk_data *md);
 static int get_card_status(struct mmc_card *card, u32 *status, int retries);
@@ -2573,6 +2580,17 @@ static const struct mmc_fixup blk_fixups[] =
        MMC_FIXUP("V10016", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc,
                  MMC_QUIRK_TRIM_BROKEN),
 
+       /*
+        *  On some Kingston SD cards, multiple erases of less than 64
+        *  sectors can cause corruption.
+        */
+       MMC_FIXUP("SD16G", 0x41, 0x3432, add_quirk_mmc,
+                 MMC_QUIRK_ERASE_BROKEN),
+       MMC_FIXUP("SD32G", 0x41, 0x3432, add_quirk_mmc,
+                 MMC_QUIRK_ERASE_BROKEN),
+       MMC_FIXUP("SD64G", 0x41, 0x3432, add_quirk_mmc,
+                 MMC_QUIRK_ERASE_BROKEN),
+
        END_FIXUP
 };
 
@@ -2580,6 +2598,7 @@ static int mmc_blk_probe(struct mmc_card *card)
 {
        struct mmc_blk_data *md, *part_md;
        char cap_str[10];
+       char quirk_str[24];
 
        /*
         * Check that the card supports the command class(es) we need.
@@ -2587,7 +2606,16 @@ static int mmc_blk_probe(struct mmc_card *card)
        if (!(card->csd.cmdclass & CCC_BLOCK_READ))
                return -ENODEV;
 
-       mmc_fixup_device(card, blk_fixups);
+       if (card_quirks) {
+               unsigned long quirks;
+               if (kstrtoul(card_quirks, 0, &quirks) == 0)
+                       card->quirks = (unsigned int)quirks;
+               else
+                       pr_err("mmc_block: Invalid card_quirks parameter '%s'\n",
+                              card_quirks);
+       }
+       else
+               mmc_fixup_device(card, blk_fixups);
 
        md = mmc_blk_alloc(card);
        if (IS_ERR(md))
@@ -2595,9 +2623,14 @@ static int mmc_blk_probe(struct mmc_card *card)
 
        string_get_size((u64)get_capacity(md->disk), 512, STRING_UNITS_2,
                        cap_str, sizeof(cap_str));
-       pr_info("%s: %s %s %s %s\n",
+       if (card->quirks)
+               snprintf(quirk_str, sizeof(quirk_str),
+                        " (quirks 0x%08x)", card->quirks);
+       else
+               quirk_str[0] = '\0';
+       pr_info("%s: %s %s %s%s%s\n",
                md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
-               cap_str, md->read_only ? "(ro)" : "");
+               cap_str, md->read_only ? " (ro)" : "", quirk_str);
 
        if (mmc_blk_alloc_parts(card, md))
                goto out;
index 2553d903a82b9eaa8577c1269bc9f63e18b00085..59a4044ea4c2e1283b1cad8afc7e67efaf8653fb 100644 (file)
@@ -2409,7 +2409,8 @@ EXPORT_SYMBOL(mmc_erase);
 int mmc_can_erase(struct mmc_card *card)
 {
        if ((card->host->caps & MMC_CAP_ERASE) &&
-           (card->csd.cmdclass & CCC_ERASE) && card->erase_size)
+           (card->csd.cmdclass & CCC_ERASE) && card->erase_size &&
+           !(card->quirks & MMC_QUIRK_ERASE_BROKEN))
                return 1;
        return 0;
 }
index 73fad83acbcb6a157587180516f9ffe7c61eb7d7..e7c9d3098ac06e3c6554fa3373a311f937cd6f96 100644 (file)
@@ -283,6 +283,9 @@ struct mmc_card {
 #define MMC_QUIRK_BROKEN_HPI   (1<<13)         /* Disable broken HPI support */
 
 
+#define MMC_QUIRK_ERASE_BROKEN (1<<31)         /* Skip erase */
+
+
        unsigned int            erase_size;     /* erase size in sectors */
        unsigned int            erase_shift;    /* if erase unit is power 2 */
        unsigned int            pref_erase;     /* in sectors */