xref: /illumos-gate/usr/src/uts/common/sys/nvme/solidigm_p5xxx.h (revision 7655c6d53c36750b508636f48c73a2de57754e5a)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2024 Oxide Computer Company
14  */
15 
16 #ifndef _SYS_NVME_SOLIDIGM_P5XXX_H
17 #define	_SYS_NVME_SOLIDIGM_P5XXX_H
18 
19 /*
20  * This header defines vendor-specific NVMe interfaces and is not a committed
21  * interface. Its contents and existence are subject to change.
22  *
23  * Vendor-specific definitions for the Intel/Solidigm 5000 series devices
24  * including the P5510, P5520, and P5620. Note, these device all share a PCI ID
25  * and must be disambiguated by their subsystem IDs. Logs fall into three
26  * buckets:
27  *
28  * 1) Those unique to the P5510. These are prefixed with INTEL_P5510.
29  * 2) Those that are shared between the P5510 and the P5[56]20. These are
30  *    prefixed with SOLIDIGM_P5XXX. All logs in this case use the same data
31  *    structure. Some logs have data structures shared across all devices and
32  *    are in the top-level <sys/nvme/solidigm.h> header.
33  * 3) Logs which are only supported by the P5520/P5620. These are prefixed with
34  *    SOLIDIGM_P5X20.
35  */
36 
37 #include <sys/stdint.h>
38 #include <sys/debug.h>
39 
40 #include <sys/nvme/ocp.h>
41 
42 #ifdef __cplusplus
43 extern "C" {
44 #endif
45 
46 /*
47  * The device ID isn't enough to distinguish these different devices and
48  * therefore we need to use the subsystem IDs as well. The 5510 only shows up
49  * with an Intel vendor ID; however, the 5520 and 5620 show up with both a
50  * Solidigm and Intel device ID.
51  */
52 #define	SOLIDIGM_P5XXX_DID	0xb60
53 #define	SOLIDIGM_P5510_U2_SDID	0x8008
54 #define	SOLIDIGM_P5520_U2_SDID	0x9008
55 #define	SOLIDIGM_P5520_E1S_9P5MM_SDID	0x900c
56 #define	SOLIDIGM_P5520_E1S_15MM_SDID	0x900d
57 #define	SOLIDIGM_P5520_E1L_SDID	0x901c
58 #define	SOLIDIGM_P5620_U2_SDID	0x9108
59 
60 typedef enum {
61 	/*
62 	 * This is a log specific to the P5510 which contains a directory of the
63 	 * other log pages that are present. This is a 512 byte log page with a
64 	 * leading version and then information about vendor specific logs
65 	 * support at an offset of 2x log page. This is here for completeness
66 	 * sake.
67 	 */
68 	INTEL_P5510_LOG_DIR		= 0xc0,
69 	/*
70 	 * The P5520 and P5620 use 0xc0 as the OCP SMART log, which is different
71 	 * from the P5510.
72 	 */
73 	SOLIDIGM_P5X20_LOG_OCP_SMART	= OCP_LOG_DSSD_SMART,
74 	/*
75 	 * The next two logs are used to contain read and write command latency
76 	 * statistics. For these to have useful content, the device must be
77 	 * explicitly told to perform tracking with a vendor-specific feature.
78 	 * Uses the solidigm_vul_p5xxx_lat_t structure.
79 	 */
80 	SOLIDIGM_P5XXX_LOG_READ_LAT	= 0xc1,
81 	SOLIDIGM_P5XXX_LOG_WRITE_LAT	= 0xc2,
82 	/*
83 	 * Uses the solidigm_vul_temp_t.
84 	 */
85 	SOLIDIGM_P5XXX_LOG_TEMP		= 0xc5,
86 	/*
87 	 * Uses the solidigm_vul_smart_log_t. The maximum number of entires is
88 	 * always grabbed, but there may be holes.
89 	 */
90 	SOLIDIGM_P5XXX_LOG_SMART	= 0xca,
91 	/*
92 	 * Uses the solidigm_vul_p5xxx_ioq_t.
93 	 */
94 	SOLIDIGM_P5XXX_LOG_IO_QUEUE	= 0xcb,
95 	/*
96 	 * This should be treated as a 512 byte log with an ASCII string encoded
97 	 * in it. However, don't assume hardware only outputs ASCII.
98 	 */
99 	SOLIDIGM_P5XXX_LOG_MARK_DESC	= 0xdd,
100 	/*
101 	 * Uses the solidigm_vul_temp_t.
102 	 */
103 	SOLIDIGM_P5X20_LOG_POWER	= 0xf2,
104 	/*
105 	 * Uses solidigm_vul_p5xxx_gc_t.
106 	 */
107 	SOLIDIGM_P5XXX_LOG_GC		= 0xfd,
108 	/*
109 	 * Uses solidigm_vul_p5xxx_lat_outlier_t.
110 	 */
111 	SOLIDIGM_P5XXX_LOG_OUTLIER	= 0xfe,
112 } solidigm_p5xxx_vul_t;
113 
114 /*
115  * All data structures must be packed to account for the layout from the various
116  * programmer's manuals.
117  */
118 #pragma pack(1)
119 
120 /*
121  * This log page is used for the read and write latency commands. These are
122  * organized into groups of 4 byte buckets. Each bucket has a range and a given
123  * step. For example, lat_63_127us_1us is latency in the range [63us, 127us)
124  * with the bucket width as the last parameter.
125  */
126 typedef struct {
127 	uint16_t lat_maj;
128 	uint16_t lat_minor;
129 	uint32_t lat_0_63us_1us[64];
130 	uint32_t lat_63_127us_1us[64];
131 	uint32_t lat_127_255us_2us[64];
132 	uint32_t lat_255_510us_4us[64];
133 	uint32_t lat_510_1p02ms_8us[64];
134 	uint32_t lat_1p02_2p04ms_16us[64];
135 	uint32_t lat_2p04_4p08ms_32us[64];
136 	uint32_t lat_4p08_8p16ms_64us[64];
137 	uint32_t lat_8p16_16p32ms_128us[64];
138 	uint32_t lat_16p32_32p64ms_256us[64];
139 	uint32_t lat_32p64_65p28ms_512us[64];
140 	uint32_t lat_65p28_130p56ms_1p024ms[64];
141 	uint32_t lat_130p56_256p12ms_2p048ms[64];
142 	uint32_t lat_251p12_522p25ms_4p096ms[64];
143 	uint32_t lat_522p24ms_1p04s_8p192ms[64];
144 	uint32_t lat_1p04_2p09s_16p384ms[64];
145 	uint32_t lat_2p09_4p18s_32p768ms[64];
146 	uint32_t lat_4p18_8p36s_65p536ms[64];
147 	uint32_t lat_8p36_16p72s_131p072ms[64];
148 	uint8_t lat_avg[8];
149 } solidigm_vul_p5xxx_lat_t;
150 
151 typedef struct {
152 	uint16_t	iosq_id;
153 	uint16_t	iosq_iocq_id;
154 	uint16_t	iosq_head;
155 	uint16_t	iosq_tail;
156 	uint16_t	iosq_out;
157 	uint16_t	iosq_max_qdepth;
158 } solidigm_vul_iosq_t;
159 
160 typedef struct {
161 	uint16_t	iocq_id;
162 	uint16_t	iocq_head;
163 	uint8_t		iocq_rsvd4[6];
164 } solidigm_vul_iocq_t;
165 
166 #define	SOLIDIGM_VUL_MAX_QUEUES	32
167 
168 typedef struct {
169 	uint16_t		ioq_vers;
170 	uint16_t		ioq_niosq;
171 	uint16_t		ioq_niocq;
172 	solidigm_vul_iosq_t	ioq_iosq[SOLIDIGM_VUL_MAX_QUEUES];
173 	solidigm_vul_iocq_t	ioq_iocq[SOLIDIGM_VUL_MAX_QUEUES];
174 	uint8_t			ioq_rsvd710[314];
175 } solidigm_vul_p5xxx_ioq_t;
176 
177 /*
178  * All values are in in the power measurement log are in uW.
179  */
180 typedef struct {
181 	uint32_t	pow_vin1;
182 	uint32_t	pow_vin2;
183 } solidigm_vul_p5x2x_power_t;
184 
185 /*
186  * This is the size we recommend one obtain while reading the marketing name log
187  * page.
188  */
189 #define	SOLIDIGM_VUC_MARK_NAME_LEN	512
190 
191 typedef struct {
192 	uint32_t	gce_type;
193 	uint64_t	gce_ts;
194 } solidigm_vul_gc_ent_t;
195 
196 #define	SOLIDIGM_VUC_MAX_GC	100
197 
198 typedef struct {
199 	uint16_t	gc_major;
200 	uint16_t	gc_minor;
201 	solidigm_vul_gc_ent_t	gc_ents[SOLIDIGM_VUC_MAX_GC];
202 } solidigm_vul_p5xxx_gc_t;
203 
204 typedef struct {
205 	uint64_t	le_ts;
206 	uint32_t	le_cmd;
207 	uint32_t	le_lat_us;
208 	uint64_t	le_lba;
209 } soligm_vul_lat_ent_t;
210 
211 typedef struct {
212 	uint16_t		lao_major;
213 	uint16_t		lao_minor;
214 	uint8_t			lao_rsvd[4];
215 	uint64_t		lao_nents;
216 	soligm_vul_lat_ent_t	lao_ents[];
217 } solidigm_vul_p5xxx_lat_outlier_t;
218 
219 #pragma	pack()	/* pack(1) */
220 
221 /*
222  * Our current version of smatch cannot handle packed structures.
223  */
224 #ifndef __CHECKER__
225 CTASSERT(sizeof (solidigm_vul_p5xxx_lat_t) == 4876);
226 CTASSERT(offsetof(solidigm_vul_p5xxx_lat_t, lat_4p18_8p36s_65p536ms) == 4356);
227 CTASSERT(sizeof (solidigm_vul_iosq_t) == 12);
228 CTASSERT(sizeof (solidigm_vul_iocq_t) == 10);
229 CTASSERT(offsetof(solidigm_vul_p5xxx_ioq_t, ioq_iocq) == 390);
230 CTASSERT(offsetof(solidigm_vul_p5xxx_ioq_t, ioq_rsvd710) == 710);
231 CTASSERT(sizeof (solidigm_vul_p5xxx_ioq_t) == 1024);
232 CTASSERT(sizeof (solidigm_vul_p5x2x_power_t) == 8);
233 CTASSERT(sizeof (solidigm_vul_gc_ent_t) == 12);
234 CTASSERT(sizeof (solidigm_vul_p5xxx_gc_t) == 1204);
235 #endif	/* __CHECKER__ */
236 
237 #ifdef __cplusplus
238 }
239 #endif
240 
241 #endif /* _SYS_NVME_SOLIDIGM_P5XXX_H */
242