X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fscsi%2Fata_piix.c;h=adad8d394992ca71e6fe79f9a2da58df2619fd0e;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=d26ee0322f6baf3647cb3de0a611f7b9d905a476;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index d26ee0322..adad8d394 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c @@ -2,6 +2,10 @@ ata_piix.c - Intel PATA/SATA controllers + Maintained by: Jeff Garzik + Please ALWAYS copy linux-ide@vger.kernel.org + on emails. + Copyright 2003-2004 Red Hat Inc Copyright 2003-2004 Jeff Garzik @@ -24,7 +28,7 @@ #include #include #include "scsi.h" -#include "hosts.h" +#include #include #define DRV_NAME "ata_piix" @@ -35,6 +39,7 @@ enum { ICH5_PMR = 0x90, /* port mapping register */ ICH5_PCS = 0x92, /* port control and status */ + PIIX_FLAG_AHCI = (1 << 28), /* AHCI possible */ PIIX_FLAG_CHECKINTR = (1 << 29), /* make sure PCI INTx enabled */ PIIX_FLAG_COMBINED = (1 << 30), /* combined mode possible */ @@ -53,6 +58,8 @@ enum { ich5_pata = 0, ich5_sata = 1, piix4_pata = 2, + ich6_sata = 3, + ich6_sata_rm = 4, }; static int piix_init_one (struct pci_dev *pdev, @@ -60,10 +67,8 @@ static int piix_init_one (struct pci_dev *pdev, static void piix_pata_phy_reset(struct ata_port *ap); static void piix_sata_phy_reset(struct ata_port *ap); -static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev, - unsigned int pio); -static void piix_set_udmamode (struct ata_port *ap, struct ata_device *adev, - unsigned int udma); +static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev); +static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev); static unsigned int in_module_init = 1; @@ -82,15 +87,9 @@ static struct pci_device_id piix_pci_tbl[] = { { 0x8086, 0x24df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, { 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, { 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata }, - - /* ICH6 operates in two modes, "looks-like-ICH5" mode, - * and enhanced mode, with queueing and other fancy stuff. - * This is distinguished by PCI class code. - */ - { 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_STORAGE_IDE << 8, 0xffff00, ich5_sata }, - { 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_STORAGE_IDE << 8, 0xffff00, ich5_sata }, + { 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata }, + { 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm }, + { 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm }, { } /* terminate list */ }; @@ -105,6 +104,7 @@ static struct pci_driver piix_pci_driver = { static Scsi_Host_Template piix_sht = { .module = THIS_MODULE, .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, @@ -123,20 +123,25 @@ static Scsi_Host_Template piix_sht = { static struct ata_port_operations piix_pata_ops = { .port_disable = ata_port_disable, .set_piomode = piix_set_piomode, - .set_udmamode = piix_set_udmamode, + .set_dmamode = piix_set_dmamode, - .tf_load = ata_tf_load_pio, - .tf_read = ata_tf_read_pio, - .check_status = ata_check_status_pio, - .exec_command = ata_exec_command_pio, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, .phy_reset = piix_pata_phy_reset, - .bmdma_start = ata_bmdma_start_pio, - .fill_sg = ata_fill_sg, + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .eng_timeout = ata_eng_timeout, .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, .port_start = ata_port_start, .port_stop = ata_port_stop, @@ -144,21 +149,24 @@ static struct ata_port_operations piix_pata_ops = { static struct ata_port_operations piix_sata_ops = { .port_disable = ata_port_disable, - .set_piomode = piix_set_piomode, - .set_udmamode = piix_set_udmamode, - .tf_load = ata_tf_load_pio, - .tf_read = ata_tf_read_pio, - .check_status = ata_check_status_pio, - .exec_command = ata_exec_command_pio, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, .phy_reset = piix_sata_phy_reset, - .bmdma_start = ata_bmdma_start_pio, - .fill_sg = ata_fill_sg, + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .eng_timeout = ata_eng_timeout, .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, .port_start = ata_port_start, .port_stop = ata_port_stop, @@ -170,7 +178,12 @@ static struct ata_port_info piix_port_info[] = { .sht = &piix_sht, .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | PIIX_FLAG_CHECKINTR, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ +#if 0 + .mwdma_mask = 0x06, /* mwdma1-2 */ +#else + .mwdma_mask = 0x00, /* mwdma broken */ +#endif .udma_mask = ATA_UDMA_MASK_40C, /* FIXME: cbl det */ .port_ops = &piix_pata_ops, }, @@ -180,8 +193,9 @@ static struct ata_port_info piix_port_info[] = { .sht = &piix_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR, - .pio_mask = 0x03, /* pio3-4 */ - .udma_mask = 0x7f, /* udma0-6 ; FIXME */ + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &piix_sata_ops, }, @@ -189,10 +203,39 @@ static struct ata_port_info piix_port_info[] = { { .sht = &piix_sht, .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ +#if 0 + .mwdma_mask = 0x06, /* mwdma1-2 */ +#else + .mwdma_mask = 0x00, /* mwdma broken */ +#endif .udma_mask = ATA_UDMA_MASK_40C, /* FIXME: cbl det */ .port_ops = &piix_pata_ops, }, + + /* ich6_sata */ + { + .sht = &piix_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | + PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR | + ATA_FLAG_SLAVE_POSS, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 */ + .port_ops = &piix_sata_ops, + }, + + /* ich6_sata_rm */ + { + .sht = &piix_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | + PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR | + ATA_FLAG_SLAVE_POSS | PIIX_FLAG_AHCI, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 */ + .port_ops = &piix_sata_ops, + }, }; static struct pci_bits piix_enable_bits[] = { @@ -266,7 +309,7 @@ static void piix_pata_phy_reset(struct ata_port *ap) /** * piix_sata_probe - Probe PCI device for present SATA devices - * @pdev: PCI device to probe + * @ap: Port associated with the PCI device we wish to probe * * Reads SATA PCI device's PCI config register Port Configuration * and Status (PCS) to determine port and device availability. @@ -321,13 +364,6 @@ static int piix_sata_probe (struct ata_port *ap) static void piix_sata_phy_reset(struct ata_port *ap) { - if (!pci_test_config_bits(ap->host_set->pdev, - &piix_enable_bits[ap->port_no])) { - ata_port_disable(ap); - printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); - return; - } - if (!piix_sata_probe(ap)) { ata_port_disable(ap); printk(KERN_INFO "ata%u: SATA port has no device.\n", ap->id); @@ -353,11 +389,11 @@ static void piix_sata_phy_reset(struct ata_port *ap) * None (inherited from caller). */ -static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev, - unsigned int pio) +static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev) { + unsigned int pio = adev->pio_mode - XFER_PIO_0; struct pci_dev *dev = ap->host_set->pdev; - unsigned int is_slave = (adev->flags & ATA_DFLAG_MASTER) ? 0 : 1; + unsigned int is_slave = (adev->devno != 0); unsigned int master_port= ap->port_no ? 0x42 : 0x40; unsigned int slave_port = 0x44; u16 master_data; @@ -394,7 +430,7 @@ static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev, } /** - * piix_set_udmamode - Initialize host controller PATA PIO timings + * piix_set_dmamode - Initialize host controller PATA PIO timings * @ap: Port whose timings we are configuring * @adev: um * @udma: udma mode, 0 - 6 @@ -405,9 +441,9 @@ static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev, * None (inherited from caller). */ -static void piix_set_udmamode (struct ata_port *ap, struct ata_device *adev, - unsigned int udma) +static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev) { + unsigned int udma = adev->dma_mode; /* FIXME: MWDMA too */ struct pci_dev *dev = ap->host_set->pdev; u8 maslave = ap->port_no ? 0x42 : 0x40; u8 speed = udma; @@ -418,16 +454,15 @@ static void piix_set_udmamode (struct ata_port *ap, struct ata_device *adev, int w_flag = 0x10 << drive_dn; int u_speed = 0; int sitre; - u16 reg4042, reg44, reg48, reg4a, reg54; - u8 reg55; + u16 reg4042, reg4a; + u8 reg48, reg54, reg55; pci_read_config_word(dev, maslave, ®4042); DPRINTK("reg4042 = 0x%04x\n", reg4042); sitre = (reg4042 & 0x4000) ? 1 : 0; - pci_read_config_word(dev, 0x44, ®44); - pci_read_config_word(dev, 0x48, ®48); + pci_read_config_byte(dev, 0x48, ®48); pci_read_config_word(dev, 0x4a, ®4a); - pci_read_config_word(dev, 0x54, ®54); + pci_read_config_byte(dev, 0x54, ®54); pci_read_config_byte(dev, 0x55, ®55); switch(speed) { @@ -438,28 +473,37 @@ static void piix_set_udmamode (struct ata_port *ap, struct ata_device *adev, case XFER_UDMA_3: case XFER_UDMA_1: u_speed = 1 << (drive_dn * 4); break; case XFER_UDMA_0: u_speed = 0 << (drive_dn * 4); break; + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: break; default: BUG(); return; } - if (!(reg48 & u_flag)) - pci_write_config_word(dev, 0x48, reg48|u_flag); - if (speed == XFER_UDMA_5) { - pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); - } else { - pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); - } - if (!(reg4a & u_speed)) { - pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); - pci_write_config_word(dev, 0x4a, reg4a|u_speed); - } - if (speed > XFER_UDMA_2) { - if (!(reg54 & v_flag)) { - pci_write_config_word(dev, 0x54, reg54|v_flag); + if (speed >= XFER_UDMA_0) { + if (!(reg48 & u_flag)) + pci_write_config_byte(dev, 0x48, reg48 | u_flag); + if (speed == XFER_UDMA_5) { + pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag); + } else { + pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); } + if ((reg4a & a_speed) != u_speed) + pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed); + if (speed > XFER_UDMA_2) { + if (!(reg54 & v_flag)) + pci_write_config_byte(dev, 0x54, reg54 | v_flag); + } else + pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); } else { - pci_write_config_word(dev, 0x54, reg54 & ~v_flag); + if (reg48 & u_flag) + pci_write_config_byte(dev, 0x48, reg48 & ~u_flag); + if (reg4a & a_speed) + pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); + if (reg54 & v_flag) + pci_write_config_byte(dev, 0x54, reg54 & ~v_flag); + if (reg55 & w_flag) + pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); } } @@ -475,6 +519,42 @@ static void pci_enable_intx(struct pci_dev *pdev) } } +#define AHCI_PCI_BAR 5 +#define AHCI_GLOBAL_CTL 0x04 +#define AHCI_ENABLE (1 << 31) +static int piix_disable_ahci(struct pci_dev *pdev) +{ + void *mmio; + unsigned long addr; + u32 tmp; + int rc = 0; + + /* BUG: pci_enable_device has not yet been called. This + * works because this device is usually set up by BIOS. + */ + + addr = pci_resource_start(pdev, AHCI_PCI_BAR); + if (!addr || !pci_resource_len(pdev, AHCI_PCI_BAR)) + return 0; + + mmio = ioremap(addr, 64); + if (!mmio) + return -ENOMEM; + + tmp = readl(mmio + AHCI_GLOBAL_CTL); + if (tmp & AHCI_ENABLE) { + tmp &= ~AHCI_ENABLE; + writel(tmp, mmio + AHCI_GLOBAL_CTL); + + tmp = readl(mmio + AHCI_GLOBAL_CTL); + if (tmp & AHCI_ENABLE) + rc = -EIO; + } + + iounmap(mmio); + return rc; +} + /** * piix_init_one - Register PIIX ATA PCI device with kernel services * @pdev: PCI device to register @@ -507,6 +587,12 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) port_info[0] = &piix_port_info[ent->driver_data]; port_info[1] = NULL; + if (port_info[0]->host_flags & PIIX_FLAG_AHCI) { + int rc = piix_disable_ahci(pdev); + if (rc) + return rc; + } + if (port_info[0]->host_flags & PIIX_FLAG_COMBINED) { u8 tmp; pci_read_config_byte(pdev, ICH5_PMR, &tmp);