]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/scsi/wd719x.c
net: stmmac: disable/enable ptp_ref_clk in suspend/resume flow
[linux.git] / drivers / scsi / wd719x.c
index c2f40068f235271cc694b56a7f9020dd5f8f8a2a..edc8a139a60d713857333e7a16dae0a258b6d553 100644 (file)
@@ -108,8 +108,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;
        }
 
@@ -128,8 +135,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);
@@ -465,6 +474,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;
@@ -477,6 +487,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");
@@ -484,6 +495,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;
@@ -506,22 +523,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,
@@ -673,7 +691,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: