sata_inic162x: use IDMA for ATAPI commands
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> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
This commit is contained in:
parent
049e8e0498
commit
b3f677e501
|
@ -192,7 +192,8 @@ struct inic_prd {
|
||||||
|
|
||||||
struct inic_pkt {
|
struct inic_pkt {
|
||||||
struct inic_cpb cpb;
|
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;
|
} __packed;
|
||||||
|
|
||||||
struct inic_host_priv {
|
struct inic_host_priv {
|
||||||
|
@ -361,23 +362,18 @@ static void inic_host_intr(struct ata_port *ap)
|
||||||
goto spurious;
|
goto spurious;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ata_is_atapi(qc->tf.protocol)) {
|
if (likely(idma_stat & IDMA_STAT_DONE)) {
|
||||||
if (likely(idma_stat & IDMA_STAT_DONE)) {
|
inic_stop_idma(ap);
|
||||||
inic_stop_idma(ap);
|
|
||||||
|
|
||||||
/* Depending on circumstances, device error
|
/* Depending on circumstances, device error
|
||||||
* isn't reported by IDMA, check it explicitly.
|
* isn't reported by IDMA, check it explicitly.
|
||||||
*/
|
*/
|
||||||
if (unlikely(readb(port_base + PORT_TF_COMMAND) &
|
if (unlikely(readb(port_base + PORT_TF_COMMAND) &
|
||||||
(ATA_DF | ATA_ERR)))
|
(ATA_DF | ATA_ERR)))
|
||||||
qc->err_mask |= AC_ERR_DEV;
|
qc->err_mask |= AC_ERR_DEV;
|
||||||
|
|
||||||
ata_qc_complete(qc);
|
ata_qc_complete(qc);
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (likely(ata_sff_host_intr(ap, qc)))
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
spurious:
|
spurious:
|
||||||
|
@ -421,6 +417,19 @@ static irqreturn_t inic_interrupt(int irq, void *dev_instance)
|
||||||
return IRQ_RETVAL(handled);
|
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)
|
static void inic_fill_sg(struct inic_prd *prd, struct ata_queued_cmd *qc)
|
||||||
{
|
{
|
||||||
struct scatterlist *sg;
|
struct scatterlist *sg;
|
||||||
|
@ -452,20 +461,21 @@ static void inic_qc_prep(struct ata_queued_cmd *qc)
|
||||||
struct inic_prd *prd = pkt->prd;
|
struct inic_prd *prd = pkt->prd;
|
||||||
bool is_atapi = ata_is_atapi(qc->tf.protocol);
|
bool is_atapi = ata_is_atapi(qc->tf.protocol);
|
||||||
bool is_data = ata_is_data(qc->tf.protocol);
|
bool is_data = ata_is_data(qc->tf.protocol);
|
||||||
|
unsigned int cdb_len = 0;
|
||||||
|
|
||||||
VPRINTK("ENTER\n");
|
VPRINTK("ENTER\n");
|
||||||
|
|
||||||
if (is_atapi)
|
if (is_atapi)
|
||||||
return;
|
cdb_len = qc->dev->cdb_len;
|
||||||
|
|
||||||
/* prepare packet, based on initio driver */
|
/* prepare packet, based on initio driver */
|
||||||
memset(pkt, 0, sizeof(struct inic_pkt));
|
memset(pkt, 0, sizeof(struct inic_pkt));
|
||||||
|
|
||||||
cpb->ctl_flags = CPB_CTL_VALID | CPB_CTL_IEN;
|
cpb->ctl_flags = CPB_CTL_VALID | CPB_CTL_IEN;
|
||||||
if (is_data)
|
if (is_atapi || is_data)
|
||||||
cpb->ctl_flags |= CPB_CTL_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->prd = cpu_to_le32(pp->pkt_dma + offsetof(struct inic_pkt, prd));
|
||||||
|
|
||||||
cpb->device = qc->tf.device;
|
cpb->device = qc->tf.device;
|
||||||
|
@ -486,6 +496,18 @@ static void inic_qc_prep(struct ata_queued_cmd *qc)
|
||||||
cpb->command = qc->tf.command;
|
cpb->command = qc->tf.command;
|
||||||
/* don't load ctl - dunno why. it's like that in the initio driver */
|
/* 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 */
|
/* setup sg table */
|
||||||
if (is_data)
|
if (is_data)
|
||||||
inic_fill_sg(prd, qc);
|
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;
|
struct ata_port *ap = qc->ap;
|
||||||
void __iomem *port_base = inic_port_base(ap);
|
void __iomem *port_base = inic_port_base(ap);
|
||||||
|
|
||||||
if (!ata_is_atapi(qc->tf.protocol)) {
|
/* fire up the ADMA engine */
|
||||||
/* fire up the ADMA engine */
|
writew(HCTL_FTHD0, port_base + HOST_CTL);
|
||||||
writew(HCTL_FTHD0, port_base + HOST_CTL);
|
writew(IDMA_CTL_GO, port_base + PORT_IDMA_CTL);
|
||||||
writew(IDMA_CTL_GO, port_base + PORT_IDMA_CTL);
|
writeb(0, port_base + PORT_CPB_PTQFIFO);
|
||||||
writeb(0, port_base + PORT_CPB_PTQFIFO);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
return ata_sff_qc_issue(qc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void inic_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
|
static void inic_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
|
||||||
|
@ -698,6 +716,7 @@ static int inic_port_start(struct ata_port *ap)
|
||||||
static struct ata_port_operations inic_port_ops = {
|
static struct ata_port_operations inic_port_ops = {
|
||||||
.inherits = &ata_sff_port_ops,
|
.inherits = &ata_sff_port_ops,
|
||||||
|
|
||||||
|
.check_atapi_dma = inic_check_atapi_dma,
|
||||||
.qc_prep = inic_qc_prep,
|
.qc_prep = inic_qc_prep,
|
||||||
.qc_issue = inic_qc_issue,
|
.qc_issue = inic_qc_issue,
|
||||||
.qc_fill_rtf = inic_qc_fill_rtf,
|
.qc_fill_rtf = inic_qc_fill_rtf,
|
||||||
|
@ -717,12 +736,6 @@ static struct ata_port_operations inic_port_ops = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ata_port_info inic_port_info = {
|
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,
|
.flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA,
|
||||||
.pio_mask = 0x1f, /* pio0-4 */
|
.pio_mask = 0x1f, /* pio0-4 */
|
||||||
.mwdma_mask = 0x07, /* mwdma0-2 */
|
.mwdma_mask = 0x07, /* mwdma0-2 */
|
||||||
|
|
Reference in New Issue