Commit a73f75e2 authored by Martin Dalecki's avatar Martin Dalecki Committed by Linus Torvalds

[PATCH] 2.5.20 IDE 84

 - Simplify ide_cmd_type_parse by removing the handling of commands which we
   never use.

 - Realize that pre_task_out_intr and pre_task_mulout_intr are semanticaly
   identical. Use only pre_task_out_intr(). This allowed us to
   eliminate the prehandler altogether.

 - Updated fix for misconfigured host chips by Vojtech Pavlik.

 - Be more permissive about ioctl handling to allow device type drivers to do
   they own checks.

 - ali14xx cleanups by Andrej Panin.

 - Unfold usage ide_cmd_type_parser in tcq.c code. This makes this operation
   local to ide-disk.c. Move it as well as the interrupt handlers used only for
   the handling of disk requests there too.

 - Guard against calling handler before the drive is ready for it in
   ata_taskfile()! Well this bug was there before, but right now we inform
   about it.

 - Unfold ide_cmd_type_praser in ide-disk.c. Merge the remaining bits of it with
   get_command. Well it's no more.

 - Move recal_intr to ide.c - the only place where it's used.

This doesn't change the "mechanics" of the code but it makes it a lot more
"obvious" what's going on.
parent 0f65c90d
...@@ -99,17 +99,6 @@ static void __devinit pci_fixup_ide_trash(struct pci_dev *d) ...@@ -99,17 +99,6 @@ static void __devinit pci_fixup_ide_trash(struct pci_dev *d)
d->resource[i].start = d->resource[i].end = d->resource[i].flags = 0; d->resource[i].start = d->resource[i].end = d->resource[i].flags = 0;
} }
static void __devinit pci_fixup_ide_exbar(struct pci_dev *d)
{
/*
* Some new Intel IDE controllers have an EXBAR register for
* MMIO instead of PIO. It's unused, undocumented (though maybe
* functional). BIOSes often assign conflicting memory address
* to this. Just kill it.
*/
d->resource[5].start = d->resource[5].end = d->resource[5].flags = 0;
}
static void __devinit pci_fixup_latency(struct pci_dev *d) static void __devinit pci_fixup_latency(struct pci_dev *d)
{ {
/* /*
...@@ -185,9 +174,9 @@ struct pci_fixup pcibios_fixups[] = { ...@@ -185,9 +174,9 @@ struct pci_fixup pcibios_fixups[] = {
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, pci_fixup_latency }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, pci_fixup_latency },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5598, pci_fixup_latency }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5598, pci_fixup_latency },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, pci_fixup_piix4_acpi }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, pci_fixup_piix4_acpi },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10, pci_fixup_ide_exbar }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10, pci_fixup_ide_trash },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_11, pci_fixup_ide_exbar }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_11, pci_fixup_ide_trash },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_9, pci_fixup_ide_exbar }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_9, pci_fixup_ide_trash },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, pci_fixup_via_northbridge_bug }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, pci_fixup_via_northbridge_bug },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8622, pci_fixup_via_northbridge_bug }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8622, pci_fixup_via_northbridge_bug },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, pci_fixup_via_northbridge_bug }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, pci_fixup_via_northbridge_bug },
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* I think the code should be pretty understandable, * I think the code should be pretty understandable,
* but I'll be happy to (try to) answer questions. * but I'll be happy to (try to) answer questions.
* *
* The critical part is in the setupDrive function. The initRegisters * The critical part is in the ali14xx_tune_drive function. The init_registers
* function doesn't seem to be necessary, but the DOS driver does it, so * function doesn't seem to be necessary, but the DOS driver does it, so
* I threw it in. * I threw it in.
* *
...@@ -37,12 +37,6 @@ ...@@ -37,12 +37,6 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <linux/ide.h> #include <linux/ide.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -52,12 +46,14 @@ ...@@ -52,12 +46,14 @@
/* port addresses for auto-detection */ /* port addresses for auto-detection */
#define ALI_NUM_PORTS 4 #define ALI_NUM_PORTS 4
static int ports[ALI_NUM_PORTS] __initdata = {0x074, 0x0f4, 0x034, 0x0e4}; static int ports[ALI_NUM_PORTS] __initdata = { 0x074, 0x0f4, 0x034, 0x0e4 };
/* register initialization data */ /* register initialization data */
typedef struct { byte reg, data; } RegInitializer; struct reg_initializer {
u8 reg, data;
};
static RegInitializer initData[] __initdata = { static struct reg_initializer init_data[] __initdata = {
{0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00}, {0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00},
{0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f},
{0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
...@@ -68,37 +64,37 @@ static RegInitializer initData[] __initdata = { ...@@ -68,37 +64,37 @@ static RegInitializer initData[] __initdata = {
}; };
/* timing parameter registers for each drive */ /* timing parameter registers for each drive */
static struct { byte reg1, reg2, reg3, reg4; } regTab[4] = { static struct {
{0x03, 0x26, 0x04, 0x27}, /* drive 0 */ u8 reg1, reg2, reg3, reg4;
{0x05, 0x28, 0x06, 0x29}, /* drive 1 */ } reg_tab[4] = {
{0x2b, 0x30, 0x2c, 0x31}, /* drive 2 */ { 0x03, 0x26, 0x04, 0x27 }, /* drive 0 */
{0x2d, 0x32, 0x2e, 0x33}, /* drive 3 */ { 0x05, 0x28, 0x06, 0x29 }, /* drive 1 */
{ 0x2b, 0x30, 0x2c, 0x31 }, /* drive 2 */
{ 0x2d, 0x32, 0x2e, 0x33 }, /* drive 3 */
}; };
static int basePort; /* base port address */ static int base_port; /* base port address */
static int regPort; /* port for register number */ static int reg_port; /* port for register number */
static int dataPort; /* port for register data */ static int data_port; /* port for register data */
static byte regOn; /* output to base port to access registers */ static u8 reg_on; /* output to base port to access registers */
static byte regOff; /* output to base port to close registers */ static u8 reg_off; /* output to base port to close registers */
/*------------------------------------------------------------------------*/
/* /*
* Read a controller register. * Read a controller register.
*/ */
static inline byte inReg (byte reg) static inline u8 in_reg(u8 reg)
{ {
outb_p(reg, regPort); outb_p(reg, reg_port);
return inb(dataPort); return inb(data_port);
} }
/* /*
* Write a controller register. * Write a controller register.
*/ */
static void outReg (byte data, byte reg) static inline void out_reg(u8 data, u8 reg)
{ {
outb_p(reg, regPort); outb_p(reg, reg_port);
outb_p(data, dataPort); outb_p(data, data_port);
} }
/* /*
...@@ -108,7 +104,7 @@ static void outReg (byte data, byte reg) ...@@ -108,7 +104,7 @@ static void outReg (byte data, byte reg)
*/ */
static void ali14xx_tune_drive(struct ata_device *drive, u8 pio) static void ali14xx_tune_drive(struct ata_device *drive, u8 pio)
{ {
int driveNum; int drive_num;
int time1, time2; int time1, time2;
u8 param1, param2, param3, param4; u8 param1, param2, param3, param4;
unsigned long flags; unsigned long flags;
...@@ -117,7 +113,7 @@ static void ali14xx_tune_drive(struct ata_device *drive, u8 pio) ...@@ -117,7 +113,7 @@ static void ali14xx_tune_drive(struct ata_device *drive, u8 pio)
if (pio == 255) if (pio == 255)
pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO); pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO);
else else
pio = XFER_PIO_0 + min_t(byte, pio, 4); pio = XFER_PIO_0 + min_t(u8, pio, 4);
t = ata_timing_data(pio); t = ata_timing_data(pio);
...@@ -130,50 +126,50 @@ static void ali14xx_tune_drive(struct ata_device *drive, u8 pio) ...@@ -130,50 +126,50 @@ static void ali14xx_tune_drive(struct ata_device *drive, u8 pio)
param3 += 8; param3 += 8;
param4 += 8; param4 += 8;
} }
printk("%s: PIO mode%d, t1=%dns, t2=%dns, cycles = %d+%d, %d+%d\n", printk(KERN_DEBUG "%s: PIO mode%d, t1=%dns, t2=%dns, cycles = %d+%d, %d+%d\n",
drive->name, pio - XFER_PIO_0, time1, time2, param1, param2, param3, param4); drive->name, pio - XFER_PIO_0, time1, time2, param1, param2, param3, param4);
/* stuff timing parameters into controller registers */ /* stuff timing parameters into controller registers */
driveNum = (drive->channel->index << 1) + drive->select.b.unit; drive_num = (drive->channel->index << 1) + drive->select.b.unit;
save_flags(flags); /* all CPUs */ save_flags(flags); /* all CPUs */
cli(); /* all CPUs */ cli(); /* all CPUs */
outb_p(regOn, basePort); outb_p(reg_on, base_port);
outReg(param1, regTab[driveNum].reg1); out_reg(param1, reg_tab[drive_num].reg1);
outReg(param2, regTab[driveNum].reg2); out_reg(param2, reg_tab[drive_num].reg2);
outReg(param3, regTab[driveNum].reg3); out_reg(param3, reg_tab[drive_num].reg3);
outReg(param4, regTab[driveNum].reg4); out_reg(param4, reg_tab[drive_num].reg4);
outb_p(regOff, basePort); outb_p(reg_off, base_port);
restore_flags(flags); /* all CPUs */ restore_flags(flags); /* all CPUs */
} }
/* /*
* Auto-detect the IDE controller port. * Auto-detect the IDE controller port.
*/ */
static int __init findPort (void) static int __init find_port(void)
{ {
int i; int i;
byte t;
unsigned long flags; unsigned long flags;
__save_flags(flags); /* local CPU only */ __save_flags(flags); /* local CPU only */
__cli(); /* local CPU only */ __cli(); /* local CPU only */
for (i = 0; i < ALI_NUM_PORTS; ++i) { for (i = 0; i < ALI_NUM_PORTS; i++) {
basePort = ports[i]; base_port = ports[i];
regOff = inb(basePort); reg_off = inb(base_port);
for (regOn = 0x30; regOn <= 0x33; ++regOn) { for (reg_on = 0x30; reg_on <= 0x33; reg_on++) {
outb_p(regOn, basePort); outb_p(reg_on, base_port);
if (inb(basePort) == regOn) { if (inb(base_port) == reg_on) {
regPort = basePort + 4; u8 t;
dataPort = basePort + 8; reg_port = base_port + 4;
t = inReg(0) & 0xf0; data_port = base_port + 8;
outb_p(regOff, basePort); t = in_reg(0) & 0xf0;
outb_p(reg_off, base_port);
__restore_flags(flags); /* local CPU only */ __restore_flags(flags); /* local CPU only */
if (t != 0x50) if (t != 0x50)
return 0; return 0;
return 1; /* success */ return 1; /* success */
} }
} }
outb_p(regOff, basePort); outb_p(reg_off, base_port);
} }
__restore_flags(flags); /* local CPU only */ __restore_flags(flags); /* local CPU only */
return 0; return 0;
...@@ -182,32 +178,34 @@ static int __init findPort (void) ...@@ -182,32 +178,34 @@ static int __init findPort (void)
/* /*
* Initialize controller registers with default values. * Initialize controller registers with default values.
*/ */
static int __init initRegisters (void) { static int __init init_registers(void)
RegInitializer *p; {
byte t; struct reg_initializer *p;
unsigned long flags; unsigned long flags;
u8 t;
__save_flags(flags); /* local CPU only */ __save_flags(flags); /* local CPU only */
__cli(); /* local CPU only */ __cli(); /* local CPU only */
outb_p(regOn, basePort); outb_p(reg_on, base_port);
for (p = initData; p->reg != 0; ++p) for (p = init_data; p->reg != 0; ++p)
outReg(p->data, p->reg); out_reg(p->data, p->reg);
outb_p(0x01, regPort); outb_p(0x01, reg_port);
t = inb(regPort) & 0x01; t = inb(reg_port) & 0x01;
outb_p(regOff, basePort); outb_p(reg_off, base_port);
__restore_flags(flags); /* local CPU only */ __restore_flags(flags); /* local CPU only */
return t; return t;
} }
void __init init_ali14xx (void) void __init init_ali14xx(void)
{ {
/* auto-detect IDE controller port */ /* auto-detect IDE controller port */
if (!findPort()) { if (!find_port()) {
printk("\nali14xx: not found"); printk(KERN_ERR "ali14xx: not found\n");
return; return;
} }
printk("\nali14xx: base= 0x%03x, regOn = 0x%02x", basePort, regOn); printk(KERN_DEBUG "ali14xx: base=%#03x, reg_on=%#02x\n",
base_port, reg_on);
ide_hwifs[0].chipset = ide_ali14xx; ide_hwifs[0].chipset = ide_ali14xx;
ide_hwifs[1].chipset = ide_ali14xx; ide_hwifs[1].chipset = ide_ali14xx;
ide_hwifs[0].tuneproc = &ali14xx_tune_drive; ide_hwifs[0].tuneproc = &ali14xx_tune_drive;
...@@ -216,8 +214,8 @@ void __init init_ali14xx (void) ...@@ -216,8 +214,8 @@ void __init init_ali14xx (void)
ide_hwifs[1].unit = ATA_SECONDARY; ide_hwifs[1].unit = ATA_SECONDARY;
/* initialize controller registers */ /* initialize controller registers */
if (!initRegisters()) { if (!init_registers()) {
printk("\nali14xx: Chip initialization failed"); printk(KERN_ERR "ali14xx: Chip initialization failed\n");
return; return;
} }
} }
...@@ -90,7 +90,224 @@ static int lba_capacity_is_ok(struct hd_driveid *id) ...@@ -90,7 +90,224 @@ static int lba_capacity_is_ok(struct hd_driveid *id)
return 0; /* lba_capacity value may be bad */ return 0; /* lba_capacity value may be bad */
} }
static u8 get_command(struct ata_device *drive, int cmd) /*
* Handler for command with PIO data-in phase
*/
static ide_startstop_t task_in_intr(struct ata_device *drive, struct request *rq)
{
char *buf = NULL;
unsigned long flags;
if (!ata_status(drive, DATA_READY, BAD_R_STAT)) {
if (drive->status & (ERR_STAT|DRQ_STAT))
return ata_error(drive, rq, __FUNCTION__);
if (!(drive->status & BUSY_STAT)) {
#if 0
printk("task_in_intr to Soon wait for next interrupt\n");
#endif
ide_set_handler(drive, task_in_intr, WAIT_CMD, NULL);
return ide_started;
}
}
buf = ide_map_rq(rq, &flags);
#if 0
printk("Read: %p, rq->current_nr_sectors: %d\n", buf, (int) rq->current_nr_sectors);
#endif
ata_read(drive, buf, SECTOR_WORDS);
ide_unmap_rq(rq, buf, &flags);
/* First segment of the request is complete. note that this does not
* necessarily mean that the entire request is done!! this is only true
* if ide_end_request() returns 0.
*/
if (--rq->current_nr_sectors <= 0) {
#if 0
printk("Request Ended stat: %02x\n", drive->status);
#endif
if (!ide_end_request(drive, rq, 1))
return ide_stopped;
}
/* still data left to transfer */
ide_set_handler(drive, task_in_intr, WAIT_CMD, NULL);
return ide_started;
}
/*
* Handler for command with PIO data-out phase
*/
static ide_startstop_t task_out_intr(struct ata_device *drive, struct request *rq)
{
char *buf = NULL;
unsigned long flags;
if (!ata_status(drive, DRIVE_READY, drive->bad_wstat))
return ata_error(drive, rq, __FUNCTION__);
if (!rq->current_nr_sectors)
if (!ide_end_request(drive, rq, 1))
return ide_stopped;
if ((rq->nr_sectors == 1) != (drive->status & DRQ_STAT)) {
buf = ide_map_rq(rq, &flags);
#if 0
printk("write: %p, rq->current_nr_sectors: %d\n", buf, (int) rq->current_nr_sectors);
#endif
ata_write(drive, buf, SECTOR_WORDS);
ide_unmap_rq(rq, buf, &flags);
rq->errors = 0;
rq->current_nr_sectors--;
}
ide_set_handler(drive, task_out_intr, WAIT_CMD, NULL);
return ide_started;
}
/*
* Handler for command with Read Multiple
*/
static ide_startstop_t task_mulin_intr(struct ata_device *drive, struct request *rq)
{
char *buf = NULL;
unsigned int msect, nsect;
unsigned long flags;
if (!ata_status(drive, DATA_READY, BAD_R_STAT)) {
if (drive->status & (ERR_STAT|DRQ_STAT))
return ata_error(drive, rq, __FUNCTION__);
/* no data yet, so wait for another interrupt */
ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
return ide_started;
}
/* (ks/hs): Fixed Multi-Sector transfer */
msect = drive->mult_count;
do {
nsect = rq->current_nr_sectors;
if (nsect > msect)
nsect = msect;
buf = ide_map_rq(rq, &flags);
#if 0
printk("Multiread: %p, nsect: %d , rq->current_nr_sectors: %d\n",
buf, nsect, rq->current_nr_sectors);
#endif
ata_read(drive, buf, nsect * SECTOR_WORDS);
ide_unmap_rq(rq, buf, &flags);
rq->errors = 0;
rq->current_nr_sectors -= nsect;
msect -= nsect;
if (!rq->current_nr_sectors) {
if (!ide_end_request(drive, rq, 1))
return ide_stopped;
}
} while (msect);
/*
* more data left
*/
ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
return ide_started;
}
static ide_startstop_t task_mulout_intr(struct ata_device *drive, struct request *rq)
{
int ok;
int mcount = drive->mult_count;
ide_startstop_t startstop;
/*
* FIXME: the drive->status checks here seem to be messy.
*
* (ks/hs): Handle last IRQ on multi-sector transfer,
* occurs after all data was sent in this chunk
*/
ok = ata_status(drive, DATA_READY, BAD_R_STAT);
if (!ok || !rq->nr_sectors) {
if (drive->status & (ERR_STAT | DRQ_STAT)) {
startstop = ata_error(drive, rq, __FUNCTION__);
return startstop;
}
}
if (!rq->nr_sectors) {
__ide_end_request(drive, rq, 1, rq->hard_nr_sectors);
rq->bio = NULL;
return ide_stopped;
}
if (!ok) {
/* no data yet, so wait for another interrupt */
if (!drive->channel->handler)
ide_set_handler(drive, task_mulout_intr, WAIT_CMD, NULL);
return ide_started;
}
do {
char *buffer;
int nsect = rq->current_nr_sectors;
unsigned long flags;
if (nsect > mcount)
nsect = mcount;
mcount -= nsect;
buffer = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq);
rq->sector += nsect;
rq->nr_sectors -= nsect;
rq->current_nr_sectors -= nsect;
/* Do we move to the next bio after this? */
if (!rq->current_nr_sectors) {
/* remember to fix this up /jens */
struct bio *bio = rq->bio->bi_next;
/* end early if we ran out of requests */
if (!bio) {
mcount = 0;
} else {
rq->bio = bio;
rq->current_nr_sectors = bio_iovec(bio)->bv_len >> 9;
}
}
/*
* Ok, we're all setup for the interrupt re-entering us on the
* last transfer.
*/
ata_write(drive, buffer, nsect * SECTOR_WORDS);
bio_kunmap_irq(buffer, &flags);
} while (mcount);
rq->errors = 0;
if (!drive->channel->handler)
ide_set_handler(drive, task_mulout_intr, WAIT_CMD, NULL);
return ide_started;
}
/*
* Decode with physical ATA command to use and setup associated data.
*/
static u8 get_command(struct ata_device *drive, struct ata_taskfile *ar, int cmd)
{ {
int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0; int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0;
...@@ -100,45 +317,64 @@ static u8 get_command(struct ata_device *drive, int cmd) ...@@ -100,45 +317,64 @@ static u8 get_command(struct ata_device *drive, int cmd)
if (lba48bit) { if (lba48bit) {
if (cmd == READ) { if (cmd == READ) {
if (drive->using_tcq) ar->command_type = IDE_DRIVE_TASK_IN;
if (drive->using_tcq) {
return WIN_READDMA_QUEUED_EXT; return WIN_READDMA_QUEUED_EXT;
if (drive->using_dma) } else if (drive->using_dma) {
return WIN_READDMA_EXT; return WIN_READDMA_EXT;
else if (drive->mult_count) } else if (drive->mult_count) {
ar->handler = task_mulin_intr;
return WIN_MULTREAD_EXT; return WIN_MULTREAD_EXT;
else } else {
ar->handler = task_in_intr;
return WIN_READ_EXT; return WIN_READ_EXT;
}
} else if (cmd == WRITE) { } else if (cmd == WRITE) {
if (drive->using_tcq) ar->command_type = IDE_DRIVE_TASK_RAW_WRITE;
if (drive->using_tcq) {
return WIN_WRITEDMA_QUEUED_EXT; return WIN_WRITEDMA_QUEUED_EXT;
if (drive->using_dma) } else if (drive->using_dma) {
return WIN_WRITEDMA_EXT; return WIN_WRITEDMA_EXT;
else if (drive->mult_count) } else if (drive->mult_count) {
ar->handler = task_mulout_intr;
return WIN_MULTWRITE_EXT; return WIN_MULTWRITE_EXT;
else } else {
ar->handler = task_out_intr;
return WIN_WRITE_EXT; return WIN_WRITE_EXT;
}
} }
} else { } else {
if (cmd == READ) { if (cmd == READ) {
if (drive->using_tcq) ar->command_type = IDE_DRIVE_TASK_IN;
if (drive->using_tcq) {
return WIN_READDMA_QUEUED; return WIN_READDMA_QUEUED;
if (drive->using_dma) } else if (drive->using_dma) {
return WIN_READDMA; return WIN_READDMA;
else if (drive->mult_count) } else if (drive->mult_count) {
ar->handler = task_in_intr;
return WIN_MULTREAD; return WIN_MULTREAD;
else } else {
ar->handler = task_in_intr;
return WIN_READ; return WIN_READ;
}
} else if (cmd == WRITE) { } else if (cmd == WRITE) {
if (drive->using_tcq) ar->command_type = IDE_DRIVE_TASK_RAW_WRITE;
if (drive->using_tcq) {
return WIN_WRITEDMA_QUEUED; return WIN_WRITEDMA_QUEUED;
if (drive->using_dma) } else if (drive->using_dma) {
return WIN_WRITEDMA; return WIN_WRITEDMA;
else if (drive->mult_count) } else if (drive->mult_count) {
ar->handler = task_mulout_intr;
return WIN_MULTWRITE; return WIN_MULTWRITE;
else } else {
ar->handler = task_out_intr;
return WIN_WRITE; return WIN_WRITE;
}
} }
} }
ar->handler = task_no_data_intr;
ar->command_type = IDE_DRIVE_TASK_NO_DATA;
return WIN_NOP; return WIN_NOP;
} }
...@@ -170,7 +406,7 @@ static ide_startstop_t chs_do_request(struct ata_device *drive, struct request * ...@@ -170,7 +406,7 @@ static ide_startstop_t chs_do_request(struct ata_device *drive, struct request *
args.taskfile.device_head = head; args.taskfile.device_head = head;
args.taskfile.device_head |= drive->select.all; args.taskfile.device_head |= drive->select.all;
args.cmd = get_command(drive, rq_data_dir(rq)); args.cmd = get_command(drive, &args, rq_data_dir(rq));
#ifdef DEBUG #ifdef DEBUG
printk("%s: %sing: ", drive->name, printk("%s: %sing: ", drive->name,
...@@ -181,7 +417,6 @@ static ide_startstop_t chs_do_request(struct ata_device *drive, struct request * ...@@ -181,7 +417,6 @@ static ide_startstop_t chs_do_request(struct ata_device *drive, struct request *
printk("buffer=%p\n", rq->buffer); printk("buffer=%p\n", rq->buffer);
#endif #endif
ide_cmd_type_parser(&args);
rq->special = &args; rq->special = &args;
return ata_taskfile(drive, &args, rq); return ata_taskfile(drive, &args, rq);
...@@ -211,7 +446,7 @@ static ide_startstop_t lba28_do_request(struct ata_device *drive, struct request ...@@ -211,7 +446,7 @@ static ide_startstop_t lba28_do_request(struct ata_device *drive, struct request
args.taskfile.device_head = ((block >> 8) & 0x0f); args.taskfile.device_head = ((block >> 8) & 0x0f);
args.taskfile.device_head |= drive->select.all; args.taskfile.device_head |= drive->select.all;
args.cmd = get_command(drive, rq_data_dir(rq)); args.cmd = get_command(drive, &args, rq_data_dir(rq));
#ifdef DEBUG #ifdef DEBUG
printk("%s: %sing: ", drive->name, printk("%s: %sing: ", drive->name,
...@@ -222,7 +457,6 @@ static ide_startstop_t lba28_do_request(struct ata_device *drive, struct request ...@@ -222,7 +457,6 @@ static ide_startstop_t lba28_do_request(struct ata_device *drive, struct request
printk("buffer=%p\n", rq->buffer); printk("buffer=%p\n", rq->buffer);
#endif #endif
ide_cmd_type_parser(&args);
rq->special = &args; rq->special = &args;
return ata_taskfile(drive, &args, rq); return ata_taskfile(drive, &args, rq);
...@@ -264,7 +498,7 @@ static ide_startstop_t lba48_do_request(struct ata_device *drive, struct request ...@@ -264,7 +498,7 @@ static ide_startstop_t lba48_do_request(struct ata_device *drive, struct request
args.hobfile.high_cylinder = (block >>= 8); /* hi lba */ args.hobfile.high_cylinder = (block >>= 8); /* hi lba */
args.hobfile.device_head = drive->select.all; args.hobfile.device_head = drive->select.all;
args.cmd = get_command(drive, rq_data_dir(rq)); args.cmd = get_command(drive, &args, rq_data_dir(rq));
#ifdef DEBUG #ifdef DEBUG
printk("%s: %sing: ", drive->name, printk("%s: %sing: ", drive->name,
...@@ -275,7 +509,6 @@ static ide_startstop_t lba48_do_request(struct ata_device *drive, struct request ...@@ -275,7 +509,6 @@ static ide_startstop_t lba48_do_request(struct ata_device *drive, struct request
printk("buffer=%p\n",rq->buffer); printk("buffer=%p\n",rq->buffer);
#endif #endif
ide_cmd_type_parser(&args);
rq->special = &args; rq->special = &args;
return ata_taskfile(drive, &args, rq); return ata_taskfile(drive, &args, rq);
...@@ -354,9 +587,9 @@ static int idedisk_open (struct inode *inode, struct file *filp, struct ata_devi ...@@ -354,9 +587,9 @@ static int idedisk_open (struct inode *inode, struct file *filp, struct ata_devi
check_disk_change(inode->i_rdev); check_disk_change(inode->i_rdev);
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
args.cmd = WIN_DOORLOCK; args.cmd = WIN_DOORLOCK;
ide_cmd_type_parser(&args); args.handler = task_no_data_intr;
args.command_type = IDE_DRIVE_TASK_NO_DATA;
/* /*
* Ignore the return code from door_lock, since the open() has * Ignore the return code from door_lock, since the open() has
...@@ -381,7 +614,8 @@ static int idedisk_flushcache(struct ata_device *drive) ...@@ -381,7 +614,8 @@ static int idedisk_flushcache(struct ata_device *drive)
else else
args.cmd = WIN_FLUSH_CACHE; args.cmd = WIN_FLUSH_CACHE;
ide_cmd_type_parser(&args); args.handler = task_no_data_intr;
args.command_type = IDE_DRIVE_TASK_NO_DATA;
return ide_raw_taskfile(drive, &args); return ide_raw_taskfile(drive, &args);
} }
...@@ -396,7 +630,8 @@ static void idedisk_release(struct inode *inode, struct file *filp, struct ata_d ...@@ -396,7 +630,8 @@ static void idedisk_release(struct inode *inode, struct file *filp, struct ata_d
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
args.cmd = WIN_DOORUNLOCK; args.cmd = WIN_DOORUNLOCK;
ide_cmd_type_parser(&args); args.handler = task_no_data_intr;
args.command_type = IDE_DRIVE_TASK_NO_DATA;
if (drive->doorlocking && if (drive->doorlocking &&
ide_raw_taskfile(drive, &args)) ide_raw_taskfile(drive, &args))
...@@ -445,7 +680,8 @@ static int set_multcount(struct ata_device *drive, int arg) ...@@ -445,7 +680,8 @@ static int set_multcount(struct ata_device *drive, int arg)
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
args.taskfile.sector_count = arg; args.taskfile.sector_count = arg;
args.cmd = WIN_SETMULT; args.cmd = WIN_SETMULT;
ide_cmd_type_parser(&args); args.handler = task_no_data_intr;
args.command_type = IDE_DRIVE_TASK_NO_DATA;
if (!ide_raw_taskfile(drive, &args)) { if (!ide_raw_taskfile(drive, &args)) {
/* all went well track this setting as valid */ /* all went well track this setting as valid */
...@@ -476,7 +712,9 @@ static int write_cache(struct ata_device *drive, int arg) ...@@ -476,7 +712,9 @@ static int write_cache(struct ata_device *drive, int arg)
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
args.taskfile.feature = (arg) ? SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE; args.taskfile.feature = (arg) ? SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
args.cmd = WIN_SETFEATURES; args.cmd = WIN_SETFEATURES;
ide_cmd_type_parser(&args); args.handler = task_no_data_intr;
args.command_type = IDE_DRIVE_TASK_NO_DATA;
ide_raw_taskfile(drive, &args); ide_raw_taskfile(drive, &args);
drive->wcache = arg; drive->wcache = arg;
...@@ -490,7 +728,8 @@ static int idedisk_standby(struct ata_device *drive) ...@@ -490,7 +728,8 @@ static int idedisk_standby(struct ata_device *drive)
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
args.cmd = WIN_STANDBYNOW1; args.cmd = WIN_STANDBYNOW1;
ide_cmd_type_parser(&args); args.handler = task_no_data_intr;
args.command_type = IDE_DRIVE_TASK_NO_DATA;
return ide_raw_taskfile(drive, &args); return ide_raw_taskfile(drive, &args);
} }
...@@ -503,7 +742,9 @@ static int set_acoustic(struct ata_device *drive, int arg) ...@@ -503,7 +742,9 @@ static int set_acoustic(struct ata_device *drive, int arg)
args.taskfile.feature = (arg)?SETFEATURES_EN_AAM:SETFEATURES_DIS_AAM; args.taskfile.feature = (arg)?SETFEATURES_EN_AAM:SETFEATURES_DIS_AAM;
args.taskfile.sector_count = arg; args.taskfile.sector_count = arg;
args.cmd = WIN_SETFEATURES; args.cmd = WIN_SETFEATURES;
ide_cmd_type_parser(&args); args.handler = task_no_data_intr;
args.command_type = IDE_DRIVE_TASK_NO_DATA;
ide_raw_taskfile(drive, &args); ide_raw_taskfile(drive, &args);
drive->acoustic = arg; drive->acoustic = arg;
......
...@@ -41,24 +41,6 @@ ...@@ -41,24 +41,6 @@
#define DTF(x...) #define DTF(x...)
#endif #endif
/*
* for now, taskfile requests are special :/
*/
static inline char *ide_map_rq(struct request *rq, unsigned long *flags)
{
if (rq->bio)
return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
else
return rq->buffer + ((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE;
}
static inline void ide_unmap_rq(struct request *rq, char *to,
unsigned long *flags)
{
if (rq->bio)
bio_kunmap_irq(to, flags);
}
/* /*
* Data transfer functions for polled IO. * Data transfer functions for polled IO.
*/ */
...@@ -195,119 +177,24 @@ int drive_is_ready(struct ata_device *drive) ...@@ -195,119 +177,24 @@ int drive_is_ready(struct ata_device *drive)
} }
/* /*
* Polling wait until the drive is ready. * Handler for commands without a data phase
*
* Stuff the first sector(s) by implicitly calling the handler driectly
* therafter.
*/ */
void ata_poll_drive_ready(struct ata_device *drive) ide_startstop_t task_no_data_intr(struct ata_device *drive, struct request *rq)
{
int i;
if (drive_is_ready(drive))
return;
/* FIXME: Replace hard-coded 100, what about error handling?
*/
for (i = 0; i < 100; ++i) {
if (drive_is_ready(drive))
break;
}
}
static ide_startstop_t pre_task_mulout_intr(struct ata_device *drive, struct request *rq)
{
struct ata_taskfile *args = rq->special;
ide_startstop_t startstop;
if (ide_wait_stat(&startstop, drive, rq, DATA_READY, drive->bad_wstat, WAIT_DRQ))
return startstop;
ata_poll_drive_ready(drive);
return args->handler(drive, rq);
}
static ide_startstop_t task_mulout_intr(struct ata_device *drive, struct request *rq)
{ {
int ok; struct ata_taskfile *ar = rq->special;
int mcount = drive->mult_count;
ide_startstop_t startstop;
/*
* FIXME: the drive->status checks here seem to be messy.
*
* (ks/hs): Handle last IRQ on multi-sector transfer,
* occurs after all data was sent in this chunk
*/
ok = ata_status(drive, DATA_READY, BAD_R_STAT);
if (!ok || !rq->nr_sectors) {
if (drive->status & (ERR_STAT | DRQ_STAT)) {
startstop = ata_error(drive, rq, __FUNCTION__);
return startstop;
}
}
if (!rq->nr_sectors) {
__ide_end_request(drive, rq, 1, rq->hard_nr_sectors);
rq->bio = NULL;
return ide_stopped;
}
if (!ok) { ide__sti(); /* local CPU only */
/* no data yet, so wait for another interrupt */
if (!drive->channel->handler)
ide_set_handler(drive, task_mulout_intr, WAIT_CMD, NULL);
return ide_started; if (!ata_status(drive, READY_STAT, BAD_STAT)) {
/* Keep quiet for NOP because it is expected to fail. */
if (ar && ar->cmd != WIN_NOP)
return ata_error(drive, rq, __FUNCTION__);
} }
do { if (ar)
char *buffer; ide_end_drive_cmd(drive, rq);
int nsect = rq->current_nr_sectors;
unsigned long flags;
if (nsect > mcount)
nsect = mcount;
mcount -= nsect;
buffer = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq);
rq->sector += nsect;
rq->nr_sectors -= nsect;
rq->current_nr_sectors -= nsect;
/* Do we move to the next bio after this? */
if (!rq->current_nr_sectors) {
/* remember to fix this up /jens */
struct bio *bio = rq->bio->bi_next;
/* end early if we ran out of requests */
if (!bio) {
mcount = 0;
} else {
rq->bio = bio;
rq->current_nr_sectors = bio_iovec(bio)->bv_len >> 9;
}
}
/*
* Ok, we're all setup for the interrupt re-entering us on the
* last transfer.
*/
ata_write(drive, buffer, nsect * SECTOR_WORDS);
bio_kunmap_irq(buffer, &flags);
} while (mcount);
rq->errors = 0;
if (!drive->channel->handler)
ide_set_handler(drive, task_mulout_intr, WAIT_CMD, NULL);
return ide_started; return ide_stopped;
} }
ide_startstop_t ata_taskfile(struct ata_device *drive, ide_startstop_t ata_taskfile(struct ata_device *drive,
...@@ -315,8 +202,11 @@ ide_startstop_t ata_taskfile(struct ata_device *drive, ...@@ -315,8 +202,11 @@ ide_startstop_t ata_taskfile(struct ata_device *drive,
{ {
struct hd_driveid *id = drive->id; struct hd_driveid *id = drive->id;
/* (ks/hs): Moved to start, do not use for multiple out commands */ /* (ks/hs): Moved to start, do not use for multiple out commands.
if (ar->handler != task_mulout_intr) { * FIXME: why not?! */
if (!(ar->cmd == CFA_WRITE_MULTI_WO_ERASE ||
ar->cmd == WIN_MULTWRITE ||
ar->cmd == WIN_MULTWRITE_EXT)) {
ata_irq_enable(drive, 1); ata_irq_enable(drive, 1);
ata_mask(drive); ata_mask(drive);
} }
...@@ -324,14 +214,12 @@ ide_startstop_t ata_taskfile(struct ata_device *drive, ...@@ -324,14 +214,12 @@ ide_startstop_t ata_taskfile(struct ata_device *drive,
if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400) && if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400) &&
(drive->addressing == 1)) (drive->addressing == 1))
ata_out_regfile(drive, &ar->hobfile); ata_out_regfile(drive, &ar->hobfile);
ata_out_regfile(drive, &ar->taskfile); ata_out_regfile(drive, &ar->taskfile);
{ OUT_BYTE((ar->taskfile.device_head & (drive->addressing ? 0xE0 : 0xEF)) | drive->select.all,
u8 HIHI = (drive->addressing) ? 0xE0 : 0xEF; IDE_SELECT_REG);
OUT_BYTE((ar->taskfile.device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
} if (ar->handler) {
if (ar->handler != NULL) {
/* This is apparently supposed to reset the wait timeout for /* This is apparently supposed to reset the wait timeout for
* the interrupt to accur. * the interrupt to accur.
...@@ -340,34 +228,90 @@ ide_startstop_t ata_taskfile(struct ata_device *drive, ...@@ -340,34 +228,90 @@ ide_startstop_t ata_taskfile(struct ata_device *drive,
ide_set_handler(drive, ar->handler, WAIT_CMD, NULL); ide_set_handler(drive, ar->handler, WAIT_CMD, NULL);
OUT_BYTE(ar->cmd, IDE_COMMAND_REG); OUT_BYTE(ar->cmd, IDE_COMMAND_REG);
/* /* FIXME: Warning check for race between handler and prehandler
* Warning check for race between handler and prehandler for * for writing first block of data. however since we are well
* writing first block of data. however since we are well
* inside the boundaries of the seek, we should be okay. * inside the boundaries of the seek, we should be okay.
*
* FIXME: Replace the switch by using a proper command_type.
*/ */
if (ar->prehandler != NULL) if (ar->cmd == CFA_WRITE_SECT_WO_ERASE ||
return ar->prehandler(drive, rq); ar->cmd == WIN_WRITE ||
ar->cmd == WIN_WRITE_EXT ||
ar->cmd == WIN_WRITE_VERIFY ||
ar->cmd == WIN_WRITE_BUFFER ||
ar->cmd == WIN_DOWNLOAD_MICROCODE ||
ar->cmd == CFA_WRITE_MULTI_WO_ERASE ||
ar->cmd == WIN_MULTWRITE ||
ar->cmd == WIN_MULTWRITE_EXT) {
ide_startstop_t startstop;
if (ide_wait_stat(&startstop, drive, rq, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
printk(KERN_ERR "%s: no DRQ after issuing %s\n",
drive->name, drive->mult_count ? "MULTWRITE" : "WRITE");
return startstop;
}
/* FIXME: This doesn't make the slightest sense.
* (ks/hs): Fixed Multi Write
*/
if (!(ar->cmd == CFA_WRITE_MULTI_WO_ERASE ||
ar->cmd == WIN_MULTWRITE ||
ar->cmd == WIN_MULTWRITE_EXT)) {
unsigned long flags;
char *buf = ide_map_rq(rq, &flags);
/* For Write_sectors we need to stuff the first sector */
ata_write(drive, buf, SECTOR_WORDS);
rq->current_nr_sectors--;
ide_unmap_rq(rq, buf, &flags);
return ide_started;
} else {
int i;
/* Polling wait until the drive is ready.
*
* Stuff the first sector(s) by calling the
* handler driectly therafter.
*
* FIXME: Replace hard-coded 100, what about
* error handling?
*/
for (i = 0; i < 100; ++i) {
if (drive_is_ready(drive))
break;
}
if (!drive_is_ready(drive)) {
printk(KERN_ERR "DISASTER WAITING TO HAPPEN!\n");
}
return ar->handler(drive, rq);
}
}
} else { } else {
/* /*
* FIXME: This is a gross hack, need to unify tcq dma proc and * FIXME: This is a gross hack, need to unify tcq dma proc and
* regular dma proc. It should now be easier. * regular dma proc. It should now be easier.
*
* FIXME: Handle the alternateives by a command type.
*/ */
if (!drive->using_dma) if (!drive->using_dma)
return ide_started; return ide_started;
/* for dma commands we don't set the handler */ /* for dma commands we don't set the handler */
if (ar->cmd == WIN_WRITEDMA if (ar->cmd == WIN_WRITEDMA ||
|| ar->cmd == WIN_WRITEDMA_EXT ar->cmd == WIN_WRITEDMA_EXT ||
|| ar->cmd == WIN_READDMA ar->cmd == WIN_READDMA ||
|| ar->cmd == WIN_READDMA_EXT) ar->cmd == WIN_READDMA_EXT)
return !udma_init(drive, rq); return !udma_init(drive, rq);
#ifdef CONFIG_BLK_DEV_IDE_TCQ #ifdef CONFIG_BLK_DEV_IDE_TCQ
else if (ar->cmd == WIN_WRITEDMA_QUEUED else if (ar->cmd == WIN_WRITEDMA_QUEUED ||
|| ar->cmd == WIN_WRITEDMA_QUEUED_EXT ar->cmd == WIN_WRITEDMA_QUEUED_EXT ||
|| ar->cmd == WIN_READDMA_QUEUED ar->cmd == WIN_READDMA_QUEUED ||
|| ar->cmd == WIN_READDMA_QUEUED_EXT) ar->cmd == WIN_READDMA_QUEUED_EXT)
return udma_tcq_taskfile(drive, rq); return udma_tcq_taskfile(drive, rq);
#endif #endif
else { else {
...@@ -379,363 +323,6 @@ ide_startstop_t ata_taskfile(struct ata_device *drive, ...@@ -379,363 +323,6 @@ ide_startstop_t ata_taskfile(struct ata_device *drive,
return ide_started; return ide_started;
} }
/*
* This is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
*/
ide_startstop_t recal_intr(struct ata_device *drive, struct request *rq)
{
if (!ata_status(drive, READY_STAT, BAD_STAT))
return ata_error(drive, rq, __FUNCTION__);
return ide_stopped;
}
/*
* Handler for commands without a data phase
*/
ide_startstop_t task_no_data_intr(struct ata_device *drive, struct request *rq)
{
struct ata_taskfile *ar = rq->special;
ide__sti(); /* local CPU only */
if (!ata_status(drive, READY_STAT, BAD_STAT)) {
/* Keep quiet for NOP because it is expected to fail. */
if (ar && ar->cmd != WIN_NOP)
return ata_error(drive, rq, __FUNCTION__);
}
if (ar)
ide_end_drive_cmd(drive, rq);
return ide_stopped;
}
/*
* Handler for command with PIO data-in phase
*/
static ide_startstop_t task_in_intr(struct ata_device *drive, struct request *rq)
{
char *buf = NULL;
unsigned long flags;
if (!ata_status(drive, DATA_READY, BAD_R_STAT)) {
if (drive->status & (ERR_STAT|DRQ_STAT))
return ata_error(drive, rq, __FUNCTION__);
if (!(drive->status & BUSY_STAT)) {
DTF("task_in_intr to Soon wait for next interrupt\n");
ide_set_handler(drive, task_in_intr, WAIT_CMD, NULL);
return ide_started;
}
}
DTF("stat: %02x\n", drive->status);
buf = ide_map_rq(rq, &flags);
DTF("Read: %p, rq->current_nr_sectors: %d\n", buf, (int) rq->current_nr_sectors);
ata_read(drive, buf, SECTOR_WORDS);
ide_unmap_rq(rq, buf, &flags);
/* First segment of the request is complete. note that this does not
* necessarily mean that the entire request is done!! this is only true
* if ide_end_request() returns 0.
*/
if (--rq->current_nr_sectors <= 0) {
DTF("Request Ended stat: %02x\n", drive->status);
if (!ide_end_request(drive, rq, 1))
return ide_stopped;
}
/* still data left to transfer */
ide_set_handler(drive, task_in_intr, WAIT_CMD, NULL);
return ide_started;
}
static ide_startstop_t pre_task_out_intr(struct ata_device *drive, struct request *rq)
{
struct ata_taskfile *args = rq->special;
ide_startstop_t startstop;
if (ide_wait_stat(&startstop, drive, rq, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name, drive->mult_count ? "MULTWRITE" : "WRITE");
return startstop;
}
/* (ks/hs): Fixed Multi Write */
if ((args->cmd != WIN_MULTWRITE) &&
(args->cmd != WIN_MULTWRITE_EXT)) {
unsigned long flags;
char *buf = ide_map_rq(rq, &flags);
/* For Write_sectors we need to stuff the first sector */
ata_write(drive, buf, SECTOR_WORDS);
rq->current_nr_sectors--;
ide_unmap_rq(rq, buf, &flags);
} else {
ata_poll_drive_ready(drive);
return args->handler(drive, rq);
}
return ide_started;
}
/*
* Handler for command with PIO data-out phase
*/
static ide_startstop_t task_out_intr(struct ata_device *drive, struct request *rq)
{
char *buf = NULL;
unsigned long flags;
if (!ata_status(drive, DRIVE_READY, drive->bad_wstat))
return ata_error(drive, rq, __FUNCTION__);
if (!rq->current_nr_sectors)
if (!ide_end_request(drive, rq, 1))
return ide_stopped;
if ((rq->nr_sectors == 1) != (drive->status & DRQ_STAT)) {
buf = ide_map_rq(rq, &flags);
DTF("write: %p, rq->current_nr_sectors: %d\n", buf, (int) rq->current_nr_sectors);
ata_write(drive, buf, SECTOR_WORDS);
ide_unmap_rq(rq, buf, &flags);
rq->errors = 0;
rq->current_nr_sectors--;
}
ide_set_handler(drive, task_out_intr, WAIT_CMD, NULL);
return ide_started;
}
/*
* Handler for command with Read Multiple
*/
static ide_startstop_t task_mulin_intr(struct ata_device *drive, struct request *rq)
{
char *buf = NULL;
unsigned int msect, nsect;
unsigned long flags;
if (!ata_status(drive, DATA_READY, BAD_R_STAT)) {
if (drive->status & (ERR_STAT|DRQ_STAT))
return ata_error(drive, rq, __FUNCTION__);
/* no data yet, so wait for another interrupt */
ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
return ide_started;
}
/* (ks/hs): Fixed Multi-Sector transfer */
msect = drive->mult_count;
do {
nsect = rq->current_nr_sectors;
if (nsect > msect)
nsect = msect;
buf = ide_map_rq(rq, &flags);
DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %d\n",
buf, nsect, rq->current_nr_sectors);
ata_read(drive, buf, nsect * SECTOR_WORDS);
ide_unmap_rq(rq, buf, &flags);
rq->errors = 0;
rq->current_nr_sectors -= nsect;
msect -= nsect;
if (!rq->current_nr_sectors) {
if (!ide_end_request(drive, rq, 1))
return ide_stopped;
}
} while (msect);
/*
* more data left
*/
ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
return ide_started;
}
/* Called to figure out the type of command being called.
*/
void ide_cmd_type_parser(struct ata_taskfile *ar)
{
struct hd_drive_task_hdr *taskfile = &ar->taskfile;
ar->prehandler = NULL;
ar->handler = NULL;
switch (ar->cmd) {
case WIN_IDENTIFY:
case WIN_PIDENTIFY:
case CFA_TRANSLATE_SECTOR:
case WIN_READ:
case WIN_READ_EXT:
case WIN_READ_BUFFER:
ar->handler = task_in_intr;
ar->command_type = IDE_DRIVE_TASK_IN;
return;
case CFA_WRITE_SECT_WO_ERASE:
case WIN_WRITE:
case WIN_WRITE_EXT:
case WIN_WRITE_VERIFY:
case WIN_WRITE_BUFFER:
case WIN_DOWNLOAD_MICROCODE:
ar->prehandler = pre_task_out_intr;
ar->handler = task_out_intr;
ar->command_type = IDE_DRIVE_TASK_RAW_WRITE;
return;
case WIN_MULTREAD:
case WIN_MULTREAD_EXT:
ar->handler = task_mulin_intr;
ar->command_type = IDE_DRIVE_TASK_IN;
return;
case CFA_WRITE_MULTI_WO_ERASE:
case WIN_MULTWRITE:
case WIN_MULTWRITE_EXT:
ar->prehandler = pre_task_mulout_intr;
ar->handler = task_mulout_intr;
ar->command_type = IDE_DRIVE_TASK_RAW_WRITE;
return;
case WIN_SECURITY_DISABLE:
case WIN_SECURITY_ERASE_UNIT:
case WIN_SECURITY_SET_PASS:
case WIN_SECURITY_UNLOCK:
ar->handler = task_out_intr;
ar->command_type = IDE_DRIVE_TASK_OUT;
return;
case WIN_SMART:
if (taskfile->feature == SMART_WRITE_LOG_SECTOR)
ar->prehandler = pre_task_out_intr;
ar->taskfile.low_cylinder = SMART_LCYL_PASS;
ar->taskfile.high_cylinder = SMART_HCYL_PASS;
switch(ar->taskfile.feature) {
case SMART_READ_VALUES:
case SMART_READ_THRESHOLDS:
case SMART_READ_LOG_SECTOR:
ar->handler = task_in_intr;
ar->command_type = IDE_DRIVE_TASK_IN;
return;
case SMART_WRITE_LOG_SECTOR:
ar->handler = task_out_intr;
ar->command_type = IDE_DRIVE_TASK_OUT;
return;
default:
ar->handler = task_no_data_intr;
ar->command_type = IDE_DRIVE_TASK_NO_DATA;
return;
}
#ifdef CONFIG_BLK_DEV_IDEDMA
case WIN_READDMA:
case WIN_IDENTIFY_DMA:
case WIN_READDMA_QUEUED:
case WIN_READDMA_EXT:
case WIN_READDMA_QUEUED_EXT:
ar->command_type = IDE_DRIVE_TASK_IN;
return;
case WIN_WRITEDMA:
case WIN_WRITEDMA_QUEUED:
case WIN_WRITEDMA_EXT:
case WIN_WRITEDMA_QUEUED_EXT:
ar->command_type = IDE_DRIVE_TASK_RAW_WRITE;
return;
#endif
case WIN_SETFEATURES:
ar->handler = task_no_data_intr;
switch (ar->taskfile.feature) {
case SETFEATURES_XFER:
ar->command_type = IDE_DRIVE_TASK_SET_XFER;
return;
case SETFEATURES_DIS_DEFECT:
case SETFEATURES_EN_APM:
case SETFEATURES_DIS_MSN:
case SETFEATURES_EN_RI:
case SETFEATURES_EN_SI:
case SETFEATURES_DIS_RPOD:
case SETFEATURES_DIS_WCACHE:
case SETFEATURES_EN_DEFECT:
case SETFEATURES_DIS_APM:
case SETFEATURES_EN_MSN:
case SETFEATURES_EN_RLA:
case SETFEATURES_PREFETCH:
case SETFEATURES_EN_RPOD:
case SETFEATURES_DIS_RI:
case SETFEATURES_DIS_SI:
default:
ar->command_type = IDE_DRIVE_TASK_NO_DATA;
return;
}
case WIN_SPECIFY:
ar->handler = task_no_data_intr;
ar->command_type = IDE_DRIVE_TASK_NO_DATA;
return;
case WIN_RESTORE:
ar->handler = recal_intr;
ar->command_type = IDE_DRIVE_TASK_NO_DATA;
return;
case WIN_DIAGNOSE:
case WIN_FLUSH_CACHE:
case WIN_FLUSH_CACHE_EXT:
case WIN_STANDBYNOW1:
case WIN_STANDBYNOW2:
case WIN_SLEEPNOW1:
case WIN_SLEEPNOW2:
case WIN_SETIDLE1:
case WIN_CHECKPOWERMODE1:
case WIN_CHECKPOWERMODE2:
case WIN_GETMEDIASTATUS:
case WIN_MEDIAEJECT:
case CFA_REQ_EXT_ERROR_CODE:
case CFA_ERASE_SECTORS:
case WIN_VERIFY:
case WIN_VERIFY_EXT:
case WIN_SEEK:
case WIN_READ_NATIVE_MAX:
case WIN_SET_MAX:
case WIN_READ_NATIVE_MAX_EXT:
case WIN_SET_MAX_EXT:
case WIN_SECURITY_ERASE_PREPARE:
case WIN_SECURITY_FREEZE_LOCK:
case WIN_DOORLOCK:
case WIN_DOORUNLOCK:
case DISABLE_SEAGATE:
case EXABYTE_ENABLE_NEST:
case WIN_SETMULT:
case WIN_NOP:
ar->handler = task_no_data_intr;
ar->command_type = IDE_DRIVE_TASK_NO_DATA;
return;
case WIN_FORMAT:
case WIN_INIT:
case WIN_DEVICE_RESET:
case WIN_QUEUED_SERVICE:
case WIN_PACKETCMD:
default:
ar->command_type = IDE_DRIVE_TASK_INVALID;
return;
}
}
/* /*
* This function issues a special IDE device request onto the request queue. * This function issues a special IDE device request onto the request queue.
* *
...@@ -813,8 +400,6 @@ EXPORT_SYMBOL(drive_is_ready); ...@@ -813,8 +400,6 @@ EXPORT_SYMBOL(drive_is_ready);
EXPORT_SYMBOL(ata_read); EXPORT_SYMBOL(ata_read);
EXPORT_SYMBOL(ata_write); EXPORT_SYMBOL(ata_write);
EXPORT_SYMBOL(ata_taskfile); EXPORT_SYMBOL(ata_taskfile);
EXPORT_SYMBOL(recal_intr);
EXPORT_SYMBOL(task_no_data_intr); EXPORT_SYMBOL(task_no_data_intr);
EXPORT_SYMBOL(ide_do_drive_cmd); EXPORT_SYMBOL(ide_do_drive_cmd);
EXPORT_SYMBOL(ide_raw_taskfile); EXPORT_SYMBOL(ide_raw_taskfile);
EXPORT_SYMBOL(ide_cmd_type_parser);
...@@ -67,9 +67,6 @@ ...@@ -67,9 +67,6 @@
#include "pcihost.h" #include "pcihost.h"
#include "ioctl.h" #include "ioctl.h"
/* default maximum number of failures */
#define IDE_DEFAULT_MAX_FAILURES 1
/* /*
* CompactFlash cards and their relatives pretend to be removable hard disks, except: * CompactFlash cards and their relatives pretend to be removable hard disks, except:
* (1) they never have a slave unit, and * (1) they never have a slave unit, and
...@@ -554,6 +551,19 @@ static void try_to_flush_leftover_data(struct ata_device *drive) ...@@ -554,6 +551,19 @@ static void try_to_flush_leftover_data(struct ata_device *drive)
# define IS_PDC4030_DRIVE (0) /* auto-NULLs out pdc4030 code */ # define IS_PDC4030_DRIVE (0) /* auto-NULLs out pdc4030 code */
#endif #endif
/*
* This is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
*
* FIXME: Why can't be just use task_no_data_intr here?
*/
static ide_startstop_t recal_intr(struct ata_device *drive, struct request *rq)
{
if (!ata_status(drive, READY_STAT, BAD_STAT))
return ata_error(drive, rq, __FUNCTION__);
return ide_stopped;
}
/* /*
* We are still on the old request path here so issuing the recalibrate command * We are still on the old request path here so issuing the recalibrate command
* directly should just work. * directly should just work.
...@@ -572,6 +582,7 @@ static int do_recalibrate(struct ata_device *drive) ...@@ -572,6 +582,7 @@ static int do_recalibrate(struct ata_device *drive)
args.taskfile.sector_count = drive->sect; args.taskfile.sector_count = drive->sect;
args.cmd = WIN_RESTORE; args.cmd = WIN_RESTORE;
args.handler = recal_intr; args.handler = recal_intr;
args.command_type = IDE_DRIVE_TASK_NO_DATA;
ata_taskfile(drive, &args, NULL); ata_taskfile(drive, &args, NULL);
} }
......
...@@ -150,19 +150,22 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned ...@@ -150,19 +150,22 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
* configuration. * configuration.
*/ */
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
switch (cmd) { switch (cmd) {
case HDIO_GET_32BIT: { case HDIO_GET_32BIT: {
unsigned long val = drive->channel->io_32bit; unsigned long val = drive->channel->io_32bit;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (put_user(val, (unsigned long *) arg)) if (put_user(val, (unsigned long *) arg))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
case HDIO_SET_32BIT: case HDIO_SET_32BIT:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (arg < 0 || arg > 1) if (arg < 0 || arg > 1)
return -EINVAL; return -EINVAL;
...@@ -178,6 +181,9 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned ...@@ -178,6 +181,9 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
return 0; return 0;
case HDIO_SET_PIO_MODE: case HDIO_SET_PIO_MODE:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (arg < 0 || arg > 255) if (arg < 0 || arg > 255)
return -EINVAL; return -EINVAL;
...@@ -198,6 +204,9 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned ...@@ -198,6 +204,9 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
case HDIO_GET_UNMASKINTR: { case HDIO_GET_UNMASKINTR: {
unsigned long val = drive->channel->unmask; unsigned long val = drive->channel->unmask;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (put_user(val, (unsigned long *) arg)) if (put_user(val, (unsigned long *) arg))
return -EFAULT; return -EFAULT;
...@@ -205,6 +214,9 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned ...@@ -205,6 +214,9 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
} }
case HDIO_SET_UNMASKINTR: case HDIO_SET_UNMASKINTR:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (arg < 0 || arg > 1) if (arg < 0 || arg > 1)
return -EINVAL; return -EINVAL;
...@@ -222,6 +234,9 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned ...@@ -222,6 +234,9 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
case HDIO_GET_DMA: { case HDIO_GET_DMA: {
unsigned long val = drive->using_dma; unsigned long val = drive->using_dma;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (put_user(val, (unsigned long *) arg)) if (put_user(val, (unsigned long *) arg))
return -EFAULT; return -EFAULT;
...@@ -229,6 +244,9 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned ...@@ -229,6 +244,9 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
} }
case HDIO_SET_DMA: case HDIO_SET_DMA:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (arg < 0 || arg > 1) if (arg < 0 || arg > 1)
return -EINVAL; return -EINVAL;
...@@ -250,6 +268,9 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned ...@@ -250,6 +268,9 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
struct hd_geometry *loc = (struct hd_geometry *) arg; struct hd_geometry *loc = (struct hd_geometry *) arg;
unsigned short bios_cyl = drive->bios_cyl; /* truncate */ unsigned short bios_cyl = drive->bios_cyl; /* truncate */
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (!loc || (drive->type != ATA_DISK && drive->type != ATA_FLOPPY)) if (!loc || (drive->type != ATA_DISK && drive->type != ATA_FLOPPY))
return -EINVAL; return -EINVAL;
...@@ -272,6 +293,9 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned ...@@ -272,6 +293,9 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
case HDIO_GETGEO_BIG_RAW: { case HDIO_GETGEO_BIG_RAW: {
struct hd_big_geometry *loc = (struct hd_big_geometry *) arg; struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (!loc || (drive->type != ATA_DISK && drive->type != ATA_FLOPPY)) if (!loc || (drive->type != ATA_DISK && drive->type != ATA_FLOPPY))
return -EINVAL; return -EINVAL;
...@@ -292,6 +316,9 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned ...@@ -292,6 +316,9 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
} }
case HDIO_GET_IDENTITY: case HDIO_GET_IDENTITY:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (minor(inode->i_rdev) & PARTN_MASK) if (minor(inode->i_rdev) & PARTN_MASK)
return -EINVAL; return -EINVAL;
...@@ -304,11 +331,17 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned ...@@ -304,11 +331,17 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
return 0; return 0;
case HDIO_GET_NICE: case HDIO_GET_NICE:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
return put_user(drive->dsc_overlap << IDE_NICE_DSC_OVERLAP | return put_user(drive->dsc_overlap << IDE_NICE_DSC_OVERLAP |
drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP, drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP,
(long *) arg); (long *) arg);
case HDIO_SET_NICE: case HDIO_SET_NICE:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP)))) if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP))))
return -EPERM; return -EPERM;
...@@ -322,18 +355,27 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned ...@@ -322,18 +355,27 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
return 0; return 0;
case HDIO_GET_BUSSTATE: case HDIO_GET_BUSSTATE:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (put_user(drive->channel->bus_state, (long *)arg)) if (put_user(drive->channel->bus_state, (long *)arg))
return -EFAULT; return -EFAULT;
return 0; return 0;
case HDIO_SET_BUSSTATE: case HDIO_SET_BUSSTATE:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (drive->channel->busproc) if (drive->channel->busproc)
drive->channel->busproc(drive, (int)arg); drive->channel->busproc(drive, (int)arg);
return 0; return 0;
case HDIO_DRIVE_CMD: case HDIO_DRIVE_CMD:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (!arg) { if (!arg) {
if (ide_spin_wait_hwgroup(drive)) if (ide_spin_wait_hwgroup(drive))
return -EBUSY; return -EBUSY;
......
...@@ -406,7 +406,8 @@ static int check_autopoll(struct ata_device *drive) ...@@ -406,7 +406,8 @@ static int check_autopoll(struct ata_device *drive)
args.taskfile.feature = 0x01; args.taskfile.feature = 0x01;
args.cmd = WIN_NOP; args.cmd = WIN_NOP;
ide_cmd_type_parser(&args); args.handler = task_no_data_intr;
args.command_type = IDE_DRIVE_TASK_NO_DATA;
/* /*
* do taskfile and check ABRT bit -- intelligent adapters will not * do taskfile and check ABRT bit -- intelligent adapters will not
...@@ -441,7 +442,8 @@ static int configure_tcq(struct ata_device *drive) ...@@ -441,7 +442,8 @@ static int configure_tcq(struct ata_device *drive)
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
args.taskfile.feature = SETFEATURES_EN_WCACHE; args.taskfile.feature = SETFEATURES_EN_WCACHE;
args.cmd = WIN_SETFEATURES; args.cmd = WIN_SETFEATURES;
ide_cmd_type_parser(&args); args.handler = task_no_data_intr;
args.command_type = IDE_DRIVE_TASK_NO_DATA;
if (ide_raw_taskfile(drive, &args)) { if (ide_raw_taskfile(drive, &args)) {
printk("%s: failed to enable write cache\n", drive->name); printk("%s: failed to enable write cache\n", drive->name);
...@@ -455,7 +457,8 @@ static int configure_tcq(struct ata_device *drive) ...@@ -455,7 +457,8 @@ static int configure_tcq(struct ata_device *drive)
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
args.taskfile.feature = SETFEATURES_DIS_RI; args.taskfile.feature = SETFEATURES_DIS_RI;
args.cmd = WIN_SETFEATURES; args.cmd = WIN_SETFEATURES;
ide_cmd_type_parser(&args); args.handler = task_no_data_intr;
args.command_type = IDE_DRIVE_TASK_NO_DATA;
if (ide_raw_taskfile(drive, &args)) { if (ide_raw_taskfile(drive, &args)) {
printk("%s: disabling release interrupt fail\n", drive->name); printk("%s: disabling release interrupt fail\n", drive->name);
...@@ -469,7 +472,8 @@ static int configure_tcq(struct ata_device *drive) ...@@ -469,7 +472,8 @@ static int configure_tcq(struct ata_device *drive)
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
args.taskfile.feature = SETFEATURES_EN_SI; args.taskfile.feature = SETFEATURES_EN_SI;
args.cmd = WIN_SETFEATURES; args.cmd = WIN_SETFEATURES;
ide_cmd_type_parser(&args); args.handler = task_no_data_intr;
args.command_type = IDE_DRIVE_TASK_NO_DATA;
if (ide_raw_taskfile(drive, &args)) { if (ide_raw_taskfile(drive, &args)) {
printk("%s: enabling service interrupt fail\n", drive->name); printk("%s: enabling service interrupt fail\n", drive->name);
......
...@@ -664,7 +664,6 @@ struct ata_taskfile { ...@@ -664,7 +664,6 @@ struct ata_taskfile {
struct hd_drive_task_hdr hobfile; struct hd_drive_task_hdr hobfile;
u8 cmd; /* actual ATA command */ u8 cmd; /* actual ATA command */
int command_type; int command_type;
ide_startstop_t (*prehandler)(struct ata_device *, struct request *);
ide_startstop_t (*handler)(struct ata_device *, struct request *); ide_startstop_t (*handler)(struct ata_device *, struct request *);
}; };
...@@ -678,17 +677,31 @@ extern ide_startstop_t ata_taskfile(struct ata_device *, ...@@ -678,17 +677,31 @@ extern ide_startstop_t ata_taskfile(struct ata_device *,
* Special Flagged Register Validation Caller * Special Flagged Register Validation Caller
*/ */
extern ide_startstop_t recal_intr(struct ata_device *, struct request *); /*
extern ide_startstop_t task_no_data_intr(struct ata_device *, struct request *); * for now, taskfile requests are special :/
*/
static inline char *ide_map_rq(struct request *rq, unsigned long *flags)
{
if (rq->bio)
return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
else
return rq->buffer + ((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE;
}
extern void ide_cmd_type_parser(struct ata_taskfile *args); static inline void ide_unmap_rq(struct request *rq, char *to,
unsigned long *flags)
{
if (rq->bio)
bio_kunmap_irq(to, flags);
}
extern ide_startstop_t task_no_data_intr(struct ata_device *, struct request *);
extern int ide_raw_taskfile(struct ata_device *, struct ata_taskfile *); extern int ide_raw_taskfile(struct ata_device *, struct ata_taskfile *);
extern void ide_fix_driveid(struct hd_driveid *id); extern void ide_fix_driveid(struct hd_driveid *id);
extern int ide_config_drive_speed(struct ata_device *, byte); extern int ide_config_drive_speed(struct ata_device *, byte);
extern byte eighty_ninty_three(struct ata_device *); extern byte eighty_ninty_three(struct ata_device *);
extern void ide_stall_queue(struct ata_device *, unsigned long); extern void ide_stall_queue(struct ata_device *, unsigned long);
extern int system_bus_speed; extern int system_bus_speed;
......
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