1affae2bfSwdenk /* 2affae2bfSwdenk * (C) Copyright 2001 3affae2bfSwdenk * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4affae2bfSwdenk * 51a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 6affae2bfSwdenk */ 7affae2bfSwdenk 8affae2bfSwdenk #include <common.h> 9affae2bfSwdenk #include <command.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 23735dd97bSGrant Likely struct block_drvr { 24735dd97bSGrant Likely char *name; 254101f687SSimon Glass struct blk_desc* (*get_dev)(int dev); 26336b6f90SStephen Warren int (*select_hwpart)(int dev_num, int hwpart); 27735dd97bSGrant Likely }; 28735dd97bSGrant Likely 29735dd97bSGrant Likely static const struct block_drvr block_drvr[] = { 30cde5c64dSJon Loeliger #if defined(CONFIG_CMD_IDE) 31735dd97bSGrant Likely { .name = "ide", .get_dev = ide_get_dev, }, 32735dd97bSGrant Likely #endif 33c7057b52SDave Liu #if defined(CONFIG_CMD_SATA) 34c7057b52SDave Liu {.name = "sata", .get_dev = sata_get_dev, }, 35c7057b52SDave Liu #endif 36cde5c64dSJon Loeliger #if defined(CONFIG_CMD_SCSI) 37735dd97bSGrant Likely { .name = "scsi", .get_dev = scsi_get_dev, }, 38735dd97bSGrant Likely #endif 39cde5c64dSJon Loeliger #if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE) 40735dd97bSGrant Likely { .name = "usb", .get_dev = usb_stor_get_dev, }, 41735dd97bSGrant Likely #endif 42735dd97bSGrant Likely #if defined(CONFIG_MMC) 43d2356284SStephen Warren { 44d2356284SStephen Warren .name = "mmc", 45d2356284SStephen Warren .get_dev = mmc_get_dev, 46d2356284SStephen Warren .select_hwpart = mmc_select_hwpart, 47d2356284SStephen Warren }, 48735dd97bSGrant Likely #endif 49735dd97bSGrant Likely #if defined(CONFIG_SYSTEMACE) 50735dd97bSGrant Likely { .name = "ace", .get_dev = systemace_get_dev, }, 51735dd97bSGrant Likely #endif 52f4d8de48SHenrik Nordström #if defined(CONFIG_SANDBOX) 53f4d8de48SHenrik Nordström { .name = "host", .get_dev = host_get_dev, }, 54f4d8de48SHenrik Nordström #endif 55735dd97bSGrant Likely { }, 56735dd97bSGrant Likely }; 57735dd97bSGrant Likely 58751bb571SStefan Roese DECLARE_GLOBAL_DATA_PTR; 59751bb571SStefan Roese 600c9c8fb5SGabe Black #ifdef HAVE_BLOCK_DEVICE 614101f687SSimon Glass static struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart) 62735dd97bSGrant Likely { 63735dd97bSGrant Likely const struct block_drvr *drvr = block_drvr; 644101f687SSimon Glass struct blk_desc* (*reloc_get_dev)(int dev); 65336b6f90SStephen Warren int (*select_hwpart)(int dev_num, int hwpart); 6623090dacSHeiko Schocher char *name; 67336b6f90SStephen Warren int ret; 68751bb571SStefan Roese 697e71dc68STim Kientzle if (!ifname) 707e71dc68STim Kientzle return NULL; 717e71dc68STim Kientzle 7223090dacSHeiko Schocher name = drvr->name; 732e5167ccSWolfgang Denk #ifdef CONFIG_NEEDS_MANUAL_RELOC 7423090dacSHeiko Schocher name += gd->reloc_off; 7523090dacSHeiko Schocher #endif 76b16aadf4SLei Wen while (drvr->name) { 7723090dacSHeiko Schocher name = drvr->name; 78521af04dSPeter Tyser reloc_get_dev = drvr->get_dev; 79336b6f90SStephen Warren select_hwpart = drvr->select_hwpart; 802e5167ccSWolfgang Denk #ifdef CONFIG_NEEDS_MANUAL_RELOC 8123090dacSHeiko Schocher name += gd->reloc_off; 82521af04dSPeter Tyser reloc_get_dev += gd->reloc_off; 83336b6f90SStephen Warren if (select_hwpart) 84336b6f90SStephen Warren select_hwpart += gd->reloc_off; 85521af04dSPeter Tyser #endif 86336b6f90SStephen Warren if (strncmp(ifname, name, strlen(name)) == 0) { 874101f687SSimon Glass struct blk_desc *dev_desc = reloc_get_dev(dev); 88336b6f90SStephen Warren if (!dev_desc) 89336b6f90SStephen Warren return NULL; 90ecdd57e2SStephen Warren if (hwpart == 0 && !select_hwpart) 91336b6f90SStephen Warren return dev_desc; 92336b6f90SStephen Warren if (!select_hwpart) 93336b6f90SStephen Warren return NULL; 94336b6f90SStephen Warren ret = select_hwpart(dev_desc->dev, hwpart); 95336b6f90SStephen Warren if (ret < 0) 96336b6f90SStephen Warren return NULL; 97336b6f90SStephen Warren return dev_desc; 98336b6f90SStephen Warren } 99735dd97bSGrant Likely drvr++; 100735dd97bSGrant Likely } 101735dd97bSGrant Likely return NULL; 102735dd97bSGrant Likely } 103336b6f90SStephen Warren 104db1d9e78SSimon Glass struct blk_desc *blk_get_dev(const char *ifname, int dev) 105336b6f90SStephen Warren { 106ecdd57e2SStephen Warren return get_dev_hwpart(ifname, dev, 0); 107336b6f90SStephen Warren } 108735dd97bSGrant Likely #else 1094101f687SSimon Glass struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart) 110336b6f90SStephen Warren { 111336b6f90SStephen Warren return NULL; 112336b6f90SStephen Warren } 113336b6f90SStephen Warren 114db1d9e78SSimon Glass struct blk_desc *blk_get_dev(const char *ifname, int dev) 115735dd97bSGrant Likely { 116735dd97bSGrant Likely return NULL; 117735dd97bSGrant Likely } 118735dd97bSGrant Likely #endif 119735dd97bSGrant Likely 1200c9c8fb5SGabe Black #ifdef HAVE_BLOCK_DEVICE 121735dd97bSGrant Likely 122affae2bfSwdenk /* ------------------------------------------------------------------------- */ 123affae2bfSwdenk /* 124affae2bfSwdenk * reports device info to the user 125affae2bfSwdenk */ 12669a2a4d9SSergei Trofimovich 12769a2a4d9SSergei Trofimovich #ifdef CONFIG_LBA48 12869a2a4d9SSergei Trofimovich typedef uint64_t lba512_t; 12969a2a4d9SSergei Trofimovich #else 13069a2a4d9SSergei Trofimovich typedef lbaint_t lba512_t; 13169a2a4d9SSergei Trofimovich #endif 13269a2a4d9SSergei Trofimovich 13369a2a4d9SSergei Trofimovich /* 13469a2a4d9SSergei Trofimovich * Overflowless variant of (block_count * mul_by / div_by) 13569a2a4d9SSergei Trofimovich * when div_by > mul_by 13669a2a4d9SSergei Trofimovich */ 13769a2a4d9SSergei Trofimovich static lba512_t lba512_muldiv(lba512_t block_count, lba512_t mul_by, lba512_t div_by) 13869a2a4d9SSergei Trofimovich { 13969a2a4d9SSergei Trofimovich lba512_t bc_quot, bc_rem; 14069a2a4d9SSergei Trofimovich 14169a2a4d9SSergei Trofimovich /* x * m / d == x / d * m + (x % d) * m / d */ 14269a2a4d9SSergei Trofimovich bc_quot = block_count / div_by; 14369a2a4d9SSergei Trofimovich bc_rem = block_count - div_by * bc_quot; 14469a2a4d9SSergei Trofimovich return bc_quot * mul_by + (bc_rem * mul_by) / div_by; 14569a2a4d9SSergei Trofimovich } 14669a2a4d9SSergei Trofimovich 1474101f687SSimon Glass void dev_print (struct blk_desc *dev_desc) 148affae2bfSwdenk { 14969a2a4d9SSergei Trofimovich lba512_t lba512; /* number of blocks if 512bytes block size */ 150affae2bfSwdenk 151af75a45dSWolfgang Denk if (dev_desc->type == DEV_TYPE_UNKNOWN) { 152af75a45dSWolfgang Denk puts ("not available\n"); 153af75a45dSWolfgang Denk return; 154af75a45dSWolfgang Denk } 155af75a45dSWolfgang Denk 1568ec6e332STor Krill switch (dev_desc->if_type) { 157574b3195SDetlev Zundel case IF_TYPE_SCSI: 158574b3195SDetlev Zundel printf ("(%d:%d) Vendor: %s Prod.: %s Rev: %s\n", 159574b3195SDetlev Zundel dev_desc->target,dev_desc->lun, 160affae2bfSwdenk dev_desc->vendor, 161affae2bfSwdenk dev_desc->product, 162affae2bfSwdenk dev_desc->revision); 163574b3195SDetlev Zundel break; 1646e24a1ebSRemy Bohmer case IF_TYPE_ATAPI: 165574b3195SDetlev Zundel case IF_TYPE_IDE: 166574b3195SDetlev Zundel case IF_TYPE_SATA: 167574b3195SDetlev Zundel printf ("Model: %s Firm: %s Ser#: %s\n", 168574b3195SDetlev Zundel dev_desc->vendor, 169574b3195SDetlev Zundel dev_desc->revision, 170574b3195SDetlev Zundel dev_desc->product); 171574b3195SDetlev Zundel break; 1726e24a1ebSRemy Bohmer case IF_TYPE_SD: 1736e24a1ebSRemy Bohmer case IF_TYPE_MMC: 17447bebe34SNícolas Carneiro Lebedenco case IF_TYPE_USB: 17547bebe34SNícolas Carneiro Lebedenco printf ("Vendor: %s Rev: %s Prod: %s\n", 17647bebe34SNícolas Carneiro Lebedenco dev_desc->vendor, 17747bebe34SNícolas Carneiro Lebedenco dev_desc->revision, 17847bebe34SNícolas Carneiro Lebedenco dev_desc->product); 17947bebe34SNícolas Carneiro Lebedenco break; 1806e24a1ebSRemy Bohmer case IF_TYPE_DOC: 1816e24a1ebSRemy Bohmer puts("device type DOC\n"); 1826e24a1ebSRemy Bohmer return; 1838ec6e332STor Krill case IF_TYPE_UNKNOWN: 1846e24a1ebSRemy Bohmer puts("device type unknown\n"); 1856e24a1ebSRemy Bohmer return; 186574b3195SDetlev Zundel default: 1876e24a1ebSRemy Bohmer printf("Unhandled device type: %i\n", dev_desc->if_type); 188574b3195SDetlev Zundel return; 189affae2bfSwdenk } 190affae2bfSwdenk puts (" Type: "); 191affae2bfSwdenk if (dev_desc->removable) 192affae2bfSwdenk puts ("Removable "); 193affae2bfSwdenk switch (dev_desc->type & 0x1F) { 194726c0f1eSDetlev Zundel case DEV_TYPE_HARDDISK: 195726c0f1eSDetlev Zundel puts ("Hard Disk"); 196affae2bfSwdenk break; 197726c0f1eSDetlev Zundel case DEV_TYPE_CDROM: 198726c0f1eSDetlev Zundel puts ("CD ROM"); 199affae2bfSwdenk break; 200726c0f1eSDetlev Zundel case DEV_TYPE_OPDISK: 201726c0f1eSDetlev Zundel puts ("Optical Device"); 202affae2bfSwdenk break; 203726c0f1eSDetlev Zundel case DEV_TYPE_TAPE: 204726c0f1eSDetlev Zundel puts ("Tape"); 205affae2bfSwdenk break; 206726c0f1eSDetlev Zundel default: 207726c0f1eSDetlev Zundel printf ("# %02X #", dev_desc->type & 0x1F); 208affae2bfSwdenk break; 209affae2bfSwdenk } 210affae2bfSwdenk puts ("\n"); 21133699df1SJerry Huang if (dev_desc->lba > 0L && dev_desc->blksz > 0L) { 212affae2bfSwdenk ulong mb, mb_quot, mb_rem, gb, gb_quot, gb_rem; 213c40b2956Swdenk lbaint_t lba; 2146e592385Swdenk 215c40b2956Swdenk lba = dev_desc->lba; 216affae2bfSwdenk 217c40b2956Swdenk lba512 = (lba * (dev_desc->blksz/512)); 218affae2bfSwdenk /* round to 1 digit */ 219214b3f31SPavel Machek /* 2048 = (1024 * 1024) / 512 MB */ 220214b3f31SPavel Machek mb = lba512_muldiv(lba512, 10, 2048); 22169a2a4d9SSergei Trofimovich 222affae2bfSwdenk mb_quot = mb / 10; 223affae2bfSwdenk mb_rem = mb - (10 * mb_quot); 224affae2bfSwdenk 225affae2bfSwdenk gb = mb / 1024; 226affae2bfSwdenk gb_quot = gb / 10; 227affae2bfSwdenk gb_rem = gb - (10 * gb_quot); 22842dfe7a1Swdenk #ifdef CONFIG_LBA48 2296e592385Swdenk if (dev_desc->lba48) 230c40b2956Swdenk printf (" Supports 48-bit addressing\n"); 231c40b2956Swdenk #endif 2324b142febSHeiko Schocher #if defined(CONFIG_SYS_64BIT_LBA) 2336c6166f5SMike Frysinger printf (" Capacity: %ld.%ld MB = %ld.%ld GB (%Ld x %ld)\n", 234c40b2956Swdenk mb_quot, mb_rem, 235c40b2956Swdenk gb_quot, gb_rem, 236c40b2956Swdenk lba, 237c40b2956Swdenk dev_desc->blksz); 238c40b2956Swdenk #else 239affae2bfSwdenk printf (" Capacity: %ld.%ld MB = %ld.%ld GB (%ld x %ld)\n", 240affae2bfSwdenk mb_quot, mb_rem, 241affae2bfSwdenk gb_quot, gb_rem, 242c40b2956Swdenk (ulong)lba, 243affae2bfSwdenk dev_desc->blksz); 244c40b2956Swdenk #endif 245affae2bfSwdenk } else { 246affae2bfSwdenk puts (" Capacity: not available\n"); 247affae2bfSwdenk } 248affae2bfSwdenk } 249b3aff0cbSJon Loeliger #endif 250affae2bfSwdenk 2510c9c8fb5SGabe Black #ifdef HAVE_BLOCK_DEVICE 252affae2bfSwdenk 2534101f687SSimon Glass void init_part(struct blk_desc *dev_desc) 254affae2bfSwdenk { 255affae2bfSwdenk #ifdef CONFIG_ISO_PARTITION 256affae2bfSwdenk if (test_part_iso(dev_desc) == 0) { 257affae2bfSwdenk dev_desc->part_type = PART_TYPE_ISO; 258affae2bfSwdenk return; 259affae2bfSwdenk } 260affae2bfSwdenk #endif 261affae2bfSwdenk 262affae2bfSwdenk #ifdef CONFIG_MAC_PARTITION 263affae2bfSwdenk if (test_part_mac(dev_desc) == 0) { 264affae2bfSwdenk dev_desc->part_type = PART_TYPE_MAC; 265affae2bfSwdenk return; 266affae2bfSwdenk } 267affae2bfSwdenk #endif 268affae2bfSwdenk 26907f3d789Srichardretanubun /* must be placed before DOS partition detection */ 27007f3d789Srichardretanubun #ifdef CONFIG_EFI_PARTITION 27107f3d789Srichardretanubun if (test_part_efi(dev_desc) == 0) { 27207f3d789Srichardretanubun dev_desc->part_type = PART_TYPE_EFI; 27307f3d789Srichardretanubun return; 27407f3d789Srichardretanubun } 27507f3d789Srichardretanubun #endif 27607f3d789Srichardretanubun 277affae2bfSwdenk #ifdef CONFIG_DOS_PARTITION 278affae2bfSwdenk if (test_part_dos(dev_desc) == 0) { 279affae2bfSwdenk dev_desc->part_type = PART_TYPE_DOS; 280affae2bfSwdenk return; 281affae2bfSwdenk } 282affae2bfSwdenk #endif 283c7de829cSwdenk 284c7de829cSwdenk #ifdef CONFIG_AMIGA_PARTITION 285c7de829cSwdenk if (test_part_amiga(dev_desc) == 0) { 286c7de829cSwdenk dev_desc->part_type = PART_TYPE_AMIGA; 287c7de829cSwdenk return; 288c7de829cSwdenk } 289c7de829cSwdenk #endif 29099d2c205SRob Herring dev_desc->part_type = PART_TYPE_UNKNOWN; 291affae2bfSwdenk } 292affae2bfSwdenk 293affae2bfSwdenk 2940c9c8fb5SGabe Black #if defined(CONFIG_MAC_PARTITION) || \ 2950c9c8fb5SGabe Black defined(CONFIG_DOS_PARTITION) || \ 2960c9c8fb5SGabe Black defined(CONFIG_ISO_PARTITION) || \ 2970c9c8fb5SGabe Black defined(CONFIG_AMIGA_PARTITION) || \ 2980c9c8fb5SGabe Black defined(CONFIG_EFI_PARTITION) 2990c9c8fb5SGabe Black 3004101f687SSimon Glass static void print_part_header(const char *type, struct blk_desc *dev_desc) 301affae2bfSwdenk { 302affae2bfSwdenk puts ("\nPartition Map for "); 303affae2bfSwdenk switch (dev_desc->if_type) { 304726c0f1eSDetlev Zundel case IF_TYPE_IDE: 305726c0f1eSDetlev Zundel puts ("IDE"); 306affae2bfSwdenk break; 307726c0f1eSDetlev Zundel case IF_TYPE_SATA: 308726c0f1eSDetlev Zundel puts ("SATA"); 309c7057b52SDave Liu break; 310726c0f1eSDetlev Zundel case IF_TYPE_SCSI: 311726c0f1eSDetlev Zundel puts ("SCSI"); 312affae2bfSwdenk break; 313726c0f1eSDetlev Zundel case IF_TYPE_ATAPI: 314726c0f1eSDetlev Zundel puts ("ATAPI"); 315affae2bfSwdenk break; 316726c0f1eSDetlev Zundel case IF_TYPE_USB: 317726c0f1eSDetlev Zundel puts ("USB"); 318affae2bfSwdenk break; 319726c0f1eSDetlev Zundel case IF_TYPE_DOC: 320726c0f1eSDetlev Zundel puts ("DOC"); 321affae2bfSwdenk break; 3228f3b9642SLei Wen case IF_TYPE_MMC: 3238f3b9642SLei Wen puts ("MMC"); 3248f3b9642SLei Wen break; 325f4d8de48SHenrik Nordström case IF_TYPE_HOST: 326f4d8de48SHenrik Nordström puts("HOST"); 327f4d8de48SHenrik Nordström break; 328726c0f1eSDetlev Zundel default: 329726c0f1eSDetlev Zundel puts ("UNKNOWN"); 330affae2bfSwdenk break; 331affae2bfSwdenk } 332affae2bfSwdenk printf (" device %d -- Partition Type: %s\n\n", 333affae2bfSwdenk dev_desc->dev, type); 334affae2bfSwdenk } 335affae2bfSwdenk 3360c9c8fb5SGabe Black #endif /* any CONFIG_..._PARTITION */ 3370c9c8fb5SGabe Black 3384101f687SSimon Glass void print_part(struct blk_desc *dev_desc) 339affae2bfSwdenk { 340affae2bfSwdenk 341affae2bfSwdenk switch (dev_desc->part_type) { 342affae2bfSwdenk #ifdef CONFIG_MAC_PARTITION 343affae2bfSwdenk case PART_TYPE_MAC: 344affae2bfSwdenk PRINTF ("## Testing for valid MAC partition ##\n"); 345affae2bfSwdenk print_part_header ("MAC", dev_desc); 346affae2bfSwdenk print_part_mac (dev_desc); 347affae2bfSwdenk return; 348affae2bfSwdenk #endif 349affae2bfSwdenk #ifdef CONFIG_DOS_PARTITION 350affae2bfSwdenk case PART_TYPE_DOS: 351affae2bfSwdenk PRINTF ("## Testing for valid DOS partition ##\n"); 352affae2bfSwdenk print_part_header ("DOS", dev_desc); 353affae2bfSwdenk print_part_dos (dev_desc); 354affae2bfSwdenk return; 355affae2bfSwdenk #endif 356affae2bfSwdenk 357affae2bfSwdenk #ifdef CONFIG_ISO_PARTITION 358affae2bfSwdenk case PART_TYPE_ISO: 359affae2bfSwdenk PRINTF ("## Testing for valid ISO Boot partition ##\n"); 360affae2bfSwdenk print_part_header ("ISO", dev_desc); 361affae2bfSwdenk print_part_iso (dev_desc); 362affae2bfSwdenk return; 363affae2bfSwdenk #endif 364c7de829cSwdenk 365c7de829cSwdenk #ifdef CONFIG_AMIGA_PARTITION 366c7de829cSwdenk case PART_TYPE_AMIGA: 367c7de829cSwdenk PRINTF ("## Testing for a valid Amiga partition ##\n"); 368c7de829cSwdenk print_part_header ("AMIGA", dev_desc); 369c7de829cSwdenk print_part_amiga (dev_desc); 370c7de829cSwdenk return; 371c7de829cSwdenk #endif 37207f3d789Srichardretanubun 37307f3d789Srichardretanubun #ifdef CONFIG_EFI_PARTITION 37407f3d789Srichardretanubun case PART_TYPE_EFI: 37507f3d789Srichardretanubun PRINTF ("## Testing for valid EFI partition ##\n"); 37607f3d789Srichardretanubun print_part_header ("EFI", dev_desc); 37707f3d789Srichardretanubun print_part_efi (dev_desc); 37807f3d789Srichardretanubun return; 37907f3d789Srichardretanubun #endif 380affae2bfSwdenk } 381affae2bfSwdenk puts ("## Unknown partition table\n"); 382affae2bfSwdenk } 383affae2bfSwdenk 3840c9c8fb5SGabe Black #endif /* HAVE_BLOCK_DEVICE */ 3852f501646SStephen Warren 3864101f687SSimon Glass int get_partition_info(struct blk_desc *dev_desc, int part, 3873f9eb6e1SPavel Machek disk_partition_t *info) 3882f501646SStephen Warren { 3890c9c8fb5SGabe Black #ifdef HAVE_BLOCK_DEVICE 3902f501646SStephen Warren 391894bfbbfSStephen Warren #ifdef CONFIG_PARTITION_UUIDS 392894bfbbfSStephen Warren /* The common case is no UUID support */ 393894bfbbfSStephen Warren info->uuid[0] = 0; 394894bfbbfSStephen Warren #endif 3957561b258SPatrick Delaunay #ifdef CONFIG_PARTITION_TYPE_GUID 3967561b258SPatrick Delaunay info->type_guid[0] = 0; 3977561b258SPatrick Delaunay #endif 398894bfbbfSStephen Warren 3992f501646SStephen Warren switch (dev_desc->part_type) { 4002f501646SStephen Warren #ifdef CONFIG_MAC_PARTITION 4012f501646SStephen Warren case PART_TYPE_MAC: 4022f501646SStephen Warren if (get_partition_info_mac(dev_desc, part, info) == 0) { 4032f501646SStephen Warren PRINTF("## Valid MAC partition found ##\n"); 4042f501646SStephen Warren return 0; 4052f501646SStephen Warren } 4062f501646SStephen Warren break; 4072f501646SStephen Warren #endif 4082f501646SStephen Warren 4092f501646SStephen Warren #ifdef CONFIG_DOS_PARTITION 4102f501646SStephen Warren case PART_TYPE_DOS: 4112f501646SStephen Warren if (get_partition_info_dos(dev_desc, part, info) == 0) { 4122f501646SStephen Warren PRINTF("## Valid DOS partition found ##\n"); 4132f501646SStephen Warren return 0; 4142f501646SStephen Warren } 4152f501646SStephen Warren break; 4162f501646SStephen Warren #endif 4172f501646SStephen Warren 4182f501646SStephen Warren #ifdef CONFIG_ISO_PARTITION 4192f501646SStephen Warren case PART_TYPE_ISO: 4202f501646SStephen Warren if (get_partition_info_iso(dev_desc, part, info) == 0) { 4212f501646SStephen Warren PRINTF("## Valid ISO boot partition found ##\n"); 4222f501646SStephen Warren return 0; 4232f501646SStephen Warren } 4242f501646SStephen Warren break; 4252f501646SStephen Warren #endif 4262f501646SStephen Warren 4272f501646SStephen Warren #ifdef CONFIG_AMIGA_PARTITION 4282f501646SStephen Warren case PART_TYPE_AMIGA: 4292f501646SStephen Warren if (get_partition_info_amiga(dev_desc, part, info) == 0) { 4302f501646SStephen Warren PRINTF("## Valid Amiga partition found ##\n"); 4312f501646SStephen Warren return 0; 4322f501646SStephen Warren } 4332f501646SStephen Warren break; 4342f501646SStephen Warren #endif 4352f501646SStephen Warren 4362f501646SStephen Warren #ifdef CONFIG_EFI_PARTITION 4372f501646SStephen Warren case PART_TYPE_EFI: 4382f501646SStephen Warren if (get_partition_info_efi(dev_desc, part, info) == 0) { 4392f501646SStephen Warren PRINTF("## Valid EFI partition found ##\n"); 4402f501646SStephen Warren return 0; 4412f501646SStephen Warren } 4422f501646SStephen Warren break; 4432f501646SStephen Warren #endif 4442f501646SStephen Warren default: 4452f501646SStephen Warren break; 4462f501646SStephen Warren } 4470c9c8fb5SGabe Black #endif /* HAVE_BLOCK_DEVICE */ 4482f501646SStephen Warren 4492f501646SStephen Warren return -1; 4502f501646SStephen Warren } 45199d2c205SRob Herring 452ebac37cfSSimon Glass int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str, 4534101f687SSimon Glass struct blk_desc **dev_desc) 4542023e608SStephen Warren { 4552023e608SStephen Warren char *ep; 456336b6f90SStephen Warren char *dup_str = NULL; 457336b6f90SStephen Warren const char *dev_str, *hwpart_str; 458336b6f90SStephen Warren int dev, hwpart; 459336b6f90SStephen Warren 460336b6f90SStephen Warren hwpart_str = strchr(dev_hwpart_str, '.'); 461336b6f90SStephen Warren if (hwpart_str) { 462336b6f90SStephen Warren dup_str = strdup(dev_hwpart_str); 463336b6f90SStephen Warren dup_str[hwpart_str - dev_hwpart_str] = 0; 464336b6f90SStephen Warren dev_str = dup_str; 465336b6f90SStephen Warren hwpart_str++; 466336b6f90SStephen Warren } else { 467336b6f90SStephen Warren dev_str = dev_hwpart_str; 468ecdd57e2SStephen Warren hwpart = 0; 469336b6f90SStephen Warren } 4702023e608SStephen Warren 4712023e608SStephen Warren dev = simple_strtoul(dev_str, &ep, 16); 4722023e608SStephen Warren if (*ep) { 4732023e608SStephen Warren printf("** Bad device specification %s %s **\n", 4742023e608SStephen Warren ifname, dev_str); 475336b6f90SStephen Warren dev = -1; 476336b6f90SStephen Warren goto cleanup; 4772023e608SStephen Warren } 4782023e608SStephen Warren 479336b6f90SStephen Warren if (hwpart_str) { 480336b6f90SStephen Warren hwpart = simple_strtoul(hwpart_str, &ep, 16); 481336b6f90SStephen Warren if (*ep) { 482336b6f90SStephen Warren printf("** Bad HW partition specification %s %s **\n", 483336b6f90SStephen Warren ifname, hwpart_str); 484336b6f90SStephen Warren dev = -1; 485336b6f90SStephen Warren goto cleanup; 486336b6f90SStephen Warren } 487336b6f90SStephen Warren } 488336b6f90SStephen Warren 489336b6f90SStephen Warren *dev_desc = get_dev_hwpart(ifname, dev, hwpart); 4902023e608SStephen Warren if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) { 491336b6f90SStephen Warren printf("** Bad device %s %s **\n", ifname, dev_hwpart_str); 492336b6f90SStephen Warren dev = -1; 493336b6f90SStephen Warren goto cleanup; 4942023e608SStephen Warren } 4952023e608SStephen Warren 49699e7fc8aSErik Tideman #ifdef HAVE_BLOCK_DEVICE 49799e7fc8aSErik Tideman /* 49899e7fc8aSErik Tideman * Updates the partition table for the specified hw partition. 49999e7fc8aSErik Tideman * Does not need to be done for hwpart 0 since it is default and 50099e7fc8aSErik Tideman * already loaded. 50199e7fc8aSErik Tideman */ 50299e7fc8aSErik Tideman if(hwpart != 0) 50399e7fc8aSErik Tideman init_part(*dev_desc); 50499e7fc8aSErik Tideman #endif 50599e7fc8aSErik Tideman 506336b6f90SStephen Warren cleanup: 507336b6f90SStephen Warren free(dup_str); 5082023e608SStephen Warren return dev; 5092023e608SStephen Warren } 5102023e608SStephen Warren 51110a37fd7SStephen Warren #define PART_UNSPECIFIED -2 51210a37fd7SStephen Warren #define PART_AUTO -1 51310a37fd7SStephen Warren #define MAX_SEARCH_PARTITIONS 16 514*e35929e4SSimon Glass int blk_get_device_part_str(const char *ifname, const char *dev_part_str, 5154101f687SSimon Glass struct blk_desc **dev_desc, 51610a37fd7SStephen Warren disk_partition_t *info, int allow_whole_dev) 51799d2c205SRob Herring { 51810a37fd7SStephen Warren int ret = -1; 51910a37fd7SStephen Warren const char *part_str; 52010a37fd7SStephen Warren char *dup_str = NULL; 52110a37fd7SStephen Warren const char *dev_str; 52299d2c205SRob Herring int dev; 52310a37fd7SStephen Warren char *ep; 52410a37fd7SStephen Warren int p; 52510a37fd7SStephen Warren int part; 52610a37fd7SStephen Warren disk_partition_t tmpinfo; 52799d2c205SRob Herring 528251cee0dSHans de Goede #if defined CONFIG_SANDBOX && defined CONFIG_CMD_UBIFS 529251cee0dSHans de Goede #error Only one of CONFIG_SANDBOX and CONFIG_CMD_UBIFS may be selected 530251cee0dSHans de Goede #endif 531251cee0dSHans de Goede 532afc1744eSHans de Goede #ifdef CONFIG_SANDBOX 5334d907025SStephen Warren /* 5343f9eb6e1SPavel Machek * Special-case a pseudo block device "hostfs", to allow access to the 5354d907025SStephen Warren * host's own filesystem. 5364d907025SStephen Warren */ 5374d907025SStephen Warren if (0 == strcmp(ifname, "hostfs")) { 5384d907025SStephen Warren *dev_desc = NULL; 5394d907025SStephen Warren info->start = 0; 5404d907025SStephen Warren info->size = 0; 5414d907025SStephen Warren info->blksz = 0; 5424d907025SStephen Warren info->bootable = 0; 5434d907025SStephen Warren strcpy((char *)info->type, BOOT_PART_TYPE); 5444d907025SStephen Warren strcpy((char *)info->name, "Sandbox host"); 5454d907025SStephen Warren #ifdef CONFIG_PARTITION_UUIDS 5464d907025SStephen Warren info->uuid[0] = 0; 5474d907025SStephen Warren #endif 5487561b258SPatrick Delaunay #ifdef CONFIG_PARTITION_TYPE_GUID 5497561b258SPatrick Delaunay info->type_guid[0] = 0; 5507561b258SPatrick Delaunay #endif 5514d907025SStephen Warren 5524d907025SStephen Warren return 0; 5534d907025SStephen Warren } 554afc1744eSHans de Goede #endif 5554d907025SStephen Warren 556251cee0dSHans de Goede #ifdef CONFIG_CMD_UBIFS 557251cee0dSHans de Goede /* 558251cee0dSHans de Goede * Special-case ubi, ubi goes through a mtd, rathen then through 559251cee0dSHans de Goede * a regular block device. 560251cee0dSHans de Goede */ 561251cee0dSHans de Goede if (0 == strcmp(ifname, "ubi")) { 562251cee0dSHans de Goede if (!ubifs_is_mounted()) { 563251cee0dSHans de Goede printf("UBIFS not mounted, use ubifsmount to mount volume first!\n"); 564251cee0dSHans de Goede return -1; 565251cee0dSHans de Goede } 566251cee0dSHans de Goede 567251cee0dSHans de Goede *dev_desc = NULL; 568251cee0dSHans de Goede memset(info, 0, sizeof(*info)); 569251cee0dSHans de Goede strcpy((char *)info->type, BOOT_PART_TYPE); 570251cee0dSHans de Goede strcpy((char *)info->name, "UBI"); 571251cee0dSHans de Goede #ifdef CONFIG_PARTITION_UUIDS 572251cee0dSHans de Goede info->uuid[0] = 0; 573251cee0dSHans de Goede #endif 574251cee0dSHans de Goede return 0; 575251cee0dSHans de Goede } 576251cee0dSHans de Goede #endif 577251cee0dSHans de Goede 57810a37fd7SStephen Warren /* If no dev_part_str, use bootdevice environment variable */ 579a10973e7SStephen Warren if (!dev_part_str || !strlen(dev_part_str) || 580a10973e7SStephen Warren !strcmp(dev_part_str, "-")) 58110a37fd7SStephen Warren dev_part_str = getenv("bootdevice"); 58299d2c205SRob Herring 58310a37fd7SStephen Warren /* If still no dev_part_str, it's an error */ 58410a37fd7SStephen Warren if (!dev_part_str) { 58510a37fd7SStephen Warren printf("** No device specified **\n"); 58610a37fd7SStephen Warren goto cleanup; 58799d2c205SRob Herring } 58899d2c205SRob Herring 58910a37fd7SStephen Warren /* Separate device and partition ID specification */ 59010a37fd7SStephen Warren part_str = strchr(dev_part_str, ':'); 59110a37fd7SStephen Warren if (part_str) { 59210a37fd7SStephen Warren dup_str = strdup(dev_part_str); 59310a37fd7SStephen Warren dup_str[part_str - dev_part_str] = 0; 59410a37fd7SStephen Warren dev_str = dup_str; 59510a37fd7SStephen Warren part_str++; 59610a37fd7SStephen Warren } else { 59710a37fd7SStephen Warren dev_str = dev_part_str; 59899d2c205SRob Herring } 59910a37fd7SStephen Warren 60010a37fd7SStephen Warren /* Look up the device */ 601ebac37cfSSimon Glass dev = blk_get_device_by_str(ifname, dev_str, dev_desc); 60210a37fd7SStephen Warren if (dev < 0) 60310a37fd7SStephen Warren goto cleanup; 60410a37fd7SStephen Warren 60510a37fd7SStephen Warren /* Convert partition ID string to number */ 60610a37fd7SStephen Warren if (!part_str || !*part_str) { 60710a37fd7SStephen Warren part = PART_UNSPECIFIED; 60810a37fd7SStephen Warren } else if (!strcmp(part_str, "auto")) { 60910a37fd7SStephen Warren part = PART_AUTO; 61010a37fd7SStephen Warren } else { 61110a37fd7SStephen Warren /* Something specified -> use exactly that */ 61210a37fd7SStephen Warren part = (int)simple_strtoul(part_str, &ep, 16); 61310a37fd7SStephen Warren /* 61410a37fd7SStephen Warren * Less than whole string converted, 61510a37fd7SStephen Warren * or request for whole device, but caller requires partition. 61610a37fd7SStephen Warren */ 61710a37fd7SStephen Warren if (*ep || (part == 0 && !allow_whole_dev)) { 61810a37fd7SStephen Warren printf("** Bad partition specification %s %s **\n", 61910a37fd7SStephen Warren ifname, dev_part_str); 62010a37fd7SStephen Warren goto cleanup; 62110a37fd7SStephen Warren } 62210a37fd7SStephen Warren } 62310a37fd7SStephen Warren 62410a37fd7SStephen Warren /* 62510a37fd7SStephen Warren * No partition table on device, 62610a37fd7SStephen Warren * or user requested partition 0 (entire device). 62710a37fd7SStephen Warren */ 62810a37fd7SStephen Warren if (((*dev_desc)->part_type == PART_TYPE_UNKNOWN) || 62910a37fd7SStephen Warren (part == 0)) { 63010a37fd7SStephen Warren if (!(*dev_desc)->lba) { 63110a37fd7SStephen Warren printf("** Bad device size - %s %s **\n", ifname, 63210a37fd7SStephen Warren dev_str); 63310a37fd7SStephen Warren goto cleanup; 63410a37fd7SStephen Warren } 63510a37fd7SStephen Warren 63610a37fd7SStephen Warren /* 63710a37fd7SStephen Warren * If user specified a partition ID other than 0, 63810a37fd7SStephen Warren * or the calling command only accepts partitions, 63910a37fd7SStephen Warren * it's an error. 64010a37fd7SStephen Warren */ 64110a37fd7SStephen Warren if ((part > 0) || (!allow_whole_dev)) { 64210a37fd7SStephen Warren printf("** No partition table - %s %s **\n", ifname, 64310a37fd7SStephen Warren dev_str); 64410a37fd7SStephen Warren goto cleanup; 64510a37fd7SStephen Warren } 64610a37fd7SStephen Warren 64750ffc3b6SLan Yixun (dlan) (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz); 64850ffc3b6SLan Yixun (dlan) 64999d2c205SRob Herring info->start = 0; 65010a37fd7SStephen Warren info->size = (*dev_desc)->lba; 65110a37fd7SStephen Warren info->blksz = (*dev_desc)->blksz; 65210a37fd7SStephen Warren info->bootable = 0; 6536ab6a650SStephen Warren strcpy((char *)info->type, BOOT_PART_TYPE); 6546ab6a650SStephen Warren strcpy((char *)info->name, "Whole Disk"); 65510a37fd7SStephen Warren #ifdef CONFIG_PARTITION_UUIDS 65610a37fd7SStephen Warren info->uuid[0] = 0; 65710a37fd7SStephen Warren #endif 6587561b258SPatrick Delaunay #ifdef CONFIG_PARTITION_TYPE_GUID 6597561b258SPatrick Delaunay info->type_guid[0] = 0; 6607561b258SPatrick Delaunay #endif 66199d2c205SRob Herring 66210a37fd7SStephen Warren ret = 0; 66310a37fd7SStephen Warren goto cleanup; 66499d2c205SRob Herring } 66599d2c205SRob Herring 66610a37fd7SStephen Warren /* 66710a37fd7SStephen Warren * Now there's known to be a partition table, 66810a37fd7SStephen Warren * not specifying a partition means to pick partition 1. 66910a37fd7SStephen Warren */ 67010a37fd7SStephen Warren if (part == PART_UNSPECIFIED) 67110a37fd7SStephen Warren part = 1; 67299d2c205SRob Herring 67310a37fd7SStephen Warren /* 67410a37fd7SStephen Warren * If user didn't specify a partition number, or did specify something 67510a37fd7SStephen Warren * other than "auto", use that partition number directly. 67610a37fd7SStephen Warren */ 67710a37fd7SStephen Warren if (part != PART_AUTO) { 67810a37fd7SStephen Warren ret = get_partition_info(*dev_desc, part, info); 67999d2c205SRob Herring if (ret) { 68010a37fd7SStephen Warren printf("** Invalid partition %d **\n", part); 68110a37fd7SStephen Warren goto cleanup; 68210a37fd7SStephen Warren } 68310a37fd7SStephen Warren } else { 68410a37fd7SStephen Warren /* 68510a37fd7SStephen Warren * Find the first bootable partition. 68610a37fd7SStephen Warren * If none are bootable, fall back to the first valid partition. 68710a37fd7SStephen Warren */ 68810a37fd7SStephen Warren part = 0; 68910a37fd7SStephen Warren for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) { 69010a37fd7SStephen Warren ret = get_partition_info(*dev_desc, p, info); 69110a37fd7SStephen Warren if (ret) 69210a37fd7SStephen Warren continue; 69310a37fd7SStephen Warren 69410a37fd7SStephen Warren /* 69510a37fd7SStephen Warren * First valid partition, or new better partition? 69610a37fd7SStephen Warren * If so, save partition ID. 69710a37fd7SStephen Warren */ 69810a37fd7SStephen Warren if (!part || info->bootable) 69910a37fd7SStephen Warren part = p; 70010a37fd7SStephen Warren 70110a37fd7SStephen Warren /* Best possible partition? Stop searching. */ 70210a37fd7SStephen Warren if (info->bootable) 70310a37fd7SStephen Warren break; 70410a37fd7SStephen Warren 70510a37fd7SStephen Warren /* 70610a37fd7SStephen Warren * We now need to search further for best possible. 70710a37fd7SStephen Warren * If we what we just queried was the best so far, 70810a37fd7SStephen Warren * save the info since we over-write it next loop. 70910a37fd7SStephen Warren */ 71010a37fd7SStephen Warren if (part == p) 71110a37fd7SStephen Warren tmpinfo = *info; 71210a37fd7SStephen Warren } 71310a37fd7SStephen Warren /* If we found any acceptable partition */ 71410a37fd7SStephen Warren if (part) { 71510a37fd7SStephen Warren /* 71610a37fd7SStephen Warren * If we searched all possible partition IDs, 71710a37fd7SStephen Warren * return the first valid partition we found. 71810a37fd7SStephen Warren */ 71910a37fd7SStephen Warren if (p == MAX_SEARCH_PARTITIONS + 1) 72010a37fd7SStephen Warren *info = tmpinfo; 72110a37fd7SStephen Warren } else { 72210a37fd7SStephen Warren printf("** No valid partitions found **\n"); 72371bba424SStephen Warren ret = -1; 72410a37fd7SStephen Warren goto cleanup; 72510a37fd7SStephen Warren } 72699d2c205SRob Herring } 72799d2c205SRob Herring if (strncmp((char *)info->type, BOOT_PART_TYPE, sizeof(info->type)) != 0) { 72899d2c205SRob Herring printf("** Invalid partition type \"%.32s\"" 72999d2c205SRob Herring " (expect \"" BOOT_PART_TYPE "\")\n", 73099d2c205SRob Herring info->type); 73110a37fd7SStephen Warren ret = -1; 73210a37fd7SStephen Warren goto cleanup; 73399d2c205SRob Herring } 73499d2c205SRob Herring 73550ffc3b6SLan Yixun (dlan) (*dev_desc)->log2blksz = LOG2((*dev_desc)->blksz); 73650ffc3b6SLan Yixun (dlan) 73710a37fd7SStephen Warren ret = part; 73810a37fd7SStephen Warren goto cleanup; 73999d2c205SRob Herring 74010a37fd7SStephen Warren cleanup: 74110a37fd7SStephen Warren free(dup_str); 74210a37fd7SStephen Warren return ret; 74399d2c205SRob Herring } 744