From dcfce584f458c573b807a768041c2dcd54f2ae07 Mon Sep 17 00:00:00 2001 From: slm Date: Wed, 20 Aug 2014 23:09:27 +0000 Subject: [PATCH] MFC r269314 and r269316 r269314: Bring in LSI's phase16 - phase18 changes * Implements Start Stop Unit for SATA direct-attach devices in IR mode to avoid data corruption. * Use CAM_DEV_NOT_THERE instead of CAM_SEL_TIMEOUT and CAM_TID_INVALID r269316: Bring in LSI's phase19 changes * Removed unused mpssas_discovery_timeout function. * Don't alter mapping boundaries if not raid firmware. * Check free_busaddr instead of post_busaddr (diff minimisation really) Approved by: ken (co-mentor) and smh git-svn-id: svn://svn.freebsd.org/base/stable/10@270250 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- sys/dev/mps/mps.c | 67 +++++++++++++----- sys/dev/mps/mps_mapping.c | 11 +-- sys/dev/mps/mps_sas.c | 110 +++++++++++++++-------------- sys/dev/mps/mps_sas.h | 1 + sys/dev/mps/mps_sas_lsi.c | 144 +++++++++++++++++++++++++++++++++++++- sys/dev/mps/mpsvar.h | 7 +- 6 files changed, 263 insertions(+), 77 deletions(-) diff --git a/sys/dev/mps/mps.c b/sys/dev/mps/mps.c index c1c1f6c99..403a4d2f8 100644 --- a/sys/dev/mps/mps.c +++ b/sys/dev/mps/mps.c @@ -140,6 +140,7 @@ mps_diag_reset(struct mps_softc *sc,int sleep_flag) { uint32_t reg; int i, error, tries = 0; + uint8_t first_wait_done = FALSE; mps_dprint(sc, MPS_TRACE, "%s\n", __func__); @@ -182,15 +183,32 @@ mps_diag_reset(struct mps_softc *sc,int sleep_flag) /* Wait up to 300 seconds in 50ms intervals */ error = ETIMEDOUT; - for (i = 0; i < 60000; i++) { - /* wait 50 msec */ - if (mtx_owned(&sc->mps_mtx) && sleep_flag == CAN_SLEEP) - msleep(&sc->msleep_fake_chan, &sc->mps_mtx, 0, - "mpsdiag", hz/20); - else if (sleep_flag == CAN_SLEEP) - pause("mpsdiag", hz/20); - else - DELAY(50 * 1000); + for (i = 0; i < 6000; i++) { + /* + * Wait 50 msec. If this is the first time through, wait 256 + * msec to satisfy Diag Reset timing requirements. + */ + if (first_wait_done) { + if (mtx_owned(&sc->mps_mtx) && sleep_flag == CAN_SLEEP) + msleep(&sc->msleep_fake_chan, &sc->mps_mtx, 0, + "mpsdiag", hz/20); + else if (sleep_flag == CAN_SLEEP) + pause("mpsdiag", hz/20); + else + DELAY(50 * 1000); + } else { + DELAY(256 * 1000); + first_wait_done = TRUE; + } + /* + * Check for the RESET_ADAPTER bit to be cleared first, then + * wait for the RESET state to be cleared, which takes a little + * longer. + */ + reg = mps_regread(sc, MPI2_HOST_DIAGNOSTIC_OFFSET); + if (reg & MPI2_DIAG_RESET_ADAPTER) { + continue; + } reg = mps_regread(sc, MPI2_DOORBELL_OFFSET); if ((reg & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_RESET) { error = 0; @@ -236,7 +254,7 @@ mps_transition_ready(struct mps_softc *sc) sleep_flags = (sc->mps_flags & MPS_FLAGS_ATTACH_DONE) ? CAN_SLEEP:NO_SLEEP; error = 0; - while (tries++ < 5) { + while (tries++ < 1200) { reg = mps_regread(sc, MPI2_DOORBELL_OFFSET); mps_dprint(sc, MPS_INIT, "Doorbell= 0x%x\n", reg); @@ -592,7 +610,7 @@ mps_iocfacts_free(struct mps_softc *sc) mps_dprint(sc, MPS_TRACE, "%s\n", __func__); - if (sc->post_busaddr != 0) + if (sc->free_busaddr != 0) bus_dmamap_unload(sc->queues_dmat, sc->queues_map); if (sc->free_queue != NULL) bus_dmamem_free(sc->queues_dmat, sc->free_queue, @@ -656,6 +674,9 @@ int mps_reinit(struct mps_softc *sc) { int error; + struct mpssas_softc *sassc; + + sassc = sc->sassc; MPS_FUNCTRACE(sc); @@ -736,6 +757,8 @@ mps_reinit(struct mps_softc *sc) mps_dprint(sc, MPS_INFO, "%s finished sc %p post %u free %u\n", __func__, sc, sc->replypostindex, sc->replyfreeindex); + mpssas_release_simq_reinit(sassc); + return 0; } @@ -2510,6 +2533,7 @@ int mps_request_polled(struct mps_softc *sc, struct mps_command *cm) { int error, timeout = 0, rc; + struct timeval cur_time, start_time; error = 0; @@ -2517,22 +2541,33 @@ mps_request_polled(struct mps_softc *sc, struct mps_command *cm) cm->cm_complete = NULL; mps_map_command(sc, cm); + getmicrotime(&start_time); while ((cm->cm_flags & MPS_CM_FLAGS_COMPLETE) == 0) { mps_intr_locked(sc); - DELAY(50 * 1000); - if (timeout++ > 1000) { + if (mtx_owned(&sc->mps_mtx)) + msleep(&sc->msleep_fake_chan, &sc->mps_mtx, 0, + "mpspoll", hz/20); + else + pause("mpsdiag", hz/20); + + /* + * Check for real-time timeout and fail if more than 60 seconds. + */ + getmicrotime(&cur_time); + timeout = cur_time.tv_sec - start_time.tv_sec; + if (timeout > 60) { mps_dprint(sc, MPS_FAULT, "polling failed\n"); error = ETIMEDOUT; break; } } - + if (error) { mps_dprint(sc, MPS_FAULT, "Calling Reinit from %s\n", __func__); rc = mps_reinit(sc); - mps_dprint(sc, MPS_FAULT, "Reinit %s\n", - (rc == 0) ? "success" : "failed"); + mps_dprint(sc, MPS_FAULT, "Reinit %s\n", (rc == 0) ? "success" : + "failed"); } return (error); diff --git a/sys/dev/mps/mps_mapping.c b/sys/dev/mps/mps_mapping.c index 97e24be79..80022ea4a 100644 --- a/sys/dev/mps/mps_mapping.c +++ b/sys/dev/mps/mps_mapping.c @@ -336,12 +336,13 @@ _mapping_get_high_missing_mt_idx(struct mps_softc *sc) end_idx = sc->max_devices; if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0) start_idx = 1; - if (sc->ir_firmware) + if (sc->ir_firmware) { _mapping_get_ir_maprange(sc, &start_idx_ir, &end_idx_ir); - if (start_idx == start_idx_ir) - start_idx = end_idx_ir + 1; - else - end_idx = start_idx_ir; + if (start_idx == start_idx_ir) + start_idx = end_idx_ir + 1; + else + end_idx = start_idx_ir; + } mt_entry = &sc->mapping_table[start_idx]; for (map_idx = start_idx; map_idx < end_idx; map_idx++, mt_entry++) { if (mt_entry->missing_count > high_missing_count) { diff --git a/sys/dev/mps/mps_sas.c b/sys/dev/mps/mps_sas.c index 0dfc771ae..6ebf6954e 100644 --- a/sys/dev/mps/mps_sas.c +++ b/sys/dev/mps/mps_sas.c @@ -115,7 +115,6 @@ static uint8_t op_code_prot[256] = { MALLOC_DEFINE(M_MPSSAS, "MPSSAS", "MPS SAS memory"); -static void mpssas_discovery_timeout(void *data); static void mpssas_remove_device(struct mps_softc *, struct mps_command *); static void mpssas_remove_complete(struct mps_softc *, struct mps_command *); static void mpssas_action(struct cam_sim *sim, union ccb *ccb); @@ -190,6 +189,16 @@ mpssas_startup_increment(struct mpssas_softc *sassc) } } +void +mpssas_release_simq_reinit(struct mpssas_softc *sassc) +{ + if (sassc->flags & MPSSAS_QUEUE_FROZEN) { + sassc->flags &= ~MPSSAS_QUEUE_FROZEN; + xpt_release_simq(sassc->sim, 1); + mps_dprint(sassc->sc, MPS_INFO, "Unfreezing SIM queue\n"); + } +} + void mpssas_startup_decrement(struct mpssas_softc *sassc) { @@ -901,46 +910,6 @@ mpssas_discovery_end(struct mpssas_softc *sassc) } -static void -mpssas_discovery_timeout(void *data) -{ - struct mpssas_softc *sassc = data; - struct mps_softc *sc; - - sc = sassc->sc; - MPS_FUNCTRACE(sc); - - mps_lock(sc); - mps_dprint(sc, MPS_INFO, - "Timeout waiting for discovery, interrupts may not be working!\n"); - sassc->flags &= ~MPSSAS_DISCOVERY_TIMEOUT_PENDING; - - /* Poll the hardware for events in case interrupts aren't working */ - mps_intr_locked(sc); - - mps_dprint(sassc->sc, MPS_INFO, - "Finished polling after discovery timeout at %d\n", ticks); - - if ((sassc->flags & MPSSAS_IN_DISCOVERY) == 0) { - mpssas_discovery_end(sassc); - } else { - if (sassc->discovery_timeouts < MPSSAS_MAX_DISCOVERY_TIMEOUTS) { - sassc->flags |= MPSSAS_DISCOVERY_TIMEOUT_PENDING; - callout_reset(&sassc->discovery_callout, - MPSSAS_DISCOVERY_TIMEOUT * hz, - mpssas_discovery_timeout, sassc); - sassc->discovery_timeouts++; - } else { - mps_dprint(sassc->sc, MPS_FAULT, - "Discovery timed out, continuing.\n"); - sassc->flags &= ~MPSSAS_IN_DISCOVERY; - mpssas_discovery_end(sassc); - } - } - - mps_unlock(sc); -} - static void mpssas_action(struct cam_sim *sim, union ccb *ccb) { @@ -1005,7 +974,7 @@ mpssas_action(struct cam_sim *sim, union ccb *ccb) cts->ccb_h.target_id)); targ = &sassc->targets[cts->ccb_h.target_id]; if (targ->handle == 0x0) { - mpssas_set_ccbstatus(ccb, CAM_SEL_TIMEOUT); + mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); break; } @@ -1122,6 +1091,14 @@ mpssas_complete_all_commands(struct mps_softc *sc) wakeup(cm); completed = 1; } + + if (cm->cm_sc->io_cmds_active != 0) { + cm->cm_sc->io_cmds_active--; + } else { + mps_dprint(cm->cm_sc, MPS_INFO, "Warning: " + "io_cmds_active is out of sync - resynching to " + "0\n"); + } if ((completed == 0) && (cm->cm_state != MPS_CM_STATE_FREE)) { /* this should never happen, but if it does, log */ @@ -1649,14 +1626,14 @@ mpssas_action_scsiio(struct mpssas_softc *sassc, union ccb *ccb) if (targ->handle == 0x0) { mps_dprint(sc, MPS_ERROR, "%s NULL handle for target %u\n", __func__, csio->ccb_h.target_id); - mpssas_set_ccbstatus(ccb, CAM_SEL_TIMEOUT); + mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); xpt_done(ccb); return; } if (targ->flags & MPS_TARGET_FLAGS_RAID_COMPONENT) { mps_dprint(sc, MPS_ERROR, "%s Raid component no SCSI IO " "supported %u\n", __func__, csio->ccb_h.target_id); - mpssas_set_ccbstatus(ccb, CAM_TID_INVALID); + mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); xpt_done(ccb); return; } @@ -1687,13 +1664,16 @@ mpssas_action_scsiio(struct mpssas_softc *sassc, union ccb *ccb) if ((sc->mps_flags & MPS_FLAGS_SHUTDOWN) != 0) { mps_dprint(sc, MPS_INFO, "%s shutting down\n", __func__); - mpssas_set_ccbstatus(ccb, CAM_TID_INVALID); + mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); xpt_done(ccb); return; } cm = mps_alloc_command(sc); - if (cm == NULL) { + if (cm == NULL || (sc->mps_flags & MPS_FLAGS_DIAGRESET)) { + if (cm != NULL) { + mps_free_command(sc, cm); + } if ((sassc->flags & MPSSAS_QUEUE_FROZEN) == 0) { xpt_freeze_simq(sassc->sim, 1); sassc->flags |= MPSSAS_QUEUE_FROZEN; @@ -2172,6 +2152,18 @@ mpssas_scsiio_complete(struct mps_softc *sc, struct mps_command *cm) } } + /* + * If this is a Start Stop Unit command and it was issued by the driver + * during shutdown, decrement the refcount to account for all of the + * commands that were sent. All SSU commands should be completed before + * shutdown completes, meaning SSU_refcount will be 0 after SSU_started + * is TRUE. + */ + if (sc->SSU_started && (csio->cdb_io.cdb_bytes[0] == START_STOP_UNIT)) { + mps_dprint(sc, MPS_INFO, "Decrementing SSU count.\n"); + sc->SSU_refcount--; + } + /* Take the fast path to completion */ if (cm->cm_reply == NULL) { if (mpssas_get_ccbstatus(ccb) == CAM_REQ_INPROG) { @@ -3001,7 +2993,7 @@ mpssas_action_smpio(struct mpssas_softc *sassc, union ccb *ccb) mps_dprint(sc, MPS_ERROR, "%s: handle %d does not have a valid " "parent handle!\n", __func__, targ->handle); - mpssas_set_ccbstatus(ccb, CAM_REQ_INVALID); + mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); goto bailout; } #ifdef OLD_MPS_PROBE @@ -3012,7 +3004,7 @@ mpssas_action_smpio(struct mpssas_softc *sassc, union ccb *ccb) mps_dprint(sc, MPS_ERROR, "%s: handle %d does not have a valid " "parent target!\n", __func__, targ->handle); - mpssas_set_ccbstatus(ccb, CAM_REQ_INVALID); + mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); goto bailout; } @@ -3022,7 +3014,7 @@ mpssas_action_smpio(struct mpssas_softc *sassc, union ccb *ccb) "%s: handle %d parent %d does not " "have an SMP target!\n", __func__, targ->handle, parent_target->handle); - mpssas_set_ccbstatus(ccb, CAM_REQ_INVALID); + mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); goto bailout; } @@ -3035,7 +3027,7 @@ mpssas_action_smpio(struct mpssas_softc *sassc, union ccb *ccb) "%s: handle %d parent %d does not " "have an SMP target!\n", __func__, targ->handle, targ->parent_handle); - mpssas_set_ccbstatus(ccb, CAM_REQ_INVALID); + mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); goto bailout; } @@ -3044,7 +3036,7 @@ mpssas_action_smpio(struct mpssas_softc *sassc, union ccb *ccb) "%s: handle %d parent handle %d does " "not have a valid SAS address!\n", __func__, targ->handle, targ->parent_handle); - mpssas_set_ccbstatus(ccb, CAM_REQ_INVALID); + mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); goto bailout; } @@ -3057,7 +3049,7 @@ mpssas_action_smpio(struct mpssas_softc *sassc, union ccb *ccb) mps_dprint(sc, MPS_INFO, "%s: unable to find SAS address for handle %d\n", __func__, targ->handle); - mpssas_set_ccbstatus(ccb, CAM_REQ_INVALID); + mpssas_set_ccbstatus(ccb, CAM_DEV_NOT_THERE); goto bailout; } mpssas_send_smpcmd(sassc, ccb, sasaddr); @@ -3368,6 +3360,20 @@ mpssas_check_eedp(struct mps_softc *sc, struct cam_path *path, } xpt_path_string(local_path, path_str, sizeof(path_str)); + + /* + * If this is a SATA direct-access end device, + * mark it so that a SCSI StartStopUnit command + * will be sent to it when the driver is being + * shutdown. + */ + if ((cgd.inq_data.device == T_DIRECT) && + (target->devinfo & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) && + ((target->devinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) == + MPI2_SAS_DEVICE_INFO_END_DEVICE)) { + lun->stop_at_shutdown = TRUE; + } + mps_dprint(sc, MPS_INFO, "Sending read cap: path %s handle %d\n", path_str, target->handle); diff --git a/sys/dev/mps/mps_sas.h b/sys/dev/mps/mps_sas.h index dac49058d..0a3ddf158 100644 --- a/sys/dev/mps/mps_sas.h +++ b/sys/dev/mps/mps_sas.h @@ -35,6 +35,7 @@ struct mpssas_lun { lun_id_t lun_id; uint8_t eedp_formatted; uint32_t eedp_block_size; + uint8_t stop_at_shutdown; }; struct mpssas_target { diff --git a/sys/dev/mps/mps_sas_lsi.c b/sys/dev/mps/mps_sas_lsi.c index c219be14b..583632947 100644 --- a/sys/dev/mps/mps_sas_lsi.c +++ b/sys/dev/mps/mps_sas_lsi.c @@ -120,6 +120,9 @@ int mpssas_get_sas_address_for_sata_disk(struct mps_softc *sc, u64 *sas_address, u16 handle, u32 device_info); static int mpssas_volume_add(struct mps_softc *sc, u16 handle); +static void mpssas_SSU_to_SATA_devices(struct mps_softc *sc); +static void mpssas_stop_unit_done(struct cam_periph *periph, + union ccb *done_ccb); void mpssas_evt_handler(struct mps_softc *sc, uintptr_t data, @@ -909,6 +912,138 @@ mpssas_volume_add(struct mps_softc *sc, u16 handle) return (error); } +/** + * mpssas_SSU_to_SATA_devices + * @sc: per adapter object + * + * Looks through the target list and issues a StartStopUnit SCSI command to each + * SATA direct-access device. This helps to ensure that data corruption is + * avoided when the system is being shut down. This must be called after the IR + * System Shutdown RAID Action is sent if in IR mode. + * + * Return nothing. + */ +static void +mpssas_SSU_to_SATA_devices(struct mps_softc *sc) +{ + struct mpssas_softc *sassc = sc->sassc; + union ccb *ccb; + path_id_t pathid = cam_sim_path(sassc->sim); + target_id_t targetid; + struct mpssas_target *target; + struct mpssas_lun *lun; + char path_str[64]; + struct timeval cur_time, start_time; + + /* + * For each LUN of each target, issue a StartStopUnit command to stop + * the device. + */ + sc->SSU_started = TRUE; + sc->SSU_refcount = 0; + for (targetid = 0; targetid < sc->facts->MaxTargets; targetid++) { + target = &sassc->targets[targetid]; + if (target->handle == 0x0) { + continue; + } + + SLIST_FOREACH(lun, &target->luns, lun_link) { + ccb = xpt_alloc_ccb_nowait(); + if (ccb == NULL) { + mps_dprint(sc, MPS_FAULT, "Unable to alloc CCB " + "to stop unit.\n"); + return; + } + + /* + * The stop_at_shutdown flag will be set if this LUN is + * a SATA direct-access end device. + */ + if (lun->stop_at_shutdown) { + if (xpt_create_path(&ccb->ccb_h.path, + xpt_periph, pathid, targetid, + lun->lun_id) != CAM_REQ_CMP) { + mps_dprint(sc, MPS_FAULT, "Unable to " + "create LUN path to stop unit.\n"); + xpt_free_ccb(ccb); + return; + } + xpt_path_string(ccb->ccb_h.path, path_str, + sizeof(path_str)); + + mps_dprint(sc, MPS_INFO, "Sending StopUnit: " + "path %s handle %d\n", path_str, + target->handle); + + /* + * Issue a START STOP UNIT command for the LUN. + * Increment the SSU counter to be used to + * count the number of required replies. + */ + mps_dprint(sc, MPS_INFO, "Incrementing SSU " + "count\n"); + sc->SSU_refcount++; + ccb->ccb_h.target_id = + xpt_path_target_id(ccb->ccb_h.path); + ccb->ccb_h.target_lun = lun->lun_id; + ccb->ccb_h.ppriv_ptr1 = sassc; + scsi_start_stop(&ccb->csio, + /*retries*/0, + mpssas_stop_unit_done, + MSG_SIMPLE_Q_TAG, + /*start*/FALSE, + /*load/eject*/0, + /*immediate*/FALSE, + MPS_SENSE_LEN, + /*timeout*/10000); + xpt_action(ccb); + } + } + } + + /* + * Wait until all of the SSU commands have completed or time has + * expired (60 seconds). pause for 100ms each time through. If any + * command times out, the target will be reset in the SCSI command + * timeout routine. + */ + getmicrotime(&start_time); + while (sc->SSU_refcount) { + pause("mpswait", hz/10); + + getmicrotime(&cur_time); + if ((cur_time.tv_sec - start_time.tv_sec) > 60) { + mps_dprint(sc, MPS_FAULT, "Time has expired waiting " + "for SSU commands to complete.\n"); + break; + } + } +} + +static void +mpssas_stop_unit_done(struct cam_periph *periph, union ccb *done_ccb) +{ + struct mpssas_softc *sassc; + char path_str[64]; + + sassc = (struct mpssas_softc *)done_ccb->ccb_h.ppriv_ptr1; + + xpt_path_string(done_ccb->ccb_h.path, path_str, sizeof(path_str)); + mps_dprint(sassc->sc, MPS_INFO, "Completing stop unit for %s\n", + path_str); + + if (done_ccb == NULL) + return; + + /* + * Nothing more to do except free the CCB and path. If the command + * timed out, an abort reset, then target reset will be issued during + * the SCSI Command process. + */ + xpt_free_path(done_ccb->ccb_h.path); + xpt_free_ccb(done_ccb); +} + /** * mpssas_ir_shutdown - IR shutdown notification * @sc: per adapter object @@ -933,7 +1068,7 @@ mpssas_ir_shutdown(struct mps_softc *sc) /* is IR firmware build loaded? */ if (!sc->ir_firmware) - return; + goto out; /* are there any volumes? Look at IR target IDs. */ // TODO-later, this should be looked up in the RAID config structure @@ -958,11 +1093,11 @@ mpssas_ir_shutdown(struct mps_softc *sc) } if (!found_volume) - return; + goto out; if ((cm = mps_alloc_command(sc)) == NULL) { printf("%s: command alloc failed\n", __func__); - return; + goto out; } action = (MPI2_RAID_ACTION_REQUEST *)cm->cm_req; @@ -978,4 +1113,7 @@ mpssas_ir_shutdown(struct mps_softc *sc) */ if (cm) mps_free_command(sc, cm); + +out: + mpssas_SSU_to_SATA_devices(sc); } diff --git a/sys/dev/mps/mpsvar.h b/sys/dev/mps/mpsvar.h index 50e93f00a..bae023e67 100644 --- a/sys/dev/mps/mpsvar.h +++ b/sys/dev/mps/mpsvar.h @@ -32,7 +32,7 @@ #ifndef _MPSVAR_H #define _MPSVAR_H -#define MPS_DRIVER_VERSION "16.00.00.00-fbsd" +#define MPS_DRIVER_VERSION "19.00.00.00-fbsd" #define MPS_DB_MAX_WAIT 2500 @@ -417,6 +417,10 @@ struct mps_softc { char exclude_ids[80]; struct timeval lastfail; + + /* StartStopUnit command handling at shutdown */ + uint32_t SSU_refcount; + uint8_t SSU_started; }; struct mps_config_params { @@ -759,6 +763,7 @@ struct mpssas_target * mpssas_find_target_by_handle(struct mpssas_softc *, int, void mpssas_realloc_targets(struct mps_softc *sc, int maxtargets); struct mps_command * mpssas_alloc_tm(struct mps_softc *sc); void mpssas_free_tm(struct mps_softc *sc, struct mps_command *tm); +void mpssas_release_simq_reinit(struct mpssas_softc *sassc); SYSCTL_DECL(_hw_mps); -- 2.45.0