@@ -1528,6 +1528,7 @@ struct aac_bus_info_response {
#define AAC_COMM_MESSAGE_TYPE3 5
#define AAC_EXTOPT_SA_FIRMWARE cpu_to_le32(1<<1)
+#define AAC_EXTOPT_SOFT_RESET cpu_to_le32(1<<16)
/* MSIX context */
struct aac_msix_ctx {
@@ -1662,6 +1663,7 @@ struct aac_dev
u8 raw_io_64;
u8 printf_enabled;
u8 in_reset;
+ u8 in_soft_reset;
u8 msi;
u8 sa_firmware;
int management_fib_count;
@@ -2504,6 +2506,7 @@ struct aac_hba_info {
#define RCV_TEMP_READINGS 0x00000025
#define GET_COMM_PREFERRED_SETTINGS 0x00000026
#define IOP_RESET_FW_FIB_DUMP 0x00000034
+#define DROP_IO 0x00000035
#define IOP_RESET 0x00001000
#define IOP_RESET_ALWAYS 0x00001001
#define RE_INIT_ADAPTER 0x000000ee
@@ -2539,6 +2542,7 @@ struct aac_hba_info {
#define FLASH_UPD_PENDING 0x00002000
#define FLASH_UPD_SUCCESS 0x00004000
#define FLASH_UPD_FAILED 0x00008000
+#define INVALID_OMR 0xffffffff
#define FWUPD_TIMEOUT (5 * 60)
/*
@@ -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;
@@ -992,6 +993,148 @@ int aac_src_init(struct aac_dev *dev)
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 +1164,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 +1217,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 +1246,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;
/*