Deleted Added
full compact
usb_msctest.c (242364) usb_msctest.c (244503)
1/* $FreeBSD: head/sys/dev/usb/usb_msctest.c 242364 2012-10-30 16:56:16Z hselasky $ */
1/* $FreeBSD: head/sys/dev/usb/usb_msctest.c 244503 2012-12-20 18:38:02Z hselasky $ */
2/*-
3 * Copyright (c) 2008,2011 Hans Petter Selasky. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27/*
28 * The following file contains code that will detect USB autoinstall
29 * disks.
30 *
31 * TODO: Potentially we could add code to automatically detect USB
32 * mass storage quirks for not supported SCSI commands!
33 */
34
35#include <sys/stdint.h>
36#include <sys/stddef.h>
37#include <sys/param.h>
38#include <sys/queue.h>
39#include <sys/types.h>
40#include <sys/systm.h>
41#include <sys/kernel.h>
42#include <sys/bus.h>
43#include <sys/module.h>
44#include <sys/lock.h>
45#include <sys/mutex.h>
46#include <sys/condvar.h>
47#include <sys/sysctl.h>
48#include <sys/sx.h>
49#include <sys/unistd.h>
50#include <sys/callout.h>
51#include <sys/malloc.h>
52#include <sys/priv.h>
53
54#include <dev/usb/usb.h>
55#include <dev/usb/usbdi.h>
56#include <dev/usb/usbdi_util.h>
57
58#define USB_DEBUG_VAR usb_debug
59
60#include <dev/usb/usb_busdma.h>
61#include <dev/usb/usb_process.h>
62#include <dev/usb/usb_transfer.h>
63#include <dev/usb/usb_msctest.h>
64#include <dev/usb/usb_debug.h>
65#include <dev/usb/usb_device.h>
66#include <dev/usb/usb_request.h>
67#include <dev/usb/usb_util.h>
68#include <dev/usb/quirk/usb_quirk.h>
69
70enum {
71 ST_COMMAND,
72 ST_DATA_RD,
73 ST_DATA_RD_CS,
74 ST_DATA_WR,
75 ST_DATA_WR_CS,
76 ST_STATUS,
77 ST_MAX,
78};
79
80enum {
81 DIR_IN,
82 DIR_OUT,
83 DIR_NONE,
84};
85
86#define SCSI_MAX_LEN 0x100
87#define SCSI_INQ_LEN 0x24
88#define SCSI_SENSE_LEN 0xFF
89
90static uint8_t scsi_test_unit_ready[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
91static uint8_t scsi_inquiry[] = { 0x12, 0x00, 0x00, 0x00, SCSI_INQ_LEN, 0x00 };
92static uint8_t scsi_rezero_init[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
93static uint8_t scsi_start_stop_unit[] = { 0x1b, 0x00, 0x00, 0x00, 0x02, 0x00 };
94static uint8_t scsi_ztestor_eject[] = { 0x85, 0x01, 0x01, 0x01, 0x18, 0x01,
95 0x01, 0x01, 0x01, 0x01, 0x00, 0x00 };
96static uint8_t scsi_cmotech_eject[] = { 0xff, 0x52, 0x44, 0x45, 0x56, 0x43,
97 0x48, 0x47 };
98static uint8_t scsi_huawei_eject[] = { 0x11, 0x06, 0x00, 0x00, 0x00, 0x00,
99 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100 0x00, 0x00, 0x00, 0x00 };
101static uint8_t scsi_tct_eject[] = { 0x06, 0xf5, 0x04, 0x02, 0x52, 0x70 };
102static uint8_t scsi_sync_cache[] = { 0x35, 0x00, 0x00, 0x00, 0x00, 0x00,
103 0x00, 0x00, 0x00, 0x00 };
104static uint8_t scsi_request_sense[] = { 0x03, 0x00, 0x00, 0x00, 0x12, 0x00,
105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
106static uint8_t scsi_read_capacity[] = { 0x25, 0x00, 0x00, 0x00, 0x00, 0x00,
107 0x00, 0x00, 0x00, 0x00 };
108
109#define BULK_SIZE 64 /* dummy */
110#define ERR_CSW_FAILED -1
111
112/* Command Block Wrapper */
113struct bbb_cbw {
114 uDWord dCBWSignature;
115#define CBWSIGNATURE 0x43425355
116 uDWord dCBWTag;
117 uDWord dCBWDataTransferLength;
118 uByte bCBWFlags;
119#define CBWFLAGS_OUT 0x00
120#define CBWFLAGS_IN 0x80
121 uByte bCBWLUN;
122 uByte bCDBLength;
123#define CBWCDBLENGTH 16
124 uByte CBWCDB[CBWCDBLENGTH];
125} __packed;
126
127/* Command Status Wrapper */
128struct bbb_csw {
129 uDWord dCSWSignature;
130#define CSWSIGNATURE 0x53425355
131 uDWord dCSWTag;
132 uDWord dCSWDataResidue;
133 uByte bCSWStatus;
134#define CSWSTATUS_GOOD 0x0
135#define CSWSTATUS_FAILED 0x1
136#define CSWSTATUS_PHASE 0x2
137} __packed;
138
139struct bbb_transfer {
140 struct mtx mtx;
141 struct cv cv;
2/*-
3 * Copyright (c) 2008,2011 Hans Petter Selasky. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27/*
28 * The following file contains code that will detect USB autoinstall
29 * disks.
30 *
31 * TODO: Potentially we could add code to automatically detect USB
32 * mass storage quirks for not supported SCSI commands!
33 */
34
35#include <sys/stdint.h>
36#include <sys/stddef.h>
37#include <sys/param.h>
38#include <sys/queue.h>
39#include <sys/types.h>
40#include <sys/systm.h>
41#include <sys/kernel.h>
42#include <sys/bus.h>
43#include <sys/module.h>
44#include <sys/lock.h>
45#include <sys/mutex.h>
46#include <sys/condvar.h>
47#include <sys/sysctl.h>
48#include <sys/sx.h>
49#include <sys/unistd.h>
50#include <sys/callout.h>
51#include <sys/malloc.h>
52#include <sys/priv.h>
53
54#include <dev/usb/usb.h>
55#include <dev/usb/usbdi.h>
56#include <dev/usb/usbdi_util.h>
57
58#define USB_DEBUG_VAR usb_debug
59
60#include <dev/usb/usb_busdma.h>
61#include <dev/usb/usb_process.h>
62#include <dev/usb/usb_transfer.h>
63#include <dev/usb/usb_msctest.h>
64#include <dev/usb/usb_debug.h>
65#include <dev/usb/usb_device.h>
66#include <dev/usb/usb_request.h>
67#include <dev/usb/usb_util.h>
68#include <dev/usb/quirk/usb_quirk.h>
69
70enum {
71 ST_COMMAND,
72 ST_DATA_RD,
73 ST_DATA_RD_CS,
74 ST_DATA_WR,
75 ST_DATA_WR_CS,
76 ST_STATUS,
77 ST_MAX,
78};
79
80enum {
81 DIR_IN,
82 DIR_OUT,
83 DIR_NONE,
84};
85
86#define SCSI_MAX_LEN 0x100
87#define SCSI_INQ_LEN 0x24
88#define SCSI_SENSE_LEN 0xFF
89
90static uint8_t scsi_test_unit_ready[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
91static uint8_t scsi_inquiry[] = { 0x12, 0x00, 0x00, 0x00, SCSI_INQ_LEN, 0x00 };
92static uint8_t scsi_rezero_init[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
93static uint8_t scsi_start_stop_unit[] = { 0x1b, 0x00, 0x00, 0x00, 0x02, 0x00 };
94static uint8_t scsi_ztestor_eject[] = { 0x85, 0x01, 0x01, 0x01, 0x18, 0x01,
95 0x01, 0x01, 0x01, 0x01, 0x00, 0x00 };
96static uint8_t scsi_cmotech_eject[] = { 0xff, 0x52, 0x44, 0x45, 0x56, 0x43,
97 0x48, 0x47 };
98static uint8_t scsi_huawei_eject[] = { 0x11, 0x06, 0x00, 0x00, 0x00, 0x00,
99 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100 0x00, 0x00, 0x00, 0x00 };
101static uint8_t scsi_tct_eject[] = { 0x06, 0xf5, 0x04, 0x02, 0x52, 0x70 };
102static uint8_t scsi_sync_cache[] = { 0x35, 0x00, 0x00, 0x00, 0x00, 0x00,
103 0x00, 0x00, 0x00, 0x00 };
104static uint8_t scsi_request_sense[] = { 0x03, 0x00, 0x00, 0x00, 0x12, 0x00,
105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
106static uint8_t scsi_read_capacity[] = { 0x25, 0x00, 0x00, 0x00, 0x00, 0x00,
107 0x00, 0x00, 0x00, 0x00 };
108
109#define BULK_SIZE 64 /* dummy */
110#define ERR_CSW_FAILED -1
111
112/* Command Block Wrapper */
113struct bbb_cbw {
114 uDWord dCBWSignature;
115#define CBWSIGNATURE 0x43425355
116 uDWord dCBWTag;
117 uDWord dCBWDataTransferLength;
118 uByte bCBWFlags;
119#define CBWFLAGS_OUT 0x00
120#define CBWFLAGS_IN 0x80
121 uByte bCBWLUN;
122 uByte bCDBLength;
123#define CBWCDBLENGTH 16
124 uByte CBWCDB[CBWCDBLENGTH];
125} __packed;
126
127/* Command Status Wrapper */
128struct bbb_csw {
129 uDWord dCSWSignature;
130#define CSWSIGNATURE 0x53425355
131 uDWord dCSWTag;
132 uDWord dCSWDataResidue;
133 uByte bCSWStatus;
134#define CSWSTATUS_GOOD 0x0
135#define CSWSTATUS_FAILED 0x1
136#define CSWSTATUS_PHASE 0x2
137} __packed;
138
139struct bbb_transfer {
140 struct mtx mtx;
141 struct cv cv;
142 struct bbb_cbw cbw;
143 struct bbb_csw csw;
142 struct bbb_cbw *cbw;
143 struct bbb_csw *csw;
144
145 struct usb_xfer *xfer[ST_MAX];
146
147 uint8_t *data_ptr;
148
149 usb_size_t data_len; /* bytes */
150 usb_size_t data_rem; /* bytes */
151 usb_timeout_t data_timeout; /* ms */
152 usb_frlength_t actlen; /* bytes */
153
154 uint8_t cmd_len; /* bytes */
155 uint8_t dir;
156 uint8_t lun;
157 uint8_t state;
158 uint8_t status_try;
159 int error;
160
144
145 struct usb_xfer *xfer[ST_MAX];
146
147 uint8_t *data_ptr;
148
149 usb_size_t data_len; /* bytes */
150 usb_size_t data_rem; /* bytes */
151 usb_timeout_t data_timeout; /* ms */
152 usb_frlength_t actlen; /* bytes */
153
154 uint8_t cmd_len; /* bytes */
155 uint8_t dir;
156 uint8_t lun;
157 uint8_t state;
158 uint8_t status_try;
159 int error;
160
161 uint8_t buffer[SCSI_MAX_LEN] __aligned(4);
161 uint8_t *buffer;
162};
163
164static usb_callback_t bbb_command_callback;
165static usb_callback_t bbb_data_read_callback;
166static usb_callback_t bbb_data_rd_cs_callback;
167static usb_callback_t bbb_data_write_callback;
168static usb_callback_t bbb_data_wr_cs_callback;
169static usb_callback_t bbb_status_callback;
170
171static void bbb_done(struct bbb_transfer *, int);
172static void bbb_transfer_start(struct bbb_transfer *, uint8_t);
173static void bbb_data_clear_stall_callback(struct usb_xfer *, uint8_t,
174 uint8_t);
175static int bbb_command_start(struct bbb_transfer *, uint8_t, uint8_t,
176 void *, size_t, void *, size_t, usb_timeout_t);
177static struct bbb_transfer *bbb_attach(struct usb_device *, uint8_t);
178static void bbb_detach(struct bbb_transfer *);
179
180static const struct usb_config bbb_config[ST_MAX] = {
181
182 [ST_COMMAND] = {
183 .type = UE_BULK,
184 .endpoint = UE_ADDR_ANY,
185 .direction = UE_DIR_OUT,
186 .bufsize = sizeof(struct bbb_cbw),
162};
163
164static usb_callback_t bbb_command_callback;
165static usb_callback_t bbb_data_read_callback;
166static usb_callback_t bbb_data_rd_cs_callback;
167static usb_callback_t bbb_data_write_callback;
168static usb_callback_t bbb_data_wr_cs_callback;
169static usb_callback_t bbb_status_callback;
170
171static void bbb_done(struct bbb_transfer *, int);
172static void bbb_transfer_start(struct bbb_transfer *, uint8_t);
173static void bbb_data_clear_stall_callback(struct usb_xfer *, uint8_t,
174 uint8_t);
175static int bbb_command_start(struct bbb_transfer *, uint8_t, uint8_t,
176 void *, size_t, void *, size_t, usb_timeout_t);
177static struct bbb_transfer *bbb_attach(struct usb_device *, uint8_t);
178static void bbb_detach(struct bbb_transfer *);
179
180static const struct usb_config bbb_config[ST_MAX] = {
181
182 [ST_COMMAND] = {
183 .type = UE_BULK,
184 .endpoint = UE_ADDR_ANY,
185 .direction = UE_DIR_OUT,
186 .bufsize = sizeof(struct bbb_cbw),
187 .flags = {.ext_buffer = 1,},
188 .callback = &bbb_command_callback,
189 .timeout = 4 * USB_MS_HZ, /* 4 seconds */
190 },
191
192 [ST_DATA_RD] = {
193 .type = UE_BULK,
194 .endpoint = UE_ADDR_ANY,
195 .direction = UE_DIR_IN,
187 .callback = &bbb_command_callback,
188 .timeout = 4 * USB_MS_HZ, /* 4 seconds */
189 },
190
191 [ST_DATA_RD] = {
192 .type = UE_BULK,
193 .endpoint = UE_ADDR_ANY,
194 .direction = UE_DIR_IN,
196 .bufsize = BULK_SIZE,
197 .flags = {.ext_buffer = 1,.proxy_buffer = 1,.short_xfer_ok = 1,},
195 .bufsize = MAX(SCSI_MAX_LEN, BULK_SIZE),
196 .flags = {.proxy_buffer = 1,.short_xfer_ok = 1,},
198 .callback = &bbb_data_read_callback,
199 .timeout = 4 * USB_MS_HZ, /* 4 seconds */
200 },
201
202 [ST_DATA_RD_CS] = {
203 .type = UE_CONTROL,
204 .endpoint = 0x00, /* Control pipe */
205 .direction = UE_DIR_ANY,
206 .bufsize = sizeof(struct usb_device_request),
207 .callback = &bbb_data_rd_cs_callback,
208 .timeout = 1 * USB_MS_HZ, /* 1 second */
209 },
210
211 [ST_DATA_WR] = {
212 .type = UE_BULK,
213 .endpoint = UE_ADDR_ANY,
214 .direction = UE_DIR_OUT,
215 .bufsize = BULK_SIZE,
216 .flags = {.ext_buffer = 1,.proxy_buffer = 1,},
217 .callback = &bbb_data_write_callback,
218 .timeout = 4 * USB_MS_HZ, /* 4 seconds */
219 },
220
221 [ST_DATA_WR_CS] = {
222 .type = UE_CONTROL,
223 .endpoint = 0x00, /* Control pipe */
224 .direction = UE_DIR_ANY,
225 .bufsize = sizeof(struct usb_device_request),
226 .callback = &bbb_data_wr_cs_callback,
227 .timeout = 1 * USB_MS_HZ, /* 1 second */
228 },
229
230 [ST_STATUS] = {
231 .type = UE_BULK,
232 .endpoint = UE_ADDR_ANY,
233 .direction = UE_DIR_IN,
234 .bufsize = sizeof(struct bbb_csw),
197 .callback = &bbb_data_read_callback,
198 .timeout = 4 * USB_MS_HZ, /* 4 seconds */
199 },
200
201 [ST_DATA_RD_CS] = {
202 .type = UE_CONTROL,
203 .endpoint = 0x00, /* Control pipe */
204 .direction = UE_DIR_ANY,
205 .bufsize = sizeof(struct usb_device_request),
206 .callback = &bbb_data_rd_cs_callback,
207 .timeout = 1 * USB_MS_HZ, /* 1 second */
208 },
209
210 [ST_DATA_WR] = {
211 .type = UE_BULK,
212 .endpoint = UE_ADDR_ANY,
213 .direction = UE_DIR_OUT,
214 .bufsize = BULK_SIZE,
215 .flags = {.ext_buffer = 1,.proxy_buffer = 1,},
216 .callback = &bbb_data_write_callback,
217 .timeout = 4 * USB_MS_HZ, /* 4 seconds */
218 },
219
220 [ST_DATA_WR_CS] = {
221 .type = UE_CONTROL,
222 .endpoint = 0x00, /* Control pipe */
223 .direction = UE_DIR_ANY,
224 .bufsize = sizeof(struct usb_device_request),
225 .callback = &bbb_data_wr_cs_callback,
226 .timeout = 1 * USB_MS_HZ, /* 1 second */
227 },
228
229 [ST_STATUS] = {
230 .type = UE_BULK,
231 .endpoint = UE_ADDR_ANY,
232 .direction = UE_DIR_IN,
233 .bufsize = sizeof(struct bbb_csw),
235 .flags = {.ext_buffer = 1,.short_xfer_ok = 1,},
234 .flags = {.short_xfer_ok = 1,},
236 .callback = &bbb_status_callback,
237 .timeout = 1 * USB_MS_HZ, /* 1 second */
238 },
239};
240
241static void
242bbb_done(struct bbb_transfer *sc, int error)
243{
235 .callback = &bbb_status_callback,
236 .timeout = 1 * USB_MS_HZ, /* 1 second */
237 },
238};
239
240static void
241bbb_done(struct bbb_transfer *sc, int error)
242{
244
245 sc->error = error;
246 sc->state = ST_COMMAND;
247 sc->status_try = 1;
248 cv_signal(&sc->cv);
249}
250
251static void
252bbb_transfer_start(struct bbb_transfer *sc, uint8_t xfer_index)
253{
254 sc->state = xfer_index;
255 usbd_transfer_start(sc->xfer[xfer_index]);
256}
257
258static void
259bbb_data_clear_stall_callback(struct usb_xfer *xfer,
260 uint8_t next_xfer, uint8_t stall_xfer)
261{
262 struct bbb_transfer *sc = usbd_xfer_softc(xfer);
263
264 if (usbd_clear_stall_callback(xfer, sc->xfer[stall_xfer])) {
265 switch (USB_GET_STATE(xfer)) {
266 case USB_ST_SETUP:
267 case USB_ST_TRANSFERRED:
268 bbb_transfer_start(sc, next_xfer);
269 break;
270 default:
271 bbb_done(sc, USB_ERR_STALLED);
272 break;
273 }
274 }
275}
276
277static void
278bbb_command_callback(struct usb_xfer *xfer, usb_error_t error)
279{
280 struct bbb_transfer *sc = usbd_xfer_softc(xfer);
281 uint32_t tag;
282
283 switch (USB_GET_STATE(xfer)) {
284 case USB_ST_TRANSFERRED:
285 bbb_transfer_start
286 (sc, ((sc->dir == DIR_IN) ? ST_DATA_RD :
287 (sc->dir == DIR_OUT) ? ST_DATA_WR :
288 ST_STATUS));
289 break;
290
291 case USB_ST_SETUP:
292 sc->status_try = 0;
243 sc->error = error;
244 sc->state = ST_COMMAND;
245 sc->status_try = 1;
246 cv_signal(&sc->cv);
247}
248
249static void
250bbb_transfer_start(struct bbb_transfer *sc, uint8_t xfer_index)
251{
252 sc->state = xfer_index;
253 usbd_transfer_start(sc->xfer[xfer_index]);
254}
255
256static void
257bbb_data_clear_stall_callback(struct usb_xfer *xfer,
258 uint8_t next_xfer, uint8_t stall_xfer)
259{
260 struct bbb_transfer *sc = usbd_xfer_softc(xfer);
261
262 if (usbd_clear_stall_callback(xfer, sc->xfer[stall_xfer])) {
263 switch (USB_GET_STATE(xfer)) {
264 case USB_ST_SETUP:
265 case USB_ST_TRANSFERRED:
266 bbb_transfer_start(sc, next_xfer);
267 break;
268 default:
269 bbb_done(sc, USB_ERR_STALLED);
270 break;
271 }
272 }
273}
274
275static void
276bbb_command_callback(struct usb_xfer *xfer, usb_error_t error)
277{
278 struct bbb_transfer *sc = usbd_xfer_softc(xfer);
279 uint32_t tag;
280
281 switch (USB_GET_STATE(xfer)) {
282 case USB_ST_TRANSFERRED:
283 bbb_transfer_start
284 (sc, ((sc->dir == DIR_IN) ? ST_DATA_RD :
285 (sc->dir == DIR_OUT) ? ST_DATA_WR :
286 ST_STATUS));
287 break;
288
289 case USB_ST_SETUP:
290 sc->status_try = 0;
293 tag = UGETDW(sc->cbw.dCBWTag) + 1;
294 USETDW(sc->cbw.dCBWSignature, CBWSIGNATURE);
295 USETDW(sc->cbw.dCBWTag, tag);
296 USETDW(sc->cbw.dCBWDataTransferLength, (uint32_t)sc->data_len);
297 sc->cbw.bCBWFlags = ((sc->dir == DIR_IN) ? CBWFLAGS_IN : CBWFLAGS_OUT);
298 sc->cbw.bCBWLUN = sc->lun;
299 sc->cbw.bCDBLength = sc->cmd_len;
300 if (sc->cbw.bCDBLength > sizeof(sc->cbw.CBWCDB)) {
301 sc->cbw.bCDBLength = sizeof(sc->cbw.CBWCDB);
291 tag = UGETDW(sc->cbw->dCBWTag) + 1;
292 USETDW(sc->cbw->dCBWSignature, CBWSIGNATURE);
293 USETDW(sc->cbw->dCBWTag, tag);
294 USETDW(sc->cbw->dCBWDataTransferLength, (uint32_t)sc->data_len);
295 sc->cbw->bCBWFlags = ((sc->dir == DIR_IN) ? CBWFLAGS_IN : CBWFLAGS_OUT);
296 sc->cbw->bCBWLUN = sc->lun;
297 sc->cbw->bCDBLength = sc->cmd_len;
298 if (sc->cbw->bCDBLength > sizeof(sc->cbw->CBWCDB)) {
299 sc->cbw->bCDBLength = sizeof(sc->cbw->CBWCDB);
302 DPRINTFN(0, "Truncating long command\n");
303 }
300 DPRINTFN(0, "Truncating long command\n");
301 }
304 usbd_xfer_set_frame_data(xfer, 0, &sc->cbw, sizeof(sc->cbw));
305 usbd_transfer_submit(xfer);
306 break;
307
308 default: /* Error */
309 bbb_done(sc, error);
310 break;
311 }
312}
313
314static void
315bbb_data_read_callback(struct usb_xfer *xfer, usb_error_t error)
316{
317 struct bbb_transfer *sc = usbd_xfer_softc(xfer);
318 usb_frlength_t max_bulk = usbd_xfer_max_len(xfer);
319 int actlen, sumlen;
320
321 usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
322
323 switch (USB_GET_STATE(xfer)) {
324 case USB_ST_TRANSFERRED:
325 sc->data_rem -= actlen;
326 sc->data_ptr += actlen;
327 sc->actlen += actlen;
328
329 if (actlen < sumlen) {
330 /* short transfer */
331 sc->data_rem = 0;
332 }
333 case USB_ST_SETUP:
334 DPRINTF("max_bulk=%d, data_rem=%d\n",
335 max_bulk, sc->data_rem);
336
337 if (sc->data_rem == 0) {
338 bbb_transfer_start(sc, ST_STATUS);
339 break;
340 }
341 if (max_bulk > sc->data_rem) {
342 max_bulk = sc->data_rem;
343 }
344 usbd_xfer_set_timeout(xfer, sc->data_timeout);
345 usbd_xfer_set_frame_data(xfer, 0, sc->data_ptr, max_bulk);
346 usbd_transfer_submit(xfer);
347 break;
348
349 default: /* Error */
350 if (error == USB_ERR_CANCELLED) {
351 bbb_done(sc, error);
352 } else {
353 bbb_transfer_start(sc, ST_DATA_RD_CS);
354 }
355 break;
356 }
357}
358
359static void
360bbb_data_rd_cs_callback(struct usb_xfer *xfer, usb_error_t error)
361{
362 bbb_data_clear_stall_callback(xfer, ST_STATUS,
363 ST_DATA_RD);
364}
365
366static void
367bbb_data_write_callback(struct usb_xfer *xfer, usb_error_t error)
368{
369 struct bbb_transfer *sc = usbd_xfer_softc(xfer);
370 usb_frlength_t max_bulk = usbd_xfer_max_len(xfer);
371 int actlen, sumlen;
372
373 usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
374
375 switch (USB_GET_STATE(xfer)) {
376 case USB_ST_TRANSFERRED:
377 sc->data_rem -= actlen;
378 sc->data_ptr += actlen;
379 sc->actlen += actlen;
380
381 if (actlen < sumlen) {
382 /* short transfer */
383 sc->data_rem = 0;
384 }
385 case USB_ST_SETUP:
386 DPRINTF("max_bulk=%d, data_rem=%d\n",
387 max_bulk, sc->data_rem);
388
389 if (sc->data_rem == 0) {
390 bbb_transfer_start(sc, ST_STATUS);
391 return;
392 }
393 if (max_bulk > sc->data_rem) {
394 max_bulk = sc->data_rem;
395 }
396 usbd_xfer_set_timeout(xfer, sc->data_timeout);
397 usbd_xfer_set_frame_data(xfer, 0, sc->data_ptr, max_bulk);
398 usbd_transfer_submit(xfer);
399 return;
400
401 default: /* Error */
402 if (error == USB_ERR_CANCELLED) {
403 bbb_done(sc, error);
404 } else {
405 bbb_transfer_start(sc, ST_DATA_WR_CS);
406 }
407 return;
408
409 }
410}
411
412static void
413bbb_data_wr_cs_callback(struct usb_xfer *xfer, usb_error_t error)
414{
415 bbb_data_clear_stall_callback(xfer, ST_STATUS,
416 ST_DATA_WR);
417}
418
419static void
420bbb_status_callback(struct usb_xfer *xfer, usb_error_t error)
421{
422 struct bbb_transfer *sc = usbd_xfer_softc(xfer);
423 int actlen;
424 int sumlen;
425
426 usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
427
428 switch (USB_GET_STATE(xfer)) {
429 case USB_ST_TRANSFERRED:
430
431 /* very simple status check */
432
302 usbd_transfer_submit(xfer);
303 break;
304
305 default: /* Error */
306 bbb_done(sc, error);
307 break;
308 }
309}
310
311static void
312bbb_data_read_callback(struct usb_xfer *xfer, usb_error_t error)
313{
314 struct bbb_transfer *sc = usbd_xfer_softc(xfer);
315 usb_frlength_t max_bulk = usbd_xfer_max_len(xfer);
316 int actlen, sumlen;
317
318 usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
319
320 switch (USB_GET_STATE(xfer)) {
321 case USB_ST_TRANSFERRED:
322 sc->data_rem -= actlen;
323 sc->data_ptr += actlen;
324 sc->actlen += actlen;
325
326 if (actlen < sumlen) {
327 /* short transfer */
328 sc->data_rem = 0;
329 }
330 case USB_ST_SETUP:
331 DPRINTF("max_bulk=%d, data_rem=%d\n",
332 max_bulk, sc->data_rem);
333
334 if (sc->data_rem == 0) {
335 bbb_transfer_start(sc, ST_STATUS);
336 break;
337 }
338 if (max_bulk > sc->data_rem) {
339 max_bulk = sc->data_rem;
340 }
341 usbd_xfer_set_timeout(xfer, sc->data_timeout);
342 usbd_xfer_set_frame_data(xfer, 0, sc->data_ptr, max_bulk);
343 usbd_transfer_submit(xfer);
344 break;
345
346 default: /* Error */
347 if (error == USB_ERR_CANCELLED) {
348 bbb_done(sc, error);
349 } else {
350 bbb_transfer_start(sc, ST_DATA_RD_CS);
351 }
352 break;
353 }
354}
355
356static void
357bbb_data_rd_cs_callback(struct usb_xfer *xfer, usb_error_t error)
358{
359 bbb_data_clear_stall_callback(xfer, ST_STATUS,
360 ST_DATA_RD);
361}
362
363static void
364bbb_data_write_callback(struct usb_xfer *xfer, usb_error_t error)
365{
366 struct bbb_transfer *sc = usbd_xfer_softc(xfer);
367 usb_frlength_t max_bulk = usbd_xfer_max_len(xfer);
368 int actlen, sumlen;
369
370 usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
371
372 switch (USB_GET_STATE(xfer)) {
373 case USB_ST_TRANSFERRED:
374 sc->data_rem -= actlen;
375 sc->data_ptr += actlen;
376 sc->actlen += actlen;
377
378 if (actlen < sumlen) {
379 /* short transfer */
380 sc->data_rem = 0;
381 }
382 case USB_ST_SETUP:
383 DPRINTF("max_bulk=%d, data_rem=%d\n",
384 max_bulk, sc->data_rem);
385
386 if (sc->data_rem == 0) {
387 bbb_transfer_start(sc, ST_STATUS);
388 return;
389 }
390 if (max_bulk > sc->data_rem) {
391 max_bulk = sc->data_rem;
392 }
393 usbd_xfer_set_timeout(xfer, sc->data_timeout);
394 usbd_xfer_set_frame_data(xfer, 0, sc->data_ptr, max_bulk);
395 usbd_transfer_submit(xfer);
396 return;
397
398 default: /* Error */
399 if (error == USB_ERR_CANCELLED) {
400 bbb_done(sc, error);
401 } else {
402 bbb_transfer_start(sc, ST_DATA_WR_CS);
403 }
404 return;
405
406 }
407}
408
409static void
410bbb_data_wr_cs_callback(struct usb_xfer *xfer, usb_error_t error)
411{
412 bbb_data_clear_stall_callback(xfer, ST_STATUS,
413 ST_DATA_WR);
414}
415
416static void
417bbb_status_callback(struct usb_xfer *xfer, usb_error_t error)
418{
419 struct bbb_transfer *sc = usbd_xfer_softc(xfer);
420 int actlen;
421 int sumlen;
422
423 usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
424
425 switch (USB_GET_STATE(xfer)) {
426 case USB_ST_TRANSFERRED:
427
428 /* very simple status check */
429
433 if (actlen < (int)sizeof(sc->csw)) {
430 if (actlen < (int)sizeof(struct bbb_csw)) {
434 bbb_done(sc, USB_ERR_SHORT_XFER);
431 bbb_done(sc, USB_ERR_SHORT_XFER);
435 } else if (sc->csw.bCSWStatus == CSWSTATUS_GOOD) {
432 } else if (sc->csw->bCSWStatus == CSWSTATUS_GOOD) {
436 bbb_done(sc, 0); /* success */
437 } else {
438 bbb_done(sc, ERR_CSW_FAILED); /* error */
439 }
440 break;
441
442 case USB_ST_SETUP:
433 bbb_done(sc, 0); /* success */
434 } else {
435 bbb_done(sc, ERR_CSW_FAILED); /* error */
436 }
437 break;
438
439 case USB_ST_SETUP:
443 usbd_xfer_set_frame_data(xfer, 0, &sc->csw, sizeof(sc->csw));
444 usbd_transfer_submit(xfer);
445 break;
446
447 default:
448 DPRINTF("Failed to read CSW: %s, try %d\n",
449 usbd_errstr(error), sc->status_try);
450
451 if (error == USB_ERR_CANCELLED || sc->status_try) {
452 bbb_done(sc, error);
453 } else {
454 sc->status_try = 1;
455 bbb_transfer_start(sc, ST_DATA_RD_CS);
456 }
457 break;
458 }
459}
460
461/*------------------------------------------------------------------------*
462 * bbb_command_start - execute a SCSI command synchronously
463 *
464 * Return values
465 * 0: Success
466 * Else: Failure
467 *------------------------------------------------------------------------*/
468static int
469bbb_command_start(struct bbb_transfer *sc, uint8_t dir, uint8_t lun,
470 void *data_ptr, size_t data_len, void *cmd_ptr, size_t cmd_len,
471 usb_timeout_t data_timeout)
472{
473 sc->lun = lun;
474 sc->dir = data_len ? dir : DIR_NONE;
475 sc->data_ptr = data_ptr;
476 sc->data_len = data_len;
477 sc->data_rem = data_len;
478 sc->data_timeout = (data_timeout + USB_MS_HZ);
479 sc->actlen = 0;
480 sc->cmd_len = cmd_len;
440 usbd_transfer_submit(xfer);
441 break;
442
443 default:
444 DPRINTF("Failed to read CSW: %s, try %d\n",
445 usbd_errstr(error), sc->status_try);
446
447 if (error == USB_ERR_CANCELLED || sc->status_try) {
448 bbb_done(sc, error);
449 } else {
450 sc->status_try = 1;
451 bbb_transfer_start(sc, ST_DATA_RD_CS);
452 }
453 break;
454 }
455}
456
457/*------------------------------------------------------------------------*
458 * bbb_command_start - execute a SCSI command synchronously
459 *
460 * Return values
461 * 0: Success
462 * Else: Failure
463 *------------------------------------------------------------------------*/
464static int
465bbb_command_start(struct bbb_transfer *sc, uint8_t dir, uint8_t lun,
466 void *data_ptr, size_t data_len, void *cmd_ptr, size_t cmd_len,
467 usb_timeout_t data_timeout)
468{
469 sc->lun = lun;
470 sc->dir = data_len ? dir : DIR_NONE;
471 sc->data_ptr = data_ptr;
472 sc->data_len = data_len;
473 sc->data_rem = data_len;
474 sc->data_timeout = (data_timeout + USB_MS_HZ);
475 sc->actlen = 0;
476 sc->cmd_len = cmd_len;
481 memset(&sc->cbw.CBWCDB, 0, sizeof(sc->cbw.CBWCDB));
482 memcpy(&sc->cbw.CBWCDB, cmd_ptr, cmd_len);
483 DPRINTFN(1, "SCSI cmd = %*D\n", (int)cmd_len, (char *)sc->cbw.CBWCDB, ":");
477 memset(&sc->cbw->CBWCDB, 0, sizeof(sc->cbw->CBWCDB));
478 memcpy(&sc->cbw->CBWCDB, cmd_ptr, cmd_len);
479 DPRINTFN(1, "SCSI cmd = %*D\n", (int)cmd_len, (char *)sc->cbw->CBWCDB, ":");
484
485 mtx_lock(&sc->mtx);
486 usbd_transfer_start(sc->xfer[sc->state]);
487
488 while (usbd_transfer_pending(sc->xfer[sc->state])) {
489 cv_wait(&sc->cv, &sc->mtx);
490 }
491 mtx_unlock(&sc->mtx);
492 return (sc->error);
493}
494
495static struct bbb_transfer *
496bbb_attach(struct usb_device *udev, uint8_t iface_index)
497{
498 struct usb_interface *iface;
499 struct usb_interface_descriptor *id;
500 struct bbb_transfer *sc;
501 usb_error_t err;
502 uint8_t do_unlock;
503
504 /* automatic locking */
505 if (usbd_enum_is_locked(udev)) {
506 do_unlock = 0;
507 } else {
508 do_unlock = 1;
509 usbd_enum_lock(udev);
510 }
511
512 /*
513 * Make sure any driver which is hooked up to this interface,
514 * like umass is gone:
515 */
516 usb_detach_device(udev, iface_index, 0);
517
518 if (do_unlock)
519 usbd_enum_unlock(udev);
520
521 iface = usbd_get_iface(udev, iface_index);
522 if (iface == NULL)
523 return (NULL);
524
525 id = iface->idesc;
526 if (id == NULL || id->bInterfaceClass != UICLASS_MASS)
527 return (NULL);
528
529 switch (id->bInterfaceSubClass) {
530 case UISUBCLASS_SCSI:
531 case UISUBCLASS_UFI:
532 case UISUBCLASS_SFF8020I:
533 case UISUBCLASS_SFF8070I:
534 break;
535 default:
536 return (NULL);
537 }
538
539 switch (id->bInterfaceProtocol) {
540 case UIPROTO_MASS_BBB_OLD:
541 case UIPROTO_MASS_BBB:
542 break;
543 default:
544 return (NULL);
545 }
546
547 sc = malloc(sizeof(*sc), M_USB, M_WAITOK | M_ZERO);
548 mtx_init(&sc->mtx, "USB autoinstall", NULL, MTX_DEF);
549 cv_init(&sc->cv, "WBBB");
550
551 err = usbd_transfer_setup(udev, &iface_index, sc->xfer, bbb_config,
552 ST_MAX, sc, &sc->mtx);
553 if (err) {
554 bbb_detach(sc);
555 return (NULL);
556 }
480
481 mtx_lock(&sc->mtx);
482 usbd_transfer_start(sc->xfer[sc->state]);
483
484 while (usbd_transfer_pending(sc->xfer[sc->state])) {
485 cv_wait(&sc->cv, &sc->mtx);
486 }
487 mtx_unlock(&sc->mtx);
488 return (sc->error);
489}
490
491static struct bbb_transfer *
492bbb_attach(struct usb_device *udev, uint8_t iface_index)
493{
494 struct usb_interface *iface;
495 struct usb_interface_descriptor *id;
496 struct bbb_transfer *sc;
497 usb_error_t err;
498 uint8_t do_unlock;
499
500 /* automatic locking */
501 if (usbd_enum_is_locked(udev)) {
502 do_unlock = 0;
503 } else {
504 do_unlock = 1;
505 usbd_enum_lock(udev);
506 }
507
508 /*
509 * Make sure any driver which is hooked up to this interface,
510 * like umass is gone:
511 */
512 usb_detach_device(udev, iface_index, 0);
513
514 if (do_unlock)
515 usbd_enum_unlock(udev);
516
517 iface = usbd_get_iface(udev, iface_index);
518 if (iface == NULL)
519 return (NULL);
520
521 id = iface->idesc;
522 if (id == NULL || id->bInterfaceClass != UICLASS_MASS)
523 return (NULL);
524
525 switch (id->bInterfaceSubClass) {
526 case UISUBCLASS_SCSI:
527 case UISUBCLASS_UFI:
528 case UISUBCLASS_SFF8020I:
529 case UISUBCLASS_SFF8070I:
530 break;
531 default:
532 return (NULL);
533 }
534
535 switch (id->bInterfaceProtocol) {
536 case UIPROTO_MASS_BBB_OLD:
537 case UIPROTO_MASS_BBB:
538 break;
539 default:
540 return (NULL);
541 }
542
543 sc = malloc(sizeof(*sc), M_USB, M_WAITOK | M_ZERO);
544 mtx_init(&sc->mtx, "USB autoinstall", NULL, MTX_DEF);
545 cv_init(&sc->cv, "WBBB");
546
547 err = usbd_transfer_setup(udev, &iface_index, sc->xfer, bbb_config,
548 ST_MAX, sc, &sc->mtx);
549 if (err) {
550 bbb_detach(sc);
551 return (NULL);
552 }
553 /* store pointer to DMA buffers */
554 sc->buffer = usbd_xfer_get_frame_buffer(
555 sc->xfer[ST_DATA_RD], 0);
556 sc->cbw = usbd_xfer_get_frame_buffer(
557 sc->xfer[ST_COMMAND], 0);
558 sc->csw = usbd_xfer_get_frame_buffer(
559 sc->xfer[ST_STATUS], 0);
560
557 return (sc);
558}
559
560static void
561bbb_detach(struct bbb_transfer *sc)
562{
563 usbd_transfer_unsetup(sc->xfer, ST_MAX);
564 mtx_destroy(&sc->mtx);
565 cv_destroy(&sc->cv);
566 free(sc, M_USB);
567}
568
569/*------------------------------------------------------------------------*
570 * usb_iface_is_cdrom
571 *
572 * Return values:
573 * 1: This interface is an auto install disk (CD-ROM)
574 * 0: Not an auto install disk.
575 *------------------------------------------------------------------------*/
576int
577usb_iface_is_cdrom(struct usb_device *udev, uint8_t iface_index)
578{
579 struct bbb_transfer *sc;
580 uint8_t timeout;
581 uint8_t is_cdrom;
582 uint8_t sid_type;
583 int err;
584
585 sc = bbb_attach(udev, iface_index);
586 if (sc == NULL)
587 return (0);
588
589 is_cdrom = 0;
590 timeout = 4; /* tries */
591 while (--timeout) {
592 err = bbb_command_start(sc, DIR_IN, 0, sc->buffer,
593 SCSI_INQ_LEN, &scsi_inquiry, sizeof(scsi_inquiry),
594 USB_MS_HZ);
595
596 if (err == 0 && sc->actlen > 0) {
597 sid_type = sc->buffer[0] & 0x1F;
598 if (sid_type == 0x05)
599 is_cdrom = 1;
600 break;
601 } else if (err != ERR_CSW_FAILED)
602 break; /* non retryable error */
603 usb_pause_mtx(NULL, hz);
604 }
605 bbb_detach(sc);
606 return (is_cdrom);
607}
608
609static uint8_t
610usb_msc_get_max_lun(struct usb_device *udev, uint8_t iface_index)
611{
612 struct usb_device_request req;
613 usb_error_t err;
614 uint8_t buf = 0;
615
616
617 /* The Get Max Lun command is a class-specific request. */
618 req.bmRequestType = UT_READ_CLASS_INTERFACE;
619 req.bRequest = 0xFE; /* GET_MAX_LUN */
620 USETW(req.wValue, 0);
621 req.wIndex[0] = iface_index;
622 req.wIndex[1] = 0;
623 USETW(req.wLength, 1);
624
625 err = usbd_do_request(udev, NULL, &req, &buf);
626 if (err)
627 buf = 0;
628
629 return (buf);
630}
631
632usb_error_t
633usb_msc_auto_quirk(struct usb_device *udev, uint8_t iface_index)
634{
635 struct bbb_transfer *sc;
636 uint8_t timeout;
637 uint8_t is_no_direct;
638 uint8_t sid_type;
639 int err;
640
641 sc = bbb_attach(udev, iface_index);
642 if (sc == NULL)
643 return (0);
644
645 /*
646 * Some devices need a delay after that the configuration
647 * value is set to function properly:
648 */
649 usb_pause_mtx(NULL, hz);
650
651 if (usb_msc_get_max_lun(udev, iface_index) == 0) {
652 DPRINTF("Device has only got one LUN.\n");
653 usbd_add_dynamic_quirk(udev, UQ_MSC_NO_GETMAXLUN);
654 }
655
656 is_no_direct = 1;
657 for (timeout = 4; timeout != 0; timeout--) {
658 err = bbb_command_start(sc, DIR_IN, 0, sc->buffer,
659 SCSI_INQ_LEN, &scsi_inquiry, sizeof(scsi_inquiry),
660 USB_MS_HZ);
661
662 if (err == 0 && sc->actlen > 0) {
663 sid_type = sc->buffer[0] & 0x1F;
664 if (sid_type == 0x00)
665 is_no_direct = 0;
666 break;
667 } else if (err != ERR_CSW_FAILED) {
668 DPRINTF("Device is not responding "
669 "properly to SCSI INQUIRY command.\n");
670 goto error; /* non retryable error */
671 }
672 usb_pause_mtx(NULL, hz);
673 }
674
675 if (is_no_direct) {
676 DPRINTF("Device is not direct access.\n");
677 goto done;
678 }
679
680 err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
681 &scsi_test_unit_ready, sizeof(scsi_test_unit_ready),
682 USB_MS_HZ);
683
684 if (err != 0) {
685
686 if (err != ERR_CSW_FAILED)
687 goto error;
688 }
689 timeout = 1;
690
691retry_sync_cache:
692 err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
693 &scsi_sync_cache, sizeof(scsi_sync_cache),
694 USB_MS_HZ);
695
696 if (err != 0) {
697
698 if (err != ERR_CSW_FAILED)
699 goto error;
700
701 DPRINTF("Device doesn't handle synchronize cache\n");
702
703 usbd_add_dynamic_quirk(udev, UQ_MSC_NO_SYNC_CACHE);
704
705 } else {
706
707 /*
708 * Certain Kingston memory sticks fail the first
709 * read capacity after a synchronize cache command
710 * has been issued. Disable the synchronize cache
711 * command for such devices.
712 */
713
714 err = bbb_command_start(sc, DIR_IN, 0, sc->buffer, 8,
715 &scsi_read_capacity, sizeof(scsi_read_capacity),
716 USB_MS_HZ);
717
718 if (err != 0) {
719 if (err != ERR_CSW_FAILED)
720 goto error;
721
722 err = bbb_command_start(sc, DIR_IN, 0, sc->buffer, 8,
723 &scsi_read_capacity, sizeof(scsi_read_capacity),
724 USB_MS_HZ);
725
726 if (err == 0) {
727 if (timeout--)
728 goto retry_sync_cache;
729
730 DPRINTF("Device most likely doesn't "
731 "handle synchronize cache\n");
732
733 usbd_add_dynamic_quirk(udev,
734 UQ_MSC_NO_SYNC_CACHE);
735 } else {
736 if (err != ERR_CSW_FAILED)
737 goto error;
738 }
739 }
740 }
741
742 /* clear sense status of any failed commands on the device */
743
744 err = bbb_command_start(sc, DIR_IN, 0, sc->buffer,
745 SCSI_INQ_LEN, &scsi_inquiry, sizeof(scsi_inquiry),
746 USB_MS_HZ);
747
748 DPRINTF("Inquiry = %d\n", err);
749
750 if (err != 0) {
751
752 if (err != ERR_CSW_FAILED)
753 goto error;
754 }
755
756 err = bbb_command_start(sc, DIR_IN, 0, sc->buffer,
757 SCSI_SENSE_LEN, &scsi_request_sense,
758 sizeof(scsi_request_sense), USB_MS_HZ);
759
760 DPRINTF("Request sense = %d\n", err);
761
762 if (err != 0) {
763
764 if (err != ERR_CSW_FAILED)
765 goto error;
766 }
767
768done:
769 bbb_detach(sc);
770 return (0);
771
772error:
773 bbb_detach(sc);
774
775 DPRINTF("Device did not respond, enabling all quirks\n");
776
777 usbd_add_dynamic_quirk(udev, UQ_MSC_NO_SYNC_CACHE);
778 usbd_add_dynamic_quirk(udev, UQ_MSC_NO_TEST_UNIT_READY);
779
780 /* Need to re-enumerate the device */
781 usbd_req_re_enumerate(udev, NULL);
782
783 return (USB_ERR_STALLED);
784}
785
786usb_error_t
787usb_msc_eject(struct usb_device *udev, uint8_t iface_index, int method)
788{
789 struct bbb_transfer *sc;
790 usb_error_t err;
791
792 sc = bbb_attach(udev, iface_index);
793 if (sc == NULL)
794 return (USB_ERR_INVAL);
795
796 err = 0;
797 switch (method) {
798 case MSC_EJECT_STOPUNIT:
799 err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
800 &scsi_test_unit_ready, sizeof(scsi_test_unit_ready),
801 USB_MS_HZ);
802 DPRINTF("Test unit ready status: %s\n", usbd_errstr(err));
803 err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
804 &scsi_start_stop_unit, sizeof(scsi_start_stop_unit),
805 USB_MS_HZ);
806 break;
807 case MSC_EJECT_REZERO:
808 err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
809 &scsi_rezero_init, sizeof(scsi_rezero_init),
810 USB_MS_HZ);
811 break;
812 case MSC_EJECT_ZTESTOR:
813 err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
814 &scsi_ztestor_eject, sizeof(scsi_ztestor_eject),
815 USB_MS_HZ);
816 break;
817 case MSC_EJECT_CMOTECH:
818 err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
819 &scsi_cmotech_eject, sizeof(scsi_cmotech_eject),
820 USB_MS_HZ);
821 break;
822 case MSC_EJECT_HUAWEI:
823 err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
824 &scsi_huawei_eject, sizeof(scsi_huawei_eject),
825 USB_MS_HZ);
826 break;
827 case MSC_EJECT_TCT:
828 /*
829 * TCTMobile needs DIR_IN flag. To get it, we
830 * supply a dummy data with the command.
831 */
832 err = bbb_command_start(sc, DIR_IN, 0, &sc->buffer,
833 sizeof(sc->buffer), &scsi_tct_eject,
834 sizeof(scsi_tct_eject), USB_MS_HZ);
835 break;
836 default:
837 printf("usb_msc_eject: unknown eject method (%d)\n", method);
838 break;
839 }
840 DPRINTF("Eject CD command status: %s\n", usbd_errstr(err));
841
842 bbb_detach(sc);
843 return (0);
844}
561 return (sc);
562}
563
564static void
565bbb_detach(struct bbb_transfer *sc)
566{
567 usbd_transfer_unsetup(sc->xfer, ST_MAX);
568 mtx_destroy(&sc->mtx);
569 cv_destroy(&sc->cv);
570 free(sc, M_USB);
571}
572
573/*------------------------------------------------------------------------*
574 * usb_iface_is_cdrom
575 *
576 * Return values:
577 * 1: This interface is an auto install disk (CD-ROM)
578 * 0: Not an auto install disk.
579 *------------------------------------------------------------------------*/
580int
581usb_iface_is_cdrom(struct usb_device *udev, uint8_t iface_index)
582{
583 struct bbb_transfer *sc;
584 uint8_t timeout;
585 uint8_t is_cdrom;
586 uint8_t sid_type;
587 int err;
588
589 sc = bbb_attach(udev, iface_index);
590 if (sc == NULL)
591 return (0);
592
593 is_cdrom = 0;
594 timeout = 4; /* tries */
595 while (--timeout) {
596 err = bbb_command_start(sc, DIR_IN, 0, sc->buffer,
597 SCSI_INQ_LEN, &scsi_inquiry, sizeof(scsi_inquiry),
598 USB_MS_HZ);
599
600 if (err == 0 && sc->actlen > 0) {
601 sid_type = sc->buffer[0] & 0x1F;
602 if (sid_type == 0x05)
603 is_cdrom = 1;
604 break;
605 } else if (err != ERR_CSW_FAILED)
606 break; /* non retryable error */
607 usb_pause_mtx(NULL, hz);
608 }
609 bbb_detach(sc);
610 return (is_cdrom);
611}
612
613static uint8_t
614usb_msc_get_max_lun(struct usb_device *udev, uint8_t iface_index)
615{
616 struct usb_device_request req;
617 usb_error_t err;
618 uint8_t buf = 0;
619
620
621 /* The Get Max Lun command is a class-specific request. */
622 req.bmRequestType = UT_READ_CLASS_INTERFACE;
623 req.bRequest = 0xFE; /* GET_MAX_LUN */
624 USETW(req.wValue, 0);
625 req.wIndex[0] = iface_index;
626 req.wIndex[1] = 0;
627 USETW(req.wLength, 1);
628
629 err = usbd_do_request(udev, NULL, &req, &buf);
630 if (err)
631 buf = 0;
632
633 return (buf);
634}
635
636usb_error_t
637usb_msc_auto_quirk(struct usb_device *udev, uint8_t iface_index)
638{
639 struct bbb_transfer *sc;
640 uint8_t timeout;
641 uint8_t is_no_direct;
642 uint8_t sid_type;
643 int err;
644
645 sc = bbb_attach(udev, iface_index);
646 if (sc == NULL)
647 return (0);
648
649 /*
650 * Some devices need a delay after that the configuration
651 * value is set to function properly:
652 */
653 usb_pause_mtx(NULL, hz);
654
655 if (usb_msc_get_max_lun(udev, iface_index) == 0) {
656 DPRINTF("Device has only got one LUN.\n");
657 usbd_add_dynamic_quirk(udev, UQ_MSC_NO_GETMAXLUN);
658 }
659
660 is_no_direct = 1;
661 for (timeout = 4; timeout != 0; timeout--) {
662 err = bbb_command_start(sc, DIR_IN, 0, sc->buffer,
663 SCSI_INQ_LEN, &scsi_inquiry, sizeof(scsi_inquiry),
664 USB_MS_HZ);
665
666 if (err == 0 && sc->actlen > 0) {
667 sid_type = sc->buffer[0] & 0x1F;
668 if (sid_type == 0x00)
669 is_no_direct = 0;
670 break;
671 } else if (err != ERR_CSW_FAILED) {
672 DPRINTF("Device is not responding "
673 "properly to SCSI INQUIRY command.\n");
674 goto error; /* non retryable error */
675 }
676 usb_pause_mtx(NULL, hz);
677 }
678
679 if (is_no_direct) {
680 DPRINTF("Device is not direct access.\n");
681 goto done;
682 }
683
684 err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
685 &scsi_test_unit_ready, sizeof(scsi_test_unit_ready),
686 USB_MS_HZ);
687
688 if (err != 0) {
689
690 if (err != ERR_CSW_FAILED)
691 goto error;
692 }
693 timeout = 1;
694
695retry_sync_cache:
696 err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
697 &scsi_sync_cache, sizeof(scsi_sync_cache),
698 USB_MS_HZ);
699
700 if (err != 0) {
701
702 if (err != ERR_CSW_FAILED)
703 goto error;
704
705 DPRINTF("Device doesn't handle synchronize cache\n");
706
707 usbd_add_dynamic_quirk(udev, UQ_MSC_NO_SYNC_CACHE);
708
709 } else {
710
711 /*
712 * Certain Kingston memory sticks fail the first
713 * read capacity after a synchronize cache command
714 * has been issued. Disable the synchronize cache
715 * command for such devices.
716 */
717
718 err = bbb_command_start(sc, DIR_IN, 0, sc->buffer, 8,
719 &scsi_read_capacity, sizeof(scsi_read_capacity),
720 USB_MS_HZ);
721
722 if (err != 0) {
723 if (err != ERR_CSW_FAILED)
724 goto error;
725
726 err = bbb_command_start(sc, DIR_IN, 0, sc->buffer, 8,
727 &scsi_read_capacity, sizeof(scsi_read_capacity),
728 USB_MS_HZ);
729
730 if (err == 0) {
731 if (timeout--)
732 goto retry_sync_cache;
733
734 DPRINTF("Device most likely doesn't "
735 "handle synchronize cache\n");
736
737 usbd_add_dynamic_quirk(udev,
738 UQ_MSC_NO_SYNC_CACHE);
739 } else {
740 if (err != ERR_CSW_FAILED)
741 goto error;
742 }
743 }
744 }
745
746 /* clear sense status of any failed commands on the device */
747
748 err = bbb_command_start(sc, DIR_IN, 0, sc->buffer,
749 SCSI_INQ_LEN, &scsi_inquiry, sizeof(scsi_inquiry),
750 USB_MS_HZ);
751
752 DPRINTF("Inquiry = %d\n", err);
753
754 if (err != 0) {
755
756 if (err != ERR_CSW_FAILED)
757 goto error;
758 }
759
760 err = bbb_command_start(sc, DIR_IN, 0, sc->buffer,
761 SCSI_SENSE_LEN, &scsi_request_sense,
762 sizeof(scsi_request_sense), USB_MS_HZ);
763
764 DPRINTF("Request sense = %d\n", err);
765
766 if (err != 0) {
767
768 if (err != ERR_CSW_FAILED)
769 goto error;
770 }
771
772done:
773 bbb_detach(sc);
774 return (0);
775
776error:
777 bbb_detach(sc);
778
779 DPRINTF("Device did not respond, enabling all quirks\n");
780
781 usbd_add_dynamic_quirk(udev, UQ_MSC_NO_SYNC_CACHE);
782 usbd_add_dynamic_quirk(udev, UQ_MSC_NO_TEST_UNIT_READY);
783
784 /* Need to re-enumerate the device */
785 usbd_req_re_enumerate(udev, NULL);
786
787 return (USB_ERR_STALLED);
788}
789
790usb_error_t
791usb_msc_eject(struct usb_device *udev, uint8_t iface_index, int method)
792{
793 struct bbb_transfer *sc;
794 usb_error_t err;
795
796 sc = bbb_attach(udev, iface_index);
797 if (sc == NULL)
798 return (USB_ERR_INVAL);
799
800 err = 0;
801 switch (method) {
802 case MSC_EJECT_STOPUNIT:
803 err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
804 &scsi_test_unit_ready, sizeof(scsi_test_unit_ready),
805 USB_MS_HZ);
806 DPRINTF("Test unit ready status: %s\n", usbd_errstr(err));
807 err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
808 &scsi_start_stop_unit, sizeof(scsi_start_stop_unit),
809 USB_MS_HZ);
810 break;
811 case MSC_EJECT_REZERO:
812 err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
813 &scsi_rezero_init, sizeof(scsi_rezero_init),
814 USB_MS_HZ);
815 break;
816 case MSC_EJECT_ZTESTOR:
817 err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
818 &scsi_ztestor_eject, sizeof(scsi_ztestor_eject),
819 USB_MS_HZ);
820 break;
821 case MSC_EJECT_CMOTECH:
822 err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
823 &scsi_cmotech_eject, sizeof(scsi_cmotech_eject),
824 USB_MS_HZ);
825 break;
826 case MSC_EJECT_HUAWEI:
827 err = bbb_command_start(sc, DIR_IN, 0, NULL, 0,
828 &scsi_huawei_eject, sizeof(scsi_huawei_eject),
829 USB_MS_HZ);
830 break;
831 case MSC_EJECT_TCT:
832 /*
833 * TCTMobile needs DIR_IN flag. To get it, we
834 * supply a dummy data with the command.
835 */
836 err = bbb_command_start(sc, DIR_IN, 0, &sc->buffer,
837 sizeof(sc->buffer), &scsi_tct_eject,
838 sizeof(scsi_tct_eject), USB_MS_HZ);
839 break;
840 default:
841 printf("usb_msc_eject: unknown eject method (%d)\n", method);
842 break;
843 }
844 DPRINTF("Eject CD command status: %s\n", usbd_errstr(err));
845
846 bbb_detach(sc);
847 return (0);
848}