diff options
author | Martin K. Petersen <martin.petersen@oracle.com> | 2010-03-23 01:16:57 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-04-30 13:52:08 -0400 |
commit | c446c1f9907e84d014edb0bf3501f30cb512e06a (patch) | |
tree | b4271bbcfb1ecaedb99428461bd22f56a5121366 /drivers/scsi/scsi_trace.c | |
parent | bf81623542332bc2cedf3db49cbb2edb724780d2 (diff) |
[SCSI] scsi_trace: Enhance SCSI command tracing
Various SCSI trace enhancements:
- Display data and protection information scatterlist lengths in the
trace output
- Add support for VERIFY and WRITE SAME commands and decode the UNMAP
bit if applicable
- Add decoding of the PROTECT field for READ/VERIFY/WRITE/WRITE SAME
commands as well as the EXPECTED INITIAL REFERENCE TAG field for
their 32-byte variants
- Decode READ CAPACITY(16), GET LBA STATUS, and UNMAP
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/scsi_trace.c')
-rw-r--r-- | drivers/scsi/scsi_trace.c | 123 |
1 files changed, 111 insertions, 12 deletions
diff --git a/drivers/scsi/scsi_trace.c b/drivers/scsi/scsi_trace.c index 9a3342a2fa36..b587289cfacb 100644 --- a/drivers/scsi/scsi_trace.c +++ b/drivers/scsi/scsi_trace.c | |||
@@ -19,7 +19,8 @@ | |||
19 | #include <linux/trace_seq.h> | 19 | #include <linux/trace_seq.h> |
20 | #include <trace/events/scsi.h> | 20 | #include <trace/events/scsi.h> |
21 | 21 | ||
22 | #define SERVICE_ACTION(cdb) ((cdb[8] << 8) | cdb[9]) | 22 | #define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f) |
23 | #define SERVICE_ACTION32(cdb) ((cdb[8] << 8) | cdb[9]) | ||
23 | 24 | ||
24 | static const char * | 25 | static const char * |
25 | scsi_trace_misc(struct trace_seq *, unsigned char *, int); | 26 | scsi_trace_misc(struct trace_seq *, unsigned char *, int); |
@@ -55,8 +56,9 @@ scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len) | |||
55 | txlen |= (cdb[7] << 8); | 56 | txlen |= (cdb[7] << 8); |
56 | txlen |= cdb[8]; | 57 | txlen |= cdb[8]; |
57 | 58 | ||
58 | trace_seq_printf(p, "lba=%llu txlen=%llu", | 59 | trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", |
59 | (unsigned long long)lba, (unsigned long long)txlen); | 60 | (unsigned long long)lba, (unsigned long long)txlen, |
61 | cdb[1] >> 5); | ||
60 | trace_seq_putc(p, 0); | 62 | trace_seq_putc(p, 0); |
61 | 63 | ||
62 | return ret; | 64 | return ret; |
@@ -77,8 +79,9 @@ scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len) | |||
77 | txlen |= (cdb[8] << 8); | 79 | txlen |= (cdb[8] << 8); |
78 | txlen |= cdb[9]; | 80 | txlen |= cdb[9]; |
79 | 81 | ||
80 | trace_seq_printf(p, "lba=%llu txlen=%llu", | 82 | trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", |
81 | (unsigned long long)lba, (unsigned long long)txlen); | 83 | (unsigned long long)lba, (unsigned long long)txlen, |
84 | cdb[1] >> 5); | ||
82 | trace_seq_putc(p, 0); | 85 | trace_seq_putc(p, 0); |
83 | 86 | ||
84 | return ret; | 87 | return ret; |
@@ -103,8 +106,13 @@ scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len) | |||
103 | txlen |= (cdb[12] << 8); | 106 | txlen |= (cdb[12] << 8); |
104 | txlen |= cdb[13]; | 107 | txlen |= cdb[13]; |
105 | 108 | ||
106 | trace_seq_printf(p, "lba=%llu txlen=%llu", | 109 | trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", |
107 | (unsigned long long)lba, (unsigned long long)txlen); | 110 | (unsigned long long)lba, (unsigned long long)txlen, |
111 | cdb[1] >> 5); | ||
112 | |||
113 | if (cdb[0] == WRITE_SAME_16) | ||
114 | trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1); | ||
115 | |||
108 | trace_seq_putc(p, 0); | 116 | trace_seq_putc(p, 0); |
109 | 117 | ||
110 | return ret; | 118 | return ret; |
@@ -113,8 +121,27 @@ scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len) | |||
113 | static const char * | 121 | static const char * |
114 | scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len) | 122 | scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len) |
115 | { | 123 | { |
116 | const char *ret = p->buffer + p->len; | 124 | const char *ret = p->buffer + p->len, *cmd; |
117 | sector_t lba = 0, txlen = 0; | 125 | sector_t lba = 0, txlen = 0; |
126 | u32 ei_lbrt = 0; | ||
127 | |||
128 | switch (SERVICE_ACTION32(cdb)) { | ||
129 | case READ_32: | ||
130 | cmd = "READ"; | ||
131 | break; | ||
132 | case VERIFY_32: | ||
133 | cmd = "VERIFY"; | ||
134 | break; | ||
135 | case WRITE_32: | ||
136 | cmd = "WRITE"; | ||
137 | break; | ||
138 | case WRITE_SAME_32: | ||
139 | cmd = "WRITE_SAME"; | ||
140 | break; | ||
141 | default: | ||
142 | trace_seq_printf(p, "UNKNOWN"); | ||
143 | goto out; | ||
144 | } | ||
118 | 145 | ||
119 | lba |= ((u64)cdb[12] << 56); | 146 | lba |= ((u64)cdb[12] << 56); |
120 | lba |= ((u64)cdb[13] << 48); | 147 | lba |= ((u64)cdb[13] << 48); |
@@ -124,15 +151,76 @@ scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len) | |||
124 | lba |= (cdb[17] << 16); | 151 | lba |= (cdb[17] << 16); |
125 | lba |= (cdb[18] << 8); | 152 | lba |= (cdb[18] << 8); |
126 | lba |= cdb[19]; | 153 | lba |= cdb[19]; |
154 | ei_lbrt |= (cdb[20] << 24); | ||
155 | ei_lbrt |= (cdb[21] << 16); | ||
156 | ei_lbrt |= (cdb[22] << 8); | ||
157 | ei_lbrt |= cdb[23]; | ||
127 | txlen |= (cdb[28] << 24); | 158 | txlen |= (cdb[28] << 24); |
128 | txlen |= (cdb[29] << 16); | 159 | txlen |= (cdb[29] << 16); |
129 | txlen |= (cdb[30] << 8); | 160 | txlen |= (cdb[30] << 8); |
130 | txlen |= cdb[31]; | 161 | txlen |= cdb[31]; |
131 | 162 | ||
132 | trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu", | 163 | trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu protect=%u ei_lbrt=%u", |
133 | (SERVICE_ACTION(cdb) == READ_32 ? "READ" : "WRITE"), | 164 | cmd, (unsigned long long)lba, |
134 | (unsigned long long)lba, (unsigned long long)txlen); | 165 | (unsigned long long)txlen, cdb[10] >> 5, ei_lbrt); |
166 | |||
167 | if (SERVICE_ACTION32(cdb) == WRITE_SAME_32) | ||
168 | trace_seq_printf(p, " unmap=%u", cdb[10] >> 3 & 1); | ||
169 | |||
170 | out: | ||
171 | trace_seq_putc(p, 0); | ||
172 | |||
173 | return ret; | ||
174 | } | ||
175 | |||
176 | static const char * | ||
177 | scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len) | ||
178 | { | ||
179 | const char *ret = p->buffer + p->len; | ||
180 | unsigned int regions = cdb[7] << 8 | cdb[8]; | ||
181 | |||
182 | trace_seq_printf(p, "regions=%u", (regions - 8) / 16); | ||
183 | trace_seq_putc(p, 0); | ||
184 | |||
185 | return ret; | ||
186 | } | ||
187 | |||
188 | static const char * | ||
189 | scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len) | ||
190 | { | ||
191 | const char *ret = p->buffer + p->len, *cmd; | ||
192 | sector_t lba = 0; | ||
193 | u32 alloc_len = 0; | ||
194 | |||
195 | switch (SERVICE_ACTION16(cdb)) { | ||
196 | case SAI_READ_CAPACITY_16: | ||
197 | cmd = "READ_CAPACITY_16"; | ||
198 | break; | ||
199 | case SAI_GET_LBA_STATUS: | ||
200 | cmd = "GET_LBA_STATUS"; | ||
201 | break; | ||
202 | default: | ||
203 | trace_seq_printf(p, "UNKNOWN"); | ||
204 | goto out; | ||
205 | } | ||
206 | |||
207 | lba |= ((u64)cdb[2] << 56); | ||
208 | lba |= ((u64)cdb[3] << 48); | ||
209 | lba |= ((u64)cdb[4] << 40); | ||
210 | lba |= ((u64)cdb[5] << 32); | ||
211 | lba |= (cdb[6] << 24); | ||
212 | lba |= (cdb[7] << 16); | ||
213 | lba |= (cdb[8] << 8); | ||
214 | lba |= cdb[9]; | ||
215 | alloc_len |= (cdb[10] << 24); | ||
216 | alloc_len |= (cdb[11] << 16); | ||
217 | alloc_len |= (cdb[12] << 8); | ||
218 | alloc_len |= cdb[13]; | ||
219 | |||
220 | trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd, | ||
221 | (unsigned long long)lba, alloc_len); | ||
135 | 222 | ||
223 | out: | ||
136 | trace_seq_putc(p, 0); | 224 | trace_seq_putc(p, 0); |
137 | 225 | ||
138 | return ret; | 226 | return ret; |
@@ -141,9 +229,11 @@ scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len) | |||
141 | static const char * | 229 | static const char * |
142 | scsi_trace_varlen(struct trace_seq *p, unsigned char *cdb, int len) | 230 | scsi_trace_varlen(struct trace_seq *p, unsigned char *cdb, int len) |
143 | { | 231 | { |
144 | switch (SERVICE_ACTION(cdb)) { | 232 | switch (SERVICE_ACTION32(cdb)) { |
145 | case READ_32: | 233 | case READ_32: |
234 | case VERIFY_32: | ||
146 | case WRITE_32: | 235 | case WRITE_32: |
236 | case WRITE_SAME_32: | ||
147 | return scsi_trace_rw32(p, cdb, len); | 237 | return scsi_trace_rw32(p, cdb, len); |
148 | default: | 238 | default: |
149 | return scsi_trace_misc(p, cdb, len); | 239 | return scsi_trace_misc(p, cdb, len); |
@@ -169,14 +259,23 @@ scsi_trace_parse_cdb(struct trace_seq *p, unsigned char *cdb, int len) | |||
169 | case WRITE_6: | 259 | case WRITE_6: |
170 | return scsi_trace_rw6(p, cdb, len); | 260 | return scsi_trace_rw6(p, cdb, len); |
171 | case READ_10: | 261 | case READ_10: |
262 | case VERIFY: | ||
172 | case WRITE_10: | 263 | case WRITE_10: |
264 | case WRITE_SAME: | ||
173 | return scsi_trace_rw10(p, cdb, len); | 265 | return scsi_trace_rw10(p, cdb, len); |
174 | case READ_12: | 266 | case READ_12: |
267 | case VERIFY_12: | ||
175 | case WRITE_12: | 268 | case WRITE_12: |
176 | return scsi_trace_rw12(p, cdb, len); | 269 | return scsi_trace_rw12(p, cdb, len); |
177 | case READ_16: | 270 | case READ_16: |
271 | case VERIFY_16: | ||
178 | case WRITE_16: | 272 | case WRITE_16: |
273 | case WRITE_SAME_16: | ||
179 | return scsi_trace_rw16(p, cdb, len); | 274 | return scsi_trace_rw16(p, cdb, len); |
275 | case UNMAP: | ||
276 | return scsi_trace_unmap(p, cdb, len); | ||
277 | case SERVICE_ACTION_IN: | ||
278 | return scsi_trace_service_action_in(p, cdb, len); | ||
180 | case VARIABLE_LENGTH_CMD: | 279 | case VARIABLE_LENGTH_CMD: |
181 | return scsi_trace_varlen(p, cdb, len); | 280 | return scsi_trace_varlen(p, cdb, len); |
182 | default: | 281 | default: |