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