45#include <sys/kernel.h>
47#include <sys/module.h>
49#include <sys/refcount.h>
50#include <sys/stdint.h>
51#include <sys/sysctl.h>
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>
71SYSCTL_NODE(_hw_usb, OID_AUTO, cfumass, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
72 "CAM Target Layer USB Mass Storage Frontend");
75 &
debug, 1,
"Enable debug messages");
78 &
max_lun, 1,
"Maximum advertised LUN number");
81 &
ignore_stop, 1,
"Ignore START STOP UNIT with START and LOEJ bits cleared");
93#ifndef CFUMASS_BULK_SIZE
94#define CFUMASS_BULK_SIZE (1U << 17)
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
110#define UR_GET_MAX_LUN 0xfe
117#define CBWSIGNATURE 0x43425355
121#define CBWFLAGS_OUT 0x00
122#define CBWFLAGS_IN 0x80
125#define CBWCBLENGTH 16
129#define CFUMASS_CBW_SIZE 31
137#define CSWSIGNATURE 0x53425355
141#define CSWSTATUS_GOOD 0x0
142#define CSWSTATUS_FAILED 0x1
143#define CSWSTATUS_PHASE 0x2
146#define CFUMASS_CSW_SIZE 13
249 .flags = {.proxy_buffer = 1, .short_xfer_ok = 1,
260 .flags = {.proxy_buffer = 1, .short_xfer_ok = 1,
271 .flags = {.short_xfer_ok = 1},
294#define CFUMASS_DEBUG(S, X, ...) \
297 device_printf(S->sc_dev, "%s: " X "\n", \
298 __func__, ## __VA_ARGS__); \
302#define CFUMASS_WARN(S, X, ...) \
305 device_printf(S->sc_dev, "WARNING: %s: " X "\n",\
306 __func__, ## __VA_ARGS__); \
310#define CFUMASS_LOCK(X) mtx_lock(&X->sc_mtx)
311#define CFUMASS_UNLOCK(X) mtx_unlock(&X->sc_mtx)
323 uaa = device_get_ivars(
dev);
339 return (BUS_PROBE_GENERIC);
349 sc = device_get_softc(
dev);
350 uaa = device_get_ivars(
dev);
360 mtx_init(&sc->
sc_mtx,
"cfumass", NULL, MTX_DEF);
380 CFUMASS_WARN(sc,
"ctl_add_initiator() failed with error %d",
402 sc = device_get_softc(
dev);
415 "with error %d",
error);
431 sc = device_get_softc(
dev);
442 sc = device_get_softc(
dev);
477 ctl_set_data_phase_error(&sc->
sc_ctl_io->scsiio);
491 0,
"cfumass_reset", hz / 100);
497 const void *preq,
void **
pptr, uint16_t *
plen,
500 static uint8_t max_lun_tmp;
505 sc = device_get_softc(
dev);
516 CFUMASS_WARN(sc,
"received Bulk-Only Mass Storage Reset");
540 if (max_lun < 0 || max_lun > 15) {
542 "invalid hw.usb.cfumass.max_lun, must be "
543 "between 0 and 15; defaulting to 0");
548 *
pptr = &max_lun_tmp;
561 struct scsi_start_stop_unit *sssu;
564 case START_STOP_UNIT:
572 if (cdb_len <
sizeof(*sssu)) {
574 "bCDBLength %d, should be %zd",
575 cdb_len,
sizeof(*sssu));
579 sssu = (
struct scsi_start_stop_unit *)cdb;
580 if ((sssu->how & SSS_PC_MASK) != 0)
583 if ((sssu->how & SSS_START) != 0)
586 if ((sssu->how & SSS_LOEJ) != 0)
619 (
"sc_ctl_io is %p, should be NULL", sc->
sc_ctl_io));
634 CFUMASS_WARN(sc,
"invalid bCDBLength %d, should be <= %zd",
668 io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = sc;
669 io->io_hdr.io_type = CTL_IO_SCSI;
672 io->io_hdr.nexus.targ_lun = ctl_decode_lun(sc->
sc_cbw->
bCBWLUN);
674 io->scsiio.tag_type = CTL_TAG_UNTAGGED;
678 error = ctl_queue(io);
679 if (
error != CTL_RETVAL_COMPLETE) {
681 "ctl_queue() failed; error %d; stalling",
error);
718 struct ctl_sg_entry sg_entry, *sglist;
719 int actlen, sumlen, sg_count;
727 io->scsiio.ext_data_filled += actlen;
728 io->scsiio.kern_data_resid -= actlen;
729 if (actlen < sumlen ||
731 io->scsiio.kern_data_resid == 0) {
733 ctl_datamove_done(io,
false);
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;
747 sglist->addr = io->scsiio.kern_data_ptr;
748 sglist->len = io->scsiio.kern_data_len;
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;
759 KASSERT(sg_count > 0, (
"Run out of S/G list entries"));
762 actlen = min(sglist->len - sumlen, max_bulk);
764 io->scsiio.ext_data_filled);
766 "segment %zd => transfer %d",
768 max_bulk, sglist->len - sumlen, actlen);
771 (uint8_t *)sglist->addr + sumlen, actlen);
793 (
"sc_ctl_io is %p, should be NULL", sc->
sc_ctl_io));
853 sc = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
860 (
"sc_ctl_io is %p, should be NULL", sc->
sc_ctl_io));
863 if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_IN) {
869 CFUMASS_WARN(sc,
"wrong bCBWFlags 0x%x, should be 0x%x",
877 CFUMASS_WARN(sc,
"wrong bCBWFlags 0x%x, should be 0x%x",
889 ctl_set_data_phase_error(&io->scsiio);
890 ctl_datamove_done(io,
true);
899 sc = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
903 KASSERT(((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE),
904 (
"invalid CTL status %#x", io->io_hdr.status));
906 (
"sc_ctl_io is %p, should be NULL", sc->
sc_ctl_io));
908 if (io->io_hdr.io_type == CTL_IO_TASK &&
909 io->taskio.task_action == CTL_TASK_I_T_NEXUS_RESET) {
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)) {
928 if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS)
934 if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SCSI_ERROR &&
935 io->scsiio.scsi_status == SCSI_STATUS_CHECK_COND)
967 printf(
"%s: ctl_port_register() failed "
968 "with error %d", __func__,
error);
984 printf(
"%s: still have %u attachments; "
992 printf(
"%s: ctl_port_deregister() failed "
993 "with error %d\n", __func__,
error);
static device_method_t cfumass_methods[]
MODULE_DEPEND(cfumass, usb, 1, 1, 1)
static struct usb_config cfumass_config[CFUMASS_T_MAX]
static void cfumass_datamove(union ctl_io *io)
MODULE_VERSION(cfumass, 0)
static void cfumass_done(union ctl_io *io)
CTL_FRONTEND_DECLARE(ctlcfumass, cfumass_frontend)
volatile u_int cfumass_refcount
static device_resume_t cfumass_resume
static usb_callback_t cfumass_t_data_callback
static device_probe_t cfumass_probe
#define CFUMASS_UNLOCK(X)
static usb_handle_request_t cfumass_handle_request
static device_detach_t cfumass_detach
#define CFUMASS_T_DATA_OUT
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)
#define CFUMASS_T_DATA_IN
static void cfumass_online(void *arg)
static usb_callback_t cfumass_t_status_callback
SYSCTL_INT(_hw_usb_cfumass, OID_AUTO, debug, CTLFLAG_RWTUN, &debug, 1, "Enable debug messages")
static void cfumass_offline(void *arg)
static device_suspend_t cfumass_suspend
static devclass_t cfumass_devclass
static int cfumass_init(void)
CTASSERT(sizeof(struct cfumass_cbw_t)==CFUMASS_CBW_SIZE)
static void cfumass_transfer_stop_and_drain(struct cfumass_softc *sc, uint8_t xfer_index)
static int cfumass_shutdown(void)
static void cfumass_transfer_start(struct cfumass_softc *sc, uint8_t xfer_index)
#define CFUMASS_DEBUG(S, X,...)
static usb_callback_t cfumass_t_command_callback
static driver_t cfumass_driver
#define CFUMASS_WARN(S, X,...)
struct cfumass_cbw_t __packed
struct ctl_port cfumass_port
DRIVER_MODULE(cfumass, uhub, cfumass_driver, cfumass_devclass, NULL, 0)
static device_attach_t cfumass_attach
static struct ctl_frontend cfumass_frontend
static int cfumass_quirk(struct cfumass_softc *sc, unsigned char *cdb, int cdb_len)
#define CFUMASS_BULK_SIZE
#define CFUMASS_T_COMMAND
uDWord dCBWDataTransferLength
struct usb_xfer * sc_xfer[CFUMASS_T_MAX]
struct cfumass_cbw_t * sc_cbw
int sc_current_transfer_length
struct cfumass_csw_t * sc_csw
struct usb_device * sc_udev
enum usb_hc_mode usb_mode
struct usbd_lookup_info info
struct usb_interface * iface
struct usb_device * device
#define UT_READ_CLASS_INTERFACE
#define USB_POWER_MODE_SAVE
#define UT_WRITE_CLASS_INTERFACE
struct usb_interface_descriptor * usbd_get_interface_descriptor(struct usb_interface *iface)
const char * usbd_errstr(usb_error_t err)
static usb_error_t usb_handle_request(struct usb_xfer *)
void usbd_set_power_mode(struct usb_device *udev, uint8_t power_mode)
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)
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)
#define USB_ST_TRANSFERRED
void() usb_callback_t(struct usb_xfer *, usb_error_t)
#define USB_GET_STATE(xfer)