mmc-utils: Add General command CMD56 read support
We can use GEN_CMD (CMD56) to read a data block with vendor-specific format and meaning, which is very helpful and useful for customers to analyze device health. This patch is to add support for this command. At the same time, in order to make CMD56 universal, let more users of mmc-utils can benefit from this. We will allow the user to enter [arg] for special commands. Because some eMMC vendors provide an additional set of commands beyond the GEN_CMD (CMD56) definition in the JEDEC specification. These additional commands are implemented using generic CMD56 commands, and they return a wealth of useful information about the state of the NAND device. For these special purposes, the [31:1]stuff bits in the CMD56 argument are used. You can refer to Micron eMMC "TN-FC-32: e·MMC Device Health Report" as an example. I didn't add data parsing, just print the raw data as it is vendor-specific. Signed-off-by: Bean Huo <beanhuo@micron.com> Acked-by: Avri Altman <Avri.Altman@wdc.com> Tested-by: Rossler Jakob (Nokia - DE/Ulm) <jakob.rossler@nokia.com> Link: https://lore.kernel.org/r/20220417111622.621650-1-huobean@gmail.com Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
This commit is contained in:
1 parent
0d493fb091
commit
b7e4d5a6ae
4 files changed
+68
No files matched your search
@@ -237,6 +237,14 @@ static struct Command commands[] = {
|
||||
"secure-trim1 | secure-trim2 | trim \n",
|
||||
NULL
|
||||
},
|
||||
{ do_general_cmd_read, -1,
|
||||
"gen_cmd read", "<device> [arg]\n"
|
||||
"Send GEN_CMD (CMD56) to read vendor-specific format/meaning data from <device>\n\n"
|
||||
"NOTE!: [arg] is optional and defaults to 0x1. If [arg] is specified, then [arg]\n"
|
||||
"must be a 32-bit hexadecimal number, prefixed with 0x/0X. And bit0 in [arg] must\n"
|
||||
"be 1.",
|
||||
NULL
|
||||
},
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
[1] Discard Enable
|
||||
[0] Identify Write Blocks for
|
||||
Erase (or TRIM Enable) R1b */
|
||||
#define MMC_GEN_CMD 56 /* adtc [31:1] stuff bits.
|
||||
[0]: RD/WR1 R1 */
|
||||
|
||||
#define R1_OUT_OF_RANGE (1 << 31) /* er, c */
|
||||
#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */
|
||||
|
||||
+57
@@ -2981,3 +2981,60 @@ out:
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
int do_general_cmd_read(int nargs, char **argv)
|
||||
{
|
||||
int dev_fd;
|
||||
char *device;
|
||||
char *endptr;
|
||||
__u8 buf[512];
|
||||
__u32 arg = 0x01;
|
||||
int ret = -EINVAL, i;
|
||||
struct mmc_ioc_cmd idata;
|
||||
|
||||
if (nargs != 2 && nargs != 3) {
|
||||
fprintf(stderr, "Usage: gen_cmd read </path/to/mmcblkX> [arg]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
device = argv[1];
|
||||
dev_fd = open(device, O_RDWR);
|
||||
if (dev_fd < 0) {
|
||||
perror("device open failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* arg is specified */
|
||||
if (nargs == 3) {
|
||||
arg = strtol(argv[2], &endptr, 16);
|
||||
if (errno != 0 || *endptr != '\0' || !(arg & 0x1)) {
|
||||
fprintf(stderr, "Wrong ARG, it should be Hex number and bit0 must be 1\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&idata, 0, sizeof(idata));
|
||||
idata.write_flag = 0;
|
||||
idata.opcode = MMC_GEN_CMD;
|
||||
idata.arg = arg;
|
||||
idata.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
|
||||
idata.blksz = 512;
|
||||
idata.blocks = 1;
|
||||
mmc_ioc_cmd_set_data(idata, buf);
|
||||
|
||||
ret = ioctl(dev_fd, MMC_IOC_CMD, &idata);
|
||||
if (ret) {
|
||||
perror("ioctl");
|
||||
goto out;
|
||||
}
|
||||
|
||||
printf("Data:\n");
|
||||
for (i = 0; i < 512; i++) {
|
||||
printf("%2x ", buf[i]);
|
||||
if ((i + 1) % 16 == 0)
|
||||
printf("\n");
|
||||
}
|
||||
out:
|
||||
close(dev_fd);
|
||||
return ret;
|
||||
}
|
||||
@@ -46,3 +46,4 @@ int do_read_scr(int argc, char **argv);
|
||||
int do_read_cid(int argc, char **argv);
|
||||
int do_read_csd(int argc, char **argv);
|
||||
int do_erase(int nargs, char **argv);
|
||||
int do_general_cmd_read(int nargs, char **argv);
|
||||
Reference in new issue
Block a user