summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2004-02-25 18:16:29 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-02-25 18:16:29 -0800
commit90d2aee3a04cb13dfcab7d37624ffa32025eda1c (patch)
treeb6f46bffe450b44f373048314fe45b7cdc64235f
parent7265df88a1fc37644ea0b4dddcc8ce4f9b227ee4 (diff)
parent333f957c3d5259337b859d3d413d805450ddcc9a (diff)
Merge bk://gkernel.bkbits.net/libata-2.5
into ppc970.osdl.org:/home/torvalds/v2.5/linux
-rw-r--r--drivers/scsi/libata-core.c77
-rw-r--r--drivers/scsi/libata-scsi.c1
-rw-r--r--drivers/scsi/libata.h2
-rw-r--r--drivers/scsi/sata_promise.c60
-rw-r--r--drivers/scsi/sata_sil.c37
5 files changed, 119 insertions, 58 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 3009f8ab6a7f..5c5211c42fd6 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1,8 +1,8 @@
/*
libata-core.c - helper library for ATA
- Copyright 2003 Red Hat, Inc. All rights reserved.
- Copyright 2003 Jeff Garzik
+ Copyright 2003-2004 Red Hat, Inc. All rights reserved.
+ Copyright 2003-2004 Jeff Garzik
The contents of this file are subject to the Open
Software License version 1.1 that can be found at
@@ -1653,18 +1653,41 @@ void ata_fill_sg(struct ata_queued_cmd *qc)
{
struct scatterlist *sg = qc->sg;
struct ata_port *ap = qc->ap;
- unsigned int i;
+ unsigned int idx, nelem;
assert(sg != NULL);
assert(qc->n_elem > 0);
- for (i = 0; i < qc->n_elem; i++) {
- ap->prd[i].addr = cpu_to_le32(sg_dma_address(&sg[i]));
- ap->prd[i].flags_len = cpu_to_le32(sg_dma_len(&sg[i]));
- VPRINTK("PRD[%u] = (0x%X, 0x%X)\n",
- i, le32_to_cpu(ap->prd[i].addr), le32_to_cpu(ap->prd[i].flags_len));
+ idx = 0;
+ for (nelem = qc->n_elem; nelem; nelem--,sg++) {
+ u32 addr, boundary;
+ u32 sg_len, len;
+
+ /* determine if physical DMA addr spans 64K boundary.
+ * Note h/w doesn't support 64-bit, so we unconditionally
+ * truncate dma_addr_t to u32.
+ */
+ addr = (u32) sg_dma_address(sg);
+ sg_len = sg_dma_len(sg);
+
+ while (sg_len) {
+ boundary = (addr & ~0xffff) + (0xffff + 1);
+ len = sg_len;
+ if ((addr + sg_len) > boundary)
+ len = boundary - addr;
+
+ ap->prd[idx].addr = cpu_to_le32(addr);
+ ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff);
+ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
+
+ idx++;
+ sg_len -= len;
+ addr += len;
+ }
}
- ap->prd[qc->n_elem - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+
+ if (idx)
+ ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
}
/**
@@ -2386,41 +2409,6 @@ static inline unsigned int ata_host_intr (struct ata_port *ap,
}
/**
- * ata_chk_spurious_int - Check for spurious interrupts
- * @ap: port to which command is being issued
- *
- * Examines the DMA status registers and clears
- * unexpected interrupts. Created to work around
- * hardware bug on Intel ICH5, but is applied to all
- * chipsets using the standard irq handler, just for safety.
- * If the bug is not present, this is simply a single
- * PIO or MMIO read addition to the irq handler.
- *
- * LOCKING:
- */
-static inline void ata_chk_spurious_int(struct ata_port *ap) {
- int host_stat;
-
- if (ap->flags & ATA_FLAG_MMIO) {
- void *mmio = (void *) ap->ioaddr.bmdma_addr;
- host_stat = readb(mmio + ATA_DMA_STATUS);
- } else
- host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
-
- if ((host_stat & (ATA_DMA_INTR | ATA_DMA_ERR | ATA_DMA_ACTIVE)) == ATA_DMA_INTR) {
- if (ap->flags & ATA_FLAG_MMIO) {
- void *mmio = (void *) ap->ioaddr.bmdma_addr;
- writeb(host_stat & ~ATA_DMA_ERR, mmio + ATA_DMA_STATUS);
- } else
- outb(host_stat & ~ATA_DMA_ERR, ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
-
- DPRINTK("ata%u: Caught spurious interrupt, status 0x%X\n", ap->id, host_stat);
- udelay(1);
- }
-}
-
-
-/**
* ata_interrupt -
* @irq:
* @dev_instance:
@@ -2452,7 +2440,6 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
qc = ata_qc_from_tag(ap, ap->active_tag);
if (qc && ((qc->flags & ATA_QCFLAG_POLL) == 0))
handled += ata_host_intr(ap, qc);
- ata_chk_spurious_int(ap);
}
}
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index ff01a69d8182..5b28a33a4f5c 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -123,6 +123,7 @@ int ata_scsi_slave_config(struct scsi_device *sdev)
{
sdev->use_10_for_rw = 1;
sdev->use_10_for_ms = 1;
+ blk_queue_max_phys_segments(sdev->request_queue, ATA_MAX_PRD / 2);
return 0; /* scsi layer doesn't check return value, sigh */
}
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index 79db90a501ac..5046ddfb9db1 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -26,7 +26,7 @@
#define __LIBATA_H__
#define DRV_NAME "libata"
-#define DRV_VERSION "1.00" /* must be exactly four chars */
+#define DRV_VERSION "1.01" /* must be exactly four chars */
struct ata_scsi_args {
struct ata_port *ap;
diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
index 014c825bf033..1293a3a90049 100644
--- a/drivers/scsi/sata_promise.c
+++ b/drivers/scsi/sata_promise.c
@@ -35,7 +35,7 @@
#include <asm/io.h>
#define DRV_NAME "sata_promise"
-#define DRV_VERSION "0.89"
+#define DRV_VERSION "0.90"
enum {
@@ -115,7 +115,12 @@ enum {
PDC_DIMM_SPD_SYSTEM_FREQ = 126,
PDC_CTL_STATUS = 0x08,
PDC_DIMM_WINDOW_CTLR = 0x0C,
+ PDC_TIME_CONTROL = 0x3C,
+ PDC_TIME_PERIOD = 0x40,
+ PDC_TIME_COUNTER = 0x44,
PDC_GENERAL_CTLR = 0x484,
+ PCI_PLL_INIT = 0x8A531824,
+ PCI_X_TCOUNT = 0xEE1E5CFF
};
@@ -1454,13 +1459,64 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
int speed, size, length;
u32 addr,spd0,pci_status;
u32 tmp=0;
+ u32 time_period=0;
+ u32 tcount=0;
+ u32 ticks=0;
+ u32 clock=0;
+ u32 fparam=0;
void *mmio = pe->mmio_base;
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
+ /* Initialize PLL based upon PCI Bus Frequency */
+
+ /* Initialize Time Period Register */
+ writel(0xffffffff, mmio + PDC_TIME_PERIOD);
+ time_period = readl(mmio + PDC_TIME_PERIOD);
+ VPRINTK("Time Period Register (0x40): 0x%x\n", time_period);
+
+ /* Enable timer */
+ writel(0x00001a0, mmio + PDC_TIME_CONTROL);
+ readl(mmio + PDC_TIME_CONTROL);
+
+ /* Wait 3 seconds */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(3 * HZ);
+
+ /*
+ When timer is enabled, counter is decreased every internal
+ clock cycle.
+ */
+
+ tcount = readl(mmio + PDC_TIME_COUNTER);
+ VPRINTK("Time Counter Register (0x44): 0x%x\n", tcount);
+
+ /*
+ If SX4 is on PCI-X bus, after 3 seconds, the timer counter
+ register should be >= (0xffffffff - 3x10^8).
+ */
+ if(tcount >= PCI_X_TCOUNT) {
+ ticks = (time_period - tcount);
+ VPRINTK("Num counters 0x%x (%d)\n", ticks, ticks);
+
+ clock = (ticks / 300000);
+ VPRINTK("10 * Internal clk = 0x%x (%d)\n", clock, clock);
+
+ clock = (clock * 33);
+ VPRINTK("10 * Internal clk * 33 = 0x%x (%d)\n", clock, clock);
+
+ /* PLL F Param (bit 22:16) */
+ fparam = (1400000 / clock) - 2;
+ VPRINTK("PLL F Param: 0x%x (%d)\n", fparam, fparam);
+
+ /* OD param = 0x2 (bit 31:30), R param = 0x5 (bit 29:25) */
+ pci_status = (0x8a001824 | (fparam << 16));
+ } else
+ pci_status = PCI_PLL_INIT;
+
/* Initialize PLL. */
- pci_status = 0x8a531824;
+ VPRINTK("pci_status: 0x%x\n", pci_status);
writel(pci_status, mmio + PDC_CTL_STATUS);
readl(mmio + PDC_CTL_STATUS);
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
index f42569be4890..ae14cbbea3fe 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/scsi/sata_sil.c
@@ -35,7 +35,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_sil"
-#define DRV_VERSION "0.52"
+#define DRV_VERSION "0.53"
enum {
sil_3112 = 0,
@@ -44,6 +44,11 @@ enum {
SIL_SYSCFG = 0x48,
SIL_MASK_IDE0_INT = (1 << 22),
SIL_MASK_IDE1_INT = (1 << 23),
+ SIL_MASK_IDE2_INT = (1 << 24),
+ SIL_MASK_IDE3_INT = (1 << 25),
+ SIL_MASK_2PORT = SIL_MASK_IDE0_INT | SIL_MASK_IDE1_INT,
+ SIL_MASK_4PORT = SIL_MASK_2PORT |
+ SIL_MASK_IDE2_INT | SIL_MASK_IDE3_INT,
SIL_IDE0_TF = 0x80,
SIL_IDE0_CTL = 0x8A,
@@ -59,6 +64,7 @@ enum {
SIL_IDE2_CTL = 0x28A,
SIL_IDE2_BMDMA = 0x200,
SIL_IDE2_SCR = 0x300,
+ SIL_INTR_STEERING = (1 << 1),
SIL_IDE3_TF = 0x2C0,
SIL_IDE3_CTL = 0x2CA,
@@ -304,7 +310,7 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
unsigned long base;
void *mmio_base;
int rc;
- u32 tmp;
+ u32 tmp, irq_mask;
if (!printed_version++)
printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
@@ -365,14 +371,6 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
probe_ent->port[1].scr_addr = base + SIL_IDE1_SCR;
ata_std_ports(&probe_ent->port[1]);
- /* make sure IDE0/1 interrupts are not masked */
- tmp = readl(mmio_base + SIL_SYSCFG);
- if (tmp & (SIL_MASK_IDE0_INT | SIL_MASK_IDE1_INT)) {
- tmp &= ~(SIL_MASK_IDE0_INT | SIL_MASK_IDE1_INT);
- writel(tmp, mmio_base + SIL_SYSCFG);
- readl(mmio_base + SIL_SYSCFG); /* flush */
- }
-
if (ent->driver_data == sil_3114) {
probe_ent->port[2].cmd_addr = base + SIL_IDE2_TF;
probe_ent->port[2].ctl_addr = base + SIL_IDE2_CTL;
@@ -385,6 +383,25 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
probe_ent->port[3].bmdma_addr = base + SIL_IDE3_BMDMA;
probe_ent->port[3].scr_addr = base + SIL_IDE3_SCR;
ata_std_ports(&probe_ent->port[3]);
+
+ irq_mask = SIL_MASK_4PORT;
+
+ /* flip the magic "make 4 ports work" bit */
+ tmp = readl(mmio_base + SIL_IDE2_BMDMA);
+ if ((tmp & SIL_INTR_STEERING) == 0)
+ writel(tmp | SIL_INTR_STEERING,
+ mmio_base + SIL_IDE2_BMDMA);
+
+ } else {
+ irq_mask = SIL_MASK_2PORT;
+ }
+
+ /* make sure IDE0/1/2/3 interrupts are not masked */
+ tmp = readl(mmio_base + SIL_SYSCFG);
+ if (tmp & irq_mask) {
+ tmp &= ~irq_mask;
+ writel(tmp, mmio_base + SIL_SYSCFG);
+ readl(mmio_base + SIL_SYSCFG); /* flush */
}
pci_set_master(pdev);