aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/mpi3mr/mpi3mr.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/mpi3mr/mpi3mr.c')
-rw-r--r--sys/dev/mpi3mr/mpi3mr.c737
1 files changed, 578 insertions, 159 deletions
diff --git a/sys/dev/mpi3mr/mpi3mr.c b/sys/dev/mpi3mr/mpi3mr.c
index 932d174a6b50..99edd3542619 100644
--- a/sys/dev/mpi3mr/mpi3mr.c
+++ b/sys/dev/mpi3mr/mpi3mr.c
@@ -1,7 +1,7 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2016-2023, Broadcom Inc. All rights reserved.
+ * Copyright (c) 2016-2025, Broadcom Inc. All rights reserved.
* Support: <fbsd-storage-driver.pdl@broadcom.com>
*
* Authors: Sumit Saxena <sumit.saxena@broadcom.com>
@@ -83,7 +83,7 @@ static void mpi3mr_port_enable_complete(struct mpi3mr_softc *sc,
struct mpi3mr_drvr_cmd *drvrcmd);
static void mpi3mr_flush_io(struct mpi3mr_softc *sc);
static int mpi3mr_issue_reset(struct mpi3mr_softc *sc, U16 reset_type,
- U32 reset_reason);
+ U16 reset_reason);
static void mpi3mr_dev_rmhs_send_tm(struct mpi3mr_softc *sc, U16 handle,
struct mpi3mr_drvr_cmd *cmdparam, U8 iou_rc);
static void mpi3mr_dev_rmhs_complete_iou(struct mpi3mr_softc *sc,
@@ -186,7 +186,7 @@ poll_for_command_completion(struct mpi3mr_softc *sc,
* Return: None.
*/
static void
-mpi3mr_trigger_snapdump(struct mpi3mr_softc *sc, U32 reason_code)
+mpi3mr_trigger_snapdump(struct mpi3mr_softc *sc, U16 reason_code)
{
U32 host_diagnostic, timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10;
@@ -221,7 +221,7 @@ mpi3mr_trigger_snapdump(struct mpi3mr_softc *sc, U32 reason_code)
*
* Return: None.
*/
-static void mpi3mr_check_rh_fault_ioc(struct mpi3mr_softc *sc, U32 reason_code)
+static void mpi3mr_check_rh_fault_ioc(struct mpi3mr_softc *sc, U16 reason_code)
{
U32 ioc_status;
@@ -1147,7 +1147,7 @@ enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_softc *sc)
return MRIOC_STATE_RESET_REQUESTED;
}
-static inline void mpi3mr_clear_resethistory(struct mpi3mr_softc *sc)
+static inline void mpi3mr_clear_reset_history(struct mpi3mr_softc *sc)
{
U32 ioc_status;
@@ -1167,9 +1167,9 @@ static inline void mpi3mr_clear_resethistory(struct mpi3mr_softc *sc)
*
* Return: 0 on success, -1 on failure.
*/
-static int mpi3mr_mur_ioc(struct mpi3mr_softc *sc, U32 reset_reason)
+static int mpi3mr_mur_ioc(struct mpi3mr_softc *sc, U16 reset_reason)
{
- U32 ioc_config, timeout, ioc_status;
+ U32 ioc_config, timeout, ioc_status, scratch_pad0;
int retval = -1;
mpi3mr_dprint(sc, MPI3MR_INFO, "Issuing Message Unit Reset(MUR)\n");
@@ -1177,8 +1177,13 @@ static int mpi3mr_mur_ioc(struct mpi3mr_softc *sc, U32 reset_reason)
mpi3mr_dprint(sc, MPI3MR_ERROR, "IOC is unrecoverable MUR not issued\n");
return retval;
}
- mpi3mr_clear_resethistory(sc);
- mpi3mr_regwrite(sc, MPI3_SYSIF_SCRATCHPAD0_OFFSET, reset_reason);
+ mpi3mr_clear_reset_history(sc);
+
+ scratch_pad0 = ((MPI3MR_RESET_REASON_OSTYPE_FREEBSD <<
+ MPI3MR_RESET_REASON_OSTYPE_SHIFT) |
+ (sc->facts.ioc_num <<
+ MPI3MR_RESET_REASON_IOCNUM_SHIFT) | reset_reason);
+ mpi3mr_regwrite(sc, MPI3_SYSIF_SCRATCHPAD0_OFFSET, scratch_pad0);
ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
ioc_config &= ~MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET, ioc_config);
@@ -1187,7 +1192,7 @@ static int mpi3mr_mur_ioc(struct mpi3mr_softc *sc, U32 reset_reason)
do {
ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)) {
- mpi3mr_clear_resethistory(sc);
+ mpi3mr_clear_reset_history(sc);
ioc_config =
mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) ||
@@ -1217,24 +1222,44 @@ static int mpi3mr_mur_ioc(struct mpi3mr_softc *sc, U32 reset_reason)
*
* Return: 0 on success, appropriate error on failure.
*/
-static int mpi3mr_bring_ioc_ready(struct mpi3mr_softc *sc)
+static int mpi3mr_bring_ioc_ready(struct mpi3mr_softc *sc,
+ U64 *start_time)
{
- U32 ioc_config, timeout;
- enum mpi3mr_iocstate current_state;
+ enum mpi3mr_iocstate current_state;
+ U32 ioc_status;
+ int retval;
- ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
- ioc_config |= MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
+ U32 ioc_config = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
+ ioc_config |= MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET, ioc_config);
- timeout = sc->ready_timeout * 10;
- do {
- current_state = mpi3mr_get_iocstate(sc);
- if (current_state == MRIOC_STATE_READY)
- return 0;
- DELAY(100 * 1000);
- } while (--timeout);
+ if (*start_time == 0)
+ *start_time = ticks;
- return -1;
+ do {
+ ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
+ if (ioc_status & (MPI3_SYSIF_IOC_STATUS_FAULT | MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)) {
+ if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) {
+ mpi3mr_print_fault_info(sc);
+ retval = mpi3mr_issue_reset(sc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, MPI3MR_RESET_FROM_BRINGUP);
+ if (retval) {
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "%s: Failed to soft reset the IOC, error 0x%d\n", __func__, retval);
+ return -1;
+ }
+ }
+ mpi3mr_clear_reset_history(sc);
+ return EAGAIN;
+ }
+
+ current_state = mpi3mr_get_iocstate(sc);
+ if (current_state == MRIOC_STATE_READY)
+ return 0;
+
+ DELAY(100 * 1000);
+
+ } while (((ticks - *start_time) / hz) < sc->ready_timeout);
+
+ return -1;
}
static const struct {
@@ -1313,6 +1338,7 @@ static const struct {
"diagnostic buffer post timeout"
},
{ MPI3MR_RESET_FROM_FIRMWARE, "firmware asynchronus reset" },
+ { MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT, "configuration request timeout" },
{ MPI3MR_RESET_REASON_COUNT, "Reset reason count" },
};
@@ -1403,14 +1429,10 @@ mpi3mr_soft_reset_success(U32 ioc_status, U32 ioc_config)
static inline bool mpi3mr_diagfault_success(struct mpi3mr_softc *sc,
U32 ioc_status)
{
- U32 fault;
-
if (!(ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT))
return false;
- fault = mpi3mr_regread(sc, MPI3_SYSIF_FAULT_OFFSET) & MPI3_SYSIF_FAULT_CODE_MASK;
- if (fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET)
- return true;
- return false;
+ mpi3mr_print_fault_info(sc);
+ return true;
}
/**
@@ -1616,6 +1638,7 @@ static int mpi3mr_process_factsdata(struct mpi3mr_softc *sc,
(facts_data->MaxPCIeSwitches);
sc->facts.max_sasexpanders =
(facts_data->MaxSASExpanders);
+ sc->facts.max_data_length = facts_data->MaxDataLength;
sc->facts.max_sasinitiators =
(facts_data->MaxSASInitiators);
sc->facts.max_enclosures = (facts_data->MaxEnclosures);
@@ -1650,6 +1673,10 @@ static int mpi3mr_process_factsdata(struct mpi3mr_softc *sc,
sc->facts.io_throttle_low = facts_data->IOThrottleLow;
sc->facts.io_throttle_high = facts_data->IOThrottleHigh;
+ if (sc->facts.max_data_length == MPI3_IOCFACTS_MAX_DATA_LENGTH_NOT_REPORTED)
+ sc->facts.max_data_length = MPI3MR_DEFAULT_MAX_IO_SIZE;
+ else
+ sc->facts.max_data_length *= MPI3MR_PAGE_SIZE_4K;
/*Store in 512b block count*/
if (sc->facts.io_throttle_data_length)
sc->io_throttle_data_length =
@@ -1889,6 +1916,15 @@ static int mpi3mr_reply_alloc(struct mpi3mr_softc *sc)
goto out_failed;
}
+ sc->cfg_cmds.reply = malloc(sc->reply_sz,
+ M_MPI3MR, M_NOWAIT | M_ZERO);
+
+ if (!sc->cfg_cmds.reply) {
+ printf(IOCNAME "Cannot allocate memory for cfg_cmds.reply\n",
+ sc->name);
+ goto out_failed;
+ }
+
sc->ioctl_cmds.reply = malloc(sc->reply_sz, M_MPI3MR, M_NOWAIT | M_ZERO);
if (!sc->ioctl_cmds.reply) {
printf(IOCNAME "Cannot allocate memory for ioctl_cmds.reply\n",
@@ -2139,7 +2175,7 @@ static int mpi3mr_issue_iocinit(struct mpi3mr_softc *sc)
strcpy(drvr_info->DriverName, MPI3MR_DRIVER_NAME);
strcpy(drvr_info->DriverVersion, MPI3MR_DRIVER_VERSION);
strcpy(drvr_info->DriverReleaseDate, MPI3MR_DRIVER_RELDATE);
- drvr_info->DriverCapabilities = 0;
+ drvr_info->DriverCapabilities = MPI3_IOCINIT_DRIVERCAP_OSEXPOSURE_NO_SPECIAL;
memcpy((U8 *)&sc->driver_info, (U8 *)drvr_info, sizeof(sc->driver_info));
memset(&iocinit_req, 0, sizeof(iocinit_req));
@@ -2175,6 +2211,8 @@ static int mpi3mr_issue_iocinit(struct mpi3mr_softc *sc)
time_in_msec = (now.tv_sec * 1000 + now.tv_usec/1000);
iocinit_req.TimeStamp = htole64(time_in_msec);
+ iocinit_req.MsgFlags |= MPI3_IOCINIT_MSGFLAGS_WRITESAMEDIVERT_SUPPORTED;
+
init_completion(&sc->init_cmds.completion);
retval = mpi3mr_submit_admin_cmd(sc, &iocinit_req,
sizeof(iocinit_req));
@@ -2267,7 +2305,7 @@ mpi3mr_display_ioc_info(struct mpi3mr_softc *sc)
printf("Capabilities=(");
if (sc->facts.ioc_capabilities &
- MPI3_IOCFACTS_CAPABILITY_RAID_CAPABLE) {
+ MPI3_IOCFACTS_CAPABILITY_RAID_SUPPORTED) {
printf("RAID");
i++;
}
@@ -2508,7 +2546,9 @@ static int mpi3mr_alloc_chain_bufs(struct mpi3mr_softc *sc)
goto out_failed;
}
- sz = MPI3MR_CHAINSGE_SIZE;
+ if (sc->max_sgl_entries > sc->facts.max_data_length / PAGE_SIZE)
+ sc->max_sgl_entries = sc->facts.max_data_length / PAGE_SIZE;
+ sz = sc->max_sgl_entries * sizeof(Mpi3SGESimple_t);
if (bus_dma_tag_create(sc->mpi3mr_parent_dmat, /* parent */
4096, 0, /* algnmnt, boundary */
@@ -2707,14 +2747,16 @@ int mpi3mr_initialize_ioc(struct mpi3mr_softc *sc, U8 init_type)
{
int retval = 0;
enum mpi3mr_iocstate ioc_state;
- U64 ioc_info;
+ U64 ioc_info, start_ticks = 0;
U32 ioc_status, ioc_control, i, timeout;
Mpi3IOCFactsData_t facts_data;
char str[32];
U32 size;
+ U8 retry = 0;
sc->cpu_count = mp_ncpus;
+retry_init:
ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
ioc_control = mpi3mr_regread(sc, MPI3_SYSIF_IOC_CONFIG_OFFSET);
ioc_info = mpi3mr_regread64(sc, MPI3_SYSIF_IOC_INFO_LOW_OFFSET);
@@ -2722,28 +2764,25 @@ int mpi3mr_initialize_ioc(struct mpi3mr_softc *sc, U8 init_type)
mpi3mr_dprint(sc, MPI3MR_INFO, "SOD ioc_status: 0x%x ioc_control: 0x%x "
"ioc_info: 0x%lx\n", ioc_status, ioc_control, ioc_info);
- /*The timeout value is in 2sec unit, changing it to seconds*/
+ /*The timeout value is in 2sec unit, changing it to seconds*/
sc->ready_timeout =
((ioc_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >>
MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT) * 2;
ioc_state = mpi3mr_get_iocstate(sc);
-
mpi3mr_dprint(sc, MPI3MR_INFO, "IOC state: %s IOC ready timeout: %d\n",
mpi3mr_iocstate_name(ioc_state), sc->ready_timeout);
- if (ioc_state == MRIOC_STATE_BECOMING_READY ||
- ioc_state == MRIOC_STATE_RESET_REQUESTED) {
- timeout = sc->ready_timeout * 10;
- do {
- DELAY(1000 * 100);
- } while (--timeout);
-
+ timeout = sc->ready_timeout * 10;
+ do {
ioc_state = mpi3mr_get_iocstate(sc);
- mpi3mr_dprint(sc, MPI3MR_INFO,
- "IOC in %s state after waiting for reset time\n",
- mpi3mr_iocstate_name(ioc_state));
- }
+
+ if (ioc_state != MRIOC_STATE_BECOMING_READY &&
+ ioc_state != MRIOC_STATE_RESET_REQUESTED)
+ break;
+
+ DELAY(1000 * 100);
+ } while (--timeout);
if (ioc_state == MRIOC_STATE_READY) {
retval = mpi3mr_mur_ioc(sc, MPI3MR_RESET_FROM_BRINGUP);
@@ -2755,53 +2794,75 @@ int mpi3mr_initialize_ioc(struct mpi3mr_softc *sc, U8 init_type)
}
if (ioc_state != MRIOC_STATE_RESET) {
- mpi3mr_print_fault_info(sc);
- mpi3mr_dprint(sc, MPI3MR_ERROR, "issuing soft reset to bring to reset state\n");
- retval = mpi3mr_issue_reset(sc,
- MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
- MPI3MR_RESET_FROM_BRINGUP);
- if (retval) {
- mpi3mr_dprint(sc, MPI3MR_ERROR,
- "%s :Failed to soft reset IOC, error 0x%d\n",
- __func__, retval);
- goto out_failed;
- }
- }
-
+ if (ioc_state == MRIOC_STATE_FAULT) {
+ mpi3mr_print_fault_info(sc);
+
+ U32 fault = mpi3mr_regread(sc, MPI3_SYSIF_FAULT_OFFSET) &
+ MPI3_SYSIF_FAULT_CODE_MASK;
+ if (fault == MPI3_SYSIF_FAULT_CODE_INSUFFICIENT_PCI_SLOT_POWER)
+ mpi3mr_dprint(sc, MPI3MR_INFO,
+ "controller faulted due to insufficient power, try by connecting it in a different slot\n");
+ goto err;
+
+ U32 host_diagnostic;
+ timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10;
+ do {
+ host_diagnostic = mpi3mr_regread(sc, MPI3_SYSIF_HOST_DIAG_OFFSET);
+ if (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS))
+ break;
+ DELAY(100 * 1000);
+ } while (--timeout);
+ }
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "issuing soft reset to bring to reset state\n");
+ retval = mpi3mr_issue_reset(sc,
+ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
+ MPI3MR_RESET_FROM_BRINGUP);
+ if (retval) {
+ mpi3mr_dprint(sc, MPI3MR_ERROR,
+ "%s :Failed to soft reset IOC, error 0x%d\n",
+ __func__, retval);
+ goto err_retry;
+ }
+ }
+
ioc_state = mpi3mr_get_iocstate(sc);
if (ioc_state != MRIOC_STATE_RESET) {
mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot bring IOC to reset state\n");
- goto out_failed;
+ goto err_retry;
}
retval = mpi3mr_setup_admin_qpair(sc);
if (retval) {
mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to setup Admin queues, error 0x%x\n",
retval);
- goto out_failed;
+ if (retval == ENOMEM)
+ goto err;
+ goto err_retry;
}
-
- retval = mpi3mr_bring_ioc_ready(sc);
+
+ retval = mpi3mr_bring_ioc_ready(sc, &start_ticks);
if (retval) {
- mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to bring IOC ready, error 0x%x\n",
- retval);
- goto out_failed;
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to bring IOC ready, error 0x%x\n", retval);
+ if (retval == EAGAIN)
+ goto err_retry;
+ goto err;
}
+
if (init_type == MPI3MR_INIT_TYPE_INIT) {
retval = mpi3mr_alloc_interrupts(sc, 1);
if (retval) {
mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocate interrupts, error 0x%x\n",
retval);
- goto out_failed;
+ goto err;
}
-
+
retval = mpi3mr_setup_irqs(sc);
if (retval) {
mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to setup ISR, error 0x%x\n",
retval);
- goto out_failed;
+ goto err;
}
}
@@ -2825,6 +2886,12 @@ int mpi3mr_initialize_ioc(struct mpi3mr_softc *sc, U8 init_type)
sc->init_cmds.dev_handle = MPI3MR_INVALID_DEV_HANDLE;
sc->init_cmds.host_tag = MPI3MR_HOSTTAG_INITCMDS;
+ mtx_init(&sc->cfg_cmds.completion.lock, "CFG commands lock", NULL, MTX_DEF);
+ sc->cfg_cmds.reply = NULL;
+ sc->cfg_cmds.state = MPI3MR_CMD_NOTUSED;
+ sc->cfg_cmds.dev_handle = MPI3MR_INVALID_DEV_HANDLE;
+ sc->cfg_cmds.host_tag = MPI3MR_HOSTTAG_CFGCMDS;
+
mtx_init(&sc->ioctl_cmds.completion.lock, "IOCTL commands lock", NULL, MTX_DEF);
sc->ioctl_cmds.reply = NULL;
sc->ioctl_cmds.state = MPI3MR_CMD_NOTUSED;
@@ -2861,25 +2928,30 @@ int mpi3mr_initialize_ioc(struct mpi3mr_softc *sc, U8 init_type)
retval = mpi3mr_issue_iocfacts(sc, &facts_data);
if (retval) {
- mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to Issue IOC Facts, retval: 0x%x\n",
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to Issue IOC Facts, error: 0x%x\n",
retval);
- goto out_failed;
+ if (retval == ENOMEM)
+ goto err;
+ goto err_retry;
}
retval = mpi3mr_process_factsdata(sc, &facts_data);
if (retval) {
- mpi3mr_dprint(sc, MPI3MR_ERROR, "IOC Facts data processing failedi, retval: 0x%x\n",
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "IOC Facts data processing failed, error: 0x%x\n",
retval);
- goto out_failed;
+ goto err_retry;
}
sc->num_io_throttle_group = sc->facts.max_io_throttle_group;
mpi3mr_atomic_set(&sc->pend_large_data_sz, 0);
-
+
if (init_type == MPI3MR_INIT_TYPE_RESET) {
retval = mpi3mr_validate_fw_update(sc);
- if (retval)
- goto out_failed;
+ if (retval) {
+ if (retval == ENOMEM)
+ goto err;
+ goto err_retry;
+ }
} else {
sc->reply_sz = sc->facts.reply_sz;
}
@@ -2888,25 +2960,27 @@ int mpi3mr_initialize_ioc(struct mpi3mr_softc *sc, U8 init_type)
retval = mpi3mr_reply_alloc(sc);
if (retval) {
- mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocated reply and sense buffers, retval: 0x%x\n",
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocated reply and sense buffers, error: 0x%x\n",
retval);
- goto out_failed;
+ goto err;
}
-
+
if (init_type == MPI3MR_INIT_TYPE_INIT) {
retval = mpi3mr_alloc_chain_bufs(sc);
if (retval) {
- mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocated chain buffers, retval: 0x%x\n",
- retval);
- goto out_failed;
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocated chain buffers, error: 0x%x\n",
+ retval);
+ goto err;
}
}
-
+
retval = mpi3mr_issue_iocinit(sc);
if (retval) {
- mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to Issue IOC Init, retval: 0x%x\n",
- retval);
- goto out_failed;
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to Issue IOC Init, error: 0x%x\n",
+ retval);
+ if (retval == ENOMEM)
+ goto err;
+ goto err_retry;
}
mpi3mr_print_fw_pkg_ver(sc);
@@ -2914,77 +2988,87 @@ int mpi3mr_initialize_ioc(struct mpi3mr_softc *sc, U8 init_type)
sc->reply_free_q_host_index = sc->num_reply_bufs;
mpi3mr_regwrite(sc, MPI3_SYSIF_REPLY_FREE_HOST_INDEX_OFFSET,
sc->reply_free_q_host_index);
-
+
sc->sense_buf_q_host_index = sc->num_sense_bufs;
-
+
mpi3mr_regwrite(sc, MPI3_SYSIF_SENSE_BUF_FREE_HOST_INDEX_OFFSET,
sc->sense_buf_q_host_index);
if (init_type == MPI3MR_INIT_TYPE_INIT) {
retval = mpi3mr_alloc_interrupts(sc, 0);
if (retval) {
- mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocate interrupts, retval: 0x%x\n",
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocate interrupts, error: 0x%x\n",
retval);
- goto out_failed;
+ goto err;
}
retval = mpi3mr_setup_irqs(sc);
if (retval) {
- printf(IOCNAME "Failed to setup ISR, error: 0x%x\n",
- sc->name, retval);
- goto out_failed;
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to setup ISR, error: 0x%x\n", retval);
+ goto err;
}
mpi3mr_enable_interrupts(sc);
} else
mpi3mr_enable_interrupts(sc);
-
- retval = mpi3mr_create_op_queues(sc);
+ retval = mpi3mr_create_op_queues(sc);
if (retval) {
mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to create operational queues, error: %d\n",
retval);
- goto out_failed;
+ if (retval == ENOMEM)
+ goto err;
+ goto err_retry;
}
if (!sc->throttle_groups && sc->num_io_throttle_group) {
- mpi3mr_dprint(sc, MPI3MR_ERROR, "allocating memory for throttle groups\n");
size = sizeof(struct mpi3mr_throttle_group_info);
sc->throttle_groups = (struct mpi3mr_throttle_group_info *)
malloc(sc->num_io_throttle_group *
size, M_MPI3MR, M_NOWAIT | M_ZERO);
- if (!sc->throttle_groups)
- goto out_failed;
+ if (!sc->throttle_groups) {
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "throttle groups memory allocation failed\n");
+ goto err;
+ }
}
if (init_type == MPI3MR_INIT_TYPE_RESET) {
- mpi3mr_dprint(sc, MPI3MR_INFO, "Re-register events\n");
+ mpi3mr_dprint(sc, MPI3MR_XINFO, "Re-register events\n");
retval = mpi3mr_register_events(sc);
if (retval) {
- mpi3mr_dprint(sc, MPI3MR_INFO, "Failed to re-register events, retval: 0x%x\n",
+ mpi3mr_dprint(sc, MPI3MR_INFO, "Failed to re-register events, error: 0x%x\n",
retval);
- goto out_failed;
+ goto err_retry;
}
mpi3mr_dprint(sc, MPI3MR_INFO, "Issuing Port Enable\n");
retval = mpi3mr_issue_port_enable(sc, 0);
if (retval) {
- mpi3mr_dprint(sc, MPI3MR_INFO, "Failed to issue port enable, retval: 0x%x\n",
+ mpi3mr_dprint(sc, MPI3MR_INFO, "Failed to issue port enable, error: 0x%x\n",
retval);
- goto out_failed;
+ goto err_retry;
}
}
retval = mpi3mr_pel_alloc(sc);
if (retval) {
- mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocate memory for PEL, retval: 0x%x\n",
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to allocate memory for PEL, error: 0x%x\n",
retval);
- goto out_failed;
+ goto err;
}
-
+
+ if (mpi3mr_cfg_get_driver_pg1(sc) != 0)
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "Failed to get the cfg driver page1\n");
+
return retval;
-out_failed:
+err_retry:
+ if ((retry++ < 2) && (((ticks - start_ticks) / hz) < (sc->ready_timeout - 60))) {
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "Retrying controller initialization,"
+ "retry_count: %d\n", retry);
+ goto retry_init;
+ }
+err:
retval = -1;
return retval;
}
@@ -3053,6 +3137,115 @@ out:
return retval;
}
+static int mpi3mr_timestamp_sync(struct mpi3mr_softc *sc)
+{
+ int retval = 0;
+ struct timeval current_time;
+ int64_t time_in_msec;
+ Mpi3IoUnitControlRequest_t iou_ctrl = {0};
+
+ mtx_lock(&sc->init_cmds.completion.lock);
+ if (sc->init_cmds.state & MPI3MR_CMD_PENDING) {
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "Issue timestamp sync: command is in use\n");
+ mtx_unlock(&sc->init_cmds.completion.lock);
+ return -1;
+ }
+
+ sc->init_cmds.state = MPI3MR_CMD_PENDING;
+ sc->init_cmds.is_waiting = 1;
+ sc->init_cmds.callback = NULL;
+ iou_ctrl.HostTag = htole64(MPI3MR_HOSTTAG_INITCMDS);
+ iou_ctrl.Function = MPI3_FUNCTION_IO_UNIT_CONTROL;
+ iou_ctrl.Operation = MPI3_CTRL_OP_UPDATE_TIMESTAMP;
+ getmicrotime(&current_time);
+ time_in_msec = (int64_t)current_time.tv_sec * 1000 + current_time.tv_usec/1000;
+ iou_ctrl.Param64[0] = htole64(time_in_msec);
+
+ init_completion(&sc->init_cmds.completion);
+
+ retval = mpi3mr_submit_admin_cmd(sc, &iou_ctrl, sizeof(iou_ctrl));
+ if (retval) {
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "timestamp sync: Admin Post failed\n");
+ goto out_unlock;
+ }
+
+ wait_for_completion_timeout(&sc->init_cmds.completion,
+ (MPI3MR_INTADMCMD_TIMEOUT));
+
+ if (!(sc->init_cmds.state & MPI3MR_CMD_COMPLETE)) {
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "Issue timestamp sync: command timed out\n");
+ sc->init_cmds.is_waiting = 0;
+
+ if (!(sc->init_cmds.state & MPI3MR_CMD_RESET))
+ mpi3mr_check_rh_fault_ioc(sc, MPI3MR_RESET_FROM_TSU_TIMEOUT);
+
+ retval = -1;
+ goto out_unlock;
+ }
+
+ if (((sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) != MPI3_IOCSTATUS_SUCCESS) &&
+ (sc->init_cmds.ioc_status != MPI3_IOCSTATUS_SUPERVISOR_ONLY)) {
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "Issue timestamp sync: Failed IOCStatus(0x%04x) Loginfo(0x%08x)\n",
+ (sc->init_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), sc->init_cmds.ioc_loginfo);
+ retval = -1;
+ }
+
+out_unlock:
+ sc->init_cmds.state = MPI3MR_CMD_NOTUSED;
+ mtx_unlock(&sc->init_cmds.completion.lock);
+
+ return retval;
+}
+
+void
+mpi3mr_timestamp_thread(void *arg)
+{
+ struct mpi3mr_softc *sc = (struct mpi3mr_softc *)arg;
+ U64 elapsed_time = 0;
+
+ sc->timestamp_thread_active = 1;
+ mtx_lock(&sc->reset_mutex);
+ while (1) {
+
+ if (sc->mpi3mr_flags & MPI3MR_FLAGS_SHUTDOWN ||
+ (sc->unrecoverable == 1)) {
+ mpi3mr_dprint(sc, MPI3MR_INFO,
+ "Exit due to %s from %s\n",
+ sc->mpi3mr_flags & MPI3MR_FLAGS_SHUTDOWN ? "Shutdown" :
+ "Hardware critical error", __func__);
+ break;
+ }
+ mtx_unlock(&sc->reset_mutex);
+
+ while (sc->reset_in_progress) {
+ if (elapsed_time)
+ elapsed_time = 0;
+ if (sc->unrecoverable)
+ break;
+ pause("mpi3mr_timestamp_thread", hz / 5);
+ }
+
+ if (elapsed_time++ >= sc->ts_update_interval * 60) {
+ mpi3mr_timestamp_sync(sc);
+ elapsed_time = 0;
+ }
+
+ /*
+ * Sleep for 1 second if we're not exiting, then loop to top
+ * to poll exit status and hardware health.
+ */
+ mtx_lock(&sc->reset_mutex);
+ if (((sc->mpi3mr_flags & MPI3MR_FLAGS_SHUTDOWN) == 0) &&
+ (!sc->unrecoverable) && (!sc->reset_in_progress)) {
+ msleep(&sc->timestamp_chan, &sc->reset_mutex, PRIBIO,
+ "mpi3mr_timestamp", 1 * hz);
+ }
+ }
+ mtx_unlock(&sc->reset_mutex);
+ sc->timestamp_thread_active = 0;
+ kproc_exit(0);
+}
+
void
mpi3mr_watchdog_thread(void *arg)
{
@@ -3118,6 +3311,14 @@ mpi3mr_watchdog_thread(void *arg)
sc->unrecoverable = 1;
break;
}
+
+ if (fault == MPI3_SYSIF_FAULT_CODE_INSUFFICIENT_PCI_SLOT_POWER) {
+ mpi3mr_dprint(sc, MPI3MR_INFO,
+ "controller faulted due to insufficient power, marking controller as unrecoverable\n");
+ sc->unrecoverable = 1;
+ break;
+ }
+
if ((fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET)
|| (fault == MPI3_SYSIF_FAULT_CODE_SOFT_RESET_IN_PROGRESS)
|| (sc->reset_in_progress))
@@ -3338,6 +3539,19 @@ void mpi3mr_update_device(struct mpi3mr_softc *sc,
break;
}
+ switch (flags & MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_MASK) {
+ case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_256_LB:
+ tgtdev->ws_len = 256;
+ break;
+ case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_2048_LB:
+ tgtdev->ws_len = 2048;
+ break;
+ case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_NO_LIMIT:
+ default:
+ tgtdev->ws_len = 0;
+ break;
+ }
+
switch (tgtdev->dev_type) {
case MPI3_DEVICE_DEVFORM_SAS_SATA:
{
@@ -3477,6 +3691,7 @@ static void mpi3mr_dev_rmhs_complete_iou(struct mpi3mr_softc *sc,
{
U16 cmd_idx = drv_cmd->host_tag - MPI3MR_HOSTTAG_DEVRMCMD_MIN;
struct delayed_dev_rmhs_node *delayed_dev_rmhs = NULL;
+ struct mpi3mr_target *tgtdev = NULL;
mpi3mr_dprint(sc, MPI3MR_EVENT,
"%s :dev_rmhs_iouctrl_complete:handle(0x%04x), ioc_status(0x%04x), loginfo(0x%08x)\n",
@@ -3497,6 +3712,13 @@ static void mpi3mr_dev_rmhs_complete_iou(struct mpi3mr_softc *sc,
"%s :dev removal handshake failed after all retries: handle(0x%04x)\n",
__func__, drv_cmd->dev_handle);
} else {
+ mtx_lock_spin(&sc->target_lock);
+ TAILQ_FOREACH(tgtdev, &sc->cam_sc->tgt_list, tgt_next) {
+ if (tgtdev->dev_handle == drv_cmd->dev_handle)
+ tgtdev->state = MPI3MR_DEV_REMOVE_HS_COMPLETED;
+ }
+ mtx_unlock_spin(&sc->target_lock);
+
mpi3mr_dprint(sc, MPI3MR_INFO,
"%s :dev removal handshake completed successfully: handle(0x%04x)\n",
__func__, drv_cmd->dev_handle);
@@ -3604,18 +3826,7 @@ static void mpi3mr_dev_rmhs_send_tm(struct mpi3mr_softc *sc, U16 handle,
U8 retrycount = 5;
struct mpi3mr_drvr_cmd *drv_cmd = cmdparam;
struct delayed_dev_rmhs_node *delayed_dev_rmhs = NULL;
- struct mpi3mr_target *tgtdev = NULL;
- mtx_lock_spin(&sc->target_lock);
- TAILQ_FOREACH(tgtdev, &sc->cam_sc->tgt_list, tgt_next) {
- if ((tgtdev->dev_handle == handle) &&
- (iou_rc == MPI3_CTRL_OP_REMOVE_DEVICE)) {
- tgtdev->state = MPI3MR_DEV_REMOVE_HS_STARTED;
- break;
- }
- }
- mtx_unlock_spin(&sc->target_lock);
-
if (drv_cmd)
goto issue_cmd;
do {
@@ -3890,7 +4101,7 @@ static void mpi3mr_sastopochg_evt_th(struct mpi3mr_softc *sc,
handle = le16toh(topo_evt->PhyEntry[i].AttachedDevHandle);
if (!handle)
continue;
- reason_code = topo_evt->PhyEntry[i].Status &
+ reason_code = topo_evt->PhyEntry[i].PhyStatus &
MPI3_EVENT_SAS_TOPO_PHY_RC_MASK;
tgtdev = mpi3mr_find_target_by_dev_handle(sc->cam_sc, handle);
switch (reason_code) {
@@ -4170,11 +4381,16 @@ static void mpi3mr_process_events(struct mpi3mr_softc *sc,
break;
}
case MPI3_EVENT_DEVICE_INFO_CHANGED:
- case MPI3_EVENT_LOG_DATA:
{
process_evt_bh = 1;
break;
}
+ case MPI3_EVENT_LOG_DATA:
+ {
+ mpi3mr_app_save_logdata(sc, (char*)event_reply->EventData,
+ le16toh(event_reply->EventDataLength) * 4);
+ break;
+ }
case MPI3_EVENT_ENERGY_PACK_CHANGE:
{
mpi3mr_energypackchg_evt_th(sc, event_reply);
@@ -4281,10 +4497,9 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_softc *sc,
status_desc = (Mpi3StatusReplyDescriptor_t *)reply_desc;
host_tag = status_desc->HostTag;
ioc_status = status_desc->IOCStatus;
- if (ioc_status &
- MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
+ if (ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
ioc_loginfo = status_desc->IOCLogInfo;
- ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
+ ioc_status &= MPI3_IOCSTATUS_STATUS_MASK;
break;
case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY:
addr_desc = (Mpi3AddressReplyDescriptor_t *)reply_desc;
@@ -4294,10 +4509,9 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_softc *sc,
goto out;
host_tag = def_reply->HostTag;
ioc_status = def_reply->IOCStatus;
- if (ioc_status &
- MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
+ if (ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
ioc_loginfo = def_reply->IOCLogInfo;
- ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
+ ioc_status &= MPI3_IOCSTATUS_STATUS_MASK;
if (def_reply->Function == MPI3_FUNCTION_SCSI_IO) {
scsi_reply = (Mpi3SCSIIOReply_t *)def_reply;
sense_buf = mpi3mr_get_sensebuf_virt_addr(sc,
@@ -4315,6 +4529,9 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_softc *sc,
case MPI3MR_HOSTTAG_INITCMDS:
cmdptr = &sc->init_cmds;
break;
+ case MPI3MR_HOSTTAG_CFGCMDS:
+ cmdptr = &sc->cfg_cmds;
+ break;
case MPI3MR_HOSTTAG_IOCTLCMDS:
cmdptr = &sc->ioctl_cmds;
break;
@@ -4391,6 +4608,7 @@ static int mpi3mr_complete_admin_cmd(struct mpi3mr_softc *sc)
U32 num_adm_reply = 0;
U64 reply_dma = 0;
Mpi3DefaultReplyDescriptor_t *reply_desc;
+ U16 threshold_comps = 0;
mtx_lock_spin(&sc->admin_reply_lock);
if (sc->admin_in_use == false) {
@@ -4428,6 +4646,11 @@ static int mpi3mr_complete_admin_cmd(struct mpi3mr_softc *sc)
if ((reply_desc->ReplyFlags &
MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
break;
+
+ if (++threshold_comps == MPI3MR_THRESHOLD_REPLY_COUNT) {
+ mpi3mr_regwrite(sc, MPI3_SYSIF_ADMIN_REPLY_Q_CI_OFFSET, adm_reply_ci);
+ threshold_comps = 0;
+ }
} while (1);
mpi3mr_regwrite(sc, MPI3_SYSIF_ADMIN_REPLY_Q_CI_OFFSET, adm_reply_ci);
@@ -4492,10 +4715,9 @@ void mpi3mr_process_op_reply_desc(struct mpi3mr_softc *sc,
status_desc = (Mpi3StatusReplyDescriptor_t *)reply_desc;
host_tag = status_desc->HostTag;
ioc_status = status_desc->IOCStatus;
- if (ioc_status &
- MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
+ if (ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
ioc_loginfo = status_desc->IOCLogInfo;
- ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
+ ioc_status &= MPI3_IOCSTATUS_STATUS_MASK;
break;
case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY:
addr_desc = (Mpi3AddressReplyDescriptor_t *)reply_desc;
@@ -4519,10 +4741,9 @@ void mpi3mr_process_op_reply_desc(struct mpi3mr_softc *sc,
resp_data = scsi_reply->ResponseData;
sense_buf = mpi3mr_get_sensebuf_virt_addr(sc,
scsi_reply->SenseDataBufferAddress);
- if (ioc_status &
- MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
+ if (ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
ioc_loginfo = scsi_reply->IOCLogInfo;
- ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
+ ioc_status &= MPI3_IOCSTATUS_STATUS_MASK;
if (sense_state == MPI3_SCSI_STATE_SENSE_BUFF_Q_EMPTY)
mpi3mr_dprint(sc, MPI3MR_ERROR, "Ran out of sense buffers\n");
@@ -4724,7 +4945,7 @@ void mpi3mr_process_op_reply_desc(struct mpi3mr_softc *sc,
csio->resid = cm->length - le32toh(xfer_count);
case MPI3_IOCSTATUS_SCSI_RECOVERED_ERROR:
case MPI3_IOCSTATUS_SUCCESS:
- if ((scsi_reply->IOCStatus & MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK) ==
+ if ((scsi_reply->IOCStatus & MPI3_IOCSTATUS_STATUS_MASK) ==
MPI3_IOCSTATUS_SCSI_RECOVERED_ERROR)
mpi3mr_dprint(sc, MPI3MR_XINFO, "func: %s line: %d recovered error\n", __func__, __LINE__);
@@ -4840,7 +5061,7 @@ int mpi3mr_complete_io_cmd(struct mpi3mr_softc *sc,
U32 num_op_replies = 0;
U64 reply_dma = 0;
Mpi3DefaultReplyDescriptor_t *reply_desc;
- U16 req_qid = 0;
+ U16 req_qid = 0, threshold_comps = 0;
mtx_lock_spin(&op_reply_q->q_lock);
if (op_reply_q->in_use == false) {
@@ -4885,6 +5106,12 @@ int mpi3mr_complete_io_cmd(struct mpi3mr_softc *sc,
if ((reply_desc->ReplyFlags &
MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
break;
+
+ if (++threshold_comps == MPI3MR_THRESHOLD_REPLY_COUNT) {
+ mpi3mr_regwrite(sc, MPI3_SYSIF_OPER_REPLY_Q_N_CI_OFFSET(op_reply_q->qid), reply_ci);
+ threshold_comps = 0;
+ }
+
} while (1);
@@ -4940,7 +5167,7 @@ mpi3mr_alloc_requests(struct mpi3mr_softc *sc)
struct mpi3mr_cmd *cmd;
int i, j, nsegs, ret;
- nsegs = MPI3MR_SG_DEPTH;
+ nsegs = sc->max_sgl_entries;
ret = bus_dma_tag_create( sc->mpi3mr_parent_dmat, /* parent */
1, 0, /* algnmnt, boundary */
sc->dma_loaddr, /* lowaddr */
@@ -5210,6 +5437,184 @@ out_failed:
mpi3mr_free_ioctl_dma_memory(sc);
}
+static void inline
+mpi3mr_free_dma_mem(struct mpi3mr_softc *sc,
+ struct dma_memory_desc *mem_desc)
+{
+ if (mem_desc->dma_addr)
+ bus_dmamap_unload(mem_desc->tag, mem_desc->dmamap);
+
+ if (mem_desc->addr != NULL) {
+ bus_dmamem_free(mem_desc->tag, mem_desc->addr, mem_desc->dmamap);
+ mem_desc->addr = NULL;
+ }
+
+ if (mem_desc->tag != NULL)
+ bus_dma_tag_destroy(mem_desc->tag);
+}
+
+static int
+mpi3mr_alloc_dma_mem(struct mpi3mr_softc *sc,
+ struct dma_memory_desc *mem_desc)
+{
+ int retval;
+
+ if (bus_dma_tag_create(sc->mpi3mr_parent_dmat, /* parent */
+ 4, 0, /* algnmnt, boundary */
+ sc->dma_loaddr, /* lowaddr */
+ sc->dma_hiaddr, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ mem_desc->size, /* maxsize */
+ 1, /* nsegments */
+ mem_desc->size, /* maxsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &mem_desc->tag)) {
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "%s: Cannot allocate DMA tag\n", __func__);
+ return ENOMEM;
+ }
+
+ if (bus_dmamem_alloc(mem_desc->tag, (void **)&mem_desc->addr,
+ BUS_DMA_NOWAIT, &mem_desc->dmamap)) {
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "%s: Cannot allocate DMA memory\n", __func__);
+ retval = ENOMEM;
+ goto out;
+ }
+
+ bzero(mem_desc->addr, mem_desc->size);
+
+ bus_dmamap_load(mem_desc->tag, mem_desc->dmamap, mem_desc->addr, mem_desc->size,
+ mpi3mr_memaddr_cb, &mem_desc->dma_addr, BUS_DMA_NOWAIT);
+
+ if (!mem_desc->addr) {
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "%s: Cannot load DMA map\n", __func__);
+ retval = ENOMEM;
+ goto out;
+ }
+ return 0;
+out:
+ mpi3mr_free_dma_mem(sc, mem_desc);
+ return retval;
+}
+
+static int
+mpi3mr_post_cfg_req(struct mpi3mr_softc *sc, Mpi3ConfigRequest_t *cfg_req)
+{
+ int retval;
+
+ mtx_lock(&sc->cfg_cmds.completion.lock);
+ if (sc->cfg_cmds.state & MPI3MR_CMD_PENDING) {
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "Issue cfg request: cfg command is in use\n");
+ mtx_unlock(&sc->cfg_cmds.completion.lock);
+ return -1;
+ }
+
+ sc->cfg_cmds.state = MPI3MR_CMD_PENDING;
+ sc->cfg_cmds.is_waiting = 1;
+ sc->cfg_cmds.callback = NULL;
+ sc->cfg_cmds.ioc_status = 0;
+ sc->cfg_cmds.ioc_loginfo = 0;
+
+ cfg_req->HostTag = htole16(MPI3MR_HOSTTAG_CFGCMDS);
+ cfg_req->Function = MPI3_FUNCTION_CONFIG;
+ cfg_req->PageType = MPI3_CONFIG_PAGETYPE_DRIVER;
+ cfg_req->PageNumber = 1;
+ cfg_req->PageAddress = 0;
+
+ init_completion(&sc->cfg_cmds.completion);
+
+ retval = mpi3mr_submit_admin_cmd(sc, cfg_req, sizeof(*cfg_req));
+ if (retval) {
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "Issue cfg request: Admin Post failed\n");
+ goto out;
+ }
+
+ wait_for_completion_timeout(&sc->cfg_cmds.completion,
+ (MPI3MR_INTADMCMD_TIMEOUT));
+
+ if (!(sc->cfg_cmds.state & MPI3MR_CMD_COMPLETE)) {
+ if (!(sc->cfg_cmds.state & MPI3MR_CMD_RESET)) {
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "config request command timed out\n");
+ mpi3mr_check_rh_fault_ioc(sc, MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT);
+ }
+ retval = -1;
+ sc->cfg_cmds.is_waiting = 0;
+ goto out;
+ }
+
+ if ((sc->cfg_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) !=
+ MPI3_IOCSTATUS_SUCCESS ) {
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "config request failed, IOCStatus(0x%04x) "
+ " Loginfo(0x%08x) \n",(sc->cfg_cmds.ioc_status &
+ MPI3_IOCSTATUS_STATUS_MASK), sc->cfg_cmds.ioc_loginfo);
+ retval = -1;
+ }
+
+out:
+ sc->cfg_cmds.state = MPI3MR_CMD_NOTUSED;
+ mtx_unlock(&sc->cfg_cmds.completion.lock);
+ return retval;
+}
+
+static int mpi3mr_process_cfg_req(struct mpi3mr_softc *sc,
+ Mpi3ConfigRequest_t *cfg_req,
+ Mpi3ConfigPageHeader_t *cfg_hdr,
+ void *cfg_buf, U32 cfg_buf_sz)
+{
+ int retval;
+ struct dma_memory_desc mem_desc = {0};
+
+ if (cfg_req->Action == MPI3_CONFIG_ACTION_PAGE_HEADER)
+ mem_desc.size = sizeof(Mpi3ConfigPageHeader_t);
+ else {
+ mem_desc.size = le16toh(cfg_hdr->PageLength) * 4;
+ cfg_req->PageLength = cfg_hdr->PageLength;
+ cfg_req->PageVersion = cfg_hdr->PageVersion;
+ }
+
+ retval = mpi3mr_alloc_dma_mem(sc, &mem_desc);
+ if (retval) {
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "%s: Failed to allocate DMA memory\n", __func__);
+ return retval;
+ }
+
+ mpi3mr_add_sg_single(&cfg_req->SGL, MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST,
+ mem_desc.size, mem_desc.dma_addr);
+
+ retval = mpi3mr_post_cfg_req(sc, cfg_req);
+ if (retval)
+ mpi3mr_dprint(sc, MPI3MR_ERROR, "%s: Failed to post config request\n", __func__);
+ else
+ memcpy(cfg_buf, mem_desc.addr, min(mem_desc.size, cfg_buf_sz));
+
+ mpi3mr_free_dma_mem(sc, &mem_desc);
+ return retval;
+}
+
+int mpi3mr_cfg_get_driver_pg1(struct mpi3mr_softc *sc)
+{
+ int retval;
+ Mpi3DriverPage1_t driver_pg1 = {0};
+ Mpi3ConfigPageHeader_t cfg_hdr = {0};
+ Mpi3ConfigRequest_t cfg_req = {0};
+
+ cfg_req.Action = MPI3_CONFIG_ACTION_PAGE_HEADER;
+ retval = mpi3mr_process_cfg_req(sc, &cfg_req, NULL, &cfg_hdr, sizeof(cfg_hdr));
+ if (retval)
+ goto error;
+
+ cfg_req.Action = MPI3_CONFIG_ACTION_READ_CURRENT;
+ retval = mpi3mr_process_cfg_req(sc, &cfg_req, &cfg_hdr, &driver_pg1, sizeof(driver_pg1));
+
+error:
+ if (!retval && driver_pg1.TimeStampUpdate)
+ sc->ts_update_interval = driver_pg1.TimeStampUpdate;
+ else
+ sc->ts_update_interval = MPI3MR_TSUPDATE_INTERVAL;
+
+ return retval;
+}
+
void
mpi3mr_destory_mtx(struct mpi3mr_softc *sc)
{
@@ -5241,6 +5646,9 @@ mpi3mr_destory_mtx(struct mpi3mr_softc *sc)
if (mtx_initialized(&sc->init_cmds.completion.lock))
mtx_destroy(&sc->init_cmds.completion.lock);
+ if (mtx_initialized(&sc->cfg_cmds.completion.lock))
+ mtx_destroy(&sc->cfg_cmds.completion.lock);
+
if (mtx_initialized(&sc->ioctl_cmds.completion.lock))
mtx_destroy(&sc->ioctl_cmds.completion.lock);
@@ -5419,6 +5827,11 @@ mpi3mr_free_mem(struct mpi3mr_softc *sc)
sc->init_cmds.reply = NULL;
}
+ if (sc->cfg_cmds.reply) {
+ free(sc->cfg_cmds.reply, M_MPI3MR);
+ sc->cfg_cmds.reply = NULL;
+ }
+
if (sc->ioctl_cmds.reply) {
free(sc->ioctl_cmds.reply, M_MPI3MR);
sc->ioctl_cmds.reply = NULL;
@@ -5536,6 +5949,9 @@ static void mpi3mr_flush_drv_cmds(struct mpi3mr_softc *sc)
cmdptr = &sc->init_cmds;
mpi3mr_drv_cmd_comp_reset(sc, cmdptr);
+ cmdptr = &sc->cfg_cmds;
+ mpi3mr_drv_cmd_comp_reset(sc, cmdptr);
+
cmdptr = &sc->ioctl_cmds;
mpi3mr_drv_cmd_comp_reset(sc, cmdptr);
@@ -5579,6 +5995,7 @@ static void mpi3mr_memset_buffers(struct mpi3mr_softc *sc)
memset(sc->admin_reply, 0, sc->admin_reply_q_sz);
memset(sc->init_cmds.reply, 0, sc->reply_sz);
+ memset(sc->cfg_cmds.reply, 0, sc->reply_sz);
memset(sc->ioctl_cmds.reply, 0, sc->reply_sz);
memset(sc->host_tm_cmds.reply, 0, sc->reply_sz);
memset(sc->pel_cmds.reply, 0, sc->reply_sz);
@@ -5642,6 +6059,7 @@ static void mpi3mr_invalidate_devhandles(struct mpi3mr_softc *sc)
target->io_throttle_enabled = 0;
target->io_divert = 0;
target->throttle_group = NULL;
+ target->ws_len = 0;
}
}
mtx_unlock_spin(&sc->target_lock);
@@ -5668,6 +6086,8 @@ static void mpi3mr_rfresh_tgtdevs(struct mpi3mr_softc *sc)
if (target->exposed_to_os)
mpi3mr_remove_device_from_os(sc, target->dev_handle);
mpi3mr_remove_device_from_list(sc, target, true);
+ } else if (target->is_hidden && target->exposed_to_os) {
+ mpi3mr_remove_device_from_os(sc, target->dev_handle);
}
}
@@ -5693,6 +6113,8 @@ static void mpi3mr_flush_io(struct mpi3mr_softc *sc)
if (cmd->callout_owner) {
ccb = (union ccb *)(cmd->ccb);
ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
+ mpi3mr_atomic_dec(&sc->fw_outstanding);
+ mpi3mr_atomic_dec(&cmd->targ->outstanding);
mpi3mr_cmd_done(sc, cmd);
} else {
cmd->ccb = NULL;
@@ -5701,23 +6123,6 @@ static void mpi3mr_flush_io(struct mpi3mr_softc *sc)
}
}
}
-/**
- * mpi3mr_clear_reset_history - Clear reset history
- * @sc: Adapter instance reference
- *
- * Write the reset history bit in IOC Status to clear the bit,
- * if it is already set.
- *
- * Return: Nothing.
- */
-static inline void mpi3mr_clear_reset_history(struct mpi3mr_softc *sc)
-{
- U32 ioc_status;
-
- ioc_status = mpi3mr_regread(sc, MPI3_SYSIF_IOC_STATUS_OFFSET);
- if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)
- mpi3mr_regwrite(sc, MPI3_SYSIF_IOC_STATUS_OFFSET, ioc_status);
-}
/**
* mpi3mr_set_diagsave - Set diag save bit for snapdump
@@ -5752,11 +6157,11 @@ static inline void mpi3mr_set_diagsave(struct mpi3mr_softc *sc)
* Return: 0 on success, non-zero on failure.
*/
static int mpi3mr_issue_reset(struct mpi3mr_softc *sc, U16 reset_type,
- U32 reset_reason)
+ U16 reset_reason)
{
int retval = -1;
U8 unlock_retry_count = 0;
- U32 host_diagnostic, ioc_status, ioc_config;
+ U32 host_diagnostic, ioc_status, ioc_config, scratch_pad0;
U32 timeout = MPI3MR_RESET_ACK_TIMEOUT * 10;
if ((reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET) &&
@@ -5810,7 +6215,14 @@ static int mpi3mr_issue_reset(struct mpi3mr_softc *sc, U16 reset_type,
unlock_retry_count, host_diagnostic);
} while (!(host_diagnostic & MPI3_SYSIF_HOST_DIAG_DIAG_WRITE_ENABLE));
- mpi3mr_regwrite(sc, MPI3_SYSIF_SCRATCHPAD0_OFFSET, reset_reason);
+ if (reset_type == MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT)
+ mpi3mr_set_diagsave(sc);
+
+ scratch_pad0 = ((MPI3MR_RESET_REASON_OSTYPE_FREEBSD <<
+ MPI3MR_RESET_REASON_OSTYPE_SHIFT) |
+ (sc->facts.ioc_num <<
+ MPI3MR_RESET_REASON_IOCNUM_SHIFT) | reset_reason);
+ mpi3mr_regwrite(sc, MPI3_SYSIF_SCRATCHPAD0_OFFSET, scratch_pad0);
mpi3mr_regwrite(sc, MPI3_SYSIF_HOST_DIAG_OFFSET, host_diagnostic | reset_type);
if (reset_type == MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET) {
@@ -5889,7 +6301,7 @@ inline void mpi3mr_cleanup_event_taskq(struct mpi3mr_softc *sc)
* Return: 0 on success, non-zero on failure.
*/
int mpi3mr_soft_reset_handler(struct mpi3mr_softc *sc,
- U32 reset_reason, bool snapdump)
+ U16 reset_reason, bool snapdump)
{
int retval = 0, i = 0;
enum mpi3mr_iocstate ioc_state;
@@ -5929,6 +6341,9 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_softc *sc,
sc->reset_in_progress = 1;
sc->block_ioctls = 1;
+ if (sc->timestamp_thread_active)
+ wakeup(&sc->timestamp_chan);
+
while (mpi3mr_atomic_read(&sc->pend_ioctls) && (i < PEND_IOCTLS_COMP_WAIT_TIME)) {
ioc_state = mpi3mr_get_iocstate(sc);
if (ioc_state == MRIOC_STATE_FAULT)
@@ -5996,10 +6411,14 @@ out:
mpi3mr_app_send_aen(sc);
}
} else {
- mpi3mr_issue_reset(sc,
- MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
+ ioc_state = mpi3mr_get_iocstate(sc);
+ if (ioc_state != MRIOC_STATE_FAULT)
+ mpi3mr_issue_reset(sc,
+ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
+
sc->unrecoverable = 1;
sc->reset_in_progress = 0;
+ sc->block_ioctls = 0;
}
mpi3mr_dprint(sc, MPI3MR_INFO, "Soft Reset: %s\n", ((retval == 0) ? "SUCCESS" : "FAILED"));