xref: /freebsd/sys/dev/mps/mps_mapping.c (revision b99419aee49e2cc53747730be4d0ec4f9b330eb2)
1d043c564SKenneth D. Merry /*-
2718cf2ccSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3718cf2ccSPedro F. Giffuni  *
4ef065d89SStephen McConnell  * Copyright (c) 2011-2015 LSI Corp.
5ef065d89SStephen McConnell  * Copyright (c) 2013-2015 Avago Technologies
6d043c564SKenneth D. Merry  * All rights reserved.
7d043c564SKenneth D. Merry  *
8d043c564SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
9d043c564SKenneth D. Merry  * modification, are permitted provided that the following conditions
10d043c564SKenneth D. Merry  * are met:
11d043c564SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright
12d043c564SKenneth D. Merry  *    notice, this list of conditions and the following disclaimer.
13d043c564SKenneth D. Merry  * 2. Redistributions in binary form must reproduce the above copyright
14d043c564SKenneth D. Merry  *    notice, this list of conditions and the following disclaimer in the
15d043c564SKenneth D. Merry  *    documentation and/or other materials provided with the distribution.
16d043c564SKenneth D. Merry  *
17d043c564SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18d043c564SKenneth D. Merry  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19d043c564SKenneth D. Merry  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20d043c564SKenneth D. Merry  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21d043c564SKenneth D. Merry  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22d043c564SKenneth D. Merry  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23d043c564SKenneth D. Merry  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24d043c564SKenneth D. Merry  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25d043c564SKenneth D. Merry  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26d043c564SKenneth D. Merry  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27d043c564SKenneth D. Merry  * SUCH DAMAGE.
28d043c564SKenneth D. Merry  *
29ef065d89SStephen McConnell  * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
30d043c564SKenneth D. Merry  */
31d043c564SKenneth D. Merry 
32d043c564SKenneth D. Merry #include <sys/cdefs.h>
33d043c564SKenneth D. Merry __FBSDID("$FreeBSD$");
34d043c564SKenneth D. Merry 
35d043c564SKenneth D. Merry /* TODO Move headers to mpsvar */
36d043c564SKenneth D. Merry #include <sys/types.h>
37d043c564SKenneth D. Merry #include <sys/param.h>
38d043c564SKenneth D. Merry #include <sys/lock.h>
39d043c564SKenneth D. Merry #include <sys/mutex.h>
40d043c564SKenneth D. Merry #include <sys/systm.h>
41d043c564SKenneth D. Merry #include <sys/kernel.h>
42d043c564SKenneth D. Merry #include <sys/malloc.h>
43d043c564SKenneth D. Merry #include <sys/kthread.h>
44d043c564SKenneth D. Merry #include <sys/taskqueue.h>
45d043c564SKenneth D. Merry #include <sys/bus.h>
46d043c564SKenneth D. Merry #include <sys/endian.h>
47d043c564SKenneth D. Merry #include <sys/sysctl.h>
48ee5c196bSScott Long #include <sys/sbuf.h>
49d043c564SKenneth D. Merry #include <sys/eventhandler.h>
50d043c564SKenneth D. Merry #include <sys/uio.h>
51d043c564SKenneth D. Merry #include <machine/bus.h>
52d043c564SKenneth D. Merry #include <machine/resource.h>
53d043c564SKenneth D. Merry #include <dev/mps/mpi/mpi2_type.h>
54d043c564SKenneth D. Merry #include <dev/mps/mpi/mpi2.h>
55d043c564SKenneth D. Merry #include <dev/mps/mpi/mpi2_ioc.h>
56d043c564SKenneth D. Merry #include <dev/mps/mpi/mpi2_sas.h>
57d043c564SKenneth D. Merry #include <dev/mps/mpi/mpi2_cnfg.h>
58d043c564SKenneth D. Merry #include <dev/mps/mpi/mpi2_init.h>
59d043c564SKenneth D. Merry #include <dev/mps/mpi/mpi2_tool.h>
60d043c564SKenneth D. Merry #include <dev/mps/mps_ioctl.h>
61d043c564SKenneth D. Merry #include <dev/mps/mpsvar.h>
62d043c564SKenneth D. Merry #include <dev/mps/mps_mapping.h>
63d043c564SKenneth D. Merry 
64d043c564SKenneth D. Merry /**
65635e58c7SStephen McConnell  * _mapping_clear_map_entry - Clear a particular mapping entry.
66d043c564SKenneth D. Merry  * @map_entry: map table entry
67d043c564SKenneth D. Merry  *
68d043c564SKenneth D. Merry  * Returns nothing.
69d043c564SKenneth D. Merry  */
70d043c564SKenneth D. Merry static inline void
71d043c564SKenneth D. Merry _mapping_clear_map_entry(struct dev_mapping_table *map_entry)
72d043c564SKenneth D. Merry {
73d043c564SKenneth D. Merry 	map_entry->physical_id = 0;
74d043c564SKenneth D. Merry 	map_entry->device_info = 0;
75d043c564SKenneth D. Merry 	map_entry->phy_bits = 0;
76d043c564SKenneth D. Merry 	map_entry->dpm_entry_num = MPS_DPM_BAD_IDX;
77d043c564SKenneth D. Merry 	map_entry->dev_handle = 0;
78d043c564SKenneth D. Merry 	map_entry->id = -1;
79d043c564SKenneth D. Merry 	map_entry->missing_count = 0;
80d043c564SKenneth D. Merry 	map_entry->init_complete = 0;
81d043c564SKenneth D. Merry 	map_entry->TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR;
82d043c564SKenneth D. Merry }
83d043c564SKenneth D. Merry 
84d043c564SKenneth D. Merry /**
85d043c564SKenneth D. Merry  * _mapping_clear_enc_entry - Clear a particular enclosure table entry.
86d043c564SKenneth D. Merry  * @enc_entry: enclosure table entry
87d043c564SKenneth D. Merry  *
88d043c564SKenneth D. Merry  * Returns nothing.
89d043c564SKenneth D. Merry  */
90d043c564SKenneth D. Merry static inline void
91d043c564SKenneth D. Merry _mapping_clear_enc_entry(struct enc_mapping_table *enc_entry)
92d043c564SKenneth D. Merry {
93d043c564SKenneth D. Merry 	enc_entry->enclosure_id = 0;
94d043c564SKenneth D. Merry 	enc_entry->start_index = MPS_MAPTABLE_BAD_IDX;
95d043c564SKenneth D. Merry 	enc_entry->phy_bits = 0;
96d043c564SKenneth D. Merry 	enc_entry->dpm_entry_num = MPS_DPM_BAD_IDX;
97d043c564SKenneth D. Merry 	enc_entry->enc_handle = 0;
98d043c564SKenneth D. Merry 	enc_entry->num_slots = 0;
99d043c564SKenneth D. Merry 	enc_entry->start_slot = 0;
100d043c564SKenneth D. Merry 	enc_entry->missing_count = 0;
101d043c564SKenneth D. Merry 	enc_entry->removal_flag = 0;
102d043c564SKenneth D. Merry 	enc_entry->skip_search = 0;
103d043c564SKenneth D. Merry 	enc_entry->init_complete = 0;
104d043c564SKenneth D. Merry }
105d043c564SKenneth D. Merry 
106d043c564SKenneth D. Merry /**
107d043c564SKenneth D. Merry  * _mapping_commit_enc_entry - write a particular enc entry in DPM page0.
108d043c564SKenneth D. Merry  * @sc: per adapter object
109d043c564SKenneth D. Merry  * @enc_entry: enclosure table entry
110d043c564SKenneth D. Merry  *
111d043c564SKenneth D. Merry  * Returns 0 for success, non-zero for failure.
112d043c564SKenneth D. Merry  */
113d043c564SKenneth D. Merry static int
114d043c564SKenneth D. Merry _mapping_commit_enc_entry(struct mps_softc *sc,
115d043c564SKenneth D. Merry     struct enc_mapping_table *et_entry)
116d043c564SKenneth D. Merry {
117d043c564SKenneth D. Merry 	Mpi2DriverMap0Entry_t *dpm_entry;
118d043c564SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
119d043c564SKenneth D. Merry 	Mpi2ConfigReply_t mpi_reply;
120d043c564SKenneth D. Merry 	Mpi2DriverMappingPage0_t config_page;
121d043c564SKenneth D. Merry 
122d043c564SKenneth D. Merry 	if (!sc->is_dpm_enable)
123d043c564SKenneth D. Merry 		return 0;
124d043c564SKenneth D. Merry 
125d043c564SKenneth D. Merry 	memset(&config_page, 0, sizeof(Mpi2DriverMappingPage0_t));
126d043c564SKenneth D. Merry 	memcpy(&config_page.Header, (u8 *) sc->dpm_pg0,
127d043c564SKenneth D. Merry 	    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
128d043c564SKenneth D. Merry 	dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
129d043c564SKenneth D. Merry 	    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
130d043c564SKenneth D. Merry 	dpm_entry += et_entry->dpm_entry_num;
131d043c564SKenneth D. Merry 	dpm_entry->PhysicalIdentifier.Low =
132d043c564SKenneth D. Merry 	    ( 0xFFFFFFFF & et_entry->enclosure_id);
133d043c564SKenneth D. Merry 	dpm_entry->PhysicalIdentifier.High =
134d043c564SKenneth D. Merry 	    ( et_entry->enclosure_id >> 32);
135d043c564SKenneth D. Merry 	mt_entry = &sc->mapping_table[et_entry->start_index];
136d043c564SKenneth D. Merry 	dpm_entry->DeviceIndex = htole16(mt_entry->id);
137d043c564SKenneth D. Merry 	dpm_entry->MappingInformation = et_entry->num_slots;
138d043c564SKenneth D. Merry 	dpm_entry->MappingInformation <<= MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT;
139d043c564SKenneth D. Merry 	dpm_entry->MappingInformation |= et_entry->missing_count;
140d043c564SKenneth D. Merry 	dpm_entry->MappingInformation = htole16(dpm_entry->MappingInformation);
141d043c564SKenneth D. Merry 	dpm_entry->PhysicalBitsMapping = htole32(et_entry->phy_bits);
142d043c564SKenneth D. Merry 	dpm_entry->Reserved1 = 0;
143d043c564SKenneth D. Merry 
144635e58c7SStephen McConnell 	mps_dprint(sc, MPS_MAPPING, "%s: Writing DPM entry %d for enclosure.\n",
145635e58c7SStephen McConnell 	    __func__, et_entry->dpm_entry_num);
146d043c564SKenneth D. Merry 	memcpy(&config_page.Entry, (u8 *)dpm_entry,
147d043c564SKenneth D. Merry 	    sizeof(Mpi2DriverMap0Entry_t));
148d043c564SKenneth D. Merry 	if (mps_config_set_dpm_pg0(sc, &mpi_reply, &config_page,
149d043c564SKenneth D. Merry 	    et_entry->dpm_entry_num)) {
150635e58c7SStephen McConnell 		mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: Write of DPM "
151635e58c7SStephen McConnell 		    "entry %d for enclosure failed.\n", __func__,
152635e58c7SStephen McConnell 		    et_entry->dpm_entry_num);
153d043c564SKenneth D. Merry 		dpm_entry->MappingInformation = le16toh(dpm_entry->
154d043c564SKenneth D. Merry 		    MappingInformation);
155d043c564SKenneth D. Merry 		dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
156d043c564SKenneth D. Merry 		dpm_entry->PhysicalBitsMapping =
157d043c564SKenneth D. Merry 		    le32toh(dpm_entry->PhysicalBitsMapping);
158d043c564SKenneth D. Merry 		return -1;
159d043c564SKenneth D. Merry 	}
160d043c564SKenneth D. Merry 	dpm_entry->MappingInformation = le16toh(dpm_entry->
161d043c564SKenneth D. Merry 	    MappingInformation);
162d043c564SKenneth D. Merry 	dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
163d043c564SKenneth D. Merry 	dpm_entry->PhysicalBitsMapping =
164d043c564SKenneth D. Merry 	    le32toh(dpm_entry->PhysicalBitsMapping);
165d043c564SKenneth D. Merry 	return 0;
166d043c564SKenneth D. Merry }
167d043c564SKenneth D. Merry 
168d043c564SKenneth D. Merry /**
169d043c564SKenneth D. Merry  * _mapping_commit_map_entry - write a particular map table entry in DPM page0.
170d043c564SKenneth D. Merry  * @sc: per adapter object
171635e58c7SStephen McConnell  * @mt_entry: mapping table entry
172d043c564SKenneth D. Merry  *
173d043c564SKenneth D. Merry  * Returns 0 for success, non-zero for failure.
174d043c564SKenneth D. Merry  */
175d043c564SKenneth D. Merry 
176d043c564SKenneth D. Merry static int
177d043c564SKenneth D. Merry _mapping_commit_map_entry(struct mps_softc *sc,
178d043c564SKenneth D. Merry     struct dev_mapping_table *mt_entry)
179d043c564SKenneth D. Merry {
180d043c564SKenneth D. Merry 	Mpi2DriverMap0Entry_t *dpm_entry;
181d043c564SKenneth D. Merry 	Mpi2ConfigReply_t mpi_reply;
182d043c564SKenneth D. Merry 	Mpi2DriverMappingPage0_t config_page;
183d043c564SKenneth D. Merry 
184d043c564SKenneth D. Merry 	if (!sc->is_dpm_enable)
185d043c564SKenneth D. Merry 		return 0;
186d043c564SKenneth D. Merry 
187635e58c7SStephen McConnell 	/*
188635e58c7SStephen McConnell 	 * It's possible that this Map Entry points to a BAD DPM index. This
189635e58c7SStephen McConnell 	 * can happen if the Map Entry is a for a missing device and the DPM
190635e58c7SStephen McConnell 	 * entry that was being used by this device is now being used by some
191635e58c7SStephen McConnell 	 * new device. So, check for a BAD DPM index and just return if so.
192635e58c7SStephen McConnell 	 */
193635e58c7SStephen McConnell 	if (mt_entry->dpm_entry_num == MPS_DPM_BAD_IDX) {
194635e58c7SStephen McConnell 		mps_dprint(sc, MPS_MAPPING, "%s: DPM entry location for target "
195635e58c7SStephen McConnell 		    "%d is invalid. DPM will not be written.\n", __func__,
196635e58c7SStephen McConnell 		    mt_entry->id);
197635e58c7SStephen McConnell 		return 0;
198635e58c7SStephen McConnell 	}
199635e58c7SStephen McConnell 
200d043c564SKenneth D. Merry 	memset(&config_page, 0, sizeof(Mpi2DriverMappingPage0_t));
201d043c564SKenneth D. Merry 	memcpy(&config_page.Header, (u8 *)sc->dpm_pg0,
202d043c564SKenneth D. Merry 	    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
203d043c564SKenneth D. Merry 	dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *) sc->dpm_pg0 +
204d043c564SKenneth D. Merry 	    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
205d043c564SKenneth D. Merry 	dpm_entry = dpm_entry + mt_entry->dpm_entry_num;
206d043c564SKenneth D. Merry 	dpm_entry->PhysicalIdentifier.Low = (0xFFFFFFFF &
207d043c564SKenneth D. Merry 	    mt_entry->physical_id);
208d043c564SKenneth D. Merry 	dpm_entry->PhysicalIdentifier.High = (mt_entry->physical_id >> 32);
209d043c564SKenneth D. Merry 	dpm_entry->DeviceIndex = htole16(mt_entry->id);
210d043c564SKenneth D. Merry 	dpm_entry->MappingInformation = htole16(mt_entry->missing_count);
211d043c564SKenneth D. Merry 	dpm_entry->PhysicalBitsMapping = 0;
212d043c564SKenneth D. Merry 	dpm_entry->Reserved1 = 0;
213d043c564SKenneth D. Merry 	memcpy(&config_page.Entry, (u8 *)dpm_entry,
214d043c564SKenneth D. Merry 	    sizeof(Mpi2DriverMap0Entry_t));
215635e58c7SStephen McConnell 
216635e58c7SStephen McConnell 	mps_dprint(sc, MPS_MAPPING, "%s: Writing DPM entry %d for target %d.\n",
217635e58c7SStephen McConnell 	    __func__, mt_entry->dpm_entry_num, mt_entry->id);
218d043c564SKenneth D. Merry 	if (mps_config_set_dpm_pg0(sc, &mpi_reply, &config_page,
219d043c564SKenneth D. Merry 	    mt_entry->dpm_entry_num)) {
220635e58c7SStephen McConnell 		mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: Write of DPM "
221635e58c7SStephen McConnell 		    "entry %d for target %d failed.\n", __func__,
222635e58c7SStephen McConnell 		    mt_entry->dpm_entry_num, mt_entry->id);
223d043c564SKenneth D. Merry 		dpm_entry->MappingInformation = le16toh(dpm_entry->
224d043c564SKenneth D. Merry 		    MappingInformation);
225d043c564SKenneth D. Merry 		dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
226d043c564SKenneth D. Merry 		return -1;
227d043c564SKenneth D. Merry 	}
228d043c564SKenneth D. Merry 
229d043c564SKenneth D. Merry 	dpm_entry->MappingInformation = le16toh(dpm_entry->MappingInformation);
230d043c564SKenneth D. Merry 	dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
231d043c564SKenneth D. Merry 	return 0;
232d043c564SKenneth D. Merry }
233d043c564SKenneth D. Merry 
234d043c564SKenneth D. Merry /**
235d043c564SKenneth D. Merry  * _mapping_get_ir_maprange - get start and end index for IR map range.
236d043c564SKenneth D. Merry  * @sc: per adapter object
237d043c564SKenneth D. Merry  * @start_idx: place holder for start index
238d043c564SKenneth D. Merry  * @end_idx: place holder for end index
239d043c564SKenneth D. Merry  *
240d043c564SKenneth D. Merry  * The IR volumes can be mapped either at start or end of the mapping table
241d043c564SKenneth D. Merry  * this function gets the detail of where IR volume mapping starts and ends
242d043c564SKenneth D. Merry  * in the device mapping table
243d043c564SKenneth D. Merry  *
244d043c564SKenneth D. Merry  * Returns nothing.
245d043c564SKenneth D. Merry  */
246d043c564SKenneth D. Merry static void
247d043c564SKenneth D. Merry _mapping_get_ir_maprange(struct mps_softc *sc, u32 *start_idx, u32 *end_idx)
248d043c564SKenneth D. Merry {
249d043c564SKenneth D. Merry 	u16 volume_mapping_flags;
250d043c564SKenneth D. Merry 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
251d043c564SKenneth D. Merry 
252d043c564SKenneth D. Merry 	volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) &
253d043c564SKenneth D. Merry 	    MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
254d043c564SKenneth D. Merry 	if (volume_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) {
255d043c564SKenneth D. Merry 		*start_idx = 0;
256d043c564SKenneth D. Merry 		if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0)
257d043c564SKenneth D. Merry 			*start_idx = 1;
258d043c564SKenneth D. Merry 	} else
259d043c564SKenneth D. Merry 		*start_idx = sc->max_devices - sc->max_volumes;
260d043c564SKenneth D. Merry 	*end_idx = *start_idx + sc->max_volumes - 1;
261d043c564SKenneth D. Merry }
262d043c564SKenneth D. Merry 
263d043c564SKenneth D. Merry /**
264d043c564SKenneth D. Merry  * _mapping_get_enc_idx_from_id - get enclosure index from enclosure ID
265d043c564SKenneth D. Merry  * @sc: per adapter object
266d043c564SKenneth D. Merry  * @enc_id: enclosure logical identifier
267d043c564SKenneth D. Merry  *
268d043c564SKenneth D. Merry  * Returns the index of enclosure entry on success or bad index.
269d043c564SKenneth D. Merry  */
270d043c564SKenneth D. Merry static u8
271d043c564SKenneth D. Merry _mapping_get_enc_idx_from_id(struct mps_softc *sc, u64 enc_id,
272d043c564SKenneth D. Merry     u64 phy_bits)
273d043c564SKenneth D. Merry {
274d043c564SKenneth D. Merry 	struct enc_mapping_table *et_entry;
275d043c564SKenneth D. Merry 	u8 enc_idx = 0;
276d043c564SKenneth D. Merry 
277d043c564SKenneth D. Merry 	for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; enc_idx++) {
278d043c564SKenneth D. Merry 		et_entry = &sc->enclosure_table[enc_idx];
279d043c564SKenneth D. Merry 		if ((et_entry->enclosure_id == le64toh(enc_id)) &&
280d043c564SKenneth D. Merry 		    (!et_entry->phy_bits || (et_entry->phy_bits &
281d043c564SKenneth D. Merry 		    le32toh(phy_bits))))
282d043c564SKenneth D. Merry 			return enc_idx;
283d043c564SKenneth D. Merry 	}
284d043c564SKenneth D. Merry 	return MPS_ENCTABLE_BAD_IDX;
285d043c564SKenneth D. Merry }
286d043c564SKenneth D. Merry 
287d043c564SKenneth D. Merry /**
288d043c564SKenneth D. Merry  * _mapping_get_enc_idx_from_handle - get enclosure index from handle
289d043c564SKenneth D. Merry  * @sc: per adapter object
290d043c564SKenneth D. Merry  * @enc_id: enclosure handle
291d043c564SKenneth D. Merry  *
292d043c564SKenneth D. Merry  * Returns the index of enclosure entry on success or bad index.
293d043c564SKenneth D. Merry  */
294d043c564SKenneth D. Merry static u8
295d043c564SKenneth D. Merry _mapping_get_enc_idx_from_handle(struct mps_softc *sc, u16 handle)
296d043c564SKenneth D. Merry {
297d043c564SKenneth D. Merry 	struct enc_mapping_table *et_entry;
298d043c564SKenneth D. Merry 	u8 enc_idx = 0;
299d043c564SKenneth D. Merry 
300d043c564SKenneth D. Merry 	for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; enc_idx++) {
301d043c564SKenneth D. Merry 		et_entry = &sc->enclosure_table[enc_idx];
302d043c564SKenneth D. Merry 		if (et_entry->missing_count)
303d043c564SKenneth D. Merry 			continue;
304d043c564SKenneth D. Merry 		if (et_entry->enc_handle == handle)
305d043c564SKenneth D. Merry 			return enc_idx;
306d043c564SKenneth D. Merry 	}
307d043c564SKenneth D. Merry 	return MPS_ENCTABLE_BAD_IDX;
308d043c564SKenneth D. Merry }
309d043c564SKenneth D. Merry 
310d043c564SKenneth D. Merry /**
311d043c564SKenneth D. Merry  * _mapping_get_high_missing_et_idx - get missing enclosure index
312d043c564SKenneth D. Merry  * @sc: per adapter object
313d043c564SKenneth D. Merry  *
314d043c564SKenneth D. Merry  * Search through the enclosure table and identifies the enclosure entry
315d043c564SKenneth D. Merry  * with high missing count and returns it's index
316d043c564SKenneth D. Merry  *
317d043c564SKenneth D. Merry  * Returns the index of enclosure entry on success or bad index.
318d043c564SKenneth D. Merry  */
319d043c564SKenneth D. Merry static u8
320d043c564SKenneth D. Merry _mapping_get_high_missing_et_idx(struct mps_softc *sc)
321d043c564SKenneth D. Merry {
322d043c564SKenneth D. Merry 	struct enc_mapping_table *et_entry;
323d043c564SKenneth D. Merry 	u8 high_missing_count = 0;
324d043c564SKenneth D. Merry 	u8 enc_idx, high_idx = MPS_ENCTABLE_BAD_IDX;
325d043c564SKenneth D. Merry 
326d043c564SKenneth D. Merry 	for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; enc_idx++) {
327d043c564SKenneth D. Merry 		et_entry = &sc->enclosure_table[enc_idx];
328d043c564SKenneth D. Merry 		if ((et_entry->missing_count > high_missing_count) &&
329d043c564SKenneth D. Merry 		    !et_entry->skip_search) {
330d043c564SKenneth D. Merry 			high_missing_count = et_entry->missing_count;
331d043c564SKenneth D. Merry 			high_idx = enc_idx;
332d043c564SKenneth D. Merry 		}
333d043c564SKenneth D. Merry 	}
334d043c564SKenneth D. Merry 	return high_idx;
335d043c564SKenneth D. Merry }
336d043c564SKenneth D. Merry 
337d043c564SKenneth D. Merry /**
338d043c564SKenneth D. Merry  * _mapping_get_high_missing_mt_idx - get missing map table index
339d043c564SKenneth D. Merry  * @sc: per adapter object
340d043c564SKenneth D. Merry  *
341d043c564SKenneth D. Merry  * Search through the map table and identifies the device entry
342d043c564SKenneth D. Merry  * with high missing count and returns it's index
343d043c564SKenneth D. Merry  *
344d043c564SKenneth D. Merry  * Returns the index of map table entry on success or bad index.
345d043c564SKenneth D. Merry  */
346d043c564SKenneth D. Merry static u32
347d043c564SKenneth D. Merry _mapping_get_high_missing_mt_idx(struct mps_softc *sc)
348d043c564SKenneth D. Merry {
349635e58c7SStephen McConnell 	u32 map_idx, high_idx = MPS_MAPTABLE_BAD_IDX;
350d043c564SKenneth D. Merry 	u8 high_missing_count = 0;
351d043c564SKenneth D. Merry 	u32 start_idx, end_idx, start_idx_ir, end_idx_ir;
352d043c564SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
353d043c564SKenneth D. Merry 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
354d043c564SKenneth D. Merry 
355d043c564SKenneth D. Merry 	start_idx = 0;
3565d0b98f2SSteven Hartland 	start_idx_ir = 0;
3575d0b98f2SSteven Hartland 	end_idx_ir = 0;
358d043c564SKenneth D. Merry 	end_idx = sc->max_devices;
359d043c564SKenneth D. Merry 	if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0)
360d043c564SKenneth D. Merry 		start_idx = 1;
361e248a3d1SSteven Hartland 	if (sc->ir_firmware) {
362d043c564SKenneth D. Merry 		_mapping_get_ir_maprange(sc, &start_idx_ir, &end_idx_ir);
363d043c564SKenneth D. Merry 		if (start_idx == start_idx_ir)
364d043c564SKenneth D. Merry 			start_idx = end_idx_ir + 1;
365d043c564SKenneth D. Merry 		else
366d043c564SKenneth D. Merry 			end_idx = start_idx_ir;
367e248a3d1SSteven Hartland 	}
368d043c564SKenneth D. Merry 	mt_entry = &sc->mapping_table[start_idx];
369d043c564SKenneth D. Merry 	for (map_idx = start_idx; map_idx < end_idx; map_idx++, mt_entry++) {
370d043c564SKenneth D. Merry 		if (mt_entry->missing_count > high_missing_count) {
371d043c564SKenneth D. Merry 			high_missing_count =  mt_entry->missing_count;
372d043c564SKenneth D. Merry 			high_idx = map_idx;
373d043c564SKenneth D. Merry 		}
374d043c564SKenneth D. Merry 	}
375d043c564SKenneth D. Merry 	return high_idx;
376d043c564SKenneth D. Merry }
377d043c564SKenneth D. Merry 
378d043c564SKenneth D. Merry /**
379d043c564SKenneth D. Merry  * _mapping_get_ir_mt_idx_from_wwid - get map table index from volume WWID
380d043c564SKenneth D. Merry  * @sc: per adapter object
381d043c564SKenneth D. Merry  * @wwid: world wide unique ID of the volume
382d043c564SKenneth D. Merry  *
383d043c564SKenneth D. Merry  * Returns the index of map table entry on success or bad index.
384d043c564SKenneth D. Merry  */
385d043c564SKenneth D. Merry static u32
386d043c564SKenneth D. Merry _mapping_get_ir_mt_idx_from_wwid(struct mps_softc *sc, u64 wwid)
387d043c564SKenneth D. Merry {
388d043c564SKenneth D. Merry 	u32 start_idx, end_idx, map_idx;
389d043c564SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
390d043c564SKenneth D. Merry 
391d043c564SKenneth D. Merry 	_mapping_get_ir_maprange(sc, &start_idx, &end_idx);
392d043c564SKenneth D. Merry 	mt_entry = &sc->mapping_table[start_idx];
393d043c564SKenneth D. Merry 	for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++)
394d043c564SKenneth D. Merry 		if (mt_entry->physical_id == wwid)
395d043c564SKenneth D. Merry 			return map_idx;
396d043c564SKenneth D. Merry 
397d043c564SKenneth D. Merry 	return MPS_MAPTABLE_BAD_IDX;
398d043c564SKenneth D. Merry }
399d043c564SKenneth D. Merry 
400d043c564SKenneth D. Merry /**
401d043c564SKenneth D. Merry  * _mapping_get_mt_idx_from_id - get map table index from a device ID
402d043c564SKenneth D. Merry  * @sc: per adapter object
403d043c564SKenneth D. Merry  * @dev_id: device identifer (SAS Address)
404d043c564SKenneth D. Merry  *
405d043c564SKenneth D. Merry  * Returns the index of map table entry on success or bad index.
406d043c564SKenneth D. Merry  */
407d043c564SKenneth D. Merry static u32
408d043c564SKenneth D. Merry _mapping_get_mt_idx_from_id(struct mps_softc *sc, u64 dev_id)
409d043c564SKenneth D. Merry {
410d043c564SKenneth D. Merry 	u32 map_idx;
411d043c564SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
412d043c564SKenneth D. Merry 
413d043c564SKenneth D. Merry 	for (map_idx = 0; map_idx < sc->max_devices; map_idx++) {
414d043c564SKenneth D. Merry 		mt_entry = &sc->mapping_table[map_idx];
415d043c564SKenneth D. Merry 		if (mt_entry->physical_id == dev_id)
416d043c564SKenneth D. Merry 			return map_idx;
417d043c564SKenneth D. Merry 	}
418d043c564SKenneth D. Merry 	return MPS_MAPTABLE_BAD_IDX;
419d043c564SKenneth D. Merry }
420d043c564SKenneth D. Merry 
421d043c564SKenneth D. Merry /**
422d043c564SKenneth D. Merry  * _mapping_get_ir_mt_idx_from_handle - get map table index from volume handle
423d043c564SKenneth D. Merry  * @sc: per adapter object
424d043c564SKenneth D. Merry  * @wwid: volume device handle
425d043c564SKenneth D. Merry  *
426d043c564SKenneth D. Merry  * Returns the index of map table entry on success or bad index.
427d043c564SKenneth D. Merry  */
428d043c564SKenneth D. Merry static u32
429d043c564SKenneth D. Merry _mapping_get_ir_mt_idx_from_handle(struct mps_softc *sc, u16 volHandle)
430d043c564SKenneth D. Merry {
431d043c564SKenneth D. Merry 	u32 start_idx, end_idx, map_idx;
432d043c564SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
433d043c564SKenneth D. Merry 
434d043c564SKenneth D. Merry 	_mapping_get_ir_maprange(sc, &start_idx, &end_idx);
435d043c564SKenneth D. Merry 	mt_entry = &sc->mapping_table[start_idx];
436d043c564SKenneth D. Merry 	for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++)
437d043c564SKenneth D. Merry 		if (mt_entry->dev_handle == volHandle)
438d043c564SKenneth D. Merry 			return map_idx;
439d043c564SKenneth D. Merry 
440d043c564SKenneth D. Merry 	return MPS_MAPTABLE_BAD_IDX;
441d043c564SKenneth D. Merry }
442d043c564SKenneth D. Merry 
443d043c564SKenneth D. Merry /**
444d043c564SKenneth D. Merry  * _mapping_get_mt_idx_from_handle - get map table index from handle
445d043c564SKenneth D. Merry  * @sc: per adapter object
446d043c564SKenneth D. Merry  * @dev_id: device handle
447d043c564SKenneth D. Merry  *
448d043c564SKenneth D. Merry  * Returns the index of map table entry on success or bad index.
449d043c564SKenneth D. Merry  */
450d043c564SKenneth D. Merry static u32
451d043c564SKenneth D. Merry _mapping_get_mt_idx_from_handle(struct mps_softc *sc, u16 handle)
452d043c564SKenneth D. Merry {
453d043c564SKenneth D. Merry 	u32 map_idx;
454d043c564SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
455d043c564SKenneth D. Merry 
456d043c564SKenneth D. Merry 	for (map_idx = 0; map_idx < sc->max_devices; map_idx++) {
457d043c564SKenneth D. Merry 		mt_entry = &sc->mapping_table[map_idx];
458d043c564SKenneth D. Merry 		if (mt_entry->dev_handle == handle)
459d043c564SKenneth D. Merry 			return map_idx;
460d043c564SKenneth D. Merry 	}
461d043c564SKenneth D. Merry 	return MPS_MAPTABLE_BAD_IDX;
462d043c564SKenneth D. Merry }
463d043c564SKenneth D. Merry 
464d043c564SKenneth D. Merry /**
465d043c564SKenneth D. Merry  * _mapping_get_free_ir_mt_idx - get first free index for a volume
466d043c564SKenneth D. Merry  * @sc: per adapter object
467d043c564SKenneth D. Merry  *
468d043c564SKenneth D. Merry  * Search through mapping table for free index for a volume and if no free
469d043c564SKenneth D. Merry  * index then looks for a volume with high mapping index
470d043c564SKenneth D. Merry  *
471d043c564SKenneth D. Merry  * Returns the index of map table entry on success or bad index.
472d043c564SKenneth D. Merry  */
473d043c564SKenneth D. Merry static u32
474d043c564SKenneth D. Merry _mapping_get_free_ir_mt_idx(struct mps_softc *sc)
475d043c564SKenneth D. Merry {
476d043c564SKenneth D. Merry 	u8 high_missing_count = 0;
477d043c564SKenneth D. Merry 	u32 start_idx, end_idx, map_idx;
478d043c564SKenneth D. Merry 	u32 high_idx = MPS_MAPTABLE_BAD_IDX;
479d043c564SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
480d043c564SKenneth D. Merry 
481635e58c7SStephen McConnell 	/*
482635e58c7SStephen McConnell 	 * The IN_USE flag should be clear if the entry is available to use.
483635e58c7SStephen McConnell 	 * This flag is cleared on initialization and and when a volume is
484635e58c7SStephen McConnell 	 * deleted. All other times this flag should be set. If, for some
485635e58c7SStephen McConnell 	 * reason, a free entry cannot be found, look for the entry with the
486635e58c7SStephen McConnell 	 * highest missing count just in case there is one.
487635e58c7SStephen McConnell 	 */
488d043c564SKenneth D. Merry 	_mapping_get_ir_maprange(sc, &start_idx, &end_idx);
489d043c564SKenneth D. Merry 
490d043c564SKenneth D. Merry 	mt_entry = &sc->mapping_table[start_idx];
491635e58c7SStephen McConnell 	for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++) {
492d043c564SKenneth D. Merry 		if (!(mt_entry->device_info & MPS_MAP_IN_USE))
493d043c564SKenneth D. Merry 			return map_idx;
494d043c564SKenneth D. Merry 
495d043c564SKenneth D. Merry 		if (mt_entry->missing_count > high_missing_count) {
496d043c564SKenneth D. Merry 			high_missing_count = mt_entry->missing_count;
497d043c564SKenneth D. Merry 			high_idx = map_idx;
498d043c564SKenneth D. Merry 		}
499d043c564SKenneth D. Merry 	}
500635e58c7SStephen McConnell 
501635e58c7SStephen McConnell 	if (high_idx == MPS_MAPTABLE_BAD_IDX) {
502635e58c7SStephen McConnell 		mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: Could not find a "
503635e58c7SStephen McConnell 		    "free entry in the mapping table for a Volume. The mapping "
504635e58c7SStephen McConnell 		    "table is probably corrupt.\n", __func__);
505635e58c7SStephen McConnell 	}
506635e58c7SStephen McConnell 
507d043c564SKenneth D. Merry 	return high_idx;
508d043c564SKenneth D. Merry }
509d043c564SKenneth D. Merry 
510d043c564SKenneth D. Merry /**
511d043c564SKenneth D. Merry  * _mapping_get_free_mt_idx - get first free index for a device
512d043c564SKenneth D. Merry  * @sc: per adapter object
513d043c564SKenneth D. Merry  * @start_idx: offset in the table to start search
514d043c564SKenneth D. Merry  *
515d043c564SKenneth D. Merry  * Returns the index of map table entry on success or bad index.
516d043c564SKenneth D. Merry  */
517d043c564SKenneth D. Merry static u32
518d043c564SKenneth D. Merry _mapping_get_free_mt_idx(struct mps_softc *sc, u32 start_idx)
519d043c564SKenneth D. Merry {
520d043c564SKenneth D. Merry 	u32 map_idx, max_idx = sc->max_devices;
521d043c564SKenneth D. Merry 	struct dev_mapping_table *mt_entry = &sc->mapping_table[start_idx];
522d043c564SKenneth D. Merry 	u16 volume_mapping_flags;
523d043c564SKenneth D. Merry 
524d043c564SKenneth D. Merry 	volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) &
525d043c564SKenneth D. Merry 	    MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
526d043c564SKenneth D. Merry 	if (sc->ir_firmware && (volume_mapping_flags ==
527d043c564SKenneth D. Merry 	    MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING))
528d043c564SKenneth D. Merry 		max_idx -= sc->max_volumes;
529635e58c7SStephen McConnell 
530d043c564SKenneth D. Merry 	for (map_idx  = start_idx; map_idx < max_idx; map_idx++, mt_entry++)
531d043c564SKenneth D. Merry 		if (!(mt_entry->device_info & (MPS_MAP_IN_USE |
532d043c564SKenneth D. Merry 		    MPS_DEV_RESERVED)))
533d043c564SKenneth D. Merry 			return map_idx;
534d043c564SKenneth D. Merry 
535d043c564SKenneth D. Merry 	return MPS_MAPTABLE_BAD_IDX;
536d043c564SKenneth D. Merry }
537d043c564SKenneth D. Merry 
538d043c564SKenneth D. Merry /**
539d043c564SKenneth D. Merry  * _mapping_get_dpm_idx_from_id - get DPM index from ID
540d043c564SKenneth D. Merry  * @sc: per adapter object
541d043c564SKenneth D. Merry  * @id: volume WWID or enclosure ID or device ID
542d043c564SKenneth D. Merry  *
543d043c564SKenneth D. Merry  * Returns the index of DPM entry on success or bad index.
544d043c564SKenneth D. Merry  */
545d043c564SKenneth D. Merry static u16
546d043c564SKenneth D. Merry _mapping_get_dpm_idx_from_id(struct mps_softc *sc, u64 id, u32 phy_bits)
547d043c564SKenneth D. Merry {
548d043c564SKenneth D. Merry 	u16 entry_num;
549d043c564SKenneth D. Merry 	uint64_t PhysicalIdentifier;
550d043c564SKenneth D. Merry 	Mpi2DriverMap0Entry_t *dpm_entry;
551d043c564SKenneth D. Merry 
552d043c564SKenneth D. Merry 	dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
553d043c564SKenneth D. Merry 	    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
554d043c564SKenneth D. Merry 	PhysicalIdentifier = dpm_entry->PhysicalIdentifier.High;
555d043c564SKenneth D. Merry 	PhysicalIdentifier = (PhysicalIdentifier << 32) |
556d043c564SKenneth D. Merry 	    dpm_entry->PhysicalIdentifier.Low;
557d043c564SKenneth D. Merry 	for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++,
558d043c564SKenneth D. Merry 	    dpm_entry++)
559d043c564SKenneth D. Merry 		if ((id == PhysicalIdentifier) &&
560d043c564SKenneth D. Merry 		    (!phy_bits || !dpm_entry->PhysicalBitsMapping ||
561d043c564SKenneth D. Merry 		    (phy_bits & dpm_entry->PhysicalBitsMapping)))
562d043c564SKenneth D. Merry 			return entry_num;
563d043c564SKenneth D. Merry 
564d043c564SKenneth D. Merry 	return MPS_DPM_BAD_IDX;
565d043c564SKenneth D. Merry }
566d043c564SKenneth D. Merry 
567d043c564SKenneth D. Merry /**
568d043c564SKenneth D. Merry  * _mapping_get_free_dpm_idx - get first available DPM index
569d043c564SKenneth D. Merry  * @sc: per adapter object
570d043c564SKenneth D. Merry  *
571d043c564SKenneth D. Merry  * Returns the index of DPM entry on success or bad index.
572d043c564SKenneth D. Merry  */
573d043c564SKenneth D. Merry static u32
574d043c564SKenneth D. Merry _mapping_get_free_dpm_idx(struct mps_softc *sc)
575d043c564SKenneth D. Merry {
576d043c564SKenneth D. Merry 	u16 entry_num;
577635e58c7SStephen McConnell 	Mpi2DriverMap0Entry_t *dpm_entry;
578635e58c7SStephen McConnell 	u16 current_entry = MPS_DPM_BAD_IDX, missing_cnt, high_missing_cnt = 0;
579635e58c7SStephen McConnell 	u64 physical_id;
580635e58c7SStephen McConnell 	struct dev_mapping_table *mt_entry;
581635e58c7SStephen McConnell 	u32 map_idx;
582d043c564SKenneth D. Merry 
583d043c564SKenneth D. Merry  	for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++) {
584635e58c7SStephen McConnell 		dpm_entry = (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 +
585635e58c7SStephen McConnell 		    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
586635e58c7SStephen McConnell 		dpm_entry += entry_num;
587635e58c7SStephen McConnell 		missing_cnt = dpm_entry->MappingInformation &
588635e58c7SStephen McConnell 		    MPI2_DRVMAP0_MAPINFO_MISSING_MASK;
589635e58c7SStephen McConnell 
590635e58c7SStephen McConnell 		/*
591635e58c7SStephen McConnell 		 * If entry is used and not missing, then this entry can't be
592635e58c7SStephen McConnell 		 * used. Look at next one.
593635e58c7SStephen McConnell 		 */
594635e58c7SStephen McConnell 		if (sc->dpm_entry_used[entry_num] && !missing_cnt)
595635e58c7SStephen McConnell 			continue;
596635e58c7SStephen McConnell 
597635e58c7SStephen McConnell 		/*
598635e58c7SStephen McConnell 		 * If this entry is not used at all, then the missing count
599635e58c7SStephen McConnell 		 * doesn't matter. Just use this one. Otherwise, keep looking
600635e58c7SStephen McConnell 		 * and make sure the entry with the highest missing count is
601635e58c7SStephen McConnell 		 * used.
602635e58c7SStephen McConnell 		 */
603635e58c7SStephen McConnell 		if (!sc->dpm_entry_used[entry_num]) {
604635e58c7SStephen McConnell 			current_entry = entry_num;
605635e58c7SStephen McConnell 			break;
606d043c564SKenneth D. Merry 		}
607635e58c7SStephen McConnell 		if ((current_entry == MPS_DPM_BAD_IDX) ||
608635e58c7SStephen McConnell 		    (missing_cnt > high_missing_cnt)) {
609635e58c7SStephen McConnell 			current_entry = entry_num;
610635e58c7SStephen McConnell 			high_missing_cnt = missing_cnt;
611635e58c7SStephen McConnell 		}
612635e58c7SStephen McConnell  	}
613635e58c7SStephen McConnell 
614635e58c7SStephen McConnell 	/*
615635e58c7SStephen McConnell 	 * If an entry has been found to use and it's already marked as used
616635e58c7SStephen McConnell 	 * it means that some device was already using this entry but it's
617635e58c7SStephen McConnell 	 * missing, and that means that the connection between the missing
618635e58c7SStephen McConnell 	 * device's DPM entry and the mapping table needs to be cleared. To do
619635e58c7SStephen McConnell 	 * this, use the Physical ID of the old device still in the DPM entry
620635e58c7SStephen McConnell 	 * to find its mapping table entry, then mark its DPM entry as BAD.
621635e58c7SStephen McConnell 	 */
622635e58c7SStephen McConnell 	if ((current_entry != MPS_DPM_BAD_IDX) &&
623635e58c7SStephen McConnell 	    sc->dpm_entry_used[current_entry]) {
624635e58c7SStephen McConnell 		dpm_entry = (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 +
625635e58c7SStephen McConnell 		    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
626635e58c7SStephen McConnell 		dpm_entry += current_entry;
627635e58c7SStephen McConnell 		physical_id = dpm_entry->PhysicalIdentifier.High;
628635e58c7SStephen McConnell 		physical_id = (physical_id << 32) |
629635e58c7SStephen McConnell 		    dpm_entry->PhysicalIdentifier.Low;
630635e58c7SStephen McConnell 		map_idx = _mapping_get_mt_idx_from_id(sc, physical_id);
631635e58c7SStephen McConnell 		if (map_idx != MPS_MAPTABLE_BAD_IDX) {
632635e58c7SStephen McConnell 			mt_entry = &sc->mapping_table[map_idx];
633635e58c7SStephen McConnell 			mt_entry->dpm_entry_num = MPS_DPM_BAD_IDX;
634635e58c7SStephen McConnell 		}
635635e58c7SStephen McConnell 	}
636635e58c7SStephen McConnell 	return current_entry;
637d043c564SKenneth D. Merry }
638d043c564SKenneth D. Merry 
639d043c564SKenneth D. Merry /**
640d043c564SKenneth D. Merry  * _mapping_update_ir_missing_cnt - Updates missing count for a volume
641d043c564SKenneth D. Merry  * @sc: per adapter object
642d043c564SKenneth D. Merry  * @map_idx: map table index of the volume
643d043c564SKenneth D. Merry  * @element: IR configuration change element
644d043c564SKenneth D. Merry  * @wwid: IR volume ID.
645d043c564SKenneth D. Merry  *
646d043c564SKenneth D. Merry  * Updates the missing count in the map table and in the DPM entry for a volume
647d043c564SKenneth D. Merry  *
648d043c564SKenneth D. Merry  * Returns nothing.
649d043c564SKenneth D. Merry  */
650d043c564SKenneth D. Merry static void
651d043c564SKenneth D. Merry _mapping_update_ir_missing_cnt(struct mps_softc *sc, u32 map_idx,
652d043c564SKenneth D. Merry     Mpi2EventIrConfigElement_t *element, u64 wwid)
653d043c564SKenneth D. Merry {
654d043c564SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
655635e58c7SStephen McConnell 	u8 missing_cnt, reason = element->ReasonCode, update_dpm = 1;
656d043c564SKenneth D. Merry 	u16 dpm_idx;
657d043c564SKenneth D. Merry 	Mpi2DriverMap0Entry_t *dpm_entry;
658d043c564SKenneth D. Merry 
659635e58c7SStephen McConnell 	/*
660635e58c7SStephen McConnell 	 * Depending on the reason code, update the missing count. Always set
661635e58c7SStephen McConnell 	 * the init_complete flag when here, so just do it first. That flag is
662635e58c7SStephen McConnell 	 * used for volumes to make sure that the DPM entry has been updated.
663635e58c7SStephen McConnell 	 * When a volume is deleted, clear the map entry's IN_USE flag so that
664635e58c7SStephen McConnell 	 * the entry can be used again if another volume is created. Also clear
665635e58c7SStephen McConnell 	 * its dev_handle entry so that other functions can't find this volume
666635e58c7SStephen McConnell 	 * by the handle, since it's not defined any longer.
667635e58c7SStephen McConnell 	 */
668d043c564SKenneth D. Merry 	mt_entry = &sc->mapping_table[map_idx];
669635e58c7SStephen McConnell 	mt_entry->init_complete = 1;
670635e58c7SStephen McConnell 	if ((reason == MPI2_EVENT_IR_CHANGE_RC_ADDED) ||
671635e58c7SStephen McConnell 	    (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED)) {
672d043c564SKenneth D. Merry 		mt_entry->missing_count = 0;
673635e58c7SStephen McConnell 	} else if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED) {
674d043c564SKenneth D. Merry 		if (mt_entry->missing_count < MPS_MAX_MISSING_COUNT)
675d043c564SKenneth D. Merry 			mt_entry->missing_count++;
676635e58c7SStephen McConnell 
677635e58c7SStephen McConnell 		mt_entry->device_info &= ~MPS_MAP_IN_USE;
678d043c564SKenneth D. Merry 		mt_entry->dev_handle = 0;
679d043c564SKenneth D. Merry 	}
680d043c564SKenneth D. Merry 
681635e58c7SStephen McConnell 	/*
682635e58c7SStephen McConnell 	 * If persistent mapping is enabled, update the DPM with the new missing
683635e58c7SStephen McConnell 	 * count for the volume. If the DPM index is bad, get a free one. If
684635e58c7SStephen McConnell 	 * it's bad for a volume that's being deleted do nothing because that
685635e58c7SStephen McConnell 	 * volume doesn't have a DPM entry.
686635e58c7SStephen McConnell 	 */
687635e58c7SStephen McConnell 	if (!sc->is_dpm_enable)
688635e58c7SStephen McConnell 		return;
689d043c564SKenneth D. Merry 	dpm_idx = mt_entry->dpm_entry_num;
690d043c564SKenneth D. Merry 	if (dpm_idx == MPS_DPM_BAD_IDX) {
691635e58c7SStephen McConnell 		if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED)
692635e58c7SStephen McConnell 		{
693635e58c7SStephen McConnell 			mps_dprint(sc, MPS_MAPPING, "%s: Volume being deleted "
694635e58c7SStephen McConnell 			    "is not in DPM so DPM missing count will not be "
695635e58c7SStephen McConnell 			    "updated.\n", __func__);
696d043c564SKenneth D. Merry 			return;
697d043c564SKenneth D. Merry 		}
698635e58c7SStephen McConnell 	}
699635e58c7SStephen McConnell 	if (dpm_idx == MPS_DPM_BAD_IDX)
700635e58c7SStephen McConnell 		dpm_idx = _mapping_get_free_dpm_idx(sc);
701635e58c7SStephen McConnell 
702635e58c7SStephen McConnell 	/*
703635e58c7SStephen McConnell 	 * Got the DPM entry for the volume or found a free DPM entry if this is
704635e58c7SStephen McConnell 	 * a new volume. Check if the current information is outdated.
705635e58c7SStephen McConnell 	 */
706d043c564SKenneth D. Merry 	if (dpm_idx != MPS_DPM_BAD_IDX) {
707d043c564SKenneth D. Merry 		dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
708d043c564SKenneth D. Merry 		    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
709d043c564SKenneth D. Merry 		dpm_entry += dpm_idx;
710d043c564SKenneth D. Merry 		missing_cnt = dpm_entry->MappingInformation &
711d043c564SKenneth D. Merry 		    MPI2_DRVMAP0_MAPINFO_MISSING_MASK;
712d043c564SKenneth D. Merry 		if ((mt_entry->physical_id ==
713635e58c7SStephen McConnell 		    le64toh(((u64)dpm_entry->PhysicalIdentifier.High << 32) |
714635e58c7SStephen McConnell 		    (u64)dpm_entry->PhysicalIdentifier.Low)) && (missing_cnt ==
715635e58c7SStephen McConnell 		    mt_entry->missing_count)) {
716635e58c7SStephen McConnell 			mps_dprint(sc, MPS_MAPPING, "%s: DPM entry for volume "
717635e58c7SStephen McConnell 			   "with target ID %d does not require an update.\n",
718635e58c7SStephen McConnell 			    __func__, mt_entry->id);
719635e58c7SStephen McConnell 			update_dpm = 0;
720635e58c7SStephen McConnell 		}
721d043c564SKenneth D. Merry 	}
722d043c564SKenneth D. Merry 
723635e58c7SStephen McConnell 	/*
724635e58c7SStephen McConnell 	 * Update the volume's persistent info if it's new or the ID or missing
725635e58c7SStephen McConnell 	 * count has changed. If a good DPM index has not been found by now,
726635e58c7SStephen McConnell 	 * there is no space left in the DPM table.
727635e58c7SStephen McConnell 	 */
728635e58c7SStephen McConnell 	if ((dpm_idx != MPS_DPM_BAD_IDX) && update_dpm) {
729635e58c7SStephen McConnell 		mps_dprint(sc, MPS_MAPPING, "%s: Update DPM entry for volume "
730635e58c7SStephen McConnell 		    "with target ID %d.\n", __func__, mt_entry->id);
731635e58c7SStephen McConnell 
732d043c564SKenneth D. Merry 		mt_entry->dpm_entry_num = dpm_idx;
733d043c564SKenneth D. Merry 		dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
734d043c564SKenneth D. Merry 		    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
735d043c564SKenneth D. Merry 		dpm_entry += dpm_idx;
736d043c564SKenneth D. Merry 		dpm_entry->PhysicalIdentifier.Low =
737d043c564SKenneth D. Merry 		    (0xFFFFFFFF & mt_entry->physical_id);
738d043c564SKenneth D. Merry 		dpm_entry->PhysicalIdentifier.High =
739d043c564SKenneth D. Merry 		    (mt_entry->physical_id >> 32);
740d043c564SKenneth D. Merry 		dpm_entry->DeviceIndex = map_idx;
741d043c564SKenneth D. Merry 		dpm_entry->MappingInformation = mt_entry->missing_count;
742d043c564SKenneth D. Merry 		dpm_entry->PhysicalBitsMapping = 0;
743d043c564SKenneth D. Merry 		dpm_entry->Reserved1 = 0;
744d043c564SKenneth D. Merry 		sc->dpm_flush_entry[dpm_idx] = 1;
745d043c564SKenneth D. Merry 		sc->dpm_entry_used[dpm_idx] = 1;
746d043c564SKenneth D. Merry 	} else if (dpm_idx == MPS_DPM_BAD_IDX) {
747635e58c7SStephen McConnell 		mps_dprint(sc, MPS_INFO | MPS_MAPPING, "%s: No space to add an "
748635e58c7SStephen McConnell 		    "entry in the DPM table for volume with target ID %d.\n",
749635e58c7SStephen McConnell 		    __func__, mt_entry->id);
750d043c564SKenneth D. Merry 	}
751d043c564SKenneth D. Merry }
752d043c564SKenneth D. Merry 
753d043c564SKenneth D. Merry /**
754635e58c7SStephen McConnell  * _mapping_add_to_removal_table - add DPM index to the removal table
755d043c564SKenneth D. Merry  * @sc: per adapter object
756635e58c7SStephen McConnell  * @dpm_idx: Index of DPM entry to remove
757d043c564SKenneth D. Merry  *
758635e58c7SStephen McConnell  * Adds a DPM entry number to the removal table.
759d043c564SKenneth D. Merry  *
760d043c564SKenneth D. Merry  * Returns nothing.
761d043c564SKenneth D. Merry  */
762d043c564SKenneth D. Merry static void
763635e58c7SStephen McConnell _mapping_add_to_removal_table(struct mps_softc *sc, u16 dpm_idx)
764d043c564SKenneth D. Merry {
765d043c564SKenneth D. Merry 	struct map_removal_table *remove_entry;
766d043c564SKenneth D. Merry 	u32 i;
767d043c564SKenneth D. Merry 
768635e58c7SStephen McConnell 	/*
769635e58c7SStephen McConnell 	 * This is only used to remove entries from the DPM in the controller.
770635e58c7SStephen McConnell 	 * If DPM is not enabled, just return.
771635e58c7SStephen McConnell 	 */
772635e58c7SStephen McConnell 	if (!sc->is_dpm_enable)
773635e58c7SStephen McConnell 		return;
774635e58c7SStephen McConnell 
775635e58c7SStephen McConnell 	/*
776635e58c7SStephen McConnell 	 * Find the first available removal_table entry and add the new entry
777635e58c7SStephen McConnell 	 * there.
778635e58c7SStephen McConnell 	 */
779d043c564SKenneth D. Merry 	remove_entry = sc->removal_table;
780d043c564SKenneth D. Merry 
781d043c564SKenneth D. Merry 	for (i = 0; i < sc->max_devices; i++, remove_entry++) {
782635e58c7SStephen McConnell 		if (remove_entry->dpm_entry_num != MPS_DPM_BAD_IDX)
783d043c564SKenneth D. Merry 			continue;
784635e58c7SStephen McConnell 
785635e58c7SStephen McConnell 		mps_dprint(sc, MPS_MAPPING, "%s: Adding DPM entry %d to table "
786635e58c7SStephen McConnell 		    "for removal.\n", __func__, dpm_idx);
787d043c564SKenneth D. Merry 		remove_entry->dpm_entry_num = dpm_idx;
788d043c564SKenneth D. Merry 		break;
789d043c564SKenneth D. Merry 	}
790d043c564SKenneth D. Merry 
791d043c564SKenneth D. Merry }
792d043c564SKenneth D. Merry 
793d043c564SKenneth D. Merry /**
794d043c564SKenneth D. Merry  * _mapping_update_missing_count - Update missing count for a device
795d043c564SKenneth D. Merry  * @sc: per adapter object
796d043c564SKenneth D. Merry  * @topo_change: Topology change event entry
797d043c564SKenneth D. Merry  *
798635e58c7SStephen McConnell  * Increment the missing count in the mapping table for a device that is not
799635e58c7SStephen McConnell  * responding. If Persitent Mapping is used, increment the DPM entry as well.
800635e58c7SStephen McConnell  * Currently, this function only increments the missing count if the device
801635e58c7SStephen McConnell  * goes missing, so after initialization has completed. This means that the
802635e58c7SStephen McConnell  * missing count can only go from 0 to 1 here. The missing count is incremented
803635e58c7SStephen McConnell  * during initialization as well, so that's where a target's missing count can
804635e58c7SStephen McConnell  * go past 1.
805d043c564SKenneth D. Merry  *
806d043c564SKenneth D. Merry  * Returns nothing.
807d043c564SKenneth D. Merry  */
808d043c564SKenneth D. Merry static void
809d043c564SKenneth D. Merry _mapping_update_missing_count(struct mps_softc *sc,
810d043c564SKenneth D. Merry     struct _map_topology_change *topo_change)
811d043c564SKenneth D. Merry {
812d043c564SKenneth D. Merry 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
813d043c564SKenneth D. Merry 	u8 entry;
814d043c564SKenneth D. Merry 	struct _map_phy_change *phy_change;
815d043c564SKenneth D. Merry 	u32 map_idx;
816d043c564SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
817d043c564SKenneth D. Merry 	Mpi2DriverMap0Entry_t *dpm_entry;
818d043c564SKenneth D. Merry 
819d043c564SKenneth D. Merry 	for (entry = 0; entry < topo_change->num_entries; entry++) {
820d043c564SKenneth D. Merry 		phy_change = &topo_change->phy_details[entry];
821d043c564SKenneth D. Merry 		if (!phy_change->dev_handle || (phy_change->reason !=
822d043c564SKenneth D. Merry 		    MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING))
823d043c564SKenneth D. Merry 			continue;
824d043c564SKenneth D. Merry 		map_idx = _mapping_get_mt_idx_from_handle(sc, phy_change->
825d043c564SKenneth D. Merry 		    dev_handle);
826d043c564SKenneth D. Merry 		phy_change->is_processed = 1;
827d043c564SKenneth D. Merry 		if (map_idx == MPS_MAPTABLE_BAD_IDX) {
828635e58c7SStephen McConnell 			mps_dprint(sc, MPS_INFO | MPS_MAPPING, "%s: device is "
829635e58c7SStephen McConnell 			    "already removed from mapping table\n", __func__);
830d043c564SKenneth D. Merry 			continue;
831d043c564SKenneth D. Merry 		}
832d043c564SKenneth D. Merry 		mt_entry = &sc->mapping_table[map_idx];
833d043c564SKenneth D. Merry 		if (mt_entry->missing_count < MPS_MAX_MISSING_COUNT)
834d043c564SKenneth D. Merry 			mt_entry->missing_count++;
835d043c564SKenneth D. Merry 
836635e58c7SStephen McConnell 		/*
837635e58c7SStephen McConnell 		 * When using Enc/Slot mapping, when a device is removed, it's
838635e58c7SStephen McConnell 		 * mapping table information should be cleared. Otherwise, the
839635e58c7SStephen McConnell 		 * target ID will be incorrect if this same device is re-added
840635e58c7SStephen McConnell 		 * to a different slot.
841635e58c7SStephen McConnell 		 */
842635e58c7SStephen McConnell 		if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
843635e58c7SStephen McConnell 		    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
844635e58c7SStephen McConnell 			_mapping_clear_map_entry(mt_entry);
845635e58c7SStephen McConnell 		}
846635e58c7SStephen McConnell 
847635e58c7SStephen McConnell 		/*
848635e58c7SStephen McConnell 		 * When using device mapping, update the missing count in the
849635e58c7SStephen McConnell 		 * DPM entry, but only if the missing count has changed.
850635e58c7SStephen McConnell 		 */
851d043c564SKenneth D. Merry 		if (((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
852d043c564SKenneth D. Merry 		    MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) &&
853635e58c7SStephen McConnell 		    sc->is_dpm_enable &&
854d043c564SKenneth D. Merry 		    mt_entry->dpm_entry_num != MPS_DPM_BAD_IDX) {
855d043c564SKenneth D. Merry 			dpm_entry =
856d043c564SKenneth D. Merry 			    (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 +
857d043c564SKenneth D. Merry 			    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
858d043c564SKenneth D. Merry 			dpm_entry += mt_entry->dpm_entry_num;
859635e58c7SStephen McConnell 			if (dpm_entry->MappingInformation !=
860635e58c7SStephen McConnell 			    mt_entry->missing_count) {
861635e58c7SStephen McConnell 				dpm_entry->MappingInformation =
862635e58c7SStephen McConnell 				    mt_entry->missing_count;
863635e58c7SStephen McConnell 				sc->dpm_flush_entry[mt_entry->dpm_entry_num] =
864635e58c7SStephen McConnell 				    1;
865d043c564SKenneth D. Merry 			}
866635e58c7SStephen McConnell 		}
867d043c564SKenneth D. Merry 	}
868d043c564SKenneth D. Merry }
869d043c564SKenneth D. Merry 
870d043c564SKenneth D. Merry /**
871d043c564SKenneth D. Merry  * _mapping_find_enc_map_space -find map table entries for enclosure
872d043c564SKenneth D. Merry  * @sc: per adapter object
873d043c564SKenneth D. Merry  * @et_entry: enclosure entry
874d043c564SKenneth D. Merry  *
875d043c564SKenneth D. Merry  * Search through the mapping table defragment it and provide contiguous
876d043c564SKenneth D. Merry  * space in map table for a particular enclosure entry
877d043c564SKenneth D. Merry  *
878d043c564SKenneth D. Merry  * Returns start index in map table or bad index.
879d043c564SKenneth D. Merry  */
880d043c564SKenneth D. Merry static u32
881d043c564SKenneth D. Merry _mapping_find_enc_map_space(struct mps_softc *sc,
882d043c564SKenneth D. Merry     struct enc_mapping_table *et_entry)
883d043c564SKenneth D. Merry {
884d043c564SKenneth D. Merry 	u16 vol_mapping_flags;
885d043c564SKenneth D. Merry 	u32 skip_count, end_of_table, map_idx, enc_idx;
886d043c564SKenneth D. Merry 	u16 num_found;
887d043c564SKenneth D. Merry 	u32 start_idx = MPS_MAPTABLE_BAD_IDX;
888d043c564SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
889d043c564SKenneth D. Merry 	struct enc_mapping_table *enc_entry;
890d043c564SKenneth D. Merry 	unsigned char done_flag = 0, found_space;
891d043c564SKenneth D. Merry 	u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs);
892d043c564SKenneth D. Merry 
893d043c564SKenneth D. Merry 	skip_count = sc->num_rsvd_entries;
894d043c564SKenneth D. Merry 	num_found = 0;
895d043c564SKenneth D. Merry 
896d043c564SKenneth D. Merry 	vol_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) &
897d043c564SKenneth D. Merry 	    MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
898d043c564SKenneth D. Merry 
899635e58c7SStephen McConnell 	/*
900635e58c7SStephen McConnell 	 * The end of the mapping table depends on where volumes are kept, if
901635e58c7SStephen McConnell 	 * IR is enabled.
902635e58c7SStephen McConnell 	 */
903d043c564SKenneth D. Merry 	if (!sc->ir_firmware)
904d043c564SKenneth D. Merry 		end_of_table = sc->max_devices;
905d043c564SKenneth D. Merry 	else if (vol_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING)
906d043c564SKenneth D. Merry 		end_of_table = sc->max_devices;
907d043c564SKenneth D. Merry 	else
908d043c564SKenneth D. Merry 		end_of_table = sc->max_devices - sc->max_volumes;
909d043c564SKenneth D. Merry 
910635e58c7SStephen McConnell 	/*
911635e58c7SStephen McConnell 	 * The skip_count is the number of entries that are reserved at the
912635e58c7SStephen McConnell 	 * beginning of the mapping table. But, it does not include the number
913635e58c7SStephen McConnell 	 * of Physical IDs that are reserved for direct attached devices. Look
914635e58c7SStephen McConnell 	 * through the mapping table after these reserved entries to see if
915635e58c7SStephen McConnell 	 * the devices for this enclosure are already mapped. The PHY bit check
916635e58c7SStephen McConnell 	 * is used to make sure that at least one PHY bit is common between the
917635e58c7SStephen McConnell 	 * enclosure and the device that is already mapped.
918635e58c7SStephen McConnell 	 */
919635e58c7SStephen McConnell 	mps_dprint(sc, MPS_MAPPING, "%s: Looking for space in the mapping "
920635e58c7SStephen McConnell 	    "table for added enclosure.\n", __func__);
921d043c564SKenneth D. Merry 	for (map_idx = (max_num_phy_ids + skip_count);
922d043c564SKenneth D. Merry 	    map_idx < end_of_table; map_idx++) {
923d043c564SKenneth D. Merry 		mt_entry = &sc->mapping_table[map_idx];
924d043c564SKenneth D. Merry 		if ((et_entry->enclosure_id == mt_entry->physical_id) &&
925d043c564SKenneth D. Merry 		    (!mt_entry->phy_bits || (mt_entry->phy_bits &
926d043c564SKenneth D. Merry 		    et_entry->phy_bits))) {
927d043c564SKenneth D. Merry 			num_found += 1;
928d043c564SKenneth D. Merry 			if (num_found == et_entry->num_slots) {
929d043c564SKenneth D. Merry 				start_idx = (map_idx - num_found) + 1;
930635e58c7SStephen McConnell 				mps_dprint(sc, MPS_MAPPING, "%s: Found space "
931635e58c7SStephen McConnell 				    "in the mapping for enclosure at map index "
932635e58c7SStephen McConnell 				    "%d.\n", __func__, start_idx);
933d043c564SKenneth D. Merry 				return start_idx;
934d043c564SKenneth D. Merry 			}
935d043c564SKenneth D. Merry 		} else
936d043c564SKenneth D. Merry 			num_found = 0;
937d043c564SKenneth D. Merry 	}
938635e58c7SStephen McConnell 
939635e58c7SStephen McConnell 	/*
940635e58c7SStephen McConnell 	 * If the enclosure's devices are not mapped already, look for
941635e58c7SStephen McConnell 	 * contiguous entries in the mapping table that are not reserved. If
942635e58c7SStephen McConnell 	 * enough entries are found, return the starting index for that space.
943635e58c7SStephen McConnell 	 */
944635e58c7SStephen McConnell 	num_found = 0;
945d043c564SKenneth D. Merry 	for (map_idx = (max_num_phy_ids + skip_count);
946d043c564SKenneth D. Merry 	    map_idx < end_of_table; map_idx++) {
947d043c564SKenneth D. Merry 		mt_entry = &sc->mapping_table[map_idx];
948d043c564SKenneth D. Merry 		if (!(mt_entry->device_info & MPS_DEV_RESERVED)) {
949d043c564SKenneth D. Merry 			num_found += 1;
950d043c564SKenneth D. Merry 			if (num_found == et_entry->num_slots) {
951d043c564SKenneth D. Merry 				start_idx = (map_idx - num_found) + 1;
952635e58c7SStephen McConnell 				mps_dprint(sc, MPS_MAPPING, "%s: Found space "
953635e58c7SStephen McConnell 				    "in the mapping for enclosure at map index "
954635e58c7SStephen McConnell 				    "%d.\n", __func__, start_idx);
955d043c564SKenneth D. Merry 				return start_idx;
956d043c564SKenneth D. Merry 			}
957d043c564SKenneth D. Merry 		} else
958d043c564SKenneth D. Merry 			num_found = 0;
959d043c564SKenneth D. Merry 	}
960d043c564SKenneth D. Merry 
961635e58c7SStephen McConnell 	/*
962635e58c7SStephen McConnell 	 * If here, it means that not enough space in the mapping table was
963635e58c7SStephen McConnell 	 * found to support this enclosure, so go through the enclosure table to
964635e58c7SStephen McConnell 	 * see if any enclosure entries have a missing count. If so, get the
965635e58c7SStephen McConnell 	 * enclosure with the highest missing count and check it to see if there
966635e58c7SStephen McConnell 	 * is enough space for the new enclosure.
967635e58c7SStephen McConnell 	 */
968d043c564SKenneth D. Merry 	while (!done_flag) {
969d043c564SKenneth D. Merry 		enc_idx = _mapping_get_high_missing_et_idx(sc);
970635e58c7SStephen McConnell 		if (enc_idx == MPS_ENCTABLE_BAD_IDX) {
971635e58c7SStephen McConnell 			mps_dprint(sc, MPS_MAPPING, "%s: Not enough space was "
972635e58c7SStephen McConnell 			    "found in the mapping for the added enclosure.\n",
973635e58c7SStephen McConnell 			    __func__);
974d043c564SKenneth D. Merry 			return MPS_MAPTABLE_BAD_IDX;
975635e58c7SStephen McConnell 		}
976635e58c7SStephen McConnell 
977635e58c7SStephen McConnell 		/*
978635e58c7SStephen McConnell 		 * Found a missing enclosure. Set the skip_search flag so this
979635e58c7SStephen McConnell 		 * enclosure is not checked again for a high missing count if
980635e58c7SStephen McConnell 		 * the loop continues. This way, all missing enclosures can
981635e58c7SStephen McConnell 		 * have their space added together to find enough space in the
982635e58c7SStephen McConnell 		 * mapping table for the added enclosure. The space must be
983635e58c7SStephen McConnell 		 * contiguous.
984635e58c7SStephen McConnell 		 */
985635e58c7SStephen McConnell 		mps_dprint(sc, MPS_MAPPING, "%s: Space from a missing "
986635e58c7SStephen McConnell 		    "enclosure was found.\n", __func__);
987d043c564SKenneth D. Merry 		enc_entry = &sc->enclosure_table[enc_idx];
988d043c564SKenneth D. Merry 		enc_entry->skip_search = 1;
989635e58c7SStephen McConnell 
990635e58c7SStephen McConnell 		/*
991635e58c7SStephen McConnell 		 * Unmark all of the missing enclosure's device's reserved
992635e58c7SStephen McConnell 		 * space. These will be remarked as reserved if this missing
993635e58c7SStephen McConnell 		 * enclosure's space is not used.
994635e58c7SStephen McConnell 		 */
995635e58c7SStephen McConnell 		mps_dprint(sc, MPS_MAPPING, "%s: Clear the reserved flag for "
996635e58c7SStephen McConnell 		    "all of the map entries for the enclosure.\n", __func__);
997d043c564SKenneth D. Merry 		mt_entry = &sc->mapping_table[enc_entry->start_index];
998d043c564SKenneth D. Merry 		for (map_idx = enc_entry->start_index; map_idx <
999d043c564SKenneth D. Merry 		    (enc_entry->start_index + enc_entry->num_slots); map_idx++,
1000d043c564SKenneth D. Merry 		    mt_entry++)
1001d043c564SKenneth D. Merry 			mt_entry->device_info &= ~MPS_DEV_RESERVED;
1002635e58c7SStephen McConnell 
1003635e58c7SStephen McConnell 		/*
1004635e58c7SStephen McConnell 		 * Now that space has been unreserved, check again to see if
1005635e58c7SStephen McConnell 		 * enough space is available for the new enclosure.
1006635e58c7SStephen McConnell 		 */
1007635e58c7SStephen McConnell 		mps_dprint(sc, MPS_MAPPING, "%s: Check if new mapping space is "
1008635e58c7SStephen McConnell 		    "enough for the new enclosure.\n", __func__);
1009d043c564SKenneth D. Merry 		found_space = 0;
1010635e58c7SStephen McConnell 		num_found = 0;
1011635e58c7SStephen McConnell 		for (map_idx = (max_num_phy_ids + skip_count);
1012635e58c7SStephen McConnell 		    map_idx < end_of_table; map_idx++) {
1013d043c564SKenneth D. Merry 			mt_entry = &sc->mapping_table[map_idx];
1014d043c564SKenneth D. Merry 			if (!(mt_entry->device_info & MPS_DEV_RESERVED)) {
1015d043c564SKenneth D. Merry 				num_found += 1;
1016d043c564SKenneth D. Merry 				if (num_found == et_entry->num_slots) {
1017d043c564SKenneth D. Merry 					start_idx = (map_idx - num_found) + 1;
1018d043c564SKenneth D. Merry 					found_space = 1;
1019635e58c7SStephen McConnell 					break;
1020d043c564SKenneth D. Merry 				}
1021d043c564SKenneth D. Merry 			} else
1022d043c564SKenneth D. Merry 				num_found = 0;
1023d043c564SKenneth D. Merry 		}
1024d043c564SKenneth D. Merry 		if (!found_space)
1025d043c564SKenneth D. Merry 			continue;
1026635e58c7SStephen McConnell 
1027635e58c7SStephen McConnell 		/*
1028635e58c7SStephen McConnell 		 * If enough space was found, all of the missing enclosures that
1029635e58c7SStephen McConnell 		 * will be used for the new enclosure must be added to the
1030635e58c7SStephen McConnell 		 * removal table. Then all mappings for the enclosure's devices
1031635e58c7SStephen McConnell 		 * and for the enclosure itself need to be cleared. There may be
1032635e58c7SStephen McConnell 		 * more than one enclosure to add to the removal table and
1033635e58c7SStephen McConnell 		 * clear.
1034635e58c7SStephen McConnell 		 */
1035635e58c7SStephen McConnell 		mps_dprint(sc, MPS_MAPPING, "%s: Found space in the mapping "
1036635e58c7SStephen McConnell 		    "for enclosure at map index %d.\n", __func__, start_idx);
1037d043c564SKenneth D. Merry 		for (map_idx = start_idx; map_idx < (start_idx + num_found);
1038d043c564SKenneth D. Merry 		    map_idx++) {
1039d043c564SKenneth D. Merry 			enc_entry = sc->enclosure_table;
1040d043c564SKenneth D. Merry 			for (enc_idx = 0; enc_idx < sc->num_enc_table_entries;
1041d043c564SKenneth D. Merry 			    enc_idx++, enc_entry++) {
1042d043c564SKenneth D. Merry 				if (map_idx < enc_entry->start_index ||
1043d043c564SKenneth D. Merry 				    map_idx > (enc_entry->start_index +
1044d043c564SKenneth D. Merry 				    enc_entry->num_slots))
1045d043c564SKenneth D. Merry 					continue;
1046d043c564SKenneth D. Merry 				if (!enc_entry->removal_flag) {
1047635e58c7SStephen McConnell 					mps_dprint(sc, MPS_MAPPING, "%s: "
1048635e58c7SStephen McConnell 					    "Enclosure %d will be removed from "
1049635e58c7SStephen McConnell 					    "the mapping table.\n", __func__,
1050635e58c7SStephen McConnell 					    enc_idx);
1051d043c564SKenneth D. Merry 					enc_entry->removal_flag = 1;
1052635e58c7SStephen McConnell 					_mapping_add_to_removal_table(sc,
1053d043c564SKenneth D. Merry 					    enc_entry->dpm_entry_num);
1054d043c564SKenneth D. Merry 				}
1055d043c564SKenneth D. Merry 				mt_entry = &sc->mapping_table[map_idx];
1056d043c564SKenneth D. Merry 				_mapping_clear_map_entry(mt_entry);
1057d043c564SKenneth D. Merry 				if (map_idx == (enc_entry->start_index +
1058d043c564SKenneth D. Merry 				    enc_entry->num_slots - 1))
1059d043c564SKenneth D. Merry 					_mapping_clear_enc_entry(et_entry);
1060d043c564SKenneth D. Merry 			}
1061d043c564SKenneth D. Merry 		}
1062635e58c7SStephen McConnell 
1063635e58c7SStephen McConnell 		/*
1064635e58c7SStephen McConnell 		 * During the search for space for this enclosure, some entries
1065635e58c7SStephen McConnell 		 * in the mapping table may have been unreserved. Go back and
1066635e58c7SStephen McConnell 		 * change all of these to reserved again. Only the enclosures
1067635e58c7SStephen McConnell 		 * with the removal_flag set should be left as unreserved. The
1068635e58c7SStephen McConnell 		 * skip_search flag needs to be cleared as well so that the
1069635e58c7SStephen McConnell 		 * enclosure's space will be looked at the next time space is
1070635e58c7SStephen McConnell 		 * needed.
1071635e58c7SStephen McConnell 		 */
1072d043c564SKenneth D. Merry 		enc_entry = sc->enclosure_table;
1073d043c564SKenneth D. Merry 		for (enc_idx = 0; enc_idx < sc->num_enc_table_entries;
1074d043c564SKenneth D. Merry 		    enc_idx++, enc_entry++) {
1075d043c564SKenneth D. Merry 			if (!enc_entry->removal_flag) {
1076635e58c7SStephen McConnell 				mps_dprint(sc, MPS_MAPPING, "%s: Reset the "
1077635e58c7SStephen McConnell 				    "reserved flag for all of the map entries "
1078635e58c7SStephen McConnell 				    "for enclosure %d.\n", __func__, enc_idx);
1079d043c564SKenneth D. Merry 				mt_entry = &sc->mapping_table[enc_entry->
1080d043c564SKenneth D. Merry 				    start_index];
1081d043c564SKenneth D. Merry 				for (map_idx = enc_entry->start_index; map_idx <
1082d043c564SKenneth D. Merry 				    (enc_entry->start_index +
1083d043c564SKenneth D. Merry 				    enc_entry->num_slots); map_idx++,
1084d043c564SKenneth D. Merry 				    mt_entry++)
1085d043c564SKenneth D. Merry 					mt_entry->device_info |=
1086d043c564SKenneth D. Merry 					    MPS_DEV_RESERVED;
1087d043c564SKenneth D. Merry 				et_entry->skip_search = 0;
1088d043c564SKenneth D. Merry 			}
1089d043c564SKenneth D. Merry 		}
1090d043c564SKenneth D. Merry 		done_flag = 1;
1091d043c564SKenneth D. Merry 	}
1092d043c564SKenneth D. Merry 	return start_idx;
1093d043c564SKenneth D. Merry }
1094d043c564SKenneth D. Merry 
1095d043c564SKenneth D. Merry /**
1096d043c564SKenneth D. Merry  * _mapping_get_dev_info -get information about newly added devices
1097d043c564SKenneth D. Merry  * @sc: per adapter object
1098d043c564SKenneth D. Merry  * @topo_change: Topology change event entry
1099d043c564SKenneth D. Merry  *
1100d043c564SKenneth D. Merry  * Search through the topology change event list and issues sas device pg0
1101d043c564SKenneth D. Merry  * requests for the newly added device and reserved entries in tables
1102d043c564SKenneth D. Merry  *
1103d043c564SKenneth D. Merry  * Returns nothing
1104d043c564SKenneth D. Merry  */
1105d043c564SKenneth D. Merry static void
1106d043c564SKenneth D. Merry _mapping_get_dev_info(struct mps_softc *sc,
1107d043c564SKenneth D. Merry     struct _map_topology_change *topo_change)
1108d043c564SKenneth D. Merry {
1109d043c564SKenneth D. Merry 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
1110d043c564SKenneth D. Merry 	Mpi2ConfigReply_t mpi_reply;
1111d043c564SKenneth D. Merry 	Mpi2SasDevicePage0_t sas_device_pg0;
1112bfa3cf97SMarcelo Araujo 	u8 entry, enc_idx, phy_idx;
1113d043c564SKenneth D. Merry 	u32 map_idx, index, device_info;
1114d043c564SKenneth D. Merry 	struct _map_phy_change *phy_change, *tmp_phy_change;
1115d043c564SKenneth D. Merry 	uint64_t sas_address;
1116d043c564SKenneth D. Merry 	struct enc_mapping_table *et_entry;
1117d043c564SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
1118d043c564SKenneth D. Merry 	u8 add_code = MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED;
1119ef065d89SStephen McConnell 	int rc = 1;
1120d043c564SKenneth D. Merry 
1121d043c564SKenneth D. Merry 	for (entry = 0; entry < topo_change->num_entries; entry++) {
1122d043c564SKenneth D. Merry 		phy_change = &topo_change->phy_details[entry];
1123d043c564SKenneth D. Merry 		if (phy_change->is_processed || !phy_change->dev_handle ||
1124d043c564SKenneth D. Merry 		    phy_change->reason != MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED)
1125d043c564SKenneth D. Merry 			continue;
1126635e58c7SStephen McConnell 
1127d043c564SKenneth D. Merry 		if (mps_config_get_sas_device_pg0(sc, &mpi_reply,
1128d043c564SKenneth D. Merry 		    &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
1129d043c564SKenneth D. Merry 		    phy_change->dev_handle)) {
1130d043c564SKenneth D. Merry 			phy_change->is_processed = 1;
1131d043c564SKenneth D. Merry 			continue;
1132d043c564SKenneth D. Merry 		}
1133d043c564SKenneth D. Merry 
1134ef065d89SStephen McConnell 		/*
1135ef065d89SStephen McConnell 		 * Always get SATA Identify information because this is used
1136ef065d89SStephen McConnell 		 * to determine if Start/Stop Unit should be sent to the drive
1137ef065d89SStephen McConnell 		 * when the system is shutdown.
1138ef065d89SStephen McConnell 		 */
1139d043c564SKenneth D. Merry 		device_info = le32toh(sas_device_pg0.DeviceInfo);
1140635e58c7SStephen McConnell 		sas_address = le32toh(sas_device_pg0.SASAddress.High);
1141d043c564SKenneth D. Merry 		sas_address = (sas_address << 32) |
1142635e58c7SStephen McConnell 		    le32toh(sas_device_pg0.SASAddress.Low);
1143ef065d89SStephen McConnell 		if ((device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE) &&
1144ef065d89SStephen McConnell 		    (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)) {
1145ef065d89SStephen McConnell 			rc = mpssas_get_sas_address_for_sata_disk(sc,
1146ef065d89SStephen McConnell 			    &sas_address, phy_change->dev_handle, device_info,
1147ef065d89SStephen McConnell 			    &phy_change->is_SATA_SSD);
1148ef065d89SStephen McConnell 			if (rc) {
1149ef065d89SStephen McConnell 				mps_dprint(sc, MPS_ERROR, "%s: failed to get "
1150ef065d89SStephen McConnell 				    "disk type (SSD or HDD) and SAS Address "
1151ef065d89SStephen McConnell 				    "for SATA device with handle 0x%04x\n",
1152ef065d89SStephen McConnell 				    __func__, phy_change->dev_handle);
1153d043c564SKenneth D. Merry 			}
1154ef065d89SStephen McConnell 		}
1155ef065d89SStephen McConnell 
1156d043c564SKenneth D. Merry 		phy_change->physical_id = sas_address;
1157d043c564SKenneth D. Merry 		phy_change->slot = le16toh(sas_device_pg0.Slot);
1158635e58c7SStephen McConnell 		phy_change->device_info = device_info;
1159d043c564SKenneth D. Merry 
1160635e58c7SStephen McConnell 		/*
1161635e58c7SStephen McConnell 		 * When using Enc/Slot mapping, if this device is an enclosure
1162635e58c7SStephen McConnell 		 * make sure that all of its slots can fit into the mapping
1163635e58c7SStephen McConnell 		 * table.
1164635e58c7SStephen McConnell 		 */
1165d043c564SKenneth D. Merry 		if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
1166d043c564SKenneth D. Merry 		    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
1167635e58c7SStephen McConnell 			/*
1168635e58c7SStephen McConnell 			 * The enclosure should already be in the enclosure
1169635e58c7SStephen McConnell 			 * table due to the Enclosure Add event. If not, just
1170635e58c7SStephen McConnell 			 * continue, nothing can be done.
1171635e58c7SStephen McConnell 			 */
1172d043c564SKenneth D. Merry 			enc_idx = _mapping_get_enc_idx_from_handle(sc,
1173d043c564SKenneth D. Merry 			    topo_change->enc_handle);
1174d043c564SKenneth D. Merry 			if (enc_idx == MPS_ENCTABLE_BAD_IDX) {
1175d043c564SKenneth D. Merry 				phy_change->is_processed = 1;
1176635e58c7SStephen McConnell 				mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: "
1177635e58c7SStephen McConnell 				    "failed to add the device with handle "
1178*b99419aeSAlexander Motin 				    "0x%04x because enclosure handle 0x%04x "
1179*b99419aeSAlexander Motin 				    "is not in the mapping table\n", __func__,
1180*b99419aeSAlexander Motin 				    phy_change->dev_handle,
1181*b99419aeSAlexander Motin 				    topo_change->enc_handle);
1182d043c564SKenneth D. Merry 				continue;
1183d043c564SKenneth D. Merry 			}
1184d043c564SKenneth D. Merry 			if (!((phy_change->device_info &
1185d043c564SKenneth D. Merry 			    MPI2_SAS_DEVICE_INFO_END_DEVICE) &&
1186d043c564SKenneth D. Merry 			    (phy_change->device_info &
1187d043c564SKenneth D. Merry 			    (MPI2_SAS_DEVICE_INFO_SSP_TARGET |
1188d043c564SKenneth D. Merry 			    MPI2_SAS_DEVICE_INFO_STP_TARGET |
1189d043c564SKenneth D. Merry 			    MPI2_SAS_DEVICE_INFO_SATA_DEVICE)))) {
1190d043c564SKenneth D. Merry 				phy_change->is_processed = 1;
1191d043c564SKenneth D. Merry 				continue;
1192d043c564SKenneth D. Merry 			}
1193d043c564SKenneth D. Merry 			et_entry = &sc->enclosure_table[enc_idx];
1194635e58c7SStephen McConnell 
1195635e58c7SStephen McConnell 			/*
1196635e58c7SStephen McConnell 			 * If the enclosure already has a start_index, it's been
1197635e58c7SStephen McConnell 			 * mapped, so go to the next Topo change.
1198635e58c7SStephen McConnell 			 */
1199d043c564SKenneth D. Merry 			if (et_entry->start_index != MPS_MAPTABLE_BAD_IDX)
1200d043c564SKenneth D. Merry 				continue;
1201635e58c7SStephen McConnell 
1202635e58c7SStephen McConnell 			/*
1203635e58c7SStephen McConnell 			 * If the Expander Handle is 0, the devices are direct
1204635e58c7SStephen McConnell 			 * attached. In that case, the start_index must be just
1205635e58c7SStephen McConnell 			 * after the reserved entries. Otherwise, find space in
1206635e58c7SStephen McConnell 			 * the mapping table for the enclosure's devices.
1207635e58c7SStephen McConnell 			 */
1208d043c564SKenneth D. Merry 			if (!topo_change->exp_handle) {
1209d043c564SKenneth D. Merry 				map_idx	= sc->num_rsvd_entries;
1210d043c564SKenneth D. Merry 				et_entry->start_index = map_idx;
1211d043c564SKenneth D. Merry 			} else {
1212d043c564SKenneth D. Merry 				map_idx = _mapping_find_enc_map_space(sc,
1213d043c564SKenneth D. Merry 				    et_entry);
1214d043c564SKenneth D. Merry 				et_entry->start_index = map_idx;
1215635e58c7SStephen McConnell 
1216635e58c7SStephen McConnell 				/*
1217635e58c7SStephen McConnell 				 * If space cannot be found to hold all of the
1218635e58c7SStephen McConnell 				 * enclosure's devices in the mapping table,
1219635e58c7SStephen McConnell 				 * there's no need to continue checking the
1220635e58c7SStephen McConnell 				 * other devices in this event. Set all of the
1221635e58c7SStephen McConnell 				 * phy_details for this event (if the change is
1222635e58c7SStephen McConnell 				 * for an add) as already processed because none
1223635e58c7SStephen McConnell 				 * of these devices can be added to the mapping
1224635e58c7SStephen McConnell 				 * table.
1225635e58c7SStephen McConnell 				 */
1226d043c564SKenneth D. Merry 				if (et_entry->start_index ==
1227d043c564SKenneth D. Merry 				    MPS_MAPTABLE_BAD_IDX) {
1228635e58c7SStephen McConnell 					mps_dprint(sc, MPS_ERROR | MPS_MAPPING,
1229635e58c7SStephen McConnell 					    "%s: failed to add the enclosure "
1230635e58c7SStephen McConnell 					    "with ID 0x%016jx because there is "
1231635e58c7SStephen McConnell 					    "no free space available in the "
1232635e58c7SStephen McConnell 					    "mapping table for all of the "
1233635e58c7SStephen McConnell 					    "enclosure's devices.\n", __func__,
1234635e58c7SStephen McConnell 					    (uintmax_t)et_entry->enclosure_id);
1235d043c564SKenneth D. Merry 					phy_change->is_processed = 1;
1236d043c564SKenneth D. Merry 					for (phy_idx = 0; phy_idx <
1237d043c564SKenneth D. Merry 					    topo_change->num_entries;
1238d043c564SKenneth D. Merry 					    phy_idx++) {
1239d043c564SKenneth D. Merry 						tmp_phy_change =
1240d043c564SKenneth D. Merry 						    &topo_change->phy_details
1241d043c564SKenneth D. Merry 						    [phy_idx];
1242d043c564SKenneth D. Merry 						if (tmp_phy_change->reason ==
1243d043c564SKenneth D. Merry 						    add_code)
1244d043c564SKenneth D. Merry 							tmp_phy_change->
1245d043c564SKenneth D. Merry 							    is_processed = 1;
1246d043c564SKenneth D. Merry 					}
1247d043c564SKenneth D. Merry 					break;
1248d043c564SKenneth D. Merry 				}
1249d043c564SKenneth D. Merry 			}
1250635e58c7SStephen McConnell 
1251635e58c7SStephen McConnell 			/*
1252635e58c7SStephen McConnell 			 * Found space in the mapping table for this enclosure.
1253635e58c7SStephen McConnell 			 * Initialize each mapping table entry for the
1254635e58c7SStephen McConnell 			 * enclosure.
1255635e58c7SStephen McConnell 			 */
1256635e58c7SStephen McConnell 			mps_dprint(sc, MPS_MAPPING, "%s: Initialize %d map "
1257635e58c7SStephen McConnell 			    "entries for the enclosure, starting at map index "
1258635e58c7SStephen McConnell 			    " %d.\n", __func__, et_entry->num_slots, map_idx);
1259d043c564SKenneth D. Merry 			mt_entry = &sc->mapping_table[map_idx];
1260d043c564SKenneth D. Merry 			for (index = map_idx; index < (et_entry->num_slots
1261d043c564SKenneth D. Merry 			    + map_idx); index++, mt_entry++) {
1262d043c564SKenneth D. Merry 				mt_entry->device_info = MPS_DEV_RESERVED;
1263d043c564SKenneth D. Merry 				mt_entry->physical_id = et_entry->enclosure_id;
1264d043c564SKenneth D. Merry 				mt_entry->phy_bits = et_entry->phy_bits;
1265635e58c7SStephen McConnell 				mt_entry->missing_count = 0;
1266d043c564SKenneth D. Merry 			}
1267d043c564SKenneth D. Merry 		}
1268d043c564SKenneth D. Merry 	}
1269d043c564SKenneth D. Merry }
1270d043c564SKenneth D. Merry 
1271d043c564SKenneth D. Merry /**
1272d043c564SKenneth D. Merry  * _mapping_set_mid_to_eid -set map table data from enclosure table
1273d043c564SKenneth D. Merry  * @sc: per adapter object
1274d043c564SKenneth D. Merry  * @et_entry: enclosure entry
1275d043c564SKenneth D. Merry  *
1276d043c564SKenneth D. Merry  * Returns nothing
1277d043c564SKenneth D. Merry  */
1278d043c564SKenneth D. Merry static inline void
1279d043c564SKenneth D. Merry _mapping_set_mid_to_eid(struct mps_softc *sc,
1280d043c564SKenneth D. Merry     struct enc_mapping_table *et_entry)
1281d043c564SKenneth D. Merry {
1282d043c564SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
1283d043c564SKenneth D. Merry 	u16 slots = et_entry->num_slots, map_idx;
1284d043c564SKenneth D. Merry 	u32 start_idx = et_entry->start_index;
1285635e58c7SStephen McConnell 
1286d043c564SKenneth D. Merry 	if (start_idx != MPS_MAPTABLE_BAD_IDX) {
1287d043c564SKenneth D. Merry 		mt_entry = &sc->mapping_table[start_idx];
1288d043c564SKenneth D. Merry 		for (map_idx = 0; map_idx < slots; map_idx++, mt_entry++)
1289d043c564SKenneth D. Merry 			mt_entry->physical_id = et_entry->enclosure_id;
1290d043c564SKenneth D. Merry 	}
1291d043c564SKenneth D. Merry }
1292d043c564SKenneth D. Merry 
1293d043c564SKenneth D. Merry /**
1294d043c564SKenneth D. Merry  * _mapping_clear_removed_entries - mark the entries to be cleared
1295d043c564SKenneth D. Merry  * @sc: per adapter object
1296d043c564SKenneth D. Merry  *
1297d043c564SKenneth D. Merry  * Search through the removal table and mark the entries which needs to be
1298d043c564SKenneth D. Merry  * flushed to DPM and also updates the map table and enclosure table by
1299d043c564SKenneth D. Merry  * clearing the corresponding entries.
1300d043c564SKenneth D. Merry  *
1301d043c564SKenneth D. Merry  * Returns nothing
1302d043c564SKenneth D. Merry  */
1303d043c564SKenneth D. Merry static void
1304d043c564SKenneth D. Merry _mapping_clear_removed_entries(struct mps_softc *sc)
1305d043c564SKenneth D. Merry {
1306d043c564SKenneth D. Merry 	u32 remove_idx;
1307d043c564SKenneth D. Merry 	struct map_removal_table *remove_entry;
1308d043c564SKenneth D. Merry 	Mpi2DriverMap0Entry_t *dpm_entry;
1309d043c564SKenneth D. Merry 	u8 done_flag = 0, num_entries, m, i;
1310d043c564SKenneth D. Merry 	struct enc_mapping_table *et_entry, *from, *to;
1311d043c564SKenneth D. Merry 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
1312d043c564SKenneth D. Merry 
1313d043c564SKenneth D. Merry 	if (sc->is_dpm_enable) {
1314d043c564SKenneth D. Merry 		remove_entry = sc->removal_table;
1315d043c564SKenneth D. Merry 		for (remove_idx = 0; remove_idx < sc->max_devices;
1316d043c564SKenneth D. Merry 		    remove_idx++, remove_entry++) {
1317d043c564SKenneth D. Merry 			if (remove_entry->dpm_entry_num != MPS_DPM_BAD_IDX) {
1318d043c564SKenneth D. Merry 				dpm_entry = (Mpi2DriverMap0Entry_t *)
1319d043c564SKenneth D. Merry 				    ((u8 *) sc->dpm_pg0 +
1320d043c564SKenneth D. Merry 				    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
1321d043c564SKenneth D. Merry 				dpm_entry += remove_entry->dpm_entry_num;
1322d043c564SKenneth D. Merry 				dpm_entry->PhysicalIdentifier.Low = 0;
1323d043c564SKenneth D. Merry 				dpm_entry->PhysicalIdentifier.High = 0;
1324d043c564SKenneth D. Merry 				dpm_entry->DeviceIndex = 0;
1325d043c564SKenneth D. Merry 				dpm_entry->MappingInformation = 0;
1326d043c564SKenneth D. Merry 				dpm_entry->PhysicalBitsMapping = 0;
1327d043c564SKenneth D. Merry 				sc->dpm_flush_entry[remove_entry->
1328d043c564SKenneth D. Merry 				    dpm_entry_num] = 1;
1329d043c564SKenneth D. Merry 				sc->dpm_entry_used[remove_entry->dpm_entry_num]
1330d043c564SKenneth D. Merry 				    = 0;
1331d043c564SKenneth D. Merry 				remove_entry->dpm_entry_num = MPS_DPM_BAD_IDX;
1332d043c564SKenneth D. Merry 			}
1333d043c564SKenneth D. Merry 		}
1334d043c564SKenneth D. Merry 	}
1335635e58c7SStephen McConnell 
1336635e58c7SStephen McConnell 	/*
1337635e58c7SStephen McConnell 	 * When using Enc/Slot mapping, if a new enclosure was added and old
1338635e58c7SStephen McConnell 	 * enclosure space was needed, the enclosure table may now have gaps
1339635e58c7SStephen McConnell 	 * that need to be closed. All enclosure mappings need to be contiguous
1340635e58c7SStephen McConnell 	 * so that space can be reused correctly if available.
1341635e58c7SStephen McConnell 	 */
1342d043c564SKenneth D. Merry 	if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
1343d043c564SKenneth D. Merry 	    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
1344d043c564SKenneth D. Merry 		num_entries = sc->num_enc_table_entries;
1345d043c564SKenneth D. Merry 		while (!done_flag) {
1346d043c564SKenneth D. Merry 			done_flag = 1;
1347d043c564SKenneth D. Merry 			et_entry = sc->enclosure_table;
1348d043c564SKenneth D. Merry 			for (i = 0; i < num_entries; i++, et_entry++) {
1349d043c564SKenneth D. Merry 				if (!et_entry->enc_handle && et_entry->
1350d043c564SKenneth D. Merry 				    init_complete) {
1351d043c564SKenneth D. Merry 					done_flag = 0;
1352d043c564SKenneth D. Merry 					if (i != (num_entries - 1)) {
1353d043c564SKenneth D. Merry 						from = &sc->enclosure_table
1354d043c564SKenneth D. Merry 						    [i+1];
1355d043c564SKenneth D. Merry 						to = &sc->enclosure_table[i];
1356d043c564SKenneth D. Merry 						for (m = i; m < (num_entries -
1357d043c564SKenneth D. Merry 						    1); m++, from++, to++) {
1358d043c564SKenneth D. Merry 							_mapping_set_mid_to_eid
1359d043c564SKenneth D. Merry 							    (sc, to);
1360d043c564SKenneth D. Merry 							*to = *from;
1361d043c564SKenneth D. Merry 						}
1362d043c564SKenneth D. Merry 						_mapping_clear_enc_entry(to);
1363d043c564SKenneth D. Merry 						sc->num_enc_table_entries--;
1364d043c564SKenneth D. Merry 						num_entries =
1365d043c564SKenneth D. Merry 						    sc->num_enc_table_entries;
1366d043c564SKenneth D. Merry 					} else {
1367d043c564SKenneth D. Merry 						_mapping_clear_enc_entry
1368d043c564SKenneth D. Merry 						    (et_entry);
1369d043c564SKenneth D. Merry 						sc->num_enc_table_entries--;
1370d043c564SKenneth D. Merry 						num_entries =
1371d043c564SKenneth D. Merry 						    sc->num_enc_table_entries;
1372d043c564SKenneth D. Merry 					}
1373d043c564SKenneth D. Merry 				}
1374d043c564SKenneth D. Merry 			}
1375d043c564SKenneth D. Merry 		}
1376d043c564SKenneth D. Merry 	}
1377d043c564SKenneth D. Merry }
1378d043c564SKenneth D. Merry 
1379d043c564SKenneth D. Merry /**
1380d043c564SKenneth D. Merry  * _mapping_add_new_device -Add the new device into mapping table
1381d043c564SKenneth D. Merry  * @sc: per adapter object
1382d043c564SKenneth D. Merry  * @topo_change: Topology change event entry
1383d043c564SKenneth D. Merry  *
1384635e58c7SStephen McConnell  * Search through the topology change event list and update map table,
1385635e58c7SStephen McConnell  * enclosure table and DPM pages for the newly added devices.
1386d043c564SKenneth D. Merry  *
1387d043c564SKenneth D. Merry  * Returns nothing
1388d043c564SKenneth D. Merry  */
1389d043c564SKenneth D. Merry static void
1390d043c564SKenneth D. Merry _mapping_add_new_device(struct mps_softc *sc,
1391d043c564SKenneth D. Merry     struct _map_topology_change *topo_change)
1392d043c564SKenneth D. Merry {
1393d043c564SKenneth D. Merry 	u8 enc_idx, missing_cnt, is_removed = 0;
1394d043c564SKenneth D. Merry 	u16 dpm_idx;
1395d043c564SKenneth D. Merry 	u32 search_idx, map_idx;
1396d043c564SKenneth D. Merry 	u32 entry;
1397d043c564SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
1398d043c564SKenneth D. Merry 	struct enc_mapping_table *et_entry;
1399d043c564SKenneth D. Merry 	struct _map_phy_change *phy_change;
1400d043c564SKenneth D. Merry 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
1401d043c564SKenneth D. Merry 	Mpi2DriverMap0Entry_t *dpm_entry;
1402d043c564SKenneth D. Merry 	uint64_t temp64_var;
1403d043c564SKenneth D. Merry 	u8 map_shift = MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT;
1404d043c564SKenneth D. Merry 	u8 hdr_sz = sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER);
1405d043c564SKenneth D. Merry 	u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs);
1406d043c564SKenneth D. Merry 
1407d043c564SKenneth D. Merry 	for (entry = 0; entry < topo_change->num_entries; entry++) {
1408d043c564SKenneth D. Merry 		phy_change = &topo_change->phy_details[entry];
1409d043c564SKenneth D. Merry 		if (phy_change->is_processed)
1410d043c564SKenneth D. Merry 			continue;
1411d043c564SKenneth D. Merry 		if (phy_change->reason != MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED ||
1412d043c564SKenneth D. Merry 		    !phy_change->dev_handle) {
1413d043c564SKenneth D. Merry 			phy_change->is_processed = 1;
1414d043c564SKenneth D. Merry 			continue;
1415d043c564SKenneth D. Merry 		}
1416d043c564SKenneth D. Merry 		if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
1417d043c564SKenneth D. Merry 		    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
1418d043c564SKenneth D. Merry 			enc_idx = _mapping_get_enc_idx_from_handle
1419d043c564SKenneth D. Merry 			    (sc, topo_change->enc_handle);
1420d043c564SKenneth D. Merry 			if (enc_idx == MPS_ENCTABLE_BAD_IDX) {
1421d043c564SKenneth D. Merry 				phy_change->is_processed = 1;
1422635e58c7SStephen McConnell 				mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: "
1423635e58c7SStephen McConnell 				    "failed to add the device with handle "
1424*b99419aeSAlexander Motin 				    "0x%04x because enclosure handle 0x%04x "
1425*b99419aeSAlexander Motin 				    "is not in the mapping table\n", __func__,
1426*b99419aeSAlexander Motin 				    phy_change->dev_handle,
1427*b99419aeSAlexander Motin 				    topo_change->enc_handle);
1428d043c564SKenneth D. Merry 				continue;
1429d043c564SKenneth D. Merry 			}
1430635e58c7SStephen McConnell 
1431635e58c7SStephen McConnell 			/*
1432635e58c7SStephen McConnell 			 * If the enclosure's start_index is BAD here, it means
1433635e58c7SStephen McConnell 			 * that there is no room in the mapping table to cover
1434635e58c7SStephen McConnell 			 * all of the devices that could be in the enclosure.
1435635e58c7SStephen McConnell 			 * There's no reason to process any of the devices for
1436635e58c7SStephen McConnell 			 * this enclosure since they can't be mapped.
1437635e58c7SStephen McConnell 			 */
1438d043c564SKenneth D. Merry 			et_entry = &sc->enclosure_table[enc_idx];
1439d043c564SKenneth D. Merry 			if (et_entry->start_index == MPS_MAPTABLE_BAD_IDX) {
1440d043c564SKenneth D. Merry 				phy_change->is_processed = 1;
1441635e58c7SStephen McConnell 				mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: "
1442635e58c7SStephen McConnell 				    "failed to add the device with handle "
1443635e58c7SStephen McConnell 				    "0x%04x because there is no free space "
1444635e58c7SStephen McConnell 				    "available in the mapping table\n",
1445d043c564SKenneth D. Merry 				    __func__, phy_change->dev_handle);
1446d043c564SKenneth D. Merry 				continue;
1447d043c564SKenneth D. Merry 			}
1448635e58c7SStephen McConnell 
1449635e58c7SStephen McConnell 			/*
1450635e58c7SStephen McConnell 			 * Add this device to the mapping table at the correct
1451635e58c7SStephen McConnell 			 * offset where space was found to map the enclosure.
1452635e58c7SStephen McConnell 			 * Then setup the DPM entry information if being used.
1453635e58c7SStephen McConnell 			 */
1454d043c564SKenneth D. Merry 			map_idx = et_entry->start_index + phy_change->slot -
1455d043c564SKenneth D. Merry 			    et_entry->start_slot;
1456d043c564SKenneth D. Merry 			mt_entry = &sc->mapping_table[map_idx];
1457d043c564SKenneth D. Merry 			mt_entry->physical_id = phy_change->physical_id;
1458d043c564SKenneth D. Merry 			mt_entry->id = map_idx;
1459d043c564SKenneth D. Merry 			mt_entry->dev_handle = phy_change->dev_handle;
1460d043c564SKenneth D. Merry 			mt_entry->missing_count = 0;
1461d043c564SKenneth D. Merry 			mt_entry->dpm_entry_num = et_entry->dpm_entry_num;
1462d043c564SKenneth D. Merry 			mt_entry->device_info = phy_change->device_info |
1463d043c564SKenneth D. Merry 			    (MPS_DEV_RESERVED | MPS_MAP_IN_USE);
1464d043c564SKenneth D. Merry 			if (sc->is_dpm_enable) {
1465d043c564SKenneth D. Merry 				dpm_idx = et_entry->dpm_entry_num;
1466d043c564SKenneth D. Merry 				if (dpm_idx == MPS_DPM_BAD_IDX)
1467d043c564SKenneth D. Merry 					dpm_idx = _mapping_get_dpm_idx_from_id
1468d043c564SKenneth D. Merry 					    (sc, et_entry->enclosure_id,
1469d043c564SKenneth D. Merry 					     et_entry->phy_bits);
1470d043c564SKenneth D. Merry 				if (dpm_idx == MPS_DPM_BAD_IDX) {
1471d043c564SKenneth D. Merry 					dpm_idx = _mapping_get_free_dpm_idx(sc);
1472d043c564SKenneth D. Merry 					if (dpm_idx != MPS_DPM_BAD_IDX) {
1473d043c564SKenneth D. Merry 						dpm_entry =
1474d043c564SKenneth D. Merry 						    (Mpi2DriverMap0Entry_t *)
1475d043c564SKenneth D. Merry 						    ((u8 *) sc->dpm_pg0 +
1476d043c564SKenneth D. Merry 						     hdr_sz);
1477d043c564SKenneth D. Merry 						dpm_entry += dpm_idx;
1478d043c564SKenneth D. Merry 						dpm_entry->
1479d043c564SKenneth D. Merry 						    PhysicalIdentifier.Low =
1480d043c564SKenneth D. Merry 						    (0xFFFFFFFF &
1481d043c564SKenneth D. Merry 						    et_entry->enclosure_id);
1482d043c564SKenneth D. Merry 						dpm_entry->
1483d043c564SKenneth D. Merry 						    PhysicalIdentifier.High =
1484d043c564SKenneth D. Merry 						    (et_entry->enclosure_id
1485d043c564SKenneth D. Merry 						     >> 32);
1486d043c564SKenneth D. Merry 						dpm_entry->DeviceIndex =
1487d043c564SKenneth D. Merry 						    (U16)et_entry->start_index;
1488d043c564SKenneth D. Merry 						dpm_entry->MappingInformation =
1489d043c564SKenneth D. Merry 						    et_entry->num_slots;
1490d043c564SKenneth D. Merry 						dpm_entry->MappingInformation
1491d043c564SKenneth D. Merry 						    <<= map_shift;
1492d043c564SKenneth D. Merry 						dpm_entry->PhysicalBitsMapping
1493d043c564SKenneth D. Merry 						    = et_entry->phy_bits;
1494d043c564SKenneth D. Merry 						et_entry->dpm_entry_num =
1495d043c564SKenneth D. Merry 						    dpm_idx;
1496d043c564SKenneth D. Merry 						sc->dpm_entry_used[dpm_idx] = 1;
1497d043c564SKenneth D. Merry 						sc->dpm_flush_entry[dpm_idx] =
1498d043c564SKenneth D. Merry 						    1;
1499d043c564SKenneth D. Merry 						phy_change->is_processed = 1;
1500d043c564SKenneth D. Merry 					} else {
1501d043c564SKenneth D. Merry 						phy_change->is_processed = 1;
1502635e58c7SStephen McConnell 						mps_dprint(sc, MPS_ERROR |
1503635e58c7SStephen McConnell 						    MPS_MAPPING, "%s: failed "
1504635e58c7SStephen McConnell 						    "to add the device with "
1505635e58c7SStephen McConnell 						    "handle 0x%04x to "
15069b91b192SKenneth D. Merry 						    "persistent table because "
15079b91b192SKenneth D. Merry 						    "there is no free space "
15089b91b192SKenneth D. Merry 						    "available\n", __func__,
1509d043c564SKenneth D. Merry 						    phy_change->dev_handle);
1510d043c564SKenneth D. Merry 					}
1511d043c564SKenneth D. Merry 				} else {
1512d043c564SKenneth D. Merry 					et_entry->dpm_entry_num = dpm_idx;
1513d043c564SKenneth D. Merry 					mt_entry->dpm_entry_num = dpm_idx;
1514d043c564SKenneth D. Merry 				}
1515d043c564SKenneth D. Merry 			}
1516d043c564SKenneth D. Merry 			et_entry->init_complete = 1;
1517d043c564SKenneth D. Merry 		} else if ((ioc_pg8_flags &
1518d043c564SKenneth D. Merry 		    MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
1519d043c564SKenneth D. Merry 		    MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
1520635e58c7SStephen McConnell 			/*
1521635e58c7SStephen McConnell 			 * Get the mapping table index for this device. If it's
1522635e58c7SStephen McConnell 			 * not in the mapping table yet, find a free entry if
1523635e58c7SStephen McConnell 			 * one is available. If there are no free entries, look
1524635e58c7SStephen McConnell 			 * for the entry that has the highest missing count. If
1525635e58c7SStephen McConnell 			 * none of that works to find an entry in the mapping
1526635e58c7SStephen McConnell 			 * table, there is a problem. Log a message and just
1527635e58c7SStephen McConnell 			 * continue on.
1528635e58c7SStephen McConnell 			 */
1529d043c564SKenneth D. Merry 			map_idx = _mapping_get_mt_idx_from_id
1530d043c564SKenneth D. Merry 			    (sc, phy_change->physical_id);
1531d043c564SKenneth D. Merry 			if (map_idx == MPS_MAPTABLE_BAD_IDX) {
1532d043c564SKenneth D. Merry 				search_idx = sc->num_rsvd_entries;
1533d043c564SKenneth D. Merry 				if (topo_change->exp_handle)
1534d043c564SKenneth D. Merry 					search_idx += max_num_phy_ids;
1535d043c564SKenneth D. Merry 				map_idx = _mapping_get_free_mt_idx(sc,
1536d043c564SKenneth D. Merry 				    search_idx);
1537d043c564SKenneth D. Merry 			}
1538635e58c7SStephen McConnell 
1539635e58c7SStephen McConnell 			/*
1540635e58c7SStephen McConnell 			 * If an entry will be used that has a missing device,
1541635e58c7SStephen McConnell 			 * clear its entry from  the DPM in the controller.
1542635e58c7SStephen McConnell 			 */
1543d043c564SKenneth D. Merry 			if (map_idx == MPS_MAPTABLE_BAD_IDX) {
1544d043c564SKenneth D. Merry 				map_idx = _mapping_get_high_missing_mt_idx(sc);
1545d043c564SKenneth D. Merry 				if (map_idx != MPS_MAPTABLE_BAD_IDX) {
1546d043c564SKenneth D. Merry 					mt_entry = &sc->mapping_table[map_idx];
1547635e58c7SStephen McConnell 					_mapping_add_to_removal_table(sc,
1548635e58c7SStephen McConnell 					    mt_entry->dpm_entry_num);
1549d043c564SKenneth D. Merry 					is_removed = 1;
1550d043c564SKenneth D. Merry 					mt_entry->init_complete = 0;
1551d043c564SKenneth D. Merry 				}
1552d043c564SKenneth D. Merry 			}
1553d043c564SKenneth D. Merry 			if (map_idx != MPS_MAPTABLE_BAD_IDX) {
1554d043c564SKenneth D. Merry 				mt_entry = &sc->mapping_table[map_idx];
1555d043c564SKenneth D. Merry 				mt_entry->physical_id = phy_change->physical_id;
1556d043c564SKenneth D. Merry 				mt_entry->id = map_idx;
1557d043c564SKenneth D. Merry 				mt_entry->dev_handle = phy_change->dev_handle;
1558d043c564SKenneth D. Merry 				mt_entry->missing_count = 0;
1559d043c564SKenneth D. Merry 				mt_entry->device_info = phy_change->device_info
1560d043c564SKenneth D. Merry 				    | (MPS_DEV_RESERVED | MPS_MAP_IN_USE);
1561d043c564SKenneth D. Merry 			} else {
1562d043c564SKenneth D. Merry 				phy_change->is_processed = 1;
1563635e58c7SStephen McConnell 				mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: "
1564635e58c7SStephen McConnell 				    "failed to add the device with handle "
1565635e58c7SStephen McConnell 				    "0x%04x because there is no free space "
1566635e58c7SStephen McConnell 				    "available in the mapping table\n",
1567d043c564SKenneth D. Merry 				    __func__, phy_change->dev_handle);
1568d043c564SKenneth D. Merry 				continue;
1569d043c564SKenneth D. Merry 			}
1570d043c564SKenneth D. Merry 			if (sc->is_dpm_enable) {
1571d043c564SKenneth D. Merry 				if (mt_entry->dpm_entry_num !=
1572d043c564SKenneth D. Merry 				    MPS_DPM_BAD_IDX) {
1573d043c564SKenneth D. Merry 					dpm_idx = mt_entry->dpm_entry_num;
1574d043c564SKenneth D. Merry 					dpm_entry = (Mpi2DriverMap0Entry_t *)
1575d043c564SKenneth D. Merry 					    ((u8 *)sc->dpm_pg0 + hdr_sz);
1576d043c564SKenneth D. Merry 					dpm_entry += dpm_idx;
1577d043c564SKenneth D. Merry 					missing_cnt = dpm_entry->
1578d043c564SKenneth D. Merry 					    MappingInformation &
1579d043c564SKenneth D. Merry 					    MPI2_DRVMAP0_MAPINFO_MISSING_MASK;
1580d043c564SKenneth D. Merry 					temp64_var = dpm_entry->
1581d043c564SKenneth D. Merry 					    PhysicalIdentifier.High;
1582d043c564SKenneth D. Merry 					temp64_var = (temp64_var << 32) |
1583d043c564SKenneth D. Merry 					   dpm_entry->PhysicalIdentifier.Low;
1584635e58c7SStephen McConnell 
1585635e58c7SStephen McConnell 					/*
1586635e58c7SStephen McConnell 					 * If the Mapping Table's info is not
1587635e58c7SStephen McConnell 					 * the same as the DPM entry, clear the
1588635e58c7SStephen McConnell 					 * init_complete flag so that it's
1589635e58c7SStephen McConnell 					 * updated.
1590635e58c7SStephen McConnell 					 */
1591d043c564SKenneth D. Merry 					if ((mt_entry->physical_id ==
1592d043c564SKenneth D. Merry 					    temp64_var) && !missing_cnt)
1593d043c564SKenneth D. Merry 						mt_entry->init_complete = 1;
1594635e58c7SStephen McConnell 					else
1595635e58c7SStephen McConnell 						mt_entry->init_complete = 0;
1596d043c564SKenneth D. Merry 				} else {
1597d043c564SKenneth D. Merry 					dpm_idx = _mapping_get_free_dpm_idx(sc);
1598d043c564SKenneth D. Merry 					mt_entry->init_complete = 0;
1599d043c564SKenneth D. Merry 				}
1600d043c564SKenneth D. Merry 				if (dpm_idx != MPS_DPM_BAD_IDX &&
1601d043c564SKenneth D. Merry 				    !mt_entry->init_complete) {
1602d043c564SKenneth D. Merry 					mt_entry->dpm_entry_num = dpm_idx;
1603d043c564SKenneth D. Merry 					dpm_entry = (Mpi2DriverMap0Entry_t *)
1604d043c564SKenneth D. Merry 					    ((u8 *)sc->dpm_pg0 + hdr_sz);
1605d043c564SKenneth D. Merry 					dpm_entry += dpm_idx;
1606d043c564SKenneth D. Merry 					dpm_entry->PhysicalIdentifier.Low =
1607d043c564SKenneth D. Merry 					    (0xFFFFFFFF &
1608d043c564SKenneth D. Merry 					    mt_entry->physical_id);
1609d043c564SKenneth D. Merry 					dpm_entry->PhysicalIdentifier.High =
1610d043c564SKenneth D. Merry 					    (mt_entry->physical_id >> 32);
1611d043c564SKenneth D. Merry 					dpm_entry->DeviceIndex = (U16) map_idx;
1612d043c564SKenneth D. Merry 					dpm_entry->MappingInformation = 0;
1613d043c564SKenneth D. Merry 					dpm_entry->PhysicalBitsMapping = 0;
1614d043c564SKenneth D. Merry 					sc->dpm_entry_used[dpm_idx] = 1;
1615d043c564SKenneth D. Merry 					sc->dpm_flush_entry[dpm_idx] = 1;
1616d043c564SKenneth D. Merry 					phy_change->is_processed = 1;
1617d043c564SKenneth D. Merry 				} else if (dpm_idx == MPS_DPM_BAD_IDX) {
1618d043c564SKenneth D. Merry 					phy_change->is_processed = 1;
1619635e58c7SStephen McConnell 					mps_dprint(sc, MPS_ERROR | MPS_MAPPING,
1620635e58c7SStephen McConnell 					    "%s: failed to add the device with "
1621635e58c7SStephen McConnell 					    "handle 0x%04x to persistent table "
1622635e58c7SStephen McConnell 					    "because there is no free space "
16239b91b192SKenneth D. Merry 					    "available\n", __func__,
1624d043c564SKenneth D. Merry 					    phy_change->dev_handle);
1625d043c564SKenneth D. Merry 				}
1626d043c564SKenneth D. Merry 			}
1627d043c564SKenneth D. Merry 			mt_entry->init_complete = 1;
1628d043c564SKenneth D. Merry 		}
1629d043c564SKenneth D. Merry 
1630d043c564SKenneth D. Merry 		phy_change->is_processed = 1;
1631d043c564SKenneth D. Merry 	}
1632d043c564SKenneth D. Merry 	if (is_removed)
1633d043c564SKenneth D. Merry 		_mapping_clear_removed_entries(sc);
1634d043c564SKenneth D. Merry }
1635d043c564SKenneth D. Merry 
1636d043c564SKenneth D. Merry /**
1637d043c564SKenneth D. Merry  * _mapping_flush_dpm_pages -Flush the DPM pages to NVRAM
1638d043c564SKenneth D. Merry  * @sc: per adapter object
1639d043c564SKenneth D. Merry  *
1640d043c564SKenneth D. Merry  * Returns nothing
1641d043c564SKenneth D. Merry  */
1642d043c564SKenneth D. Merry static void
1643d043c564SKenneth D. Merry _mapping_flush_dpm_pages(struct mps_softc *sc)
1644d043c564SKenneth D. Merry {
1645d043c564SKenneth D. Merry 	Mpi2DriverMap0Entry_t *dpm_entry;
1646d043c564SKenneth D. Merry 	Mpi2ConfigReply_t mpi_reply;
1647d043c564SKenneth D. Merry 	Mpi2DriverMappingPage0_t config_page;
1648d043c564SKenneth D. Merry 	u16 entry_num;
1649d043c564SKenneth D. Merry 
1650d043c564SKenneth D. Merry 	for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++) {
1651d043c564SKenneth D. Merry 		if (!sc->dpm_flush_entry[entry_num])
1652d043c564SKenneth D. Merry 			continue;
1653d043c564SKenneth D. Merry 		memset(&config_page, 0, sizeof(Mpi2DriverMappingPage0_t));
1654d043c564SKenneth D. Merry 		memcpy(&config_page.Header, (u8 *)sc->dpm_pg0,
1655d043c564SKenneth D. Merry 		    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
1656d043c564SKenneth D. Merry 		dpm_entry = (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 +
1657d043c564SKenneth D. Merry 		    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
1658d043c564SKenneth D. Merry 		dpm_entry += entry_num;
1659d043c564SKenneth D. Merry 		dpm_entry->MappingInformation = htole16(dpm_entry->
1660d043c564SKenneth D. Merry 		    MappingInformation);
1661d043c564SKenneth D. Merry 		dpm_entry->DeviceIndex = htole16(dpm_entry->DeviceIndex);
1662d043c564SKenneth D. Merry 		dpm_entry->PhysicalBitsMapping = htole32(dpm_entry->
1663d043c564SKenneth D. Merry 		    PhysicalBitsMapping);
1664d043c564SKenneth D. Merry 		memcpy(&config_page.Entry, (u8 *)dpm_entry,
1665d043c564SKenneth D. Merry 		    sizeof(Mpi2DriverMap0Entry_t));
1666d043c564SKenneth D. Merry 		/* TODO-How to handle failed writes? */
1667635e58c7SStephen McConnell 		mps_dprint(sc, MPS_MAPPING, "%s: Flushing DPM entry %d.\n",
1668635e58c7SStephen McConnell 		    __func__, entry_num);
1669d043c564SKenneth D. Merry 		if (mps_config_set_dpm_pg0(sc, &mpi_reply, &config_page,
1670d043c564SKenneth D. Merry 		    entry_num)) {
1671635e58c7SStephen McConnell 			mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: Flush of "
1672635e58c7SStephen McConnell 			    "DPM entry %d for device failed\n", __func__,
1673635e58c7SStephen McConnell 			    entry_num);
1674d043c564SKenneth D. Merry 		} else
1675d043c564SKenneth D. Merry 			sc->dpm_flush_entry[entry_num] = 0;
1676d043c564SKenneth D. Merry 		dpm_entry->MappingInformation = le16toh(dpm_entry->
1677d043c564SKenneth D. Merry 		    MappingInformation);
1678d043c564SKenneth D. Merry 		dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
1679d043c564SKenneth D. Merry 		dpm_entry->PhysicalBitsMapping = le32toh(dpm_entry->
1680d043c564SKenneth D. Merry 		    PhysicalBitsMapping);
1681d043c564SKenneth D. Merry 	}
1682d043c564SKenneth D. Merry }
1683d043c564SKenneth D. Merry 
1684d043c564SKenneth D. Merry /**
1685d043c564SKenneth D. Merry  * _mapping_allocate_memory- allocates the memory required for mapping tables
1686d043c564SKenneth D. Merry  * @sc: per adapter object
1687d043c564SKenneth D. Merry  *
1688d043c564SKenneth D. Merry  * Allocates the memory for all the tables required for host mapping
1689d043c564SKenneth D. Merry  *
1690d043c564SKenneth D. Merry  * Return 0 on success or non-zero on failure.
1691d043c564SKenneth D. Merry  */
1692d043c564SKenneth D. Merry int
1693d043c564SKenneth D. Merry mps_mapping_allocate_memory(struct mps_softc *sc)
1694d043c564SKenneth D. Merry {
1695d043c564SKenneth D. Merry 	uint32_t dpm_pg0_sz;
1696d043c564SKenneth D. Merry 
1697ac2fffa4SPedro F. Giffuni 	sc->mapping_table = malloc((sizeof(struct dev_mapping_table) *
1698ac2fffa4SPedro F. Giffuni 	    sc->max_devices), M_MPT2, M_ZERO|M_NOWAIT);
1699d043c564SKenneth D. Merry 	if (!sc->mapping_table)
1700d043c564SKenneth D. Merry 		goto free_resources;
1701d043c564SKenneth D. Merry 
1702ac2fffa4SPedro F. Giffuni 	sc->removal_table = malloc((sizeof(struct map_removal_table) *
1703ac2fffa4SPedro F. Giffuni 	    sc->max_devices), M_MPT2, M_ZERO|M_NOWAIT);
1704d043c564SKenneth D. Merry 	if (!sc->removal_table)
1705d043c564SKenneth D. Merry 		goto free_resources;
1706d043c564SKenneth D. Merry 
1707ac2fffa4SPedro F. Giffuni 	sc->enclosure_table = malloc((sizeof(struct enc_mapping_table) *
1708ac2fffa4SPedro F. Giffuni 	    sc->max_enclosures), M_MPT2, M_ZERO|M_NOWAIT);
1709d043c564SKenneth D. Merry 	if (!sc->enclosure_table)
1710d043c564SKenneth D. Merry 		goto free_resources;
1711d043c564SKenneth D. Merry 
1712ac2fffa4SPedro F. Giffuni 	sc->dpm_entry_used = malloc((sizeof(u8) * sc->max_dpm_entries),
1713d043c564SKenneth D. Merry 	    M_MPT2, M_ZERO|M_NOWAIT);
1714d043c564SKenneth D. Merry 	if (!sc->dpm_entry_used)
1715d043c564SKenneth D. Merry 		goto free_resources;
1716d043c564SKenneth D. Merry 
1717ac2fffa4SPedro F. Giffuni 	sc->dpm_flush_entry = malloc((sizeof(u8) * sc->max_dpm_entries),
1718d043c564SKenneth D. Merry 	    M_MPT2, M_ZERO|M_NOWAIT);
1719d043c564SKenneth D. Merry 	if (!sc->dpm_flush_entry)
1720d043c564SKenneth D. Merry 		goto free_resources;
1721d043c564SKenneth D. Merry 
1722d043c564SKenneth D. Merry 	dpm_pg0_sz = sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER) +
1723d043c564SKenneth D. Merry 	    (sc->max_dpm_entries * sizeof(MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY));
1724d043c564SKenneth D. Merry 
1725d043c564SKenneth D. Merry 	sc->dpm_pg0 = malloc(dpm_pg0_sz, M_MPT2, M_ZERO|M_NOWAIT);
1726d043c564SKenneth D. Merry 	if (!sc->dpm_pg0) {
1727d043c564SKenneth D. Merry 		printf("%s: memory alloc failed for dpm page; disabling dpm\n",
1728d043c564SKenneth D. Merry 		    __func__);
1729d043c564SKenneth D. Merry 		sc->is_dpm_enable = 0;
1730d043c564SKenneth D. Merry 	}
1731d043c564SKenneth D. Merry 
1732d043c564SKenneth D. Merry 	return 0;
1733d043c564SKenneth D. Merry 
1734d043c564SKenneth D. Merry free_resources:
1735d043c564SKenneth D. Merry 	free(sc->mapping_table, M_MPT2);
1736d043c564SKenneth D. Merry 	free(sc->removal_table, M_MPT2);
1737d043c564SKenneth D. Merry 	free(sc->enclosure_table, M_MPT2);
1738d043c564SKenneth D. Merry 	free(sc->dpm_entry_used, M_MPT2);
1739d043c564SKenneth D. Merry 	free(sc->dpm_flush_entry, M_MPT2);
1740d043c564SKenneth D. Merry 	free(sc->dpm_pg0, M_MPT2);
1741d043c564SKenneth D. Merry 	printf("%s: device initialization failed due to failure in mapping "
1742d043c564SKenneth D. Merry 	    "table memory allocation\n", __func__);
1743d043c564SKenneth D. Merry 	return -1;
1744d043c564SKenneth D. Merry }
1745d043c564SKenneth D. Merry 
1746d043c564SKenneth D. Merry /**
1747d043c564SKenneth D. Merry  * mps_mapping_free_memory- frees the memory allocated for mapping tables
1748d043c564SKenneth D. Merry  * @sc: per adapter object
1749d043c564SKenneth D. Merry  *
1750d043c564SKenneth D. Merry  * Returns nothing.
1751d043c564SKenneth D. Merry  */
1752d043c564SKenneth D. Merry void
1753d043c564SKenneth D. Merry mps_mapping_free_memory(struct mps_softc *sc)
1754d043c564SKenneth D. Merry {
1755d043c564SKenneth D. Merry 	free(sc->mapping_table, M_MPT2);
1756d043c564SKenneth D. Merry 	free(sc->removal_table, M_MPT2);
1757d043c564SKenneth D. Merry 	free(sc->enclosure_table, M_MPT2);
1758d043c564SKenneth D. Merry 	free(sc->dpm_entry_used, M_MPT2);
1759d043c564SKenneth D. Merry 	free(sc->dpm_flush_entry, M_MPT2);
1760d043c564SKenneth D. Merry 	free(sc->dpm_pg0, M_MPT2);
1761d043c564SKenneth D. Merry }
1762d043c564SKenneth D. Merry 
1763d043c564SKenneth D. Merry static void
1764d043c564SKenneth D. Merry _mapping_process_dpm_pg0(struct mps_softc *sc)
1765d043c564SKenneth D. Merry {
1766d043c564SKenneth D. Merry 	u8 missing_cnt, enc_idx;
1767d043c564SKenneth D. Merry 	u16 slot_id, entry_num, num_slots;
1768d043c564SKenneth D. Merry 	u32 map_idx, dev_idx, start_idx, end_idx;
1769d043c564SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
1770d043c564SKenneth D. Merry 	Mpi2DriverMap0Entry_t *dpm_entry;
1771d043c564SKenneth D. Merry 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
1772d043c564SKenneth D. Merry 	u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs);
1773d043c564SKenneth D. Merry 	struct enc_mapping_table *et_entry;
1774d043c564SKenneth D. Merry 	u64 physical_id;
1775d043c564SKenneth D. Merry 	u32 phy_bits = 0;
1776d043c564SKenneth D. Merry 
1777635e58c7SStephen McConnell 	/*
1778635e58c7SStephen McConnell 	 * start_idx and end_idx are only used for IR.
1779635e58c7SStephen McConnell 	 */
1780d043c564SKenneth D. Merry 	if (sc->ir_firmware)
1781d043c564SKenneth D. Merry 		_mapping_get_ir_maprange(sc, &start_idx, &end_idx);
1782d043c564SKenneth D. Merry 
1783635e58c7SStephen McConnell 	/*
1784635e58c7SStephen McConnell 	 * Look through all of the DPM entries that were read from the
1785635e58c7SStephen McConnell 	 * controller and copy them over to the driver's internal table if they
1786635e58c7SStephen McConnell 	 * have a non-zero ID. At this point, any ID with a value of 0 would be
1787635e58c7SStephen McConnell 	 * invalid, so don't copy it.
1788635e58c7SStephen McConnell 	 */
1789635e58c7SStephen McConnell 	mps_dprint(sc, MPS_MAPPING, "%s: Start copy of %d DPM entries into the "
1790635e58c7SStephen McConnell 	    "mapping table.\n", __func__, sc->max_dpm_entries);
1791d043c564SKenneth D. Merry 	dpm_entry = (Mpi2DriverMap0Entry_t *) ((uint8_t *) sc->dpm_pg0 +
1792d043c564SKenneth D. Merry 	    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
1793d043c564SKenneth D. Merry 	for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++,
1794d043c564SKenneth D. Merry 	    dpm_entry++) {
1795d043c564SKenneth D. Merry 		physical_id = dpm_entry->PhysicalIdentifier.High;
1796d043c564SKenneth D. Merry 		physical_id = (physical_id << 32) |
1797d043c564SKenneth D. Merry 		    dpm_entry->PhysicalIdentifier.Low;
1798d043c564SKenneth D. Merry 		if (!physical_id) {
1799d043c564SKenneth D. Merry 			sc->dpm_entry_used[entry_num] = 0;
1800d043c564SKenneth D. Merry 			continue;
1801d043c564SKenneth D. Merry 		}
1802d043c564SKenneth D. Merry 		sc->dpm_entry_used[entry_num] = 1;
1803d043c564SKenneth D. Merry 		dpm_entry->MappingInformation = le16toh(dpm_entry->
1804d043c564SKenneth D. Merry 		    MappingInformation);
1805d043c564SKenneth D. Merry 		missing_cnt = dpm_entry->MappingInformation &
1806d043c564SKenneth D. Merry 		    MPI2_DRVMAP0_MAPINFO_MISSING_MASK;
1807d043c564SKenneth D. Merry 		dev_idx = le16toh(dpm_entry->DeviceIndex);
1808d043c564SKenneth D. Merry 		phy_bits = le32toh(dpm_entry->PhysicalBitsMapping);
1809635e58c7SStephen McConnell 
1810635e58c7SStephen McConnell 		/*
1811635e58c7SStephen McConnell 		 * Volumes are at special locations in the mapping table so
1812635e58c7SStephen McConnell 		 * account for that. Volume mapping table entries do not depend
1813635e58c7SStephen McConnell 		 * on the type of mapping, so continue the loop after adding
1814635e58c7SStephen McConnell 		 * volumes to the mapping table.
1815635e58c7SStephen McConnell 		 */
1816d043c564SKenneth D. Merry 		if (sc->ir_firmware && (dev_idx >= start_idx) &&
1817d043c564SKenneth D. Merry 		    (dev_idx <= end_idx)) {
1818d043c564SKenneth D. Merry 			mt_entry = &sc->mapping_table[dev_idx];
1819635e58c7SStephen McConnell 			mt_entry->physical_id =
1820635e58c7SStephen McConnell 			    dpm_entry->PhysicalIdentifier.High;
1821d043c564SKenneth D. Merry 			mt_entry->physical_id = (mt_entry->physical_id << 32) |
1822d043c564SKenneth D. Merry 			    dpm_entry->PhysicalIdentifier.Low;
1823d043c564SKenneth D. Merry 			mt_entry->id = dev_idx;
1824d043c564SKenneth D. Merry 			mt_entry->missing_count = missing_cnt;
1825d043c564SKenneth D. Merry 			mt_entry->dpm_entry_num = entry_num;
1826d043c564SKenneth D. Merry 			mt_entry->device_info = MPS_DEV_RESERVED;
1827d043c564SKenneth D. Merry 			continue;
1828d043c564SKenneth D. Merry 		}
1829d043c564SKenneth D. Merry 		if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
1830d043c564SKenneth D. Merry 		    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
1831635e58c7SStephen McConnell 			/*
1832635e58c7SStephen McConnell 			 * The dev_idx for an enclosure is the start index. If
1833635e58c7SStephen McConnell 			 * the start index is within the controller's default
1834635e58c7SStephen McConnell 			 * enclosure area, set the number of slots for this
1835635e58c7SStephen McConnell 			 * enclosure to the max allowed. Otherwise, it should be
1836635e58c7SStephen McConnell 			 * a normal enclosure and the number of slots is in the
1837635e58c7SStephen McConnell 			 * DPM entry's Mapping Information.
1838635e58c7SStephen McConnell 			 */
1839d043c564SKenneth D. Merry 			if (dev_idx < (sc->num_rsvd_entries +
1840d043c564SKenneth D. Merry 			    max_num_phy_ids)) {
1841d043c564SKenneth D. Merry 				slot_id = 0;
1842d043c564SKenneth D. Merry 				if (ioc_pg8_flags &
1843d043c564SKenneth D. Merry 				    MPI2_IOCPAGE8_FLAGS_DA_START_SLOT_1)
1844d043c564SKenneth D. Merry 					slot_id = 1;
1845d043c564SKenneth D. Merry 				num_slots = max_num_phy_ids;
1846d043c564SKenneth D. Merry 			} else {
1847d043c564SKenneth D. Merry 				slot_id = 0;
1848d043c564SKenneth D. Merry 				num_slots = dpm_entry->MappingInformation &
1849d043c564SKenneth D. Merry 				    MPI2_DRVMAP0_MAPINFO_SLOT_MASK;
1850d043c564SKenneth D. Merry 				num_slots >>= MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT;
1851d043c564SKenneth D. Merry 			}
1852d043c564SKenneth D. Merry 			enc_idx = sc->num_enc_table_entries;
1853d043c564SKenneth D. Merry 			if (enc_idx >= sc->max_enclosures) {
1854635e58c7SStephen McConnell 				mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: "
1855635e58c7SStephen McConnell 				    "Number of enclosure entries in DPM exceed "
1856635e58c7SStephen McConnell 				    "the max allowed of %d.\n", __func__,
1857d043c564SKenneth D. Merry 				    sc->max_enclosures);
1858d043c564SKenneth D. Merry 				break;
1859d043c564SKenneth D. Merry 			}
1860d043c564SKenneth D. Merry 			sc->num_enc_table_entries++;
1861d043c564SKenneth D. Merry 			et_entry = &sc->enclosure_table[enc_idx];
1862d043c564SKenneth D. Merry 			physical_id = dpm_entry->PhysicalIdentifier.High;
1863d043c564SKenneth D. Merry 			et_entry->enclosure_id = (physical_id << 32) |
1864d043c564SKenneth D. Merry 			    dpm_entry->PhysicalIdentifier.Low;
1865d043c564SKenneth D. Merry 			et_entry->start_index = dev_idx;
1866d043c564SKenneth D. Merry 			et_entry->dpm_entry_num = entry_num;
1867d043c564SKenneth D. Merry 			et_entry->num_slots = num_slots;
1868d043c564SKenneth D. Merry 			et_entry->start_slot = slot_id;
1869d043c564SKenneth D. Merry 			et_entry->missing_count = missing_cnt;
1870d043c564SKenneth D. Merry 			et_entry->phy_bits = phy_bits;
1871d043c564SKenneth D. Merry 
1872635e58c7SStephen McConnell 			/*
1873635e58c7SStephen McConnell 			 * Initialize all entries for this enclosure in the
1874635e58c7SStephen McConnell 			 * mapping table and mark them as reserved. The actual
1875635e58c7SStephen McConnell 			 * devices have not been processed yet but when they are
1876635e58c7SStephen McConnell 			 * they will use these entries. If an entry is found
1877635e58c7SStephen McConnell 			 * that already has a valid DPM index, the mapping table
1878635e58c7SStephen McConnell 			 * is corrupt. This can happen if the mapping type is
1879635e58c7SStephen McConnell 			 * changed without clearing all of the DPM entries in
1880635e58c7SStephen McConnell 			 * the controller.
1881635e58c7SStephen McConnell 			 */
1882d043c564SKenneth D. Merry 			mt_entry = &sc->mapping_table[dev_idx];
1883d043c564SKenneth D. Merry 			for (map_idx = dev_idx; map_idx < (dev_idx + num_slots);
1884d043c564SKenneth D. Merry 			    map_idx++, mt_entry++) {
1885d043c564SKenneth D. Merry 				if (mt_entry->dpm_entry_num !=
1886d043c564SKenneth D. Merry 				    MPS_DPM_BAD_IDX) {
1887635e58c7SStephen McConnell 					mps_dprint(sc, MPS_ERROR | MPS_MAPPING,
1888635e58c7SStephen McConnell 					    "%s: Conflict in mapping table for "
1889*b99419aeSAlexander Motin 					    "enclosure %d device %d\n",
1890*b99419aeSAlexander Motin 					    __func__, enc_idx, map_idx);
1891d043c564SKenneth D. Merry 					break;
1892d043c564SKenneth D. Merry 				}
1893635e58c7SStephen McConnell 				physical_id =
1894635e58c7SStephen McConnell 				    dpm_entry->PhysicalIdentifier.High;
1895d043c564SKenneth D. Merry 				mt_entry->physical_id = (physical_id << 32) |
1896d043c564SKenneth D. Merry 				    dpm_entry->PhysicalIdentifier.Low;
1897d043c564SKenneth D. Merry 				mt_entry->phy_bits = phy_bits;
1898d043c564SKenneth D. Merry 				mt_entry->id = dev_idx;
1899d043c564SKenneth D. Merry 				mt_entry->dpm_entry_num = entry_num;
1900d043c564SKenneth D. Merry 				mt_entry->missing_count = missing_cnt;
1901d043c564SKenneth D. Merry 				mt_entry->device_info = MPS_DEV_RESERVED;
1902d043c564SKenneth D. Merry 			}
1903d043c564SKenneth D. Merry 		} else if ((ioc_pg8_flags &
1904d043c564SKenneth D. Merry 		    MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
1905d043c564SKenneth D. Merry 		    MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
1906635e58c7SStephen McConnell 			/*
1907635e58c7SStephen McConnell 			 * Device mapping, so simply copy the DPM entries to the
1908635e58c7SStephen McConnell 			 * mapping table, but check for a corrupt mapping table
1909635e58c7SStephen McConnell 			 * (as described above in Enc/Slot mapping).
1910635e58c7SStephen McConnell 			 */
1911d043c564SKenneth D. Merry 			map_idx = dev_idx;
1912d043c564SKenneth D. Merry 			mt_entry = &sc->mapping_table[map_idx];
1913d043c564SKenneth D. Merry 			if (mt_entry->dpm_entry_num != MPS_DPM_BAD_IDX) {
1914635e58c7SStephen McConnell 				mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: "
1915635e58c7SStephen McConnell 				    "Conflict in mapping table for device %d\n",
1916635e58c7SStephen McConnell 				    __func__, map_idx);
1917d043c564SKenneth D. Merry 				break;
1918d043c564SKenneth D. Merry 			}
1919d043c564SKenneth D. Merry 			physical_id = dpm_entry->PhysicalIdentifier.High;
1920d043c564SKenneth D. Merry 			mt_entry->physical_id = (physical_id << 32) |
1921d043c564SKenneth D. Merry 			    dpm_entry->PhysicalIdentifier.Low;
1922d043c564SKenneth D. Merry 			mt_entry->phy_bits = phy_bits;
1923d043c564SKenneth D. Merry 			mt_entry->id = dev_idx;
1924d043c564SKenneth D. Merry 			mt_entry->missing_count = missing_cnt;
1925d043c564SKenneth D. Merry 			mt_entry->dpm_entry_num = entry_num;
1926d043c564SKenneth D. Merry 			mt_entry->device_info = MPS_DEV_RESERVED;
1927d043c564SKenneth D. Merry 		}
1928d043c564SKenneth D. Merry 	} /*close the loop for DPM table */
1929d043c564SKenneth D. Merry }
1930d043c564SKenneth D. Merry 
1931d043c564SKenneth D. Merry /*
1932d043c564SKenneth D. Merry  * mps_mapping_check_devices - start of the day check for device availabilty
1933d043c564SKenneth D. Merry  * @sc: per adapter object
1934d043c564SKenneth D. Merry  *
1935d043c564SKenneth D. Merry  * Returns nothing.
1936d043c564SKenneth D. Merry  */
1937d043c564SKenneth D. Merry void
1938635e58c7SStephen McConnell mps_mapping_check_devices(void *data)
1939d043c564SKenneth D. Merry {
1940d043c564SKenneth D. Merry 	u32 i;
1941d043c564SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
1942635e58c7SStephen McConnell 	struct mps_softc *sc = (struct mps_softc *)data;
1943d043c564SKenneth D. Merry 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
1944d043c564SKenneth D. Merry 	struct enc_mapping_table *et_entry;
1945635e58c7SStephen McConnell 	u32 start_idx = 0, end_idx = 0;
1946635e58c7SStephen McConnell 	u8 stop_device_checks = 0;
1947d043c564SKenneth D. Merry 
1948635e58c7SStephen McConnell 	MPS_FUNCTRACE(sc);
1949635e58c7SStephen McConnell 
1950635e58c7SStephen McConnell 	/*
1951635e58c7SStephen McConnell 	 * Clear this flag so that this function is never called again except
1952635e58c7SStephen McConnell 	 * within this function if the check needs to be done again. The
1953635e58c7SStephen McConnell 	 * purpose is to check for missing devices that are currently in the
1954635e58c7SStephen McConnell 	 * mapping table so do this only at driver init after discovery.
1955635e58c7SStephen McConnell 	 */
1956d043c564SKenneth D. Merry 	sc->track_mapping_events = 0;
1957635e58c7SStephen McConnell 
1958635e58c7SStephen McConnell 	/*
1959635e58c7SStephen McConnell 	 * callout synchronization
1960635e58c7SStephen McConnell 	 * This is used to prevent race conditions for the callout.
1961635e58c7SStephen McConnell 	 */
1962635e58c7SStephen McConnell 	mps_dprint(sc, MPS_MAPPING, "%s: Start check for missing devices.\n",
1963635e58c7SStephen McConnell 	    __func__);
1964635e58c7SStephen McConnell 	mtx_assert(&sc->mps_mtx, MA_OWNED);
1965635e58c7SStephen McConnell 	if ((callout_pending(&sc->device_check_callout)) ||
1966635e58c7SStephen McConnell 	    (!callout_active(&sc->device_check_callout))) {
1967635e58c7SStephen McConnell 		mps_dprint(sc, MPS_MAPPING, "%s: Device Check Callout is "
1968635e58c7SStephen McConnell 		    "already pending or not active.\n", __func__);
1969635e58c7SStephen McConnell 		return;
1970635e58c7SStephen McConnell 	}
1971635e58c7SStephen McConnell 	callout_deactivate(&sc->device_check_callout);
1972635e58c7SStephen McConnell 
1973635e58c7SStephen McConnell 	/*
1974635e58c7SStephen McConnell 	 * Use callout to check if any devices in the mapping table have been
1975635e58c7SStephen McConnell 	 * processed yet. If ALL devices are marked as not init_complete, no
1976635e58c7SStephen McConnell 	 * devices have been processed and mapped. Until devices are mapped
1977635e58c7SStephen McConnell 	 * there's no reason to mark them as missing. Continue resetting this
1978635e58c7SStephen McConnell 	 * callout until devices have been mapped.
1979635e58c7SStephen McConnell 	 */
1980635e58c7SStephen McConnell 	if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
1981635e58c7SStephen McConnell 	    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
1982635e58c7SStephen McConnell 		et_entry = sc->enclosure_table;
1983635e58c7SStephen McConnell 		for (i = 0; i < sc->num_enc_table_entries; i++, et_entry++) {
1984635e58c7SStephen McConnell 			if (et_entry->init_complete) {
1985635e58c7SStephen McConnell 				stop_device_checks = 1;
1986d043c564SKenneth D. Merry 				break;
1987635e58c7SStephen McConnell 			}
1988635e58c7SStephen McConnell 		}
1989635e58c7SStephen McConnell 	} else if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
1990635e58c7SStephen McConnell 	    MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
1991635e58c7SStephen McConnell 		mt_entry = sc->mapping_table;
1992635e58c7SStephen McConnell 		for (i = 0; i < sc->max_devices; i++, mt_entry++) {
1993635e58c7SStephen McConnell 			if (mt_entry->init_complete) {
1994635e58c7SStephen McConnell 				stop_device_checks = 1;
1995635e58c7SStephen McConnell 				break;
1996635e58c7SStephen McConnell 			}
1997635e58c7SStephen McConnell 		}
1998635e58c7SStephen McConnell 	}
1999d043c564SKenneth D. Merry 
2000635e58c7SStephen McConnell 	/*
2001635e58c7SStephen McConnell 	 * Setup another callout check after a delay. Keep doing this until
2002635e58c7SStephen McConnell 	 * devices are mapped.
2003635e58c7SStephen McConnell 	 */
2004635e58c7SStephen McConnell 	if (!stop_device_checks) {
2005635e58c7SStephen McConnell 		mps_dprint(sc, MPS_MAPPING, "%s: No devices have been mapped. "
2006635e58c7SStephen McConnell 		    "Reset callout to check again after a %d second delay.\n",
2007635e58c7SStephen McConnell 		    __func__, MPS_MISSING_CHECK_DELAY);
2008635e58c7SStephen McConnell 		callout_reset(&sc->device_check_callout,
2009635e58c7SStephen McConnell 		    MPS_MISSING_CHECK_DELAY * hz, mps_mapping_check_devices,
2010635e58c7SStephen McConnell 		    sc);
2011635e58c7SStephen McConnell 		return;
2012635e58c7SStephen McConnell 	}
2013635e58c7SStephen McConnell 	mps_dprint(sc, MPS_MAPPING, "%s: Device check complete.\n", __func__);
2014d043c564SKenneth D. Merry 
2015635e58c7SStephen McConnell 	/*
2016635e58c7SStephen McConnell 	 * Depending on the mapping type, check if devices have been processed
2017635e58c7SStephen McConnell 	 * and update their missing counts if not processed.
2018635e58c7SStephen McConnell 	 */
2019d043c564SKenneth D. Merry 	if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
2020d043c564SKenneth D. Merry 	    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
2021d043c564SKenneth D. Merry 		et_entry = sc->enclosure_table;
2022d043c564SKenneth D. Merry 		for (i = 0; i < sc->num_enc_table_entries; i++, et_entry++) {
2023d043c564SKenneth D. Merry 			if (!et_entry->init_complete) {
2024d043c564SKenneth D. Merry 				if (et_entry->missing_count <
2025d043c564SKenneth D. Merry 				    MPS_MAX_MISSING_COUNT) {
2026635e58c7SStephen McConnell 					mps_dprint(sc, MPS_MAPPING, "%s: "
2027635e58c7SStephen McConnell 					    "Enclosure %d is missing from the "
2028635e58c7SStephen McConnell 					    "topology. Update its missing "
2029635e58c7SStephen McConnell 					    "count.\n", __func__, i);
2030d043c564SKenneth D. Merry 					et_entry->missing_count++;
2031d043c564SKenneth D. Merry 					if (et_entry->dpm_entry_num !=
2032635e58c7SStephen McConnell 					    MPS_DPM_BAD_IDX) {
2033d043c564SKenneth D. Merry 						_mapping_commit_enc_entry(sc,
2034d043c564SKenneth D. Merry 						    et_entry);
2035d043c564SKenneth D. Merry 					}
2036635e58c7SStephen McConnell 				}
2037d043c564SKenneth D. Merry 				et_entry->init_complete = 1;
2038d043c564SKenneth D. Merry 			}
2039d043c564SKenneth D. Merry 		}
2040d043c564SKenneth D. Merry 		if (!sc->ir_firmware)
2041d043c564SKenneth D. Merry 			return;
2042d043c564SKenneth D. Merry 		_mapping_get_ir_maprange(sc, &start_idx, &end_idx);
2043d043c564SKenneth D. Merry 		mt_entry = &sc->mapping_table[start_idx];
2044635e58c7SStephen McConnell 	} else if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
2045635e58c7SStephen McConnell 	    MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
2046635e58c7SStephen McConnell 		start_idx = 0;
2047635e58c7SStephen McConnell 		end_idx = sc->max_devices - 1;
2048635e58c7SStephen McConnell 		mt_entry = sc->mapping_table;
2049635e58c7SStephen McConnell 	}
2050635e58c7SStephen McConnell 
2051635e58c7SStephen McConnell 	/*
2052635e58c7SStephen McConnell 	 * The start and end indices have been set above according to the
2053635e58c7SStephen McConnell 	 * mapping type. Go through these mappings and update any entries that
2054635e58c7SStephen McConnell 	 * do not have the init_complete flag set, which means they are missing.
2055635e58c7SStephen McConnell 	 */
2056635e58c7SStephen McConnell 	if (end_idx == 0)
2057635e58c7SStephen McConnell 		return;
2058d043c564SKenneth D. Merry 	for (i = start_idx; i < (end_idx + 1); i++, mt_entry++) {
2059d043c564SKenneth D. Merry 		if (mt_entry->device_info & MPS_DEV_RESERVED
2060d043c564SKenneth D. Merry 		    && !mt_entry->physical_id)
2061d043c564SKenneth D. Merry 			mt_entry->init_complete = 1;
2062d043c564SKenneth D. Merry 		else if (mt_entry->device_info & MPS_DEV_RESERVED) {
2063d043c564SKenneth D. Merry 			if (!mt_entry->init_complete) {
2064635e58c7SStephen McConnell 				mps_dprint(sc, MPS_MAPPING, "%s: Device in "
2065635e58c7SStephen McConnell 				    "mapping table at index %d is missing from "
2066635e58c7SStephen McConnell 				    "topology. Update its missing count.\n",
2067635e58c7SStephen McConnell 				    __func__, i);
2068d043c564SKenneth D. Merry 				if (mt_entry->missing_count <
2069d043c564SKenneth D. Merry 				    MPS_MAX_MISSING_COUNT) {
2070d043c564SKenneth D. Merry 					mt_entry->missing_count++;
2071d043c564SKenneth D. Merry 					if (mt_entry->dpm_entry_num !=
2072635e58c7SStephen McConnell 					    MPS_DPM_BAD_IDX) {
2073d043c564SKenneth D. Merry 						_mapping_commit_map_entry(sc,
2074d043c564SKenneth D. Merry 						    mt_entry);
2075d043c564SKenneth D. Merry 					}
2076d043c564SKenneth D. Merry 				}
2077d043c564SKenneth D. Merry 				mt_entry->init_complete = 1;
2078d043c564SKenneth D. Merry 			}
2079d043c564SKenneth D. Merry 		}
2080d043c564SKenneth D. Merry 	}
2081d043c564SKenneth D. Merry }
2082d043c564SKenneth D. Merry 
2083d043c564SKenneth D. Merry /**
2084d043c564SKenneth D. Merry  * mps_mapping_initialize - initialize mapping tables
2085d043c564SKenneth D. Merry  * @sc: per adapter object
2086d043c564SKenneth D. Merry  *
2087d043c564SKenneth D. Merry  * Read controller persitant mapping tables into internal data area.
2088d043c564SKenneth D. Merry  *
2089d043c564SKenneth D. Merry  * Return 0 for success or non-zero for failure.
2090d043c564SKenneth D. Merry  */
2091d043c564SKenneth D. Merry int
2092d043c564SKenneth D. Merry mps_mapping_initialize(struct mps_softc *sc)
2093d043c564SKenneth D. Merry {
2094d043c564SKenneth D. Merry 	uint16_t volume_mapping_flags, dpm_pg0_sz;
2095d043c564SKenneth D. Merry 	uint32_t i;
2096d043c564SKenneth D. Merry 	Mpi2ConfigReply_t mpi_reply;
2097d043c564SKenneth D. Merry 	int error;
2098d043c564SKenneth D. Merry 	uint8_t retry_count;
2099d043c564SKenneth D. Merry 	uint16_t ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
2100d043c564SKenneth D. Merry 
2101d043c564SKenneth D. Merry 	/* The additional 1 accounts for the virtual enclosure
2102d043c564SKenneth D. Merry 	 * created for the controller
2103d043c564SKenneth D. Merry 	 */
2104d043c564SKenneth D. Merry 	sc->max_enclosures = sc->facts->MaxEnclosures + 1;
2105d043c564SKenneth D. Merry 	sc->max_expanders = sc->facts->MaxSasExpanders;
2106d043c564SKenneth D. Merry 	sc->max_volumes = sc->facts->MaxVolumes;
2107d043c564SKenneth D. Merry 	sc->max_devices = sc->facts->MaxTargets + sc->max_volumes;
2108d043c564SKenneth D. Merry 	sc->pending_map_events = 0;
2109d043c564SKenneth D. Merry 	sc->num_enc_table_entries = 0;
2110d043c564SKenneth D. Merry 	sc->num_rsvd_entries = 0;
2111d043c564SKenneth D. Merry 	sc->max_dpm_entries = sc->ioc_pg8.MaxPersistentEntries;
2112d043c564SKenneth D. Merry 	sc->is_dpm_enable = (sc->max_dpm_entries) ? 1 : 0;
2113d043c564SKenneth D. Merry 	sc->track_mapping_events = 0;
2114d043c564SKenneth D. Merry 
2115635e58c7SStephen McConnell 	mps_dprint(sc, MPS_MAPPING, "%s: Mapping table has a max of %d entries "
2116635e58c7SStephen McConnell 	    "and DPM has a max of %d entries.\n", __func__, sc->max_devices,
2117635e58c7SStephen McConnell 	    sc->max_dpm_entries);
2118d043c564SKenneth D. Merry 	if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_DISABLE_PERSISTENT_MAPPING)
2119d043c564SKenneth D. Merry 		sc->is_dpm_enable = 0;
2120d043c564SKenneth D. Merry 
2121d043c564SKenneth D. Merry 	if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0)
2122d043c564SKenneth D. Merry 		sc->num_rsvd_entries = 1;
2123d043c564SKenneth D. Merry 
2124d043c564SKenneth D. Merry 	volume_mapping_flags = sc->ioc_pg8.IRVolumeMappingFlags &
2125d043c564SKenneth D. Merry 	    MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
2126d043c564SKenneth D. Merry 	if (sc->ir_firmware && (volume_mapping_flags ==
2127d043c564SKenneth D. Merry 	    MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING))
2128d043c564SKenneth D. Merry 		sc->num_rsvd_entries += sc->max_volumes;
2129d043c564SKenneth D. Merry 
2130d043c564SKenneth D. Merry 	error = mps_mapping_allocate_memory(sc);
2131d043c564SKenneth D. Merry 	if (error)
2132d043c564SKenneth D. Merry 		return (error);
2133d043c564SKenneth D. Merry 
2134d043c564SKenneth D. Merry 	for (i = 0; i < sc->max_devices; i++)
2135d043c564SKenneth D. Merry 		_mapping_clear_map_entry(sc->mapping_table + i);
2136d043c564SKenneth D. Merry 
2137d043c564SKenneth D. Merry 	for (i = 0; i < sc->max_enclosures; i++)
2138d043c564SKenneth D. Merry 		_mapping_clear_enc_entry(sc->enclosure_table + i);
2139d043c564SKenneth D. Merry 
2140d043c564SKenneth D. Merry 	for (i = 0; i < sc->max_devices; i++) {
2141d043c564SKenneth D. Merry 		sc->removal_table[i].dev_handle = 0;
2142d043c564SKenneth D. Merry 		sc->removal_table[i].dpm_entry_num = MPS_DPM_BAD_IDX;
2143d043c564SKenneth D. Merry 	}
2144d043c564SKenneth D. Merry 
2145d043c564SKenneth D. Merry 	memset(sc->dpm_entry_used, 0, sc->max_dpm_entries);
2146d043c564SKenneth D. Merry 	memset(sc->dpm_flush_entry, 0, sc->max_dpm_entries);
2147d043c564SKenneth D. Merry 
2148d043c564SKenneth D. Merry 	if (sc->is_dpm_enable) {
2149d043c564SKenneth D. Merry 		dpm_pg0_sz = sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER) +
2150d043c564SKenneth D. Merry 		    (sc->max_dpm_entries *
2151d043c564SKenneth D. Merry 		     sizeof(MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY));
2152d043c564SKenneth D. Merry 		retry_count = 0;
2153d043c564SKenneth D. Merry 
2154d043c564SKenneth D. Merry retry_read_dpm:
2155d043c564SKenneth D. Merry 		if (mps_config_get_dpm_pg0(sc, &mpi_reply, sc->dpm_pg0,
2156d043c564SKenneth D. Merry 		    dpm_pg0_sz)) {
2157635e58c7SStephen McConnell 			mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: DPM page "
2158635e58c7SStephen McConnell 			    "read failed.\n", __func__);
2159d043c564SKenneth D. Merry 			if (retry_count < 3) {
2160d043c564SKenneth D. Merry 				retry_count++;
2161d043c564SKenneth D. Merry 				goto retry_read_dpm;
2162d043c564SKenneth D. Merry 			}
2163d043c564SKenneth D. Merry 			sc->is_dpm_enable = 0;
2164d043c564SKenneth D. Merry 		}
2165d043c564SKenneth D. Merry 	}
2166d043c564SKenneth D. Merry 
2167d043c564SKenneth D. Merry 	if (sc->is_dpm_enable)
2168d043c564SKenneth D. Merry 		_mapping_process_dpm_pg0(sc);
2169635e58c7SStephen McConnell 	else {
2170635e58c7SStephen McConnell 		mps_dprint(sc, MPS_MAPPING, "%s: DPM processing is disabled. "
2171635e58c7SStephen McConnell 		    "Device mappings will not persist across reboots or "
2172635e58c7SStephen McConnell 		    "resets.\n", __func__);
2173635e58c7SStephen McConnell 	}
2174d043c564SKenneth D. Merry 
2175d043c564SKenneth D. Merry 	sc->track_mapping_events = 1;
2176d043c564SKenneth D. Merry 	return 0;
2177d043c564SKenneth D. Merry }
2178d043c564SKenneth D. Merry 
2179d043c564SKenneth D. Merry /**
2180d043c564SKenneth D. Merry  * mps_mapping_exit - clear mapping table and associated memory
2181d043c564SKenneth D. Merry  * @sc: per adapter object
2182d043c564SKenneth D. Merry  *
2183d043c564SKenneth D. Merry  * Returns nothing.
2184d043c564SKenneth D. Merry  */
2185d043c564SKenneth D. Merry void
2186d043c564SKenneth D. Merry mps_mapping_exit(struct mps_softc *sc)
2187d043c564SKenneth D. Merry {
2188d043c564SKenneth D. Merry 	_mapping_flush_dpm_pages(sc);
2189d043c564SKenneth D. Merry 	mps_mapping_free_memory(sc);
2190d043c564SKenneth D. Merry }
2191d043c564SKenneth D. Merry 
2192d043c564SKenneth D. Merry /**
2193635e58c7SStephen McConnell  * mps_mapping_get_tid - return the target id for sas device and handle
2194d043c564SKenneth D. Merry  * @sc: per adapter object
2195d043c564SKenneth D. Merry  * @sas_address: sas address of the device
2196d043c564SKenneth D. Merry  * @handle: device handle
2197d043c564SKenneth D. Merry  *
2198635e58c7SStephen McConnell  * Returns valid target ID on success or BAD_ID.
2199d043c564SKenneth D. Merry  */
2200d043c564SKenneth D. Merry unsigned int
2201635e58c7SStephen McConnell mps_mapping_get_tid(struct mps_softc *sc, uint64_t sas_address, u16 handle)
2202d043c564SKenneth D. Merry {
2203d043c564SKenneth D. Merry 	u32 map_idx;
2204d043c564SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
2205d043c564SKenneth D. Merry 
2206d043c564SKenneth D. Merry 	for (map_idx = 0; map_idx < sc->max_devices; map_idx++) {
2207d043c564SKenneth D. Merry 		mt_entry = &sc->mapping_table[map_idx];
2208d043c564SKenneth D. Merry 		if (mt_entry->dev_handle == handle && mt_entry->physical_id ==
2209d043c564SKenneth D. Merry 		    sas_address)
2210d043c564SKenneth D. Merry 			return mt_entry->id;
2211d043c564SKenneth D. Merry 	}
2212d043c564SKenneth D. Merry 
2213d043c564SKenneth D. Merry 	return MPS_MAP_BAD_ID;
2214d043c564SKenneth D. Merry }
2215d043c564SKenneth D. Merry 
2216d043c564SKenneth D. Merry /**
2217635e58c7SStephen McConnell  * mps_mapping_get_tid_from_handle - find a target id in mapping table using
2218d043c564SKenneth D. Merry  * only the dev handle.  This is just a wrapper function for the local function
2219d043c564SKenneth D. Merry  * _mapping_get_mt_idx_from_handle.
2220d043c564SKenneth D. Merry  * @sc: per adapter object
2221d043c564SKenneth D. Merry  * @handle: device handle
2222d043c564SKenneth D. Merry  *
2223635e58c7SStephen McConnell  * Returns valid target ID on success or BAD_ID.
2224d043c564SKenneth D. Merry  */
2225d043c564SKenneth D. Merry unsigned int
2226635e58c7SStephen McConnell mps_mapping_get_tid_from_handle(struct mps_softc *sc, u16 handle)
2227d043c564SKenneth D. Merry {
2228d043c564SKenneth D. Merry 	return (_mapping_get_mt_idx_from_handle(sc, handle));
2229d043c564SKenneth D. Merry }
2230d043c564SKenneth D. Merry 
2231d043c564SKenneth D. Merry /**
2232635e58c7SStephen McConnell  * mps_mapping_get_raid_tid - return the target id for raid device
2233d043c564SKenneth D. Merry  * @sc: per adapter object
2234d043c564SKenneth D. Merry  * @wwid: world wide identifier for raid volume
2235635e58c7SStephen McConnell  * @volHandle: volume device handle
2236d043c564SKenneth D. Merry  *
2237635e58c7SStephen McConnell  * Returns valid target ID on success or BAD_ID.
2238d043c564SKenneth D. Merry  */
2239d043c564SKenneth D. Merry unsigned int
2240635e58c7SStephen McConnell mps_mapping_get_raid_tid(struct mps_softc *sc, u64 wwid, u16 volHandle)
2241d043c564SKenneth D. Merry {
2242635e58c7SStephen McConnell 	u32 start_idx, end_idx, map_idx;
2243d043c564SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
2244d043c564SKenneth D. Merry 
2245635e58c7SStephen McConnell 	_mapping_get_ir_maprange(sc, &start_idx, &end_idx);
2246635e58c7SStephen McConnell 	mt_entry = &sc->mapping_table[start_idx];
2247635e58c7SStephen McConnell 	for (map_idx  = start_idx; map_idx <= end_idx; map_idx++, mt_entry++) {
2248635e58c7SStephen McConnell 		if (mt_entry->dev_handle == volHandle &&
2249635e58c7SStephen McConnell 		    mt_entry->physical_id == wwid)
2250d043c564SKenneth D. Merry 			return mt_entry->id;
2251d043c564SKenneth D. Merry 	}
2252d043c564SKenneth D. Merry 
2253d043c564SKenneth D. Merry 	return MPS_MAP_BAD_ID;
2254d043c564SKenneth D. Merry }
2255d043c564SKenneth D. Merry 
2256d043c564SKenneth D. Merry /**
2257635e58c7SStephen McConnell  * mps_mapping_get_raid_tid_from_handle - find raid device in mapping table
2258d043c564SKenneth D. Merry  * using only the volume dev handle.  This is just a wrapper function for the
2259d043c564SKenneth D. Merry  * local function _mapping_get_ir_mt_idx_from_handle.
2260d043c564SKenneth D. Merry  * @sc: per adapter object
2261d043c564SKenneth D. Merry  * @volHandle: volume device handle
2262d043c564SKenneth D. Merry  *
2263635e58c7SStephen McConnell  * Returns valid target ID on success or BAD_ID.
2264d043c564SKenneth D. Merry  */
2265d043c564SKenneth D. Merry unsigned int
2266635e58c7SStephen McConnell mps_mapping_get_raid_tid_from_handle(struct mps_softc *sc, u16 volHandle)
2267d043c564SKenneth D. Merry {
2268d043c564SKenneth D. Merry 	return (_mapping_get_ir_mt_idx_from_handle(sc, volHandle));
2269d043c564SKenneth D. Merry }
2270d043c564SKenneth D. Merry 
2271d043c564SKenneth D. Merry /**
2272d043c564SKenneth D. Merry  * mps_mapping_enclosure_dev_status_change_event - handle enclosure events
2273d043c564SKenneth D. Merry  * @sc: per adapter object
2274d043c564SKenneth D. Merry  * @event_data: event data payload
2275d043c564SKenneth D. Merry  *
2276d043c564SKenneth D. Merry  * Return nothing.
2277d043c564SKenneth D. Merry  */
2278d043c564SKenneth D. Merry void
2279d043c564SKenneth D. Merry mps_mapping_enclosure_dev_status_change_event(struct mps_softc *sc,
2280d043c564SKenneth D. Merry     Mpi2EventDataSasEnclDevStatusChange_t *event_data)
2281d043c564SKenneth D. Merry {
2282d043c564SKenneth D. Merry 	u8 enc_idx, missing_count;
2283d043c564SKenneth D. Merry 	struct enc_mapping_table *et_entry;
2284d043c564SKenneth D. Merry 	Mpi2DriverMap0Entry_t *dpm_entry;
2285d043c564SKenneth D. Merry 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
2286d043c564SKenneth D. Merry 	u8 map_shift = MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT;
2287d043c564SKenneth D. Merry 	u8 update_phy_bits = 0;
2288d043c564SKenneth D. Merry 	u32 saved_phy_bits;
2289d043c564SKenneth D. Merry 	uint64_t temp64_var;
2290d043c564SKenneth D. Merry 
2291d043c564SKenneth D. Merry 	if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) !=
2292d043c564SKenneth D. Merry 	    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING)
2293d043c564SKenneth D. Merry 		goto out;
2294d043c564SKenneth D. Merry 
2295d043c564SKenneth D. Merry 	dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
2296d043c564SKenneth D. Merry 	    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
2297d043c564SKenneth D. Merry 
2298d043c564SKenneth D. Merry 	if (event_data->ReasonCode == MPI2_EVENT_SAS_ENCL_RC_ADDED) {
2299d043c564SKenneth D. Merry 		if (!event_data->NumSlots) {
2300635e58c7SStephen McConnell 			mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: Enclosure "
2301635e58c7SStephen McConnell 			    "with handle = 0x%x reported 0 slots.\n", __func__,
2302d043c564SKenneth D. Merry 			    le16toh(event_data->EnclosureHandle));
2303d043c564SKenneth D. Merry 			goto out;
2304d043c564SKenneth D. Merry 		}
2305d043c564SKenneth D. Merry 		temp64_var = event_data->EnclosureLogicalID.High;
2306d043c564SKenneth D. Merry 		temp64_var = (temp64_var << 32) |
2307d043c564SKenneth D. Merry 		    event_data->EnclosureLogicalID.Low;
2308d043c564SKenneth D. Merry 		enc_idx = _mapping_get_enc_idx_from_id(sc, temp64_var,
2309d043c564SKenneth D. Merry 		    event_data->PhyBits);
2310635e58c7SStephen McConnell 
2311635e58c7SStephen McConnell 		/*
2312635e58c7SStephen McConnell 		 * If the Added enclosure is already in the Enclosure Table,
2313635e58c7SStephen McConnell 		 * make sure that all the the enclosure info is up to date. If
2314635e58c7SStephen McConnell 		 * the enclosure was missing and has just been added back, or if
2315635e58c7SStephen McConnell 		 * the enclosure's Phy Bits have changed, clear the missing
2316635e58c7SStephen McConnell 		 * count and update the Phy Bits in the mapping table and in the
2317635e58c7SStephen McConnell 		 * DPM, if it's being used.
2318635e58c7SStephen McConnell 		 */
2319d043c564SKenneth D. Merry 		if (enc_idx != MPS_ENCTABLE_BAD_IDX) {
2320d043c564SKenneth D. Merry 			et_entry = &sc->enclosure_table[enc_idx];
2321d043c564SKenneth D. Merry 			if (et_entry->init_complete &&
2322d043c564SKenneth D. Merry 			    !et_entry->missing_count) {
2323635e58c7SStephen McConnell 				mps_dprint(sc, MPS_MAPPING, "%s: Enclosure %d "
2324635e58c7SStephen McConnell 				    "is already present with handle = 0x%x\n",
2325635e58c7SStephen McConnell 				    __func__, enc_idx, et_entry->enc_handle);
2326d043c564SKenneth D. Merry 				goto out;
2327d043c564SKenneth D. Merry 			}
2328d043c564SKenneth D. Merry 			et_entry->enc_handle = le16toh(event_data->
2329d043c564SKenneth D. Merry 			    EnclosureHandle);
2330d043c564SKenneth D. Merry 			et_entry->start_slot = le16toh(event_data->StartSlot);
2331d043c564SKenneth D. Merry 			saved_phy_bits = et_entry->phy_bits;
2332d043c564SKenneth D. Merry 			et_entry->phy_bits |= le32toh(event_data->PhyBits);
2333d043c564SKenneth D. Merry 			if (saved_phy_bits != et_entry->phy_bits)
2334d043c564SKenneth D. Merry 				update_phy_bits = 1;
2335d043c564SKenneth D. Merry 			if (et_entry->missing_count || update_phy_bits) {
2336d043c564SKenneth D. Merry 				et_entry->missing_count = 0;
2337d043c564SKenneth D. Merry 				if (sc->is_dpm_enable &&
2338d043c564SKenneth D. Merry 				    et_entry->dpm_entry_num !=
2339d043c564SKenneth D. Merry 				    MPS_DPM_BAD_IDX) {
2340d043c564SKenneth D. Merry 					dpm_entry += et_entry->dpm_entry_num;
2341d043c564SKenneth D. Merry 					missing_count =
2342d043c564SKenneth D. Merry 					    (u8)(dpm_entry->MappingInformation &
2343d043c564SKenneth D. Merry 					    MPI2_DRVMAP0_MAPINFO_MISSING_MASK);
2344635e58c7SStephen McConnell 					if (missing_count || update_phy_bits) {
2345d043c564SKenneth D. Merry 						dpm_entry->MappingInformation
2346d043c564SKenneth D. Merry 						    = et_entry->num_slots;
2347d043c564SKenneth D. Merry 						dpm_entry->MappingInformation
2348d043c564SKenneth D. Merry 						    <<= map_shift;
2349d043c564SKenneth D. Merry 						dpm_entry->PhysicalBitsMapping
2350d043c564SKenneth D. Merry 						    = et_entry->phy_bits;
2351d043c564SKenneth D. Merry 						sc->dpm_flush_entry[et_entry->
2352d043c564SKenneth D. Merry 						    dpm_entry_num] = 1;
2353d043c564SKenneth D. Merry 					}
2354d043c564SKenneth D. Merry 				}
2355d043c564SKenneth D. Merry 			}
2356d043c564SKenneth D. Merry 		} else {
2357635e58c7SStephen McConnell 			/*
2358635e58c7SStephen McConnell 			 * This is a new enclosure that is being added.
2359635e58c7SStephen McConnell 			 * Initialize the Enclosure Table entry. It will be
2360635e58c7SStephen McConnell 			 * finalized when a device is added for the enclosure
2361635e58c7SStephen McConnell 			 * and the enclosure has enough space in the Mapping
2362635e58c7SStephen McConnell 			 * Table to map its devices.
2363635e58c7SStephen McConnell 			 */
2364*b99419aeSAlexander Motin 			if (sc->num_enc_table_entries < sc->max_enclosures) {
2365d043c564SKenneth D. Merry 				enc_idx = sc->num_enc_table_entries;
2366*b99419aeSAlexander Motin 				sc->num_enc_table_entries++;
2367*b99419aeSAlexander Motin 			} else {
2368*b99419aeSAlexander Motin 				enc_idx = _mapping_get_high_missing_et_idx(sc);
2369*b99419aeSAlexander Motin 				if (enc_idx != MPS_ENCTABLE_BAD_IDX) {
2370*b99419aeSAlexander Motin 					et_entry = &sc->enclosure_table[enc_idx];
2371*b99419aeSAlexander Motin 					_mapping_add_to_removal_table(sc,
2372*b99419aeSAlexander Motin 					    et_entry->dpm_entry_num);
2373*b99419aeSAlexander Motin 					_mapping_clear_enc_entry(et_entry);
2374*b99419aeSAlexander Motin 				}
2375*b99419aeSAlexander Motin 			}
2376*b99419aeSAlexander Motin 			if (enc_idx == MPS_ENCTABLE_BAD_IDX) {
2377635e58c7SStephen McConnell 				mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: "
2378635e58c7SStephen McConnell 				    "Enclosure cannot be added to mapping "
2379635e58c7SStephen McConnell 				    "table because it's full.\n", __func__);
2380d043c564SKenneth D. Merry 				goto out;
2381d043c564SKenneth D. Merry 			}
2382d043c564SKenneth D. Merry 			et_entry = &sc->enclosure_table[enc_idx];
2383d043c564SKenneth D. Merry 			et_entry->enc_handle = le16toh(event_data->
2384d043c564SKenneth D. Merry 			    EnclosureHandle);
2385635e58c7SStephen McConnell 			et_entry->enclosure_id = le64toh(event_data->
2386635e58c7SStephen McConnell 			    EnclosureLogicalID.High);
2387635e58c7SStephen McConnell 			et_entry->enclosure_id =
2388635e58c7SStephen McConnell 			    ((et_entry->enclosure_id << 32) |
2389635e58c7SStephen McConnell 			    le64toh(event_data->EnclosureLogicalID.Low));
2390d043c564SKenneth D. Merry 			et_entry->start_index = MPS_MAPTABLE_BAD_IDX;
2391d043c564SKenneth D. Merry 			et_entry->dpm_entry_num = MPS_DPM_BAD_IDX;
2392d043c564SKenneth D. Merry 			et_entry->num_slots = le16toh(event_data->NumSlots);
2393d043c564SKenneth D. Merry 			et_entry->start_slot = le16toh(event_data->StartSlot);
2394d043c564SKenneth D. Merry 			et_entry->phy_bits = le32toh(event_data->PhyBits);
2395d043c564SKenneth D. Merry 		}
2396d043c564SKenneth D. Merry 		et_entry->init_complete = 1;
2397d043c564SKenneth D. Merry 	} else if (event_data->ReasonCode ==
2398d043c564SKenneth D. Merry 	    MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING) {
2399635e58c7SStephen McConnell 		/*
2400635e58c7SStephen McConnell 		 * An enclosure was removed. Update its missing count and then
2401635e58c7SStephen McConnell 		 * update the DPM entry with the new missing count for the
2402635e58c7SStephen McConnell 		 * enclosure.
2403635e58c7SStephen McConnell 		 */
2404d043c564SKenneth D. Merry 		enc_idx = _mapping_get_enc_idx_from_handle(sc,
2405d043c564SKenneth D. Merry 		    le16toh(event_data->EnclosureHandle));
2406d043c564SKenneth D. Merry 		if (enc_idx == MPS_ENCTABLE_BAD_IDX) {
2407635e58c7SStephen McConnell 			mps_dprint(sc, MPS_ERROR | MPS_MAPPING, "%s: Cannot "
2408*b99419aeSAlexander Motin 			    "unmap enclosure with handle 0x%04x because it "
2409*b99419aeSAlexander Motin 			    "has already been deleted.\n", __func__,
2410*b99419aeSAlexander Motin 			    le16toh(event_data->EnclosureHandle));
2411d043c564SKenneth D. Merry 			goto out;
2412d043c564SKenneth D. Merry 		}
2413d043c564SKenneth D. Merry 		et_entry = &sc->enclosure_table[enc_idx];
2414d043c564SKenneth D. Merry 		if (et_entry->missing_count < MPS_MAX_MISSING_COUNT)
2415d043c564SKenneth D. Merry 			et_entry->missing_count++;
2416635e58c7SStephen McConnell 		if (sc->is_dpm_enable &&
2417d043c564SKenneth D. Merry 		    et_entry->dpm_entry_num != MPS_DPM_BAD_IDX) {
2418d043c564SKenneth D. Merry 			dpm_entry += et_entry->dpm_entry_num;
2419d043c564SKenneth D. Merry 			dpm_entry->MappingInformation = et_entry->num_slots;
2420d043c564SKenneth D. Merry 			dpm_entry->MappingInformation <<= map_shift;
2421d043c564SKenneth D. Merry 			dpm_entry->MappingInformation |=
2422d043c564SKenneth D. Merry 			    et_entry->missing_count;
2423d043c564SKenneth D. Merry 			sc->dpm_flush_entry[et_entry->dpm_entry_num] = 1;
2424d043c564SKenneth D. Merry 		}
2425d043c564SKenneth D. Merry 		et_entry->init_complete = 1;
2426d043c564SKenneth D. Merry 	}
2427d043c564SKenneth D. Merry 
2428d043c564SKenneth D. Merry out:
2429d043c564SKenneth D. Merry 	_mapping_flush_dpm_pages(sc);
2430d043c564SKenneth D. Merry 	if (sc->pending_map_events)
2431d043c564SKenneth D. Merry 		sc->pending_map_events--;
2432d043c564SKenneth D. Merry }
2433d043c564SKenneth D. Merry 
2434d043c564SKenneth D. Merry /**
2435d043c564SKenneth D. Merry  * mps_mapping_topology_change_event - handle topology change events
2436d043c564SKenneth D. Merry  * @sc: per adapter object
2437d043c564SKenneth D. Merry  * @event_data: event data payload
2438d043c564SKenneth D. Merry  *
2439d043c564SKenneth D. Merry  * Returns nothing.
2440d043c564SKenneth D. Merry  */
2441d043c564SKenneth D. Merry void
2442d043c564SKenneth D. Merry mps_mapping_topology_change_event(struct mps_softc *sc,
2443d043c564SKenneth D. Merry     Mpi2EventDataSasTopologyChangeList_t *event_data)
2444d043c564SKenneth D. Merry {
2445d043c564SKenneth D. Merry 	struct _map_topology_change topo_change;
2446d043c564SKenneth D. Merry 	struct _map_phy_change *phy_change;
2447d043c564SKenneth D. Merry 	Mpi2EventSasTopoPhyEntry_t *event_phy_change;
2448d043c564SKenneth D. Merry 	u8 i, num_entries;
2449d043c564SKenneth D. Merry 
2450d043c564SKenneth D. Merry 	topo_change.enc_handle = le16toh(event_data->EnclosureHandle);
2451d043c564SKenneth D. Merry 	topo_change.exp_handle = le16toh(event_data->ExpanderDevHandle);
2452d043c564SKenneth D. Merry 	num_entries = event_data->NumEntries;
2453d043c564SKenneth D. Merry 	topo_change.num_entries = num_entries;
2454d043c564SKenneth D. Merry 	topo_change.start_phy_num = event_data->StartPhyNum;
2455d043c564SKenneth D. Merry 	topo_change.num_phys = event_data->NumPhys;
2456d043c564SKenneth D. Merry 	topo_change.exp_status = event_data->ExpStatus;
2457d043c564SKenneth D. Merry 	event_phy_change = event_data->PHY;
2458d043c564SKenneth D. Merry 	topo_change.phy_details = NULL;
2459d043c564SKenneth D. Merry 
2460d043c564SKenneth D. Merry 	if (!num_entries)
2461d043c564SKenneth D. Merry 		goto out;
2462ac2fffa4SPedro F. Giffuni 	phy_change = malloc(sizeof(struct _map_phy_change) * num_entries,
2463d043c564SKenneth D. Merry 	    M_MPT2, M_NOWAIT|M_ZERO);
2464d043c564SKenneth D. Merry 	topo_change.phy_details = phy_change;
2465d043c564SKenneth D. Merry 	if (!phy_change)
2466d043c564SKenneth D. Merry 		goto out;
2467d043c564SKenneth D. Merry 	for (i = 0; i < num_entries; i++, event_phy_change++, phy_change++) {
2468d043c564SKenneth D. Merry 		phy_change->dev_handle = le16toh(event_phy_change->
2469d043c564SKenneth D. Merry 		    AttachedDevHandle);
2470d043c564SKenneth D. Merry 		phy_change->reason = event_phy_change->PhyStatus &
2471d043c564SKenneth D. Merry 		    MPI2_EVENT_SAS_TOPO_RC_MASK;
2472d043c564SKenneth D. Merry 	}
2473d043c564SKenneth D. Merry 	_mapping_update_missing_count(sc, &topo_change);
2474d043c564SKenneth D. Merry 	_mapping_get_dev_info(sc, &topo_change);
2475d043c564SKenneth D. Merry 	_mapping_clear_removed_entries(sc);
2476d043c564SKenneth D. Merry 	_mapping_add_new_device(sc, &topo_change);
2477d043c564SKenneth D. Merry 
2478d043c564SKenneth D. Merry out:
2479d043c564SKenneth D. Merry 	free(topo_change.phy_details, M_MPT2);
2480d043c564SKenneth D. Merry 	_mapping_flush_dpm_pages(sc);
2481d043c564SKenneth D. Merry 	if (sc->pending_map_events)
2482d043c564SKenneth D. Merry 		sc->pending_map_events--;
2483d043c564SKenneth D. Merry }
2484d043c564SKenneth D. Merry 
2485d043c564SKenneth D. Merry /**
2486d043c564SKenneth D. Merry  * mps_mapping_ir_config_change_event - handle IR config change list events
2487d043c564SKenneth D. Merry  * @sc: per adapter object
2488d043c564SKenneth D. Merry  * @event_data: event data payload
2489d043c564SKenneth D. Merry  *
2490d043c564SKenneth D. Merry  * Returns nothing.
2491d043c564SKenneth D. Merry  */
2492d043c564SKenneth D. Merry void
2493d043c564SKenneth D. Merry mps_mapping_ir_config_change_event(struct mps_softc *sc,
2494d043c564SKenneth D. Merry     Mpi2EventDataIrConfigChangeList_t *event_data)
2495d043c564SKenneth D. Merry {
2496d043c564SKenneth D. Merry 	Mpi2EventIrConfigElement_t *element;
2497d043c564SKenneth D. Merry 	int i;
2498d043c564SKenneth D. Merry 	u64 *wwid_table;
2499d043c564SKenneth D. Merry 	u32 map_idx, flags;
2500d043c564SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
2501d043c564SKenneth D. Merry 	u16 element_flags;
2502d043c564SKenneth D. Merry 
2503ac2fffa4SPedro F. Giffuni 	wwid_table = malloc(sizeof(u64) * event_data->NumElements, M_MPT2,
2504d043c564SKenneth D. Merry 	    M_NOWAIT | M_ZERO);
2505d043c564SKenneth D. Merry 	if (!wwid_table)
2506d043c564SKenneth D. Merry 		goto out;
2507d043c564SKenneth D. Merry 	element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
2508d043c564SKenneth D. Merry 	flags = le32toh(event_data->Flags);
2509635e58c7SStephen McConnell 
2510635e58c7SStephen McConnell 	/*
2511635e58c7SStephen McConnell 	 * For volume changes, get the WWID for the volume and put it in a
2512635e58c7SStephen McConnell 	 * table to be used in the processing of the IR change event.
2513635e58c7SStephen McConnell 	 */
2514d043c564SKenneth D. Merry 	for (i = 0; i < event_data->NumElements; i++, element++) {
2515d043c564SKenneth D. Merry 		element_flags = le16toh(element->ElementFlags);
2516d043c564SKenneth D. Merry 		if ((element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_ADDED) &&
2517d043c564SKenneth D. Merry 		    (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_REMOVED) &&
2518d043c564SKenneth D. Merry 		    (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE)
2519d043c564SKenneth D. Merry 		    && (element->ReasonCode !=
2520d043c564SKenneth D. Merry 			MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED))
2521d043c564SKenneth D. Merry 			continue;
2522d043c564SKenneth D. Merry 		if ((element_flags &
2523d043c564SKenneth D. Merry 		    MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK) ==
2524d043c564SKenneth D. Merry 		    MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT) {
2525d043c564SKenneth D. Merry 			mps_config_get_volume_wwid(sc,
2526d043c564SKenneth D. Merry 			    le16toh(element->VolDevHandle), &wwid_table[i]);
2527d043c564SKenneth D. Merry 		}
2528d043c564SKenneth D. Merry 	}
2529635e58c7SStephen McConnell 
2530635e58c7SStephen McConnell 	/*
2531635e58c7SStephen McConnell 	 * Check the ReasonCode for each element in the IR event and Add/Remove
2532635e58c7SStephen McConnell 	 * Volumes or Physical Disks of Volumes to/from the mapping table. Use
2533635e58c7SStephen McConnell 	 * the WWIDs gotten above in wwid_table.
2534635e58c7SStephen McConnell 	 */
2535d043c564SKenneth D. Merry 	if (flags == MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG)
2536d043c564SKenneth D. Merry 		goto out;
2537d043c564SKenneth D. Merry 	else {
2538d043c564SKenneth D. Merry 		element = (Mpi2EventIrConfigElement_t *)&event_data->
2539d043c564SKenneth D. Merry 		    ConfigElement[0];
2540d043c564SKenneth D. Merry 		for (i = 0; i < event_data->NumElements; i++, element++) {
2541d043c564SKenneth D. Merry 			if (element->ReasonCode ==
2542d043c564SKenneth D. Merry 			    MPI2_EVENT_IR_CHANGE_RC_ADDED ||
2543d043c564SKenneth D. Merry 			    element->ReasonCode ==
2544d043c564SKenneth D. Merry 			    MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED) {
2545d043c564SKenneth D. Merry 				map_idx = _mapping_get_ir_mt_idx_from_wwid
2546d043c564SKenneth D. Merry 				    (sc, wwid_table[i]);
2547d043c564SKenneth D. Merry 				if (map_idx != MPS_MAPTABLE_BAD_IDX) {
2548635e58c7SStephen McConnell 					/*
2549635e58c7SStephen McConnell 					 * The volume is already in the mapping
2550635e58c7SStephen McConnell 					 * table. Just update it's info.
2551635e58c7SStephen McConnell 					 */
2552d043c564SKenneth D. Merry 					mt_entry = &sc->mapping_table[map_idx];
2553d043c564SKenneth D. Merry 					mt_entry->id = map_idx;
2554d043c564SKenneth D. Merry 					mt_entry->dev_handle = le16toh
2555d043c564SKenneth D. Merry 					    (element->VolDevHandle);
2556d043c564SKenneth D. Merry 					mt_entry->device_info =
2557d043c564SKenneth D. Merry 					    MPS_DEV_RESERVED | MPS_MAP_IN_USE;
2558d043c564SKenneth D. Merry 					_mapping_update_ir_missing_cnt(sc,
2559d043c564SKenneth D. Merry 					    map_idx, element, wwid_table[i]);
2560d043c564SKenneth D. Merry 					continue;
2561d043c564SKenneth D. Merry 				}
2562635e58c7SStephen McConnell 
2563635e58c7SStephen McConnell 				/*
2564635e58c7SStephen McConnell 				 * Volume is not in mapping table yet. Find a
2565635e58c7SStephen McConnell 				 * free entry in the mapping table at the
2566635e58c7SStephen McConnell 				 * volume mapping locations. If no entries are
2567635e58c7SStephen McConnell 				 * available, this is an error because it means
2568635e58c7SStephen McConnell 				 * there are more volumes than can be mapped
2569635e58c7SStephen McConnell 				 * and that should never happen for volumes.
2570635e58c7SStephen McConnell 				 */
2571d043c564SKenneth D. Merry 				map_idx = _mapping_get_free_ir_mt_idx(sc);
2572d043c564SKenneth D. Merry 				if (map_idx == MPS_MAPTABLE_BAD_IDX)
2573635e58c7SStephen McConnell 				{
2574635e58c7SStephen McConnell 					mps_dprint(sc, MPS_ERROR | MPS_MAPPING,
2575635e58c7SStephen McConnell 					    "%s: failed to add the volume with "
2576635e58c7SStephen McConnell 					    "handle 0x%04x because there is no "
2577635e58c7SStephen McConnell 					    "free space available in the "
2578635e58c7SStephen McConnell 					    "mapping table\n", __func__,
2579635e58c7SStephen McConnell 					    le16toh(element->VolDevHandle));
2580d043c564SKenneth D. Merry 					continue;
2581d043c564SKenneth D. Merry 				}
2582d043c564SKenneth D. Merry 				mt_entry = &sc->mapping_table[map_idx];
2583d043c564SKenneth D. Merry 				mt_entry->physical_id = wwid_table[i];
2584d043c564SKenneth D. Merry 				mt_entry->id = map_idx;
2585d043c564SKenneth D. Merry 				mt_entry->dev_handle = le16toh(element->
2586d043c564SKenneth D. Merry 				    VolDevHandle);
2587d043c564SKenneth D. Merry 				mt_entry->device_info = MPS_DEV_RESERVED |
2588d043c564SKenneth D. Merry 				    MPS_MAP_IN_USE;
2589d043c564SKenneth D. Merry 				_mapping_update_ir_missing_cnt(sc, map_idx,
2590d043c564SKenneth D. Merry 				    element, wwid_table[i]);
2591d043c564SKenneth D. Merry 			} else if (element->ReasonCode ==
2592d043c564SKenneth D. Merry 			    MPI2_EVENT_IR_CHANGE_RC_REMOVED) {
2593d043c564SKenneth D. Merry 				map_idx = _mapping_get_ir_mt_idx_from_wwid(sc,
2594d043c564SKenneth D. Merry 				    wwid_table[i]);
2595d043c564SKenneth D. Merry 				if (map_idx == MPS_MAPTABLE_BAD_IDX) {
2596635e58c7SStephen McConnell 					mps_dprint(sc, MPS_MAPPING,"%s: Failed "
2597635e58c7SStephen McConnell 					    "to remove a volume because it has "
2598635e58c7SStephen McConnell 					    "already been removed.\n",
2599635e58c7SStephen McConnell 					    __func__);
2600d043c564SKenneth D. Merry 					continue;
2601d043c564SKenneth D. Merry 				}
2602d043c564SKenneth D. Merry 				_mapping_update_ir_missing_cnt(sc, map_idx,
2603d043c564SKenneth D. Merry 				    element, wwid_table[i]);
2604d043c564SKenneth D. Merry 			} else if (element->ReasonCode ==
2605d043c564SKenneth D. Merry 			    MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED) {
2606d043c564SKenneth D. Merry 				map_idx = _mapping_get_mt_idx_from_handle(sc,
2607d043c564SKenneth D. Merry 				    le16toh(element->VolDevHandle));
2608d043c564SKenneth D. Merry 				if (map_idx == MPS_MAPTABLE_BAD_IDX) {
2609635e58c7SStephen McConnell 					mps_dprint(sc, MPS_MAPPING,"%s: Failed "
2610635e58c7SStephen McConnell 					    "to remove volume with handle "
2611635e58c7SStephen McConnell 					    "0x%04x because it has already "
2612635e58c7SStephen McConnell 					    "been removed.\n", __func__,
2613d043c564SKenneth D. Merry 					    le16toh(element->VolDevHandle));
2614d043c564SKenneth D. Merry 					continue;
2615d043c564SKenneth D. Merry 				}
2616d043c564SKenneth D. Merry 				mt_entry = &sc->mapping_table[map_idx];
2617d043c564SKenneth D. Merry 				_mapping_update_ir_missing_cnt(sc, map_idx,
2618d043c564SKenneth D. Merry 				    element, mt_entry->physical_id);
2619d043c564SKenneth D. Merry 			}
2620d043c564SKenneth D. Merry 		}
2621d043c564SKenneth D. Merry 	}
2622d043c564SKenneth D. Merry 
2623d043c564SKenneth D. Merry out:
2624d043c564SKenneth D. Merry 	_mapping_flush_dpm_pages(sc);
2625d043c564SKenneth D. Merry 	free(wwid_table, M_MPT2);
2626d043c564SKenneth D. Merry 	if (sc->pending_map_events)
2627d043c564SKenneth D. Merry 		sc->pending_map_events--;
2628d043c564SKenneth D. Merry }
2629ee5c196bSScott Long 
2630ee5c196bSScott Long int
2631ee5c196bSScott Long mps_mapping_dump(SYSCTL_HANDLER_ARGS)
2632ee5c196bSScott Long {
2633ee5c196bSScott Long 	struct mps_softc *sc;
2634ee5c196bSScott Long 	struct dev_mapping_table *mt_entry;
2635ee5c196bSScott Long 	struct sbuf sbuf;
2636ee5c196bSScott Long 	int i, error;
2637ee5c196bSScott Long 
2638ee5c196bSScott Long 	sc = (struct mps_softc *)arg1;
2639ee5c196bSScott Long 
2640ee5c196bSScott Long 	error = sysctl_wire_old_buffer(req, 0);
2641ee5c196bSScott Long 	if (error != 0)
2642ee5c196bSScott Long 		return (error);
2643ee5c196bSScott Long 	sbuf_new_for_sysctl(&sbuf, NULL, 128, req);
2644ee5c196bSScott Long 
2645ee5c196bSScott Long 	sbuf_printf(&sbuf, "\nindex physical_id       handle id\n");
2646ee5c196bSScott Long 	for (i = 0; i < sc->max_devices; i++) {
2647ee5c196bSScott Long 		mt_entry = &sc->mapping_table[i];
2648ee5c196bSScott Long 		if (mt_entry->physical_id == 0)
2649ee5c196bSScott Long 			continue;
2650ee5c196bSScott Long 		sbuf_printf(&sbuf, "%4d  %jx  %04x   %hd\n",
2651ee5c196bSScott Long 		    i, mt_entry->physical_id, mt_entry->dev_handle,
2652ee5c196bSScott Long 		    mt_entry->id);
2653ee5c196bSScott Long 	}
2654ee5c196bSScott Long 	error = sbuf_finish(&sbuf);
2655ee5c196bSScott Long 	sbuf_delete(&sbuf);
2656ee5c196bSScott Long 	return (error);
2657ee5c196bSScott Long }
2658ee5c196bSScott Long 
2659ee5c196bSScott Long int
2660ee5c196bSScott Long mps_mapping_encl_dump(SYSCTL_HANDLER_ARGS)
2661ee5c196bSScott Long {
2662ee5c196bSScott Long 	struct mps_softc *sc;
2663ee5c196bSScott Long 	struct enc_mapping_table *enc_entry;
2664ee5c196bSScott Long 	struct sbuf sbuf;
2665ee5c196bSScott Long 	int i, error;
2666ee5c196bSScott Long 
2667ee5c196bSScott Long 	sc = (struct mps_softc *)arg1;
2668ee5c196bSScott Long 
2669ee5c196bSScott Long 	error = sysctl_wire_old_buffer(req, 0);
2670ee5c196bSScott Long 	if (error != 0)
2671ee5c196bSScott Long 		return (error);
2672ee5c196bSScott Long 	sbuf_new_for_sysctl(&sbuf, NULL, 128, req);
2673ee5c196bSScott Long 
2674ee5c196bSScott Long 	sbuf_printf(&sbuf, "\nindex enclosure_id      handle map_index\n");
2675ee5c196bSScott Long 	for (i = 0; i < sc->max_enclosures; i++) {
2676ee5c196bSScott Long 		enc_entry = &sc->enclosure_table[i];
2677ee5c196bSScott Long 		if (enc_entry->enclosure_id == 0)
2678ee5c196bSScott Long 			continue;
2679ee5c196bSScott Long 		sbuf_printf(&sbuf, "%4d  %jx  %04x   %d\n",
2680ee5c196bSScott Long 		    i, enc_entry->enclosure_id, enc_entry->enc_handle,
2681ee5c196bSScott Long 		    enc_entry->start_index);
2682ee5c196bSScott Long 	}
2683ee5c196bSScott Long 	error = sbuf_finish(&sbuf);
2684ee5c196bSScott Long 	sbuf_delete(&sbuf);
2685ee5c196bSScott Long 	return (error);
2686ee5c196bSScott Long }
2687