1// SPDX-License-Identifier: GPL-2.0
2/*
3 * NVM Express device driver tracepoints
4 * Copyright (c) 2018 Johannes Thumshirn, SUSE Linux GmbH
5 */
6
7#include <asm/unaligned.h>
8#include "trace.h"
9
10static const char *nvme_trace_delete_sq(struct trace_seq *p, u8 *cdw10)
11{
12	const char *ret = trace_seq_buffer_ptr(p);
13	u16 sqid = get_unaligned_le16(cdw10);
14
15	trace_seq_printf(p, "sqid=%u", sqid);
16	trace_seq_putc(p, 0);
17
18	return ret;
19}
20
21static const char *nvme_trace_create_sq(struct trace_seq *p, u8 *cdw10)
22{
23	const char *ret = trace_seq_buffer_ptr(p);
24	u16 sqid = get_unaligned_le16(cdw10);
25	u16 qsize = get_unaligned_le16(cdw10 + 2);
26	u16 sq_flags = get_unaligned_le16(cdw10 + 4);
27	u16 cqid = get_unaligned_le16(cdw10 + 6);
28
29
30	trace_seq_printf(p, "sqid=%u, qsize=%u, sq_flags=0x%x, cqid=%u",
31			 sqid, qsize, sq_flags, cqid);
32	trace_seq_putc(p, 0);
33
34	return ret;
35}
36
37static const char *nvme_trace_delete_cq(struct trace_seq *p, u8 *cdw10)
38{
39	const char *ret = trace_seq_buffer_ptr(p);
40	u16 cqid = get_unaligned_le16(cdw10);
41
42	trace_seq_printf(p, "cqid=%u", cqid);
43	trace_seq_putc(p, 0);
44
45	return ret;
46}
47
48static const char *nvme_trace_create_cq(struct trace_seq *p, u8 *cdw10)
49{
50	const char *ret = trace_seq_buffer_ptr(p);
51	u16 cqid = get_unaligned_le16(cdw10);
52	u16 qsize = get_unaligned_le16(cdw10 + 2);
53	u16 cq_flags = get_unaligned_le16(cdw10 + 4);
54	u16 irq_vector = get_unaligned_le16(cdw10 + 6);
55
56	trace_seq_printf(p, "cqid=%u, qsize=%u, cq_flags=0x%x, irq_vector=%u",
57			 cqid, qsize, cq_flags, irq_vector);
58	trace_seq_putc(p, 0);
59
60	return ret;
61}
62
63static const char *nvme_trace_admin_identify(struct trace_seq *p, u8 *cdw10)
64{
65	const char *ret = trace_seq_buffer_ptr(p);
66	u8 cns = cdw10[0];
67	u16 ctrlid = get_unaligned_le16(cdw10 + 2);
68
69	trace_seq_printf(p, "cns=%u, ctrlid=%u", cns, ctrlid);
70	trace_seq_putc(p, 0);
71
72	return ret;
73}
74
75static const char *nvme_trace_admin_set_features(struct trace_seq *p,
76						 u8 *cdw10)
77{
78	const char *ret = trace_seq_buffer_ptr(p);
79	u8 fid = cdw10[0];
80	u8 sv = cdw10[3] & 0x8;
81	u32 cdw11 = get_unaligned_le32(cdw10 + 4);
82
83	trace_seq_printf(p, "fid=0x%x, sv=0x%x, cdw11=0x%x", fid, sv, cdw11);
84	trace_seq_putc(p, 0);
85
86	return ret;
87}
88
89static const char *nvme_trace_admin_get_features(struct trace_seq *p,
90						 u8 *cdw10)
91{
92	const char *ret = trace_seq_buffer_ptr(p);
93	u8 fid = cdw10[0];
94	u8 sel = cdw10[1] & 0x7;
95	u32 cdw11 = get_unaligned_le32(cdw10 + 4);
96
97	trace_seq_printf(p, "fid=0x%x, sel=0x%x, cdw11=0x%x", fid, sel, cdw11);
98	trace_seq_putc(p, 0);
99
100	return ret;
101}
102
103static const char *nvme_trace_get_lba_status(struct trace_seq *p,
104					     u8 *cdw10)
105{
106	const char *ret = trace_seq_buffer_ptr(p);
107	u64 slba = get_unaligned_le64(cdw10);
108	u32 mndw = get_unaligned_le32(cdw10 + 8);
109	u16 rl = get_unaligned_le16(cdw10 + 12);
110	u8 atype = cdw10[15];
111
112	trace_seq_printf(p, "slba=0x%llx, mndw=0x%x, rl=0x%x, atype=%u",
113			slba, mndw, rl, atype);
114	trace_seq_putc(p, 0);
115
116	return ret;
117}
118
119static const char *nvme_trace_admin_format_nvm(struct trace_seq *p, u8 *cdw10)
120{
121	const char *ret = trace_seq_buffer_ptr(p);
122	/*
123	 * lbafu(bit 13:12) is already in the upper 4 bits, lbafl: bit 03:00.
124	 */
125	u8 lbaf = (cdw10[1] & 0x30) | (cdw10[0] & 0xF);
126	u8 mset = (cdw10[0] >> 4) & 0x1;
127	u8 pi = (cdw10[0] >> 5) & 0x7;
128	u8 pil = cdw10[1] & 0x1;
129	u8 ses = (cdw10[1] >> 1) & 0x7;
130
131	trace_seq_printf(p, "lbaf=%u, mset=%u, pi=%u, pil=%u, ses=%u",
132			lbaf, mset, pi, pil, ses);
133
134	trace_seq_putc(p, 0);
135
136	return ret;
137}
138
139static const char *nvme_trace_read_write(struct trace_seq *p, u8 *cdw10)
140{
141	const char *ret = trace_seq_buffer_ptr(p);
142	u64 slba = get_unaligned_le64(cdw10);
143	u16 length = get_unaligned_le16(cdw10 + 8);
144	u16 control = get_unaligned_le16(cdw10 + 10);
145	u32 dsmgmt = get_unaligned_le32(cdw10 + 12);
146	u32 reftag = get_unaligned_le32(cdw10 +  16);
147
148	trace_seq_printf(p,
149			 "slba=%llu, len=%u, ctrl=0x%x, dsmgmt=%u, reftag=%u",
150			 slba, length, control, dsmgmt, reftag);
151	trace_seq_putc(p, 0);
152
153	return ret;
154}
155
156static const char *nvme_trace_dsm(struct trace_seq *p, u8 *cdw10)
157{
158	const char *ret = trace_seq_buffer_ptr(p);
159
160	trace_seq_printf(p, "nr=%u, attributes=%u",
161			 get_unaligned_le32(cdw10),
162			 get_unaligned_le32(cdw10 + 4));
163	trace_seq_putc(p, 0);
164
165	return ret;
166}
167
168static const char *nvme_trace_zone_mgmt_send(struct trace_seq *p, u8 *cdw10)
169{
170	static const char * const zsa_strs[] = {
171		[0x01] = "close zone",
172		[0x02] = "finish zone",
173		[0x03] = "open zone",
174		[0x04] = "reset zone",
175		[0x05] = "offline zone",
176		[0x10] = "set zone descriptor extension"
177	};
178	const char *ret = trace_seq_buffer_ptr(p);
179	u64 slba = get_unaligned_le64(cdw10);
180	const char *zsa_str;
181	u8 zsa = cdw10[12];
182	u8 all = cdw10[13];
183
184	if (zsa < ARRAY_SIZE(zsa_strs) && zsa_strs[zsa])
185		zsa_str = zsa_strs[zsa];
186	else
187		zsa_str = "reserved";
188
189	trace_seq_printf(p, "slba=%llu, zsa=%u:%s, all=%u",
190		slba, zsa, zsa_str, all);
191	trace_seq_putc(p, 0);
192
193	return ret;
194}
195
196static const char *nvme_trace_zone_mgmt_recv(struct trace_seq *p, u8 *cdw10)
197{
198	static const char * const zrasf_strs[] = {
199		[0x00] = "list all zones",
200		[0x01] = "list the zones in the ZSE: Empty state",
201		[0x02] = "list the zones in the ZSIO: Implicitly Opened state",
202		[0x03] = "list the zones in the ZSEO: Explicitly Opened state",
203		[0x04] = "list the zones in the ZSC: Closed state",
204		[0x05] = "list the zones in the ZSF: Full state",
205		[0x06] = "list the zones in the ZSRO: Read Only state",
206		[0x07] = "list the zones in the ZSO: Offline state",
207		[0x09] = "list the zones that have the zone attribute"
208	};
209	const char *ret = trace_seq_buffer_ptr(p);
210	u64 slba = get_unaligned_le64(cdw10);
211	u32 numd = get_unaligned_le32(cdw10 + 8);
212	u8 zra = cdw10[12];
213	u8 zrasf = cdw10[13];
214	const char *zrasf_str;
215	u8 pr = cdw10[14];
216
217	if (zrasf < ARRAY_SIZE(zrasf_strs) && zrasf_strs[zrasf])
218		zrasf_str = zrasf_strs[zrasf];
219	else
220		zrasf_str = "reserved";
221
222	trace_seq_printf(p, "slba=%llu, numd=%u, zra=%u, zrasf=%u:%s, pr=%u",
223		slba, numd, zra, zrasf, zrasf_str, pr);
224	trace_seq_putc(p, 0);
225
226	return ret;
227}
228
229static const char *nvme_trace_resv_reg(struct trace_seq *p, u8 *cdw10)
230{
231	const char *ret = trace_seq_buffer_ptr(p);
232	u8 rrega = cdw10[0] & 0x7;
233	u8 iekey = (cdw10[0] >> 3) & 0x1;
234	u8 ptpl = (cdw10[3] >> 6) & 0x3;
235
236	trace_seq_printf(p, "rrega=%u, iekey=%u, ptpl=%u",
237			 rrega, iekey, ptpl);
238	trace_seq_putc(p, 0);
239
240	return ret;
241}
242
243static const char *nvme_trace_resv_acq(struct trace_seq *p, u8 *cdw10)
244{
245	const char *ret = trace_seq_buffer_ptr(p);
246	u8 racqa = cdw10[0] & 0x7;
247	u8 iekey = (cdw10[0] >> 3) & 0x1;
248	u8 rtype = cdw10[1];
249
250	trace_seq_printf(p, "racqa=%u, iekey=%u, rtype=%u",
251			 racqa, iekey, rtype);
252	trace_seq_putc(p, 0);
253
254	return ret;
255}
256
257static const char *nvme_trace_resv_rel(struct trace_seq *p, u8 *cdw10)
258{
259	const char *ret = trace_seq_buffer_ptr(p);
260	u8 rrela = cdw10[0] & 0x7;
261	u8 iekey = (cdw10[0] >> 3) & 0x1;
262	u8 rtype = cdw10[1];
263
264	trace_seq_printf(p, "rrela=%u, iekey=%u, rtype=%u",
265			 rrela, iekey, rtype);
266	trace_seq_putc(p, 0);
267
268	return ret;
269}
270
271static const char *nvme_trace_resv_report(struct trace_seq *p, u8 *cdw10)
272{
273	const char *ret = trace_seq_buffer_ptr(p);
274	u32 numd = get_unaligned_le32(cdw10);
275	u8 eds = cdw10[4] & 0x1;
276
277	trace_seq_printf(p, "numd=%u, eds=%u", numd, eds);
278	trace_seq_putc(p, 0);
279
280	return ret;
281}
282
283static const char *nvme_trace_common(struct trace_seq *p, u8 *cdw10)
284{
285	const char *ret = trace_seq_buffer_ptr(p);
286
287	trace_seq_printf(p, "cdw10=%*ph", 24, cdw10);
288	trace_seq_putc(p, 0);
289
290	return ret;
291}
292
293const char *nvme_trace_parse_admin_cmd(struct trace_seq *p,
294				       u8 opcode, u8 *cdw10)
295{
296	switch (opcode) {
297	case nvme_admin_delete_sq:
298		return nvme_trace_delete_sq(p, cdw10);
299	case nvme_admin_create_sq:
300		return nvme_trace_create_sq(p, cdw10);
301	case nvme_admin_delete_cq:
302		return nvme_trace_delete_cq(p, cdw10);
303	case nvme_admin_create_cq:
304		return nvme_trace_create_cq(p, cdw10);
305	case nvme_admin_identify:
306		return nvme_trace_admin_identify(p, cdw10);
307	case nvme_admin_set_features:
308		return nvme_trace_admin_set_features(p, cdw10);
309	case nvme_admin_get_features:
310		return nvme_trace_admin_get_features(p, cdw10);
311	case nvme_admin_get_lba_status:
312		return nvme_trace_get_lba_status(p, cdw10);
313	case nvme_admin_format_nvm:
314		return nvme_trace_admin_format_nvm(p, cdw10);
315	default:
316		return nvme_trace_common(p, cdw10);
317	}
318}
319
320const char *nvme_trace_parse_nvm_cmd(struct trace_seq *p,
321				     u8 opcode, u8 *cdw10)
322{
323	switch (opcode) {
324	case nvme_cmd_read:
325	case nvme_cmd_write:
326	case nvme_cmd_write_zeroes:
327	case nvme_cmd_zone_append:
328		return nvme_trace_read_write(p, cdw10);
329	case nvme_cmd_dsm:
330		return nvme_trace_dsm(p, cdw10);
331	case nvme_cmd_zone_mgmt_send:
332		return nvme_trace_zone_mgmt_send(p, cdw10);
333	case nvme_cmd_zone_mgmt_recv:
334		return nvme_trace_zone_mgmt_recv(p, cdw10);
335	case nvme_cmd_resv_register:
336		return nvme_trace_resv_reg(p, cdw10);
337	case nvme_cmd_resv_acquire:
338		return nvme_trace_resv_acq(p, cdw10);
339	case nvme_cmd_resv_release:
340		return nvme_trace_resv_rel(p, cdw10);
341	case nvme_cmd_resv_report:
342		return nvme_trace_resv_report(p, cdw10);
343	default:
344		return nvme_trace_common(p, cdw10);
345	}
346}
347
348static const char *nvme_trace_fabrics_property_set(struct trace_seq *p, u8 *spc)
349{
350	const char *ret = trace_seq_buffer_ptr(p);
351	u8 attrib = spc[0];
352	u32 ofst = get_unaligned_le32(spc + 4);
353	u64 value = get_unaligned_le64(spc + 8);
354
355	trace_seq_printf(p, "attrib=%u, ofst=0x%x, value=0x%llx",
356			 attrib, ofst, value);
357	trace_seq_putc(p, 0);
358	return ret;
359}
360
361static const char *nvme_trace_fabrics_connect(struct trace_seq *p, u8 *spc)
362{
363	const char *ret = trace_seq_buffer_ptr(p);
364	u16 recfmt = get_unaligned_le16(spc);
365	u16 qid = get_unaligned_le16(spc + 2);
366	u16 sqsize = get_unaligned_le16(spc + 4);
367	u8 cattr = spc[6];
368	u32 kato = get_unaligned_le32(spc + 8);
369
370	trace_seq_printf(p, "recfmt=%u, qid=%u, sqsize=%u, cattr=%u, kato=%u",
371			 recfmt, qid, sqsize, cattr, kato);
372	trace_seq_putc(p, 0);
373	return ret;
374}
375
376static const char *nvme_trace_fabrics_property_get(struct trace_seq *p, u8 *spc)
377{
378	const char *ret = trace_seq_buffer_ptr(p);
379	u8 attrib = spc[0];
380	u32 ofst = get_unaligned_le32(spc + 4);
381
382	trace_seq_printf(p, "attrib=%u, ofst=0x%x", attrib, ofst);
383	trace_seq_putc(p, 0);
384	return ret;
385}
386
387static const char *nvme_trace_fabrics_auth_send(struct trace_seq *p, u8 *spc)
388{
389	const char *ret = trace_seq_buffer_ptr(p);
390	u8 spsp0 = spc[1];
391	u8 spsp1 = spc[2];
392	u8 secp = spc[3];
393	u32 tl = get_unaligned_le32(spc + 4);
394
395	trace_seq_printf(p, "spsp0=%02x, spsp1=%02x, secp=%02x, tl=%u",
396			 spsp0, spsp1, secp, tl);
397	trace_seq_putc(p, 0);
398	return ret;
399}
400
401static const char *nvme_trace_fabrics_auth_receive(struct trace_seq *p, u8 *spc)
402{
403	const char *ret = trace_seq_buffer_ptr(p);
404	u8 spsp0 = spc[1];
405	u8 spsp1 = spc[2];
406	u8 secp = spc[3];
407	u32 al = get_unaligned_le32(spc + 4);
408
409	trace_seq_printf(p, "spsp0=%02x, spsp1=%02x, secp=%02x, al=%u",
410			 spsp0, spsp1, secp, al);
411	trace_seq_putc(p, 0);
412	return ret;
413}
414
415static const char *nvme_trace_fabrics_common(struct trace_seq *p, u8 *spc)
416{
417	const char *ret = trace_seq_buffer_ptr(p);
418
419	trace_seq_printf(p, "specific=%*ph", 24, spc);
420	trace_seq_putc(p, 0);
421	return ret;
422}
423
424const char *nvme_trace_parse_fabrics_cmd(struct trace_seq *p,
425		u8 fctype, u8 *spc)
426{
427	switch (fctype) {
428	case nvme_fabrics_type_property_set:
429		return nvme_trace_fabrics_property_set(p, spc);
430	case nvme_fabrics_type_connect:
431		return nvme_trace_fabrics_connect(p, spc);
432	case nvme_fabrics_type_property_get:
433		return nvme_trace_fabrics_property_get(p, spc);
434	case nvme_fabrics_type_auth_send:
435		return nvme_trace_fabrics_auth_send(p, spc);
436	case nvme_fabrics_type_auth_receive:
437		return nvme_trace_fabrics_auth_receive(p, spc);
438	default:
439		return nvme_trace_fabrics_common(p, spc);
440	}
441}
442
443const char *nvme_trace_disk_name(struct trace_seq *p, char *name)
444{
445	const char *ret = trace_seq_buffer_ptr(p);
446
447	if (*name)
448		trace_seq_printf(p, "disk=%s, ", name);
449	trace_seq_putc(p, 0);
450
451	return ret;
452}
453
454EXPORT_TRACEPOINT_SYMBOL_GPL(nvme_sq);
455