Received: by 2002:a25:ab43:0:0:0:0:0 with SMTP id u61csp2814213ybi; Mon, 17 Jun 2019 10:51:19 -0700 (PDT) X-Google-Smtp-Source: APXvYqziuMRFL6F82TOq5fUPfXiavDNO0P4I+68LpGasjLGnQyyz8qcfOd2YHKDn0lrlCa8PkO2V X-Received: by 2002:a17:90a:9201:: with SMTP id m1mr27426806pjo.38.1560793876595; Mon, 17 Jun 2019 10:51:16 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1560793876; cv=none; d=google.com; s=arc-20160816; b=fQiyCMSJVKM7ssCiwL9FTbcm4/vv0jMrJmTPvskRVCRLaudgBl7vEnmbbMLLAYps9k LUut+y2gSJaiTfC7/zlZ05nyBNqN6yaQmeAzyOesXs/FYyjUjkmo4CTkCbURkAuiLUDa FYW3RtNEI0Uaadw6PS/WRW1XSzHPjwYgdaJA8tFM+hk8iAxa7ayuK/PZhXDg/hknVY7f kVHvdgb67RezhU/Fxo97ho+OQFhtq4LhHnXA3y33LgtUNUPew/ku+nK7tV6ozwFom5/U rsovsymwaCyPvPdFVzmhTjSDuZY4pirht+sIs4YrvZvTBnQuYT10jbo+fuozz3SS4kFt /CGg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:date:subject:cc:to:from; bh=C7SbQhWNiSzM850eEF3TlI/IPyaeVqNyGOEcA+fwGBs=; b=xDAkchWxyJQVhW9DJ8/UwAtMEPfSs+bqzGsxBl7CI/qjPn3olQIICNVi6+0e+KqW/y kM47vPNpGyJCCqhQrQDVuTcJ34itnMfriIxP+6/3MAUojKFnU4dvOOrruwMN4ls78exn altd49y2mPW42lVo7RP2FlgVJ7BMrZ4fmoh/0jPFHVb30MvP9D2v3UXyN6T73esKHCOM vmXl1y0qBtHHBoAiYnc63dA0CFKUCNcYqBD+VHlk9bcThkoopx2gm6v7S3jiyhLuIWT3 DwrKIpxO+zOuPv+PHkrb3imKuLe5TzeTcXXTNYW2RJr7AhX8He4fCJr5pCfCeFg63XxQ 7/zA== 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 a64si2754854pla.432.2019.06.17.10.51.01; Mon, 17 Jun 2019 10:51:16 -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 S1728629AbfFQRui (ORCPT + 99 others); Mon, 17 Jun 2019 13:50:38 -0400 Received: from hosting.gsystem.sk ([212.5.213.30]:50658 "EHLO hosting.gsystem.sk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726047AbfFQRuh (ORCPT ); Mon, 17 Jun 2019 13:50:37 -0400 Received: from gsql.ggedos.sk (off-20.infotel.telecom.sk [212.5.213.20]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by hosting.gsystem.sk (Postfix) with ESMTPSA id 408E47A03E0; Mon, 17 Jun 2019 19:50:36 +0200 (CEST) From: Ondrej Zary To: Hariprasad Kelam Cc: "James E . J . Bottomley" , David Rientjes , "Martin K . Petersen" , linux-scsi@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH] [resend] wd719x: Fix resets and aborts Date: Mon, 17 Jun 2019 19:50:12 +0200 Message-Id: <20190617175012.25323-1-linux@zary.sk> X-Mailer: git-send-email 2.11.0 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Host reset oopses because it calls wd719x_chip_init, which calls request_firmware, under a spinlock. Stop the RISC first, then flush active SCBs under a spinlock. Finally call wd719x_chip_init unlocked. Also found and fixed more bugs during tests: Affected active SCBs were not flushed during abort, bus and device reset. This caused problems in a following host reset (hang or oops). Device and bus reset failed under load because the result of the reset command is WD719X_SUE_TERM or WD719X_SUE_RESET. Don't treat these codes as error in wd719x_wait_done. wd719x_direct_cmd for RESET/ABORT commands didn't work properly, causing timeouts. Looks like it was caused by the WD719X_DISABLE_INT bit. Not setting it for RESET/ABORT commands seems to fix the probem. Also lower the log level of the corresponding "direct command completed" message to debug. Unfortunately, my documentation is missing some pages, including page 67 (SPIDER67.gif) about resets :( Reported-by: Hariprasad Kelam Signed-off-by: Ondrej Zary --- drivers/scsi/wd719x.c | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/wd719x.c b/drivers/scsi/wd719x.c index e3310e9488d2..2b44b0be2e00 100644 --- a/drivers/scsi/wd719x.c +++ b/drivers/scsi/wd719x.c @@ -107,8 +107,15 @@ static inline int wd719x_wait_done(struct wd719x *wd, int timeout) } if (status != WD719X_INT_NOERRORS) { + u8 sue = wd719x_readb(wd, WD719X_AMR_SCB_ERROR); + /* we get this after wd719x_dev_reset, it's not an error */ + if (sue == WD719X_SUE_TERM) + return 0; + /* we get this after wd719x_bus_reset, it's not an error */ + if (sue == WD719X_SUE_RESET) + return 0; dev_err(&wd->pdev->dev, "direct command failed, status 0x%02x, SUE 0x%02x\n", - status, wd719x_readb(wd, WD719X_AMR_SCB_ERROR)); + status, sue); return -EIO; } @@ -127,8 +134,10 @@ static int wd719x_direct_cmd(struct wd719x *wd, u8 opcode, u8 dev, u8 lun, if (wd719x_wait_ready(wd)) return -ETIMEDOUT; - /* make sure we get NO interrupts */ - dev |= WD719X_DISABLE_INT; + /* disable interrupts except for RESET/ABORT (it breaks them) */ + if (opcode != WD719X_CMD_BUSRESET && opcode != WD719X_CMD_ABORT && + opcode != WD719X_CMD_ABORT_TAG && opcode != WD719X_CMD_RESET) + dev |= WD719X_DISABLE_INT; wd719x_writeb(wd, WD719X_AMR_CMD_PARAM, dev); wd719x_writeb(wd, WD719X_AMR_CMD_PARAM_2, lun); wd719x_writeb(wd, WD719X_AMR_CMD_PARAM_3, tag); @@ -464,6 +473,7 @@ static int wd719x_abort(struct scsi_cmnd *cmd) spin_lock_irqsave(wd->sh->host_lock, flags); result = wd719x_direct_cmd(wd, action, cmd->device->id, cmd->device->lun, cmd->tag, scb->phys, 0); + wd719x_finish_cmd(scb, DID_ABORT); spin_unlock_irqrestore(wd->sh->host_lock, flags); if (result) return FAILED; @@ -476,6 +486,7 @@ static int wd719x_reset(struct scsi_cmnd *cmd, u8 opcode, u8 device) int result; unsigned long flags; struct wd719x *wd = shost_priv(cmd->device->host); + struct wd719x_scb *scb, *tmp; dev_info(&wd->pdev->dev, "%s reset requested\n", (opcode == WD719X_CMD_BUSRESET) ? "bus" : "device"); @@ -483,6 +494,12 @@ static int wd719x_reset(struct scsi_cmnd *cmd, u8 opcode, u8 device) spin_lock_irqsave(wd->sh->host_lock, flags); result = wd719x_direct_cmd(wd, opcode, device, 0, 0, 0, WD719X_WAIT_FOR_SCSI_RESET); + /* flush all SCBs (or all for a device if dev_reset) */ + list_for_each_entry_safe(scb, tmp, &wd->active_scbs, list) { + if (opcode == WD719X_CMD_BUSRESET || + scb->cmd->device->id == device) + wd719x_finish_cmd(scb, DID_RESET); + } spin_unlock_irqrestore(wd->sh->host_lock, flags); if (result) return FAILED; @@ -505,22 +522,23 @@ static int wd719x_host_reset(struct scsi_cmnd *cmd) struct wd719x *wd = shost_priv(cmd->device->host); struct wd719x_scb *scb, *tmp; unsigned long flags; - int result; dev_info(&wd->pdev->dev, "host reset requested\n"); spin_lock_irqsave(wd->sh->host_lock, flags); - /* Try to reinit the RISC */ - if (wd719x_chip_init(wd) == 0) - result = SUCCESS; - else - result = FAILED; + /* stop the RISC */ + if (wd719x_direct_cmd(wd, WD719X_CMD_SLEEP, 0, 0, 0, 0, + WD719X_WAIT_FOR_RISC)) + dev_warn(&wd->pdev->dev, "RISC sleep command failed\n"); + /* disable RISC */ + wd719x_writeb(wd, WD719X_PCI_MODE_SELECT, 0); /* flush all SCBs */ list_for_each_entry_safe(scb, tmp, &wd->active_scbs, list) - wd719x_finish_cmd(scb, result); + wd719x_finish_cmd(scb, DID_RESET); spin_unlock_irqrestore(wd->sh->host_lock, flags); - return result; + /* Try to reinit the RISC */ + return wd719x_chip_init(wd) == 0 ? SUCCESS : FAILED; } static int wd719x_biosparam(struct scsi_device *sdev, struct block_device *bdev, @@ -672,7 +690,7 @@ static irqreturn_t wd719x_interrupt(int irq, void *dev_id) else dev_err(&wd->pdev->dev, "card returned invalid SCB pointer\n"); } else - dev_warn(&wd->pdev->dev, "direct command 0x%x completed\n", + dev_dbg(&wd->pdev->dev, "direct command 0x%x completed\n", regs.bytes.OPC); break; case WD719X_INT_PIOREADY: -- Ondrej Zary