diff options
author | Dan Williams <dan.j.williams@intel.com> | 2012-01-09 13:12:52 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-02-29 16:20:01 -0500 |
commit | 45c73b65194173e77030d5b95abe5b63a402d268 (patch) | |
tree | 46e08c5fb11805dac6aa2008a3501dfee58f75c8 /drivers/scsi/libsas | |
parent | 5a998328296cb16cb8b0307a402a0f2feab533c5 (diff) |
[SCSI] libsas: pre-clean commands that won the eh vs completion race
When scrolling forward through the eh list (in a clear_q scenario) it is
possible to encounter commands that won the completion vs eh race. Rather
than sprinkle more "if (!task)" throughout the handler just make a pass
through the list and delete the race winners before handling the rest.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/libsas')
-rw-r--r-- | drivers/scsi/libsas/sas_scsi_host.c | 25 |
1 files changed, 16 insertions, 9 deletions
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 94ef76316c31..731c89250639 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c | |||
@@ -249,8 +249,8 @@ out_done: | |||
249 | 249 | ||
250 | static void sas_eh_finish_cmd(struct scsi_cmnd *cmd) | 250 | static void sas_eh_finish_cmd(struct scsi_cmnd *cmd) |
251 | { | 251 | { |
252 | struct sas_task *task = TO_SAS_TASK(cmd); | ||
253 | struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(cmd->device->host); | 252 | struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(cmd->device->host); |
253 | struct sas_task *task = TO_SAS_TASK(cmd); | ||
254 | 254 | ||
255 | /* At this point, we only get called following an actual abort | 255 | /* At this point, we only get called following an actual abort |
256 | * of the task, so we should be guaranteed not to be racing with | 256 | * of the task, so we should be guaranteed not to be racing with |
@@ -267,9 +267,9 @@ static void sas_eh_finish_cmd(struct scsi_cmnd *cmd) | |||
267 | 267 | ||
268 | static void sas_eh_defer_cmd(struct scsi_cmnd *cmd) | 268 | static void sas_eh_defer_cmd(struct scsi_cmnd *cmd) |
269 | { | 269 | { |
270 | struct sas_task *task = TO_SAS_TASK(cmd); | 270 | struct domain_device *dev = cmd_to_domain_dev(cmd); |
271 | struct domain_device *dev = task->dev; | ||
272 | struct sas_ha_struct *ha = dev->port->ha; | 271 | struct sas_ha_struct *ha = dev->port->ha; |
272 | struct sas_task *task = TO_SAS_TASK(cmd); | ||
273 | 273 | ||
274 | if (!dev_is_sata(dev)) { | 274 | if (!dev_is_sata(dev)) { |
275 | sas_eh_finish_cmd(cmd); | 275 | sas_eh_finish_cmd(cmd); |
@@ -530,8 +530,9 @@ static int sas_eh_handle_sas_errors(struct Scsi_Host *shost, | |||
530 | struct sas_internal *i = to_sas_internal(shost->transportt); | 530 | struct sas_internal *i = to_sas_internal(shost->transportt); |
531 | unsigned long flags; | 531 | unsigned long flags; |
532 | struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); | 532 | struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); |
533 | LIST_HEAD(done); | ||
533 | 534 | ||
534 | Again: | 535 | /* clean out any commands that won the completion vs eh race */ |
535 | list_for_each_entry_safe(cmd, n, work_q, eh_entry) { | 536 | list_for_each_entry_safe(cmd, n, work_q, eh_entry) { |
536 | struct domain_device *dev = cmd_to_domain_dev(cmd); | 537 | struct domain_device *dev = cmd_to_domain_dev(cmd); |
537 | struct sas_task *task; | 538 | struct sas_task *task; |
@@ -545,7 +546,12 @@ Again: | |||
545 | spin_unlock_irqrestore(&dev->done_lock, flags); | 546 | spin_unlock_irqrestore(&dev->done_lock, flags); |
546 | 547 | ||
547 | if (!task) | 548 | if (!task) |
548 | continue; | 549 | list_move_tail(&cmd->eh_entry, &done); |
550 | } | ||
551 | |||
552 | Again: | ||
553 | list_for_each_entry_safe(cmd, n, work_q, eh_entry) { | ||
554 | struct sas_task *task = TO_SAS_TASK(cmd); | ||
549 | 555 | ||
550 | list_del_init(&cmd->eh_entry); | 556 | list_del_init(&cmd->eh_entry); |
551 | 557 | ||
@@ -649,15 +655,16 @@ Again: | |||
649 | goto clear_q; | 655 | goto clear_q; |
650 | } | 656 | } |
651 | } | 657 | } |
658 | out: | ||
659 | list_splice_tail(&done, work_q); | ||
652 | list_splice_tail_init(&ha->eh_ata_q, work_q); | 660 | list_splice_tail_init(&ha->eh_ata_q, work_q); |
653 | return list_empty(work_q); | 661 | return list_empty(work_q); |
654 | clear_q: | 662 | |
663 | clear_q: | ||
655 | SAS_DPRINTK("--- Exit %s -- clear_q\n", __func__); | 664 | SAS_DPRINTK("--- Exit %s -- clear_q\n", __func__); |
656 | list_for_each_entry_safe(cmd, n, work_q, eh_entry) | 665 | list_for_each_entry_safe(cmd, n, work_q, eh_entry) |
657 | sas_eh_finish_cmd(cmd); | 666 | sas_eh_finish_cmd(cmd); |
658 | 667 | goto out; | |
659 | list_splice_tail_init(&ha->eh_ata_q, work_q); | ||
660 | return list_empty(work_q); | ||
661 | } | 668 | } |
662 | 669 | ||
663 | void sas_scsi_recover_host(struct Scsi_Host *shost) | 670 | void sas_scsi_recover_host(struct Scsi_Host *shost) |