All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2]
@ 2013-06-10 14:05 Dolev Raviv
  2013-06-10 14:05   ` Dolev Raviv
  2013-06-10 14:05   ` Dolev Raviv
  0 siblings, 2 replies; 14+ messages in thread
From: Dolev Raviv @ 2013-06-10 14:05 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-arm-msm, Dolev Raviv

Those patches replace the previous Query Request and NOP patches:
[PATCH 1/8] scsi: ufs: add support for query
[PATCH 7/8] scsi: ufs: Set fDeviceInit flag to initiate device initialization
[PATCH 8/8] scsi: ufs: Fix the response UPIU length setting

And depends on:
[PATCH 2/8] scsi: ufs: wrap the i/o access operations
[PATCH 3/8] scsi: ufs: amend interrupt configuration
[PATCH 4/8] scsi: ufs: remove version check before IS reg clear
[PATCH 5/8] scsi: ufs: rework link start-up process

Sending the query request via the SCSI vendor specific command can cause a deadlock
in case the SCSI command queue is blocked and we would like to send a query request 
(for example fDeviceInit in case of re-initialization).
In addition, usage of a vendor specific SCSI command for UFS can cause future conflicts
if this vendor specific command will be allocated for a different usage.

The below patches allocate an internal tag for NOP and query requests and do not
involve the SCSI layer in UFS specific requests transfers. 
This design also resolves the possible deadlock mentioned above.


Dolev Raviv (1):
  scsi: ufs: Set fDeviceInit flag to initiate device initialization

Sujit Reddy Thumma (1):
  scsi: ufs: Add support for sending NOP OUT UPIU

 drivers/scsi/ufs/ufs.h    |  127 +++++++-
 drivers/scsi/ufs/ufshcd.c |  802 ++++++++++++++++++++++++++++++++++++++------
 drivers/scsi/ufs/ufshcd.h |   40 +++-
 drivers/scsi/ufs/ufshci.h |    2 +-
 4 files changed, 849 insertions(+), 122 deletions(-)

-- 
1.7.6
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

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

* [PATCH 1/2] scsi: ufs: Add support for sending NOP OUT UPIU
  2013-06-10 14:05 [PATCH 0/2] Dolev Raviv
@ 2013-06-10 14:05   ` Dolev Raviv
  2013-06-10 14:05   ` Dolev Raviv
  1 sibling, 0 replies; 14+ messages in thread
From: Dolev Raviv @ 2013-06-10 14:05 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-arm-msm, Sujit Reddy Thumma, Dolev Raviv, open list

From: Sujit Reddy Thumma <sthumma@codeaurora.org>

As part of device initialization sequence, sending NOP OUT UPIU and
waiting for NOP IN UPIU response is mandatory. This confirms that the
device UFS Transport (UTP) layer is functional and the host can configure
the device with further commands. Add support for sending NOP OUT UPIU to
check the device connection path and test whether the UTP layer on the
device side is functional during initialization.

In order to send a UPIU request a UPIU request tag is required. Since
internal request is not scheduled via the block layer, a special tag is
reserved. The reserved tag is the last queuing tag (usually 31). To
avoid collisions with SCSI commands receiving a dynamic allocated tags,
the SCSI command queue depth is shorten by one. In such way the last tag
will never be used by other SCSI commands and will remain available for
internal commands. This design allows us sending maintenance commands
before the queue was initialized or when its blocked. For example
initiating urgent background operations which requires to block all
incoming SCSI requests.

Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org>
Signed-off-by: Dolev Raviv <draviv@codeaurora.org>

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 139bc06..69c0328 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -36,10 +36,16 @@
 #ifndef _UFS_H
 #define _UFS_H
 
+#include <linux/mutex.h>
+#include <linux/types.h>
+
 #define MAX_CDB_SIZE	16
+#define GENERAL_UPIU_REQUEST_SIZE 32
+#define UPIU_HEADER_DATA_SEGMENT_MAX_SIZE	((ALIGNED_UPIU_SIZE) - \
+					(GENERAL_UPIU_REQUEST_SIZE))
 
 #define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
-			((byte3 << 24) | (byte2 << 16) |\
+			cpu_to_be32((byte3 << 24) | (byte2 << 16) |\
 			 (byte1 << 8) | (byte0))
 
 /*
@@ -73,6 +79,7 @@ enum {
 	UPIU_TRANSACTION_TASK_RSP	= 0x24,
 	UPIU_TRANSACTION_READY_XFER	= 0x31,
 	UPIU_TRANSACTION_QUERY_RSP	= 0x36,
+	UPIU_TRANSACTION_REJECT_UPIU	= 0x3F,
 };
 
 /* UPIU Read/Write flags */
@@ -110,6 +117,12 @@ enum {
 	UPIU_COMMAND_SET_TYPE_QUERY	= 0x2,
 };
 
+/* UTP Transfer Request Command Offset */
+#define UPIU_COMMAND_TYPE_OFFSET	28
+
+/* Offset of the response code in the UPIU header */
+#define UPIU_RSP_CODE_OFFSET		8
+
 enum {
 	MASK_SCSI_STATUS	= 0xFF,
 	MASK_TASK_RESPONSE	= 0xFF00,
@@ -138,26 +151,32 @@ struct utp_upiu_header {
 
 /**
  * struct utp_upiu_cmd - Command UPIU structure
- * @header: UPIU header structure DW-0 to DW-2
  * @data_transfer_len: Data Transfer Length DW-3
  * @cdb: Command Descriptor Block CDB DW-4 to DW-7
  */
 struct utp_upiu_cmd {
-	struct utp_upiu_header header;
 	u32 exp_data_transfer_len;
 	u8 cdb[MAX_CDB_SIZE];
 };
 
 /**
- * struct utp_upiu_rsp - Response UPIU structure
- * @header: UPIU header DW-0 to DW-2
+ * struct utp_upiu_req - general upiu request structure
+ * @header:UPIU header structure DW-0 to DW-2
+ * @sc: fields structure for scsi command
+ */
+struct utp_upiu_req {
+	struct utp_upiu_header header;
+	struct utp_upiu_cmd sc;
+};
+
+/**
+ * struct utp_cmd_rsp - Response UPIU structure
  * @residual_transfer_count: Residual transfer count DW-3
  * @reserved: Reserved double words DW-4 to DW-7
  * @sense_data_len: Sense data length DW-8 U16
  * @sense_data: Sense data field DW-8 to DW-12
  */
-struct utp_upiu_rsp {
-	struct utp_upiu_header header;
+struct utp_cmd_rsp {
 	u32 residual_transfer_count;
 	u32 reserved[4];
 	u16 sense_data_len;
@@ -165,6 +184,16 @@ struct utp_upiu_rsp {
 };
 
 /**
+ * struct utp_upiu_rsp - general upiu response structure
+ * @header: UPIU header structure DW-0 to DW-2
+ * @sc: fields structure for scsi command
+ */
+struct utp_upiu_rsp {
+	struct utp_upiu_header header;
+	struct utp_cmd_rsp sc;
+};
+
+/**
  * struct utp_upiu_task_req - Task request UPIU structure
  * @header - UPIU header structure DW0 to DW-2
  * @input_param1: Input parameter 1 DW-3
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 48a7645..d534c50 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -43,6 +43,15 @@
 /* UIC command timeout, unit: ms */
 #define UIC_CMD_TIMEOUT	500
 
+/* NOP OUT retries waiting for NOP IN response */
+#define NOP_OUT_RETRIES    10
+/* Timeout after 30 msecs if NOP OUT hangs without response */
+#define NOP_OUT_TIMEOUT    30 /* msecs */
+
+#define SCSI_CMD_QUEUE_SIZE (hba->nutrs - 1)
+/* Reserved tag for internal commands */
+#define INTERNAL_CMD_TAG   (hba->nutrs - 1)
+
 enum {
 	UFSHCD_MAX_CHANNEL	= 0,
 	UFSHCD_MAX_ID		= 1,
@@ -71,6 +80,41 @@ enum {
 	INT_AGGR_CONFIG,
 };
 
+/*
+ * ufshcd_wait_for_register - wait for register value to change
+ * @hba - per-adapter interface
+ * @reg - mmio register offset
+ * @mask - mask to apply to read register value
+ * @val - wait condition
+ * @interval_us - polling interval in microsecs
+ * @timeout_ms - timeout in millisecs
+ *
+ * Returns final register value after iteration
+ */
+static u32 ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
+		u32 val, unsigned long interval_us, unsigned long timeout_ms)
+{
+	u32 tmp;
+	ktime_t start;
+	unsigned long diff;
+
+	tmp = ufshcd_readl(hba, reg);
+
+	start = ktime_get();
+	while ((tmp & mask) == val) {
+		/* wakeup within 50us of expiry */
+		usleep_range(interval_us, interval_us + 50);
+		tmp = ufshcd_readl(hba, reg);
+		diff = ktime_to_ms(ktime_sub(ktime_get(), start));
+		if (diff > timeout_ms) {
+			tmp = ufshcd_readl(hba, reg);
+			break;
+		}
+	}
+
+	return tmp;
+}
+
 /**
  * ufshcd_get_intr_mask - Get the interrupt bit mask
  * @hba - Pointer to adapter instance
@@ -223,18 +267,13 @@ static inline void ufshcd_free_hba_memory(struct ufs_hba *hba)
 }
 
 /**
- * ufshcd_is_valid_req_rsp - checks if controller TR response is valid
+ * ufshcd_get_req_rsp - returns the TR response
  * @ucd_rsp_ptr: pointer to response UPIU
- *
- * This function checks the response UPIU for valid transaction type in
- * response field
- * Returns 0 on success, non-zero on failure
  */
 static inline int
-ufshcd_is_valid_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr)
+ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr)
 {
-	return ((be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24) ==
-		 UPIU_TRANSACTION_RESPONSE) ? 0 : DID_ERROR << 16;
+	return be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24;
 }
 
 /**
@@ -331,9 +370,9 @@ static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp)
 {
 	int len;
 	if (lrbp->sense_buffer) {
-		len = be16_to_cpu(lrbp->ucd_rsp_ptr->sense_data_len);
+		len = be16_to_cpu(lrbp->ucd_rsp_ptr->sc.sense_data_len);
 		memcpy(lrbp->sense_buffer,
-			lrbp->ucd_rsp_ptr->sense_data,
+			lrbp->ucd_rsp_ptr->sc.sense_data,
 			min_t(int, len, SCSI_SENSE_BUFFERSIZE));
 	}
 }
@@ -551,76 +590,128 @@ static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs)
 }
 
 /**
+ * ufshcd_prepare_req_desc() - Fills the requests header
+ * descriptor according to request
+ * @lrbp: pointer to local reference block
+ * @upiu_flags: flags required in the header
+ * @cmd_dir: requests data direction
+ */
+static void ufshcd_prepare_req_desc(struct ufshcd_lrb *lrbp, u32 *upiu_flags,
+		enum dma_data_direction cmd_dir)
+{
+	struct utp_transfer_req_desc *req_desc = lrbp->utr_descriptor_ptr;
+	u32 data_direction;
+	u32 dword_0;
+
+	if (cmd_dir == DMA_FROM_DEVICE) {
+		data_direction = UTP_DEVICE_TO_HOST;
+		*upiu_flags = UPIU_CMD_FLAGS_READ;
+	} else if (cmd_dir == DMA_TO_DEVICE) {
+		data_direction = UTP_HOST_TO_DEVICE;
+		*upiu_flags = UPIU_CMD_FLAGS_WRITE;
+	} else {
+		data_direction = UTP_NO_DATA_TRANSFER;
+		*upiu_flags = UPIU_CMD_FLAGS_NONE;
+	}
+
+	dword_0 = data_direction | (lrbp->command_type
+				<< UPIU_COMMAND_TYPE_OFFSET);
+	if (lrbp->intr_cmd)
+		dword_0 |= UTP_REQ_DESC_INT_CMD;
+
+	/* Transfer request descriptor header fields */
+	req_desc->header.dword_0 = cpu_to_le32(dword_0);
+
+	/*
+	 * assigning invalid value for command status. Controller
+	 * updates OCS on command completion, with the command
+	 * status
+	 */
+	req_desc->header.dword_2 =
+		cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
+}
+
+/**
+ * ufshcd_prepare_utp_scsi_cmd_upiu() - fills the utp_transfer_req_desc,
+ * for scsi commands
+ * @lrbp - local reference block pointer
+ * @upiu_flags - flags
+ */
+static
+void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u32 upiu_flags)
+{
+	struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
+
+	/* command descriptor fields */
+	ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD(
+				UPIU_TRANSACTION_COMMAND, upiu_flags,
+				lrbp->lun, lrbp->task_tag);
+	ucd_req_ptr->header.dword_1 = UPIU_HEADER_DWORD(
+				UPIU_COMMAND_SET_TYPE_SCSI, 0, 0, 0);
+
+	/* Total EHS length and Data segment length will be zero */
+	ucd_req_ptr->header.dword_2 = 0;
+
+	ucd_req_ptr->sc.exp_data_transfer_len =
+		cpu_to_be32(lrbp->cmd->sdb.length);
+
+	memcpy(ucd_req_ptr->sc.cdb, lrbp->cmd->cmnd,
+		(min_t(unsigned short, lrbp->cmd->cmd_len, MAX_CDB_SIZE)));
+}
+
+static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp)
+{
+	struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
+
+	memset(ucd_req_ptr, 0, sizeof(struct utp_upiu_req));
+
+	/* command descriptor fields */
+	ucd_req_ptr->header.dword_0 =
+		UPIU_HEADER_DWORD(
+			UPIU_TRANSACTION_NOP_OUT, 0, 0, lrbp->task_tag);
+}
+
+/**
  * ufshcd_compose_upiu - form UFS Protocol Information Unit(UPIU)
+ * @hba - per adapter instance
  * @lrb - pointer to local reference block
  */
-static void ufshcd_compose_upiu(struct ufshcd_lrb *lrbp)
+static int ufshcd_compose_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 {
-	struct utp_transfer_req_desc *req_desc;
-	struct utp_upiu_cmd *ucd_cmd_ptr;
-	u32 data_direction;
 	u32 upiu_flags;
-
-	ucd_cmd_ptr = lrbp->ucd_cmd_ptr;
-	req_desc = lrbp->utr_descriptor_ptr;
+	int ret = 0;
 
 	switch (lrbp->command_type) {
 	case UTP_CMD_TYPE_SCSI:
-		if (lrbp->cmd->sc_data_direction == DMA_FROM_DEVICE) {
-			data_direction = UTP_DEVICE_TO_HOST;
-			upiu_flags = UPIU_CMD_FLAGS_READ;
-		} else if (lrbp->cmd->sc_data_direction == DMA_TO_DEVICE) {
-			data_direction = UTP_HOST_TO_DEVICE;
-			upiu_flags = UPIU_CMD_FLAGS_WRITE;
+		if (likely(lrbp->cmd)) {
+			ufshcd_prepare_req_desc(lrbp, &upiu_flags,
+					lrbp->cmd->sc_data_direction);
+			ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags);
 		} else {
-			data_direction = UTP_NO_DATA_TRANSFER;
-			upiu_flags = UPIU_CMD_FLAGS_NONE;
+			ret = -EINVAL;
 		}
-
-		/* Transfer request descriptor header fields */
-		req_desc->header.dword_0 =
-			cpu_to_le32(data_direction | UTP_SCSI_COMMAND);
-
-		/*
-		 * assigning invalid value for command status. Controller
-		 * updates OCS on command completion, with the command
-		 * status
-		 */
-		req_desc->header.dword_2 =
-			cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
-
-		/* command descriptor fields */
-		ucd_cmd_ptr->header.dword_0 =
-			cpu_to_be32(UPIU_HEADER_DWORD(UPIU_TRANSACTION_COMMAND,
-						      upiu_flags,
-						      lrbp->lun,
-						      lrbp->task_tag));
-		ucd_cmd_ptr->header.dword_1 =
-			cpu_to_be32(
-				UPIU_HEADER_DWORD(UPIU_COMMAND_SET_TYPE_SCSI,
-						  0,
-						  0,
-						  0));
-
-		/* Total EHS length and Data segment length will be zero */
-		ucd_cmd_ptr->header.dword_2 = 0;
-
-		ucd_cmd_ptr->exp_data_transfer_len =
-			cpu_to_be32(lrbp->cmd->sdb.length);
-
-		memcpy(ucd_cmd_ptr->cdb,
-		       lrbp->cmd->cmnd,
-		       (min_t(unsigned short,
-			      lrbp->cmd->cmd_len,
-			      MAX_CDB_SIZE)));
 		break;
 	case UTP_CMD_TYPE_DEV_MANAGE:
-		/* For query function implementation */
+		ufshcd_prepare_req_desc(lrbp, &upiu_flags, DMA_NONE);
+		if (hba->i_cmd.dev_cmd_type == DEV_CMD_TYPE_NOP)
+			ufshcd_prepare_utp_nop_upiu(lrbp);
+		else
+			ret = -EINVAL;
 		break;
 	case UTP_CMD_TYPE_UFS:
 		/* For UFS native command implementation */
+		dev_err(hba->dev, "%s: UFS native command are not supported\n",
+			__func__);
+		ret = -ENOTSUPP;
+		break;
+	default:
+		ret = -ENOTSUPP;
+		dev_err(hba->dev, "%s: unknown command type: 0x%x\n",
+				__func__, lrbp->command_type);
 		break;
 	} /* end of switch */
+
+	return ret;
 }
 
 /**
@@ -654,11 +745,11 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
 	lrbp->sense_buffer = cmd->sense_buffer;
 	lrbp->task_tag = tag;
 	lrbp->lun = cmd->device->lun;
-
+	lrbp->intr_cmd = false;
 	lrbp->command_type = UTP_CMD_TYPE_SCSI;
 
 	/* form UPIU before issuing the command */
-	ufshcd_compose_upiu(lrbp);
+	ufshcd_compose_upiu(hba, lrbp);
 	err = ufshcd_map_sg(lrbp);
 	if (err)
 		goto out;
@@ -671,6 +762,139 @@ out:
 	return err;
 }
 
+static int ufshcd_compose_internal_cmd(struct ufs_hba *hba,
+		struct ufshcd_lrb *lrbp, enum internal_cmd_type cmd_type)
+{
+	lrbp->cmd = NULL;
+	lrbp->sense_bufflen = 0;
+	lrbp->sense_buffer = NULL;
+	lrbp->task_tag = INTERNAL_CMD_TAG;
+	lrbp->lun = 0; /* internal cmd is not specific to any LUN */
+	lrbp->command_type = UTP_CMD_TYPE_DEV_MANAGE;
+	lrbp->intr_cmd = true; /* No interrupt aggregation */
+	hba->i_cmd.dev_cmd_type = cmd_type;
+
+	return ufshcd_compose_upiu(hba, lrbp);
+}
+
+static int ufshcd_wait_for_internal_cmd(struct ufs_hba *hba,
+		struct ufshcd_lrb *lrbp, int max_timeout)
+{
+	int err = 0;
+	unsigned long timeout;
+	unsigned long flags;
+
+	timeout = wait_for_completion_timeout(hba->i_cmd.dev_cmd_complete,
+			msecs_to_jiffies(max_timeout));
+
+	spin_lock_irqsave(hba->host->host_lock, flags);
+	hba->i_cmd.dev_cmd_complete = NULL;
+	if (timeout)
+		err = ufshcd_get_tr_ocs(lrbp);
+	else
+		err = -ETIMEDOUT;
+	spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+	return err;
+}
+
+static int
+ufshcd_clear_cmd(struct ufs_hba *hba, int tag)
+{
+	int err = 0;
+	unsigned long flags;
+	u32 reg;
+	u32 mask = 1 << tag;
+
+	/* clear outstanding transaction before retry */
+	spin_lock_irqsave(hba->host->host_lock, flags);
+	ufshcd_utrl_clear(hba, INTERNAL_CMD_TAG);
+	spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+	/* poll for max. 1 sec to clear door bell register by h/w */
+	reg = ufshcd_wait_for_register(hba,
+			REG_UTP_TRANSFER_REQ_DOOR_BELL,
+			mask, mask, 1000, 1000);
+	if ((reg & mask) == mask)
+		err = -ETIMEDOUT;
+
+	return err;
+}
+
+/**
+ * ufshcd_internal_cmd_completion() - handles internal command responses
+ * @hba: per adapter instance
+ * @lrbp: pointer to local reference block
+ */
+static int
+ufshcd_internal_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+{
+	int resp;
+	int err = 0;
+
+	resp = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr);
+
+	switch (resp) {
+	case UPIU_TRANSACTION_NOP_IN:
+		break;
+	case UPIU_TRANSACTION_REJECT_UPIU:
+		/* TODO: handle Reject UPIU Response */
+		dev_err(hba->dev, "Reject UPIU not fully implemented\n");
+		err = -EPERM;
+		break;
+	default:
+		dev_err(hba->dev, "Invalid internal cmd response: %x\n", resp);
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+/**
+ * ufshcd_exec_internal_cmd() - API for sending internal
+ * requests
+ * @hba - UFS hba
+ * @cmd_type - specifies the type (NOP, Query...)
+ * @timeout - time in seconds
+ *
+ * NOTE: There is only one available tag for internal commands. Thus
+ * synchronisation is the responsibilty of the user.
+ */
+static int ufshcd_exec_internal_cmd(struct ufs_hba *hba,
+		enum internal_cmd_type cmd_type, int timeout)
+{
+	struct ufshcd_lrb *lrbp;
+	int err;
+	struct completion wait;
+	unsigned long flags;
+
+	init_completion(&wait);
+	lrbp = &hba->lrb[INTERNAL_CMD_TAG];
+
+	err = ufshcd_compose_internal_cmd(hba, lrbp, cmd_type);
+	if (unlikely(err))
+		goto out;
+
+	hba->i_cmd.dev_cmd_complete = &wait;
+
+	spin_lock_irqsave(hba->host->host_lock, flags);
+	ufshcd_send_command(hba, INTERNAL_CMD_TAG);
+	spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+	err = ufshcd_wait_for_internal_cmd(hba, lrbp, timeout);
+
+	if (err == -ETIMEDOUT) {
+		if (!ufshcd_clear_cmd(hba, INTERNAL_CMD_TAG))
+			err = -EAGAIN;
+	} else if (!err) {
+		err = ufshcd_internal_cmd_completion(hba, lrbp);
+	}
+
+out:
+	return err;
+}
+
 /**
  * ufshcd_memory_alloc - allocate memory for host memory space data structures
  * @hba: per adapter instance
@@ -805,8 +1029,8 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba)
 				cpu_to_le16(ALIGNED_UPIU_SIZE);
 
 		hba->lrb[i].utr_descriptor_ptr = (utrdlp + i);
-		hba->lrb[i].ucd_cmd_ptr =
-			(struct utp_upiu_cmd *)(cmd_descp + i);
+		hba->lrb[i].ucd_req_ptr =
+			(struct utp_upiu_req *)(cmd_descp + i);
 		hba->lrb[i].ucd_rsp_ptr =
 			(struct utp_upiu_rsp *)cmd_descp[i].response_upiu;
 		hba->lrb[i].ucd_prdt_ptr =
@@ -992,6 +1216,38 @@ out:
 }
 
 /**
+ * ufshcd_validate_dev_connection() - Check device connection status
+ * @hba: per-adapter instance
+ *
+ * Send NOP OUT UPIU and wait for NOP IN response to check whether the
+ * device Transport Protocol (UTP) layer is ready after a reset.
+ * If the UTP layer at the device side is not initialized, it may
+ * not respond with NOP IN UPIU within timeout of %NOP_OUT_TIMEOUT
+ * and we retry sending NOP OUT for %NOP_OUT_RETRIES iterations.
+ */
+static int ufshcd_validate_dev_connection(struct ufs_hba *hba)
+{
+	int err = 0;
+	int retries;
+
+	for (retries = NOP_OUT_RETRIES; retries > 0; retries--) {
+		mutex_lock(&hba->i_cmd.dev_cmd_lock);
+		err = ufshcd_exec_internal_cmd(hba, DEV_CMD_TYPE_NOP,
+					       NOP_OUT_TIMEOUT);
+		mutex_unlock(&hba->i_cmd.dev_cmd_lock);
+
+		if (!err || err == -ETIMEDOUT)
+			break;
+
+		dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
+	}
+
+	if (err)
+		dev_err(hba->dev, "%s: NOP OUT failed %d\n", __func__, err);
+	return err;
+}
+
+/**
  * ufshcd_do_reset - reset the host controller
  * @hba: per adapter instance
  *
@@ -1014,16 +1270,22 @@ static int ufshcd_do_reset(struct ufs_hba *hba)
 	spin_unlock_irqrestore(hba->host->host_lock, flags);
 
 	/* abort outstanding commands */
-	for (tag = 0; tag < hba->nutrs; tag++) {
+	for (tag = 0; tag < SCSI_CMD_QUEUE_SIZE; tag++) {
 		if (test_bit(tag, &hba->outstanding_reqs)) {
 			lrbp = &hba->lrb[tag];
-			scsi_dma_unmap(lrbp->cmd);
-			lrbp->cmd->result = DID_RESET << 16;
-			lrbp->cmd->scsi_done(lrbp->cmd);
-			lrbp->cmd = NULL;
+			if (lrbp->cmd) {
+				scsi_dma_unmap(lrbp->cmd);
+				lrbp->cmd->result = DID_RESET << 16;
+				lrbp->cmd->scsi_done(lrbp->cmd);
+				lrbp->cmd = NULL;
+			}
 		}
 	}
 
+	/* complete internal command */
+	if (hba->i_cmd.dev_cmd_complete)
+		complete(hba->i_cmd.dev_cmd_complete);
+
 	/* clear outstanding request/task bit maps */
 	hba->outstanding_reqs = 0;
 	hba->outstanding_tasks = 0;
@@ -1068,7 +1330,7 @@ static int ufshcd_slave_alloc(struct scsi_device *sdev)
 	 * SAM_STAT_TASK_SET_FULL, the LUN queue depth will be adjusted
 	 * with scsi_adjust_queue_depth.
 	 */
-	scsi_activate_tcq(sdev, hba->nutrs);
+	scsi_activate_tcq(sdev, SCSI_CMD_QUEUE_SIZE);
 	return 0;
 }
 
@@ -1081,7 +1343,7 @@ static void ufshcd_slave_destroy(struct scsi_device *sdev)
 	struct ufs_hba *hba;
 
 	hba = shost_priv(sdev->host);
-	scsi_deactivate_tcq(sdev, hba->nutrs);
+	scsi_deactivate_tcq(sdev, SCSI_CMD_QUEUE_SIZE);
 }
 
 /**
@@ -1144,7 +1406,7 @@ static void ufshcd_adjust_lun_qdepth(struct scsi_cmnd *cmd)
 	 * LUN queue depth can be obtained by counting outstanding commands
 	 * on the LUN.
 	 */
-	for (i = 0; i < hba->nutrs; i++) {
+	for (i = 0; i < SCSI_CMD_QUEUE_SIZE; i++) {
 		if (test_bit(i, &hba->outstanding_reqs)) {
 
 			/*
@@ -1230,27 +1492,36 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 
 	switch (ocs) {
 	case OCS_SUCCESS:
-
 		/* check if the returned transfer response is valid */
-		result = ufshcd_is_valid_req_rsp(lrbp->ucd_rsp_ptr);
-		if (result) {
+		result = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr);
+
+		switch (result) {
+		case UPIU_TRANSACTION_RESPONSE:
+			/*
+			 * get the response UPIU result to extract
+			 * the SCSI command status
+			 */
+			result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
+
+			/*
+			 * get the result based on SCSI status response
+			 * to notify the SCSI midlayer of the command status
+			 */
+			scsi_status = result & MASK_SCSI_STATUS;
+			result = ufshcd_scsi_cmd_status(lrbp, scsi_status);
+			break;
+		case UPIU_TRANSACTION_REJECT_UPIU:
+			/* TODO: handle Reject UPIU Response */
+			result = DID_ERROR << 16;
 			dev_err(hba->dev,
-				"Invalid response = %x\n", result);
+				"Reject UPIU not fully implemented\n");
 			break;
+		default:
+			result = DID_ERROR << 16;
+			dev_err(hba->dev,
+				"Unexpected request response code = %x\n",
+				result);
 		}
-
-		/*
-		 * get the response UPIU result to extract
-		 * the SCSI command status
-		 */
-		result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
-
-		/*
-		 * get the result based on SCSI status response
-		 * to notify the SCSI midlayer of the command status
-		 */
-		scsi_status = result & MASK_SCSI_STATUS;
-		result = ufshcd_scsi_cmd_status(lrbp, scsi_status);
 		break;
 	case OCS_ABORTED:
 		result |= DID_ABORT << 16;
@@ -1290,29 +1561,37 @@ static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
  */
 static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
 {
-	struct ufshcd_lrb *lrb;
+	struct ufshcd_lrb *lrbp;
+	struct scsi_cmnd *cmd;
 	unsigned long completed_reqs;
 	u32 tr_doorbell;
 	int result;
 	int index;
+	bool int_aggr_reset = false;
 
-	lrb = hba->lrb;
 	tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
 	completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
 
 	for (index = 0; index < hba->nutrs; index++) {
 		if (test_bit(index, &completed_reqs)) {
+			lrbp = &hba->lrb[index];
+			cmd = lrbp->cmd;
 
-			result = ufshcd_transfer_rsp_status(hba, &lrb[index]);
-
-			if (lrb[index].cmd) {
-				scsi_dma_unmap(lrb[index].cmd);
-				lrb[index].cmd->result = result;
-				lrb[index].cmd->scsi_done(lrb[index].cmd);
+			if (cmd) {
+				result = ufshcd_transfer_rsp_status(hba, lrbp);
+				scsi_dma_unmap(cmd);
+				cmd->result = result;
+				cmd->scsi_done(cmd);
 
 				/* Mark completed command as NULL in LRB */
-				lrb[index].cmd = NULL;
+				lrbp->cmd = NULL;
+			} else if (lrbp->command_type ==
+					UTP_CMD_TYPE_DEV_MANAGE) {
+				if (hba->i_cmd.dev_cmd_complete)
+					complete(hba->i_cmd.dev_cmd_complete);
 			}
+			/* Don't reset counters for interrupt cmd */
+			int_aggr_reset |= !lrbp->intr_cmd;
 		} /* end of if */
 	} /* end of for */
 
@@ -1320,7 +1599,8 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
 	hba->outstanding_reqs ^= completed_reqs;
 
 	/* Reset interrupt aggregation counters */
-	ufshcd_config_int_aggr(hba, INT_AGGR_RESET);
+	if (int_aggr_reset)
+		ufshcd_config_int_aggr(hba, INT_AGGR_RESET);
 }
 
 /**
@@ -1463,10 +1743,10 @@ ufshcd_issue_tm_cmd(struct ufs_hba *hba,
 	task_req_upiup =
 		(struct utp_upiu_task_req *) task_req_descp->task_req_upiu;
 	task_req_upiup->header.dword_0 =
-		cpu_to_be32(UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, 0,
-					      lrbp->lun, lrbp->task_tag));
+		UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, 0,
+					      lrbp->lun, lrbp->task_tag);
 	task_req_upiup->header.dword_1 =
-	cpu_to_be32(UPIU_HEADER_DWORD(0, tm_function, 0, 0));
+		UPIU_HEADER_DWORD(0, tm_function, 0, 0);
 
 	task_req_upiup->input_param1 = lrbp->lun;
 	task_req_upiup->input_param1 =
@@ -1521,7 +1801,7 @@ static int ufshcd_device_reset(struct scsi_cmnd *cmd)
 	if (err == FAILED)
 		goto out;
 
-	for (pos = 0; pos < hba->nutrs; pos++) {
+	for (pos = 0; pos < SCSI_CMD_QUEUE_SIZE; pos++) {
 		if (test_bit(pos, &hba->outstanding_reqs) &&
 		    (hba->lrb[tag].lun == hba->lrb[pos].lun)) {
 
@@ -1539,6 +1819,11 @@ static int ufshcd_device_reset(struct scsi_cmnd *cmd)
 			}
 		}
 	} /* end of for */
+
+	/* complete internal command */
+	if (hba->i_cmd.dev_cmd_complete)
+		complete(hba->i_cmd.dev_cmd_complete);
+
 out:
 	return err;
 }
@@ -1618,8 +1903,16 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)
 	int ret;
 
 	ret = ufshcd_link_startup(hba);
-	if (!ret)
-		scsi_scan_host(hba->host);
+	if (ret)
+		goto out;
+
+	ret = ufshcd_validate_dev_connection(hba);
+	if (ret)
+		goto out;
+
+	scsi_scan_host(hba->host);
+out:
+	return;
 }
 
 static struct scsi_host_template ufshcd_driver_template = {
@@ -1771,8 +2064,8 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
 	/* Configure LRB */
 	ufshcd_host_memory_configure(hba);
 
-	host->can_queue = hba->nutrs;
-	host->cmd_per_lun = hba->nutrs;
+	host->can_queue = SCSI_CMD_QUEUE_SIZE;
+	host->cmd_per_lun = SCSI_CMD_QUEUE_SIZE;
 	host->max_id = UFSHCD_MAX_ID;
 	host->max_lun = UFSHCD_MAX_LUNS;
 	host->max_channel = UFSHCD_MAX_CHANNEL;
@@ -1788,6 +2081,9 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
 	/* Initialize UIC command mutex */
 	mutex_init(&hba->uic_cmd_mutex);
 
+	/* Initialize mutex for internal commands */
+	mutex_init(&hba->i_cmd.dev_cmd_lock);
+
 	/* IRQ registration */
 	err = request_irq(irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
 	if (err) {
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 49590ee..e41fa5e 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -68,6 +68,10 @@
 #define UFSHCD "ufshcd"
 #define UFSHCD_DRIVER_VERSION "0.2"
 
+enum internal_cmd_type {
+	DEV_CMD_TYPE_NOP		= 0x0,
+};
+
 /**
  * struct uic_command - UIC command structure
  * @command: UIC command
@@ -91,7 +95,7 @@ struct uic_command {
 /**
  * struct ufshcd_lrb - local reference block
  * @utr_descriptor_ptr: UTRD address of the command
- * @ucd_cmd_ptr: UCD address of the command
+ * @ucd_req_ptr: UCD address of the command
  * @ucd_rsp_ptr: Response UPIU address for this command
  * @ucd_prdt_ptr: PRDT address of the command
  * @cmd: pointer to SCSI command
@@ -101,10 +105,11 @@ struct uic_command {
  * @command_type: SCSI, UFS, Query.
  * @task_tag: Task tag of the command
  * @lun: LUN of the command
+ * @intr_cmd: Interrupt command (doesn't participate in interrupt aggregation)
  */
 struct ufshcd_lrb {
 	struct utp_transfer_req_desc *utr_descriptor_ptr;
-	struct utp_upiu_cmd *ucd_cmd_ptr;
+	struct utp_upiu_req *ucd_req_ptr;
 	struct utp_upiu_rsp *ucd_rsp_ptr;
 	struct ufshcd_sg_entry *ucd_prdt_ptr;
 
@@ -116,8 +121,20 @@ struct ufshcd_lrb {
 	int command_type;
 	int task_tag;
 	unsigned int lun;
+	bool intr_cmd;
 };
 
+/**
+ * struct ufs_internal_cmd - all assosiated fields with internal commands
+ * @dev_cmd_type: device management command type - Query, NOP OUT
+ * @dev_cmd_lock: lock to allow one internal command at a time
+ * @dev_cmd_complete: internal commands completion
+ */
+struct ufs_internal_cmd {
+	enum internal_cmd_type dev_cmd_type;
+	struct mutex dev_cmd_lock;
+	struct completion *dev_cmd_complete;
+};
 
 /**
  * struct ufs_hba - per adapter private structure
@@ -146,6 +163,7 @@ struct ufshcd_lrb {
  * @intr_mask: Interrupt Mask Bits
  * @feh_workq: Work queue for fatal controller error handling
  * @errors: HBA errors
+ * @i_cmd: ufs internal command information
  */
 struct ufs_hba {
 	void __iomem *mmio_base;
@@ -188,6 +206,9 @@ struct ufs_hba {
 
 	/* HBA Errors */
 	u32 errors;
+
+	/* Internal Request data */
+	struct ufs_internal_cmd i_cmd;
 };
 
 #define ufshcd_writel(hba, val, reg)	\
-- 
1.7.6
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

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

* [PATCH 1/2] scsi: ufs: Add support for sending NOP OUT UPIU
@ 2013-06-10 14:05   ` Dolev Raviv
  0 siblings, 0 replies; 14+ messages in thread
From: Dolev Raviv @ 2013-06-10 14:05 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-arm-msm, Sujit Reddy Thumma, Dolev Raviv, open list

From: Sujit Reddy Thumma <sthumma@codeaurora.org>

As part of device initialization sequence, sending NOP OUT UPIU and
waiting for NOP IN UPIU response is mandatory. This confirms that the
device UFS Transport (UTP) layer is functional and the host can configure
the device with further commands. Add support for sending NOP OUT UPIU to
check the device connection path and test whether the UTP layer on the
device side is functional during initialization.

In order to send a UPIU request a UPIU request tag is required. Since
internal request is not scheduled via the block layer, a special tag is
reserved. The reserved tag is the last queuing tag (usually 31). To
avoid collisions with SCSI commands receiving a dynamic allocated tags,
the SCSI command queue depth is shorten by one. In such way the last tag
will never be used by other SCSI commands and will remain available for
internal commands. This design allows us sending maintenance commands
before the queue was initialized or when its blocked. For example
initiating urgent background operations which requires to block all
incoming SCSI requests.

Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org>
Signed-off-by: Dolev Raviv <draviv@codeaurora.org>

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 139bc06..69c0328 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -36,10 +36,16 @@
 #ifndef _UFS_H
 #define _UFS_H
 
+#include <linux/mutex.h>
+#include <linux/types.h>
+
 #define MAX_CDB_SIZE	16
+#define GENERAL_UPIU_REQUEST_SIZE 32
+#define UPIU_HEADER_DATA_SEGMENT_MAX_SIZE	((ALIGNED_UPIU_SIZE) - \
+					(GENERAL_UPIU_REQUEST_SIZE))
 
 #define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
-			((byte3 << 24) | (byte2 << 16) |\
+			cpu_to_be32((byte3 << 24) | (byte2 << 16) |\
 			 (byte1 << 8) | (byte0))
 
 /*
@@ -73,6 +79,7 @@ enum {
 	UPIU_TRANSACTION_TASK_RSP	= 0x24,
 	UPIU_TRANSACTION_READY_XFER	= 0x31,
 	UPIU_TRANSACTION_QUERY_RSP	= 0x36,
+	UPIU_TRANSACTION_REJECT_UPIU	= 0x3F,
 };
 
 /* UPIU Read/Write flags */
@@ -110,6 +117,12 @@ enum {
 	UPIU_COMMAND_SET_TYPE_QUERY	= 0x2,
 };
 
+/* UTP Transfer Request Command Offset */
+#define UPIU_COMMAND_TYPE_OFFSET	28
+
+/* Offset of the response code in the UPIU header */
+#define UPIU_RSP_CODE_OFFSET		8
+
 enum {
 	MASK_SCSI_STATUS	= 0xFF,
 	MASK_TASK_RESPONSE	= 0xFF00,
@@ -138,26 +151,32 @@ struct utp_upiu_header {
 
 /**
  * struct utp_upiu_cmd - Command UPIU structure
- * @header: UPIU header structure DW-0 to DW-2
  * @data_transfer_len: Data Transfer Length DW-3
  * @cdb: Command Descriptor Block CDB DW-4 to DW-7
  */
 struct utp_upiu_cmd {
-	struct utp_upiu_header header;
 	u32 exp_data_transfer_len;
 	u8 cdb[MAX_CDB_SIZE];
 };
 
 /**
- * struct utp_upiu_rsp - Response UPIU structure
- * @header: UPIU header DW-0 to DW-2
+ * struct utp_upiu_req - general upiu request structure
+ * @header:UPIU header structure DW-0 to DW-2
+ * @sc: fields structure for scsi command
+ */
+struct utp_upiu_req {
+	struct utp_upiu_header header;
+	struct utp_upiu_cmd sc;
+};
+
+/**
+ * struct utp_cmd_rsp - Response UPIU structure
  * @residual_transfer_count: Residual transfer count DW-3
  * @reserved: Reserved double words DW-4 to DW-7
  * @sense_data_len: Sense data length DW-8 U16
  * @sense_data: Sense data field DW-8 to DW-12
  */
-struct utp_upiu_rsp {
-	struct utp_upiu_header header;
+struct utp_cmd_rsp {
 	u32 residual_transfer_count;
 	u32 reserved[4];
 	u16 sense_data_len;
@@ -165,6 +184,16 @@ struct utp_upiu_rsp {
 };
 
 /**
+ * struct utp_upiu_rsp - general upiu response structure
+ * @header: UPIU header structure DW-0 to DW-2
+ * @sc: fields structure for scsi command
+ */
+struct utp_upiu_rsp {
+	struct utp_upiu_header header;
+	struct utp_cmd_rsp sc;
+};
+
+/**
  * struct utp_upiu_task_req - Task request UPIU structure
  * @header - UPIU header structure DW0 to DW-2
  * @input_param1: Input parameter 1 DW-3
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 48a7645..d534c50 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -43,6 +43,15 @@
 /* UIC command timeout, unit: ms */
 #define UIC_CMD_TIMEOUT	500
 
+/* NOP OUT retries waiting for NOP IN response */
+#define NOP_OUT_RETRIES    10
+/* Timeout after 30 msecs if NOP OUT hangs without response */
+#define NOP_OUT_TIMEOUT    30 /* msecs */
+
+#define SCSI_CMD_QUEUE_SIZE (hba->nutrs - 1)
+/* Reserved tag for internal commands */
+#define INTERNAL_CMD_TAG   (hba->nutrs - 1)
+
 enum {
 	UFSHCD_MAX_CHANNEL	= 0,
 	UFSHCD_MAX_ID		= 1,
@@ -71,6 +80,41 @@ enum {
 	INT_AGGR_CONFIG,
 };
 
+/*
+ * ufshcd_wait_for_register - wait for register value to change
+ * @hba - per-adapter interface
+ * @reg - mmio register offset
+ * @mask - mask to apply to read register value
+ * @val - wait condition
+ * @interval_us - polling interval in microsecs
+ * @timeout_ms - timeout in millisecs
+ *
+ * Returns final register value after iteration
+ */
+static u32 ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
+		u32 val, unsigned long interval_us, unsigned long timeout_ms)
+{
+	u32 tmp;
+	ktime_t start;
+	unsigned long diff;
+
+	tmp = ufshcd_readl(hba, reg);
+
+	start = ktime_get();
+	while ((tmp & mask) == val) {
+		/* wakeup within 50us of expiry */
+		usleep_range(interval_us, interval_us + 50);
+		tmp = ufshcd_readl(hba, reg);
+		diff = ktime_to_ms(ktime_sub(ktime_get(), start));
+		if (diff > timeout_ms) {
+			tmp = ufshcd_readl(hba, reg);
+			break;
+		}
+	}
+
+	return tmp;
+}
+
 /**
  * ufshcd_get_intr_mask - Get the interrupt bit mask
  * @hba - Pointer to adapter instance
@@ -223,18 +267,13 @@ static inline void ufshcd_free_hba_memory(struct ufs_hba *hba)
 }
 
 /**
- * ufshcd_is_valid_req_rsp - checks if controller TR response is valid
+ * ufshcd_get_req_rsp - returns the TR response
  * @ucd_rsp_ptr: pointer to response UPIU
- *
- * This function checks the response UPIU for valid transaction type in
- * response field
- * Returns 0 on success, non-zero on failure
  */
 static inline int
-ufshcd_is_valid_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr)
+ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr)
 {
-	return ((be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24) ==
-		 UPIU_TRANSACTION_RESPONSE) ? 0 : DID_ERROR << 16;
+	return be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24;
 }
 
 /**
@@ -331,9 +370,9 @@ static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp)
 {
 	int len;
 	if (lrbp->sense_buffer) {
-		len = be16_to_cpu(lrbp->ucd_rsp_ptr->sense_data_len);
+		len = be16_to_cpu(lrbp->ucd_rsp_ptr->sc.sense_data_len);
 		memcpy(lrbp->sense_buffer,
-			lrbp->ucd_rsp_ptr->sense_data,
+			lrbp->ucd_rsp_ptr->sc.sense_data,
 			min_t(int, len, SCSI_SENSE_BUFFERSIZE));
 	}
 }
@@ -551,76 +590,128 @@ static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs)
 }
 
 /**
+ * ufshcd_prepare_req_desc() - Fills the requests header
+ * descriptor according to request
+ * @lrbp: pointer to local reference block
+ * @upiu_flags: flags required in the header
+ * @cmd_dir: requests data direction
+ */
+static void ufshcd_prepare_req_desc(struct ufshcd_lrb *lrbp, u32 *upiu_flags,
+		enum dma_data_direction cmd_dir)
+{
+	struct utp_transfer_req_desc *req_desc = lrbp->utr_descriptor_ptr;
+	u32 data_direction;
+	u32 dword_0;
+
+	if (cmd_dir == DMA_FROM_DEVICE) {
+		data_direction = UTP_DEVICE_TO_HOST;
+		*upiu_flags = UPIU_CMD_FLAGS_READ;
+	} else if (cmd_dir == DMA_TO_DEVICE) {
+		data_direction = UTP_HOST_TO_DEVICE;
+		*upiu_flags = UPIU_CMD_FLAGS_WRITE;
+	} else {
+		data_direction = UTP_NO_DATA_TRANSFER;
+		*upiu_flags = UPIU_CMD_FLAGS_NONE;
+	}
+
+	dword_0 = data_direction | (lrbp->command_type
+				<< UPIU_COMMAND_TYPE_OFFSET);
+	if (lrbp->intr_cmd)
+		dword_0 |= UTP_REQ_DESC_INT_CMD;
+
+	/* Transfer request descriptor header fields */
+	req_desc->header.dword_0 = cpu_to_le32(dword_0);
+
+	/*
+	 * assigning invalid value for command status. Controller
+	 * updates OCS on command completion, with the command
+	 * status
+	 */
+	req_desc->header.dword_2 =
+		cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
+}
+
+/**
+ * ufshcd_prepare_utp_scsi_cmd_upiu() - fills the utp_transfer_req_desc,
+ * for scsi commands
+ * @lrbp - local reference block pointer
+ * @upiu_flags - flags
+ */
+static
+void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u32 upiu_flags)
+{
+	struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
+
+	/* command descriptor fields */
+	ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD(
+				UPIU_TRANSACTION_COMMAND, upiu_flags,
+				lrbp->lun, lrbp->task_tag);
+	ucd_req_ptr->header.dword_1 = UPIU_HEADER_DWORD(
+				UPIU_COMMAND_SET_TYPE_SCSI, 0, 0, 0);
+
+	/* Total EHS length and Data segment length will be zero */
+	ucd_req_ptr->header.dword_2 = 0;
+
+	ucd_req_ptr->sc.exp_data_transfer_len =
+		cpu_to_be32(lrbp->cmd->sdb.length);
+
+	memcpy(ucd_req_ptr->sc.cdb, lrbp->cmd->cmnd,
+		(min_t(unsigned short, lrbp->cmd->cmd_len, MAX_CDB_SIZE)));
+}
+
+static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp)
+{
+	struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
+
+	memset(ucd_req_ptr, 0, sizeof(struct utp_upiu_req));
+
+	/* command descriptor fields */
+	ucd_req_ptr->header.dword_0 =
+		UPIU_HEADER_DWORD(
+			UPIU_TRANSACTION_NOP_OUT, 0, 0, lrbp->task_tag);
+}
+
+/**
  * ufshcd_compose_upiu - form UFS Protocol Information Unit(UPIU)
+ * @hba - per adapter instance
  * @lrb - pointer to local reference block
  */
-static void ufshcd_compose_upiu(struct ufshcd_lrb *lrbp)
+static int ufshcd_compose_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 {
-	struct utp_transfer_req_desc *req_desc;
-	struct utp_upiu_cmd *ucd_cmd_ptr;
-	u32 data_direction;
 	u32 upiu_flags;
-
-	ucd_cmd_ptr = lrbp->ucd_cmd_ptr;
-	req_desc = lrbp->utr_descriptor_ptr;
+	int ret = 0;
 
 	switch (lrbp->command_type) {
 	case UTP_CMD_TYPE_SCSI:
-		if (lrbp->cmd->sc_data_direction == DMA_FROM_DEVICE) {
-			data_direction = UTP_DEVICE_TO_HOST;
-			upiu_flags = UPIU_CMD_FLAGS_READ;
-		} else if (lrbp->cmd->sc_data_direction == DMA_TO_DEVICE) {
-			data_direction = UTP_HOST_TO_DEVICE;
-			upiu_flags = UPIU_CMD_FLAGS_WRITE;
+		if (likely(lrbp->cmd)) {
+			ufshcd_prepare_req_desc(lrbp, &upiu_flags,
+					lrbp->cmd->sc_data_direction);
+			ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags);
 		} else {
-			data_direction = UTP_NO_DATA_TRANSFER;
-			upiu_flags = UPIU_CMD_FLAGS_NONE;
+			ret = -EINVAL;
 		}
-
-		/* Transfer request descriptor header fields */
-		req_desc->header.dword_0 =
-			cpu_to_le32(data_direction | UTP_SCSI_COMMAND);
-
-		/*
-		 * assigning invalid value for command status. Controller
-		 * updates OCS on command completion, with the command
-		 * status
-		 */
-		req_desc->header.dword_2 =
-			cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
-
-		/* command descriptor fields */
-		ucd_cmd_ptr->header.dword_0 =
-			cpu_to_be32(UPIU_HEADER_DWORD(UPIU_TRANSACTION_COMMAND,
-						      upiu_flags,
-						      lrbp->lun,
-						      lrbp->task_tag));
-		ucd_cmd_ptr->header.dword_1 =
-			cpu_to_be32(
-				UPIU_HEADER_DWORD(UPIU_COMMAND_SET_TYPE_SCSI,
-						  0,
-						  0,
-						  0));
-
-		/* Total EHS length and Data segment length will be zero */
-		ucd_cmd_ptr->header.dword_2 = 0;
-
-		ucd_cmd_ptr->exp_data_transfer_len =
-			cpu_to_be32(lrbp->cmd->sdb.length);
-
-		memcpy(ucd_cmd_ptr->cdb,
-		       lrbp->cmd->cmnd,
-		       (min_t(unsigned short,
-			      lrbp->cmd->cmd_len,
-			      MAX_CDB_SIZE)));
 		break;
 	case UTP_CMD_TYPE_DEV_MANAGE:
-		/* For query function implementation */
+		ufshcd_prepare_req_desc(lrbp, &upiu_flags, DMA_NONE);
+		if (hba->i_cmd.dev_cmd_type == DEV_CMD_TYPE_NOP)
+			ufshcd_prepare_utp_nop_upiu(lrbp);
+		else
+			ret = -EINVAL;
 		break;
 	case UTP_CMD_TYPE_UFS:
 		/* For UFS native command implementation */
+		dev_err(hba->dev, "%s: UFS native command are not supported\n",
+			__func__);
+		ret = -ENOTSUPP;
+		break;
+	default:
+		ret = -ENOTSUPP;
+		dev_err(hba->dev, "%s: unknown command type: 0x%x\n",
+				__func__, lrbp->command_type);
 		break;
 	} /* end of switch */
+
+	return ret;
 }
 
 /**
@@ -654,11 +745,11 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
 	lrbp->sense_buffer = cmd->sense_buffer;
 	lrbp->task_tag = tag;
 	lrbp->lun = cmd->device->lun;
-
+	lrbp->intr_cmd = false;
 	lrbp->command_type = UTP_CMD_TYPE_SCSI;
 
 	/* form UPIU before issuing the command */
-	ufshcd_compose_upiu(lrbp);
+	ufshcd_compose_upiu(hba, lrbp);
 	err = ufshcd_map_sg(lrbp);
 	if (err)
 		goto out;
@@ -671,6 +762,139 @@ out:
 	return err;
 }
 
+static int ufshcd_compose_internal_cmd(struct ufs_hba *hba,
+		struct ufshcd_lrb *lrbp, enum internal_cmd_type cmd_type)
+{
+	lrbp->cmd = NULL;
+	lrbp->sense_bufflen = 0;
+	lrbp->sense_buffer = NULL;
+	lrbp->task_tag = INTERNAL_CMD_TAG;
+	lrbp->lun = 0; /* internal cmd is not specific to any LUN */
+	lrbp->command_type = UTP_CMD_TYPE_DEV_MANAGE;
+	lrbp->intr_cmd = true; /* No interrupt aggregation */
+	hba->i_cmd.dev_cmd_type = cmd_type;
+
+	return ufshcd_compose_upiu(hba, lrbp);
+}
+
+static int ufshcd_wait_for_internal_cmd(struct ufs_hba *hba,
+		struct ufshcd_lrb *lrbp, int max_timeout)
+{
+	int err = 0;
+	unsigned long timeout;
+	unsigned long flags;
+
+	timeout = wait_for_completion_timeout(hba->i_cmd.dev_cmd_complete,
+			msecs_to_jiffies(max_timeout));
+
+	spin_lock_irqsave(hba->host->host_lock, flags);
+	hba->i_cmd.dev_cmd_complete = NULL;
+	if (timeout)
+		err = ufshcd_get_tr_ocs(lrbp);
+	else
+		err = -ETIMEDOUT;
+	spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+	return err;
+}
+
+static int
+ufshcd_clear_cmd(struct ufs_hba *hba, int tag)
+{
+	int err = 0;
+	unsigned long flags;
+	u32 reg;
+	u32 mask = 1 << tag;
+
+	/* clear outstanding transaction before retry */
+	spin_lock_irqsave(hba->host->host_lock, flags);
+	ufshcd_utrl_clear(hba, INTERNAL_CMD_TAG);
+	spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+	/* poll for max. 1 sec to clear door bell register by h/w */
+	reg = ufshcd_wait_for_register(hba,
+			REG_UTP_TRANSFER_REQ_DOOR_BELL,
+			mask, mask, 1000, 1000);
+	if ((reg & mask) == mask)
+		err = -ETIMEDOUT;
+
+	return err;
+}
+
+/**
+ * ufshcd_internal_cmd_completion() - handles internal command responses
+ * @hba: per adapter instance
+ * @lrbp: pointer to local reference block
+ */
+static int
+ufshcd_internal_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+{
+	int resp;
+	int err = 0;
+
+	resp = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr);
+
+	switch (resp) {
+	case UPIU_TRANSACTION_NOP_IN:
+		break;
+	case UPIU_TRANSACTION_REJECT_UPIU:
+		/* TODO: handle Reject UPIU Response */
+		dev_err(hba->dev, "Reject UPIU not fully implemented\n");
+		err = -EPERM;
+		break;
+	default:
+		dev_err(hba->dev, "Invalid internal cmd response: %x\n", resp);
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+/**
+ * ufshcd_exec_internal_cmd() - API for sending internal
+ * requests
+ * @hba - UFS hba
+ * @cmd_type - specifies the type (NOP, Query...)
+ * @timeout - time in seconds
+ *
+ * NOTE: There is only one available tag for internal commands. Thus
+ * synchronisation is the responsibilty of the user.
+ */
+static int ufshcd_exec_internal_cmd(struct ufs_hba *hba,
+		enum internal_cmd_type cmd_type, int timeout)
+{
+	struct ufshcd_lrb *lrbp;
+	int err;
+	struct completion wait;
+	unsigned long flags;
+
+	init_completion(&wait);
+	lrbp = &hba->lrb[INTERNAL_CMD_TAG];
+
+	err = ufshcd_compose_internal_cmd(hba, lrbp, cmd_type);
+	if (unlikely(err))
+		goto out;
+
+	hba->i_cmd.dev_cmd_complete = &wait;
+
+	spin_lock_irqsave(hba->host->host_lock, flags);
+	ufshcd_send_command(hba, INTERNAL_CMD_TAG);
+	spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+	err = ufshcd_wait_for_internal_cmd(hba, lrbp, timeout);
+
+	if (err == -ETIMEDOUT) {
+		if (!ufshcd_clear_cmd(hba, INTERNAL_CMD_TAG))
+			err = -EAGAIN;
+	} else if (!err) {
+		err = ufshcd_internal_cmd_completion(hba, lrbp);
+	}
+
+out:
+	return err;
+}
+
 /**
  * ufshcd_memory_alloc - allocate memory for host memory space data structures
  * @hba: per adapter instance
@@ -805,8 +1029,8 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba)
 				cpu_to_le16(ALIGNED_UPIU_SIZE);
 
 		hba->lrb[i].utr_descriptor_ptr = (utrdlp + i);
-		hba->lrb[i].ucd_cmd_ptr =
-			(struct utp_upiu_cmd *)(cmd_descp + i);
+		hba->lrb[i].ucd_req_ptr =
+			(struct utp_upiu_req *)(cmd_descp + i);
 		hba->lrb[i].ucd_rsp_ptr =
 			(struct utp_upiu_rsp *)cmd_descp[i].response_upiu;
 		hba->lrb[i].ucd_prdt_ptr =
@@ -992,6 +1216,38 @@ out:
 }
 
 /**
+ * ufshcd_validate_dev_connection() - Check device connection status
+ * @hba: per-adapter instance
+ *
+ * Send NOP OUT UPIU and wait for NOP IN response to check whether the
+ * device Transport Protocol (UTP) layer is ready after a reset.
+ * If the UTP layer at the device side is not initialized, it may
+ * not respond with NOP IN UPIU within timeout of %NOP_OUT_TIMEOUT
+ * and we retry sending NOP OUT for %NOP_OUT_RETRIES iterations.
+ */
+static int ufshcd_validate_dev_connection(struct ufs_hba *hba)
+{
+	int err = 0;
+	int retries;
+
+	for (retries = NOP_OUT_RETRIES; retries > 0; retries--) {
+		mutex_lock(&hba->i_cmd.dev_cmd_lock);
+		err = ufshcd_exec_internal_cmd(hba, DEV_CMD_TYPE_NOP,
+					       NOP_OUT_TIMEOUT);
+		mutex_unlock(&hba->i_cmd.dev_cmd_lock);
+
+		if (!err || err == -ETIMEDOUT)
+			break;
+
+		dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
+	}
+
+	if (err)
+		dev_err(hba->dev, "%s: NOP OUT failed %d\n", __func__, err);
+	return err;
+}
+
+/**
  * ufshcd_do_reset - reset the host controller
  * @hba: per adapter instance
  *
@@ -1014,16 +1270,22 @@ static int ufshcd_do_reset(struct ufs_hba *hba)
 	spin_unlock_irqrestore(hba->host->host_lock, flags);
 
 	/* abort outstanding commands */
-	for (tag = 0; tag < hba->nutrs; tag++) {
+	for (tag = 0; tag < SCSI_CMD_QUEUE_SIZE; tag++) {
 		if (test_bit(tag, &hba->outstanding_reqs)) {
 			lrbp = &hba->lrb[tag];
-			scsi_dma_unmap(lrbp->cmd);
-			lrbp->cmd->result = DID_RESET << 16;
-			lrbp->cmd->scsi_done(lrbp->cmd);
-			lrbp->cmd = NULL;
+			if (lrbp->cmd) {
+				scsi_dma_unmap(lrbp->cmd);
+				lrbp->cmd->result = DID_RESET << 16;
+				lrbp->cmd->scsi_done(lrbp->cmd);
+				lrbp->cmd = NULL;
+			}
 		}
 	}
 
+	/* complete internal command */
+	if (hba->i_cmd.dev_cmd_complete)
+		complete(hba->i_cmd.dev_cmd_complete);
+
 	/* clear outstanding request/task bit maps */
 	hba->outstanding_reqs = 0;
 	hba->outstanding_tasks = 0;
@@ -1068,7 +1330,7 @@ static int ufshcd_slave_alloc(struct scsi_device *sdev)
 	 * SAM_STAT_TASK_SET_FULL, the LUN queue depth will be adjusted
 	 * with scsi_adjust_queue_depth.
 	 */
-	scsi_activate_tcq(sdev, hba->nutrs);
+	scsi_activate_tcq(sdev, SCSI_CMD_QUEUE_SIZE);
 	return 0;
 }
 
@@ -1081,7 +1343,7 @@ static void ufshcd_slave_destroy(struct scsi_device *sdev)
 	struct ufs_hba *hba;
 
 	hba = shost_priv(sdev->host);
-	scsi_deactivate_tcq(sdev, hba->nutrs);
+	scsi_deactivate_tcq(sdev, SCSI_CMD_QUEUE_SIZE);
 }
 
 /**
@@ -1144,7 +1406,7 @@ static void ufshcd_adjust_lun_qdepth(struct scsi_cmnd *cmd)
 	 * LUN queue depth can be obtained by counting outstanding commands
 	 * on the LUN.
 	 */
-	for (i = 0; i < hba->nutrs; i++) {
+	for (i = 0; i < SCSI_CMD_QUEUE_SIZE; i++) {
 		if (test_bit(i, &hba->outstanding_reqs)) {
 
 			/*
@@ -1230,27 +1492,36 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 
 	switch (ocs) {
 	case OCS_SUCCESS:
-
 		/* check if the returned transfer response is valid */
-		result = ufshcd_is_valid_req_rsp(lrbp->ucd_rsp_ptr);
-		if (result) {
+		result = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr);
+
+		switch (result) {
+		case UPIU_TRANSACTION_RESPONSE:
+			/*
+			 * get the response UPIU result to extract
+			 * the SCSI command status
+			 */
+			result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
+
+			/*
+			 * get the result based on SCSI status response
+			 * to notify the SCSI midlayer of the command status
+			 */
+			scsi_status = result & MASK_SCSI_STATUS;
+			result = ufshcd_scsi_cmd_status(lrbp, scsi_status);
+			break;
+		case UPIU_TRANSACTION_REJECT_UPIU:
+			/* TODO: handle Reject UPIU Response */
+			result = DID_ERROR << 16;
 			dev_err(hba->dev,
-				"Invalid response = %x\n", result);
+				"Reject UPIU not fully implemented\n");
 			break;
+		default:
+			result = DID_ERROR << 16;
+			dev_err(hba->dev,
+				"Unexpected request response code = %x\n",
+				result);
 		}
-
-		/*
-		 * get the response UPIU result to extract
-		 * the SCSI command status
-		 */
-		result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
-
-		/*
-		 * get the result based on SCSI status response
-		 * to notify the SCSI midlayer of the command status
-		 */
-		scsi_status = result & MASK_SCSI_STATUS;
-		result = ufshcd_scsi_cmd_status(lrbp, scsi_status);
 		break;
 	case OCS_ABORTED:
 		result |= DID_ABORT << 16;
@@ -1290,29 +1561,37 @@ static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
  */
 static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
 {
-	struct ufshcd_lrb *lrb;
+	struct ufshcd_lrb *lrbp;
+	struct scsi_cmnd *cmd;
 	unsigned long completed_reqs;
 	u32 tr_doorbell;
 	int result;
 	int index;
+	bool int_aggr_reset = false;
 
-	lrb = hba->lrb;
 	tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
 	completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
 
 	for (index = 0; index < hba->nutrs; index++) {
 		if (test_bit(index, &completed_reqs)) {
+			lrbp = &hba->lrb[index];
+			cmd = lrbp->cmd;
 
-			result = ufshcd_transfer_rsp_status(hba, &lrb[index]);
-
-			if (lrb[index].cmd) {
-				scsi_dma_unmap(lrb[index].cmd);
-				lrb[index].cmd->result = result;
-				lrb[index].cmd->scsi_done(lrb[index].cmd);
+			if (cmd) {
+				result = ufshcd_transfer_rsp_status(hba, lrbp);
+				scsi_dma_unmap(cmd);
+				cmd->result = result;
+				cmd->scsi_done(cmd);
 
 				/* Mark completed command as NULL in LRB */
-				lrb[index].cmd = NULL;
+				lrbp->cmd = NULL;
+			} else if (lrbp->command_type ==
+					UTP_CMD_TYPE_DEV_MANAGE) {
+				if (hba->i_cmd.dev_cmd_complete)
+					complete(hba->i_cmd.dev_cmd_complete);
 			}
+			/* Don't reset counters for interrupt cmd */
+			int_aggr_reset |= !lrbp->intr_cmd;
 		} /* end of if */
 	} /* end of for */
 
@@ -1320,7 +1599,8 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
 	hba->outstanding_reqs ^= completed_reqs;
 
 	/* Reset interrupt aggregation counters */
-	ufshcd_config_int_aggr(hba, INT_AGGR_RESET);
+	if (int_aggr_reset)
+		ufshcd_config_int_aggr(hba, INT_AGGR_RESET);
 }
 
 /**
@@ -1463,10 +1743,10 @@ ufshcd_issue_tm_cmd(struct ufs_hba *hba,
 	task_req_upiup =
 		(struct utp_upiu_task_req *) task_req_descp->task_req_upiu;
 	task_req_upiup->header.dword_0 =
-		cpu_to_be32(UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, 0,
-					      lrbp->lun, lrbp->task_tag));
+		UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, 0,
+					      lrbp->lun, lrbp->task_tag);
 	task_req_upiup->header.dword_1 =
-	cpu_to_be32(UPIU_HEADER_DWORD(0, tm_function, 0, 0));
+		UPIU_HEADER_DWORD(0, tm_function, 0, 0);
 
 	task_req_upiup->input_param1 = lrbp->lun;
 	task_req_upiup->input_param1 =
@@ -1521,7 +1801,7 @@ static int ufshcd_device_reset(struct scsi_cmnd *cmd)
 	if (err == FAILED)
 		goto out;
 
-	for (pos = 0; pos < hba->nutrs; pos++) {
+	for (pos = 0; pos < SCSI_CMD_QUEUE_SIZE; pos++) {
 		if (test_bit(pos, &hba->outstanding_reqs) &&
 		    (hba->lrb[tag].lun == hba->lrb[pos].lun)) {
 
@@ -1539,6 +1819,11 @@ static int ufshcd_device_reset(struct scsi_cmnd *cmd)
 			}
 		}
 	} /* end of for */
+
+	/* complete internal command */
+	if (hba->i_cmd.dev_cmd_complete)
+		complete(hba->i_cmd.dev_cmd_complete);
+
 out:
 	return err;
 }
@@ -1618,8 +1903,16 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)
 	int ret;
 
 	ret = ufshcd_link_startup(hba);
-	if (!ret)
-		scsi_scan_host(hba->host);
+	if (ret)
+		goto out;
+
+	ret = ufshcd_validate_dev_connection(hba);
+	if (ret)
+		goto out;
+
+	scsi_scan_host(hba->host);
+out:
+	return;
 }
 
 static struct scsi_host_template ufshcd_driver_template = {
@@ -1771,8 +2064,8 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
 	/* Configure LRB */
 	ufshcd_host_memory_configure(hba);
 
-	host->can_queue = hba->nutrs;
-	host->cmd_per_lun = hba->nutrs;
+	host->can_queue = SCSI_CMD_QUEUE_SIZE;
+	host->cmd_per_lun = SCSI_CMD_QUEUE_SIZE;
 	host->max_id = UFSHCD_MAX_ID;
 	host->max_lun = UFSHCD_MAX_LUNS;
 	host->max_channel = UFSHCD_MAX_CHANNEL;
@@ -1788,6 +2081,9 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
 	/* Initialize UIC command mutex */
 	mutex_init(&hba->uic_cmd_mutex);
 
+	/* Initialize mutex for internal commands */
+	mutex_init(&hba->i_cmd.dev_cmd_lock);
+
 	/* IRQ registration */
 	err = request_irq(irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
 	if (err) {
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 49590ee..e41fa5e 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -68,6 +68,10 @@
 #define UFSHCD "ufshcd"
 #define UFSHCD_DRIVER_VERSION "0.2"
 
+enum internal_cmd_type {
+	DEV_CMD_TYPE_NOP		= 0x0,
+};
+
 /**
  * struct uic_command - UIC command structure
  * @command: UIC command
@@ -91,7 +95,7 @@ struct uic_command {
 /**
  * struct ufshcd_lrb - local reference block
  * @utr_descriptor_ptr: UTRD address of the command
- * @ucd_cmd_ptr: UCD address of the command
+ * @ucd_req_ptr: UCD address of the command
  * @ucd_rsp_ptr: Response UPIU address for this command
  * @ucd_prdt_ptr: PRDT address of the command
  * @cmd: pointer to SCSI command
@@ -101,10 +105,11 @@ struct uic_command {
  * @command_type: SCSI, UFS, Query.
  * @task_tag: Task tag of the command
  * @lun: LUN of the command
+ * @intr_cmd: Interrupt command (doesn't participate in interrupt aggregation)
  */
 struct ufshcd_lrb {
 	struct utp_transfer_req_desc *utr_descriptor_ptr;
-	struct utp_upiu_cmd *ucd_cmd_ptr;
+	struct utp_upiu_req *ucd_req_ptr;
 	struct utp_upiu_rsp *ucd_rsp_ptr;
 	struct ufshcd_sg_entry *ucd_prdt_ptr;
 
@@ -116,8 +121,20 @@ struct ufshcd_lrb {
 	int command_type;
 	int task_tag;
 	unsigned int lun;
+	bool intr_cmd;
 };
 
+/**
+ * struct ufs_internal_cmd - all assosiated fields with internal commands
+ * @dev_cmd_type: device management command type - Query, NOP OUT
+ * @dev_cmd_lock: lock to allow one internal command at a time
+ * @dev_cmd_complete: internal commands completion
+ */
+struct ufs_internal_cmd {
+	enum internal_cmd_type dev_cmd_type;
+	struct mutex dev_cmd_lock;
+	struct completion *dev_cmd_complete;
+};
 
 /**
  * struct ufs_hba - per adapter private structure
@@ -146,6 +163,7 @@ struct ufshcd_lrb {
  * @intr_mask: Interrupt Mask Bits
  * @feh_workq: Work queue for fatal controller error handling
  * @errors: HBA errors
+ * @i_cmd: ufs internal command information
  */
 struct ufs_hba {
 	void __iomem *mmio_base;
@@ -188,6 +206,9 @@ struct ufs_hba {
 
 	/* HBA Errors */
 	u32 errors;
+
+	/* Internal Request data */
+	struct ufs_internal_cmd i_cmd;
 };
 
 #define ufshcd_writel(hba, val, reg)	\
-- 
1.7.6
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

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

* [PATCH 2/2] scsi: ufs: Set fDeviceInit flag to initiate device initialization
  2013-06-10 14:05 [PATCH 0/2] Dolev Raviv
@ 2013-06-10 14:05   ` Dolev Raviv
  2013-06-10 14:05   ` Dolev Raviv
  1 sibling, 0 replies; 14+ messages in thread
From: Dolev Raviv @ 2013-06-10 14:05 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-arm-msm, Dolev Raviv, Sujit Reddy Thumma, open list

Allow UFS device to complete its initialization and accept
SCSI commands by setting fDeviceInit flag. The device may take
time for this operation and hence the host should poll until
fDeviceInit flag is toggled to zero. This step is mandated by
UFS device specification for device initialization completion.

Signed-off-by: Dolev Raviv <draviv@codeaurora.org>
Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org>

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 69c0328..6ce99b0 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -43,6 +43,8 @@
 #define GENERAL_UPIU_REQUEST_SIZE 32
 #define UPIU_HEADER_DATA_SEGMENT_MAX_SIZE	((ALIGNED_UPIU_SIZE) - \
 					(GENERAL_UPIU_REQUEST_SIZE))
+#define QUERY_OSF_SIZE			((GENERAL_UPIU_REQUEST_SIZE) - \
+					(sizeof(struct utp_upiu_header)))
 
 #define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
 			cpu_to_be32((byte3 << 24) | (byte2 << 16) |\
@@ -68,7 +70,7 @@ enum {
 	UPIU_TRANSACTION_COMMAND	= 0x01,
 	UPIU_TRANSACTION_DATA_OUT	= 0x02,
 	UPIU_TRANSACTION_TASK_REQ	= 0x04,
-	UPIU_TRANSACTION_QUERY_REQ	= 0x26,
+	UPIU_TRANSACTION_QUERY_REQ	= 0x16,
 };
 
 /* UTP UPIU Transaction Codes Target to Initiator */
@@ -97,8 +99,19 @@ enum {
 	UPIU_TASK_ATTR_ACA	= 0x03,
 };
 
-/* UTP QUERY Transaction Specific Fields OpCode */
+/* UPIU Query request function */
 enum {
+	UPIU_QUERY_FUNC_STANDARD_READ_REQUEST = 0x01,
+	UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST = 0x81,
+};
+
+/* Flag idn for Query Requests*/
+enum flag_idn {
+	QUERY_FLAG_IDN_FDEVICEINIT = 0x01,
+};
+
+/* UTP QUERY Transaction Specific Fields OpCode */
+enum query_opcode {
 	UPIU_QUERY_OPCODE_NOP		= 0x0,
 	UPIU_QUERY_OPCODE_READ_DESC	= 0x1,
 	UPIU_QUERY_OPCODE_WRITE_DESC	= 0x2,
@@ -110,6 +123,21 @@ enum {
 	UPIU_QUERY_OPCODE_TOGGLE_FLAG	= 0x8,
 };
 
+/* Query response result code */
+enum {
+	QUERY_RESULT_SUCCESS			= 0x00,
+	QUERY_RESULT_NOT_READABLE		= 0xF6,
+	QUERY_RESULT_NOT_WRITEABLE		= 0xF7,
+	QUERY_RESULT_ALREADY_WRITTEN		= 0xF8,
+	QUERY_RESULT_INVALID_LENGTH		= 0xF9,
+	QUERY_RESULT_INVALID_VALUE		= 0xFA,
+	QUERY_RESULT_INVALID_SELECTOR		= 0xFB,
+	QUERY_RESULT_INVALID_INDEX		= 0xFC,
+	QUERY_RESULT_INVALID_IDN		= 0xFD,
+	QUERY_RESULT_INVALID_OPCODE		= 0xFE,
+	QUERY_RESULT_GENERAL_FAILURE		= 0xFF,
+};
+
 /* UTP Transfer Request Command Type (CT) */
 enum {
 	UPIU_COMMAND_SET_TYPE_SCSI	= 0x0,
@@ -127,6 +155,7 @@ enum {
 	MASK_SCSI_STATUS	= 0xFF,
 	MASK_TASK_RESPONSE	= 0xFF00,
 	MASK_RSP_UPIU_RESULT	= 0xFFFF,
+	MASK_QUERY_DATA_SEG_LEN	= 0xFFFF,
 };
 
 /* Task management service response */
@@ -160,13 +189,40 @@ struct utp_upiu_cmd {
 };
 
 /**
+ * struct utp_upiu_query - upiu request buffer structure for
+ * query request.
+ * @opcode: command to perform B-0
+ * @idn: a value that indicates the particular type of data B-1
+ * @index: Index to further identify data B-2
+ * @selector: Index to further identify data B-3
+ * @reserved_osf: spec reserved field B-4,5
+ * @length: number of descriptor bytes to read/write B-6,7
+ * @value: Attribute value to be written DW-6
+ * @reserved: spec reserved DW-7,8
+ */
+struct utp_upiu_query {
+	u8 opcode;
+	u8 idn;
+	u8 index;
+	u8 selector;
+	u16 reserved_osf;
+	u16 length;
+	u32 value;
+	u32 reserved[2];
+};
+
+/**
  * struct utp_upiu_req - general upiu request structure
  * @header:UPIU header structure DW-0 to DW-2
  * @sc: fields structure for scsi command
+ * @qr: fields structure for query request
  */
 struct utp_upiu_req {
 	struct utp_upiu_header header;
-	struct utp_upiu_cmd sc;
+	union {
+		struct utp_upiu_cmd sc;
+		struct utp_upiu_query qr;
+	};
 };
 
 /**
@@ -187,10 +243,14 @@ struct utp_cmd_rsp {
  * struct utp_upiu_rsp - general upiu response structure
  * @header: UPIU header structure DW-0 to DW-2
  * @sc: fields structure for scsi command
+ * @qr: fields structure for query request
  */
 struct utp_upiu_rsp {
 	struct utp_upiu_header header;
-	struct utp_cmd_rsp sc;
+	union {
+		struct utp_cmd_rsp sc;
+		struct utp_upiu_query qr;
+	};
 };
 
 /**
@@ -223,4 +283,24 @@ struct utp_upiu_task_rsp {
 	u32 reserved[3];
 };
 
+/**
+ * struct ufs_query_req - parameters for building a query request
+ * @query_func: UPIU header query function
+ * @upiu_req: the query request data
+ */
+struct ufs_query_req {
+	u8 query_func;
+	struct utp_upiu_query upiu_req;
+};
+
+/**
+ * struct ufs_query_resp - UPIU QUERY
+ * @response: device response code
+ * @upiu_res: query response data
+ */
+struct ufs_query_res {
+	u8 response;
+	struct utp_upiu_query upiu_res;
+};
+
 #endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index d534c50..6d12fae 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -48,10 +48,20 @@
 /* Timeout after 30 msecs if NOP OUT hangs without response */
 #define NOP_OUT_TIMEOUT    30 /* msecs */
 
+/* Query request retries */
+#define QUERY_REQ_RETRIES 10
+/* Query request timeout */
+#define QUERY_REQ_TIMEOUT 30 /* msec */
+/* fDeviceInit max polling number */
+#define QUERY_MAX_POLL_ITER 100
+
 #define SCSI_CMD_QUEUE_SIZE (hba->nutrs - 1)
 /* Reserved tag for internal commands */
 #define INTERNAL_CMD_TAG   (hba->nutrs - 1)
 
+/* Expose the flag value from utp_upiu_query.value */
+#define MASK_QUERY_UPIU_FLAG_LOC 0xFF
+
 enum {
 	UFSHCD_MAX_CHANNEL	= 0,
 	UFSHCD_MAX_ID		= 1,
@@ -378,6 +388,63 @@ static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp)
 }
 
 /**
+ * ufshcd_query_to_cpu() - formats the buffer to native cpu endian
+ * @response: upiu query response to convert
+ */
+static inline void ufshcd_query_to_cpu(struct utp_upiu_query *response)
+{
+	response->length = be16_to_cpu(response->length);
+	response->value = be32_to_cpu(response->value);
+}
+
+/**
+ * ufshcd_query_to_be() - formats the buffer to big endian
+ * @request: upiu query request to convert
+ */
+static inline void ufshcd_query_to_be(struct utp_upiu_query *request)
+{
+	request->length = cpu_to_be16(request->length);
+	request->value = cpu_to_be32(request->value);
+}
+
+/**
+ * ufshcd_copy_query_response() - Copy the Query Response and the data
+ * descriptor
+ * @hba: per adapter instance
+ * @lrb - pointer to local reference block
+ */
+static
+void ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+{
+	struct ufs_query_res *query_res = hba->i_cmd.query.response;
+
+	/* Get the UPIU response */
+	if (query_res) {
+		query_res->response = ufshcd_get_rsp_upiu_result(
+			lrbp->ucd_rsp_ptr) >> UPIU_RSP_CODE_OFFSET;
+
+		memcpy(&query_res->upiu_res, &lrbp->ucd_rsp_ptr->qr,
+			QUERY_OSF_SIZE);
+		ufshcd_query_to_cpu(&query_res->upiu_res);
+	}
+
+	/* Get the descriptor */
+	if (hba->i_cmd.query.descriptor && lrbp->ucd_rsp_ptr->qr.opcode ==
+			UPIU_QUERY_OPCODE_READ_DESC) {
+		u8 *descp = (u8 *)&lrbp->ucd_rsp_ptr +
+				GENERAL_UPIU_REQUEST_SIZE;
+		u16 len;
+
+		/* data segment length */
+		len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) &
+						MASK_QUERY_DATA_SEG_LEN;
+
+		memcpy(hba->i_cmd.query.descriptor, descp,
+			min_t(u16, len, UPIU_HEADER_DATA_SEGMENT_MAX_SIZE));
+	}
+}
+
+/**
  * ufshcd_hba_capabilities - Read controller capabilities
  * @hba: per adapter instance
  */
@@ -659,6 +726,47 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u32 upiu_flags)
 		(min_t(unsigned short, lrbp->cmd->cmd_len, MAX_CDB_SIZE)));
 }
 
+/**
+ * ufshcd_prepare_utp_query_req_upiu() - fills the utp_transfer_req_desc,
+ * for query requsts
+ * @hba: UFS hba
+ * @lrbp: local reference block pointer
+ * @upiu_flags: flags
+ */
+static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba,
+					struct ufshcd_lrb *lrbp,
+					u32 upiu_flags)
+{
+	struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
+	u16 len = hba->i_cmd.query.request->upiu_req.length;
+	u8 *descp = (u8 *)lrbp->ucd_req_ptr + GENERAL_UPIU_REQUEST_SIZE;
+
+	/* Query request header */
+	ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD(
+			UPIU_TRANSACTION_QUERY_REQ, upiu_flags,
+			lrbp->lun, lrbp->task_tag);
+	ucd_req_ptr->header.dword_1 = UPIU_HEADER_DWORD(
+			0, hba->i_cmd.query.request->query_func, 0, 0);
+
+	/* Data segment length */
+	ucd_req_ptr->header.dword_2 = UPIU_HEADER_DWORD(
+			0, 0, len >> 8, (u8)len);
+
+	/* Copy the Query Request buffer as is */
+	memcpy(&lrbp->ucd_req_ptr->qr, &hba->i_cmd.query.request->upiu_req,
+			QUERY_OSF_SIZE);
+	ufshcd_query_to_be(&lrbp->ucd_req_ptr->qr);
+
+	/* Copy the Descriptor */
+	if ((hba->i_cmd.query.descriptor != NULL) && (len > 0) &&
+		(hba->i_cmd.query.request->upiu_req.opcode ==
+					UPIU_QUERY_OPCODE_WRITE_DESC)) {
+		memcpy(descp, hba->i_cmd.query.descriptor,
+			min_t(u16, len, UPIU_HEADER_DATA_SEGMENT_MAX_SIZE));
+	}
+
+}
+
 static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp)
 {
 	struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
@@ -693,7 +801,10 @@ static int ufshcd_compose_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 		break;
 	case UTP_CMD_TYPE_DEV_MANAGE:
 		ufshcd_prepare_req_desc(lrbp, &upiu_flags, DMA_NONE);
-		if (hba->i_cmd.dev_cmd_type == DEV_CMD_TYPE_NOP)
+		if (hba->i_cmd.dev_cmd_type == DEV_CMD_TYPE_QUERY)
+			ufshcd_prepare_utp_query_req_upiu(
+					hba, lrbp, upiu_flags);
+		else if (hba->i_cmd.dev_cmd_type == DEV_CMD_TYPE_NOP)
 			ufshcd_prepare_utp_nop_upiu(lrbp);
 		else
 			ret = -EINVAL;
@@ -837,6 +948,9 @@ ufshcd_internal_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 	switch (resp) {
 	case UPIU_TRANSACTION_NOP_IN:
 		break;
+	case UPIU_TRANSACTION_QUERY_RSP:
+		ufshcd_copy_query_response(hba, lrbp);
+		break;
 	case UPIU_TRANSACTION_REJECT_UPIU:
 		/* TODO: handle Reject UPIU Response */
 		dev_err(hba->dev, "Reject UPIU not fully implemented\n");
@@ -896,6 +1010,121 @@ out:
 }
 
 /**
+ *  ufshcd_query_request() - API for issuing query request to the device.
+ *  @hba: ufs driver context
+ *  @query: params for query request
+ *  @descriptor: buffer for sending/receiving descriptor
+ *  @retries: number of times to try executing the command
+ *
+ *   All necessary fields for issuing a query and receiving its response
+ *   are stored in the UFS hba struct. We can use this method since we know
+ *   there is only one active query request or any internal command at all
+ *   times.
+ */
+static int ufshcd_send_query_request(struct ufs_hba *hba,
+					struct ufs_query_req *query,
+					u8 *descriptor,
+					struct ufs_query_res *response)
+{
+	int ret;
+
+	BUG_ON(!hba);
+	if (!query || !response) {
+		dev_err(hba->dev,
+			"%s: NULL pointer query = %p, response = %p\n",
+			__func__, query, response);
+		return -EINVAL;
+	}
+
+	mutex_lock(&hba->i_cmd.dev_cmd_lock);
+	hba->i_cmd.query.request = query;
+	hba->i_cmd.query.response = response;
+	hba->i_cmd.query.descriptor = descriptor;
+
+	ret = ufshcd_exec_internal_cmd(hba, DEV_CMD_TYPE_QUERY,
+					QUERY_REQ_TIMEOUT);
+
+	hba->i_cmd.query.request = NULL;
+	hba->i_cmd.query.response = NULL;
+	hba->i_cmd.query.descriptor = NULL;
+	mutex_unlock(&hba->i_cmd.dev_cmd_lock);
+
+	return ret;
+}
+
+/**
+ * ufshcd_query_flag() - Helper function for composing flag query requests
+ * hba: per-adapter instance
+ * query_opcode: flag query to perform
+ * idn: flag idn to access
+ * flag_res: the flag value after the query request completes
+ *
+ * Returns 0 for success, non-zero in case of failure
+ */
+static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
+			enum flag_idn idn, bool *flag_res)
+{
+	struct ufs_query_req *query;
+	struct ufs_query_res *response;
+	int err = -ENOMEM;
+
+	query = kzalloc(sizeof(struct ufs_query_req), GFP_KERNEL);
+	if (!query) {
+		dev_err(hba->dev,
+			"%s: Failed allocating ufs_query_req instance\n",
+			__func__);
+		goto out_no_mem;
+	}
+	response = kzalloc(sizeof(struct ufs_query_res), GFP_KERNEL);
+	if (!response) {
+		dev_err(hba->dev,
+			"%s: Failed allocating ufs_query_res instance\n",
+			__func__);
+		goto out_free_query;
+	}
+
+	switch (opcode) {
+	case UPIU_QUERY_OPCODE_SET_FLAG:
+	case UPIU_QUERY_OPCODE_CLEAR_FLAG:
+	case UPIU_QUERY_OPCODE_TOGGLE_FLAG:
+		query->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST;
+		break;
+	case UPIU_QUERY_OPCODE_READ_FLAG:
+		query->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST;
+		break;
+	default:
+		dev_err(hba->dev,
+			"%s: Expected query flag opcode but got = %d\n",
+			__func__, opcode);
+		err = -EINVAL;
+		goto out;
+	}
+	query->upiu_req.opcode = opcode;
+	query->upiu_req.idn = idn;
+
+	/* Send query request */
+	err = ufshcd_send_query_request(hba, query, NULL, response);
+
+	if (err) {
+		dev_err(hba->dev,
+			"%s: Sending flag query for idn %d failed, err = %d\n",
+			__func__, idn, err);
+		goto out;
+	}
+
+	if (flag_res)
+		*flag_res = (response->upiu_res.value &
+				MASK_QUERY_UPIU_FLAG_LOC) & 0x1;
+
+out:
+	kfree(response);
+out_free_query:
+	kfree(query);
+out_no_mem:
+	return err;
+}
+
+/**
  * ufshcd_memory_alloc - allocate memory for host memory space data structures
  * @hba: per adapter instance
  *
@@ -1064,6 +1293,59 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
 }
 
 /**
+ * ufshcd_validate_device_init() - checks device readiness
+ * hba: per-adapter instance
+ *
+ * Set fDeviceInit flag, than, query the flag until the device clears the
+ * flag.
+ */
+static int ufshcd_validate_device_init(struct ufs_hba *hba)
+{
+	int i, retries, err = 0;
+	bool flag_res = 0;
+
+	for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+		/* Set the fDeviceIntit flag */
+		err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_SET_FLAG,
+					QUERY_FLAG_IDN_FDEVICEINIT, &flag_res);
+		if (!err || err == -ETIMEDOUT)
+			break;
+		dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
+	}
+	if (err) {
+		dev_err(hba->dev,
+			"%s setting fDeviceInit flag failed with error %d\n",
+			__func__, err);
+		goto out;
+	}
+
+	/* Start polling */
+	for (i = 0; i < QUERY_MAX_POLL_ITER && !err && flag_res; i++) {
+		retries = QUERY_REQ_RETRIES;
+		for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+			err = ufshcd_query_flag(hba,
+					UPIU_QUERY_OPCODE_READ_FLAG,
+					QUERY_FLAG_IDN_FDEVICEINIT, &flag_res);
+			if (!err || err == -ETIMEDOUT)
+				break;
+			dev_dbg(hba->dev, "%s: error %d retrying\n", __func__,
+					err);
+		}
+	}
+	if (err)
+		dev_err(hba->dev,
+			"%s reading fDeviceInit flag failed with error %d\n",
+			__func__, err);
+	else if (flag_res)
+		dev_err(hba->dev,
+			"%s fDeviceInit was not cleared by the device\n",
+			__func__);
+
+out:
+	return err;
+}
+
+/**
  * ufshcd_make_hba_operational - Make UFS controller operational
  * @hba: per adapter instance
  *
@@ -1910,6 +2192,10 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)
 	if (ret)
 		goto out;
 
+	ret = ufshcd_validate_device_init(hba);
+	if (ret)
+		goto out;
+
 	scsi_scan_host(hba->host);
 out:
 	return;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index e41fa5e..4e4c56f 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -70,6 +70,7 @@
 
 enum internal_cmd_type {
 	DEV_CMD_TYPE_NOP		= 0x0,
+	DEV_CMD_TYPE_QUERY		= 0x1,
 };
 
 /**
@@ -125,15 +126,29 @@ struct ufshcd_lrb {
 };
 
 /**
+ * struct ufs_query - holds relevent data structures for query request
+ * @request: request upiu and function
+ * @descriptor: buffer for sending/receiving descriptor
+ * @response: response upiu and response
+ */
+struct ufs_query {
+	struct ufs_query_req *request;
+	u8 *descriptor;
+	struct ufs_query_res *response;
+};
+
+/**
  * struct ufs_internal_cmd - all assosiated fields with internal commands
  * @dev_cmd_type: device management command type - Query, NOP OUT
  * @dev_cmd_lock: lock to allow one internal command at a time
  * @dev_cmd_complete: internal commands completion
+ * @query: required query data structures for sending query request
  */
 struct ufs_internal_cmd {
 	enum internal_cmd_type dev_cmd_type;
 	struct mutex dev_cmd_lock;
 	struct completion *dev_cmd_complete;
+	struct ufs_query query;
 };
 
 /**
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index d5c5f14..f1e1b74 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -39,7 +39,7 @@
 enum {
 	TASK_REQ_UPIU_SIZE_DWORDS	= 8,
 	TASK_RSP_UPIU_SIZE_DWORDS	= 8,
-	ALIGNED_UPIU_SIZE		= 128,
+	ALIGNED_UPIU_SIZE		= 512,
 };
 
 /* UFSHCI Registers */
-- 
1.7.6
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

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

* [PATCH 2/2] scsi: ufs: Set fDeviceInit flag to initiate device initialization
@ 2013-06-10 14:05   ` Dolev Raviv
  0 siblings, 0 replies; 14+ messages in thread
From: Dolev Raviv @ 2013-06-10 14:05 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-arm-msm, Dolev Raviv, Sujit Reddy Thumma, open list

Allow UFS device to complete its initialization and accept
SCSI commands by setting fDeviceInit flag. The device may take
time for this operation and hence the host should poll until
fDeviceInit flag is toggled to zero. This step is mandated by
UFS device specification for device initialization completion.

Signed-off-by: Dolev Raviv <draviv@codeaurora.org>
Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org>

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 69c0328..6ce99b0 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -43,6 +43,8 @@
 #define GENERAL_UPIU_REQUEST_SIZE 32
 #define UPIU_HEADER_DATA_SEGMENT_MAX_SIZE	((ALIGNED_UPIU_SIZE) - \
 					(GENERAL_UPIU_REQUEST_SIZE))
+#define QUERY_OSF_SIZE			((GENERAL_UPIU_REQUEST_SIZE) - \
+					(sizeof(struct utp_upiu_header)))
 
 #define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
 			cpu_to_be32((byte3 << 24) | (byte2 << 16) |\
@@ -68,7 +70,7 @@ enum {
 	UPIU_TRANSACTION_COMMAND	= 0x01,
 	UPIU_TRANSACTION_DATA_OUT	= 0x02,
 	UPIU_TRANSACTION_TASK_REQ	= 0x04,
-	UPIU_TRANSACTION_QUERY_REQ	= 0x26,
+	UPIU_TRANSACTION_QUERY_REQ	= 0x16,
 };
 
 /* UTP UPIU Transaction Codes Target to Initiator */
@@ -97,8 +99,19 @@ enum {
 	UPIU_TASK_ATTR_ACA	= 0x03,
 };
 
-/* UTP QUERY Transaction Specific Fields OpCode */
+/* UPIU Query request function */
 enum {
+	UPIU_QUERY_FUNC_STANDARD_READ_REQUEST = 0x01,
+	UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST = 0x81,
+};
+
+/* Flag idn for Query Requests*/
+enum flag_idn {
+	QUERY_FLAG_IDN_FDEVICEINIT = 0x01,
+};
+
+/* UTP QUERY Transaction Specific Fields OpCode */
+enum query_opcode {
 	UPIU_QUERY_OPCODE_NOP		= 0x0,
 	UPIU_QUERY_OPCODE_READ_DESC	= 0x1,
 	UPIU_QUERY_OPCODE_WRITE_DESC	= 0x2,
@@ -110,6 +123,21 @@ enum {
 	UPIU_QUERY_OPCODE_TOGGLE_FLAG	= 0x8,
 };
 
+/* Query response result code */
+enum {
+	QUERY_RESULT_SUCCESS			= 0x00,
+	QUERY_RESULT_NOT_READABLE		= 0xF6,
+	QUERY_RESULT_NOT_WRITEABLE		= 0xF7,
+	QUERY_RESULT_ALREADY_WRITTEN		= 0xF8,
+	QUERY_RESULT_INVALID_LENGTH		= 0xF9,
+	QUERY_RESULT_INVALID_VALUE		= 0xFA,
+	QUERY_RESULT_INVALID_SELECTOR		= 0xFB,
+	QUERY_RESULT_INVALID_INDEX		= 0xFC,
+	QUERY_RESULT_INVALID_IDN		= 0xFD,
+	QUERY_RESULT_INVALID_OPCODE		= 0xFE,
+	QUERY_RESULT_GENERAL_FAILURE		= 0xFF,
+};
+
 /* UTP Transfer Request Command Type (CT) */
 enum {
 	UPIU_COMMAND_SET_TYPE_SCSI	= 0x0,
@@ -127,6 +155,7 @@ enum {
 	MASK_SCSI_STATUS	= 0xFF,
 	MASK_TASK_RESPONSE	= 0xFF00,
 	MASK_RSP_UPIU_RESULT	= 0xFFFF,
+	MASK_QUERY_DATA_SEG_LEN	= 0xFFFF,
 };
 
 /* Task management service response */
@@ -160,13 +189,40 @@ struct utp_upiu_cmd {
 };
 
 /**
+ * struct utp_upiu_query - upiu request buffer structure for
+ * query request.
+ * @opcode: command to perform B-0
+ * @idn: a value that indicates the particular type of data B-1
+ * @index: Index to further identify data B-2
+ * @selector: Index to further identify data B-3
+ * @reserved_osf: spec reserved field B-4,5
+ * @length: number of descriptor bytes to read/write B-6,7
+ * @value: Attribute value to be written DW-6
+ * @reserved: spec reserved DW-7,8
+ */
+struct utp_upiu_query {
+	u8 opcode;
+	u8 idn;
+	u8 index;
+	u8 selector;
+	u16 reserved_osf;
+	u16 length;
+	u32 value;
+	u32 reserved[2];
+};
+
+/**
  * struct utp_upiu_req - general upiu request structure
  * @header:UPIU header structure DW-0 to DW-2
  * @sc: fields structure for scsi command
+ * @qr: fields structure for query request
  */
 struct utp_upiu_req {
 	struct utp_upiu_header header;
-	struct utp_upiu_cmd sc;
+	union {
+		struct utp_upiu_cmd sc;
+		struct utp_upiu_query qr;
+	};
 };
 
 /**
@@ -187,10 +243,14 @@ struct utp_cmd_rsp {
  * struct utp_upiu_rsp - general upiu response structure
  * @header: UPIU header structure DW-0 to DW-2
  * @sc: fields structure for scsi command
+ * @qr: fields structure for query request
  */
 struct utp_upiu_rsp {
 	struct utp_upiu_header header;
-	struct utp_cmd_rsp sc;
+	union {
+		struct utp_cmd_rsp sc;
+		struct utp_upiu_query qr;
+	};
 };
 
 /**
@@ -223,4 +283,24 @@ struct utp_upiu_task_rsp {
 	u32 reserved[3];
 };
 
+/**
+ * struct ufs_query_req - parameters for building a query request
+ * @query_func: UPIU header query function
+ * @upiu_req: the query request data
+ */
+struct ufs_query_req {
+	u8 query_func;
+	struct utp_upiu_query upiu_req;
+};
+
+/**
+ * struct ufs_query_resp - UPIU QUERY
+ * @response: device response code
+ * @upiu_res: query response data
+ */
+struct ufs_query_res {
+	u8 response;
+	struct utp_upiu_query upiu_res;
+};
+
 #endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index d534c50..6d12fae 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -48,10 +48,20 @@
 /* Timeout after 30 msecs if NOP OUT hangs without response */
 #define NOP_OUT_TIMEOUT    30 /* msecs */
 
+/* Query request retries */
+#define QUERY_REQ_RETRIES 10
+/* Query request timeout */
+#define QUERY_REQ_TIMEOUT 30 /* msec */
+/* fDeviceInit max polling number */
+#define QUERY_MAX_POLL_ITER 100
+
 #define SCSI_CMD_QUEUE_SIZE (hba->nutrs - 1)
 /* Reserved tag for internal commands */
 #define INTERNAL_CMD_TAG   (hba->nutrs - 1)
 
+/* Expose the flag value from utp_upiu_query.value */
+#define MASK_QUERY_UPIU_FLAG_LOC 0xFF
+
 enum {
 	UFSHCD_MAX_CHANNEL	= 0,
 	UFSHCD_MAX_ID		= 1,
@@ -378,6 +388,63 @@ static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp)
 }
 
 /**
+ * ufshcd_query_to_cpu() - formats the buffer to native cpu endian
+ * @response: upiu query response to convert
+ */
+static inline void ufshcd_query_to_cpu(struct utp_upiu_query *response)
+{
+	response->length = be16_to_cpu(response->length);
+	response->value = be32_to_cpu(response->value);
+}
+
+/**
+ * ufshcd_query_to_be() - formats the buffer to big endian
+ * @request: upiu query request to convert
+ */
+static inline void ufshcd_query_to_be(struct utp_upiu_query *request)
+{
+	request->length = cpu_to_be16(request->length);
+	request->value = cpu_to_be32(request->value);
+}
+
+/**
+ * ufshcd_copy_query_response() - Copy the Query Response and the data
+ * descriptor
+ * @hba: per adapter instance
+ * @lrb - pointer to local reference block
+ */
+static
+void ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+{
+	struct ufs_query_res *query_res = hba->i_cmd.query.response;
+
+	/* Get the UPIU response */
+	if (query_res) {
+		query_res->response = ufshcd_get_rsp_upiu_result(
+			lrbp->ucd_rsp_ptr) >> UPIU_RSP_CODE_OFFSET;
+
+		memcpy(&query_res->upiu_res, &lrbp->ucd_rsp_ptr->qr,
+			QUERY_OSF_SIZE);
+		ufshcd_query_to_cpu(&query_res->upiu_res);
+	}
+
+	/* Get the descriptor */
+	if (hba->i_cmd.query.descriptor && lrbp->ucd_rsp_ptr->qr.opcode ==
+			UPIU_QUERY_OPCODE_READ_DESC) {
+		u8 *descp = (u8 *)&lrbp->ucd_rsp_ptr +
+				GENERAL_UPIU_REQUEST_SIZE;
+		u16 len;
+
+		/* data segment length */
+		len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) &
+						MASK_QUERY_DATA_SEG_LEN;
+
+		memcpy(hba->i_cmd.query.descriptor, descp,
+			min_t(u16, len, UPIU_HEADER_DATA_SEGMENT_MAX_SIZE));
+	}
+}
+
+/**
  * ufshcd_hba_capabilities - Read controller capabilities
  * @hba: per adapter instance
  */
@@ -659,6 +726,47 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u32 upiu_flags)
 		(min_t(unsigned short, lrbp->cmd->cmd_len, MAX_CDB_SIZE)));
 }
 
+/**
+ * ufshcd_prepare_utp_query_req_upiu() - fills the utp_transfer_req_desc,
+ * for query requsts
+ * @hba: UFS hba
+ * @lrbp: local reference block pointer
+ * @upiu_flags: flags
+ */
+static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba,
+					struct ufshcd_lrb *lrbp,
+					u32 upiu_flags)
+{
+	struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
+	u16 len = hba->i_cmd.query.request->upiu_req.length;
+	u8 *descp = (u8 *)lrbp->ucd_req_ptr + GENERAL_UPIU_REQUEST_SIZE;
+
+	/* Query request header */
+	ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD(
+			UPIU_TRANSACTION_QUERY_REQ, upiu_flags,
+			lrbp->lun, lrbp->task_tag);
+	ucd_req_ptr->header.dword_1 = UPIU_HEADER_DWORD(
+			0, hba->i_cmd.query.request->query_func, 0, 0);
+
+	/* Data segment length */
+	ucd_req_ptr->header.dword_2 = UPIU_HEADER_DWORD(
+			0, 0, len >> 8, (u8)len);
+
+	/* Copy the Query Request buffer as is */
+	memcpy(&lrbp->ucd_req_ptr->qr, &hba->i_cmd.query.request->upiu_req,
+			QUERY_OSF_SIZE);
+	ufshcd_query_to_be(&lrbp->ucd_req_ptr->qr);
+
+	/* Copy the Descriptor */
+	if ((hba->i_cmd.query.descriptor != NULL) && (len > 0) &&
+		(hba->i_cmd.query.request->upiu_req.opcode ==
+					UPIU_QUERY_OPCODE_WRITE_DESC)) {
+		memcpy(descp, hba->i_cmd.query.descriptor,
+			min_t(u16, len, UPIU_HEADER_DATA_SEGMENT_MAX_SIZE));
+	}
+
+}
+
 static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp)
 {
 	struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
@@ -693,7 +801,10 @@ static int ufshcd_compose_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 		break;
 	case UTP_CMD_TYPE_DEV_MANAGE:
 		ufshcd_prepare_req_desc(lrbp, &upiu_flags, DMA_NONE);
-		if (hba->i_cmd.dev_cmd_type == DEV_CMD_TYPE_NOP)
+		if (hba->i_cmd.dev_cmd_type == DEV_CMD_TYPE_QUERY)
+			ufshcd_prepare_utp_query_req_upiu(
+					hba, lrbp, upiu_flags);
+		else if (hba->i_cmd.dev_cmd_type == DEV_CMD_TYPE_NOP)
 			ufshcd_prepare_utp_nop_upiu(lrbp);
 		else
 			ret = -EINVAL;
@@ -837,6 +948,9 @@ ufshcd_internal_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 	switch (resp) {
 	case UPIU_TRANSACTION_NOP_IN:
 		break;
+	case UPIU_TRANSACTION_QUERY_RSP:
+		ufshcd_copy_query_response(hba, lrbp);
+		break;
 	case UPIU_TRANSACTION_REJECT_UPIU:
 		/* TODO: handle Reject UPIU Response */
 		dev_err(hba->dev, "Reject UPIU not fully implemented\n");
@@ -896,6 +1010,121 @@ out:
 }
 
 /**
+ *  ufshcd_query_request() - API for issuing query request to the device.
+ *  @hba: ufs driver context
+ *  @query: params for query request
+ *  @descriptor: buffer for sending/receiving descriptor
+ *  @retries: number of times to try executing the command
+ *
+ *   All necessary fields for issuing a query and receiving its response
+ *   are stored in the UFS hba struct. We can use this method since we know
+ *   there is only one active query request or any internal command at all
+ *   times.
+ */
+static int ufshcd_send_query_request(struct ufs_hba *hba,
+					struct ufs_query_req *query,
+					u8 *descriptor,
+					struct ufs_query_res *response)
+{
+	int ret;
+
+	BUG_ON(!hba);
+	if (!query || !response) {
+		dev_err(hba->dev,
+			"%s: NULL pointer query = %p, response = %p\n",
+			__func__, query, response);
+		return -EINVAL;
+	}
+
+	mutex_lock(&hba->i_cmd.dev_cmd_lock);
+	hba->i_cmd.query.request = query;
+	hba->i_cmd.query.response = response;
+	hba->i_cmd.query.descriptor = descriptor;
+
+	ret = ufshcd_exec_internal_cmd(hba, DEV_CMD_TYPE_QUERY,
+					QUERY_REQ_TIMEOUT);
+
+	hba->i_cmd.query.request = NULL;
+	hba->i_cmd.query.response = NULL;
+	hba->i_cmd.query.descriptor = NULL;
+	mutex_unlock(&hba->i_cmd.dev_cmd_lock);
+
+	return ret;
+}
+
+/**
+ * ufshcd_query_flag() - Helper function for composing flag query requests
+ * hba: per-adapter instance
+ * query_opcode: flag query to perform
+ * idn: flag idn to access
+ * flag_res: the flag value after the query request completes
+ *
+ * Returns 0 for success, non-zero in case of failure
+ */
+static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
+			enum flag_idn idn, bool *flag_res)
+{
+	struct ufs_query_req *query;
+	struct ufs_query_res *response;
+	int err = -ENOMEM;
+
+	query = kzalloc(sizeof(struct ufs_query_req), GFP_KERNEL);
+	if (!query) {
+		dev_err(hba->dev,
+			"%s: Failed allocating ufs_query_req instance\n",
+			__func__);
+		goto out_no_mem;
+	}
+	response = kzalloc(sizeof(struct ufs_query_res), GFP_KERNEL);
+	if (!response) {
+		dev_err(hba->dev,
+			"%s: Failed allocating ufs_query_res instance\n",
+			__func__);
+		goto out_free_query;
+	}
+
+	switch (opcode) {
+	case UPIU_QUERY_OPCODE_SET_FLAG:
+	case UPIU_QUERY_OPCODE_CLEAR_FLAG:
+	case UPIU_QUERY_OPCODE_TOGGLE_FLAG:
+		query->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST;
+		break;
+	case UPIU_QUERY_OPCODE_READ_FLAG:
+		query->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST;
+		break;
+	default:
+		dev_err(hba->dev,
+			"%s: Expected query flag opcode but got = %d\n",
+			__func__, opcode);
+		err = -EINVAL;
+		goto out;
+	}
+	query->upiu_req.opcode = opcode;
+	query->upiu_req.idn = idn;
+
+	/* Send query request */
+	err = ufshcd_send_query_request(hba, query, NULL, response);
+
+	if (err) {
+		dev_err(hba->dev,
+			"%s: Sending flag query for idn %d failed, err = %d\n",
+			__func__, idn, err);
+		goto out;
+	}
+
+	if (flag_res)
+		*flag_res = (response->upiu_res.value &
+				MASK_QUERY_UPIU_FLAG_LOC) & 0x1;
+
+out:
+	kfree(response);
+out_free_query:
+	kfree(query);
+out_no_mem:
+	return err;
+}
+
+/**
  * ufshcd_memory_alloc - allocate memory for host memory space data structures
  * @hba: per adapter instance
  *
@@ -1064,6 +1293,59 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
 }
 
 /**
+ * ufshcd_validate_device_init() - checks device readiness
+ * hba: per-adapter instance
+ *
+ * Set fDeviceInit flag, than, query the flag until the device clears the
+ * flag.
+ */
+static int ufshcd_validate_device_init(struct ufs_hba *hba)
+{
+	int i, retries, err = 0;
+	bool flag_res = 0;
+
+	for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+		/* Set the fDeviceIntit flag */
+		err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_SET_FLAG,
+					QUERY_FLAG_IDN_FDEVICEINIT, &flag_res);
+		if (!err || err == -ETIMEDOUT)
+			break;
+		dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
+	}
+	if (err) {
+		dev_err(hba->dev,
+			"%s setting fDeviceInit flag failed with error %d\n",
+			__func__, err);
+		goto out;
+	}
+
+	/* Start polling */
+	for (i = 0; i < QUERY_MAX_POLL_ITER && !err && flag_res; i++) {
+		retries = QUERY_REQ_RETRIES;
+		for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+			err = ufshcd_query_flag(hba,
+					UPIU_QUERY_OPCODE_READ_FLAG,
+					QUERY_FLAG_IDN_FDEVICEINIT, &flag_res);
+			if (!err || err == -ETIMEDOUT)
+				break;
+			dev_dbg(hba->dev, "%s: error %d retrying\n", __func__,
+					err);
+		}
+	}
+	if (err)
+		dev_err(hba->dev,
+			"%s reading fDeviceInit flag failed with error %d\n",
+			__func__, err);
+	else if (flag_res)
+		dev_err(hba->dev,
+			"%s fDeviceInit was not cleared by the device\n",
+			__func__);
+
+out:
+	return err;
+}
+
+/**
  * ufshcd_make_hba_operational - Make UFS controller operational
  * @hba: per adapter instance
  *
@@ -1910,6 +2192,10 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)
 	if (ret)
 		goto out;
 
+	ret = ufshcd_validate_device_init(hba);
+	if (ret)
+		goto out;
+
 	scsi_scan_host(hba->host);
 out:
 	return;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index e41fa5e..4e4c56f 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -70,6 +70,7 @@
 
 enum internal_cmd_type {
 	DEV_CMD_TYPE_NOP		= 0x0,
+	DEV_CMD_TYPE_QUERY		= 0x1,
 };
 
 /**
@@ -125,15 +126,29 @@ struct ufshcd_lrb {
 };
 
 /**
+ * struct ufs_query - holds relevent data structures for query request
+ * @request: request upiu and function
+ * @descriptor: buffer for sending/receiving descriptor
+ * @response: response upiu and response
+ */
+struct ufs_query {
+	struct ufs_query_req *request;
+	u8 *descriptor;
+	struct ufs_query_res *response;
+};
+
+/**
  * struct ufs_internal_cmd - all assosiated fields with internal commands
  * @dev_cmd_type: device management command type - Query, NOP OUT
  * @dev_cmd_lock: lock to allow one internal command at a time
  * @dev_cmd_complete: internal commands completion
+ * @query: required query data structures for sending query request
  */
 struct ufs_internal_cmd {
 	enum internal_cmd_type dev_cmd_type;
 	struct mutex dev_cmd_lock;
 	struct completion *dev_cmd_complete;
+	struct ufs_query query;
 };
 
 /**
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index d5c5f14..f1e1b74 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -39,7 +39,7 @@
 enum {
 	TASK_REQ_UPIU_SIZE_DWORDS	= 8,
 	TASK_RSP_UPIU_SIZE_DWORDS	= 8,
-	ALIGNED_UPIU_SIZE		= 128,
+	ALIGNED_UPIU_SIZE		= 512,
 };
 
 /* UFSHCI Registers */
-- 
1.7.6
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

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

* Re: [PATCH 1/2] scsi: ufs: Add support for sending NOP OUT UPIU
  2013-06-10 14:05   ` Dolev Raviv
  (?)
@ 2013-06-12  5:30   ` Santosh Y
  2013-06-13  4:33     ` Sujit Reddy Thumma
  -1 siblings, 1 reply; 14+ messages in thread
From: Santosh Y @ 2013-06-12  5:30 UTC (permalink / raw)
  To: Dolev Raviv; +Cc: linux-scsi, linux-arm-msm, Sujit Reddy Thumma, open list

> +/*
> + * ufshcd_wait_for_register - wait for register value to change
> + * @hba - per-adapter interface
> + * @reg - mmio register offset
> + * @mask - mask to apply to read register value
> + * @val - wait condition
> + * @interval_us - polling interval in microsecs
> + * @timeout_ms - timeout in millisecs
> + *
> + * Returns final register value after iteration
> + */
> +static u32 ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
> +               u32 val, unsigned long interval_us, unsigned long timeout_ms)
> +{
> +       u32 tmp;
> +       ktime_t start;
> +       unsigned long diff;
> +
> +       tmp = ufshcd_readl(hba, reg);
> +
> +       start = ktime_get();
> +       while ((tmp & mask) == val) {


...as now I notice it, 'val' is the wait condition and the loop
continues if the wait condition is met. I feel it's a bit confusing.
Wouldn't something like (x != wait_condition) be appropriate?

> +               /* wakeup within 50us of expiry */
> +               usleep_range(interval_us, interval_us + 50);
> +               tmp = ufshcd_readl(hba, reg);
> +               diff = ktime_to_ms(ktime_sub(ktime_get(), start));
> +               if (diff > timeout_ms) {
> +                       tmp = ufshcd_readl(hba, reg);

Why this extra read? The register value might have changed during the
execution of 2 previous statements, is that the assumption?

> +                       break;
> +               }
> +       }
> +
> +       return tmp;
> +}
> +
>  /**
>   * ufshcd_get_intr_mask - Get the interrupt bit mask
>   * @hba - Pointer to adapter instance
> @@ -223,18 +267,13 @@ static inline void ufshcd_free_hba_memory(struct ufs_hba *hba)
>  }
>
>  /**
> - * ufshcd_is_valid_req_rsp - checks if controller TR response is valid
> + * ufshcd_get_req_rsp - returns the TR response
>   * @ucd_rsp_ptr: pointer to response UPIU
> - *
> - * This function checks the response UPIU for valid transaction type in
> - * response field
> - * Returns 0 on success, non-zero on failure
>   */
>  static inline int
> -ufshcd_is_valid_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr)
> +ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr)
>  {
> -       return ((be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24) ==
> -                UPIU_TRANSACTION_RESPONSE) ? 0 : DID_ERROR << 16;
> +       return be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24;
>  }
>
>  /**
> @@ -331,9 +370,9 @@ static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp)
>  {
>         int len;
>         if (lrbp->sense_buffer) {
> -               len = be16_to_cpu(lrbp->ucd_rsp_ptr->sense_data_len);
> +               len = be16_to_cpu(lrbp->ucd_rsp_ptr->sc.sense_data_len);
>                 memcpy(lrbp->sense_buffer,
> -                       lrbp->ucd_rsp_ptr->sense_data,
> +                       lrbp->ucd_rsp_ptr->sc.sense_data,
>                         min_t(int, len, SCSI_SENSE_BUFFERSIZE));
>         }
>  }
> @@ -551,76 +590,128 @@ static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs)
>  }
>
>  /**
> + * ufshcd_prepare_req_desc() - Fills the requests header
> + * descriptor according to request
> + * @lrbp: pointer to local reference block
> + * @upiu_flags: flags required in the header
> + * @cmd_dir: requests data direction
> + */
> +static void ufshcd_prepare_req_desc(struct ufshcd_lrb *lrbp, u32 *upiu_flags,
> +               enum dma_data_direction cmd_dir)
> +{
> +       struct utp_transfer_req_desc *req_desc = lrbp->utr_descriptor_ptr;
> +       u32 data_direction;
> +       u32 dword_0;
> +
> +       if (cmd_dir == DMA_FROM_DEVICE) {
> +               data_direction = UTP_DEVICE_TO_HOST;
> +               *upiu_flags = UPIU_CMD_FLAGS_READ;
> +       } else if (cmd_dir == DMA_TO_DEVICE) {
> +               data_direction = UTP_HOST_TO_DEVICE;
> +               *upiu_flags = UPIU_CMD_FLAGS_WRITE;
> +       } else {
> +               data_direction = UTP_NO_DATA_TRANSFER;
> +               *upiu_flags = UPIU_CMD_FLAGS_NONE;
> +       }
> +
> +       dword_0 = data_direction | (lrbp->command_type
> +                               << UPIU_COMMAND_TYPE_OFFSET);
> +       if (lrbp->intr_cmd)
> +               dword_0 |= UTP_REQ_DESC_INT_CMD;
> +
> +       /* Transfer request descriptor header fields */
> +       req_desc->header.dword_0 = cpu_to_le32(dword_0);
> +
> +       /*
> +        * assigning invalid value for command status. Controller
> +        * updates OCS on command completion, with the command
> +        * status
> +        */
> +       req_desc->header.dword_2 =
> +               cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
> +}
> +
> +/**
> + * ufshcd_prepare_utp_scsi_cmd_upiu() - fills the utp_transfer_req_desc,
> + * for scsi commands
> + * @lrbp - local reference block pointer
> + * @upiu_flags - flags
> + */
> +static
> +void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u32 upiu_flags)
> +{
> +       struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
> +
> +       /* command descriptor fields */
> +       ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD(
> +                               UPIU_TRANSACTION_COMMAND, upiu_flags,
> +                               lrbp->lun, lrbp->task_tag);
> +       ucd_req_ptr->header.dword_1 = UPIU_HEADER_DWORD(
> +                               UPIU_COMMAND_SET_TYPE_SCSI, 0, 0, 0);
> +
> +       /* Total EHS length and Data segment length will be zero */
> +       ucd_req_ptr->header.dword_2 = 0;
> +
> +       ucd_req_ptr->sc.exp_data_transfer_len =
> +               cpu_to_be32(lrbp->cmd->sdb.length);
> +
> +       memcpy(ucd_req_ptr->sc.cdb, lrbp->cmd->cmnd,
> +               (min_t(unsigned short, lrbp->cmd->cmd_len, MAX_CDB_SIZE)));
> +}
> +
> +static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp)
> +{
> +       struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
> +
> +       memset(ucd_req_ptr, 0, sizeof(struct utp_upiu_req));
> +
> +       /* command descriptor fields */
> +       ucd_req_ptr->header.dword_0 =
> +               UPIU_HEADER_DWORD(
> +                       UPIU_TRANSACTION_NOP_OUT, 0, 0, lrbp->task_tag);
> +}
> +
> +/**
>   * ufshcd_compose_upiu - form UFS Protocol Information Unit(UPIU)
> + * @hba - per adapter instance
>   * @lrb - pointer to local reference block
>   */
> -static void ufshcd_compose_upiu(struct ufshcd_lrb *lrbp)
> +static int ufshcd_compose_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
>  {
> -       struct utp_transfer_req_desc *req_desc;
> -       struct utp_upiu_cmd *ucd_cmd_ptr;
> -       u32 data_direction;
>         u32 upiu_flags;
> -
> -       ucd_cmd_ptr = lrbp->ucd_cmd_ptr;
> -       req_desc = lrbp->utr_descriptor_ptr;
> +       int ret = 0;
>
>         switch (lrbp->command_type) {
>         case UTP_CMD_TYPE_SCSI:
> -               if (lrbp->cmd->sc_data_direction == DMA_FROM_DEVICE) {
> -                       data_direction = UTP_DEVICE_TO_HOST;
> -                       upiu_flags = UPIU_CMD_FLAGS_READ;
> -               } else if (lrbp->cmd->sc_data_direction == DMA_TO_DEVICE) {
> -                       data_direction = UTP_HOST_TO_DEVICE;
> -                       upiu_flags = UPIU_CMD_FLAGS_WRITE;
> +               if (likely(lrbp->cmd)) {
> +                       ufshcd_prepare_req_desc(lrbp, &upiu_flags,
> +                                       lrbp->cmd->sc_data_direction);
> +                       ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags);
>                 } else {
> -                       data_direction = UTP_NO_DATA_TRANSFER;
> -                       upiu_flags = UPIU_CMD_FLAGS_NONE;
> +                       ret = -EINVAL;
>                 }
> -
> -               /* Transfer request descriptor header fields */
> -               req_desc->header.dword_0 =
> -                       cpu_to_le32(data_direction | UTP_SCSI_COMMAND);
> -
> -               /*
> -                * assigning invalid value for command status. Controller
> -                * updates OCS on command completion, with the command
> -                * status
> -                */
> -               req_desc->header.dword_2 =
> -                       cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
> -
> -               /* command descriptor fields */
> -               ucd_cmd_ptr->header.dword_0 =
> -                       cpu_to_be32(UPIU_HEADER_DWORD(UPIU_TRANSACTION_COMMAND,
> -                                                     upiu_flags,
> -                                                     lrbp->lun,
> -                                                     lrbp->task_tag));
> -               ucd_cmd_ptr->header.dword_1 =
> -                       cpu_to_be32(
> -                               UPIU_HEADER_DWORD(UPIU_COMMAND_SET_TYPE_SCSI,
> -                                                 0,
> -                                                 0,
> -                                                 0));
> -
> -               /* Total EHS length and Data segment length will be zero */
> -               ucd_cmd_ptr->header.dword_2 = 0;
> -
> -               ucd_cmd_ptr->exp_data_transfer_len =
> -                       cpu_to_be32(lrbp->cmd->sdb.length);
> -
> -               memcpy(ucd_cmd_ptr->cdb,
> -                      lrbp->cmd->cmnd,
> -                      (min_t(unsigned short,
> -                             lrbp->cmd->cmd_len,
> -                             MAX_CDB_SIZE)));
>                 break;
>         case UTP_CMD_TYPE_DEV_MANAGE:
> -               /* For query function implementation */
> +               ufshcd_prepare_req_desc(lrbp, &upiu_flags, DMA_NONE);
> +               if (hba->i_cmd.dev_cmd_type == DEV_CMD_TYPE_NOP)
> +                       ufshcd_prepare_utp_nop_upiu(lrbp);
> +               else
> +                       ret = -EINVAL;
>                 break;
>         case UTP_CMD_TYPE_UFS:
>                 /* For UFS native command implementation */
> +               dev_err(hba->dev, "%s: UFS native command are not supported\n",
> +                       __func__);
> +               ret = -ENOTSUPP;
> +               break;
> +       default:
> +               ret = -ENOTSUPP;
> +               dev_err(hba->dev, "%s: unknown command type: 0x%x\n",
> +                               __func__, lrbp->command_type);
>                 break;
>         } /* end of switch */
> +
> +       return ret;
>  }
>
>  /**
> @@ -654,11 +745,11 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
>         lrbp->sense_buffer = cmd->sense_buffer;
>         lrbp->task_tag = tag;
>         lrbp->lun = cmd->device->lun;
> -
> +       lrbp->intr_cmd = false;
>         lrbp->command_type = UTP_CMD_TYPE_SCSI;
>
>         /* form UPIU before issuing the command */
> -       ufshcd_compose_upiu(lrbp);
> +       ufshcd_compose_upiu(hba, lrbp);
>         err = ufshcd_map_sg(lrbp);
>         if (err)
>                 goto out;
> @@ -671,6 +762,139 @@ out:
>         return err;
>  }
>
> +static int ufshcd_compose_internal_cmd(struct ufs_hba *hba,
> +               struct ufshcd_lrb *lrbp, enum internal_cmd_type cmd_type)
> +{
> +       lrbp->cmd = NULL;
> +       lrbp->sense_bufflen = 0;
> +       lrbp->sense_buffer = NULL;
> +       lrbp->task_tag = INTERNAL_CMD_TAG;
> +       lrbp->lun = 0; /* internal cmd is not specific to any LUN */
> +       lrbp->command_type = UTP_CMD_TYPE_DEV_MANAGE;
> +       lrbp->intr_cmd = true; /* No interrupt aggregation */
> +       hba->i_cmd.dev_cmd_type = cmd_type;
> +
> +       return ufshcd_compose_upiu(hba, lrbp);
> +}
> +
> +static int ufshcd_wait_for_internal_cmd(struct ufs_hba *hba,
> +               struct ufshcd_lrb *lrbp, int max_timeout)
> +{
> +       int err = 0;
> +       unsigned long timeout;
> +       unsigned long flags;
> +
> +       timeout = wait_for_completion_timeout(hba->i_cmd.dev_cmd_complete,
> +                       msecs_to_jiffies(max_timeout));
> +
> +       spin_lock_irqsave(hba->host->host_lock, flags);
> +       hba->i_cmd.dev_cmd_complete = NULL;
> +       if (timeout)
> +               err = ufshcd_get_tr_ocs(lrbp);
> +       else
> +               err = -ETIMEDOUT;
> +       spin_unlock_irqrestore(hba->host->host_lock, flags);
> +
> +       return err;
> +}
> +
> +static int
> +ufshcd_clear_cmd(struct ufs_hba *hba, int tag)
> +{
> +       int err = 0;
> +       unsigned long flags;
> +       u32 reg;
> +       u32 mask = 1 << tag;
> +
> +       /* clear outstanding transaction before retry */
> +       spin_lock_irqsave(hba->host->host_lock, flags);
> +       ufshcd_utrl_clear(hba, INTERNAL_CMD_TAG);
> +       spin_unlock_irqrestore(hba->host->host_lock, flags);
> +
> +       /* poll for max. 1 sec to clear door bell register by h/w */
> +       reg = ufshcd_wait_for_register(hba,
> +                       REG_UTP_TRANSFER_REQ_DOOR_BELL,
> +                       mask, mask, 1000, 1000);
> +       if ((reg & mask) == mask)
> +               err = -ETIMEDOUT;
> +
> +       return err;
> +}
> +
> +/**
> + * ufshcd_internal_cmd_completion() - handles internal command responses
> + * @hba: per adapter instance
> + * @lrbp: pointer to local reference block
> + */
> +static int
> +ufshcd_internal_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
> +{
> +       int resp;
> +       int err = 0;
> +
> +       resp = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr);
> +
> +       switch (resp) {
> +       case UPIU_TRANSACTION_NOP_IN:
> +               break;
> +       case UPIU_TRANSACTION_REJECT_UPIU:
> +               /* TODO: handle Reject UPIU Response */
> +               dev_err(hba->dev, "Reject UPIU not fully implemented\n");
> +               err = -EPERM;
> +               break;
> +       default:
> +               dev_err(hba->dev, "Invalid internal cmd response: %x\n", resp);
> +               err = -EINVAL;
> +               break;
> +       }
> +
> +       return err;
> +}
> +
> +/**
> + * ufshcd_exec_internal_cmd() - API for sending internal
> + * requests
> + * @hba - UFS hba
> + * @cmd_type - specifies the type (NOP, Query...)
> + * @timeout - time in seconds
> + *
> + * NOTE: There is only one available tag for internal commands. Thus
> + * synchronisation is the responsibilty of the user.
> + */
> +static int ufshcd_exec_internal_cmd(struct ufs_hba *hba,
> +               enum internal_cmd_type cmd_type, int timeout)
> +{
> +       struct ufshcd_lrb *lrbp;
> +       int err;
> +       struct completion wait;
> +       unsigned long flags;
> +
> +       init_completion(&wait);
> +       lrbp = &hba->lrb[INTERNAL_CMD_TAG];
> +
> +       err = ufshcd_compose_internal_cmd(hba, lrbp, cmd_type);
> +       if (unlikely(err))
> +               goto out;
> +
> +       hba->i_cmd.dev_cmd_complete = &wait;
> +
> +       spin_lock_irqsave(hba->host->host_lock, flags);
> +       ufshcd_send_command(hba, INTERNAL_CMD_TAG);
> +       spin_unlock_irqrestore(hba->host->host_lock, flags);
> +
> +       err = ufshcd_wait_for_internal_cmd(hba, lrbp, timeout);
> +
> +       if (err == -ETIMEDOUT) {
> +               if (!ufshcd_clear_cmd(hba, INTERNAL_CMD_TAG))
> +                       err = -EAGAIN;
> +       } else if (!err) {
> +               err = ufshcd_internal_cmd_completion(hba, lrbp);
> +       }
> +
> +out:
> +       return err;
> +}
> +
>  /**
>   * ufshcd_memory_alloc - allocate memory for host memory space data structures
>   * @hba: per adapter instance
> @@ -805,8 +1029,8 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba)
>                                 cpu_to_le16(ALIGNED_UPIU_SIZE);
>
>                 hba->lrb[i].utr_descriptor_ptr = (utrdlp + i);
> -               hba->lrb[i].ucd_cmd_ptr =
> -                       (struct utp_upiu_cmd *)(cmd_descp + i);
> +               hba->lrb[i].ucd_req_ptr =
> +                       (struct utp_upiu_req *)(cmd_descp + i);
>                 hba->lrb[i].ucd_rsp_ptr =
>                         (struct utp_upiu_rsp *)cmd_descp[i].response_upiu;
>                 hba->lrb[i].ucd_prdt_ptr =
> @@ -992,6 +1216,38 @@ out:
>  }
>
>  /**
> + * ufshcd_validate_dev_connection() - Check device connection status
> + * @hba: per-adapter instance
> + *
> + * Send NOP OUT UPIU and wait for NOP IN response to check whether the
> + * device Transport Protocol (UTP) layer is ready after a reset.
> + * If the UTP layer at the device side is not initialized, it may
> + * not respond with NOP IN UPIU within timeout of %NOP_OUT_TIMEOUT
> + * and we retry sending NOP OUT for %NOP_OUT_RETRIES iterations.
> + */
> +static int ufshcd_validate_dev_connection(struct ufs_hba *hba)
> +{
> +       int err = 0;
> +       int retries;
> +
> +       for (retries = NOP_OUT_RETRIES; retries > 0; retries--) {
> +               mutex_lock(&hba->i_cmd.dev_cmd_lock);
> +               err = ufshcd_exec_internal_cmd(hba, DEV_CMD_TYPE_NOP,
> +                                              NOP_OUT_TIMEOUT);
> +               mutex_unlock(&hba->i_cmd.dev_cmd_lock);
> +
> +               if (!err || err == -ETIMEDOUT)
> +                       break;
> +
> +               dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
> +       }
> +
> +       if (err)
> +               dev_err(hba->dev, "%s: NOP OUT failed %d\n", __func__, err);
> +       return err;
> +}
> +
> +/**
>   * ufshcd_do_reset - reset the host controller
>   * @hba: per adapter instance
>   *
> @@ -1014,16 +1270,22 @@ static int ufshcd_do_reset(struct ufs_hba *hba)
>         spin_unlock_irqrestore(hba->host->host_lock, flags);
>
>         /* abort outstanding commands */
> -       for (tag = 0; tag < hba->nutrs; tag++) {
> +       for (tag = 0; tag < SCSI_CMD_QUEUE_SIZE; tag++) {
>                 if (test_bit(tag, &hba->outstanding_reqs)) {
>                         lrbp = &hba->lrb[tag];
> -                       scsi_dma_unmap(lrbp->cmd);
> -                       lrbp->cmd->result = DID_RESET << 16;
> -                       lrbp->cmd->scsi_done(lrbp->cmd);
> -                       lrbp->cmd = NULL;
> +                       if (lrbp->cmd) {
> +                               scsi_dma_unmap(lrbp->cmd);
> +                               lrbp->cmd->result = DID_RESET << 16;
> +                               lrbp->cmd->scsi_done(lrbp->cmd);
> +                               lrbp->cmd = NULL;
> +                       }
>                 }
>         }
>
> +       /* complete internal command */
> +       if (hba->i_cmd.dev_cmd_complete)
> +               complete(hba->i_cmd.dev_cmd_complete);
> +
>         /* clear outstanding request/task bit maps */
>         hba->outstanding_reqs = 0;
>         hba->outstanding_tasks = 0;
> @@ -1068,7 +1330,7 @@ static int ufshcd_slave_alloc(struct scsi_device *sdev)
>          * SAM_STAT_TASK_SET_FULL, the LUN queue depth will be adjusted
>          * with scsi_adjust_queue_depth.
>          */
> -       scsi_activate_tcq(sdev, hba->nutrs);
> +       scsi_activate_tcq(sdev, SCSI_CMD_QUEUE_SIZE);
>         return 0;
>  }
>
> @@ -1081,7 +1343,7 @@ static void ufshcd_slave_destroy(struct scsi_device *sdev)
>         struct ufs_hba *hba;
>
>         hba = shost_priv(sdev->host);
> -       scsi_deactivate_tcq(sdev, hba->nutrs);
> +       scsi_deactivate_tcq(sdev, SCSI_CMD_QUEUE_SIZE);
>  }
>
>  /**
> @@ -1144,7 +1406,7 @@ static void ufshcd_adjust_lun_qdepth(struct scsi_cmnd *cmd)
>          * LUN queue depth can be obtained by counting outstanding commands
>          * on the LUN.
>          */
> -       for (i = 0; i < hba->nutrs; i++) {
> +       for (i = 0; i < SCSI_CMD_QUEUE_SIZE; i++) {
>                 if (test_bit(i, &hba->outstanding_reqs)) {
>
>                         /*
> @@ -1230,27 +1492,36 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
>
>         switch (ocs) {
>         case OCS_SUCCESS:
> -
>                 /* check if the returned transfer response is valid */
> -               result = ufshcd_is_valid_req_rsp(lrbp->ucd_rsp_ptr);
> -               if (result) {
> +               result = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr);
> +
> +               switch (result) {
> +               case UPIU_TRANSACTION_RESPONSE:
> +                       /*
> +                        * get the response UPIU result to extract
> +                        * the SCSI command status
> +                        */
> +                       result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
> +
> +                       /*
> +                        * get the result based on SCSI status response
> +                        * to notify the SCSI midlayer of the command status
> +                        */
> +                       scsi_status = result & MASK_SCSI_STATUS;
> +                       result = ufshcd_scsi_cmd_status(lrbp, scsi_status);
> +                       break;
> +               case UPIU_TRANSACTION_REJECT_UPIU:
> +                       /* TODO: handle Reject UPIU Response */
> +                       result = DID_ERROR << 16;
>                         dev_err(hba->dev,
> -                               "Invalid response = %x\n", result);
> +                               "Reject UPIU not fully implemented\n");
>                         break;
> +               default:
> +                       result = DID_ERROR << 16;
> +                       dev_err(hba->dev,
> +                               "Unexpected request response code = %x\n",
> +                               result);
>                 }
> -
> -               /*
> -                * get the response UPIU result to extract
> -                * the SCSI command status
> -                */
> -               result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
> -
> -               /*
> -                * get the result based on SCSI status response
> -                * to notify the SCSI midlayer of the command status
> -                */
> -               scsi_status = result & MASK_SCSI_STATUS;
> -               result = ufshcd_scsi_cmd_status(lrbp, scsi_status);
>                 break;
>         case OCS_ABORTED:
>                 result |= DID_ABORT << 16;
> @@ -1290,29 +1561,37 @@ static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
>   */
>  static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
>  {
> -       struct ufshcd_lrb *lrb;
> +       struct ufshcd_lrb *lrbp;
> +       struct scsi_cmnd *cmd;
>         unsigned long completed_reqs;
>         u32 tr_doorbell;
>         int result;
>         int index;
> +       bool int_aggr_reset = false;
>
> -       lrb = hba->lrb;
>         tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
>         completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
>
>         for (index = 0; index < hba->nutrs; index++) {
>                 if (test_bit(index, &completed_reqs)) {
> +                       lrbp = &hba->lrb[index];
> +                       cmd = lrbp->cmd;
>
> -                       result = ufshcd_transfer_rsp_status(hba, &lrb[index]);
> -
> -                       if (lrb[index].cmd) {
> -                               scsi_dma_unmap(lrb[index].cmd);
> -                               lrb[index].cmd->result = result;
> -                               lrb[index].cmd->scsi_done(lrb[index].cmd);
> +                       if (cmd) {
> +                               result = ufshcd_transfer_rsp_status(hba, lrbp);
> +                               scsi_dma_unmap(cmd);
> +                               cmd->result = result;
> +                               cmd->scsi_done(cmd);
>
>                                 /* Mark completed command as NULL in LRB */
> -                               lrb[index].cmd = NULL;
> +                               lrbp->cmd = NULL;
> +                       } else if (lrbp->command_type ==
> +                                       UTP_CMD_TYPE_DEV_MANAGE) {
> +                               if (hba->i_cmd.dev_cmd_complete)
> +                                       complete(hba->i_cmd.dev_cmd_complete);
>                         }
> +                       /* Don't reset counters for interrupt cmd */
> +                       int_aggr_reset |= !lrbp->intr_cmd;
>                 } /* end of if */
>         } /* end of for */
>
> @@ -1320,7 +1599,8 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
>         hba->outstanding_reqs ^= completed_reqs;
>
>         /* Reset interrupt aggregation counters */
> -       ufshcd_config_int_aggr(hba, INT_AGGR_RESET);
> +       if (int_aggr_reset)
> +               ufshcd_config_int_aggr(hba, INT_AGGR_RESET);
>  }
>
>  /**
> @@ -1463,10 +1743,10 @@ ufshcd_issue_tm_cmd(struct ufs_hba *hba,
>         task_req_upiup =
>                 (struct utp_upiu_task_req *) task_req_descp->task_req_upiu;
>         task_req_upiup->header.dword_0 =
> -               cpu_to_be32(UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, 0,
> -                                             lrbp->lun, lrbp->task_tag));
> +               UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, 0,
> +                                             lrbp->lun, lrbp->task_tag);
>         task_req_upiup->header.dword_1 =
> -       cpu_to_be32(UPIU_HEADER_DWORD(0, tm_function, 0, 0));
> +               UPIU_HEADER_DWORD(0, tm_function, 0, 0);
>
>         task_req_upiup->input_param1 = lrbp->lun;
>         task_req_upiup->input_param1 =
> @@ -1521,7 +1801,7 @@ static int ufshcd_device_reset(struct scsi_cmnd *cmd)
>         if (err == FAILED)
>                 goto out;
>
> -       for (pos = 0; pos < hba->nutrs; pos++) {
> +       for (pos = 0; pos < SCSI_CMD_QUEUE_SIZE; pos++) {
>                 if (test_bit(pos, &hba->outstanding_reqs) &&
>                     (hba->lrb[tag].lun == hba->lrb[pos].lun)) {
>
> @@ -1539,6 +1819,11 @@ static int ufshcd_device_reset(struct scsi_cmnd *cmd)
>                         }
>                 }
>         } /* end of for */
> +
> +       /* complete internal command */
> +       if (hba->i_cmd.dev_cmd_complete)
> +               complete(hba->i_cmd.dev_cmd_complete);
> +
>  out:
>         return err;
>  }
> @@ -1618,8 +1903,16 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)
>         int ret;
>
>         ret = ufshcd_link_startup(hba);
> -       if (!ret)
> -               scsi_scan_host(hba->host);
> +       if (ret)
> +               goto out;
> +
> +       ret = ufshcd_validate_dev_connection(hba);
> +       if (ret)
> +               goto out;
> +
> +       scsi_scan_host(hba->host);
> +out:
> +       return;
>  }
>
>  static struct scsi_host_template ufshcd_driver_template = {
> @@ -1771,8 +2064,8 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
>         /* Configure LRB */
>         ufshcd_host_memory_configure(hba);
>
> -       host->can_queue = hba->nutrs;
> -       host->cmd_per_lun = hba->nutrs;
> +       host->can_queue = SCSI_CMD_QUEUE_SIZE;


I don't think this is appropriate. Reserving a slot exclusively for
query/DM requests is not optimal.  can_queue should be changed
dynamically, scsi_adjust_queue_depth() maybe?

> +       host->cmd_per_lun = SCSI_CMD_QUEUE_SIZE;
>
>         host->max_id = UFSHCD_MAX_ID;
>         host->max_lun = UFSHCD_MAX_LUNS;
>         host->max_channel = UFSHCD_MAX_CHANNEL;
> @@ -1788,6 +2081,9 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
>         /* Initialize UIC command mutex */
>         mutex_init(&hba->uic_cmd_mutex);
>
> +       /* Initialize mutex for internal commands */
> +       mutex_init(&hba->i_cmd.dev_cmd_lock);
> +
>         /* IRQ registration */
>         err = request_irq(irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
>         if (err) {
> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> index 49590ee..e41fa5e 100644
> --- a/drivers/scsi/ufs/ufshcd.h
> +++ b/drivers/scsi/ufs/ufshcd.h
> @@ -68,6 +68,10 @@
>  #define UFSHCD "ufshcd"
>  #define UFSHCD_DRIVER_VERSION "0.2"
>
> +enum internal_cmd_type {
> +       DEV_CMD_TYPE_NOP                = 0x0,
> +};
> +
>  /**
>   * struct uic_command - UIC command structure
>   * @command: UIC command
> @@ -91,7 +95,7 @@ struct uic_command {
>  /**
>   * struct ufshcd_lrb - local reference block
>   * @utr_descriptor_ptr: UTRD address of the command
> - * @ucd_cmd_ptr: UCD address of the command
> + * @ucd_req_ptr: UCD address of the command
>   * @ucd_rsp_ptr: Response UPIU address for this command
>   * @ucd_prdt_ptr: PRDT address of the command
>   * @cmd: pointer to SCSI command
> @@ -101,10 +105,11 @@ struct uic_command {
>   * @command_type: SCSI, UFS, Query.
>   * @task_tag: Task tag of the command
>   * @lun: LUN of the command
> + * @intr_cmd: Interrupt command (doesn't participate in interrupt aggregation)
>   */
>  struct ufshcd_lrb {
>         struct utp_transfer_req_desc *utr_descriptor_ptr;
> -       struct utp_upiu_cmd *ucd_cmd_ptr;
> +       struct utp_upiu_req *ucd_req_ptr;
>         struct utp_upiu_rsp *ucd_rsp_ptr;
>         struct ufshcd_sg_entry *ucd_prdt_ptr;
>
> @@ -116,8 +121,20 @@ struct ufshcd_lrb {
>         int command_type;
>         int task_tag;
>         unsigned int lun;
> +       bool intr_cmd;
>  };
>
> +/**
> + * struct ufs_internal_cmd - all assosiated fields with internal commands
> + * @dev_cmd_type: device management command type - Query, NOP OUT
> + * @dev_cmd_lock: lock to allow one internal command at a time
> + * @dev_cmd_complete: internal commands completion
> + */
> +struct ufs_internal_cmd {
> +       enum internal_cmd_type dev_cmd_type;
> +       struct mutex dev_cmd_lock;
> +       struct completion *dev_cmd_complete;
> +};
>
>  /**
>   * struct ufs_hba - per adapter private structure
> @@ -146,6 +163,7 @@ struct ufshcd_lrb {
>   * @intr_mask: Interrupt Mask Bits
>   * @feh_workq: Work queue for fatal controller error handling
>   * @errors: HBA errors
> + * @i_cmd: ufs internal command information
>   */
>  struct ufs_hba {
>         void __iomem *mmio_base;
> @@ -188,6 +206,9 @@ struct ufs_hba {
>
>         /* HBA Errors */
>         u32 errors;
> +
> +       /* Internal Request data */
> +       struct ufs_internal_cmd i_cmd;
>  };
>
>  #define ufshcd_writel(hba, val, reg)   \
> --
> 1.7.6
> --

--
~Santosh

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

* Re: [PATCH 2/2] scsi: ufs: Set fDeviceInit flag to initiate device initialization
  2013-06-10 14:05   ` Dolev Raviv
  (?)
@ 2013-06-12  5:34   ` Santosh Y
  2013-06-13  4:36     ` Sujit Reddy Thumma
  -1 siblings, 1 reply; 14+ messages in thread
From: Santosh Y @ 2013-06-12  5:34 UTC (permalink / raw)
  To: Dolev Raviv; +Cc: linux-scsi, linux-arm-msm, Sujit Reddy Thumma, open list

>
>  /**
> + *  ufshcd_query_request() - API for issuing query request to the device.
> + *  @hba: ufs driver context
> + *  @query: params for query request
> + *  @descriptor: buffer for sending/receiving descriptor
> + *  @retries: number of times to try executing the command
> + *
> + *   All necessary fields for issuing a query and receiving its response
> + *   are stored in the UFS hba struct. We can use this method since we know
> + *   there is only one active query request or any internal command at all
> + *   times.
> + */
> +static int ufshcd_send_query_request(struct ufs_hba *hba,
> +                                       struct ufs_query_req *query,
> +                                       u8 *descriptor,
> +                                       struct ufs_query_res *response)
> +{
> +       int ret;
> +
> +       BUG_ON(!hba);
> +       if (!query || !response) {
> +               dev_err(hba->dev,
> +                       "%s: NULL pointer query = %p, response = %p\n",
> +                       __func__, query, response);
> +               return -EINVAL;
> +       }
> +
> +       mutex_lock(&hba->i_cmd.dev_cmd_lock);
> +       hba->i_cmd.query.request = query;
> +       hba->i_cmd.query.response = response;
> +       hba->i_cmd.query.descriptor = descriptor;
> +
> +       ret = ufshcd_exec_internal_cmd(hba, DEV_CMD_TYPE_QUERY,
> +                                       QUERY_REQ_TIMEOUT);

Can this be generic, as external query commands might also use it?

> +
> +       hba->i_cmd.query.request = NULL;
> +       hba->i_cmd.query.response = NULL;
> +       hba->i_cmd.query.descriptor = NULL;
> +       mutex_unlock(&hba->i_cmd.dev_cmd_lock);
> +
> +       return ret;
> +}
> +
> +/**


-- 
~Santosh

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

* Re: [PATCH 1/2] scsi: ufs: Add support for sending NOP OUT UPIU
  2013-06-12  5:30   ` Santosh Y
@ 2013-06-13  4:33     ` Sujit Reddy Thumma
  2013-06-14  7:40       ` Sujit Reddy Thumma
  0 siblings, 1 reply; 14+ messages in thread
From: Sujit Reddy Thumma @ 2013-06-13  4:33 UTC (permalink / raw)
  To: Santosh Y; +Cc: Dolev Raviv, linux-scsi, linux-arm-msm, open list

On 6/12/2013 11:00 AM, Santosh Y wrote:
>> +/*
>> + * ufshcd_wait_for_register - wait for register value to change
>> + * @hba - per-adapter interface
>> + * @reg - mmio register offset
>> + * @mask - mask to apply to read register value
>> + * @val - wait condition
>> + * @interval_us - polling interval in microsecs
>> + * @timeout_ms - timeout in millisecs
>> + *
>> + * Returns final register value after iteration
>> + */
>> +static u32 ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
>> +               u32 val, unsigned long interval_us, unsigned long timeout_ms)
>> +{
>> +       u32 tmp;
>> +       ktime_t start;
>> +       unsigned long diff;
>> +
>> +       tmp = ufshcd_readl(hba, reg);
>> +
>> +       start = ktime_get();
>> +       while ((tmp & mask) == val) {
>
>
> ...as now I notice it, 'val' is the wait condition and the loop
> continues if the wait condition is met. I feel it's a bit confusing.
> Wouldn't something like (x != wait_condition) be appropriate?

Makes sense.

>
>> +               /* wakeup within 50us of expiry */
>> +               usleep_range(interval_us, interval_us + 50);
>> +               tmp = ufshcd_readl(hba, reg);
>> +               diff = ktime_to_ms(ktime_sub(ktime_get(), start));
>> +               if (diff > timeout_ms) {
>> +                       tmp = ufshcd_readl(hba, reg);
>
> Why this extra read? The register value might have changed during the
> execution of 2 previous statements, is that the assumption?

Yes, if there is a preemption between the last register read and the 
diff calculation and the CPU comes back after long time, it can happen 
that diff is greater than timeout and we enter the if condition. So, it 
is better to read the value after a timeout and return to the caller.

>
>> +                       break;
>> +               }
>> +       }
>> +
>> +       return tmp;
>> +}
>> +
>>   /**
>>    * ufshcd_get_intr_mask - Get the interrupt bit mask
>>    * @hba - Pointer to adapter instance
>> @@ -223,18 +267,13 @@ static inline void ufshcd_free_hba_memory(struct ufs_hba *hba)
>>   }
>>
>>   /**
>> - * ufshcd_is_valid_req_rsp - checks if controller TR response is valid
>> + * ufshcd_get_req_rsp - returns the TR response
>>    * @ucd_rsp_ptr: pointer to response UPIU
>> - *
>> - * This function checks the response UPIU for valid transaction type in
>> - * response field
>> - * Returns 0 on success, non-zero on failure
>>    */
>>   static inline int
>> -ufshcd_is_valid_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr)
>> +ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr)
>>   {
>> -       return ((be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24) ==
>> -                UPIU_TRANSACTION_RESPONSE) ? 0 : DID_ERROR << 16;
>> +       return be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24;
>>   }
>>
>>   /**
>> @@ -331,9 +370,9 @@ static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp)
>>   {
>>          int len;
>>          if (lrbp->sense_buffer) {
>> -               len = be16_to_cpu(lrbp->ucd_rsp_ptr->sense_data_len);
>> +               len = be16_to_cpu(lrbp->ucd_rsp_ptr->sc.sense_data_len);
>>                  memcpy(lrbp->sense_buffer,
>> -                       lrbp->ucd_rsp_ptr->sense_data,
>> +                       lrbp->ucd_rsp_ptr->sc.sense_data,
>>                          min_t(int, len, SCSI_SENSE_BUFFERSIZE));
>>          }
>>   }
>> @@ -551,76 +590,128 @@ static void ufshcd_disable_intr(struct ufs_hba *hba, u32 intrs)
>>   }
>>
>>   /**
>> + * ufshcd_prepare_req_desc() - Fills the requests header
>> + * descriptor according to request
>> + * @lrbp: pointer to local reference block
>> + * @upiu_flags: flags required in the header
>> + * @cmd_dir: requests data direction
>> + */
>> +static void ufshcd_prepare_req_desc(struct ufshcd_lrb *lrbp, u32 *upiu_flags,
>> +               enum dma_data_direction cmd_dir)
>> +{
>> +       struct utp_transfer_req_desc *req_desc = lrbp->utr_descriptor_ptr;
>> +       u32 data_direction;
>> +       u32 dword_0;
>> +
>> +       if (cmd_dir == DMA_FROM_DEVICE) {
>> +               data_direction = UTP_DEVICE_TO_HOST;
>> +               *upiu_flags = UPIU_CMD_FLAGS_READ;
>> +       } else if (cmd_dir == DMA_TO_DEVICE) {
>> +               data_direction = UTP_HOST_TO_DEVICE;
>> +               *upiu_flags = UPIU_CMD_FLAGS_WRITE;
>> +       } else {
>> +               data_direction = UTP_NO_DATA_TRANSFER;
>> +               *upiu_flags = UPIU_CMD_FLAGS_NONE;
>> +       }
>> +
>> +       dword_0 = data_direction | (lrbp->command_type
>> +                               << UPIU_COMMAND_TYPE_OFFSET);
>> +       if (lrbp->intr_cmd)
>> +               dword_0 |= UTP_REQ_DESC_INT_CMD;
>> +
>> +       /* Transfer request descriptor header fields */
>> +       req_desc->header.dword_0 = cpu_to_le32(dword_0);
>> +
>> +       /*
>> +        * assigning invalid value for command status. Controller
>> +        * updates OCS on command completion, with the command
>> +        * status
>> +        */
>> +       req_desc->header.dword_2 =
>> +               cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
>> +}
>> +
>> +/**
>> + * ufshcd_prepare_utp_scsi_cmd_upiu() - fills the utp_transfer_req_desc,
>> + * for scsi commands
>> + * @lrbp - local reference block pointer
>> + * @upiu_flags - flags
>> + */
>> +static
>> +void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u32 upiu_flags)
>> +{
>> +       struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
>> +
>> +       /* command descriptor fields */
>> +       ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD(
>> +                               UPIU_TRANSACTION_COMMAND, upiu_flags,
>> +                               lrbp->lun, lrbp->task_tag);
>> +       ucd_req_ptr->header.dword_1 = UPIU_HEADER_DWORD(
>> +                               UPIU_COMMAND_SET_TYPE_SCSI, 0, 0, 0);
>> +
>> +       /* Total EHS length and Data segment length will be zero */
>> +       ucd_req_ptr->header.dword_2 = 0;
>> +
>> +       ucd_req_ptr->sc.exp_data_transfer_len =
>> +               cpu_to_be32(lrbp->cmd->sdb.length);
>> +
>> +       memcpy(ucd_req_ptr->sc.cdb, lrbp->cmd->cmnd,
>> +               (min_t(unsigned short, lrbp->cmd->cmd_len, MAX_CDB_SIZE)));
>> +}
>> +
>> +static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp)
>> +{
>> +       struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
>> +
>> +       memset(ucd_req_ptr, 0, sizeof(struct utp_upiu_req));
>> +
>> +       /* command descriptor fields */
>> +       ucd_req_ptr->header.dword_0 =
>> +               UPIU_HEADER_DWORD(
>> +                       UPIU_TRANSACTION_NOP_OUT, 0, 0, lrbp->task_tag);
>> +}
>> +
>> +/**
>>    * ufshcd_compose_upiu - form UFS Protocol Information Unit(UPIU)
>> + * @hba - per adapter instance
>>    * @lrb - pointer to local reference block
>>    */
>> -static void ufshcd_compose_upiu(struct ufshcd_lrb *lrbp)
>> +static int ufshcd_compose_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
>>   {
>> -       struct utp_transfer_req_desc *req_desc;
>> -       struct utp_upiu_cmd *ucd_cmd_ptr;
>> -       u32 data_direction;
>>          u32 upiu_flags;
>> -
>> -       ucd_cmd_ptr = lrbp->ucd_cmd_ptr;
>> -       req_desc = lrbp->utr_descriptor_ptr;
>> +       int ret = 0;
>>
>>          switch (lrbp->command_type) {
>>          case UTP_CMD_TYPE_SCSI:
>> -               if (lrbp->cmd->sc_data_direction == DMA_FROM_DEVICE) {
>> -                       data_direction = UTP_DEVICE_TO_HOST;
>> -                       upiu_flags = UPIU_CMD_FLAGS_READ;
>> -               } else if (lrbp->cmd->sc_data_direction == DMA_TO_DEVICE) {
>> -                       data_direction = UTP_HOST_TO_DEVICE;
>> -                       upiu_flags = UPIU_CMD_FLAGS_WRITE;
>> +               if (likely(lrbp->cmd)) {
>> +                       ufshcd_prepare_req_desc(lrbp, &upiu_flags,
>> +                                       lrbp->cmd->sc_data_direction);
>> +                       ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags);
>>                  } else {
>> -                       data_direction = UTP_NO_DATA_TRANSFER;
>> -                       upiu_flags = UPIU_CMD_FLAGS_NONE;
>> +                       ret = -EINVAL;
>>                  }
>> -
>> -               /* Transfer request descriptor header fields */
>> -               req_desc->header.dword_0 =
>> -                       cpu_to_le32(data_direction | UTP_SCSI_COMMAND);
>> -
>> -               /*
>> -                * assigning invalid value for command status. Controller
>> -                * updates OCS on command completion, with the command
>> -                * status
>> -                */
>> -               req_desc->header.dword_2 =
>> -                       cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
>> -
>> -               /* command descriptor fields */
>> -               ucd_cmd_ptr->header.dword_0 =
>> -                       cpu_to_be32(UPIU_HEADER_DWORD(UPIU_TRANSACTION_COMMAND,
>> -                                                     upiu_flags,
>> -                                                     lrbp->lun,
>> -                                                     lrbp->task_tag));
>> -               ucd_cmd_ptr->header.dword_1 =
>> -                       cpu_to_be32(
>> -                               UPIU_HEADER_DWORD(UPIU_COMMAND_SET_TYPE_SCSI,
>> -                                                 0,
>> -                                                 0,
>> -                                                 0));
>> -
>> -               /* Total EHS length and Data segment length will be zero */
>> -               ucd_cmd_ptr->header.dword_2 = 0;
>> -
>> -               ucd_cmd_ptr->exp_data_transfer_len =
>> -                       cpu_to_be32(lrbp->cmd->sdb.length);
>> -
>> -               memcpy(ucd_cmd_ptr->cdb,
>> -                      lrbp->cmd->cmnd,
>> -                      (min_t(unsigned short,
>> -                             lrbp->cmd->cmd_len,
>> -                             MAX_CDB_SIZE)));
>>                  break;
>>          case UTP_CMD_TYPE_DEV_MANAGE:
>> -               /* For query function implementation */
>> +               ufshcd_prepare_req_desc(lrbp, &upiu_flags, DMA_NONE);
>> +               if (hba->i_cmd.dev_cmd_type == DEV_CMD_TYPE_NOP)
>> +                       ufshcd_prepare_utp_nop_upiu(lrbp);
>> +               else
>> +                       ret = -EINVAL;
>>                  break;
>>          case UTP_CMD_TYPE_UFS:
>>                  /* For UFS native command implementation */
>> +               dev_err(hba->dev, "%s: UFS native command are not supported\n",
>> +                       __func__);
>> +               ret = -ENOTSUPP;
>> +               break;
>> +       default:
>> +               ret = -ENOTSUPP;
>> +               dev_err(hba->dev, "%s: unknown command type: 0x%x\n",
>> +                               __func__, lrbp->command_type);
>>                  break;
>>          } /* end of switch */
>> +
>> +       return ret;
>>   }
>>
>>   /**
>> @@ -654,11 +745,11 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
>>          lrbp->sense_buffer = cmd->sense_buffer;
>>          lrbp->task_tag = tag;
>>          lrbp->lun = cmd->device->lun;
>> -
>> +       lrbp->intr_cmd = false;
>>          lrbp->command_type = UTP_CMD_TYPE_SCSI;
>>
>>          /* form UPIU before issuing the command */
>> -       ufshcd_compose_upiu(lrbp);
>> +       ufshcd_compose_upiu(hba, lrbp);
>>          err = ufshcd_map_sg(lrbp);
>>          if (err)
>>                  goto out;
>> @@ -671,6 +762,139 @@ out:
>>          return err;
>>   }
>>
>> +static int ufshcd_compose_internal_cmd(struct ufs_hba *hba,
>> +               struct ufshcd_lrb *lrbp, enum internal_cmd_type cmd_type)
>> +{
>> +       lrbp->cmd = NULL;
>> +       lrbp->sense_bufflen = 0;
>> +       lrbp->sense_buffer = NULL;
>> +       lrbp->task_tag = INTERNAL_CMD_TAG;
>> +       lrbp->lun = 0; /* internal cmd is not specific to any LUN */
>> +       lrbp->command_type = UTP_CMD_TYPE_DEV_MANAGE;
>> +       lrbp->intr_cmd = true; /* No interrupt aggregation */
>> +       hba->i_cmd.dev_cmd_type = cmd_type;
>> +
>> +       return ufshcd_compose_upiu(hba, lrbp);
>> +}
>> +
>> +static int ufshcd_wait_for_internal_cmd(struct ufs_hba *hba,
>> +               struct ufshcd_lrb *lrbp, int max_timeout)
>> +{
>> +       int err = 0;
>> +       unsigned long timeout;
>> +       unsigned long flags;
>> +
>> +       timeout = wait_for_completion_timeout(hba->i_cmd.dev_cmd_complete,
>> +                       msecs_to_jiffies(max_timeout));
>> +
>> +       spin_lock_irqsave(hba->host->host_lock, flags);
>> +       hba->i_cmd.dev_cmd_complete = NULL;
>> +       if (timeout)
>> +               err = ufshcd_get_tr_ocs(lrbp);
>> +       else
>> +               err = -ETIMEDOUT;
>> +       spin_unlock_irqrestore(hba->host->host_lock, flags);
>> +
>> +       return err;
>> +}
>> +
>> +static int
>> +ufshcd_clear_cmd(struct ufs_hba *hba, int tag)
>> +{
>> +       int err = 0;
>> +       unsigned long flags;
>> +       u32 reg;
>> +       u32 mask = 1 << tag;
>> +
>> +       /* clear outstanding transaction before retry */
>> +       spin_lock_irqsave(hba->host->host_lock, flags);
>> +       ufshcd_utrl_clear(hba, INTERNAL_CMD_TAG);
>> +       spin_unlock_irqrestore(hba->host->host_lock, flags);
>> +
>> +       /* poll for max. 1 sec to clear door bell register by h/w */
>> +       reg = ufshcd_wait_for_register(hba,
>> +                       REG_UTP_TRANSFER_REQ_DOOR_BELL,
>> +                       mask, mask, 1000, 1000);
>> +       if ((reg & mask) == mask)
>> +               err = -ETIMEDOUT;
>> +
>> +       return err;
>> +}
>> +
>> +/**
>> + * ufshcd_internal_cmd_completion() - handles internal command responses
>> + * @hba: per adapter instance
>> + * @lrbp: pointer to local reference block
>> + */
>> +static int
>> +ufshcd_internal_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
>> +{
>> +       int resp;
>> +       int err = 0;
>> +
>> +       resp = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr);
>> +
>> +       switch (resp) {
>> +       case UPIU_TRANSACTION_NOP_IN:
>> +               break;
>> +       case UPIU_TRANSACTION_REJECT_UPIU:
>> +               /* TODO: handle Reject UPIU Response */
>> +               dev_err(hba->dev, "Reject UPIU not fully implemented\n");
>> +               err = -EPERM;
>> +               break;
>> +       default:
>> +               dev_err(hba->dev, "Invalid internal cmd response: %x\n", resp);
>> +               err = -EINVAL;
>> +               break;
>> +       }
>> +
>> +       return err;
>> +}
>> +
>> +/**
>> + * ufshcd_exec_internal_cmd() - API for sending internal
>> + * requests
>> + * @hba - UFS hba
>> + * @cmd_type - specifies the type (NOP, Query...)
>> + * @timeout - time in seconds
>> + *
>> + * NOTE: There is only one available tag for internal commands. Thus
>> + * synchronisation is the responsibilty of the user.
>> + */
>> +static int ufshcd_exec_internal_cmd(struct ufs_hba *hba,
>> +               enum internal_cmd_type cmd_type, int timeout)
>> +{
>> +       struct ufshcd_lrb *lrbp;
>> +       int err;
>> +       struct completion wait;
>> +       unsigned long flags;
>> +
>> +       init_completion(&wait);
>> +       lrbp = &hba->lrb[INTERNAL_CMD_TAG];
>> +
>> +       err = ufshcd_compose_internal_cmd(hba, lrbp, cmd_type);
>> +       if (unlikely(err))
>> +               goto out;
>> +
>> +       hba->i_cmd.dev_cmd_complete = &wait;
>> +
>> +       spin_lock_irqsave(hba->host->host_lock, flags);
>> +       ufshcd_send_command(hba, INTERNAL_CMD_TAG);
>> +       spin_unlock_irqrestore(hba->host->host_lock, flags);
>> +
>> +       err = ufshcd_wait_for_internal_cmd(hba, lrbp, timeout);
>> +
>> +       if (err == -ETIMEDOUT) {
>> +               if (!ufshcd_clear_cmd(hba, INTERNAL_CMD_TAG))
>> +                       err = -EAGAIN;
>> +       } else if (!err) {
>> +               err = ufshcd_internal_cmd_completion(hba, lrbp);
>> +       }
>> +
>> +out:
>> +       return err;
>> +}
>> +
>>   /**
>>    * ufshcd_memory_alloc - allocate memory for host memory space data structures
>>    * @hba: per adapter instance
>> @@ -805,8 +1029,8 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba)
>>                                  cpu_to_le16(ALIGNED_UPIU_SIZE);
>>
>>                  hba->lrb[i].utr_descriptor_ptr = (utrdlp + i);
>> -               hba->lrb[i].ucd_cmd_ptr =
>> -                       (struct utp_upiu_cmd *)(cmd_descp + i);
>> +               hba->lrb[i].ucd_req_ptr =
>> +                       (struct utp_upiu_req *)(cmd_descp + i);
>>                  hba->lrb[i].ucd_rsp_ptr =
>>                          (struct utp_upiu_rsp *)cmd_descp[i].response_upiu;
>>                  hba->lrb[i].ucd_prdt_ptr =
>> @@ -992,6 +1216,38 @@ out:
>>   }
>>
>>   /**
>> + * ufshcd_validate_dev_connection() - Check device connection status
>> + * @hba: per-adapter instance
>> + *
>> + * Send NOP OUT UPIU and wait for NOP IN response to check whether the
>> + * device Transport Protocol (UTP) layer is ready after a reset.
>> + * If the UTP layer at the device side is not initialized, it may
>> + * not respond with NOP IN UPIU within timeout of %NOP_OUT_TIMEOUT
>> + * and we retry sending NOP OUT for %NOP_OUT_RETRIES iterations.
>> + */
>> +static int ufshcd_validate_dev_connection(struct ufs_hba *hba)
>> +{
>> +       int err = 0;
>> +       int retries;
>> +
>> +       for (retries = NOP_OUT_RETRIES; retries > 0; retries--) {
>> +               mutex_lock(&hba->i_cmd.dev_cmd_lock);
>> +               err = ufshcd_exec_internal_cmd(hba, DEV_CMD_TYPE_NOP,
>> +                                              NOP_OUT_TIMEOUT);
>> +               mutex_unlock(&hba->i_cmd.dev_cmd_lock);
>> +
>> +               if (!err || err == -ETIMEDOUT)
>> +                       break;
>> +
>> +               dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
>> +       }
>> +
>> +       if (err)
>> +               dev_err(hba->dev, "%s: NOP OUT failed %d\n", __func__, err);
>> +       return err;
>> +}
>> +
>> +/**
>>    * ufshcd_do_reset - reset the host controller
>>    * @hba: per adapter instance
>>    *
>> @@ -1014,16 +1270,22 @@ static int ufshcd_do_reset(struct ufs_hba *hba)
>>          spin_unlock_irqrestore(hba->host->host_lock, flags);
>>
>>          /* abort outstanding commands */
>> -       for (tag = 0; tag < hba->nutrs; tag++) {
>> +       for (tag = 0; tag < SCSI_CMD_QUEUE_SIZE; tag++) {
>>                  if (test_bit(tag, &hba->outstanding_reqs)) {
>>                          lrbp = &hba->lrb[tag];
>> -                       scsi_dma_unmap(lrbp->cmd);
>> -                       lrbp->cmd->result = DID_RESET << 16;
>> -                       lrbp->cmd->scsi_done(lrbp->cmd);
>> -                       lrbp->cmd = NULL;
>> +                       if (lrbp->cmd) {
>> +                               scsi_dma_unmap(lrbp->cmd);
>> +                               lrbp->cmd->result = DID_RESET << 16;
>> +                               lrbp->cmd->scsi_done(lrbp->cmd);
>> +                               lrbp->cmd = NULL;
>> +                       }
>>                  }
>>          }
>>
>> +       /* complete internal command */
>> +       if (hba->i_cmd.dev_cmd_complete)
>> +               complete(hba->i_cmd.dev_cmd_complete);
>> +
>>          /* clear outstanding request/task bit maps */
>>          hba->outstanding_reqs = 0;
>>          hba->outstanding_tasks = 0;
>> @@ -1068,7 +1330,7 @@ static int ufshcd_slave_alloc(struct scsi_device *sdev)
>>           * SAM_STAT_TASK_SET_FULL, the LUN queue depth will be adjusted
>>           * with scsi_adjust_queue_depth.
>>           */
>> -       scsi_activate_tcq(sdev, hba->nutrs);
>> +       scsi_activate_tcq(sdev, SCSI_CMD_QUEUE_SIZE);
>>          return 0;
>>   }
>>
>> @@ -1081,7 +1343,7 @@ static void ufshcd_slave_destroy(struct scsi_device *sdev)
>>          struct ufs_hba *hba;
>>
>>          hba = shost_priv(sdev->host);
>> -       scsi_deactivate_tcq(sdev, hba->nutrs);
>> +       scsi_deactivate_tcq(sdev, SCSI_CMD_QUEUE_SIZE);
>>   }
>>
>>   /**
>> @@ -1144,7 +1406,7 @@ static void ufshcd_adjust_lun_qdepth(struct scsi_cmnd *cmd)
>>           * LUN queue depth can be obtained by counting outstanding commands
>>           * on the LUN.
>>           */
>> -       for (i = 0; i < hba->nutrs; i++) {
>> +       for (i = 0; i < SCSI_CMD_QUEUE_SIZE; i++) {
>>                  if (test_bit(i, &hba->outstanding_reqs)) {
>>
>>                          /*
>> @@ -1230,27 +1492,36 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
>>
>>          switch (ocs) {
>>          case OCS_SUCCESS:
>> -
>>                  /* check if the returned transfer response is valid */
>> -               result = ufshcd_is_valid_req_rsp(lrbp->ucd_rsp_ptr);
>> -               if (result) {
>> +               result = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr);
>> +
>> +               switch (result) {
>> +               case UPIU_TRANSACTION_RESPONSE:
>> +                       /*
>> +                        * get the response UPIU result to extract
>> +                        * the SCSI command status
>> +                        */
>> +                       result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
>> +
>> +                       /*
>> +                        * get the result based on SCSI status response
>> +                        * to notify the SCSI midlayer of the command status
>> +                        */
>> +                       scsi_status = result & MASK_SCSI_STATUS;
>> +                       result = ufshcd_scsi_cmd_status(lrbp, scsi_status);
>> +                       break;
>> +               case UPIU_TRANSACTION_REJECT_UPIU:
>> +                       /* TODO: handle Reject UPIU Response */
>> +                       result = DID_ERROR << 16;
>>                          dev_err(hba->dev,
>> -                               "Invalid response = %x\n", result);
>> +                               "Reject UPIU not fully implemented\n");
>>                          break;
>> +               default:
>> +                       result = DID_ERROR << 16;
>> +                       dev_err(hba->dev,
>> +                               "Unexpected request response code = %x\n",
>> +                               result);
>>                  }
>> -
>> -               /*
>> -                * get the response UPIU result to extract
>> -                * the SCSI command status
>> -                */
>> -               result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr);
>> -
>> -               /*
>> -                * get the result based on SCSI status response
>> -                * to notify the SCSI midlayer of the command status
>> -                */
>> -               scsi_status = result & MASK_SCSI_STATUS;
>> -               result = ufshcd_scsi_cmd_status(lrbp, scsi_status);
>>                  break;
>>          case OCS_ABORTED:
>>                  result |= DID_ABORT << 16;
>> @@ -1290,29 +1561,37 @@ static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
>>    */
>>   static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
>>   {
>> -       struct ufshcd_lrb *lrb;
>> +       struct ufshcd_lrb *lrbp;
>> +       struct scsi_cmnd *cmd;
>>          unsigned long completed_reqs;
>>          u32 tr_doorbell;
>>          int result;
>>          int index;
>> +       bool int_aggr_reset = false;
>>
>> -       lrb = hba->lrb;
>>          tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
>>          completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
>>
>>          for (index = 0; index < hba->nutrs; index++) {
>>                  if (test_bit(index, &completed_reqs)) {
>> +                       lrbp = &hba->lrb[index];
>> +                       cmd = lrbp->cmd;
>>
>> -                       result = ufshcd_transfer_rsp_status(hba, &lrb[index]);
>> -
>> -                       if (lrb[index].cmd) {
>> -                               scsi_dma_unmap(lrb[index].cmd);
>> -                               lrb[index].cmd->result = result;
>> -                               lrb[index].cmd->scsi_done(lrb[index].cmd);
>> +                       if (cmd) {
>> +                               result = ufshcd_transfer_rsp_status(hba, lrbp);
>> +                               scsi_dma_unmap(cmd);
>> +                               cmd->result = result;
>> +                               cmd->scsi_done(cmd);
>>
>>                                  /* Mark completed command as NULL in LRB */
>> -                               lrb[index].cmd = NULL;
>> +                               lrbp->cmd = NULL;
>> +                       } else if (lrbp->command_type ==
>> +                                       UTP_CMD_TYPE_DEV_MANAGE) {
>> +                               if (hba->i_cmd.dev_cmd_complete)
>> +                                       complete(hba->i_cmd.dev_cmd_complete);
>>                          }
>> +                       /* Don't reset counters for interrupt cmd */
>> +                       int_aggr_reset |= !lrbp->intr_cmd;
>>                  } /* end of if */
>>          } /* end of for */
>>
>> @@ -1320,7 +1599,8 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
>>          hba->outstanding_reqs ^= completed_reqs;
>>
>>          /* Reset interrupt aggregation counters */
>> -       ufshcd_config_int_aggr(hba, INT_AGGR_RESET);
>> +       if (int_aggr_reset)
>> +               ufshcd_config_int_aggr(hba, INT_AGGR_RESET);
>>   }
>>
>>   /**
>> @@ -1463,10 +1743,10 @@ ufshcd_issue_tm_cmd(struct ufs_hba *hba,
>>          task_req_upiup =
>>                  (struct utp_upiu_task_req *) task_req_descp->task_req_upiu;
>>          task_req_upiup->header.dword_0 =
>> -               cpu_to_be32(UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, 0,
>> -                                             lrbp->lun, lrbp->task_tag));
>> +               UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, 0,
>> +                                             lrbp->lun, lrbp->task_tag);
>>          task_req_upiup->header.dword_1 =
>> -       cpu_to_be32(UPIU_HEADER_DWORD(0, tm_function, 0, 0));
>> +               UPIU_HEADER_DWORD(0, tm_function, 0, 0);
>>
>>          task_req_upiup->input_param1 = lrbp->lun;
>>          task_req_upiup->input_param1 =
>> @@ -1521,7 +1801,7 @@ static int ufshcd_device_reset(struct scsi_cmnd *cmd)
>>          if (err == FAILED)
>>                  goto out;
>>
>> -       for (pos = 0; pos < hba->nutrs; pos++) {
>> +       for (pos = 0; pos < SCSI_CMD_QUEUE_SIZE; pos++) {
>>                  if (test_bit(pos, &hba->outstanding_reqs) &&
>>                      (hba->lrb[tag].lun == hba->lrb[pos].lun)) {
>>
>> @@ -1539,6 +1819,11 @@ static int ufshcd_device_reset(struct scsi_cmnd *cmd)
>>                          }
>>                  }
>>          } /* end of for */
>> +
>> +       /* complete internal command */
>> +       if (hba->i_cmd.dev_cmd_complete)
>> +               complete(hba->i_cmd.dev_cmd_complete);
>> +
>>   out:
>>          return err;
>>   }
>> @@ -1618,8 +1903,16 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)
>>          int ret;
>>
>>          ret = ufshcd_link_startup(hba);
>> -       if (!ret)
>> -               scsi_scan_host(hba->host);
>> +       if (ret)
>> +               goto out;
>> +
>> +       ret = ufshcd_validate_dev_connection(hba);
>> +       if (ret)
>> +               goto out;
>> +
>> +       scsi_scan_host(hba->host);
>> +out:
>> +       return;
>>   }
>>
>>   static struct scsi_host_template ufshcd_driver_template = {
>> @@ -1771,8 +2064,8 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
>>          /* Configure LRB */
>>          ufshcd_host_memory_configure(hba);
>>
>> -       host->can_queue = hba->nutrs;
>> -       host->cmd_per_lun = hba->nutrs;
>> +       host->can_queue = SCSI_CMD_QUEUE_SIZE;
>
>
> I don't think this is appropriate. Reserving a slot exclusively for
> query/DM requests is not optimal.  can_queue should be changed
> dynamically, scsi_adjust_queue_depth() maybe?
>
>> +       host->cmd_per_lun = SCSI_CMD_QUEUE_SIZE;
>>
>>          host->max_id = UFSHCD_MAX_ID;
>>          host->max_lun = UFSHCD_MAX_LUNS;
>>          host->max_channel = UFSHCD_MAX_CHANNEL;
>> @@ -1788,6 +2081,9 @@ int ufshcd_init(struct device *dev, struct ufs_hba **hba_handle,
>>          /* Initialize UIC command mutex */
>>          mutex_init(&hba->uic_cmd_mutex);
>>
>> +       /* Initialize mutex for internal commands */
>> +       mutex_init(&hba->i_cmd.dev_cmd_lock);
>> +
>>          /* IRQ registration */
>>          err = request_irq(irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba);
>>          if (err) {
>> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
>> index 49590ee..e41fa5e 100644
>> --- a/drivers/scsi/ufs/ufshcd.h
>> +++ b/drivers/scsi/ufs/ufshcd.h
>> @@ -68,6 +68,10 @@
>>   #define UFSHCD "ufshcd"
>>   #define UFSHCD_DRIVER_VERSION "0.2"
>>
>> +enum internal_cmd_type {
>> +       DEV_CMD_TYPE_NOP                = 0x0,
>> +};
>> +
>>   /**
>>    * struct uic_command - UIC command structure
>>    * @command: UIC command
>> @@ -91,7 +95,7 @@ struct uic_command {
>>   /**
>>    * struct ufshcd_lrb - local reference block
>>    * @utr_descriptor_ptr: UTRD address of the command
>> - * @ucd_cmd_ptr: UCD address of the command
>> + * @ucd_req_ptr: UCD address of the command
>>    * @ucd_rsp_ptr: Response UPIU address for this command
>>    * @ucd_prdt_ptr: PRDT address of the command
>>    * @cmd: pointer to SCSI command
>> @@ -101,10 +105,11 @@ struct uic_command {
>>    * @command_type: SCSI, UFS, Query.
>>    * @task_tag: Task tag of the command
>>    * @lun: LUN of the command
>> + * @intr_cmd: Interrupt command (doesn't participate in interrupt aggregation)
>>    */
>>   struct ufshcd_lrb {
>>          struct utp_transfer_req_desc *utr_descriptor_ptr;
>> -       struct utp_upiu_cmd *ucd_cmd_ptr;
>> +       struct utp_upiu_req *ucd_req_ptr;
>>          struct utp_upiu_rsp *ucd_rsp_ptr;
>>          struct ufshcd_sg_entry *ucd_prdt_ptr;
>>
>> @@ -116,8 +121,20 @@ struct ufshcd_lrb {
>>          int command_type;
>>          int task_tag;
>>          unsigned int lun;
>> +       bool intr_cmd;
>>   };
>>
>> +/**
>> + * struct ufs_internal_cmd - all assosiated fields with internal commands
>> + * @dev_cmd_type: device management command type - Query, NOP OUT
>> + * @dev_cmd_lock: lock to allow one internal command at a time
>> + * @dev_cmd_complete: internal commands completion
>> + */
>> +struct ufs_internal_cmd {
>> +       enum internal_cmd_type dev_cmd_type;
>> +       struct mutex dev_cmd_lock;
>> +       struct completion *dev_cmd_complete;
>> +};
>>
>>   /**
>>    * struct ufs_hba - per adapter private structure
>> @@ -146,6 +163,7 @@ struct ufshcd_lrb {
>>    * @intr_mask: Interrupt Mask Bits
>>    * @feh_workq: Work queue for fatal controller error handling
>>    * @errors: HBA errors
>> + * @i_cmd: ufs internal command information
>>    */
>>   struct ufs_hba {
>>          void __iomem *mmio_base;
>> @@ -188,6 +206,9 @@ struct ufs_hba {
>>
>>          /* HBA Errors */
>>          u32 errors;
>> +
>> +       /* Internal Request data */
>> +       struct ufs_internal_cmd i_cmd;
>>   };
>>
>>   #define ufshcd_writel(hba, val, reg)   \
>> --
>> 1.7.6
>> --
>
> --
> ~Santosh
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

-- 
Regards,
Sujit

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

* Re: [PATCH 2/2] scsi: ufs: Set fDeviceInit flag to initiate device initialization
  2013-06-12  5:34   ` Santosh Y
@ 2013-06-13  4:36     ` Sujit Reddy Thumma
  2013-06-14 13:55       ` Santosh Y
  0 siblings, 1 reply; 14+ messages in thread
From: Sujit Reddy Thumma @ 2013-06-13  4:36 UTC (permalink / raw)
  To: Santosh Y; +Cc: Dolev Raviv, linux-scsi, linux-arm-msm, open list

On 6/12/2013 11:04 AM, Santosh Y wrote:
>>
>>   /**
>> + *  ufshcd_query_request() - API for issuing query request to the device.
>> + *  @hba: ufs driver context
>> + *  @query: params for query request
>> + *  @descriptor: buffer for sending/receiving descriptor
>> + *  @retries: number of times to try executing the command
>> + *
>> + *   All necessary fields for issuing a query and receiving its response
>> + *   are stored in the UFS hba struct. We can use this method since we know
>> + *   there is only one active query request or any internal command at all
>> + *   times.
>> + */
>> +static int ufshcd_send_query_request(struct ufs_hba *hba,
>> +                                       struct ufs_query_req *query,
>> +                                       u8 *descriptor,
>> +                                       struct ufs_query_res *response)
>> +{
>> +       int ret;
>> +
>> +       BUG_ON(!hba);
>> +       if (!query || !response) {
>> +               dev_err(hba->dev,
>> +                       "%s: NULL pointer query = %p, response = %p\n",
>> +                       __func__, query, response);
>> +               return -EINVAL;
>> +       }
>> +
>> +       mutex_lock(&hba->i_cmd.dev_cmd_lock);
>> +       hba->i_cmd.query.request = query;
>> +       hba->i_cmd.query.response = response;
>> +       hba->i_cmd.query.descriptor = descriptor;
>> +
>> +       ret = ufshcd_exec_internal_cmd(hba, DEV_CMD_TYPE_QUERY,
>> +                                       QUERY_REQ_TIMEOUT);
>
> Can this be generic, as external query commands might also use it?

External query commands can call ufshcd_send_query_request() directly, 
without going into hassle of taking mutex lock and filling internal cmd 
structure.

>
>> +
>> +       hba->i_cmd.query.request = NULL;
>> +       hba->i_cmd.query.response = NULL;
>> +       hba->i_cmd.query.descriptor = NULL;
>> +       mutex_unlock(&hba->i_cmd.dev_cmd_lock);
>> +
>> +       return ret;
>> +}
>> +
>> +/**
>
>

-- 
Regards,
Sujit

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

* Re: [PATCH 1/2] scsi: ufs: Add support for sending NOP OUT UPIU
  2013-06-13  4:33     ` Sujit Reddy Thumma
@ 2013-06-14  7:40       ` Sujit Reddy Thumma
  2013-06-14 13:47         ` Santosh Y
  0 siblings, 1 reply; 14+ messages in thread
From: Sujit Reddy Thumma @ 2013-06-14  7:40 UTC (permalink / raw)
  To: Santosh Y; +Cc: Dolev Raviv, linux-scsi, linux-arm-msm, open list

On 6/13/2013 10:03 AM, Sujit Reddy Thumma wrote:
>>   static struct scsi_host_template ufshcd_driver_template = {
>> @@ -1771,8 +2064,8 @@ int ufshcd_init(struct device *dev, struct
>> ufs_hba **hba_handle,
>>          /* Configure LRB */
>>          ufshcd_host_memory_configure(hba);
>>
>> -       host->can_queue = hba->nutrs;
>> -       host->cmd_per_lun = hba->nutrs;
>> +       host->can_queue = SCSI_CMD_QUEUE_SIZE;
>
>
> I don't think this is appropriate. Reserving a slot exclusively for
> query/DM requests is not optimal.  can_queue should be changed
> dynamically, scsi_adjust_queue_depth() maybe?

The motivation to change the design for this patch  is that routing
query command through SCSI layer raised problems when we are trying to
improve the fatal error handling as we need to block the SCSI layer and
recover the link. Hence, the need to have the query/DM command send as
internal commands. Which probably makes sense.

One possible option was to look for a free command slot whenever we
try to send an internal command, but getting a free slot is not always 
guaranteed.

Even if we get hold of a tag, there is no way we can explain this to
SCSI/block layer that particular tag is in use internally (case where
normal query requests are sent in tandem with SCSI requests). In which
case, other option is to use tag[31] as you have said on need basis
and change the queue depth to 31. This again has problems - one
changing queue depth doesn't take effect immediately but for the next
command. Second, if the command in tag[31] is the root cause of the
fatal error and is stuck, then the internal command has to wait forever
(until scsi timesout) to plan recovery. Considering, all these factors
it is better to reserve a tag and use it for internal commands instead 
of playing around with the tags internally without/partially informing 
SCSI/block layers.

I am open for discussion, if there are any suggestions to handle such 
LLD requirements in the SCSI layer optimally.

Coming to how optimal is to work with 31 slots instead of h/w defined 32 
is something which we can answer when we have true multi queueing. 
AFAIK, there may not exist real-world applications which utilize full 32 
tags at particular instant. SATA AHCI controller driver which is 
ubiquitous in modern systems also reserves a slot for internal commands 
which is used only in case of error handling and AFAIK, no one has ever 
reported performance problems with this (its about 7 years the commit to 
reserve a slot is merged into Linux tree).

I hope this explains the intent. Please let me know what do you think.

-- 
Regards,
Sujit

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

* Re: [PATCH 1/2] scsi: ufs: Add support for sending NOP OUT UPIU
  2013-06-14  7:40       ` Sujit Reddy Thumma
@ 2013-06-14 13:47         ` Santosh Y
  0 siblings, 0 replies; 14+ messages in thread
From: Santosh Y @ 2013-06-14 13:47 UTC (permalink / raw)
  To: Sujit Reddy Thumma; +Cc: Dolev Raviv, linux-scsi, linux-arm-msm, open list

On Fri, Jun 14, 2013 at 1:10 PM, Sujit Reddy Thumma
<sthumma@codeaurora.org> wrote:
> On 6/13/2013 10:03 AM, Sujit Reddy Thumma wrote:
>>>
>>>   static struct scsi_host_template ufshcd_driver_template = {
>>> @@ -1771,8 +2064,8 @@ int ufshcd_init(struct device *dev, struct
>>> ufs_hba **hba_handle,
>>>          /* Configure LRB */
>>>          ufshcd_host_memory_configure(hba);
>>>
>>> -       host->can_queue = hba->nutrs;
>>> -       host->cmd_per_lun = hba->nutrs;
>>> +       host->can_queue = SCSI_CMD_QUEUE_SIZE;
>>
>>
>>
>> I don't think this is appropriate. Reserving a slot exclusively for
>> query/DM requests is not optimal.  can_queue should be changed
>> dynamically, scsi_adjust_queue_depth() maybe?
>
>
> The motivation to change the design for this patch  is that routing
> query command through SCSI layer raised problems when we are trying to
> improve the fatal error handling as we need to block the SCSI layer and
> recover the link. Hence, the need to have the query/DM command send as
> internal commands. Which probably makes sense.
>

If fatal error handling is the only concern then the only required
query/DM commands, I guess you are talking about fDeviceInit and NOP,
for the recovery can be sent internally. Moreover, it doesn't matter
on which available slot the query/DM commands are sent during the
fatal error handling since the SCSI layer is blocked. Once the
recovery completes,  query commands can go on without reserving an
exclusive slot.

> One possible option was to look for a free command slot whenever we
> try to send an internal command, but getting a free slot is not always
> guaranteed.
>
> Even if we get hold of a tag, there is no way we can explain this to
> SCSI/block layer that particular tag is in use internally (case where
> normal query requests are sent in tandem with SCSI requests). In which
> case, other option is to use tag[31] as you have said on need basis
> and change the queue depth to 31. This again has problems - one
> changing queue depth doesn't take effect immediately but for the next
> command. Second, if the command in tag[31] is the root cause of the
> fatal error and is stuck, then the internal command has to wait forever
> (until scsi timesout) to plan recovery. Considering, all these factors
> it is better to reserve a tag and use it for internal commands instead of
> playing around with the tags internally without/partially informing
> SCSI/block layers.
>
> I am open for discussion, if there are any suggestions to handle such LLD
> requirements in the SCSI layer optimally.
>
> Coming to how optimal is to work with 31 slots instead of h/w defined 32 is
> something which we can answer when we have true multi queueing. AFAIK, there
> may not exist real-world applications which utilize full 32 tags at
> particular instant. SATA AHCI controller driver which is ubiquitous in
> modern systems also reserves a slot for internal commands which is used only
> in case of error handling and AFAIK, no one has ever reported performance
> problems with this (its about 7 years the commit to reserve a slot is merged
> into Linux tree).
>
> I hope this explains the intent. Please let me know what do you think.
>

Always nutrs=32 is the assumption you are making. Spec mentions that
(1 <= nutrs <=32) and (1 <= nutmrs <= 8), and unfortunately I did come
across a host controller with nutrs=4, nutmrs=2 sometime back.
Reserving an exclusive slot for query in such cases would make a
difference. Hope this helps.


-- 
~Santosh

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

* Re: [PATCH 2/2] scsi: ufs: Set fDeviceInit flag to initiate device initialization
  2013-06-13  4:36     ` Sujit Reddy Thumma
@ 2013-06-14 13:55       ` Santosh Y
  0 siblings, 0 replies; 14+ messages in thread
From: Santosh Y @ 2013-06-14 13:55 UTC (permalink / raw)
  To: Sujit Reddy Thumma; +Cc: Dolev Raviv, linux-scsi, linux-arm-msm, open list

On Thu, Jun 13, 2013 at 10:06 AM, Sujit Reddy Thumma
<sthumma@codeaurora.org> wrote:
> On 6/12/2013 11:04 AM, Santosh Y wrote:
>>>
>>>
>>>   /**
>>> + *  ufshcd_query_request() - API for issuing query request to the
>>> device.
>>> + *  @hba: ufs driver context
>>> + *  @query: params for query request
>>> + *  @descriptor: buffer for sending/receiving descriptor
>>> + *  @retries: number of times to try executing the command
>>> + *
>>> + *   All necessary fields for issuing a query and receiving its response
>>> + *   are stored in the UFS hba struct. We can use this method since we
>>> know
>>> + *   there is only one active query request or any internal command at
>>> all
>>> + *   times.
>>> + */
>>> +static int ufshcd_send_query_request(struct ufs_hba *hba,
>>> +                                       struct ufs_query_req *query,
>>> +                                       u8 *descriptor,
>>> +                                       struct ufs_query_res *response)
>>> +{
>>> +       int ret;
>>> +
>>> +       BUG_ON(!hba);
>>> +       if (!query || !response) {
>>> +               dev_err(hba->dev,
>>> +                       "%s: NULL pointer query = %p, response = %p\n",
>>> +                       __func__, query, response);
>>> +               return -EINVAL;
>>> +       }
>>> +
>>> +       mutex_lock(&hba->i_cmd.dev_cmd_lock);
>>> +       hba->i_cmd.query.request = query;
>>> +       hba->i_cmd.query.response = response;
>>> +       hba->i_cmd.query.descriptor = descriptor;
>>> +
>>> +       ret = ufshcd_exec_internal_cmd(hba, DEV_CMD_TYPE_QUERY,
>>> +                                       QUERY_REQ_TIMEOUT);
>>
>>
>> Can this be generic, as external query commands might also use it?
>
>
> External query commands can call ufshcd_send_query_request() directly,
> without going into hassle of taking mutex lock and filling internal cmd
> structure.
>

I was not clear.
It might be confusing that user issued query commands also use methods
with name *internal_cmd*.

>
>>
>>> +
>>> +       hba->i_cmd.query.request = NULL;
>>> +       hba->i_cmd.query.response = NULL;
>>> +       hba->i_cmd.query.descriptor = NULL;
>>> +       mutex_unlock(&hba->i_cmd.dev_cmd_lock);
>>> +
>>> +       return ret;
>>> +}
>>> +
>>> +/**
>>
>>
>>
>
> --
> Regards,
> Sujit



-- 
~Santosh

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

* [PATCH 2/2] scsi: ufs: Set fDeviceInit flag to initiate device initialization
  2013-06-10 14:12 [PATCH 0/2] Add suport for internal request (NOP and Query Request) Dolev Raviv
@ 2013-06-10 14:12   ` Dolev Raviv
  0 siblings, 0 replies; 14+ messages in thread
From: Dolev Raviv @ 2013-06-10 14:12 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-arm-msm, Dolev Raviv, Sujit Reddy Thumma, open list

Allow UFS device to complete its initialization and accept
SCSI commands by setting fDeviceInit flag. The device may take
time for this operation and hence the host should poll until
fDeviceInit flag is toggled to zero. This step is mandated by
UFS device specification for device initialization completion.

Signed-off-by: Dolev Raviv <draviv@codeaurora.org>
Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org>

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 69c0328..6ce99b0 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -43,6 +43,8 @@
 #define GENERAL_UPIU_REQUEST_SIZE 32
 #define UPIU_HEADER_DATA_SEGMENT_MAX_SIZE	((ALIGNED_UPIU_SIZE) - \
 					(GENERAL_UPIU_REQUEST_SIZE))
+#define QUERY_OSF_SIZE			((GENERAL_UPIU_REQUEST_SIZE) - \
+					(sizeof(struct utp_upiu_header)))
 
 #define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
 			cpu_to_be32((byte3 << 24) | (byte2 << 16) |\
@@ -68,7 +70,7 @@ enum {
 	UPIU_TRANSACTION_COMMAND	= 0x01,
 	UPIU_TRANSACTION_DATA_OUT	= 0x02,
 	UPIU_TRANSACTION_TASK_REQ	= 0x04,
-	UPIU_TRANSACTION_QUERY_REQ	= 0x26,
+	UPIU_TRANSACTION_QUERY_REQ	= 0x16,
 };
 
 /* UTP UPIU Transaction Codes Target to Initiator */
@@ -97,8 +99,19 @@ enum {
 	UPIU_TASK_ATTR_ACA	= 0x03,
 };
 
-/* UTP QUERY Transaction Specific Fields OpCode */
+/* UPIU Query request function */
 enum {
+	UPIU_QUERY_FUNC_STANDARD_READ_REQUEST = 0x01,
+	UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST = 0x81,
+};
+
+/* Flag idn for Query Requests*/
+enum flag_idn {
+	QUERY_FLAG_IDN_FDEVICEINIT = 0x01,
+};
+
+/* UTP QUERY Transaction Specific Fields OpCode */
+enum query_opcode {
 	UPIU_QUERY_OPCODE_NOP		= 0x0,
 	UPIU_QUERY_OPCODE_READ_DESC	= 0x1,
 	UPIU_QUERY_OPCODE_WRITE_DESC	= 0x2,
@@ -110,6 +123,21 @@ enum {
 	UPIU_QUERY_OPCODE_TOGGLE_FLAG	= 0x8,
 };
 
+/* Query response result code */
+enum {
+	QUERY_RESULT_SUCCESS			= 0x00,
+	QUERY_RESULT_NOT_READABLE		= 0xF6,
+	QUERY_RESULT_NOT_WRITEABLE		= 0xF7,
+	QUERY_RESULT_ALREADY_WRITTEN		= 0xF8,
+	QUERY_RESULT_INVALID_LENGTH		= 0xF9,
+	QUERY_RESULT_INVALID_VALUE		= 0xFA,
+	QUERY_RESULT_INVALID_SELECTOR		= 0xFB,
+	QUERY_RESULT_INVALID_INDEX		= 0xFC,
+	QUERY_RESULT_INVALID_IDN		= 0xFD,
+	QUERY_RESULT_INVALID_OPCODE		= 0xFE,
+	QUERY_RESULT_GENERAL_FAILURE		= 0xFF,
+};
+
 /* UTP Transfer Request Command Type (CT) */
 enum {
 	UPIU_COMMAND_SET_TYPE_SCSI	= 0x0,
@@ -127,6 +155,7 @@ enum {
 	MASK_SCSI_STATUS	= 0xFF,
 	MASK_TASK_RESPONSE	= 0xFF00,
 	MASK_RSP_UPIU_RESULT	= 0xFFFF,
+	MASK_QUERY_DATA_SEG_LEN	= 0xFFFF,
 };
 
 /* Task management service response */
@@ -160,13 +189,40 @@ struct utp_upiu_cmd {
 };
 
 /**
+ * struct utp_upiu_query - upiu request buffer structure for
+ * query request.
+ * @opcode: command to perform B-0
+ * @idn: a value that indicates the particular type of data B-1
+ * @index: Index to further identify data B-2
+ * @selector: Index to further identify data B-3
+ * @reserved_osf: spec reserved field B-4,5
+ * @length: number of descriptor bytes to read/write B-6,7
+ * @value: Attribute value to be written DW-6
+ * @reserved: spec reserved DW-7,8
+ */
+struct utp_upiu_query {
+	u8 opcode;
+	u8 idn;
+	u8 index;
+	u8 selector;
+	u16 reserved_osf;
+	u16 length;
+	u32 value;
+	u32 reserved[2];
+};
+
+/**
  * struct utp_upiu_req - general upiu request structure
  * @header:UPIU header structure DW-0 to DW-2
  * @sc: fields structure for scsi command
+ * @qr: fields structure for query request
  */
 struct utp_upiu_req {
 	struct utp_upiu_header header;
-	struct utp_upiu_cmd sc;
+	union {
+		struct utp_upiu_cmd sc;
+		struct utp_upiu_query qr;
+	};
 };
 
 /**
@@ -187,10 +243,14 @@ struct utp_cmd_rsp {
  * struct utp_upiu_rsp - general upiu response structure
  * @header: UPIU header structure DW-0 to DW-2
  * @sc: fields structure for scsi command
+ * @qr: fields structure for query request
  */
 struct utp_upiu_rsp {
 	struct utp_upiu_header header;
-	struct utp_cmd_rsp sc;
+	union {
+		struct utp_cmd_rsp sc;
+		struct utp_upiu_query qr;
+	};
 };
 
 /**
@@ -223,4 +283,24 @@ struct utp_upiu_task_rsp {
 	u32 reserved[3];
 };
 
+/**
+ * struct ufs_query_req - parameters for building a query request
+ * @query_func: UPIU header query function
+ * @upiu_req: the query request data
+ */
+struct ufs_query_req {
+	u8 query_func;
+	struct utp_upiu_query upiu_req;
+};
+
+/**
+ * struct ufs_query_resp - UPIU QUERY
+ * @response: device response code
+ * @upiu_res: query response data
+ */
+struct ufs_query_res {
+	u8 response;
+	struct utp_upiu_query upiu_res;
+};
+
 #endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index d534c50..6d12fae 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -48,10 +48,20 @@
 /* Timeout after 30 msecs if NOP OUT hangs without response */
 #define NOP_OUT_TIMEOUT    30 /* msecs */
 
+/* Query request retries */
+#define QUERY_REQ_RETRIES 10
+/* Query request timeout */
+#define QUERY_REQ_TIMEOUT 30 /* msec */
+/* fDeviceInit max polling number */
+#define QUERY_MAX_POLL_ITER 100
+
 #define SCSI_CMD_QUEUE_SIZE (hba->nutrs - 1)
 /* Reserved tag for internal commands */
 #define INTERNAL_CMD_TAG   (hba->nutrs - 1)
 
+/* Expose the flag value from utp_upiu_query.value */
+#define MASK_QUERY_UPIU_FLAG_LOC 0xFF
+
 enum {
 	UFSHCD_MAX_CHANNEL	= 0,
 	UFSHCD_MAX_ID		= 1,
@@ -378,6 +388,63 @@ static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp)
 }
 
 /**
+ * ufshcd_query_to_cpu() - formats the buffer to native cpu endian
+ * @response: upiu query response to convert
+ */
+static inline void ufshcd_query_to_cpu(struct utp_upiu_query *response)
+{
+	response->length = be16_to_cpu(response->length);
+	response->value = be32_to_cpu(response->value);
+}
+
+/**
+ * ufshcd_query_to_be() - formats the buffer to big endian
+ * @request: upiu query request to convert
+ */
+static inline void ufshcd_query_to_be(struct utp_upiu_query *request)
+{
+	request->length = cpu_to_be16(request->length);
+	request->value = cpu_to_be32(request->value);
+}
+
+/**
+ * ufshcd_copy_query_response() - Copy the Query Response and the data
+ * descriptor
+ * @hba: per adapter instance
+ * @lrb - pointer to local reference block
+ */
+static
+void ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+{
+	struct ufs_query_res *query_res = hba->i_cmd.query.response;
+
+	/* Get the UPIU response */
+	if (query_res) {
+		query_res->response = ufshcd_get_rsp_upiu_result(
+			lrbp->ucd_rsp_ptr) >> UPIU_RSP_CODE_OFFSET;
+
+		memcpy(&query_res->upiu_res, &lrbp->ucd_rsp_ptr->qr,
+			QUERY_OSF_SIZE);
+		ufshcd_query_to_cpu(&query_res->upiu_res);
+	}
+
+	/* Get the descriptor */
+	if (hba->i_cmd.query.descriptor && lrbp->ucd_rsp_ptr->qr.opcode ==
+			UPIU_QUERY_OPCODE_READ_DESC) {
+		u8 *descp = (u8 *)&lrbp->ucd_rsp_ptr +
+				GENERAL_UPIU_REQUEST_SIZE;
+		u16 len;
+
+		/* data segment length */
+		len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) &
+						MASK_QUERY_DATA_SEG_LEN;
+
+		memcpy(hba->i_cmd.query.descriptor, descp,
+			min_t(u16, len, UPIU_HEADER_DATA_SEGMENT_MAX_SIZE));
+	}
+}
+
+/**
  * ufshcd_hba_capabilities - Read controller capabilities
  * @hba: per adapter instance
  */
@@ -659,6 +726,47 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u32 upiu_flags)
 		(min_t(unsigned short, lrbp->cmd->cmd_len, MAX_CDB_SIZE)));
 }
 
+/**
+ * ufshcd_prepare_utp_query_req_upiu() - fills the utp_transfer_req_desc,
+ * for query requsts
+ * @hba: UFS hba
+ * @lrbp: local reference block pointer
+ * @upiu_flags: flags
+ */
+static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba,
+					struct ufshcd_lrb *lrbp,
+					u32 upiu_flags)
+{
+	struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
+	u16 len = hba->i_cmd.query.request->upiu_req.length;
+	u8 *descp = (u8 *)lrbp->ucd_req_ptr + GENERAL_UPIU_REQUEST_SIZE;
+
+	/* Query request header */
+	ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD(
+			UPIU_TRANSACTION_QUERY_REQ, upiu_flags,
+			lrbp->lun, lrbp->task_tag);
+	ucd_req_ptr->header.dword_1 = UPIU_HEADER_DWORD(
+			0, hba->i_cmd.query.request->query_func, 0, 0);
+
+	/* Data segment length */
+	ucd_req_ptr->header.dword_2 = UPIU_HEADER_DWORD(
+			0, 0, len >> 8, (u8)len);
+
+	/* Copy the Query Request buffer as is */
+	memcpy(&lrbp->ucd_req_ptr->qr, &hba->i_cmd.query.request->upiu_req,
+			QUERY_OSF_SIZE);
+	ufshcd_query_to_be(&lrbp->ucd_req_ptr->qr);
+
+	/* Copy the Descriptor */
+	if ((hba->i_cmd.query.descriptor != NULL) && (len > 0) &&
+		(hba->i_cmd.query.request->upiu_req.opcode ==
+					UPIU_QUERY_OPCODE_WRITE_DESC)) {
+		memcpy(descp, hba->i_cmd.query.descriptor,
+			min_t(u16, len, UPIU_HEADER_DATA_SEGMENT_MAX_SIZE));
+	}
+
+}
+
 static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp)
 {
 	struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
@@ -693,7 +801,10 @@ static int ufshcd_compose_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 		break;
 	case UTP_CMD_TYPE_DEV_MANAGE:
 		ufshcd_prepare_req_desc(lrbp, &upiu_flags, DMA_NONE);
-		if (hba->i_cmd.dev_cmd_type == DEV_CMD_TYPE_NOP)
+		if (hba->i_cmd.dev_cmd_type == DEV_CMD_TYPE_QUERY)
+			ufshcd_prepare_utp_query_req_upiu(
+					hba, lrbp, upiu_flags);
+		else if (hba->i_cmd.dev_cmd_type == DEV_CMD_TYPE_NOP)
 			ufshcd_prepare_utp_nop_upiu(lrbp);
 		else
 			ret = -EINVAL;
@@ -837,6 +948,9 @@ ufshcd_internal_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 	switch (resp) {
 	case UPIU_TRANSACTION_NOP_IN:
 		break;
+	case UPIU_TRANSACTION_QUERY_RSP:
+		ufshcd_copy_query_response(hba, lrbp);
+		break;
 	case UPIU_TRANSACTION_REJECT_UPIU:
 		/* TODO: handle Reject UPIU Response */
 		dev_err(hba->dev, "Reject UPIU not fully implemented\n");
@@ -896,6 +1010,121 @@ out:
 }
 
 /**
+ *  ufshcd_query_request() - API for issuing query request to the device.
+ *  @hba: ufs driver context
+ *  @query: params for query request
+ *  @descriptor: buffer for sending/receiving descriptor
+ *  @retries: number of times to try executing the command
+ *
+ *   All necessary fields for issuing a query and receiving its response
+ *   are stored in the UFS hba struct. We can use this method since we know
+ *   there is only one active query request or any internal command at all
+ *   times.
+ */
+static int ufshcd_send_query_request(struct ufs_hba *hba,
+					struct ufs_query_req *query,
+					u8 *descriptor,
+					struct ufs_query_res *response)
+{
+	int ret;
+
+	BUG_ON(!hba);
+	if (!query || !response) {
+		dev_err(hba->dev,
+			"%s: NULL pointer query = %p, response = %p\n",
+			__func__, query, response);
+		return -EINVAL;
+	}
+
+	mutex_lock(&hba->i_cmd.dev_cmd_lock);
+	hba->i_cmd.query.request = query;
+	hba->i_cmd.query.response = response;
+	hba->i_cmd.query.descriptor = descriptor;
+
+	ret = ufshcd_exec_internal_cmd(hba, DEV_CMD_TYPE_QUERY,
+					QUERY_REQ_TIMEOUT);
+
+	hba->i_cmd.query.request = NULL;
+	hba->i_cmd.query.response = NULL;
+	hba->i_cmd.query.descriptor = NULL;
+	mutex_unlock(&hba->i_cmd.dev_cmd_lock);
+
+	return ret;
+}
+
+/**
+ * ufshcd_query_flag() - Helper function for composing flag query requests
+ * hba: per-adapter instance
+ * query_opcode: flag query to perform
+ * idn: flag idn to access
+ * flag_res: the flag value after the query request completes
+ *
+ * Returns 0 for success, non-zero in case of failure
+ */
+static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
+			enum flag_idn idn, bool *flag_res)
+{
+	struct ufs_query_req *query;
+	struct ufs_query_res *response;
+	int err = -ENOMEM;
+
+	query = kzalloc(sizeof(struct ufs_query_req), GFP_KERNEL);
+	if (!query) {
+		dev_err(hba->dev,
+			"%s: Failed allocating ufs_query_req instance\n",
+			__func__);
+		goto out_no_mem;
+	}
+	response = kzalloc(sizeof(struct ufs_query_res), GFP_KERNEL);
+	if (!response) {
+		dev_err(hba->dev,
+			"%s: Failed allocating ufs_query_res instance\n",
+			__func__);
+		goto out_free_query;
+	}
+
+	switch (opcode) {
+	case UPIU_QUERY_OPCODE_SET_FLAG:
+	case UPIU_QUERY_OPCODE_CLEAR_FLAG:
+	case UPIU_QUERY_OPCODE_TOGGLE_FLAG:
+		query->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST;
+		break;
+	case UPIU_QUERY_OPCODE_READ_FLAG:
+		query->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST;
+		break;
+	default:
+		dev_err(hba->dev,
+			"%s: Expected query flag opcode but got = %d\n",
+			__func__, opcode);
+		err = -EINVAL;
+		goto out;
+	}
+	query->upiu_req.opcode = opcode;
+	query->upiu_req.idn = idn;
+
+	/* Send query request */
+	err = ufshcd_send_query_request(hba, query, NULL, response);
+
+	if (err) {
+		dev_err(hba->dev,
+			"%s: Sending flag query for idn %d failed, err = %d\n",
+			__func__, idn, err);
+		goto out;
+	}
+
+	if (flag_res)
+		*flag_res = (response->upiu_res.value &
+				MASK_QUERY_UPIU_FLAG_LOC) & 0x1;
+
+out:
+	kfree(response);
+out_free_query:
+	kfree(query);
+out_no_mem:
+	return err;
+}
+
+/**
  * ufshcd_memory_alloc - allocate memory for host memory space data structures
  * @hba: per adapter instance
  *
@@ -1064,6 +1293,59 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
 }
 
 /**
+ * ufshcd_validate_device_init() - checks device readiness
+ * hba: per-adapter instance
+ *
+ * Set fDeviceInit flag, than, query the flag until the device clears the
+ * flag.
+ */
+static int ufshcd_validate_device_init(struct ufs_hba *hba)
+{
+	int i, retries, err = 0;
+	bool flag_res = 0;
+
+	for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+		/* Set the fDeviceIntit flag */
+		err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_SET_FLAG,
+					QUERY_FLAG_IDN_FDEVICEINIT, &flag_res);
+		if (!err || err == -ETIMEDOUT)
+			break;
+		dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
+	}
+	if (err) {
+		dev_err(hba->dev,
+			"%s setting fDeviceInit flag failed with error %d\n",
+			__func__, err);
+		goto out;
+	}
+
+	/* Start polling */
+	for (i = 0; i < QUERY_MAX_POLL_ITER && !err && flag_res; i++) {
+		retries = QUERY_REQ_RETRIES;
+		for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+			err = ufshcd_query_flag(hba,
+					UPIU_QUERY_OPCODE_READ_FLAG,
+					QUERY_FLAG_IDN_FDEVICEINIT, &flag_res);
+			if (!err || err == -ETIMEDOUT)
+				break;
+			dev_dbg(hba->dev, "%s: error %d retrying\n", __func__,
+					err);
+		}
+	}
+	if (err)
+		dev_err(hba->dev,
+			"%s reading fDeviceInit flag failed with error %d\n",
+			__func__, err);
+	else if (flag_res)
+		dev_err(hba->dev,
+			"%s fDeviceInit was not cleared by the device\n",
+			__func__);
+
+out:
+	return err;
+}
+
+/**
  * ufshcd_make_hba_operational - Make UFS controller operational
  * @hba: per adapter instance
  *
@@ -1910,6 +2192,10 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)
 	if (ret)
 		goto out;
 
+	ret = ufshcd_validate_device_init(hba);
+	if (ret)
+		goto out;
+
 	scsi_scan_host(hba->host);
 out:
 	return;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index e41fa5e..4e4c56f 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -70,6 +70,7 @@
 
 enum internal_cmd_type {
 	DEV_CMD_TYPE_NOP		= 0x0,
+	DEV_CMD_TYPE_QUERY		= 0x1,
 };
 
 /**
@@ -125,15 +126,29 @@ struct ufshcd_lrb {
 };
 
 /**
+ * struct ufs_query - holds relevent data structures for query request
+ * @request: request upiu and function
+ * @descriptor: buffer for sending/receiving descriptor
+ * @response: response upiu and response
+ */
+struct ufs_query {
+	struct ufs_query_req *request;
+	u8 *descriptor;
+	struct ufs_query_res *response;
+};
+
+/**
  * struct ufs_internal_cmd - all assosiated fields with internal commands
  * @dev_cmd_type: device management command type - Query, NOP OUT
  * @dev_cmd_lock: lock to allow one internal command at a time
  * @dev_cmd_complete: internal commands completion
+ * @query: required query data structures for sending query request
  */
 struct ufs_internal_cmd {
 	enum internal_cmd_type dev_cmd_type;
 	struct mutex dev_cmd_lock;
 	struct completion *dev_cmd_complete;
+	struct ufs_query query;
 };
 
 /**
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index d5c5f14..f1e1b74 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -39,7 +39,7 @@
 enum {
 	TASK_REQ_UPIU_SIZE_DWORDS	= 8,
 	TASK_RSP_UPIU_SIZE_DWORDS	= 8,
-	ALIGNED_UPIU_SIZE		= 128,
+	ALIGNED_UPIU_SIZE		= 512,
 };
 
 /* UFSHCI Registers */
-- 
1.7.6
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

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

* [PATCH 2/2] scsi: ufs: Set fDeviceInit flag to initiate device initialization
@ 2013-06-10 14:12   ` Dolev Raviv
  0 siblings, 0 replies; 14+ messages in thread
From: Dolev Raviv @ 2013-06-10 14:12 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-arm-msm, Dolev Raviv, Sujit Reddy Thumma, open list

Allow UFS device to complete its initialization and accept
SCSI commands by setting fDeviceInit flag. The device may take
time for this operation and hence the host should poll until
fDeviceInit flag is toggled to zero. This step is mandated by
UFS device specification for device initialization completion.

Signed-off-by: Dolev Raviv <draviv@codeaurora.org>
Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org>

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 69c0328..6ce99b0 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -43,6 +43,8 @@
 #define GENERAL_UPIU_REQUEST_SIZE 32
 #define UPIU_HEADER_DATA_SEGMENT_MAX_SIZE	((ALIGNED_UPIU_SIZE) - \
 					(GENERAL_UPIU_REQUEST_SIZE))
+#define QUERY_OSF_SIZE			((GENERAL_UPIU_REQUEST_SIZE) - \
+					(sizeof(struct utp_upiu_header)))
 
 #define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\
 			cpu_to_be32((byte3 << 24) | (byte2 << 16) |\
@@ -68,7 +70,7 @@ enum {
 	UPIU_TRANSACTION_COMMAND	= 0x01,
 	UPIU_TRANSACTION_DATA_OUT	= 0x02,
 	UPIU_TRANSACTION_TASK_REQ	= 0x04,
-	UPIU_TRANSACTION_QUERY_REQ	= 0x26,
+	UPIU_TRANSACTION_QUERY_REQ	= 0x16,
 };
 
 /* UTP UPIU Transaction Codes Target to Initiator */
@@ -97,8 +99,19 @@ enum {
 	UPIU_TASK_ATTR_ACA	= 0x03,
 };
 
-/* UTP QUERY Transaction Specific Fields OpCode */
+/* UPIU Query request function */
 enum {
+	UPIU_QUERY_FUNC_STANDARD_READ_REQUEST = 0x01,
+	UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST = 0x81,
+};
+
+/* Flag idn for Query Requests*/
+enum flag_idn {
+	QUERY_FLAG_IDN_FDEVICEINIT = 0x01,
+};
+
+/* UTP QUERY Transaction Specific Fields OpCode */
+enum query_opcode {
 	UPIU_QUERY_OPCODE_NOP		= 0x0,
 	UPIU_QUERY_OPCODE_READ_DESC	= 0x1,
 	UPIU_QUERY_OPCODE_WRITE_DESC	= 0x2,
@@ -110,6 +123,21 @@ enum {
 	UPIU_QUERY_OPCODE_TOGGLE_FLAG	= 0x8,
 };
 
+/* Query response result code */
+enum {
+	QUERY_RESULT_SUCCESS			= 0x00,
+	QUERY_RESULT_NOT_READABLE		= 0xF6,
+	QUERY_RESULT_NOT_WRITEABLE		= 0xF7,
+	QUERY_RESULT_ALREADY_WRITTEN		= 0xF8,
+	QUERY_RESULT_INVALID_LENGTH		= 0xF9,
+	QUERY_RESULT_INVALID_VALUE		= 0xFA,
+	QUERY_RESULT_INVALID_SELECTOR		= 0xFB,
+	QUERY_RESULT_INVALID_INDEX		= 0xFC,
+	QUERY_RESULT_INVALID_IDN		= 0xFD,
+	QUERY_RESULT_INVALID_OPCODE		= 0xFE,
+	QUERY_RESULT_GENERAL_FAILURE		= 0xFF,
+};
+
 /* UTP Transfer Request Command Type (CT) */
 enum {
 	UPIU_COMMAND_SET_TYPE_SCSI	= 0x0,
@@ -127,6 +155,7 @@ enum {
 	MASK_SCSI_STATUS	= 0xFF,
 	MASK_TASK_RESPONSE	= 0xFF00,
 	MASK_RSP_UPIU_RESULT	= 0xFFFF,
+	MASK_QUERY_DATA_SEG_LEN	= 0xFFFF,
 };
 
 /* Task management service response */
@@ -160,13 +189,40 @@ struct utp_upiu_cmd {
 };
 
 /**
+ * struct utp_upiu_query - upiu request buffer structure for
+ * query request.
+ * @opcode: command to perform B-0
+ * @idn: a value that indicates the particular type of data B-1
+ * @index: Index to further identify data B-2
+ * @selector: Index to further identify data B-3
+ * @reserved_osf: spec reserved field B-4,5
+ * @length: number of descriptor bytes to read/write B-6,7
+ * @value: Attribute value to be written DW-6
+ * @reserved: spec reserved DW-7,8
+ */
+struct utp_upiu_query {
+	u8 opcode;
+	u8 idn;
+	u8 index;
+	u8 selector;
+	u16 reserved_osf;
+	u16 length;
+	u32 value;
+	u32 reserved[2];
+};
+
+/**
  * struct utp_upiu_req - general upiu request structure
  * @header:UPIU header structure DW-0 to DW-2
  * @sc: fields structure for scsi command
+ * @qr: fields structure for query request
  */
 struct utp_upiu_req {
 	struct utp_upiu_header header;
-	struct utp_upiu_cmd sc;
+	union {
+		struct utp_upiu_cmd sc;
+		struct utp_upiu_query qr;
+	};
 };
 
 /**
@@ -187,10 +243,14 @@ struct utp_cmd_rsp {
  * struct utp_upiu_rsp - general upiu response structure
  * @header: UPIU header structure DW-0 to DW-2
  * @sc: fields structure for scsi command
+ * @qr: fields structure for query request
  */
 struct utp_upiu_rsp {
 	struct utp_upiu_header header;
-	struct utp_cmd_rsp sc;
+	union {
+		struct utp_cmd_rsp sc;
+		struct utp_upiu_query qr;
+	};
 };
 
 /**
@@ -223,4 +283,24 @@ struct utp_upiu_task_rsp {
 	u32 reserved[3];
 };
 
+/**
+ * struct ufs_query_req - parameters for building a query request
+ * @query_func: UPIU header query function
+ * @upiu_req: the query request data
+ */
+struct ufs_query_req {
+	u8 query_func;
+	struct utp_upiu_query upiu_req;
+};
+
+/**
+ * struct ufs_query_resp - UPIU QUERY
+ * @response: device response code
+ * @upiu_res: query response data
+ */
+struct ufs_query_res {
+	u8 response;
+	struct utp_upiu_query upiu_res;
+};
+
 #endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index d534c50..6d12fae 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -48,10 +48,20 @@
 /* Timeout after 30 msecs if NOP OUT hangs without response */
 #define NOP_OUT_TIMEOUT    30 /* msecs */
 
+/* Query request retries */
+#define QUERY_REQ_RETRIES 10
+/* Query request timeout */
+#define QUERY_REQ_TIMEOUT 30 /* msec */
+/* fDeviceInit max polling number */
+#define QUERY_MAX_POLL_ITER 100
+
 #define SCSI_CMD_QUEUE_SIZE (hba->nutrs - 1)
 /* Reserved tag for internal commands */
 #define INTERNAL_CMD_TAG   (hba->nutrs - 1)
 
+/* Expose the flag value from utp_upiu_query.value */
+#define MASK_QUERY_UPIU_FLAG_LOC 0xFF
+
 enum {
 	UFSHCD_MAX_CHANNEL	= 0,
 	UFSHCD_MAX_ID		= 1,
@@ -378,6 +388,63 @@ static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp)
 }
 
 /**
+ * ufshcd_query_to_cpu() - formats the buffer to native cpu endian
+ * @response: upiu query response to convert
+ */
+static inline void ufshcd_query_to_cpu(struct utp_upiu_query *response)
+{
+	response->length = be16_to_cpu(response->length);
+	response->value = be32_to_cpu(response->value);
+}
+
+/**
+ * ufshcd_query_to_be() - formats the buffer to big endian
+ * @request: upiu query request to convert
+ */
+static inline void ufshcd_query_to_be(struct utp_upiu_query *request)
+{
+	request->length = cpu_to_be16(request->length);
+	request->value = cpu_to_be32(request->value);
+}
+
+/**
+ * ufshcd_copy_query_response() - Copy the Query Response and the data
+ * descriptor
+ * @hba: per adapter instance
+ * @lrb - pointer to local reference block
+ */
+static
+void ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
+{
+	struct ufs_query_res *query_res = hba->i_cmd.query.response;
+
+	/* Get the UPIU response */
+	if (query_res) {
+		query_res->response = ufshcd_get_rsp_upiu_result(
+			lrbp->ucd_rsp_ptr) >> UPIU_RSP_CODE_OFFSET;
+
+		memcpy(&query_res->upiu_res, &lrbp->ucd_rsp_ptr->qr,
+			QUERY_OSF_SIZE);
+		ufshcd_query_to_cpu(&query_res->upiu_res);
+	}
+
+	/* Get the descriptor */
+	if (hba->i_cmd.query.descriptor && lrbp->ucd_rsp_ptr->qr.opcode ==
+			UPIU_QUERY_OPCODE_READ_DESC) {
+		u8 *descp = (u8 *)&lrbp->ucd_rsp_ptr +
+				GENERAL_UPIU_REQUEST_SIZE;
+		u16 len;
+
+		/* data segment length */
+		len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) &
+						MASK_QUERY_DATA_SEG_LEN;
+
+		memcpy(hba->i_cmd.query.descriptor, descp,
+			min_t(u16, len, UPIU_HEADER_DATA_SEGMENT_MAX_SIZE));
+	}
+}
+
+/**
  * ufshcd_hba_capabilities - Read controller capabilities
  * @hba: per adapter instance
  */
@@ -659,6 +726,47 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u32 upiu_flags)
 		(min_t(unsigned short, lrbp->cmd->cmd_len, MAX_CDB_SIZE)));
 }
 
+/**
+ * ufshcd_prepare_utp_query_req_upiu() - fills the utp_transfer_req_desc,
+ * for query requsts
+ * @hba: UFS hba
+ * @lrbp: local reference block pointer
+ * @upiu_flags: flags
+ */
+static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba,
+					struct ufshcd_lrb *lrbp,
+					u32 upiu_flags)
+{
+	struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
+	u16 len = hba->i_cmd.query.request->upiu_req.length;
+	u8 *descp = (u8 *)lrbp->ucd_req_ptr + GENERAL_UPIU_REQUEST_SIZE;
+
+	/* Query request header */
+	ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD(
+			UPIU_TRANSACTION_QUERY_REQ, upiu_flags,
+			lrbp->lun, lrbp->task_tag);
+	ucd_req_ptr->header.dword_1 = UPIU_HEADER_DWORD(
+			0, hba->i_cmd.query.request->query_func, 0, 0);
+
+	/* Data segment length */
+	ucd_req_ptr->header.dword_2 = UPIU_HEADER_DWORD(
+			0, 0, len >> 8, (u8)len);
+
+	/* Copy the Query Request buffer as is */
+	memcpy(&lrbp->ucd_req_ptr->qr, &hba->i_cmd.query.request->upiu_req,
+			QUERY_OSF_SIZE);
+	ufshcd_query_to_be(&lrbp->ucd_req_ptr->qr);
+
+	/* Copy the Descriptor */
+	if ((hba->i_cmd.query.descriptor != NULL) && (len > 0) &&
+		(hba->i_cmd.query.request->upiu_req.opcode ==
+					UPIU_QUERY_OPCODE_WRITE_DESC)) {
+		memcpy(descp, hba->i_cmd.query.descriptor,
+			min_t(u16, len, UPIU_HEADER_DATA_SEGMENT_MAX_SIZE));
+	}
+
+}
+
 static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb *lrbp)
 {
 	struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr;
@@ -693,7 +801,10 @@ static int ufshcd_compose_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 		break;
 	case UTP_CMD_TYPE_DEV_MANAGE:
 		ufshcd_prepare_req_desc(lrbp, &upiu_flags, DMA_NONE);
-		if (hba->i_cmd.dev_cmd_type == DEV_CMD_TYPE_NOP)
+		if (hba->i_cmd.dev_cmd_type == DEV_CMD_TYPE_QUERY)
+			ufshcd_prepare_utp_query_req_upiu(
+					hba, lrbp, upiu_flags);
+		else if (hba->i_cmd.dev_cmd_type == DEV_CMD_TYPE_NOP)
 			ufshcd_prepare_utp_nop_upiu(lrbp);
 		else
 			ret = -EINVAL;
@@ -837,6 +948,9 @@ ufshcd_internal_cmd_completion(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 	switch (resp) {
 	case UPIU_TRANSACTION_NOP_IN:
 		break;
+	case UPIU_TRANSACTION_QUERY_RSP:
+		ufshcd_copy_query_response(hba, lrbp);
+		break;
 	case UPIU_TRANSACTION_REJECT_UPIU:
 		/* TODO: handle Reject UPIU Response */
 		dev_err(hba->dev, "Reject UPIU not fully implemented\n");
@@ -896,6 +1010,121 @@ out:
 }
 
 /**
+ *  ufshcd_query_request() - API for issuing query request to the device.
+ *  @hba: ufs driver context
+ *  @query: params for query request
+ *  @descriptor: buffer for sending/receiving descriptor
+ *  @retries: number of times to try executing the command
+ *
+ *   All necessary fields for issuing a query and receiving its response
+ *   are stored in the UFS hba struct. We can use this method since we know
+ *   there is only one active query request or any internal command at all
+ *   times.
+ */
+static int ufshcd_send_query_request(struct ufs_hba *hba,
+					struct ufs_query_req *query,
+					u8 *descriptor,
+					struct ufs_query_res *response)
+{
+	int ret;
+
+	BUG_ON(!hba);
+	if (!query || !response) {
+		dev_err(hba->dev,
+			"%s: NULL pointer query = %p, response = %p\n",
+			__func__, query, response);
+		return -EINVAL;
+	}
+
+	mutex_lock(&hba->i_cmd.dev_cmd_lock);
+	hba->i_cmd.query.request = query;
+	hba->i_cmd.query.response = response;
+	hba->i_cmd.query.descriptor = descriptor;
+
+	ret = ufshcd_exec_internal_cmd(hba, DEV_CMD_TYPE_QUERY,
+					QUERY_REQ_TIMEOUT);
+
+	hba->i_cmd.query.request = NULL;
+	hba->i_cmd.query.response = NULL;
+	hba->i_cmd.query.descriptor = NULL;
+	mutex_unlock(&hba->i_cmd.dev_cmd_lock);
+
+	return ret;
+}
+
+/**
+ * ufshcd_query_flag() - Helper function for composing flag query requests
+ * hba: per-adapter instance
+ * query_opcode: flag query to perform
+ * idn: flag idn to access
+ * flag_res: the flag value after the query request completes
+ *
+ * Returns 0 for success, non-zero in case of failure
+ */
+static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
+			enum flag_idn idn, bool *flag_res)
+{
+	struct ufs_query_req *query;
+	struct ufs_query_res *response;
+	int err = -ENOMEM;
+
+	query = kzalloc(sizeof(struct ufs_query_req), GFP_KERNEL);
+	if (!query) {
+		dev_err(hba->dev,
+			"%s: Failed allocating ufs_query_req instance\n",
+			__func__);
+		goto out_no_mem;
+	}
+	response = kzalloc(sizeof(struct ufs_query_res), GFP_KERNEL);
+	if (!response) {
+		dev_err(hba->dev,
+			"%s: Failed allocating ufs_query_res instance\n",
+			__func__);
+		goto out_free_query;
+	}
+
+	switch (opcode) {
+	case UPIU_QUERY_OPCODE_SET_FLAG:
+	case UPIU_QUERY_OPCODE_CLEAR_FLAG:
+	case UPIU_QUERY_OPCODE_TOGGLE_FLAG:
+		query->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST;
+		break;
+	case UPIU_QUERY_OPCODE_READ_FLAG:
+		query->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST;
+		break;
+	default:
+		dev_err(hba->dev,
+			"%s: Expected query flag opcode but got = %d\n",
+			__func__, opcode);
+		err = -EINVAL;
+		goto out;
+	}
+	query->upiu_req.opcode = opcode;
+	query->upiu_req.idn = idn;
+
+	/* Send query request */
+	err = ufshcd_send_query_request(hba, query, NULL, response);
+
+	if (err) {
+		dev_err(hba->dev,
+			"%s: Sending flag query for idn %d failed, err = %d\n",
+			__func__, idn, err);
+		goto out;
+	}
+
+	if (flag_res)
+		*flag_res = (response->upiu_res.value &
+				MASK_QUERY_UPIU_FLAG_LOC) & 0x1;
+
+out:
+	kfree(response);
+out_free_query:
+	kfree(query);
+out_no_mem:
+	return err;
+}
+
+/**
  * ufshcd_memory_alloc - allocate memory for host memory space data structures
  * @hba: per adapter instance
  *
@@ -1064,6 +1293,59 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
 }
 
 /**
+ * ufshcd_validate_device_init() - checks device readiness
+ * hba: per-adapter instance
+ *
+ * Set fDeviceInit flag, than, query the flag until the device clears the
+ * flag.
+ */
+static int ufshcd_validate_device_init(struct ufs_hba *hba)
+{
+	int i, retries, err = 0;
+	bool flag_res = 0;
+
+	for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+		/* Set the fDeviceIntit flag */
+		err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_SET_FLAG,
+					QUERY_FLAG_IDN_FDEVICEINIT, &flag_res);
+		if (!err || err == -ETIMEDOUT)
+			break;
+		dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err);
+	}
+	if (err) {
+		dev_err(hba->dev,
+			"%s setting fDeviceInit flag failed with error %d\n",
+			__func__, err);
+		goto out;
+	}
+
+	/* Start polling */
+	for (i = 0; i < QUERY_MAX_POLL_ITER && !err && flag_res; i++) {
+		retries = QUERY_REQ_RETRIES;
+		for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) {
+			err = ufshcd_query_flag(hba,
+					UPIU_QUERY_OPCODE_READ_FLAG,
+					QUERY_FLAG_IDN_FDEVICEINIT, &flag_res);
+			if (!err || err == -ETIMEDOUT)
+				break;
+			dev_dbg(hba->dev, "%s: error %d retrying\n", __func__,
+					err);
+		}
+	}
+	if (err)
+		dev_err(hba->dev,
+			"%s reading fDeviceInit flag failed with error %d\n",
+			__func__, err);
+	else if (flag_res)
+		dev_err(hba->dev,
+			"%s fDeviceInit was not cleared by the device\n",
+			__func__);
+
+out:
+	return err;
+}
+
+/**
  * ufshcd_make_hba_operational - Make UFS controller operational
  * @hba: per adapter instance
  *
@@ -1910,6 +2192,10 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)
 	if (ret)
 		goto out;
 
+	ret = ufshcd_validate_device_init(hba);
+	if (ret)
+		goto out;
+
 	scsi_scan_host(hba->host);
 out:
 	return;
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index e41fa5e..4e4c56f 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -70,6 +70,7 @@
 
 enum internal_cmd_type {
 	DEV_CMD_TYPE_NOP		= 0x0,
+	DEV_CMD_TYPE_QUERY		= 0x1,
 };
 
 /**
@@ -125,15 +126,29 @@ struct ufshcd_lrb {
 };
 
 /**
+ * struct ufs_query - holds relevent data structures for query request
+ * @request: request upiu and function
+ * @descriptor: buffer for sending/receiving descriptor
+ * @response: response upiu and response
+ */
+struct ufs_query {
+	struct ufs_query_req *request;
+	u8 *descriptor;
+	struct ufs_query_res *response;
+};
+
+/**
  * struct ufs_internal_cmd - all assosiated fields with internal commands
  * @dev_cmd_type: device management command type - Query, NOP OUT
  * @dev_cmd_lock: lock to allow one internal command at a time
  * @dev_cmd_complete: internal commands completion
+ * @query: required query data structures for sending query request
  */
 struct ufs_internal_cmd {
 	enum internal_cmd_type dev_cmd_type;
 	struct mutex dev_cmd_lock;
 	struct completion *dev_cmd_complete;
+	struct ufs_query query;
 };
 
 /**
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index d5c5f14..f1e1b74 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -39,7 +39,7 @@
 enum {
 	TASK_REQ_UPIU_SIZE_DWORDS	= 8,
 	TASK_RSP_UPIU_SIZE_DWORDS	= 8,
-	ALIGNED_UPIU_SIZE		= 128,
+	ALIGNED_UPIU_SIZE		= 512,
 };
 
 /* UFSHCI Registers */
-- 
1.7.6
-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

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

end of thread, other threads:[~2013-06-14 13:55 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-06-10 14:05 [PATCH 0/2] Dolev Raviv
2013-06-10 14:05 ` [PATCH 1/2] scsi: ufs: Add support for sending NOP OUT UPIU Dolev Raviv
2013-06-10 14:05   ` Dolev Raviv
2013-06-12  5:30   ` Santosh Y
2013-06-13  4:33     ` Sujit Reddy Thumma
2013-06-14  7:40       ` Sujit Reddy Thumma
2013-06-14 13:47         ` Santosh Y
2013-06-10 14:05 ` [PATCH 2/2] scsi: ufs: Set fDeviceInit flag to initiate device initialization Dolev Raviv
2013-06-10 14:05   ` Dolev Raviv
2013-06-12  5:34   ` Santosh Y
2013-06-13  4:36     ` Sujit Reddy Thumma
2013-06-14 13:55       ` Santosh Y
2013-06-10 14:12 [PATCH 0/2] Add suport for internal request (NOP and Query Request) Dolev Raviv
2013-06-10 14:12 ` [PATCH 2/2] scsi: ufs: Set fDeviceInit flag to initiate device initialization Dolev Raviv
2013-06-10 14:12   ` Dolev Raviv

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.