Commit 92933518 authored by Patrick Mansfield's avatar Patrick Mansfield Committed by James Bottomley

[PATCH] SCSI: limit mode sense usage

Re-roll of the patch against 2.6.0-test6 to allow overriding or setting of
mode sense related flags, includes Alan Stern's as95 patch minus his
scsiglue.c changes.

Moves scsi_devinfo.h for use outside of drivers/scsi, and adds three new
devinfo flags:

	BLIST_MS_SKIP_PAGE_08
	BLIST_MS_SKIP_PAGE_3F
	BLIST_USE_10_BYTE_MS

Adds a per host template flags, and use of it in scsiglue.c. The per host
value can be overridden by a devinfo entry, the patch does not allow
scsi_default_dev_flags to override default host values.

USB mass storage and removable media (for testing mode page 3f use) were
not tested, if you have a USB storage device that still chokes on mode
sense 3f please give this a spin.

 drivers/scsi/scsi_devinfo.c    |   15 +++++++++++----
 drivers/scsi/scsi_devinfo.h    |   17 -----------------
 drivers/scsi/scsi_priv.h       |    3 ++-
 drivers/scsi/scsi_scan.c       |   17 +++++++++++++----
 drivers/scsi/sd.c              |    9 +++++++++
 drivers/usb/storage/scsiglue.c |    8 ++++----
 include/scsi/scsi_device.h     |    2 ++
 include/scsi/scsi_devinfo.h    |   22 ++++++++++++++++++++++
 include/scsi/scsi_host.h       |    6 ++++++
 9 files changed, 69 insertions(+), 30 deletions(-)
parent 4201d888
...@@ -6,10 +6,11 @@ ...@@ -6,10 +6,11 @@
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <scsi/scsi_devinfo.h>
#include "scsi.h" #include "scsi.h"
#include "hosts.h"
#include "scsi_priv.h" #include "scsi_priv.h"
#include "scsi_devinfo.h"
/* /*
* scsi_dev_info_list: structure to hold black/white listed devices. * scsi_dev_info_list: structure to hold black/white listed devices.
...@@ -322,11 +323,17 @@ static int scsi_dev_info_list_add_str(char *dev_list) ...@@ -322,11 +323,17 @@ static int scsi_dev_info_list_add_str(char *dev_list)
* Description: * Description:
* Search the scsi_dev_info_list for an entry matching @vendor and * Search the scsi_dev_info_list for an entry matching @vendor and
* @model, if found, return the matching flags value, else return * @model, if found, return the matching flags value, else return
* scsi_default_dev_flags. * the host or global default settings.
**/ **/
int scsi_get_device_flags(unsigned char *vendor, unsigned char *model) int scsi_get_device_flags(struct scsi_device *sdev, unsigned char *vendor,
unsigned char *model)
{ {
struct scsi_dev_info_list *devinfo; struct scsi_dev_info_list *devinfo;
unsigned int bflags;
bflags = sdev->host->hostt->flags;
if (!bflags)
bflags = scsi_default_dev_flags;
list_for_each_entry(devinfo, &scsi_dev_info_list, dev_info_list) { list_for_each_entry(devinfo, &scsi_dev_info_list, dev_info_list) {
if (devinfo->compatible) { if (devinfo->compatible) {
...@@ -378,7 +385,7 @@ int scsi_get_device_flags(unsigned char *vendor, unsigned char *model) ...@@ -378,7 +385,7 @@ int scsi_get_device_flags(unsigned char *vendor, unsigned char *model)
return devinfo->flags; return devinfo->flags;
} }
} }
return scsi_default_dev_flags; return bflags;
} }
#ifdef CONFIG_SCSI_PROC_FS #ifdef CONFIG_SCSI_PROC_FS
......
...@@ -85,7 +85,8 @@ extern void scsi_init_cmd_from_req(struct scsi_cmnd *cmd, ...@@ -85,7 +85,8 @@ extern void scsi_init_cmd_from_req(struct scsi_cmnd *cmd,
extern void __scsi_release_request(struct scsi_request *sreq); extern void __scsi_release_request(struct scsi_request *sreq);
/* scsi_devinfo.c */ /* scsi_devinfo.c */
extern int scsi_get_device_flags(unsigned char *vendor, unsigned char *model); extern int scsi_get_device_flags(struct scsi_device *sdev,
unsigned char *vendor, unsigned char *model);
extern int scsi_init_devinfo(void); extern int scsi_init_devinfo(void);
extern void scsi_exit_devinfo(void); extern void scsi_exit_devinfo(void);
......
...@@ -35,10 +35,10 @@ ...@@ -35,10 +35,10 @@
#include "scsi.h" #include "scsi.h"
#include "hosts.h" #include "hosts.h"
#include <scsi/scsi_driver.h> #include <scsi/scsi_driver.h>
#include <scsi/scsi_devinfo.h>
#include "scsi_priv.h" #include "scsi_priv.h"
#include "scsi_logging.h" #include "scsi_logging.h"
#include "scsi_devinfo.h"
#define ALLOC_FAILURE_MSG KERN_ERR "%s: Allocation failure during" \ #define ALLOC_FAILURE_MSG KERN_ERR "%s: Allocation failure during" \
" SCSI scanning, some SCSI devices might not be configured\n" " SCSI scanning, some SCSI devices might not be configured\n"
...@@ -365,7 +365,7 @@ static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result, ...@@ -365,7 +365,7 @@ static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result,
* bit fields in Scsi_Device, so bflags need not be passed as an * bit fields in Scsi_Device, so bflags need not be passed as an
* argument. * argument.
*/ */
*bflags |= scsi_get_device_flags(&inq_result[8], &inq_result[16]); *bflags |= scsi_get_device_flags(sdev, &inq_result[8], &inq_result[16]);
possible_inq_resp_len = (unsigned char) inq_result[4] + 5; possible_inq_resp_len = (unsigned char) inq_result[4] + 5;
if (BLIST_INQUIRY_36 & *bflags) if (BLIST_INQUIRY_36 & *bflags)
...@@ -625,7 +625,15 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags) ...@@ -625,7 +625,15 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
sdev->max_device_blocked = SCSI_DEFAULT_DEVICE_BLOCKED; sdev->max_device_blocked = SCSI_DEFAULT_DEVICE_BLOCKED;
sdev->use_10_for_rw = 1; sdev->use_10_for_rw = 1;
sdev->use_10_for_ms = 0;
if (*bflags & BLIST_MS_SKIP_PAGE_08)
sdev->skip_ms_page_8 = 1;
if (*bflags & BLIST_MS_SKIP_PAGE_3F)
sdev->skip_ms_page_3f = 1;
if (*bflags & BLIST_USE_10_BYTE_MS)
sdev->use_10_for_ms = 1;
if(sdev->host->hostt->slave_configure) if(sdev->host->hostt->slave_configure)
sdev->host->hostt->slave_configure(sdev); sdev->host->hostt->slave_configure(sdev);
...@@ -678,7 +686,8 @@ static int scsi_probe_and_add_lun(struct Scsi_Host *host, ...@@ -678,7 +686,8 @@ static int scsi_probe_and_add_lun(struct Scsi_Host *host,
if (sdevp) if (sdevp)
*sdevp = sdev; *sdevp = sdev;
if (bflagsp) if (bflagsp)
*bflagsp = scsi_get_device_flags(sdev->vendor, *bflagsp = scsi_get_device_flags(sdev,
sdev->vendor,
sdev->model); sdev->model);
return SCSI_SCAN_LUN_PRESENT; return SCSI_SCAN_LUN_PRESENT;
} }
......
...@@ -1057,6 +1057,11 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, ...@@ -1057,6 +1057,11 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
int res; int res;
struct scsi_mode_data data; struct scsi_mode_data data;
if (sdkp->device->skip_ms_page_3f) {
printk(KERN_NOTICE "%s: assuming Write Enabled\n", diskname);
return;
}
/* /*
* First attempt: ask for all pages (0x3F), but only 4 bytes. * First attempt: ask for all pages (0x3F), but only 4 bytes.
* We have to start carefully: some devices hang if we ask * We have to start carefully: some devices hang if we ask
...@@ -1103,6 +1108,8 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, ...@@ -1103,6 +1108,8 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
const int modepage = 0x08; /* current values, cache page */ const int modepage = 0x08; /* current values, cache page */
struct scsi_mode_data data; struct scsi_mode_data data;
if (sdkp->device->skip_ms_page_8)
goto defaults;
/* cautiously ask */ /* cautiously ask */
res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, 4, &data); res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, 4, &data);
...@@ -1160,6 +1167,8 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, ...@@ -1160,6 +1167,8 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
printk(KERN_ERR "%s: asking for cache data failed\n", printk(KERN_ERR "%s: asking for cache data failed\n",
diskname); diskname);
} }
defaults:
printk(KERN_ERR "%s: assuming drive cache: write through\n", printk(KERN_ERR "%s: assuming drive cache: write through\n",
diskname); diskname);
sdkp->WCE = 0; sdkp->WCE = 0;
......
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
#include <scsi/scsi_devinfo.h>
/*********************************************************************** /***********************************************************************
...@@ -64,10 +65,6 @@ static const char* host_info(struct Scsi_Host *host) ...@@ -64,10 +65,6 @@ static const char* host_info(struct Scsi_Host *host)
static int slave_configure (struct scsi_device *sdev) static int slave_configure (struct scsi_device *sdev)
{ {
/* set device to use 10-byte commands where possible */
sdev->use_10_for_ms = 1;
sdev->use_10_for_rw = 1;
/* this is to satisify the compiler, tho I don't think the /* this is to satisify the compiler, tho I don't think the
* return code is ever checked anywhere. */ * return code is ever checked anywhere. */
return 0; return 0;
...@@ -324,6 +321,9 @@ struct scsi_host_template usb_stor_host_template = { ...@@ -324,6 +321,9 @@ struct scsi_host_template usb_stor_host_template = {
/* emulated HBA */ /* emulated HBA */
.emulated = TRUE, .emulated = TRUE,
/* modify scsi_device bits on probe */
.flags = (BLIST_MS_SKIP_PAGE_08 | BLIST_USE_10_BYTE_MS),
/* module management */ /* module management */
.module = THIS_MODULE .module = THIS_MODULE
}; };
......
...@@ -86,6 +86,8 @@ struct scsi_device { ...@@ -86,6 +86,8 @@ struct scsi_device {
* because we did a bus reset. */ * because we did a bus reset. */
unsigned use_10_for_rw:1; /* first try 10-byte read / write */ unsigned use_10_for_rw:1; /* first try 10-byte read / write */
unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */ unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */
unsigned skip_ms_page_8:1; /* do not use MODE SENSE page 0x08 */
unsigned skip_ms_page_3f:1; /* do not use MODE SENSE page 0x3f */
unsigned no_start_on_add:1; /* do not issue start on add */ unsigned no_start_on_add:1; /* do not issue start on add */
unsigned int device_blocked; /* Device returned QUEUE_FULL. */ unsigned int device_blocked; /* Device returned QUEUE_FULL. */
......
#ifndef _SCSI_SCSI_DEVINFO_H
#define _SCSI_SCSI_DEVINFO_H
/* /*
* Flags for SCSI devices that need special treatment * Flags for SCSI devices that need special treatment
*/ */
...@@ -15,3 +16,7 @@ ...@@ -15,3 +16,7 @@
#define BLIST_INQUIRY_36 0x400 /* override additional length field */ #define BLIST_INQUIRY_36 0x400 /* override additional length field */
#define BLIST_INQUIRY_58 0x800 /* ... for broken inquiry responses */ #define BLIST_INQUIRY_58 0x800 /* ... for broken inquiry responses */
#define BLIST_NOSTARTONADD 0x1000 /* do not do automatic start on add */ #define BLIST_NOSTARTONADD 0x1000 /* do not do automatic start on add */
#define BLIST_MS_SKIP_PAGE_08 0x2000 /* do not send ms page 0x08 */
#define BLIST_MS_SKIP_PAGE_3F 0x4000 /* do not send ms page 0x3f */
#define BLIST_USE_10_BYTE_MS 0x8000 /* use 10 byte ms before 6 byte ms */
#endif
...@@ -344,6 +344,12 @@ struct scsi_host_template { ...@@ -344,6 +344,12 @@ struct scsi_host_template {
* module_init/module_exit. * module_init/module_exit.
*/ */
struct list_head legacy_hosts; struct list_head legacy_hosts;
/*
* Default flags settings, these modify the setting of scsi_device
* bits.
*/
unsigned int flags;
}; };
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment