git: e80317babdb9 - main - mpi3mr: Add NVData Parameter for Host Timestamp Synchronization
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 28 Apr 2025 03:25:22 UTC
The branch main has been updated by imp:
URL: https://cgit.FreeBSD.org/src/commit/?id=e80317babdb9044962dcbf16c69633579cd90b00
commit e80317babdb9044962dcbf16c69633579cd90b00
Author: Chandrakanth patil <chandrakanth.patil@broadcom.com>
AuthorDate: 2025-04-27 23:39:23 +0000
Commit: Warner Losh <imp@FreeBSD.org>
CommitDate: 2025-04-28 03:22:55 +0000
mpi3mr: Add NVData Parameter for Host Timestamp Synchronization
The driver now retrieves the Time Stamp value from Driver Page 1
during load and after controller reset. If the value is valid, it
is used to enable periodic host timestamp synchronization.
This adds a tunable NVData parameter to control the behavior of
host time sync, enhancing flexibility and platform-specific control.
Reviewed by: ssaxena, imp
Differential Revision: https://reviews.freebsd.org/D49748
---
sys/dev/mpi3mr/mpi3mr.c | 325 ++++++++++++++++++++++++++++++++++++++++++++
sys/dev/mpi3mr/mpi3mr.h | 14 +-
sys/dev/mpi3mr/mpi3mr_pci.c | 25 +++-
3 files changed, 362 insertions(+), 2 deletions(-)
diff --git a/sys/dev/mpi3mr/mpi3mr.c b/sys/dev/mpi3mr/mpi3mr.c
index c92d05d972de..398569a3963c 100644
--- a/sys/dev/mpi3mr/mpi3mr.c
+++ b/sys/dev/mpi3mr/mpi3mr.c
@@ -1338,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" },
};
@@ -1915,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",
@@ -2877,6 +2887,12 @@ retry_init:
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;
@@ -3042,6 +3058,9 @@ retry_init:
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;
err_retry:
@@ -3119,6 +3138,116 @@ 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(¤t_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)
{
@@ -4398,6 +4527,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;
@@ -5303,6 +5435,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)
{
@@ -5334,6 +5644,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);
@@ -5512,6 +5825,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;
@@ -5629,6 +5947,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);
@@ -5672,6 +5993,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);
@@ -6014,6 +6336,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)
diff --git a/sys/dev/mpi3mr/mpi3mr.h b/sys/dev/mpi3mr/mpi3mr.h
index 1ab6b8815f59..f48d58ee85d2 100644
--- a/sys/dev/mpi3mr/mpi3mr.h
+++ b/sys/dev/mpi3mr/mpi3mr.h
@@ -141,6 +141,7 @@
#define MPI3MR_HOSTTAG_PELABORT 3
#define MPI3MR_HOSTTAG_PELWAIT 4
#define MPI3MR_HOSTTAG_TMS 5
+#define MPI3MR_HOSTTAG_CFGCMDS 6
#define MAX_MGMT_ADAPTERS 8
#define MPI3MR_WAIT_BEFORE_CTRL_RESET 5
@@ -163,7 +164,7 @@ extern char fmt_os_ver[16];
raw_os_ver[3], raw_os_ver[4], raw_os_ver[5],\
raw_os_ver[6]);
#define MPI3MR_NUM_DEVRMCMD 1
-#define MPI3MR_HOSTTAG_DEVRMCMD_MIN (MPI3MR_HOSTTAG_TMS + 1)
+#define MPI3MR_HOSTTAG_DEVRMCMD_MIN (MPI3MR_HOSTTAG_CFGCMDS + 1)
#define MPI3MR_HOSTTAG_DEVRMCMD_MAX (MPI3MR_HOSTTAG_DEVRMCMD_MIN + \
MPI3MR_NUM_DEVRMCMD - 1)
#define MPI3MR_INTERNALCMDS_RESVD MPI3MR_HOSTTAG_DEVRMCMD_MAX
@@ -237,6 +238,8 @@ extern char fmt_os_ver[16];
#define WRITE_SAME_32 0x0d
+#define MPI3MR_TSUPDATE_INTERVAL 900
+
struct completion {
unsigned int done;
struct mtx lock;
@@ -313,6 +316,7 @@ enum mpi3mr_reset_reason {
MPI3MR_RESET_FROM_SCSIIO_TIMEOUT = 26,
MPI3MR_RESET_FROM_FIRMWARE = 27,
MPI3MR_DEFAULT_RESET_REASON = 28,
+ MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT = 29,
MPI3MR_RESET_REASON_COUNT,
};
@@ -555,6 +559,7 @@ struct mpi3mr_softc {
char driver_name[MPI3MR_NAME_LENGTH];
int bars;
bus_addr_t dma_loaddr;
+ bus_addr_t dma_hiaddr;
u_int mpi3mr_debug;
struct mpi3mr_reset reset;
int max_msix_vectors;
@@ -688,6 +693,7 @@ struct mpi3mr_softc {
struct mpi3mr_drvr_cmd host_tm_cmds;
struct mpi3mr_drvr_cmd dev_rmhs_cmds[MPI3MR_NUM_DEVRMCMD];
struct mpi3mr_drvr_cmd evtack_cmds[MPI3MR_NUM_EVTACKCMD];
+ struct mpi3mr_drvr_cmd cfg_cmds;
U16 devrem_bitmap_sz;
void *devrem_bitmap;
@@ -765,6 +771,10 @@ struct mpi3mr_softc {
struct dma_memory_desc ioctl_chain_sge;
struct dma_memory_desc ioctl_resp_sge;
bool ioctl_sges_allocated;
+ struct proc *timestamp_thread_proc;
+ void *timestamp_chan;
+ u_int8_t timestamp_thread_active;
+ U32 ts_update_interval;
};
static __inline uint64_t
@@ -977,6 +987,7 @@ void
mpi3mrsas_release_simq_reinit(struct mpi3mr_cam_softc *cam_sc);
void
mpi3mr_watchdog_thread(void *arg);
+void mpi3mr_timestamp_thread(void *arg);
void mpi3mr_add_device(struct mpi3mr_softc *sc, U16 per_id);
int mpi3mr_remove_device(struct mpi3mr_softc *sc, U16 handle);
int
@@ -996,4 +1007,5 @@ void mpi3mr_poll_pend_io_completions(struct mpi3mr_softc *sc);
void int_to_lun(unsigned int lun, U8 *req_lun);
void trigger_reset_from_watchdog(struct mpi3mr_softc *sc, U8 reset_type, U16 reset_reason);
void mpi3mr_alloc_ioctl_dma_memory(struct mpi3mr_softc *sc);
+int mpi3mr_cfg_get_driver_pg1(struct mpi3mr_softc *sc);
#endif /*MPI3MR_H_INCLUDED*/
diff --git a/sys/dev/mpi3mr/mpi3mr_pci.c b/sys/dev/mpi3mr/mpi3mr_pci.c
index 194401c5a847..808349f26827 100644
--- a/sys/dev/mpi3mr/mpi3mr_pci.c
+++ b/sys/dev/mpi3mr/mpi3mr_pci.c
@@ -332,6 +332,13 @@ mpi3mr_ich_startup(void *arg)
mtx_unlock(&sc->mpi3mr_mtx);
+ error = mpi3mr_kproc_create(mpi3mr_timestamp_thread, sc,
+ &sc->timestamp_thread_proc, 0, 0,
+ "mpi3mr_timestamp_thread%d",
+ device_get_unit(sc->mpi3mr_dev));
+ if (error)
+ device_printf(sc->mpi3mr_dev, "Error %d starting timestamp thread\n", error);
+
error = mpi3mr_kproc_create(mpi3mr_watchdog_thread, sc,
&sc->watchdog_thread, 0, 0, "mpi3mr_watchdog%d",
device_get_unit(sc->mpi3mr_dev));
@@ -474,7 +481,7 @@ mpi3mr_pci_attach(device_t dev)
mpi3mr_dprint(sc, MPI3MR_ERROR, "CAM attach failed\n");
goto load_failed;
}
-
+
sc->mpi3mr_ich.ich_func = mpi3mr_ich_startup;
sc->mpi3mr_ich.ich_arg = sc;
if (config_intrhook_establish(&sc->mpi3mr_ich) != 0) {
@@ -664,10 +671,26 @@ mpi3mr_pci_detach(device_t dev)
mtx_lock(&sc->reset_mutex);
sc->mpi3mr_flags |= MPI3MR_FLAGS_SHUTDOWN;
+ if (sc->timestamp_thread_active)
+ wakeup(&sc->timestamp_chan);
+
if (sc->watchdog_thread_active)
wakeup(&sc->watchdog_chan);
mtx_unlock(&sc->reset_mutex);
+ i = 0;
+ while (sc->timestamp_thread_active && (i < 180)) {
+ i++;
+ if (!(i % 5)) {
+ mpi3mr_dprint(sc, MPI3MR_INFO,
+ "[%2d]waiting for "
+ "timestamp thread to quit reset %d\n", i,
+ sc->timestamp_thread_active);
+ }
+ pause("mpi3mr_shutdown", hz);
+ }
+
+ i = 0;
while (sc->reset_in_progress && (i < PEND_IOCTLS_COMP_WAIT_TIME)) {
i++;
if (!(i % 5)) {