• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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