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)) {