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