xref: /linux/drivers/scsi/scsi_trace.c (revision b6ebbac51bedf9e98e837688bc838f400196da5e)
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) ((cdb[8] << 8) | cdb[9])
25 
26 static const char *
27 scsi_trace_misc(struct trace_seq *, unsigned char *, int);
28 
29 static const char *
30 scsi_trace_rw6(struct trace_seq *p, unsigned char *cdb, int len)
31 {
32 	const char *ret = trace_seq_buffer_ptr(p);
33 	sector_t lba = 0, txlen = 0;
34 
35 	lba |= ((cdb[1] & 0x1F) << 16);
36 	lba |=  (cdb[2] << 8);
37 	lba |=   cdb[3];
38 	txlen = cdb[4];
39 
40 	trace_seq_printf(p, "lba=%llu txlen=%llu",
41 			 (unsigned long long)lba, (unsigned long long)txlen);
42 	trace_seq_putc(p, 0);
43 
44 	return ret;
45 }
46 
47 static const char *
48 scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len)
49 {
50 	const char *ret = trace_seq_buffer_ptr(p);
51 	sector_t lba = 0, txlen = 0;
52 
53 	lba |= (cdb[2] << 24);
54 	lba |= (cdb[3] << 16);
55 	lba |= (cdb[4] << 8);
56 	lba |=  cdb[5];
57 	txlen |= (cdb[7] << 8);
58 	txlen |=  cdb[8];
59 
60 	trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
61 			 (unsigned long long)lba, (unsigned long long)txlen,
62 			 cdb[1] >> 5);
63 
64 	if (cdb[0] == WRITE_SAME)
65 		trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1);
66 
67 	trace_seq_putc(p, 0);
68 
69 	return ret;
70 }
71 
72 static const char *
73 scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len)
74 {
75 	const char *ret = trace_seq_buffer_ptr(p);
76 	sector_t lba = 0, txlen = 0;
77 
78 	lba |= (cdb[2] << 24);
79 	lba |= (cdb[3] << 16);
80 	lba |= (cdb[4] << 8);
81 	lba |=  cdb[5];
82 	txlen |= (cdb[6] << 24);
83 	txlen |= (cdb[7] << 16);
84 	txlen |= (cdb[8] << 8);
85 	txlen |=  cdb[9];
86 
87 	trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
88 			 (unsigned long long)lba, (unsigned long long)txlen,
89 			 cdb[1] >> 5);
90 	trace_seq_putc(p, 0);
91 
92 	return ret;
93 }
94 
95 static const char *
96 scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len)
97 {
98 	const char *ret = trace_seq_buffer_ptr(p);
99 	sector_t lba = 0, txlen = 0;
100 
101 	lba |= ((u64)cdb[2] << 56);
102 	lba |= ((u64)cdb[3] << 48);
103 	lba |= ((u64)cdb[4] << 40);
104 	lba |= ((u64)cdb[5] << 32);
105 	lba |= (cdb[6] << 24);
106 	lba |= (cdb[7] << 16);
107 	lba |= (cdb[8] << 8);
108 	lba |=  cdb[9];
109 	txlen |= (cdb[10] << 24);
110 	txlen |= (cdb[11] << 16);
111 	txlen |= (cdb[12] << 8);
112 	txlen |=  cdb[13];
113 
114 	trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
115 			 (unsigned long long)lba, (unsigned long long)txlen,
116 			 cdb[1] >> 5);
117 
118 	if (cdb[0] == WRITE_SAME_16)
119 		trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1);
120 
121 	trace_seq_putc(p, 0);
122 
123 	return ret;
124 }
125 
126 static const char *
127 scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len)
128 {
129 	const char *ret = trace_seq_buffer_ptr(p), *cmd;
130 	sector_t lba = 0, txlen = 0;
131 	u32 ei_lbrt = 0;
132 
133 	switch (SERVICE_ACTION32(cdb)) {
134 	case READ_32:
135 		cmd = "READ";
136 		break;
137 	case VERIFY_32:
138 		cmd = "VERIFY";
139 		break;
140 	case WRITE_32:
141 		cmd = "WRITE";
142 		break;
143 	case WRITE_SAME_32:
144 		cmd = "WRITE_SAME";
145 		break;
146 	default:
147 		trace_seq_puts(p, "UNKNOWN");
148 		goto out;
149 	}
150 
151 	lba |= ((u64)cdb[12] << 56);
152 	lba |= ((u64)cdb[13] << 48);
153 	lba |= ((u64)cdb[14] << 40);
154 	lba |= ((u64)cdb[15] << 32);
155 	lba |= (cdb[16] << 24);
156 	lba |= (cdb[17] << 16);
157 	lba |= (cdb[18] << 8);
158 	lba |=  cdb[19];
159 	ei_lbrt |= (cdb[20] << 24);
160 	ei_lbrt |= (cdb[21] << 16);
161 	ei_lbrt |= (cdb[22] << 8);
162 	ei_lbrt |=  cdb[23];
163 	txlen |= (cdb[28] << 24);
164 	txlen |= (cdb[29] << 16);
165 	txlen |= (cdb[30] << 8);
166 	txlen |=  cdb[31];
167 
168 	trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu protect=%u ei_lbrt=%u",
169 			 cmd, (unsigned long long)lba,
170 			 (unsigned long long)txlen, cdb[10] >> 5, ei_lbrt);
171 
172 	if (SERVICE_ACTION32(cdb) == WRITE_SAME_32)
173 		trace_seq_printf(p, " unmap=%u", cdb[10] >> 3 & 1);
174 
175 out:
176 	trace_seq_putc(p, 0);
177 
178 	return ret;
179 }
180 
181 static const char *
182 scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len)
183 {
184 	const char *ret = trace_seq_buffer_ptr(p);
185 	unsigned int regions = cdb[7] << 8 | cdb[8];
186 
187 	trace_seq_printf(p, "regions=%u", (regions - 8) / 16);
188 	trace_seq_putc(p, 0);
189 
190 	return ret;
191 }
192 
193 static const char *
194 scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len)
195 {
196 	const char *ret = trace_seq_buffer_ptr(p), *cmd;
197 	sector_t lba = 0;
198 	u32 alloc_len = 0;
199 
200 	switch (SERVICE_ACTION16(cdb)) {
201 	case SAI_READ_CAPACITY_16:
202 		cmd = "READ_CAPACITY_16";
203 		break;
204 	case SAI_GET_LBA_STATUS:
205 		cmd = "GET_LBA_STATUS";
206 		break;
207 	default:
208 		trace_seq_puts(p, "UNKNOWN");
209 		goto out;
210 	}
211 
212 	lba |= ((u64)cdb[2] << 56);
213 	lba |= ((u64)cdb[3] << 48);
214 	lba |= ((u64)cdb[4] << 40);
215 	lba |= ((u64)cdb[5] << 32);
216 	lba |= (cdb[6] << 24);
217 	lba |= (cdb[7] << 16);
218 	lba |= (cdb[8] << 8);
219 	lba |=  cdb[9];
220 	alloc_len |= (cdb[10] << 24);
221 	alloc_len |= (cdb[11] << 16);
222 	alloc_len |= (cdb[12] << 8);
223 	alloc_len |=  cdb[13];
224 
225 	trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd,
226 			 (unsigned long long)lba, alloc_len);
227 
228 out:
229 	trace_seq_putc(p, 0);
230 
231 	return ret;
232 }
233 
234 static const char *
235 scsi_trace_maintenance_in(struct trace_seq *p, unsigned char *cdb, int len)
236 {
237 	const char *ret = trace_seq_buffer_ptr(p), *cmd;
238 	u32 alloc_len;
239 
240 	switch (SERVICE_ACTION16(cdb)) {
241 	case MI_REPORT_IDENTIFYING_INFORMATION:
242 		cmd = "REPORT_IDENTIFYING_INFORMATION";
243 		break;
244 	case MI_REPORT_TARGET_PGS:
245 		cmd = "REPORT_TARGET_PORT_GROUPS";
246 		break;
247 	case MI_REPORT_ALIASES:
248 		cmd = "REPORT_ALIASES";
249 		break;
250 	case MI_REPORT_SUPPORTED_OPERATION_CODES:
251 		cmd = "REPORT_SUPPORTED_OPERATION_CODES";
252 		break;
253 	case MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS:
254 		cmd = "REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS";
255 		break;
256 	case MI_REPORT_PRIORITY:
257 		cmd = "REPORT_PRIORITY";
258 		break;
259 	case MI_REPORT_TIMESTAMP:
260 		cmd = "REPORT_TIMESTAMP";
261 		break;
262 	case MI_MANAGEMENT_PROTOCOL_IN:
263 		cmd = "MANAGEMENT_PROTOCOL_IN";
264 		break;
265 	default:
266 		trace_seq_puts(p, "UNKNOWN");
267 		goto out;
268 	}
269 
270 	alloc_len = get_unaligned_be32(&cdb[6]);
271 
272 	trace_seq_printf(p, "%s alloc_len=%u", cmd, alloc_len);
273 
274 out:
275 	trace_seq_putc(p, 0);
276 
277 	return ret;
278 }
279 
280 static const char *
281 scsi_trace_maintenance_out(struct trace_seq *p, unsigned char *cdb, int len)
282 {
283 	const char *ret = trace_seq_buffer_ptr(p), *cmd;
284 	u32 alloc_len;
285 
286 	switch (SERVICE_ACTION16(cdb)) {
287 	case MO_SET_IDENTIFYING_INFORMATION:
288 		cmd = "SET_IDENTIFYING_INFORMATION";
289 		break;
290 	case MO_SET_TARGET_PGS:
291 		cmd = "SET_TARGET_PORT_GROUPS";
292 		break;
293 	case MO_CHANGE_ALIASES:
294 		cmd = "CHANGE_ALIASES";
295 		break;
296 	case MO_SET_PRIORITY:
297 		cmd = "SET_PRIORITY";
298 		break;
299 	case MO_SET_TIMESTAMP:
300 		cmd = "SET_TIMESTAMP";
301 		break;
302 	case MO_MANAGEMENT_PROTOCOL_OUT:
303 		cmd = "MANAGEMENT_PROTOCOL_OUT";
304 		break;
305 	default:
306 		trace_seq_puts(p, "UNKNOWN");
307 		goto out;
308 	}
309 
310 	alloc_len = get_unaligned_be32(&cdb[6]);
311 
312 	trace_seq_printf(p, "%s alloc_len=%u", cmd, alloc_len);
313 
314 out:
315 	trace_seq_putc(p, 0);
316 
317 	return ret;
318 }
319 
320 static const char *
321 scsi_trace_zbc_in(struct trace_seq *p, unsigned char *cdb, int len)
322 {
323 	const char *ret = trace_seq_buffer_ptr(p), *cmd;
324 	u64 zone_id;
325 	u32 alloc_len;
326 	u8 options;
327 
328 	switch (SERVICE_ACTION16(cdb)) {
329 	case ZI_REPORT_ZONES:
330 		cmd = "REPORT_ZONES";
331 		break;
332 	default:
333 		trace_seq_puts(p, "UNKNOWN");
334 		goto out;
335 	}
336 
337 	zone_id = get_unaligned_be64(&cdb[2]);
338 	alloc_len = get_unaligned_be32(&cdb[10]);
339 	options = cdb[14] & 0x3f;
340 
341 	trace_seq_printf(p, "%s zone=%llu alloc_len=%u options=%u partial=%u",
342 			 cmd, (unsigned long long)zone_id, alloc_len,
343 			 options, (cdb[14] >> 7) & 1);
344 
345 out:
346 	trace_seq_putc(p, 0);
347 
348 	return ret;
349 }
350 
351 static const char *
352 scsi_trace_zbc_out(struct trace_seq *p, unsigned char *cdb, int len)
353 {
354 	const char *ret = trace_seq_buffer_ptr(p), *cmd;
355 	u64 zone_id;
356 
357 	switch (SERVICE_ACTION16(cdb)) {
358 	case ZO_CLOSE_ZONE:
359 		cmd = "CLOSE_ZONE";
360 		break;
361 	case ZO_FINISH_ZONE:
362 		cmd = "FINISH_ZONE";
363 		break;
364 	case ZO_OPEN_ZONE:
365 		cmd = "OPEN_ZONE";
366 		break;
367 	case ZO_RESET_WRITE_POINTER:
368 		cmd = "RESET_WRITE_POINTER";
369 		break;
370 	default:
371 		trace_seq_puts(p, "UNKNOWN");
372 		goto out;
373 	}
374 
375 	zone_id = get_unaligned_be64(&cdb[2]);
376 
377 	trace_seq_printf(p, "%s zone=%llu all=%u", cmd,
378 			 (unsigned long long)zone_id, cdb[14] & 1);
379 
380 out:
381 	trace_seq_putc(p, 0);
382 
383 	return ret;
384 }
385 
386 static const char *
387 scsi_trace_varlen(struct trace_seq *p, unsigned char *cdb, int len)
388 {
389 	switch (SERVICE_ACTION32(cdb)) {
390 	case READ_32:
391 	case VERIFY_32:
392 	case WRITE_32:
393 	case WRITE_SAME_32:
394 		return scsi_trace_rw32(p, cdb, len);
395 	default:
396 		return scsi_trace_misc(p, cdb, len);
397 	}
398 }
399 
400 static const char *
401 scsi_trace_misc(struct trace_seq *p, unsigned char *cdb, int len)
402 {
403 	const char *ret = trace_seq_buffer_ptr(p);
404 
405 	trace_seq_putc(p, '-');
406 	trace_seq_putc(p, 0);
407 
408 	return ret;
409 }
410 
411 const char *
412 scsi_trace_parse_cdb(struct trace_seq *p, unsigned char *cdb, int len)
413 {
414 	switch (cdb[0]) {
415 	case READ_6:
416 	case WRITE_6:
417 		return scsi_trace_rw6(p, cdb, len);
418 	case READ_10:
419 	case VERIFY:
420 	case WRITE_10:
421 	case WRITE_SAME:
422 		return scsi_trace_rw10(p, cdb, len);
423 	case READ_12:
424 	case VERIFY_12:
425 	case WRITE_12:
426 		return scsi_trace_rw12(p, cdb, len);
427 	case READ_16:
428 	case VERIFY_16:
429 	case WRITE_16:
430 	case WRITE_SAME_16:
431 		return scsi_trace_rw16(p, cdb, len);
432 	case UNMAP:
433 		return scsi_trace_unmap(p, cdb, len);
434 	case SERVICE_ACTION_IN_16:
435 		return scsi_trace_service_action_in(p, cdb, len);
436 	case VARIABLE_LENGTH_CMD:
437 		return scsi_trace_varlen(p, cdb, len);
438 	case MAINTENANCE_IN:
439 		return scsi_trace_maintenance_in(p, cdb, len);
440 	case MAINTENANCE_OUT:
441 		return scsi_trace_maintenance_out(p, cdb, len);
442 	case ZBC_IN:
443 		return scsi_trace_zbc_in(p, cdb, len);
444 	case ZBC_OUT:
445 		return scsi_trace_zbc_out(p, cdb, len);
446 	default:
447 		return scsi_trace_misc(p, cdb, len);
448 	}
449 }
450