patch-2.4.18 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: 1472
- Date:
Wed Dec 26 17:05:14 2001
- Orig file:
linux.orig/drivers/scsi/scsi_debug.c
- Orig date:
Mon Feb 18 20:18:40 2002
diff -Naur -X /home/marcelo/lib/dontdiff linux.orig/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c
@@ -3,8 +3,18 @@
*
* Copyright (C) 1992 Eric Youngdale
* Simulate a host adapter with 2 disks attached. Do a lot of checking
- * to make sure that we are not getting blocks mixed up, and panic if
+ * to make sure that we are not getting blocks mixed up, and PANIC if
* anything out of the ordinary is seen.
+ *
+ * This version is more generic, simulating a variable number of disk
+ * (or disk like devices) sharing a common amount of RAM (default 8 MB
+ * but can be set at driver/module load time).
+ *
+ * For documentation see http://www.torque.net/sg/sdebug.html
+ *
+ * D. Gilbert (dpg) work for MOD device test [20010421]
+ * dpg, work for devfs large number of disks [20010809]
+ * dpg, make more generic [20011123]
*/
#include <linux/config.h>
@@ -18,7 +28,9 @@
#include <linux/string.h>
#include <linux/genhd.h>
#include <linux/fs.h>
+#include <linux/init.h>
#include <linux/proc_fs.h>
+#include <linux/smp_lock.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -27,151 +39,162 @@
#include "scsi.h"
#include "hosts.h"
-#include "sd.h"
-
#include<linux/stat.h>
-/* A few options that we want selected */
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+static char scsi_debug_version_str[] = "Version: 0.57 (20011209)";
-#define NR_HOSTS_PRESENT 1
-#define NR_FAKE_DISKS 3
-#define N_HEAD 255
-#define N_SECTOR 63
-#define N_CYLINDER 524
+#ifndef SCSI_CMD_READ_16
+#define SCSI_CMD_READ_16 0x88
+#endif
+#ifndef SCSI_CMD_WRITE_16
+#define SCSI_CMD_WRITE_16 0x8a
+#endif
+
+/* A few options that we want selected */
+#define DEF_NR_FAKE_DEVS 1
+#define DEF_DEV_SIZE_MB 8
+#define DEF_FAKE_BLK0 0
+
+static int scsi_debug_num_devs = DEF_NR_FAKE_DEVS;
+
+#define NR_HOSTS_PRESENT (((scsi_debug_num_devs - 1) / 7) + 1)
+#define N_HEAD 8
+#define N_SECTOR 32
#define DISK_READONLY(TGT) (0)
-#define DISK_REMOVEABLE(TGT) (1)
-#define DEVICE_TYPE(TGT) (TGT == 2 ? TYPE_TAPE : TYPE_DISK);
+#define DISK_REMOVEABLE(TGT) (0)
+#define DEVICE_TYPE(TGT) (TYPE_DISK);
+
+#define SCSI_DEBUG_MAILBOXES (scsi_debug_num_devs + 1)
+
+static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
+#define STORE_SIZE (scsi_debug_dev_size_mb * 1024 * 1024)
+#define STORE_ELEM_ORDER 1
+#define STORE_ELEM_SIZE (PAGE_SIZE * (1 << STORE_ELEM_ORDER))
+#define STORE_ELEMENTS ((STORE_SIZE / STORE_ELEM_SIZE) + 1)
+
+/* default sector size is 512 bytes, 2**9 bytes */
+#define POW2_SECT_SIZE 9
+#define SECT_SIZE (1 << POW2_SECT_SIZE)
+
+#define N_CYLINDER (STORE_SIZE / (SECT_SIZE * N_SECTOR * N_HEAD))
+
+static int scsi_debug_fake_blk0 = DEF_FAKE_BLK0;
/* 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
-/* Skip some consistency checking. Good for benchmarking */
-#define SPEEDY
-/* Read return zeros. Undefine for benchmarking */
-#define CLEAR
-
-/* Number of real scsi disks that will be detected ahead of time */
-static int NR_REAL = -1;
-
-#define NR_BLK_DEV 12
-#ifndef MAJOR_NR
-#define MAJOR_NR 8
-#endif
#define START_PARTITION 4
/* Time to wait before completing a command */
#define DISK_SPEED (HZ/10) /* 100ms */
#define CAPACITY (N_HEAD * N_SECTOR * N_CYLINDER)
-#define SIZE(TGT) (TGT == 2 ? 2248 : 512)
+#define SECT_SIZE_PER(TGT) SECT_SIZE
+#define SECT_PER_ELEM (STORE_ELEM_SIZE / SECT_SIZE)
static int starts[] =
{N_SECTOR,
N_HEAD * N_SECTOR, /* Single cylinder */
N_HEAD * N_SECTOR * 4,
- CAPACITY, 0};
+ 0 /* CAPACITY */, 0};
static int npart = 0;
-#include "scsi_debug.h"
-#ifdef DEBUG
-#define DEB(x) x
-#else
-#define DEB(x)
-#endif
+typedef struct scsi_debug_store_elem {
+ unsigned char * p;
+} Sd_store_elem;
+
+static Sd_store_elem * store_arr = 0;
+
+typedef struct sdebug_dev_info {
+ Scsi_Device * sdp;
+ unsigned short host_no;
+ unsigned short id;
+ char reset;
+ char sb_index;
+} Sdebug_dev_info;
+static Sdebug_dev_info * devInfop;
+
+static int num_aborts = 0;
+static int num_dev_resets = 0;
+static int num_bus_resets = 0;
+static int num_host_resets = 0;
-#ifdef SPEEDY
-#define VERIFY1_DEBUG(RW)
-#define VERIFY_DEBUG(RW)
-#else
+static spinlock_t mailbox_lock = SPIN_LOCK_UNLOCKED;
+static rwlock_t sdebug_atomic_rw = RW_LOCK_UNLOCKED;
-#define VERIFY1_DEBUG(RW) \
- if (bufflen != 1024) {printk("%d", bufflen); panic("(1)Bad bufflen");}; \
- start = 0; \
- if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1]; \
- if (bh){ \
- if (bh->b_size != 1024) panic ("Wrong bh size"); \
- if ((bh->b_blocknr << 1) + start != block) \
- { printk("Wrong bh block# %d %d ",bh->b_blocknr, block); \
- panic ("Wrong bh block#"); \
- }; \
- if (bh->b_dev != SCpnt->request.rq_dev) \
- panic ("Bad bh target"); \
- };
-
-#define VERIFY_DEBUG(RW) \
- if (bufflen != 1024 && (!SCpnt->use_sg)) {printk("%x %d\n ",bufflen, SCpnt->use_sg); panic("Bad bufflen");}; \
- start = 0; \
- if ((MINOR(SCpnt->request.rq_dev) & 0xf) > npart) panic ("Bad partition"); \
- if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1]; \
- if (SCpnt->request.cmd != RW) panic ("Wrong operation"); \
- if (SCpnt->request.sector + start != block) panic("Wrong block."); \
- if (SCpnt->request.current_nr_sectors != 2 && (!SCpnt->use_sg)) panic ("Wrong # blocks"); \
- if (SCpnt->request.bh){ \
- if (SCpnt->request.bh->b_size != 1024) panic ("Wrong bh size"); \
- if ((SCpnt->request.bh->b_blocknr << 1) + start != block) \
- { printk("Wrong bh block# %d %d ",SCpnt->request.bh->b_blocknr, block); \
- panic ("Wrong bh block#"); \
- }; \
- if (SCpnt->request.bh->b_dev != SCpnt->request.rq_dev) \
- panic ("Bad bh target");\
- };
-#endif
+#include "scsi_debug.h"
typedef void (*done_fct_t) (Scsi_Cmnd *);
-static volatile done_fct_t do_done[SCSI_DEBUG_MAILBOXES] =
-{NULL,};
+static volatile done_fct_t * do_done = 0;
struct Scsi_Host * SHpnt = NULL;
+static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block,
+ int num, int * errstsp, Sdebug_dev_info * devip);
+static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block,
+ int num, int * errstsp, Sdebug_dev_info * devip);
static void scsi_debug_send_self_command(struct Scsi_Host * shpnt);
static void scsi_debug_intr_handle(unsigned long);
+static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp);
+static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key,
+ int asc, int asq, int inbandLen);
+static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip);
-static struct timer_list timeout[SCSI_DEBUG_MAILBOXES];
-
-Scsi_Cmnd *SCint[SCSI_DEBUG_MAILBOXES] =
-{NULL,};
-static char SCrst[SCSI_DEBUG_MAILBOXES] =
-{0,};
+static struct timer_list * timeout = 0;
+static Scsi_Cmnd ** SCint = 0;
/*
* Semaphore used to simulate bus lockups.
*/
static int scsi_debug_lockup = 0;
-static char sense_buffer[128] =
-{0,};
+#define NUM_SENSE_BUFFS 4
+#define SENSE_BUFF_LEN 32
+static char sense_buffers[NUM_SENSE_BUFFS][SENSE_BUFF_LEN];
+#ifdef SCSI_DUMP
static void scsi_dump(Scsi_Cmnd * SCpnt, int flag)
{
int i;
-#if 0
- unsigned char *pnt;
-#endif
unsigned int *lpnt;
struct scatterlist *sgpnt = NULL;
printk("use_sg: %d", SCpnt->use_sg);
if (SCpnt->use_sg) {
sgpnt = (struct scatterlist *) SCpnt->buffer;
for (i = 0; i < SCpnt->use_sg; i++) {
- printk(":%p %d\n", sgpnt[i].address, sgpnt[i].length);
- };
+ lpnt = (int *) sgpnt[i].alt_address;
+ 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: %p %p %d\n", SCpnt->request.buffer, SCpnt->buffer,
SCpnt->bufflen);
lpnt = (int *) SCpnt->request.buffer;
if (lpnt)
printk(" (Alt %x) ", lpnt[15]);
- };
+ }
lpnt = (unsigned int *) SCpnt;
for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) {
if ((i & 7) == 0)
printk("\n");
printk("%x ", *lpnt++);
- };
+ }
printk("\n");
if (flag == 0)
return;
+ lpnt = (unsigned int *) sgpnt[0].alt_address;
+ for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) {
+ if ((i & 7) == 0)
+ printk("\n");
+ printk("%x ", *lpnt++);
+ }
#if 0
printk("\n");
lpnt = (unsigned int *) sgpnt[0].address;
@@ -179,50 +202,85 @@
if ((i & 7) == 0)
printk("\n");
printk("%x ", *lpnt++);
- };
+ }
printk("\n");
#endif
printk("DMA free %d sectors.\n", scsi_dma_free_sectors);
}
+#endif
+
+static int made_block0 = 0;
+
+static void scsi_debug_mkblock0(unsigned char * buff, int bufflen,
+ Scsi_Cmnd * SCpnt)
+{
+ int i;
+ struct partition *p;
+
+ memset(buff, 0, bufflen);
+ *((unsigned short *) (buff + 510)) = 0xAA55;
+ p = (struct partition *) (buff + 0x1be);
+ i = 0;
+ while (starts[i + 1]) {
+ int start_cyl, end_cyl;
+
+ start_cyl = starts[i] / N_HEAD / N_SECTOR;
+ end_cyl = (starts[i + 1] - 1) / N_HEAD / N_SECTOR;
+ p->boot_ind = 0;
+
+ p->head = (i == 0 ? 1 : 0);
+ p->sector = 1 | ((start_cyl >> 8) << 6);
+ p->cyl = (start_cyl & 0xff);
+
+ p->end_head = N_HEAD - 1;
+ p->end_sector = N_SECTOR | ((end_cyl >> 8) << 6);
+ p->end_cyl = (end_cyl & 0xff);
+
+ p->start_sect = starts[i];
+ p->nr_sects = starts[i + 1] - starts[i];
+ p->sys_ind = 0x83; /* Linux ext2 partition */
+ p++;
+ i++;
+ }
+ if (!npart)
+ npart = i;
+ made_block0 = 1;
+ i = (bufflen > STORE_ELEM_SIZE) ? STORE_ELEM_SIZE : bufflen;
+ memcpy(store_arr[0].p, buff, i);
+}
int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
{
unchar *cmd = (unchar *) SCpnt->cmnd;
- struct partition *p;
int block;
- struct buffer_head *bh = NULL;
+ int upper_blk;
unsigned char *buff;
- int nbytes, sgcount;
int scsi_debug_errsts;
- struct scatterlist *sgpnt;
int target = SCpnt->target;
int bufflen = SCpnt->request_bufflen;
- unsigned long flags;
- int i;
- sgcount = 0;
- sgpnt = NULL;
+ unsigned long iflags;
+ int i, num, capac;
+ Sdebug_dev_info * devip = NULL;
+ char * sbuff;
#ifdef CONFIG_SMP
/*
* The io_request_lock *must* be held at this point.
*/
- if( io_request_lock.lock == 0 )
+ if(! spin_is_locked(&io_request_lock))
{
- printk("Warning - io_request_lock is not held in queuecommand\n");
+ printk("Warning - io_request_lock is not held in "
+ "queuecommand\n");
}
#endif
/*
- * If we are being notified of the mid-level reposessing a command due to timeout,
- * just return.
+ * 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;
@@ -230,249 +288,201 @@
* If a command comes for the ID of the host itself, just print
* a silly message and return.
*/
- if( target == 7 ) {
+ if(target == 7) {
printk("How do you do!\n");
SCpnt->result = 0;
done(SCpnt);
return 0;
}
- if (target >= NR_FAKE_DISKS || SCpnt->lun != 0) {
+ if ((target > 7) || (SCpnt->lun != 0)) {
SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
return 0;
}
- if (SCrst[target] != 0 && !scsi_debug_lockup) {
- SCrst[target] = 0;
- memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
- SCpnt->sense_buffer[0] = 0x70;
- SCpnt->sense_buffer[2] = UNIT_ATTENTION;
- SCpnt->result = (CHECK_CONDITION << 1);
- done(SCpnt);
+#if 0
+ printk(KERN_INFO "sdebug:qc: host_no=%d, id=%d, sdp=%p, cmd=0x%x\n",
+ (int)SCpnt->device->host->host_no, (int)SCpnt->device->id,
+ SCpnt->device, (int)(unsigned char)*cmd);
+#endif
+ if (NULL == SCpnt->device->hostdata) {
+ devip = devInfoReg(SCpnt->device);
+ if (NULL == devip) {
+ SCpnt->result = DID_NO_CONNECT << 16;
+ done(SCpnt);
+ return 0;
+ }
+ SCpnt->device->hostdata = devip;
}
+ devip = SCpnt->device->hostdata;
+
switch (*cmd) {
- case REQUEST_SENSE:
+ case REQUEST_SENSE: /* mandatory */
SCSI_LOG_LLQUEUE(3, printk("Request sense...\n"));
-#ifndef DEBUG
- {
- int i;
- 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");
- };
-#endif
- memset(buff, 0, bufflen);
- memcpy(buff, sense_buffer, bufflen);
- memset(sense_buffer, 0, sizeof(sense_buffer));
+ if (devip) {
+ sbuff = &sense_buffers[(int)devip->sb_index][0];
+ devip->sb_index = 0;
+ }
+ else
+ sbuff = &sense_buffers[0][0];
+ memcpy(buff, sbuff, (bufflen < SENSE_BUFF_LEN) ?
+ bufflen : SENSE_BUFF_LEN);
+ memset(sbuff, 0, SENSE_BUFF_LEN);
+ sbuff[0] = 0x70;
SCpnt->result = 0;
done(SCpnt);
return 0;
case START_STOP:
+ if (check_reset(SCpnt, devip)) {
+ done(SCpnt);
+ return 0;
+ }
SCSI_LOG_LLQUEUE(3, printk("START_STOP\n"));
scsi_debug_errsts = 0;
break;
case ALLOW_MEDIUM_REMOVAL:
+ if (check_reset(SCpnt, devip)) {
+ done(SCpnt);
+ return 0;
+ }
if (cmd[4]) {
- SCSI_LOG_LLQUEUE(2, printk("Medium removal inhibited..."));
+ SCSI_LOG_LLQUEUE(2, printk(
+ "Medium removal inhibited..."));
} else {
- SCSI_LOG_LLQUEUE(2, printk("Medium removal enabled..."));
+ SCSI_LOG_LLQUEUE(2,
+ printk("Medium removal enabled..."));
}
scsi_debug_errsts = 0;
break;
- case INQUIRY:
+ case INQUIRY: /* mandatory */
SCSI_LOG_LLQUEUE(3, printk("Inquiry...(%p %d)\n", buff, bufflen));
memset(buff, 0, bufflen);
buff[0] = DEVICE_TYPE(target);
- buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
- buff[2] = 1;
- buff[4] = 33 - 5;
- memcpy(&buff[8], "Foo Inc", 7);
- memcpy(&buff[16], "XYZZY", 5);
- memcpy(&buff[32], "1", 1);
+ buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0;
+ /* Removable disk */
+ buff[2] = 2; /* claim SCSI 2 */
+ buff[4] = 36 - 5;
+ memcpy(&buff[8], "Linux ", 8);
+ memcpy(&buff[16], "scsi_debug ", 16);
+ memcpy(&buff[32], "0002", 4);
+ scsi_debug_errsts = 0;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10)
+ if (SCpnt->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
+ SCpnt->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
+#endif
+ break;
+ case SEND_DIAGNOSTIC: /* mandatory */
+ SCSI_LOG_LLQUEUE(3, printk("Send Diagnostic\n"));
+ if (buff)
+ memset(buff, 0, bufflen);
scsi_debug_errsts = 0;
break;
- case TEST_UNIT_READY:
+ case TEST_UNIT_READY: /* mandatory */
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:
+ if (check_reset(SCpnt, devip)) {
+ done(SCpnt);
+ return 0;
+ }
SCSI_LOG_LLQUEUE(3, printk("Read Capacity\n"));
SHpnt = SCpnt->host;
- if (NR_REAL < 0)
- NR_REAL = (MINOR(SCpnt->request.rq_dev) >> 4) & 0x0f;
memset(buff, 0, bufflen);
- buff[0] = (CAPACITY >> 24);
- buff[1] = (CAPACITY >> 16) & 0xff;
- buff[2] = (CAPACITY >> 8) & 0xff;
- buff[3] = CAPACITY & 0xff;
+ capac = CAPACITY - 1;
+ buff[0] = (capac >> 24);
+ buff[1] = (capac >> 16) & 0xff;
+ buff[2] = (capac >> 8) & 0xff;
+ buff[3] = capac & 0xff;
buff[4] = 0;
buff[5] = 0;
- buff[6] = (SIZE(target) >> 8) & 0xff; /* 512 byte sectors */
- buff[7] = SIZE(target) & 0xff;
+ buff[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
+ buff[7] = SECT_SIZE_PER(target) & 0xff;
scsi_debug_errsts = 0;
break;
+ case SCSI_CMD_READ_16: /* SBC-2 */
+ case READ_12:
case READ_10:
case READ_6:
-#ifdef DEBUG
- printk("Read...");
-#endif
- if ((*cmd) == READ_10)
- block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
- else
- block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
- VERIFY_DEBUG(READ);
-#if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE)
- {
- int delay = SCSI_SETUP_LATENCY;
-
- delay += SCpnt->request.nr_sectors * SCSI_DATARATE;
- if (delay)
- usleep(delay);
- };
-#endif
-
-#ifdef DEBUG
- printk("(r%d)", SCpnt->request.nr_sectors);
-#endif
- nbytes = bufflen;
- if (SCpnt->use_sg) {
- sgcount = 0;
- sgpnt = (struct scatterlist *) buff;
- buff = sgpnt[sgcount].address;
- bufflen = sgpnt[sgcount].length;
- bh = SCpnt->request.bh;
- };
- scsi_debug_errsts = 0;
- do {
- VERIFY1_DEBUG(READ);
- /* For the speedy test, we do not even want to fill the buffer with anything */
-#ifdef CLEAR
- memset(buff, 0, bufflen);
-#endif
- /* If this is block 0, then we want to read the partition table for this
- * device. Let's make one up */
- if (block == 0) {
- int i;
- memset(buff, 0, bufflen);
- *((unsigned short *) (buff + 510)) = 0xAA55;
- p = (struct partition *) (buff + 0x1be);
- i = 0;
- while (starts[i + 1]) {
- int start_cyl, end_cyl;
-
- start_cyl = starts[i] / N_HEAD / N_SECTOR;
- end_cyl = (starts[i + 1] - 1) / N_HEAD / N_SECTOR;
- p->boot_ind = 0;
-
- p->head = (i == 0 ? 1 : 0);
- p->sector = 1 | ((start_cyl >> 8) << 6);
- p->cyl = (start_cyl & 0xff);
-
- p->end_head = N_HEAD - 1;
- p->end_sector = N_SECTOR | ((end_cyl >> 8) << 6);
- p->end_cyl = (end_cyl & 0xff);
-
- p->start_sect = starts[i];
- p->nr_sects = starts[i + 1] - starts[i];
- p->sys_ind = 0x81; /* Linux partition */
- p++;
- i++;
- };
- if (!npart)
- npart = i;
- scsi_debug_errsts = 0;
- break;
- };
-#ifdef DEBUG
- if (SCpnt->use_sg)
- printk("Block %x (%d %d)\n", block, SCpnt->request.nr_sectors,
- SCpnt->request.current_nr_sectors);
-#endif
-
-#if 0
- /* Simulate a disk change */
- if (block == 0xfff0) {
- sense_buffer[0] = 0x70;
- sense_buffer[2] = UNIT_ATTENTION;
- starts[0] += 10;
- starts[1] += 10;
- starts[2] += 10;
-
-#ifdef DEBUG
- {
- int i;
- printk("scsi_debug: Filling sense buffer:");
- for (i = 0; i < 12; i++)
- printk("%d ", sense_buffer[i]);
- printk("\n");
- };
-#endif
- scsi_debug_errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
- break;
- } /* End phony disk change code */
-#endif
-
-#ifdef CLEAR
- memcpy(buff, &target, sizeof(target));
- memcpy(buff + sizeof(target), cmd, 24);
- memcpy(buff + 60, &block, sizeof(block));
- memcpy(buff + 64, SCpnt, sizeof(Scsi_Cmnd));
-#endif
- nbytes -= bufflen;
- if (SCpnt->use_sg) {
-#ifdef CLEAR
- memcpy(buff + 128, bh, sizeof(struct buffer_head));
-#endif
- block += bufflen >> 9;
- bh = bh->b_reqnext;
- sgcount++;
- if (nbytes) {
- if (!bh)
- panic("Too few blocks for linked request.");
- buff = sgpnt[sgcount].address;
- bufflen = sgpnt[sgcount].length;
- };
- }
- } while (nbytes);
-
+ if (check_reset(SCpnt, devip)) {
+ done(SCpnt);
+ return 0;
+ }
+ upper_blk = 0;
+ if ((*cmd) == SCSI_CMD_READ_16) {
+ upper_blk = cmd[5] + (cmd[4] << 8) +
+ (cmd[3] << 16) + (cmd[2] << 24);
+ block = cmd[9] + (cmd[8] << 8) +
+ (cmd[7] << 16) + (cmd[6] << 24);
+ num = cmd[13] + (cmd[12] << 8) +
+ (cmd[11] << 16) + (cmd[10] << 24);
+ }
+ else if ((*cmd) == READ_12) {
+ block = cmd[5] + (cmd[4] << 8) +
+ (cmd[3] << 16) + (cmd[2] << 24);
+ num = cmd[9] + (cmd[8] << 8) +
+ (cmd[7] << 16) + (cmd[6] << 24);
+ }
+ else if ((*cmd) == READ_10) {
+ block = cmd[5] + (cmd[4] << 8) +
+ (cmd[3] << 16) + (cmd[2] << 24);
+ num = cmd[8] + (cmd[7] << 8);
+ }
+ else {
+ block = cmd[3] + (cmd[2] << 8) +
+ ((cmd[1] & 0x1f) << 16);
+ num = cmd[4];
+ }
+ if (scsi_debug_read(SCpnt, upper_blk, block, num,
+ &scsi_debug_errsts, devip))
+ break;
SCpnt->result = 0;
- (done) (SCpnt);
+/* calls bottom half in upper layers before return from scsi_do_...() */
+ (done) (SCpnt);
return 0;
-
- if (SCpnt->use_sg && !scsi_debug_errsts)
- if (bh)
- scsi_dump(SCpnt, 0);
- break;
+ case SCSI_CMD_WRITE_16: /* SBC-2 */
+ case WRITE_12:
case WRITE_10:
case WRITE_6:
-#ifdef DEBUG
- printk("Write\n");
-#endif
- if ((*cmd) == WRITE_10)
- block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
- else
- block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
- VERIFY_DEBUG(WRITE);
- /* printk("(w%d)",SCpnt->request.nr_sectors); */
- if (SCpnt->use_sg) {
- if ((bufflen >> 9) != SCpnt->request.nr_sectors)
- panic("Trying to write wrong number of blocks\n");
- sgpnt = (struct scatterlist *) buff;
- buff = sgpnt[sgcount].address;
- };
-#if 0
- if (block != *((unsigned long *) (buff + 60))) {
- printk("%x %x :", block, *((unsigned long *) (buff + 60)));
- scsi_dump(SCpnt, 1);
- panic("Bad block written.\n");
- };
-#endif
- scsi_debug_errsts = 0;
- break;
+ if (check_reset(SCpnt, devip)) {
+ done(SCpnt);
+ return 0;
+ }
+ upper_blk = 0;
+ if ((*cmd) == SCSI_CMD_WRITE_16) {
+ upper_blk = cmd[5] + (cmd[4] << 8) +
+ (cmd[3] << 16) + (cmd[2] << 24);
+ block = cmd[9] + (cmd[8] << 8) +
+ (cmd[7] << 16) + (cmd[6] << 24);
+ num = cmd[13] + (cmd[12] << 8) +
+ (cmd[11] << 16) + (cmd[10] << 24);
+ }
+ else if ((*cmd) == WRITE_12) {
+ block = cmd[5] + (cmd[4] << 8) +
+ (cmd[3] << 16) + (cmd[2] << 24);
+ num = cmd[9] + (cmd[8] << 8) +
+ (cmd[7] << 16) + (cmd[6] << 24);
+ }
+ else if ((*cmd) == WRITE_10) {
+ block = cmd[5] + (cmd[4] << 8) +
+ (cmd[3] << 16) + (cmd[2] << 24);
+ num = cmd[8] + (cmd[7] << 8);
+ }
+ else {
+ block = cmd[3] + (cmd[2] << 8) +
+ ((cmd[1] & 0x1f) << 16);
+ num = cmd[4];
+ }
+ if (scsi_debug_write(SCpnt, upper_blk, block, num,
+ &scsi_debug_errsts, devip))
+ break;
+ SCpnt->result = 0;
+/* calls bottom half in upper layers before return from scsi_do_...() */
+ (done) (SCpnt);
+ return 0;
case MODE_SENSE:
/*
* Used to detect write protected status.
@@ -481,26 +491,36 @@
memset(buff, 0, 6);
break;
default:
+#if 0
SCSI_LOG_LLQUEUE(3, printk("Unknown command %d\n", *cmd));
SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
return 0;
- };
+#else
+ if (check_reset(SCpnt, devip)) {
+ done(SCpnt);
+ return 0;
+ }
+ scsi_debug_errsts = (COMMAND_COMPLETE << 8) |
+ (CHECK_CONDITION << 1);
+ mk_sense_buffer(devip, 2, ILLEGAL_REQUEST, 0x20, 0, 14);
+ break;
+#endif
+ }
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&mailbox_lock, iflags);
for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) {
if (timeout[i].function == NULL)
break;
- };
+ }
/*
- * 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 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);
+ spin_unlock_irqrestore(&mailbox_lock, iflags);
return 1;
}
SCSI_LOG_LLQUEUE(1, printk("Command accepted - slot %d\n", i));
@@ -512,7 +532,7 @@
do_done[i] = done;
scsi_debug_intr_handle(i); /* No timer - do this one right away */
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&mailbox_lock, iflags);
#else
SCpnt->result = scsi_debug_errsts;
@@ -522,19 +542,190 @@
SCint[i] = SCpnt;
do_done[i] = done;
- restore_flags(flags);
+ spin_unlock_irqrestore(&mailbox_lock, iflags);
add_timer(&timeout[i]);
if (!done)
- panic("scsi_debug_queuecommand: done can't be NULL\n");
+ printk("scsi_debug_queuecommand: done can't be NULL\n");
#if 0
- printk("Sending command (%d %x %d %d)...", i, done, timeout[i].expires, jiffies);
+ printk("Sending command (%d %x %d %d)...", i, done,
+ timeout[i].expires, jiffies);
#endif
#endif
return 0;
}
+static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip)
+{
+ if (devip->reset) {
+ devip->reset = 0;
+ mk_sense_buffer(devip, 3, UNIT_ATTENTION, 0x29, 0, 14);
+ SCpnt->result = (COMMAND_COMPLETE << 8) |
+ (CHECK_CONDITION << 1);
+ return 1;
+ }
+ return 0;
+}
+
+static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block,
+ int num, int * errstsp, Sdebug_dev_info * devip)
+{
+ unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
+ int nbytes, sgcount;
+ struct scatterlist *sgpnt = NULL;
+ int bufflen = SCpnt->request_bufflen;
+ unsigned long iflags;
+
+ if (upper_blk || (block + num > CAPACITY)) {
+ *errstsp = (COMMAND_COMPLETE << 8) |
+ (CHECK_CONDITION << 1);
+ mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x21, 0, 14);
+ return 1;
+ }
+#if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE)
+ {
+ int delay = SCSI_SETUP_LATENCY;
+
+ delay += SCpnt->request.nr_sectors * SCSI_DATARATE;
+ if (delay)
+ usleep(delay);
+ }
+#endif
+
+ read_lock_irqsave(&sdebug_atomic_rw, iflags);
+ sgcount = 0;
+ nbytes = bufflen;
+ /* printk("scsi_debug_read: block=%d, tot_bufflen=%d\n",
+ block, bufflen); */
+ if (SCpnt->use_sg) {
+ sgcount = 0;
+ sgpnt = (struct scatterlist *) buff;
+ buff = sgpnt[sgcount].address;
+ bufflen = sgpnt[sgcount].length;
+ }
+ *errstsp = 0;
+ do {
+ int resid, k, off, len, rem, blk;
+ unsigned char * bp;
+
+ /* If this is block 0, then we want to read the partition
+ * table for this device. Let's make one up */
+ if (scsi_debug_fake_blk0 && (block == 0) && (! made_block0)) {
+ scsi_debug_mkblock0(buff, bufflen, SCpnt);
+ *errstsp = 0;
+ break;
+ }
+ bp = buff;
+ blk = block;
+ for (resid = bufflen; resid > 0; resid -= len) {
+ k = blk / SECT_PER_ELEM;
+ off = (blk % SECT_PER_ELEM) * SECT_SIZE;
+ rem = STORE_ELEM_SIZE - off;
+ len = (resid > rem) ? rem : resid;
+/* printk("sdr: blk=%d k=%d off=%d rem=%d resid"
+ "=%d len=%d sgcount=%d\n", blk, k,
+ off, rem, resid, len, sgcount); */
+ memcpy(bp, store_arr[k].p + off, len);
+ bp += len;
+ blk += len / SECT_SIZE;
+ }
+#if 0
+ /* Simulate a disk change */
+ if (block == 0xfff0) {
+ sense_buffer[0] = 0x70;
+ sense_buffer[2] = UNIT_ATTENTION;
+ starts[0] += 10;
+ starts[1] += 10;
+ starts[2] += 10;
+
+ *errstsp = (COMMAND_COMPLETE << 8) |
+ (CHECK_CONDITION << 1);
+ read_unlock_irqrestore(&sdebug_atomic_rw, iflags);
+ return 1;
+ } /* End phony disk change code */
+#endif
+ nbytes -= bufflen;
+ if (SCpnt->use_sg) {
+ block += bufflen >> POW2_SECT_SIZE;
+ sgcount++;
+ if (nbytes) {
+ buff = sgpnt[sgcount].address;
+ bufflen = sgpnt[sgcount].length;
+ }
+ }
+ else if (nbytes > 0)
+ printk("sdebug_read: unexpected nbytes=%d\n", nbytes);
+ } while (nbytes);
+ read_unlock_irqrestore(&sdebug_atomic_rw, iflags);
+ return 0;
+}
+
+static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block,
+ int num, int * errstsp, Sdebug_dev_info * devip)
+{
+ unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
+ int nbytes, sgcount;
+ struct scatterlist *sgpnt = NULL;
+ int bufflen = SCpnt->request_bufflen;
+ unsigned long iflags;
+
+ if (upper_blk || (block + num > CAPACITY)) {
+ *errstsp = (COMMAND_COMPLETE << 8) |
+ (CHECK_CONDITION << 1);
+ mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x21, 0, 14);
+ return 1;
+ }
+
+ write_lock_irqsave(&sdebug_atomic_rw, iflags);
+ sgcount = 0;
+#ifdef SCSI_DUMP
+ if (block != *((unsigned long *) (buff + 60))) {
+ printk("%x %x :", block, *((unsigned long *) (buff + 60)));
+ scsi_dump(SCpnt, 1);
+ printk("Bad block written.\n");
+ }
+#endif
+ nbytes = bufflen;
+ if (SCpnt->use_sg) {
+ sgcount = 0;
+ sgpnt = (struct scatterlist *) buff;
+ buff = sgpnt[sgcount].address;
+ bufflen = sgpnt[sgcount].length;
+ }
+ *errstsp = 0;
+ do {
+ int resid, k, off, len, rem, blk;
+ unsigned char * bp;
+
+ bp = buff;
+ blk = block;
+ for (resid = bufflen; resid > 0; resid -= len) {
+ k = blk / SECT_PER_ELEM;
+ off = (blk % SECT_PER_ELEM) * SECT_SIZE;
+ rem = STORE_ELEM_SIZE - off;
+ len = (resid > rem) ? rem : resid;
+ memcpy(store_arr[k].p + off, bp, len);
+ bp += len;
+ blk += len / SECT_SIZE;
+ }
+
+ nbytes -= bufflen;
+ if (SCpnt->use_sg) {
+ block += bufflen >> POW2_SECT_SIZE;
+ sgcount++;
+ if (nbytes) {
+ buff = sgpnt[sgcount].address;
+ bufflen = sgpnt[sgcount].length;
+ }
+ }
+ else if (nbytes > 0)
+ printk("sdebug_write: unexpected nbytes=%d\n", nbytes);
+ } while (nbytes);
+ write_unlock_irqrestore(&sdebug_atomic_rw, iflags);
+ return 0;
+}
+
static void scsi_debug_send_self_command(struct Scsi_Host * shpnt)
{
static unsigned char cmd[6] =
@@ -582,10 +773,6 @@
{
Scsi_Cmnd *SCtmp;
void (*my_done) (Scsi_Cmnd *);
-#ifdef DEBUG
- int to;
-#endif
-
#if 0
del_timer(&timeout[indx]);
#endif
@@ -600,59 +787,213 @@
printk("scsi_debug_intr_handle: Unexpected interrupt\n");
return;
}
-#ifdef DEBUG
+#if 0
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);
-#ifdef DEBUG
+#if 0
printk("Called done.\n");
#endif
}
+static int initialized = 0;
+
+static int do_init(void)
+{
+ int sz;
+
+ starts[3] = CAPACITY;
+ sz = sizeof(Sd_store_elem) * STORE_ELEMENTS;
+ store_arr = kmalloc(sz, GFP_ATOMIC);
+ if (NULL == store_arr)
+ return 1;
+ memset(store_arr, 0, sz);
+ sz = sizeof(done_fct_t) * SCSI_DEBUG_MAILBOXES;
+ do_done = kmalloc(sz, GFP_ATOMIC);
+ if (NULL == do_done) {
+ kfree(store_arr);
+ return 1;
+ }
+ memset((void *)do_done, 0, sz);
+ sz = sizeof(struct timer_list) * SCSI_DEBUG_MAILBOXES;
+ timeout = kmalloc(sz, GFP_ATOMIC);
+ if (NULL == timeout) {
+ kfree((void *)do_done);
+ kfree(store_arr);
+ return 1;
+ }
+ memset(timeout, 0, sz);
+ sz = sizeof(Scsi_Cmnd *) * SCSI_DEBUG_MAILBOXES;
+ SCint = kmalloc(sz, GFP_ATOMIC);
+ if (NULL == SCint) {
+ kfree(timeout);
+ kfree((void *)do_done);
+ kfree(store_arr);
+ return 1;
+ }
+ memset(SCint, 0, sz);
+ return 0;
+}
+
+static void do_end(void)
+{
+ kfree(SCint);
+ kfree(timeout);
+ kfree((void *)do_done);
+ kfree(store_arr);
+}
+
int scsi_debug_detect(Scsi_Host_Template * tpnt)
{
- int i;
+ int k, num, sz;
+
+ if (0 == initialized) {
+ ++initialized;
+ sz = sizeof(Sdebug_dev_info) * scsi_debug_num_devs;
+ devInfop = kmalloc(sz, GFP_ATOMIC);
+ if (NULL == devInfop) {
+ printk("scsi_debug_detect: out of memory, 0.5\n");
+ return 0;
+ }
+ memset(devInfop, 0, sz);
+ if (do_init()) {
+ printk("scsi_debug_detect: out of memory, 0\n");
+ return 0;
+ }
+ for (k = 0; k < STORE_ELEMENTS; ++k) {
+ store_arr[k].p = (unsigned char *)
+ __get_free_pages(GFP_ATOMIC, STORE_ELEM_ORDER);
+ if (0 == store_arr[k].p)
+ goto detect_err;
+ memset(store_arr[k].p, 0, STORE_ELEM_SIZE);
+ }
+ for (k = 0; k < NUM_SENSE_BUFFS; ++k)
+ sense_buffers[k][0] = 0x70;
+ for (k = 0; k < NR_HOSTS_PRESENT; k++) {
+ tpnt->proc_name = "scsi_debug"; /* In the loop??? */
+ scsi_register(tpnt, 0);
+ }
+ return NR_HOSTS_PRESENT;
+ }
+ else {
+ printk("scsi_debug_detect: called again\n");
+ return 0;
+ }
- for (i = 0; i < NR_HOSTS_PRESENT; i++) {
- tpnt->proc_name = "scsi_debug"; /* Huh? In the loop??? */
- scsi_register(tpnt, 0);
+detect_err:
+ num = k;
+ for (k = 0; k < STORE_ELEMENTS; ++k) {
+ if (0 != store_arr[k].p) {
+ free_pages((unsigned long)store_arr[k].p,
+ STORE_ELEM_ORDER);
+ store_arr[k].p = NULL;
+ }
}
- return NR_HOSTS_PRESENT;
+ printk("scsi_debug_detect: out of memory: %d out of %d bytes\n",
+ (int)(num * STORE_ELEM_SIZE),
+ (int)(scsi_debug_dev_size_mb * 1024 * 1024));
+ return 0;
+}
+
+
+static int num_releases = 0;
+
+int scsi_debug_release(struct Scsi_Host * hpnt)
+{
+ int k;
+
+ scsi_unregister(hpnt);
+ if (++num_releases != NR_HOSTS_PRESENT)
+ return 0;
+
+ for (k = 0; k < STORE_ELEMENTS; ++k) {
+ if (0 != store_arr[k].p) {
+ free_pages((unsigned long)store_arr[k].p,
+ STORE_ELEM_ORDER);
+ store_arr[k].p = NULL;
+ }
+ }
+ do_end();
+ kfree(devInfop);
+ return 0;
+}
+
+static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp)
+{
+ int k;
+ unsigned short host_no, id;
+ Sdebug_dev_info * devip;
+
+ host_no = sdp->host->host_no;
+ id = (unsigned short)sdp->id;
+ for (k = 0; k < scsi_debug_num_devs; ++k) {
+ devip = &devInfop[k];
+ if (devip->sdp && (host_no == devip->host_no) &&
+ (id == devip->id)) {
+ devip->sdp = sdp; /* overwrite previous sdp */
+ return devip;
+ }
+ if (NULL == devip->sdp) {
+ devip->sdp = sdp;
+ devip->host_no = host_no;
+ devip->id = id;
+ devip->reset = 1;
+ devip->sb_index = 0;
+ return devip;
+ }
+ }
+ return NULL;
+}
+
+static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key,
+ int asc, int asq, int inbandLen)
+{
+ char * sbuff;
+ if ((index < 0) || (index >= NUM_SENSE_BUFFS))
+ return;
+ if (devip)
+ devip->sb_index = index;
+ sbuff = &sense_buffers[index][0];
+ memset(sbuff, 0, SENSE_BUFF_LEN);
+ sbuff[0] = 0x70;
+ sbuff[2] = key;
+ sbuff[7] = (inbandLen > 7) ? (inbandLen - 8) : 0;
+ sbuff[12] = asc;
+ sbuff[13] = asq;
}
int scsi_debug_abort(Scsi_Cmnd * SCpnt)
{
-#if 0
+#if 1
+ ++num_aborts;
+ return SUCCESS;
+#else
int j;
void (*my_done) (Scsi_Cmnd *);
- unsigned long flags;
-#endif
-
- DEB(printk("scsi_debug_abort\n"));
-#if 0
+ unsigned long iflags;
SCpnt->result = SCpnt->abort_reason << 16;
for (j = 0; j < SCSI_DEBUG_MAILBOXES; j++) {
if (SCpnt == SCint[j]) {
my_done = do_done[j];
my_done(SCpnt);
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&mailbox_lock, iflags);
timeout[j] = 0;
SCint[j] = NULL;
do_done[j] = NULL;
- restore_flags(flags);
- };
- };
-#endif
+ spin_unlock_irqrestore(&mailbox_lock, iflags);
+ }
+ }
return SCSI_ABORT_SNOOZE;
+#endif
}
int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info)
{
+ /* int size = disk->capacity; */
info[0] = N_HEAD;
info[1] = N_SECTOR;
info[2] = N_CYLINDER;
@@ -661,35 +1002,130 @@
return 0;
}
+#if 0
int scsi_debug_reset(Scsi_Cmnd * SCpnt, unsigned int why)
{
int i;
- unsigned long flags;
+ unsigned long iflags;
void (*my_done) (Scsi_Cmnd *);
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++) {
if (SCint[i] == NULL)
continue;
SCint[i]->result = DID_RESET << 16;
my_done = do_done[i];
my_done(SCint[i]);
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&mailbox_lock, iflags);
SCint[i] = NULL;
do_done[i] = NULL;
timeout[i].function = NULL;
- restore_flags(flags);
+ spin_unlock_irqrestore(&mailbox_lock, iflags);
}
return SCSI_RESET_SUCCESS;
}
+#endif
+
+int scsi_debug_device_reset(Scsi_Cmnd * SCpnt)
+{
+ Scsi_Device * sdp;
+ int k;
+
+ ++num_dev_resets;
+ if (SCpnt && ((sdp = SCpnt->device))) {
+ for (k = 0; k < scsi_debug_num_devs; ++k) {
+ if (sdp->hostdata == (devInfop + k))
+ break;
+ }
+ if (k < scsi_debug_num_devs)
+ devInfop[k].reset = 1;
+ }
+ return SUCCESS;
+}
-const char *scsi_debug_info(void)
+int scsi_debug_bus_reset(Scsi_Cmnd * SCpnt)
{
- static char buffer[] = " "; /* looks nicer without anything here */
- return buffer;
+ Scsi_Device * sdp;
+ struct Scsi_Host * hp;
+ int k;
+
+ ++num_bus_resets;
+ if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
+ for (k = 0; k < scsi_debug_num_devs; ++k) {
+ if (hp == devInfop[k].sdp->host)
+ devInfop[k].reset = 1;
+ }
+ }
+ return SUCCESS;
+}
+
+int scsi_debug_host_reset(Scsi_Cmnd * SCpnt)
+{
+ int k;
+
+ ++num_host_resets;
+ for (k = 0; k < scsi_debug_num_devs; ++k)
+ devInfop[k].reset = 1;
+
+ return SUCCESS;
+}
+
+#ifndef MODULE
+static int __init scsi_debug_num_devs_setup(char *str)
+{
+ int tmp;
+
+ if (get_option(&str, &tmp) == 1) {
+ if (tmp > 0)
+ scsi_debug_num_devs = tmp;
+ return 1;
+ } else {
+ printk("scsi_debug_num_devs: usage scsi_debug_num_devs=<n> "
+ "(<n> can be from 1 to around 2000)\n");
+ return 0;
+ }
+}
+
+__setup("scsi_debug_num_devs=", scsi_debug_num_devs_setup);
+
+static int __init scsi_debug_dev_size_mb_setup(char *str)
+{
+ int tmp;
+
+ if (get_option(&str, &tmp) == 1) {
+ if (tmp > 0)
+ scsi_debug_dev_size_mb = tmp;
+ return 1;
+ } else {
+ printk("scsi_debug_dev_size_mb: usage scsi_debug_dev_size_mb=<n>\n"
+ " (<n> is number of MB ram shared by all devs\n");
+ return 0;
+ }
+}
+
+__setup("scsi_debug_dev_size_mb=", scsi_debug_dev_size_mb_setup);
+#endif
+
+MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
+MODULE_DESCRIPTION("SCSI debug adapter driver");
+MODULE_PARM(scsi_debug_num_devs, "i");
+MODULE_PARM_DESC(scsi_debug_num_devs, "number of SCSI devices to simulate");
+MODULE_PARM(scsi_debug_dev_size_mb, "i");
+MODULE_PARM_DESC(scsi_debug_dev_size_mb, "size in MB of ram shared by devs");
+
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+static char sdebug_info[256];
+
+const char * scsi_debug_info(struct Scsi_Host * shp)
+{
+ sprintf(sdebug_info, "scsi_debug, %s, num_devs=%d, "
+ "dev_size_mb=%d\n", scsi_debug_version_str,
+ scsi_debug_num_devs, scsi_debug_dev_size_mb);
+ return sdebug_info;
}
/* scsi_debug_proc_info
@@ -739,10 +1175,20 @@
}
begin = 0;
- pos = len = sprintf(buffer,
- "This driver is not a real scsi driver, but it plays one on TV.\n"
+ pos = len = sprintf(buffer, "scsi_debug adapter driver, %s\n"
+ "num_devs=%d, shared (ram) size=%d MB, sector_size=%d bytes\n"
+ "cylinders=%d, heads=%d, sectors=%d\n"
+ "number of aborts=%d, device_reset=%d, bus_resets=%d, "
+ "host_resets=%d\n",
+ scsi_debug_version_str, scsi_debug_num_devs,
+ scsi_debug_dev_size_mb, SECT_SIZE,
+ N_CYLINDER, N_HEAD, N_SECTOR,
+ num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
+#if 0
+ "This driver is not a real scsi driver, but it plays one on TV.\n"
"It is very handy for debugging specific problems because you\n"
"can simulate a variety of error conditions\n");
+#endif
if (pos < offset) {
len = 0;
begin = pos;
@@ -755,44 +1201,8 @@
return (len);
}
-#ifdef CONFIG_USER_DEBUG
-/*
- * This is a hack for the user space emulator. It allows us to
- * "insert" arbitrary numbers of additional drivers.
- */
-void *scsi_debug_get_handle(void)
-{
- static Scsi_Host_Template driver_copy = SCSI_DEBUG;
- void *rtn;
- rtn = kmalloc(sizeof(driver_copy), GFP_ATOMIC);
- if(rtn==NULL)
- return NULL;
- memcpy(rtn, (void *) &driver_copy, sizeof(driver_copy));
- return rtn;
-}
-#endif
-
/* Eventually this will go into an include file, but this will be later */
-static Scsi_Host_Template driver_template = SCSI_DEBUG;
+static Scsi_Host_Template driver_template = SCSI_DEBUG_TEMPLATE;
#include "scsi_module.c"
-/*
- * Overrides for Emacs so that we almost follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
-MODULE_LICENSE("GPL");
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)