2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2016 The FreeBSD Foundation
7 * This software was developed by Edward Tomasz Napierala under sponsorship
8 * from the FreeBSD Foundation.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * USB Mass Storage Class Bulk-Only (BBB) Transport target.
35 * http://www.usb.org/developers/docs/devclass_docs/usbmassbulk_10.pdf
37 * This code implements the USB Mass Storage frontend driver for the CAM
38 * Target Layer (ctl(4)) subsystem.
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD$");
44 #include <sys/param.h>
46 #include <sys/kernel.h>
48 #include <sys/module.h>
49 #include <sys/mutex.h>
50 #include <sys/refcount.h>
51 #include <sys/stdint.h>
52 #include <sys/sysctl.h>
53 #include <sys/systm.h>
55 #include <dev/usb/usb.h>
56 #include <dev/usb/usbdi.h>
60 #include <cam/scsi/scsi_all.h>
61 #include <cam/scsi/scsi_da.h>
62 #include <cam/ctl/ctl_io.h>
63 #include <cam/ctl/ctl.h>
64 #include <cam/ctl/ctl_backend.h>
65 #include <cam/ctl/ctl_error.h>
66 #include <cam/ctl/ctl_frontend.h>
67 #include <cam/ctl/ctl_debug.h>
68 #include <cam/ctl/ctl_ha.h>
69 #include <cam/ctl/ctl_ioctl.h>
70 #include <cam/ctl/ctl_private.h>
72 SYSCTL_NODE(_hw_usb, OID_AUTO, cfumass, CTLFLAG_RW, 0,
73 "CAM Target Layer USB Mass Storage Frontend");
75 SYSCTL_INT(_hw_usb_cfumass, OID_AUTO, debug, CTLFLAG_RWTUN,
76 &debug, 1, "Enable debug messages");
77 static int max_lun = 0;
78 SYSCTL_INT(_hw_usb_cfumass, OID_AUTO, max_lun, CTLFLAG_RWTUN,
79 &max_lun, 1, "Maximum advertised LUN number");
80 static int ignore_stop = 1;
81 SYSCTL_INT(_hw_usb_cfumass, OID_AUTO, ignore_stop, CTLFLAG_RWTUN,
82 &ignore_stop, 1, "Ignore START STOP UNIT with START and LOEJ bits cleared");
85 * The driver uses a single, global CTL port. It could create its ports
86 * in cfumass_attach() instead, but that would make it impossible to specify
87 * "port cfumass0" in ctl.conf(5), as the port generally wouldn't exist
88 * at the time ctld(8) gets run.
90 struct ctl_port cfumass_port;
91 bool cfumass_port_online;
92 volatile u_int cfumass_refcount;
94 #ifndef CFUMASS_BULK_SIZE
95 #define CFUMASS_BULK_SIZE (1U << 17) /* bytes */
99 * USB transfer definitions.
101 #define CFUMASS_T_COMMAND 0
102 #define CFUMASS_T_DATA_OUT 1
103 #define CFUMASS_T_DATA_IN 2
104 #define CFUMASS_T_STATUS 3
105 #define CFUMASS_T_MAX 4
108 * USB interface specific control requests.
110 #define UR_RESET 0xff /* Bulk-Only Mass Storage Reset */
111 #define UR_GET_MAX_LUN 0xfe /* Get Max LUN */
114 * Command Block Wrapper.
116 struct cfumass_cbw_t {
117 uDWord dCBWSignature;
118 #define CBWSIGNATURE 0x43425355 /* "USBC" */
120 uDWord dCBWDataTransferLength;
122 #define CBWFLAGS_OUT 0x00
123 #define CBWFLAGS_IN 0x80
126 #define CBWCBLENGTH 16
127 uByte CBWCB[CBWCBLENGTH];
130 #define CFUMASS_CBW_SIZE 31
131 CTASSERT(sizeof(struct cfumass_cbw_t) == CFUMASS_CBW_SIZE);
134 * Command Status Wrapper.
136 struct cfumass_csw_t {
137 uDWord dCSWSignature;
138 #define CSWSIGNATURE 0x53425355 /* "USBS" */
140 uDWord dCSWDataResidue;
142 #define CSWSTATUS_GOOD 0x0
143 #define CSWSTATUS_FAILED 0x1
144 #define CSWSTATUS_PHASE 0x2
147 #define CFUMASS_CSW_SIZE 13
148 CTASSERT(sizeof(struct cfumass_csw_t) == CFUMASS_CSW_SIZE);
150 struct cfumass_softc {
152 struct usb_device *sc_udev;
153 struct usb_xfer *sc_xfer[CFUMASS_T_MAX];
155 struct cfumass_cbw_t *sc_cbw;
156 struct cfumass_csw_t *sc_csw;
163 * This is used to communicate between CTL callbacks
164 * and USB callbacks; basically, it holds the state
165 * for the current command ("the" command, since there
166 * is no queueing in USB Mass Storage).
168 bool sc_current_stalled;
171 * The following are set upon receiving a SCSI command.
174 int sc_current_transfer_length;
175 int sc_current_flags;
178 * The following are set in ctl_datamove().
180 int sc_current_residue;
181 union ctl_io *sc_ctl_io;
184 * The following is set in cfumass_done().
186 int sc_current_status;
189 * Number of requests queued to CTL.
191 volatile u_int sc_queued;
197 static device_probe_t cfumass_probe;
198 static device_attach_t cfumass_attach;
199 static device_detach_t cfumass_detach;
200 static device_suspend_t cfumass_suspend;
201 static device_resume_t cfumass_resume;
202 static usb_handle_request_t cfumass_handle_request;
204 static usb_callback_t cfumass_t_command_callback;
205 static usb_callback_t cfumass_t_data_callback;
206 static usb_callback_t cfumass_t_status_callback;
208 static device_method_t cfumass_methods[] = {
211 DEVMETHOD(usb_handle_request, cfumass_handle_request),
213 /* Device interface. */
214 DEVMETHOD(device_probe, cfumass_probe),
215 DEVMETHOD(device_attach, cfumass_attach),
216 DEVMETHOD(device_detach, cfumass_detach),
217 DEVMETHOD(device_suspend, cfumass_suspend),
218 DEVMETHOD(device_resume, cfumass_resume),
223 static driver_t cfumass_driver = {
225 .methods = cfumass_methods,
226 .size = sizeof(struct cfumass_softc),
229 static devclass_t cfumass_devclass;
231 DRIVER_MODULE(cfumass, uhub, cfumass_driver, cfumass_devclass, NULL, 0);
232 MODULE_VERSION(cfumass, 0);
233 MODULE_DEPEND(cfumass, usb, 1, 1, 1);
234 MODULE_DEPEND(cfumass, usb_template, 1, 1, 1);
236 static struct usb_config cfumass_config[CFUMASS_T_MAX] = {
238 [CFUMASS_T_COMMAND] = {
240 .endpoint = UE_ADDR_ANY,
241 .direction = UE_DIR_OUT,
242 .bufsize = sizeof(struct cfumass_cbw_t),
243 .callback = &cfumass_t_command_callback,
244 .usb_mode = USB_MODE_DEVICE,
247 [CFUMASS_T_DATA_OUT] = {
249 .endpoint = UE_ADDR_ANY,
250 .direction = UE_DIR_OUT,
251 .bufsize = CFUMASS_BULK_SIZE,
252 .flags = {.proxy_buffer = 1, .short_xfer_ok = 1,
254 .callback = &cfumass_t_data_callback,
255 .usb_mode = USB_MODE_DEVICE,
258 [CFUMASS_T_DATA_IN] = {
260 .endpoint = UE_ADDR_ANY,
261 .direction = UE_DIR_IN,
262 .bufsize = CFUMASS_BULK_SIZE,
263 .flags = {.proxy_buffer = 1, .short_xfer_ok = 1,
265 .callback = &cfumass_t_data_callback,
266 .usb_mode = USB_MODE_DEVICE,
269 [CFUMASS_T_STATUS] = {
271 .endpoint = UE_ADDR_ANY,
272 .direction = UE_DIR_IN,
273 .bufsize = sizeof(struct cfumass_csw_t),
274 .flags = {.short_xfer_ok = 1},
275 .callback = &cfumass_t_status_callback,
276 .usb_mode = USB_MODE_DEVICE,
281 * CTL frontend interface.
283 static int cfumass_init(void);
284 static int cfumass_shutdown(void);
285 static void cfumass_online(void *arg);
286 static void cfumass_offline(void *arg);
287 static void cfumass_datamove(union ctl_io *io);
288 static void cfumass_done(union ctl_io *io);
290 static struct ctl_frontend cfumass_frontend = {
292 .init = cfumass_init,
293 .shutdown = cfumass_shutdown,
295 CTL_FRONTEND_DECLARE(ctlcfumass, cfumass_frontend);
297 #define CFUMASS_DEBUG(S, X, ...) \
300 device_printf(S->sc_dev, "%s: " X "\n", \
301 __func__, ## __VA_ARGS__); \
305 #define CFUMASS_WARN(S, X, ...) \
308 device_printf(S->sc_dev, "WARNING: %s: " X "\n",\
309 __func__, ## __VA_ARGS__); \
313 #define CFUMASS_LOCK(X) mtx_lock(&X->sc_mtx)
314 #define CFUMASS_UNLOCK(X) mtx_unlock(&X->sc_mtx)
316 static void cfumass_transfer_start(struct cfumass_softc *sc,
318 static void cfumass_terminate(struct cfumass_softc *sc);
321 cfumass_probe(device_t dev)
323 struct usb_attach_arg *uaa;
324 struct usb_interface_descriptor *id;
326 uaa = device_get_ivars(dev);
328 if (uaa->usb_mode != USB_MODE_DEVICE)
332 * Check for a compliant device.
334 id = usbd_get_interface_descriptor(uaa->iface);
336 (id->bInterfaceClass != UICLASS_MASS) ||
337 (id->bInterfaceSubClass != UISUBCLASS_SCSI) ||
338 (id->bInterfaceProtocol != UIPROTO_MASS_BBB)) {
342 return (BUS_PROBE_GENERIC);
346 cfumass_attach(device_t dev)
348 struct cfumass_softc *sc;
349 struct usb_attach_arg *uaa;
352 sc = device_get_softc(dev);
353 uaa = device_get_ivars(dev);
356 sc->sc_udev = uaa->device;
358 CFUMASS_DEBUG(sc, "go");
360 usbd_set_power_mode(uaa->device, USB_POWER_MODE_SAVE);
361 device_set_usb_desc(dev);
363 mtx_init(&sc->sc_mtx, "cfumass", NULL, MTX_DEF);
364 refcount_acquire(&cfumass_refcount);
366 error = usbd_transfer_setup(uaa->device,
367 &uaa->info.bIfaceIndex, sc->sc_xfer, cfumass_config,
368 CFUMASS_T_MAX, sc, &sc->sc_mtx);
370 CFUMASS_WARN(sc, "usbd_transfer_setup() failed: %s",
372 refcount_release(&cfumass_refcount);
377 usbd_xfer_get_frame_buffer(sc->sc_xfer[CFUMASS_T_COMMAND], 0);
379 usbd_xfer_get_frame_buffer(sc->sc_xfer[CFUMASS_T_STATUS], 0);
381 sc->sc_ctl_initid = ctl_add_initiator(&cfumass_port, -1, 0, NULL);
382 if (sc->sc_ctl_initid < 0) {
383 CFUMASS_WARN(sc, "ctl_add_initiator() failed with error %d",
385 usbd_transfer_unsetup(sc->sc_xfer, CFUMASS_T_MAX);
386 refcount_release(&cfumass_refcount);
390 refcount_init(&sc->sc_queued, 0);
393 cfumass_transfer_start(sc, CFUMASS_T_COMMAND);
400 cfumass_detach(device_t dev)
402 struct cfumass_softc *sc;
405 sc = device_get_softc(dev);
407 CFUMASS_DEBUG(sc, "go");
410 cfumass_terminate(sc);
412 usbd_transfer_unsetup(sc->sc_xfer, CFUMASS_T_MAX);
414 if (sc->sc_ctl_initid != -1) {
415 error = ctl_remove_initiator(&cfumass_port, sc->sc_ctl_initid);
417 CFUMASS_WARN(sc, "ctl_remove_initiator() failed "
418 "with error %d", error);
420 sc->sc_ctl_initid = -1;
423 mtx_destroy(&sc->sc_mtx);
424 refcount_release(&cfumass_refcount);
430 cfumass_suspend(device_t dev)
432 struct cfumass_softc *sc;
434 sc = device_get_softc(dev);
435 CFUMASS_DEBUG(sc, "go");
441 cfumass_resume(device_t dev)
443 struct cfumass_softc *sc;
445 sc = device_get_softc(dev);
446 CFUMASS_DEBUG(sc, "go");
452 cfumass_transfer_start(struct cfumass_softc *sc, uint8_t xfer_index)
455 usbd_transfer_start(sc->sc_xfer[xfer_index]);
459 cfumass_transfer_stop_and_drain(struct cfumass_softc *sc, uint8_t xfer_index)
462 usbd_transfer_stop(sc->sc_xfer[xfer_index]);
464 usbd_transfer_drain(sc->sc_xfer[xfer_index]);
469 cfumass_terminate(struct cfumass_softc *sc)
474 cfumass_transfer_stop_and_drain(sc, CFUMASS_T_COMMAND);
475 cfumass_transfer_stop_and_drain(sc, CFUMASS_T_DATA_IN);
476 cfumass_transfer_stop_and_drain(sc, CFUMASS_T_DATA_OUT);
478 if (sc->sc_ctl_io != NULL) {
479 CFUMASS_DEBUG(sc, "terminating CTL transfer");
480 ctl_set_data_phase_error(&sc->sc_ctl_io->scsiio);
481 sc->sc_ctl_io->scsiio.be_move_done(sc->sc_ctl_io);
482 sc->sc_ctl_io = NULL;
485 cfumass_transfer_stop_and_drain(sc, CFUMASS_T_STATUS);
487 refcount_acquire(&sc->sc_queued);
488 last = refcount_release(&sc->sc_queued);
492 CFUMASS_DEBUG(sc, "%d CTL tasks pending", sc->sc_queued);
493 msleep(__DEVOLATILE(void *, &sc->sc_queued), &sc->sc_mtx,
494 0, "cfumass_reset", hz / 100);
499 cfumass_handle_request(device_t dev,
500 const void *preq, void **pptr, uint16_t *plen,
501 uint16_t offset, uint8_t *pstate)
503 static uint8_t max_lun_tmp;
504 struct cfumass_softc *sc;
505 const struct usb_device_request *req;
508 sc = device_get_softc(dev);
510 is_complete = *pstate;
512 CFUMASS_DEBUG(sc, "go");
517 if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
518 (req->bRequest == UR_RESET)) {
519 CFUMASS_WARN(sc, "received Bulk-Only Mass Storage Reset");
523 cfumass_terminate(sc);
524 cfumass_transfer_start(sc, CFUMASS_T_COMMAND);
527 CFUMASS_DEBUG(sc, "Bulk-Only Mass Storage Reset done");
531 if ((req->bmRequestType == UT_READ_CLASS_INTERFACE) &&
532 (req->bRequest == UR_GET_MAX_LUN)) {
533 CFUMASS_DEBUG(sc, "received Get Max LUN");
537 * The protocol doesn't support LUN numbers higher
538 * than 15. Also, some initiators (namely Windows XP
539 * SP3 Version 2002) can't properly query the number
540 * of LUNs, resulting in inaccessible "fake" ones - thus
541 * the default limit of one LUN.
543 if (max_lun < 0 || max_lun > 15) {
545 "invalid hw.usb.cfumass.max_lun, must be "
546 "between 0 and 15; defaulting to 0");
549 max_lun_tmp = max_lun;
551 *pptr = &max_lun_tmp;
562 cfumass_quirk(struct cfumass_softc *sc, unsigned char *cdb, int cdb_len)
564 struct scsi_start_stop_unit *sssu;
567 case START_STOP_UNIT:
569 * Some initiators - eg OSX, Darwin Kernel Version 15.6.0,
570 * root:xnu-3248.60.11~2/RELEASE_X86_64 - attempt to stop
571 * the unit on eject, but fail to start it when it's plugged
572 * back. Just ignore the command.
575 if (cdb_len < sizeof(*sssu)) {
576 CFUMASS_DEBUG(sc, "received START STOP UNIT with "
577 "bCDBLength %d, should be %zd",
578 cdb_len, sizeof(*sssu));
582 sssu = (struct scsi_start_stop_unit *)cdb;
583 if ((sssu->how & SSS_PC_MASK) != 0)
586 if ((sssu->how & SSS_START) != 0)
589 if ((sssu->how & SSS_LOEJ) != 0)
592 if (ignore_stop == 0) {
594 } else if (ignore_stop == 1) {
595 CFUMASS_WARN(sc, "ignoring START STOP UNIT request");
597 CFUMASS_DEBUG(sc, "ignoring START STOP UNIT request");
600 sc->sc_current_status = 0;
601 cfumass_transfer_start(sc, CFUMASS_T_STATUS);
612 cfumass_t_command_callback(struct usb_xfer *xfer, usb_error_t usb_error)
614 struct cfumass_softc *sc;
619 sc = usbd_xfer_softc(xfer);
621 KASSERT(sc->sc_ctl_io == NULL,
622 ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io));
624 switch (USB_GET_STATE(xfer)) {
625 case USB_ST_TRANSFERRED:
626 CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED");
628 signature = UGETDW(sc->sc_cbw->dCBWSignature);
629 if (signature != CBWSIGNATURE) {
630 CFUMASS_WARN(sc, "wrong dCBWSignature 0x%08x, "
631 "should be 0x%08x", signature, CBWSIGNATURE);
635 if (sc->sc_cbw->bCDBLength <= 0 ||
636 sc->sc_cbw->bCDBLength > sizeof(sc->sc_cbw->CBWCB)) {
637 CFUMASS_WARN(sc, "invalid bCDBLength %d, should be <= %zd",
638 sc->sc_cbw->bCDBLength, sizeof(sc->sc_cbw->CBWCB));
642 sc->sc_current_stalled = false;
643 sc->sc_current_status = 0;
644 sc->sc_current_tag = UGETDW(sc->sc_cbw->dCBWTag);
645 sc->sc_current_transfer_length =
646 UGETDW(sc->sc_cbw->dCBWDataTransferLength);
647 sc->sc_current_flags = sc->sc_cbw->bCBWFlags;
650 * Make sure to report proper residue if the datamove wasn't
651 * required, or wasn't called due to SCSI error.
653 sc->sc_current_residue = sc->sc_current_transfer_length;
655 if (cfumass_quirk(sc,
656 sc->sc_cbw->CBWCB, sc->sc_cbw->bCDBLength) != 0)
659 if (!cfumass_port_online) {
660 CFUMASS_DEBUG(sc, "cfumass port is offline; stalling");
661 usbd_xfer_set_stall(xfer);
666 * Those CTL functions cannot be called with mutex held.
669 io = ctl_alloc_io(cfumass_port.ctl_pool_ref);
671 io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = sc;
672 io->io_hdr.io_type = CTL_IO_SCSI;
673 io->io_hdr.nexus.initid = sc->sc_ctl_initid;
674 io->io_hdr.nexus.targ_port = cfumass_port.targ_port;
675 io->io_hdr.nexus.targ_lun = ctl_decode_lun(sc->sc_cbw->bCBWLUN);
676 io->scsiio.tag_num = UGETDW(sc->sc_cbw->dCBWTag);
677 io->scsiio.tag_type = CTL_TAG_UNTAGGED;
678 io->scsiio.cdb_len = sc->sc_cbw->bCDBLength;
679 memcpy(io->scsiio.cdb, sc->sc_cbw->CBWCB, sc->sc_cbw->bCDBLength);
680 refcount_acquire(&sc->sc_queued);
681 error = ctl_queue(io);
682 if (error != CTL_RETVAL_COMPLETE) {
684 "ctl_queue() failed; error %d; stalling", error);
686 refcount_release(&sc->sc_queued);
688 usbd_xfer_set_stall(xfer);
697 CFUMASS_DEBUG(sc, "USB_ST_SETUP");
699 usbd_xfer_set_frame_len(xfer, 0, sizeof(*sc->sc_cbw));
700 usbd_transfer_submit(xfer);
704 if (usb_error == USB_ERR_CANCELLED) {
705 CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED");
709 CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s", usbd_errstr(usb_error));
716 cfumass_t_data_callback(struct usb_xfer *xfer, usb_error_t usb_error)
718 struct cfumass_softc *sc = usbd_xfer_softc(xfer);
719 union ctl_io *io = sc->sc_ctl_io;
721 struct ctl_sg_entry sg_entry, *sglist;
722 int actlen, sumlen, sg_count;
724 switch (USB_GET_STATE(xfer)) {
725 case USB_ST_TRANSFERRED:
726 CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED");
728 usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
729 sc->sc_current_residue -= actlen;
730 io->scsiio.ext_data_filled += actlen;
731 io->scsiio.kern_data_resid -= actlen;
732 if (actlen < sumlen ||
733 sc->sc_current_residue == 0 ||
734 io->scsiio.kern_data_resid == 0) {
735 sc->sc_ctl_io = NULL;
736 io->scsiio.be_move_done(io);
743 CFUMASS_DEBUG(sc, "USB_ST_SETUP");
745 if (io->scsiio.kern_sg_entries > 0) {
746 sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr;
747 sg_count = io->scsiio.kern_sg_entries;
750 sglist->addr = io->scsiio.kern_data_ptr;
751 sglist->len = io->scsiio.kern_data_len;
755 sumlen = io->scsiio.ext_data_filled -
756 io->scsiio.kern_rel_offset;
757 while (sumlen >= sglist->len && sg_count > 0) {
758 sumlen -= sglist->len;
762 KASSERT(sg_count > 0, ("Run out of S/G list entries"));
764 max_bulk = usbd_xfer_max_len(xfer);
765 actlen = min(sglist->len - sumlen, max_bulk);
766 actlen = min(actlen, sc->sc_current_transfer_length -
767 io->scsiio.ext_data_filled);
768 CFUMASS_DEBUG(sc, "requested %d, done %d, max_bulk %d, "
769 "segment %zd => transfer %d",
770 sc->sc_current_transfer_length, io->scsiio.ext_data_filled,
771 max_bulk, sglist->len - sumlen, actlen);
773 usbd_xfer_set_frame_data(xfer, 0,
774 (uint8_t *)sglist->addr + sumlen, actlen);
775 usbd_transfer_submit(xfer);
779 if (usb_error == USB_ERR_CANCELLED) {
780 CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED");
783 CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s", usbd_errstr(usb_error));
789 cfumass_t_status_callback(struct usb_xfer *xfer, usb_error_t usb_error)
791 struct cfumass_softc *sc;
793 sc = usbd_xfer_softc(xfer);
795 KASSERT(sc->sc_ctl_io == NULL,
796 ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io));
798 switch (USB_GET_STATE(xfer)) {
799 case USB_ST_TRANSFERRED:
800 CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED");
802 cfumass_transfer_start(sc, CFUMASS_T_COMMAND);
807 CFUMASS_DEBUG(sc, "USB_ST_SETUP");
809 if (sc->sc_current_residue > 0 && !sc->sc_current_stalled) {
810 CFUMASS_DEBUG(sc, "non-zero residue, stalling");
811 usbd_xfer_set_stall(xfer);
812 sc->sc_current_stalled = true;
815 USETDW(sc->sc_csw->dCSWSignature, CSWSIGNATURE);
816 USETDW(sc->sc_csw->dCSWTag, sc->sc_current_tag);
817 USETDW(sc->sc_csw->dCSWDataResidue, sc->sc_current_residue);
818 sc->sc_csw->bCSWStatus = sc->sc_current_status;
820 usbd_xfer_set_frame_len(xfer, 0, sizeof(*sc->sc_csw));
821 usbd_transfer_submit(xfer);
825 if (usb_error == USB_ERR_CANCELLED) {
826 CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED");
830 CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s",
831 usbd_errstr(usb_error));
838 cfumass_online(void *arg __unused)
841 cfumass_port_online = true;
845 cfumass_offline(void *arg __unused)
848 cfumass_port_online = false;
852 cfumass_datamove(union ctl_io *io)
854 struct cfumass_softc *sc;
856 sc = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
858 CFUMASS_DEBUG(sc, "go");
862 KASSERT(sc->sc_ctl_io == NULL,
863 ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io));
866 if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_IN) {
868 * Verify that CTL wants us to send the data in the direction
869 * expected by the initiator.
871 if (sc->sc_current_flags != CBWFLAGS_IN) {
872 CFUMASS_WARN(sc, "wrong bCBWFlags 0x%x, should be 0x%x",
873 sc->sc_current_flags, CBWFLAGS_IN);
877 cfumass_transfer_start(sc, CFUMASS_T_DATA_IN);
879 if (sc->sc_current_flags != CBWFLAGS_OUT) {
880 CFUMASS_WARN(sc, "wrong bCBWFlags 0x%x, should be 0x%x",
881 sc->sc_current_flags, CBWFLAGS_OUT);
885 cfumass_transfer_start(sc, CFUMASS_T_DATA_OUT);
892 ctl_set_data_phase_error(&io->scsiio);
893 io->scsiio.be_move_done(io);
894 sc->sc_ctl_io = NULL;
898 cfumass_done(union ctl_io *io)
900 struct cfumass_softc *sc;
902 sc = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
904 CFUMASS_DEBUG(sc, "go");
906 KASSERT(((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE),
907 ("invalid CTL status %#x", io->io_hdr.status));
908 KASSERT(sc->sc_ctl_io == NULL,
909 ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io));
911 if (io->io_hdr.io_type == CTL_IO_TASK &&
912 io->taskio.task_action == CTL_TASK_I_T_NEXUS_RESET) {
914 * Implicit task termination has just completed; nothing to do.
921 * Do not return status for aborted commands.
922 * There are exceptions, but none supported by CTL yet.
924 if (((io->io_hdr.flags & CTL_FLAG_ABORT) &&
925 (io->io_hdr.flags & CTL_FLAG_ABORT_STATUS) == 0) ||
926 (io->io_hdr.flags & CTL_FLAG_STATUS_SENT)) {
931 if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS)
932 sc->sc_current_status = 0;
934 sc->sc_current_status = 1;
936 /* XXX: How should we report BUSY, RESERVATION CONFLICT, etc? */
937 if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SCSI_ERROR &&
938 io->scsiio.scsi_status == SCSI_STATUS_CHECK_COND)
944 cfumass_transfer_start(sc, CFUMASS_T_STATUS);
947 refcount_release(&sc->sc_queued);
955 cfumass_port.frontend = &cfumass_frontend;
956 cfumass_port.port_type = CTL_PORT_UMASS;
957 cfumass_port.num_requested_ctl_io = 1;
958 cfumass_port.port_name = "cfumass";
959 cfumass_port.physical_port = 0;
960 cfumass_port.virtual_port = 0;
961 cfumass_port.port_online = cfumass_online;
962 cfumass_port.port_offline = cfumass_offline;
963 cfumass_port.onoff_arg = NULL;
964 cfumass_port.fe_datamove = cfumass_datamove;
965 cfumass_port.fe_done = cfumass_done;
966 cfumass_port.targ_port = -1;
968 error = ctl_port_register(&cfumass_port);
970 printf("%s: ctl_port_register() failed "
971 "with error %d", __func__, error);
974 cfumass_port_online = true;
975 refcount_init(&cfumass_refcount, 0);
981 cfumass_shutdown(void)
985 if (cfumass_refcount > 0) {
987 printf("%s: still have %u attachments; "
988 "returning EBUSY\n", __func__, cfumass_refcount);
993 error = ctl_port_deregister(&cfumass_port);
995 printf("%s: ctl_port_deregister() failed "
996 "with error %d\n", __func__, error);