diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 5121faf9738e..d893c916df0b 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2705,6 +2705,71 @@ static void ata_dev_config_cdl(struct ata_device *dev) ata_dev_cleanup_cdl_resources(dev); } +static void ata_dev_config_depop(struct ata_device *dev) +{ + unsigned int err_mask; + u64 val; + + /* Ignore old drives. */ + if (ata_id_major_version(dev->id) < 11) + goto not_supported; + + /* NCQ Autosense is required. */ + if (!ata_identify_page_supported(dev, ATA_LOG_SUPPORTED_CAPABILITIES) || + !ata_id_has_ncq_autosense(dev->id)) + goto not_supported; + + err_mask = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE, + ATA_LOG_SUPPORTED_CAPABILITIES, + dev->sector_buf, 1); + if (err_mask) + goto not_supported; + + /* Check depopulation capabilities bits. */ + val = get_unaligned_le64(&dev->sector_buf[152]); + if (!(val & BIT_ULL(63))) + goto not_supported; + + /* + * Support for at least the GET PHYSICAL ELEMENT STATUS and + * REMOVE ELEMENT AND TRUNCATE commands is mandated. + */ + if (!(val & BIT_ULL(0)) || !(val & BIT_ULL(1))) + goto not_supported; + + dev->flags |= ATA_DFLAG_DEPOP; + + /* Check if RESTORE ELEMENTS AND REBUILD is supported. */ + if (val & BIT_ULL(2)) + dev->flags |= ATA_DFLAG_DEPOP_RESTORE; + + /* + * For ZAC devices, check if REMOVE ELEMENT AND MODIFY ZONES is + * supported. + */ + if (dev->class != ATA_DEV_ZAC) + return; + + err_mask = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE, + ATA_LOG_ZONED_INFORMATION, + dev->sector_buf, 1); + if (err_mask) + return; + + val = get_unaligned_le64(&dev->sector_buf[8]); + if (!(val & BIT_ULL(63))) + return; + + if (val & BIT_ULL(1)) + dev->flags |= ATA_DFLAG_DEPOP_MODIFY; + + return; + +not_supported: + dev->flags &= ~(ATA_DFLAG_DEPOP | ATA_DFLAG_DEPOP_RESTORE | + ATA_DFLAG_DEPOP_MODIFY); +} + static int ata_dev_config_lba(struct ata_device *dev) { const u16 *id = dev->id; @@ -2942,7 +3007,7 @@ static void ata_dev_print_features(struct ata_device *dev) return; ata_dev_info(dev, - "Features:%s%s%s%s%s%s%s%s%s%s\n", + "Features:%s%s%s%s%s%s%s%s%s%s%s%s%s\n", dev->flags & ATA_DFLAG_FUA ? " FUA" : "", dev->flags & ATA_DFLAG_TRUSTED ? " Trust" : "", dev->flags & ATA_DFLAG_DA ? " Dev-Attention" : "", @@ -2952,7 +3017,10 @@ static void ata_dev_print_features(struct ata_device *dev) dev->flags & ATA_DFLAG_NCQ_SEND_RECV ? " NCQ-sndrcv" : "", dev->flags & ATA_DFLAG_NCQ_PRIO ? " NCQ-prio" : "", dev->flags & ATA_DFLAG_CDL ? " CDL" : "", - dev->cpr_log ? " CPR" : ""); + dev->cpr_log ? " CPR" : "", + dev->flags & ATA_DFLAG_DEPOP ? " Depop" : "", + dev->flags & ATA_DFLAG_DEPOP_RESTORE ? " Depop-Restore" : "", + dev->flags & ATA_DFLAG_DEPOP_MODIFY ? " Depop-Modify" : ""); } /** @@ -3115,6 +3183,7 @@ int ata_dev_configure(struct ata_device *dev) ata_dev_config_trusted(dev); ata_dev_config_cpr(dev); ata_dev_config_cdl(dev); + ata_dev_config_depop(dev); dev->cdb_len = 32; if (print_info) diff --git a/include/linux/libata.h b/include/linux/libata.h index 736ba8a6a77b..3703ef433bd4 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -139,30 +139,35 @@ enum { ATA_DFLAG_NCQ_SEND_RECV = (1UL << 11), /* device supports NCQ SEND and RECV */ ATA_DFLAG_NCQ_PRIO = (1UL << 12), /* device supports NCQ priority */ ATA_DFLAG_CDL = (1UL << 13), /* supports cmd duration limits */ - ATA_DFLAG_CFG_MASK = (1UL << 14) - 1, + ATA_DFLAG_DEPOP = (1UL << 14), /* supports depopulation capability */ + ATA_DFLAG_DEPOP_RESTORE = (1UL << 15), /* supports depopulation restoration */ + ATA_DFLAG_DEPOP_MODIFY = (1UL << 16), /* supports zoned depopulation */ + ATA_DFLAG_CFG_MASK = (1UL << 17) - 1, - ATA_DFLAG_PIO = (1UL << 14), /* device limited to PIO mode */ - ATA_DFLAG_NCQ_OFF = (1UL << 15), /* device limited to non-NCQ mode */ - ATA_DFLAG_SLEEPING = (1UL << 16), /* device is sleeping */ - ATA_DFLAG_DUBIOUS_XFER = (1UL << 17), /* data transfer not verified */ - ATA_DFLAG_NO_UNLOAD = (1UL << 18), /* device doesn't support unload */ - ATA_DFLAG_UNLOCK_HPA = (1UL << 19), /* unlock HPA */ - ATA_DFLAG_INIT_MASK = (1UL << 20) - 1, + ATA_DFLAG_PIO = (1UL << 17), /* device limited to PIO mode */ + ATA_DFLAG_NCQ_OFF = (1UL << 18), /* device limited to non-NCQ mode */ + ATA_DFLAG_SLEEPING = (1UL << 19), /* device is sleeping */ + ATA_DFLAG_DUBIOUS_XFER = (1UL << 20), /* data transfer not verified */ + ATA_DFLAG_NO_UNLOAD = (1UL << 21), /* device doesn't support unload */ + ATA_DFLAG_UNLOCK_HPA = (1UL << 22), /* unlock HPA */ + ATA_DFLAG_INIT_MASK = (1UL << 23) - 1, - ATA_DFLAG_NCQ_PRIO_ENABLED = (1UL << 20), /* Priority cmds sent to dev */ - ATA_DFLAG_CDL_ENABLED = (1UL << 21), /* cmd duration limits is enabled */ - ATA_DFLAG_RESUMING = (1UL << 22), /* Device is resuming */ - ATA_DFLAG_DETACH = (1UL << 24), - ATA_DFLAG_DETACHED = (1UL << 25), - ATA_DFLAG_DA = (1UL << 26), /* device supports Device Attention */ - ATA_DFLAG_DEVSLP = (1UL << 27), /* device supports Device Sleep */ - ATA_DFLAG_ACPI_DISABLED = (1UL << 28), /* ACPI for the device is disabled */ - ATA_DFLAG_D_SENSE = (1UL << 29), /* Descriptor sense requested */ + ATA_DFLAG_NCQ_PRIO_ENABLED = (1UL << 23), /* Priority cmds sent to dev */ + ATA_DFLAG_CDL_ENABLED = (1UL << 24), /* cmd duration limits is enabled */ + ATA_DFLAG_RESUMING = (1UL << 25), /* Device is resuming */ + ATA_DFLAG_DETACH = (1UL << 26), + ATA_DFLAG_DETACHED = (1UL << 27), + ATA_DFLAG_DA = (1UL << 28), /* device supports Device Attention */ + ATA_DFLAG_DEVSLP = (1UL << 29), /* device supports Device Sleep */ + ATA_DFLAG_ACPI_DISABLED = (1UL << 30), /* ACPI for the device is disabled */ + ATA_DFLAG_D_SENSE = (1UL << 31), /* Descriptor sense requested */ ATA_DFLAG_FEATURES_MASK = (ATA_DFLAG_TRUSTED | ATA_DFLAG_DA | \ ATA_DFLAG_DEVSLP | ATA_DFLAG_NCQ_SEND_RECV | \ ATA_DFLAG_NCQ_PRIO | ATA_DFLAG_FUA | \ - ATA_DFLAG_CDL) + ATA_DFLAG_CDL | ATA_DFLAG_DEPOP | \ + ATA_DFLAG_DEPOP_RESTORE | + ATA_DFLAG_DEPOP_MODIFY) }; enum {