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 .port_disable = ata_port_disable, 149c6fd2807SJeff Garzik .tf_load = ata_tf_load, 150c6fd2807SJeff Garzik .tf_read = ata_tf_read, 151c6fd2807SJeff Garzik .check_status = ata_check_status, 152c6fd2807SJeff Garzik .check_atapi_dma = qs_check_atapi_dma, 153c6fd2807SJeff Garzik .exec_command = ata_exec_command, 154c6fd2807SJeff Garzik .dev_select = ata_std_dev_select, 155c6fd2807SJeff Garzik .phy_reset = qs_phy_reset, 156c6fd2807SJeff Garzik .qc_prep = qs_qc_prep, 157c6fd2807SJeff Garzik .qc_issue = qs_qc_issue, 1580d5ff566STejun Heo .data_xfer = ata_data_xfer, 159c6fd2807SJeff Garzik .eng_timeout = qs_eng_timeout, 160c6fd2807SJeff Garzik .irq_clear = qs_irq_clear, 161246ce3b6SAkira Iguchi .irq_on = ata_irq_on, 162246ce3b6SAkira Iguchi .irq_ack = ata_irq_ack, 163c6fd2807SJeff Garzik .scr_read = qs_scr_read, 164c6fd2807SJeff Garzik .scr_write = qs_scr_write, 165c6fd2807SJeff Garzik .port_start = qs_port_start, 166c6fd2807SJeff Garzik .host_stop = qs_host_stop, 167c6fd2807SJeff Garzik .bmdma_stop = qs_bmdma_stop, 168c6fd2807SJeff Garzik .bmdma_status = qs_bmdma_status, 169c6fd2807SJeff Garzik }; 170c6fd2807SJeff Garzik 171c6fd2807SJeff Garzik static const struct ata_port_info qs_port_info[] = { 172c6fd2807SJeff Garzik /* board_2068_idx */ 173c6fd2807SJeff Garzik { 174cca3974eSJeff Garzik .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | 175c6fd2807SJeff Garzik ATA_FLAG_SATA_RESET | 176c6fd2807SJeff Garzik //FIXME ATA_FLAG_SRST | 177c6fd2807SJeff Garzik ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING, 178c6fd2807SJeff Garzik .pio_mask = 0x10, /* pio4 */ 179bf6263a8SJeff Garzik .udma_mask = ATA_UDMA6, 180c6fd2807SJeff Garzik .port_ops = &qs_ata_ops, 181c6fd2807SJeff Garzik }, 182c6fd2807SJeff Garzik }; 183c6fd2807SJeff Garzik 184c6fd2807SJeff Garzik static const struct pci_device_id qs_ata_pci_tbl[] = { 1852d2744fcSJeff Garzik { PCI_VDEVICE(PDC, 0x2068), board_2068_idx }, 186c6fd2807SJeff Garzik 187c6fd2807SJeff Garzik { } /* terminate list */ 188c6fd2807SJeff Garzik }; 189c6fd2807SJeff Garzik 190c6fd2807SJeff Garzik static struct pci_driver qs_ata_pci_driver = { 191c6fd2807SJeff Garzik .name = DRV_NAME, 192c6fd2807SJeff Garzik .id_table = qs_ata_pci_tbl, 193c6fd2807SJeff Garzik .probe = qs_ata_init_one, 194c6fd2807SJeff Garzik .remove = ata_pci_remove_one, 195c6fd2807SJeff Garzik }; 196c6fd2807SJeff Garzik 1970d5ff566STejun Heo static void __iomem *qs_mmio_base(struct ata_host *host) 1980d5ff566STejun Heo { 1990d5ff566STejun Heo return host->iomap[QS_MMIO_BAR]; 2000d5ff566STejun Heo } 2010d5ff566STejun Heo 202c6fd2807SJeff Garzik static int qs_check_atapi_dma(struct ata_queued_cmd *qc) 203c6fd2807SJeff Garzik { 204c6fd2807SJeff Garzik return 1; /* ATAPI DMA not supported */ 205c6fd2807SJeff Garzik } 206c6fd2807SJeff Garzik 207c6fd2807SJeff Garzik static void qs_bmdma_stop(struct ata_queued_cmd *qc) 208c6fd2807SJeff Garzik { 209c6fd2807SJeff Garzik /* nothing */ 210c6fd2807SJeff Garzik } 211c6fd2807SJeff Garzik 212c6fd2807SJeff Garzik static u8 qs_bmdma_status(struct ata_port *ap) 213c6fd2807SJeff Garzik { 214c6fd2807SJeff Garzik return 0; 215c6fd2807SJeff Garzik } 216c6fd2807SJeff Garzik 217c6fd2807SJeff Garzik static void qs_irq_clear(struct ata_port *ap) 218c6fd2807SJeff Garzik { 219c6fd2807SJeff Garzik /* nothing */ 220c6fd2807SJeff Garzik } 221c6fd2807SJeff Garzik 222c6fd2807SJeff Garzik static inline void qs_enter_reg_mode(struct ata_port *ap) 223c6fd2807SJeff Garzik { 2240d5ff566STejun Heo u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000); 225c6fd2807SJeff Garzik 226c6fd2807SJeff Garzik writeb(QS_CTR0_REG, chan + QS_CCT_CTR0); 227c6fd2807SJeff Garzik readb(chan + QS_CCT_CTR0); /* flush */ 228c6fd2807SJeff Garzik } 229c6fd2807SJeff Garzik 230c6fd2807SJeff Garzik static inline void qs_reset_channel_logic(struct ata_port *ap) 231c6fd2807SJeff Garzik { 2320d5ff566STejun Heo u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000); 233c6fd2807SJeff Garzik 234c6fd2807SJeff Garzik writeb(QS_CTR1_RCHN, chan + QS_CCT_CTR1); 235c6fd2807SJeff Garzik readb(chan + QS_CCT_CTR0); /* flush */ 236c6fd2807SJeff Garzik qs_enter_reg_mode(ap); 237c6fd2807SJeff Garzik } 238c6fd2807SJeff Garzik 239c6fd2807SJeff Garzik static void qs_phy_reset(struct ata_port *ap) 240c6fd2807SJeff Garzik { 241c6fd2807SJeff Garzik struct qs_port_priv *pp = ap->private_data; 242c6fd2807SJeff Garzik 243c6fd2807SJeff Garzik pp->state = qs_state_idle; 244c6fd2807SJeff Garzik qs_reset_channel_logic(ap); 245c6fd2807SJeff Garzik sata_phy_reset(ap); 246c6fd2807SJeff Garzik } 247c6fd2807SJeff Garzik 248c6fd2807SJeff Garzik static void qs_eng_timeout(struct ata_port *ap) 249c6fd2807SJeff Garzik { 250c6fd2807SJeff Garzik struct qs_port_priv *pp = ap->private_data; 251c6fd2807SJeff Garzik 252c6fd2807SJeff Garzik if (pp->state != qs_state_idle) /* healthy paranoia */ 253c6fd2807SJeff Garzik pp->state = qs_state_mmio; 254c6fd2807SJeff Garzik qs_reset_channel_logic(ap); 255c6fd2807SJeff Garzik ata_eng_timeout(ap); 256c6fd2807SJeff Garzik } 257c6fd2807SJeff Garzik 258da3dbb17STejun Heo static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) 259c6fd2807SJeff Garzik { 260c6fd2807SJeff Garzik if (sc_reg > SCR_CONTROL) 261da3dbb17STejun Heo return -EINVAL; 262da3dbb17STejun Heo *val = readl(ap->ioaddr.scr_addr + (sc_reg * 8)); 263da3dbb17STejun Heo return 0; 264c6fd2807SJeff Garzik } 265c6fd2807SJeff Garzik 266da3dbb17STejun Heo static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) 267c6fd2807SJeff Garzik { 268c6fd2807SJeff Garzik if (sc_reg > SCR_CONTROL) 269da3dbb17STejun Heo return -EINVAL; 2700d5ff566STejun Heo writel(val, ap->ioaddr.scr_addr + (sc_reg * 8)); 271da3dbb17STejun Heo return 0; 272c6fd2807SJeff Garzik } 273c6fd2807SJeff Garzik 274c6fd2807SJeff Garzik static unsigned int qs_fill_sg(struct ata_queued_cmd *qc) 275c6fd2807SJeff Garzik { 276c6fd2807SJeff Garzik struct scatterlist *sg; 277c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 278c6fd2807SJeff Garzik struct qs_port_priv *pp = ap->private_data; 279c6fd2807SJeff Garzik unsigned int nelem; 280c6fd2807SJeff Garzik u8 *prd = pp->pkt + QS_CPB_BYTES; 281c6fd2807SJeff Garzik 282c6fd2807SJeff Garzik WARN_ON(qc->__sg == NULL); 283c6fd2807SJeff Garzik WARN_ON(qc->n_elem == 0 && qc->pad_len == 0); 284c6fd2807SJeff Garzik 285c6fd2807SJeff Garzik nelem = 0; 286c6fd2807SJeff Garzik ata_for_each_sg(sg, qc) { 287c6fd2807SJeff Garzik u64 addr; 288c6fd2807SJeff Garzik u32 len; 289c6fd2807SJeff Garzik 290c6fd2807SJeff Garzik addr = sg_dma_address(sg); 291c6fd2807SJeff Garzik *(__le64 *)prd = cpu_to_le64(addr); 292c6fd2807SJeff Garzik prd += sizeof(u64); 293c6fd2807SJeff Garzik 294c6fd2807SJeff Garzik len = sg_dma_len(sg); 295c6fd2807SJeff Garzik *(__le32 *)prd = cpu_to_le32(len); 296c6fd2807SJeff Garzik prd += sizeof(u64); 297c6fd2807SJeff Garzik 298c6fd2807SJeff Garzik VPRINTK("PRD[%u] = (0x%llX, 0x%X)\n", nelem, 299c6fd2807SJeff Garzik (unsigned long long)addr, len); 300c6fd2807SJeff Garzik nelem++; 301c6fd2807SJeff Garzik } 302c6fd2807SJeff Garzik 303c6fd2807SJeff Garzik return nelem; 304c6fd2807SJeff Garzik } 305c6fd2807SJeff Garzik 306c6fd2807SJeff Garzik static void qs_qc_prep(struct ata_queued_cmd *qc) 307c6fd2807SJeff Garzik { 308c6fd2807SJeff Garzik struct qs_port_priv *pp = qc->ap->private_data; 309c6fd2807SJeff Garzik u8 dflags = QS_DF_PORD, *buf = pp->pkt; 310c6fd2807SJeff Garzik u8 hflags = QS_HF_DAT | QS_HF_IEN | QS_HF_VLD; 311c6fd2807SJeff Garzik u64 addr; 312c6fd2807SJeff Garzik unsigned int nelem; 313c6fd2807SJeff Garzik 314c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 315c6fd2807SJeff Garzik 316c6fd2807SJeff Garzik qs_enter_reg_mode(qc->ap); 317c6fd2807SJeff Garzik if (qc->tf.protocol != ATA_PROT_DMA) { 318c6fd2807SJeff Garzik ata_qc_prep(qc); 319c6fd2807SJeff Garzik return; 320c6fd2807SJeff Garzik } 321c6fd2807SJeff Garzik 322c6fd2807SJeff Garzik nelem = qs_fill_sg(qc); 323c6fd2807SJeff Garzik 324c6fd2807SJeff Garzik if ((qc->tf.flags & ATA_TFLAG_WRITE)) 325c6fd2807SJeff Garzik hflags |= QS_HF_DIRO; 326c6fd2807SJeff Garzik if ((qc->tf.flags & ATA_TFLAG_LBA48)) 327c6fd2807SJeff Garzik dflags |= QS_DF_ELBA; 328c6fd2807SJeff Garzik 329c6fd2807SJeff Garzik /* host control block (HCB) */ 330c6fd2807SJeff Garzik buf[ 0] = QS_HCB_HDR; 331c6fd2807SJeff Garzik buf[ 1] = hflags; 332726f0785STejun Heo *(__le32 *)(&buf[ 4]) = cpu_to_le32(qc->nbytes); 333c6fd2807SJeff Garzik *(__le32 *)(&buf[ 8]) = cpu_to_le32(nelem); 334c6fd2807SJeff Garzik addr = ((u64)pp->pkt_dma) + QS_CPB_BYTES; 335c6fd2807SJeff Garzik *(__le64 *)(&buf[16]) = cpu_to_le64(addr); 336c6fd2807SJeff Garzik 337c6fd2807SJeff Garzik /* device control block (DCB) */ 338c6fd2807SJeff Garzik buf[24] = QS_DCB_HDR; 339c6fd2807SJeff Garzik buf[28] = dflags; 340c6fd2807SJeff Garzik 341c6fd2807SJeff Garzik /* frame information structure (FIS) */ 3429977126cSTejun Heo ata_tf_to_fis(&qc->tf, 0, 1, &buf[32]); 343c6fd2807SJeff Garzik } 344c6fd2807SJeff Garzik 345c6fd2807SJeff Garzik static inline void qs_packet_start(struct ata_queued_cmd *qc) 346c6fd2807SJeff Garzik { 347c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 3480d5ff566STejun Heo u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000); 349c6fd2807SJeff Garzik 350c6fd2807SJeff Garzik VPRINTK("ENTER, ap %p\n", ap); 351c6fd2807SJeff Garzik 352c6fd2807SJeff Garzik writeb(QS_CTR0_CLER, chan + QS_CCT_CTR0); 353c6fd2807SJeff Garzik wmb(); /* flush PRDs and pkt to memory */ 354c6fd2807SJeff Garzik writel(QS_CCF_RUN_PKT, chan + QS_CCT_CFF); 355c6fd2807SJeff Garzik readl(chan + QS_CCT_CFF); /* flush */ 356c6fd2807SJeff Garzik } 357c6fd2807SJeff Garzik 358c6fd2807SJeff Garzik static unsigned int qs_qc_issue(struct ata_queued_cmd *qc) 359c6fd2807SJeff Garzik { 360c6fd2807SJeff Garzik struct qs_port_priv *pp = qc->ap->private_data; 361c6fd2807SJeff Garzik 362c6fd2807SJeff Garzik switch (qc->tf.protocol) { 363c6fd2807SJeff Garzik case ATA_PROT_DMA: 364c6fd2807SJeff Garzik 365c6fd2807SJeff Garzik pp->state = qs_state_pkt; 366c6fd2807SJeff Garzik qs_packet_start(qc); 367c6fd2807SJeff Garzik return 0; 368c6fd2807SJeff Garzik 369c6fd2807SJeff Garzik case ATA_PROT_ATAPI_DMA: 370c6fd2807SJeff Garzik BUG(); 371c6fd2807SJeff Garzik break; 372c6fd2807SJeff Garzik 373c6fd2807SJeff Garzik default: 374c6fd2807SJeff Garzik break; 375c6fd2807SJeff Garzik } 376c6fd2807SJeff Garzik 377c6fd2807SJeff Garzik pp->state = qs_state_mmio; 378c6fd2807SJeff Garzik return ata_qc_issue_prot(qc); 379c6fd2807SJeff Garzik } 380c6fd2807SJeff Garzik 381cca3974eSJeff Garzik static inline unsigned int qs_intr_pkt(struct ata_host *host) 382c6fd2807SJeff Garzik { 383c6fd2807SJeff Garzik unsigned int handled = 0; 384c6fd2807SJeff Garzik u8 sFFE; 3850d5ff566STejun Heo u8 __iomem *mmio_base = qs_mmio_base(host); 386c6fd2807SJeff Garzik 387c6fd2807SJeff Garzik do { 388c6fd2807SJeff Garzik u32 sff0 = readl(mmio_base + QS_HST_SFF); 389c6fd2807SJeff Garzik u32 sff1 = readl(mmio_base + QS_HST_SFF + 4); 390c6fd2807SJeff Garzik u8 sEVLD = (sff1 >> 30) & 0x01; /* valid flag */ 391c6fd2807SJeff Garzik sFFE = sff1 >> 31; /* empty flag */ 392c6fd2807SJeff Garzik 393c6fd2807SJeff Garzik if (sEVLD) { 394c6fd2807SJeff Garzik u8 sDST = sff0 >> 16; /* dev status */ 395c6fd2807SJeff Garzik u8 sHST = sff1 & 0x3f; /* host status */ 396c6fd2807SJeff Garzik unsigned int port_no = (sff1 >> 8) & 0x03; 397cca3974eSJeff Garzik struct ata_port *ap = host->ports[port_no]; 398c6fd2807SJeff Garzik 399c6fd2807SJeff Garzik DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n", 400c6fd2807SJeff Garzik sff1, sff0, port_no, sHST, sDST); 401c6fd2807SJeff Garzik handled = 1; 402c6fd2807SJeff Garzik if (ap && !(ap->flags & ATA_FLAG_DISABLED)) { 403c6fd2807SJeff Garzik struct ata_queued_cmd *qc; 404c6fd2807SJeff Garzik struct qs_port_priv *pp = ap->private_data; 405c6fd2807SJeff Garzik if (!pp || pp->state != qs_state_pkt) 406c6fd2807SJeff Garzik continue; 407c6fd2807SJeff Garzik qc = ata_qc_from_tag(ap, ap->active_tag); 408c6fd2807SJeff Garzik if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { 409c6fd2807SJeff Garzik switch (sHST) { 410c6fd2807SJeff Garzik case 0: /* successful CPB */ 411c6fd2807SJeff Garzik case 3: /* device error */ 412c6fd2807SJeff Garzik pp->state = qs_state_idle; 413c6fd2807SJeff Garzik qs_enter_reg_mode(qc->ap); 414c6fd2807SJeff Garzik qc->err_mask |= ac_err_mask(sDST); 415c6fd2807SJeff Garzik ata_qc_complete(qc); 416c6fd2807SJeff Garzik break; 417c6fd2807SJeff Garzik default: 418c6fd2807SJeff Garzik break; 419c6fd2807SJeff Garzik } 420c6fd2807SJeff Garzik } 421c6fd2807SJeff Garzik } 422c6fd2807SJeff Garzik } 423c6fd2807SJeff Garzik } while (!sFFE); 424c6fd2807SJeff Garzik return handled; 425c6fd2807SJeff Garzik } 426c6fd2807SJeff Garzik 427cca3974eSJeff Garzik static inline unsigned int qs_intr_mmio(struct ata_host *host) 428c6fd2807SJeff Garzik { 429c6fd2807SJeff Garzik unsigned int handled = 0, port_no; 430c6fd2807SJeff Garzik 431cca3974eSJeff Garzik for (port_no = 0; port_no < host->n_ports; ++port_no) { 432c6fd2807SJeff Garzik struct ata_port *ap; 433cca3974eSJeff Garzik ap = host->ports[port_no]; 434c6fd2807SJeff Garzik if (ap && 435c6fd2807SJeff Garzik !(ap->flags & ATA_FLAG_DISABLED)) { 436c6fd2807SJeff Garzik struct ata_queued_cmd *qc; 437c6fd2807SJeff Garzik struct qs_port_priv *pp = ap->private_data; 438c6fd2807SJeff Garzik if (!pp || pp->state != qs_state_mmio) 439c6fd2807SJeff Garzik continue; 440c6fd2807SJeff Garzik qc = ata_qc_from_tag(ap, ap->active_tag); 441c6fd2807SJeff Garzik if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { 442c6fd2807SJeff Garzik 443c6fd2807SJeff Garzik /* check main status, clearing INTRQ */ 444c6fd2807SJeff Garzik u8 status = ata_check_status(ap); 445c6fd2807SJeff Garzik if ((status & ATA_BUSY)) 446c6fd2807SJeff Garzik continue; 447c6fd2807SJeff Garzik DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", 44844877b4eSTejun Heo ap->print_id, qc->tf.protocol, status); 449c6fd2807SJeff Garzik 450c6fd2807SJeff Garzik /* complete taskfile transaction */ 451c6fd2807SJeff Garzik pp->state = qs_state_idle; 452c6fd2807SJeff Garzik qc->err_mask |= ac_err_mask(status); 453c6fd2807SJeff Garzik ata_qc_complete(qc); 454c6fd2807SJeff Garzik handled = 1; 455c6fd2807SJeff Garzik } 456c6fd2807SJeff Garzik } 457c6fd2807SJeff Garzik } 458c6fd2807SJeff Garzik return handled; 459c6fd2807SJeff Garzik } 460c6fd2807SJeff Garzik 4617d12e780SDavid Howells static irqreturn_t qs_intr(int irq, void *dev_instance) 462c6fd2807SJeff Garzik { 463cca3974eSJeff Garzik struct ata_host *host = dev_instance; 464c6fd2807SJeff Garzik unsigned int handled = 0; 465c6fd2807SJeff Garzik 466c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 467c6fd2807SJeff Garzik 468cca3974eSJeff Garzik spin_lock(&host->lock); 469cca3974eSJeff Garzik handled = qs_intr_pkt(host) | qs_intr_mmio(host); 470cca3974eSJeff Garzik spin_unlock(&host->lock); 471c6fd2807SJeff Garzik 472c6fd2807SJeff Garzik VPRINTK("EXIT\n"); 473c6fd2807SJeff Garzik 474c6fd2807SJeff Garzik return IRQ_RETVAL(handled); 475c6fd2807SJeff Garzik } 476c6fd2807SJeff Garzik 4770d5ff566STejun Heo static void qs_ata_setup_port(struct ata_ioports *port, void __iomem *base) 478c6fd2807SJeff Garzik { 479c6fd2807SJeff Garzik port->cmd_addr = 480c6fd2807SJeff Garzik port->data_addr = base + 0x400; 481c6fd2807SJeff Garzik port->error_addr = 482c6fd2807SJeff Garzik port->feature_addr = base + 0x408; /* hob_feature = 0x409 */ 483c6fd2807SJeff Garzik port->nsect_addr = base + 0x410; /* hob_nsect = 0x411 */ 484c6fd2807SJeff Garzik port->lbal_addr = base + 0x418; /* hob_lbal = 0x419 */ 485c6fd2807SJeff Garzik port->lbam_addr = base + 0x420; /* hob_lbam = 0x421 */ 486c6fd2807SJeff Garzik port->lbah_addr = base + 0x428; /* hob_lbah = 0x429 */ 487c6fd2807SJeff Garzik port->device_addr = base + 0x430; 488c6fd2807SJeff Garzik port->status_addr = 489c6fd2807SJeff Garzik port->command_addr = base + 0x438; 490c6fd2807SJeff Garzik port->altstatus_addr = 491c6fd2807SJeff Garzik port->ctl_addr = base + 0x440; 492c6fd2807SJeff Garzik port->scr_addr = base + 0xc00; 493c6fd2807SJeff Garzik } 494c6fd2807SJeff Garzik 495c6fd2807SJeff Garzik static int qs_port_start(struct ata_port *ap) 496c6fd2807SJeff Garzik { 497cca3974eSJeff Garzik struct device *dev = ap->host->dev; 498c6fd2807SJeff Garzik struct qs_port_priv *pp; 4990d5ff566STejun Heo void __iomem *mmio_base = qs_mmio_base(ap->host); 500c6fd2807SJeff Garzik void __iomem *chan = mmio_base + (ap->port_no * 0x4000); 501c6fd2807SJeff Garzik u64 addr; 502c6fd2807SJeff Garzik int rc; 503c6fd2807SJeff Garzik 504c6fd2807SJeff Garzik rc = ata_port_start(ap); 505c6fd2807SJeff Garzik if (rc) 506c6fd2807SJeff Garzik return rc; 507c6fd2807SJeff Garzik qs_enter_reg_mode(ap); 50824dc5f33STejun Heo pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); 50924dc5f33STejun Heo if (!pp) 51024dc5f33STejun Heo return -ENOMEM; 51124dc5f33STejun Heo pp->pkt = dmam_alloc_coherent(dev, QS_PKT_BYTES, &pp->pkt_dma, 512c6fd2807SJeff Garzik GFP_KERNEL); 51324dc5f33STejun Heo if (!pp->pkt) 51424dc5f33STejun Heo return -ENOMEM; 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 524cca3974eSJeff Garzik static void qs_host_stop(struct ata_host *host) 525c6fd2807SJeff Garzik { 5260d5ff566STejun Heo void __iomem *mmio_base = qs_mmio_base(host); 527c6fd2807SJeff Garzik 528c6fd2807SJeff Garzik writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */ 529c6fd2807SJeff Garzik writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */ 530c6fd2807SJeff Garzik } 531c6fd2807SJeff Garzik 5324447d351STejun Heo static void qs_host_init(struct ata_host *host, unsigned int chip_id) 533c6fd2807SJeff Garzik { 5344447d351STejun Heo void __iomem *mmio_base = host->iomap[QS_MMIO_BAR]; 535c6fd2807SJeff Garzik unsigned int port_no; 536c6fd2807SJeff Garzik 537c6fd2807SJeff Garzik writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */ 538c6fd2807SJeff Garzik writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */ 539c6fd2807SJeff Garzik 540c6fd2807SJeff Garzik /* reset each channel in turn */ 5414447d351STejun Heo for (port_no = 0; port_no < host->n_ports; ++port_no) { 542c6fd2807SJeff Garzik u8 __iomem *chan = mmio_base + (port_no * 0x4000); 543c6fd2807SJeff Garzik writeb(QS_CTR1_RDEV|QS_CTR1_RCHN, chan + QS_CCT_CTR1); 544c6fd2807SJeff Garzik writeb(QS_CTR0_REG, chan + QS_CCT_CTR0); 545c6fd2807SJeff Garzik readb(chan + QS_CCT_CTR0); /* flush */ 546c6fd2807SJeff Garzik } 547c6fd2807SJeff Garzik writeb(QS_SERD3_PHY_ENA, mmio_base + QS_HVS_SERD3); /* enable phy */ 548c6fd2807SJeff Garzik 5494447d351STejun Heo for (port_no = 0; port_no < host->n_ports; ++port_no) { 550c6fd2807SJeff Garzik u8 __iomem *chan = mmio_base + (port_no * 0x4000); 551c6fd2807SJeff Garzik /* set FIFO depths to same settings as Windows driver */ 552c6fd2807SJeff Garzik writew(32, chan + QS_CFC_HUFT); 553c6fd2807SJeff Garzik writew(32, chan + QS_CFC_HDFT); 554c6fd2807SJeff Garzik writew(10, chan + QS_CFC_DUFT); 555c6fd2807SJeff Garzik writew( 8, chan + QS_CFC_DDFT); 556c6fd2807SJeff Garzik /* set CPB size in bytes, as a power of two */ 557c6fd2807SJeff Garzik writeb(QS_CPB_ORDER, chan + QS_CCF_CSEP); 558c6fd2807SJeff Garzik } 559c6fd2807SJeff Garzik writeb(1, mmio_base + QS_HCT_CTRL); /* enable host interrupts */ 560c6fd2807SJeff Garzik } 561c6fd2807SJeff Garzik 562c6fd2807SJeff Garzik /* 563c6fd2807SJeff Garzik * The QStor understands 64-bit buses, and uses 64-bit fields 564c6fd2807SJeff Garzik * for DMA pointers regardless of bus width. We just have to 565c6fd2807SJeff Garzik * make sure our DMA masks are set appropriately for whatever 566c6fd2807SJeff Garzik * bridge lies between us and the QStor, and then the DMA mapping 567c6fd2807SJeff Garzik * code will ensure we only ever "see" appropriate buffer addresses. 568c6fd2807SJeff Garzik * If we're 32-bit limited somewhere, then our 64-bit fields will 569c6fd2807SJeff Garzik * just end up with zeros in the upper 32-bits, without any special 570c6fd2807SJeff Garzik * logic required outside of this routine (below). 571c6fd2807SJeff Garzik */ 572c6fd2807SJeff Garzik static int qs_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base) 573c6fd2807SJeff Garzik { 574c6fd2807SJeff Garzik u32 bus_info = readl(mmio_base + QS_HID_HPHY); 575c6fd2807SJeff Garzik int rc, have_64bit_bus = (bus_info & QS_HPHY_64BIT); 576c6fd2807SJeff Garzik 577c6fd2807SJeff Garzik if (have_64bit_bus && 578c6fd2807SJeff Garzik !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { 579c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); 580c6fd2807SJeff Garzik if (rc) { 581c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 582c6fd2807SJeff Garzik if (rc) { 583c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 584c6fd2807SJeff Garzik "64-bit DMA enable failed\n"); 585c6fd2807SJeff Garzik return rc; 586c6fd2807SJeff Garzik } 587c6fd2807SJeff Garzik } 588c6fd2807SJeff Garzik } else { 589c6fd2807SJeff Garzik rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); 590c6fd2807SJeff Garzik if (rc) { 591c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 592c6fd2807SJeff Garzik "32-bit DMA enable failed\n"); 593c6fd2807SJeff Garzik return rc; 594c6fd2807SJeff Garzik } 595c6fd2807SJeff Garzik rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); 596c6fd2807SJeff Garzik if (rc) { 597c6fd2807SJeff Garzik dev_printk(KERN_ERR, &pdev->dev, 598c6fd2807SJeff Garzik "32-bit consistent DMA enable failed\n"); 599c6fd2807SJeff Garzik return rc; 600c6fd2807SJeff Garzik } 601c6fd2807SJeff Garzik } 602c6fd2807SJeff Garzik return 0; 603c6fd2807SJeff Garzik } 604c6fd2807SJeff Garzik 605c6fd2807SJeff Garzik static int qs_ata_init_one(struct pci_dev *pdev, 606c6fd2807SJeff Garzik const struct pci_device_id *ent) 607c6fd2807SJeff Garzik { 608c6fd2807SJeff Garzik static int printed_version; 609c6fd2807SJeff Garzik unsigned int board_idx = (unsigned int) ent->driver_data; 6104447d351STejun Heo const struct ata_port_info *ppi[] = { &qs_port_info[board_idx], NULL }; 6114447d351STejun Heo struct ata_host *host; 612c6fd2807SJeff Garzik int rc, port_no; 613c6fd2807SJeff Garzik 614c6fd2807SJeff Garzik if (!printed_version++) 615c6fd2807SJeff Garzik dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); 616c6fd2807SJeff Garzik 6174447d351STejun Heo /* alloc host */ 6184447d351STejun Heo host = ata_host_alloc_pinfo(&pdev->dev, ppi, QS_PORTS); 6194447d351STejun Heo if (!host) 6204447d351STejun Heo return -ENOMEM; 6214447d351STejun Heo 6224447d351STejun Heo /* acquire resources and fill host */ 62324dc5f33STejun Heo rc = pcim_enable_device(pdev); 624c6fd2807SJeff Garzik if (rc) 625c6fd2807SJeff Garzik return rc; 626c6fd2807SJeff Garzik 6270d5ff566STejun Heo if ((pci_resource_flags(pdev, QS_MMIO_BAR) & IORESOURCE_MEM) == 0) 62824dc5f33STejun Heo return -ENODEV; 629c6fd2807SJeff Garzik 6300d5ff566STejun Heo rc = pcim_iomap_regions(pdev, 1 << QS_MMIO_BAR, DRV_NAME); 6310d5ff566STejun Heo if (rc) 6320d5ff566STejun Heo return rc; 6334447d351STejun Heo host->iomap = pcim_iomap_table(pdev); 634c6fd2807SJeff Garzik 6354447d351STejun Heo rc = qs_set_dma_masks(pdev, host->iomap[QS_MMIO_BAR]); 636c6fd2807SJeff Garzik if (rc) 63724dc5f33STejun Heo return rc; 638c6fd2807SJeff Garzik 6394447d351STejun Heo for (port_no = 0; port_no < host->n_ports; ++port_no) { 6400d5ff566STejun Heo void __iomem *chan = 6414447d351STejun Heo host->iomap[QS_MMIO_BAR] + (port_no * 0x4000); 6424447d351STejun Heo qs_ata_setup_port(&host->ports[port_no]->ioaddr, chan); 643c6fd2807SJeff Garzik } 644c6fd2807SJeff Garzik 645c6fd2807SJeff Garzik /* initialize adapter */ 6464447d351STejun Heo qs_host_init(host, board_idx); 647c6fd2807SJeff Garzik 6484447d351STejun Heo pci_set_master(pdev); 6494447d351STejun Heo return ata_host_activate(host, pdev->irq, qs_intr, IRQF_SHARED, 6504447d351STejun Heo &qs_ata_sht); 651c6fd2807SJeff Garzik } 652c6fd2807SJeff Garzik 653c6fd2807SJeff Garzik static int __init qs_ata_init(void) 654c6fd2807SJeff Garzik { 655c6fd2807SJeff Garzik return pci_register_driver(&qs_ata_pci_driver); 656c6fd2807SJeff Garzik } 657c6fd2807SJeff Garzik 658c6fd2807SJeff Garzik static void __exit qs_ata_exit(void) 659c6fd2807SJeff Garzik { 660c6fd2807SJeff Garzik pci_unregister_driver(&qs_ata_pci_driver); 661c6fd2807SJeff Garzik } 662c6fd2807SJeff Garzik 663c6fd2807SJeff Garzik MODULE_AUTHOR("Mark Lord"); 664c6fd2807SJeff Garzik MODULE_DESCRIPTION("Pacific Digital Corporation QStor SATA low-level driver"); 665c6fd2807SJeff Garzik MODULE_LICENSE("GPL"); 666c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, qs_ata_pci_tbl); 667c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION); 668c6fd2807SJeff Garzik 669c6fd2807SJeff Garzik module_init(qs_ata_init); 670c6fd2807SJeff Garzik module_exit(qs_ata_exit); 671