Commit b2024459 authored by Dan Williams's avatar Dan Williams Committed by James Bottomley

[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: default avatarMichal Kosciowski <michal.kosciowski@intel.com>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
Acked-by: default avatarJeff Garzik <jgarzik@redhat.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 0f3fce5c
...@@ -3839,18 +3839,25 @@ void ata_sas_port_stop(struct ata_port *ap) ...@@ -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);
if (!rc) {
ap->print_id = atomic_inc_return(&ata_print_id);
__ata_port_probe(ap); __ata_port_probe(ap);
} }
EXPORT_SYMBOL_GPL(ata_sas_async_probe);
return rc; int ata_sas_sync_probe(struct ata_port *ap)
{
return ata_port_probe(ap);
} }
EXPORT_SYMBOL_GPL(ata_sas_async_port_init); 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) ...@@ -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);
rc = ata_port_probe(ap);
}
return rc; return rc;
ap->print_id = atomic_inc_return(&ata_print_id);
return 0;
} }
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) ...@@ -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 = { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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,12 +790,14 @@ static struct domain_device *sas_ex_discover_end_dev( ...@@ -790,12 +790,14 @@ static struct domain_device *sas_ex_discover_end_dev(
if (res) if (res)
goto out_free; goto out_free;
sas_init_dev(child);
res = sas_ata_init(child);
if (res)
goto out_free;
rphy = sas_end_device_alloc(phy->port); rphy = sas_end_device_alloc(phy->port);
if (unlikely(!rphy)) if (!rphy)
goto out_free; goto out_free;
sas_init_dev(child);
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, ...@@ -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) ...@@ -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) ...@@ -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;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment