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