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$"); 29223695Sdfr 30223695Sdfr/* 31223695Sdfr * Userboot disk image handling. 32223695Sdfr */ 33223695Sdfr 34243243Sae#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 42243243Saestruct userdisk_info { 43243243Sae uint64_t mediasize; 44243243Sae uint16_t sectorsize; 45243243Sae}; 46243243Sae 47223695Sdfrint userboot_disk_maxunit = 0; 48223695Sdfr 49243243Saestatic int userdisk_maxunit = 0; 50243243Saestatic struct userdisk_info *ud_info; 51243243Sae 52223695Sdfrstatic int userdisk_init(void); 53243243Saestatic void userdisk_cleanup(void); 54223695Sdfrstatic int userdisk_strategy(void *devdata, int flag, daddr_t dblk, 55223695Sdfr size_t size, char *buf, size_t *rsize); 56223695Sdfrstatic int userdisk_open(struct open_file *f, ...); 57223695Sdfrstatic int userdisk_close(struct open_file *f); 58243243Saestatic int userdisk_ioctl(struct open_file *f, u_long cmd, void *data); 59223695Sdfrstatic void userdisk_print(int verbose); 60223695Sdfr 61223695Sdfrstruct devsw userboot_disk = { 62223695Sdfr "disk", 63223695Sdfr DEVT_DISK, 64223695Sdfr userdisk_init, 65223695Sdfr userdisk_strategy, 66223695Sdfr userdisk_open, 67223695Sdfr userdisk_close, 68243243Sae userdisk_ioctl, 69223695Sdfr userdisk_print, 70243243Sae userdisk_cleanup 71223695Sdfr}; 72223695Sdfr 73223695Sdfr/* 74243243Sae * Initialize userdisk_info structure for each disk. 75223695Sdfr */ 76223695Sdfrstatic int 77223695Sdfruserdisk_init(void) 78223695Sdfr{ 79243243Sae off_t mediasize; 80243243Sae u_int sectorsize; 81243243Sae int i; 82223695Sdfr 83243243Sae userdisk_maxunit = userboot_disk_maxunit; 84243243Sae if (userdisk_maxunit > 0) { 85243243Sae ud_info = malloc(sizeof(*ud_info) * userdisk_maxunit); 86243243Sae if (ud_info == NULL) 87243243Sae return (ENOMEM); 88243243Sae for (i = 0; i < userdisk_maxunit; i++) { 89243243Sae if (CALLBACK(diskioctl, i, DIOCGSECTORSIZE, 90243243Sae §orsize) != 0 || CALLBACK(diskioctl, i, 91243243Sae DIOCGMEDIASIZE, &mediasize) != 0) 92243243Sae return (ENXIO); 93243243Sae ud_info[i].mediasize = mediasize; 94243243Sae ud_info[i].sectorsize = sectorsize; 95243243Sae } 96243243Sae } 97243243Sae 98223695Sdfr return(0); 99223695Sdfr} 100223695Sdfr 101243243Saestatic void 102243243Saeuserdisk_cleanup(void) 103243243Sae{ 104243243Sae 105243243Sae if (userdisk_maxunit > 0) 106243243Sae free(ud_info); 107243243Sae disk_cleanup(&userboot_disk); 108243243Sae} 109243243Sae 110223695Sdfr/* 111223695Sdfr * Print information about disks 112223695Sdfr */ 113223695Sdfrstatic void 114223695Sdfruserdisk_print(int verbose) 115223695Sdfr{ 116243243Sae struct disk_devdesc dev; 117243243Sae char line[80]; 118243243Sae int i; 119223695Sdfr 120243243Sae for (i = 0; i < userdisk_maxunit; i++) { 121223695Sdfr sprintf(line, " disk%d: Guest drive image\n", i); 122223695Sdfr pager_output(line); 123223695Sdfr dev.d_dev = &userboot_disk; 124223695Sdfr dev.d_unit = i; 125223695Sdfr dev.d_slice = -1; 126223695Sdfr dev.d_partition = -1; 127243243Sae if (disk_open(&dev, ud_info[i].mediasize, 128243243Sae ud_info[i].sectorsize, 0) == 0) { 129243243Sae sprintf(line, " disk%d", i); 130243243Sae disk_print(&dev, line, verbose); 131243243Sae disk_close(&dev); 132243243Sae } 133223695Sdfr } 134223695Sdfr} 135223695Sdfr 136223695Sdfr/* 137223695Sdfr * Attempt to open the disk described by (dev) for use by (f). 138223695Sdfr */ 139223695Sdfrstatic int 140223695Sdfruserdisk_open(struct open_file *f, ...) 141223695Sdfr{ 142223695Sdfr va_list ap; 143223695Sdfr struct disk_devdesc *dev; 144223695Sdfr 145223695Sdfr va_start(ap, f); 146223695Sdfr dev = va_arg(ap, struct disk_devdesc *); 147223695Sdfr va_end(ap); 148223695Sdfr 149243243Sae if (dev->d_unit < 0 || dev->d_unit >= userdisk_maxunit) 150223695Sdfr return (EIO); 151223695Sdfr 152243243Sae return (disk_open(dev, ud_info[dev->d_unit].mediasize, 153243243Sae ud_info[dev->d_unit].sectorsize, 0)); 154223695Sdfr} 155223695Sdfr 156223695Sdfrstatic int 157223695Sdfruserdisk_close(struct open_file *f) 158223695Sdfr{ 159243243Sae struct disk_devdesc *dev; 160223695Sdfr 161243243Sae dev = (struct disk_devdesc *)f->f_devdata; 162243243Sae return (disk_close(dev)); 163223695Sdfr} 164223695Sdfr 165223695Sdfrstatic int 166223695Sdfruserdisk_strategy(void *devdata, int rw, daddr_t dblk, size_t size, 167223695Sdfr char *buf, size_t *rsize) 168223695Sdfr{ 169223695Sdfr struct disk_devdesc *dev = devdata; 170223695Sdfr uint64_t off; 171223695Sdfr size_t resid; 172223695Sdfr int rc; 173223695Sdfr 174223695Sdfr if (rw == F_WRITE) 175223695Sdfr return (EROFS); 176223695Sdfr if (rw != F_READ) 177223695Sdfr return (EINVAL); 178223695Sdfr if (rsize) 179223695Sdfr *rsize = 0; 180243243Sae off = (dblk + dev->d_offset) * ud_info[dev->d_unit].sectorsize; 181223695Sdfr rc = CALLBACK(diskread, dev->d_unit, off, buf, size, &resid); 182223695Sdfr if (rc) 183223695Sdfr return (rc); 184223695Sdfr if (rsize) 185223695Sdfr *rsize = size - resid; 186223695Sdfr return (0); 187223695Sdfr} 188243243Sae 189243243Saestatic int 190243243Saeuserdisk_ioctl(struct open_file *f, u_long cmd, void *data) 191243243Sae{ 192243243Sae struct disk_devdesc *dev; 193243243Sae 194243243Sae dev = (struct disk_devdesc *)f->f_devdata; 195243243Sae return (CALLBACK(diskioctl, dev->d_unit, cmd, data)); 196243243Sae} 197