blob: 5e10cae015e54e7dc7b5193cd67d5f76ee631582 [file] [log] [blame]
wdenkaffae2b2002-08-17 09:36:01 +00001/*
2 * (C) Copyright 2001
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02005 * SPDX-License-Identifier: GPL-2.0+
wdenkaffae2b2002-08-17 09:36:01 +00006 */
7
8#include <common.h>
9#include <command.h>
10#include <ide.h>
Stephen Warren10a37fd2012-09-21 09:50:57 +000011#include <malloc.h>
Grant Likely735dd972007-02-20 09:04:34 +010012#include <part.h>
wdenkaffae2b2002-08-17 09:36:01 +000013
14#undef PART_DEBUG
15
16#ifdef PART_DEBUG
17#define PRINTF(fmt,args...) printf (fmt ,##args)
18#else
19#define PRINTF(fmt,args...)
20#endif
21
Grant Likely735dd972007-02-20 09:04:34 +010022struct block_drvr {
23 char *name;
24 block_dev_desc_t* (*get_dev)(int dev);
Stephen Warren336b6f92014-05-07 12:19:01 -060025 int (*select_hwpart)(int dev_num, int hwpart);
Grant Likely735dd972007-02-20 09:04:34 +010026};
27
28static const struct block_drvr block_drvr[] = {
Jon Loeligercde5c642007-07-09 17:22:37 -050029#if defined(CONFIG_CMD_IDE)
Grant Likely735dd972007-02-20 09:04:34 +010030 { .name = "ide", .get_dev = ide_get_dev, },
31#endif
Dave Liuc7057b52008-03-26 22:49:44 +080032#if defined(CONFIG_CMD_SATA)
33 {.name = "sata", .get_dev = sata_get_dev, },
34#endif
Jon Loeligercde5c642007-07-09 17:22:37 -050035#if defined(CONFIG_CMD_SCSI)
Grant Likely735dd972007-02-20 09:04:34 +010036 { .name = "scsi", .get_dev = scsi_get_dev, },
37#endif
Jon Loeligercde5c642007-07-09 17:22:37 -050038#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE)
Grant Likely735dd972007-02-20 09:04:34 +010039 { .name = "usb", .get_dev = usb_stor_get_dev, },
40#endif
41#if defined(CONFIG_MMC)
42 { .name = "mmc", .get_dev = mmc_get_dev, },
43#endif
44#if defined(CONFIG_SYSTEMACE)
45 { .name = "ace", .get_dev = systemace_get_dev, },
46#endif
Henrik Nordströmf4d8de42013-11-10 10:26:56 -070047#if defined(CONFIG_SANDBOX)
48 { .name = "host", .get_dev = host_get_dev, },
49#endif
Grant Likely735dd972007-02-20 09:04:34 +010050 { },
51};
52
Stefan Roese751bb572007-02-20 13:21:57 +010053DECLARE_GLOBAL_DATA_PTR;
Stefan Roese751bb572007-02-20 13:21:57 +010054
Gabe Black0c9c8fb2012-10-12 14:26:08 +000055#ifdef HAVE_BLOCK_DEVICE
Stephen Warren336b6f92014-05-07 12:19:01 -060056block_dev_desc_t *get_dev_hwpart(const char *ifname, int dev, int hwpart)
Grant Likely735dd972007-02-20 09:04:34 +010057{
58 const struct block_drvr *drvr = block_drvr;
Stefan Roese6c7cac82007-02-22 07:43:34 +010059 block_dev_desc_t* (*reloc_get_dev)(int dev);
Stephen Warren336b6f92014-05-07 12:19:01 -060060 int (*select_hwpart)(int dev_num, int hwpart);
Heiko Schocher23090da2010-09-17 13:10:36 +020061 char *name;
Stephen Warren336b6f92014-05-07 12:19:01 -060062 int ret;
Grant Likely735dd972007-02-20 09:04:34 +010063
Tim Kientzle7e71dc62012-03-27 11:43:25 +020064 if (!ifname)
65 return NULL;
66
Heiko Schocher23090da2010-09-17 13:10:36 +020067 name = drvr->name;
Wolfgang Denk2e5167c2010-10-28 20:00:11 +020068#ifdef CONFIG_NEEDS_MANUAL_RELOC
Heiko Schocher23090da2010-09-17 13:10:36 +020069 name += gd->reloc_off;
70#endif
Lei Wenb16aadf2011-02-15 16:56:40 +080071 while (drvr->name) {
Heiko Schocher23090da2010-09-17 13:10:36 +020072 name = drvr->name;
Peter Tyser521af042009-09-21 11:20:36 -050073 reloc_get_dev = drvr->get_dev;
Stephen Warren336b6f92014-05-07 12:19:01 -060074 select_hwpart = drvr->select_hwpart;
Wolfgang Denk2e5167c2010-10-28 20:00:11 +020075#ifdef CONFIG_NEEDS_MANUAL_RELOC
Heiko Schocher23090da2010-09-17 13:10:36 +020076 name += gd->reloc_off;
Peter Tyser521af042009-09-21 11:20:36 -050077 reloc_get_dev += gd->reloc_off;
Stephen Warren336b6f92014-05-07 12:19:01 -060078 if (select_hwpart)
79 select_hwpart += gd->reloc_off;
Peter Tyser521af042009-09-21 11:20:36 -050080#endif
Stephen Warren336b6f92014-05-07 12:19:01 -060081 if (strncmp(ifname, name, strlen(name)) == 0) {
82 block_dev_desc_t *dev_desc = reloc_get_dev(dev);
83 if (!dev_desc)
84 return NULL;
85 if (hwpart == -1)
86 return dev_desc;
87 if (!select_hwpart)
88 return NULL;
89 ret = select_hwpart(dev_desc->dev, hwpart);
90 if (ret < 0)
91 return NULL;
92 return dev_desc;
93 }
Grant Likely735dd972007-02-20 09:04:34 +010094 drvr++;
95 }
96 return NULL;
97}
Stephen Warren336b6f92014-05-07 12:19:01 -060098
99block_dev_desc_t *get_dev(const char *ifname, int dev)
100{
101 return get_dev_hwpart(ifname, dev, -1);
102}
Grant Likely735dd972007-02-20 09:04:34 +0100103#else
Stephen Warren336b6f92014-05-07 12:19:01 -0600104block_dev_desc_t *get_dev_hwpart(const char *ifname, int dev, int hwpart)
105{
106 return NULL;
107}
108
Rob Herring99d2c202012-09-21 04:08:17 +0000109block_dev_desc_t *get_dev(const char *ifname, int dev)
Grant Likely735dd972007-02-20 09:04:34 +0100110{
111 return NULL;
112}
113#endif
114
Gabe Black0c9c8fb2012-10-12 14:26:08 +0000115#ifdef HAVE_BLOCK_DEVICE
Grant Likely735dd972007-02-20 09:04:34 +0100116
wdenkaffae2b2002-08-17 09:36:01 +0000117/* ------------------------------------------------------------------------- */
118/*
119 * reports device info to the user
120 */
Sergei Trofimovich69a2a4d2010-08-08 15:05:39 +0300121
122#ifdef CONFIG_LBA48
123typedef uint64_t lba512_t;
124#else
125typedef lbaint_t lba512_t;
126#endif
127
128/*
129 * Overflowless variant of (block_count * mul_by / div_by)
130 * when div_by > mul_by
131 */
132static lba512_t lba512_muldiv (lba512_t block_count, lba512_t mul_by, lba512_t div_by)
133{
134 lba512_t bc_quot, bc_rem;
135
136 /* x * m / d == x / d * m + (x % d) * m / d */
137 bc_quot = block_count / div_by;
138 bc_rem = block_count - div_by * bc_quot;
139 return bc_quot * mul_by + (bc_rem * mul_by) / div_by;
140}
141
wdenkaffae2b2002-08-17 09:36:01 +0000142void dev_print (block_dev_desc_t *dev_desc)
143{
Sergei Trofimovich69a2a4d2010-08-08 15:05:39 +0300144 lba512_t lba512; /* number of blocks if 512bytes block size */
wdenkaffae2b2002-08-17 09:36:01 +0000145
Wolfgang Denkaf75a452009-05-15 09:27:58 +0200146 if (dev_desc->type == DEV_TYPE_UNKNOWN) {
147 puts ("not available\n");
148 return;
149 }
150
Tor Krill8ec6e332008-05-29 11:10:30 +0200151 switch (dev_desc->if_type) {
Detlev Zundel574b3192008-05-05 16:11:21 +0200152 case IF_TYPE_SCSI:
153 printf ("(%d:%d) Vendor: %s Prod.: %s Rev: %s\n",
154 dev_desc->target,dev_desc->lun,
wdenkaffae2b2002-08-17 09:36:01 +0000155 dev_desc->vendor,
156 dev_desc->product,
157 dev_desc->revision);
Detlev Zundel574b3192008-05-05 16:11:21 +0200158 break;
Remy Bohmer6e24a1e2008-09-19 13:30:06 +0200159 case IF_TYPE_ATAPI:
Detlev Zundel574b3192008-05-05 16:11:21 +0200160 case IF_TYPE_IDE:
161 case IF_TYPE_SATA:
162 printf ("Model: %s Firm: %s Ser#: %s\n",
163 dev_desc->vendor,
164 dev_desc->revision,
165 dev_desc->product);
166 break;
Remy Bohmer6e24a1e2008-09-19 13:30:06 +0200167 case IF_TYPE_SD:
168 case IF_TYPE_MMC:
Nícolas Carneiro Lebedenco47bebe32008-09-04 15:35:46 -0300169 case IF_TYPE_USB:
170 printf ("Vendor: %s Rev: %s Prod: %s\n",
171 dev_desc->vendor,
172 dev_desc->revision,
173 dev_desc->product);
174 break;
Remy Bohmer6e24a1e2008-09-19 13:30:06 +0200175 case IF_TYPE_DOC:
176 puts("device type DOC\n");
177 return;
Tor Krill8ec6e332008-05-29 11:10:30 +0200178 case IF_TYPE_UNKNOWN:
Remy Bohmer6e24a1e2008-09-19 13:30:06 +0200179 puts("device type unknown\n");
180 return;
Detlev Zundel574b3192008-05-05 16:11:21 +0200181 default:
Remy Bohmer6e24a1e2008-09-19 13:30:06 +0200182 printf("Unhandled device type: %i\n", dev_desc->if_type);
Detlev Zundel574b3192008-05-05 16:11:21 +0200183 return;
wdenkaffae2b2002-08-17 09:36:01 +0000184 }
185 puts (" Type: ");
186 if (dev_desc->removable)
187 puts ("Removable ");
188 switch (dev_desc->type & 0x1F) {
Detlev Zundel726c0f12008-05-05 16:11:22 +0200189 case DEV_TYPE_HARDDISK:
190 puts ("Hard Disk");
191 break;
192 case DEV_TYPE_CDROM:
193 puts ("CD ROM");
194 break;
195 case DEV_TYPE_OPDISK:
196 puts ("Optical Device");
197 break;
198 case DEV_TYPE_TAPE:
199 puts ("Tape");
200 break;
201 default:
202 printf ("# %02X #", dev_desc->type & 0x1F);
203 break;
wdenkaffae2b2002-08-17 09:36:01 +0000204 }
205 puts ("\n");
Jerry Huang33699df2012-11-06 15:33:12 +0000206 if (dev_desc->lba > 0L && dev_desc->blksz > 0L) {
wdenkaffae2b2002-08-17 09:36:01 +0000207 ulong mb, mb_quot, mb_rem, gb, gb_quot, gb_rem;
wdenkc40b2952004-03-13 23:29:43 +0000208 lbaint_t lba;
wdenk6e592382004-04-18 17:39:38 +0000209
210 lba = dev_desc->lba;
wdenkaffae2b2002-08-17 09:36:01 +0000211
wdenkc40b2952004-03-13 23:29:43 +0000212 lba512 = (lba * (dev_desc->blksz/512));
wdenkaffae2b2002-08-17 09:36:01 +0000213 /* round to 1 digit */
Sergei Trofimovich69a2a4d2010-08-08 15:05:39 +0300214 mb = lba512_muldiv(lba512, 10, 2048); /* 2048 = (1024 * 1024) / 512 MB */
215
wdenkaffae2b2002-08-17 09:36:01 +0000216 mb_quot = mb / 10;
217 mb_rem = mb - (10 * mb_quot);
218
219 gb = mb / 1024;
220 gb_quot = gb / 10;
221 gb_rem = gb - (10 * gb_quot);
wdenk42dfe7a2004-03-14 22:25:36 +0000222#ifdef CONFIG_LBA48
wdenk6e592382004-04-18 17:39:38 +0000223 if (dev_desc->lba48)
wdenkc40b2952004-03-13 23:29:43 +0000224 printf (" Supports 48-bit addressing\n");
225#endif
Heiko Schocher4b142fe2009-12-03 11:21:21 +0100226#if defined(CONFIG_SYS_64BIT_LBA)
Mike Frysinger6c6166f2009-02-16 23:21:36 -0500227 printf (" Capacity: %ld.%ld MB = %ld.%ld GB (%Ld x %ld)\n",
wdenkc40b2952004-03-13 23:29:43 +0000228 mb_quot, mb_rem,
229 gb_quot, gb_rem,
230 lba,
231 dev_desc->blksz);
232#else
wdenkaffae2b2002-08-17 09:36:01 +0000233 printf (" Capacity: %ld.%ld MB = %ld.%ld GB (%ld x %ld)\n",
234 mb_quot, mb_rem,
235 gb_quot, gb_rem,
wdenkc40b2952004-03-13 23:29:43 +0000236 (ulong)lba,
wdenkaffae2b2002-08-17 09:36:01 +0000237 dev_desc->blksz);
wdenkc40b2952004-03-13 23:29:43 +0000238#endif
wdenkaffae2b2002-08-17 09:36:01 +0000239 } else {
240 puts (" Capacity: not available\n");
241 }
242}
Jon Loeligerb3aff0c2007-07-10 11:19:50 -0500243#endif
wdenkaffae2b2002-08-17 09:36:01 +0000244
Gabe Black0c9c8fb2012-10-12 14:26:08 +0000245#ifdef HAVE_BLOCK_DEVICE
wdenkaffae2b2002-08-17 09:36:01 +0000246
247void init_part (block_dev_desc_t * dev_desc)
248{
249#ifdef CONFIG_ISO_PARTITION
250 if (test_part_iso(dev_desc) == 0) {
251 dev_desc->part_type = PART_TYPE_ISO;
252 return;
253 }
254#endif
255
256#ifdef CONFIG_MAC_PARTITION
257 if (test_part_mac(dev_desc) == 0) {
258 dev_desc->part_type = PART_TYPE_MAC;
259 return;
260 }
261#endif
262
richardretanubun07f3d782008-09-26 11:13:22 -0400263/* must be placed before DOS partition detection */
264#ifdef CONFIG_EFI_PARTITION
265 if (test_part_efi(dev_desc) == 0) {
266 dev_desc->part_type = PART_TYPE_EFI;
267 return;
268 }
269#endif
270
wdenkaffae2b2002-08-17 09:36:01 +0000271#ifdef CONFIG_DOS_PARTITION
272 if (test_part_dos(dev_desc) == 0) {
273 dev_desc->part_type = PART_TYPE_DOS;
274 return;
275 }
276#endif
wdenkc7de8292002-11-19 11:04:11 +0000277
278#ifdef CONFIG_AMIGA_PARTITION
279 if (test_part_amiga(dev_desc) == 0) {
280 dev_desc->part_type = PART_TYPE_AMIGA;
281 return;
282 }
283#endif
Rob Herring99d2c202012-09-21 04:08:17 +0000284 dev_desc->part_type = PART_TYPE_UNKNOWN;
wdenkaffae2b2002-08-17 09:36:01 +0000285}
286
287
Gabe Black0c9c8fb2012-10-12 14:26:08 +0000288#if defined(CONFIG_MAC_PARTITION) || \
289 defined(CONFIG_DOS_PARTITION) || \
290 defined(CONFIG_ISO_PARTITION) || \
291 defined(CONFIG_AMIGA_PARTITION) || \
292 defined(CONFIG_EFI_PARTITION)
293
wdenkaffae2b2002-08-17 09:36:01 +0000294static void print_part_header (const char *type, block_dev_desc_t * dev_desc)
295{
296 puts ("\nPartition Map for ");
297 switch (dev_desc->if_type) {
Detlev Zundel726c0f12008-05-05 16:11:22 +0200298 case IF_TYPE_IDE:
299 puts ("IDE");
300 break;
301 case IF_TYPE_SATA:
302 puts ("SATA");
303 break;
304 case IF_TYPE_SCSI:
305 puts ("SCSI");
306 break;
307 case IF_TYPE_ATAPI:
308 puts ("ATAPI");
309 break;
310 case IF_TYPE_USB:
311 puts ("USB");
312 break;
313 case IF_TYPE_DOC:
314 puts ("DOC");
315 break;
Lei Wen8f3b9642010-09-13 22:07:28 +0800316 case IF_TYPE_MMC:
317 puts ("MMC");
318 break;
Henrik Nordströmf4d8de42013-11-10 10:26:56 -0700319 case IF_TYPE_HOST:
320 puts("HOST");
321 break;
Detlev Zundel726c0f12008-05-05 16:11:22 +0200322 default:
323 puts ("UNKNOWN");
324 break;
wdenkaffae2b2002-08-17 09:36:01 +0000325 }
326 printf (" device %d -- Partition Type: %s\n\n",
327 dev_desc->dev, type);
328}
329
Gabe Black0c9c8fb2012-10-12 14:26:08 +0000330#endif /* any CONFIG_..._PARTITION */
331
wdenkaffae2b2002-08-17 09:36:01 +0000332void print_part (block_dev_desc_t * dev_desc)
333{
334
335 switch (dev_desc->part_type) {
336#ifdef CONFIG_MAC_PARTITION
337 case PART_TYPE_MAC:
338 PRINTF ("## Testing for valid MAC partition ##\n");
339 print_part_header ("MAC", dev_desc);
340 print_part_mac (dev_desc);
341 return;
342#endif
343#ifdef CONFIG_DOS_PARTITION
344 case PART_TYPE_DOS:
345 PRINTF ("## Testing for valid DOS partition ##\n");
346 print_part_header ("DOS", dev_desc);
347 print_part_dos (dev_desc);
348 return;
349#endif
350
351#ifdef CONFIG_ISO_PARTITION
352 case PART_TYPE_ISO:
353 PRINTF ("## Testing for valid ISO Boot partition ##\n");
354 print_part_header ("ISO", dev_desc);
355 print_part_iso (dev_desc);
356 return;
357#endif
wdenkc7de8292002-11-19 11:04:11 +0000358
359#ifdef CONFIG_AMIGA_PARTITION
360 case PART_TYPE_AMIGA:
361 PRINTF ("## Testing for a valid Amiga partition ##\n");
362 print_part_header ("AMIGA", dev_desc);
363 print_part_amiga (dev_desc);
364 return;
365#endif
richardretanubun07f3d782008-09-26 11:13:22 -0400366
367#ifdef CONFIG_EFI_PARTITION
368 case PART_TYPE_EFI:
369 PRINTF ("## Testing for valid EFI partition ##\n");
370 print_part_header ("EFI", dev_desc);
371 print_part_efi (dev_desc);
372 return;
373#endif
wdenkaffae2b2002-08-17 09:36:01 +0000374 }
375 puts ("## Unknown partition table\n");
376}
377
Gabe Black0c9c8fb2012-10-12 14:26:08 +0000378#endif /* HAVE_BLOCK_DEVICE */
Stephen Warren2f501642012-09-21 12:46:54 +0000379
380int get_partition_info(block_dev_desc_t *dev_desc, int part
381 , disk_partition_t *info)
382{
Gabe Black0c9c8fb2012-10-12 14:26:08 +0000383#ifdef HAVE_BLOCK_DEVICE
Stephen Warren2f501642012-09-21 12:46:54 +0000384
Stephen Warren894bfbb2012-09-21 09:50:59 +0000385#ifdef CONFIG_PARTITION_UUIDS
386 /* The common case is no UUID support */
387 info->uuid[0] = 0;
388#endif
389
Stephen Warren2f501642012-09-21 12:46:54 +0000390 switch (dev_desc->part_type) {
391#ifdef CONFIG_MAC_PARTITION
392 case PART_TYPE_MAC:
393 if (get_partition_info_mac(dev_desc, part, info) == 0) {
394 PRINTF("## Valid MAC partition found ##\n");
395 return 0;
396 }
397 break;
398#endif
399
400#ifdef CONFIG_DOS_PARTITION
401 case PART_TYPE_DOS:
402 if (get_partition_info_dos(dev_desc, part, info) == 0) {
403 PRINTF("## Valid DOS partition found ##\n");
404 return 0;
405 }
406 break;
407#endif
408
409#ifdef CONFIG_ISO_PARTITION
410 case PART_TYPE_ISO:
411 if (get_partition_info_iso(dev_desc, part, info) == 0) {
412 PRINTF("## Valid ISO boot partition found ##\n");
413 return 0;
414 }
415 break;
416#endif
417
418#ifdef CONFIG_AMIGA_PARTITION
419 case PART_TYPE_AMIGA:
420 if (get_partition_info_amiga(dev_desc, part, info) == 0) {
421 PRINTF("## Valid Amiga partition found ##\n");
422 return 0;
423 }
424 break;
425#endif
426
427#ifdef CONFIG_EFI_PARTITION
428 case PART_TYPE_EFI:
429 if (get_partition_info_efi(dev_desc, part, info) == 0) {
430 PRINTF("## Valid EFI partition found ##\n");
431 return 0;
432 }
433 break;
434#endif
435 default:
436 break;
437 }
Gabe Black0c9c8fb2012-10-12 14:26:08 +0000438#endif /* HAVE_BLOCK_DEVICE */
Stephen Warren2f501642012-09-21 12:46:54 +0000439
440 return -1;
441}
Rob Herring99d2c202012-09-21 04:08:17 +0000442
Stephen Warren336b6f92014-05-07 12:19:01 -0600443int get_device(const char *ifname, const char *dev_hwpart_str,
Stephen Warren2023e602012-09-21 09:50:56 +0000444 block_dev_desc_t **dev_desc)
445{
446 char *ep;
Stephen Warren336b6f92014-05-07 12:19:01 -0600447 char *dup_str = NULL;
448 const char *dev_str, *hwpart_str;
449 int dev, hwpart;
450
451 hwpart_str = strchr(dev_hwpart_str, '.');
452 if (hwpart_str) {
453 dup_str = strdup(dev_hwpart_str);
454 dup_str[hwpart_str - dev_hwpart_str] = 0;
455 dev_str = dup_str;
456 hwpart_str++;
457 } else {
458 dev_str = dev_hwpart_str;
459 hwpart = -1;
460 }
Stephen Warren2023e602012-09-21 09:50:56 +0000461
462 dev = simple_strtoul(dev_str, &ep, 16);
463 if (*ep) {
464 printf("** Bad device specification %s %s **\n",
465 ifname, dev_str);
Stephen Warren336b6f92014-05-07 12:19:01 -0600466 dev = -1;
467 goto cleanup;
Stephen Warren2023e602012-09-21 09:50:56 +0000468 }
469
Stephen Warren336b6f92014-05-07 12:19:01 -0600470 if (hwpart_str) {
471 hwpart = simple_strtoul(hwpart_str, &ep, 16);
472 if (*ep) {
473 printf("** Bad HW partition specification %s %s **\n",
474 ifname, hwpart_str);
475 dev = -1;
476 goto cleanup;
477 }
478 }
479
480 *dev_desc = get_dev_hwpart(ifname, dev, hwpart);
Stephen Warren2023e602012-09-21 09:50:56 +0000481 if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) {
Stephen Warren336b6f92014-05-07 12:19:01 -0600482 printf("** Bad device %s %s **\n", ifname, dev_hwpart_str);
483 dev = -1;
484 goto cleanup;
Stephen Warren2023e602012-09-21 09:50:56 +0000485 }
486
Stephen Warren336b6f92014-05-07 12:19:01 -0600487cleanup:
488 free(dup_str);
Stephen Warren2023e602012-09-21 09:50:56 +0000489 return dev;
490}
491
Stephen Warren10a37fd2012-09-21 09:50:57 +0000492#define PART_UNSPECIFIED -2
493#define PART_AUTO -1
494#define MAX_SEARCH_PARTITIONS 16
495int get_device_and_partition(const char *ifname, const char *dev_part_str,
Rob Herring99d2c202012-09-21 04:08:17 +0000496 block_dev_desc_t **dev_desc,
Stephen Warren10a37fd2012-09-21 09:50:57 +0000497 disk_partition_t *info, int allow_whole_dev)
Rob Herring99d2c202012-09-21 04:08:17 +0000498{
Stephen Warren10a37fd2012-09-21 09:50:57 +0000499 int ret = -1;
500 const char *part_str;
501 char *dup_str = NULL;
502 const char *dev_str;
Rob Herring99d2c202012-09-21 04:08:17 +0000503 int dev;
Stephen Warren10a37fd2012-09-21 09:50:57 +0000504 char *ep;
505 int p;
506 int part;
507 disk_partition_t tmpinfo;
Rob Herring99d2c202012-09-21 04:08:17 +0000508
Stephen Warren10a37fd2012-09-21 09:50:57 +0000509 /* If no dev_part_str, use bootdevice environment variable */
Stephen Warrena10973e2012-09-28 05:34:09 +0000510 if (!dev_part_str || !strlen(dev_part_str) ||
511 !strcmp(dev_part_str, "-"))
Stephen Warren10a37fd2012-09-21 09:50:57 +0000512 dev_part_str = getenv("bootdevice");
Rob Herring99d2c202012-09-21 04:08:17 +0000513
Stephen Warren10a37fd2012-09-21 09:50:57 +0000514 /* If still no dev_part_str, it's an error */
515 if (!dev_part_str) {
516 printf("** No device specified **\n");
517 goto cleanup;
Rob Herring99d2c202012-09-21 04:08:17 +0000518 }
519
Stephen Warren10a37fd2012-09-21 09:50:57 +0000520 /* Separate device and partition ID specification */
521 part_str = strchr(dev_part_str, ':');
522 if (part_str) {
523 dup_str = strdup(dev_part_str);
524 dup_str[part_str - dev_part_str] = 0;
525 dev_str = dup_str;
526 part_str++;
527 } else {
528 dev_str = dev_part_str;
529 }
Rob Herring99d2c202012-09-21 04:08:17 +0000530
Stephen Warren10a37fd2012-09-21 09:50:57 +0000531 /* Look up the device */
532 dev = get_device(ifname, dev_str, dev_desc);
533 if (dev < 0)
534 goto cleanup;
535
536 /* Convert partition ID string to number */
537 if (!part_str || !*part_str) {
538 part = PART_UNSPECIFIED;
539 } else if (!strcmp(part_str, "auto")) {
540 part = PART_AUTO;
541 } else {
542 /* Something specified -> use exactly that */
543 part = (int)simple_strtoul(part_str, &ep, 16);
544 /*
545 * Less than whole string converted,
546 * or request for whole device, but caller requires partition.
547 */
548 if (*ep || (part == 0 && !allow_whole_dev)) {
549 printf("** Bad partition specification %s %s **\n",
550 ifname, dev_part_str);
551 goto cleanup;
Rob Herring99d2c202012-09-21 04:08:17 +0000552 }
Rob Herring99d2c202012-09-21 04:08:17 +0000553 }
554
Stephen Warren10a37fd2012-09-21 09:50:57 +0000555 /*
556 * No partition table on device,
557 * or user requested partition 0 (entire device).
558 */
559 if (((*dev_desc)->part_type == PART_TYPE_UNKNOWN) ||
560 (part == 0)) {
561 if (!(*dev_desc)->lba) {
562 printf("** Bad device size - %s %s **\n", ifname,
563 dev_str);
564 goto cleanup;
565 }
Rob Herring99d2c202012-09-21 04:08:17 +0000566
Stephen Warren10a37fd2012-09-21 09:50:57 +0000567 /*
568 * If user specified a partition ID other than 0,
569 * or the calling command only accepts partitions,
570 * it's an error.
571 */
572 if ((part > 0) || (!allow_whole_dev)) {
573 printf("** No partition table - %s %s **\n", ifname,
574 dev_str);
575 goto cleanup;
576 }
577
Lan Yixun (dlan)50ffc3b2013-07-20 08:17:59 +0800578 (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);
579
Stephen Warren10a37fd2012-09-21 09:50:57 +0000580 info->start = 0;
581 info->size = (*dev_desc)->lba;
582 info->blksz = (*dev_desc)->blksz;
583 info->bootable = 0;
Stephen Warren6ab6a652012-10-10 07:57:51 +0000584 strcpy((char *)info->type, BOOT_PART_TYPE);
585 strcpy((char *)info->name, "Whole Disk");
Stephen Warren10a37fd2012-09-21 09:50:57 +0000586#ifdef CONFIG_PARTITION_UUIDS
587 info->uuid[0] = 0;
588#endif
589
590 ret = 0;
591 goto cleanup;
592 }
593
594 /*
595 * Now there's known to be a partition table,
596 * not specifying a partition means to pick partition 1.
597 */
598 if (part == PART_UNSPECIFIED)
599 part = 1;
600
601 /*
602 * If user didn't specify a partition number, or did specify something
603 * other than "auto", use that partition number directly.
604 */
605 if (part != PART_AUTO) {
606 ret = get_partition_info(*dev_desc, part, info);
607 if (ret) {
608 printf("** Invalid partition %d **\n", part);
609 goto cleanup;
610 }
611 } else {
612 /*
613 * Find the first bootable partition.
614 * If none are bootable, fall back to the first valid partition.
615 */
616 part = 0;
617 for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
618 ret = get_partition_info(*dev_desc, p, info);
619 if (ret)
620 continue;
621
622 /*
623 * First valid partition, or new better partition?
624 * If so, save partition ID.
625 */
626 if (!part || info->bootable)
627 part = p;
628
629 /* Best possible partition? Stop searching. */
630 if (info->bootable)
631 break;
632
633 /*
634 * We now need to search further for best possible.
635 * If we what we just queried was the best so far,
636 * save the info since we over-write it next loop.
637 */
638 if (part == p)
639 tmpinfo = *info;
640 }
641 /* If we found any acceptable partition */
642 if (part) {
643 /*
644 * If we searched all possible partition IDs,
645 * return the first valid partition we found.
646 */
647 if (p == MAX_SEARCH_PARTITIONS + 1)
648 *info = tmpinfo;
Stephen Warren10a37fd2012-09-21 09:50:57 +0000649 } else {
650 printf("** No valid partitions found **\n");
Stephen Warren71bba422012-10-08 07:45:54 +0000651 ret = -1;
Stephen Warren10a37fd2012-09-21 09:50:57 +0000652 goto cleanup;
653 }
Rob Herring99d2c202012-09-21 04:08:17 +0000654 }
655 if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) {
656 printf("** Invalid partition type \"%.32s\""
657 " (expect \"" BOOT_PART_TYPE "\")\n",
658 info->type);
Stephen Warren10a37fd2012-09-21 09:50:57 +0000659 ret = -1;
660 goto cleanup;
Rob Herring99d2c202012-09-21 04:08:17 +0000661 }
662
Lan Yixun (dlan)50ffc3b2013-07-20 08:17:59 +0800663 (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz);
664
Stephen Warren10a37fd2012-09-21 09:50:57 +0000665 ret = part;
666 goto cleanup;
Rob Herring99d2c202012-09-21 04:08:17 +0000667
Stephen Warren10a37fd2012-09-21 09:50:57 +0000668cleanup:
669 free(dup_str);
670 return ret;
Rob Herring99d2c202012-09-21 04:08:17 +0000671}