From patchwork Mon Apr 10 13:21:57 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Garry X-Patchwork-Id: 9672523 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 550E260244 for ; Mon, 10 Apr 2017 12:52:50 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 46F412844C for ; Mon, 10 Apr 2017 12:52:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3861928462; Mon, 10 Apr 2017 12:52:50 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 997822844C for ; Mon, 10 Apr 2017 12:52:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753238AbdDJMwg (ORCPT ); Mon, 10 Apr 2017 08:52:36 -0400 Received: from szxga03-in.huawei.com ([45.249.212.189]:5428 "EHLO dggrg03-dlp.huawei.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753394AbdDJMw2 (ORCPT ); Mon, 10 Apr 2017 08:52:28 -0400 Received: from 172.30.72.57 (EHLO DGGEML401-HUB.china.huawei.com) ([172.30.72.57]) by dggrg03-dlp.huawei.com (MOS 4.4.6-GA FastPath queued) with ESMTP id ALL62809; Mon, 10 Apr 2017 20:52:14 +0800 (CST) Received: from localhost.localdomain (10.67.212.75) by DGGEML401-HUB.china.huawei.com (10.3.17.32) with Microsoft SMTP Server id 14.3.301.0; Mon, 10 Apr 2017 20:52:03 +0800 From: John Garry To: , CC: , , , , , Xiaofei Tan , John Garry Subject: [PATCH 2/6] scsi: hisi_sas: workaround a SoC SATA IO processing bug Date: Mon, 10 Apr 2017 21:21:57 +0800 Message-ID: <1491830521-21437-3-git-send-email-john.garry@huawei.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1491830521-21437-1-git-send-email-john.garry@huawei.com> References: <1491830521-21437-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.0A020206.58EB7FFF.009C, 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: 908d51206fcd394cf64b7e0cdbbb63b8 Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Xiaofei Tan This patch provides a workaround a SoC bug where SATA IPTTs for different devices may conflict. The workaround solution requests the following: 1. SATA device id must be even and not equal to SAS IPTT. 2. SATA device can not share the same IPTT with other SAS or SATA device. Besides we shall consider IPTT value 0 is reserved for another SoC bug (STP device open link at firstly after SAS controller reset). To sum up, the solution is: Each SATA device uses independent and continuous 32 even IPTT from 64 to 4094, then v2 hw can only support 63 SATA devices. All SAS device(SSP/SMP devices) share odd IPTT value from 1 to 4095. Signed-off-by: Xiaofei Tan Signed-off-by: John Garry Reviewed-by: Johannes Thumshirn --- drivers/scsi/hisi_sas/hisi_sas.h | 2 + drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 83 ++++++++++++++++++++++++++++------ 2 files changed, 72 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 72347b6..c80ca83 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -115,6 +115,7 @@ struct hisi_sas_device { atomic64_t running_req; struct list_head list; u8 dev_status; + int sata_idx; }; struct hisi_sas_slot { @@ -238,6 +239,7 @@ struct hisi_hba { struct hisi_sas_slot *slot_info; unsigned long flags; const struct hisi_sas_hw *hw; /* Low level hw interface */ + unsigned long sata_dev_bitmap[BITS_TO_LONGS(HISI_SAS_MAX_DEVICES)]; struct work_struct rst_work; }; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index c550cc4..fc8d8296 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -537,6 +537,7 @@ enum { }; #define HISI_SAS_COMMAND_ENTRIES_V2_HW 4096 +#define HISI_MAX_SATA_SUPPORT_V2_HW (HISI_SAS_COMMAND_ENTRIES_V2_HW/64 - 1) #define DIR_NO_DATA 0 #define DIR_TO_INI 1 @@ -597,39 +598,86 @@ static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba, /* This function needs to be protected from pre-emption. */ static int slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, int *slot_idx, - struct domain_device *device) + struct domain_device *device) { - /* STP link chip bug workaround:index start from 1 */ - unsigned int index = 1; - void *bitmap = hisi_hba->slot_index_tags; int sata_dev = dev_is_sata(device); + void *bitmap = hisi_hba->slot_index_tags; + struct hisi_sas_device *sas_dev = device->lldd_dev; + int sata_idx = sas_dev->sata_idx; + int start, end; + + if (!sata_dev) { + /* + * STP link SoC bug workaround: index starts from 1. + * additionally, we can only allocate odd IPTT(1~4095) + * for SAS/SMP device. + */ + start = 1; + end = hisi_hba->slot_index_count; + } else { + if (sata_idx >= HISI_MAX_SATA_SUPPORT_V2_HW) + return -EINVAL; + + /* + * For SATA device: allocate even IPTT in this interval + * [64*(sata_idx+1), 64*(sata_idx+2)], then each SATA device + * own 32 IPTTs. IPTT 0 shall not be used duing to STP link + * SoC bug workaround. So we ignore the first 32 even IPTTs. + */ + start = 64 * (sata_idx + 1); + end = 64 * (sata_idx + 2); + } while (1) { - index = find_next_zero_bit(bitmap, hisi_hba->slot_index_count, - index); - if (index >= hisi_hba->slot_index_count) + start = find_next_zero_bit(bitmap, + hisi_hba->slot_index_count, start); + if (start >= end) return -SAS_QUEUE_FULL; /* - * SAS IPTT bit0 should be 1 - */ - if (sata_dev || (index & 1)) + * SAS IPTT bit0 should be 1, and SATA IPTT bit0 should be 0. + */ + if (sata_dev ^ (start & 1)) break; - index++; + start++; } - set_bit(index, bitmap); - *slot_idx = index; + set_bit(start, bitmap); + *slot_idx = start; return 0; } +static bool sata_index_alloc_v2_hw(struct hisi_hba *hisi_hba, int *idx) +{ + unsigned int index; + struct device *dev = &hisi_hba->pdev->dev; + void *bitmap = hisi_hba->sata_dev_bitmap; + + index = find_first_zero_bit(bitmap, HISI_MAX_SATA_SUPPORT_V2_HW); + if (index >= HISI_MAX_SATA_SUPPORT_V2_HW) { + dev_warn(dev, "alloc sata index failed, index=%d\n", index); + return false; + } + + set_bit(index, bitmap); + *idx = index; + return true; +} + + static struct hisi_sas_device *alloc_dev_quirk_v2_hw(struct domain_device *device) { struct hisi_hba *hisi_hba = device->port->ha->lldd_ha; struct hisi_sas_device *sas_dev = NULL; int i, sata_dev = dev_is_sata(device); + int sata_idx = -1; spin_lock(&hisi_hba->lock); + + if (sata_dev) + if (!sata_index_alloc_v2_hw(hisi_hba, &sata_idx)) + goto out; + for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) { /* * SATA device id bit0 should be 0 @@ -643,10 +691,13 @@ hisi_sas_device *alloc_dev_quirk_v2_hw(struct domain_device *device) sas_dev->dev_type = device->dev_type; sas_dev->hisi_hba = hisi_hba; sas_dev->sas_device = device; + sas_dev->sata_idx = sata_idx; INIT_LIST_HEAD(&hisi_hba->devices[i].list); break; } } + +out: spin_unlock(&hisi_hba->lock); return sas_dev; @@ -753,6 +804,10 @@ static void free_device_v2_hw(struct hisi_hba *hisi_hba, u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3); int i; + /* SoC bug workaround */ + if (dev_is_sata(sas_dev->sas_device)) + clear_bit(sas_dev->sata_idx, hisi_hba->sata_dev_bitmap); + /* clear the itct interrupt state */ if (ENT_INT_SRC3_ITC_INT_MSK & reg_val) hisi_sas_write32(hisi_hba, ENT_INT_SRC3, @@ -3197,6 +3252,8 @@ static int hisi_sas_v2_init(struct hisi_hba *hisi_hba) { int rc; + memset(hisi_hba->sata_dev_bitmap, 0, sizeof(hisi_hba->sata_dev_bitmap)); + rc = hw_init_v2_hw(hisi_hba); if (rc) return rc;