xref: /openbmc/u-boot/disk/part.c (revision 1d6edcbf)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2affae2bfSwdenk /*
3affae2bfSwdenk  * (C) Copyright 2001
4affae2bfSwdenk  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5affae2bfSwdenk  */
6affae2bfSwdenk 
7affae2bfSwdenk #include <common.h>
8affae2bfSwdenk #include <command.h>
996e5b03cSSimon Glass #include <errno.h>
10affae2bfSwdenk #include <ide.h>
1110a37fd7SStephen Warren #include <malloc.h>
12735dd97bSGrant Likely #include <part.h>
13251cee0dSHans de Goede #include <ubifs_uboot.h>
14affae2bfSwdenk 
15affae2bfSwdenk #undef	PART_DEBUG
16affae2bfSwdenk 
17affae2bfSwdenk #ifdef	PART_DEBUG
18affae2bfSwdenk #define	PRINTF(fmt,args...)	printf (fmt ,##args)
19affae2bfSwdenk #else
20affae2bfSwdenk #define PRINTF(fmt,args...)
21affae2bfSwdenk #endif
22affae2bfSwdenk 
2330789095SSam Protsenko /* Check all partition types */
2430789095SSam Protsenko #define PART_TYPE_ALL		-1
2530789095SSam Protsenko 
part_driver_lookup_type(struct blk_desc * dev_desc)26d4729269SKever Yang static struct part_driver *part_driver_lookup_type(struct blk_desc *dev_desc)
2796e5b03cSSimon Glass {
2896e5b03cSSimon Glass 	struct part_driver *drv =
2996e5b03cSSimon Glass 		ll_entry_start(struct part_driver, part_driver);
3096e5b03cSSimon Glass 	const int n_ents = ll_entry_count(struct part_driver, part_driver);
3196e5b03cSSimon Glass 	struct part_driver *entry;
3296e5b03cSSimon Glass 
33d4729269SKever Yang 	if (dev_desc->part_type == PART_TYPE_UNKNOWN) {
3496e5b03cSSimon Glass 		for (entry = drv; entry != drv + n_ents; entry++) {
35d4729269SKever Yang 			int ret;
36d4729269SKever Yang 
37d4729269SKever Yang 			ret = entry->test(dev_desc);
38d4729269SKever Yang 			if (!ret) {
39d4729269SKever Yang 				dev_desc->part_type = entry->part_type;
4096e5b03cSSimon Glass 				return entry;
4196e5b03cSSimon Glass 			}
42d4729269SKever Yang 		}
43d4729269SKever Yang 	} else {
44d4729269SKever Yang 		for (entry = drv; entry != drv + n_ents; entry++) {
45d4729269SKever Yang 			if (dev_desc->part_type == entry->part_type)
46d4729269SKever Yang 				return entry;
47d4729269SKever Yang 		}
48d4729269SKever Yang 	}
4996e5b03cSSimon Glass 
5096e5b03cSSimon Glass 	/* Not found */
5196e5b03cSSimon Glass 	return NULL;
5296e5b03cSSimon Glass }
5396e5b03cSSimon Glass 
5456670d6fSKever Yang #ifdef CONFIG_HAVE_BLOCK_DEVICE
get_dev_hwpart(const char * ifname,int dev,int hwpart)554101f687SSimon Glass static struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart)
56735dd97bSGrant Likely {
57a6331fa8SSimon Glass 	struct blk_desc *dev_desc;
586dd9faf8SSimon Glass 	int ret;
59a6331fa8SSimon Glass 
606dd9faf8SSimon Glass 	dev_desc = blk_get_devnum_by_typename(ifname, dev);
616dd9faf8SSimon Glass 	if (!dev_desc) {
626dd9faf8SSimon Glass 		debug("%s: No device for iface '%s', dev %d\n", __func__,
636dd9faf8SSimon Glass 		      ifname, dev);
64336b6f90SStephen Warren 		return NULL;
656dd9faf8SSimon Glass 	}
666dd9faf8SSimon Glass 	ret = blk_dselect_hwpart(dev_desc, hwpart);
676dd9faf8SSimon Glass 	if (ret) {
686dd9faf8SSimon Glass 		debug("%s: Failed to select h/w partition: err-%d\n", __func__,
696dd9faf8SSimon Glass 		      ret);
70336b6f90SStephen Warren 		return NULL;
716dd9faf8SSimon Glass 	}
726dd9faf8SSimon Glass 
73336b6f90SStephen Warren 	return dev_desc;
74336b6f90SStephen Warren }
75336b6f90SStephen Warren 
blk_get_dev(const char * ifname,int dev)76db1d9e78SSimon Glass struct blk_desc *blk_get_dev(const char *ifname, int dev)
77336b6f90SStephen Warren {
78ecdd57e2SStephen Warren 	return get_dev_hwpart(ifname, dev, 0);
79336b6f90SStephen Warren }
80735dd97bSGrant Likely #else
get_dev_hwpart(const char * ifname,int dev,int hwpart)814101f687SSimon Glass struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart)
82336b6f90SStephen Warren {
83336b6f90SStephen Warren 	return NULL;
84336b6f90SStephen Warren }
85336b6f90SStephen Warren 
blk_get_dev(const char * ifname,int dev)86db1d9e78SSimon Glass struct blk_desc *blk_get_dev(const char *ifname, int dev)
87735dd97bSGrant Likely {
88735dd97bSGrant Likely 	return NULL;
89735dd97bSGrant Likely }
90735dd97bSGrant Likely #endif
91735dd97bSGrant Likely 
921811a928SAdam Ford #ifdef CONFIG_HAVE_BLOCK_DEVICE
93735dd97bSGrant Likely 
94affae2bfSwdenk /* ------------------------------------------------------------------------- */
95affae2bfSwdenk /*
96affae2bfSwdenk  * reports device info to the user
97affae2bfSwdenk  */
9869a2a4d9SSergei Trofimovich 
9969a2a4d9SSergei Trofimovich #ifdef CONFIG_LBA48
10069a2a4d9SSergei Trofimovich typedef uint64_t lba512_t;
10169a2a4d9SSergei Trofimovich #else
10269a2a4d9SSergei Trofimovich typedef lbaint_t lba512_t;
10369a2a4d9SSergei Trofimovich #endif
10469a2a4d9SSergei Trofimovich 
10569a2a4d9SSergei Trofimovich /*
10669a2a4d9SSergei Trofimovich  * Overflowless variant of (block_count * mul_by / div_by)
10769a2a4d9SSergei Trofimovich  * when div_by > mul_by
10869a2a4d9SSergei Trofimovich  */
lba512_muldiv(lba512_t block_count,lba512_t mul_by,lba512_t div_by)10969a2a4d9SSergei Trofimovich static lba512_t lba512_muldiv(lba512_t block_count, lba512_t mul_by, lba512_t div_by)
11069a2a4d9SSergei Trofimovich {
11169a2a4d9SSergei Trofimovich 	lba512_t bc_quot, bc_rem;
11269a2a4d9SSergei Trofimovich 
11369a2a4d9SSergei Trofimovich 	/* x * m / d == x / d * m + (x % d) * m / d */
11469a2a4d9SSergei Trofimovich 	bc_quot = block_count / div_by;
11569a2a4d9SSergei Trofimovich 	bc_rem  = block_count - div_by * bc_quot;
11669a2a4d9SSergei Trofimovich 	return bc_quot * mul_by + (bc_rem * mul_by) / div_by;
11769a2a4d9SSergei Trofimovich }
11869a2a4d9SSergei Trofimovich 
dev_print(struct blk_desc * dev_desc)1194101f687SSimon Glass void dev_print (struct blk_desc *dev_desc)
120affae2bfSwdenk {
12169a2a4d9SSergei Trofimovich 	lba512_t lba512; /* number of blocks if 512bytes block size */
122affae2bfSwdenk 
123af75a45dSWolfgang Denk 	if (dev_desc->type == DEV_TYPE_UNKNOWN) {
124af75a45dSWolfgang Denk 		puts ("not available\n");
125af75a45dSWolfgang Denk 		return;
126af75a45dSWolfgang Denk 	}
127af75a45dSWolfgang Denk 
1288ec6e332STor Krill 	switch (dev_desc->if_type) {
129574b3195SDetlev Zundel 	case IF_TYPE_SCSI:
130574b3195SDetlev Zundel 		printf ("(%d:%d) Vendor: %s Prod.: %s Rev: %s\n",
131574b3195SDetlev Zundel 			dev_desc->target,dev_desc->lun,
132affae2bfSwdenk 			dev_desc->vendor,
133affae2bfSwdenk 			dev_desc->product,
134affae2bfSwdenk 			dev_desc->revision);
135574b3195SDetlev Zundel 		break;
1366e24a1ebSRemy Bohmer 	case IF_TYPE_ATAPI:
137574b3195SDetlev Zundel 	case IF_TYPE_IDE:
138574b3195SDetlev Zundel 	case IF_TYPE_SATA:
139574b3195SDetlev Zundel 		printf ("Model: %s Firm: %s Ser#: %s\n",
140574b3195SDetlev Zundel 			dev_desc->vendor,
141574b3195SDetlev Zundel 			dev_desc->revision,
142574b3195SDetlev Zundel 			dev_desc->product);
143574b3195SDetlev Zundel 		break;
1446e24a1ebSRemy Bohmer 	case IF_TYPE_SD:
1456e24a1ebSRemy Bohmer 	case IF_TYPE_MMC:
14647bebe34SNícolas Carneiro Lebedenco 	case IF_TYPE_USB:
147ffab6945SZhikang Zhang 	case IF_TYPE_NVME:
14847bebe34SNícolas Carneiro Lebedenco 		printf ("Vendor: %s Rev: %s Prod: %s\n",
14947bebe34SNícolas Carneiro Lebedenco 			dev_desc->vendor,
15047bebe34SNícolas Carneiro Lebedenco 			dev_desc->revision,
15147bebe34SNícolas Carneiro Lebedenco 			dev_desc->product);
15247bebe34SNícolas Carneiro Lebedenco 		break;
153*4ad54ec4STuomas Tynkkynen 	case IF_TYPE_VIRTIO:
154*4ad54ec4STuomas Tynkkynen 		printf("%s VirtIO Block Device\n", dev_desc->vendor);
155*4ad54ec4STuomas Tynkkynen 		break;
1566e24a1ebSRemy Bohmer 	case IF_TYPE_DOC:
1576e24a1ebSRemy Bohmer 		puts("device type DOC\n");
1586e24a1ebSRemy Bohmer 		return;
1598ec6e332STor Krill 	case IF_TYPE_UNKNOWN:
1606e24a1ebSRemy Bohmer 		puts("device type unknown\n");
1616e24a1ebSRemy Bohmer 		return;
162574b3195SDetlev Zundel 	default:
1636e24a1ebSRemy Bohmer 		printf("Unhandled device type: %i\n", dev_desc->if_type);
164574b3195SDetlev Zundel 		return;
165affae2bfSwdenk 	}
166affae2bfSwdenk 	puts ("            Type: ");
167affae2bfSwdenk 	if (dev_desc->removable)
168affae2bfSwdenk 		puts ("Removable ");
169affae2bfSwdenk 	switch (dev_desc->type & 0x1F) {
170726c0f1eSDetlev Zundel 	case DEV_TYPE_HARDDISK:
171726c0f1eSDetlev Zundel 		puts ("Hard Disk");
172affae2bfSwdenk 		break;
173726c0f1eSDetlev Zundel 	case DEV_TYPE_CDROM:
174726c0f1eSDetlev Zundel 		puts ("CD ROM");
175affae2bfSwdenk 		break;
176726c0f1eSDetlev Zundel 	case DEV_TYPE_OPDISK:
177726c0f1eSDetlev Zundel 		puts ("Optical Device");
178affae2bfSwdenk 		break;
179726c0f1eSDetlev Zundel 	case DEV_TYPE_TAPE:
180726c0f1eSDetlev Zundel 		puts ("Tape");
181affae2bfSwdenk 		break;
182726c0f1eSDetlev Zundel 	default:
183726c0f1eSDetlev Zundel 		printf ("# %02X #", dev_desc->type & 0x1F);
184affae2bfSwdenk 		break;
185affae2bfSwdenk 	}
186affae2bfSwdenk 	puts ("\n");
18733699df1SJerry Huang 	if (dev_desc->lba > 0L && dev_desc->blksz > 0L) {
188affae2bfSwdenk 		ulong mb, mb_quot, mb_rem, gb, gb_quot, gb_rem;
189c40b2956Swdenk 		lbaint_t lba;
1906e592385Swdenk 
191c40b2956Swdenk 		lba = dev_desc->lba;
192affae2bfSwdenk 
193c40b2956Swdenk 		lba512 = (lba * (dev_desc->blksz/512));
194affae2bfSwdenk 		/* round to 1 digit */
195214b3f31SPavel Machek 		/* 2048 = (1024 * 1024) / 512 MB */
196214b3f31SPavel Machek 		mb = lba512_muldiv(lba512, 10, 2048);
19769a2a4d9SSergei Trofimovich 
198affae2bfSwdenk 		mb_quot	= mb / 10;
199affae2bfSwdenk 		mb_rem	= mb - (10 * mb_quot);
200affae2bfSwdenk 
201affae2bfSwdenk 		gb = mb / 1024;
202affae2bfSwdenk 		gb_quot	= gb / 10;
203affae2bfSwdenk 		gb_rem	= gb - (10 * gb_quot);
20442dfe7a1Swdenk #ifdef CONFIG_LBA48
2056e592385Swdenk 		if (dev_desc->lba48)
206c40b2956Swdenk 			printf ("            Supports 48-bit addressing\n");
207c40b2956Swdenk #endif
2084b142febSHeiko Schocher #if defined(CONFIG_SYS_64BIT_LBA)
209139f7b1dSJean-Jacques Hiblot 		printf ("            Capacity: %lu.%lu MB = %lu.%lu GB (%llu x %lu)\n",
210c40b2956Swdenk 			mb_quot, mb_rem,
211c40b2956Swdenk 			gb_quot, gb_rem,
212c40b2956Swdenk 			lba,
213c40b2956Swdenk 			dev_desc->blksz);
214c40b2956Swdenk #else
215139f7b1dSJean-Jacques Hiblot 		printf ("            Capacity: %lu.%lu MB = %lu.%lu GB (%lu x %lu)\n",
216affae2bfSwdenk 			mb_quot, mb_rem,
217affae2bfSwdenk 			gb_quot, gb_rem,
218c40b2956Swdenk 			(ulong)lba,
219affae2bfSwdenk 			dev_desc->blksz);
220c40b2956Swdenk #endif
221affae2bfSwdenk 	} else {
222affae2bfSwdenk 		puts ("            Capacity: not available\n");
223affae2bfSwdenk 	}
224affae2bfSwdenk }
225b3aff0cbSJon Loeliger #endif
226affae2bfSwdenk 
2271811a928SAdam Ford #ifdef CONFIG_HAVE_BLOCK_DEVICE
228affae2bfSwdenk 
part_init(struct blk_desc * dev_desc)2293e8bd469SSimon Glass void part_init(struct blk_desc *dev_desc)
230affae2bfSwdenk {
23196e5b03cSSimon Glass 	struct part_driver *drv =
23296e5b03cSSimon Glass 		ll_entry_start(struct part_driver, part_driver);
23396e5b03cSSimon Glass 	const int n_ents = ll_entry_count(struct part_driver, part_driver);
23496e5b03cSSimon Glass 	struct part_driver *entry;
235affae2bfSwdenk 
236e40cf34aSEric Nelson 	blkcache_invalidate(dev_desc->if_type, dev_desc->devnum);
237e40cf34aSEric Nelson 
23899d2c205SRob Herring 	dev_desc->part_type = PART_TYPE_UNKNOWN;
23996e5b03cSSimon Glass 	for (entry = drv; entry != drv + n_ents; entry++) {
24096e5b03cSSimon Glass 		int ret;
24196e5b03cSSimon Glass 
24296e5b03cSSimon Glass 		ret = entry->test(dev_desc);
24396e5b03cSSimon Glass 		debug("%s: try '%s': ret=%d\n", __func__, entry->name, ret);
24496e5b03cSSimon Glass 		if (!ret) {
24596e5b03cSSimon Glass 			dev_desc->part_type = entry->part_type;
24696e5b03cSSimon Glass 			break;
24796e5b03cSSimon Glass 		}
24896e5b03cSSimon Glass 	}
249affae2bfSwdenk }
250affae2bfSwdenk 
print_part_header(const char * type,struct blk_desc * dev_desc)25196e5b03cSSimon Glass static void print_part_header(const char *type, struct blk_desc *dev_desc)
25296e5b03cSSimon Glass {
253f18fa31cSPatrick Delaunay #if CONFIG_IS_ENABLED(MAC_PARTITION) || \
254b0cf7339SPatrick Delaunay 	CONFIG_IS_ENABLED(DOS_PARTITION) || \
2551acc0087SPatrick Delaunay 	CONFIG_IS_ENABLED(ISO_PARTITION) || \
256863c5b6cSPatrick Delaunay 	CONFIG_IS_ENABLED(AMIGA_PARTITION) || \
257bd42a942SPatrick Delaunay 	CONFIG_IS_ENABLED(EFI_PARTITION)
258affae2bfSwdenk 	puts ("\nPartition Map for ");
259affae2bfSwdenk 	switch (dev_desc->if_type) {
260726c0f1eSDetlev Zundel 	case IF_TYPE_IDE:
261726c0f1eSDetlev Zundel 		puts ("IDE");
262affae2bfSwdenk 		break;
263726c0f1eSDetlev Zundel 	case IF_TYPE_SATA:
264726c0f1eSDetlev Zundel 		puts ("SATA");
265c7057b52SDave Liu 		break;
266726c0f1eSDetlev Zundel 	case IF_TYPE_SCSI:
267726c0f1eSDetlev Zundel 		puts ("SCSI");
268affae2bfSwdenk 		break;
269726c0f1eSDetlev Zundel 	case IF_TYPE_ATAPI:
270726c0f1eSDetlev Zundel 		puts ("ATAPI");
271affae2bfSwdenk 		break;
272726c0f1eSDetlev Zundel 	case IF_TYPE_USB:
273726c0f1eSDetlev Zundel 		puts ("USB");
274affae2bfSwdenk 		break;
275726c0f1eSDetlev Zundel 	case IF_TYPE_DOC:
276726c0f1eSDetlev Zundel 		puts ("DOC");
277affae2bfSwdenk 		break;
2788f3b9642SLei Wen 	case IF_TYPE_MMC:
2798f3b9642SLei Wen 		puts ("MMC");
2808f3b9642SLei Wen 		break;
281f4d8de48SHenrik Nordström 	case IF_TYPE_HOST:
282f4d8de48SHenrik Nordström 		puts ("HOST");
283f4d8de48SHenrik Nordström 		break;
284ffab6945SZhikang Zhang 	case IF_TYPE_NVME:
285ffab6945SZhikang Zhang 		puts ("NVMe");
286ffab6945SZhikang Zhang 		break;
287*4ad54ec4STuomas Tynkkynen 	case IF_TYPE_VIRTIO:
288*4ad54ec4STuomas Tynkkynen 		puts("VirtIO");
289*4ad54ec4STuomas Tynkkynen 		break;
290726c0f1eSDetlev Zundel 	default:
291726c0f1eSDetlev Zundel 		puts ("UNKNOWN");
292affae2bfSwdenk 		break;
293affae2bfSwdenk 	}
294affae2bfSwdenk 	printf (" device %d  --   Partition Type: %s\n\n",
295bcce53d0SSimon Glass 			dev_desc->devnum, type);
2960c9c8fb5SGabe Black #endif /* any CONFIG_..._PARTITION */
29796e5b03cSSimon Glass }
2980c9c8fb5SGabe Black 
part_print(struct blk_desc * dev_desc)2993e8bd469SSimon Glass void part_print(struct blk_desc *dev_desc)
300affae2bfSwdenk {
30196e5b03cSSimon Glass 	struct part_driver *drv;
302affae2bfSwdenk 
303d4729269SKever Yang 	drv = part_driver_lookup_type(dev_desc);
30496e5b03cSSimon Glass 	if (!drv) {
30596e5b03cSSimon Glass 		printf("## Unknown partition table type %x\n",
30696e5b03cSSimon Glass 		       dev_desc->part_type);
307affae2bfSwdenk 		return;
308affae2bfSwdenk 	}
30996e5b03cSSimon Glass 
31096e5b03cSSimon Glass 	PRINTF("## Testing for valid %s partition ##\n", drv->name);
31196e5b03cSSimon Glass 	print_part_header(drv->name, dev_desc);
31296e5b03cSSimon Glass 	if (drv->print)
31396e5b03cSSimon Glass 		drv->print(dev_desc);
314affae2bfSwdenk }
315affae2bfSwdenk 
3161811a928SAdam Ford #endif /* CONFIG_HAVE_BLOCK_DEVICE */
3172f501646SStephen Warren 
part_get_info(struct blk_desc * dev_desc,int part,disk_partition_t * info)3183e8bd469SSimon Glass int part_get_info(struct blk_desc *dev_desc, int part,
3193f9eb6e1SPavel Machek 		       disk_partition_t *info)
3202f501646SStephen Warren {
3211811a928SAdam Ford #ifdef CONFIG_HAVE_BLOCK_DEVICE
32296e5b03cSSimon Glass 	struct part_driver *drv;
3232f501646SStephen Warren 
324b331cd62SPatrick Delaunay #if CONFIG_IS_ENABLED(PARTITION_UUIDS)
325894bfbbfSStephen Warren 	/* The common case is no UUID support */
326894bfbbfSStephen Warren 	info->uuid[0] = 0;
327894bfbbfSStephen Warren #endif
3287561b258SPatrick Delaunay #ifdef CONFIG_PARTITION_TYPE_GUID
3297561b258SPatrick Delaunay 	info->type_guid[0] = 0;
3307561b258SPatrick Delaunay #endif
331894bfbbfSStephen Warren 
332d4729269SKever Yang 	drv = part_driver_lookup_type(dev_desc);
33396e5b03cSSimon Glass 	if (!drv) {
33496e5b03cSSimon Glass 		debug("## Unknown partition table type %x\n",
33596e5b03cSSimon Glass 		      dev_desc->part_type);
33696e5b03cSSimon Glass 		return -EPROTONOSUPPORT;
3372f501646SStephen Warren 	}
33896e5b03cSSimon Glass 	if (!drv->get_info) {
3392ae67aecSNishanth Menon 		PRINTF("## Driver %s does not have the get_info() method\n",
3402ae67aecSNishanth Menon 		       drv->name);
34196e5b03cSSimon Glass 		return -ENOSYS;
3422f501646SStephen Warren 	}
34396e5b03cSSimon Glass 	if (drv->get_info(dev_desc, part, info) == 0) {
34496e5b03cSSimon Glass 		PRINTF("## Valid %s partition found ##\n", drv->name);
3452f501646SStephen Warren 		return 0;
3462f501646SStephen Warren 	}
3471811a928SAdam Ford #endif /* CONFIG_HAVE_BLOCK_DEVICE */
3482f501646SStephen Warren 
3492f501646SStephen Warren 	return -1;
3502f501646SStephen Warren }
35199d2c205SRob Herring 
part_get_info_whole_disk(struct blk_desc * dev_desc,disk_partition_t * info)3524bbcc965SRob Clark int part_get_info_whole_disk(struct blk_desc *dev_desc, disk_partition_t *info)
3534bbcc965SRob Clark {
3544bbcc965SRob Clark 	info->start = 0;
3554bbcc965SRob Clark 	info->size = dev_desc->lba;
3564bbcc965SRob Clark 	info->blksz = dev_desc->blksz;
3574bbcc965SRob Clark 	info->bootable = 0;
3584bbcc965SRob Clark 	strcpy((char *)info->type, BOOT_PART_TYPE);
3594bbcc965SRob Clark 	strcpy((char *)info->name, "Whole Disk");
3604bbcc965SRob Clark #if CONFIG_IS_ENABLED(PARTITION_UUIDS)
3614bbcc965SRob Clark 	info->uuid[0] = 0;
3624bbcc965SRob Clark #endif
3634bbcc965SRob Clark #ifdef CONFIG_PARTITION_TYPE_GUID
3644bbcc965SRob Clark 	info->type_guid[0] = 0;
3654bbcc965SRob Clark #endif
3664bbcc965SRob Clark 
3674bbcc965SRob Clark 	return 0;
3684bbcc965SRob Clark }
3694bbcc965SRob Clark 
blk_get_device_by_str(const char * ifname,const char * dev_hwpart_str,struct blk_desc ** dev_desc)370ebac37cfSSimon Glass int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str,
3714101f687SSimon Glass 			  struct blk_desc **dev_desc)
3722023e608SStephen Warren {
3732023e608SStephen Warren 	char *ep;
374336b6f90SStephen Warren 	char *dup_str = NULL;
375336b6f90SStephen Warren 	const char *dev_str, *hwpart_str;
376336b6f90SStephen Warren 	int dev, hwpart;
377336b6f90SStephen Warren 
378336b6f90SStephen Warren 	hwpart_str = strchr(dev_hwpart_str, '.');
379336b6f90SStephen Warren 	if (hwpart_str) {
380336b6f90SStephen Warren 		dup_str = strdup(dev_hwpart_str);
381336b6f90SStephen Warren 		dup_str[hwpart_str - dev_hwpart_str] = 0;
382336b6f90SStephen Warren 		dev_str = dup_str;
383336b6f90SStephen Warren 		hwpart_str++;
384336b6f90SStephen Warren 	} else {
385336b6f90SStephen Warren 		dev_str = dev_hwpart_str;
386ecdd57e2SStephen Warren 		hwpart = 0;
387336b6f90SStephen Warren 	}
3882023e608SStephen Warren 
3892023e608SStephen Warren 	dev = simple_strtoul(dev_str, &ep, 16);
3902023e608SStephen Warren 	if (*ep) {
3912023e608SStephen Warren 		printf("** Bad device specification %s %s **\n",
3922023e608SStephen Warren 		       ifname, dev_str);
3931598dfcbSSimon Glass 		dev = -EINVAL;
394336b6f90SStephen Warren 		goto cleanup;
3952023e608SStephen Warren 	}
3962023e608SStephen Warren 
397336b6f90SStephen Warren 	if (hwpart_str) {
398336b6f90SStephen Warren 		hwpart = simple_strtoul(hwpart_str, &ep, 16);
399336b6f90SStephen Warren 		if (*ep) {
400336b6f90SStephen Warren 			printf("** Bad HW partition specification %s %s **\n",
401336b6f90SStephen Warren 			    ifname, hwpart_str);
4021598dfcbSSimon Glass 			dev = -EINVAL;
403336b6f90SStephen Warren 			goto cleanup;
404336b6f90SStephen Warren 		}
405336b6f90SStephen Warren 	}
406336b6f90SStephen Warren 
407336b6f90SStephen Warren 	*dev_desc = get_dev_hwpart(ifname, dev, hwpart);
4082023e608SStephen Warren 	if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) {
4098f690848SSam Protsenko 		debug("** Bad device %s %s **\n", ifname, dev_hwpart_str);
4101598dfcbSSimon Glass 		dev = -ENOENT;
411336b6f90SStephen Warren 		goto cleanup;
4122023e608SStephen Warren 	}
4132023e608SStephen Warren 
4141811a928SAdam Ford #ifdef CONFIG_HAVE_BLOCK_DEVICE
41599e7fc8aSErik Tideman 	/*
41699e7fc8aSErik Tideman 	 * Updates the partition table for the specified hw partition.
41799e7fc8aSErik Tideman 	 * Does not need to be done for hwpart 0 since it is default and
41899e7fc8aSErik Tideman 	 * already loaded.
41999e7fc8aSErik Tideman 	 */
42099e7fc8aSErik Tideman 	if(hwpart != 0)
4213e8bd469SSimon Glass 		part_init(*dev_desc);
42299e7fc8aSErik Tideman #endif
42399e7fc8aSErik Tideman 
424336b6f90SStephen Warren cleanup:
425336b6f90SStephen Warren 	free(dup_str);
4262023e608SStephen Warren 	return dev;
4272023e608SStephen Warren }
4282023e608SStephen Warren 
42910a37fd7SStephen Warren #define PART_UNSPECIFIED -2
43010a37fd7SStephen Warren #define PART_AUTO -1
blk_get_device_part_str(const char * ifname,const char * dev_part_str,struct blk_desc ** dev_desc,disk_partition_t * info,int allow_whole_dev)431e35929e4SSimon Glass int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
4324101f687SSimon Glass 			     struct blk_desc **dev_desc,
43310a37fd7SStephen Warren 			     disk_partition_t *info, int allow_whole_dev)
43499d2c205SRob Herring {
43510a37fd7SStephen Warren 	int ret = -1;
43610a37fd7SStephen Warren 	const char *part_str;
43710a37fd7SStephen Warren 	char *dup_str = NULL;
43810a37fd7SStephen Warren 	const char *dev_str;
43999d2c205SRob Herring 	int dev;
44010a37fd7SStephen Warren 	char *ep;
44110a37fd7SStephen Warren 	int p;
44210a37fd7SStephen Warren 	int part;
44310a37fd7SStephen Warren 	disk_partition_t tmpinfo;
44499d2c205SRob Herring 
445afc1744eSHans de Goede #ifdef CONFIG_SANDBOX
4464d907025SStephen Warren 	/*
4473f9eb6e1SPavel Machek 	 * Special-case a pseudo block device "hostfs", to allow access to the
4484d907025SStephen Warren 	 * host's own filesystem.
4494d907025SStephen Warren 	 */
4504d907025SStephen Warren 	if (0 == strcmp(ifname, "hostfs")) {
4514d907025SStephen Warren 		*dev_desc = NULL;
4524d907025SStephen Warren 		info->start = 0;
4534d907025SStephen Warren 		info->size = 0;
4544d907025SStephen Warren 		info->blksz = 0;
4554d907025SStephen Warren 		info->bootable = 0;
4564d907025SStephen Warren 		strcpy((char *)info->type, BOOT_PART_TYPE);
4574d907025SStephen Warren 		strcpy((char *)info->name, "Sandbox host");
458b331cd62SPatrick Delaunay #if CONFIG_IS_ENABLED(PARTITION_UUIDS)
4594d907025SStephen Warren 		info->uuid[0] = 0;
4604d907025SStephen Warren #endif
4617561b258SPatrick Delaunay #ifdef CONFIG_PARTITION_TYPE_GUID
4627561b258SPatrick Delaunay 		info->type_guid[0] = 0;
4637561b258SPatrick Delaunay #endif
4644d907025SStephen Warren 
4654d907025SStephen Warren 		return 0;
4664d907025SStephen Warren 	}
467afc1744eSHans de Goede #endif
4684d907025SStephen Warren 
469251cee0dSHans de Goede #ifdef CONFIG_CMD_UBIFS
470251cee0dSHans de Goede 	/*
471251cee0dSHans de Goede 	 * Special-case ubi, ubi goes through a mtd, rathen then through
472251cee0dSHans de Goede 	 * a regular block device.
473251cee0dSHans de Goede 	 */
474251cee0dSHans de Goede 	if (0 == strcmp(ifname, "ubi")) {
475251cee0dSHans de Goede 		if (!ubifs_is_mounted()) {
476251cee0dSHans de Goede 			printf("UBIFS not mounted, use ubifsmount to mount volume first!\n");
477251cee0dSHans de Goede 			return -1;
478251cee0dSHans de Goede 		}
479251cee0dSHans de Goede 
480251cee0dSHans de Goede 		*dev_desc = NULL;
481251cee0dSHans de Goede 		memset(info, 0, sizeof(*info));
482251cee0dSHans de Goede 		strcpy((char *)info->type, BOOT_PART_TYPE);
483251cee0dSHans de Goede 		strcpy((char *)info->name, "UBI");
484b331cd62SPatrick Delaunay #if CONFIG_IS_ENABLED(PARTITION_UUIDS)
485251cee0dSHans de Goede 		info->uuid[0] = 0;
486251cee0dSHans de Goede #endif
487251cee0dSHans de Goede 		return 0;
488251cee0dSHans de Goede 	}
489251cee0dSHans de Goede #endif
490251cee0dSHans de Goede 
49110a37fd7SStephen Warren 	/* If no dev_part_str, use bootdevice environment variable */
492a10973e7SStephen Warren 	if (!dev_part_str || !strlen(dev_part_str) ||
493a10973e7SStephen Warren 	    !strcmp(dev_part_str, "-"))
49400caae6dSSimon Glass 		dev_part_str = env_get("bootdevice");
49599d2c205SRob Herring 
49610a37fd7SStephen Warren 	/* If still no dev_part_str, it's an error */
49710a37fd7SStephen Warren 	if (!dev_part_str) {
49810a37fd7SStephen Warren 		printf("** No device specified **\n");
49910a37fd7SStephen Warren 		goto cleanup;
50099d2c205SRob Herring 	}
50199d2c205SRob Herring 
50210a37fd7SStephen Warren 	/* Separate device and partition ID specification */
50310a37fd7SStephen Warren 	part_str = strchr(dev_part_str, ':');
50410a37fd7SStephen Warren 	if (part_str) {
50510a37fd7SStephen Warren 		dup_str = strdup(dev_part_str);
50610a37fd7SStephen Warren 		dup_str[part_str - dev_part_str] = 0;
50710a37fd7SStephen Warren 		dev_str = dup_str;
50810a37fd7SStephen Warren 		part_str++;
50910a37fd7SStephen Warren 	} else {
51010a37fd7SStephen Warren 		dev_str = dev_part_str;
51199d2c205SRob Herring 	}
51210a37fd7SStephen Warren 
51310a37fd7SStephen Warren 	/* Look up the device */
514ebac37cfSSimon Glass 	dev = blk_get_device_by_str(ifname, dev_str, dev_desc);
51510a37fd7SStephen Warren 	if (dev < 0)
51610a37fd7SStephen Warren 		goto cleanup;
51710a37fd7SStephen Warren 
51810a37fd7SStephen Warren 	/* Convert partition ID string to number */
51910a37fd7SStephen Warren 	if (!part_str || !*part_str) {
52010a37fd7SStephen Warren 		part = PART_UNSPECIFIED;
52110a37fd7SStephen Warren 	} else if (!strcmp(part_str, "auto")) {
52210a37fd7SStephen Warren 		part = PART_AUTO;
52310a37fd7SStephen Warren 	} else {
52410a37fd7SStephen Warren 		/* Something specified -> use exactly that */
52510a37fd7SStephen Warren 		part = (int)simple_strtoul(part_str, &ep, 16);
52610a37fd7SStephen Warren 		/*
52710a37fd7SStephen Warren 		 * Less than whole string converted,
52810a37fd7SStephen Warren 		 * or request for whole device, but caller requires partition.
52910a37fd7SStephen Warren 		 */
53010a37fd7SStephen Warren 		if (*ep || (part == 0 && !allow_whole_dev)) {
53110a37fd7SStephen Warren 			printf("** Bad partition specification %s %s **\n",
53210a37fd7SStephen Warren 			    ifname, dev_part_str);
53310a37fd7SStephen Warren 			goto cleanup;
53410a37fd7SStephen Warren 		}
53510a37fd7SStephen Warren 	}
53610a37fd7SStephen Warren 
53710a37fd7SStephen Warren 	/*
53810a37fd7SStephen Warren 	 * No partition table on device,
53910a37fd7SStephen Warren 	 * or user requested partition 0 (entire device).
54010a37fd7SStephen Warren 	 */
54110a37fd7SStephen Warren 	if (((*dev_desc)->part_type == PART_TYPE_UNKNOWN) ||
54210a37fd7SStephen Warren 	    (part == 0)) {
54310a37fd7SStephen Warren 		if (!(*dev_desc)->lba) {
54410a37fd7SStephen Warren 			printf("** Bad device size - %s %s **\n", ifname,
54510a37fd7SStephen Warren 			       dev_str);
54610a37fd7SStephen Warren 			goto cleanup;
54710a37fd7SStephen Warren 		}
54810a37fd7SStephen Warren 
54910a37fd7SStephen Warren 		/*
55010a37fd7SStephen Warren 		 * If user specified a partition ID other than 0,
55110a37fd7SStephen Warren 		 * or the calling command only accepts partitions,
55210a37fd7SStephen Warren 		 * it's an error.
55310a37fd7SStephen Warren 		 */
55410a37fd7SStephen Warren 		if ((part > 0) || (!allow_whole_dev)) {
55510a37fd7SStephen Warren 			printf("** No partition table - %s %s **\n", ifname,
55610a37fd7SStephen Warren 			       dev_str);
55710a37fd7SStephen Warren 			goto cleanup;
55810a37fd7SStephen Warren 		}
55910a37fd7SStephen Warren 
56050ffc3b6SLan Yixun (dlan) 		(*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);
56150ffc3b6SLan Yixun (dlan) 
5624bbcc965SRob Clark 		part_get_info_whole_disk(*dev_desc, info);
56399d2c205SRob Herring 
56410a37fd7SStephen Warren 		ret = 0;
56510a37fd7SStephen Warren 		goto cleanup;
56699d2c205SRob Herring 	}
56799d2c205SRob Herring 
56810a37fd7SStephen Warren 	/*
56910a37fd7SStephen Warren 	 * Now there's known to be a partition table,
57010a37fd7SStephen Warren 	 * not specifying a partition means to pick partition 1.
57110a37fd7SStephen Warren 	 */
57210a37fd7SStephen Warren 	if (part == PART_UNSPECIFIED)
57310a37fd7SStephen Warren 		part = 1;
57499d2c205SRob Herring 
57510a37fd7SStephen Warren 	/*
57610a37fd7SStephen Warren 	 * If user didn't specify a partition number, or did specify something
57710a37fd7SStephen Warren 	 * other than "auto", use that partition number directly.
57810a37fd7SStephen Warren 	 */
57910a37fd7SStephen Warren 	if (part != PART_AUTO) {
5803e8bd469SSimon Glass 		ret = part_get_info(*dev_desc, part, info);
58199d2c205SRob Herring 		if (ret) {
58210a37fd7SStephen Warren 			printf("** Invalid partition %d **\n", part);
58310a37fd7SStephen Warren 			goto cleanup;
58410a37fd7SStephen Warren 		}
58510a37fd7SStephen Warren 	} else {
58610a37fd7SStephen Warren 		/*
58710a37fd7SStephen Warren 		 * Find the first bootable partition.
58810a37fd7SStephen Warren 		 * If none are bootable, fall back to the first valid partition.
58910a37fd7SStephen Warren 		 */
59010a37fd7SStephen Warren 		part = 0;
59110a37fd7SStephen Warren 		for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
5923e8bd469SSimon Glass 			ret = part_get_info(*dev_desc, p, info);
59310a37fd7SStephen Warren 			if (ret)
59410a37fd7SStephen Warren 				continue;
59510a37fd7SStephen Warren 
59610a37fd7SStephen Warren 			/*
59710a37fd7SStephen Warren 			 * First valid partition, or new better partition?
59810a37fd7SStephen Warren 			 * If so, save partition ID.
59910a37fd7SStephen Warren 			 */
60010a37fd7SStephen Warren 			if (!part || info->bootable)
60110a37fd7SStephen Warren 				part = p;
60210a37fd7SStephen Warren 
60310a37fd7SStephen Warren 			/* Best possible partition? Stop searching. */
60410a37fd7SStephen Warren 			if (info->bootable)
60510a37fd7SStephen Warren 				break;
60610a37fd7SStephen Warren 
60710a37fd7SStephen Warren 			/*
60810a37fd7SStephen Warren 			 * We now need to search further for best possible.
60910a37fd7SStephen Warren 			 * If we what we just queried was the best so far,
61010a37fd7SStephen Warren 			 * save the info since we over-write it next loop.
61110a37fd7SStephen Warren 			 */
61210a37fd7SStephen Warren 			if (part == p)
61310a37fd7SStephen Warren 				tmpinfo = *info;
61410a37fd7SStephen Warren 		}
61510a37fd7SStephen Warren 		/* If we found any acceptable partition */
61610a37fd7SStephen Warren 		if (part) {
61710a37fd7SStephen Warren 			/*
61810a37fd7SStephen Warren 			 * If we searched all possible partition IDs,
61910a37fd7SStephen Warren 			 * return the first valid partition we found.
62010a37fd7SStephen Warren 			 */
62110a37fd7SStephen Warren 			if (p == MAX_SEARCH_PARTITIONS + 1)
62210a37fd7SStephen Warren 				*info = tmpinfo;
62310a37fd7SStephen Warren 		} else {
62410a37fd7SStephen Warren 			printf("** No valid partitions found **\n");
62571bba424SStephen Warren 			ret = -1;
62610a37fd7SStephen Warren 			goto cleanup;
62710a37fd7SStephen Warren 		}
62899d2c205SRob Herring 	}
62999d2c205SRob Herring 	if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) {
63099d2c205SRob Herring 		printf("** Invalid partition type \"%.32s\""
63199d2c205SRob Herring 			" (expect \"" BOOT_PART_TYPE "\")\n",
63299d2c205SRob Herring 			info->type);
63310a37fd7SStephen Warren 		ret  = -1;
63410a37fd7SStephen Warren 		goto cleanup;
63599d2c205SRob Herring 	}
63699d2c205SRob Herring 
63750ffc3b6SLan Yixun (dlan) 	(*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);
63850ffc3b6SLan Yixun (dlan) 
63910a37fd7SStephen Warren 	ret = part;
64010a37fd7SStephen Warren 	goto cleanup;
64199d2c205SRob Herring 
64210a37fd7SStephen Warren cleanup:
64310a37fd7SStephen Warren 	free(dup_str);
64410a37fd7SStephen Warren 	return ret;
64599d2c205SRob Herring }
64687b8530fSPetr Kulhavy 
part_get_info_by_name_type(struct blk_desc * dev_desc,const char * name,disk_partition_t * info,int part_type)64730789095SSam Protsenko int part_get_info_by_name_type(struct blk_desc *dev_desc, const char *name,
64830789095SSam Protsenko 			       disk_partition_t *info, int part_type)
64987b8530fSPetr Kulhavy {
65087b8530fSPetr Kulhavy 	struct part_driver *part_drv;
65187b8530fSPetr Kulhavy 	int ret;
65287b8530fSPetr Kulhavy 	int i;
65356670d6fSKever Yang 
65456670d6fSKever Yang 	part_drv = part_driver_lookup_type(dev_desc);
65556670d6fSKever Yang 	if (!part_drv)
65656670d6fSKever Yang 		return -1;
65787b8530fSPetr Kulhavy 	for (i = 1; i < part_drv->max_entries; i++) {
65887b8530fSPetr Kulhavy 		ret = part_drv->get_info(dev_desc, i, info);
65987b8530fSPetr Kulhavy 		if (ret != 0) {
66087b8530fSPetr Kulhavy 			/* no more entries in table */
66187b8530fSPetr Kulhavy 			break;
66287b8530fSPetr Kulhavy 		}
66387b8530fSPetr Kulhavy 		if (strcmp(name, (const char *)info->name) == 0) {
66487b8530fSPetr Kulhavy 			/* matched */
66588b6329cSAlex Deymo 			return i;
66687b8530fSPetr Kulhavy 		}
66787b8530fSPetr Kulhavy 	}
66856670d6fSKever Yang 
66987b8530fSPetr Kulhavy 	return -1;
67087b8530fSPetr Kulhavy }
671da2ee24dSPetr Kulhavy 
part_get_info_by_name(struct blk_desc * dev_desc,const char * name,disk_partition_t * info)67230789095SSam Protsenko int part_get_info_by_name(struct blk_desc *dev_desc, const char *name,
67330789095SSam Protsenko 			  disk_partition_t *info)
67430789095SSam Protsenko {
67530789095SSam Protsenko 	return part_get_info_by_name_type(dev_desc, name, info, PART_TYPE_ALL);
67630789095SSam Protsenko }
67730789095SSam Protsenko 
part_set_generic_name(const struct blk_desc * dev_desc,int part_num,char * name)678da2ee24dSPetr Kulhavy void part_set_generic_name(const struct blk_desc *dev_desc,
679da2ee24dSPetr Kulhavy 	int part_num, char *name)
680da2ee24dSPetr Kulhavy {
681da2ee24dSPetr Kulhavy 	char *devtype;
682da2ee24dSPetr Kulhavy 
683da2ee24dSPetr Kulhavy 	switch (dev_desc->if_type) {
684da2ee24dSPetr Kulhavy 	case IF_TYPE_IDE:
685da2ee24dSPetr Kulhavy 	case IF_TYPE_SATA:
686da2ee24dSPetr Kulhavy 	case IF_TYPE_ATAPI:
687da2ee24dSPetr Kulhavy 		devtype = "hd";
688da2ee24dSPetr Kulhavy 		break;
689da2ee24dSPetr Kulhavy 	case IF_TYPE_SCSI:
690da2ee24dSPetr Kulhavy 		devtype = "sd";
691da2ee24dSPetr Kulhavy 		break;
692da2ee24dSPetr Kulhavy 	case IF_TYPE_USB:
693da2ee24dSPetr Kulhavy 		devtype = "usbd";
694da2ee24dSPetr Kulhavy 		break;
695da2ee24dSPetr Kulhavy 	case IF_TYPE_DOC:
696da2ee24dSPetr Kulhavy 		devtype = "docd";
697da2ee24dSPetr Kulhavy 		break;
698da2ee24dSPetr Kulhavy 	case IF_TYPE_MMC:
699da2ee24dSPetr Kulhavy 	case IF_TYPE_SD:
700da2ee24dSPetr Kulhavy 		devtype = "mmcsd";
701da2ee24dSPetr Kulhavy 		break;
702da2ee24dSPetr Kulhavy 	default:
703da2ee24dSPetr Kulhavy 		devtype = "xx";
704da2ee24dSPetr Kulhavy 		break;
705da2ee24dSPetr Kulhavy 	}
706da2ee24dSPetr Kulhavy 
707da2ee24dSPetr Kulhavy 	sprintf(name, "%s%c%d", devtype, 'a' + dev_desc->devnum, part_num);
708da2ee24dSPetr Kulhavy }
709