Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
8b0f29fb
Commit
8b0f29fb
authored
Feb 21, 2003
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
http://linux-scsi.bkbits.net/scsi-for-linus-2.5
into home.transmeta.com:/home/torvalds/v2.5/linux
parents
227b2020
6fe854d9
Changes
23
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
874 additions
and
950 deletions
+874
-950
Documentation/scsi/scsi_mid_low_api.txt
Documentation/scsi/scsi_mid_low_api.txt
+79
-11
drivers/scsi/53c700.c
drivers/scsi/53c700.c
+22
-0
drivers/scsi/53c700.h
drivers/scsi/53c700.h
+7
-48
drivers/scsi/Kconfig
drivers/scsi/Kconfig
+1
-0
drivers/scsi/eata.c
drivers/scsi/eata.c
+0
-3
drivers/scsi/eata_pio.c
drivers/scsi/eata_pio.c
+119
-36
drivers/scsi/eata_pio.h
drivers/scsi/eata_pio.h
+0
-25
drivers/scsi/eata_pio_proc.c
drivers/scsi/eata_pio_proc.c
+0
-128
drivers/scsi/hosts.c
drivers/scsi/hosts.c
+4
-16
drivers/scsi/hosts.h
drivers/scsi/hosts.h
+1
-3
drivers/scsi/pluto.c
drivers/scsi/pluto.c
+1
-1
drivers/scsi/scsi.c
drivers/scsi/scsi.c
+98
-38
drivers/scsi/scsi.h
drivers/scsi/scsi.h
+7
-4
drivers/scsi/scsi_error.c
drivers/scsi/scsi_error.c
+428
-433
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_lib.c
+1
-18
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_scan.c
+2
-0
drivers/scsi/scsi_syms.c
drivers/scsi/scsi_syms.c
+1
-2
drivers/scsi/scsi_sysfs.c
drivers/scsi/scsi_sysfs.c
+56
-9
drivers/scsi/sg.c
drivers/scsi/sg.c
+0
-88
drivers/scsi/sim710.c
drivers/scsi/sim710.c
+7
-13
drivers/scsi/u14-34f.c
drivers/scsi/u14-34f.c
+0
-3
drivers/scsi/wd7000.c
drivers/scsi/wd7000.c
+40
-7
drivers/scsi/wd7000.h
drivers/scsi/wd7000.h
+0
-64
No files found.
Documentation/scsi/scsi_mid_low_api.txt
View file @
8b0f29fb
...
@@ -22,13 +22,28 @@ has its own PCI device address. [The one-to-one correspondance between
...
@@ -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
a SCSI host and a PCI device is common but not required (e.g. with
ISA or MCA adapters).]
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
The Linux kernel source Documentation/DocBook/scsidrivers.tmpl file
refers to this file. With the appropriate DocBook toolset, this permits
refers to this file. With the appropriate DocBook toolset, this permits
users to generate html, ps and pdf renderings of information within this
users to generate html, ps and pdf renderings of information within this
file (e.g. the interface functions).
file (e.g. the interface functions).
This version of the document roughly matches lk 2.5.50 .
Driver structure
Driver structure
================
================
Traditionally a LLD for the SCSI subsystem has been at least two files in
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)
...
@@ -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.
since the effected disk can be "cleaned up" the next time it is seen.
During LLD initialization the driver should register itself with the
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
appropriate IO bus on which it expects to find HBA(s) (e.g. the PCI bus).
can probably be done via sysfs (formerly known as driverfs). Any driver
This can probably be done via sysfs. Any driver parameters (especially
parameters (especially those that are writeable after the driver is
those that are writeable after the driver is loaded) could also be
loaded) could also be registered with sysfs at this point. At the end of
registered with sysfs at this point. At the end of driver initialization
driver initialization the SCSI mid level is typically not aware of its
the SCSI mid level is typically not aware of its presence.
presence.
At some later time, the LLD becomes aware of a HBA and what follows
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.
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
...
@@ -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
(a pointer is returned by scsi_register() ) and struct scsi_device
instances (a pointer is passed as the parameter to slave_alloc() and
instances (a pointer is passed as the parameter to slave_alloc() and
slave_configure() ). Both classes of instances are "owned" by the
slave_configure() ). Both classes of instances are "owned" by the
mid-level. struct scsi_device
s
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().
struct Scsi_Host instances are freed after scsi_unregister().
...
@@ -249,6 +263,8 @@ names all start with "scsi_".
...
@@ -249,6 +263,8 @@ names all start with "scsi_".
/**
/**
* scsi_add_host - perform sysfs registration and SCSI bus scan.
* scsi_add_host - perform sysfs registration and SCSI bus scan.
* @shost: pointer to scsi host instance
* @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)
* Returns 0 on success, negative errno of failure (e.g. -ENOMEM)
*
*
...
@@ -256,7 +272,24 @@ names all start with "scsi_".
...
@@ -256,7 +272,24 @@ names all start with "scsi_".
* successful call to scsi_register().
* successful call to scsi_register().
* Defined in drivers/scsi/hosts.c
* 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)
...
@@ -321,6 +354,21 @@ unsigned char *scsi_bios_ptable(struct block_device *dev)
void scsi_block_requests(struct Scsi_Host * SHpnt)
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
* scsi_partsize - parse partition table into cylinders, heads + sectors
* @buf: pointer to partition table
* @buf: pointer to partition table
...
@@ -429,6 +477,26 @@ void scsi_set_device(struct Scsi_Host * shost, struct device * dev)
...
@@ -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)
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
* scsi_unblock_requests - allow further commands to be queued to given host
*
*
...
@@ -1008,4 +1076,4 @@ The following people have contributed to this document:
...
@@ -1008,4 +1076,4 @@ The following people have contributed to this document:
Douglas Gilbert
Douglas Gilbert
dgilbert@interlog.com
dgilbert@interlog.com
2
9th November 2002
2
1st February 2003
drivers/scsi/53c700.c
View file @
8b0f29fb
...
@@ -122,6 +122,7 @@
...
@@ -122,6 +122,7 @@
#include <linux/ioport.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/proc_fs.h>
#include <asm/dma.h>
#include <asm/dma.h>
...
@@ -325,6 +326,7 @@ NCR_700_detect(Scsi_Host_Template *tpnt,
...
@@ -325,6 +326,7 @@ NCR_700_detect(Scsi_Host_Template *tpnt,
host
->
max_lun
=
NCR_700_MAX_LUNS
;
host
->
max_lun
=
NCR_700_MAX_LUNS
;
host
->
unique_id
=
hostdata
->
base
;
host
->
unique_id
=
hostdata
->
base
;
host
->
base
=
hostdata
->
base
;
host
->
base
=
hostdata
->
base
;
hostdata
->
eh_complete
=
NULL
;
host
->
hostdata
[
0
]
=
(
unsigned
long
)
hostdata
;
host
->
hostdata
[
0
]
=
(
unsigned
long
)
hostdata
;
/* kick the chip */
/* kick the chip */
NCR_700_writeb
(
0xff
,
host
,
CTEST9_REG
);
NCR_700_writeb
(
0xff
,
host
,
CTEST9_REG
);
...
@@ -1525,6 +1527,9 @@ NCR_700_intr(int irq, void *dev_id, struct pt_regs *regs)
...
@@ -1525,6 +1527,9 @@ NCR_700_intr(int irq, void *dev_id, struct pt_regs *regs)
hostdata
->
state
=
NCR_700_HOST_FREE
;
hostdata
->
state
=
NCR_700_HOST_FREE
;
hostdata
->
cmd
=
NULL
;
hostdata
->
cmd
=
NULL
;
/* signal back if this was an eh induced reset */
if
(
hostdata
->
eh_complete
!=
NULL
)
complete
(
hostdata
->
eh_complete
);
goto
out_unlock
;
goto
out_unlock
;
}
else
if
(
sstat0
&
SELECTION_TIMEOUT
)
{
}
else
if
(
sstat0
&
SELECTION_TIMEOUT
)
{
DEBUG
((
"scsi%d: (%d:%d) selection timeout
\n
"
,
DEBUG
((
"scsi%d: (%d:%d) selection timeout
\n
"
,
...
@@ -1949,10 +1954,27 @@ NCR_700_abort(Scsi_Cmnd * SCp)
...
@@ -1949,10 +1954,27 @@ NCR_700_abort(Scsi_Cmnd * SCp)
STATIC
int
STATIC
int
NCR_700_bus_reset
(
Scsi_Cmnd
*
SCp
)
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
"
,
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
);
SCp
->
device
->
host
->
host_no
,
SCp
->
device
->
id
,
SCp
->
device
->
lun
,
SCp
);
print_command
(
SCp
->
cmnd
);
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
);
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
;
return
SUCCESS
;
}
}
...
...
drivers/scsi/53c700.h
View file @
8b0f29fb
...
@@ -136,38 +136,6 @@ NCR_700_clear_flag(Scsi_Device *SDp, __u32 flag)
...
@@ -136,38 +136,6 @@ NCR_700_clear_flag(Scsi_Device *SDp, __u32 flag)
((
unsigned
long
)
SDp
->
hostdata
)
&=
~
(
flag
&
0xffff0000
);
((
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_command_slot
{
struct
NCR_700_SG_List
SG
[
NCR_700_SG_SEGMENTS
+
1
];
struct
NCR_700_SG_List
SG
[
NCR_700_SG_SEGMENTS
+
1
];
struct
NCR_700_SG_List
*
pSG
;
struct
NCR_700_SG_List
*
pSG
;
...
@@ -186,12 +154,8 @@ struct NCR_700_command_slot {
...
@@ -186,12 +154,8 @@ struct NCR_700_command_slot {
/* if this command is a pci_single mapping, holds the dma address
/* if this command is a pci_single mapping, holds the dma address
* for later unmapping in the done routine */
* for later unmapping in the done routine */
dma_addr_t
dma_handle
;
dma_addr_t
dma_handle
;
/* Doubly linked ITL/ITLQ list kept in strict time order
/* historical remnant, now used to link free commands */
* (latest at the back) */
struct
NCR_700_command_slot
*
ITL_forw
;
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
{
struct
NCR_700_Host_Parameters
{
...
@@ -238,20 +202,15 @@ struct NCR_700_Host_Parameters {
...
@@ -238,20 +202,15 @@ struct NCR_700_Host_Parameters {
__u8
tag_negotiated
;
__u8
tag_negotiated
;
__u8
rev
;
__u8
rev
;
__u8
reselection_id
;
__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 */
/* Free list, singly linked by ITL_forw elements */
struct
NCR_700_command_slot
*
free_list
;
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
;
};
};
/*
/*
...
...
drivers/scsi/Kconfig
View file @
8b0f29fb
...
@@ -129,6 +129,7 @@ config SCSI_MULTI_LUN
...
@@ -129,6 +129,7 @@ config SCSI_MULTI_LUN
config SCSI_REPORT_LUNS
config SCSI_REPORT_LUNS
bool "Build with SCSI REPORT LUNS support"
bool "Build with SCSI REPORT LUNS support"
depends on SCSI
depends on SCSI
default y
help
help
If you want to build with SCSI REPORT LUNS support in the kernel, say Y here.
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
The REPORT LUNS command is useful for devices (such as disk arrays) with
...
...
drivers/scsi/eata.c
View file @
8b0f29fb
...
@@ -1228,7 +1228,6 @@ static int port_detect \
...
@@ -1228,7 +1228,6 @@ static int port_detect \
sh
[
j
]
->
unchecked_isa_dma
=
FALSE
;
sh
[
j
]
->
unchecked_isa_dma
=
FALSE
;
else
{
else
{
unsigned
long
flags
;
unsigned
long
flags
;
scsi_register_blocked_host
(
sh
[
j
]);
sh
[
j
]
->
unchecked_isa_dma
=
TRUE
;
sh
[
j
]
->
unchecked_isa_dma
=
TRUE
;
flags
=
claim_dma_lock
();
flags
=
claim_dma_lock
();
...
@@ -2353,8 +2352,6 @@ static int eata2x_release(struct Scsi_Host *shpnt) {
...
@@ -2353,8 +2352,6 @@ static int eata2x_release(struct Scsi_Host *shpnt) {
if
(
sh
[
j
]
==
NULL
)
panic
(
"%s: release, invalid Scsi_Host pointer.
\n
"
,
if
(
sh
[
j
]
==
NULL
)
panic
(
"%s: release, invalid Scsi_Host pointer.
\n
"
,
driver_name
);
driver_name
);
if
(
sh
[
j
]
->
unchecked_isa_dma
)
scsi_deregister_blocked_host
(
sh
[
j
]);
for
(
i
=
0
;
i
<
sh
[
j
]
->
can_queue
;
i
++
)
for
(
i
=
0
;
i
<
sh
[
j
]
->
can_queue
;
i
++
)
if
((
&
HD
(
j
)
->
cp
[
i
])
->
sglist
)
kfree
((
&
HD
(
j
)
->
cp
[
i
])
->
sglist
);
if
((
&
HD
(
j
)
->
cp
[
i
])
->
sglist
)
kfree
((
&
HD
(
j
)
->
cp
[
i
])
->
sglist
);
...
...
drivers/scsi/eata_pio.c
View file @
8b0f29fb
...
@@ -46,10 +46,7 @@
...
@@ -46,10 +46,7 @@
* last change: 2002/11/02 OS: Linux 2.5.45 *
* last change: 2002/11/02 OS: Linux 2.5.45 *
************************************************************/
************************************************************/
/* Look in eata_pio.h for configuration information */
#include <linux/module.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/string.h>
...
@@ -59,15 +56,19 @@
...
@@ -59,15 +56,19 @@
#include <linux/pci.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/proc_fs.h>
#include <linux/interrupt.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/stat.h>
#include <linux/config.h>
/* for CONFIG_PCI */
#include <linux/config.h>
#include <linux/blk.h>
#include <linux/blk.h>
#include <linux/spinlock.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
]
=
{
static
uint
ISAbases
[
MAXISA
]
=
{
0x1F0
,
0x170
,
0x330
,
0x230
0x1F0
,
0x170
,
0x330
,
0x230
...
@@ -82,16 +83,106 @@ static unsigned char EISAbases[] = {
...
@@ -82,16 +83,106 @@ static unsigned char EISAbases[] = {
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
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
*
last_HBA
;
static
struct
Scsi_Host
*
first_HBA
;
static
struct
Scsi_Host
*
first_HBA
;
static
unsigned
char
reg_IRQ
[];
static
unsigned
char
reg_IRQ
[
16
];
static
unsigned
char
reg_IRQL
[];
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
,
"
\n
scsi%-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
)
static
int
eata_pio_release
(
struct
Scsi_Host
*
sh
)
{
{
...
@@ -895,27 +986,19 @@ static int eata_pio_detect(Scsi_Host_Template * tpnt)
...
@@ -895,27 +986,19 @@ static int eata_pio_detect(Scsi_Host_Template * tpnt)
return
(
registered_HBAs
);
return
(
registered_HBAs
);
}
}
/* Eventually this will go into an include file, but this will be later */
static
Scsi_Host_Template
driver_template
=
{
static
Scsi_Host_Template
driver_template
=
EATA_PIO
;
.
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"
);
MODULE_LICENSE
(
"GPL"
);
/*
#include "scsi_module.c"
* Overrides for Emacs so that we almost follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-indent-level: 4
* c-brace-imaginary-offset: 0
* c-brace-offset: -4
* c-argdecl-indent: 4
* c-label-offset: -4
* c-continued-statement-offset: 4
* c-continued-brace-offset: 0
* indent-tabs-mode: nil
* tab-width: 8
* End:
*/
drivers/scsi/eata_pio.h
View file @
8b0f29fb
...
@@ -9,13 +9,6 @@
...
@@ -9,13 +9,6 @@
#ifndef _EATA_PIO_H
#ifndef _EATA_PIO_H
#define _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_MAJOR 0
#define VER_MINOR 0
#define VER_MINOR 0
#define VER_SUB "1b"
#define VER_SUB "1b"
...
@@ -57,22 +50,4 @@
...
@@ -57,22 +50,4 @@
#define DBG(x, y)
#define DBG(x, y)
#endif
#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 */
#endif
/* _EATA_PIO_H */
drivers/scsi/eata_pio_proc.c
deleted
100644 → 0
View file @
227b2020
/*
* 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
,
"
\n
scsi%-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:
*/
drivers/scsi/hosts.c
View file @
8b0f29fb
...
@@ -397,6 +397,7 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes)
...
@@ -397,6 +397,7 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes)
spin_lock_init
(
&
shost
->
default_lock
);
spin_lock_init
(
&
shost
->
default_lock
);
scsi_assign_lock
(
shost
,
&
shost
->
default_lock
);
scsi_assign_lock
(
shost
,
&
shost
->
default_lock
);
INIT_LIST_HEAD
(
&
shost
->
my_devices
);
INIT_LIST_HEAD
(
&
shost
->
my_devices
);
INIT_LIST_HEAD
(
&
shost
->
eh_cmd_q
);
init_waitqueue_head
(
&
shost
->
host_wait
);
init_waitqueue_head
(
&
shost
->
host_wait
);
shost
->
dma_channel
=
0xff
;
shost
->
dma_channel
=
0xff
;
...
@@ -634,22 +635,9 @@ void scsi_host_busy_dec_and_test(struct Scsi_Host *shost, Scsi_Device *sdev)
...
@@ -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
);
spin_lock_irqsave
(
shost
->
host_lock
,
flags
);
shost
->
host_busy
--
;
shost
->
host_busy
--
;
sdev
->
device_busy
--
;
sdev
->
device_busy
--
;
if
(
shost
->
in_recovery
&&
(
shost
->
host_busy
==
shost
->
host_failed
))
{
if
(
shost
->
in_recovery
&&
shost
->
host_failed
&&
up
(
shost
->
eh_wait
);
(
shost
->
host_busy
==
shost
->
host_failed
))
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
)
{
up
(
shost
->
eh_wait
);
up
(
shost
->
eh_wait
);
SCSI_LOG_ERROR_RECOVERY
(
5
,
printk
(
"Waking error handler"
SCSI_LOG_ERROR_RECOVERY
(
5
,
printk
(
"Waking error handler"
" thread
\n
"
));
" thread
\n
"
));
...
...
drivers/scsi/hosts.h
View file @
8b0f29fb
...
@@ -384,6 +384,7 @@ struct Scsi_Host
...
@@ -384,6 +384,7 @@ struct Scsi_Host
spinlock_t
default_lock
;
spinlock_t
default_lock
;
spinlock_t
*
host_lock
;
spinlock_t
*
host_lock
;
struct
list_head
eh_cmd_q
;
struct
task_struct
*
ehandler
;
/* Error recovery thread. */
struct
task_struct
*
ehandler
;
/* Error recovery thread. */
struct
semaphore
*
eh_wait
;
/* The error recovery thread waits on
struct
semaphore
*
eh_wait
;
/* The error recovery thread waits on
this. */
this. */
...
@@ -514,8 +515,6 @@ extern Scsi_Device * scsi_get_host_dev(struct Scsi_Host *);
...
@@ -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_unblock_requests
(
struct
Scsi_Host
*
);
extern
void
scsi_block_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_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
)
static
inline
void
scsi_assign_lock
(
struct
Scsi_Host
*
shost
,
spinlock_t
*
lock
)
{
{
...
@@ -587,7 +586,6 @@ extern void scsi_host_init(void);
...
@@ -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_inc
(
struct
Scsi_Host
*
,
Scsi_Device
*
);
extern
void
scsi_host_busy_dec_and_test
(
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
* scsi_find_device - find a device given the host
...
...
drivers/scsi/pluto.c
View file @
8b0f29fb
...
@@ -287,7 +287,7 @@ int pluto_release(struct Scsi_Host *host)
...
@@ -287,7 +287,7 @@ int pluto_release(struct Scsi_Host *host)
struct
pluto
*
pluto
=
(
struct
pluto
*
)
host
->
hostdata
;
struct
pluto
*
pluto
=
(
struct
pluto
*
)
host
->
hostdata
;
fc_channel
*
fc
=
pluto
->
fc
;
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
);
fc
->
fcp_register
(
fc
,
TYPE_SCSI_FCP
,
1
);
PLND
((
" releasing pluto.
\n
"
));
PLND
((
" releasing pluto.
\n
"
));
...
...
drivers/scsi/scsi.c
View file @
8b0f29fb
...
@@ -36,9 +36,6 @@
...
@@ -36,9 +36,6 @@
* out_of_space hacks, D. Gilbert (dpg) 990608
* 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/config.h>
#include <linux/module.h>
#include <linux/module.h>
...
@@ -790,13 +787,9 @@ static void scsi_softirq(struct softirq_action *h)
...
@@ -790,13 +787,9 @@ static void scsi_softirq(struct softirq_action *h)
if
((
status_byte
(
SCpnt
->
result
)
&
CHECK_CONDITION
)
!=
0
)
{
if
((
status_byte
(
SCpnt
->
result
)
&
CHECK_CONDITION
)
!=
0
)
{
SCSI_LOG_MLCOMPLETE
(
3
,
print_sense
(
"bh"
,
SCpnt
));
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
);
if
(
!
scsi_eh_scmd_add
(
SCpnt
,
0
))
}
else
{
{
/*
/*
* We only get here if the error
* We only get here if the error
* recovery thread has died.
* recovery thread has died.
...
@@ -1147,29 +1140,6 @@ int scsi_dev_info_list_add_str (char *dev_list)
...
@@ -1147,29 +1140,6 @@ int scsi_dev_info_list_add_str (char *dev_list)
return
res
;
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
* scsi_dev_info_list_delete: called from scsi.c:exit_scsi to remove
* the scsi_dev_info_list.
* the scsi_dev_info_list.
...
@@ -1186,6 +1156,37 @@ static void scsi_dev_info_list_delete (void)
...
@@ -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
* get_device_flags - get device specific flags from the dynamic device
* list. Called during scan time.
* list. Called during scan time.
...
@@ -1298,6 +1299,44 @@ void scsi_device_put(struct scsi_device *sdev)
...
@@ -1298,6 +1299,44 @@ void scsi_device_put(struct scsi_device *sdev)
module_put
(
sdev
->
host
->
hostt
->
module
);
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()
* Function: scsi_slave_attach()
*
*
...
@@ -1437,17 +1476,38 @@ __setup("scsi_default_dev_flags=", setup_scsi_default_dev_flags);
...
@@ -1437,17 +1476,38 @@ __setup("scsi_default_dev_flags=", setup_scsi_default_dev_flags);
#endif
#endif
/* FIXME(hch): add proper error handling */
static
int
__init
init_scsi
(
void
)
static
int
__init
init_scsi
(
void
)
{
{
scsi_init_queue
();
int
error
;
scsi_init_procfs
();
devfs_mk_dir
(
NULL
,
"scsi"
,
NULL
);
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_host_init
();
scsi_dev_info_list_init
(
scsi_dev_flags
);
devfs_mk_dir
(
NULL
,
"scsi"
,
NULL
);
scsi_sysfs_register
();
open_softirq
(
SCSI_SOFTIRQ
,
scsi_softirq
,
NULL
);
open_softirq
(
SCSI_SOFTIRQ
,
scsi_softirq
,
NULL
);
printk
(
KERN_NOTICE
"SCSI subsystem initialized
\n
"
);
return
0
;
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
)
static
void
__exit
exit_scsi
(
void
)
...
...
drivers/scsi/scsi.h
View file @
8b0f29fb
...
@@ -455,6 +455,7 @@ extern int scsi_slave_attach(struct scsi_device *);
...
@@ -455,6 +455,7 @@ extern int scsi_slave_attach(struct scsi_device *);
extern
void
scsi_slave_detach
(
struct
scsi_device
*
);
extern
void
scsi_slave_detach
(
struct
scsi_device
*
);
extern
int
scsi_device_get
(
struct
scsi_device
*
);
extern
int
scsi_device_get
(
struct
scsi_device
*
);
extern
void
scsi_device_put
(
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_done
(
Scsi_Cmnd
*
SCpnt
);
extern
void
scsi_finish_command
(
Scsi_Cmnd
*
);
extern
void
scsi_finish_command
(
Scsi_Cmnd
*
);
extern
int
scsi_retry_command
(
Scsi_Cmnd
*
);
extern
int
scsi_retry_command
(
Scsi_Cmnd
*
);
...
@@ -726,6 +727,7 @@ struct scsi_cmnd {
...
@@ -726,6 +727,7 @@ struct scsi_cmnd {
struct
list_head
list
;
/* scsi_cmnd participates in queue lists */
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_state
;
/* Used for state tracking in error handlr */
int
eh_eflags
;
/* Used by error handlr */
int
eh_eflags
;
/* Used by error handlr */
void
(
*
done
)
(
struct
scsi_cmnd
*
);
/* Mid-level done function */
void
(
*
done
)
(
struct
scsi_cmnd
*
);
/* Mid-level done function */
...
@@ -850,6 +852,7 @@ struct scsi_cmnd {
...
@@ -850,6 +852,7 @@ struct scsi_cmnd {
*/
*/
#define SCSI_MLQUEUE_HOST_BUSY 0x1055
#define SCSI_MLQUEUE_HOST_BUSY 0x1055
#define SCSI_MLQUEUE_DEVICE_BUSY 0x1056
#define SCSI_MLQUEUE_DEVICE_BUSY 0x1056
#define SCSI_MLQUEUE_EH_RETRY 0x1057
/*
/*
* old style reset request from external source
* old style reset request from external source
...
@@ -960,13 +963,13 @@ static inline Scsi_Cmnd *scsi_find_tag(Scsi_Device *SDpnt, int tag) {
...
@@ -960,13 +963,13 @@ static inline Scsi_Cmnd *scsi_find_tag(Scsi_Device *SDpnt, int tag) {
/*
/*
* Scsi Error Handler Flags
* Scsi Error Handler Flags
*/
*/
#define SCSI_EH_CMD_ERR 0x0001
/* Orig cmd error'd */
#define SCSI_EH_CANCEL_CMD 0x0001
/* Cancel this cmd */
#define SCSI_EH_CMD_FAILED 0x0002
/* Orig cmd error type failed */
#define SCSI_EH_REC_TIMEOUT 0x0002
/* EH retry timed out */
#define SCSI_EH_CMD_TIMEOUT 0x0004
/* Orig cmd error type timeout */
#define SCSI_EH_REC_TIMEOUT 0x0008
/* Recovery cmd timeout */
#define SCSI_SENSE_VALID(scmd) ((scmd->sense_buffer[0] & 0x70) == 0x70)
#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
);
int
scsi_set_medium_removal
(
Scsi_Device
*
dev
,
char
state
);
extern
int
scsi_device_register
(
struct
scsi_device
*
);
extern
int
scsi_device_register
(
struct
scsi_device
*
);
...
...
drivers/scsi/scsi_error.c
View file @
8b0f29fb
...
@@ -15,33 +15,19 @@
...
@@ -15,33 +15,19 @@
*/
*/
#include <linux/module.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/stat.h>
#include <linux/blk.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/
delay
.h>
#include <linux/
blkdev
.h>
#include <linux/smp_lock.h>
#include <linux/smp_lock.h>
#include <linux/completion.h>
#include <scsi/scsi_ioctl.h>
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/dma.h>
#include "scsi.h"
#include "scsi.h"
#include "hosts.h"
#include "hosts.h"
#include <scsi/scsi_ioctl.h>
/* grr */
#ifdef DEBUG
#ifdef DEBUG
#define SENSE_TIMEOUT SCSI_TIMEOUT
#define SENSE_TIMEOUT SCSI_TIMEOUT
#else
#else
...
@@ -55,6 +41,49 @@
...
@@ -55,6 +41,49 @@
#define BUS_RESET_SETTLE_TIME 10*HZ
#define BUS_RESET_SETTLE_TIME 10*HZ
#define HOST_RESET_SETTLE_TIME 10*HZ
#define HOST_RESET_SETTLE_TIME 10*HZ
/**
* scsi_eh_scmd_add - add scsi cmd to error handling.
* @scmd: scmd to run eh on.
* @eh_flag: optional SCSI_EH flag.
*
* Return value:
* 0 on failure.
**/
int
scsi_eh_scmd_add
(
struct
scsi_cmnd
*
scmd
,
int
eh_flag
)
{
struct
Scsi_Host
*
shost
=
scmd
->
device
->
host
;
unsigned
long
flags
;
if
(
shost
->
eh_wait
==
NULL
)
return
0
;
spin_lock_irqsave
(
shost
->
host_lock
,
flags
);
scsi_eh_eflags_set
(
scmd
,
eh_flag
);
/*
* FIXME: Can we stop setting owner and state.
*/
scmd
->
owner
=
SCSI_OWNER_ERROR_HANDLER
;
scmd
->
state
=
SCSI_STATE_FAILED
;
/*
* Set the serial_number_at_timeout to the current
* serial_number
*/
scmd
->
serial_number_at_timeout
=
scmd
->
serial_number
;
list_add_tail
(
&
scmd
->
eh_entry
,
&
shost
->
eh_cmd_q
);
shost
->
in_recovery
=
1
;
shost
->
host_failed
++
;
if
(
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
);
return
1
;
}
/**
/**
* scsi_add_timer - Start timeout timer for a single scsi command.
* scsi_add_timer - Start timeout timer for a single scsi command.
* @scmd: scsi command that is about to start running.
* @scmd: scsi command that is about to start running.
...
@@ -68,8 +97,8 @@
...
@@ -68,8 +97,8 @@
* simple, really, especially compared to the old way of handling this
* simple, really, especially compared to the old way of handling this
* crap.
* crap.
**/
**/
void
scsi_add_timer
(
Scsi_Cmnd
*
scmd
,
int
timeout
,
void
(
*
complete
)
void
scsi_add_timer
(
struct
scsi_cmnd
*
scmd
,
int
timeout
,
(
Scsi_C
mnd
*
))
void
(
*
complete
)(
struct
scsi_c
mnd
*
))
{
{
/*
/*
...
@@ -77,10 +106,10 @@ void scsi_add_timer(Scsi_Cmnd *scmd, int timeout, void (*complete)
...
@@ -77,10 +106,10 @@ void scsi_add_timer(Scsi_Cmnd *scmd, int timeout, void (*complete)
* first delete the timer. The timer handling code gets rather
* first delete the timer. The timer handling code gets rather
* confused if we don't do this.
* confused if we don't do this.
*/
*/
if
(
scmd
->
eh_timeout
.
function
!=
NULL
)
{
if
(
scmd
->
eh_timeout
.
function
)
del_timer
(
&
scmd
->
eh_timeout
);
del_timer
(
&
scmd
->
eh_timeout
);
}
scmd
->
eh_timeout
.
data
=
(
unsigned
long
)
scmd
;
scmd
->
eh_timeout
.
data
=
(
unsigned
long
)
scmd
;
scmd
->
eh_timeout
.
expires
=
jiffies
+
timeout
;
scmd
->
eh_timeout
.
expires
=
jiffies
+
timeout
;
scmd
->
eh_timeout
.
function
=
(
void
(
*
)(
unsigned
long
))
complete
;
scmd
->
eh_timeout
.
function
=
(
void
(
*
)(
unsigned
long
))
complete
;
...
@@ -89,7 +118,6 @@ void scsi_add_timer(Scsi_Cmnd *scmd, int timeout, void (*complete)
...
@@ -89,7 +118,6 @@ void scsi_add_timer(Scsi_Cmnd *scmd, int timeout, void (*complete)
scmd
,
timeout
,
complete
));
scmd
,
timeout
,
complete
));
add_timer
(
&
scmd
->
eh_timeout
);
add_timer
(
&
scmd
->
eh_timeout
);
}
}
/**
/**
...
@@ -103,7 +131,7 @@ void scsi_add_timer(Scsi_Cmnd *scmd, int timeout, void (*complete)
...
@@ -103,7 +131,7 @@ void scsi_add_timer(Scsi_Cmnd *scmd, int timeout, void (*complete)
* 1 if we were able to detach the timer. 0 if we blew it, and the
* 1 if we were able to detach the timer. 0 if we blew it, and the
* timer function has already started to run.
* timer function has already started to run.
**/
**/
int
scsi_delete_timer
(
Scsi_C
mnd
*
scmd
)
int
scsi_delete_timer
(
struct
scsi_c
mnd
*
scmd
)
{
{
int
rtn
;
int
rtn
;
...
@@ -113,7 +141,7 @@ int scsi_delete_timer(Scsi_Cmnd *scmd)
...
@@ -113,7 +141,7 @@ int scsi_delete_timer(Scsi_Cmnd *scmd)
" rtn: %d
\n
"
,
__FUNCTION__
,
" rtn: %d
\n
"
,
__FUNCTION__
,
scmd
,
rtn
));
scmd
,
rtn
));
scmd
->
eh_timeout
.
data
=
(
unsigned
long
)
NULL
;
scmd
->
eh_timeout
.
data
=
(
unsigned
long
)
NULL
;
scmd
->
eh_timeout
.
function
=
NULL
;
scmd
->
eh_timeout
.
function
=
NULL
;
return
rtn
;
return
rtn
;
...
@@ -129,24 +157,16 @@ int scsi_delete_timer(Scsi_Cmnd *scmd)
...
@@ -129,24 +157,16 @@ int scsi_delete_timer(Scsi_Cmnd *scmd)
* normal completion function determines that the timer has already
* normal completion function determines that the timer has already
* fired, then it mustn't do anything.
* fired, then it mustn't do anything.
**/
**/
void
scsi_times_out
(
Scsi_C
mnd
*
scmd
)
void
scsi_times_out
(
struct
scsi_c
mnd
*
scmd
)
{
{
struct
Scsi_Host
*
shost
=
scmd
->
device
->
host
;
if
(
unlikely
(
!
scsi_eh_scmd_add
(
scmd
,
SCSI_EH_CANCEL_CMD
)))
{
/* Set the serial_number_at_timeout to the current serial_number */
scmd
->
serial_number_at_timeout
=
scmd
->
serial_number
;
scsi_eh_eflags_set
(
scmd
,
SCSI_EH_CMD_TIMEOUT
|
SCSI_EH_CMD_ERR
);
if
(
unlikely
(
shost
->
eh_wait
==
NULL
))
{
panic
(
"Error handler thread not present at %p %p %s %d"
,
panic
(
"Error handler thread not present at %p %p %s %d"
,
scmd
,
shost
,
__FILE__
,
__LINE__
);
scmd
,
s
cmd
->
device
->
host
,
__FILE__
,
__LINE__
);
}
}
scsi_host_failed_inc_and_test
(
shost
);
SCSI_LOG_TIMEOUT
(
3
,
printk
(
"Command timed out busy=%d failed=%d
\n
"
,
SCSI_LOG_TIMEOUT
(
3
,
printk
(
"Command timed out busy=%d failed=%d
\n
"
,
shost
->
host_busy
,
shost
->
host_failed
));
scmd
->
device
->
host
->
host_busy
,
scmd
->
device
->
host
->
host_failed
));
}
}
/**
/**
...
@@ -160,7 +180,7 @@ void scsi_times_out(Scsi_Cmnd *scmd)
...
@@ -160,7 +180,7 @@ void scsi_times_out(Scsi_Cmnd *scmd)
* Return value:
* Return value:
* 0 when dev was taken offline by error recovery. 1 OK to proceed.
* 0 when dev was taken offline by error recovery. 1 OK to proceed.
**/
**/
int
scsi_block_when_processing_errors
(
Scsi_D
evice
*
sdev
)
int
scsi_block_when_processing_errors
(
struct
scsi_d
evice
*
sdev
)
{
{
wait_event
(
sdev
->
host
->
host_wait
,
(
sdev
->
host
->
in_recovery
==
0
));
wait_event
(
sdev
->
host
->
host_wait
,
(
sdev
->
host
->
in_recovery
==
0
));
...
@@ -173,39 +193,40 @@ int scsi_block_when_processing_errors(Scsi_Device *sdev)
...
@@ -173,39 +193,40 @@ int scsi_block_when_processing_errors(Scsi_Device *sdev)
#if CONFIG_SCSI_LOGGING
#if CONFIG_SCSI_LOGGING
/**
/**
* scsi_eh_prt_fail_stats - Log info on failures.
* scsi_eh_prt_fail_stats - Log info on failures.
* @sc_list: List for failed cmds.
* @shost: scsi host being recovered.
* @shost: scsi host being recovered.
* @work_q: Queue of scsi cmds to process.
**/
**/
static
void
scsi_eh_prt_fail_stats
(
Scsi_Cmnd
*
sc_list
,
struct
Scsi_Host
*
shost
)
static
inline
void
scsi_eh_prt_fail_stats
(
struct
Scsi_Host
*
shost
,
struct
list_head
*
work_q
)
{
{
Scsi_C
mnd
*
scmd
;
struct
scsi_c
mnd
*
scmd
;
Scsi_D
evice
*
sdev
;
struct
scsi_d
evice
*
sdev
;
int
total_failures
=
0
;
int
total_failures
=
0
;
int
cmd_failed
=
0
;
int
cmd_failed
=
0
;
int
cmd_
timed_out
=
0
;
int
cmd_
cancel
=
0
;
int
devices_failed
=
0
;
int
devices_failed
=
0
;
list_for_each_entry
(
sdev
,
&
shost
->
my_devices
,
siblings
)
{
list_for_each_entry
(
sdev
,
&
shost
->
my_devices
,
siblings
)
{
for
(
scmd
=
sc_list
;
scmd
;
scmd
=
scmd
->
bh_next
)
{
list_for_each_entry
(
scmd
,
work_q
,
eh_entry
)
{
if
(
scmd
->
device
==
sdev
)
{
if
(
scmd
->
device
==
sdev
)
{
++
total_failures
;
++
total_failures
;
if
(
scsi_eh_eflags_chk
(
scmd
,
if
(
scsi_eh_eflags_chk
(
scmd
,
SCSI_EH_C
MD_TIMEOUT
))
SCSI_EH_C
ANCEL_CMD
))
++
cmd_
timed_out
;
++
cmd_
cancel
;
else
else
++
cmd_failed
;
++
cmd_failed
;
}
}
}
}
if
(
cmd_
timed_out
||
cmd_failed
)
{
if
(
cmd_
cancel
||
cmd_failed
)
{
SCSI_LOG_ERROR_RECOVERY
(
3
,
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s: %d:%d:%d:%d cmds failed: %d,"
printk
(
"%s: %d:%d:%d:%d cmds failed: %d,"
"
timedout
: %d
\n
"
,
"
cancel
: %d
\n
"
,
__FUNCTION__
,
shost
->
host_no
,
__FUNCTION__
,
shost
->
host_no
,
sdev
->
channel
,
sdev
->
id
,
sdev
->
lun
,
sdev
->
channel
,
sdev
->
id
,
sdev
->
lun
,
cmd_failed
,
cmd_
timed_out
));
cmd_failed
,
cmd_
cancel
));
cmd_
timed_out
=
0
;
cmd_
cancel
=
0
;
cmd_failed
=
0
;
cmd_failed
=
0
;
++
devices_failed
;
++
devices_failed
;
}
}
...
@@ -217,68 +238,6 @@ static void scsi_eh_prt_fail_stats(Scsi_Cmnd *sc_list, struct Scsi_Host *shost)
...
@@ -217,68 +238,6 @@ static void scsi_eh_prt_fail_stats(Scsi_Cmnd *sc_list, struct Scsi_Host *shost)
}
}
#endif
#endif
/**
* scsi_eh_get_failed - Gather failed cmds.
* @sc_list: A pointer to a list for failed cmds.
* @shost: Scsi host being recovered.
*
* XXX Add opaque interator for device / shost. Investigate direct
* addition to per eh list on error allowing skipping of this step.
**/
static
void
scsi_eh_get_failed
(
Scsi_Cmnd
**
sc_list
,
struct
Scsi_Host
*
shost
)
{
int
found
;
Scsi_Device
*
sdev
;
Scsi_Cmnd
*
scmd
;
found
=
0
;
list_for_each_entry
(
sdev
,
&
shost
->
my_devices
,
siblings
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
&
sdev
->
list_lock
,
flags
);
list_for_each_entry
(
scmd
,
&
sdev
->
cmd_list
,
list
)
{
if
(
scsi_eh_eflags_chk
(
scmd
,
SCSI_EH_CMD_ERR
))
{
scmd
->
bh_next
=
*
sc_list
;
*
sc_list
=
scmd
;
found
++
;
}
else
{
/*
* FIXME Verify how this can happen and if
* this is still needed??
*/
if
(
scmd
->
state
!=
SCSI_STATE_INITIALIZING
&&
scmd
->
state
!=
SCSI_STATE_UNUSED
)
{
/*
* Rats. Something is still floating
* around out there This could be the
* result of the fact that the upper level
* drivers are still frobbing commands
* that might have succeeded. There are
* two outcomes. One is that the command
* block will eventually be freed, and the
* other one is that the command will be
* queued and will be finished along the
* way.
*/
SCSI_LOG_ERROR_RECOVERY
(
1
,
printk
(
"Error hdlr"
" prematurely woken"
" cmds still active"
" (%p %x %d)
\n
"
,
scmd
,
scmd
->
state
,
scmd
->
device
->
id
));
}
}
}
spin_unlock_irqrestore
(
&
sdev
->
list_lock
,
flags
);
}
SCSI_LOG_ERROR_RECOVERY
(
1
,
scsi_eh_prt_fail_stats
(
*
sc_list
,
shost
));
if
(
shost
->
host_failed
!=
found
)
printk
(
KERN_ERR
"%s: host_failed: %d != found: %d
\n
"
,
__FUNCTION__
,
shost
->
host_failed
,
found
);
}
/**
/**
* scsi_check_sense - Examine scsi cmd sense
* scsi_check_sense - Examine scsi cmd sense
* @scmd: Cmd to have sense checked.
* @scmd: Cmd to have sense checked.
...
@@ -286,11 +245,10 @@ static void scsi_eh_get_failed(Scsi_Cmnd **sc_list, struct Scsi_Host *shost)
...
@@ -286,11 +245,10 @@ static void scsi_eh_get_failed(Scsi_Cmnd **sc_list, struct Scsi_Host *shost)
* Return value:
* Return value:
* SUCCESS or FAILED or NEEDS_RETRY
* SUCCESS or FAILED or NEEDS_RETRY
**/
**/
static
int
scsi_check_sense
(
Scsi_C
mnd
*
scmd
)
static
int
scsi_check_sense
(
struct
scsi_c
mnd
*
scmd
)
{
{
if
(
!
SCSI_SENSE_VALID
(
scmd
))
{
if
(
!
SCSI_SENSE_VALID
(
scmd
))
return
FAILED
;
return
FAILED
;
}
if
(
scmd
->
sense_buffer
[
2
]
&
0xe0
)
if
(
scmd
->
sense_buffer
[
2
]
&
0xe0
)
return
SUCCESS
;
return
SUCCESS
;
...
@@ -352,9 +310,8 @@ static int scsi_check_sense(Scsi_Cmnd *scmd)
...
@@ -352,9 +310,8 @@ static int scsi_check_sense(Scsi_Cmnd *scmd)
* don't allow for the possibility of retries here, and we are a lot
* don't allow for the possibility of retries here, and we are a lot
* more restrictive about what we consider acceptable.
* more restrictive about what we consider acceptable.
**/
**/
static
int
scsi_eh_completed_normally
(
Scsi_C
mnd
*
scmd
)
static
int
scsi_eh_completed_normally
(
struct
scsi_c
mnd
*
scmd
)
{
{
/*
/*
* first check the host byte, to see if there is anything in there
* first check the host byte, to see if there is anything in there
* that would indicate what we need to do.
* that would indicate what we need to do.
...
@@ -379,15 +336,15 @@ static int scsi_eh_completed_normally(Scsi_Cmnd *scmd)
...
@@ -379,15 +336,15 @@ static int scsi_eh_completed_normally(Scsi_Cmnd *scmd)
*/
*/
return
scsi_check_sense
(
scmd
);
return
scsi_check_sense
(
scmd
);
}
}
if
(
host_byte
(
scmd
->
result
)
!=
DID_OK
)
{
if
(
host_byte
(
scmd
->
result
)
!=
DID_OK
)
return
FAILED
;
return
FAILED
;
}
/*
/*
* next, check the message byte.
* next, check the message byte.
*/
*/
if
(
msg_byte
(
scmd
->
result
)
!=
COMMAND_COMPLETE
)
{
if
(
msg_byte
(
scmd
->
result
)
!=
COMMAND_COMPLETE
)
return
FAILED
;
return
FAILED
;
}
/*
/*
* now, check the status byte to see if this indicates
* now, check the status byte to see if this indicates
* anything special.
* anything special.
...
@@ -423,46 +380,38 @@ static int scsi_eh_completed_normally(Scsi_Cmnd *scmd)
...
@@ -423,46 +380,38 @@ static int scsi_eh_completed_normally(Scsi_Cmnd *scmd)
* for some action to complete on the device. our only job is to
* for some action to complete on the device. our only job is to
* record that it timed out, and to wake up the thread.
* record that it timed out, and to wake up the thread.
**/
**/
static
void
scsi_eh_times_out
(
Scsi_C
mnd
*
scmd
)
static
void
scsi_eh_times_out
(
struct
scsi_c
mnd
*
scmd
)
{
{
scsi_eh_eflags_set
(
scmd
,
SCSI_EH_REC_TIMEOUT
);
scsi_eh_eflags_set
(
scmd
,
SCSI_EH_REC_TIMEOUT
);
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s: scmd:%p
\n
"
,
__FUNCTION__
,
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s: scmd:%p
\n
"
,
__FUNCTION__
,
scmd
));
scmd
));
if
(
scmd
->
device
->
host
->
eh_action
!=
NULL
)
if
(
scmd
->
device
->
host
->
eh_action
)
up
(
scmd
->
device
->
host
->
eh_action
);
up
(
scmd
->
device
->
host
->
eh_action
);
else
printk
(
"%s: eh_action NULL
\n
"
,
__FUNCTION__
);
}
}
/**
/**
* scsi_eh_done - Completion function for error handling.
* scsi_eh_done - Completion function for error handling.
* @scmd: Cmd that is done.
* @scmd: Cmd that is done.
**/
**/
static
void
scsi_eh_done
(
Scsi_C
mnd
*
scmd
)
static
void
scsi_eh_done
(
struct
scsi_c
mnd
*
scmd
)
{
{
int
rtn
;
/*
/*
* if the timeout handler is already running, then just set the
* if the timeout handler is already running, then just set the
* flag which says we finished late, and return. we have no
* flag which says we finished late, and return. we have no
* way of stopping the timeout handler from running, so we must
* way of stopping the timeout handler from running, so we must
* always defer to it.
* always defer to it.
*/
*/
rtn
=
del_timer
(
&
scmd
->
eh_timeout
);
if
(
del_timer
(
&
scmd
->
eh_timeout
))
{
if
(
!
rtn
)
{
scmd
->
request
->
rq_status
=
RQ_SCSI_DONE
;
return
;
scmd
->
owner
=
SCSI_OWNER_ERROR_HANDLER
;
}
scmd
->
request
->
rq_status
=
RQ_SCSI_DONE
;
scmd
->
owner
=
SCSI_OWNER_ERROR_HANDLER
;
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s scmd: %p result: %x
\n
"
,
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s scmd: %p result: %x
\n
"
,
__FUNCTION__
,
scmd
,
scmd
->
result
));
__FUNCTION__
,
scmd
,
scmd
->
result
));
if
(
scmd
->
device
->
host
->
eh_action
!=
NULL
)
if
(
scmd
->
device
->
host
->
eh_action
)
up
(
scmd
->
device
->
host
->
eh_action
);
up
(
scmd
->
device
->
host
->
eh_action
);
}
}
}
/**
/**
...
@@ -477,10 +426,10 @@ static void scsi_eh_done(Scsi_Cmnd *scmd)
...
@@ -477,10 +426,10 @@ static void scsi_eh_done(Scsi_Cmnd *scmd)
* Return value:
* Return value:
* SUCCESS or FAILED or NEEDS_RETRY
* SUCCESS or FAILED or NEEDS_RETRY
**/
**/
static
int
scsi_send_eh_cmnd
(
Scsi_C
mnd
*
scmd
,
int
timeout
)
static
int
scsi_send_eh_cmnd
(
struct
scsi_c
mnd
*
scmd
,
int
timeout
)
{
{
unsigned
long
flags
;
struct
Scsi_Host
*
host
=
scmd
->
device
->
host
;
struct
Scsi_Host
*
host
=
scmd
->
device
->
host
;
unsigned
long
flags
;
int
rtn
=
SUCCESS
;
int
rtn
=
SUCCESS
;
ASSERT_LOCK
(
host
->
host_lock
,
0
);
ASSERT_LOCK
(
host
->
host_lock
,
0
);
...
@@ -535,7 +484,8 @@ static int scsi_send_eh_cmnd(Scsi_Cmnd *scmd, int timeout)
...
@@ -535,7 +484,8 @@ static int scsi_send_eh_cmnd(Scsi_Cmnd *scmd, int timeout)
spin_lock_irqsave
(
scmd
->
device
->
host
->
host_lock
,
flags
);
spin_lock_irqsave
(
scmd
->
device
->
host
->
host_lock
,
flags
);
if
(
scmd
->
device
->
host
->
hostt
->
eh_abort_handler
)
if
(
scmd
->
device
->
host
->
hostt
->
eh_abort_handler
)
scmd
->
device
->
host
->
hostt
->
eh_abort_handler
(
scmd
);
scmd
->
device
->
host
->
hostt
->
eh_abort_handler
(
scmd
);
spin_unlock_irqrestore
(
scmd
->
device
->
host
->
host_lock
,
flags
);
spin_unlock_irqrestore
(
scmd
->
device
->
host
->
host_lock
,
flags
);
scmd
->
request
->
rq_status
=
RQ_SCSI_DONE
;
scmd
->
request
->
rq_status
=
RQ_SCSI_DONE
;
scmd
->
owner
=
SCSI_OWNER_ERROR_HANDLER
;
scmd
->
owner
=
SCSI_OWNER_ERROR_HANDLER
;
...
@@ -592,32 +542,33 @@ static int scsi_send_eh_cmnd(Scsi_Cmnd *scmd, int timeout)
...
@@ -592,32 +542,33 @@ static int scsi_send_eh_cmnd(Scsi_Cmnd *scmd, int timeout)
* that we obtain it on our own. This function will *not* return until
* that we obtain it on our own. This function will *not* return until
* the command either times out, or it completes.
* the command either times out, or it completes.
**/
**/
static
int
scsi_request_sense
(
Scsi_C
mnd
*
scmd
)
static
int
scsi_request_sense
(
struct
scsi_c
mnd
*
scmd
)
{
{
static
unsigned
char
generic_sense
[
6
]
=
static
unsigned
char
generic_sense
[
6
]
=
{
REQUEST_SENSE
,
0
,
0
,
0
,
255
,
0
};
{
REQUEST_SENSE
,
0
,
0
,
0
,
255
,
0
};
unsigned
char
scsi_result0
[
256
],
*
scsi_result
=
NULL
;
unsigned
char
scsi_result0
[
256
],
*
scsi_result
=
&
scsi_result0
[
0
]
;
int
saved_result
;
int
saved_result
;
int
rtn
;
int
rtn
;
memcpy
((
void
*
)
scmd
->
cmnd
,
(
void
*
)
generic_sense
,
memcpy
(
scmd
->
cmnd
,
generic_sense
,
sizeof
(
generic_sense
));
sizeof
(
generic_sense
));
scsi_result
=
(
!
scmd
->
device
->
host
->
hostt
->
unchecked_isa_dma
)
?
&
scsi_result0
[
0
]
:
kmalloc
(
512
,
GFP_ATOMIC
|
GFP_DMA
);
if
(
scsi_result
==
NULL
)
{
if
(
scmd
->
device
->
host
->
hostt
->
unchecked_isa_dma
)
{
printk
(
"%s: cannot allocate scsi_result.
\n
"
,
__FUNCTION__
);
scsi_result
=
kmalloc
(
512
,
GFP_ATOMIC
|
__GFP_DMA
);
return
FAILED
;
if
(
unlikely
(
!
scsi_result
))
{
printk
(
KERN_ERR
"%s: cannot allocate scsi_result.
\n
"
,
__FUNCTION__
);
return
FAILED
;
}
}
}
/*
/*
* zero the sense buffer. some host adapters automatically always
* zero the sense buffer. some host adapters automatically always
* request sense, so it is not a good idea that
* request sense, so it is not a good idea that
* scmd->request_buffer and scmd->sense_buffer point to the same
* scmd->request_buffer and scmd->sense_buffer point to the same
* address (db). 0 is not a valid sense code.
* address (db). 0 is not a valid sense code.
*/
*/
memset
(
(
void
*
)
scmd
->
sense_buffer
,
0
,
sizeof
(
scmd
->
sense_buffer
));
memset
(
scmd
->
sense_buffer
,
0
,
sizeof
(
scmd
->
sense_buffer
));
memset
(
(
void
*
)
scsi_result
,
0
,
256
);
memset
(
scsi_result
,
0
,
256
);
saved_result
=
scmd
->
result
;
saved_result
=
scmd
->
result
;
scmd
->
request_buffer
=
scsi_result
;
scmd
->
request_buffer
=
scsi_result
;
...
@@ -630,12 +581,12 @@ static int scsi_request_sense(Scsi_Cmnd *scmd)
...
@@ -630,12 +581,12 @@ static int scsi_request_sense(Scsi_Cmnd *scmd)
rtn
=
scsi_send_eh_cmnd
(
scmd
,
SENSE_TIMEOUT
);
rtn
=
scsi_send_eh_cmnd
(
scmd
,
SENSE_TIMEOUT
);
/* last chance to have valid sense data */
/* last chance to have valid sense data */
if
(
!
SCSI_SENSE_VALID
(
scmd
))
if
(
!
SCSI_SENSE_VALID
(
scmd
))
{
memcpy
(
(
void
*
)
scmd
->
sense
_buffer
,
memcpy
(
scmd
->
sense_buffer
,
scmd
->
request
_buffer
,
scmd
->
request_buffer
,
sizeof
(
scmd
->
sense_buffer
));
sizeof
(
scmd
->
sense_buffer
));
}
if
(
scsi_result
!=
&
scsi_result0
[
0
]
&&
scsi_result
!=
NULL
)
if
(
scsi_result
!=
&
scsi_result0
[
0
])
kfree
(
scsi_result
);
kfree
(
scsi_result
);
/*
/*
...
@@ -644,10 +595,6 @@ static int scsi_request_sense(Scsi_Cmnd *scmd)
...
@@ -644,10 +595,6 @@ static int scsi_request_sense(Scsi_Cmnd *scmd)
*/
*/
scsi_setup_cmd_retry
(
scmd
);
scsi_setup_cmd_retry
(
scmd
);
scmd
->
result
=
saved_result
;
scmd
->
result
=
saved_result
;
/*
* hey, we are done. let's look to see what happened.
*/
return
rtn
;
return
rtn
;
}
}
...
@@ -659,7 +606,7 @@ static int scsi_request_sense(Scsi_Cmnd *scmd)
...
@@ -659,7 +606,7 @@ static int scsi_request_sense(Scsi_Cmnd *scmd)
* This function will *not* return until the command either times out,
* This function will *not* return until the command either times out,
* or it completes.
* or it completes.
**/
**/
static
int
scsi_eh_retry_cmd
(
Scsi_C
mnd
*
scmd
)
static
int
scsi_eh_retry_cmd
(
struct
scsi_c
mnd
*
scmd
)
{
{
int
rtn
=
SUCCESS
;
int
rtn
=
SUCCESS
;
...
@@ -676,7 +623,7 @@ static int scsi_eh_retry_cmd(Scsi_Cmnd *scmd)
...
@@ -676,7 +623,7 @@ static int scsi_eh_retry_cmd(Scsi_Cmnd *scmd)
/**
/**
* scsi_eh_finish_cmd - Handle a cmd that eh is finished with.
* scsi_eh_finish_cmd - Handle a cmd that eh is finished with.
* @scmd: Original SCSI cmd that eh has finished.
* @scmd: Original SCSI cmd that eh has finished.
* @
shost: SCSI host that cmd originally failed on
.
* @
done_q: Queue for processed commands
.
*
*
* Notes:
* Notes:
* We don't want to use the normal command completion while we are are
* We don't want to use the normal command completion while we are are
...
@@ -685,10 +632,12 @@ static int scsi_eh_retry_cmd(Scsi_Cmnd *scmd)
...
@@ -685,10 +632,12 @@ static int scsi_eh_retry_cmd(Scsi_Cmnd *scmd)
* keep a list of pending commands for final completion, and once we
* keep a list of pending commands for final completion, and once we
* are ready to leave error handling we handle completion for real.
* are ready to leave error handling we handle completion for real.
**/
**/
static
void
scsi_eh_finish_cmd
(
Scsi_Cmnd
*
scmd
,
struct
Scsi_Host
*
shost
)
static
void
scsi_eh_finish_cmd
(
struct
scsi_cmnd
*
scmd
,
struct
list_head
*
done_q
)
{
{
shost
->
host_failed
--
;
s
cmd
->
device
->
host
->
host_failed
--
;
scmd
->
state
=
SCSI_STATE_BHQUEUE
;
scmd
->
state
=
SCSI_STATE_BHQUEUE
;
scsi_eh_eflags_clr_all
(
scmd
);
scsi_eh_eflags_clr_all
(
scmd
);
/*
/*
...
@@ -696,18 +645,18 @@ static void scsi_eh_finish_cmd(Scsi_Cmnd *scmd, struct Scsi_Host *shost)
...
@@ -696,18 +645,18 @@ static void scsi_eh_finish_cmd(Scsi_Cmnd *scmd, struct Scsi_Host *shost)
* things.
* things.
*/
*/
scsi_setup_cmd_retry
(
scmd
);
scsi_setup_cmd_retry
(
scmd
);
list_move_tail
(
&
scmd
->
eh_entry
,
done_q
);
}
}
/**
/**
* scsi_eh_get_sense - Get device sense data.
* scsi_eh_get_sense - Get device sense data.
* @
sc_todo: list of cmds that have failed
.
* @
work_q: Queue of commands to process
.
* @
shost: scsi host being recovered
.
* @
done_q: Queue of proccessed commands.
.
*
*
* Description:
* Description:
* See if we need to request sense information. if so, then get it
* See if we need to request sense information. if so, then get it
* now, so we have a better idea of what to do.
* now, so we have a better idea of what to do.
*
*
*
* Notes:
* Notes:
* This has the unfortunate side effect that if a shost adapter does
* This has the unfortunate side effect that if a shost adapter does
* not automatically request sense information, that we end up shutting
* not automatically request sense information, that we end up shutting
...
@@ -718,24 +667,26 @@ static void scsi_eh_finish_cmd(Scsi_Cmnd *scmd, struct Scsi_Host *shost)
...
@@ -718,24 +667,26 @@ static void scsi_eh_finish_cmd(Scsi_Cmnd *scmd, struct Scsi_Host *shost)
* this.
* this.
*
*
* In 2.5 this capability will be going away.
* In 2.5 this capability will be going away.
*
* Really? --hch
**/
**/
static
int
scsi_eh_get_sense
(
Scsi_Cmnd
*
sc_todo
,
struct
Scsi_Host
*
shost
)
static
int
scsi_eh_get_sense
(
struct
list_head
*
work_q
,
struct
list_head
*
done_q
)
{
{
struct
list_head
*
lh
,
*
lh_sf
;
struct
scsi_cmnd
*
scmd
;
int
rtn
;
int
rtn
;
Scsi_Cmnd
*
scmd
;
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s: checking to see if we need"
" to request sense
\n
"
,
__FUNCTION__
));
for
(
scmd
=
sc_todo
;
scmd
;
scmd
=
scmd
->
bh_next
)
{
list_for_each_safe
(
lh
,
lh_sf
,
work_q
)
{
if
(
!
scsi_eh_eflags_chk
(
scmd
,
SCSI_EH_CMD_FAILED
)
||
scmd
=
list_entry
(
lh
,
struct
scsi_cmnd
,
eh_entry
);
if
(
scsi_eh_eflags_chk
(
scmd
,
SCSI_EH_CANCEL_CMD
)
||
SCSI_SENSE_VALID
(
scmd
))
SCSI_SENSE_VALID
(
scmd
))
continue
;
continue
;
SCSI_LOG_ERROR_RECOVERY
(
2
,
printk
(
"%s: requesting sense"
SCSI_LOG_ERROR_RECOVERY
(
2
,
printk
(
"%s: requesting sense"
" for tgt: %d
\n
"
,
" for id: %d
\n
"
,
__FUNCTION__
,
scmd
->
device
->
id
));
current
->
comm
,
scmd
->
device
->
id
));
rtn
=
scsi_request_sense
(
scmd
);
rtn
=
scsi_request_sense
(
scmd
);
if
(
rtn
!=
SUCCESS
)
if
(
rtn
!=
SUCCESS
)
continue
;
continue
;
...
@@ -752,7 +703,7 @@ static int scsi_eh_get_sense(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
...
@@ -752,7 +703,7 @@ static int scsi_eh_get_sense(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
* upper level.
* upper level.
*/
*/
if
(
rtn
==
SUCCESS
)
if
(
rtn
==
SUCCESS
)
scsi_eh_finish_cmd
(
scmd
,
shost
);
scsi_eh_finish_cmd
(
scmd
,
done_q
);
if
(
rtn
!=
NEEDS_RETRY
)
if
(
rtn
!=
NEEDS_RETRY
)
continue
;
continue
;
...
@@ -771,10 +722,10 @@ static int scsi_eh_get_sense(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
...
@@ -771,10 +722,10 @@ static int scsi_eh_get_sense(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
/*
/*
* we eventually hand this one back to the top level.
* we eventually hand this one back to the top level.
*/
*/
scsi_eh_finish_cmd
(
scmd
,
shost
);
scsi_eh_finish_cmd
(
scmd
,
done_q
);
}
}
return
shost
->
host_failed
;
return
list_empty
(
work_q
)
;
}
}
/**
/**
...
@@ -788,14 +739,14 @@ static int scsi_eh_get_sense(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
...
@@ -788,14 +739,14 @@ static int scsi_eh_get_sense(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
* they can provide this facility themselves. helper functions in
* they can provide this facility themselves. helper functions in
* scsi_error.c can be supplied to make this easier to do.
* scsi_error.c can be supplied to make this easier to do.
**/
**/
static
int
scsi_try_to_abort_cmd
(
Scsi_C
mnd
*
scmd
)
static
int
scsi_try_to_abort_cmd
(
struct
scsi_c
mnd
*
scmd
)
{
{
int
rtn
=
FAILED
;
unsigned
long
flags
;
unsigned
long
flags
;
int
rtn
=
FAILED
;
if
(
scmd
->
device
->
host
->
hostt
->
eh_abort_handler
==
NULL
)
{
if
(
!
scmd
->
device
->
host
->
hostt
->
eh_abort_handler
)
return
rtn
;
return
rtn
;
}
/*
/*
* scsi_done was called just after the command timed out and before
* scsi_done was called just after the command timed out and before
* we had a chance to process it. (db)
* we had a chance to process it. (db)
...
@@ -808,6 +759,7 @@ static int scsi_try_to_abort_cmd(Scsi_Cmnd *scmd)
...
@@ -808,6 +759,7 @@ static int scsi_try_to_abort_cmd(Scsi_Cmnd *scmd)
spin_lock_irqsave
(
scmd
->
device
->
host
->
host_lock
,
flags
);
spin_lock_irqsave
(
scmd
->
device
->
host
->
host_lock
,
flags
);
rtn
=
scmd
->
device
->
host
->
hostt
->
eh_abort_handler
(
scmd
);
rtn
=
scmd
->
device
->
host
->
hostt
->
eh_abort_handler
(
scmd
);
spin_unlock_irqrestore
(
scmd
->
device
->
host
->
host_lock
,
flags
);
spin_unlock_irqrestore
(
scmd
->
device
->
host
->
host_lock
,
flags
);
return
rtn
;
return
rtn
;
}
}
...
@@ -818,22 +770,19 @@ static int scsi_try_to_abort_cmd(Scsi_Cmnd *scmd)
...
@@ -818,22 +770,19 @@ static int scsi_try_to_abort_cmd(Scsi_Cmnd *scmd)
* Return value:
* Return value:
* 0 - Device is ready. 1 - Device NOT ready.
* 0 - Device is ready. 1 - Device NOT ready.
**/
**/
static
int
scsi_eh_tur
(
Scsi_C
mnd
*
scmd
)
static
int
scsi_eh_tur
(
struct
scsi_c
mnd
*
scmd
)
{
{
static
unsigned
char
tur_command
[
6
]
=
static
unsigned
char
tur_command
[
6
]
=
{
TEST_UNIT_READY
,
0
,
0
,
0
,
0
,
0
};
{
TEST_UNIT_READY
,
0
,
0
,
0
,
0
,
0
};
int
retry_cnt
=
1
,
rtn
;
int
rtn
;
int
retry_cnt
=
1
;
retry_tur:
retry_tur:
memcpy
((
void
*
)
scmd
->
cmnd
,
(
void
*
)
tur_command
,
memcpy
(
scmd
->
cmnd
,
tur_command
,
sizeof
(
tur_command
));
sizeof
(
tur_command
));
/*
/*
* zero the sense buffer. the scsi spec mandates that any
* zero the sense buffer. the scsi spec mandates that any
* untransferred sense data should be interpreted as being zero.
* untransferred sense data should be interpreted as being zero.
*/
*/
memset
(
(
void
*
)
scmd
->
sense_buffer
,
0
,
sizeof
(
scmd
->
sense_buffer
));
memset
(
scmd
->
sense_buffer
,
0
,
sizeof
(
scmd
->
sense_buffer
));
scmd
->
request_buffer
=
NULL
;
scmd
->
request_buffer
=
NULL
;
scmd
->
request_bufflen
=
0
;
scmd
->
request_bufflen
=
0
;
...
@@ -864,9 +813,9 @@ static int scsi_eh_tur(Scsi_Cmnd *scmd)
...
@@ -864,9 +813,9 @@ static int scsi_eh_tur(Scsi_Cmnd *scmd)
}
}
/**
/**
* scsi_eh_abort_cmd - abort a timed-out cmd.
* scsi_eh_abort_cmds - abort canceled commands.
* @sc_todo: A list of cmds that have failed.
* @shost: scsi host being recovered.
* @shost: scsi host being recovered.
* @eh_done_q: list_head for processed commands.
*
*
* Decription:
* Decription:
* Try and see whether or not it makes sense to try and abort the
* Try and see whether or not it makes sense to try and abort the
...
@@ -875,29 +824,36 @@ static int scsi_eh_tur(Scsi_Cmnd *scmd)
...
@@ -875,29 +824,36 @@ static int scsi_eh_tur(Scsi_Cmnd *scmd)
* no sense to try and abort the command, since as far as the shost
* no sense to try and abort the command, since as far as the shost
* adapter is concerned, it isn't running.
* adapter is concerned, it isn't running.
**/
**/
static
int
scsi_eh_abort_cmd
(
Scsi_Cmnd
*
sc_todo
,
struct
Scsi_Host
*
shost
)
static
int
scsi_eh_abort_cmds
(
struct
list_head
*
work_q
,
struct
list_head
*
done_q
)
{
{
struct
list_head
*
lh
,
*
lh_sf
;
struct
scsi_cmnd
*
scmd
;
int
rtn
;
int
rtn
;
Scsi_Cmnd
*
scmd
;
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s: checking to see if we need"
" to abort cmd
\n
"
,
__FUNCTION__
));
for
(
scmd
=
sc_todo
;
scmd
;
scmd
=
scmd
->
bh_next
)
{
list_for_each_safe
(
lh
,
lh_sf
,
work_q
)
{
if
(
!
scsi_eh_eflags_chk
(
scmd
,
SCSI_EH_CMD_TIMEOUT
))
scmd
=
list_entry
(
lh
,
struct
scsi_cmnd
,
eh_entry
);
if
(
!
scsi_eh_eflags_chk
(
scmd
,
SCSI_EH_CANCEL_CMD
))
continue
;
continue
;
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s: aborting cmd:"
"0x%p
\n
"
,
current
->
comm
,
scmd
));
rtn
=
scsi_try_to_abort_cmd
(
scmd
);
rtn
=
scsi_try_to_abort_cmd
(
scmd
);
if
(
rtn
==
SUCCESS
)
{
if
(
rtn
==
SUCCESS
)
{
if
(
!
scsi_eh_tur
(
scmd
))
{
scsi_eh_eflags_clr
(
scmd
,
SCSI_EH_CANCEL_CMD
);
rtn
=
scsi_eh_retry_cmd
(
scmd
);
if
(
!
scmd
->
device
->
online
||
!
scsi_eh_tur
(
scmd
))
{
if
(
rtn
==
SUCCESS
)
scsi_eh_finish_cmd
(
scmd
,
done_q
);
scsi_eh_finish_cmd
(
scmd
,
shost
);
}
}
}
}
else
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s: aborting"
" cmd failed:"
"0x%p
\n
"
,
current
->
comm
,
scmd
));
}
}
return
shost
->
host_failed
;
return
list_empty
(
work_q
);
}
}
/**
/**
...
@@ -910,14 +866,14 @@ static int scsi_eh_abort_cmd(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
...
@@ -910,14 +866,14 @@ static int scsi_eh_abort_cmd(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
* timer on it, and set the host back to a consistent state prior to
* timer on it, and set the host back to a consistent state prior to
* returning.
* returning.
**/
**/
static
int
scsi_try_bus_device_reset
(
Scsi_C
mnd
*
scmd
)
static
int
scsi_try_bus_device_reset
(
struct
scsi_c
mnd
*
scmd
)
{
{
unsigned
long
flags
;
unsigned
long
flags
;
int
rtn
=
FAILED
;
int
rtn
=
FAILED
;
if
(
scmd
->
device
->
host
->
hostt
->
eh_device_reset_handler
==
NULL
)
{
if
(
!
scmd
->
device
->
host
->
hostt
->
eh_device_reset_handler
)
return
rtn
;
return
rtn
;
}
scmd
->
owner
=
SCSI_OWNER_LOWLEVEL
;
scmd
->
owner
=
SCSI_OWNER_LOWLEVEL
;
spin_lock_irqsave
(
scmd
->
device
->
host
->
host_lock
,
flags
);
spin_lock_irqsave
(
scmd
->
device
->
host
->
host_lock
,
flags
);
...
@@ -933,9 +889,9 @@ static int scsi_try_bus_device_reset(Scsi_Cmnd *scmd)
...
@@ -933,9 +889,9 @@ static int scsi_try_bus_device_reset(Scsi_Cmnd *scmd)
}
}
/**
/**
* scsi_eh_bus_device_reset - send bdr is needed
* scsi_eh_bus_device_reset - send bdr if needed
* @sc_todo: a list of cmds that have failed.
* @shost: scsi host being recovered.
* @shost: scsi host being recovered.
* @eh_done_q: list_head for processed commands.
*
*
* Notes:
* Notes:
* Try a bus device reset. still, look to see whether we have multiple
* Try a bus device reset. still, look to see whether we have multiple
...
@@ -943,57 +899,70 @@ static int scsi_try_bus_device_reset(Scsi_Cmnd *scmd)
...
@@ -943,57 +899,70 @@ static int scsi_try_bus_device_reset(Scsi_Cmnd *scmd)
* makes no sense to try bus_device_reset - we really would need to try
* makes no sense to try bus_device_reset - we really would need to try
* a bus_reset instead.
* a bus_reset instead.
**/
**/
static
int
scsi_eh_bus_device_reset
(
Scsi_Cmnd
*
sc_todo
,
struct
Scsi_Host
*
shost
)
static
int
scsi_eh_bus_device_reset
(
struct
Scsi_Host
*
shost
,
struct
list_head
*
work_q
,
struct
list_head
*
done_q
)
{
{
struct
list_head
*
lh
,
*
lh_sf
;
struct
scsi_cmnd
*
scmd
,
*
bdr_scmd
;
struct
scsi_device
*
sdev
;
int
rtn
;
int
rtn
;
Scsi_Cmnd
*
scmd
;
Scsi_Device
*
sdev
;
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s: Trying BDR
\n
"
,
__FUNCTION__
));
list_for_each_entry
(
sdev
,
&
shost
->
my_devices
,
siblings
)
{
list_for_each_entry
(
sdev
,
&
shost
->
my_devices
,
siblings
)
{
for
(
scmd
=
sc_todo
;
scmd
;
scmd
=
scmd
->
bh_next
)
bdr_scmd
=
NULL
;
if
((
scmd
->
device
==
sdev
)
&&
list_for_each_entry
(
scmd
,
work_q
,
eh_entry
)
scsi_eh_eflags_chk
(
scmd
,
SCSI_EH_CMD_ERR
))
if
(
scmd
->
device
==
sdev
)
{
bdr_scmd
=
scmd
;
break
;
break
;
}
if
(
!
scmd
)
if
(
!
bdr_
scmd
)
continue
;
continue
;
/*
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s: Sending BDR sdev:"
* ok, we have a device that is having problems. try and send
" 0x%p
\n
"
,
current
->
comm
,
* a bus device reset to it.
sdev
));
*/
rtn
=
scsi_try_bus_device_reset
(
bdr_scmd
);
rtn
=
scsi_try_bus_device_reset
(
scmd
);
if
(
rtn
==
SUCCESS
)
{
if
((
rtn
==
SUCCESS
)
&&
(
!
scsi_eh_tur
(
scmd
)))
if
(
!
sdev
->
online
||
!
scsi_eh_tur
(
bdr_scmd
))
{
for
(
scmd
=
sc_todo
;
scmd
;
scmd
=
scmd
->
bh_next
)
list_for_each_safe
(
lh
,
lh_sf
,
if
((
scmd
->
device
==
sdev
)
&&
work_q
)
{
scsi_eh_eflags_chk
(
scmd
,
SCSI_EH_CMD_ERR
))
{
scmd
=
list_entry
(
lh
,
struct
rtn
=
scsi_eh_retry_cmd
(
scmd
);
scsi_cmnd
,
if
(
rtn
==
SUCCESS
)
eh_entry
);
scsi_eh_finish_cmd
(
scmd
,
shost
);
if
(
scmd
->
device
==
sdev
)
}
scsi_eh_finish_cmd
(
scmd
,
done_q
);
}
}
}
else
{
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s: BDR"
" failed sdev:"
"0x%p
\n
"
,
current
->
comm
,
sdev
));
}
}
}
return
shost
->
host_failed
;
return
list_empty
(
work_q
)
;
}
}
/**
/**
* scsi_try_bus_reset - ask host to perform a bus reset
* scsi_try_bus_reset - ask host to perform a bus reset
* @scmd: SCSI cmd to send bus reset.
* @scmd: SCSI cmd to send bus reset.
**/
**/
static
int
scsi_try_bus_reset
(
Scsi_C
mnd
*
scmd
)
static
int
scsi_try_bus_reset
(
struct
scsi_c
mnd
*
scmd
)
{
{
struct
scsi_device
*
sdev
;
unsigned
long
flags
;
unsigned
long
flags
;
int
rtn
;
int
rtn
;
Scsi_Device
*
sdev
;
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s: Snd Bus RST
\n
"
,
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s: Snd Bus RST
\n
"
,
__FUNCTION__
));
__FUNCTION__
));
scmd
->
owner
=
SCSI_OWNER_LOWLEVEL
;
scmd
->
owner
=
SCSI_OWNER_LOWLEVEL
;
scmd
->
serial_number_at_timeout
=
scmd
->
serial_number
;
scmd
->
serial_number_at_timeout
=
scmd
->
serial_number
;
if
(
scmd
->
device
->
host
->
hostt
->
eh_bus_reset_handler
==
NULL
)
if
(
!
scmd
->
device
->
host
->
hostt
->
eh_bus_reset_handler
)
return
FAILED
;
return
FAILED
;
spin_lock_irqsave
(
scmd
->
device
->
host
->
host_lock
,
flags
);
spin_lock_irqsave
(
scmd
->
device
->
host
->
host_lock
,
flags
);
...
@@ -1005,7 +974,8 @@ static int scsi_try_bus_reset(Scsi_Cmnd *scmd)
...
@@ -1005,7 +974,8 @@ static int scsi_try_bus_reset(Scsi_Cmnd *scmd)
/*
/*
* Mark all affected devices to expect a unit attention.
* Mark all affected devices to expect a unit attention.
*/
*/
list_for_each_entry
(
sdev
,
&
scmd
->
device
->
host
->
my_devices
,
siblings
)
list_for_each_entry
(
sdev
,
&
scmd
->
device
->
host
->
my_devices
,
siblings
)
if
(
scmd
->
device
->
channel
==
sdev
->
channel
)
{
if
(
scmd
->
device
->
channel
==
sdev
->
channel
)
{
sdev
->
was_reset
=
1
;
sdev
->
was_reset
=
1
;
sdev
->
expecting_cc_ua
=
1
;
sdev
->
expecting_cc_ua
=
1
;
...
@@ -1018,18 +988,18 @@ static int scsi_try_bus_reset(Scsi_Cmnd *scmd)
...
@@ -1018,18 +988,18 @@ static int scsi_try_bus_reset(Scsi_Cmnd *scmd)
* scsi_try_host_reset - ask host adapter to reset itself
* scsi_try_host_reset - ask host adapter to reset itself
* @scmd: SCSI cmd to send hsot reset.
* @scmd: SCSI cmd to send hsot reset.
**/
**/
static
int
scsi_try_host_reset
(
Scsi_C
mnd
*
scmd
)
static
int
scsi_try_host_reset
(
struct
scsi_c
mnd
*
scmd
)
{
{
struct
scsi_device
*
sdev
;
unsigned
long
flags
;
unsigned
long
flags
;
int
rtn
;
int
rtn
;
Scsi_Device
*
sdev
;
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s: Snd Host RST
\n
"
,
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s: Snd Host RST
\n
"
,
__FUNCTION__
));
__FUNCTION__
));
scmd
->
owner
=
SCSI_OWNER_LOWLEVEL
;
scmd
->
owner
=
SCSI_OWNER_LOWLEVEL
;
scmd
->
serial_number_at_timeout
=
scmd
->
serial_number
;
scmd
->
serial_number_at_timeout
=
scmd
->
serial_number
;
if
(
scmd
->
device
->
host
->
hostt
->
eh_host_reset_handler
==
NULL
)
if
(
!
scmd
->
device
->
host
->
hostt
->
eh_host_reset_handler
)
return
FAILED
;
return
FAILED
;
spin_lock_irqsave
(
scmd
->
device
->
host
->
host_lock
,
flags
);
spin_lock_irqsave
(
scmd
->
device
->
host
->
host_lock
,
flags
);
...
@@ -1041,7 +1011,8 @@ static int scsi_try_host_reset(Scsi_Cmnd *scmd)
...
@@ -1041,7 +1011,8 @@ static int scsi_try_host_reset(Scsi_Cmnd *scmd)
/*
/*
* Mark all affected devices to expect a unit attention.
* Mark all affected devices to expect a unit attention.
*/
*/
list_for_each_entry
(
sdev
,
&
scmd
->
device
->
host
->
my_devices
,
siblings
)
list_for_each_entry
(
sdev
,
&
scmd
->
device
->
host
->
my_devices
,
siblings
)
if
(
scmd
->
device
->
channel
==
sdev
->
channel
)
{
if
(
scmd
->
device
->
channel
==
sdev
->
channel
)
{
sdev
->
was_reset
=
1
;
sdev
->
was_reset
=
1
;
sdev
->
expecting_cc_ua
=
1
;
sdev
->
expecting_cc_ua
=
1
;
...
@@ -1051,26 +1022,21 @@ static int scsi_try_host_reset(Scsi_Cmnd *scmd)
...
@@ -1051,26 +1022,21 @@ static int scsi_try_host_reset(Scsi_Cmnd *scmd)
}
}
/**
/**
* scsi_eh_bus_host_reset - send a bus reset and on failure try host reset
* scsi_eh_bus_reset - send a bus reset
* @sc_todo: a list of cmds that have failed.
* @shost: scsi host being recovered.
* @shost: scsi host being recovered.
* @eh_done_q: list_head for processed commands.
**/
**/
static
int
scsi_eh_bus_host_reset
(
Scsi_Cmnd
*
sc_todo
,
struct
Scsi_Host
*
shost
)
static
int
scsi_eh_bus_reset
(
struct
Scsi_Host
*
shost
,
struct
list_head
*
work_q
,
struct
list_head
*
done_q
)
{
{
int
rtn
;
struct
list_head
*
lh
,
*
lh_sf
;
Scsi_C
mnd
*
scmd
;
struct
scsi_c
mnd
*
scmd
;
Scsi_C
mnd
*
chan_scmd
;
struct
scsi_c
mnd
*
chan_scmd
;
unsigned
int
channel
;
unsigned
int
channel
;
int
rtn
;
/*
/*
* if we ended up here, we have serious problems. the only thing left
* to try is a full bus reset. if someone has grabbed the bus and isn't
* letting go, then perhaps this will help.
*/
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s: Try Bus/Host RST
\n
"
,
__FUNCTION__
));
/*
* we really want to loop over the various channels, and do this on
* we really want to loop over the various channels, and do this on
* a channel by channel basis. we should also check to see if any
* a channel by channel basis. we should also check to see if any
* of the failed commands are on soft_reset devices, and if so, skip
* of the failed commands are on soft_reset devices, and if so, skip
...
@@ -1078,9 +1044,8 @@ static int scsi_eh_bus_host_reset(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
...
@@ -1078,9 +1044,8 @@ static int scsi_eh_bus_host_reset(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
*/
*/
for
(
channel
=
0
;
channel
<=
shost
->
max_channel
;
channel
++
)
{
for
(
channel
=
0
;
channel
<=
shost
->
max_channel
;
channel
++
)
{
for
(
scmd
=
sc_todo
;
scmd
;
scmd
=
scmd
->
bh_next
)
{
chan_scmd
=
NULL
;
if
(
!
scsi_eh_eflags_chk
(
scmd
,
SCSI_EH_CMD_ERR
))
list_for_each_entry
(
scmd
,
work_q
,
eh_entry
)
{
continue
;
if
(
channel
==
scmd
->
device
->
channel
)
{
if
(
channel
==
scmd
->
device
->
channel
)
{
chan_scmd
=
scmd
;
chan_scmd
=
scmd
;
break
;
break
;
...
@@ -1091,63 +1056,95 @@ static int scsi_eh_bus_host_reset(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
...
@@ -1091,63 +1056,95 @@ static int scsi_eh_bus_host_reset(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
}
}
}
}
if
(
!
scmd
)
if
(
!
chan_
scmd
)
continue
;
continue
;
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s: Sending BRST chan:"
" %d
\n
"
,
current
->
comm
,
channel
));
rtn
=
scsi_try_bus_reset
(
chan_scmd
);
if
(
rtn
==
SUCCESS
)
{
list_for_each_safe
(
lh
,
lh_sf
,
work_q
)
{
scmd
=
list_entry
(
lh
,
struct
scsi_cmnd
,
eh_entry
);
if
(
channel
==
scmd
->
device
->
channel
)
if
(
!
scmd
->
device
->
online
||
!
scsi_eh_tur
(
scmd
))
scsi_eh_finish_cmd
(
scmd
,
done_q
);
}
}
else
{
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s: BRST"
" failed chan: %d
\n
"
,
current
->
comm
,
channel
));
}
}
return
list_empty
(
work_q
);
}
/*
/**
* we now know that we are able to perform a reset for the
* scsi_eh_host_reset - send a host reset
* channel that scmd points to.
* @work_q: list_head for processed commands.
*/
* @done_q: list_head for processed commands.
rtn
=
scsi_try_bus_reset
(
scmd
);
**/
if
(
rtn
!=
SUCCESS
)
static
int
scsi_eh_host_reset
(
struct
list_head
*
work_q
,
rtn
=
scsi_try_host_reset
(
scmd
);
struct
list_head
*
done_q
)
{
int
rtn
;
struct
list_head
*
lh
,
*
lh_sf
;
struct
scsi_cmnd
*
scmd
;
if
(
!
list_empty
(
work_q
))
{
scmd
=
list_entry
(
work_q
->
next
,
struct
scsi_cmnd
,
eh_entry
);
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s: Sending HRST
\n
"
,
current
->
comm
));
rtn
=
scsi_try_host_reset
(
scmd
);
if
(
rtn
==
SUCCESS
)
{
if
(
rtn
==
SUCCESS
)
{
for
(
scmd
=
sc_todo
;
scmd
;
scmd
=
scmd
->
bh_next
)
{
list_for_each_safe
(
lh
,
lh_sf
,
work_q
)
{
if
(
!
scsi_eh_eflags_chk
(
scmd
,
SCSI_EH_CMD_ERR
)
scmd
=
list_entry
(
lh
,
struct
scsi_cmnd
,
eh_entry
);
||
channel
!=
scmd
->
device
->
channel
)
if
(
!
scmd
->
device
->
online
||
!
scsi_eh_tur
(
scmd
))
continue
;
scsi_eh_finish_cmd
(
scmd
,
done_q
);
if
(
!
scsi_eh_tur
(
scmd
))
{
rtn
=
scsi_eh_retry_cmd
(
scmd
);
if
(
rtn
==
SUCCESS
)
scsi_eh_finish_cmd
(
scmd
,
shost
);
}
}
}
}
else
{
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s: HRST"
" failed
\n
"
,
current
->
comm
));
}
}
}
}
return
shost
->
host_failed
;
return
list_empty
(
work_q
)
;
}
}
/**
/**
* scsi_eh_offline_sdevs - offline scsi devices that fail to recover
* scsi_eh_offline_sdevs - offline scsi devices that fail to recover
* @
sc_todo: a list of cmds that have failed
.
* @
work_q: list_head for processed commands
.
* @
shost: scsi host being recovered
.
* @
done_q: list_head for processed commands
.
*
*
**/
**/
static
void
scsi_eh_offline_sdevs
(
Scsi_Cmnd
*
sc_todo
,
struct
Scsi_Host
*
shost
)
static
void
scsi_eh_offline_sdevs
(
struct
list_head
*
work_q
,
struct
list_head
*
done_q
)
{
{
Scsi_Cmnd
*
scmd
;
struct
list_head
*
lh
,
*
lh_sf
;
struct
scsi_cmnd
*
scmd
;
for
(
scmd
=
sc_todo
;
scmd
;
scmd
=
scmd
->
bh_next
)
{
if
(
!
scsi_eh_eflags_chk
(
scmd
,
SCSI_EH_CMD_ERR
))
continue
;
list_for_each_safe
(
lh
,
lh_sf
,
work_q
)
{
scmd
=
list_entry
(
lh
,
struct
scsi_cmnd
,
eh_entry
);
printk
(
KERN_INFO
"scsi: Device offlined - not"
printk
(
KERN_INFO
"scsi: Device offlined - not"
" ready or command retry failed"
" ready after error recovery: host"
" after error recovery: host"
" %d channel %d id %d lun %d
\n
"
,
" %d channel %d id %d lun %d
\n
"
,
shost
->
host_no
,
s
cmd
->
device
->
host
->
host_no
,
scmd
->
device
->
channel
,
scmd
->
device
->
channel
,
scmd
->
device
->
id
,
scmd
->
device
->
id
,
scmd
->
device
->
lun
);
scmd
->
device
->
lun
);
scmd
->
device
->
online
=
FALSE
;
if
(
scsi_eh_eflags_chk
(
scmd
,
SCSI_EH_CMD_TIMEOUT
))
if
(
scsi_eh_eflags_chk
(
scmd
,
SCSI_EH_CANCEL_CMD
))
{
scmd
->
result
|=
(
DRIVER_TIMEOUT
<<
24
);
/*
* FIXME: Handle lost cmds.
scmd
->
device
->
online
=
0
;
*/
scsi_eh_finish_cmd
(
scmd
,
shost
);
}
scsi_eh_finish_cmd
(
scmd
,
done_q
);
}
}
return
;
return
;
}
}
...
@@ -1157,12 +1154,12 @@ static void scsi_eh_offline_sdevs(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
...
@@ -1157,12 +1154,12 @@ static void scsi_eh_offline_sdevs(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
* @sem: semphore to signal
* @sem: semphore to signal
*
*
**/
**/
static
static
void
scsi_sleep_done
(
unsigned
long
data
)
void
scsi_sleep_done
(
struct
semaphore
*
sem
)
{
{
if
(
sem
!=
NULL
)
{
struct
semaphore
*
sem
=
(
struct
semaphore
*
)
data
;
if
(
sem
)
up
(
sem
);
up
(
sem
);
}
}
}
/**
/**
...
@@ -1176,9 +1173,9 @@ void scsi_sleep(int timeout)
...
@@ -1176,9 +1173,9 @@ void scsi_sleep(int timeout)
struct
timer_list
timer
;
struct
timer_list
timer
;
init_timer
(
&
timer
);
init_timer
(
&
timer
);
timer
.
data
=
(
unsigned
long
)
&
sem
;
timer
.
data
=
(
unsigned
long
)
&
sem
;
timer
.
expires
=
jiffies
+
timeout
;
timer
.
expires
=
jiffies
+
timeout
;
timer
.
function
=
(
void
(
*
)(
unsigned
long
))
scsi_sleep_done
;
timer
.
function
=
(
void
(
*
)(
unsigned
long
))
scsi_sleep_done
;
SCSI_LOG_ERROR_RECOVERY
(
5
,
printk
(
"sleeping for timer tics %d
\n
"
,
SCSI_LOG_ERROR_RECOVERY
(
5
,
printk
(
"sleeping for timer tics %d
\n
"
,
timeout
));
timeout
));
...
@@ -1203,7 +1200,7 @@ void scsi_sleep(int timeout)
...
@@ -1203,7 +1200,7 @@ void scsi_sleep(int timeout)
* doesn't require the error handler read (i.e. we don't need to
* doesn't require the error handler read (i.e. we don't need to
* abort/reset), then this function should return SUCCESS.
* abort/reset), then this function should return SUCCESS.
**/
**/
int
scsi_decide_disposition
(
Scsi_C
mnd
*
scmd
)
int
scsi_decide_disposition
(
struct
scsi_c
mnd
*
scmd
)
{
{
int
rtn
;
int
rtn
;
...
@@ -1403,7 +1400,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
...
@@ -1403,7 +1400,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
{
{
struct
scsi_request
*
sreq
=
scsi_allocate_request
(
sdev
);
struct
scsi_request
*
sreq
=
scsi_allocate_request
(
sdev
);
if
(
sreq
==
NULL
)
{
if
(
unlikely
(
!
sreq
)
)
{
printk
(
KERN_ERR
"%s: request allocate failed,"
printk
(
KERN_ERR
"%s: request allocate failed,"
"prevent media removal cmd not sent"
,
__FUNCTION__
);
"prevent media removal cmd not sent"
,
__FUNCTION__
);
return
;
return
;
...
@@ -1437,7 +1434,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
...
@@ -1437,7 +1434,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
**/
**/
static
void
scsi_restart_operations
(
struct
Scsi_Host
*
shost
)
static
void
scsi_restart_operations
(
struct
Scsi_Host
*
shost
)
{
{
Scsi_D
evice
*
sdev
;
struct
scsi_d
evice
*
sdev
;
unsigned
long
flags
;
unsigned
long
flags
;
ASSERT_LOCK
(
shost
->
host_lock
,
0
);
ASSERT_LOCK
(
shost
->
host_lock
,
0
);
...
@@ -1459,6 +1456,8 @@ static void scsi_restart_operations(struct Scsi_Host *shost)
...
@@ -1459,6 +1456,8 @@ static void scsi_restart_operations(struct Scsi_Host *shost)
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s: waking up host to restart
\n
"
,
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s: waking up host to restart
\n
"
,
__FUNCTION__
));
__FUNCTION__
));
shost
->
in_recovery
=
0
;
wake_up
(
&
shost
->
host_wait
);
wake_up
(
&
shost
->
host_wait
);
/*
/*
...
@@ -1481,6 +1480,55 @@ static void scsi_restart_operations(struct Scsi_Host *shost)
...
@@ -1481,6 +1480,55 @@ static void scsi_restart_operations(struct Scsi_Host *shost)
spin_unlock_irqrestore
(
shost
->
host_lock
,
flags
);
spin_unlock_irqrestore
(
shost
->
host_lock
,
flags
);
}
}
/**
* scsi_eh_ready_devs - check device ready state and recover if not.
* @shost: host to be recovered.
* @eh_done_q: list_head for processed commands.
*
**/
static
void
scsi_eh_ready_devs
(
struct
Scsi_Host
*
shost
,
struct
list_head
*
work_q
,
struct
list_head
*
done_q
)
{
if
(
scsi_eh_bus_device_reset
(
shost
,
work_q
,
done_q
))
if
(
scsi_eh_bus_reset
(
shost
,
work_q
,
done_q
))
if
(
scsi_eh_host_reset
(
work_q
,
done_q
))
scsi_eh_offline_sdevs
(
work_q
,
done_q
);
}
/**
* scsi_eh_flush_done_q - finish processed commands or retry them.
* @done_q: list_head of processed commands.
*
**/
static
void
scsi_eh_flush_done_q
(
struct
list_head
*
done_q
)
{
struct
list_head
*
lh
,
*
lh_sf
;
struct
scsi_cmnd
*
scmd
;
list_for_each_safe
(
lh
,
lh_sf
,
done_q
)
{
scmd
=
list_entry
(
lh
,
struct
scsi_cmnd
,
eh_entry
);
list_del_init
(
lh
);
if
(
!
scmd
->
device
->
online
)
{
scmd
->
result
|=
(
DRIVER_TIMEOUT
<<
24
);
}
else
{
if
(
++
scmd
->
retries
<
scmd
->
allowed
)
{
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s: flush retry"
" cmd: %p
\n
"
,
current
->
comm
,
scmd
));
scsi_queue_insert
(
scmd
,
SCSI_MLQUEUE_EH_RETRY
);
continue
;
}
}
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"%s: flush finish"
" cmd: %p
\n
"
,
current
->
comm
,
scmd
));
scsi_finish_command
(
scmd
);
}
}
/**
/**
* scsi_unjam_host - Attempt to fix a host which has a cmd that failed.
* scsi_unjam_host - Attempt to fix a host which has a cmd that failed.
* @shost: Host to unjam.
* @shost: Host to unjam.
...
@@ -1506,60 +1554,21 @@ static void scsi_restart_operations(struct Scsi_Host *shost)
...
@@ -1506,60 +1554,21 @@ static void scsi_restart_operations(struct Scsi_Host *shost)
**/
**/
static
void
scsi_unjam_host
(
struct
Scsi_Host
*
shost
)
static
void
scsi_unjam_host
(
struct
Scsi_Host
*
shost
)
{
{
Scsi_Cmnd
*
sc_todo
=
NULL
;
unsigned
long
flags
;
Scsi_Cmnd
*
scmd
;
LIST_HEAD
(
eh_work_q
);
LIST_HEAD
(
eh_done_q
);
/*
* Is this assert really ok anymore (andmike). Should we at least
* be using spin_lock_unlocked.
*/
ASSERT_LOCK
(
shost
->
host_lock
,
0
);
scsi_eh_get_failed
(
&
sc_todo
,
shost
);
if
(
scsi_eh_get_sense
(
sc_todo
,
shost
))
if
(
scsi_eh_abort_cmd
(
sc_todo
,
shost
))
if
(
scsi_eh_bus_device_reset
(
sc_todo
,
shost
))
if
(
scsi_eh_bus_host_reset
(
sc_todo
,
shost
))
scsi_eh_offline_sdevs
(
sc_todo
,
shost
);
BUG_ON
(
shost
->
host_failed
);
spin_lock_irqsave
(
shost
->
host_lock
,
flags
);
list_splice_init
(
&
shost
->
eh_cmd_q
,
&
eh_work_q
);
spin_unlock_irqrestore
(
shost
->
host_lock
,
flags
);
/*
SCSI_LOG_ERROR_RECOVERY
(
1
,
scsi_eh_prt_fail_stats
(
shost
,
&
eh_work_q
));
* We are currently holding these things in a linked list - we
* didn't put them in the bottom half queue because we wanted to
* keep things quiet while we were working on recovery, and
* passing them up to the top level could easily cause the top
* level to try and queue something else again.
*
* start by marking that the host is no longer in error recovery.
*/
shost
->
in_recovery
=
0
;
/*
if
(
!
scsi_eh_get_sense
(
&
eh_work_q
,
&
eh_done_q
))
* take the list of commands, and stick them in the bottom half queue.
if
(
!
scsi_eh_abort_cmds
(
&
eh_work_q
,
&
eh_done_q
))
* the current implementation of scsi_done will do this for us - if need
scsi_eh_ready_devs
(
shost
,
&
eh_work_q
,
&
eh_done_q
);
* be we can create a special version of this function to do the
* same job for us.
*/
for
(
scmd
=
sc_todo
;
scmd
;
scmd
=
sc_todo
)
{
sc_todo
=
scmd
->
bh_next
;
scmd
->
bh_next
=
NULL
;
/*
* Oh, this is a vile hack. scsi_done() expects a timer
* to be running on the command. If there isn't, it assumes
* that the command has actually timed out, and a timer
* handler is running. That may well be how we got into
* this fix, but right now things are stable. We add
* a timer back again so that we can report completion.
* scsi_done() will immediately remove said timer from
* the command, and then process it.
*/
scsi_add_timer
(
scmd
,
100
,
scsi_eh_times_out
);
scsi_done
(
scmd
);
}
scsi_eh_flush_done_q
(
&
eh_done_q
);
}
}
/**
/**
...
@@ -1597,7 +1606,8 @@ void scsi_error_handler(void *data)
...
@@ -1597,7 +1606,8 @@ void scsi_error_handler(void *data)
/*
/*
* Wake up the thread that created us.
* Wake up the thread that created us.
*/
*/
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"Wake up parent of scsi_eh_%d
\n
"
,
shost
->
host_no
));
SCSI_LOG_ERROR_RECOVERY
(
3
,
printk
(
"Wake up parent of"
" scsi_eh_%d
\n
"
,
shost
->
host_no
));
complete
(
shost
->
eh_notify
);
complete
(
shost
->
eh_notify
);
...
@@ -1607,7 +1617,9 @@ void scsi_error_handler(void *data)
...
@@ -1607,7 +1617,9 @@ void scsi_error_handler(void *data)
* away and die. This typically happens if the user is
* away and die. This typically happens if the user is
* trying to unload a module.
* trying to unload a module.
*/
*/
SCSI_LOG_ERROR_RECOVERY
(
1
,
printk
(
"Error handler scsi_eh_%d sleeping
\n
"
,
shost
->
host_no
));
SCSI_LOG_ERROR_RECOVERY
(
1
,
printk
(
"Error handler"
" scsi_eh_%d"
" sleeping
\n
"
,
shost
->
host_no
));
/*
/*
* Note - we always use down_interruptible with the semaphore
* Note - we always use down_interruptible with the semaphore
...
@@ -1622,7 +1634,9 @@ void scsi_error_handler(void *data)
...
@@ -1622,7 +1634,9 @@ void scsi_error_handler(void *data)
if
(
shost
->
eh_kill
)
if
(
shost
->
eh_kill
)
break
;
break
;
SCSI_LOG_ERROR_RECOVERY
(
1
,
printk
(
"Error handler scsi_eh_%d waking up
\n
"
,
shost
->
host_no
));
SCSI_LOG_ERROR_RECOVERY
(
1
,
printk
(
"Error handler"
" scsi_eh_%d waking"
" up
\n
"
,
shost
->
host_no
));
shost
->
eh_active
=
1
;
shost
->
eh_active
=
1
;
...
@@ -1631,11 +1645,10 @@ void scsi_error_handler(void *data)
...
@@ -1631,11 +1645,10 @@ void scsi_error_handler(void *data)
* what we need to do to get it up and online again (if we can).
* what we need to do to get it up and online again (if we can).
* If we fail, we end up taking the thing offline.
* If we fail, we end up taking the thing offline.
*/
*/
if
(
shost
->
hostt
->
eh_strategy_handler
!=
NULL
)
{
if
(
shost
->
hostt
->
eh_strategy_handler
)
rtn
=
shost
->
hostt
->
eh_strategy_handler
(
shost
);
rtn
=
shost
->
hostt
->
eh_strategy_handler
(
shost
);
}
else
{
else
scsi_unjam_host
(
shost
);
scsi_unjam_host
(
shost
);
}
shost
->
eh_active
=
0
;
shost
->
eh_active
=
0
;
...
@@ -1650,7 +1663,8 @@ void scsi_error_handler(void *data)
...
@@ -1650,7 +1663,8 @@ void scsi_error_handler(void *data)
}
}
SCSI_LOG_ERROR_RECOVERY
(
1
,
printk
(
"Error handler scsi_eh_%d exiting
\n
"
,
shost
->
host_no
));
SCSI_LOG_ERROR_RECOVERY
(
1
,
printk
(
"Error handler scsi_eh_%d"
" exiting
\n
"
,
shost
->
host_no
));
/*
/*
* Make sure that nobody tries to wake us up again.
* Make sure that nobody tries to wake us up again.
...
@@ -1675,45 +1689,8 @@ void scsi_error_handler(void *data)
...
@@ -1675,45 +1689,8 @@ void scsi_error_handler(void *data)
complete_and_exit
(
shost
->
eh_notify
,
0
);
complete_and_exit
(
shost
->
eh_notify
,
0
);
}
}
/**
* scsi_new_reset - Send reset to a bus or device at any phase.
* @scmd: Cmd to send reset with (usually a dummy)
* @flag: Reset type.
*
* Description:
* This is used by the SCSI Generic driver to provide Bus/Device reset
* capability.
*
* Return value:
* SUCCESS/FAILED.
**/
static
int
scsi_new_reset
(
Scsi_Cmnd
*
scmd
,
int
flag
)
{
int
rtn
;
switch
(
flag
)
{
case
SCSI_TRY_RESET_DEVICE
:
rtn
=
scsi_try_bus_device_reset
(
scmd
);
if
(
rtn
==
SUCCESS
)
break
;
/* FALLTHROUGH */
case
SCSI_TRY_RESET_BUS
:
rtn
=
scsi_try_bus_reset
(
scmd
);
if
(
rtn
==
SUCCESS
)
break
;
/* FALLTHROUGH */
case
SCSI_TRY_RESET_HOST
:
rtn
=
scsi_try_host_reset
(
scmd
);
break
;
default:
rtn
=
FAILED
;
}
return
rtn
;
}
static
void
static
void
scsi_reset_provider_done_command
(
Scsi_Cmnd
*
SCpnt
)
scsi_reset_provider_done_command
(
struct
scsi_cmnd
*
scmd
)
{
{
}
}
...
@@ -1731,47 +1708,65 @@ scsi_reset_provider_done_command(Scsi_Cmnd *SCpnt)
...
@@ -1731,47 +1708,65 @@ scsi_reset_provider_done_command(Scsi_Cmnd *SCpnt)
* Bus/Device reset capability.
* Bus/Device reset capability.
*/
*/
int
int
scsi_reset_provider
(
Scsi_D
evice
*
dev
,
int
flag
)
scsi_reset_provider
(
struct
scsi_d
evice
*
dev
,
int
flag
)
{
{
struct
scsi_cmnd
*
SCpnt
=
scsi_get_command
(
dev
,
GFP_KERNEL
);
struct
scsi_cmnd
*
scmd
=
scsi_get_command
(
dev
,
GFP_KERNEL
);
struct
request
req
;
struct
request
req
;
int
rtn
;
int
rtn
;
SCpnt
->
request
=
&
req
;
scmd
->
request
=
&
req
;
memset
(
&
SCpnt
->
eh_timeout
,
0
,
sizeof
(
SCpnt
->
eh_timeout
));
memset
(
&
scmd
->
eh_timeout
,
0
,
sizeof
(
scmd
->
eh_timeout
));
SCpnt
->
request
->
rq_status
=
RQ_SCSI_BUSY
;
scmd
->
request
->
rq_status
=
RQ_SCSI_BUSY
;
SCpnt
->
state
=
SCSI_STATE_INITIALIZING
;
scmd
->
state
=
SCSI_STATE_INITIALIZING
;
SCpnt
->
owner
=
SCSI_OWNER_MIDLEVEL
;
scmd
->
owner
=
SCSI_OWNER_MIDLEVEL
;
memset
(
&
SCpnt
->
cmnd
,
'\0'
,
sizeof
(
SCpnt
->
cmnd
));
memset
(
&
scmd
->
cmnd
,
'\0'
,
sizeof
(
scmd
->
cmnd
));
SCpnt
->
scsi_done
=
scsi_reset_provider_done_command
;
scmd
->
scsi_done
=
scsi_reset_provider_done_command
;
SCpnt
->
done
=
NULL
;
scmd
->
done
=
NULL
;
SCpnt
->
reset_chain
=
NULL
;
scmd
->
reset_chain
=
NULL
;
SCpnt
->
buffer
=
NULL
;
scmd
->
buffer
=
NULL
;
SCpnt
->
bufflen
=
0
;
scmd
->
bufflen
=
0
;
SCpnt
->
request_buffer
=
NULL
;
scmd
->
request_buffer
=
NULL
;
SCpnt
->
request_bufflen
=
0
;
scmd
->
request_bufflen
=
0
;
SCpnt
->
internal_timeout
=
NORMAL_TIMEOUT
;
scmd
->
internal_timeout
=
NORMAL_TIMEOUT
;
SCpnt
->
abort_reason
=
DID_ABORT
;
scmd
->
abort_reason
=
DID_ABORT
;
SCpnt
->
cmd_len
=
0
;
scmd
->
cmd_len
=
0
;
SCpnt
->
sc_data_direction
=
SCSI_DATA_UNKNOWN
;
scmd
->
sc_data_direction
=
SCSI_DATA_UNKNOWN
;
SCpnt
->
sc_request
=
NULL
;
scmd
->
sc_request
=
NULL
;
SCpnt
->
sc_magic
=
SCSI_CMND_MAGIC
;
scmd
->
sc_magic
=
SCSI_CMND_MAGIC
;
init_timer
(
&
scmd
->
eh_timeout
);
/*
/*
* Sometimes the command can get back into the timer chain,
* Sometimes the command can get back into the timer chain,
* so use the pid as an identifier.
* so use the pid as an identifier.
*/
*/
SCpnt
->
pid
=
0
;
scmd
->
pid
=
0
;
rtn
=
scsi_new_reset
(
SCpnt
,
flag
);
switch
(
flag
)
{
case
SCSI_TRY_RESET_DEVICE
:
rtn
=
scsi_try_bus_device_reset
(
scmd
);
if
(
rtn
==
SUCCESS
)
break
;
/* FALLTHROUGH */
case
SCSI_TRY_RESET_BUS
:
rtn
=
scsi_try_bus_reset
(
scmd
);
if
(
rtn
==
SUCCESS
)
break
;
/* FALLTHROUGH */
case
SCSI_TRY_RESET_HOST
:
rtn
=
scsi_try_host_reset
(
scmd
);
break
;
default:
rtn
=
FAILED
;
}
scsi_delete_timer
(
SCpnt
);
scsi_delete_timer
(
scmd
);
scsi_put_command
(
SCpnt
);
scsi_put_command
(
scmd
);
return
rtn
;
return
rtn
;
}
}
drivers/scsi/scsi_lib.c
View file @
8b0f29fb
...
@@ -117,7 +117,7 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
...
@@ -117,7 +117,7 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
*/
*/
if
(
reason
==
SCSI_MLQUEUE_HOST_BUSY
)
if
(
reason
==
SCSI_MLQUEUE_HOST_BUSY
)
host
->
host_blocked
=
host
->
max_host_blocked
;
host
->
host_blocked
=
host
->
max_host_blocked
;
else
else
if
(
reason
==
SCSI_MLQUEUE_DEVICE_BUSY
)
device
->
device_blocked
=
device
->
max_device_blocked
;
device
->
device_blocked
=
device
->
max_device_blocked
;
/*
/*
...
@@ -1340,23 +1340,6 @@ void scsi_report_bus_reset(struct Scsi_Host *shost, int channel)
...
@@ -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
__init
scsi_init_queue
(
void
)
{
{
int
i
;
int
i
;
...
...
drivers/scsi/scsi_scan.c
View file @
8b0f29fb
...
@@ -84,6 +84,7 @@ struct dev_info scsi_static_device_list[] __initdata = {
...
@@ -84,6 +84,7 @@ struct dev_info scsi_static_device_list[] __initdata = {
{
"NEC"
,
"CD-ROM DRIVE:841"
,
"1.0"
,
BLIST_NOLUN
},
/* locks up */
{
"NEC"
,
"CD-ROM DRIVE:841"
,
"1.0"
,
BLIST_NOLUN
},
/* locks up */
{
"PHILIPS"
,
"PCA80SC"
,
"V4-2"
,
BLIST_NOLUN
},
/* responds to all lun */
{
"PHILIPS"
,
"PCA80SC"
,
"V4-2"
,
BLIST_NOLUN
},
/* responds to all lun */
{
"RODIME"
,
"RO3000S"
,
"2.33"
,
BLIST_NOLUN
},
/* locks up */
{
"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
* The following causes a failed REQUEST SENSE on lun 1 for
* aha152x controller, which causes SCSI code to reset bus.
* aha152x controller, which causes SCSI code to reset bus.
...
@@ -128,6 +129,7 @@ struct dev_info scsi_static_device_list[] __initdata = {
...
@@ -128,6 +129,7 @@ struct dev_info scsi_static_device_list[] __initdata = {
{
"MITSUMI"
,
"CD-R CR-2201CS"
,
"6119"
,
BLIST_NOLUN
},
/* locks up */
{
"MITSUMI"
,
"CD-R CR-2201CS"
,
"6119"
,
BLIST_NOLUN
},
/* locks up */
{
"RELISYS"
,
"Scorpio"
,
NULL
,
BLIST_NOLUN
},
/* responds to all lun */
{
"RELISYS"
,
"Scorpio"
,
NULL
,
BLIST_NOLUN
},
/* responds to all lun */
{
"MICROTEK"
,
"ScanMaker II"
,
"5.61"
,
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.
* Other types of devices that have special flags.
...
...
drivers/scsi/scsi_syms.c
View file @
8b0f29fb
...
@@ -74,12 +74,11 @@ EXPORT_SYMBOL(scsi_sleep);
...
@@ -74,12 +74,11 @@ EXPORT_SYMBOL(scsi_sleep);
EXPORT_SYMBOL
(
scsi_io_completion
);
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_attach
);
EXPORT_SYMBOL
(
scsi_slave_detach
);
EXPORT_SYMBOL
(
scsi_slave_detach
);
EXPORT_SYMBOL
(
scsi_device_get
);
EXPORT_SYMBOL
(
scsi_device_get
);
EXPORT_SYMBOL
(
scsi_device_put
);
EXPORT_SYMBOL
(
scsi_device_put
);
EXPORT_SYMBOL
(
scsi_set_device_offline
);
/*
/*
* This symbol is for the highlevel drivers (e.g. sg) only.
* This symbol is for the highlevel drivers (e.g. sg) only.
...
...
drivers/scsi/scsi_sysfs.c
View file @
8b0f29fb
...
@@ -14,6 +14,44 @@
...
@@ -14,6 +14,44 @@
#include "scsi.h"
#include "scsi.h"
#include "hosts.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
* scsi_host_class_name_show - copy out the SCSI host name
* @dev: device to check
* @dev: device to check
...
@@ -39,12 +77,21 @@ DEVICE_ATTR(class_name, S_IRUGO, scsi_host_class_name_show, NULL);
...
@@ -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
)
static
int
scsi_host_class_add_dev
(
struct
device
*
dev
)
{
{
int
i
;
device_create_file
(
dev
,
&
dev_attr_class_name
);
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
;
return
0
;
}
}
static
void
scsi_host_class_rm_dev
(
struct
device
*
dev
)
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
);
device_remove_file
(
dev
,
&
dev_attr_class_name
);
}
}
...
@@ -129,10 +176,10 @@ void scsi_upper_driver_unregister(struct Scsi_Device_Template *sdev_tp)
...
@@ -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
* s
dev_s
how_function: macro to create an attr function that can be used to
* show a non-bit field.
* show a non-bit field.
*/
*/
#define show_function(field, format_string) \
#define s
dev_s
how_function(field, format_string) \
static ssize_t \
static ssize_t \
show_##field (struct device *dev, char *buf) \
show_##field (struct device *dev, char *buf) \
{ \
{ \
...
@@ -146,7 +193,7 @@ show_##field (struct device *dev, char *buf) \
...
@@ -146,7 +193,7 @@ show_##field (struct device *dev, char *buf) \
* read only field.
* read only field.
*/
*/
#define sdev_rd_attr(field, format_string) \
#define sdev_rd_attr(field, format_string) \
show_function(field, format_string) \
s
dev_s
how_function(field, format_string) \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL)
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL)
...
@@ -155,27 +202,27 @@ 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.
* read/write field.
*/
*/
#define sdev_rw_attr(field, format_string) \
#define sdev_rw_attr(field, format_string) \
show_function(field, format_string) \
s
dev_s
how_function(field, format_string) \
\
\
static ssize_t \
static ssize_t \
store_##field (struct device *dev, const char *buf, size_t count) \
s
dev_s
tore_##field (struct device *dev, const char *buf, size_t count) \
{ \
{ \
struct scsi_device *sdev; \
struct scsi_device *sdev; \
sdev = to_scsi_device(dev); \
sdev = to_scsi_device(dev); \
snscanf (buf, 20, format_string, &sdev->field); \
snscanf (buf, 20, format_string, &sdev->field); \
return count; \
return count; \
} \
} \
static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, show_##field, store_##field)
static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, show_##field, s
dev_s
tore_##field)
/*
/*
* sdev_rd_attr: create a function and attribute variable for a
* sdev_rd_attr: create a function and attribute variable for a
* read/write bit field.
* read/write bit field.
*/
*/
#define sdev_rw_attr_bit(field) \
#define sdev_rw_attr_bit(field) \
show_function(field, "%d\n") \
s
dev_s
how_function(field, "%d\n") \
\
\
static ssize_t \
static ssize_t \
store_##field (struct device *dev, const char *buf, size_t count) \
s
dev_s
tore_##field (struct device *dev, const char *buf, size_t count) \
{ \
{ \
int ret; \
int ret; \
struct scsi_device *sdev; \
struct scsi_device *sdev; \
...
@@ -187,7 +234,7 @@ store_##field (struct device *dev, const char *buf, size_t count) \
...
@@ -187,7 +234,7 @@ store_##field (struct device *dev, const char *buf, size_t count) \
} \
} \
return ret; \
return ret; \
} \
} \
static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, show_##field, store_##field)
static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, show_##field, s
dev_s
tore_##field)
/*
/*
* scsi_sdev_check_buf_bit: return 0 if buf is "0", return 1 if buf is "1",
* scsi_sdev_check_buf_bit: return 0 if buf is "0", return 1 if buf is "1",
...
...
drivers/scsi/sg.c
View file @
8b0f29fb
...
@@ -2689,18 +2689,6 @@ static int sg_proc_devstrs_read(char *buffer, char **start, off_t offset,
...
@@ -2689,18 +2689,6 @@ static int sg_proc_devstrs_read(char *buffer, char **start, off_t offset,
int
size
,
int
*
eof
,
void
*
data
);
int
size
,
int
*
eof
,
void
*
data
);
static
int
sg_proc_devstrs_info
(
char
*
buffer
,
int
*
len
,
off_t
*
begin
,
static
int
sg_proc_devstrs_info
(
char
*
buffer
,
int
*
len
,
off_t
*
begin
,
off_t
offset
,
int
size
);
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
,
static
int
sg_proc_version_read
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
size
,
int
*
eof
,
void
*
data
);
int
size
,
int
*
eof
,
void
*
data
);
static
int
sg_proc_version_info
(
char
*
buffer
,
int
*
len
,
off_t
*
begin
,
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,
...
@@ -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
[]
=
{
static
read_proc_t
*
sg_proc_leaf_reads
[]
=
{
sg_proc_adio_read
,
sg_proc_dressz_read
,
sg_proc_debug_read
,
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_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
sg_proc_version_read
};
};
static
write_proc_t
*
sg_proc_leaf_writes
[]
=
{
static
write_proc_t
*
sg_proc_leaf_writes
[]
=
{
...
@@ -3033,81 +3020,6 @@ sg_proc_devstrs_info(char *buffer, int *len, off_t * begin,
...
@@ -3033,81 +3020,6 @@ sg_proc_devstrs_info(char *buffer, int *len, off_t * begin,
return
1
;
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
\t
busy
\t
cpl
\t
scatg
\t
isa
\t
emul
\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
static
int
sg_proc_version_read
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
sg_proc_version_read
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
size
,
int
*
eof
,
void
*
data
)
int
size
,
int
*
eof
,
void
*
data
)
...
...
drivers/scsi/sim710.c
View file @
8b0f29fb
...
@@ -328,7 +328,7 @@ struct eisa_driver sim710_eisa_driver = {
...
@@ -328,7 +328,7 @@ struct eisa_driver sim710_eisa_driver = {
static
int
__init
sim710_init
(
void
)
static
int
__init
sim710_init
(
void
)
{
{
int
err
=
-
ENODEV
,
err2
;
int
err
=
-
ENODEV
;
#ifdef MODULE
#ifdef MODULE
if
(
sim710
)
if
(
sim710
)
...
@@ -336,23 +336,17 @@ static int __init sim710_init(void)
...
@@ -336,23 +336,17 @@ static int __init sim710_init(void)
#endif
#endif
#ifdef CONFIG_MCA
#ifdef CONFIG_MCA
if
(
MCA_bus
)
err
=
mca_register_driver
(
&
sim710_mca_driver
);
err
=
mca_register_driver
(
&
sim710_mca_driver
);
#endif
#endif
#ifdef CONFIG_EISA
#ifdef CONFIG_EISA
err2
=
eisa_driver_register
(
&
sim710_eisa_driver
);
err
=
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
;
#endif
#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
;
return
0
;
}
}
...
...
drivers/scsi/u14-34f.c
View file @
8b0f29fb
...
@@ -905,7 +905,6 @@ static int port_detect \
...
@@ -905,7 +905,6 @@ static int port_detect \
}
}
else
{
else
{
unsigned
long
flags
;
unsigned
long
flags
;
scsi_register_blocked_host
(
sh
[
j
]);
sh
[
j
]
->
unchecked_isa_dma
=
TRUE
;
sh
[
j
]
->
unchecked_isa_dma
=
TRUE
;
flags
=
claim_dma_lock
();
flags
=
claim_dma_lock
();
...
@@ -1911,8 +1910,6 @@ static int u14_34f_release(struct Scsi_Host *shpnt) {
...
@@ -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
"
,
if
(
sh
[
j
]
==
NULL
)
panic
(
"%s: release, invalid Scsi_Host pointer.
\n
"
,
driver_name
);
driver_name
);
if
(
sh
[
j
]
->
unchecked_isa_dma
)
scsi_deregister_blocked_host
(
sh
[
j
]);
for
(
i
=
0
;
i
<
sh
[
j
]
->
can_queue
;
i
++
)
for
(
i
=
0
;
i
<
sh
[
j
]
->
can_queue
;
i
++
)
if
((
&
HD
(
j
)
->
cp
[
i
])
->
sglist
)
kfree
((
&
HD
(
j
)
->
cp
[
i
])
->
sglist
);
if
((
&
HD
(
j
)
->
cp
[
i
])
->
sglist
)
kfree
((
&
HD
(
j
)
->
cp
[
i
])
->
sglist
);
...
...
drivers/scsi/wd7000.c
View file @
8b0f29fb
...
@@ -158,6 +158,11 @@
...
@@ -158,6 +158,11 @@
* Clean up delay to udelay, and yielding sleeps
* Clean up delay to udelay, and yielding sleeps
* Make host reset actually reset the card
* Make host reset actually reset the card
* Make everything static
* 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>
#include <linux/module.h>
...
@@ -170,8 +175,8 @@
...
@@ -170,8 +175,8 @@
#include <linux/ioport.h>
#include <linux/ioport.h>
#include <linux/proc_fs.h>
#include <linux/proc_fs.h>
#include <linux/blk.h>
#include <linux/blk.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/stat.h>
#include <asm/system.h>
#include <asm/system.h>
#include <asm/dma.h>
#include <asm/dma.h>
...
@@ -179,9 +184,9 @@
...
@@ -179,9 +184,9 @@
#include "scsi.h"
#include "scsi.h"
#include "hosts.h"
#include "hosts.h"
#include <scsi/scsicam.h>
#include <scsi/scsicam.h>
#define ANY2SCSI_INLINE
/* undef this to use old macros */
#define ANY2SCSI_INLINE
/* undef this to use old macros */
#undef WD7000_DEBUG
/* general debug */
#undef WD7000_DEBUG
/* general debug */
#ifdef WD7000_DEBUG
#ifdef WD7000_DEBUG
...
@@ -190,9 +195,6 @@
...
@@ -190,9 +195,6 @@
#define dprintk(format,args...)
#define dprintk(format,args...)
#endif
#endif
#include "wd7000.h"
#include <linux/stat.h>
/*
/*
* Mailbox structure sizes.
* Mailbox structure sizes.
* I prefer to keep the number of ICMBs much larger than the number of
* I prefer to keep the number of ICMBs much larger than the number of
...
@@ -211,6 +213,21 @@
...
@@ -211,6 +213,21 @@
*/
*/
#define MAX_SCBS 32
#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
* WD7000-specific mailbox structure
*
*
...
@@ -1737,7 +1754,23 @@ MODULE_AUTHOR("Thomas Wuensche, John Boyd, Miroslav Zagorac");
...
@@ -1737,7 +1754,23 @@ MODULE_AUTHOR("Thomas Wuensche, John Boyd, Miroslav Zagorac");
MODULE_DESCRIPTION
(
"Driver for the WD7000 series ISA controllers"
);
MODULE_DESCRIPTION
(
"Driver for the WD7000 series ISA controllers"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_LICENSE
(
"GPL"
);
/* Eventually this will go into an include file, but this will be later */
static
Scsi_Host_Template
driver_template
=
{
static
Scsi_Host_Template
driver_template
=
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
,
};
#include "scsi_module.c"
#include "scsi_module.c"
drivers/scsi/wd7000.h
deleted
100644 → 0
View file @
227b2020
#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
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment