* [PATCHSET] sata_inic162x: make it work
@ 2008-04-30 7:35 Tejun Heo
2008-04-30 7:35 ` [PATCH 01/10] sata_inic162x: misc clean ups Tejun Heo
` (10 more replies)
0 siblings, 11 replies; 14+ messages in thread
From: Tejun Heo @ 2008-04-30 7:35 UTC (permalink / raw)
To: jeff, alan, linux-ide
Hello, Jeff, Alan.
Initio took the sata_inic162x driver, implemented ATA_PROT_DMA using
IDMA, renamed it to sata_initio162x and posted on their website. It
didn't work very well for me but contained enough hint on how to use
IDMA mode.
So, this is the patchset to make sata_inic162x to use IDMA for
everything including ATAPIs. There are still some issues - result TF
is not accessible, !read ATAPI commands should be issued using
ATAPI_PROT_PIO, but overall, everything including suspend/resume,
hotplug and burning cd/dvds works nicely.
Thanks.
--
tejun
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 01/10] sata_inic162x: misc clean ups
2008-04-30 7:35 [PATCHSET] sata_inic162x: make it work Tejun Heo
@ 2008-04-30 7:35 ` Tejun Heo
2008-05-06 14:08 ` Jeff Garzik
2008-04-30 7:35 ` [PATCH 02/10] sata_inic162x: add / update constants Tejun Heo
` (9 subsequent siblings)
10 siblings, 1 reply; 14+ messages in thread
From: Tejun Heo @ 2008-04-30 7:35 UTC (permalink / raw)
To: jeff, alan, linux-ide; +Cc: Tejun Heo
* use larger indents for structure member definitions
* kill unused variable @addr in inic_scr_write()
* kill unnecessary flushes in inic_freeze/thaw()
* kill buggy explicit kfree() on devres managed port private data
This is in preparation of further inic162x updates.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/sata_inic162x.c | 18 +++++-------------
1 files changed, 5 insertions(+), 13 deletions(-)
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index d27bb9a..1f5d17e 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -99,13 +99,13 @@ enum {
};
struct inic_host_priv {
- u16 cached_hctl;
+ u16 cached_hctl;
};
struct inic_port_priv {
- u8 dfl_prdctl;
- u8 cached_prdctl;
- u8 cached_pirq_mask;
+ u8 dfl_prdctl;
+ u8 cached_prdctl;
+ u8 cached_pirq_mask;
};
static struct scsi_host_template inic_sht = {
@@ -185,12 +185,10 @@ static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
static int inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
{
void __iomem *scr_addr = ap->ioaddr.scr_addr;
- void __iomem *addr;
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
return -EINVAL;
- addr = scr_addr + scr_map[sc_reg] * 4;
writel(val, scr_addr + scr_map[sc_reg] * 4);
return 0;
}
@@ -367,8 +365,6 @@ static void inic_freeze(struct ata_port *ap)
ap->ops->sff_check_status(ap);
writeb(0xff, port_base + PORT_IRQ_STAT);
-
- readb(port_base + PORT_IRQ_STAT); /* flush */
}
static void inic_thaw(struct ata_port *ap)
@@ -379,8 +375,6 @@ static void inic_thaw(struct ata_port *ap)
writeb(0xff, port_base + PORT_IRQ_STAT);
__inic_set_pirq_mask(ap, PIRQ_MASK_OTHER);
-
- readb(port_base + PORT_IRQ_STAT); /* flush */
}
/*
@@ -506,10 +500,8 @@ static int inic_port_start(struct ata_port *ap)
/* Alloc resources */
rc = ata_port_start(ap);
- if (rc) {
- kfree(pp);
+ if (rc)
return rc;
- }
init_port(ap);
--
1.5.2.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 02/10] sata_inic162x: add / update constants
2008-04-30 7:35 [PATCHSET] sata_inic162x: make it work Tejun Heo
2008-04-30 7:35 ` [PATCH 01/10] sata_inic162x: misc clean ups Tejun Heo
@ 2008-04-30 7:35 ` Tejun Heo
2008-04-30 7:35 ` [PATCH 03/10] sata_inic162x: update TF read handling Tejun Heo
` (8 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2008-04-30 7:35 UTC (permalink / raw)
To: jeff, alan, linux-ide; +Cc: Tejun Heo
* add a bunch of constants, most are from the datasheet, a few
undocumented ones are from initio's modified driver
* HCTL_PWRDWN is bit 12 not 13
This is in preparation of further inic162x updates.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/sata_inic162x.c | 59 ++++++++++++++++++++++++++++++++++++++++--
1 files changed, 56 insertions(+), 3 deletions(-)
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index 1f5d17e..1b10455 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -35,6 +35,7 @@ enum {
NR_PORTS = 2,
+ HOST_ACTRL = 0x08,
HOST_CTL = 0x7c,
HOST_STAT = 0x7e,
HOST_IRQ_STAT = 0xbc,
@@ -43,22 +44,37 @@ enum {
PORT_SIZE = 0x40,
/* registers for ATA TF operation */
- PORT_TF = 0x00,
- PORT_ALT_STAT = 0x08,
+ PORT_TF_DATA = 0x00,
+ PORT_TF_FEATURE = 0x01,
+ PORT_TF_NSECT = 0x02,
+ PORT_TF_LBAL = 0x03,
+ PORT_TF_LBAM = 0x04,
+ PORT_TF_LBAH = 0x05,
+ PORT_TF_DEVICE = 0x06,
+ PORT_TF_COMMAND = 0x07,
+ PORT_TF_ALT_STAT = 0x08,
PORT_IRQ_STAT = 0x09,
PORT_IRQ_MASK = 0x0a,
PORT_PRD_CTL = 0x0b,
PORT_PRD_ADDR = 0x0c,
PORT_PRD_XFERLEN = 0x10,
+ PORT_CPB_CPBLAR = 0x18,
+ PORT_CPB_PTQFIFO = 0x1c,
/* IDMA register */
PORT_IDMA_CTL = 0x14,
+ PORT_IDMA_STAT = 0x16,
+
+ PORT_RPQ_FIFO = 0x1e,
+ PORT_RPQ_CNT = 0x1f,
PORT_SCR = 0x20,
/* HOST_CTL bits */
HCTL_IRQOFF = (1 << 8), /* global IRQ off */
- HCTL_PWRDWN = (1 << 13), /* power down PHYs */
+ HCTL_FTHD0 = (1 << 10), /* fifo threshold 0 */
+ HCTL_FTHD1 = (1 << 11), /* fifo threshold 1*/
+ HCTL_PWRDWN = (1 << 12), /* power down PHYs */
HCTL_SOFTRST = (1 << 13), /* global reset (no phy reset) */
HCTL_RPGSEL = (1 << 15), /* register page select */
@@ -96,6 +112,43 @@ enum {
IDMA_CTL_RST_IDMA = (1 << 5), /* reset IDMA machinary */
IDMA_CTL_GO = (1 << 7), /* IDMA mode go */
IDMA_CTL_ATA_NIEN = (1 << 8), /* ATA IRQ disable */
+
+ /* PORT_IDMA_STAT bits */
+ IDMA_STAT_PERR = (1 << 0), /* PCI ERROR MODE */
+ IDMA_STAT_CPBERR = (1 << 1), /* ADMA CPB error */
+ IDMA_STAT_LGCY = (1 << 3), /* ADMA legacy */
+ IDMA_STAT_UIRQ = (1 << 4), /* ADMA unsolicited irq */
+ IDMA_STAT_STPD = (1 << 5), /* ADMA stopped */
+ IDMA_STAT_PSD = (1 << 6), /* ADMA pause */
+ IDMA_STAT_DONE = (1 << 7), /* ADMA done */
+
+ IDMA_STAT_ERR = IDMA_STAT_PERR | IDMA_STAT_CPBERR,
+
+ /* CPB Control Flags*/
+ CPB_CTL_VALID = (1 << 0), /* CPB valid */
+ CPB_CTL_QUEUED = (1 << 1), /* queued command */
+ CPB_CTL_DATA = (1 << 2), /* data, rsvd in datasheet */
+ CPB_CTL_IEN = (1 << 3), /* PCI interrupt enable */
+ CPB_CTL_DEVDIR = (1 << 4), /* device direction control */
+
+ /* CPB Response Flags */
+ CPB_RESP_DONE = (1 << 0), /* ATA command complete */
+ CPB_RESP_REL = (1 << 1), /* ATA release */
+ CPB_RESP_IGNORED = (1 << 2), /* CPB ignored */
+ CPB_RESP_ATA_ERR = (1 << 3), /* ATA command error */
+ CPB_RESP_SPURIOUS = (1 << 4), /* ATA spurious interrupt error */
+ CPB_RESP_UNDERFLOW = (1 << 5), /* APRD deficiency length error */
+ CPB_RESP_OVERFLOW = (1 << 6), /* APRD exccess length error */
+ CPB_RESP_CPB_ERR = (1 << 7), /* CPB error flag */
+
+ /* PRD Control Flags */
+ PRD_DRAIN = (1 << 1), /* ignore data excess */
+ PRD_CDB = (1 << 2), /* atapi packet command pointer */
+ PRD_DIRECT_INTR = (1 << 3), /* direct interrupt */
+ PRD_DMA = (1 << 4), /* data transfer method */
+ PRD_WRITE = (1 << 5), /* data dir, rsvd in datasheet */
+ PRD_IOM = (1 << 6), /* io/memory transfer */
+ PRD_END = (1 << 7), /* APRD chain end */
};
struct inic_host_priv {
--
1.5.2.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 03/10] sata_inic162x: update TF read handling
2008-04-30 7:35 [PATCHSET] sata_inic162x: make it work Tejun Heo
2008-04-30 7:35 ` [PATCH 01/10] sata_inic162x: misc clean ups Tejun Heo
2008-04-30 7:35 ` [PATCH 02/10] sata_inic162x: add / update constants Tejun Heo
@ 2008-04-30 7:35 ` Tejun Heo
2008-05-01 14:55 ` [PATCH 03/10 UPDATED] " Tejun Heo
2008-04-30 7:35 ` [PATCH 04/10] sata_inic162x: use IDMA for ATA_PROT_DMA Tejun Heo
` (7 subsequent siblings)
10 siblings, 1 reply; 14+ messages in thread
From: Tejun Heo @ 2008-04-30 7:35 UTC (permalink / raw)
To: jeff, alan, linux-ide; +Cc: Tejun Heo
inic162x can't reliably read back TF or at least we don't know how to
do it yet. The only values which seem reliable are status and error.
This patch updates access to TF.
* implement inic_tf_read() which reads the TF area in mmio area
* implement custom inic_qc_fill_rtf() which only returns true if
status indicates device error. it'll be returning bogus addresses
for device errors but it'll be able to report why it failed at
least.
* implement custom inic_check_ready() and use ata_wait_after_reset()
instead of the SFF version.
* use inic_tf_read() for classification && assume ATA if class is
invalid when link is online.
This is not perfect but it fixes hotplug detection failure and at
least makes the driver report 0's instead of random garbages while
reporting valid status and error for device errors.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/sata_inic162x.c | 53 +++++++++++++++++++++++++++++++++++++++++-
1 files changed, 51 insertions(+), 2 deletions(-)
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index 1b10455..db669f2 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -410,6 +410,41 @@ static unsigned int inic_qc_issue(struct ata_queued_cmd *qc)
return ata_sff_qc_issue(qc);
}
+static void inic_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ void __iomem *port_base = inic_port_base(ap);
+
+ tf->feature = readb(port_base + PORT_TF_FEATURE);
+ tf->nsect = readb(port_base + PORT_TF_NSECT);
+ tf->lbal = readb(port_base + PORT_TF_LBAL);
+ tf->lbam = readb(port_base + PORT_TF_LBAM);
+ tf->lbah = readb(port_base + PORT_TF_LBAH);
+ tf->device = readb(port_base + PORT_TF_DEVICE);
+ tf->command = readb(port_base + PORT_TF_COMMAND);
+}
+
+static bool inic_qc_fill_rtf(struct ata_queued_cmd *qc)
+{
+ struct ata_taskfile *rtf = &qc->result_tf;
+ struct ata_taskfile tf;
+
+ /* FIXME: Except for status and error, result TF access
+ * doesn't work. I tried reading from BAR0/2, CPB and BAR5.
+ * None works regardless of which command interface is used.
+ * For now return true iff status indicates device error.
+ * This means that we're reporting bogus sector for RW
+ * failures. Eeekk....
+ */
+ inic_tf_read(qc->ap, &tf);
+
+ if (!(tf.command & ATA_ERR))
+ return false;
+
+ rtf->command = tf.command;
+ rtf->feature = tf.feature;
+ return true;
+}
+
static void inic_freeze(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
@@ -430,6 +465,13 @@ static void inic_thaw(struct ata_port *ap)
__inic_set_pirq_mask(ap, PIRQ_MASK_OTHER);
}
+static int inic_check_ready(struct ata_link *link)
+{
+ void __iomem *port_base = inic_port_base(link->ap);
+
+ return !(readb(port_base + PORT_TF_COMMAND) & ATA_BUSY);
+}
+
/*
* SRST and SControl hardreset don't give valid signature on this
* controller. Only controller specific hardreset mechanism works.
@@ -465,7 +507,7 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
struct ata_taskfile tf;
/* wait for link to become ready */
- rc = ata_sff_wait_after_reset(link, 1, deadline);
+ rc = ata_wait_after_reset(link, deadline, inic_check_ready);
/* link occupied, -ENODEV too is an error */
if (rc) {
ata_link_printk(link, KERN_WARNING, "device not ready "
@@ -473,8 +515,14 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
return rc;
}
- ata_sff_tf_read(ap, &tf);
+ inic_tf_read(ap, &tf);
*class = ata_dev_classify(&tf);
+
+ /* Signature sometimes isn't reliable after hotplug,
+ * assume ATA if signature is invalid.
+ */
+ if (!ata_class_enabled(*class))
+ *class = ATA_DEV_ATA;
}
return 0;
@@ -569,6 +617,7 @@ static struct ata_port_operations inic_port_ops = {
.bmdma_stop = inic_bmdma_stop,
.bmdma_status = inic_bmdma_status,
.qc_issue = inic_qc_issue,
+ .qc_fill_rtf = inic_qc_fill_rtf,
.freeze = inic_freeze,
.thaw = inic_thaw,
--
1.5.2.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 04/10] sata_inic162x: use IDMA for ATA_PROT_DMA
2008-04-30 7:35 [PATCHSET] sata_inic162x: make it work Tejun Heo
` (2 preceding siblings ...)
2008-04-30 7:35 ` [PATCH 03/10] sata_inic162x: update TF read handling Tejun Heo
@ 2008-04-30 7:35 ` Tejun Heo
2008-04-30 7:35 ` [PATCH 05/10] sata_inic162x: kill now unused bmdma related stuff Tejun Heo
` (6 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2008-04-30 7:35 UTC (permalink / raw)
To: jeff, alan, linux-ide; +Cc: Tejun Heo
The modified driver on initio site has enough clue on how to use IDMA.
Use IDMA for ATA_PROT_DMA.
* LBA48 now works as long as it uses DMA (LBA48 devices still aren't
allowed as it can destroy data if PIO is used for any reason).
* No need to mask IRQs for read DMAs as IDMA_DONE is properly raised
after transfer to memory is actually completed. There will be some
spurious interrupts but host_intr will handle it correctly and
manipulating port IRQ mask interacts badly with the other port for
some reason, so command type dependent port IRQ masking is not used
anymore.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/sata_inic162x.c | 270 +++++++++++++++++++++++++++++++++++++------
1 files changed, 235 insertions(+), 35 deletions(-)
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index db669f2..1f105fe 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -35,6 +35,10 @@ enum {
NR_PORTS = 2,
+ IDMA_CPB_TBL_SIZE = 4 * 32,
+
+ INIC_DMA_BOUNDARY = 0xffffff,
+
HOST_ACTRL = 0x08,
HOST_CTL = 0x7c,
HOST_STAT = 0x7e,
@@ -151,11 +155,57 @@ enum {
PRD_END = (1 << 7), /* APRD chain end */
};
+/* Comman Parameter Block */
+struct inic_cpb {
+ u8 resp_flags; /* Response Flags */
+ u8 error; /* ATA Error */
+ u8 status; /* ATA Status */
+ u8 ctl_flags; /* Control Flags */
+ __le32 len; /* Total Transfer Length */
+ __le32 prd; /* First PRD pointer */
+ u8 rsvd[4];
+ /* 16 bytes */
+ u8 feature; /* ATA Feature */
+ u8 hob_feature; /* ATA Ex. Feature */
+ u8 device; /* ATA Device/Head */
+ u8 mirctl; /* Mirror Control */
+ u8 nsect; /* ATA Sector Count */
+ u8 hob_nsect; /* ATA Ex. Sector Count */
+ u8 lbal; /* ATA Sector Number */
+ u8 hob_lbal; /* ATA Ex. Sector Number */
+ u8 lbam; /* ATA Cylinder Low */
+ u8 hob_lbam; /* ATA Ex. Cylinder Low */
+ u8 lbah; /* ATA Cylinder High */
+ u8 hob_lbah; /* ATA Ex. Cylinder High */
+ u8 command; /* ATA Command */
+ u8 ctl; /* ATA Control */
+ u8 slave_error; /* Slave ATA Error */
+ u8 slave_status; /* Slave ATA Status */
+ /* 32 bytes */
+} __packed;
+
+/* Physical Region Descriptor */
+struct inic_prd {
+ __le32 mad; /* Physical Memory Address */
+ __le16 len; /* Transfer Length */
+ u8 rsvd;
+ u8 flags; /* Control Flags */
+} __packed;
+
+struct inic_pkt {
+ struct inic_cpb cpb;
+ struct inic_prd prd[LIBATA_MAX_PRD];
+} __packed;
+
struct inic_host_priv {
u16 cached_hctl;
};
struct inic_port_priv {
+ struct inic_pkt *pkt;
+ dma_addr_t pkt_dma;
+ u32 *cpb_tbl;
+ dma_addr_t cpb_tbl_dma;
u8 dfl_prdctl;
u8 cached_prdctl;
u8 cached_pirq_mask;
@@ -163,6 +213,7 @@ struct inic_port_priv {
static struct scsi_host_template inic_sht = {
ATA_BMDMA_SHT(DRV_NAME),
+ .dma_boundary = INIC_DMA_BOUNDARY,
};
static const int scr_map[] = {
@@ -303,42 +354,112 @@ static u8 inic_bmdma_status(struct ata_port *ap)
return ATA_DMA_INTR;
}
-static void inic_host_intr(struct ata_port *ap)
+static void inic_stop_idma(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
+
+ readb(port_base + PORT_RPQ_FIFO);
+ readb(port_base + PORT_RPQ_CNT);
+ writew(0, port_base + PORT_IDMA_CTL);
+}
+
+static void inic_host_err_intr(struct ata_port *ap, u8 irq_stat, u16 idma_stat)
+{
struct ata_eh_info *ehi = &ap->link.eh_info;
+ struct inic_port_priv *pp = ap->private_data;
+ struct inic_cpb *cpb = &pp->pkt->cpb;
+ bool freeze = false;
+
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "irq_stat=0x%x idma_stat=0x%x",
+ irq_stat, idma_stat);
+
+ inic_stop_idma(ap);
+
+ if (irq_stat & (PIRQ_OFFLINE | PIRQ_ONLINE)) {
+ ata_ehi_push_desc(ehi, "hotplug");
+ ata_ehi_hotplugged(ehi);
+ freeze = true;
+ }
+
+ if (idma_stat & IDMA_STAT_PERR) {
+ ata_ehi_push_desc(ehi, "PCI error");
+ freeze = true;
+ }
+
+ if (idma_stat & IDMA_STAT_CPBERR) {
+ ata_ehi_push_desc(ehi, "CPB error");
+
+ if (cpb->resp_flags & CPB_RESP_IGNORED) {
+ __ata_ehi_push_desc(ehi, " ignored");
+ ehi->err_mask |= AC_ERR_INVALID;
+ freeze = true;
+ }
+
+ if (cpb->resp_flags & CPB_RESP_ATA_ERR)
+ ehi->err_mask |= AC_ERR_DEV;
+
+ if (cpb->resp_flags & CPB_RESP_SPURIOUS) {
+ __ata_ehi_push_desc(ehi, " spurious-intr");
+ ehi->err_mask |= AC_ERR_HSM;
+ freeze = true;
+ }
+
+ if (cpb->resp_flags &
+ (CPB_RESP_UNDERFLOW | CPB_RESP_OVERFLOW)) {
+ __ata_ehi_push_desc(ehi, " data-over/underflow");
+ ehi->err_mask |= AC_ERR_HSM;
+ freeze = true;
+ }
+ }
+
+ if (freeze)
+ ata_port_freeze(ap);
+ else
+ ata_port_abort(ap);
+}
+
+static void inic_host_intr(struct ata_port *ap)
+{
+ void __iomem *port_base = inic_port_base(ap);
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
u8 irq_stat;
+ u16 idma_stat;
- /* fetch and clear irq */
+ /* read and clear IRQ status */
irq_stat = readb(port_base + PORT_IRQ_STAT);
writeb(irq_stat, port_base + PORT_IRQ_STAT);
+ idma_stat = readw(port_base + PORT_IDMA_STAT);
+
+ if (unlikely((irq_stat & PIRQ_ERR) || (idma_stat & IDMA_STAT_ERR)))
+ inic_host_err_intr(ap, irq_stat, idma_stat);
+
+ if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
+ ap->ops->sff_check_status(ap); /* clear ATA interrupt */
+ goto spurious;
+ }
+
+ if (qc->tf.protocol == ATA_PROT_DMA) {
+ if (likely(idma_stat & IDMA_STAT_DONE)) {
+ inic_stop_idma(ap);
- if (likely(!(irq_stat & PIRQ_ERR))) {
- struct ata_queued_cmd *qc =
- ata_qc_from_tag(ap, ap->link.active_tag);
+ /* Depending on circumstances, device error
+ * isn't reported by IDMA, check it explicitly.
+ */
+ if (unlikely(readb(port_base + PORT_TF_COMMAND) &
+ (ATA_DF | ATA_ERR)))
+ qc->err_mask |= AC_ERR_DEV;
- if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
- ap->ops->sff_check_status(ap); /* clear ATA interrupt */
+ ata_qc_complete(qc);
return;
}
-
+ } else {
if (likely(ata_sff_host_intr(ap, qc)))
return;
-
- ap->ops->sff_check_status(ap); /* clear ATA interrupt */
- ata_port_printk(ap, KERN_WARNING, "unhandled "
- "interrupt, irq_stat=%x\n", irq_stat);
- return;
}
- /* error */
- ata_ehi_push_desc(ehi, "irq_stat=0x%x", irq_stat);
-
- if (irq_stat & (PIRQ_OFFLINE | PIRQ_ONLINE)) {
- ata_ehi_hotplugged(ehi);
- ata_port_freeze(ap);
- } else
- ata_port_abort(ap);
+ spurious:
+ ap->ops->sff_check_status(ap); /* clear ATA interrupt */
}
static irqreturn_t inic_interrupt(int irq, void *dev_instance)
@@ -378,22 +499,83 @@ static irqreturn_t inic_interrupt(int irq, void *dev_instance)
return IRQ_RETVAL(handled);
}
+static void inic_fill_sg(struct inic_prd *prd, struct ata_queued_cmd *qc)
+{
+ struct scatterlist *sg;
+ unsigned int si;
+ u8 flags = PRD_DMA;
+
+ if (qc->tf.flags & ATA_TFLAG_WRITE)
+ flags |= PRD_WRITE;
+
+ for_each_sg(qc->sg, sg, qc->n_elem, si) {
+ prd->mad = cpu_to_le32(sg_dma_address(sg));
+ prd->len = cpu_to_le16(sg_dma_len(sg));
+ prd->flags = flags;
+ prd++;
+ }
+
+ WARN_ON(!si);
+ prd[-1].flags |= PRD_END;
+}
+
+static void inic_qc_prep(struct ata_queued_cmd *qc)
+{
+ struct inic_port_priv *pp = qc->ap->private_data;
+ struct inic_pkt *pkt = pp->pkt;
+ struct inic_cpb *cpb = &pkt->cpb;
+ struct inic_prd *prd = pkt->prd;
+
+ VPRINTK("ENTER\n");
+
+ if (qc->tf.protocol != ATA_PROT_DMA)
+ return;
+
+ /* prepare packet, based on initio driver */
+ memset(pkt, 0, sizeof(struct inic_pkt));
+
+ cpb->ctl_flags = CPB_CTL_VALID | CPB_CTL_IEN | CPB_CTL_DATA;
+
+ cpb->len = cpu_to_le32(qc->nbytes);
+ cpb->prd = cpu_to_le32(pp->pkt_dma + offsetof(struct inic_pkt, prd));
+
+ cpb->device = qc->tf.device;
+ cpb->feature = qc->tf.feature;
+ cpb->nsect = qc->tf.nsect;
+ cpb->lbal = qc->tf.lbal;
+ cpb->lbam = qc->tf.lbam;
+ cpb->lbah = qc->tf.lbah;
+
+ if (qc->tf.flags & ATA_TFLAG_LBA48) {
+ cpb->hob_feature = qc->tf.hob_feature;
+ cpb->hob_nsect = qc->tf.hob_nsect;
+ cpb->hob_lbal = qc->tf.hob_lbal;
+ cpb->hob_lbam = qc->tf.hob_lbam;
+ cpb->hob_lbah = qc->tf.hob_lbah;
+ }
+
+ cpb->command = qc->tf.command;
+ /* don't load ctl - dunno why. it's like that in the initio driver */
+
+ /* setup sg table */
+ inic_fill_sg(prd, qc);
+
+ pp->cpb_tbl[0] = pp->pkt_dma;
+}
+
static unsigned int inic_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
+ void __iomem *port_base = inic_port_base(ap);
- /* ATA IRQ doesn't wait for DMA transfer completion and vice
- * versa. Mask IRQ selectively to detect command completion.
- * Without it, ATA DMA read command can cause data corruption.
- *
- * Something similar might be needed for ATAPI writes. I
- * tried a lot of combinations but couldn't find the solution.
- */
- if (qc->tf.protocol == ATA_PROT_DMA &&
- !(qc->tf.flags & ATA_TFLAG_WRITE))
- inic_set_pirq_mask(ap, PIRQ_MASK_DMA_READ);
- else
- inic_set_pirq_mask(ap, PIRQ_MASK_OTHER);
+ if (qc->tf.protocol == ATA_PROT_DMA) {
+ /* fire up the ADMA engine */
+ writew(HCTL_FTHD0, port_base + HOST_CTL);
+ writew(IDMA_CTL_GO, port_base + PORT_IDMA_CTL);
+ writeb(0, port_base + PORT_CPB_PTQFIFO);
+
+ return 0;
+ }
/* Issuing a command to yet uninitialized port locks up the
* controller. Most of the time, this happens for the first
@@ -570,9 +752,15 @@ static void inic_dev_config(struct ata_device *dev)
static void init_port(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
+ struct inic_port_priv *pp = ap->private_data;
- /* Setup PRD address */
+ /* clear packet and CPB table */
+ memset(pp->pkt, 0, sizeof(struct inic_pkt));
+ memset(pp->cpb_tbl, 0, IDMA_CPB_TBL_SIZE);
+
+ /* setup PRD and CPB lookup table addresses */
writel(ap->prd_dma, port_base + PORT_PRD_ADDR);
+ writel(pp->cpb_tbl_dma, port_base + PORT_CPB_CPBLAR);
}
static int inic_port_resume(struct ata_port *ap)
@@ -584,12 +772,13 @@ static int inic_port_resume(struct ata_port *ap)
static int inic_port_start(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
+ struct device *dev = ap->host->dev;
struct inic_port_priv *pp;
u8 tmp;
int rc;
/* alloc and initialize private data */
- pp = devm_kzalloc(ap->host->dev, sizeof(*pp), GFP_KERNEL);
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
if (!pp)
return -ENOMEM;
ap->private_data = pp;
@@ -604,6 +793,16 @@ static int inic_port_start(struct ata_port *ap)
if (rc)
return rc;
+ pp->pkt = dmam_alloc_coherent(dev, sizeof(struct inic_pkt),
+ &pp->pkt_dma, GFP_KERNEL);
+ if (!pp->pkt)
+ return -ENOMEM;
+
+ pp->cpb_tbl = dmam_alloc_coherent(dev, IDMA_CPB_TBL_SIZE,
+ &pp->cpb_tbl_dma, GFP_KERNEL);
+ if (!pp->cpb_tbl)
+ return -ENOMEM;
+
init_port(ap);
return 0;
@@ -616,6 +815,7 @@ static struct ata_port_operations inic_port_ops = {
.bmdma_start = inic_bmdma_start,
.bmdma_stop = inic_bmdma_stop,
.bmdma_status = inic_bmdma_status,
+ .qc_prep = inic_qc_prep,
.qc_issue = inic_qc_issue,
.qc_fill_rtf = inic_qc_fill_rtf,
--
1.5.2.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 05/10] sata_inic162x: kill now unused bmdma related stuff
2008-04-30 7:35 [PATCHSET] sata_inic162x: make it work Tejun Heo
` (3 preceding siblings ...)
2008-04-30 7:35 ` [PATCH 04/10] sata_inic162x: use IDMA for ATA_PROT_DMA Tejun Heo
@ 2008-04-30 7:35 ` Tejun Heo
2008-04-30 7:35 ` [PATCH 06/10] sata_inic162x: use IDMA for non DMA ATA commands Tejun Heo
` (5 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2008-04-30 7:35 UTC (permalink / raw)
To: jeff, alan, linux-ide; +Cc: Tejun Heo
sata_inic162x doesn't use BMDMA anymore. Kill bmdma related stuff.
* prdctl manipulation
* port IRQ mask manipulation
* inherit ATA_BASE_SHT instead of ATA_BMDMA_SHT
* BMDMA methods
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/sata_inic162x.c | 103 ++----------------------------------------
1 files changed, 5 insertions(+), 98 deletions(-)
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index 1f105fe..094b0ed 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -101,9 +101,7 @@ enum {
PIRQ_PENDING = (1 << 7), /* port IRQ pending (STAT only) */
PIRQ_ERR = PIRQ_OFFLINE | PIRQ_ONLINE | PIRQ_FATAL,
-
- PIRQ_MASK_DMA_READ = PIRQ_REPLY | PIRQ_ATA,
- PIRQ_MASK_OTHER = PIRQ_REPLY | PIRQ_COMPLETE,
+ PIRQ_MASK_DEFAULT = PIRQ_REPLY,
PIRQ_MASK_FREEZE = 0xff,
/* PORT_PRD_CTL bits */
@@ -206,13 +204,11 @@ struct inic_port_priv {
dma_addr_t pkt_dma;
u32 *cpb_tbl;
dma_addr_t cpb_tbl_dma;
- u8 dfl_prdctl;
- u8 cached_prdctl;
- u8 cached_pirq_mask;
};
static struct scsi_host_template inic_sht = {
- ATA_BMDMA_SHT(DRV_NAME),
+ ATA_BASE_SHT(DRV_NAME),
+ .sg_tablesize = LIBATA_MAX_PRD, /* maybe it can be larger? */
.dma_boundary = INIC_DMA_BOUNDARY,
};
@@ -227,23 +223,6 @@ static void __iomem *inic_port_base(struct ata_port *ap)
return ap->host->iomap[MMIO_BAR] + ap->port_no * PORT_SIZE;
}
-static void __inic_set_pirq_mask(struct ata_port *ap, u8 mask)
-{
- void __iomem *port_base = inic_port_base(ap);
- struct inic_port_priv *pp = ap->private_data;
-
- writeb(mask, port_base + PORT_IRQ_MASK);
- pp->cached_pirq_mask = mask;
-}
-
-static void inic_set_pirq_mask(struct ata_port *ap, u8 mask)
-{
- struct inic_port_priv *pp = ap->private_data;
-
- if (pp->cached_pirq_mask != mask)
- __inic_set_pirq_mask(ap, mask);
-}
-
static void inic_reset_port(void __iomem *port_base)
{
void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
@@ -297,63 +276,6 @@ static int inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
return 0;
}
-/*
- * In TF mode, inic162x is very similar to SFF device. TF registers
- * function the same. DMA engine behaves similary using the same PRD
- * format as BMDMA but different command register, interrupt and event
- * notification methods are used. The following inic_bmdma_*()
- * functions do the impedance matching.
- */
-static void inic_bmdma_setup(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct inic_port_priv *pp = ap->private_data;
- void __iomem *port_base = inic_port_base(ap);
- int rw = qc->tf.flags & ATA_TFLAG_WRITE;
-
- /* make sure device sees PRD table writes */
- wmb();
-
- /* load transfer length */
- writel(qc->nbytes, port_base + PORT_PRD_XFERLEN);
-
- /* turn on DMA and specify data direction */
- pp->cached_prdctl = pp->dfl_prdctl | PRD_CTL_DMAEN;
- if (!rw)
- pp->cached_prdctl |= PRD_CTL_WR;
- writeb(pp->cached_prdctl, port_base + PORT_PRD_CTL);
-
- /* issue r/w command */
- ap->ops->sff_exec_command(ap, &qc->tf);
-}
-
-static void inic_bmdma_start(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct inic_port_priv *pp = ap->private_data;
- void __iomem *port_base = inic_port_base(ap);
-
- /* start host DMA transaction */
- pp->cached_prdctl |= PRD_CTL_START;
- writeb(pp->cached_prdctl, port_base + PORT_PRD_CTL);
-}
-
-static void inic_bmdma_stop(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct inic_port_priv *pp = ap->private_data;
- void __iomem *port_base = inic_port_base(ap);
-
- /* stop DMA engine */
- writeb(pp->dfl_prdctl, port_base + PORT_PRD_CTL);
-}
-
-static u8 inic_bmdma_status(struct ata_port *ap)
-{
- /* event is already verified by the interrupt handler */
- return ATA_DMA_INTR;
-}
-
static void inic_stop_idma(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
@@ -631,8 +553,7 @@ static void inic_freeze(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
- __inic_set_pirq_mask(ap, PIRQ_MASK_FREEZE);
-
+ writeb(PIRQ_MASK_FREEZE, port_base + PORT_IRQ_MASK);
ap->ops->sff_check_status(ap);
writeb(0xff, port_base + PORT_IRQ_STAT);
}
@@ -643,8 +564,7 @@ static void inic_thaw(struct ata_port *ap)
ap->ops->sff_check_status(ap);
writeb(0xff, port_base + PORT_IRQ_STAT);
-
- __inic_set_pirq_mask(ap, PIRQ_MASK_OTHER);
+ writeb(PIRQ_MASK_DEFAULT, port_base + PORT_IRQ_MASK);
}
static int inic_check_ready(struct ata_link *link)
@@ -713,7 +633,6 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
static void inic_error_handler(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
- struct inic_port_priv *pp = ap->private_data;
unsigned long flags;
/* reset PIO HSM and stop DMA engine */
@@ -721,7 +640,6 @@ static void inic_error_handler(struct ata_port *ap)
spin_lock_irqsave(ap->lock, flags);
ap->hsm_task_state = HSM_ST_IDLE;
- writeb(pp->dfl_prdctl, port_base + PORT_PRD_CTL);
spin_unlock_irqrestore(ap->lock, flags);
/* PIO and DMA engines have been stopped, perform recovery */
@@ -771,10 +689,8 @@ static int inic_port_resume(struct ata_port *ap)
static int inic_port_start(struct ata_port *ap)
{
- void __iomem *port_base = inic_port_base(ap);
struct device *dev = ap->host->dev;
struct inic_port_priv *pp;
- u8 tmp;
int rc;
/* alloc and initialize private data */
@@ -783,11 +699,6 @@ static int inic_port_start(struct ata_port *ap)
return -ENOMEM;
ap->private_data = pp;
- /* default PRD_CTL value, DMAEN, WR and START off */
- tmp = readb(port_base + PORT_PRD_CTL);
- tmp &= ~(PRD_CTL_DMAEN | PRD_CTL_WR | PRD_CTL_START);
- pp->dfl_prdctl = tmp;
-
/* Alloc resources */
rc = ata_port_start(ap);
if (rc)
@@ -811,10 +722,6 @@ static int inic_port_start(struct ata_port *ap)
static struct ata_port_operations inic_port_ops = {
.inherits = &ata_sff_port_ops,
- .bmdma_setup = inic_bmdma_setup,
- .bmdma_start = inic_bmdma_start,
- .bmdma_stop = inic_bmdma_stop,
- .bmdma_status = inic_bmdma_status,
.qc_prep = inic_qc_prep,
.qc_issue = inic_qc_issue,
.qc_fill_rtf = inic_qc_fill_rtf,
--
1.5.2.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 06/10] sata_inic162x: use IDMA for non DMA ATA commands
2008-04-30 7:35 [PATCHSET] sata_inic162x: make it work Tejun Heo
` (4 preceding siblings ...)
2008-04-30 7:35 ` [PATCH 05/10] sata_inic162x: kill now unused bmdma related stuff Tejun Heo
@ 2008-04-30 7:35 ` Tejun Heo
2008-04-30 7:35 ` [PATCH 07/10] sata_inic162x: use IDMA for ATAPI commands Tejun Heo
` (4 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2008-04-30 7:35 UTC (permalink / raw)
To: jeff, alan, linux-ide; +Cc: Tejun Heo
Use IDMA for PIO and non-data commands. This allows sata_inic162x to
safely drive LBA48 devices. Kill inic_dev_config() which contains
code to reject LBA48 devices.
With this change, status checking in inic_qc_issue() to avoid hard
lock up after hotplug can go away too.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/sata_inic162x.c | 49 +++++++++++++-----------------------------
1 files changed, 15 insertions(+), 34 deletions(-)
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index 094b0ed..c132942 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -356,12 +356,12 @@ static void inic_host_intr(struct ata_port *ap)
if (unlikely((irq_stat & PIRQ_ERR) || (idma_stat & IDMA_STAT_ERR)))
inic_host_err_intr(ap, irq_stat, idma_stat);
- if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
+ if (unlikely(!qc)) {
ap->ops->sff_check_status(ap); /* clear ATA interrupt */
goto spurious;
}
- if (qc->tf.protocol == ATA_PROT_DMA) {
+ if (!ata_is_atapi(qc->tf.protocol)) {
if (likely(idma_stat & IDMA_STAT_DONE)) {
inic_stop_idma(ap);
@@ -425,11 +425,14 @@ static void inic_fill_sg(struct inic_prd *prd, struct ata_queued_cmd *qc)
{
struct scatterlist *sg;
unsigned int si;
- u8 flags = PRD_DMA;
+ u8 flags = 0;
if (qc->tf.flags & ATA_TFLAG_WRITE)
flags |= PRD_WRITE;
+ if (ata_is_dma(qc->tf.protocol))
+ flags |= PRD_DMA;
+
for_each_sg(qc->sg, sg, qc->n_elem, si) {
prd->mad = cpu_to_le32(sg_dma_address(sg));
prd->len = cpu_to_le16(sg_dma_len(sg));
@@ -447,16 +450,20 @@ static void inic_qc_prep(struct ata_queued_cmd *qc)
struct inic_pkt *pkt = pp->pkt;
struct inic_cpb *cpb = &pkt->cpb;
struct inic_prd *prd = pkt->prd;
+ bool is_atapi = ata_is_atapi(qc->tf.protocol);
+ bool is_data = ata_is_data(qc->tf.protocol);
VPRINTK("ENTER\n");
- if (qc->tf.protocol != ATA_PROT_DMA)
+ if (is_atapi)
return;
/* prepare packet, based on initio driver */
memset(pkt, 0, sizeof(struct inic_pkt));
- cpb->ctl_flags = CPB_CTL_VALID | CPB_CTL_IEN | CPB_CTL_DATA;
+ cpb->ctl_flags = CPB_CTL_VALID | CPB_CTL_IEN;
+ if (is_data)
+ cpb->ctl_flags |= CPB_CTL_DATA;
cpb->len = cpu_to_le32(qc->nbytes);
cpb->prd = cpu_to_le32(pp->pkt_dma + offsetof(struct inic_pkt, prd));
@@ -480,7 +487,8 @@ static void inic_qc_prep(struct ata_queued_cmd *qc)
/* don't load ctl - dunno why. it's like that in the initio driver */
/* setup sg table */
- inic_fill_sg(prd, qc);
+ if (is_data)
+ inic_fill_sg(prd, qc);
pp->cpb_tbl[0] = pp->pkt_dma;
}
@@ -490,7 +498,7 @@ static unsigned int inic_qc_issue(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
void __iomem *port_base = inic_port_base(ap);
- if (qc->tf.protocol == ATA_PROT_DMA) {
+ if (!ata_is_atapi(qc->tf.protocol)) {
/* fire up the ADMA engine */
writew(HCTL_FTHD0, port_base + HOST_CTL);
writew(IDMA_CTL_GO, port_base + PORT_IDMA_CTL);
@@ -499,18 +507,6 @@ static unsigned int inic_qc_issue(struct ata_queued_cmd *qc)
return 0;
}
- /* Issuing a command to yet uninitialized port locks up the
- * controller. Most of the time, this happens for the first
- * command after reset which are ATA and ATAPI IDENTIFYs.
- * Fast fail if stat is 0x7f or 0xff for those commands.
- */
- if (unlikely(qc->tf.command == ATA_CMD_ID_ATA ||
- qc->tf.command == ATA_CMD_ID_ATAPI)) {
- u8 stat = ap->ops->sff_check_status(ap);
- if (stat == 0x7f || stat == 0xff)
- return AC_ERR_HSM;
- }
-
return ata_sff_qc_issue(qc);
}
@@ -653,20 +649,6 @@ static void inic_post_internal_cmd(struct ata_queued_cmd *qc)
inic_reset_port(inic_port_base(qc->ap));
}
-static void inic_dev_config(struct ata_device *dev)
-{
- /* inic can only handle upto LBA28 max sectors */
- if (dev->max_sectors > ATA_MAX_SECTORS)
- dev->max_sectors = ATA_MAX_SECTORS;
-
- if (dev->n_sectors >= 1 << 28) {
- ata_dev_printk(dev, KERN_ERR,
- "ERROR: This driver doesn't support LBA48 yet and may cause\n"
- " data corruption on such devices. Disabling.\n");
- ata_dev_disable(dev);
- }
-}
-
static void init_port(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
@@ -732,7 +714,6 @@ static struct ata_port_operations inic_port_ops = {
.hardreset = inic_hardreset,
.error_handler = inic_error_handler,
.post_internal_cmd = inic_post_internal_cmd,
- .dev_config = inic_dev_config,
.scr_read = inic_scr_read,
.scr_write = inic_scr_write,
--
1.5.2.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 07/10] sata_inic162x: use IDMA for ATAPI commands
2008-04-30 7:35 [PATCHSET] sata_inic162x: make it work Tejun Heo
` (5 preceding siblings ...)
2008-04-30 7:35 ` [PATCH 06/10] sata_inic162x: use IDMA for non DMA ATA commands Tejun Heo
@ 2008-04-30 7:35 ` Tejun Heo
2008-04-30 7:35 ` [PATCH 08/10] sata_inic162x: kill now unused SFF related stuff Tejun Heo
` (3 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2008-04-30 7:35 UTC (permalink / raw)
To: jeff, alan, linux-ide; +Cc: Tejun Heo
Use IDMA for ATAPI commands. Write and some misc commands time out
when executed using ATAPI_PROT_DMA but ATAPI_PROT_PIO works fine. As
PIO is driven by DMA too, it doesn't make any noticeable difference
for native SATA devices. inic_check_atapi_dma() is implemented to
force PIO for those ATAPI commands.
After this change, sata_inic162x issues all commands using IDMA.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/sata_inic162x.c | 81 +++++++++++++++++++++++++------------------
1 files changed, 47 insertions(+), 34 deletions(-)
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index c132942..a31dc24 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -192,7 +192,8 @@ struct inic_prd {
struct inic_pkt {
struct inic_cpb cpb;
- struct inic_prd prd[LIBATA_MAX_PRD];
+ struct inic_prd prd[LIBATA_MAX_PRD + 1]; /* + 1 for cdb */
+ u8 cdb[ATAPI_CDB_LEN];
} __packed;
struct inic_host_priv {
@@ -361,23 +362,18 @@ static void inic_host_intr(struct ata_port *ap)
goto spurious;
}
- if (!ata_is_atapi(qc->tf.protocol)) {
- if (likely(idma_stat & IDMA_STAT_DONE)) {
- inic_stop_idma(ap);
+ if (likely(idma_stat & IDMA_STAT_DONE)) {
+ inic_stop_idma(ap);
- /* Depending on circumstances, device error
- * isn't reported by IDMA, check it explicitly.
- */
- if (unlikely(readb(port_base + PORT_TF_COMMAND) &
- (ATA_DF | ATA_ERR)))
- qc->err_mask |= AC_ERR_DEV;
+ /* Depending on circumstances, device error
+ * isn't reported by IDMA, check it explicitly.
+ */
+ if (unlikely(readb(port_base + PORT_TF_COMMAND) &
+ (ATA_DF | ATA_ERR)))
+ qc->err_mask |= AC_ERR_DEV;
- ata_qc_complete(qc);
- return;
- }
- } else {
- if (likely(ata_sff_host_intr(ap, qc)))
- return;
+ ata_qc_complete(qc);
+ return;
}
spurious:
@@ -421,6 +417,19 @@ static irqreturn_t inic_interrupt(int irq, void *dev_instance)
return IRQ_RETVAL(handled);
}
+static int inic_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ /* For some reason ATAPI_PROT_DMA doesn't work for some
+ * commands including writes and other misc ops. Use PIO
+ * protocol instead, which BTW is driven by the DMA engine
+ * anyway, so it shouldn't make much difference for native
+ * SATA devices.
+ */
+ if (atapi_cmd_type(qc->cdb[0]) == READ)
+ return 0;
+ return 1;
+}
+
static void inic_fill_sg(struct inic_prd *prd, struct ata_queued_cmd *qc)
{
struct scatterlist *sg;
@@ -452,20 +461,21 @@ static void inic_qc_prep(struct ata_queued_cmd *qc)
struct inic_prd *prd = pkt->prd;
bool is_atapi = ata_is_atapi(qc->tf.protocol);
bool is_data = ata_is_data(qc->tf.protocol);
+ unsigned int cdb_len = 0;
VPRINTK("ENTER\n");
if (is_atapi)
- return;
+ cdb_len = qc->dev->cdb_len;
/* prepare packet, based on initio driver */
memset(pkt, 0, sizeof(struct inic_pkt));
cpb->ctl_flags = CPB_CTL_VALID | CPB_CTL_IEN;
- if (is_data)
+ if (is_atapi || is_data)
cpb->ctl_flags |= CPB_CTL_DATA;
- cpb->len = cpu_to_le32(qc->nbytes);
+ cpb->len = cpu_to_le32(qc->nbytes + cdb_len);
cpb->prd = cpu_to_le32(pp->pkt_dma + offsetof(struct inic_pkt, prd));
cpb->device = qc->tf.device;
@@ -486,6 +496,18 @@ static void inic_qc_prep(struct ata_queued_cmd *qc)
cpb->command = qc->tf.command;
/* don't load ctl - dunno why. it's like that in the initio driver */
+ /* setup PRD for CDB */
+ if (is_atapi) {
+ memcpy(pkt->cdb, qc->cdb, ATAPI_CDB_LEN);
+ prd->mad = cpu_to_le32(pp->pkt_dma +
+ offsetof(struct inic_pkt, cdb));
+ prd->len = cpu_to_le16(cdb_len);
+ prd->flags = PRD_CDB | PRD_WRITE;
+ if (!is_data)
+ prd->flags |= PRD_END;
+ prd++;
+ }
+
/* setup sg table */
if (is_data)
inic_fill_sg(prd, qc);
@@ -498,16 +520,12 @@ static unsigned int inic_qc_issue(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
void __iomem *port_base = inic_port_base(ap);
- if (!ata_is_atapi(qc->tf.protocol)) {
- /* fire up the ADMA engine */
- writew(HCTL_FTHD0, port_base + HOST_CTL);
- writew(IDMA_CTL_GO, port_base + PORT_IDMA_CTL);
- writeb(0, port_base + PORT_CPB_PTQFIFO);
+ /* fire up the ADMA engine */
+ writew(HCTL_FTHD0, port_base + HOST_CTL);
+ writew(IDMA_CTL_GO, port_base + PORT_IDMA_CTL);
+ writeb(0, port_base + PORT_CPB_PTQFIFO);
- return 0;
- }
-
- return ata_sff_qc_issue(qc);
+ return 0;
}
static void inic_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
@@ -704,6 +722,7 @@ static int inic_port_start(struct ata_port *ap)
static struct ata_port_operations inic_port_ops = {
.inherits = &ata_sff_port_ops,
+ .check_atapi_dma = inic_check_atapi_dma,
.qc_prep = inic_qc_prep,
.qc_issue = inic_qc_issue,
.qc_fill_rtf = inic_qc_fill_rtf,
@@ -723,12 +742,6 @@ static struct ata_port_operations inic_port_ops = {
};
static struct ata_port_info inic_port_info = {
- /* For some reason, ATAPI_PROT_PIO is broken on this
- * controller, and no, PIO_POLLING does't fix it. It somehow
- * manages to report the wrong ireason and ignoring ireason
- * results in machine lock up. Tell libata to always prefer
- * DMA.
- */
.flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
--
1.5.2.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 08/10] sata_inic162x: kill now unused SFF related stuff
2008-04-30 7:35 [PATCHSET] sata_inic162x: make it work Tejun Heo
` (6 preceding siblings ...)
2008-04-30 7:35 ` [PATCH 07/10] sata_inic162x: use IDMA for ATAPI commands Tejun Heo
@ 2008-04-30 7:35 ` Tejun Heo
2008-04-30 7:35 ` [PATCH 09/10] sata_inic162x: add cardbus support Tejun Heo
` (2 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2008-04-30 7:35 UTC (permalink / raw)
To: jeff, alan, linux-ide; +Cc: Tejun Heo
sata_inic162x now doesn't use any SFF features. Remove all SFF
related stuff.
* Mask unsolicited ATA interrupts. This removes our primary source of
spurious interrupts and spurious interrupt handling can be tightened
up. There's no need to clear ATA interrupts by reading status
register either.
* Don't dance with IDMA_CTL_ATA_NIEN and simplify accesses to
IDMA_CTL.
* Inherit from sata_port_ops instead of ata_sff_port_ops.
* Don't initialize or use ioaddr. There's no need to map BAR0-4
anymore.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/sata_inic162x.c | 69 +++++++++++-------------------------------
1 files changed, 18 insertions(+), 51 deletions(-)
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index a31dc24..ee67d6e 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -101,7 +101,7 @@ enum {
PIRQ_PENDING = (1 << 7), /* port IRQ pending (STAT only) */
PIRQ_ERR = PIRQ_OFFLINE | PIRQ_ONLINE | PIRQ_FATAL,
- PIRQ_MASK_DEFAULT = PIRQ_REPLY,
+ PIRQ_MASK_DEFAULT = PIRQ_REPLY | PIRQ_ATA,
PIRQ_MASK_FREEZE = 0xff,
/* PORT_PRD_CTL bits */
@@ -227,31 +227,26 @@ static void __iomem *inic_port_base(struct ata_port *ap)
static void inic_reset_port(void __iomem *port_base)
{
void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
- u16 ctl;
- ctl = readw(idma_ctl);
- ctl &= ~(IDMA_CTL_RST_IDMA | IDMA_CTL_ATA_NIEN | IDMA_CTL_GO);
+ /* stop IDMA engine */
+ readw(idma_ctl); /* flush */
+ msleep(1);
/* mask IRQ and assert reset */
- writew(ctl | IDMA_CTL_RST_IDMA | IDMA_CTL_ATA_NIEN, idma_ctl);
+ writew(IDMA_CTL_RST_IDMA, idma_ctl);
readw(idma_ctl); /* flush */
-
- /* give it some time */
msleep(1);
/* release reset */
- writew(ctl | IDMA_CTL_ATA_NIEN, idma_ctl);
+ writew(0, idma_ctl);
/* clear irq */
writeb(0xff, port_base + PORT_IRQ_STAT);
-
- /* reenable ATA IRQ, turn off IDMA mode */
- writew(ctl, idma_ctl);
}
static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
{
- void __iomem *scr_addr = ap->ioaddr.scr_addr;
+ void __iomem *scr_addr = inic_port_base(ap) + PORT_SCR;
void __iomem *addr;
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
@@ -268,7 +263,7 @@ static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
static int inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
{
- void __iomem *scr_addr = ap->ioaddr.scr_addr;
+ void __iomem *scr_addr = inic_port_base(ap) + PORT_SCR;
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
return -EINVAL;
@@ -357,10 +352,8 @@ static void inic_host_intr(struct ata_port *ap)
if (unlikely((irq_stat & PIRQ_ERR) || (idma_stat & IDMA_STAT_ERR)))
inic_host_err_intr(ap, irq_stat, idma_stat);
- if (unlikely(!qc)) {
- ap->ops->sff_check_status(ap); /* clear ATA interrupt */
+ if (unlikely(!qc))
goto spurious;
- }
if (likely(idma_stat & IDMA_STAT_DONE)) {
inic_stop_idma(ap);
@@ -377,7 +370,9 @@ static void inic_host_intr(struct ata_port *ap)
}
spurious:
- ap->ops->sff_check_status(ap); /* clear ATA interrupt */
+ ata_port_printk(ap, KERN_WARNING, "unhandled interrupt: "
+ "cmd=0x%x irq_stat=0x%x idma_stat=0x%x\n",
+ qc ? qc->tf.command : 0xff, irq_stat, idma_stat);
}
static irqreturn_t inic_interrupt(int irq, void *dev_instance)
@@ -568,7 +563,6 @@ static void inic_freeze(struct ata_port *ap)
void __iomem *port_base = inic_port_base(ap);
writeb(PIRQ_MASK_FREEZE, port_base + PORT_IRQ_MASK);
- ap->ops->sff_check_status(ap);
writeb(0xff, port_base + PORT_IRQ_STAT);
}
@@ -576,7 +570,6 @@ static void inic_thaw(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
- ap->ops->sff_check_status(ap);
writeb(0xff, port_base + PORT_IRQ_STAT);
writeb(PIRQ_MASK_DEFAULT, port_base + PORT_IRQ_MASK);
}
@@ -599,17 +592,15 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
void __iomem *port_base = inic_port_base(ap);
void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
- u16 val;
int rc;
/* hammer it into sane state */
inic_reset_port(port_base);
- val = readw(idma_ctl);
- writew(val | IDMA_CTL_RST_ATA, idma_ctl);
+ writew(IDMA_CTL_RST_ATA, idma_ctl);
readw(idma_ctl); /* flush */
msleep(1);
- writew(val & ~IDMA_CTL_RST_ATA, idma_ctl);
+ writew(0, idma_ctl);
rc = sata_link_resume(link, timing, deadline);
if (rc) {
@@ -647,16 +638,8 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
static void inic_error_handler(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
- unsigned long flags;
- /* reset PIO HSM and stop DMA engine */
inic_reset_port(port_base);
-
- spin_lock_irqsave(ap->lock, flags);
- ap->hsm_task_state = HSM_ST_IDLE;
- spin_unlock_irqrestore(ap->lock, flags);
-
- /* PIO and DMA engines have been stopped, perform recovery */
ata_std_error_handler(ap);
}
@@ -720,7 +703,7 @@ static int inic_port_start(struct ata_port *ap)
}
static struct ata_port_operations inic_port_ops = {
- .inherits = &ata_sff_port_ops,
+ .inherits = &sata_port_ops,
.check_atapi_dma = inic_check_atapi_dma,
.qc_prep = inic_qc_prep,
@@ -729,7 +712,6 @@ static struct ata_port_operations inic_port_ops = {
.freeze = inic_freeze,
.thaw = inic_thaw,
- .softreset = ATA_OP_NULL, /* softreset is broken */
.hardreset = inic_hardreset,
.error_handler = inic_error_handler,
.post_internal_cmd = inic_post_internal_cmd,
@@ -838,34 +820,19 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return rc;
- rc = pcim_iomap_regions(pdev, 0x3f, DRV_NAME);
+ rc = pcim_iomap_regions(pdev, 1 << MMIO_BAR, DRV_NAME);
if (rc)
return rc;
host->iomap = iomap = pcim_iomap_table(pdev);
+ hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL);
for (i = 0; i < NR_PORTS; i++) {
struct ata_port *ap = host->ports[i];
- struct ata_ioports *port = &ap->ioaddr;
- unsigned int offset = i * PORT_SIZE;
-
- port->cmd_addr = iomap[2 * i];
- port->altstatus_addr =
- port->ctl_addr = (void __iomem *)
- ((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS);
- port->scr_addr = iomap[MMIO_BAR] + offset + PORT_SCR;
-
- ata_sff_std_ports(port);
ata_port_pbar_desc(ap, MMIO_BAR, -1, "mmio");
- ata_port_pbar_desc(ap, MMIO_BAR, offset, "port");
- ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
- (unsigned long long)pci_resource_start(pdev, 2 * i),
- (unsigned long long)pci_resource_start(pdev, (2 * i + 1)) |
- ATA_PCI_CTL_OFS);
+ ata_port_pbar_desc(ap, MMIO_BAR, i * PORT_SIZE, "port");
}
- hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL);
-
/* Set dma_mask. This devices doesn't support 64bit addressing. */
rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (rc) {
--
1.5.2.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 09/10] sata_inic162x: add cardbus support
2008-04-30 7:35 [PATCHSET] sata_inic162x: make it work Tejun Heo
` (7 preceding siblings ...)
2008-04-30 7:35 ` [PATCH 08/10] sata_inic162x: kill now unused SFF related stuff Tejun Heo
@ 2008-04-30 7:35 ` Tejun Heo
2008-04-30 7:35 ` [PATCH 10/10] sata_inic162x: update intro comment, up the version and drop EXPERIMENTAL Tejun Heo
2008-04-30 7:39 ` [PATCHSET] sata_inic162x: make it work Tejun Heo
10 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2008-04-30 7:35 UTC (permalink / raw)
To: jeff, alan, linux-ide; +Cc: Tejun Heo
When attached to cardbus, mmio region is at BAR 1. Other than that,
everything else is the same. Add support for it.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/sata_inic162x.c | 36 ++++++++++++++++++++++++------------
1 files changed, 24 insertions(+), 12 deletions(-)
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index ee67d6e..bfbd34b 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -31,7 +31,8 @@
#define DRV_VERSION "0.3"
enum {
- MMIO_BAR = 5,
+ MMIO_BAR_PCI = 5,
+ MMIO_BAR_CARDBUS = 1,
NR_PORTS = 2,
@@ -197,6 +198,7 @@ struct inic_pkt {
} __packed;
struct inic_host_priv {
+ void __iomem *mmio_base;
u16 cached_hctl;
};
@@ -221,7 +223,9 @@ static const int scr_map[] = {
static void __iomem *inic_port_base(struct ata_port *ap)
{
- return ap->host->iomap[MMIO_BAR] + ap->port_no * PORT_SIZE;
+ struct inic_host_priv *hpriv = ap->host->private_data;
+
+ return hpriv->mmio_base + ap->port_no * PORT_SIZE;
}
static void inic_reset_port(void __iomem *port_base)
@@ -378,11 +382,11 @@ static void inic_host_intr(struct ata_port *ap)
static irqreturn_t inic_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
- void __iomem *mmio_base = host->iomap[MMIO_BAR];
+ struct inic_host_priv *hpriv = host->private_data;
u16 host_irq_stat;
int i, handled = 0;;
- host_irq_stat = readw(mmio_base + HOST_IRQ_STAT);
+ host_irq_stat = readw(hpriv->mmio_base + HOST_IRQ_STAT);
if (unlikely(!(host_irq_stat & HIRQ_GLOBAL)))
goto out;
@@ -776,7 +780,6 @@ static int inic_pci_device_resume(struct pci_dev *pdev)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
struct inic_host_priv *hpriv = host->private_data;
- void __iomem *mmio_base = host->iomap[MMIO_BAR];
int rc;
rc = ata_pci_device_do_resume(pdev);
@@ -784,7 +787,7 @@ static int inic_pci_device_resume(struct pci_dev *pdev)
return rc;
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
- rc = init_controller(mmio_base, hpriv->cached_hctl);
+ rc = init_controller(hpriv->mmio_base, hpriv->cached_hctl);
if (rc)
return rc;
}
@@ -802,6 +805,7 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
struct ata_host *host;
struct inic_host_priv *hpriv;
void __iomem * const *iomap;
+ int mmio_bar;
int i, rc;
if (!printed_version++)
@@ -815,22 +819,30 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
host->private_data = hpriv;
- /* acquire resources and fill host */
+ /* Acquire resources and fill host. Note that PCI and cardbus
+ * use different BARs.
+ */
rc = pcim_enable_device(pdev);
if (rc)
return rc;
- rc = pcim_iomap_regions(pdev, 1 << MMIO_BAR, DRV_NAME);
+ if (pci_resource_flags(pdev, MMIO_BAR_PCI) & IORESOURCE_MEM)
+ mmio_bar = MMIO_BAR_PCI;
+ else
+ mmio_bar = MMIO_BAR_CARDBUS;
+
+ rc = pcim_iomap_regions(pdev, 1 << mmio_bar, DRV_NAME);
if (rc)
return rc;
host->iomap = iomap = pcim_iomap_table(pdev);
- hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL);
+ hpriv->mmio_base = iomap[mmio_bar];
+ hpriv->cached_hctl = readw(hpriv->mmio_base + HOST_CTL);
for (i = 0; i < NR_PORTS; i++) {
struct ata_port *ap = host->ports[i];
- ata_port_pbar_desc(ap, MMIO_BAR, -1, "mmio");
- ata_port_pbar_desc(ap, MMIO_BAR, i * PORT_SIZE, "port");
+ ata_port_pbar_desc(ap, mmio_bar, -1, "mmio");
+ ata_port_pbar_desc(ap, mmio_bar, i * PORT_SIZE, "port");
}
/* Set dma_mask. This devices doesn't support 64bit addressing. */
@@ -860,7 +872,7 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return rc;
}
- rc = init_controller(iomap[MMIO_BAR], hpriv->cached_hctl);
+ rc = init_controller(hpriv->mmio_base, hpriv->cached_hctl);
if (rc) {
dev_printk(KERN_ERR, &pdev->dev,
"failed to initialize controller\n");
--
1.5.2.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 10/10] sata_inic162x: update intro comment, up the version and drop EXPERIMENTAL
2008-04-30 7:35 [PATCHSET] sata_inic162x: make it work Tejun Heo
` (8 preceding siblings ...)
2008-04-30 7:35 ` [PATCH 09/10] sata_inic162x: add cardbus support Tejun Heo
@ 2008-04-30 7:35 ` Tejun Heo
2008-04-30 7:39 ` [PATCHSET] sata_inic162x: make it work Tejun Heo
10 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2008-04-30 7:35 UTC (permalink / raw)
To: jeff, alan, linux-ide; +Cc: Tejun Heo
sata_inic162x is now ready for production use. Bump the version,
explain what's working and what's not and drop EXPERIMENTAL.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/ata/Kconfig | 4 ++--
drivers/ata/sata_inic162x.c | 36 ++++++++++++++++++++++++++++--------
2 files changed, 30 insertions(+), 10 deletions(-)
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 1c11df9..908738a 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -205,8 +205,8 @@ config SATA_VITESSE
If unsure, say N.
config SATA_INIC162X
- tristate "Initio 162x SATA support (HIGHLY EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL
+ tristate "Initio 162x SATA support"
+ depends on PCI
help
This option enables support for Initio 162x Serial ATA.
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index bfbd34b..2f8f1df 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -10,13 +10,33 @@
* right. Documentation is available at initio's website but it only
* documents registers (not programming model).
*
- * - ATA disks work.
- * - Hotplug works.
- * - ATAPI read works but burning doesn't. This thing is really
- * peculiar about ATAPI and I couldn't figure out how ATAPI PIO and
- * ATAPI DMA WRITE should be programmed. If you've got a clue, be
- * my guest.
- * - Both STR and STD work.
+ * This driver has interesting history. The first version was written
+ * from the documentation and a 2.4 IDE driver posted on a Taiwan
+ * company, which didn't use any IDMA features and couldn't handle
+ * LBA48. The resulting driver couldn't handle LBA48 devices either
+ * making it pretty useless.
+ *
+ * After a while, initio picked the driver up, renamed it to
+ * sata_initio162x, updated it to use IDMA for ATA DMA commands and
+ * posted it on their website. It only used ATA_PROT_DMA for IDMA and
+ * attaching both devices and issuing IDMA and !IDMA commands
+ * simultaneously broke it due to PIRQ masking interaction but it did
+ * show how to use the IDMA (ADMA + some initio specific twists)
+ * engine.
+ *
+ * Then, I picked up their changes again and here's the usable driver
+ * which uses IDMA for everything. Everything works now including
+ * LBA48, CD/DVD burning, suspend/resume and hotplug. There are some
+ * issues tho. Result Tf is not resported properly, NCQ isn't
+ * supported yet and CD/DVD writing works with DMA assisted PIO
+ * protocol (which, for native SATA devices, shouldn't cause any
+ * noticeable difference).
+ *
+ * Anyways, so, here's finally a working driver for inic162x. Enjoy!
+ *
+ * initio: If you guys wanna improve the driver regarding result TF
+ * access and other stuff, please feel free to contact me. I'll be
+ * happy to assist.
*/
#include <linux/kernel.h>
@@ -28,7 +48,7 @@
#include <scsi/scsi_device.h>
#define DRV_NAME "sata_inic162x"
-#define DRV_VERSION "0.3"
+#define DRV_VERSION "0.4"
enum {
MMIO_BAR_PCI = 5,
--
1.5.2.4
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCHSET] sata_inic162x: make it work
2008-04-30 7:35 [PATCHSET] sata_inic162x: make it work Tejun Heo
` (9 preceding siblings ...)
2008-04-30 7:35 ` [PATCH 10/10] sata_inic162x: update intro comment, up the version and drop EXPERIMENTAL Tejun Heo
@ 2008-04-30 7:39 ` Tejun Heo
10 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2008-04-30 7:39 UTC (permalink / raw)
To: jeff, alan, linux-ide
Tejun Heo wrote:
> Hello, Jeff, Alan.
>
> Initio took the sata_inic162x driver, implemented ATA_PROT_DMA using
> IDMA, renamed it to sata_initio162x and posted on their website. It
> didn't work very well for me but contained enough hint on how to use
> IDMA mode.
>
> So, this is the patchset to make sata_inic162x to use IDMA for
> everything including ATAPIs. There are still some issues - result TF
> is not accessible, !read ATAPI commands should be issued using
> ATAPI_PROT_PIO, but overall, everything including suspend/resume,
> hotplug and burning cd/dvds works nicely.
Available as git tree.
http://git.kernel.org/?p=linux/kernel/git/tj/libata-dev.git;a=shortlog;h=inic162x
git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata-dev.git inic162x
Thanks.
--
tejun
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 03/10 UPDATED] sata_inic162x: update TF read handling
2008-04-30 7:35 ` [PATCH 03/10] sata_inic162x: update TF read handling Tejun Heo
@ 2008-05-01 14:55 ` Tejun Heo
0 siblings, 0 replies; 14+ messages in thread
From: Tejun Heo @ 2008-05-01 14:55 UTC (permalink / raw)
To: jeff, alan, linux-ide
inic162x can't reliably read back TF or at least we don't know how to
do it yet. The only values which seem reliable are status and error.
This patch updates access to TF.
* implement inic_tf_read() which reads the TF area in mmio area
* implement custom inic_qc_fill_rtf() which only returns true if
status indicates device error. it'll be returning bogus addresses
for device errors but it'll be able to report why it failed at
least.
* implement custom inic_check_ready() and use ata_wait_after_reset()
instead of the SFF version.
* use inic_tf_read() for classification.
This is not perfect but it fixes hotplug detection failure and at
least makes the driver report 0's instead of random garbages while
reporting valid status and error for device errors.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
Hotplug misdetection wasn't caused by wrongly reported signature. It
was caused by bogus not-ready TF status value. This patch is updated
accordingly and the whole patchset should be applied on top of the
following patch.
http://article.gmane.org/gmane.linux.ide/31188
All other patches can be applied w/o change. The git tree is updated.
http://git.kernel.org/?p=linux/kernel/git/tj/libata-dev.git;a=shortlog;h=inic162x
git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata-dev.git inic162x
Thanks.
drivers/ata/sata_inic162x.c | 47 ++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 45 insertions(+), 2 deletions(-)
Index: work/drivers/ata/sata_inic162x.c
===================================================================
--- work.orig/drivers/ata/sata_inic162x.c
+++ work/drivers/ata/sata_inic162x.c
@@ -410,6 +410,41 @@ static unsigned int inic_qc_issue(struct
return ata_sff_qc_issue(qc);
}
+static void inic_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ void __iomem *port_base = inic_port_base(ap);
+
+ tf->feature = readb(port_base + PORT_TF_FEATURE);
+ tf->nsect = readb(port_base + PORT_TF_NSECT);
+ tf->lbal = readb(port_base + PORT_TF_LBAL);
+ tf->lbam = readb(port_base + PORT_TF_LBAM);
+ tf->lbah = readb(port_base + PORT_TF_LBAH);
+ tf->device = readb(port_base + PORT_TF_DEVICE);
+ tf->command = readb(port_base + PORT_TF_COMMAND);
+}
+
+static bool inic_qc_fill_rtf(struct ata_queued_cmd *qc)
+{
+ struct ata_taskfile *rtf = &qc->result_tf;
+ struct ata_taskfile tf;
+
+ /* FIXME: Except for status and error, result TF access
+ * doesn't work. I tried reading from BAR0/2, CPB and BAR5.
+ * None works regardless of which command interface is used.
+ * For now return true iff status indicates device error.
+ * This means that we're reporting bogus sector for RW
+ * failures. Eeekk....
+ */
+ inic_tf_read(qc->ap, &tf);
+
+ if (!(tf.command & ATA_ERR))
+ return false;
+
+ rtf->command = tf.command;
+ rtf->feature = tf.feature;
+ return true;
+}
+
static void inic_freeze(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
@@ -430,6 +465,13 @@ static void inic_thaw(struct ata_port *a
__inic_set_pirq_mask(ap, PIRQ_MASK_OTHER);
}
+static int inic_check_ready(struct ata_link *link)
+{
+ void __iomem *port_base = inic_port_base(link->ap);
+
+ return ata_check_ready(readb(port_base + PORT_TF_COMMAND));
+}
+
/*
* SRST and SControl hardreset don't give valid signature on this
* controller. Only controller specific hardreset mechanism works.
@@ -465,7 +507,7 @@ static int inic_hardreset(struct ata_lin
struct ata_taskfile tf;
/* wait for link to become ready */
- rc = ata_sff_wait_after_reset(link, 1, deadline);
+ rc = ata_wait_after_reset(link, deadline, inic_check_ready);
/* link occupied, -ENODEV too is an error */
if (rc) {
ata_link_printk(link, KERN_WARNING, "device not ready "
@@ -473,7 +515,7 @@ static int inic_hardreset(struct ata_lin
return rc;
}
- ata_sff_tf_read(ap, &tf);
+ inic_tf_read(ap, &tf);
*class = ata_dev_classify(&tf);
}
@@ -569,6 +611,7 @@ static struct ata_port_operations inic_p
.bmdma_stop = inic_bmdma_stop,
.bmdma_status = inic_bmdma_status,
.qc_issue = inic_qc_issue,
+ .qc_fill_rtf = inic_qc_fill_rtf,
.freeze = inic_freeze,
.thaw = inic_thaw,
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 01/10] sata_inic162x: misc clean ups
2008-04-30 7:35 ` [PATCH 01/10] sata_inic162x: misc clean ups Tejun Heo
@ 2008-05-06 14:08 ` Jeff Garzik
0 siblings, 0 replies; 14+ messages in thread
From: Jeff Garzik @ 2008-05-06 14:08 UTC (permalink / raw)
To: Tejun Heo; +Cc: alan, linux-ide
Tejun Heo wrote:
> * use larger indents for structure member definitions
>
> * kill unused variable @addr in inic_scr_write()
>
> * kill unnecessary flushes in inic_freeze/thaw()
>
> * kill buggy explicit kfree() on devres managed port private data
>
> This is in preparation of further inic162x updates.
>
> Signed-off-by: Tejun Heo <htejun@gmail.com>
> ---
> drivers/ata/sata_inic162x.c | 18 +++++-------------
> 1 files changed, 5 insertions(+), 13 deletions(-)
applied 1-10
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2008-05-06 14:08 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-04-30 7:35 [PATCHSET] sata_inic162x: make it work Tejun Heo
2008-04-30 7:35 ` [PATCH 01/10] sata_inic162x: misc clean ups Tejun Heo
2008-05-06 14:08 ` Jeff Garzik
2008-04-30 7:35 ` [PATCH 02/10] sata_inic162x: add / update constants Tejun Heo
2008-04-30 7:35 ` [PATCH 03/10] sata_inic162x: update TF read handling Tejun Heo
2008-05-01 14:55 ` [PATCH 03/10 UPDATED] " Tejun Heo
2008-04-30 7:35 ` [PATCH 04/10] sata_inic162x: use IDMA for ATA_PROT_DMA Tejun Heo
2008-04-30 7:35 ` [PATCH 05/10] sata_inic162x: kill now unused bmdma related stuff Tejun Heo
2008-04-30 7:35 ` [PATCH 06/10] sata_inic162x: use IDMA for non DMA ATA commands Tejun Heo
2008-04-30 7:35 ` [PATCH 07/10] sata_inic162x: use IDMA for ATAPI commands Tejun Heo
2008-04-30 7:35 ` [PATCH 08/10] sata_inic162x: kill now unused SFF related stuff Tejun Heo
2008-04-30 7:35 ` [PATCH 09/10] sata_inic162x: add cardbus support Tejun Heo
2008-04-30 7:35 ` [PATCH 10/10] sata_inic162x: update intro comment, up the version and drop EXPERIMENTAL Tejun Heo
2008-04-30 7:39 ` [PATCHSET] sata_inic162x: make it work Tejun Heo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).