1*57bed822SMarkus Pfeiffer /* $FreeBSD$ */ 2*57bed822SMarkus Pfeiffer /*- 3*57bed822SMarkus Pfeiffer * Copyright (c) 2007-2012 Hans Petter Selasky. All rights reserved. 4*57bed822SMarkus Pfeiffer * 5*57bed822SMarkus Pfeiffer * Redistribution and use in source and binary forms, with or without 6*57bed822SMarkus Pfeiffer * modification, are permitted provided that the following conditions 7*57bed822SMarkus Pfeiffer * are met: 8*57bed822SMarkus Pfeiffer * 1. Redistributions of source code must retain the above copyright 9*57bed822SMarkus Pfeiffer * notice, this list of conditions and the following disclaimer. 10*57bed822SMarkus Pfeiffer * 2. Redistributions in binary form must reproduce the above copyright 11*57bed822SMarkus Pfeiffer * notice, this list of conditions and the following disclaimer in the 12*57bed822SMarkus Pfeiffer * documentation and/or other materials provided with the distribution. 13*57bed822SMarkus Pfeiffer * 14*57bed822SMarkus Pfeiffer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*57bed822SMarkus Pfeiffer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*57bed822SMarkus Pfeiffer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*57bed822SMarkus Pfeiffer * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*57bed822SMarkus Pfeiffer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*57bed822SMarkus Pfeiffer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*57bed822SMarkus Pfeiffer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*57bed822SMarkus Pfeiffer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*57bed822SMarkus Pfeiffer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*57bed822SMarkus Pfeiffer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*57bed822SMarkus Pfeiffer * SUCH DAMAGE. 25*57bed822SMarkus Pfeiffer */ 26*57bed822SMarkus Pfeiffer 27*57bed822SMarkus Pfeiffer #include <stdio.h> 28*57bed822SMarkus Pfeiffer #include <stdint.h> 29*57bed822SMarkus Pfeiffer #include <stdlib.h> 30*57bed822SMarkus Pfeiffer #include <err.h> 31*57bed822SMarkus Pfeiffer #include <string.h> 32*57bed822SMarkus Pfeiffer #include <errno.h> 33*57bed822SMarkus Pfeiffer #include <unistd.h> 34*57bed822SMarkus Pfeiffer 35*57bed822SMarkus Pfeiffer #include <sys/sysctl.h> 36*57bed822SMarkus Pfeiffer #include <sys/time.h> 37*57bed822SMarkus Pfeiffer 38*57bed822SMarkus Pfeiffer #include <libusb20.h> 39*57bed822SMarkus Pfeiffer #include <libusb20_desc.h> 40*57bed822SMarkus Pfeiffer 41*57bed822SMarkus Pfeiffer #include <dev/usb/usb_endian.h> 42*57bed822SMarkus Pfeiffer 43*57bed822SMarkus Pfeiffer #include "usbtest.h" 44*57bed822SMarkus Pfeiffer 45*57bed822SMarkus Pfeiffer #include "usb_msc_test.h" 46*57bed822SMarkus Pfeiffer 47*57bed822SMarkus Pfeiffer /* Command Block Wrapper */ 48*57bed822SMarkus Pfeiffer typedef struct { 49*57bed822SMarkus Pfeiffer uDWord dCBWSignature; 50*57bed822SMarkus Pfeiffer #define CBWSIGNATURE 0x43425355 51*57bed822SMarkus Pfeiffer uDWord dCBWTag; 52*57bed822SMarkus Pfeiffer uDWord dCBWDataTransferLength; 53*57bed822SMarkus Pfeiffer uByte bCBWFlags; 54*57bed822SMarkus Pfeiffer #define CBWFLAGS_OUT 0x00 55*57bed822SMarkus Pfeiffer #define CBWFLAGS_IN 0x80 56*57bed822SMarkus Pfeiffer uByte bCBWLUN; 57*57bed822SMarkus Pfeiffer uByte bCDBLength; 58*57bed822SMarkus Pfeiffer #define CBWCDBLENGTH 16 59*57bed822SMarkus Pfeiffer uByte CBWCDB[CBWCDBLENGTH]; 60*57bed822SMarkus Pfeiffer } umass_bbb_cbw_t; 61*57bed822SMarkus Pfeiffer 62*57bed822SMarkus Pfeiffer #define UMASS_BBB_CBW_SIZE 31 63*57bed822SMarkus Pfeiffer 64*57bed822SMarkus Pfeiffer /* Command Status Wrapper */ 65*57bed822SMarkus Pfeiffer typedef struct { 66*57bed822SMarkus Pfeiffer uDWord dCSWSignature; 67*57bed822SMarkus Pfeiffer #define CSWSIGNATURE 0x53425355 68*57bed822SMarkus Pfeiffer #define CSWSIGNATURE_IMAGINATION_DBX1 0x43425355 69*57bed822SMarkus Pfeiffer #define CSWSIGNATURE_OLYMPUS_C1 0x55425355 70*57bed822SMarkus Pfeiffer uDWord dCSWTag; 71*57bed822SMarkus Pfeiffer uDWord dCSWDataResidue; 72*57bed822SMarkus Pfeiffer uByte bCSWStatus; 73*57bed822SMarkus Pfeiffer #define CSWSTATUS_GOOD 0x0 74*57bed822SMarkus Pfeiffer #define CSWSTATUS_FAILED 0x1 75*57bed822SMarkus Pfeiffer #define CSWSTATUS_PHASE 0x2 76*57bed822SMarkus Pfeiffer } umass_bbb_csw_t; 77*57bed822SMarkus Pfeiffer 78*57bed822SMarkus Pfeiffer #define UMASS_BBB_CSW_SIZE 13 79*57bed822SMarkus Pfeiffer 80*57bed822SMarkus Pfeiffer #define SC_READ_6 0x08 81*57bed822SMarkus Pfeiffer #define SC_READ_10 0x28 82*57bed822SMarkus Pfeiffer #define SC_READ_12 0xa8 83*57bed822SMarkus Pfeiffer #define SC_WRITE_6 0x0a 84*57bed822SMarkus Pfeiffer #define SC_WRITE_10 0x2a 85*57bed822SMarkus Pfeiffer #define SC_WRITE_12 0xaa 86*57bed822SMarkus Pfeiffer 87*57bed822SMarkus Pfeiffer static struct stats { 88*57bed822SMarkus Pfeiffer uint64_t xfer_error; 89*57bed822SMarkus Pfeiffer uint64_t xfer_success; 90*57bed822SMarkus Pfeiffer uint64_t xfer_reset; 91*57bed822SMarkus Pfeiffer uint64_t xfer_rx_bytes; 92*57bed822SMarkus Pfeiffer uint64_t xfer_tx_bytes; 93*57bed822SMarkus Pfeiffer uint64_t data_error; 94*57bed822SMarkus Pfeiffer } stats; 95*57bed822SMarkus Pfeiffer 96*57bed822SMarkus Pfeiffer static uint32_t xfer_current_id; 97*57bed822SMarkus Pfeiffer static uint32_t xfer_wrapper_sig; 98*57bed822SMarkus Pfeiffer static uint32_t block_size = 512; 99*57bed822SMarkus Pfeiffer 100*57bed822SMarkus Pfeiffer static struct libusb20_transfer *xfer_in; 101*57bed822SMarkus Pfeiffer static struct libusb20_transfer *xfer_out; 102*57bed822SMarkus Pfeiffer static struct libusb20_device *usb_pdev; 103*57bed822SMarkus Pfeiffer static uint8_t usb_iface; 104*57bed822SMarkus Pfeiffer static int sense_recurse; 105*57bed822SMarkus Pfeiffer 106*57bed822SMarkus Pfeiffer /* 107*57bed822SMarkus Pfeiffer * SCSI commands sniffed off the wire - LUN maybe needs to be 108*57bed822SMarkus Pfeiffer * adjusted! Refer to "dev/usb/storage/ustorage_fs.c" for more 109*57bed822SMarkus Pfeiffer * information. 110*57bed822SMarkus Pfeiffer */ 111*57bed822SMarkus Pfeiffer static uint8_t mode_sense_6[0x6] = {0x1a, 0, 0x3f, 0, 0x0c}; 112*57bed822SMarkus Pfeiffer static uint8_t read_capacity[0xA] = {0x25,}; 113*57bed822SMarkus Pfeiffer static uint8_t request_sense[0xC] = {0x03, 0, 0, 0, 0x12}; 114*57bed822SMarkus Pfeiffer static uint8_t test_unit_ready[0x6] = {0}; 115*57bed822SMarkus Pfeiffer static uint8_t mode_page_inquiry[0x6] = {0x12, 1, 0x80, 0, 0xff, 0}; 116*57bed822SMarkus Pfeiffer static uint8_t request_invalid[0xC] = {0xEA, 0, 0, 0, 0}; 117*57bed822SMarkus Pfeiffer static uint8_t prevent_removal[0x6] = {0x1E, 0, 0, 0, 1}; 118*57bed822SMarkus Pfeiffer static uint8_t read_toc[0xA] = {0x43, 0x02, 0, 0, 0, 0xAA, 0, 0x0C}; 119*57bed822SMarkus Pfeiffer 120*57bed822SMarkus Pfeiffer #define TIMEOUT_FILTER(x) (x) 121*57bed822SMarkus Pfeiffer 122*57bed822SMarkus Pfeiffer static void usb_request_sense(uint8_t lun); 123*57bed822SMarkus Pfeiffer 124*57bed822SMarkus Pfeiffer static void 125*57bed822SMarkus Pfeiffer do_msc_reset(uint8_t lun) 126*57bed822SMarkus Pfeiffer { 127*57bed822SMarkus Pfeiffer struct LIBUSB20_CONTROL_SETUP_DECODED setup; 128*57bed822SMarkus Pfeiffer 129*57bed822SMarkus Pfeiffer LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &setup); 130*57bed822SMarkus Pfeiffer 131*57bed822SMarkus Pfeiffer setup.bmRequestType = LIBUSB20_REQUEST_TYPE_CLASS | 132*57bed822SMarkus Pfeiffer LIBUSB20_RECIPIENT_INTERFACE; 133*57bed822SMarkus Pfeiffer setup.bRequest = 0xFF; /* BBB reset */ 134*57bed822SMarkus Pfeiffer setup.wValue = 0; 135*57bed822SMarkus Pfeiffer setup.wIndex = usb_iface; 136*57bed822SMarkus Pfeiffer setup.wLength = 0; 137*57bed822SMarkus Pfeiffer 138*57bed822SMarkus Pfeiffer if (libusb20_dev_request_sync(usb_pdev, &setup, NULL, NULL, 5000, 0)) { 139*57bed822SMarkus Pfeiffer printf("ERROR: %s\n", __FUNCTION__); 140*57bed822SMarkus Pfeiffer stats.xfer_error++; 141*57bed822SMarkus Pfeiffer } 142*57bed822SMarkus Pfeiffer libusb20_tr_clear_stall_sync(xfer_in); 143*57bed822SMarkus Pfeiffer libusb20_tr_clear_stall_sync(xfer_out); 144*57bed822SMarkus Pfeiffer 145*57bed822SMarkus Pfeiffer stats.xfer_reset++; 146*57bed822SMarkus Pfeiffer 147*57bed822SMarkus Pfeiffer usb_request_sense(lun); 148*57bed822SMarkus Pfeiffer } 149*57bed822SMarkus Pfeiffer 150*57bed822SMarkus Pfeiffer static uint8_t 151*57bed822SMarkus Pfeiffer do_msc_cmd(uint8_t *pcmd, uint8_t cmdlen, void *pdata, uint32_t datalen, 152*57bed822SMarkus Pfeiffer uint8_t isread, uint8_t isshort, uint8_t lun, uint8_t flags) 153*57bed822SMarkus Pfeiffer { 154*57bed822SMarkus Pfeiffer umass_bbb_cbw_t cbw; 155*57bed822SMarkus Pfeiffer umass_bbb_csw_t csw; 156*57bed822SMarkus Pfeiffer struct libusb20_transfer *xfer_io; 157*57bed822SMarkus Pfeiffer uint32_t actlen; 158*57bed822SMarkus Pfeiffer uint32_t timeout; 159*57bed822SMarkus Pfeiffer int error; 160*57bed822SMarkus Pfeiffer 161*57bed822SMarkus Pfeiffer memset(&cbw, 0, sizeof(cbw)); 162*57bed822SMarkus Pfeiffer 163*57bed822SMarkus Pfeiffer USETDW(cbw.dCBWSignature, xfer_wrapper_sig); 164*57bed822SMarkus Pfeiffer USETDW(cbw.dCBWTag, xfer_current_id); 165*57bed822SMarkus Pfeiffer xfer_current_id++; 166*57bed822SMarkus Pfeiffer USETDW(cbw.dCBWDataTransferLength, datalen); 167*57bed822SMarkus Pfeiffer cbw.bCBWFlags = (isread ? CBWFLAGS_IN : CBWFLAGS_OUT); 168*57bed822SMarkus Pfeiffer cbw.bCBWLUN = lun; 169*57bed822SMarkus Pfeiffer cbw.bCDBLength = cmdlen; 170*57bed822SMarkus Pfeiffer bcopy(pcmd, cbw.CBWCDB, cmdlen); 171*57bed822SMarkus Pfeiffer 172*57bed822SMarkus Pfeiffer actlen = 0; 173*57bed822SMarkus Pfeiffer 174*57bed822SMarkus Pfeiffer timeout = ((datalen + 299999) / 300000) * 1000; 175*57bed822SMarkus Pfeiffer timeout += 5000; 176*57bed822SMarkus Pfeiffer 177*57bed822SMarkus Pfeiffer if ((error = libusb20_tr_bulk_intr_sync(xfer_out, 178*57bed822SMarkus Pfeiffer &cbw, sizeof(cbw), &actlen, TIMEOUT_FILTER(1000)))) { 179*57bed822SMarkus Pfeiffer printf("ERROR: CBW reception: %d\n", error); 180*57bed822SMarkus Pfeiffer do_msc_reset(lun); 181*57bed822SMarkus Pfeiffer return (1); 182*57bed822SMarkus Pfeiffer } 183*57bed822SMarkus Pfeiffer if (actlen != sizeof(cbw)) { 184*57bed822SMarkus Pfeiffer printf("ERROR: CBW length: %d != %d\n", 185*57bed822SMarkus Pfeiffer actlen, (int)sizeof(cbw)); 186*57bed822SMarkus Pfeiffer do_msc_reset(lun); 187*57bed822SMarkus Pfeiffer return (1); 188*57bed822SMarkus Pfeiffer } 189*57bed822SMarkus Pfeiffer if (flags & 1) 190*57bed822SMarkus Pfeiffer datalen /= 2; 191*57bed822SMarkus Pfeiffer 192*57bed822SMarkus Pfeiffer if (datalen != 0) { 193*57bed822SMarkus Pfeiffer xfer_io = isread ? xfer_in : xfer_out; 194*57bed822SMarkus Pfeiffer 195*57bed822SMarkus Pfeiffer if ((error = libusb20_tr_bulk_intr_sync(xfer_io, 196*57bed822SMarkus Pfeiffer pdata, datalen, &actlen, TIMEOUT_FILTER(timeout)))) { 197*57bed822SMarkus Pfeiffer printf("ERROR: Data transfer: %d\n", error); 198*57bed822SMarkus Pfeiffer do_msc_reset(lun); 199*57bed822SMarkus Pfeiffer return (1); 200*57bed822SMarkus Pfeiffer } 201*57bed822SMarkus Pfeiffer if ((actlen != datalen) && (!isshort)) { 202*57bed822SMarkus Pfeiffer printf("ERROR: Short data: %d of %d bytes\n", 203*57bed822SMarkus Pfeiffer actlen, datalen); 204*57bed822SMarkus Pfeiffer do_msc_reset(lun); 205*57bed822SMarkus Pfeiffer return (1); 206*57bed822SMarkus Pfeiffer } 207*57bed822SMarkus Pfeiffer } 208*57bed822SMarkus Pfeiffer actlen = 0; 209*57bed822SMarkus Pfeiffer timeout = 8; 210*57bed822SMarkus Pfeiffer 211*57bed822SMarkus Pfeiffer do { 212*57bed822SMarkus Pfeiffer error = libusb20_tr_bulk_intr_sync(xfer_in, &csw, 213*57bed822SMarkus Pfeiffer sizeof(csw), &actlen, TIMEOUT_FILTER(1000)); 214*57bed822SMarkus Pfeiffer if (error) { 215*57bed822SMarkus Pfeiffer if (error == LIBUSB20_TRANSFER_TIMED_OUT) { 216*57bed822SMarkus Pfeiffer printf("TIMEOUT: Trying to get CSW again. " 217*57bed822SMarkus Pfeiffer "%d tries left.\n", timeout); 218*57bed822SMarkus Pfeiffer } else { 219*57bed822SMarkus Pfeiffer break; 220*57bed822SMarkus Pfeiffer } 221*57bed822SMarkus Pfeiffer } else { 222*57bed822SMarkus Pfeiffer break; 223*57bed822SMarkus Pfeiffer } 224*57bed822SMarkus Pfeiffer } while (--timeout); 225*57bed822SMarkus Pfeiffer 226*57bed822SMarkus Pfeiffer if (error) { 227*57bed822SMarkus Pfeiffer libusb20_tr_clear_stall_sync(xfer_in); 228*57bed822SMarkus Pfeiffer error = libusb20_tr_bulk_intr_sync(xfer_in, &csw, 229*57bed822SMarkus Pfeiffer sizeof(csw), &actlen, TIMEOUT_FILTER(1000)); 230*57bed822SMarkus Pfeiffer if (error) { 231*57bed822SMarkus Pfeiffer libusb20_tr_clear_stall_sync(xfer_in); 232*57bed822SMarkus Pfeiffer printf("ERROR: Could not read CSW: Stalled or " 233*57bed822SMarkus Pfeiffer "timeout (%d).\n", error); 234*57bed822SMarkus Pfeiffer do_msc_reset(lun); 235*57bed822SMarkus Pfeiffer return (1); 236*57bed822SMarkus Pfeiffer } 237*57bed822SMarkus Pfeiffer } 238*57bed822SMarkus Pfeiffer if (UGETDW(csw.dCSWSignature) != CSWSIGNATURE) { 239*57bed822SMarkus Pfeiffer printf("ERROR: Wrong CSW signature\n"); 240*57bed822SMarkus Pfeiffer do_msc_reset(lun); 241*57bed822SMarkus Pfeiffer return (1); 242*57bed822SMarkus Pfeiffer } 243*57bed822SMarkus Pfeiffer if (actlen != sizeof(csw)) { 244*57bed822SMarkus Pfeiffer printf("ERROR: Wrong CSW length: %d != %d\n", 245*57bed822SMarkus Pfeiffer actlen, (int)sizeof(csw)); 246*57bed822SMarkus Pfeiffer do_msc_reset(lun); 247*57bed822SMarkus Pfeiffer return (1); 248*57bed822SMarkus Pfeiffer } 249*57bed822SMarkus Pfeiffer if (csw.bCSWStatus != 0) { 250*57bed822SMarkus Pfeiffer printf("ERROR: CSW status: %d\n", (int)csw.bCSWStatus); 251*57bed822SMarkus Pfeiffer return (1); 252*57bed822SMarkus Pfeiffer } else { 253*57bed822SMarkus Pfeiffer stats.xfer_success++; 254*57bed822SMarkus Pfeiffer return (0); 255*57bed822SMarkus Pfeiffer } 256*57bed822SMarkus Pfeiffer } 257*57bed822SMarkus Pfeiffer 258*57bed822SMarkus Pfeiffer static uint8_t 259*57bed822SMarkus Pfeiffer do_read_10(uint32_t lba, uint32_t len, void *buf, uint8_t lun) 260*57bed822SMarkus Pfeiffer { 261*57bed822SMarkus Pfeiffer static uint8_t cmd[10]; 262*57bed822SMarkus Pfeiffer uint8_t retval; 263*57bed822SMarkus Pfeiffer 264*57bed822SMarkus Pfeiffer cmd[0] = SC_READ_10; 265*57bed822SMarkus Pfeiffer 266*57bed822SMarkus Pfeiffer len /= block_size; 267*57bed822SMarkus Pfeiffer 268*57bed822SMarkus Pfeiffer cmd[2] = lba >> 24; 269*57bed822SMarkus Pfeiffer cmd[3] = lba >> 16; 270*57bed822SMarkus Pfeiffer cmd[4] = lba >> 8; 271*57bed822SMarkus Pfeiffer cmd[5] = lba >> 0; 272*57bed822SMarkus Pfeiffer 273*57bed822SMarkus Pfeiffer cmd[7] = len >> 8; 274*57bed822SMarkus Pfeiffer cmd[8] = len; 275*57bed822SMarkus Pfeiffer 276*57bed822SMarkus Pfeiffer retval = do_msc_cmd(cmd, 10, buf, len * block_size, 1, 0, lun, 0); 277*57bed822SMarkus Pfeiffer 278*57bed822SMarkus Pfeiffer if (retval) { 279*57bed822SMarkus Pfeiffer printf("ERROR: %s\n", __FUNCTION__); 280*57bed822SMarkus Pfeiffer stats.xfer_error++; 281*57bed822SMarkus Pfeiffer } 282*57bed822SMarkus Pfeiffer return (retval); 283*57bed822SMarkus Pfeiffer } 284*57bed822SMarkus Pfeiffer 285*57bed822SMarkus Pfeiffer static uint8_t 286*57bed822SMarkus Pfeiffer do_write_10(uint32_t lba, uint32_t len, void *buf, uint8_t lun) 287*57bed822SMarkus Pfeiffer { 288*57bed822SMarkus Pfeiffer static uint8_t cmd[10]; 289*57bed822SMarkus Pfeiffer uint8_t retval; 290*57bed822SMarkus Pfeiffer uint8_t abort; 291*57bed822SMarkus Pfeiffer 292*57bed822SMarkus Pfeiffer cmd[0] = SC_WRITE_10; 293*57bed822SMarkus Pfeiffer 294*57bed822SMarkus Pfeiffer abort = len & 1; 295*57bed822SMarkus Pfeiffer 296*57bed822SMarkus Pfeiffer len /= block_size; 297*57bed822SMarkus Pfeiffer 298*57bed822SMarkus Pfeiffer cmd[2] = lba >> 24; 299*57bed822SMarkus Pfeiffer cmd[3] = lba >> 16; 300*57bed822SMarkus Pfeiffer cmd[4] = lba >> 8; 301*57bed822SMarkus Pfeiffer cmd[5] = lba >> 0; 302*57bed822SMarkus Pfeiffer 303*57bed822SMarkus Pfeiffer cmd[7] = len >> 8; 304*57bed822SMarkus Pfeiffer cmd[8] = len; 305*57bed822SMarkus Pfeiffer 306*57bed822SMarkus Pfeiffer retval = do_msc_cmd(cmd, 10, buf, (len * block_size), 0, 0, lun, abort); 307*57bed822SMarkus Pfeiffer 308*57bed822SMarkus Pfeiffer if (retval) { 309*57bed822SMarkus Pfeiffer printf("ERROR: %s\n", __FUNCTION__); 310*57bed822SMarkus Pfeiffer stats.xfer_error++; 311*57bed822SMarkus Pfeiffer } 312*57bed822SMarkus Pfeiffer return (retval); 313*57bed822SMarkus Pfeiffer } 314*57bed822SMarkus Pfeiffer 315*57bed822SMarkus Pfeiffer static void 316*57bed822SMarkus Pfeiffer do_io_test(struct usb_msc_params *p, uint8_t lun, uint32_t lba_max, 317*57bed822SMarkus Pfeiffer uint8_t *buffer, uint8_t *reference) 318*57bed822SMarkus Pfeiffer { 319*57bed822SMarkus Pfeiffer uint32_t io_offset; 320*57bed822SMarkus Pfeiffer uint32_t io_size; 321*57bed822SMarkus Pfeiffer uint32_t temp; 322*57bed822SMarkus Pfeiffer uint8_t do_read; 323*57bed822SMarkus Pfeiffer uint8_t retval; 324*57bed822SMarkus Pfeiffer 325*57bed822SMarkus Pfeiffer switch (p->io_mode) { 326*57bed822SMarkus Pfeiffer case USB_MSC_IO_MODE_WRITE_ONLY: 327*57bed822SMarkus Pfeiffer do_read = 0; 328*57bed822SMarkus Pfeiffer break; 329*57bed822SMarkus Pfeiffer case USB_MSC_IO_MODE_READ_WRITE: 330*57bed822SMarkus Pfeiffer do_read = (usb_ts_rand_noise() & 1); 331*57bed822SMarkus Pfeiffer break; 332*57bed822SMarkus Pfeiffer default: 333*57bed822SMarkus Pfeiffer do_read = 1; 334*57bed822SMarkus Pfeiffer break; 335*57bed822SMarkus Pfeiffer } 336*57bed822SMarkus Pfeiffer 337*57bed822SMarkus Pfeiffer switch (p->io_offset) { 338*57bed822SMarkus Pfeiffer case USB_MSC_IO_OFF_RANDOM: 339*57bed822SMarkus Pfeiffer io_offset = usb_ts_rand_noise(); 340*57bed822SMarkus Pfeiffer break; 341*57bed822SMarkus Pfeiffer default: 342*57bed822SMarkus Pfeiffer io_offset = 0; 343*57bed822SMarkus Pfeiffer break; 344*57bed822SMarkus Pfeiffer } 345*57bed822SMarkus Pfeiffer 346*57bed822SMarkus Pfeiffer switch (p->io_delay) { 347*57bed822SMarkus Pfeiffer case USB_MSC_IO_DELAY_RANDOM_10MS: 348*57bed822SMarkus Pfeiffer usleep(((uint32_t)usb_ts_rand_noise()) % 10000U); 349*57bed822SMarkus Pfeiffer break; 350*57bed822SMarkus Pfeiffer case USB_MSC_IO_DELAY_RANDOM_100MS: 351*57bed822SMarkus Pfeiffer usleep(((uint32_t)usb_ts_rand_noise()) % 100000U); 352*57bed822SMarkus Pfeiffer break; 353*57bed822SMarkus Pfeiffer case USB_MSC_IO_DELAY_FIXED_10MS: 354*57bed822SMarkus Pfeiffer usleep(10000); 355*57bed822SMarkus Pfeiffer break; 356*57bed822SMarkus Pfeiffer case USB_MSC_IO_DELAY_FIXED_100MS: 357*57bed822SMarkus Pfeiffer usleep(100000); 358*57bed822SMarkus Pfeiffer break; 359*57bed822SMarkus Pfeiffer default: 360*57bed822SMarkus Pfeiffer break; 361*57bed822SMarkus Pfeiffer } 362*57bed822SMarkus Pfeiffer 363*57bed822SMarkus Pfeiffer switch (p->io_size) { 364*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_RANDOM: 365*57bed822SMarkus Pfeiffer io_size = ((uint32_t)usb_ts_rand_noise()) & 65535U; 366*57bed822SMarkus Pfeiffer break; 367*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_INCREASING: 368*57bed822SMarkus Pfeiffer io_size = (xfer_current_id & 65535U); 369*57bed822SMarkus Pfeiffer break; 370*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_FIXED_1BLK: 371*57bed822SMarkus Pfeiffer io_size = 1; 372*57bed822SMarkus Pfeiffer break; 373*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_FIXED_2BLK: 374*57bed822SMarkus Pfeiffer io_size = 2; 375*57bed822SMarkus Pfeiffer break; 376*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_FIXED_4BLK: 377*57bed822SMarkus Pfeiffer io_size = 4; 378*57bed822SMarkus Pfeiffer break; 379*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_FIXED_8BLK: 380*57bed822SMarkus Pfeiffer io_size = 8; 381*57bed822SMarkus Pfeiffer break; 382*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_FIXED_16BLK: 383*57bed822SMarkus Pfeiffer io_size = 16; 384*57bed822SMarkus Pfeiffer break; 385*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_FIXED_32BLK: 386*57bed822SMarkus Pfeiffer io_size = 32; 387*57bed822SMarkus Pfeiffer break; 388*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_FIXED_64BLK: 389*57bed822SMarkus Pfeiffer io_size = 64; 390*57bed822SMarkus Pfeiffer break; 391*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_FIXED_128BLK: 392*57bed822SMarkus Pfeiffer io_size = 128; 393*57bed822SMarkus Pfeiffer break; 394*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_FIXED_256BLK: 395*57bed822SMarkus Pfeiffer io_size = 256; 396*57bed822SMarkus Pfeiffer break; 397*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_FIXED_512BLK: 398*57bed822SMarkus Pfeiffer io_size = 512; 399*57bed822SMarkus Pfeiffer break; 400*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_FIXED_1024BLK: 401*57bed822SMarkus Pfeiffer io_size = 1024; 402*57bed822SMarkus Pfeiffer break; 403*57bed822SMarkus Pfeiffer default: 404*57bed822SMarkus Pfeiffer io_size = 1; 405*57bed822SMarkus Pfeiffer break; 406*57bed822SMarkus Pfeiffer } 407*57bed822SMarkus Pfeiffer 408*57bed822SMarkus Pfeiffer if (io_size == 0) 409*57bed822SMarkus Pfeiffer io_size = 1; 410*57bed822SMarkus Pfeiffer 411*57bed822SMarkus Pfeiffer io_offset %= lba_max; 412*57bed822SMarkus Pfeiffer 413*57bed822SMarkus Pfeiffer temp = (lba_max - io_offset); 414*57bed822SMarkus Pfeiffer 415*57bed822SMarkus Pfeiffer if (io_size > temp) 416*57bed822SMarkus Pfeiffer io_size = temp; 417*57bed822SMarkus Pfeiffer 418*57bed822SMarkus Pfeiffer if (do_read) { 419*57bed822SMarkus Pfeiffer retval = do_read_10(io_offset, io_size * block_size, 420*57bed822SMarkus Pfeiffer buffer + (io_offset * block_size), lun); 421*57bed822SMarkus Pfeiffer 422*57bed822SMarkus Pfeiffer if (retval == 0) { 423*57bed822SMarkus Pfeiffer if (bcmp(buffer + (io_offset * block_size), 424*57bed822SMarkus Pfeiffer reference + (io_offset * block_size), 425*57bed822SMarkus Pfeiffer io_size * block_size)) { 426*57bed822SMarkus Pfeiffer printf("ERROR: Data comparison failure\n"); 427*57bed822SMarkus Pfeiffer stats.data_error++; 428*57bed822SMarkus Pfeiffer retval = 1; 429*57bed822SMarkus Pfeiffer } 430*57bed822SMarkus Pfeiffer } 431*57bed822SMarkus Pfeiffer stats.xfer_rx_bytes += (io_size * block_size); 432*57bed822SMarkus Pfeiffer 433*57bed822SMarkus Pfeiffer } else { 434*57bed822SMarkus Pfeiffer 435*57bed822SMarkus Pfeiffer retval = do_write_10(io_offset, io_size * block_size, 436*57bed822SMarkus Pfeiffer reference + (io_offset * block_size), lun); 437*57bed822SMarkus Pfeiffer 438*57bed822SMarkus Pfeiffer stats.xfer_tx_bytes += (io_size * block_size); 439*57bed822SMarkus Pfeiffer } 440*57bed822SMarkus Pfeiffer 441*57bed822SMarkus Pfeiffer if ((stats.xfer_error + stats.data_error + 442*57bed822SMarkus Pfeiffer stats.xfer_reset) >= p->max_errors) { 443*57bed822SMarkus Pfeiffer printf("Maximum number of errors exceeded\n"); 444*57bed822SMarkus Pfeiffer p->done = 1; 445*57bed822SMarkus Pfeiffer } 446*57bed822SMarkus Pfeiffer } 447*57bed822SMarkus Pfeiffer 448*57bed822SMarkus Pfeiffer static void 449*57bed822SMarkus Pfeiffer usb_request_sense(uint8_t lun) 450*57bed822SMarkus Pfeiffer { 451*57bed822SMarkus Pfeiffer uint8_t dummy_buf[255]; 452*57bed822SMarkus Pfeiffer 453*57bed822SMarkus Pfeiffer if (sense_recurse) 454*57bed822SMarkus Pfeiffer return; 455*57bed822SMarkus Pfeiffer 456*57bed822SMarkus Pfeiffer sense_recurse++; 457*57bed822SMarkus Pfeiffer 458*57bed822SMarkus Pfeiffer do_msc_cmd(request_sense, sizeof(request_sense), 459*57bed822SMarkus Pfeiffer dummy_buf, 255, 1, 1, lun, 0); 460*57bed822SMarkus Pfeiffer 461*57bed822SMarkus Pfeiffer sense_recurse--; 462*57bed822SMarkus Pfeiffer } 463*57bed822SMarkus Pfeiffer 464*57bed822SMarkus Pfeiffer static void 465*57bed822SMarkus Pfeiffer usb_msc_test(struct usb_msc_params *p) 466*57bed822SMarkus Pfeiffer { 467*57bed822SMarkus Pfeiffer struct stats last_stat; 468*57bed822SMarkus Pfeiffer struct timeval sub_tv; 469*57bed822SMarkus Pfeiffer struct timeval ref_tv; 470*57bed822SMarkus Pfeiffer struct timeval res_tv; 471*57bed822SMarkus Pfeiffer uint8_t *buffer = NULL; 472*57bed822SMarkus Pfeiffer uint8_t *reference = NULL; 473*57bed822SMarkus Pfeiffer uint32_t dummy_buf[65536 / 4]; 474*57bed822SMarkus Pfeiffer uint32_t lba_max; 475*57bed822SMarkus Pfeiffer uint32_t x; 476*57bed822SMarkus Pfeiffer uint32_t y; 477*57bed822SMarkus Pfeiffer uint32_t capacity_lba; 478*57bed822SMarkus Pfeiffer uint32_t capacity_bs; 479*57bed822SMarkus Pfeiffer time_t last_sec; 480*57bed822SMarkus Pfeiffer uint8_t lun; 481*57bed822SMarkus Pfeiffer int tries; 482*57bed822SMarkus Pfeiffer 483*57bed822SMarkus Pfeiffer memset(&last_stat, 0, sizeof(last_stat)); 484*57bed822SMarkus Pfeiffer 485*57bed822SMarkus Pfeiffer switch (p->io_lun) { 486*57bed822SMarkus Pfeiffer case USB_MSC_IO_LUN_0: 487*57bed822SMarkus Pfeiffer lun = 0; 488*57bed822SMarkus Pfeiffer break; 489*57bed822SMarkus Pfeiffer case USB_MSC_IO_LUN_1: 490*57bed822SMarkus Pfeiffer lun = 1; 491*57bed822SMarkus Pfeiffer break; 492*57bed822SMarkus Pfeiffer case USB_MSC_IO_LUN_2: 493*57bed822SMarkus Pfeiffer lun = 2; 494*57bed822SMarkus Pfeiffer break; 495*57bed822SMarkus Pfeiffer case USB_MSC_IO_LUN_3: 496*57bed822SMarkus Pfeiffer lun = 3; 497*57bed822SMarkus Pfeiffer break; 498*57bed822SMarkus Pfeiffer default: 499*57bed822SMarkus Pfeiffer lun = 0; 500*57bed822SMarkus Pfeiffer break; 501*57bed822SMarkus Pfeiffer } 502*57bed822SMarkus Pfeiffer 503*57bed822SMarkus Pfeiffer p->done = 0; 504*57bed822SMarkus Pfeiffer 505*57bed822SMarkus Pfeiffer sense_recurse = p->try_sense_on_error ? 0 : 1; 506*57bed822SMarkus Pfeiffer 507*57bed822SMarkus Pfeiffer printf("Resetting device ...\n"); 508*57bed822SMarkus Pfeiffer 509*57bed822SMarkus Pfeiffer do_msc_reset(lun); 510*57bed822SMarkus Pfeiffer 511*57bed822SMarkus Pfeiffer printf("Testing SCSI commands ...\n"); 512*57bed822SMarkus Pfeiffer 513*57bed822SMarkus Pfeiffer if (p->try_all_lun) { 514*57bed822SMarkus Pfeiffer printf("Requesting sense from LUN 0..255 ... "); 515*57bed822SMarkus Pfeiffer for (x = y = 0; x != 256; x++) { 516*57bed822SMarkus Pfeiffer if (do_msc_cmd(mode_sense_6, sizeof(mode_sense_6), 517*57bed822SMarkus Pfeiffer dummy_buf, 255, 1, 1, x, 0)) 518*57bed822SMarkus Pfeiffer y++; 519*57bed822SMarkus Pfeiffer 520*57bed822SMarkus Pfeiffer if (libusb20_dev_check_connected(usb_pdev) != 0) { 521*57bed822SMarkus Pfeiffer printf(" disconnect "); 522*57bed822SMarkus Pfeiffer break; 523*57bed822SMarkus Pfeiffer } 524*57bed822SMarkus Pfeiffer } 525*57bed822SMarkus Pfeiffer printf("Passed=%d, Failed=%d\n", 256 - y, y); 526*57bed822SMarkus Pfeiffer } 527*57bed822SMarkus Pfeiffer do_msc_cmd(mode_sense_6, sizeof(mode_sense_6), 528*57bed822SMarkus Pfeiffer dummy_buf, 255, 1, 1, lun, 0); 529*57bed822SMarkus Pfeiffer do_msc_cmd(request_sense, sizeof(request_sense), 530*57bed822SMarkus Pfeiffer dummy_buf, 255, 1, 1, lun, 0); 531*57bed822SMarkus Pfeiffer 532*57bed822SMarkus Pfeiffer for (tries = 0; tries != 4; tries++) { 533*57bed822SMarkus Pfeiffer 534*57bed822SMarkus Pfeiffer memset(dummy_buf, 0, sizeof(dummy_buf)); 535*57bed822SMarkus Pfeiffer 536*57bed822SMarkus Pfeiffer if (do_msc_cmd(read_capacity, sizeof(read_capacity), 537*57bed822SMarkus Pfeiffer dummy_buf, 255, 1, 1, lun, 0) != 0) { 538*57bed822SMarkus Pfeiffer printf("Cannot read disk capacity (%u / 4)\n", tries); 539*57bed822SMarkus Pfeiffer if (tries == 3) 540*57bed822SMarkus Pfeiffer return; 541*57bed822SMarkus Pfeiffer usleep(50000); 542*57bed822SMarkus Pfeiffer continue; 543*57bed822SMarkus Pfeiffer } else { 544*57bed822SMarkus Pfeiffer break; 545*57bed822SMarkus Pfeiffer } 546*57bed822SMarkus Pfeiffer } 547*57bed822SMarkus Pfeiffer 548*57bed822SMarkus Pfeiffer capacity_lba = be32toh(dummy_buf[0]); 549*57bed822SMarkus Pfeiffer capacity_bs = be32toh(dummy_buf[1]); 550*57bed822SMarkus Pfeiffer 551*57bed822SMarkus Pfeiffer printf("Disk reports a capacity of LBA=%u and BS=%u\n", 552*57bed822SMarkus Pfeiffer capacity_lba, capacity_bs); 553*57bed822SMarkus Pfeiffer 554*57bed822SMarkus Pfeiffer block_size = capacity_bs; 555*57bed822SMarkus Pfeiffer 556*57bed822SMarkus Pfeiffer if (capacity_bs > 65535) { 557*57bed822SMarkus Pfeiffer printf("Blocksize is too big\n"); 558*57bed822SMarkus Pfeiffer return; 559*57bed822SMarkus Pfeiffer } 560*57bed822SMarkus Pfeiffer if (capacity_bs < 1) { 561*57bed822SMarkus Pfeiffer printf("Blocksize is too small\n"); 562*57bed822SMarkus Pfeiffer return; 563*57bed822SMarkus Pfeiffer } 564*57bed822SMarkus Pfeiffer if (capacity_bs != 512) 565*57bed822SMarkus Pfeiffer printf("INFO: Blocksize is not 512 bytes\n"); 566*57bed822SMarkus Pfeiffer 567*57bed822SMarkus Pfeiffer if (p->try_invalid_scsi_command) { 568*57bed822SMarkus Pfeiffer int status; 569*57bed822SMarkus Pfeiffer 570*57bed822SMarkus Pfeiffer for (tries = 0; tries != 4; tries++) { 571*57bed822SMarkus Pfeiffer 572*57bed822SMarkus Pfeiffer printf("Trying invalid SCSI command: "); 573*57bed822SMarkus Pfeiffer 574*57bed822SMarkus Pfeiffer status = do_msc_cmd(request_invalid, 575*57bed822SMarkus Pfeiffer sizeof(request_invalid), dummy_buf, 576*57bed822SMarkus Pfeiffer 255, 1, 1, lun, 0); 577*57bed822SMarkus Pfeiffer 578*57bed822SMarkus Pfeiffer printf("Result%s as expected\n", status ? "" : " NOT"); 579*57bed822SMarkus Pfeiffer 580*57bed822SMarkus Pfeiffer usleep(50000); 581*57bed822SMarkus Pfeiffer } 582*57bed822SMarkus Pfeiffer } 583*57bed822SMarkus Pfeiffer if (p->try_invalid_wrapper_block) { 584*57bed822SMarkus Pfeiffer int status; 585*57bed822SMarkus Pfeiffer 586*57bed822SMarkus Pfeiffer for (tries = 0; tries != 4; tries++) { 587*57bed822SMarkus Pfeiffer 588*57bed822SMarkus Pfeiffer printf("Trying invalid USB wrapper block signature: "); 589*57bed822SMarkus Pfeiffer 590*57bed822SMarkus Pfeiffer xfer_wrapper_sig = 0x55663322; 591*57bed822SMarkus Pfeiffer 592*57bed822SMarkus Pfeiffer status = do_msc_cmd(read_capacity, 593*57bed822SMarkus Pfeiffer sizeof(read_capacity), dummy_buf, 594*57bed822SMarkus Pfeiffer 255, 1, 1, lun, 0); 595*57bed822SMarkus Pfeiffer 596*57bed822SMarkus Pfeiffer printf("Result%s as expected\n", status ? "" : " NOT"); 597*57bed822SMarkus Pfeiffer 598*57bed822SMarkus Pfeiffer xfer_wrapper_sig = CBWSIGNATURE; 599*57bed822SMarkus Pfeiffer 600*57bed822SMarkus Pfeiffer usleep(50000); 601*57bed822SMarkus Pfeiffer } 602*57bed822SMarkus Pfeiffer } 603*57bed822SMarkus Pfeiffer do_msc_cmd(request_sense, sizeof(request_sense), dummy_buf, 255, 1, 1, lun, 0); 604*57bed822SMarkus Pfeiffer do_msc_cmd(read_capacity, sizeof(read_capacity), dummy_buf, 255, 1, 1, lun, 0); 605*57bed822SMarkus Pfeiffer do_msc_cmd(request_sense, sizeof(request_sense), dummy_buf, 255, 1, 1, lun, 0); 606*57bed822SMarkus Pfeiffer do_msc_cmd(test_unit_ready, sizeof(test_unit_ready), 0, 0, 1, 1, lun, 0); 607*57bed822SMarkus Pfeiffer do_msc_cmd(test_unit_ready, sizeof(test_unit_ready), 0, 0, 1, 1, lun, 0); 608*57bed822SMarkus Pfeiffer do_msc_cmd(request_sense, sizeof(request_sense), dummy_buf, 255, 1, 1, lun, 0); 609*57bed822SMarkus Pfeiffer do_msc_cmd(test_unit_ready, sizeof(test_unit_ready), 0, 0, 1, 1, lun, 0); 610*57bed822SMarkus Pfeiffer do_msc_cmd(request_sense, sizeof(request_sense), dummy_buf, 255, 1, 1, lun, 0); 611*57bed822SMarkus Pfeiffer do_msc_cmd(test_unit_ready, sizeof(test_unit_ready), 0, 0, 1, 1, lun, 0); 612*57bed822SMarkus Pfeiffer do_msc_cmd(test_unit_ready, sizeof(test_unit_ready), 0, 0, 1, 1, lun, 0); 613*57bed822SMarkus Pfeiffer do_msc_cmd(test_unit_ready, sizeof(test_unit_ready), 0, 0, 1, 1, lun, 0); 614*57bed822SMarkus Pfeiffer do_msc_cmd(request_sense, sizeof(request_sense), dummy_buf, 255, 1, 1, lun, 0); 615*57bed822SMarkus Pfeiffer do_msc_cmd(test_unit_ready, sizeof(test_unit_ready), 0, 0, 1, 1, lun, 0); 616*57bed822SMarkus Pfeiffer do_msc_cmd(read_capacity, sizeof(read_capacity), dummy_buf, 255, 1, 1, lun, 0); 617*57bed822SMarkus Pfeiffer do_msc_cmd(mode_page_inquiry, sizeof(mode_page_inquiry), dummy_buf, 255, 1, 1, lun, 0); 618*57bed822SMarkus Pfeiffer do_msc_cmd(mode_page_inquiry, sizeof(mode_page_inquiry), dummy_buf, 255, 1, 1, lun, 0); 619*57bed822SMarkus Pfeiffer 620*57bed822SMarkus Pfeiffer if (do_msc_cmd(prevent_removal, sizeof(prevent_removal), 621*57bed822SMarkus Pfeiffer 0, 0, 1, 1, lun, 0)) { 622*57bed822SMarkus Pfeiffer printf("INFO: Prevent medium removal failed\n"); 623*57bed822SMarkus Pfeiffer } 624*57bed822SMarkus Pfeiffer if (do_msc_cmd(read_toc, sizeof(read_toc), 625*57bed822SMarkus Pfeiffer dummy_buf, 255, 1, 1, lun, 0)) { 626*57bed822SMarkus Pfeiffer printf("INFO: Read Table Of Content failed\n"); 627*57bed822SMarkus Pfeiffer } 628*57bed822SMarkus Pfeiffer if (p->try_last_lba) { 629*57bed822SMarkus Pfeiffer 630*57bed822SMarkus Pfeiffer for (y = 0, x = (1UL << 31); x; x >>= 1) { 631*57bed822SMarkus Pfeiffer if (do_read_10(x | y, block_size, dummy_buf, lun) == 0) 632*57bed822SMarkus Pfeiffer y |= x; 633*57bed822SMarkus Pfeiffer } 634*57bed822SMarkus Pfeiffer 635*57bed822SMarkus Pfeiffer printf("Highest readable LBA: %u (%s), " 636*57bed822SMarkus Pfeiffer "Capacity is %u MBytes\n", y, 637*57bed822SMarkus Pfeiffer (capacity_lba != y) ? "WRONG" : "OK", 638*57bed822SMarkus Pfeiffer (int)((((uint64_t)(y) * (uint64_t)block_size) + 639*57bed822SMarkus Pfeiffer (uint64_t)block_size) / 1000000ULL)); 640*57bed822SMarkus Pfeiffer } else { 641*57bed822SMarkus Pfeiffer 642*57bed822SMarkus Pfeiffer y = capacity_lba; 643*57bed822SMarkus Pfeiffer 644*57bed822SMarkus Pfeiffer printf("Highest readable LBA: %u (not " 645*57bed822SMarkus Pfeiffer "verified), Capacity is %u MBytes\n", y, 646*57bed822SMarkus Pfeiffer (int)((((uint64_t)(y) * (uint64_t)block_size) + 647*57bed822SMarkus Pfeiffer (uint64_t)block_size) / 1000000ULL)); 648*57bed822SMarkus Pfeiffer } 649*57bed822SMarkus Pfeiffer 650*57bed822SMarkus Pfeiffer if (y != 0xFFFFFFFFU) 651*57bed822SMarkus Pfeiffer y++; 652*57bed822SMarkus Pfeiffer 653*57bed822SMarkus Pfeiffer lba_max = y; 654*57bed822SMarkus Pfeiffer 655*57bed822SMarkus Pfeiffer switch (p->io_area) { 656*57bed822SMarkus Pfeiffer case USB_MSC_IO_AREA_1MB: 657*57bed822SMarkus Pfeiffer lba_max = 1024; 658*57bed822SMarkus Pfeiffer break; 659*57bed822SMarkus Pfeiffer case USB_MSC_IO_AREA_16MB: 660*57bed822SMarkus Pfeiffer lba_max = 1024 * 16; 661*57bed822SMarkus Pfeiffer break; 662*57bed822SMarkus Pfeiffer case USB_MSC_IO_AREA_256MB: 663*57bed822SMarkus Pfeiffer lba_max = 1024 * 256; 664*57bed822SMarkus Pfeiffer break; 665*57bed822SMarkus Pfeiffer case USB_MSC_IO_AREA_COMPLETE: 666*57bed822SMarkus Pfeiffer default: 667*57bed822SMarkus Pfeiffer break; 668*57bed822SMarkus Pfeiffer } 669*57bed822SMarkus Pfeiffer 670*57bed822SMarkus Pfeiffer if (lba_max > 65535) 671*57bed822SMarkus Pfeiffer lba_max = 65535; 672*57bed822SMarkus Pfeiffer 673*57bed822SMarkus Pfeiffer printf("Highest testable LBA: %u\n", (int)lba_max); 674*57bed822SMarkus Pfeiffer 675*57bed822SMarkus Pfeiffer buffer = malloc(block_size * lba_max); 676*57bed822SMarkus Pfeiffer if (buffer == NULL) { 677*57bed822SMarkus Pfeiffer printf("ERROR: Could not allocate memory\n"); 678*57bed822SMarkus Pfeiffer goto fail; 679*57bed822SMarkus Pfeiffer } 680*57bed822SMarkus Pfeiffer reference = malloc(block_size * lba_max); 681*57bed822SMarkus Pfeiffer if (reference == NULL) { 682*57bed822SMarkus Pfeiffer printf("ERROR: Could not allocate memory\n"); 683*57bed822SMarkus Pfeiffer goto fail; 684*57bed822SMarkus Pfeiffer } 685*57bed822SMarkus Pfeiffer retry_read_init: 686*57bed822SMarkus Pfeiffer 687*57bed822SMarkus Pfeiffer printf("Setting up initial data pattern, " 688*57bed822SMarkus Pfeiffer "LBA limit = %u ... ", lba_max); 689*57bed822SMarkus Pfeiffer 690*57bed822SMarkus Pfeiffer switch (p->io_mode) { 691*57bed822SMarkus Pfeiffer case USB_MSC_IO_MODE_WRITE_ONCE_READ_ONLY: 692*57bed822SMarkus Pfeiffer case USB_MSC_IO_MODE_WRITE_ONLY: 693*57bed822SMarkus Pfeiffer case USB_MSC_IO_MODE_READ_WRITE: 694*57bed822SMarkus Pfeiffer 695*57bed822SMarkus Pfeiffer switch (p->io_pattern) { 696*57bed822SMarkus Pfeiffer case USB_MSC_IO_PATTERN_FIXED: 697*57bed822SMarkus Pfeiffer for (x = 0; x != (block_size * lba_max); x += 8) { 698*57bed822SMarkus Pfeiffer reference[x + 0] = x >> 24; 699*57bed822SMarkus Pfeiffer reference[x + 1] = x >> 16; 700*57bed822SMarkus Pfeiffer reference[x + 2] = x >> 8; 701*57bed822SMarkus Pfeiffer reference[x + 3] = x >> 0; 702*57bed822SMarkus Pfeiffer reference[x + 4] = 0xFF; 703*57bed822SMarkus Pfeiffer reference[x + 5] = 0x00; 704*57bed822SMarkus Pfeiffer reference[x + 6] = 0xFF; 705*57bed822SMarkus Pfeiffer reference[x + 7] = 0x00; 706*57bed822SMarkus Pfeiffer } 707*57bed822SMarkus Pfeiffer if (do_write_10(0, lba_max * block_size, 708*57bed822SMarkus Pfeiffer reference, lun)) { 709*57bed822SMarkus Pfeiffer printf("FAILED\n"); 710*57bed822SMarkus Pfeiffer lba_max /= 2; 711*57bed822SMarkus Pfeiffer if (lba_max) 712*57bed822SMarkus Pfeiffer goto retry_read_init; 713*57bed822SMarkus Pfeiffer goto fail; 714*57bed822SMarkus Pfeiffer } 715*57bed822SMarkus Pfeiffer printf("SUCCESS\n"); 716*57bed822SMarkus Pfeiffer break; 717*57bed822SMarkus Pfeiffer case USB_MSC_IO_PATTERN_RANDOM: 718*57bed822SMarkus Pfeiffer for (x = 0; x != (block_size * lba_max); x++) { 719*57bed822SMarkus Pfeiffer reference[x] = usb_ts_rand_noise() % 255U; 720*57bed822SMarkus Pfeiffer } 721*57bed822SMarkus Pfeiffer if (do_write_10(0, lba_max * block_size, 722*57bed822SMarkus Pfeiffer reference, lun)) { 723*57bed822SMarkus Pfeiffer printf("FAILED\n"); 724*57bed822SMarkus Pfeiffer lba_max /= 2; 725*57bed822SMarkus Pfeiffer if (lba_max) 726*57bed822SMarkus Pfeiffer goto retry_read_init; 727*57bed822SMarkus Pfeiffer goto fail; 728*57bed822SMarkus Pfeiffer } 729*57bed822SMarkus Pfeiffer printf("SUCCESS\n"); 730*57bed822SMarkus Pfeiffer break; 731*57bed822SMarkus Pfeiffer default: 732*57bed822SMarkus Pfeiffer if (do_read_10(0, lba_max * block_size, 733*57bed822SMarkus Pfeiffer reference, lun)) { 734*57bed822SMarkus Pfeiffer printf("FAILED\n"); 735*57bed822SMarkus Pfeiffer lba_max /= 2; 736*57bed822SMarkus Pfeiffer if (lba_max) 737*57bed822SMarkus Pfeiffer goto retry_read_init; 738*57bed822SMarkus Pfeiffer goto fail; 739*57bed822SMarkus Pfeiffer } 740*57bed822SMarkus Pfeiffer printf("SUCCESS\n"); 741*57bed822SMarkus Pfeiffer break; 742*57bed822SMarkus Pfeiffer } 743*57bed822SMarkus Pfeiffer break; 744*57bed822SMarkus Pfeiffer 745*57bed822SMarkus Pfeiffer default: 746*57bed822SMarkus Pfeiffer if (do_read_10(0, lba_max * block_size, reference, lun)) { 747*57bed822SMarkus Pfeiffer printf("FAILED\n"); 748*57bed822SMarkus Pfeiffer lba_max /= 2; 749*57bed822SMarkus Pfeiffer if (lba_max) 750*57bed822SMarkus Pfeiffer goto retry_read_init; 751*57bed822SMarkus Pfeiffer goto fail; 752*57bed822SMarkus Pfeiffer } 753*57bed822SMarkus Pfeiffer printf("SUCCESS\n"); 754*57bed822SMarkus Pfeiffer break; 755*57bed822SMarkus Pfeiffer } 756*57bed822SMarkus Pfeiffer 757*57bed822SMarkus Pfeiffer 758*57bed822SMarkus Pfeiffer if (p->try_abort_data_write) { 759*57bed822SMarkus Pfeiffer if (do_write_10(0, (2 * block_size) | 1, reference, lun)) 760*57bed822SMarkus Pfeiffer printf("Aborted data write failed (OK)!\n"); 761*57bed822SMarkus Pfeiffer else 762*57bed822SMarkus Pfeiffer printf("Aborted data write did not fail (ERROR)!\n"); 763*57bed822SMarkus Pfeiffer 764*57bed822SMarkus Pfeiffer if (do_read_10(0, (2 * block_size), reference, lun)) 765*57bed822SMarkus Pfeiffer printf("Post-aborted data read failed (ERROR)\n"); 766*57bed822SMarkus Pfeiffer else 767*57bed822SMarkus Pfeiffer printf("Post-aborted data read success (OK)!\n"); 768*57bed822SMarkus Pfeiffer } 769*57bed822SMarkus Pfeiffer printf("Starting test ...\n"); 770*57bed822SMarkus Pfeiffer 771*57bed822SMarkus Pfeiffer gettimeofday(&ref_tv, 0); 772*57bed822SMarkus Pfeiffer 773*57bed822SMarkus Pfeiffer last_sec = ref_tv.tv_sec; 774*57bed822SMarkus Pfeiffer 775*57bed822SMarkus Pfeiffer printf("\n"); 776*57bed822SMarkus Pfeiffer 777*57bed822SMarkus Pfeiffer while (1) { 778*57bed822SMarkus Pfeiffer 779*57bed822SMarkus Pfeiffer gettimeofday(&sub_tv, 0); 780*57bed822SMarkus Pfeiffer 781*57bed822SMarkus Pfeiffer if (last_sec != sub_tv.tv_sec) { 782*57bed822SMarkus Pfeiffer 783*57bed822SMarkus Pfeiffer printf("STATUS: ID=%u, RX=%u bytes/sec, " 784*57bed822SMarkus Pfeiffer "TX=%u bytes/sec, ERR=%u, RST=%u, DERR=%u\n", 785*57bed822SMarkus Pfeiffer (int)xfer_current_id, 786*57bed822SMarkus Pfeiffer (int)(stats.xfer_rx_bytes - 787*57bed822SMarkus Pfeiffer last_stat.xfer_rx_bytes), 788*57bed822SMarkus Pfeiffer (int)(stats.xfer_tx_bytes - 789*57bed822SMarkus Pfeiffer last_stat.xfer_tx_bytes), 790*57bed822SMarkus Pfeiffer (int)(stats.xfer_error), 791*57bed822SMarkus Pfeiffer (int)(stats.xfer_reset), 792*57bed822SMarkus Pfeiffer (int)(stats.data_error)); 793*57bed822SMarkus Pfeiffer 794*57bed822SMarkus Pfeiffer fflush(stdout); 795*57bed822SMarkus Pfeiffer 796*57bed822SMarkus Pfeiffer last_sec = sub_tv.tv_sec; 797*57bed822SMarkus Pfeiffer last_stat = stats; 798*57bed822SMarkus Pfeiffer } 799*57bed822SMarkus Pfeiffer timersub(&sub_tv, &ref_tv, &res_tv); 800*57bed822SMarkus Pfeiffer 801*57bed822SMarkus Pfeiffer if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= p->duration)) 802*57bed822SMarkus Pfeiffer break; 803*57bed822SMarkus Pfeiffer 804*57bed822SMarkus Pfeiffer do_io_test(p, lun, lba_max, buffer, reference); 805*57bed822SMarkus Pfeiffer 806*57bed822SMarkus Pfeiffer if (libusb20_dev_check_connected(usb_pdev) != 0) { 807*57bed822SMarkus Pfeiffer printf("Device disconnected\n"); 808*57bed822SMarkus Pfeiffer break; 809*57bed822SMarkus Pfeiffer } 810*57bed822SMarkus Pfeiffer if (p->done) { 811*57bed822SMarkus Pfeiffer printf("Maximum number of errors exceeded\n"); 812*57bed822SMarkus Pfeiffer break; 813*57bed822SMarkus Pfeiffer } 814*57bed822SMarkus Pfeiffer } 815*57bed822SMarkus Pfeiffer 816*57bed822SMarkus Pfeiffer printf("\nTest done!\n"); 817*57bed822SMarkus Pfeiffer 818*57bed822SMarkus Pfeiffer fail: 819*57bed822SMarkus Pfeiffer if (buffer) 820*57bed822SMarkus Pfeiffer free(buffer); 821*57bed822SMarkus Pfeiffer if (reference) 822*57bed822SMarkus Pfeiffer free(reference); 823*57bed822SMarkus Pfeiffer } 824*57bed822SMarkus Pfeiffer 825*57bed822SMarkus Pfeiffer void 826*57bed822SMarkus Pfeiffer show_host_device_selection(uint8_t level, uint16_t *pvid, uint16_t *ppid) 827*57bed822SMarkus Pfeiffer { 828*57bed822SMarkus Pfeiffer struct libusb20_backend *pbe; 829*57bed822SMarkus Pfeiffer struct libusb20_device *pdev; 830*57bed822SMarkus Pfeiffer struct LIBUSB20_DEVICE_DESC_DECODED *ddesc; 831*57bed822SMarkus Pfeiffer 832*57bed822SMarkus Pfeiffer uint16_t vid[USB_DEVICES_MAX]; 833*57bed822SMarkus Pfeiffer uint16_t pid[USB_DEVICES_MAX]; 834*57bed822SMarkus Pfeiffer 835*57bed822SMarkus Pfeiffer int index; 836*57bed822SMarkus Pfeiffer int sel; 837*57bed822SMarkus Pfeiffer 838*57bed822SMarkus Pfeiffer const char *ptr; 839*57bed822SMarkus Pfeiffer 840*57bed822SMarkus Pfeiffer top: 841*57bed822SMarkus Pfeiffer pbe = libusb20_be_alloc_default(); 842*57bed822SMarkus Pfeiffer pdev = NULL; 843*57bed822SMarkus Pfeiffer index = 0; 844*57bed822SMarkus Pfeiffer 845*57bed822SMarkus Pfeiffer printf("\n[] Select USB device:\n"); 846*57bed822SMarkus Pfeiffer 847*57bed822SMarkus Pfeiffer while ((pdev = libusb20_be_device_foreach(pbe, pdev))) { 848*57bed822SMarkus Pfeiffer 849*57bed822SMarkus Pfeiffer if (libusb20_dev_get_mode(pdev) != LIBUSB20_MODE_HOST) 850*57bed822SMarkus Pfeiffer continue; 851*57bed822SMarkus Pfeiffer 852*57bed822SMarkus Pfeiffer if (index < USB_DEVICES_MAX) { 853*57bed822SMarkus Pfeiffer ddesc = libusb20_dev_get_device_desc(pdev); 854*57bed822SMarkus Pfeiffer ptr = libusb20_dev_get_desc(pdev); 855*57bed822SMarkus Pfeiffer printf("%s%d) %s\n", indent[level], index, ptr); 856*57bed822SMarkus Pfeiffer vid[index] = ddesc->idVendor; 857*57bed822SMarkus Pfeiffer pid[index] = ddesc->idProduct; 858*57bed822SMarkus Pfeiffer index++; 859*57bed822SMarkus Pfeiffer } else { 860*57bed822SMarkus Pfeiffer break; 861*57bed822SMarkus Pfeiffer } 862*57bed822SMarkus Pfeiffer } 863*57bed822SMarkus Pfeiffer 864*57bed822SMarkus Pfeiffer printf("%sr) Refresh device list\n", indent[level]); 865*57bed822SMarkus Pfeiffer printf("%sx) Return to previous menu\n", indent[level]); 866*57bed822SMarkus Pfeiffer 867*57bed822SMarkus Pfeiffer /* release data */ 868*57bed822SMarkus Pfeiffer libusb20_be_free(pbe); 869*57bed822SMarkus Pfeiffer 870*57bed822SMarkus Pfeiffer sel = get_integer(); 871*57bed822SMarkus Pfeiffer 872*57bed822SMarkus Pfeiffer if (sel == -2) 873*57bed822SMarkus Pfeiffer goto top; 874*57bed822SMarkus Pfeiffer 875*57bed822SMarkus Pfeiffer if ((sel < 0) || (sel >= index)) { 876*57bed822SMarkus Pfeiffer *pvid = 0; 877*57bed822SMarkus Pfeiffer *ppid = 0; 878*57bed822SMarkus Pfeiffer return; 879*57bed822SMarkus Pfeiffer } 880*57bed822SMarkus Pfeiffer *pvid = vid[sel]; 881*57bed822SMarkus Pfeiffer *ppid = pid[sel]; 882*57bed822SMarkus Pfeiffer } 883*57bed822SMarkus Pfeiffer 884*57bed822SMarkus Pfeiffer struct libusb20_device * 885*57bed822SMarkus Pfeiffer find_usb_device(uint16_t vid, uint16_t pid) 886*57bed822SMarkus Pfeiffer { 887*57bed822SMarkus Pfeiffer struct libusb20_backend *pbe = libusb20_be_alloc_default(); 888*57bed822SMarkus Pfeiffer struct libusb20_device *pdev = NULL; 889*57bed822SMarkus Pfeiffer struct LIBUSB20_DEVICE_DESC_DECODED *ddesc; 890*57bed822SMarkus Pfeiffer 891*57bed822SMarkus Pfeiffer while ((pdev = libusb20_be_device_foreach(pbe, pdev))) { 892*57bed822SMarkus Pfeiffer 893*57bed822SMarkus Pfeiffer if (libusb20_dev_get_mode(pdev) != LIBUSB20_MODE_HOST) 894*57bed822SMarkus Pfeiffer continue; 895*57bed822SMarkus Pfeiffer 896*57bed822SMarkus Pfeiffer ddesc = libusb20_dev_get_device_desc(pdev); 897*57bed822SMarkus Pfeiffer 898*57bed822SMarkus Pfeiffer if ((vid == ddesc->idVendor) && 899*57bed822SMarkus Pfeiffer (pid == ddesc->idProduct)) { 900*57bed822SMarkus Pfeiffer libusb20_be_dequeue_device(pbe, pdev); 901*57bed822SMarkus Pfeiffer break; 902*57bed822SMarkus Pfeiffer } 903*57bed822SMarkus Pfeiffer } 904*57bed822SMarkus Pfeiffer 905*57bed822SMarkus Pfeiffer /* release data */ 906*57bed822SMarkus Pfeiffer libusb20_be_free(pbe); 907*57bed822SMarkus Pfeiffer 908*57bed822SMarkus Pfeiffer return (pdev); 909*57bed822SMarkus Pfeiffer } 910*57bed822SMarkus Pfeiffer 911*57bed822SMarkus Pfeiffer void 912*57bed822SMarkus Pfeiffer find_usb_endpoints(struct libusb20_device *pdev, uint8_t class, 913*57bed822SMarkus Pfeiffer uint8_t subclass, uint8_t protocol, uint8_t alt_setting, 914*57bed822SMarkus Pfeiffer uint8_t *pif, uint8_t *in_ep, uint8_t *out_ep, uint8_t next_if) 915*57bed822SMarkus Pfeiffer { 916*57bed822SMarkus Pfeiffer struct libusb20_config *pcfg; 917*57bed822SMarkus Pfeiffer struct libusb20_interface *iface; 918*57bed822SMarkus Pfeiffer struct libusb20_endpoint *ep; 919*57bed822SMarkus Pfeiffer uint8_t x; 920*57bed822SMarkus Pfeiffer uint8_t y; 921*57bed822SMarkus Pfeiffer uint8_t z; 922*57bed822SMarkus Pfeiffer 923*57bed822SMarkus Pfeiffer *in_ep = 0; 924*57bed822SMarkus Pfeiffer *out_ep = 0; 925*57bed822SMarkus Pfeiffer *pif = 0; 926*57bed822SMarkus Pfeiffer 927*57bed822SMarkus Pfeiffer pcfg = libusb20_dev_alloc_config(pdev, 928*57bed822SMarkus Pfeiffer libusb20_dev_get_config_index(pdev)); 929*57bed822SMarkus Pfeiffer 930*57bed822SMarkus Pfeiffer if (pcfg == NULL) 931*57bed822SMarkus Pfeiffer return; 932*57bed822SMarkus Pfeiffer 933*57bed822SMarkus Pfeiffer for (x = 0; x != pcfg->num_interface; x++) { 934*57bed822SMarkus Pfeiffer 935*57bed822SMarkus Pfeiffer y = alt_setting; 936*57bed822SMarkus Pfeiffer 937*57bed822SMarkus Pfeiffer iface = (pcfg->interface + x); 938*57bed822SMarkus Pfeiffer 939*57bed822SMarkus Pfeiffer if ((iface->desc.bInterfaceClass == class) && 940*57bed822SMarkus Pfeiffer (iface->desc.bInterfaceSubClass == subclass || 941*57bed822SMarkus Pfeiffer subclass == 255) && 942*57bed822SMarkus Pfeiffer (iface->desc.bInterfaceProtocol == protocol || 943*57bed822SMarkus Pfeiffer protocol == 255)) { 944*57bed822SMarkus Pfeiffer 945*57bed822SMarkus Pfeiffer if (next_if) { 946*57bed822SMarkus Pfeiffer x++; 947*57bed822SMarkus Pfeiffer if (x == pcfg->num_interface) 948*57bed822SMarkus Pfeiffer break; 949*57bed822SMarkus Pfeiffer iface = (pcfg->interface + x); 950*57bed822SMarkus Pfeiffer } 951*57bed822SMarkus Pfeiffer *pif = x; 952*57bed822SMarkus Pfeiffer 953*57bed822SMarkus Pfeiffer for (z = 0; z != iface->num_endpoints; z++) { 954*57bed822SMarkus Pfeiffer ep = iface->endpoints + z; 955*57bed822SMarkus Pfeiffer 956*57bed822SMarkus Pfeiffer /* BULK only */ 957*57bed822SMarkus Pfeiffer if ((ep->desc.bmAttributes & 3) != 2) 958*57bed822SMarkus Pfeiffer continue; 959*57bed822SMarkus Pfeiffer 960*57bed822SMarkus Pfeiffer if (ep->desc.bEndpointAddress & 0x80) 961*57bed822SMarkus Pfeiffer *in_ep = ep->desc.bEndpointAddress; 962*57bed822SMarkus Pfeiffer else 963*57bed822SMarkus Pfeiffer *out_ep = ep->desc.bEndpointAddress; 964*57bed822SMarkus Pfeiffer } 965*57bed822SMarkus Pfeiffer break; 966*57bed822SMarkus Pfeiffer } 967*57bed822SMarkus Pfeiffer } 968*57bed822SMarkus Pfeiffer 969*57bed822SMarkus Pfeiffer free(pcfg); 970*57bed822SMarkus Pfeiffer } 971*57bed822SMarkus Pfeiffer 972*57bed822SMarkus Pfeiffer static void 973*57bed822SMarkus Pfeiffer exec_host_msc_test(struct usb_msc_params *p, uint16_t vid, uint16_t pid) 974*57bed822SMarkus Pfeiffer { 975*57bed822SMarkus Pfeiffer struct libusb20_device *pdev; 976*57bed822SMarkus Pfeiffer 977*57bed822SMarkus Pfeiffer uint8_t in_ep; 978*57bed822SMarkus Pfeiffer uint8_t out_ep; 979*57bed822SMarkus Pfeiffer uint8_t iface; 980*57bed822SMarkus Pfeiffer 981*57bed822SMarkus Pfeiffer int error; 982*57bed822SMarkus Pfeiffer 983*57bed822SMarkus Pfeiffer memset(&stats, 0, sizeof(stats)); 984*57bed822SMarkus Pfeiffer 985*57bed822SMarkus Pfeiffer xfer_current_id = 0; 986*57bed822SMarkus Pfeiffer xfer_wrapper_sig = CBWSIGNATURE; 987*57bed822SMarkus Pfeiffer 988*57bed822SMarkus Pfeiffer pdev = find_usb_device(vid, pid); 989*57bed822SMarkus Pfeiffer if (pdev == NULL) { 990*57bed822SMarkus Pfeiffer printf("USB device not found\n"); 991*57bed822SMarkus Pfeiffer return; 992*57bed822SMarkus Pfeiffer } 993*57bed822SMarkus Pfeiffer find_usb_endpoints(pdev, 8, 6, 0x50, 0, &iface, &in_ep, &out_ep, 0); 994*57bed822SMarkus Pfeiffer 995*57bed822SMarkus Pfeiffer if ((in_ep == 0) || (out_ep == 0)) { 996*57bed822SMarkus Pfeiffer printf("Could not find USB endpoints\n"); 997*57bed822SMarkus Pfeiffer libusb20_dev_free(pdev); 998*57bed822SMarkus Pfeiffer return; 999*57bed822SMarkus Pfeiffer } 1000*57bed822SMarkus Pfeiffer printf("Attaching to: %s @ iface %d\n", 1001*57bed822SMarkus Pfeiffer libusb20_dev_get_desc(pdev), iface); 1002*57bed822SMarkus Pfeiffer 1003*57bed822SMarkus Pfeiffer if (libusb20_dev_open(pdev, 2)) { 1004*57bed822SMarkus Pfeiffer printf("Could not open USB device\n"); 1005*57bed822SMarkus Pfeiffer libusb20_dev_free(pdev); 1006*57bed822SMarkus Pfeiffer return; 1007*57bed822SMarkus Pfeiffer } 1008*57bed822SMarkus Pfeiffer if (libusb20_dev_detach_kernel_driver(pdev, iface)) { 1009*57bed822SMarkus Pfeiffer printf("WARNING: Could not detach kernel driver\n"); 1010*57bed822SMarkus Pfeiffer } 1011*57bed822SMarkus Pfeiffer xfer_in = libusb20_tr_get_pointer(pdev, 0); 1012*57bed822SMarkus Pfeiffer error = libusb20_tr_open(xfer_in, 65536, 1, in_ep); 1013*57bed822SMarkus Pfeiffer if (error) { 1014*57bed822SMarkus Pfeiffer printf("Could not open USB endpoint %d\n", in_ep); 1015*57bed822SMarkus Pfeiffer libusb20_dev_free(pdev); 1016*57bed822SMarkus Pfeiffer return; 1017*57bed822SMarkus Pfeiffer } 1018*57bed822SMarkus Pfeiffer xfer_out = libusb20_tr_get_pointer(pdev, 1); 1019*57bed822SMarkus Pfeiffer error = libusb20_tr_open(xfer_out, 65536, 1, out_ep); 1020*57bed822SMarkus Pfeiffer if (error) { 1021*57bed822SMarkus Pfeiffer printf("Could not open USB endpoint %d\n", out_ep); 1022*57bed822SMarkus Pfeiffer libusb20_dev_free(pdev); 1023*57bed822SMarkus Pfeiffer return; 1024*57bed822SMarkus Pfeiffer } 1025*57bed822SMarkus Pfeiffer usb_pdev = pdev; 1026*57bed822SMarkus Pfeiffer usb_iface = iface; 1027*57bed822SMarkus Pfeiffer 1028*57bed822SMarkus Pfeiffer usb_msc_test(p); 1029*57bed822SMarkus Pfeiffer 1030*57bed822SMarkus Pfeiffer libusb20_dev_free(pdev); 1031*57bed822SMarkus Pfeiffer } 1032*57bed822SMarkus Pfeiffer 1033*57bed822SMarkus Pfeiffer static void 1034*57bed822SMarkus Pfeiffer set_defaults(struct usb_msc_params *p) 1035*57bed822SMarkus Pfeiffer { 1036*57bed822SMarkus Pfeiffer memset(p, 0, sizeof(*p)); 1037*57bed822SMarkus Pfeiffer 1038*57bed822SMarkus Pfeiffer p->duration = 60; /* seconds */ 1039*57bed822SMarkus Pfeiffer p->try_invalid_scsi_command = 1; 1040*57bed822SMarkus Pfeiffer p->try_invalid_wrapper_block = 1; 1041*57bed822SMarkus Pfeiffer p->try_last_lba = 1; 1042*57bed822SMarkus Pfeiffer p->max_errors = -1; 1043*57bed822SMarkus Pfeiffer } 1044*57bed822SMarkus Pfeiffer 1045*57bed822SMarkus Pfeiffer static const char * 1046*57bed822SMarkus Pfeiffer get_io_mode(const struct usb_msc_params *p) 1047*57bed822SMarkus Pfeiffer { 1048*57bed822SMarkus Pfeiffer ; /* indent fix */ 1049*57bed822SMarkus Pfeiffer switch (p->io_mode) { 1050*57bed822SMarkus Pfeiffer case USB_MSC_IO_MODE_READ_ONLY: 1051*57bed822SMarkus Pfeiffer return ("Read Only"); 1052*57bed822SMarkus Pfeiffer case USB_MSC_IO_MODE_WRITE_ONCE_READ_ONLY: 1053*57bed822SMarkus Pfeiffer return ("Write Once, Read Only"); 1054*57bed822SMarkus Pfeiffer case USB_MSC_IO_MODE_WRITE_ONLY: 1055*57bed822SMarkus Pfeiffer return ("Write Only"); 1056*57bed822SMarkus Pfeiffer case USB_MSC_IO_MODE_READ_WRITE: 1057*57bed822SMarkus Pfeiffer return ("Read and Write"); 1058*57bed822SMarkus Pfeiffer default: 1059*57bed822SMarkus Pfeiffer return ("Unknown"); 1060*57bed822SMarkus Pfeiffer } 1061*57bed822SMarkus Pfeiffer } 1062*57bed822SMarkus Pfeiffer 1063*57bed822SMarkus Pfeiffer static const char * 1064*57bed822SMarkus Pfeiffer get_io_pattern(const struct usb_msc_params *p) 1065*57bed822SMarkus Pfeiffer { 1066*57bed822SMarkus Pfeiffer ; /* indent fix */ 1067*57bed822SMarkus Pfeiffer switch (p->io_pattern) { 1068*57bed822SMarkus Pfeiffer case USB_MSC_IO_PATTERN_FIXED: 1069*57bed822SMarkus Pfeiffer return ("Fixed"); 1070*57bed822SMarkus Pfeiffer case USB_MSC_IO_PATTERN_RANDOM: 1071*57bed822SMarkus Pfeiffer return ("Random"); 1072*57bed822SMarkus Pfeiffer case USB_MSC_IO_PATTERN_PRESERVE: 1073*57bed822SMarkus Pfeiffer return ("Preserve"); 1074*57bed822SMarkus Pfeiffer default: 1075*57bed822SMarkus Pfeiffer return ("Unknown"); 1076*57bed822SMarkus Pfeiffer } 1077*57bed822SMarkus Pfeiffer } 1078*57bed822SMarkus Pfeiffer 1079*57bed822SMarkus Pfeiffer static const char * 1080*57bed822SMarkus Pfeiffer get_io_size(const struct usb_msc_params *p) 1081*57bed822SMarkus Pfeiffer { 1082*57bed822SMarkus Pfeiffer ; /* indent fix */ 1083*57bed822SMarkus Pfeiffer switch (p->io_size) { 1084*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_RANDOM: 1085*57bed822SMarkus Pfeiffer return ("Random"); 1086*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_INCREASING: 1087*57bed822SMarkus Pfeiffer return ("Increasing"); 1088*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_FIXED_1BLK: 1089*57bed822SMarkus Pfeiffer return ("Single block"); 1090*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_FIXED_2BLK: 1091*57bed822SMarkus Pfeiffer return ("2 blocks"); 1092*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_FIXED_4BLK: 1093*57bed822SMarkus Pfeiffer return ("4 blocks"); 1094*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_FIXED_8BLK: 1095*57bed822SMarkus Pfeiffer return ("8 blocks"); 1096*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_FIXED_16BLK: 1097*57bed822SMarkus Pfeiffer return ("16 blocks"); 1098*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_FIXED_32BLK: 1099*57bed822SMarkus Pfeiffer return ("32 blocks"); 1100*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_FIXED_64BLK: 1101*57bed822SMarkus Pfeiffer return ("64 blocks"); 1102*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_FIXED_128BLK: 1103*57bed822SMarkus Pfeiffer return ("128 blocks"); 1104*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_FIXED_256BLK: 1105*57bed822SMarkus Pfeiffer return ("256 blocks"); 1106*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_FIXED_512BLK: 1107*57bed822SMarkus Pfeiffer return ("512 blocks"); 1108*57bed822SMarkus Pfeiffer case USB_MSC_IO_SIZE_FIXED_1024BLK: 1109*57bed822SMarkus Pfeiffer return ("1024 blocks"); 1110*57bed822SMarkus Pfeiffer default: 1111*57bed822SMarkus Pfeiffer return ("Unknown"); 1112*57bed822SMarkus Pfeiffer } 1113*57bed822SMarkus Pfeiffer } 1114*57bed822SMarkus Pfeiffer 1115*57bed822SMarkus Pfeiffer static const char * 1116*57bed822SMarkus Pfeiffer get_io_delay(const struct usb_msc_params *p) 1117*57bed822SMarkus Pfeiffer { 1118*57bed822SMarkus Pfeiffer ; /* indent fix */ 1119*57bed822SMarkus Pfeiffer switch (p->io_delay) { 1120*57bed822SMarkus Pfeiffer case USB_MSC_IO_DELAY_NONE: 1121*57bed822SMarkus Pfeiffer return ("None"); 1122*57bed822SMarkus Pfeiffer case USB_MSC_IO_DELAY_RANDOM_10MS: 1123*57bed822SMarkus Pfeiffer return ("Random 10ms"); 1124*57bed822SMarkus Pfeiffer case USB_MSC_IO_DELAY_RANDOM_100MS: 1125*57bed822SMarkus Pfeiffer return ("Random 100ms"); 1126*57bed822SMarkus Pfeiffer case USB_MSC_IO_DELAY_FIXED_10MS: 1127*57bed822SMarkus Pfeiffer return ("Fixed 10ms"); 1128*57bed822SMarkus Pfeiffer case USB_MSC_IO_DELAY_FIXED_100MS: 1129*57bed822SMarkus Pfeiffer return ("Fixed 100ms"); 1130*57bed822SMarkus Pfeiffer default: 1131*57bed822SMarkus Pfeiffer return ("Unknown"); 1132*57bed822SMarkus Pfeiffer } 1133*57bed822SMarkus Pfeiffer } 1134*57bed822SMarkus Pfeiffer 1135*57bed822SMarkus Pfeiffer static const char * 1136*57bed822SMarkus Pfeiffer get_io_offset(const struct usb_msc_params *p) 1137*57bed822SMarkus Pfeiffer { 1138*57bed822SMarkus Pfeiffer ; /* indent fix */ 1139*57bed822SMarkus Pfeiffer switch (p->io_offset) { 1140*57bed822SMarkus Pfeiffer case USB_MSC_IO_OFF_START_OF_DISK: 1141*57bed822SMarkus Pfeiffer return ("Start Of Disk"); 1142*57bed822SMarkus Pfeiffer case USB_MSC_IO_OFF_RANDOM: 1143*57bed822SMarkus Pfeiffer return ("Random Offset"); 1144*57bed822SMarkus Pfeiffer default: 1145*57bed822SMarkus Pfeiffer return ("Unknown"); 1146*57bed822SMarkus Pfeiffer } 1147*57bed822SMarkus Pfeiffer } 1148*57bed822SMarkus Pfeiffer 1149*57bed822SMarkus Pfeiffer static const char * 1150*57bed822SMarkus Pfeiffer get_io_area(const struct usb_msc_params *p) 1151*57bed822SMarkus Pfeiffer { 1152*57bed822SMarkus Pfeiffer ; /* indent fix */ 1153*57bed822SMarkus Pfeiffer switch (p->io_area) { 1154*57bed822SMarkus Pfeiffer case USB_MSC_IO_AREA_COMPLETE: 1155*57bed822SMarkus Pfeiffer return ("Complete Disk"); 1156*57bed822SMarkus Pfeiffer case USB_MSC_IO_AREA_1MB: 1157*57bed822SMarkus Pfeiffer return ("First MegaByte"); 1158*57bed822SMarkus Pfeiffer case USB_MSC_IO_AREA_16MB: 1159*57bed822SMarkus Pfeiffer return ("First 16 MegaBytes"); 1160*57bed822SMarkus Pfeiffer case USB_MSC_IO_AREA_256MB: 1161*57bed822SMarkus Pfeiffer return ("First 256 MegaBytes"); 1162*57bed822SMarkus Pfeiffer default: 1163*57bed822SMarkus Pfeiffer return ("Unknown"); 1164*57bed822SMarkus Pfeiffer } 1165*57bed822SMarkus Pfeiffer } 1166*57bed822SMarkus Pfeiffer 1167*57bed822SMarkus Pfeiffer void 1168*57bed822SMarkus Pfeiffer show_host_msc_test(uint8_t level, uint16_t vid, 1169*57bed822SMarkus Pfeiffer uint16_t pid, uint32_t duration) 1170*57bed822SMarkus Pfeiffer { 1171*57bed822SMarkus Pfeiffer struct usb_msc_params params; 1172*57bed822SMarkus Pfeiffer uint8_t retval; 1173*57bed822SMarkus Pfeiffer 1174*57bed822SMarkus Pfeiffer set_defaults(¶ms); 1175*57bed822SMarkus Pfeiffer 1176*57bed822SMarkus Pfeiffer params.duration = duration; 1177*57bed822SMarkus Pfeiffer 1178*57bed822SMarkus Pfeiffer while (1) { 1179*57bed822SMarkus Pfeiffer 1180*57bed822SMarkus Pfeiffer retval = usb_ts_show_menu(level, 1181*57bed822SMarkus Pfeiffer "Mass Storage Test Parameters", 1182*57bed822SMarkus Pfeiffer " 1) Toggle I/O mode: <%s>\n" 1183*57bed822SMarkus Pfeiffer " 2) Toggle I/O size: <%s>\n" 1184*57bed822SMarkus Pfeiffer " 3) Toggle I/O delay: <%s>\n" 1185*57bed822SMarkus Pfeiffer " 4) Toggle I/O offset: <%s>\n" 1186*57bed822SMarkus Pfeiffer " 5) Toggle I/O area: <%s>\n" 1187*57bed822SMarkus Pfeiffer " 6) Toggle I/O pattern: <%s>\n" 1188*57bed822SMarkus Pfeiffer " 7) Toggle try invalid SCSI command: <%s>\n" 1189*57bed822SMarkus Pfeiffer " 8) Toggle try invalid wrapper block: <%s>\n" 1190*57bed822SMarkus Pfeiffer " 9) Toggle try invalid MaxPacketSize: <%s>\n" 1191*57bed822SMarkus Pfeiffer "10) Toggle try last Logical Block Address: <%s>\n" 1192*57bed822SMarkus Pfeiffer "11) Toggle I/O lun: <%d>\n" 1193*57bed822SMarkus Pfeiffer "12) Set maximum number of errors: <%d>\n" 1194*57bed822SMarkus Pfeiffer "13) Set test duration: <%d> seconds\n" 1195*57bed822SMarkus Pfeiffer "14) Toggle try aborted write transfer: <%s>\n" 1196*57bed822SMarkus Pfeiffer "15) Toggle request sense on error: <%s>\n" 1197*57bed822SMarkus Pfeiffer "16) Toggle try all LUN: <%s>\n" 1198*57bed822SMarkus Pfeiffer "20) Reset parameters\n" 1199*57bed822SMarkus Pfeiffer "30) Start test (VID=0x%04x, PID=0x%04x)\n" 1200*57bed822SMarkus Pfeiffer "40) Select another device\n" 1201*57bed822SMarkus Pfeiffer " x) Return to previous menu \n", 1202*57bed822SMarkus Pfeiffer get_io_mode(¶ms), 1203*57bed822SMarkus Pfeiffer get_io_size(¶ms), 1204*57bed822SMarkus Pfeiffer get_io_delay(¶ms), 1205*57bed822SMarkus Pfeiffer get_io_offset(¶ms), 1206*57bed822SMarkus Pfeiffer get_io_area(¶ms), 1207*57bed822SMarkus Pfeiffer get_io_pattern(¶ms), 1208*57bed822SMarkus Pfeiffer (params.try_invalid_scsi_command ? "YES" : "NO"), 1209*57bed822SMarkus Pfeiffer (params.try_invalid_wrapper_block ? "YES" : "NO"), 1210*57bed822SMarkus Pfeiffer (params.try_invalid_max_packet_size ? "YES" : "NO"), 1211*57bed822SMarkus Pfeiffer (params.try_last_lba ? "YES" : "NO"), 1212*57bed822SMarkus Pfeiffer params.io_lun, 1213*57bed822SMarkus Pfeiffer (int)params.max_errors, 1214*57bed822SMarkus Pfeiffer (int)params.duration, 1215*57bed822SMarkus Pfeiffer (params.try_abort_data_write ? "YES" : "NO"), 1216*57bed822SMarkus Pfeiffer (params.try_sense_on_error ? "YES" : "NO"), 1217*57bed822SMarkus Pfeiffer (params.try_all_lun ? "YES" : "NO"), 1218*57bed822SMarkus Pfeiffer vid, pid); 1219*57bed822SMarkus Pfeiffer switch (retval) { 1220*57bed822SMarkus Pfeiffer case 0: 1221*57bed822SMarkus Pfeiffer break; 1222*57bed822SMarkus Pfeiffer case 1: 1223*57bed822SMarkus Pfeiffer params.io_mode++; 1224*57bed822SMarkus Pfeiffer params.io_mode %= USB_MSC_IO_MODE_MAX; 1225*57bed822SMarkus Pfeiffer break; 1226*57bed822SMarkus Pfeiffer case 2: 1227*57bed822SMarkus Pfeiffer params.io_size++; 1228*57bed822SMarkus Pfeiffer params.io_size %= USB_MSC_IO_SIZE_MAX; 1229*57bed822SMarkus Pfeiffer break; 1230*57bed822SMarkus Pfeiffer case 3: 1231*57bed822SMarkus Pfeiffer params.io_delay++; 1232*57bed822SMarkus Pfeiffer params.io_delay %= USB_MSC_IO_DELAY_MAX; 1233*57bed822SMarkus Pfeiffer break; 1234*57bed822SMarkus Pfeiffer case 4: 1235*57bed822SMarkus Pfeiffer params.io_offset++; 1236*57bed822SMarkus Pfeiffer params.io_offset %= USB_MSC_IO_OFF_MAX; 1237*57bed822SMarkus Pfeiffer break; 1238*57bed822SMarkus Pfeiffer case 5: 1239*57bed822SMarkus Pfeiffer params.io_area++; 1240*57bed822SMarkus Pfeiffer params.io_area %= USB_MSC_IO_AREA_MAX; 1241*57bed822SMarkus Pfeiffer break; 1242*57bed822SMarkus Pfeiffer case 6: 1243*57bed822SMarkus Pfeiffer params.io_pattern++; 1244*57bed822SMarkus Pfeiffer params.io_pattern %= USB_MSC_IO_PATTERN_MAX; 1245*57bed822SMarkus Pfeiffer break; 1246*57bed822SMarkus Pfeiffer case 7: 1247*57bed822SMarkus Pfeiffer params.try_invalid_scsi_command ^= 1; 1248*57bed822SMarkus Pfeiffer break; 1249*57bed822SMarkus Pfeiffer case 8: 1250*57bed822SMarkus Pfeiffer params.try_invalid_wrapper_block ^= 1; 1251*57bed822SMarkus Pfeiffer break; 1252*57bed822SMarkus Pfeiffer case 9: 1253*57bed822SMarkus Pfeiffer params.try_invalid_max_packet_size ^= 1; 1254*57bed822SMarkus Pfeiffer break; 1255*57bed822SMarkus Pfeiffer case 10: 1256*57bed822SMarkus Pfeiffer params.try_last_lba ^= 1; 1257*57bed822SMarkus Pfeiffer break; 1258*57bed822SMarkus Pfeiffer case 11: 1259*57bed822SMarkus Pfeiffer params.io_lun++; 1260*57bed822SMarkus Pfeiffer params.io_lun %= USB_MSC_IO_LUN_MAX; 1261*57bed822SMarkus Pfeiffer break; 1262*57bed822SMarkus Pfeiffer case 12: 1263*57bed822SMarkus Pfeiffer params.max_errors = get_integer(); 1264*57bed822SMarkus Pfeiffer break; 1265*57bed822SMarkus Pfeiffer case 13: 1266*57bed822SMarkus Pfeiffer params.duration = get_integer(); 1267*57bed822SMarkus Pfeiffer break; 1268*57bed822SMarkus Pfeiffer case 14: 1269*57bed822SMarkus Pfeiffer params.try_abort_data_write ^= 1; 1270*57bed822SMarkus Pfeiffer break; 1271*57bed822SMarkus Pfeiffer case 15: 1272*57bed822SMarkus Pfeiffer params.try_sense_on_error ^= 1; 1273*57bed822SMarkus Pfeiffer break; 1274*57bed822SMarkus Pfeiffer case 16: 1275*57bed822SMarkus Pfeiffer params.try_all_lun ^= 1; 1276*57bed822SMarkus Pfeiffer break; 1277*57bed822SMarkus Pfeiffer case 20: 1278*57bed822SMarkus Pfeiffer set_defaults(¶ms); 1279*57bed822SMarkus Pfeiffer break; 1280*57bed822SMarkus Pfeiffer case 30: 1281*57bed822SMarkus Pfeiffer exec_host_msc_test(¶ms, vid, pid); 1282*57bed822SMarkus Pfeiffer break; 1283*57bed822SMarkus Pfeiffer case 40: 1284*57bed822SMarkus Pfeiffer show_host_device_selection(level + 1, &vid, &pid); 1285*57bed822SMarkus Pfeiffer break; 1286*57bed822SMarkus Pfeiffer default: 1287*57bed822SMarkus Pfeiffer return; 1288*57bed822SMarkus Pfeiffer } 1289*57bed822SMarkus Pfeiffer } 1290*57bed822SMarkus Pfeiffer } 1291