Please do a bk pull bk://gkernel.bkbits.net/ALL This will update the following files: drivers/pci/quirks.c | 6 drivers/scsi/Kconfig | 18 + drivers/scsi/Makefile | 2 drivers/scsi/ahci.c | 8 drivers/scsi/ata_adma.c | 636 +++++++++++++++++++++++++++++++++++++++ drivers/scsi/ata_piix.c | 15 drivers/scsi/libata-core.c | 128 +++++++ drivers/scsi/libata-scsi.c | 409 +++++++++++++++++++++++++ drivers/scsi/libata.h | 2 drivers/scsi/pata_pdc2027x.c | 694 +++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/sata_promise.c | 56 +++ drivers/scsi/sata_via.c | 202 +++++++++--- include/linux/ata.h | 1 include/linux/libata.h | 2 include/scsi/scsi.h | 3 15 files changed, 2110 insertions(+), 72 deletions(-) through these ChangeSets: : o [libata pdc2027x] fix incorrect pio and mwdma masks o [libata pdc2027x] remove quirks and ROM enable o [libata] add driver for Promise PATA 2027x : o [libata scsi] support 12-byte passthru CDB o [libata scsi] passthru CDB check condition processing o T10/04-262 ATA pass thru - patch : o [libata sata_promise] support PATA ports on SATA controllers : o SATA support for Intel ICH7 Brad Campbell: o libata basic detection and errata for PATA->SATA bridges Jeff Garzik: o [libata] add DMA blacklist o [libata] add new driver ata_adma o [libata sata_via] add support for VT6421 SATA o [libata sata_via] minor cleanups o [libata pdc2027x] update for upstream struct device conversion o [libata sata_promise] fix merge bugs o [libata] fix build breakage o [libata] fix SATA->PATA bridge detect compile breakage o [libata] fix printk warning John W. Linville: o libata: SMART support via ATA pass-thru Tobias Lorenz: o libata-scsi: get-identity ioctl support diff -Nru a/drivers/pci/quirks.c b/drivers/pci/quirks.c --- a/drivers/pci/quirks.c 2005-01-06 23:50:11 -05:00 +++ b/drivers/pci/quirks.c 2005-01-06 23:50:11 -05:00 @@ -1144,6 +1144,10 @@ case 0x2653: ich = 6; break; + case 0x27c0: + case 0x27c4: + ich = 7; + break; default: /* we do not handle this PCI device */ return; @@ -1163,7 +1167,7 @@ else return; /* not in combined mode */ } else { - WARN_ON(ich != 6); + WARN_ON((ich != 6) && (ich != 7)); tmp &= 0x3; /* interesting bits 1:0 */ if (tmp & (1 << 0)) comb = (1 << 2); /* PATA port 0, SATA port 1 */ diff -Nru a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig --- a/drivers/scsi/Kconfig 2005-01-06 23:50:11 -05:00 +++ b/drivers/scsi/Kconfig 2005-01-06 23:50:11 -05:00 @@ -414,11 +414,19 @@ If unsure, say N. +config SCSI_ATA_ADMA + tristate "ADMA ATA support" + depends on SCSI_SATA && PCI + help + This option enables support for ADMA-standard ATA controllers. + + If unsure, say N. + config SCSI_SATA_AHCI tristate "AHCI SATA support" depends on SCSI_SATA && PCI help - This option enables support for AHCI Serial ATA. + This option enables support for AHCI-standard Serial ATA. If unsure, say N. @@ -446,6 +454,14 @@ depends on SCSI_SATA && PCI && EXPERIMENTAL help This option enables support for NVIDIA Serial ATA. + + If unsure, say N. + +config SCSI_PATA_PDC2027X + tristate "Promise PATA 2027x support" + depends on SCSI_SATA && PCI + help + This option enables support for Promise PATA pdc20268 to pdc20277 host adapters. If unsure, say N. diff -Nru a/drivers/scsi/Makefile b/drivers/scsi/Makefile --- a/drivers/scsi/Makefile 2005-01-06 23:50:11 -05:00 +++ b/drivers/scsi/Makefile 2005-01-06 23:50:11 -05:00 @@ -121,9 +121,11 @@ obj-$(CONFIG_SCSI_NSP32) += nsp32.o obj-$(CONFIG_SCSI_IPR) += ipr.o obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi/ +obj-$(CONFIG_SCSI_ATA_ADMA) += libata.o ata_adma.o obj-$(CONFIG_SCSI_SATA_AHCI) += libata.o ahci.o obj-$(CONFIG_SCSI_SATA_SVW) += libata.o sata_svw.o obj-$(CONFIG_SCSI_ATA_PIIX) += libata.o ata_piix.o +obj-$(CONFIG_SCSI_PATA_PDC2027X)+= libata.o pata_pdc2027x.o obj-$(CONFIG_SCSI_SATA_PROMISE) += libata.o sata_promise.o obj-$(CONFIG_SCSI_SATA_SIL) += libata.o sata_sil.o obj-$(CONFIG_SCSI_SATA_VIA) += libata.o sata_via.o diff -Nru a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c --- a/drivers/scsi/ahci.c 2005-01-06 23:50:11 -05:00 +++ b/drivers/scsi/ahci.c 2005-01-06 23:50:11 -05:00 @@ -239,9 +239,13 @@ static struct pci_device_id ahci_pci_tbl[] = { { PCI_VENDOR_ID_INTEL, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, + board_ahci }, /* ICH6 */ { PCI_VENDOR_ID_INTEL, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - board_ahci }, + board_ahci }, /* ICH6M */ + { PCI_VENDOR_ID_INTEL, 0x27c1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_ahci }, /* ICH7 */ + { PCI_VENDOR_ID_INTEL, 0x27c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_ahci }, /* ICH7M */ { } /* terminate list */ }; diff -Nru a/drivers/scsi/ata_adma.c b/drivers/scsi/ata_adma.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/scsi/ata_adma.c 2005-01-06 23:50:11 -05:00 @@ -0,0 +1,636 @@ + +/* + * ata_adma.c - ADMA ATA support + * + * Copyright 2004 Red Hat, Inc. + * Copyright 2004 Jeff Garzik + * + * The contents of this file are subject to the Open + * Software License version 1.1 that can be found at + * http://www.opensource.org/licenses/osl-1.1.txt and is included herein + * by reference. + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License version 2 (the "GPL") as distributed + * in the kernel source COPYING file, in which case the provisions of + * the GPL are applicable instead of the above. If you wish to allow + * the use of your version of this file only under the terms of the + * GPL and not to allow others to use your version of this file under + * the OSL, indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by the GPL. + * If you do not delete the provisions above, a recipient may use your + * version of this file under either the OSL or the GPL. + * + * Draft of the ADMA hardware specification: + * http://www.t13.org/project/d1510r1-Host-Adapter.pdf + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include +#include +#include + +#define DRV_NAME "ata_adma" +#define DRV_VERSION "0.1" + + +enum board_ids_enum { + board_adma, +}; + +enum { + ADMA_PCI_BAR = 4, + ADMA_CPB_SZ = 64, + ADMA_SGTBL_LEN = (4096 - ADMA_CPB_SZ) / 16, + ADMA_SGTBL_SZ = ADMA_SGTBL_LEN * 16, + ADMA_PORT_PRIV_DMA_SZ = ADMA_CPB_SZ + ADMA_SGTBL_SZ, + + ADMA_CTL = 0x0, + ADMA_STAT = 0x2, + ADMA_CPB_COUNT = 0x4, + ADMA_NEXT_CPB = 0xC, + + ADMA_GO = (1 << 7), + + APRD_UDMA = (1 << 4), + APRD_WRITE = (1 << 5), + APRD_END = (1 << 7), + + IRQ_PCI_ERR = (1 << 0), + IRQ_CPB_ERR = (1 << 1), + IRQ_DONE = (1 << 7), + IRQ_ERR_MASK = IRQ_CPB_ERR | IRQ_PCI_ERR, + + CPB_APRD_VALID = (1 << (2 + 16)), + CPB_IEN = (1 << (3 + 16)), + CPB_LEN_SHIFT = 24, + CPB_ERR_MASK = 0xf8, /* select err bits 7-3 */ + + ADMA_USE_CLUSTERING = 1, + + N_PORTS = 2, +}; + +struct adma_prd { + u32 addr; + u32 len; + u32 flags; + u32 next_prd; +}; + +struct adma_host_priv { + unsigned long flags; +}; + +struct adma_port_priv { + u32 *cpb; + dma_addr_t cpb_dma; + struct adma_prd *aprd; + dma_addr_t aprd_dma; +}; + +static int adma_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); +static int adma_qc_issue(struct ata_queued_cmd *qc); +static irqreturn_t adma_interrupt (int irq, void *dev_instance, struct pt_regs *regs); +static void adma_phy_reset(struct ata_port *ap); +static void adma_irq_clear(struct ata_port *ap); +static int adma_port_start(struct ata_port *ap); +static void adma_port_stop(struct ata_port *ap); +static void adma_host_stop(struct ata_host_set *host_set); +static void adma_qc_prep(struct ata_queued_cmd *qc); +static void adma_set_dmamode(struct ata_port *ap, struct ata_device *adev); + +static Scsi_Host_Template adma_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, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = ADMA_SGTBL_LEN, + .max_sectors = ATA_MAX_SECTORS, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ADMA_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .bios_param = ata_std_bios_param, +}; + +static struct ata_port_operations adma_ops = { + .port_disable = ata_port_disable, + .set_dmamode = adma_set_dmamode, + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .dev_select = ata_std_dev_select, + + .phy_reset = adma_phy_reset, + + .qc_prep = adma_qc_prep, + .qc_issue = adma_qc_issue, + + .eng_timeout = ata_eng_timeout, + + .irq_handler = adma_interrupt, + .irq_clear = adma_irq_clear, + + .port_start = adma_port_start, + .port_stop = adma_port_stop, + .host_stop = adma_host_stop, +}; + +static struct ata_port_info adma_port_info[] = { + /* board_adma */ + { + .sht = &adma_sht, + .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | + ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO, + .pio_mask = 0x03, /* pio3-4 */ + .udma_mask = 0x7f, /* udma0-6 ; FIXME */ + .port_ops = &adma_ops, + }, +}; + +static struct pci_device_id adma_pci_tbl[] = { + { } /* terminate list */ +}; + + +static struct pci_driver adma_pci_driver = { + .name = DRV_NAME, + .id_table = adma_pci_tbl, + .probe = adma_init_one, + .remove = ata_pci_remove_one, +}; + + +static inline void __iomem *adma_ctl_block(struct ata_port *ap) +{ + void __iomem *mmio = ap->host_set->mmio_base; + + if (ap->port_no == 0) + mmio += 0x80; + else + mmio += 0xA0; + + return mmio; +} + +static void adma_set_dmamode(struct ata_port *ap, struct ata_device *adev) +{ + /* FIXME: todo */ +} + +static void adma_host_stop(struct ata_host_set *host_set) +{ + struct adma_host_priv *hpriv = host_set->private_data; + kfree(hpriv); +} + +static int adma_port_start(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct adma_port_priv *pp; + int rc; + void *mem; + dma_addr_t mem_dma; + + rc = ata_port_start(ap); + if (rc) + return rc; + + pp = kmalloc(sizeof(*pp), GFP_KERNEL); + if (!pp) { + rc = -ENOMEM; + goto err_out; + } + memset(pp, 0, sizeof(*pp)); + + mem = dma_alloc_coherent(dev, ADMA_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL); + if (!mem) { + rc = -ENOMEM; + goto err_out_kfree; + } + memset(mem, 0, ADMA_PORT_PRIV_DMA_SZ); + + /* + * First item in chunk of DMA memory: + * 64-byte command parameter block (CPB) + */ + pp->cpb = mem; + pp->cpb_dma = mem_dma; + + mem += ADMA_CPB_SZ; + mem_dma += ADMA_CPB_SZ; + + /* + * Second item: block of ADMA_SGTBL_LEN s/g entries + */ + pp->aprd = mem; + pp->aprd_dma = mem_dma; + + ap->private_data = pp; + + return 0; + +err_out_kfree: + kfree(pp); +err_out: + ata_port_stop(ap); + return rc; +} + + +static void adma_port_stop(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct adma_port_priv *pp = ap->private_data; + void __iomem *mmio = adma_ctl_block(ap); + + writew(0, mmio + ADMA_CTL); + + ap->private_data = NULL; + dma_free_coherent(dev, ADMA_PORT_PRIV_DMA_SZ, pp->cpb, pp->cpb_dma); + kfree(pp); + ata_port_stop(ap); +} + +static void adma_cbl_detect(struct ata_port *ap) +{ + /* FIXME: todo */ +} + +static void adma_phy_reset(struct ata_port *ap) +{ + adma_cbl_detect(ap); + ata_port_probe(ap); + ata_bus_reset(ap); +} + +static void adma_fill_sg(struct ata_queued_cmd *qc) +{ + struct adma_port_priv *pp = qc->ap->private_data; + unsigned int i, idx; + + VPRINTK("ENTER\n"); + + idx = 0; + if (is_atapi_taskfile(&qc->tf)) { + idx = 1; + + /* FIXME: point first s/g entry to ATAPI packet */ + } + + for (i = 0; i < qc->n_elem; i++, idx++) { + u32 sg_len, addr, flags; + + addr = (u32) sg_dma_address(&qc->sg[i]); + sg_len = sg_dma_len(&qc->sg[i]); + + flags = 0; + if (qc->tf.flags & ATA_TFLAG_WRITE) + flags |= APRD_WRITE; + if (i == (qc->n_elem - 1)) + flags |= APRD_END; + if (qc->tf.protocol == ATA_PROT_DMA || + qc->tf.protocol == ATA_PROT_ATAPI_DMA) { + flags |= APRD_UDMA; + flags |= (qc->dev->dma_mode << 8); + flags |= (2 << 12); /* udma bus burst size, 512b units*/ + } else { + flags |= ((qc->dev->pio_mode - 1) << 8); + } + + pp->aprd[idx].addr = cpu_to_le32(addr); + pp->aprd[idx].len = cpu_to_le32(sg_len / 8); /* len in Qwords */ + pp->aprd[idx].flags = cpu_to_le32(flags); + + if (i == (qc->n_elem - 1)) + pp->aprd[idx].next_prd = 0; + else { + u32 tmp = (u32) pp->aprd_dma; + tmp += ((idx + 1) * 16); + pp->aprd[idx].next_prd = cpu_to_le32(tmp); + } + } +} + +enum adma_regbits { + CMDEND = (1 << 15), /* end of command list */ + WNB = (1 << 14), /* wait-not-BSY */ + IGN = (1 << 13), /* ignore this entry */ + CS1n = (1 << (4 + 8)), /* std. PATA signals follow... */ + DA2 = (1 << (2 + 8)), + DA1 = (1 << (1 + 8)), + DA0 = (1 << (0 + 8)), +}; + +static const u16 adma_regaddr[] = { + CS1n, /* ATA_REG_DATA */ + CS1n | DA0, /* ATA_REG_ERR */ + CS1n | DA1, /* ATA_REG_NSECT */ + CS1n | DA1 | DA0, /* ATA_REG_LBAL */ + CS1n | DA2, /* ATA_REG_LBAM */ + CS1n | DA2 | DA0, /* ATA_REG_LBAH */ + CS1n | DA2 | DA1, /* ATA_REG_DEVICE */ + CS1n | DA2 | DA1 | DA0, /* ATA_REG_STATUS */ +}; + +static unsigned int adma_tf_to_cpb(struct ata_taskfile *tf, u16 *cpb) +{ + unsigned int idx = 0; + + cpb[idx++] = cpu_to_le16(WNB | adma_regaddr[ATA_REG_ERR] | tf->feature); + cpb[idx++] = cpu_to_le16(adma_regaddr[ATA_REG_NSECT] | tf->nsect); + cpb[idx++] = cpu_to_le16(adma_regaddr[ATA_REG_LBAL] | tf->lbal); + cpb[idx++] = cpu_to_le16(adma_regaddr[ATA_REG_LBAM] | tf->lbam); + cpb[idx++] = cpu_to_le16(adma_regaddr[ATA_REG_LBAM] | tf->lbah); + + if ((tf->flags & ATA_TFLAG_LBA48) == 0) { + cpb[idx++] = cpu_to_le16(IGN); + cpb[idx++] = cpu_to_le16(IGN); + cpb[idx++] = cpu_to_le16(IGN | CMDEND); + return idx; + } + + cpb[idx++] = cpu_to_le16(adma_regaddr[ATA_REG_ERR] | tf->hob_feature); + cpb[idx++] = cpu_to_le16(adma_regaddr[ATA_REG_NSECT] | tf->hob_nsect); + cpb[idx++] = cpu_to_le16(adma_regaddr[ATA_REG_LBAL] | tf->hob_lbal); + cpb[idx++] = cpu_to_le16(adma_regaddr[ATA_REG_LBAM] | tf->hob_lbam); + cpb[idx++] = cpu_to_le16(adma_regaddr[ATA_REG_LBAM] | tf->hob_lbah); + cpb[idx++] = cpu_to_le16(IGN); + cpb[idx++] = cpu_to_le16(IGN | CMDEND); + + return idx; +} + +static void adma_qc_prep(struct ata_queued_cmd *qc) +{ + struct adma_port_priv *pp = qc->ap->private_data; + u32 flags, *cpb = pp->cpb; + u16 *cpb16; + unsigned int cpb_used; + + cpb[0] = cpu_to_le32(1); + cpb[1] = cpu_to_le32((u32) pp->cpb_dma); + cpb[2] = cpu_to_le32((u32) pp->aprd_dma); + cpb[3] = 0; + + cpb16 = (u16 *) &cpb[4]; + cpb_used = adma_tf_to_cpb(&qc->tf, cpb16); + + flags = CPB_APRD_VALID | CPB_IEN; + flags |= (cpb_used / 4) << CPB_LEN_SHIFT; + + cpb[0] = cpu_to_le32(flags); + + if (!(qc->flags & ATA_QCFLAG_DMAMAP)) + return; + + adma_fill_sg(qc); +} + +static inline void adma_complete (struct ata_port *ap, + struct ata_queued_cmd *qc, int have_err) +{ + /* get drive status; clear intr; complete txn */ + ata_qc_complete(ata_qc_from_tag(ap, ap->active_tag), + have_err ? ATA_ERR : 0); +} + +static inline int adma_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc) +{ + void __iomem *mmio = adma_ctl_block(ap); + struct adma_port_priv *pp = ap->private_data; + u8 status; + int have_err; + + /* reading clears all flagged events */ + status = readb(mmio + ADMA_STAT); + status &= ~(1 << 2); /* mask out reserved bit */ + if (!status) + return 0; /* no irq handled */ + + if (status & IRQ_ERR_MASK) + have_err = 1; + else if (le32_to_cpu(pp->cpb[0]) & CPB_ERR_MASK) + have_err = 1; + else + have_err = 0; + + adma_complete(ap, qc, have_err); + + return 1; /* irq handled */ +} + +static void adma_irq_clear(struct ata_port *ap) +{ + /* TODO */ +} + +static irqreturn_t adma_interrupt (int irq, void *dev_instance, struct pt_regs *regs) +{ + struct ata_host_set *host_set = dev_instance; + struct adma_host_priv *hpriv; + unsigned int i, handled = 0; + void *mmio; + + VPRINTK("ENTER\n"); + + hpriv = host_set->private_data; + mmio = host_set->mmio_base; + + spin_lock(&host_set->lock); + + for (i = 0; i < host_set->n_ports; i++) { + struct ata_port *ap = host_set->ports[i]; + struct ata_queued_cmd *qc; + VPRINTK("port %u\n", i); + + qc = ata_qc_from_tag(ap, ap->active_tag); + if (qc) + handled |= adma_host_intr(ap, qc); + } + + spin_unlock(&host_set->lock); + + VPRINTK("EXIT\n"); + + return IRQ_RETVAL(handled); +} + +static int adma_qc_issue(struct ata_queued_cmd *qc) +{ + void __iomem *mmio = adma_ctl_block(qc->ap); + struct adma_port_priv *pp = qc->ap->private_data; + + writew(1, mmio + ADMA_CPB_COUNT); + writel((u32) pp->cpb_dma, mmio + ADMA_NEXT_CPB); + writew(ADMA_GO, mmio + ADMA_CTL); + + return 0; +} + +static void adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int port) +{ + void __iomem *mmio = probe_ent->mmio_base; + struct ata_ioports *ioport = &probe_ent->port[port]; + + if (port == 1) + mmio += 0x40; + + ioport->cmd_addr = (unsigned long) mmio; + ioport->data_addr = (unsigned long) mmio + (ATA_REG_DATA * 4); + ioport->error_addr = + ioport->feature_addr = (unsigned long) mmio + (ATA_REG_ERR * 4); + ioport->nsect_addr = (unsigned long) mmio + (ATA_REG_NSECT * 4); + ioport->lbal_addr = (unsigned long) mmio + (ATA_REG_LBAL * 4); + ioport->lbam_addr = (unsigned long) mmio + (ATA_REG_LBAM * 4); + ioport->lbah_addr = (unsigned long) mmio + (ATA_REG_LBAH * 4); + ioport->device_addr = (unsigned long) mmio + (ATA_REG_DEVICE * 4); + ioport->status_addr = + ioport->command_addr = (unsigned long) mmio + (ATA_REG_STATUS * 4); + ioport->altstatus_addr = + ioport->ctl_addr = (unsigned long) mmio + 0x38; +} + +static int adma_host_init(struct ata_probe_ent *probe_ent) +{ + struct pci_dev *pdev = to_pci_dev(probe_ent->dev); + unsigned int i; + + probe_ent->n_ports = N_PORTS; + + for (i = 0; i < probe_ent->n_ports; i++) + adma_setup_port(probe_ent, i); + + pci_set_master(pdev); + + return 0; +} + +static int adma_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int printed_version; + struct ata_probe_ent *probe_ent = NULL; + struct adma_host_priv *hpriv; + unsigned long base; + void *mmio_base; + unsigned int board_idx = (unsigned int) ent->driver_data; + int rc; + + VPRINTK("ENTER\n"); + + if (!printed_version++) + printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + + rc = pci_enable_device(pdev); + if (rc) + return rc; + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_out; + rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; + + probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) { + rc = -ENOMEM; + goto err_out_regions; + } + + memset(probe_ent, 0, sizeof(*probe_ent)); + probe_ent->dev = pci_dev_to_dev(pdev); + INIT_LIST_HEAD(&probe_ent->node); + + /* FIXME: ADMA BAR is always 64-bit... does the PCI + * layer assign that BAR4, or do we need to '|' with BAR5? + */ + mmio_base = ioremap(pci_resource_start(pdev, ADMA_PCI_BAR), + pci_resource_len(pdev, ADMA_PCI_BAR)); + if (mmio_base == NULL) { + rc = -ENOMEM; + goto err_out_free_ent; + } + base = (unsigned long) mmio_base; + + hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL); + if (!hpriv) { + rc = -ENOMEM; + goto err_out_iounmap; + } + memset(hpriv, 0, sizeof(*hpriv)); + + probe_ent->sht = adma_port_info[board_idx].sht; + probe_ent->host_flags = adma_port_info[board_idx].host_flags; + probe_ent->pio_mask = adma_port_info[board_idx].pio_mask; + probe_ent->udma_mask = adma_port_info[board_idx].udma_mask; + probe_ent->port_ops = adma_port_info[board_idx].port_ops; + + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = SA_SHIRQ; + probe_ent->mmio_base = mmio_base; + probe_ent->private_data = hpriv; + + /* initialize adapter */ + rc = adma_host_init(probe_ent); + if (rc) + goto err_out_hpriv; + + /* FIXME: check ata_device_add return value */ + ata_device_add(probe_ent); + kfree(probe_ent); + + return 0; + +err_out_hpriv: + kfree(hpriv); +err_out_iounmap: + iounmap(mmio_base); +err_out_free_ent: + kfree(probe_ent); +err_out_regions: + pci_release_regions(pdev); +err_out: + pci_disable_device(pdev); + return rc; +} + + +static int __init adma_init(void) +{ + return pci_module_init(&adma_pci_driver); +} + + +static void __exit adma_exit(void) +{ + pci_unregister_driver(&adma_pci_driver); +} + + +MODULE_AUTHOR("Jeff Garzik"); +MODULE_DESCRIPTION("ADMA ATA low-level driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, adma_pci_tbl); + +module_init(adma_init); +module_exit(adma_exit); diff -Nru a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c --- a/drivers/scsi/ata_piix.c 2005-01-06 23:50:11 -05:00 +++ b/drivers/scsi/ata_piix.c 2005-01-06 23:50:11 -05:00 @@ -60,6 +60,7 @@ piix4_pata = 2, ich6_sata = 3, ich6_sata_rm = 4, + ich7_sata = 5, }; static int piix_init_one (struct pci_dev *pdev, @@ -90,6 +91,8 @@ { 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 }, + { 0x8086, 0x27c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, + { 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata }, { } /* terminate list */ }; @@ -226,6 +229,18 @@ }, /* 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, + }, + + /* ich7_sata */ { .sht = &piix_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST | diff -Nru a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c --- a/drivers/scsi/libata-core.c 2005-01-06 23:50:11 -05:00 +++ b/drivers/scsi/libata-core.c 2005-01-06 23:50:11 -05:00 @@ -1166,6 +1166,37 @@ DPRINTK("EXIT, err\n"); } + +static inline u8 ata_dev_knobble(struct ata_port *ap) +{ + return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(ap->device->id))); +} + +/** + * ata_dev_config - Run device specific handlers and check for + * SATA->PATA bridges + * @ap: Bus + * @i: Device + * + * LOCKING: + */ + +void ata_dev_config(struct ata_port *ap, unsigned int i) +{ + /* limit bridge transfers to udma5, 200 sectors */ + if (ata_dev_knobble(ap)) { + printk(KERN_INFO "ata%u(%u): applying bridge limits\n", + ap->id, ap->device->devno); + ap->udma_mask &= ATA_UDMA5; + ap->host->max_sectors = ATA_MAX_SECTORS; + ap->host->hostt->max_sectors = ATA_MAX_SECTORS; + ap->device->flags |= ATA_DFLAG_LOCK_SECTORS; + } + + if (ap->ops->dev_config) + ap->ops->dev_config(ap, &ap->device[i]); +} + /** * ata_bus_probe - Reset and probe ATA bus * @ap: Bus to probe @@ -1188,8 +1219,7 @@ ata_dev_identify(ap, i); if (ata_dev_present(&ap->device[i])) { found = 1; - if (ap->ops->dev_config) - ap->ops->dev_config(ap, &ap->device[i]); + ata_dev_config(ap,i); } } @@ -1700,6 +1730,70 @@ DPRINTK("EXIT\n"); } +static void ata_pr_blacklisted(struct ata_port *ap, struct ata_device *dev) +{ + printk(KERN_WARNING "ata%u: dev %u is on DMA blacklist, disabling DMA\n", + ap->id, dev->devno); +} + +static const char * ata_dma_blacklist [] = { + "WDC AC11000H", + "WDC AC22100H", + "WDC AC32500H", + "WDC AC33100H", + "WDC AC31600H", + "WDC AC32100H", + "WDC AC23200L", + "Compaq CRD-8241B", + "CRD-8400B", + "CRD-8480B", + "CRD-8480C", + "CRD-8482B", + "CRD-84", + "SanDisk SDP3B", + "SanDisk SDP3B-64", + "SANYO CD-ROM CRD", + "HITACHI CDR-8", + "HITACHI CDR-8335", + "HITACHI CDR-8435", + "Toshiba CD-ROM XM-6202B", + "CD-532E-A", + "E-IDE CD-ROM CR-840", + "CD-ROM Drive/F5A", + "WPI CDD-820", + "SAMSUNG CD-ROM SC-148C", + "SAMSUNG CD-ROM SC", + "SanDisk SDP3B-64", + "SAMSUNG CD-ROM SN-124", + "ATAPI CD-ROM DRIVE 40X MAXIMUM", + "_NEC DV5800A", +}; + +static int ata_dma_blacklisted(struct ata_port *ap, struct ata_device *dev) +{ + unsigned char model_num[40]; + char *s; + unsigned int len; + int i; + + ata_dev_id_string(dev->id, model_num, ATA_ID_PROD_OFS, + sizeof(model_num)); + s = &model_num[0]; + len = strnlen(s, sizeof(model_num)); + + /* ATAPI specifies that empty space is blank-filled; remove blanks */ + while ((len > 0) && (s[len - 1] == ' ')) { + len--; + s[len] = 0; + } + + for (i = 0; i < ARRAY_SIZE(ata_dma_blacklist); i++) + if (!strncmp(ata_dma_blacklist[i], s, len)) + return 1; + + return 0; +} + static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift) { struct ata_device *master, *slave; @@ -1712,17 +1806,37 @@ if (shift == ATA_SHIFT_UDMA) { mask = ap->udma_mask; - if (ata_dev_present(master)) + if (ata_dev_present(master)) { mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff); - if (ata_dev_present(slave)) + if (ata_dma_blacklisted(ap, master)) { + mask = 0; + ata_pr_blacklisted(ap, master); + } + } + if (ata_dev_present(slave)) { mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff); + if (ata_dma_blacklisted(ap, slave)) { + mask = 0; + ata_pr_blacklisted(ap, slave); + } + } } else if (shift == ATA_SHIFT_MWDMA) { mask = ap->mwdma_mask; - if (ata_dev_present(master)) + if (ata_dev_present(master)) { mask &= (master->id[ATA_ID_MWDMA_MODES] & 0x07); - if (ata_dev_present(slave)) + if (ata_dma_blacklisted(ap, master)) { + mask = 0; + ata_pr_blacklisted(ap, master); + } + } + if (ata_dev_present(slave)) { mask &= (slave->id[ATA_ID_MWDMA_MODES] & 0x07); + if (ata_dma_blacklisted(ap, slave)) { + mask = 0; + ata_pr_blacklisted(ap, slave); + } + } } else if (shift == ATA_SHIFT_PIO) { mask = ap->pio_mask; @@ -3219,6 +3333,7 @@ ap->mwdma_mask = ent->mwdma_mask; ap->udma_mask = ent->udma_mask; ap->flags |= ent->host_flags; + ap->flags |= ent->port_flags[port_no]; ap->ops = ent->port_ops; ap->cbl = ATA_CBL_NONE; ap->active_tag = ATA_TAG_POISON; @@ -3844,6 +3959,7 @@ EXPORT_SYMBOL_GPL(ata_host_intr); EXPORT_SYMBOL_GPL(ata_dev_classify); EXPORT_SYMBOL_GPL(ata_dev_id_string); +EXPORT_SYMBOL_GPL(ata_dev_config); EXPORT_SYMBOL_GPL(ata_scsi_simulate); #ifdef CONFIG_PCI diff -Nru a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c --- a/drivers/scsi/libata-scsi.c 2005-01-06 23:50:11 -05:00 +++ b/drivers/scsi/libata-scsi.c 2005-01-06 23:50:11 -05:00 @@ -29,10 +29,13 @@ #include "scsi.h" #include #include +#include #include #include "libata.h" +#define SECTOR_SIZE 512 + typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, u8 *scsicmd); static struct ata_device * ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev); @@ -67,11 +70,162 @@ return 0; } +/** + * ata_cmd_ioctl - Handler for HDIO_DRIVE_CMD ioctl + * @dev: Device to whom we are issuing command + * @arg: User provided data for issuing command + * + * LOCKING: + * Defined by the SCSI layer. We don't really care. + * + * RETURNS: + * Zero on success, negative errno on error. + */ + +int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg) +{ + int rc = 0; + u8 scsi_cmd[MAX_COMMAND_SIZE]; + u8 args[4], *argbuf = NULL; + int argsize = 0; + struct scsi_request *sreq; + + if (NULL == (void *)arg) + return -EINVAL; + + if (copy_from_user(args, arg, sizeof(args))) + return -EFAULT; + + sreq = scsi_allocate_request(scsidev, GFP_KERNEL); + if (!sreq) + return -EINTR; + + memset(scsi_cmd, 0, sizeof(scsi_cmd)); + + if (args[3]) { + argsize = SECTOR_SIZE * args[3]; + argbuf = kmalloc(argsize, GFP_KERNEL); + if (argbuf == NULL) + return -ENOMEM; + + scsi_cmd[1] = (4 << 1); /* PIO Data-in */ + sreq->sr_data_direction = DMA_FROM_DEVICE; + } else { + scsi_cmd[1] = (3 << 1); /* Non-data */ + sreq->sr_data_direction = DMA_NONE; + } + + scsi_cmd[0] = ATA_16; + scsi_cmd[2] = 0x1f; /* no off.line or cc, yes all registers */ + + scsi_cmd[4] = args[2]; + if (args[0] == WIN_SMART) { /* hack -- ide driver does this too... */ + scsi_cmd[6] = args[3]; + scsi_cmd[8] = args[1]; + scsi_cmd[10] = 0x4f; + scsi_cmd[12] = 0xc2; + } else { + scsi_cmd[6] = args[1]; + } + scsi_cmd[14] = args[0]; + + /* Good values for timeout and retries? Values below + from scsi_ioctl_send_command() for default case... */ + scsi_wait_req(sreq, scsi_cmd, argbuf, argsize, (10*HZ), 5); + + if (sreq->sr_result) { + rc = -EIO; + goto error; + } + + /* Need code to retrieve data from check condition? */ + + if ((argbuf) + && copy_to_user((void *)(arg + sizeof(args)), argbuf, argsize)) + rc = -EFAULT; +error: + scsi_release_request(sreq); + + if (argbuf) + kfree(argbuf); + + return rc; +} + +/** + * ata_task_ioctl - Handler for HDIO_DRIVE_TASK ioctl + * @dev: Device to whom we are issuing command + * @arg: User provided data for issuing command + * + * LOCKING: + * Defined by the SCSI layer. We don't really care. + * + * RETURNS: + * Zero on success, negative errno on error. + */ +int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg) +{ + int rc = 0; + u8 scsi_cmd[MAX_COMMAND_SIZE]; + u8 args[7]; + struct scsi_request *sreq; + + if (NULL == (void *)arg) + return -EINVAL; + + if (copy_from_user(args, arg, sizeof(args))) + return -EFAULT; + + memset(scsi_cmd, 0, sizeof(scsi_cmd)); + scsi_cmd[0] = ATA_16; + scsi_cmd[1] = (3 << 1); /* Non-data */ + scsi_cmd[2] = 0x1f; /* no off.line or cc, yes all registers */ + scsi_cmd[4] = args[1]; + scsi_cmd[6] = args[2]; + scsi_cmd[8] = args[3]; + scsi_cmd[10] = args[4]; + scsi_cmd[12] = args[5]; + scsi_cmd[14] = args[0]; + + sreq = scsi_allocate_request(scsidev, GFP_KERNEL); + if (!sreq) { + rc = -EINTR; + goto error; + } + + sreq->sr_data_direction = DMA_NONE; + /* Good values for timeout and retries? Values below + from scsi_ioctl_send_command() for default case... */ + scsi_wait_req(sreq, scsi_cmd, NULL, 0, (10*HZ), 5); + + if (sreq->sr_result) { + rc = -EIO; + goto error; + } + + /* Need code to retrieve data from check condition? */ + +error: + scsi_release_request(sreq); + return rc; +} + int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg) { struct ata_port *ap; struct ata_device *dev; int val = -EINVAL, rc = -EINVAL; + struct hd_driveid drv_id = { + .cyls = 0, + .sectors = 0, + .heads = 0, + .fw_rev = "", + .model = "", + .cur_cyls = 0, + .cur_heads = 0, + .cur_sectors = 0, + }; + int geom[3]; ap = (struct ata_port *) &scsidev->host->hostdata[0]; if (!ap) @@ -96,6 +250,27 @@ return -EINVAL; return 0; + case HDIO_GET_IDENTITY: + ata_std_bios_param(scsidev, NULL, dev->n_sectors, geom); + drv_id.cur_heads = drv_id.heads = geom[0]; + drv_id.cur_sectors = drv_id.sectors = geom[1]; + drv_id.cur_cyls = drv_id.cyls = geom[2]; + strncpy((char *) &drv_id.model, scsidev->model, sizeof(drv_id.model)); + strncpy((char *) &drv_id.fw_rev, scsidev->rev, sizeof(drv_id.fw_rev)); + if(copy_to_user((char *) arg, (char *) &drv_id, sizeof(drv_id))) + return(-EFAULT); + return 0; + + case HDIO_DRIVE_CMD: + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) + return -EACCES; + return ata_cmd_ioctl(scsidev, arg); + + case HDIO_DRIVE_TASK: + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) + return -EACCES; + return ata_task_ioctl(scsidev, arg); + default: rc = -ENOTTY; break; @@ -313,6 +488,85 @@ } } +/* + * ata_pass_thru_cc - Generate check condition sense block. + * @qc: Command that completed. + * + * Regardless of whether the command errored or not, return + * a sense block. Copy all controller registers into + * the sense block. Clear sense key, ASC & ASCQ if + * there is no error. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + */ +void ata_pass_thru_cc(struct ata_queued_cmd *qc, u8 drv_stat) +{ + struct scsi_cmnd *cmd = qc->scsicmd; + struct ata_taskfile *tf = &qc->tf; + unsigned char *sb = cmd->sense_buffer; + unsigned char *desc = sb + 8 ; + + cmd->result = SAM_STAT_CHECK_CONDITION; + + /* + * Use ata_to_sense_error() to map status register bits + * onto sense key, asc & ascq. We will overwrite some + * (many) of the fields later. + * + * TODO: reorganise better, by splitting ata_to_sense_error() + */ + if (unlikely(drv_stat & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ))) { + ata_to_sense_error(qc, drv_stat) ; + } else { + sb[3] = sb[2] = sb[1] = 0x00 ; + } + + /* + * Sense data is current and format is + * descriptor. + */ + sb[0] = 0x72 ; + + desc[0] = 0x8e ; /* TODO: replace with official value. */ + + /* + * Set length of additional sense data. + * Since we only populate descriptor 0, the total + * length is the same (fixed) length as descriptor 0. + */ + desc[1] = sb[7] = 14 ; + + /* + * Read the controller registers. + */ + qc->ap->ops->tf_read(qc->ap, tf); + + /* + * Copy registers into sense buffer. + */ + desc[2] = 0x00 ; + desc[3] = tf->feature ; /* Note: becomes error register when read. */ + desc[5] = tf->nsect ; + desc[7] = tf->lbal ; + desc[9] = tf->lbam ; + desc[11] = tf->lbah ; + desc[12] = tf->device ; + desc[13] = drv_stat ; + + /* + * Fill in Extend bit, and the high order bytes + * if applicable. + */ + if (tf->flags & ATA_TFLAG_LBA48) { + desc[2] |= 0x01 ; + desc[4] = tf->hob_nsect ; + desc[6] = tf->hob_lbal ; + desc[8] = tf->hob_lbam ; + desc[10] = tf->hob_lbah ; + } +} + /** * ata_scsi_slave_config - Set SCSI device attributes * @sdev: SCSI device to examine @@ -621,10 +875,23 @@ { struct scsi_cmnd *cmd = qc->scsicmd; - if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) - ata_to_sense_error(qc, drv_stat); - else - cmd->result = SAM_STAT_GOOD; + /* + * If this was a pass-thru command, and the user requested + * a check condition return including register values. + * Note that check condition is generated, and the ATA + * register values are returned, whether the command completed + * successfully or not. If there was no error, SK, ASC and + * ASCQ will all be zero. + */ + if (((cmd->cmnd[0] == ATA_16) || (cmd->cmnd[0] == ATA_12)) && + (cmd->cmnd[2] & 0x20)) { + ata_pass_thru_cc(qc, drv_stat) ; + } else { + if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) + ata_to_sense_error(qc, drv_stat); + else + cmd->result = SAM_STAT_GOOD; + } qc->scsidone(cmd); @@ -686,7 +953,6 @@ if (xlat_func(qc, scsicmd)) goto err_out; - /* select device, send command to hardware */ if (ata_qc_issue(qc)) goto err_out; @@ -1381,6 +1647,135 @@ return dev; } +/* + * ata_scsi_map_proto - Map pass-thru protocol value to taskfile value. + * @byte1: Byte 1 from pass-thru CDB. + * + * RETURNS: + * ATA_PROT_UNKNOWN if mapping failed/unimplemented, protocol otherwise. + */ +static u8 +ata_scsi_map_proto(u8 byte1) +{ + switch((byte1 & 0x1e) >> 1) { + case 3: /* Non-data */ + return ATA_PROT_NODATA; + + case 6: /* DMA */ + return ATA_PROT_DMA; + + case 4: /* PIO Data-in */ + case 5: /* PIO Data-out */ + if (byte1 & 0xe0) { + return ATA_PROT_PIO_MULT; + } + return ATA_PROT_PIO; + + case 10: /* Device Reset */ + case 0: /* Hard Reset */ + case 1: /* SRST */ + case 2: /* Bus Idle */ + case 7: /* Packet */ + case 8: /* DMA Queued */ + case 9: /* Device Diagnostic */ + case 11: /* UDMA Data-in */ + case 12: /* UDMA Data-Out */ + case 13: /* FPDMA */ + default: /* Reserved */ + break; + } + + return ATA_PROT_UNKNOWN; +} + +/** + * ata_scsi_pass_thru - convert ATA pass-thru CDB to taskfile + * @qc: command structure to be initialized + * @cmd: SCSI command to convert + * + * Handles either 12 or 16-byte versions of the CDB. + * + * RETURNS: + * Zero on success, non-zero on failure. + */ +static unsigned int +ata_scsi_pass_thru(struct ata_queued_cmd *qc, u8 *scsicmd) +{ + struct ata_taskfile *tf = &(qc->tf); + struct scsi_cmnd *cmd = qc->scsicmd; + + if ((tf->protocol = ata_scsi_map_proto(scsicmd[1])) == ATA_PROT_UNKNOWN) { + return 1; + } + + /* + * 12 and 16 byte CDBs use different offsets to + * provide the various register values. + */ + if (scsicmd[0] == ATA_16) { + /* + * 16-byte CDB - may contain extended commands. + * + * If that is the case, copy the upper byte register values. + */ + if (scsicmd[1] & 0x01) { + tf->hob_feature = scsicmd[3]; + tf->hob_nsect = scsicmd[5]; + tf->hob_lbal = scsicmd[7]; + tf->hob_lbam = scsicmd[9]; + tf->hob_lbah = scsicmd[11]; + tf->flags |= ATA_TFLAG_LBA48 ; + } else { + tf->flags &= ~ATA_TFLAG_LBA48 ; + } + + /* + * Always copy low byte, device and command registers. + */ + tf->feature = scsicmd[4]; + tf->nsect = scsicmd[6]; + tf->lbal = scsicmd[8]; + tf->lbam = scsicmd[10]; + tf->lbah = scsicmd[12]; + tf->device = scsicmd[13]; + tf->command = scsicmd[14]; + } else { + /* + * 12-byte CDB - incapable of extended commands. + */ + tf->flags &= ~ATA_TFLAG_LBA48 ; + + tf->feature = scsicmd[3]; + tf->nsect = scsicmd[4]; + tf->lbal = scsicmd[5]; + tf->lbam = scsicmd[6]; + tf->lbah = scsicmd[7]; + tf->device = scsicmd[8]; + tf->command = scsicmd[9]; + } + + /* + * Set flags so that all registers will be written, + * and pass on write indication (used for PIO/DMA + * setup.) + */ + tf->flags |= (ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE) ; + + if (cmd->sc_data_direction == SCSI_DATA_WRITE) { + tf->flags |= ATA_TFLAG_WRITE; + } + + /* + * Set transfer length. + * + * TODO: find out if we need to do more here to + * cover scatter/gather case. + */ + qc->nsect = cmd->bufflen / ATA_SECT_SIZE ; + + return 0; +} + /** * ata_get_xlat_func - check if SCSI to ATA translation is possible * @dev: ATA device @@ -1413,6 +1808,10 @@ case VERIFY: case VERIFY_16: return ata_scsi_verify_xlat; + + case ATA_12: + case ATA_16: + return ata_scsi_pass_thru ; } return NULL; diff -Nru a/drivers/scsi/libata.h b/drivers/scsi/libata.h --- a/drivers/scsi/libata.h 2005-01-06 23:50:11 -05:00 +++ b/drivers/scsi/libata.h 2005-01-06 23:50:11 -05:00 @@ -43,6 +43,8 @@ unsigned int wait, unsigned int can_sleep); extern void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf); extern void swap_buf_le16(u16 *buf, unsigned int buf_words); +extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg); +extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg); /* libata-scsi.c */ diff -Nru a/drivers/scsi/pata_pdc2027x.c b/drivers/scsi/pata_pdc2027x.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/scsi/pata_pdc2027x.c 2005-01-06 23:50:11 -05:00 @@ -0,0 +1,694 @@ +/* + * Promise PATA TX2/TX4/TX2000/133 IDE driver for pdc20268 to pdc20277. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Ported to libata by: + * Albert Lee IBM Corporation + * + * Copyright (C) 1998-2002 Andre Hedrick + * Portions Copyright (C) 1999 Promise Technology, Inc. + * + * Author: Frank Tiernan (frankt@promise.com) + * Released under terms of General Public License + * + * + */ +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include +#include +#include + +#define DRV_NAME "pata_pdc2027x" +#define DRV_VERSION "0.53" +#undef PDC_DEBUG + +#ifdef PDC_DEBUG +#define PDPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ## args) +#else +#define PDPRINTK(fmt, args...) +#endif + +enum { + PDC_UDMA_100 = 0, + PDC_UDMA_133 = 1, + + PDC_100_MHZ = 100000000, + PDC_133_MHZ = 133333333, +}; + +static int pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); +static void pdc2027x_remove_one(struct pci_dev *pdev); +static void pdc2027x_phy_reset(struct ata_port *ap); +static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev); +static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev); + +/* + * ATA Timing Tables based on 133MHz controller clock. + * These tables are only used when the controller is in 133MHz clock. + * If the controller is in 100MHz clock, the ASIC hardware will + * set the timing registers automatically when "set feature" command + * is issued to the device. However, if the controller clock is 133MHz, + * the following tables must be used. + */ +static struct pdc2027x_pio_timing { + u8 value0, value1, value2; +} pdc2027x_pio_timing_tbl [] = { + { 0xfb, 0x2b, 0xac }, /* PIO mode 0 */ + { 0x46, 0x29, 0xa4 }, /* PIO mode 1 */ + { 0x23, 0x26, 0x64 }, /* PIO mode 2 */ + { 0x27, 0x0d, 0x35 }, /* PIO mode 3, IORDY on, Prefetch off */ + { 0x23, 0x09, 0x25 }, /* PIO mode 4, IORDY on, Prefetch off */ +}; + +static struct pdc2027x_mdma_timing { + u8 value0, value1; +} pdc2027x_mdma_timing_tbl [] = { + { 0xdf, 0x5f }, /* MDMA mode 0 */ + { 0x6b, 0x27 }, /* MDMA mode 1 */ + { 0x69, 0x25 }, /* MDMA mode 2 */ +}; + +static struct pdc2027x_udma_timing { + u8 value0, value1, value2; +} pdc2027x_udma_timing_tbl [] = { + { 0x4a, 0x0f, 0xd5 }, /* UDMA mode 0 */ + { 0x3a, 0x0a, 0xd0 }, /* UDMA mode 1 */ + { 0x2a, 0x07, 0xcd }, /* UDMA mode 2 */ + { 0x1a, 0x05, 0xcd }, /* UDMA mode 3 */ + { 0x1a, 0x03, 0xcd }, /* UDMA mode 4 */ + { 0x1a, 0x02, 0xcb }, /* UDMA mode 5 */ + { 0x1a, 0x01, 0xcb }, /* UDMA mode 6 */ +}; + +static struct pci_device_id pdc2027x_pci_tbl[] = { +#ifdef ATA_ENABLE_PATA + { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_100 }, + { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 }, + { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20270, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_100 }, + { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20271, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 }, + { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 }, + { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 }, + { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20277, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 }, +#endif + { } /* terminate list */ +}; + +static struct pci_driver pdc2027x_pci_driver = { + .name = DRV_NAME, + .id_table = pdc2027x_pci_tbl, + .probe = pdc2027x_init_one, + .remove = __devexit_p(pdc2027x_remove_one), +}; + +static Scsi_Host_Template pdc2027x_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .queuecommand = ata_scsi_queuecmd, + .eh_strategy_handler = ata_scsi_error, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .max_sectors = ATA_MAX_SECTORS, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .bios_param = ata_std_bios_param, +}; + +static struct ata_port_operations pdc2027x_pata_ops = { + .port_disable = ata_port_disable, + .set_piomode = pdc2027x_set_piomode, + .set_dmamode = pdc2027x_set_dmamode, + + .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 = pdc2027x_phy_reset, + + .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, +}; + +static struct ata_port_info pdc2027x_port_info[] = { + /* PDC_UDMA_100 */ + { + .sht = &pdc2027x_sht, + .host_flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS | + ATA_FLAG_SRST, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = ATA_UDMA5, /* udma0-5 */ + .port_ops = &pdc2027x_pata_ops, + }, + /* PDC_UDMA_133 */ + { + .sht = &pdc2027x_sht, + .host_flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS | + ATA_FLAG_SRST, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = ATA_UDMA6, /* udma0-6 */ + .port_ops = &pdc2027x_pata_ops, + }, +}; + +MODULE_AUTHOR("Andre Hedrick, Frank Tiernan, Albert Lee"); +MODULE_DESCRIPTION("libata driver module for Promise PDC20268 to PDC20277"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, pdc2027x_pci_tbl); + +/** + * pdc_get_indexed_reg - Set pdc202xx extended register + * @ap: Port to which the extended register is set + * @index: index of the extended register + */ +static u8 pdc_get_indexed_reg(struct ata_port *ap, u8 index) +{ + u8 tmp8; + + outb(index, ap->ioaddr.bmdma_addr + 1); + tmp8 = inb(ap->ioaddr.bmdma_addr + 3); + + PDPRINTK("Get index reg%X[%X] \n", index, tmp8); + return tmp8; +} +/** + * pdc_set_indexed_reg - Read pdc202xx extended register + * @ap: Port to which the extended register is read + * @index: index of the extended register + */ +static void pdc_set_indexed_reg(struct ata_port *ap, u8 index, u8 value) +{ + outb(index, ap->ioaddr.bmdma_addr + 1); + outb(value, ap->ioaddr.bmdma_addr + 3); + PDPRINTK("Set index reg%X[%X] \n", index, value); +} +/** + * pdc2027x_pata_cbl_detect - Probe host controller cable detect info + * @ap: Port for which cable detect info is desired + * + * Read 80c cable indicator from Promise extended register. + * This register is latched when the system is reset. + * + * LOCKING: + * None (inherited from caller). + */ +static void pdc2027x_cbl_detect(struct ata_port *ap) +{ + u8 cbl40c; + + /* check cable detect results */ + cbl40c = pdc_get_indexed_reg(ap, 0x0b) & 0x04; + + if (cbl40c) + goto cbl40; + + PDPRINTK("No cable or 80-conductor cable on port %d\n", ap->port_no); + + ap->cbl = ATA_CBL_PATA80; + return; + +cbl40: + printk(KERN_INFO DRV_NAME ": 40-conductor cable detected on port %d\n", ap->port_no); + ap->cbl = ATA_CBL_PATA40; + ap->udma_mask &= ATA_UDMA_MASK_40C; +} +/** + * pdc2027x_port_enabled - Check extended register at 0x04 to see whether the port is enabled. + * @ap: Port to check + */ +static inline int pdc2027x_port_enabled(struct ata_port *ap) +{ + return pdc_get_indexed_reg(ap, 0x04) & 0x02; +} +/** + * pdc2027x_phy_reset - Probe specified port on PATA host controller + * @ap: Port to probe + * + * Probe PATA phy. + * + * LOCKING: + * None (inherited from caller). + */ +static void pdc2027x_phy_reset(struct ata_port *ap) +{ + /* Check whether port enabled */ + if (!pdc2027x_port_enabled(ap)) { + ata_port_disable(ap); + printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); + return; + } + + pdc2027x_cbl_detect(ap); + ata_port_probe(ap); + ata_bus_reset(ap); +} +/** + * pdc2027x_set_piomode - Initialize host controller PATA PIO timings + * @ap: Port to configure + * @adev: um + * @pio: PIO mode, 0 - 4 + * + * Set PIO mode for device. + * + * LOCKING: + * None (inherited from caller). + */ +static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + unsigned int pio = adev->pio_mode - XFER_PIO_0; + unsigned int drive_dn = (ap->port_no ? 2 : 0) + adev->devno; + u8 adj = (drive_dn%2) ? 0x08 : 0x00; + u8 tmp8; + + + PDPRINTK("adev->pio_mode[%X]\n", adev->pio_mode); + + /* Sanity check */ + if(pio > 4) { + printk(KERN_ERR DRV_NAME ": Unknown pio mode [%d] ignored\n", pio); + return; + + } + + /* Set the PIO timing registers using value table for 133MHz */ + PDPRINTK("Set pio regs... \n"); + + pdc_set_indexed_reg(ap, 0x0c + adj, pdc2027x_pio_timing_tbl[pio].value0); + pdc_set_indexed_reg(ap, 0x0d + adj, pdc2027x_pio_timing_tbl[pio].value1); + pdc_set_indexed_reg(ap, 0x13 + adj, pdc2027x_pio_timing_tbl[pio].value2); + + PDPRINTK("Set pio regs done\n"); + + /* + * Check whether the device supports turning off IORDY. + * For PIO3 and above, the device must support IORDY and set bit 10 + */ + if (adev->id[49] & 0x400) { + /* IORDY_EN & PREFETCH_EN */ + /* Turn on Prefetch */ + tmp8 = pdc_get_indexed_reg(ap, 0x13 + adj); + pdc_set_indexed_reg(ap, 0x13 + adj, tmp8 | 0x03); + + PDPRINTK("Turn on prefetch\n"); + } + + printk(KERN_INFO DRV_NAME ": Set to pio mode[%u] \n", pio); +} +/** + * pdc2027x_set_dmamode - Initialize host controller PATA UDMA timings + * @ap: Port to configure + * @adev: um + * @udma: udma mode, XFER_UDMA_0 to XFER_UDMA_6 + * + * Set UDMA mode for device. + * + * LOCKING: + * None (inherited from caller). + */ +static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev) +{ + unsigned int dma_mode = adev->dma_mode; + unsigned int drive_dn = (ap->port_no ? 2 : 0) + adev->devno; + u8 adj = (drive_dn%2) ? 0x08 : 0x00; + u8 tmp8; + + if((dma_mode >= XFER_UDMA_0) && + (dma_mode <= XFER_UDMA_6)) { + /* Set the UDMA timing registers with value table for 133MHz */ + unsigned int udma_mode = dma_mode & 0x07; + + if (dma_mode == XFER_UDMA_2) { + /* + * Turn off tHOLD. + * If tHOLD is '1', the hardware will add half clock for data hold time. + * This code segment seems to be no effect. tHOLD will be overwritten below. + */ + tmp8 = pdc_get_indexed_reg(ap, 0x10 + adj); + pdc_set_indexed_reg(ap, 0x10 + adj, tmp8 & 0x7f); + } + + PDPRINTK("Set udma regs... \n"); + pdc_set_indexed_reg(ap, 0x10 + adj, pdc2027x_udma_timing_tbl[udma_mode].value0); + pdc_set_indexed_reg(ap, 0x11 + adj, pdc2027x_udma_timing_tbl[udma_mode].value1); + pdc_set_indexed_reg(ap, 0x12 + adj, pdc2027x_udma_timing_tbl[udma_mode].value2); + PDPRINTK("Set udma regs done\n"); + + printk(KERN_INFO DRV_NAME ": Set to udma mode[%u] \n", udma_mode); + + } else if((dma_mode >= XFER_MW_DMA_0) && + (dma_mode <= XFER_MW_DMA_2)) { + /* Set the MDMA timing registers with value table for 133MHz */ + unsigned int mdma_mode = dma_mode & 0x07; + + PDPRINTK("Set mdma regs... \n"); + pdc_set_indexed_reg(ap, 0x0e + adj, pdc2027x_mdma_timing_tbl[mdma_mode].value0); + pdc_set_indexed_reg(ap, 0x0f + adj, pdc2027x_mdma_timing_tbl[mdma_mode].value1); + PDPRINTK("Set mdma regs done\n"); + + printk(KERN_INFO DRV_NAME ": Set to mdma mode[%u] \n", mdma_mode); + } else { + printk(KERN_ERR DRV_NAME ": Unknown dma mode [%u] ignored\n", dma_mode); + } +} +/** + * adjust_pll - Adjust the PLL input clock in Hz. + * + * @pdc_controller: controller specific information + * @probe_ent: For the port address + * @pll_clock: The input of PLL in HZ + */ +static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsigned int board_idx) +{ + + u8 pll_ctl0, pll_ctl1; + long pll_clock_khz = pll_clock / 1000; + long pout_required = board_idx? PDC_133_MHZ:PDC_100_MHZ; + long ratio = pout_required / pll_clock_khz; + int F, R; + + + /* Sanity check */ + if (unlikely(pll_clock_khz < 5000L || pll_clock_khz > 70000L)) { + printk(KERN_ERR DRV_NAME ": Invalid PLL input clock %ldkHz, give up!\n", pll_clock_khz); + return; + } + +#ifdef PDC_DEBUG + PDPRINTK("pout_required is %ld\n", pout_required); + + /* Show the current clock value of PLL control register + * (maybe already configured by the firmware) + */ + outb(0x02, probe_ent->port[1].bmdma_addr + 0x01); + pll_ctl0 = inb(probe_ent->port[1].bmdma_addr + 0x03); + outb(0x03, probe_ent->port[1].bmdma_addr + 0x01); + pll_ctl1 = inb(probe_ent->port[1].bmdma_addr + 0x03); + + PDPRINTK("pll_ctl[%X][%X]\n", pll_ctl0, pll_ctl1); +#endif + + /* + * Calculate the ratio of F, R and OD + * POUT = (F + 2) / (( R + 2) * NO) + */ + if (ratio < 8600L) { // 8.6x + /* Using NO = 0x01, R = 0x0D */ + R = 0x0d; + } else if (ratio < 12900L) { // 12.9x + /* Using NO = 0x01, R = 0x08 */ + R = 0x08; + } else if (ratio < 16100L) { // 16.1x + /* Using NO = 0x01, R = 0x06 */ + R = 0x06; + } else if (ratio < 64000L) { // 64x + R = 0x00; + } else { + /* Invalid ratio */ + printk(KERN_ERR DRV_NAME ": Invalid ratio %ld, give up!\n", ratio); + return; + } + + F = (ratio * (R+2)) / 1000 - 2; + + if (unlikely(F < 0 || F > 127)) { + /* Invalid F */ + printk(KERN_ERR DRV_NAME ": F[%d] invalid!\n", F); + return; + } + + PDPRINTK("F[%d] R[%d] ratio*1000[%ld]\n", F, R, ratio); + + pll_ctl0 = (u8) F; + pll_ctl1 = (u8) R; + + PDPRINTK("Writing pll_ctl[%X][%X]\n", pll_ctl0, pll_ctl1); + + outb(0x02, probe_ent->port[1].bmdma_addr + 0x01); + outb(pll_ctl0, probe_ent->port[1].bmdma_addr + 0x03); + outb(0x03, probe_ent->port[1].bmdma_addr + 0x01); + outb(pll_ctl1, probe_ent->port[1].bmdma_addr + 0x03); + + /* Wait the PLL circuit to be stable */ + mdelay(30); + +#ifdef PDC_DEBUG + /* + * Show the current clock value of PLL control register + * (maybe configured by the firmware) + */ + outb(0x02, probe_ent->port[1].bmdma_addr + 0x01); + pll_ctl0 = inb(probe_ent->port[1].bmdma_addr + 0x03); + outb(0x03, probe_ent->port[1].bmdma_addr + 0x01); + pll_ctl1 = inb(probe_ent->port[1].bmdma_addr + 0x03); + + PDPRINTK("pll_ctl[%X][%X]\n", pll_ctl0, pll_ctl1); +#endif + + return; +} +/** + * detect_pll_input_clock - Detect the PLL input clock in Hz. + * @probe_ent: for the port address + * Ex. 16949000 on 33MHz PCI bus for pdc20275. + * Half of the PCI clock. + */ +static long pdc_detect_pll_input_clock(struct ata_probe_ent *probe_ent) +{ + u8 scr1; + unsigned long ctr0; + unsigned long ctr1; + unsigned long ctr2 = 0; + unsigned long ctr3 = 0; + + unsigned long start_count, end_count; + long pll_clock; + + /* Read current counter value */ + outb(0x20, probe_ent->port[0].bmdma_addr + 0x01); + ctr0 = inb(probe_ent->port[0].bmdma_addr + 0x03); + outb(0x21, probe_ent->port[0].bmdma_addr + 0x01); + ctr1 = inb(probe_ent->port[0].bmdma_addr + 0x03); + + outb(0x20, probe_ent->port[1].bmdma_addr + 0x01); + ctr2 = inb(probe_ent->port[1].bmdma_addr + 0x03); + outb(0x21, probe_ent->port[1].bmdma_addr + 0x01); + ctr3 = inb(probe_ent->port[1].bmdma_addr + 0x03); + + start_count = (ctr3 << 23 ) | (ctr2 << 15) | (ctr1 << 8) | ctr0; + + PDPRINTK("ctr0[%lX] ctr1[%lX] ctr2 [%lX] ctr3 [%lX]\n", ctr0, ctr1, ctr2, ctr3); + + /* Start the test mode */ + outb(0x01, probe_ent->port[0].bmdma_addr + 0x01); + scr1 = inb(probe_ent->port[0].bmdma_addr + 0x03); + PDPRINTK("scr1[%X]\n", scr1); + outb(scr1 | 0x40, probe_ent->port[0].bmdma_addr + 0x03); + + /* Let the counter run for 1000 us. */ + udelay(1000); + + /* Read the counter values again */ + outb(0x20, probe_ent->port[0].bmdma_addr + 0x01); + ctr0 = inb(probe_ent->port[0].bmdma_addr + 0x03); + outb(0x21, probe_ent->port[0].bmdma_addr + 0x01); + ctr1 = inb(probe_ent->port[0].bmdma_addr + 0x03); + + outb(0x20, probe_ent->port[1].bmdma_addr + 0x01); + ctr2 = inb(probe_ent->port[1].bmdma_addr + 0x03); + outb(0x21, probe_ent->port[1].bmdma_addr + 0x01); + ctr3 = inb(probe_ent->port[1].bmdma_addr + 0x03); + + end_count = (ctr3 << 23 ) | (ctr2 << 15) | (ctr1 << 8) | ctr0; + + PDPRINTK("ctr0[%lX] ctr1[%lX] ctr2 [%lX] ctr3 [%lX]\n", ctr0, ctr1, ctr2, ctr3); + + /* Stop the test mode */ + outb(0x01, probe_ent->port[0].bmdma_addr + 0x01); + scr1 = inb(probe_ent->port[0].bmdma_addr + 0x03); + PDPRINTK("scr1[%X]\n", scr1); + outb(scr1 & 0xBF, probe_ent->port[0].bmdma_addr + 0x03); + + /* calculate the input clock in Hz */ + pll_clock = (long) ((start_count - end_count) * 1000); + + PDPRINTK("start[%lu] end[%lu] \n", start_count, end_count); + PDPRINTK("PLL input clock[%ld]Hz\n", pll_clock); + + return pll_clock; +} +/** + * pdc_hardware_init - Initialize the hardware. + * @pdev: instance of pci_dev found + * @pdc_controller: controller specific information + * @pe: for the port address + */ +static int pdc_hardware_init(struct pci_dev *pdev, struct ata_probe_ent *pe, unsigned int board_idx) +{ + long pll_clock; + + /* + * Detect PLL input clock rate. + * On some system, where PCI bus is running at non-standard clock rate. + * Ex. 25MHz or 40MHz, we have to adjust the cycle_time. + * The pdc20275 controller employs PLL circuit to help correct timing registers setting. + */ + pll_clock = pdc_detect_pll_input_clock(pe); + + if(pll_clock < 0) /* counter overflow? Try again. */ + pll_clock = pdc_detect_pll_input_clock(pe); + + printk(KERN_INFO DRV_NAME ": PLL input clock %ld kHz\n", pll_clock/1000); + + /* Adjust PLL control register */ + pdc_adjust_pll(pe, pll_clock, board_idx); + + return 0; +} +/** + * pdc2027x_init_one - PCI probe function + * Called when an instance of PCI adapter is inserted. + * This function checks whether the hardware is supported, + * initialize hardware and register an instance of ata_host_set to + * libata by providing struct ata_probe_ent and ata_device_add(). + * (implements struct pci_driver.probe() ) + * + * @pdev: instance of pci_dev found + * @ent: matching entry in the id_tbl[] + */ +static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int printed_version; + unsigned int board_idx = (unsigned int) ent->driver_data; + + struct ata_probe_ent *probe_ent = NULL; + int rc; + + if (!printed_version++) + printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + + rc = pci_enable_device(pdev); + if (rc) + return rc; + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_out; + + rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; + + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; + + /* Prepare the probe entry */ + probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) { + rc = -ENOMEM; + goto err_out_regions; + } + + memset(probe_ent, 0, sizeof(*probe_ent)); + probe_ent->dev = pci_dev_to_dev(pdev); + INIT_LIST_HEAD(&probe_ent->node); + + probe_ent->sht = pdc2027x_port_info[board_idx].sht; + probe_ent->host_flags = pdc2027x_port_info[board_idx].host_flags; + probe_ent->pio_mask = pdc2027x_port_info[board_idx].pio_mask; + probe_ent->udma_mask = pdc2027x_port_info[board_idx].udma_mask; + probe_ent->port_ops = pdc2027x_port_info[board_idx].port_ops; + + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = SA_SHIRQ; + + probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); + ata_std_ports(&probe_ent->port[0]); + probe_ent->port[0].altstatus_addr = + probe_ent->port[0].ctl_addr = + pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; + probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); + + probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); + ata_std_ports(&probe_ent->port[1]); + probe_ent->port[1].altstatus_addr = + probe_ent->port[1].ctl_addr = + pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; + probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8; + + probe_ent->n_ports = 2; + + pci_set_master(pdev); + //pci_enable_intx(pdev); + + /* initialize adapter */ + if(pdc_hardware_init(pdev, probe_ent, board_idx) != 0) + goto err_out_free_ent; + + ata_device_add(probe_ent); + kfree(probe_ent); + + return 0; + +err_out_free_ent: + kfree(probe_ent); +err_out_regions: + pci_release_regions(pdev); +err_out: + pci_disable_device(pdev); + return rc; +} +/** + * pdc2027x_remove_one - Called to remove a single instance of the + * adapter. + * + * @dev: The PCI device to remove. + * FIXME: module load/unload not working yet + */ +static void __devexit pdc2027x_remove_one(struct pci_dev *pdev) +{ + ata_pci_remove_one(pdev); +} +/** + * pdc2027x_init - Called after this module is loaded into the kernel. + */ +static int __init pdc2027x_init(void) +{ + return pci_module_init(&pdc2027x_pci_driver); +} +/** + * pdc2027x_exit - Called before this module unloaded from the kernel + */ +static void __exit pdc2027x_exit(void) +{ + pci_unregister_driver(&pdc2027x_pci_driver); +} + +module_init(pdc2027x_init); +module_exit(pdc2027x_exit); diff -Nru a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c --- a/drivers/scsi/sata_promise.c 2005-01-06 23:50:11 -05:00 +++ b/drivers/scsi/sata_promise.c 2005-01-06 23:50:11 -05:00 @@ -79,6 +79,8 @@ static int pdc_port_start(struct ata_port *ap); static void pdc_port_stop(struct ata_port *ap); static void pdc_phy_reset(struct ata_port *ap); +static void pdc_pata_phy_reset(struct ata_port *ap); +static void pdc_pata_cbl_detect(struct ata_port *ap); static void pdc_qc_prep(struct ata_queued_cmd *qc); static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf); static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); @@ -127,7 +129,7 @@ /* board_2037x */ { .sht = &pdc_ata_sht, - .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + .host_flags = /* ATA_FLAG_SATA | */ ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST | ATA_FLAG_MMIO, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ @@ -244,7 +246,35 @@ static void pdc_phy_reset(struct ata_port *ap) { pdc_reset_port(ap); - sata_phy_reset(ap); + if (ap->flags & ATA_FLAG_SATA) + sata_phy_reset(ap); + else + pdc_pata_phy_reset(ap); +} + +static void pdc_pata_cbl_detect(struct ata_port *ap) +{ + u8 tmp; + void *mmio = (void *) ap->ioaddr.cmd_addr + PDC_CTLSTAT + 0x03; + + tmp = readb(mmio); + + if (tmp & 0x01) + { + ap->cbl = ATA_CBL_PATA40; + ap->udma_mask &= ATA_UDMA_MASK_40C; + } + else + ap->cbl = ATA_CBL_PATA80; +} + +static void pdc_pata_phy_reset(struct ata_port *ap) +{ + pdc_pata_cbl_detect(ap); + + ata_port_probe(ap); + + ata_bus_reset(ap); } static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) @@ -547,6 +577,7 @@ void *mmio_base; unsigned int board_idx = (unsigned int) ent->driver_data; int rc; + u8 tmp; if (!printed_version++) printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); @@ -605,6 +636,9 @@ probe_ent->port[0].scr_addr = base + 0x400; probe_ent->port[1].scr_addr = base + 0x500; + probe_ent->port_flags[0] = ATA_FLAG_SATA; + probe_ent->port_flags[1] = ATA_FLAG_SATA; + /* notice 4-port boards */ switch (board_idx) { case board_20319: @@ -615,9 +649,25 @@ probe_ent->port[2].scr_addr = base + 0x600; probe_ent->port[3].scr_addr = base + 0x700; + + probe_ent->port_flags[2] = ATA_FLAG_SATA; + probe_ent->port_flags[3] = ATA_FLAG_SATA; break; case board_2037x: - probe_ent->n_ports = 2; + /* Some boards have also PATA port */ + tmp = readb(mmio_base + PDC_FLASH_CTL+1); + if (!(tmp & 0x80)) + { + probe_ent->n_ports = 3; + + pdc_ata_setup_port(&probe_ent->port[2], base + 0x300); + + probe_ent->port_flags[2] = ATA_FLAG_SLAVE_POSS; + + printk(KERN_INFO DRV_NAME " PATA port found\n"); + } + else + probe_ent->n_ports = 2; break; default: BUG(); diff -Nru a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c --- a/drivers/scsi/sata_via.c 2005-01-06 23:50:11 -05:00 +++ b/drivers/scsi/sata_via.c 2005-01-06 23:50:11 -05:00 @@ -24,6 +24,11 @@ If you do not delete the provisions above, a recipient may use your version of this file under either the OSL or the GPL. + ---------------------------------------------------------------------- + + To-do list: + * VT6421 PATA support + */ #include @@ -38,11 +43,14 @@ #include #define DRV_NAME "sata_via" -#define DRV_VERSION "1.0" +#define DRV_VERSION "1.1" -enum { - via_sata = 0, +enum board_ids_enum { + vt6420, + vt6421, +}; +enum { SATA_CHAN_ENAB = 0x40, /* SATA channel enable */ SATA_INT_GATE = 0x41, /* SATA interrupt gating */ SATA_NATIVE_MODE = 0x42, /* Native mode enable */ @@ -50,10 +58,8 @@ PORT0 = (1 << 1), PORT1 = (1 << 0), - - ENAB_ALL = PORT0 | PORT1, - - INT_GATE_ALL = PORT0 | PORT1, + ALL_PORTS = PORT0 | PORT1, + N_PORTS = 2, NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4), @@ -66,7 +72,8 @@ static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static struct pci_device_id svia_pci_tbl[] = { - { 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, via_sata }, + { 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 }, + { 0x1106, 0x3249, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6421 }, { } /* terminate list */ }; @@ -158,18 +165,131 @@ 8, 4, 8, 4, 16, 256 }; +static const unsigned int vt6421_bar_sizes[] = { + 16, 16, 16, 16, 32, 128 +}; + static unsigned long svia_scr_addr(unsigned long addr, unsigned int port) { return addr + (port * 128); } +static unsigned long vt6421_scr_addr(unsigned long addr, unsigned int port) +{ + return addr + (port * 64); +} + +static void vt6421_init_addrs(struct ata_probe_ent *probe_ent, + struct pci_dev *pdev, + unsigned int port) +{ + unsigned long reg_addr = pci_resource_start(pdev, port); + unsigned long bmdma_addr = pci_resource_start(pdev, 4) + (port * 8); + unsigned long scr_addr; + + probe_ent->port[port].cmd_addr = reg_addr; + probe_ent->port[port].altstatus_addr = + probe_ent->port[port].ctl_addr = (reg_addr + 8) | ATA_PCI_CTL_OFS; + probe_ent->port[port].bmdma_addr = bmdma_addr; + + scr_addr = vt6421_scr_addr(pci_resource_start(pdev, 5), port); + probe_ent->port[port].scr_addr = scr_addr; + + ata_std_ports(&probe_ent->port[port]); +} + +static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev) +{ + struct ata_probe_ent *probe_ent; + struct ata_port_info *ppi = &svia_port_info; + + probe_ent = ata_pci_init_native_mode(pdev, &ppi); + if (!probe_ent) + return NULL; + + probe_ent->port[0].scr_addr = + svia_scr_addr(pci_resource_start(pdev, 5), 0); + probe_ent->port[1].scr_addr = + svia_scr_addr(pci_resource_start(pdev, 5), 1); + + return probe_ent; +} + +static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev) +{ + struct ata_probe_ent *probe_ent; + unsigned int i; + + probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + if (!probe_ent) + return NULL; + + memset(probe_ent, 0, sizeof(*probe_ent)); + probe_ent->dev = pci_dev_to_dev(pdev); + INIT_LIST_HEAD(&probe_ent->node); + + probe_ent->sht = &svia_sht; + probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET | + ATA_FLAG_NO_LEGACY; + probe_ent->port_ops = &svia_sata_ops; + probe_ent->n_ports = N_PORTS; + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = SA_SHIRQ; + probe_ent->pio_mask = 0x1f; + probe_ent->mwdma_mask = 0x07; + probe_ent->udma_mask = 0x7f; + + for (i = 0; i < N_PORTS; i++) + vt6421_init_addrs(probe_ent, pdev, i); + + return probe_ent; +} + +static void svia_configure(struct pci_dev *pdev) +{ + u8 tmp8; + + pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &tmp8); + printk(KERN_INFO DRV_NAME "(%s): routed to hard irq line %d\n", + pci_name(pdev), + (int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f); + + /* make sure SATA channels are enabled */ + pci_read_config_byte(pdev, SATA_CHAN_ENAB, &tmp8); + if ((tmp8 & ALL_PORTS) != ALL_PORTS) { + printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channels (0x%x)\n", + pci_name(pdev), (int) tmp8); + tmp8 |= ALL_PORTS; + pci_write_config_byte(pdev, SATA_CHAN_ENAB, tmp8); + } + + /* make sure interrupts for each channel sent to us */ + pci_read_config_byte(pdev, SATA_INT_GATE, &tmp8); + if ((tmp8 & ALL_PORTS) != ALL_PORTS) { + printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel interrupts (0x%x)\n", + pci_name(pdev), (int) tmp8); + tmp8 |= ALL_PORTS; + pci_write_config_byte(pdev, SATA_INT_GATE, tmp8); + } + + /* make sure native mode is enabled */ + pci_read_config_byte(pdev, SATA_NATIVE_MODE, &tmp8); + if ((tmp8 & NATIVE_MODE_ALL) != NATIVE_MODE_ALL) { + printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel native mode (0x%x)\n", + pci_name(pdev), (int) tmp8); + tmp8 |= NATIVE_MODE_ALL; + pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8); + } +} + static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; unsigned int i; int rc; - struct ata_port_info *ppi; struct ata_probe_ent *probe_ent; + int board_id = (int) ent->driver_data; + const int *bar_sizes; u8 tmp8; if (!printed_version++) @@ -183,17 +303,23 @@ if (rc) goto err_out; - pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8); - if (tmp8 & SATA_2DEV) { - printk(KERN_ERR DRV_NAME "(%s): SATA master/slave not supported (0x%x)\n", - pci_name(pdev), (int) tmp8); - rc = -EIO; - goto err_out_regions; + if (board_id == vt6420) { + pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8); + if (tmp8 & SATA_2DEV) { + printk(KERN_ERR DRV_NAME "(%s): SATA master/slave not supported (0x%x)\n", + pci_name(pdev), (int) tmp8); + rc = -EIO; + goto err_out_regions; + } + + bar_sizes = &svia_bar_sizes[0]; + } else { + bar_sizes = &vt6421_bar_sizes[0]; } for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++) if ((pci_resource_start(pdev, i) == 0) || - (pci_resource_len(pdev, i) < svia_bar_sizes[i])) { + (pci_resource_len(pdev, i) < bar_sizes[i])) { printk(KERN_ERR DRV_NAME "(%s): invalid PCI BAR %u (sz 0x%lx, val 0x%lx)\n", pci_name(pdev), i, pci_resource_start(pdev, i), @@ -209,8 +335,11 @@ if (rc) goto err_out_regions; - ppi = &svia_port_info; - probe_ent = ata_pci_init_native_mode(pdev, &ppi); + if (board_id == vt6420) + probe_ent = vt6420_init_probe_ent(pdev); + else + probe_ent = vt6421_init_probe_ent(pdev); + if (!probe_ent) { printk(KERN_ERR DRV_NAME "(%s): out of memory\n", pci_name(pdev)); @@ -218,42 +347,7 @@ goto err_out_regions; } - probe_ent->port[0].scr_addr = - svia_scr_addr(pci_resource_start(pdev, 5), 0); - probe_ent->port[1].scr_addr = - svia_scr_addr(pci_resource_start(pdev, 5), 1); - - pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &tmp8); - printk(KERN_INFO DRV_NAME "(%s): routed to hard irq line %d\n", - pci_name(pdev), - (int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f); - - /* make sure SATA channels are enabled */ - pci_read_config_byte(pdev, SATA_CHAN_ENAB, &tmp8); - if ((tmp8 & ENAB_ALL) != ENAB_ALL) { - printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channels (0x%x)\n", - pci_name(pdev), (int) tmp8); - tmp8 |= ENAB_ALL; - pci_write_config_byte(pdev, SATA_CHAN_ENAB, tmp8); - } - - /* make sure interrupts for each channel sent to us */ - pci_read_config_byte(pdev, SATA_INT_GATE, &tmp8); - if ((tmp8 & INT_GATE_ALL) != INT_GATE_ALL) { - printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel interrupts (0x%x)\n", - pci_name(pdev), (int) tmp8); - tmp8 |= INT_GATE_ALL; - pci_write_config_byte(pdev, SATA_INT_GATE, tmp8); - } - - /* make sure native mode is enabled */ - pci_read_config_byte(pdev, SATA_NATIVE_MODE, &tmp8); - if ((tmp8 & NATIVE_MODE_ALL) != NATIVE_MODE_ALL) { - printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel native mode (0x%x)\n", - pci_name(pdev), (int) tmp8); - tmp8 |= NATIVE_MODE_ALL; - pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8); - } + svia_configure(pdev); pci_set_master(pdev); diff -Nru a/include/linux/ata.h b/include/linux/ata.h --- a/include/linux/ata.h 2005-01-06 23:50:11 -05:00 +++ b/include/linux/ata.h 2005-01-06 23:50:11 -05:00 @@ -222,6 +222,7 @@ }; #define ata_id_is_ata(id) (((id)[0] & (1 << 15)) == 0) +#define ata_id_is_sata(id) ((id)[93] == 0) #define ata_id_rahead_enabled(id) ((id)[85] & (1 << 6)) #define ata_id_wcache_enabled(id) ((id)[85] & (1 << 5)) #define ata_id_has_flush(id) ((id)[83] & (1 << 12)) diff -Nru a/include/linux/libata.h b/include/linux/libata.h --- a/include/linux/libata.h 2005-01-06 23:50:11 -05:00 +++ b/include/linux/libata.h 2005-01-06 23:50:11 -05:00 @@ -205,6 +205,7 @@ unsigned long irq; unsigned int irq_flags; unsigned long host_flags; + unsigned long port_flags[ATA_MAX_PORTS]; void __iomem *mmio_base; void *private_data; }; @@ -413,6 +414,7 @@ extern unsigned int ata_dev_classify(struct ata_taskfile *tf); extern void ata_dev_id_string(u16 *id, unsigned char *s, unsigned int ofs, unsigned int len); +extern void ata_dev_config(struct ata_port *ap, unsigned int i); extern void ata_bmdma_setup (struct ata_queued_cmd *qc); extern void ata_bmdma_start (struct ata_queued_cmd *qc); extern void ata_bmdma_irq_clear(struct ata_port *ap); diff -Nru a/include/scsi/scsi.h b/include/scsi/scsi.h --- a/include/scsi/scsi.h 2005-01-06 23:50:11 -05:00 +++ b/include/scsi/scsi.h 2005-01-06 23:50:11 -05:00 @@ -113,6 +113,9 @@ /* values for service action in */ #define SAI_READ_CAPACITY_16 0x10 +/* Temporary values for T10/04-262 until official values are allocated */ +#define ATA_16 0x85 /* 16-byte pass-thru [0x85 == unused]*/ +#define ATA_12 0xb3 /* 12-byte pass-thru [0xb3 == obsolete set limits command] */ /* * SCSI Architecture Model (SAM) Status codes. Taken from SAM-3 draft