mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
[SCSI] libsas, libata: fix start of life for a sas ata_port
This changes the ordering of initialization and probing events from: 1/ allocate rphy in PORTE_BYTES_DMAED, DISCE_REVALIDATE_DOMAIN 2/ allocate ata_port and schedule port probe in DISCE_PROBE ...to: 1/ allocate ata_port in PORTE_BYTES_DMAED, DISCE_REVALIDATE_DOMAIN 2/ allocate rphy in PORTE_BYTES_DMAED, DISCE_REVALIDATE_DOMAIN 3/ schedule port probe in DISCE_PROBE This ordering prevents PHYE_SIGNAL_LOSS_EVENTS from sneaking in to destrory ata devices before they have been fully initialized: BUG: unable to handle kernel paging request at 0000000000003b10 IP: [<ffffffffa0053d7e>] sas_ata_end_eh+0x12/0x5e [libsas] ... [<ffffffffa004d1af>] sas_unregister_common_dev+0x78/0xc9 [libsas] [<ffffffffa004d4d4>] sas_unregister_dev+0x4f/0xad [libsas] [<ffffffffa004d5b1>] sas_unregister_domain_devices+0x7f/0xbf [libsas] [<ffffffffa004c487>] sas_deform_port+0x61/0x1b8 [libsas] [<ffffffffa004bed0>] sas_phye_loss_of_signal+0x29/0x2b [libsas] ...and kills the awkward "sata domain_device briefly existing in the domain without an ata_port" state. Reported-by: Michal Kosciowski <michal.kosciowski@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com> Acked-by: Jeff Garzik <jgarzik@redhat.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
parent
0f3fce5cc7
commit
b202445925
7 changed files with 56 additions and 50 deletions
|
@ -3839,18 +3839,25 @@ void ata_sas_port_stop(struct ata_port *ap)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ata_sas_port_stop);
|
EXPORT_SYMBOL_GPL(ata_sas_port_stop);
|
||||||
|
|
||||||
int ata_sas_async_port_init(struct ata_port *ap)
|
/**
|
||||||
|
* ata_sas_async_probe - simply schedule probing and return
|
||||||
|
* @ap: Port to probe
|
||||||
|
*
|
||||||
|
* For batch scheduling of probe for sas attached ata devices, assumes
|
||||||
|
* the port has already been through ata_sas_port_init()
|
||||||
|
*/
|
||||||
|
void ata_sas_async_probe(struct ata_port *ap)
|
||||||
{
|
{
|
||||||
int rc = ap->ops->port_start(ap);
|
__ata_port_probe(ap);
|
||||||
|
|
||||||
if (!rc) {
|
|
||||||
ap->print_id = atomic_inc_return(&ata_print_id);
|
|
||||||
__ata_port_probe(ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ata_sas_async_port_init);
|
EXPORT_SYMBOL_GPL(ata_sas_async_probe);
|
||||||
|
|
||||||
|
int ata_sas_sync_probe(struct ata_port *ap)
|
||||||
|
{
|
||||||
|
return ata_port_probe(ap);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(ata_sas_sync_probe);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ata_sas_port_init - Initialize a SATA device
|
* ata_sas_port_init - Initialize a SATA device
|
||||||
|
@ -3867,12 +3874,10 @@ int ata_sas_port_init(struct ata_port *ap)
|
||||||
{
|
{
|
||||||
int rc = ap->ops->port_start(ap);
|
int rc = ap->ops->port_start(ap);
|
||||||
|
|
||||||
if (!rc) {
|
if (rc)
|
||||||
ap->print_id = atomic_inc_return(&ata_print_id);
|
return rc;
|
||||||
rc = ata_port_probe(ap);
|
ap->print_id = atomic_inc_return(&ata_print_id);
|
||||||
}
|
return 0;
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ata_sas_port_init);
|
EXPORT_SYMBOL_GPL(ata_sas_port_init);
|
||||||
|
|
||||||
|
|
|
@ -4549,8 +4549,12 @@ static int ipr_ata_slave_alloc(struct scsi_device *sdev)
|
||||||
ENTER;
|
ENTER;
|
||||||
if (sdev->sdev_target)
|
if (sdev->sdev_target)
|
||||||
sata_port = sdev->sdev_target->hostdata;
|
sata_port = sdev->sdev_target->hostdata;
|
||||||
if (sata_port)
|
if (sata_port) {
|
||||||
rc = ata_sas_port_init(sata_port->ap);
|
rc = ata_sas_port_init(sata_port->ap);
|
||||||
|
if (rc == 0)
|
||||||
|
rc = ata_sas_sync_probe(sata_port->ap);
|
||||||
|
}
|
||||||
|
|
||||||
if (rc)
|
if (rc)
|
||||||
ipr_slave_destroy(sdev);
|
ipr_slave_destroy(sdev);
|
||||||
|
|
||||||
|
|
|
@ -546,11 +546,12 @@ static struct ata_port_info sata_port_info = {
|
||||||
.port_ops = &sas_sata_ops
|
.port_ops = &sas_sata_ops
|
||||||
};
|
};
|
||||||
|
|
||||||
int sas_ata_init_host_and_port(struct domain_device *found_dev)
|
int sas_ata_init(struct domain_device *found_dev)
|
||||||
{
|
{
|
||||||
struct sas_ha_struct *ha = found_dev->port->ha;
|
struct sas_ha_struct *ha = found_dev->port->ha;
|
||||||
struct Scsi_Host *shost = ha->core.shost;
|
struct Scsi_Host *shost = ha->core.shost;
|
||||||
struct ata_port *ap;
|
struct ata_port *ap;
|
||||||
|
int rc;
|
||||||
|
|
||||||
ata_host_init(&found_dev->sata_dev.ata_host,
|
ata_host_init(&found_dev->sata_dev.ata_host,
|
||||||
ha->dev,
|
ha->dev,
|
||||||
|
@ -567,8 +568,11 @@ int sas_ata_init_host_and_port(struct domain_device *found_dev)
|
||||||
ap->private_data = found_dev;
|
ap->private_data = found_dev;
|
||||||
ap->cbl = ATA_CBL_SATA;
|
ap->cbl = ATA_CBL_SATA;
|
||||||
ap->scsi_host = shost;
|
ap->scsi_host = shost;
|
||||||
/* publish initialized ata port */
|
rc = ata_sas_port_init(ap);
|
||||||
smp_wmb();
|
if (rc) {
|
||||||
|
ata_sas_port_destroy(ap);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
found_dev->sata_dev.ap = ap;
|
found_dev->sata_dev.ap = ap;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -648,18 +652,13 @@ static void sas_get_ata_command_set(struct domain_device *dev)
|
||||||
void sas_probe_sata(struct asd_sas_port *port)
|
void sas_probe_sata(struct asd_sas_port *port)
|
||||||
{
|
{
|
||||||
struct domain_device *dev, *n;
|
struct domain_device *dev, *n;
|
||||||
int err;
|
|
||||||
|
|
||||||
mutex_lock(&port->ha->disco_mutex);
|
mutex_lock(&port->ha->disco_mutex);
|
||||||
list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) {
|
list_for_each_entry(dev, &port->disco_list, disco_list_node) {
|
||||||
if (!dev_is_sata(dev))
|
if (!dev_is_sata(dev))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
err = sas_ata_init_host_and_port(dev);
|
ata_sas_async_probe(dev->sata_dev.ap);
|
||||||
if (err)
|
|
||||||
sas_fail_probe(dev, __func__, err);
|
|
||||||
else
|
|
||||||
ata_sas_async_port_init(dev->sata_dev.ap);
|
|
||||||
}
|
}
|
||||||
mutex_unlock(&port->ha->disco_mutex);
|
mutex_unlock(&port->ha->disco_mutex);
|
||||||
|
|
||||||
|
@ -718,18 +717,6 @@ static void async_sas_ata_eh(void *data, async_cookie_t cookie)
|
||||||
sas_put_device(dev);
|
sas_put_device(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool sas_ata_dev_eh_valid(struct domain_device *dev)
|
|
||||||
{
|
|
||||||
struct ata_port *ap;
|
|
||||||
|
|
||||||
if (!dev_is_sata(dev))
|
|
||||||
return false;
|
|
||||||
ap = dev->sata_dev.ap;
|
|
||||||
/* consume fully initialized ata ports */
|
|
||||||
smp_rmb();
|
|
||||||
return !!ap;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sas_ata_strategy_handler(struct Scsi_Host *shost)
|
void sas_ata_strategy_handler(struct Scsi_Host *shost)
|
||||||
{
|
{
|
||||||
struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
|
struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
|
||||||
|
@ -753,7 +740,7 @@ void sas_ata_strategy_handler(struct Scsi_Host *shost)
|
||||||
|
|
||||||
spin_lock(&port->dev_list_lock);
|
spin_lock(&port->dev_list_lock);
|
||||||
list_for_each_entry(dev, &port->dev_list, dev_list_node) {
|
list_for_each_entry(dev, &port->dev_list, dev_list_node) {
|
||||||
if (!sas_ata_dev_eh_valid(dev))
|
if (!dev_is_sata(dev))
|
||||||
continue;
|
continue;
|
||||||
async_schedule_domain(async_sas_ata_eh, dev, &async);
|
async_schedule_domain(async_sas_ata_eh, dev, &async);
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,7 @@ static int sas_get_port_device(struct asd_sas_port *port)
|
||||||
struct asd_sas_phy *phy;
|
struct asd_sas_phy *phy;
|
||||||
struct sas_rphy *rphy;
|
struct sas_rphy *rphy;
|
||||||
struct domain_device *dev;
|
struct domain_device *dev;
|
||||||
|
int rc = -ENODEV;
|
||||||
|
|
||||||
dev = sas_alloc_device();
|
dev = sas_alloc_device();
|
||||||
if (!dev)
|
if (!dev)
|
||||||
|
@ -110,9 +111,16 @@ static int sas_get_port_device(struct asd_sas_port *port)
|
||||||
|
|
||||||
sas_init_dev(dev);
|
sas_init_dev(dev);
|
||||||
|
|
||||||
|
dev->port = port;
|
||||||
switch (dev->dev_type) {
|
switch (dev->dev_type) {
|
||||||
case SAS_END_DEV:
|
|
||||||
case SATA_DEV:
|
case SATA_DEV:
|
||||||
|
rc = sas_ata_init(dev);
|
||||||
|
if (rc) {
|
||||||
|
rphy = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* fall through */
|
||||||
|
case SAS_END_DEV:
|
||||||
rphy = sas_end_device_alloc(port->port);
|
rphy = sas_end_device_alloc(port->port);
|
||||||
break;
|
break;
|
||||||
case EDGE_DEV:
|
case EDGE_DEV:
|
||||||
|
@ -131,7 +139,7 @@ static int sas_get_port_device(struct asd_sas_port *port)
|
||||||
|
|
||||||
if (!rphy) {
|
if (!rphy) {
|
||||||
sas_put_device(dev);
|
sas_put_device(dev);
|
||||||
return -ENODEV;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
rphy->identify.phy_identifier = phy->phy->identify.phy_identifier;
|
rphy->identify.phy_identifier = phy->phy->identify.phy_identifier;
|
||||||
|
@ -139,7 +147,6 @@ static int sas_get_port_device(struct asd_sas_port *port)
|
||||||
sas_fill_in_rphy(dev, rphy);
|
sas_fill_in_rphy(dev, rphy);
|
||||||
sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr);
|
sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr);
|
||||||
port->port_dev = dev;
|
port->port_dev = dev;
|
||||||
dev->port = port;
|
|
||||||
dev->linkrate = port->linkrate;
|
dev->linkrate = port->linkrate;
|
||||||
dev->min_linkrate = port->linkrate;
|
dev->min_linkrate = port->linkrate;
|
||||||
dev->max_linkrate = port->linkrate;
|
dev->max_linkrate = port->linkrate;
|
||||||
|
|
|
@ -790,11 +790,13 @@ static struct domain_device *sas_ex_discover_end_dev(
|
||||||
if (res)
|
if (res)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
|
||||||
rphy = sas_end_device_alloc(phy->port);
|
|
||||||
if (unlikely(!rphy))
|
|
||||||
goto out_free;
|
|
||||||
|
|
||||||
sas_init_dev(child);
|
sas_init_dev(child);
|
||||||
|
res = sas_ata_init(child);
|
||||||
|
if (res)
|
||||||
|
goto out_free;
|
||||||
|
rphy = sas_end_device_alloc(phy->port);
|
||||||
|
if (!rphy)
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
child->rphy = rphy;
|
child->rphy = rphy;
|
||||||
get_device(&rphy->dev);
|
get_device(&rphy->dev);
|
||||||
|
|
|
@ -996,7 +996,8 @@ extern int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *dev,
|
||||||
extern void ata_sas_port_destroy(struct ata_port *);
|
extern void ata_sas_port_destroy(struct ata_port *);
|
||||||
extern struct ata_port *ata_sas_port_alloc(struct ata_host *,
|
extern struct ata_port *ata_sas_port_alloc(struct ata_host *,
|
||||||
struct ata_port_info *, struct Scsi_Host *);
|
struct ata_port_info *, struct Scsi_Host *);
|
||||||
extern int ata_sas_async_port_init(struct ata_port *);
|
extern void ata_sas_async_probe(struct ata_port *ap);
|
||||||
|
extern int ata_sas_sync_probe(struct ata_port *ap);
|
||||||
extern int ata_sas_port_init(struct ata_port *);
|
extern int ata_sas_port_init(struct ata_port *);
|
||||||
extern int ata_sas_port_start(struct ata_port *ap);
|
extern int ata_sas_port_start(struct ata_port *ap);
|
||||||
extern void ata_sas_port_stop(struct ata_port *ap);
|
extern void ata_sas_port_stop(struct ata_port *ap);
|
||||||
|
|
|
@ -37,7 +37,7 @@ static inline int dev_is_sata(struct domain_device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy);
|
int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy);
|
||||||
int sas_ata_init_host_and_port(struct domain_device *found_dev);
|
int sas_ata_init(struct domain_device *dev);
|
||||||
void sas_ata_task_abort(struct sas_task *task);
|
void sas_ata_task_abort(struct sas_task *task);
|
||||||
void sas_ata_strategy_handler(struct Scsi_Host *shost);
|
void sas_ata_strategy_handler(struct Scsi_Host *shost);
|
||||||
void sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
|
void sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
|
||||||
|
@ -52,7 +52,7 @@ static inline int dev_is_sata(struct domain_device *dev)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
static inline int sas_ata_init_host_and_port(struct domain_device *found_dev)
|
static inline int sas_ata_init(struct domain_device *dev)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue