diff options
Diffstat (limited to 'drivers/scsi/aacraid/src.c')
-rw-r--r-- | drivers/scsi/aacraid/src.c | 205 |
1 files changed, 193 insertions, 12 deletions
diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c index a802bddf04aa..4ebb35a29caa 100644 --- a/drivers/scsi/aacraid/src.c +++ b/drivers/scsi/aacraid/src.c @@ -255,7 +255,8 @@ static int src_sync_cmd(struct aac_dev *dev, u32 command, */ src_writel(dev, MUnit.IDR, INBOUNDDOORBELL_0 << SRC_IDR_SHIFT); - if (!dev->sync_mode || command != SEND_SYNCHRONOUS_FIB) { + if ((!dev->sync_mode || command != SEND_SYNCHRONOUS_FIB) && + !dev->in_soft_reset) { ok = 0; start = jiffies; @@ -679,6 +680,25 @@ void aac_set_intx_mode(struct aac_dev *dev) } } +static void aac_clear_omr(struct aac_dev *dev) +{ + u32 omr_value = 0; + + omr_value = src_readl(dev, MUnit.OMR); + + /* + * Check for PCI Errors or Kernel Panic + */ + if ((omr_value == INVALID_OMR) || (omr_value & KERNEL_PANIC)) + omr_value = 0; + + /* + * Preserve MSIX Value if any + */ + src_writel(dev, MUnit.OMR, omr_value & AAC_INT_MODE_MSIX); + src_readl(dev, MUnit.OMR); +} + static void aac_dump_fw_fib_iop_reset(struct aac_dev *dev) { __le32 supported_options3; @@ -739,6 +759,8 @@ static void aac_send_iop_reset(struct aac_dev *dev) aac_set_intx_mode(dev); + aac_clear_omr(dev); + src_writel(dev, MUnit.IDR, IOP_SRC_RESET_MASK); msleep(5000); @@ -748,6 +770,7 @@ static void aac_send_hardware_soft_reset(struct aac_dev *dev) { u_int32_t val; + aac_clear_omr(dev); val = readl(((char *)(dev->base) + IBW_SWR_OFFSET)); val |= 0x01; writel(val, ((char *)(dev->base) + IBW_SWR_OFFSET)); @@ -992,6 +1015,148 @@ error_iounmap: return -1; } +static int aac_src_wait_sync(struct aac_dev *dev, int *status) +{ + unsigned long start = jiffies; + unsigned long usecs = 0; + int delay = 5 * HZ; + int rc = 1; + + while (time_before(jiffies, start+delay)) { + /* + * Delay 5 microseconds to let Mon960 get info. + */ + udelay(5); + + /* + * Mon960 will set doorbell0 bit when it has completed the + * command. + */ + if (aac_src_get_sync_status(dev) & OUTBOUNDDOORBELL_0) { + /* + * Clear: the doorbell. + */ + if (dev->msi_enabled) + aac_src_access_devreg(dev, AAC_CLEAR_SYNC_BIT); + else + src_writel(dev, MUnit.ODR_C, + OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); + rc = 0; + + break; + } + + /* + * Yield the processor in case we are slow + */ + usecs = 1 * USEC_PER_MSEC; + usleep_range(usecs, usecs + 50); + } + /* + * Pull the synch status from Mailbox 0. + */ + if (status && !rc) { + status[0] = readl(&dev->IndexRegs->Mailbox[0]); + status[1] = readl(&dev->IndexRegs->Mailbox[1]); + status[2] = readl(&dev->IndexRegs->Mailbox[2]); + status[3] = readl(&dev->IndexRegs->Mailbox[3]); + status[4] = readl(&dev->IndexRegs->Mailbox[4]); + } + + return rc; +} + +/** + * aac_src_soft_reset - perform soft reset to speed up + * access + * + * Assumptions: That the controller is in a state where we can + * bring it back to life with an init struct. We can only use + * fast sync commands, as the timeout is 5 seconds. + * + * @dev: device to configure + * + */ + +static int aac_src_soft_reset(struct aac_dev *dev) +{ + u32 status_omr = src_readl(dev, MUnit.OMR); + u32 status[5]; + int rc = 1; + int state = 0; + char *state_str[7] = { + "GET_ADAPTER_PROPERTIES Failed", + "GET_ADAPTER_PROPERTIES timeout", + "SOFT_RESET not supported", + "DROP_IO Failed", + "DROP_IO timeout", + "Check Health failed" + }; + + if (status_omr == INVALID_OMR) + return 1; // pcie hosed + + if (!(status_omr & KERNEL_UP_AND_RUNNING)) + return 1; // not up and running + + /* + * We go into soft reset mode to allow us to handle response + */ + dev->in_soft_reset = 1; + dev->msi_enabled = status_omr & AAC_INT_MODE_MSIX; + + /* Get adapter properties */ + rc = aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES, 0, 0, 0, + 0, 0, 0, status+0, status+1, status+2, status+3, status+4); + if (rc) + goto out; + + state++; + if (aac_src_wait_sync(dev, status)) { + rc = 1; + goto out; + } + + state++; + if (!(status[1] & le32_to_cpu(AAC_OPT_EXTENDED) && + (status[4] & le32_to_cpu(AAC_EXTOPT_SOFT_RESET)))) { + rc = 2; + goto out; + } + + if ((status[1] & le32_to_cpu(AAC_OPT_EXTENDED)) && + (status[4] & le32_to_cpu(AAC_EXTOPT_SA_FIRMWARE))) + dev->sa_firmware = 1; + + state++; + rc = aac_adapter_sync_cmd(dev, DROP_IO, 0, 0, 0, 0, 0, 0, + status+0, status+1, status+2, status+3, status+4); + + if (rc) + goto out; + + state++; + if (aac_src_wait_sync(dev, status)) { + rc = 3; + goto out; + } + + if (status[1]) + dev_err(&dev->pdev->dev, "%s: %d outstanding I/O pending\n", + __func__, status[1]); + + state++; + rc = aac_src_check_health(dev); + +out: + dev->in_soft_reset = 0; + dev->msi_enabled = 0; + if (rc) + dev_err(&dev->pdev->dev, "%s: %s status = %d", __func__, + state_str[state], rc); + +return rc; +} /** * aac_srcv_init - initialize an SRCv card * @dev: device to configure @@ -1021,8 +1186,10 @@ int aac_srcv_init(struct aac_dev *dev) if (dev->init_reset) { dev->init_reset = false; - if (!aac_src_restart_adapter(dev, 0, IOP_HWSOFT_RESET)) + if (aac_src_soft_reset(dev)) { + aac_src_restart_adapter(dev, 0, IOP_HWSOFT_RESET); ++restart; + } } /* @@ -1072,13 +1239,16 @@ int aac_srcv_init(struct aac_dev *dev) printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance); goto error_iounmap; } + start = jiffies; /* * Wait for the adapter to be up and running. Wait up to 3 minutes */ - while (!((status = src_readl(dev, MUnit.OMR)) & - KERNEL_UP_AND_RUNNING) || - status == 0xffffffff) { + do { + status = src_readl(dev, MUnit.OMR); + if (status == INVALID_OMR) + status = 0; + if ((restart && (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) || time_after(jiffies, start+HZ*startup_timeout)) { @@ -1098,7 +1268,8 @@ int aac_srcv_init(struct aac_dev *dev) ++restart; } msleep(1); - } + } while (!(status & KERNEL_UP_AND_RUNNING)); + if (restart && aac_commit) aac_commit = 1; /* @@ -1234,13 +1405,23 @@ void aac_src_access_devreg(struct aac_dev *dev, int mode) static int aac_src_get_sync_status(struct aac_dev *dev) { + int msix_val = 0; + int legacy_val = 0; - int val; + msix_val = src_readl(dev, MUnit.ODR_MSI) & SRC_MSI_READ_MASK ? 1 : 0; - if (dev->msi_enabled) - val = src_readl(dev, MUnit.ODR_MSI) & 0x1000 ? 1 : 0; - else - val = src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT; + if (!dev->msi_enabled) { + /* + * if Legacy int status indicates cmd is not complete + * sample MSIx register to see if it indiactes cmd complete, + * if yes set the controller in MSIx mode and consider cmd + * completed + */ + legacy_val = src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT; + if (!(legacy_val & 1) && msix_val) + dev->msi_enabled = 1; + return legacy_val; + } - return val; + return msix_val; } |