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