Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: core: Return correct emmc response in case of ioctl error

When a read/write command is sent via ioctl to the kernel,
and the command fails, the actual error response of the emmc
is not sent to the user.

IOCTL read/write tests are carried out using commands
17 (Single BLock Read), 24 (Single Block Write),
18 (Multi Block Read), 25 (Multi Block Write)

The tests are carried out on a 64Gb emmc device. All of these
tests try to access an "out of range" sector address (0x09B2FFFF).

It is seen that without the patch the response received by the user
is not OUT_OF_RANGE error (R1 response 31st bit is not set) as per
JEDEC specification. After applying the patch proper response is seen.
This is because the function returns without copying the response to
the user in case of failure. This patch fixes the issue.

Hence, this memcpy is required whether we get an error response or not.
Therefor it is moved up from the current position up to immediately
after we have called mmc_wait_for_req().

The test code and the output of only the CMD17 is included in the
commit to limit the message length.

CMD17 (Test Code Snippet):
==========================
printf("Forming CMD%d\n", opt_idx);
/* single block read */
cmd.blksz = 512;
cmd.blocks = 1;
cmd.write_flag = 0;
cmd.opcode = 17;
//cmd.arg = atoi(argv[3]);
cmd.arg = 0x09B2FFFF;
/* Expecting response R1B */
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;

memset(data, 0, sizeof(__u8) * 512);
mmc_ioc_cmd_set_data(cmd, data);

printf("Sending CMD%d: ARG[0x%08x]\n", opt_idx, cmd.arg);
if(ioctl(fd, MMC_IOC_CMD, &cmd))
perror("Error");

printf("\nResponse: %08x\n", cmd.response[0]);

CMD17 (Output without patch):
=============================
test@test-LIVA-Z:~$ sudo ./mmc cmd_test /dev/mmcblk0 17
Entering the do_mmc_commands:Device: /dev/mmcblk0 nargs:4
Entering the do_mmc_commands:Device: /dev/mmcblk0 options[17, 0x09B2FFF]
Forming CMD17
Sending CMD17: ARG[0x09b2ffff]
Error: Connection timed out

Response: 00000000
(Incorrect response)

CMD17 (Output with patch):
==========================
test@test-LIVA-Z:~$ sudo ./mmc cmd_test /dev/mmcblk0 17
[sudo] password for test:
Entering the do_mmc_commands:Device: /dev/mmcblk0 nargs:4
Entering the do_mmc_commands:Device: /dev/mmcblk0 options[17, 09B2FFFF]
Forming CMD17
Sending CMD17: ARG[0x09b2ffff]
Error: Connection timed out

Response: 80000900
(Correct OUT_OF_ERROR response as per JEDEC specification)

Signed-off-by: Nishad Kamdar <nishadkamdar@gmail.com>
Reviewed-by: Avri Altman <avri.altman@wdc.com>
Link: https://lore.kernel.org/r/20210824191726.8296-1-nishadkamdar@gmail.com
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Nishad Kamdar and committed by
Ulf Hansson
e72a55f2 45334ee1

+1 -2
+1 -2
drivers/mmc/core/block.c
··· 518 518 return mmc_sanitize(card, idata->ic.cmd_timeout_ms); 519 519 520 520 mmc_wait_for_req(card->host, &mrq); 521 + memcpy(&idata->ic.response, cmd.resp, sizeof(cmd.resp)); 521 522 522 523 if (cmd.error) { 523 524 dev_err(mmc_dev(card->host), "%s: cmd error %d\n", ··· 567 566 */ 568 567 if (idata->ic.postsleep_min_us) 569 568 usleep_range(idata->ic.postsleep_min_us, idata->ic.postsleep_max_us); 570 - 571 - memcpy(&(idata->ic.response), cmd.resp, sizeof(cmd.resp)); 572 569 573 570 if (idata->rpmb || (cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) { 574 571 /*