diff mbox

ahci: Fix data abort on multiple scsi resets.

Message ID 1396362400-32305-1-git-send-email-rogerq@ti.com
State Accepted
Commit 3f62971162370213271dc1e7a396b6b3a6d5b6c6
Headers show

Commit Message

Roger Quadros April 1, 2014, 2:26 p.m. UTC
Commit 2faf5fb82ed6 introduced a regression that causes a data
abort when running scsi init followed by scsi reset.

There are 2 problems with the original commit
1) ALLOC_CACHE_ALIGN_BUFFER() allocates memory on the stack but is
assigned to ataid[port] and used by other functions.
2) The function ata_scsiop_inquiry() tries to free memory which was
never allocated on the heap.

Fix these problems by using tmpid as a temporary cache aligned buffer.
Allocate memory separately for ataid[port] and re-use it if required.

Fixes: 2faf5fb82ed6 (ahci: Fix cache align error messages)

Reported-by: Eli Nidam <elini@marvell.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/block/ahci.c | 23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)

Comments

Tom Rini April 2, 2014, 9:18 p.m. UTC | #1
On Tue, Apr 01, 2014 at 05:26:40PM +0300, Roger Quadros wrote:

> Commit 2faf5fb82ed6 introduced a regression that causes a data
> abort when running scsi init followed by scsi reset.
> 
> There are 2 problems with the original commit
> 1) ALLOC_CACHE_ALIGN_BUFFER() allocates memory on the stack but is
> assigned to ataid[port] and used by other functions.
> 2) The function ata_scsiop_inquiry() tries to free memory which was
> never allocated on the heap.
> 
> Fix these problems by using tmpid as a temporary cache aligned buffer.
> Allocate memory separately for ataid[port] and re-use it if required.
> 
> Fixes: 2faf5fb82ed6 (ahci: Fix cache align error messages)
> 
> Reported-by: Eli Nidam <elini@marvell.com>
> Signed-off-by: Roger Quadros <rogerq@ti.com>

Applied to u-boot/master, thanks!
diff mbox

Patch

diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c
index a409f63..c8f6573 100644
--- a/drivers/block/ahci.c
+++ b/drivers/block/ahci.c
@@ -623,6 +623,7 @@  static int ata_scsiop_inquiry(ccb *pccb)
 		95 - 4,
 	};
 	u8 fis[20];
+	u16 *idbuf;
 	ALLOC_CACHE_ALIGN_BUFFER(u16, tmpid, ATA_ID_WORDS);
 	u8 port;
 
@@ -649,17 +650,25 @@  static int ata_scsiop_inquiry(ccb *pccb)
 		return -EIO;
 	}
 
-	if (ataid[port])
-		free(ataid[port]);
-	ataid[port] = tmpid;
-	ata_swap_buf_le16(tmpid, ATA_ID_WORDS);
+	if (!ataid[port]) {
+		ataid[port] = malloc(ATA_ID_WORDS * 2);
+		if (!ataid[port]) {
+			printf("%s: No memory for ataid[port]\n", __func__);
+			return -ENOMEM;
+		}
+	}
+
+	idbuf = ataid[port];
+
+	memcpy(idbuf, tmpid, ATA_ID_WORDS * 2);
+	ata_swap_buf_le16(idbuf, ATA_ID_WORDS);
 
 	memcpy(&pccb->pdata[8], "ATA     ", 8);
-	ata_id_strcpy((u16 *) &pccb->pdata[16], &tmpid[ATA_ID_PROD], 16);
-	ata_id_strcpy((u16 *) &pccb->pdata[32], &tmpid[ATA_ID_FW_REV], 4);
+	ata_id_strcpy((u16 *)&pccb->pdata[16], &idbuf[ATA_ID_PROD], 16);
+	ata_id_strcpy((u16 *)&pccb->pdata[32], &idbuf[ATA_ID_FW_REV], 4);
 
 #ifdef DEBUG
-	ata_dump_id(tmpid);
+	ata_dump_id(idbuf);
 #endif
 	return 0;
 }