From a6c976c6c4628ce0c9277c47e7545956d9d4f441 Mon Sep 17 00:00:00 2001
From: Matthew Dharm <mdharm-usb@one-eyed-alien.net>
Date: Sun, 4 Dec 2005 21:59:45 -0800
Subject: [PATCH] [PATCH] USB Storage: more sddr09 cleanups

This is the third of three patches to prepare the sddr09 subdriver for
conversion to the Sim-SCSI framework.  This patch (as596) moves the
computation of the LBA to the start of the read/write routines, so that
addresses completely beyond the end of the device can be detected and
reported differently from transfers that are partially within the
device's capacity.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Acked-by: Andries Brouwer <Andries.Brouwer@cwi.nl>
Signed-off-by: Matthew Dharm <mdharm-usb@one-eyed-alien.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/usb/storage/sddr09.c | 33 +++++++++++++++++++++++----------
 1 file changed, 23 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
index 760fe9362b6d..b8e7802c871d 100644
--- a/drivers/usb/storage/sddr09.c
+++ b/drivers/usb/storage/sddr09.c
@@ -711,6 +711,13 @@ sddr09_read_data(struct us_data *us,
 	unsigned int len, index, offset;
 	int result;
 
+	// Figure out the initial LBA and page
+	lba = address >> info->blockshift;
+	page = (address & info->blockmask);
+	maxlba = info->capacity >> (info->pageshift + info->blockshift);
+	if (lba >= maxlba)
+		return -EIO;
+
 	// Since we only read in one block at a time, we have to create
 	// a bounce buffer and move the data a piece at a time between the
 	// bounce buffer and the actual transfer buffer.
@@ -722,11 +729,6 @@ sddr09_read_data(struct us_data *us,
 		return -ENOMEM;
 	}
 
-	// Figure out the initial LBA and page
-	lba = address >> info->blockshift;
-	page = (address & info->blockmask);
-	maxlba = info->capacity >> (info->pageshift + info->blockshift);
-
 	// This could be made much more efficient by checking for
 	// contiguous LBA's. Another exercise left to the student.
 
@@ -928,13 +930,20 @@ sddr09_write_data(struct us_data *us,
 		  unsigned int sectors) {
 
 	struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;
-	unsigned int lba, page, pages;
+	unsigned int lba, maxlba, page, pages;
 	unsigned int pagelen, blocklen;
 	unsigned char *blockbuffer;
 	unsigned char *buffer;
 	unsigned int len, index, offset;
 	int result;
 
+	// Figure out the initial LBA and page
+	lba = address >> info->blockshift;
+	page = (address & info->blockmask);
+	maxlba = info->capacity >> (info->pageshift + info->blockshift);
+	if (lba >= maxlba)
+		return -EIO;
+
 	// blockbuffer is used for reading in the old data, overwriting
 	// with the new data, and performing ECC calculations
 
@@ -961,10 +970,6 @@ sddr09_write_data(struct us_data *us,
 		return -ENOMEM;
 	}
 
-	// Figure out the initial LBA and page
-	lba = address >> info->blockshift;
-	page = (address & info->blockmask);
-
 	result = 0;
 	index = offset = 0;
 
@@ -975,6 +980,14 @@ sddr09_write_data(struct us_data *us,
 		pages = min(sectors, info->blocksize - page);
 		len = (pages << info->pageshift);
 
+		/* Not overflowing capacity? */
+		if (lba >= maxlba) {
+			US_DEBUGP("Error: Requested lba %u exceeds "
+				  "maximum %u\n", lba, maxlba);
+			result = -EIO;
+			break;
+		}
+
 		// Get the data from the transfer buffer
 		usb_stor_access_xfer_buf(buffer, len, us->srb,
 				&index, &offset, FROM_XFER_BUF);