*
* Bits from Jeff Garzik, Copyright RedHat, Inc.
*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
+ *
+ * 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.*
+ *
+ * Vitesse hardware documentation presumably available under NDA.
+ * Intel 31244 (same hardware interface) documentation presumably
+ * available from http://developer.intel.com/
+ *
*/
#include <linux/kernel.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include "scsi.h"
+#include <linux/dma-mapping.h>
+#include <linux/device.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#define DRV_NAME "sata_vsc"
-#define DRV_VERSION "1.0"
-
-/* Interrupt register offsets (from chip base address) */
-#define VSC_SATA_INT_STAT_OFFSET 0x00
-#define VSC_SATA_INT_MASK_OFFSET 0x04
-
-/* Taskfile registers offsets */
-#define VSC_SATA_TF_CMD_OFFSET 0x00
-#define VSC_SATA_TF_DATA_OFFSET 0x00
-#define VSC_SATA_TF_ERROR_OFFSET 0x04
-#define VSC_SATA_TF_FEATURE_OFFSET 0x06
-#define VSC_SATA_TF_NSECT_OFFSET 0x08
-#define VSC_SATA_TF_LBAL_OFFSET 0x0c
-#define VSC_SATA_TF_LBAM_OFFSET 0x10
-#define VSC_SATA_TF_LBAH_OFFSET 0x14
-#define VSC_SATA_TF_DEVICE_OFFSET 0x18
-#define VSC_SATA_TF_STATUS_OFFSET 0x1c
-#define VSC_SATA_TF_COMMAND_OFFSET 0x1d
-#define VSC_SATA_TF_ALTSTATUS_OFFSET 0x28
-#define VSC_SATA_TF_CTL_OFFSET 0x29
-
-/* DMA base */
-#define VSC_SATA_UP_DESCRIPTOR_OFFSET 0x64
-#define VSC_SATA_UP_DATA_BUFFER_OFFSET 0x6C
-#define VSC_SATA_DMA_CMD_OFFSET 0x70
-
-/* SCRs base */
-#define VSC_SATA_SCR_STATUS_OFFSET 0x100
-#define VSC_SATA_SCR_ERROR_OFFSET 0x104
-#define VSC_SATA_SCR_CONTROL_OFFSET 0x108
-
-/* Port stride */
-#define VSC_SATA_PORT_OFFSET 0x200
+#define DRV_VERSION "1.2"
+
+enum {
+ /* Interrupt register offsets (from chip base address) */
+ VSC_SATA_INT_STAT_OFFSET = 0x00,
+ VSC_SATA_INT_MASK_OFFSET = 0x04,
+
+ /* Taskfile registers offsets */
+ VSC_SATA_TF_CMD_OFFSET = 0x00,
+ VSC_SATA_TF_DATA_OFFSET = 0x00,
+ VSC_SATA_TF_ERROR_OFFSET = 0x04,
+ VSC_SATA_TF_FEATURE_OFFSET = 0x06,
+ VSC_SATA_TF_NSECT_OFFSET = 0x08,
+ VSC_SATA_TF_LBAL_OFFSET = 0x0c,
+ VSC_SATA_TF_LBAM_OFFSET = 0x10,
+ VSC_SATA_TF_LBAH_OFFSET = 0x14,
+ VSC_SATA_TF_DEVICE_OFFSET = 0x18,
+ VSC_SATA_TF_STATUS_OFFSET = 0x1c,
+ VSC_SATA_TF_COMMAND_OFFSET = 0x1d,
+ VSC_SATA_TF_ALTSTATUS_OFFSET = 0x28,
+ VSC_SATA_TF_CTL_OFFSET = 0x29,
+
+ /* DMA base */
+ VSC_SATA_UP_DESCRIPTOR_OFFSET = 0x64,
+ VSC_SATA_UP_DATA_BUFFER_OFFSET = 0x6C,
+ VSC_SATA_DMA_CMD_OFFSET = 0x70,
+
+ /* SCRs base */
+ VSC_SATA_SCR_STATUS_OFFSET = 0x100,
+ VSC_SATA_SCR_ERROR_OFFSET = 0x104,
+ VSC_SATA_SCR_CONTROL_OFFSET = 0x108,
+
+ /* Port stride */
+ VSC_SATA_PORT_OFFSET = 0x200,
+
+ /* Error interrupt status bit offsets */
+ VSC_SATA_INT_ERROR_CRC = 0x40,
+ VSC_SATA_INT_ERROR_T = 0x20,
+ VSC_SATA_INT_ERROR_P = 0x10,
+ VSC_SATA_INT_ERROR_R = 0x8,
+ VSC_SATA_INT_ERROR_E = 0x4,
+ VSC_SATA_INT_ERROR_M = 0x2,
+ VSC_SATA_INT_PHY_CHANGE = 0x1,
+ VSC_SATA_INT_ERROR = (VSC_SATA_INT_ERROR_CRC | VSC_SATA_INT_ERROR_T | \
+ VSC_SATA_INT_ERROR_P | VSC_SATA_INT_ERROR_R | \
+ VSC_SATA_INT_ERROR_E | VSC_SATA_INT_ERROR_M | \
+ VSC_SATA_INT_PHY_CHANGE),
+};
+
+
+#define is_vsc_sata_int_err(port_idx, int_status) \
+ (int_status & (VSC_SATA_INT_ERROR << (8 * port_idx)))
static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
{
if (sc_reg > SCR_CONTROL)
return 0xffffffffU;
- return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+ return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
}
{
if (sc_reg > SCR_CONTROL)
return;
- writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+ writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
}
static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl)
{
- unsigned long mask_addr;
+ void __iomem *mask_addr;
u8 mask;
- mask_addr = (unsigned long) ap->host_set->mmio_base +
+ mask_addr = ap->host_set->mmio_base +
VSC_SATA_INT_MASK_OFFSET + ap->port_no;
mask = readb(mask_addr);
if (ctl & ATA_NIEN)
}
-static void vsc_sata_tf_load(struct ata_port *ap, struct ata_taskfile *tf)
+static void vsc_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
- u16 nsect, lbal, lbam, lbah;
+ u16 nsect, lbal, lbam, lbah, feature;
- nsect = tf->nsect = readw(ioaddr->nsect_addr);
- lbal = tf->lbal = readw(ioaddr->lbal_addr);
- lbam = tf->lbam = readw(ioaddr->lbam_addr);
- lbah = tf->lbah = readw(ioaddr->lbah_addr);
+ tf->command = ata_check_status(ap);
tf->device = readw(ioaddr->device_addr);
+ feature = readw(ioaddr->error_addr);
+ nsect = readw(ioaddr->nsect_addr);
+ lbal = readw(ioaddr->lbal_addr);
+ lbam = readw(ioaddr->lbam_addr);
+ lbah = readw(ioaddr->lbah_addr);
+
+ tf->feature = feature;
+ tf->nsect = nsect;
+ tf->lbal = lbal;
+ tf->lbam = lbam;
+ tf->lbah = lbah;
if (tf->flags & ATA_TFLAG_LBA48) {
- tf->hob_feature = readb(ioaddr->error_addr);
+ tf->hob_feature = feature >> 8;
tf->hob_nsect = nsect >> 8;
tf->hob_lbal = lbal >> 8;
tf->hob_lbam = lbam >> 8;
*
* Read the interrupt register and process for the devices that have them pending.
*/
-irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance,
+ struct pt_regs *regs)
{
struct ata_host_set *host_set = dev_instance;
unsigned int i;
struct ata_port *ap;
ap = host_set->ports[i];
- if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+
+ if (ap && !(ap->flags &
+ (ATA_FLAG_PORT_DISABLED|ATA_FLAG_NOINTR))) {
struct ata_queued_cmd *qc;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.ctl & ATA_NIEN)))
+ if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
handled += ata_host_intr(ap, qc);
+ } else if (is_vsc_sata_int_err(i, int_status)) {
+ /*
+ * On some chips (i.e. Intel 31244), an error
+ * interrupt will sneak in at initialization
+ * time (phy state changes). Clearing the SCR
+ * error register is not required, but it prevents
+ * the phy state change interrupts from recurring
+ * later.
+ */
+ u32 err_status;
+ err_status = vsc_sata_scr_read(ap, SCR_ERROR);
+ printk(KERN_DEBUG "%s: clearing interrupt, "
+ "status %x; sata err status %x\n",
+ __FUNCTION__,
+ int_status, err_status);
+ vsc_sata_scr_write(ap, SCR_ERROR, err_status);
+ /* Clear interrupt status */
+ ata_chk_status(ap);
+ handled++;
+ }
}
}
}
}
-static Scsi_Host_Template vsc_sata_sht = {
+static struct scsi_host_template vsc_sata_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,
};
-static struct ata_port_operations vsc_sata_ops = {
+static const struct ata_port_operations vsc_sata_ops = {
.port_disable = ata_port_disable,
.tf_load = vsc_sata_tf_load,
.tf_read = vsc_sata_tf_read,
.phy_reset = sata_phy_reset,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
.eng_timeout = ata_eng_timeout,
.scr_write = vsc_sata_scr_write,
.port_start = ata_port_start,
.port_stop = ata_port_stop,
+ .host_stop = ata_pci_host_stop,
};
static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned long base)
static int printed_version;
struct ata_probe_ent *probe_ent = NULL;
unsigned long base;
- void *mmio_base;
+ int pci_dev_busy = 0;
+ void __iomem *mmio_base;
int rc;
if (!printed_version++)
- printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
rc = pci_enable_device(pdev);
if (rc)
}
rc = pci_request_regions(pdev, DRV_NAME);
- if (rc)
+ if (rc) {
+ pci_dev_busy = 1;
goto err_out;
+ }
/*
* Use 32 bit DMA mask, because 64 bit address support is poor.
*/
- rc = pci_set_dma_mask(pdev, 0xFFFFFFFFULL);
+ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (rc)
goto err_out_regions;
- rc = pci_set_consistent_dma_mask(pdev, 0xFFFFFFFFULL);
+ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
if (rc)
goto err_out_regions;
probe_ent->dev = pci_dev_to_dev(pdev);
INIT_LIST_HEAD(&probe_ent->node);
- mmio_base = ioremap(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
+ mmio_base = pci_iomap(pdev, 0, 0);
if (mmio_base == NULL) {
rc = -ENOMEM;
goto err_out_free_ent;
pci_set_master(pdev);
- /*
+ /*
* Config offset 0x98 is "Extended Control and Status Register 0"
* Default value is (1 << 28). All bits except bit 28 are reserved in
* DPA mode. If bit 28 is set, LED 0 reflects all ports' activity.
err_out_regions:
pci_release_regions(pdev);
err_out:
- pci_disable_device(pdev);
+ if (!pci_dev_busy)
+ pci_disable_device(pdev);
return rc;
}
* 0x8086/0x3200 is the Intel 31244, which is supposed to be identical
* compatibility is untested as of yet
*/
-static struct pci_device_id vsc_sata_pci_tbl[] = {
+static const struct pci_device_id vsc_sata_pci_tbl[] = {
{ 0x1725, 0x7174, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
{ 0x8086, 0x3200, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
{ }