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
fa6bc70e
Commit
fa6bc70e
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] put ide i/o code from ide.c into ide-io.c and comment it
parent
bcf247a5
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
1320 additions
and
0 deletions
+1320
-0
drivers/ide/ide-io.c
drivers/ide/ide-io.c
+1320
-0
No files found.
drivers/ide/ide-io.c
0 → 100644
View file @
fa6bc70e
/*
* IDE I/O functions
*
* Basic PIO and command management functionality.
*
* This code was split off from ide.c. See ide.c for history and original
* copyrights.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* For the avoidance of doubt the "preferred form" of this code is one which
* is in an open non patent encumbered format. Where cryptographic key signing
* forms part of the process of creating an executable the information
* including keys needed to generate an equivalently functional executable
* are deemed to be part of the source code.
*/
#include <linux/config.h>
#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/init.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/completion.h>
#include <linux/reboot.h>
#include <linux/cdrom.h>
#include <linux/seq_file.h>
#include <linux/device.h>
#include <linux/kmod.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/bitops.h>
#include "ide_modes.h"
#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 */
}
/**
* ide_end_request - complete an IDE I/O
* @drive: IDE device for the I/O
* @uptodate:
* @nr_sectors: number of sectors completed
*
* This is our end_request wrapper function. We complete the I/O
* update random number input and dequeue the request, which if
* it was tagged may be out of order.
*/
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
);
/**
* ide_end_drive_cmd - end an explicit drive command
* @drive: command
* @stat: status bits
* @err: error bits
*
* Clean up after success/failure of an explicit drive command.
* These get thrown onto the queue so they are synchronized with
* real I/O operations on the drive.
*
* In LBA48 mode we have to read the register set twice to get
* all the extra information out.
*/
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
);
/**
* try_to_flush_leftover_data - flush junk
* @drive: drive to flush
*
* 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 - handle an error on the IDE
* @drive: drive the error occurred on
* @msg: message to report
* @stat: status bits
*
* ide_error() takes action based on the error returned by the drive.
* For normal I/O that may well include retries. We deal with
* both new-style (taskfile) and old style command handling here.
* In the case of taskfile command handling there is work left to
* do
*/
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
);
/**
* ide_cmd - issue a simple drive command
* @drive: drive the command is for
* @cmd: command byte
* @nsect: sector byte
* @handler: handler for the command completion
*
* Issue a simple drive command with interrupts.
* 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 - drive command completion interrupt
* @drive: drive the completion interrupt occurred on
*
* drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
* We do any neccessary daya reading and then wait for the drive to
* go non busy. At that point we may read the error data and complete
* the request
*/
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 - issue some special commands
* @drive: drive the command is for
*
* 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
(
KERN_ERR
"%s: bad special flag: 0x%02x
\n
"
,
drive
->
name
,
s
->
all
);
s
->
all
=
0
;
}
return
ide_stopped
;
}
EXPORT_SYMBOL
(
do_special
);
/**
* execute_drive_command - issue special drive command
* @drive: the drive to issue th command on
* @rq: the request structure holding the command
*
* execute_drive_cmd() issues a special drive command, usually
* initiated by ioctl() from the external hdparm program. The
* command can be a drive command, drive task or taskfile
* operation. Weirdly you can call it with NULL to wait for
* all commands to finish. Don't do this as that is due to change
*/
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 - start of I/O and command issuing for IDE
*
* start_request() initiates handling of a new I/O request. It
* accepts commands and I/O (read/write) requests. It also does
* the final remapping for weird stuff like EZDrive. Once
* device mapper can work sector level the EZDrive stuff can go away
*
* FIXME: this function needs a rename
*/
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
(
KERN_ERR
"%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
(
KERN_ERR
"%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
);
/**
* restart_request - reissue an IDE request
* @drive: drive for request
* @rq: request to reissue
*
* Reissue a request. See start_request for details and for
* FIXME
*/
int
restart_request
(
ide_drive_t
*
drive
,
struct
request
*
rq
)
{
(
void
)
start_request
(
drive
,
rq
);
return
0
;
}
EXPORT_SYMBOL
(
restart_request
);
/**
* ide_stall_queue - pause an IDE device
* @drive: drive to stall
* @timeout: time to stall for (jiffies)
*
* 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 - select a drive to service
* @hwgroup: hardware group to select on
*
* choose_drive() selects the next drive which will be serviced.
* This is neccessary because the IDE layer can't issue commands
* to both drives on the same cable, unlike SCSI.
*/
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
/* FIXME: use time_before */
&&
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
(
KERN_CRIT
"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
(
KERN_ERR
"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
(
KERN_WARNING
"%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 - handle lack of an IDE interrupt
* @data: timer callback magic (hwgroup)
*
* An IDE command has timed out before the expected drive return
* occurred. At this point we attempt to clean up the current
* mess. If the current handler includes an expiry handler then
* we invoke the expiry handler, and providing it is happy the
* work is done. If that fails we apply generic recovery rules
* invoking the handler and checking the drive DMA status. We
* have an excessively incestuous relationship with the DMA
* logic that wants cleaning up.
*/
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
(
KERN_ERR
"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
(
KERN_ERR
"%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
(
KERN_WARNING
"%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
);
/**
* unexpected_intr - handle an unexpected IDE interrupt
* @irq: interrupt line
* @hwgroup: hwgroup being processed
*
* 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.
*
* Note that we must walk the entire hwgroup here. We know which hwif
* is doing the current command, but we don't know which hwif burped
* mysteriously.
*/
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
(
KERN_ERR
"%s%s: unexpected interrupt, "
"status=0x%02x, count=%ld
\n
"
,
hwif
->
name
,
(
hwif
->
next
==
hwgroup
->
hwif
)
?
""
:
"(?)"
,
stat
,
count
);
}
}
}
}
while
((
hwif
=
hwif
->
next
)
!=
hwgroup
->
hwif
);
}
/**
* ide_intr - default IDE interrupt handler
* @irq: interrupt number
* @dev_id: hwif group
* @regs: unused weirdness from the kernel irq layer
*
* This is the default IRQ handler for the IDE layer. You should
* not need to override it. If you do be aware it is subtle in
* places
*
* hwgroup->hwif is the interface in the group currently performing
* a command. hwgroup->drive is the drive and hwgroup->handler is
* the IRQ handler to call. As we issue a command the handlers
* step through multiple states, reassigning the handler to the
* next step in the process. Unlike a smart SCSI controller IDE
* expects the main processor to sequence the various transfer
* stages. We also manage a poll timer to catch up with most
* timeout situations. There are still a few where the handlers
* don't ever decide to give up.
*
* The handler eventually returns ide_stopped to indicate the
* request completed. At this point we issue the next request
* on the hwgroup and the process begins again.
*/
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.
*
* FIXME: unexpected_intr should be hwif-> then we can
* remove all the ifdef PCI crap
*/
#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.
*
* [Note - this can occur if the drive is hot unplugged]
*/
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
(
KERN_ERR
"%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
(
KERN_ERR
"%s: ide_intr: huh? expected NULL handler "
"on exit
\n
"
,
drive
->
name
);
}
}
spin_unlock_irqrestore
(
&
ide_lock
,
flags
);
}
EXPORT_SYMBOL
(
ide_intr
);
/**
* ide_init_drive_cmd - initialize a drive command request
* @rq: request object
*
* Initialize a request before we fill it in and send it down to
* ide_do_drive_cmd. Commands must be set up by this function. Right
* now it doesn't do a lot, but if that changes abusers will have a
* nasty suprise.
*/
void
ide_init_drive_cmd
(
struct
request
*
rq
)
{
memset
(
rq
,
0
,
sizeof
(
*
rq
));
rq
->
flags
=
REQ_DRIVE_CMD
;
}
EXPORT_SYMBOL
(
ide_init_drive_cmd
);
/**
* ide_do_drive_cmd - issue IDE special command
* @drive: device to issue command
* @rq: request to issue
* @action: action for processing
*
* 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
/*
* FIXME: there should be a drive or hwif->special
* handler that points here by default, not hacks
* in the ide-io.c code
*/
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
);
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