drivers: disk: add DISK_IOCTL_CTRL_DEINIT command to supported IOCTLs

Add DISK_IOCTL_CTRL_DEINIT ioctl command to disk subsystem. When
disk_access_ioctl() is called with this command, the disk will be
de-initialized. After this IOCTL completes, the disk can safely be
reinitialized.

Fixes #60628

Signed-off-by: Daniel DeGrasse <daniel.degrasse@nxp.com>
This commit is contained in:
Daniel DeGrasse 2024-05-14 14:33:49 -05:00 committed by Fabio Baltieri
parent fb2d5c338b
commit d18cbb60b2
10 changed files with 60 additions and 4 deletions

View file

@ -435,6 +435,7 @@ static int disk_flash_access_ioctl(struct disk_info *disk, uint8_t cmd, void *bu
ctx = CONTAINER_OF(disk, struct flashdisk_data, info);
switch (cmd) {
case DISK_IOCTL_CTRL_DEINIT:
case DISK_IOCTL_CTRL_SYNC:
k_mutex_lock(&ctx->lock, K_FOREVER);
rc = flashdisk_cache_commit(ctx);

View file

@ -107,6 +107,7 @@ static int loopback_disk_access_ioctl(struct disk_info *disk, uint8_t cmd, void
*(uint32_t *)buff = LOOPBACK_SECTOR_SIZE;
return 0;
}
case DISK_IOCTL_CTRL_DEINIT:
case DISK_IOCTL_CTRL_SYNC:
return fs_sync(&ctx->file);
case DISK_IOCTL_CTRL_INIT:

View file

@ -85,6 +85,13 @@ static int disk_mmc_access_ioctl(struct disk_info *disk, uint8_t cmd, void *buf)
switch (cmd) {
case DISK_IOCTL_CTRL_INIT:
return disk_mmc_access_init(disk);
case DISK_IOCTL_CTRL_DEINIT:
mmc_ioctl(&data->card, DISK_IOCTL_CTRL_SYNC, NULL);
/* sd_init() will toggle power to MMC, so we can just mark
* disk as uninitialized
*/
data->status = SD_UNINIT;
return 0;
default:
return mmc_ioctl(&data->card, cmd, buf);
}

View file

@ -178,6 +178,7 @@ static int nvme_disk_ioctl(struct disk_info *disk, uint8_t cmd, void *buff)
*(uint32_t *)buff = nvme_namespace_get_sector_size(ns);
break;
case DISK_IOCTL_CTRL_DEINIT:
case DISK_IOCTL_CTRL_SYNC:
ret = nvme_disk_flush(ns);
break;

View file

@ -94,6 +94,7 @@ static int disk_ram_access_ioctl(struct disk_info *disk, uint8_t cmd, void *buff
*(uint32_t *)buff = 1U;
break;
case DISK_IOCTL_CTRL_INIT:
case DISK_IOCTL_CTRL_DEINIT:
break;
default:
return -EINVAL;

View file

@ -307,14 +307,18 @@ static int stm32_sdmmc_access_init(struct disk_info *disk)
return 0;
}
#if !defined(CONFIG_SDMMC_STM32_EMMC)
static void stm32_sdmmc_access_deinit(struct stm32_sdmmc_priv *priv)
static int stm32_sdmmc_access_deinit(struct stm32_sdmmc_priv *priv)
{
#if defined(CONFIG_SDMMC_STM32_EMMC)
HAL_MMC_DeInit(&priv->hsd);
#else
HAL_SD_DeInit(&priv->hsd);
stm32_sdmmc_clock_disable(priv);
}
#endif
priv->status = DISK_STATUS_UNINIT;
return 0;
}
static int stm32_sdmmc_access_status(struct disk_info *disk)
{
@ -483,6 +487,8 @@ static int stm32_sdmmc_access_ioctl(struct disk_info *disk, uint8_t cmd,
break;
case DISK_IOCTL_CTRL_INIT:
return stm32_sdmmc_access_init(disk);
case DISK_IOCTL_CTRL_DEINIT:
return stm32_sdmmc_access_deinit(priv);
default:
return -EINVAL;
}

View file

@ -89,8 +89,16 @@ static int disk_sdmmc_access_ioctl(struct disk_info *disk, uint8_t cmd, void *bu
const struct device *dev = disk->dev;
struct sdmmc_data *data = dev->data;
switch (cmd) {
case DISK_IOCTL_CTRL_INIT:
return disk_sdmmc_access_init(disk);
case DISK_IOCTL_CTRL_DEINIT:
sdmmc_ioctl(&data->card, DISK_IOCTL_CTRL_SYNC, NULL);
/* sd_init() will toggle power to SDMMC, so we can just mark
* disk as uninitialized
*/
data->status = SD_UNINIT;
return 0;
default:
return sdmmc_ioctl(&data->card, cmd, buf);
}

View file

@ -55,6 +55,18 @@ extern "C" {
* device
*/
#define DISK_IOCTL_CTRL_INIT 6
/** Deinitialize the disk. This IOCTL can be used to de-initialize the disk,
* enabling it to be removed from the system if the disk is hot-pluggable.
* Disk usage is reference counted, so for a given disk the
* `DISK_IOCTL_CTRL_DEINIT` IOCTL must be issued as many times as the
* `DISK_IOCTL_CTRL_INIT` IOCTL was issued in order to de-initialize it.
*
* This macro optionally accepts a pointer to a boolean as the `buf` parameter,
* which if true indicates the disk should be forcibly stopped, ignoring all
* reference counts. The disk driver must report success if a forced stop is
* requested, but this operation is inherently unsafe.
*/
#define DISK_IOCTL_CTRL_DEINIT 7
/**
* @brief Possible return bitmasks for disk_status()

View file

@ -44,7 +44,8 @@ extern "C" {
* @ref disk_access_ioctl with the IOCTL @ref DISK_IOCTL_CTRL_INIT.
*
* Disk initialization is reference counted, so only the first successful call
* to initialize a uninitialized disk will actually initialize the disk
* to initialize a uninitialized (or previously de-initialized) disk will
* actually initialize the disk
*
* @param[in] pdrv Disk name
*

View file

@ -139,6 +139,24 @@ int disk_access_ioctl(const char *pdrv, uint8_t cmd, void *buf)
LOG_ERR("Disk reference count at max value");
}
break;
case DISK_IOCTL_CTRL_DEINIT:
if ((buf != NULL) && (*((bool *)buf))) {
/* Force deinit disk */
disk->refcnt = 0U;
disk->ops->ioctl(disk, cmd, buf);
rc = 0;
} else if (disk->refcnt == 1U) {
rc = disk->ops->ioctl(disk, cmd, buf);
if (rc == 0) {
disk->refcnt--;
}
} else if (disk->refcnt > 0) {
disk->refcnt--;
rc = 0;
} else {
LOG_WRN("Disk is already deinitialized");
}
break;
default:
rc = disk->ops->ioctl(disk, cmd, buf);
}