cfumass.c revision 317337
1313959Strasz/*- 2313959Strasz * Copyright (c) 2016 The FreeBSD Foundation 3313959Strasz * All rights reserved. 4313959Strasz * 5313959Strasz * This software was developed by Edward Tomasz Napierala under sponsorship 6313959Strasz * from the FreeBSD Foundation. 7313959Strasz * 8313959Strasz * Redistribution and use in source and binary forms, with or without 9313959Strasz * modification, are permitted provided that the following conditions 10313959Strasz * are met: 11313959Strasz * 1. Redistributions of source code must retain the above copyright 12313959Strasz * notice, this list of conditions and the following disclaimer. 13313959Strasz * 2. Redistributions in binary form must reproduce the above copyright 14313959Strasz * notice, this list of conditions and the following disclaimer in the 15313959Strasz * documentation and/or other materials provided with the distribution. 16313959Strasz * 17313959Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18313959Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19313959Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20313959Strasz * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21313959Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22313959Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23313959Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24313959Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25313959Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26313959Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27313959Strasz * SUCH DAMAGE. 28313959Strasz * 29313959Strasz */ 30313959Strasz/* 31313959Strasz * USB Mass Storage Class Bulk-Only (BBB) Transport target. 32313959Strasz * 33313959Strasz * http://www.usb.org/developers/docs/devclass_docs/usbmassbulk_10.pdf 34313959Strasz * 35313959Strasz * This code implements the USB Mass Storage frontend driver for the CAM 36313959Strasz * Target Layer (ctl(4)) subsystem. 37313959Strasz */ 38313959Strasz 39313959Strasz#include <sys/cdefs.h> 40313959Strasz__FBSDID("$FreeBSD: stable/11/sys/dev/usb/storage/cfumass.c 317337 2017-04-23 09:01:01Z mav $"); 41313959Strasz 42313959Strasz#include <sys/param.h> 43313959Strasz#include <sys/bus.h> 44313959Strasz#include <sys/kernel.h> 45313959Strasz#include <sys/lock.h> 46313959Strasz#include <sys/module.h> 47313959Strasz#include <sys/mutex.h> 48313959Strasz#include <sys/refcount.h> 49313959Strasz#include <sys/stdint.h> 50313959Strasz#include <sys/sysctl.h> 51313959Strasz#include <sys/systm.h> 52313959Strasz 53313959Strasz#include <dev/usb/usb.h> 54313959Strasz#include <dev/usb/usbdi.h> 55313959Strasz#include "usbdevs.h" 56313959Strasz#include "usb_if.h" 57313959Strasz 58313959Strasz#include <cam/scsi/scsi_all.h> 59313959Strasz#include <cam/scsi/scsi_da.h> 60313959Strasz#include <cam/ctl/ctl_io.h> 61313959Strasz#include <cam/ctl/ctl.h> 62313959Strasz#include <cam/ctl/ctl_backend.h> 63313959Strasz#include <cam/ctl/ctl_error.h> 64313959Strasz#include <cam/ctl/ctl_frontend.h> 65313959Strasz#include <cam/ctl/ctl_debug.h> 66313959Strasz#include <cam/ctl/ctl_ha.h> 67313959Strasz#include <cam/ctl/ctl_ioctl.h> 68313959Strasz#include <cam/ctl/ctl_private.h> 69313959Strasz 70313959StraszSYSCTL_NODE(_hw_usb, OID_AUTO, cfumass, CTLFLAG_RW, 0, 71313959Strasz "CAM Target Layer USB Mass Storage Frontend"); 72313959Straszstatic int debug = 1; 73313959StraszSYSCTL_INT(_hw_usb_cfumass, OID_AUTO, debug, CTLFLAG_RWTUN, 74313959Strasz &debug, 1, "Enable debug messages"); 75313959Straszstatic int max_lun = 0; 76313959StraszSYSCTL_INT(_hw_usb_cfumass, OID_AUTO, max_lun, CTLFLAG_RWTUN, 77313959Strasz &max_lun, 1, "Maximum advertised LUN number"); 78313959Straszstatic int ignore_stop = 1; 79313959StraszSYSCTL_INT(_hw_usb_cfumass, OID_AUTO, ignore_stop, CTLFLAG_RWTUN, 80313959Strasz &ignore_stop, 1, "Ignore START STOP UNIT with START and LOEJ bits cleared"); 81313959Strasz 82313959Strasz/* 83313959Strasz * The driver uses a single, global CTL port. It could create its ports 84313959Strasz * in cfumass_attach() instead, but that would make it impossible to specify 85313959Strasz * "port cfumass0" in ctl.conf(5), as the port generally wouldn't exist 86313959Strasz * at the time ctld(8) gets run. 87313959Strasz */ 88313959Straszstruct ctl_port cfumass_port; 89313959Straszbool cfumass_port_online; 90313959Straszvolatile u_int cfumass_refcount; 91313959Strasz 92313959Strasz#ifndef CFUMASS_BULK_SIZE 93313959Strasz#define CFUMASS_BULK_SIZE (1U << 17) /* bytes */ 94313959Strasz#endif 95313959Strasz 96313959Strasz/* 97313959Strasz * USB transfer definitions. 98313959Strasz */ 99313959Strasz#define CFUMASS_T_COMMAND 0 100313959Strasz#define CFUMASS_T_DATA_OUT 1 101313959Strasz#define CFUMASS_T_DATA_IN 2 102313959Strasz#define CFUMASS_T_STATUS 3 103313959Strasz#define CFUMASS_T_MAX 4 104313959Strasz 105313959Strasz/* 106313959Strasz * USB interface specific control requests. 107313959Strasz */ 108313959Strasz#define UR_RESET 0xff /* Bulk-Only Mass Storage Reset */ 109313959Strasz#define UR_GET_MAX_LUN 0xfe /* Get Max LUN */ 110313959Strasz 111313959Strasz/* 112313959Strasz * Command Block Wrapper. 113313959Strasz */ 114313959Straszstruct cfumass_cbw_t { 115313959Strasz uDWord dCBWSignature; 116313959Strasz#define CBWSIGNATURE 0x43425355 /* "USBC" */ 117313959Strasz uDWord dCBWTag; 118313959Strasz uDWord dCBWDataTransferLength; 119313959Strasz uByte bCBWFlags; 120313959Strasz#define CBWFLAGS_OUT 0x00 121313959Strasz#define CBWFLAGS_IN 0x80 122313959Strasz uByte bCBWLUN; 123313959Strasz uByte bCDBLength; 124313959Strasz#define CBWCBLENGTH 16 125313959Strasz uByte CBWCB[CBWCBLENGTH]; 126313959Strasz} __packed; 127313959Strasz 128313959Strasz#define CFUMASS_CBW_SIZE 31 129313959StraszCTASSERT(sizeof(struct cfumass_cbw_t) == CFUMASS_CBW_SIZE); 130313959Strasz 131313959Strasz/* 132313959Strasz * Command Status Wrapper. 133313959Strasz */ 134313959Straszstruct cfumass_csw_t { 135313959Strasz uDWord dCSWSignature; 136313959Strasz#define CSWSIGNATURE 0x53425355 /* "USBS" */ 137313959Strasz uDWord dCSWTag; 138313959Strasz uDWord dCSWDataResidue; 139313959Strasz uByte bCSWStatus; 140313959Strasz#define CSWSTATUS_GOOD 0x0 141313959Strasz#define CSWSTATUS_FAILED 0x1 142313959Strasz#define CSWSTATUS_PHASE 0x2 143313959Strasz} __packed; 144313959Strasz 145313959Strasz#define CFUMASS_CSW_SIZE 13 146313959StraszCTASSERT(sizeof(struct cfumass_csw_t) == CFUMASS_CSW_SIZE); 147313959Strasz 148313959Straszstruct cfumass_softc { 149313959Strasz device_t sc_dev; 150313959Strasz struct usb_device *sc_udev; 151313959Strasz struct usb_xfer *sc_xfer[CFUMASS_T_MAX]; 152313959Strasz 153313959Strasz struct cfumass_cbw_t *sc_cbw; 154313959Strasz struct cfumass_csw_t *sc_csw; 155313959Strasz 156313959Strasz struct mtx sc_mtx; 157313959Strasz int sc_online; 158313959Strasz int sc_ctl_initid; 159313959Strasz 160313959Strasz /* 161313959Strasz * This is used to communicate between CTL callbacks 162313959Strasz * and USB callbacks; basically, it holds the state 163313959Strasz * for the current command ("the" command, since there 164313959Strasz * is no queueing in USB Mass Storage). 165313959Strasz */ 166313959Strasz bool sc_current_stalled; 167313959Strasz 168313959Strasz /* 169313959Strasz * The following are set upon receiving a SCSI command. 170313959Strasz */ 171313959Strasz int sc_current_tag; 172313959Strasz int sc_current_transfer_length; 173313959Strasz int sc_current_flags; 174313959Strasz 175313959Strasz /* 176313959Strasz * The following are set in ctl_datamove(). 177313959Strasz */ 178313959Strasz int sc_current_residue; 179313959Strasz union ctl_io *sc_ctl_io; 180313959Strasz 181313959Strasz /* 182313959Strasz * The following is set in cfumass_done(). 183313959Strasz */ 184313959Strasz int sc_current_status; 185313959Strasz 186313959Strasz /* 187313959Strasz * Number of requests queued to CTL. 188313959Strasz */ 189313959Strasz volatile u_int sc_queued; 190313959Strasz}; 191313959Strasz 192313959Strasz/* 193313959Strasz * USB interface. 194313959Strasz */ 195313959Straszstatic device_probe_t cfumass_probe; 196313959Straszstatic device_attach_t cfumass_attach; 197313959Straszstatic device_detach_t cfumass_detach; 198313959Straszstatic device_suspend_t cfumass_suspend; 199313959Straszstatic device_resume_t cfumass_resume; 200313959Straszstatic usb_handle_request_t cfumass_handle_request; 201313959Strasz 202313959Straszstatic usb_callback_t cfumass_t_command_callback; 203313959Straszstatic usb_callback_t cfumass_t_data_out_callback; 204313959Straszstatic usb_callback_t cfumass_t_data_in_callback; 205313959Straszstatic usb_callback_t cfumass_t_status_callback; 206313959Strasz 207313959Straszstatic device_method_t cfumass_methods[] = { 208313959Strasz 209313959Strasz /* USB interface. */ 210313959Strasz DEVMETHOD(usb_handle_request, cfumass_handle_request), 211313959Strasz 212313959Strasz /* Device interface. */ 213313959Strasz DEVMETHOD(device_probe, cfumass_probe), 214313959Strasz DEVMETHOD(device_attach, cfumass_attach), 215313959Strasz DEVMETHOD(device_detach, cfumass_detach), 216313959Strasz DEVMETHOD(device_suspend, cfumass_suspend), 217313959Strasz DEVMETHOD(device_resume, cfumass_resume), 218313959Strasz 219313959Strasz DEVMETHOD_END 220313959Strasz}; 221313959Strasz 222313959Straszstatic driver_t cfumass_driver = { 223313959Strasz .name = "cfumass", 224313959Strasz .methods = cfumass_methods, 225313959Strasz .size = sizeof(struct cfumass_softc), 226313959Strasz}; 227313959Strasz 228313959Straszstatic devclass_t cfumass_devclass; 229313959Strasz 230313959StraszDRIVER_MODULE(cfumass, uhub, cfumass_driver, cfumass_devclass, NULL, 0); 231313959StraszMODULE_VERSION(cfumass, 0); 232313959StraszMODULE_DEPEND(cfumass, usb, 1, 1, 1); 233313959StraszMODULE_DEPEND(cfumass, usb_template, 1, 1, 1); 234313959Strasz 235313959Straszstatic struct usb_config cfumass_config[CFUMASS_T_MAX] = { 236313959Strasz 237313959Strasz [CFUMASS_T_COMMAND] = { 238313959Strasz .type = UE_BULK, 239313959Strasz .endpoint = UE_ADDR_ANY, 240313959Strasz .direction = UE_DIR_OUT, 241313959Strasz .bufsize = sizeof(struct cfumass_cbw_t), 242313959Strasz .callback = &cfumass_t_command_callback, 243313959Strasz .usb_mode = USB_MODE_DEVICE, 244313959Strasz }, 245313959Strasz 246313959Strasz [CFUMASS_T_DATA_OUT] = { 247313959Strasz .type = UE_BULK, 248313959Strasz .endpoint = UE_ADDR_ANY, 249313959Strasz .direction = UE_DIR_OUT, 250313959Strasz .bufsize = CFUMASS_BULK_SIZE, 251313959Strasz .flags = {.proxy_buffer = 1, .short_xfer_ok = 1, 252313959Strasz .ext_buffer = 1}, 253313959Strasz .callback = &cfumass_t_data_out_callback, 254313959Strasz .usb_mode = USB_MODE_DEVICE, 255313959Strasz }, 256313959Strasz 257313959Strasz [CFUMASS_T_DATA_IN] = { 258313959Strasz .type = UE_BULK, 259313959Strasz .endpoint = UE_ADDR_ANY, 260313959Strasz .direction = UE_DIR_IN, 261313959Strasz .bufsize = CFUMASS_BULK_SIZE, 262313959Strasz .flags = {.proxy_buffer = 1, .short_xfer_ok = 1, 263313959Strasz .ext_buffer = 1}, 264313959Strasz .callback = &cfumass_t_data_in_callback, 265313959Strasz .usb_mode = USB_MODE_DEVICE, 266313959Strasz }, 267313959Strasz 268313959Strasz [CFUMASS_T_STATUS] = { 269313959Strasz .type = UE_BULK, 270313959Strasz .endpoint = UE_ADDR_ANY, 271313959Strasz .direction = UE_DIR_IN, 272313959Strasz .bufsize = sizeof(struct cfumass_csw_t), 273313959Strasz .flags = {.short_xfer_ok = 1}, 274313959Strasz .callback = &cfumass_t_status_callback, 275313959Strasz .usb_mode = USB_MODE_DEVICE, 276313959Strasz }, 277313959Strasz}; 278313959Strasz 279313959Strasz/* 280313959Strasz * CTL frontend interface. 281313959Strasz */ 282313959Straszstatic int cfumass_init(void); 283313959Straszstatic int cfumass_shutdown(void); 284313959Straszstatic void cfumass_online(void *arg); 285313959Straszstatic void cfumass_offline(void *arg); 286313959Straszstatic void cfumass_datamove(union ctl_io *io); 287313959Straszstatic void cfumass_done(union ctl_io *io); 288313959Strasz 289313959Straszstatic struct ctl_frontend cfumass_frontend = { 290313959Strasz .name = "umass", 291313959Strasz .init = cfumass_init, 292313959Strasz .shutdown = cfumass_shutdown, 293313959Strasz}; 294313959StraszCTL_FRONTEND_DECLARE(ctlcfumass, cfumass_frontend); 295313959Strasz 296313959Strasz#define CFUMASS_DEBUG(S, X, ...) \ 297313959Strasz do { \ 298313959Strasz if (debug > 1) { \ 299313959Strasz device_printf(S->sc_dev, "%s: " X "\n", \ 300313959Strasz __func__, ## __VA_ARGS__); \ 301313959Strasz } \ 302313959Strasz } while (0) 303313959Strasz 304313959Strasz#define CFUMASS_WARN(S, X, ...) \ 305313959Strasz do { \ 306313959Strasz if (debug > 0) { \ 307313959Strasz device_printf(S->sc_dev, "WARNING: %s: " X "\n",\ 308313959Strasz __func__, ## __VA_ARGS__); \ 309313959Strasz } \ 310313959Strasz } while (0) 311313959Strasz 312313959Strasz#define CFUMASS_LOCK(X) mtx_lock(&X->sc_mtx) 313313959Strasz#define CFUMASS_UNLOCK(X) mtx_unlock(&X->sc_mtx) 314313959Strasz 315313959Straszstatic void cfumass_transfer_start(struct cfumass_softc *sc, 316313959Strasz uint8_t xfer_index); 317313959Straszstatic void cfumass_terminate(struct cfumass_softc *sc); 318313959Strasz 319313959Straszstatic int 320313959Straszcfumass_probe(device_t dev) 321313959Strasz{ 322313959Strasz struct usb_attach_arg *uaa; 323313959Strasz struct usb_interface_descriptor *id; 324313959Strasz 325313959Strasz uaa = device_get_ivars(dev); 326313959Strasz 327313959Strasz if (uaa->usb_mode != USB_MODE_DEVICE) 328313959Strasz return (ENXIO); 329313959Strasz 330313959Strasz /* 331313959Strasz * Check for a compliant device. 332313959Strasz */ 333313959Strasz id = usbd_get_interface_descriptor(uaa->iface); 334313959Strasz if ((id == NULL) || 335313959Strasz (id->bInterfaceClass != UICLASS_MASS) || 336313959Strasz (id->bInterfaceSubClass != UISUBCLASS_SCSI) || 337313959Strasz (id->bInterfaceProtocol != UIPROTO_MASS_BBB)) { 338313959Strasz return (ENXIO); 339313959Strasz } 340313959Strasz 341313959Strasz return (BUS_PROBE_GENERIC); 342313959Strasz} 343313959Strasz 344313959Straszstatic int 345313959Straszcfumass_attach(device_t dev) 346313959Strasz{ 347313959Strasz struct cfumass_softc *sc; 348313959Strasz struct usb_attach_arg *uaa; 349313959Strasz int error; 350313959Strasz 351313959Strasz sc = device_get_softc(dev); 352313959Strasz uaa = device_get_ivars(dev); 353313959Strasz 354313959Strasz sc->sc_dev = dev; 355313959Strasz sc->sc_udev = uaa->device; 356313959Strasz 357313959Strasz CFUMASS_DEBUG(sc, "go"); 358313959Strasz 359313959Strasz usbd_set_power_mode(uaa->device, USB_POWER_MODE_SAVE); 360313959Strasz device_set_usb_desc(dev); 361313959Strasz 362313959Strasz mtx_init(&sc->sc_mtx, "cfumass", NULL, MTX_DEF); 363313959Strasz refcount_acquire(&cfumass_refcount); 364313959Strasz 365313959Strasz error = usbd_transfer_setup(uaa->device, 366313959Strasz &uaa->info.bIfaceIndex, sc->sc_xfer, cfumass_config, 367313959Strasz CFUMASS_T_MAX, sc, &sc->sc_mtx); 368313959Strasz if (error != 0) { 369313959Strasz CFUMASS_WARN(sc, "usbd_transfer_setup() failed: %s", 370313959Strasz usbd_errstr(error)); 371313959Strasz refcount_release(&cfumass_refcount); 372313959Strasz return (ENXIO); 373313959Strasz } 374313959Strasz 375313959Strasz sc->sc_cbw = 376313959Strasz usbd_xfer_get_frame_buffer(sc->sc_xfer[CFUMASS_T_COMMAND], 0); 377313959Strasz sc->sc_csw = 378313959Strasz usbd_xfer_get_frame_buffer(sc->sc_xfer[CFUMASS_T_STATUS], 0); 379313959Strasz 380313959Strasz sc->sc_ctl_initid = ctl_add_initiator(&cfumass_port, -1, 0, NULL); 381313959Strasz if (sc->sc_ctl_initid < 0) { 382313959Strasz CFUMASS_WARN(sc, "ctl_add_initiator() failed with error %d", 383313959Strasz sc->sc_ctl_initid); 384313959Strasz usbd_transfer_unsetup(sc->sc_xfer, CFUMASS_T_MAX); 385313959Strasz refcount_release(&cfumass_refcount); 386313959Strasz return (ENXIO); 387313959Strasz } 388313959Strasz 389313959Strasz refcount_init(&sc->sc_queued, 0); 390313959Strasz 391313959Strasz CFUMASS_LOCK(sc); 392313959Strasz cfumass_transfer_start(sc, CFUMASS_T_COMMAND); 393313959Strasz CFUMASS_UNLOCK(sc); 394313959Strasz 395313959Strasz return (0); 396313959Strasz} 397313959Strasz 398313959Straszstatic int 399313959Straszcfumass_detach(device_t dev) 400313959Strasz{ 401313959Strasz struct cfumass_softc *sc; 402313959Strasz int error; 403313959Strasz 404313959Strasz sc = device_get_softc(dev); 405313959Strasz 406313959Strasz CFUMASS_DEBUG(sc, "go"); 407313959Strasz 408313959Strasz CFUMASS_LOCK(sc); 409313959Strasz cfumass_terminate(sc); 410313959Strasz CFUMASS_UNLOCK(sc); 411313959Strasz usbd_transfer_unsetup(sc->sc_xfer, CFUMASS_T_MAX); 412313959Strasz 413313959Strasz if (sc->sc_ctl_initid != -1) { 414313959Strasz error = ctl_remove_initiator(&cfumass_port, sc->sc_ctl_initid); 415313959Strasz if (error != 0) { 416313959Strasz CFUMASS_WARN(sc, "ctl_remove_initiator() failed " 417313959Strasz "with error %d", error); 418313959Strasz } 419313959Strasz sc->sc_ctl_initid = -1; 420313959Strasz } 421313959Strasz 422313959Strasz mtx_destroy(&sc->sc_mtx); 423313959Strasz refcount_release(&cfumass_refcount); 424313959Strasz 425313959Strasz return (0); 426313959Strasz} 427313959Strasz 428313959Straszstatic int 429313959Straszcfumass_suspend(device_t dev) 430313959Strasz{ 431313959Strasz struct cfumass_softc *sc; 432313959Strasz 433313959Strasz sc = device_get_softc(dev); 434313959Strasz CFUMASS_DEBUG(sc, "go"); 435313959Strasz 436313959Strasz return (0); 437313959Strasz} 438313959Strasz 439313959Straszstatic int 440313959Straszcfumass_resume(device_t dev) 441313959Strasz{ 442313959Strasz struct cfumass_softc *sc; 443313959Strasz 444313959Strasz sc = device_get_softc(dev); 445313959Strasz CFUMASS_DEBUG(sc, "go"); 446313959Strasz 447313959Strasz return (0); 448313959Strasz} 449313959Strasz 450313959Straszstatic void 451313959Straszcfumass_transfer_start(struct cfumass_softc *sc, uint8_t xfer_index) 452313959Strasz{ 453313959Strasz 454313959Strasz usbd_transfer_start(sc->sc_xfer[xfer_index]); 455313959Strasz} 456313959Strasz 457313959Straszstatic void 458313959Straszcfumass_transfer_stop_and_drain(struct cfumass_softc *sc, uint8_t xfer_index) 459313959Strasz{ 460313959Strasz 461313959Strasz usbd_transfer_stop(sc->sc_xfer[xfer_index]); 462313959Strasz CFUMASS_UNLOCK(sc); 463313959Strasz usbd_transfer_drain(sc->sc_xfer[xfer_index]); 464313959Strasz CFUMASS_LOCK(sc); 465313959Strasz} 466313959Strasz 467313959Straszstatic void 468313959Straszcfumass_terminate(struct cfumass_softc *sc) 469313959Strasz{ 470313959Strasz int last; 471313959Strasz 472313959Strasz for (;;) { 473313959Strasz cfumass_transfer_stop_and_drain(sc, CFUMASS_T_COMMAND); 474313959Strasz cfumass_transfer_stop_and_drain(sc, CFUMASS_T_DATA_IN); 475313959Strasz cfumass_transfer_stop_and_drain(sc, CFUMASS_T_DATA_OUT); 476313959Strasz 477313959Strasz if (sc->sc_ctl_io != NULL) { 478313959Strasz CFUMASS_DEBUG(sc, "terminating CTL transfer"); 479313959Strasz ctl_set_data_phase_error(&sc->sc_ctl_io->scsiio); 480313959Strasz sc->sc_ctl_io->scsiio.be_move_done(sc->sc_ctl_io); 481313959Strasz sc->sc_ctl_io = NULL; 482313959Strasz } 483313959Strasz 484313959Strasz cfumass_transfer_stop_and_drain(sc, CFUMASS_T_STATUS); 485313959Strasz 486313959Strasz refcount_acquire(&sc->sc_queued); 487313959Strasz last = refcount_release(&sc->sc_queued); 488313959Strasz if (last != 0) 489313959Strasz break; 490313959Strasz 491313959Strasz CFUMASS_DEBUG(sc, "%d CTL tasks pending", sc->sc_queued); 492313959Strasz msleep(__DEVOLATILE(void *, &sc->sc_queued), &sc->sc_mtx, 493313959Strasz 0, "cfumass_reset", hz / 100); 494313959Strasz } 495313959Strasz} 496313959Strasz 497313959Straszstatic int 498313959Straszcfumass_handle_request(device_t dev, 499313959Strasz const void *preq, void **pptr, uint16_t *plen, 500313959Strasz uint16_t offset, uint8_t *pstate) 501313959Strasz{ 502313959Strasz static uint8_t max_lun_tmp; 503313959Strasz struct cfumass_softc *sc; 504313959Strasz const struct usb_device_request *req; 505313959Strasz uint8_t is_complete; 506313959Strasz 507313959Strasz sc = device_get_softc(dev); 508313959Strasz req = preq; 509313959Strasz is_complete = *pstate; 510313959Strasz 511313959Strasz CFUMASS_DEBUG(sc, "go"); 512313959Strasz 513313959Strasz if (is_complete) 514313959Strasz return (ENXIO); 515313959Strasz 516313959Strasz if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) && 517313959Strasz (req->bRequest == UR_RESET)) { 518313959Strasz CFUMASS_WARN(sc, "received Bulk-Only Mass Storage Reset"); 519313959Strasz *plen = 0; 520313959Strasz 521313959Strasz CFUMASS_LOCK(sc); 522313959Strasz cfumass_terminate(sc); 523313959Strasz cfumass_transfer_start(sc, CFUMASS_T_COMMAND); 524313959Strasz CFUMASS_UNLOCK(sc); 525313959Strasz 526313959Strasz CFUMASS_DEBUG(sc, "Bulk-Only Mass Storage Reset done"); 527313959Strasz return (0); 528313959Strasz } 529313959Strasz 530313959Strasz if ((req->bmRequestType == UT_READ_CLASS_INTERFACE) && 531313959Strasz (req->bRequest == UR_GET_MAX_LUN)) { 532313959Strasz CFUMASS_DEBUG(sc, "received Get Max LUN"); 533313959Strasz if (offset == 0) { 534313959Strasz *plen = 1; 535313959Strasz /* 536313959Strasz * The protocol doesn't support LUN numbers higher 537313959Strasz * than 15. Also, some initiators (namely Windows XP 538313959Strasz * SP3 Version 2002) can't properly query the number 539313959Strasz * of LUNs, resulting in inaccessible "fake" ones - thus 540313959Strasz * the default limit of one LUN. 541313959Strasz */ 542313959Strasz if (max_lun < 0 || max_lun > 15) { 543313959Strasz CFUMASS_WARN(sc, 544313959Strasz "invalid hw.usb.cfumass.max_lun, must be " 545313959Strasz "between 0 and 15; defaulting to 0"); 546313959Strasz max_lun_tmp = 0; 547313959Strasz } else { 548313959Strasz max_lun_tmp = max_lun; 549313959Strasz } 550313959Strasz *pptr = &max_lun_tmp; 551313959Strasz } else { 552313959Strasz *plen = 0; 553313959Strasz } 554313959Strasz return (0); 555313959Strasz } 556313959Strasz 557313959Strasz return (ENXIO); 558313959Strasz} 559313959Strasz 560313959Straszstatic int 561313959Straszcfumass_quirk(struct cfumass_softc *sc, unsigned char *cdb, int cdb_len) 562313959Strasz{ 563313959Strasz struct scsi_start_stop_unit *sssu; 564313959Strasz 565313959Strasz switch (cdb[0]) { 566313959Strasz case START_STOP_UNIT: 567313959Strasz /* 568313959Strasz * Some initiators - eg OSX, Darwin Kernel Version 15.6.0, 569313959Strasz * root:xnu-3248.60.11~2/RELEASE_X86_64 - attempt to stop 570313959Strasz * the unit on eject, but fail to start it when it's plugged 571313959Strasz * back. Just ignore the command. 572313959Strasz */ 573313959Strasz 574313959Strasz if (cdb_len < sizeof(*sssu)) { 575313959Strasz CFUMASS_DEBUG(sc, "received START STOP UNIT with " 576313959Strasz "bCDBLength %d, should be %zd", 577313959Strasz cdb_len, sizeof(*sssu)); 578313959Strasz break; 579313959Strasz } 580313959Strasz 581313959Strasz sssu = (struct scsi_start_stop_unit *)cdb; 582313959Strasz if ((sssu->how & SSS_PC_MASK) != 0) 583313959Strasz break; 584313959Strasz 585313959Strasz if ((sssu->how & SSS_START) != 0) 586313959Strasz break; 587313959Strasz 588313959Strasz if ((sssu->how & SSS_LOEJ) != 0) 589313959Strasz break; 590313959Strasz 591313959Strasz if (ignore_stop == 0) { 592313959Strasz break; 593313959Strasz } else if (ignore_stop == 1) { 594313959Strasz CFUMASS_WARN(sc, "ignoring START STOP UNIT request"); 595313959Strasz } else { 596313959Strasz CFUMASS_DEBUG(sc, "ignoring START STOP UNIT request"); 597313959Strasz } 598313959Strasz 599313959Strasz sc->sc_current_status = 0; 600313959Strasz cfumass_transfer_start(sc, CFUMASS_T_STATUS); 601313959Strasz 602313959Strasz return (1); 603313959Strasz default: 604313959Strasz break; 605313959Strasz } 606313959Strasz 607313959Strasz return (0); 608313959Strasz} 609313959Strasz 610313959Straszstatic void 611313959Straszcfumass_t_command_callback(struct usb_xfer *xfer, usb_error_t usb_error) 612313959Strasz{ 613313959Strasz struct cfumass_softc *sc; 614313959Strasz uint32_t signature; 615313959Strasz union ctl_io *io; 616313959Strasz int error = 0; 617313959Strasz 618313959Strasz sc = usbd_xfer_softc(xfer); 619313959Strasz 620313959Strasz KASSERT(sc->sc_ctl_io == NULL, 621313959Strasz ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io)); 622313959Strasz 623313959Strasz switch (USB_GET_STATE(xfer)) { 624313959Strasz case USB_ST_TRANSFERRED: 625313959Strasz CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED"); 626313959Strasz 627313959Strasz signature = UGETDW(sc->sc_cbw->dCBWSignature); 628313959Strasz if (signature != CBWSIGNATURE) { 629313959Strasz CFUMASS_WARN(sc, "wrong dCBWSignature 0x%08x, " 630313959Strasz "should be 0x%08x", signature, CBWSIGNATURE); 631313959Strasz break; 632313959Strasz } 633313959Strasz 634313959Strasz if (sc->sc_cbw->bCDBLength <= 0 || 635313959Strasz sc->sc_cbw->bCDBLength > sizeof(sc->sc_cbw->CBWCB)) { 636313959Strasz CFUMASS_WARN(sc, "invalid bCDBLength %d, should be <= %zd", 637313959Strasz sc->sc_cbw->bCDBLength, sizeof(sc->sc_cbw->CBWCB)); 638313959Strasz break; 639313959Strasz } 640313959Strasz 641313959Strasz sc->sc_current_stalled = false; 642313959Strasz sc->sc_current_status = 0; 643313959Strasz sc->sc_current_tag = UGETDW(sc->sc_cbw->dCBWTag); 644313959Strasz sc->sc_current_transfer_length = 645313959Strasz UGETDW(sc->sc_cbw->dCBWDataTransferLength); 646313959Strasz sc->sc_current_flags = sc->sc_cbw->bCBWFlags; 647313959Strasz 648313959Strasz /* 649313959Strasz * Make sure to report proper residue if the datamove wasn't 650313959Strasz * required, or wasn't called due to SCSI error. 651313959Strasz */ 652313959Strasz sc->sc_current_residue = sc->sc_current_transfer_length; 653313959Strasz 654313959Strasz if (cfumass_quirk(sc, 655313959Strasz sc->sc_cbw->CBWCB, sc->sc_cbw->bCDBLength) != 0) 656313959Strasz break; 657313959Strasz 658313959Strasz if (!cfumass_port_online) { 659313959Strasz CFUMASS_DEBUG(sc, "cfumass port is offline; stalling"); 660313959Strasz usbd_xfer_set_stall(xfer); 661313959Strasz break; 662313959Strasz } 663313959Strasz 664313959Strasz /* 665313959Strasz * Those CTL functions cannot be called with mutex held. 666313959Strasz */ 667313959Strasz CFUMASS_UNLOCK(sc); 668313959Strasz io = ctl_alloc_io(cfumass_port.ctl_pool_ref); 669313959Strasz ctl_zero_io(io); 670313959Strasz io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = sc; 671313959Strasz io->io_hdr.io_type = CTL_IO_SCSI; 672313959Strasz io->io_hdr.nexus.initid = sc->sc_ctl_initid; 673313959Strasz io->io_hdr.nexus.targ_port = cfumass_port.targ_port; 674313959Strasz io->io_hdr.nexus.targ_lun = ctl_decode_lun(sc->sc_cbw->bCBWLUN); 675313959Strasz io->scsiio.tag_num = UGETDW(sc->sc_cbw->dCBWTag); 676313959Strasz io->scsiio.tag_type = CTL_TAG_UNTAGGED; 677313959Strasz io->scsiio.cdb_len = sc->sc_cbw->bCDBLength; 678313959Strasz memcpy(io->scsiio.cdb, sc->sc_cbw->CBWCB, sc->sc_cbw->bCDBLength); 679313959Strasz refcount_acquire(&sc->sc_queued); 680313959Strasz error = ctl_queue(io); 681313959Strasz if (error != CTL_RETVAL_COMPLETE) { 682313959Strasz CFUMASS_WARN(sc, 683313959Strasz "ctl_queue() failed; error %d; stalling", error); 684313959Strasz ctl_free_io(io); 685313959Strasz refcount_release(&sc->sc_queued); 686313959Strasz CFUMASS_LOCK(sc); 687313959Strasz usbd_xfer_set_stall(xfer); 688313959Strasz break; 689313959Strasz } 690313959Strasz 691313959Strasz CFUMASS_LOCK(sc); 692313959Strasz break; 693313959Strasz 694313959Strasz case USB_ST_SETUP: 695313959Strasztr_setup: 696313959Strasz CFUMASS_DEBUG(sc, "USB_ST_SETUP"); 697313959Strasz 698313959Strasz usbd_xfer_set_frame_len(xfer, 0, sizeof(*sc->sc_cbw)); 699313959Strasz usbd_transfer_submit(xfer); 700313959Strasz break; 701313959Strasz 702313959Strasz default: 703313959Strasz if (usb_error == USB_ERR_CANCELLED) { 704313959Strasz CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED"); 705313959Strasz break; 706313959Strasz } 707313959Strasz 708313959Strasz CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s", usbd_errstr(usb_error)); 709313959Strasz 710313959Strasz goto tr_setup; 711313959Strasz } 712313959Strasz} 713313959Strasz 714313959Straszstatic void 715313959Straszcfumass_t_data_out_callback(struct usb_xfer *xfer, usb_error_t usb_error) 716313959Strasz{ 717313959Strasz struct cfumass_softc *sc; 718313959Strasz union ctl_io *io; 719313959Strasz struct ctl_sg_entry ctl_sg_entry, *ctl_sglist; 720313959Strasz int actlen, ctl_sg_count; 721313959Strasz 722313959Strasz sc = usbd_xfer_softc(xfer); 723313959Strasz io = sc->sc_ctl_io; 724313959Strasz 725313959Strasz if (io->scsiio.kern_sg_entries > 0) { 726313959Strasz ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr; 727313959Strasz ctl_sg_count = io->scsiio.kern_sg_entries; 728313959Strasz } else { 729313959Strasz ctl_sglist = &ctl_sg_entry; 730313959Strasz ctl_sglist->addr = io->scsiio.kern_data_ptr; 731313959Strasz ctl_sglist->len = io->scsiio.kern_data_len; 732313959Strasz ctl_sg_count = 1; 733313959Strasz } 734313959Strasz 735313959Strasz switch (USB_GET_STATE(xfer)) { 736313959Strasz case USB_ST_TRANSFERRED: 737313959Strasz CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED"); 738313959Strasz 739317336Smav usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 740313959Strasz if (actlen != ctl_sglist[0].len) { 741313959Strasz KASSERT(actlen <= ctl_sglist[0].len, 742313959Strasz ("actlen %d > ctl_sglist.len %zd", 743313959Strasz actlen, ctl_sglist[0].len)); 744313959Strasz CFUMASS_DEBUG(sc, "host transferred %d bytes" 745313959Strasz "instead of expected %zd bytes", 746313959Strasz actlen, ctl_sglist[0].len); 747313959Strasz } 748317336Smav sc->sc_current_residue -= actlen; 749317336Smav io->scsiio.kern_data_resid -= actlen; 750313959Strasz io->scsiio.be_move_done(io); 751313959Strasz sc->sc_ctl_io = NULL; 752313959Strasz break; 753313959Strasz 754313959Strasz case USB_ST_SETUP: 755313959Strasztr_setup: 756313959Strasz CFUMASS_DEBUG(sc, "USB_ST_SETUP"); 757313959Strasz 758313959Strasz CFUMASS_DEBUG(sc, "requested size %d, CTL segment size %zd", 759313959Strasz sc->sc_current_transfer_length, ctl_sglist[0].len); 760313959Strasz 761313959Strasz usbd_xfer_set_frame_data(xfer, 0, ctl_sglist[0].addr, ctl_sglist[0].len); 762313959Strasz usbd_transfer_submit(xfer); 763313959Strasz break; 764313959Strasz 765313959Strasz default: 766313959Strasz if (usb_error == USB_ERR_CANCELLED) { 767313959Strasz CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED"); 768313959Strasz break; 769313959Strasz } 770313959Strasz 771313959Strasz CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s", 772313959Strasz usbd_errstr(usb_error)); 773313959Strasz 774313959Strasz goto tr_setup; 775313959Strasz } 776313959Strasz} 777313959Strasz 778313959Straszstatic void 779313959Straszcfumass_t_data_in_callback(struct usb_xfer *xfer, usb_error_t usb_error) 780313959Strasz{ 781313959Strasz struct cfumass_softc *sc; 782313959Strasz union ctl_io *io; 783313959Strasz uint32_t max_bulk; 784313959Strasz struct ctl_sg_entry ctl_sg_entry, *ctl_sglist; 785317336Smav int actlen, ctl_sg_count; 786313959Strasz 787313959Strasz sc = usbd_xfer_softc(xfer); 788313959Strasz io = sc->sc_ctl_io; 789313959Strasz 790313959Strasz switch (USB_GET_STATE(xfer)) { 791313959Strasz case USB_ST_TRANSFERRED: 792313959Strasz CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED"); 793313959Strasz 794317336Smav usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 795317336Smav sc->sc_current_residue -= actlen; 796317336Smav io->scsiio.kern_data_resid -= actlen; 797313959Strasz io->scsiio.be_move_done(io); 798313959Strasz sc->sc_ctl_io = NULL; 799313959Strasz break; 800313959Strasz 801313959Strasz case USB_ST_SETUP: 802313959Strasztr_setup: 803313959Strasz CFUMASS_DEBUG(sc, "USB_ST_SETUP"); 804313959Strasz 805313959Strasz if (io->scsiio.kern_sg_entries > 0) { 806313959Strasz ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr; 807313959Strasz ctl_sg_count = io->scsiio.kern_sg_entries; 808313959Strasz } else { 809313959Strasz ctl_sglist = &ctl_sg_entry; 810313959Strasz ctl_sglist->addr = io->scsiio.kern_data_ptr; 811313959Strasz ctl_sglist->len = io->scsiio.kern_data_len; 812313959Strasz ctl_sg_count = 1; 813313959Strasz } 814313959Strasz 815313959Strasz if (sc->sc_current_transfer_length > io->scsiio.kern_total_len) { 816313959Strasz CFUMASS_DEBUG(sc, "initiator requested %d bytes, " 817313959Strasz "we will send %ju and stall", 818313959Strasz sc->sc_current_transfer_length, 819313959Strasz (uintmax_t)io->scsiio.kern_total_len); 820313959Strasz } 821313959Strasz 822317336Smav max_bulk = usbd_xfer_max_len(xfer); 823313959Strasz CFUMASS_DEBUG(sc, "max_bulk %d, requested size %d, " 824313959Strasz "CTL segment size %zd", max_bulk, 825313959Strasz sc->sc_current_transfer_length, ctl_sglist[0].len); 826313959Strasz 827313959Strasz if (max_bulk >= ctl_sglist[0].len) 828313959Strasz max_bulk = ctl_sglist[0].len; 829313959Strasz 830313959Strasz usbd_xfer_set_frame_data(xfer, 0, ctl_sglist[0].addr, max_bulk); 831313959Strasz usbd_transfer_submit(xfer); 832313959Strasz 833313959Strasz break; 834313959Strasz 835313959Strasz default: 836313959Strasz if (usb_error == USB_ERR_CANCELLED) { 837313959Strasz CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED"); 838313959Strasz break; 839313959Strasz } 840313959Strasz 841313959Strasz CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s", usbd_errstr(usb_error)); 842313959Strasz 843313959Strasz goto tr_setup; 844313959Strasz } 845313959Strasz} 846313959Strasz 847313959Straszstatic void 848313959Straszcfumass_t_status_callback(struct usb_xfer *xfer, usb_error_t usb_error) 849313959Strasz{ 850313959Strasz struct cfumass_softc *sc; 851313959Strasz 852313959Strasz sc = usbd_xfer_softc(xfer); 853313959Strasz 854313959Strasz KASSERT(sc->sc_ctl_io == NULL, 855313959Strasz ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io)); 856313959Strasz 857313959Strasz switch (USB_GET_STATE(xfer)) { 858313959Strasz case USB_ST_TRANSFERRED: 859313959Strasz CFUMASS_DEBUG(sc, "USB_ST_TRANSFERRED"); 860313959Strasz 861313959Strasz cfumass_transfer_start(sc, CFUMASS_T_COMMAND); 862313959Strasz break; 863313959Strasz 864313959Strasz case USB_ST_SETUP: 865313959Strasztr_setup: 866313959Strasz CFUMASS_DEBUG(sc, "USB_ST_SETUP"); 867313959Strasz 868313959Strasz if (sc->sc_current_residue > 0 && !sc->sc_current_stalled) { 869313959Strasz CFUMASS_DEBUG(sc, "non-zero residue, stalling"); 870313959Strasz usbd_xfer_set_stall(xfer); 871313959Strasz sc->sc_current_stalled = true; 872313959Strasz } 873313959Strasz 874313959Strasz USETDW(sc->sc_csw->dCSWSignature, CSWSIGNATURE); 875313959Strasz USETDW(sc->sc_csw->dCSWTag, sc->sc_current_tag); 876313959Strasz USETDW(sc->sc_csw->dCSWDataResidue, sc->sc_current_residue); 877313959Strasz sc->sc_csw->bCSWStatus = sc->sc_current_status; 878313959Strasz 879313959Strasz usbd_xfer_set_frame_len(xfer, 0, sizeof(*sc->sc_csw)); 880313959Strasz usbd_transfer_submit(xfer); 881313959Strasz break; 882313959Strasz 883313959Strasz default: 884313959Strasz if (usb_error == USB_ERR_CANCELLED) { 885313959Strasz CFUMASS_DEBUG(sc, "USB_ERR_CANCELLED"); 886313959Strasz break; 887313959Strasz } 888313959Strasz 889313959Strasz CFUMASS_DEBUG(sc, "USB_ST_ERROR: %s", 890313959Strasz usbd_errstr(usb_error)); 891313959Strasz 892313959Strasz goto tr_setup; 893313959Strasz } 894313959Strasz} 895313959Strasz 896313959Straszstatic void 897313959Straszcfumass_online(void *arg __unused) 898313959Strasz{ 899313959Strasz 900313959Strasz cfumass_port_online = true; 901313959Strasz} 902313959Strasz 903313959Straszstatic void 904313959Straszcfumass_offline(void *arg __unused) 905313959Strasz{ 906313959Strasz 907313959Strasz cfumass_port_online = false; 908313959Strasz} 909313959Strasz 910313959Straszstatic void 911313959Straszcfumass_datamove(union ctl_io *io) 912313959Strasz{ 913313959Strasz struct cfumass_softc *sc; 914313959Strasz 915313959Strasz sc = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr; 916313959Strasz 917313959Strasz CFUMASS_DEBUG(sc, "go"); 918313959Strasz 919313959Strasz CFUMASS_LOCK(sc); 920313959Strasz 921313959Strasz KASSERT(sc->sc_ctl_io == NULL, 922313959Strasz ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io)); 923313959Strasz sc->sc_ctl_io = io; 924313959Strasz 925313959Strasz if ((io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_IN) { 926313959Strasz /* 927313959Strasz * Verify that CTL wants us to send the data in the direction 928313959Strasz * expected by the initiator. 929313959Strasz */ 930313959Strasz if (sc->sc_current_flags != CBWFLAGS_IN) { 931313959Strasz CFUMASS_WARN(sc, "wrong bCBWFlags 0x%x, should be 0x%x", 932313959Strasz sc->sc_current_flags, CBWFLAGS_IN); 933313959Strasz goto fail; 934313959Strasz } 935313959Strasz 936313959Strasz cfumass_transfer_start(sc, CFUMASS_T_DATA_IN); 937313959Strasz } else { 938313959Strasz if (sc->sc_current_flags != CBWFLAGS_OUT) { 939313959Strasz CFUMASS_WARN(sc, "wrong bCBWFlags 0x%x, should be 0x%x", 940313959Strasz sc->sc_current_flags, CBWFLAGS_OUT); 941313959Strasz goto fail; 942313959Strasz } 943313959Strasz 944313959Strasz cfumass_transfer_start(sc, CFUMASS_T_DATA_OUT); 945313959Strasz } 946313959Strasz 947313959Strasz CFUMASS_UNLOCK(sc); 948313959Strasz return; 949313959Strasz 950313959Straszfail: 951313959Strasz ctl_set_data_phase_error(&io->scsiio); 952313959Strasz io->scsiio.be_move_done(io); 953313959Strasz sc->sc_ctl_io = NULL; 954313959Strasz} 955313959Strasz 956313959Straszstatic void 957313959Straszcfumass_done(union ctl_io *io) 958313959Strasz{ 959313959Strasz struct cfumass_softc *sc; 960313959Strasz 961313959Strasz sc = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr; 962313959Strasz 963313959Strasz CFUMASS_DEBUG(sc, "go"); 964313959Strasz 965313959Strasz KASSERT(((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE), 966313959Strasz ("invalid CTL status %#x", io->io_hdr.status)); 967313959Strasz KASSERT(sc->sc_ctl_io == NULL, 968313959Strasz ("sc_ctl_io is %p, should be NULL", sc->sc_ctl_io)); 969313959Strasz 970313959Strasz if (io->io_hdr.io_type == CTL_IO_TASK && 971313959Strasz io->taskio.task_action == CTL_TASK_I_T_NEXUS_RESET) { 972313959Strasz /* 973313959Strasz * Implicit task termination has just completed; nothing to do. 974313959Strasz */ 975313959Strasz ctl_free_io(io); 976313959Strasz return; 977313959Strasz } 978313959Strasz 979313959Strasz /* 980313959Strasz * Do not return status for aborted commands. 981313959Strasz * There are exceptions, but none supported by CTL yet. 982313959Strasz */ 983313959Strasz if (((io->io_hdr.flags & CTL_FLAG_ABORT) && 984313959Strasz (io->io_hdr.flags & CTL_FLAG_ABORT_STATUS) == 0) || 985313959Strasz (io->io_hdr.flags & CTL_FLAG_STATUS_SENT)) { 986313959Strasz ctl_free_io(io); 987313959Strasz return; 988313959Strasz } 989313959Strasz 990317337Smav if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS) 991313959Strasz sc->sc_current_status = 0; 992317337Smav else 993313959Strasz sc->sc_current_status = 1; 994313959Strasz 995317337Smav /* XXX: How should we report BUSY, RESERVATION CONFLICT, etc? */ 996317337Smav if ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SCSI_ERROR && 997317337Smav io->scsiio.scsi_status == SCSI_STATUS_CHECK_COND) 998317337Smav ctl_queue_sense(io); 999317337Smav else 1000317337Smav ctl_free_io(io); 1001317337Smav 1002313959Strasz CFUMASS_LOCK(sc); 1003313959Strasz cfumass_transfer_start(sc, CFUMASS_T_STATUS); 1004313959Strasz CFUMASS_UNLOCK(sc); 1005313959Strasz 1006313959Strasz refcount_release(&sc->sc_queued); 1007313959Strasz} 1008313959Strasz 1009313959Straszint 1010313959Straszcfumass_init(void) 1011313959Strasz{ 1012313959Strasz int error; 1013313959Strasz 1014313959Strasz cfumass_port.frontend = &cfumass_frontend; 1015313959Strasz cfumass_port.port_type = CTL_PORT_UMASS; 1016317336Smav cfumass_port.num_requested_ctl_io = 1; 1017313959Strasz cfumass_port.port_name = "cfumass"; 1018313959Strasz cfumass_port.physical_port = 0; 1019313959Strasz cfumass_port.virtual_port = 0; 1020313959Strasz cfumass_port.port_online = cfumass_online; 1021313959Strasz cfumass_port.port_offline = cfumass_offline; 1022313959Strasz cfumass_port.onoff_arg = NULL; 1023313959Strasz cfumass_port.fe_datamove = cfumass_datamove; 1024313959Strasz cfumass_port.fe_done = cfumass_done; 1025313959Strasz cfumass_port.targ_port = -1; 1026313959Strasz 1027313959Strasz error = ctl_port_register(&cfumass_port); 1028313959Strasz if (error != 0) { 1029313959Strasz printf("%s: ctl_port_register() failed " 1030313959Strasz "with error %d", __func__, error); 1031313959Strasz } 1032313959Strasz 1033313959Strasz cfumass_port_online = true; 1034313959Strasz refcount_init(&cfumass_refcount, 0); 1035313959Strasz 1036313959Strasz return (error); 1037313959Strasz} 1038313959Strasz 1039313959Straszint 1040313959Straszcfumass_shutdown(void) 1041313959Strasz{ 1042313959Strasz int error; 1043313959Strasz 1044313959Strasz if (cfumass_refcount > 0) { 1045313959Strasz if (debug > 1) { 1046313959Strasz printf("%s: still have %u attachments; " 1047313959Strasz "returning EBUSY\n", __func__, cfumass_refcount); 1048313959Strasz } 1049313959Strasz return (EBUSY); 1050313959Strasz } 1051313959Strasz 1052313959Strasz error = ctl_port_deregister(&cfumass_port); 1053313959Strasz if (error != 0) { 1054313959Strasz printf("%s: ctl_port_deregister() failed " 1055313959Strasz "with error %d\n", __func__, error); 1056313959Strasz } 1057313959Strasz 1058313959Strasz return (error); 1059313959Strasz} 1060