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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.