1#include <stdio.h>
2#include <string.h>
3#include <inttypes.h>
4#include "event-parse.h"
5
6typedef unsigned long sector_t;
7typedef uint64_t u64;
8typedef unsigned int u32;
9
10/*
11 *      SCSI opcodes
12 */
13#define TEST_UNIT_READY			0x00
14#define REZERO_UNIT			0x01
15#define REQUEST_SENSE			0x03
16#define FORMAT_UNIT			0x04
17#define READ_BLOCK_LIMITS		0x05
18#define REASSIGN_BLOCKS			0x07
19#define INITIALIZE_ELEMENT_STATUS	0x07
20#define READ_6				0x08
21#define WRITE_6				0x0a
22#define SEEK_6				0x0b
23#define READ_REVERSE			0x0f
24#define WRITE_FILEMARKS			0x10
25#define SPACE				0x11
26#define INQUIRY				0x12
27#define RECOVER_BUFFERED_DATA		0x14
28#define MODE_SELECT			0x15
29#define RESERVE				0x16
30#define RELEASE				0x17
31#define COPY				0x18
32#define ERASE				0x19
33#define MODE_SENSE			0x1a
34#define START_STOP			0x1b
35#define RECEIVE_DIAGNOSTIC		0x1c
36#define SEND_DIAGNOSTIC			0x1d
37#define ALLOW_MEDIUM_REMOVAL		0x1e
38
39#define READ_FORMAT_CAPACITIES		0x23
40#define SET_WINDOW			0x24
41#define READ_CAPACITY			0x25
42#define READ_10				0x28
43#define WRITE_10			0x2a
44#define SEEK_10				0x2b
45#define POSITION_TO_ELEMENT		0x2b
46#define WRITE_VERIFY			0x2e
47#define VERIFY				0x2f
48#define SEARCH_HIGH			0x30
49#define SEARCH_EQUAL			0x31
50#define SEARCH_LOW			0x32
51#define SET_LIMITS			0x33
52#define PRE_FETCH			0x34
53#define READ_POSITION			0x34
54#define SYNCHRONIZE_CACHE		0x35
55#define LOCK_UNLOCK_CACHE		0x36
56#define READ_DEFECT_DATA		0x37
57#define MEDIUM_SCAN			0x38
58#define COMPARE				0x39
59#define COPY_VERIFY			0x3a
60#define WRITE_BUFFER			0x3b
61#define READ_BUFFER			0x3c
62#define UPDATE_BLOCK			0x3d
63#define READ_LONG			0x3e
64#define WRITE_LONG			0x3f
65#define CHANGE_DEFINITION		0x40
66#define WRITE_SAME			0x41
67#define UNMAP				0x42
68#define READ_TOC			0x43
69#define READ_HEADER			0x44
70#define GET_EVENT_STATUS_NOTIFICATION	0x4a
71#define LOG_SELECT			0x4c
72#define LOG_SENSE			0x4d
73#define XDWRITEREAD_10			0x53
74#define MODE_SELECT_10			0x55
75#define RESERVE_10			0x56
76#define RELEASE_10			0x57
77#define MODE_SENSE_10			0x5a
78#define PERSISTENT_RESERVE_IN		0x5e
79#define PERSISTENT_RESERVE_OUT		0x5f
80#define VARIABLE_LENGTH_CMD		0x7f
81#define REPORT_LUNS			0xa0
82#define SECURITY_PROTOCOL_IN		0xa2
83#define MAINTENANCE_IN			0xa3
84#define MAINTENANCE_OUT			0xa4
85#define MOVE_MEDIUM			0xa5
86#define EXCHANGE_MEDIUM			0xa6
87#define READ_12				0xa8
88#define SERVICE_ACTION_OUT_12		0xa9
89#define WRITE_12			0xaa
90#define SERVICE_ACTION_IN_12		0xab
91#define WRITE_VERIFY_12			0xae
92#define VERIFY_12			0xaf
93#define SEARCH_HIGH_12			0xb0
94#define SEARCH_EQUAL_12			0xb1
95#define SEARCH_LOW_12			0xb2
96#define SECURITY_PROTOCOL_OUT		0xb5
97#define READ_ELEMENT_STATUS		0xb8
98#define SEND_VOLUME_TAG			0xb6
99#define WRITE_LONG_2			0xea
100#define EXTENDED_COPY			0x83
101#define RECEIVE_COPY_RESULTS		0x84
102#define ACCESS_CONTROL_IN		0x86
103#define ACCESS_CONTROL_OUT		0x87
104#define READ_16				0x88
105#define WRITE_16			0x8a
106#define READ_ATTRIBUTE			0x8c
107#define WRITE_ATTRIBUTE			0x8d
108#define VERIFY_16			0x8f
109#define SYNCHRONIZE_CACHE_16		0x91
110#define WRITE_SAME_16			0x93
111#define SERVICE_ACTION_BIDIRECTIONAL	0x9d
112#define SERVICE_ACTION_IN_16		0x9e
113#define SERVICE_ACTION_OUT_16		0x9f
114/* values for service action in */
115#define	SAI_READ_CAPACITY_16		0x10
116#define SAI_GET_LBA_STATUS		0x12
117/* values for VARIABLE_LENGTH_CMD service action codes
118 * see spc4r17 Section D.3.5, table D.7 and D.8 */
119#define VLC_SA_RECEIVE_CREDENTIAL	0x1800
120/* values for maintenance in */
121#define MI_REPORT_IDENTIFYING_INFORMATION		0x05
122#define MI_REPORT_TARGET_PGS				0x0a
123#define MI_REPORT_ALIASES				0x0b
124#define MI_REPORT_SUPPORTED_OPERATION_CODES		0x0c
125#define MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS	0x0d
126#define MI_REPORT_PRIORITY				0x0e
127#define MI_REPORT_TIMESTAMP				0x0f
128#define MI_MANAGEMENT_PROTOCOL_IN			0x10
129/* value for MI_REPORT_TARGET_PGS ext header */
130#define MI_EXT_HDR_PARAM_FMT		0x20
131/* values for maintenance out */
132#define MO_SET_IDENTIFYING_INFORMATION	0x06
133#define MO_SET_TARGET_PGS		0x0a
134#define MO_CHANGE_ALIASES		0x0b
135#define MO_SET_PRIORITY			0x0e
136#define MO_SET_TIMESTAMP		0x0f
137#define MO_MANAGEMENT_PROTOCOL_OUT	0x10
138/* values for variable length command */
139#define XDREAD_32			0x03
140#define XDWRITE_32			0x04
141#define XPWRITE_32			0x06
142#define XDWRITEREAD_32			0x07
143#define READ_32				0x09
144#define VERIFY_32			0x0a
145#define WRITE_32			0x0b
146#define WRITE_SAME_32			0x0d
147
148#define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f)
149#define SERVICE_ACTION32(cdb) ((cdb[8] << 8) | cdb[9])
150
151static const char *
152scsi_trace_misc(struct trace_seq *, unsigned char *, int);
153
154static const char *
155scsi_trace_rw6(struct trace_seq *p, unsigned char *cdb, int len)
156{
157	const char *ret = p->buffer + p->len;
158	sector_t lba = 0, txlen = 0;
159
160	lba |= ((cdb[1] & 0x1F) << 16);
161	lba |=  (cdb[2] << 8);
162	lba |=   cdb[3];
163	txlen = cdb[4];
164
165	trace_seq_printf(p, "lba=%llu txlen=%llu",
166			 (unsigned long long)lba, (unsigned long long)txlen);
167	trace_seq_putc(p, 0);
168	return ret;
169}
170
171static const char *
172scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len)
173{
174	const char *ret = p->buffer + p->len;
175	sector_t lba = 0, txlen = 0;
176
177	lba |= (cdb[2] << 24);
178	lba |= (cdb[3] << 16);
179	lba |= (cdb[4] << 8);
180	lba |=  cdb[5];
181	txlen |= (cdb[7] << 8);
182	txlen |=  cdb[8];
183
184	trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
185			 (unsigned long long)lba, (unsigned long long)txlen,
186			 cdb[1] >> 5);
187
188	if (cdb[0] == WRITE_SAME)
189		trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1);
190
191	trace_seq_putc(p, 0);
192	return ret;
193}
194
195static const char *
196scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len)
197{
198	const char *ret = p->buffer + p->len;
199	sector_t lba = 0, txlen = 0;
200
201	lba |= (cdb[2] << 24);
202	lba |= (cdb[3] << 16);
203	lba |= (cdb[4] << 8);
204	lba |=  cdb[5];
205	txlen |= (cdb[6] << 24);
206	txlen |= (cdb[7] << 16);
207	txlen |= (cdb[8] << 8);
208	txlen |=  cdb[9];
209
210	trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
211			 (unsigned long long)lba, (unsigned long long)txlen,
212			 cdb[1] >> 5);
213	trace_seq_putc(p, 0);
214	return ret;
215}
216
217static const char *
218scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len)
219{
220	const char *ret = p->buffer + p->len;
221	sector_t lba = 0, txlen = 0;
222
223	lba |= ((u64)cdb[2] << 56);
224	lba |= ((u64)cdb[3] << 48);
225	lba |= ((u64)cdb[4] << 40);
226	lba |= ((u64)cdb[5] << 32);
227	lba |= (cdb[6] << 24);
228	lba |= (cdb[7] << 16);
229	lba |= (cdb[8] << 8);
230	lba |=  cdb[9];
231	txlen |= (cdb[10] << 24);
232	txlen |= (cdb[11] << 16);
233	txlen |= (cdb[12] << 8);
234	txlen |=  cdb[13];
235
236	trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
237			 (unsigned long long)lba, (unsigned long long)txlen,
238			 cdb[1] >> 5);
239
240	if (cdb[0] == WRITE_SAME_16)
241		trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1);
242
243	trace_seq_putc(p, 0);
244	return ret;
245}
246
247static const char *
248scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len)
249{
250	const char *ret = p->buffer + p->len, *cmd;
251	sector_t lba = 0, txlen = 0;
252	u32 ei_lbrt = 0;
253
254	switch (SERVICE_ACTION32(cdb)) {
255	case READ_32:
256		cmd = "READ";
257		break;
258	case VERIFY_32:
259		cmd = "VERIFY";
260		break;
261	case WRITE_32:
262		cmd = "WRITE";
263		break;
264	case WRITE_SAME_32:
265		cmd = "WRITE_SAME";
266		break;
267	default:
268		trace_seq_printf(p, "UNKNOWN");
269		goto out;
270	}
271
272	lba |= ((u64)cdb[12] << 56);
273	lba |= ((u64)cdb[13] << 48);
274	lba |= ((u64)cdb[14] << 40);
275	lba |= ((u64)cdb[15] << 32);
276	lba |= (cdb[16] << 24);
277	lba |= (cdb[17] << 16);
278	lba |= (cdb[18] << 8);
279	lba |=  cdb[19];
280	ei_lbrt |= (cdb[20] << 24);
281	ei_lbrt |= (cdb[21] << 16);
282	ei_lbrt |= (cdb[22] << 8);
283	ei_lbrt |=  cdb[23];
284	txlen |= (cdb[28] << 24);
285	txlen |= (cdb[29] << 16);
286	txlen |= (cdb[30] << 8);
287	txlen |=  cdb[31];
288
289	trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu protect=%u ei_lbrt=%u",
290			 cmd, (unsigned long long)lba,
291			 (unsigned long long)txlen, cdb[10] >> 5, ei_lbrt);
292
293	if (SERVICE_ACTION32(cdb) == WRITE_SAME_32)
294		trace_seq_printf(p, " unmap=%u", cdb[10] >> 3 & 1);
295
296out:
297	trace_seq_putc(p, 0);
298	return ret;
299}
300
301static const char *
302scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len)
303{
304	const char *ret = p->buffer + p->len;
305	unsigned int regions = cdb[7] << 8 | cdb[8];
306
307	trace_seq_printf(p, "regions=%u", (regions - 8) / 16);
308	trace_seq_putc(p, 0);
309	return ret;
310}
311
312static const char *
313scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len)
314{
315	const char *ret = p->buffer + p->len, *cmd;
316	sector_t lba = 0;
317	u32 alloc_len = 0;
318
319	switch (SERVICE_ACTION16(cdb)) {
320	case SAI_READ_CAPACITY_16:
321		cmd = "READ_CAPACITY_16";
322		break;
323	case SAI_GET_LBA_STATUS:
324		cmd = "GET_LBA_STATUS";
325		break;
326	default:
327		trace_seq_printf(p, "UNKNOWN");
328		goto out;
329	}
330
331	lba |= ((u64)cdb[2] << 56);
332	lba |= ((u64)cdb[3] << 48);
333	lba |= ((u64)cdb[4] << 40);
334	lba |= ((u64)cdb[5] << 32);
335	lba |= (cdb[6] << 24);
336	lba |= (cdb[7] << 16);
337	lba |= (cdb[8] << 8);
338	lba |=  cdb[9];
339	alloc_len |= (cdb[10] << 24);
340	alloc_len |= (cdb[11] << 16);
341	alloc_len |= (cdb[12] << 8);
342	alloc_len |=  cdb[13];
343
344	trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd,
345			 (unsigned long long)lba, alloc_len);
346
347out:
348	trace_seq_putc(p, 0);
349	return ret;
350}
351
352static const char *
353scsi_trace_varlen(struct trace_seq *p, unsigned char *cdb, int len)
354{
355	switch (SERVICE_ACTION32(cdb)) {
356	case READ_32:
357	case VERIFY_32:
358	case WRITE_32:
359	case WRITE_SAME_32:
360		return scsi_trace_rw32(p, cdb, len);
361	default:
362		return scsi_trace_misc(p, cdb, len);
363	}
364}
365
366static const char *
367scsi_trace_misc(struct trace_seq *p, unsigned char *cdb, int len)
368{
369	const char *ret = p->buffer + p->len;
370
371	trace_seq_printf(p, "-");
372	trace_seq_putc(p, 0);
373	return ret;
374}
375
376const char *
377scsi_trace_parse_cdb(struct trace_seq *p, unsigned char *cdb, int len)
378{
379	switch (cdb[0]) {
380	case READ_6:
381	case WRITE_6:
382		return scsi_trace_rw6(p, cdb, len);
383	case READ_10:
384	case VERIFY:
385	case WRITE_10:
386	case WRITE_SAME:
387		return scsi_trace_rw10(p, cdb, len);
388	case READ_12:
389	case VERIFY_12:
390	case WRITE_12:
391		return scsi_trace_rw12(p, cdb, len);
392	case READ_16:
393	case VERIFY_16:
394	case WRITE_16:
395	case WRITE_SAME_16:
396		return scsi_trace_rw16(p, cdb, len);
397	case UNMAP:
398		return scsi_trace_unmap(p, cdb, len);
399	case SERVICE_ACTION_IN_16:
400		return scsi_trace_service_action_in(p, cdb, len);
401	case VARIABLE_LENGTH_CMD:
402		return scsi_trace_varlen(p, cdb, len);
403	default:
404		return scsi_trace_misc(p, cdb, len);
405	}
406}
407
408unsigned long long process_scsi_trace_parse_cdb(struct trace_seq *s,
409						unsigned long long *args)
410{
411	scsi_trace_parse_cdb(s, (unsigned char *) (unsigned long) args[1], args[2]);
412	return 0;
413}
414
415int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
416{
417	pevent_register_print_function(pevent,
418				       process_scsi_trace_parse_cdb,
419				       PEVENT_FUNC_ARG_STRING,
420				       "scsi_trace_parse_cdb",
421				       PEVENT_FUNC_ARG_PTR,
422				       PEVENT_FUNC_ARG_PTR,
423				       PEVENT_FUNC_ARG_INT,
424				       PEVENT_FUNC_ARG_VOID);
425	return 0;
426}
427
428void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
429{
430	pevent_unregister_print_function(pevent, process_scsi_trace_parse_cdb,
431					 "scsi_trace_parse_cdb");
432}
433