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>
This commit is contained in:
parent
b689167984
commit
775a9362b5
6 changed files with 72 additions and 22 deletions
|
@ -58,6 +58,8 @@ MODULE_ALIAS("mmc:block");
|
|||
#define INAND_CMD38_ARG_SECTRIM1 0x81
|
||||
#define INAND_CMD38_ARG_SECTRIM2 0x88
|
||||
#define MMC_BLK_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
|
||||
#define MMC_SANITIZE_REQ_TIMEOUT 240000
|
||||
#define MMC_EXTRACT_INDEX_FROM_ARG(x) ((x & 0x00FF0000) >> 16)
|
||||
|
||||
#define mmc_req_rel_wr(req) (((req->cmd_flags & REQ_FUA) || \
|
||||
(req->cmd_flags & REQ_META)) && \
|
||||
|
@ -408,6 +410,35 @@ static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int ioctl_do_sanitize(struct mmc_card *card)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!(mmc_can_sanitize(card) &&
|
||||
(card->host->caps2 & MMC_CAP2_SANITIZE))) {
|
||||
pr_warn("%s: %s - SANITIZE is not supported\n",
|
||||
mmc_hostname(card->host), __func__);
|
||||
err = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pr_debug("%s: %s - SANITIZE IN PROGRESS...\n",
|
||||
mmc_hostname(card->host), __func__);
|
||||
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_SANITIZE_START, 1,
|
||||
MMC_SANITIZE_REQ_TIMEOUT);
|
||||
|
||||
if (err)
|
||||
pr_err("%s: %s - EXT_CSD_SANITIZE_START failed. err=%d\n",
|
||||
mmc_hostname(card->host), __func__, err);
|
||||
|
||||
pr_debug("%s: %s - SANITIZE COMPLETED\n", mmc_hostname(card->host),
|
||||
__func__);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mmc_blk_ioctl_cmd(struct block_device *bdev,
|
||||
struct mmc_ioc_cmd __user *ic_ptr)
|
||||
{
|
||||
|
@ -510,6 +541,16 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
|
|||
goto cmd_rel_host;
|
||||
}
|
||||
|
||||
if (MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_SANITIZE_START) {
|
||||
err = ioctl_do_sanitize(card);
|
||||
|
||||
if (err)
|
||||
pr_err("%s: ioctl_do_sanitize() failed. err = %d",
|
||||
__func__, err);
|
||||
|
||||
goto cmd_rel_host;
|
||||
}
|
||||
|
||||
mmc_wait_for_req(card->host, &mrq);
|
||||
|
||||
if (cmd.error) {
|
||||
|
@ -939,10 +980,10 @@ 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, trim_arg, erase_arg;
|
||||
unsigned int from, nr, arg;
|
||||
int err = 0, type = MMC_BLK_SECDISCARD;
|
||||
|
||||
if (!(mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))) {
|
||||
if (!(mmc_can_secure_erase_trim(card))) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
@ -950,23 +991,11 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
|
|||
from = blk_rq_pos(req);
|
||||
nr = blk_rq_sectors(req);
|
||||
|
||||
/* The sanitize operation is supported at v4.5 only */
|
||||
if (mmc_can_sanitize(card)) {
|
||||
erase_arg = MMC_ERASE_ARG;
|
||||
trim_arg = MMC_TRIM_ARG;
|
||||
} else {
|
||||
erase_arg = MMC_SECURE_ERASE_ARG;
|
||||
trim_arg = MMC_SECURE_TRIM1_ARG;
|
||||
}
|
||||
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,
|
||||
|
@ -1002,9 +1031,6 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
|
|||
goto out;
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -173,7 +173,7 @@ static void mmc_queue_setup_discard(struct request_queue *q,
|
|||
/* granularity must not be greater than max. discard */
|
||||
if (card->pref_erase > max_discard)
|
||||
q->limits.discard_granularity = 0;
|
||||
if (mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))
|
||||
if (mmc_can_secure_erase_trim(card))
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q);
|
||||
}
|
||||
|
||||
|
|
|
@ -402,6 +402,7 @@ static int mmc_wait_for_data_req_done(struct mmc_host *host,
|
|||
context_info->is_done_rcv = false;
|
||||
context_info->is_new_req = false;
|
||||
cmd = mrq->cmd;
|
||||
|
||||
if (!cmd->error || !cmd->retries ||
|
||||
mmc_card_removed(host->card)) {
|
||||
err = host->areq->err_check(host->card,
|
||||
|
@ -436,6 +437,24 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
|
|||
wait_for_completion(&mrq->completion);
|
||||
|
||||
cmd = mrq->cmd;
|
||||
|
||||
/*
|
||||
* If host has timed out waiting for the sanitize
|
||||
* to complete, card might be still in programming state
|
||||
* so let's try to bring the card out of programming
|
||||
* state.
|
||||
*/
|
||||
if (cmd->sanitize_busy && cmd->error == -ETIMEDOUT) {
|
||||
if (!mmc_interrupt_hpi(host->card)) {
|
||||
pr_warning("%s: %s: Interrupted sanitize\n",
|
||||
mmc_hostname(host), __func__);
|
||||
cmd->error = 0;
|
||||
break;
|
||||
} else {
|
||||
pr_err("%s: %s: Failed to interrupt sanitize\n",
|
||||
mmc_hostname(host), __func__);
|
||||
}
|
||||
}
|
||||
if (!cmd->error || !cmd->retries ||
|
||||
mmc_card_removed(host->card))
|
||||
break;
|
||||
|
|
|
@ -431,6 +431,8 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
|
|||
|
||||
|
||||
cmd.cmd_timeout_ms = timeout_ms;
|
||||
if (index == EXT_CSD_SANITIZE_START)
|
||||
cmd.sanitize_busy = true;
|
||||
|
||||
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
|
||||
if (err)
|
||||
|
|
|
@ -96,6 +96,8 @@ struct mmc_command {
|
|||
*/
|
||||
|
||||
unsigned int cmd_timeout_ms; /* in milliseconds */
|
||||
/* Set this flag only for blocking sanitize request */
|
||||
bool sanitize_busy;
|
||||
|
||||
struct mmc_data *data; /* data segment associated with cmd */
|
||||
struct mmc_request *mrq; /* associated request */
|
||||
|
|
|
@ -280,6 +280,7 @@ struct mmc_host {
|
|||
#define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \
|
||||
MMC_CAP2_PACKED_WR)
|
||||
#define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14) /* Don't power up before scan */
|
||||
#define MMC_CAP2_SANITIZE (1 << 15) /* Support Sanitize */
|
||||
|
||||
mmc_pm_flag_t pm_caps; /* supported pm features */
|
||||
|
||||
|
|
Loading…
Reference in a new issue