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