OpenSSD Cosmos+ Platform Firmware  0.0.2
The firmware of Cosmos+ OpenSSD Platform for TOSHIBA nand flash module.
request_schedule.h File Reference
#include "ftl_config.h"
Include dependency graph for request_schedule.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  _COMPLETE_FLAG_TABLE
 
struct  _STATUS_REPORT_TABLE
 
struct  _ERROR_INFO_TABLE
 
struct  _RETRY_LIMIT_TABLE
 
struct  _DIE_STATE_ENTRY
 
struct  _DIE_STATE_TABLE
 The status table of each die on the flash memory. More...
 
struct  _WAY_PRIORITY_ENTRY
 The way priority table of this channel. More...
 
struct  _WAY_PRIORITY_TABLE
 The channel status table, each entry contains 7 lists. More...
 

Macros

#define WAY_NONE   0xF
 
#define LUN_0_BASE_ADDR   0x00000000
 
#define LUN_1_BASE_ADDR   0x00100000
 
#define PSEUDO_BAD_BLOCK_MARK   0
 
#define RETRY_LIMIT   5
 The max number of times a request can retry if it failed. More...
 
#define DIE_STATE_IDLE   0
 
#define DIE_STATE_EXE   1
 
#define REQ_STATUS_CHECK_OPT_NONE   0
 
#define REQ_STATUS_CHECK_OPT_CHECK   1
 
#define REQ_STATUS_CHECK_OPT_REPORT   2
 
#define REQ_STATUS_CHECK_OPT_COMPLETION_FLAG   3
 
#define REQ_STATUS_RUNNING   0
 
#define REQ_STATUS_DONE   1
 
#define REQ_STATUS_FAIL   2
 
#define REQ_STATUS_WARNING   3
 
#define ERROR_INFO_FAIL   0
 
#define ERROR_INFO_PASS   1
 
#define ERROR_INFO_WARNING   2
 

Typedefs

typedef struct _COMPLETE_FLAG_TABLE COMPLETE_FLAG_TABLE
 
typedef struct _COMPLETE_FLAG_TABLEP_COMPLETE_FLAG_TABLE
 
typedef struct _STATUS_REPORT_TABLE STATUS_REPORT_TABLE
 
typedef struct _STATUS_REPORT_TABLEP_STATUS_REPORT_TABLE
 
typedef struct _ERROR_INFO_TABLE ERROR_INFO_TABLE
 
typedef struct _ERROR_INFO_TABLEP_ERROR_INFO_TABLE
 
typedef struct _RETRY_LIMIT_TABLE RETRY_LIMIT_TABLE
 
typedef struct _RETRY_LIMIT_TABLEP_RETRY_LIMIT_TABLE
 
typedef struct _DIE_STATE_ENTRY DIE_STATE_ENTRY
 
typedef struct _DIE_STATE_ENTRYP_DIE_STATE_ENTRY
 
typedef struct _DIE_STATE_TABLE DIE_STATE_TABLE
 The status table of each die on the flash memory. More...
 
typedef struct _DIE_STATE_TABLEP_DIE_STATE_TABLE
 
typedef struct _WAY_PRIORITY_ENTRY WAY_PRIORITY_ENTRY
 The way priority table of this channel. More...
 
typedef struct _WAY_PRIORITY_ENTRYP_WAY_PRIORITY_ENTRY
 
typedef struct _WAY_PRIORITY_TABLE WAY_PRIORITY_TABLE
 The channel status table, each entry contains 7 lists. More...
 
typedef struct _WAY_PRIORITY_TABLEP_WAY_PRIORITY_TABLE
 

Functions

void InitReqScheduler ()
 Initialize scheduling related tables. More...
 
void SyncAllLowLevelReqDone ()
 Do schedule until all the requests are done. More...
 
void SyncAvailFreeReq ()
 Try release request entries by doing scheduling (both NVMe and NAND). More...
 
void SyncReleaseEraseReq (unsigned int chNo, unsigned int wayNo, unsigned int blockNo)
 Issuing requests until the specified block can be erased. More...
 
void SchedulingNandReq ()
 Iteratively do schedule on each channel by calling SchedulingNandReqPerCh. More...
 
void SchedulingNandReqPerCh (unsigned int chNo)
 The main function to schedule NAND requests on the specified channel. More...
 
void PutToNandWayPriorityTable (unsigned int reqSlotTag, unsigned int chNo, unsigned int wayNo)
 Append the specified die to a NAND state list based on the request type of the given request. More...
 
void PutToNandIdleList (unsigned int chNo, unsigned int wayNo)
 Append the specified die to the tail of the idle list of its channel. More...
 
void SelectivGetFromNandIdleList (unsigned int chNo, unsigned int wayNo)
 Remove the specified die from the idle list of its channel. More...
 
void PutToNandStatusReportList (unsigned int chNo, unsigned int wayNo)
 Append the specified die to the tail of the status report list of its channel. More...
 
void SelectivGetFromNandStatusReportList (unsigned int chNo, unsigned int wayNo)
 Remove the specified die from the status report list of its channel. More...
 
void PutToNandReadTriggerList (unsigned int chNo, unsigned int wayNo)
 Append the specified die to the tail of the read trigger list of its channel. More...
 
void SelectiveGetFromNandReadTriggerList (unsigned int chNo, unsigned int wayNo)
 Remove the specified die from the read trigger list of its channel. More...
 
void PutToNandWriteList (unsigned int chNo, unsigned int wayNo)
 Append the specified die to the tail of the write list of its channel. More...
 
void SelectiveGetFromNandWriteList (unsigned int chNo, unsigned int wayNo)
 Remove the specified die from the write list of its channel. More...
 
void PutToNandReadTransferList (unsigned int chNo, unsigned int wayNo)
 Append the specified die to the tail of the read transfer list of its channel. More...
 
void SelectiveGetFromNandReadTransferList (unsigned int chNo, unsigned int wayNo)
 Remove the specified die from the read transfer list of its channel. More...
 
void PutToNandEraseList (unsigned int chNo, unsigned int wayNo)
 Append the specified die to the tail of the erase list of its channel. More...
 
void SelectiveGetFromNandEraseList (unsigned int chNo, unsigned int wayNo)
 Remove the specified die from the erase list of its channel. More...
 
void PutToNandStatusCheckList (unsigned int chNo, unsigned int wayNo)
 Append the specified die to the tail of the status check list of its channel. More...
 
void SelectiveGetFromNandStatusCheckList (unsigned int chNo, unsigned int wayNo)
 Remove the specified die from the status check list of its channel. More...
 
void IssueNandReq (unsigned int chNo, unsigned int wayNo)
 Issue a flash operations to the storage controller. More...
 
unsigned int GenerateNandRowAddr (unsigned int reqSlotTag)
 Get the nand row (block) address of the given request. More...
 
unsigned int GenerateDataBufAddr (unsigned int reqSlotTag)
 Get the corresponding data buffer entry address of the given request. More...
 
unsigned int GenerateSpareDataBufAddr (unsigned int reqSlotTag)
 Get the corresponding sparse data buffer entry address of the given request. More...
 
unsigned int CheckReqStatus (unsigned int chNo, unsigned int wayNo)
 Update the die status and return the request status. More...
 
unsigned int CheckEccErrorInfo (unsigned int chNo, unsigned int wayNo)
 
void ExecuteNandReq (unsigned int chNo, unsigned int wayNo, unsigned int reqStatus)
 Update die state and issue new NAND requests if the die is in IDLE state. More...
 

Variables

P_COMPLETE_FLAG_TABLE completeFlagTablePtr
 
P_STATUS_REPORT_TABLE statusReportTablePtr
 
P_ERROR_INFO_TABLE eccErrorInfoTablePtr
 
P_RETRY_LIMIT_TABLE retryLimitTablePtr
 
P_DIE_STATE_TABLE dieStatusTablePtr
 
P_WAY_PRIORITY_TABLE wayPriorityTablePtr
 

Macro Definition Documentation

◆ DIE_STATE_EXE

#define DIE_STATE_EXE   1

Definition at line 69 of file request_schedule.h.

◆ DIE_STATE_IDLE

#define DIE_STATE_IDLE   0

Definition at line 68 of file request_schedule.h.

◆ ERROR_INFO_FAIL

#define ERROR_INFO_FAIL   0

Definition at line 85 of file request_schedule.h.

◆ ERROR_INFO_PASS

#define ERROR_INFO_PASS   1

Definition at line 86 of file request_schedule.h.

◆ ERROR_INFO_WARNING

#define ERROR_INFO_WARNING   2

Definition at line 87 of file request_schedule.h.

◆ LUN_0_BASE_ADDR

#define LUN_0_BASE_ADDR   0x00000000

Definition at line 54 of file request_schedule.h.

◆ LUN_1_BASE_ADDR

#define LUN_1_BASE_ADDR   0x00100000

Definition at line 55 of file request_schedule.h.

◆ PSEUDO_BAD_BLOCK_MARK

#define PSEUDO_BAD_BLOCK_MARK   0

Definition at line 57 of file request_schedule.h.

◆ REQ_STATUS_CHECK_OPT_CHECK

#define REQ_STATUS_CHECK_OPT_CHECK   1

Definition at line 72 of file request_schedule.h.

◆ REQ_STATUS_CHECK_OPT_COMPLETION_FLAG

#define REQ_STATUS_CHECK_OPT_COMPLETION_FLAG   3

Definition at line 74 of file request_schedule.h.

◆ REQ_STATUS_CHECK_OPT_NONE

#define REQ_STATUS_CHECK_OPT_NONE   0

Definition at line 71 of file request_schedule.h.

◆ REQ_STATUS_CHECK_OPT_REPORT

#define REQ_STATUS_CHECK_OPT_REPORT   2

Definition at line 73 of file request_schedule.h.

◆ REQ_STATUS_DONE

#define REQ_STATUS_DONE   1

Definition at line 81 of file request_schedule.h.

◆ REQ_STATUS_FAIL

#define REQ_STATUS_FAIL   2

Definition at line 82 of file request_schedule.h.

◆ REQ_STATUS_RUNNING

#define REQ_STATUS_RUNNING   0

Definition at line 80 of file request_schedule.h.

◆ REQ_STATUS_WARNING

#define REQ_STATUS_WARNING   3

Definition at line 83 of file request_schedule.h.

◆ RETRY_LIMIT

#define RETRY_LIMIT   5

The max number of times a request can retry if it failed.

Each die has their own retry counter, which is managed by the RETRY_LIMIT_TABLE, if a request is done or reaching the max retry times, the corresponding counter will be reset to this value.

Definition at line 66 of file request_schedule.h.

◆ WAY_NONE

#define WAY_NONE   0xF

Definition at line 52 of file request_schedule.h.

Typedef Documentation

◆ COMPLETE_FLAG_TABLE

◆ DIE_STATE_ENTRY

like a node of doubly-linked list.

Each entry consist of 4 members:

  • dieState
  • reqStatusCheckOpt
  • prevWay
  • nextWay

In the beginning, the dieState of each way was initialized to IDLE and all the ways of this channel were connected in serial order.

◆ DIE_STATE_TABLE

The status table of each die on the flash memory.

This table is simply a 2D status array of each way on each channel.

◆ ERROR_INFO_TABLE

◆ P_COMPLETE_FLAG_TABLE

◆ P_DIE_STATE_ENTRY

◆ P_DIE_STATE_TABLE

◆ P_ERROR_INFO_TABLE

◆ P_RETRY_LIMIT_TABLE

◆ P_STATUS_REPORT_TABLE

◆ P_WAY_PRIORITY_ENTRY

◆ P_WAY_PRIORITY_TABLE

◆ RETRY_LIMIT_TABLE

◆ STATUS_REPORT_TABLE

◆ WAY_PRIORITY_ENTRY

The way priority table of this channel.

This table manage several statuses:

  • idle
  • readTrigger
  • readTransfer
  • write
  • erase
  • statusReport
  • statusCheck

Each status manage the serial number of head way and tail way,

At the initialization stage, the idle list contains all ways in the channel and the other lists are empty.

◆ WAY_PRIORITY_TABLE

The channel status table, each entry contains 7 lists.

Function Documentation

◆ CheckEccErrorInfo()

unsigned int CheckEccErrorInfo ( unsigned int  chNo,
unsigned int  wayNo 
)

Definition at line 1321 of file request_schedule.c.

1322{
1323 unsigned int errorInfo0, errorInfo1, reqSlotTag;
1324
1325 reqSlotTag = nandReqQ[chNo][wayNo].headReq;
1326
1327 errorInfo0 = eccErrorInfoTablePtr->errorInfo[chNo][wayNo][0];
1328 errorInfo1 = eccErrorInfoTablePtr->errorInfo[chNo][wayNo][1];
1329
1330 if (V2FCrcValid(eccErrorInfoTablePtr->errorInfo[chNo][wayNo]))
1331 // if (V2FPageDecodeSuccess(&eccErrorInfoTablePtr->errorInfo[chNo][wayNo][1]))
1332 {
1335 return ERROR_INFO_WARNING;
1336
1337 return ERROR_INFO_PASS;
1338 }
1339
1340 return ERROR_INFO_FAIL;
1341}
#define BIT_ERROR_THRESHOLD_PER_CHUNK
Definition: ftl_config.h:187
#define V2FCrcValid(errorInformation)
Definition: nsc_driver.h:104
#define V2FWorstChunkErrorCount(errorInformation)
Definition: nsc_driver.h:105
P_REQ_POOL reqPoolPtr
NAND_REQUEST_QUEUE nandReqQ[USER_CHANNELS][USER_WAYS]
#define REQ_OPT_NAND_ECC_WARNING_ON
P_ERROR_INFO_TABLE eccErrorInfoTablePtr
#define ERROR_INFO_WARNING
#define ERROR_INFO_FAIL
#define ERROR_INFO_PASS
unsigned int errorInfo[USER_CHANNELS][USER_WAYS][ERROR_INFO_WORD_COUNT]
unsigned int headReq
Definition: request_queue.h:92
unsigned int nandEccWarning
SSD_REQ_FORMAT reqPool[AVAILABLE_OUNTSTANDING_REQ_COUNT]
REQ_OPTION reqOpt
Here is the caller graph for this function:

◆ CheckReqStatus()

unsigned int CheckReqStatus ( unsigned int  chNo,
unsigned int  wayNo 
)

Update the die status and return the request status.

Note
This function has a side effect: the flag reqStatusCheckOpt of this die may be updated from REQ_STATUS_CHECK_OPT_CHECK, which means the first stage status check, to REQ_STATUS_CHECK_OPT_REPORT, which means the second stage status check, or changed from REQ_STATUS_CHECK_OPT_REPORT to REQ_STATUS_CHECK_OPT_CHECK, so this function should be used carefully.
Parameters
chNothe target channel number to check the status.
wayNothe target die number to check the status.
Returns
unsigned int the status of the request being executed on this die.

Definition at line 1257 of file request_schedule.c.

1258{
1259 unsigned int reqSlotTag, completeFlag, statusReport, errorInfo, readyBusy, status;
1260 unsigned int *statusReportPtr;
1261
1262 reqSlotTag = nandReqQ[chNo][wayNo].headReq;
1264 {
1265 completeFlag = completeFlagTablePtr->completeFlag[chNo][wayNo];
1266
1267 if (V2FTransferComplete(completeFlag))
1268 {
1270 {
1271 errorInfo = CheckEccErrorInfo(chNo, wayNo);
1272
1273 if (errorInfo == ERROR_INFO_WARNING)
1274 return REQ_STATUS_WARNING;
1275 else if (errorInfo == ERROR_INFO_FAIL)
1276 return REQ_STATUS_FAIL;
1277 }
1278 return REQ_STATUS_DONE;
1279 }
1280 }
1282 {
1283 statusReportPtr = (unsigned int *)(&statusReportTablePtr->statusReport[chNo][wayNo]);
1284
1285 V2FStatusCheckAsync(&chCtlReg[chNo], wayNo, statusReportPtr);
1286
1288 }
1290 {
1291 statusReport = statusReportTablePtr->statusReport[chNo][wayNo];
1292
1293 if (V2FRequestReportDone(statusReport))
1294 {
1295 status = V2FEliminateReportDoneFlag(statusReport);
1296 if (V2FRequestComplete(status))
1297 {
1298 if (V2FRequestFail(status))
1299 return REQ_STATUS_FAIL;
1300
1302 return REQ_STATUS_DONE;
1303 }
1304 else
1306 }
1307 }
1309 {
1310 readyBusy = V2FReadyBusyAsync(&chCtlReg[chNo]);
1311
1312 if (V2FWayReady(readyBusy, wayNo))
1313 return REQ_STATUS_DONE;
1314 }
1315 else
1316 assert(!"[WARNING] wrong request status check option [WARNING]");
1317
1318 return REQ_STATUS_RUNNING;
1319}
T4REGS chCtlReg[USER_CHANNELS]
Definition: ftl_config.c:57
#define V2FRequestReportDone(statusReport)
Definition: nsc_driver.h:113
void V2FStatusCheckAsync(T4REGS *t4regs, int way, unsigned int *statusReport)
#define V2FRequestComplete(statusReport)
Definition: nsc_driver.h:115
#define V2FRequestFail(statusReport)
Definition: nsc_driver.h:116
#define V2FTransferComplete(completeFlag)
Definition: nsc_driver.h:112
#define V2FEliminateReportDoneFlag(statusReport)
Definition: nsc_driver.h:114
unsigned int V2FReadyBusyAsync(T4REGS *t4regs)
#define V2FWayReady(readyBusy, wayNo)
Definition: nsc_driver.h:111
#define REQ_OPT_NAND_ECC_ON
P_COMPLETE_FLAG_TABLE completeFlagTablePtr
P_DIE_STATE_TABLE dieStateTablePtr
unsigned int CheckEccErrorInfo(unsigned int chNo, unsigned int wayNo)
P_STATUS_REPORT_TABLE statusReportTablePtr
#define REQ_STATUS_FAIL
#define REQ_STATUS_CHECK_OPT_COMPLETION_FLAG
#define REQ_STATUS_RUNNING
#define REQ_STATUS_CHECK_OPT_NONE
#define REQ_STATUS_CHECK_OPT_REPORT
#define REQ_STATUS_CHECK_OPT_CHECK
#define REQ_STATUS_WARNING
#define REQ_STATUS_DONE
unsigned int completeFlag[USER_CHANNELS][USER_WAYS]
unsigned int reqStatusCheckOpt
DIE_STATE_ENTRY dieState[USER_CHANNELS][USER_WAYS]
unsigned int nandEcc
unsigned int statusReport[USER_CHANNELS][USER_WAYS]
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ExecuteNandReq()

void ExecuteNandReq ( unsigned int  chNo,
unsigned int  wayNo,
unsigned int  reqStatus 
)

Update die state and issue new NAND requests if the die is in IDLE state.

If the die state is IDLE, we can just issue new NAND request on that die. But if the state is EXE, we should do different thing based on the request status:

  • previous request is RUNNING

    Nothing to do, just wait for it.

  • previous request is DONE

    Before we set the die state to IDLE, we need to do something based on its request type:

    • if previous request is READ_TRIGGER, just convert to READ_TRANSFER
    • otherwise, removed from the request queue and reset the retry count
    Note
    if a command should be split into some continuous requests, we should modify this to ensure other requests will not be executed before these requests finished. Take READ for example, if a READ_TRIGGER finished, the data is still in its die register, thus we should make sure the READ_TRANSFER to be the next request that will be executed on this die to prevent the die register from being overwritten.
  • previous request is FAIL

    If the request failed, there are different things to do based on the request type. For READ_TRIGGER and READ_TRANSFER, retry the request (from READ_TRIGGER state) until reaching the retry limitation. For other requests, just mark as bad block.

  • previous request is WARNING

    This means ECC failed, report bad block then make die IDLE and reset retry count

    Todo:
    bad block and ECC related handling
Note
in current implementation, this is the only function that changes the dieState.
Parameters
chNothe channel number which should exec this request
wayNothe way number which should exec this request
reqStatusthe status of the previous request executed on the specified die

Definition at line 1386 of file request_schedule.c.

1387{
1388 unsigned int reqSlotTag, rowAddr, phyBlockNo;
1389 unsigned char *badCheck;
1390
1391 reqSlotTag = nandReqQ[chNo][wayNo].headReq;
1392
1393 switch (dieStateTablePtr->dieState[chNo][wayNo].dieState)
1394 {
1395 case DIE_STATE_IDLE:
1396 IssueNandReq(chNo, wayNo);
1398 break;
1399 case DIE_STATE_EXE:
1400 if (reqStatus == REQ_STATUS_DONE)
1401 {
1402 if (reqPoolPtr->reqPool[reqSlotTag].reqCode == REQ_CODE_READ)
1404 else
1405 {
1407 GetFromNandReqQ(chNo, wayNo, reqStatus, reqPoolPtr->reqPool[reqSlotTag].reqCode);
1408 }
1409
1411 }
1412 else if (reqStatus == REQ_STATUS_FAIL)
1413 {
1414 if ((reqPoolPtr->reqPool[reqSlotTag].reqCode == REQ_CODE_READ) ||
1416 if (retryLimitTablePtr->retryLimit[chNo][wayNo] > 0)
1417 {
1418 retryLimitTablePtr->retryLimit[chNo][wayNo]--;
1419 // FIXME: why not just use READ_TRANSFER
1421 reqPoolPtr->reqPool[reqSlotTag].reqCode = REQ_CODE_READ;
1422
1424 return;
1425 }
1426
1427 if (reqPoolPtr->reqPool[reqSlotTag].reqCode == REQ_CODE_READ)
1428 pr_warn("Read Trigger FAIL on ");
1429 else if (reqPoolPtr->reqPool[reqSlotTag].reqCode == REQ_CODE_READ_TRANSFER)
1430 pr_warn("Read Transfer FAIL on ");
1431 else if (reqPoolPtr->reqPool[reqSlotTag].reqCode == REQ_CODE_WRITE)
1432 pr_warn("Write FAIL on ");
1433 else if (reqPoolPtr->reqPool[reqSlotTag].reqCode == REQ_CODE_ERASE)
1434 pr_warn("Erase FAIL on ");
1435
1436 rowAddr = GenerateNandRowAddr(reqSlotTag);
1437 pr_warn("ch %x way %x rowAddr 0x%x: completeFlag 0x%x statusReport 0x%x", chNo, wayNo, rowAddr,
1438 completeFlagTablePtr->completeFlag[chNo][wayNo],
1439 statusReportTablePtr->statusReport[chNo][wayNo]);
1440
1443 {
1444 // Request fail in the bad block detection process
1445 badCheck = (unsigned char *)reqPoolPtr->reqPool[reqSlotTag].dataBufInfo.addr;
1446 *badCheck = PSEUDO_BAD_BLOCK_MARK; // FIXME: why not two step assign ?
1447 }
1448
1449 // grown bad block information update
1450 phyBlockNo = ((rowAddr % LUN_1_BASE_ADDR) / PAGES_PER_MLC_BLOCK) +
1451 ((rowAddr / LUN_1_BASE_ADDR) * TOTAL_BLOCKS_PER_LUN);
1453
1455 GetFromNandReqQ(chNo, wayNo, reqStatus, reqPoolPtr->reqPool[reqSlotTag].reqCode);
1457 }
1458 else if (reqStatus == REQ_STATUS_WARNING)
1459 {
1460 rowAddr = GenerateNandRowAddr(reqSlotTag);
1461 xil_printf("ECC Uncorrectable Soon on ch %x way %x rowAddr %x / completion %x statusReport %x \r\n",
1462 chNo, wayNo, rowAddr, completeFlagTablePtr->completeFlag[chNo][wayNo],
1463 statusReportTablePtr->statusReport[chNo][wayNo]);
1464
1465 // grown bad block information update
1466 phyBlockNo = ((rowAddr % LUN_1_BASE_ADDR) / PAGES_PER_MLC_BLOCK) +
1467 ((rowAddr / LUN_1_BASE_ADDR) * TOTAL_BLOCKS_PER_LUN);
1469
1471 GetFromNandReqQ(chNo, wayNo, reqStatus, reqPoolPtr->reqPool[reqSlotTag].reqCode);
1473 }
1474 else if (reqStatus == REQ_STATUS_RUNNING)
1475 break;
1476 else
1477 assert(!"[WARNING] wrong req status [WARNING]");
1478 break;
1479 }
1480}
void UpdatePhyBlockMapForGrownBadBlock(unsigned int dieNo, unsigned int phyBlockNo)
Mark the given physical block bad block and update the bbt later.
#define Pcw2VdieTranslation(chNo, wayNo)
Get die number from physical channel number and way number.
#define pr_warn(fmt,...)
Definition: debug.h:87
#define TOTAL_BLOCKS_PER_LUN
Definition: ftl_config.h:155
#define PAGES_PER_MLC_BLOCK
Definition: ftl_config.h:183
void GetFromNandReqQ(unsigned int chNo, unsigned int wayNo, unsigned int reqStatus, unsigned int reqCode)
Move the head request of the specified nandReqQ queue to freeReqQ.
#define REQ_OPT_DATA_BUF_ADDR
#define REQ_CODE_WRITE
#define REQ_CODE_READ_TRANSFER
#define REQ_CODE_ERASE
#define REQ_CODE_READ
#define REQ_OPT_NAND_ECC_OFF
void IssueNandReq(unsigned int chNo, unsigned int wayNo)
Issue a flash operations to the storage controller.
P_RETRY_LIMIT_TABLE retryLimitTablePtr
unsigned int GenerateNandRowAddr(unsigned int reqSlotTag)
Get the nand row (block) address of the given request.
#define LUN_1_BASE_ADDR
#define PSEUDO_BAD_BLOCK_MARK
#define DIE_STATE_IDLE
#define RETRY_LIMIT
The max number of times a request can retry if it failed.
#define DIE_STATE_EXE
unsigned int addr
unsigned int dieState
unsigned int dataBufFormat
Type of address stored in the SSD_REQ_FORMAT::dataBufInfo.
int retryLimit[USER_CHANNELS][USER_WAYS]
DATA_BUF_INFO dataBufInfo
unsigned int reqCode
Here is the call graph for this function:
Here is the caller graph for this function:

◆ GenerateDataBufAddr()

unsigned int GenerateDataBufAddr ( unsigned int  reqSlotTag)

Get the corresponding data buffer entry address of the given request.

Before issuing the DMA operations, we have to set the buffer address where the request should get/put their data during the READ/WRITE request.

To do this, we may have to specify the entry index of real data buffer and convert to the real address if the data buffer format not REQ_OPT_DATA_BUF_ADDR:

  • find the index of data buffer entry to be used:

    Similar to the two request data buffer dataBuf and tempDataBuf, there are also two types of real data buffer specified by the two address DATA_BUFFER_BASE_ADDR and TEMPORARY_DATA_BUFFER_BASE_ADDR.

    Since the two real data buffer have same number of entries with its corresponding request data buffer, AVAILABLE_TEMPORARY_DATA_BUFFER_ENTRY_COUNT for temp buffer and AVAILABLE_DATA_BUFFER_ENTRY_COUNT for normal buffer, we can just simply use the index of the request data buffer entry to find the corresponding index of real data buffer entry.

  • get the address of real data buffer entry:

    Since the real data buffer entry have the same size with NAND page size, and we have already found the entry index, we can just multiply the index by the page size defined by BYTES_PER_DATA_REGION_OF_SLICE to get the starting address of the corresponding data buffer of the given data buffer entry.

    However, if the request is a NVMe request, we should do some extra works. Since the unit size of NVMe block is 4K, which is one-fourth of the page size, if the LBA didn't align by 4, we have to move (N*4K) bytes within the real data buffer entry by using the offset to find the address corresponding to the NVMe block.

Parameters
reqSlotTagthe request data buffer entry index
Returns
unsigned int the address of real data buffer entry to be used

Definition at line 1169 of file request_schedule.c.

1170{
1171 if (reqPoolPtr->reqPool[reqSlotTag].reqType == REQ_TYPE_NAND)
1172 {
1174 return (DATA_BUFFER_BASE_ADDR +
1180 return reqPoolPtr->reqPool[reqSlotTag].dataBufInfo.addr;
1181
1182 /*
1183 * For some requests not belongs to I/O requests, such as RESET, SET_FEATURE and
1184 * ERASE, the fw just assign a reserved buffer for these requests.
1185 */
1187 }
1188 else if (reqPoolPtr->reqPool[reqSlotTag].reqType == REQ_TYPE_NVME_DMA)
1189 {
1190 // similar to NAND request, but may have offset
1192 return (DATA_BUFFER_BASE_ADDR +
1195 else
1196 assert(!"[WARNING] wrong reqOpt-dataBufFormat [WARNING]");
1197 }
1198 else
1199 assert(!"[WARNING] wrong reqType [WARNING]");
1200}
#define BYTES_PER_DATA_REGION_OF_SLICE
Definition: ftl_config.h:212
#define BYTES_PER_NVME_BLOCK
Definition: ftl_config.h:194
#define RESERVED_DATA_BUFFER_BASE_ADDR
Definition: memory_map.h:85
#define TEMPORARY_DATA_BUFFER_BASE_ADDR
Definition: memory_map.h:78
#define DATA_BUFFER_BASE_ADDR
The base address of buffer for DMA requests.
Definition: memory_map.h:77
#define REQ_TYPE_NVME_DMA
#define REQ_OPT_DATA_BUF_TEMP_ENTRY
#define REQ_OPT_DATA_BUF_ENTRY
#define REQ_TYPE_NAND
unsigned int entry
unsigned int nvmeBlockOffset
NVME_DMA_INFO nvmeDmaInfo
unsigned int reqType
Here is the caller graph for this function:

◆ GenerateNandRowAddr()

unsigned int GenerateNandRowAddr ( unsigned int  reqSlotTag)

Get the nand row (block) address of the given request.

To get the row address, we have first check if the nand address format is VSA or not. If the address is VSA, we should convert it to the physical address by doing address translation.

Warning
Toshiba NAND only have SLC mode?
Parameters
reqSlotTagthe request pool index of the target request.
Returns
unsigned int the nand row address for the target request.

Definition at line 1085 of file request_schedule.c.

1086{
1087 unsigned int rowAddr, lun, virtualBlockNo, tempBlockNo, phyBlockNo, tempPageNo, dieNo;
1088
1090 {
1092 virtualBlockNo = Vsa2VblockTranslation(reqPoolPtr->reqPool[reqSlotTag].nandInfo.virtualSliceAddr);
1093 phyBlockNo = Vblock2PblockOfTbsTranslation(virtualBlockNo);
1094 lun = phyBlockNo / TOTAL_BLOCKS_PER_LUN;
1095 tempBlockNo = phyBlockMapPtr->phyBlock[dieNo][phyBlockNo].remappedPhyBlock % TOTAL_BLOCKS_PER_LUN;
1097
1098 // if(BITS_PER_FLASH_CELL == SLC_MODE)
1099 // tempPageNo = Vpage2PlsbPageTranslation(tempPageNo);
1100 }
1102 {
1104 reqPoolPtr->reqPool[reqSlotTag].nandInfo.physicalWay);
1106 {
1108 tempBlockNo = reqPoolPtr->reqPool[reqSlotTag].nandInfo.physicalBlock % TOTAL_BLOCKS_PER_LUN;
1109 tempPageNo = reqPoolPtr->reqPool[reqSlotTag].nandInfo.physicalPage;
1110 }
1112 {
1114 tempBlockNo = reqPoolPtr->reqPool[reqSlotTag].nandInfo.physicalBlock % MAIN_BLOCKS_PER_LUN +
1116
1117 // phyBlock remap
1118 tempBlockNo = phyBlockMapPtr->phyBlock[dieNo][tempBlockNo].remappedPhyBlock % TOTAL_BLOCKS_PER_LUN;
1119 tempPageNo = reqPoolPtr->reqPool[reqSlotTag].nandInfo.physicalPage;
1120 }
1121 }
1122 else
1123 assert(!"[WARNING] wrong nand addr option [WARNING]");
1124
1125 if (lun == 0)
1126 rowAddr = LUN_0_BASE_ADDR + tempBlockNo * PAGES_PER_MLC_BLOCK + tempPageNo;
1127 else
1128 rowAddr = LUN_1_BASE_ADDR + tempBlockNo * PAGES_PER_MLC_BLOCK + tempPageNo;
1129
1130 return rowAddr;
1131}
P_PHY_BLOCK_MAP phyBlockMapPtr
#define Vsa2VpageTranslation(virtualSliceAddr)
#define Vsa2VdieTranslation(virtualSliceAddr)
#define Vblock2PblockOfTbsTranslation(blockNo)
Get the PBA (in total block space) of the given VBN.
#define Vsa2VblockTranslation(virtualSliceAddr)
#define MAIN_BLOCKS_PER_LUN
Definition: ftl_config.h:153
#define REQ_OPT_BLOCK_SPACE_MAIN
for the 1 bit flag REQ_OPTION::blockSpace.
#define REQ_OPT_BLOCK_SPACE_TOTAL
#define REQ_OPT_NAND_ADDR_VSA
#define REQ_OPT_NAND_ADDR_PHY_ORG
#define LUN_0_BASE_ADDR
unsigned int physicalBlock
unsigned int physicalWay
unsigned int physicalPage
unsigned int virtualSliceAddr
unsigned int physicalCh
unsigned int remappedPhyBlock
PHY_BLOCK_ENTRY phyBlock[USER_DIES][TOTAL_BLOCKS_PER_DIE]
unsigned int nandAddr
Type of address stored in the SSD_REQ_FORMAT::nandInfo.
unsigned int blockSpace
NAND_INFO nandInfo
Here is the caller graph for this function:

◆ GenerateSpareDataBufAddr()

unsigned int GenerateSpareDataBufAddr ( unsigned int  reqSlotTag)

Get the corresponding sparse data buffer entry address of the given request.

Similar to GenerateDataBufAddr(), but with different buffer base address, different entry size (256B for metadata/sparse data) and no need to deal with the offset of NVMe requests.

Note
the RESERVED_DATA_BUFFER_BASE_ADDR didn't explicitly split into real data area and sparse data area, hence we should manually add 16K (page size) to get the area for sparse data.
Parameters
reqSlotTagthe request data buffer entry index
Returns
unsigned int the address of sparse data buffer entry to be used

Definition at line 1216 of file request_schedule.c.

1217{
1218 if (reqPoolPtr->reqPool[reqSlotTag].reqType == REQ_TYPE_NAND)
1219 {
1227 return (reqPoolPtr->reqPool[reqSlotTag].dataBufInfo.addr +
1228 BYTES_PER_DATA_REGION_OF_SLICE); // modify PAGE_SIZE to other
1229
1231 }
1232 else if (reqPoolPtr->reqPool[reqSlotTag].reqType == REQ_TYPE_NVME_DMA)
1233 {
1237 else
1238 assert(!"[WARNING] wrong reqOpt-dataBufFormat [WARNING]");
1239 }
1240 else
1241 assert(!"[WARNING] wrong reqType [WARNING]");
1242}
#define BYTES_PER_SPARE_REGION_OF_SLICE
Definition: ftl_config.h:213
#define SPARE_DATA_BUFFER_BASE_ADDR
Definition: memory_map.h:80
#define TEMPORARY_SPARE_DATA_BUFFER_BASE_ADDR
Definition: memory_map.h:83
Here is the caller graph for this function:

◆ InitReqScheduler()

void InitReqScheduler ( )

Initialize scheduling related tables.

The following tables may be used for scheduling:

Todo:
  • dieStateTablePtr: contains the metadata of all dies
  • wayPriorityTablePtr: manages the way state table of each channel
  • completeFlagTablePtr:
  • statusReportTablePtr:
  • eccErrorInfoTablePtr:
  • retryLimitTablePtr: manages the remain retry count of each die

In this function:

  • all the ways of same channel are in the idle list of their channel.
  • all the dies are in idle state and connected in serial order
  • the completion count and status report of all die are set to 0
  • the retry limit number of each die is set to RETRY_LIMIT

Definition at line 83 of file request_schedule.c.

84{
85 int chNo, wayNo;
86
91
94
95 for (chNo = 0; chNo < USER_CHANNELS; ++chNo)
96 {
111
112 for (wayNo = 0; wayNo < USER_WAYS; ++wayNo)
113 {
116 dieStateTablePtr->dieState[chNo][wayNo].prevWay = wayNo - 1;
117 dieStateTablePtr->dieState[chNo][wayNo].nextWay = wayNo + 1;
118
119 completeFlagTablePtr->completeFlag[chNo][wayNo] = 0;
120 statusReportTablePtr->statusReport[chNo][wayNo] = 0;
122 }
125 }
126}
#define USER_CHANNELS
Definition: ftl_config.h:207
#define USER_WAYS
Definition: ftl_config.h:208
#define ERROR_INFO_TABLE_ADDR
Definition: memory_map.h:91
#define STATUS_REPORT_TABLE_ADDR
Definition: memory_map.h:90
#define RETRY_LIMIT_TABLE_ADDR
Definition: memory_map.h:114
#define DIE_STATE_TABLE_ADDR
Definition: memory_map.h:113
#define WAY_PRIORITY_TABLE_ADDR
Definition: memory_map.h:115
#define COMPLETE_FLAG_TABLE_ADDR
Definition: memory_map.h:89
P_WAY_PRIORITY_TABLE wayPriorityTablePtr
struct _STATUS_REPORT_TABLE * P_STATUS_REPORT_TABLE
struct _ERROR_INFO_TABLE * P_ERROR_INFO_TABLE
struct _RETRY_LIMIT_TABLE * P_RETRY_LIMIT_TABLE
struct _COMPLETE_FLAG_TABLE * P_COMPLETE_FLAG_TABLE
#define WAY_NONE
struct _WAY_PRIORITY_TABLE * P_WAY_PRIORITY_TABLE
struct _DIE_STATE_TABLE * P_DIE_STATE_TABLE
unsigned int nextWay
unsigned int prevWay
unsigned int readTransferHead
unsigned int readTriggerHead
unsigned int writeHead
unsigned int statusCheckTail
unsigned int eraseTail
unsigned int statusReportHead
unsigned int statusCheckHead
unsigned int idleTail
unsigned int readTransferTail
unsigned int statusReportTail
unsigned int idleHead
unsigned int readTriggerTail
unsigned int eraseHead
unsigned int writeTail
WAY_PRIORITY_ENTRY wayPriority[USER_CHANNELS]
Here is the caller graph for this function:

◆ IssueNandReq()

void IssueNandReq ( unsigned int  chNo,
unsigned int  wayNo 
)

Issue a flash operations to the storage controller.

To issue a NAND request, we should first allocate a data buffer entry for the request, though some request may not use the buffer, and then call the corresponding function defined in the nsc_driver.c based on the request type.

Before we issue the request, we should set the reqStatusCheckOpt flag of the specified die based on the request type:

  • for READ_TRANSFER request, set to REQ_STATUS_CHECK_OPT_COMPLETION_FLAG, which means the we should use the complete flag table to determine if this request is done. Beside checking the status, this flag also used for distinguishing between READ_TRANSFER and other flash operations, since the ECC result may need to be checked, check the function CheckReqStatus() for details.
  • for RESET, SET_FEATURE request, set to REQ_STATUS_CHECK_OPT_NONE, which means the request won't update the status table, and we can just use the busy/ready status to determine whether this request is done.
  • for READ_TRIGGER, WRITE, ERASE request, set to REQ_STATUS_CHECK_OPT_CHECK, but this flag is a little bit complicated; this flag actually represent the first stage status check, and this flag may be updated to the REQ_STATUS_CHECK_OPT_REPORT, which is used to represent the second stage status check, if the function CheckReqStatus() called during the scheduling process. Check SchedulingNandReqPerCh() and CheckReqStatus() for details.
Warning
replace the condition statements with switch statement
Parameters
chNothe channel number of the targe die to issue the NAND request.
wayNothe way number of the targe die to issue the NAND request.

Definition at line 1013 of file request_schedule.c.

1014{
1015 unsigned int reqSlotTag, rowAddr;
1016 void *dataBufAddr;
1017 void *spareDataBufAddr;
1018 unsigned int *errorInfo;
1019 unsigned int *completion;
1020
1021 reqSlotTag = nandReqQ[chNo][wayNo].headReq;
1022 rowAddr = GenerateNandRowAddr(reqSlotTag);
1023 dataBufAddr = (void *)GenerateDataBufAddr(reqSlotTag);
1024 spareDataBufAddr = (void *)GenerateSpareDataBufAddr(reqSlotTag);
1025
1026 if (reqPoolPtr->reqPool[reqSlotTag].reqCode == REQ_CODE_READ)
1027 {
1029
1030 V2FReadPageTriggerAsync(&chCtlReg[chNo], wayNo, rowAddr);
1031 }
1032 else if (reqPoolPtr->reqPool[reqSlotTag].reqCode == REQ_CODE_READ_TRANSFER)
1033 {
1035
1036 errorInfo = (unsigned int *)(&eccErrorInfoTablePtr->errorInfo[chNo][wayNo]);
1037 completion = (unsigned int *)(&completeFlagTablePtr->completeFlag[chNo][wayNo]);
1038
1040 V2FReadPageTransferAsync(&chCtlReg[chNo], wayNo, dataBufAddr, spareDataBufAddr, errorInfo, completion,
1041 rowAddr);
1042 else
1043 V2FReadPageTransferRawAsync(&chCtlReg[chNo], wayNo, dataBufAddr, completion);
1044 }
1045 else if (reqPoolPtr->reqPool[reqSlotTag].reqCode == REQ_CODE_WRITE)
1046 {
1048
1049 V2FProgramPageAsync(&chCtlReg[chNo], wayNo, rowAddr, dataBufAddr, spareDataBufAddr);
1050 }
1051 else if (reqPoolPtr->reqPool[reqSlotTag].reqCode == REQ_CODE_ERASE)
1052 {
1054
1055 V2FEraseBlockAsync(&chCtlReg[chNo], wayNo, rowAddr);
1056 }
1057 else if (reqPoolPtr->reqPool[reqSlotTag].reqCode == REQ_CODE_RESET)
1058 {
1060
1061 V2FResetSync(&chCtlReg[chNo], wayNo);
1062 }
1063 else if (reqPoolPtr->reqPool[reqSlotTag].reqCode == REQ_CODE_SET_FEATURE)
1064 {
1066
1068 }
1069 else
1070 assert(!"[WARNING] not defined nand req [WARNING]");
1071}
#define TEMPORARY_PAY_LOAD_ADDR
Definition: memory_map.h:92
void V2FReadPageTransferAsync(T4REGS *t4regs, int way, void *pageDataBuffer, void *spareDataBuffer, unsigned int *errorInformation, unsigned int *completion, unsigned int rowAddress)
void V2FReadPageTransferRawAsync(T4REGS *t4regs, int way, void *pageDataBuffer, unsigned int *completion)
void V2FReadPageTriggerAsync(T4REGS *t4regs, int way, unsigned int rowAddress)
#define V2FEnterToggleMode(dev, way, payLoadAddr)
Definition: nsc_driver.h:109
void V2FEraseBlockAsync(T4REGS *t4regs, int way, unsigned int rowAddress)
void V2FProgramPageAsync(T4REGS *t4regs, int way, unsigned int rowAddress, void *pageDataBuffer, void *spareDataBuffer)
void V2FResetSync(T4REGS *t4regs, int way)
#define REQ_CODE_RESET
#define REQ_CODE_SET_FEATURE
unsigned int GenerateDataBufAddr(unsigned int reqSlotTag)
Get the corresponding data buffer entry address of the given request.
unsigned int GenerateSpareDataBufAddr(unsigned int reqSlotTag)
Get the corresponding sparse data buffer entry address of the given request.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PutToNandEraseList()

void PutToNandEraseList ( unsigned int  chNo,
unsigned int  wayNo 
)

Append the specified die to the tail of the erase list of its channel.

Similar to PutToNandIdleList() but with different target list.

Parameters
chNothe channel number of target die
wayNothe way number of target die

Definition at line 859 of file request_schedule.c.

Here is the caller graph for this function:

◆ PutToNandIdleList()

void PutToNandIdleList ( unsigned int  chNo,
unsigned int  wayNo 
)

Append the specified die to the tail of the idle list of its channel.

Note
This function won't change the reqStatusCheckOpt and dieState flags.
Parameters
chNothe channel number of target die
wayNothe way number of target die

Definition at line 536 of file request_schedule.c.

537{
539 {
544 }
545 else
546 {
551 }
552}
Here is the caller graph for this function:

◆ PutToNandReadTransferList()

void PutToNandReadTransferList ( unsigned int  chNo,
unsigned int  wayNo 
)

Append the specified die to the tail of the read transfer list of its channel.

Similar to PutToNandIdleList() but with different target list.

Parameters
chNothe channel number of target die
wayNothe way number of target die

Definition at line 796 of file request_schedule.c.

Here is the caller graph for this function:

◆ PutToNandReadTriggerList()

void PutToNandReadTriggerList ( unsigned int  chNo,
unsigned int  wayNo 
)

Append the specified die to the tail of the read trigger list of its channel.

Similar to PutToNandIdleList() but with different target list.

Parameters
chNothe channel number of target die
wayNothe way number of target die

Definition at line 670 of file request_schedule.c.

Here is the caller graph for this function:

◆ PutToNandStatusCheckList()

void PutToNandStatusCheckList ( unsigned int  chNo,
unsigned int  wayNo 
)

Append the specified die to the tail of the status check list of its channel.

Similar to PutToNandIdleList() but with different target list.

Parameters
chNothe channel number of target die
wayNothe way number of target die

Definition at line 922 of file request_schedule.c.

Here is the caller graph for this function:

◆ PutToNandStatusReportList()

void PutToNandStatusReportList ( unsigned int  chNo,
unsigned int  wayNo 
)

Append the specified die to the tail of the status report list of its channel.

Similar to PutToNandIdleList() but with different target list.

Parameters
chNothe channel number of target die
wayNothe way number of target die

Definition at line 605 of file request_schedule.c.

Here is the caller graph for this function:

◆ PutToNandWayPriorityTable()

void PutToNandWayPriorityTable ( unsigned int  reqSlotTag,
unsigned int  chNo,
unsigned int  wayNo 
)

Append the specified die to a NAND state list based on the request type of the given request.

Parameters
reqSlotTagthe request pool entry index of a request.
chNothe channel number of the specified die.
wayNothe way number of the specified die.

Definition at line 511 of file request_schedule.c.

512{
513 if (reqPoolPtr->reqPool[reqSlotTag].reqCode == REQ_CODE_READ)
514 PutToNandReadTriggerList(chNo, wayNo);
515 else if (reqPoolPtr->reqPool[reqSlotTag].reqCode == REQ_CODE_READ_TRANSFER)
516 PutToNandReadTransferList(chNo, wayNo);
517 else if (reqPoolPtr->reqPool[reqSlotTag].reqCode == REQ_CODE_WRITE)
518 PutToNandWriteList(chNo, wayNo);
519 else if (reqPoolPtr->reqPool[reqSlotTag].reqCode == REQ_CODE_ERASE)
520 PutToNandEraseList(chNo, wayNo);
521 else if ((reqPoolPtr->reqPool[reqSlotTag].reqCode == REQ_CODE_RESET) ||
523 PutToNandWriteList(chNo, wayNo);
524 else
525 assert(!"[WARNING] wrong reqCode [WARNING]");
526}
void PutToNandEraseList(unsigned int chNo, unsigned int wayNo)
Append the specified die to the tail of the erase list of its channel.
void PutToNandReadTriggerList(unsigned int chNo, unsigned int wayNo)
Append the specified die to the tail of the read trigger list of its channel.
void PutToNandWriteList(unsigned int chNo, unsigned int wayNo)
Append the specified die to the tail of the write list of its channel.
void PutToNandReadTransferList(unsigned int chNo, unsigned int wayNo)
Append the specified die to the tail of the read transfer list of its channel.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PutToNandWriteList()

void PutToNandWriteList ( unsigned int  chNo,
unsigned int  wayNo 
)

Append the specified die to the tail of the write list of its channel.

Similar to PutToNandIdleList() but with different target list.

Parameters
chNothe channel number of target die
wayNothe way number of target die

Definition at line 733 of file request_schedule.c.

Here is the caller graph for this function:

◆ SchedulingNandReq()

void SchedulingNandReq ( )

Iteratively do schedule on each channel by calling SchedulingNandReqPerCh.

Definition at line 186 of file request_schedule.c.

187{
188 int chNo;
189
190 for (chNo = 0; chNo < USER_CHANNELS; chNo++)
192}
void SchedulingNandReqPerCh(unsigned int chNo)
The main function to schedule NAND requests on the specified channel.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SchedulingNandReqPerCh()

void SchedulingNandReqPerCh ( unsigned int  chNo)

The main function to schedule NAND requests on the specified channel.

This function can be separated into 3 parts:

  1. select idle ways which has requests want to execute
  2. update the request status of each way (second stage status check) and move the die to the idle list if the request is done.
  3. update some requests' status (first step status check) and issue requests based on the predefined flash operation priority.

Check the inline comments for more detailed explanation.

Parameters
chNothe channel number for scheduling

Before doing scheduling on this channel, we should check if there is any idle way on this channel.

If there is any idle way in the idle list, we have to traverse the idle list, and try to schedule requests on the idle ways.

Currently no available requests should be executed on this way, but there may be some requests in the blockedByRowAddrDepReqQ instead. Try to release the blockedByRowAddrDepReqQ and check again if there are any requests to do later.

If any blocked request is released in ReleaseBlockedByRowAddrDepReq(), they will be added to the PutToNandReqQ.

If there is any request should be scheduled on this die, move this die from idle state list to the state list corresponding to the request type. Otherwise, there is really no request want to use this die, just skip this die.

The most important task of this part is to check the request status (second stage status check). Base on the request status, move to the die to the idle state list if its request is done, or back to statusCheck list (first stage status check, check next part for details) if its request not complete yet.

But beside this, we also move the dies that had completed their requests to the corresponding state list if there is any request should be scheduled on this die, just like what we did in the previous part, before issuing requests in next part.

Since the previous part had moved all idle ways to the state list corresponding to the head request of this die, this die must not in DIE_STATE_IDLE state.

Also, we had check the request state is not REQ_STATUS_RUNNING, thus the ExecuteNandReq() must bring the die to DIE_STATE_IDLE.

Since the die become idle, now we can try to schedule request on this die like what we just did in the previous part, if there is any request should be executed on this die.

Note
In current implementation, here is the only place to change the state a die to IDLE and put it into the idle state list.

If the status shows that this request not finish yet, and the flag reqStatusCheckOpt is set to REQ_STATUS_CHECK_OPT_CHECK, which means this request is not READ_TRANSFER since READ_TRANSFER use another flag REQ_STATUS_CHECK_OPT_COMPLETION_FLAG for checking, thus we have to move it back to the statusCheck list (first stage status check) for the next part to check it again.

Similar to next part, because the CheckReqStatus() will turn the flag reqStatusCheckOpt from REQ_STATUS_CHECK_OPT_REPORT to REQ_STATUS_CHECK_OPT_CHECK, we don't have to manually change the flag after/before the die was moved to the statusCheck list.

In the last part, we now can try to issue the requests based on the priority of flash operations. (check the paper)

Note
This part reflect the priority of flash operations mentioned in the paper, therefore DO NOT break the order of these 'if' conditions as long as there is no need to adjust the priority of flash operations.

If there is at least one request should be scheduled and their ways and the channel is not busy, we can issue the requests by calling ExecuteNandReq().

Note
Since some request may make the channel controller busy, we should skip the remaining requests right away as the channel become busy.

After the command is issued, we should move the die to the state list statusCheck or statusReport based on the request type:

  • For READ_TRIGGER, WRITE, ERASE requests:

    These types of requests will be moved to the statusCheck list as they were issued. And next time we entered this part, we will check the status of those requests first, since they are in the statusCheck list and status check has the highest priority.

    To check the request status, we use the function CheckReqStatus() to get the requests status of the ways and then move the die to the statusReport list.

    Note
    the function CheckReqStatus() will change the flag reqStatusCheckOpt to REQ_STATUS_CHECK_OPT_REPORT, therefore there is no need to modified the flag before/after we move the die to the statusReport list.
    Not all the requests' status can be retrieve since the die may be busy. Therefore, we only move the dies that successfully retrieved the status to the statusReport for second stage status checking.
  • For READ_TRANSFER requests:

    This type of requests will be directly added to the statusReport list. in other words, the status of READ_TRANSFER requests will not be checked in this part.

    GUESS: The reason that we don't check the status of READ_TRANSFER requests may be this type of requests are supposed to be time consuming task, thus we have no need to check the status right after they just being issued.

    Warning
    here should second stage status check

Definition at line 211 of file request_schedule.c.

212{
213 unsigned int readyBusy, wayNo, reqStatus, nextWay, waitWayCnt;
214
215 waitWayCnt = 0;
216
225 {
227 while (wayNo != WAY_NONE)
228 {
235 if (nandReqQ[chNo][wayNo].headReq == REQ_SLOT_TAG_NONE)
237
247 if (nandReqQ[chNo][wayNo].headReq != REQ_SLOT_TAG_NONE)
248 {
249 nextWay = dieStateTablePtr->dieState[chNo][wayNo].nextWay;
250 SelectivGetFromNandIdleList(chNo, wayNo);
251 PutToNandWayPriorityTable(nandReqQ[chNo][wayNo].headReq, chNo, wayNo);
252 wayNo = nextWay;
253 }
254 else
255 {
256 wayNo = dieStateTablePtr->dieState[chNo][wayNo].nextWay;
257 waitWayCnt++;
258 }
259 }
260 }
261
273 {
274 readyBusy = V2FReadyBusyAsync(&chCtlReg[chNo]);
276
277 while (wayNo != WAY_NONE)
278 {
279 if (V2FWayReady(readyBusy, wayNo))
280 {
281 reqStatus = CheckReqStatus(chNo, wayNo);
282 if (reqStatus != REQ_STATUS_RUNNING)
283 {
292 ExecuteNandReq(chNo, wayNo, reqStatus);
293 nextWay = dieStateTablePtr->dieState[chNo][wayNo].nextWay;
294
304 if (nandReqQ[chNo][wayNo].headReq == REQ_SLOT_TAG_NONE)
306
307 if (nandReqQ[chNo][wayNo].headReq != REQ_SLOT_TAG_NONE)
308 PutToNandWayPriorityTable(nandReqQ[chNo][wayNo].headReq, chNo, wayNo);
309 else
310 {
311 PutToNandIdleList(chNo, wayNo);
312 waitWayCnt++;
313 }
314
315 wayNo = nextWay;
316 }
318 {
332 nextWay = dieStateTablePtr->dieState[chNo][wayNo].nextWay;
334 PutToNandStatusCheckList(chNo, wayNo);
335 wayNo = nextWay;
336 }
337 else
338 {
339 wayNo = dieStateTablePtr->dieState[chNo][wayNo].nextWay;
340 waitWayCnt++;
341 }
342 }
343 else
344 {
345 wayNo = dieStateTablePtr->dieState[chNo][wayNo].nextWay;
346 waitWayCnt++;
347 }
348 }
349 }
350 else
351 {
352 pr_debug("Ch[%u]: No idle way can be used to issue new request ...", chNo);
353 }
354
402 if (waitWayCnt != USER_WAYS)
403 if (!V2FIsControllerBusy(&chCtlReg[chNo]))
404 {
406 {
407 readyBusy = V2FReadyBusyAsync(&chCtlReg[chNo]);
409
410 while (wayNo != WAY_NONE)
411 {
412 if (V2FWayReady(readyBusy, wayNo)) // TODO why this need?
413 {
414 // FIXME: called again in second stage status check?? redundant?
415 reqStatus = CheckReqStatus(chNo, wayNo);
416
418 PutToNandStatusReportList(chNo, wayNo);
419
420 if (V2FIsControllerBusy(&chCtlReg[chNo]))
421 return;
422 }
423
424 wayNo = dieStateTablePtr->dieState[chNo][wayNo].nextWay;
425 }
426 }
428 {
430
431 while (wayNo != WAY_NONE)
432 {
434
436 PutToNandStatusCheckList(chNo, wayNo);
437
438 if (V2FIsControllerBusy(&chCtlReg[chNo]))
439 return;
440
441 wayNo = dieStateTablePtr->dieState[chNo][wayNo].nextWay;
442 }
443 }
444
446 {
448
449 while (wayNo != WAY_NONE)
450 {
452
454 PutToNandStatusCheckList(chNo, wayNo);
455
456 if (V2FIsControllerBusy(&chCtlReg[chNo]))
457 return;
458
459 wayNo = dieStateTablePtr->dieState[chNo][wayNo].nextWay;
460 }
461 }
463 {
465
466 while (wayNo != WAY_NONE)
467 {
469
471 PutToNandStatusCheckList(chNo, wayNo);
472
473 if (V2FIsControllerBusy(&chCtlReg[chNo]))
474 return;
475
476 wayNo = dieStateTablePtr->dieState[chNo][wayNo].nextWay;
477 }
478 }
480 {
482
483 while (wayNo != WAY_NONE)
484 {
486
488 PutToNandStatusReportList(chNo, wayNo);
489
490 if (V2FIsControllerBusy(&chCtlReg[chNo]))
491 return;
492
493 wayNo = dieStateTablePtr->dieState[chNo][wayNo].nextWay;
494 }
495 }
496 }
497}
#define pr_debug(fmt,...)
Definition: debug.h:84
#define V2FIsControllerBusy(t4regs)
Definition: nsc_driver.h:100
#define REQ_SLOT_TAG_NONE
void SelectiveGetFromNandReadTriggerList(unsigned int chNo, unsigned int wayNo)
Remove the specified die from the read trigger list of its channel.
void SelectivGetFromNandIdleList(unsigned int chNo, unsigned int wayNo)
Remove the specified die from the idle list of its channel.
void SelectivGetFromNandStatusReportList(unsigned int chNo, unsigned int wayNo)
Remove the specified die from the status report list of its channel.
unsigned int CheckReqStatus(unsigned int chNo, unsigned int wayNo)
Update the die status and return the request status.
void PutToNandStatusReportList(unsigned int chNo, unsigned int wayNo)
Append the specified die to the tail of the status report list of its channel.
void SelectiveGetFromNandWriteList(unsigned int chNo, unsigned int wayNo)
Remove the specified die from the write list of its channel.
void PutToNandWayPriorityTable(unsigned int reqSlotTag, unsigned int chNo, unsigned int wayNo)
Append the specified die to a NAND state list based on the request type of the given request.
void PutToNandStatusCheckList(unsigned int chNo, unsigned int wayNo)
Append the specified die to the tail of the status check list of its channel.
void SelectiveGetFromNandEraseList(unsigned int chNo, unsigned int wayNo)
Remove the specified die from the erase list of its channel.
void ExecuteNandReq(unsigned int chNo, unsigned int wayNo, unsigned int reqStatus)
Update die state and issue new NAND requests if the die is in IDLE state.
void SelectiveGetFromNandReadTransferList(unsigned int chNo, unsigned int wayNo)
Remove the specified die from the read transfer list of its channel.
void PutToNandIdleList(unsigned int chNo, unsigned int wayNo)
Append the specified die to the tail of the idle list of its channel.
void SelectiveGetFromNandStatusCheckList(unsigned int chNo, unsigned int wayNo)
Remove the specified die from the status check list of its channel.
void ReleaseBlockedByRowAddrDepReq(unsigned int chNo, unsigned int wayNo)
Update the row address dependency of all the requests on the specified die.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SelectiveGetFromNandEraseList()

void SelectiveGetFromNandEraseList ( unsigned int  chNo,
unsigned int  wayNo 
)

Remove the specified die from the erase list of its channel.

Similar to SelectivGetFromNandIdleList(), but with different target list.

Parameters
chNothe channel number of target die
wayNothe way number of target die

Definition at line 885 of file request_schedule.c.

886{
887 if ((dieStateTablePtr->dieState[chNo][wayNo].nextWay != WAY_NONE) &&
888 (dieStateTablePtr->dieState[chNo][wayNo].prevWay != WAY_NONE))
889 {
891 dieStateTablePtr->dieState[chNo][wayNo].nextWay;
893 dieStateTablePtr->dieState[chNo][wayNo].prevWay;
894 }
895 else if ((dieStateTablePtr->dieState[chNo][wayNo].nextWay == WAY_NONE) &&
896 (dieStateTablePtr->dieState[chNo][wayNo].prevWay != WAY_NONE))
897 {
900 }
901 else if ((dieStateTablePtr->dieState[chNo][wayNo].nextWay != WAY_NONE) &&
902 (dieStateTablePtr->dieState[chNo][wayNo].prevWay == WAY_NONE))
903 {
906 }
907 else
908 {
911 }
912}
Here is the caller graph for this function:

◆ SelectiveGetFromNandReadTransferList()

void SelectiveGetFromNandReadTransferList ( unsigned int  chNo,
unsigned int  wayNo 
)

Remove the specified die from the read transfer list of its channel.

Similar to SelectivGetFromNandIdleList(), but with different target list.

Parameters
chNothe channel number of target die
wayNothe way number of target die

Definition at line 822 of file request_schedule.c.

823{
824 if ((dieStateTablePtr->dieState[chNo][wayNo].nextWay != WAY_NONE) &&
825 (dieStateTablePtr->dieState[chNo][wayNo].prevWay != WAY_NONE))
826 {
828 dieStateTablePtr->dieState[chNo][wayNo].nextWay;
830 dieStateTablePtr->dieState[chNo][wayNo].prevWay;
831 }
832 else if ((dieStateTablePtr->dieState[chNo][wayNo].nextWay == WAY_NONE) &&
833 (dieStateTablePtr->dieState[chNo][wayNo].prevWay != WAY_NONE))
834 {
837 }
838 else if ((dieStateTablePtr->dieState[chNo][wayNo].nextWay != WAY_NONE) &&
839 (dieStateTablePtr->dieState[chNo][wayNo].prevWay == WAY_NONE))
840 {
843 }
844 else
845 {
848 }
849}
Here is the caller graph for this function:

◆ SelectiveGetFromNandReadTriggerList()

void SelectiveGetFromNandReadTriggerList ( unsigned int  chNo,
unsigned int  wayNo 
)

Remove the specified die from the read trigger list of its channel.

Similar to SelectivGetFromNandIdleList(), but with different target list.

Parameters
chNothe channel number of target die
wayNothe way number of target die

Definition at line 696 of file request_schedule.c.

697{
698 if ((dieStateTablePtr->dieState[chNo][wayNo].nextWay != WAY_NONE) &&
699 (dieStateTablePtr->dieState[chNo][wayNo].prevWay != WAY_NONE))
700 {
702 dieStateTablePtr->dieState[chNo][wayNo].nextWay;
704 dieStateTablePtr->dieState[chNo][wayNo].prevWay;
705 }
706 else if ((dieStateTablePtr->dieState[chNo][wayNo].nextWay == WAY_NONE) &&
707 (dieStateTablePtr->dieState[chNo][wayNo].prevWay != WAY_NONE))
708 {
711 }
712 else if ((dieStateTablePtr->dieState[chNo][wayNo].nextWay != WAY_NONE) &&
713 (dieStateTablePtr->dieState[chNo][wayNo].prevWay == WAY_NONE))
714 {
717 }
718 else
719 {
722 }
723}
Here is the caller graph for this function:

◆ SelectiveGetFromNandStatusCheckList()

void SelectiveGetFromNandStatusCheckList ( unsigned int  chNo,
unsigned int  wayNo 
)

Remove the specified die from the status check list of its channel.

Similar to SelectivGetFromNandIdleList(), but with different target list.

Parameters
chNothe channel number of target die
wayNothe way number of target die

Definition at line 948 of file request_schedule.c.

949{
950 if ((dieStateTablePtr->dieState[chNo][wayNo].nextWay != WAY_NONE) &&
951 (dieStateTablePtr->dieState[chNo][wayNo].prevWay != WAY_NONE))
952 {
954 dieStateTablePtr->dieState[chNo][wayNo].nextWay;
956 dieStateTablePtr->dieState[chNo][wayNo].prevWay;
957 }
958 else if ((dieStateTablePtr->dieState[chNo][wayNo].nextWay == WAY_NONE) &&
959 (dieStateTablePtr->dieState[chNo][wayNo].prevWay != WAY_NONE))
960 {
963 }
964 else if ((dieStateTablePtr->dieState[chNo][wayNo].nextWay != WAY_NONE) &&
965 (dieStateTablePtr->dieState[chNo][wayNo].prevWay == WAY_NONE))
966 {
969 }
970 else
971 {
974 }
975}
Here is the caller graph for this function:

◆ SelectiveGetFromNandWriteList()

void SelectiveGetFromNandWriteList ( unsigned int  chNo,
unsigned int  wayNo 
)

Remove the specified die from the write list of its channel.

Similar to SelectivGetFromNandIdleList(), but with different target list.

Parameters
chNothe channel number of target die
wayNothe way number of target die

Definition at line 759 of file request_schedule.c.

760{
761 if ((dieStateTablePtr->dieState[chNo][wayNo].nextWay != WAY_NONE) &&
762 (dieStateTablePtr->dieState[chNo][wayNo].prevWay != WAY_NONE))
763 {
765 dieStateTablePtr->dieState[chNo][wayNo].nextWay;
767 dieStateTablePtr->dieState[chNo][wayNo].prevWay;
768 }
769 else if ((dieStateTablePtr->dieState[chNo][wayNo].nextWay == WAY_NONE) &&
770 (dieStateTablePtr->dieState[chNo][wayNo].prevWay != WAY_NONE))
771 {
774 }
775 else if ((dieStateTablePtr->dieState[chNo][wayNo].nextWay != WAY_NONE) &&
776 (dieStateTablePtr->dieState[chNo][wayNo].prevWay == WAY_NONE))
777 {
780 }
781 else
782 {
785 }
786}
Here is the caller graph for this function:

◆ SelectivGetFromNandIdleList()

void SelectivGetFromNandIdleList ( unsigned int  chNo,
unsigned int  wayNo 
)

Remove the specified die from the idle list of its channel.

Since the state lists only records the index of head/tail way in their list, there is no need to modify the wayPriority if the target way is at the body of its idle list.

Note
Like PutToNandIdleList(), this function won't change reqStatusCheckOpt and dieState too.
Warning
function name typo
Parameters
chNothe channel number of target die
wayNothe way number of target die

Definition at line 568 of file request_schedule.c.

569{
570 if ((dieStateTablePtr->dieState[chNo][wayNo].nextWay != WAY_NONE) &&
571 (dieStateTablePtr->dieState[chNo][wayNo].prevWay != WAY_NONE))
572 {
574 dieStateTablePtr->dieState[chNo][wayNo].nextWay;
576 dieStateTablePtr->dieState[chNo][wayNo].prevWay;
577 }
578 else if ((dieStateTablePtr->dieState[chNo][wayNo].nextWay == WAY_NONE) &&
579 (dieStateTablePtr->dieState[chNo][wayNo].prevWay != WAY_NONE))
580 {
583 }
584 else if ((dieStateTablePtr->dieState[chNo][wayNo].nextWay != WAY_NONE) &&
585 (dieStateTablePtr->dieState[chNo][wayNo].prevWay == WAY_NONE))
586 {
589 }
590 else
591 {
594 }
595}
Here is the caller graph for this function:

◆ SelectivGetFromNandStatusReportList()

void SelectivGetFromNandStatusReportList ( unsigned int  chNo,
unsigned int  wayNo 
)

Remove the specified die from the status report list of its channel.

Similar to SelectivGetFromNandIdleList(), but with different target list.

Warning
function name typo
Parameters
chNothe channel number of target die
wayNothe way number of target die

Definition at line 633 of file request_schedule.c.

634{
635 if ((dieStateTablePtr->dieState[chNo][wayNo].nextWay != WAY_NONE) &&
636 (dieStateTablePtr->dieState[chNo][wayNo].prevWay != WAY_NONE))
637 {
639 dieStateTablePtr->dieState[chNo][wayNo].nextWay;
641 dieStateTablePtr->dieState[chNo][wayNo].prevWay;
642 }
643 else if ((dieStateTablePtr->dieState[chNo][wayNo].nextWay == WAY_NONE) &&
644 (dieStateTablePtr->dieState[chNo][wayNo].prevWay != WAY_NONE))
645 {
648 }
649 else if ((dieStateTablePtr->dieState[chNo][wayNo].nextWay != WAY_NONE) &&
650 (dieStateTablePtr->dieState[chNo][wayNo].prevWay == WAY_NONE))
651 {
654 }
655 else
656 {
659 }
660}
Here is the caller graph for this function:

◆ SyncAllLowLevelReqDone()

void SyncAllLowLevelReqDone ( )

Do schedule until all the requests are done.

As mentioned in the paper, the NVMe requests have higher priority than NAND requests. Therefore the function that handles NVMe request CheckDoneNvmeDmaReq() should be called before the function for scheduling NAND requests SchedulingNandReq().

Definition at line 135 of file request_schedule.c.

136{
138 {
141 }
142}
unsigned int blockedReqCnt
NVME_DMA_REQUEST_QUEUE nvmeDmaReqQ
unsigned int notCompletedNandReqCnt
void SchedulingNandReq()
Iteratively do schedule on each channel by calling SchedulingNandReqPerCh.
void CheckDoneNvmeDmaReq()
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SyncAvailFreeReq()

void SyncAvailFreeReq ( )

Try release request entries by doing scheduling (both NVMe and NAND).

Similar to SyncAllLowLevelReqDone(), but this function will stop at there is at least one free request entry exists.

Definition at line 150 of file request_schedule.c.

151{
153 {
156 }
157}
FREE_REQUEST_QUEUE freeReqQ
unsigned int headReq
Definition: request_queue.h:52
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SyncReleaseEraseReq()

void SyncReleaseEraseReq ( unsigned int  chNo,
unsigned int  wayNo,
unsigned int  blockNo 
)

Issuing requests until the specified block can be erased.

Sometimes, a request on a block may be blocked by the previous erase request on the same block. However, the erase request may also blocked by the previous read requests.

So, this function will try to release the pending requests on the specified block that is blocked by the pending erase request.

See also
CheckRowAddrDep(), UpdateRowAddrDepTableForBufBlockedReq().
Parameters
chNoThe channel number of the target block.
wayNoThe way number of the target channel.
blockNoThe block number of the target die.

Definition at line 174 of file request_schedule.c.

175{
176 while (rowAddrDependencyTablePtr->block[chNo][wayNo][blockNo].blockedEraseReqFlag)
177 {
180 }
181}
P_ROW_ADDR_DEPENDENCY_TABLE rowAddrDependencyTablePtr
unsigned int blockedEraseReqFlag
ROW_ADDR_DEPENDENCY_ENTRY block[USER_CHANNELS][USER_WAYS][MAIN_BLOCKS_PER_DIE]
Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ completeFlagTablePtr

P_COMPLETE_FLAG_TABLE completeFlagTablePtr
extern

Definition at line 54 of file request_schedule.c.

◆ dieStatusTablePtr

P_DIE_STATE_TABLE dieStatusTablePtr
extern

◆ eccErrorInfoTablePtr

P_ERROR_INFO_TABLE eccErrorInfoTablePtr
extern

Definition at line 56 of file request_schedule.c.

◆ retryLimitTablePtr

P_RETRY_LIMIT_TABLE retryLimitTablePtr
extern

Definition at line 57 of file request_schedule.c.

◆ statusReportTablePtr

P_STATUS_REPORT_TABLE statusReportTablePtr
extern

Definition at line 55 of file request_schedule.c.

◆ wayPriorityTablePtr

P_WAY_PRIORITY_TABLE wayPriorityTablePtr
extern

Definition at line 60 of file request_schedule.c.