blob: 218d089b00e9847fc04d28920c95e2c024d101ee [file] [log] [blame]
Lorenz Brunfba5da02022-12-15 11:20:47 +00001package nvme
2
3import (
4 "bytes"
5 "encoding/binary"
6 "fmt"
7 "math/big"
8)
9
10// Figure 109
11type identifyData struct {
12 // Controller Capabilities and Features
13 PCIVendorID uint16
14 PCISubsystemVendorID uint16
15 SerialNumber [20]byte
16 ModelNumber [40]byte
17 FirmwareRevision [8]byte
18 RecommendedArbitrationBurst uint8
19 IEEEOUI [3]byte
20 CMIC uint8
21 MaximumDataTransferSize uint8
22 ControllerID uint16
23 Version uint32
24 RuntimeD3ResumeLatency uint32
25 RuntimeD3EntryLatency uint32
26 OAES uint32
27 CTRATT uint32
28 _ [12]byte
29 FRUGUID [16]byte
30 _ [128]byte
31 // Admin Command Set Attributes & Optional Controller Capabilities
32 OACS uint16
33 AbortCommandLimit uint8
34 AsynchronousEventRequestLimit uint8
35 FRMW uint8
36 LPA uint8
37 ErrorLogPageEntries uint8
38 NumberOfPowerStatesSupport uint8
39 AdminVendorSpecificCmdConfig uint8
40 AutonomousPowerStateTransitionAttrs uint8
41 WarningCompositeTempThreshold uint16
42 CriticalCompositeTempThreshold uint16
43 MaximumTimeForFirmwareActivation uint16
44 HostMemoryBufferPreferredSize uint32
45 HostMemoryBufferMinimumSize uint32
46 TotalNVMCapacity uint128le
47 UnallocatedNVMCapacity uint128le
48 ReplyProtectedMemoryBlockSupport uint32
49 ExtendedDeviceSelfTestTime uint16
50 DeviceSelfTestOptions uint8
51 FirmwareUpdateGranularity uint8
52 KeepAliveSupport uint16
53 HostControlledThermalMgmtAttrs uint16
54 MinimumThermalMgmntTemp uint16
55 MaximumThermalMgmntTemp uint16
56 SanitizeCapabilities uint32
57 _ [180]byte
58 // NVM Command Set Attributes
59 SubmissionQueueEntrySize uint8
60 CompletionQueueEntrySize uint8
61 MaximumOutstandingCommands uint16
62 NumberOfNamespaces uint32
63 OptionalNVMCommandSupport uint16
64 FusedOperationSupport uint16
65 FormatNVMAttributes uint8
66 VolatileWriteCache uint8
67 AtomicWriteUnitNormal uint16
68 AtomicWriteUnitPowerFail uint16
69 NVMVendorSepcificCommandConfig uint8
70 AtomicCompareAndWriteUnit uint16
71 _ [2]byte
72 SGLSupport uint32
73 _ [228]byte
74 NVMSubsystemNVMeQualifiedName [256]byte
75 _ [1024]byte
76 // Power State Descriptors
77 PowerStateDescriptors [32][32]byte
78}
79
80// IdentifyData contains various identifying information about a NVMe
81// controller. Because the actual data structure is very large, currently not
82// all fields are exposed as properly-typed individual fields. If you need
83// a new field, please add it to this structure.
84type IdentifyData struct {
85 // PCIVendorID contains the company vendor identifier assigned by the PCI
86 // SIG.
87 PCIVendorID uint16
88 // PCISubsystemVendorID contains the company vendor identifier that is
89 // assigned by the PCI SIG for the subsystem.
90 PCISubsystemVendorID uint16
91 // SerialNumber contains the serial number for the NVM subsystem that is
92 // assigned by the vendor.
93 SerialNumber string
94 // ModelNumber contains the model number for the NVM subsystem that is
95 // assigned by the vendor.
96 ModelNumber string
97 // FirmwareRevision contains the currently active firmware revision for the
98 // NVM subsystem.
99 FirmwareRevision string
100 // IEEEOUI contains the Organization Unique Identifier for the controller
101 // vendor as assigned by the IEEE.
102 IEEEOUI [3]byte
103
104 // IsPCIVirtualFunction indicates if the controller is a virtual controller
105 // as part of a PCI virtual function.
106 IsPCIVirtualFunction bool
107
108 // SpecVersionMajor/Minor contain the version of the NVMe specification the
109 // controller supports. Only mandatory from spec version 1.2 onwards.
110 SpecVersionMajor uint16
111 SpecVersionMinor uint8
112
113 // FRUGloballyUniqueIdentifier contains a 128-bit value that is globally
114 // unique for a given Field Replaceable Unit (FRU). Contains all-zeroes if
115 // unavailable.
116 FRUGloballyUniqueIdentifier [16]byte
117 // VirtualizationManagementSupported indicates if the controller
118 // supports the Virtualization Management command.
119 VirtualizationManagementSupported bool
120 // NVMeMISupported indicates if the controller supports the NVMe-MI
121 // Send and Receive commands.
122 NVMeMISupported bool
123 // DirectivesSupported indicates if the controller supports the
124 // Directive Send and Receive commands.
125 DirectivesSupported bool
126 // SelfTestSupported indicates if the controller supports the Device Self-
127 // test command.
128 SelfTestSupported bool
129 // NamespaceManagementSupported indicates if the controller supports the
130 // Namespace Management and Attachment commands.
131 NamespaceManagementSupported bool
132 // FirmwareUpdateSupported indicates if the controller supports the
133 // Firmware Commit and Image Download commands.
134 FirmwareUpdateSupported bool
135 // FormattingSupported indicates if the controller supports the Format
136 // command.
137 FormattingSupported bool
138 // SecuritySupported indicates if the controller supports the Security Send
139 // and Receive commands.
140 SecuritySupported bool
141
142 // TotalNVMCapacity contains the total NVM capacity in bytes in the NVM
143 // subsystem. This can be 0 on devices without NamespaceManagementSupported.
144 TotalNVMCapacity *big.Int
145 // UnallocatedNVMCapacity contains the unallocated NVM capacity in bytes in
146 // the NVM subsystem. This can be 0 on devices without
147 // NamespaceManagementSupported.
148 UnallocatedNVMCapacity *big.Int
149
150 // MaximumNumberOfNamespace defines the maximum number of namespaces
151 // supported by the controller.
152 MaximumNumberOfNamespaces uint32
153}
154
155func (d *Device) Identify() (*IdentifyData, error) {
156 var resp [4096]byte
157
158 if err := d.RawCommand(&Command{
159 Opcode: 0x06,
160 Data: resp[:],
161 CDW10: 1,
162 }); err != nil {
163 return nil, fmt.Errorf("Identify command failed: %w", err)
164 }
165 var raw identifyData
166 binary.Read(bytes.NewReader(resp[:]), binary.LittleEndian, &raw)
167
168 var res IdentifyData
169 res.PCIVendorID = raw.PCIVendorID
170 res.PCISubsystemVendorID = raw.PCISubsystemVendorID
171 res.SerialNumber = string(bytes.TrimRight(raw.SerialNumber[:], " "))
172 res.ModelNumber = string(bytes.TrimRight(raw.ModelNumber[:], " "))
173 res.FirmwareRevision = string(bytes.TrimRight(raw.FirmwareRevision[:], " "))
174 // OUIs are traditionally big-endian, but NVMe exposes them in little-endian
175 res.IEEEOUI[0], res.IEEEOUI[1], res.IEEEOUI[2] = raw.IEEEOUI[2], raw.IEEEOUI[1], raw.IEEEOUI[0]
176 res.IsPCIVirtualFunction = raw.CMIC&(1<<2) != 0
177 res.SpecVersionMajor = uint16(raw.Version >> 16)
178 res.SpecVersionMinor = uint8((raw.Version >> 8) & 0xFF)
179 res.FRUGloballyUniqueIdentifier = raw.FRUGUID
180 res.VirtualizationManagementSupported = raw.OACS&(1<<7) != 0
181 res.NVMeMISupported = raw.OACS&(1<<6) != 0
182 res.DirectivesSupported = raw.OACS&(1<<5) != 0
183 res.SelfTestSupported = raw.OACS&(1<<4) != 0
184 res.NamespaceManagementSupported = raw.OACS&(1<<3) != 0
185 res.FirmwareUpdateSupported = raw.OACS&(1<<2) != 0
186 res.FormattingSupported = raw.OACS&(1<<1) != 0
187 res.SecuritySupported = raw.OACS&(1<<0) != 0
188
189 res.TotalNVMCapacity = raw.TotalNVMCapacity.BigInt()
190 res.UnallocatedNVMCapacity = raw.UnallocatedNVMCapacity.BigInt()
191 res.MaximumNumberOfNamespaces = raw.NumberOfNamespaces
192 return &res, nil
193}