mmc: fixes for eMMC v4.5 sanitize operation
authorAdrian Hunter <adrian.hunter@intel.com>
Thu, 5 Apr 2012 11:45:48 +0000 (14:45 +0300)
committerBen Hutchings <ben@decadent.org.uk>
Fri, 11 May 2012 12:13:52 +0000 (13:13 +0100)
commit 283028122db37621b124f079ca8eae5b64807ad4 upstream.

eMMC v4.5 sanitize operation erases all copies of unmapped
data.  However trim or erase operations must be used first
to unmap the required sectors.  That was not being done.

Fixes apply to linux 3.2 on.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
drivers/mmc/card/block.c
drivers/mmc/core/core.c

index e15e47d..34416d4 100644 (file)
@@ -799,7 +799,7 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
 {
        struct mmc_blk_data *md = mq->data;
        struct mmc_card *card = md->queue.card;
-       unsigned int from, nr, arg;
+       unsigned int from, nr, arg, trim_arg, erase_arg;
        int err = 0, type = MMC_BLK_SECDISCARD;
 
        if (!(mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))) {
@@ -807,20 +807,26 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
                goto out;
        }
 
+       from = blk_rq_pos(req);
+       nr = blk_rq_sectors(req);
+
        /* The sanitize operation is supported at v4.5 only */
        if (mmc_can_sanitize(card)) {
-               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                               EXT_CSD_SANITIZE_START, 1, 0);
-               goto out;
+               erase_arg = MMC_ERASE_ARG;
+               trim_arg = MMC_TRIM_ARG;
+       } else {
+               erase_arg = MMC_SECURE_ERASE_ARG;
+               trim_arg = MMC_SECURE_TRIM1_ARG;
        }
 
-       from = blk_rq_pos(req);
-       nr = blk_rq_sectors(req);
-
-       if (mmc_can_trim(card) && !mmc_erase_group_aligned(card, from, nr))
-               arg = MMC_SECURE_TRIM1_ARG;
-       else
-               arg = MMC_SECURE_ERASE_ARG;
+       if (mmc_erase_group_aligned(card, from, nr))
+               arg = erase_arg;
+       else if (mmc_can_trim(card))
+               arg = trim_arg;
+       else {
+               err = -EINVAL;
+               goto out;
+       }
 retry:
        if (card->quirks & MMC_QUIRK_INAND_CMD38) {
                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
@@ -830,25 +836,41 @@ retry:
                                 INAND_CMD38_ARG_SECERASE,
                                 0);
                if (err)
-                       goto out;
+                       goto out_retry;
        }
+
        err = mmc_erase(card, from, nr, arg);
-       if (!err && arg == MMC_SECURE_TRIM1_ARG) {
+       if (err == -EIO)
+               goto out_retry;
+       if (err)
+               goto out;
+
+       if (arg == MMC_SECURE_TRIM1_ARG) {
                if (card->quirks & MMC_QUIRK_INAND_CMD38) {
                        err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                                         INAND_CMD38_ARG_EXT_CSD,
                                         INAND_CMD38_ARG_SECTRIM2,
                                         0);
                        if (err)
-                               goto out;
+                               goto out_retry;
                }
+
                err = mmc_erase(card, from, nr, MMC_SECURE_TRIM2_ARG);
+               if (err == -EIO)
+                       goto out_retry;
+               if (err)
+                       goto out;
        }
-out:
-       if (err == -EIO && !mmc_blk_reset(md, card->host, type))
+
+       if (mmc_can_sanitize(card))
+               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                EXT_CSD_SANITIZE_START, 1, 0);
+out_retry:
+       if (err && !mmc_blk_reset(md, card->host, type))
                goto retry;
        if (!err)
                mmc_blk_reset_success(md, type);
+out:
        spin_lock_irq(&md->lock);
        __blk_end_request(req, err, blk_rq_bytes(req));
        spin_unlock_irq(&md->lock);
index c420a9e..411a994 100644 (file)
@@ -1809,6 +1809,8 @@ EXPORT_SYMBOL(mmc_can_discard);
 
 int mmc_can_sanitize(struct mmc_card *card)
 {
+       if (!mmc_can_trim(card) && !mmc_can_erase(card))
+               return 0;
        if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_SANITIZE)
                return 1;
        return 0;