void cmd_sdc(BaseSequentialStream *chp, int argc, char *argv[]) { static const char *mode[] = {"SDV11", "SDV20", "MMC", NULL}; systime_t start, end; uint32_t n, startblk; if (argc != 1) { chprintf(chp, "Usage: sdiotest read|write|erase|all\r\n"); return; } /* Card presence check.*/ if (!blkIsInserted(&SDCD1)) { chprintf(chp, "Card not inserted, aborting.\r\n"); return; } /* Connection to the card.*/ chprintf(chp, "Connecting... "); if (sdcConnect(&SDCD1)) { chprintf(chp, "failed\r\n"); return; } chprintf(chp, "OK\r\n\r\nCard Info\r\n"); chprintf(chp, "CSD : %08X %8X %08X %08X \r\n", SDCD1.csd[3], SDCD1.csd[2], SDCD1.csd[1], SDCD1.csd[0]); chprintf(chp, "CID : %08X %8X %08X %08X \r\n", SDCD1.cid[3], SDCD1.cid[2], SDCD1.cid[1], SDCD1.cid[0]); chprintf(chp, "Mode : %s\r\n", mode[SDCD1.cardmode & 3U]); chprintf(chp, "Capacity : %DMB\r\n", SDCD1.capacity / 2048); /* The test is performed in the middle of the flash area.*/ startblk = (SDCD1.capacity / MMCSD_BLOCK_SIZE) / 2; if ((strcmp(argv[0], "read") == 0) || (strcmp(argv[0], "all") == 0)) { /* Single block read performance, aligned.*/ chprintf(chp, "Single block aligned read performance: "); start = chVTGetSystemTime(); end = start + MS2ST(1000); n = 0; do { if (blkRead(&SDCD1, startblk, buf, 1)) { chprintf(chp, "failed\r\n"); goto exittest; } n++; } while (chVTIsSystemTimeWithin(start, end)); chprintf(chp, "%D blocks/S, %D bytes/S\r\n", n, n * MMCSD_BLOCK_SIZE); /* Multiple sequential blocks read performance, aligned.*/ chprintf(chp, "16 sequential blocks aligned read performance: "); start = chVTGetSystemTime(); end = start + MS2ST(1000); n = 0; do { if (blkRead(&SDCD1, startblk, buf, SDC_BURST_SIZE)) { chprintf(chp, "failed\r\n"); goto exittest; } n += SDC_BURST_SIZE; } while (chVTIsSystemTimeWithin(start, end)); chprintf(chp, "%D blocks/S, %D bytes/S\r\n", n, n * MMCSD_BLOCK_SIZE); #if STM32_SDC_SDIO_UNALIGNED_SUPPORT /* Single block read performance, unaligned.*/ chprintf(chp, "Single block unaligned read performance: "); start = chVTGetSystemTime(); end = start + MS2ST(1000); n = 0; do { if (blkRead(&SDCD1, startblk, buf + 1, 1)) { chprintf(chp, "failed\r\n"); goto exittest; } n++; } while (chVTIsSystemTimeWithin(start, end)); chprintf(chp, "%D blocks/S, %D bytes/S\r\n", n, n * MMCSD_BLOCK_SIZE); /* Multiple sequential blocks read performance, unaligned.*/ chprintf(chp, "16 sequential blocks unaligned read performance: "); start = chVTGetSystemTime(); end = start + MS2ST(1000); n = 0; do { if (blkRead(&SDCD1, startblk, buf + 1, SDC_BURST_SIZE)) { chprintf(chp, "failed\r\n"); goto exittest; } n += SDC_BURST_SIZE; } while (chVTIsSystemTimeWithin(start, end)); chprintf(chp, "%D blocks/S, %D bytes/S\r\n", n, n * MMCSD_BLOCK_SIZE); #endif /* STM32_SDC_SDIO_UNALIGNED_SUPPORT */ } if ((strcmp(argv[0], "write") == 0) || (strcmp(argv[0], "all") == 0)) { unsigned i; memset(buf, 0xAA, MMCSD_BLOCK_SIZE * 2); chprintf(chp, "Writing..."); if(sdcWrite(&SDCD1, startblk, buf, 2)) { chprintf(chp, "failed\r\n"); goto exittest; } chprintf(chp, "OK\r\n"); memset(buf, 0x55, MMCSD_BLOCK_SIZE * 2); chprintf(chp, "Reading..."); if (blkRead(&SDCD1, startblk, buf, 1)) { chprintf(chp, "failed\r\n"); goto exittest; } chprintf(chp, "OK\r\n"); for (i = 0; i < MMCSD_BLOCK_SIZE; i++) buf[i] = i + 8; chprintf(chp, "Writing..."); if(sdcWrite(&SDCD1, startblk, buf, 2)) { chprintf(chp, "failed\r\n"); goto exittest; } chprintf(chp, "OK\r\n"); memset(buf, 0, MMCSD_BLOCK_SIZE * 2); chprintf(chp, "Reading..."); if (blkRead(&SDCD1, startblk, buf, 1)) { chprintf(chp, "failed\r\n"); goto exittest; } chprintf(chp, "OK\r\n"); } if ((strcmp(argv[0], "erase") == 0) || (strcmp(argv[0], "all") == 0)) { /** * Test sdcErase() * Strategy: * 1. Fill two blocks with non-constant data * 2. Write two blocks starting at startblk * 3. Erase the second of the two blocks * 3.1. First block should be equal to the data written * 3.2. Second block should NOT be equal too the data written (i.e. erased). * 4. Erase both first and second block * 4.1 Both blocks should not be equal to the data initially written * Precondition: SDC_BURST_SIZE >= 2 */ memset(buf, 0, MMCSD_BLOCK_SIZE * 2); memset(buf2, 0, MMCSD_BLOCK_SIZE * 2); /* 1. */ unsigned int i = 0; for (; i < MMCSD_BLOCK_SIZE * 2; ++i) { buf[i] = (i + 7) % 'T'; //Ensure block 1/2 are not equal } /* 2. */ if(sdcWrite(&SDCD1, startblk, buf, 2)) { chprintf(chp, "sdcErase() test write failed\r\n"); goto exittest; } /* 3. (erase) */ if(sdcErase(&SDCD1, startblk + 1, startblk + 2)) { chprintf(chp, "sdcErase() failed\r\n"); goto exittest; } sdcflags_t errflags = sdcGetAndClearErrors(&SDCD1); if(errflags) { chprintf(chp, "sdcErase() yielded error flags: %d\r\n", errflags); goto exittest; } if(sdcRead(&SDCD1, startblk, buf2, 2)) { chprintf(chp, "single-block sdcErase() failed\r\n"); goto exittest; } /* 3.1. */ if(memcmp(buf, buf2, MMCSD_BLOCK_SIZE) != 0) { chprintf(chp, "sdcErase() non-erased block compare failed\r\n"); goto exittest; } /* 3.2. */ if(memcmp(buf + MMCSD_BLOCK_SIZE, buf2 + MMCSD_BLOCK_SIZE, MMCSD_BLOCK_SIZE) == 0) { chprintf(chp, "sdcErase() erased block compare failed\r\n"); goto exittest; } /* 4. */ if(sdcErase(&SDCD1, startblk, startblk + 2)) { chprintf(chp, "multi-block sdcErase() failed\r\n"); goto exittest; } if(sdcRead(&SDCD1, startblk, buf2, 2)) { chprintf(chp, "single-block sdcErase() failed\r\n"); goto exittest; } /* 4.1 */ if(memcmp(buf, buf2, MMCSD_BLOCK_SIZE) == 0) { chprintf(chp, "multi-block sdcErase() erased block compare failed\r\n"); goto exittest; } if(memcmp(buf + MMCSD_BLOCK_SIZE, buf2 + MMCSD_BLOCK_SIZE, MMCSD_BLOCK_SIZE) == 0) { chprintf(chp, "multi-block sdcErase() erased block compare failed\r\n"); goto exittest; } /* END of sdcErase() test */ } /* Card disconnect and command end.*/ exittest: sdcDisconnect(&SDCD1); }
/******************************************************************** Desc: This routine follows all of the blocks in a chain, verifying that they are properly linked. It also verifies each block's header. *********************************************************************/ RCODE F_DbCheck::verifyBlkChain( BLOCK_INFO * pBlkInfo, FLMUINT uiLocale, FLMUINT uiFirstBlkAddr, FLMUINT uiBlkType, FLMBOOL * pbStartOverRV ) { RCODE rc = NE_XFLM_OK; FLMINT32 i32VerifyCode = 0; F_CachedBlock * pSCache = NULL; F_BLK_HDR * pBlkHdr = NULL; FLMUINT uiPrevBlkAddress; FLMUINT uiBlkCount = 0; STATE_INFO StateInfo; FLMBOOL bStateInitialized = FALSE; FLMUINT64 ui64SaveBytesExamined; FLMUINT uiBlockSize = m_pDb->m_pDatabase->getBlockSize(); FLMUINT uiMaxBlocks = (FLMUINT)(FSGetSizeInBytes( m_pDb->m_pDatabase->getMaxFileSize(), m_pDb->m_uiLogicalEOF) / (FLMUINT64)uiBlockSize); uiPrevBlkAddress = 0; /* There must be at least ONE block if it is the LFH chain. */ if ((uiBlkType == BT_LFH_BLK) && (uiFirstBlkAddr == 0)) { i32VerifyCode = FLM_BAD_LFH_LIST_PTR; (void)chkReportError( i32VerifyCode, (FLMUINT32)uiLocale, 0, 0, 0xFF, 0, 0, 0, 0); goto Exit; } /* Read through all of the blocks, verifying them as we go. */ Restart_Chain: uiBlkCount = 0; flmInitReadState( &StateInfo, &bStateInitialized, (FLMUINT)m_pDb->m_pDatabase-> m_lastCommittedDbHdr.ui32DbVersion, m_pDb, NULL, (FLMUINT)((uiBlkType == BT_FREE) ? (FLMUINT)0xFF : (FLMUINT)0), uiBlkType, NULL); ui64SaveBytesExamined = m_Progress.ui64BytesExamined; StateInfo.ui32BlkAddress = (FLMUINT32)uiFirstBlkAddr; while ((StateInfo.ui32BlkAddress != 0) && (uiBlkCount < uiMaxBlocks)) { StateInfo.pBlkHdr = NULL; if( RC_BAD( rc = blkRead( StateInfo.ui32BlkAddress, &pBlkHdr, &pSCache, &i32VerifyCode))) { if (rc == NE_XFLM_OLD_VIEW) { FLMUINT uiSaveDictSeq = m_pDb->m_pDict->getDictSeq(); if (RC_BAD( rc = getDictInfo())) goto Exit; // If the dictionary ID changed, start over. if (m_pDb->m_pDict->getDictSeq() != uiSaveDictSeq) { *pbStartOverRV = TRUE; goto Exit; } m_Progress.ui64BytesExamined = ui64SaveBytesExamined; goto Restart_Chain; } pBlkInfo->i32ErrCode = i32VerifyCode; pBlkInfo->uiNumErrors++; rc = chkReportError( i32VerifyCode, (FLMUINT32)uiLocale, 0, 0, 0xFF, StateInfo.ui32BlkAddress, 0, 0, 0); } StateInfo.pBlkHdr = pBlkHdr; uiBlkCount++; m_Progress.ui64BytesExamined += (FLMUINT64)uiBlockSize; if (RC_BAD( rc = chkCallProgFunc())) { goto Exit; } f_yieldCPU(); if ((i32VerifyCode = flmVerifyBlockHeader( &StateInfo, pBlkInfo, uiBlockSize, 0xFFFFFFFF, uiPrevBlkAddress, TRUE)) != 0) { pBlkInfo->i32ErrCode = i32VerifyCode; pBlkInfo->uiNumErrors++; chkReportError( i32VerifyCode, (FLMUINT32)uiLocale, 0, 0, 0xFF, StateInfo.ui32BlkAddress, 0, 0, 0); goto Exit; } uiPrevBlkAddress = StateInfo.ui32BlkAddress; StateInfo.ui32BlkAddress = pBlkHdr->ui32NextBlkInChain; } if (StateInfo.ui32BlkAddress != 0 && RC_OK( m_LastStatusRc)) { switch (uiBlkType) { case BT_LFH_BLK: i32VerifyCode = FLM_BAD_LFH_LIST_END; break; case BT_FREE: i32VerifyCode = FLM_BAD_AVAIL_LIST_END; break; } pBlkInfo->i32ErrCode = i32VerifyCode; pBlkInfo->uiNumErrors++; chkReportError( i32VerifyCode, (FLMUINT32)uiLocale, 0, 0, 0xFF, (FLMUINT32)uiPrevBlkAddress, 0, 0, 0); goto Exit; } Exit: if( pSCache) { ScaReleaseCache( pSCache, FALSE); } else if( pBlkHdr) { f_free( &pBlkHdr); } if (RC_OK(rc) && (i32VerifyCode != 0)) { rc = RC_SET( NE_XFLM_DATA_ERROR); } return( rc); }