Fix several problems with mapping code.

Reviewed by:    ken, scottl, asomers, ambrisko, mav
Approved by:	ken, mav
MFC after:      1 week
Differential Revision: https://reviews.freebsd.org/D10878
This commit is contained in:
Stephen McConnell 2017-05-25 19:14:44 +00:00
parent 0edcc5b8d5
commit 635e58c715
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=318895
7 changed files with 860 additions and 419 deletions

View File

@ -1,8 +1,8 @@
.\"
.\" Copyright (c) 2010 Spectra Logic Corporation
.\" Copyright (c) 2014 LSI Corp
.\" Copyright (c) 2016 Avago Technologies
.\" Copyright (c) 2016 Broadcom Ltd.
.\" Copyright (c) 2015-2017 Avago Technologies
.\" Copyright (c) 2015-2017 Broadcom Ltd.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@ -38,7 +38,7 @@
.\" $Id: //depot/SpectraBSD/head/share/man/man4/mps.4#6 $
.\" $FreeBSD$
.\"
.Dd July 5, 2016
.Dd May 25, 2017
.Dt MPS 4
.Os
.Sh NAME
@ -241,13 +241,13 @@ Send SSU to HDDs, but not to SSDs.
Send SSU to both HDDs and SSDs.
.El
.Pp
To control the feature for a specific adapter, set this tunable value in
To control this feature for a specific adapter, set this tunable value in
.Xr loader.conf 5 :
.Bd -literal -offset indent
dev.mps.X.enable_ssu
.Ed
.Pp
The same set of values are valid when setting this tunable for all adapters.
The same set of values are valid as when setting this tunable for all adapters.
.Pp
SATA disks that take several seconds to spin up and fail the SATA Identify
command might not be discovered by the driver.
@ -273,6 +273,45 @@ dev.mps.X.spinup_wait_time=NNNN
tunable.
NNNN is the number of seconds to wait for SATA devices to spin up when they fail
the initial SATA Identify command.
.Pp
The driver can map devices discovered by the adapter so that target IDs
corresponding to a specific device persist across resets and reboots.
In some cases it is possible for devices to lose their mapped IDs due to
unexpected behavior from certain hardware, such as some types of enclosures.
To overcome this problem, a tunable is provided that will force the driver to
map devices using the Phy number associated with the device.
This feature is not recommended if the topology includes multiple
enclosures/expanders.
If multiple enclosures/expanders are present in the topology, Phy numbers are
repeated, causing all devices at these Phy numbers except the first device to
fail enumeration.
To control this feature for all adapters, set the
.Bd -literal -offset indent
hw.mps.use_phy_num
.Ed
.Pp
tunable in
.Xr loader.conf 5
to one of these values:
.Bl -tag -width 6n -offset indent
.It -1
Only use Phy numbers to map devices and bypass the driver's mapping logic.
.It 0
Never use Phy numbers to map devices.
.It 1
Use Phy numbers to map devices, but only if the driver's mapping logic fails
to map the device that is being enumerated.
This is the default value.
.El
.Pp
To control this feature for a specific adapter, set this tunable value in
.Xr loader.conf 5 :
.Bd -literal -offset indent
dev.mps.X.use_phy_num
.Ed
.Pp
The same set of values are valid as when setting this tunable for all adapters.
.Pp
.Sh DEBUGGING
To enable debugging prints from the
.Nm

View File

@ -505,7 +505,8 @@ mps_iocfacts_allocate(struct mps_softc *sc, uint8_t attaching)
*/
if (reallocating) {
mps_iocfacts_free(sc);
mpssas_realloc_targets(sc, saved_facts.MaxTargets);
mpssas_realloc_targets(sc, saved_facts.MaxTargets +
saved_facts.MaxVolumes);
}
/*
@ -1518,6 +1519,7 @@ mps_attach(struct mps_softc *sc)
mtx_init(&sc->mps_mtx, "MPT2SAS lock", NULL, MTX_DEF);
callout_init_mtx(&sc->periodic, &sc->mps_mtx, 0);
callout_init_mtx(&sc->device_check_callout, &sc->mps_mtx, 0);
TAILQ_INIT(&sc->event_list);
timevalclear(&sc->lastfail);
@ -1682,6 +1684,7 @@ mps_free(struct mps_softc *sc)
mps_unlock(sc);
/* Lock must not be held for this */
callout_drain(&sc->periodic);
callout_drain(&sc->device_check_callout);
if (((error = mps_detach_log(sc)) != 0) ||
((error = mps_detach_sas(sc)) != 0))

File diff suppressed because it is too large Load Diff

View File

@ -733,7 +733,7 @@ mps_attach_sas(struct mps_softc *sc)
* of MaxTargets here so that we don't get into trouble later. This
* should move into the reinit logic.
*/
sassc->maxtargets = sc->facts->MaxTargets;
sassc->maxtargets = sc->facts->MaxTargets + sc->facts->MaxVolumes;
sassc->targets = malloc(sizeof(struct mpssas_target) *
sassc->maxtargets, M_MPT2, M_WAITOK|M_ZERO);
if(!sassc->targets) {
@ -910,6 +910,25 @@ mpssas_discovery_end(struct mpssas_softc *sassc)
if (sassc->flags & MPSSAS_DISCOVERY_TIMEOUT_PENDING)
callout_stop(&sassc->discovery_callout);
/*
* After discovery has completed, check the mapping table for any
* missing devices and update their missing counts. Only do this once
* whenever the driver is initialized so that missing counts aren't
* updated unnecessarily. Note that just because discovery has
* completed doesn't mean that events have been processed yet. The
* check_devices function is a callout timer that checks if ALL devices
* are missing. If so, it will wait a little longer for events to
* complete and keep resetting itself until some device in the mapping
* table is not missing, meaning that event processing has started.
*/
if (sc->track_mapping_events) {
mps_dprint(sc, MPS_XINFO | MPS_MAPPING, "Discovery has "
"completed. Check for missing devices in the mapping "
"table.\n");
callout_reset(&sc->device_check_callout,
MPS_MISSING_CHECK_DELAY * hz, mps_mapping_check_devices,
sc);
}
}
static void
@ -942,7 +961,12 @@ mpssas_action(struct cam_sim *sim, union ccb *ccb)
cpi->hba_eng_cnt = 0;
cpi->max_target = sassc->maxtargets - 1;
cpi->max_lun = 255;
cpi->initiator_id = sassc->maxtargets - 1;
/*
* initiator_id is set here to an ID outside the set of valid
* target IDs (including volumes).
*/
cpi->initiator_id = sassc->maxtargets;
strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
strlcpy(cpi->hba_vid, "Avago Tech", HBA_IDLEN);
strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);

View File

@ -217,9 +217,11 @@ mpssas_fw_work(struct mps_softc *sc, struct mps_fw_event_work *fw_event)
switch (phy->PhyStatus & MPI2_EVENT_SAS_TOPO_RC_MASK) {
case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
if (mpssas_add_device(sc,
le16toh(phy->AttachedDevHandle), phy->LinkRate)){
printf("%s: failed to add device with "
"handle 0x%x\n", __func__,
le16toh(phy->AttachedDevHandle),
phy->LinkRate)){
mps_dprint(sc, MPS_ERROR, "%s: "
"failed to add device with handle "
"0x%x\n", __func__,
le16toh(phy->AttachedDevHandle));
mpssas_prepare_remove(sassc, le16toh(
phy->AttachedDevHandle));
@ -283,8 +285,8 @@ mpssas_fw_work(struct mps_softc *sc, struct mps_fw_event_work *fw_event)
element =
(Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
id = mps_mapping_get_raid_id_from_handle
(sc, element->VolDevHandle);
id = mps_mapping_get_raid_tid_from_handle(sc,
element->VolDevHandle);
mps_mapping_ir_config_change_event(sc, event_data);
@ -293,7 +295,8 @@ mpssas_fw_work(struct mps_softc *sc, struct mps_fw_event_work *fw_event)
case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
case MPI2_EVENT_IR_CHANGE_RC_ADDED:
if (!foreign_config) {
if (mpssas_volume_add(sc, le16toh(element->VolDevHandle))){
if (mpssas_volume_add(sc,
le16toh(element->VolDevHandle))){
printf("%s: failed to add RAID "
"volume with handle 0x%x\n",
__func__, le16toh(element->
@ -333,12 +336,16 @@ mpssas_fw_work(struct mps_softc *sc, struct mps_fw_event_work *fw_event)
* Phys Disk of a volume has been created. Hide
* it from the OS.
*/
targ = mpssas_find_target_by_handle(sassc, 0, element->PhysDiskDevHandle);
targ = mpssas_find_target_by_handle(sassc, 0,
element->PhysDiskDevHandle);
if (targ == NULL)
break;
/* Set raid component flags only if it is not WD.
* OR WrapDrive with WD_HIDE_ALWAYS/WD_HIDE_IF_VOLUME is set in NVRAM
/*
* Set raid component flags only if it is not
* WD. OR WrapDrive with
* WD_HIDE_ALWAYS/WD_HIDE_IF_VOLUME is set in
* NVRAM
*/
if((!sc->WD_available) ||
((sc->WD_available &&
@ -674,10 +681,17 @@ mpssas_add_device(struct mps_softc *sc, u16 handle, u8 linkrate){
* 1 - use the PhyNum field as a fallback to the mapping logic
* 0 - never use the PhyNum field
* -1 - only use the PhyNum field
*
* Note that using the Phy number to map a device can cause device adds
* to fail if multiple enclosures/expanders are in the topology. For
* example, if two devices are in the same slot number in two different
* enclosures within the topology, only one of those devices will be
* added. PhyNum mapping should not be used if multiple enclosures are
* in the topology.
*/
id = MPS_MAP_BAD_ID;
if (sc->use_phynum != -1)
id = mps_mapping_get_sas_id(sc, sas_address, handle);
id = mps_mapping_get_tid(sc, sas_address, handle);
if (id == MPS_MAP_BAD_ID) {
if ((sc->use_phynum == 0)
|| ((id = config_page.PhyNum) > sassc->maxtargets)) {
@ -688,19 +702,31 @@ mpssas_add_device(struct mps_softc *sc, u16 handle, u8 linkrate){
goto out;
}
}
mps_dprint(sc, MPS_MAPPING, "%s: Target ID for added device is %d.\n",
__func__, id);
if (mpssas_check_id(sassc, id) != 0) {
device_printf(sc->mps_dev, "Excluding target id %d\n", id);
error = ENXIO;
goto out;
}
/*
* Only do the ID check and reuse check if the target is not from a
* RAID Component. For Physical Disks of a Volume, the ID will be reused
* when a volume is deleted because the mapping entry for the PD will
* still be in the mapping table. The ID check should not be done here
* either since this PD is already being used.
*/
targ = &sassc->targets[id];
if (targ->handle != 0x0) {
mps_dprint(sc, MPS_MAPPING, "Attempting to reuse target id "
"%d handle 0x%04x\n", id, targ->handle);
error = ENXIO;
goto out;
if (!(targ->flags & MPS_TARGET_FLAGS_RAID_COMPONENT)) {
if (mpssas_check_id(sassc, id) != 0) {
device_printf(sc->mps_dev, "Excluding target id %d\n",
id);
error = ENXIO;
goto out;
}
if (targ->handle != 0x0) {
mps_dprint(sc, MPS_MAPPING, "Attempting to reuse "
"target id %d handle 0x%04x\n", id, targ->handle);
error = ENXIO;
goto out;
}
}
mps_dprint(sc, MPS_MAPPING, "SAS Address from SAS device page0 = %jx\n",
@ -787,7 +813,6 @@ mpssas_add_device(struct mps_softc *sc, u16 handle, u8 linkrate){
}
mpssas_startup_decrement(sassc);
return (error);
}
int
@ -1040,7 +1065,7 @@ mpssas_volume_add(struct mps_softc *sc, u16 handle)
goto out;
}
id = mps_mapping_get_raid_id(sc, wwid, handle);
id = mps_mapping_get_raid_tid(sc, wwid, handle);
if (id == MPS_MAP_BAD_ID) {
printf("%s: could not get ID for volume with handle 0x%04x and "
"WWID 0x%016llx\n", __func__, handle,
@ -1099,7 +1124,7 @@ mpssas_SSU_to_SATA_devices(struct mps_softc *sc)
*/
sc->SSU_started = TRUE;
sc->SSU_refcount = 0;
for (targetid = 0; targetid < sc->facts->MaxTargets; targetid++) {
for (targetid = 0; targetid < sc->max_devices; targetid++) {
target = &sassc->targets[targetid];
if (target->handle == 0x0) {
continue;
@ -1281,7 +1306,7 @@ mpssas_ir_shutdown(struct mps_softc *sc)
* 3: enable to SSD and HDD
* anything else will default to 1.
*/
for (targetid = 0; targetid < sc->facts->MaxTargets; targetid++) {
for (targetid = 0; targetid < sc->max_devices; targetid++) {
target = &sc->sassc->targets[targetid];
if (target->handle == 0x0) {
continue;

View File

@ -2052,7 +2052,7 @@ mps_user_btdh(struct mps_softc *sc, mps_btdh_mapping_t *data)
data->DevHandle = dev_handle;
} else {
bus = 0;
target = mps_mapping_get_sas_id_from_handle(sc, dev_handle);
target = mps_mapping_get_tid_from_handle(sc, dev_handle);
data->Bus = bus;
data->TargetID = target;
}

View File

@ -33,7 +33,7 @@
#ifndef _MPSVAR_H
#define _MPSVAR_H
#define MPS_DRIVER_VERSION "21.01.00.00-fbsd"
#define MPS_DRIVER_VERSION "21.02.00.00-fbsd"
#define MPS_DB_MAX_WAIT 2500
@ -53,6 +53,7 @@
#define MPS_PERIODIC_DELAY 1 /* 1 second heartbeat/watchdog check */
#define MPS_ATA_ID_TIMEOUT 5 /* 5 second timeout for SATA ID cmd */
#define MPS_MISSING_CHECK_DELAY 10 /* 10 seconds between missing check */
#define MPS_SCSI_RI_INVALID_FRAME (0x00000002)
#define MPS_STRING_LENGTH 64
@ -70,7 +71,6 @@
#define MPS_MAX_MISSING_COUNT 0x0F
#define MPS_DEV_RESERVED 0x20000000
#define MPS_MAP_IN_USE 0x10000000
#define MPS_RAID_CHANNEL 1
#define MPS_MAP_BAD_ID 0xFFFFFFFF
/*
@ -107,7 +107,6 @@ typedef uint64_t u64;
* @phy_bits: bitfields indicating controller phys
* @dpm_entry_num: index of this device in device persistent map table
* @dev_handle: device handle for the device pointed by this entry
* @channel: target channel
* @id: target id
* @missing_count: number of times the device not detected by driver
* @hide_flag: Hide this physical disk/not (foreign configuration)
@ -119,8 +118,7 @@ struct dev_mapping_table {
u32 phy_bits;
u16 dpm_entry_num;
u16 dev_handle;
u8 reserved1;
u8 channel;
u16 reserved1;
u16 id;
u8 missing_count;
u8 init_complete;
@ -293,6 +291,7 @@ struct mps_softc {
struct mps_command *commands;
struct mps_chain *chains;
struct callout periodic;
struct callout device_check_callout;
struct mpssas_softc *sassc;
char tmp_string[MPS_STRING_LENGTH];
@ -377,13 +376,10 @@ struct mps_softc {
uint8_t max_volumes;
uint8_t num_enc_table_entries;
uint8_t num_rsvd_entries;
uint8_t num_channels;
uint16_t max_dpm_entries;
uint8_t is_dpm_enable;
uint8_t track_mapping_events;
uint32_t pending_map_events;
uint8_t mt_full_retry;
uint8_t mt_add_device_failed;
/* FW diag Buffer List */
mps_fw_diagnostic_buffer_t
@ -732,19 +728,18 @@ void mps_wd_config_pages(struct mps_softc *sc);
int mps_mapping_initialize(struct mps_softc *);
void mps_mapping_topology_change_event(struct mps_softc *,
Mpi2EventDataSasTopologyChangeList_t *);
int mps_mapping_is_reinit_required(struct mps_softc *);
void mps_mapping_free_memory(struct mps_softc *sc);
int mps_config_set_dpm_pg0(struct mps_softc *, Mpi2ConfigReply_t *,
Mpi2DriverMappingPage0_t *, u16 );
void mps_mapping_exit(struct mps_softc *);
void mps_mapping_check_devices(struct mps_softc *, int);
void mps_mapping_check_devices(void *);
int mps_mapping_allocate_memory(struct mps_softc *sc);
unsigned int mps_mapping_get_sas_id(struct mps_softc *, uint64_t , u16);
unsigned int mps_mapping_get_sas_id_from_handle(struct mps_softc *sc,
unsigned int mps_mapping_get_tid(struct mps_softc *, uint64_t , u16);
unsigned int mps_mapping_get_tid_from_handle(struct mps_softc *sc,
u16 handle);
unsigned int mps_mapping_get_raid_id(struct mps_softc *sc, u64 wwid,
u16 handle);
unsigned int mps_mapping_get_raid_id_from_handle(struct mps_softc *sc,
unsigned int mps_mapping_get_raid_tid(struct mps_softc *sc, u64 wwid,
u16 volHandle);
unsigned int mps_mapping_get_raid_tid_from_handle(struct mps_softc *sc,
u16 volHandle);
void mps_mapping_enclosure_dev_status_change_event(struct mps_softc *,
Mpi2EventDataSasEnclDevStatusChange_t *event_data);