From: James Bottomley <James.Bottomley@steeleye.com>
To: dougg@torque.net
Cc: SCSI Mailing List <linux-scsi@vger.kernel.org>
Subject: Re: [PATCH] definitive abstraction of the mode_sense commands
Date: 24 Jun 2003 12:58:42 -0500 [thread overview]
Message-ID: <1056477523.2085.170.camel@mulgrave> (raw)
In-Reply-To: <3EF80775.9020105@torque.net>
[-- Attachment #1: Type: text/plain, Size: 252 bytes --]
I fixed your comments (I did have DBD's meaning reversed when I first
made the patch---I fixed it all except for the comment).
I also added the ability to pass LLBAA in the dbd part.
Plus some coding style fixes that certain persons noticed.
James
[-- Attachment #2: tmp.diff --]
[-- Type: text/plain, Size: 13586 bytes --]
# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.1408 -> 1.1414
# include/scsi/scsi_device.h 1.1 -> 1.3
# drivers/scsi/sr.c 1.82 -> 1.83
# drivers/scsi/scsi_syms.c 1.40 -> 1.42
# drivers/scsi/scsi_lib.c 1.95 -> 1.99
# drivers/scsi/sd.c 1.123 -> 1.126
# include/scsi/scsi_request.h 1.1 -> 1.3
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/06/23 jejb@raven.il.steeleye.com 1.1409
# SCSI: abstract mode_sense 6 and 10 out completely
#
# Move the mode_sense request routines to a central location and make
# all block device consumers use it. Also abstract the header as
# part of the return to hide the 6/10 differences.
#
# Note: Requestors of the Block Descriptors now must pay attention
# to the longlba flag
# --------------------------------------------
# 03/06/24 jejb@raven.il.steeleye.com 1.1410
# Fix hch comments
# --------------------------------------------
# 03/06/24 jejb@raven.il.steeleye.com 1.1411
# Fix up export symbols
# --------------------------------------------
# 03/06/24 jejb@raven.il.steeleye.com 1.1412
# More fix ups
# --------------------------------------------
# 03/06/24 jejb@raven.il.steeleye.com 1.1413
# Minor fixes
# --------------------------------------------
# 03/06/24 jejb@raven.il.steeleye.com 1.1414
# More fixes
# --------------------------------------------
#
diff -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
--- a/drivers/scsi/scsi_lib.c Tue Jun 24 12:55:16 2003
+++ b/drivers/scsi/scsi_lib.c Tue Jun 24 12:55:16 2003
@@ -1336,3 +1336,127 @@
kmem_cache_destroy(sgp->slab);
}
}
+/**
+ * __scsi_mode_sense - issue a mode sense, falling back from 10 to
+ * six bytes if necessary.
+ * @sreq: SCSI request to fill in with the MODE_SENSE
+ * @dbd: set if mode sense will allow block descriptors to be returned
+ * @modepage: mode page being requested
+ * @buffer: request buffer (may not be smaller than eight bytes)
+ * @len: length of request buffer.
+ * @timeout: command timeout
+ * @retries: number of retries before failing
+ * @data: returns a structure abstracting the mode header data
+ *
+ * Returns zero if unsuccessful, or the header offset (either 4
+ * or 8 depending on whether a six or ten byte command was
+ * issued) if successful.
+ **/
+int
+__scsi_mode_sense(struct scsi_request *sreq, int dbd, int modepage,
+ unsigned char *buffer, int len, int timeout, int retries,
+ struct scsi_mode_data *data) {
+ unsigned char cmd[12];
+ int use_10_for_ms;
+ int header_length;
+
+ memset(data, 0, sizeof(*data));
+ memset(&cmd[0], 0, 12);
+ cmd[1] = dbd & 0x18; /* allows DBD and LLBA bits */
+ cmd[2] = modepage;
+
+ retry:
+ use_10_for_ms = sreq->sr_device->use_10_for_ms;
+
+ if (use_10_for_ms) {
+ if (len < 8)
+ len = 8;
+
+ cmd[0] = MODE_SENSE_10;
+ cmd[8] = len;
+ header_length = 8;
+ } else {
+ if (len < 4)
+ len = 4;
+
+ cmd[0] = MODE_SENSE;
+ cmd[4] = len;
+ header_length = 4;
+ }
+
+ sreq->sr_cmd_len = 0;
+ sreq->sr_sense_buffer[0] = 0;
+ sreq->sr_sense_buffer[2] = 0;
+ sreq->sr_data_direction = SCSI_DATA_READ;
+
+ memset(buffer, 0, len);
+
+ scsi_wait_req(sreq, cmd, buffer, len, timeout, retries);
+
+ /* This code looks awful: what it's doing is making sure an
+ * ILLEGAL REQUEST sense return identifies the actual command
+ * byte as the problem. MODE_SENSE commands can return
+ * ILLEGAL REQUEST if the code page isn't supported */
+ if (use_10_for_ms && ! scsi_status_is_good(sreq->sr_result) &&
+ (driver_byte(sreq->sr_result) & DRIVER_SENSE) &&
+ sreq->sr_sense_buffer[2] == ILLEGAL_REQUEST &&
+ (sreq->sr_sense_buffer[4] & 0x40) == 0x40 &&
+ sreq->sr_sense_buffer[5] == 0 &&
+ sreq->sr_sense_buffer[6] == 0 ) {
+ sreq->sr_device->use_10_for_ms = 0;
+ goto retry;
+ }
+
+ if(scsi_status_is_good(sreq->sr_result)) {
+ data->header_length = header_length;
+ if(use_10_for_ms) {
+ data->length = buffer[0]*256 + buffer[1];
+ data->medium_type = buffer[2];
+ data->device_specific = buffer[3];
+ data->longlba = buffer[4] & 0x01;
+ data->block_descriptor_length = buffer[6]*256
+ + buffer[7];
+ } else {
+ data->length = buffer[0];
+ data->medium_type = buffer[1];
+ data->device_specific = buffer[3];
+ data->block_descriptor_length = buffer[4];
+ }
+ }
+
+ return sreq->sr_result;
+}
+
+/**
+ * scsi_mode_sense - issue a mode sense, falling back from 10 to
+ * six bytes if necessary.
+ * @sdev: scsi device to send command to.
+ * @dbd: set if mode sense will disable block descriptors in the return
+ * @modepage: mode page being requested
+ * @buffer: request buffer (may not be smaller than eight bytes)
+ * @len: length of request buffer.
+ * @timeout: command timeout
+ * @retries: number of retries before failing
+ *
+ * Returns zero if unsuccessful, or the header offset (either 4
+ * or 8 depending on whether a six or ten byte command was
+ * issued) if successful.
+ **/
+int
+scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
+ unsigned char *buffer, int len, int timeout, int retries,
+ struct scsi_mode_data *data)
+{
+ struct scsi_request *sreq = scsi_allocate_request(sdev);
+ int ret;
+
+ if (!sreq)
+ return -1;
+
+ ret = __scsi_mode_sense(sreq, dbd, modepage, buffer, len,
+ timeout, retries, data);
+
+ scsi_release_request(sreq);
+
+ return ret;
+}
diff -Nru a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c
--- a/drivers/scsi/scsi_syms.c Tue Jun 24 12:55:16 2003
+++ b/drivers/scsi/scsi_syms.c Tue Jun 24 12:55:16 2003
@@ -86,6 +86,9 @@
EXPORT_SYMBOL(scsi_remove_device);
EXPORT_SYMBOL(scsi_set_device_offline);
+EXPORT_SYMBOL(__scsi_mode_sense);
+EXPORT_SYMBOL(scsi_mode_sense);
+
/*
* This symbol is for the highlevel drivers (e.g. sg) only.
*/
diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c
--- a/drivers/scsi/sd.c Tue Jun 24 12:55:16 2003
+++ b/drivers/scsi/sd.c Tue Jun 24 12:55:16 2003
@@ -1062,40 +1062,12 @@
}
/* called with buffer of length 512 */
-static int
+static inline int
sd_do_mode_sense(struct scsi_request *SRpnt, int dbd, int modepage,
- unsigned char *buffer, int len) {
- unsigned char cmd[12];
-
- memset((void *) &cmd[0], 0, 12);
- cmd[1] = dbd;
- cmd[2] = modepage;
-
- if (SRpnt->sr_device->use_10_for_ms) {
- if (len < 8)
- len = 8;
-
- cmd[0] = MODE_SENSE_10;
- cmd[8] = len;
- } else {
- if (len < 4)
- len = 4;
-
- cmd[0] = MODE_SENSE;
- cmd[4] = len;
- }
-
- SRpnt->sr_cmd_len = 0;
- SRpnt->sr_sense_buffer[0] = 0;
- SRpnt->sr_sense_buffer[2] = 0;
- SRpnt->sr_data_direction = SCSI_DATA_READ;
-
- memset((void *) buffer, 0, len);
-
- scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
- len, SD_TIMEOUT, SD_MAX_RETRIES);
-
- return SRpnt->sr_result;
+ unsigned char *buffer, int len, struct scsi_mode_data *data)
+{
+ return __scsi_mode_sense(SRpnt, dbd, modepage, buffer, len,
+ SD_TIMEOUT, SD_MAX_RETRIES, data);
}
/*
@@ -1106,33 +1078,34 @@
sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
struct scsi_request *SRpnt, unsigned char *buffer) {
int res;
+ struct scsi_mode_data data;
/*
* 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);
+ 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 (res)
- res = sd_do_mode_sense(SRpnt, 0, 0, buffer, 4);
+ 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 (res)
- res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 255);
+ if (!scsi_status_is_good(res))
+ res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 255, &data);
- if (res) {
+ if (!scsi_status_is_good(res)) {
printk(KERN_WARNING
"%s: test WP failed, assume Write Enabled\n", diskname);
} else {
- sdkp->write_prot = ((buffer[2] & 0x80) != 0);
+ sdkp->write_prot = ((data.device_specific & 0x80) != 0);
printk(KERN_NOTICE "%s: Write Protect is %s\n", diskname,
sdkp->write_prot ? "on" : "off");
printk(KERN_DEBUG "%s: Mode Sense: %02x %02x %02x %02x\n",
@@ -1149,43 +1122,45 @@
struct scsi_request *SRpnt, unsigned char *buffer) {
int len = 0, res;
- const int dbd = 0x08; /* DBD */
+ const int dbd = 0; /* DBD */
const int modepage = 0x08; /* current values, cache page */
+ struct scsi_mode_data data;
+
/* cautiously ask */
- res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, 4);
+ res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, 4, &data);
- if (res == 0) {
+ if (scsi_status_is_good(res)) {
/* that went OK, now ask for the proper length */
- len = buffer[0] + 1;
+ len = data.length;
if (len > 128)
len = 128;
- res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, len);
+ res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer,
+ len, &data);
}
- if (res == 0 && buffer[3] + 6 < len) {
+ if (scsi_status_is_good(res)) {
const char *types[] = {
"write through", "none", "write back",
"write back, no read (daft)"
};
int ct = 0;
- int offset = buffer[3] + 4; /* start of mode page */
+ int offset = data.header_length +
+ data.block_descriptor_length + 2;
- sdkp->WCE = ((buffer[offset + 2] & 0x04) != 0);
- sdkp->RCD = ((buffer[offset + 2] & 0x01) != 0);
+ sdkp->WCE = ((buffer[offset] & 0x04) != 0);
+ sdkp->RCD = ((buffer[offset] & 0x01) != 0);
ct = sdkp->RCD + 2*sdkp->WCE;
printk(KERN_NOTICE "SCSI device %s: drive cache: %s\n",
diskname, types[ct]);
} else {
- if (res == 0 ||
- (status_byte(res) == CHECK_CONDITION
- && (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70
+ 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
- && SRpnt->sr_sense_buffer[13] == 0x00)) {
+ && SRpnt->sr_sense_buffer[13] == 0x00) {
printk(KERN_NOTICE "%s: cache data unavailable\n",
diskname);
} else {
diff -Nru a/drivers/scsi/sr.c b/drivers/scsi/sr.c
--- a/drivers/scsi/sr.c Tue Jun 24 12:55:16 2003
+++ b/drivers/scsi/sr.c Tue Jun 24 12:55:16 2003
@@ -660,9 +660,9 @@
static void get_capabilities(struct scsi_cd *cd)
{
- struct cdrom_generic_command cgc;
unsigned char *buffer;
int rc, n;
+ struct scsi_mode_data data;
static char *loadmech[] =
{
@@ -681,18 +681,10 @@
printk(KERN_ERR "sr: out of memory.\n");
return;
}
- memset(&cgc, 0, sizeof(struct cdrom_generic_command));
- cgc.cmd[0] = MODE_SENSE;
- cgc.cmd[2] = 0x2a;
- cgc.cmd[4] = 128;
- cgc.buffer = buffer;
- cgc.buflen = 128;
- cgc.quiet = 1;
- cgc.data_direction = SCSI_DATA_READ;
- cgc.timeout = SR_TIMEOUT;
- rc = sr_do_ioctl(cd, &cgc);
+ rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128,
+ SR_TIMEOUT, 3, &data);
- if (rc) {
+ if (!scsi_status_is_good(rc)) {
/* failed, drive doesn't have capabilities mode page */
cd->cdi.speed = 1;
cd->cdi.mask |= (CDC_CD_R | CDC_CD_RW | CDC_DVD_R |
@@ -702,7 +694,7 @@
printk("%s: scsi-1 drive\n", cd->cdi.name);
return;
}
- n = buffer[3] + 4;
+ n = data.header_length + data.block_descriptor_length;
cd->cdi.speed = ((buffer[n + 8] << 8) + buffer[n + 9]) / 176;
cd->readcd_known = 1;
cd->readcd_cdda = buffer[n + 5] & 0x01;
diff -Nru a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
--- a/include/scsi/scsi_device.h Tue Jun 24 12:55:15 2003
+++ b/include/scsi/scsi_device.h Tue Jun 24 12:55:15 2003
@@ -7,6 +7,7 @@
struct request_queue;
struct scsi_cmnd;
+struct scsi_mode_data;
struct scsi_device {
@@ -102,5 +103,9 @@
extern int scsi_track_queue_full(struct scsi_device *, int);
extern int scsi_set_medium_removal(struct scsi_device *, char);
+
+extern int scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
+ unsigned char *buffer, int len, int timeout,
+ int retries, struct scsi_mode_data *data);
#endif /* _SCSI_SCSI_DEVICE_H */
diff -Nru a/include/scsi/scsi_request.h b/include/scsi/scsi_request.h
--- a/include/scsi/scsi_request.h Tue Jun 24 12:55:16 2003
+++ b/include/scsi/scsi_request.h Tue Jun 24 12:55:16 2003
@@ -55,4 +55,19 @@
void (*done) (struct scsi_cmnd *),
int timeout, int retries);
+struct scsi_mode_data {
+ __u16 length;
+ __u16 block_descriptor_length;
+ __u8 medium_type;
+ __u8 device_specific;
+ __u8 header_length;
+ __u8 longlba:1;
+};
+
+extern int __scsi_mode_sense(struct scsi_request *SRpnt, int dbd,
+ int modepage, unsigned char *buffer, int len,
+ int timeout, int retries,
+ struct scsi_mode_data *data);
+
+
#endif /* _SCSI_SCSI_REQUEST_H */
prev parent reply other threads:[~2003-06-24 17:45 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2003-06-24 4:31 [PATCH] definitive abstraction of the mode_sense commands James Bottomley
2003-06-24 8:10 ` Douglas Gilbert
2003-06-24 8:17 ` Matthew Dharm
2003-06-24 17:58 ` James Bottomley [this message]
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=1056477523.2085.170.camel@mulgrave \
--to=james.bottomley@steeleye.com \
--cc=dougg@torque.net \
--cc=linux-scsi@vger.kernel.org \
/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