fix(ufs): retry commands on unit attention

Unit Attention Condition (UAC) gets set on a warm reset. Sending any
command (other than INQUIRY and REPORT LUNs) clears UAC, so its good to
add some retries when UAC is encountered

Signed-off-by: Anand Saminathan <anans@google.com>
Change-Id: Ia03b916d68565d0f3d25086b7f6d8c51d557b64f
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c
index 754d173..d8c0a14 100644
--- a/drivers/ufs/ufs.c
+++ b/drivers/ufs/ufs.c
@@ -477,6 +477,7 @@
 {
 	utrd_header_t *hd;
 	resp_upiu_t *resp;
+	sense_data_t *sense;
 	unsigned int data;
 	int slot;
 
@@ -499,6 +500,15 @@
 	inv_dcache_range((uintptr_t)hd, UFS_DESC_SIZE);
 	assert(hd->ocs == OCS_SUCCESS);
 	assert((resp->trans_type & TRANS_TYPE_CODE_MASK) == trans_type);
+
+	sense = &resp->sd.sense;
+	if (sense->resp_code == SENSE_DATA_VALID &&
+	    sense->sense_key == SENSE_KEY_UNIT_ATTENTION && sense->asc == 0x29 &&
+	    sense->ascq == 0) {
+		WARN("Unit Attention Condition\n");
+		return -EAGAIN;
+	}
+
 	(void)resp;
 	(void)slot;
 	return 0;
@@ -507,14 +517,18 @@
 static void ufs_send_cmd(utp_utrd_t *utrd, uint8_t cmd_op, uint8_t lun, int lba, uintptr_t buf,
 			 size_t length)
 {
-	int result;
-
-	get_utrd(utrd);
+	int result, i;
 
-	result = ufs_prepare_cmd(utrd, cmd_op, lun, lba, buf, length);
-	assert(result == 0);
-	ufs_send_request(utrd->task_tag);
-	result = ufs_check_resp(utrd, RESPONSE_UPIU);
+	for (i = 0; i < UFS_CMD_RETRIES; ++i) {
+		get_utrd(utrd);
+		result = ufs_prepare_cmd(utrd, cmd_op, lun, lba, buf, length);
+		assert(result == 0);
+		ufs_send_request(utrd->task_tag);
+		result = ufs_check_resp(utrd, RESPONSE_UPIU);
+		if (result == 0 || result == -EIO) {
+			break;
+		}
+	}
 	assert(result == 0);
 	(void)result;
 }