disk.c revision 185099
1176348Smarcel/*- 2185099Sraj * Copyright (c) 2008 Semihalf, Rafal Jaworowski 3176348Smarcel * All rights reserved. 4176348Smarcel * 5176348Smarcel * Redistribution and use in source and binary forms, with or without 6176348Smarcel * modification, are permitted provided that the following conditions 7176348Smarcel * are met: 8176348Smarcel * 1. Redistributions of source code must retain the above copyright 9176348Smarcel * notice, this list of conditions and the following disclaimer. 10176348Smarcel * 2. Redistributions in binary form must reproduce the above copyright 11176348Smarcel * notice, this list of conditions and the following disclaimer in the 12176348Smarcel * documentation and/or other materials provided with the distribution. 13176348Smarcel * 14185099Sraj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15185099Sraj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16185099Sraj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17185099Sraj * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18185099Sraj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19185099Sraj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20185099Sraj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21185099Sraj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22185099Sraj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23185099Sraj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24185099Sraj * SUCH DAMAGE. 25185099Sraj * 26176348Smarcel */ 27176348Smarcel 28185099Sraj/* 29185099Sraj * Block storage I/O routines for U-Boot 30185099Sraj */ 31185099Sraj 32176348Smarcel#include <sys/cdefs.h> 33176348Smarcel__FBSDID("$FreeBSD: head/sys/boot/uboot/lib/disk.c 185099 2008-11-19 17:34:28Z raj $"); 34176348Smarcel 35176348Smarcel#include <sys/param.h> 36176348Smarcel#include <sys/queue.h> 37176348Smarcel#include <netinet/in.h> 38176348Smarcel#include <machine/stdarg.h> 39176348Smarcel#include <stand.h> 40185099Sraj#include <uuid.h> 41176348Smarcel 42185099Sraj#define FSTYPENAMES 43185099Sraj#include <sys/disklabel.h> 44185099Sraj 45185099Sraj#include "api_public.h" 46176348Smarcel#include "bootstrap.h" 47185099Sraj#include "glue.h" 48185099Sraj#include "libuboot.h" 49176348Smarcel 50185099Sraj#define DEBUG 51185099Sraj#undef DEBUG 52176348Smarcel 53185099Sraj#define stor_printf(fmt, args...) do { \ 54185099Sraj printf("%s%d: ", dev->d_dev->dv_name, dev->d_unit); \ 55185099Sraj printf(fmt, ##args); \ 56185099Sraj} while (0) 57185099Sraj 58185099Sraj#ifdef DEBUG 59185099Sraj#define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 60185099Sraj printf(fmt,##args); } while (0) 61185099Sraj#else 62185099Sraj#define debugf(fmt, args...) 63185099Sraj#endif 64185099Sraj 65185099Srajstruct gpt_part { 66185099Sraj int gp_index; 67185099Sraj uuid_t gp_type; 68185099Sraj uint64_t gp_start; 69185099Sraj uint64_t gp_end; 70176348Smarcel}; 71176348Smarcel 72185099Srajstruct open_dev { 73185099Sraj int od_bsize; /* block size */ 74185099Sraj int od_bstart; /* start block offset from beginning of disk */ 75185099Sraj int od_type; 76185099Sraj#define OD_BSDLABEL 0x0001 77185099Sraj#define OD_GPT 0x0002 78185099Sraj union { 79185099Sraj struct { 80185099Sraj struct disklabel bsdlabel; 81185099Sraj } _bsd; 82185099Sraj struct { 83185099Sraj struct gpt_part *gpt_partitions; 84185099Sraj int gpt_nparts; 85185099Sraj } _gpt; 86185099Sraj } _data; 87176348Smarcel}; 88176348Smarcel 89185099Sraj#define od_bsdlabel _data._bsd.bsdlabel 90185099Sraj#define od_nparts _data._gpt.gpt_nparts 91185099Sraj#define od_partitions _data._gpt.gpt_partitions 92176348Smarcel 93185099Srajstatic int stor_info[UB_MAX_DEV]; 94185099Srajstatic int stor_info_no = 0; 95185099Srajstatic int stor_opendev(struct open_dev **, struct uboot_devdesc *); 96185099Srajstatic int stor_closedev(struct uboot_devdesc *); 97185099Srajstatic int stor_readdev(struct uboot_devdesc *, daddr_t, size_t, char *); 98185099Srajstatic int stor_open_count = 0; 99185099Sraj 100185099Sraj/* devsw I/F */ 101185099Srajstatic int stor_init(void); 102185099Srajstatic int stor_strategy(void *, int, daddr_t, size_t, char *, size_t *); 103185099Srajstatic int stor_open(struct open_file *, ...); 104185099Srajstatic int stor_close(struct open_file *); 105185099Srajstatic void stor_print(int); 106185099Sraj 107185099Srajstruct devsw uboot_storage = { 108185099Sraj "disk", 109185099Sraj DEVT_DISK, 110185099Sraj stor_init, 111185099Sraj stor_strategy, 112185099Sraj stor_open, 113185099Sraj stor_close, 114185099Sraj noioctl, 115185099Sraj stor_print 116185099Sraj}; 117185099Sraj 118176348Smarcelstatic int 119185099Srajstor_init(void) 120176348Smarcel{ 121185099Sraj struct device_info *di; 122185099Sraj int i, found = 0; 123177152Sobrien 124185099Sraj if (devs_no == 0) { 125185099Sraj printf("No U-Boot devices! Really enumerated?\n"); 126185099Sraj return (-1); 127185099Sraj } 128185099Sraj 129185099Sraj for (i = 0; i < devs_no; i++) { 130185099Sraj di = ub_dev_get(i); 131185099Sraj if ((di != NULL) && (di->type & DEV_TYP_STOR)) { 132185099Sraj if (stor_info_no >= UB_MAX_DEV) { 133185099Sraj printf("Too many storage devices: %d\n", 134185099Sraj stor_info_no); 135185099Sraj return (-1); 136185099Sraj } 137185099Sraj stor_info[stor_info_no++] = i; 138185099Sraj found = 1; 139185099Sraj } 140185099Sraj } 141185099Sraj 142185099Sraj if (!found) { 143185099Sraj printf("No storage devices\n"); 144185099Sraj return (-1); 145185099Sraj } 146185099Sraj 147185099Sraj debugf("storage devices found: %d\n", stor_info_no); 148185099Sraj return (0); 149176348Smarcel} 150176348Smarcel 151176348Smarcelstatic int 152185099Srajstor_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, 153176348Smarcel size_t *rsize) 154176348Smarcel{ 155185099Sraj struct uboot_devdesc *dev = (struct uboot_devdesc *)devdata; 156185099Sraj struct open_dev *od = (struct open_dev *)dev->d_disk.data; 157185099Sraj int bcount, err; 158177152Sobrien 159185099Sraj debugf("od=%p, size=%d, bsize=%d\n", od, size, od->od_bsize); 160185099Sraj 161185099Sraj if (rw != F_READ) { 162185099Sraj stor_printf("write attempt, operation not supported!\n"); 163185099Sraj return (EROFS); 164185099Sraj } 165185099Sraj 166185099Sraj if (size % od->od_bsize) { 167185099Sraj stor_printf("size=%d not multiple of device block size=%d\n", 168185099Sraj size, od->od_bsize); 169185099Sraj return (EIO); 170185099Sraj } 171185099Sraj bcount = size / od->od_bsize; 172185099Sraj 173185099Sraj if (rsize) 174185099Sraj *rsize = 0; 175185099Sraj 176185099Sraj err = stor_readdev(dev, blk + od->od_bstart, bcount, buf); 177185099Sraj if (!err && rsize) 178185099Sraj *rsize = size; 179185099Sraj 180185099Sraj return (err); 181176348Smarcel} 182176348Smarcel 183176348Smarcelstatic int 184185099Srajstor_open(struct open_file *f, ...) 185176348Smarcel{ 186185099Sraj va_list ap; 187185099Sraj struct open_dev *od; 188185099Sraj struct uboot_devdesc *dev; 189185099Sraj int err; 190177152Sobrien 191185099Sraj va_start(ap, f); 192185099Sraj dev = va_arg(ap, struct uboot_devdesc *); 193185099Sraj va_end(ap); 194185099Sraj 195185099Sraj if ((err = stor_opendev(&od, dev)) != 0) 196185099Sraj return (err); 197185099Sraj 198185099Sraj ((struct uboot_devdesc *)(f->f_devdata))->d_disk.data = od; 199185099Sraj 200185099Sraj return (0); 201176348Smarcel} 202176348Smarcel 203176348Smarcelstatic int 204185099Srajstor_close(struct open_file *f) 205176348Smarcel{ 206185099Sraj struct uboot_devdesc *dev; 207177152Sobrien 208185099Sraj dev = (struct uboot_devdesc *)(f->f_devdata); 209185099Sraj 210185099Sraj return (stor_closedev(dev)); 211176348Smarcel} 212176348Smarcel 213176348Smarcelstatic int 214185099Srajstor_open_gpt(struct open_dev *od, struct uboot_devdesc *dev) 215176348Smarcel{ 216177152Sobrien 217185099Sraj /* TODO */ 218185099Sraj return (ENXIO); 219176348Smarcel} 220176348Smarcel 221185099Srajstatic int 222185099Srajstor_open_bsdlabel(struct open_dev *od, struct uboot_devdesc *dev) 223185099Sraj{ 224185099Sraj char *buf; 225185099Sraj struct disklabel *dl; 226185099Sraj int err = 0; 227185099Sraj 228185099Sraj /* Allocate 1 block */ 229185099Sraj buf = malloc(od->od_bsize); 230185099Sraj if (!buf) { 231185099Sraj stor_printf("could not allocate memory for disklabel\n"); 232185099Sraj return (ENOMEM); 233185099Sraj } 234185099Sraj 235185099Sraj /* Read disklabel */ 236185099Sraj err = stor_readdev(dev, LABELSECTOR, 1, buf); 237185099Sraj if (err) { 238185099Sraj stor_printf("disklabel read error=%d\n", err); 239185099Sraj err = ERDLAB; 240185099Sraj goto out; 241185099Sraj } 242185099Sraj bcopy(buf + LABELOFFSET, &od->od_bsdlabel, sizeof(struct disklabel)); 243185099Sraj dl = &od->od_bsdlabel; 244185099Sraj 245185099Sraj if (dl->d_magic != DISKMAGIC) { 246185099Sraj stor_printf("no disklabel magic!\n"); 247185099Sraj err = EUNLAB; 248185099Sraj goto out; 249185099Sraj } 250185099Sraj od->od_type = OD_BSDLABEL; 251185099Sraj od->od_bstart = dl->d_partitions[dev->d_disk.partition].p_offset; 252185099Sraj 253185099Sraj debugf("bstart=%d\n", od->od_bstart); 254185099Sraj 255185099Srajout: 256185099Sraj free(buf); 257185099Sraj return (err); 258185099Sraj} 259185099Sraj 260185099Srajstatic int 261185099Srajstor_readdev(struct uboot_devdesc *dev, daddr_t blk, size_t size, char *buf) 262185099Sraj{ 263185099Sraj lbasize_t real_size; 264185099Sraj int err, handle; 265185099Sraj 266185099Sraj debugf("reading size=%d @ 0x%08x\n", size, (uint32_t)buf); 267185099Sraj 268185099Sraj handle = stor_info[dev->d_unit]; 269185099Sraj err = ub_dev_read(handle, buf, size, blk, &real_size); 270185099Sraj if (err != 0) { 271185099Sraj stor_printf("read failed, error=%d\n", err); 272185099Sraj return (EIO); 273185099Sraj } 274185099Sraj 275185099Sraj if (real_size != size) { 276185099Sraj stor_printf("real size != size\n"); 277185099Sraj err = EIO; 278185099Sraj } 279185099Sraj 280185099Sraj return (err); 281185099Sraj} 282185099Sraj 283185099Sraj 284185099Srajstatic int 285185099Srajstor_opendev(struct open_dev **odp, struct uboot_devdesc *dev) 286185099Sraj{ 287185099Sraj struct device_info *di; 288185099Sraj struct open_dev *od; 289185099Sraj int err, h; 290185099Sraj 291185099Sraj h = stor_info[dev->d_unit]; 292185099Sraj 293185099Sraj debugf("refcount=%d\n", stor_open_count); 294185099Sraj 295185099Sraj /* 296185099Sraj * There can be recursive open calls from the infrastructure, but at 297185099Sraj * U-Boot level open the device only the first time. 298185099Sraj */ 299185099Sraj if (stor_open_count > 0) 300185099Sraj stor_open_count++; 301185099Sraj else if ((err = ub_dev_open(h)) != 0) { 302185099Sraj stor_printf("device open failed with error=%d, handle=%d\n", 303185099Sraj err, h); 304185099Sraj *odp = NULL; 305185099Sraj return (ENXIO); 306185099Sraj } 307185099Sraj 308185099Sraj if ((di = ub_dev_get(h)) == NULL) 309185099Sraj panic("could not retrieve U-Boot device_info, handle=%d", h); 310185099Sraj 311185099Sraj if ((od = malloc(sizeof(struct open_dev))) == NULL) { 312185099Sraj stor_printf("could not allocate memory for open_dev\n"); 313185099Sraj return (ENOMEM); 314185099Sraj } 315185099Sraj od->od_bsize = di->di_stor.block_size; 316185099Sraj od->od_bstart = 0; 317185099Sraj od->od_type = 0; 318185099Sraj 319185099Sraj if ((err = stor_open_gpt(od, dev)) != 0) 320185099Sraj err = stor_open_bsdlabel(od, dev); 321185099Sraj 322185099Sraj if (err != 0) 323185099Sraj free(od); 324185099Sraj else { 325185099Sraj stor_open_count = 1; 326185099Sraj *odp = od; 327185099Sraj } 328185099Sraj 329185099Sraj return (err); 330185099Sraj} 331185099Sraj 332185099Srajstatic int 333185099Srajstor_closedev(struct uboot_devdesc *dev) 334185099Sraj{ 335185099Sraj int err, h; 336185099Sraj 337185099Sraj free((struct open_dev *)dev->d_disk.data); 338185099Sraj dev->d_disk.data = NULL; 339185099Sraj 340185099Sraj if (--stor_open_count == 0) { 341185099Sraj h = stor_info[dev->d_unit]; 342185099Sraj if ((err = ub_dev_close(h)) != 0) { 343185099Sraj stor_printf("device close failed with error=%d, " 344185099Sraj "handle=%d\n", err, h); 345185099Sraj return (ENXIO); 346185099Sraj } 347185099Sraj } 348185099Sraj 349185099Sraj return (0); 350185099Sraj} 351185099Sraj 352185099Sraj/* Given a size in 512 byte sectors, convert it to a human-readable number. */ 353185099Sraj/* XXX stolen from sys/boot/i386/libi386/biosdisk.c, should really be shared */ 354185099Srajstatic char * 355185099Srajdisplay_size(uint64_t size) 356185099Sraj{ 357185099Sraj static char buf[80]; 358185099Sraj char unit; 359185099Sraj 360185099Sraj size /= 2; 361185099Sraj unit = 'K'; 362185099Sraj if (size >= 10485760000LL) { 363185099Sraj size /= 1073741824; 364185099Sraj unit = 'T'; 365185099Sraj } else if (size >= 10240000) { 366185099Sraj size /= 1048576; 367185099Sraj unit = 'G'; 368185099Sraj } else if (size >= 10000) { 369185099Sraj size /= 1024; 370185099Sraj unit = 'M'; 371185099Sraj } 372185099Sraj sprintf(buf, "%.6ld%cB", (long)size, unit); 373185099Sraj return (buf); 374185099Sraj} 375185099Sraj 376176348Smarcelstatic void 377185099Srajstor_print_bsdlabel(struct uboot_devdesc *dev, char *prefix, int verbose) 378176348Smarcel{ 379185099Sraj char buf[512], line[80]; 380185099Sraj struct disklabel *dl; 381185099Sraj uint32_t off, size; 382185099Sraj int err, i, t; 383176348Smarcel 384185099Sraj /* Read disklabel */ 385185099Sraj err = stor_readdev(dev, LABELSECTOR, 1, buf); 386185099Sraj if (err) { 387185099Sraj sprintf(line, "%s%d: disklabel read error=%d\n", 388185099Sraj dev->d_dev->dv_name, dev->d_unit, err); 389185099Sraj pager_output(line); 390185099Sraj return; 391185099Sraj } 392185099Sraj dl = (struct disklabel *)buf; 393185099Sraj 394185099Sraj if (dl->d_magic != DISKMAGIC) { 395185099Sraj sprintf(line, "%s%d: no disklabel magic!\n", 396185099Sraj dev->d_dev->dv_name, dev->d_unit); 397185099Sraj pager_output(line); 398185099Sraj return; 399185099Sraj } 400185099Sraj 401185099Sraj /* Print partitions info */ 402185099Sraj for (i = 0; i < dl->d_npartitions; i++) { 403185099Sraj if ((t = dl->d_partitions[i].p_fstype) < FSMAXTYPES) { 404185099Sraj 405185099Sraj off = dl->d_partitions[i].p_offset; 406185099Sraj size = dl->d_partitions[i].p_size; 407185099Sraj if (fstypenames[t] == NULL || size == 0) 408185099Sraj continue; 409185099Sraj 410185099Sraj if ((('a' + i) == 'c') && (!verbose)) 411185099Sraj continue; 412185099Sraj 413185099Sraj sprintf(line, " %s%c: %s %s (%d - %d)\n", prefix, 414185099Sraj 'a' + i, fstypenames[t], display_size(size), 415185099Sraj off, off + size); 416185099Sraj 417185099Sraj pager_output(line); 418185099Sraj } 419185099Sraj } 420176348Smarcel} 421185099Sraj 422185099Srajstatic void 423185099Srajstor_print_one(int i, struct device_info *di, int verbose) 424185099Sraj{ 425185099Sraj struct uboot_devdesc dev; 426185099Sraj struct open_dev *od; 427185099Sraj char line[80]; 428185099Sraj 429185099Sraj sprintf(line, "\tdisk%d (%s)\n", i, ub_stor_type(di->type)); 430185099Sraj pager_output(line); 431185099Sraj 432185099Sraj dev.d_dev = &uboot_storage; 433185099Sraj dev.d_unit = i; 434185099Sraj dev.d_disk.partition = -1; 435185099Sraj dev.d_disk.data = NULL; 436185099Sraj 437185099Sraj if (stor_opendev(&od, &dev) == 0) { 438185099Sraj dev.d_disk.data = od; 439185099Sraj 440185099Sraj if (od->od_type == OD_GPT) { 441185099Sraj /* TODO */ 442185099Sraj 443185099Sraj } else if (od->od_type == OD_BSDLABEL) { 444185099Sraj sprintf(line, "\t\tdisk%d", i); 445185099Sraj stor_print_bsdlabel(&dev, line, verbose); 446185099Sraj } 447185099Sraj 448185099Sraj stor_closedev(&dev); 449185099Sraj } 450185099Sraj} 451185099Sraj 452185099Srajstatic void 453185099Srajstor_print(int verbose) 454185099Sraj{ 455185099Sraj struct device_info *di; 456185099Sraj int i; 457185099Sraj 458185099Sraj for (i = 0; i < stor_info_no; i++) { 459185099Sraj di = ub_dev_get(stor_info[i]); 460185099Sraj if (di != NULL) 461185099Sraj stor_print_one(i, di, verbose); 462185099Sraj } 463185099Sraj} 464