From patchwork Wed Apr 7 02:04:45 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kashyap Desai X-Patchwork-Id: 417120 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.6 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, MIME_HEADER_CTYPE_ONLY, SPF_HELO_NONE, SPF_PASS, T_TVD_MIME_NO_HEADERS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id DBD55C433B4 for ; Wed, 7 Apr 2021 02:05:01 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B6F87613B8 for ; Wed, 7 Apr 2021 02:05:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344341AbhDGCFJ (ORCPT ); Tue, 6 Apr 2021 22:05:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54090 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1343937AbhDGCFE (ORCPT ); Tue, 6 Apr 2021 22:05:04 -0400 Received: from mail-pj1-x1030.google.com (mail-pj1-x1030.google.com [IPv6:2607:f8b0:4864:20::1030]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2DC58C06174A for ; Tue, 6 Apr 2021 19:04:55 -0700 (PDT) Received: by mail-pj1-x1030.google.com with SMTP id j6-20020a17090adc86b02900cbfe6f2c96so477868pjv.1 for ; Tue, 06 Apr 2021 19:04:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=YX5BehSqINyFWb92hYA1qyioAcUKLII/VUPwpUCKl5Y=; b=I9YVmlfNyYPpzTsHgOpUHtWO9wIh6yWu2aSb1qyt1g9FXPkjJI2ApVwOlxBOVZYYIs nRdGYRNljpikvy9Wbck3e53mZ7UIKGK2UB1Z8l4arvqeKytsEnlEZfXx/6UiCelaEoVg SULmmFm0i/JzqpffU+rT7KNxylnOKPgGwVdE4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=YX5BehSqINyFWb92hYA1qyioAcUKLII/VUPwpUCKl5Y=; b=ZBV6ClpeSZlrFo6OlVDjpRd1Yp2HVais/l6JnTNNFj/pUin2ftBald9MD+8UPweLua +Jmi4wUetx9GS3gcoPI1BVEv+KmJeNTd1Po7q+7NgUAAduTGs16oyb5mK7p01Cvp7TG6 6knfJrBGXYTjcuHNzeFAKfi58L6mLDsVMnUydoFA89+1LrEQxSx+jtHIGBc4Ee7KyAsU kdJ2Q+EJ5i9A2ZYnx2gm8KY5kdJ5Bj70g4Xrb3ZQi4qlWeHspsB4/xz2S6wyY4hHHLKR XlI8CwhZQW75QJfZZbkVQO9UQN0gNtwpChStbSpupb32nnJe+xOf4UOeYhaWJIfJPhLd H9Jg== X-Gm-Message-State: AOAM533LoKNDjv/IhnWLAvPPzqTFNhM6y+uqfxBdmU+93mCIU2gOlAfk eEGw7J5OqhrzojbUIih3A6UYZCk+SgE26xjRUPumJLEwPoP7zxNw375cnXlPn0FjgDYmgskBeJv V+JsZiP6IL/wsci10qzX990LLwKcRmkv8KLYj9fqM3esrvmtDthb6cZKKOCDC/McXDHEFTw5WvR t2Fn21NQ== X-Google-Smtp-Source: ABdhPJzPPHVYpoPNhPQMgt2k7uhUW5S4RTx7P4gU2A4DLVqIVTyKx4eXhberHHe3URS7eLQr+UXU/A== X-Received: by 2002:a17:902:6b02:b029:e9:8e2:d107 with SMTP id o2-20020a1709026b02b02900e908e2d107mr902365plk.61.1617761094081; Tue, 06 Apr 2021 19:04:54 -0700 (PDT) Received: from drv-bst-rhel8.dhcp.broadcom.net ([192.19.234.250]) by smtp.gmail.com with ESMTPSA id y9sm3435858pja.50.2021.04.06.19.04.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 06 Apr 2021 19:04:53 -0700 (PDT) From: Kashyap Desai To: linux-scsi@vger.kernel.org Cc: Kashyap Desai , sathya.prakash@broadcom.com Subject: [PATCH v2 18/24] mpi3mr: add complete support of soft reset Date: Wed, 7 Apr 2021 07:34:45 +0530 Message-Id: <20210407020451.924822-19-kashyap.desai@broadcom.com> X-Mailer: git-send-email 2.18.1 In-Reply-To: <20210407020451.924822-1-kashyap.desai@broadcom.com> References: <20210407020451.924822-1-kashyap.desai@broadcom.com> Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org Unlock the host diagnostic registers and write the specific reset type to that, wait for reset acknowledgment from the controller, if the reset is not successful retry for the predefined number of times Signed-off-by: Kashyap Desai Reviewed-by: Hannes Reinecke Cc: sathya.prakash@broadcom.com Reviewed-by: Tomas Henzl --- drivers/scsi/mpi3mr/mpi3mr.h | 3 + drivers/scsi/mpi3mr/mpi3mr_fw.c | 245 +++++++++++++++++++++++++++++++- 2 files changed, 246 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 3ac7b0f119bb..ff3e68a6d0b5 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -189,6 +189,9 @@ enum mpi3mr_reset_reason { MPI3MR_RESET_FROM_EVTACK_TIMEOUT = 19, MPI3MR_RESET_FROM_CIACTVRST_TIMER = 20, MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT = 21, + MPI3MR_RESET_FROM_PELABORT_TIMEOUT = 22, + MPI3MR_RESET_FROM_SYSFS = 23, + MPI3MR_RESET_FROM_SYSFS_TIMEOUT = 24 }; /** diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 32b79876f0d2..79a9f98c736e 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -642,6 +642,100 @@ static const char *mpi3mr_iocstate_name(enum mpi3mr_iocstate mrioc_state) return name; } +/* Reset reason to name mapper structure*/ +static const struct { + enum mpi3mr_reset_reason value; + char *name; +} mpi3mr_reset_reason_codes[] = { + { MPI3MR_RESET_FROM_BRINGUP, "timeout in bringup" }, + { MPI3MR_RESET_FROM_FAULT_WATCH, "fault" }, + { MPI3MR_RESET_FROM_IOCTL, "application invocation" }, + { MPI3MR_RESET_FROM_EH_HOS, "error handling" }, + { MPI3MR_RESET_FROM_TM_TIMEOUT, "TM timeout" }, + { MPI3MR_RESET_FROM_IOCTL_TIMEOUT, "IOCTL timeout" }, + { MPI3MR_RESET_FROM_MUR_FAILURE, "MUR failure" }, + { MPI3MR_RESET_FROM_CTLR_CLEANUP, "timeout in controller cleanup" }, + { MPI3MR_RESET_FROM_CIACTIV_FAULT, "component image activation fault" }, + { MPI3MR_RESET_FROM_PE_TIMEOUT, "port enable timeout" }, + { MPI3MR_RESET_FROM_TSU_TIMEOUT, "time stamp update timeout" }, + { MPI3MR_RESET_FROM_DELREQQ_TIMEOUT, "delete request queue timeout" }, + { MPI3MR_RESET_FROM_DELREPQ_TIMEOUT, "delete reply queue timeout" }, + { + MPI3MR_RESET_FROM_CREATEREPQ_TIMEOUT, + "create request queue timeout" + }, + { + MPI3MR_RESET_FROM_CREATEREQQ_TIMEOUT, + "create reply queue timeout" + }, + { MPI3MR_RESET_FROM_IOCFACTS_TIMEOUT, "IOC facts timeout" }, + { MPI3MR_RESET_FROM_IOCINIT_TIMEOUT, "IOC init timeout" }, + { MPI3MR_RESET_FROM_EVTNOTIFY_TIMEOUT, "event notify timeout" }, + { MPI3MR_RESET_FROM_EVTACK_TIMEOUT, "event acknowledgment timeout" }, + { + MPI3MR_RESET_FROM_CIACTVRST_TIMER, + "component image activation timeout" + }, + { + MPI3MR_RESET_FROM_GETPKGVER_TIMEOUT, + "get package version timeout" + }, + { MPI3MR_RESET_FROM_SYSFS, "sysfs invocation" }, + { MPI3MR_RESET_FROM_SYSFS_TIMEOUT, "sysfs TM timeout" }, +}; + +/** + * mpi3mr_reset_rc_name - get reset reason code name + * @reason_code: reset reason code value + * + * Map reset reason to an NULL terminated ASCII string + * + * Return: Name corresponding to reset reason value or NULL. + */ +static const char *mpi3mr_reset_rc_name(enum mpi3mr_reset_reason reason_code) +{ + int i; + char *name = NULL; + + for (i = 0; i < ARRAY_SIZE(mpi3mr_reset_reason_codes); i++) { + if (mpi3mr_reset_reason_codes[i].value == reason_code) { + name = mpi3mr_reset_reason_codes[i].name; + break; + } + } + return name; +} + +/* Reset type to name mapper structure*/ +static const struct { + u16 reset_type; + char *name; +} mpi3mr_reset_types[] = { + { MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, "soft" }, + { MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, "diag fault" }, +}; + +/** + * mpi3mr_reset_type_name - get reset type name + * reset_type: reset type value + * + * Map reset type to an NULL terminated ASCII string + * + * Return: Name corresponding to reset type value or NULL. + */ +static const char *mpi3mr_reset_type_name(u16 reset_type) +{ + int i; + char *name = NULL; + + for (i = 0; i < ARRAY_SIZE(mpi3mr_reset_types); i++) { + if (mpi3mr_reset_types[i].reset_type == reset_type) { + name = mpi3mr_reset_types[i].name; + break; + } + } + return name; +} /** * mpi3mr_print_fault_info - Display fault information @@ -805,6 +899,48 @@ static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc) return -1; } +/** + * mpi3mr_soft_reset_success - Check softreset is success or not + * @ioc_status: IOC status register value + * @ioc_config: IOC config register value + * + * Check whether the soft reset is successful or not based on + * IOC status and IOC config register values. + * + * Return: True when the soft reset is success, false otherwise. + */ +static inline bool +mpi3mr_soft_reset_success(u32 ioc_status, u32 ioc_config) +{ + if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) || + (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) || + (ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) + return true; + return false; +} + +/** + * mpi3mr_diagfault_success - Check diag fault is success or not + * @mrioc: Adapter reference + * @ioc_status: IOC status register value + * + * Check whether the controller hit diag reset fault code. + * + * Return: True when there is diag fault, false otherwise. + */ +static inline bool mpi3mr_diagfault_success(struct mpi3mr_ioc *mrioc, + u32 ioc_status) +{ + u32 fault; + + if (!(ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) + return false; + fault = readl(&mrioc->sysif_regs->Fault) & MPI3_SYSIF_FAULT_CODE_MASK; + if (fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET) + return true; + return false; +} + /** * mpi3mr_set_diagsave - Set diag save bit for snapdump * @mrioc: Adapter reference @@ -829,14 +965,117 @@ static inline void mpi3mr_set_diagsave(struct mpi3mr_ioc *mrioc) * @reset_type: Reset type * @reset_reason: Reset reason code * - * TBD + * Unlock the host diagnostic registers and write the specific + * reset type to that, wait for reset acknowledgment from the + * controller, if the reset is not successful retry for the + * predefined number of times. * * Return: 0 on success, non-zero on failure. */ static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, u32 reset_reason) { - return 0; + int retval = -1; + u8 unlock_retry_count, reset_retry_count = 0; + u32 host_diagnostic, timeout, ioc_status, ioc_config; + + pci_cfg_access_lock(mrioc->pdev); + if ((reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET) && + (reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT)) + goto out; + if (mrioc->unrecoverable) + goto out; +retry_reset: + unlock_retry_count = 0; + mpi3mr_clear_reset_history(mrioc); + do { + ioc_info(mrioc, + "Write magic sequence to unlock host diag register (retry=%d)\n", + ++unlock_retry_count); + if (unlock_retry_count >= MPI3MR_HOSTDIAG_UNLOCK_RETRY_COUNT) { + writel(reset_reason, &mrioc->sysif_regs->Scratchpad[0]); + mrioc->unrecoverable = 1; + goto out; + } + + writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_FLUSH, + &mrioc->sysif_regs->WriteSequence); + writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_1ST, + &mrioc->sysif_regs->WriteSequence); + writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND, + &mrioc->sysif_regs->WriteSequence); + writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_3RD, + &mrioc->sysif_regs->WriteSequence); + writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_4TH, + &mrioc->sysif_regs->WriteSequence); + writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_5TH, + &mrioc->sysif_regs->WriteSequence); + writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_6TH, + &mrioc->sysif_regs->WriteSequence); + usleep_range(1000, 1100); + host_diagnostic = readl(&mrioc->sysif_regs->HostDiagnostic); + ioc_info(mrioc, + "wrote magic sequence: retry_count(%d), host_diagnostic(0x%08x)\n", + unlock_retry_count, host_diagnostic); + } while (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_DIAG_WRITE_ENABLE)); + + writel(reset_reason, &mrioc->sysif_regs->Scratchpad[0]); + ioc_info(mrioc, "%s reset due to %s(0x%x)\n", + mpi3mr_reset_type_name(reset_type), + mpi3mr_reset_rc_name(reset_reason), reset_reason); + writel(host_diagnostic | reset_type, + &mrioc->sysif_regs->HostDiagnostic); + timeout = mrioc->ready_timeout * 10; + if (reset_type == MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET) { + do { + ioc_status = readl(&mrioc->sysif_regs->IOCStatus); + if (ioc_status & + MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) { + mpi3mr_clear_reset_history(mrioc); + ioc_config = + readl(&mrioc->sysif_regs->IOCConfiguration); + if (mpi3mr_soft_reset_success(ioc_status, + ioc_config)) { + retval = 0; + break; + } + } + msleep(100); + } while (--timeout); + writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND, + &mrioc->sysif_regs->WriteSequence); + } else if (reset_type == MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT) { + do { + ioc_status = readl(&mrioc->sysif_regs->IOCStatus); + if (mpi3mr_diagfault_success(mrioc, ioc_status)) { + retval = 0; + break; + } + msleep(100); + } while (--timeout); + mpi3mr_clear_reset_history(mrioc); + writel(MPI3_SYSIF_WRITE_SEQUENCE_KEY_VALUE_2ND, + &mrioc->sysif_regs->WriteSequence); + } + if (retval && ((++reset_retry_count) < MPI3MR_MAX_RESET_RETRY_COUNT)) { + ioc_status = readl(&mrioc->sysif_regs->IOCStatus); + ioc_config = readl(&mrioc->sysif_regs->IOCConfiguration); + ioc_info(mrioc, + "Base IOC Sts/Config after reset try %d is (0x%x)/(0x%x)\n", + reset_retry_count, ioc_status, ioc_config); + goto retry_reset; + } + +out: + pci_cfg_access_unlock(mrioc->pdev); + ioc_status = readl(&mrioc->sysif_regs->IOCStatus); + ioc_config = readl(&mrioc->sysif_regs->IOCConfiguration); + + ioc_info(mrioc, + "Base IOC Sts/Config after %s reset is (0x%x)/(0x%x)\n", + (!retval)?"successful":"failed", ioc_status, + ioc_config); + return retval; } /** @@ -3458,6 +3697,8 @@ int mpi3mr_diagfault_reset_handler(struct mpi3mr_ioc *mrioc, { int retval = 0; + ioc_info(mrioc, "Entry: reason code: %s\n", + mpi3mr_reset_rc_name(reset_reason)); mrioc->reset_in_progress = 1; mpi3mr_ioc_disable_intr(mrioc);