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(&params);
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(&params),
1203*57bed822SMarkus Pfeiffer 		    get_io_size(&params),
1204*57bed822SMarkus Pfeiffer 		    get_io_delay(&params),
1205*57bed822SMarkus Pfeiffer 		    get_io_offset(&params),
1206*57bed822SMarkus Pfeiffer 		    get_io_area(&params),
1207*57bed822SMarkus Pfeiffer 		    get_io_pattern(&params),
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(&params);
1279*57bed822SMarkus Pfeiffer 			break;
1280*57bed822SMarkus Pfeiffer 		case 30:
1281*57bed822SMarkus Pfeiffer 			exec_host_msc_test(&params, 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