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/device.h> 38c6fd2807SJeff Garzik #include <scsi/scsi_host.h> 39c6fd2807SJeff Garzik #include <linux/libata.h> 40c6fd2807SJeff Garzik 41c6fd2807SJeff Garzik #define DRV_NAME "sata_qstor" 422a3103ceSJeff Garzik #define DRV_VERSION "0.09" 43c6fd2807SJeff Garzik 44c6fd2807SJeff Garzik enum { 450d5ff566STejun Heo QS_MMIO_BAR = 4, 460d5ff566STejun Heo 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 114da3dbb17STejun Heo static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); 115da3dbb17STejun Heo static int 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 int qs_port_start(struct ata_port *ap); 118cca3974eSJeff Garzik static void qs_host_stop(struct ata_host *host); 119c6fd2807SJeff Garzik static void qs_phy_reset(struct ata_port *ap); 120c6fd2807SJeff Garzik static void qs_qc_prep(struct ata_queued_cmd *qc); 121c6fd2807SJeff Garzik static unsigned int qs_qc_issue(struct ata_queued_cmd *qc); 122c6fd2807SJeff Garzik static int qs_check_atapi_dma(struct ata_queued_cmd *qc); 123c6fd2807SJeff Garzik static void qs_bmdma_stop(struct ata_queued_cmd *qc); 124c6fd2807SJeff Garzik static u8 qs_bmdma_status(struct ata_port *ap); 125c6fd2807SJeff Garzik static void qs_irq_clear(struct ata_port *ap); 126c6fd2807SJeff Garzik static void qs_eng_timeout(struct ata_port *ap); 127c6fd2807SJeff Garzik 128c6fd2807SJeff Garzik static struct scsi_host_template qs_ata_sht = { 129c6fd2807SJeff Garzik .module = THIS_MODULE, 130c6fd2807SJeff Garzik .name = DRV_NAME, 131c6fd2807SJeff Garzik .ioctl = ata_scsi_ioctl, 132c6fd2807SJeff Garzik .queuecommand = ata_scsi_queuecmd, 133c6fd2807SJeff Garzik .can_queue = ATA_DEF_QUEUE, 134c6fd2807SJeff Garzik .this_id = ATA_SHT_THIS_ID, 135c6fd2807SJeff Garzik .sg_tablesize = QS_MAX_PRD, 136c6fd2807SJeff Garzik .cmd_per_lun = ATA_SHT_CMD_PER_LUN, 137c6fd2807SJeff Garzik .emulated = ATA_SHT_EMULATED, 138c6fd2807SJeff Garzik //FIXME .use_clustering = ATA_SHT_USE_CLUSTERING, 139c6fd2807SJeff Garzik .use_clustering = ENABLE_CLUSTERING, 140c6fd2807SJeff Garzik .proc_name = DRV_NAME, 141c6fd2807SJeff Garzik .dma_boundary = QS_DMA_BOUNDARY, 142c6fd2807SJeff Garzik .slave_configure = ata_scsi_slave_config, 143c6fd2807SJeff Garzik .slave_destroy = ata_scsi_slave_destroy, 144c6fd2807SJeff Garzik .bios_param = ata_std_bios_param, 145c6fd2807SJeff Garzik }; 146c6fd2807SJeff Garzik 147c6fd2807SJeff Garzik static const struct ata_port_operations qs_ata_ops = { 148c6fd2807SJeff Garzik .tf_load = ata_tf_load, 149c6fd2807SJeff Garzik .tf_read = ata_tf_read, 150c6fd2807SJeff Garzik .check_status = ata_check_status, 151c6fd2807SJeff Garzik .check_atapi_dma = qs_check_atapi_dma, 152c6fd2807SJeff Garzik .exec_command = ata_exec_command, 153c6fd2807SJeff Garzik .dev_select = ata_std_dev_select, 154c6fd2807SJeff Garzik .phy_reset = qs_phy_reset, 155c6fd2807SJeff Garzik .qc_prep = qs_qc_prep, 156c6fd2807SJeff Garzik .qc_issue = qs_qc_issue, 1570d5ff566STejun Heo .data_xfer = ata_data_xfer, 158c6fd2807SJeff Garzik .eng_timeout = qs_eng_timeout, 159c6fd2807SJeff Garzik .irq_clear = qs_irq_clear, 160246ce3b6SAkira Iguchi .irq_on = ata_irq_on, 161c6fd2807SJeff Garzik .scr_read = qs_scr_read, 162c6fd2807SJeff Garzik .scr_write = qs_scr_write, 163c6fd2807SJeff Garzik .port_start = qs_port_start, 164c6fd2807SJeff Garzik .host_stop = qs_host_stop, 165c6fd2807SJeff Garzik .bmdma_stop = qs_bmdma_stop, 166c6fd2807SJeff Garzik .bmdma_status = qs_bmdma_status, 167c6fd2807SJeff Garzik }; 168c6fd2807SJeff Garzik 169c6fd2807SJeff Garzik static const struct ata_port_info qs_port_info[] = { 170c6fd2807SJeff Garzik /* board_2068_idx */ 171c6fd2807SJeff Garzik { 172cca3974eSJeff Garzik .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 173c6fd2807SJeff Garzik ATA_FLAG_SATA_RESET | 174c6fd2807SJeff Garzik //FIXME ATA_FLAG_SRST | 175c6fd2807SJeff Garzik ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING, 176c6fd2807SJeff Garzik .pio_mask = 0x10, /* pio4 */ 177bf6263a8SJeff Garzik .udma_mask = ATA_UDMA6, 178c6fd2807SJeff Garzik .port_ops = &qs_ata_ops, 179c6fd2807SJeff Garzik }, 180c6fd2807SJeff Garzik }; 181c6fd2807SJeff Garzik 182c6fd2807SJeff Garzik static const struct pci_device_id qs_ata_pci_tbl[] = { 1832d2744fcSJeff Garzik { PCI_VDEVICE(PDC, 0x2068), board_2068_idx }, 184c6fd2807SJeff Garzik 185c6fd2807SJeff Garzik { } /* terminate list */ 186c6fd2807SJeff Garzik }; 187c6fd2807SJeff Garzik 188c6fd2807SJeff Garzik static struct pci_driver qs_ata_pci_driver = { 189c6fd2807SJeff Garzik .name = DRV_NAME, 190c6fd2807SJeff Garzik .id_table = qs_ata_pci_tbl, 191c6fd2807SJeff Garzik .probe = qs_ata_init_one, 192c6fd2807SJeff Garzik .remove = ata_pci_remove_one, 193c6fd2807SJeff Garzik }; 194c6fd2807SJeff Garzik 1950d5ff566STejun Heo static void __iomem *qs_mmio_base(struct ata_host *host) 1960d5ff566STejun Heo { 1970d5ff566STejun Heo return host->iomap[QS_MMIO_BAR]; 1980d5ff566STejun Heo } 1990d5ff566STejun Heo 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 { 2220d5ff566STejun Heo u8 __iomem *chan = qs_mmio_base(ap->host) + (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 { 2300d5ff566STejun Heo u8 __iomem *chan = qs_mmio_base(ap->host) + (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 256da3dbb17STejun Heo static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) 257c6fd2807SJeff Garzik { 258c6fd2807SJeff Garzik if (sc_reg > SCR_CONTROL) 259da3dbb17STejun Heo return -EINVAL; 260da3dbb17STejun Heo *val = readl(ap->ioaddr.scr_addr + (sc_reg * 8)); 261da3dbb17STejun Heo return 0; 262c6fd2807SJeff Garzik } 263c6fd2807SJeff Garzik 264da3dbb17STejun Heo static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) 265c6fd2807SJeff Garzik { 266c6fd2807SJeff Garzik if (sc_reg > SCR_CONTROL) 267da3dbb17STejun Heo return -EINVAL; 2680d5ff566STejun Heo writel(val, ap->ioaddr.scr_addr + (sc_reg * 8)); 269da3dbb17STejun Heo return 0; 270c6fd2807SJeff Garzik } 271c6fd2807SJeff Garzik 272c6fd2807SJeff Garzik static unsigned int qs_fill_sg(struct ata_queued_cmd *qc) 273c6fd2807SJeff Garzik { 274c6fd2807SJeff Garzik struct scatterlist *sg; 275c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 276c6fd2807SJeff Garzik struct qs_port_priv *pp = ap->private_data; 277c6fd2807SJeff Garzik unsigned int nelem; 278c6fd2807SJeff Garzik u8 *prd = pp->pkt + QS_CPB_BYTES; 279c6fd2807SJeff Garzik 280c6fd2807SJeff Garzik WARN_ON(qc->__sg == NULL); 281c6fd2807SJeff Garzik WARN_ON(qc->n_elem == 0 && qc->pad_len == 0); 282c6fd2807SJeff Garzik 283c6fd2807SJeff Garzik nelem = 0; 284c6fd2807SJeff Garzik ata_for_each_sg(sg, qc) { 285c6fd2807SJeff Garzik u64 addr; 286c6fd2807SJeff Garzik u32 len; 287c6fd2807SJeff Garzik 288c6fd2807SJeff Garzik addr = sg_dma_address(sg); 289c6fd2807SJeff Garzik *(__le64 *)prd = cpu_to_le64(addr); 290c6fd2807SJeff Garzik prd += sizeof(u64); 291c6fd2807SJeff Garzik 292c6fd2807SJeff Garzik len = sg_dma_len(sg); 293c6fd2807SJeff Garzik *(__le32 *)prd = cpu_to_le32(len); 294c6fd2807SJeff Garzik prd += sizeof(u64); 295c6fd2807SJeff Garzik 296c6fd2807SJeff Garzik VPRINTK("PRD[%u] = (0x%llX, 0x%X)\n", nelem, 297c6fd2807SJeff Garzik (unsigned long long)addr, len); 298c6fd2807SJeff Garzik nelem++; 299c6fd2807SJeff Garzik } 300c6fd2807SJeff Garzik 301c6fd2807SJeff Garzik return nelem; 302c6fd2807SJeff Garzik } 303c6fd2807SJeff Garzik 304c6fd2807SJeff Garzik static void qs_qc_prep(struct ata_queued_cmd *qc) 305c6fd2807SJeff Garzik { 306c6fd2807SJeff Garzik struct qs_port_priv *pp = qc->ap->private_data; 307c6fd2807SJeff Garzik u8 dflags = QS_DF_PORD, *buf = pp->pkt; 308c6fd2807SJeff Garzik u8 hflags = QS_HF_DAT | QS_HF_IEN | QS_HF_VLD; 309c6fd2807SJeff Garzik u64 addr; 310c6fd2807SJeff Garzik unsigned int nelem; 311c6fd2807SJeff Garzik 312c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 313c6fd2807SJeff Garzik 314c6fd2807SJeff Garzik qs_enter_reg_mode(qc->ap); 315c6fd2807SJeff Garzik if (qc->tf.protocol != ATA_PROT_DMA) { 316c6fd2807SJeff Garzik ata_qc_prep(qc); 317c6fd2807SJeff Garzik return; 318c6fd2807SJeff Garzik } 319c6fd2807SJeff Garzik 320c6fd2807SJeff Garzik nelem = qs_fill_sg(qc); 321c6fd2807SJeff Garzik 322c6fd2807SJeff Garzik if ((qc->tf.flags & ATA_TFLAG_WRITE)) 323c6fd2807SJeff Garzik hflags |= QS_HF_DIRO; 324c6fd2807SJeff Garzik if ((qc->tf.flags & ATA_TFLAG_LBA48)) 325c6fd2807SJeff Garzik dflags |= QS_DF_ELBA; 326c6fd2807SJeff Garzik 327c6fd2807SJeff Garzik /* host control block (HCB) */ 328c6fd2807SJeff Garzik buf[ 0] = QS_HCB_HDR; 329c6fd2807SJeff Garzik buf[ 1] = hflags; 330726f0785STejun Heo *(__le32 *)(&buf[ 4]) = cpu_to_le32(qc->nbytes); 331c6fd2807SJeff Garzik *(__le32 *)(&buf[ 8]) = cpu_to_le32(nelem); 332c6fd2807SJeff Garzik addr = ((u64)pp->pkt_dma) + QS_CPB_BYTES; 333c6fd2807SJeff Garzik *(__le64 *)(&buf[16]) = cpu_to_le64(addr); 334c6fd2807SJeff Garzik 335c6fd2807SJeff Garzik /* device control block (DCB) */ 336c6fd2807SJeff Garzik buf[24] = QS_DCB_HDR; 337c6fd2807SJeff Garzik buf[28] = dflags; 338c6fd2807SJeff Garzik 339c6fd2807SJeff Garzik /* frame information structure (FIS) */ 3409977126cSTejun Heo ata_tf_to_fis(&qc->tf, 0, 1, &buf[32]); 341c6fd2807SJeff Garzik } 342c6fd2807SJeff Garzik 343c6fd2807SJeff Garzik static inline void qs_packet_start(struct ata_queued_cmd *qc) 344c6fd2807SJeff Garzik { 345c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 3460d5ff566STejun Heo u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000); 347c6fd2807SJeff Garzik 348c6fd2807SJeff Garzik VPRINTK("ENTER, ap %p\n", ap); 349c6fd2807SJeff Garzik 350c6fd2807SJeff Garzik writeb(QS_CTR0_CLER, chan + QS_CCT_CTR0); 351c6fd2807SJeff Garzik wmb(); /* flush PRDs and pkt to memory */ 352c6fd2807SJeff Garzik writel(QS_CCF_RUN_PKT, chan + QS_CCT_CFF); 353c6fd2807SJeff Garzik readl(chan + QS_CCT_CFF); /* flush */ 354c6fd2807SJeff Garzik } 355c6fd2807SJeff Garzik 356c6fd2807SJeff Garzik static unsigned int qs_qc_issue(struct ata_queued_cmd *qc) 357c6fd2807SJeff Garzik { 358c6fd2807SJeff Garzik struct qs_port_priv *pp = qc->ap->private_data; 359c6fd2807SJeff Garzik 360c6fd2807SJeff Garzik switch (qc->tf.protocol) { 361c6fd2807SJeff Garzik case ATA_PROT_DMA: 362c6fd2807SJeff Garzik 363c6fd2807SJeff Garzik pp->state = qs_state_pkt; 364c6fd2807SJeff Garzik qs_packet_start(qc); 365c6fd2807SJeff Garzik return 0; 366c6fd2807SJeff Garzik 367c6fd2807SJeff Garzik case ATA_PROT_ATAPI_DMA: 368c6fd2807SJeff Garzik BUG(); 369c6fd2807SJeff Garzik break; 370c6fd2807SJeff Garzik 371c6fd2807SJeff Garzik default: 372c6fd2807SJeff Garzik break; 373c6fd2807SJeff Garzik } 374c6fd2807SJeff Garzik 375c6fd2807SJeff Garzik pp->state = qs_state_mmio; 376c6fd2807SJeff Garzik return ata_qc_issue_prot(qc); 377c6fd2807SJeff Garzik } 378c6fd2807SJeff Garzik 379cca3974eSJeff Garzik static inline unsigned int qs_intr_pkt(struct ata_host *host) 380c6fd2807SJeff Garzik { 381c6fd2807SJeff Garzik unsigned int handled = 0; 382c6fd2807SJeff Garzik u8 sFFE; 3830d5ff566STejun Heo u8 __iomem *mmio_base = qs_mmio_base(host); 384c6fd2807SJeff Garzik 385c6fd2807SJeff Garzik do { 386c6fd2807SJeff Garzik u32 sff0 = readl(mmio_base + QS_HST_SFF); 387c6fd2807SJeff Garzik u32 sff1 = readl(mmio_base + QS_HST_SFF + 4); 388c6fd2807SJeff Garzik u8 sEVLD = (sff1 >> 30) & 0x01; /* valid flag */ 389c6fd2807SJeff Garzik sFFE = sff1 >> 31; /* empty flag */ 390c6fd2807SJeff Garzik 391c6fd2807SJeff Garzik if (sEVLD) { 392c6fd2807SJeff Garzik u8 sDST = sff0 >> 16; /* dev status */ 393c6fd2807SJeff Garzik u8 sHST = sff1 & 0x3f; /* host status */ 394c6fd2807SJeff Garzik unsigned int port_no = (sff1 >> 8) & 0x03; 395cca3974eSJeff Garzik struct ata_port *ap = host->ports[port_no]; 396c6fd2807SJeff Garzik 397c6fd2807SJeff Garzik DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n", 398c6fd2807SJeff Garzik sff1, sff0, port_no, sHST, sDST); 399c6fd2807SJeff Garzik handled = 1; 400c6fd2807SJeff Garzik if (ap && !(ap->flags & ATA_FLAG_DISABLED)) { 401c6fd2807SJeff Garzik struct ata_queued_cmd *qc; 402c6fd2807SJeff Garzik struct qs_port_priv *pp = ap->private_data; 403c6fd2807SJeff Garzik if (!pp || pp->state != qs_state_pkt) 404c6fd2807SJeff Garzik continue; 4059af5c9c9STejun Heo qc = ata_qc_from_tag(ap, ap->link.active_tag); 406c6fd2807SJeff Garzik if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { 407c6fd2807SJeff Garzik switch (sHST) { 408c6fd2807SJeff Garzik case 0: /* successful CPB */ 409c6fd2807SJeff Garzik case 3: /* device error */ 410c6fd2807SJeff Garzik pp->state = qs_state_idle; 411c6fd2807SJeff Garzik qs_enter_reg_mode(qc->ap); 412c6fd2807SJeff Garzik qc->err_mask |= ac_err_mask(sDST); 413c6fd2807SJeff Garzik ata_qc_complete(qc); 414c6fd2807SJeff Garzik break; 415c6fd2807SJeff Garzik default: 416c6fd2807SJeff Garzik break; 417c6fd2807SJeff Garzik } 418c6fd2807SJeff Garzik } 419c6fd2807SJeff Garzik } 420c6fd2807SJeff Garzik } 421c6fd2807SJeff Garzik } while (!sFFE); 422c6fd2807SJeff Garzik return handled; 423c6fd2807SJeff Garzik } 424c6fd2807SJeff Garzik 425cca3974eSJeff Garzik static inline unsigned int qs_intr_mmio(struct ata_host *host) 426c6fd2807SJeff Garzik { 427c6fd2807SJeff Garzik unsigned int handled = 0, port_no; 428c6fd2807SJeff Garzik 429cca3974eSJeff Garzik for (port_no = 0; port_no < host->n_ports; ++port_no) { 430c6fd2807SJeff Garzik struct ata_port *ap; 431cca3974eSJeff Garzik ap = host->ports[port_no]; 432c6fd2807SJeff Garzik if (ap && 433c6fd2807SJeff Garzik !(ap->flags & ATA_FLAG_DISABLED)) { 434c6fd2807SJeff Garzik struct ata_queued_cmd *qc; 435c6fd2807SJeff Garzik struct qs_port_priv *pp = ap->private_data; 436c6fd2807SJeff Garzik if (!pp || pp->state != qs_state_mmio) 437c6fd2807SJeff Garzik continue; 4389af5c9c9STejun Heo qc = ata_qc_from_tag(ap, ap->link.active_tag); 439c6fd2807SJeff Garzik if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { 440c6fd2807SJeff Garzik 441c6fd2807SJeff Garzik /* check main status, clearing INTRQ */ 442c6fd2807SJeff Garzik u8 status = ata_check_status(ap); 443c6fd2807SJeff Garzik if ((status & ATA_BUSY)) 444c6fd2807SJeff Garzik continue; 445c6fd2807SJeff Garzik DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", 44644877b4eSTejun Heo ap->print_id, qc->tf.protocol, status); 447c6fd2807SJeff Garzik 448c6fd2807SJeff Garzik /* complete taskfile transaction */ 449c6fd2807SJeff Garzik pp->state = qs_state_idle; 450c6fd2807SJeff Garzik qc->err_mask |= ac_err_mask(status); 451c6fd2807SJeff Garzik ata_qc_complete(qc); 452c6fd2807SJeff Garzik handled = 1; 453c6fd2807SJeff Garzik } 454c6fd2807SJeff Garzik } 455c6fd2807SJeff Garzik } 456c6fd2807SJeff Garzik return handled; 457c6fd2807SJeff Garzik } 458c6fd2807SJeff Garzik 4597d12e780SDavid Howells static irqreturn_t qs_intr(int irq, void *dev_instance) 460c6fd2807SJeff Garzik { 461cca3974eSJeff Garzik struct ata_host *host = dev_instance; 462c6fd2807SJeff Garzik unsigned int handled = 0; 463c6fd2807SJeff Garzik 464c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 465c6fd2807SJeff Garzik 466cca3974eSJeff Garzik spin_lock(&host->lock); 467cca3974eSJeff Garzik handled = qs_intr_pkt(host) | qs_intr_mmio(host); 468cca3974eSJeff Garzik spin_unlock(&host->lock); 469c6fd2807SJeff Garzik 470c6fd2807SJeff Garzik VPRINTK("EXIT\n"); 471c6fd2807SJeff Garzik 472c6fd2807SJeff Garzik return IRQ_RETVAL(handled); 473c6fd2807SJeff Garzik } 474c6fd2807SJeff Garzik 4750d5ff566STejun Heo static void qs_ata_setup_port(struct ata_ioports *port, void __iomem *base) 476c6fd2807SJeff Garzik { 477c6fd2807SJeff Garzik port->cmd_addr = 478c6fd2807SJeff Garzik port->data_addr = base + 0x400; 479c6fd2807SJeff Garzik port->error_addr = 480c6fd2807SJeff Garzik port->feature_addr = base + 0x408; /* hob_feature = 0x409 */ 481c6fd2807SJeff Garzik port->nsect_addr = base + 0x410; /* hob_nsect = 0x411 */ 482c6fd2807SJeff Garzik port->lbal_addr = base + 0x418; /* hob_lbal = 0x419 */ 483c6fd2807SJeff Garzik port->lbam_addr = base + 0x420; /* hob_lbam = 0x421 */ 484c6fd2807SJeff Garzik port->lbah_addr = base + 0x428; /* hob_lbah = 0x429 */ 485c6fd2807SJeff Garzik port->device_addr = base + 0x430; 486c6fd2807SJeff Garzik port->status_addr = 487c6fd2807SJeff Garzik port->command_addr = base + 0x438; 488c6fd2807SJeff Garzik port->altstatus_addr = 489c6fd2807SJeff Garzik port->ctl_addr = base + 0x440; 490c6fd2807SJeff Garzik port->scr_addr = base + 0xc00; 491c6fd2807SJeff Garzik } 492c6fd2807SJeff Garzik 493c6fd2807SJeff Garzik static int qs_port_start(struct ata_port *ap) 494c6fd2807SJeff Garzik { 495cca3974eSJeff Garzik struct device *dev = ap->host->dev; 496c6fd2807SJeff Garzik struct qs_port_priv *pp; 4970d5ff566STejun Heo void __iomem *mmio_base = qs_mmio_base(ap->host); 498c6fd2807SJeff Garzik void __iomem *chan = mmio_base + (ap->port_no * 0x4000); 499c6fd2807SJeff Garzik u64 addr; 500c6fd2807SJeff Garzik int rc; 501c6fd2807SJeff Garzik 502c6fd2807SJeff Garzik rc = ata_port_start(ap); 503c6fd2807SJeff Garzik if (rc) 504c6fd2807SJeff Garzik return rc; 505c6fd2807SJeff Garzik qs_enter_reg_mode(ap); 50624dc5f33STejun Heo pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); 50724dc5f33STejun Heo if (!pp) 50824dc5f33STejun Heo return -ENOMEM; 50924dc5f33STejun Heo pp->pkt = dmam_alloc_coherent(dev, QS_PKT_BYTES, &pp->pkt_dma, 510c6fd2807SJeff Garzik GFP_KERNEL); 51124dc5f33STejun Heo if (!pp->pkt) 51224dc5f33STejun Heo return -ENOMEM; 513c6fd2807SJeff Garzik memset(pp->pkt, 0, QS_PKT_BYTES); 514c6fd2807SJeff Garzik ap->private_data = pp; 515c6fd2807SJeff Garzik 516c6fd2807SJeff Garzik addr = (u64)pp->pkt_dma; 517c6fd2807SJeff Garzik writel((u32) addr, chan + QS_CCF_CPBA); 518c6fd2807SJeff Garzik writel((u32)(addr >> 32), chan + QS_CCF_CPBA + 4); 519c6fd2807SJeff Garzik return 0; 520c6fd2807SJeff Garzik } 521c6fd2807SJeff Garzik 522cca3974eSJeff Garzik static void qs_host_stop(struct ata_host *host) 523c6fd2807SJeff Garzik { 5240d5ff566STejun Heo void __iomem *mmio_base = qs_mmio_base(host); 525c6fd2807SJeff Garzik 526c6fd2807SJeff Garzik writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */ 527c6fd2807SJeff Garzik writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */ 528c6fd2807SJeff Garzik } 529c6fd2807SJeff Garzik 5304447d351STejun Heo static void qs_host_init(struct ata_host *host, unsigned int chip_id) 531c6fd2807SJeff Garzik { 5324447d351STejun Heo void __iomem *mmio_base = host->iomap[QS_MMIO_BAR]; 533c6fd2807SJeff Garzik unsigned int port_no; 534c6fd2807SJeff Garzik 535c6fd2807SJeff Garzik writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */ 536c6fd2807SJeff Garzik writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */ 537c6fd2807SJeff Garzik 538c6fd2807SJeff Garzik /* reset each channel in turn */ 5394447d351STejun Heo for (port_no = 0; port_no < host->n_ports; ++port_no) { 540c6fd2807SJeff Garzik u8 __iomem *chan = mmio_base + (port_no * 0x4000); 541c6fd2807SJeff Garzik writeb(QS_CTR1_RDEV|QS_CTR1_RCHN, chan + QS_CCT_CTR1); 542c6fd2807SJeff Garzik writeb(QS_CTR0_REG, chan + QS_CCT_CTR0); 543c6fd2807SJeff Garzik readb(chan + QS_CCT_CTR0); /* flush */ 544c6fd2807SJeff Garzik } 545c6fd2807SJeff Garzik writeb(QS_SERD3_PHY_ENA, mmio_base + QS_HVS_SERD3); /* enable phy */ 546c6fd2807SJeff Garzik 5474447d351STejun Heo for (port_no = 0; port_no < host->n_ports; ++port_no) { 548c6fd2807SJeff Garzik u8 __iomem *chan = mmio_base + (port_no * 0x4000); 549c6fd2807SJeff Garzik /* set FIFO depths to same settings as Windows driver */ 550c6fd2807SJeff Garzik writew(32, chan + QS_CFC_HUFT); 551c6fd2807SJeff Garzik writew(32, chan + QS_CFC_HDFT); 552c6fd2807SJeff Garzik writew(10, chan + QS_CFC_DUFT); 553c6fd2807SJeff Garzik writew( 8, chan + QS_CFC_DDFT); 554c6fd2807SJeff Garzik /* set CPB size in bytes, as a power of two */ 555c6fd2807SJeff Garzik writeb(QS_CPB_ORDER, chan + QS_CCF_CSEP); 556c6fd2807SJeff Garzik } 557c6fd2807SJeff Garzik writeb(1, mmio_base + QS_HCT_CTRL); /* enable host interrupts */ 558c6fd2807SJeff Garzik } 559c6fd2807SJeff Garzik 560c6fd2807SJeff Garzik /* 561c6fd2807SJeff Garzik * The QStor understands 64-bit buses, and uses 64-bit fields 562c6fd2807SJeff Garzik * for DMA pointers regardless of bus width. We just have to 563c6fd2807SJeff Garzik * make sure our DMA masks are set appropriately for whatever 564c6fd2807SJeff Garzik * bridge lies between us and the QStor, and then the DMA mapping 565c6fd2807SJeff Garzik * code will ensure we only ever "see" appropriate buffer addresses. 566c6fd2807SJeff Garzik * If we're 32-bit limited somewhere, then our 64-bit fields will 567c6fd2807SJeff Garzik * just end up with zeros in the upper 32-bits, without any special 568c6fd2807SJeff Garzik * logic required outside of this routine (below). 569c6fd2807SJeff Garzik */ 570c6fd2807SJeff Garzik static int qs_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base) 571c6fd2807SJeff Garzik { 572c6fd2807SJeff Garzik u32 bus_info = readl(mmio_base + QS_HID_HPHY); 573c6fd2807SJeff Garzik int rc, have_64bit_bus = (bus_info & QS_HPHY_64BIT); 574c6fd2807SJeff Garzik 575c6fd2807SJeff Garzik if (have_64bit_bus && 576c6fd2807SJeff Garzik !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { 577c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); 578c6fd2807SJeff Garzik if (rc) { 579c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 580c6fd2807SJeff Garzik if (rc) { 581c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 582c6fd2807SJeff Garzik "64-bit DMA enable failed\n"); 583c6fd2807SJeff Garzik return rc; 584c6fd2807SJeff Garzik } 585c6fd2807SJeff Garzik } 586c6fd2807SJeff Garzik } else { 587c6fd2807SJeff Garzik rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); 588c6fd2807SJeff Garzik if (rc) { 589c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 590c6fd2807SJeff Garzik "32-bit DMA enable failed\n"); 591c6fd2807SJeff Garzik return rc; 592c6fd2807SJeff Garzik } 593c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 594c6fd2807SJeff Garzik if (rc) { 595c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 596c6fd2807SJeff Garzik "32-bit consistent DMA enable failed\n"); 597c6fd2807SJeff Garzik return rc; 598c6fd2807SJeff Garzik } 599c6fd2807SJeff Garzik } 600c6fd2807SJeff Garzik return 0; 601c6fd2807SJeff Garzik } 602c6fd2807SJeff Garzik 603c6fd2807SJeff Garzik static int qs_ata_init_one(struct pci_dev *pdev, 604c6fd2807SJeff Garzik const struct pci_device_id *ent) 605c6fd2807SJeff Garzik { 606c6fd2807SJeff Garzik static int printed_version; 607c6fd2807SJeff Garzik unsigned int board_idx = (unsigned int) ent->driver_data; 6084447d351STejun Heo const struct ata_port_info *ppi[] = { &qs_port_info[board_idx], NULL }; 6094447d351STejun Heo struct ata_host *host; 610c6fd2807SJeff Garzik int rc, port_no; 611c6fd2807SJeff Garzik 612c6fd2807SJeff Garzik if (!printed_version++) 613c6fd2807SJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); 614c6fd2807SJeff Garzik 6154447d351STejun Heo /* alloc host */ 6164447d351STejun Heo host = ata_host_alloc_pinfo(&pdev->dev, ppi, QS_PORTS); 6174447d351STejun Heo if (!host) 6184447d351STejun Heo return -ENOMEM; 6194447d351STejun Heo 6204447d351STejun Heo /* acquire resources and fill host */ 62124dc5f33STejun Heo rc = pcim_enable_device(pdev); 622c6fd2807SJeff Garzik if (rc) 623c6fd2807SJeff Garzik return rc; 624c6fd2807SJeff Garzik 6250d5ff566STejun Heo if ((pci_resource_flags(pdev, QS_MMIO_BAR) & IORESOURCE_MEM) == 0) 62624dc5f33STejun Heo return -ENODEV; 627c6fd2807SJeff Garzik 6280d5ff566STejun Heo rc = pcim_iomap_regions(pdev, 1 << QS_MMIO_BAR, DRV_NAME); 6290d5ff566STejun Heo if (rc) 6300d5ff566STejun Heo return rc; 6314447d351STejun Heo host->iomap = pcim_iomap_table(pdev); 632c6fd2807SJeff Garzik 6334447d351STejun Heo rc = qs_set_dma_masks(pdev, host->iomap[QS_MMIO_BAR]); 634c6fd2807SJeff Garzik if (rc) 63524dc5f33STejun Heo return rc; 636c6fd2807SJeff Garzik 6374447d351STejun Heo for (port_no = 0; port_no < host->n_ports; ++port_no) { 638cbcdd875STejun Heo struct ata_port *ap = host->ports[port_no]; 639cbcdd875STejun Heo unsigned int offset = port_no * 0x4000; 640cbcdd875STejun Heo void __iomem *chan = host->iomap[QS_MMIO_BAR] + offset; 641cbcdd875STejun Heo 642cbcdd875STejun Heo qs_ata_setup_port(&ap->ioaddr, chan); 643cbcdd875STejun Heo 644cbcdd875STejun Heo ata_port_pbar_desc(ap, QS_MMIO_BAR, -1, "mmio"); 645cbcdd875STejun Heo ata_port_pbar_desc(ap, QS_MMIO_BAR, offset, "port"); 646c6fd2807SJeff Garzik } 647c6fd2807SJeff Garzik 648c6fd2807SJeff Garzik /* initialize adapter */ 6494447d351STejun Heo qs_host_init(host, board_idx); 650c6fd2807SJeff Garzik 6514447d351STejun Heo pci_set_master(pdev); 6524447d351STejun Heo return ata_host_activate(host, pdev->irq, qs_intr, IRQF_SHARED, 6534447d351STejun Heo &qs_ata_sht); 654c6fd2807SJeff Garzik } 655c6fd2807SJeff Garzik 656c6fd2807SJeff Garzik static int __init qs_ata_init(void) 657c6fd2807SJeff Garzik { 658c6fd2807SJeff Garzik return pci_register_driver(&qs_ata_pci_driver); 659c6fd2807SJeff Garzik } 660c6fd2807SJeff Garzik 661c6fd2807SJeff Garzik static void __exit qs_ata_exit(void) 662c6fd2807SJeff Garzik { 663c6fd2807SJeff Garzik pci_unregister_driver(&qs_ata_pci_driver); 664c6fd2807SJeff Garzik } 665c6fd2807SJeff Garzik 666c6fd2807SJeff Garzik MODULE_AUTHOR("Mark Lord"); 667c6fd2807SJeff Garzik MODULE_DESCRIPTION("Pacific Digital Corporation QStor SATA low-level driver"); 668c6fd2807SJeff Garzik MODULE_LICENSE("GPL"); 669c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, qs_ata_pci_tbl); 670c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION); 671c6fd2807SJeff Garzik 672c6fd2807SJeff Garzik module_init(qs_ata_init); 673c6fd2807SJeff Garzik module_exit(qs_ata_exit); 674