2005-04-17 02:20:36 +04:00
# include <linux/types.h>
# include <linux/string.h>
# include <linux/kernel.h>
2011-07-17 23:33:58 +04:00
# include <linux/export.h>
2005-04-17 02:20:36 +04:00
# include <linux/interrupt.h>
# include <linux/ide.h>
# include <linux/bitops.h>
/**
* ide_toggle_bounce - handle bounce buffering
* @ drive : drive to update
* @ on : on / off boolean
*
* Enable or disable bounce buffering for the device . Drives move
* between PIO and DMA and that changes the rules we need .
*/
2008-12-29 22:27:36 +03:00
2005-04-17 02:20:36 +04:00
void ide_toggle_bounce ( ide_drive_t * drive , int on )
{
u64 addr = BLK_BOUNCE_HIGH ; /* dma64_addr_t */
2005-11-19 01:13:33 +03:00
if ( ! PCI_DMA_BUS_IS_PHYS ) {
addr = BLK_BOUNCE_ANY ;
} else if ( on & & drive - > media = = ide_disk ) {
2008-02-02 01:09:31 +03:00
struct device * dev = drive - > hwif - > dev ;
if ( dev & & dev - > dma_mask )
addr = * dev - > dma_mask ;
2005-04-17 02:20:36 +04:00
}
if ( drive - > queue )
blk_queue_bounce_limit ( drive - > queue , addr ) ;
}
2009-04-08 16:13:02 +04:00
u64 ide_get_lba_addr ( struct ide_cmd * cmd , int lba48 )
2008-01-26 00:17:17 +03:00
{
2009-04-08 16:13:02 +04:00
struct ide_taskfile * tf = & cmd - > tf ;
2008-01-26 00:17:17 +03:00
u32 high , low ;
low = ( tf - > lbah < < 16 ) | ( tf - > lbam < < 8 ) | tf - > lbal ;
2009-04-08 16:13:02 +04:00
if ( lba48 ) {
tf = & cmd - > hob ;
high = ( tf - > lbah < < 16 ) | ( tf - > lbam < < 8 ) | tf - > lbal ;
} else
high = tf - > device & 0xf ;
2008-01-26 00:17:17 +03:00
return ( ( u64 ) high < < 24 ) | low ;
}
2008-01-26 00:17:17 +03:00
EXPORT_SYMBOL_GPL ( ide_get_lba_addr ) ;
2008-01-26 00:17:17 +03:00
static void ide_dump_sector ( ide_drive_t * drive )
{
2009-03-27 14:46:37 +03:00
struct ide_cmd cmd ;
struct ide_taskfile * tf = & cmd . tf ;
2008-10-13 23:39:36 +04:00
u8 lba48 = ! ! ( drive - > dev_flags & IDE_DFLAG_LBA48 ) ;
2008-01-26 00:17:17 +03:00
2009-03-27 14:46:37 +03:00
memset ( & cmd , 0 , sizeof ( cmd ) ) ;
2009-04-08 16:13:01 +04:00
if ( lba48 ) {
cmd . valid . in . tf = IDE_VALID_LBA ;
cmd . valid . in . hob = IDE_VALID_LBA ;
cmd . tf_flags = IDE_TFLAG_LBA48 ;
} else
cmd . valid . in . tf = IDE_VALID_LBA | IDE_VALID_DEVICE ;
2008-01-26 00:17:17 +03:00
2009-04-08 16:13:03 +04:00
ide_tf_readback ( drive , & cmd ) ;
2008-01-26 00:17:17 +03:00
if ( lba48 | | ( tf - > device & ATA_LBA ) )
2008-12-29 22:27:36 +03:00
printk ( KERN_CONT " , LBAsect=%llu " ,
2009-04-08 16:13:02 +04:00
( unsigned long long ) ide_get_lba_addr ( & cmd , lba48 ) ) ;
2008-01-26 00:17:17 +03:00
else
2008-12-29 22:27:36 +03:00
printk ( KERN_CONT " , CHS=%d/%d/%d " , ( tf - > lbah < < 8 ) + tf - > lbam ,
tf - > device & 0xf , tf - > lbal ) ;
2008-01-26 00:17:17 +03:00
}
2008-01-26 00:17:17 +03:00
static void ide_dump_ata_error ( ide_drive_t * drive , u8 err )
2005-04-17 02:20:36 +04:00
{
2009-05-22 18:23:37 +04:00
printk ( KERN_CONT " { " ) ;
2008-12-29 22:27:36 +03:00
if ( err & ATA_ABORTED )
printk ( KERN_CONT " DriveStatusError " ) ;
2008-10-11 00:39:21 +04:00
if ( err & ATA_ICRC )
2008-12-29 22:27:36 +03:00
printk ( KERN_CONT " %s " ,
( err & ATA_ABORTED ) ? " BadCRC " : " BadSector " ) ;
if ( err & ATA_UNC )
printk ( KERN_CONT " UncorrectableError " ) ;
if ( err & ATA_IDNF )
printk ( KERN_CONT " SectorIdNotFound " ) ;
if ( err & ATA_TRK0NF )
printk ( KERN_CONT " TrackZeroNotFound " ) ;
if ( err & ATA_AMNF )
printk ( KERN_CONT " AddrMarkNotFound " ) ;
printk ( KERN_CONT " } " ) ;
2008-10-11 00:39:21 +04:00
if ( ( err & ( ATA_BBK | ATA_ABORTED ) ) = = ATA_BBK | |
( err & ( ATA_UNC | ATA_IDNF | ATA_AMNF ) ) ) {
2009-01-06 19:20:50 +03:00
struct request * rq = drive - > hwif - > rq ;
2008-01-26 00:17:17 +03:00
ide_dump_sector ( drive ) ;
2009-01-06 19:20:50 +03:00
if ( rq )
2008-12-29 22:27:36 +03:00
printk ( KERN_CONT " , sector=%llu " ,
2009-05-07 17:24:40 +04:00
( unsigned long long ) blk_rq_pos ( rq ) ) ;
2005-04-17 02:20:36 +04:00
}
2008-12-29 22:27:36 +03:00
printk ( KERN_CONT " \n " ) ;
2008-01-26 00:17:17 +03:00
}
static void ide_dump_atapi_error ( ide_drive_t * drive , u8 err )
{
2009-05-22 18:23:37 +04:00
printk ( KERN_CONT " { " ) ;
2008-12-29 22:27:36 +03:00
if ( err & ATAPI_ILI )
printk ( KERN_CONT " IllegalLengthIndication " ) ;
if ( err & ATAPI_EOM )
printk ( KERN_CONT " EndOfMedia " ) ;
if ( err & ATA_ABORTED )
printk ( KERN_CONT " AbortedCommand " ) ;
if ( err & ATA_MCR )
printk ( KERN_CONT " MediaChangeRequested " ) ;
if ( err & ATAPI_LFS )
printk ( KERN_CONT " LastFailedSense=0x%02x " ,
( err & ATAPI_LFS ) > > 4 ) ;
printk ( KERN_CONT " } \n " ) ;
2005-04-17 02:20:36 +04:00
}
/**
2008-01-26 00:17:17 +03:00
* ide_dump_status - translate ATA / ATAPI error
2005-04-17 02:20:36 +04:00
* @ drive : drive that status applies to
* @ msg : text message to print
* @ stat : status byte to decode
*
* Error reporting , in human readable form ( luxurious , but a memory hog ) .
2008-01-26 00:17:17 +03:00
* Combines the drive name , message and status byte to provide a
* user understandable explanation of the device error .
2005-04-17 02:20:36 +04:00
*/
2008-01-26 00:17:17 +03:00
u8 ide_dump_status ( ide_drive_t * drive , const char * msg , u8 stat )
2005-04-17 02:20:36 +04:00
{
2008-01-26 00:17:12 +03:00
u8 err = 0 ;
2005-04-17 02:20:36 +04:00
2008-12-29 22:27:36 +03:00
printk ( KERN_ERR " %s: %s: status=0x%02x { " , drive - > name , msg , stat ) ;
2008-10-11 00:39:21 +04:00
if ( stat & ATA_BUSY )
2008-12-29 22:27:36 +03:00
printk ( KERN_CONT " Busy " ) ;
2005-04-17 02:20:36 +04:00
else {
2008-12-29 22:27:36 +03:00
if ( stat & ATA_DRDY )
printk ( KERN_CONT " DriveReady " ) ;
if ( stat & ATA_DF )
printk ( KERN_CONT " DeviceFault " ) ;
if ( stat & ATA_DSC )
printk ( KERN_CONT " SeekComplete " ) ;
if ( stat & ATA_DRQ )
printk ( KERN_CONT " DataRequest " ) ;
if ( stat & ATA_CORR )
printk ( KERN_CONT " CorrectedError " ) ;
2015-03-27 18:46:33 +03:00
if ( stat & ATA_SENSE )
printk ( KERN_CONT " Sense " ) ;
2008-12-29 22:27:36 +03:00
if ( stat & ATA_ERR )
printk ( KERN_CONT " Error " ) ;
2005-04-17 02:20:36 +04:00
}
2008-12-29 22:27:36 +03:00
printk ( KERN_CONT " } \n " ) ;
2008-10-11 00:39:21 +04:00
if ( ( stat & ( ATA_BUSY | ATA_ERR ) ) = = ATA_ERR ) {
2008-02-06 04:57:51 +03:00
err = ide_read_error ( drive ) ;
2008-12-29 22:27:36 +03:00
printk ( KERN_ERR " %s: %s: error=0x%02x " , drive - > name , msg , err ) ;
2008-01-26 00:17:17 +03:00
if ( drive - > media = = ide_disk )
ide_dump_ata_error ( drive , err ) ;
else
ide_dump_atapi_error ( drive , err ) ;
2005-04-17 02:20:36 +04:00
}
2009-05-22 18:23:38 +04:00
printk ( KERN_ERR " %s: possibly failed opcode: 0x%02x \n " ,
drive - > name , drive - > hwif - > cmd . tf . command ) ;
2008-01-26 00:17:12 +03:00
return err ;
2005-04-17 02:20:36 +04:00
}
EXPORT_SYMBOL ( ide_dump_status ) ;