| package nvme |
| |
| import ( |
| "bytes" |
| "encoding/binary" |
| "fmt" |
| "math/big" |
| ) |
| |
| // Figure 109 |
| type identifyData struct { |
| // Controller Capabilities and Features |
| PCIVendorID uint16 |
| PCISubsystemVendorID uint16 |
| SerialNumber [20]byte |
| ModelNumber [40]byte |
| FirmwareRevision [8]byte |
| RecommendedArbitrationBurst uint8 |
| IEEEOUI [3]byte |
| CMIC uint8 |
| MaximumDataTransferSize uint8 |
| ControllerID uint16 |
| Version uint32 |
| RuntimeD3ResumeLatency uint32 |
| RuntimeD3EntryLatency uint32 |
| OAES uint32 |
| CTRATT uint32 |
| _ [12]byte |
| FRUGUID [16]byte |
| _ [128]byte |
| // Admin Command Set Attributes & Optional Controller Capabilities |
| OACS uint16 |
| AbortCommandLimit uint8 |
| AsynchronousEventRequestLimit uint8 |
| FRMW uint8 |
| LPA uint8 |
| ErrorLogPageEntries uint8 |
| NumberOfPowerStatesSupport uint8 |
| AdminVendorSpecificCmdConfig uint8 |
| AutonomousPowerStateTransitionAttrs uint8 |
| WarningCompositeTempThreshold uint16 |
| CriticalCompositeTempThreshold uint16 |
| MaximumTimeForFirmwareActivation uint16 |
| HostMemoryBufferPreferredSize uint32 |
| HostMemoryBufferMinimumSize uint32 |
| TotalNVMCapacity uint128le |
| UnallocatedNVMCapacity uint128le |
| ReplyProtectedMemoryBlockSupport uint32 |
| ExtendedDeviceSelfTestTime uint16 |
| DeviceSelfTestOptions uint8 |
| FirmwareUpdateGranularity uint8 |
| KeepAliveSupport uint16 |
| HostControlledThermalMgmtAttrs uint16 |
| MinimumThermalMgmntTemp uint16 |
| MaximumThermalMgmntTemp uint16 |
| SanitizeCapabilities uint32 |
| _ [180]byte |
| // NVM Command Set Attributes |
| SubmissionQueueEntrySize uint8 |
| CompletionQueueEntrySize uint8 |
| MaximumOutstandingCommands uint16 |
| NumberOfNamespaces uint32 |
| OptionalNVMCommandSupport uint16 |
| FusedOperationSupport uint16 |
| FormatNVMAttributes uint8 |
| VolatileWriteCache uint8 |
| AtomicWriteUnitNormal uint16 |
| AtomicWriteUnitPowerFail uint16 |
| NVMVendorSepcificCommandConfig uint8 |
| AtomicCompareAndWriteUnit uint16 |
| _ [2]byte |
| SGLSupport uint32 |
| _ [228]byte |
| NVMSubsystemNVMeQualifiedName [256]byte |
| _ [1024]byte |
| // Power State Descriptors |
| PowerStateDescriptors [32][32]byte |
| } |
| |
| // IdentifyData contains various identifying information about a NVMe |
| // controller. Because the actual data structure is very large, currently not |
| // all fields are exposed as properly-typed individual fields. If you need |
| // a new field, please add it to this structure. |
| type IdentifyData struct { |
| // PCIVendorID contains the company vendor identifier assigned by the PCI |
| // SIG. |
| PCIVendorID uint16 |
| // PCISubsystemVendorID contains the company vendor identifier that is |
| // assigned by the PCI SIG for the subsystem. |
| PCISubsystemVendorID uint16 |
| // SerialNumber contains the serial number for the NVM subsystem that is |
| // assigned by the vendor. |
| SerialNumber string |
| // ModelNumber contains the model number for the NVM subsystem that is |
| // assigned by the vendor. |
| ModelNumber string |
| // FirmwareRevision contains the currently active firmware revision for the |
| // NVM subsystem. |
| FirmwareRevision string |
| // IEEEOUI contains the Organization Unique Identifier for the controller |
| // vendor as assigned by the IEEE. |
| IEEEOUI [3]byte |
| |
| // IsPCIVirtualFunction indicates if the controller is a virtual controller |
| // as part of a PCI virtual function. |
| IsPCIVirtualFunction bool |
| |
| // SpecVersionMajor/Minor contain the version of the NVMe specification the |
| // controller supports. Only mandatory from spec version 1.2 onwards. |
| SpecVersionMajor uint16 |
| SpecVersionMinor uint8 |
| |
| // FRUGloballyUniqueIdentifier contains a 128-bit value that is globally |
| // unique for a given Field Replaceable Unit (FRU). Contains all-zeroes if |
| // unavailable. |
| FRUGloballyUniqueIdentifier [16]byte |
| // VirtualizationManagementSupported indicates if the controller |
| // supports the Virtualization Management command. |
| VirtualizationManagementSupported bool |
| // NVMeMISupported indicates if the controller supports the NVMe-MI |
| // Send and Receive commands. |
| NVMeMISupported bool |
| // DirectivesSupported indicates if the controller supports the |
| // Directive Send and Receive commands. |
| DirectivesSupported bool |
| // SelfTestSupported indicates if the controller supports the Device Self- |
| // test command. |
| SelfTestSupported bool |
| // NamespaceManagementSupported indicates if the controller supports the |
| // Namespace Management and Attachment commands. |
| NamespaceManagementSupported bool |
| // FirmwareUpdateSupported indicates if the controller supports the |
| // Firmware Commit and Image Download commands. |
| FirmwareUpdateSupported bool |
| // FormattingSupported indicates if the controller supports the Format |
| // command. |
| FormattingSupported bool |
| // SecuritySupported indicates if the controller supports the Security Send |
| // and Receive commands. |
| SecuritySupported bool |
| |
| // TotalNVMCapacity contains the total NVM capacity in bytes in the NVM |
| // subsystem. This can be 0 on devices without NamespaceManagementSupported. |
| TotalNVMCapacity *big.Int |
| // UnallocatedNVMCapacity contains the unallocated NVM capacity in bytes in |
| // the NVM subsystem. This can be 0 on devices without |
| // NamespaceManagementSupported. |
| UnallocatedNVMCapacity *big.Int |
| |
| // MaximumNumberOfNamespace defines the maximum number of namespaces |
| // supported by the controller. |
| MaximumNumberOfNamespaces uint32 |
| } |
| |
| func (d *Device) Identify() (*IdentifyData, error) { |
| var resp [4096]byte |
| |
| if err := d.RawCommand(&Command{ |
| Opcode: 0x06, |
| Data: resp[:], |
| CDW10: 1, |
| }); err != nil { |
| return nil, fmt.Errorf("Identify command failed: %w", err) |
| } |
| var raw identifyData |
| binary.Read(bytes.NewReader(resp[:]), binary.LittleEndian, &raw) |
| |
| var res IdentifyData |
| res.PCIVendorID = raw.PCIVendorID |
| res.PCISubsystemVendorID = raw.PCISubsystemVendorID |
| res.SerialNumber = string(bytes.TrimRight(raw.SerialNumber[:], " ")) |
| res.ModelNumber = string(bytes.TrimRight(raw.ModelNumber[:], " ")) |
| res.FirmwareRevision = string(bytes.TrimRight(raw.FirmwareRevision[:], " ")) |
| // OUIs are traditionally big-endian, but NVMe exposes them in little-endian |
| res.IEEEOUI[0], res.IEEEOUI[1], res.IEEEOUI[2] = raw.IEEEOUI[2], raw.IEEEOUI[1], raw.IEEEOUI[0] |
| res.IsPCIVirtualFunction = raw.CMIC&(1<<2) != 0 |
| res.SpecVersionMajor = uint16(raw.Version >> 16) |
| res.SpecVersionMinor = uint8((raw.Version >> 8) & 0xFF) |
| res.FRUGloballyUniqueIdentifier = raw.FRUGUID |
| res.VirtualizationManagementSupported = raw.OACS&(1<<7) != 0 |
| res.NVMeMISupported = raw.OACS&(1<<6) != 0 |
| res.DirectivesSupported = raw.OACS&(1<<5) != 0 |
| res.SelfTestSupported = raw.OACS&(1<<4) != 0 |
| res.NamespaceManagementSupported = raw.OACS&(1<<3) != 0 |
| res.FirmwareUpdateSupported = raw.OACS&(1<<2) != 0 |
| res.FormattingSupported = raw.OACS&(1<<1) != 0 |
| res.SecuritySupported = raw.OACS&(1<<0) != 0 |
| |
| res.TotalNVMCapacity = raw.TotalNVMCapacity.BigInt() |
| res.UnallocatedNVMCapacity = raw.UnallocatedNVMCapacity.BigInt() |
| res.MaximumNumberOfNamespaces = raw.NumberOfNamespaces |
| return &res, nil |
| } |