blob: 4c41fbc741003867cf34394e5c008159547601ce [file]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_DEVICES_BLOCK_DRIVERS_NVME_COMMANDS_H_
#define SRC_DEVICES_BLOCK_DRIVERS_NVME_COMMANDS_H_
#include <hwreg/bitfields.h>
namespace nvme {
// NVM Express Base Specification 2.0c, section 5 "Admin Command Set".
enum AdminCommandOpcode {
kDeleteIoSubmissionQueue = 0x00,
kCreateIoSubmissionQueue = 0x01,
kGetLogPage = 0x02,
kDeleteIoCompletionQueue = 0x04,
kCreateIoCompletionQueue = 0x05,
kIdentify = 0x06,
kAbort = 0x08,
kSetFeatures = 0x09,
kGetFeatures = 0x0A,
kAsynchronousEventRequest = 0x0C,
kNamespaceManagement = 0x0D,
kFirmwareCommit = 0x10,
kFirmwareImageDownload = 0x11,
kDeviceSelftest = 0x14,
kNamespaceAttachment = 0x15,
kKeepAlive = 0x18,
kDirectiveSend = 0x19,
kDirectiveReceive = 0x1A,
kVirtualizationManagement = 0x1C,
kNVMeMISend = 0x1D,
kNVMeMIReceive = 0x1E,
kCapacityManagement = 0x20,
kLockdown = 0x24,
kDoorbellBufferConfig = 0x7C,
kFabricsCommands = 0x7F,
kFormatNVM = 0x80,
kSecuritySend = 0x81,
kSecurityReceive = 0x82,
kSanitize = 0x84,
kGetLBAStatus = 0x86,
};
// NVM Express Command Set Specification 1.0c, section 3.2 "NVM Command Set Commands".
enum IoCommandOpcode {
kFlush = 0x00,
kWrite = 0x01,
kRead = 0x02,
kWriteUncorrectable = 0x04,
kCompare = 0x05,
kWriteZeroes = 0x08,
kDatasetManagement = 0x09,
kVerify = 0x0C,
kReservationRegister = 0x0D,
kReservationReport = 0x0E,
kReservationAcquire = 0x11,
kReservationRelease = 0x15,
kCopy = 0x19,
};
// NVM Express base specification 2.0, section 3.3.3.1, "Submission Queue Entry"
struct Submission {
template <typename U>
constexpr U& GetSubmission() {
static_assert(std::is_base_of<Submission, U>::value);
static_assert(sizeof(U) == sizeof(Submission));
return *reinterpret_cast<U*>(this);
}
uint32_t command_dword0;
uint32_t namespace_id;
uint32_t command_dword2;
uint32_t command_dword3;
uint64_t metadata_pointer;
uint64_t data_pointer[2];
// The spec refers to them as "dwordN", so we name them like that too.
uint32_t dword10;
uint32_t dword11;
uint32_t dword12;
uint32_t dword13;
uint32_t dword14;
uint32_t dword15;
DEF_SUBFIELD(command_dword0, 31, 16, cid);
DEF_SUBFIELD(command_dword0, 15, 14, data_transfer_mode);
DEF_SUBFIELD(command_dword0, 9, 8, fused);
DEF_SUBFIELD(command_dword0, 7, 0, opcode);
explicit Submission(uint8_t opcode) {
memset(this, 0, sizeof(*this));
set_opcode(opcode);
}
};
static_assert(sizeof(Submission) == 64, "submission struct must be 64 bytes");
enum StatusCodeType {
kGeneric = 0,
kCommandSpecific = 1,
kIntegrityErrors = 2,
kPathRelated = 3,
kVendorSpecific = 7,
};
enum GenericStatus {
kSuccess = 0x0,
kInvalidOpcode = 0x1,
kInvalidField = 0x2,
kCommandIdConflict = 0x3,
kDataTransferError = 0x4,
kAbortedDueToPowerLossNotification = 0x5,
kInternalError = 0x6,
kAbortRequest = 0x7,
kSubmissionQueueDeleted = 0x8,
kFailedFusedCommand = 0x9,
kMissingFusedCommand = 0xa,
kInvalidNamespaceOrFormat = 0xb,
kCommandSequenceError = 0xc,
kInvalidSglSegmentDescriptor = 0xd,
kInvalidSglDescriptorCount = 0xe,
kDataSglLengthInvalid = 0xf,
kMetadataSglLengthInvalid = 0x10,
kSglDescriptorTypeInvalid = 0x11,
kInvalidControllerMemoryUse = 0x12,
kPrpOffsetInvalid = 0x13,
kAtomicWriteUnitExceeded = 0x14,
kOperationDenied = 0x15,
kSglOffsetInvalid = 0x16,
kHostIdentifierInconsistentFormat = 0x18,
kKeepAliveExpired = 0x19,
kKeepAliveInvalid = 0x1a,
kAbortedDueToPreemptAndAbort = 0x1b,
kSanitizeFailed = 0x1c,
kSanitizeInProgress = 0x1d,
kSglDataBlockGranularityInvalid = 0x1e,
kCommandNotSupportedInCmb = 0x1f,
kNamespaceWriteProtected = 0x20,
kCommandInterrupted = 0x21,
kTransientTransportError = 0x22,
kProhibitedByLockdown = 0x23,
kMediaNotReady = 0x24,
kLbaOutOfRange = 0x80,
kCapacityExceeded = 0x81,
kNamespaceNotReady = 0x82,
kReservationConflict = 0x83,
kFormatInProgress = 0x84,
kInvalidValueSize = 0x85,
kInvalidKeySize = 0x86,
kKeyNotExist = 0x87,
kUnrecoveredError = 0x88,
kKeyExists = 0x89,
};
// NVM Express base specification 2.0, section 3.3.3.2, "Common Completion Queue Entry"
struct Completion {
template <typename U>
constexpr U& GetCompletion() {
static_assert(std::is_base_of<Completion, U>::value);
static_assert(sizeof(U) == sizeof(Completion));
return *reinterpret_cast<U*>(this);
}
uint32_t command[2];
uint32_t dwords[2];
// dword 2
DEF_SUBFIELD(dwords[0], 31, 16, sq_id);
DEF_SUBFIELD(dwords[0], 15, 0, sq_head);
// dword 3
DEF_SUBBIT(dwords[1], 31, do_not_retry);
DEF_SUBBIT(dwords[1], 30, more);
DEF_SUBFIELD(dwords[1], 29, 28, command_retry_delay);
DEF_ENUM_SUBFIELD(dwords[1], StatusCodeType, 27, 25, status_code_type);
DEF_SUBFIELD(dwords[1], 24, 17, status_code);
DEF_SUBBIT(dwords[1], 16, phase);
DEF_SUBFIELD(dwords[1], 15, 0, command_id);
} __PACKED;
static_assert(sizeof(Completion) == 16, "completion struct must be 16 bytes");
} // namespace nvme
#endif // SRC_DEVICES_BLOCK_DRIVERS_NVME_COMMANDS_H_