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
Kirill Smelkov
linux
Commits
16119ae5
Commit
16119ae5
authored
Nov 23, 2007
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Import 1.1.12
parent
b7c2deb6
Changes
30
Hide whitespace changes
Inline
Side-by-side
Showing
30 changed files
with
2735 additions
and
913 deletions
+2735
-913
CREDITS
CREDITS
+17
-1
Makefile
Makefile
+1
-1
config.in
config.in
+13
-0
drivers/net/slip.c
drivers/net/slip.c
+4
-2
drivers/scsi/README.st
drivers/scsi/README.st
+141
-0
drivers/scsi/st.c
drivers/scsi/st.c
+466
-225
drivers/scsi/st.h
drivers/scsi/st.h
+6
-1
drivers/scsi/wd7000.c
drivers/scsi/wd7000.c
+914
-302
drivers/scsi/wd7000.h
drivers/scsi/wd7000.h
+17
-170
fs/buffer.c
fs/buffer.c
+1
-1
fs/proc/net.c
fs/proc/net.c
+12
-5
include/linux/if_arp.h
include/linux/if_arp.h
+7
-0
include/linux/if_slip.h
include/linux/if_slip.h
+19
-0
include/linux/ip.h
include/linux/ip.h
+18
-0
include/linux/mtio.h
include/linux/mtio.h
+19
-0
include/linux/netdevice.h
include/linux/netdevice.h
+5
-8
include/linux/sockios.h
include/linux/sockios.h
+17
-0
include/linux/tcp.h
include/linux/tcp.h
+18
-5
init/main.c
init/main.c
+4
-0
kernel/sys.c
kernel/sys.c
+2
-2
kernel/vm86.c
kernel/vm86.c
+12
-5
net/inet/arp.c
net/inet/arp.c
+232
-131
net/inet/arp.h
net/inet/arp.h
+3
-0
net/inet/ip.c
net/inet/ip.c
+2
-2
net/inet/rarp.c
net/inet/rarp.c
+512
-0
net/inet/rarp.h
net/inet/rarp.h
+14
-0
net/inet/sock.c
net/inet/sock.c
+8
-2
net/inet/tcp.c
net/inet/tcp.c
+231
-47
net/inet/timer.c
net/inet/timer.c
+1
-1
net/inet/udp.c
net/inet/udp.c
+19
-2
No files found.
CREDITS
View file @
16119ae5
...
@@ -34,7 +34,7 @@ S: 76297 Stutensee
...
@@ -34,7 +34,7 @@ S: 76297 Stutensee
S: Germany
S: Germany
N: Donald Becker
N: Donald Becker
E: becker@
super.org
E: becker@
cesdis.gsfc.nasa.gov
D: General low-level networking hacker
D: General low-level networking hacker
D: Most of the ethercard drivers
D: Most of the ethercard drivers
D: Original author of the NFS server
D: Original author of the NFS server
...
@@ -107,6 +107,7 @@ S: Bellevue WA 98007
...
@@ -107,6 +107,7 @@ S: Bellevue WA 98007
S: USA
S: USA
N: Alan Cox
N: Alan Cox
E: A.Cox@swansea.ac.uk
E: iiitac@pyr.swan.ac.uk
E: iiitac@pyr.swan.ac.uk
E: gw4pts@gw4pts.ampr.org
E: gw4pts@gw4pts.ampr.org
E: GW4PTS@GB7SWN (packet radio)
E: GW4PTS@GB7SWN (packet radio)
...
@@ -418,6 +419,14 @@ S: Dragonvagen 1 A 13
...
@@ -418,6 +419,14 @@ S: Dragonvagen 1 A 13
S: FIN-00330 Helsingfors
S: FIN-00330 Helsingfors
S: Finland
S: Finland
N: David C. Niemi
E: David.Niemi@oasis.gtegsc.com
D: FSSTND, The XFree86 Project
D: DMA memory support and future floppy driver
S: 2364 Old Trail Drive
S: Reston, VA 22091
S: USA
N: Kai Petzke
N: Kai Petzke
E: wpp@marie.physik.tu-berlin.de
E: wpp@marie.physik.tu-berlin.de
D: Driver for Laser Magnetic Storage CD-ROM
D: Driver for Laser Magnetic Storage CD-ROM
...
@@ -451,6 +460,13 @@ N: Robert Sanders
...
@@ -451,6 +460,13 @@ N: Robert Sanders
E: gt8134b@prism.gatech.edu
E: gt8134b@prism.gatech.edu
D: Dosemu
D: Dosemu
N: Hannu Savolainen
E: hannu@voxware.pp.fi
D: Kernel sound drivers
S: Pallaksentie 4 A 2
S: 00970 Helsinki
S: Finland
N: Peter De Schrijver
N: Peter De Schrijver
E: stud11@cc4.kuleuven.ac.be
E: stud11@cc4.kuleuven.ac.be
D: Mitsumi CD-ROM driver patches March version
D: Mitsumi CD-ROM driver patches March version
...
...
Makefile
View file @
16119ae5
VERSION
=
1
VERSION
=
1
PATCHLEVEL
=
1
PATCHLEVEL
=
1
SUBLEVEL
=
1
1
SUBLEVEL
=
1
2
all
:
Version zImage
all
:
Version zImage
...
...
config.in
View file @
16119ae5
...
@@ -13,6 +13,19 @@ bool 'Limit memory to low 16MB' CONFIG_MAX_16M n
...
@@ -13,6 +13,19 @@ bool 'Limit memory to low 16MB' CONFIG_MAX_16M n
bool 'System V IPC' CONFIG_SYSVIPC y
bool 'System V IPC' CONFIG_SYSVIPC y
bool 'Use -m486 flag for 486-specific optimizations' CONFIG_M486 y
bool 'Use -m486 flag for 486-specific optimizations' CONFIG_M486 y
if [ "$CONFIG_INET" = "y" ]; then
comment 'Networking options'
comment '(it is safe to leave these untouched)'
comment 'IP (required for now) y'
bool 'Reverse ARP' CONFIG_INET_RARP y
bool 'Assume subnets are local' CONFIG_INET_SNARL y
bool 'Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF n
#bool 'Novell IPX protocol' CONFIG_IPX n
#bool 'Amateur Radio AX.25 Level 2' CONFIG_AX25 n
fi
comment 'Program binary formats'
comment 'Program binary formats'
bool 'Elf executables' CONFIG_BINFMT_ELF y
bool 'Elf executables' CONFIG_BINFMT_ELF y
...
...
drivers/net/slip.c
View file @
16119ae5
...
@@ -21,6 +21,7 @@
...
@@ -21,6 +21,7 @@
* Michael Riepe : Automatic CSLIP recognition added
* Michael Riepe : Automatic CSLIP recognition added
* Charles Hedrick : CSLIP header length problem fix.
* Charles Hedrick : CSLIP header length problem fix.
* Alan Cox : Corrected non-IP cases of the above.
* Alan Cox : Corrected non-IP cases of the above.
* Alan Cox : Now uses hardware type as per FvK.
*
*
*
*
* FIXME: This driver still makes some IP'ish assumptions. It should build cleanly KISS TNC only without
* FIXME: This driver still makes some IP'ish assumptions. It should build cleanly KISS TNC only without
...
@@ -56,6 +57,7 @@
...
@@ -56,6 +57,7 @@
#include "tcp.h"
#include "tcp.h"
#endif
#endif
#include <linux/skbuff.h>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include "sock.h"
#include "sock.h"
#include "slip.h"
#include "slip.h"
#ifdef CONFIG_INET
#ifdef CONFIG_INET
...
@@ -169,6 +171,7 @@ sl_initialize(struct slip *sl, struct device *dev)
...
@@ -169,6 +171,7 @@ sl_initialize(struct slip *sl, struct device *dev)
dev
->
rmem_start
=
(
unsigned
long
)
NULL
;
dev
->
rmem_start
=
(
unsigned
long
)
NULL
;
dev
->
mem_end
=
(
unsigned
long
)
NULL
;
dev
->
mem_end
=
(
unsigned
long
)
NULL
;
dev
->
mem_start
=
(
unsigned
long
)
NULL
;
dev
->
mem_start
=
(
unsigned
long
)
NULL
;
dev
->
type
=
ARPHRD_SLIP
+
sl
->
mode
;
}
}
...
@@ -1072,15 +1075,14 @@ slip_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
...
@@ -1072,15 +1075,14 @@ slip_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
{
{
sl
->
dev
->
addr_len
=
7
;
/* sizeof an AX.25 addr */
sl
->
dev
->
addr_len
=
7
;
/* sizeof an AX.25 addr */
sl
->
dev
->
hard_header_len
=
17
;
/* We don't do digipeaters */
sl
->
dev
->
hard_header_len
=
17
;
/* We don't do digipeaters */
sl
->
dev
->
type
=
3
;
/* AF_AX25 not an AF_INET device */
}
}
else
else
{
{
sl
->
dev
->
addr_len
=
0
;
/* No mac addr in slip mode */
sl
->
dev
->
addr_len
=
0
;
/* No mac addr in slip mode */
sl
->
dev
->
hard_header_len
=
0
;
sl
->
dev
->
hard_header_len
=
0
;
sl
->
dev
->
type
=
0
;
}
}
#endif
#endif
sl
->
dev
->
type
=
ARPHRD_SLIP
+
sl
->
mode
;
return
(
0
);
return
(
0
);
case
SIOCSIFHWADDR
:
case
SIOCSIFHWADDR
:
#ifdef CONFIG_AX25
#ifdef CONFIG_AX25
...
...
drivers/scsi/README.st
0 → 100644
View file @
16119ae5
This
file
contains
brief
information
about
the
SCSI
tape
driver
.
Last
modified:
Thu
May
5
00
:
13
:
24
1994
by
root@
kai
.
home
BASICS
The
driver
is
generic
.
The
state
of
a
drive
is
not
modified
when
the
driver
is
initalized
or
a
device
is
opened
.
The
mode
parameters
of
the
drive
can
be
modified
with
ioctls
.
The
driver
supports
fixed
and
variable
block
size
(
within
buffer
limits
).
Both
the
auto-
rewind
(
minor
equals
device
number
)
and
non-
rewind
devices
(
minor
is
128
+
device
number
)
are
implemented
.
BUFFERING
The
driver
uses
a
buffer
allocated
at
system
initialization
.
The
size
of
the
buffer
is
selectable
at
compile
and/
or
boot
time
.
The
buffer
is
used
to
store
the
data
being
transferred
to/
from
the
SCSI
adapter
.
The
following
buffering
options
are
selectable
at
compile
time
and/
or
at
run
time
(
via
ioctl
)
:
Buffering
of
data
to
be
written
across
write
calls
for
fixed
block
mode
(
define
ST_BUFFER_WRITES
).
This
should
be
disabled
if
reliable
detection
of
end
of
media
(
EOM
)
for
fixed
block
mode
is
desired
.
Asynchronous
writing
.
Writing
the
buffer
contents
to
the
tape
is
started
and
the
write
call
returns
immediately
.
The
status
is
checked
at
the
next
tape
operation
.
Should
not
used
if
reliable
EOM
detection
is
desired
.
Read
ahead
for
fixed
block
mode
(
ST_READ_AHEAD
).
Filling
the
buffer
is
attempted
even
if
the
user
does
not
want
to
get
all
of
the
data
at
this
read
command
.
Should
be
disabled
for
those
drives
that
don
't like
a filemark to truncate a read request or that don'
t
like
backspacing
.
The
buffer
size
is
defined
(
in
1024
byte
units
)
by
ST_BUFFER_BLOCKS
or
at
boot
time
.
The
maximum
number
of
buffers
allocated
is
defined
by
ST_MAX_BUFFERS
.
One
buffer
is
allocated
for
each
detected
drive
up
to
the
maximum
.
The
threshold
for
triggering
asynchronous
write
is
defined
by
ST_WRITE_THRESHOLD
.
BOOT
TIME
CONFIGURATION
The
buffer
size,
write
threshold,
and
the
maximum
number
of
allocated
buffers
are
configurable
at
boot
time
using,
e
.
g
.
,
the
LILO
command
line
.
The
option
syntax
is
the
following:
st
=
aa
[
,
bb
[
,
cc
]]
where
aa
is
the
buffer
size
in
1024
byte
units
bb
is
the
write
threshold
in
1024
byte
units
cc
is
the
maximum
number
of
tape
buffers
to
allocate
(
the
number
of
buffers
is
bounded
also
by
the
number
of
drives
detected
)
IOCTLS
The
tape
is
positioned
and
the
drive
parameters
are
set
with
ioctls
defined
in
mtio
.
h
The
tape
control
program
'mt'
uses
these
ioctls
.
Try
to
find
an
mt
that
supports
all
of
the
Linux
SCSI
tape
ioctls
and
opens
the
device
for
writing
if
the
tape
contents
will
be
modified
(
look
for
a
package
mt-
st
*
from
the
Linux
ftp
sites
;
the
GNU
mt
does
not
open
for
writing
for,
e
.
g
.
,
erase
).
The
supported
ioctls
are:
The
following
use
the
structure
mtop:
MTFSF
Space
forward
over
count
filemarks
.
Tape
positioned
after
filemark
.
MTFSFM
As
above
but
tape
positioned
before
filemark
.
MTBSF
Space
backward
over
count
filemarks
.
Tape
positioned
before
filemark
.
MTBSFM
As
above
but
ape
positioned
after
filemark
.
MTFSR
Space
forward
over
count
records
.
MTBSR
Space
backward
over
count
records
.
MTWEOF
Write
count
filemarks
.
MTREW
Rewind
tape
.
MTOFFL
Set
device
off
line
(
often
rewind
plus
eject
).
MTNOP
Do
nothing
.
MTRETEN
Retension
tape
.
MTEOM
Space
to
end
of
recorded
data
.
MTERASE
Erase
tape
.
MTSEEK
Seek
to
tape
block
count
.
Uses
Tandberg-
compatible
seek
(
QFA
)
for
SCSI-
1
drives
and
SCSI-
2
seek
for
SCSI-
2
drives
.
MTSETBLK
Set
the
drive
block
size
.
Setting
to
zero
sets
the
drive
into
variable
block
mode
(
if
applicable
).
MTSETDENSITY
Sets
the
drive
density
code
to
arg
.
See
drive
documentation
for
available
codes
.
MTSETDRVBUFFER
Is
used
for
several
things
.
The
command
is
obtained
from
count
with
mask
MT_SET_OPTIONS,
the
low
order
bits
are
used
as
argument
.
The
subcommands
are:
0
The
drive
buffer
option
is
set
to
the
argument
.
Zero
means
no
buffering
.
MT_ST_BOOLEANS
Sets
the
buffering
options
.
The
bits
are
the
new
states
(
enabled
/
disabled
)
of
the
write
buffering
(
MT_ST_BUFFER_WRITES
)
,
asynchronous
writes
(
MT_ST_ASYNC_WRITES
)
,
read
ahead
(
MT_ST_READ_AHEAD
)
and
debugging
(
MT_ST_DEBUGGING
;
(
debugging
must
be
compiled
into
the
driver
).
MT_ST_WRITE_THRESHOLD
Sets
the
write
threshold
for
this
device
to
kilobytes
specified
by
the
lowest
bits
.
The
following
ioctl
uses
the
structure
mtpos:
MTIOCPOS
Reads
the
current
position
from
the
drive
.
Uses
Tandberg-
compatible
QFA
for
SCSI-
1
drives
and
the
SCSI-
2
command
for
the
SCSI-
2
drives
.
The
following
ioctl
uses
the
structure
mtget
to
return
the
status:
MTIOCGET
Returns
some
status
information
.
The
file
number
and
block
number
within
file
are
returned
.
The
block
is
-
1
when
it
can
'
t
be
determined
(
e
.
g
.
,
after
MTBSF
).
The
drive
type
is
either
MTISSCSI1
or
MTISSCSI2
.
The
number
of
recovered
errors
since
the
previous
status
call
is
stored
in
the
lower
word
of
the
field
mt_erreg
.
The
current
block
size
and
the
density
code
are
stored
in
the
field
mt_dsreg
(
shifts
for
the
subfields
are
MT_ST_BLKSIZE_SHIFT
and
MT_ST_DENSITY_SHIFT
).
The
other
fields
are
empty
.
MISCELLANEOUS
COMPILE
OPTIONS
The
recovered
write
errors
are
considered
fatal
if
ST_RECOVERED_WRITE_FATAL
is
defined
.
Immediate
return
from
tape
positioning
SCSI
commands
can
be
enabled
by
defining
ST_NOWAIT
.
When
using
read
ahead
or
buffered
writes
the
position
within
the
file
may
not
be
correct
after
the
file
is
closed
(
correct
position
may
require
backspacing
over
more
than
one
record
).
The
correct
position
within
file
can
be
obtained
if
ST_IN_FILE_POS
is
defined
.
(
The
driver
always
backs
over
a
filemark
crossed
by
read
ahead
if
the
user
does
not
request
data
that
far
.)
Kai
M
{
kisara
drivers/scsi/st.c
View file @
16119ae5
/*
/*
SCSI Tape Driver for Linux
SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying
file README.st for more information.
Version 0.02 for Linux 0.98.4 and Eric Youngdale's new scsi driver
History:
History:
Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.
Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.
Contribution and ideas from several people including Eric Youngdale and
Contribution and ideas from several people including (in alphabetical
Wolfgang Denk.
order) Klaus Ehrenfried, Wolfgang Denk, J"org Weule, and
Eric Youngdale.
Features:
- support for different block sizes and internal buffering
Copyright 1992, 1993, 1994 Kai Makisara
- support for fixed and variable block size (within buffer limit;
blocksize set to zero)
- *nix-style ioctl with codes from mtio.h from the QIC-02 driver by
Hennus Bergman (command MTSETBLK added)
- character device
- rewind and non-rewind devices
- capability to handle several tape drives simultaneously
- one buffer if one drive, two buffers if more than one drive (limits the
number of simultaneously open drives to two)
- write behind
- seek and tell (Tandberg compatible and SCSI-2)
Devices:
Autorewind devices have minor numbers equal to the tape numbers (0 > ).
Nonrewind device has the minor number equal to tape number + 128.
Problems:
The end of media detection works correctly in writing only if the drive
writes the buffer contents after the early-warning mark. If you want to
be sure that EOM is reported correctly, you should uncomment the line
defining ST_NO_DELAYED_WRITES. Note that when delayed writes are disabled
each write byte count must be an integral number of blocks.
Copyright 1992, 1993 Kai Makisara
email makisara@vtinsx.ins.vtt.fi or Kai.Makisara@vtt.fi
email makisara@vtinsx.ins.vtt.fi or Kai.Makisara@vtt.fi
Last modified:
Thu Nov 25 21:49:02 1993
by root@kai.home
Last modified:
Wed May 4 20:29:42 1994
by root@kai.home
*/
*/
#include <linux/fs.h>
#include <linux/fs.h>
...
@@ -57,44 +32,40 @@
...
@@ -57,44 +32,40 @@
#include "st.h"
#include "st.h"
#include "constants.h"
#include "constants.h"
/*
Uncomment the following if you want the rewind, etc. commands return
/*
#define DEBUG */
before command completion. */
/* #define ST_NOWAIT */
/* #define ST_NOWAIT */
/* Uncomment the following if you want the tape to be positioned correctly
within file after close (the tape is positioned correctly with respect
to the filemarks even wihout ST_IN_FILE_POS defined */
/* #define ST_IN_FILE_POS */
/* #define ST_IN_FILE_POS */
/* Uncomment the following if you want recovered write errors to be
fatal. */
/* #define ST_RECOVERED_WRITE_FATAL */
/* #define ST_RECOVERED_WRITE_FATAL */
/* Uncomment the following if you want all data from a write command to
#define ST_BUFFER_WRITES 1
be written to tape before the command returns. Disables write-behind. */
/* #define ST_NO_DELAYED_WRITES */
#define ST_ASYNC_WRITES 1
#define ST_READ_AHEAD 1
#define ST_BLOCK_SIZE 1024
#define ST_MAX_BUFFERS 2
#define ST_BUFFER_BLOCKS 32
#define ST_WRITE_THRESHOLD_BLOCKS 30
/* Number of ST_BLOCK_SIZE blocks in the buffers */
#define ST_BUFFER_BLOCKS 64
/* Write-behind can be disabled by setting ST_WRITE_THRESHOLD_BLOCKS equal
to or larger than ST_BUFFER_BLOCKS */
#define ST_WRITE_THRESHOLD_BLOCKS 60
#define ST_BLOCK_SIZE 512
#define ST_BUFFER_SIZE (ST_BUFFER_BLOCKS * ST_BLOCK_SIZE)
#define ST_BUFFER_SIZE (ST_BUFFER_BLOCKS * ST_BLOCK_SIZE)
#define ST_WRITE_THRESHOLD (ST_WRITE_THRESHOLD_BLOCKS * ST_BLOCK_SIZE)
#define ST_WRITE_THRESHOLD (ST_WRITE_THRESHOLD_BLOCKS * ST_BLOCK_SIZE)
#ifdef ST_NO_DELAYED_WRITES
/* The buffer size should fit into the 24 bits for length in the
#undef ST_WRITE_THRESHOLD_BLOCKS
#define ST_WRITE_THRESHOLD_BLOCKS ST_BUFFER_BLOCKS
#endif
/* The buffer size should fit into the 24 bits reserved for length in the
6-byte SCSI read and write commands. */
6-byte SCSI read and write commands. */
#if ST_BUFFER_SIZE >= (2 << 24 - 1)
#if ST_BUFFER_SIZE >= (2 << 24 - 1)
#error "Buffer size should not exceed (2 << 24 - 1) bytes!"
#error "Buffer size should not exceed (2 << 24 - 1) bytes!"
#endif
#endif
/* #define DEBUG */
#ifdef DEBUG
static
int
debugging
=
1
;
#endif
#define MAX_RETRIES 0
#define MAX_RETRIES 0
#define MAX_READY_RETRIES 5
#define MAX_READY_RETRIES 5
...
@@ -104,7 +75,10 @@
...
@@ -104,7 +75,10 @@
#define ST_LONG_TIMEOUT 200000
#define ST_LONG_TIMEOUT 200000
static
int
st_nbr_buffers
;
static
int
st_nbr_buffers
;
static
ST_buffer
*
st_buffers
[
2
];
static
ST_buffer
**
st_buffers
;
static
int
st_buffer_size
=
ST_BUFFER_SIZE
;
static
int
st_write_threshold
=
ST_WRITE_THRESHOLD
;
static
int
st_max_buffers
=
ST_MAX_BUFFERS
;
static
Scsi_Tape
*
scsi_tapes
;
static
Scsi_Tape
*
scsi_tapes
;
int
NR_ST
=
0
;
int
NR_ST
=
0
;
...
@@ -128,8 +102,14 @@ st_chk_result(Scsi_Cmnd * SCpnt)
...
@@ -128,8 +102,14 @@ st_chk_result(Scsi_Cmnd * SCpnt)
if
(
!
result
&&
SCpnt
->
sense_buffer
[
0
]
==
0
)
if
(
!
result
&&
SCpnt
->
sense_buffer
[
0
]
==
0
)
return
0
;
return
0
;
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: Error: %x
\n
"
,
dev
,
result
);
if
(
debugging
)
{
print_sense
(
"st"
,
SCpnt
);
printk
(
"st%d: Error: %x, cmd: %x %x %x %x %x %x Len: %d
\n
"
,
dev
,
result
,
SCpnt
->
cmnd
[
0
],
SCpnt
->
cmnd
[
1
],
SCpnt
->
cmnd
[
2
],
SCpnt
->
cmnd
[
3
],
SCpnt
->
cmnd
[
4
],
SCpnt
->
cmnd
[
5
],
SCpnt
->
request_bufflen
);
if
(
driver_byte
(
result
)
&
DRIVER_SENSE
)
print_sense
(
"st"
,
SCpnt
);
}
#endif
#endif
/* if ((sense[0] & 0x70) == 0x70 &&
/* if ((sense[0] & 0x70) == 0x70 &&
((sense[2] & 0x80) ))
((sense[2] & 0x80) ))
...
@@ -142,6 +122,7 @@ st_chk_result(Scsi_Cmnd * SCpnt)
...
@@ -142,6 +122,7 @@ st_chk_result(Scsi_Cmnd * SCpnt)
#endif
#endif
)
{
)
{
scsi_tapes
[
dev
].
recover_count
++
;
scsi_tapes
[
dev
].
recover_count
++
;
scsi_tapes
[
dev
].
mt_status
->
mt_erreg
+=
(
1
<<
MT_ST_SOFTERR_SHIFT
);
if
(
SCpnt
->
cmnd
[
0
]
==
READ_6
)
if
(
SCpnt
->
cmnd
[
0
]
==
READ_6
)
stp
=
"read"
;
stp
=
"read"
;
else
if
(
SCpnt
->
cmnd
[
0
]
==
WRITE_6
)
else
if
(
SCpnt
->
cmnd
[
0
]
==
WRITE_6
)
...
@@ -192,13 +173,12 @@ st_sleep_done (Scsi_Cmnd * SCpnt)
...
@@ -192,13 +173,12 @@ st_sleep_done (Scsi_Cmnd * SCpnt)
wake_up
(
&
(
STp
->
waiting
)
);
wake_up
(
&
(
STp
->
waiting
)
);
}
}
#ifdef DEBUG
#ifdef DEBUG
else
else
if
(
debugging
)
printk
(
"st?: Illegal interrupt device %x
\n
"
,
st_nbr
);
printk
(
"st?: Illegal interrupt device %x
\n
"
,
st_nbr
);
#endif
#endif
}
}
#if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS
/* Handle the write-behind checking */
/* Handle the write-behind checking */
static
void
static
void
write_behind_check
(
int
dev
)
write_behind_check
(
int
dev
)
...
@@ -222,11 +202,44 @@ write_behind_check(int dev)
...
@@ -222,11 +202,44 @@ write_behind_check(int dev)
STbuffer
->
b_data
+
STbuffer
->
writing
,
STbuffer
->
b_data
+
STbuffer
->
writing
,
STbuffer
->
buffer_bytes
-
STbuffer
->
writing
);
STbuffer
->
buffer_bytes
-
STbuffer
->
writing
);
STbuffer
->
buffer_bytes
-=
STbuffer
->
writing
;
STbuffer
->
buffer_bytes
-=
STbuffer
->
writing
;
if
(
STp
->
drv_block
>=
0
)
{
if
(
STp
->
block_size
==
0
)
STp
->
drv_block
++
;
else
STp
->
drv_block
+=
STbuffer
->
writing
/
STp
->
block_size
;
}
STbuffer
->
writing
=
0
;
STbuffer
->
writing
=
0
;
return
;
return
;
}
}
#endif
/* Back over EOF if it has been inadvertently crossed (ioctl not used because
it messes up the block number). */
static
int
back_over_eof
(
int
dev
)
{
Scsi_Cmnd
*
SCpnt
;
Scsi_Tape
*
STp
=
&
(
scsi_tapes
[
dev
]);
unsigned
char
cmd
[
10
];
cmd
[
0
]
=
SPACE
;
cmd
[
1
]
=
0x01
;
/* Space FileMarks */
cmd
[
2
]
=
cmd
[
3
]
=
cmd
[
4
]
=
0xff
;
/* -1 filemarks */
cmd
[
5
]
=
0
;
SCpnt
=
allocate_device
(
NULL
,
(
STp
->
device
)
->
index
,
1
);
SCpnt
->
sense_buffer
[
0
]
=
0
;
SCpnt
->
request
.
dev
=
dev
;
scsi_do_cmd
(
SCpnt
,
(
void
*
)
cmd
,
(
void
*
)
(
STp
->
buffer
)
->
b_data
,
0
,
st_sleep_done
,
ST_TIMEOUT
,
MAX_RETRIES
);
if
(
SCpnt
->
request
.
dev
==
dev
)
sleep_on
(
&
(
STp
->
waiting
)
);
SCpnt
->
request
.
dev
=
-
1
;
return
(
STp
->
buffer
)
->
last_result_fatal
;
}
/* Flush the write buffer (never need to write if variable blocksize). */
/* Flush the write buffer (never need to write if variable blocksize). */
...
@@ -239,20 +252,19 @@ flush_write_buffer(int dev)
...
@@ -239,20 +252,19 @@ flush_write_buffer(int dev)
Scsi_Cmnd
*
SCpnt
;
Scsi_Cmnd
*
SCpnt
;
Scsi_Tape
*
STp
=
&
(
scsi_tapes
[
dev
]);
Scsi_Tape
*
STp
=
&
(
scsi_tapes
[
dev
]);
#if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS
if
((
STp
->
buffer
)
->
writing
)
{
if
((
STp
->
buffer
)
->
writing
)
{
write_behind_check
(
dev
);
write_behind_check
(
dev
);
if
((
STp
->
buffer
)
->
last_result_fatal
)
{
if
((
STp
->
buffer
)
->
last_result_fatal
)
{
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: Async write error %x.
\n
"
,
dev
,
if
(
debugging
)
(
STp
->
buffer
)
->
last_result
);
printk
(
"st%d: Async write error (flush) %x.
\n
"
,
dev
,
(
STp
->
buffer
)
->
last_result
);
#endif
#endif
if
((
STp
->
buffer
)
->
last_result
==
INT_MAX
)
if
((
STp
->
buffer
)
->
last_result
==
INT_MAX
)
return
(
-
ENOSPC
);
return
(
-
ENOSPC
);
return
(
-
EIO
);
return
(
-
EIO
);
}
}
}
}
#endif
result
=
0
;
result
=
0
;
if
(
STp
->
dirty
==
1
)
{
if
(
STp
->
dirty
==
1
)
{
...
@@ -262,7 +274,8 @@ flush_write_buffer(int dev)
...
@@ -262,7 +274,8 @@ flush_write_buffer(int dev)
transfer
=
((
offset
+
STp
->
block_size
-
1
)
/
transfer
=
((
offset
+
STp
->
block_size
-
1
)
/
STp
->
block_size
)
*
STp
->
block_size
;
STp
->
block_size
)
*
STp
->
block_size
;
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: Flushing %d bytes.
\n
"
,
dev
,
transfer
);
if
(
debugging
)
printk
(
"st%d: Flushing %d bytes.
\n
"
,
dev
,
transfer
);
#endif
#endif
memset
((
STp
->
buffer
)
->
b_data
+
offset
,
0
,
transfer
-
offset
);
memset
((
STp
->
buffer
)
->
b_data
+
offset
,
0
,
transfer
-
offset
);
...
@@ -292,8 +305,11 @@ flush_write_buffer(int dev)
...
@@ -292,8 +305,11 @@ flush_write_buffer(int dev)
}
}
else
else
result
=
(
-
EIO
);
result
=
(
-
EIO
);
STp
->
drv_block
=
(
-
1
);
}
}
else
{
else
{
if
(
STp
->
drv_block
>=
0
)
STp
->
drv_block
+=
blks
;
STp
->
dirty
=
0
;
STp
->
dirty
=
0
;
(
STp
->
buffer
)
->
buffer_bytes
=
0
;
(
STp
->
buffer
)
->
buffer_bytes
=
0
;
}
}
...
@@ -332,7 +348,7 @@ flush_buffer(struct inode * inode, struct file * filp, int seek_next)
...
@@ -332,7 +348,7 @@ flush_buffer(struct inode * inode, struct file * filp, int seek_next)
result
=
0
;
result
=
0
;
if
(
!
seek_next
)
{
if
(
!
seek_next
)
{
if
((
STp
->
eof
==
ST_FM
)
&&
!
STp
->
eof_hit
)
{
if
((
STp
->
eof
==
ST_FM
)
&&
!
STp
->
eof_hit
)
{
result
=
st_int_ioctl
(
inode
,
filp
,
MTBSF
,
1
);
/* Back over the EOF hit */
result
=
back_over_eof
(
dev
);
/* Back over the EOF hit */
if
(
!
result
)
{
if
(
!
result
)
{
STp
->
eof
=
ST_NOEOF
;
STp
->
eof
=
ST_NOEOF
;
STp
->
eof_hit
=
0
;
STp
->
eof_hit
=
0
;
...
@@ -400,31 +416,36 @@ scsi_tape_open(struct inode * inode, struct file * filp)
...
@@ -400,31 +416,36 @@ scsi_tape_open(struct inode * inode, struct file * filp)
SCpnt
->
request
.
dev
=
dev
;
SCpnt
->
request
.
dev
=
dev
;
scsi_do_cmd
(
SCpnt
,
scsi_do_cmd
(
SCpnt
,
(
void
*
)
cmd
,
(
void
*
)
(
STp
->
buffer
)
->
b_data
,
(
void
*
)
cmd
,
(
void
*
)
(
STp
->
buffer
)
->
b_data
,
ST_BLOCK_SIZE
,
st_sleep_done
,
ST_LONG_TIMEOUT
,
0
,
st_sleep_done
,
ST_LONG_TIMEOUT
,
MAX_READY_RETRIES
);
MAX_READY_RETRIES
);
if
(
SCpnt
->
request
.
dev
==
dev
)
sleep_on
(
&
(
STp
->
waiting
)
);
if
(
SCpnt
->
request
.
dev
==
dev
)
sleep_on
(
&
(
STp
->
waiting
)
);
if
((
SCpnt
->
sense_buffer
[
0
]
&
0x70
)
==
0x70
&&
if
((
SCpnt
->
sense_buffer
[
0
]
&
0x70
)
==
0x70
&&
(
SCpnt
->
sense_buffer
[
2
]
&
0x0f
)
==
UNIT_ATTENTION
)
{
/* New media? */
(
SCpnt
->
sense_buffer
[
2
]
&
0x0f
)
==
UNIT_ATTENTION
)
{
/* New media? */
(
STp
->
mt_status
)
->
mt_fileno
=
0
;
SCpnt
->
sense_buffer
[
0
]
=
0
;
SCpnt
->
sense_buffer
[
0
]
=
0
;
memset
((
void
*
)
&
cmd
[
0
],
0
,
10
);
memset
((
void
*
)
&
cmd
[
0
],
0
,
10
);
cmd
[
0
]
=
TEST_UNIT_READY
;
cmd
[
0
]
=
TEST_UNIT_READY
;
SCpnt
->
request
.
dev
=
dev
;
SCpnt
->
request
.
dev
=
dev
;
scsi_do_cmd
(
SCpnt
,
scsi_do_cmd
(
SCpnt
,
(
void
*
)
cmd
,
(
void
*
)
(
STp
->
buffer
)
->
b_data
,
(
void
*
)
cmd
,
(
void
*
)
(
STp
->
buffer
)
->
b_data
,
ST_BLOCK_SIZE
,
st_sleep_done
,
ST_LONG_TIMEOUT
,
0
,
st_sleep_done
,
ST_LONG_TIMEOUT
,
MAX_READY_RETRIES
);
MAX_READY_RETRIES
);
if
(
SCpnt
->
request
.
dev
==
dev
)
sleep_on
(
&
(
STp
->
waiting
)
);
if
(
SCpnt
->
request
.
dev
==
dev
)
sleep_on
(
&
(
STp
->
waiting
)
);
(
STp
->
mt_status
)
->
mt_fileno
=
STp
->
drv_block
=
0
;
}
}
if
((
STp
->
buffer
)
->
last_result_fatal
!=
0
)
{
if
((
STp
->
buffer
)
->
last_result_fatal
!=
0
)
{
if
((
SCpnt
->
sense_buffer
[
0
]
&
0x70
)
==
0x70
&&
if
((
SCpnt
->
sense_buffer
[
0
]
&
0x70
)
==
0x70
&&
(
SCpnt
->
sense_buffer
[
2
]
&
0x0f
)
==
NO_TAPE
)
(
SCpnt
->
sense_buffer
[
2
]
&
0x0f
)
==
NO_TAPE
)
{
(
STp
->
mt_status
)
->
mt_fileno
=
STp
->
drv_block
=
0
;
printk
(
"st%d: No tape.
\n
"
,
dev
);
printk
(
"st%d: No tape.
\n
"
,
dev
);
else
}
else
{
printk
(
"st%d: Error %x.
\n
"
,
dev
,
SCpnt
->
result
);
printk
(
"st%d: Error %x.
\n
"
,
dev
,
SCpnt
->
result
);
(
STp
->
mt_status
)
->
mt_fileno
=
STp
->
drv_block
=
(
-
1
);
}
(
STp
->
buffer
)
->
in_use
=
0
;
(
STp
->
buffer
)
->
in_use
=
0
;
STp
->
in_use
=
0
;
STp
->
in_use
=
0
;
SCpnt
->
request
.
dev
=
-
1
;
/* Mark as not busy */
SCpnt
->
request
.
dev
=
-
1
;
/* Mark as not busy */
...
@@ -437,7 +458,7 @@ scsi_tape_open(struct inode * inode, struct file * filp)
...
@@ -437,7 +458,7 @@ scsi_tape_open(struct inode * inode, struct file * filp)
SCpnt
->
request
.
dev
=
dev
;
SCpnt
->
request
.
dev
=
dev
;
scsi_do_cmd
(
SCpnt
,
scsi_do_cmd
(
SCpnt
,
(
void
*
)
cmd
,
(
void
*
)
(
STp
->
buffer
)
->
b_data
,
(
void
*
)
cmd
,
(
void
*
)
(
STp
->
buffer
)
->
b_data
,
ST_BLOCK_SIZE
,
st_sleep_done
,
ST_TIMEOUT
,
MAX_READY_RETRIES
);
6
,
st_sleep_done
,
ST_TIMEOUT
,
MAX_READY_RETRIES
);
if
(
SCpnt
->
request
.
dev
==
dev
)
sleep_on
(
&
(
STp
->
waiting
)
);
if
(
SCpnt
->
request
.
dev
==
dev
)
sleep_on
(
&
(
STp
->
waiting
)
);
...
@@ -447,14 +468,16 @@ scsi_tape_open(struct inode * inode, struct file * filp)
...
@@ -447,14 +468,16 @@ scsi_tape_open(struct inode * inode, struct file * filp)
STp
->
min_block
=
((
STp
->
buffer
)
->
b_data
[
4
]
<<
8
)
|
STp
->
min_block
=
((
STp
->
buffer
)
->
b_data
[
4
]
<<
8
)
|
(
STp
->
buffer
)
->
b_data
[
5
];
(
STp
->
buffer
)
->
b_data
[
5
];
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: Block limits %d - %d bytes.
\n
"
,
dev
,
STp
->
min_block
,
if
(
debugging
)
STp
->
max_block
);
printk
(
"st%d: Block limits %d - %d bytes.
\n
"
,
dev
,
STp
->
min_block
,
STp
->
max_block
);
#endif
#endif
}
}
else
{
else
{
STp
->
min_block
=
STp
->
max_block
=
(
-
1
);
STp
->
min_block
=
STp
->
max_block
=
(
-
1
);
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: Can't read block limits.
\n
"
,
dev
);
if
(
debugging
)
printk
(
"st%d: Can't read block limits.
\n
"
,
dev
);
#endif
#endif
}
}
...
@@ -465,13 +488,14 @@ scsi_tape_open(struct inode * inode, struct file * filp)
...
@@ -465,13 +488,14 @@ scsi_tape_open(struct inode * inode, struct file * filp)
SCpnt
->
request
.
dev
=
dev
;
SCpnt
->
request
.
dev
=
dev
;
scsi_do_cmd
(
SCpnt
,
scsi_do_cmd
(
SCpnt
,
(
void
*
)
cmd
,
(
void
*
)
(
STp
->
buffer
)
->
b_data
,
(
void
*
)
cmd
,
(
void
*
)
(
STp
->
buffer
)
->
b_data
,
ST_BLOCK_SIZE
,
st_sleep_done
,
ST_TIMEOUT
,
MAX_READY_RETRIES
);
12
,
st_sleep_done
,
ST_TIMEOUT
,
MAX_READY_RETRIES
);
if
(
SCpnt
->
request
.
dev
==
dev
)
sleep_on
(
&
(
STp
->
waiting
)
);
if
(
SCpnt
->
request
.
dev
==
dev
)
sleep_on
(
&
(
STp
->
waiting
)
);
if
((
STp
->
buffer
)
->
last_result_fatal
!=
0
)
{
if
((
STp
->
buffer
)
->
last_result_fatal
!=
0
)
{
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: No Mode Sense.
\n
"
,
dev
);
if
(
debugging
)
printk
(
"st%d: No Mode Sense.
\n
"
,
dev
);
#endif
#endif
(
STp
->
buffer
)
->
b_data
[
2
]
=
(
STp
->
buffer
)
->
b_data
[
2
]
=
(
STp
->
buffer
)
->
b_data
[
3
]
=
0
;
(
STp
->
buffer
)
->
b_data
[
3
]
=
0
;
...
@@ -479,9 +503,10 @@ scsi_tape_open(struct inode * inode, struct file * filp)
...
@@ -479,9 +503,10 @@ scsi_tape_open(struct inode * inode, struct file * filp)
SCpnt
->
request
.
dev
=
-
1
;
/* Mark as not busy */
SCpnt
->
request
.
dev
=
-
1
;
/* Mark as not busy */
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: Mode sense. Length %d, medium %x, WBS %x, BLL %d
\n
"
,
dev
,
if
(
debugging
)
(
STp
->
buffer
)
->
b_data
[
0
],
(
STp
->
buffer
)
->
b_data
[
1
],
printk
(
"st%d: Mode sense. Length %d, medium %x, WBS %x, BLL %d
\n
"
,
dev
,
(
STp
->
buffer
)
->
b_data
[
2
],
(
STp
->
buffer
)
->
b_data
[
3
]);
(
STp
->
buffer
)
->
b_data
[
0
],
(
STp
->
buffer
)
->
b_data
[
1
],
(
STp
->
buffer
)
->
b_data
[
2
],
(
STp
->
buffer
)
->
b_data
[
3
]);
#endif
#endif
if
((
STp
->
buffer
)
->
b_data
[
3
]
>=
8
)
{
if
((
STp
->
buffer
)
->
b_data
[
3
]
>=
8
)
{
...
@@ -490,13 +515,13 @@ scsi_tape_open(struct inode * inode, struct file * filp)
...
@@ -490,13 +515,13 @@ scsi_tape_open(struct inode * inode, struct file * filp)
STp
->
block_size
=
(
STp
->
buffer
)
->
b_data
[
9
]
*
65536
+
STp
->
block_size
=
(
STp
->
buffer
)
->
b_data
[
9
]
*
65536
+
(
STp
->
buffer
)
->
b_data
[
10
]
*
256
+
(
STp
->
buffer
)
->
b_data
[
11
];
(
STp
->
buffer
)
->
b_data
[
10
]
*
256
+
(
STp
->
buffer
)
->
b_data
[
11
];
#ifdef DEBUG
#ifdef DEBUG
printk
(
if
(
debugging
)
"st%d: Density %x, tape length: %x, blocksize: %d, drv buffer: %d
\n
"
,
printk
(
"st%d: Density %x, tape length: %x, blocksize: %d, drv buffer: %d
\n
"
,
dev
,
STp
->
density
,
(
STp
->
buffer
)
->
b_data
[
5
]
*
65536
+
dev
,
STp
->
density
,
(
STp
->
buffer
)
->
b_data
[
5
]
*
65536
+
(
STp
->
buffer
)
->
b_data
[
6
]
*
256
+
(
STp
->
buffer
)
->
b_data
[
7
],
(
STp
->
buffer
)
->
b_data
[
6
]
*
256
+
(
STp
->
buffer
)
->
b_data
[
7
],
STp
->
block_size
,
STp
->
drv_buffer
);
STp
->
block_size
,
STp
->
drv_buffer
);
#endif
#endif
if
(
STp
->
block_size
>
ST_BUFFER_SIZE
)
{
if
(
STp
->
block_size
>
st_buffer_size
)
{
printk
(
"st%d: Blocksize %d too large for buffer.
\n
"
,
dev
,
printk
(
"st%d: Blocksize %d too large for buffer.
\n
"
,
dev
,
STp
->
block_size
);
STp
->
block_size
);
(
STp
->
buffer
)
->
in_use
=
0
;
(
STp
->
buffer
)
->
in_use
=
0
;
...
@@ -506,29 +531,31 @@ scsi_tape_open(struct inode * inode, struct file * filp)
...
@@ -506,29 +531,31 @@ scsi_tape_open(struct inode * inode, struct file * filp)
}
}
else
else
STp
->
block_size
=
ST_BLOCK_SIZE
;
STp
->
block_size
=
512
;
/* "Educated Guess" (?) */
if
(
STp
->
block_size
>
0
)
{
if
(
STp
->
block_size
>
0
)
{
(
STp
->
buffer
)
->
buffer_blocks
=
ST_BUFFER_SIZE
/
STp
->
block_size
;
(
STp
->
buffer
)
->
buffer_blocks
=
st_buffer_size
/
STp
->
block_size
;
(
STp
->
buffer
)
->
buffer_size
=
(
STp
->
buffer
)
->
buffer_size
=
(
STp
->
buffer
)
->
buffer_blocks
*
STp
->
block_size
;
(
STp
->
buffer
)
->
buffer_blocks
*
STp
->
block_size
;
}
}
else
{
else
{
(
STp
->
buffer
)
->
buffer_blocks
=
1
;
(
STp
->
buffer
)
->
buffer_blocks
=
1
;
(
STp
->
buffer
)
->
buffer_size
=
ST_BUFFER_SIZE
;
(
STp
->
buffer
)
->
buffer_size
=
st_buffer_size
;
}
}
(
STp
->
buffer
)
->
buffer_bytes
=
(
STp
->
buffer
)
->
read_pointer
=
0
;
(
STp
->
buffer
)
->
buffer_bytes
=
(
STp
->
buffer
)
->
read_pointer
=
0
;
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: Block size: %d, buffer size: %d (%d blocks).
\n
"
,
dev
,
if
(
debugging
)
STp
->
block_size
,
(
STp
->
buffer
)
->
buffer_size
,
printk
(
"st%d: Block size: %d, buffer size: %d (%d blocks).
\n
"
,
dev
,
(
STp
->
buffer
)
->
buffer_blocks
);
STp
->
block_size
,
(
STp
->
buffer
)
->
buffer_size
,
(
STp
->
buffer
)
->
buffer_blocks
);
#endif
#endif
if
((
STp
->
buffer
)
->
b_data
[
2
]
&
0x80
)
{
if
((
STp
->
buffer
)
->
b_data
[
2
]
&
0x80
)
{
STp
->
write_prot
=
1
;
STp
->
write_prot
=
1
;
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: Write protected
\n
"
,
dev
);
if
(
debugging
)
printk
(
"st%d: Write protected
\n
"
,
dev
);
#endif
#endif
}
}
...
@@ -557,7 +584,8 @@ scsi_tape_close(struct inode * inode, struct file * filp)
...
@@ -557,7 +584,8 @@ scsi_tape_close(struct inode * inode, struct file * filp)
result
=
flush_write_buffer
(
dev
);
result
=
flush_write_buffer
(
dev
);
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: File length %d bytes.
\n
"
,
dev
,
filp
->
f_pos
);
if
(
debugging
)
printk
(
"st%d: File length %ld bytes.
\n
"
,
dev
,
filp
->
f_pos
);
#endif
#endif
if
(
result
==
0
||
result
==
(
-
ENOSPC
))
{
if
(
result
==
0
||
result
==
(
-
ENOSPC
))
{
...
@@ -570,24 +598,29 @@ scsi_tape_close(struct inode * inode, struct file * filp)
...
@@ -570,24 +598,29 @@ scsi_tape_close(struct inode * inode, struct file * filp)
SCpnt
->
request
.
dev
=
dev
;
SCpnt
->
request
.
dev
=
dev
;
scsi_do_cmd
(
SCpnt
,
scsi_do_cmd
(
SCpnt
,
(
void
*
)
cmd
,
(
void
*
)
(
STp
->
buffer
)
->
b_data
,
(
void
*
)
cmd
,
(
void
*
)
(
STp
->
buffer
)
->
b_data
,
ST_BLOCK_SIZE
,
st_sleep_done
,
ST_TIMEOUT
,
MAX_RETRIES
);
0
,
st_sleep_done
,
ST_TIMEOUT
,
MAX_RETRIES
);
if
(
SCpnt
->
request
.
dev
==
dev
)
sleep_on
(
&
(
STp
->
waiting
)
);
if
(
SCpnt
->
request
.
dev
==
dev
)
sleep_on
(
&
(
STp
->
waiting
)
);
if
((
STp
->
buffer
)
->
last_result_fatal
!=
0
)
if
((
STp
->
buffer
)
->
last_result_fatal
!=
0
)
printk
(
"st%d: Error on write filemark.
\n
"
,
dev
);
printk
(
"st%d: Error on write filemark.
\n
"
,
dev
);
else
{
(
STp
->
mt_status
)
->
mt_fileno
++
;
STp
->
drv_block
=
0
;
}
SCpnt
->
request
.
dev
=
-
1
;
/* Mark as not busy */
SCpnt
->
request
.
dev
=
-
1
;
/* Mark as not busy */
}
}
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: Buffer flushed, EOF written
\n
"
,
dev
);
if
(
debugging
)
printk
(
"st%d: Buffer flushed, EOF written
\n
"
,
dev
);
#endif
#endif
}
}
else
if
(
!
rewind
)
{
else
if
(
!
rewind
)
{
#ifndef ST_IN_FILE_POS
#ifndef ST_IN_FILE_POS
if
((
STp
->
eof
==
ST_FM
)
&&
!
STp
->
eof_hit
)
if
((
STp
->
eof
==
ST_FM
)
&&
!
STp
->
eof_hit
)
st_int_ioctl
(
inode
,
filp
,
MTBSF
,
1
);
/* Back over the EOF hit */
back_over_eof
(
dev
);
#else
#else
flush_buffer
(
inode
,
filp
,
0
);
flush_buffer
(
inode
,
filp
,
0
);
#endif
#endif
...
@@ -627,7 +660,7 @@ st_write(struct inode * inode, struct file * filp, char * buf, int count)
...
@@ -627,7 +660,7 @@ st_write(struct inode * inode, struct file * filp, char * buf, int count)
if
(
STp
->
write_prot
)
if
(
STp
->
write_prot
)
return
(
-
EACCES
);
return
(
-
EACCES
);
if
(
STp
->
block_size
==
0
&&
count
>
ST_BUFFER_SIZE
)
if
(
STp
->
block_size
==
0
&&
count
>
st_buffer_size
)
return
(
-
EOVERFLOW
);
return
(
-
EOVERFLOW
);
if
(
STp
->
rw
==
ST_READING
)
{
if
(
STp
->
rw
==
ST_READING
)
{
...
@@ -637,13 +670,13 @@ st_write(struct inode * inode, struct file * filp, char * buf, int count)
...
@@ -637,13 +670,13 @@ st_write(struct inode * inode, struct file * filp, char * buf, int count)
STp
->
rw
=
ST_WRITING
;
STp
->
rw
=
ST_WRITING
;
}
}
#if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS
if
((
STp
->
buffer
)
->
writing
)
{
if
((
STp
->
buffer
)
->
writing
)
{
write_behind_check
(
dev
);
write_behind_check
(
dev
);
if
((
STp
->
buffer
)
->
last_result_fatal
)
{
if
((
STp
->
buffer
)
->
last_result_fatal
)
{
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: Async write error %x.
\n
"
,
dev
,
if
(
debugging
)
(
STp
->
buffer
)
->
last_result
);
printk
(
"st%d: Async write error (write) %x.
\n
"
,
dev
,
(
STp
->
buffer
)
->
last_result
);
#endif
#endif
if
((
STp
->
buffer
)
->
last_result
==
INT_MAX
)
{
if
((
STp
->
buffer
)
->
last_result
==
INT_MAX
)
{
retval
=
(
-
ENOSPC
);
/* All has been written */
retval
=
(
-
ENOSPC
);
/* All has been written */
...
@@ -654,20 +687,21 @@ st_write(struct inode * inode, struct file * filp, char * buf, int count)
...
@@ -654,20 +687,21 @@ st_write(struct inode * inode, struct file * filp, char * buf, int count)
return
retval
;
return
retval
;
}
}
}
}
#endif
if
(
STp
->
eof
==
ST_EOM_OK
)
if
(
STp
->
eof
==
ST_EOM_OK
)
return
(
-
ENOSPC
);
return
(
-
ENOSPC
);
else
if
(
STp
->
eof
==
ST_EOM_ERROR
)
else
if
(
STp
->
eof
==
ST_EOM_ERROR
)
return
(
-
EIO
);
return
(
-
EIO
);
#ifdef ST_NO_DELAYED_WRITES
if
(
!
STp
->
do_buffer_writes
)
{
if
(
STp
->
block_size
!=
0
&&
(
count
%
STp
->
block_size
)
!=
0
)
if
(
STp
->
block_size
!=
0
&&
(
count
%
STp
->
block_size
)
!=
0
)
return
(
-
EIO
);
/* Write must be integral number of blocks */
return
(
-
EIO
);
/* Write must be integral number of blocks */
write_threshold
=
1
;
write_threshold
=
1
;
#else
}
write_threshold
=
(
STp
->
buffer
)
->
buffer_size
;
else
#endif
write_threshold
=
(
STp
->
buffer
)
->
buffer_size
;
if
(
!
STp
->
do_async_writes
)
write_threshold
--
;
SCpnt
=
allocate_device
(
NULL
,
(
STp
->
device
)
->
index
,
1
);
SCpnt
=
allocate_device
(
NULL
,
(
STp
->
device
)
->
index
,
1
);
...
@@ -680,16 +714,9 @@ st_write(struct inode * inode, struct file * filp, char * buf, int count)
...
@@ -680,16 +714,9 @@ st_write(struct inode * inode, struct file * filp, char * buf, int count)
STp
->
rw
=
ST_WRITING
;
STp
->
rw
=
ST_WRITING
;
b_point
=
buf
;
b_point
=
buf
;
while
(
while
((
STp
->
block_size
==
0
&&
!
STp
->
do_async_writes
&&
count
>
0
)
||
#if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS
(
STp
->
block_size
!=
0
&&
STp
->
block_size
!=
0
&&
(
STp
->
buffer
)
->
buffer_bytes
+
count
>
write_threshold
))
((
STp
->
buffer
)
->
buffer_bytes
+
count
)
>
write_threshold
)
#else
(
STp
->
block_size
==
0
&&
count
>
0
)
||
((
STp
->
buffer
)
->
buffer_bytes
+
count
)
>=
write_threshold
)
#endif
{
{
if
(
STp
->
block_size
==
0
)
if
(
STp
->
block_size
==
0
)
do_count
=
count
;
do_count
=
count
;
...
@@ -702,25 +729,27 @@ st_write(struct inode * inode, struct file * filp, char * buf, int count)
...
@@ -702,25 +729,27 @@ st_write(struct inode * inode, struct file * filp, char * buf, int count)
(
STp
->
buffer
)
->
buffer_bytes
,
b_point
,
do_count
);
(
STp
->
buffer
)
->
buffer_bytes
,
b_point
,
do_count
);
if
(
STp
->
block_size
==
0
)
if
(
STp
->
block_size
==
0
)
blks
=
do_count
;
blks
=
transfer
=
do_count
;
else
else
{
blks
=
((
STp
->
buffer
)
->
buffer_bytes
+
do_count
)
/
blks
=
((
STp
->
buffer
)
->
buffer_bytes
+
do_count
)
/
STp
->
block_size
;
STp
->
block_size
;
transfer
=
blks
*
STp
->
block_size
;
}
cmd
[
2
]
=
blks
>>
16
;
cmd
[
2
]
=
blks
>>
16
;
cmd
[
3
]
=
blks
>>
8
;
cmd
[
3
]
=
blks
>>
8
;
cmd
[
4
]
=
blks
;
cmd
[
4
]
=
blks
;
SCpnt
->
sense_buffer
[
0
]
=
0
;
SCpnt
->
sense_buffer
[
0
]
=
0
;
SCpnt
->
request
.
dev
=
dev
;
SCpnt
->
request
.
dev
=
dev
;
scsi_do_cmd
(
SCpnt
,
scsi_do_cmd
(
SCpnt
,
(
void
*
)
cmd
,
(
STp
->
buffer
)
->
b_data
,
(
void
*
)
cmd
,
(
STp
->
buffer
)
->
b_data
,
transfer
,
(
STp
->
buffer
)
->
buffer_size
,
st_sleep_done
,
ST_TIMEOUT
,
MAX_RETRIES
);
st_sleep_done
,
ST_TIMEOUT
,
MAX_RETRIES
);
if
(
SCpnt
->
request
.
dev
==
dev
)
sleep_on
(
&
(
STp
->
waiting
)
);
if
(
SCpnt
->
request
.
dev
==
dev
)
sleep_on
(
&
(
STp
->
waiting
)
);
if
((
STp
->
buffer
)
->
last_result_fatal
!=
0
)
{
if
((
STp
->
buffer
)
->
last_result_fatal
!=
0
)
{
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: Error on write:
\n
"
,
dev
);
if
(
debugging
)
printk
(
"st%d: Error on write:
\n
"
,
dev
);
#endif
#endif
if
((
SCpnt
->
sense_buffer
[
0
]
&
0x70
)
==
0x70
&&
if
((
SCpnt
->
sense_buffer
[
0
]
&
0x70
)
==
0x70
&&
(
SCpnt
->
sense_buffer
[
2
]
&
0x40
))
{
(
SCpnt
->
sense_buffer
[
2
]
&
0x40
))
{
...
@@ -738,23 +767,34 @@ st_write(struct inode * inode, struct file * filp, char * buf, int count)
...
@@ -738,23 +767,34 @@ st_write(struct inode * inode, struct file * filp, char * buf, int count)
if
(
transfer
<=
do_count
)
{
if
(
transfer
<=
do_count
)
{
filp
->
f_pos
+=
do_count
-
transfer
;
filp
->
f_pos
+=
do_count
-
transfer
;
count
-=
do_count
-
transfer
;
count
-=
do_count
-
transfer
;
if
(
STp
->
drv_block
>=
0
)
{
if
(
STp
->
block_size
==
0
&&
transfer
<
do_count
)
STp
->
drv_block
++
;
else
if
(
STp
->
block_size
!=
0
)
STp
->
drv_block
+=
(
do_count
-
transfer
)
/
STp
->
block_size
;
}
STp
->
eof
=
ST_EOM_OK
;
STp
->
eof
=
ST_EOM_OK
;
retval
=
(
-
ENOSPC
);
/* EOM within current request */
retval
=
(
-
ENOSPC
);
/* EOM within current request */
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: EOM with %d bytes unwritten.
\n
"
,
if
(
debugging
)
dev
,
transfer
);
printk
(
"st%d: EOM with %d bytes unwritten.
\n
"
,
dev
,
transfer
);
#endif
#endif
}
}
else
{
else
{
STp
->
eof
=
ST_EOM_ERROR
;
STp
->
eof
=
ST_EOM_ERROR
;
STp
->
drv_block
=
(
-
1
);
/* Too cautious? */
retval
=
(
-
EIO
);
/* EOM for old data */
retval
=
(
-
EIO
);
/* EOM for old data */
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: EOM with lost data.
\n
"
,
dev
);
if
(
debugging
)
printk
(
"st%d: EOM with lost data.
\n
"
,
dev
);
#endif
#endif
}
}
}
}
else
else
{
STp
->
drv_block
=
(
-
1
);
/* Too cautious? */
retval
=
(
-
EIO
);
retval
=
(
-
EIO
);
}
SCpnt
->
request
.
dev
=
-
1
;
/* Mark as not busy */
SCpnt
->
request
.
dev
=
-
1
;
/* Mark as not busy */
(
STp
->
buffer
)
->
buffer_bytes
=
0
;
(
STp
->
buffer
)
->
buffer_bytes
=
0
;
...
@@ -767,6 +807,12 @@ st_write(struct inode * inode, struct file * filp, char * buf, int count)
...
@@ -767,6 +807,12 @@ st_write(struct inode * inode, struct file * filp, char * buf, int count)
filp
->
f_pos
+=
do_count
;
filp
->
f_pos
+=
do_count
;
b_point
+=
do_count
;
b_point
+=
do_count
;
count
-=
do_count
;
count
-=
do_count
;
if
(
STp
->
drv_block
>=
0
)
{
if
(
STp
->
block_size
==
0
)
STp
->
drv_block
++
;
else
STp
->
drv_block
+=
blks
;
}
(
STp
->
buffer
)
->
buffer_bytes
=
0
;
(
STp
->
buffer
)
->
buffer_bytes
=
0
;
STp
->
dirty
=
0
;
STp
->
dirty
=
0
;
}
}
...
@@ -784,9 +830,9 @@ st_write(struct inode * inode, struct file * filp, char * buf, int count)
...
@@ -784,9 +830,9 @@ st_write(struct inode * inode, struct file * filp, char * buf, int count)
return
(
STp
->
buffer
)
->
last_result_fatal
;
return
(
STp
->
buffer
)
->
last_result_fatal
;
}
}
#if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS
if
(
STp
->
do_async_writes
&&
if
((
STp
->
buffer
)
->
buffer_bytes
>=
ST_WRITE_THRESHOLD
||
((
STp
->
buffer
)
->
buffer_bytes
>=
STp
->
write_threshold
||
STp
->
block_size
==
0
)
{
STp
->
block_size
==
0
)
)
{
/* Schedule an asynchronous write */
/* Schedule an asynchronous write */
if
(
STp
->
block_size
==
0
)
if
(
STp
->
block_size
==
0
)
(
STp
->
buffer
)
->
writing
=
(
STp
->
buffer
)
->
buffer_bytes
;
(
STp
->
buffer
)
->
writing
=
(
STp
->
buffer
)
->
buffer_bytes
;
...
@@ -811,7 +857,6 @@ st_write(struct inode * inode, struct file * filp, char * buf, int count)
...
@@ -811,7 +857,6 @@ st_write(struct inode * inode, struct file * filp, char * buf, int count)
st_sleep_done
,
ST_TIMEOUT
,
MAX_RETRIES
);
st_sleep_done
,
ST_TIMEOUT
,
MAX_RETRIES
);
}
}
else
else
#endif
SCpnt
->
request
.
dev
=
-
1
;
/* Mark as not busy */
SCpnt
->
request
.
dev
=
-
1
;
/* Mark as not busy */
return
(
total
);
return
(
total
);
...
@@ -838,9 +883,13 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
...
@@ -838,9 +883,13 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
}
}
#endif
#endif
if
(
STp
->
block_size
==
0
&&
count
>
ST_BUFFER_SIZE
)
if
(
STp
->
block_size
==
0
&&
count
>
st_buffer_size
)
return
(
-
EOVERFLOW
);
return
(
-
EOVERFLOW
);
if
(
!
(
STp
->
do_read_ahead
)
&&
STp
->
block_size
!=
0
&&
(
count
%
STp
->
block_size
)
!=
0
)
return
(
-
EIO
);
/* Read must be integral number of blocks */
if
(
STp
->
rw
==
ST_WRITING
)
{
if
(
STp
->
rw
==
ST_WRITING
)
{
transfer
=
flush_buffer
(
inode
,
filp
,
0
);
transfer
=
flush_buffer
(
inode
,
filp
,
0
);
if
(
transfer
)
if
(
transfer
)
...
@@ -849,7 +898,7 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
...
@@ -849,7 +898,7 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
}
}
#ifdef DEBUG
#ifdef DEBUG
if
(
STp
->
eof
!=
ST_NOEOF
)
if
(
debugging
&&
STp
->
eof
!=
ST_NOEOF
)
printk
(
"st%d: EOF flag up. Bytes %d
\n
"
,
dev
,
printk
(
"st%d: EOF flag up. Bytes %d
\n
"
,
dev
,
(
STp
->
buffer
)
->
buffer_bytes
);
(
STp
->
buffer
)
->
buffer_bytes
);
#endif
#endif
...
@@ -872,8 +921,17 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
...
@@ -872,8 +921,17 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
if
(
STp
->
block_size
==
0
)
if
(
STp
->
block_size
==
0
)
blks
=
bytes
=
count
;
blks
=
bytes
=
count
;
else
{
else
{
blks
=
(
STp
->
buffer
)
->
buffer_blocks
;
if
(
STp
->
do_read_ahead
)
{
bytes
=
blks
*
STp
->
block_size
;
blks
=
(
STp
->
buffer
)
->
buffer_blocks
;
bytes
=
blks
*
STp
->
block_size
;
}
else
{
bytes
=
count
;
if
(
bytes
>
st_buffer_size
)
bytes
=
st_buffer_size
;
blks
=
bytes
/
STp
->
block_size
;
bytes
=
blks
*
STp
->
block_size
;
}
}
}
cmd
[
2
]
=
blks
>>
16
;
cmd
[
2
]
=
blks
>>
16
;
cmd
[
3
]
=
blks
>>
8
;
cmd
[
3
]
=
blks
>>
8
;
...
@@ -893,11 +951,12 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
...
@@ -893,11 +951,12 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
if
((
STp
->
buffer
)
->
last_result_fatal
)
{
if
((
STp
->
buffer
)
->
last_result_fatal
)
{
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x
\n
"
,
dev
,
if
(
debugging
)
SCpnt
->
sense_buffer
[
0
],
SCpnt
->
sense_buffer
[
1
],
printk
(
"st%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x
\n
"
,
dev
,
SCpnt
->
sense_buffer
[
2
],
SCpnt
->
sense_buffer
[
3
],
SCpnt
->
sense_buffer
[
0
],
SCpnt
->
sense_buffer
[
1
],
SCpnt
->
sense_buffer
[
4
],
SCpnt
->
sense_buffer
[
5
],
SCpnt
->
sense_buffer
[
2
],
SCpnt
->
sense_buffer
[
3
],
SCpnt
->
sense_buffer
[
6
],
SCpnt
->
sense_buffer
[
7
]);
SCpnt
->
sense_buffer
[
4
],
SCpnt
->
sense_buffer
[
5
],
SCpnt
->
sense_buffer
[
6
],
SCpnt
->
sense_buffer
[
7
]);
#endif
#endif
if
((
SCpnt
->
sense_buffer
[
0
]
&
0x70
)
==
0x70
)
{
/* extended sense */
if
((
SCpnt
->
sense_buffer
[
0
]
&
0x70
)
==
0x70
)
{
/* extended sense */
...
@@ -917,7 +976,7 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
...
@@ -917,7 +976,7 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
if
(
STp
->
block_size
==
0
)
{
if
(
STp
->
block_size
==
0
)
{
if
(
transfer
<=
0
)
if
(
transfer
<=
0
)
transfer
=
0
;
transfer
=
0
;
(
STp
->
buffer
)
->
buffer_bytes
=
count
-
transfer
;
(
STp
->
buffer
)
->
buffer_bytes
=
bytes
-
transfer
;
}
}
else
{
else
{
printk
(
"st%d: Incorrect block size.
\n
"
,
dev
);
printk
(
"st%d: Incorrect block size.
\n
"
,
dev
);
...
@@ -928,14 +987,14 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
...
@@ -928,14 +987,14 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
else
if
(
SCpnt
->
sense_buffer
[
2
]
&
0x40
)
{
else
if
(
SCpnt
->
sense_buffer
[
2
]
&
0x40
)
{
STp
->
eof
=
ST_EOM_OK
;
STp
->
eof
=
ST_EOM_OK
;
if
(
STp
->
block_size
==
0
)
if
(
STp
->
block_size
==
0
)
(
STp
->
buffer
)
->
buffer_bytes
=
count
-
transfer
;
(
STp
->
buffer
)
->
buffer_bytes
=
bytes
-
transfer
;
else
else
(
STp
->
buffer
)
->
buffer_bytes
=
(
STp
->
buffer
)
->
buffer_bytes
=
((
STp
->
buffer
)
->
buffer_blocks
-
transfer
)
*
bytes
-
transfer
*
STp
->
block_size
;
STp
->
block_size
;
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: EOM detected (%d bytes read).
\n
"
,
dev
,
if
(
debugging
)
(
STp
->
buffer
)
->
buffer_bytes
);
printk
(
"st%d: EOM detected (%d bytes read).
\n
"
,
dev
,
(
STp
->
buffer
)
->
buffer_bytes
);
#endif
#endif
}
}
else
if
(
SCpnt
->
sense_buffer
[
2
]
&
0x80
)
{
else
if
(
SCpnt
->
sense_buffer
[
2
]
&
0x80
)
{
...
@@ -944,20 +1003,22 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
...
@@ -944,20 +1003,22 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
(
STp
->
buffer
)
->
buffer_bytes
=
0
;
(
STp
->
buffer
)
->
buffer_bytes
=
0
;
else
else
(
STp
->
buffer
)
->
buffer_bytes
=
(
STp
->
buffer
)
->
buffer_bytes
=
((
STp
->
buffer
)
->
buffer_blocks
-
transfer
)
*
bytes
-
transfer
*
STp
->
block_size
;
STp
->
block_size
;
#ifdef DEBUG
#ifdef DEBUG
printk
(
if
(
debugging
)
"st%d: EOF detected (%d bytes read, transferred %d bytes).
\n
"
,
printk
(
dev
,
(
STp
->
buffer
)
->
buffer_bytes
,
total
);
"st%d: EOF detected (%d bytes read, transferred %d bytes).
\n
"
,
dev
,
(
STp
->
buffer
)
->
buffer_bytes
,
total
);
#endif
#endif
}
/* end of EOF, EOM, ILI test */
}
/* end of EOF, EOM, ILI test */
}
}
else
{
/* nonzero sense key */
else
{
/* nonzero sense key */
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: Tape error while reading.
\n
"
,
dev
);
if
(
debugging
)
printk
(
"st%d: Tape error while reading.
\n
"
,
dev
);
#endif
#endif
SCpnt
->
request
.
dev
=
-
1
;
SCpnt
->
request
.
dev
=
-
1
;
STp
->
drv_block
=
(
-
1
);
if
(
total
)
if
(
total
)
return
total
;
return
total
;
else
else
...
@@ -973,12 +1034,19 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
...
@@ -973,12 +1034,19 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
else
/* Read successful */
else
/* Read successful */
(
STp
->
buffer
)
->
buffer_bytes
=
bytes
;
(
STp
->
buffer
)
->
buffer_bytes
=
bytes
;
if
(
STp
->
drv_block
>=
0
)
{
if
(
STp
->
block_size
==
0
)
STp
->
drv_block
++
;
else
STp
->
drv_block
+=
(
STp
->
buffer
)
->
buffer_bytes
/
STp
->
block_size
;
}
}
/* if ((STp->buffer)->buffer_bytes == 0 &&
}
/* if ((STp->buffer)->buffer_bytes == 0 &&
STp->eof == ST_NOEOF) */
STp->eof == ST_NOEOF) */
if
((
STp
->
buffer
)
->
buffer_bytes
>
0
)
{
if
((
STp
->
buffer
)
->
buffer_bytes
>
0
)
{
#ifdef DEBUG
#ifdef DEBUG
if
(
STp
->
eof
!=
ST_NOEOF
)
if
(
debugging
&&
STp
->
eof
!=
ST_NOEOF
)
printk
(
"st%d: EOF up. Left %d, needed %d.
\n
"
,
dev
,
printk
(
"st%d: EOF up. Left %d, needed %d.
\n
"
,
dev
,
(
STp
->
buffer
)
->
buffer_bytes
,
count
-
total
);
(
STp
->
buffer
)
->
buffer_bytes
,
count
-
total
);
#endif
#endif
...
@@ -995,8 +1063,11 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
...
@@ -995,8 +1063,11 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
else
if
(
STp
->
eof
!=
ST_NOEOF
)
{
else
if
(
STp
->
eof
!=
ST_NOEOF
)
{
STp
->
eof_hit
=
1
;
STp
->
eof_hit
=
1
;
SCpnt
->
request
.
dev
=
-
1
;
/* Mark as not busy */
SCpnt
->
request
.
dev
=
-
1
;
/* Mark as not busy */
if
(
total
==
0
&&
STp
->
eof
==
ST_FM
)
if
(
total
==
0
&&
STp
->
eof
==
ST_FM
)
{
STp
->
eof
=
0
;
STp
->
eof
=
0
;
STp
->
drv_block
=
0
;
(
STp
->
mt_status
)
->
mt_fileno
++
;
}
if
(
total
==
0
&&
STp
->
eof
==
ST_EOM_OK
)
if
(
total
==
0
&&
STp
->
eof
==
ST_EOM_OK
)
return
(
-
EIO
);
/* ST_EOM_ERROR not used in read */
return
(
-
EIO
);
/* ST_EOM_ERROR not used in read */
return
total
;
return
total
;
...
@@ -1012,6 +1083,49 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
...
@@ -1012,6 +1083,49 @@ st_read(struct inode * inode, struct file * filp, char * buf, int count)
return
total
;
return
total
;
}
}
/* Set the driver options */
static
int
st_set_options
(
struct
inode
*
inode
,
long
options
)
{
int
dev
,
value
;
Scsi_Tape
*
STp
;
dev
=
MINOR
(
inode
->
i_rdev
)
&
127
;
STp
=
&
(
scsi_tapes
[
dev
]);
if
((
options
&
MT_ST_OPTIONS
)
==
MT_ST_BOOLEANS
)
{
STp
->
do_buffer_writes
=
(
options
&
MT_ST_BUFFER_WRITES
)
!=
0
;
STp
->
do_async_writes
=
(
options
&
MT_ST_ASYNC_WRITES
)
!=
0
;
STp
->
do_read_ahead
=
(
options
&
MT_ST_READ_AHEAD
)
!=
0
;
#ifdef DEBUG
debugging
=
(
options
&
MT_ST_DEBUGGING
)
!=
0
;
printk
(
"st%d: options: buffer writes: %d, async writes: %d, read ahead: %d
\n
"
,
dev
,
STp
->
do_buffer_writes
,
STp
->
do_async_writes
,
STp
->
do_read_ahead
);
printk
(
" debugging: %d
\n
"
,
debugging
);
#endif
}
else
if
((
options
&
MT_ST_OPTIONS
)
==
MT_ST_WRITE_THRESHOLD
)
{
value
=
(
options
&
~
MT_ST_OPTIONS
)
*
ST_BLOCK_SIZE
;
if
(
value
<
1
||
value
>
st_buffer_size
)
{
printk
(
"st: Write threshold %d too small or too large.
\n
"
,
value
);
return
(
-
EIO
);
}
STp
->
write_threshold
=
value
;
#ifdef DEBUG
printk
(
"st%d: Write threshold set to %d bytes.
\n
"
,
dev
,
STp
->
write_threshold
);
#endif
}
else
return
(
-
EIO
);
return
0
;
}
/* Internal ioctl function */
/* Internal ioctl function */
static
int
static
int
...
@@ -1025,11 +1139,15 @@ st_int_ioctl(struct inode * inode,struct file * file,
...
@@ -1025,11 +1139,15 @@ st_int_ioctl(struct inode * inode,struct file * file,
unsigned
char
cmd
[
10
];
unsigned
char
cmd
[
10
];
Scsi_Cmnd
*
SCpnt
;
Scsi_Cmnd
*
SCpnt
;
Scsi_Tape
*
STp
;
Scsi_Tape
*
STp
;
int
fileno
,
blkno
,
undone
,
datalen
;
dev
=
dev
&
127
;
dev
=
dev
&
127
;
STp
=
&
(
scsi_tapes
[
dev
]);
STp
=
&
(
scsi_tapes
[
dev
]);
fileno
=
(
STp
->
mt_status
)
->
mt_fileno
;
blkno
=
STp
->
drv_block
;
memset
(
cmd
,
0
,
10
);
memset
(
cmd
,
0
,
10
);
datalen
=
0
;
switch
(
cmd_in
)
{
switch
(
cmd_in
)
{
case
MTFSF
:
case
MTFSF
:
case
MTFSFM
:
case
MTFSFM
:
...
@@ -1039,9 +1157,12 @@ st_int_ioctl(struct inode * inode,struct file * file,
...
@@ -1039,9 +1157,12 @@ st_int_ioctl(struct inode * inode,struct file * file,
cmd
[
3
]
=
(
arg
>>
8
);
cmd
[
3
]
=
(
arg
>>
8
);
cmd
[
4
]
=
arg
;
cmd
[
4
]
=
arg
;
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: Spacing tape forward over %d filemarks.
\n
"
,
dev
,
if
(
debugging
)
cmd
[
2
]
*
65536
+
cmd
[
3
]
*
256
+
cmd
[
4
]);
printk
(
"st%d: Spacing tape forward over %d filemarks.
\n
"
,
dev
,
cmd
[
2
]
*
65536
+
cmd
[
3
]
*
256
+
cmd
[
4
]);
#endif
#endif
fileno
+=
arg
;
blkno
=
0
;
break
;
break
;
case
MTBSF
:
case
MTBSF
:
case
MTBSFM
:
case
MTBSFM
:
...
@@ -1052,11 +1173,15 @@ st_int_ioctl(struct inode * inode,struct file * file,
...
@@ -1052,11 +1173,15 @@ st_int_ioctl(struct inode * inode,struct file * file,
cmd
[
3
]
=
(
ltmp
>>
8
);
cmd
[
3
]
=
(
ltmp
>>
8
);
cmd
[
4
]
=
ltmp
;
cmd
[
4
]
=
ltmp
;
#ifdef DEBUG
#ifdef DEBUG
if
(
cmd
[
2
]
&
0x80
)
if
(
debugging
)
{
ltmp
=
0xff000000
;
if
(
cmd
[
2
]
&
0x80
)
ltmp
=
ltmp
|
(
cmd
[
2
]
<<
16
)
|
(
cmd
[
3
]
<<
8
)
|
cmd
[
4
];
ltmp
=
0xff000000
;
printk
(
"st%d: Spacing tape backward over %d filemarks.
\n
"
,
dev
,
(
-
ltmp
));
ltmp
=
ltmp
|
(
cmd
[
2
]
<<
16
)
|
(
cmd
[
3
]
<<
8
)
|
cmd
[
4
];
printk
(
"st%d: Spacing tape backward over %ld filemarks.
\n
"
,
dev
,
(
-
ltmp
));
}
#endif
#endif
fileno
-=
arg
;
blkno
=
(
-
1
);
/* We can't know the block number */
break
;
break
;
case
MTFSR
:
case
MTFSR
:
cmd
[
0
]
=
SPACE
;
cmd
[
0
]
=
SPACE
;
...
@@ -1065,9 +1190,12 @@ st_int_ioctl(struct inode * inode,struct file * file,
...
@@ -1065,9 +1190,12 @@ st_int_ioctl(struct inode * inode,struct file * file,
cmd
[
3
]
=
(
arg
>>
8
);
cmd
[
3
]
=
(
arg
>>
8
);
cmd
[
4
]
=
arg
;
cmd
[
4
]
=
arg
;
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: Spacing tape forward %d blocks.
\n
"
,
dev
,
if
(
debugging
)
cmd
[
2
]
*
65536
+
cmd
[
3
]
*
256
+
cmd
[
4
]);
printk
(
"st%d: Spacing tape forward %d blocks.
\n
"
,
dev
,
cmd
[
2
]
*
65536
+
cmd
[
3
]
*
256
+
cmd
[
4
]);
#endif
#endif
if
(
blkno
>=
0
)
blkno
+=
arg
;
break
;
break
;
case
MTBSR
:
case
MTBSR
:
cmd
[
0
]
=
SPACE
;
cmd
[
0
]
=
SPACE
;
...
@@ -1077,11 +1205,15 @@ st_int_ioctl(struct inode * inode,struct file * file,
...
@@ -1077,11 +1205,15 @@ st_int_ioctl(struct inode * inode,struct file * file,
cmd
[
3
]
=
(
ltmp
>>
8
);
cmd
[
3
]
=
(
ltmp
>>
8
);
cmd
[
4
]
=
ltmp
;
cmd
[
4
]
=
ltmp
;
#ifdef DEBUG
#ifdef DEBUG
if
(
cmd
[
2
]
&
0x80
)
if
(
debugging
)
{
ltmp
=
0xff000000
;
if
(
cmd
[
2
]
&
0x80
)
ltmp
=
ltmp
|
(
cmd
[
2
]
<<
16
)
|
(
cmd
[
3
]
<<
8
)
|
cmd
[
4
];
ltmp
=
0xff000000
;
printk
(
"st%d: Spacing tape backward %d blocks.
\n
"
,
dev
,
(
-
ltmp
));
ltmp
=
ltmp
|
(
cmd
[
2
]
<<
16
)
|
(
cmd
[
3
]
<<
8
)
|
cmd
[
4
];
printk
(
"st%d: Spacing tape backward %ld blocks.
\n
"
,
dev
,
(
-
ltmp
));
}
#endif
#endif
if
(
blkno
>=
0
)
blkno
-=
arg
;
break
;
break
;
case
MTWEOF
:
case
MTWEOF
:
if
(
STp
->
write_prot
)
if
(
STp
->
write_prot
)
...
@@ -1092,9 +1224,12 @@ st_int_ioctl(struct inode * inode,struct file * file,
...
@@ -1092,9 +1224,12 @@ st_int_ioctl(struct inode * inode,struct file * file,
cmd
[
4
]
=
arg
;
cmd
[
4
]
=
arg
;
timeout
=
ST_TIMEOUT
;
timeout
=
ST_TIMEOUT
;
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: Writing %d filemarks.
\n
"
,
dev
,
if
(
debugging
)
cmd
[
2
]
*
65536
+
cmd
[
3
]
*
256
+
cmd
[
4
]);
printk
(
"st%d: Writing %d filemarks.
\n
"
,
dev
,
cmd
[
2
]
*
65536
+
cmd
[
3
]
*
256
+
cmd
[
4
]);
#endif
#endif
fileno
+=
arg
;
blkno
=
0
;
break
;
break
;
case
MTREW
:
case
MTREW
:
cmd
[
0
]
=
REZERO_UNIT
;
cmd
[
0
]
=
REZERO_UNIT
;
...
@@ -1103,8 +1238,10 @@ st_int_ioctl(struct inode * inode,struct file * file,
...
@@ -1103,8 +1238,10 @@ st_int_ioctl(struct inode * inode,struct file * file,
timeout
=
ST_TIMEOUT
;
timeout
=
ST_TIMEOUT
;
#endif
#endif
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: Rewinding tape.
\n
"
,
dev
);
if
(
debugging
)
printk
(
"st%d: Rewinding tape.
\n
"
,
dev
);
#endif
#endif
fileno
=
blkno
=
0
;
break
;
break
;
case
MTOFFL
:
case
MTOFFL
:
cmd
[
0
]
=
START_STOP
;
cmd
[
0
]
=
START_STOP
;
...
@@ -1113,12 +1250,15 @@ st_int_ioctl(struct inode * inode,struct file * file,
...
@@ -1113,12 +1250,15 @@ st_int_ioctl(struct inode * inode,struct file * file,
timeout
=
ST_TIMEOUT
;
timeout
=
ST_TIMEOUT
;
#endif
#endif
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: Unloading tape.
\n
"
,
dev
);
if
(
debugging
)
printk
(
"st%d: Unloading tape.
\n
"
,
dev
);
#endif
#endif
fileno
=
blkno
=
0
;
break
;
break
;
case
MTNOP
:
case
MTNOP
:
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: No op on tape.
\n
"
,
dev
);
if
(
debugging
)
printk
(
"st%d: No op on tape.
\n
"
,
dev
);
#endif
#endif
return
0
;
/* Should do something ? */
return
0
;
/* Should do something ? */
break
;
break
;
...
@@ -1130,15 +1270,26 @@ st_int_ioctl(struct inode * inode,struct file * file,
...
@@ -1130,15 +1270,26 @@ st_int_ioctl(struct inode * inode,struct file * file,
#endif
#endif
cmd
[
4
]
=
3
;
cmd
[
4
]
=
3
;
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: Retensioning tape.
\n
"
,
dev
);
if
(
debugging
)
printk
(
"st%d: Retensioning tape.
\n
"
,
dev
);
#endif
#endif
fileno
=
blkno
=
0
;
break
;
break
;
case
MTEOM
:
case
MTEOM
:
/* space to the end of tape */
ioctl_result
=
st_int_ioctl
(
inode
,
file
,
MTFSF
,
0x3fff
);
fileno
=
(
STp
->
mt_status
)
->
mt_fileno
;
/* The next lines would hide the number of spaced FileMarks
That's why I inserted the previous lines. I had no luck
with detecting EOM with FSF, so we go now to EOM.
Joerg Weule */
cmd
[
0
]
=
SPACE
;
cmd
[
0
]
=
SPACE
;
cmd
[
1
]
=
3
;
cmd
[
1
]
=
3
;
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: Spacing to end of recorded medium.
\n
"
,
dev
);
if
(
debugging
)
printk
(
"st%d: Spacing to end of recorded medium.
\n
"
,
dev
);
#endif
#endif
blkno
=
(
-
1
);
break
;
break
;
case
MTERASE
:
case
MTERASE
:
if
(
STp
->
write_prot
)
if
(
STp
->
write_prot
)
...
@@ -1146,8 +1297,10 @@ st_int_ioctl(struct inode * inode,struct file * file,
...
@@ -1146,8 +1297,10 @@ st_int_ioctl(struct inode * inode,struct file * file,
cmd
[
0
]
=
ERASE
;
cmd
[
0
]
=
ERASE
;
cmd
[
1
]
=
1
;
/* To the end of tape */
cmd
[
1
]
=
1
;
/* To the end of tape */
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: Erasing tape.
\n
"
,
dev
);
if
(
debugging
)
printk
(
"st%d: Erasing tape.
\n
"
,
dev
);
#endif
#endif
fileno
=
blkno
=
0
;
break
;
break
;
case
MTSEEK
:
case
MTSEEK
:
if
((
STp
->
device
)
->
scsi_level
<
SCSI_2
)
{
if
((
STp
->
device
)
->
scsi_level
<
SCSI_2
)
{
...
@@ -1170,8 +1323,10 @@ st_int_ioctl(struct inode * inode,struct file * file,
...
@@ -1170,8 +1323,10 @@ st_int_ioctl(struct inode * inode,struct file * file,
timeout
=
ST_TIMEOUT
;
timeout
=
ST_TIMEOUT
;
#endif
#endif
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: Seeking tape to block %d.
\n
"
,
dev
,
arg
);
if
(
debugging
)
printk
(
"st%d: Seeking tape to block %ld.
\n
"
,
dev
,
arg
);
#endif
#endif
fileno
=
blkno
=
(
-
1
);
break
;
break
;
case
MTSETBLK
:
/* Set block length */
case
MTSETBLK
:
/* Set block length */
case
MTSETDENSITY
:
/* Set tape density */
case
MTSETDENSITY
:
/* Set tape density */
...
@@ -1181,12 +1336,12 @@ st_int_ioctl(struct inode * inode,struct file * file,
...
@@ -1181,12 +1336,12 @@ st_int_ioctl(struct inode * inode,struct file * file,
if
(
cmd_in
==
MTSETBLK
&&
if
(
cmd_in
==
MTSETBLK
&&
arg
!=
0
&&
arg
!=
0
&&
(
arg
<
STp
->
min_block
||
arg
>
STp
->
max_block
||
(
arg
<
STp
->
min_block
||
arg
>
STp
->
max_block
||
arg
>
ST_BUFFER_SIZE
))
{
arg
>
st_buffer_size
))
{
printk
(
"st%d: Illegal block size.
\n
"
,
dev
);
printk
(
"st%d: Illegal block size.
\n
"
,
dev
);
return
(
-
EINVAL
);
return
(
-
EINVAL
);
}
}
cmd
[
0
]
=
MODE_SELECT
;
cmd
[
0
]
=
MODE_SELECT
;
cmd
[
4
]
=
12
;
cmd
[
4
]
=
datalen
=
12
;
memset
((
STp
->
buffer
)
->
b_data
,
0
,
12
);
memset
((
STp
->
buffer
)
->
b_data
,
0
,
12
);
if
(
cmd_in
==
MTSETDRVBUFFER
)
if
(
cmd_in
==
MTSETDRVBUFFER
)
...
@@ -1208,17 +1363,19 @@ st_int_ioctl(struct inode * inode,struct file * file,
...
@@ -1208,17 +1363,19 @@ st_int_ioctl(struct inode * inode,struct file * file,
(
STp
->
buffer
)
->
b_data
[
11
]
=
ltmp
;
(
STp
->
buffer
)
->
b_data
[
11
]
=
ltmp
;
timeout
=
ST_TIMEOUT
;
timeout
=
ST_TIMEOUT
;
#ifdef DEBUG
#ifdef DEBUG
if
(
cmd_in
==
MTSETBLK
)
if
(
debugging
)
{
printk
(
"st%d: Setting block size to %d bytes.
\n
"
,
dev
,
if
(
cmd_in
==
MTSETBLK
)
(
STp
->
buffer
)
->
b_data
[
9
]
*
65536
+
printk
(
"st%d: Setting block size to %d bytes.
\n
"
,
dev
,
(
STp
->
buffer
)
->
b_data
[
10
]
*
256
+
(
STp
->
buffer
)
->
b_data
[
9
]
*
65536
+
(
STp
->
buffer
)
->
b_data
[
11
]);
(
STp
->
buffer
)
->
b_data
[
10
]
*
256
+
else
if
(
cmd_in
==
MTSETDENSITY
)
(
STp
->
buffer
)
->
b_data
[
11
]);
printk
(
"st%d: Setting density code to %x.
\n
"
,
dev
,
else
if
(
cmd_in
==
MTSETDENSITY
)
(
STp
->
buffer
)
->
b_data
[
4
]);
printk
(
"st%d: Setting density code to %x.
\n
"
,
dev
,
else
(
STp
->
buffer
)
->
b_data
[
4
]);
printk
(
"st%d: Setting drive buffer code to %d.
\n
"
,
dev
,
else
((
STp
->
buffer
)
->
b_data
[
2
]
>>
4
)
&
7
);
printk
(
"st%d: Setting drive buffer code to %d.
\n
"
,
dev
,
((
STp
->
buffer
)
->
b_data
[
2
]
>>
4
)
&
7
);
}
#endif
#endif
break
;
break
;
default:
default:
...
@@ -1230,7 +1387,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
...
@@ -1230,7 +1387,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
SCpnt
->
sense_buffer
[
0
]
=
0
;
SCpnt
->
sense_buffer
[
0
]
=
0
;
SCpnt
->
request
.
dev
=
dev
;
SCpnt
->
request
.
dev
=
dev
;
scsi_do_cmd
(
SCpnt
,
scsi_do_cmd
(
SCpnt
,
(
void
*
)
cmd
,
(
void
*
)
(
STp
->
buffer
)
->
b_data
,
ST_BLOCK_SIZE
,
(
void
*
)
cmd
,
(
void
*
)
(
STp
->
buffer
)
->
b_data
,
datalen
,
st_sleep_done
,
timeout
,
MAX_RETRIES
);
st_sleep_done
,
timeout
,
MAX_RETRIES
);
if
(
SCpnt
->
request
.
dev
==
dev
)
sleep_on
(
&
(
STp
->
waiting
)
);
if
(
SCpnt
->
request
.
dev
==
dev
)
sleep_on
(
&
(
STp
->
waiting
)
);
...
@@ -1240,6 +1397,8 @@ st_int_ioctl(struct inode * inode,struct file * file,
...
@@ -1240,6 +1397,8 @@ st_int_ioctl(struct inode * inode,struct file * file,
SCpnt
->
request
.
dev
=
-
1
;
/* Mark as not busy */
SCpnt
->
request
.
dev
=
-
1
;
/* Mark as not busy */
if
(
!
ioctl_result
)
{
if
(
!
ioctl_result
)
{
STp
->
drv_block
=
blkno
;
(
STp
->
mt_status
)
->
mt_fileno
=
fileno
;
if
(
cmd_in
==
MTBSFM
)
if
(
cmd_in
==
MTBSFM
)
ioctl_result
=
st_int_ioctl
(
inode
,
file
,
MTFSF
,
1
);
ioctl_result
=
st_int_ioctl
(
inode
,
file
,
MTFSF
,
1
);
else
if
(
cmd_in
==
MTFSFM
)
else
if
(
cmd_in
==
MTFSFM
)
...
@@ -1248,13 +1407,13 @@ st_int_ioctl(struct inode * inode,struct file * file,
...
@@ -1248,13 +1407,13 @@ st_int_ioctl(struct inode * inode,struct file * file,
STp
->
block_size
=
arg
;
STp
->
block_size
=
arg
;
if
(
arg
!=
0
)
{
if
(
arg
!=
0
)
{
(
STp
->
buffer
)
->
buffer_blocks
=
(
STp
->
buffer
)
->
buffer_blocks
=
ST_BUFFER_SIZE
/
STp
->
block_size
;
st_buffer_size
/
STp
->
block_size
;
(
STp
->
buffer
)
->
buffer_size
=
(
STp
->
buffer
)
->
buffer_size
=
(
STp
->
buffer
)
->
buffer_blocks
*
STp
->
block_size
;
(
STp
->
buffer
)
->
buffer_blocks
*
STp
->
block_size
;
}
}
else
{
else
{
(
STp
->
buffer
)
->
buffer_blocks
=
1
;
(
STp
->
buffer
)
->
buffer_blocks
=
1
;
(
STp
->
buffer
)
->
buffer_size
=
ST_BUFFER_SIZE
;
(
STp
->
buffer
)
->
buffer_size
=
st_buffer_size
;
}
}
(
STp
->
buffer
)
->
buffer_bytes
=
(
STp
->
buffer
)
->
buffer_bytes
=
(
STp
->
buffer
)
->
read_pointer
=
0
;
(
STp
->
buffer
)
->
read_pointer
=
0
;
...
@@ -1263,7 +1422,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
...
@@ -1263,7 +1422,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
STp
->
drv_buffer
=
arg
;
STp
->
drv_buffer
=
arg
;
else
if
(
cmd_in
==
MTSETDENSITY
)
else
if
(
cmd_in
==
MTSETDENSITY
)
STp
->
density
=
arg
;
STp
->
density
=
arg
;
if
(
cmd_in
==
MTEOM
||
cmd_in
==
MTWEOF
)
{
else
if
(
cmd_in
==
MTEOM
||
cmd_in
==
MTWEOF
)
{
STp
->
eof
=
ST_EOM_OK
;
STp
->
eof
=
ST_EOM_OK
;
STp
->
eof_hit
=
0
;
STp
->
eof_hit
=
0
;
}
}
...
@@ -1271,6 +1430,33 @@ st_int_ioctl(struct inode * inode,struct file * file,
...
@@ -1271,6 +1430,33 @@ st_int_ioctl(struct inode * inode,struct file * file,
STp
->
eof
=
ST_NOEOF
;
STp
->
eof
=
ST_NOEOF
;
STp
->
eof_hit
=
0
;
STp
->
eof_hit
=
0
;
}
}
}
else
{
if
(
SCpnt
->
sense_buffer
[
2
]
&
0x40
)
{
STp
->
eof
=
ST_EOM_OK
;
STp
->
eof_hit
=
0
;
STp
->
drv_block
=
0
;
}
undone
=
(
(
SCpnt
->
sense_buffer
[
3
]
<<
24
)
+
(
SCpnt
->
sense_buffer
[
4
]
<<
16
)
+
(
SCpnt
->
sense_buffer
[
5
]
<<
8
)
+
SCpnt
->
sense_buffer
[
6
]
);
if
(
(
cmd_in
==
MTFSF
)
||
(
cmd_in
==
MTFSFM
)
)
(
STp
->
mt_status
)
->
mt_fileno
=
fileno
-
undone
;
else
if
(
(
cmd_in
==
MTBSF
)
||
(
cmd_in
==
MTBSFM
)
)
(
STp
->
mt_status
)
->
mt_fileno
=
fileno
+
undone
;
else
if
(
cmd_in
==
MTFSR
)
{
if
(
blkno
>=
undone
)
STp
->
drv_block
=
blkno
-
undone
;
else
STp
->
drv_block
=
(
-
1
);
}
else
if
(
cmd_in
==
MTBSR
&&
blkno
>=
0
)
{
if
(
blkno
>=
0
)
STp
->
drv_block
=
blkno
+
undone
;
else
STp
->
drv_block
=
(
-
1
);
}
}
}
return
ioctl_result
;
return
ioctl_result
;
...
@@ -1294,7 +1480,7 @@ st_ioctl(struct inode * inode,struct file * file,
...
@@ -1294,7 +1480,7 @@ st_ioctl(struct inode * inode,struct file * file,
dev
=
dev
&
127
;
dev
=
dev
&
127
;
STp
=
&
(
scsi_tapes
[
dev
]);
STp
=
&
(
scsi_tapes
[
dev
]);
#ifdef DEBUG
#ifdef DEBUG
if
(
!
STp
->
in_use
)
{
if
(
debugging
&&
!
STp
->
in_use
)
{
printk
(
"st%d: Incorrect device.
\n
"
,
dev
);
printk
(
"st%d: Incorrect device.
\n
"
,
dev
);
return
(
-
EIO
);
return
(
-
EIO
);
}
}
...
@@ -1318,7 +1504,11 @@ st_ioctl(struct inode * inode,struct file * file,
...
@@ -1318,7 +1504,11 @@ st_ioctl(struct inode * inode,struct file * file,
if
(
i
<
0
)
if
(
i
<
0
)
return
i
;
return
i
;
return
st_int_ioctl
(
inode
,
file
,
mtc
.
mt_op
,
mtc
.
mt_count
);
if
(
mtc
.
mt_op
==
MTSETDRVBUFFER
&&
(
mtc
.
mt_count
&
MT_ST_OPTIONS
)
!=
0
)
return
st_set_options
(
inode
,
mtc
.
mt_count
);
else
return
st_int_ioctl
(
inode
,
file
,
mtc
.
mt_op
,
mtc
.
mt_count
);
}
}
else
if
(
cmd
==
(
MTIOCGET
&
IOCCMD_MASK
))
{
else
if
(
cmd
==
(
MTIOCGET
&
IOCCMD_MASK
))
{
...
@@ -1328,13 +1518,29 @@ st_ioctl(struct inode * inode,struct file * file,
...
@@ -1328,13 +1518,29 @@ st_ioctl(struct inode * inode,struct file * file,
if
(
i
)
if
(
i
)
return
i
;
return
i
;
memcpy_tofs
((
char
*
)
arg
,
(
char
*
)(
STp
->
buffer
)
->
mt_status
,
(
STp
->
mt_status
)
->
mt_dsreg
=
((
STp
->
block_size
<<
MT_ST_BLKSIZE_SHIFT
)
&
MT_ST_BLKSIZE_MASK
)
|
((
STp
->
density
<<
MT_ST_DENSITY_SHIFT
)
&
MT_ST_DENSITY_MASK
);
(
STp
->
mt_status
)
->
mt_blkno
=
STp
->
drv_block
;
if
(
STp
->
block_size
!=
0
)
{
if
(
STp
->
rw
==
ST_WRITING
)
(
STp
->
mt_status
)
->
mt_blkno
+=
(
STp
->
buffer
)
->
buffer_bytes
/
STp
->
block_size
;
else
if
(
STp
->
rw
==
ST_READING
)
(
STp
->
mt_status
)
->
mt_blkno
-=
((
STp
->
buffer
)
->
buffer_bytes
+
STp
->
block_size
-
1
)
/
STp
->
block_size
;
}
memcpy_tofs
((
char
*
)
arg
,
(
char
*
)(
STp
->
mt_status
),
sizeof
(
struct
mtget
));
sizeof
(
struct
mtget
));
(
STp
->
mt_status
)
->
mt_erreg
=
0
;
/* Clear after read */
return
0
;
return
0
;
}
}
else
if
(
cmd
==
(
MTIOCPOS
&
IOCCMD_MASK
))
{
else
if
(
cmd
==
(
MTIOCPOS
&
IOCCMD_MASK
))
{
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: get tape position.
\n
"
,
dev
);
if
(
debugging
)
printk
(
"st%d: get tape position.
\n
"
,
dev
);
#endif
#endif
if
(((
cmd_in
&
IOCSIZE_MASK
)
>>
IOCSIZE_SHIFT
)
!=
sizeof
(
struct
mtpos
))
if
(((
cmd_in
&
IOCSIZE_MASK
)
>>
IOCSIZE_SHIFT
)
!=
sizeof
(
struct
mtpos
))
return
(
-
EINVAL
);
return
(
-
EINVAL
);
...
@@ -1363,14 +1569,15 @@ st_ioctl(struct inode * inode,struct file * file,
...
@@ -1363,14 +1569,15 @@ st_ioctl(struct inode * inode,struct file * file,
SCpnt
->
sense_buffer
[
0
]
=
0
;
SCpnt
->
sense_buffer
[
0
]
=
0
;
scsi_do_cmd
(
SCpnt
,
scsi_do_cmd
(
SCpnt
,
(
void
*
)
scmd
,
(
void
*
)
(
STp
->
buffer
)
->
b_data
,
(
void
*
)
scmd
,
(
void
*
)
(
STp
->
buffer
)
->
b_data
,
ST_BLOCK_SIZE
,
st_sleep_done
,
ST_TIMEOUT
,
MAX_READY_RETRIES
);
20
,
st_sleep_done
,
ST_TIMEOUT
,
MAX_READY_RETRIES
);
if
(
SCpnt
->
request
.
dev
==
dev
)
sleep_on
(
&
(
STp
->
waiting
)
);
if
(
SCpnt
->
request
.
dev
==
dev
)
sleep_on
(
&
(
STp
->
waiting
)
);
if
((
STp
->
buffer
)
->
last_result_fatal
!=
0
)
{
if
((
STp
->
buffer
)
->
last_result_fatal
!=
0
)
{
mt_pos
.
mt_blkno
=
(
-
1
);
mt_pos
.
mt_blkno
=
(
-
1
);
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st%d: Can't read tape position.
\n
"
,
dev
);
if
(
debugging
)
printk
(
"st%d: Can't read tape position.
\n
"
,
dev
);
#endif
#endif
result
=
(
-
EIO
);
result
=
(
-
EIO
);
}
}
...
@@ -1397,8 +1604,25 @@ st_ioctl(struct inode * inode,struct file * file,
...
@@ -1397,8 +1604,25 @@ st_ioctl(struct inode * inode,struct file * file,
return
scsi_ioctl
(
STp
->
device
,
cmd_in
,
(
void
*
)
arg
);
return
scsi_ioctl
(
STp
->
device
,
cmd_in
,
(
void
*
)
arg
);
}
}
/* Set the boot options. Syntax: st=xxx,yyy
where xxx is buffer size in 512 byte blocks and yyy is write threshold
in 512 byte blocks. */
void
st_setup
(
char
*
str
,
int
*
ints
)
{
if
(
ints
[
0
]
>
0
&&
ints
[
1
]
>
0
)
st_buffer_size
=
ints
[
1
]
*
ST_BLOCK_SIZE
;
if
(
ints
[
0
]
>
1
&&
ints
[
2
]
>
0
)
{
st_write_threshold
=
ints
[
2
]
*
ST_BLOCK_SIZE
;
if
(
st_write_threshold
>
st_buffer_size
)
st_write_threshold
=
st_buffer_size
;
}
if
(
ints
[
0
]
>
2
&&
ints
[
3
]
>
0
)
st_max_buffers
=
ints
[
3
];
}
static
struct
file_operations
st_fops
=
{
static
struct
file_operations
st_fops
=
{
NULL
,
/* lseek - default */
NULL
,
/* lseek - default */
st_read
,
/* read - general block-dev read */
st_read
,
/* read - general block-dev read */
...
@@ -1426,7 +1650,8 @@ unsigned long st_init1(unsigned long mem_start, unsigned long mem_end){
...
@@ -1426,7 +1650,8 @@ unsigned long st_init1(unsigned long mem_start, unsigned long mem_end){
/* Driver initialization */
/* Driver initialization */
unsigned
long
st_init
(
unsigned
long
mem_start
,
unsigned
long
mem_end
)
unsigned
long
st_init
(
unsigned
long
mem_start
,
unsigned
long
mem_end
)
{
{
int
i
;
int
i
,
dev_nbr
;
Scsi_Tape
*
STp
;
if
(
register_chrdev
(
MAJOR_NR
,
"st"
,
&
st_fops
))
{
if
(
register_chrdev
(
MAJOR_NR
,
"st"
,
&
st_fops
))
{
printk
(
"Unable to get major %d for SCSI tapes
\n
"
,
MAJOR_NR
);
printk
(
"Unable to get major %d for SCSI tapes
\n
"
,
MAJOR_NR
);
...
@@ -1435,40 +1660,56 @@ unsigned long st_init(unsigned long mem_start, unsigned long mem_end)
...
@@ -1435,40 +1660,56 @@ unsigned long st_init(unsigned long mem_start, unsigned long mem_end)
if
(
NR_ST
==
0
)
return
mem_start
;
if
(
NR_ST
==
0
)
return
mem_start
;
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st: Init tape.
\n
"
);
printk
(
"st: Buffer size %d bytes, write threshold %d bytes.
\n
"
,
st_buffer_size
,
st_write_threshold
);
#endif
#endif
for
(
i
=
0
;
i
<
NR_ST
;
++
i
)
{
for
(
i
=
0
,
dev_nbr
=
(
-
1
);
i
<
NR_ST
;
++
i
)
{
scsi_tapes
[
i
].
capacity
=
0xfffff
;
STp
=
&
(
scsi_tapes
[
i
]);
scsi_tapes
[
i
].
dirty
=
0
;
STp
->
capacity
=
0xfffff
;
scsi_tapes
[
i
].
rw
=
ST_IDLE
;
STp
->
dirty
=
0
;
scsi_tapes
[
i
].
eof
=
ST_NOEOF
;
STp
->
rw
=
ST_IDLE
;
scsi_tapes
[
i
].
waiting
=
NULL
;
STp
->
eof
=
ST_NOEOF
;
scsi_tapes
[
i
].
in_use
=
0
;
STp
->
waiting
=
NULL
;
scsi_tapes
[
i
].
drv_buffer
=
1
;
/* Try buffering if no mode sense */
STp
->
in_use
=
0
;
scsi_tapes
[
i
].
density
=
0
;
STp
->
drv_buffer
=
1
;
/* Try buffering if no mode sense */
STp
->
density
=
0
;
STp
->
do_buffer_writes
=
ST_BUFFER_WRITES
;
STp
->
do_async_writes
=
ST_ASYNC_WRITES
;
STp
->
do_read_ahead
=
ST_READ_AHEAD
;
STp
->
write_threshold
=
st_write_threshold
;
STp
->
drv_block
=
0
;
STp
->
mt_status
=
(
struct
mtget
*
)
mem_start
;
mem_start
+=
sizeof
(
struct
mtget
);
/* Initialize status */
memset
((
void
*
)
scsi_tapes
[
i
].
mt_status
,
0
,
sizeof
(
struct
mtget
));
for
(
dev_nbr
++
;
dev_nbr
<
NR_SCSI_DEVICES
;
dev_nbr
++
)
if
(
scsi_devices
[
dev_nbr
].
type
==
TYPE_TAPE
)
break
;
if
(
dev_nbr
>=
NR_SCSI_DEVICES
)
printk
(
"st%d: ERROR: Not found in scsi chain.
\n
"
,
i
);
else
{
if
(
scsi_devices
[
dev_nbr
].
scsi_level
<=
2
)
STp
->
mt_status
->
mt_type
=
MT_ISSCSI1
;
else
STp
->
mt_status
->
mt_type
=
MT_ISSCSI2
;
}
}
}
/* Allocate the buffers */
/* Allocate the buffers */
if
(
NR_ST
==
1
)
st_nbr_buffers
=
NR_ST
;
st_nbr_buffers
=
1
;
if
(
st_nbr_buffers
>
st_max_buffers
)
else
st_nbr_buffers
=
st_max_buffers
;
st_nbr_buffers
=
2
;
st_buffers
=
(
ST_buffer
**
)
mem_start
;
mem_start
+=
st_nbr_buffers
*
sizeof
(
ST_buffer
*
);
for
(
i
=
0
;
i
<
st_nbr_buffers
;
i
++
)
{
for
(
i
=
0
;
i
<
st_nbr_buffers
;
i
++
)
{
st_buffers
[
i
]
=
(
ST_buffer
*
)
mem_start
;
st_buffers
[
i
]
=
(
ST_buffer
*
)
mem_start
;
#ifdef DEBUG
#ifdef DEBUG
printk
(
"st: Buffer address: %p
\n
"
,
st_buffers
[
i
]);
/* printk("st: Buffer address: %p\n", st_buffers[i]); */
#endif
#endif
mem_start
+=
sizeof
(
ST_buffer
)
-
1
+
ST_BUFFER_BLOCKS
*
ST_BLOCK_SIZE
;
mem_start
+=
sizeof
(
ST_buffer
)
-
1
+
st_buffer_size
;
st_buffers
[
i
]
->
mt_status
=
(
struct
mtget
*
)
mem_start
;
mem_start
+=
sizeof
(
struct
mtget
);
st_buffers
[
i
]
->
in_use
=
0
;
st_buffers
[
i
]
->
in_use
=
0
;
st_buffers
[
i
]
->
writing
=
0
;
st_buffers
[
i
]
->
writing
=
0
;
/* "generic" status */
memset
((
void
*
)
st_buffers
[
i
]
->
mt_status
,
0
,
sizeof
(
struct
mtget
));
st_buffers
[
i
]
->
mt_status
->
mt_type
=
MT_ISSCSI1
;
}
}
return
mem_start
;
return
mem_start
;
...
...
drivers/scsi/st.h
View file @
16119ae5
...
@@ -11,7 +11,6 @@
...
@@ -11,7 +11,6 @@
typedef
struct
{
typedef
struct
{
int
in_use
;
int
in_use
;
struct
mtget
*
mt_status
;
int
buffer_size
;
int
buffer_size
;
int
buffer_blocks
;
int
buffer_blocks
;
int
buffer_bytes
;
int
buffer_bytes
;
...
@@ -33,12 +32,18 @@ typedef struct {
...
@@ -33,12 +32,18 @@ typedef struct {
unsigned
in_use
:
1
;
unsigned
in_use
:
1
;
unsigned
eof_hit
:
1
;
unsigned
eof_hit
:
1
;
unsigned
drv_buffer
:
3
;
unsigned
drv_buffer
:
3
;
unsigned
do_buffer_writes
:
1
;
unsigned
do_async_writes
:
1
;
unsigned
do_read_ahead
:
1
;
unsigned
char
density
;
unsigned
char
density
;
ST_buffer
*
buffer
;
ST_buffer
*
buffer
;
int
block_size
;
int
block_size
;
int
min_block
;
int
min_block
;
int
max_block
;
int
max_block
;
int
write_threshold
;
int
recover_count
;
int
recover_count
;
int
drv_block
;
/* The block where the drive head is */
struct
mtget
*
mt_status
;
Scsi_Cmnd
SCpnt
;
Scsi_Cmnd
SCpnt
;
}
Scsi_Tape
;
}
Scsi_Tape
;
...
...
drivers/scsi/wd7000.c
View file @
16119ae5
/* $Id:
wd7000.c,v 1.2 1994/01/15 06:02:32 drew Exp
$
/* $Id: $
* linux/
kernel
/wd7000.c
* linux/
drivers/scsi
/wd7000.c
*
*
* Copyright (C) 1992 Thomas Wuensche
* Copyright (C) 1992 Thomas Wuensche
* closely related to the aha1542 driver from Tommy Thorn
* closely related to the aha1542 driver from Tommy Thorn
...
@@ -9,6 +9,95 @@
...
@@ -9,6 +9,95 @@
* accomodate Eric Youngdale's modifications to scsi.c. Nov 1992.
* accomodate Eric Youngdale's modifications to scsi.c. Nov 1992.
*
*
* Additional changes to support scatter/gather. Dec. 1992. tw/jb
* Additional changes to support scatter/gather. Dec. 1992. tw/jb
*
* No longer tries to reset SCSI bus at boot (it wasn't working anyway).
* Rewritten to support multiple host adapters.
* Miscellaneous cleanup.
* So far, still doesn't do reset or abort correctly, since I have no idea
* how to do them with this board (8^(. Jan 1994 jb
*
* This driver now supports both of the two standard configurations (per
* the 3.36 Owner's Manual, my latest reference) by the same method as
* before; namely, by looking for a BIOS signature. Thus, the location of
* the BIOS signature determines the board configuration. Until I have
* time to do something more flexible, users should stick to one of the
* following:
*
* Standard configuration for single-adapter systems:
* - BIOS at CE00h
* - I/O base address 350h
* - IRQ level 15
* - DMA channel 6
* Standard configuration for a second adapter in a system:
* - BIOS at C800h
* - I/O base address 330h
* - IRQ level 11
* - DMA channel 5
*
* Anyone who can recompile the kernel is welcome to add others as need
* arises, but unpredictable results may occur if there are conflicts.
* In any event, if there are multiple adapters in a system, they MUST
* use different I/O bases, IRQ levels, and DMA channels, since they will be
* indistinguishable (and in direct conflict) otherwise.
*
* As a point of information, the NO_OP command toggles the CMD_RDY bit
* of the status port, and this fact could be used as a test for the I/O
* base address (or more generally, board detection). There is an interrupt
* status port, so IRQ probing could also be done. I suppose the full
* DMA diagnostic could be used to detect the DMA channel being used. I
* haven't done any of this, though, because I think there's too much of
* a chance that such explorations could be destructive, if some other
* board's resources are used inadvertently. So, call me a wimp, but I
* don't want to try it. The only kind of exploration I trust is memory
* exploration, since it's more certain that reading memory won't be
* destructive.
*
* More to my liking would be a LILO boot command line specification, such
* as is used by the aha152x driver (and possibly others). I'll look into
* it, as I have time...
*
* I get mail occasionally from people who either are using or are
* considering using a WD7000 with Linux. There is a variety of
* nomenclature describing WD7000's. To the best of my knowledge, the
* following is a brief summary (from an old WD doc - I don't work for
* them or anything like that):
*
* WD7000-FASST2: This is a WD7000 board with the real-mode SST ROM BIOS
* installed. Last I heard, the BIOS was actually done by Columbia
* Data Products. The BIOS is only used by this driver (and thus
* by Linux) to identify the board; none of it can be executed under
* Linux.
*
* WD7000-ASC: This is the original adapter board, with or without BIOS.
* The board uses a WD33C93 or WD33C93A SBIC, which in turn is
* controlled by an onboard Z80 processor. The board interface
* visible to the host CPU is defined effectively by the Z80's
* firmware, and it is this firmware's revision level that is
* determined and reported by this driver. (The version of the
* on-board BIOS is of no interest whatsoever.) The host CPU has
* no access to the SBIC; hence the fact that it is a WD33C93 is
* also of no interest to this driver.
*
* WD7000-AX:
* WD7000-MX:
* WD7000-EX: These are newer versions of the WD7000-ASC. The -ASC is
* largely built from discrete components; these boards use more
* integration. The -AX is an ISA bus board (like the -ASC),
* the -MX is an MCA (i.e., PS/2) bus board), and the -EX is an
* EISA bus board.
*
* At the time of my documentation, the -?X boards were "future" products,
* and were not yet available. However, I vaguely recall that Thomas
* Wuensche had an -AX, so I believe at least it is supported by this
* driver. I have no personal knowledge of either -MX or -EX boards.
*
* P.S. Just recently, I've discovered (directly from WD and Future
* Domain) that all but the WD7000-EX have been out of production for
* two years now. FD has production rights to the 7000-EX, and are
* producing it under a new name, and with a new BIOS. If anyone has
* one of the FD boards, it would be nice to come up with a signature
* for it.
* J.B. Jan 1994.
*/
*/
#include <stdarg.h>
#include <stdarg.h>
...
@@ -17,6 +106,7 @@
...
@@ -17,6 +106,7 @@
#include <linux/types.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/malloc.h>
#include <asm/system.h>
#include <asm/system.h>
#include <asm/dma.h>
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/io.h>
...
@@ -26,17 +116,179 @@
...
@@ -26,17 +116,179 @@
#include "scsi.h"
#include "scsi.h"
#include "hosts.h"
#include "hosts.h"
/* #define DEBUG */
#define ANY2SCSI_INLINE
/* undef this to use old macros */
#undef DEBUG
#include "wd7000.h"
#include "wd7000.h"
#ifdef DEBUG
/*
#define DEB(x) x
* Mailbox structure sizes.
#else
* I prefer to keep the number of ICMBs much larger than the number of
#define DEB(x)
* OGMBs. OGMBs are used very quickly by the driver to start one or
#endif
* more commands, while ICMBs are used by the host adapter per command.
*/
#define OGMB_CNT 16
#define ICMB_CNT 32
/*
* Scb's are shared by all active adapters. So, if they all become busy,
* callers may be made to wait in alloc_scbs for them to free. That can
* be avoided by setting MAX_SCBS to NUM_CONFIG * WD7000_Q. If you'd
* rather conserve memory, use a smaller number (> 0, of course) - things
* will should still work OK.
*/
#define MAX_SCBS 32
/*
* WD7000-specific mailbox structure
*
*/
typedef
volatile
struct
mailbox
{
unchar
status
;
unchar
scbptr
[
3
];
/* SCSI-style - MSB first (big endian) */
}
Mailbox
;
/*
* This structure should contain all per-adapter global data. I.e., any
* new global per-adapter data should put in here.
*
*/
typedef
struct
adapter
{
int
num
;
/* Index into Scsi_hosts array */
struct
Scsi_Host
*
sh
;
/* Pointer to Scsi_Host structure */
int
iobase
;
/* This adapter's I/O base address */
int
irq
;
/* This adapter's IRQ level */
int
dma
;
/* This adapter's DMA channel */
struct
{
/* This adapter's mailboxes */
Mailbox
ogmb
[
OGMB_CNT
];
/* Outgoing mailboxes */
Mailbox
icmb
[
ICMB_CNT
];
/* Incoming mailboxes */
}
mb
;
int
next_ogmb
;
/* to reduce contention at mailboxes */
unchar
control
;
/* shadows CONTROL port value */
unchar
rev1
,
rev2
;
/* filled in by wd7000_revision */
}
Adapter
;
/*
* The following is set up by wd7000_detect, and used thereafter by
* wd7000_intr_handle to map the irq level to the corresponding Adapter.
* Note that if request_irq instead of irqaction to allocate the IRQ,
* or if SA_INTERRUPT is not used, wd7000_intr_handle must be changed
* to pick up the IRQ level correctly.
*/
Adapter
*
irq2host
[
16
]
=
{
NULL
};
/* Possible IRQs are 0-15 */
/*
* Standard Adapter Configurations - used by wd7000_detect
*/
typedef
struct
{
const
void
*
bios
;
/* (linear) base address for ROM BIOS */
int
iobase
;
/* I/O ports base address */
int
irq
;
/* IRQ level */
int
dma
;
/* DMA channel */
}
Config
;
static
const
Config
configs
[]
=
{
{(
void
*
)
0xce000
,
0x350
,
15
,
6
},
/* defaults for single adapter */
{(
void
*
)
0xc8000
,
0x330
,
11
,
5
},
/* defaults for second adapter */
{(
void
*
)
0xd8000
,
0x350
,
15
,
6
},
/* Arghhh.... who added this ? */
};
#define NUM_CONFIGS (sizeof(configs)/sizeof(Config))
/*
* The following list defines strings to look for in the BIOS that identify
* it as the WD7000-FASST2 SST BIOS. I suspect that something should be
* added for the Future Domain version.
*/
typedef
struct
signature
{
void
*
sig
;
/* String to look for */
unsigned
ofs
;
/* offset from BIOS base address */
unsigned
len
;
/* length of string */
}
Signature
;
static
const
Signature
signatures
[]
=
{
{
"SSTBIOS"
,
0x0000d
,
7
}
/* "SSTBIOS" @ offset 0x0000d */
};
#define NUM_SIGNATURES (sizeof(signatures)/sizeof(Signature))
/*
* I/O Port Offsets and Bit Definitions
* 4 addresses are used. Those not defined here are reserved.
*/
#define ASC_STAT 0
/* Status, Read */
#define ASC_COMMAND 0
/* Command, Write */
#define ASC_INTR_STAT 1
/* Interrupt Status, Read */
#define ASC_INTR_ACK 1
/* Acknowledge, Write */
#define ASC_CONTROL 2
/* Control, Write */
/* ASC Status Port
*/
#define INT_IM 0x80
/* Interrupt Image Flag */
#define CMD_RDY 0x40
/* Command Port Ready */
#define CMD_REJ 0x20
/* Command Port Byte Rejected */
#define ASC_INIT 0x10
/* ASC Initialized Flag */
#define ASC_STATMASK 0xf0
/* The lower 4 Bytes are reserved */
/* COMMAND opcodes
*
* Unfortunately, I have no idea how to properly use some of these commands,
* as the OEM manual does not make it clear. I have not been able to use
* enable/disable unsolicited interrupts or the reset commands with any
* discernable effect whatsoever. I think they may be related to certain
* ICB commands, but again, the OEM manual doesn't make that clear.
*/
#define NO_OP 0
/* NO-OP toggles CMD_RDY bit in ASC_STAT */
#define INITIALIZATION 1
/* initialization (10 bytes) */
#define DISABLE_UNS_INTR 2
/* disable unsolicited interrupts */
#define ENABLE_UNS_INTR 3
/* enable unsolicited interrupts */
#define INTR_ON_FREE_OGMB 4
/* interrupt on free OGMB */
#define SOFT_RESET 5
/* SCSI bus soft reset */
#define HARD_RESET_ACK 6
/* SCSI bus hard reset acknowledge */
#define START_OGMB 0x80
/* start command in OGMB (n) */
#define SCAN_OGMBS 0xc0
/* start multiple commands, signature (n) */
/* where (n) = lower 6 bits */
/* For INITIALIZATION:
*/
typedef
struct
initCmd
{
unchar
op
;
/* command opcode (= 1) */
unchar
ID
;
/* Adapter's SCSI ID */
unchar
bus_on
;
/* Bus on time, x 125ns (see below) */
unchar
bus_off
;
/* Bus off time, "" "" */
unchar
rsvd
;
/* Reserved */
unchar
mailboxes
[
3
];
/* Address of Mailboxes, MSB first */
unchar
ogmbs
;
/* Number of outgoing MBs, max 64, 0,1 = 1 */
unchar
icmbs
;
/* Number of incoming MBs, "" "" */
}
InitCmd
;
#define BUS_ON 64
/* x 125ns = 8000ns (BIOS default) */
#define BUS_OFF 15
/* x 125ns = 1875ns (BIOS default) */
/* Interrupt Status Port - also returns diagnostic codes at ASC reset
*
* if msb is zero, the lower bits are diagnostic status
* Diagnostics:
* 01 No diagnostic error occurred
* 02 RAM failure
* 03 FIFO R/W failed
* 04 SBIC register read/write failed
* 05 Initialization D-FF failed
* 06 Host IRQ D-FF failed
* 07 ROM checksum error
* Interrupt status (bitwise):
* 10NNNNNN outgoing mailbox NNNNNN is free
* 11NNNNNN incoming mailbox NNNNNN needs service
*/
#define MB_INTR 0xC0
/* Mailbox Service possible/required */
#define IMB_INTR 0x40
/* 1 Incoming / 0 Outgoing */
#define MB_MASK 0x3f
/* mask for mailbox number */
/* CONTROL port bits
*/
#define INT_EN 0x08
/* Interrupt Enable */
#define DMA_EN 0x04
/* DMA Enable */
#define SCSI_RES 0x02
/* SCSI Reset */
#define ASC_RES 0x01
/* ASC Reset */
/*
/*
Driver data structures:
Driver data structures:
...
@@ -63,103 +315,327 @@
...
@@ -63,103 +315,327 @@
indices need not be involved.
indices need not be involved.
*/
*/
static
struct
{
/*
struct
wd_mailbox
ogmb
[
OGMB_CNT
];
* WD7000-specific scatter/gather element structure
struct
wd_mailbox
icmb
[
ICMB_CNT
];
*/
}
mb
;
typedef
struct
sgb
{
static
int
next_ogmb
=
0
;
/* to reduce contention at mailboxes */
unchar
len
[
3
];
unchar
ptr
[
3
];
/* Also SCSI-style - MSB first */
}
Sgb
;
typedef
struct
scb
{
/* Command Control Block 5.4.1 */
unchar
op
;
/* Command Control Block Operation Code */
unchar
idlun
;
/* op=0,2:Target Id, op=1:Initiator Id */
/* Outbound data transfer, length is checked*/
/* Inbound data transfer, length is checked */
/* Logical Unit Number */
unchar
cdb
[
12
];
/* SCSI Command Block */
volatile
unchar
status
;
/* SCSI Return Status */
volatile
unchar
vue
;
/* Vendor Unique Error Code */
unchar
maxlen
[
3
];
/* Maximum Data Transfer Length */
unchar
dataptr
[
3
];
/* SCSI Data Block Pointer */
unchar
linkptr
[
3
];
/* Next Command Link Pointer */
unchar
direc
;
/* Transfer Direction */
unchar
reserved2
[
6
];
/* SCSI Command Descriptor Block */
/* end of hardware SCB */
Scsi_Cmnd
*
SCpnt
;
/* Scsi_Cmnd using this SCB */
Sgb
sgb
[
WD7000_SG
];
/* Scatter/gather list for this SCB */
Adapter
*
host
;
/* host adapter */
struct
scb
*
next
;
/* for lists of scbs */
}
Scb
;
/*
* This driver is written to allow host-only commands to be executed.
* These use a 16-byte block called an ICB. The format is extended by the
* driver to 18 bytes, to support the status returned in the ICMB and
* an execution phase code.
*
* There are other formats besides these; these are the ones I've tried
* to use. Formats for some of the defined ICB opcodes are not defined
* (notably, get/set unsolicited interrupt status) in my copy of the OEM
* manual, and others are ambiguous/hard to follow.
*/
#define ICB_OP_MASK 0x80
/* distinguishes scbs from icbs */
#define ICB_OP_OPEN_RBUF 0x80
/* open receive buffer */
#define ICB_OP_RECV_CMD 0x81
/* receive command from initiator */
#define ICB_OP_RECV_DATA 0x82
/* receive data from initiator */
#define ICB_OP_RECV_SDATA 0x83
/* receive data with status from init. */
#define ICB_OP_SEND_DATA 0x84
/* send data with status to initiator */
#define ICB_OP_SEND_STAT 0x86
/* send command status to initiator */
/* 0x87 is reserved */
#define ICB_OP_READ_INIT 0x88
/* read initialization bytes */
#define ICB_OP_READ_ID 0x89
/* read adapter's SCSI ID */
#define ICB_OP_SET_UMASK 0x8A
/* set unsolicited interrupt mask */
#define ICB_OP_GET_UMASK 0x8B
/* read unsolicited interrupt mask */
#define ICB_OP_GET_REVISION 0x8C
/* read firmware revision level */
#define ICB_OP_DIAGNOSTICS 0x8D
/* execute diagnostics */
#define ICB_OP_SET_EPARMS 0x8E
/* set execution parameters */
#define ICB_OP_GET_EPARMS 0x8F
/* read execution parameters */
typedef
struct
icbRecvCmd
{
unchar
op
;
unchar
IDlun
;
/* Initiator SCSI ID/lun */
unchar
len
[
3
];
/* command buffer length */
unchar
ptr
[
3
];
/* command buffer address */
unchar
rsvd
[
7
];
/* reserved */
volatile
unchar
vue
;
/* vendor-unique error code */
volatile
unchar
status
;
/* returned (icmb) status */
volatile
unchar
phase
;
/* used by interrupt handler */
}
IcbRecvCmd
;
typedef
struct
icbSendStat
{
unchar
op
;
unchar
IDlun
;
/* Target SCSI ID/lun */
unchar
stat
;
/* (outgoing) completion status byte 1 */
unchar
rsvd
[
12
];
/* reserved */
volatile
unchar
vue
;
/* vendor-unique error code */
volatile
unchar
status
;
/* returned (icmb) status */
volatile
unchar
phase
;
/* used by interrupt handler */
}
IcbSendStat
;
typedef
struct
icbRevLvl
{
unchar
op
;
volatile
unchar
primary
;
/* primary revision level (returned) */
volatile
unchar
secondary
;
/* secondary revision level (returned) */
unchar
rsvd
[
12
];
/* reserved */
volatile
unchar
vue
;
/* vendor-unique error code */
volatile
unchar
status
;
/* returned (icmb) status */
volatile
unchar
phase
;
/* used by interrupt handler */
}
IcbRevLvl
;
typedef
struct
icbUnsMask
{
/* I'm totally guessing here */
unchar
op
;
volatile
unchar
mask
[
14
];
/* mask bits */
#ifdef 0
unchar
rsvd
[
12
];
/* reserved */
#endif
volatile
unchar
vue
;
/* vendor-unique error code */
volatile
unchar
status
;
/* returned (icmb) status */
volatile
unchar
phase
;
/* used by interrupt handler */
}
IcbUnsMask
;
typedef
struct
icbDiag
{
unchar
op
;
unchar
type
;
/* diagnostics type code (0-3) */
unchar
len
[
3
];
/* buffer length */
unchar
ptr
[
3
];
/* buffer address */
unchar
rsvd
[
7
];
/* reserved */
volatile
unchar
vue
;
/* vendor-unique error code */
volatile
unchar
status
;
/* returned (icmb) status */
volatile
unchar
phase
;
/* used by interrupt handler */
}
IcbDiag
;
#define ICB_DIAG_POWERUP 0
/* Power-up diags only */
#define ICB_DIAG_WALKING 1
/* walking 1's pattern */
#define ICB_DIAG_DMA 2
/* DMA - system memory diags */
#define ICB_DIAG_FULL 3
/* do both 1 & 2 */
typedef
struct
icbParms
{
unchar
op
;
unchar
rsvd1
;
/* reserved */
unchar
len
[
3
];
/* parms buffer length */
unchar
ptr
[
3
];
/* parms buffer address */
unchar
idx
[
2
];
/* index (MSB-LSB) */
unchar
rsvd2
[
5
];
/* reserved */
volatile
unchar
vue
;
/* vendor-unique error code */
volatile
unchar
status
;
/* returned (icmb) status */
volatile
unchar
phase
;
/* used by interrupt handler */
}
IcbParms
;
typedef
struct
icbAny
{
unchar
op
;
unchar
data
[
14
];
/* format-specific data */
volatile
unchar
vue
;
/* vendor-unique error code */
volatile
unchar
status
;
/* returned (icmb) status */
volatile
unchar
phase
;
/* used by interrupt handler */
}
IcbAny
;
typedef
union
icb
{
unchar
op
;
/* ICB opcode */
IcbRecvCmd
recv_cmd
;
/* format for receive command */
IcbSendStat
send_stat
;
/* format for send status */
IcbRevLvl
rev_lvl
;
/* format for get revision level */
IcbDiag
diag
;
/* format for execute diagnostics */
IcbParms
eparms
;
/* format for get/set exec parms */
IcbAny
icb
;
/* generic format */
unchar
data
[
18
];
}
Icb
;
/*
* Driver SCB structure pool.
*
* The SCBs declared here are shared by all host adapters; hence, this
* structure is not part of the Adapter structure.
*/
static
Scb
scbs
[
MAX_SCBS
];
static
Scb
scbs
[
MAX_SCBS
];
static
Scb
*
scbfree
=
NULL
;
static
Scb
*
scbfree
=
NULL
;
/* free list */
static
int
freescbs
=
MAX_SCBS
;
/* free list counter */
/*
* END of data/declarations - code follows.
*/
#ifdef ANY2SCSI_INLINE
/*
Since they're used a lot, I've redone the following from the macros
formerly in wd7000.h, hopefully to speed them up by getting rid of
all the shifting (it may not matter; GCC might have done as well anyway).
static
int
wd7000_host
=
0
;
xany2scsi and xscsi2int were not being used, and are no longer defined.
static
unchar
controlstat
=
0
;
(They were simply 4-byte versions of these routines).
*/
typedef
union
{
/* let's cheat... */
int
i
;
unchar
u
[
sizeof
(
int
)];
/* the sizeof(int) makes it more portable */
}
i_u
;
static
unchar
rev_1
=
0
,
rev_2
=
0
;
/* filled in by wd7000_revision */
#define wd7000_intr_ack() outb(0,INTR_ACK)
static
inline
void
any2scsi
(
unchar
*
scsi
,
int
any
)
{
*
scsi
++
=
((
i_u
)
any
).
u
[
2
];
*
scsi
++
=
((
i_u
)
any
).
u
[
1
];
*
scsi
++
=
((
i_u
)
any
).
u
[
0
];
}
#define WAITnexttimeout 3000000
static
inline
int
scsi2int
(
unchar
*
scsi
)
{
i_u
result
;
result
.
i
=
0
;
/* clears unused bytes */
*
(
result
.
u
+
2
)
=
*
scsi
++
;
*
(
result
.
u
+
1
)
=
*
scsi
++
;
*
(
result
.
u
)
=
*
scsi
++
;
return
result
.
i
;
}
#else
/*
These are the old ones - I've just moved them here...
*/
#undef any2scsi
#define any2scsi(up, p) \
(up)[0] = (((unsigned long)(p)) >> 16); \
(up)[1] = ((unsigned long)(p)) >> 8; \
(up)[2] = ((unsigned long)(p));
#undef scsi2int
#define scsi2int(up) ( (((unsigned long)*(up)) << 16) + \
(((unsigned long)(up)[1]) << 8) + ((unsigned long)(up)[2]) )
#endif
static
inline
void
wd7000_enable_intr
(
void
)
static
inline
void
wd7000_enable_intr
(
Adapter
*
host
)
{
{
controlstat
|=
INT_EN
;
host
->
control
|=
INT_EN
;
outb
(
controlstat
,
CONTROL
);
outb
(
host
->
control
,
host
->
iobase
+
ASC_
CONTROL
);
}
}
static
inline
void
wd7000_enable_dma
(
void
)
static
inline
void
wd7000_enable_dma
(
Adapter
*
host
)
{
{
controlstat
|=
DMA_EN
;
host
->
control
|=
DMA_EN
;
outb
(
controlstat
,
CONTROL
);
outb
(
host
->
control
,
host
->
iobase
+
ASC_
CONTROL
);
set_dma_mode
(
DMA_CH
,
DMA_MODE_CASCADE
);
set_dma_mode
(
host
->
dma
,
DMA_MODE_CASCADE
);
enable_dma
(
DMA_CH
);
enable_dma
(
host
->
dma
);
}
}
#define WAITnexttimeout 200
/* 2 seconds */
#define WAIT(port, mask, allof, noneof) \
#define WAIT(port, mask, allof, noneof) \
{ register
WAITbits;
\
{ register
volatile unsigned WAITbits;
\
register
WAITtimeout = WAITnexttimeout;
\
register
unsigned long WAITtimeout = jiffies + WAITnexttimeout;
\
while (1) { \
while (1) { \
WAITbits = inb(port) & (mask); \
WAITbits = inb(port) & (mask); \
if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \
if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \
break; \
break; \
if (
--WAITtimeout == 0) goto fail;
\
if (
jiffies > WAITtimeout) goto fail;
\
} \
} \
}
}
static
inline
void
delay
(
unsigned
how_long
)
static
inline
void
delay
(
unsigned
how_long
)
{
{
unsigned
long
time
=
jiffies
+
how_long
;
register
unsigned
long
time
=
jiffies
+
how_long
;
while
(
jiffies
<
time
);
while
(
jiffies
<
time
);
}
}
static
inline
int
command_out
(
unchar
*
cmdp
,
int
len
)
static
inline
int
command_out
(
Adapter
*
host
,
unchar
*
cmd
,
int
len
)
{
{
if
(
len
==
1
)
{
WAIT
(
host
->
iobase
+
ASC_STAT
,
ASC_STATMASK
,
CMD_RDY
,
0
);
while
(
1
==
1
){
WAIT
(
ASC_STAT
,
STATMASK
,
CMD_RDY
,
0
);
cli
();
if
(
!
(
inb
(
ASC_STAT
)
&
CMD_RDY
))
{
sti
();
continue
;}
outb
(
*
cmdp
,
COMMAND
);
sti
();
return
1
;
}
}
else
{
cli
();
while
(
len
--
)
{
while
(
len
--
)
{
WAIT
(
ASC_STAT
,
STATMASK
,
CMD_RDY
,
0
);
do
{
outb
(
*
cmdp
++
,
COMMAND
);
outb
(
*
cmd
,
host
->
iobase
+
ASC_COMMAND
);
WAIT
(
host
->
iobase
+
ASC_STAT
,
ASC_STATMASK
,
CMD_RDY
,
0
);
}
while
(
inb
(
host
->
iobase
+
ASC_STAT
)
&
CMD_REJ
);
cmd
++
;
}
}
sti
();
}
return
1
;
return
1
;
fail:
fail:
sti
();
printk
(
"wd7000 command_out: WAIT failed(%d)
\n
"
,
len
+
1
);
printk
(
"wd7000_out WAIT failed(%d): "
,
len
+
1
);
return
0
;
return
0
;
}
}
static
inline
Scb
*
alloc_scb
(
void
)
/*
* This version of alloc_scbs is in preparation for supporting multiple
* commands per lun and command chaining, by queueing pending commands.
* We will need to allocate Scbs in blocks since they will wait to be
* executed so there is the possibility of deadlock otherwise.
* Also, to keep larger requests from being starved by smaller requests,
* we limit access to this routine with an internal busy flag, so that
* the satisfiability of a request is not dependent on the size of the
* request.
*/
static
inline
Scb
*
alloc_scbs
(
int
needed
)
{
{
Scb
*
scb
;
register
Scb
*
scb
,
*
p
;
unsigned
long
flags
;
register
unsigned
long
flags
;
register
unsigned
long
timeout
=
jiffies
+
WAITnexttimeout
;
register
unsigned
long
now
;
static
int
busy
=
0
;
int
i
;
if
(
needed
<=
0
)
return
NULL
;
/* sanity check */
save_flags
(
flags
);
save_flags
(
flags
);
cli
();
cli
();
while
(
busy
)
{
/* someone else is allocating */
if
(
scbfree
==
NULL
)
{
sti
();
panic
(
"wd7000: can't allocate free SCB.
\n
"
);
now
=
jiffies
;
while
(
jiffies
==
now
)
/* wait a jiffy */
;
restore_flags
(
flags
);
cli
();
return
NULL
;
}
busy
=
1
;
/* not busy now; it's our turn */
while
(
freescbs
<
needed
)
{
timeout
=
jiffies
+
WAITnexttimeout
;
do
{
sti
();
now
=
jiffies
;
while
(
jiffies
==
now
)
/* wait a jiffy */
;
cli
();
}
while
(
freescbs
<
needed
&&
jiffies
<=
timeout
);
/*
* If we get here with enough free Scbs, we can take them.
* Otherwise, we timed out and didn't get enough.
*/
if
(
freescbs
<
needed
)
{
busy
=
0
;
panic
(
"wd7000: can't get enough free SCBs.
\n
"
);
restore_flags
(
flags
);
return
NULL
;
}
}
}
scb
=
scbfree
;
scbfree
=
scb
->
next
;
scb
=
scbfree
;
freescbs
-=
needed
;
memset
(
scb
,
0
,
sizeof
(
Scb
));
scb
->
next
=
NULL
;
for
(
i
=
0
;
i
<
needed
;
i
++
)
{
p
=
scbfree
;
scbfree
=
p
->
next
;
}
p
->
next
=
NULL
;
busy
=
0
;
/* we're done */
restore_flags
(
flags
);
restore_flags
(
flags
);
...
@@ -169,13 +645,14 @@ static inline Scb *alloc_scb(void)
...
@@ -169,13 +645,14 @@ static inline Scb *alloc_scb(void)
static
inline
void
free_scb
(
Scb
*
scb
)
static
inline
void
free_scb
(
Scb
*
scb
)
{
{
unsigned
long
flags
;
register
unsigned
long
flags
;
save_flags
(
flags
);
save_flags
(
flags
);
cli
();
cli
();
memset
(
scb
,
0
,
sizeof
(
Scb
));
memset
(
scb
,
0
,
sizeof
(
Scb
));
scb
->
next
=
scbfree
;
scbfree
=
scb
;
scb
->
next
=
scbfree
;
scbfree
=
scb
;
freescbs
++
;
restore_flags
(
flags
);
restore_flags
(
flags
);
}
}
...
@@ -190,62 +667,74 @@ static inline void init_scbs(void)
...
@@ -190,62 +667,74 @@ static inline void init_scbs(void)
cli
();
cli
();
scbfree
=
&
(
scbs
[
0
]);
scbfree
=
&
(
scbs
[
0
]);
for
(
i
=
0
;
i
<
MAX_SCBS
-
1
;
i
++
)
scbs
[
i
].
next
=
&
(
scbs
[
i
+
1
]);
memset
(
scbs
,
0
,
sizeof
(
scbs
));
for
(
i
=
0
;
i
<
MAX_SCBS
-
1
;
i
++
)
{
scbs
[
i
].
next
=
&
(
scbs
[
i
+
1
]);
scbs
[
i
].
SCpnt
=
NULL
;
}
scbs
[
MAX_SCBS
-
1
].
next
=
NULL
;
scbs
[
MAX_SCBS
-
1
].
next
=
NULL
;
scbs
[
MAX_SCBS
-
1
].
SCpnt
=
NULL
;
restore_flags
(
flags
);
restore_flags
(
flags
);
}
}
static
int
mail_out
(
Scb
*
scbptr
)
static
int
mail_out
(
Adapter
*
host
,
Scb
*
scbptr
)
/*
/*
* Note: this can also be used for ICBs; just cast to the parm type.
* Note: this can also be used for ICBs; just cast to the parm type.
*/
*/
{
{
int
i
,
ogmb
;
register
int
i
,
ogmb
;
unsigned
char
start_cmd
;
register
unsigned
long
flags
;
unsigned
long
flags
;
unchar
start_ogmb
;
Mailbox
*
ogmbs
=
host
->
mb
.
ogmb
;
DEB
(
printk
(
"wd7000_scb_out: %06x"
);)
int
*
next_ogmb
=
&
(
host
->
next_ogmb
);
#ifdef DEBUG
printk
(
"wd7000 mail_out: %06x"
,(
unsigned
int
)
scbptr
);
#endif
/* We first look for a free outgoing mailbox */
/* We first look for a free outgoing mailbox */
save_flags
(
flags
);
save_flags
(
flags
);
cli
();
cli
();
ogmb
=
next_ogmb
;
ogmb
=
*
next_ogmb
;
for
(
i
=
0
;
i
<
OGMB_CNT
;
i
++
)
{
for
(
i
=
0
;
i
<
OGMB_CNT
;
i
++
)
{
if
(
mb
.
ogmb
[
ogmb
].
status
==
0
)
{
if
(
ogmbs
[
ogmb
].
status
==
0
)
{
DEB
(
printk
(
" using OGMB %x"
,
ogmb
));
#ifdef DEBUG
mb
.
ogmb
[
ogmb
].
status
=
1
;
printk
(
" using OGMB %x"
,
ogmb
);
any2scsi
(
mb
.
ogmb
[
ogmb
].
scbptr
,
scbptr
);
#endif
ogmbs
[
ogmb
].
status
=
1
;
any2scsi
((
unchar
*
)
ogmbs
[
ogmb
].
scbptr
,
(
int
)
scbptr
);
next_ogmb
=
(
ogmb
+
1
)
%
OGMB_CNT
;
*
next_ogmb
=
(
ogmb
+
1
)
%
OGMB_CNT
;
break
;
break
;
}
else
}
else
ogmb
=
(
++
ogmb
)
%
OGMB_CNT
;
ogmb
=
(
++
ogmb
)
%
OGMB_CNT
;
}
}
restore_flags
(
flags
);
restore_flags
(
flags
);
DEB
(
printk
(
", scb is %x"
,
scbptr
);)
#ifdef DEBUG
printk
(
", scb is %x"
,(
unsigned
int
)
scbptr
);
#endif
if
(
i
>=
OGMB_CNT
)
{
if
(
i
>=
OGMB_CNT
)
{
DEB
(
printk
(
", no free OGMBs.
\n
"
);)
/*
/* Alternatively, issue "interrupt on free OGMB", and sleep... */
* Alternatively, we might issue the "interrupt on free OGMB",
return
0
;
* and sleep, but it must be ensured that it isn't the init
* task running. Instead, this version assumes that the caller
* will be persistent, and try again. Since it's the adapter
* that marks OGMB's free, waiting even with interrupts off
* should work, since they are freed very quickly in most cases.
*/
#ifdef DEBUG
printk
(
", no free OGMBs.
\n
"
);
#endif
return
0
;
}
}
start_cmd
=
START_OGMB
|
ogmb
;
wd7000_enable_intr
(
host
);
wd7000_enable_intr
();
do
{
command_out
(
&
start_cmd
,
1
);
WAIT
(
ASC_STAT
,
STATMASK
,
CMD_RDY
,
0
);
}
while
(
inb
(
ASC_STAT
)
&
CMD_REJ
);
DEB
(
printk
(
", awaiting interrupt.
\n
"
);)
start_ogmb
=
START_OGMB
|
ogmb
;
command_out
(
host
,
&
start_ogmb
,
1
);
#ifdef DEBUG
printk
(
", awaiting interrupt.
\n
"
);
#endif
return
1
;
return
1
;
fail:
DEB
(
printk
(
", WAIT timed out.
\n
"
);)
return
0
;
}
}
...
@@ -300,135 +789,159 @@ int make_code(unsigned hosterr, unsigned scsierr)
...
@@ -300,135 +789,159 @@ int make_code(unsigned hosterr, unsigned scsierr)
static
void
wd7000_scsi_done
(
Scsi_Cmnd
*
SCpnt
)
static
void
wd7000_scsi_done
(
Scsi_Cmnd
*
SCpnt
)
{
{
DEB
(
printk
(
"wd7000_scsi_done: %06x
\n
"
,
SCpnt
);)
#ifdef DEBUG
printk
(
"wd7000_scsi_done: %06x
\n
"
,(
unsigned
int
)
SCpnt
);
#endif
SCpnt
->
SCp
.
phase
=
0
;
SCpnt
->
SCp
.
phase
=
0
;
}
}
#define wd7000_intr_ack(host) outb(0,host->iobase+ASC_INTR_ACK)
void
wd7000_intr_handle
(
int
irq
)
void
wd7000_intr_handle
(
int
irq
)
{
{
int
flag
,
icmb
,
errstatus
,
icmb_status
;
#ifdef 0
int
host_error
,
scsi_error
;
/*
Scb
*
scb
;
/* for SCSI commands */
* Use irqp as the parm, and the following declaration, if request_irq
unchar
*
icb
;
/* for host commands */
* is used or if SA_INTERRUPT is not used.
Scsi_Cmnd
*
SCpnt
;
*/
register
int
irq
=
*
(((
int
*
)
irqp
)
-
2
);
flag
=
inb
(
INTR_STAT
);
#endif
DEB
(
printk
(
"wd7000_intr_handle: intr stat = %02x"
,
flag
);)
register
int
flag
,
icmb
,
errstatus
,
icmb_status
;
register
int
host_error
,
scsi_error
;
if
(
!
(
inb
(
ASC_STAT
)
&
0x80
)){
register
Scb
*
scb
;
/* for SCSI commands */
DEB
(
printk
(
"
\n
wd7000_intr_handle: phantom interrupt...
\n
"
);)
register
IcbAny
*
icb
;
/* for host commands */
wd7000_intr_ack
();
register
Scsi_Cmnd
*
SCpnt
;
return
;
Adapter
*
host
=
irq2host
[
irq
];
/* This MUST be set!!! */
}
Mailbox
*
icmbs
=
host
->
mb
.
icmb
;
/* check for an incoming mailbox */
if
((
flag
&
0x40
)
==
0
)
{
/* for a free OGMB - need code for this case... */
DEB
(
printk
(
"wd7000_intr_handle: free outgoing mailbox
\n
"
);)
wd7000_intr_ack
();
return
;
}
/* The interrupt is for an incoming mailbox */
icmb
=
flag
&
0x3f
;
scb
=
(
struct
scb
*
)
scsi2int
(
mb
.
icmb
[
icmb
].
scbptr
);
icmb_status
=
mb
.
icmb
[
icmb
].
status
;
mb
.
icmb
[
icmb
].
status
=
0
;
#ifdef DEBUG
#ifdef DEBUG
printk
(
" ICMB %d posted for SCB/ICB %06x, status %02x, vue %02x"
,
printk
(
"wd7000_intr_handle: irq = %d, host = %06x
\n
"
,
irq
,
host
);
icmb
,
scb
,
icmb_status
,
scb
->
vue
);
#endif
#endif
if
(
!
(
scb
->
op
&
0x80
))
{
/* an SCB is done */
flag
=
inb
(
host
->
iobase
+
ASC_INTR_STAT
);
SCpnt
=
scb
->
SCpnt
;
#ifdef DEBUG
if
(
--
(
SCpnt
->
SCp
.
phase
)
<=
0
)
{
/* all scbs for SCpnt are done */
printk
(
"wd7000_intr_handle: intr stat = %02x
\n
"
,
flag
);
host_error
=
scb
->
vue
|
(
icmb_status
<<
8
);
#endif
scsi_error
=
scb
->
status
;
errstatus
=
make_code
(
host_error
,
scsi_error
);
SCpnt
->
result
=
errstatus
;
if
(
SCpnt
->
host_scribble
!=
NULL
)
if
(
!
(
inb
(
host
->
iobase
+
ASC_STAT
)
&
INT_IM
))
{
scsi_free
(
SCpnt
->
host_scribble
,
WD7000_SCRIBBLE
);
/* NB: these are _very_ possible if IRQ 15 is being used, since
free_scb
(
scb
);
it's the "garbage collector" on the 2nd 8259 PIC. Specifically,
any interrupt signal into the 8259 which can't be identified
comes out as 7 from the 8259, which is 15 to the host. Thus, it
is a good thing the WD7000 has an interrupt status port, so we
can sort these out. Otherwise, electrical noise and other such
problems would be indistinguishable from valid interrupts...
*/
#ifdef DEBUG
printk
(
"wd7000_intr_handle: phantom interrupt...
\n
"
);
#endif
wd7000_intr_ack
(
host
);
return
;
}
SCpnt
->
scsi_done
(
SCpnt
);
if
(
flag
&
MB_INTR
)
{
}
/* The interrupt is for a mailbox */
}
else
{
/* an ICB is done */
if
(
!
(
flag
&
IMB_INTR
))
{
icb
=
(
unchar
*
)
scb
;
#ifdef DEBUG
icb
[
ICB_STATUS
]
=
icmb_status
;
printk
(
"wd7000_intr_handle: free outgoing mailbox"
);
icb
[
ICB_PHASE
]
=
0
;
#endif
/*
* If sleep_on() and the "interrupt on free OGMB" command are
* used in mail_out(), wake_up() should correspondingly be called
* here. For now, we don't need to do anything special.
*/
wd7000_intr_ack
(
host
);
return
;
}
else
{
/* The interrupt is for an incoming mailbox */
icmb
=
flag
&
MB_MASK
;
icmb_status
=
icmbs
[
icmb
].
status
;
if
(
icmb_status
&
0x80
)
{
/* unsolicited - result in ICMB */
#ifdef DEBUG
printk
(
"wd7000_intr_handle: unsolicited interrupt %02xh
\n
"
,
icmb_status
);
#endif
wd7000_intr_ack
(
host
);
return
;
}
scb
=
(
struct
scb
*
)
scsi2int
((
unchar
*
)
icmbs
[
icmb
].
scbptr
);
icmbs
[
icmb
].
status
=
0
;
if
(
!
(
scb
->
op
&
ICB_OP_MASK
))
{
/* an SCB is done */
SCpnt
=
scb
->
SCpnt
;
if
(
--
(
SCpnt
->
SCp
.
phase
)
<=
0
)
{
/* all scbs are done */
host_error
=
scb
->
vue
|
(
icmb_status
<<
8
);
scsi_error
=
scb
->
status
;
errstatus
=
make_code
(
host_error
,
scsi_error
);
SCpnt
->
result
=
errstatus
;
free_scb
(
scb
);
SCpnt
->
scsi_done
(
SCpnt
);
}
}
else
{
/* an ICB is done */
icb
=
(
IcbAny
*
)
scb
;
icb
->
status
=
icmb_status
;
icb
->
phase
=
0
;
}
}
/* incoming mailbox */
}
}
wd7000_intr_ack
();
wd7000_intr_ack
(
host
);
DEB
(
printk
(
".
\n
"
);)
return
;
return
;
}
}
int
wd7000_queuecommand
(
Scsi_Cmnd
*
SCpnt
,
void
(
*
done
)(
Scsi_Cmnd
*
))
int
wd7000_queuecommand
(
Scsi_Cmnd
*
SCpnt
,
void
(
*
done
)(
Scsi_Cmnd
*
))
{
{
Scb
*
scb
;
register
Scb
*
scb
;
Sgb
*
sgb
;
register
Sgb
*
sgb
;
unchar
*
cdb
;
register
unchar
*
cdb
=
(
unchar
*
)
SCpnt
->
cmnd
;
unchar
idlun
;
register
unchar
idlun
;
short
cdblen
;
register
short
cdblen
;
Adapter
*
host
=
(
Adapter
*
)
SCpnt
->
host
->
hostdata
;
cdb
=
(
unchar
*
)
SCpnt
->
cmnd
;
cdblen
=
COMMAND_SIZE
(
*
cdb
);
cdblen
=
COMMAND_SIZE
(
cdb
[
0
]
);
idlun
=
((
SCpnt
->
target
<<
5
)
&
0xe0
)
|
(
SCpnt
->
lun
&
7
);
idlun
=
((
SCpnt
->
target
<<
5
)
&
0xe0
)
|
(
SCpnt
->
lun
&
7
);
SCpnt
->
scsi_done
=
done
;
SCpnt
->
scsi_done
=
done
;
SCpnt
->
SCp
.
phase
=
1
;
SCpnt
->
SCp
.
phase
=
1
;
scb
=
alloc_scb
(
);
scb
=
alloc_scb
s
(
1
);
scb
->
idlun
=
idlun
;
scb
->
idlun
=
idlun
;
memcpy
(
scb
->
cdb
,
cdb
,
cdblen
);
memcpy
(
scb
->
cdb
,
cdb
,
cdblen
);
scb
->
direc
=
0x40
;
/* Disable direction check */
scb
->
direc
=
0x40
;
/* Disable direction check */
scb
->
SCpnt
=
SCpnt
;
/* so we can find stuff later */
scb
->
SCpnt
=
SCpnt
;
/* so we can find stuff later */
SCpnt
->
host_scribble
=
NULL
;
SCpnt
->
host_scribble
=
(
unchar
*
)
scb
;
DEB
(
printk
(
"request_bufflen is %x, bufflen is %x
\n
"
,
\
scb
->
host
=
host
;
SCpnt
->
request_bufflen
,
SCpnt
->
bufflen
);)
if
(
SCpnt
->
use_sg
)
{
if
(
SCpnt
->
use_sg
)
{
struct
scatterlist
*
sg
=
(
struct
scatterlist
*
)
SCpnt
->
request_buffer
;
struct
scatterlist
*
sg
=
(
struct
scatterlist
*
)
SCpnt
->
request_buffer
;
unsigned
i
;
unsigned
i
;
if
(
scsi_hosts
[
wd7000_host
].
sg_tablesize
<=
0
)
{
if
(
SCpnt
->
host
->
sg_tablesize
==
SG_NONE
)
{
panic
(
"wd7000_queuecommand: scatter/gather not supported.
\n
"
);
panic
(
"wd7000_queuecommand: scatter/gather not supported.
\n
"
);
}
}
#ifdef DEBUG
#ifdef DEBUG
printk
(
"Using scatter/gather with %d elements.
\n
"
,
SCpnt
->
use_sg
);
printk
(
"Using scatter/gather with %d elements.
\n
"
,
SCpnt
->
use_sg
);
#endif
#endif
/*
Allocate memory for a scatter/gather-list in wd7000 format.
Save the pointer at host_scribble.
*/
#ifdef DEBUG
if
(
SCpnt
->
use_sg
>
WD7000_SG
)
panic
(
"WD7000: requesting too many scatterblocks
\n
"
);
#endif
SCpnt
->
host_scribble
=
(
unsigned
char
*
)
scsi_malloc
(
WD7000_SCRIBBLE
);
sgb
=
(
Sgb
*
)
SCpnt
->
host_scribble
;
if
(
sgb
==
NULL
)
panic
(
"wd7000_queuecommand: scsi_malloc() failed.
\n
"
);
sgb
=
scb
->
sgb
;
scb
->
op
=
1
;
scb
->
op
=
1
;
any2scsi
(
scb
->
dataptr
,
sgb
);
any2scsi
(
scb
->
dataptr
,
(
int
)
sgb
);
any2scsi
(
scb
->
maxlen
,
SCpnt
->
use_sg
*
sizeof
(
Sgb
)
);
any2scsi
(
scb
->
maxlen
,
SCpnt
->
use_sg
*
sizeof
(
Sgb
)
);
for
(
i
=
0
;
i
<
SCpnt
->
use_sg
;
i
++
)
{
for
(
i
=
0
;
i
<
SCpnt
->
use_sg
;
i
++
)
{
any2scsi
(
sgb
->
ptr
,
sg
[
i
].
address
);
any2scsi
(
sgb
[
i
].
ptr
,
(
int
)
sg
[
i
].
address
);
any2scsi
(
sgb
->
len
,
sg
[
i
].
length
);
any2scsi
(
sgb
[
i
].
len
,
sg
[
i
].
length
);
sgb
++
;
}
}
DEB
(
printk
(
"Using %d bytes for %d scatter/gather blocks
\n
"
,
\
scsi2int
(
scb
->
maxlen
),
SCpnt
->
use_sg
);)
}
else
{
}
else
{
scb
->
op
=
0
;
scb
->
op
=
0
;
any2scsi
(
scb
->
dataptr
,
SCpnt
->
request_buffer
);
any2scsi
(
scb
->
dataptr
,
(
int
)
SCpnt
->
request_buffer
);
any2scsi
(
scb
->
maxlen
,
SCpnt
->
request_bufflen
);
any2scsi
(
scb
->
maxlen
,
SCpnt
->
request_bufflen
);
}
}
while
(
!
mail_out
(
host
,
scb
))
/* keep trying */
;
return
mail_out
(
scb
)
;
return
1
;
}
}
...
@@ -442,192 +955,292 @@ int wd7000_command(Scsi_Cmnd *SCpnt)
...
@@ -442,192 +955,292 @@ int wd7000_command(Scsi_Cmnd *SCpnt)
}
}
int
wd7000_init
(
void
)
int
wd7000_diagnostics
(
Adapter
*
host
,
int
code
)
{
int
i
;
{
unchar
init_block
[]
=
{
static
IcbDiag
icb
=
{
ICB_OP_DIAGNOSTICS
};
INITIALIZATION
,
7
,
BUS_ON
,
BUS_OFF
,
0
,
0
,
0
,
0
,
OGMB_CNT
,
ICMB_CNT
static
unchar
buf
[
256
];
unsigned
long
timeout
;
icb
.
type
=
code
;
any2scsi
(
icb
.
len
,
sizeof
(
buf
));
any2scsi
(
icb
.
ptr
,
(
int
)
&
buf
);
icb
.
phase
=
1
;
/*
* This routine is only called at init, so there should be OGMBs
* available. I'm assuming so here. If this is going to
* fail, I can just let the timeout catch the failure.
*/
mail_out
(
host
,
(
struct
scb
*
)
&
icb
);
timeout
=
jiffies
+
WAITnexttimeout
;
/* wait up to 2 seconds */
while
(
icb
.
phase
&&
jiffies
<
timeout
)
/* wait for completion */
;
if
(
icb
.
phase
)
{
printk
(
"wd7000_diagnostics: timed out.
\n
"
);
return
0
;
}
if
(
make_code
(
icb
.
vue
|
(
icb
.
status
<<
8
),
0
))
{
printk
(
"wd7000_diagnostics: failed (%02x,%02x)
\n
"
,
icb
.
vue
,
icb
.
status
);
return
0
;
}
return
1
;
}
int
wd7000_init
(
Adapter
*
host
)
{
InitCmd
init_cmd
=
{
INITIALIZATION
,
7
,
BUS_ON
,
BUS_OFF
,
0
,
0
,
0
,
0
,
OGMB_CNT
,
ICMB_CNT
};
};
struct
sigaction
sa
=
{
wd7000_intr_handle
,
0
,
SA_INTERRUPT
,
NULL
};
int
diag
;
/* Reset the adapter. */
outb
(
SCSI_RES
|
ASC_RES
,
CONTROL
);
delay
(
1
);
/* reset pulse: this is 10ms, only need 25us */
outb
(
0
,
CONTROL
);
controlstat
=
0
;
/*
/*
Wait 2 seconds, then expect Command Port Ready.
Reset the adapter - only. The SCSI bus was initialized at power-up,
and we need to do this just so we control the mailboxes, etc.
I suspect something else needs to be done here, but I don't know
what. The OEM doc says power-up diagnostics take 2 seconds, and
indeed, SCSI commands submitted before then will time out, but
none of what follows seems deterred by _not_ waiting 2 secs.
*/
*/
delay
(
200
);
outb
(
ASC_RES
,
host
->
iobase
+
ASC_CONTROL
);
delay
(
1
);
/* reset pulse: this is 10ms, only need 25us */
WAIT
(
ASC_STAT
,
STATMASK
,
CMD_RDY
,
0
);
outb
(
0
,
host
->
iobase
+
ASC_CONTROL
);
DEB
(
printk
(
"wd7000_init: Power-on Diagnostics finished
\n
"
);)
host
->
control
=
0
;
/* this must always shadow ASC_CONTROL */
if
(((
i
=
inb
(
INTR_STAT
))
!=
1
)
&&
(
i
!=
7
))
{
WAIT
(
host
->
iobase
+
ASC_STAT
,
ASC_STATMASK
,
CMD_RDY
,
0
);
panic
(
"wd7000_init: Power-on Diagnostics error
\n
"
);
return
0
;
if
((
diag
=
inb
(
host
->
iobase
+
ASC_INTR_STAT
))
!=
1
)
{
printk
(
"wd7000_init: "
);
switch
(
diag
)
{
case
2
:
printk
(
"RAM failure.
\n
"
);
break
;
case
3
:
printk
(
"FIFO R/W failed
\n
"
);
break
;
case
4
:
printk
(
"SBIC register R/W failed
\n
"
);
break
;
case
5
:
printk
(
"Initialization D-FF failed.
\n
"
);
break
;
case
6
:
printk
(
"Host IRQ D-FF failed.
\n
"
);
break
;
case
7
:
printk
(
"ROM checksum error.
\n
"
);
break
;
default:
printk
(
"diagnostic code %02Xh received.
\n
"
,
diag
);
break
;
}
return
0
;
}
}
/* Clear mailboxes */
/* Clear mailboxes */
memset
(
&
mb
,
0
,
sizeof
(
mb
));
memset
(
&
(
host
->
mb
),
0
,
sizeof
(
host
->
mb
));
/* Set up SCB free list */
init_scbs
();
/* Set up init block */
any2scsi
(
init_block
+
5
,
&
mb
);
/* Execute init command */
/* Execute init command */
if
(
!
command_out
(
init_block
,
sizeof
(
init_block
)))
{
any2scsi
((
unchar
*
)
&
(
init_cmd
.
mailboxes
),
(
int
)
&
(
host
->
mb
));
panic
(
"WD-7000 Initialization failed.
\n
"
);
if
(
!
command_out
(
host
,
(
unchar
*
)
&
init_cmd
,
sizeof
(
init_cmd
)))
{
printk
(
"wd7000_init: adapter initialization failed.
\n
"
);
return
0
;
return
0
;
}
}
WAIT
(
host
->
iobase
+
ASC_STAT
,
ASC_STATMASK
,
ASC_INIT
,
0
);
/* Wait until init finished */
WAIT
(
ASC_STAT
,
STATMASK
,
CMD_RDY
|
ASC_INI
,
0
);
if
(
irqaction
(
host
->
irq
,
&
sa
))
{
outb
(
DISABLE_UNS_INTR
,
COMMAND
);
printk
(
"wd7000_init: can't get IRQ %d.
\n
"
,
host
->
irq
);
WAIT
(
ASC_STAT
,
STATMASK
,
CMD_RDY
|
ASC_INI
,
0
);
return
0
;
}
/* Enable Interrupt and DMA */
if
(
request_dma
(
host
->
dma
))
{
if
(
request_irq
(
IRQ_LVL
,
wd7000_intr_handle
))
{
printk
(
"wd7000_init: can't get DMA channel %d.
\n
"
,
host
->
dma
);
panic
(
"Unable to allocate IRQ for WD-7000.
\n
"
);
free_irq
(
host
->
irq
);
return
0
;
return
0
;
};
}
if
(
request_dma
(
DMA_CH
))
{
wd7000_enable_dma
(
host
);
panic
(
"Unable to allocate DMA channel for WD-7000.
\n
"
);
wd7000_enable_intr
(
host
);
free_irq
(
IRQ_LVL
);
return
0
;
if
(
!
wd7000_diagnostics
(
host
,
ICB_DIAG_FULL
))
{
};
free_dma
(
host
->
dma
);
wd7000_enable_dma
();
free_irq
(
host
->
irq
);
wd7000_enable_intr
();
return
0
;
}
printk
(
"WD-7000 initialized.
\n
"
);
return
1
;
return
1
;
fail:
fail:
printk
(
"wd7000_init: WAIT timed out.
\n
"
);
return
0
;
/* 0 = not ok */
return
0
;
/* 0 = not ok */
}
}
void
wd7000_revision
(
void
)
void
wd7000_revision
(
Adapter
*
host
)
{
{
volatile
unchar
icb
[
ICB_LEN
]
=
{
0x8c
};
/* read firmware revision level */
static
IcbRevLvl
icb
=
{
ICB_OP_GET_REVISION
};
icb
[
ICB_PHASE
]
=
1
;
mail_out
(
(
struct
scb
*
)
icb
);
while
(
icb
[
ICB_PHASE
])
/* wait for completion */
;
rev_1
=
icb
[
1
];
rev_2
=
icb
[
2
];
icb
.
phase
=
1
;
/*
/*
For boards at rev 7.0 or later, enable scatter/gather.
* Like diagnostics, this is only done at init time, in fact, from
*/
* wd7000_detect, so there should be OGMBs available. If it fails,
if
(
rev_1
>=
7
)
scsi_hosts
[
wd7000_host
].
sg_tablesize
=
WD7000_SG
;
* the only damage will be that the revision will show up as 0.0,
* which in turn means that scatter/gather will be disabled.
*/
mail_out
(
host
,
(
struct
scb
*
)
&
icb
);
while
(
icb
.
phase
)
/* wait for completion */
;
host
->
rev1
=
icb
.
primary
;
host
->
rev2
=
icb
.
secondary
;
}
}
static
const
char
*
wd_bases
[]
=
{(
char
*
)
0xce000
,(
char
*
)
0xd8000
};
typedef
struct
{
char
*
signature
;
unsigned
offset
;
unsigned
length
;
}
Signature
;
static
const
Signature
signatures
[]
=
{{
"SSTBIOS"
,
0xd
,
0x7
}};
#define NUM_SIGNATURES (sizeof(signatures)/sizeof(Signature))
int
wd7000_detect
(
int
hostnum
)
int
wd7000_detect
(
int
hostnum
)
/*
/*
* return non-zero on detection
* Returns the number of adapters this driver is supporting.
*
* The source for hosts.c says to wait to call scsi_register until 100%
* sure about an adapter. We need to do it a little sooner here; we
* need the storage set up by scsi_register before wd7000_init, and
* changing the location of an Adapter structure is more trouble than
* calling scsi_unregister.
*
*/
*/
{
{
int
i
,
j
;
int
i
,
j
,
present
=
0
;
char
const
*
base_address
=
NULL
;
const
Config
*
cfg
;
const
Signature
*
sig
;
if
(
check_region
(
IO_BASE
,
4
))
return
0
;
/* IO ports in use */
Adapter
*
host
=
NULL
;
for
(
i
=
0
;
i
<
(
sizeof
(
wd_bases
)
/
sizeof
(
char
*
));
i
++
){
struct
Scsi_Host
*
sh
;
for
(
j
=
0
;
j
<
NUM_SIGNATURES
;
j
++
){
if
(
!
memcmp
((
void
*
)(
wd_bases
[
i
]
+
signatures
[
j
].
offset
),
(
void
*
)
signatures
[
j
].
signature
,
signatures
[
j
].
length
)){
base_address
=
wd_bases
[
i
];
printk
(
"WD-7000 detected.
\n
"
);
}
}
}
if
(
base_address
==
NULL
)
return
0
;
snarf_region
(
IO_BASE
,
4
);
/* Register our ports */
/* Set up SCB free list, which is shared by all adapters */
/* Store our host number */
init_scbs
();
wd7000_host
=
hostnum
;
wd7000_init
();
cfg
=
configs
;
wd7000_revision
();
/* will set scatter/gather by rev level */
for
(
i
=
0
;
i
<
NUM_CONFIGS
;
i
++
)
{
sig
=
signatures
;
for
(
j
=
0
;
j
<
NUM_SIGNATURES
;
j
++
)
{
if
(
!
memcmp
(
cfg
->
bios
+
sig
->
ofs
,
sig
->
sig
,
sig
->
len
))
{
/* matched this one */
#ifdef DEBUG
printk
(
"WD-7000 SST BIOS detected at %04X: checking...
\n
"
,
(
int
)
cfg
->
bios
);
#endif
/*
* We won't explicitly test the configuration (in this
* version); instead, we'll just see if it works to
* setup the adapter; if it does, we'll use it.
*/
if
(
check_region
(
cfg
->
iobase
,
4
))
{
/* ports in use */
printk
(
"IO %xh already in use.
\n
"
,
host
->
iobase
);
continue
;
}
/*
* We register here, to get a pointer to the extra space,
* which we'll use as the Adapter structure (host) for
* this adapter. It is located just after the registered
* Scsi_Host structure (sh), and is located by the empty
* array hostdata.
*/
sh
=
scsi_register
(
hostnum
,
sizeof
(
Adapter
)
);
host
=
(
Adapter
*
)
sh
->
hostdata
;
#ifdef DEBUG
printk
(
"wd7000_detect: adapter allocated at %06x
\n
"
,
(
int
)
host
);
#endif
memset
(
host
,
0
,
sizeof
(
Adapter
)
);
host
->
num
=
hostnum
;
host
->
sh
=
sh
;
host
->
irq
=
cfg
->
irq
;
host
->
iobase
=
cfg
->
iobase
;
host
->
dma
=
cfg
->
dma
;
irq2host
[
host
->
irq
]
=
host
;
if
(
!
wd7000_init
(
host
))
{
/* Initialization failed */
scsi_unregister
(
sh
,
sizeof
(
Adapter
)
);
continue
;
}
/*
* OK from here - we'll use this adapter/configuration.
*/
wd7000_revision
(
host
);
/* important for scatter/gather */
printk
(
"Western Digital WD-7000 (%d.%d) "
,
host
->
rev1
,
host
->
rev2
);
printk
(
"using IO %xh IRQ %d DMA %d.
\n
"
,
host
->
iobase
,
host
->
irq
,
host
->
dma
);
snarf_region
(
host
->
iobase
,
4
);
/* Register our ports */
/*
* For boards before rev 6.0, scatter/gather isn't supported.
*/
if
(
host
->
rev1
<
6
)
sh
->
sg_tablesize
=
SG_NONE
;
present
++
;
/* count it */
break
;
/* don't try any more sigs */
}
sig
++
;
/* try next signature with this configuration */
}
cfg
++
;
/* try next configuration */
}
return
1
;
return
present
;
}
}
static
void
wd7000_append_info
(
char
*
info
,
const
char
*
fmt
,
...
)
/*
/*
*
This is just so I can use vsprintf
...
*
I have absolutely NO idea how to do an abort with the WD7000
...
*/
*/
{
va_list
args
;
extern
int
vsprintf
(
char
*
buf
,
const
char
*
fmt
,
va_list
args
);
va_start
(
args
,
fmt
);
vsprintf
(
info
,
fmt
,
args
);
va_end
(
args
);
return
;
}
const
char
*
wd7000_info
(
void
)
{
static
char
info
[
80
]
=
"Western Digital WD-7000, Firmware Revision "
;
wd7000_revision
();
wd7000_append_info
(
info
+
strlen
(
info
),
"%d.%d.
\n
"
,
rev_1
,
rev_2
);
return
info
;
}
int
wd7000_abort
(
Scsi_Cmnd
*
SCpnt
,
int
i
)
int
wd7000_abort
(
Scsi_Cmnd
*
SCpnt
,
int
i
)
{
{
#ifdef DEBUG
#ifdef DEBUG
printk
(
"wd7000_abort: Scsi_Cmnd = 0x%0
8x, code = %d "
,
SCpnt
,
i
);
printk
(
"wd7000_abort: Scsi_Cmnd = 0x%0
6x, code = %d "
,
(
int
)
SCpnt
,
i
);
printk
(
"id %d lun %d cdb"
,
SCpnt
->
target
,
SCpnt
->
lun
);
printk
(
"id %d lun %d cdb"
,
SCpnt
->
target
,
SCpnt
->
lun
);
{
int
j
;
unchar
*
cdbj
=
(
unchar
*
)
SCpnt
->
cmnd
;
{
for
(
j
=
0
;
j
<
COMMAND_SIZE
(
*
cdbj
);
j
++
)
printk
(
" %02x"
,
*
(
cdbj
++
));
int
j
;
unchar
*
cdbj
=
(
unchar
*
)
SCpnt
->
cmnd
;
printk
(
" result %08x
\n
"
,
SCpnt
->
result
);
for
(
j
=
0
;
j
<
COMMAND_SIZE
(
*
cdbj
);
j
++
)
printk
(
" %02x"
,
*
(
cdbj
++
));
printk
(
" result %08x
\n
"
,
SCpnt
->
result
);
}
}
#endif
#endif
return
0
;
return
0
;
}
}
/* We do not implement a reset function here, but the upper level code assumes
/*
that it will get some kind of response for the command in SCpnt. We must
* I also have no idea how to do a reset...
oblige, or the command will hang the scsi system */
*/
int
wd7000_reset
(
Scsi_Cmnd
*
SCpnt
)
int
wd7000_reset
(
Scsi_Cmnd
*
SCpnt
)
{
{
#ifdef DEBUG
#ifdef DEBUG
printk
(
"wd7000_reset
\n
"
);
printk
(
"wd7000_reset: Scsi_Cmnd = 0x%06x "
,
(
int
)
SCpnt
);
if
(
SCpnt
)
{
printk
(
"id %d lun %d cdb"
,
SCpnt
->
target
,
SCpnt
->
lun
);
{
int
j
;
unchar
*
cdbj
=
(
unchar
*
)
SCpnt
->
cmnd
;
for
(
j
=
0
;
j
<
COMMAND_SIZE
(
*
cdbj
);
j
++
)
printk
(
" %02x"
,
*
(
cdbj
++
));
printk
(
" result %08x"
,
SCpnt
->
result
);
}
}
printk
(
"
\n
"
);
#endif
#endif
if
(
SCpnt
)
SCpnt
->
flags
|=
NEEDS_JUMPSTART
;
if
(
SCpnt
)
SCpnt
->
flags
|=
NEEDS_JUMPSTART
;
return
0
;
return
0
;
}
}
int
wd7000_biosparam
(
int
size
,
int
dev
,
int
*
ip
)
/*
/*
* This is borrowed directly from aha1542.c, but my disks are organized
* The info routine in the WD7000 structure isn't per-adapter, so it can't
* this way, so I think it will work OK.
* really return any useful information about an adapter. Because of this,
* I'm no longer using it to return rev. level.
*/
const
char
*
wd7000_info
(
void
)
{
static
char
info
[]
=
"Western Digital WD-7000"
;
return
info
;
}
/*
* This was borrowed directly from aha1542.c, but my disks are organized
* this way, so I think it will work OK. Someone who is ambitious can
* borrow a newer or more complete version from another driver.
*/
*/
int
wd7000_biosparam
(
int
size
,
int
dev
,
int
*
ip
)
{
{
ip
[
0
]
=
64
;
ip
[
0
]
=
64
;
ip
[
1
]
=
32
;
ip
[
1
]
=
32
;
...
@@ -635,4 +1248,3 @@ int wd7000_biosparam(int size, int dev, int* ip)
...
@@ -635,4 +1248,3 @@ int wd7000_biosparam(int size, int dev, int* ip)
/* if (ip[2] >= 1024) ip[2] = 1024; */
/* if (ip[2] >= 1024) ip[2] = 1024; */
return
0
;
return
0
;
}
}
drivers/scsi/wd7000.h
View file @
16119ae5
...
@@ -4,169 +4,14 @@
...
@@ -4,169 +4,14 @@
*
*
* Header file for the WD-7000 driver for Linux
* Header file for the WD-7000 driver for Linux
*
*
* $Log: $
* John Boyd <boyd@cis.ohio-state.edu> Jan 1994:
* Revision 1.1 1992/07/24 06:27:38 root
* This file has been reduced to only the definitions needed for the
* Initial revision
* WD7000 host structure.
*
* Revision 1.1 1992/07/05 08:32:32 root
* Initial revision
*
* Revision 1.1 1992/05/15 18:38:05 root
* Initial revision
*
* Revision 1.1 1992/04/02 03:23:13 drew
* Initial revision
*
* Revision 1.3 1992/01/27 14:46:29 tthorn
* *** empty log message ***
*
*
*/
*/
#include <linux/types.h>
#include <linux/types.h>
#undef STATMASK
#undef CONTROL
#define IO_BASE 0x350
#define IRQ_LVL 15
#define DMA_CH 6
#define OGMB_CNT 8
#define ICMB_CNT 16
/* I/O Port interface 4.2 */
/* READ */
#define ASC_STAT IO_BASE
#define INT_IM 0x80
/* Interrupt Image Flag */
#define CMD_RDY 0x40
/* Command Port Ready */
#define CMD_REJ 0x20
/* Command Port Byte Rejected */
#define ASC_INI 0x10
/* ASC Initialized Flag */
#define STATMASK 0xf0
/* The lower 4 Bytes are reserved */
/* This register serves two purposes
* Diagnostics error code
* Interrupt Status
*/
#define INTR_STAT ASC_STAT+1
#define ANYINTR 0x80
/* Mailbox Service possible/required */
#define IMB 0x40
/* 1 Incoming / 0 Outgoing */
#define MBMASK 0x3f
/* if MSb is zero, the lower bits are diagnostic status *
* Diagnostics:
* 01 No diagnostic error occurred
* 02 RAM failure
* 03 FIFO R/W failed
* 04 SBIC register read/write failed
* 05 Initialization D-FF failed
* 06 Host IRQ D-FF failed
* 07 ROM checksum error
* Interrupt status (bitwise):
* 10NNNNNN outgoing mailbox NNNNNN is free
* 11NNNNNN incoming mailbox NNNNNN needs service
*/
/* WRITE */
#define COMMAND ASC_STAT
/*
* COMMAND opcodes
*/
#define NO_OP 0
#define INITIALIZATION 1
/* initialization after reset (10 bytes) */
#define DISABLE_UNS_INTR 2
/* disable unsolicited interrupts */
#define ENABLE_UNS_INTR 3
/* enable unsolicited interrupts */
#define INTR_ON_FREE_OGMB 4
/* interrupt on free OGMB */
#define SCSI_SOFT_RESET 5
/* SCSI soft reset */
#define SCSI_HARD_RESET 6
/* SCSI hard reset acknowledge */
#define START_OGMB 0x80
/* start command in OGMB (n) */
#define SCAN_OGMBS 0xc0
/* start multiple commands, signature (n) */
/* where (n) = lower 6 bits */
/*
* For INITIALIZATION:
*/
#define BUS_ON 48
/* x 125ns, 48 = 6000ns, BIOS uses 8000ns */
#define BUS_OFF 24
/* x 125ns, 24 = 3000ns, BIOS uses 1875ns */
#define INTR_ACK ASC_STAT+1
#define CONTROL ASC_STAT+2
#define INT_EN 0x08
/* Interrupt Enable */
#define DMA_EN 0x04
/* DMA Enable */
#define SCSI_RES 0x02
/* SCSI Reset */
#define ASC_RES 0x01
/* ASC Reset */
/* Mailbox Definition */
struct
wd_mailbox
{
unchar
status
;
unchar
scbptr
[
3
];
};
/* These belong in scsi.h also */
#undef any2scsi
#define any2scsi(up, p) \
(up)[0] = (((long)(p)) >> 16); \
(up)[1] = ((long)(p)) >> 8; \
(up)[2] = ((long)(p));
#define scsi2int(up) ( (((long)*(up)) << 16) + (((long)(up)[1]) << 8) + ((long)(up)[2]) )
#define xany2scsi(up, p) \
(up)[0] = ((long)(p)) >> 24; \
(up)[1] = ((long)(p)) >> 16; \
(up)[2] = ((long)(p)) >> 8; \
(up)[3] = ((long)(p));
#define xscsi2int(up) ( (((long)(up)[0]) << 24) + (((long)(up)[1]) << 16) \
+ (((long)(up)[2]) << 8) + ((long)(up)[3]) )
#define MAX_CDB 12
#define MAX_SENSE 14
typedef
struct
scb
{
/* Command Control Block 5.4.1 */
unchar
op
;
/* Command Control Block Operation Code */
unchar
idlun
;
/* op=0,2:Target Id, op=1:Initiator Id */
/* Outbound data transfer, length is checked*/
/* Inbound data transfer, length is checked */
/* Logical Unit Number */
unchar
cdb
[
12
];
/* SCSI Command Block */
unchar
status
;
/* SCSI Return Status */
unchar
vue
;
/* Vendor Unique Error Code */
unchar
maxlen
[
3
];
/* Maximum Data Transfer Length */
unchar
dataptr
[
3
];
/* SCSI Data Block Pointer */
unchar
linkptr
[
3
];
/* Next Command Link Pointer */
unchar
direc
;
/* Transfer Direction */
unchar
reserved2
[
6
];
/* SCSI Command Descriptor Block */
/* end of hardware SCB */
Scsi_Cmnd
*
SCpnt
;
/* Scsi_Cmnd using this SCB */
struct
scb
*
next
;
/* for lists of scbs */
}
Scb
;
/*
* WD7000-specific scatter/gather element structure
*/
typedef
struct
sgb
{
unchar
len
[
3
];
unchar
ptr
[
3
];
}
Sgb
;
/*
* Note: MAX_SCBS _must_ be defined large enough to keep ahead of the
* demand for SCBs, which will be at most WD7000_Q * WD7000_SG. 1 is
* added to each because they can be 0.
*/
#define MAX_SCBS ((WD7000_Q+1) * (WD7000_SG+1))
/*
* The driver is written to allow host-only commands to be executed. These
* use a 16-byte block called an ICB.
*
* (Currently, only wd7000_info uses this, to get the firmware rev. level.)
*/
#define ICB_STATUS 16
/* set to icmb status by wd7000_intr_handle */
#define ICB_PHASE 17
/* set to 0 by wd7000_intr_handle */
#define ICB_LEN 18
/* actually 16; this includes the above */
int
wd7000_detect
(
int
);
int
wd7000_detect
(
int
);
int
wd7000_command
(
Scsi_Cmnd
*
);
int
wd7000_command
(
Scsi_Cmnd
*
);
int
wd7000_queuecommand
(
Scsi_Cmnd
*
,
void
(
*
done
)(
Scsi_Cmnd
*
));
int
wd7000_queuecommand
(
Scsi_Cmnd
*
,
void
(
*
done
)(
Scsi_Cmnd
*
));
...
@@ -176,30 +21,32 @@ int wd7000_reset(Scsi_Cmnd *);
...
@@ -176,30 +21,32 @@ int wd7000_reset(Scsi_Cmnd *);
int
wd7000_biosparam
(
int
,
int
,
int
*
);
int
wd7000_biosparam
(
int
,
int
,
int
*
);
#ifndef NULL
#ifndef NULL
#define NULL 0
#define NULL 0L
#endif
#endif
/*
/*
* Define WD7000_SG to be the number of Sgbs that will fit in a block of
* In this version, sg_tablesize now defaults to WD7000_SG, and will
* size WD7000_SCRIBBLE. WD7000_SCRIBBLE must be 512, 1024, 2048, or 4096.
* 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.
*
*
*
The sg_tablesize value will default to SG_NONE for older boards (before
*
Also, it has been reported that boards at Revision 6 support scatter/
*
rev 7.0), but will be changed to WD7000_SG when a newer board is
*
gather, so the new definition of an "older" board has been changed
*
detected
.
*
accordingly
.
*/
*/
#define WD7000_SCRIBBLE 512
#define WD7000_Q 16
#define WD7000_SG 16
#define WD7000_Q OGMB_CNT
#define WD7000_SG (WD7000_SCRIBBLE / sizeof(Sgb))
#define WD7000 {\
#define WD7000 {\
"Western Digital WD-7000", \
"Western Digital WD-7000", \
wd7000_detect, \
wd7000_detect, \
wd7000_info, wd7000_command, \
wd7000_info, \
wd7000_command, \
wd7000_queuecommand, \
wd7000_queuecommand, \
wd7000_abort, \
wd7000_abort, \
wd7000_reset, \
wd7000_reset, \
NULL, \
NULL, \
wd7000_biosparam, \
wd7000_biosparam, \
WD7000_Q, 7,
SG_NONE
, 1, 0, 1}
WD7000_Q, 7,
WD7000_SG
, 1, 0, 1}
#endif
#endif
fs/buffer.c
View file @
16119ae5
...
@@ -49,7 +49,7 @@ extern int check_mcd_media_change(int, int);
...
@@ -49,7 +49,7 @@ extern int check_mcd_media_change(int, int);
static
char
buffersize_index
[
9
]
=
{
-
1
,
0
,
1
,
-
1
,
2
,
-
1
,
-
1
,
-
1
,
3
};
static
char
buffersize_index
[
9
]
=
{
-
1
,
0
,
1
,
-
1
,
2
,
-
1
,
-
1
,
-
1
,
3
};
static
short
int
bufferindex_size
[
NR_SIZES
]
=
{
512
,
1024
,
2048
,
4096
};
static
short
int
bufferindex_size
[
NR_SIZES
]
=
{
512
,
1024
,
2048
,
4096
};
#define BUFSIZE_INDEX(X) (buffersize_index[(X)>>9])
#define BUFSIZE_INDEX(X) (
(int)
buffersize_index[(X)>>9])
static
int
grow_buffers
(
int
pri
,
int
size
);
static
int
grow_buffers
(
int
pri
,
int
size
);
static
int
shrink_specific_buffers
(
unsigned
int
priority
,
int
size
);
static
int
shrink_specific_buffers
(
unsigned
int
priority
,
int
size
);
...
...
fs/proc/net.c
View file @
16119ae5
...
@@ -44,6 +44,7 @@ extern int tcp_get_info(char *, char **, off_t, int);
...
@@ -44,6 +44,7 @@ extern int tcp_get_info(char *, char **, off_t, int);
extern
int
udp_get_info
(
char
*
,
char
**
,
off_t
,
int
);
extern
int
udp_get_info
(
char
*
,
char
**
,
off_t
,
int
);
extern
int
raw_get_info
(
char
*
,
char
**
,
off_t
,
int
);
extern
int
raw_get_info
(
char
*
,
char
**
,
off_t
,
int
);
extern
int
arp_get_info
(
char
*
,
char
**
,
off_t
,
int
);
extern
int
arp_get_info
(
char
*
,
char
**
,
off_t
,
int
);
extern
int
rarp_get_info
(
char
*
,
char
**
,
off_t
,
int
);
extern
int
dev_get_info
(
char
*
,
char
**
,
off_t
,
int
);
extern
int
dev_get_info
(
char
*
,
char
**
,
off_t
,
int
);
extern
int
rt_get_info
(
char
*
,
char
**
,
off_t
,
int
);
extern
int
rt_get_info
(
char
*
,
char
**
,
off_t
,
int
);
#endif
/* CONFIG_INET */
#endif
/* CONFIG_INET */
...
@@ -96,11 +97,14 @@ static struct proc_dir_entry net_dir[] = {
...
@@ -96,11 +97,14 @@ static struct proc_dir_entry net_dir[] = {
{
131
,
3
,
"dev"
},
{
131
,
3
,
"dev"
},
{
132
,
3
,
"raw"
},
{
132
,
3
,
"raw"
},
{
133
,
3
,
"tcp"
},
{
133
,
3
,
"tcp"
},
{
134
,
3
,
"udp"
}
{
134
,
3
,
"udp"
},
#ifdef CONFIG_INET_RARP
{
135
,
4
,
"rarp"
}
#endif
#endif
/* CONFIG_INET */
#endif
/* CONFIG_INET */
#ifdef CONFIG_IPX
#ifdef CONFIG_IPX
,{
13
5
,
9
,
"ipx_route"
},
,{
13
6
,
9
,
"ipx_route"
},
{
13
6
,
3
,
"ipx"
}
{
13
7
,
3
,
"ipx"
}
#endif
/* CONFIG_IPX */
#endif
/* CONFIG_IPX */
};
};
...
@@ -212,12 +216,15 @@ static int proc_readnet(struct inode * inode, struct file * file,
...
@@ -212,12 +216,15 @@ static int proc_readnet(struct inode * inode, struct file * file,
case
134
:
case
134
:
length
=
udp_get_info
(
page
,
&
start
,
file
->
f_pos
,
thistime
);
length
=
udp_get_info
(
page
,
&
start
,
file
->
f_pos
,
thistime
);
break
;
break
;
case
135
:
length
=
rarp_get_info
(
page
,
&
start
,
file
->
f_pos
,
thistime
);
break
;
#endif
/* CONFIG_INET */
#endif
/* CONFIG_INET */
#ifdef CONFIG_IPX
#ifdef CONFIG_IPX
case
13
5
:
case
13
6
:
length
=
ipx_rt_get_info
(
page
,
&
start
,
file
->
f_pos
,
thistime
);
length
=
ipx_rt_get_info
(
page
,
&
start
,
file
->
f_pos
,
thistime
);
break
;
break
;
case
13
6
:
case
13
7
:
length
=
ipx_get_info
(
page
,
&
start
,
file
->
f_pos
,
thistime
);
length
=
ipx_get_info
(
page
,
&
start
,
file
->
f_pos
,
thistime
);
break
;
break
;
#endif
/* CONFIG_IPX */
#endif
/* CONFIG_IPX */
...
...
include/linux/if_arp.h
View file @
16119ae5
...
@@ -30,6 +30,13 @@
...
@@ -30,6 +30,13 @@
#define ARPHRD_IEEE802 6
/* IEEE 802.2 Ethernet- huh? */
#define ARPHRD_IEEE802 6
/* IEEE 802.2 Ethernet- huh? */
#define ARPHRD_ARCNET 7
/* ARCnet */
#define ARPHRD_ARCNET 7
/* ARCnet */
#define ARPHRD_APPLETLK 8
/* APPLEtalk */
#define ARPHRD_APPLETLK 8
/* APPLEtalk */
/* Dummy types for non ARP hardware */
#define ARPHRD_SLIP 256
#define ARPHRD_CSLIP 257
#define ARPHRD_SLIP6 258
#define ARPHRD_CSLIP6 259
#define ARPHRD_KISS 260
#define ARPHRD_ADAPT 264
/* ARP protocol opcodes. */
/* ARP protocol opcodes. */
#define ARPOP_REQUEST 1
/* ARP request */
#define ARPOP_REQUEST 1
/* ARP request */
...
...
include/linux/if_slip.h
0 → 100644
View file @
16119ae5
/*
* Swansea University Computer Society NET3
*
* This file declares the constants of special use with the SLIP/CSLIP/
* KISS TNC driver.
*/
#ifndef __LINUX_SLIP_H
#define __LINUX_SLIP_H
#define SL_MODE_SLIP 0
#define SL_MODE_CSLIP 1
#define SL_MODE_KISS 4
#define SL_OPT_SIXBIT 2
#define SL_OPT_ADAPTIVE 8
#endif
include/linux/ip.h
View file @
16119ae5
...
@@ -32,8 +32,17 @@ struct timestamp {
...
@@ -32,8 +32,17 @@ struct timestamp {
unsigned
char
len
;
unsigned
char
len
;
unsigned
char
ptr
;
unsigned
char
ptr
;
union
{
union
{
#if defined(__i386__)
unsigned
char
flags
:
4
,
unsigned
char
flags
:
4
,
overflow:
4
;
overflow:
4
;
#else
#if defined(__mc680x0__)
unsigned
char
overflow
:
4
,
flags:
4
;
#else
#error "Adjust this structure to match your CPU"
#endif
#endif
unsigned
char
full_char
;
unsigned
char
full_char
;
}
x
;
}
x
;
unsigned
long
data
[
9
];
unsigned
long
data
[
9
];
...
@@ -63,8 +72,17 @@ struct options {
...
@@ -63,8 +72,17 @@ struct options {
struct
iphdr
{
struct
iphdr
{
#if defined(__i386__)
unsigned
char
ihl
:
4
,
unsigned
char
ihl
:
4
,
version:
4
;
version:
4
;
#else
#if defined (__mc680x0__)
unsigned
char
version
:
4
,
ihl:
4
;
#else
#error "Adjust this structure to match your CPU"
#endif
#endif
unsigned
char
tos
;
unsigned
char
tos
;
unsigned
short
tot_len
;
unsigned
short
tot_len
;
unsigned
short
id
;
unsigned
short
id
;
...
...
include/linux/mtio.h
View file @
16119ae5
...
@@ -88,6 +88,7 @@ struct mtget {
...
@@ -88,6 +88,7 @@ struct mtget {
#define MT_ISDDS1 0x51
/* DDS device without partitions */
#define MT_ISDDS1 0x51
/* DDS device without partitions */
#define MT_ISDDS2 0x52
/* DDS device with partitions */
#define MT_ISDDS2 0x52
/* DDS device with partitions */
#define MT_ISSCSI1 0x71
/* Generic ANSI SCSI-1 tape unit */
#define MT_ISSCSI1 0x71
/* Generic ANSI SCSI-1 tape unit */
#define MT_ISSCSI2 0x72
/* Generic ANSI SCSI-2 tape unit */
struct
mt_tape_info
{
struct
mt_tape_info
{
long
t_type
;
/* device type id (mt_type) */
long
t_type
;
/* device type id (mt_type) */
...
@@ -106,6 +107,7 @@ struct mt_tape_info {
...
@@ -106,6 +107,7 @@ struct mt_tape_info {
{MT_ISWT5099EEN24, "Wangtek 5099-een24, 60MB"}, \
{MT_ISWT5099EEN24, "Wangtek 5099-een24, 60MB"}, \
{MT_ISEVEREX_FT40A, "Everex FT40A, QIC-40"}, \
{MT_ISEVEREX_FT40A, "Everex FT40A, QIC-40"}, \
{MT_ISSCSI1, "Generic SCSI-1 tape"}, \
{MT_ISSCSI1, "Generic SCSI-1 tape"}, \
{MT_ISSCSI2, "Generic SCSI-2 tape"}, \
{0, NULL} \
{0, NULL} \
}
}
...
@@ -152,5 +154,22 @@ struct mtpos {
...
@@ -152,5 +154,22 @@ struct mtpos {
* I think DDS drives are DAT drives.
* I think DDS drives are DAT drives.
*/
*/
/* SCSI-tape specific definitions */
#define MT_ST_BLKSIZE_SHIFT 0
#define MT_ST_BLKSIZE_MASK 0xffffff
#define MT_ST_DENSITY_SHIFT 24
#define MT_ST_DENSITY_MASK 0xff000000
#define MT_ST_SOFTERR_SHIFT 0
#define MT_ST_SOFTERR_MASK 0xffff
#define MT_ST_OPTIONS 0xf0000000
#define MT_ST_BOOLEANS 0x10000000
#define MT_ST_WRITE_THRESHOLD 0x20000000
#define MT_ST_BUFFER_WRITES 0x1
#define MT_ST_ASYNC_WRITES 0x2
#define MT_ST_READ_AHEAD 0x4
#define MT_ST_DEBUGGING 0x8
#endif
/* _LINUX_MTIO_H */
#endif
/* _LINUX_MTIO_H */
include/linux/netdevice.h
View file @
16119ae5
...
@@ -11,6 +11,7 @@
...
@@ -11,6 +11,7 @@
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Corey Minyard <wf-rch!minyard@relay.EU.net>
* Corey Minyard <wf-rch!minyard@relay.EU.net>
* Donald J. Becker, <becker@super.org>
* Donald J. Becker, <becker@super.org>
* Alan Cox, <A.Cox@swansea.ac.uk>
*
*
* This program is free software; you can redistribute it and/or
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* modify it under the terms of the GNU General Public License
...
@@ -34,7 +35,7 @@
...
@@ -34,7 +35,7 @@
#define IS_MYADDR 1
/* address is (one of) our own */
#define IS_MYADDR 1
/* address is (one of) our own */
#define IS_LOOPBACK 2
/* address is for LOOPBACK */
#define IS_LOOPBACK 2
/* address is for LOOPBACK */
#define IS_BROADCAST 3
/* address is a valid broadcast */
#define IS_BROADCAST 3
/* address is a valid broadcast */
#define IS_INVBCAST 4
/* Wrong netmask bcast not for us */
#define IS_INVBCAST 4
/* Wrong netmask bcast not for us
(unused)
*/
/*
/*
* The DEVICE structure.
* The DEVICE structure.
...
@@ -52,7 +53,7 @@ struct device
...
@@ -52,7 +53,7 @@ struct device
*/
*/
char
*
name
;
char
*
name
;
/* I/O specific fields.
These will be moved to DDI soon.
*/
/* I/O specific fields. */
unsigned
long
rmem_end
;
/* shmem "recv" end */
unsigned
long
rmem_end
;
/* shmem "recv" end */
unsigned
long
rmem_start
;
/* shmem "recv" start */
unsigned
long
rmem_start
;
/* shmem "recv" start */
unsigned
long
mem_end
;
/* sahared mem end */
unsigned
long
mem_end
;
/* sahared mem end */
...
@@ -65,12 +66,6 @@ struct device
...
@@ -65,12 +66,6 @@ struct device
tbusy
,
/* transmitter busy */
tbusy
,
/* transmitter busy */
interrupt
;
/* interrupt arrived */
interrupt
;
/* interrupt arrived */
/*
* Another mistake.
* This points to the next device in the "dev" chain. It will
* be moved to the "invisible" part of the structure as soon as
* it has been cleaned up. -FvK
*/
struct
device
*
next
;
struct
device
*
next
;
/* The device initialization function. Called only once. */
/* The device initialization function. Called only once. */
...
@@ -135,6 +130,8 @@ struct device
...
@@ -135,6 +130,8 @@ struct device
int
num_addrs
,
void
*
addrs
);
int
num_addrs
,
void
*
addrs
);
#define HAVE_SET_MAC_ADDR
#define HAVE_SET_MAC_ADDR
int
(
*
set_mac_address
)(
struct
device
*
dev
,
void
*
addr
);
int
(
*
set_mac_address
)(
struct
device
*
dev
,
void
*
addr
);
#define HAVE_PRIVATE_IOCTL
int
(
*
do_ioctl
)(
struct
device
*
dev
,
struct
ifreq
*
ifr
);
};
};
...
...
include/linux/sockios.h
View file @
16119ae5
...
@@ -67,4 +67,21 @@
...
@@ -67,4 +67,21 @@
#define SIOCGARP 0x8951
/* get ARP table entry */
#define SIOCGARP 0x8951
/* get ARP table entry */
#define SIOCSARP 0x8952
/* set ARP table entry */
#define SIOCSARP 0x8952
/* set ARP table entry */
/* RARP cache control calls. */
#define SIOCDRARP 0x8960
/* delete RARP table entry */
#define SIOCGRARP 0x8961
/* get RARP table entry */
#define SIOCSRARP 0x8962
/* set RARP table entry */
/* Device private ioctl calls */
/*
* These 16 ioctls are available to devices via the do_ioctl() device
* vector. Each device should include this file and redefine these names
* as their own. Because these are device dependant it is a good idea
* _NOT_ to issue them to random objects and hope.
*/
#define SIOCDEVPRIVATE 0x89F0
/* to 89FF */
#endif
/* _LINUX_SOCKIOS_H */
#endif
/* _LINUX_SOCKIOS_H */
include/linux/tcp.h
View file @
16119ae5
...
@@ -26,6 +26,7 @@ struct tcphdr {
...
@@ -26,6 +26,7 @@ struct tcphdr {
unsigned
short
dest
;
unsigned
short
dest
;
unsigned
long
seq
;
unsigned
long
seq
;
unsigned
long
ack_seq
;
unsigned
long
ack_seq
;
#if defined(__i386__)
unsigned
short
res1
:
4
,
unsigned
short
res1
:
4
,
doff:
4
,
doff:
4
,
fin:
1
,
fin:
1
,
...
@@ -35,6 +36,21 @@ struct tcphdr {
...
@@ -35,6 +36,21 @@ struct tcphdr {
ack:
1
,
ack:
1
,
urg:
1
,
urg:
1
,
res2:
2
;
res2:
2
;
#else
#if defined(__mc680x0__)
unsigned
short
res2
:
2
,
urg:
1
,
ack:
1
,
psh:
1
,
rst:
1
,
syn:
1
,
fin:
1
,
doff:
4
,
res1:
4
;
#else
#error "Adjust this structure for your cpu alignment rules"
#endif
#endif
unsigned
short
window
;
unsigned
short
window
;
unsigned
short
check
;
unsigned
short
check
;
unsigned
short
urg_ptr
;
unsigned
short
urg_ptr
;
...
@@ -45,17 +61,14 @@ enum {
...
@@ -45,17 +61,14 @@ enum {
TCP_ESTABLISHED
=
1
,
TCP_ESTABLISHED
=
1
,
TCP_SYN_SENT
,
TCP_SYN_SENT
,
TCP_SYN_RECV
,
TCP_SYN_RECV
,
#if 0
TCP_CLOSING, /* not a valid state, just a seperator so we can use
< tcp_closing or > tcp_closing for checks. */
#endif
TCP_FIN_WAIT1
,
TCP_FIN_WAIT1
,
TCP_FIN_WAIT2
,
TCP_FIN_WAIT2
,
TCP_TIME_WAIT
,
TCP_TIME_WAIT
,
TCP_CLOSE
,
TCP_CLOSE
,
TCP_CLOSE_WAIT
,
TCP_CLOSE_WAIT
,
TCP_LAST_ACK
,
TCP_LAST_ACK
,
TCP_LISTEN
TCP_LISTEN
,
TCP_CLOSING
/* now a valid state */
};
};
#endif
/* _LINUX_TCP_H */
#endif
/* _LINUX_TCP_H */
init/main.c
View file @
16119ae5
...
@@ -84,6 +84,7 @@ extern void bmouse_setup(char *str, int *ints);
...
@@ -84,6 +84,7 @@ extern void bmouse_setup(char *str, int *ints);
extern
void
eth_setup
(
char
*
str
,
int
*
ints
);
extern
void
eth_setup
(
char
*
str
,
int
*
ints
);
extern
void
xd_setup
(
char
*
str
,
int
*
ints
);
extern
void
xd_setup
(
char
*
str
,
int
*
ints
);
extern
void
mcd_setup
(
char
*
str
,
int
*
ints
);
extern
void
mcd_setup
(
char
*
str
,
int
*
ints
);
extern
void
st_setup
(
char
*
str
,
int
*
ints
);
extern
void
st0x_setup
(
char
*
str
,
int
*
ints
);
extern
void
st0x_setup
(
char
*
str
,
int
*
ints
);
extern
void
tmc8xx_setup
(
char
*
str
,
int
*
ints
);
extern
void
tmc8xx_setup
(
char
*
str
,
int
*
ints
);
extern
void
t128_setup
(
char
*
str
,
int
*
ints
);
extern
void
t128_setup
(
char
*
str
,
int
*
ints
);
...
@@ -176,6 +177,9 @@ struct {
...
@@ -176,6 +177,9 @@ struct {
#ifdef CONFIG_BLK_DEV_HD
#ifdef CONFIG_BLK_DEV_HD
{
"hd="
,
hd_setup
},
{
"hd="
,
hd_setup
},
#endif
#endif
#ifdef CONFIG_CHR_DEV_ST
{
"st="
,
st_setup
},
#endif
#ifdef CONFIG_BUSMOUSE
#ifdef CONFIG_BUSMOUSE
{
"bmouse="
,
bmouse_setup
},
{
"bmouse="
,
bmouse_setup
},
#endif
#endif
...
...
kernel/sys.c
View file @
16119ae5
...
@@ -227,7 +227,7 @@ asmlinkage int sys_setregid(gid_t rgid, gid_t egid)
...
@@ -227,7 +227,7 @@ asmlinkage int sys_setregid(gid_t rgid, gid_t egid)
}
}
}
}
if
(
rgid
!=
(
gid_t
)
-
1
||
if
(
rgid
!=
(
gid_t
)
-
1
||
egid
!=
(
gid_t
)
-
1
&&
egid
!=
old_rgid
)
(
egid
!=
(
gid_t
)
-
1
&&
egid
!=
old_rgid
)
)
current
->
sgid
=
current
->
egid
;
current
->
sgid
=
current
->
egid
;
return
0
;
return
0
;
}
}
...
@@ -314,7 +314,7 @@ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid)
...
@@ -314,7 +314,7 @@ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid)
}
}
}
}
if
(
ruid
!=
(
uid_t
)
-
1
||
if
(
ruid
!=
(
uid_t
)
-
1
||
euid
!=
(
uid_t
)
-
1
&&
euid
!=
old_ruid
)
(
euid
!=
(
uid_t
)
-
1
&&
euid
!=
old_ruid
)
)
current
->
suid
=
current
->
euid
;
current
->
suid
=
current
->
euid
;
return
0
;
return
0
;
}
}
...
...
kernel/vm86.c
View file @
16119ae5
...
@@ -31,8 +31,8 @@
...
@@ -31,8 +31,8 @@
/*
/*
* 8- and 16-bit register defines..
* 8- and 16-bit register defines..
*/
*/
#define AL(regs) (((unsigned char *)
((regs)->eax))[0])
#define AL(regs) (((unsigned char *)
&
((regs)->eax))[0])
#define AH(regs) (((unsigned char *)
((regs)->eax))[1])
#define AH(regs) (((unsigned char *)
&
((regs)->eax))[1])
#define IP(regs) (*(unsigned short *)&((regs)->eip))
#define IP(regs) (*(unsigned short *)&((regs)->eip))
#define SP(regs) (*(unsigned short *)&((regs)->esp))
#define SP(regs) (*(unsigned short *)&((regs)->esp))
...
@@ -289,9 +289,8 @@ static void do_int(struct vm86_regs *regs, int i, unsigned char * ssp, unsigned
...
@@ -289,9 +289,8 @@ static void do_int(struct vm86_regs *regs, int i, unsigned char * ssp, unsigned
if
(
seg
==
BIOSSEG
||
regs
->
cs
==
BIOSSEG
||
if
(
seg
==
BIOSSEG
||
regs
->
cs
==
BIOSSEG
||
is_revectored
(
i
,
&
current
->
vm86_info
->
int_revectored
))
is_revectored
(
i
,
&
current
->
vm86_info
->
int_revectored
))
return_to_32bit
(
regs
,
VM86_INTx
+
(
i
<<
8
));
return_to_32bit
(
regs
,
VM86_INTx
+
(
i
<<
8
));
if
(
i
==
0x21
&&
is_revectored
(
AH
(
regs
),
&
current
->
vm86_info
->
int21_revectored
))
{
if
(
i
==
0x21
&&
is_revectored
(
AH
(
regs
),
&
current
->
vm86_info
->
int21_revectored
))
return_to_32bit
(
regs
,
VM86_INTx
+
(
i
<<
8
));
return_to_32bit
(
regs
,
VM86_INTx
+
(
i
<<
8
));
}
pushw
(
ssp
,
sp
,
get_vflags
(
regs
));
pushw
(
ssp
,
sp
,
get_vflags
(
regs
));
pushw
(
ssp
,
sp
,
regs
->
cs
);
pushw
(
ssp
,
sp
,
regs
->
cs
);
pushw
(
ssp
,
sp
,
IP
(
regs
));
pushw
(
ssp
,
sp
,
IP
(
regs
));
...
@@ -305,7 +304,15 @@ static void do_int(struct vm86_regs *regs, int i, unsigned char * ssp, unsigned
...
@@ -305,7 +304,15 @@ static void do_int(struct vm86_regs *regs, int i, unsigned char * ssp, unsigned
void
handle_vm86_debug
(
struct
vm86_regs
*
regs
,
long
error_code
)
void
handle_vm86_debug
(
struct
vm86_regs
*
regs
,
long
error_code
)
{
{
do_int
(
regs
,
3
,
(
unsigned
char
*
)
(
regs
->
ss
<<
4
),
SP
(
regs
));
#if 0
do_int(regs, 1, (unsigned char *) (regs->ss << 4), SP(regs));
#else
if
(
current
->
flags
&
PF_PTRACED
)
current
->
blocked
&=
~
(
1
<<
(
SIGTRAP
-
1
));
send_sig
(
SIGTRAP
,
current
,
1
);
current
->
tss
.
trap_no
=
1
;
current
->
tss
.
error_code
=
error_code
;
#endif
}
}
void
handle_vm86_fault
(
struct
vm86_regs
*
regs
,
long
error_code
)
void
handle_vm86_fault
(
struct
vm86_regs
*
regs
,
long
error_code
)
...
...
net/inet/arp.c
View file @
16119ae5
...
@@ -25,6 +25,7 @@
...
@@ -25,6 +25,7 @@
* Alan Cox : Allow >4K in /proc
* Alan Cox : Allow >4K in /proc
* Alan Cox : Make ARP add its own protocol entry
* Alan Cox : Make ARP add its own protocol entry
*
*
* Ross Martin : Rewrote arp_rcv() and arp_get_info()
*/
*/
#include <linux/types.h>
#include <linux/types.h>
...
@@ -69,7 +70,7 @@ struct arp_table
...
@@ -69,7 +70,7 @@ struct arp_table
unsigned
long
ip
;
/* ip address of entry */
unsigned
long
ip
;
/* ip address of entry */
unsigned
char
ha
[
MAX_ADDR_LEN
];
/* Hardware address */
unsigned
char
ha
[
MAX_ADDR_LEN
];
/* Hardware address */
unsigned
char
hlen
;
/* Length of hardware address */
unsigned
char
hlen
;
/* Length of hardware address */
unsigned
char
htype
;
/* Type of hardware in use */
unsigned
short
htype
;
/* Type of hardware in use */
struct
device
*
dev
;
/* Device the entry is tied to */
struct
device
*
dev
;
/* Device the entry is tied to */
/*
/*
...
@@ -246,8 +247,9 @@ static void arp_release_entry(struct arp_table *entry)
...
@@ -246,8 +247,9 @@ static void arp_release_entry(struct arp_table *entry)
* message.
* message.
*/
*/
static
void
arp_send
(
int
type
,
unsigned
long
dest_ip
,
struct
device
*
dev
,
void
arp_send
(
int
type
,
int
ptype
,
unsigned
long
dest_ip
,
unsigned
long
src_ip
,
unsigned
char
*
dest_hw
,
unsigned
char
*
src_hw
)
struct
device
*
dev
,
unsigned
long
src_ip
,
unsigned
char
*
dest_hw
,
unsigned
char
*
src_hw
)
{
{
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
struct
arphdr
*
arp
;
struct
arphdr
*
arp
;
...
@@ -280,7 +282,7 @@ static void arp_send(int type, unsigned long dest_ip, struct device *dev,
...
@@ -280,7 +282,7 @@ static void arp_send(int type, unsigned long dest_ip, struct device *dev,
* Fill the device header for the ARP frame
* Fill the device header for the ARP frame
*/
*/
dev
->
hard_header
(
skb
->
data
,
dev
,
ETH_P_ARP
,
dest_hw
?
dest_hw
:
dev
->
broadcast
,
src_hw
?
src_hw
:
NULL
,
skb
->
len
,
skb
);
dev
->
hard_header
(
skb
->
data
,
dev
,
ptype
,
dest_hw
?
dest_hw
:
dev
->
broadcast
,
src_hw
?
src_hw
:
NULL
,
skb
->
len
,
skb
);
/* Fill out the arp protocol part. */
/* Fill out the arp protocol part. */
arp
=
(
struct
arphdr
*
)
(
skb
->
data
+
dev
->
hard_header_len
);
arp
=
(
struct
arphdr
*
)
(
skb
->
data
+
dev
->
hard_header_len
);
...
@@ -348,8 +350,8 @@ static void arp_expire_request (unsigned long arg)
...
@@ -348,8 +350,8 @@ static void arp_expire_request (unsigned long arg)
entry
->
timer
.
expires
=
ARP_RES_TIME
;
entry
->
timer
.
expires
=
ARP_RES_TIME
;
add_timer
(
&
entry
->
timer
);
add_timer
(
&
entry
->
timer
);
restore_flags
(
flags
);
restore_flags
(
flags
);
arp_send
(
ARPOP_REQUEST
,
ip
,
dev
,
dev
->
pa_addr
,
NULL
,
arp_send
(
ARPOP_REQUEST
,
ETH_P_ARP
,
ip
,
dev
,
dev
->
pa_addr
,
dev
->
dev_addr
);
NULL
,
dev
->
dev_addr
);
return
;
return
;
}
}
...
@@ -463,166 +465,249 @@ void arp_destroy(unsigned long ip_addr, int force)
...
@@ -463,166 +465,249 @@ void arp_destroy(unsigned long ip_addr, int force)
int
arp_rcv
(
struct
sk_buff
*
skb
,
struct
device
*
dev
,
struct
packet_type
*
pt
)
int
arp_rcv
(
struct
sk_buff
*
skb
,
struct
device
*
dev
,
struct
packet_type
*
pt
)
{
{
/*
/*
* We shouldn't use this type conversion. Check later.
* We shouldn't use this type conversion. Check later.
*/
*/
struct
arphdr
*
arp
=
(
struct
arphdr
*
)
skb
->
h
.
raw
;
struct
arphdr
*
arp
=
(
struct
arphdr
*
)
skb
->
h
.
raw
;
unsigned
char
*
arp_ptr
=
(
unsigned
char
*
)(
arp
+
1
);
unsigned
char
*
arp_ptr
=
(
unsigned
char
*
)(
arp
+
1
);
struct
arp_table
*
entry
;
struct
arp_table
*
entry
;
struct
arp_table
*
proxy_entry
;
struct
arp_table
*
proxy_entry
;
int
addr_hint
;
int
addr_hint
,
hlen
,
htype
;
unsigned
long
hash
;
unsigned
long
hash
,
dest_hash
;
unsigned
char
ha
[
MAX_ADDR_LEN
];
/* So we can enable ints again. */
unsigned
char
ha
[
MAX_ADDR_LEN
];
/* So we can enable ints again. */
long
sip
,
tip
;
long
sip
,
tip
;
unsigned
char
*
sha
,
*
tha
;
unsigned
char
*
sha
,
*
tha
;
/*
/*
* If this test doesn't pass, its not IP, or we should ignore it anyway
* The hardware length of the packet should match the hardware length
*/
* of the device. Similarly, the hardware types should match. The
* device should be ARP-able. Also, if pln is not 4, then the lookup
if
(
arp
->
ar_hln
!=
dev
->
addr_len
||
dev
->
type
!=
ntohs
(
arp
->
ar_hrd
)
||
dev
->
flags
&
IFF_NOARP
)
* is not from an IP number. We can't currently handle this, so toss
* it.
*/
if
(
arp
->
ar_hln
!=
dev
->
addr_len
||
dev
->
type
!=
ntohs
(
arp
->
ar_hrd
)
||
dev
->
flags
&
IFF_NOARP
||
arp
->
ar_pln
!=
4
)
{
{
kfree_skb
(
skb
,
FREE_READ
);
kfree_skb
(
skb
,
FREE_READ
);
return
0
;
return
0
;
}
}
/*
/*
* For now we will only deal with IP addresses.
* Another test.
*/
* The logic here is that the protocol being looked up by arp should
if
(
* match the protocol the device speaks. If it doesn't, there is a
* problem, so toss the packet.
*/
switch
(
dev
->
type
)
{
#ifdef CONFIG_AX25
#ifdef CONFIG_AX25
(
arp
->
ar_pro
!=
htons
(
AX25_P_IP
)
&&
dev
->
type
==
ARPHRD_AX25
)
||
case
ARPHRD_AX25
:
if
(
arp
->
ar_pro
!=
htons
(
AX25_P_IP
))
{
kfree_skb
(
skb
,
FREE_READ
);
return
0
;
}
break
;
#endif
#endif
(
arp
->
ar_pro
!=
htons
(
ETH_P_IP
)
&&
dev
->
type
!=
ARPHRD_AX25
)
case
ARPHRD_ETHER
:
||
arp
->
ar_pln
!=
4
)
if
(
arp
->
ar_pro
!=
htons
(
ETH_P_IP
))
{
{
/* This packet is not for us. Remove it. */
kfree_skb
(
skb
,
FREE_READ
);
kfree_skb
(
skb
,
FREE_READ
);
return
0
;
return
0
;
}
break
;
default:
printk
(
"ARP: dev->type mangled!
\n
"
);
kfree_skb
(
skb
,
FREE_READ
);
return
0
;
}
}
/*
/*
* Extract variable width fields
* Extract fields
*/
*/
hlen
=
dev
->
addr_len
;
htype
=
dev
->
type
;
sha
=
arp_ptr
;
sha
=
arp_ptr
;
arp_ptr
+=
dev
->
addr_
len
;
arp_ptr
+=
h
len
;
memcpy
(
&
sip
,
arp_ptr
,
4
);
memcpy
(
&
sip
,
arp_ptr
,
4
);
arp_ptr
+=
4
;
arp_ptr
+=
4
;
tha
=
arp_ptr
;
tha
=
arp_ptr
;
arp_ptr
+=
dev
->
addr_
len
;
arp_ptr
+=
h
len
;
memcpy
(
&
tip
,
arp_ptr
,
4
);
memcpy
(
&
tip
,
arp_ptr
,
4
);
/*
* Check for bad requests for 127.0.0.1. If this is one such, delete it.
*/
if
(
tip
==
INADDR_LOOPBACK
)
{
kfree_skb
(
skb
,
FREE_READ
);
return
0
;
}
/*
/*
* Process entry
* Process entry. The idea here is we want to send a reply if it is a
*/
* request for us or if it is a request for someone else that we hold
* a proxy for. We want to add an entry to our cache if it is a reply
* to us or if it is a request for our address.
* (The assumption for this last is that if someone is requesting our
* address, they are probably intending to talk to us, so it saves time
* if we cache their address. Their address is also probably not in
* our cache, since ours is not in their cache.)
*
* Putting this another way, we only care about replies if they are to
* us, in which case we add them to the cache. For requests, we care
* about those for us and those for our proxies. We reply to both,
* and in the case of requests for us we add the requester to the arp
* cache.
*/
addr_hint
=
ip_chk_addr
(
tip
);
addr_hint
=
ip_chk_addr
(
tip
);
hash
=
HASH
(
sip
);
if
(
arp
->
ar_op
==
htons
(
ARPOP_REPLY
))
proxy_entry
=
NULL
;
if
(
proxies
!=
0
&&
addr_hint
!=
IS_MYADDR
)
{
{
unsigned
long
dest_hash
=
HASH
(
tip
);
if
(
addr_hint
!=
IS_MYADDR
)
cli
();
proxy_entry
=
arp_tables
[
dest_hash
];
while
(
proxy_entry
!=
NULL
)
{
{
if
(
proxy_entry
->
ip
==
tip
&&
proxy_entry
->
htype
==
arp
->
ar_hrd
)
/*
break
;
* Replies to other machines get tossed.
proxy_entry
=
proxy_entry
->
next
;
*/
kfree_skb
(
skb
,
FREE_READ
);
return
0
;
}
}
if
(
proxy_entry
&&
(
proxy_entry
->
flags
&
ATF_PUBL
))
/*
memcpy
(
ha
,
proxy_entry
->
ha
,
dev
->
addr_len
);
* Fall through to code below that adds sender to cache.
else
*/
proxy_entry
=
NULL
;
}
}
else
else
cli
();
{
/*
* It is now an arp request
*/
if
(
addr_hint
!=
IS_MYADDR
)
{
/*
* To get in here, it is a request for someone else. We need to
* check if that someone else is one of our proxies. If it isn't,
* we can toss it.
*/
if
(
proxies
==
0
)
{
kfree_skb
(
skb
,
FREE_READ
);
return
0
;
}
dest_hash
=
HASH
(
tip
);
cli
();
for
(
proxy_entry
=
arp_tables
[
dest_hash
];
proxy_entry
;
proxy_entry
=
proxy_entry
->
next
)
{
if
(
proxy_entry
->
ip
==
tip
&&
proxy_entry
->
htype
==
htype
)
break
;
}
if
(
proxy_entry
&&
(
proxy_entry
->
flags
&
ATF_PUBL
))
{
memcpy
(
ha
,
proxy_entry
->
ha
,
hlen
);
sti
();
arp_send
(
ARPOP_REPLY
,
ETH_P_ARP
,
sip
,
dev
,
tip
,
sha
,
ha
);
kfree_skb
(
skb
,
FREE_READ
);
return
0
;
}
else
{
sti
();
kfree_skb
(
skb
,
FREE_READ
);
return
0
;
}
}
else
{
/*
* To get here, it must be an arp request for us. We need to reply.
*/
arp_send
(
ARPOP_REPLY
,
ETH_P_ARP
,
sip
,
dev
,
tip
,
sha
,
dev
->
dev_addr
);
}
}
for
(
entry
=
arp_tables
[
hash
];
entry
!=
NULL
;
entry
=
entry
->
next
)
if
(
entry
->
ip
==
sip
)
/*
* Now all replies are handled. Next, anything that falls through to here
* needs to be added to the arp cache, or have its entry updated if it is
* there.
*/
hash
=
HASH
(
sip
);
cli
();
for
(
entry
=
arp_tables
[
hash
];
entry
;
entry
=
entry
->
next
)
if
(
entry
->
ip
==
sip
&&
entry
->
htype
==
htype
)
break
;
break
;
if
(
entry
!=
NULL
)
if
(
entry
)
{
{
int
old_flags
=
entry
->
flags
;
/*
memcpy
(
entry
->
ha
,
sha
,
arp
->
ar_hln
);
* Entry found; update it.
entry
->
hlen
=
arp
->
ar_hln
;
*/
/* This seems sensible but not everyone gets it right ! */
memcpy
(
entry
->
ha
,
sha
,
hlen
);
entry
->
htype
=
ntohs
(
arp
->
ar_hrd
);
entry
->
hlen
=
hlen
;
if
(
entry
->
htype
==
0
)
entry
->
htype
=
dev
->
type
;
/* Not good but we have no choice */
entry
->
last_used
=
jiffies
;
entry
->
last_used
=
jiffies
;
if
(
!
(
entry
->
flags
&
ATF_COM
))
if
(
!
(
entry
->
flags
&
ATF_COM
))
{
{
/*
* This entry was incomplete. Delete the retransmit timer
* and switch to complete status.
*/
del_timer
(
&
entry
->
timer
);
del_timer
(
&
entry
->
timer
);
entry
->
flags
|=
ATF_COM
;
entry
->
flags
|=
ATF_COM
;
}
sti
();
sti
();
/*
if
(
!
(
old_flags
&
ATF_COM
))
* Send out waiting packets. We might have problems, if someone is
{
* manually removing entries right now -- entry might become invalid
/* Send out waiting packets. We might have problems,
* underneath us.
if someone is manually removing entries right now.
*/
I will fix this one. */
arp_send_q
(
entry
,
sha
);
arp_send_q
(
entry
,
sha
);
}
}
if
(
addr_hint
!=
IS_MYADDR
&&
proxy_entry
==
NULL
)
else
{
{
kfree_skb
(
skb
,
FREE_READ
);
sti
();
return
0
;
}
}
}
}
else
else
{
{
if
(
addr_hint
!=
IS_MYADDR
&&
proxy_entry
==
NULL
)
/*
{
* No entry found. Need to add a new entry to the arp table.
/* We don't do "smart arp" and cache all possible
*/
entries. That just makes us more work. */
entry
=
(
struct
arp_table
*
)
kmalloc
(
sizeof
(
struct
arp_table
),
GFP_ATOMIC
);
sti
();
if
(
entry
==
NULL
)
kfree_skb
(
skb
,
FREE_READ
);
return
0
;
}
entry
=
(
struct
arp_table
*
)
kmalloc
(
sizeof
(
struct
arp_table
),
GFP_ATOMIC
);
if
(
entry
==
NULL
)
{
{
sti
();
sti
();
kfree_skb
(
skb
,
FREE_READ
);
printk
(
"ARP: no memory for new arp entry
\n
"
);
printk
(
"ARP: no memory for new arp entry
\n
"
);
kfree_skb
(
skb
,
FREE_READ
);
return
0
;
return
0
;
}
}
entry
->
ip
=
sip
;
entry
->
ip
=
sip
;
entry
->
hlen
=
arp
->
ar_hl
n
;
entry
->
hlen
=
hle
n
;
entry
->
htype
=
arp
->
ar_hrd
;
entry
->
htype
=
htype
;
entry
->
flags
=
ATF_COM
;
entry
->
flags
=
ATF_COM
;
memcpy
(
entry
->
ha
,
sha
,
arp
->
ar_hl
n
);
memcpy
(
entry
->
ha
,
sha
,
hle
n
);
entry
->
last_used
=
jiffies
;
entry
->
last_used
=
jiffies
;
entry
->
next
=
arp_tables
[
hash
];
arp_tables
[
hash
]
=
entry
;
entry
->
dev
=
skb
->
dev
;
entry
->
dev
=
skb
->
dev
;
skb_queue_head_init
(
&
entry
->
skb
);
skb_queue_head_init
(
&
entry
->
skb
);
sti
();
entry
->
next
=
arp_tables
[
hash
];
}
arp_tables
[
hash
]
=
entry
;
/* From here on, interrupts are enabled. Never touch entry->..
any more. */
if
(
arp
->
ar_op
!=
htons
(
ARPOP_REQUEST
)
sti
();
||
tip
==
INADDR_LOOPBACK
)
{
/* This wasn't a request, or some bad request for 127.0.0.1
has made its way to the net, so delete it. */
kfree_skb
(
skb
,
FREE_READ
);
return
0
;
}
}
/* Either we respond with our own hw address, or we do proxy arp for
/*
another machine. */
* Replies have been sent, and entries have been added. All done.
arp_send
(
ARPOP_REPLY
,
sip
,
dev
,
tip
,
sha
,
*/
(
addr_hint
==
IS_MYADDR
)
?
dev
->
dev_addr
:
ha
);
kfree_skb
(
skb
,
FREE_READ
);
kfree_skb
(
skb
,
FREE_READ
);
return
0
;
return
0
;
}
}
...
@@ -726,7 +811,8 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
...
@@ -726,7 +811,8 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
* If we didn't find an entry, we will try to send an ARP packet.
* If we didn't find an entry, we will try to send an ARP packet.
*/
*/
arp_send
(
ARPOP_REQUEST
,
paddr
,
dev
,
saddr
,
NULL
,
dev
->
dev_addr
);
arp_send
(
ARPOP_REQUEST
,
ETH_P_ARP
,
paddr
,
dev
,
saddr
,
NULL
,
dev
->
dev_addr
);
return
1
;
return
1
;
}
}
...
@@ -734,51 +820,66 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
...
@@ -734,51 +820,66 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
/*
/*
* Write the contents of the ARP cache to a PROCfs file.
* Write the contents of the ARP cache to a PROCfs file.
*
* Will change soon to ASCII format
*/
*/
#define HBUFFERLEN 30
int
arp_get_info
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
)
int
arp_get_info
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
)
{
{
struct
arp_table
*
entry
;
struct
arpreq
*
req
=
(
struct
arpreq
*
)
buffer
;
int
i
;
off_t
pos
=
0
;
off_t
begin
=
0
;
int
len
=
0
;
int
len
=
0
;
off_t
begin
=
0
;
off_t
pos
=
0
;
int
size
;
struct
arp_table
*
entry
;
char
hbuffer
[
HBUFFERLEN
];
int
i
,
j
,
k
;
const
char
hexbuf
[]
=
"0123456789ABCDEF"
;
size
=
sprintf
(
buffer
,
"IP address HW type Flags HW address
\n
"
);
pos
+=
size
;
len
+=
size
;
cli
();
cli
();
/* Loop over the ARP table and copy structures to the buffer. */
for
(
i
=
0
;
i
<
ARP_TABLE_SIZE
;
i
++
)
for
(
i
=
0
;
i
<
ARP_TABLE_SIZE
;
i
++
)
{
{
for
(
entry
=
arp_tables
[
i
];
entry
;
entry
=
entry
->
next
)
for
(
entry
=
arp_tables
[
i
];
entry
!=
NULL
;
entry
=
entry
->
next
)
{
{
memset
(
req
,
0
,
sizeof
(
struct
arpreq
));
/*
req
->
arp_pa
.
sa_family
=
AF_INET
;
* Convert hardware address to XX:XX:XX:XX ... form.
memcpy
(
req
->
arp_pa
.
sa_data
,
&
entry
->
ip
,
4
);
*/
req
->
arp_ha
.
sa_family
=
entry
->
htype
;
for
(
k
=
0
,
j
=
0
;
k
<
HBUFFERLEN
-
3
&&
j
<
entry
->
hlen
;
j
++
)
memcpy
(
req
->
arp_ha
.
sa_data
,
&
entry
->
ha
,
MAX_ADDR_LEN
);
{
req
->
arp_flags
=
entry
->
flags
;
hbuffer
[
k
++
]
=
hexbuf
[
(
entry
->
ha
[
j
]
>>
4
)
&
15
];
req
++
;
hbuffer
[
k
++
]
=
hexbuf
[
entry
->
ha
[
j
]
&
15
];
len
+=
sizeof
(
struct
arpreq
);
hbuffer
[
k
++
]
=
':'
;
pos
+=
sizeof
(
struct
arpreq
);
}
hbuffer
[
--
k
]
=
0
;
size
=
sprintf
(
buffer
+
len
,
"%-17s0x%-10x0x%-10x%s
\n
"
,
in_ntoa
(
entry
->
ip
),
(
unsigned
int
)
entry
->
htype
,
entry
->
flags
,
hbuffer
);
len
+=
size
;
pos
=
begin
+
len
;
if
(
pos
<
offset
)
if
(
pos
<
offset
)
{
{
len
=
0
;
len
=
0
;
begin
=
pos
;
begin
=
pos
;
req
=
(
struct
arpreq
*
)
buffer
;
}
}
if
(
pos
>
offset
+
length
)
if
(
pos
>
offset
+
length
)
break
;
break
;
}
}
if
(
pos
>
offset
+
length
)
break
;
}
}
sti
();
sti
();
*
start
=
buffer
+
(
offset
-
begin
);
len
-=
(
offset
-
begin
);
*
start
=
buffer
+
(
offset
-
begin
);
/* Start of wanted data */
len
-=
(
offset
-
begin
);
/* Start slop */
if
(
len
>
length
)
if
(
len
>
length
)
len
=
length
;
len
=
length
;
/* Ending slop */
return
len
;
return
len
;
}
}
...
...
net/inet/arp.h
View file @
16119ae5
...
@@ -10,5 +10,8 @@ extern int arp_find(unsigned char *haddr, unsigned long paddr,
...
@@ -10,5 +10,8 @@ extern int arp_find(unsigned char *haddr, unsigned long paddr,
struct
device
*
dev
,
unsigned
long
saddr
,
struct
sk_buff
*
skb
);
struct
device
*
dev
,
unsigned
long
saddr
,
struct
sk_buff
*
skb
);
extern
int
arp_get_info
(
char
*
buffer
,
char
**
start
,
off_t
origin
,
int
length
);
extern
int
arp_get_info
(
char
*
buffer
,
char
**
start
,
off_t
origin
,
int
length
);
extern
int
arp_ioctl
(
unsigned
int
cmd
,
void
*
arg
);
extern
int
arp_ioctl
(
unsigned
int
cmd
,
void
*
arg
);
extern
void
arp_send
(
int
type
,
int
ptype
,
unsigned
long
dest_ip
,
struct
device
*
dev
,
unsigned
long
src_ip
,
unsigned
char
*
dest_hw
,
unsigned
char
*
src_hw
);
#endif
/* _ARP_H */
#endif
/* _ARP_H */
net/inet/ip.c
View file @
16119ae5
...
@@ -1273,7 +1273,7 @@ static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct
...
@@ -1273,7 +1273,7 @@ static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct
* Set up data on packet
* Set up data on packet
*/
*/
skb2
->
arp
=
skb
->
arp
;
skb2
->
arp
=
0
;
/*skb->arp;*/
skb2
->
free
=
skb
->
free
;
skb2
->
free
=
skb
->
free
;
skb2
->
len
=
len
+
hlen
;
skb2
->
len
=
len
+
hlen
;
skb2
->
h
.
raw
=
(
char
*
)
skb2
->
data
;
skb2
->
h
.
raw
=
(
char
*
)
skb2
->
data
;
...
@@ -1549,7 +1549,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
...
@@ -1549,7 +1549,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
ip_statistics
.
IpInReceives
++
;
ip_statistics
.
IpInReceives
++
;
DPRINTF
((
DBG_IP
,
"<<
\n
"
));
DPRINTF
((
DBG_IP
,
"<<
\n
"
));
/*
/*
* Tag the ip header of this packet so we can find it
* Tag the ip header of this packet so we can find it
*/
*/
...
...
net/inet/rarp.c
0 → 100644
View file @
16119ae5
/* linux/net/inet/rarp.c
*
* Copyright (C) 1994 by Ross Martin
* Based on linux/net/inet/arp.c, Copyright (C) 1994 by Florian La Roche
*
* This module implements the Reverse Address Resolution Protocol
* (RARP, RFC 903), which is used to convert low level addresses such
* as ethernet addresses into high level addresses such as IP addresses.
* The most common use of RARP is as a means for a diskless workstation
* to discover its IP address during a network boot.
*
**
*** WARNING:::::::::::::::::::::::::::::::::WARNING
****
***** SUN machines seem determined to boot solely from the person who
**** answered their RARP query. NEVER add a SUN to your RARP table
*** unless you have all the rest to boot the box from it.
**
*
* Currently, only ethernet address -> IP address is likely to work.
* (Is RARP ever used for anything else?)
*
* This code is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
*/
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/config.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/errno.h>
#include <linux/if_arp.h>
#include <linux/in.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <stdarg.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include "ip.h"
#include "route.h"
#include "protocol.h"
#include "tcp.h"
#include <linux/skbuff.h>
#include "sock.h"
#include "arp.h"
#include "rarp.h"
#ifdef CONFIG_AX25
#include "ax25.h"
#endif
#ifdef CONFIG_INET_RARP
/*
* This structure defines the RARP mapping cache. As long as we make
* changes in this structure, we keep interrupts off.
*/
struct
rarp_table
{
struct
rarp_table
*
next
;
/* Linked entry list */
unsigned
long
ip
;
/* ip address of entry */
unsigned
char
ha
[
MAX_ADDR_LEN
];
/* Hardware address */
unsigned
char
hlen
;
/* Length of hardware address */
unsigned
char
htype
;
/* Type of hardware in use */
struct
device
*
dev
;
/* Device the entry is tied to */
};
struct
rarp_table
*
rarp_tables
=
NULL
;
/*
* This structure defines an ethernet arp header, which is the same header
* that is used for rarp.
*/
struct
arphdr
{
unsigned
short
ar_hrd
;
/* format of hardware address */
unsigned
short
ar_pro
;
/* format of protocol address */
unsigned
char
ar_hln
;
/* length of hardware address */
unsigned
char
ar_pln
;
/* length of protocol address */
unsigned
short
ar_op
;
/* ARP opcode (command) */
#if 0
/*
* Ethernet looks like this : This bit is variable sized however...
*/
unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
unsigned char ar_sip[4]; /* sender IP address */
unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
unsigned char ar_tip[4]; /* target IP address */
#endif
};
static
struct
packet_type
rarp_packet_type
=
{
0
,
/* Should be: __constant_htons(ETH_P_RARP) - but this _doesn't_ come out constant! */
0
,
/* copy */
rarp_rcv
,
NULL
,
NULL
};
static
initflag
=
1
;
/*
* Called once when data first added to rarp cache with ioctl.
*/
static
void
rarp_init
(
void
)
{
/* Register the packet type */
rarp_packet_type
.
type
=
htons
(
ETH_P_RARP
);
dev_add_pack
(
&
rarp_packet_type
);
}
/*
* Release the memory for this entry.
*/
static
inline
void
rarp_release_entry
(
struct
rarp_table
*
entry
)
{
kfree_s
(
entry
,
sizeof
(
struct
rarp_table
));
return
;
}
/*
* Delete a RARP mapping entry in the cache.
*/
static
void
rarp_destroy
(
unsigned
long
ip_addr
)
{
struct
rarp_table
*
entry
;
struct
rarp_table
**
pentry
;
cli
();
pentry
=
&
rarp_tables
;
while
((
entry
=
*
pentry
)
!=
NULL
)
{
if
(
entry
->
ip
==
ip_addr
)
{
*
pentry
=
entry
->
next
;
sti
();
rarp_release_entry
(
entry
);
return
;
}
pentry
=
&
entry
->
next
;
}
sti
();
}
/*
* Receive an arp request by the device layer. Maybe it should be
* rewritten to use the incoming packet for the reply. The current
* "overhead" time isn't that high...
*/
int
rarp_rcv
(
struct
sk_buff
*
skb
,
struct
device
*
dev
,
struct
packet_type
*
pt
)
{
/*
* We shouldn't use this type conversion. Check later.
*/
struct
arphdr
*
rarp
=
(
struct
arphdr
*
)
skb
->
h
.
raw
;
unsigned
char
*
rarp_ptr
=
(
unsigned
char
*
)(
rarp
+
1
);
struct
rarp_table
*
entry
;
long
sip
,
tip
;
unsigned
char
*
sha
,
*
tha
;
/* s for "source", t for "target" */
/*
* If this test doesn't pass, its not IP, or we should ignore it anyway
*/
if
(
rarp
->
ar_hln
!=
dev
->
addr_len
||
dev
->
type
!=
ntohs
(
rarp
->
ar_hrd
)
||
dev
->
flags
&
IFF_NOARP
)
{
kfree_skb
(
skb
,
FREE_READ
);
return
0
;
}
/*
* If it's not a RARP request, delete it.
*/
if
(
rarp
->
ar_op
!=
htons
(
ARPOP_RREQUEST
))
{
kfree_skb
(
skb
,
FREE_READ
);
return
0
;
}
/*
* For now we will only deal with IP addresses.
*/
if
(
#ifdef CONFIG_AX25
(
rarp
->
ar_pro
!=
htons
(
AX25_P_IP
)
&&
dev
->
type
==
ARPHRD_AX25
)
||
#endif
(
rarp
->
ar_pro
!=
htons
(
ETH_P_IP
)
&&
dev
->
type
!=
ARPHRD_AX25
)
||
rarp
->
ar_pln
!=
4
)
{
/*
* This packet is not for us. Remove it.
*/
kfree_skb
(
skb
,
FREE_READ
);
return
0
;
}
/*
* Extract variable width fields
*/
sha
=
rarp_ptr
;
rarp_ptr
+=
dev
->
addr_len
;
memcpy
(
&
sip
,
rarp_ptr
,
4
);
rarp_ptr
+=
4
;
tha
=
rarp_ptr
;
rarp_ptr
+=
dev
->
addr_len
;
memcpy
(
&
tip
,
rarp_ptr
,
4
);
/*
* Process entry
*/
cli
();
for
(
entry
=
rarp_tables
;
entry
!=
NULL
;
entry
=
entry
->
next
)
if
(
!
memcmp
(
entry
->
ha
,
sha
,
rarp
->
ar_hln
))
break
;
if
(
entry
!=
NULL
)
{
sip
=
entry
->
ip
;
sti
();
arp_send
(
ARPOP_RREPLY
,
ETH_P_RARP
,
sip
,
dev
,
dev
->
pa_addr
,
sha
,
dev
->
dev_addr
);
}
else
sti
();
kfree_skb
(
skb
,
FREE_READ
);
return
0
;
}
/*
* Set (create) a RARP cache entry.
*/
static
int
rarp_req_set
(
struct
arpreq
*
req
)
{
struct
arpreq
r
;
struct
rarp_table
*
entry
;
struct
sockaddr_in
*
si
;
int
htype
,
hlen
;
unsigned
long
ip
;
struct
rtable
*
rt
;
memcpy_fromfs
(
&
r
,
req
,
sizeof
(
r
));
/*
* We only understand about IP addresses...
*/
if
(
r
.
arp_pa
.
sa_family
!=
AF_INET
)
return
-
EPFNOSUPPORT
;
switch
(
r
.
arp_ha
.
sa_family
)
{
case
ARPHRD_ETHER
:
htype
=
ARPHRD_ETHER
;
hlen
=
ETH_ALEN
;
break
;
#ifdef CONFIG_AX25
case
ARPHRD_AX25
:
htype
=
ARPHRD_AX25
;
hlen
=
7
;
break
;
#endif
default:
return
-
EPFNOSUPPORT
;
}
si
=
(
struct
sockaddr_in
*
)
&
r
.
arp_pa
;
ip
=
si
->
sin_addr
.
s_addr
;
if
(
ip
==
0
)
{
printk
(
"RARP: SETRARP: requested PA is 0.0.0.0 !
\n
"
);
return
-
EINVAL
;
}
/*
* Is it reachable directly ?
*/
rt
=
ip_rt_route
(
ip
,
NULL
,
NULL
);
if
(
rt
==
NULL
)
return
-
ENETUNREACH
;
/*
* Is there an existing entry for this address? Find out...
*/
cli
();
for
(
entry
=
rarp_tables
;
entry
!=
NULL
;
entry
=
entry
->
next
)
if
(
entry
->
ip
==
ip
)
break
;
/*
* If no entry was found, create a new one.
*/
if
(
entry
==
NULL
)
{
entry
=
(
struct
rarp_table
*
)
kmalloc
(
sizeof
(
struct
rarp_table
),
GFP_ATOMIC
);
if
(
entry
==
NULL
)
{
sti
();
return
-
ENOMEM
;
}
if
(
initflag
)
{
rarp_init
();
initflag
=
0
;
}
entry
->
next
=
rarp_tables
;
rarp_tables
=
entry
;
}
entry
->
ip
=
ip
;
entry
->
hlen
=
hlen
;
entry
->
htype
=
htype
;
memcpy
(
&
entry
->
ha
,
&
r
.
arp_ha
.
sa_data
,
hlen
);
entry
->
dev
=
rt
->
rt_dev
;
sti
();
return
0
;
}
/*
* Get a RARP cache entry.
*/
static
int
rarp_req_get
(
struct
arpreq
*
req
)
{
struct
arpreq
r
;
struct
rarp_table
*
entry
;
struct
sockaddr_in
*
si
;
unsigned
long
ip
;
/*
* We only understand about IP addresses...
*/
memcpy_fromfs
(
&
r
,
req
,
sizeof
(
r
));
if
(
r
.
arp_pa
.
sa_family
!=
AF_INET
)
return
-
EPFNOSUPPORT
;
/*
* Is there an existing entry for this address?
*/
si
=
(
struct
sockaddr_in
*
)
&
r
.
arp_pa
;
ip
=
si
->
sin_addr
.
s_addr
;
cli
();
for
(
entry
=
rarp_tables
;
entry
!=
NULL
;
entry
=
entry
->
next
)
if
(
entry
->
ip
==
ip
)
break
;
if
(
entry
==
NULL
)
{
sti
();
return
-
ENXIO
;
}
/*
* We found it; copy into structure.
*/
memcpy
(
r
.
arp_ha
.
sa_data
,
&
entry
->
ha
,
entry
->
hlen
);
r
.
arp_ha
.
sa_family
=
entry
->
htype
;
sti
();
/*
* Copy the information back
*/
memcpy_tofs
(
req
,
&
r
,
sizeof
(
r
));
return
0
;
}
/*
* Handle a RARP layer I/O control request.
*/
int
rarp_ioctl
(
unsigned
int
cmd
,
void
*
arg
)
{
struct
arpreq
r
;
struct
sockaddr_in
*
si
;
int
err
;
switch
(
cmd
)
{
case
SIOCDRARP
:
if
(
!
suser
())
return
-
EPERM
;
err
=
verify_area
(
VERIFY_READ
,
arg
,
sizeof
(
struct
arpreq
));
if
(
err
)
return
err
;
memcpy_fromfs
(
&
r
,
arg
,
sizeof
(
r
));
if
(
r
.
arp_pa
.
sa_family
!=
AF_INET
)
return
-
EPFNOSUPPORT
;
si
=
(
struct
sockaddr_in
*
)
&
r
.
arp_pa
;
rarp_destroy
(
si
->
sin_addr
.
s_addr
);
return
0
;
case
SIOCGRARP
:
err
=
verify_area
(
VERIFY_WRITE
,
arg
,
sizeof
(
struct
arpreq
));
if
(
err
)
return
err
;
return
rarp_req_get
((
struct
arpreq
*
)
arg
);
case
SIOCSRARP
:
if
(
!
suser
())
return
-
EPERM
;
err
=
verify_area
(
VERIFY_READ
,
arg
,
sizeof
(
struct
arpreq
));
if
(
err
)
return
err
;
return
rarp_req_set
((
struct
arpreq
*
)
arg
);
default:
return
-
EINVAL
;
}
/*NOTREACHED*/
return
0
;
}
int
rarp_get_info
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
)
{
int
len
=
0
;
off_t
begin
=
0
;
off_t
pos
=
0
;
int
size
;
struct
rarp_table
*
entry
;
char
ipbuffer
[
20
];
unsigned
long
netip
;
if
(
initflag
)
{
size
=
sprintf
(
buffer
,
"RARP disabled until entries added to cache.
\n
"
);
pos
+=
size
;
len
+=
size
;
}
else
{
size
=
sprintf
(
buffer
,
"IP address HW type HW address
\n
"
);
pos
+=
size
;
len
+=
size
;
cli
();
for
(
entry
=
rarp_tables
;
entry
!=
NULL
;
entry
=
entry
->
next
)
{
netip
=
htonl
(
entry
->
ip
);
/* switch to network order */
sprintf
(
ipbuffer
,
"%d.%d.%d.%d"
,
(
unsigned
int
)(
netip
>>
24
)
&
255
,
(
unsigned
int
)(
netip
>>
16
)
&
255
,
(
unsigned
int
)(
netip
>>
8
)
&
255
,
(
unsigned
int
)(
netip
)
&
255
);
size
=
sprintf
(
buffer
+
len
,
"%-17s%-20s%02x:%02x:%02x:%02x:%02x:%02x
\n
"
,
ipbuffer
,
"10Mbps Ethernet"
,
(
unsigned
int
)
entry
->
ha
[
0
],
(
unsigned
int
)
entry
->
ha
[
1
],
(
unsigned
int
)
entry
->
ha
[
2
],
(
unsigned
int
)
entry
->
ha
[
3
],
(
unsigned
int
)
entry
->
ha
[
4
],
(
unsigned
int
)
entry
->
ha
[
5
]);
len
+=
size
;
pos
=
begin
+
len
;
if
(
pos
<
offset
)
{
len
=
0
;
begin
=
pos
;
}
if
(
pos
>
offset
+
length
)
break
;
}
sti
();
}
*
start
=
buffer
+
(
offset
-
begin
);
/* Start of wanted data */
len
-=
(
offset
-
begin
);
/* Start slop */
if
(
len
>
length
)
len
=
length
;
/* Ending slop */
return
len
;
}
#endif
net/inet/rarp.h
0 → 100644
View file @
16119ae5
/* linux/net/inet/rarp.h */
#ifndef _RARP_H
#define _RARP_H
extern
int
rarp_ioctl
(
unsigned
int
cmd
,
void
*
arg
);
extern
int
rarp_rcv
(
struct
sk_buff
*
skb
,
struct
device
*
dev
,
struct
packet_type
*
pt
);
extern
int
rarp_get_info
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
);
#endif
/* _RARP_H */
net/inet/sock.c
View file @
16119ae5
...
@@ -52,6 +52,7 @@
...
@@ -52,6 +52,7 @@
* Alan Cox : Split socket option code
* Alan Cox : Split socket option code
* Alan Cox : Callbacks
* Alan Cox : Callbacks
* Alan Cox : Nagle flag for Charles & Johannes stuff
* Alan Cox : Nagle flag for Charles & Johannes stuff
* Alex : Removed restriction on inet fioctl
*
*
* To Fix:
* To Fix:
*
*
...
@@ -86,6 +87,7 @@
...
@@ -86,6 +87,7 @@
#include "ip.h"
#include "ip.h"
#include "protocol.h"
#include "protocol.h"
#include "arp.h"
#include "arp.h"
#include "rarp.h"
#include "route.h"
#include "route.h"
#include "tcp.h"
#include "tcp.h"
#include "udp.h"
#include "udp.h"
...
@@ -1482,6 +1484,11 @@ inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
...
@@ -1482,6 +1484,11 @@ inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case
SIOCSARP
:
case
SIOCSARP
:
return
(
arp_ioctl
(
cmd
,(
void
*
)
arg
));
return
(
arp_ioctl
(
cmd
,(
void
*
)
arg
));
case
SIOCDRARP
:
case
SIOCGRARP
:
case
SIOCSRARP
:
return
(
rarp_ioctl
(
cmd
,(
void
*
)
arg
));
case
SIOCGIFCONF
:
case
SIOCGIFCONF
:
case
SIOCGIFFLAGS
:
case
SIOCGIFFLAGS
:
case
SIOCSIFFLAGS
:
case
SIOCSIFFLAGS
:
...
@@ -1701,7 +1708,6 @@ inet_fioctl(struct inode *inode, struct file *file,
...
@@ -1701,7 +1708,6 @@ inet_fioctl(struct inode *inode, struct file *file,
/* Extract the minor number on which we work. */
/* Extract the minor number on which we work. */
minor
=
MINOR
(
inode
->
i_rdev
);
minor
=
MINOR
(
inode
->
i_rdev
);
if
(
minor
!=
0
)
return
(
-
ENODEV
);
/* Now dispatch on the minor device. */
/* Now dispatch on the minor device. */
switch
(
minor
)
{
switch
(
minor
)
{
...
@@ -1780,7 +1786,7 @@ void inet_proto_init(struct ddi_proto *pro)
...
@@ -1780,7 +1786,7 @@ void inet_proto_init(struct ddi_proto *pro)
struct
inet_protocol
*
p
;
struct
inet_protocol
*
p
;
int
i
;
int
i
;
printk
(
"Swansea University Computer Society NET3.01
0
\n
"
);
printk
(
"Swansea University Computer Society NET3.01
2
\n
"
);
/*
/*
* Set up our UNIX VFS major device. (compatibility)
* Set up our UNIX VFS major device. (compatibility)
*/
*/
...
...
net/inet/tcp.c
View file @
16119ae5
...
@@ -15,6 +15,7 @@
...
@@ -15,6 +15,7 @@
* Charles Hedrick, <hedrick@klinzhai.rutgers.edu>
* Charles Hedrick, <hedrick@klinzhai.rutgers.edu>
* Linus Torvalds, <torvalds@cs.helsinki.fi>
* Linus Torvalds, <torvalds@cs.helsinki.fi>
* Alan Cox, <gw4pts@gw4pts.ampr.org>
* Alan Cox, <gw4pts@gw4pts.ampr.org>
* Matthew Dillon, <dillon@apollo.west.oic.com>
*
*
* Fixes:
* Fixes:
* Alan Cox : Numerous verify_area() calls
* Alan Cox : Numerous verify_area() calls
...
@@ -67,6 +68,7 @@
...
@@ -67,6 +68,7 @@
* Linus : Rewrote tcp_read() and URG handling
* Linus : Rewrote tcp_read() and URG handling
* completely
* completely
* Gerhard Koerting: Fixed some missing timer handling
* Gerhard Koerting: Fixed some missing timer handling
* Matthew Dillon : Reworked TCP machine states as per RFC
*
*
*
*
* To Fix:
* To Fix:
...
@@ -80,6 +82,40 @@
...
@@ -80,6 +82,40 @@
* modify it under the terms of the GNU General Public License
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* as published by the Free Software Foundation; either version
* 2 of the License, or(at your option) any later version.
* 2 of the License, or(at your option) any later version.
*
* Description of States:
*
* TCP_SYN_SENT sent a connection request, waiting for ack
*
* TCP_SYN_RECV received a connection request, sent ack,
* waiting for final ack in three-way handshake.
*
* TCP_ESTABLISHED connection established
*
* TCP_FIN_WAIT1 our side has shutdown, waiting to complete
* transmission of remaining buffered data
*
* TCP_FIN_WAIT2 all buffered data sent, waiting for remote
* to shutdown
*
* TCP_CLOSING both sides have shutdown but we still have
* data we have to finish sending
*
* TCP_TIME_WAIT timeout to catch resent junk before entering
* closed, can only be entered from FIN_WAIT2
* or CLOSING. Required because the other end
* may not have gotten our last ACK causing it
* to retransmit the data packet (which we ignore)
*
* TCP_CLOSE_WAIT remote side has shutdown and is waiting for
* us to finish writing our data and to shutdown
* (we have to close() to move on to LAST_ACK)
*
* TCP_LAST_ACK out side has shutdown after remote has
* shutdown. There may still be data in our
* buffer that we have to finish sending
*
* TCP_CLOSED socket is finished
*/
*/
#include <linux/types.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/sched.h>
...
@@ -109,7 +145,6 @@
...
@@ -109,7 +145,6 @@
unsigned
long
seq_offset
;
unsigned
long
seq_offset
;
struct
tcp_mib
tcp_statistics
;
struct
tcp_mib
tcp_statistics
;
#define SUBNETSARELOCAL
static
__inline__
int
static
__inline__
int
min
(
unsigned
int
a
,
unsigned
int
b
)
min
(
unsigned
int
a
,
unsigned
int
b
)
...
@@ -1498,8 +1533,7 @@ static int tcp_read(struct sock *sk, unsigned char *to,
...
@@ -1498,8 +1533,7 @@ static int tcp_read(struct sock *sk, unsigned char *to,
/*
/*
* Send a FIN without closing the connection.
* Shutdown the sending side of a connection.
* Not called at interrupt time.
*/
*/
void
tcp_shutdown
(
struct
sock
*
sk
,
int
how
)
void
tcp_shutdown
(
struct
sock
*
sk
,
int
how
)
...
@@ -1514,22 +1548,36 @@ void tcp_shutdown(struct sock *sk, int how)
...
@@ -1514,22 +1548,36 @@ void tcp_shutdown(struct sock *sk, int how)
* We need to grab some memory, and put together a FIN,
* We need to grab some memory, and put together a FIN,
* and then put it into the queue to be sent.
* and then put it into the queue to be sent.
* FIXME:
* FIXME:
*
* Tim MacKenzie(tym@dibbler.cs.monash.edu.au) 4 Dec '92.
* Tim MacKenzie(tym@dibbler.cs.monash.edu.au) 4 Dec '92.
* Most of this is guesswork, so maybe it will work...
* Most of this is guesswork, so maybe it will work...
*/
*/
if
(
!
(
how
&
SEND_SHUTDOWN
))
return
;
/*
/*
* If we've already sent a FIN, return.
* If we've already sent a FIN, return.
*/
*/
if
(
sk
->
state
==
TCP_FIN_WAIT1
||
sk
->
state
==
TCP_FIN_WAIT2
)
if
(
sk
->
state
==
TCP_FIN_WAIT1
||
return
;
sk
->
state
==
TCP_FIN_WAIT2
||
if
(
!
(
how
&
SEND_SHUTDOWN
))
sk
->
state
==
TCP_CLOSING
||
sk
->
state
==
TCP_LAST_ACK
||
sk
->
state
==
TCP_TIME_WAIT
)
{
return
;
return
;
}
sk
->
inuse
=
1
;
sk
->
inuse
=
1
;
/*
/*
* Clear out any half completed packets.
* flag that the sender has shutdown
*/
sk
->
shutdown
|=
SEND_SHUTDOWN
;
/*
* Clear out any half completed packets.
*/
*/
if
(
sk
->
partial
)
if
(
sk
->
partial
)
...
@@ -1560,13 +1608,24 @@ void tcp_shutdown(struct sock *sk, int how)
...
@@ -1560,13 +1608,24 @@ void tcp_shutdown(struct sock *sk, int how)
{
{
/*
/*
* Finish anyway, treat this as a send that got lost.
* Finish anyway, treat this as a send that got lost.
*
* Enter FIN_WAIT1 on normal shutdown, which waits for
* written data to be completely acknowledged along
* with an acknowledge to our FIN.
*
* Enter FIN_WAIT2 on abnormal shutdown -- close before
* connection established.
*/
*/
buff
->
free
=
1
;
buff
->
free
=
1
;
prot
->
wfree
(
sk
,
buff
->
mem_addr
,
buff
->
mem_len
);
prot
->
wfree
(
sk
,
buff
->
mem_addr
,
buff
->
mem_len
);
if
(
sk
->
state
==
TCP_ESTABLISHED
)
sk
->
state
=
TCP_FIN_WAIT1
;
if
(
sk
->
state
==
TCP_ESTABLISHED
)
sk
->
state
=
TCP_FIN_WAIT1
;
else
if
(
sk
->
state
==
TCP_CLOSE_WAIT
)
sk
->
state
=
TCP_LAST_ACK
;
else
else
sk
->
state
=
TCP_FIN_WAIT2
;
sk
->
state
=
TCP_FIN_WAIT2
;
release_sock
(
sk
);
release_sock
(
sk
);
DPRINTF
((
DBG_TCP
,
"Unable to build header for fin.
\n
"
));
DPRINTF
((
DBG_TCP
,
"Unable to build header for fin.
\n
"
));
return
;
return
;
...
@@ -1610,7 +1669,9 @@ void tcp_shutdown(struct sock *sk, int how)
...
@@ -1610,7 +1669,9 @@ void tcp_shutdown(struct sock *sk, int how)
if
(
sk
->
state
==
TCP_ESTABLISHED
)
if
(
sk
->
state
==
TCP_ESTABLISHED
)
sk
->
state
=
TCP_FIN_WAIT1
;
sk
->
state
=
TCP_FIN_WAIT1
;
else
else
if
(
sk
->
state
==
TCP_CLOSE_WAIT
)
sk
->
state
=
TCP_LAST_ACK
;
else
sk
->
state
=
TCP_FIN_WAIT2
;
sk
->
state
=
TCP_FIN_WAIT2
;
release_sock
(
sk
);
release_sock
(
sk
);
...
@@ -1934,7 +1995,7 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
...
@@ -1934,7 +1995,7 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
if
(
sk
->
user_mss
)
if
(
sk
->
user_mss
)
newsk
->
mtu
=
sk
->
user_mss
;
newsk
->
mtu
=
sk
->
user_mss
;
else
{
else
{
#ifdef
SUBNETSARELOCAL
#ifdef
CONFIG_INET_SNARL
/* Sub Nets ARe Local */
if
((
saddr
^
daddr
)
&
default_mask
(
saddr
))
if
((
saddr
^
daddr
)
&
default_mask
(
saddr
))
#else
#else
if
((
saddr
^
daddr
)
&
dev
->
pa_mask
)
if
((
saddr
^
daddr
)
&
dev
->
pa_mask
)
...
@@ -2081,7 +2142,18 @@ static void tcp_close(struct sock *sk, int timeout)
...
@@ -2081,7 +2142,18 @@ static void tcp_close(struct sock *sk, int timeout)
{
{
case
TCP_FIN_WAIT1
:
case
TCP_FIN_WAIT1
:
case
TCP_FIN_WAIT2
:
case
TCP_FIN_WAIT2
:
case
TCP_LAST_ACK
:
case
TCP_CLOSING
:
/*
* These states occur when we have already closed out
* our end. If there is no timeout, we do not do
* anything. We may still be in the middle of sending
* the remainder of our buffer, for example...
* resetting the timer would be inappropriate.
*
* XXX if retransmit count reaches limit, is tcp_close()
* called with timeout == 1 ? if not, we need to fix that.
*/
#ifdef NOTDEF
/*
/*
* Start a timer.
* Start a timer.
* original code was 4 * sk->rtt. In converting to the
* original code was 4 * sk->rtt. In converting to the
...
@@ -2089,11 +2161,16 @@ static void tcp_close(struct sock *sk, int timeout)
...
@@ -2089,11 +2161,16 @@ static void tcp_close(struct sock *sk, int timeout)
* it seems to make most sense to use the backed off value
* it seems to make most sense to use the backed off value
*/
*/
reset_timer
(
sk
,
TIME_CLOSE
,
4
*
sk
->
rto
);
reset_timer
(
sk
,
TIME_CLOSE
,
4
*
sk
->
rto
);
#endif
if
(
timeout
)
if
(
timeout
)
tcp_time_wait
(
sk
);
tcp_time_wait
(
sk
);
release_sock
(
sk
);
release_sock
(
sk
);
return
;
/* break causes a double release - messy */
return
;
/* break causes a double release - messy */
case
TCP_TIME_WAIT
:
case
TCP_TIME_WAIT
:
case
TCP_LAST_ACK
:
/*
* A timeout from these states terminates the TCB.
*/
if
(
timeout
)
if
(
timeout
)
{
{
sk
->
state
=
TCP_CLOSE
;
sk
->
state
=
TCP_CLOSE
;
...
@@ -2140,6 +2217,12 @@ static void tcp_close(struct sock *sk, int timeout)
...
@@ -2140,6 +2217,12 @@ static void tcp_close(struct sock *sk, int timeout)
if
(
tmp
<
0
)
if
(
tmp
<
0
)
{
{
kfree_skb
(
buff
,
FREE_WRITE
);
kfree_skb
(
buff
,
FREE_WRITE
);
/*
* Enter FIN_WAIT1 to await completion of
* written out data and ACK to our FIN.
*/
if
(
sk
->
state
==
TCP_ESTABLISHED
)
if
(
sk
->
state
==
TCP_ESTABLISHED
)
sk
->
state
=
TCP_FIN_WAIT1
;
sk
->
state
=
TCP_FIN_WAIT1
;
else
else
...
@@ -2192,14 +2275,19 @@ static void tcp_close(struct sock *sk, int timeout)
...
@@ -2192,14 +2275,19 @@ static void tcp_close(struct sock *sk, int timeout)
skb_queue_tail
(
&
sk
->
write_queue
,
buff
);
skb_queue_tail
(
&
sk
->
write_queue
,
buff
);
}
}
if
(
sk
->
state
==
TCP_CLOSE_WAIT
)
/*
{
* If established (normal close), enter FIN_WAIT1.
sk
->
state
=
TCP_FIN_WAIT2
;
* If in CLOSE_WAIT, enter LAST_ACK
}
* If in CLOSING, remain in CLOSING
else
* otherwise enter FIN_WAIT2
{
*/
sk
->
state
=
TCP_FIN_WAIT1
;
}
if
(
sk
->
state
==
TCP_ESTABLISHED
)
sk
->
state
=
TCP_FIN_WAIT1
;
else
if
(
sk
->
state
==
TCP_CLOSE_WAIT
)
sk
->
state
=
TCP_LAST_ACK
;
else
if
(
sk
->
state
!=
TCP_CLOSING
)
sk
->
state
=
TCP_FIN_WAIT2
;
}
}
release_sock
(
sk
);
release_sock
(
sk
);
}
}
...
@@ -2276,7 +2364,10 @@ sort_send(struct sock *sk)
...
@@ -2276,7 +2364,10 @@ sort_send(struct sock *sk)
}
}
/* This routine deals with incoming acks, but not outgoing ones. */
/*
* This routine deals with incoming acks, but not outgoing ones.
*/
static
int
static
int
tcp_ack
(
struct
sock
*
sk
,
struct
tcphdr
*
th
,
unsigned
long
saddr
,
int
len
)
tcp_ack
(
struct
sock
*
sk
,
struct
tcphdr
*
th
,
unsigned
long
saddr
,
int
len
)
{
{
...
@@ -2574,33 +2665,68 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
...
@@ -2574,33 +2665,68 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
tcp_send_partial
(
sk
);
tcp_send_partial
(
sk
);
}
}
/* See if we are done. */
/*
if
(
sk
->
state
==
TCP_TIME_WAIT
)
{
* In the LAST_ACK case, the other end FIN'd us. We then FIN'd them, and
* we are now waiting for an acknowledge to our FIN. The other end is
* already in TIME_WAIT.
*
* Move to TCP_CLOSE on success.
*/
if
(
sk
->
state
==
TCP_LAST_ACK
)
{
if
(
!
sk
->
dead
)
if
(
!
sk
->
dead
)
sk
->
state_change
(
sk
);
sk
->
state_change
(
sk
);
DPRINTF
((
DBG_TCP
,
"TCP_LAST_ACK-A: %d/%d %d/%d ack/sent %d %d
\n
"
,
sk
->
rcv_ack_seq
,
sk
->
write_seq
,
sk
->
acked_seq
,
sk
->
fin_seq
,
ack
,
sk
->
sent_seq
));
if
(
sk
->
rcv_ack_seq
==
sk
->
write_seq
&&
sk
->
acked_seq
==
sk
->
fin_seq
)
{
if
(
sk
->
rcv_ack_seq
==
sk
->
write_seq
&&
sk
->
acked_seq
==
sk
->
fin_seq
)
{
DPRINTF
((
DBG_TCP
,
"tcp_ack closing socket - %X
\n
"
,
sk
));
flag
|=
1
;
flag
|=
1
;
sk
->
state
=
TCP_CLOSE
;
sk
->
state
=
TCP_CLOSE
;
sk
->
shutdown
=
SHUTDOWN_MASK
;
sk
->
shutdown
=
SHUTDOWN_MASK
;
}
}
}
}
if
(
sk
->
state
==
TCP_LAST_ACK
||
sk
->
state
==
TCP_FIN_WAIT2
)
{
/*
if
(
!
sk
->
dead
)
sk
->
state_change
(
sk
);
* Incomming ACK to a FIN we sent in the case of our initiating the close.
*
* Move to FIN_WAIT2 to await a FIN from the other end.
*/
if
(
sk
->
state
==
TCP_FIN_WAIT1
)
{
if
(
!
sk
->
dead
)
sk
->
state_change
(
sk
);
if
(
sk
->
rcv_ack_seq
==
sk
->
write_seq
)
{
if
(
sk
->
rcv_ack_seq
==
sk
->
write_seq
)
{
flag
|=
1
;
flag
|=
1
;
if
(
sk
->
acked_seq
!=
sk
->
fin_seq
)
{
if
(
sk
->
acked_seq
!=
sk
->
fin_seq
)
{
tcp_time_wait
(
sk
);
tcp_time_wait
(
sk
);
}
else
{
}
else
{
DPRINTF
((
DBG_TCP
,
"tcp_ack closing socket - %X
\n
"
,
sk
));
tcp_send_ack
(
sk
->
sent_seq
,
sk
->
acked_seq
,
sk
,
th
,
sk
->
daddr
);
sk
->
shutdown
=
SHUTDOWN_MASK
;
sk
->
shutdown
=
SHUTDOWN_MASK
;
sk
->
state
=
TCP_
CLOSE
;
sk
->
state
=
TCP_
FIN_WAIT2
;
}
}
}
}
}
}
/*
* Incomming ACK to a FIN we sent in the case of a simultanious close.
*
* Move to TIME_WAIT
*/
if
(
sk
->
state
==
TCP_CLOSING
)
{
if
(
!
sk
->
dead
)
sk
->
state_change
(
sk
);
if
(
sk
->
rcv_ack_seq
==
sk
->
write_seq
)
{
flag
|=
1
;
tcp_time_wait
(
sk
);
}
}
/*
/*
* I make no guarantees about the first clause in the following
* I make no guarantees about the first clause in the following
* test, i.e. "(!flag) || (flag&4)". I'm not entirely sure under
* test, i.e. "(!flag) || (flag&4)". I'm not entirely sure under
...
@@ -2851,6 +2977,8 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
...
@@ -2851,6 +2977,8 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
DPRINTF
((
DBG_TCP
,
"data received on dead socket.
\n
"
));
DPRINTF
((
DBG_TCP
,
"data received on dead socket.
\n
"
));
}
}
#ifdef NOTDEF
/* say what? this is handled by tcp_ack() */
if
(
sk
->
state
==
TCP_FIN_WAIT2
&&
if
(
sk
->
state
==
TCP_FIN_WAIT2
&&
sk
->
acked_seq
==
sk
->
fin_seq
&&
sk
->
rcv_ack_seq
==
sk
->
write_seq
)
{
sk
->
acked_seq
==
sk
->
fin_seq
&&
sk
->
rcv_ack_seq
==
sk
->
write_seq
)
{
DPRINTF
((
DBG_TCP
,
"tcp_data: entering last_ack state sk = %X
\n
"
,
sk
));
DPRINTF
((
DBG_TCP
,
"tcp_data: entering last_ack state sk = %X
\n
"
,
sk
));
...
@@ -2860,6 +2988,7 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
...
@@ -2860,6 +2988,7 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
sk
->
state
=
TCP_LAST_ACK
;
sk
->
state
=
TCP_LAST_ACK
;
if
(
!
sk
->
dead
)
sk
->
state_change
(
sk
);
if
(
!
sk
->
dead
)
sk
->
state_change
(
sk
);
}
}
#endif
return
(
0
);
return
(
0
);
}
}
...
@@ -2920,15 +3049,27 @@ static inline int tcp_urg(struct sock *sk, struct tcphdr *th,
...
@@ -2920,15 +3049,27 @@ static inline int tcp_urg(struct sock *sk, struct tcphdr *th,
/*
/*
* This deals with incoming fins. 'Linus at 9 O'clock' 8-)
* This deals with incoming fins. 'Linus at 9 O'clock' 8-)
*
* If we are ESTABLISHED, a received fin moves us to CLOSE-WAIT
* (and thence onto LAST-ACK and finally, CLOSED, we never enter
* TIME-WAIT)
*
* If we are in FINWAIT-1, a received FIN indicates simultanious
* close and we go into CLOSING (and later onto TIME-WAIT)
*
* If we are in FINWAIT-2, a received FIN moves us to TIME-WAIT.
*
*/
*/
static
int
tcp_fin
(
struct
sock
*
sk
,
struct
tcphdr
*
th
,
static
int
tcp_fin
(
struct
s
k_buff
*
skb
,
struct
s
ock
*
sk
,
struct
tcphdr
*
th
,
unsigned
long
saddr
,
struct
device
*
dev
)
unsigned
long
saddr
,
struct
device
*
dev
)
{
{
DPRINTF
((
DBG_TCP
,
"tcp_fin(sk=%X, th=%X, saddr=%X, dev=%X)
\n
"
,
DPRINTF
((
DBG_TCP
,
"tcp_fin(sk=%X, th=%X, saddr=%X, dev=%X)
\n
"
,
sk
,
th
,
saddr
,
dev
));
sk
,
th
,
saddr
,
dev
));
sk
->
fin_seq
=
th
->
seq
+
skb
->
len
+
th
->
syn
+
th
->
fin
;
if
(
!
sk
->
dead
)
if
(
!
sk
->
dead
)
{
{
sk
->
state_change
(
sk
);
sk
->
state_change
(
sk
);
...
@@ -2939,9 +3080,12 @@ static int tcp_fin(struct sock *sk, struct tcphdr *th,
...
@@ -2939,9 +3080,12 @@ static int tcp_fin(struct sock *sk, struct tcphdr *th,
case
TCP_SYN_RECV
:
case
TCP_SYN_RECV
:
case
TCP_SYN_SENT
:
case
TCP_SYN_SENT
:
case
TCP_ESTABLISHED
:
case
TCP_ESTABLISHED
:
/* Contains the one that needs to be acked */
/*
* move to CLOSE_WAIT, tcp_data() already handled
* sending the ack.
*/
reset_timer
(
sk
,
TIME_CLOSE
,
TCP_TIMEOUT_LEN
);
reset_timer
(
sk
,
TIME_CLOSE
,
TCP_TIMEOUT_LEN
);
sk
->
fin_seq
=
th
->
seq
+
1
;
/*sk->fin_seq = th->seq+1;*/
tcp_statistics
.
TcpCurrEstab
--
;
tcp_statistics
.
TcpCurrEstab
--
;
sk
->
state
=
TCP_CLOSE_WAIT
;
sk
->
state
=
TCP_CLOSE_WAIT
;
if
(
th
->
rst
)
if
(
th
->
rst
)
...
@@ -2949,17 +3093,46 @@ static int tcp_fin(struct sock *sk, struct tcphdr *th,
...
@@ -2949,17 +3093,46 @@ static int tcp_fin(struct sock *sk, struct tcphdr *th,
break
;
break
;
case
TCP_CLOSE_WAIT
:
case
TCP_CLOSE_WAIT
:
case
TCP_FIN_WAIT2
:
case
TCP_CLOSING
:
break
;
/* we got a retransmit of the fin. */
/*
* received a retransmission of the FIN, do
case
TCP_FIN_WAIT1
:
* nothing.
/* Contains the one that needs to be acked */
*/
sk
->
fin_seq
=
th
->
seq
+
1
;
sk
->
state
=
TCP_FIN_WAIT2
;
break
;
break
;
case
TCP_TIME_WAIT
:
/*
* received a retransmission of the FIN,
* restart the TIME_WAIT timer.
*/
reset_timer
(
sk
,
TIME_CLOSE
,
TCP_TIMEWAIT_LEN
);
return
(
0
);
case
TCP_FIN_WAIT1
:
/*
* This case occurs when a simultanious close
* happens, we must ack the received FIN and
* enter the CLOSING state.
*
* XXX timeout not set properly
*/
reset_timer
(
sk
,
TIME_CLOSE
,
TCP_TIMEWAIT_LEN
);
/*sk->fin_seq = th->seq+1;*/
sk
->
state
=
TCP_CLOSING
;
break
;
case
TCP_FIN_WAIT2
:
/*
* received a FIN -- send ACK and enter TIME_WAIT
*/
reset_timer
(
sk
,
TIME_CLOSE
,
TCP_TIMEWAIT_LEN
);
/*sk->fin_seq = th->seq+1;*/
sk
->
state
=
TCP_TIME_WAIT
;
break
;
case
TCP_CLOSE
:
/*
* already in CLOSE
*/
break
;
default:
default:
case
TCP_TIME_WAIT
:
sk
->
state
=
TCP_LAST_ACK
;
sk
->
state
=
TCP_LAST_ACK
;
/* Start the timers. */
/* Start the timers. */
...
@@ -3364,6 +3537,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n");
...
@@ -3364,6 +3537,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n");
case
TCP_ESTABLISHED
:
case
TCP_ESTABLISHED
:
case
TCP_CLOSE_WAIT
:
case
TCP_CLOSE_WAIT
:
case
TCP_CLOSING
:
case
TCP_FIN_WAIT1
:
case
TCP_FIN_WAIT1
:
case
TCP_FIN_WAIT2
:
case
TCP_FIN_WAIT2
:
case
TCP_TIME_WAIT
:
case
TCP_TIME_WAIT
:
...
@@ -3437,7 +3611,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n");
...
@@ -3437,7 +3611,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n");
}
}
/* Moved: you must do data then fin bit */
/* Moved: you must do data then fin bit */
if
(
th
->
fin
&&
tcp_fin
(
sk
,
th
,
saddr
,
dev
))
{
if
(
th
->
fin
&&
tcp_fin
(
sk
b
,
sk
,
th
,
saddr
,
dev
))
{
kfree_skb
(
skb
,
FREE_READ
);
kfree_skb
(
skb
,
FREE_READ
);
release_sock
(
sk
);
release_sock
(
sk
);
return
(
0
);
return
(
0
);
...
@@ -3622,7 +3796,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n");
...
@@ -3622,7 +3796,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n");
if
(
tcp_data
(
skb
,
sk
,
saddr
,
len
))
if
(
tcp_data
(
skb
,
sk
,
saddr
,
len
))
kfree_skb
(
skb
,
FREE_READ
);
kfree_skb
(
skb
,
FREE_READ
);
if
(
th
->
fin
)
tcp_fin
(
sk
,
th
,
saddr
,
dev
);
if
(
th
->
fin
)
tcp_fin
(
sk
b
,
sk
,
th
,
saddr
,
dev
);
release_sock
(
sk
);
release_sock
(
sk
);
return
(
0
);
return
(
0
);
}
}
...
@@ -3645,7 +3819,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n");
...
@@ -3645,7 +3819,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n");
release_sock
(
sk
);
release_sock
(
sk
);
return
(
0
);
return
(
0
);
}
}
tcp_fin
(
sk
,
th
,
saddr
,
dev
);
tcp_fin
(
sk
b
,
sk
,
th
,
saddr
,
dev
);
release_sock
(
sk
);
release_sock
(
sk
);
return
(
0
);
return
(
0
);
}
}
...
@@ -3667,9 +3841,19 @@ static void tcp_write_wakeup(struct sock *sk)
...
@@ -3667,9 +3841,19 @@ static void tcp_write_wakeup(struct sock *sk)
if
(
sk
->
zapped
)
if
(
sk
->
zapped
)
return
;
/* Afer a valid reset we can send no more */
return
;
/* Afer a valid reset we can send no more */
if
(
sk
->
state
!=
TCP_ESTABLISHED
&&
sk
->
state
!=
TCP_CLOSE_WAIT
&&
/*
sk
->
state
!=
TCP_FIN_WAIT1
&&
sk
->
state
!=
TCP_FIN_WAIT2
)
* Write data can still be transmitted/retransmitted in the
* following states. If any other state is encountered, return.
*/
if
(
sk
->
state
!=
TCP_ESTABLISHED
&&
sk
->
state
!=
TCP_CLOSE_WAIT
&&
sk
->
state
!=
TCP_FIN_WAIT1
&&
sk
->
state
!=
TCP_LAST_ACK
&&
sk
->
state
!=
TCP_CLOSING
)
{
return
;
return
;
}
buff
=
sk
->
prot
->
wmalloc
(
sk
,
MAX_ACK_SIZE
,
1
,
GFP_ATOMIC
);
buff
=
sk
->
prot
->
wmalloc
(
sk
,
MAX_ACK_SIZE
,
1
,
GFP_ATOMIC
);
if
(
buff
==
NULL
)
if
(
buff
==
NULL
)
...
...
net/inet/timer.c
View file @
16119ae5
...
@@ -195,7 +195,7 @@ net_timer (unsigned long data)
...
@@ -195,7 +195,7 @@ net_timer (unsigned long data)
DPRINTF
((
DBG_TMR
,
"timer.c TIME_WRITE time-out 2
\n
"
));
DPRINTF
((
DBG_TMR
,
"timer.c TIME_WRITE time-out 2
\n
"
));
sk
->
err
=
ETIMEDOUT
;
sk
->
err
=
ETIMEDOUT
;
if
(
sk
->
state
==
TCP_FIN_WAIT1
||
sk
->
state
==
TCP_FIN_WAIT2
if
(
sk
->
state
==
TCP_FIN_WAIT1
||
sk
->
state
==
TCP_FIN_WAIT2
||
sk
->
state
==
TCP_
LAST_ACK
)
{
||
sk
->
state
==
TCP_
CLOSING
)
{
sk
->
state
=
TCP_TIME_WAIT
;
sk
->
state
=
TCP_TIME_WAIT
;
reset_timer
(
sk
,
TIME_CLOSE
,
TCP_TIMEWAIT_LEN
);
reset_timer
(
sk
,
TIME_CLOSE
,
TCP_TIMEWAIT_LEN
);
}
else
{
}
else
{
...
...
net/inet/udp.c
View file @
16119ae5
...
@@ -36,6 +36,7 @@
...
@@ -36,6 +36,7 @@
* Alan Cox : Use ip_tos and ip_ttl
* Alan Cox : Use ip_tos and ip_ttl
* Alan Cox : SNMP Mibs
* Alan Cox : SNMP Mibs
* Alan Cox : MSG_DONTROUTE, and 0.0.0.0 support.
* Alan Cox : MSG_DONTROUTE, and 0.0.0.0 support.
* Matt Dillon : UDP length checks.
*
*
*
*
* This program is free software; you can redistribute it and/or
* This program is free software; you can redistribute it and/or
...
@@ -653,7 +654,8 @@ int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
...
@@ -653,7 +654,8 @@ int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
{
{
struct
sock
*
sk
;
struct
sock
*
sk
;
struct
udphdr
*
uh
;
struct
udphdr
*
uh
;
unsigned
short
ulen
;
/*
/*
* Get the header.
* Get the header.
*/
*/
...
@@ -661,7 +663,22 @@ int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
...
@@ -661,7 +663,22 @@ int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
ip_statistics
.
IpInDelivers
++
;
ip_statistics
.
IpInDelivers
++
;
/*
* Validate the packet and the UDP length.
*/
ulen
=
ntohs
(
uh
->
len
);
if
(
ulen
>
len
||
len
<
sizeof
(
*
uh
)
||
ulen
<
sizeof
(
*
uh
))
{
printk
(
"UDP: short packet: %d/%d
\n
"
,
ulen
,
len
);
DPRINTF
((
DBG_UDP
,
"UDP: short packet %d/%d
\n
"
,
ulen
,
len
));
udp_statistics
.
UdpInErrors
++
;
kfree_skb
(
skb
,
FREE_WRITE
);
return
(
0
);
}
len
=
ulen
;
sk
=
get_sock
(
&
udp_prot
,
uh
->
dest
,
saddr
,
uh
->
source
,
daddr
);
sk
=
get_sock
(
&
udp_prot
,
uh
->
dest
,
saddr
,
uh
->
source
,
daddr
);
if
(
sk
==
NULL
)
if
(
sk
==
NULL
)
{
{
...
...
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