xref: /freebsd/sys/dev/usb/storage/cfumass.c (revision fdafd315)
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 
68 SYSCTL_NODE(_hw_usb, OID_AUTO, cfumass, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
69     "CAM Target Layer USB Mass Storage Frontend");
70 static int debug = 1;
71 SYSCTL_INT(_hw_usb_cfumass, OID_AUTO, debug, CTLFLAG_RWTUN,
72     &debug, 1, "Enable debug messages");
73 static int max_lun = 0;
74 SYSCTL_INT(_hw_usb_cfumass, OID_AUTO, max_lun, CTLFLAG_RWTUN,
75     &max_lun, 1, "Maximum advertised LUN number");
76 static int ignore_stop = 1;
77 SYSCTL_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  */
86 struct ctl_port	cfumass_port;
87 bool		cfumass_port_online;
88 volatile 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  */
112 struct 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
127 CTASSERT(sizeof(struct cfumass_cbw_t) == CFUMASS_CBW_SIZE);
128 
129 /*
130  * Command Status Wrapper.
131  */
132 struct 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
144 CTASSERT(sizeof(struct cfumass_csw_t) == CFUMASS_CSW_SIZE);
145 
146 struct 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  */
193 static device_probe_t		cfumass_probe;
194 static device_attach_t		cfumass_attach;
195 static device_detach_t		cfumass_detach;
196 static device_suspend_t		cfumass_suspend;
197 static device_resume_t		cfumass_resume;
198 static usb_handle_request_t	cfumass_handle_request;
199 
200 static usb_callback_t		cfumass_t_command_callback;
201 static usb_callback_t		cfumass_t_data_callback;
202 static usb_callback_t		cfumass_t_status_callback;
203 
204 static 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 
218 static driver_t cfumass_driver = {
219 	.name = "cfumass",
220 	.methods = cfumass_methods,
221 	.size = sizeof(struct cfumass_softc),
222 };
223 
224 DRIVER_MODULE(cfumass, uhub, cfumass_driver, NULL, NULL);
225 MODULE_VERSION(cfumass, 0);
226 MODULE_DEPEND(cfumass, usb, 1, 1, 1);
227 MODULE_DEPEND(cfumass, usb_template, 1, 1, 1);
228 
229 static 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  */
275 static int	cfumass_init(void);
276 static int	cfumass_shutdown(void);
277 static void	cfumass_online(void *arg);
278 static void	cfumass_offline(void *arg);
279 static void	cfumass_datamove(union ctl_io *io);
280 static void	cfumass_done(union ctl_io *io);
281 
282 static struct ctl_frontend cfumass_frontend = {
283 	.name = "umass",
284 	.init = cfumass_init,
285 	.shutdown = cfumass_shutdown,
286 };
287 CTL_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 
308 static void	cfumass_transfer_start(struct cfumass_softc *sc,
309 		    uint8_t xfer_index);
310 static void	cfumass_terminate(struct cfumass_softc *sc);
311 
312 static int
cfumass_probe(device_t dev)313 cfumass_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 
337 static int
cfumass_attach(device_t dev)338 cfumass_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 
391 static int
cfumass_detach(device_t dev)392 cfumass_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 
421 static int
cfumass_suspend(device_t dev)422 cfumass_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 
432 static int
cfumass_resume(device_t dev)433 cfumass_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 
443 static void
cfumass_transfer_start(struct cfumass_softc * sc,uint8_t xfer_index)444 cfumass_transfer_start(struct cfumass_softc *sc, uint8_t xfer_index)
445 {
446 
447 	usbd_transfer_start(sc->sc_xfer[xfer_index]);
448 }
449 
450 static void
cfumass_transfer_stop_and_drain(struct cfumass_softc * sc,uint8_t xfer_index)451 cfumass_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 
460 static void
cfumass_terminate(struct cfumass_softc * sc)461 cfumass_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 
490 static int
cfumass_handle_request(device_t dev,const void * preq,void ** pptr,uint16_t * plen,uint16_t offset,uint8_t * pstate)491 cfumass_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 
553 static int
cfumass_quirk(struct cfumass_softc * sc,unsigned char * cdb,int cdb_len)554 cfumass_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 
603 static void
cfumass_t_command_callback(struct usb_xfer * xfer,usb_error_t usb_error)604 cfumass_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:
688 tr_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 
707 static void
cfumass_t_data_callback(struct usb_xfer * xfer,usb_error_t usb_error)708 cfumass_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:
734 tr_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 
780 static void
cfumass_t_status_callback(struct usb_xfer * xfer,usb_error_t usb_error)781 cfumass_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:
798 tr_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 
829 static void
cfumass_online(void * arg __unused)830 cfumass_online(void *arg __unused)
831 {
832 
833 	cfumass_port_online = true;
834 }
835 
836 static void
cfumass_offline(void * arg __unused)837 cfumass_offline(void *arg __unused)
838 {
839 
840 	cfumass_port_online = false;
841 }
842 
843 static void
cfumass_datamove(union ctl_io * io)844 cfumass_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 
883 fail:
884 	ctl_set_data_phase_error(&io->scsiio);
885 	ctl_datamove_done(io, true);
886 	sc->sc_ctl_io = NULL;
887 }
888 
889 static void
cfumass_done(union ctl_io * io)890 cfumass_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 
942 int
cfumass_init(void)943 cfumass_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 
972 int
cfumass_shutdown(void)973 cfumass_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