void InvalidQID_r10b::RunCoreTest() { /** \verbatim * Assumptions: * None. * \endverbatim */ string work; bool enableLog; uint64_t maxIOQEntries = 2; if (gCtrlrConfig->SetState(ST_DISABLE_COMPLETELY) == false) throw FrmwkEx(HERE); LOG_NRM("Create admin queues ACQ and ASQ"); SharedACQPtr acq = SharedACQPtr(new ACQ(gDutFd)); acq->Init(5); SharedASQPtr asq = SharedASQPtr(new ASQ(gDutFd)); asq->Init(5); // All queues will use identical IRQ vector IRQ::SetAnySchemeSpecifyNum(1); gCtrlrConfig->SetCSS(CtrlrConfig::CSS_NVM_CMDSET); if (gCtrlrConfig->SetState(ST_ENABLE) == false) throw FrmwkEx(HERE); // Calc X, max no. of IOCQ's DUT supports. uint32_t X = gInformative->GetFeaturesNumOfIOCQs(); LOG_NRM("Maximum num of IOCQ's DUT will support = %d", X); LOG_NRM("Setup element size for the IOCQ"); gCtrlrConfig->SetIOCQES(gInformative->GetIdentifyCmdCtrlr()-> GetValue(IDCTRLRCAP_CQES) & 0xf); LOG_NRM("Issue CreateIOCQ cmds with QID's ranging from %d to %d", (X + 1), MAX_IOQ_ID); list<uint32_t> illegalQIDs = GetIllegalQIDs(X + 1); for (list<uint32_t>::iterator qId = illegalQIDs.begin(); qId != illegalQIDs.end(); qId++) { LOG_NRM("Process each CreateIOCQCmd with iocq id #%d", *qId); SharedIOCQPtr iocq = SharedIOCQPtr(new IOCQ(gDutFd)); iocq->Init(*qId, maxIOQEntries, true, 0); SharedCreateIOCQPtr createIOCQCmd = SharedCreateIOCQPtr(new CreateIOCQ()); createIOCQCmd->Init(iocq); work = str(boost::format("iocqId.%d") % *qId); enableLog = false; if ((*qId <= (X + 8)) || (*qId >= (MAX_IOQ_ID - 8))) enableLog = true; LOG_NRM("Send and reap cmd with CQ ID #%d", *qId); IO::SendAndReapCmd(mGrpName, mTestName, CALC_TIMEOUT_ms(1), asq, acq, createIOCQCmd, work, enableLog, CESTAT_INVALID_QID); } }
void IllegalCreateQs_r10b::RunCoreTest() { /** \verbatim * Assumptions: * 1) Test CreateResources_r10b has run prior. * \endverbatim */ // Lookup objs which were created in a prior test within group SharedACQPtr acq = CAST_TO_ACQ(gRsrcMngr->GetObj(ACQ_GROUP_ID)) SharedASQPtr asq = CAST_TO_ASQ(gRsrcMngr->GetObj(ASQ_GROUP_ID)) uint32_t numEntries = 2; uint8_t dword; uint32_t mask; uint32_t value; { LOG_NRM("Create IOCQ ID #%d but toxify its QID to 0", IOQ_ID); SharedIOCQPtr iocq = SharedIOCQPtr(new IOCQ(mFd)); iocq->Init(IOQ_ID, numEntries, true, 0); LOG_NRM("Form a Create IOCQ cmd"); SharedCreateIOCQPtr iocqCmd = SharedCreateIOCQPtr(new CreateIOCQ()); iocqCmd->Init(iocq); dword = 10; mask = 0xFFFF; value = 0; SendToxicCmd(asq, acq, iocqCmd, dword, mask, value, CESTAT_INVALID_QID); } { LOG_NRM("Create IOSQ ID #%d but toxify its QID to 0", IOQ_ID); SharedIOSQPtr iosq = SharedIOSQPtr(new IOSQ(mFd)); iosq->Init(IOQ_ID, numEntries, IOQ_ID, 0); LOG_NRM("Form a Create IOSQ cmd"); SharedCreateIOSQPtr iosqCmd = SharedCreateIOSQPtr(new CreateIOSQ()); iosqCmd->Init(iosq); dword = 10; mask = 0xFFFF; value = 0; SendToxicCmd(asq, acq, iosqCmd, dword, mask, value, CESTAT_INVALID_QID); } { LOG_NRM("Create IOSQ ID #%d but wrongly associate to ACQ", IOQ_ID); SharedIOSQPtr iosq = SharedIOSQPtr(new IOSQ(mFd)); iosq->Init(IOQ_ID, numEntries, IOQ_ID, 0); LOG_NRM("Form a Create IOSQ cmd"); SharedCreateIOSQPtr iosqCmd = SharedCreateIOSQPtr(new CreateIOSQ()); iosqCmd->Init(iosq); dword = 11; mask = 0xFFFF0000; value = 0; SendToxicCmd(asq, acq, iosqCmd, dword, mask, value, CESTAT_CQ_INVALID); } }
void CIDAcceptedIOSQ_r10b::RunCoreTest() { /** \verbatim * Assumptions: * None. * \endverbatim */ if (gCtrlrConfig->SetState(ST_DISABLE_COMPLETELY) == false) throw FrmwkEx(HERE); LOG_NRM("Create ACQ and ASQ objects which have test life time"); SharedACQPtr acq = CAST_TO_ACQ(SharedACQPtr(new ACQ(gDutFd))) acq->Init(5); SharedASQPtr asq = CAST_TO_ASQ(SharedASQPtr(new ASQ(gDutFd))) asq->Init(5); IRQ::SetAnySchemeSpecifyNum(2); // throws upon error gCtrlrConfig->SetCSS(CtrlrConfig::CSS_NVM_CMDSET); if (gCtrlrConfig->SetState(ST_ENABLE) == false) throw FrmwkEx(HERE); vector<SharedIOSQPtr> iosqs; SharedIOCQPtr iocq; InitTstRsrcs(asq, acq, iosqs, iocq); SharedWritePtr writeCmd = CreateWriteCmd(); LOG_NRM("Learn initial unique command id assigned by dnvme"); uint16_t curCID; vector <SharedIOSQPtr>::iterator iosq; for (iosq = iosqs.begin(); iosq != iosqs.end(); iosq++) (*iosq)->Send(writeCmd, curCID); uint16_t prevCID = curCID; for (uint32_t nCmds = 0; nCmds < MAX_CMDS; nCmds++) { for (iosq = iosqs.begin(); iosq != iosqs.end(); iosq++) { LOG_NRM("(nCmds, curCID, prevCID, SQ ID) = (%d, %d, %d, %d)", nCmds, curCID, prevCID, (*iosq)->GetQId()); (*iosq)->Ring(); ReapVerifyCID(*iosq, iocq, prevCID); (*iosq)->Send(writeCmd, curCID); if (curCID != (uint16_t)(prevCID + 1)) { (*iosq)->Dump(FileSystem::PrepDumpFile(mGrpName, mTestName, "iosq.fail." + (*iosq)->GetQId()), "Dump Entire IOSQ"); iocq->Dump(FileSystem::PrepDumpFile(mGrpName, mTestName, "iocq.fail." + iocq->GetQId()), "Dump Entire IOCQ"); throw FrmwkEx(HERE, "curCID(%d) != (prevCID + 1)(%d)", curCID, (prevCID + 1)); } } prevCID = curCID; } }
void InvalidNamspc_r10b::RunCoreTest() { /** \verbatim * Assumptions: * 1) Test CreateResources_r10b has run prior. * \endverbatim */ uint64_t inc, i; string work; uint32_t numCE; uint32_t isrCountB4; LOG_NRM("Lookup objs which were created in a prior test within group"); SharedIOSQPtr iosq = CAST_TO_IOSQ(gRsrcMngr->GetObj(IOSQ_GROUP_ID)); SharedIOCQPtr iocq = CAST_TO_IOCQ(gRsrcMngr->GetObj(IOCQ_GROUP_ID)); if ((numCE = iocq->ReapInquiry(isrCountB4, true)) != 0) { iocq->Dump( FileSystem::PrepDumpFile(mGrpName, mTestName, "iocq", "notEmpty"), "Test assumption have not been met"); throw FrmwkEx(HERE, "Require 0 CE's within CQ %d, not upheld, found %d", iocq->GetQId(), numCE); } LOG_NRM("Setup write cmd's values that won't change per namspc"); SharedMemBufferPtr writeMem = SharedMemBufferPtr(new MemBuffer()); uint64_t lbaDataSize = 512; writeMem->Init(lbaDataSize); SharedWritePtr writeCmd = SharedWritePtr(new Write()); send_64b_bitmask prpBitmask = (send_64b_bitmask) (MASK_PRP1_PAGE | MASK_PRP2_PAGE | MASK_PRP2_LIST); writeCmd->SetPrpBuffer(prpBitmask, writeMem); writeCmd->SetNLB(0); // convert to 0-based value writeCmd->SetSLBA(0); LOG_NRM("For all namspc's issue cmd to an illegal namspc"); ConstSharedIdentifyPtr idCtrlrStruct = gInformative->GetIdentifyCmdCtrlr(); uint32_t nn = (uint32_t)idCtrlrStruct->GetValue(IDCTRLRCAP_NN); if (nn == 0 ) { throw FrmwkEx(HERE, "Required to support >= 1 namespace"); } for (i = (nn + 1), inc = 1; i <= 0xffffffff; i += (2 * inc), inc += 1327) { LOG_NRM("Issue flush cmd with illegal namspc ID=%llu", (unsigned long long)i); writeCmd->SetNSID(i); work = str(boost::format("namspc%d") % i); SendCmdToHdw(iosq, iocq, writeCmd, work); } }
void WriteDataPat_r10b::SendToIOSQ(SharedIOSQPtr iosq, SharedIOCQPtr iocq, SharedWritePtr writeCmd, string qualifier) { uint32_t numCE; uint32_t ceRemain; uint32_t numReaped; uint32_t isrCount; uint16_t uniqueId; LOG_NRM("Send the cmd to hdw via %s IOSQ", qualifier.c_str()); iosq->Send(writeCmd, uniqueId); iosq->Dump(FileSystem::PrepDumpFile(mGrpName, mTestName, "iosq", qualifier), "Just B4 ringing SQ doorbell, dump entire IOSQ contents"); iosq->Ring(); LOG_NRM("Wait for the CE to arrive in IOCQ"); if (iocq->ReapInquiryWaitSpecify(CALC_TIMEOUT_ms(1), 1, numCE, isrCount) == false) { iocq->Dump( FileSystem::PrepDumpFile(mGrpName, mTestName, "iocq", qualifier), "Unable to see any CE's in IOCQ, dump entire CQ contents"); throw FrmwkEx(HERE, "Unable to see completion of cmd"); } else if (numCE != 1) { iocq->Dump( FileSystem::PrepDumpFile(mGrpName, mTestName, "iocq", qualifier), "Unable to see any CE's in IOCQ, dump entire CQ contents"); throw FrmwkEx(HERE, "The IOCQ should only have 1 CE as a result of a cmd"); } iocq->Dump(FileSystem::PrepDumpFile(mGrpName, mTestName, "iocq", qualifier), "Just B4 reaping IOCQ, dump entire CQ contents"); LOG_NRM("The CQ's metrics B4 reaping holds head_ptr needed"); struct nvme_gen_cq iocqMetrics = iocq->GetQMetrics(); KernelAPI::LogCQMetrics(iocqMetrics); LOG_NRM("Reaping CE from IOCQ, requires memory to hold reaped CE"); SharedMemBufferPtr ceMemIOCQ = SharedMemBufferPtr(new MemBuffer()); if ((numReaped = iocq->Reap(ceRemain, ceMemIOCQ, isrCount, numCE, true)) != 1) { throw FrmwkEx(HERE, "Verified there was 1 CE, but reaping produced %d", numReaped); } LOG_NRM("The reaped CE is..."); iocq->LogCE(iocqMetrics.head_ptr); union CE ce = iocq->PeekCE(iocqMetrics.head_ptr); ProcessCE::Validate(ce); // throws upon error }
void ManyCmdSubmit_r10b::LogCEAndCQMetrics(SharedIOCQPtr iocq) { struct nvme_gen_cq iocqMetrics = iocq->GetQMetrics(); union CE ce = iocq->PeekCE(iocqMetrics.head_ptr); LOG_NRM("Logging Completion Element (CE)..."); LOG_NRM(" CE DWORD0: 0x%08X", ce.t.dw0); LOG_NRM(" CE DWORD1: 0x%08X", ce.t.dw1); LOG_NRM(" CE DWORD2: 0x%08X", ce.t.dw2); LOG_NRM(" CE DWORD3: 0x%08X", ce.t.dw3); LOG_NRM("dnvme metrics pertaining to CQ ID: %d", iocqMetrics.q_id); LOG_NRM(" tail_ptr = %d", iocqMetrics.tail_ptr); LOG_NRM(" head_ptr = %d", iocqMetrics.head_ptr); LOG_NRM(" elements = %d", iocqMetrics.elements); LOG_NRM(" irq_enabled = %s", iocqMetrics.irq_enabled ? "T" : "F"); LOG_NRM(" irq_no = %d", iocqMetrics.irq_no); LOG_NRM(" pbit_new_entry = %d", iocqMetrics.pbit_new_entry); }
void IOQRollChkDiff_r10b::ReapAndVerifyCE(SharedIOCQPtr iocq, uint32_t expectedVal) { uint32_t numCE; uint32_t ceRemain; uint32_t numReaped; uint32_t isrCount; LOG_NRM("Wait for the CE to arrive in IOCQ %d", iocq->GetQId()); if (iocq->ReapInquiryWaitSpecify(DEFAULT_CMD_WAIT_ms, 1, numCE, isrCount) == false) { iocq->Dump(FileSystem::PrepDumpFile(mGrpName, mTestName, "iocq", "reapInq"), "Unable to see any CE's in IOCQ, dump entire CQ contents"); throw FrmwkEx(HERE, "Unable to see completion of cmd"); } else if (numCE != 1) { throw FrmwkEx(HERE, "The IOCQ should only have 1 CE as a result of a cmd"); } LOG_NRM("The CQ's metrics before reaping holds head_ptr"); struct nvme_gen_cq iocqMetrics = iocq->GetQMetrics(); LOG_NRM("Reaping CE from IOCQ, requires memory to hold reaped CE"); SharedMemBufferPtr ceMemIOCQ = SharedMemBufferPtr(new MemBuffer()); if ((numReaped = iocq->Reap(ceRemain, ceMemIOCQ, isrCount, numCE, true)) != 1) { throw FrmwkEx(HERE, "Verified there was 1 CE, but reaping produced %d", numReaped); } union CE ce = iocq->PeekCE(iocqMetrics.head_ptr); ProcessCE::Validate(ce, CESTAT_SUCCESS); // throws upon error if (ce.n.SQID != IOQ_ID) { iocq->Dump( FileSystem::PrepDumpFile(mGrpName, mTestName, "iocq", "CE.SQID"), "CE SQ ID Inconsistent"); throw FrmwkEx(HERE, "Expected CE.SQID = 0x%04X in IOCQ CE but actual " "CE.SQID = 0x%04X", IOQ_ID, ce.n.SQID); } if (ce.n.SQHD != expectedVal) { iocq->Dump( FileSystem::PrepDumpFile(mGrpName, mTestName, "iocq", "CE.SQHD"), "CE SQ Head Pointer Inconsistent"); throw FrmwkEx(HERE, "Expected CE.SQHD = 0x%04X in IOCQ CE but actual " "CE.SQHD = 0x%04X", expectedVal, ce.n.SQHD); } }
void SQCQSizeMismatch_r10b::ReapVerifyOnCQ(SharedIOCQPtr iocq, SharedIOSQPtr iosq) { uint32_t numCE; uint32_t ceRemain; uint32_t numReaped; uint32_t isrCount; SharedMemBufferPtr ceMemIOCQ = SharedMemBufferPtr(new MemBuffer()); for (uint32_t nCmds = 1; nCmds < iocq->GetNumEntries(); nCmds++) { LOG_NRM("Wait for the CE to arrive in IOCQ"); if (iocq->ReapInquiryWaitSpecify(CALC_TIMEOUT_ms(1), 1, numCE, isrCount) == false) { iocq->Dump( FileSystem::PrepDumpFile(mGrpName, mTestName, "iocq", "reapInq"), "Unable to see any CE's in IOCQ, dump entire CQ contents"); throw FrmwkEx(HERE, "Unable to see completion of cmd"); } LOG_NRM("The CQ's metrics B4 reaping holds head_ptr needed"); struct nvme_gen_cq iocqMetrics = iocq->GetQMetrics(); KernelAPI::LogCQMetrics(iocqMetrics); if ((numReaped = iocq->Reap(ceRemain, ceMemIOCQ, isrCount, 1, true)) != 1) { iocq->Dump( FileSystem::PrepDumpFile(mGrpName, mTestName, "iocq", "reap"), "Unable to see any CE's in IOCQ, dump entire CQ contents"); throw FrmwkEx(HERE, "Verified there was 1 CE, but reaping failed"); } LOG_NRM("The reaped CE is..."); iocq->LogCE(iocqMetrics.head_ptr); union CE ce = iocq->PeekCE(iocqMetrics.head_ptr); ProcessCE::Validate(ce); // throws upon error if (ce.n.SQID != iosq->GetQId()) { iocq->Dump( FileSystem::PrepDumpFile(mGrpName, mTestName, "iocq", "sqId"), "Wrong SQID in the CE of IOCQ, dump entire CQ contents"); throw FrmwkEx(HERE, "Invalid SQID %d in CE, expected SQID", ce.n.SQID, iosq->GetQId()); } } }
void MaxIOQMSIXManyTo1_r10b::SendCmdAndReap(SharedIOSQPtr iosq, SharedIOCQPtr iocq, SharedCmdPtr cmd, uint32_t anticipatedIrqs) { uint16_t uniqueId; uint32_t numCE; string work; uint32_t isrCount; LOG_NRM("Send the cmd to hdw via IOSQ #%d", iosq->GetQId()); iosq->Send(cmd, uniqueId); work = str(boost::format("ioqId.%d.%s") % iosq->GetQId() % cmd->GetName().c_str()); iosq->Dump(FileSystem::PrepDumpFile(mGrpName, mTestName, "iosq", work), "Just B4 ringing doorbell, dump IOSQ"); iosq->Ring(); LOG_NRM("Wait for the CE to arrive in CQ %d", iocq->GetQId()); if (iocq->ReapInquiryWaitSpecify(DEFAULT_CMD_WAIT_ms, 1, numCE, isrCount) == false) { iocq->Dump(FileSystem::PrepDumpFile(mGrpName, mTestName, "iocq.fail", work), "Dump Entire IOCQ"); iosq->Dump(FileSystem::PrepDumpFile(mGrpName, mTestName, "iosq.fail", work), "Dump Entire IOSQ"); throw FrmwkEx(HERE, "Unable to see CEs for issued cmd"); } work = str(boost::format("iocq.%d") % uniqueId); IO::ReapCE(iocq, 1, isrCount, mGrpName, mTestName, work); if (isrCount != anticipatedIrqs) { iocq->Dump(FileSystem::PrepDumpFile(mGrpName, mTestName, "iocq.fail", work), "Dump Entire IOCQ"); iosq->Dump(FileSystem::PrepDumpFile(mGrpName, mTestName, "iosq.fail", work), "Dump Entire IOSQ"); throw FrmwkEx(HERE, "Anticipated ISRs #%d but fired #%d", anticipatedIrqs, isrCount); } }
void IOQRollChkDiff_r10b::VerifyQPointers(SharedIOSQPtr iosq, SharedIOCQPtr iocq) { struct nvme_gen_cq iocqMetrics = iocq->GetQMetrics(); struct nvme_gen_sq iosqMetrics = iosq->GetQMetrics(); uint32_t expectedVal = (2 + MAX(iocq->GetNumEntries(), iosq->GetNumEntries())) % iocq->GetNumEntries(); if (iocqMetrics.head_ptr != expectedVal) { iocq->Dump(FileSystem::PrepDumpFile(mGrpName, mTestName, "iocq", "head_ptr"), "CQ Metrics Head Pointer Inconsistent"); throw FrmwkEx(HERE, "Expected IO CQ.head_ptr = 0x%04X but actual " "IOCQ.head_ptr = 0x%04X", expectedVal, iocqMetrics.head_ptr); } expectedVal = (2 + MAX(iocq->GetNumEntries(), iosq->GetNumEntries())) % iosq->GetNumEntries(); if (iosqMetrics.tail_ptr != expectedVal) { iosq->Dump(FileSystem::PrepDumpFile(mGrpName, mTestName, "iosq", "tail_ptr"), "SQ Metrics Tail Pointer Inconsistent"); throw FrmwkEx(HERE, "Expected IO SQ.tail_ptr = 0x%04X but actual " "IOSQ.tail_ptr = 0x%04X", expectedVal, iosqMetrics.tail_ptr); } }
void CIDAcceptedIOSQ_r10b::ReapVerifyCID(SharedIOSQPtr iosq, SharedIOCQPtr iocq, uint16_t expCID) { uint32_t isrCount; uint32_t ceRemain; uint32_t numReaped; uint32_t numCE; if (iocq->ReapInquiryWaitSpecify(CALC_TIMEOUT_ms(1), 1, numCE, isrCount) == false) { iocq->Dump(FileSystem::PrepDumpFile(mGrpName, mTestName, "iocq.fail"), "Dump Entire IOCQ"); iosq->Dump(FileSystem::PrepDumpFile(mGrpName, mTestName, "iosq.fail"), "Dump Entire IOSQ"); throw FrmwkEx(HERE, "Unable to see CEs for issued cmd"); } SharedMemBufferPtr ceMem = SharedMemBufferPtr(new MemBuffer()); if ((numReaped = iocq->Reap(ceRemain, ceMem, isrCount, numCE, true)) != 1) { iocq->Dump(FileSystem::PrepDumpFile(mGrpName, mTestName, "iocq.fail"), "Dump Entire IOCQ"); iosq->Dump(FileSystem::PrepDumpFile(mGrpName, mTestName, "iosq.fail"), "Dump Entire IOSQ"); throw FrmwkEx(HERE, "Unable to reap on IOCQ"); } union CE *ce = (union CE *)ceMem->GetBuffer(); ProcessCE::Validate(*ce); // throws upon error if (ce->n.CID != expCID) { iocq->Dump(FileSystem::PrepDumpFile(mGrpName, mTestName, "iocq.fail"), "Dump Entire IOCQ"); iosq->Dump(FileSystem::PrepDumpFile(mGrpName, mTestName, "iosq.fail"), "Dump Entire IOSQ"); throw FrmwkEx(HERE, "Received CID %d but expected %d", ce->n.CID, expCID); } if (ce->n.SQID != iosq->GetQId()) { iocq->Dump(FileSystem::PrepDumpFile(mGrpName, mTestName, "iocq.fail"), "Dump Entire IOCQ"); iosq->Dump(FileSystem::PrepDumpFile(mGrpName, mTestName, "iosq.fail"), "Dump Entire IOSQ"); throw FrmwkEx(HERE, "Rx'd SDID %d but expt'd %d", ce->n.SQID, iosq->GetQId()); } }
void UnsupportRsvdFields_r10b::RunCoreTest() { /** \verbatim * Assumptions: * 1) Test CreateResources_r10b has run prior. * \endverbatim */ uint64_t maxIOQEntries = 2; // Lookup objs which were created in a prior test within group SharedASQPtr asq = CAST_TO_ASQ(gRsrcMngr->GetObj(ASQ_GROUP_ID)) SharedACQPtr acq = CAST_TO_ACQ(gRsrcMngr->GetObj(ACQ_GROUP_ID)) LOG_NRM("Setup element sizes for the IOQ's"); uint8_t iocqes = (gInformative->GetIdentifyCmdCtrlr()-> GetValue(IDCTRLRCAP_CQES) & 0xf); uint8_t iosqes = (gInformative->GetIdentifyCmdCtrlr()-> GetValue(IDCTRLRCAP_SQES) & 0xf); gCtrlrConfig->SetIOCQES(iocqes); gCtrlrConfig->SetIOSQES(iosqes); LOG_NRM("Create IOCQ"); SharedIOCQPtr iocq = SharedIOCQPtr(new IOCQ(gDutFd)); LOG_NRM("Allocate contiguous memory; IOCQ has ID=%d", IOQ_ID); iocq->Init(IOQ_ID, maxIOQEntries, true, 0); LOG_NRM("Form a Create IOCQ cmd to perform queue creation"); SharedCreateIOCQPtr createIOCQCmd = SharedCreateIOCQPtr(new CreateIOCQ()); createIOCQCmd->Init(iocq); LOG_NRM("Set all cmd's rsvd bits"); uint32_t work = createIOCQCmd->GetDword(0); work |= 0x0000fc00; // Set DW0_b15:10 bits createIOCQCmd->SetDword(work, 0); createIOCQCmd->SetDword(0xffffffff, 2); createIOCQCmd->SetDword(0xffffffff, 3); createIOCQCmd->SetDword(0xffffffff, 4); createIOCQCmd->SetDword(0xffffffff, 5); createIOCQCmd->SetDword(0xffffffff, 6); createIOCQCmd->SetDword(0xffffffff, 7); // DW11_b15:2 work = createIOCQCmd->GetDword(11); work |= 0x0000fffc; createIOCQCmd->SetDword(work, 11); createIOCQCmd->SetDword(0xffffffff, 12); createIOCQCmd->SetDword(0xffffffff, 13); createIOCQCmd->SetDword(0xffffffff, 14); createIOCQCmd->SetDword(0xffffffff, 15); IO::SendAndReapCmd(mGrpName, mTestName, CALC_TIMEOUT_ms(1), asq, acq, createIOCQCmd, "", true); LOG_NRM("Create the assoc IOSQ"); SharedIOSQPtr iosq = Queues::CreateIOSQContigToHdw(mGrpName, mTestName, CALC_TIMEOUT_ms(1), asq, acq, IOQ_ID, maxIOQEntries, false, IOCQ_GROUP_ID, IOQ_ID, 0); WriteReadVerify(iosq, iocq); }
void InvalidMSIXIRQ_r10b::RunCoreTest() { /** \verbatim * Assumptions: * 1) Requires test createResources_r10b to execute 1st * \endverbatim */ bool capable; uint16_t numIrqSupport; // Only allowed to execute if DUT supports MSI-X IRQ's if (gCtrlrConfig->IsMSIXCapable(capable, numIrqSupport) == false) throw FrmwkEx(HERE); else if (capable == false) { LOG_NRM("DUT does not support MSI-X IRQ's; unable to execute test"); return; } if (gCtrlrConfig->SetState(ST_DISABLE) == false) throw FrmwkEx(HERE); LOG_NRM("Notify DUT we plan on using all IRQ's that it supports"); if (gCtrlrConfig->SetIrqScheme(INT_MSIX, numIrqSupport) == false) { throw FrmwkEx(HERE, "Unable to use %d IRQ's, but DUT reports it supports", numIrqSupport); } gCtrlrConfig->SetCSS(CtrlrConfig::CSS_NVM_CMDSET); if (gCtrlrConfig->SetState(ST_ENABLE) == false) throw FrmwkEx(HERE); // Lookup objs which were created in a prior test within group SharedASQPtr asq = CAST_TO_ASQ(gRsrcMngr->GetObj(ASQ_GROUP_ID)) SharedACQPtr acq = CAST_TO_ACQ(gRsrcMngr->GetObj(ACQ_GROUP_ID)) LOG_NRM("Set legal IOCQ element size"); gCtrlrConfig->SetIOCQES(gInformative->GetIdentifyCmdCtrlr()-> GetValue(IDCTRLRCAP_CQES) & 0xf); // This test expects the DUT to reject the usage of illegal/unsupported // MSIX IRQ vectors, thus they should never be used. In order to safely fool // dnvme's safeguards, thus preventing a kernel crash, we need to issue a // legal cmd and allow dnvme to do it job. Then just before ringing the // doorbell inject a toxic illegal MSIX IRQ vector, the guts of this test. // So lets prepare that "legal" cmd here and then corrupt/toxify it later. LOG_NRM("Last supported MSIX IRQ vec = %d", (numIrqSupport - 1)); for (uint32_t i = numIrqSupport; i <= CtrlrConfig::MAX_MSIX_IRQ_VEC; i++) { // We must re-init the objects because a failed attempt at creating an // IOCQ forces dnvme to deconstruct the entire thing when it is reaped. LOG_NRM("Create the IOCQ and the cmd to issue to the DUT"); SharedIOCQPtr iocq = SharedIOCQPtr(new IOCQ(gDutFd)); LOG_NRM("Allocate contiguous memory; IOCQ has ID=%d", IOQ_ID); iocq->Init(IOQ_ID, NUM_IOQ_ENTRY, true, (numIrqSupport - 1)); SharedCreateIOCQPtr createIOCQCmd = SharedCreateIOCQPtr(new CreateIOCQ()); createIOCQCmd->Init(iocq); SendToxicCmd(asq, acq, createIOCQCmd, i); } }
void ManyCmdSubmit_r10b::RunCoreTest() { /** \verbatim * Assumptions: * 1) Test CreateResources_r10b has run prior. * \endverbatim */ uint32_t nCmds; uint32_t isrCount; uint32_t ceRemain; uint32_t numReaped; uint32_t numCE; uint16_t uniqueId; // Lookup objs which were created in a prior test within group SharedASQPtr asq = CAST_TO_ASQ(gRsrcMngr->GetObj(ASQ_GROUP_ID)) SharedACQPtr acq = CAST_TO_ACQ(gRsrcMngr->GetObj(ACQ_GROUP_ID)) LOG_NRM("Determine the max IOQ entries supported"); uint64_t ctrlCapReg; if (gRegisters->Read(CTLSPC_CAP, ctrlCapReg) == false) throw FrmwkEx(HERE, "Unable to determine MQES"); uint32_t maxIOQEntries = (uint32_t)(ctrlCapReg & CAP_MQES); maxIOQEntries += 1; // convert to 1-based. LOG_NRM("Create contig IOQ's"); SharedIOCQPtr iocq = Queues::CreateIOCQContigToHdw(mGrpName, mTestName, CALC_TIMEOUT_ms(1), asq, acq, IOQ_ID, maxIOQEntries, false, IOCQ_CONTIG_GROUP_ID, true, 0); SharedIOSQPtr iosq = Queues::CreateIOSQContigToHdw(mGrpName, mTestName, CALC_TIMEOUT_ms(1), asq, acq, IOQ_ID, maxIOQEntries, false, IOSQ_CONTIG_GROUP_ID, IOQ_ID, 0); SharedWritePtr writeCmd = SetWriteCmd(); uint32_t increment = 1; for (uint32_t x = 1; x < maxIOQEntries; x += increment) { LOG_NRM("Sending #%d simultaneous NVM write cmds to IOSQ", x); // Issue x simultaneous NVM write cmds. for (nCmds = 1; nCmds <= x; nCmds++) iosq->Send(writeCmd, uniqueId); iosq->Ring(); // Variable wait time w.r.t "x" and expect all CE's to arrive in CQ. if (iocq->ReapInquiryWaitSpecify(CALC_TIMEOUT_ms(x), x, numCE, isrCount) == false) { iocq->Dump(FileSystem::PrepDumpFile(mGrpName, mTestName, "iocq.reqpinq." + writeCmd->GetName()), "Dump Entire IOCQ"); LogCEAndCQMetrics(iocq); throw FrmwkEx(HERE, "Unable to see CEs for issued cmds #%d", x); } else if (numCE != x) { iocq->Dump(FileSystem::PrepDumpFile(mGrpName, mTestName, "iocq.reqpinq." + writeCmd->GetName()), "Dump Entire IOCQ"); LogCEAndCQMetrics(iocq); throw FrmwkEx(HERE, "The IOCQ should only have #%d CE's as a result " "of #%d simultaneous cmds but found #%d", x, x, numCE); } SharedMemBufferPtr ceMem = SharedMemBufferPtr(new MemBuffer()); if ((numReaped = iocq->Reap(ceRemain, ceMem, isrCount, x, true)) != x) { iocq->Dump(FileSystem::PrepDumpFile(mGrpName, mTestName, "iocq.reap." + writeCmd->GetName()), "Dump Entire IOCQ"); LogCEAndCQMetrics(iocq); throw FrmwkEx(HERE, "Unable to reap on IOCQ #%d. Reaped #%d of #%d", IOQ_ID, numReaped, x); } // Testing every cmd takes numerous hrs, so compromise. if ((maxIOQEntries - 1000) % x == 0) increment = 100; else if ((x % 1000) == 0) increment = 1000; else if ((maxIOQEntries - 100) % x == 0) increment = 10; else if ((x % 100) == 0) increment = 100; else if ((maxIOQEntries - 10) % x == 0) increment = 1; else if ((x % 10) == 0) increment = 10; } // Delete IOSQ before the IOCQ to comply with spec. Queues::DeleteIOSQToHdw(mGrpName, mTestName, CALC_TIMEOUT_ms(1), iosq, asq, acq); Queues::DeleteIOCQToHdw(mGrpName, mTestName, CALC_TIMEOUT_ms(1), iocq, asq, acq); }
void CreateIOCQ::Init(const SharedIOCQPtr iocq) { // Setup the PRP buffer based upon contig or non-contig memory int prpField = MASK_PRP1_PAGE; if (iocq->GetIsContig() == false) prpField |= MASK_PRP1_LIST; SetPrpBuffer((send_64b_bitmask)prpField, iocq->GetQBuffer(), iocq->GetQSize()); { // Handle DWORD 10 uint32_t dword10 = GetDword(10); // Handle q size dword10 &= ~0xffff0000; dword10 |= (((uint32_t)(iocq->GetNumEntries() - 1)) << 16); // Handle Q ID dword10 &= ~0x0000ffff; dword10 |= (uint32_t)iocq->GetQId(); SetDword(dword10, 10); } // Handle DWORD 10 { // Handle DWORD 11 uint32_t dword11 = GetDword(11); // Handle the PC bit if (iocq->GetIsContig()) dword11 |= 0x00000001; else dword11 &= ~0x00000001; // Handle IRQ support if (iocq->GetIrqEnabled()) { dword11 |= 0x00000002; dword11 &= ~0xffff0000; // clear it, then set it enum nvme_irq_type irq; uint16_t numIrqs; if (gCtrlrConfig->GetIrqScheme(irq, numIrqs) == false) throw FrmwkEx(HERE, "Unable to retrieve current IRQ scheme"); switch (irq) { case INT_MSI_MULTI: case INT_MSIX: dword11 |= (((uint32_t)iocq->GetIrqVector()) << 16); break; case INT_MSI_SINGLE: case INT_NONE: ; // Required to be zero break; default: throw FrmwkEx(HERE, "Unsupported IRQ scheme, what to do?"); } } else { dword11 &= ~0x00000002; dword11 &= ~0xffff0000; } SetDword(dword11, 11); } // Handle DWORD 11 }
void PartialReapMSIX_r10b::RunCoreTest() { /** \verbatim * Assumptions: * 1) Requires test createResources_r10b to execute 1st * \endverbatim */ bool capable; char work[25]; uint64_t reg; uint16_t numIrqSupport; uint16_t numIrqs = 1; uint16_t uniqueId; uint32_t isrCount; uint32_t numCE; // Only allowed to execute if DUT supports MSI-X IRQ's if (gCtrlrConfig->IsMSIXCapable(capable, numIrqSupport) == false) throw FrmwkEx(HERE); else if (capable == false) { LOG_WARN("DUT does not support MSI-X IRQ's; unable to execute test"); return; } // This requirement must be met, if not then DUT is most likely at fault if (gRegisters->Read(CTLSPC_CAP, reg) == false) throw FrmwkEx(HERE, "Unable to determine CAP.MQES"); reg &= CAP_MQES; reg += 1; // convert to 1-based if (reg < (uint64_t)NUM_IOQ_ENTRY) { LOG_WARN("Desired to support >= %d elements in IOQ's for test", NUM_IOQ_ENTRY); return; } LOG_NRM("Setup the necessary IRQ's"); if (gCtrlrConfig->SetState(ST_DISABLE) == false) throw FrmwkEx(HERE); if (gCtrlrConfig->SetIrqScheme(INT_MSIX, numIrqs) == false) { throw FrmwkEx(HERE, "Unable to use %d IRQ's, but DUT reports it supports", numIrqs); } gCtrlrConfig->SetCSS(CtrlrConfig::CSS_NVM_CMDSET); if (gCtrlrConfig->SetState(ST_ENABLE) == false) throw FrmwkEx(HERE); // Lookup objs which were created in a prior test within group SharedASQPtr asq = CAST_TO_ASQ(gRsrcMngr->GetObj(ASQ_GROUP_ID)) SharedACQPtr acq = CAST_TO_ACQ(gRsrcMngr->GetObj(ACQ_GROUP_ID)) LOG_NRM("Create the IOQ pair which is needed"); gCtrlrConfig->SetIOCQES(gInformative->GetIdentifyCmdCtrlr()-> GetValue(IDCTRLRCAP_CQES) & 0xf); SharedIOCQPtr iocq = Queues::CreateIOCQContigToHdw(mGrpName, mTestName, DEFAULT_CMD_WAIT_ms, asq, acq, IOQ_ID, NUM_IOQ_ENTRY, false, "", true, 0); gCtrlrConfig->SetIOSQES(gInformative->GetIdentifyCmdCtrlr()-> GetValue(IDCTRLRCAP_SQES) & 0xf); SharedIOSQPtr iosq = Queues::CreateIOSQContigToHdw(mGrpName, mTestName, DEFAULT_CMD_WAIT_ms, asq, acq, IOQ_ID, NUM_IOQ_ENTRY, false, "", IOQ_ID, 0); // NOTE: We are overloading IRQ 0, it is being used by ACQ and we have // created 1 IOQ's, thus to start out the ACQ will already have 2 // IRQs. The following algo must add this usage. uint32_t anticipatedIrqs = (2 + 1); SharedWritePtr writeCmd = CreateCmd(); for (unsigned i = 1; i <= NUM_CMDS_ISSUE; i++) { LOG_NRM("Sending write cmd %d", i); iosq->Send(writeCmd, uniqueId); iosq->Ring(); LOG_NRM("Wait for cmd to be processed"); if (iocq->ReapInquiryWaitSpecify(DEFAULT_CMD_WAIT_ms, i, numCE, isrCount) == false) { iocq->Dump( FileSystem::PrepDumpFile(mGrpName, mTestName, "acq", "error"), "Unable to determine if CE's arrived"); throw FrmwkEx(HERE, "Only detected %d CE's arriving", numCE); } else if (numCE != i) { iocq->Dump( FileSystem::PrepDumpFile(mGrpName, mTestName, "acq", "notEnough"), "Test requires seeing all CE's"); throw FrmwkEx(HERE, "The anticipated %d CE's have not arrived", i); } else if (isrCount != anticipatedIrqs) { // 1 IRQ per cmd did not occur iocq->Dump( FileSystem::PrepDumpFile(mGrpName, mTestName, "acq", "irqBad"), "Test requires seeing all correct num of IRQ's"); throw FrmwkEx(HERE, "The anticipated %d IRQ', but detected %d", anticipatedIrqs, isrCount); } } // There is an active IRQ outstanding and another to arrive due to the // PBA pending bit being set. The pending bit makes the 4th IRQ arrive // after reaping a single cmd. LOG_NRM("Start reaping and validate %d IRQ's", anticipatedIrqs); for (int i = 0; i < NUM_CMDS_ISSUE; i++) { snprintf(work, sizeof(work), "cmd.%d", i); IO::ReapCE(iocq, 1, isrCount, mGrpName, mTestName, work); if (isrCount != anticipatedIrqs) { iocq->Dump( FileSystem::PrepDumpFile(mGrpName, mTestName, "acq", work), "Number of IRQ's changed while reaping"); throw FrmwkEx(HERE, "Anticipated %d IRQ's; but only see %d", anticipatedIrqs, isrCount); } // Now account for a new IRQ fired due to the pending bit being handled // by the DUT, but delay processing so that latency in handling this // extra IRQ is not the cause of a test failure. Rather make the // absence of the IRQ be the failure, thus delaying is OK. if (i == 0) { anticipatedIrqs++; sleep(1); } } }
void MaxQSizeExceed_r10b::RunCoreTest() { /** \verbatim * Assumptions: * None. * \endverbatim */ string work; bool enableLog; uint64_t ctrlCapReg; LOG_NRM("Determine the max IOQ entries supported"); if (gRegisters->Read(CTLSPC_CAP, ctrlCapReg) == false) throw FrmwkEx(HERE, "Unable to determine MQES"); uint32_t maxIOQEntries = (ctrlCapReg & CAP_MQES); maxIOQEntries += 1; // convert to 1 - based. if (gCtrlrConfig->SetState(ST_DISABLE_COMPLETELY) == false) throw FrmwkEx(HERE); LOG_NRM("Create admin queues ACQ and ASQ"); SharedACQPtr acq = SharedACQPtr(new ACQ(gDutFd)); acq->Init(5); SharedASQPtr asq = SharedASQPtr(new ASQ(gDutFd)); asq->Init(5); // All queues will use identical IRQ vector IRQ::SetAnySchemeSpecifyNum(1); gCtrlrConfig->SetCSS(CtrlrConfig::CSS_NVM_CMDSET); if (gCtrlrConfig->SetState(ST_ENABLE) == false) throw FrmwkEx(HERE); LOG_NRM("Setup element size for the IOCQ"); gCtrlrConfig->SetIOCQES(gInformative->GetIdentifyCmdCtrlr()-> GetValue(IDCTRLRCAP_CQES) & 0xf); LOG_NRM("Create IOCQ with illegal Q entries ranging from 0x%04X to 0x10000", maxIOQEntries + 1); list<uint32_t> illegalQSizes = GetIllegalQSizes(maxIOQEntries); for (list<uint32_t>::iterator qSize = illegalQSizes.begin(); qSize != illegalQSizes.end(); qSize++) { LOG_NRM("Process CreateIOCQ Cmd with qSize #0x%04X", *qSize); SharedIOCQPtr iocq = SharedIOCQPtr(new IOCQ(gDutFd)); iocq->Init(IOQ_ID, *qSize, true, 0); SharedCreateIOCQPtr createIOCQCmd = SharedCreateIOCQPtr(new CreateIOCQ()); createIOCQCmd->Init(iocq); work = str(boost::format("qSize.%04Xh") % *qSize); enableLog = false; if ((*qSize <= (maxIOQEntries + 8)) || (*qSize >= (0xFFFF - 8))) enableLog = true; LOG_NRM("Send n reap ACQ for CreateIOCQCmd; qSize #0x%04X", *qSize); IO::SendAndReapCmd(mGrpName, mTestName, DEFAULT_CMD_WAIT_ms, asq, acq, createIOCQCmd, work, enableLog, CESTAT_MAX_Q_SIZE_EXCEED); } }