cfumass.c revision 316660
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 316660 2017-04-09 19:30:49Z trasz $"); 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 724 CFUMASS_DEBUG(sc, "go"); 725 726 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 727 728 io = sc->sc_ctl_io; 729 730 if (io->scsiio.kern_sg_entries > 0) { 731 ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr; 732 ctl_sg_count = io->scsiio.kern_sg_entries; 733 } else { 734 ctl_sglist = &ctl_sg_entry; 735 ctl_sglist->addr = io->scsiio.kern_data_ptr; 736 ctl_sglist->len = io->scsiio.kern_data_len; 737 ctl_sg_count = 1; 738 } 739 740 switch (USB_GET_STATE(xfer)) { 741 case USB_ST_TRANSFERRED: 742 CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED"); 743 744 /* 745 * If the host sent less data than required, zero-out 746 * the remaining buffer space, to prevent a malicious host 747 * to writing uninitialized kernel memory to the disk. 748 */ 749 if (actlen != ctl_sglist[0].len) { 750 KASSERT(actlen <= ctl_sglist[0].len, 751 ("actlen %d > ctl_sglist.len %zd", 752 actlen, ctl_sglist[0].len)); 753 754 CFUMASS_DEBUG(sc, "host transferred %d bytes" 755 "instead of expected %zd bytes", 756 actlen, ctl_sglist[0].len); 757 758 memset((char *)(ctl_sglist[0].addr) + actlen, 0, 759 ctl_sglist[0].len - actlen); 760 } 761 762 sc->sc_current_residue = 0; 763 io->scsiio.be_move_done(io); 764 sc->sc_ctl_io = NULL; 765 break; 766 767 case USB_ST_SETUP: 768tr_setup: 769 CFUMASS_DEBUG(sc, "USB_ST_SETUP"); 770 771 CFUMASS_DEBUG(sc, "requested size %d, CTL segment size %zd", 772 sc->sc_current_transfer_length, ctl_sglist[0].len); 773 774 usbd_xfer_set_frame_data(xfer, 0, ctl_sglist[0].addr, ctl_sglist[0].len); 775 usbd_transfer_submit(xfer); 776 break; 777 778 default: 779 if (usb_error == USB_ERR_CANCELLED) { 780 CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED"); 781 break; 782 } 783 784 CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s", 785 usbd_errstr(usb_error)); 786 787 goto tr_setup; 788 } 789} 790 791static void 792cfumass_t_data_in_callback(struct usb_xfer *xfer, usb_error_t usb_error) 793{ 794 struct cfumass_softc *sc; 795 union ctl_io *io; 796 uint32_t max_bulk; 797 struct ctl_sg_entry ctl_sg_entry, *ctl_sglist; 798 int ctl_sg_count; 799 800 sc = usbd_xfer_softc(xfer); 801 max_bulk = usbd_xfer_max_len(xfer); 802 803 io = sc->sc_ctl_io; 804 805 switch (USB_GET_STATE(xfer)) { 806 case USB_ST_TRANSFERRED: 807 CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED"); 808 809 io->scsiio.be_move_done(io); 810 sc->sc_ctl_io = NULL; 811 break; 812 813 case USB_ST_SETUP: 814tr_setup: 815 CFUMASS_DEBUG(sc, "USB_ST_SETUP"); 816 817 if (io->scsiio.kern_sg_entries > 0) { 818 ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr; 819 ctl_sg_count = io->scsiio.kern_sg_entries; 820 } else { 821 ctl_sglist = &ctl_sg_entry; 822 ctl_sglist->addr = io->scsiio.kern_data_ptr; 823 ctl_sglist->len = io->scsiio.kern_data_len; 824 ctl_sg_count = 1; 825 } 826 827 if (sc->sc_current_transfer_length > io->scsiio.kern_total_len) { 828 CFUMASS_DEBUG(sc, "initiator requested %d bytes, " 829 "we will send %ju and stall", 830 sc->sc_current_transfer_length, 831 (uintmax_t)io->scsiio.kern_total_len); 832 sc->sc_current_residue = sc->sc_current_transfer_length - 833 io->scsiio.kern_total_len; 834 } else { 835 sc->sc_current_residue = 0; 836 } 837 838 CFUMASS_DEBUG(sc, "max_bulk %d, requested size %d, " 839 "CTL segment size %zd", max_bulk, 840 sc->sc_current_transfer_length, ctl_sglist[0].len); 841 842 if (max_bulk >= ctl_sglist[0].len) 843 max_bulk = ctl_sglist[0].len; 844 845 usbd_xfer_set_frame_data(xfer, 0, ctl_sglist[0].addr, max_bulk); 846 usbd_transfer_submit(xfer); 847 848 break; 849 850 default: 851 if (usb_error == USB_ERR_CANCELLED) { 852 CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED"); 853 break; 854 } 855 856 CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s", usbd_errstr(usb_error)); 857 858 goto tr_setup; 859 } 860} 861 862static void 863cfumass_t_status_callback(struct usb_xfer *xfer, usb_error_t usb_error) 864{ 865 struct cfumass_softc *sc; 866 867 sc = usbd_xfer_softc(xfer); 868 869 KASSERT(sc->sc_ctl_io == NULL, 870 ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io)); 871 872 switch (USB_GET_STATE(xfer)) { 873 case USB_ST_TRANSFERRED: 874 CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED"); 875 876 cfumass_transfer_start(sc, CFUMASS_T_COMMAND); 877 break; 878 879 case USB_ST_SETUP: 880tr_setup: 881 CFUMASS_DEBUG(sc, "USB_ST_SETUP"); 882 883 if (sc->sc_current_residue > 0 && !sc->sc_current_stalled) { 884 CFUMASS_DEBUG(sc, "non-zero residue, stalling"); 885 usbd_xfer_set_stall(xfer); 886 sc->sc_current_stalled = true; 887 } 888 889 USETDW(sc->sc_csw->dCSWSignature, CSWSIGNATURE); 890 USETDW(sc->sc_csw->dCSWTag, sc->sc_current_tag); 891 USETDW(sc->sc_csw->dCSWDataResidue, sc->sc_current_residue); 892 sc->sc_csw->bCSWStatus = sc->sc_current_status; 893 894 usbd_xfer_set_frame_len(xfer, 0, sizeof(*sc->sc_csw)); 895 usbd_transfer_submit(xfer); 896 break; 897 898 default: 899 if (usb_error == USB_ERR_CANCELLED) { 900 CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED"); 901 break; 902 } 903 904 CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s", 905 usbd_errstr(usb_error)); 906 907 goto tr_setup; 908 } 909} 910 911static void 912cfumass_online(void *arg __unused) 913{ 914 915 cfumass_port_online = true; 916} 917 918static void 919cfumass_offline(void *arg __unused) 920{ 921 922 cfumass_port_online = false; 923} 924 925static void 926cfumass_datamove(union ctl_io *io) 927{ 928 struct cfumass_softc *sc; 929 930 sc = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr; 931 932 CFUMASS_DEBUG(sc, "go"); 933 934 CFUMASS_LOCK(sc); 935 936 KASSERT(sc->sc_ctl_io == NULL, 937 ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io)); 938 sc->sc_ctl_io = io; 939 940 if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_IN) { 941 /* 942 * Verify that CTL wants us to send the data in the direction 943 * expected by the initiator. 944 */ 945 if (sc->sc_current_flags != CBWFLAGS_IN) { 946 CFUMASS_WARN(sc, "wrong bCBWFlags 0x%x, should be 0x%x", 947 sc->sc_current_flags, CBWFLAGS_IN); 948 goto fail; 949 } 950 951 cfumass_transfer_start(sc, CFUMASS_T_DATA_IN); 952 } else { 953 if (sc->sc_current_flags != CBWFLAGS_OUT) { 954 CFUMASS_WARN(sc, "wrong bCBWFlags 0x%x, should be 0x%x", 955 sc->sc_current_flags, CBWFLAGS_OUT); 956 goto fail; 957 } 958 959 /* We hadn't received anything during this datamove yet. */ 960 io->scsiio.ext_data_filled = 0; 961 cfumass_transfer_start(sc, CFUMASS_T_DATA_OUT); 962 } 963 964 CFUMASS_UNLOCK(sc); 965 return; 966 967fail: 968 ctl_set_data_phase_error(&io->scsiio); 969 io->scsiio.be_move_done(io); 970 sc->sc_ctl_io = NULL; 971} 972 973static void 974cfumass_done(union ctl_io *io) 975{ 976 struct cfumass_softc *sc; 977 978 sc = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr; 979 980 CFUMASS_DEBUG(sc, "go"); 981 982 KASSERT(((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE), 983 ("invalid CTL status %#x", io->io_hdr.status)); 984 KASSERT(sc->sc_ctl_io == NULL, 985 ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io)); 986 987 if (io->io_hdr.io_type == CTL_IO_TASK && 988 io->taskio.task_action == CTL_TASK_I_T_NEXUS_RESET) { 989 /* 990 * Implicit task termination has just completed; nothing to do. 991 */ 992 ctl_free_io(io); 993 return; 994 } 995 996 /* 997 * Do not return status for aborted commands. 998 * There are exceptions, but none supported by CTL yet. 999 */ 1000 if (((io->io_hdr.flags & CTL_FLAG_ABORT) && 1001 (io->io_hdr.flags & CTL_FLAG_ABORT_STATUS) == 0) || 1002 (io->io_hdr.flags & CTL_FLAG_STATUS_SENT)) { 1003 ctl_free_io(io); 1004 return; 1005 } 1006 1007 switch (io->scsiio.scsi_status) { 1008 case SCSI_STATUS_OK: 1009 sc->sc_current_status = 0; 1010 break; 1011 default: 1012 sc->sc_current_status = 1; 1013 break; 1014 } 1015 1016 CFUMASS_LOCK(sc); 1017 cfumass_transfer_start(sc, CFUMASS_T_STATUS); 1018 CFUMASS_UNLOCK(sc); 1019 ctl_free_io(io); 1020 1021 refcount_release(&sc->sc_queued); 1022} 1023 1024int 1025cfumass_init(void) 1026{ 1027 int error; 1028 1029 cfumass_port.frontend = &cfumass_frontend; 1030 cfumass_port.port_type = CTL_PORT_UMASS; 1031 /* XXX KDM what should the real number be here? */ 1032 cfumass_port.num_requested_ctl_io = 4096; 1033 cfumass_port.port_name = "cfumass"; 1034 cfumass_port.physical_port = 0; 1035 cfumass_port.virtual_port = 0; 1036 cfumass_port.port_online = cfumass_online; 1037 cfumass_port.port_offline = cfumass_offline; 1038 cfumass_port.onoff_arg = NULL; 1039 cfumass_port.fe_datamove = cfumass_datamove; 1040 cfumass_port.fe_done = cfumass_done; 1041 cfumass_port.targ_port = -1; 1042 1043 error = ctl_port_register(&cfumass_port); 1044 if (error != 0) { 1045 printf("%s: ctl_port_register() failed " 1046 "with error %d", __func__, error); 1047 } 1048 1049 cfumass_port_online = true; 1050 refcount_init(&cfumass_refcount, 0); 1051 1052 return (error); 1053} 1054 1055int 1056cfumass_shutdown(void) 1057{ 1058 int error; 1059 1060 if (cfumass_refcount > 0) { 1061 if (debug > 1) { 1062 printf("%s: still have %u attachments; " 1063 "returning EBUSY\n", __func__, cfumass_refcount); 1064 } 1065 return (EBUSY); 1066 } 1067 1068 error = ctl_port_deregister(&cfumass_port); 1069 if (error != 0) { 1070 printf("%s: ctl_port_deregister() failed " 1071 "with error %d\n", __func__, error); 1072 } 1073 1074 return (error); 1075} 1076