Commit 79b2577a authored by Jens Axboe's avatar Jens Axboe

ide core updates, and addition of ide-iops.c

parent ce028ad0
/*
* linux/drivers/ide/ide-iops.c Version 0.33 April 11, 2002
*
* Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
*
*
*/
#include <linux/config.h>
#define __NO_VERSION__
#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 <asm/byteorder.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/bitops.h>
static inline u8 ide_inb (u32 port)
{
return (u8) IN_BYTE(port);
}
static inline u8 ide_inb_p (u32 port)
{
return (u8) IN_BYTE_P(port);
}
static inline u16 ide_inw (u32 port)
{
return (u16) IN_WORD(port);
}
static inline u16 ide_inw_p (u32 port)
{
return (u16) IN_WORD_P(port);
}
static inline void ide_insw (u32 port, void *addr, u32 count)
{
while (count--) { *(u16 *)addr = IN_WORD(port); addr += 2; }
}
static inline void ide_insw_p (u32 port, void *addr, u32 count)
{
while (count--) { *(u16 *)addr = IN_WORD_P(port); addr += 2; }
}
static inline u32 ide_inl (u32 port)
{
return (u32) IN_LONG(port);
}
static inline u32 ide_inl_p (u32 port)
{
return (u32) IN_LONG_P(port);
}
static inline void ide_insl (u32 port, void *addr, u32 count)
{
ide_insw(port, addr, (count)<<1);
// while (count--) { *(u32 *)addr = IN_LONG(port); addr += 4; }
}
static inline void ide_insl_p (u32 port, void *addr, u32 count)
{
ide_insw_p(port, addr, (count)<<1);
// while (count--) { *(u32 *)addr = IN_LONG(port); addr += 4; }
}
static inline void ide_outb (u8 addr, u32 port)
{
OUT_BYTE(addr, port);
}
static inline void ide_outb_p (u8 addr, u32 port)
{
OUT_BYTE_P(addr, port);
}
static inline void ide_outw (u16 addr, u32 port)
{
OUT_WORD(addr, port);
}
static inline void ide_outw_p (u16 addr, u32 port)
{
OUT_WORD_P(addr, port);
}
static inline void ide_outsw (u32 port, void *addr, u32 count)
{
while (count--) { OUT_WORD(*(u16 *)addr, port); addr += 2; }
}
static inline void ide_outsw_p (u32 port, void *addr, u32 count)
{
while (count--) { OUT_WORD_P(*(u16 *)addr, port); addr += 2; }
}
static inline void ide_outl (u32 addr, u32 port)
{
OUT_LONG(addr, port);
}
static inline void ide_outl_p (u32 addr, u32 port)
{
OUT_LONG_P(addr, port);
}
static inline void ide_outsl (u32 port, void *addr, u32 count)
{
ide_outsw(port, addr, (count)<<1);
// while (count--) { OUT_LONG(*(u32 *)addr, port); addr += 4; }
}
static inline void ide_outsl_p (u32 port, void *addr, u32 count)
{
ide_outsw_p(port, addr, (count)<<1);
// while (count--) { OUT_LONG_P(*(u32 *)addr, port); addr += 4; }
}
void default_hwif_iops (ide_hwif_t *hwif)
{
hwif->OUTB = ide_outb;
hwif->OUTBP = ide_outb_p;
hwif->OUTW = ide_outw;
hwif->OUTWP = ide_outw_p;
hwif->OUTL = ide_outl;
hwif->OUTLP = ide_outl_p;
hwif->OUTSW = ide_outsw;
hwif->OUTSWP = ide_outsw_p;
hwif->OUTSL = ide_outsl;
hwif->OUTSLP = ide_outsl_p;
hwif->INB = ide_inb;
hwif->INBP = ide_inb_p;
hwif->INW = ide_inw;
hwif->INWP = ide_inw_p;
hwif->INL = ide_inl;
hwif->INLP = ide_inl_p;
hwif->INSW = ide_insw;
hwif->INSWP = ide_insw_p;
hwif->INSL = ide_insl;
hwif->INSLP = ide_insl_p;
}
EXPORT_SYMBOL(default_hwif_iops);
void default_hwif_transport (ide_hwif_t *hwif)
{
hwif->ata_input_data = ata_input_data;
hwif->ata_output_data = ata_output_data;
hwif->atapi_input_bytes = atapi_input_bytes;
hwif->atapi_output_bytes = atapi_output_bytes;
}
EXPORT_SYMBOL(default_hwif_transport);
u32 read_24 (ide_drive_t *drive)
{
u8 hcyl = HWIF(drive)->INB(IDE_HCYL_REG);
u8 lcyl = HWIF(drive)->INB(IDE_LCYL_REG);
u8 sect = HWIF(drive)->INB(IDE_SECTOR_REG);
return (hcyl<<16)|(lcyl<<8)|sect;
}
EXPORT_SYMBOL(read_24);
void SELECT_DRIVE (ide_drive_t *drive)
{
if (HWIF(drive)->selectproc)
HWIF(drive)->selectproc(drive);
HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG);
}
EXPORT_SYMBOL(SELECT_DRIVE);
void SELECT_INTERRUPT (ide_drive_t *drive)
{
if (HWIF(drive)->intrproc)
HWIF(drive)->intrproc(drive);
else
HWIF(drive)->OUTB(drive->ctl|2, IDE_CONTROL_REG);
}
EXPORT_SYMBOL(SELECT_INTERRUPT);
void SELECT_MASK (ide_drive_t *drive, int mask)
{
if (HWIF(drive)->maskproc)
HWIF(drive)->maskproc(drive, mask);
}
EXPORT_SYMBOL(SELECT_MASK);
void QUIRK_LIST (ide_drive_t *drive)
{
if (HWIF(drive)->quirkproc)
drive->quirk_list = HWIF(drive)->quirkproc(drive);
}
EXPORT_SYMBOL(QUIRK_LIST);
#if SUPPORT_VLB_SYNC
/*
* Some localbus EIDE interfaces require a special access sequence
* when using 32-bit I/O instructions to transfer data. We call this
* the "vlb_sync" sequence, which consists of three successive reads
* of the sector count register location, with interrupts disabled
* to ensure that the reads all happen together.
*/
void ata_vlb_sync (ide_drive_t *drive, ide_ioreg_t port)
{
(void) HWIF(drive)->INB(port);
(void) HWIF(drive)->INB(port);
(void) HWIF(drive)->INB(port);
}
EXPORT_SYMBOL(ata_vlb_sync);
#endif /* SUPPORT_VLB_SYNC */
/*
* This is used for most PIO data transfers *from* the IDE interface
*/
void ata_input_data (ide_drive_t *drive, void *buffer, u32 wcount)
{
ide_hwif_t *hwif = HWIF(drive);
u8 io_32bit = drive->io_32bit;
if (io_32bit) {
#if SUPPORT_VLB_SYNC
if (io_32bit & 2) {
unsigned long flags;
local_irq_save(flags);
ata_vlb_sync(drive, IDE_NSECTOR_REG);
hwif->INSL(IDE_DATA_REG, buffer, wcount);
local_irq_restore(flags);
} else
#endif /* SUPPORT_VLB_SYNC */
hwif->INSL(IDE_DATA_REG, buffer, wcount);
} else {
#if SUPPORT_SLOW_DATA_PORTS
if (drive->slow) {
u16 *ptr = (u16 *) buffer;
while (wcount--) {
*ptr++ = hwif->INWP(IDE_DATA_REG);
*ptr++ = hwif->INWP(IDE_DATA_REG);
}
} else
#endif /* SUPPORT_SLOW_DATA_PORTS */
hwif->INSW(IDE_DATA_REG, buffer, wcount<<1);
}
}
EXPORT_SYMBOL(ata_input_data);
/*
* This is used for most PIO data transfers *to* the IDE interface
*/
void ata_output_data (ide_drive_t *drive, void *buffer, u32 wcount)
{
ide_hwif_t *hwif = HWIF(drive);
u8 io_32bit = drive->io_32bit;
if (io_32bit) {
#if SUPPORT_VLB_SYNC
if (io_32bit & 2) {
unsigned long flags;
local_irq_save(flags);
ata_vlb_sync(drive, IDE_NSECTOR_REG);
hwif->OUTSL(IDE_DATA_REG, buffer, wcount);
local_irq_restore(flags);
} else
#endif /* SUPPORT_VLB_SYNC */
hwif->OUTSL(IDE_DATA_REG, buffer, wcount);
} else {
#if SUPPORT_SLOW_DATA_PORTS
if (drive->slow) {
u16 *ptr = (u16 *) buffer;
while (wcount--) {
hwif->OUTWP(*ptr++, IDE_DATA_REG);
hwif->OUTWP(*ptr++, IDE_DATA_REG);
}
} else
#endif /* SUPPORT_SLOW_DATA_PORTS */
hwif->OUTSW(IDE_DATA_REG, buffer, wcount<<1);
}
}
EXPORT_SYMBOL(ata_output_data);
/*
* The following routines are mainly used by the ATAPI drivers.
*
* These routines will round up any request for an odd number of bytes,
* so if an odd bytecount is specified, be sure that there's at least one
* extra byte allocated for the buffer.
*/
void atapi_input_bytes (ide_drive_t *drive, void *buffer, u32 bytecount)
{
ide_hwif_t *hwif = HWIF(drive);
++bytecount;
#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
if (MACH_IS_ATARI || MACH_IS_Q40) {
/* Atari has a byte-swapped IDE interface */
insw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
return;
}
#endif /* CONFIG_ATARI */
hwif->ata_input_data(drive, buffer, bytecount / 4);
if ((bytecount & 0x03) >= 2)
hwif->INSW(IDE_DATA_REG, ((u8 *)buffer)+(bytecount & ~0x03), 1);
}
EXPORT_SYMBOL(atapi_input_bytes);
void atapi_output_bytes (ide_drive_t *drive, void *buffer, u32 bytecount)
{
ide_hwif_t *hwif = HWIF(drive);
++bytecount;
#if defined(CONFIG_ATARI) || defined(CONFIG_Q40)
if (MACH_IS_ATARI || MACH_IS_Q40) {
/* Atari has a byte-swapped IDE interface */
outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2);
return;
}
#endif /* CONFIG_ATARI */
hwif->ata_output_data(drive, buffer, bytecount / 4);
if ((bytecount & 0x03) >= 2)
hwif->OUTSW(IDE_DATA_REG, ((u8*)buffer)+(bytecount & ~0x03), 1);
}
EXPORT_SYMBOL(atapi_output_bytes);
/*
* Beginning of Taskfile OPCODE Library and feature sets.
*/
void ide_fix_driveid (struct hd_driveid *id)
{
#ifndef __LITTLE_ENDIAN
# ifdef __BIG_ENDIAN
int i;
u16 *stringcast;
id->config = __le16_to_cpu(id->config);
id->cyls = __le16_to_cpu(id->cyls);
id->reserved2 = __le16_to_cpu(id->reserved2);
id->heads = __le16_to_cpu(id->heads);
id->track_bytes = __le16_to_cpu(id->track_bytes);
id->sector_bytes = __le16_to_cpu(id->sector_bytes);
id->sectors = __le16_to_cpu(id->sectors);
id->vendor0 = __le16_to_cpu(id->vendor0);
id->vendor1 = __le16_to_cpu(id->vendor1);
id->vendor2 = __le16_to_cpu(id->vendor2);
stringcast = (u16 *)&id->serial_no[0];
for (i = 0; i < (20/2); i++)
stringcast[i] = __le16_to_cpu(stringcast[i]);
id->buf_type = __le16_to_cpu(id->buf_type);
id->buf_size = __le16_to_cpu(id->buf_size);
id->ecc_bytes = __le16_to_cpu(id->ecc_bytes);
stringcast = (u16 *)&id->fw_rev[0];
for (i = 0; i < (8/2); i++)
stringcast[i] = __le16_to_cpu(stringcast[i]);
stringcast = (u16 *)&id->model[0];
for (i = 0; i < (40/2); i++)
stringcast[i] = __le16_to_cpu(stringcast[i]);
id->dword_io = __le16_to_cpu(id->dword_io);
id->reserved50 = __le16_to_cpu(id->reserved50);
id->field_valid = __le16_to_cpu(id->field_valid);
id->cur_cyls = __le16_to_cpu(id->cur_cyls);
id->cur_heads = __le16_to_cpu(id->cur_heads);
id->cur_sectors = __le16_to_cpu(id->cur_sectors);
id->cur_capacity0 = __le16_to_cpu(id->cur_capacity0);
id->cur_capacity1 = __le16_to_cpu(id->cur_capacity1);
id->lba_capacity = __le32_to_cpu(id->lba_capacity);
id->dma_1word = __le16_to_cpu(id->dma_1word);
id->dma_mword = __le16_to_cpu(id->dma_mword);
id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
id->eide_dma_min = __le16_to_cpu(id->eide_dma_min);
id->eide_dma_time = __le16_to_cpu(id->eide_dma_time);
id->eide_pio = __le16_to_cpu(id->eide_pio);
id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
for (i = 0; i < 2; ++i)
id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
for (i = 0; i < 4; ++i)
id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
id->queue_depth = __le16_to_cpu(id->queue_depth);
for (i = 0; i < 4; ++i)
id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
id->major_rev_num = __le16_to_cpu(id->major_rev_num);
id->minor_rev_num = __le16_to_cpu(id->minor_rev_num);
id->command_set_1 = __le16_to_cpu(id->command_set_1);
id->command_set_2 = __le16_to_cpu(id->command_set_2);
id->cfsse = __le16_to_cpu(id->cfsse);
id->cfs_enable_1 = __le16_to_cpu(id->cfs_enable_1);
id->cfs_enable_2 = __le16_to_cpu(id->cfs_enable_2);
id->csf_default = __le16_to_cpu(id->csf_default);
id->dma_ultra = __le16_to_cpu(id->dma_ultra);
id->trseuc = __le16_to_cpu(id->trseuc);
id->trsEuc = __le16_to_cpu(id->trsEuc);
id->CurAPMvalues = __le16_to_cpu(id->CurAPMvalues);
id->mprc = __le16_to_cpu(id->mprc);
id->hw_config = __le16_to_cpu(id->hw_config);
id->acoustic = __le16_to_cpu(id->acoustic);
id->msrqs = __le16_to_cpu(id->msrqs);
id->sxfert = __le16_to_cpu(id->sxfert);
id->sal = __le16_to_cpu(id->sal);
id->spg = __le32_to_cpu(id->spg);
id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
for (i = 0; i < 22; i++)
id->words104_125[i] = __le16_to_cpu(id->words104_125[i]);
id->last_lun = __le16_to_cpu(id->last_lun);
id->word127 = __le16_to_cpu(id->word127);
id->dlf = __le16_to_cpu(id->dlf);
id->csfo = __le16_to_cpu(id->csfo);
for (i = 0; i < 26; i++)
id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
id->word156 = __le16_to_cpu(id->word156);
for (i = 0; i < 3; i++)
id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
id->cfa_power = __le16_to_cpu(id->cfa_power);
for (i = 0; i < 14; i++)
id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
for (i = 0; i < 31; i++)
id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
for (i = 0; i < 48; i++)
id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
id->integrity_word = __le16_to_cpu(id->integrity_word);
# else
# error "Please fix <asm/byteorder.h>"
# endif
#endif
}
EXPORT_SYMBOL(ide_fix_driveid);
void ide_fixstring (u8 *s, const int bytecount, const int byteswap)
{
u8 *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */
if (byteswap) {
/* convert from big-endian to host byte order */
for (p = end ; p != s;) {
unsigned short *pp = (unsigned short *) (p -= 2);
*pp = ntohs(*pp);
}
}
/* strip leading blanks */
while (s != end && *s == ' ')
++s;
/* compress internal blanks and strip trailing blanks */
while (s != end && *s) {
if (*s++ != ' ' || (s != end && *s && *s != ' '))
*p++ = *(s-1);
}
/* wipe out trailing garbage */
while (p != end)
*p++ = '\0';
}
EXPORT_SYMBOL(ide_fixstring);
/*
* Needed for PCI irq sharing
*/
int drive_is_ready (ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
u8 stat = 0;
if (drive->waiting_for_dma)
return hwif->ide_dma_test_irq(drive);
#if 0
/* need to guarantee 400ns since last command was issued */
udelay(1);
#endif
#ifdef CONFIG_IDEPCI_SHARE_IRQ
/*
* We do a passive status test under shared PCI interrupts on
* cards that truly share the ATA side interrupt, but may also share
* an interrupt with another pci card/device. We make no assumptions
* about possible isa-pnp and pci-pnp issues yet.
*/
if (IDE_CONTROL_REG)
stat = hwif->INB(IDE_ALTSTATUS_REG);
else
#endif /* CONFIG_IDEPCI_SHARE_IRQ */
/* Note: this may clear a pending IRQ!! */
stat = hwif->INB(IDE_STATUS_REG);
if (stat & BUSY_STAT)
/* drive busy: definitely not interrupting */
return 0;
/* drive ready: *might* be interrupting */
return 1;
}
EXPORT_SYMBOL(drive_is_ready);
/*
* Global for All, and taken from ide-pmac.c. Can be called
* with spinlock held & IRQs disabled, so don't schedule !
*/
int wait_for_ready (ide_drive_t *drive, int timeout)
{
ide_hwif_t *hwif = HWIF(drive);
u8 stat = 0;
while(--timeout) {
stat = hwif->INB(IDE_STATUS_REG);
if (!(stat & BUSY_STAT)) {
if (drive->ready_stat == 0)
break;
else if ((stat & drive->ready_stat)||(stat & ERR_STAT))
break;
}
mdelay(1);
}
if ((stat & ERR_STAT) || timeout <= 0) {
if (stat & ERR_STAT) {
printk(KERN_ERR "%s: wait_for_ready, "
"error status: %x\n", drive->name, stat);
}
return 1;
}
return 0;
}
EXPORT_SYMBOL(wait_for_ready);
/*
* This routine busy-waits for the drive status to be not "busy".
* It then checks the status for all of the "good" bits and none
* of the "bad" bits, and if all is okay it returns 0. All other
* cases return 1 after invoking ide_error() -- caller should just return.
*
* This routine should get fixed to not hog the cpu during extra long waits..
* That could be done by busy-waiting for the first jiffy or two, and then
* setting a timer to wake up at half second intervals thereafter,
* until timeout is achieved, before timing out.
*/
int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout)
{
ide_hwif_t *hwif = HWIF(drive);
u8 stat;
int i;
unsigned long flags;
/* bail early if we've exceeded max_failures */
if (drive->max_failures && (drive->failures > drive->max_failures)) {
*startstop = ide_stopped;
return 1;
}
udelay(1); /* spec allows drive 400ns to assert "BUSY" */
if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
local_irq_set(flags);
timeout += jiffies;
while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
if (time_after(jiffies, timeout)) {
local_irq_restore(flags);
*startstop = DRIVER(drive)->error(drive, "status timeout", stat);
return 1;
}
}
local_irq_restore(flags);
}
/*
* Allow status to settle, then read it again.
* A few rare drives vastly violate the 400ns spec here,
* so we'll wait up to 10usec for a "good" status
* rather than expensively fail things immediately.
* This fix courtesy of Matthew Faupel & Niccolo Rigacci.
*/
for (i = 0; i < 10; i++) {
udelay(1);
if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), good, bad))
return 0;
}
*startstop = DRIVER(drive)->error(drive, "status error", stat);
return 1;
}
EXPORT_SYMBOL(ide_wait_stat);
/*
* All hosts that use the 80c ribbon must use!
* The name is derived from upper byte of word 93 and the 80c ribbon.
*/
u8 eighty_ninty_three (ide_drive_t *drive)
{
#if 0
if (!HWIF(drive)->udma_four)
return 0;
if (drive->id->major_rev_num) {
int hssbd = 0;
int i;
/*
* Determime highest Supported SPEC
*/
for (i=1; i<=15; i++)
if (drive->id->major_rev_num & (1<<i))
hssbd++;
switch (hssbd) {
case 7:
case 6:
case 5:
/* ATA-4 and older do not support above Ultra 33 */
default:
return 0;
}
}
return ((u8) (
#ifndef CONFIG_IDEDMA_IVB
(drive->id->hw_config & 0x4000) &&
#endif /* CONFIG_IDEDMA_IVB */
(drive->id->hw_config & 0x6000)) ? 1 : 0);
#else
return ((u8) ((HWIF(drive)->udma_four) &&
#ifndef CONFIG_IDEDMA_IVB
(drive->id->hw_config & 0x4000) &&
#endif /* CONFIG_IDEDMA_IVB */
(drive->id->hw_config & 0x6000)) ? 1 : 0);
#endif
}
EXPORT_SYMBOL(eighty_ninty_three);
int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
{
if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
(args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
(args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
#ifndef CONFIG_IDEDMA_IVB
if ((drive->id->hw_config & 0x6000) == 0) {
#else /* !CONFIG_IDEDMA_IVB */
if (((drive->id->hw_config & 0x2000) == 0) ||
((drive->id->hw_config & 0x4000) == 0)) {
#endif /* CONFIG_IDEDMA_IVB */
printk("%s: Speed warnings UDMA 3/4/5 is not "
"functional.\n", drive->name);
return 1;
}
if (!HWIF(drive)->udma_four) {
printk("%s: Speed warnings UDMA 3/4/5 is not "
"functional.\n",
HWIF(drive)->name);
return 1;
}
}
return 0;
}
EXPORT_SYMBOL(ide_ata66_check);
/*
* Backside of HDIO_DRIVE_CMD call of SETFEATURES_XFER.
* 1 : Safe to update drive->id DMA registers.
* 0 : OOPs not allowed.
*/
int set_transfer (ide_drive_t *drive, ide_task_t *args)
{
if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
(args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) &&
(args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) &&
(drive->id->dma_ultra ||
drive->id->dma_mword ||
drive->id->dma_1word))
return 1;
return 0;
}
EXPORT_SYMBOL(set_transfer);
u8 ide_auto_reduce_xfer (ide_drive_t *drive)
{
if (!drive->crc_count)
return drive->current_speed;
drive->crc_count = 0;
switch(drive->current_speed) {
case XFER_UDMA_7: return XFER_UDMA_6;
case XFER_UDMA_6: return XFER_UDMA_5;
case XFER_UDMA_5: return XFER_UDMA_4;
case XFER_UDMA_4: return XFER_UDMA_3;
case XFER_UDMA_3: return XFER_UDMA_2;
case XFER_UDMA_2: return XFER_UDMA_1;
case XFER_UDMA_1: return XFER_UDMA_0;
/*
* OOPS we do not goto non Ultra DMA modes
* without iCRC's available we force
* the system to PIO and make the user
* invoke the ATA-1 ATA-2 DMA modes.
*/
case XFER_UDMA_0:
default: return XFER_PIO_4;
}
}
EXPORT_SYMBOL(ide_auto_reduce_xfer);
/*
* Update the
*/
int ide_driveid_update (ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
struct hd_driveid *id;
#if 0
id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
if (!id)
return 0;
taskfile_lib_get_identify(drive, (char *)&id);
ide_fix_driveid(id);
if (id) {
drive->id->dma_ultra = id->dma_ultra;
drive->id->dma_mword = id->dma_mword;
drive->id->dma_1word = id->dma_1word;
/* anything more ? */
kfree(id);
}
return 1;
#else
/*
* Re-read drive->id for possible DMA mode
* change (copied from ide-probe.c)
*/
unsigned long timeout, flags;
SELECT_MASK(drive, 1);
if (IDE_CONTROL_REG)
hwif->OUTB(drive->ctl,IDE_CONTROL_REG);
ide_delay_50ms();
hwif->OUTB(WIN_IDENTIFY, IDE_COMMAND_REG);
timeout = jiffies + WAIT_WORSTCASE;
do {
if (time_after(jiffies, timeout)) {
SELECT_MASK(drive, 0);
return 0; /* drive timed-out */
}
ide_delay_50ms(); /* give drive a breather */
} while (hwif->INB(IDE_ALTSTATUS_REG) & BUSY_STAT);
ide_delay_50ms(); /* wait for IRQ and DRQ_STAT */
if (!OK_STAT(hwif->INB(IDE_STATUS_REG),DRQ_STAT,BAD_R_STAT)) {
SELECT_MASK(drive, 0);
printk("%s: CHECK for good STATUS\n", drive->name);
return 0;
}
local_irq_save(flags);
SELECT_MASK(drive, 0);
id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
if (!id) {
local_irq_restore(flags);
return 0;
}
ata_input_data(drive, id, SECTOR_WORDS);
(void) hwif->INB(IDE_STATUS_REG); /* clear drive IRQ */
local_irq_enable();
local_irq_restore(flags);
ide_fix_driveid(id);
if (id) {
drive->id->dma_ultra = id->dma_ultra;
drive->id->dma_mword = id->dma_mword;
drive->id->dma_1word = id->dma_1word;
/* anything more ? */
kfree(id);
}
return 1;
#endif
}
EXPORT_SYMBOL(ide_driveid_update);
/*
* Similar to ide_wait_stat(), except it never calls ide_error internally.
* This is a kludge to handle the new ide_config_drive_speed() function,
* and should not otherwise be used anywhere. Eventually, the tuneproc's
* should be updated to return ide_startstop_t, in which case we can get
* rid of this abomination again. :) -ml
*
* It is gone..........
*
* const char *msg == consider adding for verbose errors.
*/
int ide_config_drive_speed (ide_drive_t *drive, u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
int i, error = 1;
u8 stat;
// while (HWGROUP(drive)->busy)
// ide_delay_50ms();
#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
hwif->ide_dma_host_off(drive);
#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
/*
* Don't use ide_wait_cmd here - it will
* attempt to set_geometry and recalibrate,
* but for some reason these don't work at
* this point (lost interrupt).
*/
/*
* Select the drive, and issue the SETFEATURES command
*/
disable_irq(hwif->irq); /* disable_irq_nosync ?? */
udelay(1);
SELECT_DRIVE(drive);
SELECT_MASK(drive, 0);
udelay(1);
if (IDE_CONTROL_REG)
hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
hwif->OUTB(speed, IDE_NSECTOR_REG);
hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG);
hwif->OUTB(WIN_SETFEATURES, IDE_COMMAND_REG);
if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
udelay(1);
/*
* Wait for drive to become non-BUSY
*/
if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
unsigned long flags, timeout;
local_irq_set(flags);
timeout = jiffies + WAIT_CMD;
while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
if (time_after(jiffies, timeout))
break;
}
local_irq_restore(flags);
}
/*
* Allow status to settle, then read it again.
* A few rare drives vastly violate the 400ns spec here,
* so we'll wait up to 10usec for a "good" status
* rather than expensively fail things immediately.
* This fix courtesy of Matthew Faupel & Niccolo Rigacci.
*/
for (i = 0; i < 10; i++) {
udelay(1);
if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
error = 0;
break;
}
}
SELECT_MASK(drive, 0);
enable_irq(hwif->irq);
if (error) {
(void) ide_dump_status(drive, "set_drive_speed_status", stat);
return error;
}
drive->id->dma_ultra &= ~0xFF00;
drive->id->dma_mword &= ~0x0F00;
drive->id->dma_1word &= ~0x0F00;
#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
if (speed >= XFER_SW_DMA_0)
hwif->ide_dma_host_on(drive);
else
hwif->ide_dma_off(drive);
#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
switch(speed) {
case XFER_UDMA_7: drive->id->dma_ultra |= 0x8080; break;
case XFER_UDMA_6: drive->id->dma_ultra |= 0x4040; break;
case XFER_UDMA_5: drive->id->dma_ultra |= 0x2020; break;
case XFER_UDMA_4: drive->id->dma_ultra |= 0x1010; break;
case XFER_UDMA_3: drive->id->dma_ultra |= 0x0808; break;
case XFER_UDMA_2: drive->id->dma_ultra |= 0x0404; break;
case XFER_UDMA_1: drive->id->dma_ultra |= 0x0202; break;
case XFER_UDMA_0: drive->id->dma_ultra |= 0x0101; break;
case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;
case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;
case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;
case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;
case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;
case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;
default: break;
}
if (!drive->init_speed)
drive->init_speed = speed;
drive->current_speed = speed;
return error;
}
EXPORT_SYMBOL(ide_config_drive_speed);
/*
* This should get invoked any time we exit the driver to
* wait for an interrupt response from a drive. handler() points
* at the appropriate code to handle the next interrupt, and a
* timer is started to prevent us from waiting forever in case
* something goes wrong (see the ide_timer_expiry() handler later on).
*/
void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
unsigned int timeout, ide_expiry_t *expiry)
{
unsigned long flags;
ide_hwgroup_t *hwgroup = HWGROUP(drive);
spin_lock_irqsave(&ide_lock, flags);
if (hwgroup->handler != NULL) {
printk("%s: ide_set_handler: handler not null; "
"old=%p, new=%p\n",
drive->name, hwgroup->handler, handler);
}
hwgroup->handler = handler;
hwgroup->expiry = expiry;
hwgroup->timer.expires = jiffies + timeout;
add_timer(&hwgroup->timer);
spin_unlock_irqrestore(&ide_lock, flags);
}
EXPORT_SYMBOL(ide_set_handler);
/* needed below */
ide_startstop_t do_reset1 (ide_drive_t *, int);
/*
* atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
* during an atapi drive reset operation. If the drive has not yet responded,
* and we have not yet hit our maximum waiting time, then the timer is restarted
* for another 50ms.
*/
static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
{
ide_hwgroup_t *hwgroup = HWGROUP(drive);
ide_hwif_t *hwif = HWIF(drive);
u8 stat;
SELECT_DRIVE(drive);
udelay (10);
if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG), 0, BUSY_STAT)) {
printk("%s: ATAPI reset complete\n", drive->name);
} else {
if (time_before(jiffies, hwgroup->poll_timeout)) {
if (HWGROUP(drive)->handler != NULL)
BUG();
ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
/* continue polling */
return ide_started;
}
/* end of polling */
hwgroup->poll_timeout = 0;
printk("%s: ATAPI reset timed-out, status=0x%02x\n",
drive->name, stat);
/* do it the old fashioned way */
return do_reset1(drive, 1);
}
/* done polling */
hwgroup->poll_timeout = 0;
return ide_stopped;
}
/*
* reset_pollfunc() gets invoked to poll the interface for completion every 50ms
* during an ide reset operation. If the drives have not yet responded,
* and we have not yet hit our maximum waiting time, then the timer is restarted
* for another 50ms.
*/
static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
{
ide_hwgroup_t *hwgroup = HWGROUP(drive);
ide_hwif_t *hwif = HWIF(drive);
u8 tmp;
if (hwif->reset_poll != NULL) {
if (hwif->reset_poll(drive)) {
printk(KERN_ERR "%s: host reset_poll failure for %s.\n",
hwif->name, drive->name);
return ide_stopped;
}
}
if (!OK_STAT(tmp = hwif->INB(IDE_STATUS_REG), 0, BUSY_STAT)) {
if (time_before(jiffies, hwgroup->poll_timeout)) {
if (HWGROUP(drive)->handler != NULL)
BUG();
ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
/* continue polling */
return ide_started;
}
printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
drive->failures++;
} else {
printk("%s: reset: ", hwif->name);
if ((tmp = hwif->INB(IDE_ERROR_REG)) == 1) {
printk("success\n");
drive->failures = 0;
} else {
drive->failures++;
#if FANCY_STATUS_DUMPS
printk("master: ");
switch (tmp & 0x7f) {
case 1: printk("passed");
break;
case 2: printk("formatter device error");
break;
case 3: printk("sector buffer error");
break;
case 4: printk("ECC circuitry error");
break;
case 5: printk("controlling MPU error");
break;
default:printk("error (0x%02x?)", tmp);
}
if (tmp & 0x80)
printk("; slave: failed");
printk("\n");
#else
printk("failed\n");
#endif /* FANCY_STATUS_DUMPS */
}
}
hwgroup->poll_timeout = 0; /* done polling */
return ide_stopped;
}
void check_dma_crc (ide_drive_t *drive)
{
if (drive->crc_count) {
(void) HWIF(drive)->ide_dma_off_quietly(drive);
if ((HWIF(drive)->speedproc) != NULL)
HWIF(drive)->speedproc(drive, ide_auto_reduce_xfer(drive));
if (drive->current_speed >= XFER_SW_DMA_0)
(void) HWIF(drive)->ide_dma_on(drive);
} else {
(void) HWIF(drive)->ide_dma_off(drive);
}
}
void pre_reset (ide_drive_t *drive)
{
if (drive->driver != NULL)
DRIVER(drive)->pre_reset(drive);
if (!drive->keep_settings) {
if (drive->using_dma) {
check_dma_crc(drive);
} else {
drive->unmask = 0;
drive->io_32bit = 0;
}
return;
}
if (drive->using_dma)
check_dma_crc(drive);
if (HWIF(drive)->pre_reset != NULL)
HWIF(drive)->pre_reset(drive);
}
/*
* do_reset1() attempts to recover a confused drive by resetting it.
* Unfortunately, resetting a disk drive actually resets all devices on
* the same interface, so it can really be thought of as resetting the
* interface rather than resetting the drive.
*
* ATAPI devices have their own reset mechanism which allows them to be
* individually reset without clobbering other devices on the same interface.
*
* Unfortunately, the IDE interface does not generate an interrupt to let
* us know when the reset operation has finished, so we must poll for this.
* Equally poor, though, is the fact that this may a very long time to complete,
* (up to 30 seconds worstcase). So, instead of busy-waiting here for it,
* we set a timer to poll at 50ms intervals.
*/
ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
{
unsigned int unit;
unsigned long flags;
ide_hwif_t *hwif = HWIF(drive);
ide_hwgroup_t *hwgroup = HWGROUP(drive);
local_irq_save(flags);
/* For an ATAPI device, first try an ATAPI SRST. */
if (drive->media != ide_disk && !do_not_try_atapi) {
pre_reset(drive);
SELECT_DRIVE(drive);
udelay (20);
hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
if (HWGROUP(drive)->handler != NULL)
BUG();
ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
local_irq_restore(flags);
return ide_started;
}
/*
* First, reset any device state data we were maintaining
* for any of the drives on this interface.
*/
for (unit = 0; unit < MAX_DRIVES; ++unit)
pre_reset(&hwif->drives[unit]);
#if OK_TO_RESET_CONTROLLER
if (!IDE_CONTROL_REG) {
local_irq_restore(flags);
return ide_stopped;
}
# if 0
{
u8 control = hwif->INB(IDE_CONTROL_REG);
control |= 0x04;
hwif->OUTB(control,IDE_CONTROL_REG);
udelay(30);
control &= 0xFB;
hwif->OUTB(control, IDE_CONTROL_REG);
}
# else
/*
* Note that we also set nIEN while resetting the device,
* to mask unwanted interrupts from the interface during the reset.
* However, due to the design of PC hardware, this will cause an
* immediate interrupt due to the edge transition it produces.
* This single interrupt gives us a "fast poll" for drives that
* recover from reset very quickly, saving us the first 50ms wait time.
*/
/* set SRST and nIEN */
hwif->OUTB(drive->ctl|6,IDE_CONTROL_REG);
/* more than enough time */
udelay(10);
if (drive->quirk_list == 2) {
/* clear SRST and nIEN */
hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
} else {
/* clear SRST, leave nIEN */
hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
}
/* more than enough time */
udelay(10);
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
if (HWGROUP(drive)->handler != NULL)
BUG();
ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
# endif
/*
* Some weird controller like resetting themselves to a strange
* state when the disks are reset this way. At least, the Winbond
* 553 documentation says that
*/
if (hwif->resetproc != NULL) {
hwif->resetproc(drive);
# if 0
if (drive->failures) {
local_irq_restore(flags);
return ide_stopped;
}
# endif
}
#endif /* OK_TO_RESET_CONTROLLER */
local_irq_restore(flags);
return ide_started;
}
#if 0
/*
* ide_do_reset() is the entry point to the drive/interface reset code.
*/
ide_startstop_t ide_do_reset (ide_drive_t *drive)
{
return do_reset1(drive, 0);
}
#else
/*
* ide_do_reset() is the entry point to the drive/interface reset code.
*/
ide_startstop_t ide_do_reset (ide_drive_t *drive)
{
ide_startstop_t start_stop = ide_started;
# if 0
u8 tmp_dma = drive->using_dma;
u8 cspeed = drive->current_speed;
u8 unmask = drive->unmask;
# endif
if (HWGROUP(drive)->handler != NULL) {
unsigned long flags;
spin_lock_irqsave(&ide_lock, flags);
HWGROUP(drive)->handler = NULL;
del_timer(&HWGROUP(drive)->timer);
spin_unlock_irqrestore(&ide_lock, flags);
}
start_stop = do_reset1(drive, 0);
# if 0
/*
* check for suspend-spindown flag,
* to attempt a restart or spinup of device.
*/
if (drive->suspend_reset) {
/*
* APM WAKE UP todo !!
* int nogoodpower = 1;
* while(nogoodpower) {
* check_power1() or check_power2()
* nogoodpower = 0;
* }
* HWIF(drive)->multiproc(drive);
*/
# endif
return start_stop;
}
#endif
EXPORT_SYMBOL(ide_do_reset);
/* /*
* linux/drivers/ide/ide.c Version 6.31 June 9, 2000 * linux/drivers/ide/ide.c Version 7.00alpha1 August 19 2002
* *
* Copyright (C) 1994-1998 Linus Torvalds & authors (see below) * Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
*/ */
...@@ -12,7 +12,8 @@ ...@@ -12,7 +12,8 @@
* See linux/MAINTAINERS for address of current maintainer. * See linux/MAINTAINERS for address of current maintainer.
* *
* This is the multiple IDE interface driver, as evolved from hd.c. * This is the multiple IDE interface driver, as evolved from hd.c.
* It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs (usually 14 & 15). * It supports up to MAX_HWIFS IDE interfaces, on one or more IRQs
* (usually 14 & 15).
* There can be up to two drives per interface, as per the ATA-2 spec. * There can be up to two drives per interface, as per the ATA-2 spec.
* *
* Primary: ide0, port 0x1f0; major=3; hda is minor=0; hdb is minor=64 * Primary: ide0, port 0x1f0; major=3; hda is minor=0; hdb is minor=64
...@@ -113,6 +114,7 @@ ...@@ -113,6 +114,7 @@
* Version 6.31 Debug Share INTR's and request queue streaming * Version 6.31 Debug Share INTR's and request queue streaming
* Native ATA-100 support * Native ATA-100 support
* Prep for Cascades Project * Prep for Cascades Project
* Version 7.00alpha First named revision of ide rearrange
* *
* Some additional driver compile-time options are in ./include/linux/ide.h * Some additional driver compile-time options are in ./include/linux/ide.h
* *
...@@ -121,8 +123,8 @@ ...@@ -121,8 +123,8 @@
* *
*/ */
#define REVISION "Revision: 6.31" #define REVISION "Revision: 7.00alpha2"
#define VERSION "Id: ide.c 6.31 2000/06/09" #define VERSION "Id: ide.c 7.00a2 20020906"
#undef REALLY_SLOW_IO /* most systems can safely undef this */ #undef REALLY_SLOW_IO /* most systems can safely undef this */
...@@ -141,9 +143,7 @@ ...@@ -141,9 +143,7 @@
#include <linux/genhd.h> #include <linux/genhd.h>
#include <linux/blkpg.h> #include <linux/blkpg.h>
#include <linux/slab.h> #include <linux/slab.h>
#ifndef MODULE
#include <linux/init.h> #include <linux/init.h>
#endif /* MODULE */
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/ide.h> #include <linux/ide.h>
...@@ -161,14 +161,16 @@ ...@@ -161,14 +161,16 @@
#include "ide_modes.h" #include "ide_modes.h"
#ifdef CONFIG_KMOD
#include <linux/kmod.h> #include <linux/kmod.h>
#endif /* CONFIG_KMOD */
/* default maximum number of failures */ /* default maximum number of failures */
#define IDE_DEFAULT_MAX_FAILURES 1 #define IDE_DEFAULT_MAX_FAILURES 1
static const byte ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR }; static const u8 ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR,
IDE2_MAJOR, IDE3_MAJOR,
IDE4_MAJOR, IDE5_MAJOR,
IDE6_MAJOR, IDE7_MAJOR,
IDE8_MAJOR, IDE9_MAJOR };
static int idebus_parameter; /* holds the "idebus=" parameter */ static int idebus_parameter; /* holds the "idebus=" parameter */
static int system_bus_speed; /* holds what we think is VESA/PCI bus speed */ static int system_bus_speed; /* holds what we think is VESA/PCI bus speed */
...@@ -176,13 +178,7 @@ static int initializing; /* set while initializing built-in drivers */ ...@@ -176,13 +178,7 @@ static int initializing; /* set while initializing built-in drivers */
spinlock_t ide_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; spinlock_t ide_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
#ifdef CONFIG_BLK_DEV_IDESCSI_24
#define CONFIG_BLK_DEV_IDESCSI
#endif
#ifdef CONFIG_BLK_DEV_IDEPCI
static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */ static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */
#endif /* CONFIG_BLK_DEV_IDEPCI */
#if defined(__mc68000__) || defined(CONFIG_APUS) #if defined(__mc68000__) || defined(CONFIG_APUS)
/* /*
...@@ -192,11 +188,16 @@ static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */ ...@@ -192,11 +188,16 @@ static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */
static int ide_intr_lock; static int ide_intr_lock;
#endif /* __mc68000__ || CONFIG_APUS */ #endif /* __mc68000__ || CONFIG_APUS */
#ifdef CONFIG_IDEDMA_AUTO
int noautodma = 0; int noautodma = 0;
#else
int noautodma = 1;
#endif
/* /*
* ide_modules keeps track of the available IDE chipset/probe/driver modules. * ide_modules keeps track of the available IDE chipset/probe/driver modules.
*/ */
ide_module_t *ide_chipsets;
ide_module_t *ide_probe; ide_module_t *ide_probe;
/* /*
...@@ -204,21 +205,40 @@ ide_module_t *ide_probe; ...@@ -204,21 +205,40 @@ ide_module_t *ide_probe;
*/ */
ide_hwif_t ide_hwifs[MAX_HWIFS]; /* master data repository */ ide_hwif_t ide_hwifs[MAX_HWIFS]; /* master data repository */
EXPORT_SYMBOL(ide_hwifs);
ide_devices_t *idedisk;
ide_devices_t *idecd;
ide_devices_t *idefloppy;
ide_devices_t *idetape;
ide_devices_t *idescsi;
EXPORT_SYMBOL(idedisk);
EXPORT_SYMBOL(idecd);
EXPORT_SYMBOL(idefloppy);
EXPORT_SYMBOL(idetape);
EXPORT_SYMBOL(idescsi);
#if (DISK_RECOVERY_TIME > 0) #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) * For really screwy hardware (hey, at least it *can* be used with Linux)
* we can enforce a minimum delay time between successive operations. * we can enforce a minimum delay time between successive operations.
*/ */
static unsigned long read_timer (void) static unsigned long read_timer (ide_hwif_t *hwif)
{ {
unsigned long t, flags; unsigned long t, flags;
int i; int i;
/* FIXME this is completely unsafe! */
local_irq_save(flags); local_irq_save(flags);
t = jiffies * 11932; t = jiffies * 11932;
outb_p(0, 0x43); outb_p(0, 0x43);
i = inb_p(0x40); i = inb_p(0x40);
i |= IN_BYTE(0x40) << 8; i |= inb_p(0x40) << 8;
local_irq_restore(flags); local_irq_restore(flags);
return (t - i); return (t - i);
} }
...@@ -227,7 +247,7 @@ static unsigned long read_timer (void) ...@@ -227,7 +247,7 @@ static unsigned long read_timer (void)
static inline void set_recovery_timer (ide_hwif_t *hwif) static inline void set_recovery_timer (ide_hwif_t *hwif)
{ {
#if (DISK_RECOVERY_TIME > 0) #if (DISK_RECOVERY_TIME > 0)
hwif->last_time = read_timer(); hwif->last_time = read_timer(hwif);
#endif /* DISK_RECOVERY_TIME */ #endif /* DISK_RECOVERY_TIME */
} }
...@@ -260,6 +280,16 @@ static void init_hwif_data (unsigned int index) ...@@ -260,6 +280,16 @@ static void init_hwif_data (unsigned int index)
hwif->name[2] = 'e'; hwif->name[2] = 'e';
hwif->name[3] = '0' + index; hwif->name[3] = '0' + index;
hwif->bus_state = BUSSTATE_ON; hwif->bus_state = BUSSTATE_ON;
hwif->reset_poll= NULL;
hwif->pre_reset = NULL;
hwif->atapi_dma = 0; /* disable all atapi dma */
hwif->ultra_mask = 0x80; /* disable all ultra */
hwif->mwdma_mask = 0x80; /* disable all mwdma */
hwif->swdma_mask = 0x80; /* disable all swdma */
default_hwif_iops(hwif);
default_hwif_transport(hwif);
for (unit = 0; unit < MAX_DRIVES; ++unit) { for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit]; ide_drive_t *drive = &hwif->drives[unit];
...@@ -275,6 +305,8 @@ static void init_hwif_data (unsigned int index) ...@@ -275,6 +305,8 @@ static void init_hwif_data (unsigned int index)
drive->name[1] = 'd'; drive->name[1] = 'd';
drive->name[2] = 'a' + (index * MAX_DRIVES) + unit; drive->name[2] = 'a' + (index * MAX_DRIVES) + unit;
drive->max_failures = IDE_DEFAULT_MAX_FAILURES; drive->max_failures = IDE_DEFAULT_MAX_FAILURES;
drive->using_dma = 0;
drive->is_flash = 0;
INIT_LIST_HEAD(&drive->list); INIT_LIST_HEAD(&drive->list);
} }
} }
...@@ -292,6 +324,9 @@ static void init_hwif_data (unsigned int index) ...@@ -292,6 +324,9 @@ static void init_hwif_data (unsigned int index)
* This is too bad, as otherwise we could dynamically allocate the * This is too bad, as otherwise we could dynamically allocate the
* ide_drive_t structs as needed, rather than always consuming memory * ide_drive_t structs as needed, rather than always consuming memory
* for the max possible number (MAX_HWIFS * MAX_DRIVES) of them. * for the max possible number (MAX_HWIFS * MAX_DRIVES) of them.
*
* FIXME: We should stuff the setup data into __init and copy the
* relevant hwifs/allocate them properly during boot.
*/ */
#define MAGIC_COOKIE 0x12345678 #define MAGIC_COOKIE 0x12345678
static void __init init_ide_data (void) static void __init init_ide_data (void)
...@@ -314,37 +349,6 @@ static void __init init_ide_data (void) ...@@ -314,37 +349,6 @@ static void __init init_ide_data (void)
system_bus_speed = 0; system_bus_speed = 0;
} }
/*
* CompactFlash cards and their brethern pretend to be removable hard disks, except:
* (1) they never have a slave unit, and
* (2) they don't have doorlock mechanisms.
* This test catches them, and is invoked elsewhere when setting appropriate config bits.
*
* FIXME: This treatment is probably applicable for *all* PCMCIA (PC CARD) devices,
* so in linux 2.3.x we should change this to just treat all PCMCIA drives this way,
* and get rid of the model-name tests below (too big of an interface change for 2.2.x).
* At that time, we might also consider parameterizing the timeouts and retries,
* since these are MUCH faster than mechanical drives. -M.Lord
*/
int drive_is_flashcard (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
if (drive->removable && id != NULL) {
if (id->config == 0x848a) return 1; /* CompactFlash */
if (!strncmp(id->model, "KODAK ATA_FLASH", 15) /* Kodak */
|| !strncmp(id->model, "Hitachi CV", 10) /* Hitachi */
|| !strncmp(id->model, "SunDisk SDCFB", 13) /* SunDisk */
|| !strncmp(id->model, "HAGIWARA HPC", 12) /* Hagiwara */
|| !strncmp(id->model, "LEXAR ATA_FLASH", 15) /* Lexar */
|| !strncmp(id->model, "ATA_FLASH", 9)) /* Simple Tech */
{
return 1; /* yes, it is a flash memory card */
}
}
return 0; /* no, it is not a flash memory card */
}
/* /*
* ide_system_bus_speed() returns what we think is the system VESA/PCI * ide_system_bus_speed() returns what we think is the system VESA/PCI
* bus speed (in MHz). This is used for calculating interface PIO timings. * bus speed (in MHz). This is used for calculating interface PIO timings.
...@@ -355,15 +359,18 @@ int drive_is_flashcard (ide_drive_t *drive) ...@@ -355,15 +359,18 @@ int drive_is_flashcard (ide_drive_t *drive)
int ide_system_bus_speed (void) int ide_system_bus_speed (void)
{ {
if (!system_bus_speed) { if (!system_bus_speed) {
if (idebus_parameter) if (idebus_parameter) {
system_bus_speed = idebus_parameter; /* user supplied value */ /* user supplied value */
#ifdef CONFIG_PCI system_bus_speed = idebus_parameter;
else if (pci_present()) } else if (pci_present()) {
system_bus_speed = 33; /* safe default value for PCI */ /* safe default value for PCI */
#endif /* CONFIG_PCI */ system_bus_speed = 33;
else } else {
system_bus_speed = 50; /* safe default value for VESA and PCI */ /* safe default value for VESA and PCI */
printk("ide: Assuming %dMHz system bus speed for PIO modes%s\n", system_bus_speed, system_bus_speed = 50;
}
printk("ide: Assuming %dMHz system bus speed "
"for PIO modes%s\n", system_bus_speed,
idebus_parameter ? "" : "; override with idebus=xx"); idebus_parameter ? "" : "; override with idebus=xx");
} }
return system_bus_speed; return system_bus_speed;
...@@ -372,7 +379,7 @@ int ide_system_bus_speed (void) ...@@ -372,7 +379,7 @@ int ide_system_bus_speed (void)
/* /*
* This is our end_request replacement function. * This is our end_request replacement function.
*/ */
int ide_end_request (ide_drive_t *drive, int uptodate) int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors)
{ {
struct request *rq; struct request *rq;
unsigned long flags; unsigned long flags;
...@@ -383,16 +390,19 @@ int ide_end_request (ide_drive_t *drive, int uptodate) ...@@ -383,16 +390,19 @@ int ide_end_request (ide_drive_t *drive, int uptodate)
BUG_ON(!(rq->flags & REQ_STARTED)); 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, * 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 we DMA timeout more than 3 times, just stay in PIO
*/ */
if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) { if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
drive->state = 0; drive->state = 0;
HWGROUP(drive)->hwif->dmaproc(ide_dma_on, drive); HWGROUP(drive)->hwif->ide_dma_on(drive);
} }
if (!end_that_request_first(rq, uptodate, rq->hard_cur_sectors)) { if (!end_that_request_first(rq, uptodate, nr_sectors)) {
add_blkdev_randomness(major(rq->rq_dev)); add_blkdev_randomness(major(rq->rq_dev));
blkdev_dequeue_request(rq); blkdev_dequeue_request(rq);
HWGROUP(drive)->rq = NULL; HWGROUP(drive)->rq = NULL;
...@@ -403,30 +413,7 @@ int ide_end_request (ide_drive_t *drive, int uptodate) ...@@ -403,30 +413,7 @@ int ide_end_request (ide_drive_t *drive, int uptodate)
return ret; return ret;
} }
/* EXPORT_SYMBOL(ide_end_request);
* This should get invoked any time we exit the driver to
* wait for an interrupt response from a drive. handler() points
* at the appropriate code to handle the next interrupt, and a
* timer is started to prevent us from waiting forever in case
* something goes wrong (see the ide_timer_expiry() handler later on).
*/
void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
unsigned int timeout, ide_expiry_t *expiry)
{
unsigned long flags;
ide_hwgroup_t *hwgroup = HWGROUP(drive);
spin_lock_irqsave(&ide_lock, flags);
if (hwgroup->handler != NULL) {
printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n",
drive->name, hwgroup->handler, handler);
}
hwgroup->handler = handler;
hwgroup->expiry = expiry;
hwgroup->timer.expires = jiffies + timeout;
add_timer(&hwgroup->timer);
spin_unlock_irqrestore(&ide_lock, flags);
}
/* /*
* current_capacity() returns the capacity (in sectors) of a drive * current_capacity() returns the capacity (in sectors) of a drive
...@@ -441,232 +428,21 @@ unsigned long current_capacity (ide_drive_t *drive) ...@@ -441,232 +428,21 @@ unsigned long current_capacity (ide_drive_t *drive)
return 0; return 0;
} }
extern struct block_device_operations ide_fops[]; EXPORT_SYMBOL(current_capacity);
static ide_startstop_t do_reset1 (ide_drive_t *, int); /* needed below */
/*
* atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
* during an atapi drive reset operation. If the drive has not yet responded,
* and we have not yet hit our maximum waiting time, then the timer is restarted
* for another 50ms.
*/
static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
{
ide_hwgroup_t *hwgroup = HWGROUP(drive);
byte stat;
SELECT_DRIVE(HWIF(drive),drive);
udelay (10);
if (OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {
printk("%s: ATAPI reset complete\n", drive->name);
} else {
if (time_before(jiffies, hwgroup->poll_timeout)) {
if (HWGROUP(drive)->handler != NULL) /* paranoia check */
BUG();
ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
return ide_started; /* continue polling */
}
hwgroup->poll_timeout = 0; /* end of polling */
printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat);
return do_reset1 (drive, 1); /* do it the old fashioned way */
}
hwgroup->poll_timeout = 0; /* done polling */
return ide_stopped;
}
/*
* reset_pollfunc() gets invoked to poll the interface for completion every 50ms
* during an ide reset operation. If the drives have not yet responded,
* and we have not yet hit our maximum waiting time, then the timer is restarted
* for another 50ms.
*/
static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
{
ide_hwgroup_t *hwgroup = HWGROUP(drive);
ide_hwif_t *hwif = HWIF(drive);
byte tmp;
if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
if (time_before(jiffies, hwgroup->poll_timeout)) {
if (HWGROUP(drive)->handler != NULL) /* paranoia check */
BUG();
ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
return ide_started; /* continue polling */
}
printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
drive->failures++;
} else {
printk("%s: reset: ", hwif->name);
if ((tmp = GET_ERR()) == 1) {
printk("success\n");
drive->failures = 0;
} else {
drive->failures++;
#if FANCY_STATUS_DUMPS
printk("master: ");
switch (tmp & 0x7f) {
case 1: printk("passed");
break;
case 2: printk("formatter device error");
break;
case 3: printk("sector buffer error");
break;
case 4: printk("ECC circuitry error");
break;
case 5: printk("controlling MPU error");
break;
default:printk("error (0x%02x?)", tmp);
}
if (tmp & 0x80)
printk("; slave: failed");
printk("\n");
#else
printk("failed\n");
#endif /* FANCY_STATUS_DUMPS */
}
}
hwgroup->poll_timeout = 0; /* done polling */
return ide_stopped;
}
static void check_dma_crc (ide_drive_t *drive)
{
if (drive->crc_count) {
(void) HWIF(drive)->dmaproc(ide_dma_off_quietly, drive);
if ((HWIF(drive)->speedproc) != NULL)
HWIF(drive)->speedproc(drive, ide_auto_reduce_xfer(drive));
if (drive->current_speed >= XFER_SW_DMA_0)
(void) HWIF(drive)->dmaproc(ide_dma_on, drive);
} else {
(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
}
}
static void pre_reset (ide_drive_t *drive)
{
if (drive->driver != NULL)
DRIVER(drive)->pre_reset(drive);
if (!drive->keep_settings) {
if (drive->using_dma) {
check_dma_crc(drive);
} else {
drive->unmask = 0;
drive->io_32bit = 0;
}
return;
}
if (drive->using_dma)
check_dma_crc(drive);
}
/*
* do_reset1() attempts to recover a confused drive by resetting it.
* Unfortunately, resetting a disk drive actually resets all devices on
* the same interface, so it can really be thought of as resetting the
* interface rather than resetting the drive.
*
* ATAPI devices have their own reset mechanism which allows them to be
* individually reset without clobbering other devices on the same interface.
*
* Unfortunately, the IDE interface does not generate an interrupt to let
* us know when the reset operation has finished, so we must poll for this.
* Equally poor, though, is the fact that this may a very long time to complete,
* (up to 30 seconds worstcase). So, instead of busy-waiting here for it,
* we set a timer to poll at 50ms intervals.
*/
static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
{
unsigned int unit;
unsigned long flags;
ide_hwif_t *hwif = HWIF(drive);
ide_hwgroup_t *hwgroup = HWGROUP(drive);
local_irq_save(flags);
/* For an ATAPI device, first try an ATAPI SRST. */
if (drive->media != ide_disk && !do_not_try_atapi) {
pre_reset(drive);
SELECT_DRIVE(hwif,drive);
udelay (20);
OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
if (HWGROUP(drive)->handler != NULL) /* paranoia check */
BUG();
ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
local_irq_restore(flags);
return ide_started;
}
/*
* First, reset any device state data we were maintaining
* for any of the drives on this interface.
*/
for (unit = 0; unit < MAX_DRIVES; ++unit)
pre_reset(&hwif->drives[unit]);
#if OK_TO_RESET_CONTROLLER
if (!IDE_CONTROL_REG) {
local_irq_restore(flags);
return ide_stopped;
}
/*
* Note that we also set nIEN while resetting the device,
* to mask unwanted interrupts from the interface during the reset.
* However, due to the design of PC hardware, this will cause an
* immediate interrupt due to the edge transition it produces.
* This single interrupt gives us a "fast poll" for drives that
* recover from reset very quickly, saving us the first 50ms wait time.
*/
OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG); /* set SRST and nIEN */
udelay(10); /* more than enough time */
if (drive->quirk_list == 2) {
OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* clear SRST and nIEN */
} else {
OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* clear SRST, leave nIEN */
}
udelay(10); /* more than enough time */
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
if (HWGROUP(drive)->handler != NULL) /* paranoia check */
BUG();
ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
/*
* Some weird controller like resetting themselves to a strange
* state when the disks are reset this way. At least, the Winbond
* 553 documentation says that
*/
if (hwif->resetproc != NULL)
hwif->resetproc(drive);
#endif /* OK_TO_RESET_CONTROLLER */
local_irq_restore(flags);
return ide_started;
}
/*
* ide_do_reset() is the entry point to the drive/interface reset code.
*/
ide_startstop_t ide_do_reset (ide_drive_t *drive)
{
return do_reset1 (drive, 0);
}
static inline u32 read_24 (ide_drive_t *drive) static inline u32 read_24 (ide_drive_t *drive)
{ {
return (IN_BYTE(IDE_HCYL_REG)<<16) | return (HWIF(drive)->INB(IDE_HCYL_REG)<<16) |
(IN_BYTE(IDE_LCYL_REG)<<8) | (HWIF(drive)->INB(IDE_LCYL_REG)<<8) |
IN_BYTE(IDE_SECTOR_REG); HWIF(drive)->INB(IDE_SECTOR_REG);
} }
/* /*
* Clean up after success/failure of an explicit drive cmd * Clean up after success/failure of an explicit drive cmd
*/ */
void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err) void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
{ {
ide_hwif_t *hwif = HWIF(drive);
unsigned long flags; unsigned long flags;
struct request *rq; struct request *rq;
...@@ -675,28 +451,28 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err) ...@@ -675,28 +451,28 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&ide_lock, flags);
if (rq->flags & REQ_DRIVE_CMD) { if (rq->flags & REQ_DRIVE_CMD) {
byte *args = (byte *) rq->buffer; u8 *args = (u8 *) rq->buffer;
if (rq->errors == 0) if (rq->errors == 0)
rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
if (args) { if (args) {
args[0] = stat; args[0] = stat;
args[1] = err; args[1] = err;
args[2] = IN_BYTE(IDE_NSECTOR_REG); args[2] = hwif->INB(IDE_NSECTOR_REG);
} }
} else if (rq->flags & REQ_DRIVE_TASK) { } else if (rq->flags & REQ_DRIVE_TASK) {
byte *args = (byte *) rq->buffer; u8 *args = (u8 *) rq->buffer;
if (rq->errors == 0) if (rq->errors == 0)
rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
if (args) { if (args) {
args[0] = stat; args[0] = stat;
args[1] = err; args[1] = err;
args[2] = IN_BYTE(IDE_NSECTOR_REG); args[2] = hwif->INB(IDE_NSECTOR_REG);
args[3] = IN_BYTE(IDE_SECTOR_REG); args[3] = hwif->INB(IDE_SECTOR_REG);
args[4] = IN_BYTE(IDE_LCYL_REG); args[4] = hwif->INB(IDE_LCYL_REG);
args[5] = IN_BYTE(IDE_HCYL_REG); args[5] = hwif->INB(IDE_HCYL_REG);
args[6] = IN_BYTE(IDE_SELECT_REG); args[6] = hwif->INB(IDE_SELECT_REG);
} }
} else if (rq->flags & REQ_DRIVE_TASKFILE) { } else if (rq->flags & REQ_DRIVE_TASKFILE) {
ide_task_t *args = (ide_task_t *) rq->special; ide_task_t *args = (ide_task_t *) rq->special;
...@@ -705,27 +481,25 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err) ...@@ -705,27 +481,25 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
if (args) { if (args) {
if (args->tf_in_flags.b.data) { if (args->tf_in_flags.b.data) {
unsigned short data = IN_WORD(IDE_DATA_REG); u16 data = hwif->INW(IDE_DATA_REG);
args->tfRegister[IDE_DATA_OFFSET] = (data) & 0xFF; args->tfRegister[IDE_DATA_OFFSET] = (data) & 0xFF;
args->hobRegister[IDE_DATA_OFFSET_HOB] = (data >> 8) & 0xFF; args->hobRegister[IDE_DATA_OFFSET_HOB] = (data >> 8) & 0xFF;
} }
args->tfRegister[IDE_ERROR_OFFSET] = err; args->tfRegister[IDE_ERROR_OFFSET] = err;
args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG); args->tfRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG);
args->tfRegister[IDE_SECTOR_OFFSET] = IN_BYTE(IDE_SECTOR_REG); args->tfRegister[IDE_SECTOR_OFFSET] = hwif->INB(IDE_SECTOR_REG);
args->tfRegister[IDE_LCYL_OFFSET] = IN_BYTE(IDE_LCYL_REG); args->tfRegister[IDE_LCYL_OFFSET] = hwif->INB(IDE_LCYL_REG);
args->tfRegister[IDE_HCYL_OFFSET] = IN_BYTE(IDE_HCYL_REG); args->tfRegister[IDE_HCYL_OFFSET] = hwif->INB(IDE_HCYL_REG);
args->tfRegister[IDE_SELECT_OFFSET] = IN_BYTE(IDE_SELECT_REG); args->tfRegister[IDE_SELECT_OFFSET] = hwif->INB(IDE_SELECT_REG);
args->tfRegister[IDE_STATUS_OFFSET] = stat; args->tfRegister[IDE_STATUS_OFFSET] = stat;
if ((drive->id->command_set_2 & 0x0400) && if (drive->addressing == 1) {
(drive->id->cfs_enable_2 & 0x0400) && hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
(drive->addressing == 1)) { args->hobRegister[IDE_FEATURE_OFFSET_HOB] = hwif->INB(IDE_FEATURE_REG);
OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB); args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = hwif->INB(IDE_NSECTOR_REG);
args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG); args->hobRegister[IDE_SECTOR_OFFSET_HOB] = hwif->INB(IDE_SECTOR_REG);
args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG); args->hobRegister[IDE_LCYL_OFFSET_HOB] = hwif->INB(IDE_LCYL_REG);
args->hobRegister[IDE_SECTOR_OFFSET_HOB] = IN_BYTE(IDE_SECTOR_REG); args->hobRegister[IDE_HCYL_OFFSET_HOB] = hwif->INB(IDE_HCYL_REG);
args->hobRegister[IDE_LCYL_OFFSET_HOB] = IN_BYTE(IDE_LCYL_REG);
args->hobRegister[IDE_HCYL_OFFSET_HOB] = IN_BYTE(IDE_HCYL_REG);
} }
} }
} }
...@@ -737,21 +511,24 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err) ...@@ -737,21 +511,24 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&ide_lock, flags);
} }
EXPORT_SYMBOL(ide_end_drive_cmd);
/* /*
* Error reporting, in human readable form (luxurious, but a memory hog). * Error reporting, in human readable form (luxurious, but a memory hog).
*/ */
byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat) u8 ide_dump_status (ide_drive_t *drive, const char *msg, u8 stat)
{ {
ide_hwif_t *hwif = HWIF(drive);
unsigned long flags; unsigned long flags;
byte err = 0; u8 err = 0;
local_irq_set(flags); local_irq_set(flags);
printk("%s: %s: status=0x%02x", drive->name, msg, stat); printk("%s: %s: status=0x%02x", drive->name, msg, stat);
#if FANCY_STATUS_DUMPS #if FANCY_STATUS_DUMPS
printk(" { "); printk(" { ");
if (stat & BUSY_STAT) if (stat & BUSY_STAT) {
printk("Busy "); printk("Busy ");
else { } else {
if (stat & READY_STAT) printk("DriveReady "); if (stat & READY_STAT) printk("DriveReady ");
if (stat & WRERR_STAT) printk("DeviceFault "); if (stat & WRERR_STAT) printk("DeviceFault ");
if (stat & SEEK_STAT) printk("SeekComplete "); if (stat & SEEK_STAT) printk("SeekComplete ");
...@@ -764,13 +541,13 @@ byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat) ...@@ -764,13 +541,13 @@ byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat)
#endif /* FANCY_STATUS_DUMPS */ #endif /* FANCY_STATUS_DUMPS */
printk("\n"); printk("\n");
if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) { if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
err = GET_ERR(); err = hwif->INB(IDE_ERROR_REG);
printk("%s: %s: error=0x%02x", drive->name, msg, err); printk("%s: %s: error=0x%02x", drive->name, msg, err);
#if FANCY_STATUS_DUMPS #if FANCY_STATUS_DUMPS
if (drive->media == ide_disk) { if (drive->media == ide_disk) {
printk(" { "); printk(" { ");
if (err & ABRT_ERR) printk("DriveStatusError "); if (err & ABRT_ERR) printk("DriveStatusError ");
if (err & ICRC_ERR) printk("%s", (err & ABRT_ERR) ? "BadCRC " : "BadSector "); if (err & ICRC_ERR) printk("Bad%s ", (err & ABRT_ERR) ? "CRC" : "Sector");
if (err & ECC_ERR) printk("UncorrectableError "); if (err & ECC_ERR) printk("UncorrectableError ");
if (err & ID_ERR) printk("SectorIdNotFound "); if (err & ID_ERR) printk("SectorIdNotFound ");
if (err & TRK0_ERR) printk("TrackZeroNotFound "); if (err & TRK0_ERR) printk("TrackZeroNotFound ");
...@@ -780,30 +557,30 @@ byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat) ...@@ -780,30 +557,30 @@ byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat)
if ((drive->id->command_set_2 & 0x0400) && if ((drive->id->command_set_2 & 0x0400) &&
(drive->id->cfs_enable_2 & 0x0400) && (drive->id->cfs_enable_2 & 0x0400) &&
(drive->addressing == 1)) { (drive->addressing == 1)) {
__u64 sectors = 0; u64 sectors = 0;
u32 low = 0, high = 0; u32 high = 0;
low = read_24(drive); u32 low = read_24(drive);
OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG); hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
high = read_24(drive); high = read_24(drive);
sectors = ((__u64)high << 24) | low; sectors = ((u64)high << 24) | low;
printk(", LBAsect=%llu, high=%d, low=%d", printk(", LBAsect=%llu, high=%d, low=%d",
(unsigned long long) sectors, (u64) sectors,
high, low); high, low);
} else { } else {
byte cur = IN_BYTE(IDE_SELECT_REG); u8 cur = hwif->INB(IDE_SELECT_REG);
if (cur & 0x40) { /* using LBA? */ if (cur & 0x40) { /* using LBA? */
printk(", LBAsect=%ld", (unsigned long) printk(", LBAsect=%ld", (unsigned long)
((cur&0xf)<<24) ((cur&0xf)<<24)
|(IN_BYTE(IDE_HCYL_REG)<<16) |(hwif->INB(IDE_HCYL_REG)<<16)
|(IN_BYTE(IDE_LCYL_REG)<<8) |(hwif->INB(IDE_LCYL_REG)<<8)
| IN_BYTE(IDE_SECTOR_REG)); | hwif->INB(IDE_SECTOR_REG));
} else { } else {
printk(", CHS=%d/%d/%d", printk(", CHS=%d/%d/%d",
(IN_BYTE(IDE_HCYL_REG)<<8) + (hwif->INB(IDE_HCYL_REG)<<8) +
IN_BYTE(IDE_LCYL_REG), hwif->INB(IDE_LCYL_REG),
cur & 0xf, cur & 0xf,
IN_BYTE(IDE_SECTOR_REG)); hwif->INB(IDE_SECTOR_REG));
} }
} }
if (HWGROUP(drive) && HWGROUP(drive)->rq) if (HWGROUP(drive) && HWGROUP(drive)->rq)
...@@ -817,6 +594,8 @@ byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat) ...@@ -817,6 +594,8 @@ byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat)
return err; return err;
} }
EXPORT_SYMBOL(ide_dump_status);
/* /*
* try_to_flush_leftover_data() is invoked in response to a drive * try_to_flush_leftover_data() is invoked in response to a drive
* unexpectedly having its DRQ_STAT bit set. As an alternative to * unexpectedly having its DRQ_STAT bit set. As an alternative to
...@@ -824,7 +603,7 @@ byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat) ...@@ -824,7 +603,7 @@ byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat)
* by read a sector's worth of data from the drive. Of course, * 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*. * this may not help if the drive is *waiting* for data from *us*.
*/ */
static void try_to_flush_leftover_data (ide_drive_t *drive) void try_to_flush_leftover_data (ide_drive_t *drive)
{ {
int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS; int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
...@@ -832,12 +611,15 @@ static void try_to_flush_leftover_data (ide_drive_t *drive) ...@@ -832,12 +611,15 @@ static void try_to_flush_leftover_data (ide_drive_t *drive)
return; return;
while (i > 0) { while (i > 0) {
u32 buffer[16]; u32 buffer[16];
unsigned int wcount = (i > 16) ? 16 : i; u32 wcount = (i > 16) ? 16 : i;
i -= wcount; i -= wcount;
ata_input_data (drive, buffer, wcount); HWIF(drive)->ata_input_data(drive, buffer, wcount);
} }
} }
EXPORT_SYMBOL(try_to_flush_leftover_data);
/* /*
* FIXME Add an ATAPI error * FIXME Add an ATAPI error
*/ */
...@@ -845,56 +627,70 @@ static void try_to_flush_leftover_data (ide_drive_t *drive) ...@@ -845,56 +627,70 @@ static void try_to_flush_leftover_data (ide_drive_t *drive)
/* /*
* ide_error() takes action based on the error returned by the drive. * ide_error() takes action based on the error returned by the drive.
*/ */
ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat) ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, u8 stat)
{ {
ide_hwif_t *hwif;
struct request *rq; struct request *rq;
byte err; u8 err;
err = ide_dump_status(drive, msg, stat); err = ide_dump_status(drive, msg, stat);
if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
return ide_stopped; return ide_stopped;
hwif = HWIF(drive);
/* retry only "normal" I/O: */ /* retry only "normal" I/O: */
if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) { if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) {
rq->errors = 1; rq->errors = 1;
ide_end_drive_cmd(drive, stat, err); ide_end_drive_cmd(drive, stat, err);
return ide_stopped; return ide_stopped;
} else if (rq->flags & REQ_DRIVE_TASKFILE) { }
if (rq->flags & REQ_DRIVE_TASKFILE) {
rq->errors = 1; rq->errors = 1;
ide_end_drive_cmd(drive, stat, err); ide_end_drive_cmd(drive, stat, err);
// ide_end_taskfile(drive, stat, err); // ide_end_taskfile(drive, stat, err);
return ide_stopped; return ide_stopped;
} }
if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */ if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
/* other bits are useless when BUSY */
rq->errors |= ERROR_RESET; rq->errors |= ERROR_RESET;
} else { } else {
if (drive->media != ide_disk)
goto media_out;
/* ide_disk */ if (stat & ERR_STAT) {
if (drive->media == ide_disk && (stat & ERR_STAT)) {
/* err has different meaning on cdrom and tape */ /* err has different meaning on cdrom and tape */
if (err == ABRT_ERR) { if (err == ABRT_ERR) {
if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY) if (drive->select.b.lba &&
return ide_stopped; /* some newer drives don't support WIN_SPECIFY */ (hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY))
} else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR)) { /* some newer drives don't
drive->crc_count++; /* UDMA crc error -- just retry the operation */ * support WIN_SPECIFY
} else if (err & (BBD_ERR | ECC_ERR)) /* retries won't help these */ */
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; rq->errors = ERROR_MAX;
else if (err & TRK0_ERR) /* help it find track zero */ } else if (err & TRK0_ERR) {
/* help it find track zero */
rq->errors |= ERROR_RECAL; rq->errors |= ERROR_RECAL;
} }
/* !ide_disk */ }
if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ) media_out:
if ((stat & DRQ_STAT) && rq_data_dir(rq) != WRITE)
try_to_flush_leftover_data(drive); try_to_flush_leftover_data(drive);
/* !ide_disk */
} }
if (GET_STAT() & (BUSY_STAT|DRQ_STAT)) if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) {
OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); /* force an abort */ /* force an abort */
hwif->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
}
if (rq->errors >= ERROR_MAX) { if (rq->errors >= ERROR_MAX) {
if (drive->driver != NULL) if (drive->driver != NULL)
DRIVER(drive)->end_request(drive, 0); DRIVER(drive)->end_request(drive, 0, 0);
else else
ide_end_request(drive, 0); ide_end_request(drive, 0, 0);
} else { } else {
if ((rq->errors & ERROR_RESET) == ERROR_RESET) { if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
++rq->errors; ++rq->errors;
...@@ -907,53 +703,62 @@ ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat) ...@@ -907,53 +703,62 @@ ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat)
return ide_stopped; return ide_stopped;
} }
EXPORT_SYMBOL(ide_error);
/* /*
* Issue a simple drive command * Issue a simple drive command
* The drive must be selected beforehand. * The drive must be selected beforehand.
*/ */
void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler) void ide_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, ide_handler_t *handler)
{ {
if (HWGROUP(drive)->handler != NULL) /* paranoia check */ ide_hwif_t *hwif = HWIF(drive);
if (HWGROUP(drive)->handler != NULL)
BUG(); BUG();
ide_set_handler (drive, handler, WAIT_CMD, NULL); ide_set_handler(drive, handler, WAIT_CMD, NULL);
if (IDE_CONTROL_REG) if (IDE_CONTROL_REG)
OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */ hwif->OUTB(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */
SELECT_MASK(HWIF(drive),drive,0); SELECT_MASK(drive,0);
OUT_BYTE(nsect,IDE_NSECTOR_REG); hwif->OUTB(nsect,IDE_NSECTOR_REG);
OUT_BYTE(cmd,IDE_COMMAND_REG); hwif->OUTB(cmd,IDE_COMMAND_REG);
} }
EXPORT_SYMBOL(ide_cmd);
/* /*
* drive_cmd_intr() is invoked on completion of a special DRIVE_CMD. * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
*/ */
static ide_startstop_t drive_cmd_intr (ide_drive_t *drive) ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
{ {
struct request *rq = HWGROUP(drive)->rq; struct request *rq = HWGROUP(drive)->rq;
byte *args = (byte *) rq->buffer; ide_hwif_t *hwif = HWIF(drive);
byte stat = GET_STAT(); u8 *args = (u8 *) rq->buffer;
u8 stat = hwif->INB(IDE_STATUS_REG);
int retries = 10; int retries = 10;
local_irq_enable(); local_irq_enable();
if ((stat & DRQ_STAT) && args && args[3]) { if ((stat & DRQ_STAT) && args && args[3]) {
byte io_32bit = drive->io_32bit; u8 io_32bit = drive->io_32bit;
drive->io_32bit = 0; drive->io_32bit = 0;
ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS); hwif->ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
drive->io_32bit = io_32bit; drive->io_32bit = io_32bit;
while (((stat = GET_STAT()) & BUSY_STAT) && retries--) while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
udelay(100); udelay(100);
} }
if (!OK_STAT(stat, READY_STAT, BAD_STAT)) if (!OK_STAT(stat, READY_STAT, BAD_STAT))
return DRIVER(drive)->error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */ return DRIVER(drive)->error(drive, "drive_cmd", stat);
ide_end_drive_cmd (drive, stat, GET_ERR()); /* calls ide_end_drive_cmd */
ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
return ide_stopped; return ide_stopped;
} }
EXPORT_SYMBOL(drive_cmd_intr);
/* /*
* do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT * 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. * 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) ide_startstop_t do_special (ide_drive_t *drive)
{ {
special_t *s = &drive->special; special_t *s = &drive->special;
...@@ -973,12 +778,15 @@ static ide_startstop_t do_special (ide_drive_t *drive) ...@@ -973,12 +778,15 @@ static ide_startstop_t do_special (ide_drive_t *drive)
return ide_stopped; return ide_stopped;
} }
EXPORT_SYMBOL(do_special);
/* /*
* execute_drive_cmd() issues a special drive command, * execute_drive_cmd() issues a special drive command,
* usually initiated by ioctl() from the external hdparm program. * usually initiated by ioctl() from the external hdparm program.
*/ */
static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq) 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) { if (rq->flags & REQ_DRIVE_TASKFILE) {
ide_task_t *args = rq->special; ide_task_t *args = rq->special;
...@@ -989,8 +797,8 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq ...@@ -989,8 +797,8 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq
return flagged_taskfile(drive, args); return flagged_taskfile(drive, args);
return do_rw_taskfile(drive, args); return do_rw_taskfile(drive, args);
} else if (rq->flags & REQ_DRIVE_TASK) { } else if (rq->flags & REQ_DRIVE_TASK) {
byte *args = rq->buffer; u8 *args = rq->buffer;
byte sel; u8 sel;
if (!args) if (!args)
goto done; goto done;
...@@ -1004,18 +812,18 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq ...@@ -1004,18 +812,18 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq
printk("hcyl=0x%02x ", args[5]); printk("hcyl=0x%02x ", args[5]);
printk("sel=0x%02x\n", args[6]); printk("sel=0x%02x\n", args[6]);
#endif #endif
OUT_BYTE(args[1], IDE_FEATURE_REG); hwif->OUTB(args[1], IDE_FEATURE_REG);
OUT_BYTE(args[3], IDE_SECTOR_REG); hwif->OUTB(args[3], IDE_SECTOR_REG);
OUT_BYTE(args[4], IDE_LCYL_REG); hwif->OUTB(args[4], IDE_LCYL_REG);
OUT_BYTE(args[5], IDE_HCYL_REG); hwif->OUTB(args[5], IDE_HCYL_REG);
sel = (args[6] & ~0x10); sel = (args[6] & ~0x10);
if (drive->select.b.unit) if (drive->select.b.unit)
sel |= 0x10; sel |= 0x10;
OUT_BYTE(sel, IDE_SELECT_REG); hwif->OUTB(sel, IDE_SELECT_REG);
ide_cmd(drive, args[0], args[2], &drive_cmd_intr); ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
return ide_started; return ide_started;
} else if (rq->flags & REQ_DRIVE_CMD) { } else if (rq->flags & REQ_DRIVE_CMD) {
byte *args = rq->buffer; u8 *args = rq->buffer;
if (!args) if (!args)
goto done; goto done;
...@@ -1027,14 +835,14 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq ...@@ -1027,14 +835,14 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq
printk("xx=0x%02x\n", args[3]); printk("xx=0x%02x\n", args[3]);
#endif #endif
if (args[0] == WIN_SMART) { if (args[0] == WIN_SMART) {
OUT_BYTE(0x4f, IDE_LCYL_REG); hwif->OUTB(0x4f, IDE_LCYL_REG);
OUT_BYTE(0xc2, IDE_HCYL_REG); hwif->OUTB(0xc2, IDE_HCYL_REG);
OUT_BYTE(args[2],IDE_FEATURE_REG); hwif->OUTB(args[2],IDE_FEATURE_REG);
OUT_BYTE(args[1],IDE_SECTOR_REG); hwif->OUTB(args[1],IDE_SECTOR_REG);
ide_cmd(drive, args[0], args[3], &drive_cmd_intr); ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
return ide_started; return ide_started;
} }
OUT_BYTE(args[2],IDE_FEATURE_REG); hwif->OUTB(args[2],IDE_FEATURE_REG);
ide_cmd(drive, args[0], args[1], &drive_cmd_intr); ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
return ide_started; return ide_started;
} }
...@@ -1047,16 +855,20 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq ...@@ -1047,16 +855,20 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq
#ifdef DEBUG #ifdef DEBUG
printk("%s: DRIVE_CMD (null)\n", drive->name); printk("%s: DRIVE_CMD (null)\n", drive->name);
#endif #endif
ide_end_drive_cmd(drive, GET_STAT(), GET_ERR()); ide_end_drive_cmd(drive,
hwif->INB(IDE_STATUS_REG),
hwif->INB(IDE_ERROR_REG));
return ide_stopped; return ide_stopped;
} }
EXPORT_SYMBOL(execute_drive_cmd);
/* /*
* start_request() initiates handling of a new I/O request * start_request() initiates handling of a new I/O request
* needed to reverse the perverted changes anonymously made back * needed to reverse the perverted changes anonymously made back
* 2.3.99-pre6 * 2.3.99-pre6
*/ */
static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
{ {
ide_startstop_t startstop; ide_startstop_t startstop;
unsigned long block; unsigned long block;
...@@ -1088,15 +900,9 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) ...@@ -1088,15 +900,9 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
hwif->name, kdevname(rq->rq_dev)); hwif->name, kdevname(rq->rq_dev));
goto kill_rq; goto kill_rq;
} }
#ifdef DEBUG
if (rq->bh && !buffer_locked(rq->bh)) {
printk("%s: block not locked\n", drive->name);
goto kill_rq;
}
#endif
block = rq->sector;
if ((rq->flags & REQ_CMD) && block = rq->sector;
if (blk_fs_request(rq) &&
(drive->media == ide_disk || drive->media == ide_floppy)) { (drive->media == ide_disk || drive->media == ide_floppy)) {
block += drive->sect0; block += drive->sect0;
} }
...@@ -1109,7 +915,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) ...@@ -1109,7 +915,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME); while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);
#endif #endif
SELECT_DRIVE(hwif, drive); SELECT_DRIVE(drive);
if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) { if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
printk("%s: drive not ready for command\n", drive->name); printk("%s: drive not ready for command\n", drive->name);
return startstop; return startstop;
...@@ -1129,18 +935,22 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) ...@@ -1129,18 +935,22 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
return do_special(drive); return do_special(drive);
kill_rq: kill_rq:
if (drive->driver != NULL) if (drive->driver != NULL)
DRIVER(drive)->end_request(drive, 0); DRIVER(drive)->end_request(drive, 0, 0);
else else
ide_end_request(drive, 0); ide_end_request(drive, 0, 0);
return ide_stopped; return ide_stopped;
} }
EXPORT_SYMBOL(start_request);
int restart_request (ide_drive_t *drive, struct request *rq) int restart_request (ide_drive_t *drive, struct request *rq)
{ {
(void) start_request(drive, rq); (void) start_request(drive, rq);
return 0; return 0;
} }
EXPORT_SYMBOL(restart_request);
/* /*
* ide_stall_queue() can be used by a drive to give excess bandwidth back * ide_stall_queue() can be used by a drive to give excess bandwidth back
* to the hwgroup by sleeping for timeout jiffies. * to the hwgroup by sleeping for timeout jiffies.
...@@ -1152,6 +962,8 @@ void ide_stall_queue (ide_drive_t *drive, unsigned long timeout) ...@@ -1152,6 +962,8 @@ void ide_stall_queue (ide_drive_t *drive, unsigned long timeout)
drive->sleep = timeout + jiffies; drive->sleep = timeout + jiffies;
} }
EXPORT_SYMBOL(ide_stall_queue);
#define WAKEUP(drive) ((drive)->service_start + 2 * (drive)->service_time) #define WAKEUP(drive) ((drive)->service_start + 2 * (drive)->service_time)
/* /*
...@@ -1242,10 +1054,11 @@ void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) ...@@ -1242,10 +1054,11 @@ void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
struct request *rq; struct request *rq;
ide_startstop_t startstop; ide_startstop_t startstop;
ide_get_lock(&ide_intr_lock, ide_intr, hwgroup);/* for atari only: POSSIBLY BROKEN HERE(?) */ /* for atari only: POSSIBLY BROKEN HERE(?) */
ide_get_lock(&ide_intr_lock, ide_intr, hwgroup);
local_irq_disable();
/* necessary paranoia: ensure IRQs are masked on local CPU */ /* necessary paranoia: ensure IRQs are masked on local CPU */
local_irq_disable();
while (!hwgroup->busy) { while (!hwgroup->busy) {
hwgroup->busy = 1; hwgroup->busy = 1;
...@@ -1271,20 +1084,30 @@ void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) ...@@ -1271,20 +1084,30 @@ void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
if (timer_pending(&hwgroup->timer)) if (timer_pending(&hwgroup->timer))
printk("ide_set_handler: timer already active\n"); printk("ide_set_handler: timer already active\n");
#endif #endif
hwgroup->sleeping = 1; /* so that ide_timer_expiry knows what to do */ /* so that ide_timer_expiry knows what to do */
hwgroup->sleeping = 1;
mod_timer(&hwgroup->timer, sleep); mod_timer(&hwgroup->timer, sleep);
/* we purposely leave hwgroup->busy==1 while sleeping */ /* we purposely leave hwgroup->busy==1
* while sleeping */
} else { } else {
/* Ugly, but how can we sleep for the lock otherwise? perhaps from tq_disk? */ /* Ugly, but how can we sleep for the lock
ide_release_lock(&ide_lock); /* for atari only */ * otherwise? perhaps from tq_disk?
*/
/* for atari only */
ide_release_lock(&ide_lock);
hwgroup->busy = 0; hwgroup->busy = 0;
} }
return; /* no more work for this hwgroup (for now) */
/* no more work for this hwgroup (for now) */
return;
} }
hwif = HWIF(drive); hwif = HWIF(drive);
if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif && hwif->io_ports[IDE_CONTROL_OFFSET]) { if (hwgroup->hwif->sharing_irq &&
hwif != hwgroup->hwif &&
hwif->io_ports[IDE_CONTROL_OFFSET]) {
/* set nIEN for previous hwif */ /* set nIEN for previous hwif */
SELECT_INTERRUPT(hwif, drive); SELECT_INTERRUPT(drive);
} }
hwgroup->hwif = hwif; hwgroup->hwif = hwif;
hwgroup->drive = drive; hwgroup->drive = drive;
...@@ -1317,6 +1140,8 @@ void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) ...@@ -1317,6 +1140,8 @@ void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
} }
} }
EXPORT_SYMBOL(ide_do_request);
/* /*
* ide_get_queue() returns the queue which corresponds to a given device. * ide_get_queue() returns the queue which corresponds to a given device.
*/ */
...@@ -1327,6 +1152,8 @@ request_queue_t *ide_get_queue (kdev_t dev) ...@@ -1327,6 +1152,8 @@ request_queue_t *ide_get_queue (kdev_t dev)
return &hwif->drives[DEVICE_NR(dev) & 1].queue; return &hwif->drives[DEVICE_NR(dev) & 1].queue;
} }
EXPORT_SYMBOL(ide_get_queue);
/* /*
* Passes the stuff to ide_do_request * Passes the stuff to ide_do_request
*/ */
...@@ -1335,7 +1162,6 @@ void do_ide_request(request_queue_t *q) ...@@ -1335,7 +1162,6 @@ void do_ide_request(request_queue_t *q)
ide_do_request(q->queuedata, 0); ide_do_request(q->queuedata, 0);
} }
#ifndef __IDEDMA_TIMEOUT
/* /*
* un-busy the hwgroup etc, and clear any pending DMA status. we want to * 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 * retry the current request in pio mode instead of risking tossing it
...@@ -1349,13 +1175,13 @@ void ide_dma_timeout_retry(ide_drive_t *drive) ...@@ -1349,13 +1175,13 @@ void ide_dma_timeout_retry(ide_drive_t *drive)
/* /*
* end current dma transaction * end current dma transaction
*/ */
(void) hwif->dmaproc(ide_dma_end, drive); (void) hwif->ide_dma_end(drive);
/* /*
* complain a little, later we might remove some of this verbosity * complain a little, later we might remove some of this verbosity
*/ */
printk("%s: timeout waiting for DMA\n", drive->name); printk("%s: timeout waiting for DMA\n", drive->name);
(void) hwif->dmaproc(ide_dma_timeout, drive); (void) hwif->ide_dma_timeout(drive);
/* /*
* disable dma for now, but remember that we did so because of * disable dma for now, but remember that we did so because of
...@@ -1364,7 +1190,7 @@ void ide_dma_timeout_retry(ide_drive_t *drive) ...@@ -1364,7 +1190,7 @@ void ide_dma_timeout_retry(ide_drive_t *drive)
*/ */
drive->retry_pio++; drive->retry_pio++;
drive->state = DMA_PIO_RETRY; drive->state = DMA_PIO_RETRY;
(void) hwif->dmaproc(ide_dma_off_quietly, drive); (void) hwif->ide_dma_off_quietly(drive);
/* /*
* un-busy drive etc (hwgroup->busy is cleared on return) and * un-busy drive etc (hwgroup->busy is cleared on return) and
...@@ -1379,15 +1205,9 @@ void ide_dma_timeout_retry(ide_drive_t *drive) ...@@ -1379,15 +1205,9 @@ void ide_dma_timeout_retry(ide_drive_t *drive)
rq->hard_cur_sectors = rq->current_nr_sectors; rq->hard_cur_sectors = rq->current_nr_sectors;
if (rq->bio) if (rq->bio)
rq->buffer = NULL; rq->buffer = NULL;
/*
* FIXME or DELETE ME
*
* so what do we do if the device is left in an invalid state
* and will not accept commands. SOFT RESET is the only chance.
*/
} }
#endif
EXPORT_SYMBOL(ide_dma_timeout_retry);
/* /*
* ide_timer_expiry() is our timeout function for all drive operations. * ide_timer_expiry() is our timeout function for all drive operations.
...@@ -1441,38 +1261,34 @@ void ide_timer_expiry (unsigned long data) ...@@ -1441,38 +1261,34 @@ void ide_timer_expiry (unsigned long data)
hwgroup->handler = NULL; hwgroup->handler = NULL;
/* /*
* We need to simulate a real interrupt when invoking * We need to simulate a real interrupt when invoking
* the handler() function, which means we need to globally * the handler() function, which means we need to
* mask the specific IRQ: * globally mask the specific IRQ:
*/ */
spin_unlock(&ide_lock); spin_unlock(&ide_lock);
hwif = HWIF(drive); hwif = HWIF(drive);
#if DISABLE_IRQ_NOSYNC #if DISABLE_IRQ_NOSYNC
disable_irq_nosync(hwif->irq); disable_irq_nosync(hwif->irq);
#else #else
disable_irq(hwif->irq); /* disable_irq_nosync ?? */ /* disable_irq_nosync ?? */
disable_irq(hwif->irq);
#endif /* DISABLE_IRQ_NOSYNC */ #endif /* DISABLE_IRQ_NOSYNC */
/* local CPU only,
* as if we were handling an interrupt */
local_irq_disable(); local_irq_disable();
/* local CPU only, as if we were handling an interrupt */
if (hwgroup->poll_timeout != 0) { if (hwgroup->poll_timeout != 0) {
startstop = handler(drive); startstop = handler(drive);
} else if (drive_is_ready(drive)) { } else if (drive_is_ready(drive)) {
if (drive->waiting_for_dma) if (drive->waiting_for_dma)
(void) hwgroup->hwif->dmaproc(ide_dma_lostirq, drive); (void) hwgroup->hwif->ide_dma_lostirq(drive);
(void)ide_ack_intr(hwif); (void)ide_ack_intr(hwif);
printk("%s: lost interrupt\n", drive->name); printk("%s: lost interrupt\n", drive->name);
startstop = handler(drive); startstop = handler(drive);
} else { } else {
if (drive->waiting_for_dma) { if (drive->waiting_for_dma) {
#ifndef __IDEDMA_TIMEOUT
startstop = ide_stopped; startstop = ide_stopped;
ide_dma_timeout_retry(drive); ide_dma_timeout_retry(drive);
#else /* __IDEDMA_TIMEOUT */
(void) hwgroup->hwif->dmaproc(ide_dma_end, drive);
printk("%s: timeout waiting for DMA\n", drive->name);
(void) hwgroup->hwif->dmaproc(ide_dma_timeout, drive);
#endif /* __IDEDMA_TIMEOUT */
} else } else
startstop = DRIVER(drive)->error(drive, "irq timeout", GET_STAT()); startstop = DRIVER(drive)->error(drive, "irq timeout", hwif->INB(IDE_STATUS_REG));
} }
set_recovery_timer(hwif); set_recovery_timer(hwif);
drive->service_time = jiffies - drive->service_start; drive->service_time = jiffies - drive->service_start;
...@@ -1486,6 +1302,8 @@ void ide_timer_expiry (unsigned long data) ...@@ -1486,6 +1302,8 @@ void ide_timer_expiry (unsigned long data)
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&ide_lock, flags);
} }
EXPORT_SYMBOL(ide_timer_expiry);
/* /*
* There's nothing really useful we can do with an unexpected interrupt, * There's nothing really useful we can do with an unexpected interrupt,
* other than reading the status register (to clear it), and logging it. * other than reading the status register (to clear it), and logging it.
...@@ -1511,7 +1329,7 @@ void ide_timer_expiry (unsigned long data) ...@@ -1511,7 +1329,7 @@ void ide_timer_expiry (unsigned long data)
*/ */
static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup) static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
{ {
byte stat; u8 stat;
ide_hwif_t *hwif = hwgroup->hwif; ide_hwif_t *hwif = hwgroup->hwif;
/* /*
...@@ -1519,15 +1337,17 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup) ...@@ -1519,15 +1337,17 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
*/ */
do { do {
if (hwif->irq == irq) { if (hwif->irq == irq) {
stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]); stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
if (!OK_STAT(stat, READY_STAT, BAD_STAT)) { if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
/* Try to not flood the console with msgs */ /* Try to not flood the console with msgs */
static unsigned long last_msgtime, count; static unsigned long last_msgtime, count;
++count; ++count;
if (time_after(jiffies, last_msgtime + HZ)) { if (time_after(jiffies, last_msgtime + HZ)) {
last_msgtime = jiffies; last_msgtime = jiffies;
printk("%s%s: unexpected interrupt, status=0x%02x, count=%ld\n", printk("%s%s: unexpected interrupt, "
hwif->name, (hwif->next == hwgroup->hwif) ? "" : "(?)", stat, count); "status=0x%02x, count=%ld\n",
hwif->name,
(hwif->next==hwgroup->hwif) ? "" : "(?)", stat, count);
} }
} }
} }
...@@ -1554,7 +1374,9 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs) ...@@ -1554,7 +1374,9 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
return; return;
} }
if ((handler = hwgroup->handler) == NULL || hwgroup->poll_timeout != 0) { if ((handler = hwgroup->handler) == NULL ||
hwgroup->poll_timeout != 0) {
printk("ide_intr: unexpected interrupt!\n");
/* /*
* Not expecting an interrupt from this drive. * Not expecting an interrupt from this drive.
* That means this could be: * That means this could be:
...@@ -1568,7 +1390,7 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs) ...@@ -1568,7 +1390,7 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
* so in that case we just ignore it and hope it goes away. * so in that case we just ignore it and hope it goes away.
*/ */
#ifdef CONFIG_BLK_DEV_IDEPCI #ifdef CONFIG_BLK_DEV_IDEPCI
if (IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL)) if (hwif->pci_dev && !hwif->pci_dev->vendor)
#endif /* CONFIG_BLK_DEV_IDEPCI */ #endif /* CONFIG_BLK_DEV_IDEPCI */
{ {
/* /*
...@@ -1582,7 +1404,7 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs) ...@@ -1582,7 +1404,7 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
* Whack the status register, just in case * Whack the status register, just in case
* we have a leftover pending IRQ. * we have a leftover pending IRQ.
*/ */
(void) IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]); (void) hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
#endif /* CONFIG_BLK_DEV_IDEPCI */ #endif /* CONFIG_BLK_DEV_IDEPCI */
} }
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&ide_lock, flags);
...@@ -1618,7 +1440,8 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs) ...@@ -1618,7 +1440,8 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
if (drive->unmask) if (drive->unmask)
local_irq_enable(); local_irq_enable();
startstop = handler(drive); /* service this interrupt, may set handler for next interrupt */ /* service this interrupt, may set handler for next interrupt */
startstop = handler(drive);
spin_lock_irq(&ide_lock); spin_lock_irq(&ide_lock);
/* /*
...@@ -1635,12 +1458,15 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs) ...@@ -1635,12 +1458,15 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
hwgroup->busy = 0; hwgroup->busy = 0;
ide_do_request(hwgroup, hwif->irq); ide_do_request(hwgroup, hwif->irq);
} else { } else {
printk("%s: ide_intr: huh? expected NULL handler on exit\n", drive->name); printk("%s: ide_intr: huh? expected NULL handler "
"on exit\n", drive->name);
} }
} }
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&ide_lock, flags);
} }
EXPORT_SYMBOL(ide_intr);
/* /*
* get_info_ptr() returns the (ide_drive_t *) for a given device number. * get_info_ptr() returns the (ide_drive_t *) for a given device number.
* It returns NULL if the given device number does not match any present drives. * It returns NULL if the given device number does not match any present drives.
...@@ -1648,9 +1474,6 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs) ...@@ -1648,9 +1474,6 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
ide_drive_t *get_info_ptr (kdev_t i_rdev) ide_drive_t *get_info_ptr (kdev_t i_rdev)
{ {
int major = major(i_rdev); int major = major(i_rdev);
#if 0
int minor = minor(i_rdev) & PARTN_MASK;
#endif
unsigned int h; unsigned int h;
for (h = 0; h < MAX_HWIFS; ++h) { for (h = 0; h < MAX_HWIFS; ++h) {
...@@ -1659,11 +1482,7 @@ ide_drive_t *get_info_ptr (kdev_t i_rdev) ...@@ -1659,11 +1482,7 @@ ide_drive_t *get_info_ptr (kdev_t i_rdev)
unsigned unit = DEVICE_NR(i_rdev); unsigned unit = DEVICE_NR(i_rdev);
if (unit < MAX_DRIVES) { if (unit < MAX_DRIVES) {
ide_drive_t *drive = &hwif->drives[unit]; ide_drive_t *drive = &hwif->drives[unit];
#if 0
if (drive->present && get_capacity(drive->disk))
#else
if (drive->present) if (drive->present)
#endif
return drive; return drive;
} }
break; break;
...@@ -1672,6 +1491,8 @@ ide_drive_t *get_info_ptr (kdev_t i_rdev) ...@@ -1672,6 +1491,8 @@ ide_drive_t *get_info_ptr (kdev_t i_rdev)
return NULL; return NULL;
} }
EXPORT_SYMBOL(get_info_ptr);
/* /*
* This function is intended to be used prior to invoking ide_do_drive_cmd(). * This function is intended to be used prior to invoking ide_do_drive_cmd().
*/ */
...@@ -1681,6 +1502,8 @@ void ide_init_drive_cmd (struct request *rq) ...@@ -1681,6 +1502,8 @@ void ide_init_drive_cmd (struct request *rq)
rq->flags = REQ_DRIVE_CMD; rq->flags = REQ_DRIVE_CMD;
} }
EXPORT_SYMBOL(ide_init_drive_cmd);
/* /*
* This function issues a special IDE device request * This function issues a special IDE device request
* onto the request queue. * onto the request queue.
...@@ -1738,18 +1561,24 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio ...@@ -1738,18 +1561,24 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
ide_do_request(hwgroup, 0); ide_do_request(hwgroup, 0);
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&ide_lock, flags);
if (action == ide_wait) { if (action == ide_wait) {
wait_for_completion(&wait); /* wait for it to be serviced */ /* wait for it to be serviced */
return rq->errors ? -EIO : 0; /* return -EIO if errors */ wait_for_completion(&wait);
/* return -EIO if errors */
return rq->errors ? -EIO : 0;
} }
return 0; return 0;
} }
EXPORT_SYMBOL(ide_do_drive_cmd);
void ide_revalidate_drive (ide_drive_t *drive) void ide_revalidate_drive (ide_drive_t *drive)
{ {
set_capacity(drive->disk, current_capacity(drive)); set_capacity(drive->disk, current_capacity(drive));
} }
EXPORT_SYMBOL(ide_revalidate_drive);
/* /*
* This routine is called to flush all partitions and partition tables * This routine is called to flush all partitions and partition tables
* for a changed disk, and then re-read the new partition table. * for a changed disk, and then re-read the new partition table.
...@@ -1758,7 +1587,7 @@ void ide_revalidate_drive (ide_drive_t *drive) ...@@ -1758,7 +1587,7 @@ void ide_revalidate_drive (ide_drive_t *drive)
* usage == 1 (we need an open channel to use an ioctl :-), so this * usage == 1 (we need an open channel to use an ioctl :-), so this
* is our limit. * is our limit.
*/ */
static int ide_revalidate_disk (kdev_t i_rdev) int ide_revalidate_disk (kdev_t i_rdev)
{ {
ide_drive_t *drive; ide_drive_t *drive;
if ((drive = get_info_ptr(i_rdev)) == NULL) if ((drive = get_info_ptr(i_rdev)) == NULL)
...@@ -1768,7 +1597,9 @@ static int ide_revalidate_disk (kdev_t i_rdev) ...@@ -1768,7 +1597,9 @@ static int ide_revalidate_disk (kdev_t i_rdev)
return 0; return 0;
} }
static void ide_probe_module (void) EXPORT_SYMBOL(ide_revalidate_disk);
void ide_probe_module (void)
{ {
if (!ide_probe) { if (!ide_probe) {
#if defined(CONFIG_KMOD) && defined(CONFIG_BLK_DEV_IDE_MODULE) #if defined(CONFIG_KMOD) && defined(CONFIG_BLK_DEV_IDE_MODULE)
...@@ -1779,32 +1610,30 @@ static void ide_probe_module (void) ...@@ -1779,32 +1610,30 @@ static void ide_probe_module (void)
} }
} }
EXPORT_SYMBOL(ide_probe_module);
static int ide_open (struct inode * inode, struct file * filp) static int ide_open (struct inode * inode, struct file * filp)
{ {
ide_drive_t *drive; ide_drive_t *drive;
if ((drive = get_info_ptr(inode->i_rdev)) == NULL) if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
return -ENXIO; return -ENXIO;
#ifdef CONFIG_KMOD
if (drive->driver == NULL) { if (drive->driver == NULL) {
if (drive->media == ide_disk) if (drive->media == ide_disk)
(void) request_module("ide-disk"); (void) request_module("ide-disk");
if (drive->scsi)
(void) request_module("ide-scsi");
if (drive->media == ide_cdrom) if (drive->media == ide_cdrom)
(void) request_module("ide-cd"); (void) request_module("ide-cd");
if (drive->media == ide_tape) if (drive->media == ide_tape)
(void) request_module("ide-tape"); (void) request_module("ide-tape");
if (drive->media == ide_floppy) if (drive->media == ide_floppy)
(void) request_module("ide-floppy"); (void) request_module("ide-floppy");
#if defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI)
if (drive->media == ide_scsi)
(void) request_module("ide-scsi");
#endif /* defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) */
} }
#endif /* CONFIG_KMOD */
drive->usage++; drive->usage++;
if (drive->driver != NULL) if (drive->driver != NULL)
return DRIVER(drive)->open(inode, filp, drive); return DRIVER(drive)->open(inode, filp, drive);
printk ("%s: driver not present\n", drive->name); printk (KERN_WARNING "%s: driver not present\n", drive->name);
drive->usage--; drive->usage--;
return -ENXIO; return -ENXIO;
} }
...@@ -1864,33 +1693,6 @@ struct seq_operations ide_drivers_op = { ...@@ -1864,33 +1693,6 @@ struct seq_operations ide_drivers_op = {
show: show_driver show: show_driver
}; };
/*
* Locking is badly broken here - since way back. That sucker is
* root-only, but that's not an excuse... The real question is what
* exclusion rules do we want here.
*/
int ide_replace_subdriver (ide_drive_t *drive, const char *driver)
{
if (!drive->present || drive->usage)
goto abort;
if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
goto abort;
strncpy(drive->driver_req, driver, 9);
if (ata_attach(drive)) {
spin_lock(&drives_lock);
list_del_init(&drive->list);
spin_unlock(&drives_lock);
drive->driver_req[0] = 0;
ata_attach(drive);
} else {
drive->driver_req[0] = 0;
}
if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver))
return 0;
abort:
return 1;
}
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
ide_proc_entry_t generic_subdriver_entries[] = { ide_proc_entry_t generic_subdriver_entries[] = {
{ "capacity", S_IFREG|S_IRUGO, proc_ide_read_capacity, NULL }, { "capacity", S_IFREG|S_IRUGO, proc_ide_read_capacity, NULL },
...@@ -1898,6 +1700,10 @@ ide_proc_entry_t generic_subdriver_entries[] = { ...@@ -1898,6 +1700,10 @@ ide_proc_entry_t generic_subdriver_entries[] = {
}; };
#endif #endif
#define hwif_release_region(addr, num) \
((hwif->mmio) ? release_mem_region((addr),(num)) : release_region((addr),(num)))
/* /*
* Note that we only release the standard ports, * Note that we only release the standard ports,
* and do not even try to handle any extra ports * and do not even try to handle any extra ports
...@@ -1905,35 +1711,32 @@ ide_proc_entry_t generic_subdriver_entries[] = { ...@@ -1905,35 +1711,32 @@ ide_proc_entry_t generic_subdriver_entries[] = {
*/ */
void hwif_unregister (ide_hwif_t *hwif) void hwif_unregister (ide_hwif_t *hwif)
{ {
if (hwif->straight8) { u32 i = 0;
ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);
goto jump_eight; if (hwif->mmio == 2)
} return;
if (hwif->io_ports[IDE_DATA_OFFSET])
ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
if (hwif->io_ports[IDE_ERROR_OFFSET])
ide_release_region(hwif->io_ports[IDE_ERROR_OFFSET], 1);
if (hwif->io_ports[IDE_NSECTOR_OFFSET])
ide_release_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1);
if (hwif->io_ports[IDE_SECTOR_OFFSET])
ide_release_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1);
if (hwif->io_ports[IDE_LCYL_OFFSET])
ide_release_region(hwif->io_ports[IDE_LCYL_OFFSET], 1);
if (hwif->io_ports[IDE_HCYL_OFFSET])
ide_release_region(hwif->io_ports[IDE_HCYL_OFFSET], 1);
if (hwif->io_ports[IDE_SELECT_OFFSET])
ide_release_region(hwif->io_ports[IDE_SELECT_OFFSET], 1);
if (hwif->io_ports[IDE_STATUS_OFFSET])
ide_release_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);
jump_eight:
if (hwif->io_ports[IDE_CONTROL_OFFSET]) if (hwif->io_ports[IDE_CONTROL_OFFSET])
ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1); hwif_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC) #if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
if (hwif->io_ports[IDE_IRQ_OFFSET]) if (hwif->io_ports[IDE_IRQ_OFFSET])
ide_release_region(hwif->io_ports[IDE_IRQ_OFFSET], 1); hwif_release_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */ #endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
if (hwif->straight8) {
hwif_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);
return;
}
for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
if (hwif->io_ports[i]) {
hwif_release_region(hwif->io_ports[i], 1);
}
}
} }
EXPORT_SYMBOL(hwif_unregister);
extern void init_hwif_data(unsigned int index);
void ide_unregister (unsigned int index) void ide_unregister (unsigned int index)
{ {
struct gendisk *gd; struct gendisk *gd;
...@@ -1994,7 +1797,7 @@ void ide_unregister (unsigned int index) ...@@ -1994,7 +1797,7 @@ void ide_unregister (unsigned int index)
g = g->next; g = g->next;
} while (g != hwgroup->hwif); } while (g != hwgroup->hwif);
if (irq_count == 1) if (irq_count == 1)
ide_free_irq(hwif->irq, hwgroup); free_irq(hwif->irq, hwgroup);
/* /*
* Note that we only release the standard ports, * Note that we only release the standard ports,
...@@ -2011,7 +1814,7 @@ void ide_unregister (unsigned int index) ...@@ -2011,7 +1814,7 @@ void ide_unregister (unsigned int index)
for (i = 0; i < MAX_DRIVES; ++i) { for (i = 0; i < MAX_DRIVES; ++i) {
drive = &hwif->drives[i]; drive = &hwif->drives[i];
if (drive->de) { if (drive->de) {
devfs_unregister (drive->de); devfs_unregister(drive->de);
drive->de = NULL; drive->de = NULL;
} }
if (!drive->present) if (!drive->present)
...@@ -2041,7 +1844,14 @@ void ide_unregister (unsigned int index) ...@@ -2041,7 +1844,14 @@ void ide_unregister (unsigned int index)
#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI) #if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
if (hwif->dma_base) { if (hwif->dma_base) {
(void) ide_release_dma(hwif); (void) ide_release_dma(hwif);
hwif->dma_base = 0; hwif->dma_base = 0;
hwif->dma_master = 0;
hwif->dma_command = 0;
hwif->dma_vendor1 = 0;
hwif->dma_status = 0;
hwif->dma_vendor3 = 0;
hwif->dma_prdtable = 0;
} }
#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */ #endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
...@@ -2060,42 +1870,133 @@ void ide_unregister (unsigned int index) ...@@ -2060,42 +1870,133 @@ void ide_unregister (unsigned int index)
kfree(gd); kfree(gd);
} }
old_hwif = *hwif; old_hwif = *hwif;
init_hwif_data (index); /* restore hwif data to pristine status */ init_hwif_data(index); /* restore hwif data to pristine status */
hwif->hwgroup = old_hwif.hwgroup; hwif->hwgroup = old_hwif.hwgroup;
hwif->proc = old_hwif.proc;
hwif->major = old_hwif.major;
// hwif->index = old_hwif.index;
// hwif->channel = old_hwif.channel;
hwif->straight8 = old_hwif.straight8;
hwif->bus_state = old_hwif.bus_state;
hwif->atapi_dma = old_hwif.atapi_dma;
hwif->ultra_mask = old_hwif.ultra_mask;
hwif->mwdma_mask = old_hwif.mwdma_mask;
hwif->swdma_mask = old_hwif.swdma_mask;
hwif->chipset = old_hwif.chipset;
#ifdef CONFIG_BLK_DEV_IDEPCI
hwif->pci_dev = old_hwif.pci_dev;
hwif->cds = old_hwif.cds;
#endif /* CONFIG_BLK_DEV_IDEPCI */
#if 0
hwif->hwifops = old_hwif.hwifops;
#else
hwif->identify = old_hwif.identify;
hwif->tuneproc = old_hwif.tuneproc; hwif->tuneproc = old_hwif.tuneproc;
hwif->speedproc = old_hwif.speedproc; hwif->speedproc = old_hwif.speedproc;
hwif->selectproc = old_hwif.selectproc; hwif->selectproc = old_hwif.selectproc;
hwif->reset_poll = old_hwif.reset_poll;
hwif->pre_reset = old_hwif.pre_reset;
hwif->resetproc = old_hwif.resetproc; hwif->resetproc = old_hwif.resetproc;
hwif->intrproc = old_hwif.intrproc; hwif->intrproc = old_hwif.intrproc;
hwif->maskproc = old_hwif.maskproc; hwif->maskproc = old_hwif.maskproc;
hwif->quirkproc = old_hwif.quirkproc; hwif->quirkproc = old_hwif.quirkproc;
hwif->rwproc = old_hwif.rwproc;
hwif->ideproc = old_hwif.ideproc;
hwif->dmaproc = old_hwif.dmaproc;
hwif->busproc = old_hwif.busproc; hwif->busproc = old_hwif.busproc;
hwif->bus_state = old_hwif.bus_state; #endif
#if 0
hwif->pioops = old_hwif.pioops;
#else
hwif->ata_input_data = old_hwif.ata_input_data;
hwif->ata_output_data = old_hwif.ata_output_data;
hwif->atapi_input_bytes = old_hwif.atapi_input_bytes;
hwif->atapi_output_bytes = old_hwif.atapi_output_bytes;
#endif
#if 0
hwif->dmaops = old_hwif.dmaops;
#else
hwif->ide_dma_read = old_hwif.ide_dma_read;
hwif->ide_dma_write = old_hwif.ide_dma_write;
hwif->ide_dma_begin = old_hwif.ide_dma_begin;
hwif->ide_dma_end = old_hwif.ide_dma_end;
hwif->ide_dma_check = old_hwif.ide_dma_check;
hwif->ide_dma_on = old_hwif.ide_dma_on;
hwif->ide_dma_off = old_hwif.ide_dma_off;
hwif->ide_dma_off_quietly = old_hwif.ide_dma_off_quietly;
hwif->ide_dma_test_irq = old_hwif.ide_dma_test_irq;
hwif->ide_dma_host_on = old_hwif.ide_dma_host_on;
hwif->ide_dma_host_off = old_hwif.ide_dma_host_off;
hwif->ide_dma_bad_drive = old_hwif.ide_dma_bad_drive;
hwif->ide_dma_good_drive = old_hwif.ide_dma_good_drive;
hwif->ide_dma_count = old_hwif.ide_dma_count;
hwif->ide_dma_verbose = old_hwif.ide_dma_verbose;
hwif->ide_dma_retune = old_hwif.ide_dma_retune;
hwif->ide_dma_lostirq = old_hwif.ide_dma_lostirq;
hwif->ide_dma_timeout = old_hwif.ide_dma_timeout;
#endif
#if 0
hwif->iops = old_hwif.iops;
#else
hwif->OUTB = old_hwif.OUTB;
hwif->OUTW = old_hwif.OUTW;
hwif->OUTL = old_hwif.OUTL;
hwif->OUTBP = old_hwif.OUTBP;
hwif->OUTWP = old_hwif.OUTWP;
hwif->OUTLP = old_hwif.OUTLP;
hwif->OUTSW = old_hwif.OUTSW;
hwif->OUTSWP = old_hwif.OUTSWP;
hwif->OUTSL = old_hwif.OUTSL;
hwif->OUTSLP = old_hwif.OUTSLP;
hwif->INB = old_hwif.INB;
hwif->INW = old_hwif.INW;
hwif->INL = old_hwif.INL;
hwif->INBP = old_hwif.INBP;
hwif->INWP = old_hwif.INWP;
hwif->INLP = old_hwif.INLP;
hwif->INSW = old_hwif.INSW;
hwif->INSWP = old_hwif.INSWP;
hwif->INSL = old_hwif.INSL;
hwif->INSLP = old_hwif.INSLP;
#endif
hwif->mmio = old_hwif.mmio;
hwif->rqsize = old_hwif.rqsize;
hwif->addressing = old_hwif.addressing;
#ifndef CONFIG_BLK_DEV_IDECS
hwif->irq = old_hwif.irq;
#endif /* CONFIG_BLK_DEV_IDECS */
hwif->initializing = old_hwif.initializing;
hwif->dma_base = old_hwif.dma_base; hwif->dma_base = old_hwif.dma_base;
hwif->dma_master = old_hwif.dma_master;
hwif->dma_command = old_hwif.dma_command;
hwif->dma_vendor1 = old_hwif.dma_vendor1;
hwif->dma_status = old_hwif.dma_status;
hwif->dma_vendor3 = old_hwif.dma_vendor3;
hwif->dma_prdtable = old_hwif.dma_prdtable;
hwif->dma_extra = old_hwif.dma_extra; hwif->dma_extra = old_hwif.dma_extra;
hwif->config_data = old_hwif.config_data; hwif->config_data = old_hwif.config_data;
hwif->select_data = old_hwif.select_data; hwif->select_data = old_hwif.select_data;
hwif->proc = old_hwif.proc;
#ifndef CONFIG_BLK_DEV_IDECS
hwif->irq = old_hwif.irq;
#endif /* CONFIG_BLK_DEV_IDECS */
hwif->major = old_hwif.major;
hwif->chipset = old_hwif.chipset;
hwif->autodma = old_hwif.autodma; hwif->autodma = old_hwif.autodma;
hwif->udma_four = old_hwif.udma_four; hwif->udma_four = old_hwif.udma_four;
#ifdef CONFIG_BLK_DEV_IDEPCI hwif->no_dsc = old_hwif.no_dsc;
hwif->pci_dev = old_hwif.pci_dev;
hwif->pci_devid = old_hwif.pci_devid;
#endif /* CONFIG_BLK_DEV_IDEPCI */
hwif->straight8 = old_hwif.straight8;
hwif->hwif_data = old_hwif.hwif_data; hwif->hwif_data = old_hwif.hwif_data;
abort: abort:
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&ide_lock, flags);
} }
EXPORT_SYMBOL(ide_unregister);
/* /*
* Setup hw_regs_t structure described by parameters. You * Setup hw_regs_t structure described by parameters. You
* may set up the hw structure yourself OR use this routine to * may set up the hw structure yourself OR use this routine to
...@@ -2104,7 +2005,11 @@ void ide_unregister (unsigned int index) ...@@ -2104,7 +2005,11 @@ void ide_unregister (unsigned int index)
void ide_setup_ports ( hw_regs_t *hw, void ide_setup_ports ( hw_regs_t *hw,
ide_ioreg_t base, int *offsets, ide_ioreg_t base, int *offsets,
ide_ioreg_t ctrl, ide_ioreg_t intr, ide_ioreg_t ctrl, ide_ioreg_t intr,
ide_ack_intr_t *ack_intr, int irq) ide_ack_intr_t *ack_intr,
/*
* ide_io_ops_t *iops,
*/
int irq)
{ {
int i; int i;
...@@ -2130,8 +2035,13 @@ void ide_setup_ports ( hw_regs_t *hw, ...@@ -2130,8 +2035,13 @@ void ide_setup_ports ( hw_regs_t *hw,
hw->irq = irq; hw->irq = irq;
hw->dma = NO_DMA; hw->dma = NO_DMA;
hw->ack_intr = ack_intr; hw->ack_intr = ack_intr;
/*
* hw->iops = iops;
*/
} }
EXPORT_SYMBOL(ide_setup_ports);
/* /*
* Register an IDE interface, specifing exactly the registers etc * Register an IDE interface, specifing exactly the registers etc
* Set init=1 iff calling before probes have taken place. * Set init=1 iff calling before probes have taken place.
...@@ -2181,6 +2091,8 @@ int ide_register_hw (hw_regs_t *hw, ide_hwif_t **hwifp) ...@@ -2181,6 +2091,8 @@ int ide_register_hw (hw_regs_t *hw, ide_hwif_t **hwifp)
return (initializing || hwif->present) ? index : -1; return (initializing || hwif->present) ? index : -1;
} }
EXPORT_SYMBOL(ide_register_hw);
/* /*
* Compatability function with existing drivers. If you want * Compatability function with existing drivers. If you want
* something different, use the function above. * something different, use the function above.
...@@ -2193,6 +2105,8 @@ int ide_register (int arg1, int arg2, int irq) ...@@ -2193,6 +2105,8 @@ int ide_register (int arg1, int arg2, int irq)
return ide_register_hw(&hw, NULL); return ide_register_hw(&hw, NULL);
} }
EXPORT_SYMBOL(ide_register);
void ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set) void ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
{ {
ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL; ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
...@@ -2204,12 +2118,18 @@ void ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioc ...@@ -2204,12 +2118,18 @@ void ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioc
memset(setting, 0, sizeof(*setting)); memset(setting, 0, sizeof(*setting));
if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL) if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL)
goto abort; goto abort;
strcpy(setting->name, name); setting->rw = rw; strcpy(setting->name, name);
setting->read_ioctl = read_ioctl; setting->write_ioctl = write_ioctl; setting->rw = rw;
setting->data_type = data_type; setting->min = min; setting->read_ioctl = read_ioctl;
setting->max = max; setting->mul_factor = mul_factor; setting->write_ioctl = write_ioctl;
setting->div_factor = div_factor; setting->data = data; setting->data_type = data_type;
setting->set = set; setting->next = *p; setting->min = min;
setting->max = max;
setting->mul_factor = mul_factor;
setting->div_factor = div_factor;
setting->data = data;
setting->set = set;
setting->next = *p;
if (drive->driver) if (drive->driver)
setting->auto_remove = 1; setting->auto_remove = 1;
*p = setting; *p = setting;
...@@ -2219,6 +2139,8 @@ void ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioc ...@@ -2219,6 +2139,8 @@ void ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioc
kfree(setting); kfree(setting);
} }
EXPORT_SYMBOL(ide_add_setting);
void ide_remove_setting (ide_drive_t *drive, char *name) void ide_remove_setting (ide_drive_t *drive, char *name)
{ {
ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting; ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting;
...@@ -2232,6 +2154,8 @@ void ide_remove_setting (ide_drive_t *drive, char *name) ...@@ -2232,6 +2154,8 @@ void ide_remove_setting (ide_drive_t *drive, char *name)
kfree(setting); kfree(setting);
} }
EXPORT_SYMBOL(ide_remove_setting);
static ide_settings_t *ide_find_setting_by_ioctl (ide_drive_t *drive, int cmd) static ide_settings_t *ide_find_setting_by_ioctl (ide_drive_t *drive, int cmd)
{ {
ide_settings_t *setting = drive->settings; ide_settings_t *setting = drive->settings;
...@@ -2316,6 +2240,8 @@ int ide_spin_wait_hwgroup (ide_drive_t *drive) ...@@ -2316,6 +2240,8 @@ int ide_spin_wait_hwgroup (ide_drive_t *drive)
return 0; return 0;
} }
EXPORT_SYMBOL(ide_spin_wait_hwgroup);
/* /*
* FIXME: This should be changed to enqueue a special request * FIXME: This should be changed to enqueue a special request
* to the driver to change settings, and then wait on a sema for completion. * to the driver to change settings, and then wait on a sema for completion.
...@@ -2356,6 +2282,8 @@ int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val) ...@@ -2356,6 +2282,8 @@ int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val)
return 0; return 0;
} }
EXPORT_SYMBOL(ide_write_setting);
static int set_io_32bit(ide_drive_t *drive, int arg) static int set_io_32bit(ide_drive_t *drive, int arg)
{ {
drive->io_32bit = arg; drive->io_32bit = arg;
...@@ -2370,10 +2298,15 @@ static int set_using_dma (ide_drive_t *drive, int arg) ...@@ -2370,10 +2298,15 @@ static int set_using_dma (ide_drive_t *drive, int arg)
{ {
if (!drive->driver || !DRIVER(drive)->supports_dma) if (!drive->driver || !DRIVER(drive)->supports_dma)
return -EPERM; return -EPERM;
if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc) if (!drive->id || !(drive->id->capability & 1))
return -EPERM; return -EPERM;
if (HWIF(drive)->dmaproc(arg ? ide_dma_on : ide_dma_off, drive)) if (HWIF(drive)->ide_dma_check == NULL)
return -EIO; return -EPERM;
if (arg) {
if (HWIF(drive)->ide_dma_on(drive)) return -EIO;
} else {
if (HWIF(drive)->ide_dma_off(drive)) return -EIO;
}
return 0; return 0;
} }
...@@ -2386,9 +2319,46 @@ static int set_pio_mode (ide_drive_t *drive, int arg) ...@@ -2386,9 +2319,46 @@ static int set_pio_mode (ide_drive_t *drive, int arg)
if (drive->special.b.set_tune) if (drive->special.b.set_tune)
return -EBUSY; return -EBUSY;
ide_init_drive_cmd(&rq); ide_init_drive_cmd(&rq);
drive->tune_req = (byte) arg; drive->tune_req = (u8) arg;
drive->special.b.set_tune = 1; drive->special.b.set_tune = 1;
(void) ide_do_drive_cmd (drive, &rq, ide_wait); (void) ide_do_drive_cmd(drive, &rq, ide_wait);
return 0;
}
static int set_xfer_rate (ide_drive_t *drive, int arg)
{
int err = ide_wait_cmd(drive,
WIN_SETFEATURES, (u8) arg,
SETFEATURES_XFER, 0, NULL);
if (!err && arg) {
if ((HWIF(drive)->speedproc) != NULL)
HWIF(drive)->speedproc(drive, (u8) arg);
ide_driveid_update(drive);
}
return err;
}
int ide_atapi_to_scsi (ide_drive_t *drive, int arg)
{
if (drive->media == ide_disk) {
drive->scsi = 0;
return 0;
}
if (drive->driver != NULL) {
#if 0
ide_unregister_subdriver(drive);
#else
if (DRIVER(drive)->cleanup(drive)) {
drive->scsi = 0;
return 0;
}
#endif
}
drive->scsi = (u8) arg;
ata_attach(drive);
return 0; return 0;
} }
...@@ -2404,37 +2374,11 @@ void ide_add_generic_settings (ide_drive_t *drive) ...@@ -2404,37 +2374,11 @@ void ide_add_generic_settings (ide_drive_t *drive)
ide_add_setting(drive, "slow", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->slow, NULL); ide_add_setting(drive, "slow", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->slow, NULL);
ide_add_setting(drive, "unmaskirq", drive->no_unmask ? SETTING_READ : SETTING_RW, HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, TYPE_BYTE, 0, 1, 1, 1, &drive->unmask, NULL); ide_add_setting(drive, "unmaskirq", drive->no_unmask ? SETTING_READ : SETTING_RW, HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, TYPE_BYTE, 0, 1, 1, 1, &drive->unmask, NULL);
ide_add_setting(drive, "using_dma", SETTING_RW, HDIO_GET_DMA, HDIO_SET_DMA, TYPE_BYTE, 0, 1, 1, 1, &drive->using_dma, set_using_dma); ide_add_setting(drive, "using_dma", SETTING_RW, HDIO_GET_DMA, HDIO_SET_DMA, TYPE_BYTE, 0, 1, 1, 1, &drive->using_dma, set_using_dma);
ide_add_setting(drive, "ide_scsi", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->scsi, NULL);
ide_add_setting(drive, "init_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->init_speed, NULL); ide_add_setting(drive, "init_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->init_speed, NULL);
ide_add_setting(drive, "current_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->current_speed, NULL); ide_add_setting(drive, "current_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->current_speed, set_xfer_rate);
ide_add_setting(drive, "number", SETTING_RW, -1, -1, TYPE_BYTE, 0, 3, 1, 1, &drive->dn, NULL); ide_add_setting(drive, "number", SETTING_RW, -1, -1, TYPE_BYTE, 0, 3, 1, 1, &drive->dn, NULL);
} if (drive->media != ide_disk)
ide_add_setting(drive, "ide-scsi", SETTING_RW, -1, HDIO_SET_IDE_SCSI, TYPE_BYTE, 0, 1, 1, 1, &drive->scsi, ide_atapi_to_scsi);
int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf)
{
struct request rq;
byte buffer[4];
if (!buf)
buf = buffer;
memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors);
ide_init_drive_cmd(&rq);
rq.buffer = buf;
*buf++ = cmd;
*buf++ = nsect;
*buf++ = feature;
*buf++ = sectors;
return ide_do_drive_cmd(drive, &rq, ide_wait);
}
int ide_wait_cmd_task (ide_drive_t *drive, byte *buf)
{
struct request rq;
ide_init_drive_cmd(&rq);
rq.flags = REQ_DRIVE_TASK;
rq.buffer = buf;
return ide_do_drive_cmd(drive, &rq, ide_wait);
} }
/* /*
...@@ -2455,11 +2399,44 @@ void ide_delay_50ms (void) ...@@ -2455,11 +2399,44 @@ void ide_delay_50ms (void)
#endif /* CONFIG_BLK_DEV_IDECS */ #endif /* CONFIG_BLK_DEV_IDECS */
} }
EXPORT_SYMBOL(ide_delay_50ms);
int system_bus_clock (void) int system_bus_clock (void)
{ {
return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed )); return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed ));
} }
EXPORT_SYMBOL(system_bus_clock);
/*
* Locking is badly broken here - since way back. That sucker is
* root-only, but that's not an excuse... The real question is what
* exclusion rules do we want here.
*/
int ide_replace_subdriver (ide_drive_t *drive, const char *driver)
{
if (!drive->present || drive->usage)
goto abort;
if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
goto abort;
strncpy(drive->driver_req, driver, 9);
if (ata_attach(drive)) {
spin_lock(&drives_lock);
list_del_init(&drive->list);
spin_unlock(&drives_lock);
drive->driver_req[0] = 0;
ata_attach(drive);
} else {
drive->driver_req[0] = 0;
}
if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver))
return 0;
abort:
return 1;
}
EXPORT_SYMBOL(ide_replace_subdriver);
int ata_attach(ide_drive_t *drive) int ata_attach(ide_drive_t *drive)
{ {
struct list_head *p; struct list_head *p;
...@@ -2469,7 +2446,7 @@ int ata_attach(ide_drive_t *drive) ...@@ -2469,7 +2446,7 @@ int ata_attach(ide_drive_t *drive)
if (!try_inc_mod_count(driver->owner)) if (!try_inc_mod_count(driver->owner))
continue; continue;
spin_unlock(&drivers_lock); spin_unlock(&drivers_lock);
if (driver->reinit(drive) == 0) { if (driver->attach(drive) == 0) {
if (driver->owner) if (driver->owner)
__MOD_DEC_USE_COUNT(driver->owner); __MOD_DEC_USE_COUNT(driver->owner);
return 0; return 0;
...@@ -2485,6 +2462,8 @@ int ata_attach(ide_drive_t *drive) ...@@ -2485,6 +2462,8 @@ int ata_attach(ide_drive_t *drive)
return 1; return 1;
} }
EXPORT_SYMBOL(ata_attach);
static int ide_ioctl (struct inode *inode, struct file *file, static int ide_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
...@@ -2514,11 +2493,11 @@ static int ide_ioctl (struct inode *inode, struct file *file, ...@@ -2514,11 +2493,11 @@ static int ide_ioctl (struct inode *inode, struct file *file,
case HDIO_GETGEO: case HDIO_GETGEO:
{ {
struct hd_geometry *loc = (struct hd_geometry *) arg; struct hd_geometry *loc = (struct hd_geometry *) arg;
unsigned short bios_cyl = drive->bios_cyl; /* truncate */ u16 bios_cyl = drive->bios_cyl; /* truncate */
if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL; if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT; if (put_user(drive->bios_head, (u8 *) &loc->heads)) return -EFAULT;
if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT; if (put_user(drive->bios_sect, (u8 *) &loc->sectors)) return -EFAULT;
if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT; if (put_user(bios_cyl, (u16 *) &loc->cylinders)) return -EFAULT;
if (put_user((unsigned)get_start_sect(inode->i_bdev), if (put_user((unsigned)get_start_sect(inode->i_bdev),
(unsigned long *) &loc->start)) return -EFAULT; (unsigned long *) &loc->start)) return -EFAULT;
return 0; return 0;
...@@ -2528,8 +2507,8 @@ static int ide_ioctl (struct inode *inode, struct file *file, ...@@ -2528,8 +2507,8 @@ static int ide_ioctl (struct inode *inode, struct file *file,
{ {
struct hd_big_geometry *loc = (struct hd_big_geometry *) arg; struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL; if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
if (put_user(drive->head, (byte *) &loc->heads)) return -EFAULT; if (put_user(drive->head, (u8 *) &loc->heads)) return -EFAULT;
if (put_user(drive->sect, (byte *) &loc->sectors)) return -EFAULT; if (put_user(drive->sect, (u8 *) &loc->sectors)) return -EFAULT;
if (put_user(drive->cyl, (unsigned int *) &loc->cylinders)) return -EFAULT; if (put_user(drive->cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
if (put_user((unsigned)get_start_sect(inode->i_bdev), if (put_user((unsigned)get_start_sect(inode->i_bdev),
(unsigned long *) &loc->start)) return -EFAULT; (unsigned long *) &loc->start)) return -EFAULT;
...@@ -2679,33 +2658,6 @@ static int ide_check_media_change (kdev_t i_rdev) ...@@ -2679,33 +2658,6 @@ static int ide_check_media_change (kdev_t i_rdev)
return 0; return 0;
} }
void ide_fixstring (byte *s, const int bytecount, const int byteswap)
{
byte *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */
if (byteswap) {
/* convert from big-endian to host byte order */
for (p = end ; p != s;) {
unsigned short *pp = (unsigned short *) (p -= 2);
*pp = ntohs(*pp);
}
}
/* strip leading blanks */
while (s != end && *s == ' ')
++s;
/* compress internal blanks and strip trailing blanks */
while (s != end && *s) {
if (*s++ != ' ' || (s != end && *s && *s != ' '))
*p++ = *(s-1);
}
/* wipe out trailing garbage */
while (p != end)
*p++ = '\0';
}
/* /*
* stridx() returns the offset of c within s, * stridx() returns the offset of c within s,
* or -1 if c is '\0' or not found within s. * or -1 if c is '\0' or not found within s.
...@@ -3170,14 +3122,12 @@ int __init ide_setup (char *s) ...@@ -3170,14 +3122,12 @@ int __init ide_setup (char *s)
*/ */
static void __init probe_for_hwifs (void) static void __init probe_for_hwifs (void)
{ {
#ifdef CONFIG_PCI #ifdef CONFIG_BLK_DEV_IDEPCI
if (pci_present()) if (pci_present())
{ {
#ifdef CONFIG_BLK_DEV_IDEPCI
ide_scan_pcibus(ide_scan_direction); ide_scan_pcibus(ide_scan_direction);
#endif /* CONFIG_BLK_DEV_IDEPCI */
} }
#endif /* CONFIG_PCI */ #endif /* CONFIG_BLK_DEV_IDEPCI */
#ifdef CONFIG_ETRAX_IDE #ifdef CONFIG_ETRAX_IDE
{ {
...@@ -3267,22 +3217,13 @@ void __init ide_init_builtin_drivers (void) ...@@ -3267,22 +3217,13 @@ void __init ide_init_builtin_drivers (void)
probe_for_hwifs (); probe_for_hwifs ();
#ifdef CONFIG_BLK_DEV_IDE #ifdef CONFIG_BLK_DEV_IDE
#if defined(__mc68000__) || defined(CONFIG_APUS) if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) { ide_get_lock(&ide_intr_lock, NULL, NULL); /* for atari only */
ide_get_lock(&ide_intr_lock, NULL, NULL);/* for atari only */
disable_irq(ide_hwifs[0].irq); /* disable_irq_nosync ?? */
// disable_irq_nosync(ide_hwifs[0].irq);
}
#endif /* __mc68000__ || CONFIG_APUS */
(void) ideprobe_init(); (void) ideprobe_init();
#if defined(__mc68000__) || defined(CONFIG_APUS) if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) { ide_release_lock(&ide_intr_lock); /* for atari only */
enable_irq(ide_hwifs[0].irq);
ide_release_lock(&ide_lock); /* for atari only */
}
#endif /* __mc68000__ || CONFIG_APUS */
#endif /* CONFIG_BLK_DEV_IDE */ #endif /* CONFIG_BLK_DEV_IDE */
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
...@@ -3317,21 +3258,21 @@ static int default_flushcache (ide_drive_t *drive) ...@@ -3317,21 +3258,21 @@ static int default_flushcache (ide_drive_t *drive)
static ide_startstop_t default_do_request (ide_drive_t *drive, struct request *rq, unsigned long block) static ide_startstop_t default_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
{ {
ide_end_request(drive, 0); ide_end_request(drive, 0, 0);
return ide_stopped; return ide_stopped;
} }
static int default_end_request (ide_drive_t *drive, int uptodate) static int default_end_request (ide_drive_t *drive, int uptodate, int nr_sects)
{ {
return ide_end_request(drive, uptodate); return ide_end_request(drive, uptodate, nr_sects);
} }
static byte default_sense (ide_drive_t *drive, const char *msg, byte stat) static u8 default_sense (ide_drive_t *drive, const char *msg, u8 stat)
{ {
return ide_dump_status(drive, msg, stat); return ide_dump_status(drive, msg, stat);
} }
static ide_startstop_t default_error (ide_drive_t *drive, const char *msg, byte stat) static ide_startstop_t default_error (ide_drive_t *drive, const char *msg, u8 stat)
{ {
return ide_error(drive, msg, stat); return ide_error(drive, msg, stat);
} }
...@@ -3375,9 +3316,10 @@ static ide_startstop_t default_special (ide_drive_t *drive) ...@@ -3375,9 +3316,10 @@ static ide_startstop_t default_special (ide_drive_t *drive)
return ide_stopped; return ide_stopped;
} }
static int default_reinit (ide_drive_t *drive) static int default_attach (ide_drive_t *drive)
{ {
printk(KERN_ERR "%s: does not support hotswap of device class !\n", drive->name); printk(KERN_ERR "%s: does not support hotswap of device class !\n",
drive->name);
return 0; return 0;
} }
...@@ -3402,7 +3344,7 @@ static void setup_driver_defaults (ide_drive_t *drive) ...@@ -3402,7 +3344,7 @@ static void setup_driver_defaults (ide_drive_t *drive)
if (d->pre_reset == NULL) d->pre_reset = default_pre_reset; if (d->pre_reset == NULL) d->pre_reset = default_pre_reset;
if (d->capacity == NULL) d->capacity = default_capacity; if (d->capacity == NULL) d->capacity = default_capacity;
if (d->special == NULL) d->special = default_special; if (d->special == NULL) d->special = default_special;
if (d->reinit == NULL) d->reinit = default_reinit; if (d->attach == NULL) d->attach = default_attach;
} }
int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version) int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version)
...@@ -3422,8 +3364,10 @@ int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int versio ...@@ -3422,8 +3364,10 @@ int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int versio
list_add(&drive->list, &driver->drives); list_add(&drive->list, &driver->drives);
spin_unlock(&drives_lock); spin_unlock(&drives_lock);
if (drive->autotune != 2) { if (drive->autotune != 2) {
if (!driver->supports_dma && HWIF(drive)->dmaproc != NULL) /* DMA timings and setup moved to ide-probe.c */
(void) (HWIF(drive)->dmaproc(ide_dma_off_quietly, drive)); if (!driver->supports_dma && HWIF(drive)->ide_dma_off_quietly)
// HWIF(drive)->ide_dma_off_quietly(drive);
HWIF(drive)->ide_dma_off(drive);
drive->dsc_overlap = (drive->next != drive && driver->supports_dsc_overlap); drive->dsc_overlap = (drive->next != drive && driver->supports_dsc_overlap);
drive->nice1 = 1; drive->nice1 = 1;
} }
...@@ -3435,6 +3379,8 @@ int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int versio ...@@ -3435,6 +3379,8 @@ int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int versio
return 0; return 0;
} }
EXPORT_SYMBOL(ide_register_subdriver);
int ide_unregister_subdriver (ide_drive_t *drive) int ide_unregister_subdriver (ide_drive_t *drive)
{ {
unsigned long flags; unsigned long flags;
...@@ -3460,6 +3406,8 @@ int ide_unregister_subdriver (ide_drive_t *drive) ...@@ -3460,6 +3406,8 @@ int ide_unregister_subdriver (ide_drive_t *drive)
return 0; return 0;
} }
EXPORT_SYMBOL(ide_unregister_subdriver);
int ide_register_driver(ide_driver_t *driver) int ide_register_driver(ide_driver_t *driver)
{ {
struct list_head list; struct list_head list;
...@@ -3481,6 +3429,8 @@ int ide_register_driver(ide_driver_t *driver) ...@@ -3481,6 +3429,8 @@ int ide_register_driver(ide_driver_t *driver)
return 0; return 0;
} }
EXPORT_SYMBOL(ide_register_driver);
void ide_unregister_driver(ide_driver_t *driver) void ide_unregister_driver(ide_driver_t *driver)
{ {
ide_drive_t *drive; ide_drive_t *drive;
...@@ -3505,6 +3455,8 @@ void ide_unregister_driver(ide_driver_t *driver) ...@@ -3505,6 +3455,8 @@ void ide_unregister_driver(ide_driver_t *driver)
} }
} }
EXPORT_SYMBOL(ide_unregister_driver);
struct block_device_operations ide_fops[] = {{ struct block_device_operations ide_fops[] = {{
owner: THIS_MODULE, owner: THIS_MODULE,
open: ide_open, open: ide_open,
...@@ -3514,10 +3466,7 @@ struct block_device_operations ide_fops[] = {{ ...@@ -3514,10 +3466,7 @@ struct block_device_operations ide_fops[] = {{
revalidate: ide_revalidate_disk revalidate: ide_revalidate_disk
}}; }};
EXPORT_SYMBOL(ide_hwifs); EXPORT_SYMBOL(ide_fops);
EXPORT_SYMBOL(ide_register_driver);
EXPORT_SYMBOL(ide_unregister_driver);
EXPORT_SYMBOL(ide_spin_wait_hwgroup);
/* /*
* Probe module * Probe module
...@@ -3526,58 +3475,7 @@ devfs_handle_t ide_devfs_handle; ...@@ -3526,58 +3475,7 @@ devfs_handle_t ide_devfs_handle;
EXPORT_SYMBOL(ide_lock); EXPORT_SYMBOL(ide_lock);
EXPORT_SYMBOL(ide_probe); EXPORT_SYMBOL(ide_probe);
EXPORT_SYMBOL(drive_is_flashcard);
EXPORT_SYMBOL(ide_timer_expiry);
EXPORT_SYMBOL(ide_intr);
EXPORT_SYMBOL(ide_fops);
EXPORT_SYMBOL(ide_get_queue);
EXPORT_SYMBOL(ide_add_generic_settings);
EXPORT_SYMBOL(ide_devfs_handle); EXPORT_SYMBOL(ide_devfs_handle);
EXPORT_SYMBOL(do_ide_request);
/*
* Driver module
*/
EXPORT_SYMBOL(ide_register_subdriver);
EXPORT_SYMBOL(ide_unregister_subdriver);
EXPORT_SYMBOL(ide_replace_subdriver);
EXPORT_SYMBOL(ide_set_handler);
EXPORT_SYMBOL(ide_dump_status);
EXPORT_SYMBOL(ide_error);
EXPORT_SYMBOL(ide_fixstring);
EXPORT_SYMBOL(ide_do_reset);
EXPORT_SYMBOL(restart_request);
EXPORT_SYMBOL(ide_init_drive_cmd);
EXPORT_SYMBOL(ide_do_drive_cmd);
EXPORT_SYMBOL(ide_end_drive_cmd);
EXPORT_SYMBOL(ide_end_request);
EXPORT_SYMBOL(ide_revalidate_drive);
EXPORT_SYMBOL(ide_cmd);
EXPORT_SYMBOL(ide_wait_cmd);
EXPORT_SYMBOL(ide_wait_cmd_task);
EXPORT_SYMBOL(ide_delay_50ms);
EXPORT_SYMBOL(ide_stall_queue);
#ifdef CONFIG_PROC_FS
EXPORT_SYMBOL(ide_add_proc_entries);
EXPORT_SYMBOL(ide_remove_proc_entries);
EXPORT_SYMBOL(proc_ide_read_geometry);
EXPORT_SYMBOL(create_proc_ide_interfaces);
EXPORT_SYMBOL(recreate_proc_ide_device);
EXPORT_SYMBOL(destroy_proc_ide_device);
#endif
EXPORT_SYMBOL(ide_add_setting);
EXPORT_SYMBOL(ide_remove_setting);
EXPORT_SYMBOL(ide_register_hw);
EXPORT_SYMBOL(ide_register);
EXPORT_SYMBOL(ide_unregister);
EXPORT_SYMBOL(ide_setup_ports);
EXPORT_SYMBOL(hwif_unregister);
EXPORT_SYMBOL(get_info_ptr);
EXPORT_SYMBOL(current_capacity);
EXPORT_SYMBOL(system_bus_clock);
EXPORT_SYMBOL(ata_attach);
static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x) static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x)
{ {
...@@ -3594,7 +3492,7 @@ static int ide_notify_reboot (struct notifier_block *this, unsigned long event, ...@@ -3594,7 +3492,7 @@ static int ide_notify_reboot (struct notifier_block *this, unsigned long event,
return NOTIFY_DONE; return NOTIFY_DONE;
} }
printk("flushing ide devices: "); printk(KERN_INFO "flushing ide devices: ");
for (i = 0; i < MAX_HWIFS; i++) { for (i = 0; i < MAX_HWIFS; i++) {
hwif = &ide_hwifs[i]; hwif = &ide_hwifs[i];
...@@ -3633,12 +3531,12 @@ int __init ide_init (void) ...@@ -3633,12 +3531,12 @@ int __init ide_init (void)
static char banner_printed; static char banner_printed;
if (!banner_printed) { if (!banner_printed) {
printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n"); printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
ide_devfs_handle = devfs_mk_dir (NULL, "ide", NULL); ide_devfs_handle = devfs_mk_dir(NULL, "ide", NULL);
system_bus_speed = ide_system_bus_speed(); system_bus_speed = ide_system_bus_speed();
banner_printed = 1; banner_printed = 1;
} }
init_ide_data (); init_ide_data();
initializing = 1; initializing = 1;
ide_init_builtin_drivers(); ide_init_builtin_drivers();
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
/* /*
* linux/include/linux/ide.h * linux/include/linux/ide.h
* *
* Copyright (C) 1994-1998 Linus Torvalds & authors * Copyright (C) 1994-2002 Linus Torvalds & authors
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -14,18 +14,14 @@ ...@@ -14,18 +14,14 @@
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/devfs_fs_kernel.h> #include <linux/devfs_fs_kernel.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/bio.h> #include <linux/bio.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/hdreg.h> #include <asm/hdreg.h>
#include <asm/io.h> #include <asm/io.h>
#ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
# define __IDEDMA_TIMEOUT
#else /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
# undef __IDEDMA_TIMEOUT
#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
/* /*
* This is the multiple IDE interface driver, as evolved from hd.c. * This is the multiple IDE interface driver, as evolved from hd.c.
* It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15). * It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15).
...@@ -42,7 +38,7 @@ ...@@ -42,7 +38,7 @@
* *
* REALLY_SLOW_IO can be defined in ide.c and ide-cd.c, if necessary * REALLY_SLOW_IO can be defined in ide.c and ide-cd.c, if necessary
*/ */
#undef REALLY_FAST_IO /* define if ide ports are perfect */ #define REALLY_FAST_IO /* define if ide ports are perfect */
#define INITIAL_MULT_COUNT 0 /* off=0; on=2,4,8,16,32, etc.. */ #define INITIAL_MULT_COUNT 0 /* off=0; on=2,4,8,16,32, etc.. */
#ifndef SUPPORT_SLOW_DATA_PORTS /* 1 to support slow data ports */ #ifndef SUPPORT_SLOW_DATA_PORTS /* 1 to support slow data ports */
...@@ -170,9 +166,6 @@ typedef unsigned char byte; /* used everywhere */ ...@@ -170,9 +166,6 @@ typedef unsigned char byte; /* used everywhere */
#define IDE_BCOUNTL_REG IDE_LCYL_REG #define IDE_BCOUNTL_REG IDE_LCYL_REG
#define IDE_BCOUNTH_REG IDE_HCYL_REG #define IDE_BCOUNTH_REG IDE_HCYL_REG
#define GET_ERR() IN_BYTE(IDE_ERROR_REG)
#define GET_STAT() IN_BYTE(IDE_STATUS_REG)
#define GET_ALTSTAT() IN_BYTE(IDE_CONTROL_REG)
#define OK_STAT(stat,good,bad) (((stat)&((good)|(bad)))==(good)) #define OK_STAT(stat,good,bad) (((stat)&((good)|(bad)))==(good))
#define BAD_R_STAT (BUSY_STAT | ERR_STAT) #define BAD_R_STAT (BUSY_STAT | ERR_STAT)
#define BAD_W_STAT (BAD_R_STAT | WRERR_STAT) #define BAD_W_STAT (BAD_R_STAT | WRERR_STAT)
...@@ -180,6 +173,43 @@ typedef unsigned char byte; /* used everywhere */ ...@@ -180,6 +173,43 @@ typedef unsigned char byte; /* used everywhere */
#define DRIVE_READY (READY_STAT | SEEK_STAT) #define DRIVE_READY (READY_STAT | SEEK_STAT)
#define DATA_READY (DRQ_STAT) #define DATA_READY (DRQ_STAT)
#define BAD_CRC (ABRT_ERR | ICRC_ERR)
#define SATA_NR_PORTS (3) /* 16 possible ?? */
#define SATA_STATUS_OFFSET (0)
#define SATA_STATUS_REG (HWIF(drive)->sata_scr[SATA_STATUS_OFFSET])
#define SATA_ERROR_OFFSET (1)
#define SATA_ERROR_REG (HWIF(drive)->sata_scr[SATA_ERROR_OFFSET])
#define SATA_CONTROL_OFFSET (2)
#define SATA_CONTROL_REG (HWIF(drive)->sata_scr[SATA_CONTROL_OFFSET])
#define SATA_MISC_OFFSET (0)
#define SATA_MISC_REG (HWIF(drive)->sata_misc[SATA_MISC_OFFSET])
#define SATA_PHY_OFFSET (1)
#define SATA_PHY_REG (HWIF(drive)->sata_misc[SATA_PHY_OFFSET])
#define SATA_IEN_OFFSET (2)
#define SATA_IEN_REG (HWIF(drive)->sata_misc[SATA_IEN_OFFSET])
/*
* Our Physical Region Descriptor (PRD) table should be large enough
* to handle the biggest I/O request we are likely to see. Since requests
* can have no more than 256 sectors, and since the typical blocksize is
* two or more sectors, we could get by with a limit of 128 entries here for
* the usual worst case. Most requests seem to include some contiguous blocks,
* further reducing the number of table entries required.
*
* The driver reverts to PIO mode for individual requests that exceed
* this limit (possible with 512 byte blocksizes, eg. MSDOS f/s), so handling
* 100% of all crazy scenarios here is not necessary.
*
* As it turns out though, we must allocate a full 4KB page for this,
* so the two PRD tables (ide0 & ide1) will each get half of that,
* allowing each to have about 256 entries (8 bytes each) from this.
*/
#define PRD_BYTES 8
#define PRD_ENTRIES (PAGE_SIZE / (2 * PRD_BYTES))
/* /*
* sector count bits * sector count bits
*/ */
...@@ -215,21 +245,12 @@ typedef unsigned char byte; /* used everywhere */ ...@@ -215,21 +245,12 @@ typedef unsigned char byte; /* used everywhere */
#define PARTN_BITS 6 /* number of minor dev bits for partitions */ #define PARTN_BITS 6 /* number of minor dev bits for partitions */
#define PARTN_MASK ((1<<PARTN_BITS)-1) /* a useful bit mask */ #define PARTN_MASK ((1<<PARTN_BITS)-1) /* a useful bit mask */
#define MAX_DRIVES 2 /* per interface; 2 assumed by lots of code */ #define MAX_DRIVES 2 /* per interface; 2 assumed by lots of code */
#define CASCADE_DRIVES 8 /* per interface; 8|2 assumed by lots of code */
#define SECTOR_SIZE 512 #define SECTOR_SIZE 512
#define SECTOR_WORDS (SECTOR_SIZE / 4) /* number of 32bit words per sector */ #define SECTOR_WORDS (SECTOR_SIZE / 4) /* number of 32bit words per sector */
#define IDE_LARGE_SEEK(b1,b2,t) (((b1) > (b2) + (t)) || ((b2) > (b1) + (t))) #define IDE_LARGE_SEEK(b1,b2,t) (((b1) > (b2) + (t)) || ((b2) > (b1) + (t)))
#define IDE_MIN(a,b) ((a)<(b) ? (a):(b)) #define IDE_MIN(a,b) ((a)<(b) ? (a):(b))
#define IDE_MAX(a,b) ((a)>(b) ? (a):(b)) #define IDE_MAX(a,b) ((a)>(b) ? (a):(b))
#ifndef SPLIT_WORD
# define SPLIT_WORD(W,HB,LB) ((HB)=(W>>8), (LB)=(W-((W>>8)<<8)))
#endif
#ifndef MAKE_WORD
# define MAKE_WORD(W,HB,LB) ((W)=((HB<<8)+LB))
#endif
/* /*
* Timeouts for various operations: * Timeouts for various operations:
*/ */
...@@ -244,39 +265,6 @@ typedef unsigned char byte; /* used everywhere */ ...@@ -244,39 +265,6 @@ typedef unsigned char byte; /* used everywhere */
#define WAIT_CMD (10*HZ) /* 10sec - maximum wait for an IRQ to happen */ #define WAIT_CMD (10*HZ) /* 10sec - maximum wait for an IRQ to happen */
#define WAIT_MIN_SLEEP (2*HZ/100) /* 20msec - minimum sleep time */ #define WAIT_MIN_SLEEP (2*HZ/100) /* 20msec - minimum sleep time */
#define SELECT_DRIVE(hwif,drive) \
{ \
if (hwif->selectproc) \
hwif->selectproc(drive); \
OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); \
}
#define SELECT_INTERRUPT(hwif,drive) \
{ \
if (hwif->intrproc) \
hwif->intrproc(drive); \
else \
OUT_BYTE((drive)->ctl|2, hwif->io_ports[IDE_CONTROL_OFFSET]); \
}
#define SELECT_MASK(hwif,drive,mask) \
{ \
if (hwif->maskproc) \
hwif->maskproc(drive,mask); \
}
#define SELECT_READ_WRITE(hwif,drive,func) \
{ \
if (hwif->rwproc) \
hwif->rwproc(drive,func); \
}
#define QUIRK_LIST(hwif,drive) \
{ \
if (hwif->quirkproc) \
(drive)->quirk_list = hwif->quirkproc(drive); \
}
#define HOST(hwif,chipset) \ #define HOST(hwif,chipset) \
{ \ { \
return ((hwif)->chipset == chipset) ? 1 : 0; \ return ((hwif)->chipset == chipset) ? 1 : 0; \
...@@ -304,9 +292,34 @@ typedef enum { ide_unknown, ide_generic, ide_pci, ...@@ -304,9 +292,34 @@ typedef enum { ide_unknown, ide_generic, ide_pci,
ide_qd65xx, ide_umc8672, ide_ht6560b, ide_qd65xx, ide_umc8672, ide_ht6560b,
ide_pdc4030, ide_rz1000, ide_trm290, ide_pdc4030, ide_rz1000, ide_trm290,
ide_cmd646, ide_cy82c693, ide_4drives, ide_cmd646, ide_cy82c693, ide_4drives,
ide_pmac, ide_etrax100 ide_pmac, ide_etrax100, ide_acorn
} hwif_chipset_t; } hwif_chipset_t;
typedef struct ide_io_ops_s {
/* insert io operations here! */
void (*OUTB)(u8 addr, u32 port);
void (*OUTW)(u16 addr, u32 port);
void (*OUTL)(u32 addr, u32 port);
void (*OUTBP)(u8 addr, u32 port);
void (*OUTWP)(u16 addr, u32 port);
void (*OUTLP)(u32 addr, u32 port);
void (*OUTSW)(u32 port, void *addr, u32 count);
void (*OUTSWP)(u32 port, void *addr, u32 count);
void (*OUTSL)(u32 port, void *addr, u32 count);
void (*OUTSLP)(u32 port, void *addr, u32 count);
u8 (*INB)(u32 port);
u16 (*INW)(u32 port);
u32 (*INL)(u32 port);
u8 (*INBP)(u32 port);
u16 (*INWP)(u32 port);
u32 (*INLP)(u32 port);
void (*INSW)(u32 port, void *addr, u32 count);
void (*INSWP)(u32 port, void *addr, u32 count);
void (*INSL)(u32 port, void *addr, u32 count);
void (*INSLP)(u32 port, void *addr, u32 count);
} ide_io_ops_t;
/* /*
* Structure to hold all information about the location of this port * Structure to hold all information about the location of this port
*/ */
...@@ -317,6 +330,11 @@ typedef struct hw_regs_s { ...@@ -317,6 +330,11 @@ typedef struct hw_regs_s {
ide_ack_intr_t *ack_intr; /* acknowledge interrupt */ ide_ack_intr_t *ack_intr; /* acknowledge interrupt */
void *priv; /* interface specific data */ void *priv; /* interface specific data */
hwif_chipset_t chipset; hwif_chipset_t chipset;
#if 0
ide_io_ops_t *iops; /* */
#endif
sata_ioreg_t sata_scr[SATA_NR_PORTS];
sata_ioreg_t sata_misc[SATA_NR_PORTS];
} hw_regs_t; } hw_regs_t;
/* /*
...@@ -333,10 +351,27 @@ void ide_setup_ports( hw_regs_t *hw, ...@@ -333,10 +351,27 @@ void ide_setup_ports( hw_regs_t *hw,
ide_ioreg_t ctrl, ide_ioreg_t ctrl,
ide_ioreg_t intr, ide_ioreg_t intr,
ide_ack_intr_t *ack_intr, ide_ack_intr_t *ack_intr,
#if 0
ide_io_ops_t *iops,
#endif
int irq); int irq);
#include <asm/ide.h> #include <asm/ide.h>
/* Currently only m68k, apus and m8xx need it */
#ifdef IDE_ARCH_ACK_INTR
extern int ide_irq_lock;
# define ide_ack_intr(hwif) (hwif->hw.ack_intr ? hwif->hw.ack_intr(hwif) : 1)
#else
# define ide_ack_intr(hwif) (1)
#endif
/* Currently only Atari needs it */
#ifndef IDE_ARCH_LOCK
# define ide_release_lock(lock) do {} while (0)
# define ide_get_lock(lock, hdlr, data) do {} while (0)
#endif /* IDE_ARCH_LOCK */
/* /*
* If the arch-dependant ide.h did not declare/define any OUT_BYTE * If the arch-dependant ide.h did not declare/define any OUT_BYTE
* or IN_BYTE functions, we make some defaults here. * or IN_BYTE functions, we make some defaults here.
...@@ -346,20 +381,30 @@ void ide_setup_ports( hw_regs_t *hw, ...@@ -346,20 +381,30 @@ void ide_setup_ports( hw_regs_t *hw,
# ifdef REALLY_FAST_IO # ifdef REALLY_FAST_IO
# define OUT_BYTE(b,p) outb((b),(p)) # define OUT_BYTE(b,p) outb((b),(p))
# define OUT_WORD(w,p) outw((w),(p)) # define OUT_WORD(w,p) outw((w),(p))
# define OUT_LONG(l,p) outl((l),(p))
# else # else
# define OUT_BYTE(b,p) outb_p((b),(p)) # define OUT_BYTE(b,p) outb_p((b),(p))
# define OUT_WORD(w,p) outw_p((w),(p)) # define OUT_WORD(w,p) outw_p((w),(p))
# define OUT_LONG(l,p) outl_p((l),(p))
# endif # endif
# define OUT_BYTE_P(b,p) outb_p((b),(p))
# define OUT_WORD_P(w,p) outw_p((w),(p))
# define OUT_LONG_P(l,p) outl_p((l),(p))
#endif #endif
#ifndef HAVE_ARCH_IN_BYTE #ifndef HAVE_ARCH_IN_BYTE
# ifdef REALLY_FAST_IO # ifdef REALLY_FAST_IO
# define IN_BYTE(p) (byte)inb(p) # define IN_BYTE(p) (u8) inb(p)
# define IN_WORD(p) (short)inw(p) # define IN_WORD(p) (u16) inw(p)
# define IN_LONG(p) (u32) inl(p)
# else # else
# define IN_BYTE(p) (byte)inb_p(p) # define IN_BYTE(p) (u8) inb_p(p)
# define IN_WORD(p) (short)inw_p(p) # define IN_WORD(p) (u16) inw_p(p)
# define IN_LONG(p) (u32) inl_p(p)
# endif # endif
# define IN_BYTE_P(p) (u8) inb_p(p)
# define IN_WORD_P(p) (u16) inw_p(p)
# define IN_LONG_P(p) (u32) inl_p(p)
#endif #endif
/* /*
...@@ -373,106 +418,373 @@ void ide_setup_ports( hw_regs_t *hw, ...@@ -373,106 +418,373 @@ void ide_setup_ports( hw_regs_t *hw,
#define ide_tape 0x1 #define ide_tape 0x1
#define ide_floppy 0x0 #define ide_floppy 0x0
/*
* Special Driver Flags
*
* set_geometry : respecify drive geometry
* recalibrate : seek to cyl 0
* set_multmode : set multmode count
* set_tune : tune interface for drive
* serviced : service command
* reserved : unused
*/
typedef union { typedef union {
unsigned all : 8; /* all of the bits together */ unsigned all : 8;
struct { struct {
#if defined(__LITTLE_ENDIAN_BITFIELD) #if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned set_geometry : 1; /* respecify drive geometry */ unsigned set_geometry : 1;
unsigned recalibrate : 1; /* seek to cyl 0 */ unsigned recalibrate : 1;
unsigned set_multmode : 1; /* set multmode count */ unsigned set_multmode : 1;
unsigned set_tune : 1; /* tune interface for drive */ unsigned set_tune : 1;
unsigned serviced : 1; /* service command */ unsigned serviced : 1;
unsigned reserved : 3; /* unused */ unsigned reserved : 3;
#elif defined(__BIG_ENDIAN_BITFIELD) #elif defined(__BIG_ENDIAN_BITFIELD)
unsigned reserved : 3; /* unused */ unsigned reserved : 3;
unsigned serviced : 1; /* service command */ unsigned serviced : 1;
unsigned set_tune : 1; /* tune interface for drive */ unsigned set_tune : 1;
unsigned set_multmode : 1; /* set multmode count */ unsigned set_multmode : 1;
unsigned recalibrate : 1; /* seek to cyl 0 */ unsigned recalibrate : 1;
unsigned set_geometry : 1; /* respecify drive geometry */ unsigned set_geometry : 1;
#else #else
#error "Please fix <asm/byteorder.h>" #error "Please fix <asm/byteorder.h>"
#endif #endif
} b; } b;
} special_t; } special_t;
/*
* ATA DATA Register Special.
* ATA NSECTOR Count Register().
* ATAPI Byte Count Register.
* Channel index ordering pairs.
*/
typedef union {
unsigned all :16;
struct {
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned low :8; /* LSB */
unsigned high :8; /* MSB */
#elif defined(__BIG_ENDIAN_BITFIELD)
unsigned high :8; /* MSB */
unsigned low :8; /* LSB */
#else
#error "Please fix <asm/byteorder.h>"
#endif
} b;
} ata_nsector_t, ata_data_t, atapi_bcount_t, ata_index_t;
/*
* ATA-IDE Error Register
*
* mark : Bad address mark
* tzero : Couldn't find track 0
* abrt : Aborted Command
* mcr : Media Change Request
* id : ID field not found
* mce : Media Change Event
* ecc : Uncorrectable ECC error
* bdd : dual meaing
*/
typedef union {
unsigned all :8;
struct {
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned mark :1;
unsigned tzero :1;
unsigned abrt :1;
unsigned mcr :1;
unsigned id :1;
unsigned mce :1;
unsigned ecc :1;
unsigned bdd :1;
#elif defined(__BIG_ENDIAN_BITFIELD)
unsigned bdd :1;
unsigned ecc :1;
unsigned mce :1;
unsigned id :1;
unsigned mcr :1;
unsigned abrt :1;
unsigned tzero :1;
unsigned mark :1;
#else
#error "Please fix <asm/byteorder.h>"
#endif
} b;
} ata_error_t;
/*
* ATA-IDE Select Register, aka Device-Head
*
* head : always zeros here
* unit : drive select number: 0/1
* bit5 : always 1
* lba : using LBA instead of CHS
* bit7 : always 1
*/
typedef union {
unsigned all : 8;
struct {
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned head : 4;
unsigned unit : 1;
unsigned bit5 : 1;
unsigned lba : 1;
unsigned bit7 : 1;
#elif defined(__BIG_ENDIAN_BITFIELD)
unsigned bit7 : 1;
unsigned lba : 1;
unsigned bit5 : 1;
unsigned unit : 1;
unsigned head : 4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
} b;
} select_t, ata_select_t;
/*
* The ATA-IDE Status Register.
* The ATAPI Status Register.
*
* check : Error occurred
* idx : Index Error
* corr : Correctable error occurred
* drq : Data is request by the device
* dsc : Disk Seek Complete : ata
* : Media access command finished : atapi
* df : Device Fault : ata
* : Reserved : atapi
* drdy : Ready, Command Mode Capable : ata
* : Ignored for ATAPI commands : atapi
* bsy : Disk is Busy
* : The device has access to the command block
*/
typedef union { typedef union {
unsigned all : 8; /* all of the bits together */ unsigned all :8;
struct { struct {
#if defined(__LITTLE_ENDIAN_BITFIELD) #if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned head : 4; /* always zeros here */ unsigned check :1;
unsigned unit : 1; /* drive select number: 0/1 */ unsigned idx :1;
unsigned bit5 : 1; /* always 1 */ unsigned corr :1;
unsigned lba : 1; /* using LBA instead of CHS */ unsigned drq :1;
unsigned bit7 : 1; /* always 1 */ unsigned dsc :1;
unsigned df :1;
unsigned drdy :1;
unsigned bsy :1;
#elif defined(__BIG_ENDIAN_BITFIELD) #elif defined(__BIG_ENDIAN_BITFIELD)
unsigned bit7 : 1; /* always 1 */ unsigned bsy :1;
unsigned lba : 1; /* using LBA instead of CHS */ unsigned drdy :1;
unsigned bit5 : 1; /* always 1 */ unsigned df :1;
unsigned unit : 1; /* drive select number: 0/1 */ unsigned dsc :1;
unsigned head : 4; /* always zeros here */ unsigned drq :1;
unsigned corr :1;
unsigned idx :1;
unsigned check :1;
#else #else
#error "Please fix <asm/byteorder.h>" #error "Please fix <asm/byteorder.h>"
#endif #endif
} b; } b;
} select_t; } ata_status_t, atapi_status_t;
/*
* ATA-IDE Control Register
*
* bit0 : Should be set to zero
* nIEN : device INTRQ to host
* SRST : host soft reset bit
* bit3 : ATA-2 thingy, Should be set to 1
* reserved456 : Reserved
* HOB : 48-bit address ordering, High Ordered Bit
*/
typedef union { typedef union {
unsigned all : 8; /* all of the bits together */ unsigned all : 8;
struct { struct {
#if defined(__LITTLE_ENDIAN_BITFIELD) #if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned bit0 : 1; unsigned bit0 : 1;
unsigned nIEN : 1; /* device INTRQ to host */ unsigned nIEN : 1;
unsigned SRST : 1; /* host soft reset bit */ unsigned SRST : 1;
unsigned bit3 : 1; /* ATA-2 thingy */ unsigned bit3 : 1;
unsigned reserved456 : 3; unsigned reserved456 : 3;
unsigned HOB : 1; /* 48-bit address ordering */ unsigned HOB : 1;
#elif defined(__BIG_ENDIAN_BITFIELD) #elif defined(__BIG_ENDIAN_BITFIELD)
unsigned HOB : 1; /* 48-bit address ordering */ unsigned HOB : 1;
unsigned reserved456 : 3; unsigned reserved456 : 3;
unsigned bit3 : 1; /* ATA-2 thingy */ unsigned bit3 : 1;
unsigned SRST : 1; /* host soft reset bit */ unsigned SRST : 1;
unsigned nIEN : 1; /* device INTRQ to host */ unsigned nIEN : 1;
unsigned bit0 : 1; unsigned bit0 : 1;
#else #else
#error "Please fix <asm/byteorder.h>" #error "Please fix <asm/byteorder.h>"
#endif #endif
} b; } b;
} control_t; } ata_control_t;
/*
* ATAPI Feature Register
*
* dma : Using DMA or PIO
* reserved321 : Reserved
* reserved654 : Reserved (Tag Type)
* reserved7 : Reserved
*/
typedef union {
unsigned all :8;
struct {
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned dma :1;
unsigned reserved321 :3;
unsigned reserved654 :3;
unsigned reserved7 :1;
#elif defined(__BIG_ENDIAN_BITFIELD)
unsigned reserved7 :1;
unsigned reserved654 :3;
unsigned reserved321 :3;
unsigned dma :1;
#else
#error "Please fix <asm/byteorder.h>"
#endif
} b;
} atapi_feature_t;
/*
* ATAPI Interrupt Reason Register.
*
* cod : Information transferred is command (1) or data (0)
* io : The device requests us to read (1) or write (0)
* reserved : Reserved
*/
typedef union {
unsigned all :8;
struct {
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned cod :1;
unsigned io :1;
unsigned reserved :6;
#elif defined(__BIG_ENDIAN_BITFIELD)
unsigned reserved :6;
unsigned io :1;
unsigned cod :1;
#else
#error "Please fix <asm/byteorder.h>"
#endif
} b;
} atapi_ireason_t;
/*
* The ATAPI error register.
*
* ili : Illegal Length Indication
* eom : End Of Media Detected
* abrt : Aborted command - As defined by ATA
* mcr : Media Change Requested - As defined by ATA
* sense_key : Sense key of the last failed packet command
*/
typedef union {
unsigned all :8;
struct {
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned ili :1;
unsigned eom :1;
unsigned abrt :1;
unsigned mcr :1;
unsigned sense_key :4;
#elif defined(__BIG_ENDIAN_BITFIELD)
unsigned sense_key :4;
unsigned mcr :1;
unsigned abrt :1;
unsigned eom :1;
unsigned ili :1;
#else
#error "Please fix <asm/byteorder.h>"
#endif
} b;
} atapi_error_t;
/*
* ATAPI floppy Drive Select Register
*
* sam_lun : Logical unit number
* reserved3 : Reserved
* drv : The responding drive will be drive 0 (0) or drive 1 (1)
* one5 : Should be set to 1
* reserved6 : Reserved
* one7 : Should be set to 1
*/
typedef union {
unsigned all :8;
struct {
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned sam_lun :3;
unsigned reserved3 :1;
unsigned drv :1;
unsigned one5 :1;
unsigned reserved6 :1;
unsigned one7 :1;
#elif defined(__BIG_ENDIAN_BITFIELD)
unsigned one7 :1;
unsigned reserved6 :1;
unsigned one5 :1;
unsigned drv :1;
unsigned reserved3 :1;
unsigned sam_lun :3;
#else
#error "Please fix <asm/byteorder.h>"
#endif
} b;
} atapi_select_t;
struct ide_driver_s; struct ide_driver_s;
struct ide_settings_s; struct ide_settings_s;
typedef struct ide_drive_s { typedef struct ide_drive_s {
char name[4]; /* drive name, such as "hda" */
char driver_req[10]; /* requests specific driver */
request_queue_t queue; /* request queue */ request_queue_t queue; /* request queue */
struct request *rq; /* current request */
struct ide_drive_s *next; /* circular list of hwgroup drives */ struct ide_drive_s *next; /* circular list of hwgroup drives */
struct ide_driver_s *driver;/* (ide_driver_t *) */
void *driver_data; /* extra driver data */
struct hd_driveid *id; /* drive model identification info */
struct proc_dir_entry *proc; /* /proc/ide/ directory entry */
struct ide_settings_s *settings;/* /proc/ide/ drive settings */
devfs_handle_t de; /* directory for device */
struct hwif_s *hwif; /* actually (ide_hwif_t *) */
unsigned long sleep; /* sleep until this time */ unsigned long sleep; /* sleep until this time */
unsigned long service_start; /* time we started last request */ unsigned long service_start; /* time we started last request */
unsigned long service_time; /* service time of last request */ unsigned long service_time; /* service time of last request */
unsigned long timeout; /* max time to wait for irq */ unsigned long timeout; /* max time to wait for irq */
special_t special; /* special action flags */ special_t special; /* special action flags */
byte keep_settings; /* restore settings after drive reset */ select_t select; /* basic drive/head select reg value */
byte using_dma; /* disk is using dma for read/write */
byte retry_pio; /* retrying dma capable host in pio */ u8 keep_settings; /* restore settings after drive reset */
byte state; /* retry state */ u8 autodma; /* device can safely use dma on host */
byte waiting_for_dma; /* dma currently in progress */ u8 using_dma; /* disk is using dma for read/write */
byte unmask; /* flag: okay to unmask other irqs */ u8 using_tcq; /* disk is using queueing */
byte slow; /* flag: slow data port */ u8 retry_pio; /* retrying dma capable host in pio */
byte bswap; /* flag: byte swap data */ u8 state; /* retry state */
byte dsc_overlap; /* flag: DSC overlap */ u8 waiting_for_dma; /* dma currently in progress */
byte nice1; /* flag: give potential excess bandwidth */ u8 unmask; /* okay to unmask other irqs */
u8 slow; /* slow data port */
u8 bswap; /* byte swap data */
u8 dsc_overlap; /* DSC overlap */
u8 nice1; /* give potential excess bandwidth */
unsigned present : 1; /* drive is physically present */ unsigned present : 1; /* drive is physically present */
unsigned noprobe : 1; /* from: hdx=noprobe */ unsigned noprobe : 1; /* from: hdx=noprobe */
unsigned removable : 1; /* 1 if need to do check_media_change */ unsigned removable : 1; /* 1 if need to do check_media_change */
unsigned is_flash : 1; /* 1 if probed as flash */
unsigned forced_geom : 1; /* 1 if hdx=c,h,s was given at boot */ unsigned forced_geom : 1; /* 1 if hdx=c,h,s was given at boot */
unsigned no_unmask : 1; /* disallow setting unmask bit */ unsigned no_unmask : 1; /* disallow setting unmask bit */
unsigned no_io_32bit : 1; /* disallow enabling 32bit I/O */ unsigned no_io_32bit : 1; /* disallow enabling 32bit I/O */
unsigned nobios : 1; /* flag: do not probe bios for drive */ unsigned nobios : 1; /* do not probe bios for drive */
unsigned atapi_overlap : 1; /* flag: ATAPI overlap (not supported) */ unsigned atapi_overlap : 1; /* ATAPI overlap (not supported) */
unsigned nice0 : 1; /* flag: give obvious excess bandwidth */ unsigned nice0 : 1; /* give obvious excess bandwidth */
unsigned nice2 : 1; /* flag: give a share in our own bandwidth */ unsigned nice2 : 1; /* give a share in our own bandwidth */
unsigned doorlocking : 1; /* flag: for removable only: door lock/unlock works */ unsigned doorlocking : 1; /* for removable only: door lock/unlock works */
unsigned autotune : 2; /* 1=autotune, 2=noautotune, 0=default */ unsigned autotune : 2; /* 1=autotune, 2=noautotune, 0=default */
unsigned remap_0_to_1 : 2; /* 0=remap if ezdrive, 1=remap, 2=noremap */ unsigned remap_0_to_1 : 2; /* 0=remap if ezdrive, 1=remap, 2=noremap */
unsigned ata_flash : 1; /* 1=present, 0=default */ unsigned ata_flash : 1; /* 1=present, 0=default */
...@@ -482,92 +794,77 @@ typedef struct ide_drive_s { ...@@ -482,92 +794,77 @@ typedef struct ide_drive_s {
* 2=48-bit doing 28-bit * 2=48-bit doing 28-bit
* 3=64-bit * 3=64-bit
*/ */
byte scsi; /* 0=default, 1=skip current ide-subdriver for ide-scsi emulation */
byte media; /* disk, cdrom, tape, floppy, ... */ u8 scsi; /* 0=default, 1=skip current ide-subdriver for ide-scsi emulation */
select_t select; /* basic drive/head select reg value */ u8 quirk_list; /* considered quirky, set for a specific host */
byte ctl; /* "normal" value for IDE_CONTROL_REG */ u8 suspend_reset; /* drive suspend mode flag, soft-reset recovers */
byte ready_stat; /* min status value for drive ready */ u8 init_speed; /* transfer rate set at boot */
byte mult_count; /* current multiple sector setting */ u8 current_speed; /* current transfer rate set */
byte mult_req; /* requested multiple sector setting */ u8 dn; /* now wide spread use */
byte tune_req; /* requested drive tuning setting */ u8 wcache; /* status of write cache */
byte io_32bit; /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */ u8 acoustic; /* acoustic management */
byte bad_wstat; /* used for ignoring WRERR_STAT */ u8 media; /* disk, cdrom, tape, floppy, ... */
byte nowerr; /* used for ignoring WRERR_STAT */ u8 ctl; /* "normal" value for IDE_CONTROL_REG */
byte sect0; /* offset of first sector for DM6:DDO */ u8 ready_stat; /* min status value for drive ready */
unsigned int usage; /* current "open()" count for drive */ u8 mult_count; /* current multiple sector setting */
byte head; /* "real" number of heads */ u8 mult_req; /* requested multiple sector setting */
byte sect; /* "real" sectors per track */ u8 tune_req; /* requested drive tuning setting */
byte bios_head; /* BIOS/fdisk/LILO number of heads */ u8 io_32bit; /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
byte bios_sect; /* BIOS/fdisk/LILO sectors per track */ u8 bad_wstat; /* used for ignoring WRERR_STAT */
u8 nowerr; /* used for ignoring WRERR_STAT */
u8 sect0; /* offset of first sector for DM6:DDO */
u8 head; /* "real" number of heads */
u8 sect; /* "real" sectors per track */
u8 bios_head; /* BIOS/fdisk/LILO number of heads */
u8 bios_sect; /* BIOS/fdisk/LILO sectors per track */
unsigned int bios_cyl; /* BIOS/fdisk/LILO number of cyls */ unsigned int bios_cyl; /* BIOS/fdisk/LILO number of cyls */
unsigned int cyl; /* "real" number of cyls */ unsigned int cyl; /* "real" number of cyls */
unsigned long capacity; /* total number of sectors */ unsigned int drive_data; /* use by tuneproc/selectproc */
unsigned long long capacity48; /* total number of sectors */ unsigned int usage; /* current "open()" count for drive */
unsigned int drive_data; /* for use by tuneproc/selectproc as needed */ unsigned int failures; /* current failure count */
struct hwif_s *hwif; /* actually (ide_hwif_t *) */ unsigned int max_failures; /* maximum allowed failure count */
struct hd_driveid *id; /* drive model identification info */
char name[4]; /* drive name, such as "hda" */ u32 capacity; /* total number of sectors */
struct ide_driver_s *driver; /* (ide_driver_t *) */ u64 capacity48; /* total number of sectors */
void *driver_data; /* extra driver data */
devfs_handle_t de; /* directory for device */
struct proc_dir_entry *proc; /* /proc/ide/ directory entry */
struct ide_settings_s *settings; /* /proc/ide/ drive settings */
char driver_req[10]; /* requests specific driver */
int last_lun; /* last logical unit */ int last_lun; /* last logical unit */
int forced_lun; /* if hdxlun was given at boot */ int forced_lun; /* if hdxlun was given at boot */
int lun; /* logical unit */ int lun; /* logical unit */
int crc_count; /* crc counter to reduce drive speed */ int crc_count; /* crc counter to reduce drive speed */
byte quirk_list; /* drive is considered quirky if set for a specific host */
byte suspend_reset; /* drive suspend mode flag, soft-reset recovers */
byte init_speed; /* transfer rate set at boot */
byte current_speed; /* current transfer rate set */
byte dn; /* now wide spread use */
byte wcache; /* status of write cache */
byte acoustic; /* acoustic management */
unsigned int failures; /* current failure count */
unsigned int max_failures; /* maximum allowed failure count */
struct list_head list; struct list_head list;
struct gendisk *disk; struct gendisk *disk;
} ide_drive_t; } ide_drive_t;
/* typedef struct ide_pio_ops_s {
* An ide_dmaproc_t() initiates/aborts DMA read/write operations on a drive. void (*ata_input_data)(ide_drive_t *, void *, u32);
* void (*ata_output_data)(ide_drive_t *, void *, u32);
* The caller is assumed to have selected the drive and programmed the drive's
* sector address using CHS or LBA. All that remains is to prepare for DMA void (*atapi_input_bytes)(ide_drive_t *, void *, u32);
* and then issue the actual read/write DMA/PIO command to the drive. void (*atapi_output_bytes)(ide_drive_t *, void *, u32);
* } ide_pio_ops_t;
* Returns 0 if all went well.
* Returns 1 if DMA read/write could not be started, in which case the caller typedef struct ide_dma_ops_s {
* should either try again later, or revert to PIO for the current request. /* insert dma operations here! */
*/ int (*ide_dma_read)(ide_drive_t *drive);
typedef enum { ide_dma_read, ide_dma_write, ide_dma_begin, int (*ide_dma_write)(ide_drive_t *drive);
ide_dma_end, ide_dma_check, ide_dma_on, int (*ide_dma_begin)(ide_drive_t *drive);
ide_dma_off, ide_dma_off_quietly, ide_dma_test_irq, int (*ide_dma_end)(ide_drive_t *drive);
ide_dma_host_on, ide_dma_host_off, int (*ide_dma_check)(ide_drive_t *drive);
ide_dma_bad_drive, ide_dma_good_drive, int (*ide_dma_on)(ide_drive_t *drive);
ide_dma_verbose, ide_dma_retune, int (*ide_dma_off)(ide_drive_t *drive);
ide_dma_lostirq, ide_dma_timeout int (*ide_dma_off_quietly)(ide_drive_t *drive);
} ide_dma_action_t; int (*ide_dma_test_irq)(ide_drive_t *drive);
int (*ide_dma_host_on)(ide_drive_t *drive);
typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *); int (*ide_dma_host_off)(ide_drive_t *drive);
int (*ide_dma_bad_drive)(ide_drive_t *drive);
/* int (*ide_dma_good_drive)(ide_drive_t *drive);
* An ide_ideproc_t() performs CPU-polled transfers to/from a drive. int (*ide_dma_count)(ide_drive_t *drive);
* Arguments are: the drive, the buffer pointer, and the length (in bytes or int (*ide_dma_verbose)(ide_drive_t *drive);
* words depending on if it's an IDE or ATAPI call). int (*ide_dma_retune)(ide_drive_t *drive);
* int (*ide_dma_lostirq)(ide_drive_t *drive);
* If it is not defined for a controller, standard-code is used from ide.c. int (*ide_dma_timeout)(ide_drive_t *drive);
* } ide_dma_ops_t;
* Controllers which are not memory-mapped in the standard way need to
* override that mechanism using this function to work.
*
*/
typedef enum { ideproc_ide_input_data, ideproc_ide_output_data,
ideproc_atapi_input_bytes, ideproc_atapi_output_bytes
} ide_ide_action_t;
typedef void (ide_ideproc_t)(ide_ide_action_t, ide_drive_t *, void *, unsigned int);
/* /*
* mapping stuff, prepare for highmem... * mapping stuff, prepare for highmem...
...@@ -602,166 +899,182 @@ extern inline void ide_unmap_buffer(char *buffer, unsigned long *flags) ...@@ -602,166 +899,182 @@ extern inline void ide_unmap_buffer(char *buffer, unsigned long *flags)
bio_kunmap_irq(buffer, flags); bio_kunmap_irq(buffer, flags);
} }
/*
* A Verbose noise maker for debugging on the attempted transfer rates.
*/
extern inline char *ide_xfer_verbose (byte 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");
}
}
/*
* A Verbose noise maker for debugging on the attempted dmaing calls.
*/
extern inline char *ide_dmafunc_verbose (ide_dma_action_t dmafunc)
{
switch (dmafunc) {
case ide_dma_read: return("ide_dma_read");
case ide_dma_write: return("ide_dma_write");
case ide_dma_begin: return("ide_dma_begin");
case ide_dma_end: return("ide_dma_end:");
case ide_dma_check: return("ide_dma_check");
case ide_dma_on: return("ide_dma_on");
case ide_dma_off: return("ide_dma_off");
case ide_dma_off_quietly: return("ide_dma_off_quietly");
case ide_dma_test_irq: return("ide_dma_test_irq");
case ide_dma_host_on: return("ide_dma_host_on");
case ide_dma_host_off: return("ide_dma_host_off");
case ide_dma_bad_drive: return("ide_dma_bad_drive");
case ide_dma_good_drive: return("ide_dma_good_drive");
case ide_dma_verbose: return("ide_dma_verbose");
case ide_dma_retune: return("ide_dma_retune");
case ide_dma_lostirq: return("ide_dma_lostirq");
case ide_dma_timeout: return("ide_dma_timeout");
default: return("unknown");
}
}
/*
* An ide_tuneproc_t() is used to set the speed of an IDE interface
* to a particular PIO mode. The "byte" parameter is used
* to select the PIO mode by number (0,1,2,3,4,5), and a value of 255
* indicates that the interface driver should "auto-tune" the PIO mode
* according to the drive capabilities in drive->id;
*
* Not all interface types support tuning, and not all of those
* support all possible PIO settings. They may silently ignore
* or round values as they see fit.
*/
typedef void (ide_tuneproc_t) (ide_drive_t *, byte);
typedef int (ide_speedproc_t) (ide_drive_t *, byte);
/*
* This is used to provide support for strange interfaces
*/
typedef void (ide_selectproc_t) (ide_drive_t *);
typedef void (ide_resetproc_t) (ide_drive_t *);
typedef int (ide_quirkproc_t) (ide_drive_t *);
typedef void (ide_intrproc_t) (ide_drive_t *);
typedef void (ide_maskproc_t) (ide_drive_t *, int);
typedef void (ide_rw_proc_t) (ide_drive_t *, ide_dma_action_t);
/*
* ide soft-power support
*/
typedef int (ide_busproc_t) (ide_drive_t *, int);
#define IDE_CHIPSET_PCI_MASK \ #define IDE_CHIPSET_PCI_MASK \
((1<<ide_pci)|(1<<ide_cmd646)|(1<<ide_ali14xx)) ((1<<ide_pci)|(1<<ide_cmd646)|(1<<ide_ali14xx))
#define IDE_CHIPSET_IS_PCI(c) ((IDE_CHIPSET_PCI_MASK >> (c)) & 1) #define IDE_CHIPSET_IS_PCI(c) ((IDE_CHIPSET_PCI_MASK >> (c)) & 1)
#ifdef CONFIG_BLK_DEV_IDEPCI #ifdef CONFIG_BLK_DEV_IDEPCI
typedef struct ide_pci_devid_s { struct ide_pci_device_s;
unsigned short vid;
unsigned short did;
} ide_pci_devid_t;
#define IDE_PCI_DEVID_NULL ((ide_pci_devid_t){0,0})
#define IDE_PCI_DEVID_EQ(a,b) (a.vid == b.vid && a.did == b.did)
#endif /* CONFIG_BLK_DEV_IDEPCI */ #endif /* CONFIG_BLK_DEV_IDEPCI */
typedef struct hwif_s { typedef struct hwif_s {
struct hwif_s *next; /* for linked-list in ide_hwgroup_t */ struct hwif_s *next; /* for linked-list in ide_hwgroup_t */
struct hwif_s *mate; /* other hwif from same PCI chip */
struct hwgroup_s *hwgroup; /* actually (ide_hwgroup_t *) */ struct hwgroup_s *hwgroup; /* actually (ide_hwgroup_t *) */
ide_ioreg_t io_ports[IDE_NR_PORTS]; /* task file registers */ struct proc_dir_entry *proc; /* /proc/ide/ directory entry */
/*
* FIXME!! need a generic register set :-/ PPC guys ideas?? char name[6]; /* name of interface, eg. "ide0" */
*
* ide_mmioreg_t mm_ports[IDE_NR_PORTS]; "task file registers" /* task file registers for pata and sata */
* ide_ioreg_t io_ports[IDE_NR_PORTS];
*/ sata_ioreg_t sata_scr[SATA_NR_PORTS];
sata_ioreg_t sata_misc[SATA_NR_PORTS];
hw_regs_t hw; /* Hardware info */ hw_regs_t hw; /* Hardware info */
ide_drive_t drives[MAX_DRIVES]; /* drive info */ ide_drive_t drives[MAX_DRIVES]; /* drive info */
int addressing; /* hosts addressing */
void (*tuneproc)(ide_drive_t *, byte); /* routine to tune PIO mode for drives */ u8 major; /* our major number */
int (*speedproc)(ide_drive_t *, byte); /* routine to retune DMA modes for drives */ u8 index; /* 0 for ide0; 1 for ide1; ... */
void (*selectproc)(ide_drive_t *); /* tweaks hardware to select drive */ u8 channel; /* for dual-port chips: 0=primary, 1=secondary */
void (*resetproc)(ide_drive_t *); /* routine to reset controller after a disk reset */ u8 straight8; /* Alan's straight 8 check */
void (*intrproc)(ide_drive_t *); /* special interrupt handling for shared pci interrupts */ u8 bus_state; /* power state of the IDE bus */
void (*maskproc)(ide_drive_t *, int); /* special host masking for drive selection */
int (*quirkproc)(ide_drive_t *); /* check host's drive quirk list */ u8 atapi_dma; /* host supports atapi_dma */
void (*rwproc)(ide_drive_t *, ide_dma_action_t); /* adjust timing based upon rq->cmd direction */ u8 ultra_mask;
void (*ideproc)(ide_ide_action_t, ide_drive_t *, void *, unsigned int); /* CPU-polled transfer routine */ u8 mwdma_mask;
int (*dmaproc)(ide_dma_action_t, ide_drive_t *); /* dma read/write/abort routine */ u8 swdma_mask;
int (*busproc)(ide_drive_t *, int); /* driver soft-power interface */
unsigned int *dmatable_cpu; /* dma physical region descriptor table (cpu view) */ hwif_chipset_t chipset; /* sub-module for tuning.. */
dma_addr_t dmatable_dma; /* dma physical region descriptor table (dma view) */
struct scatterlist *sg_table; /* Scatter-gather list used to build the above */ #ifdef CONFIG_BLK_DEV_IDEPCI
struct pci_dev *pci_dev; /* for pci chipsets */
struct ide_pci_device_s *cds; /* chipset device struct */
#endif /* CONFIG_BLK_DEV_IDEPCI */
#if 0
ide_hwif_ops_t *hwifops;
#else
/* routine is for HBA specific IDENTITY operations */
int (*identify)(ide_drive_t *);
/* routine to tune PIO mode for drives */
void (*tuneproc)(ide_drive_t *, u8);
/* routine to retune DMA modes for drives */
int (*speedproc)(ide_drive_t *, u8);
/* tweaks hardware to select drive */
void (*selectproc)(ide_drive_t *);
/* chipset polling based on hba specifics */
int (*reset_poll)(ide_drive_t *);
/* chipset specific changes to default for device-hba resets */
void (*pre_reset)(ide_drive_t *);
/* routine to reset controller after a disk reset */
void (*resetproc)(ide_drive_t *);
/* special interrupt handling for shared pci interrupts */
void (*intrproc)(ide_drive_t *);
/* special host masking for drive selection */
void (*maskproc)(ide_drive_t *, int);
/* check host's drive quirk list */
int (*quirkproc)(ide_drive_t *);
/* driver soft-power interface */
int (*busproc)(ide_drive_t *, int);
// /* host rate limiter */
// u8 (*ratemask)(ide_drive_t *);
// /* device rate limiter */
// u8 (*ratefilter)(ide_drive_t *, u8);
#endif
#if 0
ide_pio_ops_t *pioops;
#else
void (*ata_input_data)(ide_drive_t *, void *, u32);
void (*ata_output_data)(ide_drive_t *, void *, u32);
void (*atapi_input_bytes)(ide_drive_t *, void *, u32);
void (*atapi_output_bytes)(ide_drive_t *, void *, u32);
#endif
#if 0
ide_dma_ops_t *dmaops;
#else
int (*ide_dma_read)(ide_drive_t *drive);
int (*ide_dma_write)(ide_drive_t *drive);
int (*ide_dma_begin)(ide_drive_t *drive);
int (*ide_dma_end)(ide_drive_t *drive);
int (*ide_dma_check)(ide_drive_t *drive);
int (*ide_dma_on)(ide_drive_t *drive);
int (*ide_dma_off)(ide_drive_t *drive);
int (*ide_dma_off_quietly)(ide_drive_t *drive);
int (*ide_dma_test_irq)(ide_drive_t *drive);
int (*ide_dma_host_on)(ide_drive_t *drive);
int (*ide_dma_host_off)(ide_drive_t *drive);
int (*ide_dma_bad_drive)(ide_drive_t *drive);
int (*ide_dma_good_drive)(ide_drive_t *drive);
int (*ide_dma_count)(ide_drive_t *drive);
int (*ide_dma_verbose)(ide_drive_t *drive);
int (*ide_dma_retune)(ide_drive_t *drive);
int (*ide_dma_lostirq)(ide_drive_t *drive);
int (*ide_dma_timeout)(ide_drive_t *drive);
#endif
#if 0
ide_io_ops_t *iops;
#else
void (*OUTB)(u8 addr, u32 port);
void (*OUTW)(u16 addr, u32 port);
void (*OUTL)(u32 addr, u32 port);
void (*OUTBP)(u8 addr, u32 port);
void (*OUTWP)(u16 addr, u32 port);
void (*OUTLP)(u32 addr, u32 port);
void (*OUTSW)(u32 port, void *addr, u32 count);
void (*OUTSWP)(u32 port, void *addr, u32 count);
void (*OUTSL)(u32 port, void *addr, u32 count);
void (*OUTSLP)(u32 port, void *addr, u32 count);
u8 (*INB)(u32 port);
u16 (*INW)(u32 port);
u32 (*INL)(u32 port);
u8 (*INBP)(u32 port);
u16 (*INWP)(u32 port);
u32 (*INLP)(u32 port);
void (*INSW)(u32 port, void *addr, u32 count);
void (*INSWP)(u32 port, void *addr, u32 count);
void (*INSL)(u32 port, void *addr, u32 count);
void (*INSLP)(u32 port, void *addr, u32 count);
#endif
/* dma physical region descriptor table (cpu view) */
unsigned int *dmatable_cpu;
/* dma physical region descriptor table (dma view) */
dma_addr_t dmatable_dma;
/* Scatter-gather list used to build the above */
struct scatterlist *sg_table;
int sg_nents; /* Current number of entries in it */ int sg_nents; /* Current number of entries in it */
int sg_dma_direction; /* dma transfer direction */ int sg_dma_direction; /* dma transfer direction */
int sg_dma_active; /* is it in use */ int sg_dma_active; /* is it in use */
struct hwif_s *mate; /* other hwif from same PCI chip */
int mmio; /* hosts iomio (0), mmio (1) or custom (2) select */
int rqsize; /* max sectors per request */
int addressing; /* hosts addressing */
int irq; /* our irq number */
int initializing; /* set while initializing self */
unsigned long dma_master; /* reference base addr dmabase */
unsigned long dma_base; /* base addr for dma ports */ unsigned long dma_base; /* base addr for dma ports */
unsigned long dma_command; /* dma command register */
unsigned long dma_vendor1; /* dma vendor 1 register */
unsigned long dma_status; /* dma status register */
unsigned long dma_vendor3; /* dma vendor 3 register */
unsigned long dma_prdtable; /* actual prd table address */
unsigned long dma_base2; /* extended base addr for dma ports */
unsigned dma_extra; /* extra addr for dma ports */ unsigned dma_extra; /* extra addr for dma ports */
unsigned long config_data; /* for use by chipset-specific code */ unsigned long config_data; /* for use by chipset-specific code */
unsigned long select_data; /* for use by chipset-specific code */ unsigned long select_data; /* for use by chipset-specific code */
struct proc_dir_entry *proc; /* /proc/ide/ directory entry */ #if (DISK_RECOVERY_TIME > 0)
int irq; /* our irq number */ unsigned long last_time; /* time when previous rq was done */
byte major; /* our major number */ #endif
char name[6]; /* name of interface, eg. "ide0" */
byte index; /* 0 for ide0; 1 for ide1; ... */
hwif_chipset_t chipset; /* sub-module for tuning.. */
unsigned noprobe : 1; /* don't probe for this interface */ unsigned noprobe : 1; /* don't probe for this interface */
unsigned present : 1; /* this interface exists */ unsigned present : 1; /* this interface exists */
unsigned serialized : 1; /* serialized operation with mate hwif */ unsigned serialized : 1; /* serialized all channel operation */
unsigned sharing_irq: 1; /* 1 = sharing irq with another hwif */ unsigned sharing_irq: 1; /* 1 = sharing irq with another hwif */
unsigned reset : 1; /* reset after probe */ unsigned reset : 1; /* reset after probe */
unsigned autodma : 1; /* automatically try to enable DMA at boot */ unsigned autodma : 1; /* auto-attempt using DMA at boot */
unsigned udma_four : 1; /* 1=ATA-66 capable, 0=default */ unsigned udma_four : 1; /* 1=ATA-66 capable, 0=default */
unsigned no_highmem : 1; /* always use high i/o bounce */ unsigned highmem : 1; /* can do full 32-bit dma */
byte channel; /* for dual-port chips: 0=primary, 1=secondary */ unsigned no_dsc : 1; /* 0 default, 1 dsc_overlap disabled */
#ifdef CONFIG_BLK_DEV_IDEPCI
struct pci_dev *pci_dev; /* for pci chipsets */
ide_pci_devid_t pci_devid; /* for pci chipsets: {VID,DID} */
#endif /* CONFIG_BLK_DEV_IDEPCI */
#if (DISK_RECOVERY_TIME > 0)
unsigned long last_time; /* time when previous rq was done */
#endif
byte straight8; /* Alan's straight 8 check */
void *hwif_data; /* extra hwif data */ void *hwif_data; /* extra hwif data */
byte bus_state; /* power state of the IDE bus */
} ide_hwif_t; } ide_hwif_t;
/* /*
...@@ -769,7 +1082,7 @@ typedef struct hwif_s { ...@@ -769,7 +1082,7 @@ typedef struct hwif_s {
*/ */
typedef enum { typedef enum {
ide_stopped, /* no drive operation was started */ ide_stopped, /* no drive operation was started */
ide_started /* a drive operation was started, and a handler was set */ ide_started /* a drive operation was started, handler was set */
} ide_startstop_t; } ide_startstop_t;
/* /*
...@@ -778,26 +1091,41 @@ typedef enum { ...@@ -778,26 +1091,41 @@ typedef enum {
typedef ide_startstop_t (ide_pre_handler_t)(ide_drive_t *, struct request *); typedef ide_startstop_t (ide_pre_handler_t)(ide_drive_t *, struct request *);
typedef ide_startstop_t (ide_handler_t)(ide_drive_t *); typedef ide_startstop_t (ide_handler_t)(ide_drive_t *);
typedef ide_startstop_t (ide_post_handler_t)(ide_drive_t *); typedef ide_startstop_t (ide_post_handler_t)(ide_drive_t *);
/*
* when ide_timer_expiry fires, invoke a handler of this type
* to decide what to do.
*/
typedef int (ide_expiry_t)(ide_drive_t *); typedef int (ide_expiry_t)(ide_drive_t *);
typedef struct hwgroup_s { typedef struct hwgroup_s {
ide_handler_t *handler;/* irq handler, if active */ /* irq handler, if active */
ide_handler_t *handler_save;/* irq handler, if active */ ide_startstop_t (*handler)(ide_drive_t *);
volatile int busy; /* BOOL: protects all fields below */ /* irq handler, suspended if active */
int sleeping; /* BOOL: wake us up on timer expiry */ ide_startstop_t (*handler_save)(ide_drive_t *);
ide_drive_t *drive; /* current drive */ /* BOOL: protects all fields below */
ide_hwif_t *hwif; /* ptr to current hwif in linked-list */ volatile int busy;
struct request *rq; /* current request */ /* BOOL: wake us up on timer expiry */
struct timer_list timer; /* failsafe timer */ int sleeping;
struct request wrq; /* local copy of current write rq */ /* current drive */
unsigned long poll_timeout; /* timeout value during long polls */ ide_drive_t *drive;
ide_expiry_t *expiry; /* queried upon timeouts */ /* ptr to current hwif in linked-list */
int pio_clock; /* ide_system_bus_speed */ ide_hwif_t *hwif;
#ifdef CONFIG_BLK_DEV_IDEPCI
/* for pci chipsets */
struct pci_dev *pci_dev;
/* chipset device struct */
struct ide_pci_device_s *cds;
#endif /* CONFIG_BLK_DEV_IDEPCI */
/* current request */
struct request *rq;
/* failsafe timer */
struct timer_list timer;
/* local copy of current write rq */
struct request wrq;
/* timeout value during long polls */
unsigned long poll_timeout;
/* queried upon timeouts */
int (*expiry)(ide_drive_t *);
/* ide_system_bus_speed */
int pio_clock;
} ide_hwgroup_t; } ide_hwgroup_t;
/* structure attached to the request for IDE_TASK_CMDS */ /* structure attached to the request for IDE_TASK_CMDS */
...@@ -850,14 +1178,14 @@ typedef struct { ...@@ -850,14 +1178,14 @@ typedef struct {
} ide_proc_entry_t; } ide_proc_entry_t;
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
void proc_ide_create(void); extern void proc_ide_create(void);
void proc_ide_destroy(void); extern void proc_ide_destroy(void);
void recreate_proc_ide_device(ide_hwif_t *, ide_drive_t *); extern void recreate_proc_ide_device(ide_hwif_t *, ide_drive_t *);
void destroy_proc_ide_device(ide_hwif_t *, ide_drive_t *); extern void destroy_proc_ide_device(ide_hwif_t *, ide_drive_t *);
void destroy_proc_ide_drives(ide_hwif_t *); extern void destroy_proc_ide_drives(ide_hwif_t *);
void create_proc_ide_interfaces(void); extern void create_proc_ide_interfaces(void);
void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data); extern void ide_add_proc_entries(struct proc_dir_entry *, ide_proc_entry_t *, void *);
void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p); extern void ide_remove_proc_entries(struct proc_dir_entry *, ide_proc_entry_t *);
read_proc_t proc_ide_read_capacity; read_proc_t proc_ide_read_capacity;
read_proc_t proc_ide_read_geometry; read_proc_t proc_ide_read_geometry;
...@@ -889,7 +1217,7 @@ typedef struct ide_driver_s { ...@@ -889,7 +1217,7 @@ typedef struct ide_driver_s {
struct module *owner; struct module *owner;
const char *name; const char *name;
const char *version; const char *version;
byte media; u8 media;
unsigned busy : 1; unsigned busy : 1;
unsigned supports_dma : 1; unsigned supports_dma : 1;
unsigned supports_dsc_overlap : 1; unsigned supports_dsc_overlap : 1;
...@@ -899,9 +1227,9 @@ typedef struct ide_driver_s { ...@@ -899,9 +1227,9 @@ typedef struct ide_driver_s {
int (*resume)(ide_drive_t *); int (*resume)(ide_drive_t *);
int (*flushcache)(ide_drive_t *); int (*flushcache)(ide_drive_t *);
ide_startstop_t (*do_request)(ide_drive_t *, struct request *, unsigned long); ide_startstop_t (*do_request)(ide_drive_t *, struct request *, unsigned long);
int (*end_request)(ide_drive_t *, int); int (*end_request)(ide_drive_t *, int, int);
byte (*sense)(ide_drive_t *, const char *, byte); u8 (*sense)(ide_drive_t *, const char *, u8);
ide_startstop_t (*error)(ide_drive_t *, const char *, byte); ide_startstop_t (*error)(ide_drive_t *, const char *, u8);
int (*ioctl)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long); int (*ioctl)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
int (*open)(struct inode *, struct file *, ide_drive_t *); int (*open)(struct inode *, struct file *, ide_drive_t *);
void (*release)(struct inode *, struct file *, ide_drive_t *); void (*release)(struct inode *, struct file *, ide_drive_t *);
...@@ -911,7 +1239,7 @@ typedef struct ide_driver_s { ...@@ -911,7 +1239,7 @@ typedef struct ide_driver_s {
unsigned long (*capacity)(ide_drive_t *); unsigned long (*capacity)(ide_drive_t *);
ide_startstop_t (*special)(ide_drive_t *); ide_startstop_t (*special)(ide_drive_t *);
ide_proc_entry_t *proc; ide_proc_entry_t *proc;
int (*reinit)(ide_drive_t *); int (*attach)(ide_drive_t *);
void (*ata_prebuilder)(ide_drive_t *); void (*ata_prebuilder)(ide_drive_t *);
void (*atapi_prebuilder)(ide_drive_t *); void (*atapi_prebuilder)(ide_drive_t *);
struct list_head drives; struct list_head drives;
...@@ -935,6 +1263,13 @@ typedef struct ide_module_s { ...@@ -935,6 +1263,13 @@ typedef struct ide_module_s {
struct ide_module_s *next; struct ide_module_s *next;
} ide_module_t; } ide_module_t;
typedef struct ide_devices_s {
char name[4]; /* hdX */
unsigned attached : 1; /* native */
unsigned alttached : 1; /* alternate */
struct ide_devices_s *next;
} ide_devices_t;
/* /*
* ide_hwifs[] is the master data structure used to keep track * ide_hwifs[] is the master data structure used to keep track
* of just about everything in ide.c. Whenever possible, routines * of just about everything in ide.c. Whenever possible, routines
...@@ -945,7 +1280,15 @@ typedef struct ide_module_s { ...@@ -945,7 +1280,15 @@ typedef struct ide_module_s {
*/ */
#ifndef _IDE_C #ifndef _IDE_C
extern ide_hwif_t ide_hwifs[]; /* master data repository */ extern ide_hwif_t ide_hwifs[]; /* master data repository */
extern ide_module_t *ide_chipsets;
extern ide_module_t *ide_probe; extern ide_module_t *ide_probe;
extern ide_devices_t *idedisk;
extern ide_devices_t *idecd;
extern ide_devices_t *idefloppy;
extern ide_devices_t *idetape;
extern ide_devices_t *idescsi;
#endif #endif
extern int noautodma; extern int noautodma;
...@@ -957,38 +1300,47 @@ extern int noautodma; ...@@ -957,38 +1300,47 @@ extern int noautodma;
#define DEVICE_NR(device) (minor(device) >> PARTN_BITS) #define DEVICE_NR(device) (minor(device) >> PARTN_BITS)
#include <linux/blk.h> #include <linux/blk.h>
int ide_end_request (ide_drive_t *drive, int uptodate); extern int ide_end_request (ide_drive_t *drive, int uptodate, int nrsecs);
/* /*
* This is used on exit from the driver, to designate the next irq handler * This is used on exit from the driver, to designate the next irq handler
* and also to start the safety timer. * and also to start the safety timer.
*/ */
void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry); extern void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry);
/* /*
* Error reporting, in human readable form (luxurious, but a memory hog). * Error reporting, in human readable form (luxurious, but a memory hog).
*
* (drive, msg, status)
*/ */
byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat); byte ide_dump_status (ide_drive_t *drive, const char *msg, byte stat);
/* /*
* ide_error() takes action based on the error returned by the controller. * ide_error() takes action based on the error returned by the controller.
* The caller should return immediately after invoking this. * The caller should return immediately after invoking this.
*
* (drive, msg, status)
*/ */
ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat); ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat);
/* /*
* Issue a simple drive command * Issue a simple drive command
* The drive must be selected beforehand. * The drive must be selected beforehand.
*
* (drive, command, nsector, handler)
*/ */
void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler); extern void ide_cmd(ide_drive_t *, u8, u8, ide_handler_t *);
extern void ide_fix_driveid(struct hd_driveid *);
/* /*
* ide_fixstring() cleans up and (optionally) byte-swaps a text string, * ide_fixstring() cleans up and (optionally) byte-swaps a text string,
* removing leading/trailing blanks and compressing internal blanks. * removing leading/trailing blanks and compressing internal blanks.
* It is primarily used to tidy up the model name/number fields as * It is primarily used to tidy up the model name/number fields as
* returned by the WIN_[P]IDENTIFY commands. * returned by the WIN_[P]IDENTIFY commands.
*
* (s, bytecount, byteswap)
*/ */
void ide_fixstring (byte *s, const int bytecount, const int byteswap); extern void ide_fixstring(u8 *, const int, const int);
/* /*
* This routine busy-waits for the drive status to be not "busy". * This routine busy-waits for the drive status to be not "busy".
...@@ -997,43 +1349,44 @@ void ide_fixstring (byte *s, const int bytecount, const int byteswap); ...@@ -997,43 +1349,44 @@ void ide_fixstring (byte *s, const int bytecount, const int byteswap);
* cases return 1 after doing "*startstop = ide_error()", and the * cases return 1 after doing "*startstop = ide_error()", and the
* caller should return the updated value of "startstop" in this case. * caller should return the updated value of "startstop" in this case.
* "startstop" is unchanged when the function returns 0; * "startstop" is unchanged when the function returns 0;
* (startstop, drive, good, bad, timeout)
*/ */
int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout); extern int ide_wait_stat(ide_startstop_t *, ide_drive_t *, u8, u8, unsigned long);
/* /*
* This routine is called from the partition-table code in genhd.c * This routine is called from the partition-table code in genhd.c
* to "convert" a drive to a logical geometry with fewer than 1024 cyls. * to "convert" a drive to a logical geometry with fewer than 1024 cyls.
*/ */
int ide_xlate_1024 (kdev_t, int, int, const char *); extern int ide_xlate_1024 (kdev_t, int, int, const char *);
/* /*
* Convert kdev_t structure into ide_drive_t * one. * Convert kdev_t structure into ide_drive_t * one.
*/ */
ide_drive_t *get_info_ptr (kdev_t i_rdev); extern ide_drive_t *get_info_ptr (kdev_t i_rdev);
/* /*
* Return the current idea about the total capacity of this drive. * Return the current idea about the total capacity of this drive.
*/ */
unsigned long current_capacity (ide_drive_t *drive); extern unsigned long current_capacity (ide_drive_t *drive);
void ide_revalidate_drive (ide_drive_t *drive); extern void ide_revalidate_drive (ide_drive_t *drive);
/* /*
* Start a reset operation for an IDE interface. * Start a reset operation for an IDE interface.
* The caller should return immediately after invoking this. * The caller should return immediately after invoking this.
*/ */
ide_startstop_t ide_do_reset (ide_drive_t *); extern ide_startstop_t ide_do_reset (ide_drive_t *);
/* /*
* Re-Start an operation for an IDE interface. * Re-Start an operation for an IDE interface.
* The caller should return immediately after invoking this. * The caller should return immediately after invoking this.
*/ */
int restart_request (ide_drive_t *, struct request *); extern int restart_request (ide_drive_t *, struct request *);
/* /*
* This function is intended to be used prior to invoking ide_do_drive_cmd(). * This function is intended to be used prior to invoking ide_do_drive_cmd().
*/ */
void ide_init_drive_cmd (struct request *rq); extern void ide_init_drive_cmd (struct request *rq);
/* /*
* "action" parameter type for ide_do_drive_cmd() below. * "action" parameter type for ide_do_drive_cmd() below.
...@@ -1070,23 +1423,35 @@ typedef enum { ...@@ -1070,23 +1423,35 @@ typedef enum {
* for the new rq to be completed. This is again intended for careful * for the new rq to be completed. This is again intended for careful
* use by the ATAPI tape/cdrom driver code. * use by the ATAPI tape/cdrom driver code.
*/ */
int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action); extern int ide_do_drive_cmd(ide_drive_t *, struct request *, ide_action_t);
/* /*
* Clean up after success/failure of an explicit drive cmd. * Clean up after success/failure of an explicit drive cmd.
* stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD). * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD).
* stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASK_MASK). * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASK_MASK).
*
* (ide_drive_t *drive, u8 stat, u8 err)
*/ */
void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err); extern void ide_end_drive_cmd(ide_drive_t *, u8, u8);
/* /*
* Issue ATA command and wait for completion. use for implementing commands in kernel * Issue ATA command and wait for completion.
* Use for implementing commands in kernel
*
* (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf)
*/ */
int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf); extern int ide_wait_cmd(ide_drive_t *, u8, u8, u8, u8, u8 *);
int ide_wait_cmd_task (ide_drive_t *drive, byte *buf); /* (ide_drive_t *drive, u8 *buf) */
extern int ide_wait_cmd_task(ide_drive_t *, u8 *);
typedef struct ide_task_s { typedef struct ide_task_s {
/*
* struct hd_drive_task_hdr tf;
* task_struct_t tf;
* struct hd_drive_hob_hdr hobf;
* hob_struct_t hobf;
*/
task_ioreg_t tfRegister[8]; task_ioreg_t tfRegister[8];
task_ioreg_t hobRegister[8]; task_ioreg_t hobRegister[8];
ide_reg_valid_t tf_out_flags; ide_reg_valid_t tf_out_flags;
...@@ -1101,6 +1466,11 @@ typedef struct ide_task_s { ...@@ -1101,6 +1466,11 @@ typedef struct ide_task_s {
} ide_task_t; } ide_task_t;
typedef struct pkt_task_s { typedef struct pkt_task_s {
/*
* struct hd_drive_task_hdr pktf;
* task_struct_t pktf;
* u8 pkcdb[12];
*/
task_ioreg_t tfRegister[8]; task_ioreg_t tfRegister[8];
int data_phase; int data_phase;
int command_type; int command_type;
...@@ -1109,66 +1479,129 @@ typedef struct pkt_task_s { ...@@ -1109,66 +1479,129 @@ typedef struct pkt_task_s {
void *special; void *special;
} pkt_task_t; } pkt_task_t;
void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount); extern inline void SELECT_DRIVE(ide_drive_t *);
void ata_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount); extern inline void SELECT_INTERRUPT(ide_drive_t *);
void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount); extern inline void SELECT_MASK(ide_drive_t *, int);
void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount); extern inline void QUIRK_LIST(ide_drive_t *);
void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount); extern void ata_input_data(ide_drive_t *, void *, u32);
extern void ata_output_data(ide_drive_t *, void *, u32);
extern void atapi_input_bytes(ide_drive_t *, void *, u32);
extern void atapi_output_bytes(ide_drive_t *, void *, u32);
extern void taskfile_input_data(ide_drive_t *, void *, u32);
extern void taskfile_output_data(ide_drive_t *, void *, u32);
int drive_is_ready (ide_drive_t *drive); extern int drive_is_ready(ide_drive_t *);
int wait_for_ready (ide_drive_t *drive, int timeout); extern int wait_for_ready(ide_drive_t *, int /* timeout */);
/* /*
* taskfile io for disks for now...and builds request from ide_ioctl * taskfile io for disks for now...and builds request from ide_ioctl
*/ */
ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task); extern ide_startstop_t do_rw_taskfile(ide_drive_t *, ide_task_t *);
void ide_end_taskfile (ide_drive_t *drive, byte stat, byte err); /* (ide_drive_t *drive, u8 stat, u8 err) */
extern void ide_end_taskfile(ide_drive_t *, u8, u8);
/* /*
* Special Flagged Register Validation Caller * Special Flagged Register Validation Caller
*/ */
ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task); extern ide_startstop_t flagged_taskfile(ide_drive_t *, ide_task_t *);
ide_startstop_t set_multmode_intr (ide_drive_t *drive); extern ide_startstop_t set_multmode_intr(ide_drive_t *);
ide_startstop_t set_geometry_intr (ide_drive_t *drive); extern ide_startstop_t set_geometry_intr(ide_drive_t *);
ide_startstop_t recal_intr (ide_drive_t *drive); extern ide_startstop_t recal_intr(ide_drive_t *);
ide_startstop_t task_no_data_intr (ide_drive_t *drive); extern ide_startstop_t task_no_data_intr(ide_drive_t *);
ide_startstop_t task_in_intr (ide_drive_t *drive); extern ide_startstop_t task_in_intr(ide_drive_t *);
ide_startstop_t task_mulin_intr (ide_drive_t *drive); extern ide_startstop_t task_mulin_intr(ide_drive_t *);
ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq); extern ide_startstop_t pre_task_out_intr(ide_drive_t *, struct request *);
ide_startstop_t task_out_intr (ide_drive_t *drive); extern ide_startstop_t task_out_intr(ide_drive_t *);
ide_startstop_t pre_task_mulout_intr (ide_drive_t *drive, struct request *rq); extern ide_startstop_t pre_task_mulout_intr(ide_drive_t *, struct request *);
ide_startstop_t task_mulout_intr (ide_drive_t *drive); extern ide_startstop_t task_mulout_intr(ide_drive_t *);
void ide_init_drive_taskfile (struct request *rq); extern void ide_init_drive_taskfile(struct request *);
int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *cmd, byte *buf); extern int ide_raw_taskfile(ide_drive_t *, ide_task_t *, u8 *);
ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile); extern ide_pre_handler_t * ide_pre_handler_parser(struct hd_drive_task_hdr *, struct hd_drive_hob_hdr *);
ide_handler_t * ide_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile);
ide_post_handler_t * ide_post_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile); extern ide_handler_t * ide_handler_parser(struct hd_drive_task_hdr *, struct hd_drive_hob_hdr *);
extern ide_post_handler_t * ide_post_handler_parser(struct hd_drive_task_hdr *, struct hd_drive_hob_hdr *);
/* Expects args is a full set of TF registers and parses the command type */ /* Expects args is a full set of TF registers and parses the command type */
int ide_cmd_type_parser (ide_task_t *args); extern int ide_cmd_type_parser(ide_task_t *);
int ide_taskfile_ioctl(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
int ide_cmd_ioctl(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
int ide_task_ioctl(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
#if 0
#define IDEFLOPPY_PC_BUFFER_SIZE 256
#define IDETAPE_PC_BUFFER_SIZE 256
#define IDE_PC_BUFFER_SIZE 256
typedef struct ide_packet_command_s {
/* Actual packet bytes */
u8 c[12];
/* On each retry, we increment retries */
int retries;
/* Error code */
int error;
/* Bytes to transfer */
int request_transfer;
/* Bytes actually transferred */
int actually_transferred;
/* Size of our data buffer */
int buffer_size;
struct buffer_head *bh;
u8 *b_data;
/* The corresponding request */
struct request *rq;
# if 0
/* Scatter gather table */
struct scatterlist *sg;
# endif
int b_count;
/* Data buffer */
u8 *buffer;
/* Pointer into the above buffer */
u8 *current_position;
/* Called when this packet command is completed */
ide_startstop_t (*callback) (ide_drive_t *);
/* Temporary buffer */
u8 pc_buffer[IDE_PC_BUFFER_SIZE];
/* Status/Action bit flags: long for set_bit */
unsigned long flags;
} ide_pc_t;
ide-cd orthoginal :-/
struct packet_command {
char *buffer;
int buflen;
int stat;
int quiet;
int timeout;
struct request_sense *sense;
unsigned char c[12];
};
int ide_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); #endif
int ide_cmd_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
int ide_task_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
#ifdef CONFIG_PKT_TASK_IOCTL #ifdef CONFIG_PKT_TASK_IOCTL
int pkt_taskfile_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); extern int pkt_taskfile_ioctl(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
#endif /* CONFIG_PKT_TASK_IOCTL */ #endif /* CONFIG_PKT_TASK_IOCTL */
void ide_delay_50ms (void); extern void ide_delay_50ms(void);
int system_bus_clock(void); extern int system_bus_clock(void);
byte ide_auto_reduce_xfer (ide_drive_t *drive); extern u8 ide_auto_reduce_xfer(ide_drive_t *);
int ide_driveid_update (ide_drive_t *drive); extern int ide_driveid_update(ide_drive_t *);
int ide_ata66_check (ide_drive_t *drive, ide_task_t *args); extern int ide_ata66_check(ide_drive_t *, ide_task_t *);
int ide_config_drive_speed (ide_drive_t *drive, byte speed); extern int ide_config_drive_speed(ide_drive_t *, u8);
byte eighty_ninty_three (ide_drive_t *drive); extern u8 eighty_ninty_three (ide_drive_t *);
int set_transfer (ide_drive_t *drive, ide_task_t *args); extern int set_transfer(ide_drive_t *, ide_task_t *);
int taskfile_lib_get_identify (ide_drive_t *drive, byte *buf); extern int taskfile_lib_get_identify(ide_drive_t *drive, u8 *);
/* /*
* ide_system_bus_speed() returns what we think is the system VESA/PCI * ide_system_bus_speed() returns what we think is the system VESA/PCI
...@@ -1176,45 +1609,55 @@ int taskfile_lib_get_identify (ide_drive_t *drive, byte *buf); ...@@ -1176,45 +1609,55 @@ int taskfile_lib_get_identify (ide_drive_t *drive, byte *buf);
* The default is 40 for known PCI systems, 50 otherwise. * The default is 40 for known PCI systems, 50 otherwise.
* The "idebus=xx" parameter can be used to override this value. * The "idebus=xx" parameter can be used to override this value.
*/ */
int ide_system_bus_speed (void); extern int ide_system_bus_speed(void);
/* /*
* ide_stall_queue() can be used by a drive to give excess bandwidth back * ide_stall_queue() can be used by a drive to give excess bandwidth back
* to the hwgroup by sleeping for timeout jiffies. * to the hwgroup by sleeping for timeout jiffies.
*/ */
void ide_stall_queue (ide_drive_t *drive, unsigned long timeout); extern void ide_stall_queue(ide_drive_t *drive, unsigned long timeout);
/* /*
* ide_get_queue() returns the queue which corresponds to a given device. * ide_get_queue() returns the queue which corresponds to a given device.
*/ */
request_queue_t *ide_get_queue (kdev_t dev); extern request_queue_t *ide_get_queue (kdev_t dev);
/* /*
* CompactFlash cards and their brethern pretend to be removable hard disks, * CompactFlash cards and their brethern pretend to be removable hard disks,
* but they never have a slave unit, and they don't have doorlock mechanisms. * but they never have a slave unit, and they don't have doorlock mechanisms.
* This test catches them, and is invoked elsewhere when setting appropriate config bits. * This test catches them, and is invoked elsewhere when setting appropriate
* config bits.
*/ */
int drive_is_flashcard (ide_drive_t *drive); extern int drive_is_flashcard (ide_drive_t *drive);
int ide_spin_wait_hwgroup (ide_drive_t *drive); extern int ide_spin_wait_hwgroup(ide_drive_t *);
void ide_timer_expiry (unsigned long data); extern void ide_timer_expiry(unsigned long);
void ide_intr (int irq, void *dev_id, struct pt_regs *regs); extern void ide_intr(int irq, void *dev_id, struct pt_regs *regs);
void do_ide_request (request_queue_t * q); extern void do_ide_request(request_queue_t *);
void ide_init_subdrivers (void); extern void ide_init_subdrivers(void);
#ifndef _IDE_C #ifndef _IDE_C
extern struct block_device_operations ide_fops[]; extern struct block_device_operations ide_fops[];
extern ide_proc_entry_t generic_subdriver_entries[]; extern ide_proc_entry_t generic_subdriver_entries[];
#endif #endif
int ata_attach(ide_drive_t *drive); extern int ata_attach(ide_drive_t *);
#ifdef _IDE_C #ifdef _IDE_C
#ifdef CONFIG_BLK_DEV_IDE #ifdef CONFIG_BLK_DEV_IDE
int ideprobe_init (void); extern int ideprobe_init(void);
#ifdef CONFIG_BLK_DEV_IDEPCI
extern void ide_scan_pcibus(int scan_direction) __init;
#endif /* CONFIG_BLK_DEV_IDEPCI */
#endif /* CONFIG_BLK_DEV_IDE */ #endif /* CONFIG_BLK_DEV_IDE */
#endif /* _IDE_C */ #endif /* _IDE_C */
extern void default_hwif_iops(ide_hwif_t *);
extern void default_hwif_mmiops(ide_hwif_t *);
extern void default_hwif_transport(ide_hwif_t *);
int ide_register_driver(ide_driver_t *driver); int ide_register_driver(ide_driver_t *driver);
void ide_unregister_driver(ide_driver_t *driver); void ide_unregister_driver(ide_driver_t *driver);
int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version); int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version);
...@@ -1222,85 +1665,113 @@ int ide_unregister_subdriver (ide_drive_t *drive); ...@@ -1222,85 +1665,113 @@ int ide_unregister_subdriver (ide_drive_t *drive);
int ide_replace_subdriver(ide_drive_t *drive, const char *driver); int ide_replace_subdriver(ide_drive_t *drive, const char *driver);
#ifdef CONFIG_BLK_DEV_IDEPCI #ifdef CONFIG_BLK_DEV_IDEPCI
#ifdef CONFIG_PROC_FS
typedef struct ide_pci_host_proc_s {
char *name;
u8 set;
get_info_t *get_info;
struct proc_dir_entry *parent;
struct ide_pci_host_proc_s *next;
} ide_pci_host_proc_t;
void ide_pci_register_host_proc(ide_pci_host_proc_t *);
#endif /* CONFIG_PROC_FS */
#define ON_BOARD 1 #define ON_BOARD 1
#define NEVER_BOARD 0 #define NEVER_BOARD 0
#ifdef CONFIG_BLK_DEV_OFFBOARD #ifdef CONFIG_BLK_DEV_OFFBOARD
# define OFF_BOARD ON_BOARD # define OFF_BOARD ON_BOARD
#else /* CONFIG_BLK_DEV_OFFBOARD */ #else /* CONFIG_BLK_DEV_OFFBOARD */
# define OFF_BOARD NEVER_BOARD # define OFF_BOARD NEVER_BOARD
#endif /* CONFIG_BLK_DEV_OFFBOARD */ #endif /* CONFIG_BLK_DEV_OFFBOARD */
#define NODMA 0
#define NOAUTODMA 1
#define AUTODMA 2
#define EOL 255
typedef struct ide_pci_enablebit_s { typedef struct ide_pci_enablebit_s {
byte reg; /* byte pci reg holding the enable-bit */ u8 reg; /* byte pci reg holding the enable-bit */
byte mask; /* mask to isolate the enable-bit */ u8 mask; /* mask to isolate the enable-bit */
byte val; /* value of masked reg when "enabled" */ u8 val; /* value of masked reg when "enabled" */
} ide_pci_enablebit_t; } ide_pci_enablebit_t;
typedef struct ide_pci_device_s { typedef struct ide_pci_device_s {
ide_pci_devid_t devid; u16 vendor;
u16 device;
char *name; char *name;
void (*fixup_device)(struct pci_dev *, struct ide_pci_device_s *); void (*init_setup)(struct pci_dev *, struct ide_pci_device_s *);
unsigned int (*init_chipset)(struct pci_dev *, const char *); unsigned int (*init_chipset)(struct pci_dev *, const char *);
unsigned int (*ata66_check)(ide_hwif_t *); void (*init_iops)(ide_hwif_t *);
void (*init_hwif)(ide_hwif_t *); void (*init_hwif)(ide_hwif_t *);
void (*dma_init)(ide_hwif_t *, unsigned long); void (*init_dma)(ide_hwif_t *, unsigned long);
u8 channels;
u8 autodma;
ide_pci_enablebit_t enablebits[2]; ide_pci_enablebit_t enablebits[2];
byte bootable; u8 bootable;
unsigned int extra; unsigned int extra;
struct ide_pci_device_s *next;
} ide_pci_device_t; } ide_pci_device_t;
#ifdef LINUX_PCI_H #ifdef LINUX_PCI_H
extern inline void ide_register_xp_fix(struct pci_dev *dev) extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *);
{ extern void ide_setup_pci_devices(struct pci_dev *, struct pci_dev *, ide_pci_device_t *);
int i;
unsigned short cmd;
unsigned long flags;
unsigned long base_address[4] = { 0x1f0, 0x3f4, 0x170, 0x374 };
local_irq_save(flags);
pci_read_config_word(dev, PCI_COMMAND, &cmd);
pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
for (i=0; i<4; i++) {
dev->resource[i].start = 0;
dev->resource[i].end = 0;
dev->resource[i].flags = 0;
}
for (i=0; i<4; i++) {
dev->resource[i].start = base_address[i];
dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
pci_write_config_dword(dev,
(PCI_BASE_ADDRESS_0 + (i * 4)),
dev->resource[i].start);
}
pci_write_config_word(dev, PCI_COMMAND, cmd);
local_irq_restore(flags);
}
void ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t *d) __init;
#endif /* LINUX_PCI_H */ #endif /* LINUX_PCI_H */
unsigned long ide_find_free_region (unsigned short size) __init; #endif /* CONFIG_BLK_DEV_IDEPCI */
void ide_scan_pcibus (int scan_direction) __init;
#endif
#ifdef CONFIG_BLK_DEV_IDEDMA #ifdef CONFIG_BLK_DEV_IDEDMA
#define BAD_DMA_DRIVE 0 #define BAD_DMA_DRIVE 0
#define GOOD_DMA_DRIVE 1 #define GOOD_DMA_DRIVE 1
int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func); extern int ide_build_dmatable(ide_drive_t *, struct request *);
void ide_destroy_dmatable (ide_drive_t *drive); extern void ide_destroy_dmatable(ide_drive_t *);
ide_startstop_t ide_dma_intr (ide_drive_t *drive); extern ide_startstop_t ide_dma_intr(ide_drive_t *);
int check_drive_lists (ide_drive_t *drive, int good_bad); extern int ide_release_dma(ide_hwif_t *);
int report_drive_dmaing (ide_drive_t *drive); extern void ide_setup_dma(ide_hwif_t *, unsigned long, unsigned int);
int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive);
int ide_release_dma (ide_hwif_t *hwif); extern int __ide_dma_host_off(ide_drive_t *);
void ide_setup_dma (ide_hwif_t *hwif, unsigned long dmabase, unsigned int num_ports) __init; extern int __ide_dma_off_quietly(ide_drive_t *);
unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) __init; extern int __ide_dma_off(ide_drive_t *);
#endif /* CONFIG_BLK_DEV_IDEPCI */ extern int __ide_dma_host_on(ide_drive_t *);
extern int __ide_dma_on(ide_drive_t *);
extern int __ide_dma_check(ide_drive_t *);
extern int __ide_dma_read(ide_drive_t *);
extern int __ide_dma_write(ide_drive_t *);
extern int __ide_dma_begin(ide_drive_t *);
extern int __ide_dma_end(ide_drive_t *);
extern int __ide_dma_test_irq(ide_drive_t *);
extern int __ide_dma_bad_drive(ide_drive_t *);
extern int __ide_dma_good_drive(ide_drive_t *);
extern int __ide_dma_count(ide_drive_t *);
extern int __ide_dma_verbose(ide_drive_t *);
extern int __ide_dma_retune(ide_drive_t *);
extern int __ide_dma_lostirq(ide_drive_t *);
extern int __ide_dma_timeout(ide_drive_t *);
#endif /* CONFIG_BLK_DEV_IDEDMA */
extern void hwif_unregister(ide_hwif_t *);
extern void export_ide_init_queue(ide_drive_t *);
extern u8 export_probe_for_drive(ide_drive_t *);
extern int probe_hwif_init(ide_hwif_t *);
static inline void *ide_get_hwifdata (ide_hwif_t * hwif)
{
return hwif->hwif_data;
}
void hwif_unregister (ide_hwif_t *hwif); static inline void ide_set_hwifdata (ide_hwif_t * hwif, void *data)
{
hwif->hwif_data = data;
}
void export_ide_init_queue (ide_drive_t *drive); /* ide-lib.c */
byte export_probe_for_drive (ide_drive_t *drive); extern u8 ide_dma_speed(ide_drive_t *drive, u8 mode);
extern u8 ide_rate_filter(u8 mode, u8 speed);
extern int ide_dma_enable(ide_drive_t *drive);
extern char *ide_xfer_verbose(u8 xfer_rate);
extern spinlock_t ide_lock; extern spinlock_t ide_lock;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment