lkml.org 
[lkml]   [2011]   [Dec]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[RFC/PATCH v4 1/3] uas: MS UAS Gadget driver - Infrastructure
    Date
    This patch implements the infrastructure for the UAS gadget driver.
    The UAS gadget driver registers as a second configuration of the MS
    gadet driver.

    A new module parameter was added to the mass_storage module:
    bool use_uasp. (default = 0)
    If this parameter is set to true, the mass_storage module will register
    with the UAS configuration as the devices first configuration and
    operate according to the UAS protocol.

    The number of buffers used by the mass_storage device was increased
    according to the number of supported streams.

    It defines the API for COMMAND/TASK MANAGEMENT IU implementation.

    Change-Id: I86ec7f23b15e602b0f46934adbf5824472e59a1f
    Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>
    ---
    drivers/usb/gadget/f_mass_storage.c | 26 +-
    drivers/usb/gadget/f_uasp.c | 2393 +++++++++++++++++++++++++++++++++++
    drivers/usb/gadget/f_uasp.h | 430 +++++++
    drivers/usb/gadget/mass_storage.c | 67 +-
    drivers/usb/gadget/storage_common.c | 24 +-
    drivers/usb/gadget/uasp_cmdiu.c | 514 ++++++++
    drivers/usb/gadget/uasp_tmiu.c | 277 ++++
    7 files changed, 3708 insertions(+), 23 deletions(-)
    create mode 100644 drivers/usb/gadget/f_uasp.c
    create mode 100644 drivers/usb/gadget/f_uasp.h
    create mode 100644 drivers/usb/gadget/uasp_cmdiu.c
    create mode 100644 drivers/usb/gadget/uasp_tmiu.c

    diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
    index c39d588..b777d72 100644
    --- a/drivers/usb/gadget/f_mass_storage.c
    +++ b/drivers/usb/gadget/f_mass_storage.c
    @@ -2703,7 +2703,8 @@ static inline void fsg_common_put(struct fsg_common *common)

    static struct fsg_common *fsg_common_init(struct fsg_common *common,
    struct usb_composite_dev *cdev,
    - struct fsg_config *cfg)
    + struct fsg_config *cfg,
    + int start_thread)
    {
    struct usb_gadget *gadget = cdev->gadget;
    struct fsg_buffhd *bh;
    @@ -2866,12 +2867,14 @@ buffhds_first_it:
    kref_init(&common->ref);

    /* Tell the thread to start working */
    - common->thread_task =
    - kthread_create(fsg_main_thread, common,
    + if (start_thread) {
    + common->thread_task =
    + kthread_create(fsg_main_thread, common,
    cfg->thread_name ?: "file-storage");
    - if (IS_ERR(common->thread_task)) {
    - rc = PTR_ERR(common->thread_task);
    - goto error_release;
    + if (IS_ERR(common->thread_task)) {
    + rc = PTR_ERR(common->thread_task);
    + goto error_release;
    + }
    }
    init_completion(&common->thread_notifier);
    init_waitqueue_head(&common->fsg_wait);
    @@ -2902,10 +2905,11 @@ buffhds_first_it:
    }
    kfree(pathbuf);

    - DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task));
    -
    - wake_up_process(common->thread_task);
    -
    + if (start_thread) {
    + DBG(common, "I/O thread pid: %d\n",
    + task_pid_nr(common->thread_task));
    + wake_up_process(common->thread_task);
    + }
    return common;

    error_luns:
    @@ -3196,6 +3200,6 @@ fsg_common_from_params(struct fsg_common *common,
    {
    struct fsg_config cfg;
    fsg_config_from_params(&cfg, params);
    - return fsg_common_init(common, cdev, &cfg);
    + return fsg_common_init(common, cdev, &cfg, 1);
    }

    diff --git a/drivers/usb/gadget/f_uasp.c b/drivers/usb/gadget/f_uasp.c
    new file mode 100644
    index 0000000..af1569e
    --- /dev/null
    +++ b/drivers/usb/gadget/f_uasp.c
    @@ -0,0 +1,2393 @@
    +/*
    + * f_uasp.c -- Mass Storage USB UASP Composite Function
    + *
    + * Copyright (C) 2003-2005 Alan Stern
    + * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 and
    + * only version 2 as published by the Free Software Foundation.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + * GNU General Public License for more details.
    + */
    +
    +/*
    + * The UASP Function acts as a USB Mass Storage device, appearing to the
    + * host as a disk drive or as a CD-ROM drive. In contrary to
    + * f_mass_storage function that implements the BOT protocol, the UASP
    + * function implements the UAS Protocol.
    + * It's operational both in High and Super connection speeds.
    + * Streaming support depends on the DCD streaming capabilities.
    + *
    + * The Function supports multiple logical units (LUNs). Backing storage
    + * for each LUN is provided by a regular file or a block device. Access
    + * for each LUN can be limited to read-only. Moreover, the function can
    + * indicate that LUN is removable and/or CD-ROM. (The later implies
    + * read-only access.)
    + *
    + * Requirements from the system are:
    + * - 2 bulk-in and 2 bulk-out endpoints are needed.
    + * - The number of buffers used by the Function depends on whether
    + * streaming is supported by the DCD or not. If streaming is not
    + * supported then the minimum number of buffers used by the UASP
    + * function is 4 - one for each endpoint, when the buffer for the
    + * command endpoint is allocated statically and is dedicated to the
    + * command endpoint only.
    + * If streaming is supported then the number of required buffers
    + * equals num_of_streams * 4.
    + * The size of each buffer is 16K by default and is configurable
    + * by a parameter.
    + *
    + * Note that the driver is slightly non-portable in that it assumes that
    + * the same memory/DMA buffer my be used both for bulk-in and bulk-out
    + * endpoints. With most device controllers this isn't an issue, but there
    + * may be some with hardware restrictions that prevent a buffer from being
    + * used by more than one endpoint.
    + *
    + * This function is heavily based on "Mass Storage USB Composite Function" by
    + * Michal Nazarewicz which is based based on "File-backed Storage Gadget" by
    + * Alan Stern which in turn is heavily based on "Gadget Zero" by David
    + * Brownell. The driver's SCSI command interface was based on the
    + * "Information technology - Small Computer System Interface - 2"
    + * document from X3T9.2 Project 375D, Revision 10L, 7-SEP-93,
    + * available at <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>.
    + * The single exception is opcode 0x23 (READ FORMAT CAPACITIES), which
    + * was based on the "Universal Serial Bus Mass Storage Class UFI
    + * Command Specification" document, Revision 1.0, December 14, 1998,
    + * available at
    + * <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>.
    + */
    +
    +/*
    + * Driver Design
    + *
    + * The UASP Function driver registers as a second configuration to the
    + * mass_storage module. In the enumeration if the host wishes to use the
    + * UAS protocol it sends a SET_CONFIGURATION command and chooses the UASP
    + * configuration.
    + * The UASP function driver inherits from the Mass Storage Function
    + * driver and extends it according to UASP requirements.
    + *
    + * All of the control/status transfers in UASP are performed in form of
    + * IUs (Information Units. See section 6.2 of the UASP Spec). The
    + * command/data/status parts of the SCSI protocol are replaced by:
    + * - command IU / task management IU
    + * - data phase
    + * - sense IU / response IU
    + * Each command / task management is handled by the main thread (if not
    + * LUN specific) or by the specific LUN thread, if such LUN exists. Each
    + * of the threads (generic and LUN specific) implements the above
    + * host/device interaction.
    + *
    + * The guiding line through the design was to inherit as much as possible
    + * from already existing f_mass_storage driver since the UASP protocol
    + * extends the already existing BOT protocol. Re-using already
    + * implemented (by the f_mass_storage driver) functions as is wasn't
    + * always possible and a code duplication was forced. In order to clean
    + * this up all the SCSI command handling should be taken out to a
    + * different file both from the UASP driver and from the f_mass_storage
    + * driver, leaving the later two to handle just the UASP/BOT protocols
    + * and not the SCSI protocol. By doing so code duplication will be spared.
    + *
    + * An alternative design would have been to implement the USP driver from
    + * scratch, without the inheritance from f_mass_storage. The pros of this
    + * approach would have been that the existing f_mass_storage driver would
    + * remain as is (without any modifications whatsoever). On the other hand
    + * the cons were:
    + * 1. A separate mechanism would be required to indicate which one of the
    + * drivers to load when connecting to a host according to the hosts
    + * capability to support UASP. In the chosen approach this decision is
    + * left to the host to choose the configuration it wishes to operate
    + * in.
    + * 2. Code/data structures duplication. As already mentioned, the UASP
    + * protocol extends the BOT protocol implemented by the f_mass_storage
    + * driver, thus the two are similar in their data structures and basic
    + * functionality.
    + * We decided to leave this to a second phase of the development in order
    + * to leave the existing f_mass_storage driver with as less changes as
    + * possible.
    + *
    + * The handling of command IUs and task management IUs was divided into
    + * two separate files that are both included by the f_uasp driver.
    + *
    + * Several kernel threads are created as part of the init sequence:
    + * - UASP main thread
    + * - A thread for each of the existing LUNs
    + * The UASP main thread handles all of the generic commands/task
    + * management requests and routes LUN specific requests to be handled by
    + * the appropriate LUNs task.
    + * The approach of "task per LUN" was chosen due to the UAS protocol
    + * enhancement over the BOT protocol. The main retouch of the UAS
    + * protocol of the BOT protocol is the fact that independent commands can
    + * be performed in parallel. For example a READ command for two different
    + * LUNS. Thus in order to implement this concurrency a separate thread is
    + * needed for each of the existing LUNS.
    + * As long as the LUN threads are alive they keep an open reference to the
    + * backing file. This prevents the unmounting of the backing file's
    + * underlying file system and cause problems during system shutdown.
    + *
    + * In the existing f_mass_storage common data structures a single lock is
    + * used for protecting the state of the driver USB requests handled by it.
    + * Since a separate thread was created for each LUN, allowing it to handle
    + * requests addressed to it, the same protection mechanism was required.
    + * Thus a lock was added to each of the LUNS to protect the LUNs state and
    + * the IUs (USB requests) handled by that LUN.
    + *
    + * Interrupt routines field callbacks from controller driver:
    + * - bulk-in, bulk-out, command and status request notifications
    + * - disconnect events
    + * Completion requests are passed to the appropriate thread by wake up
    + * calls. Most of the ep0 requests are handled at interrupt time except
    + * for the following:
    + * - SetInterface
    + * - SetConfiguration
    + * - Device reset
    + * The above are handled by the main thread and are passed to it in form
    + * of "exceptions" using SIGUSR1 signal (since they should interrupt any
    + * ongoing I/O operations).
    + *
    + * In normal operation the main thread is created during UASP_bind but
    + * started only when the UASP configuration is choosen. This is necessary
    + * since msg main thread is also created during msg_bind but since UASP
    + * Function inherits from the Mass Storage Function, the running thread
    + * (UASP or msg) will be saved in a data structure that is shared by UASP
    + * and msg.
    + * The main thread is stopped during unbind but can also be stopped when
    + * it receives a signal. There is no point in leaving the gadget if the
    + * main thread is dead but this is not implemented yet. Maybe a callback
    + * function is needed.
    + *
    + * To provide maximum throughput the driver uses a circular pipeline of
    + * buffer heads (struct fsg_buffhd in which each of the buffers is linked
    + * in a 1:1 connection to an element of struct uasp_buf). Each buffer head
    + * contains a bulk-in and bulk-out requests and thus can be used both for
    + * IN and OUT transfers.
    + * The usage of the pipe line is similar to it's usage by the Mass Storage
    + * Function.
    + */
    +
    +#include <linux/device.h>
    +#include <linux/fcntl.h>
    +#include <linux/file.h>
    +#include <linux/fs.h>
    +#include <linux/kref.h>
    +#include <linux/kthread.h>
    +#include <linux/string.h>
    +#include <linux/usb/ch9.h>
    +#include <linux/usb/gadget.h>
    +#include <linux/kernel.h>
    +#include <linux/usb/storage.h>
    +
    +#include "uasp_cmdiu.c"
    +#include "uasp_tmiu.c"
    +
    +/* Descriptors */
    +
    +/* There is only one interface. */
    +static struct usb_interface_descriptor
    +uasp_intf_desc = {
    + .bLength = sizeof uasp_intf_desc,
    + .bDescriptorType = USB_DT_INTERFACE,
    +
    + .bNumEndpoints = 4,
    + .bInterfaceClass = USB_CLASS_MASS_STORAGE,
    + .bInterfaceSubClass = USB_SC_SCSI,
    + .bInterfaceProtocol = USB_PR_UAS,
    + .iInterface = FSG_STRING_INTERFACE,
    +};
    +
    +/* BULK-in pipe descriptors */
    +static struct usb_endpoint_descriptor
    +uasp_bulk_in_desc = {
    + .bLength = USB_DT_ENDPOINT_SIZE,
    + .bDescriptorType = USB_DT_ENDPOINT,
    + .bEndpointAddress = USB_DIR_IN,
    + .bmAttributes = USB_ENDPOINT_XFER_BULK,
    + .wMaxPacketSize = cpu_to_le16(512),
    +};
    +
    +struct usb_pipe_usage_descriptor
    +uasp_bulk_in_pipe_usg_desc = {
    + .bLength = sizeof uasp_bulk_in_pipe_usg_desc,
    + .bDescriptorType = USB_DT_PIPE_USAGE,
    + .bPipeID = PIPE_ID_DATA_IN,
    + .Reserved = 0,
    +};
    +
    +struct usb_endpoint_descriptor
    +uasp_ss_bulk_in_desc = {
    + .bLength = USB_DT_ENDPOINT_SIZE,
    + .bDescriptorType = USB_DT_ENDPOINT,
    + .bEndpointAddress = USB_DIR_IN,
    + .bmAttributes = USB_ENDPOINT_XFER_BULK,
    + .wMaxPacketSize = cpu_to_le16(0x400),
    +};
    +
    +struct usb_ss_ep_comp_descriptor
    +uasp_bulk_in_ep_comp_desc = {
    + .bLength = sizeof uasp_bulk_in_ep_comp_desc,
    + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
    + .bMaxBurst = 0, /*
    + * Doesn't support burst. Maybe update later?
    + * Should it be HW dependent?
    + */
    + .bmAttributes = UASP_SS_EP_COMP_NUM_STREAMS,
    + .wBytesPerInterval = 0,
    +};
    +
    +/* BULK-out pipe descriptors */
    +struct usb_endpoint_descriptor
    +uasp_bulk_out_desc = {
    + .bLength = USB_DT_ENDPOINT_SIZE,
    + .bDescriptorType = USB_DT_ENDPOINT,
    + .bEndpointAddress = USB_DIR_OUT,
    + .bmAttributes = USB_ENDPOINT_XFER_BULK,
    + .wMaxPacketSize = cpu_to_le16(512),
    +};
    +
    +struct usb_pipe_usage_descriptor
    +uasp_bulk_out_pipe_usg_desc = {
    + .bLength = sizeof uasp_bulk_out_pipe_usg_desc,
    + .bDescriptorType = USB_DT_PIPE_USAGE,
    + .bPipeID = PIPE_ID_DATA_OUT,
    + .Reserved = 0,
    +};
    +
    +struct usb_endpoint_descriptor
    +uasp_ss_bulk_out_desc = {
    + .bLength = USB_DT_ENDPOINT_SIZE,
    + .bDescriptorType = USB_DT_ENDPOINT,
    + .bEndpointAddress = USB_DIR_OUT,
    + .bmAttributes = USB_ENDPOINT_XFER_BULK,
    + .wMaxPacketSize = cpu_to_le16(0x400),
    +};
    +
    +struct usb_ss_ep_comp_descriptor
    +uasp_bulk_out_ep_comp_desc = {
    + .bLength = sizeof uasp_bulk_out_ep_comp_desc,
    + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
    + .bMaxBurst = 0, /*
    + * Doesn't support burst. Maybe update later?
    + * Should it be HW dependent?
    + */
    + .bmAttributes = UASP_SS_EP_COMP_NUM_STREAMS,
    + .wBytesPerInterval = 0,
    +};
    +
    +/* Status pipe - descriptors */
    +struct usb_endpoint_descriptor
    +uasp_status_in_desc = {
    + .bLength = USB_DT_ENDPOINT_SIZE,
    + .bDescriptorType = USB_DT_ENDPOINT,
    + .bEndpointAddress = USB_DIR_IN,
    + .bmAttributes = USB_ENDPOINT_XFER_BULK,
    + .wMaxPacketSize = cpu_to_le16(512),
    +};
    +
    +struct usb_pipe_usage_descriptor
    +uasp_status_in_pipe_usg_desc = {
    + .bLength = sizeof uasp_status_in_pipe_usg_desc,
    + .bDescriptorType = USB_DT_PIPE_USAGE,
    + .bPipeID = PIPE_ID_STS,
    + .Reserved = 0,
    +};
    +
    +struct usb_endpoint_descriptor
    +uasp_ss_status_in_desc = {
    + .bLength = USB_DT_ENDPOINT_SIZE,
    + .bDescriptorType = USB_DT_ENDPOINT,
    + .bEndpointAddress = USB_DIR_IN,
    + .bmAttributes = USB_ENDPOINT_XFER_BULK,
    + .wMaxPacketSize = cpu_to_le16(0x400),
    +};
    +
    +struct usb_ss_ep_comp_descriptor
    +uasp_status_in_ep_comp_desc = {
    + .bLength = sizeof uasp_status_in_ep_comp_desc,
    + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
    + .bMaxBurst = 0, /*
    + * Doesn't support burst. Maybe update later?
    + * Should it be HW dependent?
    + */
    + .bmAttributes = UASP_SS_EP_COMP_NUM_STREAMS,
    + .wBytesPerInterval = 0,
    +};
    +
    +/* Command pipe descriptors */
    +struct usb_endpoint_descriptor
    +uasp_command_out_desc = {
    + .bLength = USB_DT_ENDPOINT_SIZE,
    + .bDescriptorType = USB_DT_ENDPOINT,
    + .bEndpointAddress = USB_DIR_OUT,
    + .bmAttributes = USB_ENDPOINT_XFER_BULK,
    + .wMaxPacketSize = cpu_to_le16(512),
    +};
    +
    +struct usb_pipe_usage_descriptor
    +uasp_command_out_pipe_usg_desc = {
    + .bLength = sizeof uasp_command_out_pipe_usg_desc,
    + .bDescriptorType = USB_DT_PIPE_USAGE,
    + .bPipeID = PIPE_ID_CMD,
    + .Reserved = 0,
    +};
    +
    +struct usb_endpoint_descriptor
    +uasp_ss_command_out_desc = {
    + .bLength = USB_DT_ENDPOINT_SIZE,
    + .bDescriptorType = USB_DT_ENDPOINT,
    + .bEndpointAddress = USB_DIR_OUT,
    + .bmAttributes = USB_ENDPOINT_XFER_BULK,
    + .wMaxPacketSize = cpu_to_le16(0x400),
    +};
    +
    +struct usb_ss_ep_comp_descriptor
    +uasp_command_out_ep_comp_desc = {
    + .bLength = sizeof uasp_command_out_ep_comp_desc,
    + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
    + .bMaxBurst = 0, /*
    + * Doesn't support burst. Maybe update later?
    + * Should it be HW dependent?
    + */
    + .bmAttributes = 0, /* No streams on command endpoint */
    + .wBytesPerInterval = 0,
    +};
    +
    +/* HS configuration function descriptors */
    +struct usb_descriptor_header *uasp_hs_function_desc[] = {
    + (struct usb_descriptor_header *) &uasp_intf_desc,
    + (struct usb_descriptor_header *) &uasp_bulk_in_desc,
    + (struct usb_descriptor_header *) &uasp_bulk_in_pipe_usg_desc,
    + (struct usb_descriptor_header *) &uasp_bulk_out_desc,
    + (struct usb_descriptor_header *) &uasp_bulk_out_pipe_usg_desc,
    + (struct usb_descriptor_header *) &uasp_status_in_desc,
    + (struct usb_descriptor_header *) &uasp_status_in_pipe_usg_desc,
    + (struct usb_descriptor_header *) &uasp_command_out_desc,
    + (struct usb_descriptor_header *) &uasp_command_out_pipe_usg_desc,
    + NULL,
    +};
    +
    +/* SS configuration function descriptors */
    +struct usb_descriptor_header *uasp_ss_function_desc[] = {
    + (struct usb_descriptor_header *) &uasp_intf_desc,
    + (struct usb_descriptor_header *) &uasp_ss_bulk_in_desc,
    + (struct usb_descriptor_header *) &uasp_bulk_in_ep_comp_desc,
    + (struct usb_descriptor_header *) &uasp_bulk_in_pipe_usg_desc,
    + (struct usb_descriptor_header *) &uasp_ss_bulk_out_desc,
    + (struct usb_descriptor_header *) &uasp_bulk_out_ep_comp_desc,
    + (struct usb_descriptor_header *) &uasp_bulk_out_pipe_usg_desc,
    + (struct usb_descriptor_header *) &uasp_ss_status_in_desc,
    + (struct usb_descriptor_header *) &uasp_status_in_ep_comp_desc,
    + (struct usb_descriptor_header *) &uasp_status_in_pipe_usg_desc,
    + (struct usb_descriptor_header *) &uasp_ss_command_out_desc,
    + (struct usb_descriptor_header *) &uasp_command_out_ep_comp_desc,
    + (struct usb_descriptor_header *) &uasp_command_out_pipe_usg_desc,
    + NULL,
    +};
    +
    +/*--------------------------------------------------------------------------*/
    +static inline struct uasp_dev *uaspd_from_func(struct usb_function *f)
    +{
    + struct fsg_dev *fsg_dev = fsg_from_func(f);
    + return container_of(fsg_dev, struct uasp_dev, fsg_dev);
    +}
    +
    +static void uasp_common_release(struct kref *ref)
    +{
    + struct uasp_common *ucommon =
    + container_of(ref, struct uasp_common, ref);
    + struct uasp_lun *ulun;
    + int i;
    +
    + /* First stop all lun threads */
    + run_lun_threads(ucommon->udev, LUN_STATE_EXIT);
    + for (i = 0; i < ucommon->common->nluns; i++) {
    + ulun = &(ucommon->uluns[i]);
    + if (ulun->lun_state != LUN_STATE_TERMINATED) {
    + wait_for_completion(&ulun->thread_notifier);
    + /* The cleanup routine waits for this completion also */
    + complete(&ulun->thread_notifier);
    + }
    + }
    + fsg_common_release(&(ucommon->common->ref));
    + kfree(ucommon->uluns);
    + kfree(ucommon);
    +}
    +
    +
    +static inline void uasp_common_put(struct uasp_common *common)
    +{
    + kref_put(&(common->ref), uasp_common_release);
    +}
    +
    +static struct uasp_lun *find_lun_by_id(struct uasp_dev *udev, __u8 *lun_id)
    +{
    + int i;
    + struct uasp_lun *curlun;
    +
    + DBG(udev->ucommon->common, "%s() - Enter.\n", __func__);
    +
    + for (i = 0; i < udev->ucommon->common->nluns; ++i) {
    + curlun = &udev->ucommon->uluns[i];
    +
    + if (memcmp(lun_id, curlun->lun_id, 8) == 0) {
    + DBG(udev->ucommon->common, "%s() - LUN found\n",
    + __func__);
    + return curlun;
    + }
    + }
    + DBG(udev->ucommon->common, "%s() - LUN not found\n", __func__);
    + return 0;
    +}
    +
    +/**
    + * wakeup_lun_thread() - Wakes up the given LUn thread
    + * @lun: the LUN which thread needs wakening
    + *
    + * NOTE: Caller must hold uasp_lun->lock
    + *
    + */
    +static void wakeup_lun_thread(struct uasp_lun *lun)
    +{
    + /* Tell the lun thread that something has happened */
    + lun->thread_wakeup_needed = 1;
    + if (lun->lun_thread_task)
    + wake_up_process(lun->lun_thread_task);
    +}
    +
    +/**
    + * command_complete() - Callback function for the command endpoint
    + * @ep: pointer to the usb_ep (command endpoint)
    + * @req: usb_request received on this endpoint
    + *
    + * This function is passed to the outreq->complete() of the command endpoint.
    + * If the request completed without errors the function marks the state of the
    + * command buffer as full and wakes up the uasp main thread.
    + */
    +static void command_complete(struct usb_ep *ep, struct usb_request *req)
    +{
    + struct uasp_dev *udev = (struct uasp_dev *) ep->driver_data;
    + unsigned long flags;
    +
    + if (req->actual > 0)
    + dump_msg(udev->ucommon->common, "command", req->buf,
    + req->actual);
    + DBG(udev->ucommon->common, "%s() - Enter", __func__);
    +
    + if (req != udev->cmd_buff.outreq) {
    + ERROR(udev->ucommon->common, "(%s) req(%p) != "
    + "cmd_buff.outreq(%p), udev=%p,"
    + " common->state = %d\n",
    + __func__, req, udev->cmd_buff.outreq, udev,
    + udev->ucommon->common->state);
    + }
    +
    + if (req->status == -ECONNRESET) {
    + spin_lock_irqsave(&(udev->ucommon->common->lock), flags);
    + udev->cmd_buff.state = BUF_STATE_EMPTY;
    + spin_unlock_irqrestore(&(udev->ucommon->common->lock), flags);
    +
    + usb_ep_fifo_flush(ep);
    + return;
    + }
    +
    + spin_lock_irqsave(&(udev->ucommon->common->lock), flags);
    + udev->cmd_buff.state = BUF_STATE_FULL;
    + wakeup_thread(udev->ucommon->common);
    + spin_unlock_irqrestore(&(udev->ucommon->common->lock), flags);
    +}
    +
    +/**
    + * status_complete() - Callback function for the status endpoint
    + * @ep: pointer to the usb_ep (status endpoint)
    + * @req: usb_request received on this endpoint
    + *
    + * This function is passed to the outreq->complete() of the status endpoint.
    + * If the request completion status isn't ECONNRESET the requests tmiu/cmdiu
    + * state is updated to aborted/completed/failed (according to the completion
    + * status of the usb request). If the tmiu/cmdiu was LUN specific, the
    + * corresponding LUN thread is awaken. If it was general, uasp main thread is
    + * awaken.
    + */
    +void status_complete(struct usb_ep *ep, struct usb_request *req)
    +{
    + struct uasp_dev *udev = (struct uasp_dev *) ep->driver_data;
    + struct uasp_lun *curlun = NULL;
    + struct tm_iu *tmiu;
    + struct cmd_iu *cmdiu;
    + uint8_t cmd_id = ((uint8_t *)req->context)[0];
    + unsigned long flags;
    +
    + DBG(udev->ucommon->common, "%s() - Enter", __func__);
    +
    + if (req->status == -ECONNRESET)
    + usb_ep_fifo_flush(ep);
    +
    + spin_lock_irqsave(&(udev->ucommon->common->lock), flags);
    + /* If Sense IU is filled for TM FUNCTION IU */
    + if (cmd_id == IU_ID_TASK_MANAGEMENT) {
    + tmiu = (struct tm_iu *)req->context;
    + if (tmiu->state != COMMAND_STATE_FAILED &&
    + tmiu->state != COMMAND_STATE_ABORTED) {
    + if (req->status == -ERESTART)
    + tmiu->state = COMMAND_STATE_ABORTED;
    + else if (req->status) {
    + DBG(udev->ucommon->common,
    + "%s() - TMIU FAILED!!! Status = %d",
    + __func__, req->status);
    + tmiu->state = COMMAND_STATE_FAILED;
    + } else
    + tmiu->state = COMMAND_STATE_COMPLETED;
    + }
    + DBG(udev->ucommon->common,
    + "%s() - received IU_ID_TASK_MANAGEMENT "
    + "(Code = %02x tmiu->state = %d)\n",
    + __func__, tmiu->tm_function, tmiu->state);
    + tmiu->bh->inreq_busy = 0;
    + curlun = find_lun_by_id(udev, tmiu->lun);
    + }
    + /* If Sense IU is filled for COMMAND IU */
    + else if (cmd_id == IU_ID_COMMAND) {
    + cmdiu = (struct cmd_iu *)req->context;
    + if (cmdiu->state != COMMAND_STATE_FAILED &&
    + cmdiu->state != COMMAND_STATE_ABORTED) {
    + if (req->status == -ERESTART)
    + cmdiu->state = COMMAND_STATE_ABORTED;
    + else if (req->status) {
    + DBG(udev->ucommon->common,
    + "%s() - CMDIU FAILED!!! Status = %d",
    + __func__, req->status);
    + cmdiu->state = COMMAND_STATE_FAILED;
    + } else if (cmdiu->state == COMMAND_STATE_STATUS)
    + cmdiu->state = COMMAND_STATE_COMPLETED;
    + }
    + DBG(udev->ucommon->common, "%s() - received IU_ID_COMMAND"
    + " (OpCode = %02x, smdiu->state = %d)\n",
    + __func__, cmdiu->cdb[0], cmdiu->state);
    + cmdiu->req_sts = CMD_REQ_COMPLETED;
    + cmdiu->bh->inreq_busy = 0;
    +
    + curlun = find_lun_by_id(udev, cmdiu->lun);
    + } else {
    + ERROR(udev->ucommon->common,
    + "%s() - received invalid IU (iu_id = %02x)!\n",
    + __func__, cmd_id);
    + spin_unlock_irqrestore(&(udev->ucommon->common->lock), flags);
    + return;
    + }
    +
    + if (curlun) {
    + spin_unlock_irqrestore(&(udev->ucommon->common->lock),
    + flags);
    + spin_lock_irqsave(&(curlun->lock), flags);
    + curlun->pending_requests++;
    + curlun->active_requests--;
    + wakeup_lun_thread(curlun);
    + spin_unlock_irqrestore(&(curlun->lock), flags);
    + spin_lock_irqsave(&(udev->ucommon->common->lock),
    + flags);
    + } else {
    + udev->pending_requests++;
    + udev->active_requests--;
    + wakeup_thread(udev->ucommon->common);
    + }
    + spin_unlock_irqrestore(&(udev->ucommon->common->lock), flags);
    +}
    +
    +/**
    + * uasp_bulk_in_complete() - Callback function for the bulk IN endpoint
    + * @ep: pointer to the usb_ep (bulk IN endpoint)
    + * @req: usb_request received on this endpoint
    + *
    + * This function is passed to the outreq->complete() of the bulk IN endpoint.
    + * The requests cmdiu state is updated according to the completion status of
    + * the usb request. If the cmdiu was LUN specific, the corresponding LUN
    + * thread is awaken. If it was general, uasp main thread is awaken.
    + */
    +void uasp_bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
    +{
    + struct uasp_dev *udev = (struct uasp_dev *) ep->driver_data;
    + struct uasp_lun *curlun;
    + struct cmd_iu *cmdiu;
    + unsigned long flags;
    +
    + DBG(udev->ucommon->common, "%s() - Enter\n", __func__);
    +
    + if (req->status == -ECONNRESET)
    + usb_ep_fifo_flush(ep);
    +
    + cmdiu = (struct cmd_iu *)req->context;
    +
    + spin_lock_irqsave(&(udev->ucommon->common->lock), flags);
    + if (cmdiu->state != COMMAND_STATE_ABORTED &&
    + cmdiu->state != COMMAND_STATE_FAILED) {
    + if (req->status == -ERESTART)
    + cmdiu->state = COMMAND_STATE_ABORTED;
    + else if (req->status != 0)
    + cmdiu->state = COMMAND_STATE_FAILED;
    + }
    +
    + cmdiu->req_sts = CMD_REQ_COMPLETED;
    + cmdiu->bh->inreq_busy = 0;
    +
    +
    + curlun = find_lun_by_id(udev, cmdiu->lun);
    + if (curlun) {
    + spin_unlock_irqrestore(&udev->ucommon->common->lock, flags);
    + spin_lock_irqsave(&curlun->lock, flags);
    + curlun->pending_requests++;
    + curlun->active_requests--;
    + wakeup_lun_thread(curlun);
    + spin_unlock_irqrestore(&curlun->lock, flags);
    + spin_lock_irqsave(&(udev->ucommon->common->lock), flags);
    + } else {
    + udev->pending_requests++;
    + udev->active_requests--;
    + wakeup_thread(udev->ucommon->common);
    + }
    + spin_unlock_irqrestore(&udev->ucommon->common->lock, flags);
    +}
    +
    +
    +/**
    + * uasp_bulk_out_complete() - Callback function for the bulk OUT endpoint
    + * @ep: pointer to the usb_ep (bulk OUT endpoint)
    + * @req: usb_request received on this endpoint
    + *
    + * This function is passed to the outreq->complete() of the bulk OUT endpoint.
    + * The requests cmdiu state is updated according to the completion status of
    + * the usb request. If the cmdiu was LUN specific, the corresponding LUN
    + * thread is awaken. If it was general, uasp main thread is awaken.
    + */
    +void uasp_bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
    +{
    + struct uasp_dev *udev = (struct uasp_dev *) ep->driver_data;
    + struct uasp_lun *curlun;
    + struct cmd_iu *cmdiu;
    + unsigned long flags;
    +
    + DBG(udev->ucommon->common, "%s() - Enter\n", __func__);
    +
    + if (req->status == -ECONNRESET)
    + usb_ep_fifo_flush(ep);
    +
    + spin_lock_irqsave(&udev->ucommon->common->lock, flags);
    + cmdiu = (struct cmd_iu *)req->context;
    +
    + if (cmdiu->state != COMMAND_STATE_ABORTED &&
    + cmdiu->state != COMMAND_STATE_FAILED) {
    + if (req->status == -ERESTART)
    + cmdiu->state = COMMAND_STATE_ABORTED;
    + else if (req->status != 0)
    + cmdiu->state = COMMAND_STATE_FAILED;
    + }
    +
    + cmdiu->req_sts = CMD_REQ_COMPLETED;
    + cmdiu->bh->outreq_busy = 0;
    +
    + curlun = find_lun_by_id(udev, cmdiu->lun);
    + if (curlun) {
    + spin_unlock_irqrestore(&udev->ucommon->common->lock, flags);
    + spin_lock_irqsave(&curlun->lock, flags);
    + curlun->pending_requests++;
    + curlun->active_requests--;
    + wakeup_lun_thread(curlun);
    + spin_unlock_irqrestore(&curlun->lock, flags);
    + spin_lock_irqsave(&udev->ucommon->common->lock, flags);
    + } else {
    + udev->pending_requests++;
    + udev->active_requests--;
    + wakeup_thread(udev->ucommon->common);
    + }
    + spin_unlock_irqrestore(&udev->ucommon->common->lock, flags);
    +}
    +
    +/**
    + * remove_completed_commands() - removes all completed UIs
    + * @udev: Programming view of uasp device
    + * @cmd_queue: pointer to the command IUs queue to go over
    + * @tm_func_queue: pointer to the tm IUs queue to go over
    + *
    + * This function goes over the command IUs queue and TM IUs queue and removes
    + * all completed IUs
    + */
    +static void remove_completed_commands(struct uasp_dev *udev,
    + struct list_head *cmd_queue,
    + struct list_head *tm_func_queue)
    +{
    + struct cmd_iu *cmdiu;
    + struct cmd_iu *tmp_cmdiu;
    + struct tm_iu *tmiu;
    + struct tm_iu *tmp_tmiu;
    +
    + DBG(udev->ucommon->common, "%s() - Enter\n", __func__);
    +
    + /* Remove completed, aborted or failed commands from cmd_queue */
    + list_for_each_entry_safe(cmdiu, tmp_cmdiu, cmd_queue, node) {
    + DBG(udev->ucommon->common, "%s() - cmd_queue cycle"
    + " cmdiu->state=%d "
    + " cmdiu->req_sts=%d\n",
    + __func__, cmdiu->state, cmdiu->req_sts);
    +
    + /* Do not touch incompleted commands !!! */
    + if (cmdiu->state != COMMAND_STATE_ABORTED &&
    + cmdiu->state != COMMAND_STATE_COMPLETED &&
    + cmdiu->state != COMMAND_STATE_FAILED)
    + continue;
    +
    + if (cmdiu->state == COMMAND_STATE_ABORTED ||
    + cmdiu->state == COMMAND_STATE_FAILED) {
    + if (cmdiu->req_sts == CMD_REQ_IN_PROGRESS) {
    + if (cmdiu->bh->inreq_busy &&
    + usb_ep_dequeue(cmdiu->ep,
    + cmdiu->bh->inreq)) {
    + cmdiu->req_sts = CMD_REQ_COMPLETED;
    + cmdiu->bh->inreq_busy = 0;
    + }
    + if (cmdiu->bh->outreq_busy &&
    + usb_ep_dequeue(cmdiu->ep,
    + cmdiu->bh->outreq)) {
    + cmdiu->req_sts = CMD_REQ_COMPLETED;
    + cmdiu->bh->outreq_busy = 0;
    + }
    + }
    +
    + if (cmdiu->req_sts == CMD_REQ_IN_PROGRESS)
    + continue;
    + }
    + DBG(udev->ucommon->common, "%s() - deleted cmdiu: "
    + "cmdiu[0] = %d, cmdiu->state = %d,"
    + "cmdiu->tag = %d\n",
    + __func__, cmdiu->cdb[0], cmdiu->state, cmdiu->tag);
    + list_del(&cmdiu->node);
    + if (cmdiu->bh) {
    + DBG(udev->ucommon->common, "%s() - Freeing the "
    + "cmdiu->bh\n", __func__);
    + cmdiu->bh->state = BUF_STATE_EMPTY;
    + }
    + kfree(cmdiu);
    + }
    +
    + /* Remove completed, aborted or failed commands from tm_func_queue */
    + list_for_each_entry_safe(tmiu, tmp_tmiu, tm_func_queue, node) {
    + /* Do not touch incompleted commands !!! */
    + if (tmiu->state != COMMAND_STATE_ABORTED &&
    + tmiu->state != COMMAND_STATE_COMPLETED &&
    + tmiu->state != COMMAND_STATE_FAILED)
    + continue;
    +
    + DBG(udev->ucommon->common, "%s() - deleted tmiu\n", __func__);
    + list_del(&tmiu->node);
    + if (tmiu->bh) {
    + DBG(udev->ucommon->common, "%s() - Freeing the "
    + "tmiu->bh\n", __func__);
    + tmiu->bh->state = BUF_STATE_EMPTY;
    + }
    + kfree(tmiu);
    + }
    + if (list_empty(cmd_queue) && list_empty(tm_func_queue))
    + DBG(udev->ucommon->common, "%s() - both lists are empty\n",
    + __func__);
    + DBG(udev->ucommon->common, "%s() - exit\n", __func__);
    +}
    +
    +/**
    + * do_uasp_set_interface() - Enables/disables the UASP FD.
    + * @uaspd: pointer to the uasp device structure
    + * @new_fsg: pointer to fsg_dev for the new configuration
    + *
    + * Returns 0 on success negative error code otherwise.
    + *
    + * Initiates all endpoints and enables them. Allocates buffers and requests.
    + */
    +static int do_uasp_set_interface(struct uasp_dev *uaspd,
    + struct fsg_dev *new_fsg)
    +{
    + int rc = 0;
    + int i;
    + struct fsg_dev *fsgd;
    + struct fsg_common *fcommon;
    + unsigned long flags;
    +
    + if (!uaspd || !uaspd->ucommon || !uaspd->ucommon->common)
    + return -EIO;
    +
    + DBG(uaspd->ucommon->common, "%s()- Enter\n", __func__);
    +
    + fcommon = uaspd->ucommon->common;
    + if (uaspd->ucommon->common->running)
    + DBG(uaspd->ucommon->common, "reset inteface\n");
    +
    +reset_uasp:
    + /* Deallocate the requests */
    + if (uaspd->ucommon->common->fsg) {
    + fsgd = fcommon->fsg;
    +
    + abort_commands(uaspd, &uaspd->cmd_queue, &uaspd->tm_func_queue,
    + &(uaspd->ucommon->common->lock));
    + remove_completed_commands(uaspd, &uaspd->cmd_queue,
    + &uaspd->tm_func_queue);
    + uaspd->pending_requests = 0;
    +
    + for (i = 0; i < uaspd->ucommon->common->nluns; i++) {
    + struct uasp_lun *ulun = &uaspd->ucommon->uluns[i];
    + abort_commands(uaspd, &ulun->cmd_queue,
    + &ulun->tm_func_queue, &(ulun->lock));
    + remove_completed_commands(uaspd, &ulun->cmd_queue,
    + &ulun->tm_func_queue);
    + spin_lock_irqsave(&(ulun->lock), flags);
    + ulun->pending_requests = 0;
    + ulun->lun->prevent_medium_removal = 0;
    + ulun->lun->sense_data = SS_NO_SENSE;
    + ulun->lun->unit_attention_data = SS_NO_SENSE;
    + ulun->lun->sense_data_info = 0;
    + ulun->lun->info_valid = 0;
    + spin_unlock_irq(&(ulun->lock));
    + }
    + /* Clear out the controller's fifos */
    + if (fcommon->fsg->bulk_in_enabled)
    + usb_ep_fifo_flush(fcommon->fsg->bulk_in);
    + if (fcommon->fsg->bulk_out_enabled)
    + usb_ep_fifo_flush(fcommon->fsg->bulk_out);
    + usb_ep_fifo_flush(uaspd->ucommon->udev->status);
    + usb_ep_fifo_flush(uaspd->ucommon->udev->command);
    +
    + spin_lock_irq(&fcommon->lock);
    + /* Reset the I/O buffer states and pointers */
    + for (i = 0; i < fsg_num_buffers; ++i) {
    + struct fsg_buffhd *bh = &fcommon->buffhds[i];
    + if (bh->inreq) {
    + usb_ep_free_request(fsgd->bulk_in, bh->inreq);
    + bh->inreq = NULL;
    + }
    + if (bh->outreq) {
    + usb_ep_free_request(fsgd->bulk_out, bh->outreq);
    + bh->outreq = NULL;
    + }
    + bh->state = BUF_STATE_EMPTY;
    + }
    +
    + /* Deallocate command and status requests */
    + if (uaspd->cmd_buff.inreq) {
    + ERROR(uaspd->ucommon->common,
    + "%s(): uaspd->cmd_buff.inreq isn't NULL. "
    + "How can that be???",
    + __func__);
    + usb_ep_free_request(uaspd->command,
    + uaspd->cmd_buff.inreq);
    + uaspd->cmd_buff.inreq = NULL;
    + }
    + if (uaspd->cmd_buff.outreq) {
    + usb_ep_free_request(uaspd->command,
    + uaspd->cmd_buff.outreq);
    + uaspd->cmd_buff.outreq = NULL;
    + }
    + uaspd->cmd_buff.state = BUF_STATE_EMPTY;
    + spin_unlock_irq(&fcommon->lock);
    +
    + /* Disable the endpoints */
    + if (fsgd->bulk_in_enabled) {
    + usb_ep_disable(fsgd->bulk_in);
    + fsgd->bulk_in_enabled = 0;
    + }
    + if (fsgd->bulk_out_enabled) {
    + usb_ep_disable(fsgd->bulk_out);
    + fsgd->bulk_out_enabled = 0;
    + }
    + fsgd->bulk_in->desc = NULL;
    + fsgd->bulk_out->desc = NULL;
    +
    + if (uaspd->cmd_enabled) {
    + usb_ep_disable(uaspd->command);
    + uaspd->cmd_enabled = 0;
    + }
    + if (uaspd->status_enabled) {
    + usb_ep_disable(uaspd->status);
    + uaspd->status_enabled = 0;
    + }
    + uaspd->command->desc = NULL;
    + uaspd->status->desc = NULL;
    + DBG(uaspd->ucommon->common, "%s()- disabled endpoints\n",
    + __func__);
    +
    + fcommon->fsg = NULL;
    + wake_up(&fcommon->fsg_wait);
    + }
    +
    + fcommon->running = 0;
    + if (!new_fsg || rc)
    + return rc;
    +
    + fcommon->fsg = new_fsg;
    + fsgd = fcommon->fsg;
    +
    + /* Enable the endpoints */
    + config_ep_by_speed(fcommon->gadget, &fsgd->function, fsgd->bulk_in);
    + rc = usb_ep_enable(fsgd->bulk_in);
    + if (rc)
    + goto reset_uasp;
    + fsgd->bulk_in->driver_data = uaspd;
    + fsgd->bulk_in_enabled = 1;
    +
    + config_ep_by_speed(fsgd->common->gadget, &fsgd->function,
    + fsgd->bulk_out);
    + rc = usb_ep_enable(fsgd->bulk_out);
    + if (rc)
    + goto reset_uasp;
    + fsgd->bulk_out->driver_data = uaspd;
    + fsgd->bulk_out_enabled = 1;
    +
    + fsgd->common->bulk_out_maxpacket =
    + le16_to_cpu(fsgd->bulk_out->maxpacket);
    + clear_bit(IGNORE_BULK_OUT, &fsgd->atomic_bitflags);
    +
    + config_ep_by_speed(fsgd->common->gadget, &fsgd->function,
    + uaspd->command);
    + rc = usb_ep_enable(uaspd->command);
    + if (rc)
    + goto reset_uasp;
    + uaspd->command->driver_data = uaspd;
    + uaspd->cmd_enabled = 1;
    +
    + config_ep_by_speed(fsgd->common->gadget, &fsgd->function,
    + uaspd->status);
    + rc = usb_ep_enable(uaspd->status);
    + if (rc)
    + goto reset_uasp;
    + uaspd->status->driver_data = uaspd;
    + uaspd->status_enabled = 1;
    +
    + /* Allocate the data - requests */
    + for (i = 0; i < fsg_num_buffers; ++i) {
    + struct uasp_buff *buff = &uaspd->ucommon->ubufs[i];
    +
    + buff->fsg_buff->inreq = usb_ep_alloc_request(fsgd->bulk_in,
    + GFP_ATOMIC);
    + if (!buff->fsg_buff->inreq)
    + goto reset_uasp;
    +
    + buff->fsg_buff->outreq = usb_ep_alloc_request(fsgd->bulk_out,
    + GFP_ATOMIC);
    + if (!buff->fsg_buff->outreq)
    + goto reset_uasp;
    +
    + buff->fsg_buff->inreq->buf =
    + buff->fsg_buff->outreq->buf =
    + buff->fsg_buff->buf;
    + buff->fsg_buff->inreq->context =
    + buff->fsg_buff->outreq->context =
    + buff->fsg_buff;
    + }
    +
    + /* Allocate command ep request */
    + uaspd->cmd_buff.outreq = usb_ep_alloc_request(uaspd->command,
    + GFP_ATOMIC);
    + if (!uaspd->cmd_buff.outreq) {
    + ERROR(uaspd->ucommon->common, "failed allocating outreq for "
    + "command buffer\n");
    + goto reset_uasp;
    + }
    +
    + DBG(uaspd->ucommon->common, "%s() allocated command request = %p, "
    + "udev=%p\n", __func__,
    + uaspd->cmd_buff.outreq, uaspd);
    + uaspd->cmd_buff.outreq->buf = &(uaspd->cmd_buff.buf);
    + uaspd->cmd_buff.inreq = NULL;
    + uaspd->cmd_buff.state = BUF_STATE_EMPTY;
    +
    + fcommon->running = 1;
    + for (i = 0; i < fsgd->common->nluns; ++i)
    + fsgd->common->luns[i].unit_attention_data = SS_RESET_OCCURRED;
    + return 0;
    +}
    +
    +static void handle_uasp_exception(struct uasp_common *ucommon)
    +{
    + siginfo_t info;
    + int sig;
    + int i;
    + struct fsg_buffhd *bh;
    + enum fsg_state old_state;
    + int rc;
    +
    + struct fsg_common *fcommon = ucommon->common;
    +
    + DBG(ucommon->common, "%s()- Enter\n", __func__);
    +
    + /*
    + * Clear the existing signals. Anything but SIGUSR1 is converted
    + * into a high-priority EXIT exception.
    + */
    + for (;;) {
    + sig = dequeue_signal_lock(current, &current->blocked, &info);
    + if (!sig)
    + break;
    + if (sig != SIGUSR1) {
    + if (fcommon->state < FSG_STATE_EXIT)
    + DBG(fcommon, "Main thread exiting on signal\n");
    + fcommon->state = FSG_STATE_EXIT;
    + }
    + }
    +
    + /*
    + * Reset the I/O buffer states and pointers, the SCSI state, and the
    + * exception. Then invoke the handler.
    + */
    + spin_lock_irq(&fcommon->lock);
    +
    + for (i = 0; i < fsg_num_buffers; ++i) {
    + bh = &fcommon->buffhds[i];
    + bh->state = BUF_STATE_EMPTY;
    + }
    + old_state = fcommon->state;
    + fcommon->state = FSG_STATE_IDLE;
    + spin_unlock_irq(&fcommon->lock);
    +
    + /* Carry out any extra actions required for the exception */
    + switch (old_state) {
    + case FSG_STATE_ABORT_BULK_OUT:
    + case FSG_STATE_RESET:
    + /* TODO */
    + break;
    +
    + case FSG_STATE_CONFIG_CHANGE:
    + if (fcommon->fsg == fcommon->new_fsg) {
    + DBG(fcommon, "nothing to do. same config\n");
    + break;
    + }
    + /* Enable/disable the interface according to the new_config */
    + rc = do_uasp_set_interface(ucommon->udev, fcommon->new_fsg);
    + if (rc != 0)
    + fcommon->fsg = NULL; /* Reset on errors */
    + break;
    + case FSG_STATE_EXIT:
    + case FSG_STATE_TERMINATED:
    + /* Free resources */
    + (void)do_uasp_set_interface(ucommon->udev, NULL);
    + spin_lock_irq(&fcommon->lock);
    + fcommon->state = FSG_STATE_TERMINATED; /* Stop the thread*/
    + spin_unlock_irq(&fcommon->lock);
    + break;
    +
    + case FSG_STATE_INTERFACE_CHANGE:
    + case FSG_STATE_DISCONNECT:
    + case FSG_STATE_COMMAND_PHASE:
    + case FSG_STATE_DATA_PHASE:
    + case FSG_STATE_STATUS_PHASE:
    + case FSG_STATE_IDLE:
    + break;
    + }
    + DBG(ucommon->common, "%s()- Exit\n", __func__);
    +}
    +
    +/**
    + * uasp_command_check() - Verifies the data received via command endpoint for
    + * accuracy.
    + * @udev: Programming view of uasp device.
    + * @command: Pointer to the received data buffer.
    + *
    + * Return 0 - if no error condition and the command is a
    + * COMMAND IU
    + * 1 - if no error condition and the command is a TASK
    + * MANAGEMENT IU
    + * negative value on error.
    + *
    + * If the command is valid returns it by reference in command
    + * param. The following steps are implemented in this function:
    + * - Checking that the received data is a TM FUNCTION or COMMAND IU.
    + * - Chekcing that the length of the received data is correct
    + * (16 bytes for TM FUNCTION IU and 36 bytes for COMMAND IU).
    + * - Checking that there is no overlapped tag.
    + */
    +static int uasp_command_check(struct uasp_dev *udev, void **command)
    +{
    + int i = 0;
    + int rc = 0;
    + unsigned long flags;
    + __be16 tag;
    + uint8_t cmd_id;
    + struct uasp_lun *curlun;
    + struct cmd_iu *cmdiu, *tmp_cmdiu;
    + struct tm_iu *tmiu, *tmp_tmiu;
    + struct fsg_buffhd *bh;
    + struct usb_request *req;
    +
    + bh = &(udev->cmd_buff);
    + bh->state = BUF_STATE_EMPTY;
    + req = udev->cmd_buff.outreq;
    + *command = NULL;
    +
    + DBG(udev->ucommon->common, "%s() - Enter\n", __func__);
    +
    + /* Id of the received command (tmiu or cmdiu) */
    + cmd_id = ((uint8_t *)req->buf)[0];
    +
    + /* tag of the received command */
    + tag = ((__be16 *)req->buf)[1];
    +
    + /* Invalid completion status */
    + if (req->status) {
    + ERROR(udev->ucommon->common,
    + "%s() - Invalid completion status for command "
    + "request = -%d\n", __func__, req->status);
    + return -EINVAL;
    + }
    +
    + /* Check is the data received via command endpoint is a command */
    + if (cmd_id != IU_ID_TASK_MANAGEMENT && cmd_id != IU_ID_COMMAND) {
    + ERROR(udev->ucommon->common,
    + "%s() - Invalid data is received\n", __func__);
    + /* TODO: something needs to be done (e.g. halt endpoints) */
    + return -EINVAL;
    + }
    +
    + /* Invalid count of bytes received for tmiu */
    + if (cmd_id == IU_ID_TASK_MANAGEMENT && req->actual != 16) {
    + ERROR(udev->ucommon->common,
    + "%s() - Invalid byte count for tmiu is received = %d\n",
    + __func__, req->actual);
    + /* TODO: something needs to be done (e.g. halt endpoints) */
    + return -EINVAL;
    + }
    +
    + /* Invalid count of bytes received for cmdiu */
    + if (cmd_id == IU_ID_COMMAND && req->actual < 32) {
    + ERROR(udev->ucommon->common,
    + "%s() - Invalid byte count for cmdiu is received = %d\n",
    + __func__, req->actual);
    + /* TODO: something needs to be done (e.g. halt endpoints) */
    + return -EINVAL;
    + }
    +
    + /* Try to allocate memory for received command */
    + tmiu = NULL;
    + cmdiu = NULL;
    +
    + if (cmd_id == IU_ID_TASK_MANAGEMENT) {
    + tmiu = kmalloc(sizeof(struct tm_iu), GFP_KERNEL);
    +
    + if (!tmiu) {
    + ERROR(udev->ucommon->common,
    + "%s() - No memory for tmiu\n", __func__);
    + return -ENOMEM;
    + }
    + *command = tmiu;
    + memcpy(*command, req->buf, 16);
    + } else {
    + cmdiu = kmalloc(sizeof(struct cmd_iu), GFP_KERNEL);
    +
    + if (!cmdiu) {
    + ERROR(udev->ucommon->common,
    + "%s() - No memory for cmdiu\n", __func__);
    + return -ENOMEM;
    + }
    + *command = cmdiu;
    + memcpy(*command, req->buf, req->actual);
    + }
    +
    + /* Check for overlapping tag */
    + /* Check for tag overlapping over all cmd an tm_func queues */
    + for (i = 0; i < udev->ucommon->common->nluns; ++i) {
    + curlun = &udev->ucommon->uluns[i];
    + spin_lock_irqsave(&(curlun->lock), flags);
    +
    + list_for_each_entry(tmp_cmdiu, &curlun->cmd_queue, node) {
    + if (tmp_cmdiu->state != COMMAND_STATE_IDLE &&
    + tmp_cmdiu->state != COMMAND_STATE_DATA &&
    + tmp_cmdiu->state != COMMAND_STATE_STATUS) {
    + continue;
    + }
    + /* Overlapped tag found */
    + if (tmp_cmdiu->tag == tag) {
    + spin_unlock_irqrestore(&(curlun->lock), flags);
    + goto overlapped_tag;
    + }
    + }
    +
    + list_for_each_entry(tmp_tmiu, &curlun->tm_func_queue, node) {
    +
    + if (tmp_tmiu->state != COMMAND_STATE_IDLE &&
    + tmp_tmiu->state != COMMAND_STATE_STATUS)
    + continue;
    + /* Overlapped tag found */
    + if (tmp_tmiu->tag == tag)
    + goto overlapped_tag;
    + }
    + spin_unlock_irqrestore(&(curlun->lock), flags);
    + }
    +
    + spin_lock_irqsave(&(udev->ucommon->common->lock), flags);
    + list_for_each_entry(tmp_cmdiu, &udev->cmd_queue, node) {
    + if (tmp_cmdiu->state != COMMAND_STATE_IDLE &&
    + tmp_cmdiu->state != COMMAND_STATE_DATA &&
    + tmp_cmdiu->state != COMMAND_STATE_STATUS)
    + continue;
    +
    + /* Overlapped tag found */
    + if (tmp_cmdiu->tag == tag) {
    + spin_unlock_irqrestore(&(udev->ucommon->common->lock),
    + flags);
    + goto overlapped_tag;
    + }
    + }
    +
    + list_for_each_entry(tmp_tmiu, &udev->tm_func_queue, node) {
    + if (tmp_tmiu->state != COMMAND_STATE_IDLE &&
    + tmp_tmiu->state != COMMAND_STATE_STATUS)
    + continue;
    +
    + /* Overlapped tag found */
    + if (tmp_tmiu->tag == tag) {
    + spin_unlock_irqrestore(&(udev->ucommon->common->lock),
    + flags);
    + goto overlapped_tag;
    + }
    + }
    + spin_unlock_irqrestore(&(udev->ucommon->common->lock), flags);
    +
    + /* No overlapped tag */
    + if (cmd_id == IU_ID_TASK_MANAGEMENT)
    + return 0;
    +
    + return 1;
    +
    +overlapped_tag:
    + ERROR(udev->ucommon->common, "%s() - Overlapped tag found. "
    + "Aborting all\n", __func__);
    +
    + run_lun_threads(udev, LUN_STATE_OVERLAPPED_TAG);
    +
    + /* Wait for luns abort completion. Sleep if luns are in processing */
    + while (!all_lun_state_non_processing(udev)) {
    + DBG(udev->ucommon->common,
    + "%s() - Luns are in process. Going to sleep\n", __func__);
    + rc = sleep_thread(udev->ucommon->common);
    + if (rc) {
    + ERROR(udev->ucommon->common,
    + "%s() - sleep_thread failed! (%d)", __func__, rc);
    + return -EINVAL;
    + }
    + DBG(udev->ucommon->common, "%s() - Wakes up\n", __func__);
    + rc = 0;
    + }
    +
    + /* Abort none-lun commands */
    + abort_commands(udev, &udev->cmd_queue, &udev->tm_func_queue,
    + &(udev->ucommon->common->lock));
    +
    + spin_lock_irqsave(&(udev->ucommon->common->lock), flags);
    + udev->pending_requests = 0;
    + spin_unlock_irqrestore(&(udev->ucommon->common->lock), flags);
    +
    + if (cmd_id == IU_ID_TASK_MANAGEMENT) {
    + tmiu = *command;
    +
    + spin_lock_irqsave(&(udev->ucommon->common->lock), flags);
    + tmiu->bh = get_buffhd(udev->ucommon->common->buffhds);
    + spin_unlock_irqrestore(&(udev->ucommon->common->lock), flags);
    +
    + if (!tmiu->bh) {
    + ERROR(udev->ucommon->common,
    + "%s(): didnt manage to get buffers for tmiu!\n",
    + __func__);
    + return -EINVAL;
    + }
    + fill_response_iu(udev, (struct response_iu *)tmiu->bh->buf,
    + tmiu->tag, 0,
    + RESPONSE_OVERLAPPED_TAG_ATTEMPTED);
    + fill_usb_request(tmiu->bh->inreq, tmiu->bh->buf,
    + UASP_SIZEOF_RESPONSE_IU, 0,
    + (void *)tmiu, 0,
    + be16_to_cpup(&tmiu->tag), status_complete);
    +
    + tmiu->ep = udev->status;
    + tmiu->bh->inreq_busy = 1;
    + if (usb_ep_queue(tmiu->ep, tmiu->bh->inreq, 0))
    + tmiu->state = COMMAND_STATE_FAILED;
    + else
    + tmiu->state = COMMAND_STATE_STATUS;
    + list_add_tail(&tmiu->node, &(udev->tm_func_queue));
    + } else {
    + cmdiu = *command;
    +
    + spin_lock_irqsave(&(udev->ucommon->common->lock), flags);
    + cmdiu->bh = get_buffhd(udev->ucommon->common->buffhds);
    + spin_unlock_irqrestore(&(udev->ucommon->common->lock), flags);
    +
    + if (!cmdiu->bh) {
    + ERROR(udev->ucommon->common,
    + "%s(): didnt manage to get buffers for cmdiu!\n",
    + __func__);
    + return -EINVAL;
    + }
    +
    + fill_sense_iu(udev, (struct sense_iu *)cmdiu->bh->buf,
    + cmdiu->tag, STATUS_CHECK_CONDITION,
    + SS_OVERLAPPED_COMMANDS_ATTEMPTED);
    + fill_usb_request(cmdiu->bh->inreq, cmdiu->bh->buf,
    + UASP_SIZEOF_SENSE_IU, 0,
    + (void *)cmdiu, 0,
    + be16_to_cpup(&cmdiu->tag), status_complete);
    + cmdiu->ep = udev->status;
    + cmdiu->bh->inreq_busy = 1;
    + if (usb_ep_queue(cmdiu->ep, cmdiu->bh->inreq, 0))
    + cmdiu->state = COMMAND_STATE_FAILED;
    + else
    + cmdiu->state = COMMAND_STATE_STATUS;
    + list_add_tail(&cmdiu->node, &(udev->cmd_queue));
    + }
    + return -EINVAL;
    +}
    +
    +/**
    + * insert_tm_func_to_list() - Insert the tmiu to the appropriate queue
    + * @udev: Programming view of uasp device.
    + * @tmiu: the tmiu to place in the appropriate queue
    + *
    + * This function tries to allocate the LUN corresponding to the LUN id in the
    + * received tmiu. If such LUN is found the tmiu is placed in it's tm_func_queue.
    + * If the LUN wasn't found then the tmiu will be placed in the general
    + * tm_func_queue .
    + *
    + * TODO: Should this be protected by locks?
    + */
    +static void insert_tm_func_to_list(struct uasp_dev *udev, struct tm_iu *tmiu)
    +{
    + struct tm_iu *tmiu1;
    + struct uasp_lun *curlun;
    +
    + DBG(udev->ucommon->common, "%s() - Enter\n", __func__);
    +
    + curlun = find_lun_by_id(udev, tmiu->lun);
    + tmiu->state = COMMAND_STATE_IDLE;
    +
    + if (tmiu->tm_function == TM_FUNCTION_IT_NEXUS_RESET) {
    + list_add(&tmiu->node, &udev->tm_func_queue);
    + return;
    + }
    +
    + if (!curlun) {
    + list_add_tail(&tmiu->node, &udev->tm_func_queue);
    + return;
    + }
    +
    + /* tmiu should be handled by curlun */
    +
    + if (tmiu->tm_function == TM_FUNCTION_RESET_LUN) {
    + list_add(&tmiu->node, &curlun->tm_func_queue);
    + return;
    + }
    +
    + /*
    + * Insert tmiu to queue acording to the folowing priority:
    + * 1.TM_FUNCTION_RESET_LUN
    + * 2. TM_FUNCTION_ABORT_TASK_SET or TM_FUNCTION_CLEAR_TASK_SET
    + * 3. TM_FUNCTION_ABORT_TASK
    + * 4. TM_FUNCTION_QUERY_ASYNC_EVENT
    + * All other...
    + */
    + list_for_each_entry(tmiu1, &curlun->tm_func_queue, node) {
    + if (tmiu1->tm_function == TM_FUNCTION_RESET_LUN)
    + continue;
    +
    + if (tmiu->tm_function == TM_FUNCTION_ABORT_TASK_SET ||
    + tmiu->tm_function == TM_FUNCTION_CLEAR_TASK_SET) {
    + list_add(&tmiu->node, &tmiu1->node);
    + return;
    + }
    +
    + if (tmiu1->tm_function == TM_FUNCTION_ABORT_TASK_SET ||
    + tmiu1->tm_function == TM_FUNCTION_CLEAR_TASK_SET)
    + continue;
    +
    + if (tmiu->tm_function == TM_FUNCTION_ABORT_TASK) {
    + list_add(&tmiu->node, &tmiu1->node);
    + return;
    + }
    +
    + if (tmiu1->tm_function == TM_FUNCTION_ABORT_TASK)
    + continue;
    +
    + if (tmiu->tm_function == TM_FUNCTION_QUERY_ASYNC_EVENT) {
    + list_add(&tmiu->node, &tmiu1->node);
    + return;
    + }
    +
    + if (tmiu1->tm_function == TM_FUNCTION_QUERY_ASYNC_EVENT)
    + continue;
    +
    + list_add_tail(&tmiu->node, &tmiu1->node);
    + return;
    + }
    +
    + list_add_tail(&tmiu->node, &tmiu1->node);
    +}
    +
    +/**
    + * insert_cmd_to_list() - Insert the tmiu to the appropriate queue
    + * @udev: Programming view of uasp device.
    + * @cmdiu: the cmdiu to place in the appropriate queue
    + *
    + * This function tries to locate the LUN corresponding to the LUN id in the
    + * received cmdiu. If such LUN is found the cmdiu is placed in it's cmd_queue.
    + * If the LUN wasn't found then the cmdiu will be placed in the general
    + * cmd_queue.
    + *
    + * TODO: Should this be protected by locks?
    + */
    +static void insert_cmd_to_list(struct uasp_dev *udev, struct cmd_iu *cmdiu)
    +{
    + struct list_head *link;
    + struct cmd_iu *cmdiu1;
    + struct uasp_lun *curlun;
    +
    + DBG(udev->ucommon->common, "%s(): cmdiu->lun = %p\n", __func__,
    + cmdiu->lun);
    +
    + DBG(udev->ucommon->common, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
    + cmdiu->lun[0], cmdiu->lun[1], cmdiu->lun[2], cmdiu->lun[3],
    + cmdiu->lun[4], cmdiu->lun[5], cmdiu->lun[6], cmdiu->lun[7]);
    +
    + curlun = find_lun_by_id(udev, cmdiu->lun);
    + cmdiu->state = COMMAND_STATE_IDLE;
    +
    + if (!curlun)
    + link = &udev->cmd_queue;
    + else
    + link = &curlun->cmd_queue;
    +
    + /* Place cmdiu in the queue, in the right place */
    + if (cmdiu->forth_byte.task_attribute == TASK_ATTR_ACA) {
    + list_add(&cmdiu->node, link);
    + return;
    + }
    +
    + list_for_each_entry(cmdiu1, link, node) {
    + /* ACA should be in the head of the queue */
    + if (cmdiu1->forth_byte.task_attribute == TASK_ATTR_ACA)
    + continue;
    +
    + /* The new HEAD OF QUEUE should be placed after ACA */
    + if (cmdiu1->forth_byte.task_attribute ==
    + TASK_ATTR_HEAD_OF_QUEUE) {
    + list_add(&cmdiu->node, &cmdiu1->node);
    + return;
    + }
    +
    + /* If ORDERED or SIMPLE, place at the end of the queue */
    + list_add_tail(&cmdiu->node, link);
    + return;
    + }
    +
    + /* In the case when the queue is empty */
    + list_add_tail(&cmdiu->node, link);
    + DBG(udev->ucommon->common,
    + "%s() - Cmdiu is added to the tail of the queue\n", __func__);
    +}
    +
    +/**
    + * get_command() - Gets the next command from command emdpoint
    + * @udev: Programming view of uasp device.
    + *
    + * Return 0 if no error condition, negative value otherwise.
    + *
    + * This function is responsible for:
    + * - Utilizing the command endpoint.
    + * - Checking of the received data for accuracy. For more details please see
    + * the description of the uasp_command_check() function.
    + * - Adding the received TM FUNCTION or COMMAND IU to the appropriate queue.
    + */
    +static int get_command(struct uasp_dev *udev)
    +{
    + int rc = 0;
    + void *command = 0;
    +
    + DBG(udev->ucommon->common, "%s() - Enter\n", __func__);
    +
    +queue_cmd_ep:
    + /* If command endpoint is not active, activate */
    + if (udev->cmd_buff.state == BUF_STATE_EMPTY) {
    + udev->cmd_buff.state = BUF_STATE_BUSY;
    + /* Queue a request to read the next command */
    + udev->cmd_buff.outreq->buf = udev->cmd_buff.buf;
    + udev->cmd_buff.outreq->complete = command_complete;
    + udev->cmd_buff.outreq->length =
    + (FSG_BUFLEN < udev->command->maxpacket ? FSG_BUFLEN :
    + udev->command->maxpacket);
    + udev->cmd_buff.outreq->short_not_ok = 1;
    + rc = usb_ep_queue(udev->command, udev->cmd_buff.outreq, 0);
    + if (rc) {
    + ERROR(udev->ucommon->common,
    + "%s()usb_ep_queue failed = %d\n", __func__, rc);
    + udev->cmd_buff.state = BUF_STATE_EMPTY;
    + }
    + DBG(udev->ucommon->common, "%s() queued command request = %p\n",
    + __func__, udev->cmd_buff.outreq);
    + return rc;
    + }
    + /* If command endpoint is busy, do nothing */
    + else if (udev->cmd_buff.state == BUF_STATE_BUSY)
    + return rc;
    +
    + rc = uasp_command_check(udev, &command);
    +
    + if (rc == 0) {
    + DBG(udev->ucommon->common, "%s() - Received a TMC IU\n",
    + __func__);
    + insert_tm_func_to_list(udev, (struct tm_iu *)command);
    + udev->cmd_buff.state = BUF_STATE_EMPTY;
    + goto queue_cmd_ep;
    + } else if (rc == 1) {
    + DBG(udev->ucommon->common, "%s() -Received a CMD IU\n",
    + __func__);
    + insert_cmd_to_list(udev, (struct cmd_iu *)command);
    + udev->cmd_buff.state = BUF_STATE_EMPTY;
    + goto queue_cmd_ep;
    + }
    +
    + return rc;
    +}
    +
    +/**
    + * all_lun_state_non_processing() - Returns 1, if all luns are in
    + * none-processing state
    + * @udev: Programming view of uasp device
    + *
    + */
    +int all_lun_state_non_processing(struct uasp_dev *udev)
    +{
    + struct uasp_lun *curlun;
    + int i;
    +
    + DBG(udev->ucommon->common, "%s() - Enter\n", __func__);
    +
    + for (i = 0; i < udev->ucommon->common->nluns; ++i) {
    + curlun = &udev->ucommon->uluns[i];
    + if (curlun->lun_state > LUN_STATE_IDLE)
    + return 0;
    + }
    + return 1;
    +}
    +
    +/*
    + * pending_cmd_in_lun() - Checks for pending IUs in all LUNs queues
    + * @data: Programming view of uasp device
    + *
    + * Returns 1 if all luns are in non-processing state and and if are incomplete
    + * or pending commands in one of the luns.
    + */
    +static int pending_cmd_in_lun(void *data)
    +{
    + struct uasp_dev *udev = (struct uasp_dev *)data;
    + struct uasp_lun *curlun;
    + int i;
    +
    + DBG(udev->ucommon->common, "%s() - Enter\n", __func__);
    + for (i = 0; i < udev->ucommon->common->nluns; ++i) {
    + curlun = &udev->ucommon->uluns[i];
    + if (curlun->pending_requests)
    + return 1;
    + }
    +
    + return 0;
    +}
    +
    +static int sleep_lun_thread(struct uasp_lun *lun)
    +{
    + int rc = 0;
    +
    + /* Wait until a signal arrives or we are woken up */
    + for (;;) {
    + try_to_freeze();
    + set_current_state(TASK_INTERRUPTIBLE);
    + if (signal_pending(current)) {
    + rc = -EINTR;
    + break;
    + }
    + if (lun->thread_wakeup_needed)
    + break;
    + schedule();
    + }
    + __set_current_state(TASK_RUNNING);
    + lun->thread_wakeup_needed = 0;
    + return rc;
    +}
    +
    +/**
    + * run_lun_threads() - Wakeup all LUN threads with a given state
    + * @udev: Programming view of uasp device
    + * @state: The state to run the LUn in (from enum lun_state)
    + *
    + */
    +void run_lun_threads(struct uasp_dev *udev, int state)
    +{
    + struct uasp_lun *curlun;
    + int i;
    + unsigned long flags;
    +
    + DBG(udev->ucommon->common, "%s() - Enter. State = %d\n",
    + __func__, state);
    +
    + for (i = 0; i < udev->ucommon->common->nluns; ++i) {
    + curlun = &udev->ucommon->uluns[i];
    + spin_lock_irqsave(&(curlun->lock), flags);
    + curlun->lun_state = state;
    + wakeup_lun_thread(curlun);
    + spin_unlock_irqrestore(&(curlun->lock), flags);
    + }
    + DBG(udev->ucommon->common, "%s() - Exit\n", __func__);
    +}
    +
    +/**
    + * abort_commands() - Aborts all IUs on given queues
    + * @udev: Programming view of uasp device
    + * @cmd_queue: pointer to the cmd IUs queue to abort IUs from
    + * @tm_func_queue: pointer to the tm IUs queue to abort IUs from
    + * @lock: pointer to spinlock_t to lock when performing the abort.
    + * Can be udev->lock if the cmd_queue and the tm_func_queue are general,
    + * or curlun->lock if they belong to a specific LUN
    + *
    + * TODO: Add wait mechanism using curlun->active_requests or
    + * udev->active_requests
    + */
    +void abort_commands(struct uasp_dev *udev,
    + struct list_head *cmd_queue,
    + struct list_head *tm_func_queue,
    + spinlock_t *lock)
    +{
    + unsigned long flags;
    + struct cmd_iu *cmdiu, *tmp_cmdiu;
    + struct tm_iu *tmiu, *tmp_tmiu;
    +
    + DBG(udev->ucommon->common, "%s() - Enter\n", __func__);
    +
    + if (!cmd_queue)
    + goto tmiu_part;
    +
    + spin_lock_irqsave(lock, flags);
    + list_for_each_entry_safe(cmdiu, tmp_cmdiu, cmd_queue, node) {
    + if (cmdiu->state == COMMAND_STATE_DATA) {
    + if (cmdiu->req_sts == CMD_REQ_IN_PROGRESS) {
    + spin_unlock_irqrestore(lock, flags);
    + if (cmdiu->bh->inreq_busy)
    + usb_ep_dequeue(cmdiu->ep,
    + cmdiu->bh->inreq);
    + if (cmdiu->bh->outreq_busy)
    + usb_ep_dequeue(cmdiu->ep,
    + cmdiu->bh->outreq);
    + spin_lock_irqsave(lock, flags);
    + }
    + } else if (cmdiu->state == COMMAND_STATE_STATUS) {
    + spin_unlock_irqrestore(lock, flags);
    + usb_ep_dequeue(cmdiu->ep, cmdiu->bh->inreq);
    + spin_lock_irqsave(lock, flags);
    + } else
    + cmdiu->state = COMMAND_STATE_ABORTED;
    + }
    + spin_unlock_irqrestore(lock, flags);
    +
    +tmiu_part:
    + if (!tm_func_queue)
    + return;
    +
    + spin_lock_irqsave(lock, flags);
    + list_for_each_entry_safe(tmiu, tmp_tmiu, tm_func_queue, node) {
    + if (tmiu->state == COMMAND_STATE_STATUS) {
    + spin_unlock_irqrestore(lock, flags);
    + if (tmiu->bh->inreq_busy)
    + usb_ep_dequeue(tmiu->ep, tmiu->bh->inreq);
    + spin_lock_irqsave(lock, flags);
    + } else
    + tmiu->state = COMMAND_STATE_ABORTED;
    + }
    + spin_unlock_irqrestore(lock, flags);
    +}
    +
    +/**
    + * do_uasp() - UASP main routine
    + * @udev: Programming view of uasp device
    + *
    + * This function is responsible for operating based on UASP protocol. It is
    + * responsible for:
    + * - Getting and initial processing of TM FUNCTION IU or COMMAND IU received
    + * from HOST side via command endpoint. For more details please
    + * see the description of get_command() function.
    + * - Processing of TM FUNCTION IUs addressed to IT_NEXUS. For more details
    + * please see the tmiu.c file.
    + * - Processing of COMMAND IUs addressed to IT_NEXUS. For more details
    + * please see the tmiu.c file.
    + * - Running the threads which are responsible for processing of TM FUNCTION
    + * and COMMAND IUs addressed to a certain LUN. For more details please see
    + * the description of fsg_lun_thread(void *_lun) function.
    + */
    +void do_uasp(struct uasp_dev *udev)
    +{
    + unsigned long flags;
    + struct fsg_dev *fsg = &(udev->fsg_dev);
    + struct uasp_common *ucommon = udev->ucommon;
    + int rc;
    +
    + DBG(ucommon->common, "%s() - Enter\n", __func__);
    +
    + spin_lock_irqsave(&(fsg->common->lock), flags);
    + if (!exception_in_progress(fsg->common))
    + fsg->common->state = FSG_STATE_COMMAND_PHASE;
    + spin_unlock_irqrestore(&(fsg->common->lock), flags);
    +
    + if (exception_in_progress(fsg->common))
    + return;
    +
    + if (get_command(udev))
    + return;
    +
    + spin_lock_irqsave(&(fsg->common->lock), flags);
    + if (!exception_in_progress(fsg->common))
    + fsg->common->state = FSG_STATE_DATA_PHASE;
    + spin_unlock_irqrestore(&(fsg->common->lock), flags);
    +
    + if (exception_in_progress(fsg->common))
    + return;
    +
    + spin_lock_irqsave(&(ucommon->common->lock), flags);
    + udev->pending_requests = 0;
    + spin_unlock_irqrestore(&(ucommon->common->lock), flags);
    +
    + do_tmiu(udev, NULL);
    + if (exception_in_progress(fsg->common))
    + return;
    +
    + do_cmdiu(udev, NULL);
    + if (exception_in_progress(fsg->common))
    + return;
    +
    + remove_completed_commands(udev, &udev->cmd_queue, &udev->tm_func_queue);
    +
    + spin_lock_irqsave(&(fsg->common->lock), flags);
    + if (!exception_in_progress(fsg->common)) {
    + fsg->common->state = FSG_STATE_IDLE;
    + spin_unlock_irqrestore(&(fsg->common->lock), flags);
    + run_lun_threads(udev, LUN_STATE_PROCESSING);
    + } else
    + spin_unlock_irqrestore(&(fsg->common->lock), flags);
    +
    + rc = 0;
    + while (!rc) {
    + /* If exception is in progress */
    + if (exception_in_progress(ucommon->common)) {
    + DBG(ucommon->common,
    + "%s() - Exception is in progress\n", __func__);
    + return;
    + }
    +
    + /* Sleep if luns are in processing */
    + rc = all_lun_state_non_processing(udev);
    + if (!rc) {
    + DBG(ucommon->common,
    + "%s() - Luns are in process\n", __func__);
    + goto sleep;
    + }
    +
    + /* Wake up if command is received */
    + if (udev->cmd_buff.state == BUF_STATE_FULL) {
    + DBG(ucommon->common,
    + "%s() - Command is received\n", __func__);
    + return;
    + }
    +
    + /* Wake up if there are pending requests in luns */
    + if (pending_cmd_in_lun(udev)) {
    + DBG(ucommon->common,
    + "%s() - Pending requests in LUN\n", __func__);
    + return;
    + }
    +
    + /* Wake up if there are pending requests */
    + if (udev->pending_requests) {
    + DBG(ucommon->common,
    + "%s() - Pending requests in device\n",
    + __func__);
    + return;
    + }
    +sleep:
    + /* Try to sleep */
    + DBG(ucommon->common, "%s() - Going to sleep\n", __func__);
    + rc = sleep_thread(fsg->common);
    + if (rc)
    + return;
    + DBG(ucommon->common, "%s() - Wakes up\n", __func__);
    +
    + rc = 0;
    + }
    +}
    +
    +/**
    + * close_lun() - Close the backing file of the given LUN
    + * @ulun: pointer to the LUn to close
    + *
    + * This function should be called when fsg_common->filesem is taken!
    + */
    +void close_lun(struct uasp_lun *ulun)
    +{
    + struct fsg_lun *fsglun = ulun->lun;
    +
    + if (!fsg_lun_is_open(fsglun))
    + return;
    +
    + fsg_lun_close(fsglun);
    + fsglun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
    +}
    +
    +static int lun_exception_in_progress(struct uasp_lun *curlun)
    +{
    + if (curlun->lun_state > LUN_STATE_PROCESSING)
    + return 1;
    +
    + return 0;
    +}
    +
    +/**
    + * handle_lun_exception() - Abort all TM and CMD IUs for a given LUN
    + * @udev: Programming view of file storage gadget.
    + * @curlun: Pointer to struct uasp_lun structure.
    + *
    + * This function is responsible for aborting the active TM FUNCTION and
    + * COMMAND IUs connected to the curlun, removing all TM FUNCTION and COMMAND
    + * IUs from appropriate queues, and keeping the exception data if there is a
    + * need.
    + */
    +static void handle_lun_exception(struct uasp_dev *udev, struct uasp_lun *curlun)
    +{
    + unsigned long flags;
    + DBG(udev->ucommon->common, "%s() - Enter\n", __func__);
    +
    + /* Abort all commands and remove them from lists */
    + abort_commands(udev, &curlun->cmd_queue, &curlun->tm_func_queue,
    + &(curlun->lock));
    + remove_completed_commands(udev, &curlun->cmd_queue,
    + &curlun->tm_func_queue);
    + curlun->pending_requests = 0;
    +
    + spin_lock_irqsave(&(curlun->lock), flags);
    + switch (curlun->lun_state) {
    + case LUN_STATE_RESET:
    + curlun->lun->unit_attention_data = SS_RESET_OCCURRED;
    + case LUN_STATE_OVERLAPPED_TAG:
    + curlun->lun_state = LUN_STATE_PROCESSING;
    + break;
    + case LUN_STATE_EXIT:
    + curlun->lun_state = LUN_STATE_TERMINATED;
    + break;
    + default:
    + break;
    + }
    + spin_unlock_irqrestore(&(curlun->lock), flags);
    + DBG(udev->ucommon->common, "%s() - Exit\n", __func__);
    +}
    +
    +/**
    + * uasp_lun_thread() - UASP LUN main thread
    + * @param: pointer to the uasp LUN structure
    + *
    + * Returns 0 on success -1 otherwise
    + *
    + * This function is UASP LUN main thread. It consist of a while loop that
    + * performs the following as long as the LUN state isn't terminated:
    + * - handles LUN exceptions if such exist
    + * - handles LUN specific cmd IUs
    + * - handles LUN specific tm IUs
    + * - removes completed IUs from cmd and tm queues
    + */
    +static int uasp_lun_thread(void *param)
    +{
    + struct uasp_lun *ulun = (struct uasp_lun *)param;
    + struct uasp_dev *udev;
    + unsigned long flags;
    +
    + if (!ulun)
    + return -1;
    + udev = ulun->dev;
    + DBG(udev->ucommon->common, "%s() - Enter for lun_id = %d\n", __func__,
    + ulun->lun_id[7]);
    +
    + while (ulun->lun_state != LUN_STATE_TERMINATED) {
    + DBG(udev->ucommon->common, "%s() - Wakes up\n", __func__);
    +
    + if (lun_exception_in_progress(ulun)) {
    + DBG(udev->ucommon->common,
    + "%s() - exception_in_progress!"
    + " ulun->lun_state=%d\n", __func__,
    + ulun->lun_state);
    + handle_lun_exception(udev, ulun);
    + continue;
    + }
    +
    + /*
    + * If the main thread isn't running, no need to run lun threads
    + * as well.
    + */
    + if (!udev->ucommon->common->running) {
    + DBG(udev->ucommon->common,
    + "%s() - uasp thread main thread not running - "
    + "going to sleep...\n", __func__);
    + sleep_lun_thread(ulun);
    + continue;
    + }
    +
    + spin_lock_irqsave(&(ulun->lock), flags);
    + ulun->pending_requests = 0;
    + spin_unlock_irqrestore(&(ulun->lock), flags);
    +
    + do_tmiu(udev, ulun);
    + if (lun_exception_in_progress(ulun))
    + continue;
    +
    + do_cmdiu(udev, ulun);
    + if (lun_exception_in_progress(ulun))
    + continue;
    +
    + remove_completed_commands(udev, &ulun->cmd_queue,
    + &ulun->tm_func_queue);
    + if (lun_exception_in_progress(ulun))
    + continue;
    +
    + spin_lock_irqsave(&(udev->ucommon->common->lock), flags);
    + if (!lun_exception_in_progress(ulun)) {
    + ulun->lun_state = LUN_STATE_IDLE;
    + wakeup_thread(udev->ucommon->common);
    + }
    + spin_unlock_irqrestore(&(udev->ucommon->common->lock), flags);
    +
    + DBG(udev->ucommon->common, "%s() - Going to sleep\n", __func__);
    + sleep_lun_thread(ulun);
    + continue;
    + }
    +
    + DBG(udev->ucommon->common, "uasp lun main loop: exiting\n");
    + spin_lock_irqsave(&(udev->ucommon->common->lock), flags);
    + ulun->lun_thread_task = NULL;
    + spin_unlock_irqrestore(&(udev->ucommon->common->lock), flags);
    + /* Let the unbind and cleanup routines know the thread has exited */
    + complete_and_exit(&ulun->thread_notifier, 0);
    + return 0;
    +}
    +
    +/**
    + * uasp_main_thread() - UASP main thread
    + * @param: pointer to the uasp_common structure
    + *
    + * This function is UASP main thread. It consist of a while loop that performs
    + * the following as long as the state isn't terminated:
    + * - handles UASP device exceptions if such exist
    + * - calles do_uasp() (see do_uasp() function for more details)
    + * - when state is terminated closed all LUNS
    + */
    +static int uasp_main_thread(void *param)
    +{
    + struct uasp_common *ucommon = (struct uasp_common *)param;
    + struct fsg_common *common = ucommon->common;
    +
    + /*
    + * Allow the thread to be killed by a signal, but set the signal mask
    + * to block everything but INT, TERM, KILL, and USR1.
    + */
    + allow_signal(SIGINT);
    + allow_signal(SIGTERM);
    + allow_signal(SIGKILL);
    + allow_signal(SIGUSR1);
    +
    + /* Allow the thread to be frozen */
    + set_freezable();
    +
    + /*
    + * Arrange for userspace references to be interpreted as kernel
    + * pointers. That way we can pass a kernel pointer to a routine
    + * that expects a __user pointer and it will work okay.
    + */
    + set_fs(get_ds());
    +
    + /* The main loop */
    + while (common->state != FSG_STATE_TERMINATED) {
    + DBG(common, "uasp main loop: continuing\n");
    + if (exception_in_progress(ucommon->common) ||
    + signal_pending(current)) {
    + DBG(common, "uasp thread main loop: exception\n");
    + handle_uasp_exception(ucommon);
    + continue;
    + }
    +
    + if (!common->running) {
    + DBG(common, "uasp thread main loop: not running\n");
    + sleep_thread(ucommon->common);
    + continue;
    + }
    + do_uasp(ucommon->udev);
    + }
    +
    + DBG(common, "uasp main loop: exiting\n");
    +
    + spin_lock_irq(&common->lock);
    + common->thread_task = NULL;
    + spin_unlock_irq(&common->lock);
    +
    + if (!common->ops || !common->ops->thread_exits ||
    + common->ops->thread_exits(common) < 0) {
    + struct uasp_lun *ulun = ucommon->uluns;
    + unsigned i ;
    + down_write(&common->filesem);
    + for (i = 0; i < common->nluns; i++, ulun++)
    + close_lun(ulun);
    + up_write(&common->filesem);
    + }
    +
    + /* Let the unbind and cleanup routines know the thread has exited */
    + complete_and_exit(&common->thread_notifier, 0);
    +
    + return 0;
    +}
    +
    +/**
    + * uasp_common_init() - Init uasp_common data structure
    + * @common: pointer to inited fsg_common data structure
    + * @cdev: pointer to usb_composite device that the UASP function is a part of
    + * @cfg: pointer to fsg_config data structure
    + *
    + * This function should be called after (struct fsg_common) common was already
    + * initiated by fsg_common_init
    + */
    +static struct uasp_common *uasp_common_init(struct fsg_common *common,
    + struct usb_composite_dev *cdev,
    + struct fsg_config *cfg)
    +{
    + struct fsg_lun *flun;
    + struct uasp_lun *ulun;
    + struct uasp_common *ucommon;
    + int nluns = common->nluns;
    + int i, rc;
    +
    + if (!common || !cdev || !cfg)
    + return NULL;
    +
    + DBG(common, "%s() - Enter\n", __func__);
    +
    + ucommon = kzalloc(sizeof *ucommon, GFP_KERNEL);
    + if (unlikely(!ucommon))
    + return NULL;
    +
    + /* Save reference to fsg_common structure in ucommon */
    + ucommon->common = common;
    +
    + /* Allocate the uLUNs and init them according to fsg_common luns */
    + ulun = kzalloc(nluns * sizeof *ulun, GFP_KERNEL);
    + if (!ulun) {
    + kfree(ucommon);
    + return ERR_PTR(-ENOMEM);
    + }
    + ucommon->uluns = ulun;
    +
    + /* Create the reference between ulun and fsg_lun */
    + for (i = 0, flun = common->luns; i < nluns;
    + ++i, ++flun, ++ulun)
    + ulun->lun = flun;
    +
    + /*
    + * Buffers in ubufs are static -- no need for additional allocation.
    + * Connect each ubuf to fsg_buff from the buffhds cyclic list
    + */
    + for (i = 0; i < fsg_num_buffers; i++) {
    + ucommon->ubufs[i].fsg_buff = &(common->buffhds[i]);
    + ucommon->ubufs[i].ep = NULL;
    + ucommon->ubufs[i].stream_id = 0;
    + }
    +
    + kref_init(&ucommon->ref);
    + /* Tell the thread to start working */
    + common->thread_task =
    + kthread_create(uasp_main_thread, (void *)ucommon,
    + cfg->thread_name ?: "file-storage-UASP");
    + if (IS_ERR(common->thread_task)) {
    + rc = PTR_ERR(common->thread_task);
    + goto error_release;
    + }
    +
    +
    + /* Information */
    + INFO(common, UASP_DRIVER_DESC ", version: " UASP_DRIVER_VERSION "\n");
    + DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task));
    +
    + wake_up_process(common->thread_task);
    +
    + return ucommon;
    +
    +error_release:
    + common->state = FSG_STATE_TERMINATED; /* The thread is dead */
    + /* Call uasp_common_release() directly, ref might be not initialised */
    + uasp_common_release(&common->ref);
    + return ERR_PTR(rc);
    +}
    +
    +/**
    + * finish_lun_init() - Finish the LUN structure inialization
    + * @udev: Programming view of file storage gadget.
    + *
    + * This function is used to init the uasp_lun fileds. It's called from uasp_add
    + * after the uasp_dev was allocated. It creates (and starts) all lun tasks
    + */
    +static int finish_lun_init(struct uasp_dev *udev)
    +{
    + int i, j, rc = 0;
    + struct uasp_lun *ulun = NULL;
    + char thread_name[20];
    +
    + if (!udev)
    + return -EIO;
    +
    + for (i = 0, ulun = udev->ucommon->uluns;
    + i < udev->ucommon->common->nluns; i++, ulun++) {
    + /* TODO: this is a workaround, fix later */
    + memset(ulun->lun_id, 0, 8);
    + ulun->lun_id[0] = i;
    + INIT_LIST_HEAD(&ulun->cmd_queue);
    + INIT_LIST_HEAD(&ulun->tm_func_queue);
    + ulun->lun_state = LUN_STATE_IDLE;
    + ulun->dev = udev;
    + ulun->pending_requests = ulun->active_requests = 0;
    +
    + /* Create and start lun threads */
    + sprintf(thread_name, "uasp-lun-thread%d", i);
    + DBG(udev->ucommon->common,
    + "creating & starting lun thread: thread_name = %s\n",
    + thread_name);
    +
    + ulun->lun_thread_task = kthread_create(uasp_lun_thread,
    + (void *)ulun,
    + thread_name);
    + if (IS_ERR(ulun->lun_thread_task)) {
    + rc = PTR_ERR(ulun->lun_thread_task);
    + goto err_lun_init;
    + }
    + init_completion(&ulun->thread_notifier);
    + wake_up_process(ulun->lun_thread_task);
    + }
    + INFO(udev->ucommon->common, "All lun threads are started\n");
    + return rc;
    +
    +err_lun_init:
    + for (j = 0, ulun = udev->ucommon->uluns ; j < i; j++, ulun++)
    + ulun->lun_state = LUN_STATE_EXIT;
    + return rc;
    +}
    +
    +/*
    + * uasp_bind() - bind function
    + * @c: pointer to the usb configuration
    + * @f: pointer to the usb function
    + *
    + * Return 0 on succeed, error code on failure
    + *
    + * TODO: Add fall back to usb_ep_autoconfig() if usb_ep_autoconfig_ss() fails.
    + * In that case mark somehow that we can only operate in HS mode
    + */
    +static int __init uasp_bind(struct usb_configuration *c, struct usb_function *f)
    +{
    + struct uasp_dev *uaspd = uaspd_from_func(f);
    + struct fsg_dev *fsgd = &(uaspd->fsg_dev);
    + struct usb_gadget *gadget = c->cdev->gadget;
    + int rc;
    + int i;
    + struct usb_ep *ep;
    +
    + fsgd->common->gadget = gadget;
    +
    + /* Allocate new interface */
    + i = usb_interface_id(c, f);
    + if (i < 0)
    + return i;
    + uasp_intf_desc.bInterfaceNumber = i;
    + fsgd->interface_number = i;
    +
    + /* Find all the endpoints we will use */
    + ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bulk_in_desc,
    + &uasp_bulk_in_ep_comp_desc);
    + if (!ep)
    + goto autoconf_fail;
    + ep->driver_data = uaspd; /* claim the endpoint */
    + fsgd->bulk_in = ep;
    +
    + ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bulk_out_desc,
    + &uasp_bulk_out_ep_comp_desc);
    + if (!ep)
    + goto autoconf_fail;
    + ep->driver_data = uaspd; /* claim the endpoint */
    + fsgd->bulk_out = ep;
    +
    + ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_status_in_desc,
    + &uasp_status_in_ep_comp_desc);
    + if (!ep)
    + goto autoconf_fail;
    + ep->driver_data = uaspd; /* claim the endpoint */
    + uaspd->status = ep;
    +
    + ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_command_out_desc,
    + &uasp_command_out_ep_comp_desc);
    + if (!ep)
    + goto autoconf_fail;
    + ep->driver_data = uaspd; /* claim the endpoint */
    + uaspd->command = ep;
    +
    + /* Assume endpoint addresses are the same for both speeds */
    + uasp_bulk_in_desc.bEndpointAddress =
    + uasp_ss_bulk_in_desc.bEndpointAddress;
    + uasp_bulk_out_desc.bEndpointAddress =
    + uasp_ss_bulk_out_desc.bEndpointAddress;
    + uasp_status_in_desc.bEndpointAddress =
    + uasp_ss_status_in_desc.bEndpointAddress;
    + uasp_command_out_desc.bEndpointAddress =
    + uasp_ss_command_out_desc.bEndpointAddress;
    + f->ss_descriptors = uasp_ss_function_desc;
    +
    + return 0;
    +
    +autoconf_fail:
    + ERROR(fsgd->common, "unable to autoconfigure all endpoints\n");
    + rc = -ENOTSUPP;
    + return rc;
    +}
    +
    +static void uasp_unbind(struct usb_configuration *c, struct usb_function *f)
    +{
    + struct uasp_dev *uaspd = uaspd_from_func(f);
    +
    + DBG(uaspd->fsg_dev.common, "unbind\n");
    + if (uaspd->fsg_dev.common->fsg == &(uaspd->fsg_dev)) {
    + uaspd->fsg_dev.common->new_fsg = NULL;
    + raise_exception(uaspd->fsg_dev.common, FSG_STATE_CONFIG_CHANGE);
    + /* TODO: make interruptible or killable somehow? */
    + wait_event(uaspd->fsg_dev.common->fsg_wait,
    + !uaspd->ucommon->common->fsg);
    + }
    + uasp_common_put(uaspd->ucommon);
    + kfree(uaspd->cmd_buff.buf);
    + kfree(uaspd);
    +}
    +
    +static int uasp_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
    +{
    + struct fsg_dev *fsg = fsg_from_func(f);
    + fsg->common->new_fsg = fsg;
    + raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
    + return 0;
    +}
    +
    +static void uasp_disable(struct usb_function *f)
    +{
    + struct uasp_dev *udev = uaspd_from_func(f);
    +
    + udev->fsg_dev.common->new_fsg = NULL;
    + raise_exception(udev->fsg_dev.common, FSG_STATE_CONFIG_CHANGE);
    +}
    +
    +/**
    + * uasp_add() - Add the UASP function to the given configuration
    + * @cdev: pointer to the composite device
    + * @c: usb configuration to add the function to
    + * @common: pointer to the fsg_common data structure
    + * @ucommon: pointer to uasp common data structure
    + *
    + * Returns 0 on sucsess error code otherwise
    + *
    + * Initiate the uasp_function and adds it to the given configuration by calling
    + * usb_add_function()
    + */
    +static int uasp_add(struct usb_composite_dev *cdev,
    + struct usb_configuration *c,
    + struct fsg_common *common,
    + struct uasp_common *ucommon)
    +{
    + struct uasp_dev *uaspd;
    + int rc;
    +
    + uaspd = kzalloc(sizeof *uaspd, GFP_KERNEL);
    + if (unlikely(!uaspd))
    + return -ENOMEM;
    +
    + uaspd->fsg_dev.function.name = UASP_DRIVER_DESC;
    + uaspd->fsg_dev.function.strings = fsg_strings_array;
    + uaspd->fsg_dev.function.descriptors = uasp_hs_function_desc;
    + uaspd->fsg_dev.function.hs_descriptors = uasp_hs_function_desc;
    + uaspd->fsg_dev.function.bind = uasp_bind;
    + uaspd->fsg_dev.function.unbind = uasp_unbind;
    + uaspd->fsg_dev.function.set_alt = uasp_set_alt;
    + uaspd->fsg_dev.function.disable = uasp_disable;
    +
    + uaspd->fsg_dev.common = common;
    +
    + uaspd->ucommon = ucommon;
    +
    + /* Init the command and status buffers */
    + uaspd->cmd_buff.buf = kmalloc(FSG_BUFLEN, GFP_KERNEL);
    + if (unlikely(!uaspd->cmd_buff.buf)) {
    + rc = -ENOMEM;
    + goto uasp_add_err;
    + }
    +
    + ucommon->udev = uaspd;
    + rc = finish_lun_init(uaspd);
    + if (rc)
    + goto uasp_add_err;
    +
    + INIT_LIST_HEAD(&uaspd->cmd_queue);
    + INIT_LIST_HEAD(&uaspd->tm_func_queue);
    + /*
    + * Our caller holds a reference to common structure so we don't have
    + * to be worry about it being freed until we return from this function.
    + * So instead of incrementing counter now and decrement in error
    + * recovery we increment it only when call to usb_add_function() was
    + * successful.
    + */
    + rc = usb_add_function(c, &uaspd->fsg_dev.function);
    +
    + if (likely(rc == 0))
    + kref_get(&ucommon->ref);
    + else
    + goto uasp_add_err;
    +
    + return rc;
    +uasp_add_err:
    + kfree(ucommon);
    + kfree(uaspd->cmd_buff.buf);
    + kfree(uaspd);
    + return rc;
    +}
    +
    +/**
    + * fill_usb_request() - fills the usb_request structure with the given values.
    + * @req: pointer to usb_request structure to be filled.
    + * @buf: the buffer to send/receive
    + * @length: length field of the request.
    + * @zero: zero field of the request.
    + * @context: context field of the request.
    + * @short_not_ok: short_not_ok field of the request.
    + * @stream_id: stream_id field of the request.
    + * @complete: complete function to be called on request completion
    + *
    + */
    +void fill_usb_request(struct usb_request *req,
    + void *buf,
    + unsigned length,
    + unsigned zero,
    + void *context,
    + unsigned short_not_ok,
    + unsigned stream_id,
    + usb_request_complete_t complete)
    +{
    + req->buf = buf;
    + req->length = length;
    + req->zero = zero;
    + req->context = context;
    + req->short_not_ok = short_not_ok;
    + req->stream_id = stream_id;
    + req->complete = complete;
    +}
    +
    diff --git a/drivers/usb/gadget/f_uasp.h b/drivers/usb/gadget/f_uasp.h
    new file mode 100644
    index 0000000..f283589
    --- /dev/null
    +++ b/drivers/usb/gadget/f_uasp.h
    @@ -0,0 +1,430 @@
    +/*
    + * f_uasp.h -- Mass Storage USB UASP Composite Function header
    + *
    + * Copyright (C) 2003-2005 Alan Stern
    + * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 and
    + * only version 2 as published by the Free Software Foundation.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + * GNU General Public License for more details.
    + */
    +
    +#ifndef _F_UASP_H
    +#define _F_UASP_H
    +
    +#include <linux/kernel.h>
    +#include <scsi/scsi.h>
    +#include <scsi/scsi_cmnd.h>
    +
    +#define UASP_DRIVER_DESC "Mass Storage UASP Function"
    +#define UASP_DRIVER_VERSION "2010/07/1"
    +
    +/* Pipe usage descriptor: refer to UAS spec 5.3.3.5 */
    +#define USB_DT_PIPE_USAGE 0x24
    +
    +typedef void (*usb_request_complete_t)(struct usb_ep *ep,
    + struct usb_request *req);
    +
    +/* IU identifier summary - see table 10 of the UAS Spec */
    +enum iu_id {
    + IU_ID_COMMAND = 0x01,
    + IU_ID_SENSE = 0x03,
    + IU_ID_RESPONSE = 0x04,
    + IU_ID_TASK_MANAGEMENT = 0x05,
    + IU_ID_READ_READY = 0x06,
    + IU_ID_WRITE_READY = 0x07,
    +};
    +
    +/* TASK ATTRIBUTE field - see table 13 of the UAS Spec */
    +enum task_attribute_data {
    + TASK_ATTR_SIMPLE = 0,
    + TASK_ATTR_HEAD_OF_QUEUE = 1,
    + TASK_ATTR_ORDERED = 2,
    + TASK_ATTR_ACA = 4,
    +};
    +
    +/* USB_DT_PIPE_USAGE: Pipe usage descriptor */
    +struct usb_pipe_usage_descriptor {
    + __u8 bLength;
    + __u8 bDescriptorType;
    +
    + __u8 bPipeID;
    +/* Pipe ID defenitions: Table 9 from UAS spec*/
    +#define PIPE_ID_CMD 0x01 /* Command pipe */
    +#define PIPE_ID_STS 0x02 /* Status pipe */
    +#define PIPE_ID_DATA_IN 0x03 /* Data-in piep */
    +#define PIPE_ID_DATA_OUT 0x04 /* Data-out pipe */
    + __u8 Reserved;
    +} __attribute__((__packed__));
    +
    +/**
    + * struct uasp_buff - UASP buffer definition.
    + * @fsg_buff: pointer to the fsg_buf that this structure extends
    + * @ep: the ep the buff was allocated for
    + * @stream_id: Same as in struct usb_req
    + *
    + * Extends the struct fsg_buffhd. Each (used) buffer will be assigned to a
    + * specific stream. The stream is the same as the stream_id in the usb_request
    + * the buffer is assigned for.
    + * Note: stream_id has a meaning only when ep != null
    + */
    +struct uasp_buff {
    + struct fsg_buffhd *fsg_buff;
    + struct usb_ep *ep;
    + unsigned stream_id:16;
    +};
    +
    +/**
    + * struct uasp_common - Common data shared by all UASP devices
    + * @udev: Programming view of uasp device.
    + * @common: points to fsg_common in fsg_dev
    + * @ubufs: buffers to be used by the uasp device. Each element in
    + * ubufs[i].fsg_buff points to a fsg_buffhd struct from fsg_common data
    + * structure
    + * @uluns: luns of the uasp device. Each element in uluns[i].lun points to a
    + * fsg_lun array element from fsg_common data structure
    + *
    + * Extends the struct fsg_common structure.
    + */
    +struct uasp_common {
    + struct uasp_dev *udev;
    + struct fsg_common *common;
    + struct uasp_buff ubufs[fsg_num_buffers];
    + struct uasp_lun *uluns;
    + struct kref ref;
    +};
    +
    +/**
    + * struct uasp_dev - Programming view of the uasp device
    + * @fsg_dev: pointer to the fsg_dev this struct extends
    + * @ucommon: pointer to the common data of the device
    + * @status: status endpoint
    + * @command: command endpoint
    + * @cmd_buff: buffer used for receiving commannd IUs
    + * @op_mode: operation mode (HS_UASP_MODE/SS_UASP_MODE)
    + * @cmd_enabled: TRUE if command endpoint is enabled
    + * @status_enabled: TRUE if status endpoint is enabled
    + * @cmd_queue: General Command IUs queue
    + * @tm_func_queue: General Task Management IUs queue
    + * @active_requests: counter for currently handled (active) general requests
    + * @pending_requests: counter for pending general requests
    + *
    + * Extends the struct fsg_dev structure.
    + */
    +struct uasp_dev {
    + struct fsg_dev fsg_dev;
    +
    + struct uasp_common *ucommon;
    + struct usb_ep *status;
    + struct usb_ep *command;
    + struct fsg_buffhd cmd_buff;
    +
    + unsigned int cmd_enabled;
    + unsigned int status_enabled;
    +
    + struct list_head cmd_queue;
    + struct list_head tm_func_queue;
    + int active_requests;
    + int pending_requests;
    +};
    +
    +/* LUN state */
    +enum lun_state {
    + LUN_STATE_IDLE = 0,
    + LUN_STATE_PROCESSING = 1,
    + LUN_STATE_RESET = 2,
    + LUN_STATE_OVERLAPPED_TAG = 3,
    + LUN_STATE_EXIT = 4,
    + LUN_STATE_TERMINATED = 5,
    +};
    +
    +/**
    + * struct uasp_lun - Describes the uasp LUN
    + * @lun: pointer to the fsg_lun this struct extends
    + * @lun_id: id of this LUN
    + * @cmd_queue: Command IUs queue
    + * @tm_func_queue: TaskManagement IUs queue
    + * @lun_state: one of the values from enum lun_state
    + * @dev: Programming view of uasp device.
    + * @lock: lock protects for protecting: state, all the req_busy's
    + * @thread_wakeup_needed: TRUE if the LUN thread needs wakening
    + * @lun_thread_task: thread of this LUN. Performs all LUN tasks
    + * @thread_notifier: used for lun_thread_task
    + * @pending_requests: counter for pending requests for this LUN
    + * @active_requests: counter for currently handled (active) requests for
    + * this LUN
    + *
    + * Extends the struct fsg_lun structure.
    + */
    +struct uasp_lun {
    + struct fsg_lun *lun;
    + __u8 lun_id[8];
    + struct list_head cmd_queue;
    + struct list_head tm_func_queue;
    + enum lun_state lun_state;
    + struct uasp_dev *dev;
    +
    + spinlock_t lock;
    +
    + int thread_wakeup_needed;
    + struct task_struct *lun_thread_task;
    + struct completion thread_notifier;
    +
    + int pending_requests;
    + int active_requests;
    +};
    +
    +
    +/* COMMAND IU related defenitions*/
    +/* COMMAND IU state */
    +enum command_state {
    + COMMAND_STATE_IDLE = 0,
    + COMMAND_STATE_RR_WR = 1,
    + COMMAND_STATE_DATA = 2,
    + COMMAND_STATE_STATUS = 3,
    + COMMAND_STATE_ABORTED = 4,
    + COMMAND_STATE_COMPLETED = 5,
    + COMMAND_STATE_FAILED = 6,
    +};
    +
    +/**
    + * struct cmd_iu - COMMAND IU - Section 6.2.2 from UAS Spec
    + * @iu_id: should be set to 01h
    + * @reserved: should be set to 0
    + * @tag: see section 4.2 of the UAS spec
    + * @forth_byte: the forth byte of the COMMAND IU. Holds cmd priority and
    + * task attribute
    + * @reserved5: should be set to 0
    + * @length: the length of the CDB. Represented by bits 2-7.
    + * Bits0-1 are reserved
    + * @reserved7: should be set to 0
    + * @lun: LUN ID for this command
    + * @cdb: the SCSI CDB
    + * @add_cdb: Additional byted of the CDB
    + * @bh: buffer used for handling this command
    + * @state: command state. See enum command_state
    + * @ep: Endpoint on which the processing of COMMAND IU currently performs
    + * @req_sts: Status of the struct usb_request item submitted for certain
    + * COMMAND IU
    + * @file_offset: For READ, WRITE, VERIFY SCSI COMMANDs the current file offset
    + * @xfer_len: For READ, WRITE, VERIFY SCSI COMMANDs the remaining transfer
    + * length
    + * @node: Link for adding to the queue
    + */
    +struct cmd_iu {
    + __u8 iu_id;
    + __u8 reserved;
    + __be16 tag;
    +
    + struct {
    + unsigned reserved:1;
    + unsigned command_priority:4;
    + unsigned task_attribute:3;
    + } __attribute__((__packed__)) forth_byte;
    +
    + __u8 reserved5;
    + __u8 length;
    + __u8 reserved7;
    + __u8 lun[8];
    + __u8 cdb[16];
    + __u8 *add_cdb;
    +
    + struct fsg_buffhd *bh;
    + int state;
    + struct usb_ep *ep;
    +
    +#define CMD_REQ_NOT_SUBMITTED 0
    +#define CMD_REQ_IN_PROGRESS 1
    +#define CMD_REQ_COMPLETED 2
    + __u8 req_sts;
    + u32 file_offset;
    + u32 xfer_len;
    + struct list_head node;
    +};
    +
    +
    +/* STATUS values of SENSE IU as defined in SAM-4 */
    +enum status_code_data {
    + STATUS_GOOD = 0x00,
    + STATUS_CHECK_CONDITION = 0x02,
    + STATUS_CONDITION_MET = 0x04,
    + STATUS_BUSY = 0x08,
    + STATUS_RESERVATION_CONFLICT = 0x18,
    + STATUS_TASK_SET_FULL = 0x28,
    + STATUS_ACA_ACTIVE = 0x30,
    + STATUS_TASK_ABORTED = 0x40,
    +};
    +
    +/* SENSE IU - section 6.2.5 of the UAS spec */
    +struct sense_iu {
    + __u8 iu_id;
    + __u8 reserved1;
    + __be16 tag;
    + __be16 status_qual;
    + __u8 status;
    + __u8 rsvd8[6];
    + __be16 len;
    + __u8 sense_data[SCSI_SENSE_BUFFERSIZE];
    +};
    +#define UASP_SIZEOF_SENSE_IU (16 + SCSI_SENSE_BUFFERSIZE)
    +
    +/* TASK MANAGEMENT IU related defenitions */
    +/* TM FUNCTION types - see table 20 of the UAS Spec */
    +enum tm_function_data {
    + TM_FUNCTION_ABORT_TASK = 0x01,
    + TM_FUNCTION_ABORT_TASK_SET = 0x02,
    + TM_FUNCTION_CLEAR_TASK_SET = 0x04,
    + TM_FUNCTION_RESET_LUN = 0x08,
    + TM_FUNCTION_IT_NEXUS_RESET = 0x10,
    + TM_FUNCTION_CLEAR_ACA = 0x40,
    + TM_FUNCTION_QUERY_TASK = 0x80,
    + TM_FUNCTION_QUERY_TASK_SET = 0x81,
    + TM_FUNCTION_QUERY_ASYNC_EVENT = 0x82,
    +};
    +
    +/**
    + * struct tm_iu - TM FUNCTION IU - see table 19 of the UAS Spec
    + * @iu_id: Should be set to 05h
    + * @reserved: should be set to 0
    + * @tag: section 4.2 of the UAS spec
    + * @tm_function: valid values defined in struct tm_function_data
    + * @reserved5: should be set to 0
    + * @task_tag: Reserved for all tm_functions but ABORT_TASK and QUERY_TASK
    + * @lun: LUN ID for this command
    + * @bh: buffer used for handling this command
    + * @ep: Endpoint on which the processing of TM FUNCTION IU currently performs
    + * @state: State of the TM FUNCTION IU
    + * @node: Link for adding to the queue
    + */
    +struct tm_iu {
    + __u8 iu_id;
    + __u8 reserved1;
    + __be16 tag;
    + __u8 tm_function;
    + __u8 reserved5;
    + __be16 task_tag;
    + __u8 lun[8];
    +
    + struct fsg_buffhd *bh;
    + struct usb_ep *ep;
    + int state;
    + struct list_head node;
    +};
    +
    +/* Response code values of RESPONSE IU - see table 18 of the UAS Spec */
    +enum response_code_data {
    + RESPONSE_TM_FUNCTION_COMPLETE = 0x00,
    + RESPONSE_INVALID_IU = 0x02,
    + RESPONSE_TM_FUNCTION_NOT_SUPPORTED = 0x04,
    + RESPONSE_TM_FUNCTION_FAILED = 0x05,
    + RESPONSE_TM_FUNCTION_SUCCEEDED = 0x08,
    + RESPONSE_INCORRECT_LUN = 0x09,
    + RESPONSE_OVERLAPPED_TAG_ATTEMPTED = 0x0A,
    +};
    +
    +/* RESPONSE IU - see table 17 of the UAS Spec */
    +struct response_iu {
    + __u8 iu_id;
    + __u8 reserved;
    + __be16 tag;
    + __u8 resp_info[3];
    + __u8 status;
    +} __attribute__((__packed__));
    +#define UASP_SIZEOF_RESPONSE_IU 8
    +
    +void fill_usb_request(struct usb_request *req,
    + void *buf,
    + unsigned length,
    + unsigned zero,
    + void *context,
    + unsigned short_not_ok,
    + unsigned stream_id,
    + usb_request_complete_t complete);
    +
    +/**
    + * uasp_bulk_in_complete() - Callback function for the bulk IN endpoint
    + * @ep: pointer to the usb_ep (bulk IN endpoint)
    + * @req: usb_request received on this endpoint
    + *
    + * This function is passed to the outreq->complete() of the bulk IN endpoint.
    + * The requests cmdiu state is updated according to the completion status of
    + * the usb request. If the cmdiu was LUN specific, the corresponding LUN
    + * thread is awaken. If it was general, uasp main thread is awaken. */
    +void uasp_bulk_in_complete(struct usb_ep *ep, struct usb_request *req);
    +
    +/**
    + * uasp_bulk_out_complete() - Callback function for the bulk OUT
    + * endpoint
    + * @ep: pointer to the usb_ep (bulk OUT endpoint)
    + * @req: usb_request received on this endpoint
    + *
    + * This function is passed to the outreq->complete() of the bulk
    + * OUT endpoint. The requests cmdiu state is updated according
    + * to the completion status of the usb request. If the cmdiu was
    + * LUN specific, the corresponding LUN thread is awaken. If it
    + * was general, uasp main thread is awaken.
    + */
    +void uasp_bulk_out_complete(struct usb_ep *ep, struct usb_request *req);
    +
    +/**
    + * status_complete() - Callback function for the status endpoint
    + * @ep: pointer to the usb_ep (status endpoint)
    + * @req: usb_request received on this endpoint
    + *
    + * This function is passed to the outreq->complete() of the status endpoint.
    + * If the request completion status isn't ECONNRESET the requests tmiu/cmdiu
    + * state is updated to aborted/completed/failed (according to the completion
    + * status of the usb request). If the tmiu/cmdiu was LUN specific, the
    + * corresponding LUN thread is awaken. If it was general, uasp main thread is
    + * awaken.
    + */
    +void status_complete(struct usb_ep *ep, struct usb_request *req);
    +
    +/**
    + * abort_commands() - Aborts all IUs on given queues
    + * @udev: Programming view of uasp device
    + * @cmd_queue: pointer to the cmd IUs queue to abort IUs from
    + * @tm_func_queue: pointer to the tm IUs queue to abort IUs from
    + * @lock: pointer to spinlock_t to lock when performing the abort.
    + * Can be udev->lock if the cmd_queue and the tm_func_queue are general,
    + * or curlun->lock if they belong to a specific LUN
    + *
    + * TODO: Add wait mechanism using curlun->active_requests or
    + * udev->active_requests
    + */
    +void abort_commands(struct uasp_dev *udev,
    + struct list_head *cmd_queue,
    + struct list_head *tm_func_queue,
    + spinlock_t *lock);
    +
    +/**
    + * run_lun_threads() - Wakeup all LUN threads with a given state
    + * @udev: Programming view of uasp device
    + * @state: The state to run the LUn in (from enum lun_state)
    + *
    + */
    +void run_lun_threads(struct uasp_dev *udev, int state);
    +
    +/**
    + * all_lun_state_non_processing() - Returns 1, if all luns are in
    + * none-processing state
    + * @udev: Programming view of uasp device
    + *
    + */
    +int all_lun_state_non_processing(struct uasp_dev *udev);
    +
    +/**
    + * close_lun() - Close the backing file of the given LUN
    + * @ulun: pointer to the LUn to close
    + *
    + * This function should be called when fsg_common->filesem is
    + * taken!
    + */
    +void close_lun(struct uasp_lun *ulun);
    +
    +#endif /* _F_UASP_H */
    diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c
    index e24f72f..b7d9e7e 100644
    --- a/drivers/usb/gadget/mass_storage.c
    +++ b/drivers/usb/gadget/mass_storage.c
    @@ -53,6 +53,7 @@
    #include "config.c"
    #include "epautoconf.c"
    #include "f_mass_storage.c"
    +#include "f_uasp.c"

    /*-------------------------------------------------------------------------*/

    @@ -66,7 +67,7 @@ static struct usb_device_descriptor msg_device_desc = {
    /* Vendor and product id can be overridden by module parameters. */
    .idVendor = cpu_to_le16(FSG_VENDOR_ID),
    .idProduct = cpu_to_le16(FSG_PRODUCT_ID),
    - .bNumConfigurations = 1,
    + .bNumConfigurations = 2,
    };

    static struct usb_otg_descriptor otg_descriptor = {
    @@ -121,7 +122,8 @@ static int __init msg_do_config(struct usb_configuration *c)
    fsg_config_from_params(&config, &mod_data);
    config.ops = &ops;

    - retp = fsg_common_init(&common, c->cdev, &config);
    + /* Init fsg_common and start the fsg main thread */
    + retp = fsg_common_init(&common, c->cdev, &config, 1);
    if (IS_ERR(retp))
    return PTR_ERR(retp);

    @@ -136,19 +138,72 @@ static struct usb_configuration msg_config_driver = {
    .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
    };

    +static int __init uasp_do_config(struct usb_configuration *c)
    +{
    + static const struct fsg_operations ops = {
    + .thread_exits = msg_thread_exits,
    + };
    +
    + struct fsg_common *fcommon;
    + struct uasp_common *ucommon;
    + struct fsg_config config;
    + int ret = 0;
    +
    + fsg_config_from_params(&config, &mod_data);
    + config.ops = &ops;
    + fcommon = fsg_common_init(0, c->cdev, &config, 0);
    + if (IS_ERR(fcommon))
    + return PTR_ERR(fcommon);
    +
    + ucommon = uasp_common_init(fcommon, c->cdev, &config);
    + if (IS_ERR(ucommon))
    + return PTR_ERR(ucommon);
    + ret = uasp_add(c->cdev, c, fcommon, ucommon);
    + uasp_common_put(ucommon);
    +
    + return ret;
    +}
    +
    +static struct usb_configuration uasp_config_driver = {
    + .label = "Linux UASP File-Backed Storage",
    + .bConfigurationValue = 2,
    + .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
    +};
    +
    +

    /****************************** Gadget Bind ******************************/

    +bool use_uasp ;
    +module_param(use_uasp, bool, S_IRUGO | S_IWUSR);
    static int __init msg_bind(struct usb_composite_dev *cdev)
    {
    int status;

    - status = usb_add_config(cdev, &msg_config_driver, msg_do_config);
    - if (status < 0)
    - return status;
    -
    dev_info(&cdev->gadget->dev,
    DRIVER_DESC ", version: " DRIVER_VERSION "\n");
    +
    + if (use_uasp) {
    + /*
    + * TODO: fix the bellow!
    + * Right now the host always chooses the first configuration.
    + * Untill this is fixed, if we want the device to opperate in
    + * UASP mode we switch the configurations numbers
    + */
    + msg_config_driver.bConfigurationValue = 2;
    + uasp_config_driver.bConfigurationValue = 1;
    + /* register uasp configuration */
    + status = usb_add_config(cdev, &uasp_config_driver,
    + uasp_do_config);
    + if (status < 0)
    + return status;
    + } else {
    + /* register our second configuration */
    + status = usb_add_config(cdev, &msg_config_driver,
    + msg_do_config);
    + if (status < 0)
    + return status;
    + }
    set_bit(0, &msg_registered);
    return 0;
    }
    diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c
    index c7f291a..4937ad6 100644
    --- a/drivers/usb/gadget/storage_common.c
    +++ b/drivers/usb/gadget/storage_common.c
    @@ -217,6 +217,7 @@ struct interrupt_data {
    #define SS_UNRECOVERED_READ_ERROR 0x031100
    #define SS_WRITE_ERROR 0x030c02
    #define SS_WRITE_PROTECTED 0x072700
    +#define SS_OVERLAPPED_COMMANDS_ATTEMPTED 0x0b4e00

    #define SK(x) ((u8) ((x) >> 16)) /* Sense Key byte, etc. */
    #define ASC(x) ((u8) ((x) >> 8))
    @@ -261,9 +262,16 @@ static struct fsg_lun *fsg_lun_from_dev(struct device *dev)
    #define EP0_BUFSIZE 256
    #define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */

    +/*
    + * We limit the number of UASP streams to 256 due to memory requirements.
    + * 4 buffer will be allocated for each supported stream.
    + */
    +#define UASP_SS_EP_COMP_NUM_STREAMS 4
    +
    #ifdef CONFIG_USB_GADGET_DEBUG_FILES

    -static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS;
    +static unsigned int fsg_num_buffers = (4*
    + CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS^UASP_SS_EP_COMP_NUM_STREAMS));
    module_param_named(num_buffers, fsg_num_buffers, uint, S_IRUGO);
    MODULE_PARM_DESC(num_buffers, "Number of pipeline buffers");

    @@ -273,17 +281,18 @@ MODULE_PARM_DESC(num_buffers, "Number of pipeline buffers");
    * Number of buffers we will use.
    * 2 is usually enough for good buffering pipeline
    */
    -#define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS
    +#define fsg_num_buffers (4*\
    +(CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS^UASP_SS_EP_COMP_NUM_STREAMS))

    #endif /* CONFIG_USB_DEBUG */

    /* check if fsg_num_buffers is within a valid range */
    static inline int fsg_num_buffers_validate(void)
    {
    - if (fsg_num_buffers >= 2 && fsg_num_buffers <= 4)
    + if (fsg_num_buffers >= 64 && fsg_num_buffers <= 1024)
    return 0;
    pr_err("fsg_num_buffers %u is out of range (%d to %d)\n",
    - fsg_num_buffers, 2 ,4);
    + fsg_num_buffers, 64 , 1024);
    return -EINVAL;
    }

    @@ -681,7 +690,7 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
    ro = curlun->initially_ro;
    if (!ro) {
    filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0);
    - if (PTR_ERR(filp) == -EROFS || PTR_ERR(filp) == -EACCES)
    + if (-EROFS == PTR_ERR(filp))
    ro = 1;
    }
    if (ro)
    @@ -696,7 +705,10 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)

    if (filp->f_path.dentry)
    inode = filp->f_path.dentry->d_inode;
    - if (!inode || (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))) {
    + if (inode && S_ISBLK(inode->i_mode)) {
    + if (bdev_read_only(inode->i_bdev))
    + ro = 1;
    + } else if (!inode || !S_ISREG(inode->i_mode)) {
    LINFO(curlun, "invalid file type: %s\n", filename);
    goto out;
    }
    diff --git a/drivers/usb/gadget/uasp_cmdiu.c b/drivers/usb/gadget/uasp_cmdiu.c
    new file mode 100644
    index 0000000..9fc882d
    --- /dev/null
    +++ b/drivers/usb/gadget/uasp_cmdiu.c
    @@ -0,0 +1,514 @@
    +/*
    + * uasp_cmdiu.c -- Mass Storage UAS Protocol - COMMAND IUs handling
    + * implementation
    + *
    + * Copyright (C) 2003-2005 Alan Stern
    + * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 and
    + * only version 2 as published by the Free Software Foundation.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + * GNU General Public License for more details.
    + */
    +
    +#include <linux/list.h>
    +#include "f_uasp.h"
    +
    +/**
    + * get_buffhd() - returns a buffer fot IU processing
    + * @bh: Array of the buffers in which the search should be done.
    + *
    + * Return pointer to the found buffer if it exists, 0 otherwise.
    + *
    + * This function tries to find a free buffer for COMMAND IU or
    + * TM FUNCTION IU processing.
    + */
    +struct fsg_buffhd *get_buffhd(struct fsg_buffhd *bh)
    +{
    + int i;
    +
    + for (i = 0; i < fsg_num_buffers; i++) {
    + if (bh[i].state == BUF_STATE_EMPTY) {
    + bh[i].state = BUF_STATE_BUSY;
    + return &bh[i];
    + }
    + }
    +
    + return NULL;
    +}
    +
    +/**
    + * check_cmdiu() - initial verification of the COMMAND IU
    + * @udev: Programming view of UASP device.
    + * @curlun: Pointer to struct lun if the COMMAND IU to be checked is addressed
    + * to a valid LUN, 0 otherwise.
    + * @cmdiu: COMMAND IU to be checked.
    + * @needs_medium: Specifies, is the medium needed for the COMMAND IU processing.
    + */
    +static __u32 check_cmdiu(struct uasp_dev *udev,
    + struct uasp_lun *curlun,
    + struct cmd_iu *cmdiu,
    + __u8 needs_medium)
    +{
    + __u32 ua_data = 0;
    +
    + DBG(udev->ucommon->common, "%s() - Enter\n", __func__);
    +
    + if (!curlun || !curlun->lun) {
    + if (cmdiu->cdb[0] != INQUIRY &&
    + cmdiu->cdb[0] != REQUEST_SENSE) {
    + DBG(udev->ucommon->common,
    + "%s() - Logical unit is not supported\n",
    + __func__);
    + return SS_LOGICAL_UNIT_NOT_SUPPORTED;
    + }
    + } else {
    + if (curlun->lun->unit_attention_data &&
    + cmdiu->cdb[0] != INQUIRY &&
    + cmdiu->cdb[0] != REQUEST_SENSE) {
    + DBG(udev->ucommon->common,
    + "%s() - There is an unit attention condition\n",
    + __func__);
    + ua_data = curlun->lun->unit_attention_data;
    + curlun->lun->unit_attention_data = SS_NO_SENSE;
    + return ua_data;
    + }
    + }
    +
    + if (curlun && !(curlun->lun->filp) && needs_medium) {
    + DBG(udev->ucommon->common,
    + "%s() - Medium is not present\n", __func__);
    + return SS_MEDIUM_NOT_PRESENT;
    + }
    +
    + return SS_NO_SENSE;
    +}
    +
    +/**
    + * fill_sense_iu() - fills the struct sense_iu with a given values.
    + * @udev: Programming view of UASP device.
    + * @siu: Pointer to structure to be filled.
    + * @tag: tag field of the structure.
    + * @status: status field of the structure.
    + * @sense_data: sense_data field of the structure.
    + */
    +void fill_sense_iu(struct uasp_dev *udev,
    + struct sense_iu *siu,
    + __be16 tag,
    + __u8 status,
    + __u32 sense_data)
    +{
    + DBG(udev->ucommon->common, "%s() - Status = %02x\n", __func__, status);
    +
    + siu->iu_id = IU_ID_SENSE;
    + siu->reserved1 = 0;
    + siu->tag = tag;
    + siu->status_qual = 0; /* TODO: fix this!!! */
    + siu->status = status;
    + memset(siu->rsvd8, 0, 6);
    + siu->len = cpu_to_be16(5);
    + siu->sense_data[0] = SK(sense_data);
    + siu->sense_data[1] = ASC(sense_data);
    + siu->sense_data[2] = ASCQ(sense_data);
    +}
    +
    +/**
    + * do_uasp_inquiry() - performs INQUIRY SCSI command.
    + * @udev: Programming view of UASP device.
    + * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be
    + * performed is addressed to a valid LUN, 0 otherwise.
    + * @cmdiu: COMMAND IU to be performed.
    + *
    + * Returns 1 if usb request should be submitted to PCD after cmdiu processing,
    + * 0 otherwise.
    + */
    +static int do_uasp_inquiry(struct uasp_dev *udev,
    + struct uasp_lun *curlun,
    + struct cmd_iu *cmdiu)
    +{
    + return 0;
    +}
    +
    +
    +/**
    + * do_uasp_request_sense() - performs REQUEST SENSE SCSI command.
    + * @udev: Programming view of UASP device.
    + * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be
    + * performed is addressed to a valid LUN, 0 otherwise.
    + * @cmdiu: COMMAND IU to be performed.
    + *
    + * Returns 1 if usb request should be submitted to PCD after cmdiu processing,
    + * 0 otherwise.
    + */
    +static int do_uasp_request_sense(struct uasp_dev *udev,
    + struct uasp_lun *curlun,
    + struct cmd_iu *cmdiu)
    +{
    + return 0;
    +}
    +
    +/**
    + * do_uasp_test_unit_ready() - performs TEST UNIT READY SCSI command.
    + * @udev: Programming view of UASP device.
    + * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be
    + * performed is addressed to a valid LUN, 0 otherwise.
    + * @cmdiu: COMMAND IU to be performed.
    + *
    + * Returns 1 if usb request should be submitted to PCD after cmdiu processing,
    + * 0 otherwise.
    + */
    +static int do_uasp_test_unit_ready(struct uasp_dev *udev,
    + struct uasp_lun *curlun,
    + struct cmd_iu *cmdiu)
    +{
    + return 0;
    +}
    +
    +/**
    + * do_uasp_mode_sense() - performs MODE SENSE(6) and MODE SENSE(10)
    + * SCSI commands.
    + * @udev: Programming view of UASP device.
    + * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be
    + * performed is addressed to a valid LUN, 0 otherwise.
    + * @cmdiu: COMMAND IU to performed.
    + *
    + * Returns 1 if usb request should be submitted to PCD after cmdiu processing,
    + * 0 otherwise.
    + */
    +static int do_uasp_mode_sense(struct uasp_dev *udev,
    + struct uasp_lun *curlun,
    + struct cmd_iu *cmdiu)
    +{
    + return 0;
    +}
    +
    +/**
    + * do_uasp_prevent_allow() - performs PREVENT ALLOW MEDIUM REMOVAL SCSI command.
    + * @udev: Programming view of UASP device.
    + * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be
    + * performed is addressed to a valid LUN, 0 otherwise.
    + * @cmdiu: COMMAND IU to be performed.
    + *
    + * Returns 1 if usb request should be submitted to PCD after cmdiu processing,
    + * 0 otherwise.
    + */
    +static int do_uasp_prevent_allow(struct uasp_dev *udev,
    + struct uasp_lun *curlun,
    + struct cmd_iu *cmdiu)
    +{
    + return 0;
    +}
    +
    +/**
    + * do_uasp_read() - performs READ(6), READ(10), READ(12) SCSI commands.
    + * @udev: Programming view of UASP device.
    + * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be performed is
    + * addressed to a valid LUN, 0 otherwise.
    + * @cmdiu: COMMAND IU to be performed.
    + *
    + * Returns non zero if usb request(s) should be submitted to PCD after cmdiu
    + * processing, 0 otherwise.
    + */
    +static int do_uasp_read(struct uasp_dev *udev,
    + struct uasp_lun *curlun,
    + struct cmd_iu *cmdiu)
    +{
    + return 0;
    +}
    +
    +/**
    + * do_uasp_read_capacity() - This function performs READ CAPACITY SCSI command.
    + * @udev: Programming view of UASP device.
    + * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be performed is
    + * addressed to a valid LUN, 0 otherwise.
    + * @cmdiu: COMMAND IU to be performed.
    + *
    + * Returns 1 if usb request should be submitted to PCD after cmdiu processing,
    + * 0 otherwise.
    + *
    + */
    +static int do_uasp_read_capacity(struct uasp_dev *udev,
    + struct uasp_lun *curlun,
    + struct cmd_iu *cmdiu)
    +{
    + return 0;
    +}
    +
    +/**
    + * do_uasp_read_format_capacities() - performs READ FORMAT CAPACITIES
    + * SCSI command.
    + * @udev: Programming view of UASP device.
    + * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be performed is
    + * addressed to a valid LUN, 0 otherwise.
    + * @cmdiu: COMMAND IU to be performed.
    + *
    + * Returns 1 if usb request should be submitted to PCD after cmdiu processing,
    + * 0 otherwise.
    + */
    +static int do_uasp_read_format_capacities(struct uasp_dev *udev,
    + struct uasp_lun *curlun,
    + struct cmd_iu *cmdiu)
    +{
    + return 0;
    +}
    +
    +/**
    + * do_uasp_start_stop() - performs START STOP UNIT SCSI command.
    + * @udev: Programming view of UASP device.
    + * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be performed is
    + * addressed to a valid LUN, 0 otherwise.
    + * @cmdiu: COMMAND IU to be performed.
    + *
    + * Returns 1 if usb request should be submitted to PCD after cmdiu processing,
    + * 0 otherwise.
    + *
    + */
    +static int do_uasp_start_stop(struct uasp_dev *udev,
    + struct uasp_lun *curlun,
    + struct cmd_iu *cmdiu)
    +{
    + return 0;
    +}
    +
    +/**
    + * do_uasp_verify() - This function performs VERIFY SCSI command.
    + * @udev: Programming view of UASP device.
    + * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be performed is
    + * addressed to a valid LUN, 0 otherwise.
    + * @cmdiu: COMMAND IU to be performed.
    + *
    + * Returns 1 if usb request should be submitted to PCD after
    + * cmdiu processing, 0 otherwise.
    + *
    + * Although optional, this command is used by MS-Windows. We support a minimal
    + * version: BytChk must be 0.
    + *
    + */
    +static int do_uasp_verify(struct uasp_dev *udev,
    + struct uasp_lun *curlun,
    + struct cmd_iu *cmdiu)
    +{
    + return 0;
    +}
    +
    +/**
    + * do_uasp_write() - This function performs WRITE(6), WRITE(10), WRITE(12)
    + * SCSI commands.
    + * @udev: Programming view of UASP device.
    + * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be performed is
    + * addressed to a valid LUN, 0 otherwise.
    + * @cmdiu: COMMAND IU to be performed.
    + *
    + * Returns: 1 if an IN usb request should be submitted to PCD after processing
    + * 2 if an OUT usb request should be submitted to PCD after processing
    + * 0 otherwise.
    + */
    +static int do_uasp_write(struct uasp_dev *udev,
    + struct uasp_lun *curlun,
    + struct cmd_iu *cmdiu)
    +{
    + return 0;
    +}
    +
    +/**
    + * do_uasp_synchronize_cache() - performs SYNCHRONIZE CACHE SCSI command.
    + * @udev: Programming view of UASP device.
    + * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be performed is
    + * addressed to a valid LUN, 0 otherwise.
    + * @cmdiu: COMMAND IU to be performed.
    + *
    + * Returns 1 if usb request should be submitted to PCD after cmdiu processing,
    + * 0 otherwise.
    + *
    + */
    +static int do_uasp_synchronize_cache(struct uasp_dev *udev,
    + struct uasp_lun *curlun,
    + struct cmd_iu *cmdiu)
    +{
    + return 0;
    +}
    +
    +/**
    + * process_cmdiu() - This function performs a given COMMAND IU.
    + * @udev: Programming view of UASP device.
    + * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be performed is
    + * addressed to a valid LUN, 0 otherwise.
    + * @cmdiu: COMMAND IU to be performed.
    + */
    +static void process_cmdiu(struct uasp_dev *udev,
    + struct uasp_lun *curlun,
    + struct cmd_iu *cmdiu)
    +{
    + unsigned long flags;
    + struct sense_iu *siu;
    + struct usb_request *req;
    + int rc = 0;
    +
    + DBG(udev->ucommon->common, "%s() Enter. (cmdiu->cdb[0]=%04x)\n",
    + __func__, cmdiu->cdb[0]);
    +
    + /* We're using the backing file */
    + down_read(&udev->ucommon->common->filesem);
    + switch (cmdiu->cdb[0]) {
    + case INQUIRY:
    + rc = do_uasp_inquiry(udev, curlun, cmdiu);
    + break;
    + case MODE_SENSE:
    + case MODE_SENSE_10:
    + rc = do_uasp_mode_sense(udev, curlun, cmdiu);
    + break;
    + case ALLOW_MEDIUM_REMOVAL:
    + rc = do_uasp_prevent_allow(udev, curlun, cmdiu);
    + break;
    + case READ_6:
    + case READ_10:
    + case READ_12:
    + rc = do_uasp_read(udev, curlun, cmdiu);
    + break;
    + case READ_CAPACITY:
    + rc = do_uasp_read_capacity(udev, curlun, cmdiu);
    + break;
    + case READ_FORMAT_CAPACITIES:
    + rc = do_uasp_read_format_capacities(udev, curlun, cmdiu);
    + break;
    + case REQUEST_SENSE:
    + rc = do_uasp_request_sense(udev, curlun, cmdiu);
    + break;
    + case START_STOP:
    + rc = do_uasp_start_stop(udev, curlun, cmdiu);
    + break;
    + case SYNCHRONIZE_CACHE:
    + rc = do_uasp_synchronize_cache(udev, curlun, cmdiu);
    + break;
    + case TEST_UNIT_READY:
    + rc = do_uasp_test_unit_ready(udev, curlun, cmdiu);
    + break;
    + case VERIFY:
    + rc = do_uasp_verify(udev, curlun, cmdiu);
    + break;
    + case WRITE_6:
    + case WRITE_10:
    + case WRITE_12:
    + rc = do_uasp_write(udev, curlun, cmdiu);
    + break;
    + case FORMAT_UNIT:
    + case MODE_SELECT:
    + case MODE_SELECT_10:
    + case RELEASE:
    + case RESERVE:
    + case SEND_DIAGNOSTIC:
    + default:
    + ERROR(udev->ucommon->common,
    + "%s(): Unsupported command = %x\n",
    + __func__, cmdiu->cdb[0]);
    + cmdiu->state = COMMAND_STATE_STATUS;
    + siu = (struct sense_iu *)cmdiu->bh->inreq->buf;
    + fill_sense_iu(udev, siu, cmdiu->tag,
    + STATUS_CHECK_CONDITION,
    + SS_INVALID_COMMAND);
    + fill_usb_request(cmdiu->bh->inreq, (void *)siu,
    + UASP_SIZEOF_SENSE_IU, 0,
    + (void *)cmdiu, 0, be16_to_cpup(&cmdiu->tag),
    + status_complete);
    + cmdiu->ep = udev->status;
    + rc = 1;
    + break;
    + }
    +
    + up_read(&udev->ucommon->common->filesem);
    + if (rc) {
    + if (rc == 1) {
    + req = cmdiu->bh->inreq;
    + cmdiu->bh->inreq_busy = 1;
    + } else {
    + req = cmdiu->bh->outreq;
    + cmdiu->bh->outreq_busy = 1;
    + }
    + if (usb_ep_queue(cmdiu->ep, req, 0)) {
    + ERROR(udev->ucommon->common,
    + "%s()usb_ep_queue failed\n", __func__);
    + cmdiu->state = COMMAND_STATE_FAILED;
    + } else {
    + DBG(udev->ucommon->common,
    + "%s() - process_cmdiu: queued req to ep\n",
    + __func__);
    + if (curlun) {
    + spin_lock_irqsave(&(curlun->lock), flags);
    + curlun->active_requests++;
    + spin_unlock_irqrestore(&(curlun->lock), flags);
    + } else {
    + spin_lock_irqsave(
    + &(udev->ucommon->common->lock), flags);
    + udev->active_requests++;
    + spin_unlock_irqrestore(
    + &(udev->ucommon->common->lock), flags);
    + }
    + }
    + }
    +}
    +
    +/**
    + * do_cmdiu() - This function performs the COMMAND IUs from a given queue.
    + * @udev: Programming view of UASP device.
    + * @curlun: Pointer to struct uasp_lun if COMMAND IUs from lun::cmd_queue
    + * should be performed, 0 if COMMAND IUs from uasp_dev::cmd_queue should
    + * be performed.
    + */
    +void do_cmdiu(struct uasp_dev *udev, struct uasp_lun *curlun)
    +{
    + struct list_head *link;
    + struct cmd_iu *cmdiu, *tmp;
    + unsigned long flags;
    +
    + DBG(udev->ucommon->common, "%s() - Enter\n", __func__);
    +
    + /* Select the cmd_queue from which cmdius should be processed */
    + if (curlun)
    + link = &curlun->cmd_queue;
    + else
    + link = &udev->cmd_queue;
    +
    + list_for_each_entry_safe(cmdiu, tmp, link, node) {
    + DBG(udev->ucommon->common, "%s() - Rolling over cmdiu queue\n",
    + __func__);
    +
    + spin_lock_irqsave(&(udev->ucommon->common->lock), flags);
    + if (cmdiu->state == COMMAND_STATE_IDLE) {
    + /* Try to get buffers for cmdiu processing */
    + cmdiu->bh = get_buffhd(udev->ucommon->common->buffhds);
    + spin_unlock_irqrestore(&(udev->ucommon->common->lock),
    + flags);
    +
    + if (!cmdiu->bh) {
    + ERROR(udev->ucommon->common,
    + "%s() -Didn't manage to get buffers for "
    + "cmdiu!\n", __func__);
    + continue;
    + }
    + } else if (cmdiu->state == COMMAND_STATE_DATA) {
    + if (cmdiu->req_sts == CMD_REQ_COMPLETED)
    + spin_unlock_irqrestore(
    + &(udev->ucommon->common->lock), flags);
    + else {
    + spin_unlock_irqrestore(
    + &(udev->ucommon->common->lock), flags);
    + continue;
    + }
    + } else {
    + spin_unlock_irqrestore(&(udev->ucommon->common->lock),
    + flags);
    + continue;
    + }
    +
    + process_cmdiu(udev, curlun, cmdiu);
    +
    + if (cmdiu->state == COMMAND_STATE_DATA)
    + break;
    + }
    +}
    +
    +
    diff --git a/drivers/usb/gadget/uasp_tmiu.c b/drivers/usb/gadget/uasp_tmiu.c
    new file mode 100644
    index 0000000..23f9351
    --- /dev/null
    +++ b/drivers/usb/gadget/uasp_tmiu.c
    @@ -0,0 +1,277 @@
    +/*
    + * uasp_tmiu.c -- Mass Storage UAS Protocol - TASK MANAGEMENT IUs handling
    + * implementation
    + *
    + * Copyright (C) 2003-2005 Alan Stern
    + * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 and
    + * only version 2 as published by the Free Software Foundation.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    + * GNU General Public License for more details.
    + */
    +
    +#include <linux/list.h>
    +#include "f_uasp.h"
    +
    +/**
    + * fill_response_iu() - fills the struct response_iu with the given values.
    + * @udev: Programming view of file storage gadget.
    + * @riu: Pointer to structure to be filled.
    + * @tag: tag field of the structure.
    + * @resp_info: resp_info field of the structure.
    + * @status: status field of the structure.
    + */
    +void fill_response_iu(struct uasp_dev *udev,
    + struct response_iu *riu,
    + __be16 tag,
    + uint32_t resp_info,
    + uint8_t status)
    +{
    + DBG(udev->ucommon->common, "%s() - Enter. Status = %02x\n", __func__,
    + status);
    + riu->iu_id = IU_ID_RESPONSE;
    + riu->reserved = 0;
    + riu->tag = tag;
    + riu->resp_info[0] = SK(resp_info);
    + riu->resp_info[1] = ASC(resp_info);
    + riu->resp_info[2] = ASCQ(resp_info);
    + riu->status = status;
    +}
    +
    +/**
    + * reset_lun() - performs RESET LUN TM FUNCTION IU.
    + * @udev: Programming view of UASP device.
    + * @curlun: Pointer to struct uasp_lun if the TM FUNCTION IU to be performed is
    + * addressed to a valid LUN, 0 otherwise.
    + * @tmiu: TM FUNCTION IU to be processed.
    + *
    + * This function performs LUN reset. It aborts all of the given LUN pending
    + * commands.
    + */
    +static void reset_lun(struct uasp_dev *udev,
    + struct uasp_lun *curlun,
    + struct tm_iu *tmiu)
    +{
    + DBG(udev->ucommon->common, "%s() - Enter\n", __func__);
    +}
    +
    +/**
    + * abort_task() - This function performs ABORT TASK TM FUNCTION IU.
    + * @udev: Programming view of UASP device.
    + * @curlun: Pointer to struct uasp_lun if the TM FUNCTION IU to be performed is
    + * addressed to a valid LUN, 0 otherwise.
    + * @tmiu: TM FUNCTION IU to be processed.
    + *
    + * This function aborts the command with the same ip_tag as in the
    + * tmiu->task_tag. It's valid only for command that are handled by a specific
    + * LUN .
    + */
    +static void abort_task(struct uasp_dev *udev,
    + struct uasp_lun *curlun,
    + struct tm_iu *tmiu)
    +{
    + DBG(udev->ucommon->common, "%s() - Enter\n", __func__);
    +}
    +
    +/**
    + * abort_task_set() - This function performs ABORT TASK SET TM FUNCTION IU.
    + * @udev: Programming view of UASP device.
    + * @curlun: Pointer to struct uasp_lun if the TM FUNCTION IU to be performed is
    + * addressed to a valid LUN, 0 otherwise.
    + * @tmiu: TM FUNCTION IU to be processed.
    + *
    + * This function aborts all the commands pending for the specified LUN.
    + */
    +static void abort_task_set(struct uasp_dev *udev,
    + struct uasp_lun *curlun,
    + struct tm_iu *tmiu)
    +{
    + DBG(udev->ucommon->common, "%s() - Enter\n", __func__);
    +}
    +
    +/**
    + * reset_nexus() - This function performs RESET NEXUS TM FUNCTION IU.
    + * @udev: Programming view of UASP device.
    + * @tmiu: TM FUNCTION IU to be processed.
    + */
    +static void reset_nexus(struct uasp_dev *udev,
    + struct tm_iu *tmiu)
    +{
    + DBG(udev->ucommon->common, "%s() - Enter\n", __func__);
    +}
    +
    +/**
    + * query_unit_attention() - performs QUERY UNIT ATTENTION TM FUNCTION IU.
    + * @udev: Programming view of UASP device.
    + * @curlun: Pointer to struct uasp_lun if the TM FUNCTION IU to be performed is
    + * addressed to a valid LUN, 0 otherwise.
    + * @tmiu: TM FUNCTION IU to be processed.
    + *
    + * This function is used to obtain a unit attention condition or a deferred
    + * error pending, if such exists, for the LUN on which the task management
    + * function was received.
    + */
    +static void query_unit_attention(struct uasp_dev *udev,
    + struct uasp_lun *curlun,
    + struct tm_iu *tmiu)
    +{
    + DBG(udev->ucommon->common, "%s() - Enter\n", __func__);
    +}
    +
    +
    +/**
    + * This function performs QUERY TASK TM FUNCTION IU.
    + * @udev: Programming view of UASP device.
    + * @curlun: Pointer to struct uasp_lun if the TM FUNCTION IU to be performed is
    + * addressed to a valid LUN, 0 otherwise.
    + * @tmiu TM FUNCTION IU to be processed.
    + */
    +static void query_task(struct uasp_dev *udev,
    + struct uasp_lun *curlun,
    + struct tm_iu *tmiu)
    +{
    + DBG(udev->ucommon->common, "%s() - Enter\n", __func__);
    +}
    +
    +/**
    + * This function performs QUERY TASK SET TM FUNCTION IU.
    + * @udev: Programming view of UASP device.
    + * @curlun: Pointer to struct uasp_lun if the TM FUNCTION IU to be performed is
    + * addressed to a valid LUN, 0 otherwise.
    + * @tmiu TM FUNCTION IU to be processed.
    + */
    +static void query_task_set(struct uasp_dev *udev,
    + struct uasp_lun *curlun,
    + struct tm_iu *tmiu)
    +{
    + DBG(udev->ucommon->common, "%s() - Enter\n", __func__);
    +}
    +
    +/**
    + * process_tmiu() - process a given TM FUNCTION IU.
    + * @udev: Programming view of UASP device.
    + * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be performed is
    + * addressed to a valid LUN, 0 otherwise.
    + * @miu: TM FUNCTION IU to be processed.
    + */
    +static void process_tmiu(struct uasp_dev *udev,
    + struct uasp_lun *curlun,
    + struct tm_iu *tmiu)
    +{
    + struct response_iu *riu;
    + unsigned long flags;
    +
    + switch (tmiu->tm_function) {
    + case TM_FUNCTION_ABORT_TASK:
    + abort_task(udev, curlun, tmiu);
    + break;
    +
    + case TM_FUNCTION_ABORT_TASK_SET:
    + case TM_FUNCTION_CLEAR_TASK_SET:
    + abort_task_set(udev, curlun, tmiu);
    + break;
    +
    + case TM_FUNCTION_RESET_LUN:
    + reset_lun(udev, curlun, tmiu);
    + break;
    +
    + case TM_FUNCTION_IT_NEXUS_RESET:
    + reset_nexus(udev, tmiu);
    + break;
    +
    + case TM_FUNCTION_QUERY_TASK:
    + query_task(udev, curlun, tmiu);
    + break;
    +
    + case TM_FUNCTION_QUERY_TASK_SET:
    + query_task_set(udev, curlun, tmiu);
    + break;
    +
    + case TM_FUNCTION_QUERY_ASYNC_EVENT:
    + query_unit_attention(udev, curlun, tmiu);
    + break;
    +
    + default:
    + ERROR(udev->ucommon->common, "%s(): Unsupported tmiu = %x\n",
    + __func__, tmiu->tm_function);
    + riu = (struct response_iu *)tmiu->bh->inreq->buf;
    + fill_response_iu(udev, riu, tmiu->tag, 0,
    + RESPONSE_TM_FUNCTION_NOT_SUPPORTED);
    +
    + fill_usb_request(tmiu->bh->inreq, (void *)riu,
    + UASP_SIZEOF_RESPONSE_IU, 0,
    + (void *)tmiu, 0, be16_to_cpup(&tmiu->tag),
    + status_complete);
    + tmiu->ep = udev->status;
    + break;
    + }
    +
    + tmiu->state = COMMAND_STATE_STATUS;
    + if (usb_ep_queue(tmiu->ep, tmiu->bh->inreq, 0)) {
    + ERROR(udev->ucommon->common,
    + "%s()usb_ep_queue failed\n", __func__);
    + tmiu->state = COMMAND_STATE_FAILED;
    + } else {
    + tmiu->bh->inreq_busy = 1;
    + if (curlun) {
    + spin_lock_irqsave(&(curlun->lock), flags);
    + curlun->active_requests++;
    + spin_unlock_irqrestore(&(curlun->lock), flags);
    + } else {
    + spin_lock_irqsave(&(udev->ucommon->common->lock),
    + flags);
    + udev->active_requests++;
    + spin_unlock_irqrestore(&(udev->ucommon->common->lock),
    + flags);
    + }
    + }
    +}
    +
    +/**
    + * do_tmdiu() - processes the TM FUNCTION IUs from a given queue.
    + * @udev: Programming view of file storage gadget.
    + * @curlun: Pointer to struct uasp_lun if TM FUNCTION IUs from
    + * uasp_lun::tm_func_queue should be processed,
    + * 0 if TM FUNCTION IUs from uasp_dev::tm_func_queue should
    + * be processed.
    + */
    +void do_tmiu(struct uasp_dev *udev, struct uasp_lun *curlun)
    +{
    + struct list_head *link;
    + struct tm_iu *tmiu, *tmp;
    + unsigned long flags;
    +
    + DBG(udev->ucommon->common, "%s() - Enter\n", __func__);
    +
    + /* Select the tm_func_queue from which tmius should be processed */
    + if (curlun)
    + link = &curlun->tm_func_queue;
    + else
    + link = &udev->tm_func_queue;
    +
    + DBG(udev->ucommon->common, "%s() - Rolling over tmiu queue\n",
    + __func__);
    + list_for_each_entry_safe(tmiu, tmp, link, node) {
    + if (tmiu->state != COMMAND_STATE_IDLE)
    + continue;
    +
    + /* Try to get buffer for tmiu provessing */
    + spin_lock_irqsave(&(udev->ucommon->common->lock), flags);
    + tmiu->bh = get_buffhd(udev->ucommon->common->buffhds);
    + spin_unlock_irqrestore(&(udev->ucommon->common->lock), flags);
    +
    + if (!tmiu->bh) {
    + ERROR(udev->ucommon->common,
    + "%s() -Didnt manage to get buffers for tmiu!\n",
    + __func__);
    + continue;
    + }
    +
    + process_tmiu(udev, curlun, tmiu);
    + }
    +}
    --
    1.7.6
    --
    Sent by a Consultant for Qualcomm Innovation Center, Inc.
    Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum


    \
     
     \ /
      Last update: 2011-12-04 20:55    [W:0.241 / U:98.236 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site