/* * Copyright (c) 2021, Pankaj R * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include struct ControllerRegister { u64 cap; u32 vs; u32 intms; u32 intmc; u32 cc; u32 rsvd1; u32 csts; u32 nssr; u32 aqa; u64 asq; u64 acq; u64 rsvd2[505]; }; struct IdentifyNamespace { u64 nsze; u64 ncap; u8 rsdv1[10]; u8 flbas; u8 rsvd2[100]; u32 lbaf[16]; u64 rsvd3[488]; }; // BAR static constexpr u32 BAR_ADDR_MASK = 0xFFFFFFF0; // DOORBELL static constexpr u32 REG_SQ0TDBL_START = 0x1000; static constexpr u32 REG_SQ0TDBL_END = 0x1003; static constexpr u8 DBL_REG_SIZE = 8; // CAP static constexpr u8 CAP_DBL_SHIFT = 32; static constexpr u8 CAP_DBL_MASK = 0xf; static constexpr u8 CAP_TO_SHIFT = 24; static constexpr u64 CAP_TO_MASK = 0xff << CAP_TO_SHIFT; static constexpr u16 MQES(u64 cap) { return (cap & 0xffff) + 1; } static constexpr u32 CAP_TO(u64 cap) { return (cap & CAP_TO_MASK) >> CAP_TO_SHIFT; } // CC – Controller Configuration static constexpr u8 CC_EN_BIT = 0x0; static constexpr u8 CSTS_RDY_BIT = 0x0; static constexpr u8 CSTS_SHST_SHIFT = 2; static constexpr u32 CSTS_SHST_MASK = 0x3 << CSTS_SHST_SHIFT; static constexpr u8 CC_IOSQES_BIT = 16; static constexpr u8 CC_IOCQES_BIT = 20; static constexpr u32 CSTS_SHST(u32 x) { return (x & CSTS_SHST_MASK) >> CSTS_SHST_SHIFT; } static constexpr u16 CC_AQA_MASK = (0xfff); static constexpr u16 ACQ_SIZE(u32 x) { return (x >> 16) & CC_AQA_MASK; } static constexpr u16 ASQ_SIZE(u32 x) { return x & CC_AQA_MASK; } static constexpr u8 CQ_WIDTH = 4; // CQ is 16 bytes(2^4) in size. static constexpr u8 SQ_WIDTH = 6; // SQ size is 64 bytes(2^6) in size. static constexpr u16 CQ_SIZE(u16 q_depth) { return q_depth << CQ_WIDTH; } static constexpr u16 SQ_SIZE(u16 q_depth) { return q_depth << SQ_WIDTH; } static constexpr u8 PHASE_TAG(u16 x) { return x & 0x1; } static constexpr u16 CQ_STATUS_FIELD_MASK = 0xfffe; static constexpr u16 CQ_STATUS_FIELD(u16 x) { return (x & CQ_STATUS_FIELD_MASK) >> 1; } static constexpr u16 IO_QUEUE_SIZE = 64; // TODO:Need to be configurable // IDENTIFY static constexpr u16 NVMe_IDENTIFY_SIZE = 4096; static constexpr u8 NVMe_CNS_ID_ACTIVE_NS = 0x2; static constexpr u8 NVMe_CNS_ID_NS = 0x0; static constexpr u8 FLBA_SIZE_INDEX = 26; static constexpr u8 FLBA_SIZE_MASK = 0xf; static constexpr u8 LBA_FORMAT_SUPPORT_INDEX = 128; static constexpr u32 LBA_SIZE_MASK = 0x00ff0000; // OPCODES // ADMIN COMMAND SET enum AdminCommandOpCode { OP_ADMIN_CREATE_COMPLETION_QUEUE = 0x5, OP_ADMIN_CREATE_SUBMISSION_QUEUE = 0x1, OP_ADMIN_IDENTIFY = 0x6, }; // IO opcodes enum IOCommandOpcode { OP_NVME_WRITE = 0x1, OP_NVME_READ = 0x2 }; // FLAGS static constexpr u8 QUEUE_PHY_CONTIGUOUS = (1 << 0); static constexpr u8 QUEUE_IRQ_ENABLED = (1 << 1); static constexpr u8 QUEUE_IRQ_DISABLED = (0 << 1); struct [[gnu::packed]] NVMeCompletion { LittleEndian cmd_spec; LittleEndian res; LittleEndian sq_head; /* how much of this queue may be reclaimed */ LittleEndian sq_id; /* submission queue that generated this entry */ u16 command_id; /* of the command which completed */ LittleEndian status; /* did the command fail, and if so, why? */ }; struct [[gnu::packed]] DataPtr { LittleEndian prp1; LittleEndian prp2; }; struct [[gnu::packed]] NVMeGenericCmd { LittleEndian nsid; LittleEndian rsvd; LittleEndian metadata; struct DataPtr data_ptr; LittleEndian cdw10; LittleEndian cdw11; LittleEndian cdw12; LittleEndian cdw13; LittleEndian cdw14; LittleEndian cdw15; }; struct [[gnu::packed]] NVMeRWCmd { LittleEndian nsid; LittleEndian rsvd; LittleEndian metadata; struct DataPtr data_ptr; LittleEndian slba; LittleEndian length; LittleEndian control; LittleEndian dsmgmt; LittleEndian reftag; LittleEndian apptag; LittleEndian appmask; }; struct [[gnu::packed]] NVMeIdentifyCmd { LittleEndian nsid; LittleEndian rsvd1[2]; struct DataPtr data_ptr; u8 cns; u8 rsvd2; LittleEndian ctrlid; u8 rsvd3[3]; u8 csi; u64 rsvd4[2]; }; struct [[gnu::packed]] NVMeCreateCQCmd { u32 rsvd1[5]; LittleEndian prp1; u64 rsvd2; LittleEndian cqid; LittleEndian qsize; LittleEndian cq_flags; LittleEndian irq_vector; u64 rsvd12[2]; }; struct [[gnu::packed]] NVMeCreateSQCmd { u32 rsvd1[5]; LittleEndian prp1; u64 rsvd2; LittleEndian sqid; LittleEndian qsize; LittleEndian sq_flags; LittleEndian cqid; u64 rsvd12[2]; }; struct [[gnu::packed]] NVMeSubmission { u8 op; u8 flags; LittleEndian cmdid; union [[gnu::packed]] { NVMeGenericCmd generic; NVMeIdentifyCmd identify; NVMeRWCmd rw; NVMeCreateCQCmd create_cq; NVMeCreateSQCmd create_sq; }; };