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