scsi: aacraid: Implement DropIO sync command
IOP_RESET takes a long time to complete. If controller is in a state where we can bring it back with init struct, send a DropIO sync command instead. - If controller is faulted perform standard IOP_RESET in aac_srcv_init. - If controller is not faulted get adapter properties and extended properties. - Update the sa_firmware variable and determine if DropIO request is supported. - Issue DropIO request, and get the number of outstanding commands. - If all commands are complete with success (CT_OK), consider IOP_RESET is complete. - If any commands timeout, Perform the IOP_RESET. Signed-off-by: Prasad B Munirathnam <prasad.munirathnam@microsemi.com> Signed-off-by: Raghava Aditya Renukunta <RaghavaAditya.Renukunta@microsemi.com> Reviewed-by: Dave Carroll <david.carroll@microsemi.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Родитель
a8db6140d7
Коммит
44f1ce7d2f
|
@ -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 @@ 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 +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;
|
||||
/*
|
||||
|
|
Загрузка…
Ссылка в новой задаче