From e468dc112f38220ee78bc0de64190eca9812749b Mon Sep 17 00:00:00 2001 From: Artur Wojcik Date: Thu, 21 Jun 2012 23:41:56 -0700 Subject: [SCSI] isci: implement suspend/resume support Provide a "simple-dev-pm-ops" implementation that shuts down the domain and the device on suspend, and resumes the device and the domain on resume. All of the mechanics of restoring domain connectivity are handled by libsas once isci has notified libsas that all links should be back up. libsas is in charge of handling links that did not resume, or resumed out of order. Signed-off-by: Artur Wojcik Signed-off-by: Jacek Danecki Signed-off-by: Dan Williams Signed-off-by: James Bottomley --- drivers/scsi/isci/host.c | 2 +- drivers/scsi/isci/host.h | 2 +- drivers/scsi/isci/init.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 59 insertions(+), 3 deletions(-) (limited to 'drivers/scsi/isci') diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index 45385f531649..bc8981ed02b3 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@ -1044,7 +1044,7 @@ static enum sci_status sci_controller_start(struct isci_host *ihost, return SCI_SUCCESS; } -void isci_host_scan_start(struct Scsi_Host *shost) +void isci_host_start(struct Scsi_Host *shost) { struct isci_host *ihost = SHOST_TO_SAS_HA(shost)->lldd_ha; unsigned long tmo = sci_controller_get_suggested_start_timeout(ihost); diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h index 9ab58e0540e7..4911310a38f5 100644 --- a/drivers/scsi/isci/host.h +++ b/drivers/scsi/isci/host.h @@ -473,7 +473,7 @@ void sci_controller_remote_device_stopped(struct isci_host *ihost, enum sci_status sci_controller_continue_io(struct isci_request *ireq); int isci_host_scan_finished(struct Scsi_Host *, unsigned long); -void isci_host_scan_start(struct Scsi_Host *); +void isci_host_start(struct Scsi_Host *); u16 isci_alloc_tag(struct isci_host *ihost); enum sci_status isci_free_tag(struct isci_host *ihost, u16 io_tag); void isci_tci_free(struct isci_host *ihost, u16 tci); diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index 92c1d86d1fc6..da142a8726dc 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -156,7 +156,7 @@ static struct scsi_host_template isci_sht = { .target_alloc = sas_target_alloc, .slave_configure = sas_slave_configure, .scan_finished = isci_host_scan_finished, - .scan_start = isci_host_scan_start, + .scan_start = isci_host_start, .change_queue_depth = sas_change_queue_depth, .change_queue_type = sas_change_queue_type, .bios_param = sas_bios_param, @@ -722,11 +722,67 @@ static void __devexit isci_pci_remove(struct pci_dev *pdev) } } +#ifdef CONFIG_PM +static int isci_suspend(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct isci_host *ihost; + int i; + + for_each_isci_host(i, ihost, pdev) { + sas_suspend_ha(&ihost->sas_ha); + isci_host_deinit(ihost); + } + + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} + +static int isci_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct isci_host *ihost; + int rc, i; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + + rc = pcim_enable_device(pdev); + if (rc) { + dev_err(&pdev->dev, + "enabling device failure after resume(%d)\n", rc); + return rc; + } + + pci_set_master(pdev); + + for_each_isci_host(i, ihost, pdev) { + sas_prep_resume_ha(&ihost->sas_ha); + + isci_host_init(ihost); + isci_host_start(ihost->sas_ha.core.shost); + wait_for_start(ihost); + + sas_resume_ha(&ihost->sas_ha); + } + + return 0; +} + +static SIMPLE_DEV_PM_OPS(isci_pm_ops, isci_suspend, isci_resume); +#endif + static struct pci_driver isci_pci_driver = { .name = DRV_NAME, .id_table = isci_id_table, .probe = isci_pci_probe, .remove = __devexit_p(isci_pci_remove), +#ifdef CONFIG_PM + .driver.pm = &isci_pm_ops, +#endif }; static __init int isci_init(void) -- cgit v1.2.3 From 54b46677757ff8d6c282305fc7710f466b63d6dc Mon Sep 17 00:00:00 2001 From: Jeff Skirvin Date: Wed, 5 Sep 2012 21:36:47 -0700 Subject: [SCSI] isci: Allow SSP tasks into the task management path. This commit fixes a driver bug for SSP tasks that require task management in the target after they complete in the SCU hardware. The problem was manifested in the function "isci_task_abort_task", which tests to see if the sas_task.lldd_task is non-NULL before allowing task management; this bug would always NULL lldd_task in the SCU I/O completion path even if target management was required, which would prevent task / target manangement from happening. Note that in the case of SATA/STP targets, error recovery is provided by the libata error handler which is why SATA/STP device recovery worked correctly even though SSP handling did not. Signed-off-by: Jeff Skirvin Signed-off-by: James Bottomley --- drivers/scsi/isci/host.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/scsi/isci') diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index bc8981ed02b3..d4daa0f24595 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@ -1079,7 +1079,6 @@ static void sci_controller_completion_handler(struct isci_host *ihost) void ireq_done(struct isci_host *ihost, struct isci_request *ireq, struct sas_task *task) { - task->lldd_task = NULL; if (!test_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags) && !(task->task_state_flags & SAS_TASK_STATE_ABORTED)) { if (test_bit(IREQ_COMPLETE_IN_TARGET, &ireq->flags)) { @@ -1087,16 +1086,19 @@ void ireq_done(struct isci_host *ihost, struct isci_request *ireq, struct sas_ta dev_dbg(&ihost->pdev->dev, "%s: Normal - ireq/task = %p/%p\n", __func__, ireq, task); - + task->lldd_task = NULL; task->task_done(task); } else { dev_dbg(&ihost->pdev->dev, "%s: Error - ireq/task = %p/%p\n", __func__, ireq, task); - + if (sas_protocol_ata(task->task_proto)) + task->lldd_task = NULL; sas_task_abort(task); } - } + } else + task->lldd_task = NULL; + if (test_and_clear_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags)) wake_up_all(&ihost->eventq); -- cgit v1.2.3 From 44ef2bf72df34ef2628dc3475b4507ab984d6744 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Wed, 5 Sep 2012 16:35:44 -0700 Subject: [SCSI] isci: Fix interrupt coalescing assumption of active TCs We always assign a dummy task context to a port in order to address a silicon issue. We have 4 ports per controller. So when idle, there are always exactly 4 TCs "active". The adaptive interrupt coalescing code uses number of active TCs to figure out the coalescing values. However, we never hit "0" TCs because of the 4 dummy TCs. Putting in fix so that we calculate this correctly. Reported-by: Dan Melnic Signed-off-by: Dave Jiang Signed-off-by: James Bottomley --- drivers/scsi/isci/host.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/scsi/isci') diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index d4daa0f24595..ab026a50ace3 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@ -1122,10 +1122,16 @@ void isci_host_completion_routine(unsigned long data) sci_controller_completion_handler(ihost); spin_unlock_irq(&ihost->scic_lock); - /* the coalesence timeout doubles at each encoding step, so + /* + * we subtract SCI_MAX_PORTS to account for the number of dummy TCs + * issued for hardware issue workaround + */ + active = isci_tci_active(ihost) - SCI_MAX_PORTS; + + /* + * the coalesence timeout doubles at each encoding step, so * update it based on the ilog2 value of the outstanding requests */ - active = isci_tci_active(ihost); writel(SMU_ICC_GEN_VAL(NUMBER, active) | SMU_ICC_GEN_VAL(TIMER, ISCI_COALESCE_BASE + ilog2(active)), &ihost->smu_registers->interrupt_coalesce_control); -- cgit v1.2.3