From: Luben Tuikov <luben_tuikov@adaptec.com>
To: Eero Volotinen <eero@ping-viini.org>,
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: Mon, 25 Oct 2004 16:55:18 -0400 [thread overview]
Message-ID: <417D6836.80509@adaptec.com> (raw)
In-Reply-To: <417D6123.4060902@ping-viini.org>
[-- Attachment #1: Type: text/plain, Size: 495 bytes --]
Eero Volotinen wrote:
>
>> Eero, can you try the attached patch? I wonder if we
>> can take the maximum capacity media which could be supported?
>> (This is "patch 2", you still have to apply "patch 1" which
>> removes the broken devices from unusual devs.)
>>
>> Thanks,
>> Luben
>>
>
> Ok. I test your patch in a few days and report results then.
Forgot to add code to weed out the descriptor type 0 (reserved)
case. Please try this (attached) version of the patch.
Thanks,
Luben
[-- Attachment #2: cap.patch --]
[-- Type: application/octet-stream, Size: 5469 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-25 17:01:03 -04:00
@@ -987,6 +987,155 @@
}
}
+/* 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.
+ */
+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 = be64_to_cpu(*(u64 *)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 = be32_to_cpu(*(u32 *)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 = be64_to_cpu(*(u64 *)buffer);
+ u64 x = be64_to_cpu(*(u64 *)buf);
+ if (rlba > x - 1) {
+ goto out_spec;
+ }
+ } else {
+ u32 rlba = be32_to_cpu(*(u32 *)buffer);
+ u32 x = be32_to_cpu(*(u32 *)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() */
+
+
+/* Try to use the READ FORMAT CAPACITIES command to check whether the
+ * READ CAPACITY result is correct.
+ */
+static void sd_read_format_cap(struct scsi_disk *sd, char *diskname,
+ struct scsi_request *SRpnt, unsigned char *buffer)
+{
+ unsigned char cmd[12];
+ unsigned char buf[12];
+ u32 rlba;
+ u32 x;
+
+ /* save the old buffer contents here */
+ memcpy(buf, buffer, 12);
+
+ rlba = be32_to_cpu(*(u32 *)buffer);
+
+ cmd[0] = 0x23; /* READ_FORMAT_CAPACITIES */
+ memset(&cmd[1], 0, 11);
+ cmd[8] = 12;
+ memset(buffer, 0, 12);
+
+ 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,
+ 12, SD_TIMEOUT, SD_MAX_RETRIES);
+
+ if (SRpnt->sr_result) {
+ /* Nothing can be assumed. */
+ printk(KERN_NOTICE "%s: %s: READ FORMAT CAPACITIES "
+ "not supported\n", __FUNCTION__, diskname);
+ goto done;
+ }
+
+ if ((buffer[8] & 3) == 0)
+ goto done;
+
+ x = be32_to_cpu(*(u32 *)(buffer + 4));
+ printk(KERN_NOTICE "%s: %s: %u vs. %u\n",
+ __FUNCTION__, diskname, rlba, x);
+ if (0 < x && x <= rlba) {
+ u32 *lba = (u32 *) buf;
+
+ printk(KERN_NOTICE "%s: %s: using lower capacity\n",
+ __FUNCTION__, diskname);
+ x -= 1;
+ *lba = cpu_to_be32(x);
+ }
+ done:
+ memcpy(buffer, buf, 12);
+}
+
/*
* read disk capacity
*/
@@ -1070,7 +1219,14 @@
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)
+ sd_read_format_cap(sdkp, diskname, SRpnt, buffer);
if (!longrc) {
sector_size = (buffer[4] << 24) |
@@ -1078,12 +1234,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 +1260,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-25 20:55 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 [this message]
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
[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=417D6836.80509@adaptec.com \
--to=luben_tuikov@adaptec.com \
--cc=eero@ping-viini.org \
--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).