From patchwork Wed May 2 15:56:26 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Garry X-Patchwork-Id: 134844 Delivered-To: patch@linaro.org Received: by 10.46.151.6 with SMTP id r6csp847408lji; Wed, 2 May 2018 08:58:47 -0700 (PDT) X-Google-Smtp-Source: AB8JxZqD2a8aEGmMUjiCBE5GPX8/k+Jws1Dqtv3l59smtdgCc6XjdcbW/NeMXHkRKXoLpWS0MpXH X-Received: by 2002:a63:41c7:: with SMTP id o190-v6mr16971972pga.57.1525276727054; Wed, 02 May 2018 08:58:47 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1525276727; cv=none; d=google.com; s=arc-20160816; b=Jq3xeym3OmI91L1iAbxRRCduqvVbhB40j4RC3xIbBMKL/69+EeLK1g0FAsN0WX7JiC c2xBdigwaNNl3IrF7Zj7O02JwVRWFUSgf/olPpYEtTsf0xrGizJZu1PHFiKSwX/Of6xC FaT+ahY3z4D/uhm7R6k+92AfoQUTmoIGBVy7J2jbdePUQkjOZg7Ypc/K90thD6QSe/om 2mmLB/m98EFGL171B8rYBOjdk/7L3G65eiMopa/nfVJyMOSkYFGZg0xzvGG8R79lKc/g EZ6NuImftK8QDF8HNuCpRinCpGwPLcUa+W+A6si9ol88HdcW4hVi/oxy24lR8cOd/HuV 0B1w== 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=wsiPeIouvfDPi03du5m4TpBRya9/YWrDfVsPxzXYyUo=; b=0hAEsYoytk4iXiNa6K3qjeFERZPWfSM/UVrPRPkXWag4UTsuh3goYV0uGLqlG8YK9T /WqABAjI6/WoiC6XTtQaUedziiNTy4xysyQNBti60fJeYWX/oAMbbPlmFKPn7N2qQMaP vgV/bJVZLTgysr0FSIXEr/BoEevmGov0GV4u9rxVvhIa44ALJP2MgyTCIywquIGDjkmK 1EmdY4GjavKOmNxYhGMOPOxVy3rTOBMTEDNfKlYP/yZDX8m1iLucKDRoY2Ol18bytJIr ddrWHw7n+w9qnrjjW2APW7FEbVvGpOopvEjpabRDEh+mlzYGfAO/WALHYJ7E1MRUDafY xvXA== 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 j1-v6si9518057pgv.688.2018.05.02.08.58.46; Wed, 02 May 2018 08:58:47 -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 S1752156AbeEBP6o (ORCPT + 29 others); Wed, 2 May 2018 11:58:44 -0400 Received: from szxga06-in.huawei.com ([45.249.212.32]:54591 "EHLO huawei.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1751755AbeEBP53 (ORCPT ); Wed, 2 May 2018 11:57:29 -0400 Received: from DGGEMS403-HUB.china.huawei.com (unknown [172.30.72.58]) by Forcepoint Email with ESMTP id 333FF25E96A7D; Wed, 2 May 2018 23:57:24 +0800 (CST) Received: from localhost.localdomain (10.67.212.75) by DGGEMS403-HUB.china.huawei.com (10.3.19.203) with Microsoft SMTP Server id 14.3.361.1; Wed, 2 May 2018 23:57:16 +0800 From: John Garry To: , CC: , , , Xiang Chen , "John Garry" Subject: [PATCH 03/11] scsi: hisi_sas: check host frozen before calling "done" function Date: Wed, 2 May 2018 23:56:26 +0800 Message-ID: <1525276594-92173-4-git-send-email-john.garry@huawei.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1525276594-92173-1-git-send-email-john.garry@huawei.com> References: <1525276594-92173-1-git-send-email-john.garry@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.67.212.75] X-CFilter-Loop: Reflected Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Xiang Chen When the host is frozen in SCSI EH state, at any point after the LLDD sets SAS_TASK_STATE_DONE for the sas_task task state, libsas may free the task; see sas_scsi_find_task(). This puts the LLDD in a difficult position, in that once it sets SAS_TASK_STATE_DONE for the task state it should not reference the sas_task again. But the LLDD needs will check the sas_task indirectly in calling task->task_done()->sas_scsi_task_done() or sas_ata_task_done() (to check if the host is frozen state actually). And the LLDD cannot set SAS_TASK_STATE_DONE for the task state after task->task_done() is called (as the sas_task is free'd at this point). This situation would seem to be a problem made by libsas. To work around, check in the LLDD whether the host is in frozen state to ensure it is ok to call task->task_done() function. If in the frozen state, we rely on SCSI EH and libsas to free the sas_task directly. We do not do this for the following IO types: - SMP - they are managed in libsas directly, outside SCSI EH - Any internally originated IO, for similar reason Signed-off-by: Xiang Chen Signed-off-by: John Garry --- drivers/scsi/hisi_sas/hisi_sas.h | 1 + drivers/scsi/hisi_sas/hisi_sas_main.c | 3 +++ drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 14 ++++++++++++++ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 14 ++++++++++++++ 4 files changed, 32 insertions(+) -- 1.9.1 diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index d413d05..147cfaf 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -196,6 +196,7 @@ struct hisi_sas_slot { dma_addr_t cmd_hdr_dma; struct work_struct abort_slot; struct timer_list internal_abort_timer; + bool is_internal; }; struct hisi_sas_tmf_task { diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 52746e2..8f8e642 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -382,6 +382,8 @@ static int hisi_sas_task_prep(struct sas_task *task, struct hisi_sas_dq slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot]; slot->task = task; slot->port = port; + if (is_tmf) + slot->is_internal = true; task->lldd_task = slot; INIT_WORK(&slot->abort_slot, hisi_sas_slot_abort); @@ -1486,6 +1488,7 @@ static int hisi_sas_query_task(struct sas_task *task) slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot]; slot->task = task; slot->port = port; + slot->is_internal = true; task->lldd_task = slot; slot->buf = dma_pool_alloc(hisi_hba->buffer_pool, diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 8ca0044..6dda6eb 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -2380,18 +2380,21 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, struct device *dev = hisi_hba->dev; struct task_status_struct *ts; struct domain_device *device; + struct sas_ha_struct *ha; enum exec_status sts; struct hisi_sas_complete_v2_hdr *complete_queue = hisi_hba->complete_hdr[slot->cmplt_queue]; struct hisi_sas_complete_v2_hdr *complete_hdr = &complete_queue[slot->cmplt_queue_slot]; unsigned long flags; + bool is_internal = slot->is_internal; if (unlikely(!task || !task->lldd_task || !task->dev)) return -EINVAL; ts = &task->task_status; device = task->dev; + ha = device->port->ha; sas_dev = device->lldd_dev; spin_lock_irqsave(&task->task_state_lock, flags); @@ -2523,6 +2526,17 @@ static void slot_err_v2_hw(struct hisi_hba *hisi_hba, task->task_state_flags |= SAS_TASK_STATE_DONE; spin_unlock_irqrestore(&task->task_state_lock, flags); + if (!is_internal && (task->task_proto != SAS_PROTOCOL_SMP)) { + spin_lock_irqsave(&device->done_lock, flags); + if (test_bit(SAS_HA_FROZEN, &ha->state)) { + spin_unlock_irqrestore(&device->done_lock, flags); + dev_info(dev, "slot complete: task(%p) ignored\n ", + task); + return sts; + } + spin_unlock_irqrestore(&device->done_lock, flags); + } + if (task->task_done) task->task_done(task); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 7346110..5c0d968 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -1571,18 +1571,21 @@ static irqreturn_t fatal_axi_int_v3_hw(int irq_no, void *p) struct device *dev = hisi_hba->dev; struct task_status_struct *ts; struct domain_device *device; + struct sas_ha_struct *ha; enum exec_status sts; struct hisi_sas_complete_v3_hdr *complete_queue = hisi_hba->complete_hdr[slot->cmplt_queue]; struct hisi_sas_complete_v3_hdr *complete_hdr = &complete_queue[slot->cmplt_queue_slot]; unsigned long flags; + bool is_internal = slot->is_internal; if (unlikely(!task || !task->lldd_task || !task->dev)) return -EINVAL; ts = &task->task_status; device = task->dev; + ha = device->port->ha; sas_dev = device->lldd_dev; spin_lock_irqsave(&task->task_state_lock, flags); @@ -1700,6 +1703,17 @@ static irqreturn_t fatal_axi_int_v3_hw(int irq_no, void *p) task->task_state_flags |= SAS_TASK_STATE_DONE; spin_unlock_irqrestore(&task->task_state_lock, flags); + if (!is_internal && (task->task_proto != SAS_PROTOCOL_SMP)) { + spin_lock_irqsave(&device->done_lock, flags); + if (test_bit(SAS_HA_FROZEN, &ha->state)) { + spin_unlock_irqrestore(&device->done_lock, flags); + dev_info(dev, "slot complete: task(%p) ignored\n ", + task); + return sts; + } + spin_unlock_irqrestore(&device->done_lock, flags); + } + if (task->task_done) task->task_done(task);