1/* $FreeBSD: head/sys/dev/usb/usb_msctest.c 194228 2009-06-15 01:02:43Z thompsa $ */
| 1/* $FreeBSD: head/sys/dev/usb/usb_msctest.c 194677 2009-06-23 02:19:59Z thompsa $ */
|
2/*- 3 * Copyright (c) 2008 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
| 2/*- 3 * Copyright (c) 2008 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 <dev/usb/usb_mfunc.h> 36#include <dev/usb/usb_error.h>
| 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/linker_set.h> 44#include <sys/module.h> 45#include <sys/lock.h> 46#include <sys/mutex.h> 47#include <sys/condvar.h> 48#include <sys/sysctl.h> 49#include <sys/sx.h> 50#include <sys/unistd.h> 51#include <sys/callout.h> 52#include <sys/malloc.h> 53#include <sys/priv.h> 54
|
37#include <dev/usb/usb.h>
| 55#include <dev/usb/usb.h>
|
| 56#include <dev/usb/usbdi.h> 57#include <dev/usb/usbdi_util.h>
|
38 39#define USB_DEBUG_VAR usb_debug 40
| 58 59#define USB_DEBUG_VAR usb_debug 60
|
41#include <dev/usb/usb_core.h>
| |
42#include <dev/usb/usb_busdma.h> 43#include <dev/usb/usb_process.h> 44#include <dev/usb/usb_transfer.h> 45#include <dev/usb/usb_msctest.h> 46#include <dev/usb/usb_debug.h> 47#include <dev/usb/usb_busdma.h> 48#include <dev/usb/usb_device.h> 49#include <dev/usb/usb_request.h> 50#include <dev/usb/usb_util.h>
| 61#include <dev/usb/usb_busdma.h> 62#include <dev/usb/usb_process.h> 63#include <dev/usb/usb_transfer.h> 64#include <dev/usb/usb_msctest.h> 65#include <dev/usb/usb_debug.h> 66#include <dev/usb/usb_busdma.h> 67#include <dev/usb/usb_device.h> 68#include <dev/usb/usb_request.h> 69#include <dev/usb/usb_util.h>
|
51#include <dev/usb/usb_lookup.h>
| |
52
| 70
|
53#include <dev/usb/usb_mfunc.h> 54#include <dev/usb/usb_error.h>
| |
55#include <dev/usb/usb.h> 56 57enum { 58 ST_COMMAND, 59 ST_DATA_RD, 60 ST_DATA_RD_CS, 61 ST_DATA_WR, 62 ST_DATA_WR_CS, 63 ST_STATUS, 64 ST_MAX, 65}; 66 67enum { 68 DIR_IN, 69 DIR_OUT, 70 DIR_NONE, 71}; 72 73#define BULK_SIZE 64 /* dummy */ 74 75/* Command Block Wrapper */ 76struct bbb_cbw { 77 uDWord dCBWSignature; 78#define CBWSIGNATURE 0x43425355 79 uDWord dCBWTag; 80 uDWord dCBWDataTransferLength; 81 uByte bCBWFlags; 82#define CBWFLAGS_OUT 0x00 83#define CBWFLAGS_IN 0x80 84 uByte bCBWLUN; 85 uByte bCDBLength; 86#define CBWCDBLENGTH 16 87 uByte CBWCDB[CBWCDBLENGTH]; 88} __packed; 89 90/* Command Status Wrapper */ 91struct bbb_csw { 92 uDWord dCSWSignature; 93#define CSWSIGNATURE 0x53425355 94 uDWord dCSWTag; 95 uDWord dCSWDataResidue; 96 uByte bCSWStatus; 97#define CSWSTATUS_GOOD 0x0 98#define CSWSTATUS_FAILED 0x1 99#define CSWSTATUS_PHASE 0x2 100} __packed; 101 102struct bbb_transfer { 103 struct mtx mtx; 104 struct cv cv; 105 struct bbb_cbw cbw; 106 struct bbb_csw csw; 107 108 struct usb_xfer *xfer[ST_MAX]; 109 110 uint8_t *data_ptr; 111 112 usb_size_t data_len; /* bytes */ 113 usb_size_t data_rem; /* bytes */ 114 usb_timeout_t data_timeout; /* ms */ 115 usb_frlength_t actlen; /* bytes */ 116 117 uint8_t cmd_len; /* bytes */ 118 uint8_t dir; 119 uint8_t lun; 120 uint8_t state; 121 uint8_t error; 122 uint8_t status_try; 123 124 uint8_t buffer[256]; 125}; 126 127static usb_callback_t bbb_command_callback; 128static usb_callback_t bbb_data_read_callback; 129static usb_callback_t bbb_data_rd_cs_callback; 130static usb_callback_t bbb_data_write_callback; 131static usb_callback_t bbb_data_wr_cs_callback; 132static usb_callback_t bbb_status_callback; 133 134static const struct usb_config bbb_config[ST_MAX] = { 135 136 [ST_COMMAND] = { 137 .type = UE_BULK, 138 .endpoint = UE_ADDR_ANY, 139 .direction = UE_DIR_OUT, 140 .bufsize = sizeof(struct bbb_cbw), 141 .callback = &bbb_command_callback, 142 .timeout = 4 * USB_MS_HZ, /* 4 seconds */ 143 }, 144 145 [ST_DATA_RD] = { 146 .type = UE_BULK, 147 .endpoint = UE_ADDR_ANY, 148 .direction = UE_DIR_IN, 149 .bufsize = BULK_SIZE, 150 .flags = {.proxy_buffer = 1,.short_xfer_ok = 1,}, 151 .callback = &bbb_data_read_callback, 152 .timeout = 4 * USB_MS_HZ, /* 4 seconds */ 153 }, 154 155 [ST_DATA_RD_CS] = { 156 .type = UE_CONTROL, 157 .endpoint = 0x00, /* Control pipe */ 158 .direction = UE_DIR_ANY, 159 .bufsize = sizeof(struct usb_device_request), 160 .callback = &bbb_data_rd_cs_callback, 161 .timeout = 1 * USB_MS_HZ, /* 1 second */ 162 }, 163 164 [ST_DATA_WR] = { 165 .type = UE_BULK, 166 .endpoint = UE_ADDR_ANY, 167 .direction = UE_DIR_OUT, 168 .bufsize = BULK_SIZE, 169 .flags = {.proxy_buffer = 1,}, 170 .callback = &bbb_data_write_callback, 171 .timeout = 4 * USB_MS_HZ, /* 4 seconds */ 172 }, 173 174 [ST_DATA_WR_CS] = { 175 .type = UE_CONTROL, 176 .endpoint = 0x00, /* Control pipe */ 177 .direction = UE_DIR_ANY, 178 .bufsize = sizeof(struct usb_device_request), 179 .callback = &bbb_data_wr_cs_callback, 180 .timeout = 1 * USB_MS_HZ, /* 1 second */ 181 }, 182 183 [ST_STATUS] = { 184 .type = UE_BULK, 185 .endpoint = UE_ADDR_ANY, 186 .direction = UE_DIR_IN, 187 .bufsize = sizeof(struct bbb_csw), 188 .flags = {.short_xfer_ok = 1,}, 189 .callback = &bbb_status_callback, 190 .timeout = 1 * USB_MS_HZ, /* 1 second */ 191 }, 192}; 193 194static void 195bbb_done(struct bbb_transfer *sc, uint8_t error) 196{ 197 struct usb_xfer *xfer; 198 199 xfer = sc->xfer[sc->state]; 200 201 /* verify the error code */ 202 203 if (error) { 204 switch (USB_GET_STATE(xfer)) { 205 case USB_ST_SETUP: 206 case USB_ST_TRANSFERRED: 207 error = 1; 208 break; 209 default: 210 error = 2; 211 break; 212 } 213 } 214 sc->error = error; 215 sc->state = ST_COMMAND; 216 sc->status_try = 1; 217 cv_signal(&sc->cv); 218} 219 220static void 221bbb_transfer_start(struct bbb_transfer *sc, uint8_t xfer_index) 222{ 223 sc->state = xfer_index; 224 usbd_transfer_start(sc->xfer[xfer_index]); 225} 226 227static void 228bbb_data_clear_stall_callback(struct usb_xfer *xfer, 229 uint8_t next_xfer, uint8_t stall_xfer) 230{
| 71#include <dev/usb/usb.h> 72 73enum { 74 ST_COMMAND, 75 ST_DATA_RD, 76 ST_DATA_RD_CS, 77 ST_DATA_WR, 78 ST_DATA_WR_CS, 79 ST_STATUS, 80 ST_MAX, 81}; 82 83enum { 84 DIR_IN, 85 DIR_OUT, 86 DIR_NONE, 87}; 88 89#define BULK_SIZE 64 /* dummy */ 90 91/* Command Block Wrapper */ 92struct bbb_cbw { 93 uDWord dCBWSignature; 94#define CBWSIGNATURE 0x43425355 95 uDWord dCBWTag; 96 uDWord dCBWDataTransferLength; 97 uByte bCBWFlags; 98#define CBWFLAGS_OUT 0x00 99#define CBWFLAGS_IN 0x80 100 uByte bCBWLUN; 101 uByte bCDBLength; 102#define CBWCDBLENGTH 16 103 uByte CBWCDB[CBWCDBLENGTH]; 104} __packed; 105 106/* Command Status Wrapper */ 107struct bbb_csw { 108 uDWord dCSWSignature; 109#define CSWSIGNATURE 0x53425355 110 uDWord dCSWTag; 111 uDWord dCSWDataResidue; 112 uByte bCSWStatus; 113#define CSWSTATUS_GOOD 0x0 114#define CSWSTATUS_FAILED 0x1 115#define CSWSTATUS_PHASE 0x2 116} __packed; 117 118struct bbb_transfer { 119 struct mtx mtx; 120 struct cv cv; 121 struct bbb_cbw cbw; 122 struct bbb_csw csw; 123 124 struct usb_xfer *xfer[ST_MAX]; 125 126 uint8_t *data_ptr; 127 128 usb_size_t data_len; /* bytes */ 129 usb_size_t data_rem; /* bytes */ 130 usb_timeout_t data_timeout; /* ms */ 131 usb_frlength_t actlen; /* bytes */ 132 133 uint8_t cmd_len; /* bytes */ 134 uint8_t dir; 135 uint8_t lun; 136 uint8_t state; 137 uint8_t error; 138 uint8_t status_try; 139 140 uint8_t buffer[256]; 141}; 142 143static usb_callback_t bbb_command_callback; 144static usb_callback_t bbb_data_read_callback; 145static usb_callback_t bbb_data_rd_cs_callback; 146static usb_callback_t bbb_data_write_callback; 147static usb_callback_t bbb_data_wr_cs_callback; 148static usb_callback_t bbb_status_callback; 149 150static const struct usb_config bbb_config[ST_MAX] = { 151 152 [ST_COMMAND] = { 153 .type = UE_BULK, 154 .endpoint = UE_ADDR_ANY, 155 .direction = UE_DIR_OUT, 156 .bufsize = sizeof(struct bbb_cbw), 157 .callback = &bbb_command_callback, 158 .timeout = 4 * USB_MS_HZ, /* 4 seconds */ 159 }, 160 161 [ST_DATA_RD] = { 162 .type = UE_BULK, 163 .endpoint = UE_ADDR_ANY, 164 .direction = UE_DIR_IN, 165 .bufsize = BULK_SIZE, 166 .flags = {.proxy_buffer = 1,.short_xfer_ok = 1,}, 167 .callback = &bbb_data_read_callback, 168 .timeout = 4 * USB_MS_HZ, /* 4 seconds */ 169 }, 170 171 [ST_DATA_RD_CS] = { 172 .type = UE_CONTROL, 173 .endpoint = 0x00, /* Control pipe */ 174 .direction = UE_DIR_ANY, 175 .bufsize = sizeof(struct usb_device_request), 176 .callback = &bbb_data_rd_cs_callback, 177 .timeout = 1 * USB_MS_HZ, /* 1 second */ 178 }, 179 180 [ST_DATA_WR] = { 181 .type = UE_BULK, 182 .endpoint = UE_ADDR_ANY, 183 .direction = UE_DIR_OUT, 184 .bufsize = BULK_SIZE, 185 .flags = {.proxy_buffer = 1,}, 186 .callback = &bbb_data_write_callback, 187 .timeout = 4 * USB_MS_HZ, /* 4 seconds */ 188 }, 189 190 [ST_DATA_WR_CS] = { 191 .type = UE_CONTROL, 192 .endpoint = 0x00, /* Control pipe */ 193 .direction = UE_DIR_ANY, 194 .bufsize = sizeof(struct usb_device_request), 195 .callback = &bbb_data_wr_cs_callback, 196 .timeout = 1 * USB_MS_HZ, /* 1 second */ 197 }, 198 199 [ST_STATUS] = { 200 .type = UE_BULK, 201 .endpoint = UE_ADDR_ANY, 202 .direction = UE_DIR_IN, 203 .bufsize = sizeof(struct bbb_csw), 204 .flags = {.short_xfer_ok = 1,}, 205 .callback = &bbb_status_callback, 206 .timeout = 1 * USB_MS_HZ, /* 1 second */ 207 }, 208}; 209 210static void 211bbb_done(struct bbb_transfer *sc, uint8_t error) 212{ 213 struct usb_xfer *xfer; 214 215 xfer = sc->xfer[sc->state]; 216 217 /* verify the error code */ 218 219 if (error) { 220 switch (USB_GET_STATE(xfer)) { 221 case USB_ST_SETUP: 222 case USB_ST_TRANSFERRED: 223 error = 1; 224 break; 225 default: 226 error = 2; 227 break; 228 } 229 } 230 sc->error = error; 231 sc->state = ST_COMMAND; 232 sc->status_try = 1; 233 cv_signal(&sc->cv); 234} 235 236static void 237bbb_transfer_start(struct bbb_transfer *sc, uint8_t xfer_index) 238{ 239 sc->state = xfer_index; 240 usbd_transfer_start(sc->xfer[xfer_index]); 241} 242 243static void 244bbb_data_clear_stall_callback(struct usb_xfer *xfer, 245 uint8_t next_xfer, uint8_t stall_xfer) 246{
|
231 struct bbb_transfer *sc = xfer->priv_sc;
| 247 struct bbb_transfer *sc = usbd_xfer_softc(xfer);
|
232 233 if (usbd_clear_stall_callback(xfer, sc->xfer[stall_xfer])) { 234 switch (USB_GET_STATE(xfer)) { 235 case USB_ST_SETUP: 236 case USB_ST_TRANSFERRED: 237 bbb_transfer_start(sc, next_xfer); 238 break; 239 default: 240 bbb_done(sc, 1); 241 break; 242 } 243 } 244} 245 246static void
| 248 249 if (usbd_clear_stall_callback(xfer, sc->xfer[stall_xfer])) { 250 switch (USB_GET_STATE(xfer)) { 251 case USB_ST_SETUP: 252 case USB_ST_TRANSFERRED: 253 bbb_transfer_start(sc, next_xfer); 254 break; 255 default: 256 bbb_done(sc, 1); 257 break; 258 } 259 } 260} 261 262static void
|
247bbb_command_callback(struct usb_xfer *xfer)
| 263bbb_command_callback(struct usb_xfer *xfer, usb_error_t error)
|
248{
| 264{
|
249 struct bbb_transfer *sc = xfer->priv_sc;
| 265 struct bbb_transfer *sc = usbd_xfer_softc(xfer);
|
250 uint32_t tag; 251 252 switch (USB_GET_STATE(xfer)) { 253 case USB_ST_TRANSFERRED: 254 bbb_transfer_start 255 (sc, ((sc->dir == DIR_IN) ? ST_DATA_RD : 256 (sc->dir == DIR_OUT) ? ST_DATA_WR : 257 ST_STATUS)); 258 break; 259 260 case USB_ST_SETUP: 261 sc->status_try = 0; 262 tag = UGETDW(sc->cbw.dCBWTag) + 1; 263 USETDW(sc->cbw.dCBWSignature, CBWSIGNATURE); 264 USETDW(sc->cbw.dCBWTag, tag); 265 USETDW(sc->cbw.dCBWDataTransferLength, (uint32_t)sc->data_len); 266 sc->cbw.bCBWFlags = ((sc->dir == DIR_IN) ? CBWFLAGS_IN : CBWFLAGS_OUT); 267 sc->cbw.bCBWLUN = sc->lun; 268 sc->cbw.bCDBLength = sc->cmd_len; 269 if (sc->cbw.bCDBLength > sizeof(sc->cbw.CBWCDB)) { 270 sc->cbw.bCDBLength = sizeof(sc->cbw.CBWCDB); 271 DPRINTFN(0, "Truncating long command!\n"); 272 }
| 266 uint32_t tag; 267 268 switch (USB_GET_STATE(xfer)) { 269 case USB_ST_TRANSFERRED: 270 bbb_transfer_start 271 (sc, ((sc->dir == DIR_IN) ? ST_DATA_RD : 272 (sc->dir == DIR_OUT) ? ST_DATA_WR : 273 ST_STATUS)); 274 break; 275 276 case USB_ST_SETUP: 277 sc->status_try = 0; 278 tag = UGETDW(sc->cbw.dCBWTag) + 1; 279 USETDW(sc->cbw.dCBWSignature, CBWSIGNATURE); 280 USETDW(sc->cbw.dCBWTag, tag); 281 USETDW(sc->cbw.dCBWDataTransferLength, (uint32_t)sc->data_len); 282 sc->cbw.bCBWFlags = ((sc->dir == DIR_IN) ? CBWFLAGS_IN : CBWFLAGS_OUT); 283 sc->cbw.bCBWLUN = sc->lun; 284 sc->cbw.bCDBLength = sc->cmd_len; 285 if (sc->cbw.bCDBLength > sizeof(sc->cbw.CBWCDB)) { 286 sc->cbw.bCDBLength = sizeof(sc->cbw.CBWCDB); 287 DPRINTFN(0, "Truncating long command!\n"); 288 }
|
273 xfer->frlengths[0] = sizeof(sc->cbw); 274 275 usbd_set_frame_data(xfer, &sc->cbw, 0);
| 289 usbd_xfer_set_frame_data(xfer, 0, &sc->cbw, sizeof(sc->cbw));
|
276 usbd_transfer_submit(xfer); 277 break; 278 279 default: /* Error */ 280 bbb_done(sc, 1); 281 break; 282 } 283} 284 285static void
| 290 usbd_transfer_submit(xfer); 291 break; 292 293 default: /* Error */ 294 bbb_done(sc, 1); 295 break; 296 } 297} 298 299static void
|
286bbb_data_read_callback(struct usb_xfer *xfer)
| 300bbb_data_read_callback(struct usb_xfer *xfer, usb_error_t error)
|
287{
| 301{
|
288 struct bbb_transfer *sc = xfer->priv_sc; 289 usb_frlength_t max_bulk = xfer->max_data_length;
| 302 struct bbb_transfer *sc = usbd_xfer_softc(xfer); 303 usb_frlength_t max_bulk = usbd_xfer_max_len(xfer); 304 int actlen, sumlen;
|
290
| 305
|
| 306 usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 307
|
291 switch (USB_GET_STATE(xfer)) { 292 case USB_ST_TRANSFERRED:
| 308 switch (USB_GET_STATE(xfer)) { 309 case USB_ST_TRANSFERRED:
|
293 sc->data_rem -= xfer->actlen; 294 sc->data_ptr += xfer->actlen; 295 sc->actlen += xfer->actlen;
| 310 sc->data_rem -= actlen; 311 sc->data_ptr += actlen; 312 sc->actlen += actlen;
|
296
| 313
|
297 if (xfer->actlen < xfer->sumlen) {
| 314 if (actlen < sumlen) {
|
298 /* short transfer */ 299 sc->data_rem = 0; 300 } 301 case USB_ST_SETUP: 302 DPRINTF("max_bulk=%d, data_rem=%d\n", 303 max_bulk, sc->data_rem); 304 305 if (sc->data_rem == 0) { 306 bbb_transfer_start(sc, ST_STATUS); 307 break; 308 } 309 if (max_bulk > sc->data_rem) { 310 max_bulk = sc->data_rem; 311 }
| 315 /* short transfer */ 316 sc->data_rem = 0; 317 } 318 case USB_ST_SETUP: 319 DPRINTF("max_bulk=%d, data_rem=%d\n", 320 max_bulk, sc->data_rem); 321 322 if (sc->data_rem == 0) { 323 bbb_transfer_start(sc, ST_STATUS); 324 break; 325 } 326 if (max_bulk > sc->data_rem) { 327 max_bulk = sc->data_rem; 328 }
|
312 xfer->timeout = sc->data_timeout; 313 xfer->frlengths[0] = max_bulk; 314 315 usbd_set_frame_data(xfer, sc->data_ptr, 0);
| 329 usbd_xfer_set_timeout(xfer, sc->data_timeout); 330 usbd_xfer_set_frame_data(xfer, 0, sc->data_ptr, max_bulk);
|
316 usbd_transfer_submit(xfer); 317 break; 318 319 default: /* Error */
| 331 usbd_transfer_submit(xfer); 332 break; 333 334 default: /* Error */
|
320 if (xfer->error == USB_ERR_CANCELLED) {
| 335 if (error == USB_ERR_CANCELLED) {
|
321 bbb_done(sc, 1); 322 } else { 323 bbb_transfer_start(sc, ST_DATA_RD_CS); 324 } 325 break; 326 } 327} 328 329static void
| 336 bbb_done(sc, 1); 337 } else { 338 bbb_transfer_start(sc, ST_DATA_RD_CS); 339 } 340 break; 341 } 342} 343 344static void
|
330bbb_data_rd_cs_callback(struct usb_xfer *xfer)
| 345bbb_data_rd_cs_callback(struct usb_xfer *xfer, usb_error_t error)
|
331{ 332 bbb_data_clear_stall_callback(xfer, ST_STATUS, 333 ST_DATA_RD); 334} 335 336static void
| 346{ 347 bbb_data_clear_stall_callback(xfer, ST_STATUS, 348 ST_DATA_RD); 349} 350 351static void
|
337bbb_data_write_callback(struct usb_xfer *xfer)
| 352bbb_data_write_callback(struct usb_xfer *xfer, usb_error_t error)
|
338{
| 353{
|
339 struct bbb_transfer *sc = xfer->priv_sc; 340 usb_frlength_t max_bulk = xfer->max_data_length;
| 354 struct bbb_transfer *sc = usbd_xfer_softc(xfer); 355 usb_frlength_t max_bulk = usbd_xfer_max_len(xfer); 356 int actlen, sumlen;
|
341
| 357
|
| 358 usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 359
|
342 switch (USB_GET_STATE(xfer)) { 343 case USB_ST_TRANSFERRED:
| 360 switch (USB_GET_STATE(xfer)) { 361 case USB_ST_TRANSFERRED:
|
344 sc->data_rem -= xfer->actlen; 345 sc->data_ptr += xfer->actlen; 346 sc->actlen += xfer->actlen;
| 362 sc->data_rem -= actlen; 363 sc->data_ptr += actlen; 364 sc->actlen += actlen;
|
347
| 365
|
348 if (xfer->actlen < xfer->sumlen) {
| 366 if (actlen < sumlen) {
|
349 /* short transfer */ 350 sc->data_rem = 0; 351 } 352 case USB_ST_SETUP: 353 DPRINTF("max_bulk=%d, data_rem=%d\n", 354 max_bulk, sc->data_rem); 355 356 if (sc->data_rem == 0) { 357 bbb_transfer_start(sc, ST_STATUS); 358 return; 359 } 360 if (max_bulk > sc->data_rem) { 361 max_bulk = sc->data_rem; 362 }
| 367 /* short transfer */ 368 sc->data_rem = 0; 369 } 370 case USB_ST_SETUP: 371 DPRINTF("max_bulk=%d, data_rem=%d\n", 372 max_bulk, sc->data_rem); 373 374 if (sc->data_rem == 0) { 375 bbb_transfer_start(sc, ST_STATUS); 376 return; 377 } 378 if (max_bulk > sc->data_rem) { 379 max_bulk = sc->data_rem; 380 }
|
363 xfer->timeout = sc->data_timeout; 364 xfer->frlengths[0] = max_bulk; 365 366 usbd_set_frame_data(xfer, sc->data_ptr, 0);
| 381 usbd_xfer_set_timeout(xfer, sc->data_timeout); 382 usbd_xfer_set_frame_data(xfer, 0, sc->data_ptr, max_bulk);
|
367 usbd_transfer_submit(xfer); 368 return; 369 370 default: /* Error */
| 383 usbd_transfer_submit(xfer); 384 return; 385 386 default: /* Error */
|
371 if (xfer->error == USB_ERR_CANCELLED) {
| 387 if (error == USB_ERR_CANCELLED) {
|
372 bbb_done(sc, 1); 373 } else { 374 bbb_transfer_start(sc, ST_DATA_WR_CS); 375 } 376 return; 377 378 } 379} 380 381static void
| 388 bbb_done(sc, 1); 389 } else { 390 bbb_transfer_start(sc, ST_DATA_WR_CS); 391 } 392 return; 393 394 } 395} 396 397static void
|
382bbb_data_wr_cs_callback(struct usb_xfer *xfer)
| 398bbb_data_wr_cs_callback(struct usb_xfer *xfer, usb_error_t error)
|
383{ 384 bbb_data_clear_stall_callback(xfer, ST_STATUS, 385 ST_DATA_WR); 386} 387 388static void
| 399{ 400 bbb_data_clear_stall_callback(xfer, ST_STATUS, 401 ST_DATA_WR); 402} 403 404static void
|
389bbb_status_callback(struct usb_xfer *xfer)
| 405bbb_status_callback(struct usb_xfer *xfer, usb_error_t error)
|
390{
| 406{
|
391 struct bbb_transfer *sc = xfer->priv_sc;
| 407 struct bbb_transfer *sc = usbd_xfer_softc(xfer); 408 int actlen, sumlen;
|
392
| 409
|
| 410 usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); 411
|
393 switch (USB_GET_STATE(xfer)) { 394 case USB_ST_TRANSFERRED: 395 396 /* very simple status check */ 397
| 412 switch (USB_GET_STATE(xfer)) { 413 case USB_ST_TRANSFERRED: 414 415 /* very simple status check */ 416
|
398 if (xfer->actlen < sizeof(sc->csw)) {
| 417 if (actlen < sizeof(sc->csw)) {
|
399 bbb_done(sc, 1);/* error */ 400 } else if (sc->csw.bCSWStatus == CSWSTATUS_GOOD) { 401 bbb_done(sc, 0);/* success */ 402 } else { 403 bbb_done(sc, 1);/* error */ 404 } 405 break; 406 407 case USB_ST_SETUP:
| 418 bbb_done(sc, 1);/* error */ 419 } else if (sc->csw.bCSWStatus == CSWSTATUS_GOOD) { 420 bbb_done(sc, 0);/* success */ 421 } else { 422 bbb_done(sc, 1);/* error */ 423 } 424 break; 425 426 case USB_ST_SETUP:
|
408 xfer->frlengths[0] = sizeof(sc->csw); 409 410 usbd_set_frame_data(xfer, &sc->csw, 0);
| 427 usbd_xfer_set_frame_data(xfer, 0, &sc->csw, sizeof(sc->csw));
|
411 usbd_transfer_submit(xfer); 412 break; 413 414 default: 415 DPRINTFN(0, "Failed to read CSW: %s, try %d\n",
| 428 usbd_transfer_submit(xfer); 429 break; 430 431 default: 432 DPRINTFN(0, "Failed to read CSW: %s, try %d\n",
|
416 usbd_errstr(xfer->error), sc->status_try);
| 433 usbd_errstr(error), sc->status_try);
|
417
| 434
|
418 if ((xfer->error == USB_ERR_CANCELLED) || 419 (sc->status_try)) {
| 435 if (error == USB_ERR_CANCELLED || sc->status_try) {
|
420 bbb_done(sc, 1); 421 } else { 422 sc->status_try = 1; 423 bbb_transfer_start(sc, ST_DATA_RD_CS); 424 } 425 break; 426 } 427} 428 429/*------------------------------------------------------------------------* 430 * bbb_command_start - execute a SCSI command synchronously 431 * 432 * Return values 433 * 0: Success 434 * Else: Failure 435 *------------------------------------------------------------------------*/ 436static uint8_t 437bbb_command_start(struct bbb_transfer *sc, uint8_t dir, uint8_t lun, 438 void *data_ptr, usb_size_t data_len, uint8_t cmd_len, 439 usb_timeout_t data_timeout) 440{ 441 sc->lun = lun; 442 sc->dir = data_len ? dir : DIR_NONE; 443 sc->data_ptr = data_ptr; 444 sc->data_len = data_len; 445 sc->data_rem = data_len; 446 sc->data_timeout = (data_timeout + USB_MS_HZ); 447 sc->actlen = 0; 448 sc->cmd_len = cmd_len; 449 450 usbd_transfer_start(sc->xfer[sc->state]); 451 452 while (usbd_transfer_pending(sc->xfer[sc->state])) { 453 cv_wait(&sc->cv, &sc->mtx); 454 } 455 return (sc->error); 456} 457 458/*------------------------------------------------------------------------* 459 * usb_test_autoinstall 460 * 461 * Return values: 462 * 0: This interface is an auto install disk (CD-ROM) 463 * Else: Not an auto install disk. 464 *------------------------------------------------------------------------*/ 465usb_error_t 466usb_test_autoinstall(struct usb_device *udev, uint8_t iface_index, 467 uint8_t do_eject) 468{ 469 struct usb_interface *iface; 470 struct usb_interface_descriptor *id; 471 usb_error_t err; 472 uint8_t timeout; 473 uint8_t sid_type; 474 struct bbb_transfer *sc; 475 476 if (udev == NULL) { 477 return (USB_ERR_INVAL); 478 } 479 iface = usbd_get_iface(udev, iface_index); 480 if (iface == NULL) { 481 return (USB_ERR_INVAL); 482 } 483 id = iface->idesc; 484 if (id == NULL) { 485 return (USB_ERR_INVAL); 486 } 487 if (id->bInterfaceClass != UICLASS_MASS) { 488 return (USB_ERR_INVAL); 489 } 490 switch (id->bInterfaceSubClass) { 491 case UISUBCLASS_SCSI: 492 case UISUBCLASS_UFI: 493 break; 494 default: 495 return (USB_ERR_INVAL); 496 } 497 498 switch (id->bInterfaceProtocol) { 499 case UIPROTO_MASS_BBB_OLD: 500 case UIPROTO_MASS_BBB: 501 break; 502 default: 503 return (USB_ERR_INVAL); 504 } 505 506 sc = malloc(sizeof(*sc), M_USB, M_WAITOK | M_ZERO); 507 if (sc == NULL) { 508 return (USB_ERR_NOMEM); 509 } 510 mtx_init(&sc->mtx, "USB autoinstall", NULL, MTX_DEF); 511 cv_init(&sc->cv, "WBBB"); 512 513 err = usbd_transfer_setup(udev, 514 &iface_index, sc->xfer, bbb_config, 515 ST_MAX, sc, &sc->mtx); 516 517 if (err) { 518 goto done; 519 } 520 mtx_lock(&sc->mtx); 521 522 timeout = 4; /* tries */ 523 524repeat_inquiry: 525 526 sc->cbw.CBWCDB[0] = 0x12; /* INQUIRY */ 527 sc->cbw.CBWCDB[1] = 0; 528 sc->cbw.CBWCDB[2] = 0; 529 sc->cbw.CBWCDB[3] = 0; 530 sc->cbw.CBWCDB[4] = 0x24; /* length */ 531 sc->cbw.CBWCDB[5] = 0; 532 err = bbb_command_start(sc, DIR_IN, 0, 533 sc->buffer, 0x24, 6, USB_MS_HZ); 534 535 if ((sc->actlen != 0) && (err == 0)) { 536 sid_type = sc->buffer[0] & 0x1F; 537 if (sid_type == 0x05) { 538 /* CD-ROM */ 539 if (do_eject) { 540 /* 0: opcode: SCSI START/STOP */ 541 sc->cbw.CBWCDB[0] = 0x1b; 542 /* 1: byte2: Not immediate */ 543 sc->cbw.CBWCDB[1] = 0x00; 544 /* 2..3: reserved */ 545 sc->cbw.CBWCDB[2] = 0x00; 546 sc->cbw.CBWCDB[3] = 0x00; 547 /* 4: Load/Eject command */ 548 sc->cbw.CBWCDB[4] = 0x02; 549 /* 5: control */ 550 sc->cbw.CBWCDB[5] = 0x00; 551 err = bbb_command_start(sc, DIR_OUT, 0, 552 NULL, 0, 6, USB_MS_HZ); 553 554 DPRINTFN(0, "Eject CD command " 555 "status: %s\n", usbd_errstr(err)); 556 } 557 err = 0; 558 goto done; 559 } 560 } else if ((err != 2) && --timeout) { 561 usb_pause_mtx(&sc->mtx, hz); 562 goto repeat_inquiry; 563 } 564 err = USB_ERR_INVAL; 565 goto done; 566 567done: 568 mtx_unlock(&sc->mtx); 569 usbd_transfer_unsetup(sc->xfer, ST_MAX); 570 mtx_destroy(&sc->mtx); 571 cv_destroy(&sc->cv); 572 free(sc, M_USB); 573 return (err); 574}
| 436 bbb_done(sc, 1); 437 } else { 438 sc->status_try = 1; 439 bbb_transfer_start(sc, ST_DATA_RD_CS); 440 } 441 break; 442 } 443} 444 445/*------------------------------------------------------------------------* 446 * bbb_command_start - execute a SCSI command synchronously 447 * 448 * Return values 449 * 0: Success 450 * Else: Failure 451 *------------------------------------------------------------------------*/ 452static uint8_t 453bbb_command_start(struct bbb_transfer *sc, uint8_t dir, uint8_t lun, 454 void *data_ptr, usb_size_t data_len, uint8_t cmd_len, 455 usb_timeout_t data_timeout) 456{ 457 sc->lun = lun; 458 sc->dir = data_len ? dir : DIR_NONE; 459 sc->data_ptr = data_ptr; 460 sc->data_len = data_len; 461 sc->data_rem = data_len; 462 sc->data_timeout = (data_timeout + USB_MS_HZ); 463 sc->actlen = 0; 464 sc->cmd_len = cmd_len; 465 466 usbd_transfer_start(sc->xfer[sc->state]); 467 468 while (usbd_transfer_pending(sc->xfer[sc->state])) { 469 cv_wait(&sc->cv, &sc->mtx); 470 } 471 return (sc->error); 472} 473 474/*------------------------------------------------------------------------* 475 * usb_test_autoinstall 476 * 477 * Return values: 478 * 0: This interface is an auto install disk (CD-ROM) 479 * Else: Not an auto install disk. 480 *------------------------------------------------------------------------*/ 481usb_error_t 482usb_test_autoinstall(struct usb_device *udev, uint8_t iface_index, 483 uint8_t do_eject) 484{ 485 struct usb_interface *iface; 486 struct usb_interface_descriptor *id; 487 usb_error_t err; 488 uint8_t timeout; 489 uint8_t sid_type; 490 struct bbb_transfer *sc; 491 492 if (udev == NULL) { 493 return (USB_ERR_INVAL); 494 } 495 iface = usbd_get_iface(udev, iface_index); 496 if (iface == NULL) { 497 return (USB_ERR_INVAL); 498 } 499 id = iface->idesc; 500 if (id == NULL) { 501 return (USB_ERR_INVAL); 502 } 503 if (id->bInterfaceClass != UICLASS_MASS) { 504 return (USB_ERR_INVAL); 505 } 506 switch (id->bInterfaceSubClass) { 507 case UISUBCLASS_SCSI: 508 case UISUBCLASS_UFI: 509 break; 510 default: 511 return (USB_ERR_INVAL); 512 } 513 514 switch (id->bInterfaceProtocol) { 515 case UIPROTO_MASS_BBB_OLD: 516 case UIPROTO_MASS_BBB: 517 break; 518 default: 519 return (USB_ERR_INVAL); 520 } 521 522 sc = malloc(sizeof(*sc), M_USB, M_WAITOK | M_ZERO); 523 if (sc == NULL) { 524 return (USB_ERR_NOMEM); 525 } 526 mtx_init(&sc->mtx, "USB autoinstall", NULL, MTX_DEF); 527 cv_init(&sc->cv, "WBBB"); 528 529 err = usbd_transfer_setup(udev, 530 &iface_index, sc->xfer, bbb_config, 531 ST_MAX, sc, &sc->mtx); 532 533 if (err) { 534 goto done; 535 } 536 mtx_lock(&sc->mtx); 537 538 timeout = 4; /* tries */ 539 540repeat_inquiry: 541 542 sc->cbw.CBWCDB[0] = 0x12; /* INQUIRY */ 543 sc->cbw.CBWCDB[1] = 0; 544 sc->cbw.CBWCDB[2] = 0; 545 sc->cbw.CBWCDB[3] = 0; 546 sc->cbw.CBWCDB[4] = 0x24; /* length */ 547 sc->cbw.CBWCDB[5] = 0; 548 err = bbb_command_start(sc, DIR_IN, 0, 549 sc->buffer, 0x24, 6, USB_MS_HZ); 550 551 if ((sc->actlen != 0) && (err == 0)) { 552 sid_type = sc->buffer[0] & 0x1F; 553 if (sid_type == 0x05) { 554 /* CD-ROM */ 555 if (do_eject) { 556 /* 0: opcode: SCSI START/STOP */ 557 sc->cbw.CBWCDB[0] = 0x1b; 558 /* 1: byte2: Not immediate */ 559 sc->cbw.CBWCDB[1] = 0x00; 560 /* 2..3: reserved */ 561 sc->cbw.CBWCDB[2] = 0x00; 562 sc->cbw.CBWCDB[3] = 0x00; 563 /* 4: Load/Eject command */ 564 sc->cbw.CBWCDB[4] = 0x02; 565 /* 5: control */ 566 sc->cbw.CBWCDB[5] = 0x00; 567 err = bbb_command_start(sc, DIR_OUT, 0, 568 NULL, 0, 6, USB_MS_HZ); 569 570 DPRINTFN(0, "Eject CD command " 571 "status: %s\n", usbd_errstr(err)); 572 } 573 err = 0; 574 goto done; 575 } 576 } else if ((err != 2) && --timeout) { 577 usb_pause_mtx(&sc->mtx, hz); 578 goto repeat_inquiry; 579 } 580 err = USB_ERR_INVAL; 581 goto done; 582 583done: 584 mtx_unlock(&sc->mtx); 585 usbd_transfer_unsetup(sc->xfer, ST_MAX); 586 mtx_destroy(&sc->mtx); 587 cv_destroy(&sc->cv); 588 free(sc, M_USB); 589 return (err); 590}
|