public inbox for linux-scsi@vger.kernel.org
 help / color / mirror / Atom feed
From: Don Brace <don.brace@pmcs.com>
To: scott.teel@pmcs.com, Kevin.Barnett@pmcs.com,
	james.bottomley@parallels.com, hch@infradead.org,
	Justin.Lindley@pmcs.com, brace@pmcs.com
Cc: linux-scsi@vger.kernel.org
Subject: [PATCH v5 06/42] hpsa: hpsa decode sense data for io and tmf
Date: Thu, 23 Apr 2015 09:32:16 -0500	[thread overview]
Message-ID: <20150423143216.18832.19674.stgit@brunhilda> (raw)
In-Reply-To: <20150423141637.18832.35621.stgit@brunhilda>

From: Stephen Cameron <stephenmcameron@gmail.com>

In hba mode, we could get sense data in descriptor format so
we need to handle that.

It's possible for CommandStatus to have value 0x0D
"TMF Function Status", which we should handle.  We will get
this from a P1224 when aborting a non-existent tag, for
example.  The "ScsiStatus" field of the errinfo field
will contain the TMF function status value.

Reviewed-by: Scott Teel <scott.teel@pmcs.com>
Reviewed-by: Kevin Barnett <kevin.barnett@pmcs.com>
Reviewed-by: Tomas Henzl <thenzl@redhat.com>
Signed-off-by: Don Brace <don.brace@pmcs.com>
---
 drivers/scsi/hpsa.c     |  145 ++++++++++++++++++++++++++++++++++++-----------
 drivers/scsi/hpsa_cmd.h |    9 +++
 2 files changed, 119 insertions(+), 35 deletions(-)

diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 5532664..f9e8f7d 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -43,6 +43,7 @@
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_tcq.h>
+#include <scsi/scsi_eh.h>
 #include <linux/cciss_ioctl.h>
 #include <linux/string.h>
 #include <linux/bitmap.h>
@@ -268,16 +269,49 @@ static inline struct ctlr_info *shost_to_hba(struct Scsi_Host *sh)
 	return (struct ctlr_info *) *priv;
 }
 
+/* extract sense key, asc, and ascq from sense data.  -1 means invalid. */
+static void decode_sense_data(const u8 *sense_data, int sense_data_len,
+			u8 *sense_key, u8 *asc, u8 *ascq)
+{
+	struct scsi_sense_hdr sshdr;
+	bool rc;
+
+	*sense_key = -1;
+	*asc = -1;
+	*ascq = -1;
+
+	if (sense_data_len < 1)
+		return;
+
+	rc = scsi_normalize_sense(sense_data, sense_data_len, &sshdr);
+	if (rc) {
+		*sense_key = sshdr.sense_key;
+		*asc = sshdr.asc;
+		*ascq = sshdr.ascq;
+	}
+}
+
 static int check_for_unit_attention(struct ctlr_info *h,
 	struct CommandList *c)
 {
-	if (c->err_info->SenseInfo[2] != UNIT_ATTENTION)
+	u8 sense_key, asc, ascq;
+	int sense_len;
+
+	if (c->err_info->SenseLen > sizeof(c->err_info->SenseInfo))
+		sense_len = sizeof(c->err_info->SenseInfo);
+	else
+		sense_len = c->err_info->SenseLen;
+
+	decode_sense_data(c->err_info->SenseInfo, sense_len,
+				&sense_key, &asc, &ascq);
+	if (sense_key != UNIT_ATTENTION || asc == -1)
 		return 0;
 
-	switch (c->err_info->SenseInfo[12]) {
+	switch (asc) {
 	case STATE_CHANGED:
-		dev_warn(&h->pdev->dev, HPSA "%d: a state change "
-			"detected, command retried\n", h->ctlr);
+		dev_warn(&h->pdev->dev,
+			HPSA "%d: a state change detected, command retried\n",
+			h->ctlr);
 		break;
 	case LUN_FAILED:
 		dev_warn(&h->pdev->dev,
@@ -1855,6 +1889,34 @@ retry_cmd:
 	queue_work_on(raw_smp_processor_id(), h->resubmit_wq, &c->work);
 }
 
+/* Returns 0 on success, < 0 otherwise. */
+static int hpsa_evaluate_tmf_status(struct ctlr_info *h,
+					struct CommandList *cp)
+{
+	u8 tmf_status = cp->err_info->ScsiStatus;
+
+	switch (tmf_status) {
+	case CISS_TMF_COMPLETE:
+		/*
+		 * CISS_TMF_COMPLETE never happens, instead,
+		 * ei->CommandStatus == 0 for this case.
+		 */
+	case CISS_TMF_SUCCESS:
+		return 0;
+	case CISS_TMF_INVALID_FRAME:
+	case CISS_TMF_NOT_SUPPORTED:
+	case CISS_TMF_FAILED:
+	case CISS_TMF_WRONG_LUN:
+	case CISS_TMF_OVERLAPPED_TAG:
+		break;
+	default:
+		dev_warn(&h->pdev->dev, "Unknown TMF status: 0x%02x\n",
+				tmf_status);
+		break;
+	}
+	return -tmf_status;
+}
+
 static void complete_scsi_command(struct CommandList *cp)
 {
 	struct scsi_cmnd *cmd;
@@ -1862,9 +1924,9 @@ static void complete_scsi_command(struct CommandList *cp)
 	struct ErrorInfo *ei;
 	struct hpsa_scsi_dev_t *dev;
 
-	unsigned char sense_key;
-	unsigned char asc;      /* additional sense code */
-	unsigned char ascq;     /* additional sense code qualifier */
+	u8 sense_key;
+	u8 asc;      /* additional sense code */
+	u8 ascq;     /* additional sense code qualifier */
 	unsigned long sense_data_size;
 
 	ei = cp->err_info;
@@ -1899,8 +1961,6 @@ static void complete_scsi_command(struct CommandList *cp)
 	if (cp->cmd_type == CMD_IOACCEL2)
 		return process_ioaccel2_completion(h, cp, cmd, dev);
 
-	cmd->result |= ei->ScsiStatus;
-
 	scsi_set_resid(cmd, ei->ResidualCnt);
 	if (ei->CommandStatus == 0) {
 		if (cp->cmd_type == CMD_IOACCEL1)
@@ -1910,16 +1970,6 @@ static void complete_scsi_command(struct CommandList *cp)
 		return;
 	}
 
-	/* copy the sense data */
-	if (SCSI_SENSE_BUFFERSIZE < sizeof(ei->SenseInfo))
-		sense_data_size = SCSI_SENSE_BUFFERSIZE;
-	else
-		sense_data_size = sizeof(ei->SenseInfo);
-	if (ei->SenseLen < sense_data_size)
-		sense_data_size = ei->SenseLen;
-
-	memcpy(cmd->sense_buffer, ei->SenseInfo, sense_data_size);
-
 	/* For I/O accelerator commands, copy over some fields to the normal
 	 * CISS header used below for error handling.
 	 */
@@ -1951,14 +2001,18 @@ static void complete_scsi_command(struct CommandList *cp)
 	switch (ei->CommandStatus) {
 
 	case CMD_TARGET_STATUS:
-		if (ei->ScsiStatus) {
-			/* Get sense key */
-			sense_key = 0xf & ei->SenseInfo[2];
-			/* Get additional sense code */
-			asc = ei->SenseInfo[12];
-			/* Get addition sense code qualifier */
-			ascq = ei->SenseInfo[13];
-		}
+		cmd->result |= ei->ScsiStatus;
+		/* copy the sense data */
+		if (SCSI_SENSE_BUFFERSIZE < sizeof(ei->SenseInfo))
+			sense_data_size = SCSI_SENSE_BUFFERSIZE;
+		else
+			sense_data_size = sizeof(ei->SenseInfo);
+		if (ei->SenseLen < sense_data_size)
+			sense_data_size = ei->SenseLen;
+		memcpy(cmd->sense_buffer, ei->SenseInfo, sense_data_size);
+		if (ei->ScsiStatus)
+			decode_sense_data(ei->SenseInfo, sense_data_size,
+				&sense_key, &asc, &ascq);
 		if (ei->ScsiStatus == SAM_STAT_CHECK_CONDITION) {
 			if (sense_key == ABORTED_COMMAND) {
 				cmd->result |= DID_SOFT_ERROR << 16;
@@ -2053,6 +2107,10 @@ static void complete_scsi_command(struct CommandList *cp)
 		cmd->result = DID_ERROR << 16;
 		dev_warn(&h->pdev->dev, "Command unabortable\n");
 		break;
+	case CMD_TMF_STATUS:
+		if (hpsa_evaluate_tmf_status(h, cp)) /* TMF failed? */
+			cmd->result = DID_ERROR << 16;
+		break;
 	case CMD_IOACCEL_DISABLED:
 		/* This only handles the direct pass-through case since RAID
 		 * offload is handled above.  Just attempt a retry.
@@ -2203,16 +2261,23 @@ static void hpsa_scsi_interpret_error(struct ctlr_info *h,
 {
 	const struct ErrorInfo *ei = cp->err_info;
 	struct device *d = &cp->h->pdev->dev;
-	const u8 *sd = ei->SenseInfo;
+	u8 sense_key, asc, ascq;
+	int sense_len;
 
 	switch (ei->CommandStatus) {
 	case CMD_TARGET_STATUS:
+		if (ei->SenseLen > sizeof(ei->SenseInfo))
+			sense_len = sizeof(ei->SenseInfo);
+		else
+			sense_len = ei->SenseLen;
+		decode_sense_data(ei->SenseInfo, sense_len,
+					&sense_key, &asc, &ascq);
 		hpsa_print_cmd(h, "SCSI status", cp);
 		if (ei->ScsiStatus == SAM_STAT_CHECK_CONDITION)
-			dev_warn(d, "SCSI Status = 02, Sense key = %02x, ASC = %02x, ASCQ = %02x\n",
-				sd[2] & 0x0f, sd[12], sd[13]);
+			dev_warn(d, "SCSI Status = 02, Sense key = 0x%02x, ASC = 0x%02x, ASCQ = 0x%02x\n",
+				sense_key, asc, ascq);
 		else
-			dev_warn(d, "SCSI Status = %02x\n", ei->ScsiStatus);
+			dev_warn(d, "SCSI Status = 0x%02x\n", ei->ScsiStatus);
 		if (ei->ScsiStatus == 0)
 			dev_warn(d, "SCSI status is abnormally zero.  "
 			"(probably indicates selection timeout "
@@ -2757,7 +2822,9 @@ static int hpsa_volume_offline(struct ctlr_info *h,
 					unsigned char scsi3addr[])
 {
 	struct CommandList *c;
-	unsigned char *sense, sense_key, asc, ascq;
+	unsigned char *sense;
+	u8 sense_key, asc, ascq;
+	int sense_len;
 	int rc, ldstat = 0;
 	u16 cmd_status;
 	u8 scsi_status;
@@ -2775,9 +2842,11 @@ static int hpsa_volume_offline(struct ctlr_info *h,
 		return 0;
 	}
 	sense = c->err_info->SenseInfo;
-	sense_key = sense[2];
-	asc = sense[12];
-	ascq = sense[13];
+	if (c->err_info->SenseLen > sizeof(c->err_info->SenseInfo))
+		sense_len = sizeof(c->err_info->SenseInfo);
+	else
+		sense_len = c->err_info->SenseLen;
+	decode_sense_data(sense, sense_len, &sense_key, &asc, &ascq);
 	cmd_status = c->err_info->CommandStatus;
 	scsi_status = c->err_info->ScsiStatus;
 	cmd_free(h, c);
@@ -2853,6 +2922,9 @@ static int hpsa_device_supports_aborts(struct ctlr_info *h,
 	case CMD_ABORT_FAILED:
 		rc = 1;
 		break;
+	case CMD_TMF_STATUS:
+		rc = hpsa_evaluate_tmf_status(h, c);
+		break;
 	default:
 		rc = 0;
 		break;
@@ -4650,6 +4722,9 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
 	switch (ei->CommandStatus) {
 	case CMD_SUCCESS:
 		break;
+	case CMD_TMF_STATUS:
+		rc = hpsa_evaluate_tmf_status(h, c);
+		break;
 	case CMD_UNABORTABLE: /* Very common, don't make noise. */
 		rc = -1;
 		break;
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index f52c847..f6ca5fa 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -42,6 +42,7 @@
 #define CMD_UNSOLICITED_ABORT   0x000A
 #define CMD_TIMEOUT             0x000B
 #define CMD_UNABORTABLE		0x000C
+#define CMD_TMF_STATUS		0x000D
 #define CMD_IOACCEL_DISABLED	0x000E
 #define CMD_CTLR_LOCKUP		0xffff
 /* Note: CMD_CTLR_LOCKUP is not a value defined by the CISS spec
@@ -49,6 +50,14 @@
  * with when a controller lockup has been detected by the driver
  */
 
+/* TMF function status values */
+#define CISS_TMF_COMPLETE	0x00
+#define CISS_TMF_INVALID_FRAME	0x02
+#define CISS_TMF_NOT_SUPPORTED	0x04
+#define CISS_TMF_FAILED		0x05
+#define CISS_TMF_SUCCESS	0x08
+#define CISS_TMF_WRONG_LUN	0x09
+#define CISS_TMF_OVERLAPPED_TAG 0x0a
 
 /* Unit Attentions ASC's as defined for the MSA2012sa */
 #define POWER_OR_RESET			0x29


  parent reply	other threads:[~2015-04-23 14:33 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-04-23 14:31 [PATCH v5 00/42] hpsa updates Don Brace
2015-04-23 14:31 ` [PATCH v5 01/42] hpsa: add masked physical devices into h->dev[] array Don Brace
2015-04-23 14:31 ` [PATCH v5 02/42] hpsa: clean up host, channel, target, lun prints Don Brace
2015-04-23 14:32 ` [PATCH v5 03/42] hpsa: rework controller command submission Don Brace
2015-04-23 14:32 ` [PATCH v5 04/42] hpsa: clean up aborts Don Brace
2015-04-23 14:32 ` [PATCH v5 05/42] hpsa: decrement h->commands_outstanding in fail_all_outstanding_cmds Don Brace
2015-04-23 14:32 ` Don Brace [this message]
2015-04-23 14:32 ` [PATCH v5 07/42] hpsa: allow lockup detected to be viewed via sysfs Don Brace
2015-04-23 14:32 ` [PATCH v5 08/42] hpsa: make function names consistent Don Brace
2015-04-23 14:32 ` [PATCH v5 09/42] hpsa: factor out hpsa_init_cmd function Don Brace
2015-04-23 14:32 ` [PATCH v5 10/42] hpsa: do not ignore return value of hpsa_register_scsi Don Brace
2015-04-23 14:32 ` [PATCH v5 11/42] hpsa: try resubmitting down raid path on task set full Don Brace
2015-04-23 14:32 ` [PATCH v5 12/42] hpsa: factor out hpsa_ioaccel_submit function Don Brace
2015-04-23 14:32 ` [PATCH v5 13/42] hpsa: print accurate SSD Smart Path Enabled status Don Brace
2015-04-23 14:32 ` [PATCH v5 14/42] hpsa: use ioaccel2 path to submit IOs to physical drives in HBA mode Don Brace
2015-04-23 14:33 ` [PATCH v5 15/42] hpsa: Get queue depth from identify physical bmic for physical disks Don Brace
2015-04-23 14:33 ` [PATCH v5 16/42] hpsa: break hpsa_free_irqs_and_disable_msix into two functions Don Brace
2015-04-23 14:33 ` [PATCH v5 17/42] hpsa: clean up error handling Don Brace
2015-04-23 14:33 ` [PATCH v5 18/42] hpsa: refactor freeing of resources into more logical functions Don Brace
2015-04-23 14:33 ` [PATCH v5 19/42] hpsa: add ioaccel sg chaining for the ioaccel2 path Don Brace
2015-04-23 14:33 ` [PATCH v5 20/42] hpsa: add more ioaccel2 error handling, including underrun statuses Don Brace
2015-04-23 14:33 ` [PATCH v5 21/42] hpsa: do not check cmd_alloc return value - it cannnot return NULL Don Brace
2015-04-23 14:33 ` [PATCH v5 22/42] hpsa: correct return values from driver functions Don Brace
2015-04-23 14:33 ` [PATCH v5 23/42] hpsa: clean up driver init Don Brace
2015-04-23 14:33 ` [PATCH v5 24/42] hpsa: clean up some error reporting output in abort handler Don Brace
2015-04-23 14:34 ` [PATCH v5 25/42] hpsa: do not print ioaccel2 warning messages about unusual completions Don Brace
2015-04-23 14:34 ` [PATCH v5 26/42] hpsa: add support sending aborts to physical devices via the ioaccel2 path Don Brace
2015-04-23 14:34 ` [PATCH v5 27/42] hpsa: use helper routines for finishing commands Don Brace
2015-04-23 14:34 ` [PATCH v5 28/42] hpsa: don't return abort request until target is complete Don Brace
2015-04-23 14:34 ` [PATCH v5 29/42] hpsa: refactor and rework support for sending TEST_UNIT_READY Don Brace
2015-04-23 14:34 ` [PATCH v5 30/42] hpsa: performance tweak for hpsa_scatter_gather() Don Brace
2015-04-23 14:34 ` [PATCH v5 31/42] hpsa: call pci_release_regions after pci_disable_device Don Brace
2015-04-23 14:34 ` [PATCH v5 32/42] hpsa: skip free_irq calls if irqs are not allocated Don Brace
2015-04-23 14:34 ` [PATCH v5 33/42] hpsa: cleanup for init_one step 2 in kdump Don Brace
2015-04-23 14:34 ` [PATCH v5 34/42] hpsa: fix try_soft_reset error handling Don Brace
2015-04-23 14:34 ` [PATCH v5 35/42] hpsa: create workqueue after the driver is ready for use Don Brace
2015-04-23 14:34 ` [PATCH v5 36/42] hpsa: add interrupt number to /proc/interrupts interrupt name Don Brace
2015-04-23 14:35 ` [PATCH v5 37/42] hpsa: use block layer tag for command allocation Don Brace
2015-04-23 14:35 ` [PATCH v5 38/42] hpsa: use scsi host_no as hpsa controller number Don Brace
2015-04-23 14:35 ` [PATCH v5 39/42] hpsa: propagate the error code in hpsa_kdump_soft_reset Don Brace
2015-04-23 14:35 ` [PATCH v5 40/42] hpsa: cleanup reset Don Brace
2015-04-23 14:35 ` [PATCH v5 41/42] hpsa: add in new controller id Don Brace
2015-04-23 14:35 ` [PATCH v5 42/42] hpsa: change driver version Don Brace
2015-05-11  9:13 ` [PATCH v5 00/42] hpsa updates Christoph Hellwig

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=20150423143216.18832.19674.stgit@brunhilda \
    --to=don.brace@pmcs.com \
    --cc=Justin.Lindley@pmcs.com \
    --cc=Kevin.Barnett@pmcs.com \
    --cc=brace@pmcs.com \
    --cc=hch@infradead.org \
    --cc=james.bottomley@parallels.com \
    --cc=linux-scsi@vger.kernel.org \
    --cc=scott.teel@pmcs.com \
    /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