1176348Smarcel/*- 2185099Sraj * Copyright (c) 2008 Semihalf, Rafal Jaworowski 3191829Sraj * Copyright (c) 2009 Semihalf, Piotr Ziecik 4243243Sae * Copyright (c) 2012 Andrey V. Elsukov <ae@FreeBSD.org> 5176348Smarcel * All rights reserved. 6176348Smarcel * 7176348Smarcel * Redistribution and use in source and binary forms, with or without 8176348Smarcel * modification, are permitted provided that the following conditions 9176348Smarcel * are met: 10176348Smarcel * 1. Redistributions of source code must retain the above copyright 11176348Smarcel * notice, this list of conditions and the following disclaimer. 12176348Smarcel * 2. Redistributions in binary form must reproduce the above copyright 13176348Smarcel * notice, this list of conditions and the following disclaimer in the 14176348Smarcel * documentation and/or other materials provided with the distribution. 15176348Smarcel * 16185099Sraj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17185099Sraj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18185099Sraj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19185099Sraj * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20185099Sraj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21185099Sraj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22185099Sraj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23185099Sraj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24185099Sraj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25185099Sraj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26185099Sraj * SUCH DAMAGE. 27185099Sraj * 28176348Smarcel */ 29176348Smarcel 30185099Sraj/* 31185099Sraj * Block storage I/O routines for U-Boot 32185099Sraj */ 33185099Sraj 34176348Smarcel#include <sys/cdefs.h> 35176348Smarcel__FBSDID("$FreeBSD$"); 36176348Smarcel 37176348Smarcel#include <sys/param.h> 38243243Sae#include <sys/disk.h> 39176348Smarcel#include <machine/stdarg.h> 40176348Smarcel#include <stand.h> 41176348Smarcel 42185099Sraj#include "api_public.h" 43176348Smarcel#include "bootstrap.h" 44243243Sae#include "disk.h" 45185099Sraj#include "glue.h" 46185099Sraj#include "libuboot.h" 47176348Smarcel 48185099Sraj#define DEBUG 49185099Sraj#undef DEBUG 50176348Smarcel 51185099Sraj#define stor_printf(fmt, args...) do { \ 52185099Sraj printf("%s%d: ", dev->d_dev->dv_name, dev->d_unit); \ 53185099Sraj printf(fmt, ##args); \ 54185099Sraj} while (0) 55185099Sraj 56185099Sraj#ifdef DEBUG 57185099Sraj#define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 58185099Sraj printf(fmt,##args); } while (0) 59185099Sraj#else 60185099Sraj#define debugf(fmt, args...) 61185099Sraj#endif 62185099Sraj 63243243Saestatic struct { 64243243Sae int opened; /* device is opened */ 65243243Sae int handle; /* storage device handle */ 66243243Sae int type; /* storage type */ 67243243Sae off_t blocks; /* block count */ 68243243Sae u_int bsize; /* block size */ 69243243Sae} stor_info[UB_MAX_DEV]; 70176348Smarcel 71243243Sae#define SI(dev) (stor_info[(dev)->d_unit]) 72176348Smarcel 73185099Srajstatic int stor_info_no = 0; 74243243Saestatic int stor_opendev(struct disk_devdesc *); 75243243Saestatic int stor_readdev(struct disk_devdesc *, daddr_t, size_t, char *); 76185099Sraj 77185099Sraj/* devsw I/F */ 78185099Srajstatic int stor_init(void); 79185099Srajstatic int stor_strategy(void *, int, daddr_t, size_t, char *, size_t *); 80185099Srajstatic int stor_open(struct open_file *, ...); 81185099Srajstatic int stor_close(struct open_file *); 82243243Saestatic int stor_ioctl(struct open_file *f, u_long cmd, void *data); 83185099Srajstatic void stor_print(int); 84243243Saestatic void stor_cleanup(void); 85185099Sraj 86185099Srajstruct devsw uboot_storage = { 87185099Sraj "disk", 88185099Sraj DEVT_DISK, 89185099Sraj stor_init, 90185099Sraj stor_strategy, 91185099Sraj stor_open, 92185099Sraj stor_close, 93243243Sae stor_ioctl, 94243243Sae stor_print, 95243243Sae stor_cleanup 96185099Sraj}; 97185099Sraj 98176348Smarcelstatic int 99185099Srajstor_init(void) 100176348Smarcel{ 101185099Sraj struct device_info *di; 102243243Sae int i; 103177152Sobrien 104185099Sraj if (devs_no == 0) { 105185099Sraj printf("No U-Boot devices! Really enumerated?\n"); 106185099Sraj return (-1); 107185099Sraj } 108185099Sraj 109185099Sraj for (i = 0; i < devs_no; i++) { 110185099Sraj di = ub_dev_get(i); 111185099Sraj if ((di != NULL) && (di->type & DEV_TYP_STOR)) { 112185099Sraj if (stor_info_no >= UB_MAX_DEV) { 113185099Sraj printf("Too many storage devices: %d\n", 114185099Sraj stor_info_no); 115185099Sraj return (-1); 116185099Sraj } 117243243Sae stor_info[stor_info_no].handle = i; 118243243Sae stor_info[stor_info_no].opened = 0; 119243243Sae stor_info[stor_info_no].type = di->type; 120243243Sae stor_info[stor_info_no].blocks = 121243243Sae di->di_stor.block_count; 122243243Sae stor_info[stor_info_no].bsize = 123243243Sae di->di_stor.block_size; 124243243Sae stor_info_no++; 125185099Sraj } 126185099Sraj } 127185099Sraj 128243243Sae if (!stor_info_no) { 129208534Sraj debugf("No storage devices\n"); 130185099Sraj return (-1); 131185099Sraj } 132185099Sraj 133185099Sraj debugf("storage devices found: %d\n", stor_info_no); 134185099Sraj return (0); 135176348Smarcel} 136176348Smarcel 137243243Saestatic void 138243243Saestor_cleanup(void) 139243243Sae{ 140243243Sae int i; 141243243Sae 142243243Sae for (i = 0; i < stor_info_no; i++) 143243243Sae if (stor_info[i].opened > 0) 144243243Sae ub_dev_close(stor_info[i].handle); 145243243Sae disk_cleanup(&uboot_storage); 146243243Sae} 147243243Sae 148176348Smarcelstatic int 149185099Srajstor_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, 150176348Smarcel size_t *rsize) 151176348Smarcel{ 152243243Sae struct disk_devdesc *dev = (struct disk_devdesc *)devdata; 153243243Sae daddr_t bcount; 154243243Sae int err; 155177152Sobrien 156185099Sraj if (rw != F_READ) { 157185099Sraj stor_printf("write attempt, operation not supported!\n"); 158185099Sraj return (EROFS); 159185099Sraj } 160185099Sraj 161243243Sae if (size % SI(dev).bsize) { 162185099Sraj stor_printf("size=%d not multiple of device block size=%d\n", 163243243Sae size, SI(dev).bsize); 164185099Sraj return (EIO); 165185099Sraj } 166243243Sae bcount = size / SI(dev).bsize; 167185099Sraj if (rsize) 168185099Sraj *rsize = 0; 169185099Sraj 170243243Sae err = stor_readdev(dev, blk + dev->d_offset, bcount, buf); 171185099Sraj if (!err && rsize) 172185099Sraj *rsize = size; 173185099Sraj 174185099Sraj return (err); 175176348Smarcel} 176176348Smarcel 177176348Smarcelstatic int 178185099Srajstor_open(struct open_file *f, ...) 179176348Smarcel{ 180185099Sraj va_list ap; 181243243Sae struct disk_devdesc *dev; 182177152Sobrien 183185099Sraj va_start(ap, f); 184243243Sae dev = va_arg(ap, struct disk_devdesc *); 185185099Sraj va_end(ap); 186185099Sraj 187243243Sae return (stor_opendev(dev)); 188176348Smarcel} 189176348Smarcel 190176348Smarcelstatic int 191243243Saestor_opendev(struct disk_devdesc *dev) 192176348Smarcel{ 193243243Sae int err; 194177152Sobrien 195243243Sae if (dev->d_unit < 0 || dev->d_unit >= stor_info_no) 196243243Sae return (EIO); 197185099Sraj 198243243Sae if (SI(dev).opened == 0) { 199243243Sae err = ub_dev_open(SI(dev).handle); 200243243Sae if (err != 0) { 201243243Sae stor_printf("device open failed with error=%d, " 202243243Sae "handle=%d\n", err, SI(dev).handle); 203243243Sae return (ENXIO); 204191829Sraj } 205243243Sae SI(dev).opened++; 206191829Sraj } 207243243Sae return (disk_open(dev, SI(dev).blocks * SI(dev).bsize, 208243243Sae SI(dev).bsize, 0)); 209176348Smarcel} 210176348Smarcel 211185099Srajstatic int 212243243Saestor_close(struct open_file *f) 213243236Sae{ 214243243Sae struct disk_devdesc *dev; 215243236Sae 216243243Sae dev = (struct disk_devdesc *)(f->f_devdata); 217243243Sae return (disk_close(dev)); 218243236Sae} 219243236Sae 220243236Saestatic int 221243243Saestor_readdev(struct disk_devdesc *dev, daddr_t blk, size_t size, char *buf) 222185099Sraj{ 223185099Sraj lbasize_t real_size; 224243243Sae int err; 225185099Sraj 226243236Sae debugf("reading blk=%d size=%d @ 0x%08x\n", (int)blk, size, (uint32_t)buf); 227185099Sraj 228243243Sae err = ub_dev_read(SI(dev).handle, buf, size, blk, &real_size); 229185099Sraj if (err != 0) { 230185099Sraj stor_printf("read failed, error=%d\n", err); 231185099Sraj return (EIO); 232185099Sraj } 233185099Sraj 234185099Sraj if (real_size != size) { 235185099Sraj stor_printf("real size != size\n"); 236185099Sraj err = EIO; 237185099Sraj } 238185099Sraj 239185099Sraj return (err); 240185099Sraj} 241185099Sraj 242176348Smarcelstatic void 243243243Saestor_print(int verbose) 244176348Smarcel{ 245243243Sae struct disk_devdesc dev; 246243243Sae static char line[80]; 247243243Sae int i; 248176348Smarcel 249243243Sae for (i = 0; i < stor_info_no; i++) { 250243243Sae dev.d_dev = &uboot_storage; 251243243Sae dev.d_unit = i; 252243243Sae dev.d_slice = -1; 253243243Sae dev.d_partition = -1; 254243243Sae sprintf(line, "\tdisk%d (%s)\n", i, 255243243Sae ub_stor_type(SI(&dev).type)); 256185099Sraj pager_output(line); 257243243Sae if (stor_opendev(&dev) == 0) { 258243243Sae sprintf(line, "\tdisk%d", i); 259243243Sae disk_print(&dev, line, verbose); 260243243Sae disk_close(&dev); 261185099Sraj } 262185099Sraj } 263176348Smarcel} 264185099Sraj 265243243Saestatic int 266243243Saestor_ioctl(struct open_file *f, u_long cmd, void *data) 267191829Sraj{ 268243243Sae struct disk_devdesc *dev; 269191829Sraj 270243243Sae dev = (struct disk_devdesc *)f->f_devdata; 271243243Sae switch (cmd) { 272243243Sae case DIOCGSECTORSIZE: 273243243Sae *(u_int *)data = SI(dev).bsize; 274243243Sae break; 275243243Sae case DIOCGMEDIASIZE: 276243243Sae *(off_t *)data = SI(dev).bsize * SI(dev).blocks; 277243243Sae break; 278243243Sae default: 279243243Sae return (ENOTTY); 280191829Sraj } 281243243Sae return (0); 282191829Sraj} 283191829Sraj 284