1*ca987d46SWarner Losh /*- 2*ca987d46SWarner Losh * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3*ca987d46SWarner Losh * Copyright (c) 2012 Andrey V. Elsukov <ae@FreeBSD.org> 4*ca987d46SWarner Losh * All rights reserved. 5*ca987d46SWarner Losh * 6*ca987d46SWarner Losh * Redistribution and use in source and binary forms, with or without 7*ca987d46SWarner Losh * modification, are permitted provided that the following conditions 8*ca987d46SWarner Losh * are met: 9*ca987d46SWarner Losh * 1. Redistributions of source code must retain the above copyright 10*ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer. 11*ca987d46SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 12*ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer in the 13*ca987d46SWarner Losh * documentation and/or other materials provided with the distribution. 14*ca987d46SWarner Losh * 15*ca987d46SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*ca987d46SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*ca987d46SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*ca987d46SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*ca987d46SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*ca987d46SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*ca987d46SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*ca987d46SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*ca987d46SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*ca987d46SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*ca987d46SWarner Losh * SUCH DAMAGE. 26*ca987d46SWarner Losh */ 27*ca987d46SWarner Losh 28*ca987d46SWarner Losh #include <sys/cdefs.h> 29*ca987d46SWarner Losh __FBSDID("$FreeBSD$"); 30*ca987d46SWarner Losh 31*ca987d46SWarner Losh #include <sys/disk.h> 32*ca987d46SWarner Losh #include <sys/queue.h> 33*ca987d46SWarner Losh #include <stand.h> 34*ca987d46SWarner Losh #include <stdarg.h> 35*ca987d46SWarner Losh #include <bootstrap.h> 36*ca987d46SWarner Losh #include <part.h> 37*ca987d46SWarner Losh 38*ca987d46SWarner Losh #include "disk.h" 39*ca987d46SWarner Losh 40*ca987d46SWarner Losh #ifdef DISK_DEBUG 41*ca987d46SWarner Losh # define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) 42*ca987d46SWarner Losh #else 43*ca987d46SWarner Losh # define DEBUG(fmt, args...) 44*ca987d46SWarner Losh #endif 45*ca987d46SWarner Losh 46*ca987d46SWarner Losh struct open_disk { 47*ca987d46SWarner Losh struct ptable *table; 48*ca987d46SWarner Losh uint64_t mediasize; 49*ca987d46SWarner Losh uint64_t entrysize; 50*ca987d46SWarner Losh u_int sectorsize; 51*ca987d46SWarner Losh }; 52*ca987d46SWarner Losh 53*ca987d46SWarner Losh struct print_args { 54*ca987d46SWarner Losh struct disk_devdesc *dev; 55*ca987d46SWarner Losh const char *prefix; 56*ca987d46SWarner Losh int verbose; 57*ca987d46SWarner Losh }; 58*ca987d46SWarner Losh 59*ca987d46SWarner Losh /* Convert size to a human-readable number. */ 60*ca987d46SWarner Losh static char * 61*ca987d46SWarner Losh display_size(uint64_t size, u_int sectorsize) 62*ca987d46SWarner Losh { 63*ca987d46SWarner Losh static char buf[80]; 64*ca987d46SWarner Losh char unit; 65*ca987d46SWarner Losh 66*ca987d46SWarner Losh size = size * sectorsize / 1024; 67*ca987d46SWarner Losh unit = 'K'; 68*ca987d46SWarner Losh if (size >= 10485760000LL) { 69*ca987d46SWarner Losh size /= 1073741824; 70*ca987d46SWarner Losh unit = 'T'; 71*ca987d46SWarner Losh } else if (size >= 10240000) { 72*ca987d46SWarner Losh size /= 1048576; 73*ca987d46SWarner Losh unit = 'G'; 74*ca987d46SWarner Losh } else if (size >= 10000) { 75*ca987d46SWarner Losh size /= 1024; 76*ca987d46SWarner Losh unit = 'M'; 77*ca987d46SWarner Losh } 78*ca987d46SWarner Losh sprintf(buf, "%ld%cB", (long)size, unit); 79*ca987d46SWarner Losh return (buf); 80*ca987d46SWarner Losh } 81*ca987d46SWarner Losh 82*ca987d46SWarner Losh int 83*ca987d46SWarner Losh ptblread(void *d, void *buf, size_t blocks, uint64_t offset) 84*ca987d46SWarner Losh { 85*ca987d46SWarner Losh struct disk_devdesc *dev; 86*ca987d46SWarner Losh struct open_disk *od; 87*ca987d46SWarner Losh 88*ca987d46SWarner Losh dev = (struct disk_devdesc *)d; 89*ca987d46SWarner Losh od = (struct open_disk *)dev->d_opendata; 90*ca987d46SWarner Losh 91*ca987d46SWarner Losh /* 92*ca987d46SWarner Losh * The strategy function assumes the offset is in units of 512 byte 93*ca987d46SWarner Losh * sectors. For larger sector sizes, we need to adjust the offset to 94*ca987d46SWarner Losh * match the actual sector size. 95*ca987d46SWarner Losh */ 96*ca987d46SWarner Losh offset *= (od->sectorsize / 512); 97*ca987d46SWarner Losh /* 98*ca987d46SWarner Losh * As the GPT backup partition is located at the end of the disk, 99*ca987d46SWarner Losh * to avoid reading past disk end, flag bcache not to use RA. 100*ca987d46SWarner Losh */ 101*ca987d46SWarner Losh return (dev->d_dev->dv_strategy(dev, F_READ | F_NORA, offset, 102*ca987d46SWarner Losh blocks * od->sectorsize, (char *)buf, NULL)); 103*ca987d46SWarner Losh } 104*ca987d46SWarner Losh 105*ca987d46SWarner Losh #define PWIDTH 35 106*ca987d46SWarner Losh static int 107*ca987d46SWarner Losh ptable_print(void *arg, const char *pname, const struct ptable_entry *part) 108*ca987d46SWarner Losh { 109*ca987d46SWarner Losh struct disk_devdesc dev; 110*ca987d46SWarner Losh struct print_args *pa, bsd; 111*ca987d46SWarner Losh struct open_disk *od; 112*ca987d46SWarner Losh struct ptable *table; 113*ca987d46SWarner Losh char line[80]; 114*ca987d46SWarner Losh int res; 115*ca987d46SWarner Losh 116*ca987d46SWarner Losh pa = (struct print_args *)arg; 117*ca987d46SWarner Losh od = (struct open_disk *)pa->dev->d_opendata; 118*ca987d46SWarner Losh sprintf(line, " %s%s: %s", pa->prefix, pname, 119*ca987d46SWarner Losh parttype2str(part->type)); 120*ca987d46SWarner Losh if (pa->verbose) 121*ca987d46SWarner Losh sprintf(line, "%-*s%s", PWIDTH, line, 122*ca987d46SWarner Losh display_size(part->end - part->start + 1, 123*ca987d46SWarner Losh od->sectorsize)); 124*ca987d46SWarner Losh strcat(line, "\n"); 125*ca987d46SWarner Losh if (pager_output(line)) 126*ca987d46SWarner Losh return 1; 127*ca987d46SWarner Losh res = 0; 128*ca987d46SWarner Losh if (part->type == PART_FREEBSD) { 129*ca987d46SWarner Losh /* Open slice with BSD label */ 130*ca987d46SWarner Losh dev.d_dev = pa->dev->d_dev; 131*ca987d46SWarner Losh dev.d_unit = pa->dev->d_unit; 132*ca987d46SWarner Losh dev.d_slice = part->index; 133*ca987d46SWarner Losh dev.d_partition = -1; 134*ca987d46SWarner Losh if (disk_open(&dev, part->end - part->start + 1, 135*ca987d46SWarner Losh od->sectorsize) == 0) { 136*ca987d46SWarner Losh table = ptable_open(&dev, part->end - part->start + 1, 137*ca987d46SWarner Losh od->sectorsize, ptblread); 138*ca987d46SWarner Losh if (table != NULL) { 139*ca987d46SWarner Losh sprintf(line, " %s%s", pa->prefix, pname); 140*ca987d46SWarner Losh bsd.dev = pa->dev; 141*ca987d46SWarner Losh bsd.prefix = line; 142*ca987d46SWarner Losh bsd.verbose = pa->verbose; 143*ca987d46SWarner Losh res = ptable_iterate(table, &bsd, ptable_print); 144*ca987d46SWarner Losh ptable_close(table); 145*ca987d46SWarner Losh } 146*ca987d46SWarner Losh disk_close(&dev); 147*ca987d46SWarner Losh } 148*ca987d46SWarner Losh } 149*ca987d46SWarner Losh 150*ca987d46SWarner Losh return (res); 151*ca987d46SWarner Losh } 152*ca987d46SWarner Losh #undef PWIDTH 153*ca987d46SWarner Losh 154*ca987d46SWarner Losh int 155*ca987d46SWarner Losh disk_print(struct disk_devdesc *dev, char *prefix, int verbose) 156*ca987d46SWarner Losh { 157*ca987d46SWarner Losh struct open_disk *od; 158*ca987d46SWarner Losh struct print_args pa; 159*ca987d46SWarner Losh 160*ca987d46SWarner Losh /* Disk should be opened */ 161*ca987d46SWarner Losh od = (struct open_disk *)dev->d_opendata; 162*ca987d46SWarner Losh pa.dev = dev; 163*ca987d46SWarner Losh pa.prefix = prefix; 164*ca987d46SWarner Losh pa.verbose = verbose; 165*ca987d46SWarner Losh return (ptable_iterate(od->table, &pa, ptable_print)); 166*ca987d46SWarner Losh } 167*ca987d46SWarner Losh 168*ca987d46SWarner Losh int 169*ca987d46SWarner Losh disk_read(struct disk_devdesc *dev, void *buf, uint64_t offset, u_int blocks) 170*ca987d46SWarner Losh { 171*ca987d46SWarner Losh struct open_disk *od; 172*ca987d46SWarner Losh int ret; 173*ca987d46SWarner Losh 174*ca987d46SWarner Losh od = (struct open_disk *)dev->d_opendata; 175*ca987d46SWarner Losh ret = dev->d_dev->dv_strategy(dev, F_READ, dev->d_offset + offset, 176*ca987d46SWarner Losh blocks * od->sectorsize, buf, NULL); 177*ca987d46SWarner Losh 178*ca987d46SWarner Losh return (ret); 179*ca987d46SWarner Losh } 180*ca987d46SWarner Losh 181*ca987d46SWarner Losh int 182*ca987d46SWarner Losh disk_write(struct disk_devdesc *dev, void *buf, uint64_t offset, u_int blocks) 183*ca987d46SWarner Losh { 184*ca987d46SWarner Losh struct open_disk *od; 185*ca987d46SWarner Losh int ret; 186*ca987d46SWarner Losh 187*ca987d46SWarner Losh od = (struct open_disk *)dev->d_opendata; 188*ca987d46SWarner Losh ret = dev->d_dev->dv_strategy(dev, F_WRITE, dev->d_offset + offset, 189*ca987d46SWarner Losh blocks * od->sectorsize, buf, NULL); 190*ca987d46SWarner Losh 191*ca987d46SWarner Losh return (ret); 192*ca987d46SWarner Losh } 193*ca987d46SWarner Losh 194*ca987d46SWarner Losh int 195*ca987d46SWarner Losh disk_ioctl(struct disk_devdesc *dev, u_long cmd, void *data) 196*ca987d46SWarner Losh { 197*ca987d46SWarner Losh struct open_disk *od = dev->d_opendata; 198*ca987d46SWarner Losh 199*ca987d46SWarner Losh if (od == NULL) 200*ca987d46SWarner Losh return (ENOTTY); 201*ca987d46SWarner Losh 202*ca987d46SWarner Losh switch (cmd) { 203*ca987d46SWarner Losh case DIOCGSECTORSIZE: 204*ca987d46SWarner Losh *(u_int *)data = od->sectorsize; 205*ca987d46SWarner Losh break; 206*ca987d46SWarner Losh case DIOCGMEDIASIZE: 207*ca987d46SWarner Losh if (dev->d_offset == 0) 208*ca987d46SWarner Losh *(uint64_t *)data = od->mediasize; 209*ca987d46SWarner Losh else 210*ca987d46SWarner Losh *(uint64_t *)data = od->entrysize * od->sectorsize; 211*ca987d46SWarner Losh break; 212*ca987d46SWarner Losh default: 213*ca987d46SWarner Losh return (ENOTTY); 214*ca987d46SWarner Losh } 215*ca987d46SWarner Losh 216*ca987d46SWarner Losh return (0); 217*ca987d46SWarner Losh } 218*ca987d46SWarner Losh 219*ca987d46SWarner Losh int 220*ca987d46SWarner Losh disk_open(struct disk_devdesc *dev, uint64_t mediasize, u_int sectorsize) 221*ca987d46SWarner Losh { 222*ca987d46SWarner Losh struct open_disk *od; 223*ca987d46SWarner Losh struct ptable *table; 224*ca987d46SWarner Losh struct ptable_entry part; 225*ca987d46SWarner Losh int rc, slice, partition; 226*ca987d46SWarner Losh 227*ca987d46SWarner Losh rc = 0; 228*ca987d46SWarner Losh /* 229*ca987d46SWarner Losh * While we are reading disk metadata, make sure we do it relative 230*ca987d46SWarner Losh * to the start of the disk 231*ca987d46SWarner Losh */ 232*ca987d46SWarner Losh dev->d_offset = 0; 233*ca987d46SWarner Losh table = NULL; 234*ca987d46SWarner Losh slice = dev->d_slice; 235*ca987d46SWarner Losh partition = dev->d_partition; 236*ca987d46SWarner Losh od = (struct open_disk *)malloc(sizeof(struct open_disk)); 237*ca987d46SWarner Losh if (od == NULL) { 238*ca987d46SWarner Losh DEBUG("no memory"); 239*ca987d46SWarner Losh return (ENOMEM); 240*ca987d46SWarner Losh } 241*ca987d46SWarner Losh dev->d_opendata = od; 242*ca987d46SWarner Losh od->entrysize = 0; 243*ca987d46SWarner Losh od->mediasize = mediasize; 244*ca987d46SWarner Losh od->sectorsize = sectorsize; 245*ca987d46SWarner Losh DEBUG("%s unit %d, slice %d, partition %d => %p", 246*ca987d46SWarner Losh disk_fmtdev(dev), dev->d_unit, dev->d_slice, dev->d_partition, od); 247*ca987d46SWarner Losh 248*ca987d46SWarner Losh /* Determine disk layout. */ 249*ca987d46SWarner Losh od->table = ptable_open(dev, mediasize / sectorsize, sectorsize, 250*ca987d46SWarner Losh ptblread); 251*ca987d46SWarner Losh if (od->table == NULL) { 252*ca987d46SWarner Losh DEBUG("Can't read partition table"); 253*ca987d46SWarner Losh rc = ENXIO; 254*ca987d46SWarner Losh goto out; 255*ca987d46SWarner Losh } 256*ca987d46SWarner Losh 257*ca987d46SWarner Losh if (ptable_getsize(od->table, &mediasize) != 0) { 258*ca987d46SWarner Losh rc = ENXIO; 259*ca987d46SWarner Losh goto out; 260*ca987d46SWarner Losh } 261*ca987d46SWarner Losh if (mediasize > od->mediasize) { 262*ca987d46SWarner Losh od->mediasize = mediasize; 263*ca987d46SWarner Losh } 264*ca987d46SWarner Losh 265*ca987d46SWarner Losh if (ptable_gettype(od->table) == PTABLE_BSD && 266*ca987d46SWarner Losh partition >= 0) { 267*ca987d46SWarner Losh /* It doesn't matter what value has d_slice */ 268*ca987d46SWarner Losh rc = ptable_getpart(od->table, &part, partition); 269*ca987d46SWarner Losh if (rc == 0) { 270*ca987d46SWarner Losh dev->d_offset = part.start; 271*ca987d46SWarner Losh od->entrysize = part.end - part.start + 1; 272*ca987d46SWarner Losh } 273*ca987d46SWarner Losh } else if (slice >= 0) { 274*ca987d46SWarner Losh /* Try to get information about partition */ 275*ca987d46SWarner Losh if (slice == 0) 276*ca987d46SWarner Losh rc = ptable_getbestpart(od->table, &part); 277*ca987d46SWarner Losh else 278*ca987d46SWarner Losh rc = ptable_getpart(od->table, &part, slice); 279*ca987d46SWarner Losh if (rc != 0) /* Partition doesn't exist */ 280*ca987d46SWarner Losh goto out; 281*ca987d46SWarner Losh dev->d_offset = part.start; 282*ca987d46SWarner Losh od->entrysize = part.end - part.start + 1; 283*ca987d46SWarner Losh slice = part.index; 284*ca987d46SWarner Losh if (ptable_gettype(od->table) == PTABLE_GPT) { 285*ca987d46SWarner Losh partition = 255; 286*ca987d46SWarner Losh goto out; /* Nothing more to do */ 287*ca987d46SWarner Losh } else if (partition == 255) { 288*ca987d46SWarner Losh /* 289*ca987d46SWarner Losh * When we try to open GPT partition, but partition 290*ca987d46SWarner Losh * table isn't GPT, reset d_partition value to -1 291*ca987d46SWarner Losh * and try to autodetect appropriate value. 292*ca987d46SWarner Losh */ 293*ca987d46SWarner Losh partition = -1; 294*ca987d46SWarner Losh } 295*ca987d46SWarner Losh /* 296*ca987d46SWarner Losh * If d_partition < 0 and we are looking at a BSD slice, 297*ca987d46SWarner Losh * then try to read BSD label, otherwise return the 298*ca987d46SWarner Losh * whole MBR slice. 299*ca987d46SWarner Losh */ 300*ca987d46SWarner Losh if (partition == -1 && 301*ca987d46SWarner Losh part.type != PART_FREEBSD) 302*ca987d46SWarner Losh goto out; 303*ca987d46SWarner Losh /* Try to read BSD label */ 304*ca987d46SWarner Losh table = ptable_open(dev, part.end - part.start + 1, 305*ca987d46SWarner Losh od->sectorsize, ptblread); 306*ca987d46SWarner Losh if (table == NULL) { 307*ca987d46SWarner Losh DEBUG("Can't read BSD label"); 308*ca987d46SWarner Losh rc = ENXIO; 309*ca987d46SWarner Losh goto out; 310*ca987d46SWarner Losh } 311*ca987d46SWarner Losh /* 312*ca987d46SWarner Losh * If slice contains BSD label and d_partition < 0, then 313*ca987d46SWarner Losh * assume the 'a' partition. Otherwise just return the 314*ca987d46SWarner Losh * whole MBR slice, because it can contain ZFS. 315*ca987d46SWarner Losh */ 316*ca987d46SWarner Losh if (partition < 0) { 317*ca987d46SWarner Losh if (ptable_gettype(table) != PTABLE_BSD) 318*ca987d46SWarner Losh goto out; 319*ca987d46SWarner Losh partition = 0; 320*ca987d46SWarner Losh } 321*ca987d46SWarner Losh rc = ptable_getpart(table, &part, partition); 322*ca987d46SWarner Losh if (rc != 0) 323*ca987d46SWarner Losh goto out; 324*ca987d46SWarner Losh dev->d_offset += part.start; 325*ca987d46SWarner Losh od->entrysize = part.end - part.start + 1; 326*ca987d46SWarner Losh } 327*ca987d46SWarner Losh out: 328*ca987d46SWarner Losh if (table != NULL) 329*ca987d46SWarner Losh ptable_close(table); 330*ca987d46SWarner Losh 331*ca987d46SWarner Losh if (rc != 0) { 332*ca987d46SWarner Losh if (od->table != NULL) 333*ca987d46SWarner Losh ptable_close(od->table); 334*ca987d46SWarner Losh free(od); 335*ca987d46SWarner Losh DEBUG("%s could not open", disk_fmtdev(dev)); 336*ca987d46SWarner Losh } else { 337*ca987d46SWarner Losh /* Save the slice and partition number to the dev */ 338*ca987d46SWarner Losh dev->d_slice = slice; 339*ca987d46SWarner Losh dev->d_partition = partition; 340*ca987d46SWarner Losh DEBUG("%s offset %lld => %p", disk_fmtdev(dev), 341*ca987d46SWarner Losh (long long)dev->d_offset, od); 342*ca987d46SWarner Losh } 343*ca987d46SWarner Losh return (rc); 344*ca987d46SWarner Losh } 345*ca987d46SWarner Losh 346*ca987d46SWarner Losh int 347*ca987d46SWarner Losh disk_close(struct disk_devdesc *dev) 348*ca987d46SWarner Losh { 349*ca987d46SWarner Losh struct open_disk *od; 350*ca987d46SWarner Losh 351*ca987d46SWarner Losh od = (struct open_disk *)dev->d_opendata; 352*ca987d46SWarner Losh DEBUG("%s closed => %p", disk_fmtdev(dev), od); 353*ca987d46SWarner Losh ptable_close(od->table); 354*ca987d46SWarner Losh free(od); 355*ca987d46SWarner Losh return (0); 356*ca987d46SWarner Losh } 357*ca987d46SWarner Losh 358*ca987d46SWarner Losh char* 359*ca987d46SWarner Losh disk_fmtdev(struct disk_devdesc *dev) 360*ca987d46SWarner Losh { 361*ca987d46SWarner Losh static char buf[128]; 362*ca987d46SWarner Losh char *cp; 363*ca987d46SWarner Losh 364*ca987d46SWarner Losh cp = buf + sprintf(buf, "%s%d", dev->d_dev->dv_name, dev->d_unit); 365*ca987d46SWarner Losh if (dev->d_slice >= 0) { 366*ca987d46SWarner Losh #ifdef LOADER_GPT_SUPPORT 367*ca987d46SWarner Losh if (dev->d_partition == 255) { 368*ca987d46SWarner Losh sprintf(cp, "p%d:", dev->d_slice); 369*ca987d46SWarner Losh return (buf); 370*ca987d46SWarner Losh } else 371*ca987d46SWarner Losh #endif 372*ca987d46SWarner Losh #ifdef LOADER_MBR_SUPPORT 373*ca987d46SWarner Losh cp += sprintf(cp, "s%d", dev->d_slice); 374*ca987d46SWarner Losh #endif 375*ca987d46SWarner Losh } 376*ca987d46SWarner Losh if (dev->d_partition >= 0) 377*ca987d46SWarner Losh cp += sprintf(cp, "%c", dev->d_partition + 'a'); 378*ca987d46SWarner Losh strcat(cp, ":"); 379*ca987d46SWarner Losh return (buf); 380*ca987d46SWarner Losh } 381*ca987d46SWarner Losh 382*ca987d46SWarner Losh int 383*ca987d46SWarner Losh disk_parsedev(struct disk_devdesc *dev, const char *devspec, const char **path) 384*ca987d46SWarner Losh { 385*ca987d46SWarner Losh int unit, slice, partition; 386*ca987d46SWarner Losh const char *np; 387*ca987d46SWarner Losh char *cp; 388*ca987d46SWarner Losh 389*ca987d46SWarner Losh np = devspec; 390*ca987d46SWarner Losh unit = slice = partition = -1; 391*ca987d46SWarner Losh if (*np != '\0' && *np != ':') { 392*ca987d46SWarner Losh unit = strtol(np, &cp, 10); 393*ca987d46SWarner Losh if (cp == np) 394*ca987d46SWarner Losh return (EUNIT); 395*ca987d46SWarner Losh #ifdef LOADER_GPT_SUPPORT 396*ca987d46SWarner Losh if (*cp == 'p') { 397*ca987d46SWarner Losh np = cp + 1; 398*ca987d46SWarner Losh slice = strtol(np, &cp, 10); 399*ca987d46SWarner Losh if (np == cp) 400*ca987d46SWarner Losh return (ESLICE); 401*ca987d46SWarner Losh /* we don't support nested partitions on GPT */ 402*ca987d46SWarner Losh if (*cp != '\0' && *cp != ':') 403*ca987d46SWarner Losh return (EINVAL); 404*ca987d46SWarner Losh partition = 255; 405*ca987d46SWarner Losh } else 406*ca987d46SWarner Losh #endif 407*ca987d46SWarner Losh #ifdef LOADER_MBR_SUPPORT 408*ca987d46SWarner Losh if (*cp == 's') { 409*ca987d46SWarner Losh np = cp + 1; 410*ca987d46SWarner Losh slice = strtol(np, &cp, 10); 411*ca987d46SWarner Losh if (np == cp) 412*ca987d46SWarner Losh return (ESLICE); 413*ca987d46SWarner Losh } 414*ca987d46SWarner Losh #endif 415*ca987d46SWarner Losh if (*cp != '\0' && *cp != ':') { 416*ca987d46SWarner Losh partition = *cp - 'a'; 417*ca987d46SWarner Losh if (partition < 0) 418*ca987d46SWarner Losh return (EPART); 419*ca987d46SWarner Losh cp++; 420*ca987d46SWarner Losh } 421*ca987d46SWarner Losh } else 422*ca987d46SWarner Losh return (EINVAL); 423*ca987d46SWarner Losh 424*ca987d46SWarner Losh if (*cp != '\0' && *cp != ':') 425*ca987d46SWarner Losh return (EINVAL); 426*ca987d46SWarner Losh dev->d_unit = unit; 427*ca987d46SWarner Losh dev->d_slice = slice; 428*ca987d46SWarner Losh dev->d_partition = partition; 429*ca987d46SWarner Losh if (path != NULL) 430*ca987d46SWarner Losh *path = (*cp == '\0') ? cp: cp + 1; 431*ca987d46SWarner Losh return (0); 432*ca987d46SWarner Losh } 433