11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  sata_vsc.c - Vitesse VSC7174 4 port DPA SATA
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Maintained by:  Jeremy Higdon @ SGI
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 		    Please ALWAYS copy linux-ide@vger.kernel.org
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		    on emails.
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright 2004 SGI
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Bits from Jeff Garzik, Copyright RedHat, Inc.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
12af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *
13af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  This program is free software; you can redistribute it and/or modify
14af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  it under the terms of the GNU General Public License as published by
15af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  the Free Software Foundation; either version 2, or (at your option)
16af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  any later version.
17af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *
18af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  This program is distributed in the hope that it will be useful,
19af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  GNU General Public License for more details.
22af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *
23af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  You should have received a copy of the GNU General Public License
24af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  along with this program; see the file COPYING.  If not, write to
25af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
26af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *
27af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *
28af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  libata documentation is available via 'make {ps|pdf}docs',
29af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  as Documentation/DocBook/libata.*
30af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *
31af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  Vitesse hardware documentation presumably available under NDA.
32af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  Intel 31244 (same hardware interface) documentation presumably
33af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  available from http://developer.intel.com/
34af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
447003c05d77593f567e9940e68a944d846228fd7aDomen Puncer#include <linux/dma-mapping.h>
45a9524a76f70f3343e4be27f95a7e92a8ba5f9009Jeff Garzik#include <linux/device.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_host.h>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/libata.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRV_NAME	"sata_vsc"
502a3103ce4357a09c2289405f969acec0edf4398fJeff Garzik#define DRV_VERSION	"2.3"
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5255cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzikenum {
530d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	VSC_MMIO_BAR			= 0,
540d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo
5555cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	/* Interrupt register offsets (from chip base address) */
5655cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_INT_STAT_OFFSET	= 0x00,
5755cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_INT_MASK_OFFSET	= 0x04,
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5955cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	/* Taskfile registers offsets */
6055cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_TF_CMD_OFFSET		= 0x00,
6155cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_TF_DATA_OFFSET		= 0x00,
6255cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_TF_ERROR_OFFSET	= 0x04,
6355cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_TF_FEATURE_OFFSET	= 0x06,
6455cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_TF_NSECT_OFFSET	= 0x08,
6555cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_TF_LBAL_OFFSET		= 0x0c,
6655cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_TF_LBAM_OFFSET		= 0x10,
6755cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_TF_LBAH_OFFSET		= 0x14,
6855cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_TF_DEVICE_OFFSET	= 0x18,
6955cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_TF_STATUS_OFFSET	= 0x1c,
7055cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_TF_COMMAND_OFFSET	= 0x1d,
7155cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_TF_ALTSTATUS_OFFSET	= 0x28,
7255cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_TF_CTL_OFFSET		= 0x29,
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7455cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	/* DMA base */
7555cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_UP_DESCRIPTOR_OFFSET	= 0x64,
7655cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_UP_DATA_BUFFER_OFFSET	= 0x6C,
7755cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_DMA_CMD_OFFSET		= 0x70,
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7955cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	/* SCRs base */
8055cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_SCR_STATUS_OFFSET	= 0x100,
8155cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_SCR_ERROR_OFFSET	= 0x104,
8255cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_SCR_CONTROL_OFFSET	= 0x108,
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8455cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	/* Port stride */
8555cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_PORT_OFFSET		= 0x200,
8655cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik
8755cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	/* Error interrupt status bit offsets */
8855cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_INT_ERROR_CRC		= 0x40,
8955cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_INT_ERROR_T		= 0x20,
9055cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_INT_ERROR_P		= 0x10,
9155cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_INT_ERROR_R		= 0x8,
9255cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_INT_ERROR_E		= 0x4,
9355cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_INT_ERROR_M		= 0x2,
9455cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_INT_PHY_CHANGE		= 0x1,
9555cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik	VSC_SATA_INT_ERROR = (VSC_SATA_INT_ERROR_CRC  | VSC_SATA_INT_ERROR_T | \
9655cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik			      VSC_SATA_INT_ERROR_P    | VSC_SATA_INT_ERROR_R | \
9755cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik			      VSC_SATA_INT_ERROR_E    | VSC_SATA_INT_ERROR_M | \
9855cca65e1995ad604ee87e22c76c17d5cbceb9d0Jeff Garzik			      VSC_SATA_INT_PHY_CHANGE),
997cbaa86b937b0b1fab95c159989f6a3c00bbcf78Dan Wolstenholme};
100c962990a38167aacac91738501815deffa3afbd6Dan Williams
10182ef04fb4c82542b3eda81cca461f0594ce9cd0bTejun Heostatic int vsc_sata_scr_read(struct ata_link *link,
10282ef04fb4c82542b3eda81cca461f0594ce9cd0bTejun Heo			     unsigned int sc_reg, u32 *val)
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sc_reg > SCR_CONTROL)
105da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return -EINVAL;
10682ef04fb4c82542b3eda81cca461f0594ce9cd0bTejun Heo	*val = readl(link->ap->ioaddr.scr_addr + (sc_reg * 4));
107da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	return 0;
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11182ef04fb4c82542b3eda81cca461f0594ce9cd0bTejun Heostatic int vsc_sata_scr_write(struct ata_link *link,
11282ef04fb4c82542b3eda81cca461f0594ce9cd0bTejun Heo			      unsigned int sc_reg, u32 val)
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sc_reg > SCR_CONTROL)
115da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return -EINVAL;
11682ef04fb4c82542b3eda81cca461f0594ce9cd0bTejun Heo	writel(val, link->ap->ioaddr.scr_addr + (sc_reg * 4));
117da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	return 0;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
121ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williamsstatic void vsc_freeze(struct ata_port *ap)
122ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams{
123ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	void __iomem *mask_addr;
124ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams
125ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	mask_addr = ap->host->iomap[VSC_MMIO_BAR] +
126ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams		VSC_SATA_INT_MASK_OFFSET + ap->port_no;
127ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams
128ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	writeb(0, mask_addr);
129ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams}
130ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams
131ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams
132ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williamsstatic void vsc_thaw(struct ata_port *ap)
133ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams{
134ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	void __iomem *mask_addr;
135ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams
136ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	mask_addr = ap->host->iomap[VSC_MMIO_BAR] +
137ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams		VSC_SATA_INT_MASK_OFFSET + ap->port_no;
138ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams
139ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	writeb(0xff, mask_addr);
140ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams}
141ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams
142ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void vsc_intr_mask_update(struct ata_port *ap, u8 ctl)
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
145307e4dc28ee255bf22b431f242f847c9d96fe3faAl Viro	void __iomem *mask_addr;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 mask;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1480d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	mask_addr = ap->host->iomap[VSC_MMIO_BAR] +
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		VSC_SATA_INT_MASK_OFFSET + ap->port_no;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mask = readb(mask_addr);
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ctl & ATA_NIEN)
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mask |= 0x80;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mask &= 0x7F;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writeb(mask, mask_addr);
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
159057ace5e79da9ebf2aa82833cfea825533ac06fbJeff Garzikstatic void vsc_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ata_ioports *ioaddr = &ap->ioaddr;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * The only thing the ctl register is used for is SRST.
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * That is not enabled or disabled via tf_load.
1675796d1c4c89efff823259fda35b08ea66ebf8b23Jeff Garzik	 * However, if ATA_NIEN is changed, then we need to change
1685796d1c4c89efff823259fda35b08ea66ebf8b23Jeff Garzik	 * the interrupt register.
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((tf->ctl & ATA_NIEN) != (ap->last_ctl & ATA_NIEN)) {
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ap->last_ctl = tf->ctl;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vsc_intr_mask_update(ap, tf->ctl & ATA_NIEN);
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
175850a9d8a8bbeeba8263025a983d1c18e5e250f5dJeff Garzik		writew(tf->feature | (((u16)tf->hob_feature) << 8),
1760d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo		       ioaddr->feature_addr);
177850a9d8a8bbeeba8263025a983d1c18e5e250f5dJeff Garzik		writew(tf->nsect | (((u16)tf->hob_nsect) << 8),
1780d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo		       ioaddr->nsect_addr);
179850a9d8a8bbeeba8263025a983d1c18e5e250f5dJeff Garzik		writew(tf->lbal | (((u16)tf->hob_lbal) << 8),
1800d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo		       ioaddr->lbal_addr);
181850a9d8a8bbeeba8263025a983d1c18e5e250f5dJeff Garzik		writew(tf->lbam | (((u16)tf->hob_lbam) << 8),
1820d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo		       ioaddr->lbam_addr);
183850a9d8a8bbeeba8263025a983d1c18e5e250f5dJeff Garzik		writew(tf->lbah | (((u16)tf->hob_lbah) << 8),
1840d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo		       ioaddr->lbah_addr);
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (is_addr) {
1860d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo		writew(tf->feature, ioaddr->feature_addr);
1870d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo		writew(tf->nsect, ioaddr->nsect_addr);
1880d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo		writew(tf->lbal, ioaddr->lbal_addr);
1890d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo		writew(tf->lbam, ioaddr->lbam_addr);
1900d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo		writew(tf->lbah, ioaddr->lbah_addr);
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tf->flags & ATA_TFLAG_DEVICE)
1940d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo		writeb(tf->device, ioaddr->device_addr);
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ata_wait_idle(ap);
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ata_ioports *ioaddr = &ap->ioaddr;
203ac19bff25b6834d858274406a686f2227dd8489dJeff Garzik	u16 nsect, lbal, lbam, lbah, feature;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2059363c3825ea9ad76561eb48a395349dd29211ed6Tejun Heo	tf->command = ata_sff_check_status(ap);
2060d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	tf->device = readw(ioaddr->device_addr);
2070d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	feature = readw(ioaddr->error_addr);
2080d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	nsect = readw(ioaddr->nsect_addr);
2090d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	lbal = readw(ioaddr->lbal_addr);
2100d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	lbam = readw(ioaddr->lbam_addr);
2110d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	lbah = readw(ioaddr->lbah_addr);
212ac19bff25b6834d858274406a686f2227dd8489dJeff Garzik
213ac19bff25b6834d858274406a686f2227dd8489dJeff Garzik	tf->feature = feature;
214ac19bff25b6834d858274406a686f2227dd8489dJeff Garzik	tf->nsect = nsect;
215ac19bff25b6834d858274406a686f2227dd8489dJeff Garzik	tf->lbal = lbal;
216ac19bff25b6834d858274406a686f2227dd8489dJeff Garzik	tf->lbam = lbam;
217ac19bff25b6834d858274406a686f2227dd8489dJeff Garzik	tf->lbah = lbah;
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (tf->flags & ATA_TFLAG_LBA48) {
220ac19bff25b6834d858274406a686f2227dd8489dJeff Garzik		tf->hob_feature = feature >> 8;
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tf->hob_nsect = nsect >> 8;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tf->hob_lbal = lbal >> 8;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tf->hob_lbam = lbam >> 8;
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tf->hob_lbah = lbah >> 8;
2255796d1c4c89efff823259fda35b08ea66ebf8b23Jeff Garzik	}
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
228ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williamsstatic inline void vsc_error_intr(u8 port_status, struct ata_port *ap)
229ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams{
230ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	if (port_status & (VSC_SATA_INT_PHY_CHANGE | VSC_SATA_INT_ERROR_M))
231ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams		ata_port_freeze(ap);
232ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	else
233ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams		ata_port_abort(ap);
234ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams}
235ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams
236ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williamsstatic void vsc_port_intr(u8 port_status, struct ata_port *ap)
237ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams{
238ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	struct ata_queued_cmd *qc;
239ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	int handled = 0;
240ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams
241ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	if (unlikely(port_status & VSC_SATA_INT_ERROR)) {
242ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams		vsc_error_intr(port_status, ap);
243ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams		return;
244ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	}
245ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams
2469af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo	qc = ata_qc_from_tag(ap, ap->link.active_tag);
247ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	if (qc && likely(!(qc->tf.flags & ATA_TFLAG_POLLING)))
248c3b2889424c26f3b42962b6f39aabb4f1fd1b576Tejun Heo		handled = ata_bmdma_port_intr(ap, qc);
249ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams
250ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	/* We received an interrupt during a polled command,
251ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	 * or some other spurious condition.  Interrupt reporting
252ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	 * with this hardware is fairly reliable so it is safe to
253ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	 * simply clear the interrupt
254ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	 */
255ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	if (unlikely(!handled))
2565682ed33aae05d10a25c95633ef9d9c062825888Tejun Heo		ap->ops->sff_check_status(ap);
257ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams}
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * vsc_sata_interrupt
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2625796d1c4c89efff823259fda35b08ea66ebf8b23Jeff Garzik * Read the interrupt register and process for the devices that have
2635796d1c4c89efff823259fda35b08ea66ebf8b23Jeff Garzik * them pending.
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2655796d1c4c89efff823259fda35b08ea66ebf8b23Jeff Garzikstatic irqreturn_t vsc_sata_interrupt(int irq, void *dev_instance)
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
267cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	struct ata_host *host = dev_instance;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int i;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int handled = 0;
270ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	u32 status;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
272ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	status = readl(host->iomap[VSC_MMIO_BAR] + VSC_SATA_INT_STAT_OFFSET);
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
274ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	if (unlikely(status == 0xffffffff || status == 0)) {
275ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams		if (status)
276a44fec1fce5d5d14cc3ac4545b8da346394de666Joe Perches			dev_err(host->dev,
277a44fec1fce5d5d14cc3ac4545b8da346394de666Joe Perches				": IRQ status == 0xffffffff, PCI fault or device removal?\n");
278ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams		goto out;
279ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	}
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	spin_lock(&host->lock);
2822ae5b30ff08cee422c7f6388a759f743633c7542Dan Williams
283ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	for (i = 0; i < host->n_ports; i++) {
284ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams		u8 port_status = (status >> (8 * i)) & 0xff;
285ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams		if (port_status) {
2863e4ec3443f70fbe144799ccf0b1c3797f78d1715Tejun Heo			vsc_port_intr(port_status, host->ports[i]);
2873e4ec3443f70fbe144799ccf0b1c3797f78d1715Tejun Heo			handled++;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
291cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	spin_unlock(&host->lock);
292ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williamsout:
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_RETVAL(handled);
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
297193515d51ccb363165d6b09e9ba5c21089e34badJeff Garzikstatic struct scsi_host_template vsc_sata_sht = {
29868d1d07b510bb57a504588adc2bd2758adea0965Tejun Heo	ATA_BMDMA_SHT(DRV_NAME),
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
302029cfd6b74fc5c517865fad78cf4a3ea8d9b664aTejun Heostatic struct ata_port_operations vsc_sata_ops = {
303029cfd6b74fc5c517865fad78cf4a3ea8d9b664aTejun Heo	.inherits		= &ata_bmdma_port_ops,
304c96f1732e25362d10ee7bcac1df8412a2e6b7d23Alan Cox	/* The IRQ handling is not quite standard SFF behaviour so we
305c96f1732e25362d10ee7bcac1df8412a2e6b7d23Alan Cox	   cannot use the default lost interrupt handler */
306c96f1732e25362d10ee7bcac1df8412a2e6b7d23Alan Cox	.lost_interrupt		= ATA_OP_NULL,
3075682ed33aae05d10a25c95633ef9d9c062825888Tejun Heo	.sff_tf_load		= vsc_sata_tf_load,
3085682ed33aae05d10a25c95633ef9d9c062825888Tejun Heo	.sff_tf_read		= vsc_sata_tf_read,
309ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	.freeze			= vsc_freeze,
310ea34e45a4670c4fa0da3442fc74789fd66c1201bDan Williams	.thaw			= vsc_thaw,
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.scr_read		= vsc_sata_scr_read,
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.scr_write		= vsc_sata_scr_write,
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3150d5ff566779f894ca9937231a181eb31e4adff0eTejun Heostatic void __devinit vsc_sata_setup_port(struct ata_ioports *port,
3160d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo					  void __iomem *base)
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->cmd_addr		= base + VSC_SATA_TF_CMD_OFFSET;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->data_addr		= base + VSC_SATA_TF_DATA_OFFSET;
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->error_addr	= base + VSC_SATA_TF_ERROR_OFFSET;
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->feature_addr	= base + VSC_SATA_TF_FEATURE_OFFSET;
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->nsect_addr	= base + VSC_SATA_TF_NSECT_OFFSET;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->lbal_addr		= base + VSC_SATA_TF_LBAL_OFFSET;
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->lbam_addr		= base + VSC_SATA_TF_LBAM_OFFSET;
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->lbah_addr		= base + VSC_SATA_TF_LBAH_OFFSET;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->device_addr	= base + VSC_SATA_TF_DEVICE_OFFSET;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->status_addr	= base + VSC_SATA_TF_STATUS_OFFSET;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->command_addr	= base + VSC_SATA_TF_COMMAND_OFFSET;
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->altstatus_addr	= base + VSC_SATA_TF_ALTSTATUS_OFFSET;
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->ctl_addr		= base + VSC_SATA_TF_CTL_OFFSET;
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->bmdma_addr	= base + VSC_SATA_DMA_CMD_OFFSET;
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	port->scr_addr		= base + VSC_SATA_SCR_STATUS_OFFSET;
3330d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	writel(0, base + VSC_SATA_UP_DESCRIPTOR_OFFSET);
3340d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	writel(0, base + VSC_SATA_UP_DATA_BUFFER_OFFSET);
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3385796d1c4c89efff823259fda35b08ea66ebf8b23Jeff Garzikstatic int __devinit vsc_sata_init_one(struct pci_dev *pdev,
3395796d1c4c89efff823259fda35b08ea66ebf8b23Jeff Garzik				       const struct pci_device_id *ent)
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3414447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	static const struct ata_port_info pi = {
3429cbe056f6c467e7395d5aec39aceec47812eb98eSergei Shtylyov		.flags		= ATA_FLAG_SATA,
34314bdef982caeda19afe34010482867c18217c641Erik Inge Bolsø		.pio_mask	= ATA_PIO4,
34414bdef982caeda19afe34010482867c18217c641Erik Inge Bolsø		.mwdma_mask	= ATA_MWDMA2,
345bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA6,
3464447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo		.port_ops	= &vsc_sata_ops,
3474447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	};
3484447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	const struct ata_port_info *ppi[] = { &pi, NULL };
3494447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct ata_host *host;
350307e4dc28ee255bf22b431f242f847c9d96fe3faAl Viro	void __iomem *mmio_base;
3514447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	int i, rc;
3527de970e11fb832a56c897276967fb0e49f59b313Nate Dailey	u8 cls;
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
35406296a1e684bcd40b9a28d5d8030809e4295528bJoe Perches	ata_print_version_once(&pdev->dev, DRV_VERSION);
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3564447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	/* allocate host */
3574447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	host = ata_host_alloc_pinfo(&pdev->dev, ppi, 4);
3584447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	if (!host)
3594447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo		return -ENOMEM;
3604447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo
36124dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	rc = pcim_enable_device(pdev);
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc)
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return rc;
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3654447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	/* check if we have needed resource mapped */
36624dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	if (pci_resource_len(pdev, 0) == 0)
36724dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return -ENODEV;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
369b595076a180a56d1bb170e6eceda6eb9d76f4cd3Uwe Kleine-König	/* map IO regions and initialize host accordingly */
3700d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	rc = pcim_iomap_regions(pdev, 1 << VSC_MMIO_BAR, DRV_NAME);
3710d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	if (rc == -EBUSY)
37224dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		pcim_pin_device(pdev);
3730d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	if (rc)
37424dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return rc;
3754447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	host->iomap = pcim_iomap_table(pdev);
3764447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo
3774447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	mmio_base = host->iomap[VSC_MMIO_BAR];
3784447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo
379cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo	for (i = 0; i < host->n_ports; i++) {
380cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo		struct ata_port *ap = host->ports[i];
381cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo		unsigned int offset = (i + 1) * VSC_SATA_PORT_OFFSET;
382cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo
383cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo		vsc_sata_setup_port(&ap->ioaddr, mmio_base + offset);
384cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo
385cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo		ata_port_pbar_desc(ap, VSC_MMIO_BAR, -1, "mmio");
386cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo		ata_port_pbar_desc(ap, VSC_MMIO_BAR, offset, "port");
387cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo	}
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Use 32 bit DMA mask, because 64 bit address support is poor.
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
392284901a90a9e0b812ca3f5f852cbbfb60d10249dYang Hongyang	rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc)
39424dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return rc;
395284901a90a9e0b812ca3f5f852cbbfb60d10249dYang Hongyang	rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc)
39724dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return rc;
3987cbaa86b937b0b1fab95c159989f6a3c00bbcf78Dan Wolstenholme
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4007de970e11fb832a56c897276967fb0e49f59b313Nate Dailey	 * Due to a bug in the chip, the default cache line size can't be
4017de970e11fb832a56c897276967fb0e49f59b313Nate Dailey	 * used (unless the default is non-zero).
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4037de970e11fb832a56c897276967fb0e49f59b313Nate Dailey	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cls);
4047de970e11fb832a56c897276967fb0e49f59b313Nate Dailey	if (cls == 0x00)
4057de970e11fb832a56c897276967fb0e49f59b313Nate Dailey		pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80);
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40724dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	if (pci_enable_msi(pdev) == 0)
4087cbaa86b937b0b1fab95c159989f6a3c00bbcf78Dan Wolstenholme		pci_intx(pdev, 0);
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4108a60a07129fad60bba779a2a4038c7518b167fc7Jeff Garzik	/*
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Config offset 0x98 is "Extended Control and Status Register 0"
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Default value is (1 << 28).  All bits except bit 28 are reserved in
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * DPA mode.  If bit 28 is set, LED 0 reflects all ports' activity.
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If bit 28 is clear, each port has its own LED.
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_write_config_dword(pdev, 0x98, 0);
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4184447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	pci_set_master(pdev);
4194447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	return ata_host_activate(host, pdev->irq, vsc_sata_interrupt,
4204447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo				 IRQF_SHARED, &vsc_sata_sht);
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4233b7d697dfb7d03edb87e50b743a7ecff029618e9Jeff Garzikstatic const struct pci_device_id vsc_sata_pci_tbl[] = {
424438bc9c3dec27ab37f0ff78471d0b8b91addd2ddJeff Garzik	{ PCI_VENDOR_ID_VITESSE, 0x7174,
42574d0a988d3aa359b6b8a8536c8cb92cce02ca5d5Brent Casavant	  PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
426438bc9c3dec27ab37f0ff78471d0b8b91addd2ddJeff Garzik	{ PCI_VENDOR_ID_INTEL, 0x3200,
42774d0a988d3aa359b6b8a8536c8cb92cce02ca5d5Brent Casavant	  PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
4282d2744fc8be620a2dc469cf48349e3e704119f1bJeff Garzik
429438bc9c3dec27ab37f0ff78471d0b8b91addd2ddJeff Garzik	{ }	/* terminate list */
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_driver vsc_sata_pci_driver = {
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name			= DRV_NAME,
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id_table		= vsc_sata_pci_tbl,
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe			= vsc_sata_init_one,
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.remove			= ata_pci_remove_one,
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init vsc_sata_init(void)
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
441b7887196e38da54ff893897b80875d632d1a1114Pavel Roskin	return pci_register_driver(&vsc_sata_pci_driver);
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit vsc_sata_exit(void)
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_unregister_driver(&vsc_sata_pci_driver);
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Jeremy Higdon");
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("low-level driver for Vitesse VSC7174 SATA controller");
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(pci, vsc_sata_pci_tbl);
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_VERSION(DRV_VERSION);
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(vsc_sata_init);
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(vsc_sata_exit);
457