patch-2.1.75 linux/drivers/scsi/scsi_debug.c
Next file: linux/drivers/scsi/scsi_debug.h
Previous file: linux/drivers/scsi/scsi.h
Back to the patch index
Back to the overall index
- Lines: 497
- Date:
Sun Dec 21 17:04:49 1997
- Orig file:
v2.1.74/linux/drivers/scsi/scsi_debug.c
- Orig date:
Mon May 6 02:26:11 1996
diff -u --recursive --new-file v2.1.74/linux/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c
@@ -43,9 +43,16 @@
/* A few options that we want selected */
+#define NR_HOSTS_PRESENT 1
+#define NR_FAKE_DISKS 3
+#define N_HEAD 32
+#define N_SECTOR 64
+#define DISK_READONLY(TGT) (1)
+#define DISK_REMOVEABLE(TGT) (1)
+
/* Do not attempt to use a timer to simulate a real disk with latency */
/* Only use this in the actual kernel, not in the simulator. */
-#define IMMEDIATE
+/* #define IMMEDIATE */
/* Skip some consistency checking. Good for benchmarking */
#define SPEEDY
@@ -58,12 +65,12 @@
#define MAJOR_NR 8
#endif
#define START_PARTITION 4
-#define SCSI_DEBUG_TIMER 20
+
/* Number of jiffies to wait before completing a command */
#define DISK_SPEED 10
#define CAPACITY (0x80000)
-static int starts[] = {4, 1000, 50000, CAPACITY, 0};
+static int starts[] = {N_HEAD, N_HEAD * N_SECTOR, 50000, CAPACITY, 0};
static int npart = 0;
#include "scsi_debug.h"
@@ -74,8 +81,8 @@
#endif
#ifdef SPEEDY
-#define VERIFY1_DEBUG(RW) 1
-#define VERIFY_DEBUG(RW) 1
+#define VERIFY1_DEBUG(RW)
+#define VERIFY_DEBUG(RW)
#else
#define VERIFY1_DEBUG(RW) \
@@ -111,12 +118,16 @@
};
#endif
-static volatile void (*do_done[SCSI_DEBUG_MAILBOXES])(Scsi_Cmnd *) = {NULL, };
-extern void scsi_debug_interrupt();
+typedef void (*done_fct_t)(Scsi_Cmnd *);
+
+static volatile done_fct_t do_done[SCSI_DEBUG_MAILBOXES] = {NULL, };
+
+static void scsi_debug_intr_handle(unsigned long);
-volatile Scsi_Cmnd * SCint[SCSI_DEBUG_MAILBOXES] = {NULL,};
+static struct timer_list timeout[SCSI_DEBUG_MAILBOXES];
+
+Scsi_Cmnd * SCint[SCSI_DEBUG_MAILBOXES] = {NULL,};
static char SCrst[SCSI_DEBUG_MAILBOXES] = {0,};
-static volatile unsigned int timeout[8] ={0,};
/*
* Semaphore used to simulate bus lockups.
@@ -137,11 +148,11 @@
sgpnt = (struct scatterlist *) SCpnt->buffer;
for(i=0; i<SCpnt->use_sg; i++) {
lpnt = (int *) sgpnt[i].alt_address;
- printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
+ printk(":%p %p %d\n",sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
if (lpnt) printk(" (Alt %x) ",lpnt[15]);
};
} else {
- printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
+ printk("nosg: %p %p %d\n",SCpnt->request.buffer, SCpnt->buffer,
SCpnt->bufflen);
lpnt = (int *) SCpnt->request.buffer;
if (lpnt) printk(" (Alt %x) ",lpnt[15]);
@@ -167,14 +178,14 @@
};
printk("\n");
#endif
- printk("DMA free %d sectors.\n", dma_free_sectors);
+ printk("DMA free %d sectors.\n", scsi_dma_free_sectors);
}
int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
{
unchar *cmd = (unchar *) SCpnt->cmnd;
struct partition * p;
- int block, start;
+ int block;
struct buffer_head * bh = NULL;
unsigned char * buff;
int nbytes, sgcount;
@@ -187,15 +198,28 @@
sgcount = 0;
sgpnt = NULL;
- DEB(if (target > 1) { SCpnt->result = DID_TIME_OUT << 16;done(SCpnt);return 0;});
+ /*
+ * If we are being notified of the mid-level reposessing a command due to timeout,
+ * just return.
+ */
+ if( done == NULL )
+ {
+ return 0;
+ }
+
+ DEB(if (target >= NR_FAKE_DISKS)
+ {
+ SCpnt->result = DID_TIME_OUT << 16;done(SCpnt);return 0;
+ });
buff = (unsigned char *) SCpnt->request_buffer;
- if(target>=1 || SCpnt->lun != 0) {
+ if(target>=NR_FAKE_DISKS || SCpnt->lun != 0)
+ {
SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
return 0;
- };
+ }
if( SCrst[target] != 0 && !scsi_debug_lockup )
{
@@ -208,11 +232,11 @@
}
switch(*cmd){
case REQUEST_SENSE:
- printk("Request sense...\n");
+ SCSI_LOG_LLQUEUE(3,printk("Request sense...\n"));
#ifndef DEBUG
{
int i;
- printk("scsi_debug: Requesting sense buffer (%x %x %x %d):", SCpnt, buff, done, bufflen);
+ printk("scsi_debug: Requesting sense buffer (%p %p %p %d):", SCpnt, buff, done, bufflen);
for(i=0;i<12;i++) printk("%d ",sense_buffer[i]);
printk("\n");
};
@@ -224,15 +248,21 @@
done(SCpnt);
return 0;
case ALLOW_MEDIUM_REMOVAL:
- if(cmd[4]) printk("Medium removal inhibited...");
- else printk("Medium removal enabled...");
+ if(cmd[4])
+ {
+ SCSI_LOG_LLQUEUE(2,printk("Medium removal inhibited..."));
+ }
+ else
+ {
+ SCSI_LOG_LLQUEUE(2,printk("Medium removal enabled..."));
+ }
scsi_debug_errsts = 0;
break;
case INQUIRY:
- printk("Inquiry...(%x %d)\n", buff, bufflen);
+ SCSI_LOG_LLQUEUE(3,printk("Inquiry...(%p %d)\n", buff, bufflen));
memset(buff, 0, bufflen);
buff[0] = TYPE_DISK;
- buff[1] = 0x80; /* Removable disk */
+ buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
buff[2] = 1;
buff[4] = 33 - 5;
memcpy(&buff[8],"Foo Inc",7);
@@ -241,13 +271,13 @@
scsi_debug_errsts = 0;
break;
case TEST_UNIT_READY:
- printk("Test unit ready(%x %d)\n", buff, bufflen);
+ SCSI_LOG_LLQUEUE(3,printk("Test unit ready(%p %d)\n", buff, bufflen));
if (buff)
memset(buff, 0, bufflen);
scsi_debug_errsts = 0;
break;
case READ_CAPACITY:
- printk("Read Capacity\n");
+ SCSI_LOG_LLQUEUE(3,printk("Read Capacity\n"));
if(NR_REAL < 0) NR_REAL = (MINOR(SCpnt->request.rq_dev) >> 4) & 0x0f;
memset(buff, 0, bufflen);
buff[0] = (CAPACITY >> 24);
@@ -308,6 +338,12 @@
p->start_sect = starts[npart];
p->nr_sects = starts[npart+1] - starts [npart];
p->sys_ind = 0x81; /* Linux partition */
+ p->head = (npart == 0 ? 1 : 0);
+ p->sector = 1;
+ p->cyl = starts[npart] / N_HEAD / N_SECTOR;
+ p->end_head = N_HEAD - 1;
+ p->end_sector = N_SECTOR;
+ p->end_cyl = starts[npart + 1] / N_HEAD / N_SECTOR;
p++;
npart++;
};
@@ -365,7 +401,7 @@
SCpnt->result = 0;
(done)(SCpnt);
- return;
+ return 0;
if (SCpnt->use_sg && !scsi_debug_errsts)
if(bh) scsi_dump(SCpnt, 0);
@@ -396,8 +432,15 @@
#endif
scsi_debug_errsts = 0;
break;
+ case MODE_SENSE:
+ /*
+ * Used to detect write protected status.
+ */
+ scsi_debug_errsts = 0;
+ memset(buff, 0, 6);
+ break;
default:
- printk("Unknown command %d\n",*cmd);
+ SCSI_LOG_LLQUEUE(3,printk("Unknown command %d\n",*cmd));
SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
return 0;
@@ -406,45 +449,45 @@
save_flags(flags);
cli();
for(i=0;i<SCSI_DEBUG_MAILBOXES; i++){
- if (SCint[i] == 0) break;
+ if( timeout[i].function == NULL ) break;
};
- if (i >= SCSI_DEBUG_MAILBOXES || SCint[i] != 0)
- panic("Unable to find empty SCSI_DEBUG command slot.\n");
-
- SCint[i] = SCpnt;
-
- if (done) {
- DEB(printk("scsi_debug_queuecommand: now waiting for interrupt "););
- if (do_done[i])
- printk("scsi_debug_queuecommand: Two concurrent queuecommand?\n");
- else
- do_done[i] = done;
+ /*
+ * If all of the slots are full, just return 1. The new error handling scheme
+ * allows this, and the mid-level should queue things.
+ */
+ if (i >= SCSI_DEBUG_MAILBOXES || timeout[i].function != 0)
+ {
+ SCSI_LOG_LLQUEUE(1,printk("Command rejected - host busy\n"));
+ restore_flags(flags);
+ return 1;
}
- else
- printk("scsi_debug_queuecommand: done can't be NULL\n");
+
+ SCSI_LOG_LLQUEUE(1,printk("Command accepted - slot %d\n", i));
#ifdef IMMEDIATE
if( !scsi_debug_lockup )
{
SCpnt->result = scsi_debug_errsts;
- scsi_debug_intr_handle(); /* No timer - do this one right away */
+ scsi_debug_intr_handle(i); /* No timer - do this one right away */
}
restore_flags(flags);
#else
- timeout[i] = jiffies+DISK_SPEED;
-
- /* If no timers active, then set this one */
- if ((timer_active & (1 << SCSI_DEBUG_TIMER)) == 0) {
- timer_table[SCSI_DEBUG_TIMER].expires = timeout[i];
- timer_active |= 1 << SCSI_DEBUG_TIMER;
- };
-
+
SCpnt->result = scsi_debug_errsts;
+ timeout[i].function = scsi_debug_intr_handle;
+ timeout[i].data = i;
+ timeout[i].expires = jiffies + DISK_SPEED;
+ SCint[i] = SCpnt;
+ do_done[i] = done;
+
restore_flags(flags);
+ add_timer(&timeout[i]);
+ if (!done)
+ panic("scsi_debug_queuecommand: done can't be NULL\n");
#if 0
- printk("Sending command (%d %x %d %d)...", i, done, timeout[i],jiffies);
+ printk("Sending command (%d %x %d %d)...", i, done, timeout[i].expires,jiffies);
#endif
#endif
@@ -472,92 +515,52 @@
/* A "high" level interrupt handler. This should be called once per jiffy
* to simulate a regular scsi disk. We use a timer to do this. */
-static void scsi_debug_intr_handle(void)
+static void scsi_debug_intr_handle(unsigned long indx)
{
Scsi_Cmnd * SCtmp;
- int i, pending;
+ int pending;
void (*my_done)(Scsi_Cmnd *);
unsigned long flags;
int to;
-#ifndef IMMEDIATE
- timer_table[SCSI_DEBUG_TIMER].expires = 0;
- timer_active &= ~(1 << SCSI_DEBUG_TIMER);
-#endif
-
- repeat:
- save_flags(flags);
- cli();
- for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
- if (SCint[i] == 0) continue;
-#ifndef IMMEDIATE
- if (timeout[i] == 0) continue;
- if (timeout[i] <= jiffies) break;
-#else
- break;
+#if 0
+ del_timer(&timeout[indx]);
#endif
- };
- if(i == SCSI_DEBUG_MAILBOXES){
-#ifndef IMMEDIATE
- pending = INT_MAX;
- for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
- if (SCint[i] == 0) continue;
- if (timeout[i] == 0) continue;
- if (timeout[i] <= jiffies) {restore_flags(flags); goto repeat;};
- if (timeout[i] > jiffies) {
- if (pending > timeout[i]) pending = timeout[i];
- continue;
- };
- };
- if (pending && pending != INT_MAX) {
- timer_table[SCSI_DEBUG_TIMER].expires =
- (pending <= jiffies ? jiffies+1 : pending);
- timer_active |= 1 << SCSI_DEBUG_TIMER;
- };
- restore_flags(flags);
-#endif
- return;
- };
+ SCtmp = (Scsi_Cmnd *) SCint[indx];
+ my_done = do_done[indx];
+ do_done[indx] = NULL;
+ timeout[indx].function = NULL;
+ SCint[indx] = NULL;
+
+ if (!my_done) {
+ printk("scsi_debug_intr_handle: Unexpected interrupt\n");
+ return;
+ }
- if(i < SCSI_DEBUG_MAILBOXES){
- timeout[i] = 0;
- my_done = do_done[i];
- do_done[i] = NULL;
- to = timeout[i];
- timeout[i] = 0;
- SCtmp = (Scsi_Cmnd *) SCint[i];
- SCint[i] = NULL;
- restore_flags(flags);
-
- if (!my_done) {
- printk("scsi_debug_intr_handle: Unexpected interrupt\n");
- return;
- }
-
#ifdef DEBUG
- printk("In intr_handle...");
- printk("...done %d %x %d %d\n",i , my_done, to, jiffies);
- printk("In intr_handle: %d %x %x\n",i, SCtmp, my_done);
+ printk("In intr_handle...");
+ printk("...done %d %x %d %d\n",i , my_done, to, jiffies);
+ printk("In intr_handle: %d %x %x\n",i, SCtmp, my_done);
#endif
-
- my_done(SCtmp);
+
+ my_done(SCtmp);
#ifdef DEBUG
- printk("Called done.\n");
+ printk("Called done.\n");
#endif
- };
- goto repeat;
}
int scsi_debug_detect(Scsi_Host_Template * tpnt)
{
- tpnt->proc_dir = &proc_scsi_scsi_debug;
-#ifndef IMMEDIATE
- timer_table[SCSI_DEBUG_TIMER].fn = scsi_debug_intr_handle;
- timer_table[SCSI_DEBUG_TIMER].expires = 0;
-#endif
- return 1;
+ int i;
+
+ for(i=0; i < NR_HOSTS_PRESENT; i++)
+ {
+ tpnt->proc_dir = &proc_scsi_scsi_debug;
+ scsi_register(tpnt,0);
+ }
+ return NR_HOSTS_PRESENT;
}
int scsi_debug_abort(Scsi_Cmnd * SCpnt)
@@ -587,20 +590,20 @@
int scsi_debug_biosparam(Disk * disk, kdev_t dev, int* info){
int size = disk->capacity;
- info[0] = 32;
- info[1] = 64;
+ info[0] = N_HEAD;
+ info[1] = N_SECTOR;
info[2] = (size + 2047) >> 11;
if (info[2] >= 1024) info[2] = 1024;
return 0;
}
-int scsi_debug_reset(Scsi_Cmnd * SCpnt)
+int scsi_debug_reset(Scsi_Cmnd * SCpnt, unsigned int why)
{
int i;
unsigned long flags;
void (*my_done)(Scsi_Cmnd *);
- printk("Bus unlocked by reset(%d)\n", SCpnt->host->suggest_bus_reset);
+ printk("Bus unlocked by reset - %d\n", why);
scsi_debug_lockup = 0;
DEB(printk("scsi_debug_reset called\n"));
for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
@@ -610,9 +613,9 @@
my_done(SCint[i]);
save_flags(flags);
cli();
- SCint[i] = NULL;
- do_done[i] = NULL;
- timeout[i] = 0;
+ SCint[i] = NULL;
+ do_done[i] = NULL;
+ timeout[i].function = NULL;
restore_flags(flags);
}
return SCSI_RESET_SUCCESS;
@@ -633,12 +636,21 @@
int len, pos, begin;
int orig_length;
+ orig_length = length;
+
if(inout == 1)
{
/* First check for the Signature */
if (length >= 10 && strncmp(buffer, "scsi_debug", 10) == 0) {
buffer += 11;
length -= 11;
+
+ if( buffer[length - 1] == '\n' )
+ {
+ buffer[length-1] = '\0';
+ length--;
+ }
+
/*
* OK, we are getting some kind of command. Figure out
* what we are supposed to do here. Simulate bus lockups
@@ -647,18 +659,18 @@
if( length == 6 && strncmp(buffer, "lockup", length) == 0 )
{
scsi_debug_lockup = 1;
- return length;
+ return orig_length;
}
if( length == 6 && strncmp(buffer, "unlock", length) == 0 )
{
scsi_debug_lockup = 0;
- return length;
+ return orig_length;
}
- printk("Unknown command:%s\n", buffer);
+ printk("Unknown command:%s (%d)\n", buffer, length);
} else
- printk("Wrong Signature:%10s\n", (char *) ((ulong)buffer-11));
+ printk("Wrong Signature:%10s\n", (char *) buffer);
return -EINVAL;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov