Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 316807
b: refs/heads/master
c: 5db45bd
h: refs/heads/master
i:
  316805: 860c517
  316803: 9b85219
  316799: a2de81d
v: v3
  • Loading branch information
Dan Williams authored and James Bottomley committed Jul 20, 2012
1 parent 03cfd1e commit 08f263b
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 5 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b9d5c6b7ef570bea0d22746944d7b58fa7f17b13
refs/heads/master: 5db45bdc87ce4f503947adf7896586d60c63322c
11 changes: 11 additions & 0 deletions trunk/drivers/scsi/libsas/sas_discover.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ void sas_init_dev(struct domain_device *dev)
{
switch (dev->dev_type) {
case SAS_END_DEV:
INIT_LIST_HEAD(&dev->ssp_dev.eh_list_node);
break;
case EDGE_DEV:
case FANOUT_DEV:
Expand Down Expand Up @@ -286,6 +287,8 @@ void sas_free_device(struct kref *kref)

static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_device *dev)
{
struct sas_ha_struct *ha = port->ha;

sas_notify_lldd_dev_gone(dev);
if (!dev->parent)
dev->port->port_dev = NULL;
Expand All @@ -298,6 +301,14 @@ static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_d
sas_ata_end_eh(dev->sata_dev.ap);
spin_unlock_irq(&port->dev_list_lock);

spin_lock_irq(&ha->lock);
if (dev->dev_type == SAS_END_DEV &&
!list_empty(&dev->ssp_dev.eh_list_node)) {
list_del_init(&dev->ssp_dev.eh_list_node);
ha->eh_active--;
}
spin_unlock_irq(&ha->lock);

sas_put_device(dev);
}

Expand Down
2 changes: 2 additions & 0 deletions trunk/drivers/scsi/libsas/sas_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,9 @@ int sas_register_ha(struct sas_ha_struct *sas_ha)
set_bit(SAS_HA_REGISTERED, &sas_ha->state);
spin_lock_init(&sas_ha->lock);
mutex_init(&sas_ha->drain_mutex);
init_waitqueue_head(&sas_ha->eh_wait_q);
INIT_LIST_HEAD(&sas_ha->defer_q);
INIT_LIST_HEAD(&sas_ha->eh_dev_q);

error = sas_register_phys(sas_ha);
if (error) {
Expand Down
121 changes: 117 additions & 4 deletions trunk/drivers/scsi/libsas/sas_scsi_host.c
Original file line number Diff line number Diff line change
Expand Up @@ -460,14 +460,88 @@ struct sas_phy *sas_get_local_phy(struct domain_device *dev)
}
EXPORT_SYMBOL_GPL(sas_get_local_phy);

static void sas_wait_eh(struct domain_device *dev)
{
struct sas_ha_struct *ha = dev->port->ha;
DEFINE_WAIT(wait);

if (dev_is_sata(dev)) {
ata_port_wait_eh(dev->sata_dev.ap);
return;
}
retry:
spin_lock_irq(&ha->lock);

while (test_bit(SAS_DEV_EH_PENDING, &dev->state)) {
prepare_to_wait(&ha->eh_wait_q, &wait, TASK_UNINTERRUPTIBLE);
spin_unlock_irq(&ha->lock);
schedule();
spin_lock_irq(&ha->lock);
}
finish_wait(&ha->eh_wait_q, &wait);

spin_unlock_irq(&ha->lock);

/* make sure SCSI EH is complete */
if (scsi_host_in_recovery(ha->core.shost)) {
msleep(10);
goto retry;
}
}
EXPORT_SYMBOL(sas_wait_eh);

static int sas_queue_reset(struct domain_device *dev, int reset_type, int lun, int wait)
{
struct sas_ha_struct *ha = dev->port->ha;
int scheduled = 0, tries = 100;

/* ata: promote lun reset to bus reset */
if (dev_is_sata(dev)) {
sas_ata_schedule_reset(dev);
if (wait)
sas_ata_wait_eh(dev);
return SUCCESS;
}

while (!scheduled && tries--) {
spin_lock_irq(&ha->lock);
if (!test_bit(SAS_DEV_EH_PENDING, &dev->state) &&
!test_bit(reset_type, &dev->state)) {
scheduled = 1;
ha->eh_active++;
list_add_tail(&dev->ssp_dev.eh_list_node, &ha->eh_dev_q);
set_bit(SAS_DEV_EH_PENDING, &dev->state);
set_bit(reset_type, &dev->state);
int_to_scsilun(lun, &dev->ssp_dev.reset_lun);
scsi_schedule_eh(ha->core.shost);
}
spin_unlock_irq(&ha->lock);

if (wait)
sas_wait_eh(dev);

if (scheduled)
return SUCCESS;
}

SAS_DPRINTK("%s reset of %s failed\n",
reset_type == SAS_DEV_LU_RESET ? "LUN" : "Bus",
dev_name(&dev->rphy->dev));

return FAILED;
}

/* Attempt to send a LUN reset message to a device */
int sas_eh_device_reset_handler(struct scsi_cmnd *cmd)
{
struct domain_device *dev = cmd_to_domain_dev(cmd);
struct sas_internal *i =
to_sas_internal(dev->port->ha->core.shost->transportt);
struct scsi_lun lun;
int res;
struct scsi_lun lun;
struct Scsi_Host *host = cmd->device->host;
struct domain_device *dev = cmd_to_domain_dev(cmd);
struct sas_internal *i = to_sas_internal(host->transportt);

if (current != host->ehandler)
return sas_queue_reset(dev, SAS_DEV_LU_RESET, cmd->device->lun, 0);

int_to_scsilun(cmd->device->lun, &lun);

Expand All @@ -486,8 +560,12 @@ int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd)
{
struct domain_device *dev = cmd_to_domain_dev(cmd);
struct sas_phy *phy = sas_get_local_phy(dev);
struct Scsi_Host *host = cmd->device->host;
int res;

if (current != host->ehandler)
return sas_queue_reset(dev, SAS_DEV_RESET, 0, 0);

res = sas_phy_reset(phy, 1);
if (res)
SAS_DPRINTK("Bus reset of %s failed 0x%x\n",
Expand Down Expand Up @@ -667,6 +745,39 @@ static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head *
goto out;
}

static void sas_eh_handle_resets(struct Scsi_Host *shost)
{
struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
struct sas_internal *i = to_sas_internal(shost->transportt);

/* handle directed resets to sas devices */
spin_lock_irq(&ha->lock);
while (!list_empty(&ha->eh_dev_q)) {
struct domain_device *dev;
struct ssp_device *ssp;

ssp = list_entry(ha->eh_dev_q.next, typeof(*ssp), eh_list_node);
list_del_init(&ssp->eh_list_node);
dev = container_of(ssp, typeof(*dev), ssp_dev);
kref_get(&dev->kref);
WARN_ONCE(dev_is_sata(dev), "ssp reset to ata device?\n");

spin_unlock_irq(&ha->lock);

if (test_and_clear_bit(SAS_DEV_LU_RESET, &dev->state))
i->dft->lldd_lu_reset(dev, ssp->reset_lun.scsi_lun);

if (test_and_clear_bit(SAS_DEV_RESET, &dev->state))
i->dft->lldd_I_T_nexus_reset(dev);

sas_put_device(dev);
spin_lock_irq(&ha->lock);
clear_bit(SAS_DEV_EH_PENDING, &dev->state);
ha->eh_active--;
}
spin_unlock_irq(&ha->lock);
}


void sas_scsi_recover_host(struct Scsi_Host *shost)
{
Expand Down Expand Up @@ -709,6 +820,8 @@ void sas_scsi_recover_host(struct Scsi_Host *shost)
if (ha->lldd_max_execute_num > 1)
wake_up_process(ha->core.queue_thread);

sas_eh_handle_resets(shost);

/* now link into libata eh --- if we have any ata devices */
sas_ata_strategy_handler(shost);

Expand Down
10 changes: 10 additions & 0 deletions trunk/include/scsi/libsas.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,17 @@ struct sata_device {
u8 fis[ATA_RESP_FIS_SIZE];
};

struct ssp_device {
struct list_head eh_list_node; /* pending a user requested eh action */
struct scsi_lun reset_lun;
};

enum {
SAS_DEV_GONE,
SAS_DEV_DESTROY,
SAS_DEV_EH_PENDING,
SAS_DEV_LU_RESET,
SAS_DEV_RESET,
};

struct domain_device {
Expand Down Expand Up @@ -213,6 +220,7 @@ struct domain_device {
union {
struct expander_device ex_dev;
struct sata_device sata_dev; /* STP & directly attached */
struct ssp_device ssp_dev;
};

void *lldd_dev;
Expand Down Expand Up @@ -389,6 +397,8 @@ struct sas_ha_struct {
unsigned long state;
spinlock_t lock;
int eh_active;
wait_queue_head_t eh_wait_q;
struct list_head eh_dev_q;

struct mutex disco_mutex;

Expand Down

0 comments on commit 08f263b

Please sign in to comment.