From 6d70a74ffd616073a68ae0974d98819bfa8e6da6 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 22 Jun 2012 11:31:14 -0700 Subject: isci: fix isci_pci_probe() generates warning on efi failure path The oem parameter image embedded in the efi variable is at an offset from the start of the variable. However, in the failure path we try to free the 'orom' pointer which is only valid when the paramaters are being read from the legacy option-rom space. Since failure to load the oem parameters is unlikely and we keep the memory around in the success case just defer all de-allocation to devm. Cc: Reported-by: Don Morris Signed-off-by: Dan Williams --- drivers/scsi/isci/init.c | 1 - drivers/scsi/isci/probe_roms.c | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers/scsi/isci') diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index 47e28b55502..8870bd3b638 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -641,7 +641,6 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic orom->hdr.version)) { dev_warn(&pdev->dev, "[%d]: invalid oem parameters detected, falling back to firmware\n", i); - devm_kfree(&pdev->dev, orom); orom = NULL; break; } diff --git a/drivers/scsi/isci/probe_roms.c b/drivers/scsi/isci/probe_roms.c index 4d95654c3fd..8ac646e5edd 100644 --- a/drivers/scsi/isci/probe_roms.c +++ b/drivers/scsi/isci/probe_roms.c @@ -104,7 +104,6 @@ struct isci_orom *isci_request_oprom(struct pci_dev *pdev) if (i >= len) { dev_err(&pdev->dev, "oprom parse error\n"); - devm_kfree(&pdev->dev, rom); rom = NULL; } pci_unmap_biosrom(oprom); -- cgit v1.2.3 From a90037560588e51b3e98b49537799137cbfda17d Mon Sep 17 00:00:00 2001 From: Dave Maurer Date: Fri, 22 Jun 2012 06:45:33 +0000 Subject: isci: fix COMSAS negation timout workaround for WD SAS drives The following patch is a fix for the WD workaround COMSAS negation timeout change. This patch disables the OOB SM when the OOB is placed in reset, which allows the updated COMSAS negation timeout value to take effect. Cc: Dan Thompson Reported-by: Dan Thompson Signed-off-by: Dave Maurer Signed-off-by: Dan Williams --- drivers/scsi/isci/phy.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/scsi/isci') diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c index 18f43d4c30b..ebb8f530f70 100644 --- a/drivers/scsi/isci/phy.c +++ b/drivers/scsi/isci/phy.c @@ -1205,6 +1205,7 @@ static void scu_link_layer_start_oob(struct isci_phy *iphy) /** Reset OOB sequence - start */ val = readl(&ll->phy_configuration); val &= ~(SCU_SAS_PCFG_GEN_BIT(OOB_RESET) | + SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE) | SCU_SAS_PCFG_GEN_BIT(HARD_RESET)); writel(val, &ll->phy_configuration); readl(&ll->phy_configuration); /* flush */ @@ -1236,6 +1237,7 @@ static void scu_link_layer_tx_hard_reset( * to the starting state. */ phy_configuration_value = readl(&iphy->link_layer_registers->phy_configuration); + phy_configuration_value &= ~(SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE)); phy_configuration_value |= (SCU_SAS_PCFG_GEN_BIT(HARD_RESET) | SCU_SAS_PCFG_GEN_BIT(OOB_RESET)); -- cgit v1.2.3 From 67787c330762eb884bf8c169fe942263d55ec162 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 27 Jun 2012 12:10:06 +0300 Subject: isci: make function declaration match implementation Sparse complains that we redeclare this with a different type, because in the .c file we use an enum and in the .h file we declare the parameter as a u32. Probably it's best to use an enum in both places. Signed-off-by: Dan Carpenter Signed-off-by: Dan Williams --- drivers/scsi/isci/remote_node_context.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi/isci') diff --git a/drivers/scsi/isci/remote_node_context.h b/drivers/scsi/isci/remote_node_context.h index a703b9ce0c2..c7ee81d0112 100644 --- a/drivers/scsi/isci/remote_node_context.h +++ b/drivers/scsi/isci/remote_node_context.h @@ -212,7 +212,7 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context scics_sds_remote_node_context_callback callback, void *callback_parameter); enum sci_status sci_remote_node_context_suspend(struct sci_remote_node_context *sci_rnc, - u32 suspend_type, + enum sci_remote_node_suspension_reasons reason, u32 suspension_code); enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *sci_rnc, scics_sds_remote_node_context_callback cb_fn, -- cgit v1.2.3 From 6734092e66011def7875bd67beef889d0fee1cc9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 27 Jun 2012 12:05:21 +0300 Subject: isci: add a couple __iomem annotations These are __iomem. Sparse complains if we don't have that. drivers/scsi/isci/phy.c +149 70: warning: incorrect type in initializer (different address spaces) Signed-off-by: Dan Carpenter Signed-off-by: Dan Williams --- drivers/scsi/isci/host.c | 2 +- drivers/scsi/isci/phy.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/scsi/isci') diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index 45385f53164..b425ed523cc 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@ -1973,7 +1973,7 @@ static void sci_controller_afe_initialization(struct isci_host *ihost) } for (phy_id = 0; phy_id < SCI_MAX_PHYS; phy_id++) { - struct scu_afe_transceiver *xcvr = &afe->scu_afe_xcvr[phy_id]; + struct scu_afe_transceiver __iomem *xcvr = &afe->scu_afe_xcvr[phy_id]; const struct sci_phy_oem_params *oem_phy = &oem->phys[phy_id]; int cable_length_long = is_long_cable(phy_id, cable_selection_mask); diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c index ebb8f530f70..cb87b2ef7c9 100644 --- a/drivers/scsi/isci/phy.c +++ b/drivers/scsi/isci/phy.c @@ -169,7 +169,7 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, phy_cap.gen1_no_ssc = 1; if (ihost->oem_parameters.controller.do_enable_ssc) { struct scu_afe_registers __iomem *afe = &ihost->scu_registers->afe; - struct scu_afe_transceiver *xcvr = &afe->scu_afe_xcvr[phy_idx]; + struct scu_afe_transceiver __iomem *xcvr = &afe->scu_afe_xcvr[phy_idx]; struct isci_pci_info *pci_info = to_pci_info(ihost->pdev); bool en_sas = false; bool en_sata = false; -- cgit v1.2.3 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 45385f53164..bc8981ed02b 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 9ab58e0540e..4911310a38f 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 92c1d86d1fc..da142a8726d 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 bc8981ed02b..d4daa0f2459 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 d4daa0f2459..ab026a50ace 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