Commit 775a9362 authored by Maya Erez's avatar Maya Erez Committed by Chris Ball
Browse files

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: default avatarYaniv Gardi <ygardi@codeaurora.org>
Signed-off-by: default avatarMaya Erez <merez@codeaurora.org>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent b6891679
Loading
Loading
Loading
Loading
+47 −21
Original line number Diff line number Diff line
@@ -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 @@ retry:
			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;
+1 −1
Original line number Diff line number Diff line
@@ -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);
}

+19 −0
Original line number Diff line number Diff line
@@ -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;
+2 −0
Original line number Diff line number Diff line
@@ -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)
+2 −0
Original line number Diff line number Diff line
@@ -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 */
Loading