1184610Salfred/* $FreeBSD$ */ 2184610Salfred/*- 3184610Salfred * Copyright (C) 2003-2005 Alan Stern 4184610Salfred * Copyright (C) 2008 Hans Petter Selasky 5184610Salfred * All rights reserved. 6184610Salfred * 7184610Salfred * Redistribution and use in source and binary forms, with or without 8184610Salfred * modification, are permitted provided that the following conditions 9184610Salfred * are met: 10184610Salfred * 1. Redistributions of source code must retain the above copyright 11184610Salfred * notice, this list of conditions, and the following disclaimer, 12184610Salfred * without modification. 13184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 14184610Salfred * notice, this list of conditions and the following disclaimer in the 15184610Salfred * documentation and/or other materials provided with the distribution. 16184610Salfred * 3. The names of the above-listed copyright holders may not be used 17184610Salfred * to endorse or promote products derived from this software without 18184610Salfred * specific prior written permission. 19184610Salfred * 20184610Salfred * 21184610Salfred * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 22184610Salfred * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23184610Salfred * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24184610Salfred * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 25184610Salfred * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26184610Salfred * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27184610Salfred * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28184610Salfred * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29184610Salfred * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30184610Salfred * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31184610Salfred * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32184610Salfred */ 33184610Salfred 34184610Salfred/* 35184610Salfred * NOTE: Much of the SCSI statemachine handling code derives from the 36184610Salfred * Linux USB gadget stack. 37184610Salfred */ 38194677Sthompsa 39246122Shselasky#ifdef USB_GLOBAL_INCLUDE_FILE 40246122Shselasky#include USB_GLOBAL_INCLUDE_FILE 41246122Shselasky#else 42194677Sthompsa#include <sys/stdint.h> 43194677Sthompsa#include <sys/stddef.h> 44194677Sthompsa#include <sys/param.h> 45194677Sthompsa#include <sys/queue.h> 46194677Sthompsa#include <sys/types.h> 47194677Sthompsa#include <sys/systm.h> 48194677Sthompsa#include <sys/kernel.h> 49194677Sthompsa#include <sys/bus.h> 50194677Sthompsa#include <sys/module.h> 51194677Sthompsa#include <sys/lock.h> 52194677Sthompsa#include <sys/mutex.h> 53194677Sthompsa#include <sys/condvar.h> 54194677Sthompsa#include <sys/sysctl.h> 55194677Sthompsa#include <sys/sx.h> 56194677Sthompsa#include <sys/unistd.h> 57194677Sthompsa#include <sys/callout.h> 58194677Sthompsa#include <sys/malloc.h> 59194677Sthompsa#include <sys/priv.h> 60194677Sthompsa 61194677Sthompsa#include <dev/usb/usb.h> 62194677Sthompsa#include <dev/usb/usbdi.h> 63188746Sthompsa#include "usbdevs.h" 64194677Sthompsa#include "usb_if.h" 65184610Salfred 66184610Salfred#define USB_DEBUG_VAR ustorage_fs_debug 67188942Sthompsa#include <dev/usb/usb_debug.h> 68246122Shselasky#endif /* USB_GLOBAL_INCLUDE_FILE */ 69184610Salfred 70207077Sthompsa#ifdef USB_DEBUG 71184610Salfredstatic int ustorage_fs_debug = 0; 72184610Salfred 73192502SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, ustorage_fs, CTLFLAG_RW, 0, "USB ustorage_fs"); 74192502SthompsaSYSCTL_INT(_hw_usb_ustorage_fs, OID_AUTO, debug, CTLFLAG_RW, 75184610Salfred &ustorage_fs_debug, 0, "ustorage_fs debug level"); 76184610Salfred#endif 77184610Salfred 78184610Salfred/* Define some limits */ 79184610Salfred 80190181Sthompsa#ifndef USTORAGE_FS_BULK_SIZE 81244503Shselasky#define USTORAGE_FS_BULK_SIZE (1U << 17) /* bytes */ 82190181Sthompsa#endif 83184610Salfred 84190733Sthompsa#ifndef USTORAGE_FS_MAX_LUN 85190733Sthompsa#define USTORAGE_FS_MAX_LUN 8 /* units */ 86190733Sthompsa#endif 87190181Sthompsa 88190733Sthompsa#ifndef USTORAGE_QDATA_MAX 89190733Sthompsa#define USTORAGE_QDATA_MAX 40 /* bytes */ 90190733Sthompsa#endif 91190733Sthompsa 92190173Sthompsa/* 93190173Sthompsa * The SCSI ID string must be exactly 28 characters long 94190173Sthompsa * exluding the terminating zero. 95190173Sthompsa */ 96190173Sthompsa#ifndef USTORAGE_FS_ID_STRING 97190173Sthompsa#define USTORAGE_FS_ID_STRING \ 98190173Sthompsa "FreeBSD " /* 8 */ \ 99190173Sthompsa "File-Stor Gadget" /* 16 */ \ 100190173Sthompsa "0101" /* 4 */ 101190173Sthompsa#endif 102190173Sthompsa 103190173Sthompsa/* 104190173Sthompsa * The following macro defines the number of 105190173Sthompsa * sectors to be allocated for the RAM disk: 106190173Sthompsa */ 107190173Sthompsa#ifndef USTORAGE_FS_RAM_SECT 108190173Sthompsa#define USTORAGE_FS_RAM_SECT (1UL << 13) 109190173Sthompsa#endif 110190173Sthompsa 111184610Salfredstatic uint8_t *ustorage_fs_ramdisk; 112184610Salfred 113184610Salfred/* USB transfer definitions */ 114184610Salfred 115184610Salfred#define USTORAGE_FS_T_BBB_COMMAND 0 116184610Salfred#define USTORAGE_FS_T_BBB_DATA_DUMP 1 117184610Salfred#define USTORAGE_FS_T_BBB_DATA_READ 2 118184610Salfred#define USTORAGE_FS_T_BBB_DATA_WRITE 3 119184610Salfred#define USTORAGE_FS_T_BBB_STATUS 4 120184610Salfred#define USTORAGE_FS_T_BBB_MAX 5 121184610Salfred 122184610Salfred/* USB data stage direction */ 123184610Salfred 124184610Salfred#define DIR_NONE 0 125184610Salfred#define DIR_READ 1 126184610Salfred#define DIR_WRITE 2 127184610Salfred 128184610Salfred/* USB interface specific control request */ 129184610Salfred 130184610Salfred#define UR_BBB_RESET 0xff /* Bulk-Only reset */ 131184610Salfred#define UR_BBB_GET_MAX_LUN 0xfe /* Get maximum lun */ 132184610Salfred 133184610Salfred/* Command Block Wrapper */ 134184610Salfredtypedef struct { 135184610Salfred uDWord dCBWSignature; 136184610Salfred#define CBWSIGNATURE 0x43425355 137184610Salfred uDWord dCBWTag; 138184610Salfred uDWord dCBWDataTransferLength; 139184610Salfred uByte bCBWFlags; 140184610Salfred#define CBWFLAGS_OUT 0x00 141184610Salfred#define CBWFLAGS_IN 0x80 142184610Salfred uByte bCBWLUN; 143184610Salfred uByte bCDBLength; 144184610Salfred#define CBWCDBLENGTH 16 145184610Salfred uByte CBWCDB[CBWCDBLENGTH]; 146184610Salfred} __packed ustorage_fs_bbb_cbw_t; 147184610Salfred 148184610Salfred#define USTORAGE_FS_BBB_CBW_SIZE 31 149184610Salfred 150184610Salfred/* Command Status Wrapper */ 151184610Salfredtypedef struct { 152184610Salfred uDWord dCSWSignature; 153184610Salfred#define CSWSIGNATURE 0x53425355 154184610Salfred uDWord dCSWTag; 155184610Salfred uDWord dCSWDataResidue; 156184610Salfred uByte bCSWStatus; 157184610Salfred#define CSWSTATUS_GOOD 0x0 158184610Salfred#define CSWSTATUS_FAILED 0x1 159184610Salfred#define CSWSTATUS_PHASE 0x2 160184610Salfred} __packed ustorage_fs_bbb_csw_t; 161184610Salfred 162184610Salfred#define USTORAGE_FS_BBB_CSW_SIZE 13 163184610Salfred 164184610Salfredstruct ustorage_fs_lun { 165184610Salfred 166190181Sthompsa uint8_t *memory_image; 167184610Salfred 168184610Salfred uint32_t num_sectors; 169184610Salfred uint32_t sense_data; 170184610Salfred uint32_t sense_data_info; 171184610Salfred uint32_t unit_attention_data; 172184610Salfred 173184610Salfred uint8_t read_only:1; 174184610Salfred uint8_t prevent_medium_removal:1; 175184610Salfred uint8_t info_valid:1; 176184610Salfred uint8_t removable:1; 177184610Salfred}; 178184610Salfred 179184610Salfredstruct ustorage_fs_softc { 180184610Salfred 181244503Shselasky ustorage_fs_bbb_cbw_t *sc_cbw; /* Command Wrapper Block */ 182244503Shselasky ustorage_fs_bbb_csw_t *sc_csw; /* Command Status Block */ 183244503Shselasky void *sc_dma_ptr; /* Main data buffer */ 184184610Salfred 185184610Salfred struct mtx sc_mtx; 186184610Salfred 187184610Salfred struct ustorage_fs_lun sc_lun[USTORAGE_FS_MAX_LUN]; 188184610Salfred 189184610Salfred struct { 190184610Salfred uint8_t *data_ptr; 191184610Salfred struct ustorage_fs_lun *currlun; 192184610Salfred 193184610Salfred uint32_t data_rem; /* bytes, as reported by the command 194184610Salfred * block wrapper */ 195184610Salfred uint32_t offset; /* bytes */ 196184610Salfred 197184610Salfred uint8_t cbw_dir; 198184610Salfred uint8_t cmd_dir; 199184610Salfred uint8_t lun; 200184610Salfred uint8_t cmd_len; 201184610Salfred uint8_t data_short:1; 202184610Salfred uint8_t data_error:1; 203184610Salfred } sc_transfer; 204184610Salfred 205184610Salfred device_t sc_dev; 206192984Sthompsa struct usb_device *sc_udev; 207192984Sthompsa struct usb_xfer *sc_xfer[USTORAGE_FS_T_BBB_MAX]; 208184610Salfred 209184610Salfred uint8_t sc_iface_no; /* interface number */ 210184610Salfred uint8_t sc_last_lun; 211184610Salfred uint8_t sc_last_xfer_index; 212190733Sthompsa uint8_t sc_qdata[USTORAGE_QDATA_MAX]; 213184610Salfred}; 214184610Salfred 215184610Salfred/* prototypes */ 216184610Salfred 217184610Salfredstatic device_probe_t ustorage_fs_probe; 218184610Salfredstatic device_attach_t ustorage_fs_attach; 219184610Salfredstatic device_detach_t ustorage_fs_detach; 220184610Salfredstatic device_suspend_t ustorage_fs_suspend; 221184610Salfredstatic device_resume_t ustorage_fs_resume; 222188942Sthompsastatic usb_handle_request_t ustorage_fs_handle_request; 223184610Salfred 224193045Sthompsastatic usb_callback_t ustorage_fs_t_bbb_command_callback; 225193045Sthompsastatic usb_callback_t ustorage_fs_t_bbb_data_dump_callback; 226193045Sthompsastatic usb_callback_t ustorage_fs_t_bbb_data_read_callback; 227193045Sthompsastatic usb_callback_t ustorage_fs_t_bbb_data_write_callback; 228193045Sthompsastatic usb_callback_t ustorage_fs_t_bbb_status_callback; 229184610Salfred 230184610Salfredstatic void ustorage_fs_transfer_start(struct ustorage_fs_softc *sc, uint8_t xfer_index); 231184610Salfredstatic void ustorage_fs_transfer_stop(struct ustorage_fs_softc *sc); 232184610Salfred 233184610Salfredstatic uint8_t ustorage_fs_verify(struct ustorage_fs_softc *sc); 234184610Salfredstatic uint8_t ustorage_fs_inquiry(struct ustorage_fs_softc *sc); 235184610Salfredstatic uint8_t ustorage_fs_request_sense(struct ustorage_fs_softc *sc); 236184610Salfredstatic uint8_t ustorage_fs_read_capacity(struct ustorage_fs_softc *sc); 237184610Salfredstatic uint8_t ustorage_fs_mode_sense(struct ustorage_fs_softc *sc); 238184610Salfredstatic uint8_t ustorage_fs_start_stop(struct ustorage_fs_softc *sc); 239184610Salfredstatic uint8_t ustorage_fs_prevent_allow(struct ustorage_fs_softc *sc); 240184610Salfredstatic uint8_t ustorage_fs_read_format_capacities(struct ustorage_fs_softc *sc); 241184610Salfredstatic uint8_t ustorage_fs_mode_select(struct ustorage_fs_softc *sc); 242184610Salfredstatic uint8_t ustorage_fs_min_len(struct ustorage_fs_softc *sc, uint32_t len, uint32_t mask); 243184610Salfredstatic uint8_t ustorage_fs_read(struct ustorage_fs_softc *sc); 244184610Salfredstatic uint8_t ustorage_fs_write(struct ustorage_fs_softc *sc); 245184610Salfredstatic uint8_t ustorage_fs_check_cmd(struct ustorage_fs_softc *sc, uint8_t cmd_size, uint16_t mask, uint8_t needs_medium); 246184610Salfredstatic uint8_t ustorage_fs_do_cmd(struct ustorage_fs_softc *sc); 247184610Salfred 248184610Salfredstatic device_method_t ustorage_fs_methods[] = { 249184610Salfred /* USB interface */ 250188942Sthompsa DEVMETHOD(usb_handle_request, ustorage_fs_handle_request), 251184610Salfred 252184610Salfred /* Device interface */ 253184610Salfred DEVMETHOD(device_probe, ustorage_fs_probe), 254184610Salfred DEVMETHOD(device_attach, ustorage_fs_attach), 255184610Salfred DEVMETHOD(device_detach, ustorage_fs_detach), 256184610Salfred DEVMETHOD(device_suspend, ustorage_fs_suspend), 257184610Salfred DEVMETHOD(device_resume, ustorage_fs_resume), 258184610Salfred 259246128Ssbz DEVMETHOD_END 260184610Salfred}; 261184610Salfred 262184610Salfredstatic driver_t ustorage_fs_driver = { 263184610Salfred .name = "ustorage_fs", 264184610Salfred .methods = ustorage_fs_methods, 265184610Salfred .size = sizeof(struct ustorage_fs_softc), 266184610Salfred}; 267184610Salfred 268184610Salfredstatic devclass_t ustorage_fs_devclass; 269184610Salfred 270189275SthompsaDRIVER_MODULE(ustorage_fs, uhub, ustorage_fs_driver, ustorage_fs_devclass, NULL, 0); 271184610SalfredMODULE_VERSION(ustorage_fs, 0); 272188942SthompsaMODULE_DEPEND(ustorage_fs, usb, 1, 1, 1); 273184610Salfred 274194099Sthompsastatic struct usb_config ustorage_fs_bbb_config[USTORAGE_FS_T_BBB_MAX] = { 275184610Salfred 276184610Salfred [USTORAGE_FS_T_BBB_COMMAND] = { 277184610Salfred .type = UE_BULK, 278184610Salfred .endpoint = UE_ADDR_ANY, 279184610Salfred .direction = UE_DIR_OUT, 280190733Sthompsa .bufsize = sizeof(ustorage_fs_bbb_cbw_t), 281190733Sthompsa .callback = &ustorage_fs_t_bbb_command_callback, 282190733Sthompsa .usb_mode = USB_MODE_DEVICE, 283184610Salfred }, 284184610Salfred 285184610Salfred [USTORAGE_FS_T_BBB_DATA_DUMP] = { 286184610Salfred .type = UE_BULK, 287184610Salfred .endpoint = UE_ADDR_ANY, 288184610Salfred .direction = UE_DIR_OUT, 289190733Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 290190733Sthompsa .flags = {.proxy_buffer = 1,.short_xfer_ok = 1,}, 291190733Sthompsa .callback = &ustorage_fs_t_bbb_data_dump_callback, 292190733Sthompsa .usb_mode = USB_MODE_DEVICE, 293184610Salfred }, 294184610Salfred 295184610Salfred [USTORAGE_FS_T_BBB_DATA_READ] = { 296184610Salfred .type = UE_BULK, 297184610Salfred .endpoint = UE_ADDR_ANY, 298184610Salfred .direction = UE_DIR_OUT, 299190733Sthompsa .bufsize = USTORAGE_FS_BULK_SIZE, 300244503Shselasky .flags = {.proxy_buffer = 1,.short_xfer_ok = 1}, 301190733Sthompsa .callback = &ustorage_fs_t_bbb_data_read_callback, 302190733Sthompsa .usb_mode = USB_MODE_DEVICE, 303184610Salfred }, 304184610Salfred 305184610Salfred [USTORAGE_FS_T_BBB_DATA_WRITE] = { 306184610Salfred .type = UE_BULK, 307184610Salfred .endpoint = UE_ADDR_ANY, 308184610Salfred .direction = UE_DIR_IN, 309190733Sthompsa .bufsize = USTORAGE_FS_BULK_SIZE, 310190733Sthompsa .flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer = 1}, 311190733Sthompsa .callback = &ustorage_fs_t_bbb_data_write_callback, 312190733Sthompsa .usb_mode = USB_MODE_DEVICE, 313184610Salfred }, 314184610Salfred 315184610Salfred [USTORAGE_FS_T_BBB_STATUS] = { 316184610Salfred .type = UE_BULK, 317184610Salfred .endpoint = UE_ADDR_ANY, 318184610Salfred .direction = UE_DIR_IN, 319190733Sthompsa .bufsize = sizeof(ustorage_fs_bbb_csw_t), 320244503Shselasky .flags = {.short_xfer_ok = 1}, 321190733Sthompsa .callback = &ustorage_fs_t_bbb_status_callback, 322190733Sthompsa .usb_mode = USB_MODE_DEVICE, 323184610Salfred }, 324184610Salfred}; 325184610Salfred 326184610Salfred/* 327184610Salfred * USB device probe/attach/detach 328184610Salfred */ 329184610Salfred 330184610Salfredstatic int 331184610Salfredustorage_fs_probe(device_t dev) 332184610Salfred{ 333192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 334192984Sthompsa struct usb_interface_descriptor *id; 335184610Salfred 336192499Sthompsa if (uaa->usb_mode != USB_MODE_DEVICE) { 337184610Salfred return (ENXIO); 338184610Salfred } 339184610Salfred /* Check for a standards compliant device */ 340194228Sthompsa id = usbd_get_interface_descriptor(uaa->iface); 341184610Salfred if ((id == NULL) || 342184610Salfred (id->bInterfaceClass != UICLASS_MASS) || 343184610Salfred (id->bInterfaceSubClass != UISUBCLASS_SCSI) || 344184610Salfred (id->bInterfaceProtocol != UIPROTO_MASS_BBB)) { 345184610Salfred return (ENXIO); 346184610Salfred } 347222051Savg return (BUS_PROBE_GENERIC); 348184610Salfred} 349184610Salfred 350184610Salfredstatic int 351184610Salfredustorage_fs_attach(device_t dev) 352184610Salfred{ 353184610Salfred struct ustorage_fs_softc *sc = device_get_softc(dev); 354192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 355192984Sthompsa struct usb_interface_descriptor *id; 356184610Salfred int err; 357190733Sthompsa int unit; 358184610Salfred 359184610Salfred /* 360227461Shselasky * NOTE: the softc struct is cleared in device_set_driver. 361184610Salfred * We can safely call ustorage_fs_detach without specifically 362184610Salfred * initializing the struct. 363184610Salfred */ 364184610Salfred 365184610Salfred sc->sc_dev = dev; 366184610Salfred sc->sc_udev = uaa->device; 367190733Sthompsa unit = device_get_unit(dev); 368184610Salfred 369227462Shselasky /* enable power saving mode */ 370227462Shselasky usbd_set_power_mode(uaa->device, USB_POWER_MODE_SAVE); 371227462Shselasky 372190733Sthompsa if (unit == 0) { 373184610Salfred if (ustorage_fs_ramdisk == NULL) { 374184610Salfred /* 375184610Salfred * allocate a memory image for our ramdisk until 376184610Salfred * further 377184610Salfred */ 378184610Salfred ustorage_fs_ramdisk = 379227461Shselasky malloc(USTORAGE_FS_RAM_SECT << 9, M_USB, 380227461Shselasky M_ZERO | M_WAITOK); 381227461Shselasky 382184610Salfred if (ustorage_fs_ramdisk == NULL) { 383184610Salfred return (ENOMEM); 384184610Salfred } 385184610Salfred } 386184610Salfred sc->sc_lun[0].memory_image = ustorage_fs_ramdisk; 387184610Salfred sc->sc_lun[0].num_sectors = USTORAGE_FS_RAM_SECT; 388184610Salfred sc->sc_lun[0].removable = 1; 389184610Salfred } 390184610Salfred 391194228Sthompsa device_set_usb_desc(dev); 392184610Salfred 393184610Salfred mtx_init(&sc->sc_mtx, "USTORAGE_FS lock", 394184610Salfred NULL, (MTX_DEF | MTX_RECURSE)); 395184610Salfred 396184610Salfred /* get interface index */ 397184610Salfred 398194228Sthompsa id = usbd_get_interface_descriptor(uaa->iface); 399184610Salfred if (id == NULL) { 400184610Salfred device_printf(dev, "failed to get " 401184610Salfred "interface number\n"); 402184610Salfred goto detach; 403184610Salfred } 404184610Salfred sc->sc_iface_no = id->bInterfaceNumber; 405184610Salfred 406194228Sthompsa err = usbd_transfer_setup(uaa->device, 407184610Salfred &uaa->info.bIfaceIndex, sc->sc_xfer, ustorage_fs_bbb_config, 408184610Salfred USTORAGE_FS_T_BBB_MAX, sc, &sc->sc_mtx); 409184610Salfred if (err) { 410184610Salfred device_printf(dev, "could not setup required " 411194228Sthompsa "transfers, %s\n", usbd_errstr(err)); 412184610Salfred goto detach; 413184610Salfred } 414244503Shselasky 415244503Shselasky sc->sc_cbw = usbd_xfer_get_frame_buffer(sc->sc_xfer[ 416244503Shselasky USTORAGE_FS_T_BBB_COMMAND], 0); 417244503Shselasky sc->sc_csw = usbd_xfer_get_frame_buffer(sc->sc_xfer[ 418244503Shselasky USTORAGE_FS_T_BBB_STATUS], 0); 419244503Shselasky sc->sc_dma_ptr = usbd_xfer_get_frame_buffer(sc->sc_xfer[ 420244503Shselasky USTORAGE_FS_T_BBB_DATA_READ], 0); 421244503Shselasky 422184610Salfred /* start Mass Storage State Machine */ 423184610Salfred 424184610Salfred mtx_lock(&sc->sc_mtx); 425184610Salfred ustorage_fs_transfer_start(sc, USTORAGE_FS_T_BBB_COMMAND); 426184610Salfred mtx_unlock(&sc->sc_mtx); 427184610Salfred 428184610Salfred return (0); /* success */ 429184610Salfred 430184610Salfreddetach: 431184610Salfred ustorage_fs_detach(dev); 432184610Salfred return (ENXIO); /* failure */ 433184610Salfred} 434184610Salfred 435184610Salfredstatic int 436184610Salfredustorage_fs_detach(device_t dev) 437184610Salfred{ 438184610Salfred struct ustorage_fs_softc *sc = device_get_softc(dev); 439184610Salfred 440184610Salfred /* teardown our statemachine */ 441184610Salfred 442194228Sthompsa usbd_transfer_unsetup(sc->sc_xfer, USTORAGE_FS_T_BBB_MAX); 443184610Salfred 444184610Salfred mtx_destroy(&sc->sc_mtx); 445184610Salfred 446184610Salfred return (0); /* success */ 447184610Salfred} 448184610Salfred 449184610Salfredstatic int 450184610Salfredustorage_fs_suspend(device_t dev) 451184610Salfred{ 452184610Salfred device_printf(dev, "suspending\n"); 453184610Salfred return (0); /* success */ 454184610Salfred} 455184610Salfred 456184610Salfredstatic int 457184610Salfredustorage_fs_resume(device_t dev) 458184610Salfred{ 459184610Salfred device_printf(dev, "resuming\n"); 460184610Salfred return (0); /* success */ 461184610Salfred} 462184610Salfred 463184610Salfred/* 464184610Salfred * Generic functions to handle transfers 465184610Salfred */ 466184610Salfred 467184610Salfredstatic void 468184610Salfredustorage_fs_transfer_start(struct ustorage_fs_softc *sc, uint8_t xfer_index) 469184610Salfred{ 470184610Salfred if (sc->sc_xfer[xfer_index]) { 471184610Salfred sc->sc_last_xfer_index = xfer_index; 472194228Sthompsa usbd_transfer_start(sc->sc_xfer[xfer_index]); 473184610Salfred } 474184610Salfred} 475184610Salfred 476184610Salfredstatic void 477184610Salfredustorage_fs_transfer_stop(struct ustorage_fs_softc *sc) 478184610Salfred{ 479194228Sthompsa usbd_transfer_stop(sc->sc_xfer[sc->sc_last_xfer_index]); 480184610Salfred mtx_unlock(&sc->sc_mtx); 481194228Sthompsa usbd_transfer_drain(sc->sc_xfer[sc->sc_last_xfer_index]); 482184610Salfred mtx_lock(&sc->sc_mtx); 483184610Salfred} 484184610Salfred 485184610Salfredstatic int 486184610Salfredustorage_fs_handle_request(device_t dev, 487184610Salfred const void *preq, void **pptr, uint16_t *plen, 488195121Sthompsa uint16_t offset, uint8_t *pstate) 489184610Salfred{ 490184610Salfred struct ustorage_fs_softc *sc = device_get_softc(dev); 491192984Sthompsa const struct usb_device_request *req = preq; 492195121Sthompsa uint8_t is_complete = *pstate; 493184610Salfred 494184610Salfred if (!is_complete) { 495192057Sthompsa if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) && 496192057Sthompsa (req->bRequest == UR_BBB_RESET)) { 497184610Salfred *plen = 0; 498184610Salfred mtx_lock(&sc->sc_mtx); 499184610Salfred ustorage_fs_transfer_stop(sc); 500184610Salfred sc->sc_transfer.data_error = 1; 501184610Salfred ustorage_fs_transfer_start(sc, 502184610Salfred USTORAGE_FS_T_BBB_COMMAND); 503184610Salfred mtx_unlock(&sc->sc_mtx); 504184610Salfred return (0); 505192057Sthompsa } else if ((req->bmRequestType == UT_READ_CLASS_INTERFACE) && 506192057Sthompsa (req->bRequest == UR_BBB_GET_MAX_LUN)) { 507184610Salfred if (offset == 0) { 508184610Salfred *plen = 1; 509184610Salfred *pptr = &sc->sc_last_lun; 510184610Salfred } else { 511184610Salfred *plen = 0; 512184610Salfred } 513184610Salfred return (0); 514184610Salfred } 515184610Salfred } 516184610Salfred return (ENXIO); /* use builtin handler */ 517184610Salfred} 518184610Salfred 519184610Salfredstatic void 520194677Sthompsaustorage_fs_t_bbb_command_callback(struct usb_xfer *xfer, usb_error_t error) 521184610Salfred{ 522194677Sthompsa struct ustorage_fs_softc *sc = usbd_xfer_softc(xfer); 523184610Salfred uint32_t tag; 524194677Sthompsa uint8_t err = 0; 525184610Salfred 526184610Salfred DPRINTF("\n"); 527184610Salfred 528184610Salfred switch (USB_GET_STATE(xfer)) { 529184610Salfred case USB_ST_TRANSFERRED: 530184610Salfred 531244503Shselasky tag = UGETDW(sc->sc_cbw->dCBWSignature); 532184610Salfred 533184610Salfred if (tag != CBWSIGNATURE) { 534184610Salfred /* do nothing */ 535184610Salfred DPRINTF("invalid signature 0x%08x\n", tag); 536184610Salfred break; 537184610Salfred } 538244503Shselasky tag = UGETDW(sc->sc_cbw->dCBWTag); 539184610Salfred 540184610Salfred /* echo back tag */ 541244503Shselasky USETDW(sc->sc_csw->dCSWTag, tag); 542184610Salfred 543184610Salfred /* reset status */ 544244503Shselasky sc->sc_csw->bCSWStatus = 0; 545184610Salfred 546184610Salfred /* reset data offset, data length and data remainder */ 547184610Salfred sc->sc_transfer.offset = 0; 548184610Salfred sc->sc_transfer.data_rem = 549244503Shselasky UGETDW(sc->sc_cbw->dCBWDataTransferLength); 550184610Salfred 551184610Salfred /* reset data flags */ 552184610Salfred sc->sc_transfer.data_short = 0; 553184610Salfred 554184610Salfred /* extract LUN */ 555244503Shselasky sc->sc_transfer.lun = sc->sc_cbw->bCBWLUN; 556184610Salfred 557184610Salfred if (sc->sc_transfer.data_rem == 0) { 558184610Salfred sc->sc_transfer.cbw_dir = DIR_NONE; 559184610Salfred } else { 560244503Shselasky if (sc->sc_cbw->bCBWFlags & CBWFLAGS_IN) { 561184610Salfred sc->sc_transfer.cbw_dir = DIR_WRITE; 562184610Salfred } else { 563184610Salfred sc->sc_transfer.cbw_dir = DIR_READ; 564184610Salfred } 565184610Salfred } 566184610Salfred 567244503Shselasky sc->sc_transfer.cmd_len = sc->sc_cbw->bCDBLength; 568244503Shselasky if ((sc->sc_transfer.cmd_len > sizeof(sc->sc_cbw->CBWCDB)) || 569184610Salfred (sc->sc_transfer.cmd_len == 0)) { 570184610Salfred /* just halt - this is invalid */ 571184610Salfred DPRINTF("invalid command length %d bytes\n", 572184610Salfred sc->sc_transfer.cmd_len); 573184610Salfred break; 574184610Salfred } 575184610Salfred 576194677Sthompsa err = ustorage_fs_do_cmd(sc); 577194677Sthompsa if (err) { 578184610Salfred /* got an error */ 579184610Salfred DPRINTF("command failed\n"); 580184610Salfred break; 581184610Salfred } 582184610Salfred if ((sc->sc_transfer.data_rem > 0) && 583184610Salfred (sc->sc_transfer.cbw_dir != sc->sc_transfer.cmd_dir)) { 584184610Salfred /* contradicting data transfer direction */ 585194677Sthompsa err = 1; 586184610Salfred DPRINTF("data direction mismatch\n"); 587184610Salfred break; 588184610Salfred } 589184610Salfred switch (sc->sc_transfer.cbw_dir) { 590184610Salfred case DIR_READ: 591184610Salfred ustorage_fs_transfer_start(sc, USTORAGE_FS_T_BBB_DATA_READ); 592184610Salfred break; 593184610Salfred case DIR_WRITE: 594184610Salfred ustorage_fs_transfer_start(sc, USTORAGE_FS_T_BBB_DATA_WRITE); 595184610Salfred break; 596184610Salfred default: 597184610Salfred ustorage_fs_transfer_start(sc, 598184610Salfred USTORAGE_FS_T_BBB_STATUS); 599184610Salfred break; 600184610Salfred } 601184610Salfred break; 602184610Salfred 603184610Salfred case USB_ST_SETUP: 604184610Salfredtr_setup: 605184610Salfred if (sc->sc_transfer.data_error) { 606184610Salfred sc->sc_transfer.data_error = 0; 607194677Sthompsa usbd_xfer_set_stall(xfer); 608184610Salfred DPRINTF("stall pipe\n"); 609184610Salfred } 610244650Shselasky usbd_xfer_set_frame_len(xfer, 0, 611244650Shselasky sizeof(ustorage_fs_bbb_cbw_t)); 612194228Sthompsa usbd_transfer_submit(xfer); 613184610Salfred break; 614184610Salfred 615184610Salfred default: /* Error */ 616184610Salfred DPRINTF("error\n"); 617194677Sthompsa if (error == USB_ERR_CANCELLED) { 618184610Salfred break; 619184610Salfred } 620184610Salfred /* If the pipe is already stalled, don't do another stall */ 621194677Sthompsa if (!usbd_xfer_is_stalled(xfer)) 622184610Salfred sc->sc_transfer.data_error = 1; 623194677Sthompsa 624184610Salfred /* try again */ 625184610Salfred goto tr_setup; 626184610Salfred } 627194677Sthompsa if (err) { 628244503Shselasky if (sc->sc_csw->bCSWStatus == 0) { 629184610Salfred /* set some default error code */ 630244503Shselasky sc->sc_csw->bCSWStatus = CSWSTATUS_FAILED; 631184610Salfred } 632184610Salfred if (sc->sc_transfer.cbw_dir == DIR_READ) { 633184610Salfred /* dump all data */ 634184610Salfred ustorage_fs_transfer_start(sc, 635184610Salfred USTORAGE_FS_T_BBB_DATA_DUMP); 636184610Salfred return; 637184610Salfred } 638184610Salfred if (sc->sc_transfer.cbw_dir == DIR_WRITE) { 639184610Salfred /* need to stall before status */ 640184610Salfred sc->sc_transfer.data_error = 1; 641184610Salfred } 642184610Salfred ustorage_fs_transfer_start(sc, USTORAGE_FS_T_BBB_STATUS); 643184610Salfred } 644184610Salfred} 645184610Salfred 646184610Salfredstatic void 647194677Sthompsaustorage_fs_t_bbb_data_dump_callback(struct usb_xfer *xfer, usb_error_t error) 648184610Salfred{ 649194677Sthompsa struct ustorage_fs_softc *sc = usbd_xfer_softc(xfer); 650194677Sthompsa uint32_t max_bulk = usbd_xfer_max_len(xfer); 651194677Sthompsa int actlen, sumlen; 652184610Salfred 653194677Sthompsa usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 654194677Sthompsa 655184610Salfred DPRINTF("\n"); 656184610Salfred 657184610Salfred switch (USB_GET_STATE(xfer)) { 658184610Salfred case USB_ST_TRANSFERRED: 659194677Sthompsa sc->sc_transfer.data_rem -= actlen; 660194677Sthompsa sc->sc_transfer.offset += actlen; 661184610Salfred 662194677Sthompsa if (actlen != sumlen || sc->sc_transfer.data_rem == 0) { 663184610Salfred /* short transfer or end of data */ 664184610Salfred ustorage_fs_transfer_start(sc, 665184610Salfred USTORAGE_FS_T_BBB_STATUS); 666184610Salfred break; 667184610Salfred } 668184610Salfred /* Fallthrough */ 669184610Salfred 670184610Salfred case USB_ST_SETUP: 671184610Salfredtr_setup: 672184610Salfred if (max_bulk > sc->sc_transfer.data_rem) { 673184610Salfred max_bulk = sc->sc_transfer.data_rem; 674184610Salfred } 675184610Salfred if (sc->sc_transfer.data_error) { 676184610Salfred sc->sc_transfer.data_error = 0; 677194677Sthompsa usbd_xfer_set_stall(xfer); 678184610Salfred } 679194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, max_bulk); 680194228Sthompsa usbd_transfer_submit(xfer); 681184610Salfred break; 682184610Salfred 683184610Salfred default: /* Error */ 684194677Sthompsa if (error == USB_ERR_CANCELLED) { 685184610Salfred break; 686184610Salfred } 687184610Salfred /* 688184610Salfred * If the pipe is already stalled, don't do another stall: 689184610Salfred */ 690194677Sthompsa if (!usbd_xfer_is_stalled(xfer)) 691184610Salfred sc->sc_transfer.data_error = 1; 692194677Sthompsa 693184610Salfred /* try again */ 694184610Salfred goto tr_setup; 695184610Salfred } 696184610Salfred} 697184610Salfred 698184610Salfredstatic void 699194677Sthompsaustorage_fs_t_bbb_data_read_callback(struct usb_xfer *xfer, usb_error_t error) 700184610Salfred{ 701194677Sthompsa struct ustorage_fs_softc *sc = usbd_xfer_softc(xfer); 702194677Sthompsa uint32_t max_bulk = usbd_xfer_max_len(xfer); 703194677Sthompsa int actlen, sumlen; 704184610Salfred 705194677Sthompsa usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 706194677Sthompsa 707184610Salfred DPRINTF("\n"); 708184610Salfred 709184610Salfred switch (USB_GET_STATE(xfer)) { 710184610Salfred case USB_ST_TRANSFERRED: 711244503Shselasky /* XXX copy data from DMA buffer */ 712244503Shselasky memcpy(sc->sc_transfer.data_ptr, sc->sc_dma_ptr, actlen); 713244503Shselasky 714194677Sthompsa sc->sc_transfer.data_rem -= actlen; 715194677Sthompsa sc->sc_transfer.data_ptr += actlen; 716194677Sthompsa sc->sc_transfer.offset += actlen; 717184610Salfred 718194677Sthompsa if (actlen != sumlen || sc->sc_transfer.data_rem == 0) { 719184610Salfred /* short transfer or end of data */ 720184610Salfred ustorage_fs_transfer_start(sc, 721184610Salfred USTORAGE_FS_T_BBB_STATUS); 722184610Salfred break; 723184610Salfred } 724184610Salfred /* Fallthrough */ 725184610Salfred 726184610Salfred case USB_ST_SETUP: 727184610Salfredtr_setup: 728184610Salfred if (max_bulk > sc->sc_transfer.data_rem) { 729184610Salfred max_bulk = sc->sc_transfer.data_rem; 730184610Salfred } 731184610Salfred if (sc->sc_transfer.data_error) { 732184610Salfred sc->sc_transfer.data_error = 0; 733194677Sthompsa usbd_xfer_set_stall(xfer); 734184610Salfred } 735184610Salfred 736244503Shselasky usbd_xfer_set_frame_data(xfer, 0, sc->sc_dma_ptr, max_bulk); 737194228Sthompsa usbd_transfer_submit(xfer); 738184610Salfred break; 739184610Salfred 740184610Salfred default: /* Error */ 741194677Sthompsa if (error == USB_ERR_CANCELLED) { 742184610Salfred break; 743184610Salfred } 744184610Salfred /* If the pipe is already stalled, don't do another stall */ 745194677Sthompsa if (!usbd_xfer_is_stalled(xfer)) 746184610Salfred sc->sc_transfer.data_error = 1; 747194677Sthompsa 748184610Salfred /* try again */ 749184610Salfred goto tr_setup; 750184610Salfred } 751184610Salfred} 752184610Salfred 753184610Salfredstatic void 754194677Sthompsaustorage_fs_t_bbb_data_write_callback(struct usb_xfer *xfer, usb_error_t error) 755184610Salfred{ 756194677Sthompsa struct ustorage_fs_softc *sc = usbd_xfer_softc(xfer); 757194677Sthompsa uint32_t max_bulk = usbd_xfer_max_len(xfer); 758194677Sthompsa int actlen, sumlen; 759184610Salfred 760194677Sthompsa usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 761194677Sthompsa 762184610Salfred DPRINTF("\n"); 763184610Salfred 764184610Salfred switch (USB_GET_STATE(xfer)) { 765184610Salfred case USB_ST_TRANSFERRED: 766194677Sthompsa sc->sc_transfer.data_rem -= actlen; 767194677Sthompsa sc->sc_transfer.data_ptr += actlen; 768194677Sthompsa sc->sc_transfer.offset += actlen; 769184610Salfred 770194677Sthompsa if (actlen != sumlen || sc->sc_transfer.data_rem == 0) { 771184610Salfred /* short transfer or end of data */ 772184610Salfred ustorage_fs_transfer_start(sc, 773184610Salfred USTORAGE_FS_T_BBB_STATUS); 774184610Salfred break; 775184610Salfred } 776184610Salfred case USB_ST_SETUP: 777184610Salfredtr_setup: 778184610Salfred if (max_bulk >= sc->sc_transfer.data_rem) { 779184610Salfred max_bulk = sc->sc_transfer.data_rem; 780194677Sthompsa if (sc->sc_transfer.data_short) 781194677Sthompsa usbd_xfer_set_flag(xfer, USB_FORCE_SHORT_XFER); 782194677Sthompsa else 783194677Sthompsa usbd_xfer_clr_flag(xfer, USB_FORCE_SHORT_XFER); 784194677Sthompsa } else 785194677Sthompsa usbd_xfer_clr_flag(xfer, USB_FORCE_SHORT_XFER); 786184610Salfred 787184610Salfred if (sc->sc_transfer.data_error) { 788184610Salfred sc->sc_transfer.data_error = 0; 789194677Sthompsa usbd_xfer_set_stall(xfer); 790184610Salfred } 791184610Salfred 792244503Shselasky /* XXX copy data to DMA buffer */ 793244503Shselasky memcpy(sc->sc_dma_ptr, sc->sc_transfer.data_ptr, max_bulk); 794244503Shselasky 795244503Shselasky usbd_xfer_set_frame_data(xfer, 0, sc->sc_dma_ptr, max_bulk); 796194228Sthompsa usbd_transfer_submit(xfer); 797184610Salfred break; 798184610Salfred 799184610Salfred default: /* Error */ 800194677Sthompsa if (error == USB_ERR_CANCELLED) { 801184610Salfred break; 802184610Salfred } 803184610Salfred /* 804184610Salfred * If the pipe is already stalled, don't do another 805184610Salfred * stall 806184610Salfred */ 807194677Sthompsa if (!usbd_xfer_is_stalled(xfer)) 808184610Salfred sc->sc_transfer.data_error = 1; 809194677Sthompsa 810184610Salfred /* try again */ 811184610Salfred goto tr_setup; 812184610Salfred } 813184610Salfred} 814184610Salfred 815184610Salfredstatic void 816194677Sthompsaustorage_fs_t_bbb_status_callback(struct usb_xfer *xfer, usb_error_t error) 817184610Salfred{ 818194677Sthompsa struct ustorage_fs_softc *sc = usbd_xfer_softc(xfer); 819184610Salfred 820184610Salfred DPRINTF("\n"); 821184610Salfred 822184610Salfred switch (USB_GET_STATE(xfer)) { 823184610Salfred case USB_ST_TRANSFERRED: 824184610Salfred ustorage_fs_transfer_start(sc, USTORAGE_FS_T_BBB_COMMAND); 825184610Salfred break; 826184610Salfred 827184610Salfred case USB_ST_SETUP: 828184610Salfredtr_setup: 829244503Shselasky USETDW(sc->sc_csw->dCSWSignature, CSWSIGNATURE); 830244503Shselasky USETDW(sc->sc_csw->dCSWDataResidue, sc->sc_transfer.data_rem); 831184610Salfred 832184610Salfred if (sc->sc_transfer.data_error) { 833184610Salfred sc->sc_transfer.data_error = 0; 834194677Sthompsa usbd_xfer_set_stall(xfer); 835184610Salfred } 836244650Shselasky usbd_xfer_set_frame_len(xfer, 0, 837244650Shselasky sizeof(ustorage_fs_bbb_csw_t)); 838194228Sthompsa usbd_transfer_submit(xfer); 839184610Salfred break; 840184610Salfred 841184610Salfred default: 842194677Sthompsa if (error == USB_ERR_CANCELLED) { 843184610Salfred break; 844184610Salfred } 845184610Salfred /* If the pipe is already stalled, don't do another stall */ 846194677Sthompsa if (!usbd_xfer_is_stalled(xfer)) 847184610Salfred sc->sc_transfer.data_error = 1; 848194677Sthompsa 849184610Salfred /* try again */ 850184610Salfred goto tr_setup; 851184610Salfred } 852184610Salfred} 853184610Salfred 854184610Salfred/* SCSI commands that we recognize */ 855184610Salfred#define SC_FORMAT_UNIT 0x04 856184610Salfred#define SC_INQUIRY 0x12 857184610Salfred#define SC_MODE_SELECT_6 0x15 858184610Salfred#define SC_MODE_SELECT_10 0x55 859184610Salfred#define SC_MODE_SENSE_6 0x1a 860184610Salfred#define SC_MODE_SENSE_10 0x5a 861184610Salfred#define SC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e 862184610Salfred#define SC_READ_6 0x08 863184610Salfred#define SC_READ_10 0x28 864184610Salfred#define SC_READ_12 0xa8 865184610Salfred#define SC_READ_CAPACITY 0x25 866184610Salfred#define SC_READ_FORMAT_CAPACITIES 0x23 867184610Salfred#define SC_RELEASE 0x17 868184610Salfred#define SC_REQUEST_SENSE 0x03 869184610Salfred#define SC_RESERVE 0x16 870184610Salfred#define SC_SEND_DIAGNOSTIC 0x1d 871184610Salfred#define SC_START_STOP_UNIT 0x1b 872184610Salfred#define SC_SYNCHRONIZE_CACHE 0x35 873184610Salfred#define SC_TEST_UNIT_READY 0x00 874184610Salfred#define SC_VERIFY 0x2f 875184610Salfred#define SC_WRITE_6 0x0a 876184610Salfred#define SC_WRITE_10 0x2a 877184610Salfred#define SC_WRITE_12 0xaa 878184610Salfred 879184610Salfred/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */ 880184610Salfred#define SS_NO_SENSE 0 881184610Salfred#define SS_COMMUNICATION_FAILURE 0x040800 882184610Salfred#define SS_INVALID_COMMAND 0x052000 883184610Salfred#define SS_INVALID_FIELD_IN_CDB 0x052400 884184610Salfred#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100 885184610Salfred#define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500 886184610Salfred#define SS_MEDIUM_NOT_PRESENT 0x023a00 887184610Salfred#define SS_MEDIUM_REMOVAL_PREVENTED 0x055302 888184610Salfred#define SS_NOT_READY_TO_READY_TRANSITION 0x062800 889184610Salfred#define SS_RESET_OCCURRED 0x062900 890184610Salfred#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900 891184610Salfred#define SS_UNRECOVERED_READ_ERROR 0x031100 892184610Salfred#define SS_WRITE_ERROR 0x030c02 893184610Salfred#define SS_WRITE_PROTECTED 0x072700 894184610Salfred 895184610Salfred#define SK(x) ((uint8_t) ((x) >> 16)) /* Sense Key byte, etc. */ 896184610Salfred#define ASC(x) ((uint8_t) ((x) >> 8)) 897184610Salfred#define ASCQ(x) ((uint8_t) (x)) 898184610Salfred 899184610Salfred/* Routines for unaligned data access */ 900184610Salfred 901184610Salfredstatic uint16_t 902184610Salfredget_be16(uint8_t *buf) 903184610Salfred{ 904184610Salfred return ((uint16_t)buf[0] << 8) | ((uint16_t)buf[1]); 905184610Salfred} 906184610Salfred 907184610Salfredstatic uint32_t 908184610Salfredget_be32(uint8_t *buf) 909184610Salfred{ 910184610Salfred return ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16) | 911184610Salfred ((uint32_t)buf[2] << 8) | ((uint32_t)buf[3]); 912184610Salfred} 913184610Salfred 914184610Salfredstatic void 915184610Salfredput_be16(uint8_t *buf, uint16_t val) 916184610Salfred{ 917184610Salfred buf[0] = val >> 8; 918184610Salfred buf[1] = val; 919184610Salfred} 920184610Salfred 921184610Salfredstatic void 922184610Salfredput_be32(uint8_t *buf, uint32_t val) 923184610Salfred{ 924184610Salfred buf[0] = val >> 24; 925184610Salfred buf[1] = val >> 16; 926184610Salfred buf[2] = val >> 8; 927184610Salfred buf[3] = val & 0xff; 928184610Salfred} 929184610Salfred 930184610Salfred/*------------------------------------------------------------------------* 931184610Salfred * ustorage_fs_verify 932184610Salfred * 933184610Salfred * Returns: 934184610Salfred * 0: Success 935184610Salfred * Else: Failure 936184610Salfred *------------------------------------------------------------------------*/ 937184610Salfredstatic uint8_t 938184610Salfredustorage_fs_verify(struct ustorage_fs_softc *sc) 939184610Salfred{ 940184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 941184610Salfred uint32_t lba; 942184610Salfred uint32_t vlen; 943184610Salfred uint64_t file_offset; 944184610Salfred uint64_t amount_left; 945184610Salfred 946184610Salfred /* 947184610Salfred * Get the starting Logical Block Address 948184610Salfred */ 949244503Shselasky lba = get_be32(&sc->sc_cbw->CBWCDB[2]); 950184610Salfred 951184610Salfred /* 952184610Salfred * We allow DPO (Disable Page Out = don't save data in the cache) 953184610Salfred * but we don't implement it. 954184610Salfred */ 955244503Shselasky if ((sc->sc_cbw->CBWCDB[1] & ~0x10) != 0) { 956184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 957184610Salfred return (1); 958184610Salfred } 959244503Shselasky vlen = get_be16(&sc->sc_cbw->CBWCDB[7]); 960184610Salfred if (vlen == 0) { 961184610Salfred goto done; 962184610Salfred } 963184610Salfred /* No default reply */ 964184610Salfred 965184610Salfred /* Prepare to carry out the file verify */ 966184610Salfred amount_left = vlen; 967184610Salfred amount_left <<= 9; 968184610Salfred file_offset = lba; 969184610Salfred file_offset <<= 9; 970184610Salfred 971184610Salfred /* Range check */ 972184610Salfred vlen += lba; 973184610Salfred 974184610Salfred if ((vlen < lba) || 975184610Salfred (vlen > currlun->num_sectors) || 976184610Salfred (lba >= currlun->num_sectors)) { 977184610Salfred currlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 978184610Salfred return (1); 979184610Salfred } 980184610Salfred /* XXX TODO: verify that data is readable */ 981184610Salfreddone: 982233774Shselasky return (ustorage_fs_min_len(sc, 0, -1U)); 983184610Salfred} 984184610Salfred 985184610Salfred/*------------------------------------------------------------------------* 986184610Salfred * ustorage_fs_inquiry 987184610Salfred * 988184610Salfred * Returns: 989184610Salfred * 0: Success 990184610Salfred * Else: Failure 991184610Salfred *------------------------------------------------------------------------*/ 992184610Salfredstatic uint8_t 993184610Salfredustorage_fs_inquiry(struct ustorage_fs_softc *sc) 994184610Salfred{ 995184610Salfred uint8_t *buf = sc->sc_transfer.data_ptr; 996184610Salfred 997184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 998184610Salfred 999184610Salfred if (!sc->sc_transfer.currlun) { 1000184610Salfred /* Unsupported LUNs are okay */ 1001184610Salfred memset(buf, 0, 36); 1002184610Salfred buf[0] = 0x7f; 1003184610Salfred /* Unsupported, no device - type */ 1004233774Shselasky return (ustorage_fs_min_len(sc, 36, -1U)); 1005184610Salfred } 1006184610Salfred memset(buf, 0, 8); 1007184610Salfred /* Non - removable, direct - access device */ 1008184610Salfred if (currlun->removable) 1009184610Salfred buf[1] = 0x80; 1010184610Salfred buf[2] = 2; 1011184610Salfred /* ANSI SCSI level 2 */ 1012184610Salfred buf[3] = 2; 1013184610Salfred /* SCSI - 2 INQUIRY data format */ 1014184610Salfred buf[4] = 31; 1015184610Salfred /* Additional length */ 1016184610Salfred /* No special options */ 1017190719Sthompsa /* Copy in ID string */ 1018190719Sthompsa memcpy(buf + 8, USTORAGE_FS_ID_STRING, 28); 1019190719Sthompsa 1020190733Sthompsa#if (USTORAGE_QDATA_MAX < 36) 1021190733Sthompsa#error "(USTORAGE_QDATA_MAX < 36)" 1022190733Sthompsa#endif 1023233774Shselasky return (ustorage_fs_min_len(sc, 36, -1U)); 1024184610Salfred} 1025184610Salfred 1026184610Salfred/*------------------------------------------------------------------------* 1027184610Salfred * ustorage_fs_request_sense 1028184610Salfred * 1029184610Salfred * Returns: 1030184610Salfred * 0: Success 1031184610Salfred * Else: Failure 1032184610Salfred *------------------------------------------------------------------------*/ 1033184610Salfredstatic uint8_t 1034184610Salfredustorage_fs_request_sense(struct ustorage_fs_softc *sc) 1035184610Salfred{ 1036184610Salfred uint8_t *buf = sc->sc_transfer.data_ptr; 1037184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1038184610Salfred uint32_t sd; 1039184610Salfred uint32_t sdinfo; 1040184610Salfred uint8_t valid; 1041184610Salfred 1042184610Salfred /* 1043184610Salfred * From the SCSI-2 spec., section 7.9 (Unit attention condition): 1044184610Salfred * 1045184610Salfred * If a REQUEST SENSE command is received from an initiator 1046184610Salfred * with a pending unit attention condition (before the target 1047184610Salfred * generates the contingent allegiance condition), then the 1048184610Salfred * target shall either: 1049184610Salfred * a) report any pending sense data and preserve the unit 1050184610Salfred * attention condition on the logical unit, or, 1051184610Salfred * b) report the unit attention condition, may discard any 1052184610Salfred * pending sense data, and clear the unit attention 1053184610Salfred * condition on the logical unit for that initiator. 1054184610Salfred * 1055184610Salfred * FSG normally uses option a); enable this code to use option b). 1056184610Salfred */ 1057184610Salfred#if 0 1058184610Salfred if (currlun && currlun->unit_attention_data != SS_NO_SENSE) { 1059184610Salfred currlun->sense_data = currlun->unit_attention_data; 1060184610Salfred currlun->unit_attention_data = SS_NO_SENSE; 1061184610Salfred } 1062184610Salfred#endif 1063184610Salfred 1064184610Salfred if (!currlun) { 1065184610Salfred /* Unsupported LUNs are okay */ 1066184610Salfred sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; 1067184610Salfred sdinfo = 0; 1068184610Salfred valid = 0; 1069184610Salfred } else { 1070184610Salfred sd = currlun->sense_data; 1071184610Salfred sdinfo = currlun->sense_data_info; 1072184610Salfred valid = currlun->info_valid << 7; 1073184610Salfred currlun->sense_data = SS_NO_SENSE; 1074184610Salfred currlun->sense_data_info = 0; 1075184610Salfred currlun->info_valid = 0; 1076184610Salfred } 1077184610Salfred 1078184610Salfred memset(buf, 0, 18); 1079184610Salfred buf[0] = valid | 0x70; 1080184610Salfred /* Valid, current error */ 1081184610Salfred buf[2] = SK(sd); 1082184610Salfred put_be32(&buf[3], sdinfo); 1083184610Salfred /* Sense information */ 1084184610Salfred buf[7] = 18 - 8; 1085184610Salfred /* Additional sense length */ 1086184610Salfred buf[12] = ASC(sd); 1087184610Salfred buf[13] = ASCQ(sd); 1088190733Sthompsa 1089190733Sthompsa#if (USTORAGE_QDATA_MAX < 18) 1090190733Sthompsa#error "(USTORAGE_QDATA_MAX < 18)" 1091190733Sthompsa#endif 1092233774Shselasky return (ustorage_fs_min_len(sc, 18, -1U)); 1093184610Salfred} 1094184610Salfred 1095184610Salfred/*------------------------------------------------------------------------* 1096184610Salfred * ustorage_fs_read_capacity 1097184610Salfred * 1098184610Salfred * Returns: 1099184610Salfred * 0: Success 1100184610Salfred * Else: Failure 1101184610Salfred *------------------------------------------------------------------------*/ 1102184610Salfredstatic uint8_t 1103184610Salfredustorage_fs_read_capacity(struct ustorage_fs_softc *sc) 1104184610Salfred{ 1105184610Salfred uint8_t *buf = sc->sc_transfer.data_ptr; 1106184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1107244503Shselasky uint32_t lba = get_be32(&sc->sc_cbw->CBWCDB[2]); 1108244503Shselasky uint8_t pmi = sc->sc_cbw->CBWCDB[8]; 1109184610Salfred 1110184610Salfred /* Check the PMI and LBA fields */ 1111184610Salfred if ((pmi > 1) || ((pmi == 0) && (lba != 0))) { 1112184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 1113184610Salfred return (1); 1114184610Salfred } 1115190733Sthompsa /* Max logical block */ 1116184610Salfred put_be32(&buf[0], currlun->num_sectors - 1); 1117190733Sthompsa /* Block length */ 1118184610Salfred put_be32(&buf[4], 512); 1119190733Sthompsa 1120190733Sthompsa#if (USTORAGE_QDATA_MAX < 8) 1121190733Sthompsa#error "(USTORAGE_QDATA_MAX < 8)" 1122190733Sthompsa#endif 1123233774Shselasky return (ustorage_fs_min_len(sc, 8, -1U)); 1124184610Salfred} 1125184610Salfred 1126184610Salfred/*------------------------------------------------------------------------* 1127184610Salfred * ustorage_fs_mode_sense 1128184610Salfred * 1129184610Salfred * Returns: 1130184610Salfred * 0: Success 1131184610Salfred * Else: Failure 1132184610Salfred *------------------------------------------------------------------------*/ 1133184610Salfredstatic uint8_t 1134184610Salfredustorage_fs_mode_sense(struct ustorage_fs_softc *sc) 1135184610Salfred{ 1136184610Salfred uint8_t *buf = sc->sc_transfer.data_ptr; 1137184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1138184610Salfred uint8_t *buf0; 1139184610Salfred uint16_t len; 1140184610Salfred uint16_t limit; 1141244503Shselasky uint8_t mscmnd = sc->sc_cbw->CBWCDB[0]; 1142184610Salfred uint8_t pc; 1143184610Salfred uint8_t page_code; 1144184610Salfred uint8_t changeable_values; 1145184610Salfred uint8_t all_pages; 1146184610Salfred 1147184610Salfred buf0 = buf; 1148184610Salfred 1149244503Shselasky if ((sc->sc_cbw->CBWCDB[1] & ~0x08) != 0) { 1150184610Salfred /* Mask away DBD */ 1151184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 1152184610Salfred return (1); 1153184610Salfred } 1154244503Shselasky pc = sc->sc_cbw->CBWCDB[2] >> 6; 1155244503Shselasky page_code = sc->sc_cbw->CBWCDB[2] & 0x3f; 1156184610Salfred if (pc == 3) { 1157184610Salfred currlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; 1158184610Salfred return (1); 1159184610Salfred } 1160184610Salfred changeable_values = (pc == 1); 1161184610Salfred all_pages = (page_code == 0x3f); 1162184610Salfred 1163184610Salfred /* 1164184610Salfred * Write the mode parameter header. Fixed values are: default 1165184610Salfred * medium type, no cache control (DPOFUA), and no block descriptors. 1166184610Salfred * The only variable value is the WriteProtect bit. We will fill in 1167184610Salfred * the mode data length later. 1168184610Salfred */ 1169184610Salfred memset(buf, 0, 8); 1170184610Salfred if (mscmnd == SC_MODE_SENSE_6) { 1171184610Salfred buf[2] = (currlun->read_only ? 0x80 : 0x00); 1172184610Salfred /* WP, DPOFUA */ 1173184610Salfred buf += 4; 1174184610Salfred limit = 255; 1175184610Salfred } else { 1176184610Salfred /* SC_MODE_SENSE_10 */ 1177184610Salfred buf[3] = (currlun->read_only ? 0x80 : 0x00); 1178184610Salfred /* WP, DPOFUA */ 1179184610Salfred buf += 8; 1180184610Salfred limit = 65535; 1181184610Salfred /* Should really be mod_data.buflen */ 1182184610Salfred } 1183184610Salfred 1184184610Salfred /* No block descriptors */ 1185184610Salfred 1186184610Salfred /* 1187184610Salfred * The mode pages, in numerical order. 1188184610Salfred */ 1189184610Salfred if ((page_code == 0x08) || all_pages) { 1190184610Salfred buf[0] = 0x08; 1191184610Salfred /* Page code */ 1192184610Salfred buf[1] = 10; 1193184610Salfred /* Page length */ 1194184610Salfred memset(buf + 2, 0, 10); 1195184610Salfred /* None of the fields are changeable */ 1196184610Salfred 1197184610Salfred if (!changeable_values) { 1198184610Salfred buf[2] = 0x04; 1199184610Salfred /* Write cache enable, */ 1200184610Salfred /* Read cache not disabled */ 1201184610Salfred /* No cache retention priorities */ 1202184610Salfred put_be16(&buf[4], 0xffff); 1203184610Salfred /* Don 't disable prefetch */ 1204184610Salfred /* Minimum prefetch = 0 */ 1205184610Salfred put_be16(&buf[8], 0xffff); 1206184610Salfred /* Maximum prefetch */ 1207184610Salfred put_be16(&buf[10], 0xffff); 1208184610Salfred /* Maximum prefetch ceiling */ 1209184610Salfred } 1210184610Salfred buf += 12; 1211184610Salfred } 1212184610Salfred /* 1213184610Salfred * Check that a valid page was requested and the mode data length 1214184610Salfred * isn't too long. 1215184610Salfred */ 1216184610Salfred len = buf - buf0; 1217184610Salfred if (len > limit) { 1218184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 1219184610Salfred return (1); 1220184610Salfred } 1221184610Salfred /* Store the mode data length */ 1222184610Salfred if (mscmnd == SC_MODE_SENSE_6) 1223184610Salfred buf0[0] = len - 1; 1224184610Salfred else 1225184610Salfred put_be16(buf0, len - 2); 1226190733Sthompsa 1227190733Sthompsa#if (USTORAGE_QDATA_MAX < 24) 1228190733Sthompsa#error "(USTORAGE_QDATA_MAX < 24)" 1229190733Sthompsa#endif 1230233774Shselasky return (ustorage_fs_min_len(sc, len, -1U)); 1231184610Salfred} 1232184610Salfred 1233184610Salfred/*------------------------------------------------------------------------* 1234184610Salfred * ustorage_fs_start_stop 1235184610Salfred * 1236184610Salfred * Returns: 1237184610Salfred * 0: Success 1238184610Salfred * Else: Failure 1239184610Salfred *------------------------------------------------------------------------*/ 1240184610Salfredstatic uint8_t 1241184610Salfredustorage_fs_start_stop(struct ustorage_fs_softc *sc) 1242184610Salfred{ 1243184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1244184610Salfred uint8_t loej; 1245184610Salfred uint8_t start; 1246184610Salfred uint8_t immed; 1247184610Salfred 1248184610Salfred if (!currlun->removable) { 1249184610Salfred currlun->sense_data = SS_INVALID_COMMAND; 1250184610Salfred return (1); 1251184610Salfred } 1252244503Shselasky immed = sc->sc_cbw->CBWCDB[1] & 0x01; 1253244503Shselasky loej = sc->sc_cbw->CBWCDB[4] & 0x02; 1254244503Shselasky start = sc->sc_cbw->CBWCDB[4] & 0x01; 1255184610Salfred 1256184610Salfred if (immed || loej || start) { 1257184610Salfred /* compile fix */ 1258184610Salfred } 1259184610Salfred return (0); 1260184610Salfred} 1261184610Salfred 1262184610Salfred/*------------------------------------------------------------------------* 1263184610Salfred * ustorage_fs_prevent_allow 1264184610Salfred * 1265184610Salfred * Returns: 1266184610Salfred * 0: Success 1267184610Salfred * Else: Failure 1268184610Salfred *------------------------------------------------------------------------*/ 1269184610Salfredstatic uint8_t 1270184610Salfredustorage_fs_prevent_allow(struct ustorage_fs_softc *sc) 1271184610Salfred{ 1272184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1273184610Salfred uint8_t prevent; 1274184610Salfred 1275184610Salfred if (!currlun->removable) { 1276184610Salfred currlun->sense_data = SS_INVALID_COMMAND; 1277184610Salfred return (1); 1278184610Salfred } 1279244503Shselasky prevent = sc->sc_cbw->CBWCDB[4] & 0x01; 1280244503Shselasky if ((sc->sc_cbw->CBWCDB[4] & ~0x01) != 0) { 1281184610Salfred /* Mask away Prevent */ 1282184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 1283184610Salfred return (1); 1284184610Salfred } 1285184610Salfred if (currlun->prevent_medium_removal && !prevent) { 1286184610Salfred //fsync_sub(currlun); 1287184610Salfred } 1288184610Salfred currlun->prevent_medium_removal = prevent; 1289184610Salfred return (0); 1290184610Salfred} 1291184610Salfred 1292184610Salfred/*------------------------------------------------------------------------* 1293184610Salfred * ustorage_fs_read_format_capacities 1294184610Salfred * 1295184610Salfred * Returns: 1296184610Salfred * 0: Success 1297184610Salfred * Else: Failure 1298184610Salfred *------------------------------------------------------------------------*/ 1299184610Salfredstatic uint8_t 1300184610Salfredustorage_fs_read_format_capacities(struct ustorage_fs_softc *sc) 1301184610Salfred{ 1302184610Salfred uint8_t *buf = sc->sc_transfer.data_ptr; 1303184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1304184610Salfred 1305184610Salfred buf[0] = buf[1] = buf[2] = 0; 1306184610Salfred buf[3] = 8; 1307184610Salfred /* Only the Current / Maximum Capacity Descriptor */ 1308184610Salfred buf += 4; 1309184610Salfred 1310190733Sthompsa /* Number of blocks */ 1311184610Salfred put_be32(&buf[0], currlun->num_sectors); 1312190733Sthompsa /* Block length */ 1313184610Salfred put_be32(&buf[4], 512); 1314190733Sthompsa /* Current capacity */ 1315184610Salfred buf[4] = 0x02; 1316190733Sthompsa 1317190733Sthompsa#if (USTORAGE_QDATA_MAX < 12) 1318190733Sthompsa#error "(USTORAGE_QDATA_MAX < 12)" 1319190733Sthompsa#endif 1320233774Shselasky return (ustorage_fs_min_len(sc, 12, -1U)); 1321184610Salfred} 1322184610Salfred 1323184610Salfred/*------------------------------------------------------------------------* 1324184610Salfred * ustorage_fs_mode_select 1325184610Salfred * 1326184610Salfred * Return values: 1327184610Salfred * 0: Success 1328184610Salfred * Else: Failure 1329184610Salfred *------------------------------------------------------------------------*/ 1330184610Salfredstatic uint8_t 1331184610Salfredustorage_fs_mode_select(struct ustorage_fs_softc *sc) 1332184610Salfred{ 1333184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1334184610Salfred 1335184610Salfred /* We don't support MODE SELECT */ 1336184610Salfred currlun->sense_data = SS_INVALID_COMMAND; 1337184610Salfred return (1); 1338184610Salfred} 1339184610Salfred 1340184610Salfred/*------------------------------------------------------------------------* 1341184610Salfred * ustorage_fs_synchronize_cache 1342184610Salfred * 1343184610Salfred * Return values: 1344184610Salfred * 0: Success 1345184610Salfred * Else: Failure 1346184610Salfred *------------------------------------------------------------------------*/ 1347184610Salfredstatic uint8_t 1348184610Salfredustorage_fs_synchronize_cache(struct ustorage_fs_softc *sc) 1349184610Salfred{ 1350186730Salfred#if 0 1351184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1352184610Salfred uint8_t rc; 1353184610Salfred 1354184610Salfred /* 1355184610Salfred * We ignore the requested LBA and write out all dirty data buffers. 1356184610Salfred */ 1357184610Salfred rc = 0; 1358184610Salfred if (rc) { 1359184610Salfred currlun->sense_data = SS_WRITE_ERROR; 1360184610Salfred } 1361186730Salfred#endif 1362184610Salfred return (0); 1363184610Salfred} 1364184610Salfred 1365184610Salfred/*------------------------------------------------------------------------* 1366184610Salfred * ustorage_fs_read - read data from disk 1367184610Salfred * 1368184610Salfred * Return values: 1369184610Salfred * 0: Success 1370184610Salfred * Else: Failure 1371184610Salfred *------------------------------------------------------------------------*/ 1372184610Salfredstatic uint8_t 1373184610Salfredustorage_fs_read(struct ustorage_fs_softc *sc) 1374184610Salfred{ 1375184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1376184610Salfred uint64_t file_offset; 1377184610Salfred uint32_t lba; 1378184610Salfred uint32_t len; 1379184610Salfred 1380184610Salfred /* 1381184610Salfred * Get the starting Logical Block Address and check that it's not 1382184610Salfred * too big 1383184610Salfred */ 1384244503Shselasky if (sc->sc_cbw->CBWCDB[0] == SC_READ_6) { 1385244503Shselasky lba = (((uint32_t)sc->sc_cbw->CBWCDB[1]) << 16) | 1386244503Shselasky get_be16(&sc->sc_cbw->CBWCDB[2]); 1387184610Salfred } else { 1388244503Shselasky lba = get_be32(&sc->sc_cbw->CBWCDB[2]); 1389184610Salfred 1390184610Salfred /* 1391184610Salfred * We allow DPO (Disable Page Out = don't save data in the 1392184610Salfred * cache) and FUA (Force Unit Access = don't read from the 1393184610Salfred * cache), but we don't implement them. 1394184610Salfred */ 1395244503Shselasky if ((sc->sc_cbw->CBWCDB[1] & ~0x18) != 0) { 1396184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 1397184610Salfred return (1); 1398184610Salfred } 1399184610Salfred } 1400184610Salfred len = sc->sc_transfer.data_rem >> 9; 1401184610Salfred len += lba; 1402184610Salfred 1403184610Salfred if ((len < lba) || 1404184610Salfred (len > currlun->num_sectors) || 1405184610Salfred (lba >= currlun->num_sectors)) { 1406184610Salfred currlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 1407184610Salfred return (1); 1408184610Salfred } 1409184610Salfred file_offset = lba; 1410184610Salfred file_offset <<= 9; 1411184610Salfred 1412190181Sthompsa sc->sc_transfer.data_ptr = currlun->memory_image + file_offset; 1413184610Salfred 1414184610Salfred return (0); 1415184610Salfred} 1416184610Salfred 1417184610Salfred/*------------------------------------------------------------------------* 1418184610Salfred * ustorage_fs_write - write data to disk 1419184610Salfred * 1420184610Salfred * Return values: 1421184610Salfred * 0: Success 1422184610Salfred * Else: Failure 1423184610Salfred *------------------------------------------------------------------------*/ 1424184610Salfredstatic uint8_t 1425184610Salfredustorage_fs_write(struct ustorage_fs_softc *sc) 1426184610Salfred{ 1427184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1428184610Salfred uint64_t file_offset; 1429184610Salfred uint32_t lba; 1430184610Salfred uint32_t len; 1431184610Salfred 1432184610Salfred if (currlun->read_only) { 1433184610Salfred currlun->sense_data = SS_WRITE_PROTECTED; 1434184610Salfred return (1); 1435184610Salfred } 1436184610Salfred /* XXX clear SYNC */ 1437184610Salfred 1438184610Salfred /* 1439184610Salfred * Get the starting Logical Block Address and check that it's not 1440184610Salfred * too big. 1441184610Salfred */ 1442244503Shselasky if (sc->sc_cbw->CBWCDB[0] == SC_WRITE_6) 1443244503Shselasky lba = (((uint32_t)sc->sc_cbw->CBWCDB[1]) << 16) | 1444244503Shselasky get_be16(&sc->sc_cbw->CBWCDB[2]); 1445184610Salfred else { 1446244503Shselasky lba = get_be32(&sc->sc_cbw->CBWCDB[2]); 1447184610Salfred 1448184610Salfred /* 1449184610Salfred * We allow DPO (Disable Page Out = don't save data in the 1450184610Salfred * cache) and FUA (Force Unit Access = write directly to the 1451184610Salfred * medium). We don't implement DPO; we implement FUA by 1452184610Salfred * performing synchronous output. 1453184610Salfred */ 1454244503Shselasky if ((sc->sc_cbw->CBWCDB[1] & ~0x18) != 0) { 1455184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 1456184610Salfred return (1); 1457184610Salfred } 1458244503Shselasky if (sc->sc_cbw->CBWCDB[1] & 0x08) { 1459184610Salfred /* FUA */ 1460184610Salfred /* XXX set SYNC flag here */ 1461184610Salfred } 1462184610Salfred } 1463184610Salfred 1464184610Salfred len = sc->sc_transfer.data_rem >> 9; 1465184610Salfred len += lba; 1466184610Salfred 1467184610Salfred if ((len < lba) || 1468184610Salfred (len > currlun->num_sectors) || 1469184610Salfred (lba >= currlun->num_sectors)) { 1470184610Salfred currlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 1471184610Salfred return (1); 1472184610Salfred } 1473184610Salfred file_offset = lba; 1474184610Salfred file_offset <<= 9; 1475184610Salfred 1476190181Sthompsa sc->sc_transfer.data_ptr = currlun->memory_image + file_offset; 1477184610Salfred 1478184610Salfred return (0); 1479184610Salfred} 1480184610Salfred 1481184610Salfred/*------------------------------------------------------------------------* 1482184610Salfred * ustorage_fs_min_len 1483184610Salfred * 1484184610Salfred * Return values: 1485184610Salfred * 0: Success 1486184610Salfred * Else: Failure 1487184610Salfred *------------------------------------------------------------------------*/ 1488184610Salfredstatic uint8_t 1489184610Salfredustorage_fs_min_len(struct ustorage_fs_softc *sc, uint32_t len, uint32_t mask) 1490184610Salfred{ 1491184610Salfred if (len != sc->sc_transfer.data_rem) { 1492184610Salfred 1493184610Salfred if (sc->sc_transfer.cbw_dir == DIR_READ) { 1494184610Salfred /* 1495184610Salfred * there must be something wrong about this SCSI 1496184610Salfred * command 1497184610Salfred */ 1498244503Shselasky sc->sc_csw->bCSWStatus = CSWSTATUS_PHASE; 1499184610Salfred return (1); 1500184610Salfred } 1501184610Salfred /* compute the minimum length */ 1502184610Salfred 1503184610Salfred if (sc->sc_transfer.data_rem > len) { 1504184610Salfred /* data ends prematurely */ 1505184610Salfred sc->sc_transfer.data_rem = len; 1506184610Salfred sc->sc_transfer.data_short = 1; 1507184610Salfred } 1508184610Salfred /* check length alignment */ 1509184610Salfred 1510184610Salfred if (sc->sc_transfer.data_rem & ~mask) { 1511184610Salfred /* data ends prematurely */ 1512184610Salfred sc->sc_transfer.data_rem &= mask; 1513184610Salfred sc->sc_transfer.data_short = 1; 1514184610Salfred } 1515184610Salfred } 1516184610Salfred return (0); 1517184610Salfred} 1518184610Salfred 1519184610Salfred/*------------------------------------------------------------------------* 1520184610Salfred * ustorage_fs_check_cmd - check command routine 1521184610Salfred * 1522184610Salfred * Check whether the command is properly formed and whether its data 1523184610Salfred * size and direction agree with the values we already have. 1524184610Salfred * 1525184610Salfred * Return values: 1526184610Salfred * 0: Success 1527184610Salfred * Else: Failure 1528184610Salfred *------------------------------------------------------------------------*/ 1529184610Salfredstatic uint8_t 1530184610Salfredustorage_fs_check_cmd(struct ustorage_fs_softc *sc, uint8_t min_cmd_size, 1531184610Salfred uint16_t mask, uint8_t needs_medium) 1532184610Salfred{ 1533184610Salfred struct ustorage_fs_lun *currlun; 1534244503Shselasky uint8_t lun = (sc->sc_cbw->CBWCDB[1] >> 5); 1535184610Salfred uint8_t i; 1536184610Salfred 1537184610Salfred /* Verify the length of the command itself */ 1538184610Salfred if (min_cmd_size > sc->sc_transfer.cmd_len) { 1539184610Salfred DPRINTF("%u > %u\n", 1540184610Salfred min_cmd_size, sc->sc_transfer.cmd_len); 1541244503Shselasky sc->sc_csw->bCSWStatus = CSWSTATUS_PHASE; 1542184610Salfred return (1); 1543184610Salfred } 1544184610Salfred /* Mask away the LUN */ 1545244503Shselasky sc->sc_cbw->CBWCDB[1] &= 0x1f; 1546184610Salfred 1547184610Salfred /* Check if LUN is correct */ 1548184610Salfred if (lun != sc->sc_transfer.lun) { 1549184610Salfred 1550184610Salfred } 1551184610Salfred /* Check the LUN */ 1552184610Salfred if (sc->sc_transfer.lun <= sc->sc_last_lun) { 1553184610Salfred sc->sc_transfer.currlun = currlun = 1554184610Salfred sc->sc_lun + sc->sc_transfer.lun; 1555244503Shselasky if (sc->sc_cbw->CBWCDB[0] != SC_REQUEST_SENSE) { 1556184610Salfred currlun->sense_data = SS_NO_SENSE; 1557184610Salfred currlun->sense_data_info = 0; 1558184610Salfred currlun->info_valid = 0; 1559184610Salfred } 1560184610Salfred /* 1561184610Salfred * If a unit attention condition exists, only INQUIRY 1562184610Salfred * and REQUEST SENSE commands are allowed. Anything 1563184610Salfred * else must fail! 1564184610Salfred */ 1565184610Salfred if ((currlun->unit_attention_data != SS_NO_SENSE) && 1566244503Shselasky (sc->sc_cbw->CBWCDB[0] != SC_INQUIRY) && 1567244503Shselasky (sc->sc_cbw->CBWCDB[0] != SC_REQUEST_SENSE)) { 1568184610Salfred currlun->sense_data = currlun->unit_attention_data; 1569184610Salfred currlun->unit_attention_data = SS_NO_SENSE; 1570184610Salfred return (1); 1571184610Salfred } 1572184610Salfred } else { 1573184610Salfred sc->sc_transfer.currlun = currlun = NULL; 1574184610Salfred 1575184610Salfred /* 1576184610Salfred * INQUIRY and REQUEST SENSE commands are explicitly allowed 1577184610Salfred * to use unsupported LUNs; all others may not. 1578184610Salfred */ 1579244503Shselasky if ((sc->sc_cbw->CBWCDB[0] != SC_INQUIRY) && 1580244503Shselasky (sc->sc_cbw->CBWCDB[0] != SC_REQUEST_SENSE)) { 1581184610Salfred return (1); 1582184610Salfred } 1583184610Salfred } 1584184610Salfred 1585184610Salfred /* 1586184610Salfred * Check that only command bytes listed in the mask are 1587184610Salfred * non-zero. 1588184610Salfred */ 1589184610Salfred for (i = 0; i != min_cmd_size; i++) { 1590244503Shselasky if (sc->sc_cbw->CBWCDB[i] && !(mask & (1UL << i))) { 1591184610Salfred if (currlun) { 1592184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 1593184610Salfred } 1594184610Salfred return (1); 1595184610Salfred } 1596184610Salfred } 1597184610Salfred 1598184610Salfred /* 1599184610Salfred * If the medium isn't mounted and the command needs to access 1600184610Salfred * it, return an error. 1601184610Salfred */ 1602184610Salfred if (currlun && (!currlun->memory_image) && needs_medium) { 1603184610Salfred currlun->sense_data = SS_MEDIUM_NOT_PRESENT; 1604184610Salfred return (1); 1605184610Salfred } 1606184610Salfred return (0); 1607184610Salfred} 1608184610Salfred 1609184610Salfred/*------------------------------------------------------------------------* 1610184610Salfred * ustorage_fs_do_cmd - do command 1611184610Salfred * 1612184610Salfred * Return values: 1613184610Salfred * 0: Success 1614184610Salfred * Else: Failure 1615184610Salfred *------------------------------------------------------------------------*/ 1616184610Salfredstatic uint8_t 1617184610Salfredustorage_fs_do_cmd(struct ustorage_fs_softc *sc) 1618184610Salfred{ 1619184610Salfred uint8_t error = 1; 1620184610Salfred uint8_t i; 1621190719Sthompsa uint32_t temp; 1622190719Sthompsa const uint32_t mask9 = (0xFFFFFFFFUL >> 9) << 9; 1623184610Salfred 1624184610Salfred /* set default data transfer pointer */ 1625184610Salfred sc->sc_transfer.data_ptr = sc->sc_qdata; 1626184610Salfred 1627184610Salfred DPRINTF("cmd_data[0]=0x%02x, data_rem=0x%08x\n", 1628244503Shselasky sc->sc_cbw->CBWCDB[0], sc->sc_transfer.data_rem); 1629184610Salfred 1630244503Shselasky switch (sc->sc_cbw->CBWCDB[0]) { 1631184610Salfred case SC_INQUIRY: 1632184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1633244503Shselasky error = ustorage_fs_min_len(sc, sc->sc_cbw->CBWCDB[4], -1U); 1634184610Salfred if (error) { 1635184610Salfred break; 1636184610Salfred } 1637184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1638190719Sthompsa (1UL << 4) | 1, 0); 1639184610Salfred if (error) { 1640184610Salfred break; 1641184610Salfred } 1642184610Salfred error = ustorage_fs_inquiry(sc); 1643184610Salfred 1644184610Salfred break; 1645184610Salfred 1646184610Salfred case SC_MODE_SELECT_6: 1647184610Salfred sc->sc_transfer.cmd_dir = DIR_READ; 1648244503Shselasky error = ustorage_fs_min_len(sc, sc->sc_cbw->CBWCDB[4], -1U); 1649184610Salfred if (error) { 1650184610Salfred break; 1651184610Salfred } 1652184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1653190719Sthompsa (1UL << 1) | (1UL << 4) | 1, 0); 1654184610Salfred if (error) { 1655184610Salfred break; 1656184610Salfred } 1657184610Salfred error = ustorage_fs_mode_select(sc); 1658184610Salfred 1659184610Salfred break; 1660184610Salfred 1661184610Salfred case SC_MODE_SELECT_10: 1662184610Salfred sc->sc_transfer.cmd_dir = DIR_READ; 1663184610Salfred error = ustorage_fs_min_len(sc, 1664244503Shselasky get_be16(&sc->sc_cbw->CBWCDB[7]), -1U); 1665184610Salfred if (error) { 1666184610Salfred break; 1667184610Salfred } 1668184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1669190719Sthompsa (1UL << 1) | (3UL << 7) | 1, 0); 1670184610Salfred if (error) { 1671184610Salfred break; 1672184610Salfred } 1673184610Salfred error = ustorage_fs_mode_select(sc); 1674184610Salfred 1675184610Salfred break; 1676184610Salfred 1677184610Salfred case SC_MODE_SENSE_6: 1678184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1679244503Shselasky error = ustorage_fs_min_len(sc, sc->sc_cbw->CBWCDB[4], -1U); 1680184610Salfred if (error) { 1681184610Salfred break; 1682184610Salfred } 1683184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1684190719Sthompsa (1UL << 1) | (1UL << 2) | (1UL << 4) | 1, 0); 1685184610Salfred if (error) { 1686184610Salfred break; 1687184610Salfred } 1688184610Salfred error = ustorage_fs_mode_sense(sc); 1689184610Salfred 1690184610Salfred break; 1691184610Salfred 1692184610Salfred case SC_MODE_SENSE_10: 1693184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1694184610Salfred error = ustorage_fs_min_len(sc, 1695244503Shselasky get_be16(&sc->sc_cbw->CBWCDB[7]), -1U); 1696184610Salfred if (error) { 1697184610Salfred break; 1698184610Salfred } 1699184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1700190719Sthompsa (1UL << 1) | (1UL << 2) | (3UL << 7) | 1, 0); 1701184610Salfred if (error) { 1702184610Salfred break; 1703184610Salfred } 1704184610Salfred error = ustorage_fs_mode_sense(sc); 1705184610Salfred 1706184610Salfred break; 1707184610Salfred 1708184610Salfred case SC_PREVENT_ALLOW_MEDIUM_REMOVAL: 1709233774Shselasky error = ustorage_fs_min_len(sc, 0, -1U); 1710184610Salfred if (error) { 1711184610Salfred break; 1712184610Salfred } 1713184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1714190719Sthompsa (1UL << 4) | 1, 0); 1715184610Salfred if (error) { 1716184610Salfred break; 1717184610Salfred } 1718184610Salfred error = ustorage_fs_prevent_allow(sc); 1719184610Salfred 1720184610Salfred break; 1721184610Salfred 1722184610Salfred case SC_READ_6: 1723244503Shselasky i = sc->sc_cbw->CBWCDB[4]; 1724184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1725190719Sthompsa temp = ((i == 0) ? 256UL : i); 1726190719Sthompsa error = ustorage_fs_min_len(sc, temp << 9, mask9); 1727184610Salfred if (error) { 1728184610Salfred break; 1729184610Salfred } 1730184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1731190719Sthompsa (7UL << 1) | (1UL << 4) | 1, 1); 1732184610Salfred if (error) { 1733184610Salfred break; 1734184610Salfred } 1735184610Salfred error = ustorage_fs_read(sc); 1736184610Salfred 1737184610Salfred break; 1738184610Salfred 1739184610Salfred case SC_READ_10: 1740184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1741244503Shselasky temp = get_be16(&sc->sc_cbw->CBWCDB[7]); 1742190719Sthompsa error = ustorage_fs_min_len(sc, temp << 9, mask9); 1743184610Salfred if (error) { 1744184610Salfred break; 1745184610Salfred } 1746184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1747190719Sthompsa (1UL << 1) | (0xfUL << 2) | (3UL << 7) | 1, 1); 1748184610Salfred if (error) { 1749184610Salfred break; 1750184610Salfred } 1751184610Salfred error = ustorage_fs_read(sc); 1752184610Salfred 1753184610Salfred break; 1754184610Salfred 1755184610Salfred case SC_READ_12: 1756184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1757244503Shselasky temp = get_be32(&sc->sc_cbw->CBWCDB[6]); 1758190719Sthompsa if (temp >= (1UL << (32 - 9))) { 1759190719Sthompsa /* numerical overflow */ 1760244503Shselasky sc->sc_csw->bCSWStatus = CSWSTATUS_FAILED; 1761190719Sthompsa error = 1; 1762190719Sthompsa break; 1763190719Sthompsa } 1764190719Sthompsa error = ustorage_fs_min_len(sc, temp << 9, mask9); 1765184610Salfred if (error) { 1766184610Salfred break; 1767184610Salfred } 1768184610Salfred error = ustorage_fs_check_cmd(sc, 12, 1769190719Sthompsa (1UL << 1) | (0xfUL << 2) | (0xfUL << 6) | 1, 1); 1770184610Salfred if (error) { 1771184610Salfred break; 1772184610Salfred } 1773184610Salfred error = ustorage_fs_read(sc); 1774184610Salfred 1775184610Salfred break; 1776184610Salfred 1777184610Salfred case SC_READ_CAPACITY: 1778184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1779184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1780190719Sthompsa (0xfUL << 2) | (1UL << 8) | 1, 1); 1781184610Salfred if (error) { 1782184610Salfred break; 1783184610Salfred } 1784184610Salfred error = ustorage_fs_read_capacity(sc); 1785184610Salfred 1786184610Salfred break; 1787184610Salfred 1788184610Salfred case SC_READ_FORMAT_CAPACITIES: 1789184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1790184610Salfred error = ustorage_fs_min_len(sc, 1791244503Shselasky get_be16(&sc->sc_cbw->CBWCDB[7]), -1U); 1792184610Salfred if (error) { 1793184610Salfred break; 1794184610Salfred } 1795184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1796190719Sthompsa (3UL << 7) | 1, 1); 1797184610Salfred if (error) { 1798184610Salfred break; 1799184610Salfred } 1800184610Salfred error = ustorage_fs_read_format_capacities(sc); 1801184610Salfred 1802184610Salfred break; 1803184610Salfred 1804184610Salfred case SC_REQUEST_SENSE: 1805184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1806244503Shselasky error = ustorage_fs_min_len(sc, sc->sc_cbw->CBWCDB[4], -1U); 1807184610Salfred if (error) { 1808184610Salfred break; 1809184610Salfred } 1810184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1811190719Sthompsa (1UL << 4) | 1, 0); 1812184610Salfred if (error) { 1813184610Salfred break; 1814184610Salfred } 1815184610Salfred error = ustorage_fs_request_sense(sc); 1816184610Salfred 1817184610Salfred break; 1818184610Salfred 1819184610Salfred case SC_START_STOP_UNIT: 1820233774Shselasky error = ustorage_fs_min_len(sc, 0, -1U); 1821184610Salfred if (error) { 1822184610Salfred break; 1823184610Salfred } 1824184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1825190719Sthompsa (1UL << 1) | (1UL << 4) | 1, 0); 1826184610Salfred if (error) { 1827184610Salfred break; 1828184610Salfred } 1829184610Salfred error = ustorage_fs_start_stop(sc); 1830184610Salfred 1831184610Salfred break; 1832184610Salfred 1833184610Salfred case SC_SYNCHRONIZE_CACHE: 1834233774Shselasky error = ustorage_fs_min_len(sc, 0, -1U); 1835184610Salfred if (error) { 1836184610Salfred break; 1837184610Salfred } 1838184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1839190719Sthompsa (0xfUL << 2) | (3UL << 7) | 1, 1); 1840184610Salfred if (error) { 1841184610Salfred break; 1842184610Salfred } 1843184610Salfred error = ustorage_fs_synchronize_cache(sc); 1844184610Salfred 1845184610Salfred break; 1846184610Salfred 1847184610Salfred case SC_TEST_UNIT_READY: 1848233774Shselasky error = ustorage_fs_min_len(sc, 0, -1U); 1849184610Salfred if (error) { 1850184610Salfred break; 1851184610Salfred } 1852184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1853184610Salfred 0 | 1, 1); 1854184610Salfred break; 1855184610Salfred 1856184610Salfred /* 1857184610Salfred * Although optional, this command is used by MS-Windows. 1858184610Salfred * We support a minimal version: BytChk must be 0. 1859184610Salfred */ 1860184610Salfred case SC_VERIFY: 1861233774Shselasky error = ustorage_fs_min_len(sc, 0, -1U); 1862184610Salfred if (error) { 1863184610Salfred break; 1864184610Salfred } 1865184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1866190719Sthompsa (1UL << 1) | (0xfUL << 2) | (3UL << 7) | 1, 1); 1867184610Salfred if (error) { 1868184610Salfred break; 1869184610Salfred } 1870184610Salfred error = ustorage_fs_verify(sc); 1871184610Salfred 1872184610Salfred break; 1873184610Salfred 1874184610Salfred case SC_WRITE_6: 1875244503Shselasky i = sc->sc_cbw->CBWCDB[4]; 1876184610Salfred sc->sc_transfer.cmd_dir = DIR_READ; 1877190719Sthompsa temp = ((i == 0) ? 256UL : i); 1878190719Sthompsa error = ustorage_fs_min_len(sc, temp << 9, mask9); 1879184610Salfred if (error) { 1880184610Salfred break; 1881184610Salfred } 1882184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1883190719Sthompsa (7UL << 1) | (1UL << 4) | 1, 1); 1884184610Salfred if (error) { 1885184610Salfred break; 1886184610Salfred } 1887184610Salfred error = ustorage_fs_write(sc); 1888184610Salfred 1889184610Salfred break; 1890184610Salfred 1891184610Salfred case SC_WRITE_10: 1892184610Salfred sc->sc_transfer.cmd_dir = DIR_READ; 1893244503Shselasky temp = get_be16(&sc->sc_cbw->CBWCDB[7]); 1894190719Sthompsa error = ustorage_fs_min_len(sc, temp << 9, mask9); 1895184610Salfred if (error) { 1896184610Salfred break; 1897184610Salfred } 1898184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1899190719Sthompsa (1UL << 1) | (0xfUL << 2) | (3UL << 7) | 1, 1); 1900184610Salfred if (error) { 1901184610Salfred break; 1902184610Salfred } 1903184610Salfred error = ustorage_fs_write(sc); 1904184610Salfred 1905184610Salfred break; 1906184610Salfred 1907184610Salfred case SC_WRITE_12: 1908184610Salfred sc->sc_transfer.cmd_dir = DIR_READ; 1909244503Shselasky temp = get_be32(&sc->sc_cbw->CBWCDB[6]); 1910190719Sthompsa if (temp > (mask9 >> 9)) { 1911190719Sthompsa /* numerical overflow */ 1912244503Shselasky sc->sc_csw->bCSWStatus = CSWSTATUS_FAILED; 1913190719Sthompsa error = 1; 1914190719Sthompsa break; 1915190719Sthompsa } 1916190719Sthompsa error = ustorage_fs_min_len(sc, temp << 9, mask9); 1917184610Salfred if (error) { 1918184610Salfred break; 1919184610Salfred } 1920184610Salfred error = ustorage_fs_check_cmd(sc, 12, 1921190719Sthompsa (1UL << 1) | (0xfUL << 2) | (0xfUL << 6) | 1, 1); 1922184610Salfred if (error) { 1923184610Salfred break; 1924184610Salfred } 1925184610Salfred error = ustorage_fs_write(sc); 1926184610Salfred 1927184610Salfred break; 1928184610Salfred 1929184610Salfred /* 1930184610Salfred * Some mandatory commands that we recognize but don't 1931184610Salfred * implement. They don't mean much in this setting. 1932184610Salfred * It's left as an exercise for anyone interested to 1933184610Salfred * implement RESERVE and RELEASE in terms of Posix 1934184610Salfred * locks. 1935184610Salfred */ 1936184610Salfred case SC_FORMAT_UNIT: 1937184610Salfred case SC_RELEASE: 1938184610Salfred case SC_RESERVE: 1939184610Salfred case SC_SEND_DIAGNOSTIC: 1940184610Salfred /* Fallthrough */ 1941184610Salfred 1942184610Salfred default: 1943233774Shselasky error = ustorage_fs_min_len(sc, 0, -1U); 1944184610Salfred if (error) { 1945184610Salfred break; 1946184610Salfred } 1947184610Salfred error = ustorage_fs_check_cmd(sc, sc->sc_transfer.cmd_len, 1948184610Salfred 0xff, 0); 1949184610Salfred if (error) { 1950184610Salfred break; 1951184610Salfred } 1952184610Salfred sc->sc_transfer.currlun->sense_data = 1953184610Salfred SS_INVALID_COMMAND; 1954184610Salfred error = 1; 1955184610Salfred 1956184610Salfred break; 1957184610Salfred } 1958184610Salfred return (error); 1959184610Salfred} 1960