ustorage_fs.c revision 192984
1184610Salfred/* $FreeBSD: head/sys/dev/usb/storage/ustorage_fs.c 192984 2009-05-28 17:36:36Z thompsa $ */ 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 */ 38188746Sthompsa#include "usbdevs.h" 39188942Sthompsa#include <dev/usb/usb.h> 40188942Sthompsa#include <dev/usb/usb_mfunc.h> 41188942Sthompsa#include <dev/usb/usb_error.h> 42184610Salfred 43184610Salfred#define USB_DEBUG_VAR ustorage_fs_debug 44184610Salfred 45188942Sthompsa#include <dev/usb/usb_core.h> 46188942Sthompsa#include <dev/usb/usb_util.h> 47188942Sthompsa#include <dev/usb/usb_busdma.h> 48188942Sthompsa#include <dev/usb/usb_debug.h> 49188942Sthompsa#include <dev/usb/usb_process.h> 50188942Sthompsa#include <dev/usb/usb_device.h> 51184610Salfred 52184610Salfred#if USB_DEBUG 53184610Salfredstatic int ustorage_fs_debug = 0; 54184610Salfred 55192502SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, ustorage_fs, CTLFLAG_RW, 0, "USB ustorage_fs"); 56192502SthompsaSYSCTL_INT(_hw_usb_ustorage_fs, OID_AUTO, debug, CTLFLAG_RW, 57184610Salfred &ustorage_fs_debug, 0, "ustorage_fs debug level"); 58184610Salfred#endif 59184610Salfred 60184610Salfred/* Define some limits */ 61184610Salfred 62190181Sthompsa#ifndef USTORAGE_FS_BULK_SIZE 63190719Sthompsa#define USTORAGE_FS_BULK_SIZE (1UL << 17) /* bytes */ 64190181Sthompsa#endif 65184610Salfred 66190733Sthompsa#ifndef USTORAGE_FS_MAX_LUN 67190733Sthompsa#define USTORAGE_FS_MAX_LUN 8 /* units */ 68190733Sthompsa#endif 69190181Sthompsa 70190733Sthompsa#ifndef USTORAGE_QDATA_MAX 71190733Sthompsa#define USTORAGE_QDATA_MAX 40 /* bytes */ 72190733Sthompsa#endif 73190733Sthompsa 74190733Sthompsa#define sc_cmd_data sc_cbw.CBWCDB 75190733Sthompsa 76190173Sthompsa/* 77190173Sthompsa * The SCSI ID string must be exactly 28 characters long 78190173Sthompsa * exluding the terminating zero. 79190173Sthompsa */ 80190173Sthompsa#ifndef USTORAGE_FS_ID_STRING 81190173Sthompsa#define USTORAGE_FS_ID_STRING \ 82190173Sthompsa "FreeBSD " /* 8 */ \ 83190173Sthompsa "File-Stor Gadget" /* 16 */ \ 84190173Sthompsa "0101" /* 4 */ 85190173Sthompsa#endif 86190173Sthompsa 87190173Sthompsa/* 88190173Sthompsa * The following macro defines the number of 89190173Sthompsa * sectors to be allocated for the RAM disk: 90190173Sthompsa */ 91190173Sthompsa#ifndef USTORAGE_FS_RAM_SECT 92190173Sthompsa#define USTORAGE_FS_RAM_SECT (1UL << 13) 93190173Sthompsa#endif 94190173Sthompsa 95184610Salfredstatic uint8_t *ustorage_fs_ramdisk; 96184610Salfred 97184610Salfred/* USB transfer definitions */ 98184610Salfred 99184610Salfred#define USTORAGE_FS_T_BBB_COMMAND 0 100184610Salfred#define USTORAGE_FS_T_BBB_DATA_DUMP 1 101184610Salfred#define USTORAGE_FS_T_BBB_DATA_READ 2 102184610Salfred#define USTORAGE_FS_T_BBB_DATA_WRITE 3 103184610Salfred#define USTORAGE_FS_T_BBB_STATUS 4 104184610Salfred#define USTORAGE_FS_T_BBB_MAX 5 105184610Salfred 106184610Salfred/* USB data stage direction */ 107184610Salfred 108184610Salfred#define DIR_NONE 0 109184610Salfred#define DIR_READ 1 110184610Salfred#define DIR_WRITE 2 111184610Salfred 112184610Salfred/* USB interface specific control request */ 113184610Salfred 114184610Salfred#define UR_BBB_RESET 0xff /* Bulk-Only reset */ 115184610Salfred#define UR_BBB_GET_MAX_LUN 0xfe /* Get maximum lun */ 116184610Salfred 117184610Salfred/* Command Block Wrapper */ 118184610Salfredtypedef struct { 119184610Salfred uDWord dCBWSignature; 120184610Salfred#define CBWSIGNATURE 0x43425355 121184610Salfred uDWord dCBWTag; 122184610Salfred uDWord dCBWDataTransferLength; 123184610Salfred uByte bCBWFlags; 124184610Salfred#define CBWFLAGS_OUT 0x00 125184610Salfred#define CBWFLAGS_IN 0x80 126184610Salfred uByte bCBWLUN; 127184610Salfred uByte bCDBLength; 128184610Salfred#define CBWCDBLENGTH 16 129184610Salfred uByte CBWCDB[CBWCDBLENGTH]; 130184610Salfred} __packed ustorage_fs_bbb_cbw_t; 131184610Salfred 132184610Salfred#define USTORAGE_FS_BBB_CBW_SIZE 31 133184610Salfred 134184610Salfred/* Command Status Wrapper */ 135184610Salfredtypedef struct { 136184610Salfred uDWord dCSWSignature; 137184610Salfred#define CSWSIGNATURE 0x53425355 138184610Salfred uDWord dCSWTag; 139184610Salfred uDWord dCSWDataResidue; 140184610Salfred uByte bCSWStatus; 141184610Salfred#define CSWSTATUS_GOOD 0x0 142184610Salfred#define CSWSTATUS_FAILED 0x1 143184610Salfred#define CSWSTATUS_PHASE 0x2 144184610Salfred} __packed ustorage_fs_bbb_csw_t; 145184610Salfred 146184610Salfred#define USTORAGE_FS_BBB_CSW_SIZE 13 147184610Salfred 148184610Salfredstruct ustorage_fs_lun { 149184610Salfred 150190181Sthompsa uint8_t *memory_image; 151184610Salfred 152184610Salfred uint32_t num_sectors; 153184610Salfred uint32_t sense_data; 154184610Salfred uint32_t sense_data_info; 155184610Salfred uint32_t unit_attention_data; 156184610Salfred 157184610Salfred uint8_t read_only:1; 158184610Salfred uint8_t prevent_medium_removal:1; 159184610Salfred uint8_t info_valid:1; 160184610Salfred uint8_t removable:1; 161184610Salfred}; 162184610Salfred 163184610Salfredstruct ustorage_fs_softc { 164184610Salfred 165184610Salfred ustorage_fs_bbb_cbw_t sc_cbw; /* Command Wrapper Block */ 166184610Salfred ustorage_fs_bbb_csw_t sc_csw; /* Command Status Block */ 167184610Salfred 168184610Salfred struct mtx sc_mtx; 169184610Salfred 170184610Salfred struct ustorage_fs_lun sc_lun[USTORAGE_FS_MAX_LUN]; 171184610Salfred 172184610Salfred struct { 173184610Salfred uint8_t *data_ptr; 174184610Salfred struct ustorage_fs_lun *currlun; 175184610Salfred 176184610Salfred uint32_t data_rem; /* bytes, as reported by the command 177184610Salfred * block wrapper */ 178184610Salfred uint32_t offset; /* bytes */ 179184610Salfred 180184610Salfred uint8_t cbw_dir; 181184610Salfred uint8_t cmd_dir; 182184610Salfred uint8_t lun; 183184610Salfred uint8_t cmd_len; 184184610Salfred uint8_t data_short:1; 185184610Salfred uint8_t data_error:1; 186184610Salfred } sc_transfer; 187184610Salfred 188184610Salfred device_t sc_dev; 189192984Sthompsa struct usb_device *sc_udev; 190192984Sthompsa struct usb_xfer *sc_xfer[USTORAGE_FS_T_BBB_MAX]; 191184610Salfred 192184610Salfred uint8_t sc_iface_no; /* interface number */ 193184610Salfred uint8_t sc_last_lun; 194184610Salfred uint8_t sc_last_xfer_index; 195190733Sthompsa uint8_t sc_qdata[USTORAGE_QDATA_MAX]; 196184610Salfred}; 197184610Salfred 198184610Salfred/* prototypes */ 199184610Salfred 200184610Salfredstatic device_probe_t ustorage_fs_probe; 201184610Salfredstatic device_attach_t ustorage_fs_attach; 202184610Salfredstatic device_detach_t ustorage_fs_detach; 203184610Salfredstatic device_suspend_t ustorage_fs_suspend; 204184610Salfredstatic device_resume_t ustorage_fs_resume; 205188942Sthompsastatic usb_handle_request_t ustorage_fs_handle_request; 206184610Salfred 207184610Salfredstatic usb2_callback_t ustorage_fs_t_bbb_command_callback; 208184610Salfredstatic usb2_callback_t ustorage_fs_t_bbb_data_dump_callback; 209184610Salfredstatic usb2_callback_t ustorage_fs_t_bbb_data_read_callback; 210184610Salfredstatic usb2_callback_t ustorage_fs_t_bbb_data_write_callback; 211184610Salfredstatic usb2_callback_t ustorage_fs_t_bbb_status_callback; 212184610Salfred 213184610Salfredstatic void ustorage_fs_transfer_start(struct ustorage_fs_softc *sc, uint8_t xfer_index); 214184610Salfredstatic void ustorage_fs_transfer_stop(struct ustorage_fs_softc *sc); 215184610Salfred 216184610Salfredstatic uint8_t ustorage_fs_verify(struct ustorage_fs_softc *sc); 217184610Salfredstatic uint8_t ustorage_fs_inquiry(struct ustorage_fs_softc *sc); 218184610Salfredstatic uint8_t ustorage_fs_request_sense(struct ustorage_fs_softc *sc); 219184610Salfredstatic uint8_t ustorage_fs_read_capacity(struct ustorage_fs_softc *sc); 220184610Salfredstatic uint8_t ustorage_fs_mode_sense(struct ustorage_fs_softc *sc); 221184610Salfredstatic uint8_t ustorage_fs_start_stop(struct ustorage_fs_softc *sc); 222184610Salfredstatic uint8_t ustorage_fs_prevent_allow(struct ustorage_fs_softc *sc); 223184610Salfredstatic uint8_t ustorage_fs_read_format_capacities(struct ustorage_fs_softc *sc); 224184610Salfredstatic uint8_t ustorage_fs_mode_select(struct ustorage_fs_softc *sc); 225184610Salfredstatic uint8_t ustorage_fs_min_len(struct ustorage_fs_softc *sc, uint32_t len, uint32_t mask); 226184610Salfredstatic uint8_t ustorage_fs_read(struct ustorage_fs_softc *sc); 227184610Salfredstatic uint8_t ustorage_fs_write(struct ustorage_fs_softc *sc); 228184610Salfredstatic uint8_t ustorage_fs_check_cmd(struct ustorage_fs_softc *sc, uint8_t cmd_size, uint16_t mask, uint8_t needs_medium); 229184610Salfredstatic uint8_t ustorage_fs_do_cmd(struct ustorage_fs_softc *sc); 230184610Salfred 231184610Salfredstatic device_method_t ustorage_fs_methods[] = { 232184610Salfred /* USB interface */ 233188942Sthompsa DEVMETHOD(usb_handle_request, ustorage_fs_handle_request), 234184610Salfred 235184610Salfred /* Device interface */ 236184610Salfred DEVMETHOD(device_probe, ustorage_fs_probe), 237184610Salfred DEVMETHOD(device_attach, ustorage_fs_attach), 238184610Salfred DEVMETHOD(device_detach, ustorage_fs_detach), 239184610Salfred DEVMETHOD(device_suspend, ustorage_fs_suspend), 240184610Salfred DEVMETHOD(device_resume, ustorage_fs_resume), 241184610Salfred 242184610Salfred {0, 0} 243184610Salfred}; 244184610Salfred 245184610Salfredstatic driver_t ustorage_fs_driver = { 246184610Salfred .name = "ustorage_fs", 247184610Salfred .methods = ustorage_fs_methods, 248184610Salfred .size = sizeof(struct ustorage_fs_softc), 249184610Salfred}; 250184610Salfred 251184610Salfredstatic devclass_t ustorage_fs_devclass; 252184610Salfred 253189275SthompsaDRIVER_MODULE(ustorage_fs, uhub, ustorage_fs_driver, ustorage_fs_devclass, NULL, 0); 254184610SalfredMODULE_VERSION(ustorage_fs, 0); 255188942SthompsaMODULE_DEPEND(ustorage_fs, usb, 1, 1, 1); 256184610Salfred 257192984Sthompsastruct usb_config ustorage_fs_bbb_config[USTORAGE_FS_T_BBB_MAX] = { 258184610Salfred 259184610Salfred [USTORAGE_FS_T_BBB_COMMAND] = { 260184610Salfred .type = UE_BULK, 261184610Salfred .endpoint = UE_ADDR_ANY, 262184610Salfred .direction = UE_DIR_OUT, 263190733Sthompsa .bufsize = sizeof(ustorage_fs_bbb_cbw_t), 264190733Sthompsa .flags = {.ext_buffer = 1,}, 265190733Sthompsa .callback = &ustorage_fs_t_bbb_command_callback, 266190733Sthompsa .usb_mode = USB_MODE_DEVICE, 267184610Salfred }, 268184610Salfred 269184610Salfred [USTORAGE_FS_T_BBB_DATA_DUMP] = { 270184610Salfred .type = UE_BULK, 271184610Salfred .endpoint = UE_ADDR_ANY, 272184610Salfred .direction = UE_DIR_OUT, 273190733Sthompsa .bufsize = 0, /* use wMaxPacketSize */ 274190733Sthompsa .flags = {.proxy_buffer = 1,.short_xfer_ok = 1,}, 275190733Sthompsa .callback = &ustorage_fs_t_bbb_data_dump_callback, 276190733Sthompsa .usb_mode = USB_MODE_DEVICE, 277184610Salfred }, 278184610Salfred 279184610Salfred [USTORAGE_FS_T_BBB_DATA_READ] = { 280184610Salfred .type = UE_BULK, 281184610Salfred .endpoint = UE_ADDR_ANY, 282184610Salfred .direction = UE_DIR_OUT, 283190733Sthompsa .bufsize = USTORAGE_FS_BULK_SIZE, 284190733Sthompsa .flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer = 1}, 285190733Sthompsa .callback = &ustorage_fs_t_bbb_data_read_callback, 286190733Sthompsa .usb_mode = USB_MODE_DEVICE, 287184610Salfred }, 288184610Salfred 289184610Salfred [USTORAGE_FS_T_BBB_DATA_WRITE] = { 290184610Salfred .type = UE_BULK, 291184610Salfred .endpoint = UE_ADDR_ANY, 292184610Salfred .direction = UE_DIR_IN, 293190733Sthompsa .bufsize = USTORAGE_FS_BULK_SIZE, 294190733Sthompsa .flags = {.proxy_buffer = 1,.short_xfer_ok = 1,.ext_buffer = 1}, 295190733Sthompsa .callback = &ustorage_fs_t_bbb_data_write_callback, 296190733Sthompsa .usb_mode = USB_MODE_DEVICE, 297184610Salfred }, 298184610Salfred 299184610Salfred [USTORAGE_FS_T_BBB_STATUS] = { 300184610Salfred .type = UE_BULK, 301184610Salfred .endpoint = UE_ADDR_ANY, 302184610Salfred .direction = UE_DIR_IN, 303190733Sthompsa .bufsize = sizeof(ustorage_fs_bbb_csw_t), 304190733Sthompsa .flags = {.short_xfer_ok = 1,.ext_buffer = 1,}, 305190733Sthompsa .callback = &ustorage_fs_t_bbb_status_callback, 306190733Sthompsa .usb_mode = USB_MODE_DEVICE, 307184610Salfred }, 308184610Salfred}; 309184610Salfred 310184610Salfred/* 311184610Salfred * USB device probe/attach/detach 312184610Salfred */ 313184610Salfred 314184610Salfredstatic int 315184610Salfredustorage_fs_probe(device_t dev) 316184610Salfred{ 317192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 318192984Sthompsa struct usb_interface_descriptor *id; 319184610Salfred 320192499Sthompsa if (uaa->usb_mode != USB_MODE_DEVICE) { 321184610Salfred return (ENXIO); 322184610Salfred } 323184610Salfred if (uaa->use_generic == 0) { 324184610Salfred /* give other drivers a try first */ 325184610Salfred return (ENXIO); 326184610Salfred } 327184610Salfred /* Check for a standards compliant device */ 328184610Salfred id = usb2_get_interface_descriptor(uaa->iface); 329184610Salfred if ((id == NULL) || 330184610Salfred (id->bInterfaceClass != UICLASS_MASS) || 331184610Salfred (id->bInterfaceSubClass != UISUBCLASS_SCSI) || 332184610Salfred (id->bInterfaceProtocol != UIPROTO_MASS_BBB)) { 333184610Salfred return (ENXIO); 334184610Salfred } 335184610Salfred return (0); 336184610Salfred} 337184610Salfred 338184610Salfredstatic int 339184610Salfredustorage_fs_attach(device_t dev) 340184610Salfred{ 341184610Salfred struct ustorage_fs_softc *sc = device_get_softc(dev); 342192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 343192984Sthompsa struct usb_interface_descriptor *id; 344184610Salfred int err; 345190733Sthompsa int unit; 346184610Salfred 347184610Salfred /* 348184610Salfred * NOTE: the softc struct is bzero-ed in device_set_driver. 349184610Salfred * We can safely call ustorage_fs_detach without specifically 350184610Salfred * initializing the struct. 351184610Salfred */ 352184610Salfred 353184610Salfred sc->sc_dev = dev; 354184610Salfred sc->sc_udev = uaa->device; 355190733Sthompsa unit = device_get_unit(dev); 356184610Salfred 357190733Sthompsa if (unit == 0) { 358184610Salfred if (ustorage_fs_ramdisk == NULL) { 359184610Salfred /* 360184610Salfred * allocate a memory image for our ramdisk until 361184610Salfred * further 362184610Salfred */ 363184610Salfred ustorage_fs_ramdisk = 364184610Salfred malloc(USTORAGE_FS_RAM_SECT << 9, M_USB, M_ZERO | M_WAITOK); 365184610Salfred if (ustorage_fs_ramdisk == NULL) { 366184610Salfred return (ENOMEM); 367184610Salfred } 368184610Salfred } 369184610Salfred sc->sc_lun[0].memory_image = ustorage_fs_ramdisk; 370184610Salfred sc->sc_lun[0].num_sectors = USTORAGE_FS_RAM_SECT; 371184610Salfred sc->sc_lun[0].removable = 1; 372184610Salfred } 373184610Salfred 374184610Salfred device_set_usb2_desc(dev); 375184610Salfred 376184610Salfred mtx_init(&sc->sc_mtx, "USTORAGE_FS lock", 377184610Salfred NULL, (MTX_DEF | MTX_RECURSE)); 378184610Salfred 379184610Salfred /* get interface index */ 380184610Salfred 381184610Salfred id = usb2_get_interface_descriptor(uaa->iface); 382184610Salfred if (id == NULL) { 383184610Salfred device_printf(dev, "failed to get " 384184610Salfred "interface number\n"); 385184610Salfred goto detach; 386184610Salfred } 387184610Salfred sc->sc_iface_no = id->bInterfaceNumber; 388184610Salfred 389184610Salfred err = usb2_transfer_setup(uaa->device, 390184610Salfred &uaa->info.bIfaceIndex, sc->sc_xfer, ustorage_fs_bbb_config, 391184610Salfred USTORAGE_FS_T_BBB_MAX, sc, &sc->sc_mtx); 392184610Salfred if (err) { 393184610Salfred device_printf(dev, "could not setup required " 394184610Salfred "transfers, %s\n", usb2_errstr(err)); 395184610Salfred goto detach; 396184610Salfred } 397184610Salfred /* start Mass Storage State Machine */ 398184610Salfred 399184610Salfred mtx_lock(&sc->sc_mtx); 400184610Salfred ustorage_fs_transfer_start(sc, USTORAGE_FS_T_BBB_COMMAND); 401184610Salfred mtx_unlock(&sc->sc_mtx); 402184610Salfred 403184610Salfred return (0); /* success */ 404184610Salfred 405184610Salfreddetach: 406184610Salfred ustorage_fs_detach(dev); 407184610Salfred return (ENXIO); /* failure */ 408184610Salfred} 409184610Salfred 410184610Salfredstatic int 411184610Salfredustorage_fs_detach(device_t dev) 412184610Salfred{ 413184610Salfred struct ustorage_fs_softc *sc = device_get_softc(dev); 414184610Salfred 415184610Salfred /* teardown our statemachine */ 416184610Salfred 417184610Salfred usb2_transfer_unsetup(sc->sc_xfer, USTORAGE_FS_T_BBB_MAX); 418184610Salfred 419184610Salfred mtx_destroy(&sc->sc_mtx); 420184610Salfred 421184610Salfred return (0); /* success */ 422184610Salfred} 423184610Salfred 424184610Salfredstatic int 425184610Salfredustorage_fs_suspend(device_t dev) 426184610Salfred{ 427184610Salfred device_printf(dev, "suspending\n"); 428184610Salfred return (0); /* success */ 429184610Salfred} 430184610Salfred 431184610Salfredstatic int 432184610Salfredustorage_fs_resume(device_t dev) 433184610Salfred{ 434184610Salfred device_printf(dev, "resuming\n"); 435184610Salfred return (0); /* success */ 436184610Salfred} 437184610Salfred 438184610Salfred/* 439184610Salfred * Generic functions to handle transfers 440184610Salfred */ 441184610Salfred 442184610Salfredstatic void 443184610Salfredustorage_fs_transfer_start(struct ustorage_fs_softc *sc, uint8_t xfer_index) 444184610Salfred{ 445184610Salfred if (sc->sc_xfer[xfer_index]) { 446184610Salfred sc->sc_last_xfer_index = xfer_index; 447184610Salfred usb2_transfer_start(sc->sc_xfer[xfer_index]); 448184610Salfred } 449184610Salfred} 450184610Salfred 451184610Salfredstatic void 452184610Salfredustorage_fs_transfer_stop(struct ustorage_fs_softc *sc) 453184610Salfred{ 454184610Salfred usb2_transfer_stop(sc->sc_xfer[sc->sc_last_xfer_index]); 455184610Salfred mtx_unlock(&sc->sc_mtx); 456184610Salfred usb2_transfer_drain(sc->sc_xfer[sc->sc_last_xfer_index]); 457184610Salfred mtx_lock(&sc->sc_mtx); 458184610Salfred} 459184610Salfred 460184610Salfredstatic int 461184610Salfredustorage_fs_handle_request(device_t dev, 462184610Salfred const void *preq, void **pptr, uint16_t *plen, 463184610Salfred uint16_t offset, uint8_t is_complete) 464184610Salfred{ 465184610Salfred struct ustorage_fs_softc *sc = device_get_softc(dev); 466192984Sthompsa const struct usb_device_request *req = preq; 467184610Salfred 468184610Salfred if (!is_complete) { 469192057Sthompsa if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) && 470192057Sthompsa (req->bRequest == UR_BBB_RESET)) { 471184610Salfred *plen = 0; 472184610Salfred mtx_lock(&sc->sc_mtx); 473184610Salfred ustorage_fs_transfer_stop(sc); 474184610Salfred sc->sc_transfer.data_error = 1; 475184610Salfred ustorage_fs_transfer_start(sc, 476184610Salfred USTORAGE_FS_T_BBB_COMMAND); 477184610Salfred mtx_unlock(&sc->sc_mtx); 478184610Salfred return (0); 479192057Sthompsa } else if ((req->bmRequestType == UT_READ_CLASS_INTERFACE) && 480192057Sthompsa (req->bRequest == UR_BBB_GET_MAX_LUN)) { 481184610Salfred if (offset == 0) { 482184610Salfred *plen = 1; 483184610Salfred *pptr = &sc->sc_last_lun; 484184610Salfred } else { 485184610Salfred *plen = 0; 486184610Salfred } 487184610Salfred return (0); 488184610Salfred } 489184610Salfred } 490184610Salfred return (ENXIO); /* use builtin handler */ 491184610Salfred} 492184610Salfred 493184610Salfredstatic void 494192984Sthompsaustorage_fs_t_bbb_command_callback(struct usb_xfer *xfer) 495184610Salfred{ 496184610Salfred struct ustorage_fs_softc *sc = xfer->priv_sc; 497184610Salfred uint32_t tag; 498184610Salfred uint8_t error = 0; 499184610Salfred 500184610Salfred DPRINTF("\n"); 501184610Salfred 502184610Salfred switch (USB_GET_STATE(xfer)) { 503184610Salfred case USB_ST_TRANSFERRED: 504184610Salfred 505184610Salfred tag = UGETDW(sc->sc_cbw.dCBWSignature); 506184610Salfred 507184610Salfred if (tag != CBWSIGNATURE) { 508184610Salfred /* do nothing */ 509184610Salfred DPRINTF("invalid signature 0x%08x\n", tag); 510184610Salfred break; 511184610Salfred } 512184610Salfred tag = UGETDW(sc->sc_cbw.dCBWTag); 513184610Salfred 514184610Salfred /* echo back tag */ 515184610Salfred USETDW(sc->sc_csw.dCSWTag, tag); 516184610Salfred 517184610Salfred /* reset status */ 518184610Salfred sc->sc_csw.bCSWStatus = 0; 519184610Salfred 520184610Salfred /* reset data offset, data length and data remainder */ 521184610Salfred sc->sc_transfer.offset = 0; 522184610Salfred sc->sc_transfer.data_rem = 523184610Salfred UGETDW(sc->sc_cbw.dCBWDataTransferLength); 524184610Salfred 525184610Salfred /* reset data flags */ 526184610Salfred sc->sc_transfer.data_short = 0; 527184610Salfred 528184610Salfred /* extract LUN */ 529184610Salfred sc->sc_transfer.lun = sc->sc_cbw.bCBWLUN; 530184610Salfred 531184610Salfred if (sc->sc_transfer.data_rem == 0) { 532184610Salfred sc->sc_transfer.cbw_dir = DIR_NONE; 533184610Salfred } else { 534184610Salfred if (sc->sc_cbw.bCBWFlags & CBWFLAGS_IN) { 535184610Salfred sc->sc_transfer.cbw_dir = DIR_WRITE; 536184610Salfred } else { 537184610Salfred sc->sc_transfer.cbw_dir = DIR_READ; 538184610Salfred } 539184610Salfred } 540184610Salfred 541184610Salfred sc->sc_transfer.cmd_len = sc->sc_cbw.bCDBLength; 542184610Salfred if ((sc->sc_transfer.cmd_len > sizeof(sc->sc_cbw.CBWCDB)) || 543184610Salfred (sc->sc_transfer.cmd_len == 0)) { 544184610Salfred /* just halt - this is invalid */ 545184610Salfred DPRINTF("invalid command length %d bytes\n", 546184610Salfred sc->sc_transfer.cmd_len); 547184610Salfred break; 548184610Salfred } 549184610Salfred 550184610Salfred error = ustorage_fs_do_cmd(sc); 551184610Salfred if (error) { 552184610Salfred /* got an error */ 553184610Salfred DPRINTF("command failed\n"); 554184610Salfred break; 555184610Salfred } 556184610Salfred if ((sc->sc_transfer.data_rem > 0) && 557184610Salfred (sc->sc_transfer.cbw_dir != sc->sc_transfer.cmd_dir)) { 558184610Salfred /* contradicting data transfer direction */ 559184610Salfred error = 1; 560184610Salfred DPRINTF("data direction mismatch\n"); 561184610Salfred break; 562184610Salfred } 563184610Salfred switch (sc->sc_transfer.cbw_dir) { 564184610Salfred case DIR_READ: 565184610Salfred ustorage_fs_transfer_start(sc, USTORAGE_FS_T_BBB_DATA_READ); 566184610Salfred break; 567184610Salfred case DIR_WRITE: 568184610Salfred ustorage_fs_transfer_start(sc, USTORAGE_FS_T_BBB_DATA_WRITE); 569184610Salfred break; 570184610Salfred default: 571184610Salfred ustorage_fs_transfer_start(sc, 572184610Salfred USTORAGE_FS_T_BBB_STATUS); 573184610Salfred break; 574184610Salfred } 575184610Salfred break; 576184610Salfred 577184610Salfred case USB_ST_SETUP: 578184610Salfredtr_setup: 579184610Salfred if (sc->sc_transfer.data_error) { 580184610Salfred sc->sc_transfer.data_error = 0; 581184610Salfred xfer->flags.stall_pipe = 1; 582184610Salfred DPRINTF("stall pipe\n"); 583184610Salfred } else { 584184610Salfred xfer->flags.stall_pipe = 0; 585184610Salfred } 586184610Salfred 587184610Salfred xfer->frlengths[0] = sizeof(sc->sc_cbw); 588184610Salfred usb2_set_frame_data(xfer, &sc->sc_cbw, 0); 589184610Salfred usb2_start_hardware(xfer); 590184610Salfred break; 591184610Salfred 592184610Salfred default: /* Error */ 593184610Salfred DPRINTF("error\n"); 594184610Salfred if (xfer->error == USB_ERR_CANCELLED) { 595184610Salfred break; 596184610Salfred } 597184610Salfred /* If the pipe is already stalled, don't do another stall */ 598184610Salfred if (!xfer->pipe->is_stalled) { 599184610Salfred sc->sc_transfer.data_error = 1; 600184610Salfred } 601184610Salfred /* try again */ 602184610Salfred goto tr_setup; 603184610Salfred } 604184610Salfred if (error) { 605184610Salfred if (sc->sc_csw.bCSWStatus == 0) { 606184610Salfred /* set some default error code */ 607184610Salfred sc->sc_csw.bCSWStatus = CSWSTATUS_FAILED; 608184610Salfred } 609184610Salfred if (sc->sc_transfer.cbw_dir == DIR_READ) { 610184610Salfred /* dump all data */ 611184610Salfred ustorage_fs_transfer_start(sc, 612184610Salfred USTORAGE_FS_T_BBB_DATA_DUMP); 613184610Salfred return; 614184610Salfred } 615184610Salfred if (sc->sc_transfer.cbw_dir == DIR_WRITE) { 616184610Salfred /* need to stall before status */ 617184610Salfred sc->sc_transfer.data_error = 1; 618184610Salfred } 619184610Salfred ustorage_fs_transfer_start(sc, USTORAGE_FS_T_BBB_STATUS); 620184610Salfred } 621184610Salfred} 622184610Salfred 623184610Salfredstatic void 624192984Sthompsaustorage_fs_t_bbb_data_dump_callback(struct usb_xfer *xfer) 625184610Salfred{ 626184610Salfred struct ustorage_fs_softc *sc = xfer->priv_sc; 627184610Salfred uint32_t max_bulk = xfer->max_data_length; 628184610Salfred 629184610Salfred DPRINTF("\n"); 630184610Salfred 631184610Salfred switch (USB_GET_STATE(xfer)) { 632184610Salfred case USB_ST_TRANSFERRED: 633184610Salfred sc->sc_transfer.data_rem -= xfer->actlen; 634184610Salfred sc->sc_transfer.offset += xfer->actlen; 635184610Salfred 636184610Salfred if ((xfer->actlen != xfer->sumlen) || 637184610Salfred (sc->sc_transfer.data_rem == 0)) { 638184610Salfred /* short transfer or end of data */ 639184610Salfred ustorage_fs_transfer_start(sc, 640184610Salfred USTORAGE_FS_T_BBB_STATUS); 641184610Salfred break; 642184610Salfred } 643184610Salfred /* Fallthrough */ 644184610Salfred 645184610Salfred case USB_ST_SETUP: 646184610Salfredtr_setup: 647184610Salfred if (max_bulk > sc->sc_transfer.data_rem) { 648184610Salfred max_bulk = sc->sc_transfer.data_rem; 649184610Salfred } 650184610Salfred if (sc->sc_transfer.data_error) { 651184610Salfred sc->sc_transfer.data_error = 0; 652184610Salfred xfer->flags.stall_pipe = 1; 653184610Salfred } else { 654184610Salfred xfer->flags.stall_pipe = 0; 655184610Salfred } 656184610Salfred xfer->frlengths[0] = max_bulk; 657184610Salfred usb2_start_hardware(xfer); 658184610Salfred break; 659184610Salfred 660184610Salfred default: /* Error */ 661184610Salfred if (xfer->error == USB_ERR_CANCELLED) { 662184610Salfred break; 663184610Salfred } 664184610Salfred /* 665184610Salfred * If the pipe is already stalled, don't do another stall: 666184610Salfred */ 667184610Salfred if (!xfer->pipe->is_stalled) { 668184610Salfred sc->sc_transfer.data_error = 1; 669184610Salfred } 670184610Salfred /* try again */ 671184610Salfred goto tr_setup; 672184610Salfred } 673184610Salfred} 674184610Salfred 675184610Salfredstatic void 676192984Sthompsaustorage_fs_t_bbb_data_read_callback(struct usb_xfer *xfer) 677184610Salfred{ 678184610Salfred struct ustorage_fs_softc *sc = xfer->priv_sc; 679184610Salfred uint32_t max_bulk = xfer->max_data_length; 680184610Salfred 681184610Salfred DPRINTF("\n"); 682184610Salfred 683184610Salfred switch (USB_GET_STATE(xfer)) { 684184610Salfred case USB_ST_TRANSFERRED: 685184610Salfred sc->sc_transfer.data_rem -= xfer->actlen; 686184610Salfred sc->sc_transfer.data_ptr += xfer->actlen; 687184610Salfred sc->sc_transfer.offset += xfer->actlen; 688184610Salfred 689184610Salfred if ((xfer->actlen != xfer->sumlen) || 690184610Salfred (sc->sc_transfer.data_rem == 0)) { 691184610Salfred /* short transfer or end of data */ 692184610Salfred ustorage_fs_transfer_start(sc, 693184610Salfred USTORAGE_FS_T_BBB_STATUS); 694184610Salfred break; 695184610Salfred } 696184610Salfred /* Fallthrough */ 697184610Salfred 698184610Salfred case USB_ST_SETUP: 699184610Salfredtr_setup: 700184610Salfred if (max_bulk > sc->sc_transfer.data_rem) { 701184610Salfred max_bulk = sc->sc_transfer.data_rem; 702184610Salfred } 703184610Salfred if (sc->sc_transfer.data_error) { 704184610Salfred sc->sc_transfer.data_error = 0; 705184610Salfred xfer->flags.stall_pipe = 1; 706184610Salfred } else { 707184610Salfred xfer->flags.stall_pipe = 0; 708184610Salfred } 709184610Salfred 710184610Salfred xfer->frlengths[0] = max_bulk; 711184610Salfred usb2_set_frame_data(xfer, sc->sc_transfer.data_ptr, 0); 712184610Salfred usb2_start_hardware(xfer); 713184610Salfred break; 714184610Salfred 715184610Salfred default: /* Error */ 716184610Salfred if (xfer->error == USB_ERR_CANCELLED) { 717184610Salfred break; 718184610Salfred } 719184610Salfred /* If the pipe is already stalled, don't do another stall */ 720184610Salfred if (!xfer->pipe->is_stalled) { 721184610Salfred sc->sc_transfer.data_error = 1; 722184610Salfred } 723184610Salfred /* try again */ 724184610Salfred goto tr_setup; 725184610Salfred } 726184610Salfred} 727184610Salfred 728184610Salfredstatic void 729192984Sthompsaustorage_fs_t_bbb_data_write_callback(struct usb_xfer *xfer) 730184610Salfred{ 731184610Salfred struct ustorage_fs_softc *sc = xfer->priv_sc; 732184610Salfred uint32_t max_bulk = xfer->max_data_length; 733184610Salfred 734184610Salfred DPRINTF("\n"); 735184610Salfred 736184610Salfred switch (USB_GET_STATE(xfer)) { 737184610Salfred case USB_ST_TRANSFERRED: 738184610Salfred sc->sc_transfer.data_rem -= xfer->actlen; 739184610Salfred sc->sc_transfer.data_ptr += xfer->actlen; 740184610Salfred sc->sc_transfer.offset += xfer->actlen; 741184610Salfred 742184610Salfred if ((xfer->actlen != xfer->sumlen) || 743184610Salfred (sc->sc_transfer.data_rem == 0)) { 744184610Salfred /* short transfer or end of data */ 745184610Salfred ustorage_fs_transfer_start(sc, 746184610Salfred USTORAGE_FS_T_BBB_STATUS); 747184610Salfred break; 748184610Salfred } 749184610Salfred case USB_ST_SETUP: 750184610Salfredtr_setup: 751184610Salfred if (max_bulk >= sc->sc_transfer.data_rem) { 752184610Salfred max_bulk = sc->sc_transfer.data_rem; 753184610Salfred if (sc->sc_transfer.data_short) { 754184610Salfred xfer->flags.force_short_xfer = 1; 755184610Salfred } else { 756184610Salfred xfer->flags.force_short_xfer = 0; 757184610Salfred } 758184610Salfred } else { 759184610Salfred xfer->flags.force_short_xfer = 0; 760184610Salfred } 761184610Salfred 762184610Salfred if (sc->sc_transfer.data_error) { 763184610Salfred sc->sc_transfer.data_error = 0; 764184610Salfred xfer->flags.stall_pipe = 1; 765184610Salfred } else { 766184610Salfred xfer->flags.stall_pipe = 0; 767184610Salfred } 768184610Salfred 769184610Salfred xfer->frlengths[0] = max_bulk; 770184610Salfred usb2_set_frame_data(xfer, sc->sc_transfer.data_ptr, 0); 771184610Salfred usb2_start_hardware(xfer); 772184610Salfred break; 773184610Salfred 774184610Salfred default: /* Error */ 775184610Salfred if (xfer->error == USB_ERR_CANCELLED) { 776184610Salfred break; 777184610Salfred } 778184610Salfred /* 779184610Salfred * If the pipe is already stalled, don't do another 780184610Salfred * stall 781184610Salfred */ 782184610Salfred if (!xfer->pipe->is_stalled) { 783184610Salfred sc->sc_transfer.data_error = 1; 784184610Salfred } 785184610Salfred /* try again */ 786184610Salfred goto tr_setup; 787184610Salfred } 788184610Salfred} 789184610Salfred 790184610Salfredstatic void 791192984Sthompsaustorage_fs_t_bbb_status_callback(struct usb_xfer *xfer) 792184610Salfred{ 793184610Salfred struct ustorage_fs_softc *sc = xfer->priv_sc; 794184610Salfred 795184610Salfred DPRINTF("\n"); 796184610Salfred 797184610Salfred switch (USB_GET_STATE(xfer)) { 798184610Salfred case USB_ST_TRANSFERRED: 799184610Salfred ustorage_fs_transfer_start(sc, USTORAGE_FS_T_BBB_COMMAND); 800184610Salfred break; 801184610Salfred 802184610Salfred case USB_ST_SETUP: 803184610Salfredtr_setup: 804184610Salfred USETDW(sc->sc_csw.dCSWSignature, CSWSIGNATURE); 805184610Salfred USETDW(sc->sc_csw.dCSWDataResidue, sc->sc_transfer.data_rem); 806184610Salfred 807184610Salfred if (sc->sc_transfer.data_error) { 808184610Salfred sc->sc_transfer.data_error = 0; 809184610Salfred xfer->flags.stall_pipe = 1; 810184610Salfred } else { 811184610Salfred xfer->flags.stall_pipe = 0; 812184610Salfred } 813184610Salfred 814184610Salfred xfer->frlengths[0] = sizeof(sc->sc_csw); 815184610Salfred usb2_set_frame_data(xfer, &sc->sc_csw, 0); 816184610Salfred usb2_start_hardware(xfer); 817184610Salfred break; 818184610Salfred 819184610Salfred default: 820184610Salfred if (xfer->error == USB_ERR_CANCELLED) { 821184610Salfred break; 822184610Salfred } 823184610Salfred /* If the pipe is already stalled, don't do another stall */ 824184610Salfred if (!xfer->pipe->is_stalled) { 825184610Salfred sc->sc_transfer.data_error = 1; 826184610Salfred } 827184610Salfred /* try again */ 828184610Salfred goto tr_setup; 829184610Salfred } 830184610Salfred} 831184610Salfred 832184610Salfred/* SCSI commands that we recognize */ 833184610Salfred#define SC_FORMAT_UNIT 0x04 834184610Salfred#define SC_INQUIRY 0x12 835184610Salfred#define SC_MODE_SELECT_6 0x15 836184610Salfred#define SC_MODE_SELECT_10 0x55 837184610Salfred#define SC_MODE_SENSE_6 0x1a 838184610Salfred#define SC_MODE_SENSE_10 0x5a 839184610Salfred#define SC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e 840184610Salfred#define SC_READ_6 0x08 841184610Salfred#define SC_READ_10 0x28 842184610Salfred#define SC_READ_12 0xa8 843184610Salfred#define SC_READ_CAPACITY 0x25 844184610Salfred#define SC_READ_FORMAT_CAPACITIES 0x23 845184610Salfred#define SC_RELEASE 0x17 846184610Salfred#define SC_REQUEST_SENSE 0x03 847184610Salfred#define SC_RESERVE 0x16 848184610Salfred#define SC_SEND_DIAGNOSTIC 0x1d 849184610Salfred#define SC_START_STOP_UNIT 0x1b 850184610Salfred#define SC_SYNCHRONIZE_CACHE 0x35 851184610Salfred#define SC_TEST_UNIT_READY 0x00 852184610Salfred#define SC_VERIFY 0x2f 853184610Salfred#define SC_WRITE_6 0x0a 854184610Salfred#define SC_WRITE_10 0x2a 855184610Salfred#define SC_WRITE_12 0xaa 856184610Salfred 857184610Salfred/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */ 858184610Salfred#define SS_NO_SENSE 0 859184610Salfred#define SS_COMMUNICATION_FAILURE 0x040800 860184610Salfred#define SS_INVALID_COMMAND 0x052000 861184610Salfred#define SS_INVALID_FIELD_IN_CDB 0x052400 862184610Salfred#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100 863184610Salfred#define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500 864184610Salfred#define SS_MEDIUM_NOT_PRESENT 0x023a00 865184610Salfred#define SS_MEDIUM_REMOVAL_PREVENTED 0x055302 866184610Salfred#define SS_NOT_READY_TO_READY_TRANSITION 0x062800 867184610Salfred#define SS_RESET_OCCURRED 0x062900 868184610Salfred#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900 869184610Salfred#define SS_UNRECOVERED_READ_ERROR 0x031100 870184610Salfred#define SS_WRITE_ERROR 0x030c02 871184610Salfred#define SS_WRITE_PROTECTED 0x072700 872184610Salfred 873184610Salfred#define SK(x) ((uint8_t) ((x) >> 16)) /* Sense Key byte, etc. */ 874184610Salfred#define ASC(x) ((uint8_t) ((x) >> 8)) 875184610Salfred#define ASCQ(x) ((uint8_t) (x)) 876184610Salfred 877184610Salfred/* Routines for unaligned data access */ 878184610Salfred 879184610Salfredstatic uint16_t 880184610Salfredget_be16(uint8_t *buf) 881184610Salfred{ 882184610Salfred return ((uint16_t)buf[0] << 8) | ((uint16_t)buf[1]); 883184610Salfred} 884184610Salfred 885184610Salfredstatic uint32_t 886184610Salfredget_be32(uint8_t *buf) 887184610Salfred{ 888184610Salfred return ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16) | 889184610Salfred ((uint32_t)buf[2] << 8) | ((uint32_t)buf[3]); 890184610Salfred} 891184610Salfred 892184610Salfredstatic void 893184610Salfredput_be16(uint8_t *buf, uint16_t val) 894184610Salfred{ 895184610Salfred buf[0] = val >> 8; 896184610Salfred buf[1] = val; 897184610Salfred} 898184610Salfred 899184610Salfredstatic void 900184610Salfredput_be32(uint8_t *buf, uint32_t val) 901184610Salfred{ 902184610Salfred buf[0] = val >> 24; 903184610Salfred buf[1] = val >> 16; 904184610Salfred buf[2] = val >> 8; 905184610Salfred buf[3] = val & 0xff; 906184610Salfred} 907184610Salfred 908184610Salfred/*------------------------------------------------------------------------* 909184610Salfred * ustorage_fs_verify 910184610Salfred * 911184610Salfred * Returns: 912184610Salfred * 0: Success 913184610Salfred * Else: Failure 914184610Salfred *------------------------------------------------------------------------*/ 915184610Salfredstatic uint8_t 916184610Salfredustorage_fs_verify(struct ustorage_fs_softc *sc) 917184610Salfred{ 918184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 919184610Salfred uint32_t lba; 920184610Salfred uint32_t vlen; 921184610Salfred uint64_t file_offset; 922184610Salfred uint64_t amount_left; 923184610Salfred 924184610Salfred /* 925184610Salfred * Get the starting Logical Block Address 926184610Salfred */ 927190733Sthompsa lba = get_be32(&sc->sc_cmd_data[2]); 928184610Salfred 929184610Salfred /* 930184610Salfred * We allow DPO (Disable Page Out = don't save data in the cache) 931184610Salfred * but we don't implement it. 932184610Salfred */ 933190733Sthompsa if ((sc->sc_cmd_data[1] & ~0x10) != 0) { 934184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 935184610Salfred return (1); 936184610Salfred } 937190733Sthompsa vlen = get_be16(&sc->sc_cmd_data[7]); 938184610Salfred if (vlen == 0) { 939184610Salfred goto done; 940184610Salfred } 941184610Salfred /* No default reply */ 942184610Salfred 943184610Salfred /* Prepare to carry out the file verify */ 944184610Salfred amount_left = vlen; 945184610Salfred amount_left <<= 9; 946184610Salfred file_offset = lba; 947184610Salfred file_offset <<= 9; 948184610Salfred 949184610Salfred /* Range check */ 950184610Salfred vlen += lba; 951184610Salfred 952184610Salfred if ((vlen < lba) || 953184610Salfred (vlen > currlun->num_sectors) || 954184610Salfred (lba >= currlun->num_sectors)) { 955184610Salfred currlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 956184610Salfred return (1); 957184610Salfred } 958184610Salfred /* XXX TODO: verify that data is readable */ 959184610Salfreddone: 960184610Salfred return (ustorage_fs_min_len(sc, 0, 0 - 1)); 961184610Salfred} 962184610Salfred 963184610Salfred/*------------------------------------------------------------------------* 964184610Salfred * ustorage_fs_inquiry 965184610Salfred * 966184610Salfred * Returns: 967184610Salfred * 0: Success 968184610Salfred * Else: Failure 969184610Salfred *------------------------------------------------------------------------*/ 970184610Salfredstatic uint8_t 971184610Salfredustorage_fs_inquiry(struct ustorage_fs_softc *sc) 972184610Salfred{ 973184610Salfred uint8_t *buf = sc->sc_transfer.data_ptr; 974184610Salfred 975184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 976184610Salfred 977184610Salfred if (!sc->sc_transfer.currlun) { 978184610Salfred /* Unsupported LUNs are okay */ 979184610Salfred memset(buf, 0, 36); 980184610Salfred buf[0] = 0x7f; 981184610Salfred /* Unsupported, no device - type */ 982184610Salfred return (ustorage_fs_min_len(sc, 36, 0 - 1)); 983184610Salfred } 984184610Salfred memset(buf, 0, 8); 985184610Salfred /* Non - removable, direct - access device */ 986184610Salfred if (currlun->removable) 987184610Salfred buf[1] = 0x80; 988184610Salfred buf[2] = 2; 989184610Salfred /* ANSI SCSI level 2 */ 990184610Salfred buf[3] = 2; 991184610Salfred /* SCSI - 2 INQUIRY data format */ 992184610Salfred buf[4] = 31; 993184610Salfred /* Additional length */ 994184610Salfred /* No special options */ 995190719Sthompsa /* Copy in ID string */ 996190719Sthompsa memcpy(buf + 8, USTORAGE_FS_ID_STRING, 28); 997190719Sthompsa 998190733Sthompsa#if (USTORAGE_QDATA_MAX < 36) 999190733Sthompsa#error "(USTORAGE_QDATA_MAX < 36)" 1000190733Sthompsa#endif 1001184610Salfred return (ustorage_fs_min_len(sc, 36, 0 - 1)); 1002184610Salfred} 1003184610Salfred 1004184610Salfred/*------------------------------------------------------------------------* 1005184610Salfred * ustorage_fs_request_sense 1006184610Salfred * 1007184610Salfred * Returns: 1008184610Salfred * 0: Success 1009184610Salfred * Else: Failure 1010184610Salfred *------------------------------------------------------------------------*/ 1011184610Salfredstatic uint8_t 1012184610Salfredustorage_fs_request_sense(struct ustorage_fs_softc *sc) 1013184610Salfred{ 1014184610Salfred uint8_t *buf = sc->sc_transfer.data_ptr; 1015184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1016184610Salfred uint32_t sd; 1017184610Salfred uint32_t sdinfo; 1018184610Salfred uint8_t valid; 1019184610Salfred 1020184610Salfred /* 1021184610Salfred * From the SCSI-2 spec., section 7.9 (Unit attention condition): 1022184610Salfred * 1023184610Salfred * If a REQUEST SENSE command is received from an initiator 1024184610Salfred * with a pending unit attention condition (before the target 1025184610Salfred * generates the contingent allegiance condition), then the 1026184610Salfred * target shall either: 1027184610Salfred * a) report any pending sense data and preserve the unit 1028184610Salfred * attention condition on the logical unit, or, 1029184610Salfred * b) report the unit attention condition, may discard any 1030184610Salfred * pending sense data, and clear the unit attention 1031184610Salfred * condition on the logical unit for that initiator. 1032184610Salfred * 1033184610Salfred * FSG normally uses option a); enable this code to use option b). 1034184610Salfred */ 1035184610Salfred#if 0 1036184610Salfred if (currlun && currlun->unit_attention_data != SS_NO_SENSE) { 1037184610Salfred currlun->sense_data = currlun->unit_attention_data; 1038184610Salfred currlun->unit_attention_data = SS_NO_SENSE; 1039184610Salfred } 1040184610Salfred#endif 1041184610Salfred 1042184610Salfred if (!currlun) { 1043184610Salfred /* Unsupported LUNs are okay */ 1044184610Salfred sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; 1045184610Salfred sdinfo = 0; 1046184610Salfred valid = 0; 1047184610Salfred } else { 1048184610Salfred sd = currlun->sense_data; 1049184610Salfred sdinfo = currlun->sense_data_info; 1050184610Salfred valid = currlun->info_valid << 7; 1051184610Salfred currlun->sense_data = SS_NO_SENSE; 1052184610Salfred currlun->sense_data_info = 0; 1053184610Salfred currlun->info_valid = 0; 1054184610Salfred } 1055184610Salfred 1056184610Salfred memset(buf, 0, 18); 1057184610Salfred buf[0] = valid | 0x70; 1058184610Salfred /* Valid, current error */ 1059184610Salfred buf[2] = SK(sd); 1060184610Salfred put_be32(&buf[3], sdinfo); 1061184610Salfred /* Sense information */ 1062184610Salfred buf[7] = 18 - 8; 1063184610Salfred /* Additional sense length */ 1064184610Salfred buf[12] = ASC(sd); 1065184610Salfred buf[13] = ASCQ(sd); 1066190733Sthompsa 1067190733Sthompsa#if (USTORAGE_QDATA_MAX < 18) 1068190733Sthompsa#error "(USTORAGE_QDATA_MAX < 18)" 1069190733Sthompsa#endif 1070184610Salfred return (ustorage_fs_min_len(sc, 18, 0 - 1)); 1071184610Salfred} 1072184610Salfred 1073184610Salfred/*------------------------------------------------------------------------* 1074184610Salfred * ustorage_fs_read_capacity 1075184610Salfred * 1076184610Salfred * Returns: 1077184610Salfred * 0: Success 1078184610Salfred * Else: Failure 1079184610Salfred *------------------------------------------------------------------------*/ 1080184610Salfredstatic uint8_t 1081184610Salfredustorage_fs_read_capacity(struct ustorage_fs_softc *sc) 1082184610Salfred{ 1083184610Salfred uint8_t *buf = sc->sc_transfer.data_ptr; 1084184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1085190733Sthompsa uint32_t lba = get_be32(&sc->sc_cmd_data[2]); 1086190733Sthompsa uint8_t pmi = sc->sc_cmd_data[8]; 1087184610Salfred 1088184610Salfred /* Check the PMI and LBA fields */ 1089184610Salfred if ((pmi > 1) || ((pmi == 0) && (lba != 0))) { 1090184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 1091184610Salfred return (1); 1092184610Salfred } 1093190733Sthompsa /* Max logical block */ 1094184610Salfred put_be32(&buf[0], currlun->num_sectors - 1); 1095190733Sthompsa /* Block length */ 1096184610Salfred put_be32(&buf[4], 512); 1097190733Sthompsa 1098190733Sthompsa#if (USTORAGE_QDATA_MAX < 8) 1099190733Sthompsa#error "(USTORAGE_QDATA_MAX < 8)" 1100190733Sthompsa#endif 1101184610Salfred return (ustorage_fs_min_len(sc, 8, 0 - 1)); 1102184610Salfred} 1103184610Salfred 1104184610Salfred/*------------------------------------------------------------------------* 1105184610Salfred * ustorage_fs_mode_sense 1106184610Salfred * 1107184610Salfred * Returns: 1108184610Salfred * 0: Success 1109184610Salfred * Else: Failure 1110184610Salfred *------------------------------------------------------------------------*/ 1111184610Salfredstatic uint8_t 1112184610Salfredustorage_fs_mode_sense(struct ustorage_fs_softc *sc) 1113184610Salfred{ 1114184610Salfred uint8_t *buf = sc->sc_transfer.data_ptr; 1115184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1116184610Salfred uint8_t *buf0; 1117184610Salfred uint16_t len; 1118184610Salfred uint16_t limit; 1119190733Sthompsa uint8_t mscmnd = sc->sc_cmd_data[0]; 1120184610Salfred uint8_t pc; 1121184610Salfred uint8_t page_code; 1122184610Salfred uint8_t changeable_values; 1123184610Salfred uint8_t all_pages; 1124184610Salfred 1125184610Salfred buf0 = buf; 1126184610Salfred 1127190733Sthompsa if ((sc->sc_cmd_data[1] & ~0x08) != 0) { 1128184610Salfred /* Mask away DBD */ 1129184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 1130184610Salfred return (1); 1131184610Salfred } 1132190733Sthompsa pc = sc->sc_cmd_data[2] >> 6; 1133190733Sthompsa page_code = sc->sc_cmd_data[2] & 0x3f; 1134184610Salfred if (pc == 3) { 1135184610Salfred currlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; 1136184610Salfred return (1); 1137184610Salfred } 1138184610Salfred changeable_values = (pc == 1); 1139184610Salfred all_pages = (page_code == 0x3f); 1140184610Salfred 1141184610Salfred /* 1142184610Salfred * Write the mode parameter header. Fixed values are: default 1143184610Salfred * medium type, no cache control (DPOFUA), and no block descriptors. 1144184610Salfred * The only variable value is the WriteProtect bit. We will fill in 1145184610Salfred * the mode data length later. 1146184610Salfred */ 1147184610Salfred memset(buf, 0, 8); 1148184610Salfred if (mscmnd == SC_MODE_SENSE_6) { 1149184610Salfred buf[2] = (currlun->read_only ? 0x80 : 0x00); 1150184610Salfred /* WP, DPOFUA */ 1151184610Salfred buf += 4; 1152184610Salfred limit = 255; 1153184610Salfred } else { 1154184610Salfred /* SC_MODE_SENSE_10 */ 1155184610Salfred buf[3] = (currlun->read_only ? 0x80 : 0x00); 1156184610Salfred /* WP, DPOFUA */ 1157184610Salfred buf += 8; 1158184610Salfred limit = 65535; 1159184610Salfred /* Should really be mod_data.buflen */ 1160184610Salfred } 1161184610Salfred 1162184610Salfred /* No block descriptors */ 1163184610Salfred 1164184610Salfred /* 1165184610Salfred * The mode pages, in numerical order. 1166184610Salfred */ 1167184610Salfred if ((page_code == 0x08) || all_pages) { 1168184610Salfred buf[0] = 0x08; 1169184610Salfred /* Page code */ 1170184610Salfred buf[1] = 10; 1171184610Salfred /* Page length */ 1172184610Salfred memset(buf + 2, 0, 10); 1173184610Salfred /* None of the fields are changeable */ 1174184610Salfred 1175184610Salfred if (!changeable_values) { 1176184610Salfred buf[2] = 0x04; 1177184610Salfred /* Write cache enable, */ 1178184610Salfred /* Read cache not disabled */ 1179184610Salfred /* No cache retention priorities */ 1180184610Salfred put_be16(&buf[4], 0xffff); 1181184610Salfred /* Don 't disable prefetch */ 1182184610Salfred /* Minimum prefetch = 0 */ 1183184610Salfred put_be16(&buf[8], 0xffff); 1184184610Salfred /* Maximum prefetch */ 1185184610Salfred put_be16(&buf[10], 0xffff); 1186184610Salfred /* Maximum prefetch ceiling */ 1187184610Salfred } 1188184610Salfred buf += 12; 1189184610Salfred } 1190184610Salfred /* 1191184610Salfred * Check that a valid page was requested and the mode data length 1192184610Salfred * isn't too long. 1193184610Salfred */ 1194184610Salfred len = buf - buf0; 1195184610Salfred if (len > limit) { 1196184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 1197184610Salfred return (1); 1198184610Salfred } 1199184610Salfred /* Store the mode data length */ 1200184610Salfred if (mscmnd == SC_MODE_SENSE_6) 1201184610Salfred buf0[0] = len - 1; 1202184610Salfred else 1203184610Salfred put_be16(buf0, len - 2); 1204190733Sthompsa 1205190733Sthompsa#if (USTORAGE_QDATA_MAX < 24) 1206190733Sthompsa#error "(USTORAGE_QDATA_MAX < 24)" 1207190733Sthompsa#endif 1208184610Salfred return (ustorage_fs_min_len(sc, len, 0 - 1)); 1209184610Salfred} 1210184610Salfred 1211184610Salfred/*------------------------------------------------------------------------* 1212184610Salfred * ustorage_fs_start_stop 1213184610Salfred * 1214184610Salfred * Returns: 1215184610Salfred * 0: Success 1216184610Salfred * Else: Failure 1217184610Salfred *------------------------------------------------------------------------*/ 1218184610Salfredstatic uint8_t 1219184610Salfredustorage_fs_start_stop(struct ustorage_fs_softc *sc) 1220184610Salfred{ 1221184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1222184610Salfred uint8_t loej; 1223184610Salfred uint8_t start; 1224184610Salfred uint8_t immed; 1225184610Salfred 1226184610Salfred if (!currlun->removable) { 1227184610Salfred currlun->sense_data = SS_INVALID_COMMAND; 1228184610Salfred return (1); 1229184610Salfred } 1230190733Sthompsa immed = sc->sc_cmd_data[1] & 0x01; 1231190733Sthompsa loej = sc->sc_cmd_data[4] & 0x02; 1232190733Sthompsa start = sc->sc_cmd_data[4] & 0x01; 1233184610Salfred 1234184610Salfred if (immed || loej || start) { 1235184610Salfred /* compile fix */ 1236184610Salfred } 1237184610Salfred return (0); 1238184610Salfred} 1239184610Salfred 1240184610Salfred/*------------------------------------------------------------------------* 1241184610Salfred * ustorage_fs_prevent_allow 1242184610Salfred * 1243184610Salfred * Returns: 1244184610Salfred * 0: Success 1245184610Salfred * Else: Failure 1246184610Salfred *------------------------------------------------------------------------*/ 1247184610Salfredstatic uint8_t 1248184610Salfredustorage_fs_prevent_allow(struct ustorage_fs_softc *sc) 1249184610Salfred{ 1250184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1251184610Salfred uint8_t prevent; 1252184610Salfred 1253184610Salfred if (!currlun->removable) { 1254184610Salfred currlun->sense_data = SS_INVALID_COMMAND; 1255184610Salfred return (1); 1256184610Salfred } 1257190733Sthompsa prevent = sc->sc_cmd_data[4] & 0x01; 1258190733Sthompsa if ((sc->sc_cmd_data[4] & ~0x01) != 0) { 1259184610Salfred /* Mask away Prevent */ 1260184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 1261184610Salfred return (1); 1262184610Salfred } 1263184610Salfred if (currlun->prevent_medium_removal && !prevent) { 1264184610Salfred //fsync_sub(currlun); 1265184610Salfred } 1266184610Salfred currlun->prevent_medium_removal = prevent; 1267184610Salfred return (0); 1268184610Salfred} 1269184610Salfred 1270184610Salfred/*------------------------------------------------------------------------* 1271184610Salfred * ustorage_fs_read_format_capacities 1272184610Salfred * 1273184610Salfred * Returns: 1274184610Salfred * 0: Success 1275184610Salfred * Else: Failure 1276184610Salfred *------------------------------------------------------------------------*/ 1277184610Salfredstatic uint8_t 1278184610Salfredustorage_fs_read_format_capacities(struct ustorage_fs_softc *sc) 1279184610Salfred{ 1280184610Salfred uint8_t *buf = sc->sc_transfer.data_ptr; 1281184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1282184610Salfred 1283184610Salfred buf[0] = buf[1] = buf[2] = 0; 1284184610Salfred buf[3] = 8; 1285184610Salfred /* Only the Current / Maximum Capacity Descriptor */ 1286184610Salfred buf += 4; 1287184610Salfred 1288190733Sthompsa /* Number of blocks */ 1289184610Salfred put_be32(&buf[0], currlun->num_sectors); 1290190733Sthompsa /* Block length */ 1291184610Salfred put_be32(&buf[4], 512); 1292190733Sthompsa /* Current capacity */ 1293184610Salfred buf[4] = 0x02; 1294190733Sthompsa 1295190733Sthompsa#if (USTORAGE_QDATA_MAX < 12) 1296190733Sthompsa#error "(USTORAGE_QDATA_MAX < 12)" 1297190733Sthompsa#endif 1298184610Salfred return (ustorage_fs_min_len(sc, 12, 0 - 1)); 1299184610Salfred} 1300184610Salfred 1301184610Salfred/*------------------------------------------------------------------------* 1302184610Salfred * ustorage_fs_mode_select 1303184610Salfred * 1304184610Salfred * Return values: 1305184610Salfred * 0: Success 1306184610Salfred * Else: Failure 1307184610Salfred *------------------------------------------------------------------------*/ 1308184610Salfredstatic uint8_t 1309184610Salfredustorage_fs_mode_select(struct ustorage_fs_softc *sc) 1310184610Salfred{ 1311184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1312184610Salfred 1313184610Salfred /* We don't support MODE SELECT */ 1314184610Salfred currlun->sense_data = SS_INVALID_COMMAND; 1315184610Salfred return (1); 1316184610Salfred} 1317184610Salfred 1318184610Salfred/*------------------------------------------------------------------------* 1319184610Salfred * ustorage_fs_synchronize_cache 1320184610Salfred * 1321184610Salfred * Return values: 1322184610Salfred * 0: Success 1323184610Salfred * Else: Failure 1324184610Salfred *------------------------------------------------------------------------*/ 1325184610Salfredstatic uint8_t 1326184610Salfredustorage_fs_synchronize_cache(struct ustorage_fs_softc *sc) 1327184610Salfred{ 1328186730Salfred#if 0 1329184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1330184610Salfred uint8_t rc; 1331184610Salfred 1332184610Salfred /* 1333184610Salfred * We ignore the requested LBA and write out all dirty data buffers. 1334184610Salfred */ 1335184610Salfred rc = 0; 1336184610Salfred if (rc) { 1337184610Salfred currlun->sense_data = SS_WRITE_ERROR; 1338184610Salfred } 1339186730Salfred#endif 1340184610Salfred return (0); 1341184610Salfred} 1342184610Salfred 1343184610Salfred/*------------------------------------------------------------------------* 1344184610Salfred * ustorage_fs_read - read data from disk 1345184610Salfred * 1346184610Salfred * Return values: 1347184610Salfred * 0: Success 1348184610Salfred * Else: Failure 1349184610Salfred *------------------------------------------------------------------------*/ 1350184610Salfredstatic uint8_t 1351184610Salfredustorage_fs_read(struct ustorage_fs_softc *sc) 1352184610Salfred{ 1353184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1354184610Salfred uint64_t file_offset; 1355184610Salfred uint32_t lba; 1356184610Salfred uint32_t len; 1357184610Salfred 1358184610Salfred /* 1359184610Salfred * Get the starting Logical Block Address and check that it's not 1360184610Salfred * too big 1361184610Salfred */ 1362190733Sthompsa if (sc->sc_cmd_data[0] == SC_READ_6) { 1363190733Sthompsa lba = (((uint32_t)sc->sc_cmd_data[1]) << 16) | 1364190733Sthompsa get_be16(&sc->sc_cmd_data[2]); 1365184610Salfred } else { 1366190733Sthompsa lba = get_be32(&sc->sc_cmd_data[2]); 1367184610Salfred 1368184610Salfred /* 1369184610Salfred * We allow DPO (Disable Page Out = don't save data in the 1370184610Salfred * cache) and FUA (Force Unit Access = don't read from the 1371184610Salfred * cache), but we don't implement them. 1372184610Salfred */ 1373190733Sthompsa if ((sc->sc_cmd_data[1] & ~0x18) != 0) { 1374184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 1375184610Salfred return (1); 1376184610Salfred } 1377184610Salfred } 1378184610Salfred len = sc->sc_transfer.data_rem >> 9; 1379184610Salfred len += lba; 1380184610Salfred 1381184610Salfred if ((len < lba) || 1382184610Salfred (len > currlun->num_sectors) || 1383184610Salfred (lba >= currlun->num_sectors)) { 1384184610Salfred currlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 1385184610Salfred return (1); 1386184610Salfred } 1387184610Salfred file_offset = lba; 1388184610Salfred file_offset <<= 9; 1389184610Salfred 1390190181Sthompsa sc->sc_transfer.data_ptr = currlun->memory_image + file_offset; 1391184610Salfred 1392184610Salfred return (0); 1393184610Salfred} 1394184610Salfred 1395184610Salfred/*------------------------------------------------------------------------* 1396184610Salfred * ustorage_fs_write - write data to disk 1397184610Salfred * 1398184610Salfred * Return values: 1399184610Salfred * 0: Success 1400184610Salfred * Else: Failure 1401184610Salfred *------------------------------------------------------------------------*/ 1402184610Salfredstatic uint8_t 1403184610Salfredustorage_fs_write(struct ustorage_fs_softc *sc) 1404184610Salfred{ 1405184610Salfred struct ustorage_fs_lun *currlun = sc->sc_transfer.currlun; 1406184610Salfred uint64_t file_offset; 1407184610Salfred uint32_t lba; 1408184610Salfred uint32_t len; 1409184610Salfred 1410184610Salfred if (currlun->read_only) { 1411184610Salfred currlun->sense_data = SS_WRITE_PROTECTED; 1412184610Salfred return (1); 1413184610Salfred } 1414184610Salfred /* XXX clear SYNC */ 1415184610Salfred 1416184610Salfred /* 1417184610Salfred * Get the starting Logical Block Address and check that it's not 1418184610Salfred * too big. 1419184610Salfred */ 1420190733Sthompsa if (sc->sc_cmd_data[0] == SC_WRITE_6) 1421190733Sthompsa lba = (((uint32_t)sc->sc_cmd_data[1]) << 16) | 1422190733Sthompsa get_be16(&sc->sc_cmd_data[2]); 1423184610Salfred else { 1424190733Sthompsa lba = get_be32(&sc->sc_cmd_data[2]); 1425184610Salfred 1426184610Salfred /* 1427184610Salfred * We allow DPO (Disable Page Out = don't save data in the 1428184610Salfred * cache) and FUA (Force Unit Access = write directly to the 1429184610Salfred * medium). We don't implement DPO; we implement FUA by 1430184610Salfred * performing synchronous output. 1431184610Salfred */ 1432190733Sthompsa if ((sc->sc_cmd_data[1] & ~0x18) != 0) { 1433184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 1434184610Salfred return (1); 1435184610Salfred } 1436190733Sthompsa if (sc->sc_cmd_data[1] & 0x08) { 1437184610Salfred /* FUA */ 1438184610Salfred /* XXX set SYNC flag here */ 1439184610Salfred } 1440184610Salfred } 1441184610Salfred 1442184610Salfred len = sc->sc_transfer.data_rem >> 9; 1443184610Salfred len += lba; 1444184610Salfred 1445184610Salfred if ((len < lba) || 1446184610Salfred (len > currlun->num_sectors) || 1447184610Salfred (lba >= currlun->num_sectors)) { 1448184610Salfred currlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 1449184610Salfred return (1); 1450184610Salfred } 1451184610Salfred file_offset = lba; 1452184610Salfred file_offset <<= 9; 1453184610Salfred 1454190181Sthompsa sc->sc_transfer.data_ptr = currlun->memory_image + file_offset; 1455184610Salfred 1456184610Salfred return (0); 1457184610Salfred} 1458184610Salfred 1459184610Salfred/*------------------------------------------------------------------------* 1460184610Salfred * ustorage_fs_min_len 1461184610Salfred * 1462184610Salfred * Return values: 1463184610Salfred * 0: Success 1464184610Salfred * Else: Failure 1465184610Salfred *------------------------------------------------------------------------*/ 1466184610Salfredstatic uint8_t 1467184610Salfredustorage_fs_min_len(struct ustorage_fs_softc *sc, uint32_t len, uint32_t mask) 1468184610Salfred{ 1469184610Salfred if (len != sc->sc_transfer.data_rem) { 1470184610Salfred 1471184610Salfred if (sc->sc_transfer.cbw_dir == DIR_READ) { 1472184610Salfred /* 1473184610Salfred * there must be something wrong about this SCSI 1474184610Salfred * command 1475184610Salfred */ 1476184610Salfred sc->sc_csw.bCSWStatus = CSWSTATUS_PHASE; 1477184610Salfred return (1); 1478184610Salfred } 1479184610Salfred /* compute the minimum length */ 1480184610Salfred 1481184610Salfred if (sc->sc_transfer.data_rem > len) { 1482184610Salfred /* data ends prematurely */ 1483184610Salfred sc->sc_transfer.data_rem = len; 1484184610Salfred sc->sc_transfer.data_short = 1; 1485184610Salfred } 1486184610Salfred /* check length alignment */ 1487184610Salfred 1488184610Salfred if (sc->sc_transfer.data_rem & ~mask) { 1489184610Salfred /* data ends prematurely */ 1490184610Salfred sc->sc_transfer.data_rem &= mask; 1491184610Salfred sc->sc_transfer.data_short = 1; 1492184610Salfred } 1493184610Salfred } 1494184610Salfred return (0); 1495184610Salfred} 1496184610Salfred 1497184610Salfred/*------------------------------------------------------------------------* 1498184610Salfred * ustorage_fs_check_cmd - check command routine 1499184610Salfred * 1500184610Salfred * Check whether the command is properly formed and whether its data 1501184610Salfred * size and direction agree with the values we already have. 1502184610Salfred * 1503184610Salfred * Return values: 1504184610Salfred * 0: Success 1505184610Salfred * Else: Failure 1506184610Salfred *------------------------------------------------------------------------*/ 1507184610Salfredstatic uint8_t 1508184610Salfredustorage_fs_check_cmd(struct ustorage_fs_softc *sc, uint8_t min_cmd_size, 1509184610Salfred uint16_t mask, uint8_t needs_medium) 1510184610Salfred{ 1511184610Salfred struct ustorage_fs_lun *currlun; 1512190733Sthompsa uint8_t lun = (sc->sc_cmd_data[1] >> 5); 1513184610Salfred uint8_t i; 1514184610Salfred 1515184610Salfred /* Verify the length of the command itself */ 1516184610Salfred if (min_cmd_size > sc->sc_transfer.cmd_len) { 1517184610Salfred DPRINTF("%u > %u\n", 1518184610Salfred min_cmd_size, sc->sc_transfer.cmd_len); 1519184610Salfred sc->sc_csw.bCSWStatus = CSWSTATUS_PHASE; 1520184610Salfred return (1); 1521184610Salfred } 1522184610Salfred /* Mask away the LUN */ 1523190733Sthompsa sc->sc_cmd_data[1] &= 0x1f; 1524184610Salfred 1525184610Salfred /* Check if LUN is correct */ 1526184610Salfred if (lun != sc->sc_transfer.lun) { 1527184610Salfred 1528184610Salfred } 1529184610Salfred /* Check the LUN */ 1530184610Salfred if (sc->sc_transfer.lun <= sc->sc_last_lun) { 1531184610Salfred sc->sc_transfer.currlun = currlun = 1532184610Salfred sc->sc_lun + sc->sc_transfer.lun; 1533190733Sthompsa if (sc->sc_cmd_data[0] != SC_REQUEST_SENSE) { 1534184610Salfred currlun->sense_data = SS_NO_SENSE; 1535184610Salfred currlun->sense_data_info = 0; 1536184610Salfred currlun->info_valid = 0; 1537184610Salfred } 1538184610Salfred /* 1539184610Salfred * If a unit attention condition exists, only INQUIRY 1540184610Salfred * and REQUEST SENSE commands are allowed. Anything 1541184610Salfred * else must fail! 1542184610Salfred */ 1543184610Salfred if ((currlun->unit_attention_data != SS_NO_SENSE) && 1544190733Sthompsa (sc->sc_cmd_data[0] != SC_INQUIRY) && 1545190733Sthompsa (sc->sc_cmd_data[0] != SC_REQUEST_SENSE)) { 1546184610Salfred currlun->sense_data = currlun->unit_attention_data; 1547184610Salfred currlun->unit_attention_data = SS_NO_SENSE; 1548184610Salfred return (1); 1549184610Salfred } 1550184610Salfred } else { 1551184610Salfred sc->sc_transfer.currlun = currlun = NULL; 1552184610Salfred 1553184610Salfred /* 1554184610Salfred * INQUIRY and REQUEST SENSE commands are explicitly allowed 1555184610Salfred * to use unsupported LUNs; all others may not. 1556184610Salfred */ 1557190733Sthompsa if ((sc->sc_cmd_data[0] != SC_INQUIRY) && 1558190733Sthompsa (sc->sc_cmd_data[0] != SC_REQUEST_SENSE)) { 1559184610Salfred return (1); 1560184610Salfred } 1561184610Salfred } 1562184610Salfred 1563184610Salfred /* 1564184610Salfred * Check that only command bytes listed in the mask are 1565184610Salfred * non-zero. 1566184610Salfred */ 1567184610Salfred for (i = 0; i != min_cmd_size; i++) { 1568190733Sthompsa if (sc->sc_cmd_data[i] && !(mask & (1UL << i))) { 1569184610Salfred if (currlun) { 1570184610Salfred currlun->sense_data = SS_INVALID_FIELD_IN_CDB; 1571184610Salfred } 1572184610Salfred return (1); 1573184610Salfred } 1574184610Salfred } 1575184610Salfred 1576184610Salfred /* 1577184610Salfred * If the medium isn't mounted and the command needs to access 1578184610Salfred * it, return an error. 1579184610Salfred */ 1580184610Salfred if (currlun && (!currlun->memory_image) && needs_medium) { 1581184610Salfred currlun->sense_data = SS_MEDIUM_NOT_PRESENT; 1582184610Salfred return (1); 1583184610Salfred } 1584184610Salfred return (0); 1585184610Salfred} 1586184610Salfred 1587184610Salfred/*------------------------------------------------------------------------* 1588184610Salfred * ustorage_fs_do_cmd - do command 1589184610Salfred * 1590184610Salfred * Return values: 1591184610Salfred * 0: Success 1592184610Salfred * Else: Failure 1593184610Salfred *------------------------------------------------------------------------*/ 1594184610Salfredstatic uint8_t 1595184610Salfredustorage_fs_do_cmd(struct ustorage_fs_softc *sc) 1596184610Salfred{ 1597184610Salfred uint8_t error = 1; 1598184610Salfred uint8_t i; 1599190719Sthompsa uint32_t temp; 1600190719Sthompsa const uint32_t mask9 = (0xFFFFFFFFUL >> 9) << 9; 1601184610Salfred 1602184610Salfred /* set default data transfer pointer */ 1603184610Salfred sc->sc_transfer.data_ptr = sc->sc_qdata; 1604184610Salfred 1605184610Salfred DPRINTF("cmd_data[0]=0x%02x, data_rem=0x%08x\n", 1606190733Sthompsa sc->sc_cmd_data[0], sc->sc_transfer.data_rem); 1607184610Salfred 1608190733Sthompsa switch (sc->sc_cmd_data[0]) { 1609184610Salfred case SC_INQUIRY: 1610184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1611190733Sthompsa error = ustorage_fs_min_len(sc, sc->sc_cmd_data[4], 0 - 1); 1612184610Salfred if (error) { 1613184610Salfred break; 1614184610Salfred } 1615184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1616190719Sthompsa (1UL << 4) | 1, 0); 1617184610Salfred if (error) { 1618184610Salfred break; 1619184610Salfred } 1620184610Salfred error = ustorage_fs_inquiry(sc); 1621184610Salfred 1622184610Salfred break; 1623184610Salfred 1624184610Salfred case SC_MODE_SELECT_6: 1625184610Salfred sc->sc_transfer.cmd_dir = DIR_READ; 1626190733Sthompsa error = ustorage_fs_min_len(sc, sc->sc_cmd_data[4], 0 - 1); 1627184610Salfred if (error) { 1628184610Salfred break; 1629184610Salfred } 1630184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1631190719Sthompsa (1UL << 1) | (1UL << 4) | 1, 0); 1632184610Salfred if (error) { 1633184610Salfred break; 1634184610Salfred } 1635184610Salfred error = ustorage_fs_mode_select(sc); 1636184610Salfred 1637184610Salfred break; 1638184610Salfred 1639184610Salfred case SC_MODE_SELECT_10: 1640184610Salfred sc->sc_transfer.cmd_dir = DIR_READ; 1641184610Salfred error = ustorage_fs_min_len(sc, 1642190733Sthompsa get_be16(&sc->sc_cmd_data[7]), 0 - 1); 1643184610Salfred if (error) { 1644184610Salfred break; 1645184610Salfred } 1646184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1647190719Sthompsa (1UL << 1) | (3UL << 7) | 1, 0); 1648184610Salfred if (error) { 1649184610Salfred break; 1650184610Salfred } 1651184610Salfred error = ustorage_fs_mode_select(sc); 1652184610Salfred 1653184610Salfred break; 1654184610Salfred 1655184610Salfred case SC_MODE_SENSE_6: 1656184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1657190733Sthompsa error = ustorage_fs_min_len(sc, sc->sc_cmd_data[4], 0 - 1); 1658184610Salfred if (error) { 1659184610Salfred break; 1660184610Salfred } 1661184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1662190719Sthompsa (1UL << 1) | (1UL << 2) | (1UL << 4) | 1, 0); 1663184610Salfred if (error) { 1664184610Salfred break; 1665184610Salfred } 1666184610Salfred error = ustorage_fs_mode_sense(sc); 1667184610Salfred 1668184610Salfred break; 1669184610Salfred 1670184610Salfred case SC_MODE_SENSE_10: 1671184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1672184610Salfred error = ustorage_fs_min_len(sc, 1673190733Sthompsa get_be16(&sc->sc_cmd_data[7]), 0 - 1); 1674184610Salfred if (error) { 1675184610Salfred break; 1676184610Salfred } 1677184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1678190719Sthompsa (1UL << 1) | (1UL << 2) | (3UL << 7) | 1, 0); 1679184610Salfred if (error) { 1680184610Salfred break; 1681184610Salfred } 1682184610Salfred error = ustorage_fs_mode_sense(sc); 1683184610Salfred 1684184610Salfred break; 1685184610Salfred 1686184610Salfred case SC_PREVENT_ALLOW_MEDIUM_REMOVAL: 1687184610Salfred error = ustorage_fs_min_len(sc, 0, 0 - 1); 1688184610Salfred if (error) { 1689184610Salfred break; 1690184610Salfred } 1691184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1692190719Sthompsa (1UL << 4) | 1, 0); 1693184610Salfred if (error) { 1694184610Salfred break; 1695184610Salfred } 1696184610Salfred error = ustorage_fs_prevent_allow(sc); 1697184610Salfred 1698184610Salfred break; 1699184610Salfred 1700184610Salfred case SC_READ_6: 1701190733Sthompsa i = sc->sc_cmd_data[4]; 1702184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1703190719Sthompsa temp = ((i == 0) ? 256UL : i); 1704190719Sthompsa error = ustorage_fs_min_len(sc, temp << 9, mask9); 1705184610Salfred if (error) { 1706184610Salfred break; 1707184610Salfred } 1708184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1709190719Sthompsa (7UL << 1) | (1UL << 4) | 1, 1); 1710184610Salfred if (error) { 1711184610Salfred break; 1712184610Salfred } 1713184610Salfred error = ustorage_fs_read(sc); 1714184610Salfred 1715184610Salfred break; 1716184610Salfred 1717184610Salfred case SC_READ_10: 1718184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1719190733Sthompsa temp = get_be16(&sc->sc_cmd_data[7]); 1720190719Sthompsa error = ustorage_fs_min_len(sc, temp << 9, mask9); 1721184610Salfred if (error) { 1722184610Salfred break; 1723184610Salfred } 1724184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1725190719Sthompsa (1UL << 1) | (0xfUL << 2) | (3UL << 7) | 1, 1); 1726184610Salfred if (error) { 1727184610Salfred break; 1728184610Salfred } 1729184610Salfred error = ustorage_fs_read(sc); 1730184610Salfred 1731184610Salfred break; 1732184610Salfred 1733184610Salfred case SC_READ_12: 1734184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1735190733Sthompsa temp = get_be32(&sc->sc_cmd_data[6]); 1736190719Sthompsa if (temp >= (1UL << (32 - 9))) { 1737190719Sthompsa /* numerical overflow */ 1738190719Sthompsa sc->sc_csw.bCSWStatus = CSWSTATUS_FAILED; 1739190719Sthompsa error = 1; 1740190719Sthompsa break; 1741190719Sthompsa } 1742190719Sthompsa error = ustorage_fs_min_len(sc, temp << 9, mask9); 1743184610Salfred if (error) { 1744184610Salfred break; 1745184610Salfred } 1746184610Salfred error = ustorage_fs_check_cmd(sc, 12, 1747190719Sthompsa (1UL << 1) | (0xfUL << 2) | (0xfUL << 6) | 1, 1); 1748184610Salfred if (error) { 1749184610Salfred break; 1750184610Salfred } 1751184610Salfred error = ustorage_fs_read(sc); 1752184610Salfred 1753184610Salfred break; 1754184610Salfred 1755184610Salfred case SC_READ_CAPACITY: 1756184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1757184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1758190719Sthompsa (0xfUL << 2) | (1UL << 8) | 1, 1); 1759184610Salfred if (error) { 1760184610Salfred break; 1761184610Salfred } 1762184610Salfred error = ustorage_fs_read_capacity(sc); 1763184610Salfred 1764184610Salfred break; 1765184610Salfred 1766184610Salfred case SC_READ_FORMAT_CAPACITIES: 1767184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1768184610Salfred error = ustorage_fs_min_len(sc, 1769190733Sthompsa get_be16(&sc->sc_cmd_data[7]), 0 - 1); 1770184610Salfred if (error) { 1771184610Salfred break; 1772184610Salfred } 1773184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1774190719Sthompsa (3UL << 7) | 1, 1); 1775184610Salfred if (error) { 1776184610Salfred break; 1777184610Salfred } 1778184610Salfred error = ustorage_fs_read_format_capacities(sc); 1779184610Salfred 1780184610Salfred break; 1781184610Salfred 1782184610Salfred case SC_REQUEST_SENSE: 1783184610Salfred sc->sc_transfer.cmd_dir = DIR_WRITE; 1784190733Sthompsa error = ustorage_fs_min_len(sc, sc->sc_cmd_data[4], 0 - 1); 1785184610Salfred if (error) { 1786184610Salfred break; 1787184610Salfred } 1788184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1789190719Sthompsa (1UL << 4) | 1, 0); 1790184610Salfred if (error) { 1791184610Salfred break; 1792184610Salfred } 1793184610Salfred error = ustorage_fs_request_sense(sc); 1794184610Salfred 1795184610Salfred break; 1796184610Salfred 1797184610Salfred case SC_START_STOP_UNIT: 1798184610Salfred error = ustorage_fs_min_len(sc, 0, 0 - 1); 1799184610Salfred if (error) { 1800184610Salfred break; 1801184610Salfred } 1802184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1803190719Sthompsa (1UL << 1) | (1UL << 4) | 1, 0); 1804184610Salfred if (error) { 1805184610Salfred break; 1806184610Salfred } 1807184610Salfred error = ustorage_fs_start_stop(sc); 1808184610Salfred 1809184610Salfred break; 1810184610Salfred 1811184610Salfred case SC_SYNCHRONIZE_CACHE: 1812184610Salfred error = ustorage_fs_min_len(sc, 0, 0 - 1); 1813184610Salfred if (error) { 1814184610Salfred break; 1815184610Salfred } 1816184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1817190719Sthompsa (0xfUL << 2) | (3UL << 7) | 1, 1); 1818184610Salfred if (error) { 1819184610Salfred break; 1820184610Salfred } 1821184610Salfred error = ustorage_fs_synchronize_cache(sc); 1822184610Salfred 1823184610Salfred break; 1824184610Salfred 1825184610Salfred case SC_TEST_UNIT_READY: 1826184610Salfred error = ustorage_fs_min_len(sc, 0, 0 - 1); 1827184610Salfred if (error) { 1828184610Salfred break; 1829184610Salfred } 1830184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1831184610Salfred 0 | 1, 1); 1832184610Salfred break; 1833184610Salfred 1834184610Salfred /* 1835184610Salfred * Although optional, this command is used by MS-Windows. 1836184610Salfred * We support a minimal version: BytChk must be 0. 1837184610Salfred */ 1838184610Salfred case SC_VERIFY: 1839184610Salfred error = ustorage_fs_min_len(sc, 0, 0 - 1); 1840184610Salfred if (error) { 1841184610Salfred break; 1842184610Salfred } 1843184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1844190719Sthompsa (1UL << 1) | (0xfUL << 2) | (3UL << 7) | 1, 1); 1845184610Salfred if (error) { 1846184610Salfred break; 1847184610Salfred } 1848184610Salfred error = ustorage_fs_verify(sc); 1849184610Salfred 1850184610Salfred break; 1851184610Salfred 1852184610Salfred case SC_WRITE_6: 1853190733Sthompsa i = sc->sc_cmd_data[4]; 1854184610Salfred sc->sc_transfer.cmd_dir = DIR_READ; 1855190719Sthompsa temp = ((i == 0) ? 256UL : i); 1856190719Sthompsa error = ustorage_fs_min_len(sc, temp << 9, mask9); 1857184610Salfred if (error) { 1858184610Salfred break; 1859184610Salfred } 1860184610Salfred error = ustorage_fs_check_cmd(sc, 6, 1861190719Sthompsa (7UL << 1) | (1UL << 4) | 1, 1); 1862184610Salfred if (error) { 1863184610Salfred break; 1864184610Salfred } 1865184610Salfred error = ustorage_fs_write(sc); 1866184610Salfred 1867184610Salfred break; 1868184610Salfred 1869184610Salfred case SC_WRITE_10: 1870184610Salfred sc->sc_transfer.cmd_dir = DIR_READ; 1871190733Sthompsa temp = get_be16(&sc->sc_cmd_data[7]); 1872190719Sthompsa error = ustorage_fs_min_len(sc, temp << 9, mask9); 1873184610Salfred if (error) { 1874184610Salfred break; 1875184610Salfred } 1876184610Salfred error = ustorage_fs_check_cmd(sc, 10, 1877190719Sthompsa (1UL << 1) | (0xfUL << 2) | (3UL << 7) | 1, 1); 1878184610Salfred if (error) { 1879184610Salfred break; 1880184610Salfred } 1881184610Salfred error = ustorage_fs_write(sc); 1882184610Salfred 1883184610Salfred break; 1884184610Salfred 1885184610Salfred case SC_WRITE_12: 1886184610Salfred sc->sc_transfer.cmd_dir = DIR_READ; 1887190733Sthompsa temp = get_be32(&sc->sc_cmd_data[6]); 1888190719Sthompsa if (temp > (mask9 >> 9)) { 1889190719Sthompsa /* numerical overflow */ 1890190719Sthompsa sc->sc_csw.bCSWStatus = CSWSTATUS_FAILED; 1891190719Sthompsa error = 1; 1892190719Sthompsa break; 1893190719Sthompsa } 1894190719Sthompsa error = ustorage_fs_min_len(sc, temp << 9, mask9); 1895184610Salfred if (error) { 1896184610Salfred break; 1897184610Salfred } 1898184610Salfred error = ustorage_fs_check_cmd(sc, 12, 1899190719Sthompsa (1UL << 1) | (0xfUL << 2) | (0xfUL << 6) | 1, 1); 1900184610Salfred if (error) { 1901184610Salfred break; 1902184610Salfred } 1903184610Salfred error = ustorage_fs_write(sc); 1904184610Salfred 1905184610Salfred break; 1906184610Salfred 1907184610Salfred /* 1908184610Salfred * Some mandatory commands that we recognize but don't 1909184610Salfred * implement. They don't mean much in this setting. 1910184610Salfred * It's left as an exercise for anyone interested to 1911184610Salfred * implement RESERVE and RELEASE in terms of Posix 1912184610Salfred * locks. 1913184610Salfred */ 1914184610Salfred case SC_FORMAT_UNIT: 1915184610Salfred case SC_RELEASE: 1916184610Salfred case SC_RESERVE: 1917184610Salfred case SC_SEND_DIAGNOSTIC: 1918184610Salfred /* Fallthrough */ 1919184610Salfred 1920184610Salfred default: 1921184610Salfred error = ustorage_fs_min_len(sc, 0, 0 - 1); 1922184610Salfred if (error) { 1923184610Salfred break; 1924184610Salfred } 1925184610Salfred error = ustorage_fs_check_cmd(sc, sc->sc_transfer.cmd_len, 1926184610Salfred 0xff, 0); 1927184610Salfred if (error) { 1928184610Salfred break; 1929184610Salfred } 1930184610Salfred sc->sc_transfer.currlun->sense_data = 1931184610Salfred SS_INVALID_COMMAND; 1932184610Salfred error = 1; 1933184610Salfred 1934184610Salfred break; 1935184610Salfred } 1936184610Salfred return (error); 1937184610Salfred} 1938