mmc_cmds.c revision 22f2641fe6155fe9fb8b38a8ebe2093ec3e2ec11
1/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public
4 * License v2 as published by the Free Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
9 * General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public
12 * License along with this program; if not, write to the
13 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14 * Boston, MA 021110-1307, USA.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <sys/ioctl.h>
21#include <sys/types.h>
22#include <dirent.h>
23#include <sys/stat.h>
24#include <unistd.h>
25#include <fcntl.h>
26#include <libgen.h>
27#include <limits.h>
28#include <ctype.h>
29
30#include "mmc.h"
31#include "mmc_cmds.h"
32
33int read_extcsd(int fd, __u8 *ext_csd)
34{
35	int ret = 0;
36	struct mmc_ioc_cmd idata;
37	memset(&idata, 0, sizeof(idata));
38	memset(ext_csd, 0, sizeof(__u8) * 512);
39	idata.write_flag = 0;
40	idata.opcode = MMC_SEND_EXT_CSD;
41	idata.arg = 0;
42	idata.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
43	idata.blksz = 512;
44	idata.blocks = 1;
45	mmc_ioc_cmd_set_data(idata, ext_csd);
46
47	ret = ioctl(fd, MMC_IOC_CMD, &idata);
48	if (ret)
49		perror("ioctl");
50
51	return ret;
52}
53
54int write_extcsd_value(int fd, __u8 index, __u8 value)
55{
56	int ret = 0;
57	struct mmc_ioc_cmd idata;
58
59	memset(&idata, 0, sizeof(idata));
60	idata.write_flag = 1;
61	idata.opcode = MMC_SWITCH;
62	idata.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
63			(index << 16) |
64			(value << 8) |
65			EXT_CSD_CMD_SET_NORMAL;
66	idata.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
67
68	ret = ioctl(fd, MMC_IOC_CMD, &idata);
69	if (ret)
70		perror("ioctl");
71
72	return ret;
73}
74
75int send_status(int fd, __u32 *response)
76{
77	int ret = 0;
78	struct mmc_ioc_cmd idata;
79
80	memset(&idata, 0, sizeof(idata));
81	idata.opcode = MMC_SEND_STATUS;
82	idata.arg = (1 << 16);
83	idata.flags = MMC_RSP_R1 | MMC_CMD_AC;
84
85	ret = ioctl(fd, MMC_IOC_CMD, &idata);
86	if (ret)
87	perror("ioctl");
88
89	*response = idata.response[0];
90
91	return ret;
92}
93
94void print_writeprotect_status(__u8 *ext_csd)
95{
96	__u8 reg;
97	__u8 ext_csd_rev = ext_csd[192];
98
99	/* A43: reserved [174:0] */
100	if (ext_csd_rev >= 5) {
101		printf("Boot write protection status registers"
102			" [BOOT_WP_STATUS]: 0x%02x\n", ext_csd[174]);
103
104		reg = ext_csd[EXT_CSD_BOOT_WP];
105		printf("Boot Area Write protection [BOOT_WP]: 0x%02x\n", reg);
106		printf(" Power ro locking: ");
107		if (reg & EXT_CSD_BOOT_WP_B_PWR_WP_DIS)
108			printf("not possible\n");
109		else
110			printf("possible\n");
111
112		printf(" Permanent ro locking: ");
113		if (reg & EXT_CSD_BOOT_WP_B_PERM_WP_DIS)
114			printf("not possible\n");
115		else
116			printf("possible\n");
117
118		printf(" ro lock status: ");
119		if (reg & EXT_CSD_BOOT_WP_B_PWR_WP_EN)
120			printf("locked until next power on\n");
121		else if (reg & EXT_CSD_BOOT_WP_B_PERM_WP_EN)
122			printf("locked permanently\n");
123		else
124			printf("not locked\n");
125	}
126}
127
128int do_writeprotect_get(int nargs, char **argv)
129{
130	__u8 ext_csd[512];
131	int fd, ret;
132	char *device;
133
134	CHECK(nargs != 2, "Usage: mmc writeprotect get </path/to/mmcblkX>\n",
135			  exit(1));
136
137	device = argv[1];
138
139	fd = open(device, O_RDWR);
140	if (fd < 0) {
141		perror("open");
142		exit(1);
143	}
144
145	ret = read_extcsd(fd, ext_csd);
146	if (ret) {
147		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
148		exit(1);
149	}
150
151	print_writeprotect_status(ext_csd);
152
153	return ret;
154}
155
156int do_writeprotect_set(int nargs, char **argv)
157{
158	__u8 ext_csd[512], value;
159	int fd, ret;
160	char *device;
161
162	CHECK(nargs != 2, "Usage: mmc writeprotect set </path/to/mmcblkX>\n",
163			  exit(1));
164
165	device = argv[1];
166
167	fd = open(device, O_RDWR);
168	if (fd < 0) {
169		perror("open");
170		exit(1);
171	}
172
173	ret = read_extcsd(fd, ext_csd);
174	if (ret) {
175		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
176		exit(1);
177	}
178
179	value = ext_csd[EXT_CSD_BOOT_WP] |
180		EXT_CSD_BOOT_WP_B_PWR_WP_EN;
181	ret = write_extcsd_value(fd, EXT_CSD_BOOT_WP, value);
182	if (ret) {
183		fprintf(stderr, "Could not write 0x%02x to "
184			"EXT_CSD[%d] in %s\n",
185			value, EXT_CSD_BOOT_WP, device);
186		exit(1);
187	}
188
189	return ret;
190}
191
192int do_disable_512B_emulation(int nargs, char **argv)
193{
194	__u8 ext_csd[512], native_sector_size, data_sector_size, wr_rel_param;
195	int fd, ret;
196	char *device;
197
198	CHECK(nargs != 2, "Usage: mmc disable 512B emulation </path/to/mmcblkX>\n", exit(1));
199	device = argv[1];
200
201	fd = open(device, O_RDWR);
202	if (fd < 0) {
203		perror("open");
204		exit(1);
205	}
206
207	ret = read_extcsd(fd, ext_csd);
208	if (ret) {
209		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
210		exit(1);
211	}
212
213	wr_rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
214	native_sector_size = ext_csd[EXT_CSD_NATIVE_SECTOR_SIZE];
215	data_sector_size = ext_csd[EXT_CSD_DATA_SECTOR_SIZE];
216
217	if (native_sector_size && !data_sector_size &&
218	   (wr_rel_param & EN_REL_WR)) {
219		ret = write_extcsd_value(fd, EXT_CSD_USE_NATIVE_SECTOR, 1);
220
221		if (ret) {
222			fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
223					1, EXT_CSD_BOOT_WP, device);
224			exit(1);
225		}
226		printf("MMC disable 512B emulation successful.  Now reset the device to switch to 4KB native sector mode.\n");
227	} else if (native_sector_size && data_sector_size) {
228		printf("MMC 512B emulation mode is already disabled; doing nothing.\n");
229	} else {
230		printf("MMC does not support disabling 512B emulation mode.\n");
231	}
232
233	return ret;
234}
235
236int do_write_boot_en(int nargs, char **argv)
237{
238	__u8 ext_csd[512];
239	__u8 value = 0;
240	int fd, ret;
241	char *device;
242	int boot_area, send_ack;
243
244	CHECK(nargs != 4, "Usage: mmc bootpart enable <partition_number> "
245			  "<send_ack> </path/to/mmcblkX>\n", exit(1));
246
247	/*
248	 * If <send_ack> is 1, the device will send acknowledgment
249	 * pattern "010" to the host when boot operation begins.
250	 * If <send_ack> is 0, it won't.
251	 */
252	boot_area = strtol(argv[1], NULL, 10);
253	send_ack = strtol(argv[2], NULL, 10);
254	device = argv[3];
255
256	fd = open(device, O_RDWR);
257	if (fd < 0) {
258		perror("open");
259		exit(1);
260	}
261
262	ret = read_extcsd(fd, ext_csd);
263	if (ret) {
264		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
265		exit(1);
266	}
267
268	value = ext_csd[EXT_CSD_PART_CONFIG];
269
270	switch (boot_area) {
271	case EXT_CSD_PART_CONFIG_ACC_BOOT0:
272		value |= (1 << 3);
273		value &= ~(3 << 4);
274		break;
275	case EXT_CSD_PART_CONFIG_ACC_BOOT1:
276		value |= (1 << 4);
277		value &= ~(1 << 3);
278		value &= ~(1 << 5);
279		break;
280	case EXT_CSD_PART_CONFIG_ACC_USER_AREA:
281		value |= (boot_area << 3);
282		break;
283	default:
284		fprintf(stderr, "Cannot enable the boot area\n");
285		exit(1);
286	}
287	if (send_ack)
288		value |= EXT_CSD_PART_CONFIG_ACC_ACK;
289	else
290		value &= ~EXT_CSD_PART_CONFIG_ACC_ACK;
291
292	ret = write_extcsd_value(fd, EXT_CSD_PART_CONFIG, value);
293	if (ret) {
294		fprintf(stderr, "Could not write 0x%02x to "
295			"EXT_CSD[%d] in %s\n",
296			value, EXT_CSD_PART_CONFIG, device);
297		exit(1);
298	}
299	return ret;
300}
301
302int do_hwreset(int value, int nargs, char **argv)
303{
304	__u8 ext_csd[512];
305	int fd, ret;
306	char *device;
307
308	CHECK(nargs != 2, "Usage: mmc hwreset enable </path/to/mmcblkX>\n",
309			  exit(1));
310
311	device = argv[1];
312
313	fd = open(device, O_RDWR);
314	if (fd < 0) {
315		perror("open");
316		exit(1);
317	}
318
319	ret = read_extcsd(fd, ext_csd);
320	if (ret) {
321		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
322		exit(1);
323	}
324
325	if ((ext_csd[EXT_CSD_RST_N_FUNCTION] & EXT_CSD_RST_N_EN_MASK) ==
326	    EXT_CSD_HW_RESET_EN) {
327		fprintf(stderr,
328			"H/W Reset is already permanently enabled on %s\n",
329			device);
330		exit(1);
331	}
332	if ((ext_csd[EXT_CSD_RST_N_FUNCTION] & EXT_CSD_RST_N_EN_MASK) ==
333	    EXT_CSD_HW_RESET_DIS) {
334		fprintf(stderr,
335			"H/W Reset is already permanently disabled on %s\n",
336			device);
337		exit(1);
338	}
339
340	ret = write_extcsd_value(fd, EXT_CSD_RST_N_FUNCTION, value);
341	if (ret) {
342		fprintf(stderr,
343			"Could not write 0x%02x to EXT_CSD[%d] in %s\n",
344			value, EXT_CSD_RST_N_FUNCTION, device);
345		exit(1);
346	}
347
348	return ret;
349}
350
351int do_hwreset_en(int nargs, char **argv)
352{
353	return do_hwreset(EXT_CSD_HW_RESET_EN, nargs, argv);
354}
355
356int do_hwreset_dis(int nargs, char **argv)
357{
358	return do_hwreset(EXT_CSD_HW_RESET_DIS, nargs, argv);
359}
360
361int do_write_bkops_en(int nargs, char **argv)
362{
363	__u8 ext_csd[512], value = 0;
364	int fd, ret;
365	char *device;
366
367	CHECK(nargs != 2, "Usage: mmc bkops enable </path/to/mmcblkX>\n",
368			exit(1));
369
370	device = argv[1];
371
372	fd = open(device, O_RDWR);
373	if (fd < 0) {
374		perror("open");
375		exit(1);
376	}
377
378	ret = read_extcsd(fd, ext_csd);
379	if (ret) {
380		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
381		exit(1);
382	}
383
384	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
385		fprintf(stderr, "%s doesn't support BKOPS\n", device);
386		exit(1);
387	}
388
389	ret = write_extcsd_value(fd, EXT_CSD_BKOPS_EN, BKOPS_ENABLE);
390	if (ret) {
391		fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
392			value, EXT_CSD_BKOPS_EN, device);
393		exit(1);
394	}
395
396	return ret;
397}
398
399int do_status_get(int nargs, char **argv)
400{
401	__u32 response;
402	int fd, ret;
403	char *device;
404
405	CHECK(nargs != 2, "Usage: mmc status get </path/to/mmcblkX>\n",
406		exit(1));
407
408	device = argv[1];
409
410	fd = open(device, O_RDWR);
411	if (fd < 0) {
412		perror("open");
413		exit(1);
414	}
415
416	ret = send_status(fd, &response);
417	if (ret) {
418		fprintf(stderr, "Could not read response to SEND_STATUS from %s\n", device);
419		exit(1);
420	}
421
422	printf("SEND_STATUS response: 0x%08x\n", response);
423
424	return ret;
425}
426
427unsigned int get_sector_count(__u8 *ext_csd)
428{
429	return (ext_csd[EXT_CSD_SEC_COUNT_3] << 24) |
430	(ext_csd[EXT_CSD_SEC_COUNT_2] << 16) |
431	(ext_csd[EXT_CSD_SEC_COUNT_1] << 8)  |
432	ext_csd[EXT_CSD_SEC_COUNT_0];
433}
434
435int is_blockaddresed(__u8 *ext_csd)
436{
437	unsigned int sectors = get_sector_count(ext_csd);
438
439	return (sectors > (2u * 1024 * 1024 * 1024) / 512);
440}
441
442unsigned int get_hc_wp_grp_size(__u8 *ext_csd)
443{
444	return ext_csd[221];
445}
446
447unsigned int get_hc_erase_grp_size(__u8 *ext_csd)
448{
449	return ext_csd[224];
450}
451
452int set_partitioning_setting_completed(int dry_run, const char * const device,
453		int fd)
454{
455	int ret;
456
457	if (dry_run) {
458		fprintf(stderr, "NOT setting PARTITION_SETTING_COMPLETED\n");
459		fprintf(stderr, "These changes will not take effect neither "
460			"now nor after a power cycle\n");
461		return 1;
462	}
463
464	fprintf(stderr, "setting OTP PARTITION_SETTING_COMPLETED!\n");
465	ret = write_extcsd_value(fd, EXT_CSD_PARTITION_SETTING_COMPLETED, 0x1);
466	if (ret) {
467		fprintf(stderr, "Could not write 0x1 to "
468			"EXT_CSD[%d] in %s\n",
469			EXT_CSD_PARTITION_SETTING_COMPLETED, device);
470		return 1;
471	}
472
473	__u32 response;
474	ret = send_status(fd, &response);
475	if (ret) {
476		fprintf(stderr, "Could not get response to SEND_STATUS "
477			"from %s\n", device);
478		return 1;
479	}
480
481	if (response & R1_SWITCH_ERROR) {
482		fprintf(stderr, "Setting OTP PARTITION_SETTING_COMPLETED "
483			"failed on %s\n", device);
484		return 1;
485	}
486
487	fprintf(stderr, "Setting OTP PARTITION_SETTING_COMPLETED on "
488		"%s SUCCESS\n", device);
489	fprintf(stderr, "Device power cycle needed for settings to "
490		"take effect.\n"
491		"Confirm that PARTITION_SETTING_COMPLETED bit is set "
492		"using 'extcsd read' after power cycle\n");
493
494	return 0;
495}
496
497int do_enh_area_set(int nargs, char **argv)
498{
499	__u8 value;
500	__u8 ext_csd[512];
501	int fd, ret;
502	char *device;
503	int dry_run = 1;
504	unsigned int start_kib, length_kib, enh_start_addr, enh_size_mult;
505	unsigned long align;
506
507	CHECK(nargs != 5, "Usage: mmc enh_area set <-y|-n> <start KiB> <length KiB> "
508			  "</path/to/mmcblkX>\n", exit(1));
509
510	if (!strcmp("-y", argv[1]))
511		dry_run = 0;
512
513	start_kib = strtol(argv[2], NULL, 10);
514	length_kib = strtol(argv[3], NULL, 10);
515	device = argv[4];
516
517	fd = open(device, O_RDWR);
518	if (fd < 0) {
519		perror("open");
520		exit(1);
521	}
522
523	ret = read_extcsd(fd, ext_csd);
524	if (ret) {
525		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
526		exit(1);
527	}
528
529	/* assert ENH_ATTRIBUTE_EN */
530	if (!(ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & EXT_CSD_ENH_ATTRIBUTE_EN))
531	{
532		printf(" Device cannot have enhanced tech.\n");
533		exit(1);
534	}
535
536	/* assert not PARTITION_SETTING_COMPLETED */
537	if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED])
538	{
539		printf(" Device is already partitioned\n");
540		exit(1);
541	}
542
543	align = 512l * get_hc_wp_grp_size(ext_csd) * get_hc_erase_grp_size(ext_csd);
544
545	enh_size_mult = (length_kib + align/2l) / align;
546
547	enh_start_addr = start_kib * 1024 / (is_blockaddresed(ext_csd) ? 512 : 1);
548	enh_start_addr /= align;
549	enh_start_addr *= align;
550
551	/* set EXT_CSD_ERASE_GROUP_DEF bit 0 */
552	ret = write_extcsd_value(fd, EXT_CSD_ERASE_GROUP_DEF, 0x1);
553	if (ret) {
554		fprintf(stderr, "Could not write 0x1 to "
555			"EXT_CSD[%d] in %s\n",
556			EXT_CSD_ERASE_GROUP_DEF, device);
557		exit(1);
558	}
559
560	/* write to ENH_START_ADDR and ENH_SIZE_MULT and PARTITIONS_ATTRIBUTE's ENH_USR bit */
561	value = (enh_start_addr >> 24) & 0xff;
562	ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_3, value);
563	if (ret) {
564		fprintf(stderr, "Could not write 0x%02x to "
565			"EXT_CSD[%d] in %s\n", value,
566			EXT_CSD_ENH_START_ADDR_3, device);
567		exit(1);
568	}
569	value = (enh_start_addr >> 16) & 0xff;
570	ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_2, value);
571	if (ret) {
572		fprintf(stderr, "Could not write 0x%02x to "
573			"EXT_CSD[%d] in %s\n", value,
574			EXT_CSD_ENH_START_ADDR_2, device);
575		exit(1);
576	}
577	value = (enh_start_addr >> 8) & 0xff;
578	ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_1, value);
579	if (ret) {
580		fprintf(stderr, "Could not write 0x%02x to "
581			"EXT_CSD[%d] in %s\n", value,
582			EXT_CSD_ENH_START_ADDR_1, device);
583		exit(1);
584	}
585	value = enh_start_addr & 0xff;
586	ret = write_extcsd_value(fd, EXT_CSD_ENH_START_ADDR_0, value);
587	if (ret) {
588		fprintf(stderr, "Could not write 0x%02x to "
589			"EXT_CSD[%d] in %s\n", value,
590			EXT_CSD_ENH_START_ADDR_0, device);
591		exit(1);
592	}
593
594	value = (enh_size_mult >> 16) & 0xff;
595	ret = write_extcsd_value(fd, EXT_CSD_ENH_SIZE_MULT_2, value);
596	if (ret) {
597		fprintf(stderr, "Could not write 0x%02x to "
598			"EXT_CSD[%d] in %s\n", value,
599			EXT_CSD_ENH_SIZE_MULT_2, device);
600		exit(1);
601	}
602	value = (enh_size_mult >> 8) & 0xff;
603	ret = write_extcsd_value(fd, EXT_CSD_ENH_SIZE_MULT_1, value);
604	if (ret) {
605		fprintf(stderr, "Could not write 0x%02x to "
606			"EXT_CSD[%d] in %s\n", value,
607			EXT_CSD_ENH_SIZE_MULT_1, device);
608		exit(1);
609	}
610	value = enh_size_mult & 0xff;
611	ret = write_extcsd_value(fd, EXT_CSD_ENH_SIZE_MULT_0, value);
612	if (ret) {
613		fprintf(stderr, "Could not write 0x%02x to "
614			"EXT_CSD[%d] in %s\n", value,
615			EXT_CSD_ENH_SIZE_MULT_0, device);
616		exit(1);
617	}
618
619	ret = write_extcsd_value(fd, EXT_CSD_PARTITIONS_ATTRIBUTE, EXT_CSD_ENH_USR);
620	if (ret) {
621		fprintf(stderr, "Could not write EXT_CSD_ENH_USR to "
622			"EXT_CSD[%d] in %s\n",
623			EXT_CSD_PARTITIONS_ATTRIBUTE, device);
624		exit(1);
625	}
626
627	printf("Done setting ENH_USR area on %s\n", device);
628
629	if (!set_partitioning_setting_completed(dry_run, device, fd))
630		exit(1);
631
632	return 0;
633}
634
635int do_write_reliability_set(int nargs, char **argv)
636{
637	__u8 value;
638	__u8 ext_csd[512];
639	int fd, ret;
640
641	int dry_run = 1;
642	int partition;
643	char *device;
644
645	CHECK(nargs != 4, "Usage: mmc write_reliability set <-y|-n> "
646			"<partition> </path/to/mmcblkX>\n", exit(1));
647
648	if (!strcmp("-y", argv[1]))
649		dry_run = 0;
650
651	partition = strtol(argv[2], NULL, 10);
652	device = argv[3];
653
654	fd = open(device, O_RDWR);
655	if (fd < 0) {
656		perror("open");
657		exit(1);
658	}
659
660	ret = read_extcsd(fd, ext_csd);
661	if (ret) {
662		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
663		exit(1);
664	}
665
666	/* assert not PARTITION_SETTING_COMPLETED */
667	if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED])
668	{
669		printf(" Device is already partitioned\n");
670		exit(1);
671	}
672
673	/* assert HS_CTRL_REL */
674	if (!(ext_csd[EXT_CSD_WR_REL_PARAM] & HS_CTRL_REL)) {
675		printf("Cannot set write reliability parameters, WR_REL_SET is "
676				"read-only\n");
677		exit(1);
678	}
679
680	value = ext_csd[EXT_CSD_WR_REL_SET] | (1<<partition);
681	ret = write_extcsd_value(fd, EXT_CSD_WR_REL_SET, value);
682	if (ret) {
683		fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
684				value, EXT_CSD_WR_REL_SET, device);
685		exit(1);
686	}
687
688	printf("Done setting EXT_CSD_WR_REL_SET to 0x%02x on %s\n",
689		value, device);
690
691	if (!set_partitioning_setting_completed(dry_run, device, fd))
692		exit(1);
693
694	return 0;
695}
696
697int do_read_extcsd(int nargs, char **argv)
698{
699	__u8 ext_csd[512], ext_csd_rev, reg;
700	int fd, ret;
701	char *device;
702	const char *str;
703
704	CHECK(nargs != 2, "Usage: mmc extcsd read </path/to/mmcblkX>\n",
705			  exit(1));
706
707	device = argv[1];
708
709	fd = open(device, O_RDWR);
710	if (fd < 0) {
711		perror("open");
712		exit(1);
713	}
714
715	ret = read_extcsd(fd, ext_csd);
716	if (ret) {
717		fprintf(stderr, "Could not read EXT_CSD from %s\n", device);
718		exit(1);
719	}
720
721	ext_csd_rev = ext_csd[192];
722
723	switch (ext_csd_rev) {
724	case 6:
725		str = "4.5";
726		break;
727	case 5:
728		str = "4.41";
729		break;
730	case 3:
731		str = "4.3";
732		break;
733	case 2:
734		str = "4.2";
735		break;
736	case 1:
737		str = "4.1";
738		break;
739	case 0:
740		str = "4.0";
741		break;
742	default:
743		goto out_free;
744	}
745	printf("=============================================\n");
746	printf("  Extended CSD rev 1.%d (MMC %s)\n", ext_csd_rev, str);
747	printf("=============================================\n\n");
748
749	if (ext_csd_rev < 3)
750		goto out_free; /* No ext_csd */
751
752	/* Parse the Extended CSD registers.
753	 * Reserved bit should be read as "0" in case of spec older
754	 * than A441.
755	 */
756	reg = ext_csd[EXT_CSD_S_CMD_SET];
757	printf("Card Supported Command sets [S_CMD_SET: 0x%02x]\n", reg);
758	if (!reg)
759		printf(" - Standard MMC command sets\n");
760
761	reg = ext_csd[EXT_CSD_HPI_FEATURE];
762	printf("HPI Features [HPI_FEATURE: 0x%02x]: ", reg);
763	if (reg & EXT_CSD_HPI_SUPP) {
764		if (reg & EXT_CSD_HPI_IMPL)
765			printf("implementation based on CMD12\n");
766		else
767			printf("implementation based on CMD13\n");
768	}
769
770	printf("Background operations support [BKOPS_SUPPORT: 0x%02x]\n",
771		ext_csd[502]);
772
773	if (ext_csd_rev >= 6) {
774		printf("Max Packet Read Cmd [MAX_PACKED_READS: 0x%02x]\n",
775			ext_csd[501]);
776		printf("Max Packet Write Cmd [MAX_PACKED_WRITES: 0x%02x]\n",
777			ext_csd[500]);
778		printf("Data TAG support [DATA_TAG_SUPPORT: 0x%02x]\n",
779			ext_csd[499]);
780
781		printf("Data TAG Unit Size [TAG_UNIT_SIZE: 0x%02x]\n",
782			ext_csd[498]);
783		printf("Tag Resources Size [TAG_RES_SIZE: 0x%02x]\n",
784			ext_csd[497]);
785		printf("Context Management Capabilities"
786			" [CONTEXT_CAPABILITIES: 0x%02x]\n", ext_csd[496]);
787		printf("Large Unit Size [LARGE_UNIT_SIZE_M1: 0x%02x]\n",
788			ext_csd[495]);
789		printf("Extended partition attribute support"
790			" [EXT_SUPPORT: 0x%02x]\n", ext_csd[494]);
791		printf("Generic CMD6 Timer [GENERIC_CMD6_TIME: 0x%02x]\n",
792			ext_csd[248]);
793		printf("Power off notification [POWER_OFF_LONG_TIME: 0x%02x]\n",
794			ext_csd[247]);
795		printf("Cache Size [CACHE_SIZE] is %d KiB\n",
796			ext_csd[249] << 0 | (ext_csd[250] << 8) |
797			(ext_csd[251] << 16) | (ext_csd[252] << 24));
798	}
799
800	/* A441: Reserved [501:247]
801	    A43: reserved [246:229] */
802	if (ext_csd_rev >= 5) {
803		printf("Background operations status"
804			" [BKOPS_STATUS: 0x%02x]\n", ext_csd[246]);
805
806		/* CORRECTLY_PRG_SECTORS_NUM [245:242] TODO */
807
808		printf("1st Initialisation Time after programmed sector"
809			" [INI_TIMEOUT_AP: 0x%02x]\n", ext_csd[241]);
810
811		/* A441: reserved [240] */
812		printf("Power class for 52MHz, DDR at 3.6V"
813			" [PWR_CL_DDR_52_360: 0x%02x]\n", ext_csd[239]);
814		printf("Power class for 52MHz, DDR at 1.95V"
815			" [PWR_CL_DDR_52_195: 0x%02x]\n", ext_csd[238]);
816
817		/* A441: reserved [237-236] */
818
819		if (ext_csd_rev >= 6) {
820			printf("Power class for 200MHz at 3.6V"
821				" [PWR_CL_200_360: 0x%02x]\n", ext_csd[237]);
822			printf("Power class for 200MHz, at 1.95V"
823				" [PWR_CL_200_195: 0x%02x]\n", ext_csd[236]);
824		}
825		printf("Minimum Performance for 8bit at 52MHz in DDR mode:\n");
826		printf(" [MIN_PERF_DDR_W_8_52: 0x%02x]\n", ext_csd[235]);
827		printf(" [MIN_PERF_DDR_R_8_52: 0x%02x]\n", ext_csd[234]);
828		/* A441: reserved [233] */
829		printf("TRIM Multiplier [TRIM_MULT: 0x%02x]\n", ext_csd[232]);
830		printf("Secure Feature support [SEC_FEATURE_SUPPORT: 0x%02x]\n",
831			ext_csd[231]);
832	}
833	if (ext_csd_rev == 5) { /* Obsolete in 4.5 */
834		printf("Secure Erase Multiplier [SEC_ERASE_MULT: 0x%02x]\n",
835			ext_csd[230]);
836		printf("Secure TRIM Multiplier [SEC_TRIM_MULT: 0x%02x]\n",
837			ext_csd[229]);
838	}
839	reg = ext_csd[EXT_CSD_BOOT_INFO];
840	printf("Boot Information [BOOT_INFO: 0x%02x]\n", reg);
841	if (reg & EXT_CSD_BOOT_INFO_ALT)
842		printf(" Device supports alternative boot method\n");
843	if (reg & EXT_CSD_BOOT_INFO_DDR_DDR)
844		printf(" Device supports dual data rate during boot\n");
845	if (reg & EXT_CSD_BOOT_INFO_HS_MODE)
846		printf(" Device supports high speed timing during boot\n");
847
848	/* A441/A43: reserved [227] */
849	printf("Boot partition size [BOOT_SIZE_MULTI: 0x%02x]\n", ext_csd[226]);
850	printf("Access size [ACC_SIZE: 0x%02x]\n", ext_csd[225]);
851
852	reg = get_hc_erase_grp_size(ext_csd);
853	printf("High-capacity erase unit size [HC_ERASE_GRP_SIZE: 0x%02x]\n",
854		reg);
855	printf(" i.e. %u KiB\n", 512 * reg);
856
857	printf("High-capacity erase timeout [ERASE_TIMEOUT_MULT: 0x%02x]\n",
858		ext_csd[223]);
859	printf("Reliable write sector count [REL_WR_SEC_C: 0x%02x]\n",
860		ext_csd[222]);
861
862	reg = get_hc_wp_grp_size(ext_csd);
863	printf("High-capacity W protect group size [HC_WP_GRP_SIZE: 0x%02x]\n",
864		reg);
865	printf(" i.e. %lu KiB\n", 512l * get_hc_erase_grp_size(ext_csd) * reg);
866
867	printf("Sleep current (VCC) [S_C_VCC: 0x%02x]\n", ext_csd[220]);
868	printf("Sleep current (VCCQ) [S_C_VCCQ: 0x%02x]\n", ext_csd[219]);
869	/* A441/A43: reserved [218] */
870	printf("Sleep/awake timeout [S_A_TIMEOUT: 0x%02x]\n", ext_csd[217]);
871	/* A441/A43: reserved [216] */
872
873	unsigned int sectors =	get_sector_count(ext_csd);
874	printf("Sector Count [SEC_COUNT: 0x%08x]\n", sectors);
875	if (is_blockaddresed(ext_csd))
876		printf(" Device is block-addressed\n");
877	else
878		printf(" Device is NOT block-addressed\n");
879
880	/* A441/A43: reserved [211] */
881	printf("Minimum Write Performance for 8bit:\n");
882	printf(" [MIN_PERF_W_8_52: 0x%02x]\n", ext_csd[210]);
883	printf(" [MIN_PERF_R_8_52: 0x%02x]\n", ext_csd[209]);
884	printf(" [MIN_PERF_W_8_26_4_52: 0x%02x]\n", ext_csd[208]);
885	printf(" [MIN_PERF_R_8_26_4_52: 0x%02x]\n", ext_csd[207]);
886	printf("Minimum Write Performance for 4bit:\n");
887	printf(" [MIN_PERF_W_4_26: 0x%02x]\n", ext_csd[206]);
888	printf(" [MIN_PERF_R_4_26: 0x%02x]\n", ext_csd[205]);
889	/* A441/A43: reserved [204] */
890	printf("Power classes registers:\n");
891	printf(" [PWR_CL_26_360: 0x%02x]\n", ext_csd[203]);
892	printf(" [PWR_CL_52_360: 0x%02x]\n", ext_csd[202]);
893	printf(" [PWR_CL_26_195: 0x%02x]\n", ext_csd[201]);
894	printf(" [PWR_CL_52_195: 0x%02x]\n", ext_csd[200]);
895
896	/* A43: reserved [199:198] */
897	if (ext_csd_rev >= 5) {
898		printf("Partition switching timing "
899			"[PARTITION_SWITCH_TIME: 0x%02x]\n", ext_csd[199]);
900		printf("Out-of-interrupt busy timing"
901			" [OUT_OF_INTERRUPT_TIME: 0x%02x]\n", ext_csd[198]);
902	}
903
904	/* A441/A43: reserved	[197] [195] [193] [190] [188]
905	 * [186] [184] [182] [180] [176] */
906
907	if (ext_csd_rev >= 6)
908		printf("I/O Driver Strength [DRIVER_STRENGTH: 0x%02x]\n",
909			ext_csd[197]);
910
911	/* DEVICE_TYPE in A45, CARD_TYPE in A441 */
912	reg = ext_csd[196];
913	printf("Card Type [CARD_TYPE: 0x%02x]\n", reg);
914	if (reg & 0x20) printf(" HS200 Single Data Rate eMMC @200MHz 1.2VI/O\n");
915	if (reg & 0x10) printf(" HS200 Single Data Rate eMMC @200MHz 1.8VI/O\n");
916	if (reg & 0x08) printf(" HS Dual Data Rate eMMC @52MHz 1.2VI/O\n");
917	if (reg & 0x04)	printf(" HS Dual Data Rate eMMC @52MHz 1.8V or 3VI/O\n");
918	if (reg & 0x02)	printf(" HS eMMC @52MHz - at rated device voltage(s)\n");
919	if (reg & 0x01) printf(" HS eMMC @26MHz - at rated device voltage(s)\n");
920
921	printf("CSD structure version [CSD_STRUCTURE: 0x%02x]\n", ext_csd[194]);
922	/* ext_csd_rev = ext_csd[192] (already done!!!) */
923	printf("Command set [CMD_SET: 0x%02x]\n", ext_csd[191]);
924	printf("Command set revision [CMD_SET_REV: 0x%02x]\n", ext_csd[189]);
925	printf("Power class [POWER_CLASS: 0x%02x]\n", ext_csd[187]);
926	printf("High-speed interface timing [HS_TIMING: 0x%02x]\n",
927		ext_csd[185]);
928	/* bus_width: ext_csd[183] not readable */
929	printf("Erased memory content [ERASED_MEM_CONT: 0x%02x]\n",
930		ext_csd[181]);
931	reg = ext_csd[EXT_CSD_BOOT_CFG];
932	printf("Boot configuration bytes [PARTITION_CONFIG: 0x%02x]\n", reg);
933	switch ((reg & EXT_CSD_BOOT_CFG_EN)>>3) {
934	case 0x0:
935		printf(" Not boot enable\n");
936		break;
937	case 0x1:
938		printf(" Boot Partition 1 enabled\n");
939		break;
940	case 0x2:
941		printf(" Boot Partition 2 enabled\n");
942		break;
943	case 0x7:
944		printf(" User Area Enabled for boot\n");
945		break;
946	}
947	switch (reg & EXT_CSD_BOOT_CFG_ACC) {
948	case 0x0:
949		printf(" No access to boot partition\n");
950		break;
951	case 0x1:
952		printf(" R/W Boot Partition 1\n");
953		break;
954	case 0x2:
955		printf(" R/W Boot Partition 2\n");
956		break;
957	case 0x3:
958		printf(" R/W Replay Protected Memory Block (RPMB)\n");
959		break;
960	default:
961		printf(" Access to General Purpose partition %d\n",
962			(reg & EXT_CSD_BOOT_CFG_ACC) - 3);
963		break;
964	}
965
966	printf("Boot config protection [BOOT_CONFIG_PROT: 0x%02x]\n",
967		ext_csd[178]);
968	printf("Boot bus Conditions [BOOT_BUS_CONDITIONS: 0x%02x]\n",
969		ext_csd[177]);
970	printf("High-density erase group definition"
971		" [ERASE_GROUP_DEF: 0x%02x]\n", ext_csd[EXT_CSD_ERASE_GROUP_DEF]);
972
973	print_writeprotect_status(ext_csd);
974
975	if (ext_csd_rev >= 5) {
976		/* A441]: reserved [172] */
977		printf("User area write protection register"
978			" [USER_WP]: 0x%02x\n", ext_csd[171]);
979		/* A441]: reserved [170] */
980		printf("FW configuration [FW_CONFIG]: 0x%02x\n", ext_csd[169]);
981		printf("RPMB Size [RPMB_SIZE_MULT]: 0x%02x\n", ext_csd[168]);
982
983		reg = ext_csd[EXT_CSD_WR_REL_SET];
984		const char * const fast = "existing data is at risk if a power "
985				"failure occurs during a write operation";
986		const char * const reliable = "the device protects existing "
987				"data if a power failure occurs during a write "
988				"operation";
989		printf("Write reliability setting register"
990			" [WR_REL_SET]: 0x%02x\n", reg);
991
992		printf(" user area: %s\n", reg & (1<<0) ? reliable : fast);
993		int i;
994		for (i = 1; i <= 4; i++) {
995			printf(" partition %d: %s\n", i,
996				reg & (1<<i) ? reliable : fast);
997		}
998
999		reg = ext_csd[EXT_CSD_WR_REL_PARAM];
1000		printf("Write reliability parameter register"
1001			" [WR_REL_PARAM]: 0x%02x\n", reg);
1002		if (reg & 0x01)
1003			printf(" Device supports writing EXT_CSD_WR_REL_SET\n");
1004		if (reg & 0x04)
1005			printf(" Device supports the enhanced def. of reliable "
1006				"write\n");
1007
1008		/* sanitize_start ext_csd[165]]: not readable
1009		 * bkops_start ext_csd[164]]: only writable */
1010		printf("Enable background operations handshake"
1011			" [BKOPS_EN]: 0x%02x\n", ext_csd[163]);
1012		printf("H/W reset function"
1013			" [RST_N_FUNCTION]: 0x%02x\n", ext_csd[162]);
1014		printf("HPI management [HPI_MGMT]: 0x%02x\n", ext_csd[161]);
1015		reg = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
1016		printf("Partitioning Support [PARTITIONING_SUPPORT]: 0x%02x\n",
1017			reg);
1018		if (reg & EXT_CSD_PARTITIONING_EN)
1019			printf(" Device support partitioning feature\n");
1020		else
1021			printf(" Device NOT support partitioning feature\n");
1022		if (reg & EXT_CSD_ENH_ATTRIBUTE_EN)
1023			printf(" Device can have enhanced tech.\n");
1024		else
1025			printf(" Device cannot have enhanced tech.\n");
1026
1027		reg = (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_2] << 16) |
1028			(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_1] << 8) |
1029			ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT_0];
1030
1031		printf("Max Enhanced Area Size [MAX_ENH_SIZE_MULT]: 0x%06x\n",
1032			   reg);
1033		unsigned int wp_sz = get_hc_wp_grp_size(ext_csd);
1034		unsigned int erase_sz = get_hc_erase_grp_size(ext_csd);
1035		printf(" i.e. %lu KiB\n", 512l * reg * wp_sz * erase_sz);
1036
1037		printf("Partitions attribute [PARTITIONS_ATTRIBUTE]: 0x%02x\n",
1038			ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]);
1039		reg = ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED];
1040		printf("Partitioning Setting"
1041			" [PARTITION_SETTING_COMPLETED]: 0x%02x\n",
1042			reg);
1043		if (reg)
1044			printf(" Device partition setting complete\n");
1045		else
1046			printf(" Device partition setting NOT complete\n");
1047
1048		printf("General Purpose Partition Size\n"
1049			" [GP_SIZE_MULT_4]: 0x%06x\n", (ext_csd[154] << 16) |
1050			(ext_csd[153] << 8) | ext_csd[152]);
1051		printf(" [GP_SIZE_MULT_3]: 0x%06x\n", (ext_csd[151] << 16) |
1052			   (ext_csd[150] << 8) | ext_csd[149]);
1053		printf(" [GP_SIZE_MULT_2]: 0x%06x\n", (ext_csd[148] << 16) |
1054			   (ext_csd[147] << 8) | ext_csd[146]);
1055		printf(" [GP_SIZE_MULT_1]: 0x%06x\n", (ext_csd[145] << 16) |
1056			   (ext_csd[144] << 8) | ext_csd[143]);
1057
1058		reg =	(ext_csd[EXT_CSD_ENH_SIZE_MULT_2] << 16) |
1059			(ext_csd[EXT_CSD_ENH_SIZE_MULT_1] << 8) |
1060			ext_csd[EXT_CSD_ENH_SIZE_MULT_0];
1061		printf("Enhanced User Data Area Size"
1062			" [ENH_SIZE_MULT]: 0x%06x\n", reg);
1063		printf(" i.e. %lu KiB\n", 512l * reg *
1064		       get_hc_erase_grp_size(ext_csd) *
1065		       get_hc_wp_grp_size(ext_csd));
1066
1067		reg =	(ext_csd[EXT_CSD_ENH_START_ADDR_3] << 24) |
1068			(ext_csd[EXT_CSD_ENH_START_ADDR_2] << 16) |
1069			(ext_csd[EXT_CSD_ENH_START_ADDR_1] << 8) |
1070			ext_csd[EXT_CSD_ENH_START_ADDR_0];
1071		printf("Enhanced User Data Start Address"
1072			" [ENH_START_ADDR]: 0x%06x\n", reg);
1073		printf(" i.e. %lu bytes offset\n", (is_blockaddresed(ext_csd) ?
1074				1l : 512l) * reg);
1075
1076		/* A441]: reserved [135] */
1077		printf("Bad Block Management mode"
1078			" [SEC_BAD_BLK_MGMNT]: 0x%02x\n", ext_csd[134]);
1079		/* A441: reserved [133:0] */
1080	}
1081	/* B45 */
1082	if (ext_csd_rev >= 6) {
1083		int j;
1084		/* tcase_support ext_csd[132] not readable */
1085		printf("Periodic Wake-up [PERIODIC_WAKEUP]: 0x%02x\n",
1086			ext_csd[131]);
1087		printf("Program CID/CSD in DDR mode support"
1088			" [PROGRAM_CID_CSD_DDR_SUPPORT]: 0x%02x\n",
1089			   ext_csd[130]);
1090
1091		for (j = 127; j >= 64; j--)
1092			printf("Vendor Specific Fields"
1093				" [VENDOR_SPECIFIC_FIELD[%d]]: 0x%02x\n",
1094				j, ext_csd[j]);
1095
1096		printf("Native sector size [NATIVE_SECTOR_SIZE]: 0x%02x\n",
1097			ext_csd[63]);
1098		printf("Sector size emulation [USE_NATIVE_SECTOR]: 0x%02x\n",
1099			ext_csd[62]);
1100		printf("Sector size [DATA_SECTOR_SIZE]: 0x%02x\n", ext_csd[61]);
1101		printf("1st initialization after disabling sector"
1102			" size emulation [INI_TIMEOUT_EMU]: 0x%02x\n",
1103			ext_csd[60]);
1104		printf("Class 6 commands control [CLASS_6_CTRL]: 0x%02x\n",
1105			ext_csd[59]);
1106		printf("Number of addressed group to be Released"
1107			"[DYNCAP_NEEDED]: 0x%02x\n", ext_csd[58]);
1108		printf("Exception events control"
1109			" [EXCEPTION_EVENTS_CTRL]: 0x%04x\n",
1110			(ext_csd[57] << 8) | ext_csd[56]);
1111		printf("Exception events status"
1112			"[EXCEPTION_EVENTS_STATUS]: 0x%04x\n",
1113			(ext_csd[55] << 8) | ext_csd[54]);
1114		printf("Extended Partitions Attribute"
1115			" [EXT_PARTITIONS_ATTRIBUTE]: 0x%04x\n",
1116			(ext_csd[53] << 8) | ext_csd[52]);
1117
1118		for (j = 51; j >= 37; j--)
1119			printf("Context configuration"
1120				" [CONTEXT_CONF[%d]]: 0x%02x\n", j, ext_csd[j]);
1121
1122		printf("Packed command status"
1123			" [PACKED_COMMAND_STATUS]: 0x%02x\n", ext_csd[36]);
1124		printf("Packed command failure index"
1125			" [PACKED_FAILURE_INDEX]: 0x%02x\n", ext_csd[35]);
1126		printf("Power Off Notification"
1127			" [POWER_OFF_NOTIFICATION]: 0x%02x\n", ext_csd[34]);
1128		printf("Control to turn the Cache ON/OFF"
1129			" [CACHE_CTRL]: 0x%02x\n", ext_csd[33]);
1130		/* flush_cache ext_csd[32] not readable */
1131		/*Reserved [31:0] */
1132	}
1133
1134out_free:
1135	return ret;
1136}
1137
1138int do_sanitize(int nargs, char **argv)
1139{
1140	int fd, ret;
1141	char *device;
1142
1143	CHECK(nargs != 2, "Usage: mmc sanitize </path/to/mmcblkX>\n",
1144			exit(1));
1145
1146	device = argv[1];
1147
1148	fd = open(device, O_RDWR);
1149	if (fd < 0) {
1150		perror("open");
1151		exit(1);
1152	}
1153
1154	ret = write_extcsd_value(fd, EXT_CSD_SANITIZE_START, 1);
1155	if (ret) {
1156		fprintf(stderr, "Could not write 0x%02x to EXT_CSD[%d] in %s\n",
1157			1, EXT_CSD_SANITIZE_START, device);
1158		exit(1);
1159	}
1160
1161	return ret;
1162
1163}
1164
1165