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
44bfd5a0
Commit
44bfd5a0
authored
Nov 25, 2002
by
Alan Cox
Committed by
Linus Torvalds
Nov 25, 2002
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[PATCH] remove io related stuff from ide.c
parent
9d9b7b3f
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
164 additions
and
1164 deletions
+164
-1164
drivers/ide/ide.c
drivers/ide/ide.c
+164
-1164
No files found.
drivers/ide/ide.c
View file @
44bfd5a0
...
...
@@ -222,37 +222,6 @@ 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
(
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
);
i
=
inb_p
(
0x40
);
i
|=
inb_p
(
0x40
)
<<
8
;
local_irq_restore
(
flags
);
return
(
t
-
i
);
}
#endif
/* DISK_RECOVERY_TIME */
static
inline
void
set_recovery_timer
(
ide_hwif_t
*
hwif
)
{
#if (DISK_RECOVERY_TIME > 0)
hwif
->
last_time
=
read_timer
(
hwif
);
#endif
/* DISK_RECOVERY_TIME */
}
/*
* Do not even *think* about calling this!
...
...
@@ -310,6 +279,7 @@ static void init_hwif_data (unsigned int index)
drive
->
max_failures
=
IDE_DEFAULT_MAX_FAILURES
;
drive
->
using_dma
=
0
;
drive
->
is_flash
=
0
;
drive
->
vdma
=
0
;
INIT_LIST_HEAD
(
&
drive
->
list
);
}
}
...
...
@@ -372,55 +342,13 @@ int ide_system_bus_speed (void)
/* safe default value for VESA and PCI */
system_bus_speed
=
50
;
}
printk
(
"ide: Assuming %dMHz system bus speed "
printk
(
KERN_INFO
"ide: Assuming %dMHz system bus speed "
"for PIO modes%s
\n
"
,
system_bus_speed
,
idebus_parameter
?
""
:
"; override with idebus=xx"
);
}
return
system_bus_speed
;
}
/*
* This is our end_request replacement function.
*/
int
ide_end_request
(
ide_drive_t
*
drive
,
int
uptodate
,
int
nr_sectors
)
{
struct
request
*
rq
;
unsigned
long
flags
;
int
ret
=
1
;
spin_lock_irqsave
(
&
ide_lock
,
flags
);
rq
=
HWGROUP
(
drive
)
->
rq
;
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
->
ide_dma_on
(
drive
);
}
if
(
!
end_that_request_first
(
rq
,
uptodate
,
nr_sectors
))
{
add_disk_randomness
(
rq
->
rq_disk
);
if
(
!
blk_rq_tagged
(
rq
))
blkdev_dequeue_request
(
rq
);
else
blk_queue_end_tag
(
&
drive
->
queue
,
rq
);
HWGROUP
(
drive
)
->
rq
=
NULL
;
end_that_request_last
(
rq
);
ret
=
0
;
}
spin_unlock_irqrestore
(
&
ide_lock
,
flags
);
return
ret
;
}
EXPORT_SYMBOL
(
ide_end_request
);
/*
* current_capacity() returns the capacity (in sectors) of a drive
* according to its current geometry/LBA settings.
...
...
@@ -443,82 +371,6 @@ static inline u32 read_24 (ide_drive_t *drive)
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
,
u8
stat
,
u8
err
)
{
ide_hwif_t
*
hwif
=
HWIF
(
drive
);
unsigned
long
flags
;
struct
request
*
rq
;
spin_lock_irqsave
(
&
ide_lock
,
flags
);
rq
=
HWGROUP
(
drive
)
->
rq
;
spin_unlock_irqrestore
(
&
ide_lock
,
flags
);
if
(
rq
->
flags
&
REQ_DRIVE_CMD
)
{
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
]
=
hwif
->
INB
(
IDE_NSECTOR_REG
);
}
}
else
if
(
rq
->
flags
&
REQ_DRIVE_TASK
)
{
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
]
=
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
;
if
(
rq
->
errors
==
0
)
rq
->
errors
=
!
OK_STAT
(
stat
,
READY_STAT
,
BAD_STAT
);
if
(
args
)
{
if
(
args
->
tf_in_flags
.
b
.
data
)
{
u16
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
]
=
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
->
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
);
}
}
}
spin_lock_irqsave
(
&
ide_lock
,
flags
);
blkdev_dequeue_request
(
rq
);
HWGROUP
(
drive
)
->
rq
=
NULL
;
end_that_request_last
(
rq
);
spin_unlock_irqrestore
(
&
ide_lock
,
flags
);
}
EXPORT_SYMBOL
(
ide_end_drive_cmd
);
/*
* Error reporting, in human readable form (luxurious, but a memory hog).
*/
...
...
@@ -529,7 +381,7 @@ u8 ide_dump_status (ide_drive_t *drive, const char *msg, u8 stat)
u8
err
=
0
;
local_irq_set
(
flags
);
printk
(
"%s: %s: status=0x%02x"
,
drive
->
name
,
msg
,
stat
);
printk
(
KERN_WARNING
"%s: %s: status=0x%02x"
,
drive
->
name
,
msg
,
stat
);
#if FANCY_STATUS_DUMPS
printk
(
" { "
);
if
(
stat
&
BUSY_STAT
)
{
...
...
@@ -602,967 +454,7 @@ u8 ide_dump_status (ide_drive_t *drive, const char *msg, u8 stat)
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
* resetting the drive, this routine tries to clear the condition
* 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*.
*/
void
try_to_flush_leftover_data
(
ide_drive_t
*
drive
)
{
int
i
=
(
drive
->
mult_count
?
drive
->
mult_count
:
1
)
*
SECTOR_WORDS
;
if
(
drive
->
media
!=
ide_disk
)
return
;
while
(
i
>
0
)
{
u32
buffer
[
16
];
u32
wcount
=
(
i
>
16
)
?
16
:
i
;
i
-=
wcount
;
HWIF
(
drive
)
->
ata_input_data
(
drive
,
buffer
,
wcount
);
}
}
EXPORT_SYMBOL
(
try_to_flush_leftover_data
);
/*
* FIXME Add an ATAPI error
*/
/*
* ide_error() takes action based on the error returned by the drive.
*/
ide_startstop_t
ide_error
(
ide_drive_t
*
drive
,
const
char
*
msg
,
u8
stat
)
{
ide_hwif_t
*
hwif
;
struct
request
*
rq
;
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
;
}
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 */
rq
->
errors
|=
ERROR_RESET
;
}
else
{
if
(
drive
->
media
!=
ide_disk
)
goto
media_out
;
if
(
stat
&
ERR_STAT
)
{
/* err has different meaning on cdrom and tape */
if
(
err
==
ABRT_ERR
)
{
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 */
rq
->
errors
|=
ERROR_RECAL
;
}
}
media_out:
if
((
stat
&
DRQ_STAT
)
&&
rq_data_dir
(
rq
)
!=
WRITE
)
try_to_flush_leftover_data
(
drive
);
}
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
,
0
);
else
ide_end_request
(
drive
,
0
,
0
);
}
else
{
if
((
rq
->
errors
&
ERROR_RESET
)
==
ERROR_RESET
)
{
++
rq
->
errors
;
return
ide_do_reset
(
drive
);
}
if
((
rq
->
errors
&
ERROR_RECAL
)
==
ERROR_RECAL
)
drive
->
special
.
b
.
recalibrate
=
1
;
++
rq
->
errors
;
}
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
,
u8
cmd
,
u8
nsect
,
ide_handler_t
*
handler
)
{
ide_hwif_t
*
hwif
=
HWIF
(
drive
);
if
(
HWGROUP
(
drive
)
->
handler
!=
NULL
)
BUG
();
ide_set_handler
(
drive
,
handler
,
WAIT_CMD
,
NULL
);
if
(
IDE_CONTROL_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.
*/
ide_startstop_t
drive_cmd_intr
(
ide_drive_t
*
drive
)
{
struct
request
*
rq
=
HWGROUP
(
drive
)
->
rq
;
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
])
{
u8
io_32bit
=
drive
->
io_32bit
;
drive
->
io_32bit
=
0
;
hwif
->
ata_input_data
(
drive
,
&
args
[
4
],
args
[
3
]
*
SECTOR_WORDS
);
drive
->
io_32bit
=
io_32bit
;
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
,
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.
*/
ide_startstop_t
do_special
(
ide_drive_t
*
drive
)
{
special_t
*
s
=
&
drive
->
special
;
#ifdef DEBUG
printk
(
"%s: do_special: 0x%02x
\n
"
,
drive
->
name
,
s
->
all
);
#endif
if
(
s
->
b
.
set_tune
)
{
s
->
b
.
set_tune
=
0
;
if
(
HWIF
(
drive
)
->
tuneproc
!=
NULL
)
HWIF
(
drive
)
->
tuneproc
(
drive
,
drive
->
tune_req
);
}
else
if
(
drive
->
driver
!=
NULL
)
{
return
DRIVER
(
drive
)
->
special
(
drive
);
}
else
if
(
s
->
all
)
{
printk
(
"%s: bad special flag: 0x%02x
\n
"
,
drive
->
name
,
s
->
all
);
s
->
all
=
0
;
}
return
ide_stopped
;
}
EXPORT_SYMBOL
(
do_special
);
/*
* execute_drive_cmd() issues a special drive command,
* usually initiated by ioctl() from the external hdparm program.
*/
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
;
if
(
!
args
)
goto
done
;
if
(
args
->
tf_out_flags
.
all
!=
0
)
return
flagged_taskfile
(
drive
,
args
);
return
do_rw_taskfile
(
drive
,
args
);
}
else
if
(
rq
->
flags
&
REQ_DRIVE_TASK
)
{
u8
*
args
=
rq
->
buffer
;
u8
sel
;
if
(
!
args
)
goto
done
;
#ifdef DEBUG
printk
(
"%s: DRIVE_TASK_CMD "
,
drive
->
name
);
printk
(
"cmd=0x%02x "
,
args
[
0
]);
printk
(
"fr=0x%02x "
,
args
[
1
]);
printk
(
"ns=0x%02x "
,
args
[
2
]);
printk
(
"sc=0x%02x "
,
args
[
3
]);
printk
(
"lcyl=0x%02x "
,
args
[
4
]);
printk
(
"hcyl=0x%02x "
,
args
[
5
]);
printk
(
"sel=0x%02x
\n
"
,
args
[
6
]);
#endif
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
;
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
)
{
u8
*
args
=
rq
->
buffer
;
if
(
!
args
)
goto
done
;
#ifdef DEBUG
printk
(
"%s: DRIVE_CMD "
,
drive
->
name
);
printk
(
"cmd=0x%02x "
,
args
[
0
]);
printk
(
"sc=0x%02x "
,
args
[
1
]);
printk
(
"fr=0x%02x "
,
args
[
2
]);
printk
(
"xx=0x%02x
\n
"
,
args
[
3
]);
#endif
if
(
args
[
0
]
==
WIN_SMART
)
{
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
;
}
hwif
->
OUTB
(
args
[
2
],
IDE_FEATURE_REG
);
ide_cmd
(
drive
,
args
[
0
],
args
[
1
],
&
drive_cmd_intr
);
return
ide_started
;
}
done:
/*
* NULL is actually a valid way of waiting for
* all current requests to be flushed from the queue.
*/
#ifdef DEBUG
printk
(
"%s: DRIVE_CMD (null)
\n
"
,
drive
->
name
);
#endif
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
*/
ide_startstop_t
start_request
(
ide_drive_t
*
drive
,
struct
request
*
rq
)
{
ide_startstop_t
startstop
;
unsigned
long
block
;
BUG_ON
(
!
(
rq
->
flags
&
REQ_STARTED
));
#ifdef DEBUG
printk
(
"%s: start_request: current=0x%08lx
\n
"
,
HWIF
(
drive
)
->
name
,
(
unsigned
long
)
rq
);
#endif
/* bail early if we've exceeded max_failures */
if
(
drive
->
max_failures
&&
(
drive
->
failures
>
drive
->
max_failures
))
{
goto
kill_rq
;
}
/*
* bail early if we've sent a device to sleep, however how to wake
* this needs to be a masked flag. FIXME for proper operations.
*/
if
(
drive
->
suspend_reset
)
goto
kill_rq
;
block
=
rq
->
sector
;
if
(
blk_fs_request
(
rq
)
&&
(
drive
->
media
==
ide_disk
||
drive
->
media
==
ide_floppy
))
{
block
+=
drive
->
sect0
;
}
/* Yecch - this will shift the entire interval,
possibly killing some innocent following sector */
if
(
block
==
0
&&
drive
->
remap_0_to_1
==
1
)
block
=
1
;
/* redirect MBR access to EZ-Drive partn table */
#if (DISK_RECOVERY_TIME > 0)
while
((
read_timer
()
-
HWIF
(
drive
)
->
last_time
)
<
DISK_RECOVERY_TIME
);
#endif
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
;
}
if
(
!
drive
->
special
.
all
)
{
if
(
rq
->
flags
&
(
REQ_DRIVE_CMD
|
REQ_DRIVE_TASK
))
return
execute_drive_cmd
(
drive
,
rq
);
else
if
(
rq
->
flags
&
REQ_DRIVE_TASKFILE
)
return
execute_drive_cmd
(
drive
,
rq
);
if
(
drive
->
driver
!=
NULL
)
{
return
(
DRIVER
(
drive
)
->
do_request
(
drive
,
rq
,
block
));
}
printk
(
"%s: media type %d not supported
\n
"
,
drive
->
name
,
drive
->
media
);
goto
kill_rq
;
}
return
do_special
(
drive
);
kill_rq:
if
(
drive
->
driver
!=
NULL
)
DRIVER
(
drive
)
->
end_request
(
drive
,
0
,
0
);
else
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.
*/
void
ide_stall_queue
(
ide_drive_t
*
drive
,
unsigned
long
timeout
)
{
if
(
timeout
>
WAIT_WORSTCASE
)
timeout
=
WAIT_WORSTCASE
;
drive
->
sleep
=
timeout
+
jiffies
;
}
EXPORT_SYMBOL
(
ide_stall_queue
);
#define WAKEUP(drive) ((drive)->service_start + 2 * (drive)->service_time)
/*
* choose_drive() selects the next drive which will be serviced.
*/
static
inline
ide_drive_t
*
choose_drive
(
ide_hwgroup_t
*
hwgroup
)
{
ide_drive_t
*
drive
,
*
best
;
repeat:
best
=
NULL
;
drive
=
hwgroup
->
drive
;
do
{
if
(
!
blk_queue_empty
(
&
drive
->
queue
)
&&
(
!
drive
->
sleep
||
time_after_eq
(
jiffies
,
drive
->
sleep
)))
{
if
(
!
best
||
(
drive
->
sleep
&&
(
!
best
->
sleep
||
0
<
(
signed
long
)(
best
->
sleep
-
drive
->
sleep
)))
||
(
!
best
->
sleep
&&
0
<
(
signed
long
)(
WAKEUP
(
best
)
-
WAKEUP
(
drive
))))
{
if
(
!
blk_queue_plugged
(
&
drive
->
queue
))
best
=
drive
;
}
}
}
while
((
drive
=
drive
->
next
)
!=
hwgroup
->
drive
);
if
(
best
&&
best
->
nice1
&&
!
best
->
sleep
&&
best
!=
hwgroup
->
drive
&&
best
->
service_time
>
WAIT_MIN_SLEEP
)
{
long
t
=
(
signed
long
)(
WAKEUP
(
best
)
-
jiffies
);
if
(
t
>=
WAIT_MIN_SLEEP
)
{
/*
* We *may* have some time to spare, but first let's see if
* someone can potentially benefit from our nice mood today..
*/
drive
=
best
->
next
;
do
{
if
(
!
drive
->
sleep
&&
0
<
(
signed
long
)(
WAKEUP
(
drive
)
-
(
jiffies
-
best
->
service_time
))
&&
0
<
(
signed
long
)((
jiffies
+
t
)
-
WAKEUP
(
drive
)))
{
ide_stall_queue
(
best
,
IDE_MIN
(
t
,
10
*
WAIT_MIN_SLEEP
));
goto
repeat
;
}
}
while
((
drive
=
drive
->
next
)
!=
best
);
}
}
return
best
;
}
/*
* Issue a new request to a drive from hwgroup
* Caller must have already done spin_lock_irqsave(&ide_lock, ..);
*
* A hwgroup is a serialized group of IDE interfaces. Usually there is
* exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640)
* may have both interfaces in a single hwgroup to "serialize" access.
* Or possibly multiple ISA interfaces can share a common IRQ by being grouped
* together into one hwgroup for serialized access.
*
* Note also that several hwgroups can end up sharing a single IRQ,
* possibly along with many other devices. This is especially common in
* PCI-based systems with off-board IDE controller cards.
*
* The IDE driver uses the single global ide_lock spinlock to protect
* access to the request queues, and to protect the hwgroup->busy flag.
*
* The first thread into the driver for a particular hwgroup sets the
* hwgroup->busy flag to indicate that this hwgroup is now active,
* and then initiates processing of the top request from the request queue.
*
* Other threads attempting entry notice the busy setting, and will simply
* queue their new requests and exit immediately. Note that hwgroup->busy
* remains set even when the driver is merely awaiting the next interrupt.
* Thus, the meaning is "this hwgroup is busy processing a request".
*
* When processing of a request completes, the completing thread or IRQ-handler
* will start the next request from the queue. If no more work remains,
* the driver will clear the hwgroup->busy flag and exit.
*
* The ide_lock (spinlock) is used to protect all access to the
* hwgroup->busy flag, but is otherwise not needed for most processing in
* the driver. This makes the driver much more friendlier to shared IRQs
* than previous designs, while remaining 100% (?) SMP safe and capable.
*/
/* --BenH: made non-static as ide-pmac.c uses it to kick the hwgroup back
* into life on wakeup from machine sleep.
*/
void
ide_do_request
(
ide_hwgroup_t
*
hwgroup
,
int
masked_irq
)
{
ide_drive_t
*
drive
;
ide_hwif_t
*
hwif
;
struct
request
*
rq
;
ide_startstop_t
startstop
;
/* 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
();
while
(
!
hwgroup
->
busy
)
{
hwgroup
->
busy
=
1
;
drive
=
choose_drive
(
hwgroup
);
if
(
drive
==
NULL
)
{
unsigned
long
sleep
=
0
;
hwgroup
->
rq
=
NULL
;
drive
=
hwgroup
->
drive
;
do
{
if
(
drive
->
sleep
&&
(
!
sleep
||
0
<
(
signed
long
)(
sleep
-
drive
->
sleep
)))
sleep
=
drive
->
sleep
;
}
while
((
drive
=
drive
->
next
)
!=
hwgroup
->
drive
);
if
(
sleep
)
{
/*
* Take a short snooze, and then wake up this hwgroup again.
* This gives other hwgroups on the same a chance to
* play fairly with us, just in case there are big differences
* in relative throughputs.. don't want to hog the cpu too much.
*/
if
(
time_before
(
sleep
,
jiffies
+
WAIT_MIN_SLEEP
))
sleep
=
jiffies
+
WAIT_MIN_SLEEP
;
#if 1
if
(
timer_pending
(
&
hwgroup
->
timer
))
printk
(
"ide_set_handler: timer already active
\n
"
);
#endif
/* 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 */
}
else
{
/* Ugly, but how can we sleep for the lock
* otherwise? perhaps from tq_disk?
*/
/* for atari only */
ide_release_lock
(
&
ide_intr_lock
);
hwgroup
->
busy
=
0
;
}
/* 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
])
{
/* set nIEN for previous hwif */
SELECT_INTERRUPT
(
drive
);
}
hwgroup
->
hwif
=
hwif
;
hwgroup
->
drive
=
drive
;
drive
->
sleep
=
0
;
drive
->
service_start
=
jiffies
;
queue_next:
if
(
!
ata_can_queue
(
drive
))
{
if
(
!
ata_pending_commands
(
drive
))
hwgroup
->
busy
=
0
;
break
;
}
if
(
blk_queue_plugged
(
&
drive
->
queue
))
{
if
(
drive
->
using_tcq
)
break
;
printk
(
"ide: huh? queue was plugged!
\n
"
);
break
;
}
/*
* we know that the queue isn't empty, but this can happen
* if the q->prep_rq_fn() decides to kill a request
*/
rq
=
elv_next_request
(
&
drive
->
queue
);
if
(
!
rq
)
{
hwgroup
->
busy
=
!!
ata_pending_commands
(
drive
);
break
;
}
if
(
!
rq
->
bio
&&
ata_pending_commands
(
drive
))
break
;
hwgroup
->
rq
=
rq
;
/*
* Some systems have trouble with IDE IRQs arriving while
* the driver is still setting things up. So, here we disable
* the IRQ used by this interface while the request is being started.
* This may look bad at first, but pretty much the same thing
* happens anyway when any interrupt comes in, IDE or otherwise
* -- the kernel masks the IRQ while it is being handled.
*/
if
(
masked_irq
&&
hwif
->
irq
!=
masked_irq
)
disable_irq_nosync
(
hwif
->
irq
);
spin_unlock
(
&
ide_lock
);
local_irq_enable
();
/* allow other IRQs while we start this request */
startstop
=
start_request
(
drive
,
rq
);
spin_lock_irq
(
&
ide_lock
);
if
(
masked_irq
&&
hwif
->
irq
!=
masked_irq
)
enable_irq
(
hwif
->
irq
);
if
(
startstop
==
ide_released
)
goto
queue_next
;
if
(
startstop
==
ide_stopped
)
hwgroup
->
busy
=
0
;
}
}
EXPORT_SYMBOL
(
ide_do_request
);
/*
* Passes the stuff to ide_do_request
*/
void
do_ide_request
(
request_queue_t
*
q
)
{
ide_do_request
(
q
->
queuedata
,
0
);
}
/*
* 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
* all away
*/
void
ide_dma_timeout_retry
(
ide_drive_t
*
drive
)
{
ide_hwif_t
*
hwif
=
HWIF
(
drive
);
struct
request
*
rq
;
/*
* end current dma transaction
*/
(
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
->
ide_dma_timeout
(
drive
);
/*
* disable dma for now, but remember that we did so because of
* a timeout -- we'll reenable after we finish this next request
* (or rather the first chunk of it) in pio.
*/
drive
->
retry_pio
++
;
drive
->
state
=
DMA_PIO_RETRY
;
(
void
)
hwif
->
ide_dma_off_quietly
(
drive
);
/*
* un-busy drive etc (hwgroup->busy is cleared on return) and
* make sure request is sane
*/
rq
=
HWGROUP
(
drive
)
->
rq
;
HWGROUP
(
drive
)
->
rq
=
NULL
;
rq
->
errors
=
0
;
rq
->
sector
=
rq
->
bio
->
bi_sector
;
rq
->
current_nr_sectors
=
bio_iovec
(
rq
->
bio
)
->
bv_len
>>
9
;
rq
->
hard_cur_sectors
=
rq
->
current_nr_sectors
;
if
(
rq
->
bio
)
rq
->
buffer
=
NULL
;
}
EXPORT_SYMBOL
(
ide_dma_timeout_retry
);
/*
* ide_timer_expiry() is our timeout function for all drive operations.
* But note that it can also be invoked as a result of a "sleep" operation
* triggered by the mod_timer() call in ide_do_request.
*/
void
ide_timer_expiry
(
unsigned
long
data
)
{
ide_hwgroup_t
*
hwgroup
=
(
ide_hwgroup_t
*
)
data
;
ide_handler_t
*
handler
;
ide_expiry_t
*
expiry
;
unsigned
long
flags
;
unsigned
long
wait
;
spin_lock_irqsave
(
&
ide_lock
,
flags
);
del_timer
(
&
hwgroup
->
timer
);
if
((
handler
=
hwgroup
->
handler
)
==
NULL
)
{
/*
* Either a marginal timeout occurred
* (got the interrupt just as timer expired),
* or we were "sleeping" to give other devices a chance.
* Either way, we don't really want to complain about anything.
*/
if
(
hwgroup
->
sleeping
)
{
hwgroup
->
sleeping
=
0
;
hwgroup
->
busy
=
0
;
}
}
else
{
ide_drive_t
*
drive
=
hwgroup
->
drive
;
if
(
!
drive
)
{
printk
(
"ide_timer_expiry: hwgroup->drive was NULL
\n
"
);
hwgroup
->
handler
=
NULL
;
}
else
{
ide_hwif_t
*
hwif
;
ide_startstop_t
startstop
=
ide_stopped
;
if
(
!
hwgroup
->
busy
)
{
hwgroup
->
busy
=
1
;
/* paranoia */
printk
(
"%s: ide_timer_expiry: hwgroup->busy was 0 ??
\n
"
,
drive
->
name
);
}
if
((
expiry
=
hwgroup
->
expiry
)
!=
NULL
)
{
/* continue */
if
((
wait
=
expiry
(
drive
))
!=
0
)
{
/* reset timer */
hwgroup
->
timer
.
expires
=
jiffies
+
wait
;
add_timer
(
&
hwgroup
->
timer
);
spin_unlock_irqrestore
(
&
ide_lock
,
flags
);
return
;
}
}
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:
*/
spin_unlock
(
&
ide_lock
);
hwif
=
HWIF
(
drive
);
#if DISABLE_IRQ_NOSYNC
disable_irq_nosync
(
hwif
->
irq
);
#else
/* disable_irq_nosync ?? */
disable_irq
(
hwif
->
irq
);
#endif
/* DISABLE_IRQ_NOSYNC */
/* local CPU only,
* as if we were handling an interrupt */
local_irq_disable
();
if
(
hwgroup
->
poll_timeout
!=
0
)
{
startstop
=
handler
(
drive
);
}
else
if
(
drive_is_ready
(
drive
))
{
if
(
drive
->
waiting_for_dma
)
(
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
)
{
startstop
=
ide_stopped
;
ide_dma_timeout_retry
(
drive
);
}
else
startstop
=
DRIVER
(
drive
)
->
error
(
drive
,
"irq timeout"
,
hwif
->
INB
(
IDE_STATUS_REG
));
}
set_recovery_timer
(
hwif
);
drive
->
service_time
=
jiffies
-
drive
->
service_start
;
enable_irq
(
hwif
->
irq
);
spin_lock_irq
(
&
ide_lock
);
if
(
startstop
==
ide_stopped
)
hwgroup
->
busy
=
0
;
}
}
ide_do_request
(
hwgroup
,
0
);
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.
* There should be no way that an irq can happen before we're ready for it,
* so we needn't worry much about losing an "important" interrupt here.
*
* On laptops (and "green" PCs), an unexpected interrupt occurs whenever the
* drive enters "idle", "standby", or "sleep" mode, so if the status looks
* "good", we just ignore the interrupt completely.
*
* This routine assumes __cli() is in effect when called.
*
* If an unexpected interrupt happens on irq15 while we are handling irq14
* and if the two interfaces are "serialized" (CMD640), then it looks like
* we could screw up by interfering with a new request being set up for irq15.
*
* In reality, this is a non-issue. The new command is not sent unless the
* drive is ready to accept one, in which case we know the drive is not
* trying to interrupt us. And ide_set_handler() is always invoked before
* completing the issuance of any new drive command, so we will not be
* accidentally invoked as a result of any valid command completion interrupt.
*
*/
static
void
unexpected_intr
(
int
irq
,
ide_hwgroup_t
*
hwgroup
)
{
u8
stat
;
ide_hwif_t
*
hwif
=
hwgroup
->
hwif
;
/*
* handle the unexpected interrupt
*/
do
{
if
(
hwif
->
irq
==
irq
)
{
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
);
}
}
}
}
while
((
hwif
=
hwif
->
next
)
!=
hwgroup
->
hwif
);
}
/*
* entry point for all interrupts, caller does __cli() for us
*/
void
ide_intr
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
{
unsigned
long
flags
;
ide_hwgroup_t
*
hwgroup
=
(
ide_hwgroup_t
*
)
dev_id
;
ide_hwif_t
*
hwif
;
ide_drive_t
*
drive
;
ide_handler_t
*
handler
;
ide_startstop_t
startstop
;
spin_lock_irqsave
(
&
ide_lock
,
flags
);
hwif
=
hwgroup
->
hwif
;
if
(
!
ide_ack_intr
(
hwif
))
{
spin_unlock_irqrestore
(
&
ide_lock
,
flags
);
return
;
}
if
((
handler
=
hwgroup
->
handler
)
==
NULL
||
hwgroup
->
poll_timeout
!=
0
)
{
/*
* Not expecting an interrupt from this drive.
* That means this could be:
* (1) an interrupt from another PCI device
* sharing the same PCI INT# as us.
* or (2) a drive just entered sleep or standby mode,
* and is interrupting to let us know.
* or (3) a spurious interrupt of unknown origin.
*
* For PCI, we cannot tell the difference,
* so in that case we just ignore it and hope it goes away.
*/
#ifdef CONFIG_BLK_DEV_IDEPCI
if
(
hwif
->
pci_dev
&&
!
hwif
->
pci_dev
->
vendor
)
#endif
/* CONFIG_BLK_DEV_IDEPCI */
{
/*
* Probably not a shared PCI interrupt,
* so we can safely try to do something about it:
*/
unexpected_intr
(
irq
,
hwgroup
);
#ifdef CONFIG_BLK_DEV_IDEPCI
}
else
{
/*
* Whack the status register, just in case
* we have a leftover pending IRQ.
*/
(
void
)
hwif
->
INB
(
hwif
->
io_ports
[
IDE_STATUS_OFFSET
]);
#endif
/* CONFIG_BLK_DEV_IDEPCI */
}
spin_unlock_irqrestore
(
&
ide_lock
,
flags
);
return
;
}
drive
=
hwgroup
->
drive
;
if
(
!
drive
)
{
/*
* This should NEVER happen, and there isn't much
* we could do about it here.
*/
spin_unlock_irqrestore
(
&
ide_lock
,
flags
);
return
;
}
if
(
!
drive_is_ready
(
drive
))
{
/*
* This happens regularly when we share a PCI IRQ with
* another device. Unfortunately, it can also happen
* with some buggy drives that trigger the IRQ before
* their status register is up to date. Hopefully we have
* enough advance overhead that the latter isn't a problem.
*/
spin_unlock_irqrestore
(
&
ide_lock
,
flags
);
return
;
}
if
(
!
hwgroup
->
busy
)
{
hwgroup
->
busy
=
1
;
/* paranoia */
printk
(
"%s: ide_intr: hwgroup->busy was 0 ??
\n
"
,
drive
->
name
);
}
hwgroup
->
handler
=
NULL
;
del_timer
(
&
hwgroup
->
timer
);
spin_unlock
(
&
ide_lock
);
if
(
drive
->
unmask
)
local_irq_enable
();
/* service this interrupt, may set handler for next interrupt */
startstop
=
handler
(
drive
);
spin_lock_irq
(
&
ide_lock
);
/*
* Note that handler() may have set things up for another
* interrupt to occur soon, but it cannot happen until
* we exit from this routine, because it will be the
* same irq as is currently being serviced here, and Linux
* won't allow another of the same (on any CPU) until we return.
*/
set_recovery_timer
(
HWIF
(
drive
));
drive
->
service_time
=
jiffies
-
drive
->
service_start
;
if
(
startstop
==
ide_stopped
)
{
if
(
hwgroup
->
handler
==
NULL
)
{
/* paranoia */
hwgroup
->
busy
=
0
;
ide_do_request
(
hwgroup
,
hwif
->
irq
);
}
else
{
printk
(
"%s: ide_intr: huh? expected NULL handler "
"on exit
\n
"
,
drive
->
name
);
}
}
spin_unlock_irqrestore
(
&
ide_lock
,
flags
);
}
EXPORT_SYMBOL
(
ide_intr
);
/*
* This function is intended to be used prior to invoking ide_do_drive_cmd().
*/
void
ide_init_drive_cmd
(
struct
request
*
rq
)
{
memset
(
rq
,
0
,
sizeof
(
*
rq
));
rq
->
flags
=
REQ_DRIVE_CMD
;
}
EXPORT_SYMBOL
(
ide_init_drive_cmd
);
/*
* This function issues a special IDE device request
* onto the request queue.
*
* If action is ide_wait, then the rq is queued at the end of the
* request queue, and the function sleeps until it has been processed.
* This is for use when invoked from an ioctl handler.
*
* If action is ide_preempt, then the rq is queued at the head of
* the request queue, displacing the currently-being-processed
* request and this function returns immediately without waiting
* for the new rq to be completed. This is VERY DANGEROUS, and is
* intended for careful use by the ATAPI tape/cdrom driver code.
*
* If action is ide_next, then the rq is queued immediately after
* the currently-being-processed-request (if any), and the function
* returns without waiting for the new rq to be completed. As above,
* This is VERY DANGEROUS, and is intended for careful use by the
* ATAPI tape/cdrom driver code.
*
* If action is ide_end, then the rq is queued at the end of the
* request queue, and the function returns immediately without waiting
* 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
)
{
unsigned
long
flags
;
ide_hwgroup_t
*
hwgroup
=
HWGROUP
(
drive
);
DECLARE_COMPLETION
(
wait
);
int
insert_end
=
1
,
err
;
#ifdef CONFIG_BLK_DEV_PDC4030
if
(
HWIF
(
drive
)
->
chipset
==
ide_pdc4030
&&
rq
->
buffer
!=
NULL
)
return
-
ENOSYS
;
/* special drive cmds not supported */
#endif
rq
->
errors
=
0
;
rq
->
rq_status
=
RQ_ACTIVE
;
rq
->
rq_disk
=
drive
->
disk
;
/*
* we need to hold an extra reference to request for safe inspection
* after completion
*/
if
(
action
==
ide_wait
)
{
rq
->
ref_count
++
;
rq
->
waiting
=
&
wait
;
}
spin_lock_irqsave
(
&
ide_lock
,
flags
);
if
(
action
==
ide_preempt
)
{
hwgroup
->
rq
=
NULL
;
insert_end
=
0
;
}
__elv_add_request
(
&
drive
->
queue
,
rq
,
insert_end
,
0
);
ide_do_request
(
hwgroup
,
0
);
spin_unlock_irqrestore
(
&
ide_lock
,
flags
);
err
=
0
;
if
(
action
==
ide_wait
)
{
wait_for_completion
(
&
wait
);
if
(
rq
->
errors
)
err
=
-
EIO
;
blk_put_request
(
rq
);
}
return
err
;
}
EXPORT_SYMBOL
(
ide_do_drive_cmd
);
void
ide_probe_module
(
void
)
{
...
...
@@ -1632,11 +524,18 @@ ide_proc_entry_t generic_subdriver_entries[] = {
#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
* allocated for weird IDE interface chipsets.
/**
* hwif_unregister - free IDE resources
*
* Note that we only release the standard ports,
* and do not even try to handle any extra ports
* allocated for weird IDE interface chipsets.
*
* Note also that we don't yet handle mmio resources here. More
* importantly our caller should be doing this so we need to
* restructure this as a helper function for drivers.
*/
void
hwif_unregister
(
ide_hwif_t
*
hwif
)
{
u32
i
=
0
;
...
...
@@ -1665,6 +564,28 @@ EXPORT_SYMBOL(hwif_unregister);
extern
void
init_hwif_data
(
unsigned
int
index
);
/**
* ide_unregister - free an ide interface
* @index: index of interface (will change soon to a pointer)
*
* Perform the final unregister of an IDE interface. At the moment
* we don't refcount interfaces so this will also get split up.
*
* Locking:
* The caller must not hold the IDE locks
* The drive present/vanishing is not yet properly locked
* Take care with the callbacks. These have been split to avoid
* deadlocking the IDE layer. The shutdown callback is called
* before we take the lock and free resources. It is up to the
* caller to be sure there is no pending I/O here, and that
* the interfce will not be reopened (present/vanishing locking
* isnt yet done btw). After we commit to the final kill we
* call the cleanup callback with the ide locks held.
*
* Unregister restores the hwif structures to the default state.
* This is raving bonkers.
*/
void
ide_unregister
(
unsigned
int
index
)
{
ide_drive_t
*
drive
,
*
d
;
...
...
@@ -1675,7 +596,8 @@ void ide_unregister (unsigned int index)
ide_hwif_t
old_hwif
;
if
(
index
>=
MAX_HWIFS
)
return
;
BUG
();
spin_lock_irqsave
(
&
ide_lock
,
flags
);
hwif
=
&
ide_hwifs
[
index
];
if
(
!
hwif
->
present
)
...
...
@@ -1686,12 +608,21 @@ void ide_unregister (unsigned int index)
continue
;
if
(
drive
->
usage
)
goto
abort
;
if
(
drive
->
driver
!=
NULL
&&
DRIVER
(
drive
)
->
cleanup
(
drive
))
if
(
drive
->
driver
!=
NULL
&&
DRIVER
(
drive
)
->
shutdown
(
drive
))
goto
abort
;
}
hwif
->
present
=
0
;
spin_unlock_irqrestore
(
&
ide_lock
,
flags
);
for
(
unit
=
0
;
unit
<
MAX_DRIVES
;
++
unit
)
{
drive
=
&
hwif
->
drives
[
unit
];
if
(
!
drive
->
present
)
continue
;
if
(
drive
->
driver
!=
NULL
)
DRIVER
(
drive
)
->
cleanup
(
drive
);
}
#ifdef CONFIG_PROC_FS
destroy_proc_ide_drives
(
hwif
);
#endif
...
...
@@ -1752,7 +683,7 @@ void ide_unregister (unsigned int index)
else
hwgroup
->
hwif
=
HWIF
(
hwgroup
->
drive
);
#if
defined(CONFIG_BLK_DEV_IDEDMA) &&
!defined(CONFIG_DMA_NONPCI)
#if !defined(CONFIG_DMA_NONPCI)
if
(
hwif
->
dma_base
)
{
(
void
)
ide_release_dma
(
hwif
);
...
...
@@ -1764,7 +695,7 @@ void ide_unregister (unsigned int index)
hwif
->
dma_vendor3
=
0
;
hwif
->
dma_prdtable
=
0
;
}
#endif
/*
(CONFIG_BLK_DEV_IDEDMA) &&
!(CONFIG_DMA_NONPCI) */
#endif
/* !(CONFIG_DMA_NONPCI) */
/*
* Remove us from the kernel's knowledge
...
...
@@ -1894,11 +825,21 @@ void ide_unregister (unsigned int index)
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
* do it for you.
/**
* ide_setup_ports - set up IDE interface ports
* @hw: register descriptions
* @base: base register
* @offsets: table of register offsets
* @ctrl: control register
* @ack_irq: IRQ ack
* @irq: interrupt lie
*
* Setup hw_regs_t structure described by parameters. You
* may set up the hw structure yourself OR use this routine to
* do it for you. This is basically a helper
*
*/
void
ide_setup_ports
(
hw_regs_t
*
hw
,
ide_ioreg_t
base
,
int
*
offsets
,
ide_ioreg_t
ctrl
,
ide_ioreg_t
intr
,
...
...
@@ -2004,6 +945,27 @@ int ide_register (int arg1, int arg2, int irq)
EXPORT_SYMBOL
(
ide_register
);
/**
* ide_add_setting - attach an IDE setting
* drive: drive the setting is for
* name: name of setting
* rw: set if writable
* read_ioctl: read function
* write_ioctl: write function
* data_type: form expected
* min: minimum
* max: maximum
* mul_factor: multiply by
* div_factor: divide by
* data: value
* set: handling for setting
*
* Add a setting to the IDE drive. Support automatic removal and allow
* all the work to be done by plugged in handlers. This code is also
* rather short on locking, but the current plan is to do the locking
* internally to the function.
*/
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
;
...
...
@@ -2038,6 +1000,14 @@ void ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioc
EXPORT_SYMBOL
(
ide_add_setting
);
/**
* ide_remove_setting - remove an ioctl setting
* @name: name of the property
*
* Remove a drive ioctl setting that was created by ide_add_setting.
* Again this needs the locking fixed
*/
void
ide_remove_setting
(
ide_drive_t
*
drive
,
char
*
name
)
{
ide_settings_t
**
p
=
(
ide_settings_t
**
)
&
drive
->
settings
,
*
setting
;
...
...
@@ -2053,6 +1023,16 @@ void ide_remove_setting (ide_drive_t *drive, char *name)
EXPORT_SYMBOL
(
ide_remove_setting
);
/**
* ide_find_setting_by_ioctl - find a setting handler by its command
* @drive: drive to act for
* @cmd: ioctl command code
*
* Scan the drive handlers for an ioctl handler for this function.
* The handlers vary by drive and sometimes by drive state.
* Needs locking fixes.
*/
static
ide_settings_t
*
ide_find_setting_by_ioctl
(
ide_drive_t
*
drive
,
int
cmd
)
{
ide_settings_t
*
setting
=
drive
->
settings
;
...
...
@@ -2065,6 +1045,16 @@ static ide_settings_t *ide_find_setting_by_ioctl (ide_drive_t *drive, int cmd)
return
setting
;
}
/**
* ide_find_setting_by_name - find a setting handler by its name
* @drive: drive to act for
* @cmd: ioctl command code
*
* Scan the drive handlers handler matching the name for this function.
* The handlers vary by drive and sometimes by drive state.
* Needs locking fixes.
*/
ide_settings_t
*
ide_find_setting_by_name
(
ide_drive_t
*
drive
,
char
*
name
)
{
ide_settings_t
*
setting
=
drive
->
settings
;
...
...
@@ -2077,6 +1067,17 @@ ide_settings_t *ide_find_setting_by_name (ide_drive_t *drive, char *name)
return
setting
;
}
/**
* auto_remove_settings - remove driver settings on a device
* @drive: drive to clean
*
* Called when we change the driver bindings for a device, for
* example if the device is hot plugged. We must scrub the driver
* bindings that are thus no longer relevant to the device in case
* it changes from say a CD-ROM to a disk
* Needs locking fixes
*/
static
void
auto_remove_settings
(
ide_drive_t
*
drive
)
{
ide_settings_t
*
setting
;
...
...
@@ -2128,7 +1129,7 @@ int ide_spin_wait_hwgroup (ide_drive_t *drive)
local_irq_set
(
lflags
);
if
(
time_after
(
jiffies
,
timeout
))
{
local_irq_restore
(
lflags
);
printk
(
"%s: channel busy
\n
"
,
drive
->
name
);
printk
(
KERN_ERR
"%s: channel busy
\n
"
,
drive
->
name
);
return
-
EBUSY
;
}
local_irq_restore
(
lflags
);
...
...
@@ -2229,8 +1230,7 @@ static int set_xfer_rate (ide_drive_t *drive, int arg)
SETFEATURES_XFER
,
0
,
NULL
);
if
(
!
err
&&
arg
)
{
if
((
HWIF
(
drive
)
->
speedproc
)
!=
NULL
)
HWIF
(
drive
)
->
speedproc
(
drive
,
(
u8
)
arg
);
ide_set_xfer_rate
(
drive
,
(
u8
)
arg
);
ide_driveid_update
(
drive
);
}
return
err
;
...
...
@@ -2312,7 +1312,7 @@ EXPORT_SYMBOL(system_bus_clock);
*/
int
ide_replace_subdriver
(
ide_drive_t
*
drive
,
const
char
*
driver
)
{
if
(
!
drive
->
present
||
drive
->
usage
)
if
(
!
drive
->
present
||
drive
->
usage
||
drive
->
dead
)
goto
abort
;
if
(
drive
->
driver
!=
NULL
&&
DRIVER
(
drive
)
->
cleanup
(
drive
))
goto
abort
;
...
...
@@ -2487,7 +1487,7 @@ int generic_ide_ioctl(struct block_device *bdev, unsigned int cmd,
#if 1
spin_lock_irqsave
(
&
ide_lock
,
flags
);
if
(
HWGROUP
(
drive
)
->
handler
!=
NULL
)
{
printk
(
"%s: ide_set_handler: handler not null; %p
\n
"
,
drive
->
name
,
HWGROUP
(
drive
)
->
handler
);
printk
(
KERN_ERR
"%s: ide_set_handler: handler not null; %p
\n
"
,
drive
->
name
,
HWGROUP
(
drive
)
->
handler
);
(
void
)
HWGROUP
(
drive
)
->
handler
(
drive
);
// HWGROUP(drive)->handler = NULL;
HWGROUP
(
drive
)
->
expiry
=
NULL
;
...
...
@@ -2702,7 +1702,7 @@ int __init ide_setup (char *s)
strncmp
(
s
,
"hd"
,
2
))
/* hdx= & hdxlun= */
return
0
;
printk
(
"ide_setup: %s"
,
s
);
printk
(
KERN_INFO
"ide_setup: %s"
,
s
);
init_ide_data
();
#ifdef CONFIG_BLK_DEV_IDEDOUBLER
...
...
@@ -3050,18 +2050,6 @@ static void __init probe_for_hwifs (void)
swarm_ide_probe
();
}
#endif
/* CONFIG_BLK_DEV_IDE_SWARM */
#ifdef CONFIG_BLK_DEV_IDE_ICSIDE
{
extern
void
icside_init
(
void
);
icside_init
();
}
#endif
/* CONFIG_BLK_DEV_IDE_ICSIDE */
#ifdef CONFIG_BLK_DEV_IDE_RAPIDE
{
extern
void
rapide_init
(
void
);
rapide_init
();
}
#endif
/* CONFIG_BLK_DEV_IDE_RAPIDE */
#ifdef CONFIG_BLK_DEV_GAYLE
{
extern
void
gayle_init
(
void
);
...
...
@@ -3122,21 +2110,39 @@ void __init ide_init_builtin_drivers (void)
#endif
}
static
int
default_standby
(
ide_drive_t
*
drive
)
/*
* Actually unregister the subdriver. Called with the
* request lock dropped.
*/
static
int
default_cleanup
(
ide_drive_t
*
drive
)
{
return
0
;
return
ide_unregister_subdriver
(
drive
)
;
}
static
int
default_suspend
(
ide_drive_t
*
drive
)
{
return
0
;
}
static
int
default_
resume
(
ide_drive_t
*
drive
)
/*
* Check if we can unregister the subdriver. Called with the
* request lock held.
*/
static
int
default_
shutdown
(
ide_drive_t
*
drive
)
{
if
(
drive
->
usage
||
drive
->
driver
==
NULL
||
DRIVER
(
drive
)
->
busy
)
{
return
1
;
}
drive
->
dead
=
1
;
return
0
;
}
/*
* Default function to use for the cache flush operation. This
* must be replaced for disk devices (see ATA specification
* documents on cache flush and drive suspend rules)
*
* If we have no device attached or the device is not writable
* this handler is sufficient.
*/
static
int
default_flushcache
(
ide_drive_t
*
drive
)
{
return
0
;
...
...
@@ -3193,9 +2199,8 @@ static void setup_driver_defaults (ide_drive_t *drive)
{
ide_driver_t
*
d
=
drive
->
driver
;
if
(
d
->
standby
==
NULL
)
d
->
standby
=
default_standby
;
if
(
d
->
suspend
==
NULL
)
d
->
suspend
=
default_suspend
;
if
(
d
->
resume
==
NULL
)
d
->
resume
=
default_resume
;
if
(
d
->
cleanup
==
NULL
)
d
->
cleanup
=
default_cleanup
;
if
(
d
->
shutdown
==
NULL
)
d
->
shutdown
=
default_shutdown
;
if
(
d
->
flushcache
==
NULL
)
d
->
flushcache
=
default_flushcache
;
if
(
d
->
do_request
==
NULL
)
d
->
do_request
=
default_do_request
;
if
(
d
->
end_request
==
NULL
)
d
->
end_request
=
default_end_request
;
...
...
@@ -3213,7 +2218,7 @@ int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int versio
spin_lock_irqsave
(
&
ide_lock
,
flags
);
if
(
version
!=
IDE_SUBDRIVER_VERSION
||
!
drive
->
present
||
drive
->
driver
!=
NULL
||
drive
->
usage
)
{
drive
->
driver
!=
NULL
||
drive
->
usage
||
drive
->
dead
)
{
spin_unlock_irqrestore
(
&
ide_lock
,
flags
);
return
1
;
}
...
...
@@ -3274,13 +2279,8 @@ static int ide_drive_remove(struct device * dev)
ide_drive_t
*
drive
=
container_of
(
dev
,
ide_drive_t
,
gendev
);
ide_driver_t
*
driver
=
drive
->
driver
;
if
(
driver
)
{
if
(
driver
->
standby
)
driver
->
standby
(
drive
);
if
(
driver
->
cleanup
)
driver
->
cleanup
(
drive
);
}
if
(
driver
&&
driver
->
cleanup
)
driver
->
cleanup
(
drive
);
return
0
;
}
...
...
@@ -3321,7 +2321,7 @@ void ide_unregister_driver(ide_driver_t *driver)
while
(
!
list_empty
(
&
driver
->
drives
))
{
drive
=
list_entry
(
driver
->
drives
.
next
,
ide_drive_t
,
list
);
if
(
driver
->
cleanup
(
drive
))
{
printk
(
"%s: cleanup_module() called while still busy
\n
"
,
drive
->
name
);
printk
(
KERN_ERR
"%s: cleanup_module() called while still busy
\n
"
,
drive
->
name
);
BUG
();
}
/* We must remove proc entries defined in this module.
...
...
@@ -3395,7 +2395,7 @@ static void __init parse_options (char *line)
if
((
next
=
strchr
(
line
,
' '
))
!=
NULL
)
*
next
++
=
0
;
if
(
!
ide_setup
(
line
))
printk
(
"Unknown option '%s'
\n
"
,
line
);
printk
(
KERN_INFO
"Unknown option '%s'
\n
"
,
line
);
}
}
...
...
@@ -3411,10 +2411,10 @@ void cleanup_module (void)
for
(
index
=
0
;
index
<
MAX_HWIFS
;
++
index
)
{
ide_unregister
(
index
);
#if
defined(CONFIG_BLK_DEV_IDEDMA) &&
!defined(CONFIG_DMA_NONPCI)
#if !defined(CONFIG_DMA_NONPCI)
if
(
ide_hwifs
[
index
].
dma_base
)
(
void
)
ide_release_dma
(
&
ide_hwifs
[
index
]);
#endif
/*
(CONFIG_BLK_DEV_IDEDMA) &&
!(CONFIG_DMA_NONPCI) */
#endif
/* !(CONFIG_DMA_NONPCI) */
}
#ifdef CONFIG_PROC_FS
...
...
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