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

Commit efa6e7e9 authored by Jeff Garzik's avatar Jeff Garzik
Browse files

Merge branch 'for-jeff' of git://htj.dyndns.org/libata-tj into tejun-merge

parents 5006ecc2 aee10a03
Loading
Loading
Loading
Loading
+210 −136
Original line number Original line Diff line number Diff line
@@ -56,12 +56,15 @@ enum {
	AHCI_MAX_SG		= 168, /* hardware max is 64K */
	AHCI_MAX_SG		= 168, /* hardware max is 64K */
	AHCI_DMA_BOUNDARY	= 0xffffffff,
	AHCI_DMA_BOUNDARY	= 0xffffffff,
	AHCI_USE_CLUSTERING	= 0,
	AHCI_USE_CLUSTERING	= 0,
	AHCI_CMD_SLOT_SZ	= 32 * 32,
	AHCI_MAX_CMDS		= 32,
	AHCI_CMD_SZ		= 32,
	AHCI_CMD_SLOT_SZ	= AHCI_MAX_CMDS * AHCI_CMD_SZ,
	AHCI_RX_FIS_SZ		= 256,
	AHCI_RX_FIS_SZ		= 256,
	AHCI_CMD_TBL_HDR	= 0x80,
	AHCI_CMD_TBL_CDB	= 0x40,
	AHCI_CMD_TBL_CDB	= 0x40,
	AHCI_CMD_TBL_SZ		= AHCI_CMD_TBL_HDR + (AHCI_MAX_SG * 16),
	AHCI_CMD_TBL_HDR_SZ	= 0x80,
	AHCI_PORT_PRIV_DMA_SZ	= AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_SZ +
	AHCI_CMD_TBL_SZ		= AHCI_CMD_TBL_HDR_SZ + (AHCI_MAX_SG * 16),
	AHCI_CMD_TBL_AR_SZ	= AHCI_CMD_TBL_SZ * AHCI_MAX_CMDS,
	AHCI_PORT_PRIV_DMA_SZ	= AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_AR_SZ +
				  AHCI_RX_FIS_SZ,
				  AHCI_RX_FIS_SZ,
	AHCI_IRQ_ON_SG		= (1 << 31),
	AHCI_IRQ_ON_SG		= (1 << 31),
	AHCI_CMD_ATAPI		= (1 << 5),
	AHCI_CMD_ATAPI		= (1 << 5),
@@ -71,6 +74,7 @@ enum {
	AHCI_CMD_CLR_BUSY	= (1 << 10),
	AHCI_CMD_CLR_BUSY	= (1 << 10),


	RX_FIS_D2H_REG		= 0x40,	/* offset of D2H Register FIS data */
	RX_FIS_D2H_REG		= 0x40,	/* offset of D2H Register FIS data */
	RX_FIS_UNK		= 0x60, /* offset of Unknown FIS data */


	board_ahci		= 0,
	board_ahci		= 0,
	board_ahci_vt8251	= 1,
	board_ahci_vt8251	= 1,
@@ -88,8 +92,9 @@ enum {
	HOST_AHCI_EN		= (1 << 31), /* AHCI enabled */
	HOST_AHCI_EN		= (1 << 31), /* AHCI enabled */


	/* HOST_CAP bits */
	/* HOST_CAP bits */
	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */
	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
	HOST_CAP_NCQ		= (1 << 30), /* Native Command Queueing */
	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */


	/* registers for each SATA port */
	/* registers for each SATA port */
	PORT_LST_ADDR		= 0x00, /* command list DMA addr */
	PORT_LST_ADDR		= 0x00, /* command list DMA addr */
@@ -128,15 +133,16 @@ enum {
	PORT_IRQ_PIOS_FIS	= (1 << 1), /* PIO Setup FIS rx'd */
	PORT_IRQ_PIOS_FIS	= (1 << 1), /* PIO Setup FIS rx'd */
	PORT_IRQ_D2H_REG_FIS	= (1 << 0), /* D2H Register FIS rx'd */
	PORT_IRQ_D2H_REG_FIS	= (1 << 0), /* D2H Register FIS rx'd */


	PORT_IRQ_FATAL		= PORT_IRQ_TF_ERR |
	PORT_IRQ_FREEZE		= PORT_IRQ_HBUS_ERR |
				  PORT_IRQ_HBUS_ERR |
				  PORT_IRQ_IF_ERR |
				  PORT_IRQ_HBUS_DATA_ERR |
				  PORT_IRQ_CONNECT |
				  PORT_IRQ_IF_ERR,
				  PORT_IRQ_UNK_FIS,
	DEF_PORT_IRQ		= PORT_IRQ_FATAL | PORT_IRQ_PHYRDY |
	PORT_IRQ_ERROR		= PORT_IRQ_FREEZE |
				  PORT_IRQ_CONNECT | PORT_IRQ_SG_DONE |
				  PORT_IRQ_TF_ERR |
				  PORT_IRQ_UNK_FIS | PORT_IRQ_SDB_FIS |
				  PORT_IRQ_HBUS_DATA_ERR,
				  PORT_IRQ_DMAS_FIS | PORT_IRQ_PIOS_FIS |
	DEF_PORT_IRQ		= PORT_IRQ_ERROR | PORT_IRQ_SG_DONE |
				  PORT_IRQ_D2H_REG_FIS,
				  PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS |
				  PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,


	/* PORT_CMD bits */
	/* PORT_CMD bits */
	PORT_CMD_ATAPI		= (1 << 24), /* Device is ATAPI */
	PORT_CMD_ATAPI		= (1 << 24), /* Device is ATAPI */
@@ -185,7 +191,6 @@ struct ahci_port_priv {
	dma_addr_t		cmd_slot_dma;
	dma_addr_t		cmd_slot_dma;
	void			*cmd_tbl;
	void			*cmd_tbl;
	dma_addr_t		cmd_tbl_dma;
	dma_addr_t		cmd_tbl_dma;
	struct ahci_sg		*cmd_tbl_sg;
	void			*rx_fis;
	void			*rx_fis;
	dma_addr_t		rx_fis_dma;
	dma_addr_t		rx_fis_dma;
};
};
@@ -197,13 +202,15 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes);
static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes);
static void ahci_irq_clear(struct ata_port *ap);
static void ahci_irq_clear(struct ata_port *ap);
static void ahci_eng_timeout(struct ata_port *ap);
static int ahci_port_start(struct ata_port *ap);
static int ahci_port_start(struct ata_port *ap);
static void ahci_port_stop(struct ata_port *ap);
static void ahci_port_stop(struct ata_port *ap);
static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
static void ahci_qc_prep(struct ata_queued_cmd *qc);
static void ahci_qc_prep(struct ata_queued_cmd *qc);
static u8 ahci_check_status(struct ata_port *ap);
static u8 ahci_check_status(struct ata_port *ap);
static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
static void ahci_freeze(struct ata_port *ap);
static void ahci_thaw(struct ata_port *ap);
static void ahci_error_handler(struct ata_port *ap);
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
static void ahci_remove_one (struct pci_dev *pdev);
static void ahci_remove_one (struct pci_dev *pdev);


static struct scsi_host_template ahci_sht = {
static struct scsi_host_template ahci_sht = {
@@ -211,7 +218,8 @@ static struct scsi_host_template ahci_sht = {
	.name			= DRV_NAME,
	.name			= DRV_NAME,
	.ioctl			= ata_scsi_ioctl,
	.ioctl			= ata_scsi_ioctl,
	.queuecommand		= ata_scsi_queuecmd,
	.queuecommand		= ata_scsi_queuecmd,
	.can_queue		= ATA_DEF_QUEUE,
	.change_queue_depth	= ata_scsi_change_queue_depth,
	.can_queue		= AHCI_MAX_CMDS - 1,
	.this_id		= ATA_SHT_THIS_ID,
	.this_id		= ATA_SHT_THIS_ID,
	.sg_tablesize		= AHCI_MAX_SG,
	.sg_tablesize		= AHCI_MAX_SG,
	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
@@ -237,14 +245,18 @@ static const struct ata_port_operations ahci_ops = {
	.qc_prep		= ahci_qc_prep,
	.qc_prep		= ahci_qc_prep,
	.qc_issue		= ahci_qc_issue,
	.qc_issue		= ahci_qc_issue,


	.eng_timeout		= ahci_eng_timeout,

	.irq_handler		= ahci_interrupt,
	.irq_handler		= ahci_interrupt,
	.irq_clear		= ahci_irq_clear,
	.irq_clear		= ahci_irq_clear,


	.scr_read		= ahci_scr_read,
	.scr_read		= ahci_scr_read,
	.scr_write		= ahci_scr_write,
	.scr_write		= ahci_scr_write,


	.freeze			= ahci_freeze,
	.thaw			= ahci_thaw,

	.error_handler		= ahci_error_handler,
	.post_internal_cmd	= ahci_post_internal_cmd,

	.port_start		= ahci_port_start,
	.port_start		= ahci_port_start,
	.port_stop		= ahci_port_stop,
	.port_stop		= ahci_port_stop,
};
};
@@ -390,8 +402,6 @@ static int ahci_port_start(struct ata_port *ap)
	pp->cmd_tbl = mem;
	pp->cmd_tbl = mem;
	pp->cmd_tbl_dma = mem_dma;
	pp->cmd_tbl_dma = mem_dma;


	pp->cmd_tbl_sg = mem + AHCI_CMD_TBL_HDR;

	ap->private_data = pp;
	ap->private_data = pp;


	if (hpriv->cap & HOST_CAP_64)
	if (hpriv->cap & HOST_CAP_64)
@@ -524,12 +534,17 @@ static unsigned int ahci_dev_classify(struct ata_port *ap)
	return ata_dev_classify(&tf);
	return ata_dev_classify(&tf);
}
}


static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, u32 opts)
static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
			       u32 opts)
{
{
	pp->cmd_slot[0].opts = cpu_to_le32(opts);
	dma_addr_t cmd_tbl_dma;
	pp->cmd_slot[0].status = 0;

	pp->cmd_slot[0].tbl_addr = cpu_to_le32(pp->cmd_tbl_dma & 0xffffffff);
	cmd_tbl_dma = pp->cmd_tbl_dma + tag * AHCI_CMD_TBL_SZ;
	pp->cmd_slot[0].tbl_addr_hi = cpu_to_le32((pp->cmd_tbl_dma >> 16) >> 16);

	pp->cmd_slot[tag].opts = cpu_to_le32(opts);
	pp->cmd_slot[tag].status = 0;
	pp->cmd_slot[tag].tbl_addr = cpu_to_le32(cmd_tbl_dma & 0xffffffff);
	pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
}
}


static int ahci_clo(struct ata_port *ap)
static int ahci_clo(struct ata_port *ap)
@@ -567,7 +582,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)


	DPRINTK("ENTER\n");
	DPRINTK("ENTER\n");


	if (!sata_dev_present(ap)) {
	if (ata_port_offline(ap)) {
		DPRINTK("PHY reports no device\n");
		DPRINTK("PHY reports no device\n");
		*class = ATA_DEV_NONE;
		*class = ATA_DEV_NONE;
		return 0;
		return 0;
@@ -597,11 +612,12 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
	/* restart engine */
	/* restart engine */
	ahci_start_engine(ap);
	ahci_start_engine(ap);


	ata_tf_init(ap, &tf, 0);
	ata_tf_init(ap->device, &tf);
	fis = pp->cmd_tbl;
	fis = pp->cmd_tbl;


	/* issue the first D2H Register FIS */
	/* issue the first D2H Register FIS */
	ahci_fill_cmd_slot(pp, cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
	ahci_fill_cmd_slot(pp, 0,
			   cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);


	tf.ctl |= ATA_SRST;
	tf.ctl |= ATA_SRST;
	ata_tf_to_fis(&tf, fis, 0);
	ata_tf_to_fis(&tf, fis, 0);
@@ -620,7 +636,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
	msleep(1);
	msleep(1);


	/* issue the second D2H Register FIS */
	/* issue the second D2H Register FIS */
	ahci_fill_cmd_slot(pp, cmd_fis_len);
	ahci_fill_cmd_slot(pp, 0, cmd_fis_len);


	tf.ctl &= ~ATA_SRST;
	tf.ctl &= ~ATA_SRST;
	ata_tf_to_fis(&tf, fis, 0);
	ata_tf_to_fis(&tf, fis, 0);
@@ -640,7 +656,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
	msleep(150);
	msleep(150);


	*class = ATA_DEV_NONE;
	*class = ATA_DEV_NONE;
	if (sata_dev_present(ap)) {
	if (ata_port_online(ap)) {
		if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
		if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
			rc = -EIO;
			rc = -EIO;
			reason = "device not ready";
			reason = "device not ready";
@@ -655,8 +671,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
 fail_restart:
 fail_restart:
	ahci_start_engine(ap);
	ahci_start_engine(ap);
 fail:
 fail:
	printk(KERN_ERR "ata%u: softreset failed (%s)\n",
	ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
	       ap->id, reason);
	return rc;
	return rc;
}
}


@@ -670,7 +685,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
	rc = sata_std_hardreset(ap, class);
	rc = sata_std_hardreset(ap, class);
	ahci_start_engine(ap);
	ahci_start_engine(ap);


	if (rc == 0)
	if (rc == 0 && ata_port_online(ap))
		*class = ahci_dev_classify(ap);
		*class = ahci_dev_classify(ap);
	if (*class == ATA_DEV_UNKNOWN)
	if (*class == ATA_DEV_UNKNOWN)
		*class = ATA_DEV_NONE;
		*class = ATA_DEV_NONE;
@@ -726,9 +741,8 @@ static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
	ata_tf_from_fis(d2h_fis, tf);
	ata_tf_from_fis(d2h_fis, tf);
}
}


static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc)
static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl)
{
{
	struct ahci_port_priv *pp = qc->ap->private_data;
	struct scatterlist *sg;
	struct scatterlist *sg;
	struct ahci_sg *ahci_sg;
	struct ahci_sg *ahci_sg;
	unsigned int n_sg = 0;
	unsigned int n_sg = 0;
@@ -738,7 +752,7 @@ static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc)
	/*
	/*
	 * Next, the S/G list.
	 * Next, the S/G list.
	 */
	 */
	ahci_sg = pp->cmd_tbl_sg;
	ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ;
	ata_for_each_sg(sg, qc) {
	ata_for_each_sg(sg, qc) {
		dma_addr_t addr = sg_dma_address(sg);
		dma_addr_t addr = sg_dma_address(sg);
		u32 sg_len = sg_dma_len(sg);
		u32 sg_len = sg_dma_len(sg);
@@ -759,6 +773,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
	struct ata_port *ap = qc->ap;
	struct ata_port *ap = qc->ap;
	struct ahci_port_priv *pp = ap->private_data;
	struct ahci_port_priv *pp = ap->private_data;
	int is_atapi = is_atapi_taskfile(&qc->tf);
	int is_atapi = is_atapi_taskfile(&qc->tf);
	void *cmd_tbl;
	u32 opts;
	u32 opts;
	const u32 cmd_fis_len = 5; /* five dwords */
	const u32 cmd_fis_len = 5; /* five dwords */
	unsigned int n_elem;
	unsigned int n_elem;
@@ -767,16 +782,17 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
	 * Fill in command table information.  First, the header,
	 * Fill in command table information.  First, the header,
	 * a SATA Register - Host to Device command FIS.
	 * a SATA Register - Host to Device command FIS.
	 */
	 */
	ata_tf_to_fis(&qc->tf, pp->cmd_tbl, 0);
	cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;

	ata_tf_to_fis(&qc->tf, cmd_tbl, 0);
	if (is_atapi) {
	if (is_atapi) {
		memset(pp->cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
		memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
		memcpy(pp->cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb,
		memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
		       qc->dev->cdb_len);
	}
	}


	n_elem = 0;
	n_elem = 0;
	if (qc->flags & ATA_QCFLAG_DMAMAP)
	if (qc->flags & ATA_QCFLAG_DMAMAP)
		n_elem = ahci_fill_sg(qc);
		n_elem = ahci_fill_sg(qc, cmd_tbl);


	/*
	/*
	 * Fill in command slot information.
	 * Fill in command slot information.
@@ -787,112 +803,123 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
	if (is_atapi)
	if (is_atapi)
		opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;
		opts |= AHCI_CMD_ATAPI | AHCI_CMD_PREFETCH;


	ahci_fill_cmd_slot(pp, opts);
	ahci_fill_cmd_slot(pp, qc->tag, opts);
}
}


static void ahci_restart_port(struct ata_port *ap, u32 irq_stat)
static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
{
{
	void __iomem *mmio = ap->host_set->mmio_base;
	struct ahci_port_priv *pp = ap->private_data;
	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
	struct ata_eh_info *ehi = &ap->eh_info;
	u32 tmp;
	unsigned int err_mask = 0, action = 0;
	struct ata_queued_cmd *qc;
	u32 serror;


	if ((ap->device[0].class != ATA_DEV_ATAPI) ||
	ata_ehi_clear_desc(ehi);
	    ((irq_stat & PORT_IRQ_TF_ERR) == 0))
		printk(KERN_WARNING "ata%u: port reset, "
		       "p_is %x is %x pis %x cmd %x tf %x ss %x se %x\n",
			ap->id,
			irq_stat,
			readl(mmio + HOST_IRQ_STAT),
			readl(port_mmio + PORT_IRQ_STAT),
			readl(port_mmio + PORT_CMD),
			readl(port_mmio + PORT_TFDATA),
			readl(port_mmio + PORT_SCR_STAT),
			readl(port_mmio + PORT_SCR_ERR));

	/* stop DMA */
	ahci_stop_engine(ap);


	/* clear SATA phy error, if any */
	/* AHCI needs SError cleared; otherwise, it might lock up */
	tmp = readl(port_mmio + PORT_SCR_ERR);
	serror = ahci_scr_read(ap, SCR_ERROR);
	writel(tmp, port_mmio + PORT_SCR_ERR);
	ahci_scr_write(ap, SCR_ERROR, serror);


	/* if DRQ/BSY is set, device needs to be reset.
	/* analyze @irq_stat */
	 * if so, issue COMRESET
	ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
	 */

	tmp = readl(port_mmio + PORT_TFDATA);
	if (irq_stat & PORT_IRQ_TF_ERR)
	if (tmp & (ATA_BUSY | ATA_DRQ)) {
		err_mask |= AC_ERR_DEV;
		writel(0x301, port_mmio + PORT_SCR_CTL);

		readl(port_mmio + PORT_SCR_CTL); /* flush */
	if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
		udelay(10);
		err_mask |= AC_ERR_HOST_BUS;
		writel(0x300, port_mmio + PORT_SCR_CTL);
		action |= ATA_EH_SOFTRESET;
		readl(port_mmio + PORT_SCR_CTL); /* flush */
	}
	}


	/* re-start DMA */
	if (irq_stat & PORT_IRQ_IF_ERR) {
	ahci_start_engine(ap);
		err_mask |= AC_ERR_ATA_BUS;
		action |= ATA_EH_SOFTRESET;
		ata_ehi_push_desc(ehi, ", interface fatal error");
	}
	}


static void ahci_eng_timeout(struct ata_port *ap)
	if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
{
		err_mask |= AC_ERR_ATA_BUS;
	struct ata_host_set *host_set = ap->host_set;
		action |= ATA_EH_SOFTRESET;
	void __iomem *mmio = host_set->mmio_base;
		ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ?
	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
			"connection status changed" : "PHY RDY changed");
	struct ata_queued_cmd *qc;
	}
	unsigned long flags;

	if (irq_stat & PORT_IRQ_UNK_FIS) {
		u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);


	printk(KERN_WARNING "ata%u: handling error/timeout\n", ap->id);
		err_mask |= AC_ERR_HSM;
		action |= ATA_EH_SOFTRESET;
		ata_ehi_push_desc(ehi, ", unknown FIS %08x %08x %08x %08x",
				  unk[0], unk[1], unk[2], unk[3]);
	}


	spin_lock_irqsave(&host_set->lock, flags);
	/* okay, let's hand over to EH */
	ehi->serror |= serror;
	ehi->action |= action;


	ahci_restart_port(ap, readl(port_mmio + PORT_IRQ_STAT));
	qc = ata_qc_from_tag(ap, ap->active_tag);
	qc = ata_qc_from_tag(ap, ap->active_tag);
	qc->err_mask |= AC_ERR_TIMEOUT;
	if (qc)

		qc->err_mask |= err_mask;
	spin_unlock_irqrestore(&host_set->lock, flags);
	else
		ehi->err_mask |= err_mask;


	ata_eh_qc_complete(qc);
	if (irq_stat & PORT_IRQ_FREEZE)
		ata_port_freeze(ap);
	else
		ata_port_abort(ap);
}
}


static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
static void ahci_host_intr(struct ata_port *ap)
{
{
	void __iomem *mmio = ap->host_set->mmio_base;
	void __iomem *mmio = ap->host_set->mmio_base;
	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
	u32 status, serr, ci;
	struct ata_eh_info *ehi = &ap->eh_info;

	u32 status, qc_active;
	serr = readl(port_mmio + PORT_SCR_ERR);
	int rc;
	writel(serr, port_mmio + PORT_SCR_ERR);


	status = readl(port_mmio + PORT_IRQ_STAT);
	status = readl(port_mmio + PORT_IRQ_STAT);
	writel(status, port_mmio + PORT_IRQ_STAT);
	writel(status, port_mmio + PORT_IRQ_STAT);


	ci = readl(port_mmio + PORT_CMD_ISSUE);
	if (unlikely(status & PORT_IRQ_ERROR)) {
	if (likely((ci & 0x1) == 0)) {
		ahci_error_intr(ap, status);
		if (qc) {
		return;
			WARN_ON(qc->err_mask);
			ata_qc_complete(qc);
			qc = NULL;
		}
	}
	}


	if (status & PORT_IRQ_FATAL) {
	if (ap->sactive)
		unsigned int err_mask;
		qc_active = readl(port_mmio + PORT_SCR_ACT);
		if (status & PORT_IRQ_TF_ERR)
			err_mask = AC_ERR_DEV;
		else if (status & PORT_IRQ_IF_ERR)
			err_mask = AC_ERR_ATA_BUS;
	else
	else
			err_mask = AC_ERR_HOST_BUS;
		qc_active = readl(port_mmio + PORT_CMD_ISSUE);


		/* command processing has stopped due to error; restart */
	rc = ata_qc_complete_multiple(ap, qc_active, NULL);
		ahci_restart_port(ap, status);
	if (rc > 0)

		return;
		if (qc) {
	if (rc < 0) {
			qc->err_mask |= err_mask;
		ehi->err_mask |= AC_ERR_HSM;
			ata_qc_complete(qc);
		ehi->action |= ATA_EH_SOFTRESET;
		ata_port_freeze(ap);
		return;
	}
	}

	/* hmmm... a spurious interupt */

	/* some devices send D2H reg with I bit set during NCQ command phase */
	if (ap->sactive && status & PORT_IRQ_D2H_REG_FIS)
		return;

	/* ignore interim PIO setup fis interrupts */
	if (ata_tag_valid(ap->active_tag)) {
		struct ata_queued_cmd *qc =
			ata_qc_from_tag(ap, ap->active_tag);

		if (qc && qc->tf.protocol == ATA_PROT_PIO &&
		    (status & PORT_IRQ_PIOS_FIS))
			return;
	}
	}


	return 1;
	if (ata_ratelimit())
		ata_port_printk(ap, KERN_INFO, "spurious interrupt "
				"(irq_stat 0x%x active_tag %d sactive 0x%x)\n",
				status, ap->active_tag, ap->sactive);
}
}


static void ahci_irq_clear(struct ata_port *ap)
static void ahci_irq_clear(struct ata_port *ap)
@@ -929,14 +956,7 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *


		ap = host_set->ports[i];
		ap = host_set->ports[i];
		if (ap) {
		if (ap) {
			struct ata_queued_cmd *qc;
			ahci_host_intr(ap);
			qc = ata_qc_from_tag(ap, ap->active_tag);
			if (!ahci_host_intr(ap, qc))
				if (ata_ratelimit())
					dev_printk(KERN_WARNING, host_set->dev,
					  "unhandled interrupt on port %u\n",
					  i);

			VPRINTK("port %u\n", i);
			VPRINTK("port %u\n", i);
		} else {
		} else {
			VPRINTK("port %u (no irq)\n", i);
			VPRINTK("port %u (no irq)\n", i);
@@ -965,12 +985,64 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
	struct ata_port *ap = qc->ap;
	struct ata_port *ap = qc->ap;
	void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
	void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;


	writel(1, port_mmio + PORT_CMD_ISSUE);
	if (qc->tf.protocol == ATA_PROT_NCQ)
		writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
	writel(1 << qc->tag, port_mmio + PORT_CMD_ISSUE);
	readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
	readl(port_mmio + PORT_CMD_ISSUE);	/* flush */


	return 0;
	return 0;
}
}


static void ahci_freeze(struct ata_port *ap)
{
	void __iomem *mmio = ap->host_set->mmio_base;
	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);

	/* turn IRQ off */
	writel(0, port_mmio + PORT_IRQ_MASK);
}

static void ahci_thaw(struct ata_port *ap)
{
	void __iomem *mmio = ap->host_set->mmio_base;
	void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
	u32 tmp;

	/* clear IRQ */
	tmp = readl(port_mmio + PORT_IRQ_STAT);
	writel(tmp, port_mmio + PORT_IRQ_STAT);
	writel(1 << ap->id, mmio + HOST_IRQ_STAT);

	/* turn IRQ back on */
	writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
}

static void ahci_error_handler(struct ata_port *ap)
{
	if (!(ap->flags & ATA_FLAG_FROZEN)) {
		/* restart engine */
		ahci_stop_engine(ap);
		ahci_start_engine(ap);
	}

	/* perform recovery */
	ata_do_eh(ap, ahci_softreset, ahci_hardreset, ahci_postreset);
}

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

	if (qc->flags & ATA_QCFLAG_FAILED)
		qc->err_mask |= AC_ERR_OTHER;

	if (qc->err_mask) {
		/* make DMA engine forget about the failed command */
		ahci_stop_engine(ap);
		ahci_start_engine(ap);
	}
}

static void ahci_setup_port(struct ata_ioports *port, unsigned long base,
static void ahci_setup_port(struct ata_ioports *port, unsigned long base,
			    unsigned int port_idx)
			    unsigned int port_idx)
{
{
@@ -1115,9 +1187,6 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent)
			writel(tmp, port_mmio + PORT_IRQ_STAT);
			writel(tmp, port_mmio + PORT_IRQ_STAT);


		writel(1 << i, mmio + HOST_IRQ_STAT);
		writel(1 << i, mmio + HOST_IRQ_STAT);

		/* set irq mask (enables interrupts) */
		writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
	}
	}


	tmp = readl(mmio + HOST_CTL);
	tmp = readl(mmio + HOST_CTL);
@@ -1215,6 +1284,8 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)


	VPRINTK("ENTER\n");
	VPRINTK("ENTER\n");


	WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS);

	if (!printed_version++)
	if (!printed_version++)
		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");


@@ -1282,6 +1353,9 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
	if (rc)
	if (rc)
		goto err_out_hpriv;
		goto err_out_hpriv;


	if (hpriv->cap & HOST_CAP_NCQ)
		probe_ent->host_flags |= ATA_FLAG_NCQ;

	ahci_print_info(probe_ent);
	ahci_print_info(probe_ent);


	/* FIXME: check ata_device_add return value */
	/* FIXME: check ata_device_add return value */
+10 −4
Original line number Original line Diff line number Diff line
@@ -243,7 +243,10 @@ static const struct ata_port_operations piix_pata_ops = {
	.qc_prep		= ata_qc_prep,
	.qc_prep		= ata_qc_prep,
	.qc_issue		= ata_qc_issue_prot,
	.qc_issue		= ata_qc_issue_prot,


	.eng_timeout		= ata_eng_timeout,
	.freeze			= ata_bmdma_freeze,
	.thaw			= ata_bmdma_thaw,
	.error_handler		= ata_bmdma_error_handler,
	.post_internal_cmd	= ata_bmdma_post_internal_cmd,


	.irq_handler		= ata_interrupt,
	.irq_handler		= ata_interrupt,
	.irq_clear		= ata_bmdma_irq_clear,
	.irq_clear		= ata_bmdma_irq_clear,
@@ -271,7 +274,10 @@ static const struct ata_port_operations piix_sata_ops = {
	.qc_prep		= ata_qc_prep,
	.qc_prep		= ata_qc_prep,
	.qc_issue		= ata_qc_issue_prot,
	.qc_issue		= ata_qc_issue_prot,


	.eng_timeout		= ata_eng_timeout,
	.freeze			= ata_bmdma_freeze,
	.thaw			= ata_bmdma_thaw,
	.error_handler		= ata_bmdma_error_handler,
	.post_internal_cmd	= ata_bmdma_post_internal_cmd,


	.irq_handler		= ata_interrupt,
	.irq_handler		= ata_interrupt,
	.irq_clear		= ata_bmdma_irq_clear,
	.irq_clear		= ata_bmdma_irq_clear,
@@ -484,7 +490,7 @@ static int piix_pata_probe_reset(struct ata_port *ap, unsigned int *classes)
	struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
	struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);


	if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->hard_port_no])) {
	if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->hard_port_no])) {
		printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
		ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n");
		return 0;
		return 0;
	}
	}


@@ -565,7 +571,7 @@ static unsigned int piix_sata_probe (struct ata_port *ap)
static int piix_sata_probe_reset(struct ata_port *ap, unsigned int *classes)
static int piix_sata_probe_reset(struct ata_port *ap, unsigned int *classes)
{
{
	if (!piix_sata_probe(ap)) {
	if (!piix_sata_probe(ap)) {
		printk(KERN_INFO "ata%u: SATA port has no device.\n", ap->id);
		ata_port_printk(ap, KERN_INFO, "SATA port has no device.\n");
		return 0;
		return 0;
	}
	}


+143 −0
Original line number Original line Diff line number Diff line
@@ -652,6 +652,149 @@ void ata_bmdma_stop(struct ata_queued_cmd *qc)
	ata_altstatus(ap);        /* dummy read */
	ata_altstatus(ap);        /* dummy read */
}
}


/**
 *	ata_bmdma_freeze - Freeze BMDMA controller port
 *	@ap: port to freeze
 *
 *	Freeze BMDMA controller port.
 *
 *	LOCKING:
 *	Inherited from caller.
 */
void ata_bmdma_freeze(struct ata_port *ap)
{
	struct ata_ioports *ioaddr = &ap->ioaddr;

	ap->ctl |= ATA_NIEN;
	ap->last_ctl = ap->ctl;

	if (ap->flags & ATA_FLAG_MMIO)
		writeb(ap->ctl, (void __iomem *)ioaddr->ctl_addr);
	else
		outb(ap->ctl, ioaddr->ctl_addr);
}

/**
 *	ata_bmdma_thaw - Thaw BMDMA controller port
 *	@ap: port to thaw
 *
 *	Thaw BMDMA controller port.
 *
 *	LOCKING:
 *	Inherited from caller.
 */
void ata_bmdma_thaw(struct ata_port *ap)
{
	/* clear & re-enable interrupts */
	ata_chk_status(ap);
	ap->ops->irq_clear(ap);
	if (ap->ioaddr.ctl_addr)	/* FIXME: hack. create a hook instead */
		ata_irq_on(ap);
}

/**
 *	ata_bmdma_drive_eh - Perform EH with given methods for BMDMA controller
 *	@ap: port to handle error for
 *	@softreset: softreset method (can be NULL)
 *	@hardreset: hardreset method (can be NULL)
 *	@postreset: postreset method (can be NULL)
 *
 *	Handle error for ATA BMDMA controller.  It can handle both
 *	PATA and SATA controllers.  Many controllers should be able to
 *	use this EH as-is or with some added handling before and
 *	after.
 *
 *	This function is intended to be used for constructing
 *	->error_handler callback by low level drivers.
 *
 *	LOCKING:
 *	Kernel thread context (may sleep)
 */
void ata_bmdma_drive_eh(struct ata_port *ap, ata_reset_fn_t softreset,
			ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
{
	struct ata_host_set *host_set = ap->host_set;
	struct ata_eh_context *ehc = &ap->eh_context;
	struct ata_queued_cmd *qc;
	unsigned long flags;
	int thaw = 0;

	qc = __ata_qc_from_tag(ap, ap->active_tag);
	if (qc && !(qc->flags & ATA_QCFLAG_FAILED))
		qc = NULL;

	/* reset PIO HSM and stop DMA engine */
	spin_lock_irqsave(&host_set->lock, flags);

	ap->hsm_task_state = HSM_ST_IDLE;

	if (qc && (qc->tf.protocol == ATA_PROT_DMA ||
		   qc->tf.protocol == ATA_PROT_ATAPI_DMA)) {
		u8 host_stat;

		host_stat = ata_bmdma_status(ap);

		ata_ehi_push_desc(&ehc->i, "BMDMA stat 0x%x", host_stat);

		/* BMDMA controllers indicate host bus error by
		 * setting DMA_ERR bit and timing out.  As it wasn't
		 * really a timeout event, adjust error mask and
		 * cancel frozen state.
		 */
		if (qc->err_mask == AC_ERR_TIMEOUT && host_stat & ATA_DMA_ERR) {
			qc->err_mask = AC_ERR_HOST_BUS;
			thaw = 1;
		}

		ap->ops->bmdma_stop(qc);
	}

	ata_altstatus(ap);
	ata_chk_status(ap);
	ap->ops->irq_clear(ap);

	spin_unlock_irqrestore(&host_set->lock, flags);

	if (thaw)
		ata_eh_thaw_port(ap);

	/* PIO and DMA engines have been stopped, perform recovery */
	ata_do_eh(ap, softreset, hardreset, postreset);
}

/**
 *	ata_bmdma_error_handler - Stock error handler for BMDMA controller
 *	@ap: port to handle error for
 *
 *	Stock error handler for BMDMA controller.
 *
 *	LOCKING:
 *	Kernel thread context (may sleep)
 */
void ata_bmdma_error_handler(struct ata_port *ap)
{
	ata_reset_fn_t hardreset;

	hardreset = NULL;
	if (sata_scr_valid(ap))
		hardreset = sata_std_hardreset;

	ata_bmdma_drive_eh(ap, ata_std_softreset, hardreset, ata_std_postreset);
}

/**
 *	ata_bmdma_post_internal_cmd - Stock post_internal_cmd for
 *				      BMDMA controller
 *	@qc: internal command to clean up
 *
 *	LOCKING:
 *	Kernel thread context (may sleep)
 */
void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc)
{
	ata_bmdma_stop(qc);
}

#ifdef CONFIG_PCI
#ifdef CONFIG_PCI
static struct ata_probe_ent *
static struct ata_probe_ent *
ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
+1218 −639

File changed.

Preview size limit exceeded, changes collapsed.

+1303 −8

File changed.

Preview size limit exceeded, changes collapsed.

Loading