OpenSSD Cosmos+ Platform Firmware  0.0.2
The firmware of Cosmos+ OpenSSD Platform for TOSHIBA nand flash module.
request_schedule.c
Go to the documentation of this file.
1
2// request_schedule.c for Cosmos+ OpenSSD
3// Copyright (c) 2017 Hanyang University ENC Lab.
4// Contributed by Yong Ho Song <yhsong@enc.hanyang.ac.kr>
5// Jaewook Kwak <jwkwak@enc.hanyang.ac.kr>
6// Sangjin Lee <sjlee@enc.hanyang.ac.kr>
7//
8// This file is part of Cosmos+ OpenSSD.
9//
10// Cosmos+ OpenSSD is free software; you can redistribute it and/or modify
11// it under the terms of the GNU General Public License as published by
12// the Free Software Foundation; either version 3, or (at your option)
13// any later version.
14//
15// Cosmos+ OpenSSD is distributed in the hope that it will be useful,
16// but WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18// See the GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with Cosmos+ OpenSSD; see the file COPYING.
22// If not, see <http://www.gnu.org/licenses/>.
24
26// Company: ENC Lab. <http://enc.hanyang.ac.kr>
27// Engineer: Jaewook Kwak <jwkwak@enc.hanyang.ac.kr>
28//
29// Project Name: Cosmos+ OpenSSD
30// Design Name: Cosmos+ Firmware
31// Module Name: Request Scheduler
32// File Name: request_schedule.c
33//
34// Version: v1.0.0
35//
36// Description:
37// - decide request execution sequence
38// - issue NAND request to NAND storage controller
39// - check request execution result
41
43// Revision History:
44//
45// * v1.0.0
46// - First draft
48
49#include <assert.h>
50#include "xil_printf.h"
51#include "memory_map.h"
52#include "debug.h"
53
58
61
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}
127
136{
138 {
141 }
142}
143
151{
153 {
156 }
157}
158
174void SyncReleaseEraseReq(unsigned int chNo, unsigned int wayNo, unsigned int blockNo)
175{
176 while (rowAddrDependencyTablePtr->block[chNo][wayNo][blockNo].blockedEraseReqFlag)
177 {
180 }
181}
182
187{
188 int chNo;
189
190 for (chNo = 0; chNo < USER_CHANNELS; chNo++)
192}
193
211void SchedulingNandReqPerCh(unsigned int chNo)
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}
498
499/* -------------------------------------------------------------------------- */
500/* functions for adjusting the die state list */
501/* -------------------------------------------------------------------------- */
502
511void PutToNandWayPriorityTable(unsigned int reqSlotTag, unsigned int chNo, unsigned int wayNo)
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}
527
536void PutToNandIdleList(unsigned int chNo, unsigned int wayNo)
537{
539 {
544 }
545 else
546 {
551 }
552}
553
568void SelectivGetFromNandIdleList(unsigned int chNo, unsigned int wayNo)
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}
596
605void PutToNandStatusReportList(unsigned int chNo, unsigned int wayNo)
606{
608 {
613 }
614 else
615 {
620 }
621}
622
633void SelectivGetFromNandStatusReportList(unsigned int chNo, unsigned int wayNo)
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}
661
670void PutToNandReadTriggerList(unsigned int chNo, unsigned int wayNo)
671{
673 {
678 }
679 else
680 {
685 }
686}
687
696void SelectiveGetFromNandReadTriggerList(unsigned int chNo, unsigned int wayNo)
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}
724
733void PutToNandWriteList(unsigned int chNo, unsigned int wayNo)
734{
736 {
741 }
742 else
743 {
748 }
749}
750
759void SelectiveGetFromNandWriteList(unsigned int chNo, unsigned int wayNo)
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}
787
796void PutToNandReadTransferList(unsigned int chNo, unsigned int wayNo)
797{
799 {
804 }
805 else
806 {
811 }
812}
813
822void SelectiveGetFromNandReadTransferList(unsigned int chNo, unsigned int wayNo)
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}
850
859void PutToNandEraseList(unsigned int chNo, unsigned int wayNo)
860{
862 {
867 }
868 else
869 {
874 }
875}
876
885void SelectiveGetFromNandEraseList(unsigned int chNo, unsigned int wayNo)
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}
913
922void PutToNandStatusCheckList(unsigned int chNo, unsigned int wayNo)
923{
925 {
930 }
931 else
932 {
937 }
938}
939
948void SelectiveGetFromNandStatusCheckList(unsigned int chNo, unsigned int wayNo)
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}
976
977/* -------------------------------------------------------------------------- */
978/* end of functions for managing die state lists */
979/* -------------------------------------------------------------------------- */
980
1013void IssueNandReq(unsigned int chNo, unsigned int wayNo)
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}
1072
1085unsigned int GenerateNandRowAddr(unsigned int reqSlotTag)
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}
1132
1169unsigned int GenerateDataBufAddr(unsigned int reqSlotTag)
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}
1201
1216unsigned int GenerateSpareDataBufAddr(unsigned int reqSlotTag)
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}
1243
1257unsigned int CheckReqStatus(unsigned int chNo, unsigned int wayNo)
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}
1320
1321unsigned int CheckEccErrorInfo(unsigned int chNo, unsigned int wayNo)
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}
1342
1386void ExecuteNandReq(unsigned int chNo, unsigned int wayNo, unsigned int reqStatus)
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.
P_PHY_BLOCK_MAP phyBlockMapPtr
#define Vsa2VpageTranslation(virtualSliceAddr)
#define Pcw2VdieTranslation(chNo, wayNo)
Get die number from physical channel number and way number.
#define Vsa2VdieTranslation(virtualSliceAddr)
#define Vblock2PblockOfTbsTranslation(blockNo)
Get the PBA (in total block space) of the given VBN.
#define Vsa2VblockTranslation(virtualSliceAddr)
#define pr_warn(fmt,...)
Definition: debug.h:87
#define pr_debug(fmt,...)
Definition: debug.h:84
T4REGS chCtlReg[USER_CHANNELS]
Definition: ftl_config.c:57
#define BIT_ERROR_THRESHOLD_PER_CHUNK
Definition: ftl_config.h:187
#define USER_CHANNELS
Definition: ftl_config.h:207
#define TOTAL_BLOCKS_PER_LUN
Definition: ftl_config.h:155
#define BYTES_PER_DATA_REGION_OF_SLICE
Definition: ftl_config.h:212
#define BYTES_PER_NVME_BLOCK
Definition: ftl_config.h:194
#define BYTES_PER_SPARE_REGION_OF_SLICE
Definition: ftl_config.h:213
#define PAGES_PER_MLC_BLOCK
Definition: ftl_config.h:183
#define MAIN_BLOCKS_PER_LUN
Definition: ftl_config.h:153
#define USER_WAYS
Definition: ftl_config.h:208
#define RESERVED_DATA_BUFFER_BASE_ADDR
Definition: memory_map.h:85
#define ERROR_INFO_TABLE_ADDR
Definition: memory_map.h:91
#define TEMPORARY_DATA_BUFFER_BASE_ADDR
Definition: memory_map.h:78
#define STATUS_REPORT_TABLE_ADDR
Definition: memory_map.h:90
#define SPARE_DATA_BUFFER_BASE_ADDR
Definition: memory_map.h:80
#define RETRY_LIMIT_TABLE_ADDR
Definition: memory_map.h:114
#define DIE_STATE_TABLE_ADDR
Definition: memory_map.h:113
#define TEMPORARY_PAY_LOAD_ADDR
Definition: memory_map.h:92
#define TEMPORARY_SPARE_DATA_BUFFER_BASE_ADDR
Definition: memory_map.h:83
#define WAY_PRIORITY_TABLE_ADDR
Definition: memory_map.h:115
#define DATA_BUFFER_BASE_ADDR
The base address of buffer for DMA requests.
Definition: memory_map.h:77
#define COMPLETE_FLAG_TABLE_ADDR
Definition: memory_map.h:89
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 V2FRequestReportDone(statusReport)
Definition: nsc_driver.h:113
#define V2FEnterToggleMode(dev, way, payLoadAddr)
Definition: nsc_driver.h:109
#define V2FIsControllerBusy(t4regs)
Definition: nsc_driver.h:100
void V2FStatusCheckAsync(T4REGS *t4regs, int way, unsigned int *statusReport)
void V2FEraseBlockAsync(T4REGS *t4regs, int way, unsigned int rowAddress)
#define V2FCrcValid(errorInformation)
Definition: nsc_driver.h:104
#define V2FRequestComplete(statusReport)
Definition: nsc_driver.h:115
#define V2FRequestFail(statusReport)
Definition: nsc_driver.h:116
void V2FProgramPageAsync(T4REGS *t4regs, int way, unsigned int rowAddress, void *pageDataBuffer, void *spareDataBuffer)
#define V2FTransferComplete(completeFlag)
Definition: nsc_driver.h:112
#define V2FEliminateReportDoneFlag(statusReport)
Definition: nsc_driver.h:114
#define V2FWorstChunkErrorCount(errorInformation)
Definition: nsc_driver.h:105
unsigned int V2FReadyBusyAsync(T4REGS *t4regs)
#define V2FWayReady(readyBusy, wayNo)
Definition: nsc_driver.h:111
void V2FResetSync(T4REGS *t4regs, int way)
unsigned int blockedReqCnt
NVME_DMA_REQUEST_QUEUE nvmeDmaReqQ
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.
unsigned int notCompletedNandReqCnt
P_REQ_POOL reqPoolPtr
NAND_REQUEST_QUEUE nandReqQ[USER_CHANNELS][USER_WAYS]
FREE_REQUEST_QUEUE freeReqQ
#define REQ_SLOT_TAG_NONE
#define REQ_OPT_BLOCK_SPACE_MAIN
for the 1 bit flag REQ_OPTION::blockSpace.
#define REQ_OPT_BLOCK_SPACE_TOTAL
#define REQ_TYPE_NVME_DMA
#define REQ_OPT_DATA_BUF_TEMP_ENTRY
#define REQ_OPT_DATA_BUF_ADDR
#define REQ_CODE_RESET
#define REQ_CODE_WRITE
#define REQ_OPT_NAND_ECC_WARNING_ON
#define REQ_CODE_READ_TRANSFER
#define REQ_OPT_NAND_ADDR_VSA
#define REQ_CODE_ERASE
#define REQ_OPT_DATA_BUF_ENTRY
#define REQ_CODE_SET_FEATURE
#define REQ_CODE_READ
#define REQ_OPT_NAND_ADDR_PHY_ORG
#define REQ_TYPE_NAND
#define REQ_OPT_NAND_ECC_ON
#define REQ_OPT_NAND_ECC_OFF
unsigned int GenerateDataBufAddr(unsigned int reqSlotTag)
Get the corresponding data buffer entry address of the given request.
void SyncReleaseEraseReq(unsigned int chNo, unsigned int wayNo, unsigned int blockNo)
Issuing requests until the specified block can be erased.
void PutToNandEraseList(unsigned int chNo, unsigned int wayNo)
Append the specified die to the tail of the erase list of its channel.
void IssueNandReq(unsigned int chNo, unsigned int wayNo)
Issue a flash operations to the storage controller.
P_RETRY_LIMIT_TABLE retryLimitTablePtr
P_COMPLETE_FLAG_TABLE completeFlagTablePtr
P_DIE_STATE_TABLE dieStateTablePtr
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 SyncAllLowLevelReqDone()
Do schedule until all the requests are done.
void InitReqScheduler()
Initialize scheduling related tables.
void SelectivGetFromNandStatusReportList(unsigned int chNo, unsigned int wayNo)
Remove the specified die from the status report list of its channel.
unsigned int GenerateSpareDataBufAddr(unsigned int reqSlotTag)
Get the corresponding sparse data buffer entry address of the given request.
void PutToNandReadTriggerList(unsigned int chNo, unsigned int wayNo)
Append the specified die to the tail of the read trigger list of its channel.
void SyncAvailFreeReq()
Try release request entries by doing scheduling (both NVMe and NAND).
unsigned int CheckEccErrorInfo(unsigned int chNo, unsigned int wayNo)
unsigned int CheckReqStatus(unsigned int chNo, unsigned int wayNo)
Update the die status and return the request status.
void SchedulingNandReqPerCh(unsigned int chNo)
The main function to schedule NAND requests on the specified channel.
P_WAY_PRIORITY_TABLE wayPriorityTablePtr
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 PutToNandWriteList(unsigned int chNo, unsigned int wayNo)
Append the specified die to the tail of the write 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.
P_ERROR_INFO_TABLE eccErrorInfoTablePtr
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.
P_STATUS_REPORT_TABLE statusReportTablePtr
unsigned int GenerateNandRowAddr(unsigned int reqSlotTag)
Get the nand row (block) address of the given request.
void PutToNandReadTransferList(unsigned int chNo, unsigned int wayNo)
Append the specified die to the tail of the read transfer 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 SchedulingNandReq()
Iteratively do schedule on each channel by calling SchedulingNandReqPerCh.
#define REQ_STATUS_FAIL
struct _STATUS_REPORT_TABLE * P_STATUS_REPORT_TABLE
struct _ERROR_INFO_TABLE * P_ERROR_INFO_TABLE
struct _RETRY_LIMIT_TABLE * P_RETRY_LIMIT_TABLE
#define LUN_1_BASE_ADDR
#define REQ_STATUS_CHECK_OPT_COMPLETION_FLAG
#define ERROR_INFO_WARNING
#define REQ_STATUS_RUNNING
struct _COMPLETE_FLAG_TABLE * P_COMPLETE_FLAG_TABLE
#define WAY_NONE
struct _WAY_PRIORITY_TABLE * P_WAY_PRIORITY_TABLE
#define REQ_STATUS_CHECK_OPT_NONE
struct _DIE_STATE_TABLE * P_DIE_STATE_TABLE
#define PSEUDO_BAD_BLOCK_MARK
#define REQ_STATUS_CHECK_OPT_REPORT
#define DIE_STATE_IDLE
#define REQ_STATUS_CHECK_OPT_CHECK
#define REQ_STATUS_WARNING
#define RETRY_LIMIT
The max number of times a request can retry if it failed.
#define LUN_0_BASE_ADDR
#define DIE_STATE_EXE
#define ERROR_INFO_FAIL
#define ERROR_INFO_PASS
#define REQ_STATUS_DONE
void ReleaseBlockedByRowAddrDepReq(unsigned int chNo, unsigned int wayNo)
Update the row address dependency of all the requests on the specified die.
P_ROW_ADDR_DEPENDENCY_TABLE rowAddrDependencyTablePtr
void CheckDoneNvmeDmaReq()
unsigned int completeFlag[USER_CHANNELS][USER_WAYS]
unsigned int entry
unsigned int addr
unsigned int nextWay
unsigned int prevWay
unsigned int dieState
unsigned int reqStatusCheckOpt
The status table of each die on the flash memory.
DIE_STATE_ENTRY dieState[USER_CHANNELS][USER_WAYS]
unsigned int errorInfo[USER_CHANNELS][USER_WAYS][ERROR_INFO_WORD_COUNT]
unsigned int headReq
Definition: request_queue.h:52
unsigned int physicalBlock
unsigned int physicalWay
unsigned int physicalPage
unsigned int virtualSliceAddr
unsigned int physicalCh
unsigned int headReq
Definition: request_queue.h:92
unsigned int nvmeBlockOffset
unsigned int remappedPhyBlock
PHY_BLOCK_ENTRY phyBlock[USER_DIES][TOTAL_BLOCKS_PER_DIE]
unsigned int nandEccWarning
unsigned int dataBufFormat
Type of address stored in the SSD_REQ_FORMAT::dataBufInfo.
unsigned int nandAddr
Type of address stored in the SSD_REQ_FORMAT::nandInfo.
unsigned int blockSpace
unsigned int nandEcc
SSD_REQ_FORMAT reqPool[AVAILABLE_OUNTSTANDING_REQ_COUNT]
int retryLimit[USER_CHANNELS][USER_WAYS]
unsigned int blockedEraseReqFlag
ROW_ADDR_DEPENDENCY_ENTRY block[USER_CHANNELS][USER_WAYS][MAIN_BLOCKS_PER_DIE]
REQ_OPTION reqOpt
DATA_BUF_INFO dataBufInfo
unsigned int reqCode
NVME_DMA_INFO nvmeDmaInfo
NAND_INFO nandInfo
unsigned int reqType
unsigned int statusReport[USER_CHANNELS][USER_WAYS]
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
The channel status table, each entry contains 7 lists.
WAY_PRIORITY_ENTRY wayPriority[USER_CHANNELS]