]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/usb/storage/cfumass.c
usbdevs: sort my prior commit
[FreeBSD/FreeBSD.git] / sys / dev / usb / storage / cfumass.c
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$");
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
72 SYSCTL_NODE(_hw_usb, OID_AUTO, cfumass, CTLFLAG_RW, 0,
73     "CAM Target Layer USB Mass Storage Frontend");
74 static int debug = 1;
75 SYSCTL_INT(_hw_usb_cfumass, OID_AUTO, debug, CTLFLAG_RWTUN,
76     &debug, 1, "Enable debug messages");
77 static int max_lun = 0;
78 SYSCTL_INT(_hw_usb_cfumass, OID_AUTO, max_lun, CTLFLAG_RWTUN,
79     &max_lun, 1, "Maximum advertised LUN number");
80 static int ignore_stop = 1;
81 SYSCTL_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  */
90 struct ctl_port cfumass_port;
91 bool            cfumass_port_online;
92 volatile 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  */
116 struct 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
131 CTASSERT(sizeof(struct cfumass_cbw_t) == CFUMASS_CBW_SIZE);
132
133 /*
134  * Command Status Wrapper.
135  */
136 struct 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
148 CTASSERT(sizeof(struct cfumass_csw_t) == CFUMASS_CSW_SIZE);
149
150 struct 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  */
197 static device_probe_t           cfumass_probe;
198 static device_attach_t          cfumass_attach;
199 static device_detach_t          cfumass_detach;
200 static device_suspend_t         cfumass_suspend;
201 static device_resume_t          cfumass_resume;
202 static usb_handle_request_t     cfumass_handle_request;
203
204 static usb_callback_t           cfumass_t_command_callback;
205 static usb_callback_t           cfumass_t_data_callback;
206 static usb_callback_t           cfumass_t_status_callback;
207
208 static 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
223 static driver_t cfumass_driver = {
224         .name = "cfumass",
225         .methods = cfumass_methods,
226         .size = sizeof(struct cfumass_softc),
227 };
228
229 static devclass_t cfumass_devclass;
230
231 DRIVER_MODULE(cfumass, uhub, cfumass_driver, cfumass_devclass, NULL, 0);
232 MODULE_VERSION(cfumass, 0);
233 MODULE_DEPEND(cfumass, usb, 1, 1, 1);
234 MODULE_DEPEND(cfumass, usb_template, 1, 1, 1);
235
236 static 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  */
283 static int      cfumass_init(void);
284 static int      cfumass_shutdown(void);
285 static void     cfumass_online(void *arg);
286 static void     cfumass_offline(void *arg);
287 static void     cfumass_datamove(union ctl_io *io);
288 static void     cfumass_done(union ctl_io *io);
289
290 static struct ctl_frontend cfumass_frontend = {
291         .name = "umass",
292         .init = cfumass_init,
293         .shutdown = cfumass_shutdown,
294 };
295 CTL_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
316 static void     cfumass_transfer_start(struct cfumass_softc *sc,
317                     uint8_t xfer_index);
318 static void     cfumass_terminate(struct cfumass_softc *sc);
319
320 static int
321 cfumass_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
345 static int
346 cfumass_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
399 static int
400 cfumass_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
429 static int
430 cfumass_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
440 static int
441 cfumass_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
451 static void
452 cfumass_transfer_start(struct cfumass_softc *sc, uint8_t xfer_index)
453 {
454
455         usbd_transfer_start(sc->sc_xfer[xfer_index]);
456 }
457
458 static void
459 cfumass_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
468 static void
469 cfumass_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
498 static int
499 cfumass_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
561 static int
562 cfumass_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
611 static void
612 cfumass_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:
696 tr_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
715 static void
716 cfumass_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:
742 tr_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
788 static void
789 cfumass_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:
806 tr_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
837 static void
838 cfumass_online(void *arg __unused)
839 {
840
841         cfumass_port_online = true;
842 }
843
844 static void
845 cfumass_offline(void *arg __unused)
846 {
847
848         cfumass_port_online = false;
849 }
850
851 static void
852 cfumass_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
891 fail:
892         ctl_set_data_phase_error(&io->scsiio);
893         io->scsiio.be_move_done(io);
894         sc->sc_ctl_io = NULL;
895 }
896
897 static void
898 cfumass_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
950 int
951 cfumass_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
980 int
981 cfumass_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 }