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