Skip to content

Commit fb99ef1

Browse files
committed
ata: libata-scsi: link ata port and scsi device
There is no direct device ancestry defined between an ata_device and its scsi device which prevents the power management code from correctly ordering suspend and resume operations. Create such ancestry with the ata device as the parent to ensure that the scsi device (child) is suspended before the ata device and that resume handles the ata device before the scsi device. The parent-child (supplier-consumer) relationship is established between the ata_port (parent) and the scsi device (child) with the function device_add_link(). The parent used is not the ata_device as the PM operations are defined per port and the status of all devices connected through that port is controlled from the port operations. The device link is established with the new function ata_scsi_slave_alloc(), and this function is used to define the ->slave_alloc callback of the scsi host template of all ata drivers. Fixes: a19a93e ("scsi: core: pm: Rely on the device driver core for async power management") 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: Geert Uytterhoeven <geert+renesas@glider.be> Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com> Reviewed-by: John Garry <john.g.garry@oracle.com>
1 parent 84d7652 commit fb99ef1

File tree

2 files changed

+42
-5
lines changed

2 files changed

+42
-5
lines changed

drivers/ata/libata-scsi.c

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,6 +1089,42 @@ int ata_scsi_dev_config(struct scsi_device *sdev, struct ata_device *dev)
10891089
return 0;
10901090
}
10911091

1092+
/**
1093+
* ata_scsi_slave_alloc - Early setup of SCSI device
1094+
* @sdev: SCSI device to examine
1095+
*
1096+
* This is called from scsi_alloc_sdev() when the scsi device
1097+
* associated with an ATA device is scanned on a port.
1098+
*
1099+
* LOCKING:
1100+
* Defined by SCSI layer. We don't really care.
1101+
*/
1102+
1103+
int ata_scsi_slave_alloc(struct scsi_device *sdev)
1104+
{
1105+
struct ata_port *ap = ata_shost_to_port(sdev->host);
1106+
struct device_link *link;
1107+
1108+
ata_scsi_sdev_config(sdev);
1109+
1110+
/*
1111+
* Create a link from the ata_port device to the scsi device to ensure
1112+
* that PM does suspend/resume in the correct order: the scsi device is
1113+
* consumer (child) and the ata port the supplier (parent).
1114+
*/
1115+
link = device_link_add(&sdev->sdev_gendev, &ap->tdev,
1116+
DL_FLAG_STATELESS |
1117+
DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
1118+
if (!link) {
1119+
ata_port_err(ap, "Failed to create link to scsi device %s\n",
1120+
dev_name(&sdev->sdev_gendev));
1121+
return -ENODEV;
1122+
}
1123+
1124+
return 0;
1125+
}
1126+
EXPORT_SYMBOL_GPL(ata_scsi_slave_alloc);
1127+
10921128
/**
10931129
* ata_scsi_slave_config - Set SCSI device attributes
10941130
* @sdev: SCSI device to examine
@@ -1105,14 +1141,11 @@ int ata_scsi_slave_config(struct scsi_device *sdev)
11051141
{
11061142
struct ata_port *ap = ata_shost_to_port(sdev->host);
11071143
struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
1108-
int rc = 0;
1109-
1110-
ata_scsi_sdev_config(sdev);
11111144

11121145
if (dev)
1113-
rc = ata_scsi_dev_config(sdev, dev);
1146+
return ata_scsi_dev_config(sdev, dev);
11141147

1115-
return rc;
1148+
return 0;
11161149
}
11171150
EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
11181151

@@ -1136,6 +1169,8 @@ void ata_scsi_slave_destroy(struct scsi_device *sdev)
11361169
unsigned long flags;
11371170
struct ata_device *dev;
11381171

1172+
device_link_remove(&sdev->sdev_gendev, &ap->tdev);
1173+
11391174
spin_lock_irqsave(ap->lock, flags);
11401175
dev = __ata_scsi_find_dev(ap, sdev);
11411176
if (dev && dev->sdev) {

include/linux/libata.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,7 @@ extern int ata_std_bios_param(struct scsi_device *sdev,
11481148
struct block_device *bdev,
11491149
sector_t capacity, int geom[]);
11501150
extern void ata_scsi_unlock_native_capacity(struct scsi_device *sdev);
1151+
extern int ata_scsi_slave_alloc(struct scsi_device *sdev);
11511152
extern int ata_scsi_slave_config(struct scsi_device *sdev);
11521153
extern void ata_scsi_slave_destroy(struct scsi_device *sdev);
11531154
extern int ata_scsi_change_queue_depth(struct scsi_device *sdev,
@@ -1396,6 +1397,7 @@ extern const struct attribute_group *ata_common_sdev_groups[];
13961397
.this_id = ATA_SHT_THIS_ID, \
13971398
.emulated = ATA_SHT_EMULATED, \
13981399
.proc_name = drv_name, \
1400+
.slave_alloc = ata_scsi_slave_alloc, \
13991401
.slave_destroy = ata_scsi_slave_destroy, \
14001402
.bios_param = ata_std_bios_param, \
14011403
.unlock_native_capacity = ata_scsi_unlock_native_capacity,\

0 commit comments

Comments
 (0)