Commit 8b0f29fb authored by Linus Torvalds's avatar Linus Torvalds

Merge http://linux-scsi.bkbits.net/scsi-for-linus-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 227b2020 6fe854d9
......@@ -22,13 +22,28 @@ has its own PCI device address. [The one-to-one correspondance between
a SCSI host and a PCI device is common but not required (e.g. with
ISA or MCA adapters).]
This version of the document roughly matches linux kernel version 2.5.63 .
Documentation
=============
There is a SCSI documentation directory within the kernel source tree.
That directory is typically /usr/src/linux/Documentation/scsi . Most
documents are in plain (i.e. ASCII) text. This file can be found in that
directory, named scsi_mid_low_api.txt . Many LLDs are documented there
(e.g. aic7xxx.txt). The SCSI mid-level is briefly described in scsi.txt
(with a url to a document describing the SCSI subsystem in the lk 2.4
series). Two upper level drivers have documents in that directory:
st.txt (SCSI tape driver) and scsi-generic.txt .
Some documentation (or urls) for LLDs may be in the C source code or
in the same directory. For example to find a url about the USB mass
storage driver see the /usr/src/linux/drivers/usb/storage directory.
The Linux kernel source Documentation/DocBook/scsidrivers.tmpl file
refers to this file. With the appropriate DocBook toolset, this permits
users to generate html, ps and pdf renderings of information within this
file (e.g. the interface functions).
This version of the document roughly matches lk 2.5.50 .
Driver structure
================
Traditionally a LLD for the SCSI subsystem has been at least two files in
......@@ -100,12 +115,11 @@ the stability of the kernel (specifically the block and SCSI subsystems)
since the effected disk can be "cleaned up" the next time it is seen.
During LLD initialization the driver should register itself with the
appropriate IO bus that it expects to find HBA(s) (e.g. the PCI bus). This
can probably be done via sysfs (formerly known as driverfs). Any driver
parameters (especially those that are writeable after the driver is
loaded) could also be registered with sysfs at this point. At the end of
driver initialization the SCSI mid level is typically not aware of its
presence.
appropriate IO bus on which it expects to find HBA(s) (e.g. the PCI bus).
This can probably be done via sysfs. Any driver parameters (especially
those that are writeable after the driver is loaded) could also be
registered with sysfs at this point. At the end of driver initialization
the SCSI mid level is typically not aware of its presence.
At some later time, the LLD becomes aware of a HBA and what follows
is a typical sequence of calls between the LLD and the mid level.
......@@ -149,7 +163,7 @@ It is practical for a LLD to keep track of struct Scsi_Host instances
(a pointer is returned by scsi_register() ) and struct scsi_device
instances (a pointer is passed as the parameter to slave_alloc() and
slave_configure() ). Both classes of instances are "owned" by the
mid-level. struct scsi_devices instances are freed after slave_destroy().
mid-level. struct scsi_device instances are freed after slave_destroy().
struct Scsi_Host instances are freed after scsi_unregister().
......@@ -249,6 +263,8 @@ names all start with "scsi_".
/**
* scsi_add_host - perform sysfs registration and SCSI bus scan.
* @shost: pointer to scsi host instance
* @dev: pointer to struct device host instance of class type scsi
* (or related)
*
* Returns 0 on success, negative errno of failure (e.g. -ENOMEM)
*
......@@ -256,7 +272,24 @@ names all start with "scsi_".
* successful call to scsi_register().
* Defined in drivers/scsi/hosts.c
**/
int scsi_add_host(struct Scsi_Host *shost)
int scsi_add_host(struct Scsi_Host *shost, struct device * dev)
/**
* scsi_add_timer - (re-)start timer on a SCSI command.
* @scmd: pointer to scsi command instance
* @timeout: duration of timeout in "jiffies"
* @complete: pointer to function to call if timeout expires
*
* Returns nothing
*
* Notes: All commands issued by upper levels already have a timeout
* associated with them. A LLD can use this function to change
* the existing timeout value.
* Defined in drivers/scsi/scsi_error.c
**/
void scsi_add_timer(Scsi_Cmnd *scmd, int timeout, void (*complete)
(Scsi_Cmnd *))
/**
......@@ -321,6 +354,21 @@ unsigned char *scsi_bios_ptable(struct block_device *dev)
void scsi_block_requests(struct Scsi_Host * SHpnt)
/**
* scsi_delete_timer - cancel timer on a SCSI command.
* @scmd: pointer to scsi command instance
*
* Returns 1 if able to cancel timer else 0 (i.e. too late or already
* cancelled).
*
* Notes: All commands issued by upper levels already have a timeout
* associated with them. A LLD can use this function to cancel the
* timer.
* Defined in drivers/scsi/scsi_error.c
**/
int scsi_delete_timer(Scsi_Cmnd *scmd)
/**
* scsi_partsize - parse partition table into cylinders, heads + sectors
* @buf: pointer to partition table
......@@ -429,6 +477,26 @@ void scsi_set_device(struct Scsi_Host * shost, struct device * dev)
int scsi_to_pci_dma_dir(unsigned char scsi_data_direction)
/**
* scsi_track_queue_full - track successive QUEUE_FULL events on given
* device to determine if and when there is a need
* to adjust the queue depth on the device.
* @SDptr: pointer to SCSI device instance
* @depth: Current number of outstanding SCSI commands on this device,
* not counting the one returned as QUEUE_FULL.
*
* Returns 0 - no change needed
* >0 - adjust queue depth to this new depth
* -1 - drop back to untagged operation using host->cmd_per_lun
* as the untagged command depth
*
* Notes: LLDs may call this at any time and we will do "The Right
* Thing"; interrupt context safe.
* Defined in drivers/scsi/scsi.c .
**/
int scsi_track_queue_full(Scsi_Device *SDptr, int depth)
/**
* scsi_unblock_requests - allow further commands to be queued to given host
*
......@@ -1008,4 +1076,4 @@ The following people have contributed to this document:
Douglas Gilbert
dgilbert@interlog.com
29th November 2002
21st February 2003
......@@ -122,6 +122,7 @@
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <asm/dma.h>
......@@ -325,6 +326,7 @@ NCR_700_detect(Scsi_Host_Template *tpnt,
host->max_lun = NCR_700_MAX_LUNS;
host->unique_id = hostdata->base;
host->base = hostdata->base;
hostdata->eh_complete = NULL;
host->hostdata[0] = (unsigned long)hostdata;
/* kick the chip */
NCR_700_writeb(0xff, host, CTEST9_REG);
......@@ -1525,6 +1527,9 @@ NCR_700_intr(int irq, void *dev_id, struct pt_regs *regs)
hostdata->state = NCR_700_HOST_FREE;
hostdata->cmd = NULL;
/* signal back if this was an eh induced reset */
if(hostdata->eh_complete != NULL)
complete(hostdata->eh_complete);
goto out_unlock;
} else if(sstat0 & SELECTION_TIMEOUT) {
DEBUG(("scsi%d: (%d:%d) selection timeout\n",
......@@ -1949,10 +1954,27 @@ NCR_700_abort(Scsi_Cmnd * SCp)
STATIC int
NCR_700_bus_reset(Scsi_Cmnd * SCp)
{
DECLARE_COMPLETION(complete);
struct NCR_700_Host_Parameters *hostdata =
(struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0];
printk(KERN_INFO "scsi%d (%d:%d) New error handler wants BUS reset, cmd %p\n\t",
SCp->device->host->host_no, SCp->device->id, SCp->device->lun, SCp);
print_command(SCp->cmnd);
/* In theory, eh_complete should always be null because the
* eh is single threaded, but just in case we're handling a
* reset via sg or something */
while(hostdata->eh_complete != NULL) {
spin_unlock_irq(SCp->device->host->host_lock);
schedule_timeout(HZ/10);
spin_lock_irq(SCp->device->host->host_lock);
}
hostdata->eh_complete = &complete;
NCR_700_internal_bus_reset(SCp->device->host);
spin_unlock_irq(SCp->device->host->host_lock);
wait_for_completion(&complete);
spin_lock_irq(SCp->device->host->host_lock);
hostdata->eh_complete = NULL;
return SUCCESS;
}
......
......@@ -136,38 +136,6 @@ NCR_700_clear_flag(Scsi_Device *SDp, __u32 flag)
((unsigned long)SDp->hostdata) &= ~(flag & 0xffff0000);
}
/* These represent the Nexus hashing functions. A Nexus in SCSI terms
* just means the identification of an outstanding command, by ITL
* (Initiator Target Lun) or ITLQ (Initiator Target Lun Tag). I'm not
* very keen on XOR based hashes, so these are based on number theory
* instead. All you need to do is to fix your hash bucket size and
* then choose reasonable strides which are coprime with the chosen
* bucket size
*
* Note: this mathematical hash can be made very efficient, if the
* compiler is good at optimising: Choose the number of buckets to be
* 2^n and the modulo becomes a logical and with (2^n-1).
* Additionally, if you chose the coprimes of the form 2^n-2^n the
* multiplication can be done by a shift and an addition. */
#define MAX_ITL_HASH_BUCKETS 16
#define ITL_HASH_PRIME 7
#define MAX_ITLQ_HASH_BUCKETS 64
#define ITLQ_PUN_PRIME 7
#define ITLQ_LUN_PRIME 3
static inline int
hash_ITL(__u8 pun, __u8 lun)
{
return (pun*ITL_HASH_PRIME + lun) % MAX_ITL_HASH_BUCKETS;
}
static inline int
hash_ITLQ(__u8 pun, __u8 lun, __u8 tag)
{
return (pun*ITLQ_PUN_PRIME + lun*ITLQ_LUN_PRIME + tag) % MAX_ITLQ_HASH_BUCKETS;
}
struct NCR_700_command_slot {
struct NCR_700_SG_List SG[NCR_700_SG_SEGMENTS+1];
struct NCR_700_SG_List *pSG;
......@@ -186,12 +154,8 @@ struct NCR_700_command_slot {
/* if this command is a pci_single mapping, holds the dma address
* for later unmapping in the done routine */
dma_addr_t dma_handle;
/* Doubly linked ITL/ITLQ list kept in strict time order
* (latest at the back) */
/* historical remnant, now used to link free commands */
struct NCR_700_command_slot *ITL_forw;
struct NCR_700_command_slot *ITL_back;
struct NCR_700_command_slot *ITLQ_forw;
struct NCR_700_command_slot *ITLQ_back;
};
struct NCR_700_Host_Parameters {
......@@ -238,20 +202,15 @@ struct NCR_700_Host_Parameters {
__u8 tag_negotiated;
__u8 rev;
__u8 reselection_id;
/* flags for the host */
/* ITL list. ALL outstanding commands are hashed here in strict
* order, latest at the back */
struct NCR_700_command_slot *ITL_Hash_forw[MAX_ITL_HASH_BUCKETS];
struct NCR_700_command_slot *ITL_Hash_back[MAX_ITL_HASH_BUCKETS];
/* Only tagged outstanding commands are hashed here (also latest
* at the back) */
struct NCR_700_command_slot *ITLQ_Hash_forw[MAX_ITLQ_HASH_BUCKETS];
struct NCR_700_command_slot *ITLQ_Hash_back[MAX_ITLQ_HASH_BUCKETS];
/* Free list, singly linked by ITL_forw elements */
struct NCR_700_command_slot *free_list;
/* Completion for waited for ops, like reset, abort or
* device reset.
*
* NOTE: relies on single threading in the error handler to
* have only one outstanding at once */
struct completion *eh_complete;
};
/*
......
......@@ -129,6 +129,7 @@ config SCSI_MULTI_LUN
config SCSI_REPORT_LUNS
bool "Build with SCSI REPORT LUNS support"
depends on SCSI
default y
help
If you want to build with SCSI REPORT LUNS support in the kernel, say Y here.
The REPORT LUNS command is useful for devices (such as disk arrays) with
......
......@@ -1228,7 +1228,6 @@ static int port_detect \
sh[j]->unchecked_isa_dma = FALSE;
else {
unsigned long flags;
scsi_register_blocked_host(sh[j]);
sh[j]->unchecked_isa_dma = TRUE;
flags=claim_dma_lock();
......@@ -2353,8 +2352,6 @@ static int eata2x_release(struct Scsi_Host *shpnt) {
if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n",
driver_name);
if(sh[j]->unchecked_isa_dma) scsi_deregister_blocked_host(sh[j]);
for (i = 0; i < sh[j]->can_queue; i++)
if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist);
......
......@@ -46,10 +46,7 @@
* last change: 2002/11/02 OS: Linux 2.5.45 *
************************************************************/
/* Look in eata_pio.h for configuration information */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
......@@ -59,15 +56,19 @@
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include "eata_pio.h"
#include "eata_dma_proc.h"
#include "scsi.h"
#include <linux/stat.h>
#include <linux/config.h> /* for CONFIG_PCI */
#include <linux/config.h>
#include <linux/blk.h>
#include <linux/spinlock.h>
#include <asm/io.h>
#include "scsi.h"
#include "hosts.h"
#include <scsi/scsicam.h>
#include "eata_generic.h"
#include "eata_pio.h"
static uint ISAbases[MAXISA] = {
0x1F0, 0x170, 0x330, 0x230
......@@ -82,16 +83,106 @@ static unsigned char EISAbases[] = {
1, 1, 1, 1, 1, 1, 1, 1
};
static uint registered_HBAs = 0;
static uint registered_HBAs;
static struct Scsi_Host *last_HBA;
static struct Scsi_Host *first_HBA;
static unsigned char reg_IRQ[];
static unsigned char reg_IRQL[];
static unsigned char reg_IRQ[16];
static unsigned char reg_IRQL[16];
static unsigned long int_counter;
static unsigned long queue_counter;
static unsigned long int_counter = 0;
static unsigned long queue_counter = 0;
/*
* eata_proc_info
* inout : decides on the direction of the dataflow and the meaning of the
* variables
* buffer: If inout==FALSE data is being written to it else read from it
* *start: If inout==FALSE start of the valid data in the buffer
* offset: If inout==FALSE offset from the beginning of the imaginary file
* from which we start writing into the buffer
* length: If inout==FALSE max number of bytes to be written into the buffer
* else number of bytes in the buffer
*/
static int eata_pio_proc_info(char *buffer, char **start, off_t offset,
int length, int hostno, int rw)
{
struct Scsi_Host *shost;
struct scsi_device *sdev;
static u8 buff[512];
int size, len = 0;
off_t begin = 0, pos = 0;
if (rw)
return -ENOSYS;
shost = scsi_host_hn_get(hostno);
if (!shost)
return -EINVAL;
if (offset == 0)
memset(buff, 0, sizeof(buff));
#include "eata_pio_proc.c"
size = sprintf(buffer+len, "EATA (Extended Attachment) PIO driver version: "
"%d.%d%s\n",VER_MAJOR, VER_MINOR, VER_SUB);
len += size; pos = begin + len;
size = sprintf(buffer + len, "queued commands: %10ld\n"
"processed interrupts:%10ld\n", queue_counter, int_counter);
len += size; pos = begin + len;
size = sprintf(buffer + len, "\nscsi%-2d: HBA %.10s\n",
shost->host_no, SD(shost)->name);
len += size;
pos = begin + len;
size = sprintf(buffer + len, "Firmware revision: v%s\n",
SD(shost)->revision);
len += size;
pos = begin + len;
size = sprintf(buffer + len, "IO: PIO\n");
len += size;
pos = begin + len;
size = sprintf(buffer + len, "Base IO : %#.4x\n", (u32) shost->base);
len += size;
pos = begin + len;
size = sprintf(buffer + len, "Host Bus: %s\n",
(SD(shost)->bustype == 'P')?"PCI ":
(SD(shost)->bustype == 'E')?"EISA":"ISA ");
len += size;
pos = begin + len;
if (pos < offset) {
len = 0;
begin = pos;
}
if (pos > offset + length)
goto stop_output;
size = sprintf(buffer+len,"Attached devices: %s\n",
(!list_empty(&shost->my_devices))?"":"none");
len += size;
pos = begin + len;
list_for_each_entry(sdev, &shost->my_devices, siblings) {
proc_print_scsidevice(sdev, buffer, &size, len);
len += size;
pos = begin + len;
if (pos < offset) {
len = 0;
begin = pos;
}
if (pos > offset + length)
goto stop_output;
}
stop_output:
DBG(DBG_PROC, printk("2pos: %ld offset: %ld len: %d\n", pos, offset, len));
*start=buffer+(offset-begin); /* Start of wanted data */
len-=(offset-begin); /* Start slop */
if(len>length)
len = length; /* Ending slop */
DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len));
return (len);
}
static int eata_pio_release(struct Scsi_Host *sh)
{
......@@ -895,27 +986,19 @@ static int eata_pio_detect(Scsi_Host_Template * tpnt)
return (registered_HBAs);
}
/* Eventually this will go into an include file, but this will be later */
static Scsi_Host_Template driver_template = EATA_PIO;
static Scsi_Host_Template driver_template = {
.proc_info = eata_pio_proc_info,
.name = "EATA (Extended Attachment) PIO driver",
.detect = eata_pio_detect,
.release = eata_pio_release,
.queuecommand = eata_pio_queue,
.eh_abort_handler = eata_pio_abort,
.eh_host_reset_handler = eata_pio_host_reset,
.use_clustering = ENABLE_CLUSTERING,
};
#include "scsi_module.c"
MODULE_AUTHOR("Michael Neuffer, Alfred Arnold");
MODULE_DESCRIPTION("EATA SCSI PIO driver");
MODULE_LICENSE("GPL");
/*
* 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:
*/
#include "scsi_module.c"
......@@ -9,13 +9,6 @@
#ifndef _EATA_PIO_H
#define _EATA_PIO_H
#include <linux/blk.h>
#include "scsi.h"
#include "hosts.h"
#include <scsi/scsicam.h>
#include "eata_generic.h"
#define VER_MAJOR 0
#define VER_MINOR 0
#define VER_SUB "1b"
......@@ -57,22 +50,4 @@
#define DBG(x, y)
#endif
static int eata_pio_detect(Scsi_Host_Template *);
static int eata_pio_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
static int eata_pio_abort(Scsi_Cmnd *);
static int eata_pio_host_reset(Scsi_Cmnd *);
static int eata_pio_proc_info(char *, char **, off_t, int, int, int);
static int eata_pio_release(struct Scsi_Host *);
#define EATA_PIO { \
.proc_info = eata_pio_proc_info, /* procinfo */ \
.name = "EATA (Extended Attachment) PIO driver",\
.detect = eata_pio_detect, \
.release = eata_pio_release, \
.queuecommand = eata_pio_queue, \
.eh_abort_handler = eata_pio_abort, \
.eh_host_reset_handler = eata_pio_host_reset, \
.use_clustering = ENABLE_CLUSTERING \
}
#endif /* _EATA_PIO_H */
/*
* eata_set_info
* buffer : pointer to the data that has been written to the hostfile
* length : number of bytes written to the hostfile
* HBA_ptr: pointer to the Scsi_Host struct
*/
int eata_pio_set_info(char *buffer, int length, struct Scsi_Host *HBA_ptr)
{
DBG(DBG_PROC_WRITE, printk("%s\n", buffer));
return(-ENOSYS); /* Currently this is a no-op */
}
/*
* eata_proc_info
* inout : decides on the direction of the dataflow and the meaning of the
* variables
* buffer: If inout==FALSE data is being written to it else read from it
* *start: If inout==FALSE start of the valid data in the buffer
* offset: If inout==FALSE offset from the beginning of the imaginary file
* from which we start writing into the buffer
* length: If inout==FALSE max number of bytes to be written into the buffer
* else number of bytes in the buffer
*/
int eata_pio_proc_info(char *buffer, char **start, off_t offset, int length,
int hostno, int inout)
{
Scsi_Device *scd;
struct Scsi_Host *HBA_ptr;
static u8 buff[512];
int i;
int size, len = 0;
off_t begin = 0;
off_t pos = 0;
HBA_ptr = first_HBA;
for (i = 1; i <= registered_HBAs; i++) {
if (HBA_ptr->host_no == hostno)
break;
HBA_ptr = SD(HBA_ptr)->next;
}
if(inout == TRUE) /* Has data been written to the file ? */
return(eata_pio_set_info(buffer, length, HBA_ptr));
if (offset == 0)
memset(buff, 0, sizeof(buff));
size = sprintf(buffer+len, "EATA (Extended Attachment) PIO driver version: "
"%d.%d%s\n",VER_MAJOR, VER_MINOR, VER_SUB);
len += size; pos = begin + len;
size = sprintf(buffer + len, "queued commands: %10ld\n"
"processed interrupts:%10ld\n", queue_counter, int_counter);
len += size; pos = begin + len;
size = sprintf(buffer + len, "\nscsi%-2d: HBA %.10s\n",
HBA_ptr->host_no, SD(HBA_ptr)->name);
len += size;
pos = begin + len;
size = sprintf(buffer + len, "Firmware revision: v%s\n",
SD(HBA_ptr)->revision);
len += size;
pos = begin + len;
size = sprintf(buffer + len, "IO: PIO\n");
len += size;
pos = begin + len;
size = sprintf(buffer + len, "Base IO : %#.4x\n", (u32) HBA_ptr->base);
len += size;
pos = begin + len;
size = sprintf(buffer + len, "Host Bus: %s\n",
(SD(HBA_ptr)->bustype == 'P')?"PCI ":
(SD(HBA_ptr)->bustype == 'E')?"EISA":"ISA ");
len += size;
pos = begin + len;
if (pos < offset) {
len = 0;
begin = pos;
}
if (pos > offset + length)
goto stop_output;
size = sprintf(buffer+len,"Attached devices: %s\n",
(!list_empty(&HBA_ptr->my_devices))?"":"none");
len += size;
pos = begin + len;
list_for_each_entry(scd, &HBA_ptr->my_devices, siblings) {
proc_print_scsidevice(scd, buffer, &size, len);
len += size;
pos = begin + len;
if (pos < offset) {
len = 0;
begin = pos;
}
if (pos > offset + length)
goto stop_output;
}
stop_output:
DBG(DBG_PROC, printk("2pos: %ld offset: %ld len: %d\n", pos, offset, len));
*start=buffer+(offset-begin); /* Start of wanted data */
len-=(offset-begin); /* Start slop */
if(len>length)
len = length; /* Ending slop */
DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len));
return (len);
}
/*
* Overrides for Emacs so that we 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
* tab-width: 8
* End:
*/
......@@ -397,6 +397,7 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes)
spin_lock_init(&shost->default_lock);
scsi_assign_lock(shost, &shost->default_lock);
INIT_LIST_HEAD(&shost->my_devices);
INIT_LIST_HEAD(&shost->eh_cmd_q);
init_waitqueue_head(&shost->host_wait);
shost->dma_channel = 0xff;
......@@ -634,22 +635,9 @@ void scsi_host_busy_dec_and_test(struct Scsi_Host *shost, Scsi_Device *sdev)
spin_lock_irqsave(shost->host_lock, flags);
shost->host_busy--;
sdev->device_busy--;
if (shost->in_recovery && (shost->host_busy == shost->host_failed)) {
up(shost->eh_wait);
SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler"
" thread\n"));
}
spin_unlock_irqrestore(shost->host_lock, flags);
}
void scsi_host_failed_inc_and_test(struct Scsi_Host *shost)
{
unsigned long flags;
spin_lock_irqsave(shost->host_lock, flags);
shost->in_recovery = 1;
shost->host_failed++;
if (shost->host_busy == shost->host_failed) {
if (shost->in_recovery && shost->host_failed &&
(shost->host_busy == shost->host_failed))
{
up(shost->eh_wait);
SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler"
" thread\n"));
......
......@@ -384,6 +384,7 @@ struct Scsi_Host
spinlock_t default_lock;
spinlock_t *host_lock;
struct list_head eh_cmd_q;
struct task_struct * ehandler; /* Error recovery thread. */
struct semaphore * eh_wait; /* The error recovery thread waits on
this. */
......@@ -514,8 +515,6 @@ extern Scsi_Device * scsi_get_host_dev(struct Scsi_Host *);
extern void scsi_unblock_requests(struct Scsi_Host *);
extern void scsi_block_requests(struct Scsi_Host *);
extern void scsi_report_bus_reset(struct Scsi_Host *, int);
extern void scsi_register_blocked_host(struct Scsi_Host *);
extern void scsi_deregister_blocked_host(struct Scsi_Host *);
static inline void scsi_assign_lock(struct Scsi_Host *shost, spinlock_t *lock)
{
......@@ -587,7 +586,6 @@ extern void scsi_host_init(void);
*/
extern void scsi_host_busy_inc(struct Scsi_Host *, Scsi_Device *);
extern void scsi_host_busy_dec_and_test(struct Scsi_Host *, Scsi_Device *);
extern void scsi_host_failed_inc_and_test(struct Scsi_Host *);
/**
* scsi_find_device - find a device given the host
......
......@@ -287,7 +287,7 @@ int pluto_release(struct Scsi_Host *host)
struct pluto *pluto = (struct pluto *)host->hostdata;
fc_channel *fc = pluto->fc;
if (fc->module) __MOD_DEC_USE_COUNT(fc->module);
module_put(fc->module);
fc->fcp_register(fc, TYPE_SCSI_FCP, 1);
PLND((" releasing pluto.\n"));
......
......@@ -36,9 +36,6 @@
* out_of_space hacks, D. Gilbert (dpg) 990608
*/
#define REVISION "Revision: 1.00"
#define VERSION "Id: scsi.c 1.00 2000/09/26"
#include <linux/config.h>
#include <linux/module.h>
......@@ -790,13 +787,9 @@ static void scsi_softirq(struct softirq_action *h)
if ((status_byte(SCpnt->result) & CHECK_CONDITION) != 0) {
SCSI_LOG_MLCOMPLETE(3, print_sense("bh", SCpnt));
}
if (SCpnt->device->host->eh_wait != NULL) {
scsi_eh_eflags_set(SCpnt, SCSI_EH_CMD_FAILED | SCSI_EH_CMD_ERR);
SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
SCpnt->state = SCSI_STATE_FAILED;
scsi_host_failed_inc_and_test(SCpnt->device->host);
} else {
if (!scsi_eh_scmd_add(SCpnt, 0))
{
/*
* We only get here if the error
* recovery thread has died.
......@@ -1147,29 +1140,6 @@ int scsi_dev_info_list_add_str (char *dev_list)
return res;
}
/**
* scsi_dev_list_init: set up the dynamic device list.
* @dev_list: string of device flags to add
*
* Description:
* Add command line @dev_list entries, then add
* scsi_static_device_list entries to the scsi device info list.
**/
static void scsi_dev_info_list_init (char *dev_list)
{
int i;
if (scsi_dev_info_list_add_str(dev_list) == -ENOMEM)
return;
for (i = 0; scsi_static_device_list[i].vendor != NULL; i++)
if (scsi_dev_info_list_add(1 /* compatibile */,
scsi_static_device_list[i].vendor,
scsi_static_device_list[i].model,
NULL,
scsi_static_device_list[i].flags) == -ENOMEM)
return;
}
/**
* scsi_dev_info_list_delete: called from scsi.c:exit_scsi to remove
* the scsi_dev_info_list.
......@@ -1186,6 +1156,37 @@ static void scsi_dev_info_list_delete (void)
}
}
/**
* scsi_dev_list_init: set up the dynamic device list.
* @dev_list: string of device flags to add
*
* Description:
* Add command line @dev_list entries, then add
* scsi_static_device_list entries to the scsi device info list.
**/
static int scsi_dev_info_list_init (char *dev_list)
{
int error, i;
error = scsi_dev_info_list_add_str(dev_list);
if (error)
return error;
for (i = 0; scsi_static_device_list[i].vendor != NULL; i++) {
error = scsi_dev_info_list_add(1 /* compatibile */,
scsi_static_device_list[i].vendor,
scsi_static_device_list[i].model,
NULL,
scsi_static_device_list[i].flags);
if (error)
break;
}
if (error)
scsi_dev_info_list_delete();
return error;
}
/**
* get_device_flags - get device specific flags from the dynamic device
* list. Called during scan time.
......@@ -1298,6 +1299,44 @@ void scsi_device_put(struct scsi_device *sdev)
module_put(sdev->host->hostt->module);
}
/**
* scsi_set_device_offline - set scsi_device offline
* @sdev: pointer to struct scsi_device to offline.
*
* Locks: host_lock held on entry.
**/
void scsi_set_device_offline(struct scsi_device *sdev)
{
struct scsi_cmnd *scmd;
int cmds_active = 0;
unsigned long flags;
sdev->online = FALSE;
spin_lock_irqsave(&sdev->list_lock, flags);
list_for_each_entry(scmd, &sdev->cmd_list, list) {
if (scmd->request && scmd->request->rq_status != RQ_INACTIVE) {
/*
* If we are unable to remove the timer, it means
* that the command has already timed out or
* finished.
*/
if (!scsi_delete_timer(scmd)) {
continue;
}
++cmds_active;
scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD);
}
}
spin_unlock_irqrestore(&sdev->list_lock, flags);
if (!cmds_active) {
/* FIXME: Send online state change hotplug event */
}
}
/*
* Function: scsi_slave_attach()
*
......@@ -1437,17 +1476,38 @@ __setup("scsi_default_dev_flags=", setup_scsi_default_dev_flags);
#endif
/* FIXME(hch): add proper error handling */
static int __init init_scsi(void)
{
scsi_init_queue();
scsi_init_procfs();
devfs_mk_dir(NULL, "scsi", NULL);
int error;
error = scsi_init_queue();
if (error)
return error;
error = scsi_init_procfs();
if (error)
goto cleanup_queue;
error = scsi_dev_info_list_init(scsi_dev_flags);
if (error)
goto cleanup_procfs;
error = scsi_sysfs_register();
if (error)
goto cleanup_devlist;
scsi_host_init();
scsi_dev_info_list_init(scsi_dev_flags);
scsi_sysfs_register();
devfs_mk_dir(NULL, "scsi", NULL);
open_softirq(SCSI_SOFTIRQ, scsi_softirq, NULL);
printk(KERN_NOTICE "SCSI subsystem initialized\n");
return 0;
cleanup_devlist:
scsi_dev_info_list_delete();
cleanup_procfs:
scsi_exit_procfs();
cleanup_queue:
scsi_exit_queue();
printk(KERN_ERR "SCSI subsystem failed to initialize, error = %d\n",
-error);
return error;
}
static void __exit exit_scsi(void)
......
......@@ -455,6 +455,7 @@ extern int scsi_slave_attach(struct scsi_device *);
extern void scsi_slave_detach(struct scsi_device *);
extern int scsi_device_get(struct scsi_device *);
extern void scsi_device_put(struct scsi_device *);
extern void scsi_set_device_offline(struct scsi_device *);
extern void scsi_done(Scsi_Cmnd * SCpnt);
extern void scsi_finish_command(Scsi_Cmnd *);
extern int scsi_retry_command(Scsi_Cmnd *);
......@@ -726,6 +727,7 @@ struct scsi_cmnd {
struct list_head list; /* scsi_cmnd participates in queue lists */
struct list_head eh_entry; /* entry for the host eh_cmd_q */
int eh_state; /* Used for state tracking in error handlr */
int eh_eflags; /* Used by error handlr */
void (*done) (struct scsi_cmnd *); /* Mid-level done function */
......@@ -850,6 +852,7 @@ struct scsi_cmnd {
*/
#define SCSI_MLQUEUE_HOST_BUSY 0x1055
#define SCSI_MLQUEUE_DEVICE_BUSY 0x1056
#define SCSI_MLQUEUE_EH_RETRY 0x1057
/*
* old style reset request from external source
......@@ -960,13 +963,13 @@ static inline Scsi_Cmnd *scsi_find_tag(Scsi_Device *SDpnt, int tag) {
/*
* Scsi Error Handler Flags
*/
#define SCSI_EH_CMD_ERR 0x0001 /* Orig cmd error'd */
#define SCSI_EH_CMD_FAILED 0x0002 /* Orig cmd error type failed */
#define SCSI_EH_CMD_TIMEOUT 0x0004 /* Orig cmd error type timeout */
#define SCSI_EH_REC_TIMEOUT 0x0008 /* Recovery cmd timeout */
#define SCSI_EH_CANCEL_CMD 0x0001 /* Cancel this cmd */
#define SCSI_EH_REC_TIMEOUT 0x0002 /* EH retry timed out */
#define SCSI_SENSE_VALID(scmd) ((scmd->sense_buffer[0] & 0x70) == 0x70)
extern int scsi_eh_scmd_add(struct scsi_cmnd *, int);
int scsi_set_medium_removal(Scsi_Device *dev, char state);
extern int scsi_device_register(struct scsi_device *);
......
This diff is collapsed.
......@@ -117,7 +117,7 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
*/
if (reason == SCSI_MLQUEUE_HOST_BUSY)
host->host_blocked = host->max_host_blocked;
else
else if (reason == SCSI_MLQUEUE_DEVICE_BUSY)
device->device_blocked = device->max_device_blocked;
/*
......@@ -1340,23 +1340,6 @@ void scsi_report_bus_reset(struct Scsi_Host *shost, int channel)
}
}
/*
* FIXME(eric) - these are empty stubs for the moment. I need to re-implement
* host blocking from scratch. The theory is that hosts that wish to block
* will register/deregister using these functions instead of the old way
* of setting the wish_block flag.
*
* The details of the implementation remain to be settled, however the
* stubs are here now so that the actual drivers will properly compile.
*/
void scsi_register_blocked_host(struct Scsi_Host * shost)
{
}
void scsi_deregister_blocked_host(struct Scsi_Host * shost)
{
}
int __init scsi_init_queue(void)
{
int i;
......
......@@ -84,6 +84,7 @@ struct dev_info scsi_static_device_list[] __initdata = {
{"NEC", "CD-ROM DRIVE:841", "1.0", BLIST_NOLUN},/* locks up */
{"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN}, /* responds to all lun */
{"RODIME", "RO3000S", "2.33", BLIST_NOLUN}, /* locks up */
{"SUN", "SENA", NULL, BLIST_NOLUN}, /* responds to all luns */
/*
* The following causes a failed REQUEST SENSE on lun 1 for
* aha152x controller, which causes SCSI code to reset bus.
......@@ -128,6 +129,7 @@ struct dev_info scsi_static_device_list[] __initdata = {
{"MITSUMI", "CD-R CR-2201CS", "6119", BLIST_NOLUN}, /* locks up */
{"RELISYS", "Scorpio", NULL, BLIST_NOLUN}, /* responds to all lun */
{"MICROTEK", "ScanMaker II", "5.61", BLIST_NOLUN}, /* responds to all lun */
{"NEC", "D3856", "0009", BLIST_NOLUN},
/*
* Other types of devices that have special flags.
......
......@@ -74,12 +74,11 @@ EXPORT_SYMBOL(scsi_sleep);
EXPORT_SYMBOL(scsi_io_completion);
EXPORT_SYMBOL(scsi_register_blocked_host);
EXPORT_SYMBOL(scsi_deregister_blocked_host);
EXPORT_SYMBOL(scsi_slave_attach);
EXPORT_SYMBOL(scsi_slave_detach);
EXPORT_SYMBOL(scsi_device_get);
EXPORT_SYMBOL(scsi_device_put);
EXPORT_SYMBOL(scsi_set_device_offline);
/*
* This symbol is for the highlevel drivers (e.g. sg) only.
......
......@@ -14,6 +14,44 @@
#include "scsi.h"
#include "hosts.h"
/*
* shost_show_function: macro to create an attr function that can be used to
* show a non-bit field.
*/
#define shost_show_function(field, format_string) \
static ssize_t \
show_##field (struct device *dev, char *buf) \
{ \
struct Scsi_Host *shost = to_scsi_host(dev); \
return snprintf (buf, 20, format_string, shost->field); \
}
/*
* shost_rd_attr: macro to create a function and attribute variable for a
* read only field.
*/
#define shost_rd_attr(field, format_string) \
shost_show_function(field, format_string) \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL)
/*
* Create the actual show/store functions and data structures.
*/
shost_rd_attr(unique_id, "%u\n");
shost_rd_attr(host_busy, "%hu\n");
shost_rd_attr(cmd_per_lun, "%hd\n");
shost_rd_attr(sg_tablesize, "%hu\n");
shost_rd_attr(unchecked_isa_dma, "%d\n");
static struct device_attribute *const shost_attrs[] = {
&dev_attr_unique_id,
&dev_attr_host_busy,
&dev_attr_cmd_per_lun,
&dev_attr_sg_tablesize,
&dev_attr_unchecked_isa_dma,
};
/**
* scsi_host_class_name_show - copy out the SCSI host name
* @dev: device to check
......@@ -39,12 +77,21 @@ DEVICE_ATTR(class_name, S_IRUGO, scsi_host_class_name_show, NULL);
static int scsi_host_class_add_dev(struct device * dev)
{
int i;
device_create_file(dev, &dev_attr_class_name);
for (i = 0; i < ARRAY_SIZE(shost_attrs); i++)
device_create_file(dev, shost_attrs[i]);
return 0;
}
static void scsi_host_class_rm_dev(struct device * dev)
{
int i;
for (i = 0; i < ARRAY_SIZE(shost_attrs); i++)
device_remove_file(dev, shost_attrs[i]);
device_remove_file(dev, &dev_attr_class_name);
}
......@@ -129,10 +176,10 @@ void scsi_upper_driver_unregister(struct Scsi_Device_Template *sdev_tp)
/*
* show_function: macro to create an attr function that can be used to
* sdev_show_function: macro to create an attr function that can be used to
* show a non-bit field.
*/
#define show_function(field, format_string) \
#define sdev_show_function(field, format_string) \
static ssize_t \
show_##field (struct device *dev, char *buf) \
{ \
......@@ -146,7 +193,7 @@ show_##field (struct device *dev, char *buf) \
* read only field.
*/
#define sdev_rd_attr(field, format_string) \
show_function(field, format_string) \
sdev_show_function(field, format_string) \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL)
......@@ -155,27 +202,27 @@ static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL)
* read/write field.
*/
#define sdev_rw_attr(field, format_string) \
show_function(field, format_string) \
sdev_show_function(field, format_string) \
\
static ssize_t \
store_##field (struct device *dev, const char *buf, size_t count) \
sdev_store_##field (struct device *dev, const char *buf, size_t count) \
{ \
struct scsi_device *sdev; \
sdev = to_scsi_device(dev); \
snscanf (buf, 20, format_string, &sdev->field); \
return count; \
} \
static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, show_##field, store_##field)
static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, show_##field, sdev_store_##field)
/*
* sdev_rd_attr: create a function and attribute variable for a
* read/write bit field.
*/
#define sdev_rw_attr_bit(field) \
show_function(field, "%d\n") \
sdev_show_function(field, "%d\n") \
\
static ssize_t \
store_##field (struct device *dev, const char *buf, size_t count) \
sdev_store_##field (struct device *dev, const char *buf, size_t count) \
{ \
int ret; \
struct scsi_device *sdev; \
......@@ -187,7 +234,7 @@ store_##field (struct device *dev, const char *buf, size_t count) \
} \
return ret; \
} \
static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, show_##field, store_##field)
static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, show_##field, sdev_store_##field)
/*
* scsi_sdev_check_buf_bit: return 0 if buf is "0", return 1 if buf is "1",
......
......@@ -2689,18 +2689,6 @@ static int sg_proc_devstrs_read(char *buffer, char **start, off_t offset,
int size, int *eof, void *data);
static int sg_proc_devstrs_info(char *buffer, int *len, off_t * begin,
off_t offset, int size);
static int sg_proc_host_read(char *buffer, char **start, off_t offset,
int size, int *eof, void *data);
static int sg_proc_host_info(char *buffer, int *len, off_t * begin,
off_t offset, int size);
static int sg_proc_hosthdr_read(char *buffer, char **start, off_t offset,
int size, int *eof, void *data);
static int sg_proc_hosthdr_info(char *buffer, int *len, off_t * begin,
off_t offset, int size);
static int sg_proc_hoststrs_read(char *buffer, char **start, off_t offset,
int size, int *eof, void *data);
static int sg_proc_hoststrs_info(char *buffer, int *len, off_t * begin,
off_t offset, int size);
static int sg_proc_version_read(char *buffer, char **start, off_t offset,
int size, int *eof, void *data);
static int sg_proc_version_info(char *buffer, int *len, off_t * begin,
......@@ -2708,7 +2696,6 @@ static int sg_proc_version_info(char *buffer, int *len, off_t * begin,
static read_proc_t *sg_proc_leaf_reads[] = {
sg_proc_adio_read, sg_proc_dressz_read, sg_proc_debug_read,
sg_proc_dev_read, sg_proc_devhdr_read, sg_proc_devstrs_read,
sg_proc_host_read, sg_proc_hosthdr_read, sg_proc_hoststrs_read,
sg_proc_version_read
};
static write_proc_t *sg_proc_leaf_writes[] = {
......@@ -3033,81 +3020,6 @@ sg_proc_devstrs_info(char *buffer, int *len, off_t * begin,
return 1;
}
static int
sg_proc_host_read(char *buffer, char **start, off_t offset,
int size, int *eof, void *data)
{
SG_PROC_READ_FN(sg_proc_host_info);
}
static int
sg_proc_host_info(char *buffer, int *len, off_t * begin, off_t offset, int size)
{
struct Scsi_Host *shp;
int k;
for (k = 0, shp = scsi_host_get_next(NULL); shp;
shp = scsi_host_get_next(shp), ++k) {
for (; k < shp->host_no; ++k)
PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\n");
PRINT_PROC("%u\t%hu\t%hd\t%hu\t%d\t%d\n",
shp->unique_id, shp->host_busy, shp->cmd_per_lun,
shp->sg_tablesize, (int) shp->unchecked_isa_dma,
(int) shp->hostt->emulated);
}
return 1;
}
static int
sg_proc_hosthdr_read(char *buffer, char **start, off_t offset,
int size, int *eof, void *data)
{
SG_PROC_READ_FN(sg_proc_hosthdr_info);
}
static int
sg_proc_hosthdr_info(char *buffer, int *len, off_t * begin,
off_t offset, int size)
{
PRINT_PROC("uid\tbusy\tcpl\tscatg\tisa\temul\n");
return 1;
}
static int
sg_proc_hoststrs_read(char *buffer, char **start, off_t offset,
int size, int *eof, void *data)
{
SG_PROC_READ_FN(sg_proc_hoststrs_info);
}
#define SG_MAX_HOST_STR_LEN 256
static int
sg_proc_hoststrs_info(char *buffer, int *len, off_t * begin,
off_t offset, int size)
{
struct Scsi_Host *shp;
int k;
char buff[SG_MAX_HOST_STR_LEN];
char *cp;
for (k = 0, shp = scsi_host_get_next(NULL); shp;
shp = scsi_host_get_next(shp), ++k) {
for (; k < shp->host_no; ++k)
PRINT_PROC("<no active host>\n");
strncpy(buff, shp->hostt->info ? shp->hostt->info(shp) :
(shp->hostt->name ? shp->hostt->name : "<no name>"),
SG_MAX_HOST_STR_LEN);
buff[SG_MAX_HOST_STR_LEN - 1] = '\0';
for (cp = buff; *cp; ++cp) {
if ('\n' == *cp)
*cp = ' '; /* suppress imbedded newlines */
}
PRINT_PROC("%s\n", buff);
}
return 1;
}
static int
sg_proc_version_read(char *buffer, char **start, off_t offset,
int size, int *eof, void *data)
......
......@@ -328,7 +328,7 @@ struct eisa_driver sim710_eisa_driver = {
static int __init sim710_init(void)
{
int err = -ENODEV, err2;
int err = -ENODEV;
#ifdef MODULE
if (sim710)
......@@ -336,23 +336,17 @@ static int __init sim710_init(void)
#endif
#ifdef CONFIG_MCA
if (MCA_bus)
err = mca_register_driver(&sim710_mca_driver);
#endif
#ifdef CONFIG_EISA
err2 = eisa_driver_register(&sim710_eisa_driver);
/*
* The eise_driver_register return values are strange. I have
* no idea why we don't just use river_register directly anyway..
*/
if (err2 == 1)
err2 = 0;
err = eisa_driver_register(&sim710_eisa_driver);
#endif
/* FIXME: what we'd really like to return here is -ENODEV if
* no devices have actually been found. Instead, the err
* above actually only reports problems with kobject_register,
* so for the moment return success */
if (err < 0 || err2 < 0)
return (err < 0) ? err : err2;
return 0;
}
......
......@@ -905,7 +905,6 @@ static int port_detect \
}
else {
unsigned long flags;
scsi_register_blocked_host(sh[j]);
sh[j]->unchecked_isa_dma = TRUE;
flags=claim_dma_lock();
......@@ -1911,8 +1910,6 @@ static int u14_34f_release(struct Scsi_Host *shpnt) {
if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n",
driver_name);
if(sh[j]->unchecked_isa_dma) scsi_deregister_blocked_host(sh[j]);
for (i = 0; i < sh[j]->can_queue; i++)
if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist);
......
......@@ -158,6 +158,11 @@
* Clean up delay to udelay, and yielding sleeps
* Make host reset actually reset the card
* Make everything static
*
* 2003/02/12 - Christoph Hellwig <hch@infradead.org>
*
* Cleaned up host template defintion
* Removed now obsolete wd7000.h
*/
#include <linux/module.h>
......@@ -170,8 +175,8 @@
#include <linux/ioport.h>
#include <linux/proc_fs.h>
#include <linux/blk.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/stat.h>
#include <asm/system.h>
#include <asm/dma.h>
......@@ -179,9 +184,9 @@
#include "scsi.h"
#include "hosts.h"
#include <scsi/scsicam.h>
#define ANY2SCSI_INLINE /* undef this to use old macros */
#undef WD7000_DEBUG /* general debug */
#ifdef WD7000_DEBUG
......@@ -190,9 +195,6 @@
#define dprintk(format,args...)
#endif
#include "wd7000.h"
#include <linux/stat.h>
/*
* Mailbox structure sizes.
* I prefer to keep the number of ICMBs much larger than the number of
......@@ -211,6 +213,21 @@
*/
#define MAX_SCBS 32
/*
* In this version, sg_tablesize now defaults to WD7000_SG, and will
* be set to SG_NONE for older boards. This is the reverse of the
* previous default, and was changed so that the driver-level
* Scsi_Host_Template would reflect the driver's support for scatter/
* gather.
*
* Also, it has been reported that boards at Revision 6 support scatter/
* gather, so the new definition of an "older" board has been changed
* accordingly.
*/
#define WD7000_Q 16
#define WD7000_SG 16
/*
* WD7000-specific mailbox structure
*
......@@ -1737,7 +1754,23 @@ MODULE_AUTHOR("Thomas Wuensche, John Boyd, Miroslav Zagorac");
MODULE_DESCRIPTION("Driver for the WD7000 series ISA controllers");
MODULE_LICENSE("GPL");
/* Eventually this will go into an include file, but this will be later */
static Scsi_Host_Template driver_template = WD7000;
static Scsi_Host_Template driver_template = {
.proc_name = "wd7000",
.proc_info = wd7000_proc_info,
.name = "Western Digital WD-7000",
.detect = wd7000_detect,
.command = wd7000_command,
.queuecommand = wd7000_queuecommand,
.eh_bus_reset_handler = wd7000_bus_reset,
.eh_device_reset_handler = wd7000_device_reset,
.eh_host_reset_handler = wd7000_host_reset,
.bios_param = wd7000_biosparam,
.can_queue = WD7000_Q,
.this_id = 7,
.sg_tablesize = WD7000_SG,
.cmd_per_lun = 1,
.unchecked_isa_dma = 1,
.use_clustering = ENABLE_CLUSTERING,
};
#include "scsi_module.c"
#ifndef _WD7000_H
/* $Id: $
*
* Header file for the WD-7000 driver for Linux
*
* John Boyd <boyd@cis.ohio-state.edu> Jan 1994:
* This file has been reduced to only the definitions needed for the
* WD7000 host structure.
*
* Revision by Miroslav Zagorac <zaga@fly.cc.fer.hr> Jun 1997.
*/
#include <linux/types.h>
static int wd7000_set_info(char *buffer, int length, struct Scsi_Host *host);
static int wd7000_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
static int wd7000_detect(Scsi_Host_Template *);
static int wd7000_command(Scsi_Cmnd *);
static int wd7000_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
static int wd7000_abort(Scsi_Cmnd *);
static int wd7000_bus_reset(Scsi_Cmnd *);
static int wd7000_host_reset(Scsi_Cmnd *);
static int wd7000_device_reset(Scsi_Cmnd *);
static int wd7000_biosparam(struct scsi_device *, struct block_device *,
sector_t, int *);
#ifndef NULL
#define NULL 0L
#endif
/*
* In this version, sg_tablesize now defaults to WD7000_SG, and will
* be set to SG_NONE for older boards. This is the reverse of the
* previous default, and was changed so that the driver-level
* Scsi_Host_Template would reflect the driver's support for scatter/
* gather.
*
* Also, it has been reported that boards at Revision 6 support scatter/
* gather, so the new definition of an "older" board has been changed
* accordingly.
*/
#define WD7000_Q 16
#define WD7000_SG 16
#define WD7000 { \
.proc_name = "wd7000", \
.proc_info = wd7000_proc_info, \
.name = "Western Digital WD-7000", \
.detect = wd7000_detect, \
.command = wd7000_command, \
.queuecommand = wd7000_queuecommand, \
.eh_bus_reset_handler = wd7000_bus_reset, \
.eh_device_reset_handler = wd7000_device_reset, \
.eh_host_reset_handler = wd7000_host_reset, \
.bios_param = wd7000_biosparam, \
.can_queue = WD7000_Q, \
.this_id = 7, \
.sg_tablesize = WD7000_SG, \
.cmd_per_lun = 1, \
.unchecked_isa_dma = 1, \
.use_clustering = ENABLE_CLUSTERING, \
}
#endif
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