1*ca987d46SWarner Losh /* $FreeBSD$ */ 2*ca987d46SWarner Losh /*- 3*ca987d46SWarner Losh * Copyright (c) 2014 Hans Petter Selasky <hselasky@FreeBSD.org> 4*ca987d46SWarner Losh * All rights reserved. 5*ca987d46SWarner Losh * 6*ca987d46SWarner Losh * This software was developed by SRI International and the University of 7*ca987d46SWarner Losh * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 8*ca987d46SWarner Losh * ("CTSRD"), as part of the DARPA CRASH research programme. 9*ca987d46SWarner Losh * 10*ca987d46SWarner Losh * Redistribution and use in source and binary forms, with or without 11*ca987d46SWarner Losh * modification, are permitted provided that the following conditions 12*ca987d46SWarner Losh * are met: 13*ca987d46SWarner Losh * 1. Redistributions of source code must retain the above copyright 14*ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer. 15*ca987d46SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 16*ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer in the 17*ca987d46SWarner Losh * documentation and/or other materials provided with the distribution. 18*ca987d46SWarner Losh * 19*ca987d46SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20*ca987d46SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21*ca987d46SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22*ca987d46SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23*ca987d46SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24*ca987d46SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25*ca987d46SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26*ca987d46SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27*ca987d46SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28*ca987d46SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29*ca987d46SWarner Losh * SUCH DAMAGE. 30*ca987d46SWarner Losh */ 31*ca987d46SWarner Losh 32*ca987d46SWarner Losh #include <sys/param.h> 33*ca987d46SWarner Losh 34*ca987d46SWarner Losh #include <bootstrap.h> 35*ca987d46SWarner Losh #include <stdarg.h> 36*ca987d46SWarner Losh 37*ca987d46SWarner Losh #include <stand.h> 38*ca987d46SWarner Losh #include <disk.h> 39*ca987d46SWarner Losh 40*ca987d46SWarner Losh #define HAVE_STANDARD_DEFS 41*ca987d46SWarner Losh 42*ca987d46SWarner Losh #include USB_GLOBAL_INCLUDE_FILE 43*ca987d46SWarner Losh 44*ca987d46SWarner Losh #include "umass_common.h" 45*ca987d46SWarner Losh 46*ca987d46SWarner Losh static int umass_disk_init(void); 47*ca987d46SWarner Losh static int umass_disk_open(struct open_file *,...); 48*ca987d46SWarner Losh static int umass_disk_close(struct open_file *); 49*ca987d46SWarner Losh static void umass_disk_cleanup(void); 50*ca987d46SWarner Losh static int umass_disk_ioctl(struct open_file *, u_long, void *); 51*ca987d46SWarner Losh static int umass_disk_strategy(void *, int, daddr_t, size_t, char *, size_t *); 52*ca987d46SWarner Losh static int umass_disk_print(int); 53*ca987d46SWarner Losh 54*ca987d46SWarner Losh struct devsw umass_disk = { 55*ca987d46SWarner Losh .dv_name = "umass", 56*ca987d46SWarner Losh .dv_type = DEVT_DISK, 57*ca987d46SWarner Losh .dv_init = umass_disk_init, 58*ca987d46SWarner Losh .dv_strategy = umass_disk_strategy, 59*ca987d46SWarner Losh .dv_open = umass_disk_open, 60*ca987d46SWarner Losh .dv_close = umass_disk_close, 61*ca987d46SWarner Losh .dv_ioctl = umass_disk_ioctl, 62*ca987d46SWarner Losh .dv_print = umass_disk_print, 63*ca987d46SWarner Losh .dv_cleanup = umass_disk_cleanup, 64*ca987d46SWarner Losh }; 65*ca987d46SWarner Losh 66*ca987d46SWarner Losh static int 67*ca987d46SWarner Losh umass_disk_init(void) 68*ca987d46SWarner Losh { 69*ca987d46SWarner Losh uint32_t time; 70*ca987d46SWarner Losh 71*ca987d46SWarner Losh usb_init(); 72*ca987d46SWarner Losh usb_needs_explore_all(); 73*ca987d46SWarner Losh 74*ca987d46SWarner Losh /* wait 8 seconds for a USB mass storage device to appear */ 75*ca987d46SWarner Losh for (time = 0; time < (8 * hz); time++) { 76*ca987d46SWarner Losh usb_idle(); 77*ca987d46SWarner Losh delay(1000000 / hz); 78*ca987d46SWarner Losh time++; 79*ca987d46SWarner Losh callout_process(1); 80*ca987d46SWarner Losh if (umass_uaa.device != NULL) 81*ca987d46SWarner Losh return (0); 82*ca987d46SWarner Losh } 83*ca987d46SWarner Losh return (0); 84*ca987d46SWarner Losh } 85*ca987d46SWarner Losh 86*ca987d46SWarner Losh static int 87*ca987d46SWarner Losh umass_disk_strategy(void *devdata, int flag, daddr_t dblk, size_t size, 88*ca987d46SWarner Losh char *buf, size_t *rsizep) 89*ca987d46SWarner Losh { 90*ca987d46SWarner Losh if (umass_uaa.device == NULL) 91*ca987d46SWarner Losh return (ENXIO); 92*ca987d46SWarner Losh if (rsizep != NULL) 93*ca987d46SWarner Losh *rsizep = 0; 94*ca987d46SWarner Losh 95*ca987d46SWarner Losh flag &= F_MASK; 96*ca987d46SWarner Losh if (flag == F_WRITE) { 97*ca987d46SWarner Losh if (usb_msc_write_10(umass_uaa.device, 0, dblk, size >> 9, buf) != 0) 98*ca987d46SWarner Losh return (EINVAL); 99*ca987d46SWarner Losh } else if (flag == F_READ) { 100*ca987d46SWarner Losh if (usb_msc_read_10(umass_uaa.device, 0, dblk, size >> 9, buf) != 0) 101*ca987d46SWarner Losh return (EINVAL); 102*ca987d46SWarner Losh } else { 103*ca987d46SWarner Losh return (EROFS); 104*ca987d46SWarner Losh } 105*ca987d46SWarner Losh 106*ca987d46SWarner Losh if (rsizep != NULL) 107*ca987d46SWarner Losh *rsizep = size; 108*ca987d46SWarner Losh return (0); 109*ca987d46SWarner Losh } 110*ca987d46SWarner Losh 111*ca987d46SWarner Losh static int 112*ca987d46SWarner Losh umass_disk_open_sub(struct disk_devdesc *dev) 113*ca987d46SWarner Losh { 114*ca987d46SWarner Losh uint32_t nblock; 115*ca987d46SWarner Losh uint32_t blocksize; 116*ca987d46SWarner Losh 117*ca987d46SWarner Losh if (usb_msc_read_capacity(umass_uaa.device, 0, &nblock, &blocksize) != 0) 118*ca987d46SWarner Losh return (EINVAL); 119*ca987d46SWarner Losh 120*ca987d46SWarner Losh return (disk_open(dev, ((uint64_t)nblock + 1) * (uint64_t)blocksize, blocksize)); 121*ca987d46SWarner Losh } 122*ca987d46SWarner Losh 123*ca987d46SWarner Losh static int 124*ca987d46SWarner Losh umass_disk_open(struct open_file *f,...) 125*ca987d46SWarner Losh { 126*ca987d46SWarner Losh va_list ap; 127*ca987d46SWarner Losh struct disk_devdesc *dev; 128*ca987d46SWarner Losh 129*ca987d46SWarner Losh va_start(ap, f); 130*ca987d46SWarner Losh dev = va_arg(ap, struct disk_devdesc *); 131*ca987d46SWarner Losh va_end(ap); 132*ca987d46SWarner Losh 133*ca987d46SWarner Losh if (umass_uaa.device == NULL) 134*ca987d46SWarner Losh return (ENXIO); 135*ca987d46SWarner Losh if (dev->d_unit != 0) 136*ca987d46SWarner Losh return (EIO); 137*ca987d46SWarner Losh return (umass_disk_open_sub(dev)); 138*ca987d46SWarner Losh } 139*ca987d46SWarner Losh 140*ca987d46SWarner Losh static int 141*ca987d46SWarner Losh umass_disk_ioctl(struct open_file *f, u_long cmd, void *buf) 142*ca987d46SWarner Losh { 143*ca987d46SWarner Losh struct disk_devdesc *dev; 144*ca987d46SWarner Losh uint32_t nblock; 145*ca987d46SWarner Losh uint32_t blocksize; 146*ca987d46SWarner Losh int rc; 147*ca987d46SWarner Losh 148*ca987d46SWarner Losh dev = (struct disk_devdesc *)(f->f_devdata); 149*ca987d46SWarner Losh if (dev == NULL) 150*ca987d46SWarner Losh return (EINVAL); 151*ca987d46SWarner Losh 152*ca987d46SWarner Losh rc = disk_ioctl(dev, cmd, buf); 153*ca987d46SWarner Losh if (rc != ENOTTY) 154*ca987d46SWarner Losh return (rc); 155*ca987d46SWarner Losh 156*ca987d46SWarner Losh switch (cmd) { 157*ca987d46SWarner Losh case DIOCGSECTORSIZE: 158*ca987d46SWarner Losh case DIOCGMEDIASIZE: 159*ca987d46SWarner Losh if (usb_msc_read_capacity(umass_uaa.device, 0, 160*ca987d46SWarner Losh &nblock, &blocksize) != 0) 161*ca987d46SWarner Losh return (EINVAL); 162*ca987d46SWarner Losh 163*ca987d46SWarner Losh if (cmd == DIOCGMEDIASIZE) 164*ca987d46SWarner Losh *(uint64_t*)buf = nblock; 165*ca987d46SWarner Losh else 166*ca987d46SWarner Losh *(uint32_t*)buf = blocksize; 167*ca987d46SWarner Losh 168*ca987d46SWarner Losh return (0); 169*ca987d46SWarner Losh default: 170*ca987d46SWarner Losh return (ENXIO); 171*ca987d46SWarner Losh } 172*ca987d46SWarner Losh } 173*ca987d46SWarner Losh 174*ca987d46SWarner Losh static int 175*ca987d46SWarner Losh umass_disk_close(struct open_file *f) 176*ca987d46SWarner Losh { 177*ca987d46SWarner Losh struct disk_devdesc *dev; 178*ca987d46SWarner Losh 179*ca987d46SWarner Losh dev = (struct disk_devdesc *)f->f_devdata; 180*ca987d46SWarner Losh return (disk_close(dev)); 181*ca987d46SWarner Losh } 182*ca987d46SWarner Losh 183*ca987d46SWarner Losh static int 184*ca987d46SWarner Losh umass_disk_print(int verbose) 185*ca987d46SWarner Losh { 186*ca987d46SWarner Losh struct disk_devdesc dev; 187*ca987d46SWarner Losh 188*ca987d46SWarner Losh printf("%s devices:", umass_disk.dv_name); 189*ca987d46SWarner Losh if (pager_output("\n") != 0) 190*ca987d46SWarner Losh return (1); 191*ca987d46SWarner Losh 192*ca987d46SWarner Losh memset(&dev, 0, sizeof(dev)); 193*ca987d46SWarner Losh 194*ca987d46SWarner Losh ret = pager_output(" umass0 UMASS device\n"); 195*ca987d46SWarner Losh if (ret != 0) 196*ca987d46SWarner Losh return (ret); 197*ca987d46SWarner Losh dev.d_dev = &umass_disk; 198*ca987d46SWarner Losh dev.d_unit = 0; 199*ca987d46SWarner Losh dev.d_slice = -1; 200*ca987d46SWarner Losh dev.d_partition = -1; 201*ca987d46SWarner Losh 202*ca987d46SWarner Losh if (umass_disk_open_sub(&dev) == 0) { 203*ca987d46SWarner Losh ret = disk_print(&dev, " umass0", verbose); 204*ca987d46SWarner Losh disk_close(&dev); 205*ca987d46SWarner Losh } 206*ca987d46SWarner Losh return (ret); 207*ca987d46SWarner Losh } 208*ca987d46SWarner Losh 209*ca987d46SWarner Losh static void 210*ca987d46SWarner Losh umass_disk_cleanup(void) 211*ca987d46SWarner Losh { 212*ca987d46SWarner Losh 213*ca987d46SWarner Losh usb_uninit(); 214*ca987d46SWarner Losh } 215*ca987d46SWarner Losh 216*ca987d46SWarner Losh 217*ca987d46SWarner Losh /* USB specific functions */ 218*ca987d46SWarner Losh 219*ca987d46SWarner Losh extern void callout_process(int); 220*ca987d46SWarner Losh extern void usb_idle(void); 221*ca987d46SWarner Losh extern void usb_init(void); 222*ca987d46SWarner Losh extern void usb_uninit(void); 223*ca987d46SWarner Losh 224*ca987d46SWarner Losh void 225*ca987d46SWarner Losh DELAY(unsigned int usdelay) 226*ca987d46SWarner Losh { 227*ca987d46SWarner Losh delay(usdelay); 228*ca987d46SWarner Losh } 229*ca987d46SWarner Losh 230*ca987d46SWarner Losh int 231*ca987d46SWarner Losh pause(const char *what, int timeout) 232*ca987d46SWarner Losh { 233*ca987d46SWarner Losh if (timeout == 0) 234*ca987d46SWarner Losh timeout = 1; 235*ca987d46SWarner Losh 236*ca987d46SWarner Losh delay((1000000 / hz) * timeout); 237*ca987d46SWarner Losh 238*ca987d46SWarner Losh return (0); 239*ca987d46SWarner Losh } 240