platform: msm_shared: Fix the retrival of sense buffer

When a SCSI command fails, the reponse contains the
sense request. We need to parse the response to get
the sense buffer instead of sending a additional
sense request command which would then return data
that is not useful.

Change-Id: I95b7174978068209d1b5ed4b3fb7d3669a04c3af
diff --git a/platform/msm_shared/dme.c b/platform/msm_shared/dme.c
index 61efb47..431672b 100644
--- a/platform/msm_shared/dme.c
+++ b/platform/msm_shared/dme.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -137,7 +137,7 @@
 	req_upiu.idn           = query->idn;
 	req_upiu.trans_type    = UPIU_TYPE_QUERY_REQ;
 	req_upiu.dd            = UTRD_NO_DATA_TRANSFER;
-	req_upiu.resp_ptr      = (struct upiu_basic_hdr *) &resp_upiu;
+	req_upiu.resp_ptr      = (struct upiu_basic_resp_hdr *) &resp_upiu;
 	req_upiu.resp_len      = sizeof(resp_upiu);
 	req_upiu.resp_data_ptr = query->buf;
 	req_upiu.timeout_msecs = UTP_GENERIC_CMD_TIMEOUT;
@@ -430,7 +430,7 @@
 int dme_send_nop_query(struct ufs_dev *dev)
 {
 	struct upiu_req_build_type     req_upiu;
-	struct upiu_basic_hdr          resp_upiu;
+	struct upiu_basic_resp_hdr     resp_upiu;
 	int                            ret;
 	unsigned                       try_again;
 
diff --git a/platform/msm_shared/include/ucs.h b/platform/msm_shared/include/ucs.h
index 094946e..48c50db 100644
--- a/platform/msm_shared/include/ucs.h
+++ b/platform/msm_shared/include/ucs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2015 The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -175,4 +175,6 @@
 int ucs_do_scsi_rpmb_read(struct ufs_dev *dev, uint32_t *req_buf, uint32_t blk_cnt,
                                  uint32_t *resp_buffer, uint32_t *response_length);
 
+/* This function parses the first byte of the sense data and returns the sense key */
+int parse_sense_key(uint32_t sense_data);
 #endif
diff --git a/platform/msm_shared/include/upiu.h b/platform/msm_shared/include/upiu.h
index 1c9968d..e081909 100644
--- a/platform/msm_shared/include/upiu.h
+++ b/platform/msm_shared/include/upiu.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.

+/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.

  *

  * Redistribution and use in source and binary forms, with or without

  * modification, are permitted provided that the following conditions are

@@ -44,6 +44,27 @@
 	uint16_t data_seg_len;

 } __PACKED;

 

+

+struct upiu_basic_resp_hdr

+{

+	uint8_t  trans_type;

+	uint8_t  flags;

+	uint8_t  lun;

+	uint8_t  task_tag;

+	uint8_t  cmd_set_type;

+	uint8_t  query_task_mgmt_func;

+	uint8_t  response;

+	uint8_t  status;

+	uint8_t  total_ehs_len;

+	uint8_t  device_info;

+	uint16_t data_seg_len;

+	uint32_t residual_transfer_count;

+	uint32_t reserved[4];

+	uint16_t sense_length;

+	uint16_t sense_response_code;

+	uint32_t sense_data[4];

+} __PACKED;

+

 struct upiu_trans_mgmt_query_hdr

 {

 	struct upiu_basic_hdr basic_hdr;

@@ -149,7 +170,7 @@
 	uint8_t                         idn;

 	uint8_t                         index;

 	uint8_t                         selector;

-	struct upiu_basic_hdr       *resp_ptr;

+	struct upiu_basic_resp_hdr       *resp_ptr;

 	uint64_t                        resp_len;

 	uint16_t                        resp_data_len;

 	addr_t                        resp_data_ptr;

diff --git a/platform/msm_shared/ucs.c b/platform/msm_shared/ucs.c
index e77f2d1..f820734 100644
--- a/platform/msm_shared/ucs.c
+++ b/platform/msm_shared/ucs.c
@@ -37,8 +37,7 @@
 int ucs_do_scsi_cmd(struct ufs_dev *dev, struct scsi_req_build_type *req)
 {
 	struct upiu_req_build_type req_upiu;
-	struct upiu_basic_hdr      resp_upiu;
-	int                        ret;
+	struct upiu_basic_resp_hdr      resp_upiu;
 
 	memset(&req_upiu, 0 , sizeof(struct upiu_req_build_type));
 
@@ -68,9 +67,14 @@
 	{
 		if (resp_upiu.status == SCSI_STATUS_CHK_COND && (*((uint8_t *)(req->cdb)) != SCSI_CMD_SENSE_REQ))
 		{
-			ret = ucs_do_request_sense(dev);
-			if (ret)
-				dprintf(CRITICAL, "SCSI request sense failed.\n");
+			dprintf(CRITICAL, "Data segment length: %x\n", BE16(resp_upiu.data_seg_len));
+			if (BE16(resp_upiu.data_seg_len))
+			{
+				dprintf(CRITICAL, "SCSI Request failed and we have sense data\n");
+				dprintf(CRITICAL, "Sense Data Length/Response Code: 0x%x/0x%x\n", BE16(resp_upiu.sense_length), BE16(resp_upiu.sense_response_code));
+				parse_sense_key(resp_upiu.sense_data[0]);
+				dprintf(CRITICAL, "Sense Buffer (HEX): 0x%x 0x%x 0x%x 0x%x\n", BE32(resp_upiu.sense_data[0]), BE32(resp_upiu.sense_data[1]), BE32(resp_upiu.sense_data[2]), BE32(resp_upiu.sense_data[3]));
+			}
 		}
 
 		dprintf(CRITICAL, "ucs_do_scsi_cmd failed status = %x\n", resp_upiu.status);
@@ -80,6 +84,57 @@
 	return UFS_SUCCESS;
 }
 
+int parse_sense_key(uint32_t sense_data)
+{
+	uint32_t key = BE32(sense_data) >> 24;
+	dprintf(CRITICAL, "Sense Key: 0x%x\n", key);
+	switch(key)
+	{
+		case 0x0:
+			dprintf(INFO, "NO SENSE: No information available to be reported\n");
+			break;
+		case 0x1:
+			dprintf(INFO, "RECOVERED ERROR: Additional sense buffer bytes indicate further details\n");
+			break;
+		case 0x2:
+			dprintf(INFO, "NOT READY: Logical Unit Not Ready and cannot be accessed at this time\n");
+			break;
+		case 0x3:
+			dprintf(INFO, "MEDIUM ERROR: Last command unsuccessful due to non-recoverable error condition\n");
+			break;
+		case 0x4:
+			dprintf(INFO, "HARDWARE ERROR: Target detected a non-recoverable hardware error\n");
+			break;
+		case 0x5:
+			dprintf(INFO, "ILLEGAL REQUEST: Illegal parameter in the command descriptor block in the command sent\n");
+			break;
+		case 0x6:
+			dprintf(INFO, "UNIT ATTENTION: Unit has been reset/unexpectedly power on/removable media has changed\n");
+			break;
+		case 0x7:
+			dprintf(INFO, "DATA PROTECT: Read/Write operation attempted on a block that is protected from this operation\n");
+			break;
+		case 0x8:
+			dprintf(INFO, "BLANK CHECK: Target encountered blank or unformatted media while reading or writing\n");
+			break;
+		case 0x9:
+			dprintf(INFO, "VENDOR SPECIFIC: Vendor specific error or exceptional conditions\n");
+			break;
+		case 0xB:
+			dprintf(INFO, "ABORTED COMMAND: Target aborted the execution of the command\n");
+			break;
+		case 0xD:
+			dprintf(INFO, "VOLUME OVERFLOW: Buffered peripheral device has reached the end of partition\n");
+			break;
+		case 0xE:
+			dprintf(INFO, "MISCOMPARE: Source data did not match the data read from the media\n");
+			break;
+		default:
+			dprintf(INFO, "INVALID sense key\n");
+	}
+	return key;
+}
+
 int ucs_do_scsi_rpmb_read(struct ufs_dev *dev, uint32_t *req_buf, uint32_t blk_cnt,
                                  uint32_t *resp_buf, uint32_t *resp_len)
 {