Commit | Line | Data |
---|---|---|
bf816235 KT |
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 <trace/events/scsi.h> | |
21 | ||
c446c1f9 MP |
22 | #define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f) |
23 | #define SERVICE_ACTION32(cdb) ((cdb[8] << 8) | cdb[9]) | |
bf816235 KT |
24 | |
25 | static const char * | |
26 | scsi_trace_misc(struct trace_seq *, unsigned char *, int); | |
27 | ||
28 | static const char * | |
29 | scsi_trace_rw6(struct trace_seq *p, unsigned char *cdb, int len) | |
30 | { | |
31 | const char *ret = p->buffer + p->len; | |
32 | sector_t lba = 0, txlen = 0; | |
33 | ||
34 | lba |= ((cdb[1] & 0x1F) << 16); | |
35 | lba |= (cdb[2] << 8); | |
36 | lba |= cdb[3]; | |
37 | txlen = cdb[4]; | |
38 | ||
39 | trace_seq_printf(p, "lba=%llu txlen=%llu", | |
40 | (unsigned long long)lba, (unsigned long long)txlen); | |
41 | trace_seq_putc(p, 0); | |
42 | ||
43 | return ret; | |
44 | } | |
45 | ||
46 | static const char * | |
47 | scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len) | |
48 | { | |
49 | const char *ret = p->buffer + p->len; | |
50 | sector_t lba = 0, txlen = 0; | |
51 | ||
52 | lba |= (cdb[2] << 24); | |
53 | lba |= (cdb[3] << 16); | |
54 | lba |= (cdb[4] << 8); | |
55 | lba |= cdb[5]; | |
56 | txlen |= (cdb[7] << 8); | |
57 | txlen |= cdb[8]; | |
58 | ||
c446c1f9 MP |
59 | trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", |
60 | (unsigned long long)lba, (unsigned long long)txlen, | |
61 | cdb[1] >> 5); | |
bf816235 KT |
62 | trace_seq_putc(p, 0); |
63 | ||
64 | return ret; | |
65 | } | |
66 | ||
67 | static const char * | |
68 | scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len) | |
69 | { | |
70 | const char *ret = p->buffer + p->len; | |
71 | sector_t lba = 0, txlen = 0; | |
72 | ||
73 | lba |= (cdb[2] << 24); | |
74 | lba |= (cdb[3] << 16); | |
75 | lba |= (cdb[4] << 8); | |
76 | lba |= cdb[5]; | |
77 | txlen |= (cdb[6] << 24); | |
78 | txlen |= (cdb[7] << 16); | |
79 | txlen |= (cdb[8] << 8); | |
80 | txlen |= cdb[9]; | |
81 | ||
c446c1f9 MP |
82 | trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", |
83 | (unsigned long long)lba, (unsigned long long)txlen, | |
84 | cdb[1] >> 5); | |
bf816235 KT |
85 | trace_seq_putc(p, 0); |
86 | ||
87 | return ret; | |
88 | } | |
89 | ||
90 | static const char * | |
91 | scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len) | |
92 | { | |
93 | const char *ret = p->buffer + p->len; | |
94 | sector_t lba = 0, txlen = 0; | |
95 | ||
96 | lba |= ((u64)cdb[2] << 56); | |
97 | lba |= ((u64)cdb[3] << 48); | |
98 | lba |= ((u64)cdb[4] << 40); | |
99 | lba |= ((u64)cdb[5] << 32); | |
100 | lba |= (cdb[6] << 24); | |
101 | lba |= (cdb[7] << 16); | |
102 | lba |= (cdb[8] << 8); | |
103 | lba |= cdb[9]; | |
104 | txlen |= (cdb[10] << 24); | |
105 | txlen |= (cdb[11] << 16); | |
106 | txlen |= (cdb[12] << 8); | |
107 | txlen |= cdb[13]; | |
108 | ||
c446c1f9 MP |
109 | trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", |
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 | ||
bf816235 KT |
116 | trace_seq_putc(p, 0); |
117 | ||
118 | return ret; | |
119 | } | |
120 | ||
121 | static const char * | |
122 | scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len) | |
123 | { | |
c446c1f9 | 124 | const char *ret = p->buffer + p->len, *cmd; |
bf816235 | 125 | sector_t lba = 0, txlen = 0; |
c446c1f9 MP |
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 | } | |
bf816235 KT |
145 | |
146 | lba |= ((u64)cdb[12] << 56); | |
147 | lba |= ((u64)cdb[13] << 48); | |
148 | lba |= ((u64)cdb[14] << 40); | |
149 | lba |= ((u64)cdb[15] << 32); | |
150 | lba |= (cdb[16] << 24); | |
151 | lba |= (cdb[17] << 16); | |
152 | lba |= (cdb[18] << 8); | |
153 | lba |= cdb[19]; | |
c446c1f9 MP |
154 | ei_lbrt |= (cdb[20] << 24); |
155 | ei_lbrt |= (cdb[21] << 16); | |
156 | ei_lbrt |= (cdb[22] << 8); | |
157 | ei_lbrt |= cdb[23]; | |
bf816235 KT |
158 | txlen |= (cdb[28] << 24); |
159 | txlen |= (cdb[29] << 16); | |
160 | txlen |= (cdb[30] << 8); | |
161 | txlen |= cdb[31]; | |
162 | ||
c446c1f9 MP |
163 | trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu protect=%u ei_lbrt=%u", |
164 | cmd, (unsigned long long)lba, | |
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); | |
bf816235 | 222 | |
c446c1f9 | 223 | out: |
bf816235 KT |
224 | trace_seq_putc(p, 0); |
225 | ||
226 | return ret; | |
227 | } | |
228 | ||
229 | static const char * | |
230 | scsi_trace_varlen(struct trace_seq *p, unsigned char *cdb, int len) | |
231 | { | |
c446c1f9 | 232 | switch (SERVICE_ACTION32(cdb)) { |
bf816235 | 233 | case READ_32: |
c446c1f9 | 234 | case VERIFY_32: |
bf816235 | 235 | case WRITE_32: |
c446c1f9 | 236 | case WRITE_SAME_32: |
bf816235 KT |
237 | return scsi_trace_rw32(p, cdb, len); |
238 | default: | |
239 | return scsi_trace_misc(p, cdb, len); | |
240 | } | |
241 | } | |
242 | ||
243 | static const char * | |
244 | scsi_trace_misc(struct trace_seq *p, unsigned char *cdb, int len) | |
245 | { | |
246 | const char *ret = p->buffer + p->len; | |
247 | ||
248 | trace_seq_printf(p, "-"); | |
249 | trace_seq_putc(p, 0); | |
250 | ||
251 | return ret; | |
252 | } | |
253 | ||
254 | const char * | |
255 | scsi_trace_parse_cdb(struct trace_seq *p, unsigned char *cdb, int len) | |
256 | { | |
257 | switch (cdb[0]) { | |
258 | case READ_6: | |
259 | case WRITE_6: | |
260 | return scsi_trace_rw6(p, cdb, len); | |
261 | case READ_10: | |
c446c1f9 | 262 | case VERIFY: |
bf816235 | 263 | case WRITE_10: |
c446c1f9 | 264 | case WRITE_SAME: |
bf816235 KT |
265 | return scsi_trace_rw10(p, cdb, len); |
266 | case READ_12: | |
c446c1f9 | 267 | case VERIFY_12: |
bf816235 KT |
268 | case WRITE_12: |
269 | return scsi_trace_rw12(p, cdb, len); | |
270 | case READ_16: | |
c446c1f9 | 271 | case VERIFY_16: |
bf816235 | 272 | case WRITE_16: |
c446c1f9 | 273 | case WRITE_SAME_16: |
bf816235 | 274 | return scsi_trace_rw16(p, cdb, len); |
c446c1f9 MP |
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); | |
bf816235 KT |
279 | case VARIABLE_LENGTH_CMD: |
280 | return scsi_trace_varlen(p, cdb, len); | |
281 | default: | |
282 | return scsi_trace_misc(p, cdb, len); | |
283 | } | |
284 | } |