1060358deSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2c6fd2807SJeff Garzik /* 3c6fd2807SJeff Garzik * sata_qstor.c - Pacific Digital Corporation QStor SATA 4c6fd2807SJeff Garzik * 5c6fd2807SJeff Garzik * Maintained by: Mark Lord <mlord@pobox.com> 6c6fd2807SJeff Garzik * 7c6fd2807SJeff Garzik * Copyright 2005 Pacific Digital Corporation. 8c6fd2807SJeff Garzik * (OSL/GPL code release authorized by Jalil Fadavi). 9c6fd2807SJeff Garzik * 10c6fd2807SJeff Garzik * libata documentation is available via 'make {ps|pdf}docs', 1119285f3cSMauro Carvalho Chehab * as Documentation/driver-api/libata.rst 12c6fd2807SJeff Garzik */ 13c6fd2807SJeff Garzik 14c6fd2807SJeff Garzik #include <linux/kernel.h> 15c6fd2807SJeff Garzik #include <linux/module.h> 165a0e3ad6STejun Heo #include <linux/gfp.h> 17c6fd2807SJeff Garzik #include <linux/pci.h> 18c6fd2807SJeff Garzik #include <linux/blkdev.h> 19c6fd2807SJeff Garzik #include <linux/delay.h> 20c6fd2807SJeff Garzik #include <linux/interrupt.h> 21c6fd2807SJeff Garzik #include <linux/device.h> 22c6fd2807SJeff Garzik #include <scsi/scsi_host.h> 23c6fd2807SJeff Garzik #include <linux/libata.h> 24c6fd2807SJeff Garzik 25c6fd2807SJeff Garzik #define DRV_NAME "sata_qstor" 262a3103ceSJeff Garzik #define DRV_VERSION "0.09" 27c6fd2807SJeff Garzik 28c6fd2807SJeff Garzik enum { 290d5ff566STejun Heo QS_MMIO_BAR = 4, 300d5ff566STejun Heo 31c6fd2807SJeff Garzik QS_PORTS = 4, 32c6fd2807SJeff Garzik QS_MAX_PRD = LIBATA_MAX_PRD, 33c6fd2807SJeff Garzik QS_CPB_ORDER = 6, 34c6fd2807SJeff Garzik QS_CPB_BYTES = (1 << QS_CPB_ORDER), 35c6fd2807SJeff Garzik QS_PRD_BYTES = QS_MAX_PRD * 16, 36c6fd2807SJeff Garzik QS_PKT_BYTES = QS_CPB_BYTES + QS_PRD_BYTES, 37c6fd2807SJeff Garzik 38c6fd2807SJeff Garzik /* global register offsets */ 39c6fd2807SJeff Garzik QS_HCF_CNFG3 = 0x0003, /* host configuration offset */ 40c6fd2807SJeff Garzik QS_HID_HPHY = 0x0004, /* host physical interface info */ 41c6fd2807SJeff Garzik QS_HCT_CTRL = 0x00e4, /* global interrupt mask offset */ 42c6fd2807SJeff Garzik QS_HST_SFF = 0x0100, /* host status fifo offset */ 43c6fd2807SJeff Garzik QS_HVS_SERD3 = 0x0393, /* PHY enable offset */ 44c6fd2807SJeff Garzik 45c6fd2807SJeff Garzik /* global control bits */ 46c6fd2807SJeff Garzik QS_HPHY_64BIT = (1 << 1), /* 64-bit bus detected */ 47c6fd2807SJeff Garzik QS_CNFG3_GSRST = 0x01, /* global chip reset */ 48c6fd2807SJeff Garzik QS_SERD3_PHY_ENA = 0xf0, /* PHY detection ENAble*/ 49c6fd2807SJeff Garzik 50c6fd2807SJeff Garzik /* per-channel register offsets */ 51c6fd2807SJeff Garzik QS_CCF_CPBA = 0x0710, /* chan CPB base address */ 52c6fd2807SJeff Garzik QS_CCF_CSEP = 0x0718, /* chan CPB separation factor */ 53c6fd2807SJeff Garzik QS_CFC_HUFT = 0x0800, /* host upstream fifo threshold */ 54c6fd2807SJeff Garzik QS_CFC_HDFT = 0x0804, /* host downstream fifo threshold */ 55c6fd2807SJeff Garzik QS_CFC_DUFT = 0x0808, /* dev upstream fifo threshold */ 56c6fd2807SJeff Garzik QS_CFC_DDFT = 0x080c, /* dev downstream fifo threshold */ 57c6fd2807SJeff Garzik QS_CCT_CTR0 = 0x0900, /* chan control-0 offset */ 58c6fd2807SJeff Garzik QS_CCT_CTR1 = 0x0901, /* chan control-1 offset */ 59c6fd2807SJeff Garzik QS_CCT_CFF = 0x0a00, /* chan command fifo offset */ 60c6fd2807SJeff Garzik 61c6fd2807SJeff Garzik /* channel control bits */ 62c6fd2807SJeff Garzik QS_CTR0_REG = (1 << 1), /* register mode (vs. pkt mode) */ 63c6fd2807SJeff Garzik QS_CTR0_CLER = (1 << 2), /* clear channel errors */ 64c6fd2807SJeff Garzik QS_CTR1_RDEV = (1 << 1), /* sata phy/comms reset */ 65c6fd2807SJeff Garzik QS_CTR1_RCHN = (1 << 4), /* reset channel logic */ 66c6fd2807SJeff Garzik QS_CCF_RUN_PKT = 0x107, /* RUN a new dma PKT */ 67c6fd2807SJeff Garzik 68c6fd2807SJeff Garzik /* pkt sub-field headers */ 69c6fd2807SJeff Garzik QS_HCB_HDR = 0x01, /* Host Control Block header */ 70c6fd2807SJeff Garzik QS_DCB_HDR = 0x02, /* Device Control Block header */ 71c6fd2807SJeff Garzik 72c6fd2807SJeff Garzik /* pkt HCB flag bits */ 73c6fd2807SJeff Garzik QS_HF_DIRO = (1 << 0), /* data DIRection Out */ 74c6fd2807SJeff Garzik QS_HF_DAT = (1 << 3), /* DATa pkt */ 75c6fd2807SJeff Garzik QS_HF_IEN = (1 << 4), /* Interrupt ENable */ 76c6fd2807SJeff Garzik QS_HF_VLD = (1 << 5), /* VaLiD pkt */ 77c6fd2807SJeff Garzik 78c6fd2807SJeff Garzik /* pkt DCB flag bits */ 79c6fd2807SJeff Garzik QS_DF_PORD = (1 << 2), /* Pio OR Dma */ 80c6fd2807SJeff Garzik QS_DF_ELBA = (1 << 3), /* Extended LBA (lba48) */ 81c6fd2807SJeff Garzik 82c6fd2807SJeff Garzik /* PCI device IDs */ 83c6fd2807SJeff Garzik board_2068_idx = 0, /* QStor 4-port SATA/RAID */ 84c6fd2807SJeff Garzik }; 85c6fd2807SJeff Garzik 86c6fd2807SJeff Garzik enum { 87c6fd2807SJeff Garzik QS_DMA_BOUNDARY = ~0UL 88c6fd2807SJeff Garzik }; 89c6fd2807SJeff Garzik 9012ee7d3cSMark Lord typedef enum { qs_state_mmio, qs_state_pkt } qs_state_t; 91c6fd2807SJeff Garzik 92c6fd2807SJeff Garzik struct qs_port_priv { 93c6fd2807SJeff Garzik u8 *pkt; 94c6fd2807SJeff Garzik dma_addr_t pkt_dma; 95c6fd2807SJeff Garzik qs_state_t state; 96c6fd2807SJeff Garzik }; 97c6fd2807SJeff Garzik 9882ef04fbSTejun Heo static int qs_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); 9982ef04fbSTejun Heo static int qs_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); 100c6fd2807SJeff Garzik static int qs_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); 101c6fd2807SJeff Garzik static int qs_port_start(struct ata_port *ap); 102cca3974eSJeff Garzik static void qs_host_stop(struct ata_host *host); 10395364f36SJiri Slaby static enum ata_completion_errors qs_qc_prep(struct ata_queued_cmd *qc); 104c6fd2807SJeff Garzik static unsigned int qs_qc_issue(struct ata_queued_cmd *qc); 105c6fd2807SJeff Garzik static int qs_check_atapi_dma(struct ata_queued_cmd *qc); 1066004bda1SMark Lord static void qs_freeze(struct ata_port *ap); 1076004bda1SMark Lord static void qs_thaw(struct ata_port *ap); 108a1efdabaSTejun Heo static int qs_prereset(struct ata_link *link, unsigned long deadline); 1096004bda1SMark Lord static void qs_error_handler(struct ata_port *ap); 110c6fd2807SJeff Garzik 111c6fd2807SJeff Garzik static struct scsi_host_template qs_ata_sht = { 11268d1d07bSTejun Heo ATA_BASE_SHT(DRV_NAME), 113c6fd2807SJeff Garzik .sg_tablesize = QS_MAX_PRD, 114c6fd2807SJeff Garzik .dma_boundary = QS_DMA_BOUNDARY, 115c6fd2807SJeff Garzik }; 116c6fd2807SJeff Garzik 117029cfd6bSTejun Heo static struct ata_port_operations qs_ata_ops = { 118029cfd6bSTejun Heo .inherits = &ata_sff_port_ops, 119029cfd6bSTejun Heo 120c6fd2807SJeff Garzik .check_atapi_dma = qs_check_atapi_dma, 121c6fd2807SJeff Garzik .qc_prep = qs_qc_prep, 122c6fd2807SJeff Garzik .qc_issue = qs_qc_issue, 123029cfd6bSTejun Heo 1246004bda1SMark Lord .freeze = qs_freeze, 1256004bda1SMark Lord .thaw = qs_thaw, 126a1efdabaSTejun Heo .prereset = qs_prereset, 127a1efdabaSTejun Heo .softreset = ATA_OP_NULL, 1286004bda1SMark Lord .error_handler = qs_error_handler, 129c96f1732SAlan Cox .lost_interrupt = ATA_OP_NULL, 130029cfd6bSTejun Heo 131c6fd2807SJeff Garzik .scr_read = qs_scr_read, 132c6fd2807SJeff Garzik .scr_write = qs_scr_write, 133029cfd6bSTejun Heo 134c6fd2807SJeff Garzik .port_start = qs_port_start, 135c6fd2807SJeff Garzik .host_stop = qs_host_stop, 136c6fd2807SJeff Garzik }; 137c6fd2807SJeff Garzik 138c6fd2807SJeff Garzik static const struct ata_port_info qs_port_info[] = { 139c6fd2807SJeff Garzik /* board_2068_idx */ 140c6fd2807SJeff Garzik { 1419cbe056fSSergei Shtylyov .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_POLLING, 14214bdef98SErik Inge Bolsø .pio_mask = ATA_PIO4_ONLY, 143bf6263a8SJeff Garzik .udma_mask = ATA_UDMA6, 144c6fd2807SJeff Garzik .port_ops = &qs_ata_ops, 145c6fd2807SJeff Garzik }, 146c6fd2807SJeff Garzik }; 147c6fd2807SJeff Garzik 148c6fd2807SJeff Garzik static const struct pci_device_id qs_ata_pci_tbl[] = { 1492d2744fcSJeff Garzik { PCI_VDEVICE(PDC, 0x2068), board_2068_idx }, 150c6fd2807SJeff Garzik 151c6fd2807SJeff Garzik { } /* terminate list */ 152c6fd2807SJeff Garzik }; 153c6fd2807SJeff Garzik 154c6fd2807SJeff Garzik static struct pci_driver qs_ata_pci_driver = { 155c6fd2807SJeff Garzik .name = DRV_NAME, 156c6fd2807SJeff Garzik .id_table = qs_ata_pci_tbl, 157c6fd2807SJeff Garzik .probe = qs_ata_init_one, 158c6fd2807SJeff Garzik .remove = ata_pci_remove_one, 159c6fd2807SJeff Garzik }; 160c6fd2807SJeff Garzik 1610d5ff566STejun Heo static void __iomem *qs_mmio_base(struct ata_host *host) 1620d5ff566STejun Heo { 1630d5ff566STejun Heo return host->iomap[QS_MMIO_BAR]; 1640d5ff566STejun Heo } 1650d5ff566STejun Heo 166c6fd2807SJeff Garzik static int qs_check_atapi_dma(struct ata_queued_cmd *qc) 167c6fd2807SJeff Garzik { 168c6fd2807SJeff Garzik return 1; /* ATAPI DMA not supported */ 169c6fd2807SJeff Garzik } 170c6fd2807SJeff Garzik 171c6fd2807SJeff Garzik static inline void qs_enter_reg_mode(struct ata_port *ap) 172c6fd2807SJeff Garzik { 1730d5ff566STejun Heo u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000); 17412ee7d3cSMark Lord struct qs_port_priv *pp = ap->private_data; 175c6fd2807SJeff Garzik 17612ee7d3cSMark Lord pp->state = qs_state_mmio; 177c6fd2807SJeff Garzik writeb(QS_CTR0_REG, chan + QS_CCT_CTR0); 178c6fd2807SJeff Garzik readb(chan + QS_CCT_CTR0); /* flush */ 179c6fd2807SJeff Garzik } 180c6fd2807SJeff Garzik 181c6fd2807SJeff Garzik static inline void qs_reset_channel_logic(struct ata_port *ap) 182c6fd2807SJeff Garzik { 1830d5ff566STejun Heo u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000); 184c6fd2807SJeff Garzik 185c6fd2807SJeff Garzik writeb(QS_CTR1_RCHN, chan + QS_CCT_CTR1); 186c6fd2807SJeff Garzik readb(chan + QS_CCT_CTR0); /* flush */ 187c6fd2807SJeff Garzik qs_enter_reg_mode(ap); 188c6fd2807SJeff Garzik } 189c6fd2807SJeff Garzik 1906004bda1SMark Lord static void qs_freeze(struct ata_port *ap) 191c6fd2807SJeff Garzik { 1926004bda1SMark Lord u8 __iomem *mmio_base = qs_mmio_base(ap->host); 1936004bda1SMark Lord 1946004bda1SMark Lord writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */ 1956004bda1SMark Lord qs_enter_reg_mode(ap); 196c6fd2807SJeff Garzik } 197c6fd2807SJeff Garzik 1986004bda1SMark Lord static void qs_thaw(struct ata_port *ap) 199c6fd2807SJeff Garzik { 2006004bda1SMark Lord u8 __iomem *mmio_base = qs_mmio_base(ap->host); 2016004bda1SMark Lord 2026004bda1SMark Lord qs_enter_reg_mode(ap); 2036004bda1SMark Lord writeb(1, mmio_base + QS_HCT_CTRL); /* enable host interrupts */ 2046004bda1SMark Lord } 2056004bda1SMark Lord 2066004bda1SMark Lord static int qs_prereset(struct ata_link *link, unsigned long deadline) 2076004bda1SMark Lord { 2086004bda1SMark Lord struct ata_port *ap = link->ap; 2096004bda1SMark Lord 210c6fd2807SJeff Garzik qs_reset_channel_logic(ap); 2119363c382STejun Heo return ata_sff_prereset(link, deadline); 212c6fd2807SJeff Garzik } 213c6fd2807SJeff Garzik 21482ef04fbSTejun Heo static int qs_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val) 215c6fd2807SJeff Garzik { 216c6fd2807SJeff Garzik if (sc_reg > SCR_CONTROL) 217da3dbb17STejun Heo return -EINVAL; 21882ef04fbSTejun Heo *val = readl(link->ap->ioaddr.scr_addr + (sc_reg * 8)); 219da3dbb17STejun Heo return 0; 220c6fd2807SJeff Garzik } 221c6fd2807SJeff Garzik 2226004bda1SMark Lord static void qs_error_handler(struct ata_port *ap) 2236004bda1SMark Lord { 2246004bda1SMark Lord qs_enter_reg_mode(ap); 225fe06e5f9STejun Heo ata_sff_error_handler(ap); 2266004bda1SMark Lord } 2276004bda1SMark Lord 22882ef04fbSTejun Heo static int qs_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) 229c6fd2807SJeff Garzik { 230c6fd2807SJeff Garzik if (sc_reg > SCR_CONTROL) 231da3dbb17STejun Heo return -EINVAL; 23282ef04fbSTejun Heo writel(val, link->ap->ioaddr.scr_addr + (sc_reg * 8)); 233da3dbb17STejun Heo return 0; 234c6fd2807SJeff Garzik } 235c6fd2807SJeff Garzik 236c6fd2807SJeff Garzik static unsigned int qs_fill_sg(struct ata_queued_cmd *qc) 237c6fd2807SJeff Garzik { 238c6fd2807SJeff Garzik struct scatterlist *sg; 239c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 240c6fd2807SJeff Garzik struct qs_port_priv *pp = ap->private_data; 241c6fd2807SJeff Garzik u8 *prd = pp->pkt + QS_CPB_BYTES; 242ff2aeb1eSTejun Heo unsigned int si; 243c6fd2807SJeff Garzik 244ff2aeb1eSTejun Heo for_each_sg(qc->sg, sg, qc->n_elem, si) { 245c6fd2807SJeff Garzik u64 addr; 246c6fd2807SJeff Garzik u32 len; 247c6fd2807SJeff Garzik 248c6fd2807SJeff Garzik addr = sg_dma_address(sg); 249c6fd2807SJeff Garzik *(__le64 *)prd = cpu_to_le64(addr); 250c6fd2807SJeff Garzik prd += sizeof(u64); 251c6fd2807SJeff Garzik 252c6fd2807SJeff Garzik len = sg_dma_len(sg); 253c6fd2807SJeff Garzik *(__le32 *)prd = cpu_to_le32(len); 254c6fd2807SJeff Garzik prd += sizeof(u64); 255c6fd2807SJeff Garzik 256ff2aeb1eSTejun Heo VPRINTK("PRD[%u] = (0x%llX, 0x%X)\n", si, 257c6fd2807SJeff Garzik (unsigned long long)addr, len); 258c6fd2807SJeff Garzik } 259c6fd2807SJeff Garzik 260ff2aeb1eSTejun Heo return si; 261c6fd2807SJeff Garzik } 262c6fd2807SJeff Garzik 26395364f36SJiri Slaby static enum ata_completion_errors qs_qc_prep(struct ata_queued_cmd *qc) 264c6fd2807SJeff Garzik { 265c6fd2807SJeff Garzik struct qs_port_priv *pp = qc->ap->private_data; 266c6fd2807SJeff Garzik u8 dflags = QS_DF_PORD, *buf = pp->pkt; 267c6fd2807SJeff Garzik u8 hflags = QS_HF_DAT | QS_HF_IEN | QS_HF_VLD; 268c6fd2807SJeff Garzik u64 addr; 269c6fd2807SJeff Garzik unsigned int nelem; 270c6fd2807SJeff Garzik 271c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 272c6fd2807SJeff Garzik 273c6fd2807SJeff Garzik qs_enter_reg_mode(qc->ap); 274f47451c4STejun Heo if (qc->tf.protocol != ATA_PROT_DMA) 27595364f36SJiri Slaby return AC_ERR_OK; 276c6fd2807SJeff Garzik 277c6fd2807SJeff Garzik nelem = qs_fill_sg(qc); 278c6fd2807SJeff Garzik 279c6fd2807SJeff Garzik if ((qc->tf.flags & ATA_TFLAG_WRITE)) 280c6fd2807SJeff Garzik hflags |= QS_HF_DIRO; 281c6fd2807SJeff Garzik if ((qc->tf.flags & ATA_TFLAG_LBA48)) 282c6fd2807SJeff Garzik dflags |= QS_DF_ELBA; 283c6fd2807SJeff Garzik 284c6fd2807SJeff Garzik /* host control block (HCB) */ 285c6fd2807SJeff Garzik buf[ 0] = QS_HCB_HDR; 286c6fd2807SJeff Garzik buf[ 1] = hflags; 287726f0785STejun Heo *(__le32 *)(&buf[ 4]) = cpu_to_le32(qc->nbytes); 288c6fd2807SJeff Garzik *(__le32 *)(&buf[ 8]) = cpu_to_le32(nelem); 289c6fd2807SJeff Garzik addr = ((u64)pp->pkt_dma) + QS_CPB_BYTES; 290c6fd2807SJeff Garzik *(__le64 *)(&buf[16]) = cpu_to_le64(addr); 291c6fd2807SJeff Garzik 292c6fd2807SJeff Garzik /* device control block (DCB) */ 293c6fd2807SJeff Garzik buf[24] = QS_DCB_HDR; 294c6fd2807SJeff Garzik buf[28] = dflags; 295c6fd2807SJeff Garzik 296c6fd2807SJeff Garzik /* frame information structure (FIS) */ 2979977126cSTejun Heo ata_tf_to_fis(&qc->tf, 0, 1, &buf[32]); 29895364f36SJiri Slaby 29995364f36SJiri Slaby return AC_ERR_OK; 300c6fd2807SJeff Garzik } 301c6fd2807SJeff Garzik 302c6fd2807SJeff Garzik static inline void qs_packet_start(struct ata_queued_cmd *qc) 303c6fd2807SJeff Garzik { 304c6fd2807SJeff Garzik struct ata_port *ap = qc->ap; 3050d5ff566STejun Heo u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000); 306c6fd2807SJeff Garzik 307c6fd2807SJeff Garzik VPRINTK("ENTER, ap %p\n", ap); 308c6fd2807SJeff Garzik 309c6fd2807SJeff Garzik writeb(QS_CTR0_CLER, chan + QS_CCT_CTR0); 310c6fd2807SJeff Garzik wmb(); /* flush PRDs and pkt to memory */ 311c6fd2807SJeff Garzik writel(QS_CCF_RUN_PKT, chan + QS_CCT_CFF); 312c6fd2807SJeff Garzik readl(chan + QS_CCT_CFF); /* flush */ 313c6fd2807SJeff Garzik } 314c6fd2807SJeff Garzik 315c6fd2807SJeff Garzik static unsigned int qs_qc_issue(struct ata_queued_cmd *qc) 316c6fd2807SJeff Garzik { 317c6fd2807SJeff Garzik struct qs_port_priv *pp = qc->ap->private_data; 318c6fd2807SJeff Garzik 319c6fd2807SJeff Garzik switch (qc->tf.protocol) { 320c6fd2807SJeff Garzik case ATA_PROT_DMA: 321c6fd2807SJeff Garzik pp->state = qs_state_pkt; 322c6fd2807SJeff Garzik qs_packet_start(qc); 323c6fd2807SJeff Garzik return 0; 324c6fd2807SJeff Garzik 3250dc36888STejun Heo case ATAPI_PROT_DMA: 326c6fd2807SJeff Garzik BUG(); 327c6fd2807SJeff Garzik break; 328c6fd2807SJeff Garzik 329c6fd2807SJeff Garzik default: 330c6fd2807SJeff Garzik break; 331c6fd2807SJeff Garzik } 332c6fd2807SJeff Garzik 333c6fd2807SJeff Garzik pp->state = qs_state_mmio; 3349363c382STejun Heo return ata_sff_qc_issue(qc); 335c6fd2807SJeff Garzik } 336c6fd2807SJeff Garzik 3376004bda1SMark Lord static void qs_do_or_die(struct ata_queued_cmd *qc, u8 status) 3386004bda1SMark Lord { 3396004bda1SMark Lord qc->err_mask |= ac_err_mask(status); 3406004bda1SMark Lord 3416004bda1SMark Lord if (!qc->err_mask) { 3426004bda1SMark Lord ata_qc_complete(qc); 3436004bda1SMark Lord } else { 3446004bda1SMark Lord struct ata_port *ap = qc->ap; 3456004bda1SMark Lord struct ata_eh_info *ehi = &ap->link.eh_info; 3466004bda1SMark Lord 3476004bda1SMark Lord ata_ehi_clear_desc(ehi); 3486004bda1SMark Lord ata_ehi_push_desc(ehi, "status 0x%02X", status); 3496004bda1SMark Lord 3506004bda1SMark Lord if (qc->err_mask == AC_ERR_DEV) 3516004bda1SMark Lord ata_port_abort(ap); 3526004bda1SMark Lord else 3536004bda1SMark Lord ata_port_freeze(ap); 3546004bda1SMark Lord } 3556004bda1SMark Lord } 3566004bda1SMark Lord 357cca3974eSJeff Garzik static inline unsigned int qs_intr_pkt(struct ata_host *host) 358c6fd2807SJeff Garzik { 359c6fd2807SJeff Garzik unsigned int handled = 0; 360c6fd2807SJeff Garzik u8 sFFE; 3610d5ff566STejun Heo u8 __iomem *mmio_base = qs_mmio_base(host); 362c6fd2807SJeff Garzik 363c6fd2807SJeff Garzik do { 364c6fd2807SJeff Garzik u32 sff0 = readl(mmio_base + QS_HST_SFF); 365c6fd2807SJeff Garzik u32 sff1 = readl(mmio_base + QS_HST_SFF + 4); 366c6fd2807SJeff Garzik u8 sEVLD = (sff1 >> 30) & 0x01; /* valid flag */ 367c6fd2807SJeff Garzik sFFE = sff1 >> 31; /* empty flag */ 368c6fd2807SJeff Garzik 369c6fd2807SJeff Garzik if (sEVLD) { 370c6fd2807SJeff Garzik u8 sDST = sff0 >> 16; /* dev status */ 371c6fd2807SJeff Garzik u8 sHST = sff1 & 0x3f; /* host status */ 372c6fd2807SJeff Garzik unsigned int port_no = (sff1 >> 8) & 0x03; 373cca3974eSJeff Garzik struct ata_port *ap = host->ports[port_no]; 3743e4ec344STejun Heo struct qs_port_priv *pp = ap->private_data; 3753e4ec344STejun Heo struct ata_queued_cmd *qc; 376c6fd2807SJeff Garzik 377*1891b92aSHannes Reinecke dev_dbg(host->dev, "SFF=%08x%08x: sHST=%d sDST=%02x\n", 378*1891b92aSHannes Reinecke sff1, sff0, sHST, sDST); 379c6fd2807SJeff Garzik handled = 1; 380c6fd2807SJeff Garzik if (!pp || pp->state != qs_state_pkt) 381c6fd2807SJeff Garzik continue; 3829af5c9c9STejun Heo qc = ata_qc_from_tag(ap, ap->link.active_tag); 383c6fd2807SJeff Garzik if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) { 384c6fd2807SJeff Garzik switch (sHST) { 385c6fd2807SJeff Garzik case 0: /* successful CPB */ 386c6fd2807SJeff Garzik case 3: /* device error */ 387c6fd2807SJeff Garzik qs_enter_reg_mode(qc->ap); 3886004bda1SMark Lord qs_do_or_die(qc, sDST); 389c6fd2807SJeff Garzik break; 390c6fd2807SJeff Garzik default: 391c6fd2807SJeff Garzik break; 392c6fd2807SJeff Garzik } 393c6fd2807SJeff Garzik } 394c6fd2807SJeff Garzik } 395c6fd2807SJeff Garzik } while (!sFFE); 396c6fd2807SJeff Garzik return handled; 397c6fd2807SJeff Garzik } 398c6fd2807SJeff Garzik 399cca3974eSJeff Garzik static inline unsigned int qs_intr_mmio(struct ata_host *host) 400c6fd2807SJeff Garzik { 401c6fd2807SJeff Garzik unsigned int handled = 0, port_no; 402c6fd2807SJeff Garzik 403cca3974eSJeff Garzik for (port_no = 0; port_no < host->n_ports; ++port_no) { 4043e4ec344STejun Heo struct ata_port *ap = host->ports[port_no]; 4053e4ec344STejun Heo struct qs_port_priv *pp = ap->private_data; 406c6fd2807SJeff Garzik struct ata_queued_cmd *qc; 4073e4ec344STejun Heo 408904c7badSMark Lord qc = ata_qc_from_tag(ap, ap->link.active_tag); 4093e4ec344STejun Heo if (!qc) { 410904c7badSMark Lord /* 411904c7badSMark Lord * The qstor hardware generates spurious 412904c7badSMark Lord * interrupts from time to time when switching 4133e4ec344STejun Heo * in and out of packet mode. There's no 4143e4ec344STejun Heo * obvious way to know if we're here now due 4153e4ec344STejun Heo * to that, so just ack the irq and pretend we 4163e4ec344STejun Heo * knew it was ours.. (ugh). This does not 4173e4ec344STejun Heo * affect packet mode. 418904c7badSMark Lord */ 4199363c382STejun Heo ata_sff_check_status(ap); 420904c7badSMark Lord handled = 1; 421904c7badSMark Lord continue; 422904c7badSMark Lord } 4233e4ec344STejun Heo 424c6fd2807SJeff Garzik if (!pp || pp->state != qs_state_mmio) 425c6fd2807SJeff Garzik continue; 426904c7badSMark Lord if (!(qc->tf.flags & ATA_TFLAG_POLLING)) 427c3b28894STejun Heo handled |= ata_sff_port_intr(ap, qc); 428c6fd2807SJeff Garzik } 429c6fd2807SJeff Garzik return handled; 430c6fd2807SJeff Garzik } 431c6fd2807SJeff Garzik 4327d12e780SDavid Howells static irqreturn_t qs_intr(int irq, void *dev_instance) 433c6fd2807SJeff Garzik { 434cca3974eSJeff Garzik struct ata_host *host = dev_instance; 435c6fd2807SJeff Garzik unsigned int handled = 0; 436904c7badSMark Lord unsigned long flags; 437c6fd2807SJeff Garzik 438c6fd2807SJeff Garzik VPRINTK("ENTER\n"); 439c6fd2807SJeff Garzik 440904c7badSMark Lord spin_lock_irqsave(&host->lock, flags); 441cca3974eSJeff Garzik handled = qs_intr_pkt(host) | qs_intr_mmio(host); 442904c7badSMark Lord spin_unlock_irqrestore(&host->lock, flags); 443c6fd2807SJeff Garzik 444c6fd2807SJeff Garzik VPRINTK("EXIT\n"); 445c6fd2807SJeff Garzik 446c6fd2807SJeff Garzik return IRQ_RETVAL(handled); 447c6fd2807SJeff Garzik } 448c6fd2807SJeff Garzik 4490d5ff566STejun Heo static void qs_ata_setup_port(struct ata_ioports *port, void __iomem *base) 450c6fd2807SJeff Garzik { 451c6fd2807SJeff Garzik port->cmd_addr = 452c6fd2807SJeff Garzik port->data_addr = base + 0x400; 453c6fd2807SJeff Garzik port->error_addr = 454c6fd2807SJeff Garzik port->feature_addr = base + 0x408; /* hob_feature = 0x409 */ 455c6fd2807SJeff Garzik port->nsect_addr = base + 0x410; /* hob_nsect = 0x411 */ 456c6fd2807SJeff Garzik port->lbal_addr = base + 0x418; /* hob_lbal = 0x419 */ 457c6fd2807SJeff Garzik port->lbam_addr = base + 0x420; /* hob_lbam = 0x421 */ 458c6fd2807SJeff Garzik port->lbah_addr = base + 0x428; /* hob_lbah = 0x429 */ 459c6fd2807SJeff Garzik port->device_addr = base + 0x430; 460c6fd2807SJeff Garzik port->status_addr = 461c6fd2807SJeff Garzik port->command_addr = base + 0x438; 462c6fd2807SJeff Garzik port->altstatus_addr = 463c6fd2807SJeff Garzik port->ctl_addr = base + 0x440; 464c6fd2807SJeff Garzik port->scr_addr = base + 0xc00; 465c6fd2807SJeff Garzik } 466c6fd2807SJeff Garzik 467c6fd2807SJeff Garzik static int qs_port_start(struct ata_port *ap) 468c6fd2807SJeff Garzik { 469cca3974eSJeff Garzik struct device *dev = ap->host->dev; 470c6fd2807SJeff Garzik struct qs_port_priv *pp; 4710d5ff566STejun Heo void __iomem *mmio_base = qs_mmio_base(ap->host); 472c6fd2807SJeff Garzik void __iomem *chan = mmio_base + (ap->port_no * 0x4000); 473c6fd2807SJeff Garzik u64 addr; 474c6fd2807SJeff Garzik 47524dc5f33STejun Heo pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); 47624dc5f33STejun Heo if (!pp) 47724dc5f33STejun Heo return -ENOMEM; 47824dc5f33STejun Heo pp->pkt = dmam_alloc_coherent(dev, QS_PKT_BYTES, &pp->pkt_dma, 479c6fd2807SJeff Garzik GFP_KERNEL); 48024dc5f33STejun Heo if (!pp->pkt) 48124dc5f33STejun Heo return -ENOMEM; 482c6fd2807SJeff Garzik ap->private_data = pp; 483c6fd2807SJeff Garzik 48412ee7d3cSMark Lord qs_enter_reg_mode(ap); 485c6fd2807SJeff Garzik addr = (u64)pp->pkt_dma; 486c6fd2807SJeff Garzik writel((u32) addr, chan + QS_CCF_CPBA); 487c6fd2807SJeff Garzik writel((u32)(addr >> 32), chan + QS_CCF_CPBA + 4); 488c6fd2807SJeff Garzik return 0; 489c6fd2807SJeff Garzik } 490c6fd2807SJeff Garzik 491cca3974eSJeff Garzik static void qs_host_stop(struct ata_host *host) 492c6fd2807SJeff Garzik { 4930d5ff566STejun Heo void __iomem *mmio_base = qs_mmio_base(host); 494c6fd2807SJeff Garzik 495c6fd2807SJeff Garzik writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */ 496c6fd2807SJeff Garzik writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */ 497c6fd2807SJeff Garzik } 498c6fd2807SJeff Garzik 4994447d351STejun Heo static void qs_host_init(struct ata_host *host, unsigned int chip_id) 500c6fd2807SJeff Garzik { 5014447d351STejun Heo void __iomem *mmio_base = host->iomap[QS_MMIO_BAR]; 502c6fd2807SJeff Garzik unsigned int port_no; 503c6fd2807SJeff Garzik 504c6fd2807SJeff Garzik writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */ 505c6fd2807SJeff Garzik writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */ 506c6fd2807SJeff Garzik 507c6fd2807SJeff Garzik /* reset each channel in turn */ 5084447d351STejun Heo for (port_no = 0; port_no < host->n_ports; ++port_no) { 509c6fd2807SJeff Garzik u8 __iomem *chan = mmio_base + (port_no * 0x4000); 510c6fd2807SJeff Garzik writeb(QS_CTR1_RDEV|QS_CTR1_RCHN, chan + QS_CCT_CTR1); 511c6fd2807SJeff Garzik writeb(QS_CTR0_REG, chan + QS_CCT_CTR0); 512c6fd2807SJeff Garzik readb(chan + QS_CCT_CTR0); /* flush */ 513c6fd2807SJeff Garzik } 514c6fd2807SJeff Garzik writeb(QS_SERD3_PHY_ENA, mmio_base + QS_HVS_SERD3); /* enable phy */ 515c6fd2807SJeff Garzik 5164447d351STejun Heo for (port_no = 0; port_no < host->n_ports; ++port_no) { 517c6fd2807SJeff Garzik u8 __iomem *chan = mmio_base + (port_no * 0x4000); 518c6fd2807SJeff Garzik /* set FIFO depths to same settings as Windows driver */ 519c6fd2807SJeff Garzik writew(32, chan + QS_CFC_HUFT); 520c6fd2807SJeff Garzik writew(32, chan + QS_CFC_HDFT); 521c6fd2807SJeff Garzik writew(10, chan + QS_CFC_DUFT); 522c6fd2807SJeff Garzik writew( 8, chan + QS_CFC_DDFT); 523c6fd2807SJeff Garzik /* set CPB size in bytes, as a power of two */ 524c6fd2807SJeff Garzik writeb(QS_CPB_ORDER, chan + QS_CCF_CSEP); 525c6fd2807SJeff Garzik } 526c6fd2807SJeff Garzik writeb(1, mmio_base + QS_HCT_CTRL); /* enable host interrupts */ 527c6fd2807SJeff Garzik } 528c6fd2807SJeff Garzik 529c6fd2807SJeff Garzik /* 530c6fd2807SJeff Garzik * The QStor understands 64-bit buses, and uses 64-bit fields 531c6fd2807SJeff Garzik * for DMA pointers regardless of bus width. We just have to 532c6fd2807SJeff Garzik * make sure our DMA masks are set appropriately for whatever 533c6fd2807SJeff Garzik * bridge lies between us and the QStor, and then the DMA mapping 534c6fd2807SJeff Garzik * code will ensure we only ever "see" appropriate buffer addresses. 535c6fd2807SJeff Garzik * If we're 32-bit limited somewhere, then our 64-bit fields will 536c6fd2807SJeff Garzik * just end up with zeros in the upper 32-bits, without any special 537c6fd2807SJeff Garzik * logic required outside of this routine (below). 538c6fd2807SJeff Garzik */ 539c6fd2807SJeff Garzik static int qs_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base) 540c6fd2807SJeff Garzik { 541c6fd2807SJeff Garzik u32 bus_info = readl(mmio_base + QS_HID_HPHY); 542440bd77fSChristoph Hellwig int dma_bits = (bus_info & QS_HPHY_64BIT) ? 64 : 32; 543440bd77fSChristoph Hellwig int rc; 544c6fd2807SJeff Garzik 545440bd77fSChristoph Hellwig rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(dma_bits)); 546440bd77fSChristoph Hellwig if (rc) 547440bd77fSChristoph Hellwig dev_err(&pdev->dev, "%d-bit DMA enable failed\n", dma_bits); 548c6fd2807SJeff Garzik return rc; 549c6fd2807SJeff Garzik } 550c6fd2807SJeff Garzik 551c6fd2807SJeff Garzik static int qs_ata_init_one(struct pci_dev *pdev, 552c6fd2807SJeff Garzik const struct pci_device_id *ent) 553c6fd2807SJeff Garzik { 554c6fd2807SJeff Garzik unsigned int board_idx = (unsigned int) ent->driver_data; 5554447d351STejun Heo const struct ata_port_info *ppi[] = { &qs_port_info[board_idx], NULL }; 5564447d351STejun Heo struct ata_host *host; 557c6fd2807SJeff Garzik int rc, port_no; 558c6fd2807SJeff Garzik 55906296a1eSJoe Perches ata_print_version_once(&pdev->dev, DRV_VERSION); 560c6fd2807SJeff Garzik 5614447d351STejun Heo /* alloc host */ 5624447d351STejun Heo host = ata_host_alloc_pinfo(&pdev->dev, ppi, QS_PORTS); 5634447d351STejun Heo if (!host) 5644447d351STejun Heo return -ENOMEM; 5654447d351STejun Heo 5664447d351STejun Heo /* acquire resources and fill host */ 56724dc5f33STejun Heo rc = pcim_enable_device(pdev); 568c6fd2807SJeff Garzik if (rc) 569c6fd2807SJeff Garzik return rc; 570c6fd2807SJeff Garzik 5710d5ff566STejun Heo if ((pci_resource_flags(pdev, QS_MMIO_BAR) & IORESOURCE_MEM) == 0) 57224dc5f33STejun Heo return -ENODEV; 573c6fd2807SJeff Garzik 5740d5ff566STejun Heo rc = pcim_iomap_regions(pdev, 1 << QS_MMIO_BAR, DRV_NAME); 5750d5ff566STejun Heo if (rc) 5760d5ff566STejun Heo return rc; 5774447d351STejun Heo host->iomap = pcim_iomap_table(pdev); 578c6fd2807SJeff Garzik 5794447d351STejun Heo rc = qs_set_dma_masks(pdev, host->iomap[QS_MMIO_BAR]); 580c6fd2807SJeff Garzik if (rc) 58124dc5f33STejun Heo return rc; 582c6fd2807SJeff Garzik 5834447d351STejun Heo for (port_no = 0; port_no < host->n_ports; ++port_no) { 584cbcdd875STejun Heo struct ata_port *ap = host->ports[port_no]; 585cbcdd875STejun Heo unsigned int offset = port_no * 0x4000; 586cbcdd875STejun Heo void __iomem *chan = host->iomap[QS_MMIO_BAR] + offset; 587cbcdd875STejun Heo 588cbcdd875STejun Heo qs_ata_setup_port(&ap->ioaddr, chan); 589cbcdd875STejun Heo 590cbcdd875STejun Heo ata_port_pbar_desc(ap, QS_MMIO_BAR, -1, "mmio"); 591cbcdd875STejun Heo ata_port_pbar_desc(ap, QS_MMIO_BAR, offset, "port"); 592c6fd2807SJeff Garzik } 593c6fd2807SJeff Garzik 594c6fd2807SJeff Garzik /* initialize adapter */ 5954447d351STejun Heo qs_host_init(host, board_idx); 596c6fd2807SJeff Garzik 5974447d351STejun Heo pci_set_master(pdev); 5984447d351STejun Heo return ata_host_activate(host, pdev->irq, qs_intr, IRQF_SHARED, 5994447d351STejun Heo &qs_ata_sht); 600c6fd2807SJeff Garzik } 601c6fd2807SJeff Garzik 6022fc75da0SAxel Lin module_pci_driver(qs_ata_pci_driver); 603c6fd2807SJeff Garzik 604c6fd2807SJeff Garzik MODULE_AUTHOR("Mark Lord"); 605c6fd2807SJeff Garzik MODULE_DESCRIPTION("Pacific Digital Corporation QStor SATA low-level driver"); 606c6fd2807SJeff Garzik MODULE_LICENSE("GPL"); 607c6fd2807SJeff Garzik MODULE_DEVICE_TABLE(pci, qs_ata_pci_tbl); 608c6fd2807SJeff Garzik MODULE_VERSION(DRV_VERSION); 609