1 /*
2 * Copyright (C) 2010 FUJITSU LIMITED
3 * Copyright (C) 2010 Tomohiro Kusumi <kusumi.tomohiro@jp.fujitsu.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 #include <linux/kernel.h>
19 #include <linux/trace_seq.h>
20 #include <asm/unaligned.h>
21 #include <trace/events/scsi.h>
22
23 #define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f)
24 #define SERVICE_ACTION32(cdb) (get_unaligned_be16(&cdb[8]))
25
26 static const char *
27 scsi_trace_misc(struct trace_seq *, unsigned char *, int);
28
29 static const char *
scsi_trace_rw6(struct trace_seq * p,unsigned char * cdb,int len)30 scsi_trace_rw6(struct trace_seq *p, unsigned char *cdb, int len)
31 {
32 const char *ret = trace_seq_buffer_ptr(p);
33 u32 lba = 0, txlen;
34
35 lba |= ((cdb[1] & 0x1F) << 16);
36 lba |= (cdb[2] << 8);
37 lba |= cdb[3];
38 /*
39 * From SBC-2: a TRANSFER LENGTH field set to zero specifies that 256
40 * logical blocks shall be read (READ(6)) or written (WRITE(6)).
41 */
42 txlen = cdb[4] ? cdb[4] : 256;
43
44 trace_seq_printf(p, "lba=%u txlen=%u", lba, txlen);
45 trace_seq_putc(p, 0);
46
47 return ret;
48 }
49
50 static const char *
scsi_trace_rw10(struct trace_seq * p,unsigned char * cdb,int len)51 scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len)
52 {
53 const char *ret = trace_seq_buffer_ptr(p);
54 u32 lba, txlen;
55
56 lba = get_unaligned_be32(&cdb[2]);
57 txlen = get_unaligned_be16(&cdb[7]);
58
59 trace_seq_printf(p, "lba=%u txlen=%u protect=%u", lba, txlen,
60 cdb[1] >> 5);
61
62 if (cdb[0] == WRITE_SAME)
63 trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1);
64
65 trace_seq_putc(p, 0);
66
67 return ret;
68 }
69
70 static const char *
scsi_trace_rw12(struct trace_seq * p,unsigned char * cdb,int len)71 scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len)
72 {
73 const char *ret = trace_seq_buffer_ptr(p);
74 u32 lba, txlen;
75
76 lba = get_unaligned_be32(&cdb[2]);
77 txlen = get_unaligned_be32(&cdb[6]);
78
79 trace_seq_printf(p, "lba=%u txlen=%u protect=%u", lba, txlen,
80 cdb[1] >> 5);
81 trace_seq_putc(p, 0);
82
83 return ret;
84 }
85
86 static const char *
scsi_trace_rw16(struct trace_seq * p,unsigned char * cdb,int len)87 scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len)
88 {
89 const char *ret = trace_seq_buffer_ptr(p);
90 u64 lba;
91 u32 txlen;
92
93 lba = get_unaligned_be64(&cdb[2]);
94 txlen = get_unaligned_be32(&cdb[10]);
95
96 trace_seq_printf(p, "lba=%llu txlen=%u protect=%u", lba, txlen,
97 cdb[1] >> 5);
98
99 if (cdb[0] == WRITE_SAME_16)
100 trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1);
101
102 trace_seq_putc(p, 0);
103
104 return ret;
105 }
106
107 static const char *
scsi_trace_rw32(struct trace_seq * p,unsigned char * cdb,int len)108 scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len)
109 {
110 const char *ret = trace_seq_buffer_ptr(p), *cmd;
111 u64 lba;
112 u32 ei_lbrt, txlen;
113
114 switch (SERVICE_ACTION32(cdb)) {
115 case READ_32:
116 cmd = "READ";
117 break;
118 case VERIFY_32:
119 cmd = "VERIFY";
120 break;
121 case WRITE_32:
122 cmd = "WRITE";
123 break;
124 case WRITE_SAME_32:
125 cmd = "WRITE_SAME";
126 break;
127 default:
128 trace_seq_puts(p, "UNKNOWN");
129 goto out;
130 }
131
132 lba = get_unaligned_be64(&cdb[12]);
133 ei_lbrt = get_unaligned_be32(&cdb[20]);
134 txlen = get_unaligned_be32(&cdb[28]);
135
136 trace_seq_printf(p, "%s_32 lba=%llu txlen=%u protect=%u ei_lbrt=%u",
137 cmd, lba, txlen, cdb[10] >> 5, ei_lbrt);
138
139 if (SERVICE_ACTION32(cdb) == WRITE_SAME_32)
140 trace_seq_printf(p, " unmap=%u", cdb[10] >> 3 & 1);
141
142 out:
143 trace_seq_putc(p, 0);
144
145 return ret;
146 }
147
148 static const char *
scsi_trace_unmap(struct trace_seq * p,unsigned char * cdb,int len)149 scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len)
150 {
151 const char *ret = trace_seq_buffer_ptr(p);
152 unsigned int regions = get_unaligned_be16(&cdb[7]);
153
154 trace_seq_printf(p, "regions=%u", (regions - 8) / 16);
155 trace_seq_putc(p, 0);
156
157 return ret;
158 }
159
160 static const char *
scsi_trace_service_action_in(struct trace_seq * p,unsigned char * cdb,int len)161 scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len)
162 {
163 const char *ret = trace_seq_buffer_ptr(p), *cmd;
164 u64 lba;
165 u32 alloc_len;
166
167 switch (SERVICE_ACTION16(cdb)) {
168 case SAI_READ_CAPACITY_16:
169 cmd = "READ_CAPACITY_16";
170 break;
171 case SAI_GET_LBA_STATUS:
172 cmd = "GET_LBA_STATUS";
173 break;
174 default:
175 trace_seq_puts(p, "UNKNOWN");
176 goto out;
177 }
178
179 lba = get_unaligned_be64(&cdb[2]);
180 alloc_len = get_unaligned_be32(&cdb[10]);
181
182 trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd, lba, alloc_len);
183
184 out:
185 trace_seq_putc(p, 0);
186
187 return ret;
188 }
189
190 static const char *
scsi_trace_maintenance_in(struct trace_seq * p,unsigned char * cdb,int len)191 scsi_trace_maintenance_in(struct trace_seq *p, unsigned char *cdb, int len)
192 {
193 const char *ret = trace_seq_buffer_ptr(p), *cmd;
194 u32 alloc_len;
195
196 switch (SERVICE_ACTION16(cdb)) {
197 case MI_REPORT_IDENTIFYING_INFORMATION:
198 cmd = "REPORT_IDENTIFYING_INFORMATION";
199 break;
200 case MI_REPORT_TARGET_PGS:
201 cmd = "REPORT_TARGET_PORT_GROUPS";
202 break;
203 case MI_REPORT_ALIASES:
204 cmd = "REPORT_ALIASES";
205 break;
206 case MI_REPORT_SUPPORTED_OPERATION_CODES:
207 cmd = "REPORT_SUPPORTED_OPERATION_CODES";
208 break;
209 case MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS:
210 cmd = "REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS";
211 break;
212 case MI_REPORT_PRIORITY:
213 cmd = "REPORT_PRIORITY";
214 break;
215 case MI_REPORT_TIMESTAMP:
216 cmd = "REPORT_TIMESTAMP";
217 break;
218 case MI_MANAGEMENT_PROTOCOL_IN:
219 cmd = "MANAGEMENT_PROTOCOL_IN";
220 break;
221 default:
222 trace_seq_puts(p, "UNKNOWN");
223 goto out;
224 }
225
226 alloc_len = get_unaligned_be32(&cdb[6]);
227
228 trace_seq_printf(p, "%s alloc_len=%u", cmd, alloc_len);
229
230 out:
231 trace_seq_putc(p, 0);
232
233 return ret;
234 }
235
236 static const char *
scsi_trace_maintenance_out(struct trace_seq * p,unsigned char * cdb,int len)237 scsi_trace_maintenance_out(struct trace_seq *p, unsigned char *cdb, int len)
238 {
239 const char *ret = trace_seq_buffer_ptr(p), *cmd;
240 u32 alloc_len;
241
242 switch (SERVICE_ACTION16(cdb)) {
243 case MO_SET_IDENTIFYING_INFORMATION:
244 cmd = "SET_IDENTIFYING_INFORMATION";
245 break;
246 case MO_SET_TARGET_PGS:
247 cmd = "SET_TARGET_PORT_GROUPS";
248 break;
249 case MO_CHANGE_ALIASES:
250 cmd = "CHANGE_ALIASES";
251 break;
252 case MO_SET_PRIORITY:
253 cmd = "SET_PRIORITY";
254 break;
255 case MO_SET_TIMESTAMP:
256 cmd = "SET_TIMESTAMP";
257 break;
258 case MO_MANAGEMENT_PROTOCOL_OUT:
259 cmd = "MANAGEMENT_PROTOCOL_OUT";
260 break;
261 default:
262 trace_seq_puts(p, "UNKNOWN");
263 goto out;
264 }
265
266 alloc_len = get_unaligned_be32(&cdb[6]);
267
268 trace_seq_printf(p, "%s alloc_len=%u", cmd, alloc_len);
269
270 out:
271 trace_seq_putc(p, 0);
272
273 return ret;
274 }
275
276 static const char *
scsi_trace_zbc_in(struct trace_seq * p,unsigned char * cdb,int len)277 scsi_trace_zbc_in(struct trace_seq *p, unsigned char *cdb, int len)
278 {
279 const char *ret = trace_seq_buffer_ptr(p), *cmd;
280 u64 zone_id;
281 u32 alloc_len;
282 u8 options;
283
284 switch (SERVICE_ACTION16(cdb)) {
285 case ZI_REPORT_ZONES:
286 cmd = "REPORT_ZONES";
287 break;
288 default:
289 trace_seq_puts(p, "UNKNOWN");
290 goto out;
291 }
292
293 zone_id = get_unaligned_be64(&cdb[2]);
294 alloc_len = get_unaligned_be32(&cdb[10]);
295 options = cdb[14] & 0x3f;
296
297 trace_seq_printf(p, "%s zone=%llu alloc_len=%u options=%u partial=%u",
298 cmd, (unsigned long long)zone_id, alloc_len,
299 options, (cdb[14] >> 7) & 1);
300
301 out:
302 trace_seq_putc(p, 0);
303
304 return ret;
305 }
306
307 static const char *
scsi_trace_zbc_out(struct trace_seq * p,unsigned char * cdb,int len)308 scsi_trace_zbc_out(struct trace_seq *p, unsigned char *cdb, int len)
309 {
310 const char *ret = trace_seq_buffer_ptr(p), *cmd;
311 u64 zone_id;
312
313 switch (SERVICE_ACTION16(cdb)) {
314 case ZO_CLOSE_ZONE:
315 cmd = "CLOSE_ZONE";
316 break;
317 case ZO_FINISH_ZONE:
318 cmd = "FINISH_ZONE";
319 break;
320 case ZO_OPEN_ZONE:
321 cmd = "OPEN_ZONE";
322 break;
323 case ZO_RESET_WRITE_POINTER:
324 cmd = "RESET_WRITE_POINTER";
325 break;
326 default:
327 trace_seq_puts(p, "UNKNOWN");
328 goto out;
329 }
330
331 zone_id = get_unaligned_be64(&cdb[2]);
332
333 trace_seq_printf(p, "%s zone=%llu all=%u", cmd,
334 (unsigned long long)zone_id, cdb[14] & 1);
335
336 out:
337 trace_seq_putc(p, 0);
338
339 return ret;
340 }
341
342 static const char *
scsi_trace_varlen(struct trace_seq * p,unsigned char * cdb,int len)343 scsi_trace_varlen(struct trace_seq *p, unsigned char *cdb, int len)
344 {
345 switch (SERVICE_ACTION32(cdb)) {
346 case READ_32:
347 case VERIFY_32:
348 case WRITE_32:
349 case WRITE_SAME_32:
350 return scsi_trace_rw32(p, cdb, len);
351 default:
352 return scsi_trace_misc(p, cdb, len);
353 }
354 }
355
356 static const char *
scsi_trace_misc(struct trace_seq * p,unsigned char * cdb,int len)357 scsi_trace_misc(struct trace_seq *p, unsigned char *cdb, int len)
358 {
359 const char *ret = trace_seq_buffer_ptr(p);
360
361 trace_seq_putc(p, '-');
362 trace_seq_putc(p, 0);
363
364 return ret;
365 }
366
367 const char *
scsi_trace_parse_cdb(struct trace_seq * p,unsigned char * cdb,int len)368 scsi_trace_parse_cdb(struct trace_seq *p, unsigned char *cdb, int len)
369 {
370 switch (cdb[0]) {
371 case READ_6:
372 case WRITE_6:
373 return scsi_trace_rw6(p, cdb, len);
374 case READ_10:
375 case VERIFY:
376 case WRITE_10:
377 case WRITE_SAME:
378 return scsi_trace_rw10(p, cdb, len);
379 case READ_12:
380 case VERIFY_12:
381 case WRITE_12:
382 return scsi_trace_rw12(p, cdb, len);
383 case READ_16:
384 case VERIFY_16:
385 case WRITE_16:
386 case WRITE_SAME_16:
387 return scsi_trace_rw16(p, cdb, len);
388 case UNMAP:
389 return scsi_trace_unmap(p, cdb, len);
390 case SERVICE_ACTION_IN_16:
391 return scsi_trace_service_action_in(p, cdb, len);
392 case VARIABLE_LENGTH_CMD:
393 return scsi_trace_varlen(p, cdb, len);
394 case MAINTENANCE_IN:
395 return scsi_trace_maintenance_in(p, cdb, len);
396 case MAINTENANCE_OUT:
397 return scsi_trace_maintenance_out(p, cdb, len);
398 case ZBC_IN:
399 return scsi_trace_zbc_in(p, cdb, len);
400 case ZBC_OUT:
401 return scsi_trace_zbc_out(p, cdb, len);
402 default:
403 return scsi_trace_misc(p, cdb, len);
404 }
405 }
406