2005-04-17 02:20:36 +04:00
/*
* 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/completion.h>
# include <linux/reboot.h>
# include <linux/cdrom.h>
# include <linux/seq_file.h>
# include <linux/device.h>
# include <linux/kmod.h>
# include <linux/scatterlist.h>
# include <asm/byteorder.h>
# include <asm/irq.h>
# include <asm/uaccess.h>
# include <asm/io.h>
# include <asm/bitops.h>
int __ide_end_request ( ide_drive_t * drive , struct request * rq , int uptodate ,
int nr_sectors )
{
int ret = 1 ;
BUG_ON ( ! ( rq - > flags & REQ_STARTED ) ) ;
/*
* if failfast is set on a request , override number of sectors and
* complete the whole request right now
*/
if ( blk_noretry_request ( rq ) & & end_io_error ( uptodate ) )
nr_sectors = rq - > hard_nr_sectors ;
if ( ! blk_fs_request ( rq ) & & end_io_error ( uptodate ) & & ! rq - > errors )
rq - > errors = - EIO ;
/*
* 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 ) )
blk_queue_end_tag ( drive - > queue , rq ) ;
blkdev_dequeue_request ( rq ) ;
HWGROUP ( drive ) - > rq = NULL ;
end_that_request_last ( rq ) ;
ret = 0 ;
}
return ret ;
}
EXPORT_SYMBOL ( __ide_end_request ) ;
/**
* 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 ;
if ( ! nr_sectors )
nr_sectors = rq - > hard_cur_sectors ;
if ( blk_complete_barrier_rq_locked ( drive - > queue , rq , nr_sectors ) )
ret = rq - > nr_sectors ! = 0 ;
else
ret = __ide_end_request ( drive , rq , uptodate , nr_sectors ) ;
spin_unlock_irqrestore ( & ide_lock , flags ) ;
return ret ;
}
EXPORT_SYMBOL ( ide_end_request ) ;
/*
* Power Management state machine . This one is rather trivial for now ,
* we should probably add more , like switching back to PIO on suspend
* to help some BIOSes , re - do the door locking on resume , etc . . .
*/
enum {
ide_pm_flush_cache = ide_pm_state_start_suspend ,
idedisk_pm_standby ,
idedisk_pm_idle = ide_pm_state_start_resume ,
ide_pm_restore_dma ,
} ;
static void ide_complete_power_step ( ide_drive_t * drive , struct request * rq , u8 stat , u8 error )
{
if ( drive - > media ! = ide_disk )
return ;
switch ( rq - > pm - > pm_step ) {
case ide_pm_flush_cache : /* Suspend step 1 (flush cache) complete */
2005-09-04 02:57:01 +04:00
if ( rq - > pm - > pm_state = = PM_EVENT_FREEZE )
2005-04-17 02:20:36 +04:00
rq - > pm - > pm_step = ide_pm_state_completed ;
else
rq - > pm - > pm_step = idedisk_pm_standby ;
break ;
case idedisk_pm_standby : /* Suspend step 2 (standby) complete */
rq - > pm - > pm_step = ide_pm_state_completed ;
break ;
case idedisk_pm_idle : /* Resume step 1 (idle) complete */
rq - > pm - > pm_step = ide_pm_restore_dma ;
break ;
}
}
static ide_startstop_t ide_start_power_step ( ide_drive_t * drive , struct request * rq )
{
ide_task_t * args = rq - > special ;
memset ( args , 0 , sizeof ( * args ) ) ;
if ( drive - > media ! = ide_disk ) {
/* skip idedisk_pm_idle for ATAPI devices */
if ( rq - > pm - > pm_step = = idedisk_pm_idle )
rq - > pm - > pm_step = ide_pm_restore_dma ;
}
switch ( rq - > pm - > pm_step ) {
case ide_pm_flush_cache : /* Suspend step 1 (flush cache) */
if ( drive - > media ! = ide_disk )
break ;
/* Not supported? Switch to next step now. */
if ( ! drive - > wcache | | ! ide_id_has_flush_cache ( drive - > id ) ) {
ide_complete_power_step ( drive , rq , 0 , 0 ) ;
return ide_stopped ;
}
if ( ide_id_has_flush_cache_ext ( drive - > id ) )
args - > tfRegister [ IDE_COMMAND_OFFSET ] = WIN_FLUSH_CACHE_EXT ;
else
args - > tfRegister [ IDE_COMMAND_OFFSET ] = WIN_FLUSH_CACHE ;
args - > command_type = IDE_DRIVE_TASK_NO_DATA ;
args - > handler = & task_no_data_intr ;
return do_rw_taskfile ( drive , args ) ;
case idedisk_pm_standby : /* Suspend step 2 (standby) */
args - > tfRegister [ IDE_COMMAND_OFFSET ] = WIN_STANDBYNOW1 ;
args - > command_type = IDE_DRIVE_TASK_NO_DATA ;
args - > handler = & task_no_data_intr ;
return do_rw_taskfile ( drive , args ) ;
case idedisk_pm_idle : /* Resume step 1 (idle) */
args - > tfRegister [ IDE_COMMAND_OFFSET ] = WIN_IDLEIMMEDIATE ;
args - > command_type = IDE_DRIVE_TASK_NO_DATA ;
args - > handler = task_no_data_intr ;
return do_rw_taskfile ( drive , args ) ;
case ide_pm_restore_dma : /* Resume step 2 (restore DMA) */
/*
* Right now , all we do is call hwif - > ide_dma_check ( drive ) ,
* we could be smarter and check for current xfer_speed
* in struct drive etc . . .
*/
if ( ( drive - > id - > capability & 1 ) = = 0 )
break ;
if ( drive - > hwif - > ide_dma_check = = NULL )
break ;
drive - > hwif - > ide_dma_check ( drive ) ;
break ;
}
rq - > pm - > pm_step = ide_pm_state_completed ;
return ide_stopped ;
}
/**
* ide_complete_pm_request - end the current Power Management request
* @ drive : target drive
* @ rq : request
*
* This function cleans up the current PM request and stops the queue
* if necessary .
*/
static void ide_complete_pm_request ( ide_drive_t * drive , struct request * rq )
{
unsigned long flags ;
# ifdef DEBUG_PM
printk ( " %s: completing PM request, %s \n " , drive - > name ,
blk_pm_suspend_request ( rq ) ? " suspend " : " resume " ) ;
# endif
spin_lock_irqsave ( & ide_lock , flags ) ;
if ( blk_pm_suspend_request ( rq ) ) {
blk_stop_queue ( drive - > queue ) ;
} else {
drive - > blocked = 0 ;
blk_start_queue ( drive - > queue ) ;
}
blkdev_dequeue_request ( rq ) ;
HWGROUP ( drive ) - > rq = NULL ;
end_that_request_last ( rq ) ;
spin_unlock_irqrestore ( & ide_lock , flags ) ;
}
/*
* FIXME : probably move this somewhere else , name is bad too : )
*/
u64 ide_get_error_location ( ide_drive_t * drive , char * args )
{
u32 high , low ;
u8 hcyl , lcyl , sect ;
u64 sector ;
high = 0 ;
hcyl = args [ 5 ] ;
lcyl = args [ 4 ] ;
sect = args [ 3 ] ;
if ( ide_id_has_flush_cache_ext ( drive - > id ) ) {
low = ( hcyl < < 16 ) | ( lcyl < < 8 ) | sect ;
HWIF ( drive ) - > OUTB ( drive - > ctl | 0x80 , IDE_CONTROL_REG ) ;
high = ide_read_24 ( drive ) ;
} else {
u8 cur = HWIF ( drive ) - > INB ( IDE_SELECT_REG ) ;
if ( cur & 0x40 ) {
high = cur & 0xf ;
low = ( hcyl < < 16 ) | ( lcyl < < 8 ) | sect ;
} else {
low = hcyl * drive - > head * drive - > sect ;
low + = lcyl * drive - > sect ;
low + = sect - 1 ;
}
}
sector = ( ( u64 ) high < < 24 ) | low ;
return sector ;
}
EXPORT_SYMBOL ( ide_get_error_location ) ;
/**
* 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 ] = ( data > > 8 ) & 0xFF ;
}
args - > tfRegister [ IDE_ERROR_OFFSET ] = err ;
/* be sure we're looking at the low order bits */
hwif - > OUTB ( drive - > ctl & ~ 0x80 , IDE_CONTROL_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 - > addressing = = 1 ) {
hwif - > OUTB ( drive - > ctl | 0x80 , IDE_CONTROL_REG ) ;
args - > hobRegister [ IDE_FEATURE_OFFSET ] = hwif - > INB ( IDE_FEATURE_REG ) ;
args - > hobRegister [ IDE_NSECTOR_OFFSET ] = hwif - > INB ( IDE_NSECTOR_REG ) ;
args - > hobRegister [ IDE_SECTOR_OFFSET ] = hwif - > INB ( IDE_SECTOR_REG ) ;
args - > hobRegister [ IDE_LCYL_OFFSET ] = hwif - > INB ( IDE_LCYL_REG ) ;
args - > hobRegister [ IDE_HCYL_OFFSET ] = hwif - > INB ( IDE_HCYL_REG ) ;
}
}
} else if ( blk_pm_request ( rq ) ) {
# ifdef DEBUG_PM
printk ( " %s: complete_power_step(step: %d, stat: %x, err: %x) \n " ,
drive - > name , rq - > pm - > pm_step , stat , err ) ;
# endif
ide_complete_power_step ( drive , rq , stat , err ) ;
if ( rq - > pm - > pm_step = = ide_pm_state_completed )
ide_complete_pm_request ( drive , rq ) ;
return ;
}
spin_lock_irqsave ( & ide_lock , flags ) ;
blkdev_dequeue_request ( rq ) ;
HWGROUP ( drive ) - > rq = NULL ;
rq - > errors = err ;
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 * .
*/
static 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 ) ;
}
}
static void ide_kill_rq ( ide_drive_t * drive , struct request * rq )
{
if ( rq - > rq_disk ) {
ide_driver_t * drv ;
drv = * ( ide_driver_t * * ) rq - > rq_disk - > private_data ;
drv - > end_request ( drive , 0 , 0 ) ;
} else
ide_end_request ( drive , 0 , 0 ) ;
}
static ide_startstop_t ide_ata_error ( ide_drive_t * drive , struct request * rq , u8 stat , u8 err )
{
ide_hwif_t * hwif = drive - > hwif ;
if ( stat & BUSY_STAT | | ( ( stat & WRERR_STAT ) & & ! drive - > nowerr ) ) {
/* other bits are useless when BUSY */
rq - > errors | = ERROR_RESET ;
} else if ( stat & ERR_STAT ) {
/* err has different meaning on cdrom and tape */
if ( err = = ABRT_ERR ) {
if ( drive - > select . b . lba & &
/* some newer drives don't support WIN_SPECIFY */
hwif - > INB ( IDE_COMMAND_REG ) = = WIN_SPECIFY )
return ide_stopped ;
} else if ( ( err & BAD_CRC ) = = BAD_CRC ) {
/* UDMA crc error, just retry the operation */
drive - > crc_count + + ;
} 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 ;
}
}
if ( ( stat & DRQ_STAT ) & & rq_data_dir ( rq ) = = READ )
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 | | blk_noretry_request ( rq ) )
ide_kill_rq ( drive , rq ) ;
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 ;
}
static ide_startstop_t ide_atapi_error ( ide_drive_t * drive , struct request * rq , u8 stat , u8 err )
{
ide_hwif_t * hwif = drive - > hwif ;
if ( stat & BUSY_STAT | | ( ( stat & WRERR_STAT ) & & ! drive - > nowerr ) ) {
/* other bits are useless when BUSY */
rq - > errors | = ERROR_RESET ;
} else {
/* add decoding error stuff */
}
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 ) {
ide_kill_rq ( drive , rq ) ;
} else {
if ( ( rq - > errors & ERROR_RESET ) = = ERROR_RESET ) {
+ + rq - > errors ;
return ide_do_reset ( drive ) ;
}
+ + rq - > errors ;
}
return ide_stopped ;
}
ide_startstop_t
__ide_error ( ide_drive_t * drive , struct request * rq , u8 stat , u8 err )
{
if ( drive - > media = = ide_disk )
return ide_ata_error ( drive , rq , stat , err ) ;
return ide_atapi_error ( drive , rq , stat , err ) ;
}
EXPORT_SYMBOL_GPL ( __ide_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 )
{
struct request * rq ;
u8 err ;
err = ide_dump_status ( drive , msg , stat ) ;
if ( ( rq = HWGROUP ( drive ) - > rq ) = = NULL )
return ide_stopped ;
/* retry only "normal" I/O: */
if ( rq - > flags & ( REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE ) ) {
rq - > errors = 1 ;
ide_end_drive_cmd ( drive , stat , err ) ;
return ide_stopped ;
}
if ( rq - > rq_disk ) {
ide_driver_t * drv ;
drv = * ( ide_driver_t * * ) rq - > rq_disk - > private_data ;
return drv - > error ( drive , rq , stat , err ) ;
} else
return __ide_error ( drive , rq , stat , err ) ;
}
EXPORT_SYMBOL_GPL ( ide_error ) ;
ide_startstop_t __ide_abort ( ide_drive_t * drive , struct request * rq )
{
if ( drive - > media ! = ide_disk )
rq - > errors | = ERROR_RESET ;
ide_kill_rq ( drive , rq ) ;
return ide_stopped ;
}
EXPORT_SYMBOL_GPL ( __ide_abort ) ;
/**
2005-09-10 11:26:54 +04:00
* ide_abort - abort pending IDE operations
2005-04-17 02:20:36 +04:00
* @ drive : drive the error occurred on
* @ msg : message to report
*
* ide_abort kills and cleans up when we are about to do a
* host initiated reset on active commands . Longer term we
* want handlers to have sensible abort handling themselves
*
* This differs fundamentally from ide_error because in
* this case the command is doing just fine when we
* blow it away .
*/
ide_startstop_t ide_abort ( ide_drive_t * drive , const char * msg )
{
struct request * rq ;
if ( drive = = NULL | | ( rq = HWGROUP ( drive ) - > rq ) = = NULL )
return ide_stopped ;
/* retry only "normal" I/O: */
if ( rq - > flags & ( REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE ) ) {
rq - > errors = 1 ;
ide_end_drive_cmd ( drive , BUSY_STAT , 0 ) ;
return ide_stopped ;
}
if ( rq - > rq_disk ) {
ide_driver_t * drv ;
drv = * ( ide_driver_t * * ) rq - > rq_disk - > private_data ;
return drv - > abort ( drive , rq ) ;
} else
return __ide_abort ( drive , rq ) ;
}
/**
* 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 .
*/
static void ide_cmd ( ide_drive_t * drive , u8 cmd , u8 nsect ,
ide_handler_t * handler )
{
ide_hwif_t * hwif = HWIF ( drive ) ;
if ( IDE_CONTROL_REG )
hwif - > OUTB ( drive - > ctl , IDE_CONTROL_REG ) ; /* clear nIEN */
SELECT_MASK ( drive , 0 ) ;
hwif - > OUTB ( nsect , IDE_NSECTOR_REG ) ;
ide_execute_command ( drive , cmd , handler , WAIT_CMD , NULL ) ;
}
/**
* 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 .
2005-09-10 11:26:54 +04:00
* We do any necessary data reading and then wait for the drive to
2005-04-17 02:20:36 +04:00
* go non busy . At that point we may read the error data and complete
* the request
*/
static 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 ide_error ( drive , " drive_cmd " , stat ) ;
/* calls ide_end_drive_cmd */
ide_end_drive_cmd ( drive , stat , hwif - > INB ( IDE_ERROR_REG ) ) ;
return ide_stopped ;
}
static void ide_init_specify_cmd ( ide_drive_t * drive , ide_task_t * task )
{
task - > tfRegister [ IDE_NSECTOR_OFFSET ] = drive - > sect ;
task - > tfRegister [ IDE_SECTOR_OFFSET ] = drive - > sect ;
task - > tfRegister [ IDE_LCYL_OFFSET ] = drive - > cyl ;
task - > tfRegister [ IDE_HCYL_OFFSET ] = drive - > cyl > > 8 ;
task - > tfRegister [ IDE_SELECT_OFFSET ] = ( ( drive - > head - 1 ) | drive - > select . all ) & 0xBF ;
task - > tfRegister [ IDE_COMMAND_OFFSET ] = WIN_SPECIFY ;
task - > handler = & set_geometry_intr ;
}
static void ide_init_restore_cmd ( ide_drive_t * drive , ide_task_t * task )
{
task - > tfRegister [ IDE_NSECTOR_OFFSET ] = drive - > sect ;
task - > tfRegister [ IDE_COMMAND_OFFSET ] = WIN_RESTORE ;
task - > handler = & recal_intr ;
}
static void ide_init_setmult_cmd ( ide_drive_t * drive , ide_task_t * task )
{
task - > tfRegister [ IDE_NSECTOR_OFFSET ] = drive - > mult_req ;
task - > tfRegister [ IDE_COMMAND_OFFSET ] = WIN_SETMULT ;
task - > handler = & set_multmode_intr ;
}
static ide_startstop_t ide_disk_special ( ide_drive_t * drive )
{
special_t * s = & drive - > special ;
ide_task_t args ;
memset ( & args , 0 , sizeof ( ide_task_t ) ) ;
args . command_type = IDE_DRIVE_TASK_NO_DATA ;
if ( s - > b . set_geometry ) {
s - > b . set_geometry = 0 ;
ide_init_specify_cmd ( drive , & args ) ;
} else if ( s - > b . recalibrate ) {
s - > b . recalibrate = 0 ;
ide_init_restore_cmd ( drive , & args ) ;
} else if ( s - > b . set_multmode ) {
s - > b . set_multmode = 0 ;
if ( drive - > mult_req > drive - > id - > max_multsect )
drive - > mult_req = drive - > id - > max_multsect ;
ide_init_setmult_cmd ( drive , & args ) ;
} else if ( s - > all ) {
int special = s - > all ;
s - > all = 0 ;
printk ( KERN_ERR " %s: bad special flag: 0x%02x \n " , drive - > name , special ) ;
return ide_stopped ;
}
do_rw_taskfile ( drive , & args ) ;
return ide_started ;
}
/**
* 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 .
*/
static 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 ) ;
return ide_stopped ;
} else {
if ( drive - > media = = ide_disk )
return ide_disk_special ( drive ) ;
s - > all = 0 ;
drive - > mult_req = 0 ;
return ide_stopped ;
}
}
void ide_map_sg ( ide_drive_t * drive , struct request * rq )
{
ide_hwif_t * hwif = drive - > hwif ;
struct scatterlist * sg = hwif - > sg_table ;
if ( hwif - > sg_mapped ) /* needed by ide-scsi */
return ;
if ( ( rq - > flags & REQ_DRIVE_TASKFILE ) = = 0 ) {
hwif - > sg_nents = blk_rq_map_sg ( drive - > queue , rq , sg ) ;
} else {
sg_init_one ( sg , rq - > buffer , rq - > nr_sectors * SECTOR_SIZE ) ;
hwif - > sg_nents = 1 ;
}
}
EXPORT_SYMBOL_GPL ( ide_map_sg ) ;
void ide_init_sg_cmd ( ide_drive_t * drive , struct request * rq )
{
ide_hwif_t * hwif = drive - > hwif ;
hwif - > nsect = hwif - > nleft = rq - > nr_sectors ;
hwif - > cursg = hwif - > cursg_ofs = 0 ;
}
EXPORT_SYMBOL_GPL ( ide_init_sg_cmd ) ;
/**
* execute_drive_command - issue special drive command
2005-09-10 11:26:54 +04:00
* @ drive : the drive to issue the command on
2005-04-17 02:20:36 +04:00
* @ 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
*/
static 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 ;
hwif - > data_phase = args - > data_phase ;
switch ( hwif - > data_phase ) {
case TASKFILE_MULTI_OUT :
case TASKFILE_OUT :
case TASKFILE_MULTI_IN :
case TASKFILE_IN :
ide_init_sg_cmd ( drive , rq ) ;
ide_map_sg ( drive , rq ) ;
default :
break ;
}
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 ;
}
/**
* 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
*/
static ide_startstop_t start_request ( ide_drive_t * drive , struct request * rq )
{
ide_startstop_t startstop ;
sector_t 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 ;
}
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 ( blk_pm_suspend_request ( rq ) & &
rq - > pm - > pm_step = = ide_pm_state_start_suspend )
/* Mark drive blocked when starting the suspend sequence. */
drive - > blocked = 1 ;
else if ( blk_pm_resume_request ( rq ) & &
rq - > pm - > pm_step = = ide_pm_state_start_resume ) {
/*
* The first thing we do on wakeup is to wait for BSY bit to
* go away ( with a looong timeout ) as a drive on this hwif may
* just be POSTing itself .
* We do that before even selecting as the " other " device on
* the bus may be broken enough to walk on our toes at this
* point .
*/
int rc ;
# ifdef DEBUG_PM
printk ( " %s: Wakeup request inited, waiting for !BSY... \n " , drive - > name ) ;
# endif
rc = ide_wait_not_busy ( HWIF ( drive ) , 35000 ) ;
if ( rc )
printk ( KERN_WARNING " %s: bus not ready on wakeup \n " , drive - > name ) ;
SELECT_DRIVE ( drive ) ;
HWIF ( drive ) - > OUTB ( 8 , HWIF ( drive ) - > io_ports [ IDE_CONTROL_OFFSET ] ) ;
rc = ide_wait_not_busy ( HWIF ( drive ) , 10000 ) ;
if ( rc )
printk ( KERN_WARNING " %s: drive not ready on wakeup \n " , drive - > name ) ;
}
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 ) {
ide_driver_t * drv ;
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 ) ;
else if ( blk_pm_request ( rq ) ) {
# ifdef DEBUG_PM
printk ( " %s: start_power_step(step: %d) \n " ,
drive - > name , rq - > pm - > pm_step ) ;
# endif
startstop = ide_start_power_step ( drive , rq ) ;
if ( startstop = = ide_stopped & &
rq - > pm - > pm_step = = ide_pm_state_completed )
ide_complete_pm_request ( drive , rq ) ;
return startstop ;
}
drv = * ( ide_driver_t * * ) rq - > rq_disk - > private_data ;
return drv - > do_request ( drive , rq , block ) ;
}
return do_special ( drive ) ;
kill_rq :
ide_kill_rq ( drive , rq ) ;
return ide_stopped ;
}
/**
* 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 ;
drive - > sleeping = 1 ;
}
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 necessary 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 ;
/*
* drive is doing pre - flush , ordered write , post - flush sequence . even
* though that is 3 requests , it must be seen as a single transaction .
* we must not preempt this drive until that is complete
*/
if ( blk_queue_flushing ( drive - > queue ) ) {
/*
* small race where queue could get replugged during
* the 3 - request flush cycle , just yank the plug since
* we want it to finish asap
*/
blk_remove_plug ( drive - > queue ) ;
return drive ;
}
do {
if ( ( ! drive - > sleeping | | time_after_eq ( jiffies , drive - > sleep ) )
& & ! elv_queue_empty ( drive - > queue ) ) {
if ( ! best
| | ( drive - > sleeping & & ( ! best - > sleeping | | time_before ( drive - > sleep , best - > sleep ) ) )
| | ( ! best - > sleeping & & time_before ( WAKEUP ( drive ) , WAKEUP ( best ) ) ) )
{
if ( ! blk_queue_plugged ( drive - > queue ) )
best = drive ;
}
}
} while ( ( drive = drive - > next ) ! = hwgroup - > drive ) ;
if ( best & & best - > nice1 & & ! best - > sleeping & & 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 - > sleeping
& & time_before ( jiffies - best - > service_time , WAKEUP ( drive ) )
& & time_before ( WAKEUP ( drive ) , jiffies + t ) )
{
ide_stall_queue ( best , min_t ( long , 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 .
*/
static 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 ;
2005-10-09 04:37:47 +04:00
int loops = 0 ;
2005-04-17 02:20:36 +04:00
/* for atari only: POSSIBLY BROKEN HERE(?) */
ide_get_lock ( ide_intr , hwgroup ) ;
/* caller must own ide_lock */
BUG_ON ( ! irqs_disabled ( ) ) ;
while ( ! hwgroup - > busy ) {
hwgroup - > busy = 1 ;
drive = choose_drive ( hwgroup ) ;
if ( drive = = NULL ) {
int sleeping = 0 ;
unsigned long sleep = 0 ; /* shut up, gcc */
hwgroup - > rq = NULL ;
drive = hwgroup - > drive ;
do {
if ( drive - > sleeping & & ( ! sleeping | | time_before ( drive - > sleep , sleep ) ) ) {
sleeping = 1 ;
sleep = drive - > sleep ;
}
} while ( ( drive = drive - > next ) ! = hwgroup - > drive ) ;
if ( sleeping ) {
/*
* 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 ( ) ;
hwgroup - > busy = 0 ;
}
/* no more work for this hwgroup (for now) */
return ;
}
2005-10-09 04:37:47 +04:00
again :
2005-04-17 02:20:36 +04:00
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 - > sleeping = 0 ;
drive - > service_start = jiffies ;
if ( blk_queue_plugged ( drive - > queue ) ) {
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 = 0 ;
break ;
}
/*
* Sanity : don ' t accept a request that isn ' t a PM request
* if we are currently power managed . This is very important as
* blk_stop_queue ( ) doesn ' t prevent the elv_next_request ( )
* above to return us whatever is in the queue . Since we call
* ide_do_request ( ) ourselves , we end up taking requests while
* the queue is blocked . . .
*
* We let requests forced at head of queue with ide - preempt
* though . I hope that doesn ' t happen too much , hopefully not
* unless the subdriver triggers such a thing in its own PM
* state machine .
2005-10-09 04:37:47 +04:00
*
* We count how many times we loop here to make sure we service
* all drives in the hwgroup without looping for ever
2005-04-17 02:20:36 +04:00
*/
if ( drive - > blocked & & ! blk_pm_request ( rq ) & & ! ( rq - > flags & REQ_PREEMPT ) ) {
2005-10-09 04:37:47 +04:00
drive = drive - > next ? drive - > next : hwgroup - > drive ;
if ( loops + + < 4 & & ! blk_queue_plugged ( drive - > queue ) )
goto again ;
2005-04-17 02:20:36 +04:00
/* We clear busy, there should be no pending ATA command at this point. */
hwgroup - > busy = 0 ;
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 ! = IDE_NO_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 ! = IDE_NO_IRQ & & hwif - > irq ! = masked_irq )
enable_irq ( hwif - > irq ) ;
if ( startstop = = ide_stopped )
hwgroup - > busy = 0 ;
}
}
/*
* Passes the stuff to ide_do_request
*/
void do_ide_request ( request_queue_t * q )
{
ide_drive_t * drive = q - > queuedata ;
ide_do_request ( HWGROUP ( drive ) , IDE_NO_IRQ ) ;
}
/*
* 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
*/
static ide_startstop_t ide_dma_timeout_retry ( ide_drive_t * drive , int error )
{
ide_hwif_t * hwif = HWIF ( drive ) ;
struct request * rq ;
ide_startstop_t ret = ide_stopped ;
/*
* end current dma transaction
*/
if ( error < 0 ) {
printk ( KERN_WARNING " %s: DMA timeout error \n " , drive - > name ) ;
( void ) HWIF ( drive ) - > ide_dma_end ( drive ) ;
ret = ide_error ( drive , " dma timeout error " ,
hwif - > INB ( IDE_STATUS_REG ) ) ;
} else {
printk ( KERN_WARNING " %s: DMA timeout retry \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 ;
if ( ! rq - > bio )
goto out ;
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 ;
rq - > buffer = bio_data ( rq - > bio ) ;
out :
return ret ;
}
/**
* 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 = - 1 ;
spin_lock_irqsave ( & ide_lock , flags ) ;
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 - > polling ) {
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_dma_timeout_retry ( drive , wait ) ;
} else
startstop =
ide_error ( drive , " irq timeout " , hwif - > INB ( IDE_STATUS_REG ) ) ;
}
drive - > service_time = jiffies - drive - > service_start ;
spin_lock_irq ( & ide_lock ) ;
enable_irq ( hwif - > irq ) ;
if ( startstop = = ide_stopped )
hwgroup - > busy = 0 ;
}
}
ide_do_request ( hwgroup , IDE_NO_IRQ ) ;
spin_unlock_irqrestore ( & ide_lock , flags ) ;
}
/**
* 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 .
*/
irqreturn_t 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 IRQ_NONE ;
}
if ( ( handler = hwgroup - > handler ) = = NULL | | hwgroup - > polling ) {
/*
* 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 IRQ_NONE ;
}
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 IRQ_HANDLED ;
}
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 IRQ_NONE ;
}
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 .
*/
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 ) ;
return IRQ_HANDLED ;
}
/**
* 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 ;
rq - > ref_count = 1 ;
}
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 where = ELEVATOR_INSERT_BACK , err ;
int must_wait = ( action = = ide_wait | | action = = ide_head_wait ) ;
rq - > errors = 0 ;
rq - > rq_status = RQ_ACTIVE ;
/*
* we need to hold an extra reference to request for safe inspection
* after completion
*/
if ( must_wait ) {
rq - > ref_count + + ;
rq - > waiting = & wait ;
rq - > end_io = blk_end_sync_rq ;
}
spin_lock_irqsave ( & ide_lock , flags ) ;
if ( action = = ide_preempt )
hwgroup - > rq = NULL ;
if ( action = = ide_preempt | | action = = ide_head_wait ) {
where = ELEVATOR_INSERT_FRONT ;
rq - > flags | = REQ_PREEMPT ;
}
__elv_add_request ( drive - > queue , rq , where , 0 ) ;
ide_do_request ( hwgroup , IDE_NO_IRQ ) ;
spin_unlock_irqrestore ( & ide_lock , flags ) ;
err = 0 ;
if ( must_wait ) {
wait_for_completion ( & wait ) ;
rq - > waiting = NULL ;
if ( rq - > errors )
err = - EIO ;
blk_put_request ( rq ) ;
}
return err ;
}
EXPORT_SYMBOL ( ide_do_drive_cmd ) ;