From mboxrd@z Thu Jan 1 00:00:00 1970 From: Patrick Mansfield Subject: [PATCH/RFT] mode sense madness always use page 8 Date: Thu, 30 Oct 2003 10:05:01 -0800 Sender: linux-scsi-owner@vger.kernel.org Message-ID: <20031030100501.A7250@beaverton.ibm.com> References: <1067531731.4250.11.camel@pathost1.iomegacorp.com> <20031030091808.A6781@beaverton.ibm.com> <1067535485.6411.42.camel@pathost1.iomegacorp.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Return-path: Received: from e5.ny.us.ibm.com ([32.97.182.105]:59094 "EHLO e5.ny.us.ibm.com") by vger.kernel.org with ESMTP id S262725AbTJ3SGA (ORCPT ); Thu, 30 Oct 2003 13:06:00 -0500 Content-Disposition: inline In-Reply-To: <1067535485.6411.42.camel@pathost1.iomegacorp.com>; from p.lavarre@ieee.org on Thu, Oct 30, 2003 at 10:38:05AM -0700 List-Id: linux-scsi@vger.kernel.org To: Pat LaVarre Cc: stern@rowland.harvard.edu, ronald@kuetemeier.com, linux-scsi@vger.kernel.org, usb-storage@one-eyed-alien.net, james.bottomley@steeleye.com Here's a patch, per Pat Lavarre's suggestion, this can't go in without others verifying and testing it, and without input or comment from others (at least James). Again no USB testing here, tested on 2 sets of SPI attached disks, and 2 sets of FCP attached disks. It really needs testing on removable media to actually hit the write protect check. Ronald does this work for you? ------ Use MODE SENSE page 8 whether asking for write protect information or cache type. Always use the exact size of the expected result. diff -uprN -X /home/patman/dontdiff bl-25/drivers/scsi/scsi_lib.c use_page8_always-bl-2.5/drivers/scsi/scsi_lib.c --- bl-25/drivers/scsi/scsi_lib.c Mon Sep 29 12:21:09 2003 +++ use_page8_always-bl-2.5/drivers/scsi/scsi_lib.c Thu Oct 30 09:23:19 2003 @@ -1377,6 +1377,11 @@ __scsi_mode_sense(struct scsi_request *s if (use_10_for_ms) { if (len < 8) len = 8; + else if (len > 28) + /* + * 20 bytes + 8 byte header + */ + len = 28; cmd[0] = MODE_SENSE_10; cmd[8] = len; @@ -1384,6 +1389,11 @@ __scsi_mode_sense(struct scsi_request *s } else { if (len < 4) len = 4; + else if (len > 24) + /* + * 20 bytes + 4 byte header + */ + len = 24; cmd[0] = MODE_SENSE; cmd[4] = len; diff -uprN -X /home/patman/dontdiff bl-25/drivers/scsi/sd.c use_page8_always-bl-2.5/drivers/scsi/sd.c --- bl-25/drivers/scsi/sd.c Mon Oct 27 14:28:18 2003 +++ use_page8_always-bl-2.5/drivers/scsi/sd.c Thu Oct 30 09:35:53 2003 @@ -1085,8 +1085,10 @@ sd_do_mode_sense(struct scsi_request *SR */ static void sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, - struct scsi_request *SRpnt, unsigned char *buffer) { + struct scsi_request *SRpnt, unsigned char *buffer) +{ int res; + int len; struct scsi_mode_data data; if (sdkp->device->skip_ms_page_3f) { @@ -1094,26 +1096,16 @@ sd_read_write_protect_flag(struct scsi_d return; } - /* - * First attempt: ask for all pages (0x3F), but only 4 bytes. - * We have to start carefully: some devices hang if we ask - * for more than is available. - */ - res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 4, &data); - - /* - * Second attempt: ask for page 0 - * When only page 0 is implemented, a request for page 3F may return - * Sense Key 5: Illegal Request, Sense Code 24: Invalid field in CDB. - */ - if (!scsi_status_is_good(res)) - res = sd_do_mode_sense(SRpnt, 0, 0, buffer, 4, &data); - - /* - * Third attempt: ask 255 bytes, as we did earlier. - */ - if (!scsi_status_is_good(res)) - res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 255, &data); + if (sdkp->device->use_10_for_ms) + /* + * __mode_sense auto-retries with a size of 24 if it + * switches to a 6 byte command. + */ + len = 28; /* 20 + 8 byte header */ + else + len = 24; /* 20 + 4 byte header */ + + res = sd_do_mode_sense(SRpnt, 0, 8, buffer, len, &data); if (!scsi_status_is_good(res)) { printk(KERN_WARNING @@ -1130,42 +1122,36 @@ sd_read_write_protect_flag(struct scsi_d /* * sd_read_cache_type - called only from sd_revalidate_disk() * called with buffer of length 512 + * + * XXX Combine this with sd_read_write_protect_flag, so we only get the + * page once. */ static void sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, - struct scsi_request *SRpnt, unsigned char *buffer) { + struct scsi_request *SRpnt, unsigned char *buffer) +{ int len = 0, res; - - const int dbd = 0; /* DBD */ - const int modepage = 0x08; /* current values, cache page */ struct scsi_mode_data data; - if (sdkp->device->skip_ms_page_8) - goto defaults; - - /* cautiously ask */ - res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, 4, &data); - - if (!scsi_status_is_good(res)) - goto bad_sense; + sdkp->WCE = 0; + sdkp->RCD = 0; - /* that went OK, now ask for the proper length */ - len = data.length; - - /* - * We're only interested in the first three bytes, actually. - * But the data cache page is defined for the first 20. - */ - if (len < 3) - goto bad_sense; - if (len > 20) - len = 20; + if (sdkp->device->skip_ms_page_8) { + printk(KERN_ERR "%s: assuming drive cache: write through\n", + diskname); + return; + } - /* Take headers and block descriptors into account */ - len += data.header_length + data.block_descriptor_length; + if (sdkp->device->use_10_for_ms) + /* + * __mode_sense auto-retries with a size of 24 if it + * switches to a 6 byte command. + */ + len = 28; /* 20 + 8 byte header */ + else + len = 24; /* 20 + 4 byte header */ - /* Get the data */ - res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, len, &data); + res = sd_do_mode_sense(SRpnt, 0, 8, buffer, len, &data); if (scsi_status_is_good(res)) { const char *types[] = { @@ -1185,10 +1171,7 @@ sd_read_cache_type(struct scsi_disk *sdk diskname, types[ct]); return; - } - -bad_sense: - if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 + } else if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 && (SRpnt->sr_sense_buffer[2] & 0x0f) == ILLEGAL_REQUEST /* ASC 0x24 ASCQ 0x00: Invalid field in CDB */ && SRpnt->sr_sense_buffer[12] == 0x24 @@ -1199,12 +1182,6 @@ bad_sense: printk(KERN_ERR "%s: asking for cache data failed\n", diskname); } - -defaults: - printk(KERN_ERR "%s: assuming drive cache: write through\n", - diskname); - sdkp->WCE = 0; - sdkp->RCD = 0; } /**