cfumass.c revision 317336
1/*- 2 * Copyright (c) 2016 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Edward Tomasz Napierala under sponsorship 6 * from the FreeBSD Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 */ 30/* 31 * USB Mass Storage Class Bulk-Only (BBB) Transport target. 32 * 33 * http://www.usb.org/developers/docs/devclass_docs/usbmassbulk_10.pdf 34 * 35 * This code implements the USB Mass Storage frontend driver for the CAM 36 * Target Layer (ctl(4)) subsystem. 37 */ 38 39#include <sys/cdefs.h> 40__FBSDID("$FreeBSD: stable/11/sys/dev/usb/storage/cfumass.c 317336 2017-04-23 09:00:26Z mav $"); 41 42#include <sys/param.h> 43#include <sys/bus.h> 44#include <sys/kernel.h> 45#include <sys/lock.h> 46#include <sys/module.h> 47#include <sys/mutex.h> 48#include <sys/refcount.h> 49#include <sys/stdint.h> 50#include <sys/sysctl.h> 51#include <sys/systm.h> 52 53#include <dev/usb/usb.h> 54#include <dev/usb/usbdi.h> 55#include "usbdevs.h" 56#include "usb_if.h" 57 58#include <cam/scsi/scsi_all.h> 59#include <cam/scsi/scsi_da.h> 60#include <cam/ctl/ctl_io.h> 61#include <cam/ctl/ctl.h> 62#include <cam/ctl/ctl_backend.h> 63#include <cam/ctl/ctl_error.h> 64#include <cam/ctl/ctl_frontend.h> 65#include <cam/ctl/ctl_debug.h> 66#include <cam/ctl/ctl_ha.h> 67#include <cam/ctl/ctl_ioctl.h> 68#include <cam/ctl/ctl_private.h> 69 70SYSCTL_NODE(_hw_usb, OID_AUTO, cfumass, CTLFLAG_RW, 0, 71 "CAM Target Layer USB Mass Storage Frontend"); 72static int debug = 1; 73SYSCTL_INT(_hw_usb_cfumass, OID_AUTO, debug, CTLFLAG_RWTUN, 74 &debug, 1, "Enable debug messages"); 75static int max_lun = 0; 76SYSCTL_INT(_hw_usb_cfumass, OID_AUTO, max_lun, CTLFLAG_RWTUN, 77 &max_lun, 1, "Maximum advertised LUN number"); 78static int ignore_stop = 1; 79SYSCTL_INT(_hw_usb_cfumass, OID_AUTO, ignore_stop, CTLFLAG_RWTUN, 80 &ignore_stop, 1, "Ignore START STOP UNIT with START and LOEJ bits cleared"); 81 82/* 83 * The driver uses a single, global CTL port. It could create its ports 84 * in cfumass_attach() instead, but that would make it impossible to specify 85 * "port cfumass0" in ctl.conf(5), as the port generally wouldn't exist 86 * at the time ctld(8) gets run. 87 */ 88struct ctl_port cfumass_port; 89bool cfumass_port_online; 90volatile u_int cfumass_refcount; 91 92#ifndef CFUMASS_BULK_SIZE 93#define CFUMASS_BULK_SIZE (1U << 17) /* bytes */ 94#endif 95 96/* 97 * USB transfer definitions. 98 */ 99#define CFUMASS_T_COMMAND 0 100#define CFUMASS_T_DATA_OUT 1 101#define CFUMASS_T_DATA_IN 2 102#define CFUMASS_T_STATUS 3 103#define CFUMASS_T_MAX 4 104 105/* 106 * USB interface specific control requests. 107 */ 108#define UR_RESET 0xff /* Bulk-Only Mass Storage Reset */ 109#define UR_GET_MAX_LUN 0xfe /* Get Max LUN */ 110 111/* 112 * Command Block Wrapper. 113 */ 114struct cfumass_cbw_t { 115 uDWord dCBWSignature; 116#define CBWSIGNATURE 0x43425355 /* "USBC" */ 117 uDWord dCBWTag; 118 uDWord dCBWDataTransferLength; 119 uByte bCBWFlags; 120#define CBWFLAGS_OUT 0x00 121#define CBWFLAGS_IN 0x80 122 uByte bCBWLUN; 123 uByte bCDBLength; 124#define CBWCBLENGTH 16 125 uByte CBWCB[CBWCBLENGTH]; 126} __packed; 127 128#define CFUMASS_CBW_SIZE 31 129CTASSERT(sizeof(struct cfumass_cbw_t) == CFUMASS_CBW_SIZE); 130 131/* 132 * Command Status Wrapper. 133 */ 134struct cfumass_csw_t { 135 uDWord dCSWSignature; 136#define CSWSIGNATURE 0x53425355 /* "USBS" */ 137 uDWord dCSWTag; 138 uDWord dCSWDataResidue; 139 uByte bCSWStatus; 140#define CSWSTATUS_GOOD 0x0 141#define CSWSTATUS_FAILED 0x1 142#define CSWSTATUS_PHASE 0x2 143} __packed; 144 145#define CFUMASS_CSW_SIZE 13 146CTASSERT(sizeof(struct cfumass_csw_t) == CFUMASS_CSW_SIZE); 147 148struct cfumass_softc { 149 device_t sc_dev; 150 struct usb_device *sc_udev; 151 struct usb_xfer *sc_xfer[CFUMASS_T_MAX]; 152 153 struct cfumass_cbw_t *sc_cbw; 154 struct cfumass_csw_t *sc_csw; 155 156 struct mtx sc_mtx; 157 int sc_online; 158 int sc_ctl_initid; 159 160 /* 161 * This is used to communicate between CTL callbacks 162 * and USB callbacks; basically, it holds the state 163 * for the current command ("the" command, since there 164 * is no queueing in USB Mass Storage). 165 */ 166 bool sc_current_stalled; 167 168 /* 169 * The following are set upon receiving a SCSI command. 170 */ 171 int sc_current_tag; 172 int sc_current_transfer_length; 173 int sc_current_flags; 174 175 /* 176 * The following are set in ctl_datamove(). 177 */ 178 int sc_current_residue; 179 union ctl_io *sc_ctl_io; 180 181 /* 182 * The following is set in cfumass_done(). 183 */ 184 int sc_current_status; 185 186 /* 187 * Number of requests queued to CTL. 188 */ 189 volatile u_int sc_queued; 190}; 191 192/* 193 * USB interface. 194 */ 195static device_probe_t cfumass_probe; 196static device_attach_t cfumass_attach; 197static device_detach_t cfumass_detach; 198static device_suspend_t cfumass_suspend; 199static device_resume_t cfumass_resume; 200static usb_handle_request_t cfumass_handle_request; 201 202static usb_callback_t cfumass_t_command_callback; 203static usb_callback_t cfumass_t_data_out_callback; 204static usb_callback_t cfumass_t_data_in_callback; 205static usb_callback_t cfumass_t_status_callback; 206 207static device_method_t cfumass_methods[] = { 208 209 /* USB interface. */ 210 DEVMETHOD(usb_handle_request, cfumass_handle_request), 211 212 /* Device interface. */ 213 DEVMETHOD(device_probe, cfumass_probe), 214 DEVMETHOD(device_attach, cfumass_attach), 215 DEVMETHOD(device_detach, cfumass_detach), 216 DEVMETHOD(device_suspend, cfumass_suspend), 217 DEVMETHOD(device_resume, cfumass_resume), 218 219 DEVMETHOD_END 220}; 221 222static driver_t cfumass_driver = { 223 .name = "cfumass", 224 .methods = cfumass_methods, 225 .size = sizeof(struct cfumass_softc), 226}; 227 228static devclass_t cfumass_devclass; 229 230DRIVER_MODULE(cfumass, uhub, cfumass_driver, cfumass_devclass, NULL, 0); 231MODULE_VERSION(cfumass, 0); 232MODULE_DEPEND(cfumass, usb, 1, 1, 1); 233MODULE_DEPEND(cfumass, usb_template, 1, 1, 1); 234 235static struct usb_config cfumass_config[CFUMASS_T_MAX] = { 236 237 [CFUMASS_T_COMMAND] = { 238 .type = UE_BULK, 239 .endpoint = UE_ADDR_ANY, 240 .direction = UE_DIR_OUT, 241 .bufsize = sizeof(struct cfumass_cbw_t), 242 .callback = &cfumass_t_command_callback, 243 .usb_mode = USB_MODE_DEVICE, 244 }, 245 246 [CFUMASS_T_DATA_OUT] = { 247 .type = UE_BULK, 248 .endpoint = UE_ADDR_ANY, 249 .direction = UE_DIR_OUT, 250 .bufsize = CFUMASS_BULK_SIZE, 251 .flags = {.proxy_buffer = 1, .short_xfer_ok = 1, 252 .ext_buffer = 1}, 253 .callback = &cfumass_t_data_out_callback, 254 .usb_mode = USB_MODE_DEVICE, 255 }, 256 257 [CFUMASS_T_DATA_IN] = { 258 .type = UE_BULK, 259 .endpoint = UE_ADDR_ANY, 260 .direction = UE_DIR_IN, 261 .bufsize = CFUMASS_BULK_SIZE, 262 .flags = {.proxy_buffer = 1, .short_xfer_ok = 1, 263 .ext_buffer = 1}, 264 .callback = &cfumass_t_data_in_callback, 265 .usb_mode = USB_MODE_DEVICE, 266 }, 267 268 [CFUMASS_T_STATUS] = { 269 .type = UE_BULK, 270 .endpoint = UE_ADDR_ANY, 271 .direction = UE_DIR_IN, 272 .bufsize = sizeof(struct cfumass_csw_t), 273 .flags = {.short_xfer_ok = 1}, 274 .callback = &cfumass_t_status_callback, 275 .usb_mode = USB_MODE_DEVICE, 276 }, 277}; 278 279/* 280 * CTL frontend interface. 281 */ 282static int cfumass_init(void); 283static int cfumass_shutdown(void); 284static void cfumass_online(void *arg); 285static void cfumass_offline(void *arg); 286static void cfumass_datamove(union ctl_io *io); 287static void cfumass_done(union ctl_io *io); 288 289static struct ctl_frontend cfumass_frontend = { 290 .name = "umass", 291 .init = cfumass_init, 292 .shutdown = cfumass_shutdown, 293}; 294CTL_FRONTEND_DECLARE(ctlcfumass, cfumass_frontend); 295 296#define CFUMASS_DEBUG(S, X, ...) \ 297 do { \ 298 if (debug > 1) { \ 299 device_printf(S->sc_dev, "%s: " X "\n", \ 300 __func__, ## __VA_ARGS__); \ 301 } \ 302 } while (0) 303 304#define CFUMASS_WARN(S, X, ...) \ 305 do { \ 306 if (debug > 0) { \ 307 device_printf(S->sc_dev, "WARNING: %s: " X "\n",\ 308 __func__, ## __VA_ARGS__); \ 309 } \ 310 } while (0) 311 312#define CFUMASS_LOCK(X) mtx_lock(&X->sc_mtx) 313#define CFUMASS_UNLOCK(X) mtx_unlock(&X->sc_mtx) 314 315static void cfumass_transfer_start(struct cfumass_softc *sc, 316 uint8_t xfer_index); 317static void cfumass_terminate(struct cfumass_softc *sc); 318 319static int 320cfumass_probe(device_t dev) 321{ 322 struct usb_attach_arg *uaa; 323 struct usb_interface_descriptor *id; 324 325 uaa = device_get_ivars(dev); 326 327 if (uaa->usb_mode != USB_MODE_DEVICE) 328 return (ENXIO); 329 330 /* 331 * Check for a compliant device. 332 */ 333 id = usbd_get_interface_descriptor(uaa->iface); 334 if ((id == NULL) || 335 (id->bInterfaceClass != UICLASS_MASS) || 336 (id->bInterfaceSubClass != UISUBCLASS_SCSI) || 337 (id->bInterfaceProtocol != UIPROTO_MASS_BBB)) { 338 return (ENXIO); 339 } 340 341 return (BUS_PROBE_GENERIC); 342} 343 344static int 345cfumass_attach(device_t dev) 346{ 347 struct cfumass_softc *sc; 348 struct usb_attach_arg *uaa; 349 int error; 350 351 sc = device_get_softc(dev); 352 uaa = device_get_ivars(dev); 353 354 sc->sc_dev = dev; 355 sc->sc_udev = uaa->device; 356 357 CFUMASS_DEBUG(sc, "go"); 358 359 usbd_set_power_mode(uaa->device, USB_POWER_MODE_SAVE); 360 device_set_usb_desc(dev); 361 362 mtx_init(&sc->sc_mtx, "cfumass", NULL, MTX_DEF); 363 refcount_acquire(&cfumass_refcount); 364 365 error = usbd_transfer_setup(uaa->device, 366 &uaa->info.bIfaceIndex, sc->sc_xfer, cfumass_config, 367 CFUMASS_T_MAX, sc, &sc->sc_mtx); 368 if (error != 0) { 369 CFUMASS_WARN(sc, "usbd_transfer_setup() failed: %s", 370 usbd_errstr(error)); 371 refcount_release(&cfumass_refcount); 372 return (ENXIO); 373 } 374 375 sc->sc_cbw = 376 usbd_xfer_get_frame_buffer(sc->sc_xfer[CFUMASS_T_COMMAND], 0); 377 sc->sc_csw = 378 usbd_xfer_get_frame_buffer(sc->sc_xfer[CFUMASS_T_STATUS], 0); 379 380 sc->sc_ctl_initid = ctl_add_initiator(&cfumass_port, -1, 0, NULL); 381 if (sc->sc_ctl_initid < 0) { 382 CFUMASS_WARN(sc, "ctl_add_initiator() failed with error %d", 383 sc->sc_ctl_initid); 384 usbd_transfer_unsetup(sc->sc_xfer, CFUMASS_T_MAX); 385 refcount_release(&cfumass_refcount); 386 return (ENXIO); 387 } 388 389 refcount_init(&sc->sc_queued, 0); 390 391 CFUMASS_LOCK(sc); 392 cfumass_transfer_start(sc, CFUMASS_T_COMMAND); 393 CFUMASS_UNLOCK(sc); 394 395 return (0); 396} 397 398static int 399cfumass_detach(device_t dev) 400{ 401 struct cfumass_softc *sc; 402 int error; 403 404 sc = device_get_softc(dev); 405 406 CFUMASS_DEBUG(sc, "go"); 407 408 CFUMASS_LOCK(sc); 409 cfumass_terminate(sc); 410 CFUMASS_UNLOCK(sc); 411 usbd_transfer_unsetup(sc->sc_xfer, CFUMASS_T_MAX); 412 413 if (sc->sc_ctl_initid != -1) { 414 error = ctl_remove_initiator(&cfumass_port, sc->sc_ctl_initid); 415 if (error != 0) { 416 CFUMASS_WARN(sc, "ctl_remove_initiator() failed " 417 "with error %d", error); 418 } 419 sc->sc_ctl_initid = -1; 420 } 421 422 mtx_destroy(&sc->sc_mtx); 423 refcount_release(&cfumass_refcount); 424 425 return (0); 426} 427 428static int 429cfumass_suspend(device_t dev) 430{ 431 struct cfumass_softc *sc; 432 433 sc = device_get_softc(dev); 434 CFUMASS_DEBUG(sc, "go"); 435 436 return (0); 437} 438 439static int 440cfumass_resume(device_t dev) 441{ 442 struct cfumass_softc *sc; 443 444 sc = device_get_softc(dev); 445 CFUMASS_DEBUG(sc, "go"); 446 447 return (0); 448} 449 450static void 451cfumass_transfer_start(struct cfumass_softc *sc, uint8_t xfer_index) 452{ 453 454 usbd_transfer_start(sc->sc_xfer[xfer_index]); 455} 456 457static void 458cfumass_transfer_stop_and_drain(struct cfumass_softc *sc, uint8_t xfer_index) 459{ 460 461 usbd_transfer_stop(sc->sc_xfer[xfer_index]); 462 CFUMASS_UNLOCK(sc); 463 usbd_transfer_drain(sc->sc_xfer[xfer_index]); 464 CFUMASS_LOCK(sc); 465} 466 467static void 468cfumass_terminate(struct cfumass_softc *sc) 469{ 470 int last; 471 472 for (;;) { 473 cfumass_transfer_stop_and_drain(sc, CFUMASS_T_COMMAND); 474 cfumass_transfer_stop_and_drain(sc, CFUMASS_T_DATA_IN); 475 cfumass_transfer_stop_and_drain(sc, CFUMASS_T_DATA_OUT); 476 477 if (sc->sc_ctl_io != NULL) { 478 CFUMASS_DEBUG(sc, "terminating CTL transfer"); 479 ctl_set_data_phase_error(&sc->sc_ctl_io->scsiio); 480 sc->sc_ctl_io->scsiio.be_move_done(sc->sc_ctl_io); 481 sc->sc_ctl_io = NULL; 482 } 483 484 cfumass_transfer_stop_and_drain(sc, CFUMASS_T_STATUS); 485 486 refcount_acquire(&sc->sc_queued); 487 last = refcount_release(&sc->sc_queued); 488 if (last != 0) 489 break; 490 491 CFUMASS_DEBUG(sc, "%d CTL tasks pending", sc->sc_queued); 492 msleep(__DEVOLATILE(void *, &sc->sc_queued), &sc->sc_mtx, 493 0, "cfumass_reset", hz / 100); 494 } 495} 496 497static int 498cfumass_handle_request(device_t dev, 499 const void *preq, void **pptr, uint16_t *plen, 500 uint16_t offset, uint8_t *pstate) 501{ 502 static uint8_t max_lun_tmp; 503 struct cfumass_softc *sc; 504 const struct usb_device_request *req; 505 uint8_t is_complete; 506 507 sc = device_get_softc(dev); 508 req = preq; 509 is_complete = *pstate; 510 511 CFUMASS_DEBUG(sc, "go"); 512 513 if (is_complete) 514 return (ENXIO); 515 516 if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) && 517 (req->bRequest == UR_RESET)) { 518 CFUMASS_WARN(sc, "received Bulk-Only Mass Storage Reset"); 519 *plen = 0; 520 521 CFUMASS_LOCK(sc); 522 cfumass_terminate(sc); 523 cfumass_transfer_start(sc, CFUMASS_T_COMMAND); 524 CFUMASS_UNLOCK(sc); 525 526 CFUMASS_DEBUG(sc, "Bulk-Only Mass Storage Reset done"); 527 return (0); 528 } 529 530 if ((req->bmRequestType == UT_READ_CLASS_INTERFACE) && 531 (req->bRequest == UR_GET_MAX_LUN)) { 532 CFUMASS_DEBUG(sc, "received Get Max LUN"); 533 if (offset == 0) { 534 *plen = 1; 535 /* 536 * The protocol doesn't support LUN numbers higher 537 * than 15. Also, some initiators (namely Windows XP 538 * SP3 Version 2002) can't properly query the number 539 * of LUNs, resulting in inaccessible "fake" ones - thus 540 * the default limit of one LUN. 541 */ 542 if (max_lun < 0 || max_lun > 15) { 543 CFUMASS_WARN(sc, 544 "invalid hw.usb.cfumass.max_lun, must be " 545 "between 0 and 15; defaulting to 0"); 546 max_lun_tmp = 0; 547 } else { 548 max_lun_tmp = max_lun; 549 } 550 *pptr = &max_lun_tmp; 551 } else { 552 *plen = 0; 553 } 554 return (0); 555 } 556 557 return (ENXIO); 558} 559 560static int 561cfumass_quirk(struct cfumass_softc *sc, unsigned char *cdb, int cdb_len) 562{ 563 struct scsi_start_stop_unit *sssu; 564 565 switch (cdb[0]) { 566 case START_STOP_UNIT: 567 /* 568 * Some initiators - eg OSX, Darwin Kernel Version 15.6.0, 569 * root:xnu-3248.60.11~2/RELEASE_X86_64 - attempt to stop 570 * the unit on eject, but fail to start it when it's plugged 571 * back. Just ignore the command. 572 */ 573 574 if (cdb_len < sizeof(*sssu)) { 575 CFUMASS_DEBUG(sc, "received START STOP UNIT with " 576 "bCDBLength %d, should be %zd", 577 cdb_len, sizeof(*sssu)); 578 break; 579 } 580 581 sssu = (struct scsi_start_stop_unit *)cdb; 582 if ((sssu->how & SSS_PC_MASK) != 0) 583 break; 584 585 if ((sssu->how & SSS_START) != 0) 586 break; 587 588 if ((sssu->how & SSS_LOEJ) != 0) 589 break; 590 591 if (ignore_stop == 0) { 592 break; 593 } else if (ignore_stop == 1) { 594 CFUMASS_WARN(sc, "ignoring START STOP UNIT request"); 595 } else { 596 CFUMASS_DEBUG(sc, "ignoring START STOP UNIT request"); 597 } 598 599 sc->sc_current_status = 0; 600 cfumass_transfer_start(sc, CFUMASS_T_STATUS); 601 602 return (1); 603 default: 604 break; 605 } 606 607 return (0); 608} 609 610static void 611cfumass_t_command_callback(struct usb_xfer *xfer, usb_error_t usb_error) 612{ 613 struct cfumass_softc *sc; 614 uint32_t signature; 615 union ctl_io *io; 616 int error = 0; 617 618 sc = usbd_xfer_softc(xfer); 619 620 KASSERT(sc->sc_ctl_io == NULL, 621 ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io)); 622 623 switch (USB_GET_STATE(xfer)) { 624 case USB_ST_TRANSFERRED: 625 CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED"); 626 627 signature = UGETDW(sc->sc_cbw->dCBWSignature); 628 if (signature != CBWSIGNATURE) { 629 CFUMASS_WARN(sc, "wrong dCBWSignature 0x%08x, " 630 "should be 0x%08x", signature, CBWSIGNATURE); 631 break; 632 } 633 634 if (sc->sc_cbw->bCDBLength <= 0 || 635 sc->sc_cbw->bCDBLength > sizeof(sc->sc_cbw->CBWCB)) { 636 CFUMASS_WARN(sc, "invalid bCDBLength %d, should be <= %zd", 637 sc->sc_cbw->bCDBLength, sizeof(sc->sc_cbw->CBWCB)); 638 break; 639 } 640 641 sc->sc_current_stalled = false; 642 sc->sc_current_status = 0; 643 sc->sc_current_tag = UGETDW(sc->sc_cbw->dCBWTag); 644 sc->sc_current_transfer_length = 645 UGETDW(sc->sc_cbw->dCBWDataTransferLength); 646 sc->sc_current_flags = sc->sc_cbw->bCBWFlags; 647 648 /* 649 * Make sure to report proper residue if the datamove wasn't 650 * required, or wasn't called due to SCSI error. 651 */ 652 sc->sc_current_residue = sc->sc_current_transfer_length; 653 654 if (cfumass_quirk(sc, 655 sc->sc_cbw->CBWCB, sc->sc_cbw->bCDBLength) != 0) 656 break; 657 658 if (!cfumass_port_online) { 659 CFUMASS_DEBUG(sc, "cfumass port is offline; stalling"); 660 usbd_xfer_set_stall(xfer); 661 break; 662 } 663 664 /* 665 * Those CTL functions cannot be called with mutex held. 666 */ 667 CFUMASS_UNLOCK(sc); 668 io = ctl_alloc_io(cfumass_port.ctl_pool_ref); 669 ctl_zero_io(io); 670 io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = sc; 671 io->io_hdr.io_type = CTL_IO_SCSI; 672 io->io_hdr.nexus.initid = sc->sc_ctl_initid; 673 io->io_hdr.nexus.targ_port = cfumass_port.targ_port; 674 io->io_hdr.nexus.targ_lun = ctl_decode_lun(sc->sc_cbw->bCBWLUN); 675 io->scsiio.tag_num = UGETDW(sc->sc_cbw->dCBWTag); 676 io->scsiio.tag_type = CTL_TAG_UNTAGGED; 677 io->scsiio.cdb_len = sc->sc_cbw->bCDBLength; 678 memcpy(io->scsiio.cdb, sc->sc_cbw->CBWCB, sc->sc_cbw->bCDBLength); 679 refcount_acquire(&sc->sc_queued); 680 error = ctl_queue(io); 681 if (error != CTL_RETVAL_COMPLETE) { 682 CFUMASS_WARN(sc, 683 "ctl_queue() failed; error %d; stalling", error); 684 ctl_free_io(io); 685 refcount_release(&sc->sc_queued); 686 CFUMASS_LOCK(sc); 687 usbd_xfer_set_stall(xfer); 688 break; 689 } 690 691 CFUMASS_LOCK(sc); 692 break; 693 694 case USB_ST_SETUP: 695tr_setup: 696 CFUMASS_DEBUG(sc, "USB_ST_SETUP"); 697 698 usbd_xfer_set_frame_len(xfer, 0, sizeof(*sc->sc_cbw)); 699 usbd_transfer_submit(xfer); 700 break; 701 702 default: 703 if (usb_error == USB_ERR_CANCELLED) { 704 CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED"); 705 break; 706 } 707 708 CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s", usbd_errstr(usb_error)); 709 710 goto tr_setup; 711 } 712} 713 714static void 715cfumass_t_data_out_callback(struct usb_xfer *xfer, usb_error_t usb_error) 716{ 717 struct cfumass_softc *sc; 718 union ctl_io *io; 719 struct ctl_sg_entry ctl_sg_entry, *ctl_sglist; 720 int actlen, ctl_sg_count; 721 722 sc = usbd_xfer_softc(xfer); 723 io = sc->sc_ctl_io; 724 725 if (io->scsiio.kern_sg_entries > 0) { 726 ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr; 727 ctl_sg_count = io->scsiio.kern_sg_entries; 728 } else { 729 ctl_sglist = &ctl_sg_entry; 730 ctl_sglist->addr = io->scsiio.kern_data_ptr; 731 ctl_sglist->len = io->scsiio.kern_data_len; 732 ctl_sg_count = 1; 733 } 734 735 switch (USB_GET_STATE(xfer)) { 736 case USB_ST_TRANSFERRED: 737 CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED"); 738 739 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 740 if (actlen != ctl_sglist[0].len) { 741 KASSERT(actlen <= ctl_sglist[0].len, 742 ("actlen %d > ctl_sglist.len %zd", 743 actlen, ctl_sglist[0].len)); 744 CFUMASS_DEBUG(sc, "host transferred %d bytes" 745 "instead of expected %zd bytes", 746 actlen, ctl_sglist[0].len); 747 } 748 sc->sc_current_residue -= actlen; 749 io->scsiio.kern_data_resid -= actlen; 750 io->scsiio.be_move_done(io); 751 sc->sc_ctl_io = NULL; 752 break; 753 754 case USB_ST_SETUP: 755tr_setup: 756 CFUMASS_DEBUG(sc, "USB_ST_SETUP"); 757 758 CFUMASS_DEBUG(sc, "requested size %d, CTL segment size %zd", 759 sc->sc_current_transfer_length, ctl_sglist[0].len); 760 761 usbd_xfer_set_frame_data(xfer, 0, ctl_sglist[0].addr, ctl_sglist[0].len); 762 usbd_transfer_submit(xfer); 763 break; 764 765 default: 766 if (usb_error == USB_ERR_CANCELLED) { 767 CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED"); 768 break; 769 } 770 771 CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s", 772 usbd_errstr(usb_error)); 773 774 goto tr_setup; 775 } 776} 777 778static void 779cfumass_t_data_in_callback(struct usb_xfer *xfer, usb_error_t usb_error) 780{ 781 struct cfumass_softc *sc; 782 union ctl_io *io; 783 uint32_t max_bulk; 784 struct ctl_sg_entry ctl_sg_entry, *ctl_sglist; 785 int actlen, ctl_sg_count; 786 787 sc = usbd_xfer_softc(xfer); 788 io = sc->sc_ctl_io; 789 790 switch (USB_GET_STATE(xfer)) { 791 case USB_ST_TRANSFERRED: 792 CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED"); 793 794 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 795 sc->sc_current_residue -= actlen; 796 io->scsiio.kern_data_resid -= actlen; 797 io->scsiio.be_move_done(io); 798 sc->sc_ctl_io = NULL; 799 break; 800 801 case USB_ST_SETUP: 802tr_setup: 803 CFUMASS_DEBUG(sc, "USB_ST_SETUP"); 804 805 if (io->scsiio.kern_sg_entries > 0) { 806 ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr; 807 ctl_sg_count = io->scsiio.kern_sg_entries; 808 } else { 809 ctl_sglist = &ctl_sg_entry; 810 ctl_sglist->addr = io->scsiio.kern_data_ptr; 811 ctl_sglist->len = io->scsiio.kern_data_len; 812 ctl_sg_count = 1; 813 } 814 815 if (sc->sc_current_transfer_length > io->scsiio.kern_total_len) { 816 CFUMASS_DEBUG(sc, "initiator requested %d bytes, " 817 "we will send %ju and stall", 818 sc->sc_current_transfer_length, 819 (uintmax_t)io->scsiio.kern_total_len); 820 } 821 822 max_bulk = usbd_xfer_max_len(xfer); 823 CFUMASS_DEBUG(sc, "max_bulk %d, requested size %d, " 824 "CTL segment size %zd", max_bulk, 825 sc->sc_current_transfer_length, ctl_sglist[0].len); 826 827 if (max_bulk >= ctl_sglist[0].len) 828 max_bulk = ctl_sglist[0].len; 829 830 usbd_xfer_set_frame_data(xfer, 0, ctl_sglist[0].addr, max_bulk); 831 usbd_transfer_submit(xfer); 832 833 break; 834 835 default: 836 if (usb_error == USB_ERR_CANCELLED) { 837 CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED"); 838 break; 839 } 840 841 CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s", usbd_errstr(usb_error)); 842 843 goto tr_setup; 844 } 845} 846 847static void 848cfumass_t_status_callback(struct usb_xfer *xfer, usb_error_t usb_error) 849{ 850 struct cfumass_softc *sc; 851 852 sc = usbd_xfer_softc(xfer); 853 854 KASSERT(sc->sc_ctl_io == NULL, 855 ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io)); 856 857 switch (USB_GET_STATE(xfer)) { 858 case USB_ST_TRANSFERRED: 859 CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED"); 860 861 cfumass_transfer_start(sc, CFUMASS_T_COMMAND); 862 break; 863 864 case USB_ST_SETUP: 865tr_setup: 866 CFUMASS_DEBUG(sc, "USB_ST_SETUP"); 867 868 if (sc->sc_current_residue > 0 && !sc->sc_current_stalled) { 869 CFUMASS_DEBUG(sc, "non-zero residue, stalling"); 870 usbd_xfer_set_stall(xfer); 871 sc->sc_current_stalled = true; 872 } 873 874 USETDW(sc->sc_csw->dCSWSignature, CSWSIGNATURE); 875 USETDW(sc->sc_csw->dCSWTag, sc->sc_current_tag); 876 USETDW(sc->sc_csw->dCSWDataResidue, sc->sc_current_residue); 877 sc->sc_csw->bCSWStatus = sc->sc_current_status; 878 879 usbd_xfer_set_frame_len(xfer, 0, sizeof(*sc->sc_csw)); 880 usbd_transfer_submit(xfer); 881 break; 882 883 default: 884 if (usb_error == USB_ERR_CANCELLED) { 885 CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED"); 886 break; 887 } 888 889 CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s", 890 usbd_errstr(usb_error)); 891 892 goto tr_setup; 893 } 894} 895 896static void 897cfumass_online(void *arg __unused) 898{ 899 900 cfumass_port_online = true; 901} 902 903static void 904cfumass_offline(void *arg __unused) 905{ 906 907 cfumass_port_online = false; 908} 909 910static void 911cfumass_datamove(union ctl_io *io) 912{ 913 struct cfumass_softc *sc; 914 915 sc = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr; 916 917 CFUMASS_DEBUG(sc, "go"); 918 919 CFUMASS_LOCK(sc); 920 921 KASSERT(sc->sc_ctl_io == NULL, 922 ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io)); 923 sc->sc_ctl_io = io; 924 925 if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_IN) { 926 /* 927 * Verify that CTL wants us to send the data in the direction 928 * expected by the initiator. 929 */ 930 if (sc->sc_current_flags != CBWFLAGS_IN) { 931 CFUMASS_WARN(sc, "wrong bCBWFlags 0x%x, should be 0x%x", 932 sc->sc_current_flags, CBWFLAGS_IN); 933 goto fail; 934 } 935 936 cfumass_transfer_start(sc, CFUMASS_T_DATA_IN); 937 } else { 938 if (sc->sc_current_flags != CBWFLAGS_OUT) { 939 CFUMASS_WARN(sc, "wrong bCBWFlags 0x%x, should be 0x%x", 940 sc->sc_current_flags, CBWFLAGS_OUT); 941 goto fail; 942 } 943 944 cfumass_transfer_start(sc, CFUMASS_T_DATA_OUT); 945 } 946 947 CFUMASS_UNLOCK(sc); 948 return; 949 950fail: 951 ctl_set_data_phase_error(&io->scsiio); 952 io->scsiio.be_move_done(io); 953 sc->sc_ctl_io = NULL; 954} 955 956static void 957cfumass_done(union ctl_io *io) 958{ 959 struct cfumass_softc *sc; 960 961 sc = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr; 962 963 CFUMASS_DEBUG(sc, "go"); 964 965 KASSERT(((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE), 966 ("invalid CTL status %#x", io->io_hdr.status)); 967 KASSERT(sc->sc_ctl_io == NULL, 968 ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io)); 969 970 if (io->io_hdr.io_type == CTL_IO_TASK && 971 io->taskio.task_action == CTL_TASK_I_T_NEXUS_RESET) { 972 /* 973 * Implicit task termination has just completed; nothing to do. 974 */ 975 ctl_free_io(io); 976 return; 977 } 978 979 /* 980 * Do not return status for aborted commands. 981 * There are exceptions, but none supported by CTL yet. 982 */ 983 if (((io->io_hdr.flags & CTL_FLAG_ABORT) && 984 (io->io_hdr.flags & CTL_FLAG_ABORT_STATUS) == 0) || 985 (io->io_hdr.flags & CTL_FLAG_STATUS_SENT)) { 986 ctl_free_io(io); 987 return; 988 } 989 990 switch (io->scsiio.scsi_status) { 991 case SCSI_STATUS_OK: 992 sc->sc_current_status = 0; 993 break; 994 default: 995 sc->sc_current_status = 1; 996 break; 997 } 998 999 CFUMASS_LOCK(sc); 1000 cfumass_transfer_start(sc, CFUMASS_T_STATUS); 1001 CFUMASS_UNLOCK(sc); 1002 ctl_free_io(io); 1003 1004 refcount_release(&sc->sc_queued); 1005} 1006 1007int 1008cfumass_init(void) 1009{ 1010 int error; 1011 1012 cfumass_port.frontend = &cfumass_frontend; 1013 cfumass_port.port_type = CTL_PORT_UMASS; 1014 cfumass_port.num_requested_ctl_io = 1; 1015 cfumass_port.port_name = "cfumass"; 1016 cfumass_port.physical_port = 0; 1017 cfumass_port.virtual_port = 0; 1018 cfumass_port.port_online = cfumass_online; 1019 cfumass_port.port_offline = cfumass_offline; 1020 cfumass_port.onoff_arg = NULL; 1021 cfumass_port.fe_datamove = cfumass_datamove; 1022 cfumass_port.fe_done = cfumass_done; 1023 cfumass_port.targ_port = -1; 1024 1025 error = ctl_port_register(&cfumass_port); 1026 if (error != 0) { 1027 printf("%s: ctl_port_register() failed " 1028 "with error %d", __func__, error); 1029 } 1030 1031 cfumass_port_online = true; 1032 refcount_init(&cfumass_refcount, 0); 1033 1034 return (error); 1035} 1036 1037int 1038cfumass_shutdown(void) 1039{ 1040 int error; 1041 1042 if (cfumass_refcount > 0) { 1043 if (debug > 1) { 1044 printf("%s: still have %u attachments; " 1045 "returning EBUSY\n", __func__, cfumass_refcount); 1046 } 1047 return (EBUSY); 1048 } 1049 1050 error = ctl_port_deregister(&cfumass_port); 1051 if (error != 0) { 1052 printf("%s: ctl_port_deregister() failed " 1053 "with error %d\n", __func__, error); 1054 } 1055 1056 return (error); 1057} 1058