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