diff --git a/drivers/disk/flashdisk.c b/drivers/disk/flashdisk.c index 1ac3d15ba62f6..7d41a973d11ee 100644 --- a/drivers/disk/flashdisk.c +++ b/drivers/disk/flashdisk.c @@ -427,6 +427,40 @@ static int disk_flash_access_write(struct disk_info *disk, const uint8_t *buff, return 0; } +static int disk_flash_access_erase(struct disk_info *disk, uint32_t start_sector, + uint32_t sector_count) +{ + struct flashdisk_data *ctx; + off_t fl_start, fl_end; + uint32_t size; + int rc = 0; + + ctx = CONTAINER_OF(disk, struct flashdisk_data, info); + + if (!sectors_in_range(ctx, start_sector, sector_count)) { + return -EINVAL; + } + + fl_start = ctx->offset + start_sector * ctx->sector_size; + size = (sector_count * ctx->sector_size); + fl_end = fl_start + size; + + k_mutex_lock(&ctx->lock, K_FOREVER); + + /* Erase the provided sectors */ + if (flash_erase(ctx->info.dev, fl_start, size) < 0) { + rc = -EIO; + } + /* Invalidate cache if it was pointing in this address range */ + if (ctx->cache_valid && ((fl_start <= ctx->cached_addr) && (ctx->cached_addr < fl_end))) { + ctx->cache_valid = false; + ctx->cache_dirty = false; + } + k_mutex_unlock(&ctx->lock); + + return rc; +} + static int disk_flash_access_ioctl(struct disk_info *disk, uint8_t cmd, void *buff) { int rc; @@ -466,6 +500,7 @@ static const struct disk_operations flash_disk_ops = { .status = disk_flash_access_status, .read = disk_flash_access_read, .write = disk_flash_access_write, + .erase = disk_flash_access_erase, .ioctl = disk_flash_access_ioctl, }; diff --git a/drivers/disk/loopback_disk.c b/drivers/disk/loopback_disk.c index c7f587b0c1955..6ce32defc6302 100644 --- a/drivers/disk/loopback_disk.c +++ b/drivers/disk/loopback_disk.c @@ -94,6 +94,34 @@ static int loopback_disk_access_write(struct disk_info *disk, const uint8_t *dat return 0; } +static int loopback_disk_access_erase(struct disk_info *disk, uint32_t start_sector, + uint32_t num_sector) +{ + const uint8_t erase_bytes[CONFIG_LOOPBACK_DISK_SECTOR_SIZE] = { 0x00 }; + struct loopback_disk_access *ctx = get_ctx(disk); + + if (start_sector + num_sector > ctx->num_sectors) { + LOG_WRN("Tried to erase past end of backing file"); + return -EINVAL; + } + + int ret = fs_seek(&ctx->file, start_sector * LOOPBACK_SECTOR_SIZE, FS_SEEK_SET); + + if (ret != 0) { + LOG_ERR("Failed to seek backing file: %d", ret); + return ret; + } + + for (int i = 0; i < num_sector; i++) { + ret = fs_write(&ctx->file, erase_bytes, LOOPBACK_SECTOR_SIZE); + if (ret < 0) { + LOG_ERR("Failed to erase backing file: %d", ret); + return ret; + } + } + + return 0; +} static int loopback_disk_access_ioctl(struct disk_info *disk, uint8_t cmd, void *buff) { struct loopback_disk_access *ctx = get_ctx(disk); @@ -126,6 +154,7 @@ static const struct disk_operations loopback_disk_operations = { .status = loopback_disk_access_status, .read = loopback_disk_access_read, .write = loopback_disk_access_write, + .erase = loopback_disk_access_erase, .ioctl = loopback_disk_access_ioctl, }; diff --git a/drivers/disk/ramdisk.c b/drivers/disk/ramdisk.c index d4da37ea9d9d4..71cba39029525 100644 --- a/drivers/disk/ramdisk.c +++ b/drivers/disk/ramdisk.c @@ -77,6 +77,24 @@ static int disk_ram_access_write(struct disk_info *disk, const uint8_t *buff, return 0; } +static int disk_ram_access_erase(struct disk_info *disk, uint32_t sector, + uint32_t count) +{ + const struct device *dev = disk->dev; + const struct ram_disk_config *config = dev->config; + uint32_t last_sector = sector + count; + + if (last_sector < sector || last_sector > config->sector_count) { + LOG_ERR("Sector %" PRIu32 " is outside the range %zu", + last_sector, config->sector_count); + return -EINVAL; + } + + memset(lba_to_address(dev, sector), 0, count * config->sector_size); + + return 0; +} + static int disk_ram_access_ioctl(struct disk_info *disk, uint8_t cmd, void *buff) { const struct ram_disk_config *config = disk->dev->config; @@ -122,6 +140,7 @@ static const struct disk_operations ram_disk_ops = { .status = disk_ram_access_status, .read = disk_ram_access_read, .write = disk_ram_access_write, + .erase = disk_ram_access_erase, .ioctl = disk_ram_access_ioctl, }; diff --git a/drivers/disk/sdmmc_stm32.c b/drivers/disk/sdmmc_stm32.c index ff55df60696df..3166a35fb011b 100644 --- a/drivers/disk/sdmmc_stm32.c +++ b/drivers/disk/sdmmc_stm32.c @@ -553,6 +553,29 @@ static int stm32_sdmmc_access_write(struct disk_info *disk, return err; } +static int stm32_sdmmc_access_erase(struct disk_info *disk, uint32_t sector, uint32_t count) +{ + const struct device *dev = disk->dev; + struct stm32_sdmmc_priv *priv = dev->data; + int err; + + k_sem_take(&priv->thread_lock, K_FOREVER); + + err = HAL_SD_Erase(&priv->hsd, sector, sector + count); + if (err != HAL_OK) { + LOG_ERR("sd erase block failed %d", err); + err = -EIO; + goto end; + } + + while (!stm32_sdmmc_is_card_in_transfer(&priv->hsd)) { + } + +end: + k_sem_give(&priv->thread_lock); + return err; +} + static int stm32_sdmmc_get_card_info(HandleTypeDef *hsd, CardInfoTypeDef *info) { #ifdef CONFIG_SDMMC_STM32_EMMC @@ -606,6 +629,7 @@ static const struct disk_operations stm32_sdmmc_ops = { .status = stm32_sdmmc_access_status, .read = stm32_sdmmc_access_read, .write = stm32_sdmmc_access_write, + .erase = stm32_sdmmc_access_erase, .ioctl = stm32_sdmmc_access_ioctl, }; diff --git a/drivers/disk/sdmmc_subsys.c b/drivers/disk/sdmmc_subsys.c index 6fc8d7fd6e3fa..76c2eaf5beb47 100644 --- a/drivers/disk/sdmmc_subsys.c +++ b/drivers/disk/sdmmc_subsys.c @@ -85,6 +85,14 @@ static int disk_sdmmc_access_write(struct disk_info *disk, const uint8_t *buf, return sdmmc_write_blocks(&data->card, buf, sector, count); } +static int disk_sdmmc_access_erase(struct disk_info *disk, uint32_t sector, uint32_t count) +{ + const struct device *dev = disk->dev; + struct sdmmc_data *data = dev->data; + + return sdmmc_erase_blocks(&data->card, sector, count); +} + static int disk_sdmmc_access_ioctl(struct disk_info *disk, uint8_t cmd, void *buf) { const struct device *dev = disk->dev; @@ -109,6 +117,7 @@ static const struct disk_operations sdmmc_disk_ops = { .status = disk_sdmmc_access_status, .read = disk_sdmmc_access_read, .write = disk_sdmmc_access_write, + .erase = disk_sdmmc_access_erase, .ioctl = disk_sdmmc_access_ioctl, }; diff --git a/include/zephyr/drivers/disk.h b/include/zephyr/drivers/disk.h index c248ccd93db3c..aa64c7978019c 100644 --- a/include/zephyr/drivers/disk.h +++ b/include/zephyr/drivers/disk.h @@ -109,6 +109,7 @@ struct disk_operations { uint32_t start_sector, uint32_t num_sector); int (*write)(struct disk_info *disk, const uint8_t *data_buf, uint32_t start_sector, uint32_t num_sector); + int (*erase)(struct disk_info *disk, uint32_t start_sector, uint32_t num_sector); int (*ioctl)(struct disk_info *disk, uint8_t cmd, void *buff); }; diff --git a/include/zephyr/sd/sdmmc.h b/include/zephyr/sd/sdmmc.h index acb4e9538d159..4a67566ddea25 100644 --- a/include/zephyr/sd/sdmmc.h +++ b/include/zephyr/sd/sdmmc.h @@ -20,6 +20,20 @@ extern "C" { #endif +/** + * @brief Erase blocks from SD card + * + * @param card SD card to write from + * @param start_block first block to erase + * @param num_blocks number of blocks to erase + * @retval 0 erase succeeded + * @retval -EBUSY: card is busy with another request + * @retval -EINVAL: requested erase outside of card bounds + * @retval -ETIMEDOUT: card write timed out + * @retval -EIO: I/O error + */ +int sdmmc_erase_blocks(struct sd_card *card, uint32_t start_block, uint32_t num_blocks); + /** * @brief Write blocks to SD card from buffer * diff --git a/include/zephyr/storage/disk_access.h b/include/zephyr/storage/disk_access.h index a5ce72dd5bfb3..aeac662658cbb 100644 --- a/include/zephyr/storage/disk_access.h +++ b/include/zephyr/storage/disk_access.h @@ -100,6 +100,26 @@ int disk_access_read(const char *pdrv, uint8_t *data_buf, int disk_access_write(const char *pdrv, const uint8_t *data_buf, uint32_t start_sector, uint32_t num_sector); +enum disk_access_erase_type { + /** Erase the physical bytes on the disk to their natural erase value (0x00 or 0xFF) */ + DISK_ACCESS_ERASE_PHYSICAL = 0, +}; + +/** + * @brief erase data from disk + * + * The result of this operation depends on the type of erase, as specified by @a erase_type. + * + * @param[in] pdrv Disk name + * @param[in] start_sector Start disk sector to erase + * @param[in] num_sector Number of disk sectors to erase + * @param[in] erase_type Type of erase to perform + * + * @return 0 on success, negative errno code on fail + */ +int disk_access_erase(const char *pdrv, uint32_t start_sector, uint32_t num_sector, + enum disk_access_erase_type erase_type); + /** * @brief Get/Configure disk parameters * diff --git a/subsys/disk/disk_access.c b/subsys/disk/disk_access.c index 313c937c15d31..b9512a788abc3 100644 --- a/subsys/disk/disk_access.c +++ b/subsys/disk/disk_access.c @@ -118,6 +118,36 @@ int disk_access_write(const char *pdrv, const uint8_t *data_buf, return rc; } +int disk_access_erase(const char *pdrv, uint32_t start_sector, uint32_t num_sector, + enum disk_access_erase_type erase_type) +{ + struct disk_info *disk = disk_access_get_di(pdrv); + uint32_t erase_sector_size; + int rc = -EINVAL; + + /* Only support physical erase for now. + * This parameter is not passed through to the underlying disk to leave the design + * space open for future erase types (Other erase types may be dedicated functions). + */ + if (erase_type != DISK_ACCESS_ERASE_PHYSICAL) { + return -EINVAL; + } + + /* Validate sector sizes, if underlying driver exposes a way to query it */ + if (disk_access_ioctl(pdrv, DISK_IOCTL_GET_ERASE_BLOCK_SZ, &erase_sector_size) == 0) { + /* Alignment check on both start and range of erase request */ + if ((start_sector % erase_sector_size) || (num_sector % erase_sector_size)) { + return -EINVAL; + } + } + + if ((disk != NULL) && (disk->ops != NULL) && (disk->ops->erase != NULL)) { + rc = disk->ops->erase(disk, start_sector, num_sector); + } + + return rc; +} + int disk_access_ioctl(const char *pdrv, uint8_t cmd, void *buf) { struct disk_info *disk = disk_access_get_di(pdrv); diff --git a/subsys/sd/sd_ops.c b/subsys/sd/sd_ops.c index da5e0ff74f969..66cfd79f5afee 100644 --- a/subsys/sd/sd_ops.c +++ b/subsys/sd/sd_ops.c @@ -770,6 +770,85 @@ int card_write_blocks(struct sd_card *card, const uint8_t *wbuf, uint32_t start_ return 0; } +static int card_erase(struct sd_card *card, uint32_t start_block, uint32_t num_blocks) +{ + int ret; + struct sdhc_command cmd; + + LOG_DBG("ERASE: Sector = %u, Count = %u", start_block, num_blocks); + cmd.retries = CONFIG_SD_DATA_RETRIES; + cmd.timeout_ms = CONFIG_SD_CMD_TIMEOUT; + + cmd.opcode = SD_ERASE_BLOCK_START; + cmd.response_type = (SD_RSP_TYPE_R1 | SD_SPI_RSP_TYPE_R1); + cmd.arg = start_block; + if (!(card->flags & SD_HIGH_CAPACITY_FLAG)) { + /* Standard capacity cards use byte unit address */ + cmd.arg *= card->block_size; + } + ret = sdhc_request(card->sdhc, &cmd, NULL); + if (ret) { + LOG_DBG("SD_ERASE_BLOCK_START failed (%d)", ret); + return ret; + } + + cmd.opcode = SD_ERASE_BLOCK_END; + cmd.response_type = (SD_RSP_TYPE_R1 | SD_SPI_RSP_TYPE_R1); + cmd.arg = start_block + num_blocks - 1; + if (!(card->flags & SD_HIGH_CAPACITY_FLAG)) { + /* Standard capacity cards use byte unit address */ + cmd.arg *= card->block_size; + } + ret = sdhc_request(card->sdhc, &cmd, NULL); + if (ret) { + LOG_DBG("SD_ERASE_BLOCK_END failed (%d)", ret); + return ret; + } + + cmd.opcode = SD_ERASE_BLOCK_OPERATION; + cmd.response_type = (SD_RSP_TYPE_R1b | SD_SPI_RSP_TYPE_R1b); + cmd.arg = 0x00000000; + ret = sdhc_request(card->sdhc, &cmd, NULL); + if (ret) { + LOG_DBG("SD_ERASE_BLOCK_OPERATION failed (%d)", ret); + return ret; + } + + /* Verify card is back in transfer state after write */ + ret = sdmmc_wait_ready(card); + if (ret) { + LOG_ERR("Card did not return to ready state"); + return -ETIMEDOUT; + } + return 0; +} + +/* Erase blocks from SD card memory card */ +int card_erase_blocks(struct sd_card *card, uint32_t start_block, uint32_t num_blocks) +{ + int ret; + + /* Overflow aware ((start_block + num_blocks) > card->block_count) */ + if (num_blocks > card->block_count || (card->block_count - num_blocks) < start_block) { + return -EINVAL; + } + if (card->type == CARD_SDIO) { + LOG_WRN("SDIO does not support MMC commands"); + return -ENOTSUP; + } + ret = k_mutex_lock(&card->lock, K_MSEC(CONFIG_SD_DATA_TIMEOUT)); + if (ret) { + LOG_WRN("Could not get SD card mutex"); + return -EBUSY; + } + ret = card_erase(card, start_block, num_blocks); + k_mutex_unlock(&card->lock); + if (ret) { + LOG_ERR("Erase failed"); + } + return ret; +} + /* IO Control handler for SD MMC */ int card_ioctl(struct sd_card *card, uint8_t cmd, void *buf) { diff --git a/subsys/sd/sd_ops.h b/subsys/sd/sd_ops.h index c12a020a018a5..f9378016276f7 100644 --- a/subsys/sd/sd_ops.h +++ b/subsys/sd/sd_ops.h @@ -53,6 +53,9 @@ int card_read_blocks(struct sd_card *card, uint8_t *rbuf, int card_write_blocks(struct sd_card *card, const uint8_t *wbuf, uint32_t start_block, uint32_t num_blocks); +int card_erase_blocks(struct sd_card *card, uint32_t start_block, + uint32_t num_blocks); + int card_app_command(struct sd_card *card, int relative_card_address); int sdmmc_read_status(struct sd_card *card); diff --git a/subsys/sd/sdmmc.c b/subsys/sd/sdmmc.c index ed7acaf439bbc..1c80df5f92946 100644 --- a/subsys/sd/sdmmc.c +++ b/subsys/sd/sdmmc.c @@ -793,3 +793,9 @@ int sdmmc_write_blocks(struct sd_card *card, const uint8_t *wbuf, uint32_t start { return card_write_blocks(card, wbuf, start_block, num_blocks); } + +int sdmmc_erase_blocks(struct sd_card *card, uint32_t start_block, + uint32_t num_blocks) +{ + return card_erase_blocks(card, start_block, num_blocks); +} diff --git a/tests/drivers/disk/disk_access/README.txt b/tests/drivers/disk/disk_access/README.txt index 834d7c9f7d82f..dad89c572a853 100644 --- a/tests/drivers/disk/disk_access/README.txt +++ b/tests/drivers/disk/disk_access/README.txt @@ -25,3 +25,10 @@ disk devices as well. The test has the following phases: of various length to various sectors (once again, the driver must reject writes that would be outside the bounds of the disk), then performs multiple writes to the same location. + +* Erase test: Verifies that the driver can consistently erase sectors. This test + follows the same flow as the write test, but at each step erases the data + written to the disk and reads it back to ensure all data is 0x00 or 0xFF. The + test first performs writes of various length to various sectors (once again, + the driver must reject erases that would be outside the bounds of the disk), + then performs multiple erases to the same location. diff --git a/tests/drivers/disk/disk_access/boards/native_sim.overlay b/tests/drivers/disk/disk_access/boards/native_sim.overlay index f8e71a2d4b844..565dbb84edfd0 100644 --- a/tests/drivers/disk/disk_access/boards/native_sim.overlay +++ b/tests/drivers/disk/disk_access/boards/native_sim.overlay @@ -10,6 +10,8 @@ &flash0 { reg = <0x00000000 DT_SIZE_K(1024)>; + erase-block-size = <512>; + partitions { compatible = "fixed-partitions"; #address-cells = <1>; diff --git a/tests/drivers/disk/disk_access/src/main.c b/tests/drivers/disk/disk_access/src/main.c index 769d4047f18d1..020bbadb6215d 100644 --- a/tests/drivers/disk/disk_access/src/main.c +++ b/tests/drivers/disk/disk_access/src/main.c @@ -47,10 +47,11 @@ #define SECTOR_SIZE 512 /* Sector counts to read */ -#define SECTOR_COUNT1 8 -#define SECTOR_COUNT2 1 -#define SECTOR_COUNT3 29 -#define SECTOR_COUNT4 31 +#define SECTOR_COUNT1 8 +#define SECTOR_COUNT2 1 +#define SECTOR_COUNT3 29 +#define SECTOR_COUNT4 31 +#define SECTOR_COUNT_MAX 32 #define OVERFLOW_CANARY 0xDE @@ -59,10 +60,10 @@ static uint32_t disk_sector_count; static uint32_t disk_sector_size; /* + 4 to make sure the second buffer is dword-aligned for NVME */ -static uint8_t scratch_buf[2][SECTOR_COUNT4 * SECTOR_SIZE + 4]; +static uint8_t scratch_buf[2][SECTOR_COUNT_MAX * SECTOR_SIZE + 4]; #ifdef CONFIG_DISK_DRIVER_LOOPBACK -#define BACKING_PATH "/"DISK_NAME_PHYS":" +#define BACKING_PATH "/" DISK_NAME_PHYS ":" static struct loopback_disk_access lo_access; static FATFS fat_fs; @@ -126,7 +127,7 @@ static void test_setup(void) * just verify our assumed maximum size */ zassert_true(cmd_buf <= SECTOR_SIZE, - "Test will fail, SECTOR_SIZE definition must be increased"); + "Test will fail, SECTOR_SIZE definition must be increased"); } /* Reads sectors, verifying overflow does not occur */ @@ -139,7 +140,7 @@ static int read_sector(uint8_t *buf, uint32_t start, uint32_t num_sectors) rc = disk_access_read(disk_pdrv, buf, start, num_sectors); /* Check canary */ zassert_equal(buf[num_sectors * disk_sector_size], OVERFLOW_CANARY, - "Read overflowed requested length"); + "Read overflowed requested length"); return rc; /* Let calling function check return code */ } @@ -173,8 +174,7 @@ static void test_sector_read(uint8_t *buf, uint32_t num_sectors) /* Write sector of disk, and check the data to ensure it is valid * WARNING: this test is destructive- it will overwrite data on the disk! */ -static int write_sector_checked(uint8_t *wbuf, uint8_t *rbuf, - uint32_t start, uint32_t num_sectors) +static int write_sector_checked(uint8_t *wbuf, uint8_t *rbuf, uint32_t start, uint32_t num_sectors) { int rc, i; @@ -195,10 +195,34 @@ static int write_sector_checked(uint8_t *wbuf, uint8_t *rbuf, } /* Check the read data versus the written data */ zassert_mem_equal(wbuf, rbuf, num_sectors * disk_sector_size, - "Read data did not match data written to disk"); + "Read data did not match data written to disk"); return rc; } +static int erase_sector_checked(uint8_t *rbuf, uint32_t start, uint32_t num_sectors) +{ + int rc, i; + + /* Erase the specified sectors */ + rc = disk_access_erase(disk_pdrv, start, num_sectors, DISK_ACCESS_ERASE_PHYSICAL); + if (rc) { + return rc; /* Let calling function handle disk error */ + } + + /* Read the erased sectors */ + rc = read_sector(rbuf, start, num_sectors); + if (rc) { + return rc; + } + + /* All data should be equal 0x00 or 0xFF */ + for (i = 0; i < num_sectors * disk_sector_size; i++) { + zassert_true((rbuf[i] == 0x00) || (rbuf[i] == 0xFF), + "Data not erased from disk sector %u", start + i); + } + return 0; +} + /* Tests writing to a variety of sectors * WARNING: this test is destructive- it will overwrite data on the disk! */ @@ -228,6 +252,49 @@ static void test_sector_write(uint8_t *wbuf, uint8_t *rbuf, uint32_t num_sectors } } +/* Tests erasing a variety of sectors + * WARNING: this test is destructive- it will overwrite data on the disk! + */ +static void test_sector_erase(uint8_t *wbuf, uint8_t *rbuf, uint32_t num_sectors) +{ + int rc, sector; + + TC_PRINT("Testing erase of %u sectors\n", num_sectors); + /* Write and erase disk sector zero */ + rc = write_sector_checked(wbuf, rbuf, 0, num_sectors); + zassert_equal(rc, 0, "Failed to write to sector zero"); + rc = erase_sector_checked(rbuf, 0, num_sectors); + zassert_equal(rc, 0, "Failed to erase sector zero"); + + /* Write and erase sectors in the "middle" of the disk */ + if (disk_sector_count / 2 > num_sectors) { + sector = disk_sector_count / 2 - num_sectors; + } else { + sector = 0; + } + rc = write_sector_checked(wbuf, rbuf, sector, num_sectors); + zassert_equal(rc, 0, "Failed to write to mid disk sector"); + rc = erase_sector_checked(rbuf, sector, num_sectors); + zassert_equal(rc, 0, "Failed to erase mid disk sector"); + + /* Write and erase the last sector */ + rc = write_sector_checked(wbuf, rbuf, disk_sector_count - num_sectors, num_sectors); + zassert_equal(rc, 0, "Failed to write to last sector"); + rc = erase_sector_checked(rbuf, disk_sector_count - num_sectors, num_sectors); + zassert_equal(rc, 0, "Failed to erase last sector"); + + /* Try and erase past the last sector */ + rc = erase_sector_checked(rbuf, disk_sector_count - num_sectors + 1, num_sectors); + zassert_equal(rc, -EINVAL, + "Unexpected error code when attempting to erase past end of disk"); + rc = erase_sector_checked(rbuf, disk_sector_count + 1, num_sectors); + zassert_equal(rc, -EINVAL, + "Unexpected error code when attempting to erase past end of disk"); + rc = erase_sector_checked(rbuf, UINT32_MAX, num_sectors); + zassert_equal(rc, -EINVAL, + "Unexpected error code when attempting to erase past end of disk"); +} + /* Test multiple reads in series, and reading from a variety of blocks */ ZTEST(disk_driver, test_read) { @@ -248,9 +315,8 @@ ZTEST(disk_driver, test_read) memset(scratch_buf[1], 0xff, SECTOR_COUNT1 * disk_sector_size); rc = read_sector(scratch_buf[1], 0, SECTOR_COUNT1); zassert_equal(rc, 0, "Failed to read from disk at same sector location"); - zassert_mem_equal(scratch_buf[1], scratch_buf[0], - SECTOR_COUNT1 * disk_sector_size, - "Multiple reads mismatch"); + zassert_mem_equal(scratch_buf[1], scratch_buf[0], SECTOR_COUNT1 * disk_sector_size, + "Multiple reads mismatch"); } } @@ -275,6 +341,34 @@ ZTEST(disk_driver, test_write) } } +/* Test multiple erases in series, and erasing from a variety of blocks */ +ZTEST(disk_driver, test_erase) +{ + int rc, i; + + /* Skip the test if erasing not supported by the driver */ + if (disk_access_erase(disk_pdrv, 0, 1, DISK_ACCESS_ERASE_PHYSICAL) == -EINVAL) { + ztest_test_skip(); + return; + } + + /* Test erasing with a bad erase type */ + rc = disk_access_erase(disk_pdrv, 0, 1, DISK_ACCESS_ERASE_PHYSICAL + 1); + zassert_equal(-EINVAL, rc); + + /* Verify a range of erase sizes work */ + test_sector_erase(scratch_buf[0], scratch_buf[1], 8); + test_sector_erase(scratch_buf[0], scratch_buf[1], 16); + test_sector_erase(scratch_buf[0], scratch_buf[1], 24); + test_sector_erase(scratch_buf[0], scratch_buf[1], 32); + + /* Verify that multiple erases to the same location work */ + for (i = 0; i < 10; i++) { + rc = erase_sector_checked(scratch_buf[1], 0, 16); + zassert_equal(0, rc, "Failed to erase sector zero"); + } +} + static void *disk_driver_setup(void) { #ifdef CONFIG_DISK_DRIVER_LOOPBACK