Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 25 May 2017 19:20:06 +0000 (UTC)
From:      Stephen McConnell <slm@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r318896 - in head: share/man/man4 sys/dev/mpr
Message-ID:  <201705251920.v4PJK6AL075430@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: slm
Date: Thu May 25 19:20:06 2017
New Revision: 318896
URL: https://svnweb.freebsd.org/changeset/base/318896

Log:
  Fix several problems with mapping code.
  
  Reviewed by:    ken, scottl, asomers, ambrisko, mav
  Approved by:	ken, mav
  MFC after:      1 week
  Differential Revision: https://reviews.freebsd.org/D10861

Modified:
  head/share/man/man4/mpr.4
  head/sys/dev/mpr/mpr.c
  head/sys/dev/mpr/mpr_mapping.c
  head/sys/dev/mpr/mpr_sas.c
  head/sys/dev/mpr/mpr_sas_lsi.c
  head/sys/dev/mpr/mpr_user.c
  head/sys/dev/mpr/mprvar.h

Modified: head/share/man/man4/mpr.4
==============================================================================
--- head/share/man/man4/mpr.4	Thu May 25 19:14:44 2017	(r318895)
+++ head/share/man/man4/mpr.4	Thu May 25 19:20:06 2017	(r318896)
@@ -1,8 +1,8 @@
 .\"
 .\" Copyright (c) 2010 Spectra Logic Corporation
 .\" Copyright (c) 2014 LSI Corp
-.\" Copyright (c) 2017 Avago Technologies
-.\" Copyright (c) 2017 Broadcom Ltd.
+.\" Copyright (c) 2015-2017 Avago Technologies
+.\" Copyright (c) 2015-2017 Broadcom Ltd.
 .\" All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
@@ -38,7 +38,7 @@
 .\" $Id$
 .\" $FreeBSD$
 .\"
-.Dd May 17, 2017
+.Dd May 25, 2017
 .Dt MPR 4
 .Os
 .Sh NAME

Modified: head/sys/dev/mpr/mpr.c
==============================================================================
--- head/sys/dev/mpr/mpr.c	Thu May 25 19:14:44 2017	(r318895)
+++ head/sys/dev/mpr/mpr.c	Thu May 25 19:20:06 2017	(r318896)
@@ -520,7 +520,8 @@ mpr_iocfacts_allocate(struct mpr_softc *
 	 */
 	if (reallocating) {
 		mpr_iocfacts_free(sc);
-		mprsas_realloc_targets(sc, saved_facts.MaxTargets);
+		mprsas_realloc_targets(sc, saved_facts.MaxTargets +
+		    saved_facts.MaxVolumes);
 	}
 
 	/*
@@ -1663,6 +1664,7 @@ mpr_attach(struct mpr_softc *sc)
 
 	mtx_init(&sc->mpr_mtx, "MPR lock", NULL, MTX_DEF);
 	callout_init_mtx(&sc->periodic, &sc->mpr_mtx, 0);
+	callout_init_mtx(&sc->device_check_callout, &sc->mpr_mtx, 0);
 	TAILQ_INIT(&sc->event_list);
 	timevalclear(&sc->lastfail);
 
@@ -1832,6 +1834,7 @@ mpr_free(struct mpr_softc *sc)
 	mpr_unlock(sc);
 	/* Lock must not be held for this */
 	callout_drain(&sc->periodic);
+	callout_drain(&sc->device_check_callout);
 
 	if (((error = mpr_detach_log(sc)) != 0) ||
 	    ((error = mpr_detach_sas(sc)) != 0))

Modified: head/sys/dev/mpr/mpr_mapping.c
==============================================================================
--- head/sys/dev/mpr/mpr_mapping.c	Thu May 25 19:14:44 2017	(r318895)
+++ head/sys/dev/mpr/mpr_mapping.c	Thu May 25 19:20:06 2017	(r318896)
@@ -60,7 +60,7 @@ __FBSDID("$FreeBSD$");
 #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
  *
  * Returns nothing.
@@ -73,7 +73,6 @@ _mapping_clear_map_entry(struct dev_mapp
 	map_entry->phy_bits = 0;
 	map_entry->dpm_entry_num = MPR_DPM_BAD_IDX;
 	map_entry->dev_handle = 0;
-	map_entry->channel = -1;
 	map_entry->id = -1;
 	map_entry->missing_count = 0;
 	map_entry->init_complete = 0;
@@ -140,12 +139,15 @@ _mapping_commit_enc_entry(struct mpr_sof
 	dpm_entry->PhysicalBitsMapping = htole32(et_entry->phy_bits);
 	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,
 	    sizeof(Mpi2DriverMap0Entry_t));
 	if (mpr_config_set_dpm_pg0(sc, &mpi_reply, &config_page,
 	    et_entry->dpm_entry_num)) {
-		printf("%s: write of dpm entry %d for enclosure failed\n",
-		    __func__, et_entry->dpm_entry_num);
+		mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: Write of DPM "
+		    "entry %d for enclosure failed.\n", __func__,
+		    et_entry->dpm_entry_num);
 		dpm_entry->MappingInformation = le16toh(dpm_entry->
 		    MappingInformation);
 		dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
@@ -164,7 +166,7 @@ _mapping_commit_enc_entry(struct mpr_sof
 /**
  * _mapping_commit_map_entry - write a particular map table entry in DPM page0.
  * @sc: per adapter object
- * @enc_entry: enclosure table entry
+ * @mt_entry: mapping table entry
  *
  * Returns 0 for success, non-zero for failure.
  */
@@ -180,6 +182,19 @@ _mapping_commit_map_entry(struct mpr_sof
 	if (!sc->is_dpm_enable)
 		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));
 	memcpy(&config_page.Header, (u8 *)sc->dpm_pg0,
 	    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
@@ -193,13 +208,16 @@ _mapping_commit_map_entry(struct mpr_sof
 	dpm_entry->MappingInformation = htole16(mt_entry->missing_count);
 	dpm_entry->PhysicalBitsMapping = 0;
 	dpm_entry->Reserved1 = 0;
-	dpm_entry->MappingInformation = htole16(dpm_entry->MappingInformation);
 	memcpy(&config_page.Entry, (u8 *)dpm_entry,
 	    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,
 	    mt_entry->dpm_entry_num)) {
-		printf("%s: write of dpm entry %d for device failed\n",
-		    __func__, mt_entry->dpm_entry_num);
+		mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: Write of DPM "
+		    "entry %d for target %d failed.\n", __func__,
+		    mt_entry->dpm_entry_num, mt_entry->id);
 		dpm_entry->MappingInformation = le16toh(dpm_entry->
 		    MappingInformation);
 		dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
@@ -307,7 +325,7 @@ _mapping_get_high_missing_et_idx(struct 
 		et_entry = &sc->enclosure_table[enc_idx];
 		if ((et_entry->missing_count > high_missing_count) &&
 		    !et_entry->skip_search) {
-			high_missing_count =  et_entry->missing_count;
+			high_missing_count = et_entry->missing_count;
 			high_idx = enc_idx;
 		}
 	}
@@ -326,7 +344,7 @@ _mapping_get_high_missing_et_idx(struct 
 static u32
 _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;
 	u32 start_idx, end_idx, start_idx_ir, end_idx_ir;
 	struct dev_mapping_table *mt_entry;
@@ -370,7 +388,7 @@ _mapping_get_ir_mt_idx_from_wwid(struct 
 
 	_mapping_get_ir_maprange(sc, &start_idx, &end_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)
 			return map_idx;
 
@@ -458,20 +476,31 @@ _mapping_get_free_ir_mt_idx(struct mpr_s
 	u32 high_idx = MPR_MAPTABLE_BAD_IDX;
 	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);
-
 	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))
 			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) {
 			high_missing_count = mt_entry->missing_count;
 			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;
 }
 
@@ -494,6 +523,7 @@ _mapping_get_free_mt_idx(struct mpr_soft
 	if (sc->ir_firmware && (volume_mapping_flags ==
 	    MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING))
 		max_idx -= sc->max_volumes;
+
 	for (map_idx  = start_idx; map_idx < max_idx; map_idx++, mt_entry++)
 		if (!(mt_entry->device_info & (MPR_MAP_IN_USE |
 		    MPR_DEV_RESERVED)))
@@ -542,12 +572,66 @@ static u32
 _mapping_get_free_dpm_idx(struct mpr_softc *sc)
 {
 	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++) {
-		if (!sc->dpm_entry_used[entry_num])
-			return entry_num;
+		dpm_entry = (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 +
+		    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;
+		}
+		if ((current_entry == MPR_DPM_BAD_IDX) ||
+		    (missing_cnt > high_missing_cnt)) {
+			current_entry = entry_num;
+			high_missing_cnt = missing_cnt;
+		}
 	}
-	return MPR_DPM_BAD_IDX;
+
+	/*
+	 * 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;
 }
 
 /**
@@ -566,40 +650,57 @@ _mapping_update_ir_missing_cnt(struct mp
     Mpi2EventIrConfigElement_t *element, u64 wwid)
 {
 	struct dev_mapping_table *mt_entry;
-	u8 missing_cnt, reason = element->ReasonCode;
+	u8 missing_cnt, reason = element->ReasonCode, update_dpm = 1;
 	u16 dpm_idx;
 	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];
-	if (reason == MPI2_EVENT_IR_CHANGE_RC_ADDED) {
-		mt_entry->missing_count = 0;
-	} else if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED) {
+	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->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)
-				mt_entry->missing_count++;
-			else
-				mt_entry->init_complete = 1;
-		}
-		if (!mt_entry->missing_count)
+	} else if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED) {
+		if (mt_entry->missing_count < MPR_MAX_MISSING_COUNT)
 			mt_entry->missing_count++;
+
+		mt_entry->device_info &= ~MPR_MAP_IN_USE;
 		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;
 	if (dpm_idx == MPR_DPM_BAD_IDX) {
-		if ((reason == MPI2_EVENT_IR_CHANGE_RC_ADDED) ||
-		    (reason == MPI2_EVENT_IR_CHANGE_RC_REMOVED))
-			dpm_idx = _mapping_get_dpm_idx_from_id(sc,
-			    mt_entry->physical_id, 0);
-		else if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED)
+		if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED)
+		{
+			mpr_dprint(sc, MPR_MAPPING, "%s: Volume being deleted "
+			    "is not in DPM so DPM missing count will not be "
+			    "updated.\n", __func__);
 			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) {
 		dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
 		    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
@@ -607,17 +708,24 @@ _mapping_update_ir_missing_cnt(struct mp
 		missing_cnt = dpm_entry->MappingInformation &
 		    MPI2_DRVMAP0_MAPINFO_MISSING_MASK;
 		if ((mt_entry->physical_id ==
-		    le64toh((u64)dpm_entry->PhysicalIdentifier.High |
-		    dpm_entry->PhysicalIdentifier.Low)) && (missing_cnt ==
-		    mt_entry->missing_count))
-			mt_entry->init_complete = 1;
-	} else {
-		dpm_idx = _mapping_get_free_dpm_idx(sc);
-		mt_entry->init_complete = 0;
+		    le64toh(((u64)dpm_entry->PhysicalIdentifier.High << 32) |
+		    (u64)dpm_entry->PhysicalIdentifier.Low)) && (missing_cnt ==
+		    mt_entry->missing_count)) {
+			mpr_dprint(sc, MPR_MAPPING, "%s: DPM entry for volume "
+			   "with target ID %d does not require an update.\n",
+			    __func__, mt_entry->id);
+			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;
 		dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
 		    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
@@ -633,44 +741,46 @@ _mapping_update_ir_missing_cnt(struct mp
 		sc->dpm_flush_entry[dpm_idx] = 1;
 		sc->dpm_entry_used[dpm_idx] = 1;
 	} else if (dpm_idx == MPR_DPM_BAD_IDX) {
-		printf("%s: no space to add entry in DPM table\n", __func__);
-		mt_entry->init_complete = 1;
+		mpr_dprint(sc, MPR_INFO | MPR_MAPPING, "%s: No space to add an "
+		    "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
- * @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.
  */
 static void
-_mapping_add_to_removal_table(struct mpr_softc *sc, u16 handle,
-    u16 dpm_idx)
+_mapping_add_to_removal_table(struct mpr_softc *sc, u16 dpm_idx)
 {
 	struct map_removal_table *remove_entry;
 	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++) {
-		if (remove_entry->dev_handle || remove_entry->dpm_entry_num !=
-		    MPR_DPM_BAD_IDX)
+		if (remove_entry->dpm_entry_num != MPR_DPM_BAD_IDX)
 			continue;
-		if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
-		    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
-			if (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;
+ 
+		mpr_dprint(sc, MPR_MAPPING, "%s: Adding DPM entry %d to table "
+		    "for removal.\n", __func__, dpm_idx);
+		remove_entry->dpm_entry_num = dpm_idx;
 		break;
 	}
 
@@ -683,8 +793,11 @@ _mapping_add_to_removal_table(struct mpr
  *
  * 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
- * DPM entry as well. Also, add this device to the removal table for possible
- * removal if a new device is added.
+ * DPM entry as well. Currently, this function is only called if the target
+ * 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.
  */
@@ -696,33 +809,40 @@ _mapping_inc_missing_count(struct mpr_so
 	Mpi2DriverMap0Entry_t *dpm_entry;
 
 	if (map_idx == MPR_MAPTABLE_BAD_IDX) {
-		mpr_dprint(sc, MPR_INFO, "%s: device is already removed from "
-		    "mapping table\n", __func__);
+		mpr_dprint(sc, MPR_INFO | MPR_MAPPING, "%s: device is already "
+		    "removed from mapping table\n", __func__);
 		return;
 	}
 	mt_entry = &sc->mapping_table[map_idx];
-	if (!mt_entry->init_complete) {
-		if (mt_entry->missing_count < MPR_MAX_MISSING_COUNT)
-			mt_entry->missing_count++;
-		else
-			mt_entry->init_complete = 1;
-	}
-	if (!mt_entry->missing_count)
+	if (mt_entry->missing_count < MPR_MAX_MISSING_COUNT)
 		mt_entry->missing_count++;
-	_mapping_add_to_removal_table(sc, mt_entry->dev_handle, 0);
-	mt_entry->dev_handle = 0;
 
+	/*
+	 * 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);
+	}
+
+	/*
+	 * 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) ==
 	    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) {
 		dpm_entry = (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 +
 		    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
 		dpm_entry += mt_entry->dpm_entry_num;
-		dpm_entry->MappingInformation = mt_entry->missing_count;
-		sc->dpm_flush_entry[mt_entry->dpm_entry_num] = 1;
+		if (dpm_entry->MappingInformation != mt_entry->missing_count) {
+			dpm_entry->MappingInformation = mt_entry->missing_count;
+			sc->dpm_flush_entry[mt_entry->dpm_entry_num] = 1;
+		}
 	}
-	mt_entry->init_complete = 1;
 }
 
 /**
@@ -814,6 +934,10 @@ _mapping_find_enc_map_space(struct mpr_s
 	vol_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) &
 	    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)
 		end_of_table = sc->max_devices;
 	else if (vol_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING)
@@ -821,6 +945,17 @@ _mapping_find_enc_map_space(struct mpr_s
 	else
 		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);
 	    map_idx < end_of_table; map_idx++) {
 		mt_entry = &sc->mapping_table[map_idx];
@@ -830,11 +965,21 @@ _mapping_find_enc_map_space(struct mpr_s
 			num_found += 1;
 			if (num_found == et_entry->num_slots) {
 				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;
 			}
 		} else
 			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);
 	    map_idx < end_of_table; map_idx++) {
 		mt_entry = &sc->mapping_table[map_idx];
@@ -842,40 +987,91 @@ _mapping_find_enc_map_space(struct mpr_s
 			num_found += 1;
 			if (num_found == et_entry->num_slots) {
 				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;
 			}
 		} else
 			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) {
 		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;
+		}
+
+		/*
+		 * 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];
-		/*VSP FIXME*/
 		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];
 		for (map_idx = enc_entry->start_index; map_idx <
 		    (enc_entry->start_index + enc_entry->num_slots); map_idx++,
 		    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;
-		for (map_idx = (max_num_phy_ids +
-		    skip_count); map_idx < end_of_table; map_idx++) {
+		num_found = 0;
+		for (map_idx = (max_num_phy_ids + skip_count);
+		    map_idx < end_of_table; map_idx++) {
 			mt_entry = &sc->mapping_table[map_idx];
 			if (!(mt_entry->device_info & MPR_DEV_RESERVED)) {
 				num_found += 1;
 				if (num_found == et_entry->num_slots) {
 					start_idx = (map_idx - num_found) + 1;
 					found_space = 1;
+					break;
 				}
 			} else
 				num_found = 0;
 		}
-
 		if (!found_space)
 			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);
 		    map_idx++) {
 			enc_entry = sc->enclosure_table;
@@ -886,26 +1082,38 @@ _mapping_find_enc_map_space(struct mpr_s
 				    enc_entry->num_slots))
 					continue;
 				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;
-					_mapping_add_to_removal_table(sc, 0,
+					_mapping_add_to_removal_table(sc,
 					    enc_entry->dpm_entry_num);
 				}
 				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 +
 				    enc_entry->num_slots - 1))
 					_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;
 		for (enc_idx = 0; enc_idx < sc->num_enc_table_entries;
 		    enc_idx++, enc_entry++) {
 			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->
 				    start_index];
 				for (map_idx = enc_entry->start_index; map_idx <
@@ -939,7 +1147,7 @@ _mapping_get_dev_info(struct mpr_softc *
 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
 	Mpi2ConfigReply_t mpi_reply;
 	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;
 	struct _map_phy_change *phy_change, *tmp_phy_change;
 	uint64_t sas_address;
@@ -953,6 +1161,7 @@ _mapping_get_dev_info(struct mpr_softc *
 		if (phy_change->is_processed || !phy_change->dev_handle ||
 		    phy_change->reason != MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED)
 			continue;
+
 		if (mpr_config_get_sas_device_pg0(sc, &mpi_reply,
 		    &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
 		    phy_change->dev_handle)) {
@@ -966,13 +1175,11 @@ _mapping_get_dev_info(struct mpr_softc *
 		 * when the system is shutdown.
 		 */
 		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_device_pg0.SASAddress.Low;
-		sata_end_device = 0;
+		    le32toh(sas_device_pg0.SASAddress.Low);
 		if ((device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE) &&
 		    (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)) {
-			sata_end_device = 1;
 			rc = mprsas_get_sas_address_for_sata_disk(sc,
 			    &sas_address, phy_change->dev_handle, device_info,
 			    &phy_change->is_SATA_SSD);
@@ -991,16 +1198,27 @@ _mapping_get_dev_info(struct mpr_softc *
 		phy_change->slot = le16toh(sas_device_pg0.Slot);
 		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) ==
 		    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,
 			    topo_change->enc_handle);
 			if (enc_idx == MPR_ENCTABLE_BAD_IDX) {
 				phy_change->is_processed = 1;
-				mpr_dprint(sc, MPR_MAPPING, "%s: failed to add "
-				    "the device with handle 0x%04x because the "
-				    "enclosure is not in the mapping table\n",
-				    __func__, phy_change->dev_handle);
+				mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: "
+				    "failed to add the device with handle "
+				    "0x%04x because the enclosure is not in "
+				    "the mapping table\n", __func__,
+				    phy_change->dev_handle);
 				continue;
 			}
 			if (!((phy_change->device_info &
@@ -1013,8 +1231,20 @@ _mapping_get_dev_info(struct mpr_softc *
 				continue;
 			}
 			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)
 				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) {
 				map_idx	= sc->num_rsvd_entries;
 				et_entry->start_index = map_idx;
@@ -1022,8 +1252,26 @@ _mapping_get_dev_info(struct mpr_softc *
 				map_idx = _mapping_find_enc_map_space(sc,
 				    et_entry);
 				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 ==
 				    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;
 					for (phy_idx = 0; phy_idx <
 					    topo_change->num_entries;
@@ -1040,7 +1288,14 @@ _mapping_get_dev_info(struct mpr_softc *
 				}
 			}
 
-			/* 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];
 			for (index = map_idx; index < (et_entry->num_slots
 			    + map_idx); index++, mt_entry++) {
@@ -1098,16 +1353,27 @@ _mapping_get_pcie_dev_info(struct mpr_so
 		port_change->slot = le16toh(pcie_device_pg0.Slot);
 		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) ==
 		    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,
 			    topo_change->enc_handle);
 			if (enc_idx == MPR_ENCTABLE_BAD_IDX) {
 				port_change->is_processed = 1;
-				mpr_dprint(sc, MPR_MAPPING, "%s: failed to add "
-				    "the device with handle 0x%04x because the "
-				    "enclosure is not in the mapping table\n",
-				    __func__, port_change->dev_handle);
+				mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: "
+				    "failed to add the device with handle "
+				    "0x%04x because the enclosure is not in "
+				    "the mapping table\n", __func__,
+				    port_change->dev_handle);
 				continue;
 			}
 			if (!(port_change->device_info &
@@ -1116,8 +1382,20 @@ _mapping_get_pcie_dev_info(struct mpr_so
 				continue;
 			}
 			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)
 				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) {
 				map_idx	= sc->num_rsvd_entries;
 				et_entry->start_index = map_idx;
@@ -1125,8 +1403,26 @@ _mapping_get_pcie_dev_info(struct mpr_so
 				map_idx = _mapping_find_enc_map_space(sc,
 				    et_entry);
 				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 ==
 				    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;
 					for (port_idx = 0; port_idx <
 					    topo_change->num_entries;
@@ -1143,7 +1439,14 @@ _mapping_get_pcie_dev_info(struct mpr_so
 				}
 			}
 
-			/* 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];
 			for (index = map_idx; index < (et_entry->num_slots
 			    + map_idx); index++, mt_entry++) {
@@ -1170,6 +1473,7 @@ _mapping_set_mid_to_eid(struct mpr_softc
 	struct dev_mapping_table *mt_entry;
 	u16 slots = et_entry->num_slots, map_idx;
 	u32 start_idx = et_entry->start_index;
+
 	if (start_idx != MPR_MAPTABLE_BAD_IDX) {
 		mt_entry = &sc->mapping_table[start_idx];
 		for (map_idx = 0; map_idx < slots; map_idx++, mt_entry++)
@@ -1219,6 +1523,13 @@ _mapping_clear_removed_entries(struct mp
 			}
 		}
 	}
+
+	/*
+	 * 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) ==
 	    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
 		num_entries = sc->num_enc_table_entries;
@@ -1299,31 +1610,41 @@ _mapping_add_new_device(struct mpr_softc
 			    (sc, topo_change->enc_handle);
 			if (enc_idx == MPR_ENCTABLE_BAD_IDX) {
 				phy_change->is_processed = 1;
-				mpr_dprint(sc, MPR_ERROR, "%s: failed to add "
-				    "the device with handle 0x%04x because the "
-				    "enclosure is not in the mapping table\n",
-				    __func__, phy_change->dev_handle);
+				mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: "
+				    "failed to add the device with handle "
+				    "0x%04x because the enclosure is not in "
+				    "the mapping table\n", __func__,
+				    phy_change->dev_handle);
 				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];
 			if (et_entry->start_index == MPR_MAPTABLE_BAD_IDX) {
 				phy_change->is_processed = 1;
-				if (!sc->mt_full_retry) {
-					sc->mt_add_device_failed = 1;
-					continue;
-				}

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201705251920.v4PJK6AL075430>