#include <asm/io.h>
#define DRV_NAME "sata_sil24"
-#define DRV_VERSION "0.24"
+#define DRV_VERSION "0.3"
/*
* Port request block (PRB) 32 bytes
*/
struct sil24_prb {
- u16 ctrl;
- u16 prot;
- u32 rx_cnt;
+ __le16 ctrl;
+ __le16 prot;
+ __le32 rx_cnt;
u8 fis[6 * 4];
};
* Scatter gather entry (SGE) 16 bytes
*/
struct sil24_sge {
- u64 addr;
- u32 cnt;
- u32 flags;
+ __le64 addr;
+ __le32 cnt;
+ __le32 flags;
};
/*
* Port multiplier
*/
struct sil24_port_multiplier {
- u32 diag;
- u32 sactive;
+ __le32 diag;
+ __le32 sactive;
};
enum {
* (8192 bytes @ +0x0000, +0x2000, +0x4000 and +0x6000 @ BAR2)
*/
PORT_REGS_SIZE = 0x2000,
- PORT_PRB = 0x0000, /* (32 bytes PRB + 16 bytes SGEs * 6) * 31 (3968 bytes) */
+
+ PORT_LRAM = 0x0000, /* 31 LRAM slots and PM regs */
+ PORT_LRAM_SLOT_SZ = 0x0080, /* 32 bytes PRB + 2 SGE, ACT... */
PORT_PM = 0x0f80, /* 8 bytes PM * 16 (128 bytes) */
/* 32 bit regs */
PORT_IRQ_SDB_NOTIFY = (1 << 11), /* SDB notify received */
DEF_PORT_IRQ = PORT_IRQ_COMPLETE | PORT_IRQ_ERROR |
- PORT_IRQ_DEV_XCHG | PORT_IRQ_UNK_FIS,
+ PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG |
+ PORT_IRQ_UNK_FIS,
/* bits[27:16] are unmasked (raw) */
PORT_IRQ_RAW_SHIFT = 16,
SGE_DRD = (1 << 29), /* discard data read (/dev/null)
data address ignored */
+ SIL24_MAX_CMDS = 31,
+
/* board id */
BID_SIL3124 = 0,
BID_SIL3132 = 1,
/* host flags */
SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+ ATA_FLAG_NCQ | ATA_FLAG_SKIP_D2H_BSY,
SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */
IRQ_STAT_4PORTS = 0xf,
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_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
-static int sil24_probe_reset(struct ata_port *ap, unsigned int *classes);
static void sil24_qc_prep(struct ata_queued_cmd *qc);
static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
static void sil24_irq_clear(struct ata_port *ap);
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
- .can_queue = ATA_DEF_QUEUE,
+ .change_queue_depth = ata_scsi_change_queue_depth,
+ .can_queue = SIL24_MAX_CMDS,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = LIBATA_MAX_PRD,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.proc_name = DRV_NAME,
.dma_boundary = ATA_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
};
.tf_read = sil24_tf_read,
- .probe_reset = sil24_probe_reset,
-
.qc_prep = sil24_qc_prep,
.qc_issue = sil24_qc_issue,
},
};
+static int sil24_tag(int tag)
+{
+ if (unlikely(ata_tag_internal(tag)))
+ return 0;
+ return tag;
+}
+
static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev)
{
void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
{
void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
const char *reason;
- int tout_msec;
+ int tout_msec, rc;
u32 tmp;
/* sil24 does the right thing(tm) without any protection */
tmp = ata_wait_register(port + PORT_CTRL_STAT,
PORT_CS_DEV_RST, PORT_CS_DEV_RST, 10, tout_msec);
- /* SStatus oscillates between zero and valid status for short
- * duration after DEV_RST, give it time to settle.
+ /* SStatus oscillates between zero and valid status after
+ * DEV_RST, debounce it.
*/
- msleep(100);
+ rc = sata_phy_debounce(ap, sata_deb_timing_before_fsrst);
+ if (rc) {
+ reason = "PHY debouncing failed";
+ goto err;
+ }
if (tmp & PORT_CS_DEV_RST) {
if (ata_port_offline(ap))
goto err;
}
- if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
- reason = "device not ready";
- goto err;
- }
-
- /* sil24 doesn't report device class code after hardreset,
- * leave *class alone.
+ /* Sil24 doesn't store signature FIS after hardreset, so we
+ * can't wait for BSY to clear. Some devices take a long time
+ * to get ready and those devices will choke if we don't wait
+ * for BSY clearance here. Tell libata to perform follow-up
+ * softreset.
*/
- return 0;
+ return -EAGAIN;
err:
ata_port_printk(ap, KERN_ERR, "hardreset failed (%s)\n", reason);
return -EIO;
}
-static int sil24_probe_reset(struct ata_port *ap, unsigned int *classes)
-{
- return ata_drive_probe_reset(ap, ata_std_probeinit,
- sil24_softreset, sil24_hardreset,
- ata_std_postreset, classes);
-}
-
static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
struct sil24_sge *sge)
{
{
struct ata_port *ap = qc->ap;
struct sil24_port_priv *pp = ap->private_data;
- union sil24_cmd_block *cb = pp->cmd_block + qc->tag;
+ union sil24_cmd_block *cb;
struct sil24_prb *prb;
struct sil24_sge *sge;
u16 ctrl = 0;
+ cb = &pp->cmd_block[sil24_tag(qc->tag)];
+
switch (qc->tf.protocol) {
case ATA_PROT_PIO:
case ATA_PROT_DMA:
+ case ATA_PROT_NCQ:
case ATA_PROT_NODATA:
prb = &cb->ata.prb;
sge = cb->ata.sge;
static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
struct sil24_port_priv *pp = ap->private_data;
- dma_addr_t paddr = pp->cmd_block_dma + qc->tag * sizeof(*pp->cmd_block);
+ void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
+ unsigned int tag = sil24_tag(qc->tag);
+ dma_addr_t paddr;
+ void __iomem *activate;
- writel((u32)paddr, port + PORT_CMD_ACTIVATE);
- writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
+ paddr = pp->cmd_block_dma + tag * sizeof(*pp->cmd_block);
+ activate = port + PORT_CMD_ACTIVATE + tag * 8;
+
+ writel((u32)paddr, activate);
+ writel((u64)paddr >> 32, activate + 4);
return 0;
}
ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
- if (irq_stat & PORT_IRQ_DEV_XCHG) {
- ehi->err_mask |= AC_ERR_ATA_BUS;
- /* sil24 doesn't recover very well from phy
- * disconnection with a softreset. Force hardreset.
- */
- ehi->action |= ATA_EH_HARDRESET;
- ata_ehi_push_desc(ehi, ", device_exchanged");
+ if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) {
+ ata_ehi_hotplugged(ehi);
+ ata_ehi_push_desc(ehi, ", %s",
+ irq_stat & PORT_IRQ_PHYRDY_CHG ?
+ "PHY RDY changed" : "device exchanged");
freeze = 1;
}
/* record error info */
qc = ata_qc_from_tag(ap, ap->active_tag);
if (qc) {
- int tag = qc->tag;
- if (unlikely(ata_tag_internal(tag)))
- tag = 0;
sil24_update_tf(ap);
qc->err_mask |= err_mask;
} else
ata_port_abort(ap);
}
+static void sil24_finish_qc(struct ata_queued_cmd *qc)
+{
+ if (qc->flags & ATA_QCFLAG_RESULT_TF)
+ sil24_update_tf(qc->ap);
+}
+
static inline void sil24_host_intr(struct ata_port *ap)
{
void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr;
- struct ata_queued_cmd *qc;
- u32 slot_stat;
+ u32 slot_stat, qc_active;
+ int rc;
slot_stat = readl(port + PORT_SLOT_STAT);
if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC)
writel(PORT_IRQ_COMPLETE, port + PORT_IRQ_STAT);
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc) {
- if (qc->flags & ATA_QCFLAG_RESULT_TF)
- sil24_update_tf(ap);
- ata_qc_complete(qc);
+ qc_active = slot_stat & ~HOST_SSTAT_ATTN;
+ rc = ata_qc_complete_multiple(ap, qc_active, sil24_finish_qc);
+ if (rc > 0)
+ return;
+ if (rc < 0) {
+ struct ata_eh_info *ehi = &ap->eh_info;
+ ehi->err_mask |= AC_ERR_HSM;
+ ehi->action |= ATA_EH_SOFTRESET;
+ ata_port_freeze(ap);
return;
}
if (ata_ratelimit())
ata_port_printk(ap, KERN_INFO, "spurious interrupt "
- "(slot_stat 0x%x active_tag %d)\n",
- slot_stat, ap->active_tag);
+ "(slot_stat 0x%x active_tag %d sactive 0x%x)\n",
+ slot_stat, ap->active_tag, ap->sactive);
}
static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
}
/* perform recovery */
- ata_do_eh(ap, sil24_softreset, sil24_hardreset, ata_std_postreset);
+ ata_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset,
+ ata_std_postreset);
}
static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
static inline void sil24_cblk_free(struct sil24_port_priv *pp, struct device *dev)
{
- const size_t cb_size = sizeof(*pp->cmd_block);
+ const size_t cb_size = sizeof(*pp->cmd_block) * SIL24_MAX_CMDS;
dma_free_coherent(dev, cb_size, pp->cmd_block, pp->cmd_block_dma);
}
struct device *dev = ap->host_set->dev;
struct sil24_port_priv *pp;
union sil24_cmd_block *cb;
- size_t cb_size = sizeof(*cb);
+ size_t cb_size = sizeof(*cb) * SIL24_MAX_CMDS;
dma_addr_t cb_dma;
int rc = -ENOMEM;
void __iomem *port = port_base + i * PORT_REGS_SIZE;
unsigned long portu = (unsigned long)port;
- probe_ent->port[i].cmd_addr = portu + PORT_PRB;
+ probe_ent->port[i].cmd_addr = portu;
probe_ent->port[i].scr_addr = portu + PORT_SCONTROL;
ata_std_ports(&probe_ent->port[i]);