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