Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
79b2577a
Commit
79b2577a
authored
Sep 11, 2002
by
Jens Axboe
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ide core updates, and addition of ide-iops.c
parent
ce028ad0
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
2823 additions
and
1200 deletions
+2823
-1200
drivers/ide/ide-iops.c
drivers/ide/ide-iops.c
+1254
-0
drivers/ide/ide.c
drivers/ide/ide.c
+618
-720
include/linux/ide.h
include/linux/ide.h
+951
-480
No files found.
drivers/ide/ide-iops.c
0 → 100644
View file @
79b2577a
/*
* linux/drivers/ide/ide-iops.c Version 0.33 April 11, 2002
*
* Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
*
*
*/
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/major.h>
#include <linux/errno.h>
#include <linux/genhd.h>
#include <linux/blkpg.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/bitops.h>
static
inline
u8
ide_inb
(
u32
port
)
{
return
(
u8
)
IN_BYTE
(
port
);
}
static
inline
u8
ide_inb_p
(
u32
port
)
{
return
(
u8
)
IN_BYTE_P
(
port
);
}
static
inline
u16
ide_inw
(
u32
port
)
{
return
(
u16
)
IN_WORD
(
port
);
}
static
inline
u16
ide_inw_p
(
u32
port
)
{
return
(
u16
)
IN_WORD_P
(
port
);
}
static
inline
void
ide_insw
(
u32
port
,
void
*
addr
,
u32
count
)
{
while
(
count
--
)
{
*
(
u16
*
)
addr
=
IN_WORD
(
port
);
addr
+=
2
;
}
}
static
inline
void
ide_insw_p
(
u32
port
,
void
*
addr
,
u32
count
)
{
while
(
count
--
)
{
*
(
u16
*
)
addr
=
IN_WORD_P
(
port
);
addr
+=
2
;
}
}
static
inline
u32
ide_inl
(
u32
port
)
{
return
(
u32
)
IN_LONG
(
port
);
}
static
inline
u32
ide_inl_p
(
u32
port
)
{
return
(
u32
)
IN_LONG_P
(
port
);
}
static
inline
void
ide_insl
(
u32
port
,
void
*
addr
,
u32
count
)
{
ide_insw
(
port
,
addr
,
(
count
)
<<
1
);
// while (count--) { *(u32 *)addr = IN_LONG(port); addr += 4; }
}
static
inline
void
ide_insl_p
(
u32
port
,
void
*
addr
,
u32
count
)
{
ide_insw_p
(
port
,
addr
,
(
count
)
<<
1
);
// while (count--) { *(u32 *)addr = IN_LONG(port); addr += 4; }
}
static
inline
void
ide_outb
(
u8
addr
,
u32
port
)
{
OUT_BYTE
(
addr
,
port
);
}
static
inline
void
ide_outb_p
(
u8
addr
,
u32
port
)
{
OUT_BYTE_P
(
addr
,
port
);
}
static
inline
void
ide_outw
(
u16
addr
,
u32
port
)
{
OUT_WORD
(
addr
,
port
);
}
static
inline
void
ide_outw_p
(
u16
addr
,
u32
port
)
{
OUT_WORD_P
(
addr
,
port
);
}
static
inline
void
ide_outsw
(
u32
port
,
void
*
addr
,
u32
count
)
{
while
(
count
--
)
{
OUT_WORD
(
*
(
u16
*
)
addr
,
port
);
addr
+=
2
;
}
}
static
inline
void
ide_outsw_p
(
u32
port
,
void
*
addr
,
u32
count
)
{
while
(
count
--
)
{
OUT_WORD_P
(
*
(
u16
*
)
addr
,
port
);
addr
+=
2
;
}
}
static
inline
void
ide_outl
(
u32
addr
,
u32
port
)
{
OUT_LONG
(
addr
,
port
);
}
static
inline
void
ide_outl_p
(
u32
addr
,
u32
port
)
{
OUT_LONG_P
(
addr
,
port
);
}
static
inline
void
ide_outsl
(
u32
port
,
void
*
addr
,
u32
count
)
{
ide_outsw
(
port
,
addr
,
(
count
)
<<
1
);
// while (count--) { OUT_LONG(*(u32 *)addr, port); addr += 4; }
}
static
inline
void
ide_outsl_p
(
u32
port
,
void
*
addr
,
u32
count
)
{
ide_outsw_p
(
port
,
addr
,
(
count
)
<<
1
);
// while (count--) { OUT_LONG_P(*(u32 *)addr, port); addr += 4; }
}
void
default_hwif_iops
(
ide_hwif_t
*
hwif
)
{
hwif
->
OUTB
=
ide_outb
;
hwif
->
OUTBP
=
ide_outb_p
;
hwif
->
OUTW
=
ide_outw
;
hwif
->
OUTWP
=
ide_outw_p
;
hwif
->
OUTL
=
ide_outl
;
hwif
->
OUTLP
=
ide_outl_p
;
hwif
->
OUTSW
=
ide_outsw
;
hwif
->
OUTSWP
=
ide_outsw_p
;
hwif
->
OUTSL
=
ide_outsl
;
hwif
->
OUTSLP
=
ide_outsl_p
;
hwif
->
INB
=
ide_inb
;
hwif
->
INBP
=
ide_inb_p
;
hwif
->
INW
=
ide_inw
;
hwif
->
INWP
=
ide_inw_p
;
hwif
->
INL
=
ide_inl
;
hwif
->
INLP
=
ide_inl_p
;
hwif
->
INSW
=
ide_insw
;
hwif
->
INSWP
=
ide_insw_p
;
hwif
->
INSL
=
ide_insl
;
hwif
->
INSLP
=
ide_insl_p
;
}
EXPORT_SYMBOL
(
default_hwif_iops
);
void
default_hwif_transport
(
ide_hwif_t
*
hwif
)
{
hwif
->
ata_input_data
=
ata_input_data
;
hwif
->
ata_output_data
=
ata_output_data
;
hwif
->
atapi_input_bytes
=
atapi_input_bytes
;
hwif
->
atapi_output_bytes
=
atapi_output_bytes
;
}
EXPORT_SYMBOL
(
default_hwif_transport
);
u32
read_24
(
ide_drive_t
*
drive
)
{
u8
hcyl
=
HWIF
(
drive
)
->
INB
(
IDE_HCYL_REG
);
u8
lcyl
=
HWIF
(
drive
)
->
INB
(
IDE_LCYL_REG
);
u8
sect
=
HWIF
(
drive
)
->
INB
(
IDE_SECTOR_REG
);
return
(
hcyl
<<
16
)
|
(
lcyl
<<
8
)
|
sect
;
}
EXPORT_SYMBOL
(
read_24
);
void
SELECT_DRIVE
(
ide_drive_t
*
drive
)
{
if
(
HWIF
(
drive
)
->
selectproc
)
HWIF
(
drive
)
->
selectproc
(
drive
);
HWIF
(
drive
)
->
OUTB
(
drive
->
select
.
all
,
IDE_SELECT_REG
);
}
EXPORT_SYMBOL
(
SELECT_DRIVE
);
void
SELECT_INTERRUPT
(
ide_drive_t
*
drive
)
{
if
(
HWIF
(
drive
)
->
intrproc
)
HWIF
(
drive
)
->
intrproc
(
drive
);
else
HWIF
(
drive
)
->
OUTB
(
drive
->
ctl
|
2
,
IDE_CONTROL_REG
);
}
EXPORT_SYMBOL
(
SELECT_INTERRUPT
);
void
SELECT_MASK
(
ide_drive_t
*
drive
,
int
mask
)
{
if
(
HWIF
(
drive
)
->
maskproc
)
HWIF
(
drive
)
->
maskproc
(
drive
,
mask
);
}
EXPORT_SYMBOL
(
SELECT_MASK
);
void
QUIRK_LIST
(
ide_drive_t
*
drive
)
{
if
(
HWIF
(
drive
)
->
quirkproc
)
drive
->
quirk_list
=
HWIF
(
drive
)
->
quirkproc
(
drive
);
}
EXPORT_SYMBOL
(
QUIRK_LIST
);
#if SUPPORT_VLB_SYNC
/*
* Some localbus EIDE interfaces require a special access sequence
* when using 32-bit I/O instructions to transfer data. We call this
* the "vlb_sync" sequence, which consists of three successive reads
* of the sector count register location, with interrupts disabled
* to ensure that the reads all happen together.
*/
void
ata_vlb_sync
(
ide_drive_t
*
drive
,
ide_ioreg_t
port
)
{
(
void
)
HWIF
(
drive
)
->
INB
(
port
);
(
void
)
HWIF
(
drive
)
->
INB
(
port
);
(
void
)
HWIF
(
drive
)
->
INB
(
port
);
}
EXPORT_SYMBOL
(
ata_vlb_sync
);
#endif
/* SUPPORT_VLB_SYNC */
/*
* This is used for most PIO data transfers *from* the IDE interface
*/
void
ata_input_data
(
ide_drive_t
*
drive
,
void
*
buffer
,
u32
wcount
)
{
ide_hwif_t
*
hwif
=
HWIF
(
drive
);
u8
io_32bit
=
drive
->
io_32bit
;
if
(
io_32bit
)
{
#if SUPPORT_VLB_SYNC
if
(
io_32bit
&
2
)
{
unsigned
long
flags
;
local_irq_save
(
flags
);
ata_vlb_sync
(
drive
,
IDE_NSECTOR_REG
);
hwif
->
INSL
(
IDE_DATA_REG
,
buffer
,
wcount
);
local_irq_restore
(
flags
);
}
else
#endif
/* SUPPORT_VLB_SYNC */
hwif
->
INSL
(
IDE_DATA_REG
,
buffer
,
wcount
);
}
else
{
#if SUPPORT_SLOW_DATA_PORTS
if
(
drive
->
slow
)
{
u16
*
ptr
=
(
u16
*
)
buffer
;
while
(
wcount
--
)
{
*
ptr
++
=
hwif
->
INWP
(
IDE_DATA_REG
);
*
ptr
++
=
hwif
->
INWP
(
IDE_DATA_REG
);
}
}
else
#endif
/* SUPPORT_SLOW_DATA_PORTS */
hwif
->
INSW
(
IDE_DATA_REG
,
buffer
,
wcount
<<
1
);
}
}
EXPORT_SYMBOL
(
ata_input_data
);
/*
* This is used for most PIO data transfers *to* the IDE interface
*/
void
ata_output_data
(
ide_drive_t
*
drive
,
void
*
buffer
,
u32
wcount
)
{
ide_hwif_t
*
hwif
=
HWIF
(
drive
);
u8
io_32bit
=
drive
->
io_32bit
;
if
(
io_32bit
)
{
#if SUPPORT_VLB_SYNC
if
(
io_32bit
&
2
)
{
unsigned
long
flags
;
local_irq_save
(
flags
);
ata_vlb_sync
(
drive
,
IDE_NSECTOR_REG
);
hwif
->
OUTSL
(
IDE_DATA_REG
,
buffer
,
wcount
);
local_irq_restore
(
flags
);
}
else
#endif
/* SUPPORT_VLB_SYNC */
hwif
->
OUTSL
(
IDE_DATA_REG
,
buffer
,
wcount
);
}
else
{
#if SUPPORT_SLOW_DATA_PORTS
if
(
drive
->
slow
)
{
u16
*
ptr
=
(
u16
*
)
buffer
;
while
(
wcount
--
)
{
hwif
->
OUTWP
(
*
ptr
++
,
IDE_DATA_REG
);
hwif
->
OUTWP
(
*
ptr
++
,
IDE_DATA_REG
);
}
}
else
#endif
/* SUPPORT_SLOW_DATA_PORTS */
hwif
->
OUTSW
(
IDE_DATA_REG
,
buffer
,
wcount
<<
1
);
}
}
EXPORT_SYMBOL
(
ata_output_data
);
/*
* The following routines are mainly used by the ATAPI drivers.
*
* These routines will round up any request for an odd number of bytes,
* so if an odd bytecount is specified, be sure that there's at least one
* extra byte allocated for the buffer.
*/
void
atapi_input_bytes
(
ide_drive_t
*
drive
,
void
*
buffer
,
u32
bytecount
)
{
ide_hwif_t
*
hwif
=
HWIF
(
drive
);
++
bytecount
;
#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
if
(
MACH_IS_ATARI
||
MACH_IS_Q40
)
{
/* Atari has a byte-swapped IDE interface */
insw_swapw
(
IDE_DATA_REG
,
buffer
,
bytecount
/
2
);
return
;
}
#endif
/* CONFIG_ATARI */
hwif
->
ata_input_data
(
drive
,
buffer
,
bytecount
/
4
);
if
((
bytecount
&
0x03
)
>=
2
)
hwif
->
INSW
(
IDE_DATA_REG
,
((
u8
*
)
buffer
)
+
(
bytecount
&
~
0x03
),
1
);
}
EXPORT_SYMBOL
(
atapi_input_bytes
);
void
atapi_output_bytes
(
ide_drive_t
*
drive
,
void
*
buffer
,
u32
bytecount
)
{
ide_hwif_t
*
hwif
=
HWIF
(
drive
);
++
bytecount
;
#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
if
(
MACH_IS_ATARI
||
MACH_IS_Q40
)
{
/* Atari has a byte-swapped IDE interface */
outsw_swapw
(
IDE_DATA_REG
,
buffer
,
bytecount
/
2
);
return
;
}
#endif
/* CONFIG_ATARI */
hwif
->
ata_output_data
(
drive
,
buffer
,
bytecount
/
4
);
if
((
bytecount
&
0x03
)
>=
2
)
hwif
->
OUTSW
(
IDE_DATA_REG
,
((
u8
*
)
buffer
)
+
(
bytecount
&
~
0x03
),
1
);
}
EXPORT_SYMBOL
(
atapi_output_bytes
);
/*
* Beginning of Taskfile OPCODE Library and feature sets.
*/
void
ide_fix_driveid
(
struct
hd_driveid
*
id
)
{
#ifndef __LITTLE_ENDIAN
# ifdef __BIG_ENDIAN
int
i
;
u16
*
stringcast
;
id
->
config
=
__le16_to_cpu
(
id
->
config
);
id
->
cyls
=
__le16_to_cpu
(
id
->
cyls
);
id
->
reserved2
=
__le16_to_cpu
(
id
->
reserved2
);
id
->
heads
=
__le16_to_cpu
(
id
->
heads
);
id
->
track_bytes
=
__le16_to_cpu
(
id
->
track_bytes
);
id
->
sector_bytes
=
__le16_to_cpu
(
id
->
sector_bytes
);
id
->
sectors
=
__le16_to_cpu
(
id
->
sectors
);
id
->
vendor0
=
__le16_to_cpu
(
id
->
vendor0
);
id
->
vendor1
=
__le16_to_cpu
(
id
->
vendor1
);
id
->
vendor2
=
__le16_to_cpu
(
id
->
vendor2
);
stringcast
=
(
u16
*
)
&
id
->
serial_no
[
0
];
for
(
i
=
0
;
i
<
(
20
/
2
);
i
++
)
stringcast
[
i
]
=
__le16_to_cpu
(
stringcast
[
i
]);
id
->
buf_type
=
__le16_to_cpu
(
id
->
buf_type
);
id
->
buf_size
=
__le16_to_cpu
(
id
->
buf_size
);
id
->
ecc_bytes
=
__le16_to_cpu
(
id
->
ecc_bytes
);
stringcast
=
(
u16
*
)
&
id
->
fw_rev
[
0
];
for
(
i
=
0
;
i
<
(
8
/
2
);
i
++
)
stringcast
[
i
]
=
__le16_to_cpu
(
stringcast
[
i
]);
stringcast
=
(
u16
*
)
&
id
->
model
[
0
];
for
(
i
=
0
;
i
<
(
40
/
2
);
i
++
)
stringcast
[
i
]
=
__le16_to_cpu
(
stringcast
[
i
]);
id
->
dword_io
=
__le16_to_cpu
(
id
->
dword_io
);
id
->
reserved50
=
__le16_to_cpu
(
id
->
reserved50
);
id
->
field_valid
=
__le16_to_cpu
(
id
->
field_valid
);
id
->
cur_cyls
=
__le16_to_cpu
(
id
->
cur_cyls
);
id
->
cur_heads
=
__le16_to_cpu
(
id
->
cur_heads
);
id
->
cur_sectors
=
__le16_to_cpu
(
id
->
cur_sectors
);
id
->
cur_capacity0
=
__le16_to_cpu
(
id
->
cur_capacity0
);
id
->
cur_capacity1
=
__le16_to_cpu
(
id
->
cur_capacity1
);
id
->
lba_capacity
=
__le32_to_cpu
(
id
->
lba_capacity
);
id
->
dma_1word
=
__le16_to_cpu
(
id
->
dma_1word
);
id
->
dma_mword
=
__le16_to_cpu
(
id
->
dma_mword
);
id
->
eide_pio_modes
=
__le16_to_cpu
(
id
->
eide_pio_modes
);
id
->
eide_dma_min
=
__le16_to_cpu
(
id
->
eide_dma_min
);
id
->
eide_dma_time
=
__le16_to_cpu
(
id
->
eide_dma_time
);
id
->
eide_pio
=
__le16_to_cpu
(
id
->
eide_pio
);
id
->
eide_pio_iordy
=
__le16_to_cpu
(
id
->
eide_pio_iordy
);
for
(
i
=
0
;
i
<
2
;
++
i
)
id
->
words69_70
[
i
]
=
__le16_to_cpu
(
id
->
words69_70
[
i
]);
for
(
i
=
0
;
i
<
4
;
++
i
)
id
->
words71_74
[
i
]
=
__le16_to_cpu
(
id
->
words71_74
[
i
]);
id
->
queue_depth
=
__le16_to_cpu
(
id
->
queue_depth
);
for
(
i
=
0
;
i
<
4
;
++
i
)
id
->
words76_79
[
i
]
=
__le16_to_cpu
(
id
->
words76_79
[
i
]);
id
->
major_rev_num
=
__le16_to_cpu
(
id
->
major_rev_num
);
id
->
minor_rev_num
=
__le16_to_cpu
(
id
->
minor_rev_num
);
id
->
command_set_1
=
__le16_to_cpu
(
id
->
command_set_1
);
id
->
command_set_2
=
__le16_to_cpu
(
id
->
command_set_2
);
id
->
cfsse
=
__le16_to_cpu
(
id
->
cfsse
);
id
->
cfs_enable_1
=
__le16_to_cpu
(
id
->
cfs_enable_1
);
id
->
cfs_enable_2
=
__le16_to_cpu
(
id
->
cfs_enable_2
);
id
->
csf_default
=
__le16_to_cpu
(
id
->
csf_default
);
id
->
dma_ultra
=
__le16_to_cpu
(
id
->
dma_ultra
);
id
->
trseuc
=
__le16_to_cpu
(
id
->
trseuc
);
id
->
trsEuc
=
__le16_to_cpu
(
id
->
trsEuc
);
id
->
CurAPMvalues
=
__le16_to_cpu
(
id
->
CurAPMvalues
);
id
->
mprc
=
__le16_to_cpu
(
id
->
mprc
);
id
->
hw_config
=
__le16_to_cpu
(
id
->
hw_config
);
id
->
acoustic
=
__le16_to_cpu
(
id
->
acoustic
);
id
->
msrqs
=
__le16_to_cpu
(
id
->
msrqs
);
id
->
sxfert
=
__le16_to_cpu
(
id
->
sxfert
);
id
->
sal
=
__le16_to_cpu
(
id
->
sal
);
id
->
spg
=
__le32_to_cpu
(
id
->
spg
);
id
->
lba_capacity_2
=
__le64_to_cpu
(
id
->
lba_capacity_2
);
for
(
i
=
0
;
i
<
22
;
i
++
)
id
->
words104_125
[
i
]
=
__le16_to_cpu
(
id
->
words104_125
[
i
]);
id
->
last_lun
=
__le16_to_cpu
(
id
->
last_lun
);
id
->
word127
=
__le16_to_cpu
(
id
->
word127
);
id
->
dlf
=
__le16_to_cpu
(
id
->
dlf
);
id
->
csfo
=
__le16_to_cpu
(
id
->
csfo
);
for
(
i
=
0
;
i
<
26
;
i
++
)
id
->
words130_155
[
i
]
=
__le16_to_cpu
(
id
->
words130_155
[
i
]);
id
->
word156
=
__le16_to_cpu
(
id
->
word156
);
for
(
i
=
0
;
i
<
3
;
i
++
)
id
->
words157_159
[
i
]
=
__le16_to_cpu
(
id
->
words157_159
[
i
]);
id
->
cfa_power
=
__le16_to_cpu
(
id
->
cfa_power
);
for
(
i
=
0
;
i
<
14
;
i
++
)
id
->
words161_175
[
i
]
=
__le16_to_cpu
(
id
->
words161_175
[
i
]);
for
(
i
=
0
;
i
<
31
;
i
++
)
id
->
words176_205
[
i
]
=
__le16_to_cpu
(
id
->
words176_205
[
i
]);
for
(
i
=
0
;
i
<
48
;
i
++
)
id
->
words206_254
[
i
]
=
__le16_to_cpu
(
id
->
words206_254
[
i
]);
id
->
integrity_word
=
__le16_to_cpu
(
id
->
integrity_word
);
# else
# error "Please fix <asm/byteorder.h>"
# endif
#endif
}
EXPORT_SYMBOL
(
ide_fix_driveid
);
void
ide_fixstring
(
u8
*
s
,
const
int
bytecount
,
const
int
byteswap
)
{
u8
*
p
=
s
,
*
end
=
&
s
[
bytecount
&
~
1
];
/* bytecount must be even */
if
(
byteswap
)
{
/* convert from big-endian to host byte order */
for
(
p
=
end
;
p
!=
s
;)
{
unsigned
short
*
pp
=
(
unsigned
short
*
)
(
p
-=
2
);
*
pp
=
ntohs
(
*
pp
);
}
}
/* strip leading blanks */
while
(
s
!=
end
&&
*
s
==
' '
)
++
s
;
/* compress internal blanks and strip trailing blanks */
while
(
s
!=
end
&&
*
s
)
{
if
(
*
s
++
!=
' '
||
(
s
!=
end
&&
*
s
&&
*
s
!=
' '
))
*
p
++
=
*
(
s
-
1
);
}
/* wipe out trailing garbage */
while
(
p
!=
end
)
*
p
++
=
'\0'
;
}
EXPORT_SYMBOL
(
ide_fixstring
);
/*
* Needed for PCI irq sharing
*/
int
drive_is_ready
(
ide_drive_t
*
drive
)
{
ide_hwif_t
*
hwif
=
HWIF
(
drive
);
u8
stat
=
0
;
if
(
drive
->
waiting_for_dma
)
return
hwif
->
ide_dma_test_irq
(
drive
);
#if 0
/* need to guarantee 400ns since last command was issued */
udelay(1);
#endif
#ifdef CONFIG_IDEPCI_SHARE_IRQ
/*
* We do a passive status test under shared PCI interrupts on
* cards that truly share the ATA side interrupt, but may also share
* an interrupt with another pci card/device. We make no assumptions
* about possible isa-pnp and pci-pnp issues yet.
*/
if
(
IDE_CONTROL_REG
)
stat
=
hwif
->
INB
(
IDE_ALTSTATUS_REG
);
else
#endif
/* CONFIG_IDEPCI_SHARE_IRQ */
/* Note: this may clear a pending IRQ!! */
stat
=
hwif
->
INB
(
IDE_STATUS_REG
);
if
(
stat
&
BUSY_STAT
)
/* drive busy: definitely not interrupting */
return
0
;
/* drive ready: *might* be interrupting */
return
1
;
}
EXPORT_SYMBOL
(
drive_is_ready
);
/*
* Global for All, and taken from ide-pmac.c. Can be called
* with spinlock held & IRQs disabled, so don't schedule !
*/
int
wait_for_ready
(
ide_drive_t
*
drive
,
int
timeout
)
{
ide_hwif_t
*
hwif
=
HWIF
(
drive
);
u8
stat
=
0
;
while
(
--
timeout
)
{
stat
=
hwif
->
INB
(
IDE_STATUS_REG
);
if
(
!
(
stat
&
BUSY_STAT
))
{
if
(
drive
->
ready_stat
==
0
)
break
;
else
if
((
stat
&
drive
->
ready_stat
)
||
(
stat
&
ERR_STAT
))
break
;
}
mdelay
(
1
);
}
if
((
stat
&
ERR_STAT
)
||
timeout
<=
0
)
{
if
(
stat
&
ERR_STAT
)
{
printk
(
KERN_ERR
"%s: wait_for_ready, "
"error status: %x
\n
"
,
drive
->
name
,
stat
);
}
return
1
;
}
return
0
;
}
EXPORT_SYMBOL
(
wait_for_ready
);
/*
* This routine busy-waits for the drive status to be not "busy".
* It then checks the status for all of the "good" bits and none
* of the "bad" bits, and if all is okay it returns 0. All other
* cases return 1 after invoking ide_error() -- caller should just return.
*
* This routine should get fixed to not hog the cpu during extra long waits..
* That could be done by busy-waiting for the first jiffy or two, and then
* setting a timer to wake up at half second intervals thereafter,
* until timeout is achieved, before timing out.
*/
int
ide_wait_stat
(
ide_startstop_t
*
startstop
,
ide_drive_t
*
drive
,
u8
good
,
u8
bad
,
unsigned
long
timeout
)
{
ide_hwif_t
*
hwif
=
HWIF
(
drive
);
u8
stat
;
int
i
;
unsigned
long
flags
;
/* bail early if we've exceeded max_failures */
if
(
drive
->
max_failures
&&
(
drive
->
failures
>
drive
->
max_failures
))
{
*
startstop
=
ide_stopped
;
return
1
;
}
udelay
(
1
);
/* spec allows drive 400ns to assert "BUSY" */
if
((
stat
=
hwif
->
INB
(
IDE_STATUS_REG
))
&
BUSY_STAT
)
{
local_irq_set
(
flags
);
timeout
+=
jiffies
;
while
((
stat
=
hwif
->
INB
(
IDE_STATUS_REG
))
&
BUSY_STAT
)
{
if
(
time_after
(
jiffies
,
timeout
))
{
local_irq_restore
(
flags
);
*
startstop
=
DRIVER
(
drive
)
->
error
(
drive
,
"status timeout"
,
stat
);
return
1
;
}
}
local_irq_restore
(
flags
);
}
/*
* Allow status to settle, then read it again.
* A few rare drives vastly violate the 400ns spec here,
* so we'll wait up to 10usec for a "good" status
* rather than expensively fail things immediately.
* This fix courtesy of Matthew Faupel & Niccolo Rigacci.
*/
for
(
i
=
0
;
i
<
10
;
i
++
)
{
udelay
(
1
);
if
(
OK_STAT
((
stat
=
hwif
->
INB
(
IDE_STATUS_REG
)),
good
,
bad
))
return
0
;
}
*
startstop
=
DRIVER
(
drive
)
->
error
(
drive
,
"status error"
,
stat
);
return
1
;
}
EXPORT_SYMBOL
(
ide_wait_stat
);
/*
* All hosts that use the 80c ribbon must use!
* The name is derived from upper byte of word 93 and the 80c ribbon.
*/
u8
eighty_ninty_three
(
ide_drive_t
*
drive
)
{
#if 0
if (!HWIF(drive)->udma_four)
return 0;
if (drive->id->major_rev_num) {
int hssbd = 0;
int i;
/*
* Determime highest Supported SPEC
*/
for (i=1; i<=15; i++)
if (drive->id->major_rev_num & (1<<i))
hssbd++;
switch (hssbd) {
case 7:
case 6:
case 5:
/* ATA-4 and older do not support above Ultra 33 */
default:
return 0;
}
}
return ((u8) (
#ifndef CONFIG_IDEDMA_IVB
(drive->id->hw_config & 0x4000) &&
#endif /* CONFIG_IDEDMA_IVB */
(drive->id->hw_config & 0x6000)) ? 1 : 0);
#else
return
((
u8
)
((
HWIF
(
drive
)
->
udma_four
)
&&
#ifndef CONFIG_IDEDMA_IVB
(
drive
->
id
->
hw_config
&
0x4000
)
&&
#endif
/* CONFIG_IDEDMA_IVB */
(
drive
->
id
->
hw_config
&
0x6000
))
?
1
:
0
);
#endif
}
EXPORT_SYMBOL
(
eighty_ninty_three
);
int
ide_ata66_check
(
ide_drive_t
*
drive
,
ide_task_t
*
args
)
{
if
((
args
->
tfRegister
[
IDE_COMMAND_OFFSET
]
==
WIN_SETFEATURES
)
&&
(
args
->
tfRegister
[
IDE_SECTOR_OFFSET
]
>
XFER_UDMA_2
)
&&
(
args
->
tfRegister
[
IDE_FEATURE_OFFSET
]
==
SETFEATURES_XFER
))
{
#ifndef CONFIG_IDEDMA_IVB
if
((
drive
->
id
->
hw_config
&
0x6000
)
==
0
)
{
#else
/* !CONFIG_IDEDMA_IVB */
if
(((
drive
->
id
->
hw_config
&
0x2000
)
==
0
)
||
((
drive
->
id
->
hw_config
&
0x4000
)
==
0
))
{
#endif
/* CONFIG_IDEDMA_IVB */
printk
(
"%s: Speed warnings UDMA 3/4/5 is not "
"functional.
\n
"
,
drive
->
name
);
return
1
;
}
if
(
!
HWIF
(
drive
)
->
udma_four
)
{
printk
(
"%s: Speed warnings UDMA 3/4/5 is not "
"functional.
\n
"
,
HWIF
(
drive
)
->
name
);
return
1
;
}
}
return
0
;
}
EXPORT_SYMBOL
(
ide_ata66_check
);
/*
* Backside of HDIO_DRIVE_CMD call of SETFEATURES_XFER.
* 1 : Safe to update drive->id DMA registers.
* 0 : OOPs not allowed.
*/
int
set_transfer
(
ide_drive_t
*
drive
,
ide_task_t
*
args
)
{
if
((
args
->
tfRegister
[
IDE_COMMAND_OFFSET
]
==
WIN_SETFEATURES
)
&&
(
args
->
tfRegister
[
IDE_SECTOR_OFFSET
]
>=
XFER_SW_DMA_0
)
&&
(
args
->
tfRegister
[
IDE_FEATURE_OFFSET
]
==
SETFEATURES_XFER
)
&&
(
drive
->
id
->
dma_ultra
||
drive
->
id
->
dma_mword
||
drive
->
id
->
dma_1word
))
return
1
;
return
0
;
}
EXPORT_SYMBOL
(
set_transfer
);
u8
ide_auto_reduce_xfer
(
ide_drive_t
*
drive
)
{
if
(
!
drive
->
crc_count
)
return
drive
->
current_speed
;
drive
->
crc_count
=
0
;
switch
(
drive
->
current_speed
)
{
case
XFER_UDMA_7
:
return
XFER_UDMA_6
;
case
XFER_UDMA_6
:
return
XFER_UDMA_5
;
case
XFER_UDMA_5
:
return
XFER_UDMA_4
;
case
XFER_UDMA_4
:
return
XFER_UDMA_3
;
case
XFER_UDMA_3
:
return
XFER_UDMA_2
;
case
XFER_UDMA_2
:
return
XFER_UDMA_1
;
case
XFER_UDMA_1
:
return
XFER_UDMA_0
;
/*
* OOPS we do not goto non Ultra DMA modes
* without iCRC's available we force
* the system to PIO and make the user
* invoke the ATA-1 ATA-2 DMA modes.
*/
case
XFER_UDMA_0
:
default:
return
XFER_PIO_4
;
}
}
EXPORT_SYMBOL
(
ide_auto_reduce_xfer
);
/*
* Update the
*/
int
ide_driveid_update
(
ide_drive_t
*
drive
)
{
ide_hwif_t
*
hwif
=
HWIF
(
drive
);
struct
hd_driveid
*
id
;
#if 0
id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
if (!id)
return 0;
taskfile_lib_get_identify(drive, (char *)&id);
ide_fix_driveid(id);
if (id) {
drive->id->dma_ultra = id->dma_ultra;
drive->id->dma_mword = id->dma_mword;
drive->id->dma_1word = id->dma_1word;
/* anything more ? */
kfree(id);
}
return 1;
#else
/*
* Re-read drive->id for possible DMA mode
* change (copied from ide-probe.c)
*/
unsigned
long
timeout
,
flags
;
SELECT_MASK
(
drive
,
1
);
if
(
IDE_CONTROL_REG
)
hwif
->
OUTB
(
drive
->
ctl
,
IDE_CONTROL_REG
);
ide_delay_50ms
();
hwif
->
OUTB
(
WIN_IDENTIFY
,
IDE_COMMAND_REG
);
timeout
=
jiffies
+
WAIT_WORSTCASE
;
do
{
if
(
time_after
(
jiffies
,
timeout
))
{
SELECT_MASK
(
drive
,
0
);
return
0
;
/* drive timed-out */
}
ide_delay_50ms
();
/* give drive a breather */
}
while
(
hwif
->
INB
(
IDE_ALTSTATUS_REG
)
&
BUSY_STAT
);
ide_delay_50ms
();
/* wait for IRQ and DRQ_STAT */
if
(
!
OK_STAT
(
hwif
->
INB
(
IDE_STATUS_REG
),
DRQ_STAT
,
BAD_R_STAT
))
{
SELECT_MASK
(
drive
,
0
);
printk
(
"%s: CHECK for good STATUS
\n
"
,
drive
->
name
);
return
0
;
}
local_irq_save
(
flags
);
SELECT_MASK
(
drive
,
0
);
id
=
kmalloc
(
SECTOR_WORDS
*
4
,
GFP_ATOMIC
);
if
(
!
id
)
{
local_irq_restore
(
flags
);
return
0
;
}
ata_input_data
(
drive
,
id
,
SECTOR_WORDS
);
(
void
)
hwif
->
INB
(
IDE_STATUS_REG
);
/* clear drive IRQ */
local_irq_enable
();
local_irq_restore
(
flags
);
ide_fix_driveid
(
id
);
if
(
id
)
{
drive
->
id
->
dma_ultra
=
id
->
dma_ultra
;
drive
->
id
->
dma_mword
=
id
->
dma_mword
;
drive
->
id
->
dma_1word
=
id
->
dma_1word
;
/* anything more ? */
kfree
(
id
);
}
return
1
;
#endif
}
EXPORT_SYMBOL
(
ide_driveid_update
);
/*
* Similar to ide_wait_stat(), except it never calls ide_error internally.
* This is a kludge to handle the new ide_config_drive_speed() function,
* and should not otherwise be used anywhere. Eventually, the tuneproc's
* should be updated to return ide_startstop_t, in which case we can get
* rid of this abomination again. :) -ml
*
* It is gone..........
*
* const char *msg == consider adding for verbose errors.
*/
int
ide_config_drive_speed
(
ide_drive_t
*
drive
,
u8
speed
)
{
ide_hwif_t
*
hwif
=
HWIF
(
drive
);
int
i
,
error
=
1
;
u8
stat
;
// while (HWGROUP(drive)->busy)
// ide_delay_50ms();
#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
hwif
->
ide_dma_host_off
(
drive
);
#endif
/* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
/*
* Don't use ide_wait_cmd here - it will
* attempt to set_geometry and recalibrate,
* but for some reason these don't work at
* this point (lost interrupt).
*/
/*
* Select the drive, and issue the SETFEATURES command
*/
disable_irq
(
hwif
->
irq
);
/* disable_irq_nosync ?? */
udelay
(
1
);
SELECT_DRIVE
(
drive
);
SELECT_MASK
(
drive
,
0
);
udelay
(
1
);
if
(
IDE_CONTROL_REG
)
hwif
->
OUTB
(
drive
->
ctl
|
2
,
IDE_CONTROL_REG
);
hwif
->
OUTB
(
speed
,
IDE_NSECTOR_REG
);
hwif
->
OUTB
(
SETFEATURES_XFER
,
IDE_FEATURE_REG
);
hwif
->
OUTB
(
WIN_SETFEATURES
,
IDE_COMMAND_REG
);
if
((
IDE_CONTROL_REG
)
&&
(
drive
->
quirk_list
==
2
))
hwif
->
OUTB
(
drive
->
ctl
,
IDE_CONTROL_REG
);
udelay
(
1
);
/*
* Wait for drive to become non-BUSY
*/
if
((
stat
=
hwif
->
INB
(
IDE_STATUS_REG
))
&
BUSY_STAT
)
{
unsigned
long
flags
,
timeout
;
local_irq_set
(
flags
);
timeout
=
jiffies
+
WAIT_CMD
;
while
((
stat
=
hwif
->
INB
(
IDE_STATUS_REG
))
&
BUSY_STAT
)
{
if
(
time_after
(
jiffies
,
timeout
))
break
;
}
local_irq_restore
(
flags
);
}
/*
* Allow status to settle, then read it again.
* A few rare drives vastly violate the 400ns spec here,
* so we'll wait up to 10usec for a "good" status
* rather than expensively fail things immediately.
* This fix courtesy of Matthew Faupel & Niccolo Rigacci.
*/
for
(
i
=
0
;
i
<
10
;
i
++
)
{
udelay
(
1
);
if
(
OK_STAT
((
stat
=
hwif
->
INB
(
IDE_STATUS_REG
)),
DRIVE_READY
,
BUSY_STAT
|
DRQ_STAT
|
ERR_STAT
))
{
error
=
0
;
break
;
}
}
SELECT_MASK
(
drive
,
0
);
enable_irq
(
hwif
->
irq
);
if
(
error
)
{
(
void
)
ide_dump_status
(
drive
,
"set_drive_speed_status"
,
stat
);
return
error
;
}
drive
->
id
->
dma_ultra
&=
~
0xFF00
;
drive
->
id
->
dma_mword
&=
~
0x0F00
;
drive
->
id
->
dma_1word
&=
~
0x0F00
;
#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
if
(
speed
>=
XFER_SW_DMA_0
)
hwif
->
ide_dma_host_on
(
drive
);
else
hwif
->
ide_dma_off
(
drive
);
#endif
/* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
switch
(
speed
)
{
case
XFER_UDMA_7
:
drive
->
id
->
dma_ultra
|=
0x8080
;
break
;
case
XFER_UDMA_6
:
drive
->
id
->
dma_ultra
|=
0x4040
;
break
;
case
XFER_UDMA_5
:
drive
->
id
->
dma_ultra
|=
0x2020
;
break
;
case
XFER_UDMA_4
:
drive
->
id
->
dma_ultra
|=
0x1010
;
break
;
case
XFER_UDMA_3
:
drive
->
id
->
dma_ultra
|=
0x0808
;
break
;
case
XFER_UDMA_2
:
drive
->
id
->
dma_ultra
|=
0x0404
;
break
;
case
XFER_UDMA_1
:
drive
->
id
->
dma_ultra
|=
0x0202
;
break
;
case
XFER_UDMA_0
:
drive
->
id
->
dma_ultra
|=
0x0101
;
break
;
case
XFER_MW_DMA_2
:
drive
->
id
->
dma_mword
|=
0x0404
;
break
;
case
XFER_MW_DMA_1
:
drive
->
id
->
dma_mword
|=
0x0202
;
break
;
case
XFER_MW_DMA_0
:
drive
->
id
->
dma_mword
|=
0x0101
;
break
;
case
XFER_SW_DMA_2
:
drive
->
id
->
dma_1word
|=
0x0404
;
break
;
case
XFER_SW_DMA_1
:
drive
->
id
->
dma_1word
|=
0x0202
;
break
;
case
XFER_SW_DMA_0
:
drive
->
id
->
dma_1word
|=
0x0101
;
break
;
default:
break
;
}
if
(
!
drive
->
init_speed
)
drive
->
init_speed
=
speed
;
drive
->
current_speed
=
speed
;
return
error
;
}
EXPORT_SYMBOL
(
ide_config_drive_speed
);
/*
* This should get invoked any time we exit the driver to
* wait for an interrupt response from a drive. handler() points
* at the appropriate code to handle the next interrupt, and a
* timer is started to prevent us from waiting forever in case
* something goes wrong (see the ide_timer_expiry() handler later on).
*/
void
ide_set_handler
(
ide_drive_t
*
drive
,
ide_handler_t
*
handler
,
unsigned
int
timeout
,
ide_expiry_t
*
expiry
)
{
unsigned
long
flags
;
ide_hwgroup_t
*
hwgroup
=
HWGROUP
(
drive
);
spin_lock_irqsave
(
&
ide_lock
,
flags
);
if
(
hwgroup
->
handler
!=
NULL
)
{
printk
(
"%s: ide_set_handler: handler not null; "
"old=%p, new=%p
\n
"
,
drive
->
name
,
hwgroup
->
handler
,
handler
);
}
hwgroup
->
handler
=
handler
;
hwgroup
->
expiry
=
expiry
;
hwgroup
->
timer
.
expires
=
jiffies
+
timeout
;
add_timer
(
&
hwgroup
->
timer
);
spin_unlock_irqrestore
(
&
ide_lock
,
flags
);
}
EXPORT_SYMBOL
(
ide_set_handler
);
/* needed below */
ide_startstop_t
do_reset1
(
ide_drive_t
*
,
int
);
/*
* atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
* during an atapi drive reset operation. If the drive has not yet responded,
* and we have not yet hit our maximum waiting time, then the timer is restarted
* for another 50ms.
*/
static
ide_startstop_t
atapi_reset_pollfunc
(
ide_drive_t
*
drive
)
{
ide_hwgroup_t
*
hwgroup
=
HWGROUP
(
drive
);
ide_hwif_t
*
hwif
=
HWIF
(
drive
);
u8
stat
;
SELECT_DRIVE
(
drive
);
udelay
(
10
);
if
(
OK_STAT
(
stat
=
hwif
->
INB
(
IDE_STATUS_REG
),
0
,
BUSY_STAT
))
{
printk
(
"%s: ATAPI reset complete
\n
"
,
drive
->
name
);
}
else
{
if
(
time_before
(
jiffies
,
hwgroup
->
poll_timeout
))
{
if
(
HWGROUP
(
drive
)
->
handler
!=
NULL
)
BUG
();
ide_set_handler
(
drive
,
&
atapi_reset_pollfunc
,
HZ
/
20
,
NULL
);
/* continue polling */
return
ide_started
;
}
/* end of polling */
hwgroup
->
poll_timeout
=
0
;
printk
(
"%s: ATAPI reset timed-out, status=0x%02x
\n
"
,
drive
->
name
,
stat
);
/* do it the old fashioned way */
return
do_reset1
(
drive
,
1
);
}
/* done polling */
hwgroup
->
poll_timeout
=
0
;
return
ide_stopped
;
}
/*
* reset_pollfunc() gets invoked to poll the interface for completion every 50ms
* during an ide reset operation. If the drives have not yet responded,
* and we have not yet hit our maximum waiting time, then the timer is restarted
* for another 50ms.
*/
static
ide_startstop_t
reset_pollfunc
(
ide_drive_t
*
drive
)
{
ide_hwgroup_t
*
hwgroup
=
HWGROUP
(
drive
);
ide_hwif_t
*
hwif
=
HWIF
(
drive
);
u8
tmp
;
if
(
hwif
->
reset_poll
!=
NULL
)
{
if
(
hwif
->
reset_poll
(
drive
))
{
printk
(
KERN_ERR
"%s: host reset_poll failure for %s.
\n
"
,
hwif
->
name
,
drive
->
name
);
return
ide_stopped
;
}
}
if
(
!
OK_STAT
(
tmp
=
hwif
->
INB
(
IDE_STATUS_REG
),
0
,
BUSY_STAT
))
{
if
(
time_before
(
jiffies
,
hwgroup
->
poll_timeout
))
{
if
(
HWGROUP
(
drive
)
->
handler
!=
NULL
)
BUG
();
ide_set_handler
(
drive
,
&
reset_pollfunc
,
HZ
/
20
,
NULL
);
/* continue polling */
return
ide_started
;
}
printk
(
"%s: reset timed-out, status=0x%02x
\n
"
,
hwif
->
name
,
tmp
);
drive
->
failures
++
;
}
else
{
printk
(
"%s: reset: "
,
hwif
->
name
);
if
((
tmp
=
hwif
->
INB
(
IDE_ERROR_REG
))
==
1
)
{
printk
(
"success
\n
"
);
drive
->
failures
=
0
;
}
else
{
drive
->
failures
++
;
#if FANCY_STATUS_DUMPS
printk
(
"master: "
);
switch
(
tmp
&
0x7f
)
{
case
1
:
printk
(
"passed"
);
break
;
case
2
:
printk
(
"formatter device error"
);
break
;
case
3
:
printk
(
"sector buffer error"
);
break
;
case
4
:
printk
(
"ECC circuitry error"
);
break
;
case
5
:
printk
(
"controlling MPU error"
);
break
;
default:
printk
(
"error (0x%02x?)"
,
tmp
);
}
if
(
tmp
&
0x80
)
printk
(
"; slave: failed"
);
printk
(
"
\n
"
);
#else
printk
(
"failed
\n
"
);
#endif
/* FANCY_STATUS_DUMPS */
}
}
hwgroup
->
poll_timeout
=
0
;
/* done polling */
return
ide_stopped
;
}
void
check_dma_crc
(
ide_drive_t
*
drive
)
{
if
(
drive
->
crc_count
)
{
(
void
)
HWIF
(
drive
)
->
ide_dma_off_quietly
(
drive
);
if
((
HWIF
(
drive
)
->
speedproc
)
!=
NULL
)
HWIF
(
drive
)
->
speedproc
(
drive
,
ide_auto_reduce_xfer
(
drive
));
if
(
drive
->
current_speed
>=
XFER_SW_DMA_0
)
(
void
)
HWIF
(
drive
)
->
ide_dma_on
(
drive
);
}
else
{
(
void
)
HWIF
(
drive
)
->
ide_dma_off
(
drive
);
}
}
void
pre_reset
(
ide_drive_t
*
drive
)
{
if
(
drive
->
driver
!=
NULL
)
DRIVER
(
drive
)
->
pre_reset
(
drive
);
if
(
!
drive
->
keep_settings
)
{
if
(
drive
->
using_dma
)
{
check_dma_crc
(
drive
);
}
else
{
drive
->
unmask
=
0
;
drive
->
io_32bit
=
0
;
}
return
;
}
if
(
drive
->
using_dma
)
check_dma_crc
(
drive
);
if
(
HWIF
(
drive
)
->
pre_reset
!=
NULL
)
HWIF
(
drive
)
->
pre_reset
(
drive
);
}
/*
* do_reset1() attempts to recover a confused drive by resetting it.
* Unfortunately, resetting a disk drive actually resets all devices on
* the same interface, so it can really be thought of as resetting the
* interface rather than resetting the drive.
*
* ATAPI devices have their own reset mechanism which allows them to be
* individually reset without clobbering other devices on the same interface.
*
* Unfortunately, the IDE interface does not generate an interrupt to let
* us know when the reset operation has finished, so we must poll for this.
* Equally poor, though, is the fact that this may a very long time to complete,
* (up to 30 seconds worstcase). So, instead of busy-waiting here for it,
* we set a timer to poll at 50ms intervals.
*/
ide_startstop_t
do_reset1
(
ide_drive_t
*
drive
,
int
do_not_try_atapi
)
{
unsigned
int
unit
;
unsigned
long
flags
;
ide_hwif_t
*
hwif
=
HWIF
(
drive
);
ide_hwgroup_t
*
hwgroup
=
HWGROUP
(
drive
);
local_irq_save
(
flags
);
/* For an ATAPI device, first try an ATAPI SRST. */
if
(
drive
->
media
!=
ide_disk
&&
!
do_not_try_atapi
)
{
pre_reset
(
drive
);
SELECT_DRIVE
(
drive
);
udelay
(
20
);
hwif
->
OUTB
(
WIN_SRST
,
IDE_COMMAND_REG
);
hwgroup
->
poll_timeout
=
jiffies
+
WAIT_WORSTCASE
;
if
(
HWGROUP
(
drive
)
->
handler
!=
NULL
)
BUG
();
ide_set_handler
(
drive
,
&
atapi_reset_pollfunc
,
HZ
/
20
,
NULL
);
local_irq_restore
(
flags
);
return
ide_started
;
}
/*
* First, reset any device state data we were maintaining
* for any of the drives on this interface.
*/
for
(
unit
=
0
;
unit
<
MAX_DRIVES
;
++
unit
)
pre_reset
(
&
hwif
->
drives
[
unit
]);
#if OK_TO_RESET_CONTROLLER
if
(
!
IDE_CONTROL_REG
)
{
local_irq_restore
(
flags
);
return
ide_stopped
;
}
# if 0
{
u8
control
=
hwif
->
INB
(
IDE_CONTROL_REG
);
control
|=
0x04
;
hwif
->
OUTB
(
control
,
IDE_CONTROL_REG
);
udelay
(
30
);
control
&=
0xFB
;
hwif
->
OUTB
(
control
,
IDE_CONTROL_REG
);
}
# else
/*
* Note that we also set nIEN while resetting the device,
* to mask unwanted interrupts from the interface during the reset.
* However, due to the design of PC hardware, this will cause an
* immediate interrupt due to the edge transition it produces.
* This single interrupt gives us a "fast poll" for drives that
* recover from reset very quickly, saving us the first 50ms wait time.
*/
/* set SRST and nIEN */
hwif
->
OUTB
(
drive
->
ctl
|
6
,
IDE_CONTROL_REG
);
/* more than enough time */
udelay
(
10
);
if
(
drive
->
quirk_list
==
2
)
{
/* clear SRST and nIEN */
hwif
->
OUTB
(
drive
->
ctl
,
IDE_CONTROL_REG
);
}
else
{
/* clear SRST, leave nIEN */
hwif
->
OUTB
(
drive
->
ctl
|
2
,
IDE_CONTROL_REG
);
}
/* more than enough time */
udelay
(
10
);
hwgroup
->
poll_timeout
=
jiffies
+
WAIT_WORSTCASE
;
if
(
HWGROUP
(
drive
)
->
handler
!=
NULL
)
BUG
();
ide_set_handler
(
drive
,
&
reset_pollfunc
,
HZ
/
20
,
NULL
);
# endif
/*
* Some weird controller like resetting themselves to a strange
* state when the disks are reset this way. At least, the Winbond
* 553 documentation says that
*/
if
(
hwif
->
resetproc
!=
NULL
)
{
hwif
->
resetproc
(
drive
);
# if 0
if
(
drive
->
failures
)
{
local_irq_restore
(
flags
);
return
ide_stopped
;
}
# endif
}
#endif
/* OK_TO_RESET_CONTROLLER */
local_irq_restore
(
flags
);
return
ide_started
;
}
#if 0
/*
* ide_do_reset() is the entry point to the drive/interface reset code.
*/
ide_startstop_t ide_do_reset (ide_drive_t *drive)
{
return do_reset1(drive, 0);
}
#else
/*
* ide_do_reset() is the entry point to the drive/interface reset code.
*/
ide_startstop_t
ide_do_reset
(
ide_drive_t
*
drive
)
{
ide_startstop_t
start_stop
=
ide_started
;
# if 0
u8
tmp_dma
=
drive
->
using_dma
;
u8
cspeed
=
drive
->
current_speed
;
u8
unmask
=
drive
->
unmask
;
# endif
if
(
HWGROUP
(
drive
)
->
handler
!=
NULL
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
&
ide_lock
,
flags
);
HWGROUP
(
drive
)
->
handler
=
NULL
;
del_timer
(
&
HWGROUP
(
drive
)
->
timer
);
spin_unlock_irqrestore
(
&
ide_lock
,
flags
);
}
start_stop
=
do_reset1
(
drive
,
0
);
# if 0
/*
* check for suspend-spindown flag,
* to attempt a restart or spinup of device.
*/
if
(
drive
->
suspend_reset
)
{
/*
* APM WAKE UP todo !!
* int nogoodpower = 1;
* while(nogoodpower) {
* check_power1() or check_power2()
* nogoodpower = 0;
* }
* HWIF(drive)->multiproc(drive);
*/
# endif
return
start_stop
;
}
#endif
EXPORT_SYMBOL
(
ide_do_reset
);
drivers/ide/ide.c
View file @
79b2577a
/*
* linux/drivers/ide/ide.c Version
6.31 June 9, 2000
* linux/drivers/ide/ide.c Version
7.00alpha1 August 19 2002
*
* Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
*/
...
...
@@ -12,7 +12,8 @@
* See linux/MAINTAINERS for address of current maintainer.
*
* This is the multiple IDE interface driver, as evolved from hd.c.
* It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs (usually 14 & 15).
* It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs
* (usually 14 & 15).
* There can be up to two drives per interface, as per the ATA-2 spec.
*
* Primary: ide0, port 0x1f0; major=3; hda is minor=0; hdb is minor=64
...
...
@@ -113,6 +114,7 @@
* Version 6.31 Debug Share INTR's and request queue streaming
* Native ATA-100 support
* Prep for Cascades Project
* Version 7.00alpha First named revision of ide rearrange
*
* Some additional driver compile-time options are in ./include/linux/ide.h
*
...
...
@@ -121,8 +123,8 @@
*
*/
#define REVISION "Revision:
6.31
"
#define VERSION "Id: ide.c
6.31 2000/06/09
"
#define REVISION "Revision:
7.00alpha2
"
#define VERSION "Id: ide.c
7.00a2 20020906
"
#undef REALLY_SLOW_IO
/* most systems can safely undef this */
...
...
@@ -141,9 +143,7 @@
#include <linux/genhd.h>
#include <linux/blkpg.h>
#include <linux/slab.h>
#ifndef MODULE
#include <linux/init.h>
#endif
/* MODULE */
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/ide.h>
...
...
@@ -161,28 +161,24 @@
#include "ide_modes.h"
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
/* CONFIG_KMOD */
/* default maximum number of failures */
#define IDE_DEFAULT_MAX_FAILURES 1
static
const
byte
ide_hwif_to_major
[]
=
{
IDE0_MAJOR
,
IDE1_MAJOR
,
IDE2_MAJOR
,
IDE3_MAJOR
,
IDE4_MAJOR
,
IDE5_MAJOR
,
IDE6_MAJOR
,
IDE7_MAJOR
,
IDE8_MAJOR
,
IDE9_MAJOR
};
static
const
u8
ide_hwif_to_major
[]
=
{
IDE0_MAJOR
,
IDE1_MAJOR
,
IDE2_MAJOR
,
IDE3_MAJOR
,
IDE4_MAJOR
,
IDE5_MAJOR
,
IDE6_MAJOR
,
IDE7_MAJOR
,
IDE8_MAJOR
,
IDE9_MAJOR
};
static
int
idebus_parameter
;
/* holds the "idebus=" parameter */
static
int
system_bus_speed
;
/* holds what we think is VESA/PCI bus speed */
static
int
initializing
;
/* set while initializing built-in drivers */
static
int
idebus_parameter
;
/* holds the "idebus=" parameter */
static
int
system_bus_speed
;
/* holds what we think is VESA/PCI bus speed */
static
int
initializing
;
/* set while initializing built-in drivers */
spinlock_t
ide_lock
__cacheline_aligned_in_smp
=
SPIN_LOCK_UNLOCKED
;
#ifdef CONFIG_BLK_DEV_IDESCSI_24
#define CONFIG_BLK_DEV_IDESCSI
#endif
#ifdef CONFIG_BLK_DEV_IDEPCI
static
int
ide_scan_direction
;
/* THIS was formerly 2.2.x pci=reverse */
#endif
/* CONFIG_BLK_DEV_IDEPCI */
static
int
ide_scan_direction
;
/* THIS was formerly 2.2.x pci=reverse */
#if defined(__mc68000__) || defined(CONFIG_APUS)
/*
...
...
@@ -192,33 +188,57 @@ static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */
static
int
ide_intr_lock
;
#endif
/* __mc68000__ || CONFIG_APUS */
#ifdef CONFIG_IDEDMA_AUTO
int
noautodma
=
0
;
#else
int
noautodma
=
1
;
#endif
/*
* ide_modules keeps track of the available IDE chipset/probe/driver modules.
*/
ide_module_t
*
ide_chipsets
;
ide_module_t
*
ide_probe
;
/*
* This is declared extern in ide.h, for access by other IDE modules:
*/
ide_hwif_t
ide_hwifs
[
MAX_HWIFS
];
/* master data repository */
ide_hwif_t
ide_hwifs
[
MAX_HWIFS
];
/* master data repository */
EXPORT_SYMBOL
(
ide_hwifs
);
ide_devices_t
*
idedisk
;
ide_devices_t
*
idecd
;
ide_devices_t
*
idefloppy
;
ide_devices_t
*
idetape
;
ide_devices_t
*
idescsi
;
EXPORT_SYMBOL
(
idedisk
);
EXPORT_SYMBOL
(
idecd
);
EXPORT_SYMBOL
(
idefloppy
);
EXPORT_SYMBOL
(
idetape
);
EXPORT_SYMBOL
(
idescsi
);
#if (DISK_RECOVERY_TIME > 0)
Error
So
the
User
Has
To
Fix
the
Compilation
And
Stop
Hacking
Port
0x43
Does
anyone
ever
use
this
anyway
??
/*
* For really screwy hardware (hey, at least it *can* be used with Linux)
* we can enforce a minimum delay time between successive operations.
*/
static
unsigned
long
read_timer
(
void
)
static
unsigned
long
read_timer
(
ide_hwif_t
*
hwif
)
{
unsigned
long
t
,
flags
;
int
i
;
/* FIXME this is completely unsafe! */
local_irq_save
(
flags
);
t
=
jiffies
*
11932
;
outb_p
(
0
,
0x43
);
outb_p
(
0
,
0x43
);
i
=
inb_p
(
0x40
);
i
|=
IN_BYTE
(
0x40
)
<<
8
;
i
|=
inb_p
(
0x40
)
<<
8
;
local_irq_restore
(
flags
);
return
(
t
-
i
);
}
...
...
@@ -227,7 +247,7 @@ static unsigned long read_timer (void)
static
inline
void
set_recovery_timer
(
ide_hwif_t
*
hwif
)
{
#if (DISK_RECOVERY_TIME > 0)
hwif
->
last_time
=
read_timer
();
hwif
->
last_time
=
read_timer
(
hwif
);
#endif
/* DISK_RECOVERY_TIME */
}
...
...
@@ -260,6 +280,16 @@ static void init_hwif_data (unsigned int index)
hwif
->
name
[
2
]
=
'e'
;
hwif
->
name
[
3
]
=
'0'
+
index
;
hwif
->
bus_state
=
BUSSTATE_ON
;
hwif
->
reset_poll
=
NULL
;
hwif
->
pre_reset
=
NULL
;
hwif
->
atapi_dma
=
0
;
/* disable all atapi dma */
hwif
->
ultra_mask
=
0x80
;
/* disable all ultra */
hwif
->
mwdma_mask
=
0x80
;
/* disable all mwdma */
hwif
->
swdma_mask
=
0x80
;
/* disable all swdma */
default_hwif_iops
(
hwif
);
default_hwif_transport
(
hwif
);
for
(
unit
=
0
;
unit
<
MAX_DRIVES
;
++
unit
)
{
ide_drive_t
*
drive
=
&
hwif
->
drives
[
unit
];
...
...
@@ -275,6 +305,8 @@ static void init_hwif_data (unsigned int index)
drive
->
name
[
1
]
=
'd'
;
drive
->
name
[
2
]
=
'a'
+
(
index
*
MAX_DRIVES
)
+
unit
;
drive
->
max_failures
=
IDE_DEFAULT_MAX_FAILURES
;
drive
->
using_dma
=
0
;
drive
->
is_flash
=
0
;
INIT_LIST_HEAD
(
&
drive
->
list
);
}
}
...
...
@@ -292,6 +324,9 @@ static void init_hwif_data (unsigned int index)
* This is too bad, as otherwise we could dynamically allocate the
* ide_drive_t structs as needed, rather than always consuming memory
* for the max possible number (MAX_HWIFS * MAX_DRIVES) of them.
*
* FIXME: We should stuff the setup data into __init and copy the
* relevant hwifs/allocate them properly during boot.
*/
#define MAGIC_COOKIE 0x12345678
static
void
__init
init_ide_data
(
void
)
...
...
@@ -314,37 +349,6 @@ static void __init init_ide_data (void)
system_bus_speed
=
0
;
}
/*
* CompactFlash cards and their brethern pretend to be removable hard disks, except:
* (1) they never have a slave unit, and
* (2) they don't have doorlock mechanisms.
* This test catches them, and is invoked elsewhere when setting appropriate config bits.
*
* FIXME: This treatment is probably applicable for *all* PCMCIA (PC CARD) devices,
* so in linux 2.3.x we should change this to just treat all PCMCIA drives this way,
* and get rid of the model-name tests below (too big of an interface change for 2.2.x).
* At that time, we might also consider parameterizing the timeouts and retries,
* since these are MUCH faster than mechanical drives. -M.Lord
*/
int
drive_is_flashcard
(
ide_drive_t
*
drive
)
{
struct
hd_driveid
*
id
=
drive
->
id
;
if
(
drive
->
removable
&&
id
!=
NULL
)
{
if
(
id
->
config
==
0x848a
)
return
1
;
/* CompactFlash */
if
(
!
strncmp
(
id
->
model
,
"KODAK ATA_FLASH"
,
15
)
/* Kodak */
||
!
strncmp
(
id
->
model
,
"Hitachi CV"
,
10
)
/* Hitachi */
||
!
strncmp
(
id
->
model
,
"SunDisk SDCFB"
,
13
)
/* SunDisk */
||
!
strncmp
(
id
->
model
,
"HAGIWARA HPC"
,
12
)
/* Hagiwara */
||
!
strncmp
(
id
->
model
,
"LEXAR ATA_FLASH"
,
15
)
/* Lexar */
||
!
strncmp
(
id
->
model
,
"ATA_FLASH"
,
9
))
/* Simple Tech */
{
return
1
;
/* yes, it is a flash memory card */
}
}
return
0
;
/* no, it is not a flash memory card */
}
/*
* ide_system_bus_speed() returns what we think is the system VESA/PCI
* bus speed (in MHz). This is used for calculating interface PIO timings.
...
...
@@ -355,15 +359,18 @@ int drive_is_flashcard (ide_drive_t *drive)
int
ide_system_bus_speed
(
void
)
{
if
(
!
system_bus_speed
)
{
if
(
idebus_parameter
)
system_bus_speed
=
idebus_parameter
;
/* user supplied value */
#ifdef CONFIG_PCI
else
if
(
pci_present
())
system_bus_speed
=
33
;
/* safe default value for PCI */
#endif
/* CONFIG_PCI */
else
system_bus_speed
=
50
;
/* safe default value for VESA and PCI */
printk
(
"ide: Assuming %dMHz system bus speed for PIO modes%s
\n
"
,
system_bus_speed
,
if
(
idebus_parameter
)
{
/* user supplied value */
system_bus_speed
=
idebus_parameter
;
}
else
if
(
pci_present
())
{
/* safe default value for PCI */
system_bus_speed
=
33
;
}
else
{
/* safe default value for VESA and PCI */
system_bus_speed
=
50
;
}
printk
(
"ide: Assuming %dMHz system bus speed "
"for PIO modes%s
\n
"
,
system_bus_speed
,
idebus_parameter
?
""
:
"; override with idebus=xx"
);
}
return
system_bus_speed
;
...
...
@@ -372,7 +379,7 @@ int ide_system_bus_speed (void)
/*
* This is our end_request replacement function.
*/
int
ide_end_request
(
ide_drive_t
*
drive
,
int
uptodate
)
int
ide_end_request
(
ide_drive_t
*
drive
,
int
uptodate
,
int
nr_sectors
)
{
struct
request
*
rq
;
unsigned
long
flags
;
...
...
@@ -383,16 +390,19 @@ int ide_end_request (ide_drive_t *drive, int uptodate)
BUG_ON
(
!
(
rq
->
flags
&
REQ_STARTED
));
if
(
!
nr_sectors
)
nr_sectors
=
rq
->
hard_cur_sectors
;
/*
* decide whether to reenable DMA -- 3 is a random magic for now,
* if we DMA timeout more than 3 times, just stay in PIO
*/
if
(
drive
->
state
==
DMA_PIO_RETRY
&&
drive
->
retry_pio
<=
3
)
{
drive
->
state
=
0
;
HWGROUP
(
drive
)
->
hwif
->
dmaproc
(
ide_dma_on
,
drive
);
HWGROUP
(
drive
)
->
hwif
->
ide_dma_on
(
drive
);
}
if
(
!
end_that_request_first
(
rq
,
uptodate
,
rq
->
hard_cu
r_sectors
))
{
if
(
!
end_that_request_first
(
rq
,
uptodate
,
n
r_sectors
))
{
add_blkdev_randomness
(
major
(
rq
->
rq_dev
));
blkdev_dequeue_request
(
rq
);
HWGROUP
(
drive
)
->
rq
=
NULL
;
...
...
@@ -403,30 +413,7 @@ int ide_end_request (ide_drive_t *drive, int uptodate)
return
ret
;
}
/*
* This should get invoked any time we exit the driver to
* wait for an interrupt response from a drive. handler() points
* at the appropriate code to handle the next interrupt, and a
* timer is started to prevent us from waiting forever in case
* something goes wrong (see the ide_timer_expiry() handler later on).
*/
void
ide_set_handler
(
ide_drive_t
*
drive
,
ide_handler_t
*
handler
,
unsigned
int
timeout
,
ide_expiry_t
*
expiry
)
{
unsigned
long
flags
;
ide_hwgroup_t
*
hwgroup
=
HWGROUP
(
drive
);
spin_lock_irqsave
(
&
ide_lock
,
flags
);
if
(
hwgroup
->
handler
!=
NULL
)
{
printk
(
"%s: ide_set_handler: handler not null; old=%p, new=%p
\n
"
,
drive
->
name
,
hwgroup
->
handler
,
handler
);
}
hwgroup
->
handler
=
handler
;
hwgroup
->
expiry
=
expiry
;
hwgroup
->
timer
.
expires
=
jiffies
+
timeout
;
add_timer
(
&
hwgroup
->
timer
);
spin_unlock_irqrestore
(
&
ide_lock
,
flags
);
}
EXPORT_SYMBOL
(
ide_end_request
);
/*
* current_capacity() returns the capacity (in sectors) of a drive
...
...
@@ -441,232 +428,21 @@ unsigned long current_capacity (ide_drive_t *drive)
return
0
;
}
extern
struct
block_device_operations
ide_fops
[];
static
ide_startstop_t
do_reset1
(
ide_drive_t
*
,
int
);
/* needed below */
/*
* atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
* during an atapi drive reset operation. If the drive has not yet responded,
* and we have not yet hit our maximum waiting time, then the timer is restarted
* for another 50ms.
*/
static
ide_startstop_t
atapi_reset_pollfunc
(
ide_drive_t
*
drive
)
{
ide_hwgroup_t
*
hwgroup
=
HWGROUP
(
drive
);
byte
stat
;
SELECT_DRIVE
(
HWIF
(
drive
),
drive
);
udelay
(
10
);
if
(
OK_STAT
(
stat
=
GET_STAT
(),
0
,
BUSY_STAT
))
{
printk
(
"%s: ATAPI reset complete
\n
"
,
drive
->
name
);
}
else
{
if
(
time_before
(
jiffies
,
hwgroup
->
poll_timeout
))
{
if
(
HWGROUP
(
drive
)
->
handler
!=
NULL
)
/* paranoia check */
BUG
();
ide_set_handler
(
drive
,
&
atapi_reset_pollfunc
,
HZ
/
20
,
NULL
);
return
ide_started
;
/* continue polling */
}
hwgroup
->
poll_timeout
=
0
;
/* end of polling */
printk
(
"%s: ATAPI reset timed-out, status=0x%02x
\n
"
,
drive
->
name
,
stat
);
return
do_reset1
(
drive
,
1
);
/* do it the old fashioned way */
}
hwgroup
->
poll_timeout
=
0
;
/* done polling */
return
ide_stopped
;
}
/*
* reset_pollfunc() gets invoked to poll the interface for completion every 50ms
* during an ide reset operation. If the drives have not yet responded,
* and we have not yet hit our maximum waiting time, then the timer is restarted
* for another 50ms.
*/
static
ide_startstop_t
reset_pollfunc
(
ide_drive_t
*
drive
)
{
ide_hwgroup_t
*
hwgroup
=
HWGROUP
(
drive
);
ide_hwif_t
*
hwif
=
HWIF
(
drive
);
byte
tmp
;
if
(
!
OK_STAT
(
tmp
=
GET_STAT
(),
0
,
BUSY_STAT
))
{
if
(
time_before
(
jiffies
,
hwgroup
->
poll_timeout
))
{
if
(
HWGROUP
(
drive
)
->
handler
!=
NULL
)
/* paranoia check */
BUG
();
ide_set_handler
(
drive
,
&
reset_pollfunc
,
HZ
/
20
,
NULL
);
return
ide_started
;
/* continue polling */
}
printk
(
"%s: reset timed-out, status=0x%02x
\n
"
,
hwif
->
name
,
tmp
);
drive
->
failures
++
;
}
else
{
printk
(
"%s: reset: "
,
hwif
->
name
);
if
((
tmp
=
GET_ERR
())
==
1
)
{
printk
(
"success
\n
"
);
drive
->
failures
=
0
;
}
else
{
drive
->
failures
++
;
#if FANCY_STATUS_DUMPS
printk
(
"master: "
);
switch
(
tmp
&
0x7f
)
{
case
1
:
printk
(
"passed"
);
break
;
case
2
:
printk
(
"formatter device error"
);
break
;
case
3
:
printk
(
"sector buffer error"
);
break
;
case
4
:
printk
(
"ECC circuitry error"
);
break
;
case
5
:
printk
(
"controlling MPU error"
);
break
;
default:
printk
(
"error (0x%02x?)"
,
tmp
);
}
if
(
tmp
&
0x80
)
printk
(
"; slave: failed"
);
printk
(
"
\n
"
);
#else
printk
(
"failed
\n
"
);
#endif
/* FANCY_STATUS_DUMPS */
}
}
hwgroup
->
poll_timeout
=
0
;
/* done polling */
return
ide_stopped
;
}
static
void
check_dma_crc
(
ide_drive_t
*
drive
)
{
if
(
drive
->
crc_count
)
{
(
void
)
HWIF
(
drive
)
->
dmaproc
(
ide_dma_off_quietly
,
drive
);
if
((
HWIF
(
drive
)
->
speedproc
)
!=
NULL
)
HWIF
(
drive
)
->
speedproc
(
drive
,
ide_auto_reduce_xfer
(
drive
));
if
(
drive
->
current_speed
>=
XFER_SW_DMA_0
)
(
void
)
HWIF
(
drive
)
->
dmaproc
(
ide_dma_on
,
drive
);
}
else
{
(
void
)
HWIF
(
drive
)
->
dmaproc
(
ide_dma_off
,
drive
);
}
}
static
void
pre_reset
(
ide_drive_t
*
drive
)
{
if
(
drive
->
driver
!=
NULL
)
DRIVER
(
drive
)
->
pre_reset
(
drive
);
if
(
!
drive
->
keep_settings
)
{
if
(
drive
->
using_dma
)
{
check_dma_crc
(
drive
);
}
else
{
drive
->
unmask
=
0
;
drive
->
io_32bit
=
0
;
}
return
;
}
if
(
drive
->
using_dma
)
check_dma_crc
(
drive
);
}
/*
* do_reset1() attempts to recover a confused drive by resetting it.
* Unfortunately, resetting a disk drive actually resets all devices on
* the same interface, so it can really be thought of as resetting the
* interface rather than resetting the drive.
*
* ATAPI devices have their own reset mechanism which allows them to be
* individually reset without clobbering other devices on the same interface.
*
* Unfortunately, the IDE interface does not generate an interrupt to let
* us know when the reset operation has finished, so we must poll for this.
* Equally poor, though, is the fact that this may a very long time to complete,
* (up to 30 seconds worstcase). So, instead of busy-waiting here for it,
* we set a timer to poll at 50ms intervals.
*/
static
ide_startstop_t
do_reset1
(
ide_drive_t
*
drive
,
int
do_not_try_atapi
)
{
unsigned
int
unit
;
unsigned
long
flags
;
ide_hwif_t
*
hwif
=
HWIF
(
drive
);
ide_hwgroup_t
*
hwgroup
=
HWGROUP
(
drive
);
local_irq_save
(
flags
);
/* For an ATAPI device, first try an ATAPI SRST. */
if
(
drive
->
media
!=
ide_disk
&&
!
do_not_try_atapi
)
{
pre_reset
(
drive
);
SELECT_DRIVE
(
hwif
,
drive
);
udelay
(
20
);
OUT_BYTE
(
WIN_SRST
,
IDE_COMMAND_REG
);
hwgroup
->
poll_timeout
=
jiffies
+
WAIT_WORSTCASE
;
if
(
HWGROUP
(
drive
)
->
handler
!=
NULL
)
/* paranoia check */
BUG
();
ide_set_handler
(
drive
,
&
atapi_reset_pollfunc
,
HZ
/
20
,
NULL
);
local_irq_restore
(
flags
);
return
ide_started
;
}
/*
* First, reset any device state data we were maintaining
* for any of the drives on this interface.
*/
for
(
unit
=
0
;
unit
<
MAX_DRIVES
;
++
unit
)
pre_reset
(
&
hwif
->
drives
[
unit
]);
#if OK_TO_RESET_CONTROLLER
if
(
!
IDE_CONTROL_REG
)
{
local_irq_restore
(
flags
);
return
ide_stopped
;
}
/*
* Note that we also set nIEN while resetting the device,
* to mask unwanted interrupts from the interface during the reset.
* However, due to the design of PC hardware, this will cause an
* immediate interrupt due to the edge transition it produces.
* This single interrupt gives us a "fast poll" for drives that
* recover from reset very quickly, saving us the first 50ms wait time.
*/
OUT_BYTE
(
drive
->
ctl
|
6
,
IDE_CONTROL_REG
);
/* set SRST and nIEN */
udelay
(
10
);
/* more than enough time */
if
(
drive
->
quirk_list
==
2
)
{
OUT_BYTE
(
drive
->
ctl
,
IDE_CONTROL_REG
);
/* clear SRST and nIEN */
}
else
{
OUT_BYTE
(
drive
->
ctl
|
2
,
IDE_CONTROL_REG
);
/* clear SRST, leave nIEN */
}
udelay
(
10
);
/* more than enough time */
hwgroup
->
poll_timeout
=
jiffies
+
WAIT_WORSTCASE
;
if
(
HWGROUP
(
drive
)
->
handler
!=
NULL
)
/* paranoia check */
BUG
();
ide_set_handler
(
drive
,
&
reset_pollfunc
,
HZ
/
20
,
NULL
);
/*
* Some weird controller like resetting themselves to a strange
* state when the disks are reset this way. At least, the Winbond
* 553 documentation says that
*/
if
(
hwif
->
resetproc
!=
NULL
)
hwif
->
resetproc
(
drive
);
#endif
/* OK_TO_RESET_CONTROLLER */
local_irq_restore
(
flags
);
return
ide_started
;
}
/*
* ide_do_reset() is the entry point to the drive/interface reset code.
*/
ide_startstop_t
ide_do_reset
(
ide_drive_t
*
drive
)
{
return
do_reset1
(
drive
,
0
);
}
EXPORT_SYMBOL
(
current_capacity
);
static
inline
u32
read_24
(
ide_drive_t
*
drive
)
{
return
(
IN_BYTE
(
IDE_HCYL_REG
)
<<
16
)
|
(
IN_BYTE
(
IDE_LCYL_REG
)
<<
8
)
|
IN_BYTE
(
IDE_SECTOR_REG
);
return
(
HWIF
(
drive
)
->
INB
(
IDE_HCYL_REG
)
<<
16
)
|
(
HWIF
(
drive
)
->
INB
(
IDE_LCYL_REG
)
<<
8
)
|
HWIF
(
drive
)
->
INB
(
IDE_SECTOR_REG
);
}
/*
* Clean up after success/failure of an explicit drive cmd
*/
void
ide_end_drive_cmd
(
ide_drive_t
*
drive
,
byte
stat
,
byte
err
)
void
ide_end_drive_cmd
(
ide_drive_t
*
drive
,
u8
stat
,
u8
err
)
{
ide_hwif_t
*
hwif
=
HWIF
(
drive
);
unsigned
long
flags
;
struct
request
*
rq
;
...
...
@@ -675,28 +451,28 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
spin_unlock_irqrestore
(
&
ide_lock
,
flags
);
if
(
rq
->
flags
&
REQ_DRIVE_CMD
)
{
byte
*
args
=
(
byte
*
)
rq
->
buffer
;
u8
*
args
=
(
u8
*
)
rq
->
buffer
;
if
(
rq
->
errors
==
0
)
rq
->
errors
=
!
OK_STAT
(
stat
,
READY_STAT
,
BAD_STAT
);
if
(
args
)
{
args
[
0
]
=
stat
;
args
[
1
]
=
err
;
args
[
2
]
=
IN_BYTE
(
IDE_NSECTOR_REG
);
args
[
2
]
=
hwif
->
INB
(
IDE_NSECTOR_REG
);
}
}
else
if
(
rq
->
flags
&
REQ_DRIVE_TASK
)
{
byte
*
args
=
(
byte
*
)
rq
->
buffer
;
u8
*
args
=
(
u8
*
)
rq
->
buffer
;
if
(
rq
->
errors
==
0
)
rq
->
errors
=
!
OK_STAT
(
stat
,
READY_STAT
,
BAD_STAT
);
if
(
args
)
{
args
[
0
]
=
stat
;
args
[
1
]
=
err
;
args
[
2
]
=
IN_BYTE
(
IDE_NSECTOR_REG
);
args
[
3
]
=
IN_BYTE
(
IDE_SECTOR_REG
);
args
[
4
]
=
IN_BYTE
(
IDE_LCYL_REG
);
args
[
5
]
=
IN_BYTE
(
IDE_HCYL_REG
);
args
[
6
]
=
IN_BYTE
(
IDE_SELECT_REG
);
args
[
2
]
=
hwif
->
INB
(
IDE_NSECTOR_REG
);
args
[
3
]
=
hwif
->
INB
(
IDE_SECTOR_REG
);
args
[
4
]
=
hwif
->
INB
(
IDE_LCYL_REG
);
args
[
5
]
=
hwif
->
INB
(
IDE_HCYL_REG
);
args
[
6
]
=
hwif
->
INB
(
IDE_SELECT_REG
);
}
}
else
if
(
rq
->
flags
&
REQ_DRIVE_TASKFILE
)
{
ide_task_t
*
args
=
(
ide_task_t
*
)
rq
->
special
;
...
...
@@ -705,27 +481,25 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
if
(
args
)
{
if
(
args
->
tf_in_flags
.
b
.
data
)
{
u
nsigned
short
data
=
IN_WORD
(
IDE_DATA_REG
);
u
16
data
=
hwif
->
INW
(
IDE_DATA_REG
);
args
->
tfRegister
[
IDE_DATA_OFFSET
]
=
(
data
)
&
0xFF
;
args
->
hobRegister
[
IDE_DATA_OFFSET_HOB
]
=
(
data
>>
8
)
&
0xFF
;
}
args
->
tfRegister
[
IDE_ERROR_OFFSET
]
=
err
;
args
->
tfRegister
[
IDE_NSECTOR_OFFSET
]
=
IN_BYTE
(
IDE_NSECTOR_REG
);
args
->
tfRegister
[
IDE_SECTOR_OFFSET
]
=
IN_BYTE
(
IDE_SECTOR_REG
);
args
->
tfRegister
[
IDE_LCYL_OFFSET
]
=
IN_BYTE
(
IDE_LCYL_REG
);
args
->
tfRegister
[
IDE_HCYL_OFFSET
]
=
IN_BYTE
(
IDE_HCYL_REG
);
args
->
tfRegister
[
IDE_SELECT_OFFSET
]
=
IN_BYTE
(
IDE_SELECT_REG
);
args
->
tfRegister
[
IDE_NSECTOR_OFFSET
]
=
hwif
->
INB
(
IDE_NSECTOR_REG
);
args
->
tfRegister
[
IDE_SECTOR_OFFSET
]
=
hwif
->
INB
(
IDE_SECTOR_REG
);
args
->
tfRegister
[
IDE_LCYL_OFFSET
]
=
hwif
->
INB
(
IDE_LCYL_REG
);
args
->
tfRegister
[
IDE_HCYL_OFFSET
]
=
hwif
->
INB
(
IDE_HCYL_REG
);
args
->
tfRegister
[
IDE_SELECT_OFFSET
]
=
hwif
->
INB
(
IDE_SELECT_REG
);
args
->
tfRegister
[
IDE_STATUS_OFFSET
]
=
stat
;
if
((
drive
->
id
->
command_set_2
&
0x0400
)
&&
(
drive
->
id
->
cfs_enable_2
&
0x0400
)
&&
(
drive
->
addressing
==
1
))
{
OUT_BYTE
(
drive
->
ctl
|
0x80
,
IDE_CONTROL_REG_HOB
);
args
->
hobRegister
[
IDE_FEATURE_OFFSET_HOB
]
=
IN_BYTE
(
IDE_FEATURE_REG
);
args
->
hobRegister
[
IDE_NSECTOR_OFFSET_HOB
]
=
IN_BYTE
(
IDE_NSECTOR_REG
);
args
->
hobRegister
[
IDE_SECTOR_OFFSET_HOB
]
=
IN_BYTE
(
IDE_SECTOR_REG
);
args
->
hobRegister
[
IDE_LCYL_OFFSET_HOB
]
=
IN_BYTE
(
IDE_LCYL_REG
);
args
->
hobRegister
[
IDE_HCYL_OFFSET_HOB
]
=
IN_BYTE
(
IDE_HCYL_REG
);
if
(
drive
->
addressing
==
1
)
{
hwif
->
OUTB
(
drive
->
ctl
|
0x80
,
IDE_CONTROL_REG_HOB
);
args
->
hobRegister
[
IDE_FEATURE_OFFSET_HOB
]
=
hwif
->
INB
(
IDE_FEATURE_REG
);
args
->
hobRegister
[
IDE_NSECTOR_OFFSET_HOB
]
=
hwif
->
INB
(
IDE_NSECTOR_REG
);
args
->
hobRegister
[
IDE_SECTOR_OFFSET_HOB
]
=
hwif
->
INB
(
IDE_SECTOR_REG
);
args
->
hobRegister
[
IDE_LCYL_OFFSET_HOB
]
=
hwif
->
INB
(
IDE_LCYL_REG
);
args
->
hobRegister
[
IDE_HCYL_OFFSET_HOB
]
=
hwif
->
INB
(
IDE_HCYL_REG
);
}
}
}
...
...
@@ -737,21 +511,24 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
spin_unlock_irqrestore
(
&
ide_lock
,
flags
);
}
EXPORT_SYMBOL
(
ide_end_drive_cmd
);
/*
* Error reporting, in human readable form (luxurious, but a memory hog).
*/
byte
ide_dump_status
(
ide_drive_t
*
drive
,
const
char
*
msg
,
byte
stat
)
u8
ide_dump_status
(
ide_drive_t
*
drive
,
const
char
*
msg
,
u8
stat
)
{
ide_hwif_t
*
hwif
=
HWIF
(
drive
);
unsigned
long
flags
;
byte
err
=
0
;
u8
err
=
0
;
local_irq_set
(
flags
);
printk
(
"%s: %s: status=0x%02x"
,
drive
->
name
,
msg
,
stat
);
#if FANCY_STATUS_DUMPS
printk
(
" { "
);
if
(
stat
&
BUSY_STAT
)
if
(
stat
&
BUSY_STAT
)
{
printk
(
"Busy "
);
else
{
}
else
{
if
(
stat
&
READY_STAT
)
printk
(
"DriveReady "
);
if
(
stat
&
WRERR_STAT
)
printk
(
"DeviceFault "
);
if
(
stat
&
SEEK_STAT
)
printk
(
"SeekComplete "
);
...
...
@@ -764,13 +541,13 @@ byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat)
#endif
/* FANCY_STATUS_DUMPS */
printk
(
"
\n
"
);
if
((
stat
&
(
BUSY_STAT
|
ERR_STAT
))
==
ERR_STAT
)
{
err
=
GET_ERR
(
);
err
=
hwif
->
INB
(
IDE_ERROR_REG
);
printk
(
"%s: %s: error=0x%02x"
,
drive
->
name
,
msg
,
err
);
#if FANCY_STATUS_DUMPS
if
(
drive
->
media
==
ide_disk
)
{
printk
(
" { "
);
if
(
err
&
ABRT_ERR
)
printk
(
"DriveStatusError "
);
if
(
err
&
ICRC_ERR
)
printk
(
"
%s"
,
(
err
&
ABRT_ERR
)
?
"BadCRC "
:
"BadSector
"
);
if
(
err
&
ICRC_ERR
)
printk
(
"
Bad%s "
,
(
err
&
ABRT_ERR
)
?
"CRC"
:
"Sector
"
);
if
(
err
&
ECC_ERR
)
printk
(
"UncorrectableError "
);
if
(
err
&
ID_ERR
)
printk
(
"SectorIdNotFound "
);
if
(
err
&
TRK0_ERR
)
printk
(
"TrackZeroNotFound "
);
...
...
@@ -780,30 +557,30 @@ byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat)
if
((
drive
->
id
->
command_set_2
&
0x0400
)
&&
(
drive
->
id
->
cfs_enable_2
&
0x0400
)
&&
(
drive
->
addressing
==
1
))
{
__
u64
sectors
=
0
;
u32
low
=
0
,
high
=
0
;
low
=
read_24
(
drive
);
OUT_BYTE
(
drive
->
ctl
|
0x80
,
IDE_CONTROL_REG
);
u64
sectors
=
0
;
u32
high
=
0
;
u32
low
=
read_24
(
drive
);
hwif
->
OUTB
(
drive
->
ctl
|
0x80
,
IDE_CONTROL_REG
);
high
=
read_24
(
drive
);
sectors
=
((
__
u64
)
high
<<
24
)
|
low
;
sectors
=
((
u64
)
high
<<
24
)
|
low
;
printk
(
", LBAsect=%llu, high=%d, low=%d"
,
(
u
nsigned
long
long
)
sectors
,
(
u
64
)
sectors
,
high
,
low
);
}
else
{
byte
cur
=
IN_BYTE
(
IDE_SELECT_REG
);
u8
cur
=
hwif
->
INB
(
IDE_SELECT_REG
);
if
(
cur
&
0x40
)
{
/* using LBA? */
printk
(
", LBAsect=%ld"
,
(
unsigned
long
)
((
cur
&
0xf
)
<<
24
)
|
(
IN_BYTE
(
IDE_HCYL_REG
)
<<
16
)
|
(
IN_BYTE
(
IDE_LCYL_REG
)
<<
8
)
|
IN_BYTE
(
IDE_SECTOR_REG
));
|
(
hwif
->
INB
(
IDE_HCYL_REG
)
<<
16
)
|
(
hwif
->
INB
(
IDE_LCYL_REG
)
<<
8
)
|
hwif
->
INB
(
IDE_SECTOR_REG
));
}
else
{
printk
(
", CHS=%d/%d/%d"
,
(
IN_BYTE
(
IDE_HCYL_REG
)
<<
8
)
+
IN_BYTE
(
IDE_LCYL_REG
),
(
hwif
->
INB
(
IDE_HCYL_REG
)
<<
8
)
+
hwif
->
INB
(
IDE_LCYL_REG
),
cur
&
0xf
,
IN_BYTE
(
IDE_SECTOR_REG
));
hwif
->
INB
(
IDE_SECTOR_REG
));
}
}
if
(
HWGROUP
(
drive
)
&&
HWGROUP
(
drive
)
->
rq
)
...
...
@@ -817,6 +594,8 @@ byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat)
return
err
;
}
EXPORT_SYMBOL
(
ide_dump_status
);
/*
* try_to_flush_leftover_data() is invoked in response to a drive
* unexpectedly having its DRQ_STAT bit set. As an alternative to
...
...
@@ -824,7 +603,7 @@ byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat)
* by read a sector's worth of data from the drive. Of course,
* this may not help if the drive is *waiting* for data from *us*.
*/
static
void
try_to_flush_leftover_data
(
ide_drive_t
*
drive
)
void
try_to_flush_leftover_data
(
ide_drive_t
*
drive
)
{
int
i
=
(
drive
->
mult_count
?
drive
->
mult_count
:
1
)
*
SECTOR_WORDS
;
...
...
@@ -832,12 +611,15 @@ static void try_to_flush_leftover_data (ide_drive_t *drive)
return
;
while
(
i
>
0
)
{
u32
buffer
[
16
];
unsigned
int
wcount
=
(
i
>
16
)
?
16
:
i
;
u32
wcount
=
(
i
>
16
)
?
16
:
i
;
i
-=
wcount
;
ata_input_data
(
drive
,
buffer
,
wcount
);
HWIF
(
drive
)
->
ata_input_data
(
drive
,
buffer
,
wcount
);
}
}
EXPORT_SYMBOL
(
try_to_flush_leftover_data
);
/*
* FIXME Add an ATAPI error
*/
...
...
@@ -845,56 +627,70 @@ static void try_to_flush_leftover_data (ide_drive_t *drive)
/*
* ide_error() takes action based on the error returned by the drive.
*/
ide_startstop_t
ide_error
(
ide_drive_t
*
drive
,
const
char
*
msg
,
byte
stat
)
ide_startstop_t
ide_error
(
ide_drive_t
*
drive
,
const
char
*
msg
,
u8
stat
)
{
ide_hwif_t
*
hwif
;
struct
request
*
rq
;
byte
err
;
u8
err
;
err
=
ide_dump_status
(
drive
,
msg
,
stat
);
if
(
drive
==
NULL
||
(
rq
=
HWGROUP
(
drive
)
->
rq
)
==
NULL
)
return
ide_stopped
;
hwif
=
HWIF
(
drive
);
/* retry only "normal" I/O: */
if
(
rq
->
flags
&
(
REQ_DRIVE_CMD
|
REQ_DRIVE_TASK
))
{
rq
->
errors
=
1
;
ide_end_drive_cmd
(
drive
,
stat
,
err
);
return
ide_stopped
;
}
else
if
(
rq
->
flags
&
REQ_DRIVE_TASKFILE
)
{
}
if
(
rq
->
flags
&
REQ_DRIVE_TASKFILE
)
{
rq
->
errors
=
1
;
ide_end_drive_cmd
(
drive
,
stat
,
err
);
// ide_end_taskfile(drive, stat, err);
return
ide_stopped
;
}
if
(
stat
&
BUSY_STAT
||
((
stat
&
WRERR_STAT
)
&&
!
drive
->
nowerr
))
{
/* other bits are useless when BUSY */
if
(
stat
&
BUSY_STAT
||
((
stat
&
WRERR_STAT
)
&&
!
drive
->
nowerr
))
{
/* other bits are useless when BUSY */
rq
->
errors
|=
ERROR_RESET
;
}
else
{
if
(
drive
->
media
!=
ide_disk
)
goto
media_out
;
/* ide_disk */
if
(
drive
->
media
==
ide_disk
&&
(
stat
&
ERR_STAT
))
{
if
(
stat
&
ERR_STAT
)
{
/* err has different meaning on cdrom and tape */
if
(
err
==
ABRT_ERR
)
{
if
(
drive
->
select
.
b
.
lba
&&
IN_BYTE
(
IDE_COMMAND_REG
)
==
WIN_SPECIFY
)
return
ide_stopped
;
/* some newer drives don't support WIN_SPECIFY */
}
else
if
((
err
&
(
ABRT_ERR
|
ICRC_ERR
))
==
(
ABRT_ERR
|
ICRC_ERR
))
{
drive
->
crc_count
++
;
/* UDMA crc error -- just retry the operation */
}
else
if
(
err
&
(
BBD_ERR
|
ECC_ERR
))
/* retries won't help these */
if
(
drive
->
select
.
b
.
lba
&&
(
hwif
->
INB
(
IDE_COMMAND_REG
)
==
WIN_SPECIFY
))
/* some newer drives don't
* support WIN_SPECIFY
*/
return
ide_stopped
;
}
else
if
((
err
&
BAD_CRC
)
==
BAD_CRC
)
{
drive
->
crc_count
++
;
/* UDMA crc error -- just retry the operation */
}
else
if
(
err
&
(
BBD_ERR
|
ECC_ERR
))
{
/* retries won't help these */
rq
->
errors
=
ERROR_MAX
;
else
if
(
err
&
TRK0_ERR
)
/* help it find track zero */
}
else
if
(
err
&
TRK0_ERR
)
{
/* help it find track zero */
rq
->
errors
|=
ERROR_RECAL
;
}
}
/* !ide_disk */
if
((
stat
&
DRQ_STAT
)
&&
rq_data_dir
(
rq
)
==
READ
)
media_out:
if
((
stat
&
DRQ_STAT
)
&&
rq_data_dir
(
rq
)
!=
WRITE
)
try_to_flush_leftover_data
(
drive
);
/* !ide_disk */
}
if
(
GET_STAT
()
&
(
BUSY_STAT
|
DRQ_STAT
))
OUT_BYTE
(
WIN_IDLEIMMEDIATE
,
IDE_COMMAND_REG
);
/* force an abort */
if
(
hwif
->
INB
(
IDE_STATUS_REG
)
&
(
BUSY_STAT
|
DRQ_STAT
))
{
/* force an abort */
hwif
->
OUTB
(
WIN_IDLEIMMEDIATE
,
IDE_COMMAND_REG
);
}
if
(
rq
->
errors
>=
ERROR_MAX
)
{
if
(
drive
->
driver
!=
NULL
)
DRIVER
(
drive
)
->
end_request
(
drive
,
0
);
DRIVER
(
drive
)
->
end_request
(
drive
,
0
,
0
);
else
ide_end_request
(
drive
,
0
);
ide_end_request
(
drive
,
0
,
0
);
}
else
{
if
((
rq
->
errors
&
ERROR_RESET
)
==
ERROR_RESET
)
{
++
rq
->
errors
;
...
...
@@ -907,53 +703,62 @@ ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat)
return
ide_stopped
;
}
EXPORT_SYMBOL
(
ide_error
);
/*
* Issue a simple drive command
* The drive must be selected beforehand.
*/
void
ide_cmd
(
ide_drive_t
*
drive
,
byte
cmd
,
byte
nsect
,
ide_handler_t
*
handler
)
void
ide_cmd
(
ide_drive_t
*
drive
,
u8
cmd
,
u8
nsect
,
ide_handler_t
*
handler
)
{
if
(
HWGROUP
(
drive
)
->
handler
!=
NULL
)
/* paranoia check */
ide_hwif_t
*
hwif
=
HWIF
(
drive
);
if
(
HWGROUP
(
drive
)
->
handler
!=
NULL
)
BUG
();
ide_set_handler
(
drive
,
handler
,
WAIT_CMD
,
NULL
);
ide_set_handler
(
drive
,
handler
,
WAIT_CMD
,
NULL
);
if
(
IDE_CONTROL_REG
)
OUT_BYTE
(
drive
->
ctl
,
IDE_CONTROL_REG
);
/* clear nIEN */
SELECT_MASK
(
HWIF
(
drive
),
drive
,
0
);
OUT_BYTE
(
nsect
,
IDE_NSECTOR_REG
);
OUT_BYTE
(
cmd
,
IDE_COMMAND_REG
);
hwif
->
OUTB
(
drive
->
ctl
,
IDE_CONTROL_REG
);
/* clear nIEN */
SELECT_MASK
(
drive
,
0
);
hwif
->
OUTB
(
nsect
,
IDE_NSECTOR_REG
);
hwif
->
OUTB
(
cmd
,
IDE_COMMAND_REG
);
}
EXPORT_SYMBOL
(
ide_cmd
);
/*
* drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
*/
static
ide_startstop_t
drive_cmd_intr
(
ide_drive_t
*
drive
)
ide_startstop_t
drive_cmd_intr
(
ide_drive_t
*
drive
)
{
struct
request
*
rq
=
HWGROUP
(
drive
)
->
rq
;
byte
*
args
=
(
byte
*
)
rq
->
buffer
;
byte
stat
=
GET_STAT
();
ide_hwif_t
*
hwif
=
HWIF
(
drive
);
u8
*
args
=
(
u8
*
)
rq
->
buffer
;
u8
stat
=
hwif
->
INB
(
IDE_STATUS_REG
);
int
retries
=
10
;
local_irq_enable
();
if
((
stat
&
DRQ_STAT
)
&&
args
&&
args
[
3
])
{
byte
io_32bit
=
drive
->
io_32bit
;
u8
io_32bit
=
drive
->
io_32bit
;
drive
->
io_32bit
=
0
;
ata_input_data
(
drive
,
&
args
[
4
],
args
[
3
]
*
SECTOR_WORDS
);
hwif
->
ata_input_data
(
drive
,
&
args
[
4
],
args
[
3
]
*
SECTOR_WORDS
);
drive
->
io_32bit
=
io_32bit
;
while
(((
stat
=
GET_STAT
(
))
&
BUSY_STAT
)
&&
retries
--
)
while
(((
stat
=
hwif
->
INB
(
IDE_STATUS_REG
))
&
BUSY_STAT
)
&&
retries
--
)
udelay
(
100
);
}
if
(
!
OK_STAT
(
stat
,
READY_STAT
,
BAD_STAT
))
return
DRIVER
(
drive
)
->
error
(
drive
,
"drive_cmd"
,
stat
);
/* calls ide_end_drive_cmd */
ide_end_drive_cmd
(
drive
,
stat
,
GET_ERR
());
return
DRIVER
(
drive
)
->
error
(
drive
,
"drive_cmd"
,
stat
);
/* calls ide_end_drive_cmd */
ide_end_drive_cmd
(
drive
,
stat
,
hwif
->
INB
(
IDE_ERROR_REG
));
return
ide_stopped
;
}
EXPORT_SYMBOL
(
drive_cmd_intr
);
/*
* do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT
* commands to a drive. It used to do much more, but has been scaled back.
*/
static
ide_startstop_t
do_special
(
ide_drive_t
*
drive
)
ide_startstop_t
do_special
(
ide_drive_t
*
drive
)
{
special_t
*
s
=
&
drive
->
special
;
...
...
@@ -973,12 +778,15 @@ static ide_startstop_t do_special (ide_drive_t *drive)
return
ide_stopped
;
}
EXPORT_SYMBOL
(
do_special
);
/*
* execute_drive_cmd() issues a special drive command,
* usually initiated by ioctl() from the external hdparm program.
*/
static
ide_startstop_t
execute_drive_cmd
(
ide_drive_t
*
drive
,
struct
request
*
rq
)
ide_startstop_t
execute_drive_cmd
(
ide_drive_t
*
drive
,
struct
request
*
rq
)
{
ide_hwif_t
*
hwif
=
HWIF
(
drive
);
if
(
rq
->
flags
&
REQ_DRIVE_TASKFILE
)
{
ide_task_t
*
args
=
rq
->
special
;
...
...
@@ -989,8 +797,8 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq
return
flagged_taskfile
(
drive
,
args
);
return
do_rw_taskfile
(
drive
,
args
);
}
else
if
(
rq
->
flags
&
REQ_DRIVE_TASK
)
{
byte
*
args
=
rq
->
buffer
;
byte
sel
;
u8
*
args
=
rq
->
buffer
;
u8
sel
;
if
(
!
args
)
goto
done
;
...
...
@@ -1004,18 +812,18 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq
printk
(
"hcyl=0x%02x "
,
args
[
5
]);
printk
(
"sel=0x%02x
\n
"
,
args
[
6
]);
#endif
OUT_BYTE
(
args
[
1
],
IDE_FEATURE_REG
);
OUT_BYTE
(
args
[
3
],
IDE_SECTOR_REG
);
OUT_BYTE
(
args
[
4
],
IDE_LCYL_REG
);
OUT_BYTE
(
args
[
5
],
IDE_HCYL_REG
);
hwif
->
OUTB
(
args
[
1
],
IDE_FEATURE_REG
);
hwif
->
OUTB
(
args
[
3
],
IDE_SECTOR_REG
);
hwif
->
OUTB
(
args
[
4
],
IDE_LCYL_REG
);
hwif
->
OUTB
(
args
[
5
],
IDE_HCYL_REG
);
sel
=
(
args
[
6
]
&
~
0x10
);
if
(
drive
->
select
.
b
.
unit
)
sel
|=
0x10
;
OUT_BYTE
(
sel
,
IDE_SELECT_REG
);
hwif
->
OUTB
(
sel
,
IDE_SELECT_REG
);
ide_cmd
(
drive
,
args
[
0
],
args
[
2
],
&
drive_cmd_intr
);
return
ide_started
;
}
else
if
(
rq
->
flags
&
REQ_DRIVE_CMD
)
{
byte
*
args
=
rq
->
buffer
;
u8
*
args
=
rq
->
buffer
;
if
(
!
args
)
goto
done
;
...
...
@@ -1027,14 +835,14 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq
printk
(
"xx=0x%02x
\n
"
,
args
[
3
]);
#endif
if
(
args
[
0
]
==
WIN_SMART
)
{
OUT_BYTE
(
0x4f
,
IDE_LCYL_REG
);
OUT_BYTE
(
0xc2
,
IDE_HCYL_REG
);
OUT_BYTE
(
args
[
2
],
IDE_FEATURE_REG
);
OUT_BYTE
(
args
[
1
],
IDE_SECTOR_REG
);
hwif
->
OUTB
(
0x4f
,
IDE_LCYL_REG
);
hwif
->
OUTB
(
0xc2
,
IDE_HCYL_REG
);
hwif
->
OUTB
(
args
[
2
],
IDE_FEATURE_REG
);
hwif
->
OUTB
(
args
[
1
],
IDE_SECTOR_REG
);
ide_cmd
(
drive
,
args
[
0
],
args
[
3
],
&
drive_cmd_intr
);
return
ide_started
;
}
OUT_BYTE
(
args
[
2
],
IDE_FEATURE_REG
);
hwif
->
OUTB
(
args
[
2
],
IDE_FEATURE_REG
);
ide_cmd
(
drive
,
args
[
0
],
args
[
1
],
&
drive_cmd_intr
);
return
ide_started
;
}
...
...
@@ -1047,16 +855,20 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq
#ifdef DEBUG
printk
(
"%s: DRIVE_CMD (null)
\n
"
,
drive
->
name
);
#endif
ide_end_drive_cmd
(
drive
,
GET_STAT
(),
GET_ERR
());
ide_end_drive_cmd
(
drive
,
hwif
->
INB
(
IDE_STATUS_REG
),
hwif
->
INB
(
IDE_ERROR_REG
));
return
ide_stopped
;
}
EXPORT_SYMBOL
(
execute_drive_cmd
);
/*
* start_request() initiates handling of a new I/O request
* needed to reverse the perverted changes anonymously made back
* 2.3.99-pre6
*/
static
ide_startstop_t
start_request
(
ide_drive_t
*
drive
,
struct
request
*
rq
)
ide_startstop_t
start_request
(
ide_drive_t
*
drive
,
struct
request
*
rq
)
{
ide_startstop_t
startstop
;
unsigned
long
block
;
...
...
@@ -1088,15 +900,9 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
hwif
->
name
,
kdevname
(
rq
->
rq_dev
));
goto
kill_rq
;
}
#ifdef DEBUG
if
(
rq
->
bh
&&
!
buffer_locked
(
rq
->
bh
))
{
printk
(
"%s: block not locked
\n
"
,
drive
->
name
);
goto
kill_rq
;
}
#endif
block
=
rq
->
sector
;
if
((
rq
->
flags
&
REQ_CMD
)
&&
block
=
rq
->
sector
;
if
(
blk_fs_request
(
rq
)
&&
(
drive
->
media
==
ide_disk
||
drive
->
media
==
ide_floppy
))
{
block
+=
drive
->
sect0
;
}
...
...
@@ -1109,7 +915,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
while
((
read_timer
()
-
hwif
->
last_time
)
<
DISK_RECOVERY_TIME
);
#endif
SELECT_DRIVE
(
hwif
,
drive
);
SELECT_DRIVE
(
drive
);
if
(
ide_wait_stat
(
&
startstop
,
drive
,
drive
->
ready_stat
,
BUSY_STAT
|
DRQ_STAT
,
WAIT_READY
))
{
printk
(
"%s: drive not ready for command
\n
"
,
drive
->
name
);
return
startstop
;
...
...
@@ -1129,18 +935,22 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
return
do_special
(
drive
);
kill_rq:
if
(
drive
->
driver
!=
NULL
)
DRIVER
(
drive
)
->
end_request
(
drive
,
0
);
DRIVER
(
drive
)
->
end_request
(
drive
,
0
,
0
);
else
ide_end_request
(
drive
,
0
);
ide_end_request
(
drive
,
0
,
0
);
return
ide_stopped
;
}
EXPORT_SYMBOL
(
start_request
);
int
restart_request
(
ide_drive_t
*
drive
,
struct
request
*
rq
)
{
(
void
)
start_request
(
drive
,
rq
);
return
0
;
}
EXPORT_SYMBOL
(
restart_request
);
/*
* ide_stall_queue() can be used by a drive to give excess bandwidth back
* to the hwgroup by sleeping for timeout jiffies.
...
...
@@ -1152,6 +962,8 @@ void ide_stall_queue (ide_drive_t *drive, unsigned long timeout)
drive
->
sleep
=
timeout
+
jiffies
;
}
EXPORT_SYMBOL
(
ide_stall_queue
);
#define WAKEUP(drive) ((drive)->service_start + 2 * (drive)->service_time)
/*
...
...
@@ -1242,10 +1054,11 @@ void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
struct
request
*
rq
;
ide_startstop_t
startstop
;
ide_get_lock
(
&
ide_intr_lock
,
ide_intr
,
hwgroup
);
/* for atari only: POSSIBLY BROKEN HERE(?) */
/* for atari only: POSSIBLY BROKEN HERE(?) */
ide_get_lock
(
&
ide_intr_lock
,
ide_intr
,
hwgroup
);
/* necessary paranoia: ensure IRQs are masked on local CPU */
local_irq_disable
();
/* necessary paranoia: ensure IRQs are masked on local CPU */
while
(
!
hwgroup
->
busy
)
{
hwgroup
->
busy
=
1
;
...
...
@@ -1271,20 +1084,30 @@ void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
if
(
timer_pending
(
&
hwgroup
->
timer
))
printk
(
"ide_set_handler: timer already active
\n
"
);
#endif
hwgroup
->
sleeping
=
1
;
/* so that ide_timer_expiry knows what to do */
/* so that ide_timer_expiry knows what to do */
hwgroup
->
sleeping
=
1
;
mod_timer
(
&
hwgroup
->
timer
,
sleep
);
/* we purposely leave hwgroup->busy==1 while sleeping */
/* we purposely leave hwgroup->busy==1
* while sleeping */
}
else
{
/* Ugly, but how can we sleep for the lock otherwise? perhaps from tq_disk? */
ide_release_lock
(
&
ide_lock
);
/* for atari only */
/* Ugly, but how can we sleep for the lock
* otherwise? perhaps from tq_disk?
*/
/* for atari only */
ide_release_lock
(
&
ide_lock
);
hwgroup
->
busy
=
0
;
}
return
;
/* no more work for this hwgroup (for now) */
/* no more work for this hwgroup (for now) */
return
;
}
hwif
=
HWIF
(
drive
);
if
(
hwgroup
->
hwif
->
sharing_irq
&&
hwif
!=
hwgroup
->
hwif
&&
hwif
->
io_ports
[
IDE_CONTROL_OFFSET
])
{
if
(
hwgroup
->
hwif
->
sharing_irq
&&
hwif
!=
hwgroup
->
hwif
&&
hwif
->
io_ports
[
IDE_CONTROL_OFFSET
])
{
/* set nIEN for previous hwif */
SELECT_INTERRUPT
(
hwif
,
drive
);
SELECT_INTERRUPT
(
drive
);
}
hwgroup
->
hwif
=
hwif
;
hwgroup
->
drive
=
drive
;
...
...
@@ -1317,6 +1140,8 @@ void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
}
}
EXPORT_SYMBOL
(
ide_do_request
);
/*
* ide_get_queue() returns the queue which corresponds to a given device.
*/
...
...
@@ -1327,6 +1152,8 @@ request_queue_t *ide_get_queue (kdev_t dev)
return
&
hwif
->
drives
[
DEVICE_NR
(
dev
)
&
1
].
queue
;
}
EXPORT_SYMBOL
(
ide_get_queue
);
/*
* Passes the stuff to ide_do_request
*/
...
...
@@ -1335,7 +1162,6 @@ void do_ide_request(request_queue_t *q)
ide_do_request
(
q
->
queuedata
,
0
);
}
#ifndef __IDEDMA_TIMEOUT
/*
* un-busy the hwgroup etc, and clear any pending DMA status. we want to
* retry the current request in pio mode instead of risking tossing it
...
...
@@ -1349,13 +1175,13 @@ void ide_dma_timeout_retry(ide_drive_t *drive)
/*
* end current dma transaction
*/
(
void
)
hwif
->
dmaproc
(
ide_dma_end
,
drive
);
(
void
)
hwif
->
ide_dma_end
(
drive
);
/*
* complain a little, later we might remove some of this verbosity
*/
printk
(
"%s: timeout waiting for DMA
\n
"
,
drive
->
name
);
(
void
)
hwif
->
dmaproc
(
ide_dma_timeout
,
drive
);
(
void
)
hwif
->
ide_dma_timeout
(
drive
);
/*
* disable dma for now, but remember that we did so because of
...
...
@@ -1364,7 +1190,7 @@ void ide_dma_timeout_retry(ide_drive_t *drive)
*/
drive
->
retry_pio
++
;
drive
->
state
=
DMA_PIO_RETRY
;
(
void
)
hwif
->
dmaproc
(
ide_dma_off_quietly
,
drive
);
(
void
)
hwif
->
ide_dma_off_quietly
(
drive
);
/*
* un-busy drive etc (hwgroup->busy is cleared on return) and
...
...
@@ -1379,15 +1205,9 @@ void ide_dma_timeout_retry(ide_drive_t *drive)
rq
->
hard_cur_sectors
=
rq
->
current_nr_sectors
;
if
(
rq
->
bio
)
rq
->
buffer
=
NULL
;
/*
* FIXME or DELETE ME
*
* so what do we do if the device is left in an invalid state
* and will not accept commands. SOFT RESET is the only chance.
*/
}
#endif
EXPORT_SYMBOL
(
ide_dma_timeout_retry
);
/*
* ide_timer_expiry() is our timeout function for all drive operations.
...
...
@@ -1441,38 +1261,34 @@ void ide_timer_expiry (unsigned long data)
hwgroup
->
handler
=
NULL
;
/*
* We need to simulate a real interrupt when invoking
* the handler() function, which means we need to
globally
* mask the specific IRQ:
* the handler() function, which means we need to
*
globally
mask the specific IRQ:
*/
spin_unlock
(
&
ide_lock
);
hwif
=
HWIF
(
drive
);
#if DISABLE_IRQ_NOSYNC
disable_irq_nosync
(
hwif
->
irq
);
#else
disable_irq
(
hwif
->
irq
);
/* disable_irq_nosync ?? */
/* disable_irq_nosync ?? */
disable_irq
(
hwif
->
irq
);
#endif
/* DISABLE_IRQ_NOSYNC */
/* local CPU only,
* as if we were handling an interrupt */
local_irq_disable
();
/* local CPU only, as if we were handling an interrupt */
if
(
hwgroup
->
poll_timeout
!=
0
)
{
startstop
=
handler
(
drive
);
}
else
if
(
drive_is_ready
(
drive
))
{
if
(
drive
->
waiting_for_dma
)
(
void
)
hwgroup
->
hwif
->
dmaproc
(
ide_dma_lostirq
,
drive
);
(
void
)
hwgroup
->
hwif
->
ide_dma_lostirq
(
drive
);
(
void
)
ide_ack_intr
(
hwif
);
printk
(
"%s: lost interrupt
\n
"
,
drive
->
name
);
startstop
=
handler
(
drive
);
}
else
{
if
(
drive
->
waiting_for_dma
)
{
#ifndef __IDEDMA_TIMEOUT
startstop
=
ide_stopped
;
ide_dma_timeout_retry
(
drive
);
#else
/* __IDEDMA_TIMEOUT */
(
void
)
hwgroup
->
hwif
->
dmaproc
(
ide_dma_end
,
drive
);
printk
(
"%s: timeout waiting for DMA
\n
"
,
drive
->
name
);
(
void
)
hwgroup
->
hwif
->
dmaproc
(
ide_dma_timeout
,
drive
);
#endif
/* __IDEDMA_TIMEOUT */
}
else
startstop
=
DRIVER
(
drive
)
->
error
(
drive
,
"irq timeout"
,
GET_STAT
(
));
startstop
=
DRIVER
(
drive
)
->
error
(
drive
,
"irq timeout"
,
hwif
->
INB
(
IDE_STATUS_REG
));
}
set_recovery_timer
(
hwif
);
drive
->
service_time
=
jiffies
-
drive
->
service_start
;
...
...
@@ -1486,6 +1302,8 @@ void ide_timer_expiry (unsigned long data)
spin_unlock_irqrestore
(
&
ide_lock
,
flags
);
}
EXPORT_SYMBOL
(
ide_timer_expiry
);
/*
* There's nothing really useful we can do with an unexpected interrupt,
* other than reading the status register (to clear it), and logging it.
...
...
@@ -1511,7 +1329,7 @@ void ide_timer_expiry (unsigned long data)
*/
static
void
unexpected_intr
(
int
irq
,
ide_hwgroup_t
*
hwgroup
)
{
byte
stat
;
u8
stat
;
ide_hwif_t
*
hwif
=
hwgroup
->
hwif
;
/*
...
...
@@ -1519,15 +1337,17 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
*/
do
{
if
(
hwif
->
irq
==
irq
)
{
stat
=
IN_BYTE
(
hwif
->
io_ports
[
IDE_STATUS_OFFSET
]);
stat
=
hwif
->
INB
(
hwif
->
io_ports
[
IDE_STATUS_OFFSET
]);
if
(
!
OK_STAT
(
stat
,
READY_STAT
,
BAD_STAT
))
{
/* Try to not flood the console with msgs */
static
unsigned
long
last_msgtime
,
count
;
++
count
;
if
(
time_after
(
jiffies
,
last_msgtime
+
HZ
))
{
last_msgtime
=
jiffies
;
printk
(
"%s%s: unexpected interrupt, status=0x%02x, count=%ld
\n
"
,
hwif
->
name
,
(
hwif
->
next
==
hwgroup
->
hwif
)
?
""
:
"(?)"
,
stat
,
count
);
printk
(
"%s%s: unexpected interrupt, "
"status=0x%02x, count=%ld
\n
"
,
hwif
->
name
,
(
hwif
->
next
==
hwgroup
->
hwif
)
?
""
:
"(?)"
,
stat
,
count
);
}
}
}
...
...
@@ -1554,7 +1374,9 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
return
;
}
if
((
handler
=
hwgroup
->
handler
)
==
NULL
||
hwgroup
->
poll_timeout
!=
0
)
{
if
((
handler
=
hwgroup
->
handler
)
==
NULL
||
hwgroup
->
poll_timeout
!=
0
)
{
printk
(
"ide_intr: unexpected interrupt!
\n
"
);
/*
* Not expecting an interrupt from this drive.
* That means this could be:
...
...
@@ -1568,7 +1390,7 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
* so in that case we just ignore it and hope it goes away.
*/
#ifdef CONFIG_BLK_DEV_IDEPCI
if
(
IDE_PCI_DEVID_EQ
(
hwif
->
pci_devid
,
IDE_PCI_DEVID_NULL
)
)
if
(
hwif
->
pci_dev
&&
!
hwif
->
pci_dev
->
vendor
)
#endif
/* CONFIG_BLK_DEV_IDEPCI */
{
/*
...
...
@@ -1582,7 +1404,7 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
* Whack the status register, just in case
* we have a leftover pending IRQ.
*/
(
void
)
IN_BYTE
(
hwif
->
io_ports
[
IDE_STATUS_OFFSET
]);
(
void
)
hwif
->
INB
(
hwif
->
io_ports
[
IDE_STATUS_OFFSET
]);
#endif
/* CONFIG_BLK_DEV_IDEPCI */
}
spin_unlock_irqrestore
(
&
ide_lock
,
flags
);
...
...
@@ -1618,7 +1440,8 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
if
(
drive
->
unmask
)
local_irq_enable
();
startstop
=
handler
(
drive
);
/* service this interrupt, may set handler for next interrupt */
/* service this interrupt, may set handler for next interrupt */
startstop
=
handler
(
drive
);
spin_lock_irq
(
&
ide_lock
);
/*
...
...
@@ -1635,12 +1458,15 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
hwgroup
->
busy
=
0
;
ide_do_request
(
hwgroup
,
hwif
->
irq
);
}
else
{
printk
(
"%s: ide_intr: huh? expected NULL handler on exit
\n
"
,
drive
->
name
);
printk
(
"%s: ide_intr: huh? expected NULL handler "
"on exit
\n
"
,
drive
->
name
);
}
}
spin_unlock_irqrestore
(
&
ide_lock
,
flags
);
}
EXPORT_SYMBOL
(
ide_intr
);
/*
* get_info_ptr() returns the (ide_drive_t *) for a given device number.
* It returns NULL if the given device number does not match any present drives.
...
...
@@ -1648,9 +1474,6 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
ide_drive_t
*
get_info_ptr
(
kdev_t
i_rdev
)
{
int
major
=
major
(
i_rdev
);
#if 0
int minor = minor(i_rdev) & PARTN_MASK;
#endif
unsigned
int
h
;
for
(
h
=
0
;
h
<
MAX_HWIFS
;
++
h
)
{
...
...
@@ -1659,11 +1482,7 @@ ide_drive_t *get_info_ptr (kdev_t i_rdev)
unsigned
unit
=
DEVICE_NR
(
i_rdev
);
if
(
unit
<
MAX_DRIVES
)
{
ide_drive_t
*
drive
=
&
hwif
->
drives
[
unit
];
#if 0
if (drive->present && get_capacity(drive->disk))
#else
if
(
drive
->
present
)
#endif
return
drive
;
}
break
;
...
...
@@ -1672,6 +1491,8 @@ ide_drive_t *get_info_ptr (kdev_t i_rdev)
return
NULL
;
}
EXPORT_SYMBOL
(
get_info_ptr
);
/*
* This function is intended to be used prior to invoking ide_do_drive_cmd().
*/
...
...
@@ -1681,6 +1502,8 @@ void ide_init_drive_cmd (struct request *rq)
rq
->
flags
=
REQ_DRIVE_CMD
;
}
EXPORT_SYMBOL
(
ide_init_drive_cmd
);
/*
* This function issues a special IDE device request
* onto the request queue.
...
...
@@ -1738,18 +1561,24 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
ide_do_request
(
hwgroup
,
0
);
spin_unlock_irqrestore
(
&
ide_lock
,
flags
);
if
(
action
==
ide_wait
)
{
wait_for_completion
(
&
wait
);
/* wait for it to be serviced */
return
rq
->
errors
?
-
EIO
:
0
;
/* return -EIO if errors */
/* wait for it to be serviced */
wait_for_completion
(
&
wait
);
/* return -EIO if errors */
return
rq
->
errors
?
-
EIO
:
0
;
}
return
0
;
}
EXPORT_SYMBOL
(
ide_do_drive_cmd
);
void
ide_revalidate_drive
(
ide_drive_t
*
drive
)
{
set_capacity
(
drive
->
disk
,
current_capacity
(
drive
));
}
EXPORT_SYMBOL
(
ide_revalidate_drive
);
/*
* This routine is called to flush all partitions and partition tables
* for a changed disk, and then re-read the new partition table.
...
...
@@ -1758,7 +1587,7 @@ void ide_revalidate_drive (ide_drive_t *drive)
* usage == 1 (we need an open channel to use an ioctl :-), so this
* is our limit.
*/
static
int
ide_revalidate_disk
(
kdev_t
i_rdev
)
int
ide_revalidate_disk
(
kdev_t
i_rdev
)
{
ide_drive_t
*
drive
;
if
((
drive
=
get_info_ptr
(
i_rdev
))
==
NULL
)
...
...
@@ -1768,7 +1597,9 @@ static int ide_revalidate_disk (kdev_t i_rdev)
return
0
;
}
static
void
ide_probe_module
(
void
)
EXPORT_SYMBOL
(
ide_revalidate_disk
);
void
ide_probe_module
(
void
)
{
if
(
!
ide_probe
)
{
#if defined(CONFIG_KMOD) && defined(CONFIG_BLK_DEV_IDE_MODULE)
...
...
@@ -1779,32 +1610,30 @@ static void ide_probe_module (void)
}
}
EXPORT_SYMBOL
(
ide_probe_module
);
static
int
ide_open
(
struct
inode
*
inode
,
struct
file
*
filp
)
{
ide_drive_t
*
drive
;
if
((
drive
=
get_info_ptr
(
inode
->
i_rdev
))
==
NULL
)
return
-
ENXIO
;
#ifdef CONFIG_KMOD
if
(
drive
->
driver
==
NULL
)
{
if
(
drive
->
media
==
ide_disk
)
(
void
)
request_module
(
"ide-disk"
);
if
(
drive
->
scsi
)
(
void
)
request_module
(
"ide-scsi"
);
if
(
drive
->
media
==
ide_cdrom
)
(
void
)
request_module
(
"ide-cd"
);
if
(
drive
->
media
==
ide_tape
)
(
void
)
request_module
(
"ide-tape"
);
if
(
drive
->
media
==
ide_floppy
)
(
void
)
request_module
(
"ide-floppy"
);
#if defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI)
if
(
drive
->
media
==
ide_scsi
)
(
void
)
request_module
(
"ide-scsi"
);
#endif
/* defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) */
}
#endif
/* CONFIG_KMOD */
drive
->
usage
++
;
if
(
drive
->
driver
!=
NULL
)
return
DRIVER
(
drive
)
->
open
(
inode
,
filp
,
drive
);
printk
(
"%s: driver not present
\n
"
,
drive
->
name
);
printk
(
KERN_WARNING
"%s: driver not present
\n
"
,
drive
->
name
);
drive
->
usage
--
;
return
-
ENXIO
;
}
...
...
@@ -1864,33 +1693,6 @@ struct seq_operations ide_drivers_op = {
show:
show_driver
};
/*
* Locking is badly broken here - since way back. That sucker is
* root-only, but that's not an excuse... The real question is what
* exclusion rules do we want here.
*/
int
ide_replace_subdriver
(
ide_drive_t
*
drive
,
const
char
*
driver
)
{
if
(
!
drive
->
present
||
drive
->
usage
)
goto
abort
;
if
(
drive
->
driver
!=
NULL
&&
DRIVER
(
drive
)
->
cleanup
(
drive
))
goto
abort
;
strncpy
(
drive
->
driver_req
,
driver
,
9
);
if
(
ata_attach
(
drive
))
{
spin_lock
(
&
drives_lock
);
list_del_init
(
&
drive
->
list
);
spin_unlock
(
&
drives_lock
);
drive
->
driver_req
[
0
]
=
0
;
ata_attach
(
drive
);
}
else
{
drive
->
driver_req
[
0
]
=
0
;
}
if
(
DRIVER
(
drive
)
&&
!
strcmp
(
DRIVER
(
drive
)
->
name
,
driver
))
return
0
;
abort:
return
1
;
}
#ifdef CONFIG_PROC_FS
ide_proc_entry_t
generic_subdriver_entries
[]
=
{
{
"capacity"
,
S_IFREG
|
S_IRUGO
,
proc_ide_read_capacity
,
NULL
},
...
...
@@ -1898,6 +1700,10 @@ ide_proc_entry_t generic_subdriver_entries[] = {
};
#endif
#define hwif_release_region(addr, num) \
((hwif->mmio) ? release_mem_region((addr),(num)) : release_region((addr),(num)))
/*
* Note that we only release the standard ports,
* and do not even try to handle any extra ports
...
...
@@ -1905,35 +1711,32 @@ ide_proc_entry_t generic_subdriver_entries[] = {
*/
void
hwif_unregister
(
ide_hwif_t
*
hwif
)
{
if
(
hwif
->
straight8
)
{
ide_release_region
(
hwif
->
io_ports
[
IDE_DATA_OFFSET
],
8
);
goto
jump_eight
;
}
if
(
hwif
->
io_ports
[
IDE_DATA_OFFSET
])
ide_release_region
(
hwif
->
io_ports
[
IDE_DATA_OFFSET
],
1
);
if
(
hwif
->
io_ports
[
IDE_ERROR_OFFSET
])
ide_release_region
(
hwif
->
io_ports
[
IDE_ERROR_OFFSET
],
1
);
if
(
hwif
->
io_ports
[
IDE_NSECTOR_OFFSET
])
ide_release_region
(
hwif
->
io_ports
[
IDE_NSECTOR_OFFSET
],
1
);
if
(
hwif
->
io_ports
[
IDE_SECTOR_OFFSET
])
ide_release_region
(
hwif
->
io_ports
[
IDE_SECTOR_OFFSET
],
1
);
if
(
hwif
->
io_ports
[
IDE_LCYL_OFFSET
])
ide_release_region
(
hwif
->
io_ports
[
IDE_LCYL_OFFSET
],
1
);
if
(
hwif
->
io_ports
[
IDE_HCYL_OFFSET
])
ide_release_region
(
hwif
->
io_ports
[
IDE_HCYL_OFFSET
],
1
);
if
(
hwif
->
io_ports
[
IDE_SELECT_OFFSET
])
ide_release_region
(
hwif
->
io_ports
[
IDE_SELECT_OFFSET
],
1
);
if
(
hwif
->
io_ports
[
IDE_STATUS_OFFSET
])
ide_release_region
(
hwif
->
io_ports
[
IDE_STATUS_OFFSET
],
1
);
jump_eight:
u32
i
=
0
;
if
(
hwif
->
mmio
==
2
)
return
;
if
(
hwif
->
io_ports
[
IDE_CONTROL_OFFSET
])
ide
_release_region
(
hwif
->
io_ports
[
IDE_CONTROL_OFFSET
],
1
);
hwif
_release_region
(
hwif
->
io_ports
[
IDE_CONTROL_OFFSET
],
1
);
#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
if
(
hwif
->
io_ports
[
IDE_IRQ_OFFSET
])
ide
_release_region
(
hwif
->
io_ports
[
IDE_IRQ_OFFSET
],
1
);
hwif
_release_region
(
hwif
->
io_ports
[
IDE_IRQ_OFFSET
],
1
);
#endif
/* (CONFIG_AMIGA) || (CONFIG_MAC) */
if
(
hwif
->
straight8
)
{
hwif_release_region
(
hwif
->
io_ports
[
IDE_DATA_OFFSET
],
8
);
return
;
}
for
(
i
=
IDE_DATA_OFFSET
;
i
<=
IDE_STATUS_OFFSET
;
i
++
)
{
if
(
hwif
->
io_ports
[
i
])
{
hwif_release_region
(
hwif
->
io_ports
[
i
],
1
);
}
}
}
EXPORT_SYMBOL
(
hwif_unregister
);
extern
void
init_hwif_data
(
unsigned
int
index
);
void
ide_unregister
(
unsigned
int
index
)
{
struct
gendisk
*
gd
;
...
...
@@ -1994,7 +1797,7 @@ void ide_unregister (unsigned int index)
g
=
g
->
next
;
}
while
(
g
!=
hwgroup
->
hwif
);
if
(
irq_count
==
1
)
ide_
free_irq
(
hwif
->
irq
,
hwgroup
);
free_irq
(
hwif
->
irq
,
hwgroup
);
/*
* Note that we only release the standard ports,
...
...
@@ -2011,7 +1814,7 @@ void ide_unregister (unsigned int index)
for
(
i
=
0
;
i
<
MAX_DRIVES
;
++
i
)
{
drive
=
&
hwif
->
drives
[
i
];
if
(
drive
->
de
)
{
devfs_unregister
(
drive
->
de
);
devfs_unregister
(
drive
->
de
);
drive
->
de
=
NULL
;
}
if
(
!
drive
->
present
)
...
...
@@ -2041,7 +1844,14 @@ void ide_unregister (unsigned int index)
#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
if
(
hwif
->
dma_base
)
{
(
void
)
ide_release_dma
(
hwif
);
hwif
->
dma_base
=
0
;
hwif
->
dma_master
=
0
;
hwif
->
dma_command
=
0
;
hwif
->
dma_vendor1
=
0
;
hwif
->
dma_status
=
0
;
hwif
->
dma_vendor3
=
0
;
hwif
->
dma_prdtable
=
0
;
}
#endif
/* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
...
...
@@ -2059,43 +1869,134 @@ void ide_unregister (unsigned int index)
hwif
->
drives
[
i
].
disk
=
NULL
;
kfree
(
gd
);
}
old_hwif
=
*
hwif
;
init_hwif_data
(
index
);
/* restore hwif data to pristine status */
hwif
->
hwgroup
=
old_hwif
.
hwgroup
;
hwif
->
tuneproc
=
old_hwif
.
tuneproc
;
hwif
->
speedproc
=
old_hwif
.
speedproc
;
hwif
->
selectproc
=
old_hwif
.
selectproc
;
hwif
->
resetproc
=
old_hwif
.
resetproc
;
hwif
->
intrproc
=
old_hwif
.
intrproc
;
hwif
->
maskproc
=
old_hwif
.
maskproc
;
hwif
->
quirkproc
=
old_hwif
.
quirkproc
;
hwif
->
rwproc
=
old_hwif
.
rwproc
;
hwif
->
ideproc
=
old_hwif
.
ideproc
;
hwif
->
dmaproc
=
old_hwif
.
dmaproc
;
hwif
->
busproc
=
old_hwif
.
busproc
;
hwif
->
bus_state
=
old_hwif
.
bus_state
;
hwif
->
dma_base
=
old_hwif
.
dma_base
;
hwif
->
dma_extra
=
old_hwif
.
dma_extra
;
hwif
->
config_data
=
old_hwif
.
config_data
;
hwif
->
select_data
=
old_hwif
.
select_data
;
hwif
->
proc
=
old_hwif
.
proc
;
#ifndef CONFIG_BLK_DEV_IDECS
hwif
->
irq
=
old_hwif
.
irq
;
#endif
/* CONFIG_BLK_DEV_IDECS */
hwif
->
major
=
old_hwif
.
major
;
hwif
->
chipset
=
old_hwif
.
chipset
;
hwif
->
autodma
=
old_hwif
.
autodma
;
hwif
->
udma_four
=
old_hwif
.
udma_four
;
old_hwif
=
*
hwif
;
init_hwif_data
(
index
);
/* restore hwif data to pristine status */
hwif
->
hwgroup
=
old_hwif
.
hwgroup
;
hwif
->
proc
=
old_hwif
.
proc
;
hwif
->
major
=
old_hwif
.
major
;
// hwif->index = old_hwif.index;
// hwif->channel = old_hwif.channel;
hwif
->
straight8
=
old_hwif
.
straight8
;
hwif
->
bus_state
=
old_hwif
.
bus_state
;
hwif
->
atapi_dma
=
old_hwif
.
atapi_dma
;
hwif
->
ultra_mask
=
old_hwif
.
ultra_mask
;
hwif
->
mwdma_mask
=
old_hwif
.
mwdma_mask
;
hwif
->
swdma_mask
=
old_hwif
.
swdma_mask
;
hwif
->
chipset
=
old_hwif
.
chipset
;
#ifdef CONFIG_BLK_DEV_IDEPCI
hwif
->
pci_dev
=
old_hwif
.
pci_dev
;
hwif
->
pci_devid
=
old_hwif
.
pci_devid
;
hwif
->
pci_dev
=
old_hwif
.
pci_dev
;
hwif
->
cds
=
old_hwif
.
cds
;
#endif
/* CONFIG_BLK_DEV_IDEPCI */
hwif
->
straight8
=
old_hwif
.
straight8
;
hwif
->
hwif_data
=
old_hwif
.
hwif_data
;
#if 0
hwif->hwifops = old_hwif.hwifops;
#else
hwif
->
identify
=
old_hwif
.
identify
;
hwif
->
tuneproc
=
old_hwif
.
tuneproc
;
hwif
->
speedproc
=
old_hwif
.
speedproc
;
hwif
->
selectproc
=
old_hwif
.
selectproc
;
hwif
->
reset_poll
=
old_hwif
.
reset_poll
;
hwif
->
pre_reset
=
old_hwif
.
pre_reset
;
hwif
->
resetproc
=
old_hwif
.
resetproc
;
hwif
->
intrproc
=
old_hwif
.
intrproc
;
hwif
->
maskproc
=
old_hwif
.
maskproc
;
hwif
->
quirkproc
=
old_hwif
.
quirkproc
;
hwif
->
busproc
=
old_hwif
.
busproc
;
#endif
#if 0
hwif->pioops = old_hwif.pioops;
#else
hwif
->
ata_input_data
=
old_hwif
.
ata_input_data
;
hwif
->
ata_output_data
=
old_hwif
.
ata_output_data
;
hwif
->
atapi_input_bytes
=
old_hwif
.
atapi_input_bytes
;
hwif
->
atapi_output_bytes
=
old_hwif
.
atapi_output_bytes
;
#endif
#if 0
hwif->dmaops = old_hwif.dmaops;
#else
hwif
->
ide_dma_read
=
old_hwif
.
ide_dma_read
;
hwif
->
ide_dma_write
=
old_hwif
.
ide_dma_write
;
hwif
->
ide_dma_begin
=
old_hwif
.
ide_dma_begin
;
hwif
->
ide_dma_end
=
old_hwif
.
ide_dma_end
;
hwif
->
ide_dma_check
=
old_hwif
.
ide_dma_check
;
hwif
->
ide_dma_on
=
old_hwif
.
ide_dma_on
;
hwif
->
ide_dma_off
=
old_hwif
.
ide_dma_off
;
hwif
->
ide_dma_off_quietly
=
old_hwif
.
ide_dma_off_quietly
;
hwif
->
ide_dma_test_irq
=
old_hwif
.
ide_dma_test_irq
;
hwif
->
ide_dma_host_on
=
old_hwif
.
ide_dma_host_on
;
hwif
->
ide_dma_host_off
=
old_hwif
.
ide_dma_host_off
;
hwif
->
ide_dma_bad_drive
=
old_hwif
.
ide_dma_bad_drive
;
hwif
->
ide_dma_good_drive
=
old_hwif
.
ide_dma_good_drive
;
hwif
->
ide_dma_count
=
old_hwif
.
ide_dma_count
;
hwif
->
ide_dma_verbose
=
old_hwif
.
ide_dma_verbose
;
hwif
->
ide_dma_retune
=
old_hwif
.
ide_dma_retune
;
hwif
->
ide_dma_lostirq
=
old_hwif
.
ide_dma_lostirq
;
hwif
->
ide_dma_timeout
=
old_hwif
.
ide_dma_timeout
;
#endif
#if 0
hwif->iops = old_hwif.iops;
#else
hwif
->
OUTB
=
old_hwif
.
OUTB
;
hwif
->
OUTW
=
old_hwif
.
OUTW
;
hwif
->
OUTL
=
old_hwif
.
OUTL
;
hwif
->
OUTBP
=
old_hwif
.
OUTBP
;
hwif
->
OUTWP
=
old_hwif
.
OUTWP
;
hwif
->
OUTLP
=
old_hwif
.
OUTLP
;
hwif
->
OUTSW
=
old_hwif
.
OUTSW
;
hwif
->
OUTSWP
=
old_hwif
.
OUTSWP
;
hwif
->
OUTSL
=
old_hwif
.
OUTSL
;
hwif
->
OUTSLP
=
old_hwif
.
OUTSLP
;
hwif
->
INB
=
old_hwif
.
INB
;
hwif
->
INW
=
old_hwif
.
INW
;
hwif
->
INL
=
old_hwif
.
INL
;
hwif
->
INBP
=
old_hwif
.
INBP
;
hwif
->
INWP
=
old_hwif
.
INWP
;
hwif
->
INLP
=
old_hwif
.
INLP
;
hwif
->
INSW
=
old_hwif
.
INSW
;
hwif
->
INSWP
=
old_hwif
.
INSWP
;
hwif
->
INSL
=
old_hwif
.
INSL
;
hwif
->
INSLP
=
old_hwif
.
INSLP
;
#endif
hwif
->
mmio
=
old_hwif
.
mmio
;
hwif
->
rqsize
=
old_hwif
.
rqsize
;
hwif
->
addressing
=
old_hwif
.
addressing
;
#ifndef CONFIG_BLK_DEV_IDECS
hwif
->
irq
=
old_hwif
.
irq
;
#endif
/* CONFIG_BLK_DEV_IDECS */
hwif
->
initializing
=
old_hwif
.
initializing
;
hwif
->
dma_base
=
old_hwif
.
dma_base
;
hwif
->
dma_master
=
old_hwif
.
dma_master
;
hwif
->
dma_command
=
old_hwif
.
dma_command
;
hwif
->
dma_vendor1
=
old_hwif
.
dma_vendor1
;
hwif
->
dma_status
=
old_hwif
.
dma_status
;
hwif
->
dma_vendor3
=
old_hwif
.
dma_vendor3
;
hwif
->
dma_prdtable
=
old_hwif
.
dma_prdtable
;
hwif
->
dma_extra
=
old_hwif
.
dma_extra
;
hwif
->
config_data
=
old_hwif
.
config_data
;
hwif
->
select_data
=
old_hwif
.
select_data
;
hwif
->
autodma
=
old_hwif
.
autodma
;
hwif
->
udma_four
=
old_hwif
.
udma_four
;
hwif
->
no_dsc
=
old_hwif
.
no_dsc
;
hwif
->
hwif_data
=
old_hwif
.
hwif_data
;
abort:
spin_unlock_irqrestore
(
&
ide_lock
,
flags
);
}
EXPORT_SYMBOL
(
ide_unregister
);
/*
* Setup hw_regs_t structure described by parameters. You
* may set up the hw structure yourself OR use this routine to
...
...
@@ -2104,7 +2005,11 @@ void ide_unregister (unsigned int index)
void
ide_setup_ports
(
hw_regs_t
*
hw
,
ide_ioreg_t
base
,
int
*
offsets
,
ide_ioreg_t
ctrl
,
ide_ioreg_t
intr
,
ide_ack_intr_t
*
ack_intr
,
int
irq
)
ide_ack_intr_t
*
ack_intr
,
/*
* ide_io_ops_t *iops,
*/
int
irq
)
{
int
i
;
...
...
@@ -2130,8 +2035,13 @@ void ide_setup_ports ( hw_regs_t *hw,
hw
->
irq
=
irq
;
hw
->
dma
=
NO_DMA
;
hw
->
ack_intr
=
ack_intr
;
/*
* hw->iops = iops;
*/
}
EXPORT_SYMBOL
(
ide_setup_ports
);
/*
* Register an IDE interface, specifing exactly the registers etc
* Set init=1 iff calling before probes have taken place.
...
...
@@ -2181,6 +2091,8 @@ int ide_register_hw (hw_regs_t *hw, ide_hwif_t **hwifp)
return
(
initializing
||
hwif
->
present
)
?
index
:
-
1
;
}
EXPORT_SYMBOL
(
ide_register_hw
);
/*
* Compatability function with existing drivers. If you want
* something different, use the function above.
...
...
@@ -2193,6 +2105,8 @@ int ide_register (int arg1, int arg2, int irq)
return
ide_register_hw
(
&
hw
,
NULL
);
}
EXPORT_SYMBOL
(
ide_register
);
void
ide_add_setting
(
ide_drive_t
*
drive
,
const
char
*
name
,
int
rw
,
int
read_ioctl
,
int
write_ioctl
,
int
data_type
,
int
min
,
int
max
,
int
mul_factor
,
int
div_factor
,
void
*
data
,
ide_procset_t
*
set
)
{
ide_settings_t
**
p
=
(
ide_settings_t
**
)
&
drive
->
settings
,
*
setting
=
NULL
;
...
...
@@ -2204,12 +2118,18 @@ void ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioc
memset
(
setting
,
0
,
sizeof
(
*
setting
));
if
((
setting
->
name
=
kmalloc
(
strlen
(
name
)
+
1
,
GFP_KERNEL
))
==
NULL
)
goto
abort
;
strcpy
(
setting
->
name
,
name
);
setting
->
rw
=
rw
;
setting
->
read_ioctl
=
read_ioctl
;
setting
->
write_ioctl
=
write_ioctl
;
setting
->
data_type
=
data_type
;
setting
->
min
=
min
;
setting
->
max
=
max
;
setting
->
mul_factor
=
mul_factor
;
setting
->
div_factor
=
div_factor
;
setting
->
data
=
data
;
setting
->
set
=
set
;
setting
->
next
=
*
p
;
strcpy
(
setting
->
name
,
name
);
setting
->
rw
=
rw
;
setting
->
read_ioctl
=
read_ioctl
;
setting
->
write_ioctl
=
write_ioctl
;
setting
->
data_type
=
data_type
;
setting
->
min
=
min
;
setting
->
max
=
max
;
setting
->
mul_factor
=
mul_factor
;
setting
->
div_factor
=
div_factor
;
setting
->
data
=
data
;
setting
->
set
=
set
;
setting
->
next
=
*
p
;
if
(
drive
->
driver
)
setting
->
auto_remove
=
1
;
*
p
=
setting
;
...
...
@@ -2219,6 +2139,8 @@ void ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioc
kfree
(
setting
);
}
EXPORT_SYMBOL
(
ide_add_setting
);
void
ide_remove_setting
(
ide_drive_t
*
drive
,
char
*
name
)
{
ide_settings_t
**
p
=
(
ide_settings_t
**
)
&
drive
->
settings
,
*
setting
;
...
...
@@ -2232,6 +2154,8 @@ void ide_remove_setting (ide_drive_t *drive, char *name)
kfree
(
setting
);
}
EXPORT_SYMBOL
(
ide_remove_setting
);
static
ide_settings_t
*
ide_find_setting_by_ioctl
(
ide_drive_t
*
drive
,
int
cmd
)
{
ide_settings_t
*
setting
=
drive
->
settings
;
...
...
@@ -2316,6 +2240,8 @@ int ide_spin_wait_hwgroup (ide_drive_t *drive)
return
0
;
}
EXPORT_SYMBOL
(
ide_spin_wait_hwgroup
);
/*
* FIXME: This should be changed to enqueue a special request
* to the driver to change settings, and then wait on a sema for completion.
...
...
@@ -2356,6 +2282,8 @@ int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val)
return
0
;
}
EXPORT_SYMBOL
(
ide_write_setting
);
static
int
set_io_32bit
(
ide_drive_t
*
drive
,
int
arg
)
{
drive
->
io_32bit
=
arg
;
...
...
@@ -2370,10 +2298,15 @@ static int set_using_dma (ide_drive_t *drive, int arg)
{
if
(
!
drive
->
driver
||
!
DRIVER
(
drive
)
->
supports_dma
)
return
-
EPERM
;
if
(
!
drive
->
id
||
!
(
drive
->
id
->
capability
&
1
)
||
!
HWIF
(
drive
)
->
dmaproc
)
if
(
!
drive
->
id
||
!
(
drive
->
id
->
capability
&
1
))
return
-
EPERM
;
if
(
HWIF
(
drive
)
->
dmaproc
(
arg
?
ide_dma_on
:
ide_dma_off
,
drive
))
return
-
EIO
;
if
(
HWIF
(
drive
)
->
ide_dma_check
==
NULL
)
return
-
EPERM
;
if
(
arg
)
{
if
(
HWIF
(
drive
)
->
ide_dma_on
(
drive
))
return
-
EIO
;
}
else
{
if
(
HWIF
(
drive
)
->
ide_dma_off
(
drive
))
return
-
EIO
;
}
return
0
;
}
...
...
@@ -2386,9 +2319,46 @@ static int set_pio_mode (ide_drive_t *drive, int arg)
if
(
drive
->
special
.
b
.
set_tune
)
return
-
EBUSY
;
ide_init_drive_cmd
(
&
rq
);
drive
->
tune_req
=
(
byte
)
arg
;
drive
->
tune_req
=
(
u8
)
arg
;
drive
->
special
.
b
.
set_tune
=
1
;
(
void
)
ide_do_drive_cmd
(
drive
,
&
rq
,
ide_wait
);
(
void
)
ide_do_drive_cmd
(
drive
,
&
rq
,
ide_wait
);
return
0
;
}
static
int
set_xfer_rate
(
ide_drive_t
*
drive
,
int
arg
)
{
int
err
=
ide_wait_cmd
(
drive
,
WIN_SETFEATURES
,
(
u8
)
arg
,
SETFEATURES_XFER
,
0
,
NULL
);
if
(
!
err
&&
arg
)
{
if
((
HWIF
(
drive
)
->
speedproc
)
!=
NULL
)
HWIF
(
drive
)
->
speedproc
(
drive
,
(
u8
)
arg
);
ide_driveid_update
(
drive
);
}
return
err
;
}
int
ide_atapi_to_scsi
(
ide_drive_t
*
drive
,
int
arg
)
{
if
(
drive
->
media
==
ide_disk
)
{
drive
->
scsi
=
0
;
return
0
;
}
if
(
drive
->
driver
!=
NULL
)
{
#if 0
ide_unregister_subdriver(drive);
#else
if
(
DRIVER
(
drive
)
->
cleanup
(
drive
))
{
drive
->
scsi
=
0
;
return
0
;
}
#endif
}
drive
->
scsi
=
(
u8
)
arg
;
ata_attach
(
drive
);
return
0
;
}
...
...
@@ -2404,37 +2374,11 @@ void ide_add_generic_settings (ide_drive_t *drive)
ide_add_setting
(
drive
,
"slow"
,
SETTING_RW
,
-
1
,
-
1
,
TYPE_BYTE
,
0
,
1
,
1
,
1
,
&
drive
->
slow
,
NULL
);
ide_add_setting
(
drive
,
"unmaskirq"
,
drive
->
no_unmask
?
SETTING_READ
:
SETTING_RW
,
HDIO_GET_UNMASKINTR
,
HDIO_SET_UNMASKINTR
,
TYPE_BYTE
,
0
,
1
,
1
,
1
,
&
drive
->
unmask
,
NULL
);
ide_add_setting
(
drive
,
"using_dma"
,
SETTING_RW
,
HDIO_GET_DMA
,
HDIO_SET_DMA
,
TYPE_BYTE
,
0
,
1
,
1
,
1
,
&
drive
->
using_dma
,
set_using_dma
);
ide_add_setting
(
drive
,
"ide_scsi"
,
SETTING_RW
,
-
1
,
-
1
,
TYPE_BYTE
,
0
,
1
,
1
,
1
,
&
drive
->
scsi
,
NULL
);
ide_add_setting
(
drive
,
"init_speed"
,
SETTING_RW
,
-
1
,
-
1
,
TYPE_BYTE
,
0
,
70
,
1
,
1
,
&
drive
->
init_speed
,
NULL
);
ide_add_setting
(
drive
,
"current_speed"
,
SETTING_RW
,
-
1
,
-
1
,
TYPE_BYTE
,
0
,
70
,
1
,
1
,
&
drive
->
current_speed
,
NULL
);
ide_add_setting
(
drive
,
"current_speed"
,
SETTING_RW
,
-
1
,
-
1
,
TYPE_BYTE
,
0
,
70
,
1
,
1
,
&
drive
->
current_speed
,
set_xfer_rate
);
ide_add_setting
(
drive
,
"number"
,
SETTING_RW
,
-
1
,
-
1
,
TYPE_BYTE
,
0
,
3
,
1
,
1
,
&
drive
->
dn
,
NULL
);
}
int
ide_wait_cmd
(
ide_drive_t
*
drive
,
int
cmd
,
int
nsect
,
int
feature
,
int
sectors
,
byte
*
buf
)
{
struct
request
rq
;
byte
buffer
[
4
];
if
(
!
buf
)
buf
=
buffer
;
memset
(
buf
,
0
,
4
+
SECTOR_WORDS
*
4
*
sectors
);
ide_init_drive_cmd
(
&
rq
);
rq
.
buffer
=
buf
;
*
buf
++
=
cmd
;
*
buf
++
=
nsect
;
*
buf
++
=
feature
;
*
buf
++
=
sectors
;
return
ide_do_drive_cmd
(
drive
,
&
rq
,
ide_wait
);
}
int
ide_wait_cmd_task
(
ide_drive_t
*
drive
,
byte
*
buf
)
{
struct
request
rq
;
ide_init_drive_cmd
(
&
rq
);
rq
.
flags
=
REQ_DRIVE_TASK
;
rq
.
buffer
=
buf
;
return
ide_do_drive_cmd
(
drive
,
&
rq
,
ide_wait
);
if
(
drive
->
media
!=
ide_disk
)
ide_add_setting
(
drive
,
"ide-scsi"
,
SETTING_RW
,
-
1
,
HDIO_SET_IDE_SCSI
,
TYPE_BYTE
,
0
,
1
,
1
,
1
,
&
drive
->
scsi
,
ide_atapi_to_scsi
);
}
/*
...
...
@@ -2455,11 +2399,44 @@ void ide_delay_50ms (void)
#endif
/* CONFIG_BLK_DEV_IDECS */
}
EXPORT_SYMBOL
(
ide_delay_50ms
);
int
system_bus_clock
(
void
)
{
return
((
int
)
((
!
system_bus_speed
)
?
ide_system_bus_speed
()
:
system_bus_speed
));
}
EXPORT_SYMBOL
(
system_bus_clock
);
/*
* Locking is badly broken here - since way back. That sucker is
* root-only, but that's not an excuse... The real question is what
* exclusion rules do we want here.
*/
int
ide_replace_subdriver
(
ide_drive_t
*
drive
,
const
char
*
driver
)
{
if
(
!
drive
->
present
||
drive
->
usage
)
goto
abort
;
if
(
drive
->
driver
!=
NULL
&&
DRIVER
(
drive
)
->
cleanup
(
drive
))
goto
abort
;
strncpy
(
drive
->
driver_req
,
driver
,
9
);
if
(
ata_attach
(
drive
))
{
spin_lock
(
&
drives_lock
);
list_del_init
(
&
drive
->
list
);
spin_unlock
(
&
drives_lock
);
drive
->
driver_req
[
0
]
=
0
;
ata_attach
(
drive
);
}
else
{
drive
->
driver_req
[
0
]
=
0
;
}
if
(
DRIVER
(
drive
)
&&
!
strcmp
(
DRIVER
(
drive
)
->
name
,
driver
))
return
0
;
abort:
return
1
;
}
EXPORT_SYMBOL
(
ide_replace_subdriver
);
int
ata_attach
(
ide_drive_t
*
drive
)
{
struct
list_head
*
p
;
...
...
@@ -2469,7 +2446,7 @@ int ata_attach(ide_drive_t *drive)
if
(
!
try_inc_mod_count
(
driver
->
owner
))
continue
;
spin_unlock
(
&
drivers_lock
);
if
(
driver
->
reinit
(
drive
)
==
0
)
{
if
(
driver
->
attach
(
drive
)
==
0
)
{
if
(
driver
->
owner
)
__MOD_DEC_USE_COUNT
(
driver
->
owner
);
return
0
;
...
...
@@ -2485,6 +2462,8 @@ int ata_attach(ide_drive_t *drive)
return
1
;
}
EXPORT_SYMBOL
(
ata_attach
);
static
int
ide_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
...
...
@@ -2514,11 +2493,11 @@ static int ide_ioctl (struct inode *inode, struct file *file,
case
HDIO_GETGEO
:
{
struct
hd_geometry
*
loc
=
(
struct
hd_geometry
*
)
arg
;
u
nsigned
short
bios_cyl
=
drive
->
bios_cyl
;
/* truncate */
u
16
bios_cyl
=
drive
->
bios_cyl
;
/* truncate */
if
(
!
loc
||
(
drive
->
media
!=
ide_disk
&&
drive
->
media
!=
ide_floppy
))
return
-
EINVAL
;
if
(
put_user
(
drive
->
bios_head
,
(
byte
*
)
&
loc
->
heads
))
return
-
EFAULT
;
if
(
put_user
(
drive
->
bios_sect
,
(
byte
*
)
&
loc
->
sectors
))
return
-
EFAULT
;
if
(
put_user
(
bios_cyl
,
(
u
nsigned
short
*
)
&
loc
->
cylinders
))
return
-
EFAULT
;
if
(
put_user
(
drive
->
bios_head
,
(
u8
*
)
&
loc
->
heads
))
return
-
EFAULT
;
if
(
put_user
(
drive
->
bios_sect
,
(
u8
*
)
&
loc
->
sectors
))
return
-
EFAULT
;
if
(
put_user
(
bios_cyl
,
(
u
16
*
)
&
loc
->
cylinders
))
return
-
EFAULT
;
if
(
put_user
((
unsigned
)
get_start_sect
(
inode
->
i_bdev
),
(
unsigned
long
*
)
&
loc
->
start
))
return
-
EFAULT
;
return
0
;
...
...
@@ -2528,8 +2507,8 @@ static int ide_ioctl (struct inode *inode, struct file *file,
{
struct
hd_big_geometry
*
loc
=
(
struct
hd_big_geometry
*
)
arg
;
if
(
!
loc
||
(
drive
->
media
!=
ide_disk
&&
drive
->
media
!=
ide_floppy
))
return
-
EINVAL
;
if
(
put_user
(
drive
->
head
,
(
byte
*
)
&
loc
->
heads
))
return
-
EFAULT
;
if
(
put_user
(
drive
->
sect
,
(
byte
*
)
&
loc
->
sectors
))
return
-
EFAULT
;
if
(
put_user
(
drive
->
head
,
(
u8
*
)
&
loc
->
heads
))
return
-
EFAULT
;
if
(
put_user
(
drive
->
sect
,
(
u8
*
)
&
loc
->
sectors
))
return
-
EFAULT
;
if
(
put_user
(
drive
->
cyl
,
(
unsigned
int
*
)
&
loc
->
cylinders
))
return
-
EFAULT
;
if
(
put_user
((
unsigned
)
get_start_sect
(
inode
->
i_bdev
),
(
unsigned
long
*
)
&
loc
->
start
))
return
-
EFAULT
;
...
...
@@ -2679,33 +2658,6 @@ static int ide_check_media_change (kdev_t i_rdev)
return
0
;
}
void
ide_fixstring
(
byte
*
s
,
const
int
bytecount
,
const
int
byteswap
)
{
byte
*
p
=
s
,
*
end
=
&
s
[
bytecount
&
~
1
];
/* bytecount must be even */
if
(
byteswap
)
{
/* convert from big-endian to host byte order */
for
(
p
=
end
;
p
!=
s
;)
{
unsigned
short
*
pp
=
(
unsigned
short
*
)
(
p
-=
2
);
*
pp
=
ntohs
(
*
pp
);
}
}
/* strip leading blanks */
while
(
s
!=
end
&&
*
s
==
' '
)
++
s
;
/* compress internal blanks and strip trailing blanks */
while
(
s
!=
end
&&
*
s
)
{
if
(
*
s
++
!=
' '
||
(
s
!=
end
&&
*
s
&&
*
s
!=
' '
))
*
p
++
=
*
(
s
-
1
);
}
/* wipe out trailing garbage */
while
(
p
!=
end
)
*
p
++
=
'\0'
;
}
/*
* stridx() returns the offset of c within s,
* or -1 if c is '\0' or not found within s.
...
...
@@ -3170,14 +3122,12 @@ int __init ide_setup (char *s)
*/
static
void
__init
probe_for_hwifs
(
void
)
{
#ifdef CONFIG_PCI
#ifdef CONFIG_
BLK_DEV_IDE
PCI
if
(
pci_present
())
{
#ifdef CONFIG_BLK_DEV_IDEPCI
ide_scan_pcibus
(
ide_scan_direction
);
#endif
/* CONFIG_BLK_DEV_IDEPCI */
}
#endif
/* CONFIG_PCI */
#endif
/* CONFIG_
BLK_DEV_IDE
PCI */
#ifdef CONFIG_ETRAX_IDE
{
...
...
@@ -3267,22 +3217,13 @@ void __init ide_init_builtin_drivers (void)
probe_for_hwifs
();
#ifdef CONFIG_BLK_DEV_IDE
#if defined(__mc68000__) || defined(CONFIG_APUS)
if
(
ide_hwifs
[
0
].
io_ports
[
IDE_DATA_OFFSET
])
{
ide_get_lock
(
&
ide_intr_lock
,
NULL
,
NULL
);
/* for atari only */
disable_irq
(
ide_hwifs
[
0
].
irq
);
/* disable_irq_nosync ?? */
// disable_irq_nosync(ide_hwifs[0].irq);
}
#endif
/* __mc68000__ || CONFIG_APUS */
if
(
ide_hwifs
[
0
].
io_ports
[
IDE_DATA_OFFSET
])
ide_get_lock
(
&
ide_intr_lock
,
NULL
,
NULL
);
/* for atari only */
(
void
)
ideprobe_init
();
#if defined(__mc68000__) || defined(CONFIG_APUS)
if
(
ide_hwifs
[
0
].
io_ports
[
IDE_DATA_OFFSET
])
{
enable_irq
(
ide_hwifs
[
0
].
irq
);
ide_release_lock
(
&
ide_lock
);
/* for atari only */
}
#endif
/* __mc68000__ || CONFIG_APUS */
if
(
ide_hwifs
[
0
].
io_ports
[
IDE_DATA_OFFSET
])
ide_release_lock
(
&
ide_intr_lock
);
/* for atari only */
#endif
/* CONFIG_BLK_DEV_IDE */
#ifdef CONFIG_PROC_FS
...
...
@@ -3317,21 +3258,21 @@ static int default_flushcache (ide_drive_t *drive)
static
ide_startstop_t
default_do_request
(
ide_drive_t
*
drive
,
struct
request
*
rq
,
unsigned
long
block
)
{
ide_end_request
(
drive
,
0
);
ide_end_request
(
drive
,
0
,
0
);
return
ide_stopped
;
}
static
int
default_end_request
(
ide_drive_t
*
drive
,
int
uptodate
)
static
int
default_end_request
(
ide_drive_t
*
drive
,
int
uptodate
,
int
nr_sects
)
{
return
ide_end_request
(
drive
,
uptodate
);
return
ide_end_request
(
drive
,
uptodate
,
nr_sects
);
}
static
byte
default_sense
(
ide_drive_t
*
drive
,
const
char
*
msg
,
byte
stat
)
static
u8
default_sense
(
ide_drive_t
*
drive
,
const
char
*
msg
,
u8
stat
)
{
return
ide_dump_status
(
drive
,
msg
,
stat
);
}
static
ide_startstop_t
default_error
(
ide_drive_t
*
drive
,
const
char
*
msg
,
byte
stat
)
static
ide_startstop_t
default_error
(
ide_drive_t
*
drive
,
const
char
*
msg
,
u8
stat
)
{
return
ide_error
(
drive
,
msg
,
stat
);
}
...
...
@@ -3375,9 +3316,10 @@ static ide_startstop_t default_special (ide_drive_t *drive)
return
ide_stopped
;
}
static
int
default_
reinit
(
ide_drive_t
*
drive
)
static
int
default_
attach
(
ide_drive_t
*
drive
)
{
printk
(
KERN_ERR
"%s: does not support hotswap of device class !
\n
"
,
drive
->
name
);
printk
(
KERN_ERR
"%s: does not support hotswap of device class !
\n
"
,
drive
->
name
);
return
0
;
}
...
...
@@ -3402,7 +3344,7 @@ static void setup_driver_defaults (ide_drive_t *drive)
if
(
d
->
pre_reset
==
NULL
)
d
->
pre_reset
=
default_pre_reset
;
if
(
d
->
capacity
==
NULL
)
d
->
capacity
=
default_capacity
;
if
(
d
->
special
==
NULL
)
d
->
special
=
default_special
;
if
(
d
->
reinit
==
NULL
)
d
->
reinit
=
default_reinit
;
if
(
d
->
attach
==
NULL
)
d
->
attach
=
default_attach
;
}
int
ide_register_subdriver
(
ide_drive_t
*
drive
,
ide_driver_t
*
driver
,
int
version
)
...
...
@@ -3422,8 +3364,10 @@ int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int versio
list_add
(
&
drive
->
list
,
&
driver
->
drives
);
spin_unlock
(
&
drives_lock
);
if
(
drive
->
autotune
!=
2
)
{
if
(
!
driver
->
supports_dma
&&
HWIF
(
drive
)
->
dmaproc
!=
NULL
)
(
void
)
(
HWIF
(
drive
)
->
dmaproc
(
ide_dma_off_quietly
,
drive
));
/* DMA timings and setup moved to ide-probe.c */
if
(
!
driver
->
supports_dma
&&
HWIF
(
drive
)
->
ide_dma_off_quietly
)
// HWIF(drive)->ide_dma_off_quietly(drive);
HWIF
(
drive
)
->
ide_dma_off
(
drive
);
drive
->
dsc_overlap
=
(
drive
->
next
!=
drive
&&
driver
->
supports_dsc_overlap
);
drive
->
nice1
=
1
;
}
...
...
@@ -3435,6 +3379,8 @@ int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int versio
return
0
;
}
EXPORT_SYMBOL
(
ide_register_subdriver
);
int
ide_unregister_subdriver
(
ide_drive_t
*
drive
)
{
unsigned
long
flags
;
...
...
@@ -3460,6 +3406,8 @@ int ide_unregister_subdriver (ide_drive_t *drive)
return
0
;
}
EXPORT_SYMBOL
(
ide_unregister_subdriver
);
int
ide_register_driver
(
ide_driver_t
*
driver
)
{
struct
list_head
list
;
...
...
@@ -3481,6 +3429,8 @@ int ide_register_driver(ide_driver_t *driver)
return
0
;
}
EXPORT_SYMBOL
(
ide_register_driver
);
void
ide_unregister_driver
(
ide_driver_t
*
driver
)
{
ide_drive_t
*
drive
;
...
...
@@ -3505,6 +3455,8 @@ void ide_unregister_driver(ide_driver_t *driver)
}
}
EXPORT_SYMBOL
(
ide_unregister_driver
);
struct
block_device_operations
ide_fops
[]
=
{{
owner:
THIS_MODULE
,
open:
ide_open
,
...
...
@@ -3514,10 +3466,7 @@ struct block_device_operations ide_fops[] = {{
revalidate:
ide_revalidate_disk
}};
EXPORT_SYMBOL
(
ide_hwifs
);
EXPORT_SYMBOL
(
ide_register_driver
);
EXPORT_SYMBOL
(
ide_unregister_driver
);
EXPORT_SYMBOL
(
ide_spin_wait_hwgroup
);
EXPORT_SYMBOL
(
ide_fops
);
/*
* Probe module
...
...
@@ -3526,58 +3475,7 @@ devfs_handle_t ide_devfs_handle;
EXPORT_SYMBOL
(
ide_lock
);
EXPORT_SYMBOL
(
ide_probe
);
EXPORT_SYMBOL
(
drive_is_flashcard
);
EXPORT_SYMBOL
(
ide_timer_expiry
);
EXPORT_SYMBOL
(
ide_intr
);
EXPORT_SYMBOL
(
ide_fops
);
EXPORT_SYMBOL
(
ide_get_queue
);
EXPORT_SYMBOL
(
ide_add_generic_settings
);
EXPORT_SYMBOL
(
ide_devfs_handle
);
EXPORT_SYMBOL
(
do_ide_request
);
/*
* Driver module
*/
EXPORT_SYMBOL
(
ide_register_subdriver
);
EXPORT_SYMBOL
(
ide_unregister_subdriver
);
EXPORT_SYMBOL
(
ide_replace_subdriver
);
EXPORT_SYMBOL
(
ide_set_handler
);
EXPORT_SYMBOL
(
ide_dump_status
);
EXPORT_SYMBOL
(
ide_error
);
EXPORT_SYMBOL
(
ide_fixstring
);
EXPORT_SYMBOL
(
ide_do_reset
);
EXPORT_SYMBOL
(
restart_request
);
EXPORT_SYMBOL
(
ide_init_drive_cmd
);
EXPORT_SYMBOL
(
ide_do_drive_cmd
);
EXPORT_SYMBOL
(
ide_end_drive_cmd
);
EXPORT_SYMBOL
(
ide_end_request
);
EXPORT_SYMBOL
(
ide_revalidate_drive
);
EXPORT_SYMBOL
(
ide_cmd
);
EXPORT_SYMBOL
(
ide_wait_cmd
);
EXPORT_SYMBOL
(
ide_wait_cmd_task
);
EXPORT_SYMBOL
(
ide_delay_50ms
);
EXPORT_SYMBOL
(
ide_stall_queue
);
#ifdef CONFIG_PROC_FS
EXPORT_SYMBOL
(
ide_add_proc_entries
);
EXPORT_SYMBOL
(
ide_remove_proc_entries
);
EXPORT_SYMBOL
(
proc_ide_read_geometry
);
EXPORT_SYMBOL
(
create_proc_ide_interfaces
);
EXPORT_SYMBOL
(
recreate_proc_ide_device
);
EXPORT_SYMBOL
(
destroy_proc_ide_device
);
#endif
EXPORT_SYMBOL
(
ide_add_setting
);
EXPORT_SYMBOL
(
ide_remove_setting
);
EXPORT_SYMBOL
(
ide_register_hw
);
EXPORT_SYMBOL
(
ide_register
);
EXPORT_SYMBOL
(
ide_unregister
);
EXPORT_SYMBOL
(
ide_setup_ports
);
EXPORT_SYMBOL
(
hwif_unregister
);
EXPORT_SYMBOL
(
get_info_ptr
);
EXPORT_SYMBOL
(
current_capacity
);
EXPORT_SYMBOL
(
system_bus_clock
);
EXPORT_SYMBOL
(
ata_attach
);
static
int
ide_notify_reboot
(
struct
notifier_block
*
this
,
unsigned
long
event
,
void
*
x
)
{
...
...
@@ -3594,7 +3492,7 @@ static int ide_notify_reboot (struct notifier_block *this, unsigned long event,
return
NOTIFY_DONE
;
}
printk
(
"flushing ide devices: "
);
printk
(
KERN_INFO
"flushing ide devices: "
);
for
(
i
=
0
;
i
<
MAX_HWIFS
;
i
++
)
{
hwif
=
&
ide_hwifs
[
i
];
...
...
@@ -3633,12 +3531,12 @@ int __init ide_init (void)
static
char
banner_printed
;
if
(
!
banner_printed
)
{
printk
(
KERN_INFO
"Uniform Multi-Platform E-IDE driver "
REVISION
"
\n
"
);
ide_devfs_handle
=
devfs_mk_dir
(
NULL
,
"ide"
,
NULL
);
ide_devfs_handle
=
devfs_mk_dir
(
NULL
,
"ide"
,
NULL
);
system_bus_speed
=
ide_system_bus_speed
();
banner_printed
=
1
;
}
init_ide_data
();
init_ide_data
();
initializing
=
1
;
ide_init_builtin_drivers
();
...
...
include/linux/ide.h
View file @
79b2577a
...
...
@@ -3,7 +3,7 @@
/*
* linux/include/linux/ide.h
*
* Copyright (C) 1994-
1998
Linus Torvalds & authors
* Copyright (C) 1994-
2002
Linus Torvalds & authors
*/
#include <linux/config.h>
...
...
@@ -14,18 +14,14 @@
#include <linux/blkdev.h>
#include <linux/proc_fs.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/bio.h>
#include <asm/byteorder.h>
#include <asm/system.h>
#include <asm/hdreg.h>
#include <asm/io.h>
#ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
# define __IDEDMA_TIMEOUT
#else
/* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
# undef __IDEDMA_TIMEOUT
#endif
/* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
/*
* This is the multiple IDE interface driver, as evolved from hd.c.
* It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15).
...
...
@@ -42,7 +38,7 @@
*
* REALLY_SLOW_IO can be defined in ide.c and ide-cd.c, if necessary
*/
#
undef
REALLY_FAST_IO
/* define if ide ports are perfect */
#
define
REALLY_FAST_IO
/* define if ide ports are perfect */
#define INITIAL_MULT_COUNT 0
/* off=0; on=2,4,8,16,32, etc.. */
#ifndef SUPPORT_SLOW_DATA_PORTS
/* 1 to support slow data ports */
...
...
@@ -170,9 +166,6 @@ typedef unsigned char byte; /* used everywhere */
#define IDE_BCOUNTL_REG IDE_LCYL_REG
#define IDE_BCOUNTH_REG IDE_HCYL_REG
#define GET_ERR() IN_BYTE(IDE_ERROR_REG)
#define GET_STAT() IN_BYTE(IDE_STATUS_REG)
#define GET_ALTSTAT() IN_BYTE(IDE_CONTROL_REG)
#define OK_STAT(stat,good,bad) (((stat)&((good)|(bad)))==(good))
#define BAD_R_STAT (BUSY_STAT | ERR_STAT)
#define BAD_W_STAT (BAD_R_STAT | WRERR_STAT)
...
...
@@ -180,6 +173,43 @@ typedef unsigned char byte; /* used everywhere */
#define DRIVE_READY (READY_STAT | SEEK_STAT)
#define DATA_READY (DRQ_STAT)
#define BAD_CRC (ABRT_ERR | ICRC_ERR)
#define SATA_NR_PORTS (3)
/* 16 possible ?? */
#define SATA_STATUS_OFFSET (0)
#define SATA_STATUS_REG (HWIF(drive)->sata_scr[SATA_STATUS_OFFSET])
#define SATA_ERROR_OFFSET (1)
#define SATA_ERROR_REG (HWIF(drive)->sata_scr[SATA_ERROR_OFFSET])
#define SATA_CONTROL_OFFSET (2)
#define SATA_CONTROL_REG (HWIF(drive)->sata_scr[SATA_CONTROL_OFFSET])
#define SATA_MISC_OFFSET (0)
#define SATA_MISC_REG (HWIF(drive)->sata_misc[SATA_MISC_OFFSET])
#define SATA_PHY_OFFSET (1)
#define SATA_PHY_REG (HWIF(drive)->sata_misc[SATA_PHY_OFFSET])
#define SATA_IEN_OFFSET (2)
#define SATA_IEN_REG (HWIF(drive)->sata_misc[SATA_IEN_OFFSET])
/*
* Our Physical Region Descriptor (PRD) table should be large enough
* to handle the biggest I/O request we are likely to see. Since requests
* can have no more than 256 sectors, and since the typical blocksize is
* two or more sectors, we could get by with a limit of 128 entries here for
* the usual worst case. Most requests seem to include some contiguous blocks,
* further reducing the number of table entries required.
*
* The driver reverts to PIO mode for individual requests that exceed
* this limit (possible with 512 byte blocksizes, eg. MSDOS f/s), so handling
* 100% of all crazy scenarios here is not necessary.
*
* As it turns out though, we must allocate a full 4KB page for this,
* so the two PRD tables (ide0 & ide1) will each get half of that,
* allowing each to have about 256 entries (8 bytes each) from this.
*/
#define PRD_BYTES 8
#define PRD_ENTRIES (PAGE_SIZE / (2 * PRD_BYTES))
/*
* sector count bits
*/
...
...
@@ -215,21 +245,12 @@ typedef unsigned char byte; /* used everywhere */
#define PARTN_BITS 6
/* number of minor dev bits for partitions */
#define PARTN_MASK ((1<<PARTN_BITS)-1)
/* a useful bit mask */
#define MAX_DRIVES 2
/* per interface; 2 assumed by lots of code */
#define CASCADE_DRIVES 8
/* per interface; 8|2 assumed by lots of code */
#define SECTOR_SIZE 512
#define SECTOR_WORDS (SECTOR_SIZE / 4)
/* number of 32bit words per sector */
#define IDE_LARGE_SEEK(b1,b2,t) (((b1) > (b2) + (t)) || ((b2) > (b1) + (t)))
#define IDE_MIN(a,b) ((a)<(b) ? (a):(b))
#define IDE_MAX(a,b) ((a)>(b) ? (a):(b))
#ifndef SPLIT_WORD
# define SPLIT_WORD(W,HB,LB) ((HB)=(W>>8), (LB)=(W-((W>>8)<<8)))
#endif
#ifndef MAKE_WORD
# define MAKE_WORD(W,HB,LB) ((W)=((HB<<8)+LB))
#endif
/*
* Timeouts for various operations:
*/
...
...
@@ -244,39 +265,6 @@ typedef unsigned char byte; /* used everywhere */
#define WAIT_CMD (10*HZ)
/* 10sec - maximum wait for an IRQ to happen */
#define WAIT_MIN_SLEEP (2*HZ/100)
/* 20msec - minimum sleep time */
#define SELECT_DRIVE(hwif,drive) \
{ \
if (hwif->selectproc) \
hwif->selectproc(drive); \
OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); \
}
#define SELECT_INTERRUPT(hwif,drive) \
{ \
if (hwif->intrproc) \
hwif->intrproc(drive); \
else \
OUT_BYTE((drive)->ctl|2, hwif->io_ports[IDE_CONTROL_OFFSET]); \
}
#define SELECT_MASK(hwif,drive,mask) \
{ \
if (hwif->maskproc) \
hwif->maskproc(drive,mask); \
}
#define SELECT_READ_WRITE(hwif,drive,func) \
{ \
if (hwif->rwproc) \
hwif->rwproc(drive,func); \
}
#define QUIRK_LIST(hwif,drive) \
{ \
if (hwif->quirkproc) \
(drive)->quirk_list = hwif->quirkproc(drive); \
}
#define HOST(hwif,chipset) \
{ \
return ((hwif)->chipset == chipset) ? 1 : 0; \
...
...
@@ -304,9 +292,34 @@ typedef enum { ide_unknown, ide_generic, ide_pci,
ide_qd65xx
,
ide_umc8672
,
ide_ht6560b
,
ide_pdc4030
,
ide_rz1000
,
ide_trm290
,
ide_cmd646
,
ide_cy82c693
,
ide_4drives
,
ide_pmac
,
ide_etrax100
ide_pmac
,
ide_etrax100
,
ide_acorn
}
hwif_chipset_t
;
typedef
struct
ide_io_ops_s
{
/* insert io operations here! */
void
(
*
OUTB
)(
u8
addr
,
u32
port
);
void
(
*
OUTW
)(
u16
addr
,
u32
port
);
void
(
*
OUTL
)(
u32
addr
,
u32
port
);
void
(
*
OUTBP
)(
u8
addr
,
u32
port
);
void
(
*
OUTWP
)(
u16
addr
,
u32
port
);
void
(
*
OUTLP
)(
u32
addr
,
u32
port
);
void
(
*
OUTSW
)(
u32
port
,
void
*
addr
,
u32
count
);
void
(
*
OUTSWP
)(
u32
port
,
void
*
addr
,
u32
count
);
void
(
*
OUTSL
)(
u32
port
,
void
*
addr
,
u32
count
);
void
(
*
OUTSLP
)(
u32
port
,
void
*
addr
,
u32
count
);
u8
(
*
INB
)(
u32
port
);
u16
(
*
INW
)(
u32
port
);
u32
(
*
INL
)(
u32
port
);
u8
(
*
INBP
)(
u32
port
);
u16
(
*
INWP
)(
u32
port
);
u32
(
*
INLP
)(
u32
port
);
void
(
*
INSW
)(
u32
port
,
void
*
addr
,
u32
count
);
void
(
*
INSWP
)(
u32
port
,
void
*
addr
,
u32
count
);
void
(
*
INSL
)(
u32
port
,
void
*
addr
,
u32
count
);
void
(
*
INSLP
)(
u32
port
,
void
*
addr
,
u32
count
);
}
ide_io_ops_t
;
/*
* Structure to hold all information about the location of this port
*/
...
...
@@ -317,6 +330,11 @@ typedef struct hw_regs_s {
ide_ack_intr_t
*
ack_intr
;
/* acknowledge interrupt */
void
*
priv
;
/* interface specific data */
hwif_chipset_t
chipset
;
#if 0
ide_io_ops_t *iops; /* */
#endif
sata_ioreg_t
sata_scr
[
SATA_NR_PORTS
];
sata_ioreg_t
sata_misc
[
SATA_NR_PORTS
];
}
hw_regs_t
;
/*
...
...
@@ -333,10 +351,27 @@ void ide_setup_ports( hw_regs_t *hw,
ide_ioreg_t
ctrl
,
ide_ioreg_t
intr
,
ide_ack_intr_t
*
ack_intr
,
#if 0
ide_io_ops_t *iops,
#endif
int
irq
);
#include <asm/ide.h>
/* Currently only m68k, apus and m8xx need it */
#ifdef IDE_ARCH_ACK_INTR
extern
int
ide_irq_lock
;
# define ide_ack_intr(hwif) (hwif->hw.ack_intr ? hwif->hw.ack_intr(hwif) : 1)
#else
# define ide_ack_intr(hwif) (1)
#endif
/* Currently only Atari needs it */
#ifndef IDE_ARCH_LOCK
# define ide_release_lock(lock) do {} while (0)
# define ide_get_lock(lock, hdlr, data) do {} while (0)
#endif
/* IDE_ARCH_LOCK */
/*
* If the arch-dependant ide.h did not declare/define any OUT_BYTE
* or IN_BYTE functions, we make some defaults here.
...
...
@@ -346,20 +381,30 @@ void ide_setup_ports( hw_regs_t *hw,
# ifdef REALLY_FAST_IO
# define OUT_BYTE(b,p) outb((b),(p))
# define OUT_WORD(w,p) outw((w),(p))
# define OUT_LONG(l,p) outl((l),(p))
# else
# define OUT_BYTE(b,p) outb_p((b),(p))
# define OUT_WORD(w,p) outw_p((w),(p))
# define OUT_LONG(l,p) outl_p((l),(p))
# endif
# define OUT_BYTE_P(b,p) outb_p((b),(p))
# define OUT_WORD_P(w,p) outw_p((w),(p))
# define OUT_LONG_P(l,p) outl_p((l),(p))
#endif
#ifndef HAVE_ARCH_IN_BYTE
# ifdef REALLY_FAST_IO
# define IN_BYTE(p) (byte)inb(p)
# define IN_WORD(p) (short)inw(p)
# define IN_BYTE(p) (u8) inb(p)
# define IN_WORD(p) (u16) inw(p)
# define IN_LONG(p) (u32) inl(p)
# else
# define IN_BYTE(p) (byte)inb_p(p)
# define IN_WORD(p) (short)inw_p(p)
# define IN_BYTE(p) (u8) inb_p(p)
# define IN_WORD(p) (u16) inw_p(p)
# define IN_LONG(p) (u32) inl_p(p)
# endif
# define IN_BYTE_P(p) (u8) inb_p(p)
# define IN_WORD_P(p) (u16) inw_p(p)
# define IN_LONG_P(p) (u32) inl_p(p)
#endif
/*
...
...
@@ -373,201 +418,453 @@ void ide_setup_ports( hw_regs_t *hw,
#define ide_tape 0x1
#define ide_floppy 0x0
/*
* Special Driver Flags
*
* set_geometry : respecify drive geometry
* recalibrate : seek to cyl 0
* set_multmode : set multmode count
* set_tune : tune interface for drive
* serviced : service command
* reserved : unused
*/
typedef
union
{
unsigned
all
:
8
;
/* all of the bits together */
unsigned
all
:
8
;
struct
{
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned
set_geometry
:
1
;
/* respecify drive geometry */
unsigned
recalibrate
:
1
;
/* seek to cyl 0 */
unsigned
set_multmode
:
1
;
/* set multmode count */
unsigned
set_tune
:
1
;
/* tune interface for drive */
unsigned
serviced
:
1
;
/* service command */
unsigned
reserved
:
3
;
/* unused */
unsigned
set_geometry
:
1
;
unsigned
recalibrate
:
1
;
unsigned
set_multmode
:
1
;
unsigned
set_tune
:
1
;
unsigned
serviced
:
1
;
unsigned
reserved
:
3
;
#elif defined(__BIG_ENDIAN_BITFIELD)
unsigned
reserved
:
3
;
/* unused */
unsigned
serviced
:
1
;
/* service command */
unsigned
set_tune
:
1
;
/* tune interface for drive */
unsigned
set_multmode
:
1
;
/* set multmode count */
unsigned
recalibrate
:
1
;
/* seek to cyl 0 */
unsigned
set_geometry
:
1
;
/* respecify drive geometry */
unsigned
reserved
:
3
;
unsigned
serviced
:
1
;
unsigned
set_tune
:
1
;
unsigned
set_multmode
:
1
;
unsigned
recalibrate
:
1
;
unsigned
set_geometry
:
1
;
#else
#error "Please fix <asm/byteorder.h>"
#endif
}
b
;
}
special_t
;
/*
* ATA DATA Register Special.
* ATA NSECTOR Count Register().
* ATAPI Byte Count Register.
* Channel index ordering pairs.
*/
typedef
union
{
unsigned
all
:
16
;
struct
{
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned
low
:
8
;
/* LSB */
unsigned
high
:
8
;
/* MSB */
#elif defined(__BIG_ENDIAN_BITFIELD)
unsigned
high
:
8
;
/* MSB */
unsigned
low
:
8
;
/* LSB */
#else
#error "Please fix <asm/byteorder.h>"
#endif
}
b
;
}
ata_nsector_t
,
ata_data_t
,
atapi_bcount_t
,
ata_index_t
;
/*
* ATA-IDE Error Register
*
* mark : Bad address mark
* tzero : Couldn't find track 0
* abrt : Aborted Command
* mcr : Media Change Request
* id : ID field not found
* mce : Media Change Event
* ecc : Uncorrectable ECC error
* bdd : dual meaing
*/
typedef
union
{
unsigned
all
:
8
;
/* all of the bits together */
unsigned
all
:
8
;
struct
{
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned
head
:
4
;
/* always zeros here */
unsigned
unit
:
1
;
/* drive select number: 0/1 */
unsigned
bit5
:
1
;
/* always 1 */
unsigned
lba
:
1
;
/* using LBA instead of CHS */
unsigned
bit7
:
1
;
/* always 1 */
unsigned
mark
:
1
;
unsigned
tzero
:
1
;
unsigned
abrt
:
1
;
unsigned
mcr
:
1
;
unsigned
id
:
1
;
unsigned
mce
:
1
;
unsigned
ecc
:
1
;
unsigned
bdd
:
1
;
#elif defined(__BIG_ENDIAN_BITFIELD)
unsigned
bit7
:
1
;
/* always 1 */
unsigned
lba
:
1
;
/* using LBA instead of CHS */
unsigned
bit5
:
1
;
/* always 1 */
unsigned
unit
:
1
;
/* drive select number: 0/1 */
unsigned
head
:
4
;
/* always zeros here */
unsigned
bdd
:
1
;
unsigned
ecc
:
1
;
unsigned
mce
:
1
;
unsigned
id
:
1
;
unsigned
mcr
:
1
;
unsigned
abrt
:
1
;
unsigned
tzero
:
1
;
unsigned
mark
:
1
;
#else
#error "Please fix <asm/byteorder.h>"
#endif
}
b
;
}
select
_t
;
}
ata_error
_t
;
/*
* ATA-IDE Select Register, aka Device-Head
*
* head : always zeros here
* unit : drive select number: 0/1
* bit5 : always 1
* lba : using LBA instead of CHS
* bit7 : always 1
*/
typedef
union
{
unsigned
all
:
8
;
/* all of the bits together */
unsigned
all
:
8
;
struct
{
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned
head
:
4
;
unsigned
unit
:
1
;
unsigned
bit5
:
1
;
unsigned
lba
:
1
;
unsigned
bit7
:
1
;
#elif defined(__BIG_ENDIAN_BITFIELD)
unsigned
bit7
:
1
;
unsigned
lba
:
1
;
unsigned
bit5
:
1
;
unsigned
unit
:
1
;
unsigned
head
:
4
;
#else
#error "Please fix <asm/byteorder.h>"
#endif
}
b
;
}
select_t
,
ata_select_t
;
/*
* The ATA-IDE Status Register.
* The ATAPI Status Register.
*
* check : Error occurred
* idx : Index Error
* corr : Correctable error occurred
* drq : Data is request by the device
* dsc : Disk Seek Complete : ata
* : Media access command finished : atapi
* df : Device Fault : ata
* : Reserved : atapi
* drdy : Ready, Command Mode Capable : ata
* : Ignored for ATAPI commands : atapi
* bsy : Disk is Busy
* : The device has access to the command block
*/
typedef
union
{
unsigned
all
:
8
;
struct
{
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned
check
:
1
;
unsigned
idx
:
1
;
unsigned
corr
:
1
;
unsigned
drq
:
1
;
unsigned
dsc
:
1
;
unsigned
df
:
1
;
unsigned
drdy
:
1
;
unsigned
bsy
:
1
;
#elif defined(__BIG_ENDIAN_BITFIELD)
unsigned
bsy
:
1
;
unsigned
drdy
:
1
;
unsigned
df
:
1
;
unsigned
dsc
:
1
;
unsigned
drq
:
1
;
unsigned
corr
:
1
;
unsigned
idx
:
1
;
unsigned
check
:
1
;
#else
#error "Please fix <asm/byteorder.h>"
#endif
}
b
;
}
ata_status_t
,
atapi_status_t
;
/*
* ATA-IDE Control Register
*
* bit0 : Should be set to zero
* nIEN : device INTRQ to host
* SRST : host soft reset bit
* bit3 : ATA-2 thingy, Should be set to 1
* reserved456 : Reserved
* HOB : 48-bit address ordering, High Ordered Bit
*/
typedef
union
{
unsigned
all
:
8
;
struct
{
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned
bit0
:
1
;
unsigned
nIEN
:
1
;
/* device INTRQ to host */
unsigned
SRST
:
1
;
/* host soft reset bit */
unsigned
bit3
:
1
;
/* ATA-2 thingy */
unsigned
reserved456
:
3
;
unsigned
HOB
:
1
;
/* 48-bit address ordering */
unsigned
nIEN
:
1
;
unsigned
SRST
:
1
;
unsigned
bit3
:
1
;
unsigned
reserved456
:
3
;
unsigned
HOB
:
1
;
#elif defined(__BIG_ENDIAN_BITFIELD)
unsigned
HOB
:
1
;
/* 48-bit address ordering */
unsigned
HOB
:
1
;
unsigned
reserved456
:
3
;
unsigned
bit3
:
1
;
/* ATA-2 thingy */
unsigned
SRST
:
1
;
/* host soft reset bit */
unsigned
nIEN
:
1
;
/* device INTRQ to host */
unsigned
bit3
:
1
;
unsigned
SRST
:
1
;
unsigned
nIEN
:
1
;
unsigned
bit0
:
1
;
#else
#error "Please fix <asm/byteorder.h>"
#endif
}
b
;
}
control_t
;
}
ata_
control_t
;
/*
* ATAPI Feature Register
*
* dma : Using DMA or PIO
* reserved321 : Reserved
* reserved654 : Reserved (Tag Type)
* reserved7 : Reserved
*/
typedef
union
{
unsigned
all
:
8
;
struct
{
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned
dma
:
1
;
unsigned
reserved321
:
3
;
unsigned
reserved654
:
3
;
unsigned
reserved7
:
1
;
#elif defined(__BIG_ENDIAN_BITFIELD)
unsigned
reserved7
:
1
;
unsigned
reserved654
:
3
;
unsigned
reserved321
:
3
;
unsigned
dma
:
1
;
#else
#error "Please fix <asm/byteorder.h>"
#endif
}
b
;
}
atapi_feature_t
;
/*
* ATAPI Interrupt Reason Register.
*
* cod : Information transferred is command (1) or data (0)
* io : The device requests us to read (1) or write (0)
* reserved : Reserved
*/
typedef
union
{
unsigned
all
:
8
;
struct
{
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned
cod
:
1
;
unsigned
io
:
1
;
unsigned
reserved
:
6
;
#elif defined(__BIG_ENDIAN_BITFIELD)
unsigned
reserved
:
6
;
unsigned
io
:
1
;
unsigned
cod
:
1
;
#else
#error "Please fix <asm/byteorder.h>"
#endif
}
b
;
}
atapi_ireason_t
;
/*
* The ATAPI error register.
*
* ili : Illegal Length Indication
* eom : End Of Media Detected
* abrt : Aborted command - As defined by ATA
* mcr : Media Change Requested - As defined by ATA
* sense_key : Sense key of the last failed packet command
*/
typedef
union
{
unsigned
all
:
8
;
struct
{
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned
ili
:
1
;
unsigned
eom
:
1
;
unsigned
abrt
:
1
;
unsigned
mcr
:
1
;
unsigned
sense_key
:
4
;
#elif defined(__BIG_ENDIAN_BITFIELD)
unsigned
sense_key
:
4
;
unsigned
mcr
:
1
;
unsigned
abrt
:
1
;
unsigned
eom
:
1
;
unsigned
ili
:
1
;
#else
#error "Please fix <asm/byteorder.h>"
#endif
}
b
;
}
atapi_error_t
;
/*
* ATAPI floppy Drive Select Register
*
* sam_lun : Logical unit number
* reserved3 : Reserved
* drv : The responding drive will be drive 0 (0) or drive 1 (1)
* one5 : Should be set to 1
* reserved6 : Reserved
* one7 : Should be set to 1
*/
typedef
union
{
unsigned
all
:
8
;
struct
{
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned
sam_lun
:
3
;
unsigned
reserved3
:
1
;
unsigned
drv
:
1
;
unsigned
one5
:
1
;
unsigned
reserved6
:
1
;
unsigned
one7
:
1
;
#elif defined(__BIG_ENDIAN_BITFIELD)
unsigned
one7
:
1
;
unsigned
reserved6
:
1
;
unsigned
one5
:
1
;
unsigned
drv
:
1
;
unsigned
reserved3
:
1
;
unsigned
sam_lun
:
3
;
#else
#error "Please fix <asm/byteorder.h>"
#endif
}
b
;
}
atapi_select_t
;
struct
ide_driver_s
;
struct
ide_settings_s
;
typedef
struct
ide_drive_s
{
request_queue_t
queue
;
/* request queue */
char
name
[
4
];
/* drive name, such as "hda" */
char
driver_req
[
10
];
/* requests specific driver */
request_queue_t
queue
;
/* request queue */
struct
request
*
rq
;
/* current request */
struct
ide_drive_s
*
next
;
/* circular list of hwgroup drives */
struct
ide_driver_s
*
driver
;
/* (ide_driver_t *) */
void
*
driver_data
;
/* extra driver data */
struct
hd_driveid
*
id
;
/* drive model identification info */
struct
proc_dir_entry
*
proc
;
/* /proc/ide/ directory entry */
struct
ide_settings_s
*
settings
;
/* /proc/ide/ drive settings */
devfs_handle_t
de
;
/* directory for device */
struct
hwif_s
*
hwif
;
/* actually (ide_hwif_t *) */
unsigned
long
sleep
;
/* sleep until this time */
unsigned
long
service_start
;
/* time we started last request */
unsigned
long
service_time
;
/* service time of last request */
unsigned
long
timeout
;
/* max time to wait for irq */
special_t
special
;
/* special action flags */
byte
keep_settings
;
/* restore settings after drive reset */
byte
using_dma
;
/* disk is using dma for read/write */
byte
retry_pio
;
/* retrying dma capable host in pio */
byte
state
;
/* retry state */
byte
waiting_for_dma
;
/* dma currently in progress */
byte
unmask
;
/* flag: okay to unmask other irqs */
byte
slow
;
/* flag: slow data port */
byte
bswap
;
/* flag: byte swap data */
byte
dsc_overlap
;
/* flag: DSC overlap */
byte
nice1
;
/* flag: give potential excess bandwidth */
select_t
select
;
/* basic drive/head select reg value */
u8
keep_settings
;
/* restore settings after drive reset */
u8
autodma
;
/* device can safely use dma on host */
u8
using_dma
;
/* disk is using dma for read/write */
u8
using_tcq
;
/* disk is using queueing */
u8
retry_pio
;
/* retrying dma capable host in pio */
u8
state
;
/* retry state */
u8
waiting_for_dma
;
/* dma currently in progress */
u8
unmask
;
/* okay to unmask other irqs */
u8
slow
;
/* slow data port */
u8
bswap
;
/* byte swap data */
u8
dsc_overlap
;
/* DSC overlap */
u8
nice1
;
/* give potential excess bandwidth */
unsigned
present
:
1
;
/* drive is physically present */
unsigned
noprobe
:
1
;
/* from: hdx=noprobe */
unsigned
removable
:
1
;
/* 1 if need to do check_media_change */
unsigned
is_flash
:
1
;
/* 1 if probed as flash */
unsigned
forced_geom
:
1
;
/* 1 if hdx=c,h,s was given at boot */
unsigned
no_unmask
:
1
;
/* disallow setting unmask bit */
unsigned
no_io_32bit
:
1
;
/* disallow enabling 32bit I/O */
unsigned
nobios
:
1
;
/*
flag:
do not probe bios for drive */
unsigned
atapi_overlap
:
1
;
/*
flag:
ATAPI overlap (not supported) */
unsigned
nice0
:
1
;
/*
flag:
give obvious excess bandwidth */
unsigned
nice2
:
1
;
/*
flag:
give a share in our own bandwidth */
unsigned
doorlocking
:
1
;
/* f
lag: f
or removable only: door lock/unlock works */
unsigned
nobios
:
1
;
/* do not probe bios for drive */
unsigned
atapi_overlap
:
1
;
/* ATAPI overlap (not supported) */
unsigned
nice0
:
1
;
/* give obvious excess bandwidth */
unsigned
nice2
:
1
;
/* give a share in our own bandwidth */
unsigned
doorlocking
:
1
;
/* for removable only: door lock/unlock works */
unsigned
autotune
:
2
;
/* 1=autotune, 2=noautotune, 0=default */
unsigned
remap_0_to_1
:
2
;
/* 0=remap if ezdrive, 1=remap, 2=noremap */
unsigned
ata_flash
:
1
;
/* 1=present, 0=default */
unsigned
addressing
;
/*
: 3;
unsigned
addressing
;
/*
: 3;
* 0=28-bit
* 1=48-bit
* 2=48-bit doing 28-bit
* 3=64-bit
*/
byte
scsi
;
/* 0=default, 1=skip current ide-subdriver for ide-scsi emulation */
byte
media
;
/* disk, cdrom, tape, floppy, ... */
select_t
select
;
/* basic drive/head select reg value */
byte
ctl
;
/* "normal" value for IDE_CONTROL_REG */
byte
ready_stat
;
/* min status value for drive ready */
byte
mult_count
;
/* current multiple sector setting */
byte
mult_req
;
/* requested multiple sector setting */
byte
tune_req
;
/* requested drive tuning setting */
byte
io_32bit
;
/* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
byte
bad_wstat
;
/* used for ignoring WRERR_STAT */
byte
nowerr
;
/* used for ignoring WRERR_STAT */
byte
sect0
;
/* offset of first sector for DM6:DDO */
unsigned
int
usage
;
/* current "open()" count for drive */
byte
head
;
/* "real" number of heads */
byte
sect
;
/* "real" sectors per track */
byte
bios_head
;
/* BIOS/fdisk/LILO number of heads */
byte
bios_sect
;
/* BIOS/fdisk/LILO sectors per track */
u8
scsi
;
/* 0=default, 1=skip current ide-subdriver for ide-scsi emulation */
u8
quirk_list
;
/* considered quirky, set for a specific host */
u8
suspend_reset
;
/* drive suspend mode flag, soft-reset recovers */
u8
init_speed
;
/* transfer rate set at boot */
u8
current_speed
;
/* current transfer rate set */
u8
dn
;
/* now wide spread use */
u8
wcache
;
/* status of write cache */
u8
acoustic
;
/* acoustic management */
u8
media
;
/* disk, cdrom, tape, floppy, ... */
u8
ctl
;
/* "normal" value for IDE_CONTROL_REG */
u8
ready_stat
;
/* min status value for drive ready */
u8
mult_count
;
/* current multiple sector setting */
u8
mult_req
;
/* requested multiple sector setting */
u8
tune_req
;
/* requested drive tuning setting */
u8
io_32bit
;
/* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
u8
bad_wstat
;
/* used for ignoring WRERR_STAT */
u8
nowerr
;
/* used for ignoring WRERR_STAT */
u8
sect0
;
/* offset of first sector for DM6:DDO */
u8
head
;
/* "real" number of heads */
u8
sect
;
/* "real" sectors per track */
u8
bios_head
;
/* BIOS/fdisk/LILO number of heads */
u8
bios_sect
;
/* BIOS/fdisk/LILO sectors per track */
unsigned
int
bios_cyl
;
/* BIOS/fdisk/LILO number of cyls */
unsigned
int
cyl
;
/* "real" number of cyls */
unsigned
long
capacity
;
/* total number of sectors */
unsigned
long
long
capacity48
;
/* total number of sectors */
unsigned
int
drive_data
;
/* for use by tuneproc/selectproc as needed */
struct
hwif_s
*
hwif
;
/* actually (ide_hwif_t *) */
struct
hd_driveid
*
id
;
/* drive model identification info */
char
name
[
4
];
/* drive name, such as "hda" */
struct
ide_driver_s
*
driver
;
/* (ide_driver_t *) */
void
*
driver_data
;
/* extra driver data */
devfs_handle_t
de
;
/* directory for device */
struct
proc_dir_entry
*
proc
;
/* /proc/ide/ directory entry */
struct
ide_settings_s
*
settings
;
/* /proc/ide/ drive settings */
char
driver_req
[
10
];
/* requests specific driver */
unsigned
int
drive_data
;
/* use by tuneproc/selectproc */
unsigned
int
usage
;
/* current "open()" count for drive */
unsigned
int
failures
;
/* current failure count */
unsigned
int
max_failures
;
/* maximum allowed failure count */
u32
capacity
;
/* total number of sectors */
u64
capacity48
;
/* total number of sectors */
int
last_lun
;
/* last logical unit */
int
forced_lun
;
/* if hdxlun was given at boot */
int
lun
;
/* logical unit */
int
crc_count
;
/* crc counter to reduce drive speed */
byte
quirk_list
;
/* drive is considered quirky if set for a specific host */
byte
suspend_reset
;
/* drive suspend mode flag, soft-reset recovers */
byte
init_speed
;
/* transfer rate set at boot */
byte
current_speed
;
/* current transfer rate set */
byte
dn
;
/* now wide spread use */
byte
wcache
;
/* status of write cache */
byte
acoustic
;
/* acoustic management */
unsigned
int
failures
;
/* current failure count */
unsigned
int
max_failures
;
/* maximum allowed failure count */
struct
list_head
list
;
struct
gendisk
*
disk
;
}
ide_drive_t
;
/*
* An ide_dmaproc_t() initiates/aborts DMA read/write operations on a drive.
*
* The caller is assumed to have selected the drive and programmed the drive's
* sector address using CHS or LBA. All that remains is to prepare for DMA
* and then issue the actual read/write DMA/PIO command to the drive.
*
* Returns 0 if all went well.
* Returns 1 if DMA read/write could not be started, in which case the caller
* should either try again later, or revert to PIO for the current request.
*/
typedef
enum
{
ide_dma_read
,
ide_dma_write
,
ide_dma_begin
,
ide_dma_end
,
ide_dma_check
,
ide_dma_on
,
ide_dma_off
,
ide_dma_off_quietly
,
ide_dma_test_irq
,
ide_dma_host_on
,
ide_dma_host_off
,
ide_dma_bad_drive
,
ide_dma_good_drive
,
ide_dma_verbose
,
ide_dma_retune
,
ide_dma_lostirq
,
ide_dma_timeout
}
ide_dma_action_t
;
typedef
int
(
ide_dmaproc_t
)(
ide_dma_action_t
,
ide_drive_t
*
);
/*
* An ide_ideproc_t() performs CPU-polled transfers to/from a drive.
* Arguments are: the drive, the buffer pointer, and the length (in bytes or
* words depending on if it's an IDE or ATAPI call).
*
* If it is not defined for a controller, standard-code is used from ide.c.
*
* Controllers which are not memory-mapped in the standard way need to
* override that mechanism using this function to work.
*
*/
typedef
enum
{
ideproc_ide_input_data
,
ideproc_ide_output_data
,
ideproc_atapi_input_bytes
,
ideproc_atapi_output_bytes
}
ide_ide_action_t
;
typedef
void
(
ide_ideproc_t
)(
ide_ide_action_t
,
ide_drive_t
*
,
void
*
,
unsigned
int
);
typedef
struct
ide_pio_ops_s
{
void
(
*
ata_input_data
)(
ide_drive_t
*
,
void
*
,
u32
);
void
(
*
ata_output_data
)(
ide_drive_t
*
,
void
*
,
u32
);
void
(
*
atapi_input_bytes
)(
ide_drive_t
*
,
void
*
,
u32
);
void
(
*
atapi_output_bytes
)(
ide_drive_t
*
,
void
*
,
u32
);
}
ide_pio_ops_t
;
typedef
struct
ide_dma_ops_s
{
/* insert dma operations here! */
int
(
*
ide_dma_read
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_write
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_begin
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_end
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_check
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_on
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_off
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_off_quietly
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_test_irq
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_host_on
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_host_off
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_bad_drive
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_good_drive
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_count
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_verbose
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_retune
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_lostirq
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_timeout
)(
ide_drive_t
*
drive
);
}
ide_dma_ops_t
;
/*
* mapping stuff, prepare for highmem...
...
...
@@ -602,166 +899,182 @@ extern inline void ide_unmap_buffer(char *buffer, unsigned long *flags)
bio_kunmap_irq
(
buffer
,
flags
);
}
/*
* A Verbose noise maker for debugging on the attempted transfer rates.
*/
extern
inline
char
*
ide_xfer_verbose
(
byte
xfer_rate
)
{
switch
(
xfer_rate
)
{
case
XFER_UDMA_7
:
return
(
"UDMA 7"
);
case
XFER_UDMA_6
:
return
(
"UDMA 6"
);
case
XFER_UDMA_5
:
return
(
"UDMA 5"
);
case
XFER_UDMA_4
:
return
(
"UDMA 4"
);
case
XFER_UDMA_3
:
return
(
"UDMA 3"
);
case
XFER_UDMA_2
:
return
(
"UDMA 2"
);
case
XFER_UDMA_1
:
return
(
"UDMA 1"
);
case
XFER_UDMA_0
:
return
(
"UDMA 0"
);
case
XFER_MW_DMA_2
:
return
(
"MW DMA 2"
);
case
XFER_MW_DMA_1
:
return
(
"MW DMA 1"
);
case
XFER_MW_DMA_0
:
return
(
"MW DMA 0"
);
case
XFER_SW_DMA_2
:
return
(
"SW DMA 2"
);
case
XFER_SW_DMA_1
:
return
(
"SW DMA 1"
);
case
XFER_SW_DMA_0
:
return
(
"SW DMA 0"
);
case
XFER_PIO_4
:
return
(
"PIO 4"
);
case
XFER_PIO_3
:
return
(
"PIO 3"
);
case
XFER_PIO_2
:
return
(
"PIO 2"
);
case
XFER_PIO_1
:
return
(
"PIO 1"
);
case
XFER_PIO_0
:
return
(
"PIO 0"
);
case
XFER_PIO_SLOW
:
return
(
"PIO SLOW"
);
default:
return
(
"XFER ERROR"
);
}
}
/*
* A Verbose noise maker for debugging on the attempted dmaing calls.
*/
extern
inline
char
*
ide_dmafunc_verbose
(
ide_dma_action_t
dmafunc
)
{
switch
(
dmafunc
)
{
case
ide_dma_read
:
return
(
"ide_dma_read"
);
case
ide_dma_write
:
return
(
"ide_dma_write"
);
case
ide_dma_begin
:
return
(
"ide_dma_begin"
);
case
ide_dma_end
:
return
(
"ide_dma_end:"
);
case
ide_dma_check
:
return
(
"ide_dma_check"
);
case
ide_dma_on
:
return
(
"ide_dma_on"
);
case
ide_dma_off
:
return
(
"ide_dma_off"
);
case
ide_dma_off_quietly
:
return
(
"ide_dma_off_quietly"
);
case
ide_dma_test_irq
:
return
(
"ide_dma_test_irq"
);
case
ide_dma_host_on
:
return
(
"ide_dma_host_on"
);
case
ide_dma_host_off
:
return
(
"ide_dma_host_off"
);
case
ide_dma_bad_drive
:
return
(
"ide_dma_bad_drive"
);
case
ide_dma_good_drive
:
return
(
"ide_dma_good_drive"
);
case
ide_dma_verbose
:
return
(
"ide_dma_verbose"
);
case
ide_dma_retune
:
return
(
"ide_dma_retune"
);
case
ide_dma_lostirq
:
return
(
"ide_dma_lostirq"
);
case
ide_dma_timeout
:
return
(
"ide_dma_timeout"
);
default:
return
(
"unknown"
);
}
}
/*
* An ide_tuneproc_t() is used to set the speed of an IDE interface
* to a particular PIO mode. The "byte" parameter is used
* to select the PIO mode by number (0,1,2,3,4,5), and a value of 255
* indicates that the interface driver should "auto-tune" the PIO mode
* according to the drive capabilities in drive->id;
*
* Not all interface types support tuning, and not all of those
* support all possible PIO settings. They may silently ignore
* or round values as they see fit.
*/
typedef
void
(
ide_tuneproc_t
)
(
ide_drive_t
*
,
byte
);
typedef
int
(
ide_speedproc_t
)
(
ide_drive_t
*
,
byte
);
/*
* This is used to provide support for strange interfaces
*/
typedef
void
(
ide_selectproc_t
)
(
ide_drive_t
*
);
typedef
void
(
ide_resetproc_t
)
(
ide_drive_t
*
);
typedef
int
(
ide_quirkproc_t
)
(
ide_drive_t
*
);
typedef
void
(
ide_intrproc_t
)
(
ide_drive_t
*
);
typedef
void
(
ide_maskproc_t
)
(
ide_drive_t
*
,
int
);
typedef
void
(
ide_rw_proc_t
)
(
ide_drive_t
*
,
ide_dma_action_t
);
/*
* ide soft-power support
*/
typedef
int
(
ide_busproc_t
)
(
ide_drive_t
*
,
int
);
#define IDE_CHIPSET_PCI_MASK \
((1<<ide_pci)|(1<<ide_cmd646)|(1<<ide_ali14xx))
#define IDE_CHIPSET_IS_PCI(c) ((IDE_CHIPSET_PCI_MASK >> (c)) & 1)
#ifdef CONFIG_BLK_DEV_IDEPCI
typedef
struct
ide_pci_devid_s
{
unsigned
short
vid
;
unsigned
short
did
;
}
ide_pci_devid_t
;
#define IDE_PCI_DEVID_NULL ((ide_pci_devid_t){0,0})
#define IDE_PCI_DEVID_EQ(a,b) (a.vid == b.vid && a.did == b.did)
struct
ide_pci_device_s
;
#endif
/* CONFIG_BLK_DEV_IDEPCI */
typedef
struct
hwif_s
{
struct
hwif_s
*
next
;
/* for linked-list in ide_hwgroup_t */
struct
hwif_s
*
next
;
/* for linked-list in ide_hwgroup_t */
struct
hwif_s
*
mate
;
/* other hwif from same PCI chip */
struct
hwgroup_s
*
hwgroup
;
/* actually (ide_hwgroup_t *) */
ide_ioreg_t
io_ports
[
IDE_NR_PORTS
];
/* task file registers */
/*
* FIXME!! need a generic register set :-/ PPC guys ideas??
*
* ide_mmioreg_t mm_ports[IDE_NR_PORTS]; "task file registers"
*
*/
struct
proc_dir_entry
*
proc
;
/* /proc/ide/ directory entry */
char
name
[
6
];
/* name of interface, eg. "ide0" */
/* task file registers for pata and sata */
ide_ioreg_t
io_ports
[
IDE_NR_PORTS
];
sata_ioreg_t
sata_scr
[
SATA_NR_PORTS
];
sata_ioreg_t
sata_misc
[
SATA_NR_PORTS
];
hw_regs_t
hw
;
/* Hardware info */
ide_drive_t
drives
[
MAX_DRIVES
];
/* drive info */
int
addressing
;
/* hosts addressing */
void
(
*
tuneproc
)(
ide_drive_t
*
,
byte
);
/* routine to tune PIO mode for drives */
int
(
*
speedproc
)(
ide_drive_t
*
,
byte
);
/* routine to retune DMA modes for drives */
void
(
*
selectproc
)(
ide_drive_t
*
);
/* tweaks hardware to select drive */
void
(
*
resetproc
)(
ide_drive_t
*
);
/* routine to reset controller after a disk reset */
void
(
*
intrproc
)(
ide_drive_t
*
);
/* special interrupt handling for shared pci interrupts */
void
(
*
maskproc
)(
ide_drive_t
*
,
int
);
/* special host masking for drive selection */
int
(
*
quirkproc
)(
ide_drive_t
*
);
/* check host's drive quirk list */
void
(
*
rwproc
)(
ide_drive_t
*
,
ide_dma_action_t
);
/* adjust timing based upon rq->cmd direction */
void
(
*
ideproc
)(
ide_ide_action_t
,
ide_drive_t
*
,
void
*
,
unsigned
int
);
/* CPU-polled transfer routine */
int
(
*
dmaproc
)(
ide_dma_action_t
,
ide_drive_t
*
);
/* dma read/write/abort routine */
int
(
*
busproc
)(
ide_drive_t
*
,
int
);
/* driver soft-power interface */
unsigned
int
*
dmatable_cpu
;
/* dma physical region descriptor table (cpu view) */
dma_addr_t
dmatable_dma
;
/* dma physical region descriptor table (dma view) */
struct
scatterlist
*
sg_table
;
/* Scatter-gather list used to build the above */
u8
major
;
/* our major number */
u8
index
;
/* 0 for ide0; 1 for ide1; ... */
u8
channel
;
/* for dual-port chips: 0=primary, 1=secondary */
u8
straight8
;
/* Alan's straight 8 check */
u8
bus_state
;
/* power state of the IDE bus */
u8
atapi_dma
;
/* host supports atapi_dma */
u8
ultra_mask
;
u8
mwdma_mask
;
u8
swdma_mask
;
hwif_chipset_t
chipset
;
/* sub-module for tuning.. */
#ifdef CONFIG_BLK_DEV_IDEPCI
struct
pci_dev
*
pci_dev
;
/* for pci chipsets */
struct
ide_pci_device_s
*
cds
;
/* chipset device struct */
#endif
/* CONFIG_BLK_DEV_IDEPCI */
#if 0
ide_hwif_ops_t *hwifops;
#else
/* routine is for HBA specific IDENTITY operations */
int
(
*
identify
)(
ide_drive_t
*
);
/* routine to tune PIO mode for drives */
void
(
*
tuneproc
)(
ide_drive_t
*
,
u8
);
/* routine to retune DMA modes for drives */
int
(
*
speedproc
)(
ide_drive_t
*
,
u8
);
/* tweaks hardware to select drive */
void
(
*
selectproc
)(
ide_drive_t
*
);
/* chipset polling based on hba specifics */
int
(
*
reset_poll
)(
ide_drive_t
*
);
/* chipset specific changes to default for device-hba resets */
void
(
*
pre_reset
)(
ide_drive_t
*
);
/* routine to reset controller after a disk reset */
void
(
*
resetproc
)(
ide_drive_t
*
);
/* special interrupt handling for shared pci interrupts */
void
(
*
intrproc
)(
ide_drive_t
*
);
/* special host masking for drive selection */
void
(
*
maskproc
)(
ide_drive_t
*
,
int
);
/* check host's drive quirk list */
int
(
*
quirkproc
)(
ide_drive_t
*
);
/* driver soft-power interface */
int
(
*
busproc
)(
ide_drive_t
*
,
int
);
// /* host rate limiter */
// u8 (*ratemask)(ide_drive_t *);
// /* device rate limiter */
// u8 (*ratefilter)(ide_drive_t *, u8);
#endif
#if 0
ide_pio_ops_t *pioops;
#else
void
(
*
ata_input_data
)(
ide_drive_t
*
,
void
*
,
u32
);
void
(
*
ata_output_data
)(
ide_drive_t
*
,
void
*
,
u32
);
void
(
*
atapi_input_bytes
)(
ide_drive_t
*
,
void
*
,
u32
);
void
(
*
atapi_output_bytes
)(
ide_drive_t
*
,
void
*
,
u32
);
#endif
#if 0
ide_dma_ops_t *dmaops;
#else
int
(
*
ide_dma_read
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_write
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_begin
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_end
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_check
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_on
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_off
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_off_quietly
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_test_irq
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_host_on
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_host_off
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_bad_drive
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_good_drive
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_count
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_verbose
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_retune
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_lostirq
)(
ide_drive_t
*
drive
);
int
(
*
ide_dma_timeout
)(
ide_drive_t
*
drive
);
#endif
#if 0
ide_io_ops_t *iops;
#else
void
(
*
OUTB
)(
u8
addr
,
u32
port
);
void
(
*
OUTW
)(
u16
addr
,
u32
port
);
void
(
*
OUTL
)(
u32
addr
,
u32
port
);
void
(
*
OUTBP
)(
u8
addr
,
u32
port
);
void
(
*
OUTWP
)(
u16
addr
,
u32
port
);
void
(
*
OUTLP
)(
u32
addr
,
u32
port
);
void
(
*
OUTSW
)(
u32
port
,
void
*
addr
,
u32
count
);
void
(
*
OUTSWP
)(
u32
port
,
void
*
addr
,
u32
count
);
void
(
*
OUTSL
)(
u32
port
,
void
*
addr
,
u32
count
);
void
(
*
OUTSLP
)(
u32
port
,
void
*
addr
,
u32
count
);
u8
(
*
INB
)(
u32
port
);
u16
(
*
INW
)(
u32
port
);
u32
(
*
INL
)(
u32
port
);
u8
(
*
INBP
)(
u32
port
);
u16
(
*
INWP
)(
u32
port
);
u32
(
*
INLP
)(
u32
port
);
void
(
*
INSW
)(
u32
port
,
void
*
addr
,
u32
count
);
void
(
*
INSWP
)(
u32
port
,
void
*
addr
,
u32
count
);
void
(
*
INSL
)(
u32
port
,
void
*
addr
,
u32
count
);
void
(
*
INSLP
)(
u32
port
,
void
*
addr
,
u32
count
);
#endif
/* dma physical region descriptor table (cpu view) */
unsigned
int
*
dmatable_cpu
;
/* dma physical region descriptor table (dma view) */
dma_addr_t
dmatable_dma
;
/* Scatter-gather list used to build the above */
struct
scatterlist
*
sg_table
;
int
sg_nents
;
/* Current number of entries in it */
int
sg_dma_direction
;
/* dma transfer direction */
int
sg_dma_active
;
/* is it in use */
struct
hwif_s
*
mate
;
/* other hwif from same PCI chip */
int
mmio
;
/* hosts iomio (0), mmio (1) or custom (2) select */
int
rqsize
;
/* max sectors per request */
int
addressing
;
/* hosts addressing */
int
irq
;
/* our irq number */
int
initializing
;
/* set while initializing self */
unsigned
long
dma_master
;
/* reference base addr dmabase */
unsigned
long
dma_base
;
/* base addr for dma ports */
unsigned
long
dma_command
;
/* dma command register */
unsigned
long
dma_vendor1
;
/* dma vendor 1 register */
unsigned
long
dma_status
;
/* dma status register */
unsigned
long
dma_vendor3
;
/* dma vendor 3 register */
unsigned
long
dma_prdtable
;
/* actual prd table address */
unsigned
long
dma_base2
;
/* extended base addr for dma ports */
unsigned
dma_extra
;
/* extra addr for dma ports */
unsigned
long
config_data
;
/* for use by chipset-specific code */
unsigned
long
select_data
;
/* for use by chipset-specific code */
struct
proc_dir_entry
*
proc
;
/* /proc/ide/ directory entry */
int
irq
;
/* our irq number */
byte
major
;
/* our major number */
char
name
[
6
];
/* name of interface, eg. "ide0" */
byte
index
;
/* 0 for ide0; 1 for ide1; ... */
hwif_chipset_t
chipset
;
/* sub-module for tuning.. */
#if (DISK_RECOVERY_TIME > 0)
unsigned
long
last_time
;
/* time when previous rq was done */
#endif
unsigned
noprobe
:
1
;
/* don't probe for this interface */
unsigned
present
:
1
;
/* this interface exists */
unsigned
serialized
:
1
;
/* serialized
operation with mate hwif
*/
unsigned
serialized
:
1
;
/* serialized
all channel operation
*/
unsigned
sharing_irq
:
1
;
/* 1 = sharing irq with another hwif */
unsigned
reset
:
1
;
/* reset after probe */
unsigned
autodma
:
1
;
/* auto
matically try to enable
DMA at boot */
unsigned
autodma
:
1
;
/* auto
-attempt using
DMA at boot */
unsigned
udma_four
:
1
;
/* 1=ATA-66 capable, 0=default */
unsigned
no_highmem
:
1
;
/* always use high i/o bounce */
byte
channel
;
/* for dual-port chips: 0=primary, 1=secondary */
#ifdef CONFIG_BLK_DEV_IDEPCI
struct
pci_dev
*
pci_dev
;
/* for pci chipsets */
ide_pci_devid_t
pci_devid
;
/* for pci chipsets: {VID,DID} */
#endif
/* CONFIG_BLK_DEV_IDEPCI */
#if (DISK_RECOVERY_TIME > 0)
unsigned
long
last_time
;
/* time when previous rq was done */
#endif
byte
straight8
;
/* Alan's straight 8 check */
unsigned
highmem
:
1
;
/* can do full 32-bit dma */
unsigned
no_dsc
:
1
;
/* 0 default, 1 dsc_overlap disabled */
void
*
hwif_data
;
/* extra hwif data */
byte
bus_state
;
/* power state of the IDE bus */
}
ide_hwif_t
;
/*
...
...
@@ -769,7 +1082,7 @@ typedef struct hwif_s {
*/
typedef
enum
{
ide_stopped
,
/* no drive operation was started */
ide_started
/* a drive operation was started,
and a
handler was set */
ide_started
/* a drive operation was started, handler was set */
}
ide_startstop_t
;
/*
...
...
@@ -778,26 +1091,41 @@ typedef enum {
typedef
ide_startstop_t
(
ide_pre_handler_t
)(
ide_drive_t
*
,
struct
request
*
);
typedef
ide_startstop_t
(
ide_handler_t
)(
ide_drive_t
*
);
typedef
ide_startstop_t
(
ide_post_handler_t
)(
ide_drive_t
*
);
/*
* when ide_timer_expiry fires, invoke a handler of this type
* to decide what to do.
*/
typedef
int
(
ide_expiry_t
)(
ide_drive_t
*
);
typedef
struct
hwgroup_s
{
ide_handler_t
*
handler
;
/* irq handler, if active */
ide_handler_t
*
handler_save
;
/* irq handler, if active */
volatile
int
busy
;
/* BOOL: protects all fields below */
int
sleeping
;
/* BOOL: wake us up on timer expiry */
ide_drive_t
*
drive
;
/* current drive */
ide_hwif_t
*
hwif
;
/* ptr to current hwif in linked-list */
struct
request
*
rq
;
/* current request */
struct
timer_list
timer
;
/* failsafe timer */
struct
request
wrq
;
/* local copy of current write rq */
unsigned
long
poll_timeout
;
/* timeout value during long polls */
ide_expiry_t
*
expiry
;
/* queried upon timeouts */
int
pio_clock
;
/* ide_system_bus_speed */
/* irq handler, if active */
ide_startstop_t
(
*
handler
)(
ide_drive_t
*
);
/* irq handler, suspended if active */
ide_startstop_t
(
*
handler_save
)(
ide_drive_t
*
);
/* BOOL: protects all fields below */
volatile
int
busy
;
/* BOOL: wake us up on timer expiry */
int
sleeping
;
/* current drive */
ide_drive_t
*
drive
;
/* ptr to current hwif in linked-list */
ide_hwif_t
*
hwif
;
#ifdef CONFIG_BLK_DEV_IDEPCI
/* for pci chipsets */
struct
pci_dev
*
pci_dev
;
/* chipset device struct */
struct
ide_pci_device_s
*
cds
;
#endif
/* CONFIG_BLK_DEV_IDEPCI */
/* current request */
struct
request
*
rq
;
/* failsafe timer */
struct
timer_list
timer
;
/* local copy of current write rq */
struct
request
wrq
;
/* timeout value during long polls */
unsigned
long
poll_timeout
;
/* queried upon timeouts */
int
(
*
expiry
)(
ide_drive_t
*
);
/* ide_system_bus_speed */
int
pio_clock
;
}
ide_hwgroup_t
;
/* structure attached to the request for IDE_TASK_CMDS */
...
...
@@ -850,14 +1178,14 @@ typedef struct {
}
ide_proc_entry_t
;
#ifdef CONFIG_PROC_FS
void
proc_ide_create
(
void
);
void
proc_ide_destroy
(
void
);
void
recreate_proc_ide_device
(
ide_hwif_t
*
,
ide_drive_t
*
);
void
destroy_proc_ide_device
(
ide_hwif_t
*
,
ide_drive_t
*
);
void
destroy_proc_ide_drives
(
ide_hwif_t
*
);
void
create_proc_ide_interfaces
(
void
);
void
ide_add_proc_entries
(
struct
proc_dir_entry
*
dir
,
ide_proc_entry_t
*
p
,
void
*
data
);
void
ide_remove_proc_entries
(
struct
proc_dir_entry
*
dir
,
ide_proc_entry_t
*
p
);
extern
void
proc_ide_create
(
void
);
extern
void
proc_ide_destroy
(
void
);
extern
void
recreate_proc_ide_device
(
ide_hwif_t
*
,
ide_drive_t
*
);
extern
void
destroy_proc_ide_device
(
ide_hwif_t
*
,
ide_drive_t
*
);
extern
void
destroy_proc_ide_drives
(
ide_hwif_t
*
);
extern
void
create_proc_ide_interfaces
(
void
);
extern
void
ide_add_proc_entries
(
struct
proc_dir_entry
*
,
ide_proc_entry_t
*
,
void
*
);
extern
void
ide_remove_proc_entries
(
struct
proc_dir_entry
*
,
ide_proc_entry_t
*
);
read_proc_t
proc_ide_read_capacity
;
read_proc_t
proc_ide_read_geometry
;
...
...
@@ -889,7 +1217,7 @@ typedef struct ide_driver_s {
struct
module
*
owner
;
const
char
*
name
;
const
char
*
version
;
byte
media
;
u8
media
;
unsigned
busy
:
1
;
unsigned
supports_dma
:
1
;
unsigned
supports_dsc_overlap
:
1
;
...
...
@@ -899,9 +1227,9 @@ typedef struct ide_driver_s {
int
(
*
resume
)(
ide_drive_t
*
);
int
(
*
flushcache
)(
ide_drive_t
*
);
ide_startstop_t
(
*
do_request
)(
ide_drive_t
*
,
struct
request
*
,
unsigned
long
);
int
(
*
end_request
)(
ide_drive_t
*
,
int
);
byte
(
*
sense
)(
ide_drive_t
*
,
const
char
*
,
byte
);
ide_startstop_t
(
*
error
)(
ide_drive_t
*
,
const
char
*
,
byte
);
int
(
*
end_request
)(
ide_drive_t
*
,
int
,
int
);
u8
(
*
sense
)(
ide_drive_t
*
,
const
char
*
,
u8
);
ide_startstop_t
(
*
error
)(
ide_drive_t
*
,
const
char
*
,
u8
);
int
(
*
ioctl
)(
ide_drive_t
*
,
struct
inode
*
,
struct
file
*
,
unsigned
int
,
unsigned
long
);
int
(
*
open
)(
struct
inode
*
,
struct
file
*
,
ide_drive_t
*
);
void
(
*
release
)(
struct
inode
*
,
struct
file
*
,
ide_drive_t
*
);
...
...
@@ -910,8 +1238,8 @@ typedef struct ide_driver_s {
void
(
*
pre_reset
)(
ide_drive_t
*
);
unsigned
long
(
*
capacity
)(
ide_drive_t
*
);
ide_startstop_t
(
*
special
)(
ide_drive_t
*
);
ide_proc_entry_t
*
proc
;
int
(
*
reinit
)(
ide_drive_t
*
);
ide_proc_entry_t
*
proc
;
int
(
*
attach
)(
ide_drive_t
*
);
void
(
*
ata_prebuilder
)(
ide_drive_t
*
);
void
(
*
atapi_prebuilder
)(
ide_drive_t
*
);
struct
list_head
drives
;
...
...
@@ -935,6 +1263,13 @@ typedef struct ide_module_s {
struct
ide_module_s
*
next
;
}
ide_module_t
;
typedef
struct
ide_devices_s
{
char
name
[
4
];
/* hdX */
unsigned
attached
:
1
;
/* native */
unsigned
alttached
:
1
;
/* alternate */
struct
ide_devices_s
*
next
;
}
ide_devices_t
;
/*
* ide_hwifs[] is the master data structure used to keep track
* of just about everything in ide.c. Whenever possible, routines
...
...
@@ -945,7 +1280,15 @@ typedef struct ide_module_s {
*/
#ifndef _IDE_C
extern
ide_hwif_t
ide_hwifs
[];
/* master data repository */
extern
ide_module_t
*
ide_chipsets
;
extern
ide_module_t
*
ide_probe
;
extern
ide_devices_t
*
idedisk
;
extern
ide_devices_t
*
idecd
;
extern
ide_devices_t
*
idefloppy
;
extern
ide_devices_t
*
idetape
;
extern
ide_devices_t
*
idescsi
;
#endif
extern
int
noautodma
;
...
...
@@ -957,38 +1300,47 @@ extern int noautodma;
#define DEVICE_NR(device) (minor(device) >> PARTN_BITS)
#include <linux/blk.h>
int
ide_end_request
(
ide_drive_t
*
drive
,
int
uptodate
);
extern
int
ide_end_request
(
ide_drive_t
*
drive
,
int
uptodate
,
int
nrsecs
);
/*
* This is used on exit from the driver, to designate the next irq handler
* and also to start the safety timer.
*/
void
ide_set_handler
(
ide_drive_t
*
drive
,
ide_handler_t
*
handler
,
unsigned
int
timeout
,
ide_expiry_t
*
expiry
);
extern
void
ide_set_handler
(
ide_drive_t
*
drive
,
ide_handler_t
*
handler
,
unsigned
int
timeout
,
ide_expiry_t
*
expiry
);
/*
* Error reporting, in human readable form (luxurious, but a memory hog).
*
* (drive, msg, status)
*/
byte
ide_dump_status
(
ide_drive_t
*
drive
,
const
char
*
msg
,
byte
stat
);
/*
* ide_error() takes action based on the error returned by the controller.
* The caller should return immediately after invoking this.
*
* (drive, msg, status)
*/
ide_startstop_t
ide_error
(
ide_drive_t
*
drive
,
const
char
*
msg
,
byte
stat
);
/*
* Issue a simple drive command
* The drive must be selected beforehand.
*
* (drive, command, nsector, handler)
*/
void
ide_cmd
(
ide_drive_t
*
drive
,
byte
cmd
,
byte
nsect
,
ide_handler_t
*
handler
);
extern
void
ide_cmd
(
ide_drive_t
*
,
u8
,
u8
,
ide_handler_t
*
);
extern
void
ide_fix_driveid
(
struct
hd_driveid
*
);
/*
* ide_fixstring() cleans up and (optionally) byte-swaps a text string,
* removing leading/trailing blanks and compressing internal blanks.
* It is primarily used to tidy up the model name/number fields as
* returned by the WIN_[P]IDENTIFY commands.
*
* (s, bytecount, byteswap)
*/
void
ide_fixstring
(
byte
*
s
,
const
int
bytecount
,
const
int
byteswap
);
extern
void
ide_fixstring
(
u8
*
,
const
int
,
const
int
);
/*
* This routine busy-waits for the drive status to be not "busy".
...
...
@@ -997,43 +1349,44 @@ void ide_fixstring (byte *s, const int bytecount, const int byteswap);
* cases return 1 after doing "*startstop = ide_error()", and the
* caller should return the updated value of "startstop" in this case.
* "startstop" is unchanged when the function returns 0;
* (startstop, drive, good, bad, timeout)
*/
int
ide_wait_stat
(
ide_startstop_t
*
startstop
,
ide_drive_t
*
drive
,
byte
good
,
byte
bad
,
unsigned
long
timeout
);
extern
int
ide_wait_stat
(
ide_startstop_t
*
,
ide_drive_t
*
,
u8
,
u8
,
unsigned
long
);
/*
* This routine is called from the partition-table code in genhd.c
* to "convert" a drive to a logical geometry with fewer than 1024 cyls.
*/
int
ide_xlate_1024
(
kdev_t
,
int
,
int
,
const
char
*
);
extern
int
ide_xlate_1024
(
kdev_t
,
int
,
int
,
const
char
*
);
/*
* Convert kdev_t structure into ide_drive_t * one.
*/
ide_drive_t
*
get_info_ptr
(
kdev_t
i_rdev
);
extern
ide_drive_t
*
get_info_ptr
(
kdev_t
i_rdev
);
/*
* Return the current idea about the total capacity of this drive.
*/
unsigned
long
current_capacity
(
ide_drive_t
*
drive
);
extern
unsigned
long
current_capacity
(
ide_drive_t
*
drive
);
void
ide_revalidate_drive
(
ide_drive_t
*
drive
);
extern
void
ide_revalidate_drive
(
ide_drive_t
*
drive
);
/*
* Start a reset operation for an IDE interface.
* The caller should return immediately after invoking this.
*/
ide_startstop_t
ide_do_reset
(
ide_drive_t
*
);
extern
ide_startstop_t
ide_do_reset
(
ide_drive_t
*
);
/*
* Re-Start an operation for an IDE interface.
* The caller should return immediately after invoking this.
*/
int
restart_request
(
ide_drive_t
*
,
struct
request
*
);
extern
int
restart_request
(
ide_drive_t
*
,
struct
request
*
);
/*
* This function is intended to be used prior to invoking ide_do_drive_cmd().
*/
void
ide_init_drive_cmd
(
struct
request
*
rq
);
extern
void
ide_init_drive_cmd
(
struct
request
*
rq
);
/*
* "action" parameter type for ide_do_drive_cmd() below.
...
...
@@ -1070,23 +1423,35 @@ typedef enum {
* for the new rq to be completed. This is again intended for careful
* use by the ATAPI tape/cdrom driver code.
*/
int
ide_do_drive_cmd
(
ide_drive_t
*
drive
,
struct
request
*
rq
,
ide_action_t
action
);
extern
int
ide_do_drive_cmd
(
ide_drive_t
*
,
struct
request
*
,
ide_action_t
);
/*
* Clean up after success/failure of an explicit drive cmd.
* stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD).
* stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASK_MASK).
*
* (ide_drive_t *drive, u8 stat, u8 err)
*/
void
ide_end_drive_cmd
(
ide_drive_t
*
drive
,
byte
stat
,
byte
err
);
extern
void
ide_end_drive_cmd
(
ide_drive_t
*
,
u8
,
u8
);
/*
* Issue ATA command and wait for completion. use for implementing commands in kernel
* Issue ATA command and wait for completion.
* Use for implementing commands in kernel
*
* (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf)
*/
int
ide_wait_cmd
(
ide_drive_t
*
drive
,
int
cmd
,
int
nsect
,
int
feature
,
int
sectors
,
byte
*
buf
);
extern
int
ide_wait_cmd
(
ide_drive_t
*
,
u8
,
u8
,
u8
,
u8
,
u8
*
);
/* (ide_drive_t *drive, u8 *buf) */
extern
int
ide_wait_cmd_task
(
ide_drive_t
*
,
u8
*
);
int
ide_wait_cmd_task
(
ide_drive_t
*
drive
,
byte
*
buf
);
typedef
struct
ide_task_s
{
/*
* struct hd_drive_task_hdr tf;
* task_struct_t tf;
* struct hd_drive_hob_hdr hobf;
* hob_struct_t hobf;
*/
task_ioreg_t
tfRegister
[
8
];
task_ioreg_t
hobRegister
[
8
];
ide_reg_valid_t
tf_out_flags
;
...
...
@@ -1101,6 +1466,11 @@ typedef struct ide_task_s {
}
ide_task_t
;
typedef
struct
pkt_task_s
{
/*
* struct hd_drive_task_hdr pktf;
* task_struct_t pktf;
* u8 pkcdb[12];
*/
task_ioreg_t
tfRegister
[
8
];
int
data_phase
;
int
command_type
;
...
...
@@ -1109,66 +1479,129 @@ typedef struct pkt_task_s {
void
*
special
;
}
pkt_task_t
;
void
ata_input_data
(
ide_drive_t
*
drive
,
void
*
buffer
,
unsigned
int
wcount
);
void
ata_output_data
(
ide_drive_t
*
drive
,
void
*
buffer
,
unsigned
int
wcount
);
void
atapi_input_bytes
(
ide_drive_t
*
drive
,
void
*
buffer
,
unsigned
int
bytecount
);
void
atapi_output_bytes
(
ide_drive_t
*
drive
,
void
*
buffer
,
unsigned
int
bytecount
);
void
taskfile_input_data
(
ide_drive_t
*
drive
,
void
*
buffer
,
unsigned
int
wcount
);
void
taskfile_output_data
(
ide_drive_t
*
drive
,
void
*
buffer
,
unsigned
int
wcount
);
extern
inline
void
SELECT_DRIVE
(
ide_drive_t
*
);
extern
inline
void
SELECT_INTERRUPT
(
ide_drive_t
*
);
extern
inline
void
SELECT_MASK
(
ide_drive_t
*
,
int
);
extern
inline
void
QUIRK_LIST
(
ide_drive_t
*
);
int
drive_is_ready
(
ide_drive_t
*
drive
);
int
wait_for_ready
(
ide_drive_t
*
drive
,
int
timeout
);
extern
void
ata_input_data
(
ide_drive_t
*
,
void
*
,
u32
);
extern
void
ata_output_data
(
ide_drive_t
*
,
void
*
,
u32
);
extern
void
atapi_input_bytes
(
ide_drive_t
*
,
void
*
,
u32
);
extern
void
atapi_output_bytes
(
ide_drive_t
*
,
void
*
,
u32
);
extern
void
taskfile_input_data
(
ide_drive_t
*
,
void
*
,
u32
);
extern
void
taskfile_output_data
(
ide_drive_t
*
,
void
*
,
u32
);
extern
int
drive_is_ready
(
ide_drive_t
*
);
extern
int
wait_for_ready
(
ide_drive_t
*
,
int
/* timeout */
);
/*
* taskfile io for disks for now...and builds request from ide_ioctl
*/
ide_startstop_t
do_rw_taskfile
(
ide_drive_t
*
drive
,
ide_task_t
*
task
);
extern
ide_startstop_t
do_rw_taskfile
(
ide_drive_t
*
,
ide_task_t
*
);
void
ide_end_taskfile
(
ide_drive_t
*
drive
,
byte
stat
,
byte
err
);
/* (ide_drive_t *drive, u8 stat, u8 err) */
extern
void
ide_end_taskfile
(
ide_drive_t
*
,
u8
,
u8
);
/*
* Special Flagged Register Validation Caller
*/
ide_startstop_t
flagged_taskfile
(
ide_drive_t
*
drive
,
ide_task_t
*
task
);
ide_startstop_t
set_multmode_intr
(
ide_drive_t
*
drive
);
ide_startstop_t
set_geometry_intr
(
ide_drive_t
*
drive
);
ide_startstop_t
recal_intr
(
ide_drive_t
*
drive
);
ide_startstop_t
task_no_data_intr
(
ide_drive_t
*
drive
);
ide_startstop_t
task_in_intr
(
ide_drive_t
*
drive
);
ide_startstop_t
task_mulin_intr
(
ide_drive_t
*
drive
);
ide_startstop_t
pre_task_out_intr
(
ide_drive_t
*
drive
,
struct
request
*
rq
);
ide_startstop_t
task_out_intr
(
ide_drive_t
*
drive
);
ide_startstop_t
pre_task_mulout_intr
(
ide_drive_t
*
drive
,
struct
request
*
rq
);
ide_startstop_t
task_mulout_intr
(
ide_drive_t
*
drive
);
void
ide_init_drive_taskfile
(
struct
request
*
rq
);
int
ide_raw_taskfile
(
ide_drive_t
*
drive
,
ide_task_t
*
cmd
,
byte
*
buf
);
ide_pre_handler_t
*
ide_pre_handler_parser
(
struct
hd_drive_task_hdr
*
taskfile
,
struct
hd_drive_hob_hdr
*
hobfile
);
ide_handler_t
*
ide_handler_parser
(
struct
hd_drive_task_hdr
*
taskfile
,
struct
hd_drive_hob_hdr
*
hobfile
);
ide_post_handler_t
*
ide_post_handler_parser
(
struct
hd_drive_task_hdr
*
taskfile
,
struct
hd_drive_hob_hdr
*
hobfile
);
extern
ide_startstop_t
flagged_taskfile
(
ide_drive_t
*
,
ide_task_t
*
);
extern
ide_startstop_t
set_multmode_intr
(
ide_drive_t
*
);
extern
ide_startstop_t
set_geometry_intr
(
ide_drive_t
*
);
extern
ide_startstop_t
recal_intr
(
ide_drive_t
*
);
extern
ide_startstop_t
task_no_data_intr
(
ide_drive_t
*
);
extern
ide_startstop_t
task_in_intr
(
ide_drive_t
*
);
extern
ide_startstop_t
task_mulin_intr
(
ide_drive_t
*
);
extern
ide_startstop_t
pre_task_out_intr
(
ide_drive_t
*
,
struct
request
*
);
extern
ide_startstop_t
task_out_intr
(
ide_drive_t
*
);
extern
ide_startstop_t
pre_task_mulout_intr
(
ide_drive_t
*
,
struct
request
*
);
extern
ide_startstop_t
task_mulout_intr
(
ide_drive_t
*
);
extern
void
ide_init_drive_taskfile
(
struct
request
*
);
extern
int
ide_raw_taskfile
(
ide_drive_t
*
,
ide_task_t
*
,
u8
*
);
extern
ide_pre_handler_t
*
ide_pre_handler_parser
(
struct
hd_drive_task_hdr
*
,
struct
hd_drive_hob_hdr
*
);
extern
ide_handler_t
*
ide_handler_parser
(
struct
hd_drive_task_hdr
*
,
struct
hd_drive_hob_hdr
*
);
extern
ide_post_handler_t
*
ide_post_handler_parser
(
struct
hd_drive_task_hdr
*
,
struct
hd_drive_hob_hdr
*
);
/* Expects args is a full set of TF registers and parses the command type */
int
ide_cmd_type_parser
(
ide_task_t
*
args
);
extern
int
ide_cmd_type_parser
(
ide_task_t
*
);
int
ide_taskfile_ioctl
(
ide_drive_t
*
,
struct
inode
*
,
struct
file
*
,
unsigned
int
,
unsigned
long
);
int
ide_cmd_ioctl
(
ide_drive_t
*
,
struct
inode
*
,
struct
file
*
,
unsigned
int
,
unsigned
long
);
int
ide_task_ioctl
(
ide_drive_t
*
,
struct
inode
*
,
struct
file
*
,
unsigned
int
,
unsigned
long
);
#if 0
#define IDEFLOPPY_PC_BUFFER_SIZE 256
#define IDETAPE_PC_BUFFER_SIZE 256
#define IDE_PC_BUFFER_SIZE 256
typedef struct ide_packet_command_s {
/* Actual packet bytes */
u8 c[12];
/* On each retry, we increment retries */
int retries;
/* Error code */
int error;
/* Bytes to transfer */
int request_transfer;
/* Bytes actually transferred */
int actually_transferred;
/* Size of our data buffer */
int buffer_size;
struct buffer_head *bh;
u8 *b_data;
/* The corresponding request */
struct request *rq;
# if 0
/* Scatter gather table */
struct scatterlist *sg;
# endif
int
b_count
;
/* Data buffer */
u8
*
buffer
;
/* Pointer into the above buffer */
u8
*
current_position
;
/* Called when this packet command is completed */
ide_startstop_t
(
*
callback
)
(
ide_drive_t
*
);
/* Temporary buffer */
u8
pc_buffer
[
IDE_PC_BUFFER_SIZE
];
/* Status/Action bit flags: long for set_bit */
unsigned
long
flags
;
}
ide_pc_t
;
ide
-
cd
orthoginal
:-/
struct
packet_command
{
char
*
buffer
;
int
buflen
;
int
stat
;
int
quiet
;
int
timeout
;
struct
request_sense
*
sense
;
unsigned
char
c
[
12
];
};
int
ide_taskfile_ioctl
(
ide_drive_t
*
drive
,
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
);
int
ide_cmd_ioctl
(
ide_drive_t
*
drive
,
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
);
int
ide_task_ioctl
(
ide_drive_t
*
drive
,
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
);
#endif
#ifdef CONFIG_PKT_TASK_IOCTL
int
pkt_taskfile_ioctl
(
ide_drive_t
*
drive
,
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
ar
g
);
extern
int
pkt_taskfile_ioctl
(
ide_drive_t
*
,
struct
inode
*
,
struct
file
*
,
unsigned
int
,
unsigned
lon
g
);
#endif
/* CONFIG_PKT_TASK_IOCTL */
void
ide_delay_50ms
(
void
);
int
system_bus_clock
(
void
);
extern
void
ide_delay_50ms
(
void
);
extern
int
system_bus_clock
(
void
);
byte
ide_auto_reduce_xfer
(
ide_drive_t
*
drive
);
int
ide_driveid_update
(
ide_drive_t
*
drive
);
int
ide_ata66_check
(
ide_drive_t
*
drive
,
ide_task_t
*
args
);
int
ide_config_drive_speed
(
ide_drive_t
*
drive
,
byte
speed
);
byte
eighty_ninty_three
(
ide_drive_t
*
drive
);
int
set_transfer
(
ide_drive_t
*
drive
,
ide_task_t
*
args
);
int
taskfile_lib_get_identify
(
ide_drive_t
*
drive
,
byte
*
buf
);
extern
u8
ide_auto_reduce_xfer
(
ide_drive_t
*
);
extern
int
ide_driveid_update
(
ide_drive_t
*
);
extern
int
ide_ata66_check
(
ide_drive_t
*
,
ide_task_t
*
);
extern
int
ide_config_drive_speed
(
ide_drive_t
*
,
u8
);
extern
u8
eighty_ninty_three
(
ide_drive_t
*
);
extern
int
set_transfer
(
ide_drive_t
*
,
ide_task_t
*
);
extern
int
taskfile_lib_get_identify
(
ide_drive_t
*
drive
,
u8
*
);
/*
* ide_system_bus_speed() returns what we think is the system VESA/PCI
...
...
@@ -1176,45 +1609,55 @@ int taskfile_lib_get_identify (ide_drive_t *drive, byte *buf);
* The default is 40 for known PCI systems, 50 otherwise.
* The "idebus=xx" parameter can be used to override this value.
*/
int
ide_system_bus_speed
(
void
);
extern
int
ide_system_bus_speed
(
void
);
/*
* ide_stall_queue() can be used by a drive to give excess bandwidth back
* to the hwgroup by sleeping for timeout jiffies.
*/
void
ide_stall_queue
(
ide_drive_t
*
drive
,
unsigned
long
timeout
);
extern
void
ide_stall_queue
(
ide_drive_t
*
drive
,
unsigned
long
timeout
);
/*
* ide_get_queue() returns the queue which corresponds to a given device.
*/
request_queue_t
*
ide_get_queue
(
kdev_t
dev
);
extern
request_queue_t
*
ide_get_queue
(
kdev_t
dev
);
/*
* CompactFlash cards and their brethern pretend to be removable hard disks,
* but they never have a slave unit, and they don't have doorlock mechanisms.
* This test catches them, and is invoked elsewhere when setting appropriate config bits.
* This test catches them, and is invoked elsewhere when setting appropriate
* config bits.
*/
int
drive_is_flashcard
(
ide_drive_t
*
drive
);
extern
int
drive_is_flashcard
(
ide_drive_t
*
drive
);
int
ide_spin_wait_hwgroup
(
ide_drive_t
*
drive
);
void
ide_timer_expiry
(
unsigned
long
data
);
void
ide_intr
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
);
void
do_ide_request
(
request_queue_t
*
q
);
void
ide_init_subdrivers
(
void
);
extern
int
ide_spin_wait_hwgroup
(
ide_drive_t
*
);
extern
void
ide_timer_expiry
(
unsigned
long
);
extern
void
ide_intr
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
);
extern
void
do_ide_request
(
request_queue_t
*
);
extern
void
ide_init_subdrivers
(
void
);
#ifndef _IDE_C
extern
struct
block_device_operations
ide_fops
[];
extern
ide_proc_entry_t
generic_subdriver_entries
[];
#endif
int
ata_attach
(
ide_drive_t
*
drive
);
extern
int
ata_attach
(
ide_drive_t
*
);
#ifdef _IDE_C
#ifdef CONFIG_BLK_DEV_IDE
int
ideprobe_init
(
void
);
extern
int
ideprobe_init
(
void
);
#ifdef CONFIG_BLK_DEV_IDEPCI
extern
void
ide_scan_pcibus
(
int
scan_direction
)
__init
;
#endif
/* CONFIG_BLK_DEV_IDEPCI */
#endif
/* CONFIG_BLK_DEV_IDE */
#endif
/* _IDE_C */
extern
void
default_hwif_iops
(
ide_hwif_t
*
);
extern
void
default_hwif_mmiops
(
ide_hwif_t
*
);
extern
void
default_hwif_transport
(
ide_hwif_t
*
);
int
ide_register_driver
(
ide_driver_t
*
driver
);
void
ide_unregister_driver
(
ide_driver_t
*
driver
);
int
ide_register_subdriver
(
ide_drive_t
*
drive
,
ide_driver_t
*
driver
,
int
version
);
...
...
@@ -1222,85 +1665,113 @@ int ide_unregister_subdriver (ide_drive_t *drive);
int
ide_replace_subdriver
(
ide_drive_t
*
drive
,
const
char
*
driver
);
#ifdef CONFIG_BLK_DEV_IDEPCI
#ifdef CONFIG_PROC_FS
typedef
struct
ide_pci_host_proc_s
{
char
*
name
;
u8
set
;
get_info_t
*
get_info
;
struct
proc_dir_entry
*
parent
;
struct
ide_pci_host_proc_s
*
next
;
}
ide_pci_host_proc_t
;
void
ide_pci_register_host_proc
(
ide_pci_host_proc_t
*
);
#endif
/* CONFIG_PROC_FS */
#define ON_BOARD 1
#define NEVER_BOARD 0
#ifdef CONFIG_BLK_DEV_OFFBOARD
# define OFF_BOARD ON_BOARD
#else
/* CONFIG_BLK_DEV_OFFBOARD */
# define OFF_BOARD NEVER_BOARD
#endif
/* CONFIG_BLK_DEV_OFFBOARD */
#define NODMA 0
#define NOAUTODMA 1
#define AUTODMA 2
#define EOL 255
typedef
struct
ide_pci_enablebit_s
{
byte
reg
;
/* byte pci reg holding the enable-bit */
byte
mask
;
/* mask to isolate the enable-bit */
byte
val
;
/* value of masked reg when "enabled" */
u8
reg
;
/* byte pci reg holding the enable-bit */
u8
mask
;
/* mask to isolate the enable-bit */
u8
val
;
/* value of masked reg when "enabled" */
}
ide_pci_enablebit_t
;
typedef
struct
ide_pci_device_s
{
ide_pci_devid_t
devid
;
u16
vendor
;
u16
device
;
char
*
name
;
void
(
*
fixup_device
)(
struct
pci_dev
*
,
struct
ide_pci_device_s
*
);
void
(
*
init_setup
)(
struct
pci_dev
*
,
struct
ide_pci_device_s
*
);
unsigned
int
(
*
init_chipset
)(
struct
pci_dev
*
,
const
char
*
);
unsigned
int
(
*
ata66_check
)(
ide_hwif_t
*
);
void
(
*
init_hwif
)(
ide_hwif_t
*
);
void
(
*
dma_init
)(
ide_hwif_t
*
,
unsigned
long
);
void
(
*
init_iops
)(
ide_hwif_t
*
);
void
(
*
init_hwif
)(
ide_hwif_t
*
);
void
(
*
init_dma
)(
ide_hwif_t
*
,
unsigned
long
);
u8
channels
;
u8
autodma
;
ide_pci_enablebit_t
enablebits
[
2
];
byte
bootable
;
u8
bootable
;
unsigned
int
extra
;
struct
ide_pci_device_s
*
next
;
}
ide_pci_device_t
;
#ifdef LINUX_PCI_H
extern
inline
void
ide_register_xp_fix
(
struct
pci_dev
*
dev
)
{
int
i
;
unsigned
short
cmd
;
unsigned
long
flags
;
unsigned
long
base_address
[
4
]
=
{
0x1f0
,
0x3f4
,
0x170
,
0x374
};
local_irq_save
(
flags
);
pci_read_config_word
(
dev
,
PCI_COMMAND
,
&
cmd
);
pci_write_config_word
(
dev
,
PCI_COMMAND
,
cmd
&
~
PCI_COMMAND_IO
);
for
(
i
=
0
;
i
<
4
;
i
++
)
{
dev
->
resource
[
i
].
start
=
0
;
dev
->
resource
[
i
].
end
=
0
;
dev
->
resource
[
i
].
flags
=
0
;
}
for
(
i
=
0
;
i
<
4
;
i
++
)
{
dev
->
resource
[
i
].
start
=
base_address
[
i
];
dev
->
resource
[
i
].
flags
|=
PCI_BASE_ADDRESS_SPACE_IO
;
pci_write_config_dword
(
dev
,
(
PCI_BASE_ADDRESS_0
+
(
i
*
4
)),
dev
->
resource
[
i
].
start
);
}
pci_write_config_word
(
dev
,
PCI_COMMAND
,
cmd
);
local_irq_restore
(
flags
);
}
void
ide_setup_pci_device
(
struct
pci_dev
*
dev
,
ide_pci_device_t
*
d
)
__init
;
extern
void
ide_setup_pci_device
(
struct
pci_dev
*
,
ide_pci_device_t
*
);
extern
void
ide_setup_pci_devices
(
struct
pci_dev
*
,
struct
pci_dev
*
,
ide_pci_device_t
*
);
#endif
/* LINUX_PCI_H */
unsigned
long
ide_find_free_region
(
unsigned
short
size
)
__init
;
void
ide_scan_pcibus
(
int
scan_direction
)
__init
;
#endif
#endif
/* CONFIG_BLK_DEV_IDEPCI */
#ifdef CONFIG_BLK_DEV_IDEDMA
#define BAD_DMA_DRIVE 0
#define GOOD_DMA_DRIVE 1
int
ide_build_dmatable
(
ide_drive_t
*
drive
,
ide_dma_action_t
func
);
void
ide_destroy_dmatable
(
ide_drive_t
*
drive
);
ide_startstop_t
ide_dma_intr
(
ide_drive_t
*
drive
);
int
check_drive_lists
(
ide_drive_t
*
drive
,
int
good_bad
);
int
report_drive_dmaing
(
ide_drive_t
*
drive
);
int
ide_dmaproc
(
ide_dma_action_t
func
,
ide_drive_t
*
drive
);
int
ide_release_dma
(
ide_hwif_t
*
hwif
);
void
ide_setup_dma
(
ide_hwif_t
*
hwif
,
unsigned
long
dmabase
,
unsigned
int
num_ports
)
__init
;
unsigned
long
ide_get_or_set_dma_base
(
ide_hwif_t
*
hwif
,
int
extra
,
const
char
*
name
)
__init
;
#endif
/* CONFIG_BLK_DEV_IDEPCI */
extern
int
ide_build_dmatable
(
ide_drive_t
*
,
struct
request
*
);
extern
void
ide_destroy_dmatable
(
ide_drive_t
*
);
extern
ide_startstop_t
ide_dma_intr
(
ide_drive_t
*
);
extern
int
ide_release_dma
(
ide_hwif_t
*
);
extern
void
ide_setup_dma
(
ide_hwif_t
*
,
unsigned
long
,
unsigned
int
);
extern
int
__ide_dma_host_off
(
ide_drive_t
*
);
extern
int
__ide_dma_off_quietly
(
ide_drive_t
*
);
extern
int
__ide_dma_off
(
ide_drive_t
*
);
extern
int
__ide_dma_host_on
(
ide_drive_t
*
);
extern
int
__ide_dma_on
(
ide_drive_t
*
);
extern
int
__ide_dma_check
(
ide_drive_t
*
);
extern
int
__ide_dma_read
(
ide_drive_t
*
);
extern
int
__ide_dma_write
(
ide_drive_t
*
);
extern
int
__ide_dma_begin
(
ide_drive_t
*
);
extern
int
__ide_dma_end
(
ide_drive_t
*
);
extern
int
__ide_dma_test_irq
(
ide_drive_t
*
);
extern
int
__ide_dma_bad_drive
(
ide_drive_t
*
);
extern
int
__ide_dma_good_drive
(
ide_drive_t
*
);
extern
int
__ide_dma_count
(
ide_drive_t
*
);
extern
int
__ide_dma_verbose
(
ide_drive_t
*
);
extern
int
__ide_dma_retune
(
ide_drive_t
*
);
extern
int
__ide_dma_lostirq
(
ide_drive_t
*
);
extern
int
__ide_dma_timeout
(
ide_drive_t
*
);
#endif
/* CONFIG_BLK_DEV_IDEDMA */
extern
void
hwif_unregister
(
ide_hwif_t
*
);
extern
void
export_ide_init_queue
(
ide_drive_t
*
);
extern
u8
export_probe_for_drive
(
ide_drive_t
*
);
extern
int
probe_hwif_init
(
ide_hwif_t
*
);
static
inline
void
*
ide_get_hwifdata
(
ide_hwif_t
*
hwif
)
{
return
hwif
->
hwif_data
;
}
void
hwif_unregister
(
ide_hwif_t
*
hwif
);
static
inline
void
ide_set_hwifdata
(
ide_hwif_t
*
hwif
,
void
*
data
)
{
hwif
->
hwif_data
=
data
;
}
void
export_ide_init_queue
(
ide_drive_t
*
drive
);
byte
export_probe_for_drive
(
ide_drive_t
*
drive
);
/* ide-lib.c */
extern
u8
ide_dma_speed
(
ide_drive_t
*
drive
,
u8
mode
);
extern
u8
ide_rate_filter
(
u8
mode
,
u8
speed
);
extern
int
ide_dma_enable
(
ide_drive_t
*
drive
);
extern
char
*
ide_xfer_verbose
(
u8
xfer_rate
);
extern
spinlock_t
ide_lock
;
...
...
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