diff --git a/CHANGELOG.md b/CHANGELOG.md index ea20a01..5969a54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ The version lives in `_VER` in `src/main.c`. Binaries are published only as the [`latest`](https://github.com/OpenIPC/microsnander/releases/latest) release, rebuilt from every push to `main`; this file is the change history. +## 1.20.2 — 2026-11-04 + +- SPI NAND: a USB transfer that fails now fails the operation. The result of a read from the + cache and of a status read was not looked at: a read ended with `Status: OK` and wrong data, + a write programmed a page over data it had not read, and page data that never reached the + chip still ended in a program command and `Status: OK`. The read, write or erase stops with + a message, and the failed page is not kept. So does the detection, when the ECC setup fails. + ## 1.20.1 — 2026-11-04 - Faster SPI NAND reads: the ECC check of a page takes the status its ready poll has already diff --git a/src/main.c b/src/main.c index 3af4293..4f164b7 100644 --- a/src/main.c +++ b/src/main.c @@ -36,7 +36,7 @@ struct flash_cmd prog; extern unsigned int bsize; -#define _VER "1.20.1" +#define _VER "1.20.2" const char *ms_version = _VER; diff --git a/src/spi_nand_flash.c b/src/spi_nand_flash.c index 3de60c8..ccbf654 100644 --- a/src/spi_nand_flash.c +++ b/src/spi_nand_flash.c @@ -2705,7 +2705,8 @@ static SPI_NAND_FLASH_RTN_T spi_nand_protocol_set_feature( u8 addr, u8 data ) _SPI_NAND_WRITE_ONE_BYTE( data ); /* 5. Chip Select High */ - _SPI_NAND_READ_CHIP_SELECT_HIGH(); + if( _SPI_NAND_READ_CHIP_SELECT_HIGH() != SPI_CONTROLLER_RTN_NO_ERROR ) + rtn_status = SPI_NAND_FLASH_RTN_IO_ERROR; _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1, "spi_nand_protocol_set_feature %x: val = 0x%x\n", addr, data); @@ -2743,10 +2744,12 @@ static SPI_NAND_FLASH_RTN_T spi_nand_protocol_get_feature( u8 addr, u8 *ptr_rtn_ _SPI_NAND_WRITE_ONE_BYTE( addr ); /* 4. Read 1 byte data */ - _SPI_NAND_READ_NBYTE( ptr_rtn_data, _SPI_NAND_LEN_ONE_BYTE, SPI_CONTROLLER_SPEED_SINGLE); + if( _SPI_NAND_READ_NBYTE( ptr_rtn_data, _SPI_NAND_LEN_ONE_BYTE, SPI_CONTROLLER_SPEED_SINGLE) != SPI_CONTROLLER_RTN_NO_ERROR ) + rtn_status = SPI_NAND_FLASH_RTN_IO_ERROR; /* 5. Chip Select High */ - _SPI_NAND_READ_CHIP_SELECT_HIGH(); + if( _SPI_NAND_READ_CHIP_SELECT_HIGH() != SPI_CONTROLLER_RTN_NO_ERROR ) + rtn_status = SPI_NAND_FLASH_RTN_IO_ERROR; _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1, "spi_nand_protocol_get_feature %x: val = 0x%x\n", addr, *ptr_rtn_data); @@ -3239,11 +3242,13 @@ static SPI_NAND_FLASH_RTN_T spi_nand_protocol_read_from_cache( u32 data_offset, { struct SPI_NAND_FLASH_INFO_T *ptr_dev_info_t; SPI_NAND_FLASH_RTN_T rtn_status = SPI_NAND_FLASH_RTN_NO_ERROR; + SPI_CONTROLLER_RTN_T ret = SPI_CONTROLLER_RTN_NO_ERROR; ptr_dev_info_t = _SPI_NAND_GET_DEVICE_INFO_PTR; /* 1. Chip Select low */ - _SPI_NAND_READ_CHIP_SELECT_LOW(); + if( _SPI_NAND_READ_CHIP_SELECT_LOW() != SPI_CONTROLLER_RTN_NO_ERROR ) + rtn_status = SPI_NAND_FLASH_RTN_IO_ERROR; #if 0 /* 2. Send opcode */ switch (read_mode) @@ -3301,23 +3306,26 @@ static SPI_NAND_FLASH_RTN_T spi_nand_protocol_read_from_cache( u32 data_offset, switch (read_mode) { case SPI_NAND_FLASH_READ_SPEED_MODE_SINGLE: - _SPI_NAND_READ_NBYTE( ptr_rtn_buf, len, SPI_CONTROLLER_SPEED_SINGLE); + ret = _SPI_NAND_READ_NBYTE( ptr_rtn_buf, len, SPI_CONTROLLER_SPEED_SINGLE); break; case SPI_NAND_FLASH_READ_SPEED_MODE_DUAL: - _SPI_NAND_READ_NBYTE( ptr_rtn_buf, len, SPI_CONTROLLER_SPEED_DUAL); + ret = _SPI_NAND_READ_NBYTE( ptr_rtn_buf, len, SPI_CONTROLLER_SPEED_DUAL); break; case SPI_NAND_FLASH_READ_SPEED_MODE_QUAD: - _SPI_NAND_READ_NBYTE( ptr_rtn_buf, len, SPI_CONTROLLER_SPEED_QUAD); + ret = _SPI_NAND_READ_NBYTE( ptr_rtn_buf, len, SPI_CONTROLLER_SPEED_QUAD); break; default: break; } + if( ret != SPI_CONTROLLER_RTN_NO_ERROR ) + rtn_status = SPI_NAND_FLASH_RTN_IO_ERROR; /* 5. Chip Select High */ - _SPI_NAND_READ_CHIP_SELECT_HIGH(); + if( _SPI_NAND_READ_CHIP_SELECT_HIGH() != SPI_CONTROLLER_RTN_NO_ERROR ) + rtn_status = SPI_NAND_FLASH_RTN_IO_ERROR; _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1, "spi_nand_protocol_read_from_cache : data_offset = 0x%x, buf = 0x%x\n", data_offset, ptr_rtn_buf); @@ -3350,13 +3358,15 @@ static SPI_NAND_FLASH_RTN_T spi_nand_protocol_program_load ( u32 addr, u8 *ptr_d { struct SPI_NAND_FLASH_INFO_T *ptr_dev_info_t; SPI_NAND_FLASH_RTN_T rtn_status = SPI_NAND_FLASH_RTN_NO_ERROR; + SPI_CONTROLLER_RTN_T ret = SPI_CONTROLLER_RTN_NO_ERROR; ptr_dev_info_t = _SPI_NAND_GET_DEVICE_INFO_PTR; _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1, "spi_nand_protocol_program_load: addr = 0xl%x, len = 0x%x\n", addr, len ); /* 1. Chip Select low */ - _SPI_NAND_READ_CHIP_SELECT_LOW(); + if( _SPI_NAND_READ_CHIP_SELECT_LOW() != SPI_CONTROLLER_RTN_NO_ERROR ) + rtn_status = SPI_NAND_FLASH_RTN_IO_ERROR; #if 0 /* 2. Send opcode */ switch (write_mode) @@ -3393,19 +3403,23 @@ static SPI_NAND_FLASH_RTN_T spi_nand_protocol_program_load ( u32 addr, u8 *ptr_d switch (write_mode) { case SPI_NAND_FLASH_WRITE_SPEED_MODE_SINGLE: - _SPI_NAND_WRITE_NBYTE( ptr_data, len, SPI_CONTROLLER_SPEED_SINGLE); + ret = _SPI_NAND_WRITE_NBYTE( ptr_data, len, SPI_CONTROLLER_SPEED_SINGLE); break; case SPI_NAND_FLASH_WRITE_SPEED_MODE_QUAD: - _SPI_NAND_WRITE_NBYTE( ptr_data, len, SPI_CONTROLLER_SPEED_QUAD); + ret = _SPI_NAND_WRITE_NBYTE( ptr_data, len, SPI_CONTROLLER_SPEED_QUAD); break; default: break; } + /* a page is too long to be held: this is the only place its failure shows */ + if( ret != SPI_CONTROLLER_RTN_NO_ERROR ) + rtn_status = SPI_NAND_FLASH_RTN_IO_ERROR; /* 5. Chip Select High */ - _SPI_NAND_READ_CHIP_SELECT_HIGH(); + if( _SPI_NAND_READ_CHIP_SELECT_HIGH() != SPI_CONTROLLER_RTN_NO_ERROR ) + rtn_status = SPI_NAND_FLASH_RTN_IO_ERROR; return (rtn_status); } @@ -3860,14 +3874,27 @@ static long long spi_nand_now_ms(void) return (long long)ts.tv_sec * 1000 + ts.tv_nsec / 1000000; } +/* Failures that end the operation: the chip's state is not known, so they are + neither a BAD page for -k nor a result to go on from. */ +static int spi_nand_stopped( SPI_NAND_FLASH_RTN_T status ) +{ + return status == SPI_NAND_FLASH_RTN_TIMEOUT || status == SPI_NAND_FLASH_RTN_IO_ERROR; +} + /* Poll the status register until OIP clears; the last status is in *ptr_status. - SPI_NAND_FLASH_RTN_TIMEOUT if the chip is still busy after the timeout. */ + SPI_NAND_FLASH_RTN_TIMEOUT if the chip is still busy after the timeout, + SPI_NAND_FLASH_RTN_IO_ERROR if the status did not come back over USB. That is + also how a command that failed before it shows: the failure of a held transfer + comes with the next read (spi_controller.c). */ static SPI_NAND_FLASH_RTN_T spi_nand_wait_ready( u8 *ptr_status, const char *what, u32 index ) { long long start = spi_nand_now_ms(); for (;;) { - spi_nand_protocol_get_status_reg_3( ptr_status ); + if( spi_nand_protocol_get_status_reg_3( ptr_status ) != SPI_NAND_FLASH_RTN_NO_ERROR ) { + _SPI_NAND_PRINTF("\n%s 0x%x: the USB transfer failed\n", what, index); + return SPI_NAND_FLASH_RTN_IO_ERROR; + } if( !(*ptr_status & _SPI_NAND_VAL_OIP) ) return SPI_NAND_FLASH_RTN_NO_ERROR; if( spi_nand_now_ms() - start > SPI_NAND_OIP_TIMEOUT_MS ) { @@ -3896,8 +3923,9 @@ static SPI_NAND_FLASH_RTN_T spi_nand_load_page_into_cache( u32 page_number) spi_nand_protocol_page_read ( page_number ); /* Checking status for load page/erase/program complete */ - if( spi_nand_wait_ready( &status, "Page read", page_number ) != SPI_NAND_FLASH_RTN_NO_ERROR ) - return SPI_NAND_FLASH_RTN_TIMEOUT; + rtn_status = spi_nand_wait_ready( &status, "Page read", page_number ); + if( rtn_status != SPI_NAND_FLASH_RTN_NO_ERROR ) + return rtn_status; _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1, "spi_nand_load_page_into_cache : status = 0x%x\n", status); if (ECC_fcheck && !ECC_ignore) @@ -3985,9 +4013,10 @@ SPI_NAND_FLASH_RTN_T spi_nand_erase_block ( u32 block_index) spi_nand_protocol_block_erase( block_index ); /* 2.4 Checking status for erase complete */ - if( spi_nand_wait_ready( &status, "Block erase", block_index ) != SPI_NAND_FLASH_RTN_NO_ERROR ) { + rtn_status = spi_nand_wait_ready( &status, "Block erase", block_index ); + if( rtn_status != SPI_NAND_FLASH_RTN_NO_ERROR ) { spi_nand_protocol_write_disable(); - return SPI_NAND_FLASH_RTN_TIMEOUT; + return rtn_status; } /* 2.5 Disable write_flash */ @@ -4061,7 +4090,7 @@ static SPI_NAND_FLASH_RTN_T spi_nand_erase_internal( u32 addr, u32 len ) _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1, "spi_nand_erase_internal: addr = 0x%x, len = 0x%x, block_idx = 0x%x\n", addr, len, block_index ); rtn_status = spi_nand_erase_block(block_index); - if( rtn_status == SPI_NAND_FLASH_RTN_TIMEOUT ) + if( spi_nand_stopped(rtn_status) ) break; /* 2.6 Check Erase Fail Bit: the erase goes on with the next blocks, @@ -4082,7 +4111,7 @@ static SPI_NAND_FLASH_RTN_T spi_nand_erase_internal( u32 addr, u32 len ) fflush(stdout); } } - if( rtn_status == SPI_NAND_FLASH_RTN_TIMEOUT ) + if( spi_nand_stopped(rtn_status) ) printf("Erase stopped at [%u] of [%u] bytes \n", erase_len, len); else if( failed ) { @@ -4122,7 +4151,7 @@ static SPI_NAND_FLASH_RTN_T spi_nand_read_page (u32 page_number, SPI_NAND_FLASH_ /* 1. Load Page into cache of NAND Flash Chip */ rtn_status = spi_nand_load_page_into_cache(page_number); - if( rtn_status == SPI_NAND_FLASH_RTN_TIMEOUT ) + if( spi_nand_stopped(rtn_status) ) return rtn_status; if( rtn_status == SPI_NAND_FLASH_RTN_DETECTED_BAD_BLOCK ) { @@ -4148,8 +4177,12 @@ static SPI_NAND_FLASH_RTN_T spi_nand_read_page (u32 page_number, SPI_NAND_FLASH_ _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1,"spi_nand_read_page: plane select = 0x%x\n", _plane_select_bit); } + if( spi_nand_protocol_read_from_cache(read_addr, ((ptr_dev_info_t->page_size)+(ptr_dev_info_t->oob_size)), &_current_cache_page[0], speed_mode, ptr_dev_info_t->dummy_mode ) != SPI_NAND_FLASH_RTN_NO_ERROR ) { - spi_nand_protocol_read_from_cache(read_addr, ((ptr_dev_info_t->page_size)+(ptr_dev_info_t->oob_size)), &_current_cache_page[0], speed_mode, ptr_dev_info_t->dummy_mode ); + /* the buffers do not hold this page: the next read goes to the chip */ + _current_page_num = 0xFFFFFFFF; + _SPI_NAND_PRINTF("\nPage read 0x%x: the USB transfer failed\n", page_number); + return SPI_NAND_FLASH_RTN_IO_ERROR; } _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_2, "spi_nand_read_page: after read, _current_cache_page:\n"); @@ -4222,7 +4255,7 @@ static SPI_NAND_FLASH_RTN_T spi_nand_write_page( u32 page_number, u32 data_offse /* with -k a BAD page must still be found, as a -k read skips it */ if( Skip_BAD_page ) { rtn_status = spi_nand_read_page(page_number, speed_mode); - if( rtn_status == SPI_NAND_FLASH_RTN_TIMEOUT || rtn_status == SPI_NAND_FLASH_RTN_DETECTED_BAD_BLOCK ) + if( spi_nand_stopped(rtn_status) || rtn_status == SPI_NAND_FLASH_RTN_DETECTED_BAD_BLOCK ) return rtn_status; } return SPI_NAND_FLASH_RTN_NO_ERROR; @@ -4238,7 +4271,7 @@ static SPI_NAND_FLASH_RTN_T spi_nand_write_page( u32 page_number, u32 data_offse /* Read Current page data to software cache buffer */ rtn_status = spi_nand_read_page(page_number, speed_mode); - if( rtn_status == SPI_NAND_FLASH_RTN_TIMEOUT ) + if( spi_nand_stopped(rtn_status) ) return rtn_status; if (Skip_BAD_page && (rtn_status == SPI_NAND_FLASH_RTN_DETECTED_BAD_BLOCK)) { /* skip BAD page, go to next page */ return SPI_NAND_FLASH_RTN_DETECTED_BAD_BLOCK; @@ -4302,9 +4335,7 @@ static SPI_NAND_FLASH_RTN_T spi_nand_write_page( u32 page_number, u32 data_offse ((ptr_dev_info_t->mfr_id) == _SPI_NAND_MANUFACTURER_ID_ATO_2) || (((ptr_dev_info_t->mfr_id) == _SPI_NAND_MANUFACTURER_ID_ATO) && ((ptr_dev_info_t->dev_id) == _SPI_NAND_DEVICE_ID_ATO25D2GA))) { - { - spi_nand_protocol_program_load(write_addr, &_current_cache_page[0], ((ptr_dev_info_t->page_size) + (ptr_dev_info_t->oob_size)), speed_mode); - } + rtn_status = spi_nand_protocol_program_load(write_addr, &_current_cache_page[0], ((ptr_dev_info_t->page_size) + (ptr_dev_info_t->oob_size)), speed_mode); /* Enable write_to flash */ spi_nand_protocol_write_enable(); @@ -4314,19 +4345,28 @@ static SPI_NAND_FLASH_RTN_T spi_nand_write_page( u32 page_number, u32 data_offse /* Enable write_to flash */ spi_nand_protocol_write_enable(); - { - /* Proram data into buffer of SPI NAND chip */ - spi_nand_protocol_program_load(write_addr, &_current_cache_page[0], ((ptr_dev_info_t->page_size) + (ptr_dev_info_t->oob_size)), speed_mode); - } + /* Proram data into buffer of SPI NAND chip */ + rtn_status = spi_nand_protocol_program_load(write_addr, &_current_cache_page[0], ((ptr_dev_info_t->page_size) + (ptr_dev_info_t->oob_size)), speed_mode); + } + + /* the chip's cache does not hold the page: nothing to program */ + if( rtn_status != SPI_NAND_FLASH_RTN_NO_ERROR ) { + _SPI_NAND_PRINTF("\nPage program 0x%x: the USB transfer failed\n", page_number); + spi_nand_protocol_write_disable(); + SPI_NAND_Flash_Clear_Read_Cache_Data(); + return rtn_status; } /* Execute program data into SPI NAND chip */ spi_nand_protocol_program_execute ( page_number ); /* Checking status for program complete */ - if( spi_nand_wait_ready( &status, "Page program", page_number ) != SPI_NAND_FLASH_RTN_NO_ERROR ) { + rtn_status = spi_nand_wait_ready( &status, "Page program", page_number ); + if( rtn_status != SPI_NAND_FLASH_RTN_NO_ERROR ) { spi_nand_protocol_write_disable(); - return SPI_NAND_FLASH_RTN_TIMEOUT; + /* the buffers hold what was to be written, not what the chip has */ + SPI_NAND_Flash_Clear_Read_Cache_Data(); + return rtn_status; } /*. Disable write_flash */ @@ -4508,7 +4548,7 @@ static SPI_NAND_FLASH_RTN_T spi_nand_read_internal ( u32 addr, u32 len, u8 *ptr_ rtn_status = SPI_NAND_FLASH_RTN_DETECTED_BAD_BLOCK; else rtn_status = spi_nand_read_page(page_number, speed_mode); - if( rtn_status == SPI_NAND_FLASH_RTN_TIMEOUT ) { + if( spi_nand_stopped(rtn_status) ) { *status = rtn_status; _SPI_NAND_SEMAPHORE_UNLOCK(); return (rtn_status); @@ -5266,7 +5306,11 @@ SPI_NAND_FLASH_RTN_T SPI_NAND_Flash_Init(u32 rom_base) } else { _SPI_NAND_PRINTF("Disable Flash ECC.\n"); } - SPI_NAND_Flash_Enable_OnDie_ECC(); + if( SPI_NAND_Flash_Enable_OnDie_ECC() != SPI_NAND_FLASH_RTN_NO_ERROR ) + { + _SPI_NAND_PRINTF("SPI NAND Flash: the USB transfer failed while setting ECC\n"); + return SPI_NAND_FLASH_RTN_IO_ERROR; + } _SPI_NAND_PRINTF("Detected SPI NAND Flash: %s, Flash Size: %d MB\n", _current_flash_info_t.ptr_name, ECC_fcheck ? _current_flash_info_t.device_size >> 20 : (_current_flash_info_t.device_size - ecc_size) >> 20); rtn_status = SPI_NAND_FLASH_RTN_NO_ERROR; @@ -5513,10 +5557,33 @@ void SPI_NAND_Flash_Clear_Read_Cache_Data( void ) _current_page_num = 0xFFFFFFFF; } +/* Set or clear the on-die ECC bit of the feature register at addr. A failed USB + transfer is the result; the read after the write also brings a held one that failed. */ +static SPI_NAND_FLASH_RTN_T spi_nand_set_ondie_ecc( u8 addr ) +{ + u8 feature; + + if( spi_nand_protocol_get_feature(addr, &feature) != SPI_NAND_FLASH_RTN_NO_ERROR ) + return SPI_NAND_FLASH_RTN_IO_ERROR; + _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1, "before setting : SPI_NAND_Flash_Enable_OnDie_ECC, reg 0x%x = 0x%x\n", addr, feature); + if (ECC_fcheck) + feature |= 0x10; + else + feature &= ~(1 << 4); + if( spi_nand_protocol_set_feature(addr, feature) != SPI_NAND_FLASH_RTN_NO_ERROR ) + return SPI_NAND_FLASH_RTN_IO_ERROR; + + /* Value check*/ + if( spi_nand_protocol_get_feature(addr, &feature) != SPI_NAND_FLASH_RTN_NO_ERROR ) + return SPI_NAND_FLASH_RTN_IO_ERROR; + _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1, "after setting : SPI_NAND_Flash_Enable_OnDie_ECC, reg 0x%x = 0x%x\n", addr, feature); + return SPI_NAND_FLASH_RTN_NO_ERROR; +} + SPI_NAND_FLASH_RTN_T SPI_NAND_Flash_Enable_OnDie_ECC( void ) { - unsigned char feature; struct SPI_NAND_FLASH_INFO_T *ptr_dev_info_t; + SPI_NAND_FLASH_RTN_T rtn_status = SPI_NAND_FLASH_RTN_NO_ERROR; u8 die_num; int i; @@ -5525,73 +5592,28 @@ SPI_NAND_FLASH_RTN_T SPI_NAND_Flash_Enable_OnDie_ECC( void ) if(((ptr_dev_info_t->feature) & SPI_NAND_FLASH_DIE_SELECT_1_HAVE)) { die_num = (ptr_dev_info_t->device_size / ptr_dev_info_t->page_size) >> 16; - for(i = 0; i < die_num; i++) { + for(i = 0; i < die_num && rtn_status == SPI_NAND_FLASH_RTN_NO_ERROR; i++) { spi_nand_protocol_die_select_1(i); - - spi_nand_protocol_get_status_reg_2(&feature); - _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1, "before setting : SPI_NAND_Flash_Enable_OnDie_ECC, status reg = 0x%x\n", feature); - if (ECC_fcheck) - feature |= 0x10; - else - feature &= ~(1 << 4); - spi_nand_protocol_set_status_reg_2(feature); - - /* Value check*/ - spi_nand_protocol_get_status_reg_2(&feature); - _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1, "after setting : SPI_NAND_Flash_Enable_OnDie_ECC, status reg = 0x%x\n", feature); + rtn_status = spi_nand_set_ondie_ecc(_SPI_NAND_ADDR_FEATURE); } } else if(((ptr_dev_info_t->feature) & SPI_NAND_FLASH_DIE_SELECT_2_HAVE)) { die_num = (ptr_dev_info_t->device_size / ptr_dev_info_t->page_size) >> 17; - for(i = 0; i < die_num; i++) { + for(i = 0; i < die_num && rtn_status == SPI_NAND_FLASH_RTN_NO_ERROR; i++) { spi_nand_protocol_die_select_2(i); - - spi_nand_protocol_get_status_reg_2(&feature); - _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1, "before setting : SPI_NAND_Flash_Enable_OnDie_ECC, status reg = 0x%x\n", feature); - if (ECC_fcheck) - feature |= 0x10; - else - feature &= ~(1 << 4); - spi_nand_protocol_set_status_reg_2(feature); - - /* Value check*/ - spi_nand_protocol_get_status_reg_2(&feature); - _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1, "after setting : SPI_NAND_Flash_Enable_OnDie_ECC, status reg = 0x%x\n", feature); + rtn_status = spi_nand_set_ondie_ecc(_SPI_NAND_ADDR_FEATURE); } } else { if( ((ptr_dev_info_t->mfr_id) == _SPI_NAND_MANUFACTURER_ID_PN) || ((ptr_dev_info_t->mfr_id) == _SPI_NAND_MANUFACTURER_ID_FM) || ((ptr_dev_info_t->mfr_id) == _SPI_NAND_MANUFACTURER_ID_FORESEE) || (((ptr_dev_info_t->mfr_id) == _SPI_NAND_MANUFACTURER_ID_XTX) && ((ptr_dev_info_t->dev_id) == _SPI_NAND_DEVICE_ID_XT26G02B)) ) - { - spi_nand_protocol_get_feature(_SPI_NAND_ADDR_ECC, &feature); - _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1, "before setting : SPI_NAND_Flash_Enable_OnDie_ECC, ecc reg = 0x%x\n", feature); - if (ECC_fcheck) - feature |= 0x10; - else - feature &= ~(1 << 4); - spi_nand_protocol_set_feature(_SPI_NAND_ADDR_ECC, feature); - - /* Value check*/ - spi_nand_protocol_get_feature(_SPI_NAND_ADDR_ECC, &feature); - _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1, "after setting : SPI_NAND_Flash_Enable_OnDie_ECC, ecc reg = 0x%x\n", feature); - } + rtn_status = spi_nand_set_ondie_ecc(_SPI_NAND_ADDR_ECC); else - { - spi_nand_protocol_get_status_reg_2(&feature); - _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1, "before setting : SPI_NAND_Flash_Enable_OnDie_ECC, status reg = 0x%x\n", feature); - - if (ECC_fcheck) - feature |= 0x10; - else - feature &= ~(1 << 4); - spi_nand_protocol_set_status_reg_2(feature); - - /* Value check*/ - spi_nand_protocol_get_status_reg_2(&feature); - _SPI_NAND_DEBUG_PRINTF(SPI_NAND_FLASH_DEBUG_LEVEL_1, "after setting : SPI_NAND_Flash_Enable_OnDie_ECC, status reg = 0x%x\n", feature); - } + rtn_status = spi_nand_set_ondie_ecc(_SPI_NAND_ADDR_FEATURE); } + if( rtn_status != SPI_NAND_FLASH_RTN_NO_ERROR ) + return rtn_status; if (ECC_fcheck) _ondie_ecc_flag = 1; diff --git a/src/spi_nand_flash.h b/src/spi_nand_flash.h index f7827fb..ea2b28d 100644 --- a/src/spi_nand_flash.h +++ b/src/spi_nand_flash.h @@ -49,6 +49,7 @@ typedef enum{ SPI_NAND_FLASH_RTN_ERASE_FAIL, SPI_NAND_FLASH_RTN_PROGRAM_FAIL, SPI_NAND_FLASH_RTN_TIMEOUT, /* the chip stayed busy (OIP) too long */ + SPI_NAND_FLASH_RTN_IO_ERROR, /* a USB transfer failed: nothing is known of the chip */ SPI_NAND_FLASH_RTN_DEF_NO } SPI_NAND_FLASH_RTN_T; diff --git a/tests/nandsim.c b/tests/nandsim.c index 3bd6155..408565b 100644 --- a/tests/nandsim.c +++ b/tests/nandsim.c @@ -36,6 +36,12 @@ static unsigned int nprog; /* program executes (0x10) */ static int col_hi_read = -1, col_hi_load = -1; /* high column byte of the last read from cache / program load */ static int stuck_busy; /* the status register always shows OIP */ static int busy_after = -1; /* stay busy from this program execute on */ +static long loaded = -1; /* the page last read into the chip's cache */ +static long fail_cache = -1; /* the USB transfer fails when this page is read from the cache */ +static int fail_feature = -1; /* the USB transfer of a read of this feature register fails */ +static int fail_after_program; /* status reads fail from the next program execute on */ +static int fail_set_feature; /* CS high fails after a write of a feature register */ +static int fail_load; /* the USB transfer of the page data of a program load fails */ static int in(const long *set, long v) { for (int i = 0; i < MAXBAD; i++) if (set[i] == v) return 1; return 0; } static unsigned long row(void) { return ((cmd[1] << 16) | (cmd[2] << 8) | cmd[3]) % PAGES; } @@ -47,6 +53,8 @@ SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Chip_Select_Low(void) { ncmd = nread = 0; re SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Write_NByte(u8 *d, u32 len, SPI_CONTROLLER_SPEED_T speed) { (void)speed; + if (fail_load && len > 4 && (cmd[0] == 0x02 || cmd[0] == 0x32 || cmd[0] == 0x84 || cmd[0] == 0x34)) + return SPI_CONTROLLER_RTN_WRITE_DATAPFIFO_ERROR; for (u32 i = 0; i < len; i++) { if (ncmd < 3 || (cmd[0] != 0x02 && cmd[0] != 0x32 && cmd[0] != 0x84 && cmd[0] != 0x34)) { if (ncmd < sizeof(cmd)) cmd[ncmd] = d[i]; @@ -66,6 +74,12 @@ SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Write_One_Byte(u8 data) { return SPI_CONTROL SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Read_NByte(u8 *d, u32 len, SPI_CONTROLLER_SPEED_T speed) { (void)speed; + /* a failed transfer brings nothing back: the buffer stays as it was */ + if (fail_cache >= 0 && fail_cache == loaded && + (cmd[0] == 0x03 || cmd[0] == 0x0b || cmd[0] == 0x3b || cmd[0] == 0x6b)) + return SPI_CONTROLLER_RTN_READ_DATAPFIFO_ERROR; + if (fail_feature >= 0 && cmd[0] == 0x0f && cmd[1] == fail_feature) + return SPI_CONTROLLER_RTN_READ_DATAPFIFO_ERROR; for (u32 i = 0; i < len; i++, nread++) { switch (cmd[0]) { case 0x9f: { /* without an address byte a dummy byte comes first, as on Winbond */ @@ -88,6 +102,10 @@ SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Read_NByte(u8 *d, u32 len, SPI_CONTROLLER_SP SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Chip_Select_High(void) { unsigned char *p; + if (fail_set_feature && cmd[0] == 0x1f) { + ncmd = nread = 0; + return SPI_CONTROLLER_RTN_WRITE_DATAPFIFO_ERROR; + } switch (cmd[0]) { case 0x03: case 0x0b: case 0x3b: case 0x6b: col_hi_read = cmd[1]; break; case 0x02: case 0x32: case 0x84: case 0x34: col_hi_load = cmd[1]; break; @@ -96,10 +114,12 @@ SPI_CONTROLLER_RTN_T SPI_CONTROLLER_Chip_Select_High(void) case 0x04: feat[0xc0] &= ~0x02; break; case 0x13: /* page read: ECC result in status bits 5:4 */ memcpy(cache, mem + row() * (PAGE + OOB), sizeof(cache)); + loaded = row(); feat[0xc0] = (feat[0xc0] & ~0x30) | (in(ecc_bad, row()) ? 0x20 : 0); break; case 0x10: /* program execute */ if (busy_after >= 0 && (int)nprog >= busy_after) stuck_busy = 1; + if (fail_after_program) fail_feature = 0xc0; nprog++; feat[0xc0] &= ~0x08; if (in(prog_fail, row())) { feat[0xc0] |= 0x08; break; } @@ -401,6 +421,82 @@ int main(void) stuck_busy = 0; check(snand_read(got, 0, PAGE) == PAGE, " works again when the chip is ready"); + /* a USB transfer that fails fails the operation: what it brought is not the chip's */ + chip(0xef, 0xaa, 0x21); + snand_init(); + Skip_BAD_page = 0; + snand_erase(10L * 128 * 1024, 128 * 1024); + fill(buf, 3, 21); + check(snand_write(buf, 640L * PAGE, 3 * PAGE) == 3 * PAGE, "write 3 pages for the USB failures"); + snand_read(got, 0, PAGE); + fail_cache = 642; + check(snand_read(got, 640L * PAGE, 3 * PAGE) < 0, "read fails when the USB transfer of a page fails"); + fail_cache = -1; + check(snand_read(got, 640L * PAGE, 3 * PAGE) == 3 * PAGE && !memcmp(got, buf, 3 * PAGE), + " the failed page is not kept: the next read brings the data"); + snand_read(got, 0, PAGE); + fail_feature = 0xc0; + check(snand_read(got, 640L * PAGE, PAGE) < 0, "read fails when the USB transfer of the status fails"); + fail_feature = -1; + Skip_BAD_page = 1; + snand_read(got, 0, PAGE); + fail_cache = 641; + check(snand_read(got, 640L * PAGE, 3 * PAGE) < 0, "-k read fails on a USB failure, it is not a BAD page"); + fail_cache = -1; + check(skipped_page(641) == 0, " and the page is not recorded as skipped"); + Skip_BAD_page = 0; + /* a write reads the page first: without its data the rest of the page would be lost */ + fill(buf, 1, 22); + snand_read(got, 0, PAGE); + fail_cache = 660; + memset(page(660), 0xff, PAGE + OOB); + check(snand_write(buf, 660L * PAGE, PAGE) < 0, "write fails when the read before it fails on USB"); + fail_cache = -1; + { + int blank = 1; + for (int i = 0; i < PAGE; i++) if (page(660)[i] != 0xff) blank = 0; + check(blank, " and nothing is programmed"); + } + fail_feature = 0xc0; + check(snand_write(buf, 661L * PAGE, PAGE) < 0, "write fails when the USB transfer of the status fails"); + check(snand_erase(11L * 128 * 1024, 128 * 1024) != 0, "erase fails when the USB transfer of the status fails"); + fail_feature = -1; + + /* a page whose program result did not come back: what the chip has is read, not the buffer */ + fill(buf, 1, 23); + memset(page(662), 0xff, PAGE + OOB); + fail_after_program = 1; + check(snand_write(buf, 662L * PAGE, PAGE) < 0, "write fails when the status after the program fails on USB"); + fail_after_program = 0; + fail_feature = -1; + memset(page(662), 0x5a, PAGE + OOB); + check(snand_read(got, 662L * PAGE, PAGE) == PAGE && got[0] == 0x5a && got[PAGE - 1] == 0x5a, + " the next read brings the chip's data, not the buffer's"); + + /* page data that did not reach the chip is not programmed */ + memset(page(663), 0xff, PAGE + OOB); + fill(buf, 1, 24); + nprog = 0; + fail_load = 1; + check(snand_write(buf, 663L * PAGE, PAGE) < 0, "write fails when the USB transfer of the page data fails"); + fail_load = 0; + check(nprog == 0, " and the chip is not told to program"); + check(!(feat[0xc0] & 0x02), " and the write enable latch is cleared"); + memset(page(663), 0x5a, PAGE + OOB); + check(snand_read(got, 663L * PAGE, PAGE) == PAGE && got[0] == 0x5a, " the next read brings the chip's data"); + + /* the ECC setup of the detection: a chip it could not set is not reported as ready */ + fail_feature = 0xb0; + check(snand_init() <= 0, "detection fails when the USB transfer of the ECC setup fails"); + fail_feature = 0x90; + chip(0xcd, 0x71, 0x71); + check(snand_init() <= 0, " also through the ECC register (F35SQA001G)"); + fail_feature = -1; + check(snand_init() > 0, " works again when the transfers do"); + fail_set_feature = 1; + check(snand_init() <= 0, "detection fails when CS high of the ECC write fails"); + fail_set_feature = 0; + if (!fail) printf("all nandsim checks passed\n"); return fail; }