Linux-ide Archive mirror
 help / color / mirror / Atom feed
From: Tejun Heo <htejun@gmail.com>
To: jeff@garzik.org, linux-ide@vger.kernel.org,
	alan@lxorguk.ukuu.org.uk, liml@rtr.ca, albertl@mail.com,
	jens.axboe@oracle.com
Cc: Tejun Heo <htejun@gmail.com>
Subject: [PATCH 14/15] libata: implement ATAPI per-command-type DMA horkages
Date: Wed,  5 Dec 2007 16:43:14 +0900	[thread overview]
Message-ID: <119684059865-git-send-email-htejun@gmail.com> (raw)
In-Reply-To: <11968405951262-git-send-email-htejun@gmail.com>

ATAPI DMA is filled with mines.  Sector aligned READ transfers usually
work but many other commands transfer non-sector aligned or variable
number of bytes, and there are devices and controllers which have
problems dealing with such non-aligned DMA transactions.

This patch implement ATAPI per-command-type DMA horkages and EH logic
to set those quickly.  This way, failures localized to certain command
type don't affect other operations (most importantly READs) and
working configuration is found quickly such that the device can be
used.

Signed-off-by: Tejun Heo <htejun@gmail.com>
---
 drivers/ata/libata-core.c |   21 +++++++++++++++++++++
 drivers/ata/libata-eh.c   |   35 +++++++++++++++++++++++++++++++++++
 include/linux/libata.h    |    5 +++++
 3 files changed, 61 insertions(+), 0 deletions(-)

diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 1a81e22..21c60d6 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4637,6 +4637,27 @@ static void ata_fill_sg_dumb(struct ata_queued_cmd *qc)
 int ata_check_atapi_dma(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
+	unsigned int horkage = qc->dev->horkage;
+
+	switch (atapi_cmd_type(qc->cdb[0])) {
+	case ATAPI_READ:
+		break;
+
+	case ATAPI_WRITE:
+		if (horkage & ATAPI_DMA_HORKAGE_WRITE)
+			return 1;
+		break;
+
+	case ATAPI_READ_CD:
+		if (horkage & ATAPI_DMA_HORKAGE_READ_CD)
+			return 1;
+		break;
+
+	case ATAPI_MISC:
+		if (horkage & ATAPI_DMA_HORKAGE_MISC)
+			return 1;
+		break;
+	}
 
 	/* Don't allow DMA if it isn't multiple of 16 bytes.  Quite a
 	 * few ATAPI devices choke on such DMA requests.
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 3688f21..b3bce72 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1489,6 +1489,38 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
 	return action;
 }
 
+static void atapi_eh_dma_horkages(struct ata_queued_cmd *qc)
+{
+	struct ata_device *dev = qc->dev;
+	const char *type;
+
+	if (!ata_is_atapi(qc->tf.protocol) || !ata_is_dma(qc->tf.protocol) ||
+	    !(qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT)))
+		return;
+
+	switch (atapi_cmd_type(qc->cdb[0])) {
+	case ATAPI_WRITE:
+		type = "WRITE";
+		dev->horkage |= ATAPI_DMA_HORKAGE_WRITE;
+		break;
+	case ATAPI_READ_CD:
+		type = "READ CD [MSF]";
+		dev->horkage |= ATAPI_DMA_HORKAGE_READ_CD;
+		break;
+	case ATAPI_MISC:
+		type = "MISC";
+		dev->horkage |= ATAPI_DMA_HORKAGE_MISC;
+		break;
+	default:
+		return;
+	}
+
+	ata_dev_printk(dev, KERN_WARNING, "ATAPI DMA for %s disabled (0x%x). \n"
+		"         If this continues to happen, please report to\n"
+		"         linux-ide@vger.kernel.org\n",
+		       type, dev->horkage);
+}
+
 static int ata_eh_categorize_error(unsigned int eflags, unsigned int err_mask,
 				   int *xfer_ok)
 {
@@ -1809,6 +1841,9 @@ static void ata_eh_link_autopsy(struct ata_link *link)
 		all_err_mask |= qc->err_mask;
 		if (qc->flags & ATA_QCFLAG_IO)
 			eflags |= ATA_EFLAG_IS_IO;
+
+		/* handle ATAPI DMA horkages */
+		atapi_eh_dma_horkages(qc);
 	}
 
 	/* enforce default EH actions */
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 73080d9..b3ec5ab 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -342,6 +342,11 @@ enum {
 	ATA_HORKAGE_IVB		= (1 << 8),	/* cbl det validity bit bugs */
 	ATA_HORKAGE_STUCK_ERR	= (1 << 9),	/* stuck ERR on next PACKET */
 
+	ATAPI_DMA_HORKAGE_WRITE		= (1 << 28), /* PIO for WRITEs */
+	ATAPI_DMA_HORKAGE_READ_CD	= (1 << 29), /* PIO for READ_CDs */
+	ATAPI_DMA_HORKAGE_READ_DVD_STR	= (1 << 30), /* PIO for READ DVD STR */
+	ATAPI_DMA_HORKAGE_MISC		= (1 << 31), /* PIO for MISC commands */
+
 	 /* DMA mask for user DMA control: User visible values; DO NOT
 	    renumber */
 	ATA_DMA_MASK_ATA	= (1 << 0),	/* DMA on ATA Disk */
-- 
1.5.2.4


  parent reply	other threads:[~2007-12-05  7:44 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-12-05  7:43 [PATCHSET] libata: improve ATAPI data transfer handling, take #3 Tejun Heo
2007-12-05  7:43 ` [PATCH 01/15] libata: make atapi_request_sense() use sg Tejun Heo
2007-12-18 21:30   ` Jeff Garzik
2007-12-05  7:43 ` [PATCH 02/15] libata: zero xfer length on ATAPI data xfer IRQ is HSM violation Tejun Heo
2007-12-06  6:44   ` Albert Lee
2007-12-05  7:43 ` [PATCH 03/15] libata: update atapi_eh_request_sense() such that lbam/lbah contains buffer size Tejun Heo
2007-12-05  7:43 ` [PATCH 04/15] cdrom: add more GPCMD_* constants Tejun Heo
2007-12-05  7:43 ` [PATCH 05/15] libata: rename ATA_PROT_ATAPI_* to ATAPI_PROT_* Tejun Heo
2007-12-18 21:35   ` Jeff Garzik
2007-12-05  7:43 ` [PATCH 06/15] libata: add ATAPI_* cmd types and implement atapi_cmd_type() Tejun Heo
2007-12-05  7:43 ` [PATCH 07/15] change-data_xfer Tejun Heo
2007-12-18 21:38   ` Jeff Garzik
2007-12-05  7:43 ` [PATCH 08/15] libata: improve ATAPI draining Tejun Heo
2007-12-06  6:47   ` Albert Lee
2007-12-18 21:41   ` Jeff Garzik
2007-12-05  7:43 ` [PATCH 09/15] libata: kill non-sg DMA interface Tejun Heo
2007-12-05  7:43 ` [PATCH 10/15] libata: change ATA_QCFLAG_DMAMAP semantics Tejun Heo
2007-12-05  7:43 ` [PATCH 11/15] libata: convert to chained sg Tejun Heo
2007-12-05  7:43 ` [PATCH 12/15] libata: make qc->nbytes include extra buffers Tejun Heo
2007-12-18 21:44   ` Jeff Garzik
2007-12-05  7:43 ` [PATCH 13/15] libata: implement ATAPI drain buffer Tejun Heo
2007-12-18 21:45   ` Jeff Garzik
2007-12-05  7:43 ` Tejun Heo [this message]
2007-12-05  7:43 ` [PATCH 15/15] libata: use PIO for misc ATAPI commands Tejun Heo
2007-12-05 13:00   ` Alan Cox

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=119684059865-git-send-email-htejun@gmail.com \
    --to=htejun@gmail.com \
    --cc=alan@lxorguk.ukuu.org.uk \
    --cc=albertl@mail.com \
    --cc=jeff@garzik.org \
    --cc=jens.axboe@oracle.com \
    --cc=liml@rtr.ca \
    --cc=linux-ide@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).