Merge branch 'upstream-fixes' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev
This commit is contained in:
commit
d4bf205305
2 changed files with 162 additions and 38 deletions
|
@ -2,6 +2,7 @@
|
||||||
* sata_mv.c - Marvell SATA support
|
* sata_mv.c - Marvell SATA support
|
||||||
*
|
*
|
||||||
* Copyright 2005: EMC Corporation, all rights reserved.
|
* Copyright 2005: EMC Corporation, all rights reserved.
|
||||||
|
* Copyright 2005 Red Hat, Inc. All rights reserved.
|
||||||
*
|
*
|
||||||
* Please ALWAYS copy linux-ide@vger.kernel.org on emails.
|
* Please ALWAYS copy linux-ide@vger.kernel.org on emails.
|
||||||
*
|
*
|
||||||
|
@ -36,7 +37,7 @@
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
|
||||||
#define DRV_NAME "sata_mv"
|
#define DRV_NAME "sata_mv"
|
||||||
#define DRV_VERSION "0.25"
|
#define DRV_VERSION "0.5"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
/* BAR's are enumerated in terms of pci_resource_start() terms */
|
/* BAR's are enumerated in terms of pci_resource_start() terms */
|
||||||
|
|
|
@ -5,17 +5,6 @@
|
||||||
*
|
*
|
||||||
* Based on preview driver from Silicon Image.
|
* Based on preview driver from Silicon Image.
|
||||||
*
|
*
|
||||||
* NOTE: No NCQ/ATAPI support yet. The preview driver didn't support
|
|
||||||
* NCQ nor ATAPI, and, unfortunately, I couldn't find out how to make
|
|
||||||
* those work. Enabling those shouldn't be difficult. Basic
|
|
||||||
* structure is all there (in libata-dev tree). If you have any
|
|
||||||
* information about this hardware, please contact me or linux-ide.
|
|
||||||
* Info is needed on...
|
|
||||||
*
|
|
||||||
* - How to issue tagged commands and turn on sactive on issue accordingly.
|
|
||||||
* - Where to put an ATAPI command and how to tell the device to send it.
|
|
||||||
* - How to enable/use 64bit.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the
|
* under the terms of the GNU General Public License as published by the
|
||||||
* Free Software Foundation; either version 2, or (at your option) any
|
* Free Software Foundation; either version 2, or (at your option) any
|
||||||
|
@ -42,7 +31,7 @@
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
|
||||||
#define DRV_NAME "sata_sil24"
|
#define DRV_NAME "sata_sil24"
|
||||||
#define DRV_VERSION "0.22" /* Silicon Image's preview driver was 0.10 */
|
#define DRV_VERSION "0.23"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Port request block (PRB) 32 bytes
|
* Port request block (PRB) 32 bytes
|
||||||
|
@ -221,11 +210,22 @@ enum {
|
||||||
IRQ_STAT_4PORTS = 0xf,
|
IRQ_STAT_4PORTS = 0xf,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sil24_cmd_block {
|
struct sil24_ata_block {
|
||||||
struct sil24_prb prb;
|
struct sil24_prb prb;
|
||||||
struct sil24_sge sge[LIBATA_MAX_PRD];
|
struct sil24_sge sge[LIBATA_MAX_PRD];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct sil24_atapi_block {
|
||||||
|
struct sil24_prb prb;
|
||||||
|
u8 cdb[16];
|
||||||
|
struct sil24_sge sge[LIBATA_MAX_PRD - 1];
|
||||||
|
};
|
||||||
|
|
||||||
|
union sil24_cmd_block {
|
||||||
|
struct sil24_ata_block ata;
|
||||||
|
struct sil24_atapi_block atapi;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ap->private_data
|
* ap->private_data
|
||||||
*
|
*
|
||||||
|
@ -233,7 +233,7 @@ struct sil24_cmd_block {
|
||||||
* here from the previous interrupt.
|
* here from the previous interrupt.
|
||||||
*/
|
*/
|
||||||
struct sil24_port_priv {
|
struct sil24_port_priv {
|
||||||
struct sil24_cmd_block *cmd_block; /* 32 cmd blocks */
|
union sil24_cmd_block *cmd_block; /* 32 cmd blocks */
|
||||||
dma_addr_t cmd_block_dma; /* DMA base addr for them */
|
dma_addr_t cmd_block_dma; /* DMA base addr for them */
|
||||||
struct ata_taskfile tf; /* Cached taskfile registers */
|
struct ata_taskfile tf; /* Cached taskfile registers */
|
||||||
};
|
};
|
||||||
|
@ -244,6 +244,7 @@ struct sil24_host_priv {
|
||||||
void __iomem *port_base; /* port registers (4 * 8192 bytes @BAR2) */
|
void __iomem *port_base; /* port registers (4 * 8192 bytes @BAR2) */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev);
|
||||||
static u8 sil24_check_status(struct ata_port *ap);
|
static u8 sil24_check_status(struct ata_port *ap);
|
||||||
static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
|
static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
|
||||||
static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
|
static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
|
||||||
|
@ -297,6 +298,8 @@ static struct scsi_host_template sil24_sht = {
|
||||||
static const struct ata_port_operations sil24_ops = {
|
static const struct ata_port_operations sil24_ops = {
|
||||||
.port_disable = ata_port_disable,
|
.port_disable = ata_port_disable,
|
||||||
|
|
||||||
|
.dev_config = sil24_dev_config,
|
||||||
|
|
||||||
.check_status = sil24_check_status,
|
.check_status = sil24_check_status,
|
||||||
.check_altstatus = sil24_check_status,
|
.check_altstatus = sil24_check_status,
|
||||||
.dev_select = ata_noop_dev_select,
|
.dev_select = ata_noop_dev_select,
|
||||||
|
@ -333,7 +336,7 @@ static struct ata_port_info sil24_port_info[] = {
|
||||||
{
|
{
|
||||||
.sht = &sil24_sht,
|
.sht = &sil24_sht,
|
||||||
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
|
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
|
||||||
ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
|
ATA_FLAG_SRST | ATA_FLAG_MMIO |
|
||||||
ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(4),
|
ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(4),
|
||||||
.pio_mask = 0x1f, /* pio0-4 */
|
.pio_mask = 0x1f, /* pio0-4 */
|
||||||
.mwdma_mask = 0x07, /* mwdma0-2 */
|
.mwdma_mask = 0x07, /* mwdma0-2 */
|
||||||
|
@ -344,7 +347,7 @@ static struct ata_port_info sil24_port_info[] = {
|
||||||
{
|
{
|
||||||
.sht = &sil24_sht,
|
.sht = &sil24_sht,
|
||||||
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
|
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
|
||||||
ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
|
ATA_FLAG_SRST | ATA_FLAG_MMIO |
|
||||||
ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(2),
|
ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(2),
|
||||||
.pio_mask = 0x1f, /* pio0-4 */
|
.pio_mask = 0x1f, /* pio0-4 */
|
||||||
.mwdma_mask = 0x07, /* mwdma0-2 */
|
.mwdma_mask = 0x07, /* mwdma0-2 */
|
||||||
|
@ -355,7 +358,7 @@ static struct ata_port_info sil24_port_info[] = {
|
||||||
{
|
{
|
||||||
.sht = &sil24_sht,
|
.sht = &sil24_sht,
|
||||||
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
|
.host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
|
||||||
ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
|
ATA_FLAG_SRST | ATA_FLAG_MMIO |
|
||||||
ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(1),
|
ATA_FLAG_PIO_DMA | SIL24_NPORTS2FLAG(1),
|
||||||
.pio_mask = 0x1f, /* pio0-4 */
|
.pio_mask = 0x1f, /* pio0-4 */
|
||||||
.mwdma_mask = 0x07, /* mwdma0-2 */
|
.mwdma_mask = 0x07, /* mwdma0-2 */
|
||||||
|
@ -364,6 +367,16 @@ static struct ata_port_info sil24_port_info[] = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev)
|
||||||
|
{
|
||||||
|
void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
|
||||||
|
|
||||||
|
if (ap->cdb_len == 16)
|
||||||
|
writel(PORT_CS_CDB16, port + PORT_CTRL_STAT);
|
||||||
|
else
|
||||||
|
writel(PORT_CS_CDB16, port + PORT_CTRL_CLR);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void sil24_update_tf(struct ata_port *ap)
|
static inline void sil24_update_tf(struct ata_port *ap)
|
||||||
{
|
{
|
||||||
struct sil24_port_priv *pp = ap->private_data;
|
struct sil24_port_priv *pp = ap->private_data;
|
||||||
|
@ -415,22 +428,73 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
|
||||||
*tf = pp->tf;
|
*tf = pp->tf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sil24_issue_SRST(struct ata_port *ap)
|
||||||
|
{
|
||||||
|
void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
|
||||||
|
struct sil24_port_priv *pp = ap->private_data;
|
||||||
|
struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
|
||||||
|
dma_addr_t paddr = pp->cmd_block_dma;
|
||||||
|
u32 irq_enable, irq_stat;
|
||||||
|
int cnt;
|
||||||
|
|
||||||
|
/* temporarily turn off IRQs during SRST */
|
||||||
|
irq_enable = readl(port + PORT_IRQ_ENABLE_SET);
|
||||||
|
writel(irq_enable, port + PORT_IRQ_ENABLE_CLR);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX: Not sure whether the following sleep is needed or not.
|
||||||
|
* The original driver had it. So....
|
||||||
|
*/
|
||||||
|
msleep(10);
|
||||||
|
|
||||||
|
prb->ctrl = PRB_CTRL_SRST;
|
||||||
|
prb->fis[1] = 0; /* no PM yet */
|
||||||
|
|
||||||
|
writel((u32)paddr, port + PORT_CMD_ACTIVATE);
|
||||||
|
|
||||||
|
for (cnt = 0; cnt < 100; cnt++) {
|
||||||
|
irq_stat = readl(port + PORT_IRQ_STAT);
|
||||||
|
writel(irq_stat, port + PORT_IRQ_STAT); /* clear irq */
|
||||||
|
|
||||||
|
irq_stat >>= PORT_IRQ_RAW_SHIFT;
|
||||||
|
if (irq_stat & (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR))
|
||||||
|
break;
|
||||||
|
|
||||||
|
msleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* restore IRQs */
|
||||||
|
writel(irq_enable, port + PORT_IRQ_ENABLE_SET);
|
||||||
|
|
||||||
|
if (!(irq_stat & PORT_IRQ_COMPLETE))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* update TF */
|
||||||
|
sil24_update_tf(ap);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void sil24_phy_reset(struct ata_port *ap)
|
static void sil24_phy_reset(struct ata_port *ap)
|
||||||
{
|
{
|
||||||
|
struct sil24_port_priv *pp = ap->private_data;
|
||||||
|
|
||||||
__sata_phy_reset(ap);
|
__sata_phy_reset(ap);
|
||||||
/*
|
if (ap->flags & ATA_FLAG_PORT_DISABLED)
|
||||||
* No ATAPI yet. Just unconditionally indicate ATA device.
|
return;
|
||||||
* If ATAPI device is attached, it will fail ATA_CMD_ID_ATA
|
|
||||||
* and libata core will ignore the device.
|
if (sil24_issue_SRST(ap) < 0) {
|
||||||
*/
|
printk(KERN_ERR DRV_NAME
|
||||||
if (!(ap->flags & ATA_FLAG_PORT_DISABLED))
|
" ata%u: SRST failed, disabling port\n", ap->id);
|
||||||
ap->device[0].class = ATA_DEV_ATA;
|
ap->ops->port_disable(ap);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ap->device->class = ata_dev_classify(&pp->tf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
|
static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
|
||||||
struct sil24_cmd_block *cb)
|
struct sil24_sge *sge)
|
||||||
{
|
{
|
||||||
struct sil24_sge *sge = cb->sge;
|
|
||||||
struct scatterlist *sg;
|
struct scatterlist *sg;
|
||||||
unsigned int idx = 0;
|
unsigned int idx = 0;
|
||||||
|
|
||||||
|
@ -451,23 +515,47 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
|
||||||
{
|
{
|
||||||
struct ata_port *ap = qc->ap;
|
struct ata_port *ap = qc->ap;
|
||||||
struct sil24_port_priv *pp = ap->private_data;
|
struct sil24_port_priv *pp = ap->private_data;
|
||||||
struct sil24_cmd_block *cb = pp->cmd_block + qc->tag;
|
union sil24_cmd_block *cb = pp->cmd_block + qc->tag;
|
||||||
struct sil24_prb *prb = &cb->prb;
|
struct sil24_prb *prb;
|
||||||
|
struct sil24_sge *sge;
|
||||||
|
|
||||||
switch (qc->tf.protocol) {
|
switch (qc->tf.protocol) {
|
||||||
case ATA_PROT_PIO:
|
case ATA_PROT_PIO:
|
||||||
case ATA_PROT_DMA:
|
case ATA_PROT_DMA:
|
||||||
case ATA_PROT_NODATA:
|
case ATA_PROT_NODATA:
|
||||||
|
prb = &cb->ata.prb;
|
||||||
|
sge = cb->ata.sge;
|
||||||
|
prb->ctrl = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ATA_PROT_ATAPI:
|
||||||
|
case ATA_PROT_ATAPI_DMA:
|
||||||
|
case ATA_PROT_ATAPI_NODATA:
|
||||||
|
prb = &cb->atapi.prb;
|
||||||
|
sge = cb->atapi.sge;
|
||||||
|
memset(cb->atapi.cdb, 0, 32);
|
||||||
|
memcpy(cb->atapi.cdb, qc->cdb, ap->cdb_len);
|
||||||
|
|
||||||
|
if (qc->tf.protocol != ATA_PROT_ATAPI_NODATA) {
|
||||||
|
if (qc->tf.flags & ATA_TFLAG_WRITE)
|
||||||
|
prb->ctrl = PRB_CTRL_PACKET_WRITE;
|
||||||
|
else
|
||||||
|
prb->ctrl = PRB_CTRL_PACKET_READ;
|
||||||
|
} else
|
||||||
|
prb->ctrl = 0;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* ATAPI isn't supported yet */
|
prb = NULL; /* shut up, gcc */
|
||||||
|
sge = NULL;
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
|
||||||
ata_tf_to_fis(&qc->tf, prb->fis, 0);
|
ata_tf_to_fis(&qc->tf, prb->fis, 0);
|
||||||
|
|
||||||
if (qc->flags & ATA_QCFLAG_DMAMAP)
|
if (qc->flags & ATA_QCFLAG_DMAMAP)
|
||||||
sil24_fill_sg(qc, cb);
|
sil24_fill_sg(qc, sge);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sil24_qc_issue(struct ata_queued_cmd *qc)
|
static int sil24_qc_issue(struct ata_queued_cmd *qc)
|
||||||
|
@ -486,6 +574,31 @@ static void sil24_irq_clear(struct ata_port *ap)
|
||||||
/* unused */
|
/* unused */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __sil24_restart_controller(void __iomem *port)
|
||||||
|
{
|
||||||
|
u32 tmp;
|
||||||
|
int cnt;
|
||||||
|
|
||||||
|
writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
|
||||||
|
|
||||||
|
/* Max ~10ms */
|
||||||
|
for (cnt = 0; cnt < 10000; cnt++) {
|
||||||
|
tmp = readl(port + PORT_CTRL_STAT);
|
||||||
|
if (tmp & PORT_CS_RDY)
|
||||||
|
return 0;
|
||||||
|
udelay(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sil24_restart_controller(struct ata_port *ap)
|
||||||
|
{
|
||||||
|
if (__sil24_restart_controller((void __iomem *)ap->ioaddr.cmd_addr))
|
||||||
|
printk(KERN_ERR DRV_NAME
|
||||||
|
" ata%u: failed to restart controller\n", ap->id);
|
||||||
|
}
|
||||||
|
|
||||||
static int __sil24_reset_controller(void __iomem *port)
|
static int __sil24_reset_controller(void __iomem *port)
|
||||||
{
|
{
|
||||||
int cnt;
|
int cnt;
|
||||||
|
@ -505,7 +618,11 @@ static int __sil24_reset_controller(void __iomem *port)
|
||||||
|
|
||||||
if (tmp & PORT_CS_DEV_RST)
|
if (tmp & PORT_CS_DEV_RST)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (tmp & PORT_CS_RDY)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
return __sil24_restart_controller(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sil24_reset_controller(struct ata_port *ap)
|
static void sil24_reset_controller(struct ata_port *ap)
|
||||||
|
@ -567,7 +684,13 @@ static void sil24_error_intr(struct ata_port *ap, u32 slot_stat)
|
||||||
if (serror)
|
if (serror)
|
||||||
writel(serror, port + PORT_SERROR);
|
writel(serror, port + PORT_SERROR);
|
||||||
|
|
||||||
printk(KERN_ERR DRV_NAME " ata%u: error interrupt on port%d\n"
|
/*
|
||||||
|
* Don't log ATAPI device errors. They're supposed to happen
|
||||||
|
* and any serious errors will be logged using sense data by
|
||||||
|
* the SCSI layer.
|
||||||
|
*/
|
||||||
|
if (ap->device[0].class != ATA_DEV_ATAPI || cmd_err > PORT_CERR_SDB)
|
||||||
|
printk("ata%u: error interrupt on port%d\n"
|
||||||
" stat=0x%x irq=0x%x cmd_err=%d sstatus=0x%x serror=0x%x\n",
|
" stat=0x%x irq=0x%x cmd_err=%d sstatus=0x%x serror=0x%x\n",
|
||||||
ap->id, ap->port_no, slot_stat, irq_stat, cmd_err, sstatus, serror);
|
ap->id, ap->port_no, slot_stat, irq_stat, cmd_err, sstatus, serror);
|
||||||
|
|
||||||
|
@ -577,6 +700,7 @@ static void sil24_error_intr(struct ata_port *ap, u32 slot_stat)
|
||||||
*/
|
*/
|
||||||
sil24_update_tf(ap);
|
sil24_update_tf(ap);
|
||||||
err_mask = ac_err_mask(pp->tf.command);
|
err_mask = ac_err_mask(pp->tf.command);
|
||||||
|
sil24_restart_controller(ap);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Other errors. libata currently doesn't have any
|
* Other errors. libata currently doesn't have any
|
||||||
|
@ -584,12 +708,11 @@ static void sil24_error_intr(struct ata_port *ap, u32 slot_stat)
|
||||||
* ATA_ERR.
|
* ATA_ERR.
|
||||||
*/
|
*/
|
||||||
err_mask = AC_ERR_OTHER;
|
err_mask = AC_ERR_OTHER;
|
||||||
|
sil24_reset_controller(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qc)
|
if (qc)
|
||||||
ata_qc_complete(qc, err_mask);
|
ata_qc_complete(qc, err_mask);
|
||||||
|
|
||||||
sil24_reset_controller(ap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void sil24_host_intr(struct ata_port *ap)
|
static inline void sil24_host_intr(struct ata_port *ap)
|
||||||
|
@ -665,7 +788,7 @@ static int sil24_port_start(struct ata_port *ap)
|
||||||
{
|
{
|
||||||
struct device *dev = ap->host_set->dev;
|
struct device *dev = ap->host_set->dev;
|
||||||
struct sil24_port_priv *pp;
|
struct sil24_port_priv *pp;
|
||||||
struct sil24_cmd_block *cb;
|
union sil24_cmd_block *cb;
|
||||||
size_t cb_size = sizeof(*cb);
|
size_t cb_size = sizeof(*cb);
|
||||||
dma_addr_t cb_dma;
|
dma_addr_t cb_dma;
|
||||||
int rc = -ENOMEM;
|
int rc = -ENOMEM;
|
||||||
|
|
Loading…
Reference in a new issue