mmc: msm_sdcc: Send CMD12 even if r/w command has errors

In SD/eMMC cards read/write multi block commands (CMD18/CMD25)
cause state transition from Transfer state to Data/Receive
state. If there are errors in recieving the response for
these commands the driver doesn't send CMD12 to stop the
transaction and hence the card forever be in Data/Rcv
state until further CMD7 or CMD12 is issued. Fix this by
sending  CMD12 (STOP_TRANSMISSION) to change the state back to
transfer mode aborting data transfers.

Note: With current r/w command response it is impossible to
determine if the card has actually transitioned to Data/Rcv
state since the actual card status is reflected at execution
time. Also, there may be errors in "sending" CMD18/25 itself.
Sending CMD12 in this case doesn't cause any harm except one
more command timeout error which is non-fatal.

Change-Id: I1e298260d39cfac796113a4276652626c4011fc3
Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org>
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index cdfe10e..e853699 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -477,7 +477,11 @@
 			goto out;
 		}
 		msmsdcc_stop_data(host);
-		if (!mrq->data->stop || mrq->cmd->error ||
+
+		if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
+				|| !mrq->sbc)) {
+			msmsdcc_start_command(host, mrq->data->stop, 0);
+		} else if (!mrq->data->stop || mrq->cmd->error ||
 			(mrq->sbc && !mrq->data->error)) {
 			host->curr.mrq = NULL;
 			host->curr.cmd = NULL;
@@ -487,9 +491,6 @@
 
 			mmc_request_done(host->mmc, mrq);
 			return;
-		} else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
-				|| !mrq->sbc)) {
-			msmsdcc_start_command(host, mrq->data->stop, 0);
 		}
 	}
 
@@ -634,7 +635,10 @@
 			return;
 		}
 		msmsdcc_stop_data(host);
-		if (!mrq->data->stop || mrq->cmd->error ||
+		if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
+				|| !mrq->sbc)) {
+			msmsdcc_start_command(host, mrq->data->stop, 0);
+		} else if (!mrq->data->stop || mrq->cmd->error ||
 			(mrq->sbc && !mrq->data->error)) {
 			host->curr.mrq = NULL;
 			host->curr.cmd = NULL;
@@ -644,9 +648,6 @@
 
 			mmc_request_done(host->mmc, mrq);
 			return;
-		} else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
-				|| !mrq->sbc)) {
-			msmsdcc_start_command(host, mrq->data->stop, 0);
 		}
 	}
 	spin_unlock_irqrestore(&host->lock, flags);
@@ -943,7 +944,7 @@
 msmsdcc_start_command_deferred(struct msmsdcc_host *host,
 				struct mmc_command *cmd, u32 *c)
 {
-	DBG(host, "op %02x arg %08x flags %08x\n",
+	DBG(host, "op %d arg %08x flags %08x\n",
 	    cmd->opcode, cmd->arg, cmd->flags);
 
 	*c |= (cmd->opcode | MCI_CPSM_ENABLE);
@@ -1392,9 +1393,16 @@
 		else if (host->curr.data) { /* Non DMA */
 			msmsdcc_reset_and_restore(host);
 			msmsdcc_stop_data(host);
-			msmsdcc_request_end(host, cmd->mrq);
+			if (cmd->data && cmd->data->stop)
+				msmsdcc_start_command(host,
+						cmd->data->stop, 0);
+			else
+				msmsdcc_request_end(host, cmd->mrq);
 		} else { /* host->data == NULL */
-			if (!cmd->error && host->prog_enable) {
+			if (cmd->data && cmd->data->stop) {
+				msmsdcc_start_command(host,
+						cmd->data->stop, 0);
+			} else if (!cmd->error && host->prog_enable) {
 				if (status & MCI_PROGDONE) {
 					host->prog_enable = 0;
 					msmsdcc_request_end(host, cmd->mrq);