From: Shao Mingyin A Gemini ATA port can start successfully when only one of its SATA bridges comes online. gemini_sata_start_bridge() disables the clock of a failed bridge, but port_stop later stops every mapped bridge, including the failed one. A missing disk on one bridge can thus cause an unbalanced clk_disable() warning when the port is removed. Record which bridges start successfully and stop only those bridges. Clear the bitmap after stopping them so a later start begins with no bridges marked active. Fixes: be4e456ed3a5 ("ata: Add driver for Faraday Technology FTIDE010") Reported-by: Sashiko Link: https://lore.kernel.org/all/20260626091006.5A2C11F00A3A@smtp.kernel.org/ Signed-off-by: Shao Mingyin --- Tested on 7.4.0-rc1-next-20261105 under QEMU/KVM (x86_64, 2 vCPUs), with lockdep and KASAN. Both kernels carry the same TEST-ONLY harness using synthetic ATA hosts, RAM-backed bridge registers and clock providers. The original port and bridge callbacks run through libata and the real common clock framework; only this fix differs. Each kernel completes 24 start/stop cycles covering both partial-failure directions, both bridges ready, neither ready, single-bridge controls and repeated starts with the same private state. The unpatched kernel reports six CCF "already disabled" warnings; the patched kernel reports none. Both retain 16 successful starts, eight -EINVAL returns and zero clock enables left over. The patched guest shuts down without lockdep or KASAN reports. Real Gemini probe, PHY hardware, disk I/O, DMA allocation failure and full device unbind were not exercised. drivers/ata/pata_ftide010.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/ata/pata_ftide010.c b/drivers/ata/pata_ftide010.c index c41da296eb..ca683fd96f 100644 --- a/drivers/ata/pata_ftide010.c +++ b/drivers/ata/pata_ftide010.c @@ -29,6 +29,7 @@ * @master_cbl: master cable type * @slave_cbl: slave cable type * @sg: Gemini SATA bridge pointer, if running on the Gemini + * @sata_bridge_mask: bitmap of Gemini SATA bridges successfully started * @master_to_sata0: Gemini SATA bridge: the ATA master is connected * to the SATA0 bridge * @slave_to_sata0: Gemini SATA bridge: the ATA slave is connected @@ -47,6 +48,7 @@ struct ftide010 { unsigned int slave_cbl; /* Gemini-specific properties */ struct sata_gemini *sg; + unsigned int sata_bridge_mask; bool master_to_sata0; bool slave_to_sata0; bool master_to_sata1; @@ -281,28 +283,36 @@ static int pata_ftide010_gemini_port_start(struct ata_port *ap) if (ftide->master_to_sata0) { dev_info(dev, "SATA0 (master) start\n"); ret = gemini_sata_start_bridge(sg, 0); - if (!ret) + if (!ret) { + ftide->sata_bridge_mask |= BIT(0); bridges++; + } } if (ftide->master_to_sata1) { dev_info(dev, "SATA1 (master) start\n"); ret = gemini_sata_start_bridge(sg, 1); - if (!ret) + if (!ret) { + ftide->sata_bridge_mask |= BIT(1); bridges++; + } } /* Avoid double-starting */ if (ftide->slave_to_sata0 && !ftide->master_to_sata0) { dev_info(dev, "SATA0 (slave) start\n"); ret = gemini_sata_start_bridge(sg, 0); - if (!ret) + if (!ret) { + ftide->sata_bridge_mask |= BIT(0); bridges++; + } } /* Avoid double-starting */ if (ftide->slave_to_sata1 && !ftide->master_to_sata1) { dev_info(dev, "SATA1 (slave) start\n"); ret = gemini_sata_start_bridge(sg, 1); - if (!ret) + if (!ret) { + ftide->sata_bridge_mask |= BIT(1); bridges++; + } } dev_info(dev, "brought %d bridges online\n", bridges); @@ -315,24 +325,15 @@ static void pata_ftide010_gemini_port_stop(struct ata_port *ap) struct device *dev = ftide->dev; struct sata_gemini *sg = ftide->sg; - if (ftide->master_to_sata0) { - dev_info(dev, "SATA0 (master) stop\n"); - gemini_sata_stop_bridge(sg, 0); - } - if (ftide->master_to_sata1) { - dev_info(dev, "SATA1 (master) stop\n"); - gemini_sata_stop_bridge(sg, 1); - } - /* Avoid double-stopping */ - if (ftide->slave_to_sata0 && !ftide->master_to_sata0) { - dev_info(dev, "SATA0 (slave) stop\n"); + if (ftide->sata_bridge_mask & BIT(0)) { + dev_info(dev, "SATA0 stop\n"); gemini_sata_stop_bridge(sg, 0); } - /* Avoid double-stopping */ - if (ftide->slave_to_sata1 && !ftide->master_to_sata1) { - dev_info(dev, "SATA1 (slave) stop\n"); + if (ftide->sata_bridge_mask & BIT(1)) { + dev_info(dev, "SATA1 stop\n"); gemini_sata_stop_bridge(sg, 1); } + ftide->sata_bridge_mask = 0; } static int pata_ftide010_gemini_cable_detect(struct ata_port *ap) -- 2.27.0