diff options
author | Maya Erez <merez@codeaurora.org> | 2013-04-18 08:41:55 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2013-05-26 14:23:13 -0400 |
commit | 775a9362b5d7e006ff6bbec5cb9c9c9d5a751696 (patch) | |
tree | 78d66b7a04b5e339c2e0faa24290f72eb8f8bae4 /drivers/mmc/card | |
parent | b689167984bc14ed06c8bcff52ef5eb1fd9cf83b (diff) |
mmc: card: Adding support for sanitize in eMMC 4.5
The sanitize support is added as a user-app ioctl call, and
was removed from the block-device request, since its purpose is
to be invoked not via File-System but by a user.
This feature deletes the unmap memory region of the eMMC card,
by writing to a specific register in the EXT_CSD.
unmap region is the memory region that was previously deleted
(by erase, trim or discard operation).
In order to avoid timeout when sanitizing large-scale cards,
the timeout for sanitize operation is 240 seconds.
Signed-off-by: Yaniv Gardi <ygardi@codeaurora.org>
Signed-off-by: Maya Erez <merez@codeaurora.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/card')
-rw-r--r-- | drivers/mmc/card/block.c | 68 | ||||
-rw-r--r-- | drivers/mmc/card/queue.c | 2 |
2 files changed, 48 insertions, 22 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index dd27b0783d52..80b05b280241 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c | |||
@@ -58,6 +58,8 @@ MODULE_ALIAS("mmc:block"); | |||
58 | #define INAND_CMD38_ARG_SECTRIM1 0x81 | 58 | #define INAND_CMD38_ARG_SECTRIM1 0x81 |
59 | #define INAND_CMD38_ARG_SECTRIM2 0x88 | 59 | #define INAND_CMD38_ARG_SECTRIM2 0x88 |
60 | #define MMC_BLK_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */ | 60 | #define MMC_BLK_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */ |
61 | #define MMC_SANITIZE_REQ_TIMEOUT 240000 | ||
62 | #define MMC_EXTRACT_INDEX_FROM_ARG(x) ((x & 0x00FF0000) >> 16) | ||
61 | 63 | ||
62 | #define mmc_req_rel_wr(req) (((req->cmd_flags & REQ_FUA) || \ | 64 | #define mmc_req_rel_wr(req) (((req->cmd_flags & REQ_FUA) || \ |
63 | (req->cmd_flags & REQ_META)) && \ | 65 | (req->cmd_flags & REQ_META)) && \ |
@@ -408,6 +410,35 @@ static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status, | |||
408 | return err; | 410 | return err; |
409 | } | 411 | } |
410 | 412 | ||
413 | static int ioctl_do_sanitize(struct mmc_card *card) | ||
414 | { | ||
415 | int err; | ||
416 | |||
417 | if (!(mmc_can_sanitize(card) && | ||
418 | (card->host->caps2 & MMC_CAP2_SANITIZE))) { | ||
419 | pr_warn("%s: %s - SANITIZE is not supported\n", | ||
420 | mmc_hostname(card->host), __func__); | ||
421 | err = -EOPNOTSUPP; | ||
422 | goto out; | ||
423 | } | ||
424 | |||
425 | pr_debug("%s: %s - SANITIZE IN PROGRESS...\n", | ||
426 | mmc_hostname(card->host), __func__); | ||
427 | |||
428 | err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | ||
429 | EXT_CSD_SANITIZE_START, 1, | ||
430 | MMC_SANITIZE_REQ_TIMEOUT); | ||
431 | |||
432 | if (err) | ||
433 | pr_err("%s: %s - EXT_CSD_SANITIZE_START failed. err=%d\n", | ||
434 | mmc_hostname(card->host), __func__, err); | ||
435 | |||
436 | pr_debug("%s: %s - SANITIZE COMPLETED\n", mmc_hostname(card->host), | ||
437 | __func__); | ||
438 | out: | ||
439 | return err; | ||
440 | } | ||
441 | |||
411 | static int mmc_blk_ioctl_cmd(struct block_device *bdev, | 442 | static int mmc_blk_ioctl_cmd(struct block_device *bdev, |
412 | struct mmc_ioc_cmd __user *ic_ptr) | 443 | struct mmc_ioc_cmd __user *ic_ptr) |
413 | { | 444 | { |
@@ -510,6 +541,16 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, | |||
510 | goto cmd_rel_host; | 541 | goto cmd_rel_host; |
511 | } | 542 | } |
512 | 543 | ||
544 | if (MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_SANITIZE_START) { | ||
545 | err = ioctl_do_sanitize(card); | ||
546 | |||
547 | if (err) | ||
548 | pr_err("%s: ioctl_do_sanitize() failed. err = %d", | ||
549 | __func__, err); | ||
550 | |||
551 | goto cmd_rel_host; | ||
552 | } | ||
553 | |||
513 | mmc_wait_for_req(card->host, &mrq); | 554 | mmc_wait_for_req(card->host, &mrq); |
514 | 555 | ||
515 | if (cmd.error) { | 556 | if (cmd.error) { |
@@ -939,10 +980,10 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, | |||
939 | { | 980 | { |
940 | struct mmc_blk_data *md = mq->data; | 981 | struct mmc_blk_data *md = mq->data; |
941 | struct mmc_card *card = md->queue.card; | 982 | struct mmc_card *card = md->queue.card; |
942 | unsigned int from, nr, arg, trim_arg, erase_arg; | 983 | unsigned int from, nr, arg; |
943 | int err = 0, type = MMC_BLK_SECDISCARD; | 984 | int err = 0, type = MMC_BLK_SECDISCARD; |
944 | 985 | ||
945 | if (!(mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))) { | 986 | if (!(mmc_can_secure_erase_trim(card))) { |
946 | err = -EOPNOTSUPP; | 987 | err = -EOPNOTSUPP; |
947 | goto out; | 988 | goto out; |
948 | } | 989 | } |
@@ -950,23 +991,11 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, | |||
950 | from = blk_rq_pos(req); | 991 | from = blk_rq_pos(req); |
951 | nr = blk_rq_sectors(req); | 992 | nr = blk_rq_sectors(req); |
952 | 993 | ||
953 | /* The sanitize operation is supported at v4.5 only */ | 994 | if (mmc_can_trim(card) && !mmc_erase_group_aligned(card, from, nr)) |
954 | if (mmc_can_sanitize(card)) { | 995 | arg = MMC_SECURE_TRIM1_ARG; |
955 | erase_arg = MMC_ERASE_ARG; | 996 | else |
956 | trim_arg = MMC_TRIM_ARG; | 997 | arg = MMC_SECURE_ERASE_ARG; |
957 | } else { | ||
958 | erase_arg = MMC_SECURE_ERASE_ARG; | ||
959 | trim_arg = MMC_SECURE_TRIM1_ARG; | ||
960 | } | ||
961 | 998 | ||
962 | if (mmc_erase_group_aligned(card, from, nr)) | ||
963 | arg = erase_arg; | ||
964 | else if (mmc_can_trim(card)) | ||
965 | arg = trim_arg; | ||
966 | else { | ||
967 | err = -EINVAL; | ||
968 | goto out; | ||
969 | } | ||
970 | retry: | 999 | retry: |
971 | if (card->quirks & MMC_QUIRK_INAND_CMD38) { | 1000 | if (card->quirks & MMC_QUIRK_INAND_CMD38) { |
972 | err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | 1001 | err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, |
@@ -1002,9 +1031,6 @@ retry: | |||
1002 | goto out; | 1031 | goto out; |
1003 | } | 1032 | } |
1004 | 1033 | ||
1005 | if (mmc_can_sanitize(card)) | ||
1006 | err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | ||
1007 | EXT_CSD_SANITIZE_START, 1, 0); | ||
1008 | out_retry: | 1034 | out_retry: |
1009 | if (err && !mmc_blk_reset(md, card->host, type)) | 1035 | if (err && !mmc_blk_reset(md, card->host, type)) |
1010 | goto retry; | 1036 | goto retry; |
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index 9447a0e970d1..fa9632eb63f1 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c | |||
@@ -173,7 +173,7 @@ static void mmc_queue_setup_discard(struct request_queue *q, | |||
173 | /* granularity must not be greater than max. discard */ | 173 | /* granularity must not be greater than max. discard */ |
174 | if (card->pref_erase > max_discard) | 174 | if (card->pref_erase > max_discard) |
175 | q->limits.discard_granularity = 0; | 175 | q->limits.discard_granularity = 0; |
176 | if (mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card)) | 176 | if (mmc_can_secure_erase_trim(card)) |
177 | queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q); | 177 | queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q); |
178 | } | 178 | } |
179 | 179 | ||