aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c37
-rw-r--r--include/scsi/libsas.h1
2 files changed, 37 insertions, 1 deletions
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index f90c332474c8..d0c04ebeb8b0 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -389,6 +389,19 @@ static int sas_recover_I_T(struct domain_device *dev)
389 return res; 389 return res;
390} 390}
391 391
392static int eh_reset_phy_helper(struct sas_phy *phy)
393{
394 int tmf_resp;
395
396 tmf_resp = sas_phy_reset(phy, 1);
397 if (tmf_resp)
398 SAS_DPRINTK("Hard reset of phy %d failed 0x%x\n",
399 phy->identify.phy_identifier,
400 tmf_resp);
401
402 return tmf_resp;
403}
404
392void sas_scsi_recover_host(struct Scsi_Host *shost) 405void sas_scsi_recover_host(struct Scsi_Host *shost)
393{ 406{
394 struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); 407 struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
@@ -396,8 +409,9 @@ void sas_scsi_recover_host(struct Scsi_Host *shost)
396 LIST_HEAD(error_q); 409 LIST_HEAD(error_q);
397 struct scsi_cmnd *cmd, *n; 410 struct scsi_cmnd *cmd, *n;
398 enum task_disposition res = TASK_IS_DONE; 411 enum task_disposition res = TASK_IS_DONE;
399 int tmf_resp; 412 int tmf_resp, need_reset;
400 struct sas_internal *i = to_sas_internal(shost->transportt); 413 struct sas_internal *i = to_sas_internal(shost->transportt);
414 struct sas_phy *task_sas_phy = NULL;
401 415
402 spin_lock_irqsave(shost->host_lock, flags); 416 spin_lock_irqsave(shost->host_lock, flags);
403 list_splice_init(&shost->eh_cmd_q, &error_q); 417 list_splice_init(&shost->eh_cmd_q, &error_q);
@@ -418,6 +432,13 @@ Again:
418 SAS_DPRINTK("%s: taskless cmd?!\n", __FUNCTION__); 432 SAS_DPRINTK("%s: taskless cmd?!\n", __FUNCTION__);
419 continue; 433 continue;
420 } 434 }
435
436 spin_lock_irqsave(&task->task_state_lock, flags);
437 need_reset = task->task_state_flags & SAS_TASK_NEED_DEV_RESET;
438 if (need_reset)
439 task_sas_phy = task->dev->port->phy;
440 spin_unlock_irqrestore(&task->task_state_lock, flags);
441
421 SAS_DPRINTK("trying to find task 0x%p\n", task); 442 SAS_DPRINTK("trying to find task 0x%p\n", task);
422 res = sas_scsi_find_task(task); 443 res = sas_scsi_find_task(task);
423 444
@@ -428,11 +449,15 @@ Again:
428 SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__, 449 SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
429 task); 450 task);
430 task->task_done(task); 451 task->task_done(task);
452 if (need_reset)
453 eh_reset_phy_helper(task_sas_phy);
431 continue; 454 continue;
432 case TASK_IS_ABORTED: 455 case TASK_IS_ABORTED:
433 SAS_DPRINTK("%s: task 0x%p is aborted\n", 456 SAS_DPRINTK("%s: task 0x%p is aborted\n",
434 __FUNCTION__, task); 457 __FUNCTION__, task);
435 task->task_done(task); 458 task->task_done(task);
459 if (need_reset)
460 eh_reset_phy_helper(task_sas_phy);
436 continue; 461 continue;
437 case TASK_IS_AT_LU: 462 case TASK_IS_AT_LU:
438 SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task); 463 SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task);
@@ -443,6 +468,8 @@ Again:
443 SAS_ADDR(task->dev), 468 SAS_ADDR(task->dev),
444 cmd->device->lun); 469 cmd->device->lun);
445 task->task_done(task); 470 task->task_done(task);
471 if (need_reset)
472 eh_reset_phy_helper(task_sas_phy);
446 sas_scsi_clear_queue_lu(&error_q, cmd); 473 sas_scsi_clear_queue_lu(&error_q, cmd);
447 goto Again; 474 goto Again;
448 } 475 }
@@ -455,6 +482,8 @@ Again:
455 SAS_DPRINTK("I_T %016llx recovered\n", 482 SAS_DPRINTK("I_T %016llx recovered\n",
456 SAS_ADDR(task->dev->sas_addr)); 483 SAS_ADDR(task->dev->sas_addr));
457 task->task_done(task); 484 task->task_done(task);
485 if (need_reset)
486 eh_reset_phy_helper(task_sas_phy);
458 sas_scsi_clear_queue_I_T(&error_q, task->dev); 487 sas_scsi_clear_queue_I_T(&error_q, task->dev);
459 goto Again; 488 goto Again;
460 } 489 }
@@ -468,6 +497,8 @@ Again:
468 SAS_DPRINTK("clear nexus port:%d " 497 SAS_DPRINTK("clear nexus port:%d "
469 "succeeded\n", port->id); 498 "succeeded\n", port->id);
470 task->task_done(task); 499 task->task_done(task);
500 if (need_reset)
501 eh_reset_phy_helper(task_sas_phy);
471 sas_scsi_clear_queue_port(&error_q, 502 sas_scsi_clear_queue_port(&error_q,
472 port); 503 port);
473 goto Again; 504 goto Again;
@@ -480,6 +511,8 @@ Again:
480 SAS_DPRINTK("clear nexus ha " 511 SAS_DPRINTK("clear nexus ha "
481 "succeeded\n"); 512 "succeeded\n");
482 task->task_done(task); 513 task->task_done(task);
514 if (need_reset)
515 eh_reset_phy_helper(task_sas_phy);
483 goto out; 516 goto out;
484 } 517 }
485 } 518 }
@@ -493,6 +526,8 @@ Again:
493 cmd->device->lun); 526 cmd->device->lun);
494 527
495 task->task_done(task); 528 task->task_done(task);
529 if (need_reset)
530 eh_reset_phy_helper(task_sas_phy);
496 goto clear_q; 531 goto clear_q;
497 } 532 }
498 } 533 }
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index 1d394855b366..75df71f08ce1 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -553,6 +553,7 @@ struct sas_task {
553#define SAS_TASK_STATE_PENDING 1 553#define SAS_TASK_STATE_PENDING 1
554#define SAS_TASK_STATE_DONE 2 554#define SAS_TASK_STATE_DONE 2
555#define SAS_TASK_STATE_ABORTED 4 555#define SAS_TASK_STATE_ABORTED 4
556#define SAS_TASK_NEED_DEV_RESET 8
556#define SAS_TASK_AT_INITIATOR 16 557#define SAS_TASK_AT_INITIATOR 16
557 558
558static inline struct sas_task *sas_alloc_task(gfp_t flags) 559static inline struct sas_task *sas_alloc_task(gfp_t flags)