GIT d495e3d2ec3f007f32703be2d6da2325e621e178 master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev.git#ALL --- diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -438,11 +438,19 @@ config SCSI_SATA 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. @@ -514,6 +522,14 @@ config SCSI_SATA_SIL If unsure, say N. +config SCSI_SATA_SIL24 + tristate "Silicon Image 3124/3132 SATA support" + depends on SCSI_SATA && PCI && EXPERIMENTAL + help + This option enables support for Silicon Image 3124/3132 Serial ATA. + + If unsure, say N. + config SCSI_SATA_SIS tristate "SiS 964/180 SATA support" depends on SCSI_SATA && PCI && EXPERIMENTAL diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -122,12 +122,14 @@ obj-$(CONFIG_SCSI_LASI700) += 53c700.o l 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_SATA_PROMISE) += libata.o sata_promise.o obj-$(CONFIG_SCSI_SATA_QSTOR) += libata.o sata_qstor.o obj-$(CONFIG_SCSI_SATA_SIL) += libata.o sata_sil.o +obj-$(CONFIG_SCSI_SATA_SIL24) += libata.o sata_sil24.o obj-$(CONFIG_SCSI_SATA_VIA) += libata.o sata_via.o obj-$(CONFIG_SCSI_SATA_VITESSE) += libata.o sata_vsc.o obj-$(CONFIG_SCSI_SATA_SIS) += libata.o sata_sis.o diff --git a/drivers/scsi/ata_adma.c b/drivers/scsi/ata_adma.c new file mode 100644 --- /dev/null +++ b/drivers/scsi/ata_adma.c @@ -0,0 +1,789 @@ + +/* + * ata_adma.c - ADMA ATA support + * + * Copyright 2004-2005 Red Hat, Inc. + * Copyright 2004-2005 Jeff Garzik + * + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * libata documentation is available via 'make {ps|pdf}docs', + * as Documentation/DocBook/libata.* + * + * 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, + + APCI_TIM0 = 0x40, + APCI_TIM1 = 0x42, + APCI_UDMA_CTL = 0x48, + APCI_UDMA_TIMING = 0x4A, + APCI_IO_CFG = 0x54, + + ADMA_CTL = 0x0, + ADMA_STAT = 0x2, + ADMA_CPB_COUNT = 0x4, + ADMA_NEXT_CPB = 0xC, + + ADMA_AIEN = (1 << 8), + 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_piomode(struct ata_port *ap, struct ata_device *adev); +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_piomode = adma_set_piomode, + .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 = 0x3f, /* udma0-5 */ + .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(void __iomem *mmio, + unsigned int port_no) +{ + if (port_no == 0) + mmio += 0x80; + else + mmio += 0xA0; + + return mmio; +} + +static inline void __iomem *adma_ctl_block(struct ata_port *ap) +{ + return __adma_ctl_block(ap->host_set->mmio_base, ap->port_no); +} + +static const struct adma_timing { + unsigned int clk66, clk100; + u16 cyc_tim; +} adma_udma_modes[] = { + { 0, 0, 0 }, /* udma0 */ + { 0, 0, 1 }, /* udma1 */ + { 0, 0, 2 }, /* udma2 */ + { 1, 0, 1 }, /* udma3 */ + { 1, 0, 2 }, /* udma4 */ + { 1, 1, 1 }, /* udma5 */ +}; + +static void adma_set_dmamode(struct ata_port *ap, struct ata_device *adev) +{ + unsigned int udma = adev->dma_mode; /* FIXME: MWDMA too */ + struct pci_dev *dev = to_pci_dev(ap->host_set->dev); + unsigned int is_slave = (adev->devno != 0); + unsigned int shift = ap->hard_port_no ? 2 : 0; + const struct adma_timing *tim = &adma_udma_modes[udma]; + u8 tmp8, new8; + u16 tmp16, new16; + u32 tmp32, new32; + + if (is_slave) + shift++; + + /* + * turn on UDMA for port X, device Y + */ + pci_read_config_byte(dev, APCI_UDMA_CTL, &tmp8); + new8 = tmp8 | (1 << shift); + if (tmp8 != new8) + pci_write_config_byte(dev, APCI_UDMA_CTL, new8); + + /* + * set UDMA cycle time + */ + shift = ap->hard_port_no ? 8 : 0; + if (is_slave) + shift += 4; + + pci_read_config_word(dev, APCI_UDMA_TIMING, &tmp16); + new16 = (tmp16 & ~(3 << shift)) | tim->cyc_tim; + if (tmp16 != new16) + pci_write_config_word(dev, APCI_UDMA_TIMING, new16); + + /* + * set 66/100Mhz base clocks + */ + pci_read_config_dword(dev, APCI_IO_CFG, &tmp32); + new32 = tmp32; + + shift = ap->hard_port_no ? 2 : 0; /* 66 Mhz */ + if (is_slave) + shift++; + if (tim->clk66) + new32 |= (1 << shift); + else + new32 &= ~(1 << shift); + + shift = ap->hard_port_no ? 14 : 12; /* 100 Mhz */ + if (is_slave) + shift++; + if (tim->clk100) + new32 |= (1 << shift); + else + new32 &= ~(1 << shift); + + if (tmp32 != new32) + pci_write_config_dword(dev, APCI_IO_CFG, new32); +} + +static void adma_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + unsigned int pio = adev->pio_mode - XFER_PIO_0; + struct pci_dev *dev = to_pci_dev(ap->host_set->dev); + unsigned int is_slave = (adev->devno != 0); + u16 mask = is_slave ? 0x0f : 0xf0; + unsigned int reg = ap->hard_port_no ? APCI_TIM1 : APCI_TIM0; + void __iomem *mmio = adma_ctl_block(ap); + u16 tmp, new, timing1, timing2; + + timing1 = (1 << 15) | (1 << 13) | (1 << 8); /* pio3; decode enable */ + if (pio == 4) + timing1 |= (1 << 9); /* -> pio4 */ + + timing2 = (1 << 0) | (1 << 1); /* fast drv tim sel; IODRY sample pt. */ + if (adev->class == ATA_DEV_ATA) + timing2 |= (1 << 2); /* ATA or ATAPI device ? */ + if (is_slave) + timing2 <<= 4; + + pci_read_config_word(dev, reg, &tmp); + new = (tmp & mask) | timing1 | timing2; + if (tmp != new) + pci_write_config_word(dev, reg, new); + + tmp = readw(mmio + ADMA_CTL) & ~0x3; + tmp |= (pio - 1) & 0x3; + writew(tmp, mmio + ADMA_CTL); +} + +static void adma_host_stop(struct ata_host_set *host_set) +{ + struct adma_host_priv *hpriv = host_set->private_data; + kfree(hpriv); + + ata_host_stop(host_set); +} + +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); + u16 tmp; + + tmp = readw(mmio + ADMA_CTL); + writew((tmp & 0x3) | ADMA_AIEN, 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; + u16 tmp; + + writew(1, mmio + ADMA_CPB_COUNT); + writel((u32) pp->cpb_dma, mmio + ADMA_NEXT_CPB); + + tmp = readw(mmio + ADMA_CTL); + writew((tmp & 0x3) | 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; + u16 tmp16, new16; + u32 tmp32, new32; + + probe_ent->n_ports = N_PORTS; + + for (i = 0; i < probe_ent->n_ports; i++) + adma_setup_port(probe_ent, i); + + /* enable I/O address range decoding, disable Dev1 timing register */ + pci_read_config_word(pdev, APCI_TIM0, &tmp16); + new16 = (tmp16 & ~(1 << 14)) | (1 << 15); + if (new16 != tmp16) + pci_write_config_word(pdev, APCI_TIM0, new16); + pci_read_config_word(pdev, APCI_TIM1, &tmp16); + new16 = (tmp16 & ~(1 << 14)) | (1 << 15); + if (new16 != tmp16) + pci_write_config_word(pdev, APCI_TIM1, new16); + + /* make sure ATA signal pins are not driven low or tri-stated */ + pci_read_config_dword(pdev, APCI_IO_CFG, &tmp32); + new32 = tmp32 & ~(0xfU << 16); + if (new32 != tmp32) + pci_write_config_dword(pdev, APCI_IO_CFG, new32); + + for (i = 0; i < probe_ent->n_ports; i++) { + void __iomem *mmio = __adma_ctl_block(probe_ent->mmio_base, i); + u16 tmp; + + /* enable interrupt, clear reset if not already clear */ + tmp = readw(mmio + ADMA_CTL); + writew(tmp & 0x3, mmio + ADMA_CTL); + } + + 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_set_mwi(pdev); + if (rc) + goto err_out; + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_out_mwi; + 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_mwi: + pci_clear_mwi(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 --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -62,6 +62,7 @@ static unsigned int ata_busy_sleep (struct ata_port *ap, unsigned long tmout_pat, unsigned long tmout); +static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev); static void ata_set_mode(struct ata_port *ap); static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev); static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift); @@ -1131,7 +1132,7 @@ static inline void ata_dump_id(struct at static void ata_dev_identify(struct ata_port *ap, unsigned int device) { struct ata_device *dev = &ap->device[device]; - unsigned int i; + unsigned int major_version; u16 tmp; unsigned long xfer_modes; u8 status; @@ -1229,9 +1230,9 @@ retry: * common ATA, ATAPI feature tests */ - /* we require LBA and DMA support (bits 8 & 9 of word 49) */ - if (!ata_id_has_dma(dev->id) || !ata_id_has_lba(dev->id)) { - printk(KERN_DEBUG "ata%u: no dma/lba\n", ap->id); + /* we require DMA support (bits 8 of word 49) */ + if (!ata_id_has_dma(dev->id)) { + printk(KERN_DEBUG "ata%u: no dma\n", ap->id); goto err_out_nosup; } @@ -1251,32 +1252,69 @@ retry: if (!ata_id_is_ata(dev->id)) /* sanity check */ goto err_out_nosup; + /* get major version */ tmp = dev->id[ATA_ID_MAJOR_VER]; - for (i = 14; i >= 1; i--) - if (tmp & (1 << i)) + for (major_version = 14; major_version >= 1; major_version--) + if (tmp & (1 << major_version)) break; - /* we require at least ATA-3 */ - if (i < 3) { - printk(KERN_DEBUG "ata%u: no ATA-3\n", ap->id); - goto err_out_nosup; - } + /* + * The exact sequence expected by certain pre-ATA4 drives is: + * SRST RESET + * IDENTIFY + * INITIALIZE DEVICE PARAMETERS + * anything else.. + * Some drives were very specific about that exact sequence. + */ + if (major_version < 4 || (!ata_id_has_lba(dev->id))) + ata_dev_init_params(ap, dev); + + if (ata_id_has_lba(dev->id)) { + dev->flags |= ATA_DFLAG_LBA; + + if (ata_id_has_lba48(dev->id)) { + dev->flags |= ATA_DFLAG_LBA48; + dev->n_sectors = ata_id_u64(dev->id, 100); + } else { + dev->n_sectors = ata_id_u32(dev->id, 60); + } + + /* print device info to dmesg */ + printk(KERN_INFO "ata%u: dev %u ATA-%d, max %s, %Lu sectors:%s\n", + ap->id, device, + major_version, + ata_mode_string(xfer_modes), + (unsigned long long)dev->n_sectors, + dev->flags & ATA_DFLAG_LBA48 ? " LBA48" : " LBA"); + } else { + /* CHS */ + + /* Default translation */ + dev->cylinders = dev->id[1]; + dev->heads = dev->id[3]; + dev->sectors = dev->id[6]; + dev->n_sectors = dev->cylinders * dev->heads * dev->sectors; + + if (ata_id_current_chs_valid(dev->id)) { + /* Current CHS translation is valid. */ + dev->cylinders = dev->id[54]; + dev->heads = dev->id[55]; + dev->sectors = dev->id[56]; + + dev->n_sectors = ata_id_u32(dev->id, 57); + } + + /* print device info to dmesg */ + printk(KERN_INFO "ata%u: dev %u ATA-%d, max %s, %Lu sectors: CHS %d/%d/%d\n", + ap->id, device, + major_version, + ata_mode_string(xfer_modes), + (unsigned long long)dev->n_sectors, + (int)dev->cylinders, (int)dev->heads, (int)dev->sectors); - if (ata_id_has_lba48(dev->id)) { - dev->flags |= ATA_DFLAG_LBA48; - dev->n_sectors = ata_id_u64(dev->id, 100); - } else { - dev->n_sectors = ata_id_u32(dev->id, 60); } ap->host->max_cmd_len = 16; - - /* print device info to dmesg */ - printk(KERN_INFO "ata%u: dev %u ATA, max %s, %Lu sectors:%s\n", - ap->id, device, - ata_mode_string(xfer_modes), - (unsigned long long)dev->n_sectors, - dev->flags & ATA_DFLAG_LBA48 ? " lba48" : ""); } /* ATAPI-specific feature tests */ @@ -2144,6 +2182,54 @@ static void ata_dev_set_xfermode(struct } /** + * ata_dev_init_params - Issue INIT DEV PARAMS command + * @ap: Port associated with device @dev + * @dev: Device to which command will be sent + * + * LOCKING: + */ + +static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev) +{ + DECLARE_COMPLETION(wait); + struct ata_queued_cmd *qc; + int rc; + unsigned long flags; + u16 sectors = dev->id[6]; + u16 heads = dev->id[3]; + + /* Number of sectors per track 1-255. Number of heads 1-16 */ + if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16) + return; + + /* set up init dev params taskfile */ + DPRINTK("init dev params \n"); + + qc = ata_qc_new_init(ap, dev); + BUG_ON(qc == NULL); + + qc->tf.command = ATA_CMD_INIT_DEV_PARAMS; + qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + qc->tf.protocol = ATA_PROT_NODATA; + qc->tf.nsect = sectors; + qc->tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */ + + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_noop; + + spin_lock_irqsave(&ap->host_set->lock, flags); + rc = ata_qc_issue(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + if (rc) + ata_port_disable(ap); + else + wait_for_completion(&wait); + + DPRINTK("EXIT\n"); +} + +/** * ata_sg_clean - Unmap DMA memory associated with command * @qc: Command containing DMA memory to be released * @@ -3147,8 +3233,12 @@ struct ata_queued_cmd *ata_qc_new_init(s ata_tf_init(ap, &qc->tf, dev->devno); - if (dev->flags & ATA_DFLAG_LBA48) - qc->tf.flags |= ATA_TFLAG_LBA48; + if (dev->flags & ATA_DFLAG_LBA) { + qc->tf.flags |= ATA_TFLAG_LBA; + + if (dev->flags & ATA_DFLAG_LBA48) + qc->tf.flags |= ATA_TFLAG_LBA48; + } } return qc; @@ -3921,6 +4011,7 @@ static void ata_host_init(struct ata_por 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; diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -40,10 +40,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); @@ -78,6 +81,148 @@ int ata_std_bios_param(struct scsi_devic 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 */ + scsi_cmd[2] = 0x0e; /* no off.line or cc, read from dev, + block count in sector count field */ + sreq->sr_data_direction = DMA_FROM_DEVICE; + } else { + scsi_cmd[1] = (3 << 1); /* Non-data */ + /* scsi_cmd[2] is already 0 -- no off.line, cc, or data xfer */ + sreq->sr_data_direction = DMA_NONE; + } + + scsi_cmd[0] = ATA_16; + + 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] is already 0 -- no off.line, cc, or data xfer */ + 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; @@ -107,6 +252,16 @@ int ata_scsi_ioctl(struct scsi_device *s return -EINVAL; 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; @@ -165,24 +320,69 @@ struct ata_queued_cmd *ata_scsi_qc_new(s } /** + * ata_dump_status - user friendly display of error info + * @id: id of the port in question + * @tf: ptr to filled out taskfile + * + * Decode and dump the ATA error/status registers for the user so + * that they have some idea what really happened at the non + * make-believe layer. + * + * LOCKING: + * inherited from caller + */ +void ata_dump_status(unsigned id, struct ata_taskfile *tf) +{ + u8 stat = tf->command, err = tf->feature; + + printk(KERN_WARNING "ata%u: status=0x%02x { ", id, stat); + if (stat & ATA_BUSY) { + printk("Busy }\n"); /* Data is not valid in this case */ + } else { + if (stat & 0x40) printk("DriveReady "); + if (stat & 0x20) printk("DeviceFault "); + if (stat & 0x10) printk("SeekComplete "); + if (stat & 0x08) printk("DataRequest "); + if (stat & 0x04) printk("CorrectedError "); + if (stat & 0x02) printk("Index "); + if (stat & 0x01) printk("Error "); + printk("}\n"); + + if (err) { + printk(KERN_WARNING "ata%u: error=0x%02x { ", id, err); + if (err & 0x04) printk("DriveStatusError "); + if (err & 0x80) { + if (err & 0x04) printk("BadCRC "); + else printk("Sector "); + } + if (err & 0x40) printk("UncorrectableError "); + if (err & 0x10) printk("SectorIdNotFound "); + if (err & 0x02) printk("TrackZeroNotFound "); + if (err & 0x01) printk("AddrMarkNotFound "); + printk("}\n"); + } + } +} + +/** * ata_to_sense_error - convert ATA error to SCSI error - * @qc: Command that we are erroring out * @drv_stat: value contained in ATA status register + * @drv_err: value contained in ATA error register + * @sk: the sense key we'll fill out + * @asc: the additional sense code we'll fill out + * @ascq: the additional sense code qualifier we'll fill out * - * Converts an ATA error into a SCSI error. While we are at it - * we decode and dump the ATA error for the user so that they - * have some idea what really happened at the non make-believe - * layer. + * Converts an ATA error into a SCSI error. Fill out pointers to + * SK, ASC, and ASCQ bytes for later use in fixed or descriptor + * format sense blocks. * * LOCKING: * spin_lock_irqsave(host_set lock) */ - -void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) +void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc, + u8 *ascq) { - struct scsi_cmnd *cmd = qc->scsicmd; - u8 err = 0; - unsigned char *sb = cmd->sense_buffer; + int i; /* Based on the 3ware driver translation table */ static unsigned char sense_table[][4] = { /* BBD|ECC|ID|MAR */ @@ -223,105 +423,187 @@ void ata_to_sense_error(struct ata_queue {0x04, RECOVERED_ERROR, 0x11, 0x00}, // Recovered ECC error Medium error, recovered {0xFF, 0xFF, 0xFF, 0xFF}, // END mark }; - int i = 0; - - cmd->result = SAM_STAT_CHECK_CONDITION; /* * Is this an error we can process/parse */ + if (drv_stat & ATA_BUSY) { + drv_err = 0; /* Ignore the err bits, they're invalid */ + } - if(drv_stat & ATA_ERR) - /* Read the err bits */ - err = ata_chk_err(qc->ap); - - /* Display the ATA level error info */ - - printk(KERN_WARNING "ata%u: status=0x%02x { ", qc->ap->id, drv_stat); - if(drv_stat & 0x80) - { - printk("Busy "); - err = 0; /* Data is not valid in this case */ + if (drv_err) { + /* Look for drv_err */ + for (i = 0; sense_table[i][0] != 0xFF; i++) { + /* Look for best matches first */ + if ((sense_table[i][0] & drv_err) == + sense_table[i][0]) { + *sk = sense_table[i][1]; + *asc = sense_table[i][2]; + *ascq = sense_table[i][3]; + goto translate_done; + } + } + /* No immediate match */ + printk(KERN_WARNING "ata%u: no sense translation for " + "error 0x%02x\n", id, drv_err); } - else { - if(drv_stat & 0x40) printk("DriveReady "); - if(drv_stat & 0x20) printk("DeviceFault "); - if(drv_stat & 0x10) printk("SeekComplete "); - if(drv_stat & 0x08) printk("DataRequest "); - if(drv_stat & 0x04) printk("CorrectedError "); - if(drv_stat & 0x02) printk("Index "); - if(drv_stat & 0x01) printk("Error "); - } - printk("}\n"); - - if(err) - { - printk(KERN_WARNING "ata%u: error=0x%02x { ", qc->ap->id, err); - if(err & 0x04) printk("DriveStatusError "); - if(err & 0x80) - { - if(err & 0x04) - printk("BadCRC "); - else - printk("Sector "); + + /* Fall back to interpreting status bits */ + for (i = 0; stat_table[i][0] != 0xFF; i++) { + if (stat_table[i][0] & drv_stat) { + *sk = stat_table[i][1]; + *asc = stat_table[i][2]; + *ascq = stat_table[i][3]; + goto translate_done; } - if(err & 0x40) printk("UncorrectableError "); - if(err & 0x10) printk("SectorIdNotFound "); - if(err & 0x02) printk("TrackZeroNotFound "); - if(err & 0x01) printk("AddrMarkNotFound "); - printk("}\n"); + } + /* No error? Undecoded? */ + printk(KERN_WARNING "ata%u: no sense translation for status: 0x%02x\n", + id, drv_stat); + + /* For our last chance pick, use medium read error because + * it's much more common than an ATA drive telling you a write + * has failed. + */ + *sk = MEDIUM_ERROR; + *asc = 0x11; /* "unrecovered read error" */ + *ascq = 0x04; /* "auto-reallocation failed" */ + + translate_done: + printk(KERN_ERR "ata%u: translated ATA stat/err 0x%02x/%02x to " + "SCSI SK/ASC/ASCQ 0x%x/%02x/%02x\n", id, drv_stat, drv_err, + *sk, *asc, *ascq); + return; +} + +/* + * ata_gen_ata_desc_sense - Generate check condition sense block. + * @qc: Command that completed. + * + * This function is specific to the ATA descriptor format sense + * block specified for the ATA pass through commands. 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_gen_ata_desc_sense(struct ata_queued_cmd *qc) +{ + struct scsi_cmnd *cmd = qc->scsicmd; + struct ata_taskfile *tf = &qc->tf; + unsigned char *sb = cmd->sense_buffer; + unsigned char *desc = sb + 8; + + memset(sb, 0, SCSI_SENSE_BUFFERSIZE); + + cmd->result = SAM_STAT_CHECK_CONDITION; + + /* + * Read the controller registers. + */ + assert(NULL != qc->ap->ops->tf_read); + qc->ap->ops->tf_read(qc->ap, tf); - /* Should we dump sector info here too ?? */ + /* + * Use ata_to_sense_error() to map status register bits + * onto sense key, asc & ascq. + */ + if (unlikely(tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ))) { + ata_to_sense_error(qc->ap->id, tf->command, tf->feature, + &sb[1], &sb[2], &sb[3]); + sb[1] &= 0x0f; } + /* + * Sense data is current and format is descriptor. + */ + sb[0] = 0x72; + + desc[0] = 0x09; - /* Look for err */ - while(sense_table[i][0] != 0xFF) - { - /* Look for best matches first */ - if((sense_table[i][0] & err) == sense_table[i][0]) - { - sb[0] = 0x70; - sb[2] = sense_table[i][1]; - sb[7] = 0x0a; - sb[12] = sense_table[i][2]; - sb[13] = sense_table[i][3]; - return; - } - i++; + /* + * 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; + + /* + * Copy registers into sense buffer. + */ + desc[2] = 0x00; + desc[3] = tf->feature; /* == error reg */ + desc[5] = tf->nsect; + desc[7] = tf->lbal; + desc[9] = tf->lbam; + desc[11] = tf->lbah; + desc[12] = tf->device; + desc[13] = tf->command; /* == status reg */ + + /* + * 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; } - /* No immediate match */ - if(err) - printk(KERN_DEBUG "ata%u: no sense translation for 0x%02x\n", qc->ap->id, err); +} - i = 0; - /* Fall back to interpreting status bits */ - while(stat_table[i][0] != 0xFF) - { - if(stat_table[i][0] & drv_stat) - { - sb[0] = 0x70; - sb[2] = stat_table[i][1]; - sb[7] = 0x0a; - sb[12] = stat_table[i][2]; - sb[13] = stat_table[i][3]; - return; - } - i++; +/** + * ata_gen_fixed_sense - generate a SCSI fixed sense block + * @qc: Command that we are erroring out + * + * Leverage ata_to_sense_error() to give us the codes. Fit our + * LBA in here if there's room. + * + * LOCKING: + * inherited from caller + */ +void ata_gen_fixed_sense(struct ata_queued_cmd *qc) +{ + struct scsi_cmnd *cmd = qc->scsicmd; + struct ata_taskfile *tf = &qc->tf; + unsigned char *sb = cmd->sense_buffer; + + memset(sb, 0, SCSI_SENSE_BUFFERSIZE); + + cmd->result = SAM_STAT_CHECK_CONDITION; + + /* + * Read the controller registers. + */ + assert(NULL != qc->ap->ops->tf_read); + qc->ap->ops->tf_read(qc->ap, tf); + + /* + * Use ata_to_sense_error() to map status register bits + * onto sense key, asc & ascq. + */ + if (unlikely(tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ))) { + ata_to_sense_error(qc->ap->id, tf->command, tf->feature, + &sb[2], &sb[12], &sb[13]); + sb[2] &= 0x0f; } - /* No error ?? */ - printk(KERN_ERR "ata%u: called with no error (%02X)!\n", qc->ap->id, drv_stat); - /* additional-sense-code[-qualifier] */ sb[0] = 0x70; - sb[2] = MEDIUM_ERROR; - sb[7] = 0x0A; - if (cmd->sc_data_direction == DMA_FROM_DEVICE) { - sb[12] = 0x11; /* "unrecovered read error" */ - sb[13] = 0x04; - } else { - sb[12] = 0x0C; /* "write error - */ - sb[13] = 0x02; /* auto-reallocation failed" */ + sb[7] = 0x0a; + +#if 0 /* when C/H/S support is merged */ + if (tf->flags & ATA_TFLAG_LBA && !(tf->flags & ATA_TFLAG_LBA48)) { +#endif + if (!(tf->flags & ATA_TFLAG_LBA48)) { + /* A small (28b) LBA will fit in the 32b info field */ + sb[0] |= 0x80; /* set valid bit */ + sb[3] = tf->device & 0x0f; + sb[4] = tf->lbah; + sb[5] = tf->lbam; + sb[6] = tf->lbal; } } @@ -504,77 +786,107 @@ static unsigned int ata_scsi_flush_xlat( static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) { struct ata_taskfile *tf = &qc->tf; + struct ata_device *dev = qc->dev; + unsigned int lba = tf->flags & ATA_TFLAG_LBA; unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; u64 dev_sectors = qc->dev->n_sectors; - u64 sect = 0; - u32 n_sect = 0; + u64 block = 0; + u32 n_block = 0; tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; tf->protocol = ATA_PROT_NODATA; - tf->device |= ATA_LBA; if (scsicmd[0] == VERIFY) { - sect |= ((u64)scsicmd[2]) << 24; - sect |= ((u64)scsicmd[3]) << 16; - sect |= ((u64)scsicmd[4]) << 8; - sect |= ((u64)scsicmd[5]); + block |= ((u64)scsicmd[2]) << 24; + block |= ((u64)scsicmd[3]) << 16; + block |= ((u64)scsicmd[4]) << 8; + block |= ((u64)scsicmd[5]); - n_sect |= ((u32)scsicmd[7]) << 8; - n_sect |= ((u32)scsicmd[8]); + n_block |= ((u32)scsicmd[7]) << 8; + n_block |= ((u32)scsicmd[8]); } else if (scsicmd[0] == VERIFY_16) { - sect |= ((u64)scsicmd[2]) << 56; - sect |= ((u64)scsicmd[3]) << 48; - sect |= ((u64)scsicmd[4]) << 40; - sect |= ((u64)scsicmd[5]) << 32; - sect |= ((u64)scsicmd[6]) << 24; - sect |= ((u64)scsicmd[7]) << 16; - sect |= ((u64)scsicmd[8]) << 8; - sect |= ((u64)scsicmd[9]); - - n_sect |= ((u32)scsicmd[10]) << 24; - n_sect |= ((u32)scsicmd[11]) << 16; - n_sect |= ((u32)scsicmd[12]) << 8; - n_sect |= ((u32)scsicmd[13]); + block |= ((u64)scsicmd[2]) << 56; + block |= ((u64)scsicmd[3]) << 48; + block |= ((u64)scsicmd[4]) << 40; + block |= ((u64)scsicmd[5]) << 32; + block |= ((u64)scsicmd[6]) << 24; + block |= ((u64)scsicmd[7]) << 16; + block |= ((u64)scsicmd[8]) << 8; + block |= ((u64)scsicmd[9]); + + n_block |= ((u32)scsicmd[10]) << 24; + n_block |= ((u32)scsicmd[11]) << 16; + n_block |= ((u32)scsicmd[12]) << 8; + n_block |= ((u32)scsicmd[13]); } else return 1; - if (!n_sect) + if (!n_block) return 1; - if (sect >= dev_sectors) + if (block >= dev_sectors) return 1; - if ((sect + n_sect) > dev_sectors) + if ((block + n_block) > dev_sectors) return 1; if (lba48) { - if (n_sect > (64 * 1024)) + if (n_block > (64 * 1024)) return 1; } else { - if (n_sect > 256) + if (n_block > 256) return 1; } - if (lba48) { - tf->command = ATA_CMD_VERIFY_EXT; + if (lba) { + if (lba48) { + tf->command = ATA_CMD_VERIFY_EXT; - tf->hob_nsect = (n_sect >> 8) & 0xff; + tf->hob_nsect = (n_block >> 8) & 0xff; - tf->hob_lbah = (sect >> 40) & 0xff; - tf->hob_lbam = (sect >> 32) & 0xff; - tf->hob_lbal = (sect >> 24) & 0xff; - } else { - tf->command = ATA_CMD_VERIFY; + tf->hob_lbah = (block >> 40) & 0xff; + tf->hob_lbam = (block >> 32) & 0xff; + tf->hob_lbal = (block >> 24) & 0xff; + } else { + tf->command = ATA_CMD_VERIFY; - tf->device |= (sect >> 24) & 0xf; - } + tf->device |= (block >> 24) & 0xf; + } + + tf->nsect = n_block & 0xff; - tf->nsect = n_sect & 0xff; + tf->lbah = (block >> 16) & 0xff; + tf->lbam = (block >> 8) & 0xff; + tf->lbal = block & 0xff; - tf->lbah = (sect >> 16) & 0xff; - tf->lbam = (sect >> 8) & 0xff; - tf->lbal = sect & 0xff; + tf->device |= ATA_LBA; + } else { + /* CHS */ + u32 sect, head, cyl, track; + + /* Convert LBA to CHS */ + track = (u32)block / dev->sectors; + cyl = track / dev->heads; + head = track % dev->heads; + sect = (u32)block % dev->sectors + 1; + + DPRINTK("block[%u] track[%u] cyl[%u] head[%u] sect[%u] \n", (u32)block, track, cyl, head, sect); + + /* Check whether the converted CHS can fit. + Cylinder: 0-65535 + Head: 0-15 + Sector: 1-255*/ + if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) + return 1; + + tf->command = ATA_CMD_VERIFY; + tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */ + tf->lbal = sect; + tf->lbam = cyl; + tf->lbah = cyl >> 8; + tf->device |= head; + } return 0; } @@ -602,11 +914,14 @@ static unsigned int ata_scsi_verify_xlat static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) { struct ata_taskfile *tf = &qc->tf; + struct ata_device *dev = qc->dev; + unsigned int lba = tf->flags & ATA_TFLAG_LBA; unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; + u64 block = 0; + u32 n_block = 0; tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; tf->protocol = qc->dev->xfer_protocol; - tf->device |= ATA_LBA; if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 || scsicmd[0] == READ_16) { @@ -616,100 +931,149 @@ static unsigned int ata_scsi_rw_xlat(str tf->flags |= ATA_TFLAG_WRITE; } + /* Calculate the SCSI LBA and transfer length. */ if (scsicmd[0] == READ_10 || scsicmd[0] == WRITE_10) { - if (lba48) { - tf->hob_nsect = scsicmd[7]; - tf->hob_lbal = scsicmd[2]; - - qc->nsect = ((unsigned int)scsicmd[7] << 8) | - scsicmd[8]; - } else { - /* if we don't support LBA48 addressing, the request - * -may- be too large. */ - if ((scsicmd[2] & 0xf0) || scsicmd[7]) - return 1; - - /* stores LBA27:24 in lower 4 bits of device reg */ - tf->device |= scsicmd[2]; + block |= ((u64)scsicmd[2]) << 24; + block |= ((u64)scsicmd[3]) << 16; + block |= ((u64)scsicmd[4]) << 8; + block |= ((u64)scsicmd[5]); - qc->nsect = scsicmd[8]; - } - - tf->nsect = scsicmd[8]; - tf->lbal = scsicmd[5]; - tf->lbam = scsicmd[4]; - tf->lbah = scsicmd[3]; + n_block |= ((u32)scsicmd[7]) << 8; + n_block |= ((u32)scsicmd[8]); VPRINTK("ten-byte command\n"); - if (qc->nsect == 0) /* we don't support length==0 cmds */ - return 1; - return 0; - } - - if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) { - qc->nsect = tf->nsect = scsicmd[4]; - if (!qc->nsect) { - qc->nsect = 256; - if (lba48) - tf->hob_nsect = 1; - } - - tf->lbal = scsicmd[3]; - tf->lbam = scsicmd[2]; - tf->lbah = scsicmd[1] & 0x1f; /* mask out reserved bits */ - + } else if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) { + block |= ((u64)scsicmd[2]) << 8; + block |= ((u64)scsicmd[3]); + + n_block |= ((u32)scsicmd[4]); + if (!n_block) + n_block = 256; + VPRINTK("six-byte command\n"); - return 0; + } else if (scsicmd[0] == READ_16 || scsicmd[0] == WRITE_16) { + block |= ((u64)scsicmd[2]) << 56; + block |= ((u64)scsicmd[3]) << 48; + block |= ((u64)scsicmd[4]) << 40; + block |= ((u64)scsicmd[5]) << 32; + block |= ((u64)scsicmd[6]) << 24; + block |= ((u64)scsicmd[7]) << 16; + block |= ((u64)scsicmd[8]) << 8; + block |= ((u64)scsicmd[9]); + + n_block |= ((u32)scsicmd[10]) << 24; + n_block |= ((u32)scsicmd[11]) << 16; + n_block |= ((u32)scsicmd[12]) << 8; + n_block |= ((u32)scsicmd[13]); + + VPRINTK("sixteen-byte command\n"); + } else { + DPRINTK("no-byte command\n"); + return 1; } - if (scsicmd[0] == READ_16 || scsicmd[0] == WRITE_16) { - /* rule out impossible LBAs and sector counts */ - if (scsicmd[2] || scsicmd[3] || scsicmd[10] || scsicmd[11]) - return 1; + /* Check and compose ATA command */ + if (!n_block) + /* In ATA, sector count 0 means 256 or 65536 sectors, not 0 sectors. */ + return 1; + if (lba) { if (lba48) { - tf->hob_nsect = scsicmd[12]; - tf->hob_lbal = scsicmd[6]; - tf->hob_lbam = scsicmd[5]; - tf->hob_lbah = scsicmd[4]; - - qc->nsect = ((unsigned int)scsicmd[12] << 8) | - scsicmd[13]; - } else { - /* once again, filter out impossible non-zero values */ - if (scsicmd[4] || scsicmd[5] || scsicmd[12] || - (scsicmd[6] & 0xf0)) + /* The request -may- be too large for LBA48. */ + if ((block >> 48) || (n_block > 65536)) return 1; - /* stores LBA27:24 in lower 4 bits of device reg */ - tf->device |= scsicmd[6]; + tf->hob_nsect = (n_block >> 8) & 0xff; + + tf->hob_lbah = (block >> 40) & 0xff; + tf->hob_lbam = (block >> 32) & 0xff; + tf->hob_lbal = (block >> 24) & 0xff; + } else { + /* LBA28 */ - qc->nsect = scsicmd[13]; + /* The request -may- be too large for LBA28. */ + if ((block >> 28) || (n_block > 256)) + return 1; + + tf->device |= (block >> 24) & 0xf; } + + qc->nsect = n_block; + tf->nsect = n_block & 0xff; + + tf->lbah = (block >> 16) & 0xff; + tf->lbam = (block >> 8) & 0xff; + tf->lbal = block & 0xff; - tf->nsect = scsicmd[13]; - tf->lbal = scsicmd[9]; - tf->lbam = scsicmd[8]; - tf->lbah = scsicmd[7]; + tf->device |= ATA_LBA; + } else { + /* CHS */ + u32 sect, head, cyl, track; - VPRINTK("sixteen-byte command\n"); - if (qc->nsect == 0) /* we don't support length==0 cmds */ + /* The request -may- be too large for CHS addressing. */ + if ((block >> 28) || (n_block > 256)) return 1; - return 0; + + /* Convert LBA to CHS */ + track = (u32)block / dev->sectors; + cyl = track / dev->heads; + head = track % dev->heads; + sect = (u32)block % dev->sectors + 1; + + DPRINTK("block[%u] track[%u] cyl[%u] head[%u] sect[%u] \n", + (u32)block, track, cyl, head, sect); + + /* Check whether the converted CHS can fit. + Cylinder: 0-65535 + Head: 0-15 + Sector: 1-255*/ + if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) + return 1; + + qc->nsect = n_block; + tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */ + tf->lbal = sect; + tf->lbam = cyl; + tf->lbah = cyl >> 8; + tf->device |= head; } - DPRINTK("no-byte command\n"); - return 1; + return 0; } static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) { struct scsi_cmnd *cmd = qc->scsicmd; + int need_sense = drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ); - if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) - ata_to_sense_error(qc, drv_stat); - else - cmd->result = SAM_STAT_GOOD; + /* For ATA pass thru (SAT) commands, generate a sense block if + * user mandated it or if there's an error. Note that if we + * generate because the user forced us to, a 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) || need_sense)) { + ata_gen_ata_desc_sense(qc); + } else { + if (!need_sense) { + cmd->result = SAM_STAT_GOOD; + } else { + /* TODO: decide which descriptor format to use + * for 48b LBA devices and call that here + * instead of the fixed desc, which is only + * good for smaller LBA (and maybe CHS?) + * devices. + */ + ata_gen_fixed_sense(qc); + } + } + + if (need_sense) { + /* The ata_gen_..._sense routines fill in tf */ + ata_dump_status(qc->ap->id, &qc->tf); + } qc->scsidone(cmd); @@ -771,7 +1135,6 @@ static void ata_scsi_translate(struct at if (xlat_func(qc, scsicmd)) goto err_out; - /* select device, send command to hardware */ if (ata_qc_issue(qc)) goto err_out; @@ -1246,10 +1609,20 @@ unsigned int ata_scsiop_read_cap(struct VPRINTK("ENTER\n"); - if (ata_id_has_lba48(args->id)) - n_sectors = ata_id_u64(args->id, 100); - else - n_sectors = ata_id_u32(args->id, 60); + if (ata_id_has_lba(args->id)) { + if (ata_id_has_lba48(args->id)) + n_sectors = ata_id_u64(args->id, 100); + else + n_sectors = ata_id_u32(args->id, 60); + } else { + /* CHS default translation */ + n_sectors = args->id[1] * args->id[3] * args->id[6]; + + if (ata_id_current_chs_valid(args->id)) + /* CHS current translation */ + n_sectors = ata_id_u32(args->id, 57); + } + n_sectors--; /* ATA TotalUserSectors - 1 */ if (args->cmd->cmnd[0] == READ_CAPACITY) { @@ -1478,6 +1851,143 @@ ata_scsi_find_dev(struct ata_port *ap, s 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]; + } + + /* + * Filter SET_FEATURES - XFER MODE command -- otherwise, + * SET_FEATURES - XFER MODE must be preceded/succeeded + * by an update to hardware-specific registers for each + * controller (i.e. the reason for ->set_piomode(), + * ->set_dmamode(), and ->post_set_mode() hooks). + */ + if ((tf->command == ATA_CMD_SET_FEATURES) + && (tf->feature == SETFEATURES_XFER)) + return 1; + + /* + * 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 == DMA_TO_DEVICE) + 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 @@ -1510,6 +2020,11 @@ static inline ata_xlat_func_t ata_get_xl case VERIFY: case VERIFY_16: return ata_scsi_verify_xlat; + + case ATA_12: + case ATA_16: + return ata_scsi_pass_thru; + case START_STOP: return ata_scsi_start_stop_xlat; } @@ -1668,7 +2183,7 @@ void ata_scsi_simulate(u16 *id, ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns); break; - /* mandantory commands we haven't implemented yet */ + /* mandatory commands we haven't implemented yet */ case REQUEST_SENSE: /* all other commands */ diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -48,10 +48,11 @@ extern void ata_dev_select(struct ata_po 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 */ -extern void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat); extern int ata_scsi_error(struct Scsi_Host *host); extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen); diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -84,6 +84,7 @@ static irqreturn_t pdc_interrupt (int ir static void pdc_eng_timeout(struct ata_port *ap); static int pdc_port_start(struct ata_port *ap); static void pdc_port_stop(struct ata_port *ap); +static void pdc_pata_cbl_detect(struct ata_port *ap); static void pdc_pata_phy_reset(struct ata_port *ap); static void pdc_sata_phy_reset(struct ata_port *ap); static void pdc_qc_prep(struct ata_queued_cmd *qc); @@ -161,7 +162,7 @@ static struct ata_port_info pdc_port_inf /* 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 */ @@ -306,17 +307,34 @@ static void pdc_reset_port(struct ata_po static void pdc_sata_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) { - /* FIXME: add cable detect. Don't assume 40-pin cable */ - ap->cbl = ATA_CBL_PATA40; - ap->udma_mask &= ATA_UDMA_MASK_40C; + pdc_pata_cbl_detect(ap); - pdc_reset_port(ap); ata_port_probe(ap); + ata_bus_reset(ap); } @@ -629,6 +647,7 @@ static int pdc_ata_init_one (struct pci_ unsigned int board_idx = (unsigned int) ent->driver_data; int pci_dev_busy = 0; int rc; + u8 tmp; if (!printed_version++) printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); @@ -688,6 +707,9 @@ static int pdc_ata_init_one (struct pci_ 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: @@ -698,9 +720,25 @@ static int pdc_ata_init_one (struct pci_ 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; case board_20619: probe_ent->n_ports = 4; diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c new file mode 100644 --- /dev/null +++ b/drivers/scsi/sata_sil24.c @@ -0,0 +1,785 @@ +/* + * sata_sil24.c - Driver for Silicon Image 3124/3132 SATA-2 controllers + * + * Copyright 2005 Tejun Heo + * + * Based on preview driver from Silicon Image. + * + * NOTE: No NCQ/ATAPI support yet. The preview driver didn't support + * NCQ nor ATAPI, and, unfortunately, I couldn't find out how to make + * those work. Enabling those shouldn't be difficult. Basic + * structure is all there (in libata-dev tree). If you have any + * information about this hardware, please contact me or linux-ide. + * Info is needed on... + * + * - How to issue tagged commands and turn on sactive on issue accordingly. + * - Where to put an ATAPI command and how to tell the device to send it. + * - How to enable/use 64bit. + * + * 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, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include +#include + +#define DRV_NAME "sata_sil24" +#define DRV_VERSION "0.20" /* Silicon Image's preview driver was 0.10 */ + +#define NR_PORTS 4 + +/* + * Port request block (PRB) 32 bytes + */ +struct sil24_prb { + u16 ctrl; + u16 prot; + u32 rx_cnt; + u8 fis[6 * 4]; +}; + +/* + * Scatter gather entry (SGE) 16 bytes + */ +struct sil24_sge { + u64 addr; + u32 cnt; + u32 flags; +}; + +/* + * Port multiplier + */ +struct sil24_port_multiplier { + u32 diag; + u32 sactive; +}; + +enum { + /* + * Global controller registers (128 bytes @ BAR0) + */ + /* 32 bit regs */ + HOST_SLOT_STAT = 0x00, /* 32 bit slot stat * 4 */ + HOST_CTRL = 0x40, + HOST_IRQ_STAT = 0x44, + HOST_PHY_CFG = 0x48, + HOST_BIST_CTRL = 0x50, + HOST_BIST_PTRN = 0x54, + HOST_BIST_STAT = 0x58, + HOST_MEM_BIST_STAT = 0x5c, + HOST_FLASH_CMD = 0x70, + /* 8 bit regs */ + HOST_FLASH_DATA = 0x74, + HOST_TRANSITION_DETECT = 0x75, + HOST_GPIO_CTRL = 0x76, + HOST_I2C_ADDR = 0x78, /* 32 bit */ + HOST_I2C_DATA = 0x7c, + HOST_I2C_XFER_CNT = 0x7e, + HOST_I2C_CTRL = 0x7f, + + /* HOST_SLOT_STAT bits */ + HOST_SSTAT_ATTN = (1 << 31), + + /* + * Port registers + * (8192 bytes @ +0x0000, +0x2000, +0x4000 and +0x6000 @ BAR2) + */ + PORT_REGS_SIZE = 0x2000, + PORT_PRB = 0x0000, /* (32 bytes PRB + 16 bytes SGEs * 6) * 31 (3968 bytes) */ + + PORT_PM = 0x0f80, /* 8 bytes PM * 16 (128 bytes) */ + /* 32 bit regs */ + PORT_CTRL_STAT = 0x1000, /* write: ctrl-set, read: stat */ + PORT_CTRL_CLR = 0x1004, /* write: ctrl-clear */ + PORT_IRQ_STAT = 0x1008, /* high: status, low: interrupt */ + PORT_IRQ_ENABLE_SET = 0x1010, /* write: enable-set */ + PORT_IRQ_ENABLE_CLR = 0x1014, /* write: enable-clear */ + PORT_ACTIVATE_UPPER_ADDR= 0x101c, + PORT_EXEC_FIFO = 0x1020, /* command execution fifo */ + PORT_CMD_ERR = 0x1024, /* command error number */ + PORT_FIS_CFG = 0x1028, + PORT_FIFO_THRES = 0x102c, + /* 16 bit regs */ + PORT_DECODE_ERR_CNT = 0x1040, + PORT_DECODE_ERR_THRESH = 0x1042, + PORT_CRC_ERR_CNT = 0x1044, + PORT_CRC_ERR_THRESH = 0x1046, + PORT_HSHK_ERR_CNT = 0x1048, + PORT_HSHK_ERR_THRESH = 0x104a, + /* 32 bit regs */ + PORT_PHY_CFG = 0x1050, + PORT_SLOT_STAT = 0x1800, + PORT_CMD_ACTIVATE = 0x1c00, /* 64 bit cmd activate * 31 (248 bytes) */ + PORT_EXEC_DIAG = 0x1e00, /* 32bit exec diag * 16 (64 bytes, 0-10 used on 3124) */ + PORT_PSD_DIAG = 0x1e40, /* 32bit psd diag * 16 (64 bytes, 0-8 used on 3124) */ + PORT_SCONTROL = 0x1f00, + PORT_SSTATUS = 0x1f04, + PORT_SERROR = 0x1f08, + PORT_SACTIVE = 0x1f0c, + + /* PORT_CTRL_STAT bits */ + PORT_CS_PORT_RST = (1 << 0), /* port reset */ + PORT_CS_DEV_RST = (1 << 1), /* device reset */ + PORT_CS_INIT = (1 << 2), /* port initialize */ + PORT_CS_IRQ_WOC = (1 << 3), /* interrupt write one to clear */ + PORT_CS_RESUME = (1 << 6), /* port resume */ + PORT_CS_32BIT_ACTV = (1 << 10), /* 32-bit activation */ + PORT_CS_PM_EN = (1 << 13), /* port multiplier enable */ + PORT_CS_RDY = (1 << 31), /* port ready to accept commands */ + + /* PORT_IRQ_STAT/ENABLE_SET/CLR */ + /* bits[11:0] are masked */ + PORT_IRQ_COMPLETE = (1 << 0), /* command(s) completed */ + PORT_IRQ_ERROR = (1 << 1), /* command execution error */ + PORT_IRQ_PORTRDY_CHG = (1 << 2), /* port ready change */ + PORT_IRQ_PWR_CHG = (1 << 3), /* power management change */ + PORT_IRQ_PHYRDY_CHG = (1 << 4), /* PHY ready change */ + PORT_IRQ_COMWAKE = (1 << 5), /* COMWAKE received */ + PORT_IRQ_UNK_FIS = (1 << 6), /* Unknown FIS received */ + PORT_IRQ_SDB_FIS = (1 << 11), /* SDB FIS received */ + + /* bits[27:16] are unmasked (raw) */ + PORT_IRQ_RAW_SHIFT = 16, + PORT_IRQ_MASKED_MASK = 0x7ff, + PORT_IRQ_RAW_MASK = (0x7ff << PORT_IRQ_RAW_SHIFT), + + /* ENABLE_SET/CLR specific, intr steering - 2 bit field */ + PORT_IRQ_STEER_SHIFT = 30, + PORT_IRQ_STEER_MASK = (3 << PORT_IRQ_STEER_SHIFT), + + /* PORT_CMD_ERR constants */ + PORT_CERR_DEV = 1, /* Error bit in D2H Register FIS */ + PORT_CERR_SDB = 2, /* Error bit in SDB FIS */ + PORT_CERR_DATA = 3, /* Error in data FIS not detected by dev */ + PORT_CERR_SEND = 4, /* Initial cmd FIS transmission failure */ + PORT_CERR_INCONSISTENT = 5, /* Protocol mismatch */ + PORT_CERR_DIRECTION = 6, /* Data direction mismatch */ + PORT_CERR_UNDERRUN = 7, /* Ran out of SGEs while writing */ + PORT_CERR_OVERRUN = 8, /* Ran out of SGEs while reading */ + PORT_CERR_PKT_PROT = 11, /* DIR invalid in 1st PIO setup of ATAPI */ + PORT_CERR_SGT_BOUNDARY = 16, /* PLD ecode 00 - SGT not on qword boundary */ + PORT_CERR_SGT_TGTABRT = 17, /* PLD ecode 01 - target abort */ + PORT_CERR_SGT_MSTABRT = 18, /* PLD ecode 10 - master abort */ + PORT_CERR_SGT_PCIPERR = 19, /* PLD ecode 11 - PCI parity err while fetching SGT */ + PORT_CERR_CMD_BOUNDARY = 24, /* ctrl[15:13] 001 - PRB not on qword boundary */ + PORT_CERR_CMD_TGTABRT = 25, /* ctrl[15:13] 010 - target abort */ + PORT_CERR_CMD_MSTABRT = 26, /* ctrl[15:13] 100 - master abort */ + PORT_CERR_CMD_PCIPERR = 27, /* ctrl[15:13] 110 - PCI parity err while fetching PRB */ + PORT_CERR_XFR_UNDEF = 32, /* PSD ecode 00 - undefined */ + PORT_CERR_XFR_TGTABRT = 33, /* PSD ecode 01 - target abort */ + PORT_CERR_XFR_MSGABRT = 34, /* PSD ecode 10 - master abort */ + PORT_CERR_XFR_PCIPERR = 35, /* PSD ecode 11 - PCI prity err during transfer */ + PORT_CERR_SENDSERVICE = 36, /* FIS received while sending service */ + + /* + * Other constants + */ + SGE_TRM = (1 << 31), /* Last SGE in chain */ + PRB_SOFT_RST = (1 << 7), /* Soft reset request (ign BSY?) */ + + /* board id */ + BID_SIL3124 = 0, + BID_SIL3132 = 1, + + IRQ_STAT_4PORTS = 0xf, +}; + +struct sil24_cmd_block { + struct sil24_prb prb; + struct sil24_sge sge[LIBATA_MAX_PRD]; +}; + +/* + * ap->private_data + * + * The preview driver always returned 0 for status. We emulate it + * here from the previous interrupt. + */ +struct sil24_port_priv { + struct sil24_cmd_block *cmd_block; /* 32 cmd blocks */ + dma_addr_t cmd_block_dma; /* DMA base addr for them */ +}; + +/* ap->host_set->private_data */ +struct sil24_host_priv { + void *host_base; /* global controller control (128 bytes @BAR0) */ + void *port_base; /* port registers (4 * 8192 bytes @BAR2) */ +}; + +static u8 sil24_check_status(struct ata_port *ap); +static u8 sil24_check_err(struct ata_port *ap); +static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg); +static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val); +static void sil24_phy_reset(struct ata_port *ap); +static void sil24_qc_prep(struct ata_queued_cmd *qc); +static int sil24_qc_issue(struct ata_queued_cmd *qc); +static void sil24_irq_clear(struct ata_port *ap); +static void sil24_eng_timeout(struct ata_port *ap); +static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static int sil24_port_start(struct ata_port *ap); +static void sil24_port_stop(struct ata_port *ap); +static void sil24_host_stop(struct ata_host_set *host_set); +static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); + +static struct pci_device_id sil24_pci_tbl[] = { + { 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 }, + { 0x1095, 0x3132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3132 }, +}; + +static struct pci_driver sil24_pci_driver = { + .name = DRV_NAME, + .id_table = sil24_pci_tbl, + .probe = sil24_init_one, + .remove = ata_pci_remove_one, /* safe? */ +}; + +static Scsi_Host_Template sil24_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 = 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, + .ordered_flush = 1, /* NCQ not supported yet */ +}; + +static struct ata_port_operations sil24_ops = { + .port_disable = ata_port_disable, + + .check_status = sil24_check_status, + .check_altstatus = sil24_check_status, + .check_err = sil24_check_err, + .dev_select = ata_noop_dev_select, + + .phy_reset = sil24_phy_reset, + + .qc_prep = sil24_qc_prep, + .qc_issue = sil24_qc_issue, + + .eng_timeout = sil24_eng_timeout, + + .irq_handler = sil24_interrupt, + .irq_clear = sil24_irq_clear, + + .scr_read = sil24_scr_read, + .scr_write = sil24_scr_write, + + .port_start = sil24_port_start, + .port_stop = sil24_port_stop, + .host_stop = sil24_host_stop, +}; + +static struct ata_port_info sil24_port_info[] = { + /* sil_3124 */ + { + .sht = &sil24_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | + ATA_FLAG_PIO_DMA, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x3f, /* udma0-5 */ + .port_ops = &sil24_ops, + }, + /* sil_3132 */ + { + .sht = &sil24_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | + ATA_FLAG_PIO_DMA, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x3f, /* udma0-5 */ + .port_ops = &sil24_ops, + }, +}; + +static u8 sil24_check_status(struct ata_port *ap) +{ + return ATA_DRDY; +} + +static u8 sil24_check_err(struct ata_port *ap) +{ + return 0; +} + +static int sil24_scr_map[] = { + [SCR_CONTROL] = 0, + [SCR_STATUS] = 1, + [SCR_ERROR] = 2, + [SCR_ACTIVE] = 3, +}; + +static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg) +{ + void *scr_addr = (void *)ap->ioaddr.scr_addr; + if (sc_reg < ARRAY_SIZE(sil24_scr_map)) { + void *addr; + addr = scr_addr + sil24_scr_map[sc_reg] * 4; + return readl(scr_addr + sil24_scr_map[sc_reg] * 4); + } + return 0xffffffffU; +} + +static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val) +{ + void *scr_addr = (void *)ap->ioaddr.scr_addr; + if (sc_reg < ARRAY_SIZE(sil24_scr_map)) { + void *addr; + addr = scr_addr + sil24_scr_map[sc_reg] * 4; + writel(val, scr_addr + sil24_scr_map[sc_reg] * 4); + } +} + +static void sil24_phy_reset(struct ata_port *ap) +{ + __sata_phy_reset(ap); + /* + * No ATAPI yet. Just unconditionally indicate ATA device. + * If ATAPI device is attached, it will fail ATA_CMD_ID_ATA + * and libata core will ignore the device. + */ + if (!(ap->flags & ATA_FLAG_PORT_DISABLED)) + ap->device[0].class = ATA_DEV_ATA; +} + +static inline void sil24_fill_sg(struct ata_queued_cmd *qc, + struct sil24_cmd_block *cb) +{ + struct scatterlist *sg = qc->sg; + struct sil24_sge *sge = cb->sge; + unsigned i; + + for (i = 0; i < qc->n_elem; i++, sg++, sge++) { + sge->addr = cpu_to_le64(sg_dma_address(sg)); + sge->cnt = cpu_to_le32(sg_dma_len(sg)); + sge->flags = 0; + sge->flags = i < qc->n_elem - 1 ? 0 : cpu_to_le32(SGE_TRM); + } +} + +static void sil24_qc_prep(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct sil24_port_priv *pp = ap->private_data; + struct sil24_cmd_block *cb = pp->cmd_block + qc->tag; + struct sil24_prb *prb = &cb->prb; + + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + case ATA_PROT_DMA: + case ATA_PROT_NODATA: + break; + default: + /* ATAPI isn't supported yet */ + BUG(); + } + + ata_tf_to_fis(&qc->tf, prb->fis, 0); + + if (qc->flags & ATA_QCFLAG_DMAMAP) + sil24_fill_sg(qc, cb); +} + +static int sil24_qc_issue(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + void *port = (void *)ap->ioaddr.cmd_addr; + struct sil24_port_priv *pp = ap->private_data; + dma_addr_t paddr = pp->cmd_block_dma + qc->tag * sizeof(*pp->cmd_block); + + writel((u32)paddr, port + PORT_CMD_ACTIVATE); + return 0; +} + +static void sil24_irq_clear(struct ata_port *ap) +{ + /* unused */ +} + +static void sil24_reset_controller(struct ata_port *ap) +{ + void *port = (void *)ap->ioaddr.cmd_addr; + int cnt; + u32 tmp; + + printk(KERN_NOTICE DRV_NAME + " ata%u: resetting controller...\n", ap->id); + + /* Reset controller state. Is this correct? */ + writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT); + readl(port + PORT_CTRL_STAT); /* sync */ + + /* Max ~100ms */ + for (cnt = 0; cnt < 1000; cnt++) { + udelay(100); + tmp = readl(port + PORT_CTRL_STAT); + if (!(tmp & PORT_CS_DEV_RST)) + break; + } + if (tmp & PORT_CS_DEV_RST) + printk(KERN_ERR DRV_NAME + " ata%u: failed to reset controller\n", ap->id); +} + +static void sil24_eng_timeout(struct ata_port *ap) +{ + struct ata_queued_cmd *qc; + + qc = ata_qc_from_tag(ap, ap->active_tag); + if (!qc) { + printk(KERN_ERR "ata%u: BUG: tiemout without command\n", + ap->id); + return; + } + + /* + * hack alert! We cannot use the supplied completion + * function from inside the ->eh_strategy_handler() thread. + * libata is the only user of ->eh_strategy_handler() in + * any kernel, so the default scsi_done() assumes it is + * not being called from the SCSI EH. + */ + printk(KERN_ERR "ata%u: command timeout\n", ap->id); + qc->scsidone = scsi_finish_command; + ata_qc_complete(qc, ATA_ERR); + + sil24_reset_controller(ap); +} + +static void sil24_error_intr(struct ata_port *ap, u32 slot_stat) +{ + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); + void *port = (void *)ap->ioaddr.cmd_addr; + u32 irq_stat, cmd_err, sstatus, serror; + + irq_stat = readl(port + PORT_IRQ_STAT); + cmd_err = readl(port + PORT_CMD_ERR); + sstatus = readl(port + PORT_SSTATUS); + serror = readl(port + PORT_SERROR); + + /* Clear IRQ/errors */ + writel(irq_stat, port + PORT_IRQ_STAT); + if (cmd_err) + writel(cmd_err, port + PORT_CMD_ERR); + if (serror) + writel(serror, port + PORT_SERROR); + + printk(KERN_ERR DRV_NAME " ata%u: error interrupt on port%d\n" + " stat=0x%x irq=0x%x cmd_err=%d sstatus=0x%x serror=0x%x\n", + ap->id, ap->port_no, slot_stat, irq_stat, cmd_err, sstatus, serror); + + if (qc) + ata_qc_complete(qc, ATA_ERR); + + sil24_reset_controller(ap); +} + +static inline void sil24_host_intr(struct ata_port *ap) +{ + struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); + void *port = (void *)ap->ioaddr.cmd_addr; + u32 slot_stat; + + slot_stat = readl(port + PORT_SLOT_STAT); + if (!(slot_stat & HOST_SSTAT_ATTN)) { + if (qc) + ata_qc_complete(qc, 0); + } else + sil24_error_intr(ap, slot_stat); +} + +static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct ata_host_set *host_set = dev_instance; + struct sil24_host_priv *hpriv = host_set->private_data; + unsigned handled = 0; + u32 status; + int i; + + status = readl(hpriv->host_base + HOST_IRQ_STAT); + + if (status == 0xffffffff) { + printk(KERN_ERR DRV_NAME ": IRQ status == 0xffffffff, " + "PCI fault or device removal?\n"); + goto out; + } + + if (!(status & IRQ_STAT_4PORTS)) + goto out; + + spin_lock(&host_set->lock); + + for (i = 0; i < host_set->n_ports; i++) + if (status & (1 << i)) { + struct ata_port *ap = host_set->ports[i]; + if (ap && !(ap->flags & ATA_FLAG_PORT_DISABLED)) { + sil24_host_intr(host_set->ports[i]); + handled++; + } else + printk(KERN_ERR DRV_NAME + ": interrupt from disabled port %d\n", i); + } + + spin_unlock(&host_set->lock); + out: + return IRQ_RETVAL(handled); +} + +static int sil24_port_start(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct sil24_port_priv *pp; + struct sil24_cmd_block *cb; + size_t cb_size = sizeof(*cb); + dma_addr_t cb_dma; + + pp = kmalloc(sizeof(*pp), GFP_KERNEL); + if (!pp) + return -ENOMEM; + memset(pp, 0, sizeof(*pp)); + + cb = dma_alloc_coherent(dev, cb_size, &cb_dma, GFP_KERNEL); + if (!cb) { + kfree(pp); + return -ENOMEM; + } + memset(cb, 0, cb_size); + + pp->cmd_block = cb; + pp->cmd_block_dma = cb_dma; + + ap->private_data = pp; + + return 0; +} + +static void sil24_port_stop(struct ata_port *ap) +{ + struct device *dev = ap->host_set->dev; + struct sil24_port_priv *pp = ap->private_data; + size_t cb_size = sizeof(*pp->cmd_block); + + dma_free_coherent(dev, cb_size, pp->cmd_block, pp->cmd_block_dma); + kfree(pp); +} + +static void sil24_host_stop(struct ata_host_set *host_set) +{ + struct sil24_host_priv *hpriv = host_set->private_data; + + iounmap(hpriv->host_base); + iounmap(hpriv->port_base); + kfree(hpriv); +} + +static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int printed_version = 0; + unsigned int board_id = (unsigned int)ent->driver_data; + struct ata_probe_ent *probe_ent = NULL; + struct sil24_host_priv *hpriv = NULL; + void *host_base = NULL, *port_base = NULL; + int i, 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 out_disable; + + rc = -ENOMEM; + /* ioremap mmio registers */ + host_base = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (!host_base) + goto out_free; + port_base = ioremap(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2)); + if (!port_base) + goto out_free; + + /* allocate & init probe_ent and hpriv */ + probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + if (!probe_ent) + goto out_free; + + hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL); + if (!hpriv) + goto out_free; + + memset(probe_ent, 0, sizeof(*probe_ent)); + probe_ent->dev = pci_dev_to_dev(pdev); + INIT_LIST_HEAD(&probe_ent->node); + + probe_ent->sht = sil24_port_info[board_id].sht; + probe_ent->host_flags = sil24_port_info[board_id].host_flags; + probe_ent->pio_mask = sil24_port_info[board_id].pio_mask; + probe_ent->udma_mask = sil24_port_info[board_id].udma_mask; + probe_ent->port_ops = sil24_port_info[board_id].port_ops; + probe_ent->n_ports = (board_id == BID_SIL3124) ? 4 : 2; + + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = SA_SHIRQ; + probe_ent->mmio_base = port_base; + probe_ent->private_data = hpriv; + + memset(hpriv, 0, sizeof(*hpriv)); + hpriv->host_base = host_base; + hpriv->port_base = port_base; + + /* + * Configure the device + */ + /* + * FIXME: This device is certainly 64-bit capable. We just + * don't know how to use it. After fixing 32bit activation in + * this function, enable 64bit masks here. + */ + rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) { + printk(KERN_ERR DRV_NAME "(%s): 32-bit DMA enable failed\n", + pci_name(pdev)); + goto out_free; + } + rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) { + printk(KERN_ERR DRV_NAME "(%s): 32-bit consistent DMA enable failed\n", + pci_name(pdev)); + goto out_free; + } + + /* GPIO off */ + writel(0, host_base + HOST_FLASH_CMD); + + /* Mask interrupts during initialization */ + writel(0, host_base + HOST_CTRL); + + for (i = 0; i < probe_ent->n_ports; i++) { + void *port = port_base + i * PORT_REGS_SIZE; + unsigned long portu = (unsigned long)port; + u32 tmp; + int cnt; + + probe_ent->port[i].cmd_addr = portu + PORT_PRB; + probe_ent->port[i].scr_addr = portu + PORT_SCONTROL; + + ata_std_ports(&probe_ent->port[i]); + + /* Initial PHY setting */ + writel(0x20c, port + PORT_PHY_CFG); + + /* Clear port RST */ + tmp = readl(port + PORT_CTRL_STAT); + if (tmp & PORT_CS_PORT_RST) { + writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR); + readl(port + PORT_CTRL_STAT); /* sync */ + for (cnt = 0; cnt < 10; cnt++) { + msleep(10); + tmp = readl(port + PORT_CTRL_STAT); + if (!(tmp & PORT_CS_PORT_RST)) + break; + } + if (tmp & PORT_CS_PORT_RST) + printk(KERN_ERR DRV_NAME + "(%s): failed to clear port RST\n", + pci_name(pdev)); + } + + /* Zero error counters. */ + writel(0x8000, port + PORT_DECODE_ERR_THRESH); + writel(0x8000, port + PORT_CRC_ERR_THRESH); + writel(0x8000, port + PORT_HSHK_ERR_THRESH); + writel(0x0000, port + PORT_DECODE_ERR_CNT); + writel(0x0000, port + PORT_CRC_ERR_CNT); + writel(0x0000, port + PORT_HSHK_ERR_CNT); + + /* FIXME: 32bit activation? */ + writel(0, port + PORT_ACTIVATE_UPPER_ADDR); + writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_STAT); + + /* Configure interrupts */ + writel(0xffff, port + PORT_IRQ_ENABLE_CLR); + writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR | PORT_IRQ_SDB_FIS, + port + PORT_IRQ_ENABLE_SET); + + /* Clear interrupts */ + writel(0x0fff0fff, port + PORT_IRQ_STAT); + writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); + } + + /* Turn on interrupts */ + writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL); + + pci_set_master(pdev); + + /* FIXME: check ata_device_add return value */ + ata_device_add(probe_ent); + + kfree(probe_ent); + return 0; + + out_free: + if (host_base) + iounmap(host_base); + if (port_base) + iounmap(port_base); + kfree(probe_ent); + kfree(hpriv); + pci_release_regions(pdev); + out_disable: + pci_disable_device(pdev); + return rc; +} + +static int __init sil24_init(void) +{ + return pci_module_init(&sil24_pci_driver); +} + +static void __exit sil24_exit(void) +{ + pci_unregister_driver(&sil24_pci_driver); +} + +MODULE_AUTHOR("Tejun Heo"); +MODULE_DESCRIPTION("Silicon Image 3124/3132 SATA low-level driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, sil24_pci_tbl); + +module_init(sil24_init); +module_exit(sil24_exit); diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c @@ -47,7 +47,16 @@ #include #define DRV_NAME "sata_vsc" -#define DRV_VERSION "1.0" +#define DRV_VERSION "1.1" + +enum vsc_pci_cfg_constants { + VSC_CFG = 0x98, /* VSC7174 Configuration */ + VSC_DMA = 0xA0, /* DMA control / status */ + + VSC_DMA_NO_M = (1 << 2), /* disable PCI MWI/MRM */ + VSC_DMA_WCACHE = (1 << 1), /* wr DMA cacheln align */ + VSC_DMA_RCACHE = (1 << 0), /* rd DMA cacheln align */ +}; /* Interrupt register offsets (from chip base address) */ #define VSC_SATA_INT_STAT_OFFSET 0x00 @@ -276,6 +285,33 @@ static void __devinit vsc_sata_setup_por writel(0, base + VSC_SATA_UP_DATA_BUFFER_OFFSET); } +static void vsc_pci_cfg_dma(struct pci_dev *pdev, int mwi) +{ + u32 dmacfg, new_dmacfg; + u8 clnsz = 0; + + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &clnsz); + pci_read_config_dword(pdev, VSC_DMA, &dmacfg); + + /* Set DMA burst length. Should always be greater than + * clnsz, except when we are at maximum (0x80) + */ + + new_dmacfg = dmacfg & 0xffff00f8; /* Mask out DMA BL, low 3 bits */ + if ((clnsz > 0) && mwi) { + if (clnsz >= 0x80) + new_dmacfg |= (0x80 << 8); + else + new_dmacfg |= ((clnsz * 2) << 8); + new_dmacfg |= VSC_DMA_WCACHE | VSC_DMA_RCACHE; + } else { + new_dmacfg |= (0x80 << 8); + new_dmacfg |= VSC_DMA_NO_M; /* Disable PCI MRM/MWI */ + } + + if (new_dmacfg != dmacfg) + pci_write_config_dword(pdev, VSC_DMA, new_dmacfg); +} static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -285,6 +321,7 @@ static int __devinit vsc_sata_init_one ( int pci_dev_busy = 0; void *mmio_base; int rc; + int mwi = 1; if (!printed_version++) printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); @@ -307,20 +344,24 @@ static int __devinit vsc_sata_init_one ( goto err_out; } + rc = pci_set_mwi(pdev); + if (rc) + mwi = 0; + /* * Use 32 bit DMA mask, because 64 bit address support is poor. */ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (rc) - goto err_out_regions; + goto err_out_mwi; rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); if (rc) - goto err_out_regions; + goto err_out_mwi; probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); if (probe_ent == NULL) { rc = -ENOMEM; - goto err_out_regions; + goto err_out_mwi; } memset(probe_ent, 0, sizeof(*probe_ent)); probe_ent->dev = pci_dev_to_dev(pdev); @@ -333,10 +374,7 @@ static int __devinit vsc_sata_init_one ( } base = (unsigned long) mmio_base; - /* - * Due to a bug in the chip, the default cache line size can't be used - */ - pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80); + vsc_pci_cfg_dma(pdev, mwi); probe_ent->sht = &vsc_sata_sht; probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | @@ -368,7 +406,7 @@ static int __devinit vsc_sata_init_one ( * DPA mode. If bit 28 is set, LED 0 reflects all ports' activity. * If bit 28 is clear, each port has its own LED. */ - pci_write_config_dword(pdev, 0x98, 0); + pci_write_config_dword(pdev, VSC_CFG, 0); /* FIXME: check ata_device_add return value */ ata_device_add(probe_ent); @@ -378,7 +416,12 @@ static int __devinit vsc_sata_init_one ( err_out_free_ent: kfree(probe_ent); -err_out_regions: +err_out_mwi: + /* FIXME: create a custom PCI ->remove() hook, which calls + * pci_clear_mwi() at ->remove time + */ + if (mwi) + pci_clear_mwi(pdev); pci_release_regions(pdev); err_out: if (!pci_dev_busy) diff --git a/include/linux/ata.h b/include/linux/ata.h --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -132,6 +132,7 @@ enum { ATA_CMD_PACKET = 0xA0, ATA_CMD_VERIFY = 0x40, ATA_CMD_VERIFY_EXT = 0x42, + ATA_CMD_INIT_DEV_PARAMS = 0x91, /* SETFEATURES stuff */ SETFEATURES_XFER = 0x03, @@ -181,6 +182,7 @@ enum { ATA_TFLAG_ISADDR = (1 << 1), /* enable r/w to nsect/lba regs */ ATA_TFLAG_DEVICE = (1 << 2), /* enable r/w to device reg */ ATA_TFLAG_WRITE = (1 << 3), /* data dir: host->dev==1 (write) */ + ATA_TFLAG_LBA = (1 << 4), /* enable LBA */ }; enum ata_tf_protocols { @@ -250,6 +252,18 @@ struct ata_taskfile { ((u64) (id)[(n) + 1] << 16) | \ ((u64) (id)[(n) + 0]) ) +static inline int ata_id_current_chs_valid(u16 *id) +{ + /* For ATA-1 devices, if the INITIALIZE DEVICE PARAMETERS command + has not been issued to the device then the values of + id[54] to id[56] are vendor specific. */ + return (id[53] & 0x01) && /* Current translation valid */ + id[54] && /* cylinders in current translation */ + id[55] && /* heads in current translation */ + id[55] <= 16 && + id[56]; /* sectors in current translation */ +} + static inline int atapi_cdb_len(u16 *dev_id) { u16 tmp = dev_id[0] & 0x3; diff --git a/include/linux/libata.h b/include/linux/libata.h --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -97,6 +97,7 @@ enum { ATA_DFLAG_LBA48 = (1 << 0), /* device supports LBA48 */ ATA_DFLAG_PIO = (1 << 1), /* device currently in PIO mode */ ATA_DFLAG_LOCK_SECTORS = (1 << 2), /* don't adjust max_sectors */ + ATA_DFLAG_LBA = (1 << 3), /* device supports LBA */ ATA_DEV_UNKNOWN = 0, /* unknown device */ ATA_DEV_ATA = 1, /* ATA device */ @@ -209,6 +210,7 @@ struct ata_probe_ent { 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; }; @@ -282,6 +284,11 @@ struct ata_device { u8 xfer_protocol; /* taskfile xfer protocol */ u8 read_cmd; /* opcode to use on read */ u8 write_cmd; /* opcode to use on write */ + + /* for CHS addressing */ + u16 cylinders; /* Number of cylinders */ + u16 heads; /* Number of heads */ + u16 sectors; /* Number of sectors per track */ }; struct ata_port { diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h @@ -116,6 +116,9 @@ extern const char *const scsi_device_typ /* values for service action in */ #define SAI_READ_CAPACITY_16 0x10 +/* Values for T10/04-262r7 */ +#define ATA_16 0x85 /* 16-byte pass-thru */ +#define ATA_12 0xa1 /* 12-byte pass-thru */ /* * SCSI Architecture Model (SAM) Status codes. Taken from SAM-3 draft