| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | *  sata_vsc.c - Vitesse VSC7174 4 port DPA SATA | 
|  | 3 | * | 
|  | 4 | *  Maintained by:  Jeremy Higdon @ SGI | 
|  | 5 | * 		    Please ALWAYS copy linux-ide@vger.kernel.org | 
|  | 6 | *		    on emails. | 
|  | 7 | * | 
|  | 8 | *  Copyright 2004 SGI | 
|  | 9 | * | 
|  | 10 | *  Bits from Jeff Garzik, Copyright RedHat, Inc. | 
|  | 11 | * | 
| Jeff Garzik | af36d7f | 2005-08-28 20:18:39 -0400 | [diff] [blame] | 12 | * | 
|  | 13 | *  This program is free software; you can redistribute it and/or modify | 
|  | 14 | *  it under the terms of the GNU General Public License as published by | 
|  | 15 | *  the Free Software Foundation; either version 2, or (at your option) | 
|  | 16 | *  any later version. | 
|  | 17 | * | 
|  | 18 | *  This program is distributed in the hope that it will be useful, | 
|  | 19 | *  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 20 | *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | 21 | *  GNU General Public License for more details. | 
|  | 22 | * | 
|  | 23 | *  You should have received a copy of the GNU General Public License | 
|  | 24 | *  along with this program; see the file COPYING.  If not, write to | 
|  | 25 | *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | 
|  | 26 | * | 
|  | 27 | * | 
|  | 28 | *  libata documentation is available via 'make {ps|pdf}docs', | 
|  | 29 | *  as Documentation/DocBook/libata.* | 
|  | 30 | * | 
|  | 31 | *  Vitesse hardware documentation presumably available under NDA. | 
|  | 32 | *  Intel 31244 (same hardware interface) documentation presumably | 
|  | 33 | *  available from http://developer.intel.com/ | 
|  | 34 | * | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 35 | */ | 
|  | 36 |  | 
|  | 37 | #include <linux/kernel.h> | 
|  | 38 | #include <linux/module.h> | 
|  | 39 | #include <linux/pci.h> | 
|  | 40 | #include <linux/init.h> | 
|  | 41 | #include <linux/blkdev.h> | 
|  | 42 | #include <linux/delay.h> | 
|  | 43 | #include <linux/interrupt.h> | 
| domen@coderock.org | 7003c05 | 2005-04-08 09:53:09 +0200 | [diff] [blame] | 44 | #include <linux/dma-mapping.h> | 
| Jeff Garzik | a9524a7 | 2005-10-30 14:39:11 -0500 | [diff] [blame] | 45 | #include <linux/device.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 46 | #include "scsi.h" | 
|  | 47 | #include <scsi/scsi_host.h> | 
|  | 48 | #include <linux/libata.h> | 
|  | 49 |  | 
|  | 50 | #define DRV_NAME	"sata_vsc" | 
|  | 51 | #define DRV_VERSION	"1.0" | 
|  | 52 |  | 
|  | 53 | /* Interrupt register offsets (from chip base address) */ | 
|  | 54 | #define VSC_SATA_INT_STAT_OFFSET	0x00 | 
|  | 55 | #define VSC_SATA_INT_MASK_OFFSET	0x04 | 
|  | 56 |  | 
|  | 57 | /* Taskfile registers offsets */ | 
|  | 58 | #define VSC_SATA_TF_CMD_OFFSET		0x00 | 
|  | 59 | #define VSC_SATA_TF_DATA_OFFSET		0x00 | 
|  | 60 | #define VSC_SATA_TF_ERROR_OFFSET	0x04 | 
|  | 61 | #define VSC_SATA_TF_FEATURE_OFFSET	0x06 | 
|  | 62 | #define VSC_SATA_TF_NSECT_OFFSET	0x08 | 
|  | 63 | #define VSC_SATA_TF_LBAL_OFFSET		0x0c | 
|  | 64 | #define VSC_SATA_TF_LBAM_OFFSET		0x10 | 
|  | 65 | #define VSC_SATA_TF_LBAH_OFFSET		0x14 | 
|  | 66 | #define VSC_SATA_TF_DEVICE_OFFSET	0x18 | 
|  | 67 | #define VSC_SATA_TF_STATUS_OFFSET	0x1c | 
|  | 68 | #define VSC_SATA_TF_COMMAND_OFFSET	0x1d | 
|  | 69 | #define VSC_SATA_TF_ALTSTATUS_OFFSET	0x28 | 
|  | 70 | #define VSC_SATA_TF_CTL_OFFSET		0x29 | 
|  | 71 |  | 
|  | 72 | /* DMA base */ | 
|  | 73 | #define VSC_SATA_UP_DESCRIPTOR_OFFSET	0x64 | 
|  | 74 | #define VSC_SATA_UP_DATA_BUFFER_OFFSET	0x6C | 
|  | 75 | #define VSC_SATA_DMA_CMD_OFFSET		0x70 | 
|  | 76 |  | 
|  | 77 | /* SCRs base */ | 
|  | 78 | #define VSC_SATA_SCR_STATUS_OFFSET	0x100 | 
|  | 79 | #define VSC_SATA_SCR_ERROR_OFFSET	0x104 | 
|  | 80 | #define VSC_SATA_SCR_CONTROL_OFFSET	0x108 | 
|  | 81 |  | 
|  | 82 | /* Port stride */ | 
|  | 83 | #define VSC_SATA_PORT_OFFSET		0x200 | 
|  | 84 |  | 
|  | 85 |  | 
|  | 86 | static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) | 
|  | 87 | { | 
|  | 88 | if (sc_reg > SCR_CONTROL) | 
|  | 89 | return 0xffffffffU; | 
| Al Viro | 307e4dc | 2005-10-21 06:46:02 +0100 | [diff] [blame] | 90 | return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 91 | } | 
|  | 92 |  | 
|  | 93 |  | 
|  | 94 | static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, | 
|  | 95 | u32 val) | 
|  | 96 | { | 
|  | 97 | if (sc_reg > SCR_CONTROL) | 
|  | 98 | return; | 
| Al Viro | 307e4dc | 2005-10-21 06:46:02 +0100 | [diff] [blame] | 99 | writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 100 | } | 
|  | 101 |  | 
|  | 102 |  | 
|  | 103 | static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl) | 
|  | 104 | { | 
| Al Viro | 307e4dc | 2005-10-21 06:46:02 +0100 | [diff] [blame] | 105 | void __iomem *mask_addr; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 106 | u8 mask; | 
|  | 107 |  | 
| Al Viro | 307e4dc | 2005-10-21 06:46:02 +0100 | [diff] [blame] | 108 | mask_addr = ap->host_set->mmio_base + | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 109 | VSC_SATA_INT_MASK_OFFSET + ap->port_no; | 
|  | 110 | mask = readb(mask_addr); | 
|  | 111 | if (ctl & ATA_NIEN) | 
|  | 112 | mask |= 0x80; | 
|  | 113 | else | 
|  | 114 | mask &= 0x7F; | 
|  | 115 | writeb(mask, mask_addr); | 
|  | 116 | } | 
|  | 117 |  | 
|  | 118 |  | 
| Jeff Garzik | 057ace5 | 2005-10-22 14:27:05 -0400 | [diff] [blame] | 119 | static void vsc_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 120 | { | 
|  | 121 | struct ata_ioports *ioaddr = &ap->ioaddr; | 
|  | 122 | unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; | 
|  | 123 |  | 
|  | 124 | /* | 
|  | 125 | * The only thing the ctl register is used for is SRST. | 
|  | 126 | * That is not enabled or disabled via tf_load. | 
|  | 127 | * However, if ATA_NIEN is changed, then we need to change the interrupt register. | 
|  | 128 | */ | 
|  | 129 | if ((tf->ctl & ATA_NIEN) != (ap->last_ctl & ATA_NIEN)) { | 
|  | 130 | ap->last_ctl = tf->ctl; | 
|  | 131 | vsc_intr_mask_update(ap, tf->ctl & ATA_NIEN); | 
|  | 132 | } | 
|  | 133 | if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { | 
|  | 134 | writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->feature_addr); | 
|  | 135 | writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr); | 
|  | 136 | writew(tf->lbal | (((u16)tf->hob_lbal) << 8), ioaddr->lbal_addr); | 
|  | 137 | writew(tf->lbam | (((u16)tf->hob_lbam) << 8), ioaddr->lbam_addr); | 
|  | 138 | writew(tf->lbah | (((u16)tf->hob_lbah) << 8), ioaddr->lbah_addr); | 
|  | 139 | } else if (is_addr) { | 
|  | 140 | writew(tf->feature, ioaddr->feature_addr); | 
|  | 141 | writew(tf->nsect, ioaddr->nsect_addr); | 
|  | 142 | writew(tf->lbal, ioaddr->lbal_addr); | 
|  | 143 | writew(tf->lbam, ioaddr->lbam_addr); | 
|  | 144 | writew(tf->lbah, ioaddr->lbah_addr); | 
|  | 145 | } | 
|  | 146 |  | 
|  | 147 | if (tf->flags & ATA_TFLAG_DEVICE) | 
|  | 148 | writeb(tf->device, ioaddr->device_addr); | 
|  | 149 |  | 
|  | 150 | ata_wait_idle(ap); | 
|  | 151 | } | 
|  | 152 |  | 
|  | 153 |  | 
|  | 154 | static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) | 
|  | 155 | { | 
|  | 156 | struct ata_ioports *ioaddr = &ap->ioaddr; | 
| Jeff Garzik | ac19bff | 2005-10-29 13:58:21 -0400 | [diff] [blame] | 157 | u16 nsect, lbal, lbam, lbah, feature; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 158 |  | 
| Jeff Garzik | ac19bff | 2005-10-29 13:58:21 -0400 | [diff] [blame] | 159 | tf->command = ata_check_status(ap); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 160 | tf->device = readw(ioaddr->device_addr); | 
| Jeff Garzik | ac19bff | 2005-10-29 13:58:21 -0400 | [diff] [blame] | 161 | feature = readw(ioaddr->error_addr); | 
|  | 162 | nsect = readw(ioaddr->nsect_addr); | 
|  | 163 | lbal = readw(ioaddr->lbal_addr); | 
|  | 164 | lbam = readw(ioaddr->lbam_addr); | 
|  | 165 | lbah = readw(ioaddr->lbah_addr); | 
|  | 166 |  | 
|  | 167 | tf->feature = feature; | 
|  | 168 | tf->nsect = nsect; | 
|  | 169 | tf->lbal = lbal; | 
|  | 170 | tf->lbam = lbam; | 
|  | 171 | tf->lbah = lbah; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 172 |  | 
|  | 173 | if (tf->flags & ATA_TFLAG_LBA48) { | 
| Jeff Garzik | ac19bff | 2005-10-29 13:58:21 -0400 | [diff] [blame] | 174 | tf->hob_feature = feature >> 8; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 175 | tf->hob_nsect = nsect >> 8; | 
|  | 176 | tf->hob_lbal = lbal >> 8; | 
|  | 177 | tf->hob_lbam = lbam >> 8; | 
|  | 178 | tf->hob_lbah = lbah >> 8; | 
|  | 179 | } | 
|  | 180 | } | 
|  | 181 |  | 
|  | 182 |  | 
|  | 183 | /* | 
|  | 184 | * vsc_sata_interrupt | 
|  | 185 | * | 
|  | 186 | * Read the interrupt register and process for the devices that have them pending. | 
|  | 187 | */ | 
|  | 188 | static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance, | 
|  | 189 | struct pt_regs *regs) | 
|  | 190 | { | 
|  | 191 | struct ata_host_set *host_set = dev_instance; | 
|  | 192 | unsigned int i; | 
|  | 193 | unsigned int handled = 0; | 
|  | 194 | u32 int_status; | 
|  | 195 |  | 
|  | 196 | spin_lock(&host_set->lock); | 
|  | 197 |  | 
|  | 198 | int_status = readl(host_set->mmio_base + VSC_SATA_INT_STAT_OFFSET); | 
|  | 199 |  | 
|  | 200 | for (i = 0; i < host_set->n_ports; i++) { | 
|  | 201 | if (int_status & ((u32) 0xFF << (8 * i))) { | 
|  | 202 | struct ata_port *ap; | 
|  | 203 |  | 
|  | 204 | ap = host_set->ports[i]; | 
| Tejun Heo | c138950 | 2005-08-22 14:59:24 +0900 | [diff] [blame] | 205 | if (ap && !(ap->flags & | 
|  | 206 | (ATA_FLAG_PORT_DISABLED|ATA_FLAG_NOINTR))) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 207 | struct ata_queued_cmd *qc; | 
|  | 208 |  | 
|  | 209 | qc = ata_qc_from_tag(ap, ap->active_tag); | 
|  | 210 | if (qc && (!(qc->tf.ctl & ATA_NIEN))) | 
|  | 211 | handled += ata_host_intr(ap, qc); | 
|  | 212 | } | 
|  | 213 | } | 
|  | 214 | } | 
|  | 215 |  | 
|  | 216 | spin_unlock(&host_set->lock); | 
|  | 217 |  | 
|  | 218 | return IRQ_RETVAL(handled); | 
|  | 219 | } | 
|  | 220 |  | 
|  | 221 |  | 
|  | 222 | static Scsi_Host_Template vsc_sata_sht = { | 
|  | 223 | .module			= THIS_MODULE, | 
|  | 224 | .name			= DRV_NAME, | 
|  | 225 | .ioctl			= ata_scsi_ioctl, | 
|  | 226 | .queuecommand		= ata_scsi_queuecmd, | 
|  | 227 | .eh_strategy_handler	= ata_scsi_error, | 
|  | 228 | .can_queue		= ATA_DEF_QUEUE, | 
|  | 229 | .this_id		= ATA_SHT_THIS_ID, | 
|  | 230 | .sg_tablesize		= LIBATA_MAX_PRD, | 
|  | 231 | .max_sectors		= ATA_MAX_SECTORS, | 
|  | 232 | .cmd_per_lun		= ATA_SHT_CMD_PER_LUN, | 
|  | 233 | .emulated		= ATA_SHT_EMULATED, | 
|  | 234 | .use_clustering		= ATA_SHT_USE_CLUSTERING, | 
|  | 235 | .proc_name		= DRV_NAME, | 
|  | 236 | .dma_boundary		= ATA_DMA_BOUNDARY, | 
|  | 237 | .slave_configure	= ata_scsi_slave_config, | 
|  | 238 | .bios_param		= ata_std_bios_param, | 
|  | 239 | .ordered_flush		= 1, | 
|  | 240 | }; | 
|  | 241 |  | 
|  | 242 |  | 
| Jeff Garzik | 057ace5 | 2005-10-22 14:27:05 -0400 | [diff] [blame] | 243 | static const struct ata_port_operations vsc_sata_ops = { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 244 | .port_disable		= ata_port_disable, | 
|  | 245 | .tf_load		= vsc_sata_tf_load, | 
|  | 246 | .tf_read		= vsc_sata_tf_read, | 
|  | 247 | .exec_command		= ata_exec_command, | 
|  | 248 | .check_status		= ata_check_status, | 
|  | 249 | .dev_select		= ata_std_dev_select, | 
|  | 250 | .phy_reset		= sata_phy_reset, | 
|  | 251 | .bmdma_setup            = ata_bmdma_setup, | 
|  | 252 | .bmdma_start            = ata_bmdma_start, | 
|  | 253 | .bmdma_stop		= ata_bmdma_stop, | 
|  | 254 | .bmdma_status		= ata_bmdma_status, | 
|  | 255 | .qc_prep		= ata_qc_prep, | 
|  | 256 | .qc_issue		= ata_qc_issue_prot, | 
|  | 257 | .eng_timeout		= ata_eng_timeout, | 
|  | 258 | .irq_handler		= vsc_sata_interrupt, | 
|  | 259 | .irq_clear		= ata_bmdma_irq_clear, | 
|  | 260 | .scr_read		= vsc_sata_scr_read, | 
|  | 261 | .scr_write		= vsc_sata_scr_write, | 
|  | 262 | .port_start		= ata_port_start, | 
|  | 263 | .port_stop		= ata_port_stop, | 
| Jeff Garzik | 374b187 | 2005-08-30 05:42:52 -0400 | [diff] [blame] | 264 | .host_stop		= ata_pci_host_stop, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 265 | }; | 
|  | 266 |  | 
|  | 267 | static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned long base) | 
|  | 268 | { | 
|  | 269 | port->cmd_addr		= base + VSC_SATA_TF_CMD_OFFSET; | 
|  | 270 | port->data_addr		= base + VSC_SATA_TF_DATA_OFFSET; | 
|  | 271 | port->error_addr	= base + VSC_SATA_TF_ERROR_OFFSET; | 
|  | 272 | port->feature_addr	= base + VSC_SATA_TF_FEATURE_OFFSET; | 
|  | 273 | port->nsect_addr	= base + VSC_SATA_TF_NSECT_OFFSET; | 
|  | 274 | port->lbal_addr		= base + VSC_SATA_TF_LBAL_OFFSET; | 
|  | 275 | port->lbam_addr		= base + VSC_SATA_TF_LBAM_OFFSET; | 
|  | 276 | port->lbah_addr		= base + VSC_SATA_TF_LBAH_OFFSET; | 
|  | 277 | port->device_addr	= base + VSC_SATA_TF_DEVICE_OFFSET; | 
|  | 278 | port->status_addr	= base + VSC_SATA_TF_STATUS_OFFSET; | 
|  | 279 | port->command_addr	= base + VSC_SATA_TF_COMMAND_OFFSET; | 
|  | 280 | port->altstatus_addr	= base + VSC_SATA_TF_ALTSTATUS_OFFSET; | 
|  | 281 | port->ctl_addr		= base + VSC_SATA_TF_CTL_OFFSET; | 
|  | 282 | port->bmdma_addr	= base + VSC_SATA_DMA_CMD_OFFSET; | 
|  | 283 | port->scr_addr		= base + VSC_SATA_SCR_STATUS_OFFSET; | 
|  | 284 | writel(0, base + VSC_SATA_UP_DESCRIPTOR_OFFSET); | 
|  | 285 | writel(0, base + VSC_SATA_UP_DATA_BUFFER_OFFSET); | 
|  | 286 | } | 
|  | 287 |  | 
|  | 288 |  | 
|  | 289 | static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | 
|  | 290 | { | 
|  | 291 | static int printed_version; | 
|  | 292 | struct ata_probe_ent *probe_ent = NULL; | 
|  | 293 | unsigned long base; | 
|  | 294 | int pci_dev_busy = 0; | 
| Al Viro | 307e4dc | 2005-10-21 06:46:02 +0100 | [diff] [blame] | 295 | void __iomem *mmio_base; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 296 | int rc; | 
|  | 297 |  | 
|  | 298 | if (!printed_version++) | 
| Jeff Garzik | a9524a7 | 2005-10-30 14:39:11 -0500 | [diff] [blame] | 299 | dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 300 |  | 
|  | 301 | rc = pci_enable_device(pdev); | 
|  | 302 | if (rc) | 
|  | 303 | return rc; | 
|  | 304 |  | 
|  | 305 | /* | 
|  | 306 | * Check if we have needed resource mapped. | 
|  | 307 | */ | 
|  | 308 | if (pci_resource_len(pdev, 0) == 0) { | 
|  | 309 | rc = -ENODEV; | 
|  | 310 | goto err_out; | 
|  | 311 | } | 
|  | 312 |  | 
|  | 313 | rc = pci_request_regions(pdev, DRV_NAME); | 
|  | 314 | if (rc) { | 
|  | 315 | pci_dev_busy = 1; | 
|  | 316 | goto err_out; | 
|  | 317 | } | 
|  | 318 |  | 
|  | 319 | /* | 
|  | 320 | * Use 32 bit DMA mask, because 64 bit address support is poor. | 
|  | 321 | */ | 
|  | 322 | rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); | 
|  | 323 | if (rc) | 
|  | 324 | goto err_out_regions; | 
|  | 325 | rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); | 
|  | 326 | if (rc) | 
|  | 327 | goto err_out_regions; | 
|  | 328 |  | 
|  | 329 | probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); | 
|  | 330 | if (probe_ent == NULL) { | 
|  | 331 | rc = -ENOMEM; | 
|  | 332 | goto err_out_regions; | 
|  | 333 | } | 
|  | 334 | memset(probe_ent, 0, sizeof(*probe_ent)); | 
|  | 335 | probe_ent->dev = pci_dev_to_dev(pdev); | 
|  | 336 | INIT_LIST_HEAD(&probe_ent->node); | 
|  | 337 |  | 
| Jeff Garzik | 374b187 | 2005-08-30 05:42:52 -0400 | [diff] [blame] | 338 | mmio_base = pci_iomap(pdev, 0, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 339 | if (mmio_base == NULL) { | 
|  | 340 | rc = -ENOMEM; | 
|  | 341 | goto err_out_free_ent; | 
|  | 342 | } | 
|  | 343 | base = (unsigned long) mmio_base; | 
|  | 344 |  | 
|  | 345 | /* | 
|  | 346 | * Due to a bug in the chip, the default cache line size can't be used | 
|  | 347 | */ | 
|  | 348 | pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80); | 
|  | 349 |  | 
|  | 350 | probe_ent->sht = &vsc_sata_sht; | 
|  | 351 | probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | | 
|  | 352 | ATA_FLAG_MMIO | ATA_FLAG_SATA_RESET; | 
|  | 353 | probe_ent->port_ops = &vsc_sata_ops; | 
|  | 354 | probe_ent->n_ports = 4; | 
|  | 355 | probe_ent->irq = pdev->irq; | 
|  | 356 | probe_ent->irq_flags = SA_SHIRQ; | 
|  | 357 | probe_ent->mmio_base = mmio_base; | 
|  | 358 |  | 
|  | 359 | /* We don't care much about the PIO/UDMA masks, but the core won't like us | 
|  | 360 | * if we don't fill these | 
|  | 361 | */ | 
|  | 362 | probe_ent->pio_mask = 0x1f; | 
|  | 363 | probe_ent->mwdma_mask = 0x07; | 
|  | 364 | probe_ent->udma_mask = 0x7f; | 
|  | 365 |  | 
|  | 366 | /* We have 4 ports per PCI function */ | 
|  | 367 | vsc_sata_setup_port(&probe_ent->port[0], base + 1 * VSC_SATA_PORT_OFFSET); | 
|  | 368 | vsc_sata_setup_port(&probe_ent->port[1], base + 2 * VSC_SATA_PORT_OFFSET); | 
|  | 369 | vsc_sata_setup_port(&probe_ent->port[2], base + 3 * VSC_SATA_PORT_OFFSET); | 
|  | 370 | vsc_sata_setup_port(&probe_ent->port[3], base + 4 * VSC_SATA_PORT_OFFSET); | 
|  | 371 |  | 
|  | 372 | pci_set_master(pdev); | 
|  | 373 |  | 
| Jeff Garzik | 8a60a07 | 2005-07-31 13:13:24 -0400 | [diff] [blame] | 374 | /* | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 375 | * Config offset 0x98 is "Extended Control and Status Register 0" | 
|  | 376 | * Default value is (1 << 28).  All bits except bit 28 are reserved in | 
|  | 377 | * DPA mode.  If bit 28 is set, LED 0 reflects all ports' activity. | 
|  | 378 | * If bit 28 is clear, each port has its own LED. | 
|  | 379 | */ | 
|  | 380 | pci_write_config_dword(pdev, 0x98, 0); | 
|  | 381 |  | 
|  | 382 | /* FIXME: check ata_device_add return value */ | 
|  | 383 | ata_device_add(probe_ent); | 
|  | 384 | kfree(probe_ent); | 
|  | 385 |  | 
|  | 386 | return 0; | 
|  | 387 |  | 
|  | 388 | err_out_free_ent: | 
|  | 389 | kfree(probe_ent); | 
|  | 390 | err_out_regions: | 
|  | 391 | pci_release_regions(pdev); | 
|  | 392 | err_out: | 
|  | 393 | if (!pci_dev_busy) | 
|  | 394 | pci_disable_device(pdev); | 
|  | 395 | return rc; | 
|  | 396 | } | 
|  | 397 |  | 
|  | 398 |  | 
|  | 399 | /* | 
|  | 400 | * 0x1725/0x7174 is the Vitesse VSC-7174 | 
|  | 401 | * 0x8086/0x3200 is the Intel 31244, which is supposed to be identical | 
|  | 402 | * compatibility is untested as of yet | 
|  | 403 | */ | 
|  | 404 | static struct pci_device_id vsc_sata_pci_tbl[] = { | 
|  | 405 | { 0x1725, 0x7174, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, | 
|  | 406 | { 0x8086, 0x3200, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, | 
|  | 407 | { } | 
|  | 408 | }; | 
|  | 409 |  | 
|  | 410 |  | 
|  | 411 | static struct pci_driver vsc_sata_pci_driver = { | 
|  | 412 | .name			= DRV_NAME, | 
|  | 413 | .id_table		= vsc_sata_pci_tbl, | 
|  | 414 | .probe			= vsc_sata_init_one, | 
|  | 415 | .remove			= ata_pci_remove_one, | 
|  | 416 | }; | 
|  | 417 |  | 
|  | 418 |  | 
|  | 419 | static int __init vsc_sata_init(void) | 
|  | 420 | { | 
|  | 421 | return pci_module_init(&vsc_sata_pci_driver); | 
|  | 422 | } | 
|  | 423 |  | 
|  | 424 |  | 
|  | 425 | static void __exit vsc_sata_exit(void) | 
|  | 426 | { | 
|  | 427 | pci_unregister_driver(&vsc_sata_pci_driver); | 
|  | 428 | } | 
|  | 429 |  | 
|  | 430 |  | 
|  | 431 | MODULE_AUTHOR("Jeremy Higdon"); | 
|  | 432 | MODULE_DESCRIPTION("low-level driver for Vitesse VSC7174 SATA controller"); | 
|  | 433 | MODULE_LICENSE("GPL"); | 
|  | 434 | MODULE_DEVICE_TABLE(pci, vsc_sata_pci_tbl); | 
|  | 435 | MODULE_VERSION(DRV_VERSION); | 
|  | 436 |  | 
|  | 437 | module_init(vsc_sata_init); | 
|  | 438 | module_exit(vsc_sata_exit); |