From e8fe098170142416f11a0cae201254cd779f7fe9 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Thu, 4 Dec 2025 14:18:04 +0100 Subject: ata: libata-scsi: Remove superfluous local_irq_save() Commit 28a3fc2295a7 ("libata: implement ZBC IN translation") added ata_scsi_report_zones_complete(). Since the beginning, this function has disabled IRQs on the local CPU using local_irq_save(). qc->complete_fn is always called with ap->lock held, and the ap->lock is always taken using spin_lock_irq*(). Thus, this local_irq_save() is superfluous and can be removed. Signed-off-by: Niklas Cassel Reviewed-by: Hannes Reinecke Signed-off-by: Damien Le Moal --- drivers/ata/libata-scsi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 721d3f270c8e..244d10e48472 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3573,13 +3573,13 @@ static void ata_scsi_report_zones_complete(struct ata_queued_cmd *qc) { struct scsi_cmnd *scmd = qc->scsicmd; struct sg_mapping_iter miter; - unsigned long flags; unsigned int bytes = 0; + lockdep_assert_held(qc->ap->lock); + sg_miter_start(&miter, scsi_sglist(scmd), scsi_sg_count(scmd), SG_MITER_TO_SG | SG_MITER_ATOMIC); - local_irq_save(flags); while (sg_miter_next(&miter)) { unsigned int offset = 0; @@ -3627,7 +3627,6 @@ static void ata_scsi_report_zones_complete(struct ata_queued_cmd *qc) } } sg_miter_stop(&miter); - local_irq_restore(flags); ata_scsi_qc_complete(qc); } -- cgit v1.2.3 From 151cabd140322205e27dae5c4bbf261ede0056e3 Mon Sep 17 00:00:00 2001 From: Henry Tseng Date: Mon, 1 Dec 2025 17:46:22 +0800 Subject: ata: libata: avoid long timeouts on hot-unplugged SATA DAS When a SATA DAS enclosure is connected behind a Thunderbolt PCIe switch, hot-unplugging the whole enclosure causes pciehp to tear down the PCI hierarchy before the SCSI layer issues SYNCHRONIZE CACHE and START STOP UNIT for the disks. libata still queues these commands and the AHCI driver tries to access the HBA registers even though the PCI channel is already offline. This results in a series of timeouts and error recovery attempts, e.g.: [ 824.778346] pcieport 0000:00:07.0: pciehp: Slot(14): Link Down [ 891.612720] ata8.00: qc timeout after 5000 msecs (cmd 0xec) [ 902.876501] ata8.00: qc timeout after 10000 msecs (cmd 0xec) [ 934.107998] ata8.00: qc timeout after 30000 msecs (cmd 0xec) [ 936.206431] sd 7:0:0:0: [sda] Synchronize Cache(10) failed: Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK ... [ 1006.298356] ata1.00: qc timeout after 5000 msecs (cmd 0xec) [ 1017.561926] ata1.00: qc timeout after 10000 msecs (cmd 0xec) [ 1048.791790] ata1.00: qc timeout after 30000 msecs (cmd 0xec) [ 1050.890035] sd 0:0:0:0: [sdb] Synchronize Cache(10) failed: Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK With this patch applied, the same hot-unplug looks like: [ 59.965496] pcieport 0000:00:07.0: pciehp: Slot(14): Link Down [ 60.002502] sd 7:0:0:0: [sda] Synchronize Cache(10) failed: Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK ... [ 60.103050] sd 0:0:0:0: [sdb] Synchronize Cache(10) failed: Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK In this test setup with two disks, the hot-unplug sequence shrinks from about 226 seconds (~3.8 minutes) between the Link Down event and the last SYNCHRONIZE CACHE failure to under a second. Without this patch the total delay grows roughly with the number of disks, because each disk gets its own SYNCHRONIZE CACHE and qc timeout series. If the underlying PCI device is already gone, these commands cannot succeed anyway. Avoid issuing them by introducing ata_adapter_is_online(), which checks pci_channel_offline() for PCI-based hosts. It is used from ata_scsi_find_dev() to return NULL, causing the SCSI layer to fail new commands with DID_BAD_TARGET immediately, and from ata_qc_issue() to bail out before touching the HBA registers. Since such failures would otherwise trigger libata error handling, ata_adapter_is_online() is also consulted from ata_scsi_port_error_handler(). When the adapter is offline, libata skips ap->ops->error_handler(ap) and completes error handling using the existing path, rather than running a full EH sequence against a dead adapter. With this change, SYNCHRONIZE CACHE and START STOP UNIT commands issued during hot-unplug fail quickly once the PCI channel is offline, without qc timeout spam or long libata EH delays. Suggested-by: Damien Le Moal Signed-off-by: Henry Tseng Signed-off-by: Damien Le Moal --- drivers/ata/libata-core.c | 24 ++++++++++++++++++++++++ drivers/ata/libata-eh.c | 3 ++- drivers/ata/libata-scsi.c | 3 +++ drivers/ata/libata.h | 1 + 4 files changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 0b24bd169d61..871ef87a02ca 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2358,6 +2358,24 @@ static bool ata_dev_check_adapter(struct ata_device *dev, return false; } +bool ata_adapter_is_online(struct ata_port *ap) +{ + struct device *dev; + + if (!ap || !ap->host) + return false; + + dev = ap->host->dev; + if (!dev) + return false; + + if (dev_is_pci(dev) && + pci_channel_offline(to_pci_dev(dev))) + return false; + + return true; +} + static int ata_dev_config_ncq(struct ata_device *dev, char *desc, size_t desc_sz) { @@ -5073,6 +5091,12 @@ void ata_qc_issue(struct ata_queued_cmd *qc) qc->flags |= ATA_QCFLAG_ACTIVE; ap->qc_active |= 1ULL << qc->tag; + /* Make sure the device is still accessible. */ + if (!ata_adapter_is_online(ap)) { + qc->err_mask |= AC_ERR_HOST_BUS; + goto sys_err; + } + /* * We guarantee to LLDs that they will have at least one * non-zero sg if the command is a data command. diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 2586e77ebf45..f4c9541d1910 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -736,7 +736,8 @@ void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap) spin_unlock_irqrestore(ap->lock, flags); /* invoke EH, skip if unloading or suspended */ - if (!(ap->pflags & (ATA_PFLAG_UNLOADING | ATA_PFLAG_SUSPENDED))) + if (!(ap->pflags & (ATA_PFLAG_UNLOADING | ATA_PFLAG_SUSPENDED)) && + ata_adapter_is_online(ap)) ap->ops->error_handler(ap); else { /* if unloading, commence suicide */ diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 244d10e48472..d388a4ff9ae4 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -2982,6 +2982,9 @@ ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev) { struct ata_device *dev = __ata_scsi_find_dev(ap, scsidev); + if (!ata_adapter_is_online(ap)) + return NULL; + if (unlikely(!dev || !ata_dev_enabled(dev))) return NULL; diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 0e7ecac73680..89dd0ae2b991 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -94,6 +94,7 @@ extern int atapi_check_dma(struct ata_queued_cmd *qc); extern void swap_buf_le16(u16 *buf, unsigned int buf_words); extern bool ata_phys_link_online(struct ata_link *link); extern bool ata_phys_link_offline(struct ata_link *link); +bool ata_adapter_is_online(struct ata_port *ap); extern void ata_dev_init(struct ata_device *dev); extern void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp); extern int sata_link_init_spd(struct ata_link *link); -- cgit v1.2.3 From 59b7bb3d48333889adb1dd2aac3ab0cf26714390 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Tue, 2 Dec 2025 13:21:31 +0100 Subject: ata: libata: Add ATA_QUIRK_MAX_SEC and convert all device quirks Add a new quirk ATA_QUIRK_MAX_SEC, which has a separate table with device specific values. Convert all existing ATA_QUIRK_MAX_SEC_XXX device quirks in __ata_dev_quirks to the new format. Quirks ATA_QUIRK_MAX_SEC_128 and ATA_QUIRK_MAX_SEC_1024 cannot be removed yet, since they are also used by libata.force, which functionally, is a separate user of the quirks. The quirks will be removed once all users have been converted to use the new format. The quirk ATA_QUIRK_MAX_SEC_8191 can be removed since it has no equivalent libata.force parameter. Signed-off-by: Niklas Cassel Reviewed-by: Damien Le Moal Reviewed-by: Martin K. Petersen Signed-off-by: Damien Le Moal --- drivers/ata/libata-core.c | 68 ++++++++++++++++++++++++++++++++++++++++------- include/linux/ata.h | 1 - include/linux/libata.h | 4 +-- 3 files changed, 61 insertions(+), 12 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 871ef87a02ca..b6127fa0b550 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -77,6 +77,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev, static unsigned int ata_dev_set_xfermode(struct ata_device *dev); static void ata_dev_xfermask(struct ata_device *dev); static unsigned int ata_dev_quirks(const struct ata_device *dev); +static u64 ata_dev_get_quirk_value(struct ata_device *dev, unsigned int quirk); static DEFINE_IDA(ata_ida); @@ -3164,9 +3165,10 @@ int ata_dev_configure(struct ata_device *dev) dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_1024, dev->max_sectors); - if (dev->quirks & ATA_QUIRK_MAX_SEC_8191) - dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_8191, - dev->max_sectors); + if (dev->quirks & ATA_QUIRK_MAX_SEC) + dev->max_sectors = min_t(unsigned int, dev->max_sectors, + ata_dev_get_quirk_value(dev, + ATA_QUIRK_MAX_SEC)); if (dev->quirks & ATA_QUIRK_MAX_SEC_LBA48) dev->max_sectors = ATA_MAX_SECTORS_LBA48; @@ -4020,7 +4022,7 @@ static const char * const ata_quirk_names[] = { [__ATA_QUIRK_NO_DMA_LOG] = "nodmalog", [__ATA_QUIRK_NOTRIM] = "notrim", [__ATA_QUIRK_MAX_SEC_1024] = "maxsec1024", - [__ATA_QUIRK_MAX_SEC_8191] = "maxsec8191", + [__ATA_QUIRK_MAX_SEC] = "maxsec", [__ATA_QUIRK_MAX_TRIM_128M] = "maxtrim128m", [__ATA_QUIRK_NO_NCQ_ON_ATI] = "noncqonati", [__ATA_QUIRK_NO_LPM_ON_ATI] = "nolpmonati", @@ -4065,6 +4067,21 @@ static void ata_dev_print_quirks(const struct ata_device *dev, kfree(str); } +struct ata_dev_quirk_value { + const char *model_num; + const char *model_rev; + u64 val; +}; + +static const struct ata_dev_quirk_value __ata_dev_max_sec_quirks[] = { + { "TORiSAN DVD-ROM DRD-N216", NULL, 128 }, + { "ST380013AS", "3.20", 1024 }, + { "LITEON CX1-JB*-HP", NULL, 1024 }, + { "LITEON EP1-*", NULL, 1024 }, + { "DELLBOSS VD", "MV.R00-0", 8191 }, + { }, +}; + struct ata_dev_quirks_entry { const char *model_num; const char *model_rev; @@ -4109,7 +4126,7 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = { { "ASMT109x- Config", NULL, ATA_QUIRK_DISABLE }, /* Weird ATAPI devices */ - { "TORiSAN DVD-ROM DRD-N216", NULL, ATA_QUIRK_MAX_SEC_128 }, + { "TORiSAN DVD-ROM DRD-N216", NULL, ATA_QUIRK_MAX_SEC }, { "QUANTUM DAT DAT72-000", NULL, ATA_QUIRK_ATAPI_MOD16_DMA }, { "Slimtype DVD A DS8A8SH", NULL, ATA_QUIRK_MAX_SEC_LBA48 }, { "Slimtype DVD A DS8A9SH", NULL, ATA_QUIRK_MAX_SEC_LBA48 }, @@ -4118,20 +4135,20 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = { * Causes silent data corruption with higher max sects. * http://lkml.kernel.org/g/x49wpy40ysk.fsf@segfault.boston.devel.redhat.com */ - { "ST380013AS", "3.20", ATA_QUIRK_MAX_SEC_1024 }, + { "ST380013AS", "3.20", ATA_QUIRK_MAX_SEC }, /* * These devices time out with higher max sects. * https://bugzilla.kernel.org/show_bug.cgi?id=121671 */ - { "LITEON CX1-JB*-HP", NULL, ATA_QUIRK_MAX_SEC_1024 }, - { "LITEON EP1-*", NULL, ATA_QUIRK_MAX_SEC_1024 }, + { "LITEON CX1-JB*-HP", NULL, ATA_QUIRK_MAX_SEC }, + { "LITEON EP1-*", NULL, ATA_QUIRK_MAX_SEC }, /* * These devices time out with higher max sects. * https://bugzilla.kernel.org/show_bug.cgi?id=220693 */ - { "DELLBOSS VD", "MV.R00-0", ATA_QUIRK_MAX_SEC_8191 }, + { "DELLBOSS VD", "MV.R00-0", ATA_QUIRK_MAX_SEC }, /* Devices we expect to fail diagnostics */ @@ -4381,6 +4398,39 @@ static unsigned int ata_dev_quirks(const struct ata_device *dev) return 0; } +static u64 ata_dev_get_max_sec_quirk_value(struct ata_device *dev) +{ + unsigned char model_num[ATA_ID_PROD_LEN + 1]; + unsigned char model_rev[ATA_ID_FW_REV_LEN + 1]; + const struct ata_dev_quirk_value *ad = __ata_dev_max_sec_quirks; + u64 val = 0; + + ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); + ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev)); + + while (ad->model_num) { + if (glob_match(ad->model_num, model_num) && + (!ad->model_rev || glob_match(ad->model_rev, model_rev))) { + val = ad->val; + break; + } + ad++; + } + + ata_dev_warn(dev, "%s quirk is using value: %llu\n", + ata_quirk_names[__ATA_QUIRK_MAX_SEC], val); + + return val; +} + +static u64 ata_dev_get_quirk_value(struct ata_device *dev, unsigned int quirk) +{ + if (quirk == ATA_QUIRK_MAX_SEC) + return ata_dev_get_max_sec_quirk_value(dev); + + return 0; +} + static bool ata_dev_nodma(const struct ata_device *dev) { /* diff --git a/include/linux/ata.h b/include/linux/ata.h index 54b416e26995..c9013e472aa3 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -29,7 +29,6 @@ enum { ATA_MAX_SECTORS_128 = 128, ATA_MAX_SECTORS = 256, ATA_MAX_SECTORS_1024 = 1024, - ATA_MAX_SECTORS_8191 = 8191, ATA_MAX_SECTORS_LBA48 = 65535,/* avoid count to be 0000h */ ATA_MAX_SECTORS_TAPE = 65535, ATA_MAX_TRIM_RNUM = 64, /* 512-byte payload / (6-byte LBA + 2-byte range per entry) */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 39534fafa36a..11b6a44572ac 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -75,7 +75,7 @@ enum ata_quirks { __ATA_QUIRK_NO_DMA_LOG, /* Do not use DMA for log read */ __ATA_QUIRK_NOTRIM, /* Do not use TRIM */ __ATA_QUIRK_MAX_SEC_1024, /* Limit max sects to 1024 */ - __ATA_QUIRK_MAX_SEC_8191, /* Limit max sects to 8191 */ + __ATA_QUIRK_MAX_SEC, /* Limit max sectors */ __ATA_QUIRK_MAX_TRIM_128M, /* Limit max trim size to 128M */ __ATA_QUIRK_NO_NCQ_ON_ATI, /* Disable NCQ on ATI chipset */ __ATA_QUIRK_NO_LPM_ON_ATI, /* Disable LPM on ATI chipset */ @@ -116,7 +116,7 @@ enum { ATA_QUIRK_NO_DMA_LOG = (1U << __ATA_QUIRK_NO_DMA_LOG), ATA_QUIRK_NOTRIM = (1U << __ATA_QUIRK_NOTRIM), ATA_QUIRK_MAX_SEC_1024 = (1U << __ATA_QUIRK_MAX_SEC_1024), - ATA_QUIRK_MAX_SEC_8191 = (1U << __ATA_QUIRK_MAX_SEC_8191), + ATA_QUIRK_MAX_SEC = (1U << __ATA_QUIRK_MAX_SEC), ATA_QUIRK_MAX_TRIM_128M = (1U << __ATA_QUIRK_MAX_TRIM_128M), ATA_QUIRK_NO_NCQ_ON_ATI = (1U << __ATA_QUIRK_NO_NCQ_ON_ATI), ATA_QUIRK_NO_LPM_ON_ATI = (1U << __ATA_QUIRK_NO_LPM_ON_ATI), -- cgit v1.2.3 From 873abd72b8b54443ac7783d207be7333289f8287 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Tue, 2 Dec 2025 13:21:32 +0100 Subject: ata: libata: Add ata_force_get_fe_for_dev() helper Add ata_force_get_fe_for_dev() helper to get the struct ata_force_ent for a struct ata_device. Use the helper in ata_force_quirks(). The helper will also be used in follow up commits. No functional change intended. Signed-off-by: Niklas Cassel Reviewed-by: Martin K. Petersen Reviewed-by: Damien Le Moal Signed-off-by: Damien Le Moal --- drivers/ata/libata-core.c | 56 ++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b6127fa0b550..1779cd5a1cbb 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -474,19 +474,10 @@ static void ata_force_xfermask(struct ata_device *dev) } } -/** - * ata_force_quirks - force quirks according to libata.force - * @dev: ATA device of interest - * - * Force quirks according to libata.force and whine about it. - * For consistency with link selection, device number 15 selects - * the first device connected to the host link. - * - * LOCKING: - * EH context. - */ -static void ata_force_quirks(struct ata_device *dev) +static const struct ata_force_ent * +ata_force_get_fe_for_dev(struct ata_device *dev) { + const struct ata_force_ent *fe; int devno = dev->link->pmp + dev->devno; int alt_devno = devno; int i; @@ -496,8 +487,7 @@ static void ata_force_quirks(struct ata_device *dev) alt_devno += 15; for (i = 0; i < ata_force_tbl_size; i++) { - const struct ata_force_ent *fe = &ata_force_tbl[i]; - + fe = &ata_force_tbl[i]; if (fe->port != -1 && fe->port != dev->link->ap->print_id) continue; @@ -505,16 +495,38 @@ static void ata_force_quirks(struct ata_device *dev) fe->device != alt_devno) continue; - if (!(~dev->quirks & fe->param.quirk_on) && - !(dev->quirks & fe->param.quirk_off)) - continue; + return fe; + } - dev->quirks |= fe->param.quirk_on; - dev->quirks &= ~fe->param.quirk_off; + return NULL; +} - ata_dev_notice(dev, "FORCE: modified (%s)\n", - fe->param.name); - } +/** + * ata_force_quirks - force quirks according to libata.force + * @dev: ATA device of interest + * + * Force quirks according to libata.force and whine about it. + * For consistency with link selection, device number 15 selects + * the first device connected to the host link. + * + * LOCKING: + * EH context. + */ +static void ata_force_quirks(struct ata_device *dev) +{ + const struct ata_force_ent *fe = ata_force_get_fe_for_dev(dev); + + if (!fe) + return; + + if (!(~dev->quirks & fe->param.quirk_on) && + !(dev->quirks & fe->param.quirk_off)) + return; + + dev->quirks |= fe->param.quirk_on; + dev->quirks &= ~fe->param.quirk_off; + + ata_dev_notice(dev, "FORCE: modified (%s)\n", fe->param.name); } #else static inline void ata_force_pflags(struct ata_port *ap) { } -- cgit v1.2.3 From dfd975151df9f8ec69e14466f18c4b4af9823f88 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Tue, 2 Dec 2025 13:21:33 +0100 Subject: ata: libata: Change libata.force to use the generic ATA_QUIRK_MAX_SEC quirk Modify the existing libata.force parameters "max_sec_128" and "max_sec_1024" to use the generic ATA_QUIRK_MAX_SEC quirk rather than individual quirks. This also allows us to remove the individual quirks ATA_QUIRK_MAX_SEC_128 and ATA_QUIRK_MAX_SEC_1024. Signed-off-by: Niklas Cassel Reviewed-by: Martin K. Petersen Reviewed-by: Damien Le Moal Signed-off-by: Damien Le Moal --- drivers/ata/libata-core.c | 28 ++++++++++++++++------------ include/linux/ata.h | 2 -- include/linux/libata.h | 4 ---- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 1779cd5a1cbb..cf7b57d048a3 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -84,6 +84,7 @@ static DEFINE_IDA(ata_ida); #ifdef CONFIG_ATA_FORCE struct ata_force_param { const char *name; + u64 value; u8 cbl; u8 spd_limit; unsigned int xfer_mask; @@ -3169,14 +3170,6 @@ int ata_dev_configure(struct ata_device *dev) dev->quirks |= ATA_QUIRK_STUCK_ERR; } - if (dev->quirks & ATA_QUIRK_MAX_SEC_128) - dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128, - dev->max_sectors); - - if (dev->quirks & ATA_QUIRK_MAX_SEC_1024) - dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_1024, - dev->max_sectors); - if (dev->quirks & ATA_QUIRK_MAX_SEC) dev->max_sectors = min_t(unsigned int, dev->max_sectors, ata_dev_get_quirk_value(dev, @@ -4012,7 +4005,6 @@ static const char * const ata_quirk_names[] = { [__ATA_QUIRK_DIAGNOSTIC] = "diagnostic", [__ATA_QUIRK_NODMA] = "nodma", [__ATA_QUIRK_NONCQ] = "noncq", - [__ATA_QUIRK_MAX_SEC_128] = "maxsec128", [__ATA_QUIRK_BROKEN_HPA] = "brokenhpa", [__ATA_QUIRK_DISABLE] = "disable", [__ATA_QUIRK_HPA_SIZE] = "hpasize", @@ -4033,7 +4025,6 @@ static const char * const ata_quirk_names[] = { [__ATA_QUIRK_ZERO_AFTER_TRIM] = "zeroaftertrim", [__ATA_QUIRK_NO_DMA_LOG] = "nodmalog", [__ATA_QUIRK_NOTRIM] = "notrim", - [__ATA_QUIRK_MAX_SEC_1024] = "maxsec1024", [__ATA_QUIRK_MAX_SEC] = "maxsec", [__ATA_QUIRK_MAX_TRIM_128M] = "maxtrim128m", [__ATA_QUIRK_NO_NCQ_ON_ATI] = "noncqonati", @@ -4417,6 +4408,14 @@ static u64 ata_dev_get_max_sec_quirk_value(struct ata_device *dev) const struct ata_dev_quirk_value *ad = __ata_dev_max_sec_quirks; u64 val = 0; +#ifdef CONFIG_ATA_FORCE + const struct ata_force_ent *fe = ata_force_get_fe_for_dev(dev); + if (fe && (fe->param.quirk_on & ATA_QUIRK_MAX_SEC) && fe->param.value) + val = fe->param.value; +#endif + if (val) + goto out; + ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev)); @@ -4429,6 +4428,7 @@ static u64 ata_dev_get_max_sec_quirk_value(struct ata_device *dev) ad++; } +out: ata_dev_warn(dev, "%s quirk is using value: %llu\n", ata_quirk_names[__ATA_QUIRK_MAX_SEC], val); @@ -6482,6 +6482,10 @@ EXPORT_SYMBOL_GPL(ata_platform_remove_one); #define force_quirk_on(name, flag) \ { #name, .quirk_on = (flag) } +#define force_quirk_val(name, flag, val) \ + { #name, .quirk_on = (flag), \ + .value = (val) } + #define force_quirk_onoff(name, flag) \ { "no" #name, .quirk_on = (flag) }, \ { #name, .quirk_off = (flag) } @@ -6556,8 +6560,8 @@ static const struct ata_force_param force_tbl[] __initconst = { force_quirk_onoff(iddevlog, ATA_QUIRK_NO_ID_DEV_LOG), force_quirk_onoff(logdir, ATA_QUIRK_NO_LOG_DIR), - force_quirk_on(max_sec_128, ATA_QUIRK_MAX_SEC_128), - force_quirk_on(max_sec_1024, ATA_QUIRK_MAX_SEC_1024), + force_quirk_val(max_sec_128, ATA_QUIRK_MAX_SEC, 128), + force_quirk_val(max_sec_1024, ATA_QUIRK_MAX_SEC, 1024), force_quirk_on(max_sec_lba48, ATA_QUIRK_MAX_SEC_LBA48), force_quirk_onoff(lpm, ATA_QUIRK_NOLPM), diff --git a/include/linux/ata.h b/include/linux/ata.h index c9013e472aa3..8fd48bcb2a46 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -26,9 +26,7 @@ enum { ATA_MAX_DEVICES = 2, /* per bus/port */ ATA_MAX_PRD = 256, /* we could make these 256/256 */ ATA_SECT_SIZE = 512, - ATA_MAX_SECTORS_128 = 128, ATA_MAX_SECTORS = 256, - ATA_MAX_SECTORS_1024 = 1024, ATA_MAX_SECTORS_LBA48 = 65535,/* avoid count to be 0000h */ ATA_MAX_SECTORS_TAPE = 65535, ATA_MAX_TRIM_RNUM = 64, /* 512-byte payload / (6-byte LBA + 2-byte range per entry) */ diff --git a/include/linux/libata.h b/include/linux/libata.h index 11b6a44572ac..7e5cd1647353 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -52,7 +52,6 @@ enum ata_quirks { __ATA_QUIRK_DIAGNOSTIC, /* Failed boot diag */ __ATA_QUIRK_NODMA, /* DMA problems */ __ATA_QUIRK_NONCQ, /* Don't use NCQ */ - __ATA_QUIRK_MAX_SEC_128, /* Limit max sects to 128 */ __ATA_QUIRK_BROKEN_HPA, /* Broken HPA */ __ATA_QUIRK_DISABLE, /* Disable it */ __ATA_QUIRK_HPA_SIZE, /* Native size off by one */ @@ -74,7 +73,6 @@ enum ata_quirks { __ATA_QUIRK_ZERO_AFTER_TRIM, /* Guarantees zero after trim */ __ATA_QUIRK_NO_DMA_LOG, /* Do not use DMA for log read */ __ATA_QUIRK_NOTRIM, /* Do not use TRIM */ - __ATA_QUIRK_MAX_SEC_1024, /* Limit max sects to 1024 */ __ATA_QUIRK_MAX_SEC, /* Limit max sectors */ __ATA_QUIRK_MAX_TRIM_128M, /* Limit max trim size to 128M */ __ATA_QUIRK_NO_NCQ_ON_ATI, /* Disable NCQ on ATI chipset */ @@ -94,7 +92,6 @@ enum { ATA_QUIRK_DIAGNOSTIC = (1U << __ATA_QUIRK_DIAGNOSTIC), ATA_QUIRK_NODMA = (1U << __ATA_QUIRK_NODMA), ATA_QUIRK_NONCQ = (1U << __ATA_QUIRK_NONCQ), - ATA_QUIRK_MAX_SEC_128 = (1U << __ATA_QUIRK_MAX_SEC_128), ATA_QUIRK_BROKEN_HPA = (1U << __ATA_QUIRK_BROKEN_HPA), ATA_QUIRK_DISABLE = (1U << __ATA_QUIRK_DISABLE), ATA_QUIRK_HPA_SIZE = (1U << __ATA_QUIRK_HPA_SIZE), @@ -115,7 +112,6 @@ enum { ATA_QUIRK_ZERO_AFTER_TRIM = (1U << __ATA_QUIRK_ZERO_AFTER_TRIM), ATA_QUIRK_NO_DMA_LOG = (1U << __ATA_QUIRK_NO_DMA_LOG), ATA_QUIRK_NOTRIM = (1U << __ATA_QUIRK_NOTRIM), - ATA_QUIRK_MAX_SEC_1024 = (1U << __ATA_QUIRK_MAX_SEC_1024), ATA_QUIRK_MAX_SEC = (1U << __ATA_QUIRK_MAX_SEC), ATA_QUIRK_MAX_TRIM_128M = (1U << __ATA_QUIRK_MAX_TRIM_128M), ATA_QUIRK_NO_NCQ_ON_ATI = (1U << __ATA_QUIRK_NO_NCQ_ON_ATI), -- cgit v1.2.3 From 45c4c5a6156a5ab450a7595dd1c8985e2d459403 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Tue, 2 Dec 2025 13:21:34 +0100 Subject: ata: libata: Add support to parse equal sign in libata.force Currently, no libata.force parameter supports an arbitrary value. All allowed values, e.g. udma/16, udma/25, udma/33, udma/44, udma/66, udma/100, udma/133 have hardcoded entries in the force_tbl table. Add code to allow a libata.force param with the format libata.force=param=param_value, where param_value can be an arbitrary value. This code will be used in a follow up commit. Signed-off-by: Niklas Cassel Reviewed-by: Martin K. Petersen Reviewed-by: Damien Le Moal Signed-off-by: Damien Le Moal --- drivers/ata/libata-core.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index cf7b57d048a3..cd1ebdbe659b 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6490,6 +6490,13 @@ EXPORT_SYMBOL_GPL(ata_platform_remove_one); { "no" #name, .quirk_on = (flag) }, \ { #name, .quirk_off = (flag) } +/* + * If the ata_force_param struct member 'name' ends with '=', then the value + * after the equal sign will be parsed as an u64, and will be saved in the + * ata_force_param struct member 'value'. This works because each libata.force + * entry (struct ata_force_ent) is separated by commas, so each entry represents + * a single quirk, and can thus only have a single value. + */ static const struct ata_force_param force_tbl[] __initconst = { force_cbl(40c, ATA_CBL_PATA40), force_cbl(80c, ATA_CBL_PATA80), @@ -6577,8 +6584,9 @@ static int __init ata_parse_force_one(char **cur, const char **reason) { char *start = *cur, *p = *cur; - char *id, *val, *endp; + char *id, *val, *endp, *equalsign, *char_after_equalsign; const struct ata_force_param *match_fp = NULL; + u64 val_after_equalsign; int nr_matches = 0, i; /* find where this param ends and update *cur */ @@ -6621,10 +6629,36 @@ static int __init ata_parse_force_one(char **cur, } parse_val: - /* parse val, allow shortcuts so that both 1.5 and 1.5Gbps work */ + equalsign = strchr(val, '='); + if (equalsign) { + char_after_equalsign = equalsign + 1; + if (!strlen(char_after_equalsign) || + kstrtoull(char_after_equalsign, 10, &val_after_equalsign)) { + *reason = "invalid value after equal sign"; + return -EINVAL; + } + } + + /* Parse the parameter value. */ for (i = 0; i < ARRAY_SIZE(force_tbl); i++) { const struct ata_force_param *fp = &force_tbl[i]; + /* + * If val contains equal sign, match has to be exact, i.e. + * shortcuts are not supported. + */ + if (equalsign && + (strncasecmp(val, fp->name, + char_after_equalsign - val) == 0)) { + force_ent->param = *fp; + force_ent->param.value = val_after_equalsign; + return 0; + } + + /* + * If val does not contain equal sign, allow shortcuts so that + * both 1.5 and 1.5Gbps work. + */ if (strncasecmp(val, fp->name, strlen(val))) continue; -- cgit v1.2.3 From ad50d922f4857ca58dbda172d5d6356ab53e7845 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Tue, 2 Dec 2025 13:21:35 +0100 Subject: ata: libata: Add libata.force parameter max_sec Add a new libata.force parameter called max_sec. The parameter can take an arbitrary value using the format: libata.force=max_sec= e.g. libata.force=max_sec=8191 or libata.force=max_sec=2048 This will allow the user to set an arbitrary maximum command size (dev->max_sectors) using libata.force. We cannot remove the existing libata.force parameters "max_sec_128" and "max_sec_1024", as these are a part of the exising user facing API. Signed-off-by: Niklas Cassel Reviewed-by: Martin K. Petersen Reviewed-by: Damien Le Moal Signed-off-by: Damien Le Moal --- Documentation/admin-guide/kernel-parameters.txt | 5 +++++ drivers/ata/libata-core.c | 1 + 2 files changed, 6 insertions(+) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index a8d0afde7f85..a467a7661efb 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3412,6 +3412,11 @@ Kernel parameters * [no]logdir: Enable or disable access to the general purpose log directory. + * max_sec=: Set the transfer size limit, in + number of 512-byte sectors, to the value specified in + . The value specified in has to be + a non-zero positive integer. + * max_sec_128: Set transfer size limit to 128 sectors. * max_sec_1024: Set or clear transfer size limit to diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index cd1ebdbe659b..9b0efca03a7d 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6569,6 +6569,7 @@ static const struct ata_force_param force_tbl[] __initconst = { force_quirk_val(max_sec_128, ATA_QUIRK_MAX_SEC, 128), force_quirk_val(max_sec_1024, ATA_QUIRK_MAX_SEC, 1024), + force_quirk_on(max_sec=, ATA_QUIRK_MAX_SEC), force_quirk_on(max_sec_lba48, ATA_QUIRK_MAX_SEC_LBA48), force_quirk_onoff(lpm, ATA_QUIRK_NOLPM), -- cgit v1.2.3 From f474c70065e14bac928716100eebfcfb15e1a725 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Tue, 2 Dec 2025 13:21:36 +0100 Subject: ata: libata: Allow more quirks We have currently used up 30 out of the 32-bits in the struct ata_device struct member quirks. Thus, it is only possible to add two more quirks. Change the struct ata_device struct member quirks from an unsigned int to an u64. Doing this core level change now, will make it easier for us now, as we will not need to also do core level changes once the final two bits are used as well. Signed-off-by: Niklas Cassel Reviewed-by: Martin K. Petersen Reviewed-by: Damien Le Moal Signed-off-by: Damien Le Moal --- drivers/ata/libata-core.c | 18 ++++++------- include/linux/libata.h | 64 +++++++++++++++++++++++------------------------ 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 9b0efca03a7d..b96105481784 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -76,8 +76,8 @@ static unsigned int ata_dev_init_params(struct ata_device *dev, u16 heads, u16 sectors); static unsigned int ata_dev_set_xfermode(struct ata_device *dev); static void ata_dev_xfermask(struct ata_device *dev); -static unsigned int ata_dev_quirks(const struct ata_device *dev); -static u64 ata_dev_get_quirk_value(struct ata_device *dev, unsigned int quirk); +static u64 ata_dev_quirks(const struct ata_device *dev); +static u64 ata_dev_get_quirk_value(struct ata_device *dev, u64 quirk); static DEFINE_IDA(ata_ida); @@ -88,8 +88,8 @@ struct ata_force_param { u8 cbl; u8 spd_limit; unsigned int xfer_mask; - unsigned int quirk_on; - unsigned int quirk_off; + u64 quirk_on; + u64 quirk_off; unsigned int pflags_on; u16 lflags_on; u16 lflags_off; @@ -4088,7 +4088,7 @@ static const struct ata_dev_quirk_value __ata_dev_max_sec_quirks[] = { struct ata_dev_quirks_entry { const char *model_num; const char *model_rev; - unsigned int quirks; + u64 quirks; }; static const struct ata_dev_quirks_entry __ata_dev_quirks[] = { @@ -4377,14 +4377,14 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = { { } }; -static unsigned int ata_dev_quirks(const struct ata_device *dev) +static u64 ata_dev_quirks(const struct ata_device *dev) { unsigned char model_num[ATA_ID_PROD_LEN + 1]; unsigned char model_rev[ATA_ID_FW_REV_LEN + 1]; const struct ata_dev_quirks_entry *ad = __ata_dev_quirks; - /* dev->quirks is an unsigned int. */ - BUILD_BUG_ON(__ATA_QUIRK_MAX > 32); + /* dev->quirks is an u64. */ + BUILD_BUG_ON(__ATA_QUIRK_MAX > 64); ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev)); @@ -4435,7 +4435,7 @@ out: return val; } -static u64 ata_dev_get_quirk_value(struct ata_device *dev, unsigned int quirk) +static u64 ata_dev_get_quirk_value(struct ata_device *dev, u64 quirk) { if (quirk == ATA_QUIRK_MAX_SEC) return ata_dev_get_max_sec_quirk_value(dev); diff --git a/include/linux/libata.h b/include/linux/libata.h index 7e5cd1647353..aa88244f3d83 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -46,7 +46,7 @@ /* * Quirk flags bits. - * ata_device->quirks is an unsigned int, so __ATA_QUIRK_MAX must not exceed 32. + * ata_device->quirks is an u64, so __ATA_QUIRK_MAX must not exceed 64. */ enum ata_quirks { __ATA_QUIRK_DIAGNOSTIC, /* Failed boot diag */ @@ -89,36 +89,36 @@ enum ata_quirks { * Some quirks may be drive/controller pair dependent. */ enum { - ATA_QUIRK_DIAGNOSTIC = (1U << __ATA_QUIRK_DIAGNOSTIC), - ATA_QUIRK_NODMA = (1U << __ATA_QUIRK_NODMA), - ATA_QUIRK_NONCQ = (1U << __ATA_QUIRK_NONCQ), - ATA_QUIRK_BROKEN_HPA = (1U << __ATA_QUIRK_BROKEN_HPA), - ATA_QUIRK_DISABLE = (1U << __ATA_QUIRK_DISABLE), - ATA_QUIRK_HPA_SIZE = (1U << __ATA_QUIRK_HPA_SIZE), - ATA_QUIRK_IVB = (1U << __ATA_QUIRK_IVB), - ATA_QUIRK_STUCK_ERR = (1U << __ATA_QUIRK_STUCK_ERR), - ATA_QUIRK_BRIDGE_OK = (1U << __ATA_QUIRK_BRIDGE_OK), - ATA_QUIRK_ATAPI_MOD16_DMA = (1U << __ATA_QUIRK_ATAPI_MOD16_DMA), - ATA_QUIRK_FIRMWARE_WARN = (1U << __ATA_QUIRK_FIRMWARE_WARN), - ATA_QUIRK_1_5_GBPS = (1U << __ATA_QUIRK_1_5_GBPS), - ATA_QUIRK_NOSETXFER = (1U << __ATA_QUIRK_NOSETXFER), - ATA_QUIRK_BROKEN_FPDMA_AA = (1U << __ATA_QUIRK_BROKEN_FPDMA_AA), - ATA_QUIRK_DUMP_ID = (1U << __ATA_QUIRK_DUMP_ID), - ATA_QUIRK_MAX_SEC_LBA48 = (1U << __ATA_QUIRK_MAX_SEC_LBA48), - ATA_QUIRK_ATAPI_DMADIR = (1U << __ATA_QUIRK_ATAPI_DMADIR), - ATA_QUIRK_NO_NCQ_TRIM = (1U << __ATA_QUIRK_NO_NCQ_TRIM), - ATA_QUIRK_NOLPM = (1U << __ATA_QUIRK_NOLPM), - ATA_QUIRK_WD_BROKEN_LPM = (1U << __ATA_QUIRK_WD_BROKEN_LPM), - ATA_QUIRK_ZERO_AFTER_TRIM = (1U << __ATA_QUIRK_ZERO_AFTER_TRIM), - ATA_QUIRK_NO_DMA_LOG = (1U << __ATA_QUIRK_NO_DMA_LOG), - ATA_QUIRK_NOTRIM = (1U << __ATA_QUIRK_NOTRIM), - ATA_QUIRK_MAX_SEC = (1U << __ATA_QUIRK_MAX_SEC), - ATA_QUIRK_MAX_TRIM_128M = (1U << __ATA_QUIRK_MAX_TRIM_128M), - ATA_QUIRK_NO_NCQ_ON_ATI = (1U << __ATA_QUIRK_NO_NCQ_ON_ATI), - ATA_QUIRK_NO_LPM_ON_ATI = (1U << __ATA_QUIRK_NO_LPM_ON_ATI), - ATA_QUIRK_NO_ID_DEV_LOG = (1U << __ATA_QUIRK_NO_ID_DEV_LOG), - ATA_QUIRK_NO_LOG_DIR = (1U << __ATA_QUIRK_NO_LOG_DIR), - ATA_QUIRK_NO_FUA = (1U << __ATA_QUIRK_NO_FUA), + ATA_QUIRK_DIAGNOSTIC = BIT_ULL(__ATA_QUIRK_DIAGNOSTIC), + ATA_QUIRK_NODMA = BIT_ULL(__ATA_QUIRK_NODMA), + ATA_QUIRK_NONCQ = BIT_ULL(__ATA_QUIRK_NONCQ), + ATA_QUIRK_BROKEN_HPA = BIT_ULL(__ATA_QUIRK_BROKEN_HPA), + ATA_QUIRK_DISABLE = BIT_ULL(__ATA_QUIRK_DISABLE), + ATA_QUIRK_HPA_SIZE = BIT_ULL(__ATA_QUIRK_HPA_SIZE), + ATA_QUIRK_IVB = BIT_ULL(__ATA_QUIRK_IVB), + ATA_QUIRK_STUCK_ERR = BIT_ULL(__ATA_QUIRK_STUCK_ERR), + ATA_QUIRK_BRIDGE_OK = BIT_ULL(__ATA_QUIRK_BRIDGE_OK), + ATA_QUIRK_ATAPI_MOD16_DMA = BIT_ULL(__ATA_QUIRK_ATAPI_MOD16_DMA), + ATA_QUIRK_FIRMWARE_WARN = BIT_ULL(__ATA_QUIRK_FIRMWARE_WARN), + ATA_QUIRK_1_5_GBPS = BIT_ULL(__ATA_QUIRK_1_5_GBPS), + ATA_QUIRK_NOSETXFER = BIT_ULL(__ATA_QUIRK_NOSETXFER), + ATA_QUIRK_BROKEN_FPDMA_AA = BIT_ULL(__ATA_QUIRK_BROKEN_FPDMA_AA), + ATA_QUIRK_DUMP_ID = BIT_ULL(__ATA_QUIRK_DUMP_ID), + ATA_QUIRK_MAX_SEC_LBA48 = BIT_ULL(__ATA_QUIRK_MAX_SEC_LBA48), + ATA_QUIRK_ATAPI_DMADIR = BIT_ULL(__ATA_QUIRK_ATAPI_DMADIR), + ATA_QUIRK_NO_NCQ_TRIM = BIT_ULL(__ATA_QUIRK_NO_NCQ_TRIM), + ATA_QUIRK_NOLPM = BIT_ULL(__ATA_QUIRK_NOLPM), + ATA_QUIRK_WD_BROKEN_LPM = BIT_ULL(__ATA_QUIRK_WD_BROKEN_LPM), + ATA_QUIRK_ZERO_AFTER_TRIM = BIT_ULL(__ATA_QUIRK_ZERO_AFTER_TRIM), + ATA_QUIRK_NO_DMA_LOG = BIT_ULL(__ATA_QUIRK_NO_DMA_LOG), + ATA_QUIRK_NOTRIM = BIT_ULL(__ATA_QUIRK_NOTRIM), + ATA_QUIRK_MAX_SEC = BIT_ULL(__ATA_QUIRK_MAX_SEC), + ATA_QUIRK_MAX_TRIM_128M = BIT_ULL(__ATA_QUIRK_MAX_TRIM_128M), + ATA_QUIRK_NO_NCQ_ON_ATI = BIT_ULL(__ATA_QUIRK_NO_NCQ_ON_ATI), + ATA_QUIRK_NO_LPM_ON_ATI = BIT_ULL(__ATA_QUIRK_NO_LPM_ON_ATI), + ATA_QUIRK_NO_ID_DEV_LOG = BIT_ULL(__ATA_QUIRK_NO_ID_DEV_LOG), + ATA_QUIRK_NO_LOG_DIR = BIT_ULL(__ATA_QUIRK_NO_LOG_DIR), + ATA_QUIRK_NO_FUA = BIT_ULL(__ATA_QUIRK_NO_FUA), }; enum { @@ -719,7 +719,7 @@ struct ata_cdl { struct ata_device { struct ata_link *link; unsigned int devno; /* 0 or 1 */ - unsigned int quirks; /* List of broken features */ + u64 quirks; /* List of broken features */ unsigned long flags; /* ATA_DFLAG_xxx */ struct scsi_device *sdev; /* attached SCSI device */ void *private_data; -- cgit v1.2.3 From 2dc8a3295b07261aad614f45175616c8c9cd0a76 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Mon, 5 Jan 2026 15:29:16 -0600 Subject: dt-bindings: ata: ahci-platform: Drop unnecessary select schema The "select" schema is not necessary. It looks like it is there to prevent matching on "generic-ahci" compatible, but that's not necessary because this is the only place "generic-ahci" compatible is present. Signed-off-by: Rob Herring (Arm) Signed-off-by: Damien Le Moal --- .../devicetree/bindings/ata/ahci-platform.yaml | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.yaml b/Documentation/devicetree/bindings/ata/ahci-platform.yaml index cc35cdc02840..cd67926aae41 100644 --- a/Documentation/devicetree/bindings/ata/ahci-platform.yaml +++ b/Documentation/devicetree/bindings/ata/ahci-platform.yaml @@ -18,26 +18,6 @@ maintainers: - Hans de Goede - Jens Axboe -select: - properties: - compatible: - contains: - enum: - - brcm,iproc-ahci - - cavium,octeon-7130-ahci - - hisilicon,hisi-ahci - - ibm,476gtr-ahci - - marvell,armada-3700-ahci - - marvell,armada-8k-ahci - - marvell,berlin2q-ahci - - qcom,apq8064-ahci - - qcom,ipq806x-ahci - - socionext,uniphier-pro4-ahci - - socionext,uniphier-pxs2-ahci - - socionext,uniphier-pxs3-ahci - required: - - compatible - properties: compatible: oneOf: -- cgit v1.2.3 From 602f6612826b47f6a70931002172c404db9da872 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 5 Jan 2026 15:29:45 +0100 Subject: ata: ahci-dwc: Simplify with scoped for each OF child loop Use scoped for-each loop when iterating over device nodes and switch to iterating already over available nodes to make code a bit simpler. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Damien Le Moal --- drivers/ata/ahci_dwc.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/ata/ahci_dwc.c b/drivers/ata/ahci_dwc.c index aec6d793f51a..64abf865bb67 100644 --- a/drivers/ata/ahci_dwc.c +++ b/drivers/ata/ahci_dwc.c @@ -260,7 +260,6 @@ static void ahci_dwc_init_timer(struct ahci_host_priv *hpriv) static int ahci_dwc_init_dmacr(struct ahci_host_priv *hpriv) { struct ahci_dwc_host_priv *dpriv = hpriv->plat_data; - struct device_node *child; void __iomem *port_mmio; u32 port, dmacr, ts; @@ -271,14 +270,9 @@ static int ahci_dwc_init_dmacr(struct ahci_host_priv *hpriv) * the HBA global reset so we can freely initialize it once until the * next system reset. */ - for_each_child_of_node(dpriv->pdev->dev.of_node, child) { - if (!of_device_is_available(child)) - continue; - - if (of_property_read_u32(child, "reg", &port)) { - of_node_put(child); + for_each_available_child_of_node_scoped(dpriv->pdev->dev.of_node, child) { + if (of_property_read_u32(child, "reg", &port)) return -EINVAL; - } port_mmio = __ahci_port_base(hpriv, port); dmacr = readl(port_mmio + AHCI_DWC_PORT_DMACR); -- cgit v1.2.3 From 4afc71c225130dab95ce15fcb385b5b500c02ed4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 5 Jan 2026 15:29:46 +0100 Subject: ata: ahci-imx: Fix Wvoid-pointer-to-enum-cast warning "imxpriv->type" is an enum, thus cast of pointer on 64-bit compile test with clang W=1 causes: ahci_imx.c:872:18: error: cast to smaller integer type 'enum ahci_imx_type' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast] Signed-off-by: Krzysztof Kozlowski Signed-off-by: Damien Le Moal --- drivers/ata/ahci_imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index 86aedd5923ac..3d26595524d3 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c @@ -869,7 +869,7 @@ static int imx_ahci_probe(struct platform_device *pdev) imxpriv->ahci_pdev = pdev; imxpriv->no_device = false; imxpriv->first_time = true; - imxpriv->type = (enum ahci_imx_type)device_get_match_data(dev); + imxpriv->type = (unsigned long)device_get_match_data(dev); imxpriv->sata_clk = devm_clk_get(dev, "sata"); if (IS_ERR(imxpriv->sata_clk)) { -- cgit v1.2.3 From 97e01439e902b743b8f89497e9c144e3ddda5e59 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 5 Jan 2026 15:29:47 +0100 Subject: ata: ahci-xgene: Fix Wvoid-pointer-to-enum-cast warning "version" is an enum, thus cast of pointer on 64-bit compile test with clang W=1 causes: ahci_xgene.c:776:13: error: cast to smaller integer type 'enum xgene_ahci_version' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast] Signed-off-by: Krzysztof Kozlowski Signed-off-by: Damien Le Moal --- drivers/ata/ahci_xgene.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index 6b8844646fcd..98c99b5a8242 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c @@ -773,7 +773,7 @@ static int xgene_ahci_probe(struct platform_device *pdev) } if (dev->of_node) { - version = (enum xgene_ahci_version)of_device_get_match_data(dev); + version = (unsigned long)of_device_get_match_data(dev); } #ifdef CONFIG_ACPI else { -- cgit v1.2.3 From bb3a8154b1a1dc2c86d037482c0a2cf9186829ed Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Wed, 17 Dec 2025 14:05:25 +0900 Subject: ata: libata-scsi: refactor ata_scsi_translate() Factor out of ata_scsi_translate() the code handling queued command deferral using the port qc_defer callback and issuing the queued command with ata_qc_issue() into the new function ata_scsi_qc_issue(), and simplify the goto used in ata_scsi_translate(). While at it, also add a lockdep annotation to check that the port lock is held when ata_scsi_translate() is called. No functional changes. Cc: stable@vger.kernel.org Signed-off-by: Damien Le Moal Reviewed-by: Niklas Cassel Reviewed-by: Martin K. Petersen Reviewed-by: John Garry Reviewed-by: Igor Pylypiv --- drivers/ata/libata-scsi.c | 81 +++++++++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index d388a4ff9ae4..be620bc04584 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1691,6 +1691,42 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) ata_qc_done(qc); } +static int ata_scsi_qc_issue(struct ata_port *ap, struct ata_queued_cmd *qc) +{ + int ret; + + if (!ap->ops->qc_defer) + goto issue; + + /* Check if the command needs to be deferred. */ + ret = ap->ops->qc_defer(qc); + switch (ret) { + case 0: + break; + case ATA_DEFER_LINK: + ret = SCSI_MLQUEUE_DEVICE_BUSY; + break; + case ATA_DEFER_PORT: + ret = SCSI_MLQUEUE_HOST_BUSY; + break; + default: + WARN_ON_ONCE(1); + ret = SCSI_MLQUEUE_HOST_BUSY; + break; + } + + if (ret) { + /* Force a requeue of the command to defer its execution. */ + ata_qc_free(qc); + return ret; + } + +issue: + ata_qc_issue(qc); + + return 0; +} + /** * ata_scsi_translate - Translate then issue SCSI command to ATA device * @dev: ATA device to which the command is addressed @@ -1714,66 +1750,49 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) * spin_lock_irqsave(host lock) * * RETURNS: - * 0 on success, SCSI_ML_QUEUE_DEVICE_BUSY if the command - * needs to be deferred. + * 0 on success, SCSI_ML_QUEUE_DEVICE_BUSY or SCSI_MLQUEUE_HOST_BUSY if the + * command needs to be deferred. */ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd, ata_xlat_func_t xlat_func) { struct ata_port *ap = dev->link->ap; struct ata_queued_cmd *qc; - int rc; + lockdep_assert_held(ap->lock); + + /* + * ata_scsi_qc_new() calls scsi_done(cmd) in case of failure. So we + * have nothing further to do when allocating a qc fails. + */ qc = ata_scsi_qc_new(dev, cmd); if (!qc) - goto err_mem; + return 0; /* data is present; dma-map it */ if (cmd->sc_data_direction == DMA_FROM_DEVICE || cmd->sc_data_direction == DMA_TO_DEVICE) { if (unlikely(scsi_bufflen(cmd) < 1)) { ata_dev_warn(dev, "WARNING: zero len r/w req\n"); - goto err_did; + cmd->result = (DID_ERROR << 16); + goto done; } ata_sg_init(qc, scsi_sglist(cmd), scsi_sg_count(cmd)); - qc->dma_dir = cmd->sc_data_direction; } qc->complete_fn = ata_scsi_qc_complete; if (xlat_func(qc)) - goto early_finish; - - if (ap->ops->qc_defer) { - if ((rc = ap->ops->qc_defer(qc))) - goto defer; - } - - /* select device, send command to hardware */ - ata_qc_issue(qc); + goto done; - return 0; - -early_finish: - ata_qc_free(qc); - scsi_done(cmd); - return 0; + return ata_scsi_qc_issue(ap, qc); -err_did: +done: ata_qc_free(qc); - cmd->result = (DID_ERROR << 16); scsi_done(cmd); -err_mem: return 0; - -defer: - ata_qc_free(qc); - if (rc == ATA_DEFER_LINK) - return SCSI_MLQUEUE_DEVICE_BUSY; - else - return SCSI_MLQUEUE_HOST_BUSY; } /** -- cgit v1.2.3 From 0ea84089dbf62a92dc7889c79e6b18fc89260808 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Wed, 17 Dec 2025 16:40:48 +0900 Subject: ata: libata-scsi: avoid Non-NCQ command starvation When a non-NCQ command is issued while NCQ commands are being executed, ata_scsi_qc_issue() indicates to the SCSI layer that the command issuing should be deferred by returning SCSI_MLQUEUE_XXX_BUSY. This command deferring is correct and as mandated by the ACS specifications since NCQ and non-NCQ commands cannot be mixed. However, in the case of a host adapter using multiple submission queues, when the target device is under a constant load of NCQ commands, there are no guarantees that requeueing the non-NCQ command will be executed later and it may be deferred again repeatedly as other submission queues can constantly issue NCQ commands from different CPUs ahead of the non-NCQ command. This can lead to very long delays for the execution of non-NCQ commands, and even complete starvation for these commands in the worst case scenario. Since the block layer and the SCSI layer do not distinguish between queueable (NCQ) and non queueable (non-NCQ) commands, libata-scsi SAT implementation must ensure forward progress for non-NCQ commands in the presence of NCQ command traffic. This is similar to what SAS HBAs with a hardware/firmware based SAT implementation do. Implement such forward progress guarantee by limiting requeueing of non-NCQ commands from ata_scsi_qc_issue(): when a non-NCQ command is received and NCQ commands are in-flight, do not force a requeue of the non-NCQ command by returning SCSI_MLQUEUE_XXX_BUSY and instead return 0 to indicate that the command was accepted but hold on to the qc using the new deferred_qc field of struct ata_port. This deferred qc will be issued using the work item deferred_qc_work running the function ata_scsi_deferred_qc_work() once all in-flight commands complete, which is checked with the port qc_defer() callback return value indicating that no further delay is necessary. This check is done using the helper function ata_scsi_schedule_deferred_qc() which is called from ata_scsi_qc_complete(). This thus excludes this mechanism from all internal non-NCQ commands issued by ATA EH. When a port deferred_qc is non NULL, that is, the port has a command waiting for the device queue to drain, the issuing of all incoming commands (both NCQ and non-NCQ) is deferred using the regular busy mechanism. This simplifies the code and also avoids potential denial of service problems if a user issues too many non-NCQ commands. Finally, whenever ata EH is scheduled, regardless of the reason, a deferred qc is always requeued so that it can be retried once EH completes. This is done by calling the function ata_scsi_requeue_deferred_qc() from ata_eh_set_pending(). This avoids the need for any special processing for the deferred qc in case of NCQ error, link or device reset, or device timeout. Reported-by: Xingui Yang Reported-by: Igor Pylypiv Fixes: bdb01301f3ea ("scsi: Add host and host template flag 'host_tagset'") Cc: stable@vger.kernel.org Signed-off-by: Damien Le Moal Reviewed-by: Niklas Cassel Reviewed-by: Martin K. Petersen Reviewed-by: John Garry Tested-by: Igor Pylypiv Tested-by: Xingui Yang --- drivers/ata/libata-core.c | 5 +++ drivers/ata/libata-eh.c | 6 +++ drivers/ata/libata-scsi.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/ata/libata.h | 2 + include/linux/libata.h | 3 ++ 5 files changed, 109 insertions(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b96105481784..e888f2445692 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5644,6 +5644,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host) mutex_init(&ap->scsi_scan_mutex); INIT_DELAYED_WORK(&ap->hotplug_task, ata_scsi_hotplug); INIT_DELAYED_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan); + INIT_WORK(&ap->deferred_qc_work, ata_scsi_deferred_qc_work); INIT_LIST_HEAD(&ap->eh_done_q); init_waitqueue_head(&ap->eh_wait_q); init_completion(&ap->park_req_pending); @@ -6256,6 +6257,10 @@ static void ata_port_detach(struct ata_port *ap) } } + /* Make sure the deferred qc work finished. */ + cancel_work_sync(&ap->deferred_qc_work); + WARN_ON(ap->deferred_qc); + /* Tell EH to disable all devices */ ap->pflags |= ATA_PFLAG_UNLOADING; ata_port_schedule_eh(ap); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index f4c9541d1910..72a22b6c9682 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -918,6 +918,12 @@ static void ata_eh_set_pending(struct ata_port *ap, bool fastdrain) ap->pflags |= ATA_PFLAG_EH_PENDING; + /* + * If we have a deferred qc, requeue it so that it is retried once EH + * completes. + */ + ata_scsi_requeue_deferred_qc(ap); + if (!fastdrain) return; diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index be620bc04584..e7898bf56308 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1658,8 +1658,77 @@ static void ata_qc_done(struct ata_queued_cmd *qc) done(cmd); } +void ata_scsi_deferred_qc_work(struct work_struct *work) +{ + struct ata_port *ap = + container_of(work, struct ata_port, deferred_qc_work); + struct ata_queued_cmd *qc; + unsigned long flags; + + spin_lock_irqsave(ap->lock, flags); + + /* + * If we still have a deferred qc and we are not in EH, issue it. In + * such case, we should not need any more deferring the qc, so warn if + * qc_defer() says otherwise. + */ + qc = ap->deferred_qc; + if (qc && !ata_port_eh_scheduled(ap)) { + WARN_ON_ONCE(ap->ops->qc_defer(qc)); + ap->deferred_qc = NULL; + ata_qc_issue(qc); + } + + spin_unlock_irqrestore(ap->lock, flags); +} + +void ata_scsi_requeue_deferred_qc(struct ata_port *ap) +{ + struct ata_queued_cmd *qc = ap->deferred_qc; + struct scsi_cmnd *scmd; + + lockdep_assert_held(ap->lock); + + /* + * If we have a deferred qc when a reset occurs or NCQ commands fail, + * do not try to be smart about what to do with this deferred command + * and simply retry it by completing it with DID_SOFT_ERROR. + */ + if (!qc) + return; + + scmd = qc->scsicmd; + ap->deferred_qc = NULL; + ata_qc_free(qc); + scmd->result = (DID_SOFT_ERROR << 16); + scsi_done(scmd); +} + +static void ata_scsi_schedule_deferred_qc(struct ata_port *ap) +{ + struct ata_queued_cmd *qc = ap->deferred_qc; + + lockdep_assert_held(ap->lock); + + /* + * If we have a deferred qc, then qc_defer() is defined and we can use + * this callback to determine if this qc is good to go, unless EH has + * been scheduled. + */ + if (!qc) + return; + + if (ata_port_eh_scheduled(ap)) { + ata_scsi_requeue_deferred_qc(ap); + return; + } + if (!ap->ops->qc_defer(qc)) + queue_work(system_highpri_wq, &ap->deferred_qc_work); +} + static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) { + struct ata_port *ap = qc->ap; struct scsi_cmnd *cmd = qc->scsicmd; u8 *cdb = cmd->cmnd; bool have_sense = qc->flags & ATA_QCFLAG_SENSE_VALID; @@ -1689,6 +1758,8 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) } ata_qc_done(qc); + + ata_scsi_schedule_deferred_qc(ap); } static int ata_scsi_qc_issue(struct ata_port *ap, struct ata_queued_cmd *qc) @@ -1698,6 +1769,16 @@ static int ata_scsi_qc_issue(struct ata_port *ap, struct ata_queued_cmd *qc) if (!ap->ops->qc_defer) goto issue; + /* + * If we already have a deferred qc, then rely on the SCSI layer to + * requeue and defer all incoming commands until the deferred qc is + * processed, once all on-going commands complete. + */ + if (ap->deferred_qc) { + ata_qc_free(qc); + return SCSI_MLQUEUE_DEVICE_BUSY; + } + /* Check if the command needs to be deferred. */ ret = ap->ops->qc_defer(qc); switch (ret) { @@ -1716,6 +1797,18 @@ static int ata_scsi_qc_issue(struct ata_port *ap, struct ata_queued_cmd *qc) } if (ret) { + /* + * We must defer this qc: if this is not an NCQ command, keep + * this qc as a deferred one and report to the SCSI layer that + * we issued it so that it is not requeued. The deferred qc will + * be issued with the port deferred_qc_work once all on-going + * commands complete. + */ + if (!ata_is_ncq(qc->tf.protocol)) { + ap->deferred_qc = qc; + return 0; + } + /* Force a requeue of the command to defer its execution. */ ata_qc_free(qc); return ret; diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 89dd0ae2b991..9b4e578ad07e 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -166,6 +166,8 @@ void ata_scsi_sdev_config(struct scsi_device *sdev); int ata_scsi_dev_config(struct scsi_device *sdev, struct queue_limits *lim, struct ata_device *dev); int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, struct ata_device *dev); +void ata_scsi_deferred_qc_work(struct work_struct *work); +void ata_scsi_requeue_deferred_qc(struct ata_port *ap); /* libata-eh.c */ extern unsigned int ata_internal_cmd_timeout(struct ata_device *dev, u8 cmd); diff --git a/include/linux/libata.h b/include/linux/libata.h index aa88244f3d83..d612d4c1660a 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -899,6 +899,9 @@ struct ata_port { u64 qc_active; int nr_active_links; /* #links with active qcs */ + struct work_struct deferred_qc_work; + struct ata_queued_cmd *deferred_qc; + struct ata_link link; /* host default link */ struct ata_link *slave_link; /* see ata_slave_link_init() */ -- cgit v1.2.3 From bcbd8ef484773580edfcaa3f54d7f27986c7cd1c Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Wed, 7 Jan 2026 19:41:23 +0530 Subject: dt-bindings: ata: sata: Document the graph port An external connector like M.2 could expose the SATA interface to the plugin cards. So add the graph port to establish link between the SATA port and the connector node. Signed-off-by: Manivannan Sadhasivam Reviewed-by: Rob Herring (Arm) Signed-off-by: Damien Le Moal --- Documentation/devicetree/bindings/ata/sata-common.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/ata/sata-common.yaml b/Documentation/devicetree/bindings/ata/sata-common.yaml index 58c9342b9925..97cd69ebf331 100644 --- a/Documentation/devicetree/bindings/ata/sata-common.yaml +++ b/Documentation/devicetree/bindings/ata/sata-common.yaml @@ -54,4 +54,7 @@ $defs: each port can have a Port Multiplier attached thus allowing to access more than one drive by means of a single SATA port. + port: + $ref: /schemas/graph.yaml#/properties/port + ... -- cgit v1.2.3 From 5f64ae1ef639a2bab7e39497c55f76cc0682f108 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Tue, 20 Jan 2026 11:32:38 +0100 Subject: ata: libata-core: Quirk INTEL SSDSC2KG480G8 max_sectors Commit 9b8b84879d4a ("block: Increase BLK_DEF_MAX_SECTORS_CAP") increased the default max_sectors_kb from 1280 KiB to 4096 KiB. INTEL SSDSC2KG480G8 with FW rev XCV10120 times out when sending I/Os of size 4096 KiB. Enable ATA_QUIRK_MAX_SEC, with value 8191 (sectors) for this device, since any I/O with more sectors than that lead to I/O timeouts. With this, the INTEL SSDSC2KG480G8 is usable again. Link: https://lore.kernel.org/linux-ide/176839089913.2398366.61500945766820256@eldamar.lan/ Fixes: 9b8b84879d4a ("block: Increase BLK_DEF_MAX_SECTORS_CAP") Signed-off-by: Niklas Cassel Reviewed-by: Martin K. Petersen Signed-off-by: Damien Le Moal --- drivers/ata/libata-core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index e888f2445692..8e41e8a33096 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4082,6 +4082,7 @@ static const struct ata_dev_quirk_value __ata_dev_max_sec_quirks[] = { { "LITEON CX1-JB*-HP", NULL, 1024 }, { "LITEON EP1-*", NULL, 1024 }, { "DELLBOSS VD", "MV.R00-0", 8191 }, + { "INTEL SSDSC2KG480G8", "XCV10120", 8191 }, { }, }; @@ -4336,6 +4337,8 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = { { "Micron*", NULL, ATA_QUIRK_ZERO_AFTER_TRIM }, { "Crucial*", NULL, ATA_QUIRK_ZERO_AFTER_TRIM }, + { "INTEL SSDSC2KG480G8", "XCV10120", ATA_QUIRK_ZERO_AFTER_TRIM | + ATA_QUIRK_MAX_SEC }, { "INTEL*SSD*", NULL, ATA_QUIRK_ZERO_AFTER_TRIM }, { "SSD*INTEL*", NULL, ATA_QUIRK_ZERO_AFTER_TRIM }, { "Samsung*SSD*", NULL, ATA_QUIRK_ZERO_AFTER_TRIM }, -- cgit v1.2.3 From 3c4d783f6922e47fc31528c3ed6a240612c4ce15 Mon Sep 17 00:00:00 2001 From: Ethan Nelson-Moore Date: Fri, 30 Jan 2026 16:47:30 -0800 Subject: ata: pata_legacy: remove VLB support This significantly reduces the complexity of the pata_legacy driver. The VLB bus is very obsolete and last appeared on P5 Pentium-era hardware. Support for it has been removed from other drivers, and it is highly unlikely anyone is using it with modern Linux kernels. Some of these chips were integrated on motherboards, but they seem to have all been 486-era boards, which are equally obsolete. Signed-off-by: Ethan Nelson-Moore Signed-off-by: Damien Le Moal --- drivers/ata/Kconfig | 17 +- drivers/ata/pata_legacy.c | 867 +--------------------------------------------- 2 files changed, 6 insertions(+), 878 deletions(-) diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 120a2b7067fc..2349bca136e0 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -1127,13 +1127,6 @@ config PATA_OF_PLATFORM If unsure, say N. -config PATA_QDI - tristate "QDI VLB PATA support" - depends on ISA - select PATA_LEGACY - help - Support for QDI 6500 and 6580 PATA controllers on VESA local bus. - config PATA_RB532 tristate "RouterBoard 532 PATA CompactFlash support" depends on MIKROTIK_RB532 @@ -1152,14 +1145,6 @@ config PATA_RZ1000 If unsure, say N. -config PATA_WINBOND_VLB - tristate "Winbond W83759A VLB PATA support (Experimental)" - depends on ISA - select PATA_LEGACY - help - Support for the Winbond W83759A controller on Vesa Local Bus - systems. - config PATA_PARPORT tristate "Parallel port IDE device support" depends on PARPORT_PC @@ -1201,7 +1186,7 @@ config PATA_LEGACY depends on (ISA || PCI) && HAS_IOPORT select PATA_TIMINGS help - This option enables support for ISA/VLB/PCI bus legacy PATA + This option enables support for ISA/PCI bus legacy PATA ports and allows them to be accessed via the new ATA layer. If unsure, say N. diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index e7ac142c2423..80486f8820e4 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -5,43 +5,10 @@ * * An ATA driver for the legacy ATA ports. * - * Data Sources: - * Opti 82C465/82C611 support: Data sheets at opti-inc.com - * HT6560 series: - * Promise 20230/20620: - * http://www.ryston.cz/petr/vlb/pdc20230b.html - * http://www.ryston.cz/petr/vlb/pdc20230c.html - * http://www.ryston.cz/petr/vlb/pdc20630.html - * QDI65x0: - * http://www.ryston.cz/petr/vlb/qd6500.html - * http://www.ryston.cz/petr/vlb/qd6580.html - * - * QDI65x0 probe code based on drivers/ide/legacy/qd65xx.c - * Rewritten from the work of Colten Edwards by - * Samuel Thibault - * - * Unsupported but docs exist: - * Appian/Adaptec AIC25VL01/Cirrus Logic PD7220 - * - * This driver handles legacy (that is "ISA/VLB side") IDE ports found - * on PC class systems. There are three hybrid devices that are exceptions + * This driver handles legacy (that is "ISA side") IDE ports found + * on PC class systems. There are three hybrid devices that are exceptions: * The Cyrix 5510/5520 where a pre SFF ATA device is on the bridge and * the MPIIX where the tuning is PCI side but the IDE is "ISA side". - * - * Specific support is included for the ht6560a/ht6560b/opti82c611a/ - * opti82c465mv/promise 20230c/20630/qdi65x0/winbond83759A - * - * Support for the Winbond 83759A when operating in advanced mode. - * Multichip mode is not currently supported. - * - * Use the autospeed and pio_mask options with: - * Appian ADI/2 aka CLPD7220 or AIC25VL01. - * Use the jumpers, autospeed and set pio_mask to the mode on the jumpers with - * Goldstar GM82C711, PIC-1288A-125, UMC 82C871F, Winbond W83759, - * Winbond W83759A, Promise PDC20230-B - * - * For now use autospeed and pio_mask as above with the W83759A. This may - * change. */ #include @@ -87,55 +54,9 @@ static int iordy_mask = 0xFFFFFFFF; module_param(iordy_mask, int, 0); MODULE_PARM_DESC(iordy_mask, "Use IORDY if available"); -static int ht6560a; -module_param(ht6560a, int, 0); -MODULE_PARM_DESC(ht6560a, "HT 6560A on primary 1, second 2, both 3"); - -static int ht6560b; -module_param(ht6560b, int, 0); -MODULE_PARM_DESC(ht6560b, "HT 6560B on primary 1, secondary 2, both 3"); - -static int opti82c611a; -module_param(opti82c611a, int, 0); -MODULE_PARM_DESC(opti82c611a, - "Opti 82c611A on primary 1, secondary 2, both 3"); - -static int opti82c46x; -module_param(opti82c46x, int, 0); -MODULE_PARM_DESC(opti82c46x, - "Opti 82c465MV on primary 1, secondary 2, both 3"); - -#ifdef CONFIG_PATA_QDI_MODULE -static int qdi = 1; -#else -static int qdi; -#endif -module_param(qdi, int, 0); -MODULE_PARM_DESC(qdi, "Set to probe QDI controllers"); - -#ifdef CONFIG_PATA_WINBOND_VLB_MODULE -static int winbond = 1; -#else -static int winbond; -#endif -module_param(winbond, int, 0); -MODULE_PARM_DESC(winbond, - "Set to probe Winbond controllers, " - "give I/O port if non standard"); - - enum controller { BIOS = 0, SNOOP = 1, - PDC20230 = 2, - HT6560A = 3, - HT6560B = 4, - OPTI611A = 5, - OPTI46X = 6, - QDI6500 = 7, - QDI6580 = 8, - QDI6580DP = 9, /* Dual channel mode is different */ - W83759A = 10, UNKNOWN = -1 }; @@ -183,7 +104,7 @@ static struct ata_host *legacy_host[NR_HOST]; * * Add an entry into the probe list for ATA controllers. This is used * to add the default ISA slots and then to build up the table - * further according to other ISA/VLB/Weird device scans + * further according to other ISA/Weird device scans * * An I/O port list is used to keep ordering stable and sane, as we * don't have any good way to talk about ordering otherwise @@ -276,613 +197,11 @@ static struct ata_port_operations legacy_port_ops = { .set_mode = legacy_set_mode, }; -/* - * Promise 20230C and 20620 support - * - * This controller supports PIO0 to PIO2. We set PIO timings - * conservatively to allow for 50MHz Vesa Local Bus. The 20620 DMA - * support is weird being DMA to controller and PIO'd to the host - * and not supported. - */ - -static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev) -{ - int tries = 5; - int pio = adev->pio_mode - XFER_PIO_0; - u8 rt; - unsigned long flags; - - /* Safe as UP only. Force I/Os to occur together */ - - local_irq_save(flags); - - /* Unlock the control interface */ - do { - inb(0x1F5); - outb(inb(0x1F2) | 0x80, 0x1F2); - inb(0x1F2); - inb(0x3F6); - inb(0x3F6); - inb(0x1F2); - inb(0x1F2); - } - while ((inb(0x1F2) & 0x80) && --tries); - - local_irq_restore(flags); - - outb(inb(0x1F4) & 0x07, 0x1F4); - - rt = inb(0x1F3); - rt &= ~(0x07 << (3 * !adev->devno)); - if (pio) - rt |= (1 + 3 * pio) << (3 * !adev->devno); - outb(rt, 0x1F3); - - udelay(100); - outb(inb(0x1F2) | 0x01, 0x1F2); - udelay(100); - inb(0x1F5); - -} - -static unsigned int pdc_data_xfer_vlb(struct ata_queued_cmd *qc, - unsigned char *buf, unsigned int buflen, int rw) -{ - struct ata_device *dev = qc->dev; - struct ata_port *ap = dev->link->ap; - int slop = buflen & 3; - - /* 32bit I/O capable *and* we need to write a whole number of dwords */ - if (ata_id_has_dword_io(dev->id) && (slop == 0 || slop == 3) - && (ap->pflags & ATA_PFLAG_PIO32)) { - unsigned long flags; - - local_irq_save(flags); - - /* Perform the 32bit I/O synchronization sequence */ - ioread8(ap->ioaddr.nsect_addr); - ioread8(ap->ioaddr.nsect_addr); - ioread8(ap->ioaddr.nsect_addr); - - /* Now the data */ - if (rw == READ) - ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); - else - iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); - - if (unlikely(slop)) { - __le32 pad = 0; - - if (rw == READ) { - pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr)); - memcpy(buf + buflen - slop, &pad, slop); - } else { - memcpy(&pad, buf + buflen - slop, slop); - iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr); - } - buflen += 4 - slop; - } - local_irq_restore(flags); - } else - buflen = ata_sff_data_xfer32(qc, buf, buflen, rw); - - return buflen; -} - -static struct ata_port_operations pdc20230_port_ops = { - .inherits = &legacy_base_port_ops, - .set_piomode = pdc20230_set_piomode, - .sff_data_xfer = pdc_data_xfer_vlb, -}; - -/* - * Holtek 6560A support - * - * This controller supports PIO0 to PIO2 (no IORDY even though higher - * timings can be loaded). - */ - -static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev) -{ - u8 active, recover; - struct ata_timing t; - - /* Get the timing data in cycles. For now play safe at 50Mhz */ - ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000); - - active = clamp_val(t.active, 2, 15); - recover = clamp_val(t.recover, 4, 15); - - inb(0x3E6); - inb(0x3E6); - inb(0x3E6); - inb(0x3E6); - - iowrite8(recover << 4 | active, ap->ioaddr.device_addr); - ioread8(ap->ioaddr.status_addr); -} - -static struct ata_port_operations ht6560a_port_ops = { - .inherits = &legacy_base_port_ops, - .set_piomode = ht6560a_set_piomode, -}; - -/* - * Holtek 6560B support - * - * This controller supports PIO0 to PIO4. We honour the BIOS/jumper FIFO - * setting unless we see an ATAPI device in which case we force it off. - * - * FIXME: need to implement 2nd channel support. - */ - -static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev) -{ - u8 active, recover; - struct ata_timing t; - - /* Get the timing data in cycles. For now play safe at 50Mhz */ - ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000); - - active = clamp_val(t.active, 2, 15); - recover = clamp_val(t.recover, 2, 16) & 0x0F; - - inb(0x3E6); - inb(0x3E6); - inb(0x3E6); - inb(0x3E6); - - iowrite8(recover << 4 | active, ap->ioaddr.device_addr); - - if (adev->class != ATA_DEV_ATA) { - u8 rconf = inb(0x3E6); - if (rconf & 0x24) { - rconf &= ~0x24; - outb(rconf, 0x3E6); - } - } - ioread8(ap->ioaddr.status_addr); -} - -static struct ata_port_operations ht6560b_port_ops = { - .inherits = &legacy_base_port_ops, - .set_piomode = ht6560b_set_piomode, -}; - -/* - * Opti core chipset helpers - */ - -/** - * opti_syscfg - read OPTI chipset configuration - * @reg: Configuration register to read - * - * Returns the value of an OPTI system board configuration register. - */ - -static u8 opti_syscfg(u8 reg) -{ - unsigned long flags; - u8 r; - - /* Uniprocessor chipset and must force cycles adjancent */ - local_irq_save(flags); - outb(reg, 0x22); - r = inb(0x24); - local_irq_restore(flags); - return r; -} - -/* - * Opti 82C611A - * - * This controller supports PIO0 to PIO3. - */ - -static void opti82c611a_set_piomode(struct ata_port *ap, - struct ata_device *adev) -{ - u8 active, recover, setup; - struct ata_timing t; - struct ata_device *pair = ata_dev_pair(adev); - int clock; - int khz[4] = { 50000, 40000, 33000, 25000 }; - u8 rc; - - /* Enter configuration mode */ - ioread16(ap->ioaddr.error_addr); - ioread16(ap->ioaddr.error_addr); - iowrite8(3, ap->ioaddr.nsect_addr); - - /* Read VLB clock strapping */ - clock = 1000000000 / khz[ioread8(ap->ioaddr.lbah_addr) & 0x03]; - - /* Get the timing data in cycles */ - ata_timing_compute(adev, adev->pio_mode, &t, clock, 1000); - - /* Setup timing is shared */ - if (pair) { - struct ata_timing tp; - ata_timing_compute(pair, pair->pio_mode, &tp, clock, 1000); - - ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP); - } - - active = clamp_val(t.active, 2, 17) - 2; - recover = clamp_val(t.recover, 1, 16) - 1; - setup = clamp_val(t.setup, 1, 4) - 1; - - /* Select the right timing bank for write timing */ - rc = ioread8(ap->ioaddr.lbal_addr); - rc &= 0x7F; - rc |= (adev->devno << 7); - iowrite8(rc, ap->ioaddr.lbal_addr); - - /* Write the timings */ - iowrite8(active << 4 | recover, ap->ioaddr.error_addr); - - /* Select the right bank for read timings, also - load the shared timings for address */ - rc = ioread8(ap->ioaddr.device_addr); - rc &= 0xC0; - rc |= adev->devno; /* Index select */ - rc |= (setup << 4) | 0x04; - iowrite8(rc, ap->ioaddr.device_addr); - - /* Load the read timings */ - iowrite8(active << 4 | recover, ap->ioaddr.data_addr); - - /* Ensure the timing register mode is right */ - rc = ioread8(ap->ioaddr.lbal_addr); - rc &= 0x73; - rc |= 0x84; - iowrite8(rc, ap->ioaddr.lbal_addr); - - /* Exit command mode */ - iowrite8(0x83, ap->ioaddr.nsect_addr); -} - - -static struct ata_port_operations opti82c611a_port_ops = { - .inherits = &legacy_base_port_ops, - .set_piomode = opti82c611a_set_piomode, -}; - -/* - * Opti 82C465MV - * - * This controller supports PIO0 to PIO3. Unlike the 611A the MVB - * version is dual channel but doesn't have a lot of unique registers. - */ - -static void opti82c46x_set_piomode(struct ata_port *ap, struct ata_device *adev) -{ - u8 active, recover, setup; - struct ata_timing t; - struct ata_device *pair = ata_dev_pair(adev); - int clock; - int khz[4] = { 50000, 40000, 33000, 25000 }; - u8 rc; - u8 sysclk; - - /* Get the clock */ - sysclk = (opti_syscfg(0xAC) & 0xC0) >> 6; /* BIOS set */ - - /* Enter configuration mode */ - ioread16(ap->ioaddr.error_addr); - ioread16(ap->ioaddr.error_addr); - iowrite8(3, ap->ioaddr.nsect_addr); - - /* Read VLB clock strapping */ - clock = 1000000000 / khz[sysclk]; - - /* Get the timing data in cycles */ - ata_timing_compute(adev, adev->pio_mode, &t, clock, 1000); - - /* Setup timing is shared */ - if (pair) { - struct ata_timing tp; - ata_timing_compute(pair, pair->pio_mode, &tp, clock, 1000); - - ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP); - } - - active = clamp_val(t.active, 2, 17) - 2; - recover = clamp_val(t.recover, 1, 16) - 1; - setup = clamp_val(t.setup, 1, 4) - 1; - - /* Select the right timing bank for write timing */ - rc = ioread8(ap->ioaddr.lbal_addr); - rc &= 0x7F; - rc |= (adev->devno << 7); - iowrite8(rc, ap->ioaddr.lbal_addr); - - /* Write the timings */ - iowrite8(active << 4 | recover, ap->ioaddr.error_addr); - - /* Select the right bank for read timings, also - load the shared timings for address */ - rc = ioread8(ap->ioaddr.device_addr); - rc &= 0xC0; - rc |= adev->devno; /* Index select */ - rc |= (setup << 4) | 0x04; - iowrite8(rc, ap->ioaddr.device_addr); - - /* Load the read timings */ - iowrite8(active << 4 | recover, ap->ioaddr.data_addr); - - /* Ensure the timing register mode is right */ - rc = ioread8(ap->ioaddr.lbal_addr); - rc &= 0x73; - rc |= 0x84; - iowrite8(rc, ap->ioaddr.lbal_addr); - - /* Exit command mode */ - iowrite8(0x83, ap->ioaddr.nsect_addr); - - /* We need to know this for quad device on the MVB */ - ap->host->private_data = ap; -} - -/** - * opti82c46x_qc_issue - command issue - * @qc: command pending - * - * Called when the libata layer is about to issue a command. We wrap - * this interface so that we can load the correct ATA timings. The - * MVB has a single set of timing registers and these are shared - * across channels. As there are two registers we really ought to - * track the last two used values as a sort of register window. For - * now we just reload on a channel switch. On the single channel - * setup this condition never fires so we do nothing extra. - * - * FIXME: dual channel needs ->serialize support - */ - -static unsigned int opti82c46x_qc_issue(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - struct ata_device *adev = qc->dev; - - /* If timings are set and for the wrong channel (2nd test is - due to a libata shortcoming and will eventually go I hope) */ - if (ap->host->private_data != ap->host - && ap->host->private_data != NULL) - opti82c46x_set_piomode(ap, adev); - - return ata_sff_qc_issue(qc); -} - -static struct ata_port_operations opti82c46x_port_ops = { - .inherits = &legacy_base_port_ops, - .set_piomode = opti82c46x_set_piomode, - .qc_issue = opti82c46x_qc_issue, -}; - -/** - * qdi65x0_set_piomode - PIO setup for QDI65x0 - * @ap: Port - * @adev: Device - * - * In single channel mode the 6580 has one clock per device and we can - * avoid the requirement to clock switch. We also have to load the timing - * into the right clock according to whether we are master or slave. - * - * In dual channel mode the 6580 has one clock per channel and we have - * to software clockswitch in qc_issue. - */ - -static void qdi65x0_set_piomode(struct ata_port *ap, struct ata_device *adev) -{ - struct ata_timing t; - struct legacy_data *ld_qdi = ap->host->private_data; - int active, recovery; - u8 timing; - - /* Get the timing data in cycles */ - ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); - - if (ld_qdi->fast) { - active = 8 - clamp_val(t.active, 1, 8); - recovery = 18 - clamp_val(t.recover, 3, 18); - } else { - active = 9 - clamp_val(t.active, 2, 9); - recovery = 15 - clamp_val(t.recover, 0, 15); - } - timing = (recovery << 4) | active | 0x08; - ld_qdi->clock[adev->devno] = timing; - - if (ld_qdi->type == QDI6580) - outb(timing, ld_qdi->timing + 2 * adev->devno); - else - outb(timing, ld_qdi->timing + 2 * ap->port_no); - - /* Clear the FIFO */ - if (ld_qdi->type != QDI6500 && adev->class != ATA_DEV_ATA) - outb(0x5F, (ld_qdi->timing & 0xFFF0) + 3); -} - -/** - * qdi_qc_issue - command issue - * @qc: command pending - * - * Called when the libata layer is about to issue a command. We wrap - * this interface so that we can load the correct ATA timings. - */ - -static unsigned int qdi_qc_issue(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - struct ata_device *adev = qc->dev; - struct legacy_data *ld_qdi = ap->host->private_data; - - if (ld_qdi->clock[adev->devno] != ld_qdi->last) { - if (adev->pio_mode) { - ld_qdi->last = ld_qdi->clock[adev->devno]; - outb(ld_qdi->clock[adev->devno], ld_qdi->timing + - 2 * ap->port_no); - } - } - return ata_sff_qc_issue(qc); -} - -static unsigned int vlb32_data_xfer(struct ata_queued_cmd *qc, - unsigned char *buf, - unsigned int buflen, int rw) -{ - struct ata_device *adev = qc->dev; - struct ata_port *ap = adev->link->ap; - int slop = buflen & 3; - - if (ata_id_has_dword_io(adev->id) && (slop == 0 || slop == 3) - && (ap->pflags & ATA_PFLAG_PIO32)) { - if (rw == WRITE) - iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); - else - ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); - - if (unlikely(slop)) { - __le32 pad = 0; - - if (rw == WRITE) { - memcpy(&pad, buf + buflen - slop, slop); - iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr); - } else { - pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr)); - memcpy(buf + buflen - slop, &pad, slop); - } - } - return (buflen + 3) & ~3; - } else - return ata_sff_data_xfer(qc, buf, buflen, rw); -} - -static int qdi_port(struct platform_device *dev, - struct legacy_probe *lp, struct legacy_data *ld) -{ - if (devm_request_region(&dev->dev, lp->private, 4, "qdi") == NULL) - return -EBUSY; - ld->timing = lp->private; - return 0; -} - -static struct ata_port_operations qdi6500_port_ops = { - .inherits = &legacy_base_port_ops, - .set_piomode = qdi65x0_set_piomode, - .qc_issue = qdi_qc_issue, - .sff_data_xfer = vlb32_data_xfer, -}; - -static struct ata_port_operations qdi6580_port_ops = { - .inherits = &legacy_base_port_ops, - .set_piomode = qdi65x0_set_piomode, - .sff_data_xfer = vlb32_data_xfer, -}; - -static struct ata_port_operations qdi6580dp_port_ops = { - .inherits = &legacy_base_port_ops, - .set_piomode = qdi65x0_set_piomode, - .qc_issue = qdi_qc_issue, - .sff_data_xfer = vlb32_data_xfer, -}; - -static DEFINE_SPINLOCK(winbond_lock); - -static void winbond_writecfg(unsigned long port, u8 reg, u8 val) -{ - unsigned long flags; - spin_lock_irqsave(&winbond_lock, flags); - outb(reg, port + 0x01); - outb(val, port + 0x02); - spin_unlock_irqrestore(&winbond_lock, flags); -} - -static u8 winbond_readcfg(unsigned long port, u8 reg) -{ - u8 val; - - unsigned long flags; - spin_lock_irqsave(&winbond_lock, flags); - outb(reg, port + 0x01); - val = inb(port + 0x02); - spin_unlock_irqrestore(&winbond_lock, flags); - - return val; -} - -static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev) -{ - struct ata_timing t; - struct legacy_data *ld_winbond = ap->host->private_data; - int active, recovery; - u8 reg; - int timing = 0x88 + (ap->port_no * 4) + (adev->devno * 2); - - reg = winbond_readcfg(ld_winbond->timing, 0x81); - - /* Get the timing data in cycles */ - if (reg & 0x40) /* Fast VLB bus, assume 50MHz */ - ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000); - else - ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); - - active = (clamp_val(t.active, 3, 17) - 1) & 0x0F; - recovery = (clamp_val(t.recover, 1, 15) + 1) & 0x0F; - timing = (active << 4) | recovery; - winbond_writecfg(ld_winbond->timing, timing, reg); - - /* Load the setup timing */ - - reg = 0x35; - if (adev->class != ATA_DEV_ATA) - reg |= 0x08; /* FIFO off */ - if (!ata_pio_need_iordy(adev)) - reg |= 0x02; /* IORDY off */ - reg |= (clamp_val(t.setup, 0, 3) << 6); - winbond_writecfg(ld_winbond->timing, timing + 1, reg); -} - -static int winbond_port(struct platform_device *dev, - struct legacy_probe *lp, struct legacy_data *ld) -{ - if (devm_request_region(&dev->dev, lp->private, 4, "winbond") == NULL) - return -EBUSY; - ld->timing = lp->private; - return 0; -} - -static struct ata_port_operations winbond_port_ops = { - .inherits = &legacy_base_port_ops, - .set_piomode = winbond_set_piomode, - .sff_data_xfer = vlb32_data_xfer, -}; - static struct legacy_controller controllers[] = { {"BIOS", &legacy_port_ops, ATA_PIO4, ATA_FLAG_NO_IORDY, 0, NULL }, {"Snooping", &simple_port_ops, ATA_PIO4, 0, 0, NULL }, - {"PDC20230", &pdc20230_port_ops, ATA_PIO2, - ATA_FLAG_NO_IORDY, - ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, NULL }, - {"HT6560A", &ht6560a_port_ops, ATA_PIO2, - ATA_FLAG_NO_IORDY, 0, NULL }, - {"HT6560B", &ht6560b_port_ops, ATA_PIO4, - ATA_FLAG_NO_IORDY, 0, NULL }, - {"OPTI82C611A", &opti82c611a_port_ops, ATA_PIO3, - 0, 0, NULL }, - {"OPTI82C46X", &opti82c46x_port_ops, ATA_PIO3, - 0, 0, NULL }, - {"QDI6500", &qdi6500_port_ops, ATA_PIO2, - ATA_FLAG_NO_IORDY, - ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, qdi_port }, - {"QDI6580", &qdi6580_port_ops, ATA_PIO4, - 0, ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, qdi_port }, - {"QDI6580DP", &qdi6580dp_port_ops, ATA_PIO4, - 0, ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, qdi_port }, - {"W83759A", &winbond_port_ops, ATA_PIO4, - 0, ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE, - winbond_port } }; /** @@ -897,62 +216,6 @@ static __init int probe_chip_type(struct legacy_probe *probe) { int mask = 1 << probe->slot; - if (winbond && (probe->port == 0x1F0 || probe->port == 0x170)) { - u8 reg = winbond_readcfg(winbond, 0x81); - reg |= 0x80; /* jumpered mode off */ - winbond_writecfg(winbond, 0x81, reg); - reg = winbond_readcfg(winbond, 0x83); - reg |= 0xF0; /* local control */ - winbond_writecfg(winbond, 0x83, reg); - reg = winbond_readcfg(winbond, 0x85); - reg |= 0xF0; /* programmable timing */ - winbond_writecfg(winbond, 0x85, reg); - - reg = winbond_readcfg(winbond, 0x81); - - if (reg & mask) - return W83759A; - } - if (probe->port == 0x1F0) { - unsigned long flags; - local_irq_save(flags); - /* Probes */ - outb(inb(0x1F2) | 0x80, 0x1F2); - inb(0x1F5); - inb(0x1F2); - inb(0x3F6); - inb(0x3F6); - inb(0x1F2); - inb(0x1F2); - - if ((inb(0x1F2) & 0x80) == 0) { - /* PDC20230c or 20630 ? */ - printk(KERN_INFO "PDC20230-C/20630 VLB ATA controller" - " detected.\n"); - udelay(100); - inb(0x1F5); - local_irq_restore(flags); - return PDC20230; - } else { - outb(0x55, 0x1F2); - inb(0x1F2); - inb(0x1F2); - if (inb(0x1F2) == 0x00) - printk(KERN_INFO "PDC20230-B VLB ATA " - "controller detected.\n"); - local_irq_restore(flags); - return BIOS; - } - } - - if (ht6560a & mask) - return HT6560A; - if (ht6560b & mask) - return HT6560B; - if (opti82c611a & mask) - return OPTI611A; - if (opti82c46x & mask) - return OPTI46X; if (autospeed & mask) return SNOOP; return BIOS; @@ -1085,123 +348,13 @@ static void __init legacy_check_special_cases(struct pci_dev *p, int *primary, } } -static __init void probe_opti_vlb(void) -{ - /* If an OPTI 82C46X is present find out where the channels are */ - static const char *optis[4] = { - "3/463MV", "5MV", - "5MVA", "5MVB" - }; - u8 chans = 1; - u8 ctrl = (opti_syscfg(0x30) & 0xC0) >> 6; - - opti82c46x = 3; /* Assume master and slave first */ - printk(KERN_INFO DRV_NAME ": Opti 82C46%s chipset support.\n", - optis[ctrl]); - if (ctrl == 3) - chans = (opti_syscfg(0x3F) & 0x20) ? 2 : 1; - ctrl = opti_syscfg(0xAC); - /* Check enabled and this port is the 465MV port. On the - MVB we may have two channels */ - if (ctrl & 8) { - if (chans == 2) { - legacy_probe_add(0x1F0, 14, OPTI46X, 0); - legacy_probe_add(0x170, 15, OPTI46X, 0); - } - if (ctrl & 4) - legacy_probe_add(0x170, 15, OPTI46X, 0); - else - legacy_probe_add(0x1F0, 14, OPTI46X, 0); - } else - legacy_probe_add(0x1F0, 14, OPTI46X, 0); -} - -static __init void qdi65_identify_port(u8 r, u8 res, unsigned long port) -{ - static const unsigned long ide_port[2] = { 0x170, 0x1F0 }; - /* Check card type */ - if ((r & 0xF0) == 0xC0) { - /* QD6500: single channel */ - if (r & 8) - /* Disabled ? */ - return; - legacy_probe_add(ide_port[r & 0x01], 14 + (r & 0x01), - QDI6500, port); - } - if (((r & 0xF0) == 0xA0) || (r & 0xF0) == 0x50) { - /* QD6580: dual channel */ - if (!request_region(port + 2 , 2, "pata_qdi")) { - release_region(port, 2); - return; - } - res = inb(port + 3); - /* Single channel mode ? */ - if (res & 1) - legacy_probe_add(ide_port[r & 0x01], 14 + (r & 0x01), - QDI6580, port); - else { /* Dual channel mode */ - legacy_probe_add(0x1F0, 14, QDI6580DP, port); - /* port + 0x02, r & 0x04 */ - legacy_probe_add(0x170, 15, QDI6580DP, port + 2); - } - release_region(port + 2, 2); - } -} - -static __init void probe_qdi_vlb(void) -{ - unsigned long flags; - static const unsigned long qd_port[2] = { 0x30, 0xB0 }; - int i; - - /* - * Check each possible QD65xx base address - */ - - for (i = 0; i < 2; i++) { - unsigned long port = qd_port[i]; - u8 r, res; - - - if (request_region(port, 2, "pata_qdi")) { - /* Check for a card */ - local_irq_save(flags); - /* I have no h/w that needs this delay but it - is present in the historic code */ - r = inb(port); - udelay(1); - outb(0x19, port); - udelay(1); - res = inb(port); - udelay(1); - outb(r, port); - udelay(1); - local_irq_restore(flags); - - /* Fail */ - if (res == 0x19) { - release_region(port, 2); - continue; - } - /* Passes the presence test */ - r = inb(port + 1); - udelay(1); - /* Check port agrees with port set */ - if ((r & 2) >> 1 == i) - qdi65_identify_port(r, res, port); - release_region(port, 2); - } - } -} - /** * legacy_init - attach legacy interfaces * * Attach legacy IDE interfaces by scanning the usual IRQ/port suspects. * Right now we do not scan the ide0 and ide1 address but should do so * for non PCI systems or systems with no PCI IDE legacy mode devices. - * If you fix that note there are special cases to consider like VLB - * drivers and CS5510/20. + * If you fix that note there are special cases to consider like CS5510/20. */ static __init int legacy_init(void) @@ -1235,27 +388,19 @@ static __init int legacy_init(void) pci_present = 1; } - if (winbond == 1) - winbond = 0x130; /* Default port, alt is 1B0 */ - if (primary == 0 || all) legacy_probe_add(0x1F0, 14, UNKNOWN, 0); if (secondary == 0 || all) legacy_probe_add(0x170, 15, UNKNOWN, 0); if (probe_all || !pci_present) { - /* ISA/VLB extra ports */ + /* ISA extra ports */ legacy_probe_add(0x1E8, 11, UNKNOWN, 0); legacy_probe_add(0x168, 10, UNKNOWN, 0); legacy_probe_add(0x1E0, 8, UNKNOWN, 0); legacy_probe_add(0x160, 12, UNKNOWN, 0); } - if (opti82c46x) - probe_opti_vlb(); - if (qdi) - probe_qdi_vlb(); - for (i = 0; i < NR_HOST; i++, pl++) { if (pl->port == 0) continue; @@ -1287,8 +432,6 @@ MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("low-level driver for legacy ATA"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); -MODULE_ALIAS("pata_qdi"); -MODULE_ALIAS("pata_winbond"); module_init(legacy_init); module_exit(legacy_exit); -- cgit v1.2.3 From 82ef60ec084b2ea418c50fca2c8776fb8ec27067 Mon Sep 17 00:00:00 2001 From: Ethan Nelson-Moore Date: Fri, 30 Jan 2026 19:28:11 -0800 Subject: ata: pata_cypress: fix typo in error message An error message in the pata_cypress driver has a typo "mome" for "mode". Fix it. Signed-off-by: Ethan Nelson-Moore Signed-off-by: Damien Le Moal --- drivers/ata/pata_cypress.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index ae347b5c2871..3b0e6858d727 100644 --- a/drivers/ata/pata_cypress.c +++ b/drivers/ata/pata_cypress.c @@ -62,7 +62,7 @@ static void cy82c693_set_piomode(struct ata_port *ap, struct ata_device *adev) u32 addr; if (ata_timing_compute(adev, adev->pio_mode, &t, T, 1) < 0) { - ata_dev_err(adev, DRV_NAME ": mome computation failed.\n"); + ata_dev_err(adev, DRV_NAME ": mode computation failed.\n"); return; } -- cgit v1.2.3 From ff4a46c278ac6a4b3f39be1492a4568b6dcc6105 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 3 Feb 2026 11:23:01 +0100 Subject: ata: pata_ftide010: Fix some DMA timings The FTIDE010 has been missing some timing settings since its inception, since the upstream OpenWrt patch was missing these. The community has since come up with the appropriate timings. Fixes: be4e456ed3a5 ("ata: Add driver for Faraday Technology FTIDE010") Cc: stable@vger.kernel.org Signed-off-by: Linus Walleij Signed-off-by: Niklas Cassel --- drivers/ata/pata_ftide010.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/ata/pata_ftide010.c b/drivers/ata/pata_ftide010.c index c3a8384c3e04..c41da296eb38 100644 --- a/drivers/ata/pata_ftide010.c +++ b/drivers/ata/pata_ftide010.c @@ -122,10 +122,10 @@ static const u8 mwdma_50_active_time[3] = {6, 2, 2}; static const u8 mwdma_50_recovery_time[3] = {6, 2, 1}; static const u8 mwdma_66_active_time[3] = {8, 3, 3}; static const u8 mwdma_66_recovery_time[3] = {8, 2, 1}; -static const u8 udma_50_setup_time[6] = {3, 3, 2, 2, 1, 1}; +static const u8 udma_50_setup_time[6] = {3, 3, 2, 2, 1, 9}; static const u8 udma_50_hold_time[6] = {3, 1, 1, 1, 1, 1}; -static const u8 udma_66_setup_time[7] = {4, 4, 3, 2, }; -static const u8 udma_66_hold_time[7] = {}; +static const u8 udma_66_setup_time[7] = {4, 4, 3, 2, 1, 9, 9}; +static const u8 udma_66_hold_time[7] = {4, 2, 1, 1, 1, 1, 1}; /* * We set 66 MHz for all MWDMA modes -- cgit v1.2.3