Skip to content

Commit

Permalink
[SCSI] libsas: async ata scanning
Browse files Browse the repository at this point in the history
libsas ata error handling is already async but this does not help the
scan case.  Move initial link recovery out from under host->scan_mutex,
and delay synchronization with eh until after all port probe/recovery
work has been queued.

Device ordering is maintained with scan order by still calling
sas_rphy_add() in order of domain discovery.

Since we now scan the domain list when invoking libata-eh we need to be
careful to check for fully initialized ata ports.

Acked-by: Jack Wang <jack_wang@usish.com>
Acked-by: Jeff Garzik <jgarzik@redhat.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
  • Loading branch information
djbw authored and James Bottomley committed Feb 29, 2012
1 parent 92625f9 commit 9508a66
Show file tree
Hide file tree
Showing 14 changed files with 123 additions and 66 deletions.
34 changes: 18 additions & 16 deletions drivers/ata/libata-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -5936,29 +5936,31 @@ void ata_host_init(struct ata_host *host, struct device *dev,
host->ops = ops;
}

int ata_port_probe(struct ata_port *ap)
void __ata_port_probe(struct ata_port *ap)
{
int rc = 0;
struct ata_eh_info *ehi = &ap->link.eh_info;
unsigned long flags;

/* probe */
if (ap->ops->error_handler) {
struct ata_eh_info *ehi = &ap->link.eh_info;
unsigned long flags;
/* kick EH for boot probing */
spin_lock_irqsave(ap->lock, flags);

/* kick EH for boot probing */
spin_lock_irqsave(ap->lock, flags);
ehi->probe_mask |= ATA_ALL_DEVICES;
ehi->action |= ATA_EH_RESET;
ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;

ehi->probe_mask |= ATA_ALL_DEVICES;
ehi->action |= ATA_EH_RESET;
ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
ap->pflags &= ~ATA_PFLAG_INITIALIZING;
ap->pflags |= ATA_PFLAG_LOADING;
ata_port_schedule_eh(ap);

ap->pflags &= ~ATA_PFLAG_INITIALIZING;
ap->pflags |= ATA_PFLAG_LOADING;
ata_port_schedule_eh(ap);
spin_unlock_irqrestore(ap->lock, flags);
}

spin_unlock_irqrestore(ap->lock, flags);
int ata_port_probe(struct ata_port *ap)
{
int rc = 0;

/* wait for EH to finish */
if (ap->ops->error_handler) {
__ata_port_probe(ap);
ata_port_wait_eh(ap);
} else {
DPRINTK("ata%u: bus probe begin\n", ap->print_id);
Expand Down
13 changes: 13 additions & 0 deletions drivers/ata/libata-scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -3838,6 +3838,19 @@ void ata_sas_port_stop(struct ata_port *ap)
}
EXPORT_SYMBOL_GPL(ata_sas_port_stop);

int ata_sas_async_port_init(struct ata_port *ap)
{
int rc = ap->ops->port_start(ap);

if (!rc) {
ap->print_id = ata_print_id++;
__ata_port_probe(ap);
}

return rc;
}
EXPORT_SYMBOL_GPL(ata_sas_async_port_init);

/**
* ata_sas_port_init - Initialize a SATA device
* @ap: SATA port to initialize
Expand Down
1 change: 1 addition & 0 deletions drivers/ata/libata.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
extern struct ata_port *ata_port_alloc(struct ata_host *host);
extern const char *sata_spd_string(unsigned int spd);
extern int ata_port_probe(struct ata_port *ap);
extern void __ata_port_probe(struct ata_port *ap);

/* libata-acpi.c */
#ifdef CONFIG_ATA_ACPI
Expand Down
1 change: 0 additions & 1 deletion drivers/scsi/aic94xx/aic94xx_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ static struct scsi_host_template aic94xx_sht = {
.use_clustering = ENABLE_CLUSTERING,
.eh_device_reset_handler = sas_eh_device_reset_handler,
.eh_bus_reset_handler = sas_eh_bus_reset_handler,
.slave_alloc = sas_slave_alloc,
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
};
Expand Down
1 change: 0 additions & 1 deletion drivers/scsi/isci/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@ static struct scsi_host_template isci_sht = {
.sg_tablesize = SG_ALL,
.max_sectors = SCSI_DEFAULT_MAX_SECTORS,
.use_clustering = ENABLE_CLUSTERING,
.slave_alloc = sas_slave_alloc,
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
.shost_attrs = isci_host_attrs,
Expand Down
74 changes: 63 additions & 11 deletions drivers/scsi/libsas/sas_ata.c
Original file line number Diff line number Diff line change
Expand Up @@ -585,11 +585,10 @@ static struct ata_port_info sata_port_info = {
.port_ops = &sas_sata_ops
};

int sas_ata_init_host_and_port(struct domain_device *found_dev,
struct scsi_target *starget)
int sas_ata_init_host_and_port(struct domain_device *found_dev)
{
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
struct sas_ha_struct *ha = found_dev->port->ha;
struct Scsi_Host *shost = ha->core.shost;
struct ata_port *ap;

ata_host_init(&found_dev->sata_dev.ata_host,
Expand All @@ -607,6 +606,8 @@ int sas_ata_init_host_and_port(struct domain_device *found_dev,
ap->private_data = found_dev;
ap->cbl = ATA_CBL_SATA;
ap->scsi_host = shost;
/* publish initialized ata port */
smp_wmb();
found_dev->sata_dev.ap = ap;

return 0;
Expand Down Expand Up @@ -683,6 +684,38 @@ static void sas_get_ata_command_set(struct domain_device *dev)
dev->sata_dev.command_set = ATAPI_COMMAND_SET;
}

void sas_probe_sata(struct asd_sas_port *port)
{
struct domain_device *dev, *n;
int err;

mutex_lock(&port->ha->disco_mutex);
list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) {
if (!dev_is_sata(dev))
continue;

err = sas_ata_init_host_and_port(dev);
if (err)
sas_fail_probe(dev, __func__, err);
else
ata_sas_async_port_init(dev->sata_dev.ap);
}
mutex_unlock(&port->ha->disco_mutex);

list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) {
if (!dev_is_sata(dev))
continue;

sas_ata_wait_eh(dev);

/* if libata could not bring the link up, don't surface
* the device
*/
if (ata_dev_disabled(sas_to_ata_dev(dev)))
sas_fail_probe(dev, __func__, -ENODEV);
}
}

/**
* sas_discover_sata -- discover an STP/SATA domain device
* @dev: pointer to struct domain_device of interest
Expand Down Expand Up @@ -724,11 +757,23 @@ static void async_sas_ata_eh(void *data, async_cookie_t cookie)
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)
{
struct scsi_device *sdev;
struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
LIST_HEAD(async);
int i;

/* it's ok to defer revalidation events during ata eh, these
* disks are in one of three states:
Expand All @@ -740,14 +785,21 @@ void sas_ata_strategy_handler(struct Scsi_Host *shost)
*/
sas_disable_revalidation(sas_ha);

shost_for_each_device(sdev, shost) {
struct domain_device *ddev = sdev_to_domain_dev(sdev);

if (!dev_is_sata(ddev))
continue;
spin_lock_irq(&sas_ha->phy_port_lock);
for (i = 0; i < sas_ha->num_phys; i++) {
struct asd_sas_port *port = sas_ha->sas_port[i];
struct domain_device *dev;

async_schedule_domain(async_sas_ata_eh, ddev, &async);
spin_lock(&port->dev_list_lock);
list_for_each_entry(dev, &port->dev_list, dev_list_node) {
if (!sas_ata_dev_eh_valid(dev))
continue;
async_schedule_domain(async_sas_ata_eh, dev, &async);
}
spin_unlock(&port->dev_list_lock);
}
spin_unlock_irq(&sas_ha->phy_port_lock);

async_synchronize_full_domain(&async);

sas_enable_revalidation(sas_ha);
Expand Down
22 changes: 11 additions & 11 deletions drivers/scsi/libsas/sas_discover.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,22 +207,22 @@ static void sas_probe_devices(struct work_struct *work)

clear_bit(DISCE_PROBE, &port->disc.pending);

list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) {
int err;

/* devices must be domain members before link recovery and probe */
list_for_each_entry(dev, &port->disco_list, disco_list_node) {
spin_lock_irq(&port->dev_list_lock);
list_add_tail(&dev->dev_list_node, &port->dev_list);
spin_unlock_irq(&port->dev_list_lock);
}

err = sas_rphy_add(dev->rphy);
sas_probe_sata(port);

if (err) {
SAS_DPRINTK("%s: for %s device %16llx returned %d\n",
__func__, dev->parent ? "exp-attached" :
"direct-attached",
SAS_ADDR(dev->sas_addr), err);
sas_unregister_dev(port, dev);
} else
list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) {
int err;

err = sas_rphy_add(dev->rphy);
if (err)
sas_fail_probe(dev, __func__, err);
else
list_del_init(&dev->disco_list_node);
}
}
Expand Down
9 changes: 9 additions & 0 deletions drivers/scsi/libsas/sas_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,15 @@ static inline int sas_smp_host_handler(struct Scsi_Host *shost,
}
#endif

static inline void sas_fail_probe(struct domain_device *dev, const char *func, int err)
{
SAS_DPRINTK("%s: for %s device %16llx returned %d\n",
func, dev->parent ? "exp-attached" :
"direct-attached",
SAS_ADDR(dev->sas_addr), err);
sas_unregister_dev(dev->port, dev);
}

static inline void sas_fill_in_rphy(struct domain_device *dev,
struct sas_rphy *rphy)
{
Expand Down
18 changes: 0 additions & 18 deletions drivers/scsi/libsas/sas_scsi_host.c
Original file line number Diff line number Diff line change
Expand Up @@ -762,17 +762,10 @@ int sas_target_alloc(struct scsi_target *starget)
{
struct sas_rphy *rphy = dev_to_rphy(starget->dev.parent);
struct domain_device *found_dev = sas_find_dev_by_rphy(rphy);
int res;

if (!found_dev)
return -ENODEV;

if (dev_is_sata(found_dev)) {
res = sas_ata_init_host_and_port(found_dev, starget);
if (res)
return res;
}

kref_get(&found_dev->kref);
starget->hostdata = found_dev;
return 0;
Expand Down Expand Up @@ -1012,16 +1005,6 @@ void sas_task_abort(struct sas_task *task)
}
}

int sas_slave_alloc(struct scsi_device *scsi_dev)
{
struct domain_device *dev = sdev_to_domain_dev(scsi_dev);

if (dev_is_sata(dev))
return ata_sas_port_init(dev->sata_dev.ap);

return 0;
}

void sas_target_destroy(struct scsi_target *starget)
{
struct domain_device *found_dev = starget->hostdata;
Expand Down Expand Up @@ -1082,6 +1065,5 @@ EXPORT_SYMBOL_GPL(sas_task_abort);
EXPORT_SYMBOL_GPL(sas_phy_reset);
EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler);
EXPORT_SYMBOL_GPL(sas_eh_bus_reset_handler);
EXPORT_SYMBOL_GPL(sas_slave_alloc);
EXPORT_SYMBOL_GPL(sas_target_destroy);
EXPORT_SYMBOL_GPL(sas_ioctl);
1 change: 0 additions & 1 deletion drivers/scsi/mvsas/mv_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ static struct scsi_host_template mvs_sht = {
.use_clustering = ENABLE_CLUSTERING,
.eh_device_reset_handler = sas_eh_device_reset_handler,
.eh_bus_reset_handler = sas_eh_bus_reset_handler,
.slave_alloc = sas_slave_alloc,
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
.shost_attrs = mvst_host_attrs,
Expand Down
1 change: 0 additions & 1 deletion drivers/scsi/pm8001/pm8001_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ static struct scsi_host_template pm8001_sht = {
.use_clustering = ENABLE_CLUSTERING,
.eh_device_reset_handler = sas_eh_device_reset_handler,
.eh_bus_reset_handler = sas_eh_bus_reset_handler,
.slave_alloc = sas_slave_alloc,
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
.shost_attrs = pm8001_host_attrs,
Expand Down
1 change: 1 addition & 0 deletions include/linux/libata.h
Original file line number Diff line number Diff line change
Expand Up @@ -996,6 +996,7 @@ extern int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *dev,
extern void ata_sas_port_destroy(struct ata_port *);
extern struct ata_port *ata_sas_port_alloc(struct ata_host *,
struct ata_port_info *, struct Scsi_Host *);
extern int ata_sas_async_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 void ata_sas_port_stop(struct ata_port *ap);
Expand Down
1 change: 0 additions & 1 deletion include/scsi/libsas.h
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,6 @@ int sas_phy_reset(struct sas_phy *phy, int hard_reset);
int sas_queue_up(struct sas_task *task);
extern int sas_queuecommand(struct Scsi_Host * ,struct scsi_cmnd *);
extern int sas_target_alloc(struct scsi_target *);
extern int sas_slave_alloc(struct scsi_device *);
extern int sas_slave_configure(struct scsi_device *);
extern int sas_change_queue_depth(struct scsi_device *, int new_depth,
int reason);
Expand Down
12 changes: 7 additions & 5 deletions include/scsi/sas_ata.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,24 +37,22 @@ 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_ata_init_host_and_port(struct domain_device *found_dev,
struct scsi_target *starget);

int sas_ata_init_host_and_port(struct domain_device *found_dev);
void sas_ata_task_abort(struct sas_task *task);
void sas_ata_strategy_handler(struct Scsi_Host *shost);
void sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
struct list_head *done_q);
void sas_ata_schedule_reset(struct domain_device *dev);
void sas_ata_wait_eh(struct domain_device *dev);
void sas_probe_sata(struct asd_sas_port *port);
#else


static inline int dev_is_sata(struct domain_device *dev)
{
return 0;
}
static inline int sas_ata_init_host_and_port(struct domain_device *found_dev,
struct scsi_target *starget)
static inline int sas_ata_init_host_and_port(struct domain_device *found_dev)
{
return 0;
}
Expand All @@ -79,6 +77,10 @@ static inline void sas_ata_wait_eh(struct domain_device *dev)
{
}

static inline void sas_probe_sata(struct asd_sas_port *port)
{
}

static inline int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy)
{
return 0;
Expand Down

0 comments on commit 9508a66

Please sign in to comment.