aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libsas
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@us.ibm.com>2007-01-11 17:15:17 -0500
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2007-01-13 17:17:27 -0500
commit3ebf6922b0833807e54c73f4794c74baf9945fc8 (patch)
treef6a986a1fc80efe6f3c1a30073cfec34fd7edc7c /drivers/scsi/libsas
parent37958fb040cf6f88b354b9fa7e846014ffbd3b73 (diff)
[SCSI] libsas: Enable the EH strategy handler to reset a phy after a command
When a SAS LLDD needs to request a device port reset, it needs to have all commands aborted before it can reset the port. Since commands are put on the EH's list in the order that they were queued, the LLDD can set a "need reset" flag in the last task to be aborted so that the EH can reset the port after all commands are aborted. Signed-off-by: Darrick J. Wong <djwong@us.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/libsas')
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c37
1 files changed, 36 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 }