-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhpsa-handle-command-status-tmf-function-status
149 lines (139 loc) · 4.64 KB
/
hpsa-handle-command-status-tmf-function-status
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
hpsa: handle Command Status TMF function status
From: Stephen M. Cameron <scameron@beardog.cce.hp.com>
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.
Signed-off-by: Stephen M. Cameron <scameron@beardog.cce.hp.com>
---
drivers/scsi/hpsa.c | 58 +++++++++++++++++++++++++++++++++++++----------
drivers/scsi/hpsa_cmd.h | 9 +++++++
2 files changed, 55 insertions(+), 12 deletions(-)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index fb931d0..7fb7d8b 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -1877,6 +1877,33 @@ 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: %02x\n",
+ tmf_status);
+ break;
+ }
+ return -tmf_status;
+}
+
static void complete_scsi_command(struct CommandList *cp)
{
struct scsi_cmnd *cmd;
@@ -1905,8 +1932,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) {
cmd_free(h, cp);
@@ -1914,16 +1939,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.
*/
@@ -1953,6 +1968,15 @@ static void complete_scsi_command(struct CommandList *cp)
switch (ei->CommandStatus) {
case CMD_TARGET_STATUS:
+ 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);
@@ -2050,6 +2074,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.
@@ -2847,6 +2875,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;
@@ -4602,6 +4633,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 d5baded..5ec8553 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -42,8 +42,17 @@
#define CMD_UNSOLICITED_ABORT 0x000A
#define CMD_TIMEOUT 0x000B
#define CMD_UNABORTABLE 0x000C
+#define CMD_TMF_STATUS 0x000D
#define CMD_IOACCEL_DISABLED 0x000E
+/* 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