Lorenz Brun | fba5da0 | 2022-12-15 11:20:47 +0000 | [diff] [blame] | 1 | package nvme |
| 2 | |
| 3 | import ( |
| 4 | "bytes" |
| 5 | "encoding/binary" |
| 6 | "fmt" |
| 7 | "math/big" |
| 8 | ) |
| 9 | |
| 10 | // Figure 109 |
| 11 | type 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. |
| 84 | type 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 | |
| 155 | func (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 | } |