git: 004ce88ad1ef - main - mpr: Add workaround for too few slots being automatically scanned
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 31 Aug 2025 19:01:33 UTC
The branch main has been updated by imp: URL: https://cgit.FreeBSD.org/src/commit/?id=004ce88ad1efd42a1d7d5692849b4aa6906178fc commit 004ce88ad1efd42a1d7d5692849b4aa6906178fc Author: Peter Eriksson <pen@lysator.liu.se> AuthorDate: 2025-08-31 18:58:56 +0000 Commit: Warner Losh <imp@FreeBSD.org> CommitDate: 2025-08-31 19:01:09 +0000 mpr: Add workaround for too few slots being automatically scanned This patch adds a /boot/loader.conf setting that makes it possibly to override the detected number of slots in storage enclosures. Some (yes I'm looking at you HPE D6020!) reports less available slots that there actually are (the D6020 seems to report 18 but actually has 35 per drawer). This causes the mpr driver to have problems detecting/managing all drives in a multienclosure setting. For the D6020 this occurs when connecting two or more fully equipped (140 drives) enclosures to one controller... This problem can be "fixed" by adding the following to /boot/loader.conf and rebooting: hw.mpr.encl_min_slots="35" Note: I (Warner) don't have this hardware to see if there's some way to fix the detection, so I'm committing this as a stop-gap. It's a no-op if no tunable is set. PR: 271238 Reivewed by: imp --- sys/dev/mpr/mpr.c | 10 ++++++++++ sys/dev/mpr/mpr_mapping.c | 18 ++++++++++++++++++ sys/dev/mpr/mprvar.h | 1 + 3 files changed, 29 insertions(+) diff --git a/sys/dev/mpr/mpr.c b/sys/dev/mpr/mpr.c index d1c572e40669..262d6b58b705 100644 --- a/sys/dev/mpr/mpr.c +++ b/sys/dev/mpr/mpr.c @@ -1729,6 +1729,7 @@ mpr_get_tunables(struct mpr_softc *sc) sc->enable_ssu = MPR_SSU_ENABLE_SSD_DISABLE_HDD; sc->spinup_wait_time = DEFAULT_SPINUP_WAIT; sc->use_phynum = 1; + sc->encl_min_slots = 0; sc->max_reqframes = MPR_REQ_FRAMES; sc->max_prireqframes = MPR_PRI_REQ_FRAMES; sc->max_replyframes = MPR_REPLY_FRAMES; @@ -1748,6 +1749,7 @@ mpr_get_tunables(struct mpr_softc *sc) TUNABLE_INT_FETCH("hw.mpr.enable_ssu", &sc->enable_ssu); TUNABLE_INT_FETCH("hw.mpr.spinup_wait_time", &sc->spinup_wait_time); TUNABLE_INT_FETCH("hw.mpr.use_phy_num", &sc->use_phynum); + TUNABLE_INT_FETCH("hw.mpr.encl_min_slots", &sc->encl_min_slots); TUNABLE_INT_FETCH("hw.mpr.max_reqframes", &sc->max_reqframes); TUNABLE_INT_FETCH("hw.mpr.max_prireqframes", &sc->max_prireqframes); TUNABLE_INT_FETCH("hw.mpr.max_replyframes", &sc->max_replyframes); @@ -1797,6 +1799,10 @@ mpr_get_tunables(struct mpr_softc *sc) device_get_unit(sc->mpr_dev)); TUNABLE_INT_FETCH(tmpstr, &sc->use_phynum); + snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.encl_min_slots", + device_get_unit(sc->mpr_dev)); + TUNABLE_INT_FETCH(tmpstr, &sc->encl_min_slots); + snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_reqframes", device_get_unit(sc->mpr_dev)); TUNABLE_INT_FETCH(tmpstr, &sc->max_reqframes); @@ -1951,6 +1957,10 @@ mpr_setup_sysctl(struct mpr_softc *sc) SYSCTL_ADD_UQUAD(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, "prp_page_alloc_fail", CTLFLAG_RD, &sc->prp_page_alloc_fail, "PRP page allocation failures"); + + SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), + OID_AUTO, "encl_min_slots", CTLFLAG_RW, &sc->encl_min_slots, 0, + "force enclosure minimum slots"); } static struct mpr_debug_string { diff --git a/sys/dev/mpr/mpr_mapping.c b/sys/dev/mpr/mpr_mapping.c index f9a9ac1c53d0..38aa4dfc7ef2 100644 --- a/sys/dev/mpr/mpr_mapping.c +++ b/sys/dev/mpr/mpr_mapping.c @@ -2785,6 +2785,8 @@ mpr_mapping_enclosure_dev_status_change_event(struct mpr_softc *sc, * DPM, if it's being used. */ if (enc_idx != MPR_ENCTABLE_BAD_IDX) { + u16 new_num_slots; + et_entry = &sc->enclosure_table[enc_idx]; if (et_entry->init_complete && !et_entry->missing_count) { @@ -2796,6 +2798,17 @@ mpr_mapping_enclosure_dev_status_change_event(struct mpr_softc *sc, et_entry->enc_handle = le16toh(event_data-> EnclosureHandle); et_entry->start_slot = le16toh(event_data->StartSlot); + new_num_slots = le16toh(event_data->NumSlots); + if (new_num_slots < sc->encl_min_slots) { + mpr_dprint(sc, MPR_MAPPING, "%s: Enclosure %d num_slots %d, overriding with %d.\n", + __func__, enc_idx, new_num_slots, sc->encl_min_slots); + new_num_slots = sc->encl_min_slots; + } + if (et_entry->num_slots != new_num_slots) { + mpr_dprint(sc, MPR_MAPPING, "%s: Enclosure %d old num_slots %d, new %d.\n", + __func__, enc_idx, et_entry->num_slots, sc->encl_min_slots); + et_entry->num_slots = new_num_slots; + } saved_phy_bits = et_entry->phy_bits; et_entry->phy_bits |= le32toh(event_data->PhyBits); if (saved_phy_bits != et_entry->phy_bits) @@ -2858,6 +2871,11 @@ mpr_mapping_enclosure_dev_status_change_event(struct mpr_softc *sc, et_entry->start_index = MPR_MAPTABLE_BAD_IDX; et_entry->dpm_entry_num = MPR_DPM_BAD_IDX; et_entry->num_slots = le16toh(event_data->NumSlots); + if (et_entry->num_slots < sc->encl_min_slots) { + mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: Enclosure %d num_slots is %d, overriding with %d.\n", + __func__, enc_idx, et_entry->num_slots, sc->encl_min_slots); + et_entry->num_slots = sc->encl_min_slots; + } et_entry->start_slot = le16toh(event_data->StartSlot); et_entry->phy_bits = le32toh(event_data->PhyBits); } diff --git a/sys/dev/mpr/mprvar.h b/sys/dev/mpr/mprvar.h index 0f1743f4266e..93f3fbffe079 100644 --- a/sys/dev/mpr/mprvar.h +++ b/sys/dev/mpr/mprvar.h @@ -366,6 +366,7 @@ struct mpr_softc { int spinup_wait_time; int use_phynum; int dump_reqs_alltypes; + int encl_min_slots; uint64_t chain_alloc_fail; uint64_t prp_page_alloc_fail; struct sysctl_ctx_list sysctl_ctx;