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)
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)
{
/*
......@@ -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_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_82801CA_10, pci_fixup_ide_exbar },
{ 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_82801DB_9, 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_trash },
{ 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_8622, 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 @@
* I think the code should be pretty understandable,
* 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
* I threw it in.
*
......@@ -37,12 +37,6 @@
#include <linux/types.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/init.h>
......@@ -52,12 +46,14 @@
/* port addresses for auto-detection */
#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 */
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},
{0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f},
{0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
......@@ -68,37 +64,37 @@ static RegInitializer initData[] __initdata = {
};
/* timing parameter registers for each drive */
static struct { byte reg1, reg2, reg3, reg4; } regTab[4] = {
{0x03, 0x26, 0x04, 0x27}, /* drive 0 */
{0x05, 0x28, 0x06, 0x29}, /* drive 1 */
{0x2b, 0x30, 0x2c, 0x31}, /* drive 2 */
{0x2d, 0x32, 0x2e, 0x33}, /* drive 3 */
static struct {
u8 reg1, reg2, reg3, reg4;
} reg_tab[4] = {
{ 0x03, 0x26, 0x04, 0x27 }, /* drive 0 */
{ 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 regPort; /* port for register number */
static int dataPort; /* port for register data */
static byte regOn; /* output to base port to access registers */
static byte regOff; /* output to base port to close registers */
/*------------------------------------------------------------------------*/
static int base_port; /* base port address */
static int reg_port; /* port for register number */
static int data_port; /* port for register data */
static u8 reg_on; /* output to base port to access registers */
static u8 reg_off; /* output to base port to close registers */
/*
* Read a controller register.
*/
static inline byte inReg (byte reg)
static inline u8 in_reg(u8 reg)
{
outb_p(reg, regPort);
return inb(dataPort);
outb_p(reg, reg_port);
return inb(data_port);
}
/*
* 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(data, dataPort);
outb_p(reg, reg_port);
outb_p(data, data_port);
}
/*
......@@ -108,7 +104,7 @@ static void outReg (byte data, byte reg)
*/
static void ali14xx_tune_drive(struct ata_device *drive, u8 pio)
{
int driveNum;
int drive_num;
int time1, time2;
u8 param1, param2, param3, param4;
unsigned long flags;
......@@ -117,7 +113,7 @@ static void ali14xx_tune_drive(struct ata_device *drive, u8 pio)
if (pio == 255)
pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO);
else
pio = XFER_PIO_0 + min_t(byte, pio, 4);
pio = XFER_PIO_0 + min_t(u8, pio, 4);
t = ata_timing_data(pio);
......@@ -130,50 +126,50 @@ static void ali14xx_tune_drive(struct ata_device *drive, u8 pio)
param3 += 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);
/* 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 */
cli(); /* all CPUs */
outb_p(regOn, basePort);
outReg(param1, regTab[driveNum].reg1);
outReg(param2, regTab[driveNum].reg2);
outReg(param3, regTab[driveNum].reg3);
outReg(param4, regTab[driveNum].reg4);
outb_p(regOff, basePort);
outb_p(reg_on, base_port);
out_reg(param1, reg_tab[drive_num].reg1);
out_reg(param2, reg_tab[drive_num].reg2);
out_reg(param3, reg_tab[drive_num].reg3);
out_reg(param4, reg_tab[drive_num].reg4);
outb_p(reg_off, base_port);
restore_flags(flags); /* all CPUs */
}
/*
* Auto-detect the IDE controller port.
*/
static int __init findPort (void)
static int __init find_port(void)
{
int i;
byte t;
unsigned long flags;
__save_flags(flags); /* local CPU only */
__cli(); /* local CPU only */
for (i = 0; i < ALI_NUM_PORTS; ++i) {
basePort = ports[i];
regOff = inb(basePort);
for (regOn = 0x30; regOn <= 0x33; ++regOn) {
outb_p(regOn, basePort);
if (inb(basePort) == regOn) {
regPort = basePort + 4;
dataPort = basePort + 8;
t = inReg(0) & 0xf0;
outb_p(regOff, basePort);
for (i = 0; i < ALI_NUM_PORTS; i++) {
base_port = ports[i];
reg_off = inb(base_port);
for (reg_on = 0x30; reg_on <= 0x33; reg_on++) {
outb_p(reg_on, base_port);
if (inb(base_port) == reg_on) {
u8 t;
reg_port = base_port + 4;
data_port = base_port + 8;
t = in_reg(0) & 0xf0;
outb_p(reg_off, base_port);
__restore_flags(flags); /* local CPU only */
if (t != 0x50)
return 0;
return 1; /* success */
}
}
outb_p(regOff, basePort);
outb_p(reg_off, base_port);
}
__restore_flags(flags); /* local CPU only */
return 0;
......@@ -182,32 +178,34 @@ static int __init findPort (void)
/*
* Initialize controller registers with default values.
*/
static int __init initRegisters (void) {
RegInitializer *p;
byte t;
static int __init init_registers(void)
{
struct reg_initializer *p;
unsigned long flags;
u8 t;
__save_flags(flags); /* local CPU only */
__cli(); /* local CPU only */
outb_p(regOn, basePort);
for (p = initData; p->reg != 0; ++p)
outReg(p->data, p->reg);
outb_p(0x01, regPort);
t = inb(regPort) & 0x01;
outb_p(regOff, basePort);
outb_p(reg_on, base_port);
for (p = init_data; p->reg != 0; ++p)
out_reg(p->data, p->reg);
outb_p(0x01, reg_port);
t = inb(reg_port) & 0x01;
outb_p(reg_off, base_port);
__restore_flags(flags); /* local CPU only */
return t;
}
void __init init_ali14xx (void)
void __init init_ali14xx(void)
{
/* auto-detect IDE controller port */
if (!findPort()) {
printk("\nali14xx: not found");
if (!find_port()) {
printk(KERN_ERR "ali14xx: not found\n");
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[1].chipset = ide_ali14xx;
ide_hwifs[0].tuneproc = &ali14xx_tune_drive;
......@@ -216,8 +214,8 @@ void __init init_ali14xx (void)
ide_hwifs[1].unit = ATA_SECONDARY;
/* initialize controller registers */
if (!initRegisters()) {
printk("\nali14xx: Chip initialization failed");
if (!init_registers()) {
printk(KERN_ERR "ali14xx: Chip initialization failed\n");
return;
}
}
This diff is collapsed.
This diff is collapsed.
......@@ -67,9 +67,6 @@
#include "pcihost.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:
* (1) they never have a slave unit, and
......@@ -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 */
#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
* directly should just work.
......@@ -572,6 +582,7 @@ static int do_recalibrate(struct ata_device *drive)
args.taskfile.sector_count = drive->sect;
args.cmd = WIN_RESTORE;
args.handler = recal_intr;
args.command_type = IDE_DRIVE_TASK_NO_DATA;
ata_taskfile(drive, &args, NULL);
}
......
......@@ -150,19 +150,22 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
* configuration.
*/
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
switch (cmd) {
case HDIO_GET_32BIT: {
unsigned long val = drive->channel->io_32bit;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (put_user(val, (unsigned long *) arg))
return -EFAULT;
return 0;
}
case HDIO_SET_32BIT:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (arg < 0 || arg > 1)
return -EINVAL;
......@@ -178,6 +181,9 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
return 0;
case HDIO_SET_PIO_MODE:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (arg < 0 || arg > 255)
return -EINVAL;
......@@ -198,6 +204,9 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
case HDIO_GET_UNMASKINTR: {
unsigned long val = drive->channel->unmask;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (put_user(val, (unsigned long *) arg))
return -EFAULT;
......@@ -205,6 +214,9 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
}
case HDIO_SET_UNMASKINTR:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (arg < 0 || arg > 1)
return -EINVAL;
......@@ -222,6 +234,9 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
case HDIO_GET_DMA: {
unsigned long val = drive->using_dma;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (put_user(val, (unsigned long *) arg))
return -EFAULT;
......@@ -229,6 +244,9 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
}
case HDIO_SET_DMA:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (arg < 0 || arg > 1)
return -EINVAL;
......@@ -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;
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))
return -EINVAL;
......@@ -272,6 +293,9 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
case HDIO_GETGEO_BIG_RAW: {
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))
return -EINVAL;
......@@ -292,6 +316,9 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
}
case HDIO_GET_IDENTITY:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (minor(inode->i_rdev) & PARTN_MASK)
return -EINVAL;
......@@ -304,11 +331,17 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
return 0;
case HDIO_GET_NICE:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
return put_user(drive->dsc_overlap << IDE_NICE_DSC_OVERLAP |
drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP,
(long *) arg);
case HDIO_SET_NICE:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP))))
return -EPERM;
......@@ -322,18 +355,27 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
return 0;
case HDIO_GET_BUSSTATE:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (put_user(drive->channel->bus_state, (long *)arg))
return -EFAULT;
return 0;
case HDIO_SET_BUSSTATE:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (drive->channel->busproc)
drive->channel->busproc(drive, (int)arg);
return 0;
case HDIO_DRIVE_CMD:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (!arg) {
if (ide_spin_wait_hwgroup(drive))
return -EBUSY;
......
......@@ -406,7 +406,8 @@ static int check_autopoll(struct ata_device *drive)
args.taskfile.feature = 0x01;
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
......@@ -441,7 +442,8 @@ static int configure_tcq(struct ata_device *drive)
memset(&args, 0, sizeof(args));
args.taskfile.feature = SETFEATURES_EN_WCACHE;
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)) {
printk("%s: failed to enable write cache\n", drive->name);
......@@ -455,7 +457,8 @@ static int configure_tcq(struct ata_device *drive)
memset(&args, 0, sizeof(args));
args.taskfile.feature = SETFEATURES_DIS_RI;
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)) {
printk("%s: disabling release interrupt fail\n", drive->name);
......@@ -469,7 +472,8 @@ static int configure_tcq(struct ata_device *drive)
memset(&args, 0, sizeof(args));
args.taskfile.feature = SETFEATURES_EN_SI;
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)) {
printk("%s: enabling service interrupt fail\n", drive->name);
......
......@@ -664,7 +664,6 @@ struct ata_taskfile {
struct hd_drive_task_hdr hobfile;
u8 cmd; /* actual ATA command */
int command_type;
ide_startstop_t (*prehandler)(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 *,
* 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 void ide_fix_driveid(struct hd_driveid *id);
extern int ide_config_drive_speed(struct ata_device *, byte);
extern byte eighty_ninty_three(struct ata_device *);
extern void ide_stall_queue(struct ata_device *, unsigned long);
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