2 * Copyright (c) 2016 The FreeBSD Foundation
5 * This software was developed by Edward Tomasz Napierala under sponsorship
6 * from the FreeBSD Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
31 * USB Mass Storage Class Bulk-Only (BBB) Transport target.
33 * http://www.usb.org/developers/docs/devclass_docs/usbmassbulk_10.pdf
35 * This code implements the USB Mass Storage frontend driver for the CAM
36 * Target Layer (ctl(4)) subsystem.
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
42 #include <sys/param.h>
44 #include <sys/kernel.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>
53 #include <dev/usb/usb.h>
54 #include <dev/usb/usbdi.h>
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>
70 SYSCTL_NODE(_hw_usb, OID_AUTO, cfumass, CTLFLAG_RW, 0,
71 "CAM Target Layer USB Mass Storage Frontend");
73 SYSCTL_INT(_hw_usb_cfumass, OID_AUTO, debug, CTLFLAG_RWTUN,
74 &debug, 1, "Enable debug messages");
75 static int max_lun = 0;
76 SYSCTL_INT(_hw_usb_cfumass, OID_AUTO, max_lun, CTLFLAG_RWTUN,
77 &max_lun, 1, "Maximum advertised LUN number");
78 static int ignore_stop = 1;
79 SYSCTL_INT(_hw_usb_cfumass, OID_AUTO, ignore_stop, CTLFLAG_RWTUN,
80 &ignore_stop, 1, "Ignore START STOP UNIT with START and LOEJ bits cleared");
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.
88 struct ctl_port cfumass_port;
89 bool cfumass_port_online;
90 volatile u_int cfumass_refcount;
92 #ifndef CFUMASS_BULK_SIZE
93 #define CFUMASS_BULK_SIZE (1U << 17) /* bytes */
97 * USB transfer definitions.
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
106 * USB interface specific control requests.
108 #define UR_RESET 0xff /* Bulk-Only Mass Storage Reset */
109 #define UR_GET_MAX_LUN 0xfe /* Get Max LUN */
112 * Command Block Wrapper.
114 struct cfumass_cbw_t {
115 uDWord dCBWSignature;
116 #define CBWSIGNATURE 0x43425355 /* "USBC" */
118 uDWord dCBWDataTransferLength;
120 #define CBWFLAGS_OUT 0x00
121 #define CBWFLAGS_IN 0x80
124 #define CBWCBLENGTH 16
125 uByte CBWCB[CBWCBLENGTH];
128 #define CFUMASS_CBW_SIZE 31
129 CTASSERT(sizeof(struct cfumass_cbw_t) == CFUMASS_CBW_SIZE);
132 * Command Status Wrapper.
134 struct cfumass_csw_t {
135 uDWord dCSWSignature;
136 #define CSWSIGNATURE 0x53425355 /* "USBS" */
138 uDWord dCSWDataResidue;
140 #define CSWSTATUS_GOOD 0x0
141 #define CSWSTATUS_FAILED 0x1
142 #define CSWSTATUS_PHASE 0x2
145 #define CFUMASS_CSW_SIZE 13
146 CTASSERT(sizeof(struct cfumass_csw_t) == CFUMASS_CSW_SIZE);
148 struct cfumass_softc {
150 struct usb_device *sc_udev;
151 struct usb_xfer *sc_xfer[CFUMASS_T_MAX];
153 struct cfumass_cbw_t *sc_cbw;
154 struct cfumass_csw_t *sc_csw;
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).
166 bool sc_current_stalled;
169 * The following are set upon receiving a SCSI command.
172 int sc_current_transfer_length;
173 int sc_current_flags;
176 * The following are set in ctl_datamove().
178 int sc_current_residue;
179 union ctl_io *sc_ctl_io;
182 * The following is set in cfumass_done().
184 int sc_current_status;
187 * Number of requests queued to CTL.
189 volatile u_int sc_queued;
195 static device_probe_t cfumass_probe;
196 static device_attach_t cfumass_attach;
197 static device_detach_t cfumass_detach;
198 static device_suspend_t cfumass_suspend;
199 static device_resume_t cfumass_resume;
200 static usb_handle_request_t cfumass_handle_request;
202 static usb_callback_t cfumass_t_command_callback;
203 static usb_callback_t cfumass_t_data_out_callback;
204 static usb_callback_t cfumass_t_data_in_callback;
205 static usb_callback_t cfumass_t_status_callback;
207 static device_method_t cfumass_methods[] = {
210 DEVMETHOD(usb_handle_request, cfumass_handle_request),
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),
222 static driver_t cfumass_driver = {
224 .methods = cfumass_methods,
225 .size = sizeof(struct cfumass_softc),
228 static devclass_t cfumass_devclass;
230 DRIVER_MODULE(cfumass, uhub, cfumass_driver, cfumass_devclass, NULL, 0);
231 MODULE_VERSION(cfumass, 0);
232 MODULE_DEPEND(cfumass, usb, 1, 1, 1);
233 MODULE_DEPEND(cfumass, usb_template, 1, 1, 1);
235 static struct usb_config cfumass_config[CFUMASS_T_MAX] = {
237 [CFUMASS_T_COMMAND] = {
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,
246 [CFUMASS_T_DATA_OUT] = {
248 .endpoint = UE_ADDR_ANY,
249 .direction = UE_DIR_OUT,
250 .bufsize = CFUMASS_BULK_SIZE,
251 .flags = {.proxy_buffer = 1, .short_xfer_ok = 1,
253 .callback = &cfumass_t_data_out_callback,
254 .usb_mode = USB_MODE_DEVICE,
257 [CFUMASS_T_DATA_IN] = {
259 .endpoint = UE_ADDR_ANY,
260 .direction = UE_DIR_IN,
261 .bufsize = CFUMASS_BULK_SIZE,
262 .flags = {.proxy_buffer = 1, .short_xfer_ok = 1,
264 .callback = &cfumass_t_data_in_callback,
265 .usb_mode = USB_MODE_DEVICE,
268 [CFUMASS_T_STATUS] = {
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,
280 * CTL frontend interface.
282 static int cfumass_init(void);
283 static int cfumass_shutdown(void);
284 static void cfumass_online(void *arg);
285 static void cfumass_offline(void *arg);
286 static void cfumass_datamove(union ctl_io *io);
287 static void cfumass_done(union ctl_io *io);
289 static struct ctl_frontend cfumass_frontend = {
291 .init = cfumass_init,
292 .shutdown = cfumass_shutdown,
294 CTL_FRONTEND_DECLARE(ctlcfumass, cfumass_frontend);
296 #define CFUMASS_DEBUG(S, X, ...) \
299 device_printf(S->sc_dev, "%s: " X "\n", \
300 __func__, ## __VA_ARGS__); \
304 #define CFUMASS_WARN(S, X, ...) \
307 device_printf(S->sc_dev, "WARNING: %s: " X "\n",\
308 __func__, ## __VA_ARGS__); \
312 #define CFUMASS_LOCK(X) mtx_lock(&X->sc_mtx)
313 #define CFUMASS_UNLOCK(X) mtx_unlock(&X->sc_mtx)
315 static void cfumass_transfer_start(struct cfumass_softc *sc,
317 static void cfumass_terminate(struct cfumass_softc *sc);
320 cfumass_probe(device_t dev)
322 struct usb_attach_arg *uaa;
323 struct usb_interface_descriptor *id;
325 uaa = device_get_ivars(dev);
327 if (uaa->usb_mode != USB_MODE_DEVICE)
331 * Check for a compliant device.
333 id = usbd_get_interface_descriptor(uaa->iface);
335 (id->bInterfaceClass != UICLASS_MASS) ||
336 (id->bInterfaceSubClass != UISUBCLASS_SCSI) ||
337 (id->bInterfaceProtocol != UIPROTO_MASS_BBB)) {
341 return (BUS_PROBE_GENERIC);
345 cfumass_attach(device_t dev)
347 struct cfumass_softc *sc;
348 struct usb_attach_arg *uaa;
351 sc = device_get_softc(dev);
352 uaa = device_get_ivars(dev);
355 sc->sc_udev = uaa->device;
357 CFUMASS_DEBUG(sc, "go");
359 usbd_set_power_mode(uaa->device, USB_POWER_MODE_SAVE);
360 device_set_usb_desc(dev);
362 mtx_init(&sc->sc_mtx, "cfumass", NULL, MTX_DEF);
363 refcount_acquire(&cfumass_refcount);
365 error = usbd_transfer_setup(uaa->device,
366 &uaa->info.bIfaceIndex, sc->sc_xfer, cfumass_config,
367 CFUMASS_T_MAX, sc, &sc->sc_mtx);
369 CFUMASS_WARN(sc, "usbd_transfer_setup() failed: %s",
371 refcount_release(&cfumass_refcount);
376 usbd_xfer_get_frame_buffer(sc->sc_xfer[CFUMASS_T_COMMAND], 0);
378 usbd_xfer_get_frame_buffer(sc->sc_xfer[CFUMASS_T_STATUS], 0);
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",
384 usbd_transfer_unsetup(sc->sc_xfer, CFUMASS_T_MAX);
385 refcount_release(&cfumass_refcount);
389 refcount_init(&sc->sc_queued, 0);
392 cfumass_transfer_start(sc, CFUMASS_T_COMMAND);
399 cfumass_detach(device_t dev)
401 struct cfumass_softc *sc;
404 sc = device_get_softc(dev);
406 CFUMASS_DEBUG(sc, "go");
409 cfumass_terminate(sc);
411 usbd_transfer_unsetup(sc->sc_xfer, CFUMASS_T_MAX);
413 if (sc->sc_ctl_initid != -1) {
414 error = ctl_remove_initiator(&cfumass_port, sc->sc_ctl_initid);
416 CFUMASS_WARN(sc, "ctl_remove_initiator() failed "
417 "with error %d", error);
419 sc->sc_ctl_initid = -1;
422 mtx_destroy(&sc->sc_mtx);
423 refcount_release(&cfumass_refcount);
429 cfumass_suspend(device_t dev)
431 struct cfumass_softc *sc;
433 sc = device_get_softc(dev);
434 CFUMASS_DEBUG(sc, "go");
440 cfumass_resume(device_t dev)
442 struct cfumass_softc *sc;
444 sc = device_get_softc(dev);
445 CFUMASS_DEBUG(sc, "go");
451 cfumass_transfer_start(struct cfumass_softc *sc, uint8_t xfer_index)
454 usbd_transfer_start(sc->sc_xfer[xfer_index]);
458 cfumass_transfer_stop_and_drain(struct cfumass_softc *sc, uint8_t xfer_index)
461 usbd_transfer_stop(sc->sc_xfer[xfer_index]);
463 usbd_transfer_drain(sc->sc_xfer[xfer_index]);
468 cfumass_terminate(struct cfumass_softc *sc)
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);
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;
484 cfumass_transfer_stop_and_drain(sc, CFUMASS_T_STATUS);
486 refcount_acquire(&sc->sc_queued);
487 last = refcount_release(&sc->sc_queued);
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);
498 cfumass_handle_request(device_t dev,
499 const void *preq, void **pptr, uint16_t *plen,
500 uint16_t offset, uint8_t *pstate)
502 static uint8_t max_lun_tmp;
503 struct cfumass_softc *sc;
504 const struct usb_device_request *req;
507 sc = device_get_softc(dev);
509 is_complete = *pstate;
511 CFUMASS_DEBUG(sc, "go");
516 if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
517 (req->bRequest == UR_RESET)) {
518 CFUMASS_WARN(sc, "received Bulk-Only Mass Storage Reset");
522 cfumass_terminate(sc);
523 cfumass_transfer_start(sc, CFUMASS_T_COMMAND);
526 CFUMASS_DEBUG(sc, "Bulk-Only Mass Storage Reset done");
530 if ((req->bmRequestType == UT_READ_CLASS_INTERFACE) &&
531 (req->bRequest == UR_GET_MAX_LUN)) {
532 CFUMASS_DEBUG(sc, "received Get Max LUN");
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.
542 if (max_lun < 0 || max_lun > 15) {
544 "invalid hw.usb.cfumass.max_lun, must be "
545 "between 0 and 15; defaulting to 0");
548 max_lun_tmp = max_lun;
550 *pptr = &max_lun_tmp;
561 cfumass_quirk(struct cfumass_softc *sc, unsigned char *cdb, int cdb_len)
563 struct scsi_start_stop_unit *sssu;
566 case START_STOP_UNIT:
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.
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));
581 sssu = (struct scsi_start_stop_unit *)cdb;
582 if ((sssu->how & SSS_PC_MASK) != 0)
585 if ((sssu->how & SSS_START) != 0)
588 if ((sssu->how & SSS_LOEJ) != 0)
591 if (ignore_stop == 0) {
593 } else if (ignore_stop == 1) {
594 CFUMASS_WARN(sc, "ignoring START STOP UNIT request");
596 CFUMASS_DEBUG(sc, "ignoring START STOP UNIT request");
599 sc->sc_current_status = 0;
600 cfumass_transfer_start(sc, CFUMASS_T_STATUS);
611 cfumass_t_command_callback(struct usb_xfer *xfer, usb_error_t usb_error)
613 struct cfumass_softc *sc;
618 sc = usbd_xfer_softc(xfer);
620 KASSERT(sc->sc_ctl_io == NULL,
621 ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io));
623 switch (USB_GET_STATE(xfer)) {
624 case USB_ST_TRANSFERRED:
625 CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED");
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);
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));
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;
649 * Make sure to report proper residue if the datamove wasn't
650 * required, or wasn't called due to SCSI error.
652 sc->sc_current_residue = sc->sc_current_transfer_length;
654 if (cfumass_quirk(sc,
655 sc->sc_cbw->CBWCB, sc->sc_cbw->bCDBLength) != 0)
658 if (!cfumass_port_online) {
659 CFUMASS_DEBUG(sc, "cfumass port is offline; stalling");
660 usbd_xfer_set_stall(xfer);
665 * Those CTL functions cannot be called with mutex held.
668 io = ctl_alloc_io(cfumass_port.ctl_pool_ref);
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) {
683 "ctl_queue() failed; error %d; stalling", error);
685 refcount_release(&sc->sc_queued);
687 usbd_xfer_set_stall(xfer);
696 CFUMASS_DEBUG(sc, "USB_ST_SETUP");
698 usbd_xfer_set_frame_len(xfer, 0, sizeof(*sc->sc_cbw));
699 usbd_transfer_submit(xfer);
703 if (usb_error == USB_ERR_CANCELLED) {
704 CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED");
708 CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s", usbd_errstr(usb_error));
715 cfumass_t_data_out_callback(struct usb_xfer *xfer, usb_error_t usb_error)
717 struct cfumass_softc *sc;
719 struct ctl_sg_entry ctl_sg_entry, *ctl_sglist;
720 int actlen, ctl_sg_count;
722 sc = usbd_xfer_softc(xfer);
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;
729 ctl_sglist = &ctl_sg_entry;
730 ctl_sglist->addr = io->scsiio.kern_data_ptr;
731 ctl_sglist->len = io->scsiio.kern_data_len;
735 switch (USB_GET_STATE(xfer)) {
736 case USB_ST_TRANSFERRED:
737 CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED");
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);
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;
756 CFUMASS_DEBUG(sc, "USB_ST_SETUP");
758 CFUMASS_DEBUG(sc, "requested size %d, CTL segment size %zd",
759 sc->sc_current_transfer_length, ctl_sglist[0].len);
761 usbd_xfer_set_frame_data(xfer, 0, ctl_sglist[0].addr, ctl_sglist[0].len);
762 usbd_transfer_submit(xfer);
766 if (usb_error == USB_ERR_CANCELLED) {
767 CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED");
771 CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s",
772 usbd_errstr(usb_error));
779 cfumass_t_data_in_callback(struct usb_xfer *xfer, usb_error_t usb_error)
781 struct cfumass_softc *sc;
784 struct ctl_sg_entry ctl_sg_entry, *ctl_sglist;
785 int actlen, ctl_sg_count;
787 sc = usbd_xfer_softc(xfer);
790 switch (USB_GET_STATE(xfer)) {
791 case USB_ST_TRANSFERRED:
792 CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED");
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;
803 CFUMASS_DEBUG(sc, "USB_ST_SETUP");
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;
809 ctl_sglist = &ctl_sg_entry;
810 ctl_sglist->addr = io->scsiio.kern_data_ptr;
811 ctl_sglist->len = io->scsiio.kern_data_len;
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);
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);
827 if (max_bulk >= ctl_sglist[0].len)
828 max_bulk = ctl_sglist[0].len;
830 usbd_xfer_set_frame_data(xfer, 0, ctl_sglist[0].addr, max_bulk);
831 usbd_transfer_submit(xfer);
836 if (usb_error == USB_ERR_CANCELLED) {
837 CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED");
841 CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s", usbd_errstr(usb_error));
848 cfumass_t_status_callback(struct usb_xfer *xfer, usb_error_t usb_error)
850 struct cfumass_softc *sc;
852 sc = usbd_xfer_softc(xfer);
854 KASSERT(sc->sc_ctl_io == NULL,
855 ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io));
857 switch (USB_GET_STATE(xfer)) {
858 case USB_ST_TRANSFERRED:
859 CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED");
861 cfumass_transfer_start(sc, CFUMASS_T_COMMAND);
866 CFUMASS_DEBUG(sc, "USB_ST_SETUP");
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;
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;
879 usbd_xfer_set_frame_len(xfer, 0, sizeof(*sc->sc_csw));
880 usbd_transfer_submit(xfer);
884 if (usb_error == USB_ERR_CANCELLED) {
885 CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED");
889 CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s",
890 usbd_errstr(usb_error));
897 cfumass_online(void *arg __unused)
900 cfumass_port_online = true;
904 cfumass_offline(void *arg __unused)
907 cfumass_port_online = false;
911 cfumass_datamove(union ctl_io *io)
913 struct cfumass_softc *sc;
915 sc = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
917 CFUMASS_DEBUG(sc, "go");
921 KASSERT(sc->sc_ctl_io == NULL,
922 ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io));
925 if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_IN) {
927 * Verify that CTL wants us to send the data in the direction
928 * expected by the initiator.
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);
936 cfumass_transfer_start(sc, CFUMASS_T_DATA_IN);
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);
944 cfumass_transfer_start(sc, CFUMASS_T_DATA_OUT);
951 ctl_set_data_phase_error(&io->scsiio);
952 io->scsiio.be_move_done(io);
953 sc->sc_ctl_io = NULL;
957 cfumass_done(union ctl_io *io)
959 struct cfumass_softc *sc;
961 sc = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
963 CFUMASS_DEBUG(sc, "go");
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));
970 if (io->io_hdr.io_type == CTL_IO_TASK &&
971 io->taskio.task_action == CTL_TASK_I_T_NEXUS_RESET) {
973 * Implicit task termination has just completed; nothing to do.
980 * Do not return status for aborted commands.
981 * There are exceptions, but none supported by CTL yet.
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)) {
990 switch (io->scsiio.scsi_status) {
992 sc->sc_current_status = 0;
995 sc->sc_current_status = 1;
1000 cfumass_transfer_start(sc, CFUMASS_T_STATUS);
1004 refcount_release(&sc->sc_queued);
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;
1025 error = ctl_port_register(&cfumass_port);
1027 printf("%s: ctl_port_register() failed "
1028 "with error %d", __func__, error);
1031 cfumass_port_online = true;
1032 refcount_init(&cfumass_refcount, 0);
1038 cfumass_shutdown(void)
1042 if (cfumass_refcount > 0) {
1044 printf("%s: still have %u attachments; "
1045 "returning EBUSY\n", __func__, cfumass_refcount);
1050 error = ctl_port_deregister(&cfumass_port);
1052 printf("%s: ctl_port_deregister() failed "
1053 "with error %d\n", __func__, error);