1c6fd2807SJeff Garzik /* 2c6fd2807SJeff Garzik * sata_qstor.c - Pacific Digital Corporation QStor SATA 3c6fd2807SJeff Garzik * 4c6fd2807SJeff Garzik * Maintained by: Mark Lord <mlord@pobox.com> 5c6fd2807SJeff Garzik * 6c6fd2807SJeff Garzik * Copyright 2005 Pacific Digital Corporation. 7c6fd2807SJeff Garzik * (OSL/GPL code release authorized by Jalil Fadavi). 8c6fd2807SJeff Garzik * 9c6fd2807SJeff Garzik * 10c6fd2807SJeff Garzik * This program is free software; you can redistribute it and/or modify 11c6fd2807SJeff Garzik * it under the terms of the GNU General Public License as published by 12c6fd2807SJeff Garzik * the Free Software Foundation; either version 2, or (at your option) 13c6fd2807SJeff Garzik * any later version. 14c6fd2807SJeff Garzik * 15c6fd2807SJeff Garzik * This program is distributed in the hope that it will be useful, 16c6fd2807SJeff Garzik * but WITHOUT ANY WARRANTY; without even the implied warranty of 17c6fd2807SJeff Garzik * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18c6fd2807SJeff Garzik * GNU General Public License for more details. 19c6fd2807SJeff Garzik * 20c6fd2807SJeff Garzik * You should have received a copy of the GNU General Public License 21c6fd2807SJeff Garzik * along with this program; see the file COPYING. If not, write to 22c6fd2807SJeff Garzik * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 23c6fd2807SJeff Garzik * 24c6fd2807SJeff Garzik * 25c6fd2807SJeff Garzik * libata documentation is available via 'make {ps|pdf}docs', 26c6fd2807SJeff Garzik * as Documentation/DocBook/libata.* 27c6fd2807SJeff Garzik * 28c6fd2807SJeff Garzik */ 29c6fd2807SJeff Garzik 30c6fd2807SJeff Garzik #include <linux/kernel.h> 31c6fd2807SJeff Garzik #include <linux/module.h> 32c6fd2807SJeff Garzik #include <linux/pci.h> 33c6fd2807SJeff Garzik #include <linux/init.h> 34c6fd2807SJeff Garzik #include <linux/blkdev.h> 35c6fd2807SJeff Garzik #include <linux/delay.h> 36c6fd2807SJeff Garzik #include <linux/interrupt.h> 37c6fd2807SJeff Garzik #include <linux/sched.h> 38c6fd2807SJeff Garzik #include <linux/device.h> 39c6fd2807SJeff Garzik #include <scsi/scsi_host.h> 40c6fd2807SJeff Garzik #include <asm/io.h> 41c6fd2807SJeff Garzik #include <linux/libata.h> 42c6fd2807SJeff Garzik 43c6fd2807SJeff Garzik #define DRV_NAME "sata_qstor" 44c6fd2807SJeff Garzik #define DRV_VERSION "0.06" 45c6fd2807SJeff Garzik 46c6fd2807SJeff Garzik enum { 47c6fd2807SJeff Garzik QS_PORTS = 4, 48c6fd2807SJeff Garzik QS_MAX_PRD = LIBATA_MAX_PRD, 49c6fd2807SJeff Garzik QS_CPB_ORDER = 6, 50c6fd2807SJeff Garzik QS_CPB_BYTES = (1 << QS_CPB_ORDER), 51c6fd2807SJeff Garzik QS_PRD_BYTES = QS_MAX_PRD * 16, 52c6fd2807SJeff Garzik QS_PKT_BYTES = QS_CPB_BYTES + QS_PRD_BYTES, 53c6fd2807SJeff Garzik 54c6fd2807SJeff Garzik /* global register offsets */ 55c6fd2807SJeff Garzik QS_HCF_CNFG3 = 0x0003, /* host configuration offset */ 56c6fd2807SJeff Garzik QS_HID_HPHY = 0x0004, /* host physical interface info */ 57c6fd2807SJeff Garzik QS_HCT_CTRL = 0x00e4, /* global interrupt mask offset */ 58c6fd2807SJeff Garzik QS_HST_SFF = 0x0100, /* host status fifo offset */ 59c6fd2807SJeff Garzik QS_HVS_SERD3 = 0x0393, /* PHY enable offset */ 60c6fd2807SJeff Garzik 61c6fd2807SJeff Garzik /* global control bits */ 62c6fd2807SJeff Garzik QS_HPHY_64BIT = (1 << 1), /* 64-bit bus detected */ 63c6fd2807SJeff Garzik QS_CNFG3_GSRST = 0x01, /* global chip reset */ 64c6fd2807SJeff Garzik QS_SERD3_PHY_ENA = 0xf0, /* PHY detection ENAble*/ 65c6fd2807SJeff Garzik 66c6fd2807SJeff Garzik /* per-channel register offsets */ 67c6fd2807SJeff Garzik QS_CCF_CPBA = 0x0710, /* chan CPB base address */ 68c6fd2807SJeff Garzik QS_CCF_CSEP = 0x0718, /* chan CPB separation factor */ 69c6fd2807SJeff Garzik QS_CFC_HUFT = 0x0800, /* host upstream fifo threshold */ 70c6fd2807SJeff Garzik QS_CFC_HDFT = 0x0804, /* host downstream fifo threshold */ 71c6fd2807SJeff Garzik QS_CFC_DUFT = 0x0808, /* dev upstream fifo threshold */ 72c6fd2807SJeff Garzik QS_CFC_DDFT = 0x080c, /* dev downstream fifo threshold */ 73c6fd2807SJeff Garzik QS_CCT_CTR0 = 0x0900, /* chan control-0 offset */ 74c6fd2807SJeff Garzik QS_CCT_CTR1 = 0x0901, /* chan control-1 offset */ 75c6fd2807SJeff Garzik QS_CCT_CFF = 0x0a00, /* chan command fifo offset */ 76c6fd2807SJeff Garzik 77c6fd2807SJeff Garzik /* channel control bits */ 78c6fd2807SJeff Garzik QS_CTR0_REG = (1 << 1), /* register mode (vs. pkt mode) */ 79c6fd2807SJeff Garzik QS_CTR0_CLER = (1 << 2), /* clear channel errors */ 80c6fd2807SJeff Garzik QS_CTR1_RDEV = (1 << 1), /* sata phy/comms reset */ 81c6fd2807SJeff Garzik QS_CTR1_RCHN = (1 << 4), /* reset channel logic */ 82c6fd2807SJeff Garzik QS_CCF_RUN_PKT = 0x107, /* RUN a new dma PKT */ 83c6fd2807SJeff Garzik 84c6fd2807SJeff Garzik /* pkt sub-field headers */ 85c6fd2807SJeff Garzik QS_HCB_HDR = 0x01, /* Host Control Block header */ 86c6fd2807SJeff Garzik QS_DCB_HDR = 0x02, /* Device Control Block header */ 87c6fd2807SJeff Garzik 88c6fd2807SJeff Garzik /* pkt HCB flag bits */ 89c6fd2807SJeff Garzik QS_HF_DIRO = (1 << 0), /* data DIRection Out */ 90c6fd2807SJeff Garzik QS_HF_DAT = (1 << 3), /* DATa pkt */ 91c6fd2807SJeff Garzik QS_HF_IEN = (1 << 4), /* Interrupt ENable */ 92c6fd2807SJeff Garzik QS_HF_VLD = (1 << 5), /* VaLiD pkt */ 93c6fd2807SJeff Garzik 94c6fd2807SJeff Garzik /* pkt DCB flag bits */ 95c6fd2807SJeff Garzik QS_DF_PORD = (1 << 2), /* Pio OR Dma */ 96c6fd2807SJeff Garzik QS_DF_ELBA = (1 << 3), /* Extended LBA (lba48) */ 97c6fd2807SJeff Garzik 98c6fd2807SJeff Garzik /* PCI device IDs */ 99c6fd2807SJeff Garzik board_2068_idx = 0, /* QStor 4-port SATA/RAID */ 100c6fd2807SJeff Garzik }; 101c6fd2807SJeff Garzik 102c6fd2807SJeff Garzik enum { 103c6fd2807SJeff Garzik QS_DMA_BOUNDARY = ~0UL 104c6fd2807SJeff Garzik }; 105c6fd2807SJeff Garzik 106c6fd2807SJeff Garzik typedef enum { qs_state_idle, qs_state_pkt, qs_state_mmio } qs_state_t; 107c6fd2807SJeff Garzik 108c6fd2807SJeff Garzik struct qs_port_priv { 109c6fd2807SJeff Garzik u8 *pkt; 110c6fd2807SJeff Garzik dma_addr_t pkt_dma; 111c6fd2807SJeff Garzik qs_state_t state; 112c6fd2807SJeff Garzik }; 113c6fd2807SJeff Garzik 114c6fd2807SJeff Garzik static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg); 115c6fd2807SJeff Garzik static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); 116c6fd2807SJeff Garzik static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); 117c6fd2807SJeff Garzik static irqreturn_t qs_intr (int irq, void *dev_instance, struct pt_regs *regs); 118c6fd2807SJeff Garzik static int qs_port_start(struct ata_port *ap); 119cca3974eSJeff Garzik static void qs_host_stop(struct ata_host *host); 120c6fd2807SJeff Garzik static void qs_port_stop(struct ata_port *ap); 121c6fd2807SJeff Garzik static void qs_phy_reset(struct ata_port *ap); 122c6fd2807SJeff Garzik static void qs_qc_prep(struct ata_queued_cmd *qc); 123c6fd2807SJeff Garzik static unsigned int qs_qc_issue(struct ata_queued_cmd *qc); 124c6fd2807SJeff Garzik static int qs_check_atapi_dma(struct ata_queued_cmd *qc); 125c6fd2807SJeff Garzik static void qs_bmdma_stop(struct ata_queued_cmd *qc); 126c6fd2807SJeff Garzik static u8 qs_bmdma_status(struct ata_port *ap); 127c6fd2807SJeff Garzik static void qs_irq_clear(struct ata_port *ap); 128c6fd2807SJeff Garzik static void qs_eng_timeout(struct ata_port *ap); 129c6fd2807SJeff Garzik 130c6fd2807SJeff Garzik static struct scsi_host_template qs_ata_sht = { 131c6fd2807SJeff Garzik .module = THIS_MODULE, 132c6fd2807SJeff Garzik .name = DRV_NAME, 133c6fd2807SJeff Garzik .ioctl = ata_scsi_ioctl, 134c6fd2807SJeff Garzik .queuecommand = ata_scsi_queuecmd, 135c6fd2807SJeff Garzik .can_queue = ATA_DEF_QUEUE, 136c6fd2807SJeff Garzik .this_id = ATA_SHT_THIS_ID, 137c6fd2807SJeff Garzik .sg_tablesize = QS_MAX_PRD, 138c6fd2807SJeff Garzik .cmd_per_lun = ATA_SHT_CMD_PER_LUN, 139c6fd2807SJeff Garzik .emulated = ATA_SHT_EMULATED, 140c6fd2807SJeff Garzik //FIXME .use_clustering = ATA_SHT_USE_CLUSTERING, 141c6fd2807SJeff Garzik .use_clustering = ENABLE_CLUSTERING, 142c6fd2807SJeff Garzik .proc_name = DRV_NAME, 143c6fd2807SJeff Garzik .dma_boundary = QS_DMA_BOUNDARY, 144c6fd2807SJeff Garzik .slave_configure = ata_scsi_slave_config, 145c6fd2807SJeff Garzik .slave_destroy = ata_scsi_slave_destroy, 146c6fd2807SJeff Garzik .bios_param = ata_std_bios_param, 147c6fd2807SJeff Garzik }; 148c6fd2807SJeff Garzik 149c6fd2807SJeff Garzik static const struct ata_port_operations qs_ata_ops = { 150c6fd2807SJeff Garzik .port_disable = ata_port_disable, 151c6fd2807SJeff Garzik .tf_load = ata_tf_load, 152c6fd2807SJeff Garzik .tf_read = ata_tf_read, 153c6fd2807SJeff Garzik .check_status = ata_check_status, 154c6fd2807SJeff Garzik .check_atapi_dma = qs_check_atapi_dma, 155c6fd2807SJeff Garzik .exec_command = ata_exec_command, 156c6fd2807SJeff Garzik .dev_select = ata_std_dev_select, 157c6fd2807SJeff Garzik .phy_reset = qs_phy_reset, 158c6fd2807SJeff Garzik .qc_prep = qs_qc_prep, 159c6fd2807SJeff Garzik .qc_issue = qs_qc_issue, 160c6fd2807SJeff Garzik .data_xfer = ata_mmio_data_xfer, 161c6fd2807SJeff Garzik .eng_timeout = qs_eng_timeout, 162c6fd2807SJeff Garzik .irq_handler = qs_intr, 163c6fd2807SJeff Garzik .irq_clear = qs_irq_clear, 164c6fd2807SJeff Garzik .scr_read = qs_scr_read, 165c6fd2807SJeff Garzik .scr_write = qs_scr_write, 166c6fd2807SJeff Garzik .port_start = qs_port_start, 167c6fd2807SJeff Garzik .port_stop = qs_port_stop, 168c6fd2807SJeff Garzik .host_stop = qs_host_stop, 169c6fd2807SJeff Garzik .bmdma_stop = qs_bmdma_stop, 170c6fd2807SJeff Garzik .bmdma_status = qs_bmdma_status, 171c6fd2807SJeff Garzik }; 172c6fd2807SJeff Garzik 173c6fd2807SJeff Garzik static const struct ata_port_info qs_port_info[] = { 174c6fd2807SJeff Garzik /* board_2068_idx */ 175c6fd2807SJeff Garzik { 176c6fd2807SJeff Garzik .sht = &qs_ata_sht, 177cca3974eSJeff Garzik .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 178c6fd2807SJeff Garzik ATA_FLAG_SATA_RESET | 179c6fd2807SJeff Garzik //FIXME ATA_FLAG_SRST | 180c6fd2807SJeff Garzik ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING, 181c6fd2807SJeff Garzik .pio_mask = 0x10, /* pio4 */ 182c6fd2807SJeff Garzik .udma_mask = 0x7f, /* udma0-6 */ 183c6fd2807SJeff Garzik .port_ops = &qs_ata_ops, 184c6fd2807SJeff Garzik }, 185c6fd2807SJeff Garzik }; 186c6fd2807SJeff Garzik 187c6fd2807SJeff Garzik static const struct pci_device_id qs_ata_pci_tbl[] = { 1882d2744fcSJeff Garzik { PCI_VDEVICE(PDC, 0x2068), board_2068_idx }, 189c6fd2807SJeff Garzik 190c6fd2807SJeff Garzik { } /* terminate list */ 191c6fd2807SJeff Garzik }; 192c6fd2807SJeff Garzik 193c6fd2807SJeff Garzik static struct pci_driver qs_ata_pci_driver = { 194c6fd2807SJeff Garzik .name = DRV_NAME, 195c6fd2807SJeff Garzik .id_table = qs_ata_pci_tbl, 196c6fd2807SJeff Garzik .probe = qs_ata_init_one, 197c6fd2807SJeff Garzik .remove = ata_pci_remove_one, 198c6fd2807SJeff Garzik }; 199c6fd2807SJeff Garzik 200c6fd2807SJeff Garzik static int qs_check_atapi_dma(struct ata_queued_cmd *qc) 201c6fd2807SJeff Garzik { 202c6fd2807SJeff Garzik return 1; /* ATAPI DMA not supported */ 203c6fd2807SJeff Garzik } 204c6fd2807SJeff Garzik 205c6fd2807SJeff Garzik static void qs_bmdma_stop(struct ata_queued_cmd *qc) 206c6fd2807SJeff Garzik { 207c6fd2807SJeff Garzik /* nothing */ 208c6fd2807SJeff Garzik } 209c6fd2807SJeff Garzik 210c6fd2807SJeff Garzik static u8 qs_bmdma_status(struct ata_port *ap) 211c6fd2807SJeff Garzik { 212c6fd2807SJeff Garzik return 0; 213c6fd2807SJeff Garzik } 214c6fd2807SJeff Garzik 215c6fd2807SJeff Garzik static void qs_irq_clear(struct ata_port *ap) 216c6fd2807SJeff Garzik { 217c6fd2807SJeff Garzik /* nothing */ 218c6fd2807SJeff Garzik } 219c6fd2807SJeff Garzik 220c6fd2807SJeff Garzik static inline void qs_enter_reg_mode(struct ata_port *ap) 221c6fd2807SJeff Garzik { 222cca3974eSJeff Garzik u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000); 223c6fd2807SJeff Garzik 224c6fd2807SJeff Garzik writeb(QS_CTR0_REG, chan + QS_CCT_CTR0); 225c6fd2807SJeff Garzik readb(chan + QS_CCT_CTR0); /* flush */ 226c6fd2807SJeff Garzik } 227c6fd2807SJeff Garzik 228c6fd2807SJeff Garzik static inline void qs_reset_channel_logic(struct ata_port *ap) 229c6fd2807SJeff Garzik { 230cca3974eSJeff Garzik u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000); 231c6fd2807SJeff Garzik 232c6fd2807SJeff Garzik writeb(QS_CTR1_RCHN, chan + QS_CCT_CTR1); 233c6fd2807SJeff Garzik readb(chan + QS_CCT_CTR0); /* flush */ 234c6fd2807SJeff Garzik qs_enter_reg_mode(ap); 235c6fd2807SJeff Garzik } 236c6fd2807SJeff Garzik 237c6fd2807SJeff Garzik static void qs_phy_reset(struct ata_port *ap) 238c6fd2807SJeff Garzik { 239c6fd2807SJeff Garzik struct qs_port_priv *pp = ap->private_data; 240c6fd2807SJeff Garzik 241c6fd2807SJeff Garzik pp->state = qs_state_idle; 242c6fd2807SJeff Garzik qs_reset_channel_logic(ap); 243c6fd2807SJeff Garzik sata_phy_reset(ap); 244c6fd2807SJeff Garzik } 245c6fd2807SJeff Garzik 246c6fd2807SJeff Garzik static void qs_eng_timeout(struct ata_port *ap) 247c6fd2807SJeff Garzik { 248c6fd2807SJeff Garzik struct qs_port_priv *pp = ap->private_data; 249c6fd2807SJeff Garzik 250c6fd2807SJeff Garzik if (pp->state != qs_state_idle) /* healthy paranoia */ 251c6fd2807SJeff Garzik pp->state = qs_state_mmio; 252c6fd2807SJeff Garzik qs_reset_channel_logic(ap); 253c6fd2807SJeff Garzik ata_eng_timeout(ap); 254c6fd2807SJeff Garzik } 255c6fd2807SJeff Garzik 256c6fd2807SJeff Garzik static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg) 257c6fd2807SJeff Garzik { 258c6fd2807SJeff Garzik if (sc_reg > SCR_CONTROL) 259c6fd2807SJeff Garzik return ~0U; 260c6fd2807SJeff Garzik return readl((void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8))); 261c6fd2807SJeff Garzik } 262c6fd2807SJeff Garzik 263c6fd2807SJeff Garzik static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) 264c6fd2807SJeff Garzik { 265c6fd2807SJeff Garzik if (sc_reg > SCR_CONTROL) 266c6fd2807SJeff Garzik return; 267c6fd2807SJeff Garzik writel(val, (void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8))); 268c6fd2807SJeff Garzik } 269c6fd2807SJeff Garzik 270c6fd2807SJeff Garzik static unsigned int qs_fill_sg(struct ata_queued_cmd *qc) 271c6fd2807SJeff Garzik { 272c6fd2807SJeff Garzik struct scatterlist *sg; 273c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 274c6fd2807SJeff Garzik struct qs_port_priv *pp = ap->private_data; 275c6fd2807SJeff Garzik unsigned int nelem; 276c6fd2807SJeff Garzik u8 *prd = pp->pkt + QS_CPB_BYTES; 277c6fd2807SJeff Garzik 278c6fd2807SJeff Garzik WARN_ON(qc->__sg == NULL); 279c6fd2807SJeff Garzik WARN_ON(qc->n_elem == 0 && qc->pad_len == 0); 280c6fd2807SJeff Garzik 281c6fd2807SJeff Garzik nelem = 0; 282c6fd2807SJeff Garzik ata_for_each_sg(sg, qc) { 283c6fd2807SJeff Garzik u64 addr; 284c6fd2807SJeff Garzik u32 len; 285c6fd2807SJeff Garzik 286c6fd2807SJeff Garzik addr = sg_dma_address(sg); 287c6fd2807SJeff Garzik *(__le64 *)prd = cpu_to_le64(addr); 288c6fd2807SJeff Garzik prd += sizeof(u64); 289c6fd2807SJeff Garzik 290c6fd2807SJeff Garzik len = sg_dma_len(sg); 291c6fd2807SJeff Garzik *(__le32 *)prd = cpu_to_le32(len); 292c6fd2807SJeff Garzik prd += sizeof(u64); 293c6fd2807SJeff Garzik 294c6fd2807SJeff Garzik VPRINTK("PRD[%u] = (0x%llX, 0x%X)\n", nelem, 295c6fd2807SJeff Garzik (unsigned long long)addr, len); 296c6fd2807SJeff Garzik nelem++; 297c6fd2807SJeff Garzik } 298c6fd2807SJeff Garzik 299c6fd2807SJeff Garzik return nelem; 300c6fd2807SJeff Garzik } 301c6fd2807SJeff Garzik 302c6fd2807SJeff Garzik static void qs_qc_prep(struct ata_queued_cmd *qc) 303c6fd2807SJeff Garzik { 304c6fd2807SJeff Garzik struct qs_port_priv *pp = qc->ap->private_data; 305c6fd2807SJeff Garzik u8 dflags = QS_DF_PORD, *buf = pp->pkt; 306c6fd2807SJeff Garzik u8 hflags = QS_HF_DAT | QS_HF_IEN | QS_HF_VLD; 307c6fd2807SJeff Garzik u64 addr; 308c6fd2807SJeff Garzik unsigned int nelem; 309c6fd2807SJeff Garzik 310c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 311c6fd2807SJeff Garzik 312c6fd2807SJeff Garzik qs_enter_reg_mode(qc->ap); 313c6fd2807SJeff Garzik if (qc->tf.protocol != ATA_PROT_DMA) { 314c6fd2807SJeff Garzik ata_qc_prep(qc); 315c6fd2807SJeff Garzik return; 316c6fd2807SJeff Garzik } 317c6fd2807SJeff Garzik 318c6fd2807SJeff Garzik nelem = qs_fill_sg(qc); 319c6fd2807SJeff Garzik 320c6fd2807SJeff Garzik if ((qc->tf.flags & ATA_TFLAG_WRITE)) 321c6fd2807SJeff Garzik hflags |= QS_HF_DIRO; 322c6fd2807SJeff Garzik if ((qc->tf.flags & ATA_TFLAG_LBA48)) 323c6fd2807SJeff Garzik dflags |= QS_DF_ELBA; 324c6fd2807SJeff Garzik 325c6fd2807SJeff Garzik /* host control block (HCB) */ 326c6fd2807SJeff Garzik buf[ 0] = QS_HCB_HDR; 327c6fd2807SJeff Garzik buf[ 1] = hflags; 328c6fd2807SJeff Garzik *(__le32 *)(&buf[ 4]) = cpu_to_le32(qc->nsect * ATA_SECT_SIZE); 329c6fd2807SJeff Garzik *(__le32 *)(&buf[ 8]) = cpu_to_le32(nelem); 330c6fd2807SJeff Garzik addr = ((u64)pp->pkt_dma) + QS_CPB_BYTES; 331c6fd2807SJeff Garzik *(__le64 *)(&buf[16]) = cpu_to_le64(addr); 332c6fd2807SJeff Garzik 333c6fd2807SJeff Garzik /* device control block (DCB) */ 334c6fd2807SJeff Garzik buf[24] = QS_DCB_HDR; 335c6fd2807SJeff Garzik buf[28] = dflags; 336c6fd2807SJeff Garzik 337c6fd2807SJeff Garzik /* frame information structure (FIS) */ 338c6fd2807SJeff Garzik ata_tf_to_fis(&qc->tf, &buf[32], 0); 339c6fd2807SJeff Garzik } 340c6fd2807SJeff Garzik 341c6fd2807SJeff Garzik static inline void qs_packet_start(struct ata_queued_cmd *qc) 342c6fd2807SJeff Garzik { 343c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 344cca3974eSJeff Garzik u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000); 345c6fd2807SJeff Garzik 346c6fd2807SJeff Garzik VPRINTK("ENTER, ap %p\n", ap); 347c6fd2807SJeff Garzik 348c6fd2807SJeff Garzik writeb(QS_CTR0_CLER, chan + QS_CCT_CTR0); 349c6fd2807SJeff Garzik wmb(); /* flush PRDs and pkt to memory */ 350c6fd2807SJeff Garzik writel(QS_CCF_RUN_PKT, chan + QS_CCT_CFF); 351c6fd2807SJeff Garzik readl(chan + QS_CCT_CFF); /* flush */ 352c6fd2807SJeff Garzik } 353c6fd2807SJeff Garzik 354c6fd2807SJeff Garzik static unsigned int qs_qc_issue(struct ata_queued_cmd *qc) 355c6fd2807SJeff Garzik { 356c6fd2807SJeff Garzik struct qs_port_priv *pp = qc->ap->private_data; 357c6fd2807SJeff Garzik 358c6fd2807SJeff Garzik switch (qc->tf.protocol) { 359c6fd2807SJeff Garzik case ATA_PROT_DMA: 360c6fd2807SJeff Garzik 361c6fd2807SJeff Garzik pp->state = qs_state_pkt; 362c6fd2807SJeff Garzik qs_packet_start(qc); 363c6fd2807SJeff Garzik return 0; 364c6fd2807SJeff Garzik 365c6fd2807SJeff Garzik case ATA_PROT_ATAPI_DMA: 366c6fd2807SJeff Garzik BUG(); 367c6fd2807SJeff Garzik break; 368c6fd2807SJeff Garzik 369c6fd2807SJeff Garzik default: 370c6fd2807SJeff Garzik break; 371c6fd2807SJeff Garzik } 372c6fd2807SJeff Garzik 373c6fd2807SJeff Garzik pp->state = qs_state_mmio; 374c6fd2807SJeff Garzik return ata_qc_issue_prot(qc); 375c6fd2807SJeff Garzik } 376c6fd2807SJeff Garzik 377cca3974eSJeff Garzik static inline unsigned int qs_intr_pkt(struct ata_host *host) 378c6fd2807SJeff Garzik { 379c6fd2807SJeff Garzik unsigned int handled = 0; 380c6fd2807SJeff Garzik u8 sFFE; 381cca3974eSJeff Garzik u8 __iomem *mmio_base = host->mmio_base; 382c6fd2807SJeff Garzik 383c6fd2807SJeff Garzik do { 384c6fd2807SJeff Garzik u32 sff0 = readl(mmio_base + QS_HST_SFF); 385c6fd2807SJeff Garzik u32 sff1 = readl(mmio_base + QS_HST_SFF + 4); 386c6fd2807SJeff Garzik u8 sEVLD = (sff1 >> 30) & 0x01; /* valid flag */ 387c6fd2807SJeff Garzik sFFE = sff1 >> 31; /* empty flag */ 388c6fd2807SJeff Garzik 389c6fd2807SJeff Garzik if (sEVLD) { 390c6fd2807SJeff Garzik u8 sDST = sff0 >> 16; /* dev status */ 391c6fd2807SJeff Garzik u8 sHST = sff1 & 0x3f; /* host status */ 392c6fd2807SJeff Garzik unsigned int port_no = (sff1 >> 8) & 0x03; 393cca3974eSJeff Garzik struct ata_port *ap = host->ports[port_no]; 394c6fd2807SJeff Garzik 395c6fd2807SJeff Garzik DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n", 396c6fd2807SJeff Garzik sff1, sff0, port_no, sHST, sDST); 397c6fd2807SJeff Garzik handled = 1; 398c6fd2807SJeff Garzik if (ap && !(ap->flags & ATA_FLAG_DISABLED)) { 399c6fd2807SJeff Garzik struct ata_queued_cmd *qc; 400c6fd2807SJeff Garzik struct qs_port_priv *pp = ap->private_data; 401c6fd2807SJeff Garzik if (!pp || pp->state != qs_state_pkt) 402c6fd2807SJeff Garzik continue; 403c6fd2807SJeff Garzik qc = ata_qc_from_tag(ap, ap->active_tag); 404c6fd2807SJeff Garzik if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { 405c6fd2807SJeff Garzik switch (sHST) { 406c6fd2807SJeff Garzik case 0: /* successful CPB */ 407c6fd2807SJeff Garzik case 3: /* device error */ 408c6fd2807SJeff Garzik pp->state = qs_state_idle; 409c6fd2807SJeff Garzik qs_enter_reg_mode(qc->ap); 410c6fd2807SJeff Garzik qc->err_mask |= ac_err_mask(sDST); 411c6fd2807SJeff Garzik ata_qc_complete(qc); 412c6fd2807SJeff Garzik break; 413c6fd2807SJeff Garzik default: 414c6fd2807SJeff Garzik break; 415c6fd2807SJeff Garzik } 416c6fd2807SJeff Garzik } 417c6fd2807SJeff Garzik } 418c6fd2807SJeff Garzik } 419c6fd2807SJeff Garzik } while (!sFFE); 420c6fd2807SJeff Garzik return handled; 421c6fd2807SJeff Garzik } 422c6fd2807SJeff Garzik 423cca3974eSJeff Garzik static inline unsigned int qs_intr_mmio(struct ata_host *host) 424c6fd2807SJeff Garzik { 425c6fd2807SJeff Garzik unsigned int handled = 0, port_no; 426c6fd2807SJeff Garzik 427cca3974eSJeff Garzik for (port_no = 0; port_no < host->n_ports; ++port_no) { 428c6fd2807SJeff Garzik struct ata_port *ap; 429cca3974eSJeff Garzik ap = host->ports[port_no]; 430c6fd2807SJeff Garzik if (ap && 431c6fd2807SJeff Garzik !(ap->flags & ATA_FLAG_DISABLED)) { 432c6fd2807SJeff Garzik struct ata_queued_cmd *qc; 433c6fd2807SJeff Garzik struct qs_port_priv *pp = ap->private_data; 434c6fd2807SJeff Garzik if (!pp || pp->state != qs_state_mmio) 435c6fd2807SJeff Garzik continue; 436c6fd2807SJeff Garzik qc = ata_qc_from_tag(ap, ap->active_tag); 437c6fd2807SJeff Garzik if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { 438c6fd2807SJeff Garzik 439c6fd2807SJeff Garzik /* check main status, clearing INTRQ */ 440c6fd2807SJeff Garzik u8 status = ata_check_status(ap); 441c6fd2807SJeff Garzik if ((status & ATA_BUSY)) 442c6fd2807SJeff Garzik continue; 443c6fd2807SJeff Garzik DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", 444c6fd2807SJeff Garzik ap->id, qc->tf.protocol, status); 445c6fd2807SJeff Garzik 446c6fd2807SJeff Garzik /* complete taskfile transaction */ 447c6fd2807SJeff Garzik pp->state = qs_state_idle; 448c6fd2807SJeff Garzik qc->err_mask |= ac_err_mask(status); 449c6fd2807SJeff Garzik ata_qc_complete(qc); 450c6fd2807SJeff Garzik handled = 1; 451c6fd2807SJeff Garzik } 452c6fd2807SJeff Garzik } 453c6fd2807SJeff Garzik } 454c6fd2807SJeff Garzik return handled; 455c6fd2807SJeff Garzik } 456c6fd2807SJeff Garzik 457c6fd2807SJeff Garzik static irqreturn_t qs_intr(int irq, void *dev_instance, struct pt_regs *regs) 458c6fd2807SJeff Garzik { 459cca3974eSJeff Garzik struct ata_host *host = dev_instance; 460c6fd2807SJeff Garzik unsigned int handled = 0; 461c6fd2807SJeff Garzik 462c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 463c6fd2807SJeff Garzik 464cca3974eSJeff Garzik spin_lock(&host->lock); 465cca3974eSJeff Garzik handled = qs_intr_pkt(host) | qs_intr_mmio(host); 466cca3974eSJeff Garzik spin_unlock(&host->lock); 467c6fd2807SJeff Garzik 468c6fd2807SJeff Garzik VPRINTK("EXIT\n"); 469c6fd2807SJeff Garzik 470c6fd2807SJeff Garzik return IRQ_RETVAL(handled); 471c6fd2807SJeff Garzik } 472c6fd2807SJeff Garzik 473c6fd2807SJeff Garzik static void qs_ata_setup_port(struct ata_ioports *port, unsigned long base) 474c6fd2807SJeff Garzik { 475c6fd2807SJeff Garzik port->cmd_addr = 476c6fd2807SJeff Garzik port->data_addr = base + 0x400; 477c6fd2807SJeff Garzik port->error_addr = 478c6fd2807SJeff Garzik port->feature_addr = base + 0x408; /* hob_feature = 0x409 */ 479c6fd2807SJeff Garzik port->nsect_addr = base + 0x410; /* hob_nsect = 0x411 */ 480c6fd2807SJeff Garzik port->lbal_addr = base + 0x418; /* hob_lbal = 0x419 */ 481c6fd2807SJeff Garzik port->lbam_addr = base + 0x420; /* hob_lbam = 0x421 */ 482c6fd2807SJeff Garzik port->lbah_addr = base + 0x428; /* hob_lbah = 0x429 */ 483c6fd2807SJeff Garzik port->device_addr = base + 0x430; 484c6fd2807SJeff Garzik port->status_addr = 485c6fd2807SJeff Garzik port->command_addr = base + 0x438; 486c6fd2807SJeff Garzik port->altstatus_addr = 487c6fd2807SJeff Garzik port->ctl_addr = base + 0x440; 488c6fd2807SJeff Garzik port->scr_addr = base + 0xc00; 489c6fd2807SJeff Garzik } 490c6fd2807SJeff Garzik 491c6fd2807SJeff Garzik static int qs_port_start(struct ata_port *ap) 492c6fd2807SJeff Garzik { 493cca3974eSJeff Garzik struct device *dev = ap->host->dev; 494c6fd2807SJeff Garzik struct qs_port_priv *pp; 495cca3974eSJeff Garzik void __iomem *mmio_base = ap->host->mmio_base; 496c6fd2807SJeff Garzik void __iomem *chan = mmio_base + (ap->port_no * 0x4000); 497c6fd2807SJeff Garzik u64 addr; 498c6fd2807SJeff Garzik int rc; 499c6fd2807SJeff Garzik 500c6fd2807SJeff Garzik rc = ata_port_start(ap); 501c6fd2807SJeff Garzik if (rc) 502c6fd2807SJeff Garzik return rc; 503c6fd2807SJeff Garzik qs_enter_reg_mode(ap); 504c6fd2807SJeff Garzik pp = kzalloc(sizeof(*pp), GFP_KERNEL); 505c6fd2807SJeff Garzik if (!pp) { 506c6fd2807SJeff Garzik rc = -ENOMEM; 507c6fd2807SJeff Garzik goto err_out; 508c6fd2807SJeff Garzik } 509c6fd2807SJeff Garzik pp->pkt = dma_alloc_coherent(dev, QS_PKT_BYTES, &pp->pkt_dma, 510c6fd2807SJeff Garzik GFP_KERNEL); 511c6fd2807SJeff Garzik if (!pp->pkt) { 512c6fd2807SJeff Garzik rc = -ENOMEM; 513c6fd2807SJeff Garzik goto err_out_kfree; 514c6fd2807SJeff Garzik } 515c6fd2807SJeff Garzik memset(pp->pkt, 0, QS_PKT_BYTES); 516c6fd2807SJeff Garzik ap->private_data = pp; 517c6fd2807SJeff Garzik 518c6fd2807SJeff Garzik addr = (u64)pp->pkt_dma; 519c6fd2807SJeff Garzik writel((u32) addr, chan + QS_CCF_CPBA); 520c6fd2807SJeff Garzik writel((u32)(addr >> 32), chan + QS_CCF_CPBA + 4); 521c6fd2807SJeff Garzik return 0; 522c6fd2807SJeff Garzik 523c6fd2807SJeff Garzik err_out_kfree: 524c6fd2807SJeff Garzik kfree(pp); 525c6fd2807SJeff Garzik err_out: 526c6fd2807SJeff Garzik ata_port_stop(ap); 527c6fd2807SJeff Garzik return rc; 528c6fd2807SJeff Garzik } 529c6fd2807SJeff Garzik 530c6fd2807SJeff Garzik static void qs_port_stop(struct ata_port *ap) 531c6fd2807SJeff Garzik { 532cca3974eSJeff Garzik struct device *dev = ap->host->dev; 533c6fd2807SJeff Garzik struct qs_port_priv *pp = ap->private_data; 534c6fd2807SJeff Garzik 535c6fd2807SJeff Garzik if (pp != NULL) { 536c6fd2807SJeff Garzik ap->private_data = NULL; 537c6fd2807SJeff Garzik if (pp->pkt != NULL) 538c6fd2807SJeff Garzik dma_free_coherent(dev, QS_PKT_BYTES, pp->pkt, 539c6fd2807SJeff Garzik pp->pkt_dma); 540c6fd2807SJeff Garzik kfree(pp); 541c6fd2807SJeff Garzik } 542c6fd2807SJeff Garzik ata_port_stop(ap); 543c6fd2807SJeff Garzik } 544c6fd2807SJeff Garzik 545cca3974eSJeff Garzik static void qs_host_stop(struct ata_host *host) 546c6fd2807SJeff Garzik { 547cca3974eSJeff Garzik void __iomem *mmio_base = host->mmio_base; 548cca3974eSJeff Garzik struct pci_dev *pdev = to_pci_dev(host->dev); 549c6fd2807SJeff Garzik 550c6fd2807SJeff Garzik writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */ 551c6fd2807SJeff Garzik writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */ 552c6fd2807SJeff Garzik 553c6fd2807SJeff Garzik pci_iounmap(pdev, mmio_base); 554c6fd2807SJeff Garzik } 555c6fd2807SJeff Garzik 556c6fd2807SJeff Garzik static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe) 557c6fd2807SJeff Garzik { 558c6fd2807SJeff Garzik void __iomem *mmio_base = pe->mmio_base; 559c6fd2807SJeff Garzik unsigned int port_no; 560c6fd2807SJeff Garzik 561c6fd2807SJeff Garzik writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */ 562c6fd2807SJeff Garzik writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */ 563c6fd2807SJeff Garzik 564c6fd2807SJeff Garzik /* reset each channel in turn */ 565c6fd2807SJeff Garzik for (port_no = 0; port_no < pe->n_ports; ++port_no) { 566c6fd2807SJeff Garzik u8 __iomem *chan = mmio_base + (port_no * 0x4000); 567c6fd2807SJeff Garzik writeb(QS_CTR1_RDEV|QS_CTR1_RCHN, chan + QS_CCT_CTR1); 568c6fd2807SJeff Garzik writeb(QS_CTR0_REG, chan + QS_CCT_CTR0); 569c6fd2807SJeff Garzik readb(chan + QS_CCT_CTR0); /* flush */ 570c6fd2807SJeff Garzik } 571c6fd2807SJeff Garzik writeb(QS_SERD3_PHY_ENA, mmio_base + QS_HVS_SERD3); /* enable phy */ 572c6fd2807SJeff Garzik 573c6fd2807SJeff Garzik for (port_no = 0; port_no < pe->n_ports; ++port_no) { 574c6fd2807SJeff Garzik u8 __iomem *chan = mmio_base + (port_no * 0x4000); 575c6fd2807SJeff Garzik /* set FIFO depths to same settings as Windows driver */ 576c6fd2807SJeff Garzik writew(32, chan + QS_CFC_HUFT); 577c6fd2807SJeff Garzik writew(32, chan + QS_CFC_HDFT); 578c6fd2807SJeff Garzik writew(10, chan + QS_CFC_DUFT); 579c6fd2807SJeff Garzik writew( 8, chan + QS_CFC_DDFT); 580c6fd2807SJeff Garzik /* set CPB size in bytes, as a power of two */ 581c6fd2807SJeff Garzik writeb(QS_CPB_ORDER, chan + QS_CCF_CSEP); 582c6fd2807SJeff Garzik } 583c6fd2807SJeff Garzik writeb(1, mmio_base + QS_HCT_CTRL); /* enable host interrupts */ 584c6fd2807SJeff Garzik } 585c6fd2807SJeff Garzik 586c6fd2807SJeff Garzik /* 587c6fd2807SJeff Garzik * The QStor understands 64-bit buses, and uses 64-bit fields 588c6fd2807SJeff Garzik * for DMA pointers regardless of bus width. We just have to 589c6fd2807SJeff Garzik * make sure our DMA masks are set appropriately for whatever 590c6fd2807SJeff Garzik * bridge lies between us and the QStor, and then the DMA mapping 591c6fd2807SJeff Garzik * code will ensure we only ever "see" appropriate buffer addresses. 592c6fd2807SJeff Garzik * If we're 32-bit limited somewhere, then our 64-bit fields will 593c6fd2807SJeff Garzik * just end up with zeros in the upper 32-bits, without any special 594c6fd2807SJeff Garzik * logic required outside of this routine (below). 595c6fd2807SJeff Garzik */ 596c6fd2807SJeff Garzik static int qs_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base) 597c6fd2807SJeff Garzik { 598c6fd2807SJeff Garzik u32 bus_info = readl(mmio_base + QS_HID_HPHY); 599c6fd2807SJeff Garzik int rc, have_64bit_bus = (bus_info & QS_HPHY_64BIT); 600c6fd2807SJeff Garzik 601c6fd2807SJeff Garzik if (have_64bit_bus && 602c6fd2807SJeff Garzik !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { 603c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); 604c6fd2807SJeff Garzik if (rc) { 605c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 606c6fd2807SJeff Garzik if (rc) { 607c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 608c6fd2807SJeff Garzik "64-bit DMA enable failed\n"); 609c6fd2807SJeff Garzik return rc; 610c6fd2807SJeff Garzik } 611c6fd2807SJeff Garzik } 612c6fd2807SJeff Garzik } else { 613c6fd2807SJeff Garzik rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); 614c6fd2807SJeff Garzik if (rc) { 615c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 616c6fd2807SJeff Garzik "32-bit DMA enable failed\n"); 617c6fd2807SJeff Garzik return rc; 618c6fd2807SJeff Garzik } 619c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 620c6fd2807SJeff Garzik if (rc) { 621c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 622c6fd2807SJeff Garzik "32-bit consistent DMA enable failed\n"); 623c6fd2807SJeff Garzik return rc; 624c6fd2807SJeff Garzik } 625c6fd2807SJeff Garzik } 626c6fd2807SJeff Garzik return 0; 627c6fd2807SJeff Garzik } 628c6fd2807SJeff Garzik 629c6fd2807SJeff Garzik static int qs_ata_init_one(struct pci_dev *pdev, 630c6fd2807SJeff Garzik const struct pci_device_id *ent) 631c6fd2807SJeff Garzik { 632c6fd2807SJeff Garzik static int printed_version; 633c6fd2807SJeff Garzik struct ata_probe_ent *probe_ent = NULL; 634c6fd2807SJeff Garzik void __iomem *mmio_base; 635c6fd2807SJeff Garzik unsigned int board_idx = (unsigned int) ent->driver_data; 636c6fd2807SJeff Garzik int rc, port_no; 637c6fd2807SJeff Garzik 638c6fd2807SJeff Garzik if (!printed_version++) 639c6fd2807SJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); 640c6fd2807SJeff Garzik 641c6fd2807SJeff Garzik rc = pci_enable_device(pdev); 642c6fd2807SJeff Garzik if (rc) 643c6fd2807SJeff Garzik return rc; 644c6fd2807SJeff Garzik 645c6fd2807SJeff Garzik rc = pci_request_regions(pdev, DRV_NAME); 646c6fd2807SJeff Garzik if (rc) 647c6fd2807SJeff Garzik goto err_out; 648c6fd2807SJeff Garzik 649c6fd2807SJeff Garzik if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) { 650c6fd2807SJeff Garzik rc = -ENODEV; 651c6fd2807SJeff Garzik goto err_out_regions; 652c6fd2807SJeff Garzik } 653c6fd2807SJeff Garzik 654c6fd2807SJeff Garzik mmio_base = pci_iomap(pdev, 4, 0); 655c6fd2807SJeff Garzik if (mmio_base == NULL) { 656c6fd2807SJeff Garzik rc = -ENOMEM; 657c6fd2807SJeff Garzik goto err_out_regions; 658c6fd2807SJeff Garzik } 659c6fd2807SJeff Garzik 660c6fd2807SJeff Garzik rc = qs_set_dma_masks(pdev, mmio_base); 661c6fd2807SJeff Garzik if (rc) 662c6fd2807SJeff Garzik goto err_out_iounmap; 663c6fd2807SJeff Garzik 664c6fd2807SJeff Garzik probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); 665c6fd2807SJeff Garzik if (probe_ent == NULL) { 666c6fd2807SJeff Garzik rc = -ENOMEM; 667c6fd2807SJeff Garzik goto err_out_iounmap; 668c6fd2807SJeff Garzik } 669c6fd2807SJeff Garzik 670c6fd2807SJeff Garzik memset(probe_ent, 0, sizeof(*probe_ent)); 671c6fd2807SJeff Garzik probe_ent->dev = pci_dev_to_dev(pdev); 672c6fd2807SJeff Garzik INIT_LIST_HEAD(&probe_ent->node); 673c6fd2807SJeff Garzik 674c6fd2807SJeff Garzik probe_ent->sht = qs_port_info[board_idx].sht; 675cca3974eSJeff Garzik probe_ent->port_flags = qs_port_info[board_idx].flags; 676c6fd2807SJeff Garzik probe_ent->pio_mask = qs_port_info[board_idx].pio_mask; 677c6fd2807SJeff Garzik probe_ent->mwdma_mask = qs_port_info[board_idx].mwdma_mask; 678c6fd2807SJeff Garzik probe_ent->udma_mask = qs_port_info[board_idx].udma_mask; 679c6fd2807SJeff Garzik probe_ent->port_ops = qs_port_info[board_idx].port_ops; 680c6fd2807SJeff Garzik 681c6fd2807SJeff Garzik probe_ent->irq = pdev->irq; 682c6fd2807SJeff Garzik probe_ent->irq_flags = IRQF_SHARED; 683c6fd2807SJeff Garzik probe_ent->mmio_base = mmio_base; 684c6fd2807SJeff Garzik probe_ent->n_ports = QS_PORTS; 685c6fd2807SJeff Garzik 686c6fd2807SJeff Garzik for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) { 687c6fd2807SJeff Garzik unsigned long chan = (unsigned long)mmio_base + 688c6fd2807SJeff Garzik (port_no * 0x4000); 689c6fd2807SJeff Garzik qs_ata_setup_port(&probe_ent->port[port_no], chan); 690c6fd2807SJeff Garzik } 691c6fd2807SJeff Garzik 692c6fd2807SJeff Garzik pci_set_master(pdev); 693c6fd2807SJeff Garzik 694c6fd2807SJeff Garzik /* initialize adapter */ 695c6fd2807SJeff Garzik qs_host_init(board_idx, probe_ent); 696c6fd2807SJeff Garzik 697c6fd2807SJeff Garzik rc = ata_device_add(probe_ent); 698c6fd2807SJeff Garzik kfree(probe_ent); 699c6fd2807SJeff Garzik if (rc != QS_PORTS) 700c6fd2807SJeff Garzik goto err_out_iounmap; 701c6fd2807SJeff Garzik return 0; 702c6fd2807SJeff Garzik 703c6fd2807SJeff Garzik err_out_iounmap: 704c6fd2807SJeff Garzik pci_iounmap(pdev, mmio_base); 705c6fd2807SJeff Garzik err_out_regions: 706c6fd2807SJeff Garzik pci_release_regions(pdev); 707c6fd2807SJeff Garzik err_out: 708c6fd2807SJeff Garzik pci_disable_device(pdev); 709c6fd2807SJeff Garzik return rc; 710c6fd2807SJeff Garzik } 711c6fd2807SJeff Garzik 712c6fd2807SJeff Garzik static int __init qs_ata_init(void) 713c6fd2807SJeff Garzik { 714c6fd2807SJeff Garzik return pci_register_driver(&qs_ata_pci_driver); 715c6fd2807SJeff Garzik } 716c6fd2807SJeff Garzik 717c6fd2807SJeff Garzik static void __exit qs_ata_exit(void) 718c6fd2807SJeff Garzik { 719c6fd2807SJeff Garzik pci_unregister_driver(&qs_ata_pci_driver); 720c6fd2807SJeff Garzik } 721c6fd2807SJeff Garzik 722c6fd2807SJeff Garzik MODULE_AUTHOR("Mark Lord"); 723c6fd2807SJeff Garzik MODULE_DESCRIPTION("Pacific Digital Corporation QStor SATA low-level driver"); 724c6fd2807SJeff Garzik MODULE_LICENSE("GPL"); 725c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, qs_ata_pci_tbl); 726c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION); 727c6fd2807SJeff Garzik 728c6fd2807SJeff Garzik module_init(qs_ata_init); 729c6fd2807SJeff Garzik module_exit(qs_ata_exit); 730