Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/mpr/mpr_mapping.c
Show First 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | |||||
#include <dev/mpr/mpi/mpi2_cnfg.h> | #include <dev/mpr/mpi/mpi2_cnfg.h> | ||||
#include <dev/mpr/mpi/mpi2_init.h> | #include <dev/mpr/mpi/mpi2_init.h> | ||||
#include <dev/mpr/mpi/mpi2_tool.h> | #include <dev/mpr/mpi/mpi2_tool.h> | ||||
#include <dev/mpr/mpr_ioctl.h> | #include <dev/mpr/mpr_ioctl.h> | ||||
#include <dev/mpr/mprvar.h> | #include <dev/mpr/mprvar.h> | ||||
#include <dev/mpr/mpr_mapping.h> | #include <dev/mpr/mpr_mapping.h> | ||||
/** | /** | ||||
* _mapping_clear_entry - Clear a particular mapping entry. | * _mapping_clear_map_entry - Clear a particular mapping entry. | ||||
* @map_entry: map table entry | * @map_entry: map table entry | ||||
* | * | ||||
* Returns nothing. | * Returns nothing. | ||||
*/ | */ | ||||
static inline void | static inline void | ||||
_mapping_clear_map_entry(struct dev_mapping_table *map_entry) | _mapping_clear_map_entry(struct dev_mapping_table *map_entry) | ||||
{ | { | ||||
map_entry->physical_id = 0; | map_entry->physical_id = 0; | ||||
map_entry->device_info = 0; | map_entry->device_info = 0; | ||||
map_entry->phy_bits = 0; | map_entry->phy_bits = 0; | ||||
map_entry->dpm_entry_num = MPR_DPM_BAD_IDX; | map_entry->dpm_entry_num = MPR_DPM_BAD_IDX; | ||||
map_entry->dev_handle = 0; | map_entry->dev_handle = 0; | ||||
map_entry->channel = -1; | |||||
map_entry->id = -1; | map_entry->id = -1; | ||||
map_entry->missing_count = 0; | map_entry->missing_count = 0; | ||||
map_entry->init_complete = 0; | map_entry->init_complete = 0; | ||||
map_entry->TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR; | map_entry->TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR; | ||||
} | } | ||||
/** | /** | ||||
* _mapping_clear_enc_entry - Clear a particular enclosure table entry. | * _mapping_clear_enc_entry - Clear a particular enclosure table entry. | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | _mapping_commit_enc_entry(struct mpr_softc *sc, | ||||
dpm_entry->DeviceIndex = htole16(mt_entry->id); | dpm_entry->DeviceIndex = htole16(mt_entry->id); | ||||
dpm_entry->MappingInformation = et_entry->num_slots; | dpm_entry->MappingInformation = et_entry->num_slots; | ||||
dpm_entry->MappingInformation <<= MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT; | dpm_entry->MappingInformation <<= MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT; | ||||
dpm_entry->MappingInformation |= et_entry->missing_count; | dpm_entry->MappingInformation |= et_entry->missing_count; | ||||
dpm_entry->MappingInformation = htole16(dpm_entry->MappingInformation); | dpm_entry->MappingInformation = htole16(dpm_entry->MappingInformation); | ||||
dpm_entry->PhysicalBitsMapping = htole32(et_entry->phy_bits); | dpm_entry->PhysicalBitsMapping = htole32(et_entry->phy_bits); | ||||
dpm_entry->Reserved1 = 0; | dpm_entry->Reserved1 = 0; | ||||
mpr_dprint(sc, MPR_MAPPING, "%s: Writing DPM entry %d for enclosure.\n", | |||||
__func__, et_entry->dpm_entry_num); | |||||
memcpy(&config_page.Entry, (u8 *)dpm_entry, | memcpy(&config_page.Entry, (u8 *)dpm_entry, | ||||
sizeof(Mpi2DriverMap0Entry_t)); | sizeof(Mpi2DriverMap0Entry_t)); | ||||
if (mpr_config_set_dpm_pg0(sc, &mpi_reply, &config_page, | if (mpr_config_set_dpm_pg0(sc, &mpi_reply, &config_page, | ||||
et_entry->dpm_entry_num)) { | et_entry->dpm_entry_num)) { | ||||
printf("%s: write of dpm entry %d for enclosure failed\n", | mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: Write of DPM " | ||||
__func__, et_entry->dpm_entry_num); | "entry %d for enclosure failed.\n", __func__, | ||||
et_entry->dpm_entry_num); | |||||
dpm_entry->MappingInformation = le16toh(dpm_entry-> | dpm_entry->MappingInformation = le16toh(dpm_entry-> | ||||
MappingInformation); | MappingInformation); | ||||
dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex); | dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex); | ||||
dpm_entry->PhysicalBitsMapping = | dpm_entry->PhysicalBitsMapping = | ||||
le32toh(dpm_entry->PhysicalBitsMapping); | le32toh(dpm_entry->PhysicalBitsMapping); | ||||
return -1; | return -1; | ||||
} | } | ||||
dpm_entry->MappingInformation = le16toh(dpm_entry-> | dpm_entry->MappingInformation = le16toh(dpm_entry-> | ||||
MappingInformation); | MappingInformation); | ||||
dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex); | dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex); | ||||
dpm_entry->PhysicalBitsMapping = | dpm_entry->PhysicalBitsMapping = | ||||
le32toh(dpm_entry->PhysicalBitsMapping); | le32toh(dpm_entry->PhysicalBitsMapping); | ||||
return 0; | return 0; | ||||
} | } | ||||
/** | /** | ||||
* _mapping_commit_map_entry - write a particular map table entry in DPM page0. | * _mapping_commit_map_entry - write a particular map table entry in DPM page0. | ||||
* @sc: per adapter object | * @sc: per adapter object | ||||
* @enc_entry: enclosure table entry | * @mt_entry: mapping table entry | ||||
* | * | ||||
* Returns 0 for success, non-zero for failure. | * Returns 0 for success, non-zero for failure. | ||||
*/ | */ | ||||
static int | static int | ||||
_mapping_commit_map_entry(struct mpr_softc *sc, | _mapping_commit_map_entry(struct mpr_softc *sc, | ||||
struct dev_mapping_table *mt_entry) | struct dev_mapping_table *mt_entry) | ||||
{ | { | ||||
Mpi2DriverMap0Entry_t *dpm_entry; | Mpi2DriverMap0Entry_t *dpm_entry; | ||||
Mpi2ConfigReply_t mpi_reply; | Mpi2ConfigReply_t mpi_reply; | ||||
Mpi2DriverMappingPage0_t config_page; | Mpi2DriverMappingPage0_t config_page; | ||||
if (!sc->is_dpm_enable) | if (!sc->is_dpm_enable) | ||||
return 0; | return 0; | ||||
/* | |||||
* It's possible that this Map Entry points to a BAD DPM index. This | |||||
* can happen if the Map Entry is a for a missing device and the DPM | |||||
* entry that was being used by this device is now being used by some | |||||
* new device. So, check for a BAD DPM index and just return if so. | |||||
*/ | |||||
if (mt_entry->dpm_entry_num == MPR_DPM_BAD_IDX) { | |||||
mpr_dprint(sc, MPR_MAPPING, "%s: DPM entry location for target " | |||||
"%d is invalid. DPM will not be written.\n", __func__, | |||||
mt_entry->id); | |||||
return 0; | |||||
} | |||||
memset(&config_page, 0, sizeof(Mpi2DriverMappingPage0_t)); | memset(&config_page, 0, sizeof(Mpi2DriverMappingPage0_t)); | ||||
memcpy(&config_page.Header, (u8 *)sc->dpm_pg0, | memcpy(&config_page.Header, (u8 *)sc->dpm_pg0, | ||||
sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); | sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); | ||||
dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *) sc->dpm_pg0 + | dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *) sc->dpm_pg0 + | ||||
sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); | sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); | ||||
dpm_entry = dpm_entry + mt_entry->dpm_entry_num; | dpm_entry = dpm_entry + mt_entry->dpm_entry_num; | ||||
dpm_entry->PhysicalIdentifier.Low = (0xFFFFFFFF & | dpm_entry->PhysicalIdentifier.Low = (0xFFFFFFFF & | ||||
mt_entry->physical_id); | mt_entry->physical_id); | ||||
dpm_entry->PhysicalIdentifier.High = (mt_entry->physical_id >> 32); | dpm_entry->PhysicalIdentifier.High = (mt_entry->physical_id >> 32); | ||||
dpm_entry->DeviceIndex = htole16(mt_entry->id); | dpm_entry->DeviceIndex = htole16(mt_entry->id); | ||||
dpm_entry->MappingInformation = htole16(mt_entry->missing_count); | dpm_entry->MappingInformation = htole16(mt_entry->missing_count); | ||||
dpm_entry->PhysicalBitsMapping = 0; | dpm_entry->PhysicalBitsMapping = 0; | ||||
dpm_entry->Reserved1 = 0; | dpm_entry->Reserved1 = 0; | ||||
dpm_entry->MappingInformation = htole16(dpm_entry->MappingInformation); | |||||
memcpy(&config_page.Entry, (u8 *)dpm_entry, | memcpy(&config_page.Entry, (u8 *)dpm_entry, | ||||
sizeof(Mpi2DriverMap0Entry_t)); | sizeof(Mpi2DriverMap0Entry_t)); | ||||
mpr_dprint(sc, MPR_MAPPING, "%s: Writing DPM entry %d for target %d.\n", | |||||
__func__, mt_entry->dpm_entry_num, mt_entry->id); | |||||
if (mpr_config_set_dpm_pg0(sc, &mpi_reply, &config_page, | if (mpr_config_set_dpm_pg0(sc, &mpi_reply, &config_page, | ||||
mt_entry->dpm_entry_num)) { | mt_entry->dpm_entry_num)) { | ||||
printf("%s: write of dpm entry %d for device failed\n", | mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: Write of DPM " | ||||
__func__, mt_entry->dpm_entry_num); | "entry %d for target %d failed.\n", __func__, | ||||
mt_entry->dpm_entry_num, mt_entry->id); | |||||
dpm_entry->MappingInformation = le16toh(dpm_entry-> | dpm_entry->MappingInformation = le16toh(dpm_entry-> | ||||
MappingInformation); | MappingInformation); | ||||
dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex); | dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex); | ||||
return -1; | return -1; | ||||
} | } | ||||
dpm_entry->MappingInformation = le16toh(dpm_entry->MappingInformation); | dpm_entry->MappingInformation = le16toh(dpm_entry->MappingInformation); | ||||
dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex); | dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex); | ||||
▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | _mapping_get_high_missing_et_idx(struct mpr_softc *sc) | ||||
struct enc_mapping_table *et_entry; | struct enc_mapping_table *et_entry; | ||||
u8 high_missing_count = 0; | u8 high_missing_count = 0; | ||||
u8 enc_idx, high_idx = MPR_ENCTABLE_BAD_IDX; | u8 enc_idx, high_idx = MPR_ENCTABLE_BAD_IDX; | ||||
for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; enc_idx++) { | for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; enc_idx++) { | ||||
et_entry = &sc->enclosure_table[enc_idx]; | et_entry = &sc->enclosure_table[enc_idx]; | ||||
if ((et_entry->missing_count > high_missing_count) && | if ((et_entry->missing_count > high_missing_count) && | ||||
!et_entry->skip_search) { | !et_entry->skip_search) { | ||||
high_missing_count = et_entry->missing_count; | high_missing_count = et_entry->missing_count; | ||||
high_idx = enc_idx; | high_idx = enc_idx; | ||||
} | } | ||||
} | } | ||||
return high_idx; | return high_idx; | ||||
} | } | ||||
/** | /** | ||||
* _mapping_get_high_missing_mt_idx - get missing map table index | * _mapping_get_high_missing_mt_idx - get missing map table index | ||||
* @sc: per adapter object | * @sc: per adapter object | ||||
* | * | ||||
* Search through the map table and identifies the device entry | * Search through the map table and identifies the device entry | ||||
* with high missing count and returns it's index | * with high missing count and returns it's index | ||||
* | * | ||||
* Returns the index of map table entry on success or bad index. | * Returns the index of map table entry on success or bad index. | ||||
*/ | */ | ||||
static u32 | static u32 | ||||
_mapping_get_high_missing_mt_idx(struct mpr_softc *sc) | _mapping_get_high_missing_mt_idx(struct mpr_softc *sc) | ||||
{ | { | ||||
u32 map_idx, high_idx = MPR_ENCTABLE_BAD_IDX; | u32 map_idx, high_idx = MPR_MAPTABLE_BAD_IDX; | ||||
u8 high_missing_count = 0; | u8 high_missing_count = 0; | ||||
u32 start_idx, end_idx, start_idx_ir, end_idx_ir; | u32 start_idx, end_idx, start_idx_ir, end_idx_ir; | ||||
struct dev_mapping_table *mt_entry; | struct dev_mapping_table *mt_entry; | ||||
u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); | u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); | ||||
start_idx = 0; | start_idx = 0; | ||||
start_idx_ir = 0; | start_idx_ir = 0; | ||||
end_idx_ir = 0; | end_idx_ir = 0; | ||||
Show All 27 Lines | |||||
static u32 | static u32 | ||||
_mapping_get_ir_mt_idx_from_wwid(struct mpr_softc *sc, u64 wwid) | _mapping_get_ir_mt_idx_from_wwid(struct mpr_softc *sc, u64 wwid) | ||||
{ | { | ||||
u32 start_idx, end_idx, map_idx; | u32 start_idx, end_idx, map_idx; | ||||
struct dev_mapping_table *mt_entry; | struct dev_mapping_table *mt_entry; | ||||
_mapping_get_ir_maprange(sc, &start_idx, &end_idx); | _mapping_get_ir_maprange(sc, &start_idx, &end_idx); | ||||
mt_entry = &sc->mapping_table[start_idx]; | mt_entry = &sc->mapping_table[start_idx]; | ||||
for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++) | for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++) | ||||
if (mt_entry->physical_id == wwid) | if (mt_entry->physical_id == wwid) | ||||
return map_idx; | return map_idx; | ||||
return MPR_MAPTABLE_BAD_IDX; | return MPR_MAPTABLE_BAD_IDX; | ||||
} | } | ||||
/** | /** | ||||
* _mapping_get_mt_idx_from_id - get map table index from a device ID | * _mapping_get_mt_idx_from_id - get map table index from a device ID | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | |||||
static u32 | static u32 | ||||
_mapping_get_free_ir_mt_idx(struct mpr_softc *sc) | _mapping_get_free_ir_mt_idx(struct mpr_softc *sc) | ||||
{ | { | ||||
u8 high_missing_count = 0; | u8 high_missing_count = 0; | ||||
u32 start_idx, end_idx, map_idx; | u32 start_idx, end_idx, map_idx; | ||||
u32 high_idx = MPR_MAPTABLE_BAD_IDX; | u32 high_idx = MPR_MAPTABLE_BAD_IDX; | ||||
struct dev_mapping_table *mt_entry; | struct dev_mapping_table *mt_entry; | ||||
/* | |||||
* The IN_USE flag should be clear if the entry is available to use. | |||||
* This flag is cleared on initialization and and when a volume is | |||||
* deleted. All other times this flag should be set. If, for some | |||||
* reason, a free entry cannot be found, look for the entry with the | |||||
* highest missing count just in case there is one. | |||||
*/ | |||||
_mapping_get_ir_maprange(sc, &start_idx, &end_idx); | _mapping_get_ir_maprange(sc, &start_idx, &end_idx); | ||||
mt_entry = &sc->mapping_table[start_idx]; | mt_entry = &sc->mapping_table[start_idx]; | ||||
for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++) | for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++) { | ||||
if (!(mt_entry->device_info & MPR_MAP_IN_USE)) | if (!(mt_entry->device_info & MPR_MAP_IN_USE)) | ||||
return map_idx; | return map_idx; | ||||
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) { | if (mt_entry->missing_count > high_missing_count) { | ||||
high_missing_count = mt_entry->missing_count; | high_missing_count = mt_entry->missing_count; | ||||
high_idx = map_idx; | high_idx = map_idx; | ||||
} | } | ||||
} | } | ||||
if (high_idx == MPR_MAPTABLE_BAD_IDX) { | |||||
mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: Could not find a " | |||||
"free entry in the mapping table for a Volume. The mapping " | |||||
"table is probably corrupt.\n", __func__); | |||||
} | |||||
return high_idx; | return high_idx; | ||||
} | } | ||||
/** | /** | ||||
* _mapping_get_free_mt_idx - get first free index for a device | * _mapping_get_free_mt_idx - get first free index for a device | ||||
* @sc: per adapter object | * @sc: per adapter object | ||||
* @start_idx: offset in the table to start search | * @start_idx: offset in the table to start search | ||||
* | * | ||||
* Returns the index of map table entry on success or bad index. | * Returns the index of map table entry on success or bad index. | ||||
*/ | */ | ||||
static u32 | static u32 | ||||
_mapping_get_free_mt_idx(struct mpr_softc *sc, u32 start_idx) | _mapping_get_free_mt_idx(struct mpr_softc *sc, u32 start_idx) | ||||
{ | { | ||||
u32 map_idx, max_idx = sc->max_devices; | u32 map_idx, max_idx = sc->max_devices; | ||||
struct dev_mapping_table *mt_entry = &sc->mapping_table[start_idx]; | struct dev_mapping_table *mt_entry = &sc->mapping_table[start_idx]; | ||||
u16 volume_mapping_flags; | u16 volume_mapping_flags; | ||||
volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) & | volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) & | ||||
MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; | MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; | ||||
if (sc->ir_firmware && (volume_mapping_flags == | if (sc->ir_firmware && (volume_mapping_flags == | ||||
MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING)) | MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING)) | ||||
max_idx -= sc->max_volumes; | max_idx -= sc->max_volumes; | ||||
for (map_idx = start_idx; map_idx < max_idx; map_idx++, mt_entry++) | for (map_idx = start_idx; map_idx < max_idx; map_idx++, mt_entry++) | ||||
if (!(mt_entry->device_info & (MPR_MAP_IN_USE | | if (!(mt_entry->device_info & (MPR_MAP_IN_USE | | ||||
MPR_DEV_RESERVED))) | MPR_DEV_RESERVED))) | ||||
return map_idx; | return map_idx; | ||||
return MPR_MAPTABLE_BAD_IDX; | return MPR_MAPTABLE_BAD_IDX; | ||||
} | } | ||||
Show All 32 Lines | |||||
* @sc: per adapter object | * @sc: per adapter object | ||||
* | * | ||||
* Returns the index of DPM entry on success or bad index. | * Returns the index of DPM entry on success or bad index. | ||||
*/ | */ | ||||
static u32 | static u32 | ||||
_mapping_get_free_dpm_idx(struct mpr_softc *sc) | _mapping_get_free_dpm_idx(struct mpr_softc *sc) | ||||
{ | { | ||||
u16 entry_num; | u16 entry_num; | ||||
Mpi2DriverMap0Entry_t *dpm_entry; | |||||
u16 current_entry = MPR_DPM_BAD_IDX, missing_cnt, high_missing_cnt = 0; | |||||
u64 physical_id; | |||||
struct dev_mapping_table *mt_entry; | |||||
u32 map_idx; | |||||
for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++) { | for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++) { | ||||
if (!sc->dpm_entry_used[entry_num]) | dpm_entry = (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 + | ||||
return entry_num; | sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); | ||||
dpm_entry += entry_num; | |||||
missing_cnt = dpm_entry->MappingInformation & | |||||
MPI2_DRVMAP0_MAPINFO_MISSING_MASK; | |||||
/* | |||||
* If entry is used and not missing, then this entry can't be | |||||
* used. Look at next one. | |||||
*/ | |||||
if (sc->dpm_entry_used[entry_num] && !missing_cnt) | |||||
continue; | |||||
/* | |||||
* If this entry is not used at all, then the missing count | |||||
* doesn't matter. Just use this one. Otherwise, keep looking | |||||
* and make sure the entry with the highest missing count is | |||||
* used. | |||||
*/ | |||||
if (!sc->dpm_entry_used[entry_num]) { | |||||
current_entry = entry_num; | |||||
break; | |||||
} | } | ||||
return MPR_DPM_BAD_IDX; | if ((current_entry == MPR_DPM_BAD_IDX) || | ||||
(missing_cnt > high_missing_cnt)) { | |||||
current_entry = entry_num; | |||||
high_missing_cnt = missing_cnt; | |||||
} | } | ||||
} | |||||
/* | |||||
* If an entry has been found to use and it's already marked as used | |||||
* it means that some device was already using this entry but it's | |||||
* missing, and that means that the connection between the missing | |||||
* device's DPM entry and the mapping table needs to be cleared. To do | |||||
* this, use the Physical ID of the old device still in the DPM entry | |||||
* to find its mapping table entry, then mark its DPM entry as BAD. | |||||
*/ | |||||
if ((current_entry != MPR_DPM_BAD_IDX) && | |||||
sc->dpm_entry_used[current_entry]) { | |||||
dpm_entry = (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 + | |||||
sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); | |||||
dpm_entry += current_entry; | |||||
physical_id = dpm_entry->PhysicalIdentifier.High; | |||||
physical_id = (physical_id << 32) | | |||||
dpm_entry->PhysicalIdentifier.Low; | |||||
map_idx = _mapping_get_mt_idx_from_id(sc, physical_id); | |||||
if (map_idx != MPR_MAPTABLE_BAD_IDX) { | |||||
mt_entry = &sc->mapping_table[map_idx]; | |||||
mt_entry->dpm_entry_num = MPR_DPM_BAD_IDX; | |||||
} | |||||
} | |||||
return current_entry; | |||||
} | |||||
/** | /** | ||||
* _mapping_update_ir_missing_cnt - Updates missing count for a volume | * _mapping_update_ir_missing_cnt - Updates missing count for a volume | ||||
* @sc: per adapter object | * @sc: per adapter object | ||||
* @map_idx: map table index of the volume | * @map_idx: map table index of the volume | ||||
* @element: IR configuration change element | * @element: IR configuration change element | ||||
* @wwid: IR volume ID. | * @wwid: IR volume ID. | ||||
* | * | ||||
* Updates the missing count in the map table and in the DPM entry for a volume | * Updates the missing count in the map table and in the DPM entry for a volume | ||||
* | * | ||||
* Returns nothing. | * Returns nothing. | ||||
*/ | */ | ||||
static void | static void | ||||
_mapping_update_ir_missing_cnt(struct mpr_softc *sc, u32 map_idx, | _mapping_update_ir_missing_cnt(struct mpr_softc *sc, u32 map_idx, | ||||
Mpi2EventIrConfigElement_t *element, u64 wwid) | Mpi2EventIrConfigElement_t *element, u64 wwid) | ||||
{ | { | ||||
struct dev_mapping_table *mt_entry; | struct dev_mapping_table *mt_entry; | ||||
u8 missing_cnt, reason = element->ReasonCode; | u8 missing_cnt, reason = element->ReasonCode, update_dpm = 1; | ||||
u16 dpm_idx; | u16 dpm_idx; | ||||
Mpi2DriverMap0Entry_t *dpm_entry; | Mpi2DriverMap0Entry_t *dpm_entry; | ||||
if (!sc->is_dpm_enable) | /* | ||||
return; | * Depending on the reason code, update the missing count. Always set | ||||
* the init_complete flag when here, so just do it first. That flag is | |||||
* used for volumes to make sure that the DPM entry has been updated. | |||||
* When a volume is deleted, clear the map entry's IN_USE flag so that | |||||
* the entry can be used again if another volume is created. Also clear | |||||
* its dev_handle entry so that other functions can't find this volume | |||||
* by the handle, since it's not defined any longer. | |||||
*/ | |||||
mt_entry = &sc->mapping_table[map_idx]; | mt_entry = &sc->mapping_table[map_idx]; | ||||
if (reason == MPI2_EVENT_IR_CHANGE_RC_ADDED) { | mt_entry->init_complete = 1; | ||||
if ((reason == MPI2_EVENT_IR_CHANGE_RC_ADDED) || | |||||
(reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED)) { | |||||
mt_entry->missing_count = 0; | mt_entry->missing_count = 0; | ||||
} else if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED) { | } else if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED) { | ||||
mt_entry->missing_count = 0; | |||||
mt_entry->init_complete = 0; | |||||
} else if ((reason == MPI2_EVENT_IR_CHANGE_RC_REMOVED) || | |||||
(reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED)) { | |||||
if (!mt_entry->init_complete) { | |||||
if (mt_entry->missing_count < MPR_MAX_MISSING_COUNT) | if (mt_entry->missing_count < MPR_MAX_MISSING_COUNT) | ||||
mt_entry->missing_count++; | mt_entry->missing_count++; | ||||
else | |||||
mt_entry->init_complete = 1; | mt_entry->device_info &= ~MPR_MAP_IN_USE; | ||||
} | |||||
if (!mt_entry->missing_count) | |||||
mt_entry->missing_count++; | |||||
mt_entry->dev_handle = 0; | mt_entry->dev_handle = 0; | ||||
} | } | ||||
/* | |||||
* If persistent mapping is enabled, update the DPM with the new missing | |||||
* count for the volume. If the DPM index is bad, get a free one. If | |||||
* it's bad for a volume that's being deleted do nothing because that | |||||
* volume doesn't have a DPM entry. | |||||
*/ | |||||
if (!sc->is_dpm_enable) | |||||
return; | |||||
dpm_idx = mt_entry->dpm_entry_num; | dpm_idx = mt_entry->dpm_entry_num; | ||||
if (dpm_idx == MPR_DPM_BAD_IDX) { | if (dpm_idx == MPR_DPM_BAD_IDX) { | ||||
if ((reason == MPI2_EVENT_IR_CHANGE_RC_ADDED) || | if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED) | ||||
(reason == MPI2_EVENT_IR_CHANGE_RC_REMOVED)) | { | ||||
dpm_idx = _mapping_get_dpm_idx_from_id(sc, | mpr_dprint(sc, MPR_MAPPING, "%s: Volume being deleted " | ||||
mt_entry->physical_id, 0); | "is not in DPM so DPM missing count will not be " | ||||
else if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED) | "updated.\n", __func__); | ||||
return; | return; | ||||
} | } | ||||
} | |||||
if (dpm_idx == MPR_DPM_BAD_IDX) | |||||
dpm_idx = _mapping_get_free_dpm_idx(sc); | |||||
/* | |||||
* Got the DPM entry for the volume or found a free DPM entry if this is | |||||
* a new volume. Check if the current information is outdated. | |||||
*/ | |||||
if (dpm_idx != MPR_DPM_BAD_IDX) { | if (dpm_idx != MPR_DPM_BAD_IDX) { | ||||
dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 + | dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 + | ||||
sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); | sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); | ||||
dpm_entry += dpm_idx; | dpm_entry += dpm_idx; | ||||
missing_cnt = dpm_entry->MappingInformation & | missing_cnt = dpm_entry->MappingInformation & | ||||
MPI2_DRVMAP0_MAPINFO_MISSING_MASK; | MPI2_DRVMAP0_MAPINFO_MISSING_MASK; | ||||
if ((mt_entry->physical_id == | if ((mt_entry->physical_id == | ||||
le64toh((u64)dpm_entry->PhysicalIdentifier.High | | le64toh(((u64)dpm_entry->PhysicalIdentifier.High << 32) | | ||||
dpm_entry->PhysicalIdentifier.Low)) && (missing_cnt == | (u64)dpm_entry->PhysicalIdentifier.Low)) && (missing_cnt == | ||||
mt_entry->missing_count)) | mt_entry->missing_count)) { | ||||
mt_entry->init_complete = 1; | mpr_dprint(sc, MPR_MAPPING, "%s: DPM entry for volume " | ||||
} else { | "with target ID %d does not require an update.\n", | ||||
dpm_idx = _mapping_get_free_dpm_idx(sc); | __func__, mt_entry->id); | ||||
mt_entry->init_complete = 0; | update_dpm = 0; | ||||
} | } | ||||
} | |||||
if ((dpm_idx != MPR_DPM_BAD_IDX) && !mt_entry->init_complete) { | /* | ||||
mt_entry->init_complete = 1; | * Update the volume's persistent info if it's new or the ID or missing | ||||
* count has changed. If a good DPM index has not been found by now, | |||||
* there is no space left in the DPM table. | |||||
*/ | |||||
if ((dpm_idx != MPR_DPM_BAD_IDX) && update_dpm) { | |||||
mpr_dprint(sc, MPR_MAPPING, "%s: Update DPM entry for volume " | |||||
"with target ID %d.\n", __func__, mt_entry->id); | |||||
mt_entry->dpm_entry_num = dpm_idx; | mt_entry->dpm_entry_num = dpm_idx; | ||||
dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 + | dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 + | ||||
sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); | sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); | ||||
dpm_entry += dpm_idx; | dpm_entry += dpm_idx; | ||||
dpm_entry->PhysicalIdentifier.Low = | dpm_entry->PhysicalIdentifier.Low = | ||||
(0xFFFFFFFF & mt_entry->physical_id); | (0xFFFFFFFF & mt_entry->physical_id); | ||||
dpm_entry->PhysicalIdentifier.High = | dpm_entry->PhysicalIdentifier.High = | ||||
(mt_entry->physical_id >> 32); | (mt_entry->physical_id >> 32); | ||||
dpm_entry->DeviceIndex = map_idx; | dpm_entry->DeviceIndex = map_idx; | ||||
dpm_entry->MappingInformation = mt_entry->missing_count; | dpm_entry->MappingInformation = mt_entry->missing_count; | ||||
dpm_entry->PhysicalBitsMapping = 0; | dpm_entry->PhysicalBitsMapping = 0; | ||||
dpm_entry->Reserved1 = 0; | dpm_entry->Reserved1 = 0; | ||||
sc->dpm_flush_entry[dpm_idx] = 1; | sc->dpm_flush_entry[dpm_idx] = 1; | ||||
sc->dpm_entry_used[dpm_idx] = 1; | sc->dpm_entry_used[dpm_idx] = 1; | ||||
} else if (dpm_idx == MPR_DPM_BAD_IDX) { | } else if (dpm_idx == MPR_DPM_BAD_IDX) { | ||||
printf("%s: no space to add entry in DPM table\n", __func__); | mpr_dprint(sc, MPR_INFO | MPR_MAPPING, "%s: No space to add an " | ||||
mt_entry->init_complete = 1; | "entry in the DPM table for volume with target ID %d.\n", | ||||
__func__, mt_entry->id); | |||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* _mapping_add_to_removal_table - mark an entry for removal | * _mapping_add_to_removal_table - add DPM index to the removal table | ||||
* @sc: per adapter object | * @sc: per adapter object | ||||
* @handle: Handle of enclosures/device/volume | * @dpm_idx: Index of DPM entry to remove | ||||
* | * | ||||
* Adds the handle or DPM entry number in removal table. | * Adds a DPM entry number to the removal table. | ||||
* | * | ||||
* Returns nothing. | * Returns nothing. | ||||
*/ | */ | ||||
static void | static void | ||||
_mapping_add_to_removal_table(struct mpr_softc *sc, u16 handle, | _mapping_add_to_removal_table(struct mpr_softc *sc, u16 dpm_idx) | ||||
u16 dpm_idx) | |||||
{ | { | ||||
struct map_removal_table *remove_entry; | struct map_removal_table *remove_entry; | ||||
u32 i; | u32 i; | ||||
u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); | |||||
remove_entry = sc->removal_table; | /* | ||||
* This is only used to remove entries from the DPM in the controller. | |||||
* If DPM is not enabled, just return. | |||||
*/ | |||||
if (!sc->is_dpm_enable) | |||||
return; | |||||
/* | |||||
* Find the first available removal_table entry and add the new entry | |||||
* there. | |||||
*/ | |||||
remove_entry = sc->removal_table; | |||||
for (i = 0; i < sc->max_devices; i++, remove_entry++) { | for (i = 0; i < sc->max_devices; i++, remove_entry++) { | ||||
if (remove_entry->dev_handle || remove_entry->dpm_entry_num != | if (remove_entry->dpm_entry_num != MPR_DPM_BAD_IDX) | ||||
MPR_DPM_BAD_IDX) | |||||
continue; | continue; | ||||
if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | |||||
MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { | mpr_dprint(sc, MPR_MAPPING, "%s: Adding DPM entry %d to table " | ||||
if (dpm_idx) | "for removal.\n", __func__, dpm_idx); | ||||
remove_entry->dpm_entry_num = dpm_idx; | remove_entry->dpm_entry_num = dpm_idx; | ||||
if (remove_entry->dpm_entry_num == MPR_DPM_BAD_IDX) | |||||
remove_entry->dev_handle = handle; | |||||
} else if ((ioc_pg8_flags & | |||||
MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | |||||
MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) | |||||
remove_entry->dev_handle = handle; | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* _mapping_inc_missing_count | * _mapping_inc_missing_count | ||||
* @sc: per adapter object | * @sc: per adapter object | ||||
* @map_idx: index into the mapping table for the device that is missing | * @map_idx: index into the mapping table for the device that is missing | ||||
* | * | ||||
* Increment the missing count in the mapping table for a SAS, SATA, or PCIe | * Increment the missing count in the mapping table for a SAS, SATA, or PCIe | ||||
* device that is not responding. If Persitent Mapping is used, increment the | * device that is not responding. If Persitent Mapping is used, increment the | ||||
* DPM entry as well. Also, add this device to the removal table for possible | * DPM entry as well. Currently, this function is only called if the target | ||||
* removal if a new device is added. | * goes missing, so after initialization has completed. This means that the | ||||
* missing count can only go from 0 to 1 here. The missing count is incremented | |||||
* during initialization as well, so that's where a target's missing count can | |||||
* go past 1. | |||||
* | * | ||||
* Returns nothing. | * Returns nothing. | ||||
*/ | */ | ||||
static void | static void | ||||
_mapping_inc_missing_count(struct mpr_softc *sc, u32 map_idx) | _mapping_inc_missing_count(struct mpr_softc *sc, u32 map_idx) | ||||
{ | { | ||||
u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); | u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); | ||||
struct dev_mapping_table *mt_entry; | struct dev_mapping_table *mt_entry; | ||||
Mpi2DriverMap0Entry_t *dpm_entry; | Mpi2DriverMap0Entry_t *dpm_entry; | ||||
if (map_idx == MPR_MAPTABLE_BAD_IDX) { | if (map_idx == MPR_MAPTABLE_BAD_IDX) { | ||||
mpr_dprint(sc, MPR_INFO, "%s: device is already removed from " | mpr_dprint(sc, MPR_INFO | MPR_MAPPING, "%s: device is already " | ||||
"mapping table\n", __func__); | "removed from mapping table\n", __func__); | ||||
return; | return; | ||||
} | } | ||||
mt_entry = &sc->mapping_table[map_idx]; | mt_entry = &sc->mapping_table[map_idx]; | ||||
if (!mt_entry->init_complete) { | |||||
if (mt_entry->missing_count < MPR_MAX_MISSING_COUNT) | if (mt_entry->missing_count < MPR_MAX_MISSING_COUNT) | ||||
mt_entry->missing_count++; | mt_entry->missing_count++; | ||||
else | |||||
mt_entry->init_complete = 1; | /* | ||||
* When using Enc/Slot mapping, when a device is removed, it's mapping | |||||
* table information should be cleared. Otherwise, the target ID will | |||||
* be incorrect if this same device is re-added to a different slot. | |||||
*/ | |||||
if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | |||||
MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { | |||||
_mapping_clear_map_entry(mt_entry); | |||||
} | } | ||||
if (!mt_entry->missing_count) | |||||
mt_entry->missing_count++; | |||||
_mapping_add_to_removal_table(sc, mt_entry->dev_handle, 0); | |||||
mt_entry->dev_handle = 0; | |||||
/* | |||||
* When using device mapping, update the missing count in the DPM entry, | |||||
* but only if the missing count has changed. | |||||
*/ | |||||
if (((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | if (((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | ||||
MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) && | MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) && | ||||
sc->is_dpm_enable && !mt_entry->init_complete && | sc->is_dpm_enable && | ||||
mt_entry->dpm_entry_num != MPR_DPM_BAD_IDX) { | mt_entry->dpm_entry_num != MPR_DPM_BAD_IDX) { | ||||
dpm_entry = (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 + | dpm_entry = (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 + | ||||
sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); | sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); | ||||
dpm_entry += mt_entry->dpm_entry_num; | dpm_entry += mt_entry->dpm_entry_num; | ||||
if (dpm_entry->MappingInformation != mt_entry->missing_count) { | |||||
dpm_entry->MappingInformation = mt_entry->missing_count; | dpm_entry->MappingInformation = mt_entry->missing_count; | ||||
sc->dpm_flush_entry[mt_entry->dpm_entry_num] = 1; | sc->dpm_flush_entry[mt_entry->dpm_entry_num] = 1; | ||||
} | } | ||||
mt_entry->init_complete = 1; | |||||
} | } | ||||
} | |||||
/** | /** | ||||
* _mapping_update_missing_count - Update missing count for a device | * _mapping_update_missing_count - Update missing count for a device | ||||
* @sc: per adapter object | * @sc: per adapter object | ||||
* @topo_change: Topology change event entry | * @topo_change: Topology change event entry | ||||
* | * | ||||
* Search through the topology change list and if any device is found not | * Search through the topology change list and if any device is found not | ||||
* responding it's associated map table entry and DPM entry is updated | * responding it's associated map table entry and DPM entry is updated | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | _mapping_find_enc_map_space(struct mpr_softc *sc, | ||||
u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs); | u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs); | ||||
skip_count = sc->num_rsvd_entries; | skip_count = sc->num_rsvd_entries; | ||||
num_found = 0; | num_found = 0; | ||||
vol_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) & | vol_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) & | ||||
MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; | MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; | ||||
/* | |||||
* The end of the mapping table depends on where volumes are kept, if | |||||
* IR is enabled. | |||||
*/ | |||||
if (!sc->ir_firmware) | if (!sc->ir_firmware) | ||||
end_of_table = sc->max_devices; | end_of_table = sc->max_devices; | ||||
else if (vol_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) | else if (vol_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) | ||||
end_of_table = sc->max_devices; | end_of_table = sc->max_devices; | ||||
else | else | ||||
end_of_table = sc->max_devices - sc->max_volumes; | end_of_table = sc->max_devices - sc->max_volumes; | ||||
/* | |||||
* The skip_count is the number of entries that are reserved at the | |||||
* beginning of the mapping table. But, it does not include the number | |||||
* of Physical IDs that are reserved for direct attached devices. Look | |||||
* through the mapping table after these reserved entries to see if | |||||
* the devices for this enclosure are already mapped. The PHY bit check | |||||
* is used to make sure that at least one PHY bit is common between the | |||||
* enclosure and the device that is already mapped. | |||||
*/ | |||||
mpr_dprint(sc, MPR_MAPPING, "%s: Looking for space in the mapping " | |||||
"table for added enclosure.\n", __func__); | |||||
for (map_idx = (max_num_phy_ids + skip_count); | for (map_idx = (max_num_phy_ids + skip_count); | ||||
map_idx < end_of_table; map_idx++) { | map_idx < end_of_table; map_idx++) { | ||||
mt_entry = &sc->mapping_table[map_idx]; | mt_entry = &sc->mapping_table[map_idx]; | ||||
if ((et_entry->enclosure_id == mt_entry->physical_id) && | if ((et_entry->enclosure_id == mt_entry->physical_id) && | ||||
(!mt_entry->phy_bits || (mt_entry->phy_bits & | (!mt_entry->phy_bits || (mt_entry->phy_bits & | ||||
et_entry->phy_bits))) { | et_entry->phy_bits))) { | ||||
num_found += 1; | num_found += 1; | ||||
if (num_found == et_entry->num_slots) { | if (num_found == et_entry->num_slots) { | ||||
start_idx = (map_idx - num_found) + 1; | start_idx = (map_idx - num_found) + 1; | ||||
mpr_dprint(sc, MPR_MAPPING, "%s: Found space " | |||||
"in the mapping for enclosure at map index " | |||||
"%d.\n", __func__, start_idx); | |||||
return start_idx; | return start_idx; | ||||
} | } | ||||
} else | } else | ||||
num_found = 0; | num_found = 0; | ||||
} | } | ||||
/* | |||||
* If the enclosure's devices are not mapped already, look for | |||||
* contiguous entries in the mapping table that are not reserved. If | |||||
* enough entries are found, return the starting index for that space. | |||||
*/ | |||||
num_found = 0; | |||||
for (map_idx = (max_num_phy_ids + skip_count); | for (map_idx = (max_num_phy_ids + skip_count); | ||||
map_idx < end_of_table; map_idx++) { | map_idx < end_of_table; map_idx++) { | ||||
mt_entry = &sc->mapping_table[map_idx]; | mt_entry = &sc->mapping_table[map_idx]; | ||||
if (!(mt_entry->device_info & MPR_DEV_RESERVED)) { | if (!(mt_entry->device_info & MPR_DEV_RESERVED)) { | ||||
num_found += 1; | num_found += 1; | ||||
if (num_found == et_entry->num_slots) { | if (num_found == et_entry->num_slots) { | ||||
start_idx = (map_idx - num_found) + 1; | start_idx = (map_idx - num_found) + 1; | ||||
mpr_dprint(sc, MPR_MAPPING, "%s: Found space " | |||||
"in the mapping for enclosure at map index " | |||||
"%d.\n", __func__, start_idx); | |||||
return start_idx; | return start_idx; | ||||
} | } | ||||
} else | } else | ||||
num_found = 0; | num_found = 0; | ||||
} | } | ||||
/* | |||||
* If here, it means that not enough space in the mapping table was | |||||
* found to support this enclosure, so go through the enclosure table to | |||||
* see if any enclosure entries have a missing count. If so, get the | |||||
* enclosure with the highest missing count and check it to see if there | |||||
* is enough space for the new enclosure. | |||||
*/ | |||||
while (!done_flag) { | while (!done_flag) { | ||||
enc_idx = _mapping_get_high_missing_et_idx(sc); | enc_idx = _mapping_get_high_missing_et_idx(sc); | ||||
if (enc_idx == MPR_ENCTABLE_BAD_IDX) | if (enc_idx == MPR_ENCTABLE_BAD_IDX) { | ||||
mpr_dprint(sc, MPR_MAPPING, "%s: Not enough space was " | |||||
"found in the mapping for the added enclosure.\n", | |||||
__func__); | |||||
return MPR_MAPTABLE_BAD_IDX; | return MPR_MAPTABLE_BAD_IDX; | ||||
} | |||||
/* | |||||
* Found a missing enclosure. Set the skip_search flag so this | |||||
* enclosure is not checked again for a high missing count if | |||||
* the loop continues. This way, all missing enclosures can | |||||
* have their space added together to find enough space in the | |||||
* mapping table for the added enclosure. The space must be | |||||
* contiguous. | |||||
*/ | |||||
mpr_dprint(sc, MPR_MAPPING, "%s: Space from a missing " | |||||
"enclosure was found.\n", __func__); | |||||
enc_entry = &sc->enclosure_table[enc_idx]; | enc_entry = &sc->enclosure_table[enc_idx]; | ||||
/*VSP FIXME*/ | |||||
enc_entry->skip_search = 1; | enc_entry->skip_search = 1; | ||||
/* | |||||
* Unmark all of the missing enclosure's device's reserved | |||||
* space. These will be remarked as reserved if this missing | |||||
* enclosure's space is not used. | |||||
*/ | |||||
mpr_dprint(sc, MPR_MAPPING, "%s: Clear the reserved flag for " | |||||
"all of the map entries for the enclosure.\n", __func__); | |||||
mt_entry = &sc->mapping_table[enc_entry->start_index]; | mt_entry = &sc->mapping_table[enc_entry->start_index]; | ||||
for (map_idx = enc_entry->start_index; map_idx < | for (map_idx = enc_entry->start_index; map_idx < | ||||
(enc_entry->start_index + enc_entry->num_slots); map_idx++, | (enc_entry->start_index + enc_entry->num_slots); map_idx++, | ||||
mt_entry++) | mt_entry++) | ||||
mt_entry->device_info &= ~MPR_DEV_RESERVED; | mt_entry->device_info &= ~MPR_DEV_RESERVED; | ||||
/* | |||||
* Now that space has been unreserved, check again to see if | |||||
* enough space is available for the new enclosure. | |||||
*/ | |||||
mpr_dprint(sc, MPR_MAPPING, "%s: Check if new mapping space is " | |||||
"enough for the new enclosure.\n", __func__); | |||||
found_space = 0; | found_space = 0; | ||||
for (map_idx = (max_num_phy_ids + | num_found = 0; | ||||
skip_count); map_idx < end_of_table; map_idx++) { | for (map_idx = (max_num_phy_ids + skip_count); | ||||
map_idx < end_of_table; map_idx++) { | |||||
mt_entry = &sc->mapping_table[map_idx]; | mt_entry = &sc->mapping_table[map_idx]; | ||||
if (!(mt_entry->device_info & MPR_DEV_RESERVED)) { | if (!(mt_entry->device_info & MPR_DEV_RESERVED)) { | ||||
num_found += 1; | num_found += 1; | ||||
if (num_found == et_entry->num_slots) { | if (num_found == et_entry->num_slots) { | ||||
start_idx = (map_idx - num_found) + 1; | start_idx = (map_idx - num_found) + 1; | ||||
found_space = 1; | found_space = 1; | ||||
break; | |||||
} | } | ||||
} else | } else | ||||
num_found = 0; | num_found = 0; | ||||
} | } | ||||
if (!found_space) | if (!found_space) | ||||
continue; | continue; | ||||
/* | |||||
* If enough space was found, all of the missing enclosures that | |||||
* will be used for the new enclosure must be added to the | |||||
* removal table. Then all mappings for the enclosure's devices | |||||
* and for the enclosure itself need to be cleared. There may be | |||||
* more than one enclosure to add to the removal table and | |||||
* clear. | |||||
*/ | |||||
mpr_dprint(sc, MPR_MAPPING, "%s: Found space in the mapping " | |||||
"for enclosure at map index %d.\n", __func__, start_idx); | |||||
for (map_idx = start_idx; map_idx < (start_idx + num_found); | for (map_idx = start_idx; map_idx < (start_idx + num_found); | ||||
map_idx++) { | map_idx++) { | ||||
enc_entry = sc->enclosure_table; | enc_entry = sc->enclosure_table; | ||||
for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; | for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; | ||||
enc_idx++, enc_entry++) { | enc_idx++, enc_entry++) { | ||||
if (map_idx < enc_entry->start_index || | if (map_idx < enc_entry->start_index || | ||||
map_idx > (enc_entry->start_index + | map_idx > (enc_entry->start_index + | ||||
enc_entry->num_slots)) | enc_entry->num_slots)) | ||||
continue; | continue; | ||||
if (!enc_entry->removal_flag) { | if (!enc_entry->removal_flag) { | ||||
mpr_dprint(sc, MPR_MAPPING, "%s: " | |||||
"Enclosure %d will be removed from " | |||||
"the mapping table.\n", __func__, | |||||
enc_idx); | |||||
enc_entry->removal_flag = 1; | enc_entry->removal_flag = 1; | ||||
_mapping_add_to_removal_table(sc, 0, | _mapping_add_to_removal_table(sc, | ||||
enc_entry->dpm_entry_num); | enc_entry->dpm_entry_num); | ||||
} | } | ||||
mt_entry = &sc->mapping_table[map_idx]; | mt_entry = &sc->mapping_table[map_idx]; | ||||
if (mt_entry->device_info & | |||||
MPR_MAP_IN_USE) { | |||||
_mapping_add_to_removal_table(sc, | |||||
mt_entry->dev_handle, 0); | |||||
_mapping_clear_map_entry(mt_entry); | _mapping_clear_map_entry(mt_entry); | ||||
} | |||||
if (map_idx == (enc_entry->start_index + | if (map_idx == (enc_entry->start_index + | ||||
enc_entry->num_slots - 1)) | enc_entry->num_slots - 1)) | ||||
_mapping_clear_enc_entry(et_entry); | _mapping_clear_enc_entry(et_entry); | ||||
} | } | ||||
} | } | ||||
/* | |||||
* During the search for space for this enclosure, some entries | |||||
* in the mapping table may have been unreserved. Go back and | |||||
* change all of these to reserved again. Only the enclosures | |||||
* with the removal_flag set should be left as unreserved. The | |||||
* skip_search flag needs to be cleared as well so that the | |||||
* enclosure's space will be looked at the next time space is | |||||
* needed. | |||||
*/ | |||||
enc_entry = sc->enclosure_table; | enc_entry = sc->enclosure_table; | ||||
for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; | for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; | ||||
enc_idx++, enc_entry++) { | enc_idx++, enc_entry++) { | ||||
if (!enc_entry->removal_flag) { | if (!enc_entry->removal_flag) { | ||||
mpr_dprint(sc, MPR_MAPPING, "%s: Reset the " | |||||
"reserved flag for all of the map entries " | |||||
"for enclosure %d.\n", __func__, enc_idx); | |||||
mt_entry = &sc->mapping_table[enc_entry-> | mt_entry = &sc->mapping_table[enc_entry-> | ||||
start_index]; | start_index]; | ||||
for (map_idx = enc_entry->start_index; map_idx < | for (map_idx = enc_entry->start_index; map_idx < | ||||
(enc_entry->start_index + | (enc_entry->start_index + | ||||
enc_entry->num_slots); map_idx++, | enc_entry->num_slots); map_idx++, | ||||
mt_entry++) | mt_entry++) | ||||
mt_entry->device_info |= | mt_entry->device_info |= | ||||
MPR_DEV_RESERVED; | MPR_DEV_RESERVED; | ||||
Show All 17 Lines | |||||
*/ | */ | ||||
static void | static void | ||||
_mapping_get_dev_info(struct mpr_softc *sc, | _mapping_get_dev_info(struct mpr_softc *sc, | ||||
struct _map_topology_change *topo_change) | struct _map_topology_change *topo_change) | ||||
{ | { | ||||
u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); | u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); | ||||
Mpi2ConfigReply_t mpi_reply; | Mpi2ConfigReply_t mpi_reply; | ||||
Mpi2SasDevicePage0_t sas_device_pg0; | Mpi2SasDevicePage0_t sas_device_pg0; | ||||
u8 entry, enc_idx, phy_idx, sata_end_device; | u8 entry, enc_idx, phy_idx; | ||||
u32 map_idx, index, device_info; | u32 map_idx, index, device_info; | ||||
struct _map_phy_change *phy_change, *tmp_phy_change; | struct _map_phy_change *phy_change, *tmp_phy_change; | ||||
uint64_t sas_address; | uint64_t sas_address; | ||||
struct enc_mapping_table *et_entry; | struct enc_mapping_table *et_entry; | ||||
struct dev_mapping_table *mt_entry; | struct dev_mapping_table *mt_entry; | ||||
u8 add_code = MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED; | u8 add_code = MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED; | ||||
int rc = 1; | int rc = 1; | ||||
for (entry = 0; entry < topo_change->num_entries; entry++) { | for (entry = 0; entry < topo_change->num_entries; entry++) { | ||||
phy_change = &topo_change->phy_details[entry]; | phy_change = &topo_change->phy_details[entry]; | ||||
if (phy_change->is_processed || !phy_change->dev_handle || | if (phy_change->is_processed || !phy_change->dev_handle || | ||||
phy_change->reason != MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED) | phy_change->reason != MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED) | ||||
continue; | continue; | ||||
if (mpr_config_get_sas_device_pg0(sc, &mpi_reply, | if (mpr_config_get_sas_device_pg0(sc, &mpi_reply, | ||||
&sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, | &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, | ||||
phy_change->dev_handle)) { | phy_change->dev_handle)) { | ||||
phy_change->is_processed = 1; | phy_change->is_processed = 1; | ||||
continue; | continue; | ||||
} | } | ||||
/* | /* | ||||
* Always get SATA Identify information because this is used | * Always get SATA Identify information because this is used | ||||
* to determine if Start/Stop Unit should be sent to the drive | * to determine if Start/Stop Unit should be sent to the drive | ||||
* when the system is shutdown. | * when the system is shutdown. | ||||
*/ | */ | ||||
device_info = le32toh(sas_device_pg0.DeviceInfo); | device_info = le32toh(sas_device_pg0.DeviceInfo); | ||||
sas_address = sas_device_pg0.SASAddress.High; | sas_address = le32toh(sas_device_pg0.SASAddress.High); | ||||
sas_address = (sas_address << 32) | | sas_address = (sas_address << 32) | | ||||
sas_device_pg0.SASAddress.Low; | le32toh(sas_device_pg0.SASAddress.Low); | ||||
sata_end_device = 0; | |||||
if ((device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE) && | if ((device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE) && | ||||
(device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)) { | (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)) { | ||||
sata_end_device = 1; | |||||
rc = mprsas_get_sas_address_for_sata_disk(sc, | rc = mprsas_get_sas_address_for_sata_disk(sc, | ||||
&sas_address, phy_change->dev_handle, device_info, | &sas_address, phy_change->dev_handle, device_info, | ||||
&phy_change->is_SATA_SSD); | &phy_change->is_SATA_SSD); | ||||
if (rc) { | if (rc) { | ||||
mpr_dprint(sc, MPR_ERROR, "%s: failed to get " | mpr_dprint(sc, MPR_ERROR, "%s: failed to get " | ||||
"disk type (SSD or HDD) and SAS Address " | "disk type (SSD or HDD) and SAS Address " | ||||
"for SATA device with handle 0x%04x\n", | "for SATA device with handle 0x%04x\n", | ||||
__func__, phy_change->dev_handle); | __func__, phy_change->dev_handle); | ||||
} else { | } else { | ||||
mpr_dprint(sc, MPR_INFO, "SAS Address for SATA " | mpr_dprint(sc, MPR_INFO, "SAS Address for SATA " | ||||
"device = %jx\n", sas_address); | "device = %jx\n", sas_address); | ||||
} | } | ||||
} | } | ||||
phy_change->physical_id = sas_address; | phy_change->physical_id = sas_address; | ||||
phy_change->slot = le16toh(sas_device_pg0.Slot); | phy_change->slot = le16toh(sas_device_pg0.Slot); | ||||
phy_change->device_info = device_info; | phy_change->device_info = device_info; | ||||
/* | |||||
* When using Enc/Slot mapping, if this device is an enclosure | |||||
* make sure that all of its slots can fit into the mapping | |||||
* table. | |||||
*/ | |||||
if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | ||||
MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { | MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { | ||||
/* | |||||
* The enclosure should already be in the enclosure | |||||
* table due to the Enclosure Add event. If not, just | |||||
* continue, nothing can be done. | |||||
*/ | |||||
enc_idx = _mapping_get_enc_idx_from_handle(sc, | enc_idx = _mapping_get_enc_idx_from_handle(sc, | ||||
topo_change->enc_handle); | topo_change->enc_handle); | ||||
if (enc_idx == MPR_ENCTABLE_BAD_IDX) { | if (enc_idx == MPR_ENCTABLE_BAD_IDX) { | ||||
phy_change->is_processed = 1; | phy_change->is_processed = 1; | ||||
mpr_dprint(sc, MPR_MAPPING, "%s: failed to add " | mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: " | ||||
"the device with handle 0x%04x because the " | "failed to add the device with handle " | ||||
"enclosure is not in the mapping table\n", | "0x%04x because the enclosure is not in " | ||||
__func__, phy_change->dev_handle); | "the mapping table\n", __func__, | ||||
phy_change->dev_handle); | |||||
continue; | continue; | ||||
} | } | ||||
if (!((phy_change->device_info & | if (!((phy_change->device_info & | ||||
MPI2_SAS_DEVICE_INFO_END_DEVICE) && | MPI2_SAS_DEVICE_INFO_END_DEVICE) && | ||||
(phy_change->device_info & | (phy_change->device_info & | ||||
(MPI2_SAS_DEVICE_INFO_SSP_TARGET | | (MPI2_SAS_DEVICE_INFO_SSP_TARGET | | ||||
MPI2_SAS_DEVICE_INFO_STP_TARGET | | MPI2_SAS_DEVICE_INFO_STP_TARGET | | ||||
MPI2_SAS_DEVICE_INFO_SATA_DEVICE)))) { | MPI2_SAS_DEVICE_INFO_SATA_DEVICE)))) { | ||||
phy_change->is_processed = 1; | phy_change->is_processed = 1; | ||||
continue; | continue; | ||||
} | } | ||||
et_entry = &sc->enclosure_table[enc_idx]; | et_entry = &sc->enclosure_table[enc_idx]; | ||||
/* | |||||
* If the enclosure already has a start_index, it's been | |||||
* mapped, so go to the next Topo change. | |||||
*/ | |||||
if (et_entry->start_index != MPR_MAPTABLE_BAD_IDX) | if (et_entry->start_index != MPR_MAPTABLE_BAD_IDX) | ||||
continue; | continue; | ||||
/* | |||||
* If the Expander Handle is 0, the devices are direct | |||||
* attached. In that case, the start_index must be just | |||||
* after the reserved entries. Otherwise, find space in | |||||
* the mapping table for the enclosure's devices. | |||||
*/ | |||||
if (!topo_change->exp_handle) { | if (!topo_change->exp_handle) { | ||||
map_idx = sc->num_rsvd_entries; | map_idx = sc->num_rsvd_entries; | ||||
et_entry->start_index = map_idx; | et_entry->start_index = map_idx; | ||||
} else { | } else { | ||||
map_idx = _mapping_find_enc_map_space(sc, | map_idx = _mapping_find_enc_map_space(sc, | ||||
et_entry); | et_entry); | ||||
et_entry->start_index = map_idx; | et_entry->start_index = map_idx; | ||||
/* | |||||
* If space cannot be found to hold all of the | |||||
* enclosure's devices in the mapping table, | |||||
* there's no need to continue checking the | |||||
* other devices in this event. Set all of the | |||||
* phy_details for this event (if the change is | |||||
* for an add) as already processed because none | |||||
* of these devices can be added to the mapping | |||||
* table. | |||||
*/ | |||||
if (et_entry->start_index == | if (et_entry->start_index == | ||||
MPR_MAPTABLE_BAD_IDX) { | MPR_MAPTABLE_BAD_IDX) { | ||||
mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, | |||||
"%s: failed to add the enclosure " | |||||
"with ID 0x%016jx because there is " | |||||
"no free space available in the " | |||||
"mapping table for all of the " | |||||
"enclosure's devices.\n", __func__, | |||||
(uintmax_t)et_entry->enclosure_id); | |||||
phy_change->is_processed = 1; | phy_change->is_processed = 1; | ||||
for (phy_idx = 0; phy_idx < | for (phy_idx = 0; phy_idx < | ||||
topo_change->num_entries; | topo_change->num_entries; | ||||
phy_idx++) { | phy_idx++) { | ||||
tmp_phy_change = | tmp_phy_change = | ||||
&topo_change->phy_details | &topo_change->phy_details | ||||
[phy_idx]; | [phy_idx]; | ||||
if (tmp_phy_change->reason == | if (tmp_phy_change->reason == | ||||
add_code) | add_code) | ||||
tmp_phy_change-> | tmp_phy_change-> | ||||
is_processed = 1; | is_processed = 1; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
/* Found space in enclosure for mapping entry */ | /* | ||||
* Found space in the mapping table for this enclosure. | |||||
* Initialize each mapping table entry for the | |||||
* enclosure. | |||||
*/ | |||||
mpr_dprint(sc, MPR_MAPPING, "%s: Initialize %d map " | |||||
"entries for the enclosure, starting at map index " | |||||
" %d.\n", __func__, et_entry->num_slots, map_idx); | |||||
mt_entry = &sc->mapping_table[map_idx]; | mt_entry = &sc->mapping_table[map_idx]; | ||||
for (index = map_idx; index < (et_entry->num_slots | for (index = map_idx; index < (et_entry->num_slots | ||||
+ map_idx); index++, mt_entry++) { | + map_idx); index++, mt_entry++) { | ||||
mt_entry->device_info = MPR_DEV_RESERVED; | mt_entry->device_info = MPR_DEV_RESERVED; | ||||
mt_entry->physical_id = et_entry->enclosure_id; | mt_entry->physical_id = et_entry->enclosure_id; | ||||
mt_entry->phy_bits = et_entry->phy_bits; | mt_entry->phy_bits = et_entry->phy_bits; | ||||
mt_entry->missing_count = 0; | mt_entry->missing_count = 0; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | for (entry = 0; entry < topo_change->num_entries; entry++) { | ||||
} | } | ||||
pcie_wwid = pcie_device_pg0.WWID.High; | pcie_wwid = pcie_device_pg0.WWID.High; | ||||
pcie_wwid = (pcie_wwid << 32) | pcie_device_pg0.WWID.Low; | pcie_wwid = (pcie_wwid << 32) | pcie_device_pg0.WWID.Low; | ||||
port_change->physical_id = pcie_wwid; | port_change->physical_id = pcie_wwid; | ||||
port_change->slot = le16toh(pcie_device_pg0.Slot); | port_change->slot = le16toh(pcie_device_pg0.Slot); | ||||
port_change->device_info = le32toh(pcie_device_pg0.DeviceInfo); | port_change->device_info = le32toh(pcie_device_pg0.DeviceInfo); | ||||
/* | |||||
* When using Enc/Slot mapping, if this device is an enclosure | |||||
* make sure that all of its slots can fit into the mapping | |||||
* table. | |||||
*/ | |||||
if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | ||||
MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { | MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { | ||||
/* | |||||
* The enclosure should already be in the enclosure | |||||
* table due to the Enclosure Add event. If not, just | |||||
* continue, nothing can be done. | |||||
*/ | |||||
enc_idx = _mapping_get_enc_idx_from_handle(sc, | enc_idx = _mapping_get_enc_idx_from_handle(sc, | ||||
topo_change->enc_handle); | topo_change->enc_handle); | ||||
if (enc_idx == MPR_ENCTABLE_BAD_IDX) { | if (enc_idx == MPR_ENCTABLE_BAD_IDX) { | ||||
port_change->is_processed = 1; | port_change->is_processed = 1; | ||||
mpr_dprint(sc, MPR_MAPPING, "%s: failed to add " | mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: " | ||||
"the device with handle 0x%04x because the " | "failed to add the device with handle " | ||||
"enclosure is not in the mapping table\n", | "0x%04x because the enclosure is not in " | ||||
__func__, port_change->dev_handle); | "the mapping table\n", __func__, | ||||
port_change->dev_handle); | |||||
continue; | continue; | ||||
} | } | ||||
if (!(port_change->device_info & | if (!(port_change->device_info & | ||||
MPI26_PCIE_DEVINFO_NVME)) { | MPI26_PCIE_DEVINFO_NVME)) { | ||||
port_change->is_processed = 1; | port_change->is_processed = 1; | ||||
continue; | continue; | ||||
} | } | ||||
et_entry = &sc->enclosure_table[enc_idx]; | et_entry = &sc->enclosure_table[enc_idx]; | ||||
/* | |||||
* If the enclosure already has a start_index, it's been | |||||
* mapped, so go to the next Topo change. | |||||
*/ | |||||
if (et_entry->start_index != MPR_MAPTABLE_BAD_IDX) | if (et_entry->start_index != MPR_MAPTABLE_BAD_IDX) | ||||
continue; | continue; | ||||
/* | |||||
* If the Switch Handle is 0, the devices are direct | |||||
* attached. In that case, the start_index must be just | |||||
* after the reserved entries. Otherwise, find space in | |||||
* the mapping table for the enclosure's devices. | |||||
*/ | |||||
if (!topo_change->switch_dev_handle) { | if (!topo_change->switch_dev_handle) { | ||||
map_idx = sc->num_rsvd_entries; | map_idx = sc->num_rsvd_entries; | ||||
et_entry->start_index = map_idx; | et_entry->start_index = map_idx; | ||||
} else { | } else { | ||||
map_idx = _mapping_find_enc_map_space(sc, | map_idx = _mapping_find_enc_map_space(sc, | ||||
et_entry); | et_entry); | ||||
et_entry->start_index = map_idx; | et_entry->start_index = map_idx; | ||||
/* | |||||
* If space cannot be found to hold all of the | |||||
* enclosure's devices in the mapping table, | |||||
* there's no need to continue checking the | |||||
* other devices in this event. Set all of the | |||||
* port_details for this event (if the change is | |||||
* for an add) as already processed because none | |||||
* of these devices can be added to the mapping | |||||
* table. | |||||
*/ | |||||
if (et_entry->start_index == | if (et_entry->start_index == | ||||
MPR_MAPTABLE_BAD_IDX) { | MPR_MAPTABLE_BAD_IDX) { | ||||
mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, | |||||
"%s: failed to add the enclosure " | |||||
"with ID 0x%016jx because there is " | |||||
"no free space available in the " | |||||
"mapping table for all of the " | |||||
"enclosure's devices.\n", __func__, | |||||
(uintmax_t)et_entry->enclosure_id); | |||||
port_change->is_processed = 1; | port_change->is_processed = 1; | ||||
for (port_idx = 0; port_idx < | for (port_idx = 0; port_idx < | ||||
topo_change->num_entries; | topo_change->num_entries; | ||||
port_idx++) { | port_idx++) { | ||||
tmp_port_change = | tmp_port_change = | ||||
&topo_change->port_details | &topo_change->port_details | ||||
[port_idx]; | [port_idx]; | ||||
if (tmp_port_change->reason == | if (tmp_port_change->reason == | ||||
add_code) | add_code) | ||||
tmp_port_change-> | tmp_port_change-> | ||||
is_processed = 1; | is_processed = 1; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
/* Found space in enclosure for mapping entry */ | /* | ||||
* Found space in the mapping table for this enclosure. | |||||
* Initialize each mapping table entry for the | |||||
* enclosure. | |||||
*/ | |||||
mpr_dprint(sc, MPR_MAPPING, "%s: Initialize %d map " | |||||
"entries for the enclosure, starting at map index " | |||||
" %d.\n", __func__, et_entry->num_slots, map_idx); | |||||
mt_entry = &sc->mapping_table[map_idx]; | mt_entry = &sc->mapping_table[map_idx]; | ||||
for (index = map_idx; index < (et_entry->num_slots | for (index = map_idx; index < (et_entry->num_slots | ||||
+ map_idx); index++, mt_entry++) { | + map_idx); index++, mt_entry++) { | ||||
mt_entry->device_info = MPR_DEV_RESERVED; | mt_entry->device_info = MPR_DEV_RESERVED; | ||||
mt_entry->physical_id = et_entry->enclosure_id; | mt_entry->physical_id = et_entry->enclosure_id; | ||||
mt_entry->phy_bits = et_entry->phy_bits; | mt_entry->phy_bits = et_entry->phy_bits; | ||||
mt_entry->missing_count = 0; | mt_entry->missing_count = 0; | ||||
} | } | ||||
Show All 10 Lines | |||||
*/ | */ | ||||
static inline void | static inline void | ||||
_mapping_set_mid_to_eid(struct mpr_softc *sc, | _mapping_set_mid_to_eid(struct mpr_softc *sc, | ||||
struct enc_mapping_table *et_entry) | struct enc_mapping_table *et_entry) | ||||
{ | { | ||||
struct dev_mapping_table *mt_entry; | struct dev_mapping_table *mt_entry; | ||||
u16 slots = et_entry->num_slots, map_idx; | u16 slots = et_entry->num_slots, map_idx; | ||||
u32 start_idx = et_entry->start_index; | u32 start_idx = et_entry->start_index; | ||||
if (start_idx != MPR_MAPTABLE_BAD_IDX) { | if (start_idx != MPR_MAPTABLE_BAD_IDX) { | ||||
mt_entry = &sc->mapping_table[start_idx]; | mt_entry = &sc->mapping_table[start_idx]; | ||||
for (map_idx = 0; map_idx < slots; map_idx++, mt_entry++) | for (map_idx = 0; map_idx < slots; map_idx++, mt_entry++) | ||||
mt_entry->physical_id = et_entry->enclosure_id; | mt_entry->physical_id = et_entry->enclosure_id; | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
Show All 33 Lines | for (remove_idx = 0; remove_idx < sc->max_devices; | ||||
sc->dpm_flush_entry[remove_entry-> | sc->dpm_flush_entry[remove_entry-> | ||||
dpm_entry_num] = 1; | dpm_entry_num] = 1; | ||||
sc->dpm_entry_used[remove_entry->dpm_entry_num] | sc->dpm_entry_used[remove_entry->dpm_entry_num] | ||||
= 0; | = 0; | ||||
remove_entry->dpm_entry_num = MPR_DPM_BAD_IDX; | remove_entry->dpm_entry_num = MPR_DPM_BAD_IDX; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* | |||||
* When using Enc/Slot mapping, if a new enclosure was added and old | |||||
* enclosure space was needed, the enclosure table may now have gaps | |||||
* that need to be closed. All enclosure mappings need to be contiguous | |||||
* so that space can be reused correctly if available. | |||||
*/ | |||||
if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | ||||
MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { | MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { | ||||
num_entries = sc->num_enc_table_entries; | num_entries = sc->num_enc_table_entries; | ||||
while (!done_flag) { | while (!done_flag) { | ||||
done_flag = 1; | done_flag = 1; | ||||
et_entry = sc->enclosure_table; | et_entry = sc->enclosure_table; | ||||
for (i = 0; i < num_entries; i++, et_entry++) { | for (i = 0; i < num_entries; i++, et_entry++) { | ||||
if (!et_entry->enc_handle && et_entry-> | if (!et_entry->enc_handle && et_entry-> | ||||
▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | if (phy_change->reason != MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED || | ||||
continue; | continue; | ||||
} | } | ||||
if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | ||||
MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { | MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { | ||||
enc_idx = _mapping_get_enc_idx_from_handle | enc_idx = _mapping_get_enc_idx_from_handle | ||||
(sc, topo_change->enc_handle); | (sc, topo_change->enc_handle); | ||||
if (enc_idx == MPR_ENCTABLE_BAD_IDX) { | if (enc_idx == MPR_ENCTABLE_BAD_IDX) { | ||||
phy_change->is_processed = 1; | phy_change->is_processed = 1; | ||||
mpr_dprint(sc, MPR_ERROR, "%s: failed to add " | mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: " | ||||
"the device with handle 0x%04x because the " | "failed to add the device with handle " | ||||
"enclosure is not in the mapping table\n", | "0x%04x because the enclosure is not in " | ||||
__func__, phy_change->dev_handle); | "the mapping table\n", __func__, | ||||
phy_change->dev_handle); | |||||
continue; | continue; | ||||
} | } | ||||
/* | |||||
* If the enclosure's start_index is BAD here, it means | |||||
* that there is no room in the mapping table to cover | |||||
* all of the devices that could be in the enclosure. | |||||
* There's no reason to process any of the devices for | |||||
* this enclosure since they can't be mapped. | |||||
*/ | |||||
et_entry = &sc->enclosure_table[enc_idx]; | et_entry = &sc->enclosure_table[enc_idx]; | ||||
if (et_entry->start_index == MPR_MAPTABLE_BAD_IDX) { | if (et_entry->start_index == MPR_MAPTABLE_BAD_IDX) { | ||||
phy_change->is_processed = 1; | phy_change->is_processed = 1; | ||||
if (!sc->mt_full_retry) { | mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: " | ||||
sc->mt_add_device_failed = 1; | "failed to add the device with handle " | ||||
"0x%04x because there is no free space " | |||||
"available in the mapping table\n", | |||||
__func__, phy_change->dev_handle); | |||||
continue; | continue; | ||||
} | } | ||||
mpr_dprint(sc, MPR_INFO, "%s: failed to add " | |||||
"the device with handle 0x%04x because " | /* | ||||
"there is no free space available in the " | * Add this device to the mapping table at the correct | ||||
"mapping table\n", __func__, | * offset where space was found to map the enclosure. | ||||
phy_change->dev_handle); | * Then setup the DPM entry information if being used. | ||||
continue; | */ | ||||
} | |||||
map_idx = et_entry->start_index + phy_change->slot - | map_idx = et_entry->start_index + phy_change->slot - | ||||
et_entry->start_slot; | et_entry->start_slot; | ||||
mt_entry = &sc->mapping_table[map_idx]; | mt_entry = &sc->mapping_table[map_idx]; | ||||
mt_entry->physical_id = phy_change->physical_id; | mt_entry->physical_id = phy_change->physical_id; | ||||
mt_entry->channel = 0; | |||||
mt_entry->id = map_idx; | mt_entry->id = map_idx; | ||||
mt_entry->dev_handle = phy_change->dev_handle; | mt_entry->dev_handle = phy_change->dev_handle; | ||||
mt_entry->missing_count = 0; | mt_entry->missing_count = 0; | ||||
mt_entry->dpm_entry_num = et_entry->dpm_entry_num; | mt_entry->dpm_entry_num = et_entry->dpm_entry_num; | ||||
mt_entry->device_info = phy_change->device_info | | mt_entry->device_info = phy_change->device_info | | ||||
(MPR_DEV_RESERVED | MPR_MAP_IN_USE); | (MPR_DEV_RESERVED | MPR_MAP_IN_USE); | ||||
if (sc->is_dpm_enable) { | if (sc->is_dpm_enable) { | ||||
dpm_idx = et_entry->dpm_entry_num; | dpm_idx = et_entry->dpm_entry_num; | ||||
Show All 10 Lines | if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | ||||
hdr_sz); | hdr_sz); | ||||
dpm_entry += dpm_idx; | dpm_entry += dpm_idx; | ||||
dpm_entry-> | dpm_entry-> | ||||
PhysicalIdentifier.Low = | PhysicalIdentifier.Low = | ||||
(0xFFFFFFFF & | (0xFFFFFFFF & | ||||
et_entry->enclosure_id); | et_entry->enclosure_id); | ||||
dpm_entry-> | dpm_entry-> | ||||
PhysicalIdentifier.High = | PhysicalIdentifier.High = | ||||
( et_entry->enclosure_id | (et_entry->enclosure_id | ||||
>> 32); | >> 32); | ||||
dpm_entry->DeviceIndex = | dpm_entry->DeviceIndex = | ||||
(U16)et_entry->start_index; | (U16)et_entry->start_index; | ||||
dpm_entry->MappingInformation = | dpm_entry->MappingInformation = | ||||
et_entry->num_slots; | et_entry->num_slots; | ||||
dpm_entry->MappingInformation | dpm_entry->MappingInformation | ||||
<<= map_shift; | <<= map_shift; | ||||
dpm_entry->PhysicalBitsMapping | dpm_entry->PhysicalBitsMapping | ||||
= et_entry->phy_bits; | = et_entry->phy_bits; | ||||
et_entry->dpm_entry_num = | et_entry->dpm_entry_num = | ||||
dpm_idx; | dpm_idx; | ||||
/* FIXME Do I need to set the dpm_idxin mt_entry too */ | |||||
sc->dpm_entry_used[dpm_idx] = 1; | sc->dpm_entry_used[dpm_idx] = 1; | ||||
sc->dpm_flush_entry[dpm_idx] = | sc->dpm_flush_entry[dpm_idx] = | ||||
1; | 1; | ||||
phy_change->is_processed = 1; | phy_change->is_processed = 1; | ||||
} else { | } else { | ||||
phy_change->is_processed = 1; | phy_change->is_processed = 1; | ||||
mpr_dprint(sc, MPR_INFO, "%s: " | mpr_dprint(sc, MPR_ERROR | | ||||
"failed to add the device " | MPR_MAPPING, "%s: failed " | ||||
"with handle 0x%04x to " | "to add the device with " | ||||
"handle 0x%04x to " | |||||
"persistent table because " | "persistent table because " | ||||
"there is no free space " | "there is no free space " | ||||
"available\n", __func__, | "available\n", __func__, | ||||
phy_change->dev_handle); | phy_change->dev_handle); | ||||
} | } | ||||
} else { | } else { | ||||
et_entry->dpm_entry_num = dpm_idx; | et_entry->dpm_entry_num = dpm_idx; | ||||
mt_entry->dpm_entry_num = dpm_idx; | mt_entry->dpm_entry_num = dpm_idx; | ||||
} | } | ||||
} | } | ||||
/* FIXME Why not mt_entry too? */ | |||||
et_entry->init_complete = 1; | et_entry->init_complete = 1; | ||||
} else if ((ioc_pg8_flags & | } else if ((ioc_pg8_flags & | ||||
MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | ||||
MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) { | MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) { | ||||
/* | |||||
* Get the mapping table index for this device. If it's | |||||
* not in the mapping table yet, find a free entry if | |||||
* one is available. If there are no free entries, look | |||||
* for the entry that has the highest missing count. If | |||||
* none of that works to find an entry in the mapping | |||||
* table, there is a problem. Log a message and just | |||||
* continue on. | |||||
*/ | |||||
map_idx = _mapping_get_mt_idx_from_id | map_idx = _mapping_get_mt_idx_from_id | ||||
(sc, phy_change->physical_id); | (sc, phy_change->physical_id); | ||||
if (map_idx == MPR_MAPTABLE_BAD_IDX) { | if (map_idx == MPR_MAPTABLE_BAD_IDX) { | ||||
search_idx = sc->num_rsvd_entries; | search_idx = sc->num_rsvd_entries; | ||||
if (topo_change->exp_handle) | if (topo_change->exp_handle) | ||||
search_idx += max_num_phy_ids; | search_idx += max_num_phy_ids; | ||||
map_idx = _mapping_get_free_mt_idx(sc, | map_idx = _mapping_get_free_mt_idx(sc, | ||||
search_idx); | search_idx); | ||||
} | } | ||||
/* | |||||
* If an entry will be used that has a missing device, | |||||
* clear its entry from the DPM in the controller. | |||||
*/ | |||||
if (map_idx == MPR_MAPTABLE_BAD_IDX) { | if (map_idx == MPR_MAPTABLE_BAD_IDX) { | ||||
map_idx = _mapping_get_high_missing_mt_idx(sc); | map_idx = _mapping_get_high_missing_mt_idx(sc); | ||||
if (map_idx != MPR_MAPTABLE_BAD_IDX) { | if (map_idx != MPR_MAPTABLE_BAD_IDX) { | ||||
mt_entry = &sc->mapping_table[map_idx]; | mt_entry = &sc->mapping_table[map_idx]; | ||||
if (mt_entry->dev_handle) { | _mapping_add_to_removal_table(sc, | ||||
_mapping_add_to_removal_table | mt_entry->dpm_entry_num); | ||||
(sc, mt_entry->dev_handle, | |||||
0); | |||||
is_removed = 1; | is_removed = 1; | ||||
} | |||||
mt_entry->init_complete = 0; | mt_entry->init_complete = 0; | ||||
} | } | ||||
} | } | ||||
if (map_idx != MPR_MAPTABLE_BAD_IDX) { | if (map_idx != MPR_MAPTABLE_BAD_IDX) { | ||||
mt_entry = &sc->mapping_table[map_idx]; | mt_entry = &sc->mapping_table[map_idx]; | ||||
mt_entry->physical_id = phy_change->physical_id; | mt_entry->physical_id = phy_change->physical_id; | ||||
mt_entry->channel = 0; | |||||
mt_entry->id = map_idx; | mt_entry->id = map_idx; | ||||
mt_entry->dev_handle = phy_change->dev_handle; | mt_entry->dev_handle = phy_change->dev_handle; | ||||
mt_entry->missing_count = 0; | mt_entry->missing_count = 0; | ||||
mt_entry->device_info = phy_change->device_info | mt_entry->device_info = phy_change->device_info | ||||
| (MPR_DEV_RESERVED | MPR_MAP_IN_USE); | | (MPR_DEV_RESERVED | MPR_MAP_IN_USE); | ||||
} else { | } else { | ||||
phy_change->is_processed = 1; | phy_change->is_processed = 1; | ||||
if (!sc->mt_full_retry) { | mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: " | ||||
sc->mt_add_device_failed = 1; | "failed to add the device with handle " | ||||
"0x%04x because there is no free space " | |||||
"available in the mapping table\n", | |||||
__func__, phy_change->dev_handle); | |||||
continue; | continue; | ||||
} | } | ||||
mpr_dprint(sc, MPR_INFO, "%s: failed to add " | |||||
"the device with handle 0x%04x because " | |||||
"there is no free space available in the " | |||||
"mapping table\n", __func__, | |||||
phy_change->dev_handle); | |||||
continue; | |||||
} | |||||
if (sc->is_dpm_enable) { | if (sc->is_dpm_enable) { | ||||
if (mt_entry->dpm_entry_num != | if (mt_entry->dpm_entry_num != | ||||
MPR_DPM_BAD_IDX) { | MPR_DPM_BAD_IDX) { | ||||
dpm_idx = mt_entry->dpm_entry_num; | dpm_idx = mt_entry->dpm_entry_num; | ||||
dpm_entry = (Mpi2DriverMap0Entry_t *) | dpm_entry = (Mpi2DriverMap0Entry_t *) | ||||
((u8 *)sc->dpm_pg0 + hdr_sz); | ((u8 *)sc->dpm_pg0 + hdr_sz); | ||||
dpm_entry += dpm_idx; | dpm_entry += dpm_idx; | ||||
missing_cnt = dpm_entry-> | missing_cnt = dpm_entry-> | ||||
MappingInformation & | MappingInformation & | ||||
MPI2_DRVMAP0_MAPINFO_MISSING_MASK; | MPI2_DRVMAP0_MAPINFO_MISSING_MASK; | ||||
temp64_var = dpm_entry-> | temp64_var = dpm_entry-> | ||||
PhysicalIdentifier.High; | PhysicalIdentifier.High; | ||||
temp64_var = (temp64_var << 32) | | temp64_var = (temp64_var << 32) | | ||||
dpm_entry->PhysicalIdentifier.Low; | dpm_entry->PhysicalIdentifier.Low; | ||||
/* | |||||
* If the Mapping Table's info is not | |||||
* the same as the DPM entry, clear the | |||||
* init_complete flag so that it's | |||||
* updated. | |||||
*/ | |||||
if ((mt_entry->physical_id == | if ((mt_entry->physical_id == | ||||
temp64_var) && !missing_cnt) | temp64_var) && !missing_cnt) | ||||
mt_entry->init_complete = 1; | mt_entry->init_complete = 1; | ||||
else | |||||
mt_entry->init_complete = 0; | |||||
} else { | } else { | ||||
dpm_idx = _mapping_get_free_dpm_idx(sc); | dpm_idx = _mapping_get_free_dpm_idx(sc); | ||||
mt_entry->init_complete = 0; | mt_entry->init_complete = 0; | ||||
} | } | ||||
if (dpm_idx != MPR_DPM_BAD_IDX && | if (dpm_idx != MPR_DPM_BAD_IDX && | ||||
!mt_entry->init_complete) { | !mt_entry->init_complete) { | ||||
mt_entry->init_complete = 1; | |||||
mt_entry->dpm_entry_num = dpm_idx; | mt_entry->dpm_entry_num = dpm_idx; | ||||
dpm_entry = (Mpi2DriverMap0Entry_t *) | dpm_entry = (Mpi2DriverMap0Entry_t *) | ||||
((u8 *)sc->dpm_pg0 + hdr_sz); | ((u8 *)sc->dpm_pg0 + hdr_sz); | ||||
dpm_entry += dpm_idx; | dpm_entry += dpm_idx; | ||||
dpm_entry->PhysicalIdentifier.Low = | dpm_entry->PhysicalIdentifier.Low = | ||||
(0xFFFFFFFF & | (0xFFFFFFFF & | ||||
mt_entry->physical_id); | mt_entry->physical_id); | ||||
dpm_entry->PhysicalIdentifier.High = | dpm_entry->PhysicalIdentifier.High = | ||||
(mt_entry->physical_id >> 32); | (mt_entry->physical_id >> 32); | ||||
dpm_entry->DeviceIndex = (U16) map_idx; | dpm_entry->DeviceIndex = (U16) map_idx; | ||||
dpm_entry->MappingInformation = 0; | dpm_entry->MappingInformation = 0; | ||||
dpm_entry->PhysicalBitsMapping = 0; | dpm_entry->PhysicalBitsMapping = 0; | ||||
sc->dpm_entry_used[dpm_idx] = 1; | sc->dpm_entry_used[dpm_idx] = 1; | ||||
sc->dpm_flush_entry[dpm_idx] = 1; | sc->dpm_flush_entry[dpm_idx] = 1; | ||||
phy_change->is_processed = 1; | phy_change->is_processed = 1; | ||||
} else if (dpm_idx == MPR_DPM_BAD_IDX) { | } else if (dpm_idx == MPR_DPM_BAD_IDX) { | ||||
phy_change->is_processed = 1; | phy_change->is_processed = 1; | ||||
mpr_dprint(sc, MPR_INFO, "%s: failed " | mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, | ||||
"to add the device with handle " | "%s: failed to add the device with " | ||||
"0x%04x to persistent table " | "handle 0x%04x to persistent table " | ||||
"because there is no free space " | "because there is no free space " | ||||
"available\n", __func__, | "available\n", __func__, | ||||
phy_change->dev_handle); | phy_change->dev_handle); | ||||
} | } | ||||
} | } | ||||
mt_entry->init_complete = 1; | mt_entry->init_complete = 1; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | if (port_change->reason != MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED || | ||||
continue; | continue; | ||||
} | } | ||||
if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | ||||
MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { | MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { | ||||
enc_idx = _mapping_get_enc_idx_from_handle | enc_idx = _mapping_get_enc_idx_from_handle | ||||
(sc, topo_change->enc_handle); | (sc, topo_change->enc_handle); | ||||
if (enc_idx == MPR_ENCTABLE_BAD_IDX) { | if (enc_idx == MPR_ENCTABLE_BAD_IDX) { | ||||
port_change->is_processed = 1; | port_change->is_processed = 1; | ||||
mpr_dprint(sc, MPR_ERROR, "%s: failed to add " | mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: " | ||||
"the device with handle 0x%04x because the " | "failed to add the device with handle " | ||||
"enclosure is not in the mapping table\n", | "0x%04x because the enclosure is not in " | ||||
__func__, port_change->dev_handle); | "the mapping table\n", __func__, | ||||
port_change->dev_handle); | |||||
continue; | continue; | ||||
} | } | ||||
/* | |||||
* If the enclosure's start_index is BAD here, it means | |||||
* that there is no room in the mapping table to cover | |||||
* all of the devices that could be in the enclosure. | |||||
* There's no reason to process any of the devices for | |||||
* this enclosure since they can't be mapped. | |||||
*/ | |||||
et_entry = &sc->enclosure_table[enc_idx]; | et_entry = &sc->enclosure_table[enc_idx]; | ||||
if (et_entry->start_index == MPR_MAPTABLE_BAD_IDX) { | if (et_entry->start_index == MPR_MAPTABLE_BAD_IDX) { | ||||
port_change->is_processed = 1; | port_change->is_processed = 1; | ||||
if (!sc->mt_full_retry) { | mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: " | ||||
sc->mt_add_device_failed = 1; | "failed to add the device with handle " | ||||
"0x%04x because there is no free space " | |||||
"available in the mapping table\n", | |||||
__func__, port_change->dev_handle); | |||||
continue; | continue; | ||||
} | } | ||||
mpr_dprint(sc, MPR_INFO, "%s: failed to add " | |||||
"the device with handle 0x%04x because " | /* | ||||
"there is no free space available in the " | * Add this device to the mapping table at the correct | ||||
"mapping table\n", __func__, | * offset where space was found to map the enclosure. | ||||
port_change->dev_handle); | * Then setup the DPM entry information if being used. | ||||
continue; | */ | ||||
} | |||||
map_idx = et_entry->start_index + port_change->slot - | map_idx = et_entry->start_index + port_change->slot - | ||||
et_entry->start_slot; | et_entry->start_slot; | ||||
mt_entry = &sc->mapping_table[map_idx]; | mt_entry = &sc->mapping_table[map_idx]; | ||||
mt_entry->physical_id = port_change->physical_id; | mt_entry->physical_id = port_change->physical_id; | ||||
mt_entry->channel = 0; | |||||
mt_entry->id = map_idx; | mt_entry->id = map_idx; | ||||
mt_entry->dev_handle = port_change->dev_handle; | mt_entry->dev_handle = port_change->dev_handle; | ||||
mt_entry->missing_count = 0; | mt_entry->missing_count = 0; | ||||
mt_entry->dpm_entry_num = et_entry->dpm_entry_num; | mt_entry->dpm_entry_num = et_entry->dpm_entry_num; | ||||
mt_entry->device_info = port_change->device_info | | mt_entry->device_info = port_change->device_info | | ||||
(MPR_DEV_RESERVED | MPR_MAP_IN_USE); | (MPR_DEV_RESERVED | MPR_MAP_IN_USE); | ||||
if (sc->is_dpm_enable) { | if (sc->is_dpm_enable) { | ||||
dpm_idx = et_entry->dpm_entry_num; | dpm_idx = et_entry->dpm_entry_num; | ||||
Show All 10 Lines | if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | ||||
hdr_sz); | hdr_sz); | ||||
dpm_entry += dpm_idx; | dpm_entry += dpm_idx; | ||||
dpm_entry-> | dpm_entry-> | ||||
PhysicalIdentifier.Low = | PhysicalIdentifier.Low = | ||||
(0xFFFFFFFF & | (0xFFFFFFFF & | ||||
et_entry->enclosure_id); | et_entry->enclosure_id); | ||||
dpm_entry-> | dpm_entry-> | ||||
PhysicalIdentifier.High = | PhysicalIdentifier.High = | ||||
( et_entry->enclosure_id | (et_entry->enclosure_id | ||||
>> 32); | >> 32); | ||||
dpm_entry->DeviceIndex = | dpm_entry->DeviceIndex = | ||||
(U16)et_entry->start_index; | (U16)et_entry->start_index; | ||||
dpm_entry->MappingInformation = | dpm_entry->MappingInformation = | ||||
et_entry->num_slots; | et_entry->num_slots; | ||||
dpm_entry->MappingInformation | dpm_entry->MappingInformation | ||||
<<= map_shift; | <<= map_shift; | ||||
dpm_entry->PhysicalBitsMapping | dpm_entry->PhysicalBitsMapping | ||||
= et_entry->phy_bits; | = et_entry->phy_bits; | ||||
et_entry->dpm_entry_num = | et_entry->dpm_entry_num = | ||||
dpm_idx; | dpm_idx; | ||||
/* FIXME Do I need to set the dpm_idxin mt_entry too */ | |||||
sc->dpm_entry_used[dpm_idx] = 1; | sc->dpm_entry_used[dpm_idx] = 1; | ||||
sc->dpm_flush_entry[dpm_idx] = | sc->dpm_flush_entry[dpm_idx] = | ||||
1; | 1; | ||||
port_change->is_processed = 1; | port_change->is_processed = 1; | ||||
} else { | } else { | ||||
port_change->is_processed = 1; | port_change->is_processed = 1; | ||||
mpr_dprint(sc, MPR_INFO, "%s: " | mpr_dprint(sc, MPR_ERROR | | ||||
"failed to add the device " | MPR_MAPPING, "%s: failed " | ||||
"with handle 0x%04x to " | "to add the device with " | ||||
"handle 0x%04x to " | |||||
"persistent table because " | "persistent table because " | ||||
"there is no free space " | "there is no free space " | ||||
"available\n", __func__, | "available\n", __func__, | ||||
port_change->dev_handle); | port_change->dev_handle); | ||||
} | } | ||||
} else { | } else { | ||||
et_entry->dpm_entry_num = dpm_idx; | et_entry->dpm_entry_num = dpm_idx; | ||||
mt_entry->dpm_entry_num = dpm_idx; | mt_entry->dpm_entry_num = dpm_idx; | ||||
} | } | ||||
} | } | ||||
/* FIXME Why not mt_entry too? */ | |||||
et_entry->init_complete = 1; | et_entry->init_complete = 1; | ||||
} else if ((ioc_pg8_flags & | } else if ((ioc_pg8_flags & | ||||
MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | ||||
MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) { | MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) { | ||||
/* | |||||
* Get the mapping table index for this device. If it's | |||||
* not in the mapping table yet, find a free entry if | |||||
* one is available. If there are no free entries, look | |||||
* for the entry that has the highest missing count. If | |||||
* none of that works to find an entry in the mapping | |||||
* table, there is a problem. Log a message and just | |||||
* continue on. | |||||
*/ | |||||
map_idx = _mapping_get_mt_idx_from_id | map_idx = _mapping_get_mt_idx_from_id | ||||
(sc, port_change->physical_id); | (sc, port_change->physical_id); | ||||
if (map_idx == MPR_MAPTABLE_BAD_IDX) { | if (map_idx == MPR_MAPTABLE_BAD_IDX) { | ||||
search_idx = sc->num_rsvd_entries; | search_idx = sc->num_rsvd_entries; | ||||
if (topo_change->switch_dev_handle) | if (topo_change->switch_dev_handle) | ||||
search_idx += max_num_phy_ids; | search_idx += max_num_phy_ids; | ||||
map_idx = _mapping_get_free_mt_idx(sc, | map_idx = _mapping_get_free_mt_idx(sc, | ||||
search_idx); | search_idx); | ||||
} | } | ||||
/* | |||||
* If an entry will be used that has a missing device, | |||||
* clear its entry from the DPM in the controller. | |||||
*/ | |||||
if (map_idx == MPR_MAPTABLE_BAD_IDX) { | if (map_idx == MPR_MAPTABLE_BAD_IDX) { | ||||
map_idx = _mapping_get_high_missing_mt_idx(sc); | map_idx = _mapping_get_high_missing_mt_idx(sc); | ||||
if (map_idx != MPR_MAPTABLE_BAD_IDX) { | if (map_idx != MPR_MAPTABLE_BAD_IDX) { | ||||
mt_entry = &sc->mapping_table[map_idx]; | mt_entry = &sc->mapping_table[map_idx]; | ||||
if (mt_entry->dev_handle) { | _mapping_add_to_removal_table(sc, | ||||
_mapping_add_to_removal_table | mt_entry->dpm_entry_num); | ||||
(sc, mt_entry->dev_handle, | |||||
0); | |||||
is_removed = 1; | is_removed = 1; | ||||
} | |||||
mt_entry->init_complete = 0; | mt_entry->init_complete = 0; | ||||
} | } | ||||
} | } | ||||
if (map_idx != MPR_MAPTABLE_BAD_IDX) { | if (map_idx != MPR_MAPTABLE_BAD_IDX) { | ||||
mt_entry = &sc->mapping_table[map_idx]; | mt_entry = &sc->mapping_table[map_idx]; | ||||
mt_entry->physical_id = | mt_entry->physical_id = | ||||
port_change->physical_id; | port_change->physical_id; | ||||
mt_entry->channel = 0; | |||||
mt_entry->id = map_idx; | mt_entry->id = map_idx; | ||||
mt_entry->dev_handle = port_change->dev_handle; | mt_entry->dev_handle = port_change->dev_handle; | ||||
mt_entry->missing_count = 0; | mt_entry->missing_count = 0; | ||||
mt_entry->device_info = | mt_entry->device_info = | ||||
port_change->device_info | | port_change->device_info | | ||||
(MPR_DEV_RESERVED | MPR_MAP_IN_USE); | (MPR_DEV_RESERVED | MPR_MAP_IN_USE); | ||||
} else { | } else { | ||||
port_change->is_processed = 1; | port_change->is_processed = 1; | ||||
if (!sc->mt_full_retry) { | mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: " | ||||
sc->mt_add_device_failed = 1; | "failed to add the device with handle " | ||||
"0x%04x because there is no free space " | |||||
"available in the mapping table\n", | |||||
__func__, port_change->dev_handle); | |||||
continue; | continue; | ||||
} | } | ||||
mpr_dprint(sc, MPR_INFO, "%s: failed to add " | |||||
"the device with handle 0x%04x because " | |||||
"there is no free space available in the " | |||||
"mapping table\n", __func__, | |||||
port_change->dev_handle); | |||||
continue; | |||||
} | |||||
if (sc->is_dpm_enable) { | if (sc->is_dpm_enable) { | ||||
if (mt_entry->dpm_entry_num != | if (mt_entry->dpm_entry_num != | ||||
MPR_DPM_BAD_IDX) { | MPR_DPM_BAD_IDX) { | ||||
dpm_idx = mt_entry->dpm_entry_num; | dpm_idx = mt_entry->dpm_entry_num; | ||||
dpm_entry = (Mpi2DriverMap0Entry_t *) | dpm_entry = (Mpi2DriverMap0Entry_t *) | ||||
((u8 *)sc->dpm_pg0 + hdr_sz); | ((u8 *)sc->dpm_pg0 + hdr_sz); | ||||
dpm_entry += dpm_idx; | dpm_entry += dpm_idx; | ||||
missing_cnt = dpm_entry-> | missing_cnt = dpm_entry-> | ||||
MappingInformation & | MappingInformation & | ||||
MPI2_DRVMAP0_MAPINFO_MISSING_MASK; | MPI2_DRVMAP0_MAPINFO_MISSING_MASK; | ||||
temp64_var = dpm_entry-> | temp64_var = dpm_entry-> | ||||
PhysicalIdentifier.High; | PhysicalIdentifier.High; | ||||
temp64_var = (temp64_var << 32) | | temp64_var = (temp64_var << 32) | | ||||
dpm_entry->PhysicalIdentifier.Low; | dpm_entry->PhysicalIdentifier.Low; | ||||
/* | |||||
* If the Mapping Table's info is not | |||||
* the same as the DPM entry, clear the | |||||
* init_complete flag so that it's | |||||
* updated. | |||||
*/ | |||||
if ((mt_entry->physical_id == | if ((mt_entry->physical_id == | ||||
temp64_var) && !missing_cnt) | temp64_var) && !missing_cnt) | ||||
mt_entry->init_complete = 1; | mt_entry->init_complete = 1; | ||||
else | |||||
mt_entry->init_complete = 0; | |||||
} else { | } else { | ||||
dpm_idx = _mapping_get_free_dpm_idx(sc); | dpm_idx = _mapping_get_free_dpm_idx(sc); | ||||
mt_entry->init_complete = 0; | mt_entry->init_complete = 0; | ||||
} | } | ||||
if (dpm_idx != MPR_DPM_BAD_IDX && | if (dpm_idx != MPR_DPM_BAD_IDX && | ||||
!mt_entry->init_complete) { | !mt_entry->init_complete) { | ||||
mt_entry->init_complete = 1; | |||||
mt_entry->dpm_entry_num = dpm_idx; | mt_entry->dpm_entry_num = dpm_idx; | ||||
dpm_entry = (Mpi2DriverMap0Entry_t *) | dpm_entry = (Mpi2DriverMap0Entry_t *) | ||||
((u8 *)sc->dpm_pg0 + hdr_sz); | ((u8 *)sc->dpm_pg0 + hdr_sz); | ||||
dpm_entry += dpm_idx; | dpm_entry += dpm_idx; | ||||
dpm_entry->PhysicalIdentifier.Low = | dpm_entry->PhysicalIdentifier.Low = | ||||
(0xFFFFFFFF & | (0xFFFFFFFF & | ||||
mt_entry->physical_id); | mt_entry->physical_id); | ||||
dpm_entry->PhysicalIdentifier.High = | dpm_entry->PhysicalIdentifier.High = | ||||
(mt_entry->physical_id >> 32); | (mt_entry->physical_id >> 32); | ||||
dpm_entry->DeviceIndex = (U16) map_idx; | dpm_entry->DeviceIndex = (U16) map_idx; | ||||
dpm_entry->MappingInformation = 0; | dpm_entry->MappingInformation = 0; | ||||
dpm_entry->PhysicalBitsMapping = 0; | dpm_entry->PhysicalBitsMapping = 0; | ||||
sc->dpm_entry_used[dpm_idx] = 1; | sc->dpm_entry_used[dpm_idx] = 1; | ||||
sc->dpm_flush_entry[dpm_idx] = 1; | sc->dpm_flush_entry[dpm_idx] = 1; | ||||
port_change->is_processed = 1; | port_change->is_processed = 1; | ||||
} else if (dpm_idx == MPR_DPM_BAD_IDX) { | } else if (dpm_idx == MPR_DPM_BAD_IDX) { | ||||
port_change->is_processed = 1; | port_change->is_processed = 1; | ||||
mpr_dprint(sc, MPR_INFO, "%s: failed " | mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, | ||||
"to add the device with handle " | "%s: failed to add the device with " | ||||
"0x%04x to persistent table " | "handle 0x%04x to persistent table " | ||||
"because there is no free space " | "because there is no free space " | ||||
"available\n", __func__, | "available\n", __func__, | ||||
port_change->dev_handle); | port_change->dev_handle); | ||||
} | } | ||||
} | } | ||||
mt_entry->init_complete = 1; | mt_entry->init_complete = 1; | ||||
} | } | ||||
Show All 29 Lines | for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++) { | ||||
dpm_entry->MappingInformation = htole16(dpm_entry-> | dpm_entry->MappingInformation = htole16(dpm_entry-> | ||||
MappingInformation); | MappingInformation); | ||||
dpm_entry->DeviceIndex = htole16(dpm_entry->DeviceIndex); | dpm_entry->DeviceIndex = htole16(dpm_entry->DeviceIndex); | ||||
dpm_entry->PhysicalBitsMapping = htole32(dpm_entry-> | dpm_entry->PhysicalBitsMapping = htole32(dpm_entry-> | ||||
PhysicalBitsMapping); | PhysicalBitsMapping); | ||||
memcpy(&config_page.Entry, (u8 *)dpm_entry, | memcpy(&config_page.Entry, (u8 *)dpm_entry, | ||||
sizeof(Mpi2DriverMap0Entry_t)); | sizeof(Mpi2DriverMap0Entry_t)); | ||||
/* TODO-How to handle failed writes? */ | /* TODO-How to handle failed writes? */ | ||||
mpr_dprint(sc, MPR_MAPPING, "%s: Flushing DPM entry %d.\n", | |||||
__func__, entry_num); | |||||
if (mpr_config_set_dpm_pg0(sc, &mpi_reply, &config_page, | if (mpr_config_set_dpm_pg0(sc, &mpi_reply, &config_page, | ||||
entry_num)) { | entry_num)) { | ||||
printf("%s: write of dpm entry %d for device failed\n", | mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: Flush of " | ||||
__func__, entry_num); | "DPM entry %d for device failed\n", __func__, | ||||
entry_num); | |||||
} else | } else | ||||
sc->dpm_flush_entry[entry_num] = 0; | sc->dpm_flush_entry[entry_num] = 0; | ||||
dpm_entry->MappingInformation = le16toh(dpm_entry-> | dpm_entry->MappingInformation = le16toh(dpm_entry-> | ||||
MappingInformation); | MappingInformation); | ||||
dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex); | dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex); | ||||
dpm_entry->PhysicalBitsMapping = le32toh(dpm_entry-> | dpm_entry->PhysicalBitsMapping = le32toh(dpm_entry-> | ||||
PhysicalBitsMapping); | PhysicalBitsMapping); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | mpr_mapping_free_memory(struct mpr_softc *sc) | ||||
free(sc->mapping_table, M_MPR); | free(sc->mapping_table, M_MPR); | ||||
free(sc->removal_table, M_MPR); | free(sc->removal_table, M_MPR); | ||||
free(sc->enclosure_table, M_MPR); | free(sc->enclosure_table, M_MPR); | ||||
free(sc->dpm_entry_used, M_MPR); | free(sc->dpm_entry_used, M_MPR); | ||||
free(sc->dpm_flush_entry, M_MPR); | free(sc->dpm_flush_entry, M_MPR); | ||||
free(sc->dpm_pg0, M_MPR); | free(sc->dpm_pg0, M_MPR); | ||||
} | } | ||||
static void | static void | ||||
_mapping_process_dpm_pg0(struct mpr_softc *sc) | _mapping_process_dpm_pg0(struct mpr_softc *sc) | ||||
{ | { | ||||
u8 missing_cnt, enc_idx; | u8 missing_cnt, enc_idx; | ||||
u16 slot_id, entry_num, num_slots; | u16 slot_id, entry_num, num_slots; | ||||
u32 map_idx, dev_idx, start_idx, end_idx; | u32 map_idx, dev_idx, start_idx, end_idx; | ||||
struct dev_mapping_table *mt_entry; | struct dev_mapping_table *mt_entry; | ||||
Mpi2DriverMap0Entry_t *dpm_entry; | Mpi2DriverMap0Entry_t *dpm_entry; | ||||
u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); | u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); | ||||
u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs); | u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs); | ||||
struct enc_mapping_table *et_entry; | struct enc_mapping_table *et_entry; | ||||
u64 physical_id; | u64 physical_id; | ||||
u32 phy_bits = 0; | u32 phy_bits = 0; | ||||
/* | |||||
* start_idx and end_idx are only used for IR. | |||||
*/ | |||||
if (sc->ir_firmware) | if (sc->ir_firmware) | ||||
_mapping_get_ir_maprange(sc, &start_idx, &end_idx); | _mapping_get_ir_maprange(sc, &start_idx, &end_idx); | ||||
/* | |||||
* Look through all of the DPM entries that were read from the | |||||
* controller and copy them over to the driver's internal table if they | |||||
* have a non-zero ID. At this point, any ID with a value of 0 would be | |||||
* invalid, so don't copy it. | |||||
*/ | |||||
mpr_dprint(sc, MPR_MAPPING, "%s: Start copy of %d DPM entries into the " | |||||
"mapping table.\n", __func__, sc->max_dpm_entries); | |||||
dpm_entry = (Mpi2DriverMap0Entry_t *) ((uint8_t *) sc->dpm_pg0 + | dpm_entry = (Mpi2DriverMap0Entry_t *) ((uint8_t *) sc->dpm_pg0 + | ||||
sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); | sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); | ||||
for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++, | for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++, | ||||
dpm_entry++) { | dpm_entry++) { | ||||
physical_id = dpm_entry->PhysicalIdentifier.High; | physical_id = dpm_entry->PhysicalIdentifier.High; | ||||
physical_id = (physical_id << 32) | | physical_id = (physical_id << 32) | | ||||
dpm_entry->PhysicalIdentifier.Low; | dpm_entry->PhysicalIdentifier.Low; | ||||
if (!physical_id) { | if (!physical_id) { | ||||
sc->dpm_entry_used[entry_num] = 0; | sc->dpm_entry_used[entry_num] = 0; | ||||
continue; | continue; | ||||
} | } | ||||
sc->dpm_entry_used[entry_num] = 1; | sc->dpm_entry_used[entry_num] = 1; | ||||
dpm_entry->MappingInformation = le16toh(dpm_entry-> | dpm_entry->MappingInformation = le16toh(dpm_entry-> | ||||
MappingInformation); | MappingInformation); | ||||
missing_cnt = dpm_entry->MappingInformation & | missing_cnt = dpm_entry->MappingInformation & | ||||
MPI2_DRVMAP0_MAPINFO_MISSING_MASK; | MPI2_DRVMAP0_MAPINFO_MISSING_MASK; | ||||
dev_idx = le16toh(dpm_entry->DeviceIndex); | dev_idx = le16toh(dpm_entry->DeviceIndex); | ||||
phy_bits = le32toh(dpm_entry->PhysicalBitsMapping); | phy_bits = le32toh(dpm_entry->PhysicalBitsMapping); | ||||
/* | |||||
* Volumes are at special locations in the mapping table so | |||||
* account for that. Volume mapping table entries do not depend | |||||
* on the type of mapping, so continue the loop after adding | |||||
* volumes to the mapping table. | |||||
*/ | |||||
if (sc->ir_firmware && (dev_idx >= start_idx) && | if (sc->ir_firmware && (dev_idx >= start_idx) && | ||||
(dev_idx <= end_idx)) { | (dev_idx <= end_idx)) { | ||||
mt_entry = &sc->mapping_table[dev_idx]; | mt_entry = &sc->mapping_table[dev_idx]; | ||||
mt_entry->physical_id = dpm_entry->PhysicalIdentifier.High; | mt_entry->physical_id = | ||||
dpm_entry->PhysicalIdentifier.High; | |||||
mt_entry->physical_id = (mt_entry->physical_id << 32) | | mt_entry->physical_id = (mt_entry->physical_id << 32) | | ||||
dpm_entry->PhysicalIdentifier.Low; | dpm_entry->PhysicalIdentifier.Low; | ||||
mt_entry->channel = MPR_RAID_CHANNEL; | |||||
mt_entry->id = dev_idx; | mt_entry->id = dev_idx; | ||||
mt_entry->missing_count = missing_cnt; | mt_entry->missing_count = missing_cnt; | ||||
mt_entry->dpm_entry_num = entry_num; | mt_entry->dpm_entry_num = entry_num; | ||||
mt_entry->device_info = MPR_DEV_RESERVED; | mt_entry->device_info = MPR_DEV_RESERVED; | ||||
continue; | continue; | ||||
} | } | ||||
if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | ||||
MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { | MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { | ||||
/* | |||||
* The dev_idx for an enclosure is the start index. If | |||||
* the start index is within the controller's default | |||||
* enclosure area, set the number of slots for this | |||||
* enclosure to the max allowed. Otherwise, it should be | |||||
* a normal enclosure and the number of slots is in the | |||||
* DPM entry's Mapping Information. | |||||
*/ | |||||
if (dev_idx < (sc->num_rsvd_entries + | if (dev_idx < (sc->num_rsvd_entries + | ||||
max_num_phy_ids)) { | max_num_phy_ids)) { | ||||
slot_id = 0; | slot_id = 0; | ||||
if (ioc_pg8_flags & | if (ioc_pg8_flags & | ||||
MPI2_IOCPAGE8_FLAGS_DA_START_SLOT_1) | MPI2_IOCPAGE8_FLAGS_DA_START_SLOT_1) | ||||
slot_id = 1; | slot_id = 1; | ||||
num_slots = max_num_phy_ids; | num_slots = max_num_phy_ids; | ||||
} else { | } else { | ||||
slot_id = 0; | slot_id = 0; | ||||
num_slots = dpm_entry->MappingInformation & | num_slots = dpm_entry->MappingInformation & | ||||
MPI2_DRVMAP0_MAPINFO_SLOT_MASK; | MPI2_DRVMAP0_MAPINFO_SLOT_MASK; | ||||
num_slots >>= MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT; | num_slots >>= MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT; | ||||
} | } | ||||
enc_idx = sc->num_enc_table_entries; | enc_idx = sc->num_enc_table_entries; | ||||
if (enc_idx >= sc->max_enclosures) { | if (enc_idx >= sc->max_enclosures) { | ||||
printf("%s: enclosure entries exceed max " | mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: " | ||||
"enclosures of %d\n", __func__, | "Number of enclosure entries in DPM exceed " | ||||
"the max allowed of %d.\n", __func__, | |||||
sc->max_enclosures); | sc->max_enclosures); | ||||
break; | break; | ||||
} | } | ||||
sc->num_enc_table_entries++; | sc->num_enc_table_entries++; | ||||
et_entry = &sc->enclosure_table[enc_idx]; | et_entry = &sc->enclosure_table[enc_idx]; | ||||
physical_id = dpm_entry->PhysicalIdentifier.High; | physical_id = dpm_entry->PhysicalIdentifier.High; | ||||
et_entry->enclosure_id = (physical_id << 32) | | et_entry->enclosure_id = (physical_id << 32) | | ||||
dpm_entry->PhysicalIdentifier.Low; | dpm_entry->PhysicalIdentifier.Low; | ||||
et_entry->start_index = dev_idx; | et_entry->start_index = dev_idx; | ||||
et_entry->dpm_entry_num = entry_num; | et_entry->dpm_entry_num = entry_num; | ||||
et_entry->num_slots = num_slots; | et_entry->num_slots = num_slots; | ||||
et_entry->start_slot = slot_id; | et_entry->start_slot = slot_id; | ||||
et_entry->missing_count = missing_cnt; | et_entry->missing_count = missing_cnt; | ||||
et_entry->phy_bits = phy_bits; | et_entry->phy_bits = phy_bits; | ||||
/* | |||||
* Initialize all entries for this enclosure in the | |||||
* mapping table and mark them as reserved. The actual | |||||
* devices have not been processed yet but when they are | |||||
* they will use these entries. If an entry is found | |||||
* that already has a valid DPM index, the mapping table | |||||
* is corrupt. This can happen if the mapping type is | |||||
* changed without clearing all of the DPM entries in | |||||
* the controller. | |||||
*/ | |||||
mt_entry = &sc->mapping_table[dev_idx]; | mt_entry = &sc->mapping_table[dev_idx]; | ||||
for (map_idx = dev_idx; map_idx < (dev_idx + num_slots); | for (map_idx = dev_idx; map_idx < (dev_idx + num_slots); | ||||
map_idx++, mt_entry++) { | map_idx++, mt_entry++) { | ||||
if (mt_entry->dpm_entry_num != | if (mt_entry->dpm_entry_num != | ||||
MPR_DPM_BAD_IDX) { | MPR_DPM_BAD_IDX) { | ||||
printf("%s: conflict in mapping table " | mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, | ||||
"for enclosure %d\n", __func__, | "%s: Conflict in mapping table for " | ||||
" enclosure %d\n", __func__, | |||||
enc_idx); | enc_idx); | ||||
break; | break; | ||||
} | } | ||||
physical_id = dpm_entry->PhysicalIdentifier.High; | physical_id = | ||||
dpm_entry->PhysicalIdentifier.High; | |||||
mt_entry->physical_id = (physical_id << 32) | | mt_entry->physical_id = (physical_id << 32) | | ||||
dpm_entry->PhysicalIdentifier.Low; | dpm_entry->PhysicalIdentifier.Low; | ||||
mt_entry->phy_bits = phy_bits; | mt_entry->phy_bits = phy_bits; | ||||
mt_entry->channel = 0; | |||||
mt_entry->id = dev_idx; | mt_entry->id = dev_idx; | ||||
mt_entry->dpm_entry_num = entry_num; | mt_entry->dpm_entry_num = entry_num; | ||||
mt_entry->missing_count = missing_cnt; | mt_entry->missing_count = missing_cnt; | ||||
mt_entry->device_info = MPR_DEV_RESERVED; | mt_entry->device_info = MPR_DEV_RESERVED; | ||||
} | } | ||||
} else if ((ioc_pg8_flags & | } else if ((ioc_pg8_flags & | ||||
MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | ||||
MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) { | MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) { | ||||
/* | |||||
* Device mapping, so simply copy the DPM entries to the | |||||
* mapping table, but check for a corrupt mapping table | |||||
* (as described above in Enc/Slot mapping). | |||||
*/ | |||||
map_idx = dev_idx; | map_idx = dev_idx; | ||||
mt_entry = &sc->mapping_table[map_idx]; | mt_entry = &sc->mapping_table[map_idx]; | ||||
if (mt_entry->dpm_entry_num != MPR_DPM_BAD_IDX) { | if (mt_entry->dpm_entry_num != MPR_DPM_BAD_IDX) { | ||||
printf("%s: conflict in mapping table for " | mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: " | ||||
"device %d\n", __func__, map_idx); | "Conflict in mapping table for device %d\n", | ||||
__func__, map_idx); | |||||
break; | break; | ||||
} | } | ||||
physical_id = dpm_entry->PhysicalIdentifier.High; | physical_id = dpm_entry->PhysicalIdentifier.High; | ||||
mt_entry->physical_id = (physical_id << 32) | | mt_entry->physical_id = (physical_id << 32) | | ||||
dpm_entry->PhysicalIdentifier.Low; | dpm_entry->PhysicalIdentifier.Low; | ||||
mt_entry->phy_bits = phy_bits; | mt_entry->phy_bits = phy_bits; | ||||
mt_entry->channel = 0; | |||||
mt_entry->id = dev_idx; | mt_entry->id = dev_idx; | ||||
mt_entry->missing_count = missing_cnt; | mt_entry->missing_count = missing_cnt; | ||||
mt_entry->dpm_entry_num = entry_num; | mt_entry->dpm_entry_num = entry_num; | ||||
mt_entry->device_info = MPR_DEV_RESERVED; | mt_entry->device_info = MPR_DEV_RESERVED; | ||||
} | } | ||||
} /*close the loop for DPM table */ | } /*close the loop for DPM table */ | ||||
} | } | ||||
/* | /* | ||||
* mpr_mapping_check_devices - start of the day check for device availabilty | * mpr_mapping_check_devices - start of the day check for device availabilty | ||||
* @sc: per adapter object | * @sc: per adapter object | ||||
* @sleep_flag: Flag indicating whether this function can sleep or not | |||||
* | * | ||||
* Returns nothing. | * Returns nothing. | ||||
*/ | */ | ||||
void | void | ||||
mpr_mapping_check_devices(struct mpr_softc *sc, int sleep_flag) | mpr_mapping_check_devices(void *data) | ||||
{ | { | ||||
u32 i; | u32 i; | ||||
/* u32 cntdn, i; | |||||
u32 timeout = 60;*/ | |||||
struct dev_mapping_table *mt_entry; | struct dev_mapping_table *mt_entry; | ||||
struct mpr_softc *sc = (struct mpr_softc *)data; | |||||
u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); | u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags); | ||||
struct enc_mapping_table *et_entry; | struct enc_mapping_table *et_entry; | ||||
u32 start_idx, end_idx; | u32 start_idx = 0, end_idx = 0; | ||||
u8 stop_device_checks = 0; | |||||
/* We need to ucomment this when this function is called | MPR_FUNCTRACE(sc); | ||||
* from the port enable complete */ | |||||
#if 0 | /* | ||||
* Clear this flag so that this function is never called again except | |||||
* within this function if the check needs to be done again. The | |||||
* purpose is to check for missing devices that are currently in the | |||||
* mapping table so do this only at driver init after discovery. | |||||
*/ | |||||
sc->track_mapping_events = 0; | sc->track_mapping_events = 0; | ||||
cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; | |||||
do { | |||||
if (!sc->pending_map_events) | |||||
break; | |||||
if (sleep_flag == CAN_SLEEP) | |||||
pause("mpr_pause", (hz/1000));/* 1msec sleep */ | |||||
else | |||||
DELAY(500); /* 500 useconds delay */ | |||||
} while (--cntdn); | |||||
/* | |||||
* callout synchronization | |||||
* This is used to prevent race conditions for the callout. | |||||
*/ | |||||
mpr_dprint(sc, MPR_MAPPING, "%s: Start check for missing devices.\n", | |||||
__func__); | |||||
mtx_assert(&sc->mpr_mtx, MA_OWNED); | |||||
if ((callout_pending(&sc->device_check_callout)) || | |||||
(!callout_active(&sc->device_check_callout))) { | |||||
mpr_dprint(sc, MPR_MAPPING, "%s: Device Check Callout is " | |||||
"already pending or not active.\n", __func__); | |||||
return; | |||||
} | |||||
callout_deactivate(&sc->device_check_callout); | |||||
if (!cntdn) | /* | ||||
printf("%s: there are %d" | * Use callout to check if any devices in the mapping table have been | ||||
" pending events after %d seconds of delay\n", | * processed yet. If ALL devices are marked as not init_complete, no | ||||
__func__, sc->pending_map_events, timeout); | * devices have been processed and mapped. Until devices are mapped | ||||
#endif | * there's no reason to mark them as missing. Continue resetting this | ||||
sc->pending_map_events = 0; | * callout until devices have been mapped. | ||||
*/ | |||||
if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | |||||
MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { | |||||
et_entry = sc->enclosure_table; | |||||
for (i = 0; i < sc->num_enc_table_entries; i++, et_entry++) { | |||||
if (et_entry->init_complete) { | |||||
stop_device_checks = 1; | |||||
break; | |||||
} | |||||
} | |||||
} else if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | |||||
MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) { | |||||
mt_entry = sc->mapping_table; | |||||
for (i = 0; i < sc->max_devices; i++, mt_entry++) { | |||||
if (mt_entry->init_complete) { | |||||
stop_device_checks = 1; | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
/* | |||||
* Setup another callout check after a delay. Keep doing this until | |||||
* devices are mapped. | |||||
*/ | |||||
if (!stop_device_checks) { | |||||
mpr_dprint(sc, MPR_MAPPING, "%s: No devices have been mapped. " | |||||
"Reset callout to check again after a %d second delay.\n", | |||||
__func__, MPR_MISSING_CHECK_DELAY); | |||||
callout_reset(&sc->device_check_callout, | |||||
MPR_MISSING_CHECK_DELAY * hz, mpr_mapping_check_devices, | |||||
sc); | |||||
return; | |||||
} | |||||
mpr_dprint(sc, MPR_MAPPING, "%s: Device check complete.\n", __func__); | |||||
/* | |||||
* Depending on the mapping type, check if devices have been processed | |||||
* and update their missing counts if not processed. | |||||
*/ | |||||
if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | ||||
MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { | MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) { | ||||
et_entry = sc->enclosure_table; | et_entry = sc->enclosure_table; | ||||
for (i = 0; i < sc->num_enc_table_entries; i++, et_entry++) { | for (i = 0; i < sc->num_enc_table_entries; i++, et_entry++) { | ||||
if (!et_entry->init_complete) { | if (!et_entry->init_complete) { | ||||
if (et_entry->missing_count < | if (et_entry->missing_count < | ||||
MPR_MAX_MISSING_COUNT) { | MPR_MAX_MISSING_COUNT) { | ||||
mpr_dprint(sc, MPR_MAPPING, "%s: " | |||||
"Enclosure %d is missing from the " | |||||
"topology. Update its missing " | |||||
"count.\n", __func__, i); | |||||
et_entry->missing_count++; | et_entry->missing_count++; | ||||
if (et_entry->dpm_entry_num != | if (et_entry->dpm_entry_num != | ||||
MPR_DPM_BAD_IDX) | MPR_DPM_BAD_IDX) { | ||||
_mapping_commit_enc_entry(sc, | _mapping_commit_enc_entry(sc, | ||||
et_entry); | et_entry); | ||||
} | } | ||||
} | |||||
et_entry->init_complete = 1; | et_entry->init_complete = 1; | ||||
} | } | ||||
} | } | ||||
if (!sc->ir_firmware) | if (!sc->ir_firmware) | ||||
return; | return; | ||||
_mapping_get_ir_maprange(sc, &start_idx, &end_idx); | _mapping_get_ir_maprange(sc, &start_idx, &end_idx); | ||||
mt_entry = &sc->mapping_table[start_idx]; | mt_entry = &sc->mapping_table[start_idx]; | ||||
for (i = start_idx; i < (end_idx + 1); i++, mt_entry++) { | |||||
if (mt_entry->device_info & MPR_DEV_RESERVED | |||||
&& !mt_entry->physical_id) | |||||
mt_entry->init_complete = 1; | |||||
else if (mt_entry->device_info & MPR_DEV_RESERVED) { | |||||
if (!mt_entry->init_complete) { | |||||
if (mt_entry->missing_count < | |||||
MPR_MAX_MISSING_COUNT) { | |||||
mt_entry->missing_count++; | |||||
if (mt_entry->dpm_entry_num != | |||||
MPR_DPM_BAD_IDX) | |||||
_mapping_commit_map_entry(sc, | |||||
mt_entry); | |||||
} | |||||
mt_entry->init_complete = 1; | |||||
} | |||||
} | |||||
} | |||||
} else if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | } else if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) == | ||||
MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) { | MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) { | ||||
start_idx = 0; | |||||
end_idx = sc->max_devices - 1; | |||||
mt_entry = sc->mapping_table; | mt_entry = sc->mapping_table; | ||||
for (i = 0; i < sc->max_devices; i++, mt_entry++) { | } | ||||
/* | |||||
* The start and end indices have been set above according to the | |||||
* mapping type. Go through these mappings and update any entries that | |||||
* do not have the init_complete flag set, which means they are missing. | |||||
*/ | |||||
if (end_idx == 0) | |||||
return; | |||||
for (i = start_idx; i < (end_idx + 1); i++, mt_entry++) { | |||||
if (mt_entry->device_info & MPR_DEV_RESERVED | if (mt_entry->device_info & MPR_DEV_RESERVED | ||||
&& !mt_entry->physical_id) | && !mt_entry->physical_id) | ||||
mt_entry->init_complete = 1; | mt_entry->init_complete = 1; | ||||
else if (mt_entry->device_info & MPR_DEV_RESERVED) { | else if (mt_entry->device_info & MPR_DEV_RESERVED) { | ||||
if (!mt_entry->init_complete) { | if (!mt_entry->init_complete) { | ||||
mpr_dprint(sc, MPR_MAPPING, "%s: Device in " | |||||
"mapping table at index %d is missing from " | |||||
"topology. Update its missing count.\n", | |||||
__func__, i); | |||||
if (mt_entry->missing_count < | if (mt_entry->missing_count < | ||||
MPR_MAX_MISSING_COUNT) { | MPR_MAX_MISSING_COUNT) { | ||||
mt_entry->missing_count++; | mt_entry->missing_count++; | ||||
if (mt_entry->dpm_entry_num != | if (mt_entry->dpm_entry_num != | ||||
MPR_DPM_BAD_IDX) | MPR_DPM_BAD_IDX) { | ||||
_mapping_commit_map_entry(sc, | _mapping_commit_map_entry(sc, | ||||
mt_entry); | mt_entry); | ||||
} | } | ||||
} | |||||
mt_entry->init_complete = 1; | mt_entry->init_complete = 1; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | |||||
/** | /** | ||||
* mpr_mapping_is_reinit_required - check whether event replay required | |||||
* @sc: per adapter object | |||||
* | |||||
* Checks the per ioc flags and decide whether reinit of events required | |||||
* | |||||
* Returns 1 for reinit of ioc 0 for not. | |||||
*/ | |||||
int mpr_mapping_is_reinit_required(struct mpr_softc *sc) | |||||
{ | |||||
if (!sc->mt_full_retry && sc->mt_add_device_failed) { | |||||
sc->mt_full_retry = 1; | |||||
sc->mt_add_device_failed = 0; | |||||
_mapping_flush_dpm_pages(sc); | |||||
return 1; | |||||
} | |||||
sc->mt_full_retry = 1; | |||||
return 0; | |||||
} | |||||
/** | |||||
* mpr_mapping_initialize - initialize mapping tables | * mpr_mapping_initialize - initialize mapping tables | ||||
* @sc: per adapter object | * @sc: per adapter object | ||||
* | * | ||||
* Read controller persitant mapping tables into internal data area. | * Read controller persitant mapping tables into internal data area. | ||||
* | * | ||||
* Return 0 for success or non-zero for failure. | * Return 0 for success or non-zero for failure. | ||||
*/ | */ | ||||
int | int | ||||
Show All 11 Lines | mpr_mapping_initialize(struct mpr_softc *sc) | ||||
*/ | */ | ||||
sc->max_enclosures = sc->facts->MaxEnclosures + 1; | sc->max_enclosures = sc->facts->MaxEnclosures + 1; | ||||
sc->max_expanders = sc->facts->MaxSasExpanders; | sc->max_expanders = sc->facts->MaxSasExpanders; | ||||
sc->max_volumes = sc->facts->MaxVolumes; | sc->max_volumes = sc->facts->MaxVolumes; | ||||
sc->max_devices = sc->facts->MaxTargets + sc->max_volumes; | sc->max_devices = sc->facts->MaxTargets + sc->max_volumes; | ||||
sc->pending_map_events = 0; | sc->pending_map_events = 0; | ||||
sc->num_enc_table_entries = 0; | sc->num_enc_table_entries = 0; | ||||
sc->num_rsvd_entries = 0; | sc->num_rsvd_entries = 0; | ||||
sc->num_channels = 1; | |||||
sc->max_dpm_entries = sc->ioc_pg8.MaxPersistentEntries; | sc->max_dpm_entries = sc->ioc_pg8.MaxPersistentEntries; | ||||
sc->is_dpm_enable = (sc->max_dpm_entries) ? 1 : 0; | sc->is_dpm_enable = (sc->max_dpm_entries) ? 1 : 0; | ||||
sc->track_mapping_events = 0; | sc->track_mapping_events = 0; | ||||
mpr_dprint(sc, MPR_MAPPING, "%s: Mapping table has a max of %d entries " | |||||
"and DPM has a max of %d entries.\n", __func__, sc->max_devices, | |||||
sc->max_dpm_entries); | |||||
if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_DISABLE_PERSISTENT_MAPPING) | if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_DISABLE_PERSISTENT_MAPPING) | ||||
sc->is_dpm_enable = 0; | sc->is_dpm_enable = 0; | ||||
if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0) | if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0) | ||||
sc->num_rsvd_entries = 1; | sc->num_rsvd_entries = 1; | ||||
volume_mapping_flags = sc->ioc_pg8.IRVolumeMappingFlags & | volume_mapping_flags = sc->ioc_pg8.IRVolumeMappingFlags & | ||||
MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; | MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; | ||||
Show All 23 Lines | if (sc->is_dpm_enable) { | ||||
dpm_pg0_sz = sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER) + | dpm_pg0_sz = sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER) + | ||||
(sc->max_dpm_entries * | (sc->max_dpm_entries * | ||||
sizeof(MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY)); | sizeof(MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY)); | ||||
retry_count = 0; | retry_count = 0; | ||||
retry_read_dpm: | retry_read_dpm: | ||||
if (mpr_config_get_dpm_pg0(sc, &mpi_reply, sc->dpm_pg0, | if (mpr_config_get_dpm_pg0(sc, &mpi_reply, sc->dpm_pg0, | ||||
dpm_pg0_sz)) { | dpm_pg0_sz)) { | ||||
printf("%s: dpm page read failed; disabling dpm\n", | mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: DPM page " | ||||
__func__); | "read failed.\n", __func__); | ||||
if (retry_count < 3) { | if (retry_count < 3) { | ||||
retry_count++; | retry_count++; | ||||
goto retry_read_dpm; | goto retry_read_dpm; | ||||
} | } | ||||
sc->is_dpm_enable = 0; | sc->is_dpm_enable = 0; | ||||
} | } | ||||
} | } | ||||
if (sc->is_dpm_enable) | if (sc->is_dpm_enable) | ||||
_mapping_process_dpm_pg0(sc); | _mapping_process_dpm_pg0(sc); | ||||
else { | |||||
mpr_dprint(sc, MPR_MAPPING, "%s: DPM processing is disabled. " | |||||
"Device mappings will not persist across reboots or " | |||||
"resets.\n", __func__); | |||||
} | |||||
sc->track_mapping_events = 1; | sc->track_mapping_events = 1; | ||||
return 0; | return 0; | ||||
} | } | ||||
/** | /** | ||||
* mpr_mapping_exit - clear mapping table and associated memory | * mpr_mapping_exit - clear mapping table and associated memory | ||||
* @sc: per adapter object | * @sc: per adapter object | ||||
* | * | ||||
* Returns nothing. | * Returns nothing. | ||||
*/ | */ | ||||
void | void | ||||
mpr_mapping_exit(struct mpr_softc *sc) | mpr_mapping_exit(struct mpr_softc *sc) | ||||
{ | { | ||||
_mapping_flush_dpm_pages(sc); | _mapping_flush_dpm_pages(sc); | ||||
mpr_mapping_free_memory(sc); | mpr_mapping_free_memory(sc); | ||||
} | } | ||||
/** | /** | ||||
* mpr_mapping_get_sas_id - assign a target id for sas device | * mpr_mapping_get_tid - return the target id for sas device and handle | ||||
* @sc: per adapter object | * @sc: per adapter object | ||||
* @sas_address: sas address of the device | * @sas_address: sas address of the device | ||||
* @handle: device handle | * @handle: device handle | ||||
* | * | ||||
* Returns valid ID on success or BAD_ID. | * Returns valid target ID on success or BAD_ID. | ||||
*/ | */ | ||||
unsigned int | unsigned int | ||||
mpr_mapping_get_sas_id(struct mpr_softc *sc, uint64_t sas_address, u16 handle) | mpr_mapping_get_tid(struct mpr_softc *sc, uint64_t sas_address, u16 handle) | ||||
{ | { | ||||
u32 map_idx; | u32 map_idx; | ||||
struct dev_mapping_table *mt_entry; | struct dev_mapping_table *mt_entry; | ||||
for (map_idx = 0; map_idx < sc->max_devices; map_idx++) { | for (map_idx = 0; map_idx < sc->max_devices; map_idx++) { | ||||
mt_entry = &sc->mapping_table[map_idx]; | mt_entry = &sc->mapping_table[map_idx]; | ||||
if (mt_entry->dev_handle == handle && mt_entry->physical_id == | if (mt_entry->dev_handle == handle && mt_entry->physical_id == | ||||
sas_address) | sas_address) | ||||
return mt_entry->id; | return mt_entry->id; | ||||
} | } | ||||
return MPR_MAP_BAD_ID; | return MPR_MAP_BAD_ID; | ||||
} | } | ||||
/** | /** | ||||
* mpr_mapping_get_sas_id_from_handle - find a target id in mapping table using | * mpr_mapping_get_tid_from_handle - find a target id in mapping table using | ||||
* only the dev handle. This is just a wrapper function for the local function | * only the dev handle. This is just a wrapper function for the local function | ||||
* _mapping_get_mt_idx_from_handle. | * _mapping_get_mt_idx_from_handle. | ||||
* @sc: per adapter object | * @sc: per adapter object | ||||
* @handle: device handle | * @handle: device handle | ||||
* | * | ||||
* Returns valid ID on success or BAD_ID. | * Returns valid target ID on success or BAD_ID. | ||||
*/ | */ | ||||
unsigned int | unsigned int | ||||
mpr_mapping_get_sas_id_from_handle(struct mpr_softc *sc, u16 handle) | mpr_mapping_get_tid_from_handle(struct mpr_softc *sc, u16 handle) | ||||
{ | { | ||||
return (_mapping_get_mt_idx_from_handle(sc, handle)); | return (_mapping_get_mt_idx_from_handle(sc, handle)); | ||||
} | } | ||||
/** | /** | ||||
* mpr_mapping_get_raid_id - assign a target id for raid device | * mpr_mapping_get_raid_tid - return the target id for raid device | ||||
* @sc: per adapter object | * @sc: per adapter object | ||||
* @wwid: world wide identifier for raid volume | * @wwid: world wide identifier for raid volume | ||||
* @handle: device handle | * @volHandle: volume device handle | ||||
* | * | ||||
* Returns valid ID on success or BAD_ID. | * Returns valid target ID on success or BAD_ID. | ||||
*/ | */ | ||||
unsigned int | unsigned int | ||||
mpr_mapping_get_raid_id(struct mpr_softc *sc, u64 wwid, u16 handle) | mpr_mapping_get_raid_tid(struct mpr_softc *sc, u64 wwid, u16 volHandle) | ||||
{ | { | ||||
u32 map_idx; | u32 start_idx, end_idx, map_idx; | ||||
struct dev_mapping_table *mt_entry; | struct dev_mapping_table *mt_entry; | ||||
for (map_idx = 0; map_idx < sc->max_devices; map_idx++) { | _mapping_get_ir_maprange(sc, &start_idx, &end_idx); | ||||
mt_entry = &sc->mapping_table[map_idx]; | mt_entry = &sc->mapping_table[start_idx]; | ||||
if (mt_entry->dev_handle == handle && mt_entry->physical_id == | for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++) { | ||||
wwid) | if (mt_entry->dev_handle == volHandle && | ||||
mt_entry->physical_id == wwid) | |||||
return mt_entry->id; | return mt_entry->id; | ||||
} | } | ||||
return MPR_MAP_BAD_ID; | return MPR_MAP_BAD_ID; | ||||
} | } | ||||
/** | /** | ||||
* mpr_mapping_get_raid_id_from_handle - find raid device in mapping table | * mpr_mapping_get_raid_tid_from_handle - find raid device in mapping table | ||||
* using only the volume dev handle. This is just a wrapper function for the | * using only the volume dev handle. This is just a wrapper function for the | ||||
* local function _mapping_get_ir_mt_idx_from_handle. | * local function _mapping_get_ir_mt_idx_from_handle. | ||||
* @sc: per adapter object | * @sc: per adapter object | ||||
* @volHandle: volume device handle | * @volHandle: volume device handle | ||||
* | * | ||||
* Returns valid ID on success or BAD_ID. | * Returns valid target ID on success or BAD_ID. | ||||
*/ | */ | ||||
unsigned int | unsigned int | ||||
mpr_mapping_get_raid_id_from_handle(struct mpr_softc *sc, u16 volHandle) | mpr_mapping_get_raid_tid_from_handle(struct mpr_softc *sc, u16 volHandle) | ||||
{ | { | ||||
return (_mapping_get_ir_mt_idx_from_handle(sc, volHandle)); | return (_mapping_get_ir_mt_idx_from_handle(sc, volHandle)); | ||||
} | } | ||||
/** | /** | ||||
* mpr_mapping_enclosure_dev_status_change_event - handle enclosure events | * mpr_mapping_enclosure_dev_status_change_event - handle enclosure events | ||||
* @sc: per adapter object | * @sc: per adapter object | ||||
* @event_data: event data payload | * @event_data: event data payload | ||||
Show All 17 Lines | if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) != | ||||
MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) | MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) | ||||
goto out; | goto out; | ||||
dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 + | dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 + | ||||
sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); | sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER)); | ||||
if (event_data->ReasonCode == MPI2_EVENT_SAS_ENCL_RC_ADDED) { | if (event_data->ReasonCode == MPI2_EVENT_SAS_ENCL_RC_ADDED) { | ||||
if (!event_data->NumSlots) { | if (!event_data->NumSlots) { | ||||
printf("%s: enclosure with handle = 0x%x reported 0 " | mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: Enclosure " | ||||
"slots\n", __func__, | "with handle = 0x%x reported 0 slots.\n", __func__, | ||||
le16toh(event_data->EnclosureHandle)); | le16toh(event_data->EnclosureHandle)); | ||||
goto out; | goto out; | ||||
} | } | ||||
temp64_var = event_data->EnclosureLogicalID.High; | temp64_var = event_data->EnclosureLogicalID.High; | ||||
temp64_var = (temp64_var << 32) | | temp64_var = (temp64_var << 32) | | ||||
event_data->EnclosureLogicalID.Low; | event_data->EnclosureLogicalID.Low; | ||||
enc_idx = _mapping_get_enc_idx_from_id(sc, temp64_var, | enc_idx = _mapping_get_enc_idx_from_id(sc, temp64_var, | ||||
event_data->PhyBits); | event_data->PhyBits); | ||||
/* | |||||
* If the Added enclosure is already in the Enclosure Table, | |||||
* make sure that all the the enclosure info is up to date. If | |||||
* the enclosure was missing and has just been added back, or if | |||||
* the enclosure's Phy Bits have changed, clear the missing | |||||
* count and update the Phy Bits in the mapping table and in the | |||||
* DPM, if it's being used. | |||||
*/ | |||||
if (enc_idx != MPR_ENCTABLE_BAD_IDX) { | if (enc_idx != MPR_ENCTABLE_BAD_IDX) { | ||||
et_entry = &sc->enclosure_table[enc_idx]; | et_entry = &sc->enclosure_table[enc_idx]; | ||||
if (et_entry->init_complete && | if (et_entry->init_complete && | ||||
!et_entry->missing_count) { | !et_entry->missing_count) { | ||||
printf("%s: enclosure %d is already present " | mpr_dprint(sc, MPR_MAPPING, "%s: Enclosure %d " | ||||
"with handle = 0x%x\n",__func__, enc_idx, | "is already present with handle = 0x%x\n", | ||||
et_entry->enc_handle); | __func__, enc_idx, et_entry->enc_handle); | ||||
goto out; | goto out; | ||||
} | } | ||||
et_entry->enc_handle = le16toh(event_data-> | et_entry->enc_handle = le16toh(event_data-> | ||||
EnclosureHandle); | EnclosureHandle); | ||||
et_entry->start_slot = le16toh(event_data->StartSlot); | et_entry->start_slot = le16toh(event_data->StartSlot); | ||||
saved_phy_bits = et_entry->phy_bits; | saved_phy_bits = et_entry->phy_bits; | ||||
et_entry->phy_bits |= le32toh(event_data->PhyBits); | et_entry->phy_bits |= le32toh(event_data->PhyBits); | ||||
if (saved_phy_bits != et_entry->phy_bits) | if (saved_phy_bits != et_entry->phy_bits) | ||||
update_phy_bits = 1; | update_phy_bits = 1; | ||||
if (et_entry->missing_count || update_phy_bits) { | if (et_entry->missing_count || update_phy_bits) { | ||||
et_entry->missing_count = 0; | et_entry->missing_count = 0; | ||||
if (sc->is_dpm_enable && | if (sc->is_dpm_enable && | ||||
et_entry->dpm_entry_num != | et_entry->dpm_entry_num != | ||||
MPR_DPM_BAD_IDX) { | MPR_DPM_BAD_IDX) { | ||||
dpm_entry += et_entry->dpm_entry_num; | dpm_entry += et_entry->dpm_entry_num; | ||||
missing_count = | missing_count = | ||||
(u8)(dpm_entry->MappingInformation & | (u8)(dpm_entry->MappingInformation & | ||||
MPI2_DRVMAP0_MAPINFO_MISSING_MASK); | MPI2_DRVMAP0_MAPINFO_MISSING_MASK); | ||||
if (!et_entry->init_complete && ( | if (missing_count || update_phy_bits) { | ||||
missing_count || update_phy_bits)) { | |||||
dpm_entry->MappingInformation | dpm_entry->MappingInformation | ||||
= et_entry->num_slots; | = et_entry->num_slots; | ||||
dpm_entry->MappingInformation | dpm_entry->MappingInformation | ||||
<<= map_shift; | <<= map_shift; | ||||
dpm_entry->PhysicalBitsMapping | dpm_entry->PhysicalBitsMapping | ||||
= et_entry->phy_bits; | = et_entry->phy_bits; | ||||
sc->dpm_flush_entry[et_entry-> | sc->dpm_flush_entry[et_entry-> | ||||
dpm_entry_num] = 1; | dpm_entry_num] = 1; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
/* | |||||
* This is a new enclosure that is being added. | |||||
* Initialize the Enclosure Table entry. It will be | |||||
* finalized when a device is added for the enclosure | |||||
* and the enclosure has enough space in the Mapping | |||||
* Table to map its devices. | |||||
*/ | |||||
enc_idx = sc->num_enc_table_entries; | enc_idx = sc->num_enc_table_entries; | ||||
if (enc_idx >= sc->max_enclosures) { | if (enc_idx >= sc->max_enclosures) { | ||||
printf("%s: enclosure can not be added; " | mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: " | ||||
"mapping table is full\n", __func__); | "Enclosure cannot be added to mapping " | ||||
"table because it's full.\n", __func__); | |||||
goto out; | goto out; | ||||
} | } | ||||
sc->num_enc_table_entries++; | sc->num_enc_table_entries++; | ||||
et_entry = &sc->enclosure_table[enc_idx]; | et_entry = &sc->enclosure_table[enc_idx]; | ||||
et_entry->enc_handle = le16toh(event_data-> | et_entry->enc_handle = le16toh(event_data-> | ||||
EnclosureHandle); | EnclosureHandle); | ||||
et_entry->enclosure_id = event_data-> | et_entry->enclosure_id = le64toh(event_data-> | ||||
EnclosureLogicalID.High; | EnclosureLogicalID.High); | ||||
et_entry->enclosure_id = ( et_entry->enclosure_id << | et_entry->enclosure_id = | ||||
32) | event_data->EnclosureLogicalID.Low; | ((et_entry->enclosure_id << 32) | | ||||
le64toh(event_data->EnclosureLogicalID.Low)); | |||||
et_entry->start_index = MPR_MAPTABLE_BAD_IDX; | et_entry->start_index = MPR_MAPTABLE_BAD_IDX; | ||||
et_entry->dpm_entry_num = MPR_DPM_BAD_IDX; | et_entry->dpm_entry_num = MPR_DPM_BAD_IDX; | ||||
et_entry->num_slots = le16toh(event_data->NumSlots); | et_entry->num_slots = le16toh(event_data->NumSlots); | ||||
et_entry->start_slot = le16toh(event_data->StartSlot); | et_entry->start_slot = le16toh(event_data->StartSlot); | ||||
et_entry->phy_bits = le32toh(event_data->PhyBits); | et_entry->phy_bits = le32toh(event_data->PhyBits); | ||||
} | } | ||||
et_entry->init_complete = 1; | et_entry->init_complete = 1; | ||||
} else if (event_data->ReasonCode == | } else if (event_data->ReasonCode == | ||||
MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING) { | MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING) { | ||||
/* | |||||
* An enclosure was removed. Update its missing count and then | |||||
* update the DPM entry with the new missing count for the | |||||
* enclosure. | |||||
*/ | |||||
enc_idx = _mapping_get_enc_idx_from_handle(sc, | enc_idx = _mapping_get_enc_idx_from_handle(sc, | ||||
le16toh(event_data->EnclosureHandle)); | le16toh(event_data->EnclosureHandle)); | ||||
if (enc_idx == MPR_ENCTABLE_BAD_IDX) { | if (enc_idx == MPR_ENCTABLE_BAD_IDX) { | ||||
printf("%s: cannot unmap enclosure %d because it has " | mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: Cannot " | ||||
"already been deleted", __func__, enc_idx); | "unmap enclosure %d because it has already been " | ||||
"deleted.\n", __func__, enc_idx); | |||||
goto out; | goto out; | ||||
} | } | ||||
et_entry = &sc->enclosure_table[enc_idx]; | et_entry = &sc->enclosure_table[enc_idx]; | ||||
if (!et_entry->init_complete) { | |||||
if (et_entry->missing_count < MPR_MAX_MISSING_COUNT) | if (et_entry->missing_count < MPR_MAX_MISSING_COUNT) | ||||
et_entry->missing_count++; | et_entry->missing_count++; | ||||
else | if (sc->is_dpm_enable && | ||||
et_entry->init_complete = 1; | |||||
} | |||||
if (!et_entry->missing_count) | |||||
et_entry->missing_count++; | |||||
if (sc->is_dpm_enable && !et_entry->init_complete && | |||||
et_entry->dpm_entry_num != MPR_DPM_BAD_IDX) { | et_entry->dpm_entry_num != MPR_DPM_BAD_IDX) { | ||||
dpm_entry += et_entry->dpm_entry_num; | dpm_entry += et_entry->dpm_entry_num; | ||||
dpm_entry->MappingInformation = et_entry->num_slots; | dpm_entry->MappingInformation = et_entry->num_slots; | ||||
dpm_entry->MappingInformation <<= map_shift; | dpm_entry->MappingInformation <<= map_shift; | ||||
dpm_entry->MappingInformation |= | dpm_entry->MappingInformation |= | ||||
et_entry->missing_count; | et_entry->missing_count; | ||||
sc->dpm_flush_entry[et_entry->dpm_entry_num] = 1; | sc->dpm_flush_entry[et_entry->dpm_entry_num] = 1; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 103 Lines • ▼ Show 20 Lines | |||||
out: | out: | ||||
free(topo_change.port_details, M_MPR); | free(topo_change.port_details, M_MPR); | ||||
_mapping_flush_dpm_pages(sc); | _mapping_flush_dpm_pages(sc); | ||||
if (sc->pending_map_events) | if (sc->pending_map_events) | ||||
sc->pending_map_events--; | sc->pending_map_events--; | ||||
} | } | ||||
/** | /** | ||||
* _mapping_check_update_ir_mt_idx - Check and update IR map table index | |||||
* @sc: per adapter object | |||||
* @event_data: event data payload | |||||
* @evt_idx: current event index | |||||
* @map_idx: current index and the place holder for new map table index | |||||
* @wwid_table: world wide name for volumes in the element table | |||||
* | |||||
* pass through IR events and find whether any events matches and if so | |||||
* tries to find new index if not returns failure | |||||
* | |||||
* Returns 0 on success and 1 on failure | |||||
*/ | |||||
static int | |||||
_mapping_check_update_ir_mt_idx(struct mpr_softc *sc, | |||||
Mpi2EventDataIrConfigChangeList_t *event_data, int evt_idx, u32 *map_idx, | |||||
u64 *wwid_table) | |||||
{ | |||||
struct dev_mapping_table *mt_entry; | |||||
u32 st_idx, end_idx, mt_idx = *map_idx; | |||||
u8 match = 0; | |||||
Mpi2EventIrConfigElement_t *element; | |||||
u16 element_flags; | |||||
int i; | |||||
mt_entry = &sc->mapping_table[mt_idx]; | |||||
_mapping_get_ir_maprange(sc, &st_idx, &end_idx); | |||||
search_again: | |||||
match = 0; | |||||
for (i = evt_idx + 1; i < event_data->NumElements; i++) { | |||||
element = (Mpi2EventIrConfigElement_t *) | |||||
&event_data->ConfigElement[i]; | |||||
element_flags = le16toh(element->ElementFlags); | |||||
if ((element_flags & | |||||
MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK) != | |||||
MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT) | |||||
continue; | |||||
if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_ADDED || | |||||
element->ReasonCode == | |||||
MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED) { | |||||
if (mt_entry->physical_id == wwid_table[i]) { | |||||
match = 1; | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
if (match) { | |||||
do { | |||||
mt_idx++; | |||||
if (mt_idx > end_idx) | |||||
return 1; | |||||
mt_entry = &sc->mapping_table[mt_idx]; | |||||
} while (mt_entry->device_info & MPR_MAP_IN_USE); | |||||
goto search_again; | |||||
} | |||||
*map_idx = mt_idx; | |||||
return 0; | |||||
} | |||||
/** | |||||
* mpr_mapping_ir_config_change_event - handle IR config change list events | * mpr_mapping_ir_config_change_event - handle IR config change list events | ||||
* @sc: per adapter object | * @sc: per adapter object | ||||
* @event_data: event data payload | * @event_data: event data payload | ||||
* | * | ||||
* Returns nothing. | * Returns nothing. | ||||
*/ | */ | ||||
void | void | ||||
mpr_mapping_ir_config_change_event(struct mpr_softc *sc, | mpr_mapping_ir_config_change_event(struct mpr_softc *sc, | ||||
Mpi2EventDataIrConfigChangeList_t *event_data) | Mpi2EventDataIrConfigChangeList_t *event_data) | ||||
{ | { | ||||
Mpi2EventIrConfigElement_t *element; | Mpi2EventIrConfigElement_t *element; | ||||
int i; | int i; | ||||
u64 *wwid_table; | u64 *wwid_table; | ||||
u32 map_idx, flags; | u32 map_idx, flags; | ||||
struct dev_mapping_table *mt_entry; | struct dev_mapping_table *mt_entry; | ||||
u16 element_flags; | u16 element_flags; | ||||
u8 log_full_error = 0; | |||||
wwid_table = malloc(sizeof(u64) * event_data->NumElements, M_MPR, | wwid_table = malloc(sizeof(u64) * event_data->NumElements, M_MPR, | ||||
M_NOWAIT | M_ZERO); | M_NOWAIT | M_ZERO); | ||||
if (!wwid_table) | if (!wwid_table) | ||||
goto out; | goto out; | ||||
element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; | element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; | ||||
flags = le32toh(event_data->Flags); | flags = le32toh(event_data->Flags); | ||||
/* | |||||
* For volume changes, get the WWID for the volume and put it in a | |||||
* table to be used in the processing of the IR change event. | |||||
*/ | |||||
for (i = 0; i < event_data->NumElements; i++, element++) { | for (i = 0; i < event_data->NumElements; i++, element++) { | ||||
element_flags = le16toh(element->ElementFlags); | element_flags = le16toh(element->ElementFlags); | ||||
if ((element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_ADDED) && | if ((element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_ADDED) && | ||||
(element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_REMOVED) && | (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_REMOVED) && | ||||
(element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE) | (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE) | ||||
&& (element->ReasonCode != | && (element->ReasonCode != | ||||
MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED)) | MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED)) | ||||
continue; | continue; | ||||
if ((element_flags & | if ((element_flags & | ||||
MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK) == | MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK) == | ||||
MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT) { | MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT) { | ||||
mpr_config_get_volume_wwid(sc, | mpr_config_get_volume_wwid(sc, | ||||
le16toh(element->VolDevHandle), &wwid_table[i]); | le16toh(element->VolDevHandle), &wwid_table[i]); | ||||
map_idx = _mapping_get_ir_mt_idx_from_wwid(sc, | |||||
wwid_table[i]); | |||||
if (map_idx != MPR_MAPTABLE_BAD_IDX) { | |||||
mt_entry = &sc->mapping_table[map_idx]; | |||||
mt_entry->device_info |= MPR_MAP_IN_USE; | |||||
} | } | ||||
} | } | ||||
} | |||||
/* | |||||
* Check the ReasonCode for each element in the IR event and Add/Remove | |||||
* Volumes or Physical Disks of Volumes to/from the mapping table. Use | |||||
* the WWIDs gotten above in wwid_table. | |||||
*/ | |||||
if (flags == MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) | if (flags == MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) | ||||
goto out; | goto out; | ||||
else { | else { | ||||
element = (Mpi2EventIrConfigElement_t *)&event_data-> | element = (Mpi2EventIrConfigElement_t *)&event_data-> | ||||
ConfigElement[0]; | ConfigElement[0]; | ||||
for (i = 0; i < event_data->NumElements; i++, element++) { | for (i = 0; i < event_data->NumElements; i++, element++) { | ||||
if (element->ReasonCode == | if (element->ReasonCode == | ||||
MPI2_EVENT_IR_CHANGE_RC_ADDED || | MPI2_EVENT_IR_CHANGE_RC_ADDED || | ||||
element->ReasonCode == | element->ReasonCode == | ||||
MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED) { | MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED) { | ||||
map_idx = _mapping_get_ir_mt_idx_from_wwid | map_idx = _mapping_get_ir_mt_idx_from_wwid | ||||
(sc, wwid_table[i]); | (sc, wwid_table[i]); | ||||
if (map_idx != MPR_MAPTABLE_BAD_IDX) { | if (map_idx != MPR_MAPTABLE_BAD_IDX) { | ||||
/* | |||||
* The volume is already in the mapping | |||||
* table. Just update it's info. | |||||
*/ | |||||
mt_entry = &sc->mapping_table[map_idx]; | mt_entry = &sc->mapping_table[map_idx]; | ||||
mt_entry->channel = MPR_RAID_CHANNEL; | |||||
mt_entry->id = map_idx; | mt_entry->id = map_idx; | ||||
mt_entry->dev_handle = le16toh | mt_entry->dev_handle = le16toh | ||||
(element->VolDevHandle); | (element->VolDevHandle); | ||||
mt_entry->device_info = | mt_entry->device_info = | ||||
MPR_DEV_RESERVED | MPR_MAP_IN_USE; | MPR_DEV_RESERVED | MPR_MAP_IN_USE; | ||||
_mapping_update_ir_missing_cnt(sc, | _mapping_update_ir_missing_cnt(sc, | ||||
map_idx, element, wwid_table[i]); | map_idx, element, wwid_table[i]); | ||||
continue; | continue; | ||||
} | } | ||||
/* | |||||
* Volume is not in mapping table yet. Find a | |||||
* free entry in the mapping table at the | |||||
* volume mapping locations. If no entries are | |||||
* available, this is an error because it means | |||||
* there are more volumes than can be mapped | |||||
* and that should never happen for volumes. | |||||
*/ | |||||
map_idx = _mapping_get_free_ir_mt_idx(sc); | map_idx = _mapping_get_free_ir_mt_idx(sc); | ||||
if (map_idx == MPR_MAPTABLE_BAD_IDX) | if (map_idx == MPR_MAPTABLE_BAD_IDX) | ||||
log_full_error = 1; | { | ||||
else if (i < (event_data->NumElements - 1)) { | mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, | ||||
log_full_error = | "%s: failed to add the volume with " | ||||
_mapping_check_update_ir_mt_idx | "handle 0x%04x because there is no " | ||||
(sc, event_data, i, &map_idx, | "free space available in the " | ||||
wwid_table); | "mapping table\n", __func__, | ||||
} | le16toh(element->VolDevHandle)); | ||||
if (log_full_error) { | |||||
printf("%s: no space to add the RAID " | |||||
"volume with handle 0x%04x in " | |||||
"mapping table\n", __func__, le16toh | |||||
(element->VolDevHandle)); | |||||
continue; | continue; | ||||
} | } | ||||
mt_entry = &sc->mapping_table[map_idx]; | mt_entry = &sc->mapping_table[map_idx]; | ||||
mt_entry->physical_id = wwid_table[i]; | mt_entry->physical_id = wwid_table[i]; | ||||
mt_entry->channel = MPR_RAID_CHANNEL; | |||||
mt_entry->id = map_idx; | mt_entry->id = map_idx; | ||||
mt_entry->dev_handle = le16toh(element-> | mt_entry->dev_handle = le16toh(element-> | ||||
VolDevHandle); | VolDevHandle); | ||||
mt_entry->device_info = MPR_DEV_RESERVED | | mt_entry->device_info = MPR_DEV_RESERVED | | ||||
MPR_MAP_IN_USE; | MPR_MAP_IN_USE; | ||||
mt_entry->init_complete = 0; | |||||
_mapping_update_ir_missing_cnt(sc, map_idx, | _mapping_update_ir_missing_cnt(sc, map_idx, | ||||
element, wwid_table[i]); | element, wwid_table[i]); | ||||
} else if (element->ReasonCode == | } else if (element->ReasonCode == | ||||
MPI2_EVENT_IR_CHANGE_RC_REMOVED) { | MPI2_EVENT_IR_CHANGE_RC_REMOVED) { | ||||
map_idx = _mapping_get_ir_mt_idx_from_wwid(sc, | map_idx = _mapping_get_ir_mt_idx_from_wwid(sc, | ||||
wwid_table[i]); | wwid_table[i]); | ||||
if (map_idx == MPR_MAPTABLE_BAD_IDX) { | if (map_idx == MPR_MAPTABLE_BAD_IDX) { | ||||
printf("%s: failed to remove a volume " | mpr_dprint(sc, MPR_MAPPING,"%s: Failed " | ||||
"because it has already been " | "to remove a volume because it has " | ||||
"removed\n", __func__); | "already been removed.\n", | ||||
__func__); | |||||
continue; | continue; | ||||
} | } | ||||
_mapping_update_ir_missing_cnt(sc, map_idx, | _mapping_update_ir_missing_cnt(sc, map_idx, | ||||
element, wwid_table[i]); | element, wwid_table[i]); | ||||
} else if (element->ReasonCode == | } else if (element->ReasonCode == | ||||
MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED) { | MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED) { | ||||
map_idx = _mapping_get_mt_idx_from_handle(sc, | map_idx = _mapping_get_mt_idx_from_handle(sc, | ||||
le16toh(element->VolDevHandle)); | le16toh(element->VolDevHandle)); | ||||
if (map_idx == MPR_MAPTABLE_BAD_IDX) { | if (map_idx == MPR_MAPTABLE_BAD_IDX) { | ||||
printf("%s: failed to remove volume " | mpr_dprint(sc, MPR_MAPPING,"%s: Failed " | ||||
"with handle 0x%04x because it has " | "to remove volume with handle " | ||||
"already been removed\n", __func__, | "0x%04x because it has already " | ||||
"been removed.\n", __func__, | |||||
le16toh(element->VolDevHandle)); | le16toh(element->VolDevHandle)); | ||||
continue; | continue; | ||||
} | } | ||||
mt_entry = &sc->mapping_table[map_idx]; | mt_entry = &sc->mapping_table[map_idx]; | ||||
_mapping_update_ir_missing_cnt(sc, map_idx, | _mapping_update_ir_missing_cnt(sc, map_idx, | ||||
element, mt_entry->physical_id); | element, mt_entry->physical_id); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
out: | out: | ||||
_mapping_flush_dpm_pages(sc); | _mapping_flush_dpm_pages(sc); | ||||
free(wwid_table, M_MPR); | free(wwid_table, M_MPR); | ||||
if (sc->pending_map_events) | if (sc->pending_map_events) | ||||
sc->pending_map_events--; | sc->pending_map_events--; | ||||
} | } |