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
9096518f
Commit
9096518f
authored
Nov 06, 2002
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://linux-scsi.bkbits.net/scsi-dledford
into home.transmeta.com:/home/torvalds/v2.5/linux
parents
fd4b35fd
5605a515
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
432 additions
and
633 deletions
+432
-633
drivers/scsi/aic7xxx_old.c
drivers/scsi/aic7xxx_old.c
+409
-613
drivers/scsi/aic7xxx_old/aic7xxx.h
drivers/scsi/aic7xxx_old/aic7xxx.h
+6
-0
drivers/scsi/aic7xxx_old/aic7xxx_proc.c
drivers/scsi/aic7xxx_old/aic7xxx_proc.c
+17
-20
No files found.
drivers/scsi/aic7xxx_old.c
View file @
9096518f
...
...
@@ -252,7 +252,7 @@
#include <linux/config.h>
/* for CONFIG_PCI */
#define AIC7XXX_C_VERSION "5.2.
5
"
#define AIC7XXX_C_VERSION "5.2.
6
"
#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
...
...
@@ -274,30 +274,20 @@
#endif
/*
* You can try raising me if tagged queueing is enabled, or lowering
* me if you only have 4 SCBs.
* You can try raising me for better performance or lowering me if you have
* flaky devices that go off the scsi bus when hit with too many tagged
* commands (like some IBM SCSI-3 LVD drives).
*/
#define AIC7XXX_CMDS_PER_DEVICE 32
/*
* *** Determining commands per LUN ***
*
* When AIC7XXX_CMDS_PER_DEVICE is not defined, the driver will use its
* own algorithm to determine the commands/LUN. If SCB paging is
* enabled, which is always now, the default is 8 commands per lun
* that indicates it supports tagged queueing. All non-tagged devices
* use an internal queue depth of 3, with no more than one of those
* three commands active at one time.
*/
typedef
struct
{
unsigned
char
tag_commands
[
16
];
/* Allow for wide/twin adapters. */
}
adapter_tag_info_t
;
/*
* Make a define that will tell the driver not to
use tagged queueing
*
by default
.
* Make a define that will tell the driver not to
the default tag depth
*
everywhere
.
*/
#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\
0, 0, 0, 0, 0, 0, 0, 0}
...
...
@@ -878,7 +868,6 @@ struct aic_dev_data {
volatile
unsigned
short
temp_q_depth
;
unsigned
short
max_q_depth
;
volatile
unsigned
char
active_cmds
;
unsigned
char
cmds_sent
;
/*
* Statistics Kept:
*
...
...
@@ -891,6 +880,9 @@ struct aic_dev_data {
*/
long
w_total
;
/* total writes */
long
r_total
;
/* total reads */
long
barrier_total
;
/* total num of REQ_BARRIER commands */
long
ordered_total
;
/* How many REQ_BARRIER commands we
used ordered tags to satisfy */
long
w_bins
[
6
];
/* binned write */
long
r_bins
[
6
];
/* binned reads */
transinfo_type
cur
;
...
...
@@ -998,7 +990,7 @@ struct aic7xxx_host {
unsigned
short
sc_size
;
struct
aic7xxx_host
*
next
;
/* allow for multiple IRQs */
struct
Scsi_Host
*
host
;
/* pointer to scsi host */
struct
list_head
aic_devs
;
/* all aic
dev
s on host */
struct
list_head
aic_devs
;
/* all aic
_dev struct
s on host */
int
host_no
;
/* SCSI host number */
unsigned
long
mbase
;
/* I/O memory address */
ahc_chip
chip
;
/* chip type */
...
...
@@ -1066,6 +1058,10 @@ static struct aic7xxx_syncrate {
* rule are noted in the comments.
*/
/*
* Use this as the default queue depth when setting tagged queueing on.
*/
static
unsigned
int
aic7xxx_default_queue_depth
=
AIC7XXX_CMDS_PER_DEVICE
;
/*
* Skip the scsi bus reset. Non 0 make us skip the reset at startup. This
...
...
@@ -1369,6 +1365,7 @@ aic7xxx_setup(char *s)
{
"pci_parity"
,
&
aic7xxx_pci_parity
},
{
"dump_card"
,
&
aic7xxx_dump_card
},
{
"dump_sequencer"
,
&
aic7xxx_dump_sequencer
},
{
"default_queue_depth"
,
&
aic7xxx_default_queue_depth
},
{
"scbram"
,
&
aic7xxx_scbram
},
{
"seltime"
,
&
aic7xxx_seltime
},
{
"tag_info"
,
NULL
}
...
...
@@ -2636,6 +2633,7 @@ aic7xxx_allocate_scb(struct aic7xxx_host *p)
static
void
aic7xxx_queue_cmd_complete
(
struct
aic7xxx_host
*
p
,
Scsi_Cmnd
*
cmd
)
{
aic7xxx_position
(
cmd
)
=
SCB_LIST_NULL
;
cmd
->
host_scribble
=
(
char
*
)
p
->
completeq
.
head
;
p
->
completeq
.
head
=
cmd
;
}
...
...
@@ -2869,6 +2867,12 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
aic_dev
->
r_total
++
;
ptr
=
aic_dev
->
r_bins
;
}
if
(
cmd
->
device
->
simple_tags
&&
cmd
->
request
->
flags
&
REQ_BARRIER
)
{
aic_dev
->
barrier_total
++
;
if
(
scb
->
tag_action
==
MSG_ORDERED_Q_TAG
)
aic_dev
->
ordered_total
++
;
}
x
=
scb
->
sg_length
;
x
>>=
10
;
for
(
i
=
0
;
i
<
6
;
i
++
)
...
...
@@ -3130,23 +3134,41 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
{
struct
aic7xxx_scb
*
scbp
,
*
prev_scbp
;
struct
scsi_device
*
sd
;
unsigned
char
active_scb
,
tcl
;
unsigned
char
active_scb
,
tcl
,
scb_tag
;
int
i
=
0
,
init_lists
=
FALSE
;
struct
list_head
*
list_item
,
*
list_head
;
struct
aic_dev_data
*
aic_dev
;
struct
aic_dev_data
*
aic_dev
,
*
remove_aic_dev
=
NULL
;
/*
* Restore this when we're done
*/
active_scb
=
aic_inb
(
p
,
SCBPTR
);
/*
* If we are still scanning devices, this device may not be linked into
* our host controller yet. So, we grab the temporary aic_dev that we
* allocate during the device scan (by getting device->hostdata for the
* active device) and if the list struct in the aic_dev is empty, we
* add it to p->aic_devs. Then at the end of the function, if we added
* the aic_dev to our host struct so our loop would work, then we just
* remove it.
*/
scb_tag
=
aic_inb
(
p
,
SCB_TAG
);
if
(
scb_tag
<
p
->
scb_data
->
numscbs
)
{
scbp
=
p
->
scb_data
->
scb_array
[
scb_tag
];
remove_aic_dev
=
(
struct
aic_dev_data
*
)
scbp
->
cmd
->
device
->
hostdata
;
if
(
list_empty
(
&
remove_aic_dev
->
list
))
list_add_tail
(
&
remove_aic_dev
->
list
,
&
p
->
aic_devs
);
else
remove_aic_dev
=
NULL
;
}
if
(
aic7xxx_verbose
&
(
VERBOSE_RESET_PROCESS
|
VERBOSE_ABORT_PROCESS
))
{
printk
(
INFO_LEAD
"Reset device,
active_scb %d
\n
"
,
p
->
host_no
,
channel
,
target
,
lun
,
active_scb
);
printk
(
INFO_LEAD
"Current scb
_tag
%d, SEQADDR 0x%x, LASTPHASE "
printk
(
INFO_LEAD
"Reset device,
hardware_scb %d, aic_dev %p,
\n
"
,
p
->
host_no
,
channel
,
target
,
lun
,
active_scb
,
remove_aic_dev
);
printk
(
INFO_LEAD
"Current scb %d, SEQADDR 0x%x, LASTPHASE "
"0x%x
\n
"
,
p
->
host_no
,
channel
,
target
,
lun
,
aic_inb
(
p
,
SCB_TAG
)
,
p
->
host_no
,
channel
,
target
,
lun
,
scb_tag
,
aic_inb
(
p
,
SEQADDR0
)
|
(
aic_inb
(
p
,
SEQADDR1
)
<<
8
),
aic_inb
(
p
,
LASTPHASE
));
printk
(
INFO_LEAD
"SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x
\n
"
,
...
...
@@ -3157,13 +3179,15 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
p
->
host_no
,
channel
,
target
,
lun
,
aic_inb
(
p
,
SSTAT0
),
aic_inb
(
p
,
SSTAT1
),
aic_inb
(
p
,
SSTAT2
));
}
/*
* Deal with the busy target and linked next issues.
*/
list_head
=
&
p
->
aic_devs
;
list_for_each
(
list_item
,
list_head
)
list_for_each_entry
(
aic_dev
,
&
p
->
aic_devs
,
list
)
{
aic_dev
=
list_entry
(
list_item
,
struct
aic_dev_data
,
list
);
if
(
aic7xxx_verbose
&
(
VERBOSE_RESET_PROCESS
|
VERBOSE_ABORT_PROCESS
))
printk
(
INFO_LEAD
"processing aic_dev %p
\n
"
,
p
->
host_no
,
channel
,
target
,
lun
,
aic_dev
);
sd
=
aic_dev
->
SDptr
;
if
((
target
!=
ALL_TARGETS
&&
target
!=
sd
->
id
)
||
...
...
@@ -3205,6 +3229,8 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
}
}
}
if
(
remove_aic_dev
)
list_del
(
&
remove_aic_dev
->
list
);
if
(
aic7xxx_verbose
&
(
VERBOSE_ABORT_PROCESS
|
VERBOSE_RESET_PROCESS
))
printk
(
INFO_LEAD
"Cleaning QINFIFO.
\n
"
,
p
->
host_no
,
channel
,
target
,
lun
);
...
...
@@ -6526,22 +6552,19 @@ do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
/*+F*************************************************************************
* Function:
* aic7xxx_init_
aic_dev
* aic7xxx_init_
transinfo
*
* Description:
* Set up the initial aic_dev values from the BIOS settings and
data
*
we got back from INQUIRY commands.
* Set up the initial aic_dev values from the BIOS settings and
from
*
INQUIRY results
*-F*************************************************************************/
static
void
aic7xxx_init_
aic_dev
(
struct
aic7xxx_host
*
p
,
struct
aic_dev_data
*
aic_dev
)
aic7xxx_init_
transinfo
(
struct
aic7xxx_host
*
p
,
struct
aic_dev_data
*
aic_dev
)
{
struct
scsi_d
evice
*
sdpnt
=
aic_dev
->
SDptr
;
Scsi_D
evice
*
sdpnt
=
aic_dev
->
SDptr
;
unsigned
char
tindex
;
tindex
=
sdpnt
->
id
|
(
sdpnt
->
channel
<<
3
);
scbq_init
(
&
aic_dev
->
delayed_scbs
);
if
(
!
(
aic_dev
->
flags
&
DEVICE_DTR_SCANNED
))
{
aic_dev
->
flags
|=
DEVICE_DTR_SCANNED
;
...
...
@@ -6597,6 +6620,31 @@ aic7xxx_init_aic_dev(struct aic7xxx_host *p, struct aic_dev_data *aic_dev)
}
}
/*+F*************************************************************************
* Function:
* aic7xxx_alloc_aic_dev
*
* Description:
* Set up the initial aic_dev struct pointers
*-F*************************************************************************/
static
struct
aic_dev_data
*
aic7xxx_alloc_aic_dev
(
struct
aic7xxx_host
*
p
,
Scsi_Device
*
SDptr
)
{
struct
aic_dev_data
*
aic_dev
;
aic_dev
=
kmalloc
(
sizeof
(
struct
aic_dev_data
),
GFP_ATOMIC
|
GFP_KERNEL
);
if
(
!
aic_dev
)
return
aic_dev
;
memset
(
aic_dev
,
0
,
sizeof
(
struct
aic_dev_data
));
SDptr
->
hostdata
=
aic_dev
;
aic_dev
->
SDptr
=
SDptr
;
aic_dev
->
max_q_depth
=
1
;
aic_dev
->
temp_q_depth
=
1
;
scbq_init
(
&
aic_dev
->
delayed_scbs
);
INIT_LIST_HEAD
(
&
aic_dev
->
list
);
return
aic_dev
;
}
/*+F*************************************************************************
* Function:
* aic7xxx_device_queue_depth
...
...
@@ -6605,7 +6653,11 @@ aic7xxx_init_aic_dev(struct aic7xxx_host *p, struct aic_dev_data *aic_dev)
* Determines the queue depth for a given device. There are two ways
* a queue depth can be obtained for a tagged queueing device. One
* way is the default queue depth which is determined by whether
* AIC7XXX_CMDS_PER_DEVICE is defined. If it is defined, then it is used
* aic7xxx_default_queue_depth. The other is by the aic7xxx_tag_info
* array.
*
* If tagged queueing isn't supported on the device, then we set the
* depth to p->host->hostt->cmd_per_lun for internal driver queueing.
* as the default queue depth. Otherwise, we use either 4 or 8 as the
* default queue depth (dependent on the number of hardware SCBs).
* The other way we determine queue depth is through the use of the
...
...
@@ -6617,7 +6669,7 @@ aic7xxx_init_aic_dev(struct aic7xxx_host *p, struct aic_dev_data *aic_dev)
static
void
aic7xxx_device_queue_depth
(
struct
aic7xxx_host
*
p
,
Scsi_Device
*
device
)
{
int
default_depth
=
p
->
host
->
hostt
->
cmd_per_lun
;
int
tag_enabled
=
FALSE
;
struct
aic_dev_data
*
aic_dev
=
device
->
hostdata
;
unsigned
char
tindex
;
...
...
@@ -6626,14 +6678,9 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
if
(
device
->
simple_tags
)
return
;
// We've already enabled this device
aic_dev
->
temp_q_depth
=
1
;
aic_dev
->
max_q_depth
=
1
;
if
(
device
->
tagged_supported
)
{
int
tag_enabled
=
TRUE
;
default_depth
=
AIC7XXX_CMDS_PER_DEVICE
;
tag_enabled
=
TRUE
;
if
(
!
(
p
->
discenable
&
(
1
<<
tindex
)))
{
...
...
@@ -6641,6 +6688,7 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
printk
(
INFO_LEAD
"Disconnection disabled, unable to "
"enable tagged queueing.
\n
"
,
p
->
host_no
,
device
->
channel
,
device
->
id
,
device
->
lun
);
tag_enabled
=
FALSE
;
}
else
{
...
...
@@ -6655,7 +6703,8 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
" the aic7xxx.c source file.
\n
"
);
print_warning
=
FALSE
;
}
aic_dev
->
max_q_depth
=
aic_dev
->
temp_q_depth
=
default_depth
;
aic_dev
->
max_q_depth
=
aic_dev
->
temp_q_depth
=
aic7xxx_default_queue_depth
;
}
else
{
...
...
@@ -6666,7 +6715,8 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
}
else
if
(
aic7xxx_tag_info
[
p
->
instance
].
tag_commands
[
tindex
]
==
0
)
{
aic_dev
->
max_q_depth
=
aic_dev
->
temp_q_depth
=
default_depth
;
aic_dev
->
max_q_depth
=
aic_dev
->
temp_q_depth
=
aic7xxx_default_queue_depth
;
}
else
{
...
...
@@ -6674,17 +6724,27 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
aic7xxx_tag_info
[
p
->
instance
].
tag_commands
[
tindex
];
}
}
}
}
if
(
tag_enabled
)
{
if
(
aic7xxx_verbose
&
VERBOSE_NEGOTIATION2
)
{
printk
(
INFO_LEAD
"Enabled tagged queuing
, queue depth %d.
\n
"
,
printk
(
INFO_LEAD
"Tagged queuing enabled
, queue depth %d.
\n
"
,
p
->
host_no
,
device
->
channel
,
device
->
id
,
device
->
lun
,
aic_dev
->
max_q_depth
);
}
scsi_adjust_queue_depth
(
device
,
MSG_ORDERED_TAG
,
aic_dev
->
max_q_depth
);
}
else
{
if
(
aic7xxx_verbose
&
VERBOSE_NEGOTIATION2
)
{
printk
(
INFO_LEAD
"Tagged queuing disabled, queue depth %d.
\n
"
,
p
->
host_no
,
device
->
channel
,
device
->
id
,
device
->
lun
,
device
->
host
->
cmd_per_lun
);
}
scsi_adjust_queue_depth
(
device
,
0
,
device
->
host
->
cmd_per_lun
);
}
return
;
}
...
...
@@ -6722,28 +6782,22 @@ aic7xxx_slave_attach(Scsi_Device *sdpnt)
struct
aic7xxx_host
*
p
=
(
struct
aic7xxx_host
*
)
sdpnt
->
host
->
hostdata
;
struct
aic_dev_data
*
aic_dev
;
int
scbnum
;
struct
list_head
*
list_ptr
,
*
list_head
;
if
(
!
sdpnt
->
hostdata
)
{
sdpnt
->
hostdata
=
kmalloc
(
sizeof
(
struct
aic_dev_data
),
GFP_ATOMIC
);
if
(
!
sdpnt
->
hostdata
)
return
1
;
memset
(
sdpnt
->
hostdata
,
0
,
sizeof
(
struct
aic_dev_data
));
}
aic_dev
=
sdpnt
->
hostdata
;
aic_dev
->
SDptr
=
sdpnt
;
aic
7xxx_init_aic_dev
(
p
,
aic_dev
)
;
aic
_dev
=
(
struct
aic_dev_data
*
)
sdpnt
->
hostdata
;
list_add
(
&
aic_dev
->
list
,
&
p
->
aic_devs
);
if
(
!
aic_dev
)
{
aic_dev
=
aic7xxx_alloc_aic_dev
(
p
,
sdpnt
);
}
if
(
!
aic_dev
)
return
1
;
aic7xxx_init_transinfo
(
p
,
aic_dev
);
aic7xxx_device_queue_depth
(
p
,
sdpnt
);
if
(
list_empty
(
&
aic_dev
->
list
))
list_add_tail
(
&
aic_dev
->
list
,
&
p
->
aic_devs
);
scbnum
=
0
;
list_head
=
&
p
->
aic_devs
;
list_for_each
(
list_ptr
,
list_head
)
{
aic_dev
=
list_entry
(
list_ptr
,
struct
aic_dev_data
,
list
);
list_for_each_entry
(
aic_dev
,
&
p
->
aic_devs
,
list
)
{
scbnum
+=
aic_dev
->
max_q_depth
;
}
while
(
scbnum
>
p
->
scb_data
->
numscbs
)
...
...
@@ -7878,6 +7932,7 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
p
->
completeq
.
tail
=
NULL
;
scbq_init
(
&
p
->
scb_data
->
free_scbs
);
scbq_init
(
&
p
->
waiting_scbs
);
INIT_LIST_HEAD
(
&
p
->
aic_devs
);
/*
* We currently have no commands of any type
...
...
@@ -10117,30 +10172,6 @@ aic7xxx_detect(Scsi_Host_Template *template)
return
(
found
);
}
#ifdef AIC7XXX_VERBOSE_DEBUGGING
/*+F*************************************************************************
* Function:
* aic7xxx_print_scb
*
* Description:
* Dump the byte codes for an about to be sent SCB.
*-F*************************************************************************/
static
void
aic7xxx_print_scb
(
struct
aic7xxx_host
*
p
,
struct
aic7xxx_scb
*
scb
)
{
int
i
;
unsigned
char
*
x
;
x
=
(
unsigned
char
*
)
&
scb
->
hscb
->
control
;
for
(
i
=
0
;
i
<
32
;
i
++
)
{
printk
(
"%02x "
,
x
[
i
]);
}
printk
(
"
\n
"
);
}
#endif
/*+F*************************************************************************
* Function:
* aic7xxx_buildscb
...
...
@@ -10157,6 +10188,7 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
struct
aic_dev_data
*
aic_dev
=
cmd
->
device
->
hostdata
;
struct
scsi_device
*
sdptr
=
cmd
->
device
;
unsigned
char
tindex
=
TARGET_INDEX
(
cmd
);
struct
request
*
req
=
cmd
->
request
;
mask
=
(
0x01
<<
tindex
);
hscb
=
scb
->
hscb
;
...
...
@@ -10171,16 +10203,17 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
if
(
p
->
discenable
&
mask
)
{
hscb
->
control
|=
DISCENB
;
if
(
(
sdptr
->
simple_tags
)
&&
(
cmd
->
cmnd
[
0
]
!=
TEST_UNIT_READY
)
)
/* We always force TEST_UNIT_READY to untagged */
if
(
cmd
->
cmnd
[
0
]
!=
TEST_UNIT_READY
&&
sdptr
->
simple_tags
)
{
if
(
req
->
flags
&
REQ_BARRIER
)
{
aic_dev
->
cmds_sent
++
;
if
(
aic_dev
->
cmds_sent
>=
254
&&
sdptr
->
ordered_tags
)
if
(
sdptr
->
ordered_tags
)
{
aic_dev
->
cmds_sent
=
0
;
hscb
->
control
|=
MSG_ORDERED_Q_TAG
;
scb
->
tag_action
=
MSG_ORDERED_Q_TAG
;
}
}
else
{
hscb
->
control
|=
MSG_SIMPLE_Q_TAG
;
...
...
@@ -10306,19 +10339,25 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
struct
aic7xxx_host
*
p
;
struct
aic7xxx_scb
*
scb
;
struct
aic_dev_data
*
aic_dev
;
#ifdef AIC7XXX_VERBOSE_DEBUGGING
int
tindex
=
TARGET_INDEX
(
cmd
);
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
unsigned
long
cpu_flags
=
0
;
#endif
p
=
(
struct
aic7xxx_host
*
)
cmd
->
host
->
hostdata
;
aic_dev
=
cmd
->
device
->
hostdata
;
if
(
!
aic_dev
)
{
aic_dev
=
aic7xxx_alloc_aic_dev
(
p
,
cmd
->
device
);
if
(
!
aic_dev
)
return
1
;
}
else
{
aic_dev
=
AIC_DEV
(
cmd
);
}
#ifdef AIC7XXX_VERBOSE_DEBUGGING
/*
* Check to see if channel was scanned.
*/
#ifdef AIC7XXX_VERBOSE_DEBUGGING
if
(
!
(
p
->
flags
&
AHC_A_SCANNED
)
&&
(
cmd
->
channel
==
0
))
{
if
(
aic7xxx_verbose
&
VERBOSE_PROBE2
)
...
...
@@ -10337,25 +10376,15 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
}
}
if
(
p
->
dev_active_cmds
[
tindex
]
>
(
cmd
->
device
->
queue_depth
+
1
)
)
if
(
aic_dev
->
active_cmds
>
aic_dev
->
max_q_depth
)
{
printk
(
WARN_LEAD
"Commands queued exceeds queue "
"depth, active=%d
\n
"
,
p
->
host_no
,
CTL_OF_CMD
(
cmd
),
p
->
dev_active_cmds
[
tindex
]);
if
(
p
->
dev_active_cmds
[
tindex
]
>
220
)
p
->
dev_active_cmds
[
tindex
]
=
0
;
aic_dev
->
active_cmds
);
}
#endif
if
(
!
cmd
->
device
->
hostdata
)
{
aic_dev
=
kmalloc
(
sizeof
(
struct
aic_dev_data
),
GFP_ATOMIC
);
if
(
!
aic_dev
)
return
1
;
memset
(
aic_dev
,
0
,
sizeof
(
struct
aic_dev_data
));
cmd
->
device
->
hostdata
=
aic_dev
;
}
scb
=
scbq_remove_head
(
&
p
->
scb_data
->
free_scbs
);
if
(
scb
==
NULL
)
{
...
...
@@ -10369,13 +10398,13 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
}
}
scb
->
cmd
=
cmd
;
aic7xxx_position
(
cmd
)
=
scb
->
hscb
->
tag
;
/*
* Make sure the Scsi_Cmnd pointer is saved, the struct it points to
* is set up properly, and the parity error flag is reset, then send
* the SCB to the sequencer and watch the fun begin.
*/
aic7xxx_position
(
cmd
)
=
scb
->
hscb
->
tag
;
cmd
->
scsi_done
=
fn
;
cmd
->
result
=
DID_OK
;
memset
(
cmd
->
sense_buffer
,
0
,
sizeof
(
cmd
->
sense_buffer
));
...
...
@@ -10392,10 +10421,7 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
scb
->
flags
|=
SCB_ACTIVE
|
SCB_WAITINGQ
;
scbq_insert_tail
(
&
p
->
waiting_scbs
,
scb
);
if
(
(
p
->
flags
&
(
AHC_IN_ISR
|
AHC_IN_ABORT
|
AHC_IN_RESET
))
==
0
)
{
aic7xxx_run_waiting_queues
(
p
);
}
return
(
0
);
}
...
...
@@ -10410,21 +10436,40 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
* aborted, then we will reset the channel and have all devices renegotiate.
* Returns an enumerated type that indicates the status of the operation.
*-F*************************************************************************/
static
int
aic7xxx_bus_device_reset
(
struct
aic7xxx_host
*
p
,
Scsi_Cmnd
*
cmd
)
int
aic7xxx_bus_device_reset
(
Scsi_Cmnd
*
cmd
)
{
struct
aic7xxx_host
*
p
;
struct
aic7xxx_scb
*
scb
;
struct
aic7xxx_hwscb
*
hscb
;
int
result
=
-
1
;
int
channel
;
unsigned
char
saved_scbptr
,
lastphase
;
unsigned
char
hscb_index
;
int
disconnected
;
struct
aic_dev_data
*
aic_dev
=
AIC_DEV
(
cmd
)
;
struct
aic_dev_data
*
aic_dev
;
if
(
cmd
==
NULL
)
{
printk
(
KERN_ERR
"aic7xxx_bus_device_reset: called with NULL cmd!
\n
"
);
return
FAILED
;
}
p
=
(
struct
aic7xxx_host
*
)
cmd
->
host
->
hostdata
;
aic_dev
=
AIC_DEV
(
cmd
);
if
(
aic7xxx_position
(
cmd
)
<
p
->
scb_data
->
numscbs
)
scb
=
(
p
->
scb_data
->
scb_array
[
aic7xxx_position
(
cmd
)]);
else
return
FAILED
;
hscb
=
scb
->
hscb
;
aic7xxx_isr
(
p
->
irq
,
(
void
*
)
p
,
NULL
);
aic7xxx_done_cmds_complete
(
p
);
/* If the command was already complete or just completed, then we didn't
* do a reset, return FAILED */
if
(
!
scb
->
flags
&
SCB_ACTIVE
)
return
FAILED
;
pause_sequencer
(
p
);
lastphase
=
aic_inb
(
p
,
LASTPHASE
);
if
(
aic7xxx_verbose
&
VERBOSE_RESET_PROCESS
)
{
...
...
@@ -10494,12 +10539,19 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
printk
(
WARN_LEAD
"Invalid SCB ID %d is active, "
"SCB flags = 0x%x.
\n
"
,
p
->
host_no
,
CTL_OF_CMD
(
cmd
),
scb
->
hscb
->
tag
,
scb
->
flags
);
return
(
SCSI_RESET_ERROR
);
unpause_sequencer
(
p
,
FALSE
);
return
FAILED
;
}
if
(
scb
->
hscb
->
tag
==
aic_inb
(
p
,
SCB_TAG
))
{
if
(
(
lastphase
!=
P_MESGOUT
)
&&
(
lastphase
!
=
P_MESGIN
)
)
if
(
(
lastphase
==
P_MESGOUT
)
||
(
lastphase
=
=
P_MESGIN
)
)
{
printk
(
WARN_LEAD
"Device reset, Message buffer "
"in use
\n
"
,
p
->
host_no
,
CTL_OF_SCB
(
scb
));
unpause_sequencer
(
p
,
FALSE
);
return
FAILED
;
}
if
(
aic7xxx_verbose
&
VERBOSE_RESET_PROCESS
)
printk
(
INFO_LEAD
"Device reset message in "
"message buffer
\n
"
,
p
->
host_no
,
CTL_OF_SCB
(
scb
));
...
...
@@ -10509,86 +10561,73 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
/* Send the abort message to the active SCB. */
aic_outb
(
p
,
HOST_MSG
,
MSG_OUT
);
aic_outb
(
p
,
lastphase
|
ATNO
,
SCSISIGO
);
return
(
SCSI_RESET_PENDING
);
}
unpause_sequencer
(
p
,
FALSE
);
spin_unlock_irq
(
p
->
host
->
host_lock
);
scsi_sleep
(
HZ
);
spin_lock_irq
(
p
->
host
->
host_lock
);
if
(
aic_dev
->
flags
&
BUS_DEVICE_RESET_PENDING
)
return
FAILED
;
else
{
/* We want to send out the message, but it could screw an already */
/* in place and being used message. Instead, we return an error */
/* to try and start the bus reset phase since this command is */
/* probably hung (aborts failed, and now reset is failing). We */
/* also make sure to set BUS_DEVICE_RESET_PENDING so we won't try */
/* any more on this device, but instead will escalate to a bus or */
/* host reset (additionally, we won't try to abort any more). */
printk
(
WARN_LEAD
"Device reset, Message buffer "
"in use
\n
"
,
p
->
host_no
,
CTL_OF_SCB
(
scb
));
scb
->
flags
|=
SCB_RESET
|
SCB_DEVICE_RESET
;
aic7xxx_error
(
cmd
)
=
DID_RESET
;
aic_dev
->
flags
|=
BUS_DEVICE_RESET_PENDING
;
return
(
SCSI_RESET_ERROR
);
}
return
SUCCESS
;
}
}
/* if (last_phase != P_BUSFREE).....indicates we are idle and can work */
hscb_index
=
aic7xxx_find_scb
(
p
,
scb
);
if
(
hscb_index
==
SCB_LIST_NULL
)
{
disconnected
=
(
aic7xxx_scb_on_qoutfifo
(
p
,
scb
))
?
FALSE
:
TRUE
;
}
else
{
aic_outb
(
p
,
hscb_index
,
SCBPTR
);
if
(
aic_inb
(
p
,
SCB_CONTROL
)
&
DISCONNECTED
)
{
disconnected
=
TRUE
;
}
}
if
(
disconnected
)
{
/*
* Simply set the MK_MESSAGE flag and the SEQINT handler will do
* the rest on a re
connect.
* the rest on a reconnect/
connect.
*/
scb
->
hscb
->
control
|=
MK_MESSAGE
;
scb
->
flags
|=
SCB_RESET
|
SCB_DEVICE_RESET
;
aic_dev
->
flags
|=
BUS_DEVICE_RESET_PENDING
;
if
(
hscb_index
!=
SCB_LIST_NULL
)
/*
* Check to see if the command is on the qinfifo. If it is, then we will
* not need to queue the command again since the card should start it soon
*/
if
(
aic7xxx_search_qinfifo
(
p
,
cmd
->
channel
,
cmd
->
target
,
cmd
->
lun
,
hscb
->
tag
,
0
,
TRUE
,
NULL
)
==
0
)
{
disconnected
=
TRUE
;
if
((
hscb_index
=
aic7xxx_find_scb
(
p
,
scb
))
!=
SCB_LIST_NULL
)
{
unsigned
char
scb_control
;
aic_outb
(
p
,
hscb_index
,
SCBPTR
);
scb_control
=
aic_inb
(
p
,
SCB_CONTROL
);
/*
* If the DISCONNECTED bit is not set in SCB_CONTROL, then we are
* actually on the waiting list, not disconnected, and we don't
* need to requeue the command.
*/
disconnected
=
(
scb_control
&
DISCONNECTED
);
aic_outb
(
p
,
scb_control
|
MK_MESSAGE
,
SCB_CONTROL
);
}
if
(
disconnected
)
{
/*
* Actually requeue this SCB in case we can select the
* device before it reconnects. If the transaction we
* want to abort is not tagged, then this will be the only
* outstanding command and we can simply shove it on the
* qoutfifo and be done. If it is tagged, then it goes right
* in with all the others, no problem :) We need to add it
* to the qinfifo and let the sequencer know it is there.
* Now, the only problem left to deal with is, *IF* this
* command completes, in spite of the MK_MESSAGE bit in the
* control byte, then we need to pick that up in the interrupt
* routine and clean things up. This *shouldn't* ever happen.
* device before it reconnects. This can result in the command
* being on the qinfifo twice, but we don't care because it will
* all get cleaned up if/when the reset takes place.
*/
if
(
aic7xxx_verbose
&
VERBOSE_RESET_PROCESS
)
printk
(
INFO_LEAD
"Queueing device reset "
"command.
\n
"
,
p
->
host_no
,
CTL_OF_SCB
(
scb
));
printk
(
INFO_LEAD
"Queueing device reset command.
\n
"
,
p
->
host_no
,
CTL_OF_SCB
(
scb
));
p
->
qinfifo
[
p
->
qinfifonext
++
]
=
scb
->
hscb
->
tag
;
if
(
p
->
features
&
AHC_QUEUE_REGS
)
aic_outb
(
p
,
p
->
qinfifonext
,
HNSCB_QOFF
);
else
aic_outb
(
p
,
p
->
qinfifonext
,
KERNEL_QINPOS
);
scb
->
flags
|=
SCB_QUEUED_ABORT
;
result
=
SCSI_RESET_PENDING
;
}
else
if
(
result
==
-
1
)
{
result
=
SCSI_RESET_ERROR
;
}
aic_outb
(
p
,
saved_scbptr
,
SCBPTR
);
return
(
result
);
unpause_sequencer
(
p
,
FALSE
);
spin_unlock_irq
(
p
->
host
->
host_lock
);
scsi_sleep
(
HZ
/
4
);
spin_lock_irq
(
p
->
host
->
host_lock
);
if
(
aic_dev
->
flags
&
BUS_DEVICE_RESET_PENDING
)
return
FAILED
;
else
return
SUCCESS
;
}
...
...
@@ -10630,12 +10669,30 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
{
struct
aic7xxx_scb
*
scb
=
NULL
;
struct
aic7xxx_host
*
p
;
struct
aic_dev_data
*
aic_dev
=
AIC_DEV
(
cmd
)
;
int
result
,
found
=
0
;
unsigned
char
tmp_char
,
saved_hscbptr
,
next_hscbptr
,
prev_hscbptr
;
int
found
=
0
,
disconnected
;
unsigned
char
saved_hscbptr
,
hscbptr
,
scb_control
;
struct
aic_dev_data
*
aic_dev
;
p
=
(
struct
aic7xxx_host
*
)
cmd
->
host
->
hostdata
;
if
(
cmd
==
NULL
)
{
printk
(
KERN_ERR
"aic7xxx_abort: called with NULL cmd!
\n
"
);
return
FAILED
;
}
p
=
(
struct
aic7xxx_host
*
)
cmd
->
host
->
hostdata
;
aic_dev
=
AIC_DEV
(
cmd
);
if
(
aic7xxx_position
(
cmd
)
<
p
->
scb_data
->
numscbs
)
scb
=
(
p
->
scb_data
->
scb_array
[
aic7xxx_position
(
cmd
)]);
else
return
FAILED
;
aic7xxx_isr
(
p
->
irq
,
(
void
*
)
p
,
NULL
);
aic7xxx_done_cmds_complete
(
p
);
/* If the command was already complete or just completed, then we didn't
* do a reset, return FAILED */
if
(
!
scb
->
flags
&
SCB_ACTIVE
)
return
FAILED
;
pause_sequencer
(
p
);
/*
* I added a new config option to the driver: "panic_on_abort" that will
...
...
@@ -10648,92 +10705,6 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
if
(
aic7xxx_panic_on_abort
)
aic7xxx_panic_abort
(
p
,
cmd
);
/*
* Run the isr to grab any command in the QOUTFIFO and any other misc.
* assundry tasks. This should also set up the bh handler if there is
* anything to be done, but it won't run until we are done here since
* we are following a straight code path without entering the scheduler
* code.
*/
pause_sequencer
(
p
);
while
(
(
aic_inb
(
p
,
INTSTAT
)
&
INT_PEND
)
&&
!
(
p
->
flags
&
AHC_IN_ISR
))
{
aic7xxx_isr
(
p
->
irq
,
p
,
(
void
*
)
NULL
);
pause_sequencer
(
p
);
}
aic7xxx_done_cmds_complete
(
p
);
if
(
scb
==
NULL
)
{
if
(
aic7xxx_verbose
&
VERBOSE_ABORT_MID
)
printk
(
INFO_LEAD
"Abort called with bogus Scsi_Cmnd "
"pointer.
\n
"
,
p
->
host_no
,
CTL_OF_CMD
(
cmd
));
unpause_sequencer
(
p
,
FALSE
);
return
(
SCSI_ABORT_NOT_RUNNING
);
}
if
(
scb
->
cmd
!=
cmd
)
/* Hmmm...either this SCB is currently free with a */
{
/* NULL cmd pointer (NULLed out when freed) or it */
/* has already been recycled for another command */
/* Either way, this SCB has nothing to do with this*/
/* command and we need to deal with cmd without */
/* touching the SCB. */
/* The theory here is to return a value that will */
/* make the queued for complete command actually */
/* finish successfully, or to indicate that we */
/* don't have this cmd any more and the mid level */
/* code needs to find it. */
if
(
aic7xxx_verbose
&
VERBOSE_ABORT_MID
)
printk
(
INFO_LEAD
"Abort called for already completed"
" command.
\n
"
,
p
->
host_no
,
CTL_OF_CMD
(
cmd
));
unpause_sequencer
(
p
,
FALSE
);
return
(
SCSI_ABORT_NOT_RUNNING
);
}
/* At this point we know the following:
* the SCB pointer is valid
* the command pointer passed in to us and the scb->cmd pointer match
* this then means that the command we need to abort is the same as the
* command held by the scb pointer and is a valid abort request.
* Now, we just have to figure out what to do from here. Current plan is:
* if we have already been here on this command, escalate to a reset
* if scb is on waiting list or QINFIFO, send it back as aborted, but
* we also need to be aware of the possibility that we could be using
* a faked negotiation command that is holding this command up, if
* so we need to take care of that command instead, which means we
* would then treat this one like it was sitting around disconnected
* instead.
* if scb is on WAITING_SCB list in sequencer, free scb and send back
* if scb is disconnected and not completed, abort with abort message
* if scb is currently running, then it may be causing the bus to hang
* so we want a return value that indicates a reset would be appropriate
* if the command does not finish shortly
* if scb is already complete but not on completeq, we're screwed because
* this can't happen (except if the command is in the QOUTFIFO, in which
* case we would like it to complete successfully instead of having to
* to be re-done)
* All other scenarios already dealt with by previous code.
*/
if
(
scb
->
flags
&
(
SCB_ABORT
|
SCB_RESET
|
SCB_QUEUED_ABORT
)
)
{
if
(
aic7xxx_verbose
&
VERBOSE_ABORT_PROCESS
)
printk
(
INFO_LEAD
"SCB aborted once already, "
"escalating.
\n
"
,
p
->
host_no
,
CTL_OF_SCB
(
scb
));
unpause_sequencer
(
p
,
FALSE
);
return
(
SCSI_ABORT_SNOOZE
);
}
if
(
(
p
->
flags
&
(
AHC_RESET_PENDING
|
AHC_ABORT_PENDING
))
||
(
aic_dev
->
flags
&
BUS_DEVICE_RESET_PENDING
)
)
{
if
(
aic7xxx_verbose
&
VERBOSE_ABORT_PROCESS
)
printk
(
INFO_LEAD
"Reset/Abort pending for this "
"device, not wasting our time.
\n
"
,
p
->
host_no
,
CTL_OF_SCB
(
scb
));
unpause_sequencer
(
p
,
FALSE
);
return
(
SCSI_ABORT_PENDING
);
}
found
=
0
;
p
->
flags
|=
AHC_IN_ABORT
;
if
(
aic7xxx_verbose
&
VERBOSE_ABORT
)
{
printk
(
INFO_LEAD
"Aborting scb %d, flags 0x%x, SEQADDR 0x%x, LASTPHASE "
...
...
@@ -10750,56 +10721,8 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
aic_inb
(
p
,
SSTAT1
),
aic_inb
(
p
,
SSTAT2
));
}
/*
* First, let's check to see if the currently running command is our target
* since if it is, the return is fairly easy and quick since we don't want
* to touch the command in case it might complete, but we do want a timeout
* in case it's actually hung, so we really do nothing, but tell the mid
* level code to reset the timeout.
*/
if
(
scb
->
hscb
->
tag
==
aic_inb
(
p
,
SCB_TAG
)
)
if
(
scb
->
flags
&
SCB_WAITINGQ
)
{
/*
* Check to see if the sequencer is just sitting on this command, or
* if it's actively being run.
*/
result
=
aic_inb
(
p
,
LASTPHASE
);
switch
(
result
)
{
case
P_DATAOUT
:
/* For any of these cases, we can assume we are */
case
P_DATAIN
:
/* an active command and act according. For */
case
P_COMMAND
:
/* anything else we are going to fall on through*/
case
P_STATUS
:
/* The SCSI_ABORT_SNOOZE will give us two abort */
case
P_MESGOUT
:
/* chances to finish and then escalate to a */
case
P_MESGIN
:
/* reset call */
if
(
aic7xxx_verbose
&
VERBOSE_ABORT_PROCESS
)
printk
(
INFO_LEAD
"SCB is currently active. "
"Waiting on completion.
\n
"
,
p
->
host_no
,
CTL_OF_SCB
(
scb
));
printk
(
INFO_LEAD
"SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
"0x%x
\n
"
,
p
->
host_no
,
CTL_OF_SCB
(
scb
),
aic_inb
(
p
,
SCSISIGI
),
aic_inb
(
p
,
SEQADDR0
)
|
(
aic_inb
(
p
,
SEQADDR1
)
<<
8
),
aic_inb
(
p
,
SSTAT0
),
aic_inb
(
p
,
SSTAT1
));
printk
(
INFO_LEAD
"SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x
\n
"
,
p
->
host_no
,
CTL_OF_SCB
(
scb
),
(
p
->
features
&
AHC_ULTRA2
)
?
aic_inb
(
p
,
SG_CACHEPTR
)
:
0
,
aic_inb
(
p
,
SSTAT2
),
aic_inb
(
p
,
STCNT
+
2
)
<<
16
|
aic_inb
(
p
,
STCNT
+
1
)
<<
8
|
aic_inb
(
p
,
STCNT
));
unpause_sequencer
(
p
,
FALSE
);
p
->
flags
&=
~
AHC_IN_ABORT
;
scb
->
flags
|=
SCB_RECOVERY_SCB
;
/* Note the fact that we've been */
p
->
flags
|=
AHC_ABORT_PENDING
;
/* here so we will know not to */
return
(
SCSI_ABORT_PENDING
);
/* one doesn't complete and clear */
break
;
/* out. */
default:
break
;
}
}
if
((
found
==
0
)
&&
(
scb
->
flags
&
SCB_WAITINGQ
))
{
if
(
aic7xxx_verbose
&
VERBOSE_ABORT_PROCESS
)
printk
(
INFO_LEAD
"SCB found on waiting list and "
"aborted.
\n
"
,
p
->
host_no
,
CTL_OF_SCB
(
scb
));
...
...
@@ -10809,95 +10732,123 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
p
->
activescbs
++
;
scb
->
flags
&=
~
(
SCB_WAITINGQ
|
SCB_ACTIVE
);
scb
->
flags
|=
SCB_ABORT
|
SCB_QUEUED_FOR_DONE
;
found
=
1
;
goto
success
;
}
/*
* We just checked the waiting_q, now for the QINFIFO
*/
if
(
found
==
0
)
{
if
(
((
found
=
aic7xxx_search_qinfifo
(
p
,
cmd
->
target
,
cmd
->
channel
,
if
(
((
found
=
aic7xxx_search_qinfifo
(
p
,
cmd
->
target
,
cmd
->
channel
,
cmd
->
lun
,
scb
->
hscb
->
tag
,
SCB_ABORT
|
SCB_QUEUED_FOR_DONE
,
FALSE
,
NULL
))
!=
0
)
&&
(
aic7xxx_verbose
&
VERBOSE_ABORT_PROCESS
))
printk
(
INFO_LEAD
"SCB found in QINFIFO and "
"aborted.
\n
"
,
p
->
host_no
,
CTL_OF_SCB
(
scb
));
{
printk
(
INFO_LEAD
"SCB found in QINFIFO and aborted.
\n
"
,
p
->
host_no
,
CTL_OF_SCB
(
scb
));
goto
success
;
}
/*
* QINFIFO, waitingq, completeq done. Next, check WAITING_SCB list in card
*/
if
(
found
==
0
)
{
unsigned
char
scb_next_ptr
;
prev_hscbptr
=
SCB_LIST_NULL
;
saved_hscbptr
=
aic_inb
(
p
,
SCBPTR
);
next_hscbptr
=
aic_inb
(
p
,
WAITING_SCBH
);
while
(
next_hscbptr
!=
SCB_LIST_NULL
)
{
aic_outb
(
p
,
next_hscbptr
,
SCBPTR
);
if
(
scb
->
hscb
->
tag
==
aic_inb
(
p
,
SCB_TAG
)
)
if
((
hscbptr
=
aic7xxx_find_scb
(
p
,
scb
))
!=
SCB_LIST_NULL
)
{
found
=
1
;
aic_outb
(
p
,
hscbptr
,
SCBPTR
);
scb_control
=
aic_inb
(
p
,
SCB_CONTROL
);
disconnected
=
scb_control
&
DISCONNECTED
;
/*
* If the DISCONNECTED bit is not set in SCB_CONTROL, then we are
* either currently active or on the waiting list.
*/
if
(
!
disconnected
&&
aic_inb
(
p
,
LASTPHASE
)
==
P_BUSFREE
)
{
if
(
aic7xxx_verbose
&
VERBOSE_ABORT_PROCESS
)
printk
(
INFO_LEAD
"SCB found on hardware waiting"
" list and aborted.
\n
"
,
p
->
host_no
,
CTL_OF_SCB
(
scb
));
if
(
prev_hscbptr
==
SCB_LIST_NULL
)
/* If we are the only waiting command, stop the selection engine */
if
(
aic_inb
(
p
,
WAITING_SCBH
)
==
hscbptr
&&
aic_inb
(
p
,
SCB_NEXT
)
==
SCB_LIST_NULL
)
{
aic_outb
(
p
,
aic_inb
(
p
,
SCB_NEXT
),
WAITING_SCBH
);
/* stop the selection since we just
* grabbed the scb out from under the
* card
*/
aic_outb
(
p
,
aic_inb
(
p
,
SCSISEQ
)
&
~
ENSELO
,
SCSISEQ
);
aic_outb
(
p
,
CLRSELTIMEO
,
CLRSINT1
);
aic_outb
(
p
,
SCB_LIST_NULL
,
WAITING_SCBH
);
}
else
{
scb_next_ptr
=
aic_inb
(
p
,
SCB_NEXT
);
aic_outb
(
p
,
prev_hscbptr
,
SCBPTR
);
aic_outb
(
p
,
scb_next_ptr
,
SCB_NEXT
);
aic_outb
(
p
,
next_hscbptr
,
SCBPTR
);
unsigned
char
prev
,
next
;
prev
=
SCB_LIST_NULL
;
next
=
aic_inb
(
p
,
WAITING_SCBH
);
while
(
next
!=
SCB_LIST_NULL
)
{
aic_outb
(
p
,
next
,
SCBPTR
);
if
(
next
==
hscbptr
)
{
next
=
aic_inb
(
p
,
SCB_NEXT
);
if
(
prev
!=
SCB_LIST_NULL
)
{
aic_outb
(
p
,
prev
,
SCBPTR
);
aic_outb
(
p
,
next
,
SCB_NEXT
);
}
else
aic_outb
(
p
,
next
,
WAITING_SCBH
);
aic_outb
(
p
,
hscbptr
,
SCBPTR
);
next
=
SCB_LIST_NULL
;
}
else
{
prev
=
next
;
next
=
aic_inb
(
p
,
SCB_NEXT
);
}
}
}
aic_outb
(
p
,
SCB_LIST_NULL
,
SCB_TAG
);
aic_outb
(
p
,
0
,
SCB_CONTROL
);
aic7xxx_add_curscb_to_free_list
(
p
);
scb
->
flags
=
SCB_ABORT
|
SCB_QUEUED_FOR_DONE
;
break
;
goto
success
;
}
else
if
(
!
disconnected
)
{
/*
* We are the currently active command
*/
if
((
aic_inb
(
p
,
LASTPHASE
)
==
P_MESGIN
)
||
(
aic_inb
(
p
,
LASTPHASE
)
==
P_MESGOUT
))
{
/*
* Message buffer busy, unable to abort
*/
printk
(
INFO_LEAD
"message buffer busy, unable to abort.
\n
"
,
p
->
host_no
,
CTL_OF_SCB
(
scb
));
unpause_sequencer
(
p
,
FALSE
);
return
FAILED
;
}
/* Fallthrough to below, set ATNO after we set SCB_CONTROL */
}
prev_hscbptr
=
next_hscbptr
;
next_hscbptr
=
aic_inb
(
p
,
SCB_NEXT
);
aic_outb
(
p
,
scb_control
|
MK_MESSAGE
,
SCB_CONTROL
);
if
(
!
disconnected
)
{
aic_outb
(
p
,
HOST_MSG
,
MSG_OUT
);
aic_outb
(
p
,
aic_inb
(
p
,
SCSISIGI
)
|
ATNO
,
SCSISIGO
);
}
aic_outb
(
p
,
saved_hscbptr
,
SCBPTR
);
aic_outb
(
p
,
saved_hscbptr
,
SCBPTR
);
}
/*
* Hmmm...completeq, QOUTFIFO, QINFIFO, WAITING_SCBH, waitingq all checked.
* OK...the sequencer's paused, interrupts are off, and we haven't found the
* command anyplace where it could be easily aborted. Time for the hard
* work. We also know the command is valid. This essentially means the
* command is disconnected, or connected but not into any phases yet, which
* we know due to the tests we ran earlier on the current active scb phase.
* At this point we can queue the abort tag and go on with life.
else
{
/*
* The scb isn't in the card at all and it is active and it isn't in
* any of the queues, so it must be disconnected and paged out. Fall
* through to the code below.
*/
disconnected
=
1
;
}
if
(
found
==
0
)
{
p
->
flags
|=
AHC_ABORT_PENDING
;
scb
->
flags
|=
SCB_QUEUED_ABORT
|
SCB_ABORT
|
SCB_RECOVERY_SCB
;
scb
->
hscb
->
control
|=
MK_MESSAGE
;
result
=
aic7xxx_find_scb
(
p
,
scb
);
if
(
result
!=
SCB_LIST_NULL
)
if
(
disconnected
)
{
saved_hscbptr
=
aic_inb
(
p
,
SCBPTR
);
aic_outb
(
p
,
result
,
SCBPTR
);
tmp_char
=
aic_inb
(
p
,
SCB_CONTROL
);
aic_outb
(
p
,
tmp_char
|
MK_MESSAGE
,
SCB_CONTROL
);
aic_outb
(
p
,
saved_hscbptr
,
SCBPTR
);
}
if
(
aic7xxx_verbose
&
VERBOSE_ABORT_PROCESS
)
printk
(
INFO_LEAD
"SCB disconnected. Queueing Abort"
" SCB.
\n
"
,
p
->
host_no
,
CTL_OF_SCB
(
scb
));
...
...
@@ -10907,31 +10858,30 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
else
aic_outb
(
p
,
p
->
qinfifonext
,
KERNEL_QINPOS
);
}
if
(
found
)
unpause_sequencer
(
p
,
FALSE
);
spin_unlock_irq
(
p
->
host
->
host_lock
);
scsi_sleep
(
HZ
/
4
);
spin_lock_irq
(
p
->
host
->
host_lock
);
if
(
p
->
flags
&
AHC_ABORT_PENDING
)
{
aic7xxx_run_done_queue
(
p
,
TRUE
);
aic7xxx_run_waiting_queues
(
p
);
if
(
aic7xxx_verbose
&
VERBOSE_ABORT_RETURN
)
printk
(
INFO_LEAD
"Abort never delivered, returning FAILED
\n
"
,
p
->
host_no
,
CTL_OF_CMD
(
cmd
));
p
->
flags
&=
~
AHC_ABORT_PENDING
;
return
FAILED
;
}
p
->
flags
&=
~
AHC_IN_ABORT
;
unpause_sequencer
(
p
,
FALSE
);
if
(
aic7xxx_verbose
&
VERBOSE_ABORT_RETURN
)
printk
(
INFO_LEAD
"Abort successful.
\n
"
,
p
->
host_no
,
CTL_OF_CMD
(
cmd
));
return
SUCCESS
;
/*
* On the return value. If we found the command and aborted it, then we know
* it's already sent back and there is no reason for a further timeout, so
* we use SCSI_ABORT_SUCCESS. On the queued abort side, we aren't so certain
* there hasn't been a bus hang or something that might keep the abort from
* from completing. Therefore, we use SCSI_ABORT_PENDING. The first time this
* is passed back, the timeout on the command gets extended, the second time
* we pass this back, the mid level SCSI code calls our reset function, which
* would shake loose a hung bus.
*/
if
(
found
!=
0
)
return
(
SCSI_ABORT_SUCCESS
);
else
return
(
SCSI_ABORT_PENDING
);
success:
if
(
aic7xxx_verbose
&
VERBOSE_ABORT_RETURN
)
printk
(
INFO_LEAD
"Abort successful.
\n
"
,
p
->
host_no
,
CTL_OF_CMD
(
cmd
));
aic7xxx_run_done_queue
(
p
,
TRUE
);
unpause_sequencer
(
p
,
FALSE
);
return
SUCCESS
;
}
/*+F*************************************************************************
* Function:
* aic7xxx_reset
...
...
@@ -10943,38 +10893,24 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
* the SCSI bus reset line.
*-F*************************************************************************/
int
aic7xxx_reset
(
Scsi_Cmnd
*
cmd
,
unsigned
int
flags
)
aic7xxx_reset
(
Scsi_Cmnd
*
cmd
)
{
struct
aic7xxx_scb
*
scb
=
NULL
;
struct
aic7xxx_scb
*
scb
;
struct
aic7xxx_host
*
p
;
struct
aic_dev_data
*
aic_dev
;
int
tindex
;
int
result
=
-
1
;
#define DEVICE_RESET 0x01
#define BUS_RESET 0x02
#define HOST_RESET 0x04
#define RESET_DELAY 0x08
int
action
;
if
(
cmd
==
NULL
)
{
printk
(
KERN_WARNING
"(scsi?:?:?:?) Reset called with NULL Scsi_Cmnd "
"pointer, failing.
\n
"
);
return
(
SCSI_RESET_SNOOZE
);
}
p
=
(
struct
aic7xxx_host
*
)
cmd
->
host
->
hostdata
;
aic_dev
=
AIC_DEV
(
cmd
);
if
(
aic
_dev
)
if
(
aic
7xxx_position
(
cmd
)
<
p
->
scb_data
->
numscbs
)
{
scb
=
(
p
->
scb_data
->
scb_array
[
aic7xxx_position
(
cmd
)]);
if
(
scb
->
cmd
!=
cmd
)
scb
=
NULL
;
}
else
{
scb
=
NULL
;
}
tindex
=
TARGET_INDEX
(
cmd
);
/*
* I added a new config option to the driver: "panic_on_abort" that will
...
...
@@ -10989,44 +10925,6 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
pause_sequencer
(
p
);
if
(
flags
&
SCSI_RESET_SYNCHRONOUS
)
{
if
(
aic7xxx_verbose
&
VERBOSE_RESET_MID
)
printk
(
INFO_LEAD
"Reset called for a SYNCHRONOUS reset, flags 0x%x, "
"cmd->result 0x%x.
\n
"
,
p
->
host_no
,
CTL_OF_CMD
(
cmd
),
flags
,
cmd
->
result
);
scb
=
NULL
;
action
=
HOST_RESET
;
}
else
if
((
scb
==
NULL
)
||
(
scb
->
cmd
!=
cmd
))
{
if
(
aic7xxx_verbose
&
VERBOSE_RESET_MID
)
printk
(
INFO_LEAD
"Reset called with bogus Scsi_Cmnd"
"->SCB mapping, failing.
\n
"
,
p
->
host_no
,
CTL_OF_CMD
(
cmd
));
aic7xxx_done_cmds_complete
(
p
);
aic7xxx_run_waiting_queues
(
p
);
unpause_sequencer
(
p
,
FALSE
);
return
(
SCSI_RESET_NOT_RUNNING
);
}
else
{
if
(
aic7xxx_verbose
&
VERBOSE_RESET_MID
)
printk
(
INFO_LEAD
"Reset called, scb %d, flags "
"0x%x
\n
"
,
p
->
host_no
,
CTL_OF_SCB
(
scb
),
scb
->
hscb
->
tag
,
scb
->
flags
);
if
(
flags
&
SCSI_RESET_SUGGEST_HOST_RESET
)
{
action
=
HOST_RESET
;
}
else
if
(
flags
&
SCSI_RESET_SUGGEST_BUS_RESET
)
{
action
=
BUS_RESET
;
}
else
{
action
=
DEVICE_RESET
;
}
}
while
((
aic_inb
(
p
,
INTSTAT
)
&
INT_PEND
)
&&
!
(
p
->
flags
&
AHC_IN_ISR
))
{
aic7xxx_isr
(
p
->
irq
,
p
,
(
void
*
)
NULL
);
...
...
@@ -11040,134 +10938,32 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
* We just completed the command when we ran the isr stuff, so we no
* longer have it.
*/
aic7xxx_run_waiting_queues
(
p
);
unpause_sequencer
(
p
,
FALSE
);
return
(
SCSI_RESET_SUCCESS
)
;
return
SUCCESS
;
}
if
(
(
action
&
DEVICE_RESET
)
&&
(
aic_dev
->
flags
&
BUS_DEVICE_RESET_PENDING
)
)
{
if
(
aic7xxx_verbose
&
VERBOSE_RESET_PROCESS
)
printk
(
INFO_LEAD
"Bus device reset already sent to "
"device, escalating.
\n
"
,
p
->
host_no
,
CTL_OF_CMD
(
cmd
));
action
=
BUS_RESET
;
}
if
(
(
action
&
DEVICE_RESET
)
&&
(
scb
->
flags
&
SCB_QUEUED_ABORT
)
)
{
if
(
aic7xxx_verbose
&
VERBOSE_RESET_PROCESS
)
{
printk
(
INFO_LEAD
"Have already attempted to reach "
"device with queued
\n
"
,
p
->
host_no
,
CTL_OF_CMD
(
cmd
));
printk
(
INFO_LEAD
"message, will escalate to bus "
"reset.
\n
"
,
p
->
host_no
,
CTL_OF_CMD
(
cmd
));
}
action
=
BUS_RESET
;
}
if
(
(
action
&
DEVICE_RESET
)
&&
(
p
->
flags
&
(
AHC_RESET_PENDING
|
AHC_ABORT_PENDING
))
)
{
if
(
aic7xxx_verbose
&
VERBOSE_RESET_PROCESS
)
printk
(
INFO_LEAD
"Bus device reset stupid when "
"other action has failed.
\n
"
,
p
->
host_no
,
CTL_OF_CMD
(
cmd
));
action
=
BUS_RESET
;
}
if
(
(
action
&
BUS_RESET
)
&&
!
(
p
->
features
&
AHC_TWIN
)
)
{
action
=
HOST_RESET
;
}
if
(
(
aic_dev
->
flags
&
DEVICE_RESET_DELAY
)
&&
!
(
action
&
(
HOST_RESET
|
BUS_RESET
)))
{
if
(
aic7xxx_verbose
&
VERBOSE_RESET_PROCESS
)
{
printk
(
INFO_LEAD
"Reset called too soon after last "
"reset without requesting
\n
"
,
p
->
host_no
,
CTL_OF_CMD
(
cmd
));
printk
(
INFO_LEAD
"bus or host reset, escalating.
\n
"
,
p
->
host_no
,
CTL_OF_CMD
(
cmd
));
}
action
=
BUS_RESET
;
}
if
(
(
p
->
flags
&
AHC_RESET_DELAY
)
&&
(
action
&
(
HOST_RESET
|
BUS_RESET
))
)
{
if
(
aic7xxx_verbose
&
VERBOSE_RESET_PROCESS
)
printk
(
INFO_LEAD
"Reset called too soon after "
"last bus reset, delaying.
\n
"
,
p
->
host_no
,
CTL_OF_CMD
(
cmd
));
action
=
RESET_DELAY
;
}
/*
* By this point, we want to already know what we are going to do and
* only have the following code implement our course of action.
*/
switch
(
action
)
{
case
RESET_DELAY
:
aic7xxx_run_waiting_queues
(
p
);
unpause_sequencer
(
p
,
FALSE
);
if
(
scb
==
NULL
)
return
(
SCSI_RESET_PUNT
);
else
return
(
SCSI_RESET_PENDING
);
break
;
case
DEVICE_RESET
:
p
->
flags
|=
AHC_IN_RESET
;
result
=
aic7xxx_bus_device_reset
(
p
,
cmd
);
aic7xxx_run_done_queue
(
p
,
TRUE
);
/* We can't rely on run_waiting_queues to unpause the sequencer for
* PCI based controllers since we use AAP */
aic7xxx_run_waiting_queues
(
p
);
unpause_sequencer
(
p
,
FALSE
);
p
->
flags
&=
~
AHC_IN_RESET
;
return
(
result
);
break
;
case
BUS_RESET
:
case
HOST_RESET
:
default:
p
->
flags
|=
AHC_IN_RESET
|
AHC_RESET_DELAY
;
aic7xxx_reset_channel
(
p
,
cmd
->
channel
,
TRUE
);
if
(
(
p
->
features
&
AHC_TWIN
)
&&
(
action
&
HOST_RESET
)
)
if
(
p
->
features
&
AHC_TWIN
)
{
aic7xxx_reset_channel
(
p
,
cmd
->
channel
^
0x01
,
TRUE
);
restart_sequencer
(
p
);
}
if
(
action
!=
HOST_RESET
)
result
=
SCSI_RESET_SUCCESS
|
SCSI_RESET_BUS_RESET
;
else
{
result
=
SCSI_RESET_SUCCESS
|
SCSI_RESET_HOST_RESET
;
aic_outb
(
p
,
aic_inb
(
p
,
SIMODE1
)
&
~
(
ENREQINIT
|
ENBUSFREE
),
SIMODE1
);
aic_outb
(
p
,
aic_inb
(
p
,
SIMODE1
)
&
~
(
ENREQINIT
|
ENBUSFREE
),
SIMODE1
);
aic7xxx_clear_intstat
(
p
);
p
->
flags
&=
~
AHC_HANDLING_REQINITS
;
p
->
msg_type
=
MSG_TYPE_NONE
;
p
->
msg_index
=
0
;
p
->
msg_len
=
0
;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
if
(
flags
&
SCSI_RESET_SYNCHRONOUS
)
{
cmd
->
result
=
DID_RESET
<<
16
;
cmd
->
done
(
cmd
);
}
#endif
aic7xxx_run_done_queue
(
p
,
TRUE
);
p
->
flags
&=
~
AHC_IN_RESET
;
/*
* We can't rely on run_waiting_queues to unpause the sequencer for
* PCI based controllers since we use AAP. NOTE: this also sets
* the timer for the one command we might have queued in the case
* of a synch reset.
*/
aic7xxx_run_waiting_queues
(
p
);
unpause_sequencer
(
p
,
FALSE
);
if
(
scb
==
NULL
)
return
(
SCSI_RESET_SUCCESS
|
SCSI_RESET_HOST_RESET
);
else
return
(
result
);
break
;
}
spin_unlock_irq
(
p
->
host
->
host_lock
);
scsi_sleep
(
2
*
HZ
);
spin_lock_irq
(
p
->
host
->
host_lock
);
return
SUCCESS
;
}
/*+F*************************************************************************
...
...
drivers/scsi/aic7xxx_old/aic7xxx.h
View file @
9096518f
...
...
@@ -38,6 +38,9 @@
slave_attach: aic7xxx_slave_attach, \
slave_detach: aic7xxx_slave_detach, \
bios_param: aic7xxx_biosparam, \
eh_abort_handler: aic7xxx_abort, \
eh_device_reset_handler: aic7xxx_bus_device_reset, \
eh_host_reset_handler: aic7xxx_reset, \
can_queue: 255,
/* max simultaneous cmds */
\
this_id: -1,
/* scsi id of host adapter */
\
sg_tablesize: 0,
/* max scatter-gather cmds */
\
...
...
@@ -55,6 +58,9 @@ extern int aic7xxx_command(Scsi_Cmnd *);
extern
int
aic7xxx_release
(
struct
Scsi_Host
*
);
extern
int
aic7xxx_slave_attach
(
Scsi_Device
*
);
extern
void
aic7xxx_slave_detach
(
Scsi_Device
*
);
extern
int
aic7xxx_abort
(
Scsi_Cmnd
*
);
extern
int
aic7xxx_bus_device_reset
(
Scsi_Cmnd
*
);
extern
int
aic7xxx_reset
(
Scsi_Cmnd
*
);
extern
const
char
*
aic7xxx_info
(
struct
Scsi_Host
*
);
...
...
drivers/scsi/aic7xxx_old/aic7xxx_proc.c
View file @
9096518f
...
...
@@ -90,7 +90,6 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
int
size
=
0
;
unsigned
char
i
;
unsigned
char
tindex
;
struct
list_head
*
list_item
;
HBAptr
=
NULL
;
...
...
@@ -132,10 +131,8 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
*/
size
=
4096
;
list_for_each
(
list_item
,
&
p
->
aic_devs
)
{
list_for_each_entry
(
aic_dev
,
&
p
->
aic_devs
,
list
)
size
+=
512
;
}
if
(
aic7xxx_buffer_size
!=
size
)
{
if
(
aic7xxx_buffer
!=
NULL
)
...
...
@@ -157,13 +154,6 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
size
+=
sprintf
(
BLS
,
"Adaptec AIC7xxx driver version: "
);
size
+=
sprintf
(
BLS
,
"%s/"
,
AIC7XXX_C_VERSION
);
size
+=
sprintf
(
BLS
,
"%s"
,
AIC7XXX_H_VERSION
);
size
+=
sprintf
(
BLS
,
"
\n
"
);
size
+=
sprintf
(
BLS
,
"Compile Options:
\n
"
);
#ifdef CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT
size
+=
sprintf
(
BLS
,
" TCQ Enabled By Default : Enabled
\n
"
);
#else
size
+=
sprintf
(
BLS
,
" TCQ Enabled By Default : Disabled
\n
"
);
#endif
size
+=
sprintf
(
BLS
,
"
\n
"
);
size
+=
sprintf
(
BLS
,
"Adapter Configuration:
\n
"
);
size
+=
sprintf
(
BLS
,
" SCSI Adapter: %s
\n
"
,
...
...
@@ -263,7 +253,7 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
{
size
+=
sprintf
(
BLS
,
" Ultra Enable Flags: 0x%04x
\n
"
,
p
->
ultraenb
);
}
size
+=
sprintf
(
BLS
,
"Default Tag Queue Depth: %d
\n
"
,
AIC7XXX_CMDS_PER_DEVICE
);
size
+=
sprintf
(
BLS
,
"Default Tag Queue Depth: %d
\n
"
,
aic7xxx_default_queue_depth
);
size
+=
sprintf
(
BLS
,
" Tagged Queue By Device array for aic7xxx host "
"instance %d:
\n
"
,
p
->
instance
);
size
+=
sprintf
(
BLS
,
" {"
);
...
...
@@ -273,9 +263,8 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
size
+=
sprintf
(
BLS
,
"
\n
"
);
size
+=
sprintf
(
BLS
,
"Statistics:
\n\n
"
);
list_for_each
(
list_item
,
&
p
->
aic_devs
)
list_for_each
_entry
(
aic_dev
,
&
p
->
aic_devs
,
list
)
{
aic_dev
=
list_entry
(
list_item
,
struct
aic_dev_data
,
list
);
sdptr
=
aic_dev
->
SDptr
;
tindex
=
sdptr
->
channel
<<
3
|
sdptr
->
id
;
size
+=
sprintf
(
BLS
,
"(scsi%d:%d:%d:%d)
\n
"
,
...
...
@@ -322,24 +311,32 @@ aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
p
->
user
[
tindex
].
offset
,
p
->
user
[
tindex
].
width
,
p
->
user
[
tindex
].
options
);
size
+=
sprintf
(
BLS
,
" Total transfers %ld (%ld reads and %ld writes)
\n
"
,
aic_dev
->
r_total
+
aic_dev
->
w_total
,
aic_dev
->
r_total
,
aic_dev
->
w_total
);
if
(
sdptr
->
simple_tags
)
{
size
+=
sprintf
(
BLS
,
" Tagged Command Queueing Enabled, Ordered Tags %s
\n
"
,
sdptr
->
ordered_tags
?
"Enabled"
:
"Disabled"
);
}
if
(
aic_dev
->
barrier_total
)
size
+=
sprintf
(
BLS
,
" Total transfers %ld:
\n
(%ld/%ld/%ld/%ld reads/writes/REQ_BARRIER/Ordered Tags)
\n
"
,
aic_dev
->
r_total
+
aic_dev
->
w_total
,
aic_dev
->
r_total
,
aic_dev
->
w_total
,
aic_dev
->
barrier_total
,
aic_dev
->
ordered_total
);
else
size
+=
sprintf
(
BLS
,
" Total transfers %ld:
\n
(%ld/%ld reads/writes)
\n
"
,
aic_dev
->
r_total
+
aic_dev
->
w_total
,
aic_dev
->
r_total
,
aic_dev
->
w_total
);
size
+=
sprintf
(
BLS
,
"%s
\n
"
,
HDRB
);
size
+=
sprintf
(
BLS
,
" Reads:"
);
for
(
i
=
0
;
i
<
NUMBER
(
aic_dev
->
r_bins
);
i
++
)
{
size
+=
sprintf
(
BLS
,
" %
7
ld"
,
aic_dev
->
r_bins
[
i
]);
size
+=
sprintf
(
BLS
,
" %
10
ld"
,
aic_dev
->
r_bins
[
i
]);
}
size
+=
sprintf
(
BLS
,
"
\n
"
);
size
+=
sprintf
(
BLS
,
" Writes:"
);
for
(
i
=
0
;
i
<
NUMBER
(
aic_dev
->
w_bins
);
i
++
)
{
size
+=
sprintf
(
BLS
,
" %
7
ld"
,
aic_dev
->
w_bins
[
i
]);
size
+=
sprintf
(
BLS
,
" %
10
ld"
,
aic_dev
->
w_bins
[
i
]);
}
size
+=
sprintf
(
BLS
,
"
\n
"
);
size
+=
sprintf
(
BLS
,
"
\n\n
"
);
}
if
(
size
>=
aic7xxx_buffer_size
)
{
printk
(
KERN_WARNING
"aic7xxx: Overflow in aic7xxx_proc.c
\n
"
);
...
...
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