This post follows the 3.5.1 Memory-based Transport Controller Initialization of NVM Express Base Specification 2.0b.
You can confirm the code in “.\lib\nvmedevice.ncs”. The function name is “Controller.Initialization”.
import(“dev”, “.\lib\nvmedevice.ncs”)
Controller.Initialization(16, 16, 4, 16)
ListQueue

* Preprocessing
import(“dev”, “.\lib\nvmedevice.ncs”)
Controller.Initialization = function(asqs, acqs, ioqcount, ioqs)
// asqs – The size of admin submission queue
// acqs – The size of admin submission queue
// ioqcount – The count of IO queue
// ioqs – The size of IO queue
1. The host waits for the controller to indicate that any previous reset is complete by waiting for CSTS.RDY to become ‘0’;
if Controller.Status == “enabled” then
if(Controller.Disable() == false) then
return false
end if
end if
2. The host configures the Admin Queue by setting the Admin Queue Attributes (AQA), Admin Submission Queue Base Address (ASQ), and Admin Completion Queue Base Address (ACQ) to appropriate values;
// Setting the AQA
AQAval = acqs-1
AQAval = BitShiftLeft32(AQAval, 16)
AQAval = BitOr32(AQAval, asqs-1)
CtrlProperty.Set(CtrlProperty.AQA, AQAval)
// Setting the ASQ
asqmem = new PCMEM
asqmem.PCMem_Assign(asqs*64, true)
CtrlProperty.Set(CtrlProperty.ASQ_l, asqmem.address_l)
CtrlProperty.Set(CtrlProperty.ASQ_u, asqmem.address_u)
// Setting the ACQ
acqmem = new PCMEM
acqmem.PCMem_Assign(acqs*16, true)
CtrlProperty.Set(CtrlProperty.ACQ_l, acqmem.address_l)
CtrlProperty.Set(CtrlProperty.ACQ_u, acqmem.address_u)
3. The host determines the supported I/O Command Sets by checking the state of CAP.CSS and appropriately initializing CC.CSS as follows:
a. If the CAP.CSS bit 7 is set to ‘1’, then the CC.CSS field should be set to 111b;
b. If the CAP.CSS bit 6 is set to ‘1’, then the CC.CSS field should be set to 110b;
c. If the CAP.CSS bit 6 is cleared to ‘0’ and bit 0 is set to ‘1’, then the CC.CSS field should be set
to 000b;
CAPuval = CtrlProperty.Get(CtrlProperty.CAP_u)
CAP_CSS = BitShiftRight32(CAPuval, 5)
CAP_CSS = BitAnd32(CAP_CSS, 0x000000FF)
if BitAnd32(CAP_CSS, 0x80) != 0 then
CCval = CtrlProperty.Get(CtrlProperty.CC)
CCval = BitAnd32(CCval, BitNot32(0x00000070))
CC_CSS = BitShiftLeft32(7, 4)
CCval = BitOr32(CCval, CC_CSS)
CtrlProperty.Set(CtrlProperty.CC, CCval)
end if
if BitAnd32(CAP_CSS, 0x40) != 0 then
CCval = CtrlProperty.Get(CtrlProperty.CC)
CCval = BitAnd32(CCval , BitNot32(0x00000070))
CC_CSS = BitShiftLeft32(6, 4)
CCval = BitOr32(CCval, CC_CSS)
CtrlProperty.Set(CtrlProperty.CC, CCval)
end if
if BitAnd32(CAP_CSS, 0x40) == 0 then
if BitAnd32(CAP_CSS, 0x01) == 1 then
CCval = CtrlProperty.Get(CtrlProperty.CC)
CCval = BitAnd32(CCval , BitNot32(0x00000070))
CC_CSS = BitShiftLeft32(0, 4)
CCval = BitOr32(CCval, CC_CSS)
CtrlProperty.Set(CtrlProperty.CC, CCval)
end if
end if
4. The controller settings should be configured. Specifically:
a. The arbitration mechanism should be selected in CC.AMS; and
b. The memory page size should be initialized in CC.MPS;
// Setting CC
// CC.IOCQES
CCval = CtrlProperty.Get(CtrlProperty.CC)
CCval = BitAnd32(CCval, BitNot32(BitShiftLeft32(0x0F, 20)))
CCval = BitOr32(CCval, BitShiftLeft32(0x04, 20))
CtrlProperty.Set(CtrlProperty.CC, CCval);
// CC.IOSQES
CCval = CtrlProperty.Get(CtrlProperty.CC)
CCval = BitAnd32(CCval, BitNot32(BitShiftLeft32(0x0F, 16)))
CCval = BitOr32(CCval, BitShiftLeft32(0x06, 16))
CtrlProperty.Set(CtrlProperty.CC, CCval);
// CC.AMS
CCval = CtrlProperty.Get(CtrlProperty.CC)
CCval = BitAnd32(CCval, BitNot32(BitShiftLeft32(0x07, 11)))
CCval = BitOr32(CCval, BitShiftLeft32(0x00, 11))
CtrlProperty.Set(CtrlProperty.CC, CCval);
// CC.MPS
CCval = CtrlProperty.Get(CtrlProperty.CC)
CCval = BitAnd32(CCval, BitNot32(BitShiftLeft32(0x07, 7)))
CCval = BitOr32(CCval, BitShiftLeft32(0x00, 7))
CtrlProperty.Set(CtrlProperty.CC, CCval);
5. The host enables the controller by setting CC.EN to ‘1’;
6. The host waits for the controller to indicate that the controller is ready to process commands. The controller is ready to process commands when CSTS.RDY is set to ‘1’;
if(Controller.Enable() == false) then
return false
end if
7. The host determines the configuration of the controller by issuing the Identify command specifying the Identify Controller data structure (i.e., CNS 01h);
iddata = new DATAMEM
iddata.DataMem_Assign(4096)
asqe = new SQE
asqe.opc = AdminCommand.Identify.opcode
asqe.datamem = iddata
asqe.cdw10 = 1
asqe.Sqe_SubmitTailSync(0, 0.5)
8. The host determines any I/O Command Set specific configuration information as follows:
a. If the CC.CSS field is set to 000b, then the host should determine the configuration of each
namespace by issuing the Identify command for each namespace, specifying the Identify
Namespace data structure (CNS 00h);
CC_CSSval = BitAnd32(BitShiftRight32(CtrlProperty.Get(CtrlProperty.CC), 4), 0x07)
if (CC_CSSval == 0x00) then
iddata = new DATAMEM
iddata.DataMem_Assign(4096)
asqe = new SQE
asqe.opc = AdminCommand.Identify.opcode
asqe.datamem = iddata
asqe.ns = 1
asqe.cdw10 = 0
asqe.Sqe_SubmitTailSync(0, 0.5)
end if
b. If the CAP.CSS bit 6 is set to ‘1’, then the host does the following:
CAP_CSSval = BitAnd32(BitShiftRight32(CtrlProperty.Get(CtrlProperty.CAP_u), 5), 0xFF)
CAP_CSS_bit6 = BitAnd32(BitShiftRight32(CAP_CSSval, 6), 0x01)
if (CAP_CSS_bit6 == 1) then
iddata = new DATAMEM
iddata.DataMem_Assign(4096)
asqe = new SQE
asqe.opc = AdminCommand.Identify.opcode
asqe.datamem = iddata
asqe.ns = 0
asqe.cdw10 = 0x1C
asqe.Sqe_SubmitTailSync(0, 0.5)
end if
9. If the controller implements I/O queues, then the host should determine the number of I/O Submission Queues and I/O Completion Queues supported using the Set Features command with the Number of Queues feature identifier. After determining the number of I/O Queues, the NVMe Transport specific interrupt registers (e.g. MSI and/or MSI-X registers) should be configured;
asqe = new SQE
asqe.opc = AdminCommand.SetFeatures.opcode
asqe.cdw10 = FeatureId.NumberofQueues.FID
asqe.cdw11 = BitShiftLeft32((ioqs-1), 16)
asqe.cdw11 = BitOr32(asqe.cdw11, (ioqs-1))
asqe.Sqe_SubmitTailSync(0, 1)
10. If the controller implements I/O queues, then the host should allocate the appropriate number of I/O Completion Queues based on the number required for the system configuration and the number supported by the controller. The I/O Completion Queues are allocated using the Create I/O Completion Queue command;
for qid in range (1, ioqcount)
iocqmem = new PCMEM
iocqmem.PCMem_Assign(ioqs*16, true)
asqe = new SQE
asqe.pcmem = iocqmem
asqe.opc = AdminCommand.CreateIoCompletionQueue.opcode
asqe.cdw10 = BitShiftLeft32((ioqs-1), 16)
asqe.cdw10 = BitOr32(asqe.cdw10, qid)
asqe.cdw11 = BitShiftLeft32(1, 1)
asqe.cdw11 = BitOr32(asqe.cdw11, BitShiftLeft32(1, 0))
asqe.Sqe_SubmitTailSync(0, 1)
end for
11. If the controller implements I/O queues, then the host should allocate the appropriate number of I/O Submission Queues based on the number required for the system configuration and the number
supported by the controller. The I/O Submission Queues are allocated using the Create I/O Submission Queue command;
for qid in range (1, ioqcount)
iosqmem = new PCMEM
iosqmem.PCMem_Assign(ioqs*64, true)
asqe = new SQE
asqe.pcmem = iosqmem
asqe.opc = AdminCommand.CreateIoSubmissionQueue.opcode
asqe.cdw10 = BitShiftLeft32((ioqs-1), 16)
asqe.cdw10 = BitOr32(asqe.cdw10, qid)
asqe.cdw11 = BitShiftLeft32(qid, 16)
asqe.cdw11 = BitOr32(asqe.cdw11, BitShiftLeft32(2, 1))
asqe.cdw11 = BitOr32(asqe.cdw11, BitShiftLeft32(1, 0))
asqe.Sqe_SubmitTailSync(0, 1)
end for
Share this post: on Twitter on Facebook