linux-ide.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH #upstream 1/2] libata-eh: update atapi_eh_request_sense() to take @dev instead of @qc
@ 2008-06-10  9:28 Tejun Heo
  2008-06-10  9:28 ` [PATCH #upstream 2/2] libata-eh: clear UNIT ATTENTION after reset Tejun Heo
  2008-06-27  6:41 ` [PATCH #upstream 1/2] libata-eh: update atapi_eh_request_sense() to take @dev instead of @qc Jeff Garzik
  0 siblings, 2 replies; 6+ messages in thread
From: Tejun Heo @ 2008-06-10  9:28 UTC (permalink / raw)
  To: Jeff Garzik, IDE/ATA development list

Update atapi_eh_request_sense() to take @dev, @sense_buf and
@dfl_sense_key instead of taking @qc and extracting information from
it.  This change is to make the function more generic and allow it to
be called from other places.

While at it, make cdb initialization use initializer.

Signed-off-by: Tejun Heo <htejun@gmail.com>
---
 drivers/ata/libata-eh.c |   19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

Index: work/drivers/ata/libata-eh.c
===================================================================
--- work.orig/drivers/ata/libata-eh.c
+++ work/drivers/ata/libata-eh.c
@@ -1238,6 +1238,7 @@ static int ata_eh_read_log_10h(struct at
  *	atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
  *	@dev: device to perform REQUEST_SENSE to
  *	@sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long)
+ *	@dfl_sense_key: default sense key to use
  *
  *	Perform ATAPI REQUEST_SENSE after the device reported CHECK
  *	SENSE.  This function is EH helper.
@@ -1248,13 +1249,13 @@ static int ata_eh_read_log_10h(struct at
  *	RETURNS:
  *	0 on success, AC_ERR_* mask on failure
  */
-static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc)
+static unsigned int atapi_eh_request_sense(struct ata_device *dev,
+					   u8 *sense_buf, u8 dfl_sense_key)
 {
-	struct ata_device *dev = qc->dev;
-	unsigned char *sense_buf = qc->scsicmd->sense_buffer;
+	u8 cdb[ATAPI_CDB_LEN] =
+		{ REQUEST_SENSE, 0, 0, 0, SCSI_SENSE_BUFFERSIZE, 0 };
 	struct ata_port *ap = dev->link->ap;
 	struct ata_taskfile tf;
-	u8 cdb[ATAPI_CDB_LEN];
 
 	DPRINTK("ATAPI request sense\n");
 
@@ -1265,15 +1266,11 @@ static unsigned int atapi_eh_request_sen
 	 * for the case where they are -not- overwritten
 	 */
 	sense_buf[0] = 0x70;
-	sense_buf[2] = qc->result_tf.feature >> 4;
+	sense_buf[2] = dfl_sense_key;
 
 	/* some devices time out if garbage left in tf */
 	ata_tf_init(dev, &tf);
 
-	memset(cdb, 0, ATAPI_CDB_LEN);
-	cdb[0] = REQUEST_SENSE;
-	cdb[4] = SCSI_SENSE_BUFFERSIZE;
-
 	tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
 	tf.command = ATA_CMD_PACKET;
 
@@ -1450,7 +1447,9 @@ static unsigned int ata_eh_analyze_tf(st
 
 	case ATA_DEV_ATAPI:
 		if (!(qc->ap->pflags & ATA_PFLAG_FROZEN)) {
-			tmp = atapi_eh_request_sense(qc);
+			tmp = atapi_eh_request_sense(qc->dev,
+						qc->scsicmd->sense_buffer,
+						qc->result_tf.feature >> 4);
 			if (!tmp) {
 				/* ATA_QCFLAG_SENSE_VALID is used to
 				 * tell atapi_qc_complete() that sense

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH #upstream 2/2] libata-eh: clear UNIT ATTENTION after reset
  2008-06-10  9:28 [PATCH #upstream 1/2] libata-eh: update atapi_eh_request_sense() to take @dev instead of @qc Tejun Heo
@ 2008-06-10  9:28 ` Tejun Heo
  2008-06-27  6:41   ` Jeff Garzik
  2008-06-27  6:41 ` [PATCH #upstream 1/2] libata-eh: update atapi_eh_request_sense() to take @dev instead of @qc Jeff Garzik
  1 sibling, 1 reply; 6+ messages in thread
From: Tejun Heo @ 2008-06-10  9:28 UTC (permalink / raw)
  To: Jeff Garzik, IDE/ATA development list

Resets make ATAPI devices raise UNIT ATTENTION which fails the next
command.  As resets can happen asynchronously for unrelated reasons,
this sometimes disrupts innocent users.  For example, reading DVD
fails after the system wakes up from suspend or the other device
sharing the channel went through bus error.

Clearing UA has some problems as it might clear UA which the userland
needs to know about.  However, UA after resets can only be about the
reset itself and benefits of clearing it overweights cons.  Missing UA
can only delay failure to one of the following commands anyway.  For
example, timeout while burning is in progress will trigger reset and
reset the device state and probably corrupt the burning run.  Although
the userland application won't get the UA, its pending writes will
fail.

Signed-off-by: Tejun Heo <htejun@gmail.com>
---
 drivers/ata/libata-eh.c |  105 +++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 99 insertions(+), 6 deletions(-)

Index: work/drivers/ata/libata-eh.c
===================================================================
--- work.orig/drivers/ata/libata-eh.c
+++ work/drivers/ata/libata-eh.c
@@ -66,15 +66,16 @@ enum {
 	ATA_ECAT_DUBIOUS_TOUT_HSM	= 6,
 	ATA_ECAT_DUBIOUS_UNK_DEV	= 7,
 	ATA_ECAT_NR			= 8,
-};
 
-/* Waiting in ->prereset can never be reliable.  It's sometimes nice
- * to wait there but it can't be depended upon; otherwise, we wouldn't
- * be resetting.  Just give it enough time for most drives to spin up.
- */
-enum {
+	/* Waiting in ->prereset can never be reliable.  It's
+	 * sometimes nice to wait there but it can't be depended upon;
+	 * otherwise, we wouldn't be resetting.  Just give it enough
+	 * time for most drives to spin up.
+	 */
 	ATA_EH_PRERESET_TIMEOUT		= 10 * HZ,
 	ATA_EH_FASTDRAIN_INTERVAL	= 3 * HZ,
+
+	ATA_EH_UA_TRIES			= 5,
 };
 
 /* The following table determines how we sequence resets.  Each entry
@@ -1235,6 +1236,37 @@ static int ata_eh_read_log_10h(struct at
 }
 
 /**
+ *	atapi_eh_tur - perform ATAPI TEST_UNIT_READY
+ *	@dev: target ATAPI device
+ *	@r_sense_key: out parameter for sense_key
+ *
+ *	Perform ATAPI TEST_UNIT_READY.
+ *
+ *	LOCKING:
+ *	EH context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, AC_ERR_* mask on failure.
+ */
+static unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
+{
+	u8 cdb[ATAPI_CDB_LEN] = { TEST_UNIT_READY, 0, 0, 0, 0, 0 };
+	struct ata_taskfile tf;
+	unsigned int err_mask;
+
+	ata_tf_init(dev, &tf);
+
+	tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+	tf.command = ATA_CMD_PACKET;
+	tf.protocol = ATAPI_PROT_NODATA;
+
+	err_mask = ata_exec_internal(dev, &tf, cdb, DMA_NONE, NULL, 0, 0);
+	if (err_mask == AC_ERR_DEV)
+		*r_sense_key = tf.feature >> 4;
+	return err_mask;
+}
+
+/**
  *	atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
  *	@dev: device to perform REQUEST_SENSE to
  *	@sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long)
@@ -2445,6 +2477,53 @@ int ata_set_mode(struct ata_link *link, 
 	return rc;
 }
 
+/**
+ *	atapi_eh_clear_ua - Clear ATAPI UNIT ATTENTION after reset
+ *	@dev: ATAPI device to clear UA for
+ *
+ *	Resets and other operations can make an ATAPI device raise
+ *	UNIT ATTENTION which causes the next operation to fail.  This
+ *	function clears UA.
+ *
+ *	LOCKING:
+ *	EH context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+static int atapi_eh_clear_ua(struct ata_device *dev)
+{
+	int i;
+
+	for (i = 0; i < ATA_EH_UA_TRIES; i++) {
+		u8 sense_buffer[SCSI_SENSE_BUFFERSIZE];
+		u8 sense_key = 0;
+		unsigned int err_mask;
+
+		err_mask = atapi_eh_tur(dev, &sense_key);
+		if (err_mask != 0 && err_mask != AC_ERR_DEV) {
+			ata_dev_printk(dev, KERN_WARNING, "TEST_UNIT_READY "
+				"failed (err_mask=0x%x)\n", err_mask);
+			return -EIO;
+		}
+
+		if (!err_mask || sense_key != UNIT_ATTENTION)
+			return 0;
+
+		err_mask = atapi_eh_request_sense(dev, sense_buffer, sense_key);
+		if (err_mask) {
+			ata_dev_printk(dev, KERN_WARNING, "failed to clear "
+				"UNIT ATTENTION (err_mask=0x%x)\n", err_mask);
+			return -EIO;
+		}
+	}
+
+	ata_dev_printk(dev, KERN_WARNING,
+		"UNIT ATTENTION persists after %d tries\n", ATA_EH_UA_TRIES);
+
+	return 0;
+}
+
 static int ata_link_nr_enabled(struct ata_link *link)
 {
 	struct ata_device *dev;
@@ -2702,6 +2781,20 @@ int ata_eh_recover(struct ata_port *ap, 
 			ehc->i.flags &= ~ATA_EHI_SETMODE;
 		}
 
+		/* If reset has been issued, clear UA to avoid
+		 * disrupting the current users of the device.
+		 */
+		if (ehc->i.flags & ATA_EHI_DID_RESET) {
+			ata_link_for_each_dev(dev, link) {
+				if (dev->class != ATA_DEV_ATAPI)
+					continue;
+				rc = atapi_eh_clear_ua(dev);
+				if (rc)
+					goto dev_fail;
+			}
+		}
+
+		/* configure link power saving */
 		if (ehc->i.action & ATA_EH_LPM)
 			ata_link_for_each_dev(dev, link)
 				ata_dev_enable_pm(dev, ap->pm_policy);

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH #upstream 1/2] libata-eh: update atapi_eh_request_sense() to take @dev instead of @qc
  2008-06-10  9:28 [PATCH #upstream 1/2] libata-eh: update atapi_eh_request_sense() to take @dev instead of @qc Tejun Heo
  2008-06-10  9:28 ` [PATCH #upstream 2/2] libata-eh: clear UNIT ATTENTION after reset Tejun Heo
@ 2008-06-27  6:41 ` Jeff Garzik
  1 sibling, 0 replies; 6+ messages in thread
From: Jeff Garzik @ 2008-06-27  6:41 UTC (permalink / raw)
  To: Tejun Heo; +Cc: IDE/ATA development list

Tejun Heo wrote:
> Update atapi_eh_request_sense() to take @dev, @sense_buf and
> @dfl_sense_key instead of taking @qc and extracting information from
> it.  This change is to make the function more generic and allow it to
> be called from other places.
> 
> While at it, make cdb initialization use initializer.
> 
> Signed-off-by: Tejun Heo <htejun@gmail.com>
> ---
>  drivers/ata/libata-eh.c |   19 +++++++++----------
>  1 file changed, 9 insertions(+), 10 deletions(-)

applied



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH #upstream 2/2] libata-eh: clear UNIT ATTENTION after reset
  2008-06-10  9:28 ` [PATCH #upstream 2/2] libata-eh: clear UNIT ATTENTION after reset Tejun Heo
@ 2008-06-27  6:41   ` Jeff Garzik
  2008-08-30 12:20     ` [PATCH #upstream UPDATED " Tejun Heo
  0 siblings, 1 reply; 6+ messages in thread
From: Jeff Garzik @ 2008-06-27  6:41 UTC (permalink / raw)
  To: Tejun Heo; +Cc: IDE/ATA development list

Tejun Heo wrote:
> Resets make ATAPI devices raise UNIT ATTENTION which fails the next
> command.  As resets can happen asynchronously for unrelated reasons,
> this sometimes disrupts innocent users.  For example, reading DVD
> fails after the system wakes up from suspend or the other device
> sharing the channel went through bus error.
> 
> Clearing UA has some problems as it might clear UA which the userland
> needs to know about.  However, UA after resets can only be about the
> reset itself and benefits of clearing it overweights cons.  Missing UA
> can only delay failure to one of the following commands anyway.  For
> example, timeout while burning is in progress will trigger reset and
> reset the device state and probably corrupt the burning run.  Although
> the userland application won't get the UA, its pending writes will
> fail.
> 
> Signed-off-by: Tejun Heo <htejun@gmail.com>
> ---
>  drivers/ata/libata-eh.c |  105 +++++++++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 99 insertions(+), 6 deletions(-)

ACK, but does not apply to #upstream



^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH #upstream UPDATED 2/2] libata-eh: clear UNIT ATTENTION after reset
  2008-06-27  6:41   ` Jeff Garzik
@ 2008-08-30 12:20     ` Tejun Heo
  2008-09-29  4:34       ` Jeff Garzik
  0 siblings, 1 reply; 6+ messages in thread
From: Tejun Heo @ 2008-08-30 12:20 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: IDE/ATA development list

Resets make ATAPI devices raise UNIT ATTENTION which fails the next
command.  As resets can happen asynchronously for unrelated reasons,
this sometimes disrupts innocent users.  For example, reading DVD
fails after the system wakes up from suspend or the other device
sharing the channel went through bus error.

Clearing UA has some problems as it might clear UA which the userland
needs to know about.  However, UA after resets can only be about the
reset itself and benefits of clearing it overweights cons.  Missing UA
can only delay failure to one of the following commands anyway.  For
example, timeout while burning is in progress will trigger reset and
reset the device state and probably corrupt the burning run.  Although
the userland application won't get the UA, its pending writes will
fail.

Signed-off-by: Tejun Heo <tj@kernel.org>
---
Ah... It slipped through the cracks somehow.  Updated to the current
#upstream.  Thanks.

 drivers/ata/libata-eh.c |   94 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 94 insertions(+)

diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 58bdc53..e02ca0d 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -79,6 +79,8 @@ enum {
 	 */
 	ATA_EH_PRERESET_TIMEOUT		= 10000,
 	ATA_EH_FASTDRAIN_INTERVAL	=  3000,
+
+	ATA_EH_UA_TRIES			= 5,
 };
 
 /* The following table determines how we sequence resets.  Each entry
@@ -1357,6 +1359,37 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
 }
 
 /**
+ *	atapi_eh_tur - perform ATAPI TEST_UNIT_READY
+ *	@dev: target ATAPI device
+ *	@r_sense_key: out parameter for sense_key
+ *
+ *	Perform ATAPI TEST_UNIT_READY.
+ *
+ *	LOCKING:
+ *	EH context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, AC_ERR_* mask on failure.
+ */
+static unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
+{
+	u8 cdb[ATAPI_CDB_LEN] = { TEST_UNIT_READY, 0, 0, 0, 0, 0 };
+	struct ata_taskfile tf;
+	unsigned int err_mask;
+
+	ata_tf_init(dev, &tf);
+
+	tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+	tf.command = ATA_CMD_PACKET;
+	tf.protocol = ATAPI_PROT_NODATA;
+
+	err_mask = ata_exec_internal(dev, &tf, cdb, DMA_NONE, NULL, 0, 0);
+	if (err_mask == AC_ERR_DEV)
+		*r_sense_key = tf.feature >> 4;
+	return err_mask;
+}
+
+/**
  *	atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
  *	@dev: device to perform REQUEST_SENSE to
  *	@sense_buf: result sense data buffer (SCSI_SENSE_BUFFERSIZE bytes long)
@@ -2614,6 +2647,53 @@ int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
 	return rc;
 }
 
+/**
+ *	atapi_eh_clear_ua - Clear ATAPI UNIT ATTENTION after reset
+ *	@dev: ATAPI device to clear UA for
+ *
+ *	Resets and other operations can make an ATAPI device raise
+ *	UNIT ATTENTION which causes the next operation to fail.  This
+ *	function clears UA.
+ *
+ *	LOCKING:
+ *	EH context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+static int atapi_eh_clear_ua(struct ata_device *dev)
+{
+	int i;
+
+	for (i = 0; i < ATA_EH_UA_TRIES; i++) {
+		u8 sense_buffer[SCSI_SENSE_BUFFERSIZE];
+		u8 sense_key = 0;
+		unsigned int err_mask;
+
+		err_mask = atapi_eh_tur(dev, &sense_key);
+		if (err_mask != 0 && err_mask != AC_ERR_DEV) {
+			ata_dev_printk(dev, KERN_WARNING, "TEST_UNIT_READY "
+				"failed (err_mask=0x%x)\n", err_mask);
+			return -EIO;
+		}
+
+		if (!err_mask || sense_key != UNIT_ATTENTION)
+			return 0;
+
+		err_mask = atapi_eh_request_sense(dev, sense_buffer, sense_key);
+		if (err_mask) {
+			ata_dev_printk(dev, KERN_WARNING, "failed to clear "
+				"UNIT ATTENTION (err_mask=0x%x)\n", err_mask);
+			return -EIO;
+		}
+	}
+
+	ata_dev_printk(dev, KERN_WARNING,
+		"UNIT ATTENTION persists after %d tries\n", ATA_EH_UA_TRIES);
+
+	return 0;
+}
+
 static int ata_link_nr_enabled(struct ata_link *link)
 {
 	struct ata_device *dev;
@@ -2856,6 +2936,20 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
 			ehc->i.flags &= ~ATA_EHI_SETMODE;
 		}
 
+		/* If reset has been issued, clear UA to avoid
+		 * disrupting the current users of the device.
+		 */
+		if (ehc->i.flags & ATA_EHI_DID_RESET) {
+			ata_link_for_each_dev(dev, link) {
+				if (dev->class != ATA_DEV_ATAPI)
+					continue;
+				rc = atapi_eh_clear_ua(dev);
+				if (rc)
+					goto dev_fail;
+			}
+		}
+
+		/* configure link power saving */
 		if (ehc->i.action & ATA_EH_LPM)
 			ata_link_for_each_dev(dev, link)
 				ata_dev_enable_pm(dev, ap->pm_policy);

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH #upstream UPDATED 2/2] libata-eh: clear UNIT ATTENTION after reset
  2008-08-30 12:20     ` [PATCH #upstream UPDATED " Tejun Heo
@ 2008-09-29  4:34       ` Jeff Garzik
  0 siblings, 0 replies; 6+ messages in thread
From: Jeff Garzik @ 2008-09-29  4:34 UTC (permalink / raw)
  To: Tejun Heo; +Cc: IDE/ATA development list

Tejun Heo wrote:
> Resets make ATAPI devices raise UNIT ATTENTION which fails the next
> command.  As resets can happen asynchronously for unrelated reasons,
> this sometimes disrupts innocent users.  For example, reading DVD
> fails after the system wakes up from suspend or the other device
> sharing the channel went through bus error.
> 
> Clearing UA has some problems as it might clear UA which the userland
> needs to know about.  However, UA after resets can only be about the
> reset itself and benefits of clearing it overweights cons.  Missing UA
> can only delay failure to one of the following commands anyway.  For
> example, timeout while burning is in progress will trigger reset and
> reset the device state and probably corrupt the burning run.  Although
> the userland application won't get the UA, its pending writes will
> fail.
> 
> Signed-off-by: Tejun Heo <tj@kernel.org>
> ---
> Ah... It slipped through the cracks somehow.  Updated to the current
> #upstream.  Thanks.
> 
>  drivers/ata/libata-eh.c |   94 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 94 insertions(+)

applied



^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2008-09-29  4:34 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-06-10  9:28 [PATCH #upstream 1/2] libata-eh: update atapi_eh_request_sense() to take @dev instead of @qc Tejun Heo
2008-06-10  9:28 ` [PATCH #upstream 2/2] libata-eh: clear UNIT ATTENTION after reset Tejun Heo
2008-06-27  6:41   ` Jeff Garzik
2008-08-30 12:20     ` [PATCH #upstream UPDATED " Tejun Heo
2008-09-29  4:34       ` Jeff Garzik
2008-06-27  6:41 ` [PATCH #upstream 1/2] libata-eh: update atapi_eh_request_sense() to take @dev instead of @qc Jeff Garzik

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 NNTP newsgroup(s).