On Mon, Aug 12, 2019 at 05:49:29PM +0000, Stephen Douthit wrote: > Does anyone know the background of the original PCS workaround? Based on a few git-blame iterations on history.git the original PCS handling (just when initializing) goes back to this BK commit: -- >From c0835b838e76c9500facad05dc305170a1a577a8 Mon Sep 17 00:00:00 2001 From: Jeff Garzik <jgarzik@xxxxxxxxx> Date: Thu, 14 Oct 2004 16:11:44 -0400 Subject: [libata ahci] fix several bugs * PCI IDs from test version didn't make it into mainline... doh * do all command setup in ->qc_prep * phy_reset routine that does signature check * check SATA phy for errors * reset hardware from scratch, in case card BIOS didn't run * implement staggered spinup by default * adding additional debugging output --- drivers/scsi/ahci.c | 150 ++++++++++++++++++++++++++++++++------------ 1 file changed, 109 insertions(+), 41 deletions(-) diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index e2fdeb8b857e..408ecc527b59 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -38,7 +38,7 @@ #include <asm/io.h> #define DRV_NAME "ahci" -#define DRV_VERSION "0.10" +#define DRV_VERSION "0.11" enum { @@ -52,6 +52,7 @@ enum { AHCI_PORT_PRIV_DMA_SZ = AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_SZ + AHCI_RX_FIS_SZ, AHCI_IRQ_ON_SG = (1 << 31), + AHCI_CMD_ATAPI = (1 << 5), AHCI_CMD_WRITE = (1 << 6), RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */ @@ -82,8 +83,10 @@ enum { PORT_IRQ_MASK = 0x14, /* interrupt enable/disable mask */ PORT_CMD = 0x18, /* port command */ PORT_TFDATA = 0x20, /* taskfile data */ + PORT_SIG = 0x24, /* device TF signature */ PORT_CMD_ISSUE = 0x38, /* command issue */ PORT_SCR = 0x28, /* SATA phy register block */ + PORT_SCR_STAT = 0x28, /* SATA phy register: SStatus */ PORT_SCR_CTL = 0x2c, /* SATA phy register: SControl */ PORT_SCR_ERR = 0x30, /* SATA phy register: SError */ @@ -161,9 +164,9 @@ struct ahci_port_priv { static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg); static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); -static void ahci_dma_setup(struct ata_queued_cmd *qc); -static void ahci_dma_start(struct ata_queued_cmd *qc); +static int ahci_qc_issue(struct ata_queued_cmd *qc); static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs); +static void ahci_phy_reset(struct ata_port *ap); static void ahci_irq_clear(struct ata_port *ap); static void ahci_eng_timeout(struct ata_port *ap); static int ahci_port_start(struct ata_port *ap); @@ -202,13 +205,12 @@ static struct ata_port_operations ahci_ops = { .tf_read = ahci_tf_read, .check_status = ahci_check_status, .exec_command = ahci_exec_command, + .dev_select = ata_noop_dev_select, - .phy_reset = sata_phy_reset, + .phy_reset = ahci_phy_reset, - .bmdma_setup = ahci_dma_setup, - .bmdma_start = ahci_dma_start, .qc_prep = ahci_qc_prep, - .qc_issue = ata_qc_issue_prot, + .qc_issue = ahci_qc_issue, .eng_timeout = ahci_eng_timeout, @@ -236,7 +238,9 @@ static struct ata_port_info ahci_port_info[] = { }; static struct pci_device_id ahci_pci_tbl[] = { - { PCI_VENDOR_ID_INTEL, 0x0000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + { PCI_VENDOR_ID_INTEL, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_ahci }, + { PCI_VENDOR_ID_INTEL, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_ahci }, { } /* terminate list */ }; @@ -292,6 +296,7 @@ static int ahci_port_start(struct ata_port *ap) rc = -ENOMEM; goto err_out_kfree; } + memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ); pp->rx_fis = mem; pp->rx_fis_dma = mem_dma; @@ -302,7 +307,7 @@ static int ahci_port_start(struct ata_port *ap) pp->cmd_tbl = mem; pp->cmd_tbl_dma = mem_dma; - mem2 = mem + 128; + mem2 = mem + 0x80; pp->cmd_tbl_sg = mem2; mem += AHCI_CMD_TBL_SZ; @@ -398,6 +403,29 @@ static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in, writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4)); } +static void ahci_phy_reset(struct ata_port *ap) +{ + void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; + struct ata_taskfile tf; + struct ata_device *dev = &ap->device[0]; + u32 tmp; + + __sata_phy_reset(ap); + + if (ap->flags & ATA_FLAG_PORT_DISABLED) + return; + + tmp = readl(port_mmio + PORT_SIG); + tf.lbah = (tmp >> 24) & 0xff; + tf.lbam = (tmp >> 16) & 0xff; + tf.lbal = (tmp >> 8) & 0xff; + tf.nsect = (tmp) & 0xff; + + dev->class = ata_dev_classify(&tf); + if (!ata_dev_present(dev)) + ata_port_disable(ap); +} + static u8 ahci_check_status(struct ata_port *ap) { void *mmio = (void *) ap->ioaddr.cmd_addr; @@ -424,7 +452,7 @@ static void ahci_fill_sg(struct ata_queued_cmd *qc) pp->cmd_tbl_sg[i].addr = cpu_to_le32(addr & 0xffffffff); pp->cmd_tbl_sg[i].addr_hi = cpu_to_le32((addr >> 16) >> 16); - pp->cmd_tbl_sg[i].flags_size = cpu_to_le32(sg_len); + pp->cmd_tbl_sg[i].flags_size = cpu_to_le32(sg_len - 1); } } @@ -442,6 +470,19 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) opts = (qc->n_elem << 16) | cmd_fis_len; if (qc->tf.flags & ATA_TFLAG_WRITE) opts |= AHCI_CMD_WRITE; + + switch (qc->tf.protocol) { + case ATA_PROT_ATAPI: + case ATA_PROT_ATAPI_NODATA: + case ATA_PROT_ATAPI_DMA: + opts |= AHCI_CMD_ATAPI; + break; + + default: + /* do nothing */ + break; + } + pp->cmd_slot->opts = cpu_to_le32(opts); pp->cmd_slot->status = 0; pp->cmd_slot->tbl_addr = cpu_to_le32(pp->cmd_tbl_dma & 0xffffffff); @@ -547,11 +588,12 @@ static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc) { void *mmio = ap->host_set->mmio_base; void *port_mmio = ahci_port_base(mmio, ap->port_no); - u32 status, ci; + u32 status, serr, ci; + + serr = readl(port_mmio + PORT_SCR_ERR); + writel(serr, port_mmio + PORT_SCR_ERR); status = readl(port_mmio + PORT_IRQ_STAT); - if (!status) - return 0; writel(status, port_mmio + PORT_IRQ_STAT); ci = readl(port_mmio + PORT_CMD_ISSUE); @@ -624,18 +666,15 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs * return IRQ_RETVAL(handled); } -static void ahci_dma_setup(struct ata_queued_cmd *qc) -{ - /* do nothing... for now */ -} - -static void ahci_dma_start(struct ata_queued_cmd *qc) +static int ahci_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; void *mmio = (void *) ap->ioaddr.cmd_addr; writel(1, mmio + PORT_CMD_ISSUE); readl(mmio + PORT_CMD_ISSUE); /* flush */ + + return 0; } static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf) @@ -663,20 +702,30 @@ static void ahci_exec_command(struct ata_port *ap, struct ata_taskfile *tf) static void ahci_setup_port(struct ata_ioports *port, unsigned long base, unsigned int port_idx) { + VPRINTK("ENTER, base==0x%lx, port_idx %u\n", base, port_idx); base = ahci_port_base_ul(base, port_idx); + VPRINTK("base now==0x%lx\n", base); port->cmd_addr = base; port->scr_addr = base + PORT_SCR; + + VPRINTK("EXIT\n"); } static int ahci_host_init(struct ata_probe_ent *probe_ent) { struct ahci_host_priv *hpriv = probe_ent->private_data; struct pci_dev *pdev = probe_ent->pdev; - void *mmio = probe_ent->mmio_base; - u32 tmp; - unsigned int i, using_dac; + void __iomem *mmio = probe_ent->mmio_base; + u32 tmp, cap_save; + u16 tmp16; + unsigned int i, j, using_dac; int rc; + void __iomem *port_mmio; + + cap_save = readl(mmio + HOST_CAP); + cap_save &= ( (1<<28) | (1<<17) ); + cap_save |= (1 << 27); /* global controller reset */ tmp = readl(mmio + HOST_CTL); @@ -698,23 +747,22 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) return -EIO; } - /* make sure we're in AHCI mode, with irq disabled */ - if ((tmp & (HOST_AHCI_EN | HOST_IRQ_EN)) != HOST_AHCI_EN) { - tmp |= HOST_AHCI_EN; - tmp &= ~HOST_IRQ_EN; - writel(tmp, mmio + HOST_CTL); - readl(mmio + HOST_CTL); /* flush */ - } - tmp = readl(mmio + HOST_CTL); - if ((tmp & (HOST_AHCI_EN | HOST_IRQ_EN)) != HOST_AHCI_EN) { - printk(KERN_ERR DRV_NAME "(%s): AHCI enable failed (0x%x)\n", - pci_name(pdev), tmp); - return -EIO; - } + writel(HOST_AHCI_EN, mmio + HOST_CTL); + (void) readl(mmio + HOST_CTL); /* flush */ + writel(cap_save, mmio + HOST_CAP); + writel(0xf, mmio + HOST_PORTS_IMPL); + (void) readl(mmio + HOST_PORTS_IMPL); /* flush */ + + pci_read_config_word(pdev, 0x92, &tmp16); + tmp16 |= 0xf; + pci_write_config_word(pdev, 0x92, tmp16); hpriv->cap = readl(mmio + HOST_CAP); hpriv->port_map = readl(mmio + HOST_PORTS_IMPL); - probe_ent->n_ports = hpriv->cap & 0x1f; + probe_ent->n_ports = (hpriv->cap & 0x1f) + 1; + + VPRINTK("cap 0x%x port_map 0x%x n_ports %d\n", + hpriv->cap, hpriv->port_map, probe_ent->n_ports); using_dac = hpriv->cap & HOST_CAP_64; if (using_dac && @@ -746,18 +794,18 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) } for (i = 0; i < probe_ent->n_ports; i++) { - void *port_mmio; - if (!(hpriv->port_map & (1 << i))) continue; port_mmio = ahci_port_base(mmio, i); + VPRINTK("mmio %p port_mmio %p\n", mmio, port_mmio); ahci_setup_port(&probe_ent->port[i], (unsigned long) mmio, i); /* make sure port is not active */ tmp = readl(port_mmio + PORT_CMD); + VPRINTK("PORT_CMD 0x%x\n", tmp); if (tmp & (PORT_CMD_LIST_ON | PORT_CMD_FIS_ON | PORT_CMD_FIS_RX | PORT_CMD_START)) { tmp &= ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON | @@ -772,14 +820,27 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) schedule_timeout((HZ / 2) + 1); } + writel(PORT_CMD_SPIN_UP, port_mmio + PORT_CMD); + + j = 0; + while (j < 100) { + msleep(10); + tmp = readl(port_mmio + PORT_SCR_STAT); + if ((tmp & 0xf) == 0x3) + break; + j++; + } + + tmp = readl(port_mmio + PORT_SCR_ERR); + VPRINTK("PORT_SCR_ERR 0x%x\n", tmp); + writel(tmp, port_mmio + PORT_SCR_ERR); + /* ack any pending irq events for this port */ tmp = readl(port_mmio + PORT_IRQ_STAT); + VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp); if (tmp) writel(tmp, port_mmio + PORT_IRQ_STAT); - tmp = readl(port_mmio + PORT_SCR_ERR); - writel(tmp, port_mmio + PORT_SCR_ERR); - writel(1 << i, mmio + HOST_IRQ_STAT); /* set irq mask (enables interrupts) */ @@ -787,7 +848,10 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) } tmp = readl(mmio + HOST_CTL); + VPRINTK("HOST_CTL 0x%x\n", tmp); writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL); + tmp = readl(mmio + HOST_CTL); + VPRINTK("HOST_CTL 0x%x\n", tmp); pci_set_master(pdev); @@ -830,10 +894,12 @@ static void ahci_print_info(struct ata_probe_ent *probe_ent) "%u slots %u ports %s Gbps 0x%x impl\n" , pci_name(pdev), + (vers >> 24) & 0xff, (vers >> 16) & 0xff, (vers >> 8) & 0xff, vers & 0xff, + ((cap >> 8) & 0x1f) + 1, (cap & 0x1f) + 1, speed_s, @@ -872,6 +938,8 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) unsigned int board_idx = (unsigned int) ent->driver_data; int rc; + VPRINTK("ENTER\n"); + if (!printed_version++) printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); -- 2.20.1