1*129a2703SSascha Wildner /* $FreeBSD: head/tools/tools/usbtest/usb_msc_test.c 260587 2014-01-13 13:27:00Z hselasky $ */
257bed822SMarkus Pfeiffer /*-
357bed822SMarkus Pfeiffer  * Copyright (c) 2007-2012 Hans Petter Selasky. All rights reserved.
457bed822SMarkus Pfeiffer  *
557bed822SMarkus Pfeiffer  * Redistribution and use in source and binary forms, with or without
657bed822SMarkus Pfeiffer  * modification, are permitted provided that the following conditions
757bed822SMarkus Pfeiffer  * are met:
857bed822SMarkus Pfeiffer  * 1. Redistributions of source code must retain the above copyright
957bed822SMarkus Pfeiffer  *    notice, this list of conditions and the following disclaimer.
1057bed822SMarkus Pfeiffer  * 2. Redistributions in binary form must reproduce the above copyright
1157bed822SMarkus Pfeiffer  *    notice, this list of conditions and the following disclaimer in the
1257bed822SMarkus Pfeiffer  *    documentation and/or other materials provided with the distribution.
1357bed822SMarkus Pfeiffer  *
1457bed822SMarkus Pfeiffer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1557bed822SMarkus Pfeiffer  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1657bed822SMarkus Pfeiffer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1757bed822SMarkus Pfeiffer  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1857bed822SMarkus Pfeiffer  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1957bed822SMarkus Pfeiffer  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2057bed822SMarkus Pfeiffer  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2157bed822SMarkus Pfeiffer  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2257bed822SMarkus Pfeiffer  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2357bed822SMarkus Pfeiffer  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2457bed822SMarkus Pfeiffer  * SUCH DAMAGE.
2557bed822SMarkus Pfeiffer  */
2657bed822SMarkus Pfeiffer 
2757bed822SMarkus Pfeiffer #include <stdio.h>
2857bed822SMarkus Pfeiffer #include <stdint.h>
2957bed822SMarkus Pfeiffer #include <stdlib.h>
3057bed822SMarkus Pfeiffer #include <err.h>
3157bed822SMarkus Pfeiffer #include <string.h>
3257bed822SMarkus Pfeiffer #include <errno.h>
3357bed822SMarkus Pfeiffer #include <unistd.h>
3457bed822SMarkus Pfeiffer 
3557bed822SMarkus Pfeiffer #include <sys/sysctl.h>
3657bed822SMarkus Pfeiffer #include <sys/time.h>
3757bed822SMarkus Pfeiffer 
3857bed822SMarkus Pfeiffer #include <libusb20.h>
3957bed822SMarkus Pfeiffer #include <libusb20_desc.h>
4057bed822SMarkus Pfeiffer 
41*129a2703SSascha Wildner #include <bus/u4b/usb_endian.h>
4257bed822SMarkus Pfeiffer 
4357bed822SMarkus Pfeiffer #include "usbtest.h"
4457bed822SMarkus Pfeiffer 
4557bed822SMarkus Pfeiffer #include "usb_msc_test.h"
4657bed822SMarkus Pfeiffer 
4757bed822SMarkus Pfeiffer /* Command Block Wrapper */
4857bed822SMarkus Pfeiffer typedef struct {
4957bed822SMarkus Pfeiffer 	uDWord	dCBWSignature;
5057bed822SMarkus Pfeiffer #define	CBWSIGNATURE	0x43425355
5157bed822SMarkus Pfeiffer 	uDWord	dCBWTag;
5257bed822SMarkus Pfeiffer 	uDWord	dCBWDataTransferLength;
5357bed822SMarkus Pfeiffer 	uByte	bCBWFlags;
5457bed822SMarkus Pfeiffer #define	CBWFLAGS_OUT	0x00
5557bed822SMarkus Pfeiffer #define	CBWFLAGS_IN	0x80
5657bed822SMarkus Pfeiffer 	uByte	bCBWLUN;
5757bed822SMarkus Pfeiffer 	uByte	bCDBLength;
5857bed822SMarkus Pfeiffer #define	CBWCDBLENGTH	16
5957bed822SMarkus Pfeiffer 	uByte	CBWCDB[CBWCDBLENGTH];
6057bed822SMarkus Pfeiffer } umass_bbb_cbw_t;
6157bed822SMarkus Pfeiffer 
6257bed822SMarkus Pfeiffer #define	UMASS_BBB_CBW_SIZE	31
6357bed822SMarkus Pfeiffer 
6457bed822SMarkus Pfeiffer /* Command Status Wrapper */
6557bed822SMarkus Pfeiffer typedef struct {
6657bed822SMarkus Pfeiffer 	uDWord	dCSWSignature;
6757bed822SMarkus Pfeiffer #define	CSWSIGNATURE	0x53425355
6857bed822SMarkus Pfeiffer #define	CSWSIGNATURE_IMAGINATION_DBX1	0x43425355
6957bed822SMarkus Pfeiffer #define	CSWSIGNATURE_OLYMPUS_C1	0x55425355
7057bed822SMarkus Pfeiffer 	uDWord	dCSWTag;
7157bed822SMarkus Pfeiffer 	uDWord	dCSWDataResidue;
7257bed822SMarkus Pfeiffer 	uByte	bCSWStatus;
7357bed822SMarkus Pfeiffer #define	CSWSTATUS_GOOD	0x0
7457bed822SMarkus Pfeiffer #define	CSWSTATUS_FAILED	0x1
7557bed822SMarkus Pfeiffer #define	CSWSTATUS_PHASE	0x2
7657bed822SMarkus Pfeiffer } umass_bbb_csw_t;
7757bed822SMarkus Pfeiffer 
7857bed822SMarkus Pfeiffer #define	UMASS_BBB_CSW_SIZE	13
7957bed822SMarkus Pfeiffer 
8057bed822SMarkus Pfeiffer #define	SC_READ_6			0x08
8157bed822SMarkus Pfeiffer #define	SC_READ_10			0x28
8257bed822SMarkus Pfeiffer #define	SC_READ_12			0xa8
8357bed822SMarkus Pfeiffer #define	SC_WRITE_6			0x0a
8457bed822SMarkus Pfeiffer #define	SC_WRITE_10			0x2a
8557bed822SMarkus Pfeiffer #define	SC_WRITE_12			0xaa
8657bed822SMarkus Pfeiffer 
8757bed822SMarkus Pfeiffer static struct stats {
8857bed822SMarkus Pfeiffer 	uint64_t xfer_error;
8957bed822SMarkus Pfeiffer 	uint64_t xfer_success;
9057bed822SMarkus Pfeiffer 	uint64_t xfer_reset;
9157bed822SMarkus Pfeiffer 	uint64_t xfer_rx_bytes;
9257bed822SMarkus Pfeiffer 	uint64_t xfer_tx_bytes;
9357bed822SMarkus Pfeiffer 	uint64_t data_error;
9457bed822SMarkus Pfeiffer }	stats;
9557bed822SMarkus Pfeiffer 
9657bed822SMarkus Pfeiffer static uint32_t xfer_current_id;
9757bed822SMarkus Pfeiffer static uint32_t xfer_wrapper_sig;
9857bed822SMarkus Pfeiffer static uint32_t block_size = 512;
9957bed822SMarkus Pfeiffer 
10057bed822SMarkus Pfeiffer static struct libusb20_transfer *xfer_in;
10157bed822SMarkus Pfeiffer static struct libusb20_transfer *xfer_out;
10257bed822SMarkus Pfeiffer static struct libusb20_device *usb_pdev;
10357bed822SMarkus Pfeiffer static uint8_t usb_iface;
10457bed822SMarkus Pfeiffer static int sense_recurse;
10557bed822SMarkus Pfeiffer 
10657bed822SMarkus Pfeiffer /*
10757bed822SMarkus Pfeiffer  * SCSI commands sniffed off the wire - LUN maybe needs to be
108*129a2703SSascha Wildner  * adjusted!  Refer to "bus/u4b/storage/ustorage_fs.c" for more
10957bed822SMarkus Pfeiffer  * information.
11057bed822SMarkus Pfeiffer  */
11157bed822SMarkus Pfeiffer static uint8_t mode_sense_6[0x6] = {0x1a, 0, 0x3f, 0, 0x0c};
11257bed822SMarkus Pfeiffer static uint8_t read_capacity[0xA] = {0x25,};
11357bed822SMarkus Pfeiffer static uint8_t request_sense[0xC] = {0x03, 0, 0, 0, 0x12};
11457bed822SMarkus Pfeiffer static uint8_t test_unit_ready[0x6] = {0};
11557bed822SMarkus Pfeiffer static uint8_t mode_page_inquiry[0x6] = {0x12, 1, 0x80, 0, 0xff, 0};
11657bed822SMarkus Pfeiffer static uint8_t request_invalid[0xC] = {0xEA, 0, 0, 0, 0};
11757bed822SMarkus Pfeiffer static uint8_t prevent_removal[0x6] = {0x1E, 0, 0, 0, 1};
11857bed822SMarkus Pfeiffer static uint8_t read_toc[0xA] = {0x43, 0x02, 0, 0, 0, 0xAA, 0, 0x0C};
11957bed822SMarkus Pfeiffer 
12057bed822SMarkus Pfeiffer #define	TIMEOUT_FILTER(x) (x)
12157bed822SMarkus Pfeiffer 
12257bed822SMarkus Pfeiffer static void usb_request_sense(uint8_t lun);
12357bed822SMarkus Pfeiffer 
12457bed822SMarkus Pfeiffer static void
do_msc_reset(uint8_t lun)12557bed822SMarkus Pfeiffer do_msc_reset(uint8_t lun)
12657bed822SMarkus Pfeiffer {
12757bed822SMarkus Pfeiffer 	struct LIBUSB20_CONTROL_SETUP_DECODED setup;
12857bed822SMarkus Pfeiffer 
12957bed822SMarkus Pfeiffer 	LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &setup);
13057bed822SMarkus Pfeiffer 
13157bed822SMarkus Pfeiffer 	setup.bmRequestType = LIBUSB20_REQUEST_TYPE_CLASS |
13257bed822SMarkus Pfeiffer 	    LIBUSB20_RECIPIENT_INTERFACE;
13357bed822SMarkus Pfeiffer 	setup.bRequest = 0xFF;		/* BBB reset */
13457bed822SMarkus Pfeiffer 	setup.wValue = 0;
13557bed822SMarkus Pfeiffer 	setup.wIndex = usb_iface;
13657bed822SMarkus Pfeiffer 	setup.wLength = 0;
13757bed822SMarkus Pfeiffer 
13857bed822SMarkus Pfeiffer 	if (libusb20_dev_request_sync(usb_pdev, &setup, NULL, NULL, 5000, 0)) {
13957bed822SMarkus Pfeiffer 		printf("ERROR: %s\n", __FUNCTION__);
14057bed822SMarkus Pfeiffer 		stats.xfer_error++;
14157bed822SMarkus Pfeiffer 	}
14257bed822SMarkus Pfeiffer 	libusb20_tr_clear_stall_sync(xfer_in);
14357bed822SMarkus Pfeiffer 	libusb20_tr_clear_stall_sync(xfer_out);
14457bed822SMarkus Pfeiffer 
14557bed822SMarkus Pfeiffer 	stats.xfer_reset++;
14657bed822SMarkus Pfeiffer 
14757bed822SMarkus Pfeiffer 	usb_request_sense(lun);
14857bed822SMarkus Pfeiffer }
14957bed822SMarkus Pfeiffer 
15057bed822SMarkus Pfeiffer static uint8_t
do_msc_cmd(uint8_t * pcmd,uint8_t cmdlen,void * pdata,uint32_t datalen,uint8_t isread,uint8_t isshort,uint8_t lun,uint8_t flags)15157bed822SMarkus Pfeiffer do_msc_cmd(uint8_t *pcmd, uint8_t cmdlen, void *pdata, uint32_t datalen,
15257bed822SMarkus Pfeiffer     uint8_t isread, uint8_t isshort, uint8_t lun, uint8_t flags)
15357bed822SMarkus Pfeiffer {
15457bed822SMarkus Pfeiffer 	umass_bbb_cbw_t cbw;
15557bed822SMarkus Pfeiffer 	umass_bbb_csw_t csw;
15657bed822SMarkus Pfeiffer 	struct libusb20_transfer *xfer_io;
15757bed822SMarkus Pfeiffer 	uint32_t actlen;
15857bed822SMarkus Pfeiffer 	uint32_t timeout;
15957bed822SMarkus Pfeiffer 	int error;
16057bed822SMarkus Pfeiffer 
16157bed822SMarkus Pfeiffer 	memset(&cbw, 0, sizeof(cbw));
16257bed822SMarkus Pfeiffer 
16357bed822SMarkus Pfeiffer 	USETDW(cbw.dCBWSignature, xfer_wrapper_sig);
16457bed822SMarkus Pfeiffer 	USETDW(cbw.dCBWTag, xfer_current_id);
16557bed822SMarkus Pfeiffer 	xfer_current_id++;
16657bed822SMarkus Pfeiffer 	USETDW(cbw.dCBWDataTransferLength, datalen);
16757bed822SMarkus Pfeiffer 	cbw.bCBWFlags = (isread ? CBWFLAGS_IN : CBWFLAGS_OUT);
16857bed822SMarkus Pfeiffer 	cbw.bCBWLUN = lun;
16957bed822SMarkus Pfeiffer 	cbw.bCDBLength = cmdlen;
17057bed822SMarkus Pfeiffer 	bcopy(pcmd, cbw.CBWCDB, cmdlen);
17157bed822SMarkus Pfeiffer 
17257bed822SMarkus Pfeiffer 	actlen = 0;
17357bed822SMarkus Pfeiffer 
17457bed822SMarkus Pfeiffer 	timeout = ((datalen + 299999) / 300000) * 1000;
17557bed822SMarkus Pfeiffer 	timeout += 5000;
17657bed822SMarkus Pfeiffer 
17757bed822SMarkus Pfeiffer 	if ((error = libusb20_tr_bulk_intr_sync(xfer_out,
17857bed822SMarkus Pfeiffer 	    &cbw, sizeof(cbw), &actlen, TIMEOUT_FILTER(1000)))) {
17957bed822SMarkus Pfeiffer 		printf("ERROR: CBW reception: %d\n", error);
18057bed822SMarkus Pfeiffer 		do_msc_reset(lun);
18157bed822SMarkus Pfeiffer 		return (1);
18257bed822SMarkus Pfeiffer 	}
18357bed822SMarkus Pfeiffer 	if (actlen != sizeof(cbw)) {
18457bed822SMarkus Pfeiffer 		printf("ERROR: CBW length: %d != %d\n",
18557bed822SMarkus Pfeiffer 		    actlen, (int)sizeof(cbw));
18657bed822SMarkus Pfeiffer 		do_msc_reset(lun);
18757bed822SMarkus Pfeiffer 		return (1);
18857bed822SMarkus Pfeiffer 	}
18957bed822SMarkus Pfeiffer 	if (flags & 1)
19057bed822SMarkus Pfeiffer 		datalen /= 2;
19157bed822SMarkus Pfeiffer 
19257bed822SMarkus Pfeiffer 	if (datalen != 0) {
19357bed822SMarkus Pfeiffer 		xfer_io = isread ? xfer_in : xfer_out;
19457bed822SMarkus Pfeiffer 
19557bed822SMarkus Pfeiffer 		if ((error = libusb20_tr_bulk_intr_sync(xfer_io,
19657bed822SMarkus Pfeiffer 		    pdata, datalen, &actlen, TIMEOUT_FILTER(timeout)))) {
19757bed822SMarkus Pfeiffer 			printf("ERROR: Data transfer: %d\n", error);
19857bed822SMarkus Pfeiffer 			do_msc_reset(lun);
19957bed822SMarkus Pfeiffer 			return (1);
20057bed822SMarkus Pfeiffer 		}
20157bed822SMarkus Pfeiffer 		if ((actlen != datalen) && (!isshort)) {
20257bed822SMarkus Pfeiffer 			printf("ERROR: Short data: %d of %d bytes\n",
20357bed822SMarkus Pfeiffer 			    actlen, datalen);
20457bed822SMarkus Pfeiffer 			do_msc_reset(lun);
20557bed822SMarkus Pfeiffer 			return (1);
20657bed822SMarkus Pfeiffer 		}
20757bed822SMarkus Pfeiffer 	}
20857bed822SMarkus Pfeiffer 	actlen = 0;
20957bed822SMarkus Pfeiffer 	timeout = 8;
21057bed822SMarkus Pfeiffer 
21157bed822SMarkus Pfeiffer 	do {
21257bed822SMarkus Pfeiffer 		error = libusb20_tr_bulk_intr_sync(xfer_in, &csw,
21357bed822SMarkus Pfeiffer 		    sizeof(csw), &actlen, TIMEOUT_FILTER(1000));
21457bed822SMarkus Pfeiffer 		if (error) {
21557bed822SMarkus Pfeiffer 			if (error == LIBUSB20_TRANSFER_TIMED_OUT) {
21657bed822SMarkus Pfeiffer 				printf("TIMEOUT: Trying to get CSW again. "
21757bed822SMarkus Pfeiffer 				    "%d tries left.\n", timeout);
21857bed822SMarkus Pfeiffer 			} else {
21957bed822SMarkus Pfeiffer 				break;
22057bed822SMarkus Pfeiffer 			}
22157bed822SMarkus Pfeiffer 		} else {
22257bed822SMarkus Pfeiffer 			break;
22357bed822SMarkus Pfeiffer 		}
22457bed822SMarkus Pfeiffer 	} while (--timeout);
22557bed822SMarkus Pfeiffer 
22657bed822SMarkus Pfeiffer 	if (error) {
22757bed822SMarkus Pfeiffer 		libusb20_tr_clear_stall_sync(xfer_in);
22857bed822SMarkus Pfeiffer 		error = libusb20_tr_bulk_intr_sync(xfer_in, &csw,
22957bed822SMarkus Pfeiffer 		    sizeof(csw), &actlen, TIMEOUT_FILTER(1000));
23057bed822SMarkus Pfeiffer 		if (error) {
23157bed822SMarkus Pfeiffer 			libusb20_tr_clear_stall_sync(xfer_in);
23257bed822SMarkus Pfeiffer 			printf("ERROR: Could not read CSW: Stalled or "
23357bed822SMarkus Pfeiffer 			    "timeout (%d).\n", error);
23457bed822SMarkus Pfeiffer 			do_msc_reset(lun);
23557bed822SMarkus Pfeiffer 			return (1);
23657bed822SMarkus Pfeiffer 		}
23757bed822SMarkus Pfeiffer 	}
23857bed822SMarkus Pfeiffer 	if (UGETDW(csw.dCSWSignature) != CSWSIGNATURE) {
23957bed822SMarkus Pfeiffer 		printf("ERROR: Wrong CSW signature\n");
24057bed822SMarkus Pfeiffer 		do_msc_reset(lun);
24157bed822SMarkus Pfeiffer 		return (1);
24257bed822SMarkus Pfeiffer 	}
24357bed822SMarkus Pfeiffer 	if (actlen != sizeof(csw)) {
24457bed822SMarkus Pfeiffer 		printf("ERROR: Wrong CSW length: %d != %d\n",
24557bed822SMarkus Pfeiffer 		    actlen, (int)sizeof(csw));
24657bed822SMarkus Pfeiffer 		do_msc_reset(lun);
24757bed822SMarkus Pfeiffer 		return (1);
24857bed822SMarkus Pfeiffer 	}
24957bed822SMarkus Pfeiffer 	if (csw.bCSWStatus != 0) {
25057bed822SMarkus Pfeiffer 		printf("ERROR: CSW status: %d\n", (int)csw.bCSWStatus);
25157bed822SMarkus Pfeiffer 		return (1);
25257bed822SMarkus Pfeiffer 	} else {
25357bed822SMarkus Pfeiffer 		stats.xfer_success++;
25457bed822SMarkus Pfeiffer 		return (0);
25557bed822SMarkus Pfeiffer 	}
25657bed822SMarkus Pfeiffer }
25757bed822SMarkus Pfeiffer 
258*129a2703SSascha Wildner static void
do_msc_shorter_cmd(uint8_t lun)259*129a2703SSascha Wildner do_msc_shorter_cmd(uint8_t lun)
260*129a2703SSascha Wildner {
261*129a2703SSascha Wildner 	uint8_t buffer[sizeof(umass_bbb_cbw_t)];
262*129a2703SSascha Wildner 	int actlen;
263*129a2703SSascha Wildner 	int error;
264*129a2703SSascha Wildner 	int x;
265*129a2703SSascha Wildner 
266*129a2703SSascha Wildner 	memset(buffer, 0, sizeof(buffer));
267*129a2703SSascha Wildner 
268*129a2703SSascha Wildner 	for (x = 0; x != (sizeof(buffer) - 1); x++) {
269*129a2703SSascha Wildner 		error = libusb20_tr_bulk_intr_sync(xfer_out,
270*129a2703SSascha Wildner 		    buffer, x, &actlen, 250);
271*129a2703SSascha Wildner 
272*129a2703SSascha Wildner 		printf("Sent short %d of %d bytes wrapper block, "
273*129a2703SSascha Wildner 		    "status = %d\n", x, (int)(sizeof(buffer) - 1),
274*129a2703SSascha Wildner 		    error);
275*129a2703SSascha Wildner 
276*129a2703SSascha Wildner 		do_msc_reset(lun);
277*129a2703SSascha Wildner 
278*129a2703SSascha Wildner 		if (error != 0) {
279*129a2703SSascha Wildner 			printf("ERROR: Too short command wrapper "
280*129a2703SSascha Wildner 			    "was not accepted\n");
281*129a2703SSascha Wildner 			stats.xfer_error++;
282*129a2703SSascha Wildner 			break;
283*129a2703SSascha Wildner 		}
284*129a2703SSascha Wildner 	}
285*129a2703SSascha Wildner }
286*129a2703SSascha Wildner 
28757bed822SMarkus Pfeiffer static uint8_t
do_read_10(uint32_t lba,uint32_t len,void * buf,uint8_t lun)28857bed822SMarkus Pfeiffer do_read_10(uint32_t lba, uint32_t len, void *buf, uint8_t lun)
28957bed822SMarkus Pfeiffer {
29057bed822SMarkus Pfeiffer 	static uint8_t cmd[10];
29157bed822SMarkus Pfeiffer 	uint8_t retval;
29257bed822SMarkus Pfeiffer 
29357bed822SMarkus Pfeiffer 	cmd[0] = SC_READ_10;
29457bed822SMarkus Pfeiffer 
29557bed822SMarkus Pfeiffer 	len /= block_size;
29657bed822SMarkus Pfeiffer 
29757bed822SMarkus Pfeiffer 	cmd[2] = lba >> 24;
29857bed822SMarkus Pfeiffer 	cmd[3] = lba >> 16;
29957bed822SMarkus Pfeiffer 	cmd[4] = lba >> 8;
30057bed822SMarkus Pfeiffer 	cmd[5] = lba >> 0;
30157bed822SMarkus Pfeiffer 
30257bed822SMarkus Pfeiffer 	cmd[7] = len >> 8;
30357bed822SMarkus Pfeiffer 	cmd[8] = len;
30457bed822SMarkus Pfeiffer 
30557bed822SMarkus Pfeiffer 	retval = do_msc_cmd(cmd, 10, buf, len * block_size, 1, 0, lun, 0);
30657bed822SMarkus Pfeiffer 
30757bed822SMarkus Pfeiffer 	if (retval) {
30857bed822SMarkus Pfeiffer 		printf("ERROR: %s\n", __FUNCTION__);
30957bed822SMarkus Pfeiffer 		stats.xfer_error++;
31057bed822SMarkus Pfeiffer 	}
31157bed822SMarkus Pfeiffer 	return (retval);
31257bed822SMarkus Pfeiffer }
31357bed822SMarkus Pfeiffer 
31457bed822SMarkus Pfeiffer static uint8_t
do_write_10(uint32_t lba,uint32_t len,void * buf,uint8_t lun)31557bed822SMarkus Pfeiffer do_write_10(uint32_t lba, uint32_t len, void *buf, uint8_t lun)
31657bed822SMarkus Pfeiffer {
31757bed822SMarkus Pfeiffer 	static uint8_t cmd[10];
31857bed822SMarkus Pfeiffer 	uint8_t retval;
31957bed822SMarkus Pfeiffer 	uint8_t abort;
32057bed822SMarkus Pfeiffer 
32157bed822SMarkus Pfeiffer 	cmd[0] = SC_WRITE_10;
32257bed822SMarkus Pfeiffer 
32357bed822SMarkus Pfeiffer 	abort = len & 1;
32457bed822SMarkus Pfeiffer 
32557bed822SMarkus Pfeiffer 	len /= block_size;
32657bed822SMarkus Pfeiffer 
32757bed822SMarkus Pfeiffer 	cmd[2] = lba >> 24;
32857bed822SMarkus Pfeiffer 	cmd[3] = lba >> 16;
32957bed822SMarkus Pfeiffer 	cmd[4] = lba >> 8;
33057bed822SMarkus Pfeiffer 	cmd[5] = lba >> 0;
33157bed822SMarkus Pfeiffer 
33257bed822SMarkus Pfeiffer 	cmd[7] = len >> 8;
33357bed822SMarkus Pfeiffer 	cmd[8] = len;
33457bed822SMarkus Pfeiffer 
33557bed822SMarkus Pfeiffer 	retval = do_msc_cmd(cmd, 10, buf, (len * block_size), 0, 0, lun, abort);
33657bed822SMarkus Pfeiffer 
33757bed822SMarkus Pfeiffer 	if (retval) {
33857bed822SMarkus Pfeiffer 		printf("ERROR: %s\n", __FUNCTION__);
33957bed822SMarkus Pfeiffer 		stats.xfer_error++;
34057bed822SMarkus Pfeiffer 	}
34157bed822SMarkus Pfeiffer 	return (retval);
34257bed822SMarkus Pfeiffer }
34357bed822SMarkus Pfeiffer 
34457bed822SMarkus Pfeiffer static void
do_io_test(struct usb_msc_params * p,uint8_t lun,uint32_t lba_max,uint8_t * buffer,uint8_t * reference)34557bed822SMarkus Pfeiffer do_io_test(struct usb_msc_params *p, uint8_t lun, uint32_t lba_max,
34657bed822SMarkus Pfeiffer     uint8_t *buffer, uint8_t *reference)
34757bed822SMarkus Pfeiffer {
34857bed822SMarkus Pfeiffer 	uint32_t io_offset;
34957bed822SMarkus Pfeiffer 	uint32_t io_size;
35057bed822SMarkus Pfeiffer 	uint32_t temp;
35157bed822SMarkus Pfeiffer 	uint8_t do_read;
35257bed822SMarkus Pfeiffer 	uint8_t retval;
35357bed822SMarkus Pfeiffer 
35457bed822SMarkus Pfeiffer 	switch (p->io_mode) {
35557bed822SMarkus Pfeiffer 	case USB_MSC_IO_MODE_WRITE_ONLY:
35657bed822SMarkus Pfeiffer 		do_read = 0;
35757bed822SMarkus Pfeiffer 		break;
35857bed822SMarkus Pfeiffer 	case USB_MSC_IO_MODE_READ_WRITE:
35957bed822SMarkus Pfeiffer 		do_read = (usb_ts_rand_noise() & 1);
36057bed822SMarkus Pfeiffer 		break;
36157bed822SMarkus Pfeiffer 	default:
36257bed822SMarkus Pfeiffer 		do_read = 1;
36357bed822SMarkus Pfeiffer 		break;
36457bed822SMarkus Pfeiffer 	}
36557bed822SMarkus Pfeiffer 
36657bed822SMarkus Pfeiffer 	switch (p->io_offset) {
36757bed822SMarkus Pfeiffer 	case USB_MSC_IO_OFF_RANDOM:
36857bed822SMarkus Pfeiffer 		io_offset = usb_ts_rand_noise();
36957bed822SMarkus Pfeiffer 		break;
37057bed822SMarkus Pfeiffer 	default:
37157bed822SMarkus Pfeiffer 		io_offset = 0;
37257bed822SMarkus Pfeiffer 		break;
37357bed822SMarkus Pfeiffer 	}
37457bed822SMarkus Pfeiffer 
37557bed822SMarkus Pfeiffer 	switch (p->io_delay) {
37657bed822SMarkus Pfeiffer 	case USB_MSC_IO_DELAY_RANDOM_10MS:
37757bed822SMarkus Pfeiffer 		usleep(((uint32_t)usb_ts_rand_noise()) % 10000U);
37857bed822SMarkus Pfeiffer 		break;
37957bed822SMarkus Pfeiffer 	case USB_MSC_IO_DELAY_RANDOM_100MS:
38057bed822SMarkus Pfeiffer 		usleep(((uint32_t)usb_ts_rand_noise()) % 100000U);
38157bed822SMarkus Pfeiffer 		break;
38257bed822SMarkus Pfeiffer 	case USB_MSC_IO_DELAY_FIXED_10MS:
38357bed822SMarkus Pfeiffer 		usleep(10000);
38457bed822SMarkus Pfeiffer 		break;
38557bed822SMarkus Pfeiffer 	case USB_MSC_IO_DELAY_FIXED_100MS:
38657bed822SMarkus Pfeiffer 		usleep(100000);
38757bed822SMarkus Pfeiffer 		break;
38857bed822SMarkus Pfeiffer 	default:
38957bed822SMarkus Pfeiffer 		break;
39057bed822SMarkus Pfeiffer 	}
39157bed822SMarkus Pfeiffer 
39257bed822SMarkus Pfeiffer 	switch (p->io_size) {
39357bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_RANDOM:
39457bed822SMarkus Pfeiffer 		io_size = ((uint32_t)usb_ts_rand_noise()) & 65535U;
39557bed822SMarkus Pfeiffer 		break;
39657bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_INCREASING:
39757bed822SMarkus Pfeiffer 		io_size = (xfer_current_id & 65535U);
39857bed822SMarkus Pfeiffer 		break;
39957bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_FIXED_1BLK:
40057bed822SMarkus Pfeiffer 		io_size = 1;
40157bed822SMarkus Pfeiffer 		break;
40257bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_FIXED_2BLK:
40357bed822SMarkus Pfeiffer 		io_size = 2;
40457bed822SMarkus Pfeiffer 		break;
40557bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_FIXED_4BLK:
40657bed822SMarkus Pfeiffer 		io_size = 4;
40757bed822SMarkus Pfeiffer 		break;
40857bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_FIXED_8BLK:
40957bed822SMarkus Pfeiffer 		io_size = 8;
41057bed822SMarkus Pfeiffer 		break;
41157bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_FIXED_16BLK:
41257bed822SMarkus Pfeiffer 		io_size = 16;
41357bed822SMarkus Pfeiffer 		break;
41457bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_FIXED_32BLK:
41557bed822SMarkus Pfeiffer 		io_size = 32;
41657bed822SMarkus Pfeiffer 		break;
41757bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_FIXED_64BLK:
41857bed822SMarkus Pfeiffer 		io_size = 64;
41957bed822SMarkus Pfeiffer 		break;
42057bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_FIXED_128BLK:
42157bed822SMarkus Pfeiffer 		io_size = 128;
42257bed822SMarkus Pfeiffer 		break;
42357bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_FIXED_256BLK:
42457bed822SMarkus Pfeiffer 		io_size = 256;
42557bed822SMarkus Pfeiffer 		break;
42657bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_FIXED_512BLK:
42757bed822SMarkus Pfeiffer 		io_size = 512;
42857bed822SMarkus Pfeiffer 		break;
42957bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_FIXED_1024BLK:
43057bed822SMarkus Pfeiffer 		io_size = 1024;
43157bed822SMarkus Pfeiffer 		break;
43257bed822SMarkus Pfeiffer 	default:
43357bed822SMarkus Pfeiffer 		io_size = 1;
43457bed822SMarkus Pfeiffer 		break;
43557bed822SMarkus Pfeiffer 	}
43657bed822SMarkus Pfeiffer 
43757bed822SMarkus Pfeiffer 	if (io_size == 0)
43857bed822SMarkus Pfeiffer 		io_size = 1;
43957bed822SMarkus Pfeiffer 
44057bed822SMarkus Pfeiffer 	io_offset %= lba_max;
44157bed822SMarkus Pfeiffer 
44257bed822SMarkus Pfeiffer 	temp = (lba_max - io_offset);
44357bed822SMarkus Pfeiffer 
44457bed822SMarkus Pfeiffer 	if (io_size > temp)
44557bed822SMarkus Pfeiffer 		io_size = temp;
44657bed822SMarkus Pfeiffer 
44757bed822SMarkus Pfeiffer 	if (do_read) {
44857bed822SMarkus Pfeiffer 		retval = do_read_10(io_offset, io_size * block_size,
44957bed822SMarkus Pfeiffer 		    buffer + (io_offset * block_size), lun);
45057bed822SMarkus Pfeiffer 
45157bed822SMarkus Pfeiffer 		if (retval == 0) {
45257bed822SMarkus Pfeiffer 			if (bcmp(buffer + (io_offset * block_size),
45357bed822SMarkus Pfeiffer 			    reference + (io_offset * block_size),
45457bed822SMarkus Pfeiffer 			    io_size * block_size)) {
45557bed822SMarkus Pfeiffer 				printf("ERROR: Data comparison failure\n");
45657bed822SMarkus Pfeiffer 				stats.data_error++;
45757bed822SMarkus Pfeiffer 				retval = 1;
45857bed822SMarkus Pfeiffer 			}
45957bed822SMarkus Pfeiffer 		}
46057bed822SMarkus Pfeiffer 		stats.xfer_rx_bytes += (io_size * block_size);
46157bed822SMarkus Pfeiffer 
46257bed822SMarkus Pfeiffer 	} else {
46357bed822SMarkus Pfeiffer 
46457bed822SMarkus Pfeiffer 		retval = do_write_10(io_offset, io_size * block_size,
46557bed822SMarkus Pfeiffer 		    reference + (io_offset * block_size), lun);
46657bed822SMarkus Pfeiffer 
46757bed822SMarkus Pfeiffer 		stats.xfer_tx_bytes += (io_size * block_size);
46857bed822SMarkus Pfeiffer 	}
46957bed822SMarkus Pfeiffer 
47057bed822SMarkus Pfeiffer 	if ((stats.xfer_error + stats.data_error +
47157bed822SMarkus Pfeiffer 	    stats.xfer_reset) >= p->max_errors) {
47257bed822SMarkus Pfeiffer 		printf("Maximum number of errors exceeded\n");
47357bed822SMarkus Pfeiffer 		p->done = 1;
47457bed822SMarkus Pfeiffer 	}
47557bed822SMarkus Pfeiffer }
47657bed822SMarkus Pfeiffer 
47757bed822SMarkus Pfeiffer static void
usb_request_sense(uint8_t lun)47857bed822SMarkus Pfeiffer usb_request_sense(uint8_t lun)
47957bed822SMarkus Pfeiffer {
48057bed822SMarkus Pfeiffer 	uint8_t dummy_buf[255];
48157bed822SMarkus Pfeiffer 
48257bed822SMarkus Pfeiffer 	if (sense_recurse)
48357bed822SMarkus Pfeiffer 		return;
48457bed822SMarkus Pfeiffer 
48557bed822SMarkus Pfeiffer 	sense_recurse++;
48657bed822SMarkus Pfeiffer 
48757bed822SMarkus Pfeiffer 	do_msc_cmd(request_sense, sizeof(request_sense),
48857bed822SMarkus Pfeiffer 	    dummy_buf, 255, 1, 1, lun, 0);
48957bed822SMarkus Pfeiffer 
49057bed822SMarkus Pfeiffer 	sense_recurse--;
49157bed822SMarkus Pfeiffer }
49257bed822SMarkus Pfeiffer 
49357bed822SMarkus Pfeiffer static void
usb_msc_test(struct usb_msc_params * p)49457bed822SMarkus Pfeiffer usb_msc_test(struct usb_msc_params *p)
49557bed822SMarkus Pfeiffer {
49657bed822SMarkus Pfeiffer 	struct stats last_stat;
49757bed822SMarkus Pfeiffer 	struct timeval sub_tv;
49857bed822SMarkus Pfeiffer 	struct timeval ref_tv;
49957bed822SMarkus Pfeiffer 	struct timeval res_tv;
50057bed822SMarkus Pfeiffer 	uint8_t *buffer = NULL;
50157bed822SMarkus Pfeiffer 	uint8_t *reference = NULL;
50257bed822SMarkus Pfeiffer 	uint32_t dummy_buf[65536 / 4];
50357bed822SMarkus Pfeiffer 	uint32_t lba_max;
50457bed822SMarkus Pfeiffer 	uint32_t x;
50557bed822SMarkus Pfeiffer 	uint32_t y;
50657bed822SMarkus Pfeiffer 	uint32_t capacity_lba;
50757bed822SMarkus Pfeiffer 	uint32_t capacity_bs;
50857bed822SMarkus Pfeiffer 	time_t last_sec;
50957bed822SMarkus Pfeiffer 	uint8_t lun;
51057bed822SMarkus Pfeiffer 	int tries;
51157bed822SMarkus Pfeiffer 
51257bed822SMarkus Pfeiffer 	memset(&last_stat, 0, sizeof(last_stat));
51357bed822SMarkus Pfeiffer 
51457bed822SMarkus Pfeiffer 	switch (p->io_lun) {
51557bed822SMarkus Pfeiffer 	case USB_MSC_IO_LUN_0:
51657bed822SMarkus Pfeiffer 		lun = 0;
51757bed822SMarkus Pfeiffer 		break;
51857bed822SMarkus Pfeiffer 	case USB_MSC_IO_LUN_1:
51957bed822SMarkus Pfeiffer 		lun = 1;
52057bed822SMarkus Pfeiffer 		break;
52157bed822SMarkus Pfeiffer 	case USB_MSC_IO_LUN_2:
52257bed822SMarkus Pfeiffer 		lun = 2;
52357bed822SMarkus Pfeiffer 		break;
52457bed822SMarkus Pfeiffer 	case USB_MSC_IO_LUN_3:
52557bed822SMarkus Pfeiffer 		lun = 3;
52657bed822SMarkus Pfeiffer 		break;
52757bed822SMarkus Pfeiffer 	default:
52857bed822SMarkus Pfeiffer 		lun = 0;
52957bed822SMarkus Pfeiffer 		break;
53057bed822SMarkus Pfeiffer 	}
53157bed822SMarkus Pfeiffer 
53257bed822SMarkus Pfeiffer 	p->done = 0;
53357bed822SMarkus Pfeiffer 
53457bed822SMarkus Pfeiffer 	sense_recurse = p->try_sense_on_error ? 0 : 1;
53557bed822SMarkus Pfeiffer 
53657bed822SMarkus Pfeiffer 	printf("Resetting device ...\n");
53757bed822SMarkus Pfeiffer 
53857bed822SMarkus Pfeiffer 	do_msc_reset(lun);
53957bed822SMarkus Pfeiffer 
54057bed822SMarkus Pfeiffer 	printf("Testing SCSI commands ...\n");
54157bed822SMarkus Pfeiffer 
54257bed822SMarkus Pfeiffer 	if (p->try_all_lun) {
54357bed822SMarkus Pfeiffer 		printf("Requesting sense from LUN 0..255 ... ");
54457bed822SMarkus Pfeiffer 		for (x = y = 0; x != 256; x++) {
54557bed822SMarkus Pfeiffer 			if (do_msc_cmd(mode_sense_6, sizeof(mode_sense_6),
54657bed822SMarkus Pfeiffer 			    dummy_buf, 255, 1, 1, x, 0))
54757bed822SMarkus Pfeiffer 				y++;
54857bed822SMarkus Pfeiffer 
54957bed822SMarkus Pfeiffer 			if (libusb20_dev_check_connected(usb_pdev) != 0) {
55057bed822SMarkus Pfeiffer 				printf(" disconnect ");
55157bed822SMarkus Pfeiffer 				break;
55257bed822SMarkus Pfeiffer 			}
55357bed822SMarkus Pfeiffer 		}
55457bed822SMarkus Pfeiffer 		printf("Passed=%d, Failed=%d\n", 256 - y, y);
55557bed822SMarkus Pfeiffer 	}
55657bed822SMarkus Pfeiffer 	do_msc_cmd(mode_sense_6, sizeof(mode_sense_6),
55757bed822SMarkus Pfeiffer 	    dummy_buf, 255, 1, 1, lun, 0);
55857bed822SMarkus Pfeiffer 	do_msc_cmd(request_sense, sizeof(request_sense),
55957bed822SMarkus Pfeiffer 	    dummy_buf, 255, 1, 1, lun, 0);
56057bed822SMarkus Pfeiffer 
56157bed822SMarkus Pfeiffer 	for (tries = 0; tries != 4; tries++) {
56257bed822SMarkus Pfeiffer 
56357bed822SMarkus Pfeiffer 		memset(dummy_buf, 0, sizeof(dummy_buf));
56457bed822SMarkus Pfeiffer 
56557bed822SMarkus Pfeiffer 		if (do_msc_cmd(read_capacity, sizeof(read_capacity),
56657bed822SMarkus Pfeiffer 		    dummy_buf, 255, 1, 1, lun, 0) != 0) {
56757bed822SMarkus Pfeiffer 			printf("Cannot read disk capacity (%u / 4)\n", tries);
56857bed822SMarkus Pfeiffer 			if (tries == 3)
56957bed822SMarkus Pfeiffer 				return;
57057bed822SMarkus Pfeiffer 			usleep(50000);
57157bed822SMarkus Pfeiffer 			continue;
57257bed822SMarkus Pfeiffer 		} else {
57357bed822SMarkus Pfeiffer 			break;
57457bed822SMarkus Pfeiffer 		}
57557bed822SMarkus Pfeiffer 	}
57657bed822SMarkus Pfeiffer 
57757bed822SMarkus Pfeiffer 	capacity_lba = be32toh(dummy_buf[0]);
57857bed822SMarkus Pfeiffer 	capacity_bs = be32toh(dummy_buf[1]);
57957bed822SMarkus Pfeiffer 
58057bed822SMarkus Pfeiffer 	printf("Disk reports a capacity of LBA=%u and BS=%u\n",
58157bed822SMarkus Pfeiffer 	    capacity_lba, capacity_bs);
58257bed822SMarkus Pfeiffer 
58357bed822SMarkus Pfeiffer 	block_size = capacity_bs;
58457bed822SMarkus Pfeiffer 
58557bed822SMarkus Pfeiffer 	if (capacity_bs > 65535) {
58657bed822SMarkus Pfeiffer 		printf("Blocksize is too big\n");
58757bed822SMarkus Pfeiffer 		return;
58857bed822SMarkus Pfeiffer 	}
58957bed822SMarkus Pfeiffer 	if (capacity_bs < 1) {
59057bed822SMarkus Pfeiffer 		printf("Blocksize is too small\n");
59157bed822SMarkus Pfeiffer 		return;
59257bed822SMarkus Pfeiffer 	}
59357bed822SMarkus Pfeiffer 	if (capacity_bs != 512)
59457bed822SMarkus Pfeiffer 		printf("INFO: Blocksize is not 512 bytes\n");
59557bed822SMarkus Pfeiffer 
596*129a2703SSascha Wildner 	if (p->try_shorter_wrapper_block) {
597*129a2703SSascha Wildner 		printf("Trying too short command wrapper:\n");
598*129a2703SSascha Wildner 		do_msc_shorter_cmd(lun);
599*129a2703SSascha Wildner 	}
600*129a2703SSascha Wildner 
60157bed822SMarkus Pfeiffer 	if (p->try_invalid_scsi_command) {
60257bed822SMarkus Pfeiffer 		int status;
60357bed822SMarkus Pfeiffer 
60457bed822SMarkus Pfeiffer 		for (tries = 0; tries != 4; tries++) {
60557bed822SMarkus Pfeiffer 
60657bed822SMarkus Pfeiffer 			printf("Trying invalid SCSI command: ");
60757bed822SMarkus Pfeiffer 
60857bed822SMarkus Pfeiffer 			status = do_msc_cmd(request_invalid,
60957bed822SMarkus Pfeiffer 			    sizeof(request_invalid), dummy_buf,
61057bed822SMarkus Pfeiffer 			    255, 1, 1, lun, 0);
61157bed822SMarkus Pfeiffer 
61257bed822SMarkus Pfeiffer 			printf("Result%s as expected\n", status ? "" : " NOT");
61357bed822SMarkus Pfeiffer 
61457bed822SMarkus Pfeiffer 			usleep(50000);
61557bed822SMarkus Pfeiffer 		}
61657bed822SMarkus Pfeiffer 	}
61757bed822SMarkus Pfeiffer 	if (p->try_invalid_wrapper_block) {
61857bed822SMarkus Pfeiffer 		int status;
61957bed822SMarkus Pfeiffer 
62057bed822SMarkus Pfeiffer 		for (tries = 0; tries != 4; tries++) {
62157bed822SMarkus Pfeiffer 
62257bed822SMarkus Pfeiffer 			printf("Trying invalid USB wrapper block signature: ");
62357bed822SMarkus Pfeiffer 
62457bed822SMarkus Pfeiffer 			xfer_wrapper_sig = 0x55663322;
62557bed822SMarkus Pfeiffer 
62657bed822SMarkus Pfeiffer 			status = do_msc_cmd(read_capacity,
62757bed822SMarkus Pfeiffer 			    sizeof(read_capacity), dummy_buf,
62857bed822SMarkus Pfeiffer 			    255, 1, 1, lun, 0);
62957bed822SMarkus Pfeiffer 
63057bed822SMarkus Pfeiffer 			printf("Result%s as expected\n", status ? "" : " NOT");
63157bed822SMarkus Pfeiffer 
63257bed822SMarkus Pfeiffer 			xfer_wrapper_sig = CBWSIGNATURE;
63357bed822SMarkus Pfeiffer 
63457bed822SMarkus Pfeiffer 			usleep(50000);
63557bed822SMarkus Pfeiffer 		}
63657bed822SMarkus Pfeiffer 	}
63757bed822SMarkus Pfeiffer 	do_msc_cmd(request_sense, sizeof(request_sense), dummy_buf, 255, 1, 1, lun, 0);
63857bed822SMarkus Pfeiffer 	do_msc_cmd(read_capacity, sizeof(read_capacity), dummy_buf, 255, 1, 1, lun, 0);
63957bed822SMarkus Pfeiffer 	do_msc_cmd(request_sense, sizeof(request_sense), dummy_buf, 255, 1, 1, lun, 0);
64057bed822SMarkus Pfeiffer 	do_msc_cmd(test_unit_ready, sizeof(test_unit_ready), 0, 0, 1, 1, lun, 0);
64157bed822SMarkus Pfeiffer 	do_msc_cmd(test_unit_ready, sizeof(test_unit_ready), 0, 0, 1, 1, lun, 0);
64257bed822SMarkus Pfeiffer 	do_msc_cmd(request_sense, sizeof(request_sense), dummy_buf, 255, 1, 1, lun, 0);
64357bed822SMarkus Pfeiffer 	do_msc_cmd(test_unit_ready, sizeof(test_unit_ready), 0, 0, 1, 1, lun, 0);
64457bed822SMarkus Pfeiffer 	do_msc_cmd(request_sense, sizeof(request_sense), dummy_buf, 255, 1, 1, lun, 0);
64557bed822SMarkus Pfeiffer 	do_msc_cmd(test_unit_ready, sizeof(test_unit_ready), 0, 0, 1, 1, lun, 0);
64657bed822SMarkus Pfeiffer 	do_msc_cmd(test_unit_ready, sizeof(test_unit_ready), 0, 0, 1, 1, lun, 0);
64757bed822SMarkus Pfeiffer 	do_msc_cmd(test_unit_ready, sizeof(test_unit_ready), 0, 0, 1, 1, lun, 0);
64857bed822SMarkus Pfeiffer 	do_msc_cmd(request_sense, sizeof(request_sense), dummy_buf, 255, 1, 1, lun, 0);
64957bed822SMarkus Pfeiffer 	do_msc_cmd(test_unit_ready, sizeof(test_unit_ready), 0, 0, 1, 1, lun, 0);
65057bed822SMarkus Pfeiffer 	do_msc_cmd(read_capacity, sizeof(read_capacity), dummy_buf, 255, 1, 1, lun, 0);
65157bed822SMarkus Pfeiffer 	do_msc_cmd(mode_page_inquiry, sizeof(mode_page_inquiry), dummy_buf, 255, 1, 1, lun, 0);
65257bed822SMarkus Pfeiffer 	do_msc_cmd(mode_page_inquiry, sizeof(mode_page_inquiry), dummy_buf, 255, 1, 1, lun, 0);
65357bed822SMarkus Pfeiffer 
65457bed822SMarkus Pfeiffer 	if (do_msc_cmd(prevent_removal, sizeof(prevent_removal),
65557bed822SMarkus Pfeiffer 	    0, 0, 1, 1, lun, 0)) {
65657bed822SMarkus Pfeiffer 		printf("INFO: Prevent medium removal failed\n");
65757bed822SMarkus Pfeiffer 	}
65857bed822SMarkus Pfeiffer 	if (do_msc_cmd(read_toc, sizeof(read_toc),
65957bed822SMarkus Pfeiffer 	    dummy_buf, 255, 1, 1, lun, 0)) {
66057bed822SMarkus Pfeiffer 		printf("INFO: Read Table Of Content failed\n");
66157bed822SMarkus Pfeiffer 	}
66257bed822SMarkus Pfeiffer 	if (p->try_last_lba) {
66357bed822SMarkus Pfeiffer 
66457bed822SMarkus Pfeiffer 		for (y = 0, x = (1UL << 31); x; x >>= 1) {
66557bed822SMarkus Pfeiffer 			if (do_read_10(x | y, block_size, dummy_buf, lun) == 0)
66657bed822SMarkus Pfeiffer 				y |= x;
66757bed822SMarkus Pfeiffer 		}
66857bed822SMarkus Pfeiffer 
66957bed822SMarkus Pfeiffer 		printf("Highest readable LBA: %u (%s), "
67057bed822SMarkus Pfeiffer 		    "Capacity is %u MBytes\n", y,
67157bed822SMarkus Pfeiffer 		    (capacity_lba != y) ? "WRONG" : "OK",
67257bed822SMarkus Pfeiffer 		    (int)((((uint64_t)(y) * (uint64_t)block_size) +
67357bed822SMarkus Pfeiffer 		    (uint64_t)block_size) / 1000000ULL));
67457bed822SMarkus Pfeiffer 	} else {
67557bed822SMarkus Pfeiffer 
67657bed822SMarkus Pfeiffer 		y = capacity_lba;
67757bed822SMarkus Pfeiffer 
67857bed822SMarkus Pfeiffer 		printf("Highest readable LBA: %u (not "
67957bed822SMarkus Pfeiffer 		    "verified), Capacity is %u MBytes\n", y,
68057bed822SMarkus Pfeiffer 		    (int)((((uint64_t)(y) * (uint64_t)block_size) +
68157bed822SMarkus Pfeiffer 		    (uint64_t)block_size) / 1000000ULL));
68257bed822SMarkus Pfeiffer 	}
68357bed822SMarkus Pfeiffer 
68457bed822SMarkus Pfeiffer 	if (y != 0xFFFFFFFFU)
68557bed822SMarkus Pfeiffer 		y++;
68657bed822SMarkus Pfeiffer 
68757bed822SMarkus Pfeiffer 	lba_max = y;
68857bed822SMarkus Pfeiffer 
68957bed822SMarkus Pfeiffer 	switch (p->io_area) {
69057bed822SMarkus Pfeiffer 	case USB_MSC_IO_AREA_1MB:
69157bed822SMarkus Pfeiffer 		lba_max = 1024;
69257bed822SMarkus Pfeiffer 		break;
69357bed822SMarkus Pfeiffer 	case USB_MSC_IO_AREA_16MB:
69457bed822SMarkus Pfeiffer 		lba_max = 1024 * 16;
69557bed822SMarkus Pfeiffer 		break;
69657bed822SMarkus Pfeiffer 	case USB_MSC_IO_AREA_256MB:
69757bed822SMarkus Pfeiffer 		lba_max = 1024 * 256;
69857bed822SMarkus Pfeiffer 		break;
69957bed822SMarkus Pfeiffer 	case USB_MSC_IO_AREA_COMPLETE:
70057bed822SMarkus Pfeiffer 	default:
70157bed822SMarkus Pfeiffer 		break;
70257bed822SMarkus Pfeiffer 	}
70357bed822SMarkus Pfeiffer 
70457bed822SMarkus Pfeiffer 	if (lba_max > 65535)
70557bed822SMarkus Pfeiffer 		lba_max = 65535;
70657bed822SMarkus Pfeiffer 
70757bed822SMarkus Pfeiffer 	printf("Highest testable LBA: %u\n", (int)lba_max);
70857bed822SMarkus Pfeiffer 
70957bed822SMarkus Pfeiffer 	buffer = malloc(block_size * lba_max);
71057bed822SMarkus Pfeiffer 	if (buffer == NULL) {
71157bed822SMarkus Pfeiffer 		printf("ERROR: Could not allocate memory\n");
71257bed822SMarkus Pfeiffer 		goto fail;
71357bed822SMarkus Pfeiffer 	}
71457bed822SMarkus Pfeiffer 	reference = malloc(block_size * lba_max);
71557bed822SMarkus Pfeiffer 	if (reference == NULL) {
71657bed822SMarkus Pfeiffer 		printf("ERROR: Could not allocate memory\n");
71757bed822SMarkus Pfeiffer 		goto fail;
71857bed822SMarkus Pfeiffer 	}
71957bed822SMarkus Pfeiffer retry_read_init:
72057bed822SMarkus Pfeiffer 
72157bed822SMarkus Pfeiffer 	printf("Setting up initial data pattern, "
72257bed822SMarkus Pfeiffer 	    "LBA limit = %u ... ", lba_max);
72357bed822SMarkus Pfeiffer 
72457bed822SMarkus Pfeiffer 	switch (p->io_mode) {
72557bed822SMarkus Pfeiffer 	case USB_MSC_IO_MODE_WRITE_ONCE_READ_ONLY:
72657bed822SMarkus Pfeiffer 	case USB_MSC_IO_MODE_WRITE_ONLY:
72757bed822SMarkus Pfeiffer 	case USB_MSC_IO_MODE_READ_WRITE:
72857bed822SMarkus Pfeiffer 
72957bed822SMarkus Pfeiffer 		switch (p->io_pattern) {
73057bed822SMarkus Pfeiffer 		case USB_MSC_IO_PATTERN_FIXED:
73157bed822SMarkus Pfeiffer 			for (x = 0; x != (block_size * lba_max); x += 8) {
73257bed822SMarkus Pfeiffer 				reference[x + 0] = x >> 24;
73357bed822SMarkus Pfeiffer 				reference[x + 1] = x >> 16;
73457bed822SMarkus Pfeiffer 				reference[x + 2] = x >> 8;
73557bed822SMarkus Pfeiffer 				reference[x + 3] = x >> 0;
73657bed822SMarkus Pfeiffer 				reference[x + 4] = 0xFF;
73757bed822SMarkus Pfeiffer 				reference[x + 5] = 0x00;
73857bed822SMarkus Pfeiffer 				reference[x + 6] = 0xFF;
73957bed822SMarkus Pfeiffer 				reference[x + 7] = 0x00;
74057bed822SMarkus Pfeiffer 			}
74157bed822SMarkus Pfeiffer 			if (do_write_10(0, lba_max * block_size,
74257bed822SMarkus Pfeiffer 			    reference, lun)) {
74357bed822SMarkus Pfeiffer 				printf("FAILED\n");
74457bed822SMarkus Pfeiffer 				lba_max /= 2;
74557bed822SMarkus Pfeiffer 				if (lba_max)
74657bed822SMarkus Pfeiffer 					goto retry_read_init;
74757bed822SMarkus Pfeiffer 				goto fail;
74857bed822SMarkus Pfeiffer 			}
74957bed822SMarkus Pfeiffer 			printf("SUCCESS\n");
75057bed822SMarkus Pfeiffer 			break;
75157bed822SMarkus Pfeiffer 		case USB_MSC_IO_PATTERN_RANDOM:
75257bed822SMarkus Pfeiffer 			for (x = 0; x != (block_size * lba_max); x++) {
75357bed822SMarkus Pfeiffer 				reference[x] = usb_ts_rand_noise() % 255U;
75457bed822SMarkus Pfeiffer 			}
75557bed822SMarkus Pfeiffer 			if (do_write_10(0, lba_max * block_size,
75657bed822SMarkus Pfeiffer 			    reference, lun)) {
75757bed822SMarkus Pfeiffer 				printf("FAILED\n");
75857bed822SMarkus Pfeiffer 				lba_max /= 2;
75957bed822SMarkus Pfeiffer 				if (lba_max)
76057bed822SMarkus Pfeiffer 					goto retry_read_init;
76157bed822SMarkus Pfeiffer 				goto fail;
76257bed822SMarkus Pfeiffer 			}
76357bed822SMarkus Pfeiffer 			printf("SUCCESS\n");
76457bed822SMarkus Pfeiffer 			break;
76557bed822SMarkus Pfeiffer 		default:
76657bed822SMarkus Pfeiffer 			if (do_read_10(0, lba_max * block_size,
76757bed822SMarkus Pfeiffer 			    reference, lun)) {
76857bed822SMarkus Pfeiffer 				printf("FAILED\n");
76957bed822SMarkus Pfeiffer 				lba_max /= 2;
77057bed822SMarkus Pfeiffer 				if (lba_max)
77157bed822SMarkus Pfeiffer 					goto retry_read_init;
77257bed822SMarkus Pfeiffer 				goto fail;
77357bed822SMarkus Pfeiffer 			}
77457bed822SMarkus Pfeiffer 			printf("SUCCESS\n");
77557bed822SMarkus Pfeiffer 			break;
77657bed822SMarkus Pfeiffer 		}
77757bed822SMarkus Pfeiffer 		break;
77857bed822SMarkus Pfeiffer 
77957bed822SMarkus Pfeiffer 	default:
78057bed822SMarkus Pfeiffer 		if (do_read_10(0, lba_max * block_size, reference, lun)) {
78157bed822SMarkus Pfeiffer 			printf("FAILED\n");
78257bed822SMarkus Pfeiffer 			lba_max /= 2;
78357bed822SMarkus Pfeiffer 			if (lba_max)
78457bed822SMarkus Pfeiffer 				goto retry_read_init;
78557bed822SMarkus Pfeiffer 			goto fail;
78657bed822SMarkus Pfeiffer 		}
78757bed822SMarkus Pfeiffer 		printf("SUCCESS\n");
78857bed822SMarkus Pfeiffer 		break;
78957bed822SMarkus Pfeiffer 	}
79057bed822SMarkus Pfeiffer 
79157bed822SMarkus Pfeiffer 
79257bed822SMarkus Pfeiffer 	if (p->try_abort_data_write) {
79357bed822SMarkus Pfeiffer 		if (do_write_10(0, (2 * block_size) | 1, reference, lun))
79457bed822SMarkus Pfeiffer 			printf("Aborted data write failed (OK)!\n");
79557bed822SMarkus Pfeiffer 		else
79657bed822SMarkus Pfeiffer 			printf("Aborted data write did not fail (ERROR)!\n");
79757bed822SMarkus Pfeiffer 
79857bed822SMarkus Pfeiffer 		if (do_read_10(0, (2 * block_size), reference, lun))
79957bed822SMarkus Pfeiffer 			printf("Post-aborted data read failed (ERROR)\n");
80057bed822SMarkus Pfeiffer 		else
80157bed822SMarkus Pfeiffer 			printf("Post-aborted data read success (OK)!\n");
80257bed822SMarkus Pfeiffer 	}
80357bed822SMarkus Pfeiffer 	printf("Starting test ...\n");
80457bed822SMarkus Pfeiffer 
80557bed822SMarkus Pfeiffer 	gettimeofday(&ref_tv, 0);
80657bed822SMarkus Pfeiffer 
80757bed822SMarkus Pfeiffer 	last_sec = ref_tv.tv_sec;
80857bed822SMarkus Pfeiffer 
80957bed822SMarkus Pfeiffer 	printf("\n");
81057bed822SMarkus Pfeiffer 
81157bed822SMarkus Pfeiffer 	while (1) {
81257bed822SMarkus Pfeiffer 
81357bed822SMarkus Pfeiffer 		gettimeofday(&sub_tv, 0);
81457bed822SMarkus Pfeiffer 
81557bed822SMarkus Pfeiffer 		if (last_sec != sub_tv.tv_sec) {
81657bed822SMarkus Pfeiffer 
81757bed822SMarkus Pfeiffer 			printf("STATUS: ID=%u, RX=%u bytes/sec, "
81857bed822SMarkus Pfeiffer 			    "TX=%u bytes/sec, ERR=%u, RST=%u, DERR=%u\n",
81957bed822SMarkus Pfeiffer 			    (int)xfer_current_id,
82057bed822SMarkus Pfeiffer 			    (int)(stats.xfer_rx_bytes -
82157bed822SMarkus Pfeiffer 			    last_stat.xfer_rx_bytes),
82257bed822SMarkus Pfeiffer 			    (int)(stats.xfer_tx_bytes -
82357bed822SMarkus Pfeiffer 			    last_stat.xfer_tx_bytes),
82457bed822SMarkus Pfeiffer 			    (int)(stats.xfer_error),
82557bed822SMarkus Pfeiffer 			    (int)(stats.xfer_reset),
82657bed822SMarkus Pfeiffer 			    (int)(stats.data_error));
82757bed822SMarkus Pfeiffer 
82857bed822SMarkus Pfeiffer 			fflush(stdout);
82957bed822SMarkus Pfeiffer 
83057bed822SMarkus Pfeiffer 			last_sec = sub_tv.tv_sec;
83157bed822SMarkus Pfeiffer 			last_stat = stats;
83257bed822SMarkus Pfeiffer 		}
83357bed822SMarkus Pfeiffer 		timersub(&sub_tv, &ref_tv, &res_tv);
83457bed822SMarkus Pfeiffer 
835*129a2703SSascha Wildner 		if ((res_tv.tv_sec < 0) || (res_tv.tv_sec >= (int)p->duration))
83657bed822SMarkus Pfeiffer 			break;
83757bed822SMarkus Pfeiffer 
83857bed822SMarkus Pfeiffer 		do_io_test(p, lun, lba_max, buffer, reference);
83957bed822SMarkus Pfeiffer 
84057bed822SMarkus Pfeiffer 		if (libusb20_dev_check_connected(usb_pdev) != 0) {
84157bed822SMarkus Pfeiffer 			printf("Device disconnected\n");
84257bed822SMarkus Pfeiffer 			break;
84357bed822SMarkus Pfeiffer 		}
84457bed822SMarkus Pfeiffer 		if (p->done) {
84557bed822SMarkus Pfeiffer 			printf("Maximum number of errors exceeded\n");
84657bed822SMarkus Pfeiffer 			break;
84757bed822SMarkus Pfeiffer 		}
84857bed822SMarkus Pfeiffer 	}
84957bed822SMarkus Pfeiffer 
85057bed822SMarkus Pfeiffer 	printf("\nTest done!\n");
85157bed822SMarkus Pfeiffer 
85257bed822SMarkus Pfeiffer fail:
85357bed822SMarkus Pfeiffer 	if (buffer)
85457bed822SMarkus Pfeiffer 		free(buffer);
85557bed822SMarkus Pfeiffer 	if (reference)
85657bed822SMarkus Pfeiffer 		free(reference);
85757bed822SMarkus Pfeiffer }
85857bed822SMarkus Pfeiffer 
85957bed822SMarkus Pfeiffer void
show_host_device_selection(uint8_t level,uint16_t * pvid,uint16_t * ppid)86057bed822SMarkus Pfeiffer show_host_device_selection(uint8_t level, uint16_t *pvid, uint16_t *ppid)
86157bed822SMarkus Pfeiffer {
86257bed822SMarkus Pfeiffer 	struct libusb20_backend *pbe;
86357bed822SMarkus Pfeiffer 	struct libusb20_device *pdev;
86457bed822SMarkus Pfeiffer 	struct LIBUSB20_DEVICE_DESC_DECODED *ddesc;
86557bed822SMarkus Pfeiffer 
86657bed822SMarkus Pfeiffer 	uint16_t vid[USB_DEVICES_MAX];
86757bed822SMarkus Pfeiffer 	uint16_t pid[USB_DEVICES_MAX];
86857bed822SMarkus Pfeiffer 
86957bed822SMarkus Pfeiffer 	int index;
87057bed822SMarkus Pfeiffer 	int sel;
87157bed822SMarkus Pfeiffer 
87257bed822SMarkus Pfeiffer 	const char *ptr;
87357bed822SMarkus Pfeiffer 
87457bed822SMarkus Pfeiffer top:
87557bed822SMarkus Pfeiffer 	pbe = libusb20_be_alloc_default();
87657bed822SMarkus Pfeiffer 	pdev = NULL;
87757bed822SMarkus Pfeiffer 	index = 0;
87857bed822SMarkus Pfeiffer 
87957bed822SMarkus Pfeiffer 	printf("\n[] Select USB device:\n");
88057bed822SMarkus Pfeiffer 
88157bed822SMarkus Pfeiffer 	while ((pdev = libusb20_be_device_foreach(pbe, pdev))) {
88257bed822SMarkus Pfeiffer 
88357bed822SMarkus Pfeiffer 		if (libusb20_dev_get_mode(pdev) != LIBUSB20_MODE_HOST)
88457bed822SMarkus Pfeiffer 			continue;
88557bed822SMarkus Pfeiffer 
88657bed822SMarkus Pfeiffer 		if (index < USB_DEVICES_MAX) {
88757bed822SMarkus Pfeiffer 			ddesc = libusb20_dev_get_device_desc(pdev);
88857bed822SMarkus Pfeiffer 			ptr = libusb20_dev_get_desc(pdev);
88957bed822SMarkus Pfeiffer 			printf("%s%d) %s\n", indent[level], index, ptr);
89057bed822SMarkus Pfeiffer 			vid[index] = ddesc->idVendor;
89157bed822SMarkus Pfeiffer 			pid[index] = ddesc->idProduct;
89257bed822SMarkus Pfeiffer 			index++;
89357bed822SMarkus Pfeiffer 		} else {
89457bed822SMarkus Pfeiffer 			break;
89557bed822SMarkus Pfeiffer 		}
89657bed822SMarkus Pfeiffer 	}
89757bed822SMarkus Pfeiffer 
89857bed822SMarkus Pfeiffer 	printf("%sr) Refresh device list\n", indent[level]);
89957bed822SMarkus Pfeiffer 	printf("%sx) Return to previous menu\n", indent[level]);
90057bed822SMarkus Pfeiffer 
90157bed822SMarkus Pfeiffer 	/* release data */
90257bed822SMarkus Pfeiffer 	libusb20_be_free(pbe);
90357bed822SMarkus Pfeiffer 
90457bed822SMarkus Pfeiffer 	sel = get_integer();
90557bed822SMarkus Pfeiffer 
90657bed822SMarkus Pfeiffer 	if (sel == -2)
90757bed822SMarkus Pfeiffer 		goto top;
90857bed822SMarkus Pfeiffer 
90957bed822SMarkus Pfeiffer 	if ((sel < 0) || (sel >= index)) {
91057bed822SMarkus Pfeiffer 		*pvid = 0;
91157bed822SMarkus Pfeiffer 		*ppid = 0;
91257bed822SMarkus Pfeiffer 		return;
91357bed822SMarkus Pfeiffer 	}
91457bed822SMarkus Pfeiffer 	*pvid = vid[sel];
91557bed822SMarkus Pfeiffer 	*ppid = pid[sel];
91657bed822SMarkus Pfeiffer }
91757bed822SMarkus Pfeiffer 
91857bed822SMarkus Pfeiffer struct libusb20_device *
find_usb_device(uint16_t vid,uint16_t pid)91957bed822SMarkus Pfeiffer find_usb_device(uint16_t vid, uint16_t pid)
92057bed822SMarkus Pfeiffer {
92157bed822SMarkus Pfeiffer 	struct libusb20_backend *pbe = libusb20_be_alloc_default();
92257bed822SMarkus Pfeiffer 	struct libusb20_device *pdev = NULL;
92357bed822SMarkus Pfeiffer 	struct LIBUSB20_DEVICE_DESC_DECODED *ddesc;
92457bed822SMarkus Pfeiffer 
92557bed822SMarkus Pfeiffer 	while ((pdev = libusb20_be_device_foreach(pbe, pdev))) {
92657bed822SMarkus Pfeiffer 
92757bed822SMarkus Pfeiffer 		if (libusb20_dev_get_mode(pdev) != LIBUSB20_MODE_HOST)
92857bed822SMarkus Pfeiffer 			continue;
92957bed822SMarkus Pfeiffer 
93057bed822SMarkus Pfeiffer 		ddesc = libusb20_dev_get_device_desc(pdev);
93157bed822SMarkus Pfeiffer 
93257bed822SMarkus Pfeiffer 		if ((vid == ddesc->idVendor) &&
93357bed822SMarkus Pfeiffer 		    (pid == ddesc->idProduct)) {
93457bed822SMarkus Pfeiffer 			libusb20_be_dequeue_device(pbe, pdev);
93557bed822SMarkus Pfeiffer 			break;
93657bed822SMarkus Pfeiffer 		}
93757bed822SMarkus Pfeiffer 	}
93857bed822SMarkus Pfeiffer 
93957bed822SMarkus Pfeiffer 	/* release data */
94057bed822SMarkus Pfeiffer 	libusb20_be_free(pbe);
94157bed822SMarkus Pfeiffer 
94257bed822SMarkus Pfeiffer 	return (pdev);
94357bed822SMarkus Pfeiffer }
94457bed822SMarkus Pfeiffer 
94557bed822SMarkus Pfeiffer void
find_usb_endpoints(struct libusb20_device * pdev,uint8_t class,uint8_t subclass,uint8_t protocol,uint8_t alt_setting,uint8_t * pif,uint8_t * in_ep,uint8_t * out_ep,uint8_t next_if)94657bed822SMarkus Pfeiffer find_usb_endpoints(struct libusb20_device *pdev, uint8_t class,
94757bed822SMarkus Pfeiffer     uint8_t subclass, uint8_t protocol, uint8_t alt_setting,
94857bed822SMarkus Pfeiffer     uint8_t *pif, uint8_t *in_ep, uint8_t *out_ep, uint8_t next_if)
94957bed822SMarkus Pfeiffer {
95057bed822SMarkus Pfeiffer 	struct libusb20_config *pcfg;
95157bed822SMarkus Pfeiffer 	struct libusb20_interface *iface;
95257bed822SMarkus Pfeiffer 	struct libusb20_endpoint *ep;
95357bed822SMarkus Pfeiffer 	uint8_t x;
95457bed822SMarkus Pfeiffer 	uint8_t y;
95557bed822SMarkus Pfeiffer 	uint8_t z;
95657bed822SMarkus Pfeiffer 
95757bed822SMarkus Pfeiffer 	*in_ep = 0;
95857bed822SMarkus Pfeiffer 	*out_ep = 0;
95957bed822SMarkus Pfeiffer 	*pif = 0;
96057bed822SMarkus Pfeiffer 
96157bed822SMarkus Pfeiffer 	pcfg = libusb20_dev_alloc_config(pdev,
96257bed822SMarkus Pfeiffer 	    libusb20_dev_get_config_index(pdev));
96357bed822SMarkus Pfeiffer 
96457bed822SMarkus Pfeiffer 	if (pcfg == NULL)
96557bed822SMarkus Pfeiffer 		return;
96657bed822SMarkus Pfeiffer 
96757bed822SMarkus Pfeiffer 	for (x = 0; x != pcfg->num_interface; x++) {
96857bed822SMarkus Pfeiffer 
96957bed822SMarkus Pfeiffer 		y = alt_setting;
97057bed822SMarkus Pfeiffer 
97157bed822SMarkus Pfeiffer 		iface = (pcfg->interface + x);
97257bed822SMarkus Pfeiffer 
97357bed822SMarkus Pfeiffer 		if ((iface->desc.bInterfaceClass == class) &&
97457bed822SMarkus Pfeiffer 		    (iface->desc.bInterfaceSubClass == subclass ||
97557bed822SMarkus Pfeiffer 		    subclass == 255) &&
97657bed822SMarkus Pfeiffer 		    (iface->desc.bInterfaceProtocol == protocol ||
97757bed822SMarkus Pfeiffer 		    protocol == 255)) {
97857bed822SMarkus Pfeiffer 
97957bed822SMarkus Pfeiffer 			if (next_if) {
98057bed822SMarkus Pfeiffer 				x++;
98157bed822SMarkus Pfeiffer 				if (x == pcfg->num_interface)
98257bed822SMarkus Pfeiffer 					break;
98357bed822SMarkus Pfeiffer 				iface = (pcfg->interface + x);
98457bed822SMarkus Pfeiffer 			}
98557bed822SMarkus Pfeiffer 			*pif = x;
98657bed822SMarkus Pfeiffer 
98757bed822SMarkus Pfeiffer 			for (z = 0; z != iface->num_endpoints; z++) {
98857bed822SMarkus Pfeiffer 				ep = iface->endpoints + z;
98957bed822SMarkus Pfeiffer 
99057bed822SMarkus Pfeiffer 				/* BULK only */
99157bed822SMarkus Pfeiffer 				if ((ep->desc.bmAttributes & 3) != 2)
99257bed822SMarkus Pfeiffer 					continue;
99357bed822SMarkus Pfeiffer 
99457bed822SMarkus Pfeiffer 				if (ep->desc.bEndpointAddress & 0x80)
99557bed822SMarkus Pfeiffer 					*in_ep = ep->desc.bEndpointAddress;
99657bed822SMarkus Pfeiffer 				else
99757bed822SMarkus Pfeiffer 					*out_ep = ep->desc.bEndpointAddress;
99857bed822SMarkus Pfeiffer 			}
99957bed822SMarkus Pfeiffer 			break;
100057bed822SMarkus Pfeiffer 		}
100157bed822SMarkus Pfeiffer 	}
100257bed822SMarkus Pfeiffer 
100357bed822SMarkus Pfeiffer 	free(pcfg);
100457bed822SMarkus Pfeiffer }
100557bed822SMarkus Pfeiffer 
100657bed822SMarkus Pfeiffer static void
exec_host_msc_test(struct usb_msc_params * p,uint16_t vid,uint16_t pid)100757bed822SMarkus Pfeiffer exec_host_msc_test(struct usb_msc_params *p, uint16_t vid, uint16_t pid)
100857bed822SMarkus Pfeiffer {
100957bed822SMarkus Pfeiffer 	struct libusb20_device *pdev;
101057bed822SMarkus Pfeiffer 
101157bed822SMarkus Pfeiffer 	uint8_t in_ep;
101257bed822SMarkus Pfeiffer 	uint8_t out_ep;
101357bed822SMarkus Pfeiffer 	uint8_t iface;
101457bed822SMarkus Pfeiffer 
101557bed822SMarkus Pfeiffer 	int error;
101657bed822SMarkus Pfeiffer 
101757bed822SMarkus Pfeiffer 	memset(&stats, 0, sizeof(stats));
101857bed822SMarkus Pfeiffer 
101957bed822SMarkus Pfeiffer 	xfer_current_id = 0;
102057bed822SMarkus Pfeiffer 	xfer_wrapper_sig = CBWSIGNATURE;
102157bed822SMarkus Pfeiffer 
102257bed822SMarkus Pfeiffer 	pdev = find_usb_device(vid, pid);
102357bed822SMarkus Pfeiffer 	if (pdev == NULL) {
102457bed822SMarkus Pfeiffer 		printf("USB device not found\n");
102557bed822SMarkus Pfeiffer 		return;
102657bed822SMarkus Pfeiffer 	}
102757bed822SMarkus Pfeiffer 	find_usb_endpoints(pdev, 8, 6, 0x50, 0, &iface, &in_ep, &out_ep, 0);
102857bed822SMarkus Pfeiffer 
102957bed822SMarkus Pfeiffer 	if ((in_ep == 0) || (out_ep == 0)) {
103057bed822SMarkus Pfeiffer 		printf("Could not find USB endpoints\n");
103157bed822SMarkus Pfeiffer 		libusb20_dev_free(pdev);
103257bed822SMarkus Pfeiffer 		return;
103357bed822SMarkus Pfeiffer 	}
103457bed822SMarkus Pfeiffer 	printf("Attaching to: %s @ iface %d\n",
103557bed822SMarkus Pfeiffer 	    libusb20_dev_get_desc(pdev), iface);
103657bed822SMarkus Pfeiffer 
103757bed822SMarkus Pfeiffer 	if (libusb20_dev_open(pdev, 2)) {
103857bed822SMarkus Pfeiffer 		printf("Could not open USB device\n");
103957bed822SMarkus Pfeiffer 		libusb20_dev_free(pdev);
104057bed822SMarkus Pfeiffer 		return;
104157bed822SMarkus Pfeiffer 	}
104257bed822SMarkus Pfeiffer 	if (libusb20_dev_detach_kernel_driver(pdev, iface)) {
104357bed822SMarkus Pfeiffer 		printf("WARNING: Could not detach kernel driver\n");
104457bed822SMarkus Pfeiffer 	}
104557bed822SMarkus Pfeiffer 	xfer_in = libusb20_tr_get_pointer(pdev, 0);
104657bed822SMarkus Pfeiffer 	error = libusb20_tr_open(xfer_in, 65536, 1, in_ep);
104757bed822SMarkus Pfeiffer 	if (error) {
104857bed822SMarkus Pfeiffer 		printf("Could not open USB endpoint %d\n", in_ep);
104957bed822SMarkus Pfeiffer 		libusb20_dev_free(pdev);
105057bed822SMarkus Pfeiffer 		return;
105157bed822SMarkus Pfeiffer 	}
105257bed822SMarkus Pfeiffer 	xfer_out = libusb20_tr_get_pointer(pdev, 1);
105357bed822SMarkus Pfeiffer 	error = libusb20_tr_open(xfer_out, 65536, 1, out_ep);
105457bed822SMarkus Pfeiffer 	if (error) {
105557bed822SMarkus Pfeiffer 		printf("Could not open USB endpoint %d\n", out_ep);
105657bed822SMarkus Pfeiffer 		libusb20_dev_free(pdev);
105757bed822SMarkus Pfeiffer 		return;
105857bed822SMarkus Pfeiffer 	}
105957bed822SMarkus Pfeiffer 	usb_pdev = pdev;
106057bed822SMarkus Pfeiffer 	usb_iface = iface;
106157bed822SMarkus Pfeiffer 
106257bed822SMarkus Pfeiffer 	usb_msc_test(p);
106357bed822SMarkus Pfeiffer 
106457bed822SMarkus Pfeiffer 	libusb20_dev_free(pdev);
106557bed822SMarkus Pfeiffer }
106657bed822SMarkus Pfeiffer 
106757bed822SMarkus Pfeiffer static void
set_defaults(struct usb_msc_params * p)106857bed822SMarkus Pfeiffer set_defaults(struct usb_msc_params *p)
106957bed822SMarkus Pfeiffer {
107057bed822SMarkus Pfeiffer 	memset(p, 0, sizeof(*p));
107157bed822SMarkus Pfeiffer 
107257bed822SMarkus Pfeiffer 	p->duration = 60;		/* seconds */
107357bed822SMarkus Pfeiffer 	p->try_invalid_scsi_command = 1;
107457bed822SMarkus Pfeiffer 	p->try_invalid_wrapper_block = 1;
107557bed822SMarkus Pfeiffer 	p->try_last_lba = 1;
107657bed822SMarkus Pfeiffer 	p->max_errors = -1;
107757bed822SMarkus Pfeiffer }
107857bed822SMarkus Pfeiffer 
107957bed822SMarkus Pfeiffer static const char *
get_io_mode(const struct usb_msc_params * p)108057bed822SMarkus Pfeiffer get_io_mode(const struct usb_msc_params *p)
108157bed822SMarkus Pfeiffer {
108257bed822SMarkus Pfeiffer 	;				/* indent fix */
108357bed822SMarkus Pfeiffer 	switch (p->io_mode) {
108457bed822SMarkus Pfeiffer 	case USB_MSC_IO_MODE_READ_ONLY:
108557bed822SMarkus Pfeiffer 		return ("Read Only");
108657bed822SMarkus Pfeiffer 	case USB_MSC_IO_MODE_WRITE_ONCE_READ_ONLY:
108757bed822SMarkus Pfeiffer 		return ("Write Once, Read Only");
108857bed822SMarkus Pfeiffer 	case USB_MSC_IO_MODE_WRITE_ONLY:
108957bed822SMarkus Pfeiffer 		return ("Write Only");
109057bed822SMarkus Pfeiffer 	case USB_MSC_IO_MODE_READ_WRITE:
109157bed822SMarkus Pfeiffer 		return ("Read and Write");
109257bed822SMarkus Pfeiffer 	default:
109357bed822SMarkus Pfeiffer 		return ("Unknown");
109457bed822SMarkus Pfeiffer 	}
109557bed822SMarkus Pfeiffer }
109657bed822SMarkus Pfeiffer 
109757bed822SMarkus Pfeiffer static const char *
get_io_pattern(const struct usb_msc_params * p)109857bed822SMarkus Pfeiffer get_io_pattern(const struct usb_msc_params *p)
109957bed822SMarkus Pfeiffer {
110057bed822SMarkus Pfeiffer 	;				/* indent fix */
110157bed822SMarkus Pfeiffer 	switch (p->io_pattern) {
110257bed822SMarkus Pfeiffer 	case USB_MSC_IO_PATTERN_FIXED:
110357bed822SMarkus Pfeiffer 		return ("Fixed");
110457bed822SMarkus Pfeiffer 	case USB_MSC_IO_PATTERN_RANDOM:
110557bed822SMarkus Pfeiffer 		return ("Random");
110657bed822SMarkus Pfeiffer 	case USB_MSC_IO_PATTERN_PRESERVE:
110757bed822SMarkus Pfeiffer 		return ("Preserve");
110857bed822SMarkus Pfeiffer 	default:
110957bed822SMarkus Pfeiffer 		return ("Unknown");
111057bed822SMarkus Pfeiffer 	}
111157bed822SMarkus Pfeiffer }
111257bed822SMarkus Pfeiffer 
111357bed822SMarkus Pfeiffer static const char *
get_io_size(const struct usb_msc_params * p)111457bed822SMarkus Pfeiffer get_io_size(const struct usb_msc_params *p)
111557bed822SMarkus Pfeiffer {
111657bed822SMarkus Pfeiffer 	;				/* indent fix */
111757bed822SMarkus Pfeiffer 	switch (p->io_size) {
111857bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_RANDOM:
111957bed822SMarkus Pfeiffer 		return ("Random");
112057bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_INCREASING:
112157bed822SMarkus Pfeiffer 		return ("Increasing");
112257bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_FIXED_1BLK:
112357bed822SMarkus Pfeiffer 		return ("Single block");
112457bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_FIXED_2BLK:
112557bed822SMarkus Pfeiffer 		return ("2 blocks");
112657bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_FIXED_4BLK:
112757bed822SMarkus Pfeiffer 		return ("4 blocks");
112857bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_FIXED_8BLK:
112957bed822SMarkus Pfeiffer 		return ("8 blocks");
113057bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_FIXED_16BLK:
113157bed822SMarkus Pfeiffer 		return ("16 blocks");
113257bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_FIXED_32BLK:
113357bed822SMarkus Pfeiffer 		return ("32 blocks");
113457bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_FIXED_64BLK:
113557bed822SMarkus Pfeiffer 		return ("64 blocks");
113657bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_FIXED_128BLK:
113757bed822SMarkus Pfeiffer 		return ("128 blocks");
113857bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_FIXED_256BLK:
113957bed822SMarkus Pfeiffer 		return ("256 blocks");
114057bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_FIXED_512BLK:
114157bed822SMarkus Pfeiffer 		return ("512 blocks");
114257bed822SMarkus Pfeiffer 	case USB_MSC_IO_SIZE_FIXED_1024BLK:
114357bed822SMarkus Pfeiffer 		return ("1024 blocks");
114457bed822SMarkus Pfeiffer 	default:
114557bed822SMarkus Pfeiffer 		return ("Unknown");
114657bed822SMarkus Pfeiffer 	}
114757bed822SMarkus Pfeiffer }
114857bed822SMarkus Pfeiffer 
114957bed822SMarkus Pfeiffer static const char *
get_io_delay(const struct usb_msc_params * p)115057bed822SMarkus Pfeiffer get_io_delay(const struct usb_msc_params *p)
115157bed822SMarkus Pfeiffer {
115257bed822SMarkus Pfeiffer 	;				/* indent fix */
115357bed822SMarkus Pfeiffer 	switch (p->io_delay) {
115457bed822SMarkus Pfeiffer 	case USB_MSC_IO_DELAY_NONE:
115557bed822SMarkus Pfeiffer 		return ("None");
115657bed822SMarkus Pfeiffer 	case USB_MSC_IO_DELAY_RANDOM_10MS:
115757bed822SMarkus Pfeiffer 		return ("Random 10ms");
115857bed822SMarkus Pfeiffer 	case USB_MSC_IO_DELAY_RANDOM_100MS:
115957bed822SMarkus Pfeiffer 		return ("Random 100ms");
116057bed822SMarkus Pfeiffer 	case USB_MSC_IO_DELAY_FIXED_10MS:
116157bed822SMarkus Pfeiffer 		return ("Fixed 10ms");
116257bed822SMarkus Pfeiffer 	case USB_MSC_IO_DELAY_FIXED_100MS:
116357bed822SMarkus Pfeiffer 		return ("Fixed 100ms");
116457bed822SMarkus Pfeiffer 	default:
116557bed822SMarkus Pfeiffer 		return ("Unknown");
116657bed822SMarkus Pfeiffer 	}
116757bed822SMarkus Pfeiffer }
116857bed822SMarkus Pfeiffer 
116957bed822SMarkus Pfeiffer static const char *
get_io_offset(const struct usb_msc_params * p)117057bed822SMarkus Pfeiffer get_io_offset(const struct usb_msc_params *p)
117157bed822SMarkus Pfeiffer {
117257bed822SMarkus Pfeiffer 	;				/* indent fix */
117357bed822SMarkus Pfeiffer 	switch (p->io_offset) {
117457bed822SMarkus Pfeiffer 	case USB_MSC_IO_OFF_START_OF_DISK:
117557bed822SMarkus Pfeiffer 		return ("Start Of Disk");
117657bed822SMarkus Pfeiffer 	case USB_MSC_IO_OFF_RANDOM:
117757bed822SMarkus Pfeiffer 		return ("Random Offset");
117857bed822SMarkus Pfeiffer 	default:
117957bed822SMarkus Pfeiffer 		return ("Unknown");
118057bed822SMarkus Pfeiffer 	}
118157bed822SMarkus Pfeiffer }
118257bed822SMarkus Pfeiffer 
118357bed822SMarkus Pfeiffer static const char *
get_io_area(const struct usb_msc_params * p)118457bed822SMarkus Pfeiffer get_io_area(const struct usb_msc_params *p)
118557bed822SMarkus Pfeiffer {
118657bed822SMarkus Pfeiffer 	;				/* indent fix */
118757bed822SMarkus Pfeiffer 	switch (p->io_area) {
118857bed822SMarkus Pfeiffer 	case USB_MSC_IO_AREA_COMPLETE:
118957bed822SMarkus Pfeiffer 		return ("Complete Disk");
119057bed822SMarkus Pfeiffer 	case USB_MSC_IO_AREA_1MB:
119157bed822SMarkus Pfeiffer 		return ("First MegaByte");
119257bed822SMarkus Pfeiffer 	case USB_MSC_IO_AREA_16MB:
119357bed822SMarkus Pfeiffer 		return ("First 16 MegaBytes");
119457bed822SMarkus Pfeiffer 	case USB_MSC_IO_AREA_256MB:
119557bed822SMarkus Pfeiffer 		return ("First 256 MegaBytes");
119657bed822SMarkus Pfeiffer 	default:
119757bed822SMarkus Pfeiffer 		return ("Unknown");
119857bed822SMarkus Pfeiffer 	}
119957bed822SMarkus Pfeiffer }
120057bed822SMarkus Pfeiffer 
120157bed822SMarkus Pfeiffer void
show_host_msc_test(uint8_t level,uint16_t vid,uint16_t pid,uint32_t duration)120257bed822SMarkus Pfeiffer show_host_msc_test(uint8_t level, uint16_t vid,
120357bed822SMarkus Pfeiffer     uint16_t pid, uint32_t duration)
120457bed822SMarkus Pfeiffer {
120557bed822SMarkus Pfeiffer 	struct usb_msc_params params;
120657bed822SMarkus Pfeiffer 	uint8_t retval;
120757bed822SMarkus Pfeiffer 
120857bed822SMarkus Pfeiffer 	set_defaults(&params);
120957bed822SMarkus Pfeiffer 
121057bed822SMarkus Pfeiffer 	params.duration = duration;
121157bed822SMarkus Pfeiffer 
121257bed822SMarkus Pfeiffer 	while (1) {
121357bed822SMarkus Pfeiffer 
121457bed822SMarkus Pfeiffer 		retval = usb_ts_show_menu(level,
121557bed822SMarkus Pfeiffer 		    "Mass Storage Test Parameters",
121657bed822SMarkus Pfeiffer 		    " 1) Toggle I/O mode: <%s>\n"
121757bed822SMarkus Pfeiffer 		    " 2) Toggle I/O size: <%s>\n"
121857bed822SMarkus Pfeiffer 		    " 3) Toggle I/O delay: <%s>\n"
121957bed822SMarkus Pfeiffer 		    " 4) Toggle I/O offset: <%s>\n"
122057bed822SMarkus Pfeiffer 		    " 5) Toggle I/O area: <%s>\n"
122157bed822SMarkus Pfeiffer 		    " 6) Toggle I/O pattern: <%s>\n"
122257bed822SMarkus Pfeiffer 		    " 7) Toggle try invalid SCSI command: <%s>\n"
122357bed822SMarkus Pfeiffer 		    " 8) Toggle try invalid wrapper block: <%s>\n"
122457bed822SMarkus Pfeiffer 		    " 9) Toggle try invalid MaxPacketSize: <%s>\n"
122557bed822SMarkus Pfeiffer 		    "10) Toggle try last Logical Block Address: <%s>\n"
122657bed822SMarkus Pfeiffer 		    "11) Toggle I/O lun: <%d>\n"
122757bed822SMarkus Pfeiffer 		    "12) Set maximum number of errors: <%d>\n"
122857bed822SMarkus Pfeiffer 		    "13) Set test duration: <%d> seconds\n"
122957bed822SMarkus Pfeiffer 		    "14) Toggle try aborted write transfer: <%s>\n"
123057bed822SMarkus Pfeiffer 		    "15) Toggle request sense on error: <%s>\n"
123157bed822SMarkus Pfeiffer 		    "16) Toggle try all LUN: <%s>\n"
1232*129a2703SSascha Wildner 		    "17) Toggle try too short wrapper block: <%s>\n"
123357bed822SMarkus Pfeiffer 		    "20) Reset parameters\n"
123457bed822SMarkus Pfeiffer 		    "30) Start test (VID=0x%04x, PID=0x%04x)\n"
123557bed822SMarkus Pfeiffer 		    "40) Select another device\n"
123657bed822SMarkus Pfeiffer 		    " x) Return to previous menu \n",
123757bed822SMarkus Pfeiffer 		    get_io_mode(&params),
123857bed822SMarkus Pfeiffer 		    get_io_size(&params),
123957bed822SMarkus Pfeiffer 		    get_io_delay(&params),
124057bed822SMarkus Pfeiffer 		    get_io_offset(&params),
124157bed822SMarkus Pfeiffer 		    get_io_area(&params),
124257bed822SMarkus Pfeiffer 		    get_io_pattern(&params),
124357bed822SMarkus Pfeiffer 		    (params.try_invalid_scsi_command ? "YES" : "NO"),
124457bed822SMarkus Pfeiffer 		    (params.try_invalid_wrapper_block ? "YES" : "NO"),
124557bed822SMarkus Pfeiffer 		    (params.try_invalid_max_packet_size ? "YES" : "NO"),
124657bed822SMarkus Pfeiffer 		    (params.try_last_lba ? "YES" : "NO"),
124757bed822SMarkus Pfeiffer 		    params.io_lun,
124857bed822SMarkus Pfeiffer 		    (int)params.max_errors,
124957bed822SMarkus Pfeiffer 		    (int)params.duration,
125057bed822SMarkus Pfeiffer 		    (params.try_abort_data_write ? "YES" : "NO"),
125157bed822SMarkus Pfeiffer 		    (params.try_sense_on_error ? "YES" : "NO"),
125257bed822SMarkus Pfeiffer 		    (params.try_all_lun ? "YES" : "NO"),
1253*129a2703SSascha Wildner 		    (params.try_shorter_wrapper_block ? "YES" : "NO"),
125457bed822SMarkus Pfeiffer 		    vid, pid);
125557bed822SMarkus Pfeiffer 		switch (retval) {
125657bed822SMarkus Pfeiffer 		case 0:
125757bed822SMarkus Pfeiffer 			break;
125857bed822SMarkus Pfeiffer 		case 1:
125957bed822SMarkus Pfeiffer 			params.io_mode++;
126057bed822SMarkus Pfeiffer 			params.io_mode %= USB_MSC_IO_MODE_MAX;
126157bed822SMarkus Pfeiffer 			break;
126257bed822SMarkus Pfeiffer 		case 2:
126357bed822SMarkus Pfeiffer 			params.io_size++;
126457bed822SMarkus Pfeiffer 			params.io_size %= USB_MSC_IO_SIZE_MAX;
126557bed822SMarkus Pfeiffer 			break;
126657bed822SMarkus Pfeiffer 		case 3:
126757bed822SMarkus Pfeiffer 			params.io_delay++;
126857bed822SMarkus Pfeiffer 			params.io_delay %= USB_MSC_IO_DELAY_MAX;
126957bed822SMarkus Pfeiffer 			break;
127057bed822SMarkus Pfeiffer 		case 4:
127157bed822SMarkus Pfeiffer 			params.io_offset++;
127257bed822SMarkus Pfeiffer 			params.io_offset %= USB_MSC_IO_OFF_MAX;
127357bed822SMarkus Pfeiffer 			break;
127457bed822SMarkus Pfeiffer 		case 5:
127557bed822SMarkus Pfeiffer 			params.io_area++;
127657bed822SMarkus Pfeiffer 			params.io_area %= USB_MSC_IO_AREA_MAX;
127757bed822SMarkus Pfeiffer 			break;
127857bed822SMarkus Pfeiffer 		case 6:
127957bed822SMarkus Pfeiffer 			params.io_pattern++;
128057bed822SMarkus Pfeiffer 			params.io_pattern %= USB_MSC_IO_PATTERN_MAX;
128157bed822SMarkus Pfeiffer 			break;
128257bed822SMarkus Pfeiffer 		case 7:
128357bed822SMarkus Pfeiffer 			params.try_invalid_scsi_command ^= 1;
128457bed822SMarkus Pfeiffer 			break;
128557bed822SMarkus Pfeiffer 		case 8:
128657bed822SMarkus Pfeiffer 			params.try_invalid_wrapper_block ^= 1;
128757bed822SMarkus Pfeiffer 			break;
128857bed822SMarkus Pfeiffer 		case 9:
128957bed822SMarkus Pfeiffer 			params.try_invalid_max_packet_size ^= 1;
129057bed822SMarkus Pfeiffer 			break;
129157bed822SMarkus Pfeiffer 		case 10:
129257bed822SMarkus Pfeiffer 			params.try_last_lba ^= 1;
129357bed822SMarkus Pfeiffer 			break;
129457bed822SMarkus Pfeiffer 		case 11:
129557bed822SMarkus Pfeiffer 			params.io_lun++;
129657bed822SMarkus Pfeiffer 			params.io_lun %= USB_MSC_IO_LUN_MAX;
129757bed822SMarkus Pfeiffer 			break;
129857bed822SMarkus Pfeiffer 		case 12:
129957bed822SMarkus Pfeiffer 			params.max_errors = get_integer();
130057bed822SMarkus Pfeiffer 			break;
130157bed822SMarkus Pfeiffer 		case 13:
130257bed822SMarkus Pfeiffer 			params.duration = get_integer();
130357bed822SMarkus Pfeiffer 			break;
130457bed822SMarkus Pfeiffer 		case 14:
130557bed822SMarkus Pfeiffer 			params.try_abort_data_write ^= 1;
130657bed822SMarkus Pfeiffer 			break;
130757bed822SMarkus Pfeiffer 		case 15:
130857bed822SMarkus Pfeiffer 			params.try_sense_on_error ^= 1;
130957bed822SMarkus Pfeiffer 			break;
131057bed822SMarkus Pfeiffer 		case 16:
131157bed822SMarkus Pfeiffer 			params.try_all_lun ^= 1;
131257bed822SMarkus Pfeiffer 			break;
1313*129a2703SSascha Wildner 		case 17:
1314*129a2703SSascha Wildner 			params.try_shorter_wrapper_block ^= 1;
1315*129a2703SSascha Wildner 			break;
131657bed822SMarkus Pfeiffer 		case 20:
131757bed822SMarkus Pfeiffer 			set_defaults(&params);
131857bed822SMarkus Pfeiffer 			break;
131957bed822SMarkus Pfeiffer 		case 30:
132057bed822SMarkus Pfeiffer 			exec_host_msc_test(&params, vid, pid);
132157bed822SMarkus Pfeiffer 			break;
132257bed822SMarkus Pfeiffer 		case 40:
132357bed822SMarkus Pfeiffer 			show_host_device_selection(level + 1, &vid, &pid);
132457bed822SMarkus Pfeiffer 			break;
132557bed822SMarkus Pfeiffer 		default:
132657bed822SMarkus Pfeiffer 			return;
132757bed822SMarkus Pfeiffer 		}
132857bed822SMarkus Pfeiffer 	}
132957bed822SMarkus Pfeiffer }
1330