1/*- 2 * Copyright (c) 2008 Semihalf, Rafal Jaworowski 3 * Copyright (c) 2009 Semihalf, Piotr Ziecik 4 * Copyright (c) 2012 Andrey V. Elsukov <ae@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 */ 29 30/* 31 * Block storage I/O routines for U-Boot 32 */ 33 34#include <sys/cdefs.h> 35__FBSDID("$FreeBSD$"); 36 37#include <sys/param.h> 38#include <sys/disk.h> 39#include <machine/stdarg.h> 40#include <stand.h> 41 42#include "api_public.h" 43#include "bootstrap.h" 44#include "disk.h" 45#include "glue.h" 46#include "libuboot.h" 47 48#define DEBUG 49#undef DEBUG 50 51#define stor_printf(fmt, args...) do { \ 52 printf("%s%d: ", dev->d_dev->dv_name, dev->d_unit); \ 53 printf(fmt, ##args); \ 54} while (0) 55 56#ifdef DEBUG 57#define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 58 printf(fmt,##args); } while (0) 59#else 60#define debugf(fmt, args...) 61#endif 62 63static struct { 64 int opened; /* device is opened */ 65 int handle; /* storage device handle */ 66 int type; /* storage type */ 67 off_t blocks; /* block count */ 68 u_int bsize; /* block size */ 69} stor_info[UB_MAX_DEV]; 70 71#define SI(dev) (stor_info[(dev)->d_unit]) 72 73static int stor_info_no = 0; 74static int stor_opendev(struct disk_devdesc *); 75static int stor_readdev(struct disk_devdesc *, daddr_t, size_t, char *); 76 77/* devsw I/F */ 78static int stor_init(void); 79static int stor_strategy(void *, int, daddr_t, size_t, char *, size_t *); 80static int stor_open(struct open_file *, ...); 81static int stor_close(struct open_file *); 82static int stor_ioctl(struct open_file *f, u_long cmd, void *data); 83static void stor_print(int); 84static void stor_cleanup(void); 85 86struct devsw uboot_storage = { 87 "disk", 88 DEVT_DISK, 89 stor_init, 90 stor_strategy, 91 stor_open, 92 stor_close, 93 stor_ioctl, 94 stor_print, 95 stor_cleanup 96}; 97 98static int 99stor_init(void) 100{ 101 struct device_info *di; 102 int i; 103 104 if (devs_no == 0) { 105 printf("No U-Boot devices! Really enumerated?\n"); 106 return (-1); 107 } 108 109 for (i = 0; i < devs_no; i++) { 110 di = ub_dev_get(i); 111 if ((di != NULL) && (di->type & DEV_TYP_STOR)) { 112 if (stor_info_no >= UB_MAX_DEV) { 113 printf("Too many storage devices: %d\n", 114 stor_info_no); 115 return (-1); 116 } 117 stor_info[stor_info_no].handle = i; 118 stor_info[stor_info_no].opened = 0; 119 stor_info[stor_info_no].type = di->type; 120 stor_info[stor_info_no].blocks = 121 di->di_stor.block_count; 122 stor_info[stor_info_no].bsize = 123 di->di_stor.block_size; 124 stor_info_no++; 125 } 126 } 127 128 if (!stor_info_no) { 129 debugf("No storage devices\n"); 130 return (-1); 131 } 132 133 debugf("storage devices found: %d\n", stor_info_no); 134 return (0); 135} 136 137static void 138stor_cleanup(void) 139{ 140 int i; 141 142 for (i = 0; i < stor_info_no; i++) 143 if (stor_info[i].opened > 0) 144 ub_dev_close(stor_info[i].handle); 145 disk_cleanup(&uboot_storage); 146} 147 148static int 149stor_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, 150 size_t *rsize) 151{ 152 struct disk_devdesc *dev = (struct disk_devdesc *)devdata; 153 daddr_t bcount; 154 int err; 155 156 if (rw != F_READ) { 157 stor_printf("write attempt, operation not supported!\n"); 158 return (EROFS); 159 } 160 161 if (size % SI(dev).bsize) { 162 stor_printf("size=%d not multiple of device block size=%d\n", 163 size, SI(dev).bsize); 164 return (EIO); 165 } 166 bcount = size / SI(dev).bsize; 167 if (rsize) 168 *rsize = 0; 169 170 err = stor_readdev(dev, blk + dev->d_offset, bcount, buf); 171 if (!err && rsize) 172 *rsize = size; 173 174 return (err); 175} 176 177static int 178stor_open(struct open_file *f, ...) 179{ 180 va_list ap; 181 struct disk_devdesc *dev; 182 183 va_start(ap, f); 184 dev = va_arg(ap, struct disk_devdesc *); 185 va_end(ap); 186 187 return (stor_opendev(dev)); 188} 189 190static int 191stor_opendev(struct disk_devdesc *dev) 192{ 193 int err; 194 195 if (dev->d_unit < 0 || dev->d_unit >= stor_info_no) 196 return (EIO); 197 198 if (SI(dev).opened == 0) { 199 err = ub_dev_open(SI(dev).handle); 200 if (err != 0) { 201 stor_printf("device open failed with error=%d, " 202 "handle=%d\n", err, SI(dev).handle); 203 return (ENXIO); 204 } 205 SI(dev).opened++; 206 } 207 return (disk_open(dev, SI(dev).blocks * SI(dev).bsize, 208 SI(dev).bsize, 0)); 209} 210 211static int 212stor_close(struct open_file *f) 213{ 214 struct disk_devdesc *dev; 215 216 dev = (struct disk_devdesc *)(f->f_devdata); 217 return (disk_close(dev)); 218} 219 220static int 221stor_readdev(struct disk_devdesc *dev, daddr_t blk, size_t size, char *buf) 222{ 223 lbasize_t real_size; 224 int err; 225 226 debugf("reading blk=%d size=%d @ 0x%08x\n", (int)blk, size, (uint32_t)buf); 227 228 err = ub_dev_read(SI(dev).handle, buf, size, blk, &real_size); 229 if (err != 0) { 230 stor_printf("read failed, error=%d\n", err); 231 return (EIO); 232 } 233 234 if (real_size != size) { 235 stor_printf("real size != size\n"); 236 err = EIO; 237 } 238 239 return (err); 240} 241 242static void 243stor_print(int verbose) 244{ 245 struct disk_devdesc dev; 246 static char line[80]; 247 int i; 248 249 for (i = 0; i < stor_info_no; i++) { 250 dev.d_dev = &uboot_storage; 251 dev.d_unit = i; 252 dev.d_slice = -1; 253 dev.d_partition = -1; 254 sprintf(line, "\tdisk%d (%s)\n", i, 255 ub_stor_type(SI(&dev).type)); 256 pager_output(line); 257 if (stor_opendev(&dev) == 0) { 258 sprintf(line, "\tdisk%d", i); 259 disk_print(&dev, line, verbose); 260 disk_close(&dev); 261 } 262 } 263} 264 265static int 266stor_ioctl(struct open_file *f, u_long cmd, void *data) 267{ 268 struct disk_devdesc *dev; 269 270 dev = (struct disk_devdesc *)f->f_devdata; 271 switch (cmd) { 272 case DIOCGSECTORSIZE: 273 *(u_int *)data = SI(dev).bsize; 274 break; 275 case DIOCGMEDIASIZE: 276 *(off_t *)data = SI(dev).bsize * SI(dev).blocks; 277 break; 278 default: 279 return (ENOTTY); 280 } 281 return (0); 282} 283 284