I am enclosing a patch for you folks to test out. The actual
patch contains a number of accumulated things that I have picked up from
linux-scsi - the main thing I am interested in is the > 7 lun stuff in
scsi-scan.c.
I have a couple of questions related to this. The first is that I
have essentially lifted the hardcoded limit of 8 in the lun scan - it now
follows the maximum lun specified for the host, which would normally be 8
except for fibre channel and any other variants that support more luns.
My question is what should happen in the instance of a changer listed in
the blacklist where we know there to be exactly 8 lun. Thus the question
is whether we should interpret BLIST_FORCELUN as limiting the number of
luns to 8 - much like BLIST_MAX5LUN.
The second question has to do with the correct setting for the 2nd
command byte. This is typically set to something like:
scsi_cmd[1] = (lun << 5) & 0xe0;
which is obviously broken in the event that the number of luns is > 8.
This patch starts to clean this up by forcing scsi_cmd[1] to 0 in such
instances. The actual change came from someone else - my question is what
is the appropriate setting for scsi_cmd[1]? A value of 0 seems
reasonable, I guess.
Finally, Doug Gilbert pointed out that the SCSI_IOCTL_GET_IDLUN
ioctl is broke for > 255 in target, lun, channel, etc, and there is no
checking for overflow. I believe I should go in and validate the ranges
of all of the things we are stuffing into various bytes, and if one of the
fields doesn't fit in a byte, that the ioctl fail. In the long run, this
ioctl needs to be replaced with something that uses larger fields for
these numbers...
-Eric
--
"The world was a library, and its books were the stones, leaves,
brooks, grass, and the birds of the earth. We learned to do what only
a student of nature ever learns, and that was to feel beauty."
Chief Luther Standing Bear - Teton Sioux
Index: linux/CREDITS
diff -u linux/CREDITS:1.1.1.23 linux/CREDITS:1.24
--- linux/CREDITS:1.1.1.23 Fri Feb 2 00:33:13 2001
+++ linux/CREDITS Fri Feb 2 00:44:31 2001
@@ -2955,8 +2955,8 @@
W: http://www.andante.org
D: General kernel hacker
D: SCSI iso9660 and ELF
-S: 17 Canterbury Square #101
-S: Alexandria, Virginia 22304
+S: 6389 Hawk View Lane
+S: Alexandria, Virginia 22312
S: USA
N: Niibe Yutaka
Index: linux/drivers/scsi/scsi_error.c
diff -u linux/drivers/scsi/scsi_error.c:1.1.1.12 linux/drivers/scsi/scsi_error.c:1.17
--- linux/drivers/scsi/scsi_error.c:1.1.1.12 Mon Jan 22 08:30:43 2001
+++ linux/drivers/scsi/scsi_error.c Mon Jan 22 20:09:09 2001
@@ -549,6 +549,9 @@
/*
* Hey, we are done. Let's look to see what happened.
*/
+ SCSI_LOG_ERROR_RECOVERY(3,
+ printk("scsi_test_unit_ready: SCpnt %p eh_state %x\n",
+ SCpnt, SCpnt->eh_state));
return SCpnt->eh_state;
}
@@ -671,11 +674,8 @@
spin_unlock_irqrestore(&io_request_lock, flags);
SCpnt->result = temp;
- if (scsi_eh_completed_normally(SCpnt)) {
- SCpnt->eh_state = SUCCESS;
- } else {
- SCpnt->eh_state = FAILED;
- }
+ /* Fall through to code below to examine status. */
+ SCpnt->eh_state = SUCCESS;
}
/*
@@ -683,7 +683,10 @@
* did complete normally.
*/
if (SCpnt->eh_state == SUCCESS) {
- switch (scsi_eh_completed_normally(SCpnt)) {
+ int ret = scsi_eh_completed_normally(SCpnt);
+ SCSI_LOG_ERROR_RECOVERY(3,
+ printk("scsi_send_eh_cmnd: scsi_eh_completed_normally %x\n",
+ret));
+ switch (ret) {
case SUCCESS:
SCpnt->eh_state = SUCCESS;
break;
@@ -1104,7 +1107,6 @@
*/
STATIC int scsi_eh_completed_normally(Scsi_Cmnd * SCpnt)
{
- int rtn;
/*
* First check the host byte, to see if there is anything in there
* that would indicate what we need to do.
@@ -1144,11 +1146,7 @@
case COMMAND_TERMINATED:
return SUCCESS;
case CHECK_CONDITION:
- rtn = scsi_check_sense(SCpnt);
- if (rtn == NEEDS_RETRY) {
- return FAILED;
- }
- return rtn;
+ return scsi_check_sense(SCpnt);
case CONDITION_GOOD:
case INTERMEDIATE_GOOD:
case INTERMEDIATE_C_GOOD:
@@ -1634,8 +1632,10 @@
* FIXME(eric) - is this really the
correct thing to do?
*/
if (rtn != SUCCESS) {
- SCloop->device->online =
FALSE;
- SCloop->host->host_failed--;
+ printk(KERN_INFO "scsi: device
+set offline - not ready or command retry failed after bus reset: host %d channel %d
+id %d lun %d\n", SDloop->host->host_no, SDloop->channel, SDloop->id, SDloop->lun);
+
+ SDloop->online = FALSE;
+ SDloop->host->host_failed--;
scsi_eh_finish_command(&SCdone, SCloop);
}
}
@@ -1725,8 +1725,9 @@
}
}
if (rtn != SUCCESS) {
- SCloop->device->online =
FALSE;
- SCloop->host->host_failed--;
+ printk(KERN_INFO "scsi: device
+set offline - not ready or command retry failed after host reset: host %d channel %d
+id %d lun %d\n", SDloop->host->host_no, SDloop->channel, SDloop->id, SDloop->lun);
+ SDloop->online = FALSE;
+ SDloop->host->host_failed--;
scsi_eh_finish_command(&SCdone, SCloop);
}
}
@@ -1753,7 +1754,11 @@
for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
for (SCloop = SDpnt->device_queue; SCloop; SCloop = SCloop->next) {
if (SCloop->state == SCSI_STATE_FAILED || SCloop->state ==
SCSI_STATE_TIMEOUT) {
- SCloop->device->online = FALSE;
+ SDloop = SCloop->device;
+ if (SDloop->online == TRUE) {
+ printk(KERN_INFO "scsi: device set offline -
+command error recover failed: host %d channel %d id %d lun %d\n",
+SDloop->host->host_no, SDloop->channel, SDloop->id, SDloop->lun);
+ SDloop->online = FALSE;
+ }
/*
* This should pass the failure up to the top level
driver, and
@@ -1765,7 +1770,7 @@
SCloop->result |= (DRIVER_TIMEOUT << 24);
}
SCSI_LOG_ERROR_RECOVERY(3, printk("Finishing command
for device %d %x\n",
- SCloop->device->id, SCloop->result));
+ SDloop->id, SCloop->result));
scsi_eh_finish_command(&SCdone, SCloop);
}
Index: linux/drivers/scsi/scsi_scan.c
diff -u linux/drivers/scsi/scsi_scan.c:1.1.1.10 linux/drivers/scsi/scsi_scan.c:1.25
--- linux/drivers/scsi/scsi_scan.c:1.1.1.10 Wed Sep 20 19:47:57 2000
+++ linux/drivers/scsi/scsi_scan.c Fri Feb 2 00:26:58 2001
@@ -40,9 +40,10 @@
#define BLIST_ISROM 0x200
static void print_inquiry(unsigned char *data);
-static int scan_scsis_single(int channel, int dev, int lun, int *max_scsi_dev,
- int *sparse_lun, Scsi_Device ** SDpnt,
- struct Scsi_Host *shpnt, char *scsi_result);
+static int scan_scsis_single(unsigned int channel, unsigned int dev,
+ unsigned int lun, unsigned int *max_scsi_dev,
+ unsigned int *sparse_lun, Scsi_Device ** SDpnt,
+ struct Scsi_Host *shpnt, char *scsi_result);
struct dev_info {
const char *vendor;
@@ -153,29 +154,31 @@
{NULL, NULL, NULL}
};
+#define MAX_SCSI_LUNS 0xFFFFFFFF
+
#ifdef CONFIG_SCSI_MULTI_LUN
-static int max_scsi_luns = 8;
+static unsigned int max_scsi_luns = MAX_SCSI_LUNS;
#else
-static int max_scsi_luns = 1;
+static unsigned int max_scsi_luns = 1;
#endif
#ifdef MODULE
MODULE_PARM(max_scsi_luns, "i");
-MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 8)");
+MODULE_PARM_DESC(max_scsi_luns, "last scsi LUN (should be between 1 and 2^32-1)");
#else
static int __init scsi_luns_setup(char *str)
{
- int tmp;
+ unsigned int tmp;
if (get_option(&str, &tmp) == 1) {
max_scsi_luns = tmp;
return 1;
} else {
printk("scsi_luns_setup : usage max_scsi_luns=n "
- "(n should be between 1 and 8)\n");
+ "(n should be between 1 and 2^32-1)\n");
return 0;
}
}
@@ -263,14 +266,14 @@
uint hlun)
{
uint channel;
- int dev;
- int lun;
- int max_dev_lun;
+ unsigned int dev;
+ unsigned int lun;
+ unsigned int max_dev_lun;
unsigned char *scsi_result;
unsigned char scsi_result0[256];
Scsi_Device *SDpnt;
Scsi_Device *SDtail;
- int sparse_lun;
+ unsigned int sparse_lun;
scsi_result = NULL;
@@ -460,8 +463,9 @@
* Returning 0 means Please don't ask further for lun!=0, 1 means OK go on.
* Global variables used : scsi_devices(linked list)
*/
-static int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
- int *sparse_lun, Scsi_Device ** SDpnt2,
+static int scan_scsis_single(unsigned int channel, unsigned int dev,
+ unsigned int lun, unsigned int *max_dev_lun,
+ unsigned int *sparse_lun, Scsi_Device ** SDpnt2,
struct Scsi_Host *shpnt, char *scsi_result)
{
char devname[64];
@@ -505,7 +509,9 @@
* Build an INQUIRY command block.
*/
scsi_cmd[0] = INQUIRY;
- scsi_cmd[1] = (lun << 5) & 0xe0;
+ if (shpnt->max_lun <= 8)
+ scsi_cmd[1] = (lun << 5) & 0xe0;
+ else scsi_cmd[1] = 0; /* any other idea? */
scsi_cmd[2] = 0;
scsi_cmd[3] = 0;
scsi_cmd[4] = 255;
@@ -661,7 +667,9 @@
printk("Unlocked floptical drive.\n");
SDpnt->lockable = 0;
scsi_cmd[0] = MODE_SENSE;
- scsi_cmd[1] = (lun << 5) & 0xe0;
+ if (shpnt->max_lun <= 8)
+ scsi_cmd[1] = (lun << 5) & 0xe0;
+ else scsi_cmd[1] = 0; /* any other idea? */
scsi_cmd[2] = 0x2e;
scsi_cmd[3] = 0;
scsi_cmd[4] = 0x2a;
@@ -744,7 +752,19 @@
* other settings, and scan all of them.
*/
if (bflags & BLIST_SPARSELUN) {
- *max_dev_lun = 8;
+ /*
+ * Scanning MAX_SCSI_LUNS units would be a bad idea.
+ * Any better idea?
+ * I think we need REPORT LUNS in future to avoid scanning
+ * of unused LUNs. But, that is another item.
+ *
+ * FIXME(eric) - perhaps this should be a kernel configurable?
+ */
+ if (*max_dev_lun < shpnt->max_lun)
+ *max_dev_lun = shpnt->max_lun;
+ else if ((max_scsi_luns >> 1) >= *max_dev_lun)
+ *max_dev_lun += shpnt->max_lun;
+ else *max_dev_lun = max_scsi_luns;
*sparse_lun = 1;
return 1;
}
@@ -753,7 +773,17 @@
* settings, and scan all of them.
*/
if (bflags & BLIST_FORCELUN) {
- *max_dev_lun = 8;
+ /*
+ * Scanning MAX_SCSI_LUNS units would be a bad idea.
+ * Any better idea?
+ * I think we need REPORT LUNS in future to avoid scanning
+ * of unused LUNs. But, that is another item.
+ */
+ if (*max_dev_lun < shpnt->max_lun)
+ *max_dev_lun = shpnt->max_lun;
+ else if ((max_scsi_luns >> 1) >= *max_dev_lun)
+ *max_dev_lun += shpnt->max_lun;
+ else *max_dev_lun = max_scsi_luns;
return 1;
}
/*
Index: linux/drivers/scsi/sd.c
diff -u linux/drivers/scsi/sd.c:1.1.1.23 linux/drivers/scsi/sd.c:1.30
--- linux/drivers/scsi/sd.c:1.1.1.23 Sat Nov 4 13:23:23 2000
+++ linux/drivers/scsi/sd.c Fri Feb 2 00:10:29 2001
@@ -798,9 +798,9 @@
SRpnt->sr_data_direction = SCSI_DATA_READ;
scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
0/*512*/, SD_TIMEOUT, MAX_RETRIES);
+ spintime_value = jiffies;
}
spintime = 1;
- spintime_value = jiffies;
time1 = HZ;
/* Wait 1 second for next try */
do {
Index: linux/include/linux/blkdev.h
diff -u linux/include/linux/blkdev.h:1.1.1.12 linux/include/linux/blkdev.h:1.3
--- linux/include/linux/blkdev.h:1.1.1.12 Mon Jan 22 09:31:17 2001
+++ linux/include/linux/blkdev.h Mon Jan 22 10:01:35 2001
@@ -146,7 +146,6 @@
*/
#define BLK_DEFAULT_QUEUE(_MAJOR) &blk_dev[_MAJOR].request_queue
-extern struct sec_size * blk_sec[MAX_BLKDEV];
extern struct blk_dev_struct blk_dev[MAX_BLKDEV];
extern void grok_partitions(struct gendisk *dev, int drive, unsigned minors, long
size);
extern void register_disk(struct gendisk *dev, kdev_t first, unsigned minors, struct
block_device_operations *ops, long size);
@@ -174,8 +173,6 @@
extern int * max_readahead[MAX_BLKDEV];
extern int * max_sectors[MAX_BLKDEV];
-
-extern int * max_segments[MAX_BLKDEV];
extern atomic_t queued_sectors;