Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 67651ee5 authored by Jeff Garzik's avatar Jeff Garzik Committed by Jeff Garzik
Browse files

[libata] sata_sx4: convert to new exception handling methods



Signed-off-by: default avatarJeff Garzik <jgarzik@redhat.com>
parent 5d41343a
Loading
Loading
Loading
Loading
+121 −45
Original line number Diff line number Diff line
@@ -213,8 +213,9 @@ struct pdc_host_priv {


static int pdc_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static void pdc_eng_timeout(struct ata_port *ap);
static void pdc_20621_phy_reset(struct ata_port *ap);
static void pdc_error_handler(struct ata_port *ap);
static void pdc_freeze(struct ata_port *ap);
static void pdc_thaw(struct ata_port *ap);
static int pdc_port_start(struct ata_port *ap);
static void pdc20621_qc_prep(struct ata_queued_cmd *qc);
static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
@@ -233,6 +234,10 @@ static void pdc20621_put_to_dimm(struct ata_host *host,
				 void *psource, u32 offset, u32 size);
static void pdc20621_irq_clear(struct ata_port *ap);
static unsigned int pdc20621_qc_issue(struct ata_queued_cmd *qc);
static int pdc_softreset(struct ata_link *link, unsigned int *class,
			 unsigned long deadline);
static void pdc_post_internal_cmd(struct ata_queued_cmd *qc);
static int pdc_check_atapi_dma(struct ata_queued_cmd *qc);


static struct scsi_host_template pdc_sata_sht = {
@@ -243,20 +248,24 @@ static struct scsi_host_template pdc_sata_sht = {

/* TODO: inherit from base port_ops after converting to new EH */
static struct ata_port_operations pdc_20621_ops = {
	.sff_tf_load		= pdc_tf_load_mmio,
	.sff_tf_read		= ata_sff_tf_read,
	.sff_check_status	= ata_sff_check_status,
	.sff_exec_command	= pdc_exec_command_mmio,
	.sff_dev_select		= ata_sff_dev_select,
	.phy_reset		= pdc_20621_phy_reset,
	.inherits		= &ata_sff_port_ops,

	.check_atapi_dma	= pdc_check_atapi_dma,
	.qc_prep		= pdc20621_qc_prep,
	.qc_issue		= pdc20621_qc_issue,
	.qc_fill_rtf		= ata_sff_qc_fill_rtf,
	.sff_data_xfer		= ata_sff_data_xfer,
	.eng_timeout		= pdc_eng_timeout,
	.sff_irq_clear		= pdc20621_irq_clear,
	.sff_irq_on		= ata_sff_irq_on,

	.freeze			= pdc_freeze,
	.thaw			= pdc_thaw,
	.softreset		= pdc_softreset,
	.error_handler		= pdc_error_handler,
	.lost_interrupt		= ATA_OP_NULL,
	.post_internal_cmd	= pdc_post_internal_cmd,

	.port_start		= pdc_port_start,

	.sff_tf_load		= pdc_tf_load_mmio,
	.sff_exec_command	= pdc_exec_command_mmio,
	.sff_irq_clear		= pdc20621_irq_clear,
};

static const struct ata_port_info pdc_port_info[] = {
@@ -310,14 +319,6 @@ static int pdc_port_start(struct ata_port *ap)
	return 0;
}

static void pdc_20621_phy_reset(struct ata_port *ap)
{
	VPRINTK("ENTER\n");
	ap->cbl = ATA_CBL_SATA;
	ata_port_probe(ap);
	ata_bus_reset(ap);
}

static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf,
				   unsigned int portno,
					   unsigned int total_len)
@@ -859,40 +860,115 @@ static irqreturn_t pdc20621_interrupt(int irq, void *dev_instance)
	return IRQ_RETVAL(handled);
}

static void pdc_eng_timeout(struct ata_port *ap)
static void pdc_freeze(struct ata_port *ap)
{
	u8 drv_stat;
	struct ata_host *host = ap->host;
	struct ata_queued_cmd *qc;
	unsigned long flags;
	void __iomem *mmio = ap->ioaddr.cmd_addr;
	u32 tmp;

	DPRINTK("ENTER\n");
	/* FIXME: if all 4 ATA engines are stopped, also stop HDMA engine */

	spin_lock_irqsave(&host->lock, flags);
	tmp = readl(mmio + PDC_CTLSTAT);
	tmp |= PDC_MASK_INT;
	tmp &= ~PDC_DMA_ENABLE;
	writel(tmp, mmio + PDC_CTLSTAT);
	readl(mmio + PDC_CTLSTAT); /* flush */
}

	qc = ata_qc_from_tag(ap, ap->link.active_tag);
static void pdc_thaw(struct ata_port *ap)
{
	void __iomem *mmio = ap->ioaddr.cmd_addr;
	void __iomem *mmio_base;
	u32 tmp;

	switch (qc->tf.protocol) {
	case ATA_PROT_DMA:
	case ATA_PROT_NODATA:
		ata_port_printk(ap, KERN_ERR, "command timeout\n");
		qc->err_mask |= __ac_err_mask(ata_wait_idle(ap));
		break;
	/* FIXME: start HDMA engine, if zero ATA engines running */

	default:
		drv_stat = ata_sff_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
	/* reading SEQ mask register clears IRQ */
	mmio_base = ap->host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS;
	readl(mmio_base + PDC_20621_SEQMASK);

	/* turn IRQ back on */
	tmp = readl(mmio + PDC_CTLSTAT);
	tmp &= ~PDC_MASK_INT;
	writel(tmp, mmio + PDC_CTLSTAT);
	readl(mmio + PDC_CTLSTAT); /* flush */
}

static void pdc_reset_port(struct ata_port *ap)
{
	void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_CTLSTAT;
	unsigned int i;
	u32 tmp;

		ata_port_printk(ap, KERN_ERR,
				"unknown timeout, cmd 0x%x stat 0x%x\n",
				qc->tf.command, drv_stat);
	/* FIXME: handle HDMA copy engine */

		qc->err_mask |= ac_err_mask(drv_stat);
	for (i = 11; i > 0; i--) {
		tmp = readl(mmio);
		if (tmp & PDC_RESET)
			break;

		udelay(100);

		tmp |= PDC_RESET;
		writel(tmp, mmio);
	}

	tmp &= ~PDC_RESET;
	writel(tmp, mmio);
	readl(mmio);	/* flush */
}

	spin_unlock_irqrestore(&host->lock, flags);
	ata_eh_qc_complete(qc);
	DPRINTK("EXIT\n");
static int pdc_softreset(struct ata_link *link, unsigned int *class,
			 unsigned long deadline)
{
	pdc_reset_port(link->ap);
	return ata_sff_softreset(link, class, deadline);
}

static void pdc_error_handler(struct ata_port *ap)
{
	if (!(ap->pflags & ATA_PFLAG_FROZEN))
		pdc_reset_port(ap);

	ata_std_error_handler(ap);
}

static void pdc_post_internal_cmd(struct ata_queued_cmd *qc)
{
	struct ata_port *ap = qc->ap;

	/* make DMA engine forget about the failed command */
	if (qc->flags & ATA_QCFLAG_FAILED)
		pdc_reset_port(ap);
}

static int pdc_check_atapi_dma(struct ata_queued_cmd *qc)
{
	u8 *scsicmd = qc->scsicmd->cmnd;
	int pio = 1; /* atapi dma off by default */

	/* Whitelist commands that may use DMA. */
	switch (scsicmd[0]) {
	case WRITE_12:
	case WRITE_10:
	case WRITE_6:
	case READ_12:
	case READ_10:
	case READ_6:
	case 0xad: /* READ_DVD_STRUCTURE */
	case 0xbe: /* READ_CD */
		pio = 0;
	}
	/* -45150 (FFFF4FA2) to -1 (FFFFFFFF) shall use PIO mode */
	if (scsicmd[0] == WRITE_10) {
		unsigned int lba =
			(scsicmd[2] << 24) |
			(scsicmd[3] << 16) |
			(scsicmd[4] << 8) |
			scsicmd[5];
		if (lba >= 0xFFFF4FA2)
			pio = 1;
	}
	return pio;
}

static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)