Coverage Report

Created: 2026-09-28 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-nvme-mi-mi.c
Line
Count
Source
1
/* packet-nvme-mi-mi.c
2
 * NVMe-MI MI Command dissector (NMIMT=1, NVMe-MI 2.1 §5)
3
 * Copyright 2026, Brandon Chiu
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 1998 Gerald Combs
8
 *
9
 * SPDX-License-Identifier: GPL-2.0-or-later
10
 */
11
12
/* Reference: NVM Express Management Interface specification
13
 * https://nvmexpress.org/specification/nvme-mi-specification/
14
 *
15
 * Decodes the Management Interface Command Set request dwords (NMD0/NMD1),
16
 * the command-specific NVMe Management Response field, and the Response Data
17
 * structures for opcodes 00h-04h.  Opcodes 05h-0Ch are named but their
18
 * bodies are rendered as raw dwords/data until fixtures exist for them.
19
 */
20
21
#include <config.h>
22
23
#include <epan/expert.h>
24
#include <epan/packet.h>
25
#include <epan/tfs.h>
26
#include <wsutil/array.h>
27
#include <wsutil/utf8_entities.h>
28
#include "packet-nvme.h"
29
#include "packet-nvme-mi.h"
30
31
void proto_register_nvme_mi_mi(void);
32
void proto_reg_handoff_nvme_mi_mi(void);
33
34
static int proto_nvme_mi_mi;
35
36
static dissector_handle_t nvme_mi_mi_handle;
37
38
static int hf_nvme_mi_mi_opcode;
39
static int hf_nvme_mi_mi_cdw0;
40
static int hf_nvme_mi_mi_cdw1;
41
static int hf_nvme_mi_mi_status;
42
static int hf_nvme_mi_mi_nmresp;
43
static int hf_nvme_mi_mi_data;
44
45
/* Read NVMe-MI Data Structure (00h) */
46
static int hf_nvme_mi_mi_rds_dtyp;
47
static int hf_nvme_mi_mi_rds_portid;
48
static int hf_nvme_mi_mi_rds_ctrlid;
49
static int hf_nvme_mi_mi_rds_iocsi;
50
static int hf_nvme_mi_mi_rds_rdl;
51
52
/* NVM Subsystem Health Status Poll (01h) */
53
static int hf_nvme_mi_mi_nshsp_cs;
54
55
/* Controller Health Status Poll (02h) */
56
static int hf_nvme_mi_mi_chsp_all;
57
static int hf_nvme_mi_mi_chsp_incvf;
58
static int hf_nvme_mi_mi_chsp_incpf;
59
static int hf_nvme_mi_mi_chsp_incf;
60
static int hf_nvme_mi_mi_chsp_maxrent;
61
static int hf_nvme_mi_mi_chsp_sctlid;
62
static int hf_nvme_mi_mi_chsp_ccf;
63
static int hf_nvme_mi_mi_chsp_cwarn;
64
static int hf_nvme_mi_mi_chsp_spare;
65
static int hf_nvme_mi_mi_chsp_pdlu;
66
static int hf_nvme_mi_mi_chsp_ctemp;
67
static int hf_nvme_mi_mi_chsp_csts;
68
static int hf_nvme_mi_mi_chsp_rent;
69
70
/* Configuration Set (03h) / Configuration Get (04h) */
71
static int hf_nvme_mi_mi_cfg_cid;
72
static int hf_nvme_mi_mi_cfg_portid;
73
static int hf_nvme_mi_mi_cfg_sfreq;
74
static int hf_nvme_mi_mi_cfg_mtus;
75
static int hf_nvme_mi_mi_cfg_sfreq_cur;
76
static int hf_nvme_mi_mi_cfg_mtus_cur;
77
static int hf_nvme_mi_mi_cfg_aeelver;
78
/* Health Status Change clear-selection bits (Configuration Set, NMD1) */
79
static int hf_nvme_mi_mi_cfg_hsc_tcida;
80
static int hf_nvme_mi_mi_cfg_hsc_cwarn;
81
static int hf_nvme_mi_mi_cfg_hsc_spare;
82
static int hf_nvme_mi_mi_cfg_hsc_pdlu;
83
static int hf_nvme_mi_mi_cfg_hsc_ctemp;
84
static int hf_nvme_mi_mi_cfg_hsc_cschng;
85
static int hf_nvme_mi_mi_cfg_hsc_fa;
86
static int hf_nvme_mi_mi_cfg_hsc_nac;
87
static int hf_nvme_mi_mi_cfg_hsc_ceco;
88
static int hf_nvme_mi_mi_cfg_hsc_nssro;
89
static int hf_nvme_mi_mi_cfg_hsc_shst;
90
static int hf_nvme_mi_mi_cfg_hsc_cfs;
91
static int hf_nvme_mi_mi_cfg_hsc_rdy;
92
93
/* VPD Read (05h) / VPD Write (06h) — shared layout */
94
static int hf_nvme_mi_mi_vpd_dofst;
95
static int hf_nvme_mi_mi_vpd_dlen;
96
static int hf_nvme_mi_mi_vpd_data;
97
98
/* Configuration Set (03h) Asynchronous Event — request dword 0
99
 * and the AE Enable List request data */
100
static int hf_nvme_mi_mi_cfg_ae_envfa;
101
static int hf_nvme_mi_mi_cfg_ae_enpfa;
102
static int hf_nvme_mi_mi_cfg_ae_encfa;
103
static int hf_nvme_mi_mi_cfg_ae_aemd;
104
static int hf_nvme_mi_mi_cfg_ae_aerd;
105
static int hf_nvme_mi_mi_ae;
106
static int hf_nvme_mi_mi_ae_numaee;
107
static int hf_nvme_mi_mi_ae_aeelver;
108
static int hf_nvme_mi_mi_ae_aeetl;
109
static int hf_nvme_mi_mi_ae_aeelhl;
110
static int hf_nvme_mi_mi_ae_entry;
111
static int hf_nvme_mi_mi_ae_aeel;
112
static int hf_nvme_mi_mi_ae_aee;
113
static int hf_nvme_mi_mi_ae_id;
114
115
/* Configuration Get (04h) Asynchronous Event — AE Supported List response
116
 * data; same shape as the AE Enable List, different names. */
117
static int hf_nvme_mi_mi_aes;
118
static int hf_nvme_mi_mi_aes_numaes;
119
static int hf_nvme_mi_mi_aes_aeslver;
120
static int hf_nvme_mi_mi_aes_aestl;
121
static int hf_nvme_mi_mi_aes_aeslhl;
122
static int hf_nvme_mi_mi_aes_entry;
123
static int hf_nvme_mi_mi_aes_aesl;
124
static int hf_nvme_mi_mi_aes_aese;
125
static int hf_nvme_mi_mi_aes_id;
126
127
/* Reset (07h) */
128
static int hf_nvme_mi_mi_reset_rsttyp;
129
130
/* Shutdown (0Ch) */
131
static int hf_nvme_mi_mi_shutdown_shdntyp;
132
133
/* NVM Subsystem Information data structure (DTYP 00h) */
134
static int hf_nvme_mi_mi_subsys_nump;
135
static int hf_nvme_mi_mi_subsys_mjr;
136
static int hf_nvme_mi_mi_subsys_mnr;
137
static int hf_nvme_mi_mi_subsys_nnsc;
138
static int hf_nvme_mi_mi_subsys_sre;
139
140
/* Port Information data structure (DTYP 01h) */
141
static int hf_nvme_mi_mi_port_prttyp;
142
static int hf_nvme_mi_mi_port_prtcap;
143
static int hf_nvme_mi_mi_port_aems;
144
static int hf_nvme_mi_mi_port_ciaps;
145
static int hf_nvme_mi_mi_port_mmtus;
146
static int hf_nvme_mi_mi_port_mebs;
147
static int hf_nvme_mi_mi_port_pcie_mps;
148
static int hf_nvme_mi_mi_port_pcie_slsv;
149
static int hf_nvme_mi_mi_port_pcie_cls;
150
static int hf_nvme_mi_mi_port_pcie_mlw;
151
static int hf_nvme_mi_mi_port_pcie_nlw;
152
static int hf_nvme_mi_mi_port_pcie_pn;
153
static int hf_nvme_mi_mi_port_twire_cvpdaddr;
154
static int hf_nvme_mi_mi_port_twire_mvpdfreq;
155
static int hf_nvme_mi_mi_port_twire_cmeaddr;
156
static int hf_nvme_mi_mi_port_twire_twprt;
157
static int hf_nvme_mi_mi_port_twire_i3csprt;
158
static int hf_nvme_mi_mi_port_twire_msmbfreq;
159
static int hf_nvme_mi_mi_port_twire_nvmebm;
160
static int hf_nvme_mi_mi_port_twire_nvmebms;
161
162
/* Controller List data structure (DTYP 02h, NVMe Base) */
163
static int hf_nvme_mi_mi_ctrllist_numids;
164
static int hf_nvme_mi_mi_ctrllist_ctrlid;
165
166
/* Controller Information data structure (DTYP 03h) */
167
static int hf_nvme_mi_mi_ctrlinfo_portid;
168
static int hf_nvme_mi_mi_ctrlinfo_prii;
169
static int hf_nvme_mi_mi_ctrlinfo_riv;
170
static int hf_nvme_mi_mi_ctrlinfo_pri;
171
static int hf_nvme_mi_mi_ctrlinfo_pri_bus;
172
static int hf_nvme_mi_mi_ctrlinfo_pri_dev;
173
static int hf_nvme_mi_mi_ctrlinfo_pri_fn;
174
static int hf_nvme_mi_mi_ctrlinfo_pcivid;
175
static int hf_nvme_mi_mi_ctrlinfo_pcidid;
176
static int hf_nvme_mi_mi_ctrlinfo_pcisvid;
177
static int hf_nvme_mi_mi_ctrlinfo_pcisdid;
178
static int hf_nvme_mi_mi_ctrlinfo_pciesn;
179
180
/* Optionally Supported / MEB Supported Command List (DTYP 04h/05h) */
181
static int hf_nvme_mi_mi_cmdlist_numcmd;
182
static int hf_nvme_mi_mi_cmdlist_ctyp;
183
static int hf_nvme_mi_mi_cmdlist_nmimt;
184
static int hf_nvme_mi_mi_cmdlist_opc;
185
186
/* NVM Subsystem Health Data Structure (NSHDS) */
187
static int hf_nvme_mi_mi_nshds_nss;
188
static int hf_nvme_mi_mi_nshds_nss_atf;
189
static int hf_nvme_mi_mi_nshds_nss_sfm;
190
static int hf_nvme_mi_mi_nshds_nss_df;
191
static int hf_nvme_mi_mi_nshds_nss_rnr;
192
static int hf_nvme_mi_mi_nshds_nss_p0la;
193
static int hf_nvme_mi_mi_nshds_nss_p1la;
194
static int hf_nvme_mi_mi_nshds_nss_snfm;
195
static int hf_nvme_mi_mi_nshds_sw;
196
static int hf_nvme_mi_mi_nshds_sw_ips;
197
static int hf_nvme_mi_mi_nshds_sw_pmre;
198
static int hf_nvme_mi_mi_nshds_sw_vmbf;
199
static int hf_nvme_mi_mi_nshds_sw_ro;
200
static int hf_nvme_mi_mi_nshds_sw_rd;
201
static int hf_nvme_mi_mi_nshds_sw_taut;
202
static int hf_nvme_mi_mi_nshds_sw_st;
203
static int hf_nvme_mi_mi_nshds_ctemp;
204
static int hf_nvme_mi_mi_nshds_pdlu;
205
static int hf_nvme_mi_mi_nshds_ccs;
206
207
/* Shared health-status flag bits — same bit layout in the NVMe-MI 2.1
208
 * "Composite Controller Status Data Structure (CCSDS)" and "Controller
209
 * Health Status Changed Flags (CHSCF)" figures. */
210
static int hf_nvme_mi_mi_hsf_tcida;
211
static int hf_nvme_mi_mi_hsf_cwarn;
212
static int hf_nvme_mi_mi_hsf_spare;
213
static int hf_nvme_mi_mi_hsf_pdlu;
214
static int hf_nvme_mi_mi_hsf_ctemp;
215
static int hf_nvme_mi_mi_hsf_csts;
216
static int hf_nvme_mi_mi_hsf_fa;
217
static int hf_nvme_mi_mi_hsf_nac;
218
static int hf_nvme_mi_mi_hsf_ceco;
219
static int hf_nvme_mi_mi_hsf_nssro;
220
static int hf_nvme_mi_mi_hsf_shst;
221
static int hf_nvme_mi_mi_hsf_cfs;
222
static int hf_nvme_mi_mi_hsf_rdy;
223
224
/* Controller Health Data Structure (CHDS) */
225
static int hf_nvme_mi_mi_chds_ctlid;
226
static int hf_nvme_mi_mi_chds_csts;
227
static int hf_nvme_mi_mi_chds_csts_tcida;
228
static int hf_nvme_mi_mi_chds_csts_fa;
229
static int hf_nvme_mi_mi_chds_csts_nac;
230
static int hf_nvme_mi_mi_chds_csts_ceco;
231
static int hf_nvme_mi_mi_chds_csts_nssro;
232
static int hf_nvme_mi_mi_chds_csts_shst;
233
static int hf_nvme_mi_mi_chds_csts_cfs;
234
static int hf_nvme_mi_mi_chds_csts_rdy;
235
static int hf_nvme_mi_mi_chds_ctemp;
236
static int hf_nvme_mi_mi_chds_pdlu;
237
static int hf_nvme_mi_mi_chds_spare;
238
static int hf_nvme_mi_mi_chds_cwarn;
239
static int hf_nvme_mi_mi_chds_cwarn_ips;
240
static int hf_nvme_mi_mi_chds_cwarn_pmre;
241
static int hf_nvme_mi_mi_chds_cwarn_vmbf;
242
static int hf_nvme_mi_mi_chds_cwarn_ro;
243
static int hf_nvme_mi_mi_chds_cwarn_rd;
244
static int hf_nvme_mi_mi_chds_cwarn_taut;
245
static int hf_nvme_mi_mi_chds_cwarn_st;
246
static int hf_nvme_mi_mi_chds_chsc;
247
248
static int ett_nvme_mi_mi;
249
static int ett_nvme_mi_mi_field;
250
static int ett_nvme_mi_mi_entry;
251
252
static expert_field ei_nvme_mi_mi_truncated;
253
static expert_field ei_nvme_mi_mi_orphan_response;
254
static expert_field ei_nvme_mi_mi_reserved_dtyp;
255
static expert_field ei_nvme_mi_mi_reserved_configid;
256
static expert_field ei_nvme_mi_mi_reserved_value;
257
258
/* MI command opcodes (NVMe-MI 2.1 "Opcodes for Management Interface Command
259
 * Set").  Only 00h-07h, 0Ch get field-level
260
 * decode; 08h-0Bh are named for display and fall through to the raw dword
261
 * rendering. */
262
enum nvme_mi_mi_opc {
263
    NVME_MI_MI_OPC_READ_DS    = 0x00,
264
    NVME_MI_MI_OPC_SUBSYS_HSP = 0x01,
265
    NVME_MI_MI_OPC_CTRL_HSP   = 0x02,
266
    NVME_MI_MI_OPC_CONFIG_SET = 0x03,
267
    NVME_MI_MI_OPC_CONFIG_GET = 0x04,
268
    NVME_MI_MI_OPC_VPD_READ   = 0x05,
269
    NVME_MI_MI_OPC_VPD_WRITE  = 0x06,
270
    NVME_MI_MI_OPC_RESET      = 0x07,
271
    NVME_MI_MI_OPC_SES_RECV   = 0x08,
272
    NVME_MI_MI_OPC_SES_SEND   = 0x09,
273
    NVME_MI_MI_OPC_MEB_READ   = 0x0A,
274
    NVME_MI_MI_OPC_MEB_WRITE  = 0x0B,
275
    NVME_MI_MI_OPC_SHUTDOWN   = 0x0C,
276
};
277
278
static const range_string mi_opcode_vals[] = {
279
    { NVME_MI_MI_OPC_READ_DS,    NVME_MI_MI_OPC_READ_DS,    "Read NVMe-MI Data Structure" },
280
    { NVME_MI_MI_OPC_SUBSYS_HSP, NVME_MI_MI_OPC_SUBSYS_HSP, "NVM Subsystem Health Status Poll" },
281
    { NVME_MI_MI_OPC_CTRL_HSP,   NVME_MI_MI_OPC_CTRL_HSP,   "Controller Health Status Poll" },
282
    { NVME_MI_MI_OPC_CONFIG_SET, NVME_MI_MI_OPC_CONFIG_SET, "Configuration Set" },
283
    { NVME_MI_MI_OPC_CONFIG_GET, NVME_MI_MI_OPC_CONFIG_GET, "Configuration Get" },
284
    { NVME_MI_MI_OPC_VPD_READ,   NVME_MI_MI_OPC_VPD_READ,   "VPD Read" },
285
    { NVME_MI_MI_OPC_VPD_WRITE,  NVME_MI_MI_OPC_VPD_WRITE,  "VPD Write" },
286
    { NVME_MI_MI_OPC_RESET,      NVME_MI_MI_OPC_RESET,      "Reset" },
287
    { NVME_MI_MI_OPC_SES_RECV,   NVME_MI_MI_OPC_SES_RECV,   "SES Receive" },
288
    { NVME_MI_MI_OPC_SES_SEND,   NVME_MI_MI_OPC_SES_SEND,   "SES Send" },
289
    { NVME_MI_MI_OPC_MEB_READ,   NVME_MI_MI_OPC_MEB_READ,   "Management Endpoint Buffer Read" },
290
    { NVME_MI_MI_OPC_MEB_WRITE,  NVME_MI_MI_OPC_MEB_WRITE,  "Management Endpoint Buffer Write" },
291
    { NVME_MI_MI_OPC_SHUTDOWN,   NVME_MI_MI_OPC_SHUTDOWN,   "Shutdown" },
292
    { 0xC0, 0xFF,                                           "Vendor Specific" },
293
    { 0, 0, NULL },
294
};
295
296
/* Data Structure Types (Read NVMe-MI Data Structure NVMe Management
297
 * Dword 0); 06h-FFh are reserved. */
298
enum nvme_mi_dtyp {
299
    NVME_MI_DTYP_SUBSYS_INFO = 0x00,
300
    NVME_MI_DTYP_PORT_INFO   = 0x01,
301
    NVME_MI_DTYP_CTRL_LIST   = 0x02,
302
    NVME_MI_DTYP_CTRL_INFO   = 0x03,
303
    NVME_MI_DTYP_OSC_LIST    = 0x04,
304
    NVME_MI_DTYP_MEB_LIST    = 0x05,
305
    NVME_MI_DTYP_MAX         = NVME_MI_DTYP_MEB_LIST,
306
};
307
308
static const value_string mi_dtyp_vals[] = {
309
    { NVME_MI_DTYP_SUBSYS_INFO, "NVM Subsystem Information" },
310
    { NVME_MI_DTYP_PORT_INFO,   "Port Information" },
311
    { NVME_MI_DTYP_CTRL_LIST,   "Controller List" },
312
    { NVME_MI_DTYP_CTRL_INFO,   "Controller Information" },
313
    { NVME_MI_DTYP_OSC_LIST,    "Optionally Supported Command List" },
314
    { NVME_MI_DTYP_MEB_LIST,    "Management Endpoint Buffer Command Support List" },
315
    { 0, NULL },
316
};
317
318
/* Configuration Identifiers; 00h and 05h-BFh are reserved,
319
 * C0h-FFh vendor specific. */
320
enum nvme_mi_cfgid {
321
    NVME_MI_CFGID_SMBUS_FREQ = 0x01,
322
    NVME_MI_CFGID_HSC        = 0x02,
323
    NVME_MI_CFGID_MTUS       = 0x03,
324
    NVME_MI_CFGID_AE         = 0x04,
325
    NVME_MI_CFGID_RESERVED_FIRST = 0x05,
326
    NVME_MI_CFGID_RESERVED_LAST  = 0xBF,
327
};
328
329
static const range_string mi_configid_vals[] = {
330
    { 0x00, 0x00,                                                 "Reserved" },
331
    { NVME_MI_CFGID_SMBUS_FREQ, NVME_MI_CFGID_SMBUS_FREQ,         "SMBus/I2C Frequency" },
332
    { NVME_MI_CFGID_HSC,        NVME_MI_CFGID_HSC,                "Health Status Change" },
333
    { NVME_MI_CFGID_MTUS,       NVME_MI_CFGID_MTUS,               "MCTP Transmission Unit Size" },
334
    { NVME_MI_CFGID_AE,         NVME_MI_CFGID_AE,                 "Asynchronous Event" },
335
    { NVME_MI_CFGID_RESERVED_FIRST, NVME_MI_CFGID_RESERVED_LAST,  "Reserved" },
336
    { 0xC0, 0xFF,                                                 "Vendor Specific" },
337
    { 0, 0, NULL },
338
};
339
340
/* AE Enable ID — Asynchronous Events */
341
static const range_string mi_ae_id_vals[] = {
342
    { 0x00, 0x00, "Controller Ready" },
343
    { 0x01, 0x01, "Controller Fatal Status" },
344
    { 0x02, 0x02, "Shutdown Status" },
345
    { 0x03, 0x03, "Controller Enable" },
346
    { 0x04, 0x04, "Namespace Attribute Changed" },
347
    { 0x05, 0x05, "Firmware Activated" },
348
    { 0x06, 0x06, "Composite Temperature" },
349
    { 0x07, 0x07, "Percentage Drive Life Used" },
350
    { 0x08, 0x08, "Available Spare" },
351
    { 0x09, 0x09, "SMART Warnings" },
352
    { 0x0a, 0x0a, "Telemetry Controller-Initiated Data Available" },
353
    { 0x0b, 0x0b, "PCIe Link Active" },
354
    { 0x0c, 0x0c, "Sanitize Failure Mode" },
355
    { 0x0d, 0x0d, "Sanitize Namespace Failure Mode" },
356
    { 0x0e, 0x0e, "Power Threshold Exceeded" },
357
    { 0xC0, 0xFF, "Vendor Specific" },
358
    { 0, 0, NULL },
359
};
360
361
/* SMBus/I2C frequency encoding */
362
static const value_string mi_sfreq_vals[] = {
363
    { 0x0, "Obsolete/Reserved" },
364
    { 0x1, "100 kHz" },
365
    { 0x2, "400 kHz" },
366
    { 0x3, "1 MHz" },
367
    { 0, NULL },
368
};
369
370
/* Maximum VPD access / maximum SMBus frequency (2-Wire Port Specific
371
 * Data) */
372
static const value_string mi_vpdfreq_vals[] = {
373
    { 0x0, "Not supported" },
374
    { 0x1, "100 kHz" },
375
    { 0x2, "400 kHz" },
376
    { 0x3, "1 MHz" },
377
    { 0, NULL },
378
};
379
380
static const value_string mi_prttyp_vals[] = {
381
    { 0x0, "Inactive" },
382
    { 0x1, "PCIe" },
383
    { 0x2, "2-Wire" },
384
    { 0, NULL },
385
};
386
387
static const value_string mi_pciemps_vals[] = {
388
    { 0x0, "128 bytes" },
389
    { 0x1, "256 bytes" },
390
    { 0x2, "512 bytes" },
391
    { 0x3, "1 KiB" },
392
    { 0x4, "2 KiB" },
393
    { 0x5, "4 KiB" },
394
    { 0, NULL },
395
};
396
397
static const value_string mi_pciecls_vals[] = {
398
    { 0x0, "Link not active" },
399
    { 0x1, "2.5 GT/s" },
400
    { 0x2, "5.0 GT/s" },
401
    { 0x3, "8.0 GT/s" },
402
    { 0x4, "16.0 GT/s" },
403
    { 0x5, "32.0 GT/s" },
404
    { 0x6, "64.0 GT/s" },
405
    { 0, NULL },
406
};
407
408
/* Reset Type; 01h-FFh reserved */
409
0
#define NVME_MI_RSTTYP_MAX 0x00     /* highest valid Reset Type */
410
static const value_string mi_rsttyp_vals[] = {
411
    { 0x00, "Reset NVM Subsystem" },
412
    { 0, NULL },
413
};
414
415
/* Shutdown Type; 02h-FFh reserved */
416
0
#define NVME_MI_SHDNTYP_MAX 0x01    /* highest valid Shutdown Type */
417
static const value_string mi_shdntyp_vals[] = {
418
    { 0x00, "Normal NVM Subsystem Shutdown" },
419
    { 0x01, "Abrupt NVM Subsystem Shutdown" },
420
    { 0, NULL },
421
};
422
423
/*
424
 * CSTS.SHST shutdown status: reuse packet-nvme.c's shst_table (shared via
425
 * packet-nvme.h) so the MI CHDS decode and the NVMe Base decode never drift.
426
 *
427
 * NMIMT in command-list entries (the Optionally/MEB Supported Command Data
428
 * Structure entries) uses the same encoding as the
429
 * message header, so the entry decode reuses mi_type_vals (packet-nvme-mi.h).
430
 */
431
432
/*
433
 * Per-transaction request context hung off nvme_mi_transaction.body_ctx
434
 * (wmem_file_scope).  Records the request parameter that selects the
435
 * response layout; only the member matching the transaction's opcode is
436
 * meaningful.
437
 */
438
struct nvme_mi_mi_req_ctx {
439
    uint8_t dtyp;       /* Read NVMe-MI Data Structure (00h) */
440
    uint8_t configid;   /* Configuration Set/Get (03h/04h) */
441
};
442
443
static int * const rds_cdw0_fields[] = {
444
    &hf_nvme_mi_mi_rds_dtyp,
445
    &hf_nvme_mi_mi_rds_portid,
446
    &hf_nvme_mi_mi_rds_ctrlid,
447
    NULL,
448
};
449
static int * const rds_cdw1_fields[] = {
450
    &hf_nvme_mi_mi_rds_iocsi,
451
    NULL,
452
};
453
static int * const nshsp_cdw1_fields[] = {
454
    &hf_nvme_mi_mi_nshsp_cs,
455
    NULL,
456
};
457
static int * const chsp_cdw0_fields[] = {
458
    &hf_nvme_mi_mi_chsp_all,
459
    &hf_nvme_mi_mi_chsp_incvf,
460
    &hf_nvme_mi_mi_chsp_incpf,
461
    &hf_nvme_mi_mi_chsp_incf,
462
    &hf_nvme_mi_mi_chsp_maxrent,
463
    &hf_nvme_mi_mi_chsp_sctlid,
464
    NULL,
465
};
466
static int * const chsp_cdw1_fields[] = {
467
    &hf_nvme_mi_mi_chsp_ccf,
468
    &hf_nvme_mi_mi_chsp_cwarn,
469
    &hf_nvme_mi_mi_chsp_spare,
470
    &hf_nvme_mi_mi_chsp_pdlu,
471
    &hf_nvme_mi_mi_chsp_ctemp,
472
    &hf_nvme_mi_mi_chsp_csts,
473
    NULL,
474
};
475
static int * const cfg_cdw0_fields_cid[] = {
476
    &hf_nvme_mi_mi_cfg_cid,
477
    NULL,
478
};
479
static int * const cfg_cdw0_fields_port[] = {
480
    &hf_nvme_mi_mi_cfg_portid,
481
    &hf_nvme_mi_mi_cfg_cid,
482
    NULL,
483
};
484
static int * const cfg_cdw0_fields_sfreq[] = {
485
    &hf_nvme_mi_mi_cfg_portid,
486
    &hf_nvme_mi_mi_cfg_sfreq,
487
    &hf_nvme_mi_mi_cfg_cid,
488
    NULL,
489
};
490
static int * const cfg_cdw1_fields_hsc[] = {
491
    &hf_nvme_mi_mi_cfg_hsc_tcida,
492
    &hf_nvme_mi_mi_cfg_hsc_cwarn,
493
    &hf_nvme_mi_mi_cfg_hsc_spare,
494
    &hf_nvme_mi_mi_cfg_hsc_pdlu,
495
    &hf_nvme_mi_mi_cfg_hsc_ctemp,
496
    &hf_nvme_mi_mi_cfg_hsc_cschng,
497
    &hf_nvme_mi_mi_cfg_hsc_fa,
498
    &hf_nvme_mi_mi_cfg_hsc_nac,
499
    &hf_nvme_mi_mi_cfg_hsc_ceco,
500
    &hf_nvme_mi_mi_cfg_hsc_nssro,
501
    &hf_nvme_mi_mi_cfg_hsc_shst,
502
    &hf_nvme_mi_mi_cfg_hsc_cfs,
503
    &hf_nvme_mi_mi_cfg_hsc_rdy,
504
    NULL,
505
};
506
static int * const cfg_cdw1_fields_mtus[] = {
507
    &hf_nvme_mi_mi_cfg_mtus,
508
    NULL,
509
};
510
/* Configuration Set of the Asynchronous Event configuration; the
511
 * Configuration Get form has these bits reserved. */
512
static int * const cfg_cdw0_fields_ae_set[] = {
513
    &hf_nvme_mi_mi_cfg_ae_envfa,
514
    &hf_nvme_mi_mi_cfg_ae_enpfa,
515
    &hf_nvme_mi_mi_cfg_ae_encfa,
516
    &hf_nvme_mi_mi_cfg_ae_aemd,
517
    &hf_nvme_mi_mi_cfg_ae_aerd,
518
    &hf_nvme_mi_mi_cfg_cid,
519
    NULL,
520
};
521
static int * const vpd_cdw0_fields[] = {
522
    &hf_nvme_mi_mi_vpd_dofst,
523
    NULL,
524
};
525
static int * const vpd_cdw1_fields[] = {
526
    &hf_nvme_mi_mi_vpd_dlen,
527
    NULL,
528
};
529
static int * const reset_cdw0_fields[] = {
530
    &hf_nvme_mi_mi_reset_rsttyp,
531
    NULL,
532
};
533
static int * const shutdown_cdw0_fields[] = {
534
    &hf_nvme_mi_mi_shutdown_shdntyp,
535
    NULL,
536
};
537
static int * const subsys_nnsc_fields[] = {
538
    &hf_nvme_mi_mi_subsys_sre,
539
    NULL,
540
};
541
static int * const port_prtcap_fields[] = {
542
    &hf_nvme_mi_mi_port_aems,
543
    &hf_nvme_mi_mi_port_ciaps,
544
    NULL,
545
};
546
static int * const port_twprt_fields[] = {
547
    &hf_nvme_mi_mi_port_twire_i3csprt,
548
    &hf_nvme_mi_mi_port_twire_msmbfreq,
549
    NULL,
550
};
551
static int * const port_nvmebm_fields[] = {
552
    &hf_nvme_mi_mi_port_twire_nvmebms,
553
    NULL,
554
};
555
static int * const ctrlinfo_prii_fields[] = {
556
    &hf_nvme_mi_mi_ctrlinfo_riv,
557
    NULL,
558
};
559
static int * const ctrlinfo_pri_fields[] = {
560
    &hf_nvme_mi_mi_ctrlinfo_pri_bus,
561
    &hf_nvme_mi_mi_ctrlinfo_pri_dev,
562
    &hf_nvme_mi_mi_ctrlinfo_pri_fn,
563
    NULL,
564
};
565
static int * const cmdlist_ctyp_fields[] = {
566
    &hf_nvme_mi_mi_cmdlist_nmimt,
567
    NULL,
568
};
569
static int * const nshds_nss_fields[] = {
570
    &hf_nvme_mi_mi_nshds_nss_atf,
571
    &hf_nvme_mi_mi_nshds_nss_sfm,
572
    &hf_nvme_mi_mi_nshds_nss_df,
573
    &hf_nvme_mi_mi_nshds_nss_rnr,
574
    &hf_nvme_mi_mi_nshds_nss_p0la,
575
    &hf_nvme_mi_mi_nshds_nss_p1la,
576
    &hf_nvme_mi_mi_nshds_nss_snfm,
577
    NULL,
578
};
579
/*
580
 * NSHDS SMART Warnings is the bitwise *inverse* of the SMART / Health
581
 * Information Critical Warning field: a bit is set to '1' when the condition
582
 * is clear on every Controller in the NVM Subsystem, and cleared to '0' when
583
 * any Controller asserts it.  The bit positions match CHDS CWARN, but the
584
 * sense is opposite, so these must not use tfs_set_notset.
585
 */
586
static const true_false_string tfs_nshds_sw = { "Normal", "Warning" };
587
static int * const nshds_sw_fields[] = {
588
    &hf_nvme_mi_mi_nshds_sw_ips,
589
    &hf_nvme_mi_mi_nshds_sw_pmre,
590
    &hf_nvme_mi_mi_nshds_sw_vmbf,
591
    &hf_nvme_mi_mi_nshds_sw_ro,
592
    &hf_nvme_mi_mi_nshds_sw_rd,
593
    &hf_nvme_mi_mi_nshds_sw_taut,
594
    &hf_nvme_mi_mi_nshds_sw_st,
595
    NULL,
596
};
597
static int * const hsf_fields[] = {
598
    &hf_nvme_mi_mi_hsf_tcida,
599
    &hf_nvme_mi_mi_hsf_cwarn,
600
    &hf_nvme_mi_mi_hsf_spare,
601
    &hf_nvme_mi_mi_hsf_pdlu,
602
    &hf_nvme_mi_mi_hsf_ctemp,
603
    &hf_nvme_mi_mi_hsf_csts,
604
    &hf_nvme_mi_mi_hsf_fa,
605
    &hf_nvme_mi_mi_hsf_nac,
606
    &hf_nvme_mi_mi_hsf_ceco,
607
    &hf_nvme_mi_mi_hsf_nssro,
608
    &hf_nvme_mi_mi_hsf_shst,
609
    &hf_nvme_mi_mi_hsf_cfs,
610
    &hf_nvme_mi_mi_hsf_rdy,
611
    NULL,
612
};
613
static int * const chds_csts_fields[] = {
614
    &hf_nvme_mi_mi_chds_csts_tcida,
615
    &hf_nvme_mi_mi_chds_csts_fa,
616
    &hf_nvme_mi_mi_chds_csts_nac,
617
    &hf_nvme_mi_mi_chds_csts_ceco,
618
    &hf_nvme_mi_mi_chds_csts_nssro,
619
    &hf_nvme_mi_mi_chds_csts_shst,
620
    &hf_nvme_mi_mi_chds_csts_cfs,
621
    &hf_nvme_mi_mi_chds_csts_rdy,
622
    NULL,
623
};
624
static int * const chds_cwarn_fields[] = {
625
    &hf_nvme_mi_mi_chds_cwarn_ips,
626
    &hf_nvme_mi_mi_chds_cwarn_pmre,
627
    &hf_nvme_mi_mi_chds_cwarn_vmbf,
628
    &hf_nvme_mi_mi_chds_cwarn_ro,
629
    &hf_nvme_mi_mi_chds_cwarn_rd,
630
    &hf_nvme_mi_mi_chds_cwarn_taut,
631
    &hf_nvme_mi_mi_chds_cwarn_st,
632
    NULL,
633
};
634
635
/*
636
 * NSHDS CTEMP encoding: 00h-7Eh = 0-126 °C, 7Fh = 127 °C or
637
 * higher, 80h/81h = sentinel codes, C4h = -60 °C or lower, C5h-FFh =
638
 * -59 to -1 °C in two's complement, the rest reserved.
639
 */
640
static void
641
nvme_mi_mi_fmt_nshds_ctemp(char *buf, uint32_t value)
642
0
{
643
0
    if (value <= 0x7e)
644
0
        snprintf(buf, ITEM_LABEL_LENGTH, "%u " UTF8_DEGREE_SIGN "C", value);
645
0
    else if (value == 0x7f)
646
0
        snprintf(buf, ITEM_LABEL_LENGTH, "127 " UTF8_DEGREE_SIGN "C or higher");
647
0
    else if (value == 0x80)
648
0
        snprintf(buf, ITEM_LABEL_LENGTH, "No temperature data or data is stale");
649
0
    else if (value == 0x81)
650
0
        snprintf(buf, ITEM_LABEL_LENGTH, "Temperature sensor failure");
651
0
    else if (value <= 0xc3)
652
0
        snprintf(buf, ITEM_LABEL_LENGTH, "Reserved (0x%02x)", value);
653
0
    else if (value == 0xc4)
654
0
        snprintf(buf, ITEM_LABEL_LENGTH, "-60 " UTF8_DEGREE_SIGN "C or lower");
655
0
    else
656
0
        snprintf(buf, ITEM_LABEL_LENGTH, "%d " UTF8_DEGREE_SIGN "C",
657
0
                 (int)value - 256);
658
0
}
659
660
/* Flag truncated response data and render the leftover bytes raw. */
661
static void
662
nvme_mi_mi_data_truncated(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
663
                          proto_item *it, int off)
664
0
{
665
0
    nvme_mi_dissect_truncated(tvb, pinfo, tree, it, &ei_nvme_mi_mi_truncated,
666
0
                              hf_nvme_mi_mi_data, off);
667
0
}
668
669
/* DTYP 00h — NVM Subsystem Information Data Structure */
670
static void
671
nvme_mi_mi_data_subsys_info(tvbuff_t *tvb, packet_info *pinfo,
672
                            proto_tree *tree, proto_item *it, int off, int len)
673
0
{
674
0
    if (len < 4) {
675
0
        nvme_mi_mi_data_truncated(tvb, pinfo, tree, it, off);
676
0
        return;
677
0
    }
678
0
    proto_tree_add_item(tree, hf_nvme_mi_mi_subsys_nump, tvb, off, 1, ENC_NA);
679
0
    proto_tree_add_item(tree, hf_nvme_mi_mi_subsys_mjr, tvb, off + 1, 1, ENC_NA);
680
0
    proto_tree_add_item(tree, hf_nvme_mi_mi_subsys_mnr, tvb, off + 2, 1, ENC_NA);
681
0
    proto_tree_add_bitmask(tree, tvb, off + 3, hf_nvme_mi_mi_subsys_nnsc,
682
0
                           ett_nvme_mi_mi_field, subsys_nnsc_fields, ENC_NA);
683
    /* bytes 31:04 reserved */
684
0
}
685
686
/* DTYP 01h — Port Information Data Structure */
687
static void
688
nvme_mi_mi_data_port_info(tvbuff_t *tvb, packet_info *pinfo,
689
                          proto_tree *tree, proto_item *it, int off, int len)
690
0
{
691
0
    uint32_t prttyp;
692
693
0
    if (len < 8) {
694
0
        nvme_mi_mi_data_truncated(tvb, pinfo, tree, it, off);
695
0
        return;
696
0
    }
697
0
    proto_tree_add_item_ret_uint(tree, hf_nvme_mi_mi_port_prttyp,
698
0
                                 tvb, off, 1, ENC_NA, &prttyp);
699
0
    proto_tree_add_bitmask(tree, tvb, off + 1, hf_nvme_mi_mi_port_prtcap,
700
0
                           ett_nvme_mi_mi_field, port_prtcap_fields, ENC_NA);
701
0
    proto_tree_add_item(tree, hf_nvme_mi_mi_port_mmtus,
702
0
                        tvb, off + 2, 2, ENC_LITTLE_ENDIAN);
703
0
    proto_tree_add_item(tree, hf_nvme_mi_mi_port_mebs,
704
0
                        tvb, off + 4, 4, ENC_LITTLE_ENDIAN);
705
706
0
    switch (prttyp) {
707
0
    case 0x1:   /* PCIe Port Specific Data */
708
0
        if (len < 14) {
709
0
            nvme_mi_mi_data_truncated(tvb, pinfo, tree, it, off + 8);
710
0
            return;
711
0
        }
712
0
        proto_tree_add_item(tree, hf_nvme_mi_mi_port_pcie_mps,
713
0
                            tvb, off + 8, 1, ENC_NA);
714
0
        proto_tree_add_item(tree, hf_nvme_mi_mi_port_pcie_slsv,
715
0
                            tvb, off + 9, 1, ENC_NA);
716
0
        proto_tree_add_item(tree, hf_nvme_mi_mi_port_pcie_cls,
717
0
                            tvb, off + 10, 1, ENC_NA);
718
0
        proto_tree_add_item(tree, hf_nvme_mi_mi_port_pcie_mlw,
719
0
                            tvb, off + 11, 1, ENC_NA);
720
0
        proto_tree_add_item(tree, hf_nvme_mi_mi_port_pcie_nlw,
721
0
                            tvb, off + 12, 1, ENC_NA);
722
0
        proto_tree_add_item(tree, hf_nvme_mi_mi_port_pcie_pn,
723
0
                            tvb, off + 13, 1, ENC_NA);
724
0
        break;
725
0
    case 0x2:   /* 2-Wire Port Specific Data */
726
0
        if (len < 13) {
727
0
            nvme_mi_mi_data_truncated(tvb, pinfo, tree, it, off + 8);
728
0
            return;
729
0
        }
730
0
        proto_tree_add_item(tree, hf_nvme_mi_mi_port_twire_cvpdaddr,
731
0
                            tvb, off + 8, 1, ENC_NA);
732
0
        proto_tree_add_item(tree, hf_nvme_mi_mi_port_twire_mvpdfreq,
733
0
                            tvb, off + 9, 1, ENC_NA);
734
0
        proto_tree_add_item(tree, hf_nvme_mi_mi_port_twire_cmeaddr,
735
0
                            tvb, off + 10, 1, ENC_NA);
736
0
        proto_tree_add_bitmask(tree, tvb, off + 11,
737
0
                               hf_nvme_mi_mi_port_twire_twprt,
738
0
                               ett_nvme_mi_mi_field, port_twprt_fields, ENC_NA);
739
0
        proto_tree_add_bitmask(tree, tvb, off + 12,
740
0
                               hf_nvme_mi_mi_port_twire_nvmebm,
741
0
                               ett_nvme_mi_mi_field, port_nvmebm_fields, ENC_NA);
742
0
        break;
743
0
    default:
744
        /* Inactive or reserved port type: PTSP bytes rendered raw */
745
0
        if (len > 8)
746
0
            proto_tree_add_item(tree, hf_nvme_mi_mi_data, tvb, off + 8, -1,
747
0
                                ENC_NA);
748
0
        break;
749
0
    }
750
0
}
751
752
/* DTYP 02h — Controller List (NVMe Base format: count + uint16le IDs) */
753
static void
754
nvme_mi_mi_data_ctrl_list(tvbuff_t *tvb, packet_info *pinfo,
755
                          proto_tree *tree, proto_item *it, int off, int len)
756
0
{
757
0
    uint32_t numids;
758
0
    int pos = off + 2;
759
760
0
    if (len < 2) {
761
0
        nvme_mi_mi_data_truncated(tvb, pinfo, tree, it, off);
762
0
        return;
763
0
    }
764
0
    proto_tree_add_item_ret_uint(tree, hf_nvme_mi_mi_ctrllist_numids,
765
0
                                 tvb, off, 2, ENC_LITTLE_ENDIAN, &numids);
766
0
    for (uint32_t i = 0; i < numids; i++) {
767
0
        if (pos + 2 > off + len) {
768
0
            nvme_mi_mi_data_truncated(tvb, pinfo, tree, it, pos);
769
0
            return;
770
0
        }
771
0
        proto_tree_add_item(tree, hf_nvme_mi_mi_ctrllist_ctrlid,
772
0
                            tvb, pos, 2, ENC_LITTLE_ENDIAN);
773
0
        pos += 2;
774
0
    }
775
0
}
776
777
/* DTYP 03h — Controller Information Data Structure */
778
static void
779
nvme_mi_mi_data_ctrl_info(tvbuff_t *tvb, packet_info *pinfo,
780
                          proto_tree *tree, proto_item *it, int off, int len)
781
0
{
782
0
    if (len < 17) {
783
0
        nvme_mi_mi_data_truncated(tvb, pinfo, tree, it, off);
784
0
        return;
785
0
    }
786
0
    proto_tree_add_item(tree, hf_nvme_mi_mi_ctrlinfo_portid,
787
0
                        tvb, off, 1, ENC_NA);
788
    /* bytes 04:01 reserved */
789
0
    proto_tree_add_bitmask(tree, tvb, off + 5, hf_nvme_mi_mi_ctrlinfo_prii,
790
0
                           ett_nvme_mi_mi_field, ctrlinfo_prii_fields, ENC_NA);
791
0
    proto_tree_add_bitmask(tree, tvb, off + 6, hf_nvme_mi_mi_ctrlinfo_pri,
792
0
                           ett_nvme_mi_mi_field, ctrlinfo_pri_fields,
793
0
                           ENC_LITTLE_ENDIAN);
794
0
    proto_tree_add_item(tree, hf_nvme_mi_mi_ctrlinfo_pcivid,
795
0
                        tvb, off + 8, 2, ENC_LITTLE_ENDIAN);
796
0
    proto_tree_add_item(tree, hf_nvme_mi_mi_ctrlinfo_pcidid,
797
0
                        tvb, off + 10, 2, ENC_LITTLE_ENDIAN);
798
0
    proto_tree_add_item(tree, hf_nvme_mi_mi_ctrlinfo_pcisvid,
799
0
                        tvb, off + 12, 2, ENC_LITTLE_ENDIAN);
800
0
    proto_tree_add_item(tree, hf_nvme_mi_mi_ctrlinfo_pcisdid,
801
0
                        tvb, off + 14, 2, ENC_LITTLE_ENDIAN);
802
0
    proto_tree_add_item(tree, hf_nvme_mi_mi_ctrlinfo_pciesn,
803
0
                        tvb, off + 16, 1, ENC_NA);
804
    /* bytes 31:17 reserved */
805
0
}
806
807
/* DTYP 04h/05h — Optionally Supported / MEB Supported Command List
808
 * (both share the count + (CTYP, OPC) entry format) */
809
static void
810
nvme_mi_mi_data_cmd_list(tvbuff_t *tvb, packet_info *pinfo,
811
                         proto_tree *tree, proto_item *it, int off, int len)
812
0
{
813
0
    uint32_t numcmd;
814
0
    int pos = off + 2;
815
816
0
    if (len < 2) {
817
0
        nvme_mi_mi_data_truncated(tvb, pinfo, tree, it, off);
818
0
        return;
819
0
    }
820
0
    proto_tree_add_item_ret_uint(tree, hf_nvme_mi_mi_cmdlist_numcmd,
821
0
                                 tvb, off, 2, ENC_LITTLE_ENDIAN, &numcmd);
822
0
    for (uint32_t i = 0; i < numcmd; i++) {
823
0
        uint64_t ctyp;
824
0
        uint8_t opc;
825
0
        proto_item *opc_it;
826
0
        const char *opc_name = NULL;
827
828
0
        if (pos + 2 > off + len) {
829
0
            nvme_mi_mi_data_truncated(tvb, pinfo, tree, it, pos);
830
0
            return;
831
0
        }
832
0
        proto_tree_add_bitmask_ret_uint64(tree, tvb, pos, hf_nvme_mi_mi_cmdlist_ctyp,
833
0
                                          ett_nvme_mi_mi_field, cmdlist_ctyp_fields,
834
0
                                          ENC_NA, &ctyp);
835
0
        opc_it = proto_tree_add_item_ret_uint8(tree, hf_nvme_mi_mi_cmdlist_opc,
836
0
                                               tvb, pos + 1, 1, ENC_NA, &opc);
837
        /* NMIMT (CTYP bits 6:3) selects which opcode namespace OPC belongs to
838
         * -- both tables already exist in-tree, so name the entry from
839
         * whichever one the command actually lives in instead of leaving it
840
         * a bare byte. */
841
0
        switch ((ctyp & 0x78) >> 3) {
842
0
        case NVME_MI_TYPE_MI:
843
0
            opc_name = rval_to_str_const(opc, mi_opcode_vals, "Unknown");
844
0
            break;
845
0
        case NVME_MI_TYPE_ADMIN:
846
0
            opc_name = nvme_get_opcode_string(opc, 0);
847
0
            break;
848
0
        default:
849
0
            break;
850
0
        }
851
0
        if (opc_name)
852
0
            proto_item_append_text(opc_it, " (%s)", opc_name);
853
0
        pos += 2;
854
0
    }
855
0
}
856
857
/* NVM Subsystem Health Data Structure (NSHDS; 8 bytes) */
858
static void
859
nvme_mi_mi_data_nshds(tvbuff_t *tvb, packet_info *pinfo,
860
                      proto_tree *tree, proto_item *it, int off, int len)
861
0
{
862
0
    if (len < 8) {
863
0
        nvme_mi_mi_data_truncated(tvb, pinfo, tree, it, off);
864
0
        return;
865
0
    }
866
0
    proto_tree_add_bitmask(tree, tvb, off, hf_nvme_mi_mi_nshds_nss,
867
0
                           ett_nvme_mi_mi_field, nshds_nss_fields, ENC_NA);
868
0
    proto_tree_add_bitmask(tree, tvb, off + 1, hf_nvme_mi_mi_nshds_sw,
869
0
                           ett_nvme_mi_mi_field, nshds_sw_fields, ENC_NA);
870
0
    proto_tree_add_item(tree, hf_nvme_mi_mi_nshds_ctemp,
871
0
                        tvb, off + 2, 1, ENC_NA);
872
0
    proto_tree_add_item(tree, hf_nvme_mi_mi_nshds_pdlu,
873
0
                        tvb, off + 3, 1, ENC_NA);
874
0
    proto_tree_add_bitmask(tree, tvb, off + 4, hf_nvme_mi_mi_nshds_ccs,
875
0
                           ett_nvme_mi_mi_field, hsf_fields,
876
0
                           ENC_LITTLE_ENDIAN);
877
    /* bytes 7:6 reserved */
878
0
}
879
880
/* Array of 16-byte Controller Health Data Structures (CHDS) */
881
static void
882
nvme_mi_mi_data_chds_list(tvbuff_t *tvb, packet_info *pinfo,
883
                          proto_tree *tree, proto_item *it, int off, int len)
884
0
{
885
0
    unsigned idx = 0;
886
0
    int pos = off;
887
888
0
    while (off + len - pos >= 16) {
889
0
        proto_tree *etree = proto_tree_add_subtree_format(tree, tvb, pos, 16,
890
0
                ett_nvme_mi_mi_entry, NULL,
891
0
                "Controller Health Data Structure %u", idx);
892
0
        proto_tree_add_item(etree, hf_nvme_mi_mi_chds_ctlid,
893
0
                            tvb, pos, 2, ENC_LITTLE_ENDIAN);
894
0
        proto_tree_add_bitmask(etree, tvb, pos + 2, hf_nvme_mi_mi_chds_csts,
895
0
                               ett_nvme_mi_mi_field, chds_csts_fields,
896
0
                               ENC_LITTLE_ENDIAN);
897
0
        proto_tree_add_item(etree, hf_nvme_mi_mi_chds_ctemp,
898
0
                            tvb, pos + 4, 2, ENC_LITTLE_ENDIAN);
899
0
        proto_tree_add_item(etree, hf_nvme_mi_mi_chds_pdlu,
900
0
                            tvb, pos + 6, 1, ENC_NA);
901
0
        proto_tree_add_item(etree, hf_nvme_mi_mi_chds_spare,
902
0
                            tvb, pos + 7, 1, ENC_NA);
903
0
        proto_tree_add_bitmask(etree, tvb, pos + 8, hf_nvme_mi_mi_chds_cwarn,
904
0
                               ett_nvme_mi_mi_field, chds_cwarn_fields,
905
0
                               ENC_NA);
906
0
        proto_tree_add_bitmask(etree, tvb, pos + 9, hf_nvme_mi_mi_chds_chsc,
907
0
                               ett_nvme_mi_mi_field, hsf_fields,
908
0
                               ENC_LITTLE_ENDIAN);
909
        /* bytes 15:11 reserved */
910
0
        pos += 16;
911
0
        idx++;
912
0
    }
913
0
    if (pos < off + len)
914
0
        nvme_mi_mi_data_truncated(tvb, pinfo, tree, it, pos);
915
0
}
916
917
/* Append " (<opcode>[: <detail>])" to COL_INFO. */
918
static void
919
nvme_mi_mi_col_append(packet_info *pinfo, unsigned opcode, const char *detail)
920
0
{
921
0
    const char *name = rval_to_str_const(opcode, mi_opcode_vals, "Unknown");
922
923
0
    if (detail)
924
0
        col_append_fstr(pinfo->cinfo, COL_INFO, " (%s: %s)", name, detail);
925
0
    else
926
0
        col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", name);
927
0
}
928
929
static const char *
930
nvme_mi_mi_configid_name(uint8_t cid)
931
0
{
932
0
    return rval_to_str_const(cid, mi_configid_vals, "Reserved");
933
0
}
934
935
/*
936
 * Decode a request whose only parameter is a type byte in NMD0 bits 31:24
937
 * with NMD1 reserved (Reset RSTTYP; Shutdown SHDNTYP).  Values above
938
 * max_valid are in the Reserved range.  Returns
939
 * the type's display name for COL_INFO.
940
 */
941
static const char *
942
nvme_mi_mi_dissect_typebyte_req(tvbuff_t *tvb, packet_info *pinfo,
943
                                proto_tree *mi_tree, int * const *cdw0_fields,
944
                                uint8_t max_valid, const value_string *vals)
945
0
{
946
0
    proto_item *cdw_it;
947
0
    uint64_t cdw0;
948
0
    uint8_t typ;
949
950
0
    cdw_it = proto_tree_add_bitmask_ret_uint64(mi_tree, tvb, 4,
951
0
            hf_nvme_mi_mi_cdw0, ett_nvme_mi_mi_field,
952
0
            cdw0_fields, ENC_LITTLE_ENDIAN, &cdw0);
953
0
    typ = (uint8_t)(cdw0 >> 24);
954
0
    if (typ > max_valid)
955
0
        expert_add_info(pinfo, cdw_it, &ei_nvme_mi_mi_reserved_value);
956
0
    proto_tree_add_item(mi_tree, hf_nvme_mi_mi_cdw1,
957
0
                        tvb, 8, 4, ENC_LITTLE_ENDIAN);
958
0
    return val_to_str_const(typ, vals, "Reserved");
959
0
}
960
961
/*
962
 * The AE Enable List sent as Configuration Set (03h) request data and the
963
 * AE Supported List returned as Configuration Get (04h) response data share
964
 * one layout: a header (count, version,
965
 * total length, header length) followed by <count> entries, each a 1-byte
966
 * length plus a 2-byte info word (flag bit 15, AE ID bits 7:0).  Only the
967
 * field names differ, so the walk below is driven by this descriptor.
968
 */
969
struct nvme_mi_mi_ae_list_hf {
970
    int         list;
971
    int         num;
972
    int         ver;
973
    int         total_len;
974
    int         hdr_len;
975
    int         entry;
976
    int         entry_len;
977
    int         flag;
978
    int         id;
979
    const char *entry_name;
980
};
981
982
static void
983
dissect_nvme_mi_mi_ae_list(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
984
                           proto_item *it, unsigned off, unsigned len,
985
                           const struct nvme_mi_mi_ae_list_hf *hf)
986
0
{
987
0
    proto_tree *ae_tree;
988
0
    proto_item *ti;
989
0
    uint32_t num, hdr_len, i;
990
0
    unsigned pos;
991
992
0
    ti = proto_tree_add_item(tree, hf->list, tvb, off, len, ENC_NA);
993
0
    ae_tree = proto_item_add_subtree(ti, ett_nvme_mi_mi);
994
995
    /* The list header is 5 bytes; anything shorter is truncated. */
996
0
    if (len < 5) {
997
0
        nvme_mi_mi_data_truncated(tvb, pinfo, ae_tree, it, off);
998
0
        return;
999
0
    }
1000
1001
0
    proto_tree_add_item_ret_uint(ae_tree, hf->num,
1002
0
                                 tvb, off, 1, ENC_LITTLE_ENDIAN, &num);
1003
0
    proto_tree_add_item(ae_tree, hf->ver,
1004
0
                        tvb, off + 1, 1, ENC_LITTLE_ENDIAN);
1005
0
    proto_tree_add_item(ae_tree, hf->total_len,
1006
0
                        tvb, off + 2, 2, ENC_LITTLE_ENDIAN);
1007
0
    proto_tree_add_item_ret_uint(ae_tree, hf->hdr_len,
1008
0
                                 tvb, off + 4, 1, ENC_LITTLE_ENDIAN, &hdr_len);
1009
1010
    /* The list body starts at the offset the header declares, not at a fixed
1011
     * 5; a value below the 5 defined header bytes is bogus, so clamp forward
1012
     * to keep the entry walk inside the body. */
1013
0
    if (hdr_len < 5)
1014
0
        hdr_len = 5;
1015
1016
0
    pos = off + hdr_len;
1017
0
    for (i = 0; i < num; i++) {
1018
0
        proto_tree *e_tree;
1019
0
        proto_item *e_ti;
1020
0
        unsigned elen, entry_len;
1021
1022
        /* Each entry is at least 3 bytes (length + info word).  Stop if the
1023
         * next entry would run past the list data. */
1024
0
        if (pos + 3 > off + len)
1025
0
            break;
1026
0
        elen = tvb_get_uint8(tvb, pos);
1027
0
        if (elen < 3)
1028
0
            elen = 3;   /* spec value is 3h; guarantee forward progress */
1029
1030
        /* A bogus length must not drive the entry item past the list data;
1031
         * clamp its displayed length to what remains so a truncated list
1032
         * stops cleanly rather than raising a bounds exception. */
1033
0
        entry_len = elen;
1034
0
        if (pos + entry_len > off + len)
1035
0
            entry_len = off + len - pos;
1036
1037
0
        e_ti = proto_tree_add_item(ae_tree, hf->entry,
1038
0
                                   tvb, pos, entry_len, ENC_NA);
1039
0
        proto_item_set_text(e_ti, "%s %u", hf->entry_name, i);
1040
0
        e_tree = proto_item_add_subtree(e_ti, ett_nvme_mi_mi_field);
1041
0
        proto_tree_add_item(e_tree, hf->entry_len,
1042
0
                            tvb, pos, 1, ENC_LITTLE_ENDIAN);
1043
0
        proto_tree_add_item(e_tree, hf->flag,
1044
0
                            tvb, pos + 1, 2, ENC_LITTLE_ENDIAN);
1045
0
        proto_tree_add_item(e_tree, hf->id,
1046
0
                            tvb, pos + 1, 2, ENC_LITTLE_ENDIAN);
1047
0
        pos += elen;
1048
0
    }
1049
0
}
1050
1051
/* AE Enable List (Configuration Set request data). */
1052
static void
1053
dissect_nvme_mi_mi_ae_enable_list(tvbuff_t *tvb, packet_info *pinfo,
1054
                                  proto_tree *tree, proto_item *it,
1055
                                  unsigned off, unsigned len)
1056
0
{
1057
0
    const struct nvme_mi_mi_ae_list_hf hf = {
1058
0
        hf_nvme_mi_mi_ae,        hf_nvme_mi_mi_ae_numaee,
1059
0
        hf_nvme_mi_mi_ae_aeelver, hf_nvme_mi_mi_ae_aeetl,
1060
0
        hf_nvme_mi_mi_ae_aeelhl, hf_nvme_mi_mi_ae_entry,
1061
0
        hf_nvme_mi_mi_ae_aeel,   hf_nvme_mi_mi_ae_aee,
1062
0
        hf_nvme_mi_mi_ae_id,     "AE Enable",
1063
0
    };
1064
1065
0
    dissect_nvme_mi_mi_ae_list(tvb, pinfo, tree, it, off, len, &hf);
1066
0
}
1067
1068
/* AE Supported List (Configuration Get response data). */
1069
static void
1070
dissect_nvme_mi_mi_ae_supported_list(tvbuff_t *tvb, packet_info *pinfo,
1071
                                     proto_tree *tree, proto_item *it,
1072
                                     unsigned off, unsigned len)
1073
0
{
1074
0
    const struct nvme_mi_mi_ae_list_hf hf = {
1075
0
        hf_nvme_mi_mi_aes,        hf_nvme_mi_mi_aes_numaes,
1076
0
        hf_nvme_mi_mi_aes_aeslver, hf_nvme_mi_mi_aes_aestl,
1077
0
        hf_nvme_mi_mi_aes_aeslhl, hf_nvme_mi_mi_aes_entry,
1078
0
        hf_nvme_mi_mi_aes_aesl,   hf_nvme_mi_mi_aes_aese,
1079
0
        hf_nvme_mi_mi_aes_id,     "AE Supported",
1080
0
    };
1081
1082
0
    dissect_nvme_mi_mi_ae_list(tvb, pinfo, tree, it, off, len, &hf);
1083
0
}
1084
1085
/*
1086
 * Body worker.  Kept separate from the registered wrapper so that a future
1087
 * in-band NVMe-MI Send/Receive decode (NVMe Admin opcodes 1Dh/1Eh tunnel the
1088
 * same MI command bytes) can call it directly with an explicit direction and
1089
 * a NULL transaction.
1090
 */
1091
static int
1092
dissect_nvme_mi_mi_body(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1093
                        bool resp, struct nvme_mi_transaction *trans)
1094
0
{
1095
0
    proto_item *it, *it2;
1096
0
    proto_tree *mi_tree;
1097
0
    unsigned len = tvb_reported_length(tvb);
1098
1099
0
    it = proto_tree_add_item(tree, proto_nvme_mi_mi, tvb, 0, -1, ENC_NA);
1100
0
    mi_tree = proto_item_add_subtree(it, ett_nvme_mi_mi);
1101
1102
0
    if (!resp) {
1103
0
        struct nvme_mi_mi_req_ctx *req = NULL;
1104
0
        const char *detail = NULL;
1105
0
        proto_item *cdw_it;
1106
0
        uint8_t opcode;
1107
1108
0
        if (len < 1) {
1109
0
            expert_add_info(pinfo, it, &ei_nvme_mi_mi_truncated);
1110
0
            return tvb_captured_length(tvb);
1111
0
        }
1112
1113
0
        proto_tree_add_item_ret_uint8(mi_tree, hf_nvme_mi_mi_opcode, tvb, 0, 1, ENC_NA, &opcode);
1114
1115
0
        if (len < 12) {
1116
0
            nvme_mi_mi_col_append(pinfo, opcode, NULL);
1117
0
            nvme_mi_mi_data_truncated(tvb, pinfo, mi_tree, it, 1);
1118
0
            return tvb_captured_length(tvb);
1119
0
        }
1120
1121
        /* The command dwords are present; persist the response-layout
1122
         * selectors for the response pass. */
1123
0
        if (trans)
1124
0
            req = nvme_mi_trans_body_ctx(trans, sizeof(*req));
1125
1126
0
        switch (opcode) {
1127
0
        case NVME_MI_MI_OPC_READ_DS: {
1128
0
            uint64_t cdw0;
1129
0
            uint8_t dtyp;
1130
1131
0
            cdw_it = proto_tree_add_bitmask_ret_uint64(mi_tree, tvb, 4,
1132
0
                    hf_nvme_mi_mi_cdw0, ett_nvme_mi_mi_field,
1133
0
                    rds_cdw0_fields, ENC_LITTLE_ENDIAN, &cdw0);
1134
0
            dtyp = (uint8_t)(cdw0 >> 24);
1135
0
            if (dtyp > NVME_MI_DTYP_MAX)
1136
0
                expert_add_info(pinfo, cdw_it, &ei_nvme_mi_mi_reserved_dtyp);
1137
0
            proto_tree_add_bitmask(mi_tree, tvb, 8, hf_nvme_mi_mi_cdw1,
1138
0
                                   ett_nvme_mi_mi_field, rds_cdw1_fields,
1139
0
                                   ENC_LITTLE_ENDIAN);
1140
0
            if (req)
1141
0
                req->dtyp = dtyp;
1142
0
            detail = val_to_str_const(dtyp, mi_dtyp_vals, "Reserved");
1143
0
            break;
1144
0
        }
1145
0
        case NVME_MI_MI_OPC_SUBSYS_HSP:
1146
            /* NMD0 is reserved for this command */
1147
0
            proto_tree_add_item(mi_tree, hf_nvme_mi_mi_cdw0,
1148
0
                                tvb, 4, 4, ENC_LITTLE_ENDIAN);
1149
0
            proto_tree_add_bitmask(mi_tree, tvb, 8, hf_nvme_mi_mi_cdw1,
1150
0
                                   ett_nvme_mi_mi_field, nshsp_cdw1_fields,
1151
0
                                   ENC_LITTLE_ENDIAN);
1152
0
            break;
1153
0
        case NVME_MI_MI_OPC_CTRL_HSP:
1154
0
            proto_tree_add_bitmask(mi_tree, tvb, 4, hf_nvme_mi_mi_cdw0,
1155
0
                                   ett_nvme_mi_mi_field, chsp_cdw0_fields,
1156
0
                                   ENC_LITTLE_ENDIAN);
1157
0
            proto_tree_add_bitmask(mi_tree, tvb, 8, hf_nvme_mi_mi_cdw1,
1158
0
                                   ett_nvme_mi_mi_field, chsp_cdw1_fields,
1159
0
                                   ENC_LITTLE_ENDIAN);
1160
0
            break;
1161
0
        case NVME_MI_MI_OPC_CONFIG_SET:
1162
0
        case NVME_MI_MI_OPC_CONFIG_GET: {
1163
            /* The CONFIGID value in NMD0 bits 7:0 selects the layout of the
1164
             * surrounding configuration-specific fields, so peek it before
1165
             * choosing which field array decodes the dword. */
1166
0
            uint8_t cid = tvb_get_uint8(tvb, 4);
1167
0
            int * const *f0 = cfg_cdw0_fields_cid;
1168
0
            int * const *f1 = NULL;
1169
1170
0
            switch (cid) {
1171
0
            case NVME_MI_CFGID_SMBUS_FREQ:
1172
0
                f0 = (opcode == NVME_MI_MI_OPC_CONFIG_SET)
1173
0
                         ? cfg_cdw0_fields_sfreq : cfg_cdw0_fields_port;
1174
0
                break;
1175
0
            case NVME_MI_CFGID_HSC:
1176
0
                if (opcode == NVME_MI_MI_OPC_CONFIG_SET)
1177
0
                    f1 = cfg_cdw1_fields_hsc;
1178
0
                break;
1179
0
            case NVME_MI_CFGID_MTUS:
1180
0
                f0 = cfg_cdw0_fields_port;
1181
0
                if (opcode == NVME_MI_MI_OPC_CONFIG_SET)
1182
0
                    f1 = cfg_cdw1_fields_mtus;
1183
0
                break;
1184
0
            case NVME_MI_CFGID_AE:
1185
0
                if (opcode == NVME_MI_MI_OPC_CONFIG_SET)
1186
0
                    f0 = cfg_cdw0_fields_ae_set;
1187
0
                break;
1188
0
            default:
1189
0
                break;
1190
0
            }
1191
1192
0
            cdw_it = proto_tree_add_bitmask(mi_tree, tvb, 4,
1193
0
                    hf_nvme_mi_mi_cdw0, ett_nvme_mi_mi_field, f0,
1194
0
                    ENC_LITTLE_ENDIAN);
1195
0
            if (cid == 0 || (cid >= NVME_MI_CFGID_RESERVED_FIRST &&
1196
0
                             cid <= NVME_MI_CFGID_RESERVED_LAST))
1197
0
                expert_add_info(pinfo, cdw_it,
1198
0
                                &ei_nvme_mi_mi_reserved_configid);
1199
0
            if (f1)
1200
0
                proto_tree_add_bitmask(mi_tree, tvb, 8, hf_nvme_mi_mi_cdw1,
1201
0
                                       ett_nvme_mi_mi_field, f1,
1202
0
                                       ENC_LITTLE_ENDIAN);
1203
0
            else
1204
0
                proto_tree_add_item(mi_tree, hf_nvme_mi_mi_cdw1,
1205
0
                                    tvb, 8, 4, ENC_LITTLE_ENDIAN);
1206
0
            if (req)
1207
0
                req->configid = cid;
1208
0
            detail = nvme_mi_mi_configid_name(cid);
1209
0
            break;
1210
0
        }
1211
0
        case NVME_MI_MI_OPC_VPD_READ:
1212
0
        case NVME_MI_MI_OPC_VPD_WRITE: {
1213
            /* DOFST in NMD0 bits 15:0, DLEN in NMD1 bits 15:0 (Figures
1214
             * 128/129 and 131/132 — identical layouts). */
1215
0
            uint64_t cdw0, cdw1;
1216
1217
0
            proto_tree_add_bitmask_ret_uint64(mi_tree, tvb, 4,
1218
0
                    hf_nvme_mi_mi_cdw0, ett_nvme_mi_mi_field,
1219
0
                    vpd_cdw0_fields, ENC_LITTLE_ENDIAN, &cdw0);
1220
0
            proto_tree_add_bitmask_ret_uint64(mi_tree, tvb, 8,
1221
0
                    hf_nvme_mi_mi_cdw1, ett_nvme_mi_mi_field,
1222
0
                    vpd_cdw1_fields, ENC_LITTLE_ENDIAN, &cdw1);
1223
0
            detail = wmem_strdup_printf(pinfo->pool, "offset %u, %u bytes",
1224
0
                                        (unsigned)(cdw0 & 0xFFFF),
1225
0
                                        (unsigned)(cdw1 & 0xFFFF));
1226
0
            break;
1227
0
        }
1228
0
        case NVME_MI_MI_OPC_RESET:
1229
0
            detail = nvme_mi_mi_dissect_typebyte_req(tvb, pinfo, mi_tree,
1230
0
                    reset_cdw0_fields, NVME_MI_RSTTYP_MAX, mi_rsttyp_vals);
1231
0
            break;
1232
0
        case NVME_MI_MI_OPC_SHUTDOWN:
1233
0
            detail = nvme_mi_mi_dissect_typebyte_req(tvb, pinfo, mi_tree,
1234
0
                    shutdown_cdw0_fields, NVME_MI_SHDNTYP_MAX,
1235
0
                    mi_shdntyp_vals);
1236
0
            break;
1237
0
        default:
1238
0
            proto_tree_add_item(mi_tree, hf_nvme_mi_mi_cdw0,
1239
0
                                tvb, 4, 4, ENC_LITTLE_ENDIAN);
1240
0
            proto_tree_add_item(mi_tree, hf_nvme_mi_mi_cdw1,
1241
0
                                tvb, 8, 4, ENC_LITTLE_ENDIAN);
1242
0
            break;
1243
0
        }
1244
1245
0
        nvme_mi_mi_col_append(pinfo, opcode, detail);
1246
1247
0
        if (len > 12) {
1248
            /* A few commands carry structured Request Data after the command
1249
             * dwords: a Configuration Set of the Asynchronous Event config
1250
             * sends an AE Enable List; VPD Write sends the VPD bytes (opaque,
1251
             * just labeled).  Everything else is an opaque blob. */
1252
0
            if (opcode == NVME_MI_MI_OPC_CONFIG_SET &&
1253
0
                tvb_get_uint8(tvb, 4) == NVME_MI_CFGID_AE) {
1254
0
                dissect_nvme_mi_mi_ae_enable_list(tvb, pinfo, mi_tree, it, 12,
1255
0
                                                  len - 12);
1256
0
            } else {
1257
0
                int data_hf = (opcode == NVME_MI_MI_OPC_VPD_WRITE)
1258
0
                              ? hf_nvme_mi_mi_vpd_data : hf_nvme_mi_mi_data;
1259
0
                proto_tree_add_item(mi_tree, data_hf, tvb, 12, -1, ENC_NA);
1260
0
            }
1261
0
        }
1262
0
    } else {
1263
        /* The response carries no opcode; recover it from the matching request
1264
         * (of this same NMIMT).  Without one, the helper notes an orphan
1265
         * response rather than fabricating an opcode-0 item. */
1266
0
        unsigned opcode;
1267
0
        it2 = nvme_mi_recover_resp_opcode(tvb, pinfo, mi_tree, it, trans,
1268
0
                                          NVME_MI_TYPE_MI, hf_nvme_mi_mi_opcode,
1269
0
                                          &ei_nvme_mi_mi_orphan_response,
1270
0
                                          &opcode);
1271
0
        bool opcode_known = (it2 != NULL);
1272
0
        const struct nvme_mi_mi_req_ctx *req = opcode_known
1273
0
                ? (const struct nvme_mi_mi_req_ctx *)trans->body_ctx : NULL;
1274
0
        const char *detail = NULL;
1275
0
        uint8_t status;
1276
1277
0
        if (opcode_known) {
1278
0
            if (req) {
1279
0
                if (opcode == NVME_MI_MI_OPC_READ_DS)
1280
0
                    detail = val_to_str_const(req->dtyp, mi_dtyp_vals,
1281
0
                                              "Reserved");
1282
0
                else if (opcode == NVME_MI_MI_OPC_CONFIG_SET ||
1283
0
                         opcode == NVME_MI_MI_OPC_CONFIG_GET)
1284
0
                    detail = nvme_mi_mi_configid_name(req->configid);
1285
0
            }
1286
0
            nvme_mi_mi_col_append(pinfo, opcode, detail);
1287
0
        }
1288
1289
0
        if (len < 1) {
1290
0
            expert_add_info(pinfo, it, &ei_nvme_mi_mi_truncated);
1291
0
            return tvb_captured_length(tvb);
1292
0
        }
1293
1294
0
        proto_tree_add_item_ret_uint8(mi_tree, hf_nvme_mi_mi_status,
1295
0
                                      tvb, 0, 1, ENC_NA, &status);
1296
1297
0
        if (len < 4) {
1298
0
            nvme_mi_mi_data_truncated(tvb, pinfo, mi_tree, it, 1);
1299
0
            return tvb_captured_length(tvb);
1300
0
        }
1301
1302
        /* The NVMe Management Response field and the Response Data are only
1303
         * defined for a Success Response.  On an error response those same
1304
         * bytes are the Parameter Error Location, the More Processing Required
1305
         * Time, or Reserved, so the shared helper owns them and NMRESP is not
1306
         * rendered over them (NVMe-MI 2.1 "Generic Error Response" /
1307
         * "Invalid Parameter Error Response Fields" / "More Processing
1308
         * Required Response Fields"). */
1309
0
        bool success = nvme_mi_dissect_resp_status_bytes(tvb, mi_tree, status);
1310
1311
0
        if (success)
1312
0
            proto_tree_add_item(mi_tree, hf_nvme_mi_mi_nmresp,
1313
0
                                tvb, 1, 3, ENC_LITTLE_ENDIAN);
1314
1315
0
        if (success && opcode_known) {
1316
0
            switch (opcode) {
1317
0
            case NVME_MI_MI_OPC_READ_DS:
1318
                /* NMRESP bits 15:0 = Response Data Length (Read NVMe-MI
1319
                 * Data Structure NVMe Management Response) */
1320
0
                proto_tree_add_item(mi_tree, hf_nvme_mi_mi_rds_rdl,
1321
0
                                    tvb, 1, 2, ENC_LITTLE_ENDIAN);
1322
0
                break;
1323
0
            case NVME_MI_MI_OPC_CTRL_HSP:
1324
                /* NMRESP bits 23:16 = Response Entries (Controller Health
1325
                 * Status Poll NVMe Management Response) */
1326
0
                proto_tree_add_item(mi_tree, hf_nvme_mi_mi_chsp_rent,
1327
0
                                    tvb, 3, 1, ENC_NA);
1328
0
                break;
1329
0
            case NVME_MI_MI_OPC_CONFIG_GET:
1330
0
                if (!req)
1331
0
                    break;
1332
0
                switch (req->configid) {
1333
0
                case NVME_MI_CFGID_SMBUS_FREQ:
1334
0
                    proto_tree_add_item(mi_tree, hf_nvme_mi_mi_cfg_sfreq_cur,
1335
0
                                        tvb, 1, 1, ENC_NA);
1336
0
                    break;
1337
0
                case NVME_MI_CFGID_MTUS:
1338
0
                    proto_tree_add_item(mi_tree, hf_nvme_mi_mi_cfg_mtus_cur,
1339
0
                                        tvb, 1, 2, ENC_LITTLE_ENDIAN);
1340
0
                    break;
1341
0
                case NVME_MI_CFGID_AE:
1342
0
                    proto_tree_add_item(mi_tree, hf_nvme_mi_mi_cfg_aeelver,
1343
0
                                        tvb, 1, 1, ENC_NA);
1344
0
                    break;
1345
0
                default:
1346
0
                    break;
1347
0
                }
1348
0
                break;
1349
0
            default:
1350
0
                break;
1351
0
            }
1352
0
        }
1353
1354
0
        if (len > 4) {
1355
0
            int dlen = (int)len - 4;
1356
1357
            /* Response Data is only defined for a Success response of a known
1358
             * opcode; everything else (errors, MPR, orphan) renders raw. */
1359
0
            if (success && opcode_known) {
1360
0
                switch (opcode) {
1361
0
                case NVME_MI_MI_OPC_READ_DS:
1362
                    /* The request's DTYP selects the structure layout; without
1363
                     * it (truncated request) fall back to raw. */
1364
0
                    if (!req) {
1365
0
                        proto_tree_add_item(mi_tree, hf_nvme_mi_mi_data,
1366
0
                                            tvb, 4, -1, ENC_NA);
1367
0
                        break;
1368
0
                    }
1369
0
                    switch (req->dtyp) {
1370
0
                    case NVME_MI_DTYP_SUBSYS_INFO:
1371
0
                        nvme_mi_mi_data_subsys_info(tvb, pinfo, mi_tree, it,
1372
0
                                                    4, dlen);
1373
0
                        break;
1374
0
                    case NVME_MI_DTYP_PORT_INFO:
1375
0
                        nvme_mi_mi_data_port_info(tvb, pinfo, mi_tree, it,
1376
0
                                                  4, dlen);
1377
0
                        break;
1378
0
                    case NVME_MI_DTYP_CTRL_LIST:
1379
0
                        nvme_mi_mi_data_ctrl_list(tvb, pinfo, mi_tree, it,
1380
0
                                                  4, dlen);
1381
0
                        break;
1382
0
                    case NVME_MI_DTYP_CTRL_INFO:
1383
0
                        nvme_mi_mi_data_ctrl_info(tvb, pinfo, mi_tree, it,
1384
0
                                                  4, dlen);
1385
0
                        break;
1386
0
                    case NVME_MI_DTYP_OSC_LIST:
1387
0
                    case NVME_MI_DTYP_MEB_LIST:
1388
0
                        nvme_mi_mi_data_cmd_list(tvb, pinfo, mi_tree, it,
1389
0
                                                 4, dlen);
1390
0
                        break;
1391
0
                    default:
1392
0
                        proto_tree_add_item(mi_tree, hf_nvme_mi_mi_data,
1393
0
                                            tvb, 4, -1, ENC_NA);
1394
0
                        break;
1395
0
                    }
1396
0
                    break;
1397
0
                case NVME_MI_MI_OPC_SUBSYS_HSP:
1398
0
                    nvme_mi_mi_data_nshds(tvb, pinfo, mi_tree, it, 4, dlen);
1399
0
                    break;
1400
0
                case NVME_MI_MI_OPC_CTRL_HSP:
1401
0
                    nvme_mi_mi_data_chds_list(tvb, pinfo, mi_tree, it, 4, dlen);
1402
0
                    break;
1403
0
                case NVME_MI_MI_OPC_CONFIG_GET:
1404
                    /* Only the Asynchronous Event configuration returns
1405
                     * Response Data: the AE Supported List. */
1406
0
                    if (req && req->configid == NVME_MI_CFGID_AE)
1407
0
                        dissect_nvme_mi_mi_ae_supported_list(tvb, pinfo,
1408
0
                                mi_tree, it, 4, dlen);
1409
0
                    else
1410
0
                        proto_tree_add_item(mi_tree, hf_nvme_mi_mi_data,
1411
0
                                            tvb, 4, -1, ENC_NA);
1412
0
                    break;
1413
0
                case NVME_MI_MI_OPC_VPD_READ:
1414
                    /* Response Data is the requested window of VPD bytes
1415
                     * (the "VPD Read Response Data" figure). */
1416
0
                    proto_tree_add_item(mi_tree, hf_nvme_mi_mi_vpd_data,
1417
0
                                        tvb, 4, -1, ENC_NA);
1418
0
                    break;
1419
0
                default:
1420
0
                    proto_tree_add_item(mi_tree, hf_nvme_mi_mi_data,
1421
0
                                        tvb, 4, -1, ENC_NA);
1422
0
                    break;
1423
0
                }
1424
0
            } else {
1425
0
                proto_tree_add_item(mi_tree, hf_nvme_mi_mi_data,
1426
0
                                    tvb, 4, -1, ENC_NA);
1427
0
            }
1428
0
        }
1429
0
    }
1430
1431
0
    return tvb_captured_length(tvb);
1432
0
}
1433
1434
static int
1435
dissect_nvme_mi_mi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1436
                   void *data)
1437
0
{
1438
0
    struct nvme_mi_dissect_ctx *ctx = (struct nvme_mi_dissect_ctx *)data;
1439
1440
0
    if (!ctx)
1441
0
        return 0;
1442
1443
0
    return dissect_nvme_mi_mi_body(tvb, pinfo, tree, ctx->resp, ctx->trans);
1444
0
}
1445
1446
void
1447
proto_register_nvme_mi_mi(void)
1448
16
{
1449
    /* *INDENT-OFF* */
1450
16
    static hf_register_info hf[] = {
1451
16
        { &hf_nvme_mi_mi_opcode,
1452
16
          { "Opcode", "nvme-mi.mi.opcode",
1453
16
            FT_UINT8, BASE_HEX | BASE_RANGE_STRING, RVALS(mi_opcode_vals), 0,
1454
16
            NULL, HFILL },
1455
16
        },
1456
16
        { &hf_nvme_mi_mi_cdw0,
1457
16
          { "Command dword 0", "nvme-mi.mi.cdw0",
1458
16
            FT_UINT32, BASE_HEX, NULL, 0,
1459
16
            "NVMe Management Dword 0 (NMD0)", HFILL },
1460
16
        },
1461
16
        { &hf_nvme_mi_mi_cdw1,
1462
16
          { "Command dword 1", "nvme-mi.mi.cdw1",
1463
16
            FT_UINT32, BASE_HEX, NULL, 0,
1464
16
            "NVMe Management Dword 1 (NMD1)", HFILL },
1465
16
        },
1466
16
        { &hf_nvme_mi_mi_status,
1467
16
          { "Status", "nvme-mi.mi.status",
1468
16
            FT_UINT8, BASE_HEX | BASE_RANGE_STRING, RVALS(nvme_mi_status_vals), 0,
1469
16
            "Response Message Status (NVMe-MI 2.1 'Response Message"
1470
16
            " Status Values')", HFILL },
1471
16
        },
1472
16
        { &hf_nvme_mi_mi_nmresp,
1473
16
          { "Management Response", "nvme-mi.mi.nmresp",
1474
16
            FT_UINT24, BASE_HEX, NULL, 0,
1475
16
            NULL, HFILL },
1476
16
        },
1477
16
        { &hf_nvme_mi_mi_data,
1478
16
          { "Data", "nvme-mi.mi.data",
1479
16
            FT_BYTES, SEP_SPACE, NULL, 0,
1480
16
            NULL, HFILL },
1481
16
        },
1482
1483
        /* Read NVMe-MI Data Structure (00h) */
1484
16
        { &hf_nvme_mi_mi_rds_dtyp,
1485
16
          { "Data Structure Type (DTYP)", "nvme-mi.mi.rds.dtyp",
1486
16
            FT_UINT32, BASE_HEX, VALS(mi_dtyp_vals), 0xFF000000,
1487
16
            "Data structure to return", HFILL },
1488
16
        },
1489
16
        { &hf_nvme_mi_mi_rds_portid,
1490
16
          { "Port Identifier (PORTID)", "nvme-mi.mi.rds.portid",
1491
16
            FT_UINT32, BASE_DEC, NULL, 0x00FF0000,
1492
16
            "Port whose data structure is returned (DTYP 01h/05h)", HFILL },
1493
16
        },
1494
16
        { &hf_nvme_mi_mi_rds_ctrlid,
1495
16
          { "Controller Identifier (CTRLID)", "nvme-mi.mi.rds.ctrlid",
1496
16
            FT_UINT32, BASE_HEX, NULL, 0x0000FFFF,
1497
16
            "Controller whose data structure is returned (DTYP 02h-04h)",
1498
16
            HFILL },
1499
16
        },
1500
16
        { &hf_nvme_mi_mi_rds_iocsi,
1501
16
          { "I/O Command Set Identifier (IOCSI)", "nvme-mi.mi.rds.iocsi",
1502
16
            FT_UINT32, BASE_HEX, NULL, 0x000000FF,
1503
16
            "Selects the I/O Command Set for Admin entries (DTYP 04h/05h)",
1504
16
            HFILL },
1505
16
        },
1506
16
        { &hf_nvme_mi_mi_rds_rdl,
1507
16
          { "Response Data Length (RDL)", "nvme-mi.mi.rds.rdl",
1508
16
            FT_UINT16, BASE_DEC, NULL, 0,
1509
16
            "Length in bytes of the Response Data field",
1510
16
            HFILL },
1511
16
        },
1512
1513
        /* NVM Subsystem Health Status Poll (01h) */
1514
16
        { &hf_nvme_mi_mi_nshsp_cs,
1515
16
          { "Clear Status (CS)", "nvme-mi.mi.nshsp.cs",
1516
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x80000000,
1517
16
            "Clear the Composite Controller Status Flags after copying them"
1518
16
            " into the response", HFILL },
1519
16
        },
1520
1521
        /* Controller Health Status Poll (02h) */
1522
16
        { &hf_nvme_mi_mi_chsp_all,
1523
16
          { "Report All (ALL)", "nvme-mi.mi.chsp.all",
1524
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x80000000,
1525
16
            "Ignore the error selection bits when selecting Controllers",
1526
16
            HFILL },
1527
16
        },
1528
16
        { &hf_nvme_mi_mi_chsp_incvf,
1529
16
          { "Include SR-IOV Virtual Functions (INCVF)", "nvme-mi.mi.chsp.incvf",
1530
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x04000000,
1531
16
            NULL, HFILL },
1532
16
        },
1533
16
        { &hf_nvme_mi_mi_chsp_incpf,
1534
16
          { "Include SR-IOV Physical Functions (INCPF)", "nvme-mi.mi.chsp.incpf",
1535
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x02000000,
1536
16
            NULL, HFILL },
1537
16
        },
1538
16
        { &hf_nvme_mi_mi_chsp_incf,
1539
16
          { "Include PCI Functions (INCF)", "nvme-mi.mi.chsp.incf",
1540
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x01000000,
1541
16
            NULL, HFILL },
1542
16
        },
1543
16
        { &hf_nvme_mi_mi_chsp_maxrent,
1544
16
          { "Maximum Response Entries (MAXRENT)", "nvme-mi.mi.chsp.maxrent",
1545
16
            FT_UINT32, BASE_DEC, NULL, 0x00FF0000,
1546
16
            "Maximum number of CHDS entries to return, 0's based", HFILL },
1547
16
        },
1548
16
        { &hf_nvme_mi_mi_chsp_sctlid,
1549
16
          { "Starting Controller ID (SCTLID)", "nvme-mi.mi.chsp.sctlid",
1550
16
            FT_UINT32, BASE_HEX, NULL, 0x0000FFFF,
1551
16
            NULL, HFILL },
1552
16
        },
1553
16
        { &hf_nvme_mi_mi_chsp_ccf,
1554
16
          { "Clear Changed Flags (CCF)", "nvme-mi.mi.chsp.ccf",
1555
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x80000000,
1556
16
            "Copy then clear each returned Controller's Health Status"
1557
16
            " Changed Flags", HFILL },
1558
16
        },
1559
16
        { &hf_nvme_mi_mi_chsp_cwarn,
1560
16
          { "Select on Critical Warning (CWARN)", "nvme-mi.mi.chsp.cwarn",
1561
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x00000010,
1562
16
            NULL, HFILL },
1563
16
        },
1564
16
        { &hf_nvme_mi_mi_chsp_spare,
1565
16
          { "Select on Available Spare (SPARE)", "nvme-mi.mi.chsp.spare",
1566
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x00000008,
1567
16
            NULL, HFILL },
1568
16
        },
1569
16
        { &hf_nvme_mi_mi_chsp_pdlu,
1570
16
          { "Select on Percentage Used (PDLU)", "nvme-mi.mi.chsp.pdlu",
1571
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x00000004,
1572
16
            NULL, HFILL },
1573
16
        },
1574
16
        { &hf_nvme_mi_mi_chsp_ctemp,
1575
16
          { "Select on Composite Temperature Changes (CTEMP)",
1576
16
            "nvme-mi.mi.chsp.ctemp",
1577
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x00000002,
1578
16
            NULL, HFILL },
1579
16
        },
1580
16
        { &hf_nvme_mi_mi_chsp_csts,
1581
16
          { "Select on Controller Status Changes (CSTS)",
1582
16
            "nvme-mi.mi.chsp.csts",
1583
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x00000001,
1584
16
            NULL, HFILL },
1585
16
        },
1586
16
        { &hf_nvme_mi_mi_chsp_rent,
1587
16
          { "Response Entries (RENT)", "nvme-mi.mi.chsp.rent",
1588
16
            FT_UINT8, BASE_DEC, NULL, 0,
1589
16
            "Number of CHDS entries in the Response Data",
1590
16
            HFILL },
1591
16
        },
1592
1593
        /* Configuration Set (03h) / Configuration Get (04h) */
1594
16
        { &hf_nvme_mi_mi_cfg_cid,
1595
16
          { "Configuration Identifier (CID)", "nvme-mi.mi.config.cid",
1596
16
            FT_UINT32, BASE_HEX | BASE_RANGE_STRING, RVALS(mi_configid_vals), 0x000000FF,
1597
16
            "Configuration being read or written (NVMe-MI 2.1 'NVMe"
1598
16
            " Management Interface Configuration Identifiers')", HFILL },
1599
16
        },
1600
16
        { &hf_nvme_mi_mi_cfg_portid,
1601
16
          { "Port Identifier (PORTID)", "nvme-mi.mi.config.portid",
1602
16
            FT_UINT32, BASE_DEC, NULL, 0xFF000000,
1603
16
            NULL, HFILL },
1604
16
        },
1605
16
        { &hf_nvme_mi_mi_cfg_sfreq,
1606
16
          { "SMBus/I2C Frequency (SFREQ)", "nvme-mi.mi.config.sfreq",
1607
16
            FT_UINT32, BASE_HEX, VALS(mi_sfreq_vals), 0x00000F00,
1608
16
            "New frequency for the 2-Wire port", HFILL },
1609
16
        },
1610
16
        { &hf_nvme_mi_mi_cfg_mtus,
1611
16
          { "MCTP Transmission Unit Size (MTUS)", "nvme-mi.mi.config.mtus",
1612
16
            FT_UINT32, BASE_DEC, NULL, 0x0000FFFF,
1613
16
            "Requested MCTP Transmission Unit Size in bytes",
1614
16
            HFILL },
1615
16
        },
1616
16
        { &hf_nvme_mi_mi_cfg_sfreq_cur,
1617
16
          { "Current SMBus/I2C Frequency (SFREQ)",
1618
16
            "nvme-mi.mi.config.sfreq_cur",
1619
16
            FT_UINT8, BASE_HEX, VALS(mi_sfreq_vals), 0x0F,
1620
16
            "Current 2-Wire frequency", HFILL },
1621
16
        },
1622
16
        { &hf_nvme_mi_mi_cfg_mtus_cur,
1623
16
          { "Current MCTP Transmission Unit Size (MTUS)",
1624
16
            "nvme-mi.mi.config.mtus_cur",
1625
16
            FT_UINT16, BASE_DEC, NULL, 0,
1626
16
            "Current MCTP Transmission Unit Size in bytes",
1627
16
            HFILL },
1628
16
        },
1629
16
        { &hf_nvme_mi_mi_cfg_aeelver,
1630
16
          { "AE Enable List Version Number (AEELVER)",
1631
16
            "nvme-mi.mi.config.aeelver",
1632
16
            FT_UINT8, BASE_HEX, NULL, 0,
1633
16
            "Version of the AE Enable List data structure",
1634
16
            HFILL },
1635
16
        },
1636
16
        { &hf_nvme_mi_mi_cfg_hsc_tcida,
1637
16
          { "Clear Telemetry Controller-Initiated Data Available (TCIDA)",
1638
16
            "nvme-mi.mi.config.hsc.tcida",
1639
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x00001000,
1640
16
            NULL, HFILL },
1641
16
        },
1642
16
        { &hf_nvme_mi_mi_cfg_hsc_cwarn,
1643
16
          { "Clear Critical Warning (CWARN)", "nvme-mi.mi.config.hsc.cwarn",
1644
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x00000800,
1645
16
            NULL, HFILL },
1646
16
        },
1647
16
        { &hf_nvme_mi_mi_cfg_hsc_spare,
1648
16
          { "Clear Available Spare (SPARE)", "nvme-mi.mi.config.hsc.spare",
1649
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x00000400,
1650
16
            NULL, HFILL },
1651
16
        },
1652
16
        { &hf_nvme_mi_mi_cfg_hsc_pdlu,
1653
16
          { "Clear Percentage Used (PDLU)", "nvme-mi.mi.config.hsc.pdlu",
1654
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x00000200,
1655
16
            NULL, HFILL },
1656
16
        },
1657
16
        { &hf_nvme_mi_mi_cfg_hsc_ctemp,
1658
16
          { "Clear Composite Temperature (CTEMP)",
1659
16
            "nvme-mi.mi.config.hsc.ctemp",
1660
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x00000100,
1661
16
            NULL, HFILL },
1662
16
        },
1663
16
        { &hf_nvme_mi_mi_cfg_hsc_cschng,
1664
16
          { "Clear Controller Status Change (CSCHNG)",
1665
16
            "nvme-mi.mi.config.hsc.cschng",
1666
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x00000080,
1667
16
            NULL, HFILL },
1668
16
        },
1669
16
        { &hf_nvme_mi_mi_cfg_hsc_fa,
1670
16
          { "Clear Firmware Activated (FA)", "nvme-mi.mi.config.hsc.fa",
1671
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x00000040,
1672
16
            NULL, HFILL },
1673
16
        },
1674
16
        { &hf_nvme_mi_mi_cfg_hsc_nac,
1675
16
          { "Clear Namespace Attribute Changed (NAC)",
1676
16
            "nvme-mi.mi.config.hsc.nac",
1677
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x00000020,
1678
16
            NULL, HFILL },
1679
16
        },
1680
16
        { &hf_nvme_mi_mi_cfg_hsc_ceco,
1681
16
          { "Clear Controller Enable Change Occurred (CECO)",
1682
16
            "nvme-mi.mi.config.hsc.ceco",
1683
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x00000010,
1684
16
            NULL, HFILL },
1685
16
        },
1686
16
        { &hf_nvme_mi_mi_cfg_hsc_nssro,
1687
16
          { "Clear NVM Subsystem Reset Occurred (NSSRO)",
1688
16
            "nvme-mi.mi.config.hsc.nssro",
1689
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x00000008,
1690
16
            NULL, HFILL },
1691
16
        },
1692
16
        { &hf_nvme_mi_mi_cfg_hsc_shst,
1693
16
          { "Clear Shutdown Status (SHST)", "nvme-mi.mi.config.hsc.shst",
1694
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x00000004,
1695
16
            NULL, HFILL },
1696
16
        },
1697
16
        { &hf_nvme_mi_mi_cfg_hsc_cfs,
1698
16
          { "Clear Controller Fatal Status (CFS)",
1699
16
            "nvme-mi.mi.config.hsc.cfs",
1700
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x00000002,
1701
16
            NULL, HFILL },
1702
16
        },
1703
16
        { &hf_nvme_mi_mi_cfg_hsc_rdy,
1704
16
          { "Clear Ready (RDY)", "nvme-mi.mi.config.hsc.rdy",
1705
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x00000001,
1706
16
            NULL, HFILL },
1707
16
        },
1708
1709
        /* VPD Read (05h) / VPD Write (06h) */
1710
16
        { &hf_nvme_mi_mi_vpd_dofst,
1711
16
          { "Data Offset (DOFST)", "nvme-mi.mi.vpd.dofst",
1712
16
            FT_UINT32, BASE_DEC, NULL, 0x0000FFFF,
1713
16
            "Starting byte offset into the VPD", HFILL },
1714
16
        },
1715
16
        { &hf_nvme_mi_mi_vpd_dlen,
1716
16
          { "Data Length (DLEN)", "nvme-mi.mi.vpd.dlen",
1717
16
            FT_UINT32, BASE_DEC, NULL, 0x0000FFFF,
1718
16
            "Length in bytes to read from or write to the VPD", HFILL },
1719
16
        },
1720
16
        { &hf_nvme_mi_mi_vpd_data,
1721
16
          { "VPD Data", "nvme-mi.mi.vpd.data",
1722
16
            FT_BYTES, SEP_SPACE, NULL, 0,
1723
16
            "VPD contents transferred by the command (NVMe-MI 2.1 'VPD"
1724
16
            " Read Response Data' / 'VPD Write Request Data')",
1725
16
            HFILL },
1726
16
        },
1727
1728
        /* Configuration Set (03h) Asynchronous Event — command dword 0 */
1729
16
        { &hf_nvme_mi_mi_cfg_ae_envfa,
1730
16
          { "Enable SR-IOV Virtual Functions AE (ENVFA)",
1731
16
            "nvme-mi.mi.config.ae.envfa",
1732
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x04000000,
1733
16
            NULL, HFILL },
1734
16
        },
1735
16
        { &hf_nvme_mi_mi_cfg_ae_enpfa,
1736
16
          { "Enable SR-IOV Physical Functions AE (ENPFA)",
1737
16
            "nvme-mi.mi.config.ae.enpfa",
1738
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x02000000,
1739
16
            NULL, HFILL },
1740
16
        },
1741
16
        { &hf_nvme_mi_mi_cfg_ae_encfa,
1742
16
          { "Enable PCI Functions AE (ENCFA)", "nvme-mi.mi.config.ae.encfa",
1743
16
            FT_BOOLEAN, 32, TFS(&tfs_set_notset), 0x01000000,
1744
16
            NULL, HFILL },
1745
16
        },
1746
16
        { &hf_nvme_mi_mi_cfg_ae_aemd,
1747
16
          { "AEM Delay (AEMD)", "nvme-mi.mi.config.ae.aemd",
1748
16
            FT_UINT32, BASE_DEC, NULL, 0x00FF0000,
1749
16
            "Delay in seconds before an AEM is transmitted",
1750
16
            HFILL },
1751
16
        },
1752
16
        { &hf_nvme_mi_mi_cfg_ae_aerd,
1753
16
          { "AEM Retry Delay (AERD)", "nvme-mi.mi.config.ae.aerd",
1754
16
            FT_UINT32, BASE_DEC, NULL, 0x0000FF00,
1755
16
            "Delay in 100 ms units between AEM retransmissions",
1756
16
            HFILL },
1757
16
        },
1758
1759
        /* Configuration Set (03h) Asynchronous Event — AE Enable List */
1760
16
        { &hf_nvme_mi_mi_ae,
1761
16
          { "AE Enable List", "nvme-mi.mi.ae",
1762
16
            FT_BYTES, BASE_NONE, NULL, 0,
1763
16
            "Asynchronous Event Enable List request data (NVMe-MI 2.1"
1764
16
            " 'AE Enable List Data Structure')", HFILL },
1765
16
        },
1766
16
        { &hf_nvme_mi_mi_ae_numaee,
1767
16
          { "Number of AE Enable Data Structures (NUMAEE)", "nvme-mi.mi.ae.numaee",
1768
16
            FT_UINT8, BASE_DEC, NULL, 0,
1769
16
            NULL, HFILL },
1770
16
        },
1771
16
        { &hf_nvme_mi_mi_ae_aeelver,
1772
16
          { "AE Enable List Version (AEELVER)", "nvme-mi.mi.ae.aeelver",
1773
16
            FT_UINT8, BASE_DEC, NULL, 0,
1774
16
            NULL, HFILL },
1775
16
        },
1776
16
        { &hf_nvme_mi_mi_ae_aeetl,
1777
16
          { "AE Enable Total Length (AEETL)", "nvme-mi.mi.ae.aeetl",
1778
16
            FT_UINT16, BASE_DEC, NULL, 0,
1779
16
            NULL, HFILL },
1780
16
        },
1781
16
        { &hf_nvme_mi_mi_ae_aeelhl,
1782
16
          { "AE Enable List Header Length (AEELHL)", "nvme-mi.mi.ae.aeelhl",
1783
16
            FT_UINT8, BASE_DEC, NULL, 0,
1784
16
            NULL, HFILL },
1785
16
        },
1786
16
        { &hf_nvme_mi_mi_ae_entry,
1787
16
          { "AE Enable", "nvme-mi.mi.ae.entry",
1788
16
            FT_BYTES, BASE_NONE, NULL, 0,
1789
16
            "AE Enable data structure", HFILL },
1790
16
        },
1791
16
        { &hf_nvme_mi_mi_ae_aeel,
1792
16
          { "AE Enable Length (AEEL)", "nvme-mi.mi.ae.aeel",
1793
16
            FT_UINT8, BASE_DEC, NULL, 0,
1794
16
            NULL, HFILL },
1795
16
        },
1796
16
        { &hf_nvme_mi_mi_ae_aee,
1797
16
          { "AE Enable (AEE)", "nvme-mi.mi.ae.aee",
1798
16
            FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x8000,
1799
16
            "Enable (1) or disable (0) the indicated asynchronous event", HFILL },
1800
16
        },
1801
16
        { &hf_nvme_mi_mi_ae_id,
1802
16
          { "AE Enable ID", "nvme-mi.mi.ae.id",
1803
16
            FT_UINT16, BASE_HEX | BASE_RANGE_STRING, RVALS(mi_ae_id_vals), 0x00FF,
1804
16
            "Identifier of the asynchronous event (NVMe-MI 2.1"
1805
16
            " 'Asynchronous Events')", HFILL },
1806
16
        },
1807
1808
        /* Configuration Get (04h) Asynchronous Event — AE Supported List */
1809
16
        { &hf_nvme_mi_mi_aes,
1810
16
          { "AE Supported List", "nvme-mi.mi.aes",
1811
16
            FT_BYTES, BASE_NONE, NULL, 0,
1812
16
            "Asynchronous Event Supported List response data (NVMe-MI 2.1"
1813
16
            " 'AE Supported List Data Structure')",
1814
16
            HFILL },
1815
16
        },
1816
16
        { &hf_nvme_mi_mi_aes_numaes,
1817
16
          { "Number of AE Supported Data Structures (NUMAES)",
1818
16
            "nvme-mi.mi.aes.numaes",
1819
16
            FT_UINT8, BASE_DEC, NULL, 0,
1820
16
            NULL, HFILL },
1821
16
        },
1822
16
        { &hf_nvme_mi_mi_aes_aeslver,
1823
16
          { "AE Supported List Version (AESLVER)", "nvme-mi.mi.aes.aeslver",
1824
16
            FT_UINT8, BASE_DEC, NULL, 0,
1825
16
            NULL, HFILL },
1826
16
        },
1827
16
        { &hf_nvme_mi_mi_aes_aestl,
1828
16
          { "AE Supported Total Length (AESTL)", "nvme-mi.mi.aes.aestl",
1829
16
            FT_UINT16, BASE_DEC, NULL, 0,
1830
16
            NULL, HFILL },
1831
16
        },
1832
16
        { &hf_nvme_mi_mi_aes_aeslhl,
1833
16
          { "AE Supported List Header Length (AESLHL)",
1834
16
            "nvme-mi.mi.aes.aeslhl",
1835
16
            FT_UINT8, BASE_DEC, NULL, 0,
1836
16
            NULL, HFILL },
1837
16
        },
1838
16
        { &hf_nvme_mi_mi_aes_entry,
1839
16
          { "AE Supported", "nvme-mi.mi.aes.entry",
1840
16
            FT_BYTES, BASE_NONE, NULL, 0,
1841
16
            "AE Supported data structure", HFILL },
1842
16
        },
1843
16
        { &hf_nvme_mi_mi_aes_aesl,
1844
16
          { "AE Supported Length (AESL)", "nvme-mi.mi.aes.aesl",
1845
16
            FT_UINT8, BASE_DEC, NULL, 0,
1846
16
            NULL, HFILL },
1847
16
        },
1848
16
        { &hf_nvme_mi_mi_aes_aese,
1849
16
          { "AE Supported Enable (AESE)", "nvme-mi.mi.aes.aese",
1850
16
            FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x8000,
1851
16
            "The indicated asynchronous event is currently enabled", HFILL },
1852
16
        },
1853
16
        { &hf_nvme_mi_mi_aes_id,
1854
16
          { "AE Supported ID", "nvme-mi.mi.aes.id",
1855
16
            FT_UINT16, BASE_HEX | BASE_RANGE_STRING, RVALS(mi_ae_id_vals), 0x00FF,
1856
16
            "Identifier of the asynchronous event (NVMe-MI 2.1"
1857
16
            " 'Asynchronous Events')", HFILL },
1858
16
        },
1859
1860
        /* Reset (07h) */
1861
16
        { &hf_nvme_mi_mi_reset_rsttyp,
1862
16
          { "Reset Type (RSTTYP)", "nvme-mi.mi.reset.rsttyp",
1863
16
            FT_UINT32, BASE_HEX, VALS(mi_rsttyp_vals), 0xFF000000,
1864
16
            "Type of reset to perform", HFILL },
1865
16
        },
1866
1867
        /* Shutdown (0Ch) */
1868
16
        { &hf_nvme_mi_mi_shutdown_shdntyp,
1869
16
          { "Shutdown Type (SHDNTYP)", "nvme-mi.mi.shutdown.shdntyp",
1870
16
            FT_UINT32, BASE_HEX, VALS(mi_shdntyp_vals), 0xFF000000,
1871
16
            "Type of shutdown to perform", HFILL },
1872
16
        },
1873
1874
        /* NVM Subsystem Information (DTYP 00h) */
1875
16
        { &hf_nvme_mi_mi_subsys_nump,
1876
16
          { "Number of Ports (NUMP)", "nvme-mi.mi.subsys.nump",
1877
16
            FT_UINT8, BASE_DEC, NULL, 0,
1878
16
            "Maximum number of ports supported, 0's based", HFILL },
1879
16
        },
1880
16
        { &hf_nvme_mi_mi_subsys_mjr,
1881
16
          { "NVMe-MI Major Version Number (MJR)", "nvme-mi.mi.subsys.mjr",
1882
16
            FT_UINT8, BASE_DEC, NULL, 0,
1883
16
            NULL, HFILL },
1884
16
        },
1885
16
        { &hf_nvme_mi_mi_subsys_mnr,
1886
16
          { "NVMe-MI Minor Version Number (MNR)", "nvme-mi.mi.subsys.mnr",
1887
16
            FT_UINT8, BASE_DEC, NULL, 0,
1888
16
            NULL, HFILL },
1889
16
        },
1890
16
        { &hf_nvme_mi_mi_subsys_nnsc,
1891
16
          { "NVM Subsystem Capabilities (NNSC)", "nvme-mi.mi.subsys.nnsc",
1892
16
            FT_UINT8, BASE_HEX, NULL, 0,
1893
16
            NULL, HFILL },
1894
16
        },
1895
16
        { &hf_nvme_mi_mi_subsys_sre,
1896
16
          { "Status Reporting Enhancements (SRE)", "nvme-mi.mi.subsys.sre",
1897
16
            FT_BOOLEAN, 8, TFS(&tfs_supported_not_supported), 0x01,
1898
16
            NULL, HFILL },
1899
16
        },
1900
1901
        /* Port Information (DTYP 01h) */
1902
16
        { &hf_nvme_mi_mi_port_prttyp,
1903
16
          { "Port Type (PRTTYP)", "nvme-mi.mi.port.prttyp",
1904
16
            FT_UINT8, BASE_HEX, VALS(mi_prttyp_vals), 0,
1905
16
            NULL, HFILL },
1906
16
        },
1907
16
        { &hf_nvme_mi_mi_port_prtcap,
1908
16
          { "Port Capabilities (PRTCAP)", "nvme-mi.mi.port.prtcap",
1909
16
            FT_UINT8, BASE_HEX, NULL, 0,
1910
16
            NULL, HFILL },
1911
16
        },
1912
16
        { &hf_nvme_mi_mi_port_aems,
1913
16
          { "Asynchronous Event Messages Supported (AEMS)",
1914
16
            "nvme-mi.mi.port.aems",
1915
16
            FT_BOOLEAN, 8, TFS(&tfs_supported_not_supported), 0x02,
1916
16
            NULL, HFILL },
1917
16
        },
1918
16
        { &hf_nvme_mi_mi_port_ciaps,
1919
16
          { "Command Initiated Auto Pause Supported (CIAPS)",
1920
16
            "nvme-mi.mi.port.ciaps",
1921
16
            FT_BOOLEAN, 8, TFS(&tfs_supported_not_supported), 0x01,
1922
16
            NULL, HFILL },
1923
16
        },
1924
16
        { &hf_nvme_mi_mi_port_mmtus,
1925
16
          { "Maximum MCTP Transmission Unit Size (MMTUS)",
1926
16
            "nvme-mi.mi.port.mmtus",
1927
16
            FT_UINT16, BASE_DEC, NULL, 0,
1928
16
            NULL, HFILL },
1929
16
        },
1930
16
        { &hf_nvme_mi_mi_port_mebs,
1931
16
          { "Management Endpoint Buffer Size (MEBS)", "nvme-mi.mi.port.mebs",
1932
16
            FT_UINT32, BASE_DEC, NULL, 0,
1933
16
            "Size in bytes; 0 = no Management Endpoint Buffer", HFILL },
1934
16
        },
1935
16
        { &hf_nvme_mi_mi_port_pcie_mps,
1936
16
          { "PCIe Maximum Payload Size (PCIEMPS)", "nvme-mi.mi.port.pcie.mps",
1937
16
            FT_UINT8, BASE_HEX, VALS(mi_pciemps_vals), 0,
1938
16
            NULL, HFILL },
1939
16
        },
1940
16
        { &hf_nvme_mi_mi_port_pcie_slsv,
1941
16
          { "PCIe Supported Link Speeds Vector (PCIESLSV)",
1942
16
            "nvme-mi.mi.port.pcie.slsv",
1943
16
            FT_UINT8, BASE_HEX, NULL, 0,
1944
16
            "Bit 0 = 2.5, 1 = 5.0, 2 = 8.0, 3 = 16.0, 4 = 32.0, 5 = 64.0 GT/s",
1945
16
            HFILL },
1946
16
        },
1947
16
        { &hf_nvme_mi_mi_port_pcie_cls,
1948
16
          { "PCIe Current Link Speed (PCIECLS)", "nvme-mi.mi.port.pcie.cls",
1949
16
            FT_UINT8, BASE_HEX, VALS(mi_pciecls_vals), 0,
1950
16
            NULL, HFILL },
1951
16
        },
1952
16
        { &hf_nvme_mi_mi_port_pcie_mlw,
1953
16
          { "PCIe Maximum Link Width (PCIEMLW)", "nvme-mi.mi.port.pcie.mlw",
1954
16
            FT_UINT8, BASE_DEC, NULL, 0,
1955
16
            "Maximum link width in lanes", HFILL },
1956
16
        },
1957
16
        { &hf_nvme_mi_mi_port_pcie_nlw,
1958
16
          { "PCIe Negotiated Link Width (PCIENLW)", "nvme-mi.mi.port.pcie.nlw",
1959
16
            FT_UINT8, BASE_DEC, NULL, 0,
1960
16
            "Negotiated link width in lanes; 0 = link not active", HFILL },
1961
16
        },
1962
16
        { &hf_nvme_mi_mi_port_pcie_pn,
1963
16
          { "PCIe Port Number (PCIEPN)", "nvme-mi.mi.port.pcie.pn",
1964
16
            FT_UINT8, BASE_DEC, NULL, 0,
1965
16
            NULL, HFILL },
1966
16
        },
1967
16
        { &hf_nvme_mi_mi_port_twire_cvpdaddr,
1968
16
          { "Current VPD Address (CVPDADDR)", "nvme-mi.mi.port.cvpdaddr",
1969
16
            FT_UINT8, BASE_HEX, NULL, 0,
1970
16
            "Current VPD SMBus/I2C address; 0 = no VPD", HFILL },
1971
16
        },
1972
16
        { &hf_nvme_mi_mi_port_twire_mvpdfreq,
1973
16
          { "Maximum VPD Access Frequency (MVPDFREQ)",
1974
16
            "nvme-mi.mi.port.mvpdfreq",
1975
16
            FT_UINT8, BASE_HEX, VALS(mi_vpdfreq_vals), 0,
1976
16
            NULL, HFILL },
1977
16
        },
1978
16
        { &hf_nvme_mi_mi_port_twire_cmeaddr,
1979
16
          { "Current Management Endpoint Address (CMEADDR)",
1980
16
            "nvme-mi.mi.port.cmeaddr",
1981
16
            FT_UINT8, BASE_HEX, NULL, 0,
1982
16
            "Current 2-Wire address; 0 = no Management Endpoint", HFILL },
1983
16
        },
1984
16
        { &hf_nvme_mi_mi_port_twire_twprt,
1985
16
          { "2-Wire Protocols Supported (TWPRT)", "nvme-mi.mi.port.twprt",
1986
16
            FT_UINT8, BASE_HEX, NULL, 0,
1987
16
            NULL, HFILL },
1988
16
        },
1989
16
        { &hf_nvme_mi_mi_port_twire_i3csprt,
1990
16
          { "I3C Support (I3CSPRT)", "nvme-mi.mi.port.i3csprt",
1991
16
            FT_BOOLEAN, 8, TFS(&tfs_supported_not_supported), 0x80,
1992
16
            NULL, HFILL },
1993
16
        },
1994
16
        { &hf_nvme_mi_mi_port_twire_msmbfreq,
1995
16
          { "Maximum SMBus/I2C Frequency (MSMBFREQ)",
1996
16
            "nvme-mi.mi.port.msmbfreq",
1997
16
            FT_UINT8, BASE_HEX, VALS(mi_vpdfreq_vals), 0x03,
1998
16
            NULL, HFILL },
1999
16
        },
2000
16
        { &hf_nvme_mi_mi_port_twire_nvmebm,
2001
16
          { "NVMe Basic Management (NVMEBM)", "nvme-mi.mi.port.nvmebm",
2002
16
            FT_UINT8, BASE_HEX, NULL, 0,
2003
16
            NULL, HFILL },
2004
16
        },
2005
16
        { &hf_nvme_mi_mi_port_twire_nvmebms,
2006
16
          { "NVMe Basic Management Support (NVMEBMS)",
2007
16
            "nvme-mi.mi.port.nvmebms",
2008
16
            FT_BOOLEAN, 8, TFS(&tfs_supported_not_supported), 0x01,
2009
16
            NULL, HFILL },
2010
16
        },
2011
2012
        /* Controller List (DTYP 02h) */
2013
16
        { &hf_nvme_mi_mi_ctrllist_numids,
2014
16
          { "Number of Identifiers", "nvme-mi.mi.ctrllist.numids",
2015
16
            FT_UINT16, BASE_DEC, NULL, 0,
2016
16
            NULL, HFILL },
2017
16
        },
2018
16
        { &hf_nvme_mi_mi_ctrllist_ctrlid,
2019
16
          { "Controller Identifier", "nvme-mi.mi.ctrllist.ctrlid",
2020
16
            FT_UINT16, BASE_HEX, NULL, 0,
2021
16
            NULL, HFILL },
2022
16
        },
2023
2024
        /* Controller Information (DTYP 03h) */
2025
16
        { &hf_nvme_mi_mi_ctrlinfo_portid,
2026
16
          { "Port Identifier (PORTID)", "nvme-mi.mi.ctrlinfo.portid",
2027
16
            FT_UINT8, BASE_DEC, NULL, 0,
2028
16
            "PCIe port with which the Controller is associated", HFILL },
2029
16
        },
2030
16
        { &hf_nvme_mi_mi_ctrlinfo_prii,
2031
16
          { "PCIe Routing ID Information (PRII)", "nvme-mi.mi.ctrlinfo.prii",
2032
16
            FT_UINT8, BASE_HEX, NULL, 0,
2033
16
            NULL, HFILL },
2034
16
        },
2035
16
        { &hf_nvme_mi_mi_ctrlinfo_riv,
2036
16
          { "PCIe Routing ID Valid (PCIERIV)", "nvme-mi.mi.ctrlinfo.riv",
2037
16
            FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x01,
2038
16
            "Bus and Device numbers have been captured", HFILL },
2039
16
        },
2040
16
        { &hf_nvme_mi_mi_ctrlinfo_pri,
2041
16
          { "PCIe Routing ID (PRI)", "nvme-mi.mi.ctrlinfo.pri",
2042
16
            FT_UINT16, BASE_HEX, NULL, 0,
2043
16
            NULL, HFILL },
2044
16
        },
2045
16
        { &hf_nvme_mi_mi_ctrlinfo_pri_bus,
2046
16
          { "PCI Bus Number (PCIBN)", "nvme-mi.mi.ctrlinfo.pri.bus",
2047
16
            FT_UINT16, BASE_HEX, NULL, 0xFF00,
2048
16
            NULL, HFILL },
2049
16
        },
2050
16
        { &hf_nvme_mi_mi_ctrlinfo_pri_dev,
2051
16
          { "PCI Device Number (PCIDN)", "nvme-mi.mi.ctrlinfo.pri.dev",
2052
16
            FT_UINT16, BASE_HEX, NULL, 0x00F8,
2053
16
            NULL, HFILL },
2054
16
        },
2055
16
        { &hf_nvme_mi_mi_ctrlinfo_pri_fn,
2056
16
          { "PCI Function Number (PCIFN)", "nvme-mi.mi.ctrlinfo.pri.fn",
2057
16
            FT_UINT16, BASE_HEX, NULL, 0x0007,
2058
16
            NULL, HFILL },
2059
16
        },
2060
16
        { &hf_nvme_mi_mi_ctrlinfo_pcivid,
2061
16
          { "PCI Vendor ID (PCIVID)", "nvme-mi.mi.ctrlinfo.pcivid",
2062
16
            FT_UINT16, BASE_HEX, NULL, 0,
2063
16
            NULL, HFILL },
2064
16
        },
2065
16
        { &hf_nvme_mi_mi_ctrlinfo_pcidid,
2066
16
          { "PCI Device ID (PCIDID)", "nvme-mi.mi.ctrlinfo.pcidid",
2067
16
            FT_UINT16, BASE_HEX, NULL, 0,
2068
16
            NULL, HFILL },
2069
16
        },
2070
16
        { &hf_nvme_mi_mi_ctrlinfo_pcisvid,
2071
16
          { "PCI Subsystem Vendor ID (PCISVID)", "nvme-mi.mi.ctrlinfo.pcisvid",
2072
16
            FT_UINT16, BASE_HEX, NULL, 0,
2073
16
            NULL, HFILL },
2074
16
        },
2075
16
        { &hf_nvme_mi_mi_ctrlinfo_pcisdid,
2076
16
          { "PCI Subsystem Device ID (PCISDID)", "nvme-mi.mi.ctrlinfo.pcisdid",
2077
16
            FT_UINT16, BASE_HEX, NULL, 0,
2078
16
            NULL, HFILL },
2079
16
        },
2080
16
        { &hf_nvme_mi_mi_ctrlinfo_pciesn,
2081
16
          { "PCIe Segment Number (PCIESN)", "nvme-mi.mi.ctrlinfo.pciesn",
2082
16
            FT_UINT8, BASE_DEC, NULL, 0,
2083
16
            "Segment Number when the PCIe link is in Flit mode", HFILL },
2084
16
        },
2085
2086
        /* Command lists (DTYP 04h/05h) */
2087
16
        { &hf_nvme_mi_mi_cmdlist_numcmd,
2088
16
          { "Number of Commands (NUMCMD)", "nvme-mi.mi.cmdlist.numcmd",
2089
16
            FT_UINT16, BASE_DEC, NULL, 0,
2090
16
            NULL, HFILL },
2091
16
        },
2092
16
        { &hf_nvme_mi_mi_cmdlist_ctyp,
2093
16
          { "Command Type (CTYP)", "nvme-mi.mi.cmdlist.ctyp",
2094
16
            FT_UINT8, BASE_HEX, NULL, 0,
2095
16
            NULL, HFILL },
2096
16
        },
2097
16
        { &hf_nvme_mi_mi_cmdlist_nmimt,
2098
16
          { "NVMe-MI Message Type (NMIMT)", "nvme-mi.mi.cmdlist.nmimt",
2099
16
            FT_UINT8, BASE_HEX, VALS(mi_type_vals), 0x78,
2100
16
            NULL, HFILL },
2101
16
        },
2102
16
        { &hf_nvme_mi_mi_cmdlist_opc,
2103
16
          { "Opcode (OPC)", "nvme-mi.mi.cmdlist.opc",
2104
16
            FT_UINT8, BASE_HEX, NULL, 0,
2105
16
            NULL, HFILL },
2106
16
        },
2107
2108
        /* NVM Subsystem Health Data Structure */
2109
16
        { &hf_nvme_mi_mi_nshds_nss,
2110
16
          { "NVM Subsystem Status (NSS)", "nvme-mi.mi.nshds.nss",
2111
16
            FT_UINT8, BASE_HEX, NULL, 0,
2112
16
            NULL, HFILL },
2113
16
        },
2114
16
        { &hf_nvme_mi_mi_nshds_nss_atf,
2115
16
          { "AEM Transmission Failure (ATF)", "nvme-mi.mi.nshds.nss.atf",
2116
16
            FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x80,
2117
16
            NULL, HFILL },
2118
16
        },
2119
16
        { &hf_nvme_mi_mi_nshds_nss_sfm,
2120
16
          { "Sanitize Failure Mode (SFM)", "nvme-mi.mi.nshds.nss.sfm",
2121
16
            FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x40,
2122
16
            NULL, HFILL },
2123
16
        },
2124
16
        { &hf_nvme_mi_mi_nshds_nss_df,
2125
16
          { "Drive Functional (DF)", "nvme-mi.mi.nshds.nss.df",
2126
16
            FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x20,
2127
16
            NULL, HFILL },
2128
16
        },
2129
16
        { &hf_nvme_mi_mi_nshds_nss_rnr,
2130
16
          { "Reset Not Required (RNR)", "nvme-mi.mi.nshds.nss.rnr",
2131
16
            FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x10,
2132
16
            NULL, HFILL },
2133
16
        },
2134
16
        { &hf_nvme_mi_mi_nshds_nss_p0la,
2135
16
          { "Port 0 PCIe Link Active (P0LA)", "nvme-mi.mi.nshds.nss.p0la",
2136
16
            FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x08,
2137
16
            NULL, HFILL },
2138
16
        },
2139
16
        { &hf_nvme_mi_mi_nshds_nss_p1la,
2140
16
          { "Port 1 PCIe Link Active (P1LA)", "nvme-mi.mi.nshds.nss.p1la",
2141
16
            FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x04,
2142
16
            NULL, HFILL },
2143
16
        },
2144
16
        { &hf_nvme_mi_mi_nshds_nss_snfm,
2145
16
          { "Sanitize Namespace Failure Mode (SNFM)",
2146
16
            "nvme-mi.mi.nshds.nss.snfm",
2147
16
            FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x02,
2148
16
            NULL, HFILL },
2149
16
        },
2150
16
        { &hf_nvme_mi_mi_nshds_sw,
2151
16
          { "SMART Warnings (SW)", "nvme-mi.mi.nshds.sw",
2152
16
            FT_UINT8, BASE_HEX, NULL, 0,
2153
16
            "Inverted Critical Warning field of the SMART log page",
2154
16
            HFILL },
2155
16
        },
2156
16
        { &hf_nvme_mi_mi_nshds_sw_ips,
2157
16
          { "Indeterminate Personality State (IPS)",
2158
16
            "nvme-mi.mi.nshds.sw.ips",
2159
16
            FT_BOOLEAN, 8, TFS(&tfs_nshds_sw), 0x40,
2160
16
            NULL, HFILL },
2161
16
        },
2162
16
        { &hf_nvme_mi_mi_nshds_sw_pmre,
2163
16
          { "Persistent Memory Region Error (PMRE)",
2164
16
            "nvme-mi.mi.nshds.sw.pmre",
2165
16
            FT_BOOLEAN, 8, TFS(&tfs_nshds_sw), 0x20,
2166
16
            NULL, HFILL },
2167
16
        },
2168
16
        { &hf_nvme_mi_mi_nshds_sw_vmbf,
2169
16
          { "Volatile Memory Backup Failed (VMBF)",
2170
16
            "nvme-mi.mi.nshds.sw.vmbf",
2171
16
            FT_BOOLEAN, 8, TFS(&tfs_nshds_sw), 0x10,
2172
16
            NULL, HFILL },
2173
16
        },
2174
16
        { &hf_nvme_mi_mi_nshds_sw_ro,
2175
16
          { "Read Only (RO)", "nvme-mi.mi.nshds.sw.ro",
2176
16
            FT_BOOLEAN, 8, TFS(&tfs_nshds_sw), 0x08,
2177
16
            NULL, HFILL },
2178
16
        },
2179
16
        { &hf_nvme_mi_mi_nshds_sw_rd,
2180
16
          { "Reliability Degraded (RD)", "nvme-mi.mi.nshds.sw.rd",
2181
16
            FT_BOOLEAN, 8, TFS(&tfs_nshds_sw), 0x04,
2182
16
            NULL, HFILL },
2183
16
        },
2184
16
        { &hf_nvme_mi_mi_nshds_sw_taut,
2185
16
          { "Temperature Above or Under Threshold (TAUT)",
2186
16
            "nvme-mi.mi.nshds.sw.taut",
2187
16
            FT_BOOLEAN, 8, TFS(&tfs_nshds_sw), 0x02,
2188
16
            NULL, HFILL },
2189
16
        },
2190
16
        { &hf_nvme_mi_mi_nshds_sw_st,
2191
16
          { "Spare Threshold (ST)", "nvme-mi.mi.nshds.sw.st",
2192
16
            FT_BOOLEAN, 8, TFS(&tfs_nshds_sw), 0x01,
2193
16
            NULL, HFILL },
2194
16
        },
2195
16
        { &hf_nvme_mi_mi_nshds_ctemp,
2196
16
          { "Composite Temperature (CTEMP)", "nvme-mi.mi.nshds.ctemp",
2197
16
            FT_UINT8, BASE_CUSTOM, CF_FUNC(nvme_mi_mi_fmt_nshds_ctemp), 0,
2198
16
            "Composite temperature of the NVM Subsystem", HFILL },
2199
16
        },
2200
16
        { &hf_nvme_mi_mi_nshds_pdlu,
2201
16
          { "Percentage Drive Life Used (PDLU)", "nvme-mi.mi.nshds.pdlu",
2202
16
            FT_UINT8, BASE_DEC, NULL, 0,
2203
16
            NULL, HFILL },
2204
16
        },
2205
16
        { &hf_nvme_mi_mi_nshds_ccs,
2206
16
          { "Composite Controller Status (CCS)", "nvme-mi.mi.nshds.ccs",
2207
16
            FT_UINT16, BASE_HEX, NULL, 0,
2208
16
            "Composite Controller Status Flags (NVMe-MI 2.1 'Composite"
2209
16
            " Controller Status Data Structure (CCSDS)')", HFILL },
2210
16
        },
2211
2212
        /* Shared health-status flag bits (NVMe-MI 2.1 "Controller Health
2213
         * Status Changed Flags (CHSCF)" / "Composite Controller Status
2214
         * Data Structure (CCSDS)") */
2215
16
        { &hf_nvme_mi_mi_hsf_tcida,
2216
16
          { "Telemetry Controller-Initiated Data Available (TCIDA)",
2217
16
            "nvme-mi.mi.hsf.tcida",
2218
16
            FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x2000,
2219
16
            NULL, HFILL },
2220
16
        },
2221
16
        { &hf_nvme_mi_mi_hsf_cwarn,
2222
16
          { "Critical Warning (CWARN)", "nvme-mi.mi.hsf.cwarn",
2223
16
            FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x1000,
2224
16
            NULL, HFILL },
2225
16
        },
2226
16
        { &hf_nvme_mi_mi_hsf_spare,
2227
16
          { "Available Spare (SPARE)", "nvme-mi.mi.hsf.spare",
2228
16
            FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0800,
2229
16
            NULL, HFILL },
2230
16
        },
2231
16
        { &hf_nvme_mi_mi_hsf_pdlu,
2232
16
          { "Percentage Used (PDLU)", "nvme-mi.mi.hsf.pdlu",
2233
16
            FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0400,
2234
16
            NULL, HFILL },
2235
16
        },
2236
16
        { &hf_nvme_mi_mi_hsf_ctemp,
2237
16
          { "Composite Temperature Change (CTEMP)", "nvme-mi.mi.hsf.ctemp",
2238
16
            FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0200,
2239
16
            NULL, HFILL },
2240
16
        },
2241
16
        { &hf_nvme_mi_mi_hsf_csts,
2242
16
          { "Controller Status Change (CSTS)", "nvme-mi.mi.hsf.csts",
2243
16
            FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0100,
2244
16
            NULL, HFILL },
2245
16
        },
2246
16
        { &hf_nvme_mi_mi_hsf_fa,
2247
16
          { "Firmware Activated (FA)", "nvme-mi.mi.hsf.fa",
2248
16
            FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0080,
2249
16
            NULL, HFILL },
2250
16
        },
2251
16
        { &hf_nvme_mi_mi_hsf_nac,
2252
16
          { "Namespace Attribute Changed (NAC)", "nvme-mi.mi.hsf.nac",
2253
16
            FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0040,
2254
16
            NULL, HFILL },
2255
16
        },
2256
16
        { &hf_nvme_mi_mi_hsf_ceco,
2257
16
          { "Controller Enable Change Occurred (CECO)", "nvme-mi.mi.hsf.ceco",
2258
16
            FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0020,
2259
16
            NULL, HFILL },
2260
16
        },
2261
16
        { &hf_nvme_mi_mi_hsf_nssro,
2262
16
          { "NVM Subsystem Reset Occurred (NSSRO)", "nvme-mi.mi.hsf.nssro",
2263
16
            FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0010,
2264
16
            NULL, HFILL },
2265
16
        },
2266
16
        { &hf_nvme_mi_mi_hsf_shst,
2267
16
          { "Shutdown Status (SHST)", "nvme-mi.mi.hsf.shst",
2268
16
            FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0004,
2269
16
            NULL, HFILL },
2270
16
        },
2271
16
        { &hf_nvme_mi_mi_hsf_cfs,
2272
16
          { "Controller Fatal Status (CFS)", "nvme-mi.mi.hsf.cfs",
2273
16
            FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0002,
2274
16
            NULL, HFILL },
2275
16
        },
2276
16
        { &hf_nvme_mi_mi_hsf_rdy,
2277
16
          { "Ready (RDY)", "nvme-mi.mi.hsf.rdy",
2278
16
            FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0001,
2279
16
            NULL, HFILL },
2280
16
        },
2281
2282
        /* Controller Health Data Structure */
2283
16
        { &hf_nvme_mi_mi_chds_ctlid,
2284
16
          { "Controller Identifier (CTLID)", "nvme-mi.mi.chds.ctlid",
2285
16
            FT_UINT16, BASE_HEX, NULL, 0,
2286
16
            NULL, HFILL },
2287
16
        },
2288
16
        { &hf_nvme_mi_mi_chds_csts,
2289
16
          { "Controller Status (CSTS)", "nvme-mi.mi.chds.csts",
2290
16
            FT_UINT16, BASE_HEX, NULL, 0,
2291
16
            NULL, HFILL },
2292
16
        },
2293
16
        { &hf_nvme_mi_mi_chds_csts_tcida,
2294
16
          { "Telemetry Controller-Initiated Data Available (TCIDA)",
2295
16
            "nvme-mi.mi.chds.csts.tcida",
2296
16
            FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0100,
2297
16
            NULL, HFILL },
2298
16
        },
2299
16
        { &hf_nvme_mi_mi_chds_csts_fa,
2300
16
          { "Firmware Activated (FA)", "nvme-mi.mi.chds.csts.fa",
2301
16
            FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0080,
2302
16
            NULL, HFILL },
2303
16
        },
2304
16
        { &hf_nvme_mi_mi_chds_csts_nac,
2305
16
          { "Namespace Attribute Changed (NAC)", "nvme-mi.mi.chds.csts.nac",
2306
16
            FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0040,
2307
16
            NULL, HFILL },
2308
16
        },
2309
16
        { &hf_nvme_mi_mi_chds_csts_ceco,
2310
16
          { "Controller Enable Change Occurred (CECO)",
2311
16
            "nvme-mi.mi.chds.csts.ceco",
2312
16
            FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0020,
2313
16
            "Indicates the value of CC.EN", HFILL },
2314
16
        },
2315
16
        { &hf_nvme_mi_mi_chds_csts_nssro,
2316
16
          { "NVM Subsystem Reset Occurred (NSSRO)",
2317
16
            "nvme-mi.mi.chds.csts.nssro",
2318
16
            FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0010,
2319
16
            NULL, HFILL },
2320
16
        },
2321
16
        { &hf_nvme_mi_mi_chds_csts_shst,
2322
16
          { "Shutdown Status (SHST)", "nvme-mi.mi.chds.csts.shst",
2323
16
            FT_UINT16, BASE_HEX, VALS(shst_table), 0x000C,
2324
16
            NULL, HFILL },
2325
16
        },
2326
16
        { &hf_nvme_mi_mi_chds_csts_cfs,
2327
16
          { "Controller Fatal Status (CFS)", "nvme-mi.mi.chds.csts.cfs",
2328
16
            FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0002,
2329
16
            NULL, HFILL },
2330
16
        },
2331
16
        { &hf_nvme_mi_mi_chds_csts_rdy,
2332
16
          { "Ready (RDY)", "nvme-mi.mi.chds.csts.rdy",
2333
16
            FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0001,
2334
16
            NULL, HFILL },
2335
16
        },
2336
16
        { &hf_nvme_mi_mi_chds_ctemp,
2337
16
          { "Composite Temperature (CTEMP)", "nvme-mi.mi.chds.ctemp",
2338
16
            FT_UINT16, BASE_DEC, NULL, 0,
2339
16
            "Composite temperature of the Controller in Kelvins", HFILL },
2340
16
        },
2341
16
        { &hf_nvme_mi_mi_chds_pdlu,
2342
16
          { "Percentage Used (PDLU)", "nvme-mi.mi.chds.pdlu",
2343
16
            FT_UINT8, BASE_DEC, NULL, 0,
2344
16
            NULL, HFILL },
2345
16
        },
2346
16
        { &hf_nvme_mi_mi_chds_spare,
2347
16
          { "Available Spare (SPARE)", "nvme-mi.mi.chds.spare",
2348
16
            FT_UINT8, BASE_DEC, NULL, 0,
2349
16
            "Normalized percentage of remaining spare capacity", HFILL },
2350
16
        },
2351
16
        { &hf_nvme_mi_mi_chds_cwarn,
2352
16
          { "Critical Warning (CWARN)", "nvme-mi.mi.chds.cwarn",
2353
16
            FT_UINT8, BASE_HEX, NULL, 0,
2354
16
            NULL, HFILL },
2355
16
        },
2356
16
        { &hf_nvme_mi_mi_chds_cwarn_ips,
2357
16
          { "Indeterminate Personality State (IPS)",
2358
16
            "nvme-mi.mi.chds.cwarn.ips",
2359
16
            FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x40,
2360
16
            NULL, HFILL },
2361
16
        },
2362
16
        { &hf_nvme_mi_mi_chds_cwarn_pmre,
2363
16
          { "Persistent Memory Region Error (PMRE)",
2364
16
            "nvme-mi.mi.chds.cwarn.pmre",
2365
16
            FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x20,
2366
16
            NULL, HFILL },
2367
16
        },
2368
16
        { &hf_nvme_mi_mi_chds_cwarn_vmbf,
2369
16
          { "Volatile Memory Backup Failed (VMBF)",
2370
16
            "nvme-mi.mi.chds.cwarn.vmbf",
2371
16
            FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x10,
2372
16
            NULL, HFILL },
2373
16
        },
2374
16
        { &hf_nvme_mi_mi_chds_cwarn_ro,
2375
16
          { "Read Only (RO)", "nvme-mi.mi.chds.cwarn.ro",
2376
16
            FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x08,
2377
16
            NULL, HFILL },
2378
16
        },
2379
16
        { &hf_nvme_mi_mi_chds_cwarn_rd,
2380
16
          { "Reliability Degraded (RD)", "nvme-mi.mi.chds.cwarn.rd",
2381
16
            FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x04,
2382
16
            NULL, HFILL },
2383
16
        },
2384
16
        { &hf_nvme_mi_mi_chds_cwarn_taut,
2385
16
          { "Temperature Above or Under Threshold (TAUT)",
2386
16
            "nvme-mi.mi.chds.cwarn.taut",
2387
16
            FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x02,
2388
16
            NULL, HFILL },
2389
16
        },
2390
16
        { &hf_nvme_mi_mi_chds_cwarn_st,
2391
16
          { "Spare Threshold (ST)", "nvme-mi.mi.chds.cwarn.st",
2392
16
            FT_BOOLEAN, 8, TFS(&tfs_set_notset), 0x01,
2393
16
            NULL, HFILL },
2394
16
        },
2395
16
        { &hf_nvme_mi_mi_chds_chsc,
2396
16
          { "Controller Health Status Changed (CHSC)",
2397
16
            "nvme-mi.mi.chds.chsc",
2398
16
            FT_UINT16, BASE_HEX, NULL, 0,
2399
16
            "Controller Health Status Changed Flags (CHSCF)", HFILL },
2400
16
        },
2401
16
    };
2402
    /* *INDENT-ON* */
2403
2404
16
    static int *ett[] = {
2405
16
        &ett_nvme_mi_mi,
2406
16
        &ett_nvme_mi_mi_field,
2407
16
        &ett_nvme_mi_mi_entry,
2408
16
    };
2409
2410
16
    static ei_register_info ei[] = {
2411
16
        { &ei_nvme_mi_mi_truncated,
2412
16
          { "nvme-mi.mi.truncated", PI_MALFORMED, PI_WARN,
2413
16
            "MI command payload truncated", EXPFILL }
2414
16
        },
2415
16
        { &ei_nvme_mi_mi_orphan_response,
2416
16
          { "nvme-mi.mi.orphan_response", PI_SEQUENCE, PI_NOTE,
2417
16
            "MI response without a usable matching request (missing or"
2418
16
            " truncated); opcode could not be recovered", EXPFILL }
2419
16
        },
2420
16
        { &ei_nvme_mi_mi_reserved_dtyp,
2421
16
          { "nvme-mi.mi.reserved_dtyp", PI_PROTOCOL, PI_NOTE,
2422
16
            "Data Structure Type is in the Reserved range (06h-FFh)",
2423
16
            EXPFILL }
2424
16
        },
2425
16
        { &ei_nvme_mi_mi_reserved_configid,
2426
16
          { "nvme-mi.mi.reserved_configid", PI_PROTOCOL, PI_NOTE,
2427
16
            "Configuration Identifier is in a Reserved range (00h, 05h-BFh)",
2428
16
            EXPFILL }
2429
16
        },
2430
16
        { &ei_nvme_mi_mi_reserved_value,
2431
16
          { "nvme-mi.mi.reserved_value", PI_PROTOCOL, PI_NOTE,
2432
16
            "A command-specific field carries a Reserved value", EXPFILL }
2433
16
        }
2434
16
    };
2435
2436
16
    expert_module_t *expert_nvme_mi_mi;
2437
2438
16
    proto_nvme_mi_mi = proto_register_protocol(
2439
16
            "NVMe-MI MI Command", "NVMe-MI MI", "nvme-mi.mi");
2440
16
    proto_register_field_array(proto_nvme_mi_mi, hf, array_length(hf));
2441
16
    proto_register_subtree_array(ett, array_length(ett));
2442
2443
16
    expert_nvme_mi_mi = expert_register_protocol(proto_nvme_mi_mi);
2444
16
    expert_register_field_array(expert_nvme_mi_mi, ei, array_length(ei));
2445
2446
16
    nvme_mi_mi_handle = register_dissector_with_description(
2447
16
            "nvme-mi.mi", "NVMe-MI MI Command",
2448
16
            dissect_nvme_mi_mi, proto_nvme_mi_mi);
2449
16
}
2450
2451
void
2452
proto_reg_handoff_nvme_mi_mi(void)
2453
16
{
2454
16
    dissector_add_uint("nvme-mi.type", NVME_MI_TYPE_MI,
2455
16
                       nvme_mi_mi_handle);
2456
16
}
2457
2458
/*
2459
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
2460
 *
2461
 * Local variables:
2462
 * c-basic-offset: 4
2463
 * tab-width: 8
2464
 * indent-tabs-mode: nil
2465
 * End:
2466
 *
2467
 * vi: set shiftwidth=4 tabstop=8 expandtab:
2468
 * :indentSize=4:tabSize=8:noTabs=true:
2469
 */