From patchwork Sun Mar 11 07:28:25 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 145953 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 265AAB6EF3 for ; Sun, 11 Mar 2012 18:13:11 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751512Ab2CKHNK (ORCPT ); Sun, 11 Mar 2012 03:13:10 -0400 Received: from mga03.intel.com ([143.182.124.21]:18382 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751084Ab2CKHNJ (ORCPT ); Sun, 11 Mar 2012 03:13:09 -0400 Received: from azsmga001.ch.intel.com ([10.2.17.19]) by azsmga101.ch.intel.com with ESMTP; 10 Mar 2012 23:13:08 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.71,315,1320652800"; d="scan'208";a="117336540" Received: from dwillia2-linux.jf.intel.com ([10.23.45.110]) by azsmga001.ch.intel.com with ESMTP; 10 Mar 2012 23:13:08 -0800 Received: from dwillia2-linux.jf.intel.com (localhost.localdomain [IPv6:::1]) by dwillia2-linux.jf.intel.com (Postfix) with ESMTP id 92780800DF; Sat, 10 Mar 2012 23:28:25 -0800 (PST) Subject: [isci PATCH v2 08/18] isci: fix controller stop To: linux-scsi@vger.kernel.org From: Dan Williams Cc: linux-ide@vger.kernel.org, Richard Boyd Date: Sat, 10 Mar 2012 23:28:25 -0800 Message-ID: <20120311072825.6320.19024.stgit@dwillia2-linux.jf.intel.com> In-Reply-To: <20120311072518.6320.61717.stgit@dwillia2-linux.jf.intel.com> References: <20120311072518.6320.61717.stgit@dwillia2-linux.jf.intel.com> User-Agent: StGit/0.16-1-g7004 MIME-Version: 1.0 Sender: linux-ide-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ide@vger.kernel.org 1/ notify waiters when controller stop completes (fixes 10 second stall unloading the driver) 2/ make sure phy stop is after port and device stop Cc: Richard Boyd Signed-off-by: Dan Williams --- drivers/scsi/isci/host.c | 99 +++++++++++++++++++++++++--------------------- drivers/scsi/isci/host.h | 8 ---- 2 files changed, 55 insertions(+), 52 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-ide" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index 0fe372f..95c3da6 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@ -1046,7 +1046,7 @@ void isci_host_scan_start(struct Scsi_Host *shost) spin_unlock_irq(&ihost->scic_lock); } -static void isci_host_stop_complete(struct isci_host *ihost, enum sci_status completion_status) +static void isci_host_stop_complete(struct isci_host *ihost) { sci_controller_disable_interrupts(ihost); clear_bit(IHOST_STOP_PENDING, &ihost->flags); @@ -1232,7 +1232,7 @@ static enum sci_status sci_controller_reset(struct isci_host *ihost) switch (ihost->sm.current_state_id) { case SCIC_RESET: case SCIC_READY: - case SCIC_STOPPED: + case SCIC_STOPPING: case SCIC_FAILED: /* * The reset operation is not a graceful cleanup, just @@ -1247,6 +1247,44 @@ static enum sci_status sci_controller_reset(struct isci_host *ihost) } } +static enum sci_status sci_controller_stop_phys(struct isci_host *ihost) +{ + u32 index; + enum sci_status status; + enum sci_status phy_status; + + status = SCI_SUCCESS; + + for (index = 0; index < SCI_MAX_PHYS; index++) { + phy_status = sci_phy_stop(&ihost->phys[index]); + + if (phy_status != SCI_SUCCESS && + phy_status != SCI_FAILURE_INVALID_STATE) { + status = SCI_FAILURE; + + dev_warn(&ihost->pdev->dev, + "%s: Controller stop operation failed to stop " + "phy %d because of status %d.\n", + __func__, + ihost->phys[index].phy_index, phy_status); + } + } + + return status; +} + + +/** + * isci_host_deinit - shutdown frame reception and dma + * @ihost: host to take down + * + * This is called in either the driver shutdown or the suspend path. In + * the shutdown case libsas went through port teardown and normal device + * removal (i.e. physical links stayed up to service scsi_device removal + * commands). In the suspend case we disable the hardware without + * notifying libsas of the link down events since we want libsas to + * remember the domain across the suspend/resume cycle + */ void isci_host_deinit(struct isci_host *ihost) { int i; @@ -1255,16 +1293,6 @@ void isci_host_deinit(struct isci_host *ihost) for (i = 0; i < isci_gpio_count(ihost); i++) writel(SGPIO_HW_CONTROL, &ihost->scu_registers->peg0.sgpio.output_data_select[i]); - for (i = 0; i < SCI_MAX_PORTS; i++) { - struct isci_port *iport = &ihost->ports[i]; - struct isci_remote_device *idev, *d; - - list_for_each_entry_safe(idev, d, &iport->remote_dev_list, node) { - if (test_bit(IDEV_ALLOCATED, &idev->flags)) - isci_remote_device_stop(ihost, idev); - } - } - set_bit(IHOST_STOP_PENDING, &ihost->flags); spin_lock_irq(&ihost->scic_lock); @@ -1273,6 +1301,13 @@ void isci_host_deinit(struct isci_host *ihost) wait_for_stop(ihost); + /* phy stop is after controller stop to allow port and device to + * go idle before shutting down the phys, but the expectation is + * that i/o has been shut off well before we reach this + * function. + */ + sci_controller_stop_phys(ihost); + /* disable sgpio: where the above wait should give time for the * enclosure to sample the gpios going inactive */ @@ -1476,32 +1511,6 @@ static void sci_controller_ready_state_exit(struct sci_base_state_machine *sm) sci_controller_set_interrupt_coalescence(ihost, 0, 0); } -static enum sci_status sci_controller_stop_phys(struct isci_host *ihost) -{ - u32 index; - enum sci_status status; - enum sci_status phy_status; - - status = SCI_SUCCESS; - - for (index = 0; index < SCI_MAX_PHYS; index++) { - phy_status = sci_phy_stop(&ihost->phys[index]); - - if (phy_status != SCI_SUCCESS && - phy_status != SCI_FAILURE_INVALID_STATE) { - status = SCI_FAILURE; - - dev_warn(&ihost->pdev->dev, - "%s: Controller stop operation failed to stop " - "phy %d because of status %d.\n", - __func__, - ihost->phys[index].phy_index, phy_status); - } - } - - return status; -} - static enum sci_status sci_controller_stop_ports(struct isci_host *ihost) { u32 index; @@ -1561,10 +1570,11 @@ static void sci_controller_stopping_state_enter(struct sci_base_state_machine *s { struct isci_host *ihost = container_of(sm, typeof(*ihost), sm); - /* Stop all of the components for this controller */ - sci_controller_stop_phys(ihost); - sci_controller_stop_ports(ihost); sci_controller_stop_devices(ihost); + sci_controller_stop_ports(ihost); + + if (!sci_controller_has_remote_devices_stopping(ihost)) + isci_host_stop_complete(ihost); } static void sci_controller_stopping_state_exit(struct sci_base_state_machine *sm) @@ -1621,7 +1631,6 @@ static const struct sci_base_state sci_controller_state_table[] = { .enter_state = sci_controller_stopping_state_enter, .exit_state = sci_controller_stopping_state_exit, }, - [SCIC_STOPPED] = {}, [SCIC_FAILED] = {} }; @@ -1641,7 +1650,7 @@ static void controller_timeout(unsigned long data) sci_controller_transition_to_ready(ihost, SCI_FAILURE_TIMEOUT); else if (sm->current_state_id == SCIC_STOPPING) { sci_change_state(sm, SCIC_FAILED); - isci_host_stop_complete(ihost, SCI_FAILURE_TIMEOUT); + isci_host_stop_complete(ihost); } else /* / @todo Now what do we want to do in this case? */ dev_err(&ihost->pdev->dev, "%s: Controller timer fired when controller was not " @@ -2452,7 +2461,7 @@ void sci_controller_link_down(struct isci_host *ihost, struct isci_port *iport, } } -static bool sci_controller_has_remote_devices_stopping(struct isci_host *ihost) +bool sci_controller_has_remote_devices_stopping(struct isci_host *ihost) { u32 index; @@ -2478,7 +2487,7 @@ void sci_controller_remote_device_stopped(struct isci_host *ihost, } if (!sci_controller_has_remote_devices_stopping(ihost)) - sci_change_state(&ihost->sm, SCIC_STOPPED); + isci_host_stop_complete(ihost); } void sci_controller_post_request(struct isci_host *ihost, u32 request) diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h index 4695162..a89c0e3 100644 --- a/drivers/scsi/isci/host.h +++ b/drivers/scsi/isci/host.h @@ -277,13 +277,6 @@ enum sci_controller_states { SCIC_STOPPING, /** - * This state indicates that the controller has successfully been stopped. - * In this state no new IO operations are permitted. - * This state is entered from the STOPPING state. - */ - SCIC_STOPPED, - - /** * This state indicates that the controller could not successfully be * initialized. In this state no new IO operations are permitted. * This state is entered from the INITIALIZING state. @@ -479,6 +472,7 @@ int isci_host_init(struct isci_host *); void isci_host_completion_routine(unsigned long data); void isci_host_deinit(struct isci_host *); void sci_controller_disable_interrupts(struct isci_host *ihost); +bool sci_controller_has_remote_devices_stopping(struct isci_host *ihost); enum sci_status sci_controller_start_io( struct isci_host *ihost,