mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-24 02:18:54 +00:00
88b2b32bab
* Convert {ide_hwif_t,ide_pci_device_t}->host_flag to be u16. * Add IDE_HFLAG_POST_SET_MODE host flag to indicate the need to program the host for the transfer mode after programming the device. Set it in au1xxx-ide, amd74xx, cs5530, cs5535, pdc202xx_new, sc1200, pmac and via82cxxx host drivers. * Add IDE_HFLAG_NO_SET_MODE host flag to indicate the need to completely skip programming of host/device for the transfer mode ("smart" hosts). Set it in it821x host driver and check it in ide_tune_dma(). * Add ide_set_pio_mode()/ide_set_dma_mode() helpers and convert all direct ->set_pio_mode/->speedproc users to use these helpers. * Move ide_config_drive_speed() calls from ->set_pio_mode/->speedproc methods to callers. * Rename ->speedproc method to ->set_dma_mode, make it void and update all implementations accordingly. * Update ide_set_xfer_rate() comments. * Unexport ide_config_drive_speed(). v2: * Fix issues noticed by Sergei: - export ide_set_dma_mode() instead of moving ->set_pio_mode abuse wrt to setting DMA modes from sc1200_set_pio_mode() to do_special() - check IDE_HFLAG_NO_SET_MODE in ide_tune_dma() - check for (hwif->set_pio_mode) == NULL in ide_set_pio_mode() - check for (hwif->set_dma_mode) == NULL in ide_set_dma_mode() - return -1 from ide_set_{pio,dma}_mode() if ->set_{pio,dma}_mode == NULL - don't set ->set_{pio,dma}_mode on it821x in "smart" mode - fix build problem in pmac.c - minor fixes in au1xxx-ide.c/cs5530.c/siimage.c - improve patch description Changes in behavior caused by this patch: - HDIO_SET_PIO_MODE ioctl would now return -ENOSYS for attempts to change PIO mode if it821x controller is in "smart" mode - removal of two debugging printk-s (from cs5530.c and sc1200.c) - transfer modes 0x00-0x07 passed from user space may be programmed twice on the device (not really an issue since 0x00 is not supported correctly by any host driver ATM, 0x01 is not supported at all and 0x02-0x07 are invalid) Acked-by: Sergei Shtylyov <sshtylyov@ru.mvista.com> Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
633 lines
16 KiB
C
633 lines
16 KiB
C
#include <linux/module.h>
|
|
#include <linux/types.h>
|
|
#include <linux/string.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/timer.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/major.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/genhd.h>
|
|
#include <linux/blkpg.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/pci.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/hdreg.h>
|
|
#include <linux/ide.h>
|
|
#include <linux/bitops.h>
|
|
|
|
#include <asm/byteorder.h>
|
|
#include <asm/irq.h>
|
|
#include <asm/uaccess.h>
|
|
#include <asm/io.h>
|
|
|
|
/*
|
|
* IDE library routines. These are plug in code that most
|
|
* drivers can use but occasionally may be weird enough
|
|
* to want to do their own thing with
|
|
*
|
|
* Add common non I/O op stuff here. Make sure it has proper
|
|
* kernel-doc function headers or your patch will be rejected
|
|
*/
|
|
|
|
|
|
/**
|
|
* ide_xfer_verbose - return IDE mode names
|
|
* @xfer_rate: rate to name
|
|
*
|
|
* Returns a constant string giving the name of the mode
|
|
* requested.
|
|
*/
|
|
|
|
char *ide_xfer_verbose (u8 xfer_rate)
|
|
{
|
|
switch(xfer_rate) {
|
|
case XFER_UDMA_7: return("UDMA 7");
|
|
case XFER_UDMA_6: return("UDMA 6");
|
|
case XFER_UDMA_5: return("UDMA 5");
|
|
case XFER_UDMA_4: return("UDMA 4");
|
|
case XFER_UDMA_3: return("UDMA 3");
|
|
case XFER_UDMA_2: return("UDMA 2");
|
|
case XFER_UDMA_1: return("UDMA 1");
|
|
case XFER_UDMA_0: return("UDMA 0");
|
|
case XFER_MW_DMA_2: return("MW DMA 2");
|
|
case XFER_MW_DMA_1: return("MW DMA 1");
|
|
case XFER_MW_DMA_0: return("MW DMA 0");
|
|
case XFER_SW_DMA_2: return("SW DMA 2");
|
|
case XFER_SW_DMA_1: return("SW DMA 1");
|
|
case XFER_SW_DMA_0: return("SW DMA 0");
|
|
case XFER_PIO_4: return("PIO 4");
|
|
case XFER_PIO_3: return("PIO 3");
|
|
case XFER_PIO_2: return("PIO 2");
|
|
case XFER_PIO_1: return("PIO 1");
|
|
case XFER_PIO_0: return("PIO 0");
|
|
case XFER_PIO_SLOW: return("PIO SLOW");
|
|
default: return("XFER ERROR");
|
|
}
|
|
}
|
|
|
|
EXPORT_SYMBOL(ide_xfer_verbose);
|
|
|
|
/**
|
|
* ide_rate_filter - filter transfer mode
|
|
* @drive: IDE device
|
|
* @speed: desired speed
|
|
*
|
|
* Given the available transfer modes this function returns
|
|
* the best available speed at or below the speed requested.
|
|
*
|
|
* TODO: check device PIO capabilities
|
|
*/
|
|
|
|
static u8 ide_rate_filter(ide_drive_t *drive, u8 speed)
|
|
{
|
|
ide_hwif_t *hwif = drive->hwif;
|
|
u8 mode = ide_find_dma_mode(drive, speed);
|
|
|
|
if (mode == 0) {
|
|
if (hwif->pio_mask)
|
|
mode = fls(hwif->pio_mask) - 1 + XFER_PIO_0;
|
|
else
|
|
mode = XFER_PIO_4;
|
|
}
|
|
|
|
// printk("%s: mode 0x%02x, speed 0x%02x\n", __FUNCTION__, mode, speed);
|
|
|
|
return min(speed, mode);
|
|
}
|
|
|
|
int ide_use_fast_pio(ide_drive_t *drive)
|
|
{
|
|
struct hd_driveid *id = drive->id;
|
|
|
|
if ((id->capability & 1) && drive->autodma)
|
|
return 1;
|
|
|
|
if ((id->capability & 8) || (id->field_valid & 2))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(ide_use_fast_pio);
|
|
|
|
/*
|
|
* Standard (generic) timings for PIO modes, from ATA2 specification.
|
|
* These timings are for access to the IDE data port register *only*.
|
|
* Some drives may specify a mode, while also specifying a different
|
|
* value for cycle_time (from drive identification data).
|
|
*/
|
|
const ide_pio_timings_t ide_pio_timings[6] = {
|
|
{ 70, 165, 600 }, /* PIO Mode 0 */
|
|
{ 50, 125, 383 }, /* PIO Mode 1 */
|
|
{ 30, 100, 240 }, /* PIO Mode 2 */
|
|
{ 30, 80, 180 }, /* PIO Mode 3 with IORDY */
|
|
{ 25, 70, 120 }, /* PIO Mode 4 with IORDY */
|
|
{ 20, 50, 100 } /* PIO Mode 5 with IORDY (nonstandard) */
|
|
};
|
|
|
|
EXPORT_SYMBOL_GPL(ide_pio_timings);
|
|
|
|
/*
|
|
* Shared data/functions for determining best PIO mode for an IDE drive.
|
|
* Most of this stuff originally lived in cmd640.c, and changes to the
|
|
* ide_pio_blacklist[] table should be made with EXTREME CAUTION to avoid
|
|
* breaking the fragile cmd640.c support.
|
|
*/
|
|
|
|
/*
|
|
* Black list. Some drives incorrectly report their maximal PIO mode,
|
|
* at least in respect to CMD640. Here we keep info on some known drives.
|
|
*/
|
|
static struct ide_pio_info {
|
|
const char *name;
|
|
int pio;
|
|
} ide_pio_blacklist [] = {
|
|
/* { "Conner Peripherals 1275MB - CFS1275A", 4 }, */
|
|
{ "Conner Peripherals 540MB - CFS540A", 3 },
|
|
|
|
{ "WDC AC2700", 3 },
|
|
{ "WDC AC2540", 3 },
|
|
{ "WDC AC2420", 3 },
|
|
{ "WDC AC2340", 3 },
|
|
{ "WDC AC2250", 0 },
|
|
{ "WDC AC2200", 0 },
|
|
{ "WDC AC21200", 4 },
|
|
{ "WDC AC2120", 0 },
|
|
{ "WDC AC2850", 3 },
|
|
{ "WDC AC1270", 3 },
|
|
{ "WDC AC1170", 1 },
|
|
{ "WDC AC1210", 1 },
|
|
{ "WDC AC280", 0 },
|
|
/* { "WDC AC21000", 4 }, */
|
|
{ "WDC AC31000", 3 },
|
|
{ "WDC AC31200", 3 },
|
|
/* { "WDC AC31600", 4 }, */
|
|
|
|
{ "Maxtor 7131 AT", 1 },
|
|
{ "Maxtor 7171 AT", 1 },
|
|
{ "Maxtor 7213 AT", 1 },
|
|
{ "Maxtor 7245 AT", 1 },
|
|
{ "Maxtor 7345 AT", 1 },
|
|
{ "Maxtor 7546 AT", 3 },
|
|
{ "Maxtor 7540 AV", 3 },
|
|
|
|
{ "SAMSUNG SHD-3121A", 1 },
|
|
{ "SAMSUNG SHD-3122A", 1 },
|
|
{ "SAMSUNG SHD-3172A", 1 },
|
|
|
|
/* { "ST51080A", 4 },
|
|
* { "ST51270A", 4 },
|
|
* { "ST31220A", 4 },
|
|
* { "ST31640A", 4 },
|
|
* { "ST32140A", 4 },
|
|
* { "ST3780A", 4 },
|
|
*/
|
|
{ "ST5660A", 3 },
|
|
{ "ST3660A", 3 },
|
|
{ "ST3630A", 3 },
|
|
{ "ST3655A", 3 },
|
|
{ "ST3391A", 3 },
|
|
{ "ST3390A", 1 },
|
|
{ "ST3600A", 1 },
|
|
{ "ST3290A", 0 },
|
|
{ "ST3144A", 0 },
|
|
{ "ST3491A", 1 }, /* reports 3, should be 1 or 2 (depending on */
|
|
/* drive) according to Seagates FIND-ATA program */
|
|
|
|
{ "QUANTUM ELS127A", 0 },
|
|
{ "QUANTUM ELS170A", 0 },
|
|
{ "QUANTUM LPS240A", 0 },
|
|
{ "QUANTUM LPS210A", 3 },
|
|
{ "QUANTUM LPS270A", 3 },
|
|
{ "QUANTUM LPS365A", 3 },
|
|
{ "QUANTUM LPS540A", 3 },
|
|
{ "QUANTUM LIGHTNING 540A", 3 },
|
|
{ "QUANTUM LIGHTNING 730A", 3 },
|
|
|
|
{ "QUANTUM FIREBALL_540", 3 }, /* Older Quantum Fireballs don't work */
|
|
{ "QUANTUM FIREBALL_640", 3 },
|
|
{ "QUANTUM FIREBALL_1080", 3 },
|
|
{ "QUANTUM FIREBALL_1280", 3 },
|
|
{ NULL, 0 }
|
|
};
|
|
|
|
/**
|
|
* ide_scan_pio_blacklist - check for a blacklisted drive
|
|
* @model: Drive model string
|
|
*
|
|
* This routine searches the ide_pio_blacklist for an entry
|
|
* matching the start/whole of the supplied model name.
|
|
*
|
|
* Returns -1 if no match found.
|
|
* Otherwise returns the recommended PIO mode from ide_pio_blacklist[].
|
|
*/
|
|
|
|
static int ide_scan_pio_blacklist (char *model)
|
|
{
|
|
struct ide_pio_info *p;
|
|
|
|
for (p = ide_pio_blacklist; p->name != NULL; p++) {
|
|
if (strncmp(p->name, model, strlen(p->name)) == 0)
|
|
return p->pio;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
unsigned int ide_pio_cycle_time(ide_drive_t *drive, u8 pio)
|
|
{
|
|
struct hd_driveid *id = drive->id;
|
|
int cycle_time = 0;
|
|
|
|
if (id->field_valid & 2) {
|
|
if (id->capability & 8)
|
|
cycle_time = id->eide_pio_iordy;
|
|
else
|
|
cycle_time = id->eide_pio;
|
|
}
|
|
|
|
/* conservative "downgrade" for all pre-ATA2 drives */
|
|
if (pio < 3) {
|
|
if (cycle_time && cycle_time < ide_pio_timings[pio].cycle_time)
|
|
cycle_time = 0; /* use standard timing */
|
|
}
|
|
|
|
return cycle_time ? cycle_time : ide_pio_timings[pio].cycle_time;
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(ide_pio_cycle_time);
|
|
|
|
/**
|
|
* ide_get_best_pio_mode - get PIO mode from drive
|
|
* @drive: drive to consider
|
|
* @mode_wanted: preferred mode
|
|
* @max_mode: highest allowed mode
|
|
*
|
|
* This routine returns the recommended PIO settings for a given drive,
|
|
* based on the drive->id information and the ide_pio_blacklist[].
|
|
*
|
|
* Drive PIO mode is auto-selected if 255 is passed as mode_wanted.
|
|
* This is used by most chipset support modules when "auto-tuning".
|
|
*/
|
|
|
|
u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode)
|
|
{
|
|
int pio_mode;
|
|
struct hd_driveid* id = drive->id;
|
|
int overridden = 0;
|
|
|
|
if (mode_wanted != 255)
|
|
return min_t(u8, mode_wanted, max_mode);
|
|
|
|
if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_BLACKLIST) == 0 &&
|
|
(pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
|
|
printk(KERN_INFO "%s: is on PIO blacklist\n", drive->name);
|
|
} else {
|
|
pio_mode = id->tPIO;
|
|
if (pio_mode > 2) { /* 2 is maximum allowed tPIO value */
|
|
pio_mode = 2;
|
|
overridden = 1;
|
|
}
|
|
if (id->field_valid & 2) { /* drive implements ATA2? */
|
|
if (id->capability & 8) { /* IORDY supported? */
|
|
if (id->eide_pio_modes & 7) {
|
|
overridden = 0;
|
|
if (id->eide_pio_modes & 4)
|
|
pio_mode = 5;
|
|
else if (id->eide_pio_modes & 2)
|
|
pio_mode = 4;
|
|
else
|
|
pio_mode = 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (overridden)
|
|
printk(KERN_INFO "%s: tPIO > 2, assuming tPIO = 2\n",
|
|
drive->name);
|
|
|
|
/*
|
|
* Conservative "downgrade" for all pre-ATA2 drives
|
|
*/
|
|
if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_DOWNGRADE) == 0 &&
|
|
pio_mode && pio_mode < 4) {
|
|
pio_mode--;
|
|
printk(KERN_INFO "%s: applying conservative "
|
|
"PIO \"downgrade\"\n", drive->name);
|
|
}
|
|
}
|
|
|
|
if (pio_mode > max_mode)
|
|
pio_mode = max_mode;
|
|
|
|
return pio_mode;
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(ide_get_best_pio_mode);
|
|
|
|
/* req_pio == "255" for auto-tune */
|
|
void ide_set_pio(ide_drive_t *drive, u8 req_pio)
|
|
{
|
|
ide_hwif_t *hwif = drive->hwif;
|
|
u8 host_pio, pio;
|
|
|
|
if (hwif->set_pio_mode == NULL)
|
|
return;
|
|
|
|
BUG_ON(hwif->pio_mask == 0x00);
|
|
|
|
host_pio = fls(hwif->pio_mask) - 1;
|
|
|
|
pio = ide_get_best_pio_mode(drive, req_pio, host_pio);
|
|
|
|
/*
|
|
* TODO:
|
|
* - report device max PIO mode
|
|
* - check req_pio != 255 against device max PIO mode
|
|
*/
|
|
printk(KERN_DEBUG "%s: host max PIO%d wanted PIO%d%s selected PIO%d\n",
|
|
drive->name, host_pio, req_pio,
|
|
req_pio == 255 ? "(auto-tune)" : "", pio);
|
|
|
|
(void)ide_set_pio_mode(drive, XFER_PIO_0 + pio);
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(ide_set_pio);
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
|
|
void ide_toggle_bounce(ide_drive_t *drive, int on)
|
|
{
|
|
u64 addr = BLK_BOUNCE_HIGH; /* dma64_addr_t */
|
|
|
|
if (!PCI_DMA_BUS_IS_PHYS) {
|
|
addr = BLK_BOUNCE_ANY;
|
|
} else if (on && drive->media == ide_disk) {
|
|
if (HWIF(drive)->pci_dev)
|
|
addr = HWIF(drive)->pci_dev->dma_mask;
|
|
}
|
|
|
|
if (drive->queue)
|
|
blk_queue_bounce_limit(drive->queue, addr);
|
|
}
|
|
|
|
int ide_set_pio_mode(ide_drive_t *drive, const u8 mode)
|
|
{
|
|
ide_hwif_t *hwif = drive->hwif;
|
|
|
|
if (hwif->set_pio_mode == NULL)
|
|
return -1;
|
|
|
|
/*
|
|
* TODO: temporary hack for some legacy host drivers that didn't
|
|
* set transfer mode on the device in ->set_pio_mode method...
|
|
*/
|
|
if (hwif->set_dma_mode == NULL) {
|
|
hwif->set_pio_mode(drive, mode - XFER_PIO_0);
|
|
return 0;
|
|
}
|
|
|
|
if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
|
|
if (ide_config_drive_speed(drive, mode))
|
|
return -1;
|
|
hwif->set_pio_mode(drive, mode - XFER_PIO_0);
|
|
return 0;
|
|
} else {
|
|
hwif->set_pio_mode(drive, mode - XFER_PIO_0);
|
|
return ide_config_drive_speed(drive, mode);
|
|
}
|
|
}
|
|
|
|
int ide_set_dma_mode(ide_drive_t *drive, const u8 mode)
|
|
{
|
|
ide_hwif_t *hwif = drive->hwif;
|
|
|
|
if (hwif->set_dma_mode == NULL)
|
|
return -1;
|
|
|
|
if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
|
|
if (ide_config_drive_speed(drive, mode))
|
|
return -1;
|
|
hwif->set_dma_mode(drive, mode);
|
|
return 0;
|
|
} else {
|
|
hwif->set_dma_mode(drive, mode);
|
|
return ide_config_drive_speed(drive, mode);
|
|
}
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(ide_set_dma_mode);
|
|
|
|
/**
|
|
* ide_set_xfer_rate - set transfer rate
|
|
* @drive: drive to set
|
|
* @rate: speed to attempt to set
|
|
*
|
|
* General helper for setting the speed of an IDE device. This
|
|
* function knows about user enforced limits from the configuration
|
|
* which ->set_pio_mode/->set_dma_mode does not.
|
|
*/
|
|
|
|
int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
|
|
{
|
|
ide_hwif_t *hwif = drive->hwif;
|
|
|
|
if (hwif->set_dma_mode == NULL)
|
|
return -1;
|
|
|
|
rate = ide_rate_filter(drive, rate);
|
|
|
|
if (rate >= XFER_PIO_0 && rate <= XFER_PIO_5)
|
|
return ide_set_pio_mode(drive, rate);
|
|
|
|
/*
|
|
* TODO: transfer modes 0x00-0x07 passed from the user-space are
|
|
* currently handled here which needs fixing (please note that such
|
|
* case could happen iff the transfer mode has already been set on
|
|
* the device by ide-proc.c::set_xfer_rate()).
|
|
*/
|
|
|
|
return ide_set_dma_mode(drive, rate);
|
|
}
|
|
|
|
static void ide_dump_opcode(ide_drive_t *drive)
|
|
{
|
|
struct request *rq;
|
|
u8 opcode = 0;
|
|
int found = 0;
|
|
|
|
spin_lock(&ide_lock);
|
|
rq = NULL;
|
|
if (HWGROUP(drive))
|
|
rq = HWGROUP(drive)->rq;
|
|
spin_unlock(&ide_lock);
|
|
if (!rq)
|
|
return;
|
|
if (rq->cmd_type == REQ_TYPE_ATA_CMD ||
|
|
rq->cmd_type == REQ_TYPE_ATA_TASK) {
|
|
char *args = rq->buffer;
|
|
if (args) {
|
|
opcode = args[0];
|
|
found = 1;
|
|
}
|
|
} else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
|
|
ide_task_t *args = rq->special;
|
|
if (args) {
|
|
task_struct_t *tf = (task_struct_t *) args->tfRegister;
|
|
opcode = tf->command;
|
|
found = 1;
|
|
}
|
|
}
|
|
|
|
printk("ide: failed opcode was: ");
|
|
if (!found)
|
|
printk("unknown\n");
|
|
else
|
|
printk("0x%02x\n", opcode);
|
|
}
|
|
|
|
static u8 ide_dump_ata_status(ide_drive_t *drive, const char *msg, u8 stat)
|
|
{
|
|
ide_hwif_t *hwif = HWIF(drive);
|
|
unsigned long flags;
|
|
u8 err = 0;
|
|
|
|
local_irq_save(flags);
|
|
printk("%s: %s: status=0x%02x { ", drive->name, msg, stat);
|
|
if (stat & BUSY_STAT)
|
|
printk("Busy ");
|
|
else {
|
|
if (stat & READY_STAT) printk("DriveReady ");
|
|
if (stat & WRERR_STAT) printk("DeviceFault ");
|
|
if (stat & SEEK_STAT) printk("SeekComplete ");
|
|
if (stat & DRQ_STAT) printk("DataRequest ");
|
|
if (stat & ECC_STAT) printk("CorrectedError ");
|
|
if (stat & INDEX_STAT) printk("Index ");
|
|
if (stat & ERR_STAT) printk("Error ");
|
|
}
|
|
printk("}\n");
|
|
if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
|
|
err = hwif->INB(IDE_ERROR_REG);
|
|
printk("%s: %s: error=0x%02x { ", drive->name, msg, err);
|
|
if (err & ABRT_ERR) printk("DriveStatusError ");
|
|
if (err & ICRC_ERR)
|
|
printk((err & ABRT_ERR) ? "BadCRC " : "BadSector ");
|
|
if (err & ECC_ERR) printk("UncorrectableError ");
|
|
if (err & ID_ERR) printk("SectorIdNotFound ");
|
|
if (err & TRK0_ERR) printk("TrackZeroNotFound ");
|
|
if (err & MARK_ERR) printk("AddrMarkNotFound ");
|
|
printk("}");
|
|
if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR ||
|
|
(err & (ECC_ERR|ID_ERR|MARK_ERR))) {
|
|
if (drive->addressing == 1) {
|
|
__u64 sectors = 0;
|
|
u32 low = 0, high = 0;
|
|
low = ide_read_24(drive);
|
|
hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
|
|
high = ide_read_24(drive);
|
|
sectors = ((__u64)high << 24) | low;
|
|
printk(", LBAsect=%llu, high=%d, low=%d",
|
|
(unsigned long long) sectors,
|
|
high, low);
|
|
} else {
|
|
u8 cur = hwif->INB(IDE_SELECT_REG);
|
|
if (cur & 0x40) { /* using LBA? */
|
|
printk(", LBAsect=%ld", (unsigned long)
|
|
((cur&0xf)<<24)
|
|
|(hwif->INB(IDE_HCYL_REG)<<16)
|
|
|(hwif->INB(IDE_LCYL_REG)<<8)
|
|
| hwif->INB(IDE_SECTOR_REG));
|
|
} else {
|
|
printk(", CHS=%d/%d/%d",
|
|
(hwif->INB(IDE_HCYL_REG)<<8) +
|
|
hwif->INB(IDE_LCYL_REG),
|
|
cur & 0xf,
|
|
hwif->INB(IDE_SECTOR_REG));
|
|
}
|
|
}
|
|
if (HWGROUP(drive) && HWGROUP(drive)->rq)
|
|
printk(", sector=%llu",
|
|
(unsigned long long)HWGROUP(drive)->rq->sector);
|
|
}
|
|
printk("\n");
|
|
}
|
|
ide_dump_opcode(drive);
|
|
local_irq_restore(flags);
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* ide_dump_atapi_status - print human readable atapi status
|
|
* @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).
|
|
*/
|
|
|
|
static u8 ide_dump_atapi_status(ide_drive_t *drive, const char *msg, u8 stat)
|
|
{
|
|
unsigned long flags;
|
|
|
|
atapi_status_t status;
|
|
atapi_error_t error;
|
|
|
|
status.all = stat;
|
|
error.all = 0;
|
|
local_irq_save(flags);
|
|
printk("%s: %s: status=0x%02x { ", drive->name, msg, stat);
|
|
if (status.b.bsy)
|
|
printk("Busy ");
|
|
else {
|
|
if (status.b.drdy) printk("DriveReady ");
|
|
if (status.b.df) printk("DeviceFault ");
|
|
if (status.b.dsc) printk("SeekComplete ");
|
|
if (status.b.drq) printk("DataRequest ");
|
|
if (status.b.corr) printk("CorrectedError ");
|
|
if (status.b.idx) printk("Index ");
|
|
if (status.b.check) printk("Error ");
|
|
}
|
|
printk("}\n");
|
|
if (status.b.check && !status.b.bsy) {
|
|
error.all = HWIF(drive)->INB(IDE_ERROR_REG);
|
|
printk("%s: %s: error=0x%02x { ", drive->name, msg, error.all);
|
|
if (error.b.ili) printk("IllegalLengthIndication ");
|
|
if (error.b.eom) printk("EndOfMedia ");
|
|
if (error.b.abrt) printk("AbortedCommand ");
|
|
if (error.b.mcr) printk("MediaChangeRequested ");
|
|
if (error.b.sense_key) printk("LastFailedSense=0x%02x ",
|
|
error.b.sense_key);
|
|
printk("}\n");
|
|
}
|
|
ide_dump_opcode(drive);
|
|
local_irq_restore(flags);
|
|
return error.all;
|
|
}
|
|
|
|
/**
|
|
* ide_dump_status - translate ATA/ATAPI error
|
|
* @drive: drive the error occured on
|
|
* @msg: information string
|
|
* @stat: status byte
|
|
*
|
|
* Error reporting, in human readable form (luxurious, but a memory hog).
|
|
* Combines the drive name, message and status byte to provide a
|
|
* user understandable explanation of the device error.
|
|
*/
|
|
|
|
u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat)
|
|
{
|
|
if (drive->media == ide_disk)
|
|
return ide_dump_ata_status(drive, msg, stat);
|
|
return ide_dump_atapi_status(drive, msg, stat);
|
|
}
|
|
|
|
EXPORT_SYMBOL(ide_dump_status);
|