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 | ||
