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 39194677Sthompsa#include <sys/stdint.h> 40194677Sthompsa#include <sys/stddef.h> 41194677Sthompsa#include <sys/param.h> 42194677Sthompsa#include <sys/queue.h> 43194677Sthompsa#include <sys/types.h> 44194677Sthompsa#include <sys/systm.h> 45194677Sthompsa#include <sys/kernel.h> 46194677Sthompsa#include <sys/bus.h> 47194677Sthompsa#include <sys/module.h> 48194677Sthompsa#include <sys/lock.h> 49194677Sthompsa#include <sys/mutex.h> 50194677Sthompsa#include <sys/condvar.h> 51194677Sthompsa#include <sys/sysctl.h> 52194677Sthompsa#include <sys/sx.h> 53194677Sthompsa#include <sys/unistd.h> 54194677Sthompsa#include <sys/callout.h> 55194677Sthompsa#include <sys/malloc.h> 56194677Sthompsa#include <sys/priv.h> 57194677Sthompsa 58194677Sthompsa#include <dev/usb/usb.h> 59194677Sthompsa#include <dev/usb/usbdi.h> 60188746Sthompsa#include "usbdevs.h" 61194677Sthompsa#include "usb_if.h" 62184610Salfred 63184610Salfred#define USB_DEBUG_VAR ustorage_fs_debug 64188942Sthompsa#include <dev/usb/usb_debug.h> 65184610Salfred 66207077Sthompsa#ifdef USB_DEBUG 67184610Salfredstatic int ustorage_fs_debug = 0; 68184610Salfred 69192502SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, ustorage_fs, CTLFLAG_RW, 0, "USB ustorage_fs"); 70192502SthompsaSYSCTL_INT(_hw_usb_ustorage_fs, OID_AUTO, debug, CTLFLAG_RW, 71184610Salfred &ustorage_fs_debug, 0, "ustorage_fs debug level"); 72184610Salfred#endif 73184610Salfred 74184610Salfred/* Define some limits */ 75184610Salfred 76190181Sthompsa#ifndef USTORAGE_FS_BULK_SIZE 77259454Shselasky#define USTORAGE_FS_BULK_SIZE (1U << 17) /* bytes */ 78190181Sthompsa#endif 79184610Salfred 80190733Sthompsa#ifndef USTORAGE_FS_MAX_LUN 81190733Sthompsa#define USTORAGE_FS_MAX_LUN 8 /* units */ 82190733Sthompsa#endif 83190181Sthompsa 84190733Sthompsa#ifndef USTORAGE_QDATA_MAX 85190733Sthompsa#define USTORAGE_QDATA_MAX 40 /* bytes */ 86190733Sthompsa#endif 87190733Sthompsa 88190173Sthompsa/* 89190173Sthompsa * The SCSI ID string must be exactly 28 characters long 90190173Sthompsa * exluding the terminating zero. 91190173Sthompsa */ 92190173Sthompsa#ifndef USTORAGE_FS_ID_STRING 93190173Sthompsa#define USTORAGE_FS_ID_STRING \ 94190173Sthompsa "FreeBSD " /* 8 */ \ 95190173Sthompsa "File-Stor Gadget" /* 16 */ \ 96190173Sthompsa "0101" /* 4 */ 97190173Sthompsa#endif 98190173Sthompsa 99190173Sthompsa/* 100190173Sthompsa * The following macro defines the number of 101190173Sthompsa * sectors to be allocated for the RAM disk: 102190173Sthompsa */ 103190173Sthompsa#ifndef USTORAGE_FS_RAM_SECT 104190173Sthompsa#define USTORAGE_FS_RAM_SECT (1UL << 13) 105190173Sthompsa#endif 106190173Sthompsa 107184610Salfredstatic uint8_t *ustorage_fs_ramdisk; 108184610Salfred 109184610Salfred/* USB transfer definitions */ 110184610Salfred 111184610Salfred#define USTORAGE_FS_T_BBB_COMMAND 0 112184610Salfred#define USTORAGE_FS_T_BBB_DATA_DUMP 1 113184610Salfred#define USTORAGE_FS_T_BBB_DATA_READ 2 114184610Salfred#define USTORAGE_FS_T_BBB_DATA_WRITE 3 115184610Salfred#define USTORAGE_FS_T_BBB_STATUS 4 116184610Salfred#define USTORAGE_FS_T_BBB_MAX 5 117184610Salfred 118184610Salfred/* USB data stage direction */ 119184610Salfred 120184610Salfred#define DIR_NONE 0 121184610Salfred#define DIR_READ 1 122184610Salfred#define DIR_WRITE 2 123184610Salfred 124184610Salfred/* USB interface specific control request */ 125184610Salfred 126184610Salfred#define UR_BBB_RESET 0xff /* Bulk-Only reset */ 127184610Salfred#define UR_BBB_GET_MAX_LUN 0xfe /* Get maximum lun */ 128184610Salfred 129184610Salfred/* Command Block Wrapper */ 130184610Salfredtypedef struct { 131184610Salfred uDWord dCBWSignature; 132184610Salfred#define CBWSIGNATURE 0x43425355 133184610Salfred uDWord dCBWTag; 134184610Salfred uDWord dCBWDataTransferLength; 135184610Salfred uByte bCBWFlags; 136184610Salfred#define CBWFLAGS_OUT 0x00 137184610Salfred#define CBWFLAGS_IN 0x80 138184610Salfred uByte bCBWLUN; 139184610Salfred uByte bCDBLength; 140184610Salfred#define CBWCDBLENGTH 16 141184610Salfred uByte CBWCDB[CBWCDBLENGTH]; 142184610Salfred} __packed ustorage_fs_bbb_cbw_t; 143184610Salfred 144184610Salfred#define USTORAGE_FS_BBB_CBW_SIZE 31 145184610Salfred 146184610Salfred/* Command Status Wrapper */ 147184610Salfredtypedef struct { 148184610Salfred uDWord dCSWSignature; 149184610Salfred#define CSWSIGNATURE 0x53425355 150184610Salfred uDWord dCSWTag; 151184610Salfred uDWord dCSWDataResidue; 152184610Salfred uByte bCSWStatus; 153184610Salfred#define CSWSTATUS_GOOD 0x0 154184610Salfred#define CSWSTATUS_FAILED 0x1 155184610Salfred#define CSWSTATUS_PHASE 0x2 156184610Salfred} __packed ustorage_fs_bbb_csw_t; 157184610Salfred 158184610Salfred#define USTORAGE_FS_BBB_CSW_SIZE 13 159184610Salfred 160184610Salfredstruct ustorage_fs_lun { 161184610Salfred 162190181Sthompsa uint8_t *memory_image; 163184610Salfred 164184610Salfred uint32_t num_sectors; 165184610Salfred uint32_t sense_data; 166184610Salfred uint32_t sense_data_info; 167184610Salfred uint32_t unit_attention_data; 168184610Salfred 169184610Salfred uint8_t read_only:1; 170184610Salfred uint8_t prevent_medium_removal:1; 171184610Salfred uint8_t info_valid:1; 172184610Salfred uint8_t removable:1; 173184610Salfred}; 174184610Salfred 175184610Salfredstruct ustorage_fs_softc { 176184610Salfred 177259454Shselasky ustorage_fs_bbb_cbw_t *sc_cbw; /* Command Wrapper Block */ 178259454Shselasky ustorage_fs_bbb_csw_t *sc_csw; /* Command Status Block */ 179259454Shselasky void *sc_dma_ptr; /* Main data buffer */ 180184610Salfred 181184610Salfred struct mtx sc_mtx; 182184610Salfred 183184610Salfred struct ustorage_fs_lun sc_lun[USTORAGE_FS_MAX_LUN]; 184184610Salfred 185184610Salfred struct { 186184610Salfred uint8_t *data_ptr; 187184610Salfred struct ustorage_fs_lun *currlun; 188184610Salfred 189184610Salfred uint32_t data_rem; /* bytes, as reported by the command 190184610Salfred * block wrapper */ 191184610Salfred uint32_t offset; /* bytes */ 192184610Salfred 193184610Salfred uint8_t cbw_dir; 194184610Salfred uint8_t cmd_dir; 195184610Salfred uint8_t lun; 196184610Salfred uint8_t cmd_len; 197184610Salfred uint8_t data_short:1; 198184610Salfred uint8_t data_error:1; 199184610Salfred } sc_transfer; 200184610Salfred 201184610Salfred device_t sc_dev; 202192984Sthompsa struct usb_device *sc_udev; 203192984Sthompsa struct usb_xfer *sc_xfer[USTORAGE_FS_T_BBB_MAX]; 204184610Salfred 205184610Salfred uint8_t sc_iface_no; /* interface number */ 206184610Salfred uint8_t sc_last_lun; 207184610Salfred uint8_t sc_last_xfer_index; 208190733Sthompsa uint8_t sc_qdata[USTORAGE_QDATA_MAX]; 209184610Salfred}; 210184610Salfred 211184610Salfred/* prototypes */ 212184610Salfred 213184610Salfredstatic device_probe_t ustorage_fs_probe; 214184610Salfredstatic device_attach_t ustorage_fs_attach; 215184610Salfredstatic device_detach_t ustorage_fs_detach; 216184610Salfredstatic device_suspend_t ustorage_fs_suspend; 217184610Salfredstatic device_resume_t ustorage_fs_resume; 218188942Sthompsastatic usb_handle_request_t ustorage_fs_handle_request; 219184610Salfred 220193045Sthompsastatic usb_callback_t ustorage_fs_t_bbb_command_callback; 221193045Sthompsastatic usb_callback_t ustorage_fs_t_bbb_data_dump_callback; 222193045Sthompsastatic usb_callback_t ustorage_fs_t_bbb_data_read_callback; 223193045Sthompsastatic usb_callback_t ustorage_fs_t_bbb_data_write_callback; 224193045Sthompsastatic usb_callback_t ustorage_fs_t_bbb_status_callback; 225184610Salfred 226184610Salfredstatic void ustorage_fs_transfer_start(struct ustorage_fs_softc *sc, uint8_t xfer_index); 227184610Salfredstatic void ustorage_fs_transfer_stop(struct ustorage_fs_softc *sc); 228184610Salfred 229184610Salfredstatic uint8_t ustorage_fs_verify(struct ustorage_fs_softc *sc); 230184610Salfredstatic uint8_t ustorage_fs_inquiry(struct ustorage_fs_softc *sc); 231184610Salfredstatic uint8_t ustorage_fs_request_sense(struct ustorage_fs_softc *sc); 232184610Salfredstatic uint8_t ustorage_fs_read_capacity(struct ustorage_fs_softc *sc); 233184610Salfredstatic uint8_t ustorage_fs_mode_sense(struct ustorage_fs_softc *sc); 234184610Salfredstatic uint8_t ustorage_fs_start_stop(struct ustorage_fs_softc *sc); 235184610Salfredstatic uint8_t ustorage_fs_prevent_allow(struct ustorage_fs_softc *sc); 236184610Salfredstatic uint8_t ustorage_fs_read_format_capacities(struct ustorage_fs_softc *sc); 237184610Salfredstatic uint8_t ustorage_fs_mode_select(struct ustorage_fs_softc *sc); 238184610Salfredstatic uint8_t ustorage_fs_min_len(struct ustorage_fs_softc *sc, uint32_t len, uint32_t mask); 239184610Salfredstatic uint8_t ustorage_fs_read(struct ustorage_fs_softc *sc); 240184610Salfredstatic uint8_t ustorage_fs_write(struct ustorage_fs_softc *sc); 241184610Salfredstatic uint8_t ustorage_fs_check_cmd(struct ustorage_fs_softc *sc, uint8_t cmd_size, uint16_t mask, uint8_t needs_medium); 242184610Salfredstatic uint8_t ustorage_fs_do_cmd(struct ustorage_fs_softc *sc); 243184610Salfred 244184610Salfredstatic device_method_t ustorage_fs_methods[] = { 245184610Salfred /* USB interface */ 246188942Sthompsa DEVMETHOD(usb_handle_request, ustorage_fs_handle_request), 247184610Salfred 248184610Salfred /* Device interface */ 249184610Salfred DEVMETHOD(device_probe, ustorage_fs_probe), 250184610Salfred DEVMETHOD(device_attach, ustorage_fs_attach), 251184610Salfred DEVMETHOD(device_detach, ustorage_fs_detach), 252184610Salfred DEVMETHOD(device_suspend, ustorage_fs_suspend), 253184610Salfred DEVMETHOD(device_resume, ustorage_fs_resume), 254184610Salfred 255184610Salfred {0, 0} 256184610Salfred}; 257184610Salfred 258184610Salfredstatic driver_t ustorage_fs_driver = { 259184610Salfred .name = "ustorage_fs", 260184610Salfred .methods = ustorage_fs_methods, 261184610Salfred .size = sizeof(struct ustorage_fs_softc), 262184610Salfred}; 263184610Salfred 264184610Salfredstatic devclass_t ustorage_fs_devclass; 265184610Salfred 266189275SthompsaDRIVER_MODULE(ustorage_fs, uhub, ustorage_fs_driver, ustorage_fs_devclass, NULL, 0); 267184610SalfredMODULE_VERSION(ustorage_fs, 0); 268188942SthompsaMODULE_DEPEND(ustorage_fs, usb, 1, 1, 1); 269184610Salfred 270194099Sthompsastatic struct usb_config ustorage_fs_bbb_config[USTORAGE_FS_T_BBB_MAX] = { 271184610Salfred 272184610Salfred [USTORAGE_FS_T_BBB_COMMAND] = { 273184610Salfred .type = UE_BULK, 274184610Salfred .endpoint = UE_ADDR_ANY, 275184610Salfred .direction = UE_DIR_OUT, 276190733Sthompsa .bufsize = sizeof(ustorage_fs_bbb_cbw_t), 277190733Sthompsa .callback = &ustorage_fs_t_bbb_command_callback, 278190733Sthompsa .usb_mode = USB_MODE_DEVICE, 279184610Salfred }, 280184610Salfred 281184610Salfred [USTORAGE_FS_T_BBB_DATA_DUMP] = { 282184610Salfred .type = UE_BULK, 283184610Salfred .endpoint = UE_ADDR_ANY, 284184610Salfred .direction = UE_DIR_OUT, 285190733Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 286190733Sthompsa .flags = {.proxy_buffer = 1,.short_xfer_ok = 1,}, 287190733Sthompsa .callback = &ustorage_fs_t_bbb_data_dump_callback, 288190733Sthompsa .usb_mode = USB_MODE_DEVICE, 289184610Salfred }, 290184610Salfred 291184610Salfred [USTORAGE_FS_T_BBB_DATA_READ] = { 292184610Salfred .type = UE_BULK, 293184610Salfred .endpoint = UE_ADDR_ANY, 294184610Salfred .direction = UE_DIR_OUT, 295190733Sthompsa .bufsize = USTORAGE_FS_BULK_SIZE, 296259454Shselasky .flags = {.proxy_buffer = 1,.short_xfer_ok = 1}, 297190733Sthompsa .callback = &ustorage_fs_t_bbb_data_read_callback, 298190733Sthompsa .usb_mode = USB_MODE_DEVICE, 299184610Salfred }, 300184610Salfred 301184610Salfred [USTORAGE_FS_T_BBB_DATA_WRITE] = { 302184610Salfred .type = UE_BULK, 303184610Salfred .endpoint = UE_ADDR_ANY, 304184610Salfred .direction = UE_DIR_IN, 305190733Sthompsa .bufsize = USTORAGE_FS_BULK_SIZE, 306190733Sthompsa .flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer = 1}, 307190733Sthompsa .callback = &ustorage_fs_t_bbb_data_write_callback, 308190733Sthompsa .usb_mode = USB_MODE_DEVICE, 309184610Salfred }, 310184610Salfred 311184610Salfred [USTORAGE_FS_T_BBB_STATUS] = { 312184610Salfred .type = UE_BULK, 313184610Salfred .endpoint = UE_ADDR_ANY, 314184610Salfred .direction = UE_DIR_IN, 315190733Sthompsa .bufsize = sizeof(ustorage_fs_bbb_csw_t), 316259454Shselasky .flags = {.short_xfer_ok = 1}, 317190733Sthompsa .callback = &ustorage_fs_t_bbb_status_callback, 318190733Sthompsa .usb_mode = USB_MODE_DEVICE, 319184610Salfred }, 320184610Salfred}; 321184610Salfred 322184610Salfred/* 323184610Salfred * USB device probe/attach/detach 324184610Salfred */ 325184610Salfred 326184610Salfredstatic int 327184610Salfredustorage_fs_probe(device_t dev) 328184610Salfred{ 329192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 330192984Sthompsa struct usb_interface_descriptor *id; 331184610Salfred 332192499Sthompsa if (uaa->usb_mode != USB_MODE_DEVICE) { 333184610Salfred return (ENXIO); 334184610Salfred } 335184610Salfred /* Check for a standards compliant device */ 336194228Sthompsa id = usbd_get_interface_descriptor(uaa->iface); 337184610Salfred if ((id == NULL) || 338184610Salfred (id->bInterfaceClass != UICLASS_MASS) || 339184610Salfred (id->bInterfaceSubClass != UISUBCLASS_SCSI) || 340184610Salfred (id->bInterfaceProtocol != UIPROTO_MASS_BBB)) { 341184610Salfred return (ENXIO); 342184610Salfred } 343222051Savg return (BUS_PROBE_GENERIC); 344184610Salfred} 345184610Salfred 346184610Salfredstatic int 347184610Salfredustorage_fs_attach(device_t dev) 348184610Salfred{ 349184610Salfred struct ustorage_fs_softc *sc = device_get_softc(dev); 350192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 351192984Sthompsa struct usb_interface_descriptor *id; 352184610Salfred int err; 353190733Sthompsa int unit; 354184610Salfred 355184610Salfred /* 356229080Shselasky * NOTE: the softc struct is cleared in device_set_driver. 357184610Salfred * We can safely call ustorage_fs_detach without specifically 358184610Salfred * initializing the struct. 359184610Salfred */ 360184610Salfred 361184610Salfred sc->sc_dev = dev; 362184610Salfred sc->sc_udev = uaa->device; 363190733Sthompsa unit = device_get_unit(dev); 364184610Salfred 365229107Shselasky /* enable power saving mode */ 366229107Shselasky usbd_set_power_mode(uaa->device, USB_POWER_MODE_SAVE); 367229107Shselasky 368190733Sthompsa if (unit == 0) { 369184610Salfred if (ustorage_fs_ramdisk == NULL) { 370184610Salfred /* 371184610Salfred * allocate a memory image for our ramdisk until 372184610Salfred * further 373184610Salfred */ 374184610Salfred ustorage_fs_ramdisk = 375229080Shselasky malloc(USTORAGE_FS_RAM_SECT << 9, M_USB, 376229080Shselasky M_ZERO | M_WAITOK); 377229080Shselasky 378184610Salfred if (ustorage_fs_ramdisk == NULL) { 379184610Salfred return (ENOMEM); 380184610Salfred } 381184610Salfred } 382184610Salfred sc->sc_lun[0].memory_image = ustorage_fs_ramdisk; 383184610Salfred sc->sc_lun[0].num_sectors = USTORAGE_FS_RAM_SECT; 384184610Salfred sc->sc_lun[0].removable = 1; 385184610Salfred } 386184610Salfred 387194228Sthompsa device_set_usb_desc(dev); 388184610Salfred 389184610Salfred mtx_init(&sc->sc_mtx, "USTORAGE_FS lock", 390184610Salfred NULL, (MTX_DEF | MTX_RECURSE)); 391184610Salfred 392184610Salfred /* get interface index */ 393184610Salfred 394194228Sthompsa id = usbd_get_interface_descriptor(uaa->iface); 395184610Salfred if (id == NULL) { 396184610Salfred device_printf(dev, "failed to get " 397184610Salfred "interface number\n"); 398184610Salfred goto detach; 399184610Salfred } 400184610Salfred sc->sc_iface_no = id->bInterfaceNumber; 401184610Salfred 402194228Sthompsa err = usbd_transfer_setup(uaa->device, 403184610Salfred &uaa->info.bIfaceIndex, sc->sc_xfer, ustorage_fs_bbb_config, 404184610Salfred USTORAGE_FS_T_BBB_MAX, sc, &sc->sc_mtx); 405184610Salfred if (err) { 406184610Salfred device_printf(dev, "could not setup required " 407194228Sthompsa "transfers, %s\n", usbd_errstr(err)); 408184610Salfred goto detach; 409184610Salfred } 410259454Shselasky 411259454Shselasky sc->sc_cbw = usbd_xfer_get_frame_buffer(sc->sc_xfer[ 412259454Shselasky USTORAGE_FS_T_BBB_COMMAND], 0); 413259454Shselasky sc->sc_csw = usbd_xfer_get_frame_buffer(sc->sc_xfer[ 414259454Shselasky USTORAGE_FS_T_BBB_STATUS], 0); 415259454Shselasky sc->sc_dma_ptr = usbd_xfer_get_frame_buffer(sc->sc_xfer[ 416259454Shselasky USTORAGE_FS_T_BBB_DATA_READ], 0); 417259454Shselasky 418184610Salfred /* start Mass Storage State Machine */ 419184610Salfred 420184610Salfred mtx_lock(&sc->sc_mtx); 421184610Salfred ustorage_fs_transfer_start(sc, USTORAGE_FS_T_BBB_COMMAND); 422184610Salfred mtx_unlock(&sc->sc_mtx); 423184610Salfred 424184610Salfred return (0); /* success */ 425184610Salfred 426184610Salfreddetach: 427184610Salfred ustorage_fs_detach(dev); 428184610Salfred return (ENXIO); /* failure */ 429184610Salfred} 430184610Salfred 431184610Salfredstatic int 432184610Salfredustorage_fs_detach(device_t dev) 433184610Salfred{ 434184610Salfred struct ustorage_fs_softc *sc = device_get_softc(dev); 435184610Salfred 436184610Salfred /* teardown our statemachine */ 437184610Salfred 438194228Sthompsa usbd_transfer_unsetup(sc->sc_xfer, USTORAGE_FS_T_BBB_MAX); 439184610Salfred 440184610Salfred mtx_destroy(&sc->sc_mtx); 441184610Salfred 442184610Salfred return (0); /* success */ 443184610Salfred} 444184610Salfred 445184610Salfredstatic int 446184610Salfredustorage_fs_suspend(device_t dev) 447184610Salfred{ 448184610Salfred device_printf(dev, "suspending\n"); 449184610Salfred return (0); /* success */ 450184610Salfred} 451184610Salfred 452184610Salfredstatic int 453184610Salfredustorage_fs_resume(device_t dev) 454184610Salfred{ 455184610Salfred device_printf(dev, "resuming\n"); 456184610Salfred return (0); /* success */ 457184610Salfred} 458184610Salfred 459184610Salfred/* 460184610Salfred * Generic functions to handle transfers 461184610Salfred */ 462184610Salfred 463184610Salfredstatic void 464184610Salfredustorage_fs_transfer_start(struct ustorage_fs_softc *sc, uint8_t xfer_index) 465184610Salfred{ 466184610Salfred if (sc->sc_xfer[xfer_index]) { 467184610Salfred sc->sc_last_xfer_index = xfer_index; 468194228Sthompsa usbd_transfer_start(sc->sc_xfer[xfer_index]); 469184610Salfred } 470184610Salfred} 471184610Salfred 472184610Salfredstatic void 473184610Salfredustorage_fs_transfer_stop(struct ustorage_fs_softc *sc) 474184610Salfred{ 475194228Sthompsa usbd_transfer_stop(sc->sc_xfer[sc->sc_last_xfer_index]); 476184610Salfred mtx_unlock(&sc->sc_mtx); 477194228Sthompsa usbd_transfer_drain(sc->sc_xfer[sc->sc_last_xfer_index]); 478184610Salfred mtx_lock(&sc->sc_mtx); 479184610Salfred} 480184610Salfred 481184610Salfredstatic int 482184610Salfredustorage_fs_handle_request(device_t dev, 483184610Salfred const void *preq, void **pptr, uint16_t *plen, 484195121Sthompsa uint16_t offset, uint8_t *pstate) 485184610Salfred{ 486184610Salfred struct ustorage_fs_softc *sc = device_get_softc(dev); 487192984Sthompsa const struct usb_device_request *req = preq; 488195121Sthompsa uint8_t is_complete = *pstate; 489184610Salfred 490184610Salfred if (!is_complete) { 491192057Sthompsa if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) && 492192057Sthompsa (req->bRequest == UR_BBB_RESET)) { 493184610Salfred *plen = 0; 494184610Salfred mtx_lock(&sc->sc_mtx); 495184610Salfred ustorage_fs_transfer_stop(sc); 496184610Salfred sc->sc_transfer.data_error = 1; 497184610Salfred ustorage_fs_transfer_start(sc, 498184610Salfred USTORAGE_FS_T_BBB_COMMAND); 499184610Salfred mtx_unlock(&sc->sc_mtx); 500184610Salfred return (0); 501192057Sthompsa } else if ((req->bmRequestType == UT_READ_CLASS_INTERFACE) && 502192057Sthompsa (req->bRequest == UR_BBB_GET_MAX_LUN)) { 503184610Salfred if (offset == 0) { 504184610Salfred *plen = 1; 505184610Salfred *pptr = &sc->sc_last_lun; 506184610Salfred } else { 507184610Salfred *plen = 0; 508184610Salfred } 509184610Salfred return (0); 510184610Salfred } 511184610Salfred } 512184610Salfred return (ENXIO); /* use builtin handler */ 513184610Salfred} 514184610Salfred 515184610Salfredstatic void 516194677Sthompsaustorage_fs_t_bbb_command_callback(struct usb_xfer *xfer, usb_error_t error) 517184610Salfred{ 518194677Sthompsa struct ustorage_fs_softc *sc = usbd_xfer_softc(xfer); 519184610Salfred uint32_t tag; 520194677Sthompsa uint8_t err = 0; 521184610Salfred 522184610Salfred DPRINTF("\n"); 523184610Salfred 524184610Salfred switch (USB_GET_STATE(xfer)) { 525184610Salfred case USB_ST_TRANSFERRED: 526184610Salfred 527259454Shselasky tag = UGETDW(sc->sc_cbw->dCBWSignature); 528184610Salfred 529184610Salfred if (tag != CBWSIGNATURE) { 530184610Salfred /* do nothing */ 531184610Salfred DPRINTF("invalid signature 0x%08x\n", tag); 532184610Salfred break; 533184610Salfred } 534259454Shselasky tag = UGETDW(sc->sc_cbw->dCBWTag); 535184610Salfred 536184610Salfred /* echo back tag */ 537259454Shselasky USETDW(sc->sc_csw->dCSWTag, tag); 538184610Salfred 539184610Salfred /* reset status */ 540259454Shselasky sc->sc_csw->bCSWStatus = 0; 541184610Salfred 542184610Salfred /* reset data offset, data length and data remainder */ 543184610Salfred sc->sc_transfer.offset = 0; 544184610Salfred sc->sc_transfer.data_rem = 545259454Shselasky UGETDW(sc->sc_cbw->dCBWDataTransferLength); 546184610Salfred 547184610Salfred /* reset data flags */ 548184610Salfred sc->sc_transfer.data_short = 0; 549184610Salfred 550184610Salfred /* extract LUN */ 551259454Shselasky sc->sc_transfer.lun = sc->sc_cbw->bCBWLUN; 552184610Salfred 553184610Salfred if (sc->sc_transfer.data_rem == 0) { 554184610Salfred sc->sc_transfer.cbw_dir = DIR_NONE; 555184610Salfred } else { 556259454Shselasky if (sc->sc_cbw->bCBWFlags & CBWFLAGS_IN) { 557184610Salfred sc->sc_transfer.cbw_dir = DIR_WRITE; 558184610Salfred } else { 559184610Salfred sc->sc_transfer.cbw_dir = DIR_READ; 560184610Salfred } 561184610Salfred } 562184610Salfred 563259454Shselasky sc->sc_transfer.cmd_len = sc->sc_cbw->bCDBLength; 564259454Shselasky if ((sc->sc_transfer.cmd_len > sizeof(sc->sc_cbw->CBWCDB)) || 565184610Salfred (sc->sc_transfer.cmd_len == 0)) { 566184610Salfred /* just halt - this is invalid */ 567184610Salfred DPRINTF("invalid command length %d bytes\n", 568184610Salfred sc->sc_transfer.cmd_len); 569184610Salfred break; 570184610Salfred } 571184610Salfred 572194677Sthompsa err = ustorage_fs_do_cmd(sc); 573194677Sthompsa if (err) { 574184610Salfred /* got an error */ 575184610Salfred DPRINTF("command failed\n"); 576184610Salfred break; 577184610Salfred } 578184610Salfred if ((sc->sc_transfer.data_rem > 0) && 579184610Salfred (sc->sc_transfer.cbw_dir != sc->sc_transfer.cmd_dir)) { 580184610Salfred /* contradicting data transfer direction */ 581194677Sthompsa err = 1; 582184610Salfred DPRINTF("data direction mismatch\n"); 583184610Salfred break; 584184610Salfred } 585184610Salfred switch (sc->sc_transfer.cbw_dir) { 586184610Salfred case DIR_READ: 587184610Salfred ustorage_fs_transfer_start(sc, USTORAGE_FS_T_BBB_DATA_READ); 588184610Salfred break; 589184610Salfred case DIR_WRITE: 590184610Salfred ustorage_fs_transfer_start(sc, USTORAGE_FS_T_BBB_DATA_WRITE); 591184610Salfred break; 592184610Salfred default: 593184610Salfred ustorage_fs_transfer_start(sc, 594184610Salfred USTORAGE_FS_T_BBB_STATUS); 595184610Salfred break; 596184610Salfred } 597184610Salfred break; 598184610Salfred 599184610Salfred case USB_ST_SETUP: 600184610Salfredtr_setup: 601184610Salfred if (sc->sc_transfer.data_error) { 602184610Salfred sc->sc_transfer.data_error = 0; 603194677Sthompsa usbd_xfer_set_stall(xfer); 604184610Salfred DPRINTF("stall pipe\n"); 605184610Salfred } 606260575Shselasky usbd_xfer_set_frame_len(xfer, 0, 607260575Shselasky sizeof(ustorage_fs_bbb_cbw_t)); 608194228Sthompsa usbd_transfer_submit(xfer); 609184610Salfred break; 610184610Salfred 611184610Salfred default: /* Error */ 612184610Salfred DPRINTF("error\n"); 613194677Sthompsa if (error == USB_ERR_CANCELLED) { 614184610Salfred break; 615184610Salfred } 616184610Salfred /* If the pipe is already stalled, don't do another stall */ 617194677Sthompsa if (!usbd_xfer_is_stalled(xfer)) 618184610Salfred sc->sc_transfer.data_error = 1; 619194677Sthompsa 620184610Salfred /* try again */ 621184610Salfred goto tr_setup; 622184610Salfred } 623194677Sthompsa if (err) { 624259454Shselasky if (sc->sc_csw->bCSWStatus == 0) { 625184610Salfred /* set some default error code */ 626259454Shselasky sc->sc_csw->bCSWStatus = CSWSTATUS_FAILED; 627184610Salfred } 628184610Salfred if (sc->sc_transfer.cbw_dir == DIR_READ) { 629184610Salfred /* dump all data */ 630184610Salfred ustorage_fs_transfer_start(sc, 631184610Salfred USTORAGE_FS_T_BBB_DATA_DUMP); 632184610Salfred return; 633184610Salfred } 634184610Salfred if (sc->sc_transfer.cbw_dir == DIR_WRITE) { 635184610Salfred /* need to stall before status */ 636184610Salfred sc->sc_transfer.data_error = 1; 637184610Salfred } 638184610Salfred ustorage_fs_transfer_start(sc, USTORAGE_FS_T_BBB_STATUS); 639184610Salfred } 640184610Salfred} 641184610Salfred 642184610Salfredstatic void 643194677Sthompsaustorage_fs_t_bbb_data_dump_callback(struct usb_xfer *xfer, usb_error_t error) 644184610Salfred{ 645194677Sthompsa struct ustorage_fs_softc *sc = usbd_xfer_softc(xfer); 646194677Sthompsa uint32_t max_bulk = usbd_xfer_max_len(xfer); 647194677Sthompsa int actlen, sumlen; 648184610Salfred 649194677Sthompsa usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 650194677Sthompsa 651184610Salfred DPRINTF("\n"); 652184610Salfred 653184610Salfred switch (USB_GET_STATE(xfer)) { 654184610Salfred case USB_ST_TRANSFERRED: 655194677Sthompsa sc->sc_transfer.data_rem -= actlen; 656194677Sthompsa sc->sc_transfer.offset += actlen; 657184610Salfred 658194677Sthompsa if (actlen != sumlen || sc->sc_transfer.data_rem == 0) { 659184610Salfred /* short transfer or end of data */ 660184610Salfred ustorage_fs_transfer_start(sc, 661184610Salfred USTORAGE_FS_T_BBB_STATUS); 662184610Salfred break; 663184610Salfred } 664184610Salfred /* Fallthrough */ 665184610Salfred 666184610Salfred case USB_ST_SETUP: 667184610Salfredtr_setup: 668184610Salfred if (max_bulk > sc->sc_transfer.data_rem) { 669184610Salfred max_bulk = sc->sc_transfer.data_rem; 670184610Salfred } 671184610Salfred if (sc->sc_transfer.data_error) { 672184610Salfred sc->sc_transfer.data_error = 0; 673194677Sthompsa usbd_xfer_set_stall(xfer); 674184610Salfred } 675194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, max_bulk); 676194228Sthompsa usbd_transfer_submit(xfer); 677184610Salfred break; 678184610Salfred 679184610Salfred default: /* Error */ 680194677Sthompsa if (error == USB_ERR_CANCELLED) { 681184610Salfred break; 682184610Salfred } 683184610Salfred /* 684184610Salfred * If the pipe is already stalled, don't do another stall: 685184610Salfred */ 686194677Sthompsa if (!usbd_xfer_is_stalled(xfer)) 687184610Salfred sc->sc_transfer.data_error = 1; 688194677Sthompsa 689184610Salfred /* try again */ 690184610Salfred goto tr_setup; 691184610Salfred } 692184610Salfred} 693184610Salfred 694184610Salfredstatic void 695194677Sthompsaustorage_fs_t_bbb_data_read_callback(struct usb_xfer *xfer, usb_error_t error) 696184610Salfred{ 697194677Sthompsa struct ustorage_fs_softc *sc = usbd_xfer_softc(xfer); 698194677Sthompsa uint32_t max_bulk = usbd_xfer_max_len(xfer); 699194677Sthompsa int actlen, sumlen; 700184610Salfred 701194677Sthompsa usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 702194677Sthompsa 703184610Salfred DPRINTF("\n"); 704184610Salfred 705184610Salfred switch (USB_GET_STATE(xfer)) { 706184610Salfred case USB_ST_TRANSFERRED: 707259454Shselasky /* XXX copy data from DMA buffer */ 708259454Shselasky memcpy(sc->sc_transfer.data_ptr, sc->sc_dma_ptr, actlen); 709259454Shselasky 710194677Sthompsa sc->sc_transfer.data_rem -= actlen; 711194677Sthompsa sc->sc_transfer.data_ptr += actlen; 712194677Sthompsa sc->sc_transfer.offset += actlen; 713184610Salfred 714194677Sthompsa if (actlen != sumlen || sc->sc_transfer.data_rem == 0) { 715184610Salfred /* short transfer or end of data */ 716184610Salfred ustorage_fs_transfer_start(sc, 717184610Salfred USTORAGE_FS_T_BBB_STATUS); 718184610Salfred break; 719184610Salfred } 720184610Salfred /* Fallthrough */ 721184610Salfred 722184610Salfred case USB_ST_SETUP: 723184610Salfredtr_setup: 724184610Salfred if (max_bulk > sc->sc_transfer.data_rem) { 725184610Salfred max_bulk = sc->sc_transfer.data_rem; 726184610Salfred } 727184610Salfred if (sc->sc_transfer.data_error) { 728184610Salfred sc->sc_transfer.data_error = 0; 729194677Sthompsa usbd_xfer_set_stall(xfer); 730184610Salfred } 731184610Salfred 732259454Shselasky usbd_xfer_set_frame_data(xfer, 0, sc->sc_dma_ptr, max_bulk); 733194228Sthompsa usbd_transfer_submit(xfer); 734184610Salfred break; 735184610Salfred 736184610Salfred default: /* Error */ 737194677Sthompsa if (error == USB_ERR_CANCELLED) { 738184610Salfred break; 739184610Salfred } 740184610Salfred /* If the pipe is already stalled, don't do another stall */ 741194677Sthompsa if (!usbd_xfer_is_stalled(xfer)) 742184610Salfred sc->sc_transfer.data_error = 1; 743194677Sthompsa 744184610Salfred /* try again */ 745184610Salfred goto tr_setup; 746184610Salfred } 747184610Salfred} 748184610Salfred 749184610Salfredstatic void 750194677Sthompsaustorage_fs_t_bbb_data_write_callback(struct usb_xfer *xfer, usb_error_t error) 751184610Salfred{ 752194677Sthompsa struct ustorage_fs_softc *sc = usbd_xfer_softc(xfer); 753194677Sthompsa uint32_t max_bulk = usbd_xfer_max_len(xfer); 754194677Sthompsa int actlen, sumlen; 755184610Salfred 756194677Sthompsa usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 757194677Sthompsa 758184610Salfred DPRINTF("\n"); 759184610Salfred 760184610Salfred switch (USB_GET_STATE(xfer)) { 761184610Salfred case USB_ST_TRANSFERRED: 762194677Sthompsa sc->sc_transfer.data_rem -= actlen; 763194677Sthompsa sc->sc_transfer.data_ptr += actlen; 764194677Sthompsa sc->sc_transfer.offset += actlen; 765184610Salfred 766194677Sthompsa if (actlen != sumlen || sc->sc_transfer.data_rem == 0) { 767184610Salfred /* short transfer or end of data */ 768184610Salfred ustorage_fs_transfer_start(sc, 769184610Salfred USTORAGE_FS_T_BBB_STATUS); 770184610Salfred break; 771184610Salfred } 772184610Salfred case USB_ST_SETUP: 773184610Salfredtr_setup: 774184610Salfred if (max_bulk >= sc->sc_transfer.data_rem) { 775184610Salfred max_bulk = sc->sc_transfer.data_rem; 776194677Sthompsa if (sc->sc_transfer.data_short) 777194677Sthompsa usbd_xfer_set_flag(xfer, USB_FORCE_SHORT_XFER); 778194677Sthompsa else 779194677Sthompsa usbd_xfer_clr_flag(xfer, USB_FORCE_SHORT_XFER); 780194677Sthompsa } else 781194677Sthompsa usbd_xfer_clr_flag(xfer, USB_FORCE_SHORT_XFER); 782184610Salfred 783184610Salfred if (sc->sc_transfer.data_error) { 784184610Salfred sc->sc_transfer.data_error = 0; 785194677Sthompsa usbd_xfer_set_stall(xfer); 786184610Salfred } 787184610Salfred 788259454Shselasky /* XXX copy data to DMA buffer */ 789259454Shselasky memcpy(sc->sc_dma_ptr, sc->sc_transfer.data_ptr, max_bulk); 790259454Shselasky 791259454Shselasky usbd_xfer_set_frame_data(xfer, 0, sc->sc_dma_ptr, max_bulk); 792194228Sthompsa usbd_transfer_submit(xfer); 793184610Salfred break; 794184610Salfred 795184610Salfred default: /* Error */ 796194677Sthompsa if (error == USB_ERR_CANCELLED) { 797184610Salfred break; 798184610Salfred } 799184610Salfred /* 800184610Salfred * If the pipe is already stalled, don't do another 801184610Salfred * stall 802184610Salfred */ 803194677Sthompsa if (!usbd_xfer_is_stalled(xfer)) 804184610Salfred sc->sc_transfer.data_error = 1; 805194677Sthompsa 806184610Salfred /* try again */ 807184610Salfred goto tr_setup; 808184610Salfred } 809184610Salfred} 810184610Salfred 811184610Salfredstatic void 812194677Sthompsaustorage_fs_t_bbb_status_callback(struct usb_xfer *xfer, usb_error_t error) 813184610Salfred{ 814194677Sthompsa struct ustorage_fs_softc *sc = usbd_xfer_softc(xfer); 815184610Salfred 816184610Salfred DPRINTF("\n"); 817184610Salfred 818184610Salfred switch (USB_GET_STATE(xfer)) { 819184610Salfred case USB_ST_TRANSFERRED: 820184610Salfred ustorage_fs_transfer_start(sc, USTORAGE_FS_T_BBB_COMMAND); 821184610Salfred break; 822184610Salfred 823184610Salfred case USB_ST_SETUP: 824184610Salfredtr_setup: 825259454Shselasky USETDW(sc->sc_csw->dCSWSignature, CSWSIGNATURE); 826259454Shselasky USETDW(sc->sc_csw->dCSWDataResidue, sc->sc_transfer.data_rem); 827184610Salfred 828184610Salfred if (sc->sc_transfer.data_error) { 829184610Salfred sc->sc_transfer.data_error = 0; 830194677Sthompsa usbd_xfer_set_stall(xfer); 831184610Salfred } 832260575Shselasky usbd_xfer_set_frame_len(xfer, 0, 833260575Shselasky sizeof(ustorage_fs_bbb_csw_t)); 834194228Sthompsa usbd_transfer_submit(xfer); 835184610Salfred break; 836184610Salfred 837184610Salfred default: 838194677Sthompsa if (error == USB_ERR_CANCELLED) { 839184610Salfred break; 840184610Salfred } 841184610Salfred /* If the pipe is already stalled, don't do another stall */ 842194677Sthompsa if (!usbd_xfer_is_stalled(xfer)) 843184610Salfred sc->sc_transfer.data_error = 1; 844194677Sthompsa 845184610Salfred /* try again */ 846184610Salfred goto tr_setup; 847184610Salfred } 848184610Salfred} 849184610Salfred 850184610Salfred/* SCSI commands that we recognize */ 851184610Salfred#define SC_FORMAT_UNIT 0x04 852184610Salfred#define SC_INQUIRY 0x12 853184610Salfred#define SC_MODE_SELECT_6 0x15 854184610Salfred#define SC_MODE_SELECT_10 0x55 855184610Salfred#define SC_MODE_SENSE_6 0x1a 856184610Salfred#define SC_MODE_SENSE_10 0x5a 857184610Salfred#define SC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e 858184610Salfred#define SC_READ_6 0x08 859184610Salfred#define SC_READ_10 0x28 860184610Salfred#define SC_READ_12 0xa8 861184610Salfred#define SC_READ_CAPACITY 0x25 862184610Salfred#define SC_READ_FORMAT_CAPACITIES 0x23 863184610Salfred#define SC_RELEASE 0x17 864184610Salfred#define SC_REQUEST_SENSE 0x03 865184610Salfred#define SC_RESERVE 0x16 866184610Salfred#define SC_SEND_DIAGNOSTIC 0x1d 867184610Salfred#define SC_START_STOP_UNIT 0x1b 868184610Salfred#define SC_SYNCHRONIZE_CACHE 0x35 869184610Salfred#define SC_TEST_UNIT_READY 0x00 870184610Salfred#define SC_VERIFY 0x2f 871184610Salfred#define SC_WRITE_6 0x0a 872184610Salfred#define SC_WRITE_10 0x2a 873184610Salfred#define SC_WRITE_12 0xaa 874184610Salfred 875184610Salfred/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */ 876184610Salfred#define SS_NO_SENSE 0 877184610Salfred#define SS_COMMUNICATION_FAILURE 0x040800 878184610Salfred#define SS_INVALID_COMMAND 0x052000 879184610Salfred#define SS_INVALID_FIELD_IN_CDB 0x052400 880184610Salfred#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100 881184610Salfred#define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500 882184610Salfred#define SS_MEDIUM_NOT_PRESENT 0x023a00 883184610Salfred#define SS_MEDIUM_REMOVAL_PREVENTED 0x055302 884184610Salfred#define SS_NOT_READY_TO_READY_TRANSITION 0x062800 885184610Salfred#define SS_RESET_OCCURRED 0x062900 886184610Salfred#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900 887184610Salfred#define SS_UNRECOVERED_READ_ERROR 0x031100 888184610Salfred#define SS_WRITE_ERROR 0x030c02 889184610Salfred#define SS_WRITE_PROTECTED 0x072700 890184610Salfred 891184610Salfred#define SK(x) ((uint8_t) ((x) >> 16)) /* Sense Key byte, etc. */ 892184610Salfred#define ASC(x) ((uint8_t) ((x) >> 8)) 893184610Salfred#define ASCQ(x) ((uint8_t) (x)) 894184610Salfred 895184610Salfred/* Routines for unaligned data access */ 896184610Salfred 897184610Salfredstatic uint16_t 898184610Salfredget_be16(uint8_t *buf) 899184610Salfred{ 900184610Salfred return ((uint16_t)buf[0] << 8) | ((uint16_t)buf[1]); 901184610Salfred} 902184610Salfred 903184610Salfredstatic uint32_t 904184610Salfredget_be32(uint8_t *buf) 905184610Salfred{ 906184610Salfred return ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16) | 907184610Salfred ((uint32_t)buf[2] << 8) | ((uint32_t)buf[3]); 908184610Salfred} 909184610Salfred 910184610Salfredstatic void 911184610Salfredput_be16(uint8_t *buf, uint16_t val) 912184610Salfred{ 913184610Salfred buf[0] = val >> 8; 914184610Salfred buf[1] = val; 915184610Salfred} 916184610Salfred 917184610Salfredstatic void 918184610Salfredput_be32(uint8_t *buf, uint32_t val) 919184610Salfred{ 920184610Salfred buf[0] = val >> 24; 921184610Salfred buf[1] = val >> 16; 922184610Salfred buf[2] = val >> 8; 923184610Salfred buf[3] = val & 0xff; 924184610Salfred} 925184610Salfred 926184610Salfred/*------------------------------------------------------------------------* 927184610Salfred * ustorage_fs_verify 928184610Salfred * 929184610Salfred * Returns: 930184610Salfred * 0: Success 931184610Salfred * Else: Failure 932184610Salfred *------------------------------------------------------------------------*/ 933184610Salfredstatic uint8_t 934184610Salfredustorage_fs_verify(struct ustorage_fs_softc *sc) 935184610Salfred{ 936184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 937184610Salfred uint32_t lba; 938184610Salfred uint32_t vlen; 939184610Salfred uint64_t file_offset; 940184610Salfred uint64_t amount_left; 941184610Salfred 942184610Salfred /* 943184610Salfred * Get the starting Logical Block Address 944184610Salfred */ 945259454Shselasky lba = get_be32(&sc->sc_cbw->CBWCDB[2]); 946184610Salfred 947184610Salfred /* 948184610Salfred * We allow DPO (Disable Page Out = don't save data in the cache) 949184610Salfred * but we don't implement it. 950184610Salfred */ 951259454Shselasky if ((sc->sc_cbw->CBWCDB[1] & ~0x10) != 0) { 952184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 953184610Salfred return (1); 954184610Salfred } 955259454Shselasky vlen = get_be16(&sc->sc_cbw->CBWCDB[7]); 956184610Salfred if (vlen == 0) { 957184610Salfred goto done; 958184610Salfred } 959184610Salfred /* No default reply */ 960184610Salfred 961184610Salfred /* Prepare to carry out the file verify */ 962184610Salfred amount_left = vlen; 963184610Salfred amount_left <<= 9; 964184610Salfred file_offset = lba; 965184610Salfred file_offset <<= 9; 966184610Salfred 967184610Salfred /* Range check */ 968184610Salfred vlen += lba; 969184610Salfred 970184610Salfred if ((vlen < lba) || 971184610Salfred (vlen > currlun->num_sectors) || 972184610Salfred (lba >= currlun->num_sectors)) { 973184610Salfred currlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 974184610Salfred return (1); 975184610Salfred } 976184610Salfred /* XXX TODO: verify that data is readable */ 977184610Salfreddone: 978235000Shselasky return (ustorage_fs_min_len(sc, 0, -1U)); 979184610Salfred} 980184610Salfred 981184610Salfred/*------------------------------------------------------------------------* 982184610Salfred * ustorage_fs_inquiry 983184610Salfred * 984184610Salfred * Returns: 985184610Salfred * 0: Success 986184610Salfred * Else: Failure 987184610Salfred *------------------------------------------------------------------------*/ 988184610Salfredstatic uint8_t 989184610Salfredustorage_fs_inquiry(struct ustorage_fs_softc *sc) 990184610Salfred{ 991184610Salfred uint8_t *buf = sc->sc_transfer.data_ptr; 992184610Salfred 993184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 994184610Salfred 995184610Salfred if (!sc->sc_transfer.currlun) { 996184610Salfred /* Unsupported LUNs are okay */ 997184610Salfred memset(buf, 0, 36); 998184610Salfred buf[0] = 0x7f; 999184610Salfred /* Unsupported, no device - type */ 1000235000Shselasky return (ustorage_fs_min_len(sc, 36, -1U)); 1001184610Salfred } 1002184610Salfred memset(buf, 0, 8); 1003184610Salfred /* Non - removable, direct - access device */ 1004184610Salfred if (currlun->removable) 1005184610Salfred buf[1] = 0x80; 1006184610Salfred buf[2] = 2; 1007184610Salfred /* ANSI SCSI level 2 */ 1008184610Salfred buf[3] = 2; 1009184610Salfred /* SCSI - 2 INQUIRY data format */ 1010184610Salfred buf[4] = 31; 1011184610Salfred /* Additional length */ 1012184610Salfred /* No special options */ 1013190719Sthompsa /* Copy in ID string */ 1014190719Sthompsa memcpy(buf + 8, USTORAGE_FS_ID_STRING, 28); 1015190719Sthompsa 1016190733Sthompsa#if (USTORAGE_QDATA_MAX < 36) 1017190733Sthompsa#error "(USTORAGE_QDATA_MAX < 36)" 1018190733Sthompsa#endif 1019235000Shselasky return (ustorage_fs_min_len(sc, 36, -1U)); 1020184610Salfred} 1021184610Salfred 1022184610Salfred/*------------------------------------------------------------------------* 1023184610Salfred * ustorage_fs_request_sense 1024184610Salfred * 1025184610Salfred * Returns: 1026184610Salfred * 0: Success 1027184610Salfred * Else: Failure 1028184610Salfred *------------------------------------------------------------------------*/ 1029184610Salfredstatic uint8_t 1030184610Salfredustorage_fs_request_sense(struct ustorage_fs_softc *sc) 1031184610Salfred{ 1032184610Salfred uint8_t *buf = sc->sc_transfer.data_ptr; 1033184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1034184610Salfred uint32_t sd; 1035184610Salfred uint32_t sdinfo; 1036184610Salfred uint8_t valid; 1037184610Salfred 1038184610Salfred /* 1039184610Salfred * From the SCSI-2 spec., section 7.9 (Unit attention condition): 1040184610Salfred * 1041184610Salfred * If a REQUEST SENSE command is received from an initiator 1042184610Salfred * with a pending unit attention condition (before the target 1043184610Salfred * generates the contingent allegiance condition), then the 1044184610Salfred * target shall either: 1045184610Salfred * a) report any pending sense data and preserve the unit 1046184610Salfred * attention condition on the logical unit, or, 1047184610Salfred * b) report the unit attention condition, may discard any 1048184610Salfred * pending sense data, and clear the unit attention 1049184610Salfred * condition on the logical unit for that initiator. 1050184610Salfred * 1051184610Salfred * FSG normally uses option a); enable this code to use option b). 1052184610Salfred */ 1053184610Salfred#if 0 1054184610Salfred if (currlun && currlun->unit_attention_data != SS_NO_SENSE) { 1055184610Salfred currlun->sense_data = currlun->unit_attention_data; 1056184610Salfred currlun->unit_attention_data = SS_NO_SENSE; 1057184610Salfred } 1058184610Salfred#endif 1059184610Salfred 1060184610Salfred if (!currlun) { 1061184610Salfred /* Unsupported LUNs are okay */ 1062184610Salfred sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; 1063184610Salfred sdinfo = 0; 1064184610Salfred valid = 0; 1065184610Salfred } else { 1066184610Salfred sd = currlun->sense_data; 1067184610Salfred sdinfo = currlun->sense_data_info; 1068184610Salfred valid = currlun->info_valid << 7; 1069184610Salfred currlun->sense_data = SS_NO_SENSE; 1070184610Salfred currlun->sense_data_info = 0; 1071184610Salfred currlun->info_valid = 0; 1072184610Salfred } 1073184610Salfred 1074184610Salfred memset(buf, 0, 18); 1075184610Salfred buf[0] = valid | 0x70; 1076184610Salfred /* Valid, current error */ 1077184610Salfred buf[2] = SK(sd); 1078184610Salfred put_be32(&buf[3], sdinfo); 1079184610Salfred /* Sense information */ 1080184610Salfred buf[7] = 18 - 8; 1081184610Salfred /* Additional sense length */ 1082184610Salfred buf[12] = ASC(sd); 1083184610Salfred buf[13] = ASCQ(sd); 1084190733Sthompsa 1085190733Sthompsa#if (USTORAGE_QDATA_MAX < 18) 1086190733Sthompsa#error "(USTORAGE_QDATA_MAX < 18)" 1087190733Sthompsa#endif 1088235000Shselasky return (ustorage_fs_min_len(sc, 18, -1U)); 1089184610Salfred} 1090184610Salfred 1091184610Salfred/*------------------------------------------------------------------------* 1092184610Salfred * ustorage_fs_read_capacity 1093184610Salfred * 1094184610Salfred * Returns: 1095184610Salfred * 0: Success 1096184610Salfred * Else: Failure 1097184610Salfred *------------------------------------------------------------------------*/ 1098184610Salfredstatic uint8_t 1099184610Salfredustorage_fs_read_capacity(struct ustorage_fs_softc *sc) 1100184610Salfred{ 1101184610Salfred uint8_t *buf = sc->sc_transfer.data_ptr; 1102184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1103259454Shselasky uint32_t lba = get_be32(&sc->sc_cbw->CBWCDB[2]); 1104259454Shselasky uint8_t pmi = sc->sc_cbw->CBWCDB[8]; 1105184610Salfred 1106184610Salfred /* Check the PMI and LBA fields */ 1107184610Salfred if ((pmi > 1) || ((pmi == 0) && (lba != 0))) { 1108184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 1109184610Salfred return (1); 1110184610Salfred } 1111190733Sthompsa /* Max logical block */ 1112184610Salfred put_be32(&buf[0], currlun->num_sectors - 1); 1113190733Sthompsa /* Block length */ 1114184610Salfred put_be32(&buf[4], 512); 1115190733Sthompsa 1116190733Sthompsa#if (USTORAGE_QDATA_MAX < 8) 1117190733Sthompsa#error "(USTORAGE_QDATA_MAX < 8)" 1118190733Sthompsa#endif 1119235000Shselasky return (ustorage_fs_min_len(sc, 8, -1U)); 1120184610Salfred} 1121184610Salfred 1122184610Salfred/*------------------------------------------------------------------------* 1123184610Salfred * ustorage_fs_mode_sense 1124184610Salfred * 1125184610Salfred * Returns: 1126184610Salfred * 0: Success 1127184610Salfred * Else: Failure 1128184610Salfred *------------------------------------------------------------------------*/ 1129184610Salfredstatic uint8_t 1130184610Salfredustorage_fs_mode_sense(struct ustorage_fs_softc *sc) 1131184610Salfred{ 1132184610Salfred uint8_t *buf = sc->sc_transfer.data_ptr; 1133184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1134184610Salfred uint8_t *buf0; 1135184610Salfred uint16_t len; 1136184610Salfred uint16_t limit; 1137259454Shselasky uint8_t mscmnd = sc->sc_cbw->CBWCDB[0]; 1138184610Salfred uint8_t pc; 1139184610Salfred uint8_t page_code; 1140184610Salfred uint8_t changeable_values; 1141184610Salfred uint8_t all_pages; 1142184610Salfred 1143184610Salfred buf0 = buf; 1144184610Salfred 1145259454Shselasky if ((sc->sc_cbw->CBWCDB[1] & ~0x08) != 0) { 1146184610Salfred /* Mask away DBD */ 1147184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 1148184610Salfred return (1); 1149184610Salfred } 1150259454Shselasky pc = sc->sc_cbw->CBWCDB[2] >> 6; 1151259454Shselasky page_code = sc->sc_cbw->CBWCDB[2] & 0x3f; 1152184610Salfred if (pc == 3) { 1153184610Salfred currlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; 1154184610Salfred return (1); 1155184610Salfred } 1156184610Salfred changeable_values = (pc == 1); 1157184610Salfred all_pages = (page_code == 0x3f); 1158184610Salfred 1159184610Salfred /* 1160184610Salfred * Write the mode parameter header. Fixed values are: default 1161184610Salfred * medium type, no cache control (DPOFUA), and no block descriptors. 1162184610Salfred * The only variable value is the WriteProtect bit. We will fill in 1163184610Salfred * the mode data length later. 1164184610Salfred */ 1165184610Salfred memset(buf, 0, 8); 1166184610Salfred if (mscmnd == SC_MODE_SENSE_6) { 1167184610Salfred buf[2] = (currlun->read_only ? 0x80 : 0x00); 1168184610Salfred /* WP, DPOFUA */ 1169184610Salfred buf += 4; 1170184610Salfred limit = 255; 1171184610Salfred } else { 1172184610Salfred /* SC_MODE_SENSE_10 */ 1173184610Salfred buf[3] = (currlun->read_only ? 0x80 : 0x00); 1174184610Salfred /* WP, DPOFUA */ 1175184610Salfred buf += 8; 1176184610Salfred limit = 65535; 1177184610Salfred /* Should really be mod_data.buflen */ 1178184610Salfred } 1179184610Salfred 1180184610Salfred /* No block descriptors */ 1181184610Salfred 1182184610Salfred /* 1183184610Salfred * The mode pages, in numerical order. 1184184610Salfred */ 1185184610Salfred if ((page_code == 0x08) || all_pages) { 1186184610Salfred buf[0] = 0x08; 1187184610Salfred /* Page code */ 1188184610Salfred buf[1] = 10; 1189184610Salfred /* Page length */ 1190184610Salfred memset(buf + 2, 0, 10); 1191184610Salfred /* None of the fields are changeable */ 1192184610Salfred 1193184610Salfred if (!changeable_values) { 1194184610Salfred buf[2] = 0x04; 1195184610Salfred /* Write cache enable, */ 1196184610Salfred /* Read cache not disabled */ 1197184610Salfred /* No cache retention priorities */ 1198184610Salfred put_be16(&buf[4], 0xffff); 1199184610Salfred /* Don 't disable prefetch */ 1200184610Salfred /* Minimum prefetch = 0 */ 1201184610Salfred put_be16(&buf[8], 0xffff); 1202184610Salfred /* Maximum prefetch */ 1203184610Salfred put_be16(&buf[10], 0xffff); 1204184610Salfred /* Maximum prefetch ceiling */ 1205184610Salfred } 1206184610Salfred buf += 12; 1207184610Salfred } 1208184610Salfred /* 1209184610Salfred * Check that a valid page was requested and the mode data length 1210184610Salfred * isn't too long. 1211184610Salfred */ 1212184610Salfred len = buf - buf0; 1213184610Salfred if (len > limit) { 1214184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 1215184610Salfred return (1); 1216184610Salfred } 1217184610Salfred /* Store the mode data length */ 1218184610Salfred if (mscmnd == SC_MODE_SENSE_6) 1219184610Salfred buf0[0] = len - 1; 1220184610Salfred else 1221184610Salfred put_be16(buf0, len - 2); 1222190733Sthompsa 1223190733Sthompsa#if (USTORAGE_QDATA_MAX < 24) 1224190733Sthompsa#error "(USTORAGE_QDATA_MAX < 24)" 1225190733Sthompsa#endif 1226235000Shselasky return (ustorage_fs_min_len(sc, len, -1U)); 1227184610Salfred} 1228184610Salfred 1229184610Salfred/*------------------------------------------------------------------------* 1230184610Salfred * ustorage_fs_start_stop 1231184610Salfred * 1232184610Salfred * Returns: 1233184610Salfred * 0: Success 1234184610Salfred * Else: Failure 1235184610Salfred *------------------------------------------------------------------------*/ 1236184610Salfredstatic uint8_t 1237184610Salfredustorage_fs_start_stop(struct ustorage_fs_softc *sc) 1238184610Salfred{ 1239184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1240184610Salfred uint8_t loej; 1241184610Salfred uint8_t start; 1242184610Salfred uint8_t immed; 1243184610Salfred 1244184610Salfred if (!currlun->removable) { 1245184610Salfred currlun->sense_data = SS_INVALID_COMMAND; 1246184610Salfred return (1); 1247184610Salfred } 1248259454Shselasky immed = sc->sc_cbw->CBWCDB[1] & 0x01; 1249259454Shselasky loej = sc->sc_cbw->CBWCDB[4] & 0x02; 1250259454Shselasky start = sc->sc_cbw->CBWCDB[4] & 0x01; 1251184610Salfred 1252184610Salfred if (immed || loej || start) { 1253184610Salfred /* compile fix */ 1254184610Salfred } 1255184610Salfred return (0); 1256184610Salfred} 1257184610Salfred 1258184610Salfred/*------------------------------------------------------------------------* 1259184610Salfred * ustorage_fs_prevent_allow 1260184610Salfred * 1261184610Salfred * Returns: 1262184610Salfred * 0: Success 1263184610Salfred * Else: Failure 1264184610Salfred *------------------------------------------------------------------------*/ 1265184610Salfredstatic uint8_t 1266184610Salfredustorage_fs_prevent_allow(struct ustorage_fs_softc *sc) 1267184610Salfred{ 1268184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1269184610Salfred uint8_t prevent; 1270184610Salfred 1271184610Salfred if (!currlun->removable) { 1272184610Salfred currlun->sense_data = SS_INVALID_COMMAND; 1273184610Salfred return (1); 1274184610Salfred } 1275259454Shselasky prevent = sc->sc_cbw->CBWCDB[4] & 0x01; 1276259454Shselasky if ((sc->sc_cbw->CBWCDB[4] & ~0x01) != 0) { 1277184610Salfred /* Mask away Prevent */ 1278184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 1279184610Salfred return (1); 1280184610Salfred } 1281184610Salfred if (currlun->prevent_medium_removal && !prevent) { 1282184610Salfred //fsync_sub(currlun); 1283184610Salfred } 1284184610Salfred currlun->prevent_medium_removal = prevent; 1285184610Salfred return (0); 1286184610Salfred} 1287184610Salfred 1288184610Salfred/*------------------------------------------------------------------------* 1289184610Salfred * ustorage_fs_read_format_capacities 1290184610Salfred * 1291184610Salfred * Returns: 1292184610Salfred * 0: Success 1293184610Salfred * Else: Failure 1294184610Salfred *------------------------------------------------------------------------*/ 1295184610Salfredstatic uint8_t 1296184610Salfredustorage_fs_read_format_capacities(struct ustorage_fs_softc *sc) 1297184610Salfred{ 1298184610Salfred uint8_t *buf = sc->sc_transfer.data_ptr; 1299184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1300184610Salfred 1301184610Salfred buf[0] = buf[1] = buf[2] = 0; 1302184610Salfred buf[3] = 8; 1303184610Salfred /* Only the Current / Maximum Capacity Descriptor */ 1304184610Salfred buf += 4; 1305184610Salfred 1306190733Sthompsa /* Number of blocks */ 1307184610Salfred put_be32(&buf[0], currlun->num_sectors); 1308190733Sthompsa /* Block length */ 1309184610Salfred put_be32(&buf[4], 512); 1310190733Sthompsa /* Current capacity */ 1311184610Salfred buf[4] = 0x02; 1312190733Sthompsa 1313190733Sthompsa#if (USTORAGE_QDATA_MAX < 12) 1314190733Sthompsa#error "(USTORAGE_QDATA_MAX < 12)" 1315190733Sthompsa#endif 1316235000Shselasky return (ustorage_fs_min_len(sc, 12, -1U)); 1317184610Salfred} 1318184610Salfred 1319184610Salfred/*------------------------------------------------------------------------* 1320184610Salfred * ustorage_fs_mode_select 1321184610Salfred * 1322184610Salfred * Return values: 1323184610Salfred * 0: Success 1324184610Salfred * Else: Failure 1325184610Salfred *------------------------------------------------------------------------*/ 1326184610Salfredstatic uint8_t 1327184610Salfredustorage_fs_mode_select(struct ustorage_fs_softc *sc) 1328184610Salfred{ 1329184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1330184610Salfred 1331184610Salfred /* We don't support MODE SELECT */ 1332184610Salfred currlun->sense_data = SS_INVALID_COMMAND; 1333184610Salfred return (1); 1334184610Salfred} 1335184610Salfred 1336184610Salfred/*------------------------------------------------------------------------* 1337184610Salfred * ustorage_fs_synchronize_cache 1338184610Salfred * 1339184610Salfred * Return values: 1340184610Salfred * 0: Success 1341184610Salfred * Else: Failure 1342184610Salfred *------------------------------------------------------------------------*/ 1343184610Salfredstatic uint8_t 1344184610Salfredustorage_fs_synchronize_cache(struct ustorage_fs_softc *sc) 1345184610Salfred{ 1346186730Salfred#if 0 1347184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1348184610Salfred uint8_t rc; 1349184610Salfred 1350184610Salfred /* 1351184610Salfred * We ignore the requested LBA and write out all dirty data buffers. 1352184610Salfred */ 1353184610Salfred rc = 0; 1354184610Salfred if (rc) { 1355184610Salfred currlun->sense_data = SS_WRITE_ERROR; 1356184610Salfred } 1357186730Salfred#endif 1358184610Salfred return (0); 1359184610Salfred} 1360184610Salfred 1361184610Salfred/*------------------------------------------------------------------------* 1362184610Salfred * ustorage_fs_read - read data from disk 1363184610Salfred * 1364184610Salfred * Return values: 1365184610Salfred * 0: Success 1366184610Salfred * Else: Failure 1367184610Salfred *------------------------------------------------------------------------*/ 1368184610Salfredstatic uint8_t 1369184610Salfredustorage_fs_read(struct ustorage_fs_softc *sc) 1370184610Salfred{ 1371184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1372184610Salfred uint64_t file_offset; 1373184610Salfred uint32_t lba; 1374184610Salfred uint32_t len; 1375184610Salfred 1376184610Salfred /* 1377184610Salfred * Get the starting Logical Block Address and check that it's not 1378184610Salfred * too big 1379184610Salfred */ 1380259454Shselasky if (sc->sc_cbw->CBWCDB[0] == SC_READ_6) { 1381259454Shselasky lba = (((uint32_t)sc->sc_cbw->CBWCDB[1]) << 16) | 1382259454Shselasky get_be16(&sc->sc_cbw->CBWCDB[2]); 1383184610Salfred } else { 1384259454Shselasky lba = get_be32(&sc->sc_cbw->CBWCDB[2]); 1385184610Salfred 1386184610Salfred /* 1387184610Salfred * We allow DPO (Disable Page Out = don't save data in the 1388184610Salfred * cache) and FUA (Force Unit Access = don't read from the 1389184610Salfred * cache), but we don't implement them. 1390184610Salfred */ 1391259454Shselasky if ((sc->sc_cbw->CBWCDB[1] & ~0x18) != 0) { 1392184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 1393184610Salfred return (1); 1394184610Salfred } 1395184610Salfred } 1396184610Salfred len = sc->sc_transfer.data_rem >> 9; 1397184610Salfred len += lba; 1398184610Salfred 1399184610Salfred if ((len < lba) || 1400184610Salfred (len > currlun->num_sectors) || 1401184610Salfred (lba >= currlun->num_sectors)) { 1402184610Salfred currlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 1403184610Salfred return (1); 1404184610Salfred } 1405184610Salfred file_offset = lba; 1406184610Salfred file_offset <<= 9; 1407184610Salfred 1408190181Sthompsa sc->sc_transfer.data_ptr = currlun->memory_image + file_offset; 1409184610Salfred 1410184610Salfred return (0); 1411184610Salfred} 1412184610Salfred 1413184610Salfred/*------------------------------------------------------------------------* 1414184610Salfred * ustorage_fs_write - write data to disk 1415184610Salfred * 1416184610Salfred * Return values: 1417184610Salfred * 0: Success 1418184610Salfred * Else: Failure 1419184610Salfred *------------------------------------------------------------------------*/ 1420184610Salfredstatic uint8_t 1421184610Salfredustorage_fs_write(struct ustorage_fs_softc *sc) 1422184610Salfred{ 1423184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1424184610Salfred uint64_t file_offset; 1425184610Salfred uint32_t lba; 1426184610Salfred uint32_t len; 1427184610Salfred 1428184610Salfred if (currlun->read_only) { 1429184610Salfred currlun->sense_data = SS_WRITE_PROTECTED; 1430184610Salfred return (1); 1431184610Salfred } 1432184610Salfred /* XXX clear SYNC */ 1433184610Salfred 1434184610Salfred /* 1435184610Salfred * Get the starting Logical Block Address and check that it's not 1436184610Salfred * too big. 1437184610Salfred */ 1438259454Shselasky if (sc->sc_cbw->CBWCDB[0] == SC_WRITE_6) 1439259454Shselasky lba = (((uint32_t)sc->sc_cbw->CBWCDB[1]) << 16) | 1440259454Shselasky get_be16(&sc->sc_cbw->CBWCDB[2]); 1441184610Salfred else { 1442259454Shselasky lba = get_be32(&sc->sc_cbw->CBWCDB[2]); 1443184610Salfred 1444184610Salfred /* 1445184610Salfred * We allow DPO (Disable Page Out = don't save data in the 1446184610Salfred * cache) and FUA (Force Unit Access = write directly to the 1447184610Salfred * medium). We don't implement DPO; we implement FUA by 1448184610Salfred * performing synchronous output. 1449184610Salfred */ 1450259454Shselasky if ((sc->sc_cbw->CBWCDB[1] & ~0x18) != 0) { 1451184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 1452184610Salfred return (1); 1453184610Salfred } 1454259454Shselasky if (sc->sc_cbw->CBWCDB[1] & 0x08) { 1455184610Salfred /* FUA */ 1456184610Salfred /* XXX set SYNC flag here */ 1457184610Salfred } 1458184610Salfred } 1459184610Salfred 1460184610Salfred len = sc->sc_transfer.data_rem >> 9; 1461184610Salfred len += lba; 1462184610Salfred 1463184610Salfred if ((len < lba) || 1464184610Salfred (len > currlun->num_sectors) || 1465184610Salfred (lba >= currlun->num_sectors)) { 1466184610Salfred currlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 1467184610Salfred return (1); 1468184610Salfred } 1469184610Salfred file_offset = lba; 1470184610Salfred file_offset <<= 9; 1471184610Salfred 1472190181Sthompsa sc->sc_transfer.data_ptr = currlun->memory_image + file_offset; 1473184610Salfred 1474184610Salfred return (0); 1475184610Salfred} 1476184610Salfred 1477184610Salfred/*------------------------------------------------------------------------* 1478184610Salfred * ustorage_fs_min_len 1479184610Salfred * 1480184610Salfred * Return values: 1481184610Salfred * 0: Success 1482184610Salfred * Else: Failure 1483184610Salfred *------------------------------------------------------------------------*/ 1484184610Salfredstatic uint8_t 1485184610Salfredustorage_fs_min_len(struct ustorage_fs_softc *sc, uint32_t len, uint32_t mask) 1486184610Salfred{ 1487184610Salfred if (len != sc->sc_transfer.data_rem) { 1488184610Salfred 1489184610Salfred if (sc->sc_transfer.cbw_dir == DIR_READ) { 1490184610Salfred /* 1491184610Salfred * there must be something wrong about this SCSI 1492184610Salfred * command 1493184610Salfred */ 1494259454Shselasky sc->sc_csw->bCSWStatus = CSWSTATUS_PHASE; 1495184610Salfred return (1); 1496184610Salfred } 1497184610Salfred /* compute the minimum length */ 1498184610Salfred 1499184610Salfred if (sc->sc_transfer.data_rem > len) { 1500184610Salfred /* data ends prematurely */ 1501184610Salfred sc->sc_transfer.data_rem = len; 1502184610Salfred sc->sc_transfer.data_short = 1; 1503184610Salfred } 1504184610Salfred /* check length alignment */ 1505184610Salfred 1506184610Salfred if (sc->sc_transfer.data_rem & ~mask) { 1507184610Salfred /* data ends prematurely */ 1508184610Salfred sc->sc_transfer.data_rem &= mask; 1509184610Salfred sc->sc_transfer.data_short = 1; 1510184610Salfred } 1511184610Salfred } 1512184610Salfred return (0); 1513184610Salfred} 1514184610Salfred 1515184610Salfred/*------------------------------------------------------------------------* 1516184610Salfred * ustorage_fs_check_cmd - check command routine 1517184610Salfred * 1518184610Salfred * Check whether the command is properly formed and whether its data 1519184610Salfred * size and direction agree with the values we already have. 1520184610Salfred * 1521184610Salfred * Return values: 1522184610Salfred * 0: Success 1523184610Salfred * Else: Failure 1524184610Salfred *------------------------------------------------------------------------*/ 1525184610Salfredstatic uint8_t 1526184610Salfredustorage_fs_check_cmd(struct ustorage_fs_softc *sc, uint8_t min_cmd_size, 1527184610Salfred uint16_t mask, uint8_t needs_medium) 1528184610Salfred{ 1529184610Salfred struct ustorage_fs_lun *currlun; 1530259454Shselasky uint8_t lun = (sc->sc_cbw->CBWCDB[1] >> 5); 1531184610Salfred uint8_t i; 1532184610Salfred 1533184610Salfred /* Verify the length of the command itself */ 1534184610Salfred if (min_cmd_size > sc->sc_transfer.cmd_len) { 1535184610Salfred DPRINTF("%u > %u\n", 1536184610Salfred min_cmd_size, sc->sc_transfer.cmd_len); 1537259454Shselasky sc->sc_csw->bCSWStatus = CSWSTATUS_PHASE; 1538184610Salfred return (1); 1539184610Salfred } 1540184610Salfred /* Mask away the LUN */ 1541259454Shselasky sc->sc_cbw->CBWCDB[1] &= 0x1f; 1542184610Salfred 1543184610Salfred /* Check if LUN is correct */ 1544184610Salfred if (lun != sc->sc_transfer.lun) { 1545184610Salfred 1546184610Salfred } 1547184610Salfred /* Check the LUN */ 1548184610Salfred if (sc->sc_transfer.lun <= sc->sc_last_lun) { 1549184610Salfred sc->sc_transfer.currlun = currlun = 1550184610Salfred sc->sc_lun + sc->sc_transfer.lun; 1551259454Shselasky if (sc->sc_cbw->CBWCDB[0] != SC_REQUEST_SENSE) { 1552184610Salfred currlun->sense_data = SS_NO_SENSE; 1553184610Salfred currlun->sense_data_info = 0; 1554184610Salfred currlun->info_valid = 0; 1555184610Salfred } 1556184610Salfred /* 1557184610Salfred * If a unit attention condition exists, only INQUIRY 1558184610Salfred * and REQUEST SENSE commands are allowed. Anything 1559184610Salfred * else must fail! 1560184610Salfred */ 1561184610Salfred if ((currlun->unit_attention_data != SS_NO_SENSE) && 1562259454Shselasky (sc->sc_cbw->CBWCDB[0] != SC_INQUIRY) && 1563259454Shselasky (sc->sc_cbw->CBWCDB[0] != SC_REQUEST_SENSE)) { 1564184610Salfred currlun->sense_data = currlun->unit_attention_data; 1565184610Salfred currlun->unit_attention_data = SS_NO_SENSE; 1566184610Salfred return (1); 1567184610Salfred } 1568184610Salfred } else { 1569184610Salfred sc->sc_transfer.currlun = currlun = NULL; 1570184610Salfred 1571184610Salfred /* 1572184610Salfred * INQUIRY and REQUEST SENSE commands are explicitly allowed 1573184610Salfred * to use unsupported LUNs; all others may not. 1574184610Salfred */ 1575259454Shselasky if ((sc->sc_cbw->CBWCDB[0] != SC_INQUIRY) && 1576259454Shselasky (sc->sc_cbw->CBWCDB[0] != SC_REQUEST_SENSE)) { 1577184610Salfred return (1); 1578184610Salfred } 1579184610Salfred } 1580184610Salfred 1581184610Salfred /* 1582184610Salfred * Check that only command bytes listed in the mask are 1583184610Salfred * non-zero. 1584184610Salfred */ 1585184610Salfred for (i = 0; i != min_cmd_size; i++) { 1586259454Shselasky if (sc->sc_cbw->CBWCDB[i] && !(mask & (1UL << i))) { 1587184610Salfred if (currlun) { 1588184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 1589184610Salfred } 1590184610Salfred return (1); 1591184610Salfred } 1592184610Salfred } 1593184610Salfred 1594184610Salfred /* 1595184610Salfred * If the medium isn't mounted and the command needs to access 1596184610Salfred * it, return an error. 1597184610Salfred */ 1598184610Salfred if (currlun && (!currlun->memory_image) && needs_medium) { 1599184610Salfred currlun->sense_data = SS_MEDIUM_NOT_PRESENT; 1600184610Salfred return (1); 1601184610Salfred } 1602184610Salfred return (0); 1603184610Salfred} 1604184610Salfred 1605184610Salfred/*------------------------------------------------------------------------* 1606184610Salfred * ustorage_fs_do_cmd - do command 1607184610Salfred * 1608184610Salfred * Return values: 1609184610Salfred * 0: Success 1610184610Salfred * Else: Failure 1611184610Salfred *------------------------------------------------------------------------*/ 1612184610Salfredstatic uint8_t 1613184610Salfredustorage_fs_do_cmd(struct ustorage_fs_softc *sc) 1614184610Salfred{ 1615184610Salfred uint8_t error = 1; 1616184610Salfred uint8_t i; 1617190719Sthompsa uint32_t temp; 1618190719Sthompsa const uint32_t mask9 = (0xFFFFFFFFUL >> 9) << 9; 1619184610Salfred 1620184610Salfred /* set default data transfer pointer */ 1621184610Salfred sc->sc_transfer.data_ptr = sc->sc_qdata; 1622184610Salfred 1623184610Salfred DPRINTF("cmd_data[0]=0x%02x, data_rem=0x%08x\n", 1624259454Shselasky sc->sc_cbw->CBWCDB[0], sc->sc_transfer.data_rem); 1625184610Salfred 1626259454Shselasky switch (sc->sc_cbw->CBWCDB[0]) { 1627184610Salfred case SC_INQUIRY: 1628184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1629259454Shselasky error = ustorage_fs_min_len(sc, sc->sc_cbw->CBWCDB[4], -1U); 1630184610Salfred if (error) { 1631184610Salfred break; 1632184610Salfred } 1633184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1634190719Sthompsa (1UL << 4) | 1, 0); 1635184610Salfred if (error) { 1636184610Salfred break; 1637184610Salfred } 1638184610Salfred error = ustorage_fs_inquiry(sc); 1639184610Salfred 1640184610Salfred break; 1641184610Salfred 1642184610Salfred case SC_MODE_SELECT_6: 1643184610Salfred sc->sc_transfer.cmd_dir = DIR_READ; 1644259454Shselasky error = ustorage_fs_min_len(sc, sc->sc_cbw->CBWCDB[4], -1U); 1645184610Salfred if (error) { 1646184610Salfred break; 1647184610Salfred } 1648184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1649190719Sthompsa (1UL << 1) | (1UL << 4) | 1, 0); 1650184610Salfred if (error) { 1651184610Salfred break; 1652184610Salfred } 1653184610Salfred error = ustorage_fs_mode_select(sc); 1654184610Salfred 1655184610Salfred break; 1656184610Salfred 1657184610Salfred case SC_MODE_SELECT_10: 1658184610Salfred sc->sc_transfer.cmd_dir = DIR_READ; 1659184610Salfred error = ustorage_fs_min_len(sc, 1660259454Shselasky get_be16(&sc->sc_cbw->CBWCDB[7]), -1U); 1661184610Salfred if (error) { 1662184610Salfred break; 1663184610Salfred } 1664184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1665190719Sthompsa (1UL << 1) | (3UL << 7) | 1, 0); 1666184610Salfred if (error) { 1667184610Salfred break; 1668184610Salfred } 1669184610Salfred error = ustorage_fs_mode_select(sc); 1670184610Salfred 1671184610Salfred break; 1672184610Salfred 1673184610Salfred case SC_MODE_SENSE_6: 1674184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1675259454Shselasky error = ustorage_fs_min_len(sc, sc->sc_cbw->CBWCDB[4], -1U); 1676184610Salfred if (error) { 1677184610Salfred break; 1678184610Salfred } 1679184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1680190719Sthompsa (1UL << 1) | (1UL << 2) | (1UL << 4) | 1, 0); 1681184610Salfred if (error) { 1682184610Salfred break; 1683184610Salfred } 1684184610Salfred error = ustorage_fs_mode_sense(sc); 1685184610Salfred 1686184610Salfred break; 1687184610Salfred 1688184610Salfred case SC_MODE_SENSE_10: 1689184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1690184610Salfred error = ustorage_fs_min_len(sc, 1691259454Shselasky get_be16(&sc->sc_cbw->CBWCDB[7]), -1U); 1692184610Salfred if (error) { 1693184610Salfred break; 1694184610Salfred } 1695184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1696190719Sthompsa (1UL << 1) | (1UL << 2) | (3UL << 7) | 1, 0); 1697184610Salfred if (error) { 1698184610Salfred break; 1699184610Salfred } 1700184610Salfred error = ustorage_fs_mode_sense(sc); 1701184610Salfred 1702184610Salfred break; 1703184610Salfred 1704184610Salfred case SC_PREVENT_ALLOW_MEDIUM_REMOVAL: 1705235000Shselasky error = ustorage_fs_min_len(sc, 0, -1U); 1706184610Salfred if (error) { 1707184610Salfred break; 1708184610Salfred } 1709184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1710190719Sthompsa (1UL << 4) | 1, 0); 1711184610Salfred if (error) { 1712184610Salfred break; 1713184610Salfred } 1714184610Salfred error = ustorage_fs_prevent_allow(sc); 1715184610Salfred 1716184610Salfred break; 1717184610Salfred 1718184610Salfred case SC_READ_6: 1719259454Shselasky i = sc->sc_cbw->CBWCDB[4]; 1720184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1721190719Sthompsa temp = ((i == 0) ? 256UL : i); 1722190719Sthompsa error = ustorage_fs_min_len(sc, temp << 9, mask9); 1723184610Salfred if (error) { 1724184610Salfred break; 1725184610Salfred } 1726184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1727190719Sthompsa (7UL << 1) | (1UL << 4) | 1, 1); 1728184610Salfred if (error) { 1729184610Salfred break; 1730184610Salfred } 1731184610Salfred error = ustorage_fs_read(sc); 1732184610Salfred 1733184610Salfred break; 1734184610Salfred 1735184610Salfred case SC_READ_10: 1736184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1737259454Shselasky temp = get_be16(&sc->sc_cbw->CBWCDB[7]); 1738190719Sthompsa error = ustorage_fs_min_len(sc, temp << 9, mask9); 1739184610Salfred if (error) { 1740184610Salfred break; 1741184610Salfred } 1742184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1743190719Sthompsa (1UL << 1) | (0xfUL << 2) | (3UL << 7) | 1, 1); 1744184610Salfred if (error) { 1745184610Salfred break; 1746184610Salfred } 1747184610Salfred error = ustorage_fs_read(sc); 1748184610Salfred 1749184610Salfred break; 1750184610Salfred 1751184610Salfred case SC_READ_12: 1752184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1753259454Shselasky temp = get_be32(&sc->sc_cbw->CBWCDB[6]); 1754190719Sthompsa if (temp >= (1UL << (32 - 9))) { 1755190719Sthompsa /* numerical overflow */ 1756259454Shselasky sc->sc_csw->bCSWStatus = CSWSTATUS_FAILED; 1757190719Sthompsa error = 1; 1758190719Sthompsa break; 1759190719Sthompsa } 1760190719Sthompsa error = ustorage_fs_min_len(sc, temp << 9, mask9); 1761184610Salfred if (error) { 1762184610Salfred break; 1763184610Salfred } 1764184610Salfred error = ustorage_fs_check_cmd(sc, 12, 1765190719Sthompsa (1UL << 1) | (0xfUL << 2) | (0xfUL << 6) | 1, 1); 1766184610Salfred if (error) { 1767184610Salfred break; 1768184610Salfred } 1769184610Salfred error = ustorage_fs_read(sc); 1770184610Salfred 1771184610Salfred break; 1772184610Salfred 1773184610Salfred case SC_READ_CAPACITY: 1774184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1775184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1776190719Sthompsa (0xfUL << 2) | (1UL << 8) | 1, 1); 1777184610Salfred if (error) { 1778184610Salfred break; 1779184610Salfred } 1780184610Salfred error = ustorage_fs_read_capacity(sc); 1781184610Salfred 1782184610Salfred break; 1783184610Salfred 1784184610Salfred case SC_READ_FORMAT_CAPACITIES: 1785184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1786184610Salfred error = ustorage_fs_min_len(sc, 1787259454Shselasky get_be16(&sc->sc_cbw->CBWCDB[7]), -1U); 1788184610Salfred if (error) { 1789184610Salfred break; 1790184610Salfred } 1791184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1792190719Sthompsa (3UL << 7) | 1, 1); 1793184610Salfred if (error) { 1794184610Salfred break; 1795184610Salfred } 1796184610Salfred error = ustorage_fs_read_format_capacities(sc); 1797184610Salfred 1798184610Salfred break; 1799184610Salfred 1800184610Salfred case SC_REQUEST_SENSE: 1801184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1802259454Shselasky error = ustorage_fs_min_len(sc, sc->sc_cbw->CBWCDB[4], -1U); 1803184610Salfred if (error) { 1804184610Salfred break; 1805184610Salfred } 1806184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1807190719Sthompsa (1UL << 4) | 1, 0); 1808184610Salfred if (error) { 1809184610Salfred break; 1810184610Salfred } 1811184610Salfred error = ustorage_fs_request_sense(sc); 1812184610Salfred 1813184610Salfred break; 1814184610Salfred 1815184610Salfred case SC_START_STOP_UNIT: 1816235000Shselasky error = ustorage_fs_min_len(sc, 0, -1U); 1817184610Salfred if (error) { 1818184610Salfred break; 1819184610Salfred } 1820184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1821190719Sthompsa (1UL << 1) | (1UL << 4) | 1, 0); 1822184610Salfred if (error) { 1823184610Salfred break; 1824184610Salfred } 1825184610Salfred error = ustorage_fs_start_stop(sc); 1826184610Salfred 1827184610Salfred break; 1828184610Salfred 1829184610Salfred case SC_SYNCHRONIZE_CACHE: 1830235000Shselasky error = ustorage_fs_min_len(sc, 0, -1U); 1831184610Salfred if (error) { 1832184610Salfred break; 1833184610Salfred } 1834184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1835190719Sthompsa (0xfUL << 2) | (3UL << 7) | 1, 1); 1836184610Salfred if (error) { 1837184610Salfred break; 1838184610Salfred } 1839184610Salfred error = ustorage_fs_synchronize_cache(sc); 1840184610Salfred 1841184610Salfred break; 1842184610Salfred 1843184610Salfred case SC_TEST_UNIT_READY: 1844235000Shselasky error = ustorage_fs_min_len(sc, 0, -1U); 1845184610Salfred if (error) { 1846184610Salfred break; 1847184610Salfred } 1848184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1849184610Salfred 0 | 1, 1); 1850184610Salfred break; 1851184610Salfred 1852184610Salfred /* 1853184610Salfred * Although optional, this command is used by MS-Windows. 1854184610Salfred * We support a minimal version: BytChk must be 0. 1855184610Salfred */ 1856184610Salfred case SC_VERIFY: 1857235000Shselasky error = ustorage_fs_min_len(sc, 0, -1U); 1858184610Salfred if (error) { 1859184610Salfred break; 1860184610Salfred } 1861184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1862190719Sthompsa (1UL << 1) | (0xfUL << 2) | (3UL << 7) | 1, 1); 1863184610Salfred if (error) { 1864184610Salfred break; 1865184610Salfred } 1866184610Salfred error = ustorage_fs_verify(sc); 1867184610Salfred 1868184610Salfred break; 1869184610Salfred 1870184610Salfred case SC_WRITE_6: 1871259454Shselasky i = sc->sc_cbw->CBWCDB[4]; 1872184610Salfred sc->sc_transfer.cmd_dir = DIR_READ; 1873190719Sthompsa temp = ((i == 0) ? 256UL : i); 1874190719Sthompsa error = ustorage_fs_min_len(sc, temp << 9, mask9); 1875184610Salfred if (error) { 1876184610Salfred break; 1877184610Salfred } 1878184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1879190719Sthompsa (7UL << 1) | (1UL << 4) | 1, 1); 1880184610Salfred if (error) { 1881184610Salfred break; 1882184610Salfred } 1883184610Salfred error = ustorage_fs_write(sc); 1884184610Salfred 1885184610Salfred break; 1886184610Salfred 1887184610Salfred case SC_WRITE_10: 1888184610Salfred sc->sc_transfer.cmd_dir = DIR_READ; 1889259454Shselasky temp = get_be16(&sc->sc_cbw->CBWCDB[7]); 1890190719Sthompsa error = ustorage_fs_min_len(sc, temp << 9, mask9); 1891184610Salfred if (error) { 1892184610Salfred break; 1893184610Salfred } 1894184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1895190719Sthompsa (1UL << 1) | (0xfUL << 2) | (3UL << 7) | 1, 1); 1896184610Salfred if (error) { 1897184610Salfred break; 1898184610Salfred } 1899184610Salfred error = ustorage_fs_write(sc); 1900184610Salfred 1901184610Salfred break; 1902184610Salfred 1903184610Salfred case SC_WRITE_12: 1904184610Salfred sc->sc_transfer.cmd_dir = DIR_READ; 1905259454Shselasky temp = get_be32(&sc->sc_cbw->CBWCDB[6]); 1906190719Sthompsa if (temp > (mask9 >> 9)) { 1907190719Sthompsa /* numerical overflow */ 1908259454Shselasky sc->sc_csw->bCSWStatus = CSWSTATUS_FAILED; 1909190719Sthompsa error = 1; 1910190719Sthompsa break; 1911190719Sthompsa } 1912190719Sthompsa error = ustorage_fs_min_len(sc, temp << 9, mask9); 1913184610Salfred if (error) { 1914184610Salfred break; 1915184610Salfred } 1916184610Salfred error = ustorage_fs_check_cmd(sc, 12, 1917190719Sthompsa (1UL << 1) | (0xfUL << 2) | (0xfUL << 6) | 1, 1); 1918184610Salfred if (error) { 1919184610Salfred break; 1920184610Salfred } 1921184610Salfred error = ustorage_fs_write(sc); 1922184610Salfred 1923184610Salfred break; 1924184610Salfred 1925184610Salfred /* 1926184610Salfred * Some mandatory commands that we recognize but don't 1927184610Salfred * implement. They don't mean much in this setting. 1928184610Salfred * It's left as an exercise for anyone interested to 1929184610Salfred * implement RESERVE and RELEASE in terms of Posix 1930184610Salfred * locks. 1931184610Salfred */ 1932184610Salfred case SC_FORMAT_UNIT: 1933184610Salfred case SC_RELEASE: 1934184610Salfred case SC_RESERVE: 1935184610Salfred case SC_SEND_DIAGNOSTIC: 1936184610Salfred /* Fallthrough */ 1937184610Salfred 1938184610Salfred default: 1939235000Shselasky error = ustorage_fs_min_len(sc, 0, -1U); 1940184610Salfred if (error) { 1941184610Salfred break; 1942184610Salfred } 1943184610Salfred error = ustorage_fs_check_cmd(sc, sc->sc_transfer.cmd_len, 1944184610Salfred 0xff, 0); 1945184610Salfred if (error) { 1946184610Salfred break; 1947184610Salfred } 1948184610Salfred sc->sc_transfer.currlun->sense_data = 1949184610Salfred SS_INVALID_COMMAND; 1950184610Salfred error = 1; 1951184610Salfred 1952184610Salfred break; 1953184610Salfred } 1954184610Salfred return (error); 1955184610Salfred} 1956