OpenSSD Cosmos+ Platform Firmware
0.0.2
The firmware of Cosmos+ OpenSSD Platform for TOSHIBA nand flash module.
|
#include "xil_printf.h"
#include <assert.h>
#include "nvme/nvme.h"
#include "nvme/host_lld.h"
#include "memory_map.h"
#include "ftl_config.h"
Go to the source code of this file.
Functions | |
void | InitDependencyTable () |
void | ReqTransNvmeToSlice (unsigned int cmdSlotTag, unsigned int startLba, unsigned int nlb, unsigned int cmdCode) |
Split NVMe command into slice requests. More... | |
void | EvictDataBufEntry (unsigned int originReqSlotTag) |
Clear the specified data buffer entry and sync dirty data if needed. More... | |
void | DataReadFromNand (unsigned int originReqSlotTag) |
Generate and dispatch a flash read request for the given slice request. More... | |
void | ReqTransSliceToLowLevel () |
Data Buffer Manager. Handle all the pending slice requests. More... | |
unsigned int | CheckBufDep (unsigned int reqSlotTag) |
Check if this request has the buffer dependency problem. More... | |
unsigned int | CheckRowAddrDep (unsigned int reqSlotTag, unsigned int checkRowAddrDepOpt) |
Check if this NAND request has the row address dependency problem. More... | |
unsigned int | UpdateRowAddrDepTableForBufBlockedReq (unsigned int reqSlotTag) |
Update the dependency info and dispatch the request if possible. More... | |
void | SelectLowLevelReqQ (unsigned int reqSlotTag) |
Dispatch given NVMe/NAND request to corresponding request queue. More... | |
void | ReleaseBlockedByBufDepReq (unsigned int reqSlotTag) |
Pop the specified request from the buffer dependency queue. More... | |
void | ReleaseBlockedByRowAddrDepReq (unsigned int chNo, unsigned int wayNo) |
Update the row address dependency of all the requests on the specified die. More... | |
void | IssueNvmeDmaReq (unsigned int reqSlotTag) |
Allocate data buffer for the specified DMA request and inform the controller. More... | |
void | CheckDoneNvmeDmaReq () |
Variables | |
P_ROW_ADDR_DEPENDENCY_TABLE | rowAddrDependencyTablePtr |
unsigned int CheckBufDep | ( | unsigned int | reqSlotTag | ) |
Check if this request has the buffer dependency problem.
Requests that share the same data buffer entry must be executed in correct order, and the execution order is identical to the order of the request entry index appended to the blocking request queue, so we can simply check if the previous request in the blocking request queue exists.
UpdateDataBufEntryInfoBlockingReq()
and DATA_BUF_ENTRY
.reqSlotTag | the request pool entry index of the request to be checked |
Definition at line 407 of file request_transform.c.
void CheckDoneNvmeDmaReq | ( | ) |
Definition at line 918 of file request_transform.c.
unsigned int CheckRowAddrDep | ( | unsigned int | reqSlotTag, |
unsigned int | checkRowAddrDepOpt | ||
) |
Check if this NAND request has the row address dependency problem.
First, the NAND request should already be assigned a VSA, and we need to translate the VSA info physical info.
Now we the physical info of the target address of the specified request, but different type of request have different dependency problem:
For a write request:
In current implementation, pages in the same block will be allocated sequentially, and thus here we should block all the write requests whose target PBN is not the expected page of the current working block on the target die.
For a erase request:
Before erasing a block, we must ensure that there is no pending read request that require access to any of the pages within the target block.
programmedPageCnt
?For a read request:
Before performing read operation the a block, we should ensure the pending write and erase requests are already finished.
reqSlotTag | The request pool entry index of the request to be checked. |
checkRowAddrDepOpt | Increased or decreased the count of block info. |
Definition at line 454 of file request_transform.c.
void DataReadFromNand | ( | unsigned int | originReqSlotTag | ) |
Generate and dispatch a flash read request for the given slice request.
Before issuing NVMe Tx request and migration, we must read the target page into target data buffer entry. To do this, we should create and issue a sub-request for flash read operation.
nandInfo.virtualSliceAddr
was assigned after calling the function UpdateDataBufEntryInfoBlockingReq()
.ReqTransSliceToLowLevel()
originReqSlotTag | the request pool entry index of the parent NVMe slice request. |
Definition at line 262 of file request_transform.c.
void EvictDataBufEntry | ( | unsigned int | originReqSlotTag | ) |
Clear the specified data buffer entry and sync dirty data if needed.
In current implementation, the write request from host will not write the data directly to the flash memory, but will cache the data in the data buffer and mark the entry as dirty entry instead. Therefore, once the data buffer become full, the fw should check whether the evicted entry is dirty and perform write request if needed before the entry being evicted.
originReqSlotTag | the request entry index of the data buffer entry to be evicted. |
Definition at line 218 of file request_transform.c.
void InitDependencyTable | ( | ) |
Definition at line 58 of file request_transform.c.
void IssueNvmeDmaReq | ( | unsigned int | reqSlotTag | ) |
Allocate data buffer for the specified DMA request and inform the controller.
This function is used for issuing a new DMA request, the DMA procedure can be split into 2 steps:
dataBufFormat
of the specified DMA requestInform NVMe controller
For a DMA request, it might want to rx/tx a data whose size is larger than 4K which is the NVMe block size, so the firmware need to inform the NVMe controller for each NVMe block.
The tail reg of the DMA queue will be updated during the set_auto_rx_dma()
and set_auto_tx_dma()
, so we need to update the nvmeDmaInfo.reqTail
after issuing the DMA request.
GenerateDataBufAddr()
is chosen based on the REQ_OPT_DATA_BUF_ENTRY
, however, since the size of a data entry is BYTES_PER_DATA_REGION_OF_SLICE
(default 4), will the data buffer used by the DMA request overlap with other requests' data buffer if the numOfNvmeBlock
of the DMA request is larger than NVME_BLOCKS_PER_PAGE
?reqSlotTag | the request pool index of the given request. |
Definition at line 878 of file request_transform.c.
void ReleaseBlockedByBufDepReq | ( | unsigned int | reqSlotTag | ) |
Pop the specified request from the buffer dependency queue.
In the current implementation, this function is only called after the specified request entry is moved to the free request queue, which means that the previous request has released the data buffer entry it occupied. Therefore, we now need to update the relevant information about the data buffer dependency.
DATA_BUF_ENTRY
maintains only the tail of blocked requests, the specified request should be the head of blocked requests to ensure that the request order is not messed up.reqSlotTag | The request entry index of the given request |
Definition at line 729 of file request_transform.c.
void ReleaseBlockedByRowAddrDepReq | ( | unsigned int | chNo, |
unsigned int | wayNo | ||
) |
Update the row address dependency of all the requests on the specified die.
Traverse the blockedByRowAddrDepReqQ
of the specified die, and then recheck the row address dependency for all the requests on that die. When a request is found that it can pass the dependency check, it will be dispatched (move to the NAND request queue).
By updating the row address dependency info, some requests on the target die may be released.
CheckRowAddrDep()
.chNo | The channel number of the specified die. |
wayNo | The way number of the specified die. |
Definition at line 820 of file request_transform.c.
void ReqTransNvmeToSlice | ( | unsigned int | cmdSlotTag, |
unsigned int | startLba, | ||
unsigned int | nlb, | ||
unsigned int | cmdCode | ||
) |
Split NVMe command into slice requests.
startLba
and nlb
is NVMe block, not NAND block.To get the starting LSA of this NVMe command, we need to divide the given startLba
by NVME_BLOCKS_PER_SLICE
which indicates that how many NVMe blocks can be merged into a slice request.
To get the number of NAND blocks needed by this NVMe command, we should first align the starting NVMe block address startLba
to slice 0, then convert the ending NVMe block address (startLba
% NVME_BLOCKS_PER_SLICE
+ requestedNvmeBlock
) to LSA, then the result indicates the number of slice requests needed by this NVMe command.
requestedNvmeBlock
by 1 to get the real number of NVMe blocks to be read/written by this NVMe command.Now the address translation part is finished and we can start to split the NVMe command into slice requests. The splitting process can be separated into 3 steps:
Fill the remaining NVMe blocks in first slice request (head)
Since the startLba
may not perfectly align to the first NVMe block of first slice command, we should access the trailing N NVMe blocks in the first slice request, where N is the number of misaligned NVMe blocks in the first slice requests.
Generate slice requests for the aligned NVMe blocks (body)
General case. The number of the NVMe blocks to be filled by these slice requests is exactly NVME_BLOCKS_PER_SLICE
. So here just simply use a loop to generate same slice requests.
Generate slice request for the remaining NVMe blocks (tail)
Similar to the first step, but here we need to access the first K NVMe blocks in the last slice request, where K is the number of remaining NVMe blocks in this slice request.
cmdSlotTag |
startLba | address of the first logical NVMe block to read/write. |
nlb | number of logical NVMe blocks to read/write. |
cmdCode | opcode of the given NVMe command. |
Definition at line 123 of file request_transform.c.
void ReqTransSliceToLowLevel | ( | ) |
Data Buffer Manager. Handle all the pending slice requests.
This function will repeat the following steps until all the pending slice requests are consumed:
sliceReqQ
.Allocate a data buffer entry for the request and generate flash requests if needed.
logicalSliceAddr
and generate flash request when buffer hit? data cache hit??Generate NVMe transfer/receive request for read/write request.
SelectLowLevelReqQ()
.handle_nvme_io_cmd()
during the process of handling NVMe I/O commands in nvme_main.c
. Definition at line 323 of file request_transform.c.
void SelectLowLevelReqQ | ( | unsigned int | reqSlotTag | ) |
Dispatch given NVMe/NAND request to corresponding request queue.
This function is in charge of issuing the given NVMe/NAND request. But before issuing the request, we should first make sure that this request is safe to be issued.
We first need to check whether this request is blocked by any other request that uses the same data buffer (check UpdateDataBufEntryInfoBlockingReq()
for details).
For a NAND request, we must do something before issuing the request:
However, for NAND requests, since there may be some dependency problems between the requests (e.g., ERASE cannot be simply reordered before READ), we must check this kind of dependency problems (called "row address dependency" here) before dispatching the NAND requests by using the function CheckRowAddrDep()
.
Once it was confirmed to have no row address dependency problem on this request, the request can then be dispatched; otherwise, the request should be blocked and inserted to the row address dependency queue.
REQ_OPT_ROW_ADDR_DEPENDENCY_CHECK
.If the request is blocked by data buffer dependency
The fw will try to recheck the data buffer dependency problem and release the request if possible, by calling UpdateRowAddrDepTableForBufBlockedReq()
, which is similar to CheckRowAddrDep()
.
reqSlotTag | the request pool index of the given request. |
Definition at line 634 of file request_transform.c.
unsigned int UpdateRowAddrDepTableForBufBlockedReq | ( | unsigned int | reqSlotTag | ) |
Update the dependency info and dispatch the request if possible.
This function will update the data buffer and row address dependency info of the given request. If the given request is READ request and have no dependency problem, it will be dispatched in this function.
// FIXME: why only update buf dep for READ request? why ignore WRITE request?
CheckRowAddrDep()
, this function may insert the given READ request into blockedByRowAddrDepReqQ
and update relevant blocking info directly.CheckRowAddrDep()
, SelectLowLevelReqQ()
.reqSlotTag | Request entry index of the request to be checked. |
Definition at line 547 of file request_transform.c.
P_ROW_ADDR_DEPENDENCY_TABLE rowAddrDependencyTablePtr |
Definition at line 56 of file request_transform.c.