1223695Sdfr/*- 2223695Sdfr * Copyright (c) 2011 Google, Inc. 3223695Sdfr * All rights reserved. 4223695Sdfr * 5223695Sdfr * Redistribution and use in source and binary forms, with or without 6223695Sdfr * modification, are permitted provided that the following conditions 7223695Sdfr * are met: 8223695Sdfr * 1. Redistributions of source code must retain the above copyright 9223695Sdfr * notice, this list of conditions and the following disclaimer. 10223695Sdfr * 2. Redistributions in binary form must reproduce the above copyright 11223695Sdfr * notice, this list of conditions and the following disclaimer in the 12223695Sdfr * documentation and/or other materials provided with the distribution. 13223695Sdfr * 14223695Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15223695Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16223695Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17223695Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18223695Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19223695Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20223695Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21223695Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22223695Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23223695Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24223695Sdfr * SUCH DAMAGE. 25223695Sdfr */ 26223695Sdfr 27223695Sdfr#include <sys/cdefs.h> 28223695Sdfr__FBSDID("$FreeBSD: stable/11/stand/userboot/userboot/userboot_disk.c 332154 2018-04-06 21:37:25Z kevans $"); 29223695Sdfr 30223695Sdfr/* 31223695Sdfr * Userboot disk image handling. 32223695Sdfr */ 33223695Sdfr 34239058Sae#include <sys/disk.h> 35223695Sdfr#include <stand.h> 36223695Sdfr#include <stdarg.h> 37223695Sdfr#include <bootstrap.h> 38223695Sdfr 39223695Sdfr#include "disk.h" 40223695Sdfr#include "libuserboot.h" 41223695Sdfr 42239058Saestruct userdisk_info { 43239058Sae uint64_t mediasize; 44239058Sae uint16_t sectorsize; 45298230Sallanjude int ud_open; /* reference counter */ 46298230Sallanjude void *ud_bcache; /* buffer cache data */ 47239058Sae}; 48239058Sae 49223695Sdfrint userboot_disk_maxunit = 0; 50223695Sdfr 51239058Saestatic int userdisk_maxunit = 0; 52239058Saestatic struct userdisk_info *ud_info; 53239058Sae 54223695Sdfrstatic int userdisk_init(void); 55239058Saestatic void userdisk_cleanup(void); 56223695Sdfrstatic int userdisk_strategy(void *devdata, int flag, daddr_t dblk, 57313355Stsoome size_t size, char *buf, size_t *rsize); 58298230Sallanjudestatic int userdisk_realstrategy(void *devdata, int flag, daddr_t dblk, 59313355Stsoome size_t size, char *buf, size_t *rsize); 60223695Sdfrstatic int userdisk_open(struct open_file *f, ...); 61223695Sdfrstatic int userdisk_close(struct open_file *f); 62239058Saestatic int userdisk_ioctl(struct open_file *f, u_long cmd, void *data); 63328889Skevansstatic int userdisk_print(int verbose); 64223695Sdfr 65223695Sdfrstruct devsw userboot_disk = { 66223695Sdfr "disk", 67223695Sdfr DEVT_DISK, 68223695Sdfr userdisk_init, 69223695Sdfr userdisk_strategy, 70223695Sdfr userdisk_open, 71223695Sdfr userdisk_close, 72239058Sae userdisk_ioctl, 73223695Sdfr userdisk_print, 74239058Sae userdisk_cleanup 75223695Sdfr}; 76223695Sdfr 77223695Sdfr/* 78239058Sae * Initialize userdisk_info structure for each disk. 79223695Sdfr */ 80223695Sdfrstatic int 81223695Sdfruserdisk_init(void) 82223695Sdfr{ 83239058Sae off_t mediasize; 84239058Sae u_int sectorsize; 85239058Sae int i; 86223695Sdfr 87239058Sae userdisk_maxunit = userboot_disk_maxunit; 88239058Sae if (userdisk_maxunit > 0) { 89239058Sae ud_info = malloc(sizeof(*ud_info) * userdisk_maxunit); 90239058Sae if (ud_info == NULL) 91239058Sae return (ENOMEM); 92239058Sae for (i = 0; i < userdisk_maxunit; i++) { 93239058Sae if (CALLBACK(diskioctl, i, DIOCGSECTORSIZE, 94329100Skevans §orsize) != 0 || CALLBACK(diskioctl, i, 95329100Skevans DIOCGMEDIASIZE, &mediasize) != 0) 96239058Sae return (ENXIO); 97239058Sae ud_info[i].mediasize = mediasize; 98239058Sae ud_info[i].sectorsize = sectorsize; 99298230Sallanjude ud_info[i].ud_open = 0; 100298230Sallanjude ud_info[i].ud_bcache = NULL; 101239058Sae } 102239058Sae } 103298230Sallanjude bcache_add_dev(userdisk_maxunit); 104223695Sdfr return(0); 105223695Sdfr} 106223695Sdfr 107239058Saestatic void 108239058Saeuserdisk_cleanup(void) 109239058Sae{ 110239058Sae 111239058Sae if (userdisk_maxunit > 0) 112239058Sae free(ud_info); 113239058Sae} 114239058Sae 115223695Sdfr/* 116223695Sdfr * Print information about disks 117223695Sdfr */ 118328889Skevansstatic int 119223695Sdfruserdisk_print(int verbose) 120223695Sdfr{ 121239058Sae struct disk_devdesc dev; 122239058Sae char line[80]; 123328889Skevans int i, ret = 0; 124223695Sdfr 125328889Skevans if (userdisk_maxunit == 0) 126328889Skevans return (0); 127328889Skevans 128328889Skevans printf("%s devices:", userboot_disk.dv_name); 129328889Skevans if ((ret = pager_output("\n")) != 0) 130328889Skevans return (ret); 131328889Skevans 132239058Sae for (i = 0; i < userdisk_maxunit; i++) { 133328889Skevans snprintf(line, sizeof(line), 134328889Skevans " disk%d: Guest drive image\n", i); 135328889Skevans ret = pager_output(line); 136328889Skevans if (ret != 0) 137328889Skevans break; 138332154Skevans dev.dd.d_dev = &userboot_disk; 139332154Skevans dev.dd.d_unit = i; 140223695Sdfr dev.d_slice = -1; 141223695Sdfr dev.d_partition = -1; 142239058Sae if (disk_open(&dev, ud_info[i].mediasize, 143329099Skevans ud_info[i].sectorsize) == 0) { 144328889Skevans snprintf(line, sizeof(line), " disk%d", i); 145328889Skevans ret = disk_print(&dev, line, verbose); 146239058Sae disk_close(&dev); 147328889Skevans if (ret != 0) 148328889Skevans break; 149239058Sae } 150223695Sdfr } 151328889Skevans return (ret); 152223695Sdfr} 153223695Sdfr 154223695Sdfr/* 155223695Sdfr * Attempt to open the disk described by (dev) for use by (f). 156223695Sdfr */ 157223695Sdfrstatic int 158223695Sdfruserdisk_open(struct open_file *f, ...) 159223695Sdfr{ 160223695Sdfr va_list ap; 161223695Sdfr struct disk_devdesc *dev; 162223695Sdfr 163223695Sdfr va_start(ap, f); 164223695Sdfr dev = va_arg(ap, struct disk_devdesc *); 165223695Sdfr va_end(ap); 166223695Sdfr 167332154Skevans if (dev->dd.d_unit < 0 || dev->dd.d_unit >= userdisk_maxunit) 168223695Sdfr return (EIO); 169332154Skevans ud_info[dev->dd.d_unit].ud_open++; 170332154Skevans if (ud_info[dev->dd.d_unit].ud_bcache == NULL) 171332154Skevans ud_info[dev->dd.d_unit].ud_bcache = bcache_allocate(); 172332154Skevans return (disk_open(dev, ud_info[dev->dd.d_unit].mediasize, 173332154Skevans ud_info[dev->dd.d_unit].sectorsize)); 174223695Sdfr} 175223695Sdfr 176223695Sdfrstatic int 177223695Sdfruserdisk_close(struct open_file *f) 178223695Sdfr{ 179239058Sae struct disk_devdesc *dev; 180223695Sdfr 181239058Sae dev = (struct disk_devdesc *)f->f_devdata; 182332154Skevans ud_info[dev->dd.d_unit].ud_open--; 183332154Skevans if (ud_info[dev->dd.d_unit].ud_open == 0) { 184332154Skevans bcache_free(ud_info[dev->dd.d_unit].ud_bcache); 185332154Skevans ud_info[dev->dd.d_unit].ud_bcache = NULL; 186298230Sallanjude } 187239058Sae return (disk_close(dev)); 188223695Sdfr} 189223695Sdfr 190223695Sdfrstatic int 191313355Stsoomeuserdisk_strategy(void *devdata, int rw, daddr_t dblk, size_t size, 192313355Stsoome char *buf, size_t *rsize) 193223695Sdfr{ 194298230Sallanjude struct bcache_devdata bcd; 195298230Sallanjude struct disk_devdesc *dev; 196298230Sallanjude 197298230Sallanjude dev = (struct disk_devdesc *)devdata; 198298230Sallanjude bcd.dv_strategy = userdisk_realstrategy; 199298230Sallanjude bcd.dv_devdata = devdata; 200332154Skevans bcd.dv_cache = ud_info[dev->dd.d_unit].ud_bcache; 201313355Stsoome return (bcache_strategy(&bcd, rw, dblk + dev->d_offset, 202298230Sallanjude size, buf, rsize)); 203298230Sallanjude} 204298230Sallanjude 205298230Sallanjudestatic int 206313355Stsoomeuserdisk_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, 207313355Stsoome char *buf, size_t *rsize) 208298230Sallanjude{ 209223695Sdfr struct disk_devdesc *dev = devdata; 210223695Sdfr uint64_t off; 211223695Sdfr size_t resid; 212223695Sdfr int rc; 213223695Sdfr 214329100Skevans rw &= F_MASK; 215223695Sdfr if (rw == F_WRITE) 216223695Sdfr return (EROFS); 217223695Sdfr if (rw != F_READ) 218223695Sdfr return (EINVAL); 219223695Sdfr if (rsize) 220223695Sdfr *rsize = 0; 221332154Skevans off = dblk * ud_info[dev->dd.d_unit].sectorsize; 222332154Skevans rc = CALLBACK(diskread, dev->dd.d_unit, off, buf, size, &resid); 223223695Sdfr if (rc) 224223695Sdfr return (rc); 225223695Sdfr if (rsize) 226223695Sdfr *rsize = size - resid; 227223695Sdfr return (0); 228223695Sdfr} 229239058Sae 230239058Saestatic int 231239058Saeuserdisk_ioctl(struct open_file *f, u_long cmd, void *data) 232239058Sae{ 233239058Sae struct disk_devdesc *dev; 234329100Skevans int rc; 235239058Sae 236239058Sae dev = (struct disk_devdesc *)f->f_devdata; 237329100Skevans rc = disk_ioctl(dev, cmd, data); 238329100Skevans if (rc != ENOTTY) 239329100Skevans return (rc); 240329100Skevans 241332154Skevans return (CALLBACK(diskioctl, dev->dd.d_unit, cmd, data)); 242239058Sae} 243