Skip to content

Commit 84d7652

Browse files
committed
ata: libata-core: Fix port and device removal
Whenever an ATA adapter driver is removed (e.g. rmmod), ata_port_detach() is called repeatedly for all the adapter ports to remove (unload) the devices attached to the port and delete the port device itself. Removing of devices is done using libata EH with the ATA_PFLAG_UNLOADING port flag set. This causes libata EH to execute ata_eh_unload() which disables all devices attached to the port. ata_port_detach() finishes by calling scsi_remove_host() to remove the scsi host associated with the port. This function will trigger the removal of all scsi devices attached to the host and in the case of disks, calls to sd_shutdown() which will flush the device write cache and stop the device. However, given that the devices were already disabled by ata_eh_unload(), the synchronize write cache command and start stop unit commands fail. E.g. running "rmmod ahci" with first removing sd_mod results in error messages like: ata13.00: disable device sd 0:0:0:0: [sda] Synchronizing SCSI cache sd 0:0:0:0: [sda] Synchronize Cache(10) failed: Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK sd 0:0:0:0: [sda] Stopping disk sd 0:0:0:0: [sda] Start/Stop Unit failed: Result: hostbyte=DID_BAD_TARGET driverbyte=DRIVER_OK Fix this by removing all scsi devices of the ata devices connected to the port before scheduling libata EH to disable the ATA devices. Fixes: 720ba12 ("[PATCH] libata-hp: update unload-unplug") Cc: stable@vger.kernel.org Signed-off-by: Damien Le Moal <dlemoal@kernel.org> Reviewed-by: Hannes Reinecke <hare@suse.de> Reviewed-by: Niklas Cassel <niklas.cassel@wdc.com> Tested-by: Chia-Lin Kao (AceLan) <acelan.kao@canonical.com> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be> Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent 3b8e0af commit 84d7652

File tree

1 file changed

+20
-1
lines changed

1 file changed

+20
-1
lines changed

drivers/ata/libata-core.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5948,11 +5948,30 @@ static void ata_port_detach(struct ata_port *ap)
59485948
struct ata_link *link;
59495949
struct ata_device *dev;
59505950

5951-
/* tell EH we're leaving & flush EH */
5951+
/* Wait for any ongoing EH */
5952+
ata_port_wait_eh(ap);
5953+
5954+
mutex_lock(&ap->scsi_scan_mutex);
59525955
spin_lock_irqsave(ap->lock, flags);
5956+
5957+
/* Remove scsi devices */
5958+
ata_for_each_link(link, ap, HOST_FIRST) {
5959+
ata_for_each_dev(dev, link, ALL) {
5960+
if (dev->sdev) {
5961+
spin_unlock_irqrestore(ap->lock, flags);
5962+
scsi_remove_device(dev->sdev);
5963+
spin_lock_irqsave(ap->lock, flags);
5964+
dev->sdev = NULL;
5965+
}
5966+
}
5967+
}
5968+
5969+
/* Tell EH to disable all devices */
59535970
ap->pflags |= ATA_PFLAG_UNLOADING;
59545971
ata_port_schedule_eh(ap);
5972+
59555973
spin_unlock_irqrestore(ap->lock, flags);
5974+
mutex_unlock(&ap->scsi_scan_mutex);
59565975

59575976
/* wait till EH commits suicide */
59585977
ata_port_wait_eh(ap);

0 commit comments

Comments
 (0)