From patchwork Thu Aug 10 16:09:26 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Garry X-Patchwork-Id: 109837 Delivered-To: patch@linaro.org Received: by 10.140.95.78 with SMTP id h72csp2548986qge; Thu, 10 Aug 2017 08:50:20 -0700 (PDT) X-Received: by 10.98.103.145 with SMTP id t17mr4449933pfj.13.1502380219607; Thu, 10 Aug 2017 08:50:19 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1502380219; cv=none; d=google.com; s=arc-20160816; b=eZX9Bx1iyFKV9bMg1sTXrw3TqyRCEmwZB9GdrknZMBI5sYYvgyzkMs6ynfzhbfgBon 18bce2i87tAxi/uBzR2uccF4a+F2e5mKI05+jfleR++Xpn5gP1bgcDEU93FQGUjIubGE mzw58Epz8r0Q65fG22tfCJnhWyJMOb0BBBBsF8Cv8OFuWZksKyAfKf4O/UFCUQZNjXfm xWKX1h2inEwj9qHyYAWnfEWgO0Lq2WzVIVJhGFkarO6DkZIOKyDmMPzRGoT4O7Afp4Qv a3swdIdO68kMURXfXQGvHyxezfd9gVB1R6Dr3h8BgJsI3LIilFOIS4HzKm0rrJRlEZYD Etcw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:arc-authentication-results; bh=c2w8RR6y4g6sn+57C0fTc7WLGcFZq6SbNPs0QqTyCGE=; b=Vj7hTP5r8Htecy88/fwRBGbP8evMS+8ucli4AxsIC/eNY66N9wgyB1oS2FBL7TP/TL ILzE4X7a4gHg6+0+NWUS+EjKYQh7klh6FTidJDvs/yeAPJhASbICGxoxWaijv+AKDxWd JvJGjmcC7Or5dHuxEwM+yEtN9t8/p2dzzmGFHhXFKWXUBeg5+GWVkGbmW4phGc2/lKT/ s7j+KzV7su0Bcw4StD6OehdpcKccN1hoNtyhnmu6Pg2K16iU9UmB/4shAQaiJAZUpFhK ojToDwFiOn9bF2NFJO2Q4brv6DKDGeoZf0YJ9lPe/a8NCpUbASAENtNeJ0KTu0xAFuq4 mv1w== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id q83si3606018pfa.305.2017.08.10.08.50.19; Thu, 10 Aug 2017 08:50:19 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753128AbdHJPtH (ORCPT + 25 others); Thu, 10 Aug 2017 11:49:07 -0400 Received: from szxga05-in.huawei.com ([45.249.212.191]:3049 "EHLO szxga05-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752890AbdHJPmu (ORCPT ); Thu, 10 Aug 2017 11:42:50 -0400 Received: from 172.30.72.59 (EHLO DGGEMS402-HUB.china.huawei.com) ([172.30.72.59]) by dggrg05-dlp.huawei.com (MOS 4.4.6-GA FastPath queued) with ESMTP id DEY38525; Thu, 10 Aug 2017 23:42:47 +0800 (CST) Received: from localhost.localdomain (10.67.212.75) by DGGEMS402-HUB.china.huawei.com (10.3.19.202) with Microsoft SMTP Server id 14.3.301.0; Thu, 10 Aug 2017 23:42:35 +0800 From: John Garry To: , CC: , , , , Xiaofei Tan , John Garry Subject: [PATCH 01/19] scsi: hisi_sas: fix reset and port ID refresh issues Date: Fri, 11 Aug 2017 00:09:26 +0800 Message-ID: <1502381384-219889-2-git-send-email-john.garry@huawei.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1502381384-219889-1-git-send-email-john.garry@huawei.com> References: <1502381384-219889-1-git-send-email-john.garry@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.67.212.75] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A090203.598C7EF8.004D, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0, ip=0.0.0.0, so=2014-11-16 11:51:01, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: c25b3dd54b58f07be3aa18b8f289d6b7 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Xiaofei Tan This patch provides fixes for the following issues: 1. Fix issue of controller reset required to send commands. For reset process, it may be required to send commands to the controller, but not during soft reset. So add HISI_SAS_NOT_ACCEPT_CMD_BIT to prevent executing a task during this period. 2. Send a broadcast event in rescan topology to detect any topology changes during reset. 3. Previously it was not ensured that libsas has processed the PHY up and down events after reset. Potentially this could cause an issue that we still process the PHY event after reset. So resolve this by flushing shot workqueue in LLDD reset. 4. Port ID requires refresh after reset. The port ID generated after reset is not guaranteed to be the same as before reset, so it needs to be refreshed for each device's ITCT. Signed-off-by: Xiaofei Tan Signed-off-by: John Garry --- drivers/scsi/hisi_sas/hisi_sas.h | 4 +- drivers/scsi/hisi_sas/hisi_sas_main.c | 152 ++++++++++++++++++++++----------- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 36 ++++---- 3 files changed, 118 insertions(+), 74 deletions(-) -- 1.9.1 diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index a722f2b..3c4defa 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -33,6 +33,7 @@ #define HISI_SAS_MAX_ITCT_ENTRIES 2048 #define HISI_SAS_MAX_DEVICES HISI_SAS_MAX_ITCT_ENTRIES #define HISI_SAS_RESET_BIT 0 +#define HISI_SAS_REJECT_CMD_BIT 1 #define HISI_SAS_STATUS_BUF_SZ (sizeof(struct hisi_sas_status_buffer)) #define HISI_SAS_COMMAND_TABLE_SZ (sizeof(union hisi_sas_command_table)) @@ -201,6 +202,7 @@ struct hisi_sas_hw { void (*dereg_device)(struct hisi_hba *hisi_hba, struct domain_device *device); int (*soft_reset)(struct hisi_hba *hisi_hba); + u32 (*get_phys_state)(struct hisi_hba *hisi_hba); int max_command_entries; int complete_hdr_size; }; @@ -408,6 +410,4 @@ extern void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, struct hisi_sas_slot *slot); extern void hisi_sas_init_mem(struct hisi_hba *hisi_hba); -extern void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state, - u32 state); #endif diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 4022c3f..bd1d619 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -433,7 +433,7 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_sas_dq *dq = sas_dev->dq; - if (unlikely(test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags))) + if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) return -EINVAL; /* protect task_prep and start_delivery sequence */ @@ -967,37 +967,117 @@ static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device, sizeof(ssp_task), tmf); } +static void hisi_sas_refresh_port_id(struct hisi_hba *hisi_hba, + struct asd_sas_port *sas_port, enum sas_linkrate linkrate) +{ + struct hisi_sas_device *sas_dev; + struct domain_device *device; + int i; + + for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) { + sas_dev = &hisi_hba->devices[i]; + device = sas_dev->sas_device; + if ((sas_dev->dev_type == SAS_PHY_UNUSED) + || !device || (device->port != sas_port)) + continue; + + hisi_hba->hw->free_device(hisi_hba, sas_dev); + + /* Update linkrate of directly attached device. */ + if (!device->parent) + device->linkrate = linkrate; + + hisi_hba->hw->setup_itct(hisi_hba, sas_dev); + } +} + +static void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state, + u32 state) +{ + struct sas_ha_struct *sas_ha = &hisi_hba->sha; + struct asd_sas_port *_sas_port = NULL; + int phy_no; + + for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) { + struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; + struct asd_sas_phy *sas_phy = &phy->sas_phy; + struct asd_sas_port *sas_port = sas_phy->port; + struct hisi_sas_port *port = to_hisi_sas_port(sas_port); + bool do_port_check = !!(_sas_port != sas_port); + + if (!sas_phy->phy->enabled) + continue; + + /* Report PHY state change to libsas */ + if (state & (1 << phy_no)) { + if (do_port_check && sas_port) { + struct domain_device *dev = sas_port->port_dev; + + _sas_port = sas_port; + port->id = phy->port_id; + hisi_sas_refresh_port_id(hisi_hba, + sas_port, sas_phy->linkrate); + + if (DEV_IS_EXPANDER(dev->dev_type)) + sas_ha->notify_port_event(sas_phy, + PORTE_BROADCAST_RCVD); + } + } else if (old_state & (1 << phy_no)) + /* PHY down but was up before */ + hisi_sas_phy_down(hisi_hba, phy_no, 0); + + } + + drain_workqueue(hisi_hba->shost->work_q); +} + static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba) { + struct sas_ha_struct *sas_ha = &hisi_hba->sha; + struct device *dev = hisi_hba->dev; + struct Scsi_Host *shost = hisi_hba->shost; + u32 old_state, state; + unsigned long flags; int rc; if (!hisi_hba->hw->soft_reset) return -1; - if (!test_and_set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) { - struct device *dev = hisi_hba->dev; - struct sas_ha_struct *sas_ha = &hisi_hba->sha; - unsigned long flags; + if (test_and_set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) + return -1; - dev_dbg(dev, "controller reset begins!\n"); - scsi_block_requests(hisi_hba->shost); - rc = hisi_hba->hw->soft_reset(hisi_hba); - if (rc) { - dev_warn(dev, "controller reset failed (%d)\n", rc); - goto out; - } - spin_lock_irqsave(&hisi_hba->lock, flags); - hisi_sas_release_tasks(hisi_hba); - spin_unlock_irqrestore(&hisi_hba->lock, flags); + dev_dbg(dev, "controller resetting...\n"); + old_state = hisi_hba->hw->get_phys_state(hisi_hba); - sas_ha->notify_ha_event(sas_ha, HAE_RESET); - dev_dbg(dev, "controller reset successful!\n"); - } else - return -1; + scsi_block_requests(shost); + set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); + rc = hisi_hba->hw->soft_reset(hisi_hba); + if (rc) { + dev_warn(dev, "controller reset failed (%d)\n", rc); + clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); + goto out; + } + spin_lock_irqsave(&hisi_hba->lock, flags); + hisi_sas_release_tasks(hisi_hba); + spin_unlock_irqrestore(&hisi_hba->lock, flags); + + sas_ha->notify_ha_event(sas_ha, HAE_RESET); + clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); + + /* Init and wait for PHYs to come up and all libsas event finished. */ + hisi_hba->hw->phys_init(hisi_hba); + msleep(1000); + drain_workqueue(hisi_hba->wq); + drain_workqueue(shost->work_q); + + state = hisi_hba->hw->get_phys_state(hisi_hba); + hisi_sas_rescan_topology(hisi_hba, old_state, state); + dev_dbg(dev, "controller reset complete\n"); out: - scsi_unblock_requests(hisi_hba->shost); + scsi_unblock_requests(shost); clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags); + return rc; } @@ -1241,7 +1321,7 @@ static int hisi_sas_query_task(struct sas_task *task) int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx; unsigned long flags, flags_dq; - if (unlikely(test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags))) + if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) return -EINVAL; if (!device->port) @@ -1437,36 +1517,6 @@ void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy) } EXPORT_SYMBOL_GPL(hisi_sas_phy_down); -void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state, - u32 state) -{ - struct sas_ha_struct *sas_ha = &hisi_hba->sha; - int phy_no; - - for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) { - struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; - struct asd_sas_phy *sas_phy = &phy->sas_phy; - struct asd_sas_port *sas_port = sas_phy->port; - struct domain_device *dev; - - if (sas_phy->enabled) { - /* Report PHY state change to libsas */ - if (state & (1 << phy_no)) - continue; - - if (old_state & (1 << phy_no)) - /* PHY down but was up before */ - hisi_sas_phy_down(hisi_hba, phy_no, 0); - } - if (!sas_port) - continue; - dev = sas_port->port_dev; - - if (DEV_IS_EXPANDER(dev->dev_type)) - sas_ha->notify_phy_event(sas_phy, PORTE_BROADCAST_RCVD); - } -} -EXPORT_SYMBOL_GPL(hisi_sas_rescan_topology); struct scsi_transport_template *hisi_sas_stt; EXPORT_SYMBOL_GPL(hisi_sas_stt); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 2bfea70..a6be33c 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1364,8 +1364,15 @@ static void start_phys_v2_hw(struct hisi_hba *hisi_hba) { int i; - for (i = 0; i < hisi_hba->n_phy; i++) + for (i = 0; i < hisi_hba->n_phy; i++) { + struct hisi_sas_phy *phy = &hisi_hba->phy[i]; + struct asd_sas_phy *sas_phy = &phy->sas_phy; + + if (!sas_phy->phy->enabled) + continue; + start_phy_v2_hw(hisi_hba, i); + } } static void phys_init_v2_hw(struct hisi_hba *hisi_hba) @@ -3383,14 +3390,16 @@ static void interrupt_disable_v2_hw(struct hisi_hba *hisi_hba) synchronize_irq(platform_get_irq(pdev, i)); } + +static u32 get_phys_state_v2_hw(struct hisi_hba *hisi_hba) +{ + return hisi_sas_read32(hisi_hba, PHY_STATE); +} + static int soft_reset_v2_hw(struct hisi_hba *hisi_hba) { struct device *dev = hisi_hba->dev; - u32 old_state, state; int rc, cnt; - int phy_no; - - old_state = hisi_sas_read32(hisi_hba, PHY_STATE); interrupt_disable_v2_hw(hisi_hba); hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0x0); @@ -3425,22 +3434,6 @@ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba) phys_reject_stp_links_v2_hw(hisi_hba); - /* Re-enable the PHYs */ - for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) { - struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; - struct asd_sas_phy *sas_phy = &phy->sas_phy; - - if (sas_phy->enabled) - start_phy_v2_hw(hisi_hba, phy_no); - } - - /* Wait for the PHYs to come up and read the PHY state */ - msleep(1000); - - state = hisi_sas_read32(hisi_hba, PHY_STATE); - - hisi_sas_rescan_topology(hisi_hba, old_state, state); - return 0; } @@ -3468,6 +3461,7 @@ static int soft_reset_v2_hw(struct hisi_hba *hisi_hba) .max_command_entries = HISI_SAS_COMMAND_ENTRIES_V2_HW, .complete_hdr_size = sizeof(struct hisi_sas_complete_v2_hdr), .soft_reset = soft_reset_v2_hw, + .get_phys_state = get_phys_state_v2_hw, }; static int hisi_sas_v2_probe(struct platform_device *pdev)