cfumass.c revision 332617
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2016 The FreeBSD Foundation
5 * All rights reserved.
6 *
7 * This software was developed by Edward Tomasz Napierala under sponsorship
8 * from the FreeBSD Foundation.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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.
18 *
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
29 * SUCH DAMAGE.
30 *
31 */
32/*
33 * USB Mass Storage Class Bulk-Only (BBB) Transport target.
34 *
35 * http://www.usb.org/developers/docs/devclass_docs/usbmassbulk_10.pdf
36 *
37 * This code implements the USB Mass Storage frontend driver for the CAM
38 * Target Layer (ctl(4)) subsystem.
39 */
40
41#include <sys/cdefs.h>
42__FBSDID("$FreeBSD: stable/11/sys/dev/usb/storage/cfumass.c 332617 2018-04-16 17:15:26Z trasz $");
43
44#include <sys/param.h>
45#include <sys/bus.h>
46#include <sys/kernel.h>
47#include <sys/lock.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>
54
55#include <dev/usb/usb.h>
56#include <dev/usb/usbdi.h>
57#include "usbdevs.h"
58#include "usb_if.h"
59
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>
71
72SYSCTL_NODE(_hw_usb, OID_AUTO, cfumass, CTLFLAG_RW, 0,
73    "CAM Target Layer USB Mass Storage Frontend");
74static int debug = 1;
75SYSCTL_INT(_hw_usb_cfumass, OID_AUTO, debug, CTLFLAG_RWTUN,
76    &debug, 1, "Enable debug messages");
77static int max_lun = 0;
78SYSCTL_INT(_hw_usb_cfumass, OID_AUTO, max_lun, CTLFLAG_RWTUN,
79    &max_lun, 1, "Maximum advertised LUN number");
80static int ignore_stop = 1;
81SYSCTL_INT(_hw_usb_cfumass, OID_AUTO, ignore_stop, CTLFLAG_RWTUN,
82    &ignore_stop, 1, "Ignore START STOP UNIT with START and LOEJ bits cleared");
83
84/*
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.
89 */
90struct ctl_port	cfumass_port;
91bool		cfumass_port_online;
92volatile u_int	cfumass_refcount;
93
94#ifndef CFUMASS_BULK_SIZE
95#define	CFUMASS_BULK_SIZE	(1U << 17)	/* bytes */
96#endif
97
98/*
99 * USB transfer definitions.
100 */
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
106
107/*
108 * USB interface specific control requests.
109 */
110#define	UR_RESET	0xff	/* Bulk-Only Mass Storage Reset */
111#define	UR_GET_MAX_LUN	0xfe	/* Get Max LUN */
112
113/*
114 * Command Block Wrapper.
115 */
116struct cfumass_cbw_t {
117	uDWord	dCBWSignature;
118#define	CBWSIGNATURE		0x43425355 /* "USBC" */
119	uDWord	dCBWTag;
120	uDWord	dCBWDataTransferLength;
121	uByte	bCBWFlags;
122#define	CBWFLAGS_OUT		0x00
123#define	CBWFLAGS_IN		0x80
124	uByte	bCBWLUN;
125	uByte	bCDBLength;
126#define	CBWCBLENGTH		16
127	uByte	CBWCB[CBWCBLENGTH];
128} __packed;
129
130#define	CFUMASS_CBW_SIZE	31
131CTASSERT(sizeof(struct cfumass_cbw_t) == CFUMASS_CBW_SIZE);
132
133/*
134 * Command Status Wrapper.
135 */
136struct cfumass_csw_t {
137	uDWord	dCSWSignature;
138#define	CSWSIGNATURE		0x53425355 /* "USBS" */
139	uDWord	dCSWTag;
140	uDWord	dCSWDataResidue;
141	uByte	bCSWStatus;
142#define	CSWSTATUS_GOOD		0x0
143#define	CSWSTATUS_FAILED	0x1
144#define	CSWSTATUS_PHASE		0x2
145} __packed;
146
147#define	CFUMASS_CSW_SIZE	13
148CTASSERT(sizeof(struct cfumass_csw_t) == CFUMASS_CSW_SIZE);
149
150struct cfumass_softc {
151	device_t		sc_dev;
152	struct usb_device	*sc_udev;
153	struct usb_xfer		*sc_xfer[CFUMASS_T_MAX];
154
155	struct cfumass_cbw_t *sc_cbw;
156	struct cfumass_csw_t *sc_csw;
157
158	struct mtx	sc_mtx;
159	int		sc_online;
160	int		sc_ctl_initid;
161
162	/*
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).
167	 */
168	bool		sc_current_stalled;
169
170	/*
171	 * The following are set upon receiving a SCSI command.
172	 */
173	int		sc_current_tag;
174	int		sc_current_transfer_length;
175	int		sc_current_flags;
176
177	/*
178	 * The following are set in ctl_datamove().
179	 */
180	int		sc_current_residue;
181	union ctl_io	*sc_ctl_io;
182
183	/*
184	 * The following is set in cfumass_done().
185	 */
186	int		sc_current_status;
187
188	/*
189	 * Number of requests queued to CTL.
190	 */
191	volatile u_int	sc_queued;
192};
193
194/*
195 * USB interface.
196 */
197static device_probe_t		cfumass_probe;
198static device_attach_t		cfumass_attach;
199static device_detach_t		cfumass_detach;
200static device_suspend_t		cfumass_suspend;
201static device_resume_t		cfumass_resume;
202static usb_handle_request_t	cfumass_handle_request;
203
204static usb_callback_t		cfumass_t_command_callback;
205static usb_callback_t		cfumass_t_data_callback;
206static usb_callback_t		cfumass_t_status_callback;
207
208static device_method_t cfumass_methods[] = {
209
210	/* USB interface. */
211	DEVMETHOD(usb_handle_request, cfumass_handle_request),
212
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),
219
220	DEVMETHOD_END
221};
222
223static driver_t cfumass_driver = {
224	.name = "cfumass",
225	.methods = cfumass_methods,
226	.size = sizeof(struct cfumass_softc),
227};
228
229static devclass_t cfumass_devclass;
230
231DRIVER_MODULE(cfumass, uhub, cfumass_driver, cfumass_devclass, NULL, 0);
232MODULE_VERSION(cfumass, 0);
233MODULE_DEPEND(cfumass, usb, 1, 1, 1);
234MODULE_DEPEND(cfumass, usb_template, 1, 1, 1);
235
236static struct usb_config cfumass_config[CFUMASS_T_MAX] = {
237
238	[CFUMASS_T_COMMAND] = {
239		.type = UE_BULK,
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,
245	},
246
247	[CFUMASS_T_DATA_OUT] = {
248		.type = UE_BULK,
249		.endpoint = UE_ADDR_ANY,
250		.direction = UE_DIR_OUT,
251		.bufsize = CFUMASS_BULK_SIZE,
252		.flags = {.proxy_buffer = 1, .short_xfer_ok = 1,
253		    .ext_buffer = 1},
254		.callback = &cfumass_t_data_callback,
255		.usb_mode = USB_MODE_DEVICE,
256	},
257
258	[CFUMASS_T_DATA_IN] = {
259		.type = UE_BULK,
260		.endpoint = UE_ADDR_ANY,
261		.direction = UE_DIR_IN,
262		.bufsize = CFUMASS_BULK_SIZE,
263		.flags = {.proxy_buffer = 1, .short_xfer_ok = 1,
264		    .ext_buffer = 1},
265		.callback = &cfumass_t_data_callback,
266		.usb_mode = USB_MODE_DEVICE,
267	},
268
269	[CFUMASS_T_STATUS] = {
270		.type = UE_BULK,
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,
277	},
278};
279
280/*
281 * CTL frontend interface.
282 */
283static int	cfumass_init(void);
284static int	cfumass_shutdown(void);
285static void	cfumass_online(void *arg);
286static void	cfumass_offline(void *arg);
287static void	cfumass_datamove(union ctl_io *io);
288static void	cfumass_done(union ctl_io *io);
289
290static struct ctl_frontend cfumass_frontend = {
291	.name = "umass",
292	.init = cfumass_init,
293	.shutdown = cfumass_shutdown,
294};
295CTL_FRONTEND_DECLARE(ctlcfumass, cfumass_frontend);
296
297#define	CFUMASS_DEBUG(S, X, ...)					\
298	do {								\
299		if (debug > 1) {					\
300			device_printf(S->sc_dev, "%s: " X "\n",		\
301			    __func__, ## __VA_ARGS__);			\
302		}							\
303	} while (0)
304
305#define	CFUMASS_WARN(S, X, ...)						\
306	do {								\
307		if (debug > 0) {					\
308			device_printf(S->sc_dev, "WARNING: %s: " X "\n",\
309			    __func__, ## __VA_ARGS__);			\
310		}							\
311	} while (0)
312
313#define CFUMASS_LOCK(X)		mtx_lock(&X->sc_mtx)
314#define CFUMASS_UNLOCK(X)	mtx_unlock(&X->sc_mtx)
315
316static void	cfumass_transfer_start(struct cfumass_softc *sc,
317		    uint8_t xfer_index);
318static void	cfumass_terminate(struct cfumass_softc *sc);
319
320static int
321cfumass_probe(device_t dev)
322{
323	struct usb_attach_arg *uaa;
324	struct usb_interface_descriptor *id;
325
326	uaa = device_get_ivars(dev);
327
328	if (uaa->usb_mode != USB_MODE_DEVICE)
329		return (ENXIO);
330
331	/*
332	 * Check for a compliant device.
333	 */
334	id = usbd_get_interface_descriptor(uaa->iface);
335	if ((id == NULL) ||
336	    (id->bInterfaceClass != UICLASS_MASS) ||
337	    (id->bInterfaceSubClass != UISUBCLASS_SCSI) ||
338	    (id->bInterfaceProtocol != UIPROTO_MASS_BBB)) {
339		return (ENXIO);
340	}
341
342	return (BUS_PROBE_GENERIC);
343}
344
345static int
346cfumass_attach(device_t dev)
347{
348	struct cfumass_softc *sc;
349	struct usb_attach_arg *uaa;
350	int error;
351
352	sc = device_get_softc(dev);
353	uaa = device_get_ivars(dev);
354
355	sc->sc_dev = dev;
356	sc->sc_udev = uaa->device;
357
358	CFUMASS_DEBUG(sc, "go");
359
360	usbd_set_power_mode(uaa->device, USB_POWER_MODE_SAVE);
361	device_set_usb_desc(dev);
362
363	mtx_init(&sc->sc_mtx, "cfumass", NULL, MTX_DEF);
364	refcount_acquire(&cfumass_refcount);
365
366	error = usbd_transfer_setup(uaa->device,
367	    &uaa->info.bIfaceIndex, sc->sc_xfer, cfumass_config,
368	    CFUMASS_T_MAX, sc, &sc->sc_mtx);
369	if (error != 0) {
370		CFUMASS_WARN(sc, "usbd_transfer_setup() failed: %s",
371		    usbd_errstr(error));
372		refcount_release(&cfumass_refcount);
373		return (ENXIO);
374	}
375
376	sc->sc_cbw =
377	    usbd_xfer_get_frame_buffer(sc->sc_xfer[CFUMASS_T_COMMAND], 0);
378	sc->sc_csw =
379	    usbd_xfer_get_frame_buffer(sc->sc_xfer[CFUMASS_T_STATUS], 0);
380
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",
384		    sc->sc_ctl_initid);
385		usbd_transfer_unsetup(sc->sc_xfer, CFUMASS_T_MAX);
386		refcount_release(&cfumass_refcount);
387		return (ENXIO);
388	}
389
390	refcount_init(&sc->sc_queued, 0);
391
392	CFUMASS_LOCK(sc);
393	cfumass_transfer_start(sc, CFUMASS_T_COMMAND);
394	CFUMASS_UNLOCK(sc);
395
396	return (0);
397}
398
399static int
400cfumass_detach(device_t dev)
401{
402	struct cfumass_softc *sc;
403	int error;
404
405	sc = device_get_softc(dev);
406
407	CFUMASS_DEBUG(sc, "go");
408
409	CFUMASS_LOCK(sc);
410	cfumass_terminate(sc);
411	CFUMASS_UNLOCK(sc);
412	usbd_transfer_unsetup(sc->sc_xfer, CFUMASS_T_MAX);
413
414	if (sc->sc_ctl_initid != -1) {
415		error = ctl_remove_initiator(&cfumass_port, sc->sc_ctl_initid);
416		if (error != 0) {
417			CFUMASS_WARN(sc, "ctl_remove_initiator() failed "
418			    "with error %d", error);
419		}
420		sc->sc_ctl_initid = -1;
421	}
422
423	mtx_destroy(&sc->sc_mtx);
424	refcount_release(&cfumass_refcount);
425
426	return (0);
427}
428
429static int
430cfumass_suspend(device_t dev)
431{
432	struct cfumass_softc *sc;
433
434	sc = device_get_softc(dev);
435	CFUMASS_DEBUG(sc, "go");
436
437	return (0);
438}
439
440static int
441cfumass_resume(device_t dev)
442{
443	struct cfumass_softc *sc;
444
445	sc = device_get_softc(dev);
446	CFUMASS_DEBUG(sc, "go");
447
448	return (0);
449}
450
451static void
452cfumass_transfer_start(struct cfumass_softc *sc, uint8_t xfer_index)
453{
454
455	usbd_transfer_start(sc->sc_xfer[xfer_index]);
456}
457
458static void
459cfumass_transfer_stop_and_drain(struct cfumass_softc *sc, uint8_t xfer_index)
460{
461
462	usbd_transfer_stop(sc->sc_xfer[xfer_index]);
463	CFUMASS_UNLOCK(sc);
464	usbd_transfer_drain(sc->sc_xfer[xfer_index]);
465	CFUMASS_LOCK(sc);
466}
467
468static void
469cfumass_terminate(struct cfumass_softc *sc)
470{
471	int last;
472
473	for (;;) {
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);
477
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;
483		}
484
485		cfumass_transfer_stop_and_drain(sc, CFUMASS_T_STATUS);
486
487		refcount_acquire(&sc->sc_queued);
488		last = refcount_release(&sc->sc_queued);
489		if (last != 0)
490			break;
491
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);
495	}
496}
497
498static int
499cfumass_handle_request(device_t dev,
500    const void *preq, void **pptr, uint16_t *plen,
501    uint16_t offset, uint8_t *pstate)
502{
503	static uint8_t max_lun_tmp;
504	struct cfumass_softc *sc;
505	const struct usb_device_request *req;
506	uint8_t is_complete;
507
508	sc = device_get_softc(dev);
509	req = preq;
510	is_complete = *pstate;
511
512	CFUMASS_DEBUG(sc, "go");
513
514	if (is_complete)
515		return (ENXIO);
516
517	if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) &&
518	    (req->bRequest == UR_RESET)) {
519		CFUMASS_WARN(sc, "received Bulk-Only Mass Storage Reset");
520		*plen = 0;
521
522		CFUMASS_LOCK(sc);
523		cfumass_terminate(sc);
524		cfumass_transfer_start(sc, CFUMASS_T_COMMAND);
525		CFUMASS_UNLOCK(sc);
526
527		CFUMASS_DEBUG(sc, "Bulk-Only Mass Storage Reset done");
528		return (0);
529	}
530
531	if ((req->bmRequestType == UT_READ_CLASS_INTERFACE) &&
532	    (req->bRequest == UR_GET_MAX_LUN)) {
533		CFUMASS_DEBUG(sc, "received Get Max LUN");
534		if (offset == 0) {
535			*plen = 1;
536			/*
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.
542			 */
543			if (max_lun < 0 || max_lun > 15) {
544				CFUMASS_WARN(sc,
545				    "invalid hw.usb.cfumass.max_lun, must be "
546				    "between 0 and 15; defaulting to 0");
547				max_lun_tmp = 0;
548			} else {
549				max_lun_tmp = max_lun;
550			}
551			*pptr = &max_lun_tmp;
552		} else {
553			*plen = 0;
554		}
555		return (0);
556	}
557
558	return (ENXIO);
559}
560
561static int
562cfumass_quirk(struct cfumass_softc *sc, unsigned char *cdb, int cdb_len)
563{
564	struct scsi_start_stop_unit *sssu;
565
566	switch (cdb[0]) {
567	case START_STOP_UNIT:
568		/*
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.
573		 */
574
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));
579			break;
580		}
581
582		sssu = (struct scsi_start_stop_unit *)cdb;
583		if ((sssu->how & SSS_PC_MASK) != 0)
584			break;
585
586		if ((sssu->how & SSS_START) != 0)
587			break;
588
589		if ((sssu->how & SSS_LOEJ) != 0)
590			break;
591
592		if (ignore_stop == 0) {
593			break;
594		} else if (ignore_stop == 1) {
595			CFUMASS_WARN(sc, "ignoring START STOP UNIT request");
596		} else {
597			CFUMASS_DEBUG(sc, "ignoring START STOP UNIT request");
598		}
599
600		sc->sc_current_status = 0;
601		cfumass_transfer_start(sc, CFUMASS_T_STATUS);
602
603		return (1);
604	default:
605		break;
606	}
607
608	return (0);
609}
610
611static void
612cfumass_t_command_callback(struct usb_xfer *xfer, usb_error_t usb_error)
613{
614	struct cfumass_softc *sc;
615	uint32_t signature;
616	union ctl_io *io;
617	int error = 0;
618
619	sc = usbd_xfer_softc(xfer);
620
621	KASSERT(sc->sc_ctl_io == NULL,
622	    ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io));
623
624	switch (USB_GET_STATE(xfer)) {
625	case USB_ST_TRANSFERRED:
626		CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED");
627
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);
632			break;
633		}
634
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));
639			break;
640		}
641
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;
648
649		/*
650		 * Make sure to report proper residue if the datamove wasn't
651		 * required, or wasn't called due to SCSI error.
652		 */
653		sc->sc_current_residue = sc->sc_current_transfer_length;
654
655		if (cfumass_quirk(sc,
656		    sc->sc_cbw->CBWCB, sc->sc_cbw->bCDBLength) != 0)
657			break;
658
659		if (!cfumass_port_online) {
660			CFUMASS_DEBUG(sc, "cfumass port is offline; stalling");
661			usbd_xfer_set_stall(xfer);
662			break;
663		}
664
665		/*
666		 * Those CTL functions cannot be called with mutex held.
667		 */
668		CFUMASS_UNLOCK(sc);
669		io = ctl_alloc_io(cfumass_port.ctl_pool_ref);
670		ctl_zero_io(io);
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) {
683			CFUMASS_WARN(sc,
684			    "ctl_queue() failed; error %d; stalling", error);
685			ctl_free_io(io);
686			refcount_release(&sc->sc_queued);
687			CFUMASS_LOCK(sc);
688			usbd_xfer_set_stall(xfer);
689			break;
690		}
691
692		CFUMASS_LOCK(sc);
693		break;
694
695	case USB_ST_SETUP:
696tr_setup:
697		CFUMASS_DEBUG(sc, "USB_ST_SETUP");
698
699		usbd_xfer_set_frame_len(xfer, 0, sizeof(*sc->sc_cbw));
700		usbd_transfer_submit(xfer);
701		break;
702
703	default:
704		if (usb_error == USB_ERR_CANCELLED) {
705			CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED");
706			break;
707		}
708
709		CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s", usbd_errstr(usb_error));
710
711		goto tr_setup;
712	}
713}
714
715static void
716cfumass_t_data_callback(struct usb_xfer *xfer, usb_error_t usb_error)
717{
718	struct cfumass_softc *sc = usbd_xfer_softc(xfer);
719	union ctl_io *io = sc->sc_ctl_io;
720	uint32_t max_bulk;
721	struct ctl_sg_entry sg_entry, *sglist;
722	int actlen, sumlen, sg_count;
723
724	switch (USB_GET_STATE(xfer)) {
725	case USB_ST_TRANSFERRED:
726		CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED");
727
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);
737			break;
738		}
739		/* FALLTHROUGH */
740
741	case USB_ST_SETUP:
742tr_setup:
743		CFUMASS_DEBUG(sc, "USB_ST_SETUP");
744
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;
748		} else {
749			sglist = &sg_entry;
750			sglist->addr = io->scsiio.kern_data_ptr;
751			sglist->len = io->scsiio.kern_data_len;
752			sg_count = 1;
753		}
754
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;
759			sglist++;
760			sg_count--;
761		}
762		KASSERT(sg_count > 0, ("Run out of S/G list entries"));
763
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);
772
773		usbd_xfer_set_frame_data(xfer, 0,
774		    (uint8_t *)sglist->addr + sumlen, actlen);
775		usbd_transfer_submit(xfer);
776		break;
777
778	default:
779		if (usb_error == USB_ERR_CANCELLED) {
780			CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED");
781			break;
782		}
783		CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s", usbd_errstr(usb_error));
784		goto tr_setup;
785	}
786}
787
788static void
789cfumass_t_status_callback(struct usb_xfer *xfer, usb_error_t usb_error)
790{
791	struct cfumass_softc *sc;
792
793	sc = usbd_xfer_softc(xfer);
794
795	KASSERT(sc->sc_ctl_io == NULL,
796	    ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io));
797
798	switch (USB_GET_STATE(xfer)) {
799	case USB_ST_TRANSFERRED:
800		CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED");
801
802		cfumass_transfer_start(sc, CFUMASS_T_COMMAND);
803		break;
804
805	case USB_ST_SETUP:
806tr_setup:
807		CFUMASS_DEBUG(sc, "USB_ST_SETUP");
808
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;
813		}
814
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;
819
820		usbd_xfer_set_frame_len(xfer, 0, sizeof(*sc->sc_csw));
821		usbd_transfer_submit(xfer);
822		break;
823
824	default:
825		if (usb_error == USB_ERR_CANCELLED) {
826			CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED");
827			break;
828		}
829
830		CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s",
831		    usbd_errstr(usb_error));
832
833		goto tr_setup;
834	}
835}
836
837static void
838cfumass_online(void *arg __unused)
839{
840
841	cfumass_port_online = true;
842}
843
844static void
845cfumass_offline(void *arg __unused)
846{
847
848	cfumass_port_online = false;
849}
850
851static void
852cfumass_datamove(union ctl_io *io)
853{
854	struct cfumass_softc *sc;
855
856	sc = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
857
858	CFUMASS_DEBUG(sc, "go");
859
860	CFUMASS_LOCK(sc);
861
862	KASSERT(sc->sc_ctl_io == NULL,
863	    ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io));
864	sc->sc_ctl_io = io;
865
866	if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_IN) {
867		/*
868		 * Verify that CTL wants us to send the data in the direction
869		 * expected by the initiator.
870		 */
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);
874			goto fail;
875		}
876
877		cfumass_transfer_start(sc, CFUMASS_T_DATA_IN);
878	} else {
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);
882			goto fail;
883		}
884
885		cfumass_transfer_start(sc, CFUMASS_T_DATA_OUT);
886	}
887
888	CFUMASS_UNLOCK(sc);
889	return;
890
891fail:
892	ctl_set_data_phase_error(&io->scsiio);
893	io->scsiio.be_move_done(io);
894	sc->sc_ctl_io = NULL;
895}
896
897static void
898cfumass_done(union ctl_io *io)
899{
900	struct cfumass_softc *sc;
901
902	sc = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
903
904	CFUMASS_DEBUG(sc, "go");
905
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));
910
911	if (io->io_hdr.io_type == CTL_IO_TASK &&
912	    io->taskio.task_action == CTL_TASK_I_T_NEXUS_RESET) {
913		/*
914		 * Implicit task termination has just completed; nothing to do.
915		 */
916		ctl_free_io(io);
917		return;
918	}
919
920	/*
921	 * Do not return status for aborted commands.
922	 * There are exceptions, but none supported by CTL yet.
923	 */
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)) {
927		ctl_free_io(io);
928		return;
929	}
930
931	if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS)
932		sc->sc_current_status = 0;
933	else
934		sc->sc_current_status = 1;
935
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)
939		ctl_queue_sense(io);
940	else
941		ctl_free_io(io);
942
943	CFUMASS_LOCK(sc);
944	cfumass_transfer_start(sc, CFUMASS_T_STATUS);
945	CFUMASS_UNLOCK(sc);
946
947	refcount_release(&sc->sc_queued);
948}
949
950int
951cfumass_init(void)
952{
953	int error;
954
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;
967
968	error = ctl_port_register(&cfumass_port);
969	if (error != 0) {
970		printf("%s: ctl_port_register() failed "
971		    "with error %d", __func__, error);
972	}
973
974	cfumass_port_online = true;
975	refcount_init(&cfumass_refcount, 0);
976
977	return (error);
978}
979
980int
981cfumass_shutdown(void)
982{
983	int error;
984
985	if (cfumass_refcount > 0) {
986		if (debug > 1) {
987			printf("%s: still have %u attachments; "
988			    "returning EBUSY\n", __func__, cfumass_refcount);
989		}
990		return (EBUSY);
991	}
992
993	error = ctl_port_deregister(&cfumass_port);
994	if (error != 0) {
995		printf("%s: ctl_port_deregister() failed "
996		    "with error %d\n", __func__, error);
997	}
998
999	return (error);
1000}
1001