Commit b7c36ad9 authored by James Bottomley's avatar James Bottomley

Merge mulgrave.(none):/home/jejb/BK/scsi-misc-2.5

into mulgrave.(none):/home/jejb/BK/scsi-misc-new-2.5
parents 5be2bc3c ffd91b2f
......@@ -115,6 +115,9 @@ simscsi_detect (Scsi_Host_Template *templ)
{
templ->proc_name = "simscsi";
host = scsi_register(templ, 0);
if(host == NULL)
return 0;
return 1; /* fake one SCSI host adapter */
}
......
......@@ -204,6 +204,9 @@ static int aac_detect(Scsi_Host_Template *template)
* specific information.
*/
host_ptr = scsi_register( template, sizeof(struct aac_dev) );
if(host_ptr == NULL)
continue;
/*
* These three parameters can be used to allow for wide SCSI
* and for host adapters that support multiple buses.
......
......@@ -3991,6 +3991,9 @@ GDTH_INITFUNC(int, gdth_detect(Scsi_Host_Template *shtp))
break;
if (gdth_search_isa(isa_bios)) { /* controller found */
shp = scsi_register(shtp,sizeof(gdth_ext_str));
if(shp == NULL)
continue;
ha = HADATA(shp);
if (!gdth_init_isa(isa_bios,ha)) {
scsi_unregister(shp);
......@@ -4105,6 +4108,9 @@ GDTH_INITFUNC(int, gdth_detect(Scsi_Host_Template *shtp))
break;
if (gdth_search_eisa(eisa_slot)) { /* controller found */
shp = scsi_register(shtp,sizeof(gdth_ext_str));
if(shp == NULL)
continue;
ha = HADATA(shp);
if (!gdth_init_eisa(eisa_slot,ha)) {
scsi_unregister(shp);
......@@ -4214,6 +4220,9 @@ GDTH_INITFUNC(int, gdth_detect(Scsi_Host_Template *shtp))
if (gdth_ctr_count >= MAXHA)
break;
shp = scsi_register(shtp,sizeof(gdth_ext_str));
if(shp == NULL)
continue;
ha = HADATA(shp);
if (!gdth_init_pci(&pcistr[ctr],ha)) {
scsi_unregister(shp);
......
......@@ -51,6 +51,7 @@ static spinlock_t scsi_host_list_lock = SPIN_LOCK_UNLOCKED;
static int scsi_host_next_hn; /* host_no for next new host */
static int scsi_hosts_registered; /* cnt of registered scsi hosts */
static int scsi_ignore_no_error_handling = 0;
/**
* scsi_tp_for_each_host - call function for each scsi host off a template
......@@ -345,6 +346,22 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes)
int gfp_mask;
DECLARE_MUTEX_LOCKED(sem);
/*
* Determine host number. Check reserved first before allocating
* new one
*/
hname = (shost_tp->proc_name) ? shost_tp->proc_name : "";
hname_len = strlen(hname);
/* Check to see if this host has any error handling facilities */
if(shost_tp->eh_strategy_handler == NULL &&
shost_tp->eh_abort_handler == NULL &&
shost_tp->eh_device_reset_handler == NULL &&
shost_tp->eh_bus_reset_handler == NULL &&
shost_tp->eh_host_reset_handler == NULL) {
printk(KERN_ERR "ERROR: SCSI host `%s' has no error handling\nERROR: This is not a safe way to run your SCSI host\nERROR: The error handling must be added to this driver\n", hname);
dump_stack();
}
gfp_mask = GFP_KERNEL;
if (shost_tp->unchecked_isa_dma && xtr_bytes)
gfp_mask |= __GFP_DMA;
......@@ -357,13 +374,6 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes)
memset(shost, 0, sizeof(struct Scsi_Host) + xtr_bytes);
/*
* Determine host number. Check reserved first before allocating
* new one
*/
hname = (shost_tp->proc_name) ? shost_tp->proc_name : "";
hname_len = strlen(hname);
if (hname_len)
list_for_each(lh, &scsi_host_hn_list) {
shn = list_entry(lh, Scsi_Host_Name, shn_list);
......
......@@ -53,8 +53,6 @@
* type of host adapter that is supported on the system.
*/
typedef struct scsi_disk Disk;
typedef struct SHT
{
/* Used with loadable modules so that we know when it is safe to unload */
......@@ -515,13 +513,6 @@ extern void scsi_proc_host_mkdir(Scsi_Host_Template *);
extern void scsi_proc_host_add(struct Scsi_Host *);
extern void scsi_proc_host_rm(struct Scsi_Host *);
/*
* scsi_init initializes the scsi hosts.
*/
extern int next_scsi_host;
unsigned int scsi_init(void);
extern void scsi_register_blocked_host(struct Scsi_Host *);
extern void scsi_deregister_blocked_host(struct Scsi_Host *);
......@@ -543,10 +534,6 @@ static inline void scsi_set_pci_device(struct Scsi_Host *shost,
*/
extern void scan_scsis(struct Scsi_Host *, uint, uint, uint, uint);
extern void scsi_mark_host_reset(struct Scsi_Host *);
#define BLANK_HOST {"", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
struct Scsi_Device_Template
{
struct Scsi_Device_Template * next;
......@@ -554,7 +541,6 @@ struct Scsi_Device_Template
const char * tag;
struct module * module; /* Used for loadable modules */
unsigned char scsi_type;
int (*detect)(Scsi_Device *); /* Returns 1 if we can attach this device */
int (*attach)(Scsi_Device *); /* Attach devices to arrays */
void (*detach)(Scsi_Device *);
int (*init_command)(Scsi_Cmnd *); /* Used by new queueing code.
......
......@@ -153,10 +153,8 @@ static int osst_copy_from_buffer(OSST_buffer *, unsigned char *);
static int osst_init(void);
static int osst_attach(Scsi_Device *);
static int osst_detect(Scsi_Device *);
static void osst_detach(Scsi_Device *);
static int osst_dev_noticed;
static int osst_nr_dev;
static int osst_dev_max;
......@@ -166,7 +164,6 @@ struct Scsi_Device_Template osst_template =
name: "OnStream tape",
tag: "osst",
scsi_type: TYPE_TAPE,
detect: osst_detect,
attach: osst_attach,
detach: osst_detach
};
......@@ -5564,15 +5561,6 @@ static int osst_attach(Scsi_Device * SDp)
return 0;
};
static int osst_detect(Scsi_Device * SDp)
{
if (SDp->type != TYPE_TAPE) return 0;
if ( ! osst_supports(SDp) ) return 0;
osst_dev_noticed++;
return 1;
}
static int osst_registered = 0;
/* Driver initialization (not __initfunc because may be called later) */
......@@ -5580,9 +5568,6 @@ static int osst_init()
{
int i;
if (osst_dev_noticed == 0)
return 0;
if (!osst_registered) {
if (register_chrdev(MAJOR_NR,"osst",&osst_fops)) {
printk(KERN_ERR "osst :W: Unable to get major %d for OnStream tapes\n",MAJOR_NR);
......@@ -5653,7 +5638,6 @@ static void osst_detach(Scsi_Device * SDp)
os_scsi_tapes[i] = NULL;
scsi_slave_detach(SDp);
osst_nr_dev--;
osst_dev_noticed--;
return;
}
}
......
......@@ -1224,6 +1224,9 @@ static int nsp_detect(Scsi_Host_Template *sht)
request_region(data->BaseAddress, data->NumAddress, "nsp_cs");
host = scsi_register(sht, 0);
if(host == NULL)
return 0;
host->unique_id = data->BaseAddress;
host->io_port = data->BaseAddress;
host->n_io_port = data->NumAddress;
......
......@@ -226,6 +226,8 @@ void scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt)
if (!SHpnt->use_clustering)
clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
blk_queue_prep_rq(q, scsi_prep_fn);
}
#ifdef MODULE
......@@ -1958,17 +1960,6 @@ static int proc_scsi_gen_write(struct file * file, const char * buf,
}
#endif
void scsi_detect_device(struct scsi_device *sdev)
{
struct Scsi_Device_Template *sdt;
down_read(&scsi_devicelist_mutex);
for (sdt = scsi_devicelist; sdt; sdt = sdt->next)
if (sdt->detect)
(*sdt->detect)(sdev);
up_read(&scsi_devicelist_mutex);
}
int scsi_attach_device(struct scsi_device *sdev)
{
struct Scsi_Device_Template *sdt;
......@@ -2089,22 +2080,6 @@ int scsi_register_device(struct Scsi_Device_Template *tpnt)
driver_register(&tpnt->scsi_driverfs_driver);
/*
* First scan the devices that we know about, and see if we notice them.
*/
for (shpnt = scsi_host_get_next(NULL); shpnt;
shpnt = scsi_host_get_next(shpnt)) {
for (SDpnt = shpnt->host_queue; SDpnt;
SDpnt = SDpnt->next) {
if (tpnt->detect)
(*tpnt->detect) (SDpnt);
}
}
/*
* Now actually connect the devices to the new driver.
*/
for (shpnt = scsi_host_get_next(NULL); shpnt;
shpnt = scsi_host_get_next(shpnt)) {
for (SDpnt = shpnt->host_queue; SDpnt;
......
......@@ -404,15 +404,7 @@ typedef struct scsi_request Scsi_Request;
* Here is where we prototype most of the mid-layer.
*/
/*
* Initializes all SCSI devices. This scans all scsi busses.
*/
extern unsigned int scsi_logging_level; /* What do we log? */
extern unsigned int scsi_dma_free_sectors; /* How much room do we have left */
extern unsigned int scsi_need_isa_buffer; /* True if some devices need indirection
* buffers */
extern volatile int in_scan_scsis;
extern struct bus_type scsi_driverfs_bus_type;
......@@ -455,6 +447,7 @@ extern int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int);
extern void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
int block_sectors);
extern void scsi_queue_next_request(request_queue_t * q, Scsi_Cmnd * SCpnt);
extern int scsi_prep_fn(struct request_queue *q, struct request *req);
extern void scsi_request_fn(request_queue_t * q);
extern int scsi_starvation_completion(Scsi_Device * SDpnt);
......@@ -480,7 +473,6 @@ extern void scsi_do_cmd(Scsi_Cmnd *, const void *cmnd,
int timeout, int retries);
extern int scsi_dev_init(void);
extern int scsi_mlqueue_insert(struct scsi_cmnd *, int);
extern void scsi_detect_device(struct scsi_device *);
extern int scsi_attach_device(struct scsi_device *);
extern void scsi_detach_device(struct scsi_device *);
......@@ -500,12 +492,6 @@ extern void scsi_do_req(Scsi_Request *, const void *cmnd,
extern int scsi_insert_special_req(Scsi_Request * SRpnt, int);
extern void scsi_init_cmd_from_req(Scsi_Cmnd *, Scsi_Request *);
/*
* Prototypes for functions/data in hosts.c
*/
extern int max_scsi_hosts;
/*
* Prototypes for functions in scsi_proc.c
*/
......@@ -837,25 +823,6 @@ struct scsi_cmnd {
#define SCSI_MLQUEUE_HOST_BUSY 0x1055
#define SCSI_MLQUEUE_DEVICE_BUSY 0x1056
#define SCSI_SLEEP(QUEUE, CONDITION) { \
if (CONDITION) { \
DECLARE_WAITQUEUE(wait, current); \
add_wait_queue(QUEUE, &wait); \
for(;;) { \
set_current_state(TASK_UNINTERRUPTIBLE); \
if (CONDITION) { \
if (in_interrupt()) \
panic("scsi: trying to call schedule() in interrupt" \
", file %s, line %d.\n", __FILE__, __LINE__); \
schedule(); \
} \
else \
break; \
} \
remove_wait_queue(QUEUE, &wait);\
current->state = TASK_RUNNING; \
}; }
/*
* old style reset request from external source
* (private to sg.c and scsi_error.c, supplied by scsi_obsolete.c)
......
/*
* linux/kernel/scsi_debug.c
*
* vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
* 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
* anything out of the ordinary is seen.
* ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*
* 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).
* (or disk like devices) sharing a common amount of RAM
*
*
* For documentation see http://www.torque.net/sg/sdebug.html
*
......@@ -36,8 +37,6 @@
#include <linux/smp_lock.h>
#include <linux/vmalloc.h>
#include <asm/io.h>
#include <linux/blk.h>
#include "scsi.h"
#include "hosts.h"
......@@ -50,9 +49,7 @@
#include "scsi_debug.h"
static const char * scsi_debug_version_str = "Version: 1.63 (20021103)";
#define DRIVERFS_SUPPORT 1 /* comment out whole line to disable */
static const char * scsi_debug_version_str = "Version: 1.64 (20021109)";
#ifndef SCSI_CMD_READ_16
......@@ -72,6 +69,8 @@ static const char * scsi_debug_version_str = "Version: 1.63 (20021103)";
#define DEF_DELAY 1
#define DEF_MAX_LUNS 2
#define DEF_SCSI_LEVEL 3
#define DEF_ADD_HOST 1
#define MAX_NUM_HOSTS 128
#define DEF_OPTS 0
#define SCSI_DEBUG_OPT_NOISE 1
......@@ -87,8 +86,9 @@ static int scsi_debug_cmnd_count = 0;
static int scsi_debug_delay = DEF_DELAY;
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_ADD_HOST;
#define NR_HOSTS_PRESENT (((scsi_debug_num_devs - 1) / 7) + 1)
/* #define NR_HOSTS_PRESENT (((scsi_debug_num_devs - 1) / 7) + 1) */
/* This assumes one lun used per allocated target id */
#define N_HEAD 8
#define N_SECTOR 32
......@@ -109,6 +109,7 @@ static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
#define CAPACITY (N_HEAD * N_SECTOR * N_CYLINDER)
#define SECT_SIZE_PER(TGT) SECT_SIZE
struct Scsi_Host *scsi_debug_hosts[MAX_NUM_HOSTS];
#define SDEBUG_SENSE_LEN 32
......@@ -146,9 +147,7 @@ static int num_host_resets = 0;
static spinlock_t queued_arr_lock = SPIN_LOCK_UNLOCKED;
static rwlock_t atomic_rw = RW_LOCK_UNLOCKED;
#ifdef DRIVERFS_SUPPORT
static struct device_driver sdebug_driverfs_driver;
#endif
/* function declarations */
static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff,
......@@ -176,10 +175,9 @@ static void stop_all_queued(void);
static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
static int inquiry_evpd_83(unsigned char * arr, int dev_id_num,
const char * dev_id_str, int dev_id_str_len);
#ifdef DRIVERFS_SUPPORT
static void do_create_driverfs_files(void);
static void do_remove_driverfs_files(void);
#endif
static struct Scsi_Host * sdebug_add_shost(void);
static unsigned char * scatg2virt(const struct scatterlist * sclp)
......@@ -225,7 +223,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
bufflen = SDEBUG_SENSE_LEN;
}
if(target == driver_template.this_id) {
if(target == sdebug_driver_template.this_id) {
printk(KERN_WARNING
"scsi_debug: initiator's id used as target!\n");
return schedule_resp(SCpnt, NULL, done, 0, 0);
......@@ -809,92 +807,9 @@ static void timer_intr_handler(unsigned long indx)
spin_unlock_irqrestore(&queued_arr_lock, iflags);
}
static int initialized = 0;
static int num_hosts_present = 0;
static const char * sdebug_proc_name = "scsi_debug";
static int scsi_debug_detect(struct SHT * tpnt)
{
int k, sz;
struct Scsi_Host * hpnt;
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: detect\n");
if (0 == initialized) {
++initialized;
sz = sizeof(struct sdebug_dev_info) * scsi_debug_num_devs;
devInfop = vmalloc(sz);
if (NULL == devInfop) {
printk(KERN_ERR "scsi_debug_detect: out of "
"memory\n");
return 0;
}
memset(devInfop, 0, sz);
sz = STORE_SIZE;
fake_storep = vmalloc(sz);
if (NULL == fake_storep) {
printk(KERN_ERR "scsi_debug_detect: out of memory"
", 1\n");
return 0;
}
memset(fake_storep, 0, sz);
init_all_queued();
#ifdef DRIVERFS_SUPPORT
sdebug_driverfs_driver.name = (char *)sdebug_proc_name;
sdebug_driverfs_driver.bus = &scsi_driverfs_bus_type;
driver_register(&sdebug_driverfs_driver);
do_create_driverfs_files();
#endif
tpnt->proc_name = (char *)sdebug_proc_name;
for (num_hosts_present = 0, k = 0; k < NR_HOSTS_PRESENT; k++) {
if ((hpnt = scsi_register(tpnt, 0)) == NULL)
printk(KERN_ERR "scsi_debug_detect: "
"scsi_register failed k=%d\n", k);
else {
hpnt->max_lun = scsi_debug_max_luns;
++num_hosts_present;
}
}
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: ... built %d host(s)\n",
num_hosts_present);
return num_hosts_present;
} else {
printk(KERN_WARNING "scsi_debug_detect: called again\n");
return 0;
}
}
static int num_releases = 0;
static int scsi_debug_release(struct Scsi_Host * hpnt)
{
int host_no = hpnt->host_no;
if (++num_releases == num_hosts_present) {
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: [last] release, "
"host_no=%u\n", host_no);
num_releases = 0;
initialized = 0;
stop_all_queued();
#ifdef DRIVERFS_SUPPORT
do_remove_driverfs_files();
driver_unregister(&sdebug_driverfs_driver);
#endif
vfree(fake_storep);
vfree(devInfop);
}
else {
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: release, host_no=%u\n",
host_no);
}
scsi_unregister(hpnt);
return 0;
}
static int scsi_debug_slave_attach(struct scsi_device * sdp)
{
int k;
......@@ -1290,6 +1205,22 @@ static int __init delay_setup(char *str)
}
__setup("scsi_debug_delay=", delay_setup);
static int __init add_host_setup(char *str)
{
int tmp;
if (get_option(&str, &tmp) == 1) {
scsi_debug_add_host = tmp;
return 1;
} else {
printk(KERN_INFO "scsi_debug_add_host: usage "
"scsi_debug_add_host=<n>\n"
" <n> 0..127 (default 1)\n");
return 0;
}
}
__setup("scsi_debug_add_host=", add_host_setup);
#endif
MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
......@@ -1308,6 +1239,8 @@ MODULE_PARM(scsi_debug_every_nth, "i");
MODULE_PARM_DESC(scsi_debug_every_nth, "timeout every nth command(def=100)");
MODULE_PARM(scsi_debug_delay, "i");
MODULE_PARM_DESC(scsi_debug_delay, "# of jiffies to delay response(def=1)");
MODULE_PARM(scsi_debug_add_host, "i");
MODULE_PARM_DESC(scsi_debug_add_host, "0..127 hosts allowed(def=1)");
MODULE_LICENSE("GPL");
static char sdebug_info[256];
......@@ -1372,7 +1305,6 @@ static int scsi_debug_proc_info(char *buffer, char **start, off_t offset,
return len;
}
#ifdef DRIVERFS_SUPPORT
static ssize_t sdebug_delay_read(struct device_driver * ddp, char * buf,
size_t count, loff_t off)
{
......@@ -1464,6 +1396,69 @@ static ssize_t sdebug_scsi_level_read(struct device_driver * ddp, char * buf,
}
DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_read, NULL)
static ssize_t sdebug_add_host_read(struct device_driver * ddp, char * buf,
size_t count, loff_t off)
{
return off ? 0 : snprintf(buf, count, "%d\n", scsi_debug_add_host);
}
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 add_host, num, k;
char work[20];
if (off)
return 0;
if (1 != sscanf(buf, "%10s", work))
return -EINVAL;
{ /* temporary hack around sscanf() problem with -ve nums */
int neg = 0;
if ('-' == *work)
neg = 1;
if (1 != sscanf(work + neg, "%d", &add_host))
return -EINVAL;
if (neg)
add_host = -add_host;
}
num = 0;
if (add_host > 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;
break;
}
}
if (k == MAX_NUM_HOSTS)
break;
++num;
} while (--add_host);
scsi_debug_add_host += num;
} else if (add_host < 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;
break;
}
}
if (k < 0)
break;
++num;
} while (++add_host);
scsi_debug_add_host -= num;
}
return count;
}
DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_read,
sdebug_add_host_write)
static void do_create_driverfs_files()
{
driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
......@@ -1473,10 +1468,12 @@ static void do_create_driverfs_files()
driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
}
static void do_remove_driverfs_files()
{
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
......@@ -1485,6 +1482,100 @@ static void do_remove_driverfs_files()
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
}
#endif
#include "scsi_module.c"
static struct Scsi_Host * sdebug_add_shost(void)
{
struct Scsi_Host * hpnt;
int err;
hpnt = scsi_register(&sdebug_driver_template, 0);
if (NULL == hpnt) {
printk(KERN_ERR "sdebug_add_shost: scsi_register failed\n");
return NULL;
}
err = scsi_add_host(hpnt);
if (err) {
printk(KERN_ERR "sdebug_add_shost: scsi_add_host failed\n");
scsi_unregister(hpnt);
return NULL;
}
hpnt->max_lun = scsi_debug_max_luns;
return hpnt;
}
static int __init scsi_debug_init(void)
{
struct Scsi_Host * hpnt;
int sz, k;
if (scsi_debug_num_devs > 0) {
sz = sizeof(struct sdebug_dev_info) * scsi_debug_num_devs;
devInfop = vmalloc(sz);
if (NULL == devInfop) {
printk(KERN_ERR "scsi_debug_init: out of memory\n");
return -ENOMEM;
}
memset(devInfop, 0, sz);
}
sz = STORE_SIZE;
fake_storep = vmalloc(sz);
if (NULL == fake_storep) {
printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
if (devInfop)
vfree(devInfop);
return -ENOMEM;
}
memset(fake_storep, 0, sz);
init_all_queued();
sdebug_driverfs_driver.name = (char *)sdebug_proc_name;
sdebug_driverfs_driver.bus = &scsi_driverfs_bus_type;
driver_register(&sdebug_driverfs_driver);
do_create_driverfs_files();
sdebug_driver_template.proc_name = (char *)sdebug_proc_name;
for (k = 0; (k < scsi_debug_add_host) && (k < MAX_NUM_HOSTS); k++) {
hpnt = sdebug_add_shost();
if (NULL == hpnt) {
printk(KERN_ERR "scsi_debug_init: "
"sdebug_add_shost failed k=%d\n", k);
break;
}
++num_hosts_present;
scsi_debug_hosts[k] = hpnt;
}
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
printk(KERN_INFO "scsi_debug: ... built %d host(s)\n",
num_hosts_present);
}
return 0;
}
static void __exit scsi_debug_exit(void)
{
int k;
for (k = 0; k < num_hosts_present; k++) {
scsi_remove_host(scsi_debug_hosts[k]);
scsi_unregister(scsi_debug_hosts[k]);
scsi_debug_hosts[k] = NULL;
}
stop_all_queued();
do_remove_driverfs_files();
driver_unregister(&sdebug_driverfs_driver);
vfree(fake_storep);
if (devInfop)
vfree(devInfop);
}
module_init(scsi_debug_init);
module_exit(scsi_debug_exit);
#ifndef _SCSI_DEBUG_H
#include <linux/types.h>
#include <linux/kdev_t.h>
static int scsi_debug_detect(struct SHT *);
static int scsi_debug_slave_attach(struct scsi_device *);
static void scsi_debug_slave_detach(struct scsi_device *);
static int scsi_debug_release(struct Scsi_Host *);
/* static int scsi_debug_command(struct scsi_cmnd *); */
static int scsi_debug_queuecommand(struct scsi_cmnd *,
void (*done) (struct scsi_cmnd *));
static int scsi_debug_ioctl(struct scsi_device *, int, void *);
......@@ -20,10 +16,6 @@ static int scsi_debug_host_reset(struct scsi_cmnd *);
static int scsi_debug_proc_info(char *, char **, off_t, int, int, int);
static const char * scsi_debug_info(struct Scsi_Host *);
#ifndef NULL
#define NULL 0
#endif
/*
* This driver is written for the lk 2.5 series
*/
......@@ -31,14 +23,12 @@ static const char * scsi_debug_info(struct Scsi_Host *);
#define SCSI_DEBUG_MAX_CMD_LEN 16
static Scsi_Host_Template driver_template = {
static Scsi_Host_Template sdebug_driver_template = {
.proc_info = scsi_debug_proc_info,
.name = "SCSI DEBUG",
.info = scsi_debug_info,
.detect = scsi_debug_detect,
.slave_attach = scsi_debug_slave_attach,
.slave_detach = scsi_debug_slave_detach,
.release = scsi_debug_release,
.ioctl = scsi_debug_ioctl,
.queuecommand = scsi_debug_queuecommand,
.eh_abort_handler = scsi_debug_abort,
......@@ -50,8 +40,9 @@ static Scsi_Host_Template driver_template = {
.this_id = 7,
.sg_tablesize = 64,
.cmd_per_lun = 3,
.max_sectors = 4096,
.unchecked_isa_dma = 0,
.use_clustering = ENABLE_CLUSTERING,
}; /* the name 'driver_template' is used by scsi_module.c */
};
#endif
......@@ -177,8 +177,7 @@ void scsi_times_out(Scsi_Cmnd *scmd)
**/
int scsi_block_when_processing_errors(Scsi_Device *sdev)
{
SCSI_SLEEP(&sdev->host->host_wait, sdev->host->in_recovery);
wait_event(sdev->host->host_wait, (sdev->host->in_recovery == 0));
SCSI_LOG_ERROR_RECOVERY(5, printk("%s: rtn: %d\n", __FUNCTION__,
sdev->online));
......
......@@ -102,6 +102,13 @@ int scsi_insert_special_req(Scsi_Request * SRpnt, int at_head)
{
request_queue_t *q = &SRpnt->sr_device->request_queue;
/* This is used to insert SRpnt specials. Because users of
* this function are apt to reuse requests with no modification,
* we have to sanitise the request flags here
*/
SRpnt->sr_request->flags &= ~REQ_DONTPREP;
blk_insert_request(q, SRpnt->sr_request, at_head, SRpnt);
return 0;
}
......@@ -240,6 +247,12 @@ void scsi_queue_next_request(request_queue_t * q, Scsi_Cmnd * SCpnt)
SCpnt->request->special = (void *) SCpnt;
if(blk_rq_tagged(SCpnt->request))
blk_queue_end_tag(q, SCpnt->request);
/* set REQ_SPECIAL - we have a command
* clear REQ_DONTPREP - we assume the sg table has been
* nuked so we need to set it up again.
*/
SCpnt->request->flags |= REQ_SPECIAL;
SCpnt->request->flags &= ~REQ_DONTPREP;
__elv_add_request(q, SCpnt->request, 0, 0);
}
......@@ -741,7 +754,7 @@ static int scsi_init_io(Scsi_Cmnd *SCpnt)
SCpnt->use_sg = req->nr_phys_segments;
gfp_mask = GFP_NOIO;
if (in_interrupt()) {
if (likely(in_atomic())) {
gfp_mask &= ~__GFP_WAIT;
gfp_mask |= __GFP_HIGH;
}
......@@ -788,6 +801,116 @@ static int scsi_init_io(Scsi_Cmnd *SCpnt)
return 0;
}
int scsi_prep_fn(struct request_queue *q, struct request *req)
{
struct Scsi_Device_Template *STpnt;
Scsi_Cmnd *SCpnt;
Scsi_Device *SDpnt;
SDpnt = (Scsi_Device *) q->queuedata;
BUG_ON(!SDpnt);
/*
* Find the actual device driver associated with this command.
* The SPECIAL requests are things like character device or
* ioctls, which did not originate from ll_rw_blk. Note that
* the special field is also used to indicate the SCpnt for
* the remainder of a partially fulfilled request that can
* come up when there is a medium error. We have to treat
* these two cases differently. We differentiate by looking
* at request->cmd, as this tells us the real story.
*/
if (req->flags & REQ_SPECIAL) {
Scsi_Request *SRpnt;
STpnt = NULL;
SCpnt = (Scsi_Cmnd *) req->special;
SRpnt = (Scsi_Request *) req->special;
if( SRpnt->sr_magic == SCSI_REQ_MAGIC ) {
SCpnt = scsi_allocate_device(SRpnt->sr_device,
FALSE, FALSE);
if (!SCpnt)
return BLKPREP_DEFER;
scsi_init_cmd_from_req(SCpnt, SRpnt);
}
} else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
/*
* Now try and find a command block that we can use.
*/
if (req->special) {
SCpnt = (Scsi_Cmnd *) req->special;
} else {
SCpnt = scsi_allocate_device(SDpnt, FALSE, FALSE);
}
/*
* if command allocation failure, wait a bit
*/
if (unlikely(!SCpnt))
return BLKPREP_DEFER;
/* pull a tag out of the request if we have one */
SCpnt->tag = req->tag;
} else {
blk_dump_rq_flags(req, "SCSI bad req");
return BLKPREP_KILL;
}
/* note the overloading of req->special. When the tag
* is active it always means SCpnt. If the tag goes
* back for re-queueing, it may be reset */
req->special = SCpnt;
SCpnt->request = req;
/*
* FIXME: drop the lock here because the functions below
* expect to be called without the queue lock held. Also,
* previously, we dequeued the request before dropping the
* lock. We hope REQ_STARTED prevents anything untoward from
* happening now.
*/
if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
/*
* This will do a couple of things:
* 1) Fill in the actual SCSI command.
* 2) Fill in any other upper-level specific fields
* (timeout).
*
* If this returns 0, it means that the request failed
* (reading past end of disk, reading offline device,
* etc). This won't actually talk to the device, but
* some kinds of consistency checking may cause the
* request to be rejected immediately.
*/
STpnt = scsi_get_request_dev(req);
BUG_ON(!STpnt);
/*
* This sets up the scatter-gather table (allocating if
* required).
*/
if (!scsi_init_io(SCpnt)) {
/* Mark it as special --- We already have an
* allocated command associated with it */
req->flags |= REQ_SPECIAL;
return BLKPREP_DEFER;
}
/*
* Initialize the actual SCSI command for this request.
*/
if (!STpnt->init_command(SCpnt)) {
scsi_release_buffers(SCpnt);
return BLKPREP_KILL;
}
}
/* The request is now prepped, no need to come back here */
req->flags |= REQ_DONTPREP;
return BLKPREP_OK;
}
/*
* Function: scsi_request_fn()
*
......@@ -811,10 +934,8 @@ void scsi_request_fn(request_queue_t * q)
{
struct request *req;
Scsi_Cmnd *SCpnt;
Scsi_Request *SRpnt;
Scsi_Device *SDpnt;
struct Scsi_Host *SHpnt;
struct Scsi_Device_Template *STpnt;
ASSERT_LOCK(q->queue_lock, 1);
......@@ -837,6 +958,14 @@ void scsi_request_fn(request_queue_t * q)
if (SHpnt->in_recovery || blk_queue_plugged(q))
return;
/*
* get next queueable request. We do this early to make sure
* that the request is fully prepared even if we cannot
* accept it. If there is no request, we'll detect this
* lower down.
*/
req = elv_next_request(q);
if(SHpnt->host_busy == 0 && SHpnt->host_blocked) {
/* unblock after host_blocked iterates to zero */
if(--SHpnt->host_blocked == 0) {
......@@ -888,141 +1017,40 @@ void scsi_request_fn(request_queue_t * q)
if (blk_queue_empty(q))
break;
/*
* get next queueable request.
*/
req = elv_next_request(q);
/*
* Find the actual device driver associated with this command.
* The SPECIAL requests are things like character device or
* ioctls, which did not originate from ll_rw_blk. Note that
* the special field is also used to indicate the SCpnt for
* the remainder of a partially fulfilled request that can
* come up when there is a medium error. We have to treat
* these two cases differently. We differentiate by looking
* at request->cmd, as this tells us the real story.
*/
if (req->flags & REQ_SPECIAL) {
STpnt = NULL;
SCpnt = (Scsi_Cmnd *) req->special;
SRpnt = (Scsi_Request *) req->special;
if( SRpnt->sr_magic == SCSI_REQ_MAGIC ) {
SCpnt = scsi_allocate_device(SRpnt->sr_device,
FALSE, FALSE);
if (!SCpnt)
break;
scsi_init_cmd_from_req(SCpnt, SRpnt);
}
} else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
SRpnt = NULL;
STpnt = scsi_get_request_dev(req);
if (!STpnt) {
panic("Unable to find device associated with request");
}
/*
* Now try and find a command block that we can use.
*/
if (req->special) {
SCpnt = (Scsi_Cmnd *) req->special;
} else {
SCpnt = scsi_allocate_device(SDpnt, FALSE, FALSE);
}
/*
* If so, we are ready to do something. Bump the count
* while the queue is locked and then break out of the
* loop. Otherwise loop around and try another request.
*/
if (!SCpnt)
break;
/* pull a tag out of the request if we have one */
SCpnt->tag = req->tag;
} else {
blk_dump_rq_flags(req, "SCSI bad req");
if(!req) {
/* can happen if the prep fails
* FIXME: elv_next_request() should be plugging the
* queue */
blk_plug_device(q);
break;
}
/*
* Now bump the usage count for both the host and the
* device.
SCpnt = (struct scsi_cmnd *)req->special;
/* Should be impossible for a correctly prepared request
* please mail the stack trace to linux-scsi@vger.kernel.org
*/
SHpnt->host_busy++;
SDpnt->device_busy++;
BUG_ON(!SCpnt);
/*
* Finally, before we release the lock, we copy the
* request to the command block, and remove the
* request from the request list. Note that we always
* request from the request list. Note that we always
* operate on the queue head - there is absolutely no
* reason to search the list, because all of the commands
* in this queue are for the same device.
* reason to search the list, because all of the
* commands in this queue are for the same device.
*/
if(!(blk_queue_tagged(q) && (blk_queue_start_tag(q, req) == 0)))
blkdev_dequeue_request(req);
/* note the overloading of req->special. When the tag
* is active it always means SCpnt. If the tag goes
* back for re-queueing, it may be reset */
req->special = SCpnt;
SCpnt->request = req;
/*
* Now it is finally safe to release the lock. We are
* not going to noodle the request list until this
* request has been queued and we loop back to queue
* another.
* Now bump the usage count for both the host and the
* device.
*/
req = NULL;
SHpnt->host_busy++;
SDpnt->device_busy++;
spin_unlock_irq(q->queue_lock);
if (!(SCpnt->request->flags & REQ_DONTPREP)
&& (SCpnt->request->flags & (REQ_CMD | REQ_BLOCK_PC))) {
/*
* This will do a couple of things:
* 1) Fill in the actual SCSI command.
* 2) Fill in any other upper-level specific fields
* (timeout).
*
* If this returns 0, it means that the request failed
* (reading past end of disk, reading offline device,
* etc). This won't actually talk to the device, but
* some kinds of consistency checking may cause the
* request to be rejected immediately.
*/
if (STpnt == NULL)
STpnt = scsi_get_request_dev(SCpnt->request);
/*
* This sets up the scatter-gather table (allocating if
* required).
*/
if (!scsi_init_io(SCpnt)) {
scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_DEVICE_BUSY);
spin_lock_irq(q->queue_lock);
break;
}
/*
* Initialize the actual SCSI command for this request.
*/
if (!STpnt->init_command(SCpnt)) {
scsi_release_buffers(SCpnt);
SCpnt = __scsi_end_request(SCpnt, 0,
SCpnt->request->nr_sectors, 0, 0);
if( SCpnt != NULL )
{
panic("Should not have leftover blocks\n");
}
spin_lock_irq(q->queue_lock);
SHpnt->host_busy--;
SDpnt->device_busy--;
continue;
}
}
SCpnt->request->flags |= REQ_DONTPREP;
/*
* Finally, initialize any error handling parameters, and set up
* the timers for timeouts.
......
......@@ -33,13 +33,13 @@ their own directory under the drivers/scsi directory.
scsi_module.c is normally included at the end of a lower
level driver. For it to work a declaration like this is needed before
it is included:
static Scsi_Host_Template driver_template = DRIVER_TEMPLATE;
static struct SHT driver_template = DRIVER_TEMPLATE;
#include "scsi_module.c"
In this case "DRIVER_TEMPLATE" is defined to be a structure initializer
that is placed in the driver header file by convention. It contains
pointers to supported interface functions and other values.
Scsi_Host_Template is defined in hosts.h .
struct SHT is defined in hosts.h .
The scsi_module.c assumes the name "driver_template" is appropriately
defined. scsi_module.c contains 2 functions:
......@@ -53,18 +53,42 @@ files (all found in the drivers/scsi directory) will need some attention:
Makefile, Config.help and Config.in . It is probably best to look at what
an existing lower level driver does in this regard.
Conventions
===========
First there is Linus's thoughts on C coding found in file
Documentation/CodingStyle .
Next there is a movement to "outlaw" typedefs introducing synonyms for
struct tags. Both can be still found in the scsi subsystem, for example:
"typedef struct SHT { ...} Scsi_Host_Template;" in hosts.h . In this
case "struct SHT" is preferred to "Scsi_Host_Template".
Also C99 additions are encouraged to the extent they are supported
by the relevant gcc compilers. So "//" style comments are encouraged
were appropriate as are C99 style structure and array initializers.
Interface Functions
===================
Interface functions should be declared static. The accepted convention
is that driver "xyz" will declare its detect() function as:
static int xyz_detect(Scsi_Host_Template * shtp);
static int xyz_detect(struct SHT * shtp);
A pointer to this function should be placed in the 'detect' member of
a Scsi_Host_Template instance. A pointer to such an instance should
a "struct SHT" instance. A pointer to such an instance should
passed to the mid level's scsi_register_host().
The interface functions are also described in the hosts.h file immediately
above their definition point in "struct SHT". In some cases more detail
is given in hosts.h than below.
Those interface functions marked "Required: yes" must be implemented
by the lower level driver and a pointer to that function must be
placed in the driver's "struct SHT" instance. Interface functions marked
"Required: no" need not be implemented and if they are a pointer to
that function should be placed in the driver's "struct SHT" instance.
The interface functions are listed below in alphabetical order.
......@@ -72,7 +96,7 @@ The interface functions are listed below in alphabetical order.
* bios_param - fetch head, sector, cylinder info for a disk
* @sdev: pointer to scsi device context (defined in scsi.h)
* @bdev: pointer to block device context (defined in fs.h)
* @capacity: device size
* @capacity: device size (in sectors)
* @params: three element array to place output:
* params[0] number of heads
* params[1] number of sectors
......@@ -84,13 +108,13 @@ The interface functions are listed below in alphabetical order.
*
* Locks: none
*
* Notes: sd driver will make up geometry (based on READ CAPACITY)
* Notes: an arbitrary geometry (based on READ CAPACITY) is used
* if this function is not provided. The params array is
* pre-initialized with made up values just in case this function
* doesn't output anything.
**/
int bios_param(struct scsi_device * sdev, struct block_device *bdev,
sector_t capacity, int params[3]);
sector_t capacity, int params[3]);
/**
......@@ -101,16 +125,16 @@ The interface functions are listed below in alphabetical order.
* host_byte, driver_byte (status_byte is in the lsb). A value of
* 0 is an unqualified success.
*
* Required: if Scsi_Host::can_queue can ever by cleared (zero)
* Required: if struct Scsi_Host::can_queue can ever by cleared (zero)
* then this function is required.
*
* Locks: Scsi_Host::host_lock held on entry (with "irqsave") and
* is expected to be held on return.
* Locks: struct Scsi_Host::host_lock held on entry (with "irqsave")
* and is expected to be held on return.
*
* Notes: Drivers tend to be dropping support for this function and
* rather supporting queuecommand().
**/
int command(Scsi_Cmnd * scp);
int command(struct scsi_cmnd * scp);
/**
......@@ -129,7 +153,7 @@ The interface functions are listed below in alphabetical order.
* For each host found, this method should call scsi_register()
* [see hosts.c].
**/
int detect(Scsi_Host_Template * shtp);
int detect(struct SHT * shtp);
/**
......@@ -140,13 +164,13 @@ The interface functions are listed below in alphabetical order.
*
* Required: no
*
* Locks: Scsi_Host::host_lock held (with irqsave) on entry and assumed
* to be held on return.
* Locks: struct Scsi_Host::host_lock held (with irqsave) on entry
* and assumed to be held on return.
*
* Notes: Invoked from scsi_eh thread. No other commands will be
* queued on current host during eh.
**/
int eh_abort_handler(Scsi_Cmnd * scp);
int eh_abort_handler(struct scsi_cmnd * scp);
/**
......@@ -157,13 +181,13 @@ The interface functions are listed below in alphabetical order.
*
* Required: no
*
* Locks: Scsi_Host::host_lock held (with irqsave) on entry and assumed
* to be held on return.
* Locks: struct Scsi_Host::host_lock held (with irqsave) on entry
* and assumed to be held on return.
*
* Notes: Invoked from scsi_eh thread. No other commands will be
* queued on current host during eh.
**/
int eh_device_reset_handler(Scsi_Cmnd * scp);
int eh_device_reset_handler(struct scsi_cmnd * scp);
/**
......@@ -174,13 +198,13 @@ The interface functions are listed below in alphabetical order.
*
* Required: no
*
* Locks: Scsi_Host::host_lock held (with irqsave) on entry and assumed
* to be held on return.
* Locks: struct Scsi_Host::host_lock held (with irqsave) on entry
* and assumed to be held on return.
*
* Notes: Invoked from scsi_eh thread. No other commands will be
* queued on current host during eh.
**/
int eh_bus_reset_handler(Scsi_Cmnd * scp);
int eh_bus_reset_handler(struct scsi_cmnd * scp);
/**
......@@ -191,8 +215,8 @@ The interface functions are listed below in alphabetical order.
*
* Required: no
*
* Locks: Scsi_Host::host_lock held (with irqsave) on entry and assumed
* to be held on return.
* Locks: struct Scsi_Host::host_lock held (with irqsave) on entry
* and assumed to be held on return.
*
* Notes: Invoked from scsi_eh thread. No other commands will be
* queued on current host during eh.
......@@ -201,7 +225,7 @@ The interface functions are listed below in alphabetical order.
* defined (or they all return FAILED) then the device in question
* will be set offline whenever eh is invoked.
**/
int eh_host_reset_handler(Scsi_Cmnd * scp);
int eh_host_reset_handler(struct scsi_cmnd * scp);
/**
......@@ -234,11 +258,12 @@ The interface functions are listed below in alphabetical order.
* Locks: none
*
* Notes: Often supplies PCI or ISA information such as IO addresses
* and interrupt numbers. If not supplied Scsi_Host::name used
* and interrupt numbers. If not supplied struct Scsi_Host::name used
* instead. It is assumed the returned information fits on one line
* (i.e. does not included embedded newlines).
* The SCSI_IOCTL_PROBE_HOST ioctl yields the string returned by this
* function (or Scsi_Host::name if this function is not available).
* function (or struct Scsi_Host::name if this function is not
* available).
* In a similar manner, scsi_register_host() outputs to the console
* each host's "info" (or name) for the driver it is registering.
* Also if proc_info() is not supplied, the output of this function
......@@ -275,7 +300,7 @@ The interface functions are listed below in alphabetical order.
* Unfortunately some applications expect -EINVAL and react badly
* when -ENOTTY is returned; stick with -EINVAL.
**/
int ioctl(Scsi_Device *sdp, int cmd, void *arg);
int ioctl(struct scsi_device *sdp, int cmd, void *arg);
/**
......@@ -287,7 +312,7 @@ The interface functions are listed below in alphabetical order.
* @offset: offset within buffer 0==writeto1_read0 is actually
* interested in. Ignored when 1==writeto1_read0 .
* @length: maximum (or actual) extent of buffer
* @host_no: host number of interest (Scsi_Host::host_no)
* @host_no: host number of interest (struct Scsi_Host::host_no)
* @writeto1_read0: 1 -> data coming from user space towards driver
* (e.g. "echo some_string > /proc/scsi/xyz/2")
* 0 -> user what data from this driver
......@@ -314,13 +339,13 @@ int proc_info(char * buffer, char ** start, off_t offset,
* Returns 1 if the adapter (host) is busy, else returns 0. One
* reason for an adapter to be busy is that the number
* of outstanding queued commands is already equal to
* Scsi_Host::can_queue .
* struct Scsi_Host::can_queue .
*
* Required: if Scsi_Host::can_queue is ever non-zero
* Required: if struct Scsi_Host::can_queue is ever non-zero
* then this function is required.
*
* Locks: Scsi_Host::host_lock held on entry (with "irqsave") and
* is expected to be held on return.
* Locks: struct Scsi_Host::host_lock held on entry (with "irqsave")
* and is expected to be held on return.
*
* Notes: This function should be relatively fast. Normally it will
* not wait for IO to complete. Hence the 'done' callback is invoked
......@@ -336,9 +361,11 @@ int proc_info(char * buffer, char ** start, off_t offset,
* returns.
* If a status of CHECK CONDITION is placed in "result" when the
* 'done' callback is invoked, then the lower level driver should
* perform autosense and fill in the Scsi_Cmnd::sense_buffer array.
* perform autosense and fill in the struct scsi_cmnd::sense_buffer
* array.
**/
int queuecommand(Scsi_Cmnd * scp, void (*done)(Scsi_Cmnd *));
int queuecommand(struct scsi_cmnd * scp,
void (*done)(struct scsi_cmnd *));
/**
......@@ -358,6 +385,7 @@ int proc_info(char * buffer, char ** start, off_t offset,
**/
int release(struct Scsi_Host * shp);
/**
* select_queue_depths - calculate allowable number of scsi commands
* that can be queued on each device (disk)
......@@ -373,16 +401,64 @@ int proc_info(char * buffer, char ** start, off_t offset,
*
* Notes: This function should examine all devices on the given host.
* The next device can be fetched with sdp->next (NULL when finished).
* Queue depths should be placed in Scsi_Device::queue_depth .
* Queue depths should be placed in struct scsi_device::queue_depth .
**/
void select_queue_depths(struct Scsi_Host * shp, struct scsi_device * sdp);
/**
* slave_attach - driver fine tuning for give device just after it
* has been first scan (i.e. it responded to an
* INQUIRY)
* @sdp: device that has just been attached
*
* Returns 0 if ok. Any other return is assumed to be an error and
* the device is taken offline.
*
* Required: no
*
* Locks: none
*
* Notes: Allows the driver to inspect the response to the initial
* INQUIRY done by the scanning code and take appropriate action.
* For more details see the hosts.h file.
* If this function is not supplied, the mid level will call
* scsi_adjust_queue_depth() with the struct Scsi_Host::cmd_per_lun
* value on behalf of the given device. If this function is
* supplied then its implementation is expected to call
* scsi_adjust_queue_depth().
**/
void select_queue_depths(struct Scsi_Host * shp, Scsi_Device * sdp);
int slave_attach(struct scsi_device *sdp);
/**
* slave_detach - given device is about to be shut down. No further
* commands will be sent.
* @sdp: device that is about to be detached
*
* Returns nothing
*
* Required: no
*
* Locks: none
*
* Notes: Mid level structures for given device are still in place
* but are about to be torn down. Any per device resources allocated
* by this driver for given device should be freed now. No further
* commands will be sent for this sdp instance. [However the device
* could be re-attached in the future in which case a new instance
* of struct scsi_device would be supplied by a future slave_attach()
* call.]
**/
void slave_detach(struct scsi_device *sdp);
Data Structures
===============
Scsi_Host_Template
------------------
There is one Scsi_Host_Template instance per lower level driver. It is
struct SHT
----------
There is one "struct SHT" instance per lower level driver ***. It is
typically initialized as a file scope static in a driver's header file. That
way members that are not explicitly initialized will be set to 0 or NULL.
Member of interest:
......@@ -391,19 +467,23 @@ Member of interest:
proc_name - name used in "/proc/scsi/<proc_name>/<host_no>"
The structure is defined and commented in hosts.h
Scsi_Host
---------
There is one Scsi_Host instance per host (HBA) that a lower level driver
controls. The Scsi_Host structure has many members in common with the
Scsi_Host_Template. When a new Scsi_Host instance is created (in
*** In extreme situations a single driver may have several instances
if it controls several different classes of hardware (e.g. the
advansys driver handles both ISA and PCI cards).
struct Scsi_Host
----------------
There is one struct Scsi_Host instance per host (HBA) that a lower level
driver controls. The struct Scsi_Host structure has many members in common
with "struct SHT". When a new struct Scsi_Host instance is created (in
scsi_register() in hosts.c) those common members are initialized from
the driver's Scsi_Host_Template instance. Members of interest:
the driver's struct SHT instance. Members of interest:
host_no - system wide unique number that is used for identifying
this host. Issued in ascending order from 0 (and the
positioning can be influenced by the scsihosts
kernel boot (or module) parameter)
can_queue - 0->use command(), greater than 0->use queuecommand() and do
not send more than can_queue commands to the adapter.
can_queue - 0->use command(), greater than 0->use queuecommand() and
do not send more than can_queue commands to the adapter.
this_id - scsi id of host (scsi initiator) or -1 if not known
sg_tablesize - maximum scatter gather elements allowed by host.
0 implies scatter gather not supported by host
......@@ -419,25 +499,26 @@ the driver's Scsi_Host_Template instance. Members of interest:
0->disallow scsi command merging
highmem_io - 1->can DMA in to or out of high memory,
0->use bounce buffers if data is in high memory
hostt - pointer to driver's Scsi_Host_Template from which this
Scsi_Host instance was spawned
hostt - pointer to driver's struct SHT from which this
struct Scsi_Host instance was spawned
host_queue - deceptively named pointer to the start of a double linked
list of Scsi_Device instances that belong to this host.
list of struct scsi_device instances that belong to this
host.
The structure is defined in hosts.h
Scsi_Device
-----------
struct scsi_device
------------------
Generally, there is one instance of this structure for each scsi logical unit
on a host. Scsi devices are uniquely identified within a host by bus number,
target id and logical unit number (lun).
The structure is defined in scsi.h
Scsi_Cmnd
---------
struct scsi_cmnd
----------------
Instances of this structure convey scsi commands to the lower level
driver. Each scsi device has a pool of Scsi_Cmnd instances whose size
is determined by select_queue_depths (or Scsi_Host::cmd_per_lun). There
will be at least one instance of Scsi_Cmnd for each scsi device.
driver. Each scsi device has a pool of struct scsi_cmnd instances whose size
is determined by select_queue_depths (or struct Scsi_Host::cmd_per_lun).
There will be at least one instance of struct scsi_cmnd for each scsi device.
The structure is defined in scsi.h
......@@ -474,14 +555,14 @@ Notes
Locks
=====
Each Scsi_Host instance has a spin_lock called Scsi_Host::default_lock
which is initialized in scsi_register() [found in hosts.c]. Within the
same function the Scsi_Host::host_lock pointer is initialized to point
at default_lock with the scsi_assign_lock() function. Thereafter
lock and unlock operations performed by the mid level use the
Scsi_Host::host_lock pointer.
Lower level drivers can override the use of Scsi_Host::default_lock by
Each struct Scsi_Host instance has a spin_lock called struct
Scsi_Host::default_lock which is initialized in scsi_register() [found in
hosts.c]. Within the same function the struct Scsi_Host::host_lock pointer
is initialized to point at default_lock with the scsi_assign_lock() function.
Thereafter lock and unlock operations performed by the mid level use the
struct Scsi_Host::host_lock pointer.
Lower level drivers can override the use of struct Scsi_Host::default_lock by
using scsi_assign_lock(). The earliest opportunity to do this would
be in the detect() function after it has invoked scsi_register(). It
could be replaced by a coarser grain lock (e.g. per driver) or a
......@@ -501,7 +582,7 @@ done when the lower level driver detects a CHECK CONDITION status by either:
b) or, the lower level driver issuing a REQUEST SENSE command itself
Either way, the mid level decides whether the lower level driver has
performed autosense by checking Scsi_Cmnd::sense_buffer[0] . If this
performed autosense by checking struct scsi_cmnd::sense_buffer[0] . If this
byte has an upper nibble of 7 then autosense is assumed to have taken
place. If it has another value (and this byte is initialized to 0 before
each command) then the mid level will issue a REQUEST SENSE command.
......@@ -515,12 +596,12 @@ level driver to perform autosense.
Changes since lk 2.4 series
===========================
io_request_lock has been replaced by several finer grained locks. The lock
relevant to lower level drivers is Scsi_Host::host_lock and there is one
per scsi host.
relevant to lower level drivers is struct Scsi_Host::host_lock and there is
one per scsi host.
The older error handling mechanism has been removed. This means the
lower level interface functions abort() and reset() have been removed.
The Scsi_Host_Template::use_new_eh_code flag has been removed.
The struct SHT::use_new_eh_code flag has been removed.
In the 2.4 series the scsi subsystem configuration descriptions were
aggregated with the configuration descriptions from all other Linux
......@@ -528,6 +609,8 @@ subsystems in the Documentation/Configure.help file. In the 2.5 series,
the scsi subsystem now has its own (much smaller) drivers/scsi/Config.help
file.
Addition of slave_attach() and slave_detach().
Credits
=======
......@@ -539,4 +622,4 @@ The following people have contributed to this document:
Douglas Gilbert
dgilbert@interlog.com
13th August 2002
8th November 2002
......@@ -1478,8 +1478,6 @@ static int scsi_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew,
* function */
sdev->max_device_blocked = SCSI_DEFAULT_DEVICE_BLOCKED;
scsi_detect_device(sdev);
if (sdevnew != NULL)
*sdevnew = sdev;
......
......@@ -94,7 +94,6 @@ static void sd_init_onedisk(struct scsi_disk * sdkp, struct gendisk *disk);
static void sd_rw_intr(struct scsi_cmnd * SCpnt);
static int sd_attach(struct scsi_device *);
static int sd_detect(struct scsi_device *);
static void sd_detach(struct scsi_device *);
static int sd_init_command(struct scsi_cmnd *);
static int sd_synchronize_cache(struct scsi_disk *, int);
......@@ -107,7 +106,6 @@ static struct Scsi_Device_Template sd_template = {
.name = "disk",
.tag = "sd",
.scsi_type = TYPE_DISK,
.detect = sd_detect,
.attach = sd_attach,
.detach = sd_detach,
.init_command = sd_init_command,
......@@ -758,7 +756,6 @@ static void
sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
struct scsi_request *SRpnt, unsigned char *buffer) {
unsigned char cmd[10];
struct scsi_device *sdp = sdkp->device;
unsigned long spintime_value = 0;
int the_result, retries, spintime;
......@@ -1165,23 +1162,6 @@ sd_init_onedisk(struct scsi_disk * sdkp, struct gendisk *disk)
kfree(buffer);
}
/**
* sd_detect - called at the start of driver initialization, once
* for each scsi device (not just disks) present.
*
* Returns 0 if not interested in this scsi device (e.g. scanner);
* 1 if this device is of interest (e.g. a disk).
*
* Note: this function is invoked from the scsi mid-level.
**/
static int sd_detect(struct scsi_device * sdp)
{
SCSI_LOG_HLQUEUE(3, printk("sd_detect: type=%d\n", sdp->type));
if (sdp->type != TYPE_DISK && sdp->type != TYPE_MOD)
return 0;
return 1;
}
/**
* sd_attach - called during driver initialization and whenever a
* new scsi device is attached to the system. It is called once
......
......@@ -111,7 +111,6 @@ static int sg_allow_dio = SG_ALLOW_DIO_DEF;
#define SG_DEV_ARR_LUMP 6 /* amount to over allocate sg_dev_arr by */
static int sg_attach(Scsi_Device *);
static int sg_detect(Scsi_Device *);
static void sg_detach(Scsi_Device *);
static Scsi_Request *dummy_cmdp; /* only used for sizeof */
......@@ -124,7 +123,6 @@ static struct Scsi_Device_Template sg_template = {
.name = "generic",
.tag = "sg",
.scsi_type = 0xff,
.detect = sg_detect,
.attach = sg_attach,
.detach = sg_detach
};
......@@ -233,7 +231,6 @@ static int sg_last_dev(void);
#endif
static Sg_device **sg_dev_arr = NULL;
static int sg_dev_noticed;
static int sg_dev_max;
static int sg_nr_dev;
......@@ -1338,13 +1335,6 @@ static struct file_operations sg_fops = {
.fasync = sg_fasync,
};
static int
sg_detect(Scsi_Device * scsidp)
{
sg_dev_noticed++;
return 1;
}
#ifndef MODULE
static int __init
sg_def_reserved_size_setup(char *str)
......@@ -1563,7 +1553,6 @@ sg_detach(Scsi_Device * scsidp)
}
scsi_slave_detach(scsidp);
sg_nr_dev--;
sg_dev_noticed--; /* from <dan@lectra.fr> */
break;
}
write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
......
......@@ -66,7 +66,6 @@ MODULE_PARM(xa_test, "i"); /* see sr_ioctl.c */
CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_GENERIC_PACKET)
static int sr_attach(struct scsi_device *);
static int sr_detect(struct scsi_device *);
static void sr_detach(struct scsi_device *);
static int sr_init_command(struct scsi_cmnd *);
......@@ -75,7 +74,6 @@ static struct Scsi_Device_Template sr_template = {
.name = "cdrom",
.tag = "sr",
.scsi_type = TYPE_ROM,
.detect = sr_detect,
.attach = sr_attach,
.detach = sr_detach,
.init_command = sr_init_command
......@@ -489,14 +487,6 @@ static int sr_open(struct cdrom_device_info *cdi, int purpose)
return 0;
}
static int sr_detect(struct scsi_device * SDp)
{
if (SDp->type != TYPE_ROM && SDp->type != TYPE_WORM)
return 0;
return 1;
}
static int sr_attach(struct scsi_device *sdev)
{
struct gendisk *disk;
......
......@@ -170,7 +170,6 @@ static int sgl_map_user_pages(struct scatterlist *, const unsigned int,
static int sgl_unmap_user_pages(struct scatterlist *, const unsigned int, int);
static int st_attach(Scsi_Device *);
static int st_detect(Scsi_Device *);
static void st_detach(Scsi_Device *);
static struct Scsi_Device_Template st_template = {
......@@ -178,7 +177,6 @@ static struct Scsi_Device_Template st_template = {
.name = "tape",
.tag = "st",
.scsi_type = TYPE_TAPE,
.detect = st_detect,
.attach = st_attach,
.detach = st_detach
};
......@@ -3885,13 +3883,6 @@ static int st_attach(Scsi_Device * SDp)
return 0;
};
static int st_detect(Scsi_Device * SDp)
{
if (SDp->type != TYPE_TAPE || st_incompatible(SDp))
return 0;
return 1;
}
static void st_detach(Scsi_Device * SDp)
{
Scsi_Tape *tpnt;
......
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