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