199767f8919635c4928607450d9e0abb932109ceToomas Soome/* $FreeBSD$ */
199767f8919635c4928607450d9e0abb932109ceToomas Soome/*-
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Copyright (c) 2014 Hans Petter Selasky <hselasky@FreeBSD.org>
199767f8919635c4928607450d9e0abb932109ceToomas Soome * All rights reserved.
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
199767f8919635c4928607450d9e0abb932109ceToomas Soome * This software was developed by SRI International and the University of
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
199767f8919635c4928607450d9e0abb932109ceToomas Soome * ("CTSRD"), as part of the DARPA CRASH research programme.
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
199767f8919635c4928607450d9e0abb932109ceToomas Soome * Redistribution and use in source and binary forms, with or without
199767f8919635c4928607450d9e0abb932109ceToomas Soome * modification, are permitted provided that the following conditions
199767f8919635c4928607450d9e0abb932109ceToomas Soome * are met:
199767f8919635c4928607450d9e0abb932109ceToomas Soome * 1. Redistributions of source code must retain the above copyright
199767f8919635c4928607450d9e0abb932109ceToomas Soome * notice, this list of conditions and the following disclaimer.
199767f8919635c4928607450d9e0abb932109ceToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
199767f8919635c4928607450d9e0abb932109ceToomas Soome * notice, this list of conditions and the following disclaimer in the
199767f8919635c4928607450d9e0abb932109ceToomas Soome * documentation and/or other materials provided with the distribution.
199767f8919635c4928607450d9e0abb932109ceToomas Soome *
199767f8919635c4928607450d9e0abb932109ceToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
199767f8919635c4928607450d9e0abb932109ceToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
199767f8919635c4928607450d9e0abb932109ceToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
199767f8919635c4928607450d9e0abb932109ceToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
199767f8919635c4928607450d9e0abb932109ceToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
199767f8919635c4928607450d9e0abb932109ceToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
199767f8919635c4928607450d9e0abb932109ceToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
199767f8919635c4928607450d9e0abb932109ceToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
199767f8919635c4928607450d9e0abb932109ceToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
199767f8919635c4928607450d9e0abb932109ceToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
199767f8919635c4928607450d9e0abb932109ceToomas Soome * SUCH DAMAGE.
199767f8919635c4928607450d9e0abb932109ceToomas Soome */
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <sys/param.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <bootstrap.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <stdarg.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <stand.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include <disk.h>
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#define HAVE_STANDARD_DEFS
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include USB_GLOBAL_INCLUDE_FILE
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome#include "umass_common.h"
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int umass_disk_init(void);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int umass_disk_open(struct open_file *,...);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int umass_disk_close(struct open_file *);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic void umass_disk_cleanup(void);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int umass_disk_ioctl(struct open_file *, u_long, void *);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int umass_disk_strategy(void *, int, daddr_t, size_t, char *, size_t *);
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic void umass_disk_print(int);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestruct devsw umass_disk = {
199767f8919635c4928607450d9e0abb932109ceToomas Soome .dv_name = "umass",
199767f8919635c4928607450d9e0abb932109ceToomas Soome .dv_type = DEVT_DISK,
199767f8919635c4928607450d9e0abb932109ceToomas Soome .dv_init = umass_disk_init,
199767f8919635c4928607450d9e0abb932109ceToomas Soome .dv_strategy = umass_disk_strategy,
199767f8919635c4928607450d9e0abb932109ceToomas Soome .dv_open = umass_disk_open,
199767f8919635c4928607450d9e0abb932109ceToomas Soome .dv_close = umass_disk_close,
199767f8919635c4928607450d9e0abb932109ceToomas Soome .dv_ioctl = umass_disk_ioctl,
199767f8919635c4928607450d9e0abb932109ceToomas Soome .dv_print = umass_disk_print,
199767f8919635c4928607450d9e0abb932109ceToomas Soome .dv_cleanup = umass_disk_cleanup,
199767f8919635c4928607450d9e0abb932109ceToomas Soome};
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomeumass_disk_init(void)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome uint32_t time;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome usb_init();
199767f8919635c4928607450d9e0abb932109ceToomas Soome usb_needs_explore_all();
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome /* wait 8 seconds for a USB mass storage device to appear */
199767f8919635c4928607450d9e0abb932109ceToomas Soome for (time = 0; time < (8 * hz); time++) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome usb_idle();
199767f8919635c4928607450d9e0abb932109ceToomas Soome delay(1000000 / hz);
199767f8919635c4928607450d9e0abb932109ceToomas Soome time++;
199767f8919635c4928607450d9e0abb932109ceToomas Soome callout_process(1);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (umass_uaa.device != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomeumass_disk_strategy(void *devdata, int flag, daddr_t dblk, size_t size,
199767f8919635c4928607450d9e0abb932109ceToomas Soome char *buf, size_t *rsizep)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (umass_uaa.device == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (ENXIO);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (rsizep != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome *rsizep = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (flag == F_WRITE) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (usb_msc_write_10(umass_uaa.device, 0, dblk, size >> 9, buf) != 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EINVAL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else if (flag == F_READ) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (usb_msc_read_10(umass_uaa.device, 0, dblk, size >> 9, buf) != 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EINVAL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome } else {
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EROFS);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (rsizep != NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome *rsizep = size;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomeumass_disk_open_sub(struct disk_devdesc *dev)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome uint32_t nblock;
199767f8919635c4928607450d9e0abb932109ceToomas Soome uint32_t blocksize;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (usb_msc_read_capacity(umass_uaa.device, 0, &nblock, &blocksize) != 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EINVAL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (disk_open(dev, ((uint64_t)nblock + 1) * (uint64_t)blocksize, blocksize, 0));
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomeumass_disk_open(struct open_file *f,...)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome va_list ap;
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct disk_devdesc *dev;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome va_start(ap, f);
199767f8919635c4928607450d9e0abb932109ceToomas Soome dev = va_arg(ap, struct disk_devdesc *);
199767f8919635c4928607450d9e0abb932109ceToomas Soome va_end(ap);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (umass_uaa.device == NULL)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (ENXIO);
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (dev->d_unit != 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EIO);
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (umass_disk_open_sub(dev));
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomeumass_disk_ioctl(struct open_file *f __unused, u_long cmd, void *buf)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome uint32_t nblock;
199767f8919635c4928607450d9e0abb932109ceToomas Soome uint32_t blocksize;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome switch (cmd) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome case IOCTL_GET_BLOCK_SIZE:
199767f8919635c4928607450d9e0abb932109ceToomas Soome case IOCTL_GET_BLOCKS:
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (usb_msc_read_capacity(umass_uaa.device, 0,
199767f8919635c4928607450d9e0abb932109ceToomas Soome &nblock, &blocksize) != 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (EINVAL);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (cmd == IOCTL_GET_BLOCKS)
199767f8919635c4928607450d9e0abb932109ceToomas Soome *(uint32_t*)buf = nblock;
199767f8919635c4928607450d9e0abb932109ceToomas Soome else
199767f8919635c4928607450d9e0abb932109ceToomas Soome *(uint32_t*)buf = blocksize;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome default:
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (ENXIO);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic int
199767f8919635c4928607450d9e0abb932109ceToomas Soomeumass_disk_close(struct open_file *f)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct disk_devdesc *dev;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome dev = (struct disk_devdesc *)f->f_devdata;
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (disk_close(dev));
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic void
199767f8919635c4928607450d9e0abb932109ceToomas Soomeumass_disk_print(int verbose)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome struct disk_devdesc dev;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome memset(&dev, 0, sizeof(dev));
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome pager_output(" umass0 UMASS device\n");
199767f8919635c4928607450d9e0abb932109ceToomas Soome dev.d_dev = &umass_disk;
199767f8919635c4928607450d9e0abb932109ceToomas Soome dev.d_unit = 0;
199767f8919635c4928607450d9e0abb932109ceToomas Soome dev.d_slice = -1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome dev.d_partition = -1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (umass_disk_open_sub(&dev) == 0) {
199767f8919635c4928607450d9e0abb932109ceToomas Soome disk_print(&dev, " umass0", verbose);
199767f8919635c4928607450d9e0abb932109ceToomas Soome disk_close(&dev);
199767f8919635c4928607450d9e0abb932109ceToomas Soome }
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomestatic void
199767f8919635c4928607450d9e0abb932109ceToomas Soomeumass_disk_cleanup(void)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome disk_cleanup(&umass_disk);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome usb_uninit();
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome/* USB specific functions */
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomeextern void callout_process(int);
199767f8919635c4928607450d9e0abb932109ceToomas Soomeextern void usb_idle(void);
199767f8919635c4928607450d9e0abb932109ceToomas Soomeextern void usb_init(void);
199767f8919635c4928607450d9e0abb932109ceToomas Soomeextern void usb_uninit(void);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomevoid
199767f8919635c4928607450d9e0abb932109ceToomas SoomeDELAY(unsigned int usdelay)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome delay(usdelay);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soomeint
199767f8919635c4928607450d9e0abb932109ceToomas Soomepause(const char *what, int timeout)
199767f8919635c4928607450d9e0abb932109ceToomas Soome{
199767f8919635c4928607450d9e0abb932109ceToomas Soome if (timeout == 0)
199767f8919635c4928607450d9e0abb932109ceToomas Soome timeout = 1;
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome delay((1000000 / hz) * timeout);
199767f8919635c4928607450d9e0abb932109ceToomas Soome
199767f8919635c4928607450d9e0abb932109ceToomas Soome return (0);
199767f8919635c4928607450d9e0abb932109ceToomas Soome}