linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC/PATCH v4 1/3] uas: MS UAS Gadget driver - Infrastructure
@ 2011-12-04 19:53 Shimrit Malichi
  2011-12-05  8:20 ` [RFC] UASP on target (was: [RFC/PATCH v4 1/3] uas: MS UAS Gadget driver - Infrastructure) Sebastian Andrzej Siewior
  0 siblings, 1 reply; 12+ messages in thread
From: Shimrit Malichi @ 2011-12-04 19:53 UTC (permalink / raw)
  Cc: Shimrit Malichi, Tatyana Brokhman, open list:USB GADGET/PERIPH...,
	open list

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

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC] UASP on target (was: [RFC/PATCH v4 1/3] uas: MS UAS Gadget driver - Infrastructure)
  2011-12-04 19:53 [RFC/PATCH v4 1/3] uas: MS UAS Gadget driver - Infrastructure Shimrit Malichi
@ 2011-12-05  8:20 ` Sebastian Andrzej Siewior
  2011-12-05  8:23   ` Sebastian Andrzej Siewior
  0 siblings, 1 reply; 12+ messages in thread
From: Sebastian Andrzej Siewior @ 2011-12-05  8:20 UTC (permalink / raw)
  To: Shimrit Malichi
  Cc: Tatyana Brokhman, open list:USB GADGET/PERIPH...,
	open list, target-devel

* Shimrit Malichi | 2011-12-04 21:53:09 [+0200]:

>This patch implements the infrastructure for the UAS gadget driver.
>The UAS gadget driver registers as a second configuration of the MS
>gadet driver.
hch said to use target framework and you haven't done so. This is what I
have so far. It is not yet complete. What I need to do is:
- wire up command processing (currently here)
- wire up data processing
- check it works => post v1
- wire up command tagging => v2
- remove hard codings and fix whatever people complained about.

Sebastian

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC] UASP on target (was: [RFC/PATCH v4 1/3] uas: MS UAS Gadget driver - Infrastructure)
  2011-12-05  8:20 ` [RFC] UASP on target (was: [RFC/PATCH v4 1/3] uas: MS UAS Gadget driver - Infrastructure) Sebastian Andrzej Siewior
@ 2011-12-05  8:23   ` Sebastian Andrzej Siewior
  2011-12-05  8:39     ` Felipe Balbi
                       ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Sebastian Andrzej Siewior @ 2011-12-05  8:23 UTC (permalink / raw)
  To: Shimrit Malichi
  Cc: Tatyana Brokhman, open list:USB GADGET/PERIPH...,
	open list, target-devel

* Sebastian Andrzej Siewior | 2011-12-05 09:20:47 [+0100]:

>* Shimrit Malichi | 2011-12-04 21:53:09 [+0200]:
>
>>This patch implements the infrastructure for the UAS gadget driver.
>>The UAS gadget driver registers as a second configuration of the MS
>>gadet driver.
>hch said to use target framework and you haven't done so. This is what I
>have so far. It is not yet complete. What I need to do is:
>- wire up command processing (currently here)
>- wire up data processing
>- check it works => post v1
>- wire up command tagging => v2
>- remove hard codings and fix whatever people complained about.

diff --git a/drivers/target/Kconfig b/drivers/target/Kconfig
index e66fcc7..64d3204 100644
--- a/drivers/target/Kconfig
+++ b/drivers/target/Kconfig
@@ -50,3 +50,4 @@ source "drivers/target/tcm_qla2xxx/Kconfig"
 source "drivers/target/tcm_vhost/Kconfig"
 
 endif
+source "drivers/target/uasp/Kconfig"
diff --git a/drivers/target/Makefile b/drivers/target/Makefile
index 1945dba..b1135d5 100644
--- a/drivers/target/Makefile
+++ b/drivers/target/Makefile
@@ -28,3 +28,4 @@ obj-$(CONFIG_TCM_FC)		+= tcm_fc/
 obj-$(CONFIG_ISCSI_TARGET)	+= iscsi/
 obj-$(CONFIG_TCM_QLA2XXX)	+= tcm_qla2xxx/
 obj-$(CONFIG_TCM_VHOST)		+= tcm_vhost/
+obj-$(CONFIG_TARGET_UASP)	+= uasp/
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index f7cb64f..127496a 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -162,6 +162,13 @@ static struct config_group *target_core_register_fabric(
 				" tcm_loop.ko: %d\n", ret);
 			return ERR_PTR(-EINVAL);
 		}
+	} else if (!strncmp(name, "uasp", 4)) {
+		ret = request_module("tcm_uasp");
+		if (ret < 0) {
+			pr_err("request_module() failed for"
+				" tcm_loop.ko: %d\n", ret);
+			return ERR_PTR(-EINVAL);
+		}
 	}
 
 	tf = target_core_get_fabric(name);
diff --git a/drivers/target/uasp/Kconfig b/drivers/target/uasp/Kconfig
new file mode 100644
index 0000000..0d48a58
--- /dev/null
+++ b/drivers/target/uasp/Kconfig
@@ -0,0 +1,6 @@
+config TARGET_UASP
+	tristate "UASP fabric module"
+	depends on TARGET_CORE && CONFIGFS_FS
+	depends on USB_GADGET
+	---help---
+	Say Y here to enable the UASP fabric module
diff --git a/drivers/target/uasp/Makefile b/drivers/target/uasp/Makefile
new file mode 100644
index 0000000..25883ab
--- /dev/null
+++ b/drivers/target/uasp/Makefile
@@ -0,0 +1,5 @@
+CFLAGS_gadget.o			:= -I$(srctree)/drivers/usb/gadget
+tcm_uasp-objs			:= uasp_fabric.o \
+					gadget.o \
+					   uasp_configfs.o
+obj-$(CONFIG_TARGET_UASP)	+= tcm_uasp.o
diff --git a/drivers/target/uasp/gadget.c b/drivers/target/uasp/gadget.c
new file mode 100644
index 0000000..a1ad056
--- /dev/null
+++ b/drivers/target/uasp/gadget.c
@@ -0,0 +1,541 @@
+
+#include <linux/kernel.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/composite.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/storage.h>
+
+#include "gadget.h"
+#include "gadget_ops.h"
+#include "uasp_configfs.h"
+
+#include "usbstring.c"
+#include "epautoconf.c"
+#include "config.c"
+#include "composite.c"
+
+#define UAS_G_STR_MANUFACTOR	1
+#define UAS_G_STR_PRODUCT	2
+#define UAS_G_STR_SERIAL	3
+#define UAS_G_STR_CONFIG	4
+#define UAS_G_STR_INTERFACE	5
+
+#define UASP_SS_EP_COMP_NUM_STREAMS 4
+
+struct f_uas {
+	struct usb_function     function;
+	u16			iface;
+	struct usb_ep		*ep_in;
+	struct usb_ep		*ep_out;
+	struct usb_ep		*ep_status;
+	struct usb_ep		*ep_cmd;
+
+	struct usb_request	*req_in;
+	struct usb_request	*req_out;
+	struct usb_request	*req_status;
+	struct usb_request	*req_cmd;
+
+	void			*cmd_buff;
+	u32			flags;
+#define UASP_ACTIVE		(1 << 0)
+#define UASP_SS_MODE		(1 << 1)
+};
+
+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 =		UAS_G_STR_INTERFACE,
+};
+
+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),
+};
+
+static 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,
+};
+
+static 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(1024),
+};
+
+static 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,
+};
+
+static 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),
+};
+
+static 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,
+};
+
+static 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),
+};
+
+static 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,
+	.bmAttributes =		UASP_SS_EP_COMP_NUM_STREAMS,
+};
+
+static 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),
+};
+
+static 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,
+};
+
+static 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(1024),
+};
+
+static 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,
+	.bmAttributes =		UASP_SS_EP_COMP_NUM_STREAMS,
+};
+
+static 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),
+};
+
+static 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,
+};
+
+static 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(1024),
+};
+
+static 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,
+};
+
+static 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,
+};
+
+static 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,
+};
+
+#define UAS_VENDOR_ID	0x0525	/* NetChip */
+#define UAS_PRODUCT_ID	0xa4a5	/* Linux-USB File-backed Storage Gadget */
+
+static struct usb_device_descriptor uas_device_desc = {
+	.bLength =              sizeof uas_device_desc,
+	.bDescriptorType =      USB_DT_DEVICE,
+	.bcdUSB =               cpu_to_le16(0x0200),
+	.bDeviceClass =         USB_CLASS_PER_INTERFACE,
+	.idVendor =             cpu_to_le16(UAS_VENDOR_ID),
+	.idProduct =            cpu_to_le16(UAS_PRODUCT_ID),
+	.bNumConfigurations =   1,
+};
+
+static struct usb_string	uas_us_strings[] = {
+	{ UAS_G_STR_MANUFACTOR,	"UAS Manufactor"},
+	{ UAS_G_STR_PRODUCT,	"UAS Product"},
+	{ UAS_G_STR_SERIAL,	"UAS Serial"},
+	{ UAS_G_STR_CONFIG,	"UAS Config"},
+	{ UAS_G_STR_INTERFACE,	"UAS Interface"},
+	{ },
+};
+
+static struct usb_gadget_strings uas_stringtab = {
+	.language = 0x0409,
+	.strings = uas_us_strings,
+};
+
+static struct usb_gadget_strings *uas_strings[] = {
+	&uas_stringtab,
+	NULL,
+};
+
+static int guas_unbind(struct usb_composite_dev *cdev)
+{
+	printk(KERN_ERR "%s()\n", __func__);
+	return 0;
+}
+
+static struct usb_configuration uasp_config_driver = {
+	.label                  = "Linux UASP Storage",
+	.bConfigurationValue    = 1,
+	.bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
+};
+
+static struct f_uas *to_f_uas(struct usb_function *f)
+{
+	return container_of(f, struct f_uas, function);
+}
+
+static void give_back_ep(struct usb_ep **pep)
+{
+	struct usb_ep *ep = *pep;
+	if (!ep)
+		return;
+	ep->driver_data = NULL;
+}
+
+static int uasp_bind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct f_uas		*fu = to_f_uas(f);
+	struct usb_gadget	*gadget = c->cdev->gadget;
+	struct usb_ep		*ep;
+	int			iface;
+
+	printk(KERN_ERR "%s(%d) %p, g%p\n", __func__, __LINE__, fu, gadget);
+
+	iface = usb_interface_id(c, f);
+	if (iface < 0)
+		return iface;
+
+	uasp_intf_desc.bInterfaceNumber = iface;
+	fu->iface = iface;
+	ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bulk_in_desc,
+			&uasp_bulk_in_ep_comp_desc);
+	if (!ep)
+		goto ep_fail;
+
+	ep->driver_data = fu;
+	fu->ep_in = ep;
+
+	ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bulk_out_desc,
+			&uasp_bulk_out_ep_comp_desc);
+	if (!ep)
+		goto ep_fail;
+	ep->driver_data = fu;
+	fu->ep_out = ep;
+
+	ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_status_in_desc,
+			&uasp_status_in_ep_comp_desc);
+	if (!ep)
+		goto ep_fail;
+	ep->driver_data = fu;
+	fu->ep_status = ep;
+
+	ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_command_out_desc,
+			&uasp_command_out_ep_comp_desc);
+	if (!ep)
+		goto ep_fail;
+	ep->driver_data = fu;
+	fu->ep_cmd = 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;
+ep_fail:
+	pr_err("Can't claim all required eps\n");
+
+	give_back_ep(&fu->ep_in);
+	give_back_ep(&fu->ep_out);
+	give_back_ep(&fu->ep_status);
+	give_back_ep(&fu->ep_cmd);
+	return -ENOTSUPP;
+}
+
+static void uasp_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct f_uas *fu = to_f_uas(f);
+
+	printk(KERN_ERR "%s(%d) %p\n", __func__, __LINE__, fu);
+	kfree(fu);
+}
+
+static void uasp_cleanup_old_alt(struct f_uas *fu)
+{
+	if (!(fu->flags & UASP_ACTIVE))
+		return;
+	fu->flags = 0;
+
+	usb_ep_disable(fu->ep_in);
+	usb_ep_disable(fu->ep_out);
+	usb_ep_disable(fu->ep_status);
+	usb_ep_disable(fu->ep_cmd);
+
+	usb_ep_free_request(fu->ep_in, fu->req_in);
+	usb_ep_free_request(fu->ep_out, fu->req_out);
+	usb_ep_free_request(fu->ep_status, fu->req_status);
+	usb_ep_free_request(fu->ep_cmd, fu->req_cmd);
+
+	fu->req_in = NULL;
+	fu->req_out = NULL;
+	fu->req_status = NULL;
+	fu->req_cmd = NULL;
+
+	kfree(fu->cmd_buff);
+	fu->cmd_buff = NULL;
+}
+
+static void guas_cmd_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	printk(KERN_ERR "Tada %d\n", req->status);
+
+	if (req->status < 0) {
+		pr_err("%s() bad status\n", __func__);
+		return;
+	}
+
+	printk(KERN_ERR "%s() transfered %d bytes\n", __func__, req->actual);
+	print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET,
+			16, 1,
+			req->buf, req->actual, false);
+}
+
+static int uasp_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+	struct f_uas *fu = to_f_uas(f);
+	struct usb_gadget *gadget = f->config->cdev->gadget;
+	int ret;
+
+	printk(KERN_ERR "%s(%d) %d %d | %p %p\n", __func__, __LINE__, intf, alt,
+			fu, gadget);
+	uasp_cleanup_old_alt(fu);
+
+	if (gadget->speed == USB_SPEED_SUPER)
+			fu->flags |= UASP_SS_MODE;
+
+	config_ep_by_speed(gadget, f, fu->ep_in);
+	ret = usb_ep_enable(fu->ep_in);
+	if (ret)
+		goto err_b_in;
+
+	config_ep_by_speed(gadget, f, fu->ep_out);
+	ret = usb_ep_enable(fu->ep_out);
+	if (ret)
+		goto err_b_out;
+
+	config_ep_by_speed(gadget, f, fu->ep_cmd);
+	ret = usb_ep_enable(fu->ep_cmd);
+	if (ret)
+		goto err_cmd;
+	config_ep_by_speed(gadget, f, fu->ep_status);
+	ret = usb_ep_enable(fu->ep_status);
+	if (ret)
+		goto err_status;
+
+	ret = -ENOMEM;
+	fu->req_in = usb_ep_alloc_request(fu->ep_in, GFP_ATOMIC);
+	if (!fu->req_in)
+		goto err_req_bi;
+
+	fu->req_out = usb_ep_alloc_request(fu->ep_out, GFP_ATOMIC);
+	if (!fu->req_out)
+		goto err_req_bo;
+
+	fu->req_status = usb_ep_alloc_request(fu->ep_status, GFP_ATOMIC);
+	if (!fu->req_status)
+		goto err_req_status;
+
+	fu->req_cmd = usb_ep_alloc_request(fu->ep_cmd, GFP_ATOMIC);
+	if (!fu->req_cmd)
+		goto err_req_cmd;
+
+	fu->cmd_buff = kmalloc(fu->ep_cmd->maxpacket, GFP_ATOMIC);
+	if (!fu->cmd_buff)
+		goto err_cmd_buf;
+
+	fu->req_cmd->complete = guas_cmd_complete;
+	fu->req_cmd->buf = fu->cmd_buff;
+	fu->req_cmd->length = fu->ep_cmd->maxpacket;
+
+	ret = usb_ep_queue(fu->ep_cmd, fu->req_cmd, GFP_ATOMIC);
+	if (ret)
+		goto err_enqueue;
+
+	fu->flags |= UASP_ACTIVE;
+	return 0;
+
+err_enqueue:
+	kfree(fu->cmd_buff);
+	fu->cmd_buff = NULL;
+err_cmd_buf:
+	usb_ep_free_request(fu->ep_cmd, fu->req_cmd);
+	fu->req_cmd = NULL;
+err_req_cmd:
+	usb_ep_free_request(fu->ep_status, fu->req_status);
+	fu->req_status = NULL;
+err_req_status:
+	usb_ep_free_request(fu->ep_out, fu->req_out);
+	fu->req_out = NULL;
+err_req_bo:
+	usb_ep_free_request(fu->ep_in, fu->req_in);
+	fu->req_in = NULL;
+err_req_bi:
+	usb_ep_disable(fu->ep_status);
+err_status:
+	usb_ep_disable(fu->ep_cmd);
+err_cmd:
+	usb_ep_disable(fu->ep_out);
+err_b_out:
+	usb_ep_disable(fu->ep_in);
+err_b_in:
+	fu->flags = 0;
+	return ret;
+}
+
+static void uasp_disable(struct usb_function *f)
+{
+	struct f_uas *fu = to_f_uas(f);
+
+	printk(KERN_ERR "%s(%d) %p\n", __func__, __LINE__, fu);
+	uasp_cleanup_old_alt(fu);
+}
+
+static int uas_cfg_bind(struct usb_configuration *c)
+{
+	struct f_uas *fu;
+	int ret;
+
+	fu = kzalloc(sizeof *fu, GFP_KERNEL);
+	if (!fu)
+		return -ENOMEM;
+	fu->function.name = "UASP Function";
+	fu->function.descriptors = uasp_hs_function_desc;
+	fu->function.hs_descriptors = uasp_hs_function_desc;
+	fu->function.bind = uasp_bind;
+	fu->function.unbind = uasp_unbind;
+	fu->function.set_alt = uasp_set_alt;
+	fu->function.disable = uasp_disable;
+
+	ret = usb_add_function(c, &fu->function);
+	if (ret)
+		goto err;
+	return 0;
+err:
+	kfree(fu);
+	return ret;
+}
+
+static int guas_bind(struct usb_composite_dev *cdev)
+{
+	int ret;
+
+	ret = usb_add_config(cdev, &uasp_config_driver,
+			uas_cfg_bind);
+	return 0;
+}
+
+static struct usb_composite_driver uas_driver = {
+	.name           = "g_uas",
+	.dev            = &uas_device_desc,
+	.strings        = uas_strings,
+	.max_speed      = USB_SPEED_SUPER,
+	.unbind         = guas_unbind,
+};
+
+int gadget_attach(void)
+{
+	pr_err("%s(%d)\n", __func__, __LINE__);
+	return usb_composite_probe(&uas_driver, guas_bind);
+}
+
+void gadget_detach(void)
+{
+	usb_composite_unregister(&uas_driver);
+}
+
+static int __init guas_init(void)
+{
+	int ret;
+
+	ret = uasp_register_configfs();
+	return ret;
+}
+module_init(guas_init);
+
+static void __exit guas_exit(void)
+{
+	uasp_deregister_configfs();
+}
+module_exit(guas_exit);
+
+MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
+MODULE_DESCRIPTION("UAS faabric");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/target/uasp/gadget.h b/drivers/target/uasp/gadget.h
new file mode 100644
index 0000000..fe3ccc1
--- /dev/null
+++ b/drivers/target/uasp/gadget.h
@@ -0,0 +1,17 @@
+#ifndef __GTARGET_UAS_H__
+#define __GTARGET_UAS_H__
+
+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__));
+
+#endif
diff --git a/drivers/target/uasp/gadget_ops.h b/drivers/target/uasp/gadget_ops.h
new file mode 100644
index 0000000..109bc08
--- /dev/null
+++ b/drivers/target/uasp/gadget_ops.h
@@ -0,0 +1,7 @@
+#ifndef __GADGET_OPS_H__
+#define __GADGET_OPS_H__
+
+int gadget_attach(void);
+void gadget_detach(void);
+
+#endif
diff --git a/drivers/target/uasp/uasp_base.h b/drivers/target/uasp/uasp_base.h
new file mode 100644
index 0000000..b7a400a
--- /dev/null
+++ b/drivers/target/uasp/uasp_base.h
@@ -0,0 +1,32 @@
+#define UASP_VERSION  "v0.1"
+#define UASP_NAMELEN 32
+
+struct uasp_nacl {
+	/* Binary World Wide unique Port Name for SAS Initiator port */
+	u64 iport_wwpn;
+	/* ASCII formatted WWPN for Sas Initiator port */
+	char iport_name[UASP_NAMELEN];
+	/* Returned by uasp_make_nodeacl() */
+	struct se_node_acl se_node_acl;
+};
+
+struct uasp_tpg {
+	/* SAS port target portal group tag for TCM */
+	u16 tport_tpgt;
+	/* Pointer back to uasp_tport */
+	struct uasp_tport *tport;
+	/* Returned by uasp_make_tpg() */
+	struct se_portal_group se_tpg;
+	u32 gadget_connect;
+};
+
+struct uasp_tport {
+	/* SCSI protocol the tport is providing */
+	u8 tport_proto_id;
+	/* Binary World Wide unique Port Name for SAS Target port */
+	u64 tport_wwpn;
+	/* ASCII formatted WWPN for SAS Target port */
+	char tport_name[UASP_NAMELEN];
+	/* Returned by uasp_make_tport() */
+	struct se_wwn tport_wwn;
+};
diff --git a/drivers/target/uasp/uasp_configfs.c b/drivers/target/uasp/uasp_configfs.c
new file mode 100644
index 0000000..7f6b280
--- /dev/null
+++ b/drivers/target/uasp/uasp_configfs.c
@@ -0,0 +1,333 @@
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <generated/utsrelease.h>
+#include <linux/utsname.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/configfs.h>
+#include <linux/ctype.h>
+#include <asm/unaligned.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/target_core_configfs.h>
+#include <target/configfs_macros.h>
+
+#include "uasp_base.h"
+#include "uasp_fabric.h"
+#include "gadget_ops.h"
+
+/* Local pointer to allocated TCM configfs fabric module */
+struct target_fabric_configfs *uasp_fabric_configfs;
+
+static const char *uasp_check_wwn(const char *name)
+{
+	const char *n;
+	unsigned int len;
+
+	n = strstr(name, "naa.");
+	if (!n)
+		return NULL;
+	n += 4;
+	len = strlen(n);
+	if (len == 0 || len > UASP_NAMELEN - 1)
+		return NULL;
+	return n;
+}
+
+static struct se_node_acl *uasp_make_nodeacl(
+	struct se_portal_group *se_tpg,
+	struct config_group *group,
+	const char *name)
+{
+	struct se_node_acl *se_nacl, *se_nacl_new;
+	struct uasp_nacl *nacl;
+	u64 wwpn = 0;
+	u32 nexus_depth;
+	const char *wnn_name;
+
+	wnn_name = uasp_check_wwn(name);
+	if (!wnn_name)
+		return ERR_PTR(-EINVAL);
+	se_nacl_new = uasp_alloc_fabric_acl(se_tpg);
+	if (!(se_nacl_new))
+		return ERR_PTR(-ENOMEM);
+//#warning FIXME: Hardcoded nexus depth in uasp_make_nodeacl()
+	nexus_depth = 1;
+	/*
+	 * se_nacl_new may be released by core_tpg_add_initiator_node_acl()
+	 * when converting a NodeACL from demo mode -> explict
+	 */
+	se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,
+				name, nexus_depth);
+	if (IS_ERR(se_nacl)) {
+		uasp_release_fabric_acl(se_tpg, se_nacl_new);
+		return se_nacl;
+	}
+	/*
+	 * Locate our struct uasp_nacl and set the FC Nport WWPN
+	 */
+	nacl = container_of(se_nacl, struct uasp_nacl, se_node_acl);
+	nacl->iport_wwpn = wwpn;
+	snprintf(nacl->iport_name, sizeof(nacl->iport_name), "%s", name);
+	return se_nacl;
+}
+
+static void uasp_drop_nodeacl(struct se_node_acl *se_acl)
+{
+	struct uasp_nacl *nacl = container_of(se_acl,
+				struct uasp_nacl, se_node_acl);
+	core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1);
+	kfree(nacl);
+}
+
+static struct se_portal_group *uasp_make_tpg(
+	struct se_wwn *wwn,
+	struct config_group *group,
+	const char *name)
+{
+	struct uasp_tport*tport = container_of(wwn,
+			struct uasp_tport, tport_wwn);
+
+	struct uasp_tpg *tpg;
+	unsigned long tpgt;
+	int ret;
+
+	if (strstr(name, "tpgt_") != name)
+		return ERR_PTR(-EINVAL);
+	if (strict_strtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX)
+		return ERR_PTR(-EINVAL);
+
+	tpg = kzalloc(sizeof(struct uasp_tpg), GFP_KERNEL);
+	if (!tpg) {
+		printk(KERN_ERR "Unable to allocate struct uasp_tpg");
+		return ERR_PTR(-ENOMEM);
+	}
+	tpg->tport = tport;
+	tpg->tport_tpgt = tpgt;
+
+	ret = core_tpg_register(&uasp_fabric_configfs->tf_ops, wwn,
+				&tpg->se_tpg, tpg,
+				TRANSPORT_TPG_TYPE_NORMAL);
+	if (ret < 0) {
+		kfree(tpg);
+		return NULL;
+	}
+	return &tpg->se_tpg;
+}
+
+static void uasp_drop_tpg(struct se_portal_group *se_tpg)
+{
+	struct uasp_tpg *tpg = container_of(se_tpg,
+				struct uasp_tpg, se_tpg);
+
+	core_tpg_deregister(se_tpg);
+	kfree(tpg);
+}
+
+static struct se_wwn *uasp_make_tport(
+	struct target_fabric_configfs *tf,
+	struct config_group *group,
+	const char *name)
+{
+	struct uasp_tport *tport;
+	const char *wnn_name;
+	u64 wwpn = 0;
+
+	wnn_name = uasp_check_wwn(name);
+	if (!wnn_name)
+		return ERR_PTR(-EINVAL);
+
+	tport = kzalloc(sizeof(struct uasp_tport), GFP_KERNEL);
+	if (!(tport)) {
+		printk(KERN_ERR "Unable to allocate struct uasp_tport");
+		return ERR_PTR(-ENOMEM);
+	}
+	tport->tport_wwpn = wwpn;
+	snprintf(tport->tport_name, sizeof(tport->tport_name), wnn_name);
+	return &tport->tport_wwn;
+}
+
+static void uasp_drop_tport(struct se_wwn *wwn)
+{
+	struct uasp_tport *tport = container_of(wwn,
+				struct uasp_tport, tport_wwn);
+	kfree(tport);
+}
+
+static ssize_t uasp_wwn_show_attr_version(
+	struct target_fabric_configfs *tf,
+	char *page)
+{
+	return sprintf(page, "UASP fabric module %s on %s/%s"
+		"on "UTS_RELEASE"\n", UASP_VERSION, utsname()->sysname,
+		utsname()->machine);
+}
+
+TF_WWN_ATTR_RO(uasp, version);
+
+static struct configfs_attribute *uasp_wwn_attrs[] = {
+	&uasp_wwn_version.attr,
+	NULL,
+};
+
+static ssize_t tcm_uasp_tpg_show_gadget_connect(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct uasp_tpg  *tpg = container_of(se_tpg, struct uasp_tpg, se_tpg);
+
+	return snprintf(page, PAGE_SIZE, "%u\n", tpg->gadget_connect);
+}
+
+static ssize_t tcm_uasp_tpg_store_gadget_connect(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct uasp_tpg  *tpg = container_of(se_tpg, struct uasp_tpg, se_tpg);
+	unsigned int op;
+	ssize_t ret = count;
+
+	op = simple_strtoul(page, NULL, 0);
+	if (op > 1)
+		return -EINVAL;
+
+	if (op && tpg->gadget_connect)
+		goto out;
+	if (!op && !tpg->gadget_connect)
+		goto out;
+
+	if (op) {
+		ret = gadget_attach();
+		if (ret)
+			goto out;
+		ret = count;
+	} else {
+		gadget_detach();
+	}
+	tpg->gadget_connect = op;
+out:
+	return ret;
+}
+
+TF_TPG_BASE_ATTR(tcm_uasp, gadget_connect, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *uasp_base_attrs[] = {
+	&tcm_uasp_tpg_gadget_connect.attr,
+	NULL,
+};
+
+static struct target_core_fabric_ops uasp_ops = {
+	.get_fabric_name		= uasp_get_fabric_name,
+	.get_fabric_proto_ident		= uasp_get_fabric_proto_ident,
+	.tpg_get_wwn			= uasp_get_fabric_wwn,
+	.tpg_get_tag			= uasp_get_tag,
+	.tpg_get_default_depth		= uasp_get_default_depth,
+	.tpg_get_pr_transport_id	= uasp_get_pr_transport_id,
+	.tpg_get_pr_transport_id_len	= uasp_get_pr_transport_id_len,
+	.tpg_parse_pr_out_transport_id	= uasp_parse_pr_out_transport_id,
+	.tpg_check_demo_mode		= uasp_check_false,
+	.tpg_check_demo_mode_cache	= uasp_check_true,
+	.tpg_check_demo_mode_write_protect = uasp_check_true,
+	.tpg_check_prod_mode_write_protect = uasp_check_false,
+	.tpg_alloc_fabric_acl		= uasp_alloc_fabric_acl,
+	.tpg_release_fabric_acl		= uasp_release_fabric_acl,
+	.tpg_get_inst_index		= uasp_tpg_get_inst_index,
+	.release_cmd			= uasp_release_cmd,
+	.shutdown_session		= uasp_shutdown_session,
+	.close_session			= uasp_close_session,
+	.stop_session			= uasp_stop_session,
+	.fall_back_to_erl0		= uasp_reset_nexus,
+	.sess_logged_in			= uasp_sess_logged_in,
+	.sess_get_index			= uasp_sess_get_index,
+	.sess_get_initiator_sid		= NULL,
+	.write_pending			= uasp_write_pending,
+	.write_pending_status		= uasp_write_pending_status,
+	.set_default_node_attributes	= uasp_set_default_node_attrs,
+	.get_task_tag			= uasp_get_task_tag,
+	.get_cmd_state			= uasp_get_cmd_state,
+	.queue_data_in			= uasp_queue_data_in,
+	.queue_status			= uasp_queue_status,
+	.queue_tm_rsp			= uasp_queue_tm_rsp,
+	.get_fabric_sense_len		= uasp_get_fabric_sense_len,
+	.set_fabric_sense_len		= uasp_set_fabric_sense_len,
+	.is_state_remove		= uasp_is_state_remove,
+	/*
+	 * Setup function pointers for generic logic in target_core_fabric_configfs.c
+	 */
+	.fabric_make_wwn		= uasp_make_tport,
+	.fabric_drop_wwn		= uasp_drop_tport,
+	.fabric_make_tpg		= uasp_make_tpg,
+	.fabric_drop_tpg		= uasp_drop_tpg,
+	.fabric_post_link		= NULL,
+	.fabric_pre_unlink		= NULL,
+	.fabric_make_np			= NULL,
+	.fabric_drop_np			= NULL,
+	.fabric_make_nodeacl		= uasp_make_nodeacl,
+	.fabric_drop_nodeacl		= uasp_drop_nodeacl,
+};
+
+int uasp_register_configfs(void)
+{
+	struct target_fabric_configfs *fabric;
+	int ret;
+
+	printk(KERN_INFO "UASP fabric module %s on %s/%s"
+		" on "UTS_RELEASE"\n",UASP_VERSION, utsname()->sysname,
+		utsname()->machine);
+	/*
+	 * Register the top level struct config_item_type with TCM core
+	 */
+	fabric = target_fabric_configfs_init(THIS_MODULE, "uasp");
+	if (!(fabric)) {
+		printk(KERN_ERR "target_fabric_configfs_init() failed\n");
+		return -ENOMEM;
+	}
+	/*
+	 * Setup fabric->tf_ops from our local uasp_ops
+	 */
+	fabric->tf_ops = uasp_ops;
+	/*
+	 * Setup default attribute lists for various fabric->tf_cit_tmpl
+	 */
+	TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = uasp_wwn_attrs;
+	TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = uasp_base_attrs;
+	TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;
+	/*
+	 * Register the fabric for use within TCM
+	 */
+	ret = target_fabric_configfs_register(fabric);
+	if (ret < 0) {
+		printk(KERN_ERR "target_fabric_configfs_register() failed"
+				" for UASP\n");
+		return ret;
+	}
+	/*
+	 * Setup our local pointer to *fabric
+	 */
+	uasp_fabric_configfs = fabric;
+	printk(KERN_INFO "UASP[0] - Set fabric -> uasp_fabric_configfs\n");
+	return 0;
+};
+
+void uasp_deregister_configfs(void)
+{
+	if (!(uasp_fabric_configfs))
+		return;
+
+	target_fabric_configfs_deregister(uasp_fabric_configfs);
+	uasp_fabric_configfs = NULL;
+	printk(KERN_INFO "UASP[0] - Cleared uasp_fabric_configfs\n");
+};
diff --git a/drivers/target/uasp/uasp_configfs.h b/drivers/target/uasp/uasp_configfs.h
new file mode 100644
index 0000000..646c096
--- /dev/null
+++ b/drivers/target/uasp/uasp_configfs.h
@@ -0,0 +1,7 @@
+#ifndef __UASP_CONFIGFS_H_
+#define __UASP_CONFIGFS_H_
+
+int uasp_register_configfs(void);
+void uasp_deregister_configfs(void);
+
+#endif
diff --git a/drivers/target/uasp/uasp_fabric.c b/drivers/target/uasp/uasp_fabric.c
new file mode 100644
index 0000000..304c934
--- /dev/null
+++ b/drivers/target/uasp/uasp_fabric.c
@@ -0,0 +1,287 @@
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <asm/unaligned.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/libfc.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+#include <target/target_core_configfs.h>
+
+#include "uasp_base.h"
+#include "uasp_fabric.h"
+
+int uasp_check_true(struct se_portal_group *se_tpg)
+{
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return 1;
+}
+
+int uasp_check_false(struct se_portal_group *se_tpg)
+{
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return 0;
+}
+
+char *uasp_get_fabric_name(void)
+{
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return "uasp";
+}
+
+u8 uasp_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+	struct uasp_tpg *tpg = container_of(se_tpg,
+				struct uasp_tpg, se_tpg);
+	struct uasp_tport *tport = tpg->tport;
+	u8 proto_id;
+
+	switch (tport->tport_proto_id) {
+	case SCSI_PROTOCOL_SAS:
+	default:
+		proto_id = sas_get_fabric_proto_ident(se_tpg);
+		break;
+	}
+
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return proto_id;
+}
+
+char *uasp_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+	struct uasp_tpg *tpg = container_of(se_tpg,
+				struct uasp_tpg, se_tpg);
+	struct uasp_tport *tport = tpg->tport;
+
+	printk(KERN_ERR "%s(%d) '%s'\n", __func__, __LINE__, tport->tport_name);
+	return &tport->tport_name[0];
+}
+
+u16 uasp_get_tag(struct se_portal_group *se_tpg)
+{
+	struct uasp_tpg *tpg = container_of(se_tpg,
+				struct uasp_tpg, se_tpg);
+	printk(KERN_ERR "%s(%d) %d\n", __func__, __LINE__, tpg->tport_tpgt);
+	return tpg->tport_tpgt;
+}
+
+u32 uasp_get_default_depth(struct se_portal_group *se_tpg)
+{
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return 1;
+}
+
+u32 uasp_get_pr_transport_id(
+	struct se_portal_group *se_tpg,
+	struct se_node_acl *se_nacl,
+	struct t10_pr_registration *pr_reg,
+	int *format_code,
+	unsigned char *buf)
+{
+	struct uasp_tpg *tpg = container_of(se_tpg,
+				struct uasp_tpg, se_tpg);
+	struct uasp_tport *tport = tpg->tport;
+	int ret = 0;
+
+	switch (tport->tport_proto_id) {
+	case SCSI_PROTOCOL_SAS:
+	default:
+		ret = sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
+					format_code, buf);
+		break;
+	}
+
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return ret;
+}
+
+u32 uasp_get_pr_transport_id_len(
+	struct se_portal_group *se_tpg,
+	struct se_node_acl *se_nacl,
+	struct t10_pr_registration *pr_reg,
+	int *format_code)
+{
+	struct uasp_tpg *tpg = container_of(se_tpg,
+				struct uasp_tpg, se_tpg);
+	struct uasp_tport *tport = tpg->tport;
+	int ret = 0;
+
+	switch (tport->tport_proto_id) {
+	case SCSI_PROTOCOL_SAS:
+	default:
+		ret = sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
+					format_code);
+		break;
+	}
+
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return ret;
+}
+
+char *uasp_parse_pr_out_transport_id(
+	struct se_portal_group *se_tpg,
+	const char *buf,
+	u32 *out_tid_len,
+	char **port_nexus_ptr)
+{
+	struct uasp_tpg *tpg = container_of(se_tpg,
+				struct uasp_tpg, se_tpg);
+	struct uasp_tport *tport = tpg->tport;
+	char *tid = NULL;
+
+	switch (tport->tport_proto_id) {
+	case SCSI_PROTOCOL_SAS:
+	default:
+		tid = sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
+					port_nexus_ptr);
+	}
+
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return tid;
+}
+
+struct se_node_acl *uasp_alloc_fabric_acl(struct se_portal_group *se_tpg)
+{
+	struct uasp_nacl *nacl;
+
+	nacl = kzalloc(sizeof(struct uasp_nacl), GFP_KERNEL);
+	if (!(nacl)) {
+		printk(KERN_ERR "Unable to alocate struct uasp_nacl\n");
+		return NULL;
+	}
+
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return &nacl->se_node_acl;
+}
+
+void uasp_release_fabric_acl(
+	struct se_portal_group *se_tpg,
+	struct se_node_acl *se_nacl)
+{
+	struct uasp_nacl *nacl = container_of(se_nacl,
+			struct uasp_nacl, se_node_acl);
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	kfree(nacl);
+}
+
+u32 uasp_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return 1;
+}
+
+void uasp_release_cmd(struct se_cmd *se_cmd)
+{
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return;
+}
+
+int uasp_shutdown_session(struct se_session *se_sess)
+{
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return 0;
+}
+
+void uasp_close_session(struct se_session *se_sess)
+{
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return;
+}
+
+void uasp_stop_session(struct se_session *se_sess, int sess_sleep , int conn_sleep)
+{
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return;
+}
+
+void uasp_reset_nexus(struct se_session *se_sess)
+{
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return;
+}
+
+int uasp_sess_logged_in(struct se_session *se_sess)
+{
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return 0;
+}
+
+u32 uasp_sess_get_index(struct se_session *se_sess)
+{
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return 0;
+}
+
+int uasp_write_pending(struct se_cmd *se_cmd)
+{
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return 0;
+}
+
+int uasp_write_pending_status(struct se_cmd *se_cmd)
+{
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return 0;
+}
+
+void uasp_set_default_node_attrs(struct se_node_acl *nacl)
+{
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return;
+}
+
+u32 uasp_get_task_tag(struct se_cmd *se_cmd)
+{
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return 0;
+}
+
+int uasp_get_cmd_state(struct se_cmd *se_cmd)
+{
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return 0;
+}
+
+int uasp_queue_data_in(struct se_cmd *se_cmd)
+{
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return 0;
+}
+
+int uasp_queue_status(struct se_cmd *se_cmd)
+{
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return 0;
+}
+
+int uasp_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return 0;
+}
+
+u16 uasp_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
+{
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return 0;
+}
+
+u16 uasp_get_fabric_sense_len(void)
+{
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return 0;
+}
+
+int uasp_is_state_remove(struct se_cmd *se_cmd)
+{
+	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
+	return 0;
+}
diff --git a/drivers/target/uasp/uasp_fabric.h b/drivers/target/uasp/uasp_fabric.h
new file mode 100644
index 0000000..cf5a300
--- /dev/null
+++ b/drivers/target/uasp/uasp_fabric.h
@@ -0,0 +1,37 @@
+int uasp_check_true(struct se_portal_group *);
+int uasp_check_false(struct se_portal_group *);
+char *uasp_get_fabric_name(void);
+u8 uasp_get_fabric_proto_ident(struct se_portal_group *);
+char *uasp_get_fabric_wwn(struct se_portal_group *);
+u16 uasp_get_tag(struct se_portal_group *);
+u32 uasp_get_default_depth(struct se_portal_group *);
+u32 uasp_get_pr_transport_id(struct se_portal_group *,
+			struct se_node_acl *, struct t10_pr_registration *,
+			int *, unsigned char *);
+u32 uasp_get_pr_transport_id_len(struct se_portal_group *,
+			struct se_node_acl *, struct t10_pr_registration *,
+			int *);
+char *uasp_parse_pr_out_transport_id(struct se_portal_group *,
+			const char *, u32 *, char **);
+struct se_node_acl *uasp_alloc_fabric_acl(struct se_portal_group *);
+void uasp_release_fabric_acl(struct se_portal_group *,
+			struct se_node_acl *);
+u32 uasp_tpg_get_inst_index(struct se_portal_group *);
+void uasp_release_cmd(struct se_cmd *);
+int uasp_shutdown_session(struct se_session *);
+void uasp_close_session(struct se_session *);
+void uasp_stop_session(struct se_session *, int, int);
+void uasp_reset_nexus(struct se_session *);
+int uasp_sess_logged_in(struct se_session *);
+u32 uasp_sess_get_index(struct se_session *);
+int uasp_write_pending(struct se_cmd *);
+int uasp_write_pending_status(struct se_cmd *);
+void uasp_set_default_node_attrs(struct se_node_acl *);
+u32 uasp_get_task_tag(struct se_cmd *);
+int uasp_get_cmd_state(struct se_cmd *);
+int uasp_queue_data_in(struct se_cmd *);
+int uasp_queue_status(struct se_cmd *);
+int uasp_queue_tm_rsp(struct se_cmd *);
+u16 uasp_set_fabric_sense_len(struct se_cmd *, u32);
+u16 uasp_get_fabric_sense_len(void);
+int uasp_is_state_remove(struct se_cmd *);
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 5a084b9..84fb67a 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -774,6 +774,9 @@ config USB_MASS_STORAGE
 	  Say "y" to link the driver statically, or "m" to build
 	  a dynamically linked module called "g_mass_storage".
 
+comment "You need to go to the target framework for UASP support"
+	depends on TARGET_UASP=n
+
 config USB_G_SERIAL
 	tristate "Serial Gadget (with CDC ACM and CDC OBEX support)"
 	help

Sebastian

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [RFC] UASP on target (was: [RFC/PATCH v4 1/3] uas: MS UAS Gadget driver - Infrastructure)
  2011-12-05  8:23   ` Sebastian Andrzej Siewior
@ 2011-12-05  8:39     ` Felipe Balbi
  2011-12-05  8:55       ` [RFC] UASP on target Sebastian Andrzej Siewior
  2011-12-05 16:10     ` [RFC] UASP on target (was: [RFC/PATCH v4 1/3] uas: MS UAS Gadget driver - Infrastructure) Alan Stern
  2011-12-06  7:40     ` [RFC] UASP on target (was: [RFC/PATCH v4 1/3] uas: MS UAS Gadget driver - Infrastructure) Nicholas A. Bellinger
  2 siblings, 1 reply; 12+ messages in thread
From: Felipe Balbi @ 2011-12-05  8:39 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior
  Cc: Shimrit Malichi, Tatyana Brokhman, open list:USB GADGET/PERIPH...,
	open list, target-devel

[-- Attachment #1: Type: text/plain, Size: 1250 bytes --]

Hi,

On Mon, Dec 05, 2011 at 09:23:26AM +0100, Sebastian Andrzej Siewior wrote:
> * Sebastian Andrzej Siewior | 2011-12-05 09:20:47 [+0100]:
> 
> >* Shimrit Malichi | 2011-12-04 21:53:09 [+0200]:
> >
> >>This patch implements the infrastructure for the UAS gadget driver.
> >>The UAS gadget driver registers as a second configuration of the MS
> >>gadet driver.
> >hch said to use target framework and you haven't done so. This is what I
> >have so far. It is not yet complete. What I need to do is:
> >- wire up command processing (currently here)
> >- wire up data processing
> >- check it works => post v1
> >- wire up command tagging => v2
> >- remove hard codings and fix whatever people complained about.

This is much better, indeed, but the way it is now, it's only usable by
the gadget framework because you have put the function driver on the
transport layer. I wonder if there wouldn't be a simple way to split the
"SCSI Over USB" part in a more generic way which could be shared between
gadget side UASP and host side UASP drivers ?!? Maybe ?!?

The drivers/target/uasp_*.c would really be just a transport layer and
gadget/host drivers would make calls to that "library" ? Something like
that ??

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC] UASP on target
  2011-12-05  8:39     ` Felipe Balbi
@ 2011-12-05  8:55       ` Sebastian Andrzej Siewior
  2011-12-05  9:11         ` Felipe Balbi
  0 siblings, 1 reply; 12+ messages in thread
From: Sebastian Andrzej Siewior @ 2011-12-05  8:55 UTC (permalink / raw)
  To: balbi
  Cc: Shimrit Malichi, Tatyana Brokhman, open list:USB GADGET/PERIPH...,
	open list, target-devel

On 12/05/2011 09:39 AM, Felipe Balbi wrote:
> Hi,
Hi,

> On Mon, Dec 05, 2011 at 09:23:26AM +0100, Sebastian Andrzej Siewior wrote:
>> * Sebastian Andrzej Siewior | 2011-12-05 09:20:47 [+0100]:
>>
>>> * Shimrit Malichi | 2011-12-04 21:53:09 [+0200]:
>>>
>>>> This patch implements the infrastructure for the UAS gadget driver.
>>>> The UAS gadget driver registers as a second configuration of the MS
>>>> gadet driver.
>>> hch said to use target framework and you haven't done so. This is what I
>>> have so far. It is not yet complete. What I need to do is:
>>> - wire up command processing (currently here)
>>> - wire up data processing
>>> - check it works =>  post v1
>>> - wire up command tagging =>  v2
>>> - remove hard codings and fix whatever people complained about.
>
> This is much better, indeed, but the way it is now, it's only usable by
> the gadget framework because you have put the function driver on the
> transport layer. I wonder if there wouldn't be a simple way to split the
> "SCSI Over USB" part in a more generic way which could be shared between
> gadget side UASP and host side UASP drivers ?!? Maybe ?!?
>
> The drivers/target/uasp_*.c would really be just a transport layer and
> gadget/host drivers would make calls to that "library" ? Something like
> that ??

There is very little code that is not host specific. For instance
uas_alloc_cmd_urb() is something that could be used on both side but
the host is boxing the command and I need to unbox it. So I don't see
how I could share things except for the defines.
Most of the things are usb specific. So UAS gets the commands from the
scsi framework, puts the usb layer around it and sends them.

Sebastian

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC] UASP on target
  2011-12-05  8:55       ` [RFC] UASP on target Sebastian Andrzej Siewior
@ 2011-12-05  9:11         ` Felipe Balbi
  2011-12-05 12:10           ` Shimrit Malichi
  0 siblings, 1 reply; 12+ messages in thread
From: Felipe Balbi @ 2011-12-05  9:11 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior
  Cc: balbi, Shimrit Malichi, Tatyana Brokhman,
	open list:USB GADGET/PERIPH...,
	open list, target-devel

[-- Attachment #1: Type: text/plain, Size: 1981 bytes --]

On Mon, Dec 05, 2011 at 09:55:13AM +0100, Sebastian Andrzej Siewior wrote:
> On 12/05/2011 09:39 AM, Felipe Balbi wrote:
> >Hi,
> Hi,
> 
> >On Mon, Dec 05, 2011 at 09:23:26AM +0100, Sebastian Andrzej Siewior wrote:
> >>* Sebastian Andrzej Siewior | 2011-12-05 09:20:47 [+0100]:
> >>
> >>>* Shimrit Malichi | 2011-12-04 21:53:09 [+0200]:
> >>>
> >>>>This patch implements the infrastructure for the UAS gadget driver.
> >>>>The UAS gadget driver registers as a second configuration of the MS
> >>>>gadet driver.
> >>>hch said to use target framework and you haven't done so. This is what I
> >>>have so far. It is not yet complete. What I need to do is:
> >>>- wire up command processing (currently here)
> >>>- wire up data processing
> >>>- check it works =>  post v1
> >>>- wire up command tagging =>  v2
> >>>- remove hard codings and fix whatever people complained about.
> >
> >This is much better, indeed, but the way it is now, it's only usable by
> >the gadget framework because you have put the function driver on the
> >transport layer. I wonder if there wouldn't be a simple way to split the
> >"SCSI Over USB" part in a more generic way which could be shared between
> >gadget side UASP and host side UASP drivers ?!? Maybe ?!?
> >
> >The drivers/target/uasp_*.c would really be just a transport layer and
> >gadget/host drivers would make calls to that "library" ? Something like
> >that ??
> 
> There is very little code that is not host specific. For instance
> uas_alloc_cmd_urb() is something that could be used on both side but
> the host is boxing the command and I need to unbox it. So I don't see
> how I could share things except for the defines.
> Most of the things are usb specific. So UAS gets the commands from the
> scsi framework, puts the usb layer around it and sends them.

k, fair enough ;-) Just thought there'd be a better way to share this
code with host side implementation. Nevermind then

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC] UASP on target
  2011-12-05  9:11         ` Felipe Balbi
@ 2011-12-05 12:10           ` Shimrit Malichi
  2011-12-05 12:14             ` Felipe Balbi
  0 siblings, 1 reply; 12+ messages in thread
From: Shimrit Malichi @ 2011-12-05 12:10 UTC (permalink / raw)
  To: balbi
  Cc: Sebastian Andrzej Siewior, Shimrit Malichi, Tatyana Brokhman,
	USB GADGET/PERIPH...,
	open list, target-devel


> On Mon, Dec 05, 2011 at 09:55:13AM +0100, Sebastian Andrzej Siewior wrote:
>> On 12/05/2011 09:39 AM, Felipe Balbi wrote:
>> >Hi,
>> Hi,
>>
>> >On Mon, Dec 05, 2011 at 09:23:26AM +0100, Sebastian Andrzej Siewior
>> wrote:
>> >>* Sebastian Andrzej Siewior | 2011-12-05 09:20:47 [+0100]:
>> >>
>> >>>* Shimrit Malichi | 2011-12-04 21:53:09 [+0200]:
>> >>>
>> >>>>This patch implements the infrastructure for the UAS gadget driver.
>> >>>>The UAS gadget driver registers as a second configuration of the MS
>> >>>>gadet driver.
>> >>>hch said to use target framework and you haven't done so. This is
>> what I
>> >>>have so far. It is not yet complete. What I need to do is:
>> >>>- wire up command processing (currently here)
>> >>>- wire up data processing
>> >>>- check it works =>  post v1
>> >>>- wire up command tagging =>  v2
>> >>>- remove hard codings and fix whatever people complained about.
>> >
>> >This is much better, indeed, but the way it is now, it's only usable by
>> >the gadget framework because you have put the function driver on the
>> >transport layer. I wonder if there wouldn't be a simple way to split
>> the
>> >"SCSI Over USB" part in a more generic way which could be shared
>> between
>> >gadget side UASP and host side UASP drivers ?!? Maybe ?!?
>> >
>> >The drivers/target/uasp_*.c would really be just a transport layer and
>> >gadget/host drivers would make calls to that "library" ? Something like
>> >that ??
>>
>> There is very little code that is not host specific. For instance
>> uas_alloc_cmd_urb() is something that could be used on both side but
>> the host is boxing the command and I need to unbox it. So I don't see
>> how I could share things except for the defines.
>> Most of the things are usb specific. So UAS gets the commands from the
>> scsi framework, puts the usb layer around it and sends them.
>
> k, fair enough ;-) Just thought there'd be a better way to share this
> code with host side implementation. Nevermind then
>
> --
> balbi
>

Hi guys,

Thanks for your quick response.
We are glad to see that our initial implementation is being used and
gaining momentum.

We  intend to learn and re-implement the UAS protocol using the target
framework, and continue our work started few months ago.

We hope to get your corporation in the future as well.

Thanks,
Shimrit


-- 
Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC] UASP on target
  2011-12-05 12:10           ` Shimrit Malichi
@ 2011-12-05 12:14             ` Felipe Balbi
  0 siblings, 0 replies; 12+ messages in thread
From: Felipe Balbi @ 2011-12-05 12:14 UTC (permalink / raw)
  To: Shimrit Malichi
  Cc: balbi, Sebastian Andrzej Siewior, Tatyana Brokhman,
	USB GADGET/PERIPH...,
	open list, target-devel

[-- Attachment #1: Type: text/plain, Size: 2772 bytes --]

On Mon, Dec 05, 2011 at 04:10:50AM -0800, Shimrit Malichi wrote:
> 
> > On Mon, Dec 05, 2011 at 09:55:13AM +0100, Sebastian Andrzej Siewior wrote:
> >> On 12/05/2011 09:39 AM, Felipe Balbi wrote:
> >> >Hi,
> >> Hi,
> >>
> >> >On Mon, Dec 05, 2011 at 09:23:26AM +0100, Sebastian Andrzej Siewior
> >> wrote:
> >> >>* Sebastian Andrzej Siewior | 2011-12-05 09:20:47 [+0100]:
> >> >>
> >> >>>* Shimrit Malichi | 2011-12-04 21:53:09 [+0200]:
> >> >>>
> >> >>>>This patch implements the infrastructure for the UAS gadget driver.
> >> >>>>The UAS gadget driver registers as a second configuration of the MS
> >> >>>>gadet driver.
> >> >>>hch said to use target framework and you haven't done so. This is
> >> what I
> >> >>>have so far. It is not yet complete. What I need to do is:
> >> >>>- wire up command processing (currently here)
> >> >>>- wire up data processing
> >> >>>- check it works =>  post v1
> >> >>>- wire up command tagging =>  v2
> >> >>>- remove hard codings and fix whatever people complained about.
> >> >
> >> >This is much better, indeed, but the way it is now, it's only usable by
> >> >the gadget framework because you have put the function driver on the
> >> >transport layer. I wonder if there wouldn't be a simple way to split
> >> the
> >> >"SCSI Over USB" part in a more generic way which could be shared
> >> between
> >> >gadget side UASP and host side UASP drivers ?!? Maybe ?!?
> >> >
> >> >The drivers/target/uasp_*.c would really be just a transport layer and
> >> >gadget/host drivers would make calls to that "library" ? Something like
> >> >that ??
> >>
> >> There is very little code that is not host specific. For instance
> >> uas_alloc_cmd_urb() is something that could be used on both side but
> >> the host is boxing the command and I need to unbox it. So I don't see
> >> how I could share things except for the defines.
> >> Most of the things are usb specific. So UAS gets the commands from the
> >> scsi framework, puts the usb layer around it and sends them.
> >
> > k, fair enough ;-) Just thought there'd be a better way to share this
> > code with host side implementation. Nevermind then
> >
> > --
> > balbi
> >
> 
> Hi guys,
> 
> Thanks for your quick response.
> We are glad to see that our initial implementation is being used and
> gaining momentum.
> 
> We  intend to learn and re-implement the UAS protocol using the target
> framework, and continue our work started few months ago.

Sebastian has been doing for the last few days or so, you guys should
join efforts to avoid duplicated work.

> We hope to get your corporation in the future as well.

sorry, but I'm not allowed to you my corporation. Hope my cooperation is
enough :-)

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC] UASP on target (was: [RFC/PATCH v4 1/3] uas: MS UAS Gadget driver - Infrastructure)
  2011-12-05  8:23   ` Sebastian Andrzej Siewior
  2011-12-05  8:39     ` Felipe Balbi
@ 2011-12-05 16:10     ` Alan Stern
  2011-12-05 16:52       ` [RFC] UASP on target Sebastian Andrzej Siewior
  2011-12-06  7:40     ` [RFC] UASP on target (was: [RFC/PATCH v4 1/3] uas: MS UAS Gadget driver - Infrastructure) Nicholas A. Bellinger
  2 siblings, 1 reply; 12+ messages in thread
From: Alan Stern @ 2011-12-05 16:10 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior
  Cc: Shimrit Malichi, Tatyana Brokhman, USB list,
	Kernel development list, target-devel

On Mon, 5 Dec 2011, Sebastian Andrzej Siewior wrote:

> * Sebastian Andrzej Siewior | 2011-12-05 09:20:47 [+0100]:
> 
> >* Shimrit Malichi | 2011-12-04 21:53:09 [+0200]:
> >
> >>This patch implements the infrastructure for the UAS gadget driver.
> >>The UAS gadget driver registers as a second configuration of the MS
> >>gadet driver.
> >hch said to use target framework and you haven't done so. This is what I
> >have so far. It is not yet complete. What I need to do is:
> >- wire up command processing (currently here)
> >- wire up data processing
> >- check it works => post v1
> >- wire up command tagging => v2
> >- remove hard codings and fix whatever people complained about.

Evidently you were able to find enough information about the target 
framework to write a driver using it.  Can you tell us where this 
information is?  It hasn't been easy to locate.

Alan Stern


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC] UASP on target
  2011-12-05 16:10     ` [RFC] UASP on target (was: [RFC/PATCH v4 1/3] uas: MS UAS Gadget driver - Infrastructure) Alan Stern
@ 2011-12-05 16:52       ` Sebastian Andrzej Siewior
  0 siblings, 0 replies; 12+ messages in thread
From: Sebastian Andrzej Siewior @ 2011-12-05 16:52 UTC (permalink / raw)
  To: Alan Stern
  Cc: Shimrit Malichi, Tatyana Brokhman, USB list,
	Kernel development list, target-devel

On 12/05/2011 05:10 PM, Alan Stern wrote:

> Evidently you were able to find enough information about the target
> framework to write a driver using it.  Can you tell us where this
> information is?  It hasn't been easy to locate.

Hehe. Well, I've been told that the target framework has everything one
needs to get it done so I've been digging in the code. First I tried to
come up with an easy setup where I can use it. _This_ was already hard
to get done for someone who is not familiar with scsi. Once I had all
pieces together I wrote this [0].With this information I know more or
less how that thing works or should work.
So at this point I understood that I need to comeup with somethin like
tcm_loop or tcm_vhost. Looking at the host side of the uas driver it is
using SAS as the protocol and nothing special if you ignore "struct iu"
for a moment.
Then I found the python script in Documentation/target which creates you 
a skeleton driver. So I used this and started hacking. First I took
the usb descriptors and looked what happens after I connected the
dummy_hcd driver/gadget. I received a usb command message. So now I try 
to wire it up in target. I look at the loopback/vhost_scsi for some
inspiration. Other than that I have no additional information....

[0] http://article.gmane.org/gmane.linux.scsi.target.devel/654

> Alan Stern

Sebastian

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC] UASP on target (was: [RFC/PATCH v4 1/3] uas: MS UAS Gadget driver - Infrastructure)
  2011-12-05  8:23   ` Sebastian Andrzej Siewior
  2011-12-05  8:39     ` Felipe Balbi
  2011-12-05 16:10     ` [RFC] UASP on target (was: [RFC/PATCH v4 1/3] uas: MS UAS Gadget driver - Infrastructure) Alan Stern
@ 2011-12-06  7:40     ` Nicholas A. Bellinger
  2011-12-06  9:19       ` [RFC] UASP on target Sebastian Andrzej Siewior
  2 siblings, 1 reply; 12+ messages in thread
From: Nicholas A. Bellinger @ 2011-12-06  7:40 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior
  Cc: Shimrit Malichi, Tatyana Brokhman, open list:USB GADGET/PERIPH...,
	open list, target-devel, Jerome Martin

On Mon, 2011-12-05 at 09:23 +0100, Sebastian Andrzej Siewior wrote:
> * Sebastian Andrzej Siewior | 2011-12-05 09:20:47 [+0100]:
> 
> >* Shimrit Malichi | 2011-12-04 21:53:09 [+0200]:
> >
> >>This patch implements the infrastructure for the UAS gadget driver.
> >>The UAS gadget driver registers as a second configuration of the MS
> >>gadet driver.
> >hch said to use target framework and you haven't done so. This is what I
> >have so far. It is not yet complete. What I need to do is:
> >- wire up command processing (currently here)
> >- wire up data processing
> >- check it works => post v1
> >- wire up command tagging => v2
> >- remove hard codings and fix whatever people complained about.
> 

Hi Sebastian,

So this looks like a reasonable first step to get a control plane up
for /sys/kernel/config/target/uasp/.  I have not at the USB parts beyond
the initial patch so I can't really comment there, but thanks for using
tcm_mod_builder.py to generate your initial skeleton.  

Just a minor few comments below on the target-related pieces below, and
a few comments to keep in mind for he main I/O path with struct
uasp_cmd->se_cmd descriptor usage.

> diff --git a/drivers/target/Kconfig b/drivers/target/Kconfig
> index e66fcc7..64d3204 100644
> --- a/drivers/target/Kconfig
> +++ b/drivers/target/Kconfig
> @@ -50,3 +50,4 @@ source "drivers/target/tcm_qla2xxx/Kconfig"
>  source "drivers/target/tcm_vhost/Kconfig"
>  
>  endif
> +source "drivers/target/uasp/Kconfig"
> diff --git a/drivers/target/Makefile b/drivers/target/Makefile
> index 1945dba..b1135d5 100644
> --- a/drivers/target/Makefile
> +++ b/drivers/target/Makefile
> @@ -28,3 +28,4 @@ obj-$(CONFIG_TCM_FC)		+= tcm_fc/
>  obj-$(CONFIG_ISCSI_TARGET)	+= iscsi/
>  obj-$(CONFIG_TCM_QLA2XXX)	+= tcm_qla2xxx/
>  obj-$(CONFIG_TCM_VHOST)		+= tcm_vhost/
> +obj-$(CONFIG_TARGET_UASP)	+= uasp/
> diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
> index f7cb64f..127496a 100644
> --- a/drivers/target/target_core_configfs.c
> +++ b/drivers/target/target_core_configfs.c
> @@ -162,6 +162,13 @@ static struct config_group *target_core_register_fabric(
>  				" tcm_loop.ko: %d\n", ret);
>  			return ERR_PTR(-EINVAL);
>  		}
> +	} else if (!strncmp(name, "uasp", 4)) {
> +		ret = request_module("tcm_uasp");
> +		if (ret < 0) {
> +			pr_err("request_module() failed for"
> +				" tcm_loop.ko: %d\n", ret);
> +			return ERR_PTR(-EINVAL);
> +		}
>  	}
>  
>  	tf = target_core_get_fabric(name);

So making the request_module() calls was an original feature of v3.x
target core code, but this is not strictly required for normal usage
after loading the module, or with rtslib /var/target/spec/uasp.spec
usage.

As we are trying to avoid extra request_module() usage in target-core,
please go ahead and drop this part for now..

> diff --git a/drivers/target/uasp/Kconfig b/drivers/target/uasp/Kconfig
> new file mode 100644
> index 0000000..0d48a58
> --- /dev/null
> +++ b/drivers/target/uasp/Kconfig
> @@ -0,0 +1,6 @@
> +config TARGET_UASP
> +	tristate "UASP fabric module"
> +	depends on TARGET_CORE && CONFIGFS_FS
> +	depends on USB_GADGET
> +	---help---
> +	Say Y here to enable the UASP fabric module
> diff --git a/drivers/target/uasp/Makefile b/drivers/target/uasp/Makefile
> new file mode 100644
> index 0000000..25883ab
> --- /dev/null
> +++ b/drivers/target/uasp/Makefile
> @@ -0,0 +1,5 @@
> +CFLAGS_gadget.o			:= -I$(srctree)/drivers/usb/gadget
> +tcm_uasp-objs			:= uasp_fabric.o \
> +					gadget.o \
> +					   uasp_configfs.o
> +obj-$(CONFIG_TARGET_UASP)	+= tcm_uasp.o
> diff --git a/drivers/target/uasp/gadget.c b/drivers/target/uasp/gadget.c
> new file mode 100644

<SNIP>

> diff --git a/drivers/target/uasp/uasp_configfs.c b/drivers/target/uasp/uasp_configfs.c
> new file mode 100644
> index 0000000..7f6b280
> --- /dev/null
> +++ b/drivers/target/uasp/uasp_configfs.c
> @@ -0,0 +1,333 @@
> +#include <linux/module.h>
> +#include <linux/moduleparam.h>
> +#include <linux/version.h>
> +#include <generated/utsrelease.h>
> +#include <linux/utsname.h>
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +#include <linux/kthread.h>
> +#include <linux/types.h>
> +#include <linux/string.h>
> +#include <linux/configfs.h>
> +#include <linux/ctype.h>
> +#include <asm/unaligned.h>
> +
> +#include <target/target_core_base.h>
> +#include <target/target_core_fabric.h>
> +#include <target/target_core_fabric_configfs.h>
> +#include <target/target_core_configfs.h>
> +#include <target/configfs_macros.h>
> +
> +#include "uasp_base.h"
> +#include "uasp_fabric.h"
> +#include "gadget_ops.h"
> +
> +/* Local pointer to allocated TCM configfs fabric module */
> +struct target_fabric_configfs *uasp_fabric_configfs;
> +
> +static const char *uasp_check_wwn(const char *name)
> +{
> +	const char *n;
> +	unsigned int len;
> +
> +	n = strstr(name, "naa.");
> +	if (!n)
> +		return NULL;
> +	n += 4;
> +	len = strlen(n);
> +	if (len == 0 || len > UASP_NAMELEN - 1)
> +		return NULL;
> +	return n;
> +}
> +

Note this is currently using naa. prefixed targetnames for UASP
endpoints, as loopback does with SAS proto_id port emulation..

> +int uasp_register_configfs(void)
> +{
> +	struct target_fabric_configfs *fabric;
> +	int ret;
> +
> +	printk(KERN_INFO "UASP fabric module %s on %s/%s"
> +		" on "UTS_RELEASE"\n",UASP_VERSION, utsname()->sysname,
> +		utsname()->machine);
> +	/*
> +	 * Register the top level struct config_item_type with TCM core
> +	 */
> +	fabric = target_fabric_configfs_init(THIS_MODULE, "uasp");
> +	if (!(fabric)) {
> +		printk(KERN_ERR "target_fabric_configfs_init() failed\n");
> +		return -ENOMEM;
> +	}

This should be checking using IS_ERR() with fabric, which is a current
bug in tcm_mod_builder.py

> +	/*
> +	 * Setup fabric->tf_ops from our local uasp_ops
> +	 */
> +	fabric->tf_ops = uasp_ops;
> +	/*
> +	 * Setup default attribute lists for various fabric->tf_cit_tmpl
> +	 */
> +	TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = uasp_wwn_attrs;
> +	TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = uasp_base_attrs;
> +	TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL;
> +	TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;
> +	TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;
> +	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL;
> +	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
> +	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
> +	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;
> +	/*
> +	 * Register the fabric for use within TCM
> +	 */
> +	ret = target_fabric_configfs_register(fabric);
> +	if (ret < 0) {
> +		printk(KERN_ERR "target_fabric_configfs_register() failed"
> +				" for UASP\n");
> +		return ret;
> +	}
> +	/*
> +	 * Setup our local pointer to *fabric
> +	 */
> +	uasp_fabric_configfs = fabric;
> +	printk(KERN_INFO "UASP[0] - Set fabric -> uasp_fabric_configfs\n");
> +	return 0;
> +};
> +
> +void uasp_deregister_configfs(void)
> +{
> +	if (!(uasp_fabric_configfs))
> +		return;
> +
> +	target_fabric_configfs_deregister(uasp_fabric_configfs);
> +	uasp_fabric_configfs = NULL;
> +	printk(KERN_INFO "UASP[0] - Cleared uasp_fabric_configfs\n");
> +};

> diff --git a/drivers/target/uasp/uasp_fabric.c b/drivers/target/uasp/uasp_fabric.c
> new file mode 100644
> index 0000000..304c934
> --- /dev/null
> +++ b/drivers/target/uasp/uasp_fabric.c
> @@ -0,0 +1,287 @@
> +#include <linux/slab.h>
> +#include <linux/kthread.h>
> +#include <linux/types.h>
> +#include <linux/list.h>
> +#include <linux/types.h>
> +#include <linux/string.h>
> +#include <linux/ctype.h>
> +#include <asm/unaligned.h>
> +#include <scsi/scsi.h>
> +#include <scsi/scsi_host.h>
> +#include <scsi/scsi_device.h>
> +#include <scsi/scsi_cmnd.h>
> +#include <scsi/libfc.h>
> +
> +#include <target/target_core_base.h>
> +#include <target/target_core_fabric.h>
> +#include <target/target_core_configfs.h>
> +
> +#include "uasp_base.h"
> +#include "uasp_fabric.h"
> +
> +int uasp_check_true(struct se_portal_group *se_tpg)
> +{
> +	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
> +	return 1;
> +}
> +
> +int uasp_check_false(struct se_portal_group *se_tpg)
> +{
> +	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
> +	return 0;
> +}
> +
> +char *uasp_get_fabric_name(void)
> +{
> +	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
> +	return "uasp";
> +}
> +
> +u8 uasp_get_fabric_proto_ident(struct se_portal_group *se_tpg)
> +{
> +	struct uasp_tpg *tpg = container_of(se_tpg,
> +				struct uasp_tpg, se_tpg);
> +	struct uasp_tport *tport = tpg->tport;
> +	u8 proto_id;
> +
> +	switch (tport->tport_proto_id) {
> +	case SCSI_PROTOCOL_SAS:
> +	default:
> +		proto_id = sas_get_fabric_proto_ident(se_tpg);
> +		break;
> +	}
> +
> +	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
> +	return proto_id;
> +}
> +
> +char *uasp_get_fabric_wwn(struct se_portal_group *se_tpg)
> +{
> +	struct uasp_tpg *tpg = container_of(se_tpg,
> +				struct uasp_tpg, se_tpg);
> +	struct uasp_tport *tport = tpg->tport;
> +
> +	printk(KERN_ERR "%s(%d) '%s'\n", __func__, __LINE__, tport->tport_name);
> +	return &tport->tport_name[0];
> +}
> +
> +u16 uasp_get_tag(struct se_portal_group *se_tpg)
> +{
> +	struct uasp_tpg *tpg = container_of(se_tpg,
> +				struct uasp_tpg, se_tpg);
> +	printk(KERN_ERR "%s(%d) %d\n", __func__, __LINE__, tpg->tport_tpgt);
> +	return tpg->tport_tpgt;
> +}
> +
> +u32 uasp_get_default_depth(struct se_portal_group *se_tpg)
> +{
> +	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
> +	return 1;
> +}
> +
> +u32 uasp_get_pr_transport_id(
> +	struct se_portal_group *se_tpg,
> +	struct se_node_acl *se_nacl,
> +	struct t10_pr_registration *pr_reg,
> +	int *format_code,
> +	unsigned char *buf)
> +{
> +	struct uasp_tpg *tpg = container_of(se_tpg,
> +				struct uasp_tpg, se_tpg);
> +	struct uasp_tport *tport = tpg->tport;
> +	int ret = 0;
> +
> +	switch (tport->tport_proto_id) {
> +	case SCSI_PROTOCOL_SAS:
> +	default:
> +		ret = sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
> +					format_code, buf);
> +		break;
> +	}
> +
> +	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
> +	return ret;
> +}
> +
> +u32 uasp_get_pr_transport_id_len(
> +	struct se_portal_group *se_tpg,
> +	struct se_node_acl *se_nacl,
> +	struct t10_pr_registration *pr_reg,
> +	int *format_code)
> +{
> +	struct uasp_tpg *tpg = container_of(se_tpg,
> +				struct uasp_tpg, se_tpg);
> +	struct uasp_tport *tport = tpg->tport;
> +	int ret = 0;
> +
> +	switch (tport->tport_proto_id) {
> +	case SCSI_PROTOCOL_SAS:
> +	default:
> +		ret = sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
> +					format_code);
> +		break;
> +	}
> +
> +	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
> +	return ret;
> +}
> +
> +char *uasp_parse_pr_out_transport_id(
> +	struct se_portal_group *se_tpg,
> +	const char *buf,
> +	u32 *out_tid_len,
> +	char **port_nexus_ptr)
> +{
> +	struct uasp_tpg *tpg = container_of(se_tpg,
> +				struct uasp_tpg, se_tpg);
> +	struct uasp_tport *tport = tpg->tport;
> +	char *tid = NULL;
> +
> +	switch (tport->tport_proto_id) {
> +	case SCSI_PROTOCOL_SAS:
> +	default:
> +		tid = sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
> +					port_nexus_ptr);
> +	}
> +
> +	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
> +	return tid;
> +}
> +
> +struct se_node_acl *uasp_alloc_fabric_acl(struct se_portal_group *se_tpg)
> +{
> +	struct uasp_nacl *nacl;
> +
> +	nacl = kzalloc(sizeof(struct uasp_nacl), GFP_KERNEL);
> +	if (!(nacl)) {
> +		printk(KERN_ERR "Unable to alocate struct uasp_nacl\n");
> +		return NULL;
> +	}
> +
> +	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
> +	return &nacl->se_node_acl;
> +}
> +
> +void uasp_release_fabric_acl(
> +	struct se_portal_group *se_tpg,
> +	struct se_node_acl *se_nacl)
> +{
> +	struct uasp_nacl *nacl = container_of(se_nacl,
> +			struct uasp_nacl, se_node_acl);
> +	printk(KERN_ERR "%s(%d)\n", __func__, __LINE__);
> +	kfree(nacl);
> +}
> +

<SNIP>

So for the primary incoming I/O path, you'll want to be using the new
target_submit_cmd() call that we've been working on in
lio-core.git/qla_tgt-3.3 recently, as this will simplify incoming I/O +
exception handling for struct uasp_cmd from processing context usage.

Also, do you expect this new driver to pass pre-populated scatterlists,
or to leave se_cmd->t_data_sg allocation up to target-core..?  Depending
on the expected usage this will look slightly different from the current
usage in tcm_loop/tcm_vhost that both pass pre-populated scatterlists
from Linux/SCSI.

Aside from that, let me know if you have questions while filling in the
write_pending and response (queue_data_in + queue_status) fabric
callbacks.

Thanks!

--nab


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC] UASP on target
  2011-12-06  7:40     ` [RFC] UASP on target (was: [RFC/PATCH v4 1/3] uas: MS UAS Gadget driver - Infrastructure) Nicholas A. Bellinger
@ 2011-12-06  9:19       ` Sebastian Andrzej Siewior
  0 siblings, 0 replies; 12+ messages in thread
From: Sebastian Andrzej Siewior @ 2011-12-06  9:19 UTC (permalink / raw)
  To: Nicholas A. Bellinger
  Cc: Shimrit Malichi, Tatyana Brokhman, open list:USB GADGET/PERIPH...,
	open list, target-devel, Jerome Martin

On 12/06/2011 08:40 AM, Nicholas A. Bellinger wrote:
> Hi Sebastian,

Hi Nicholas,

> So this looks like a reasonable first step to get a control plane up
> for /sys/kernel/config/target/uasp/.  I have not at the USB parts beyond
> the initial patch so I can't really comment there, but thanks for using
> tcm_mod_builder.py to generate your initial skeleton.

Thanks for providing the skeleton building script :)
I don't have more yet. Storage on USB should provide two
configurations: BOT and UASP. BOT is currently served by drivers/usb
/gadget/mass_storage.c. The configuration (modprobe parameters) and
protocol handling is done there. Since UASP brings its own
configuration I think that it will be too complicated to merge both
code basis (not to mention the way both handling things internally). So
I decided first to integrate UASP with target and then worry about BOT.

> Just a minor few comments below on the target-related pieces below, and
> a few comments to keep in mind for he main I/O path with struct
> uasp_cmd->se_cmd descriptor usage.
>
>> diff --git a/drivers/target/Kconfig b/drivers/target/Kconfig
>> index e66fcc7..64d3204 100644
>> --- a/drivers/target/Kconfig
>> +++ b/drivers/target/Kconfig
>> @@ -50,3 +50,4 @@ source "drivers/target/tcm_qla2xxx/Kconfig"
>>   source "drivers/target/tcm_vhost/Kconfig"
>>
>>   endif
>> +source "drivers/target/uasp/Kconfig"
>> diff --git a/drivers/target/Makefile b/drivers/target/Makefile
>> index 1945dba..b1135d5 100644
>> --- a/drivers/target/Makefile
>> +++ b/drivers/target/Makefile
>> @@ -28,3 +28,4 @@ obj-$(CONFIG_TCM_FC)		+= tcm_fc/
>>   obj-$(CONFIG_ISCSI_TARGET)	+= iscsi/
>>   obj-$(CONFIG_TCM_QLA2XXX)	+= tcm_qla2xxx/
>>   obj-$(CONFIG_TCM_VHOST)		+= tcm_vhost/
>> +obj-$(CONFIG_TARGET_UASP)	+= uasp/
>> diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
>> index f7cb64f..127496a 100644
>> --- a/drivers/target/target_core_configfs.c
>> +++ b/drivers/target/target_core_configfs.c
>> @@ -162,6 +162,13 @@ static struct config_group *target_core_register_fabric(
>>   				" tcm_loop.ko: %d\n", ret);
>>   			return ERR_PTR(-EINVAL);
>>   		}
>> +	} else if (!strncmp(name, "uasp", 4)) {
>> +		ret = request_module("tcm_uasp");
>> +		if (ret<  0) {
>> +			pr_err("request_module() failed for"
>> +				" tcm_loop.ko: %d\n", ret);
>> +			return ERR_PTR(-EINVAL);
>> +		}
>>   	}
>>
>>   	tf = target_core_get_fabric(name);
>
> So making the request_module() calls was an original feature of v3.x
> target core code, but this is not strictly required for normal usage
> after loading the module, or with rtslib /var/target/spec/uasp.spec
> usage.
I see.

> As we are trying to avoid extra request_module() usage in target-core,
> please go ahead and drop this part for now..

Okay.

>> diff --git a/drivers/target/uasp/uasp_configfs.c b/drivers/target/uasp/uasp_configfs.c
>> new file mode 100644
>> index 0000000..7f6b280
>> --- /dev/null
>> +++ b/drivers/target/uasp/uasp_configfs.c
>> @@ -0,0 +1,333 @@
>> +#include<linux/module.h>
>> +#include<linux/moduleparam.h>
>> +#include<linux/version.h>
>> +#include<generated/utsrelease.h>
>> +#include<linux/utsname.h>
>> +#include<linux/init.h>
>> +#include<linux/slab.h>
>> +#include<linux/kthread.h>
>> +#include<linux/types.h>
>> +#include<linux/string.h>
>> +#include<linux/configfs.h>
>> +#include<linux/ctype.h>
>> +#include<asm/unaligned.h>
>> +
>> +#include<target/target_core_base.h>
>> +#include<target/target_core_fabric.h>
>> +#include<target/target_core_fabric_configfs.h>
>> +#include<target/target_core_configfs.h>
>> +#include<target/configfs_macros.h>
>> +
>> +#include "uasp_base.h"
>> +#include "uasp_fabric.h"
>> +#include "gadget_ops.h"
>> +
>> +/* Local pointer to allocated TCM configfs fabric module */
>> +struct target_fabric_configfs *uasp_fabric_configfs;
>> +
>> +static const char *uasp_check_wwn(const char *name)
>> +{
>> +	const char *n;
>> +	unsigned int len;
>> +
>> +	n = strstr(name, "naa.");
>> +	if (!n)
>> +		return NULL;
>> +	n += 4;
>> +	len = strlen(n);
>> +	if (len == 0 || len>  UASP_NAMELEN - 1)
>> +		return NULL;
>> +	return n;
>> +}
>> +
>
> Note this is currently using naa. prefixed targetnames for UASP
> endpoints, as loopback does with SAS proto_id port emulation..

Not sure if this is the right thing to do. I've seen it in loop and
vhost that once "naa." has been found, the protocol was set to SAS.
I think I have to use SAS so I am using the same prefix here.

>> +int uasp_register_configfs(void)
>> +{
>> +	struct target_fabric_configfs *fabric;
>> +	int ret;
>> +
>> +	printk(KERN_INFO "UASP fabric module %s on %s/%s"
>> +		" on "UTS_RELEASE"\n",UASP_VERSION, utsname()->sysname,
>> +		utsname()->machine);
>> +	/*
>> +	 * Register the top level struct config_item_type with TCM core
>> +	 */
>> +	fabric = target_fabric_configfs_init(THIS_MODULE, "uasp");
>> +	if (!(fabric)) {
>> +		printk(KERN_ERR "target_fabric_configfs_init() failed\n");
>> +		return -ENOMEM;
>> +	}
>
> This should be checking using IS_ERR() with fabric, which is a current
> bug in tcm_mod_builder.py

Okay, will fix in both.

> <SNIP>
>
> So for the primary incoming I/O path, you'll want to be using the new
> target_submit_cmd() call that we've been working on in
> lio-core.git/qla_tgt-3.3 recently, as this will simplify incoming I/O +
> exception handling for struct uasp_cmd from processing context usage.

Okay, will look at that.

> Also, do you expect this new driver to pass pre-populated scatterlists,
> or to leave se_cmd->t_data_sg allocation up to target-core..?  Depending
> on the expected usage this will look slightly different from the current
> usage in tcm_loop/tcm_vhost that both pass pre-populated scatterlists
> from Linux/SCSI.

USB has IN and OUT packets. OUT packets are sent by the HOST (received 
by the UDC or device and IN packets are received by the host and ..... 
OUT and IN is always seen / described from HOST's point of view. That 
means USB-OUT packet for the device is "receive-data".
I have to queue an USB-OUT packet for the endpoint that receives the
command. For that I have to allocate memory. That means cdb + sense can
be part of that. For both I don't know the exact size. For cdb I
allocate maxpacket size (that is 512 bytes for high speed and 1024
bytes for super speed) memory and I receive the size, the host sent to
me.
For DATA-IN/OUT transfers I think it would be easier to let the core
allocate the memory. After all I don't know the exact size of the
transfer. We don't have scatterlist support on the gadget framework yet
but Felipe is looking into. So sgl is perfect, will provide a buffer
fallback and people may udpate their drivers if it is too slow :)

> Aside from that, let me know if you have questions while filling in the
> write_pending and response (queue_data_in + queue_status) fabric
> callbacks.

Thanks for that. Once I have something I try to come up with a sane
question :)

> Thanks!
>
> --nab

Sebastian

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2011-12-06  9:19 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-12-04 19:53 [RFC/PATCH v4 1/3] uas: MS UAS Gadget driver - Infrastructure Shimrit Malichi
2011-12-05  8:20 ` [RFC] UASP on target (was: [RFC/PATCH v4 1/3] uas: MS UAS Gadget driver - Infrastructure) Sebastian Andrzej Siewior
2011-12-05  8:23   ` Sebastian Andrzej Siewior
2011-12-05  8:39     ` Felipe Balbi
2011-12-05  8:55       ` [RFC] UASP on target Sebastian Andrzej Siewior
2011-12-05  9:11         ` Felipe Balbi
2011-12-05 12:10           ` Shimrit Malichi
2011-12-05 12:14             ` Felipe Balbi
2011-12-05 16:10     ` [RFC] UASP on target (was: [RFC/PATCH v4 1/3] uas: MS UAS Gadget driver - Infrastructure) Alan Stern
2011-12-05 16:52       ` [RFC] UASP on target Sebastian Andrzej Siewior
2011-12-06  7:40     ` [RFC] UASP on target (was: [RFC/PATCH v4 1/3] uas: MS UAS Gadget driver - Infrastructure) Nicholas A. Bellinger
2011-12-06  9:19       ` [RFC] UASP on target Sebastian Andrzej Siewior

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).