summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gilbert <dougg@torque.net>2002-11-19 07:19:09 -0600
committerChristoph Hellwig <hch@lst.de>2002-11-19 07:19:09 -0600
commit4e13766b137646d90ef9b7182b986a63c0edce41 (patch)
tree4909d7378fb747e066d96c0f09ef66624934f4c6
parent3dda41af8cf941d5f5db01dd85df502c5d96aa02 (diff)
scsi_debug 1.65 for lk 2.5.48
The scsi_debug version in lk 2.5.48 is the second last one I sent to this list. So this patch includes the changes from the last one I sent: - fix "in use" counting [hch] - clean up bios_param() code It also merges a sysfs re-organisation from Mike Anderson.
-rw-r--r--drivers/scsi/scsi_debug.c261
-rw-r--r--drivers/scsi/scsi_debug.h1
2 files changed, 190 insertions, 72 deletions
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 03916d84b911..73dd804b38b9 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -19,6 +19,7 @@
* use vmalloc() more inquiry+mode_sense [20020302]
* add timers for delayed responses [20020721]
* Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031]
+ * Mike Anderson <andmike@us.ibm.com> sysfs work [20021118]
*/
#include <linux/config.h>
@@ -40,6 +41,7 @@
#include <linux/blk.h>
#include "scsi.h"
#include "hosts.h"
+#include <scsi/scsicam.h>
#include <linux/stat.h>
@@ -49,7 +51,7 @@
#include "scsi_debug.h"
-static const char * scsi_debug_version_str = "Version: 1.64 (20021111 2)";
+static const char * scsi_debug_version_str = "Version: 1.65 (20021119)";
#ifndef SCSI_CMD_READ_16
#define SCSI_CMD_READ_16 0x88
@@ -60,24 +62,26 @@ static const char * scsi_debug_version_str = "Version: 1.64 (20021111 2)";
#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
-/* A few options that we want selected */
+/* Default values for driver parameters */
#define DEF_NR_FAKE_DEVS 1
#define DEF_DEV_SIZE_MB 8
-#define DEF_FAKE_BLK0 0
#define DEF_EVERY_NTH 100
#define DEF_DELAY 1
#define DEF_MAX_LUNS 2
#define DEF_SCSI_LEVEL 3
#define DEF_NUM_HOST 1
+#define DEF_OPTS 0
+
#define MAX_NUM_HOSTS 128
-#define DEF_OPTS 0
+/* bit mask values for scsi_debug_opts */
#define SCSI_DEBUG_OPT_NOISE 1
#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
#define SCSI_DEBUG_OPT_EVERY_NTH 4
#define OPT_MEDIUM_ERR_ADDR 0x1234
+static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
static int scsi_debug_num_devs = DEF_NR_FAKE_DEVS;
static int scsi_debug_opts = DEF_OPTS;
static int scsi_debug_every_nth = DEF_EVERY_NTH;
@@ -87,27 +91,30 @@ static int scsi_debug_max_luns = DEF_MAX_LUNS;
static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
static int scsi_debug_add_host = DEF_NUM_HOST;
- /* This assumes one lun used per allocated target id */
-#define N_HEAD 8
-#define N_SECTOR 32
#define DEV_READONLY(TGT) (0)
#define DEV_REMOVEABLE(TGT) (0)
#define PERIPH_DEVICE_TYPE(TGT) (TYPE_DISK);
-static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
-#define STORE_SIZE (scsi_debug_dev_size_mb * 1024 * 1024)
+static unsigned long sdebug_store_size; /* in bytes */
+static sector_t sdebug_capacity; /* in sectors */
+
+/* old BIOS stuff, kernel may get rid of them but some mode sense pages
+ may still need them */
+static int sdebug_heads; /* heads per disk */
+static int sdebug_cylinders_per; /* cylinders per surface */
+static int sdebug_sectors_per; /* sectors per cylinder */
/* 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))
-
-/* Time to wait before completing a command */
-#define CAPACITY (N_HEAD * N_SECTOR * N_CYLINDER)
#define SECT_SIZE_PER(TGT) SECT_SIZE
-struct Scsi_Host *scsi_debug_hosts[MAX_NUM_HOSTS];
+struct sdebug_host_info {
+ struct Scsi_Host *shost;
+ struct device *dev;
+};
+
+struct sdebug_host_info * scsi_debug_hosts;
#define SDEBUG_SENSE_LEN 32
@@ -145,7 +152,10 @@ static int num_host_resets = 0;
static spinlock_t queued_arr_lock = SPIN_LOCK_UNLOCKED;
static rwlock_t atomic_rw = RW_LOCK_UNLOCKED;
-static struct device_driver sdebug_driverfs_driver;
+static char sdebug_proc_name[] = "scsi_debug";
+static struct device_driver sdebug_driverfs_driver = {
+ .name = sdebug_proc_name,
+};
/* function declarations */
static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff,
@@ -175,8 +185,15 @@ static int inquiry_evpd_83(unsigned char * arr, int dev_id_num,
const char * dev_id_str, int dev_id_str_len);
static void do_create_driverfs_files(void);
static void do_remove_driverfs_files(void);
-static struct Scsi_Host * sdebug_add_shost(void);
+static void sdebug_add_shost(int num);
+static void sdebug_remove_shost(int num);
+static int sdebug_add_adapter(int num);
+static void sdebug_remove_adapter(int num);
+static struct device pseudo_primary;
+static struct bus_type pseudo_lld_bus;
+int scsi_debug_register_driver(struct device_driver *);
+int scsi_debug_unregister_driver(struct device_driver *);
static unsigned char * scatg2virt(const struct scatterlist * sclp)
{
@@ -193,13 +210,12 @@ static
int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
{
unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
- int block;
- int upper_blk;
+ int block, upper_blk, num;
unsigned char *buff;
int errsts = 0;
int target = SCpnt->target;
int bufflen = SCpnt->request_bufflen;
- int num, capac;
+ unsigned long capac;
struct sdebug_dev_info * devip = NULL;
unsigned char * sbuff;
@@ -230,11 +246,6 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
if (SCpnt->lun >= scsi_debug_max_luns)
return schedule_resp(SCpnt, NULL, done,
DID_NO_CONNECT << 16, 0);
-#if 0
- printk(KERN_INFO "sdebug:qc: host_no=%u, id=%u, sdp=%p, cmd=0x%x\n",
- (int)SCpnt->device->host->host_no, (int)SCpnt->device->id,
- SCpnt->device, (int)*cmd);
-#endif
devip = devInfoReg(SCpnt);
if (NULL == devip)
return schedule_resp(SCpnt, NULL, done,
@@ -302,7 +313,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
errsts = check_reset(SCpnt, devip);
memset(buff, 0, bufflen);
if (bufflen > 7) {
- capac = CAPACITY - 1;
+ capac = (unsigned long)sdebug_capacity - 1;
buff[0] = (capac >> 24);
buff[1] = (capac >> 16) & 0xff;
buff[2] = (capac >> 8) & 0xff;
@@ -382,10 +393,6 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
memset(buff, 0, bufflen);
break;
default:
-#if 0
- printk(KERN_INFO "scsi_debug: Unsupported command, "
- "opcode=0x%x\n", (int)cmd[0]);
-#endif
if ((errsts = check_reset(SCpnt, devip)))
break;
mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x20, 0, 14);
@@ -543,8 +550,8 @@ static int resp_format_pg(unsigned char * p, int pcontrol, int target)
0, 0, 0, 0, 0x40, 0, 0, 0};
memcpy(p, format_pg, sizeof(format_pg));
- p[10] = (N_SECTOR >> 8) & 0xff;
- p[11] = N_SECTOR & 0xff;
+ p[10] = (sdebug_sectors_per >> 8) & 0xff;
+ p[11] = sdebug_sectors_per & 0xff;
p[12] = (SECT_SIZE >> 8) & 0xff;
p[13] = SECT_SIZE & 0xff;
if (DEV_REMOVEABLE(target))
@@ -673,7 +680,7 @@ static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block,
int bufflen = SCpnt->request_bufflen;
unsigned long iflags;
- if (upper_blk || (block + num > CAPACITY)) {
+ if (upper_blk || (block + num > sdebug_capacity)) {
mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x21, 0, 14);
return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
}
@@ -722,7 +729,7 @@ static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block,
int bufflen = SCpnt->request_bufflen;
unsigned long iflags;
- if (upper_blk || (block + num > CAPACITY)) {
+ if (upper_blk || (block + num > sdebug_capacity)) {
mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x21, 0, 14);
return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
}
@@ -805,8 +812,6 @@ static void timer_intr_handler(unsigned long indx)
spin_unlock_irqrestore(&queued_arr_lock, iflags);
}
-static const char * sdebug_proc_name = "scsi_debug";
-
static int scsi_debug_slave_attach(struct scsi_device * sdp)
{
int k;
@@ -910,14 +915,22 @@ static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
static int scsi_debug_biosparam(struct scsi_device *sdev,
struct block_device * bdev, sector_t capacity, int *info)
{
+ int res;
+ unsigned char *buf;
+
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: biosparam\n");
- /* int size = capacity; */
- info[0] = N_HEAD;
- info[1] = N_SECTOR;
- info[2] = N_CYLINDER;
- if (info[2] >= 1024)
- info[2] = 1024;
+ buf = scsi_bios_ptable(bdev);
+ if (buf) {
+ res = scsi_partsize(buf, capacity,
+ &info[2], &info[0], &info[1]);
+ kfree(buf);
+ if (! res)
+ return res;
+ }
+ info[0] = sdebug_heads;
+ info[1] = sdebug_sectors_per;
+ info[2] = sdebug_cylinders_per;
return 0;
}
@@ -1289,7 +1302,7 @@ static int scsi_debug_proc_info(char *buffer, char **start, off_t offset,
scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
scsi_debug_cmnd_count, scsi_debug_delay,
scsi_debug_max_luns, scsi_debug_scsi_level,
- SECT_SIZE, N_CYLINDER, N_HEAD, N_SECTOR,
+ SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
if (pos < offset) {
len = 0;
@@ -1402,7 +1415,6 @@ static ssize_t sdebug_add_host_read(struct device_driver * ddp, char * buf,
static ssize_t sdebug_add_host_write(struct device_driver * ddp,
const char * buf, size_t count, loff_t off)
{
- struct Scsi_Host * hpnt;
int delta_hosts, k;
char work[20];
@@ -1410,14 +1422,21 @@ static ssize_t sdebug_add_host_write(struct device_driver * ddp,
return 0;
if (1 != sscanf(buf, "%10s", work))
return -EINVAL;
- if (1 != sscanf(work, "%d", &delta_hosts))
- return -EINVAL;
+ { /* temporary hack around sscanf() problem with -ve nums */
+ int neg = 0;
+
+ if ('-' == *work)
+ neg = 1;
+ if (1 != sscanf(work + neg, "%d", &delta_hosts))
+ return -EINVAL;
+ if (neg)
+ delta_hosts = -delta_hosts;
+ }
if (delta_hosts > 0) {
do {
for (k = 0; k < MAX_NUM_HOSTS; ++k) {
- if (NULL == scsi_debug_hosts[k]) {
- hpnt = sdebug_add_shost();
- scsi_debug_hosts[k] = hpnt;
+ if (NULL == scsi_debug_hosts[k].shost) {
+ sdebug_add_shost(k);
break;
}
}
@@ -1428,10 +1447,8 @@ static ssize_t sdebug_add_host_write(struct device_driver * ddp,
} else if (delta_hosts < 0) {
do {
for (k = MAX_NUM_HOSTS - 1; k >= 0; --k) {
- if (scsi_debug_hosts[k]) {
- scsi_remove_host(scsi_debug_hosts[k]);
- scsi_unregister(scsi_debug_hosts[k]);
- scsi_debug_hosts[k] = NULL;
+ if (scsi_debug_hosts[k].shost) {
+ sdebug_remove_shost(k);
break;
}
}
@@ -1469,30 +1486,65 @@ static void do_remove_driverfs_files()
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
}
-static struct Scsi_Host * sdebug_add_shost(void)
+static void sdebug_add_shost(int num)
{
struct Scsi_Host * hpnt;
int err;
+ if (sdebug_add_adapter(num)){
+ printk(KERN_ERR "sdebug_add_shost: sdebug_add_adapter failed\n");
+ return;
+ }
hpnt = scsi_register(&sdebug_driver_template, 0);
if (NULL == hpnt) {
+ sdebug_remove_adapter(num);
printk(KERN_ERR "sdebug_add_shost: scsi_register failed\n");
- return NULL;
+ return;
}
err = scsi_add_host(hpnt);
if (err) {
printk(KERN_ERR "sdebug_add_shost: scsi_add_host failed\n");
scsi_unregister(hpnt);
- return NULL;
+ sdebug_remove_adapter(num);
+ return;
}
hpnt->max_lun = scsi_debug_max_luns;
- return hpnt;
+
+ scsi_debug_hosts[num].shost = hpnt;
}
+static void sdebug_remove_shost(int num)
+{
+ scsi_remove_host(scsi_debug_hosts[num].shost);
+ scsi_unregister(scsi_debug_hosts[num].shost);
+ sdebug_remove_adapter(num);
+ scsi_debug_hosts[num].shost = NULL;
+}
static int __init scsi_debug_init(void)
{
- int sz, k;
+ unsigned long sz;
+ int k;
+
+ sdebug_store_size = (unsigned long)scsi_debug_dev_size_mb * 1048576;
+ sdebug_capacity = sdebug_store_size / SECT_SIZE;
+
+ /* play around with geometry, don't waste too much on track 0 */
+ sdebug_heads = 8;
+ sdebug_sectors_per = 32;
+ if (scsi_debug_dev_size_mb >= 16)
+ sdebug_heads = 32;
+ else if (scsi_debug_dev_size_mb >= 256)
+ sdebug_heads = 64;
+ sdebug_cylinders_per = (unsigned long)sdebug_capacity /
+ (sdebug_sectors_per * sdebug_heads);
+ if (sdebug_cylinders_per >= 1024) {
+ /* other LLDs do this; implies >= 1GB ram disk ... */
+ sdebug_heads = 255;
+ sdebug_sectors_per = 63;
+ sdebug_cylinders_per = (unsigned long)sdebug_capacity /
+ (sdebug_sectors_per * sdebug_heads);
+ }
if (scsi_debug_num_devs > 0) {
sz = sizeof(struct sdebug_dev_info) * scsi_debug_num_devs;
@@ -1504,7 +1556,15 @@ static int __init scsi_debug_init(void)
memset(devInfop, 0, sz);
}
- sz = STORE_SIZE;
+ sz = sizeof(struct sdebug_host_info) * MAX_NUM_HOSTS;
+ scsi_debug_hosts = vmalloc(sz);
+ if (NULL == scsi_debug_hosts) {
+ printk(KERN_ERR "scsi_debug_init: out of memory 1\n");
+ return -ENOMEM;
+ }
+ memset(scsi_debug_hosts, 0, sz);
+
+ sz = sdebug_store_size;
fake_storep = vmalloc(sz);
if (NULL == fake_storep) {
printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
@@ -1516,23 +1576,22 @@ static int __init scsi_debug_init(void)
init_all_queued();
- sdebug_driverfs_driver.name = (char *)sdebug_proc_name;
- sdebug_driverfs_driver.bus = &scsi_driverfs_bus_type;
- driver_register(&sdebug_driverfs_driver);
+ device_register(&pseudo_primary);
+ bus_register(&pseudo_lld_bus);
+ scsi_debug_register_driver(&sdebug_driverfs_driver);
do_create_driverfs_files();
sdebug_driver_template.proc_name = (char *)sdebug_proc_name;
- memset(scsi_debug_hosts, 0, sizeof(struct Scsi_Host *) * MAX_NUM_HOSTS);
for (k = 0; (k < scsi_debug_add_host) && (k < MAX_NUM_HOSTS); k++) {
- scsi_debug_hosts[k] = sdebug_add_shost();
- if (NULL == scsi_debug_hosts[k]) {
+ sdebug_add_shost(k);
+ if (NULL == scsi_debug_hosts[k].shost) {
printk(KERN_ERR "scsi_debug_init: "
"sdebug_add_shost failed k=%d\n", k);
break;
}
}
- scsi_debug_add_host = k; // number of hosts actually present
+ scsi_debug_add_host = k; // number of hosts actually present
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
printk(KERN_INFO "scsi_debug: ... built %d host(s)\n",
@@ -1546,20 +1605,78 @@ static void __exit scsi_debug_exit(void)
int k;
for (k = MAX_NUM_HOSTS - 1; k >= 0; --k) {
- if (scsi_debug_hosts[k]) {
- scsi_remove_host(scsi_debug_hosts[k]);
- scsi_unregister(scsi_debug_hosts[k]);
- scsi_debug_hosts[k] = NULL;
+ if (scsi_debug_hosts[k].shost) {
+ sdebug_remove_shost(k);
}
}
stop_all_queued();
do_remove_driverfs_files();
- driver_unregister(&sdebug_driverfs_driver);
+ scsi_debug_unregister_driver(&sdebug_driverfs_driver);
+ bus_unregister(&pseudo_lld_bus);
+ device_unregister(&pseudo_primary);
vfree(fake_storep);
if (devInfop)
vfree(devInfop);
}
-module_init(scsi_debug_init);
+device_initcall(scsi_debug_init);
module_exit(scsi_debug_exit);
+
+static struct device pseudo_primary = {
+ .name = "Host/Pseudo Bridge",
+ .bus_id = "pseudo_0",
+};
+
+static int pseudo_lld_bus_match(struct device *dev,
+ struct device_driver *dev_driver)
+{
+ return 1;
+}
+
+static struct bus_type pseudo_lld_bus = {
+ name: "pseudo",
+ match: pseudo_lld_bus_match,
+};
+
+int scsi_debug_register_driver(struct device_driver *dev_driver)
+{
+ dev_driver->bus = &pseudo_lld_bus;
+ driver_register(dev_driver);
+
+ return 0;
+}
+
+int scsi_debug_unregister_driver(struct device_driver *dev_driver)
+{
+ driver_unregister(dev_driver);
+ return 0;
+}
+
+static int sdebug_add_adapter(int num)
+{
+ struct device * dev;
+
+ dev = kmalloc(sizeof(*dev),GFP_KERNEL);
+ if (NULL == dev) {
+ printk(KERN_ERR "%s: out of memory\n", __FUNCTION__);
+ return 1;
+ }
+
+ memset(dev, 0, sizeof(*dev));
+ dev->bus = &pseudo_lld_bus;
+ dev->parent = &pseudo_primary;
+ sprintf(dev->name, "scsi debug adapter");
+ sprintf(dev->bus_id, "adapter%d", num);
+
+ device_register(dev);
+
+ scsi_debug_hosts[num].dev = dev;
+
+ return 0;
+}
+
+static void sdebug_remove_adapter(int num)
+{
+ device_unregister(scsi_debug_hosts[num].dev);
+}
diff --git a/drivers/scsi/scsi_debug.h b/drivers/scsi/scsi_debug.h
index 5f14d699009f..967c3b6afc4f 100644
--- a/drivers/scsi/scsi_debug.h
+++ b/drivers/scsi/scsi_debug.h
@@ -43,6 +43,7 @@ static Scsi_Host_Template sdebug_driver_template = {
.max_sectors = 4096,
.unchecked_isa_dma = 0,
.use_clustering = ENABLE_CLUSTERING,
+ .module = THIS_MODULE,
};
#endif