diff mbox series

[6/7] mmc-utils: discrete commands for enhanced and extended attribute setting

Message ID 0d4f799fa7347b6733a263ef83cbcd8c1bdd2cfe.1539103468.git.jamesnuss@nanometrics.ca (mailing list archive)
State New, archived
Headers show
Series fix bugs in write_reliability and enh_area set commands + more extcsd parsing | expand

Commit Message

James Nuss Oct. 9, 2018, 5:31 p.m. UTC
The enhanced and extended attributes must be set on all required partitions
in a single command instead of one command per partition.

Remove the enhanced and extended attribute setting parameters from the
"gp create" and "enh_area set" commands and create new commands:
* "enh_area set_partitions"
* "enh_area set_user_data"
* "gp set_extended"

Signed-off-by: James Nuss <jamesnuss@nanometrics.ca>
---
 mmc.c      |  42 ++++++++++++---
 mmc_cmds.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++---------------
 mmc_cmds.h |   4 +-
 3 files changed, 167 insertions(+), 48 deletions(-)
diff mbox series

Patch

diff --git a/mmc.c b/mmc.c
index 655546b..f2c714c 100644
--- a/mmc.c
+++ b/mmc.c
@@ -87,14 +87,42 @@  static struct Command commands[] = {
 		"Set the eMMC data sector size to 4KB by disabling emulation on\n<device>.",
 	  NULL
 	},
-	{ do_create_gp_partition, -6,
-	  "gp create", "<-y|-n|-c> " "<length KiB> " "<partition> " "<enh_attr> " "<ext_attr> " "<device>\n"
-		"Create general purpose partition for the <device>.\nDry-run only unless -y or -c is passed.\nUse -c if more partitioning settings are still to come.\nNOTE!  This is a one-time programmable (unreversible) change.\nTo set enhanced attribute to general partition being created set\n <enh_attr> to 1 else set it to 0.\nTo set extended attribute to general partition\n set <ext_attr> to 1,2 else set it to 0",
+	{ do_create_gp_partition, 4,
+	  "gp create", "<-y|-n|-c> " "<length KiB> " "<partition> " "<device>\n"
+		"Create general purpose partition for the <device>.\n"
+		"Dry-run only unless -y or -c is passed.\n"
+		"Use -c if more partitioning settings are still to come.\n"
+		"NOTE!  This is a one-time programmable (unreversible) change.",
 	  NULL
 	},
-	{ do_enh_area_set, -4,
-	  "enh_area set", "<-y|-n|-c> " "<start KiB> " "<length KiB> " "<device>\n"
-		"Enable the enhanced user area for the <device>.\nDry-run only unless -y or -c is passed.\nUse -c if more partitioning settings are still to come.\nNOTE!  This is a one-time programmable (unreversible) change.",
+	{ do_gp_set_extended, 3,
+	  "gp set_extended", "<-y|-n|-c> " "<partition-mask> " "<device>\n"
+		"Set extended attribute on specified general purpose partitions for the <device>.\n"
+		"GP4=bit[15:12], GP3=bit[11:8], GP2=bit[7:4], GP1=bit[3:0]\n"   
+		"e.g setting <partition-mask> to 0x0120 will set extended attribute 0x02 on 'GP2'\n"
+		"  partition and extended attribute 0x01 on 'GP3' partition\n"
+		"Dry-run only unless -y or -c is passed.\n"
+		"Use -c if more partitioning settings are still to come.\n"
+		"NOTE!  This is a one-time programmable (unreversible) change.",
+	  NULL
+	},
+	{ do_enh_area_set_user_data, -4,
+	  "enh_area set_user_data", "<-y|-n|-c> " "<start KiB> " "<length KiB> " "<device>\n"
+		"Set the size and offset of the enhanced user data area for the <device>.\n"
+		"Dry-run only unless -y or -c is passed.\n"
+		"Use -c if more partitioning settings are still to come.\n"
+		"NOTE!  This is a one-time programmable (unreversible) change.",
+	  NULL
+	},
+	{ do_enh_area_set_partitions, 3,
+	  "enh_area set_partitions", "<-y|-n|-c> " "<partition-mask> " "<device>\n"
+		"Enable enhanced attribute on specified partitions for the <device>.\n"
+		"User area=bit[0], GP1=bit[1], GP2=bit[2], GP3=bit[3], GP4=bit[4]\n"
+		"e.g setting <partition-mask> to 0x03 will set 'User Area' and 'GP1' partitions \n"
+		"    with enhanced attribute, and all others without enhanced attribute.\n"
+		"Dry-run only unless -y or -c is passed.\n"
+		"Use -c if more partitioning settings are still to come.\n"
+		"NOTE!  This is a one-time programmable (unreversible) change.",
 	  NULL
 	},
 	{ do_write_reliability_set_register, -2,
@@ -102,7 +130,7 @@  static struct Command commands[] = {
 		"Set the write-reliability register (WR_REL_SET) for the <device>.\n"
 		"User area=bit0, GP1=bit1, GP2=bit2, GP3=bit3, GP4=bit4\n"
 		"e.g setting register to 0x03 will set 'User Area' and 'GP1' partitions \n"
-		"with write-reliability, and all others without write-reliability.\n"
+		"    with write-reliability, and all others without write-reliability.\n"
 		"NOTE!  This is a one-time programmable (irreversible) change.",
 	  NULL
 	},
diff --git a/mmc_cmds.c b/mmc_cmds.c
index 9565bc9..793b7fa 100644
--- a/mmc_cmds.c
+++ b/mmc_cmds.c
@@ -967,6 +967,81 @@  int check_enhanced_area_total_limit(const char * const device, int fd)
 	return 0;
 }
 
+// TODO: check if enhanced attributes set on GP partitions (only allowed either enhanced or extended attribute)
+int do_gp_set_extended(int nargs, char **argv)
+{
+	__u8 value;
+	__u8 ext_csd[512];
+	__u8 address;
+	int fd, ret;
+	char *device;
+	int dry_run = 1;
+	long partition_mask;
+	char *endptr;
+
+	if (nargs != 4) {
+		fprintf(stderr, "Usage: mmc gp set_extended <-y|-n|-c> <partition-mask> </path/to/mmcblkX>\n");
+		exit(1);
+	}
+
+	if (!strcmp("-y", argv[1])) {
+		dry_run = 0;
+        } else if (!strcmp("-c", argv[1])) {
+		dry_run = 2;
+	}
+
+	errno = 0;
+	partition_mask = strtol(argv[2], &endptr, 0);
+	if (errno != 0 || endptr == argv[2] || *endptr != 0 || partition_mask < 0 || partition_mask > 0xffff) {
+		fprintf(stderr, "Partition mask invalid: %s\n", argv[2]);
+		exit(1);
+	}
+
+	device = argv[3];
+	fd = open(device, O_RDWR);
+	if (fd < 0) {
+		perror("open");
+		exit(1);
+	}
+
+	ret = read_extcsd(fd, ext_csd);
+	if (ret) {
+		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
+		exit(1);
+	}
+
+	/* assert not PARTITION_SETTING_COMPLETED */
+	if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED]) {
+		printf(" Device is already partitioned\n");
+		exit(1);
+	}
+
+	value = (__u8)partition_mask;
+	address = EXT_CSD_EXT_PARTITIONS_ATTRIBUTE_0;
+	ret = write_extcsd_value(fd, address, value);
+	fprintf(stderr, "Writing 0x%02x to EXT_CSD[%d]\n", value, address);
+	if (ret) {
+		fprintf(stderr, "Could not write 0x%x to EXT_CSD[%d] in %s\n",
+			value, address, device);
+		exit(1);
+	}
+
+	value = (__u8)(partition_mask >> 8);
+	address = EXT_CSD_EXT_PARTITIONS_ATTRIBUTE_1;
+	ret = write_extcsd_value(fd, address, value);
+	fprintf(stderr, "Writing 0x%02x to EXT_CSD[%d]\n", value, address);
+	if (ret) {
+		fprintf(stderr, "Could not write 0x%x to EXT_CSD[%d] in %s\n",
+			value, address, device);
+		exit(1);
+	}
+
+	if (set_partitioning_setting_completed(dry_run, device, fd))
+		exit(1);
+
+	return 0;
+}
+
 int do_create_gp_partition(int nargs, char **argv)
 {
 	__u8 value;
@@ -975,12 +1050,12 @@  int do_create_gp_partition(int nargs, char **argv)
 	int fd, ret;
 	char *device;
 	int dry_run = 1;
-	int partition, enh_attr, ext_attr;
+	int partition;
 	unsigned int length_kib, gp_size_mult;
 	unsigned long align;
 
-	if (nargs != 7) {
-		fprintf(stderr, "Usage: mmc gp create <-y|-n|-c> <length KiB> <partition> <enh_attr> <ext_attr> </path/to/mmcblkX>\n");
+	if (nargs != 5) {
+		fprintf(stderr, "Usage: mmc gp create <-y|-n|-c> <length KiB> <partition> </path/to/mmcblkX>\n");
 		exit(1);
 	}
 
@@ -992,20 +1067,13 @@  int do_create_gp_partition(int nargs, char **argv)
 
 	length_kib = strtol(argv[2], NULL, 10);
 	partition = strtol(argv[3], NULL, 10);
-	enh_attr = strtol(argv[4], NULL, 10);
-	ext_attr = strtol(argv[5], NULL, 10);
-	device = argv[6];
+	device = argv[4];
 
 	if (partition < 1 || partition > 4) {
 		printf("Invalid gp partition number; valid range [1-4].\n");
 		exit(1);
 	}
 
-	if (enh_attr && ext_attr) {
-		printf("Not allowed to set both enhanced attribute and extended attribute\n");
-		exit(1);
-	}
-
 	fd = open(device, O_RDWR);
 	if (fd < 0) {
 		perror("open");
@@ -1060,30 +1128,52 @@  int do_create_gp_partition(int nargs, char **argv)
 		exit(1);
 	}
 
-	value = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
-	if (enh_attr)
-		value |= (1 << partition);
-	else
-		value &= ~(1 << partition);
+	if (set_partitioning_setting_completed(dry_run, device, fd))
+		exit(1);
 
-	ret = write_extcsd_value(fd, EXT_CSD_PARTITIONS_ATTRIBUTE, value);
-	if (ret) {
-		fprintf(stderr, "Could not write EXT_CSD_ENH_%x to EXT_CSD[%d] in %s\n",
-			partition, EXT_CSD_PARTITIONS_ATTRIBUTE, device);
+	return 0;
+}
+
+// TODO: check if extended attributes set on GP partitions (only allowed either enhanced or extended attribute)
+int do_enh_area_set_partitions(int nargs, char **argv)
+{
+	int fd, ret;
+	char *device;
+	int dry_run = 1;
+	long partition_mask;
+	char *endptr;
+
+	if (nargs != 4) {
+		fprintf(stderr, "Usage: mmc enh_area set_partitions <-y|-n|-c> <partition-mask> </path/to/mmcblkX>\n");
 		exit(1);
 	}
 
-	address = EXT_CSD_EXT_PARTITIONS_ATTRIBUTE_0 + (partition - 1) / 2;
-	value = ext_csd[address];
-	if (ext_attr)
-		value |= (ext_attr << (4 * ((partition - 1) % 2)));
-	else
-		value &= (0xF << (4 * ((partition % 2))));
+	if (!strcmp("-y", argv[1])) {
+		dry_run = 0;
+	} else if (!strcmp("-c", argv[1])) {
+		dry_run = 2;
+	}
 
-	ret = write_extcsd_value(fd, address, value);
+	errno = 0;
+	partition_mask = strtol(argv[2], &endptr, 0);
+	if (errno != 0 || endptr == argv[2] || *endptr != 0 || partition_mask < 0 || partition_mask > 0x1f) {
+		fprintf(stderr, "Partition mask invalid: %s\n", argv[2]);
+		exit(1);
+	}
+
+	device = argv[3];
+	fd = open(device, O_RDWR);
+	if (fd < 0) {
+		perror("open");
+		exit(1);
+	}
+
+	ret = write_extcsd_value(fd, EXT_CSD_PARTITIONS_ATTRIBUTE, (__u8)partition_mask);
 	if (ret) {
-		fprintf(stderr, "Could not write 0x%x to EXT_CSD[%d] in %s\n",
-			value, address, device);
+		fprintf(stderr, "Could not write 0x%02x to "
+			"EXT_CSD[%d] in %s\n",
+		       	(__u8)partition_mask,
+			EXT_CSD_PARTITIONS_ATTRIBUTE, device);
 		exit(1);
 	}
 
@@ -1097,7 +1187,7 @@  int do_create_gp_partition(int nargs, char **argv)
 	return 0;
 }
 
-int do_enh_area_set(int nargs, char **argv)
+int do_enh_area_set_user_data(int nargs, char **argv)
 {
 	__u8 value;
 	__u8 ext_csd[512];
@@ -1108,7 +1198,7 @@  int do_enh_area_set(int nargs, char **argv)
 	unsigned long align;
 
 	if (nargs != 5) {
-		fprintf(stderr, "Usage: mmc enh_area set <-y|-n|-c> <start KiB> <length KiB> </path/to/mmcblkX>\n");
+		fprintf(stderr, "Usage: mmc enh_area set_user_data <-y|-n|-c> <start KiB> <length KiB> </path/to/mmcblkX>\n");
 		exit(1);
 	}
 
@@ -1148,6 +1238,13 @@  int do_enh_area_set(int nargs, char **argv)
 		exit(1);
 	}
 
+	/* assert enhanced attribute is set on user partition */
+	if (!(ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & EXT_CSD_ENH_USR))
+	{
+		fprintf(stderr, "error: User partition must be set with enhanced attribute first\n");
+		exit(1);
+	}
+
 	align = 512l * get_hc_wp_grp_size(ext_csd) * get_hc_erase_grp_size(ext_csd);
 
 	enh_size_mult = (length_kib + align/2l) / align;
@@ -1165,7 +1262,7 @@  int do_enh_area_set(int nargs, char **argv)
 		exit(1);
 	}
 
-	/* write to ENH_START_ADDR and ENH_SIZE_MULT and PARTITIONS_ATTRIBUTE's ENH_USR bit */
+	/* write to ENH_START_ADDR and ENH_SIZE_MULT */
 	value = (enh_start_addr >> 24) & 0xff;
 	ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_3, value);
 	if (ret) {
@@ -1223,14 +1320,6 @@  int do_enh_area_set(int nargs, char **argv)
 			EXT_CSD_ENH_SIZE_MULT_0, device);
 		exit(1);
 	}
-	value = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] | EXT_CSD_ENH_USR;
-	ret = write_extcsd_value(fd, EXT_CSD_PARTITIONS_ATTRIBUTE, value);
-	if (ret) {
-		fprintf(stderr, "Could not write EXT_CSD_ENH_USR to "
-			"EXT_CSD[%d] in %s\n",
-			EXT_CSD_PARTITIONS_ATTRIBUTE, device);
-		exit(1);
-	}
 
 	ret = check_enhanced_area_total_limit(device, fd);
 	if (ret)
diff --git a/mmc_cmds.h b/mmc_cmds.h
index cf6c6fb..a8a90c2 100644
--- a/mmc_cmds.h
+++ b/mmc_cmds.h
@@ -33,7 +33,9 @@  int do_hwreset_dis(int nargs, char **argv);
 int do_sanitize(int nargs, char **argv);
 int do_status_get(int nargs, char **argv);
 int do_create_gp_partition(int nargs, char **argv);
-int do_enh_area_set(int nargs, char **argv);
+int do_gp_set_extended(int nargs, char **argv);
+int do_enh_area_set_user_data(int nargs, char **argv);
+int do_enh_area_set_partitions(int nargs, char **argv);
 int do_write_reliability_set_register(int nargs, char **argv);
 int do_rpmb_write_key(int nargs, char **argv);
 int do_rpmb_read_counter(int nargs, char **argv);