From: Luben Tuikov <luben_tuikov@adaptec.com>
To: SCSI Mailing List <linux-scsi@vger.kernel.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Subject: Re: Handling erroneous READ CAPACITY response in sd.c
Date: Wed, 20 Oct 2004 09:28:42 -0400 [thread overview]
Message-ID: <4176680A.7080208@adaptec.com> (raw)
In-Reply-To: <Pine.LNX.4.44L0.0410191738250.713-100000@netrider.rowland.org>
[-- Attachment #1: Type: text/plain, Size: 93 bytes --]
(patch attached -- got lost somehow)
Signed-off-by: Luben Tuikov <luben_tuikov@adaptec.com>
[-- Attachment #2: sd_read_cap.patch --]
[-- Type: application/octet-stream, Size: 4565 bytes --]
===== drivers/scsi/sd.c 1.161 vs edited =====
--- 1.161/drivers/scsi/sd.c 2004-10-15 10:46:07 -04:00
+++ edited/drivers/scsi/sd.c 2004-10-19 16:51:46 -04:00
@@ -987,6 +987,112 @@
}
}
+/* sd_read_true_cap: Some device servers incorrectly return the
+ * capacity as opposed to the LBA of the last logical block of the
+ * block device.
+ *
+ * We try to fix this as follows: Let x = Returned LBA from the last
+ * READ CAPACITY command issued (result in "buffer"). Reissue the
+ * READ CAPACITY command as follows: set the partial medium indicator
+ * (PMI) bit to one; set the LBA to x - 1. Fire off that READ CAPACITY
+ * command.
+ *
+ * If we get success,
+ * If Returned LBA > x - 1, then capacity is x+1, spec behavior.
+ * Else Returned LBA <= x - 1, then capacity is x, broken device server.
+ * Else error, nothing can be assumed, capacity is x+1.
+ */
+#define GET_RLBA_READ_CAP16(_buffer) (((u64)(_buffer)[0] << 56) | \
+ ((u64)(_buffer)[1] << 48) | \
+ ((u64)(_buffer)[2] << 40) | \
+ ((u64)(_buffer)[3] << 32) | \
+ ((sector_t)(_buffer)[4] << 24) | \
+ ((sector_t)(_buffer)[5] << 16) | \
+ ((sector_t)(_buffer)[6] << 8) | \
+ (sector_t)(_buffer)[7])
+#define GET_RLBA_READ_CAP10(_buffer) (((sector_t)(_buffer)[0] << 24) | \
+ ((_buffer)[1] << 16) | \
+ ((_buffer)[2] << 8) | \
+ (_buffer)[3])
+static void sd_read_true_cap(struct scsi_disk *sd, char *diskname,
+ struct scsi_request *SRpnt, unsigned char *buffer,
+ int longrc)
+{
+ unsigned char cmd[16];
+ unsigned char buf[12];
+
+ /* save the old buffer contents here */
+ memcpy(buf, buffer, 12);
+
+ if (longrc) {
+ u64 *lba = (u64 *) (cmd+2);
+ u64 rlba;
+
+ memset((void *) cmd, 0, 16);
+ cmd[0] = SERVICE_ACTION_IN;
+ cmd[1] = SAI_READ_CAPACITY_16;
+ cmd[13] = 12;
+
+ rlba = GET_RLBA_READ_CAP16(buffer);
+ rlba -= 1;
+ *lba = cpu_to_be64(rlba);
+ /* turn on the PMI bit */
+ cmd[14] |= 1;
+ memset((void *) buffer, 0, 12);
+ } else {
+ u32 *lba = (u32 *) (cmd+2);
+ u32 rlba;
+
+ cmd[0] = READ_CAPACITY;
+ memset((void *) &cmd[1], 0, 9);
+
+ rlba = GET_RLBA_READ_CAP10(buffer);
+ rlba -= 1;
+ *lba = cpu_to_be32(rlba);
+ /* turn on the PMI bit */
+ cmd[8] |= 1;
+ memset((void *) buffer, 0, 8);
+ }
+
+ SRpnt->sr_cmd_len = 0;
+ SRpnt->sr_sense_buffer[0] = 0;
+ SRpnt->sr_sense_buffer[2] = 0;
+ SRpnt->sr_data_direction = DMA_FROM_DEVICE;
+
+ scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
+ longrc ? 12 : 8, SD_TIMEOUT, SD_MAX_RETRIES);
+
+ if (SRpnt->sr_result) {
+ /* Nothing can be assumed. */
+ printk(KERN_NOTICE "%s: %s: PMI not supported\n",
+ __FUNCTION__, diskname);
+ memcpy(buffer, buf, 12);
+ return;
+ }
+
+ if (longrc) {
+ u64 rlba = GET_RLBA_READ_CAP16(buffer);
+ u64 x = GET_RLBA_READ_CAP16(buf);
+ if (rlba > x - 1) {
+ goto out_spec;
+ }
+ } else {
+ u32 rlba = GET_RLBA_READ_CAP10(buffer);
+ u32 x = GET_RLBA_READ_CAP10(buf);
+ if (rlba > x - 1) {
+ goto out_spec;
+ }
+ }
+ printk(KERN_NOTICE "%s: %s: broken device server\n", __FUNCTION__,
+ diskname);
+ return;
+
+ out_spec:
+ /* Capacity is x+1, spec behavior. */
+ printk(KERN_NOTICE "%s: %s: spec behavior\n", __FUNCTION__, diskname);
+ memcpy(buffer, buf, 12);
+} /* end sd_read_true_cap() */
+
/*
* read disk capacity
*/
@@ -1070,7 +1176,12 @@
sdkp->capacity = 1 + (sector_t) 0xffffffff;
goto got_data;
- }
+ }
+
+ /* Check if the device reported CAPACITY as opposed to
+ * the maxumum LBA (as per the SBC spec).
+ */
+ sd_read_true_cap(sdkp, diskname, SRpnt, buffer, longrc);
if (!longrc) {
sector_size = (buffer[4] << 24) |
@@ -1078,12 +1189,14 @@
if (buffer[0] == 0xff && buffer[1] == 0xff &&
buffer[2] == 0xff && buffer[3] == 0xff) {
if(sizeof(sdkp->capacity) > 4) {
- printk(KERN_NOTICE "%s : very big device. try to use"
- " READ CAPACITY(16).\n", diskname);
+ printk(KERN_NOTICE "%s : very big device. "
+ "try to use READ CAPACITY(16).\n",
+ diskname);
longrc = 1;
goto repeat;
} else {
- printk(KERN_ERR "%s: too big for kernel. Assuming maximum 2Tb\n", diskname);
+ printk(KERN_ERR "%s: too big for kernel. "
+ "Assuming maximum 2Tb\n", diskname);
}
}
sdkp->capacity = 1 + (((sector_t)buffer[0] << 24) |
@@ -1102,7 +1215,7 @@
sector_size = (buffer[8] << 24) |
(buffer[9] << 16) | (buffer[10] << 8) | buffer[11];
- }
+ }
got_data:
if (sector_size == 0) {
next prev parent reply other threads:[~2004-10-20 13:28 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-10-15 19:19 Handling erroneous READ CAPACITY response in sd.c Alan Stern
2004-10-19 20:58 ` Luben Tuikov
2004-10-19 21:52 ` Alan Stern
2004-10-20 12:40 ` Luben Tuikov
2004-10-20 15:48 ` Alan Stern
2004-10-24 12:34 ` Eero Volotinen
2004-10-25 19:41 ` Alan Stern
2004-10-25 20:27 ` Luben Tuikov
2004-10-25 20:08 ` Luben Tuikov
[not found] ` <417D6123.4060902@ping-viini.org>
2004-10-25 20:55 ` Luben Tuikov
2004-11-05 16:18 ` Alan Stern
2004-11-05 18:06 ` Matthew Dharm
2004-11-05 18:34 ` Alan Stern
2004-11-05 18:44 ` [usb-storage] " Andries Brouwer
2004-11-05 21:38 ` Alan Stern
2004-11-05 21:59 ` Andries Brouwer
2004-11-08 18:55 ` Luben Tuikov
2004-11-08 21:03 ` Alan Stern
2004-11-08 21:35 ` Luben Tuikov
2004-11-08 22:04 ` Matthew Dharm
2004-11-08 22:08 ` Alan Stern
2004-10-20 13:28 ` Luben Tuikov [this message]
[not found] <417AFDA5.5080806@micro.ee.nthu.edu.tw>
2004-10-24 17:11 ` Alan Stern
2004-10-25 21:54 ` Darsen
2004-10-26 14:43 ` Alan Stern
[not found] <417F6412.90000@micro.ee.nthu.edu.tw>
2004-10-27 19:11 ` Alan Stern
2004-10-29 14:22 ` Darsen
2004-10-29 16:46 ` Alan Stern
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4176680A.7080208@adaptec.com \
--to=luben_tuikov@adaptec.com \
--cc=linux-scsi@vger.kernel.org \
--cc=stern@rowland.harvard.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).