xref: /freebsd/sys/dev/mpr/mpr_mapping.c (revision 67feec504576aacb04baaab0db77c475500c399e)
1991554f2SKenneth D. Merry /*-
2a2c14879SStephen McConnell  * Copyright (c) 2011-2015 LSI Corp.
37a2a6a1aSStephen McConnell  * Copyright (c) 2013-2016 Avago Technologies
4991554f2SKenneth D. Merry  * All rights reserved.
5991554f2SKenneth D. Merry  *
6991554f2SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
7991554f2SKenneth D. Merry  * modification, are permitted provided that the following conditions
8991554f2SKenneth D. Merry  * are met:
9991554f2SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright
10991554f2SKenneth D. Merry  *    notice, this list of conditions and the following disclaimer.
11991554f2SKenneth D. Merry  * 2. Redistributions in binary form must reproduce the above copyright
12991554f2SKenneth D. Merry  *    notice, this list of conditions and the following disclaimer in the
13991554f2SKenneth D. Merry  *    documentation and/or other materials provided with the distribution.
14991554f2SKenneth D. Merry  *
15991554f2SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16991554f2SKenneth D. Merry  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17991554f2SKenneth D. Merry  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18991554f2SKenneth D. Merry  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19991554f2SKenneth D. Merry  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20991554f2SKenneth D. Merry  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21991554f2SKenneth D. Merry  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22991554f2SKenneth D. Merry  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23991554f2SKenneth D. Merry  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24991554f2SKenneth D. Merry  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25991554f2SKenneth D. Merry  * SUCH DAMAGE.
26991554f2SKenneth D. Merry  *
27a2c14879SStephen McConnell  * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
28991554f2SKenneth D. Merry  */
29991554f2SKenneth D. Merry 
30991554f2SKenneth D. Merry #include <sys/cdefs.h>
31991554f2SKenneth D. Merry __FBSDID("$FreeBSD$");
32991554f2SKenneth D. Merry 
33991554f2SKenneth D. Merry /* TODO Move headers to mprvar */
34991554f2SKenneth D. Merry #include <sys/types.h>
35991554f2SKenneth D. Merry #include <sys/param.h>
36991554f2SKenneth D. Merry #include <sys/lock.h>
37991554f2SKenneth D. Merry #include <sys/mutex.h>
38991554f2SKenneth D. Merry #include <sys/systm.h>
39991554f2SKenneth D. Merry #include <sys/kernel.h>
40991554f2SKenneth D. Merry #include <sys/malloc.h>
41991554f2SKenneth D. Merry #include <sys/kthread.h>
42991554f2SKenneth D. Merry #include <sys/taskqueue.h>
43991554f2SKenneth D. Merry #include <sys/bus.h>
44991554f2SKenneth D. Merry #include <sys/endian.h>
45991554f2SKenneth D. Merry #include <sys/sysctl.h>
46991554f2SKenneth D. Merry #include <sys/eventhandler.h>
47991554f2SKenneth D. Merry #include <sys/uio.h>
48991554f2SKenneth D. Merry #include <machine/bus.h>
49991554f2SKenneth D. Merry #include <machine/resource.h>
50991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_type.h>
51991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2.h>
52991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_ioc.h>
53991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_sas.h>
54*67feec50SStephen McConnell #include <dev/mpr/mpi/mpi2_pci.h>
55991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_cnfg.h>
56991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_init.h>
57991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_tool.h>
58991554f2SKenneth D. Merry #include <dev/mpr/mpr_ioctl.h>
59991554f2SKenneth D. Merry #include <dev/mpr/mprvar.h>
60991554f2SKenneth D. Merry #include <dev/mpr/mpr_mapping.h>
61991554f2SKenneth D. Merry 
62991554f2SKenneth D. Merry /**
63991554f2SKenneth D. Merry  * _mapping_clear_entry - Clear a particular mapping entry.
64991554f2SKenneth D. Merry  * @map_entry: map table entry
65991554f2SKenneth D. Merry  *
66991554f2SKenneth D. Merry  * Returns nothing.
67991554f2SKenneth D. Merry  */
68991554f2SKenneth D. Merry static inline void
69991554f2SKenneth D. Merry _mapping_clear_map_entry(struct dev_mapping_table *map_entry)
70991554f2SKenneth D. Merry {
71991554f2SKenneth D. Merry 	map_entry->physical_id = 0;
72991554f2SKenneth D. Merry 	map_entry->device_info = 0;
73991554f2SKenneth D. Merry 	map_entry->phy_bits = 0;
74991554f2SKenneth D. Merry 	map_entry->dpm_entry_num = MPR_DPM_BAD_IDX;
75991554f2SKenneth D. Merry 	map_entry->dev_handle = 0;
76991554f2SKenneth D. Merry 	map_entry->channel = -1;
77991554f2SKenneth D. Merry 	map_entry->id = -1;
78991554f2SKenneth D. Merry 	map_entry->missing_count = 0;
79991554f2SKenneth D. Merry 	map_entry->init_complete = 0;
80991554f2SKenneth D. Merry 	map_entry->TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR;
81991554f2SKenneth D. Merry }
82991554f2SKenneth D. Merry 
83991554f2SKenneth D. Merry /**
84991554f2SKenneth D. Merry  * _mapping_clear_enc_entry - Clear a particular enclosure table entry.
85991554f2SKenneth D. Merry  * @enc_entry: enclosure table entry
86991554f2SKenneth D. Merry  *
87991554f2SKenneth D. Merry  * Returns nothing.
88991554f2SKenneth D. Merry  */
89991554f2SKenneth D. Merry static inline void
90991554f2SKenneth D. Merry _mapping_clear_enc_entry(struct enc_mapping_table *enc_entry)
91991554f2SKenneth D. Merry {
92991554f2SKenneth D. Merry 	enc_entry->enclosure_id = 0;
93991554f2SKenneth D. Merry 	enc_entry->start_index = MPR_MAPTABLE_BAD_IDX;
94991554f2SKenneth D. Merry 	enc_entry->phy_bits = 0;
95991554f2SKenneth D. Merry 	enc_entry->dpm_entry_num = MPR_DPM_BAD_IDX;
96991554f2SKenneth D. Merry 	enc_entry->enc_handle = 0;
97991554f2SKenneth D. Merry 	enc_entry->num_slots = 0;
98991554f2SKenneth D. Merry 	enc_entry->start_slot = 0;
99991554f2SKenneth D. Merry 	enc_entry->missing_count = 0;
100991554f2SKenneth D. Merry 	enc_entry->removal_flag = 0;
101991554f2SKenneth D. Merry 	enc_entry->skip_search = 0;
102991554f2SKenneth D. Merry 	enc_entry->init_complete = 0;
103991554f2SKenneth D. Merry }
104991554f2SKenneth D. Merry 
105991554f2SKenneth D. Merry /**
106991554f2SKenneth D. Merry  * _mapping_commit_enc_entry - write a particular enc entry in DPM page0.
107991554f2SKenneth D. Merry  * @sc: per adapter object
108991554f2SKenneth D. Merry  * @enc_entry: enclosure table entry
109991554f2SKenneth D. Merry  *
110991554f2SKenneth D. Merry  * Returns 0 for success, non-zero for failure.
111991554f2SKenneth D. Merry  */
112991554f2SKenneth D. Merry static int
113991554f2SKenneth D. Merry _mapping_commit_enc_entry(struct mpr_softc *sc,
114991554f2SKenneth D. Merry     struct enc_mapping_table *et_entry)
115991554f2SKenneth D. Merry {
116991554f2SKenneth D. Merry 	Mpi2DriverMap0Entry_t *dpm_entry;
117991554f2SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
118991554f2SKenneth D. Merry 	Mpi2ConfigReply_t mpi_reply;
119991554f2SKenneth D. Merry 	Mpi2DriverMappingPage0_t config_page;
120991554f2SKenneth D. Merry 
121991554f2SKenneth D. Merry 	if (!sc->is_dpm_enable)
122991554f2SKenneth D. Merry 		return 0;
123991554f2SKenneth D. Merry 
124991554f2SKenneth D. Merry 	memset(&config_page, 0, sizeof(Mpi2DriverMappingPage0_t));
125991554f2SKenneth D. Merry 	memcpy(&config_page.Header, (u8 *) sc->dpm_pg0,
126991554f2SKenneth D. Merry 	    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
127991554f2SKenneth D. Merry 	dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
128991554f2SKenneth D. Merry 	    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
129991554f2SKenneth D. Merry 	dpm_entry += et_entry->dpm_entry_num;
130991554f2SKenneth D. Merry 	dpm_entry->PhysicalIdentifier.Low =
131991554f2SKenneth D. Merry 	    ( 0xFFFFFFFF & et_entry->enclosure_id);
132991554f2SKenneth D. Merry 	dpm_entry->PhysicalIdentifier.High =
133991554f2SKenneth D. Merry 	    ( et_entry->enclosure_id >> 32);
134991554f2SKenneth D. Merry 	mt_entry = &sc->mapping_table[et_entry->start_index];
135991554f2SKenneth D. Merry 	dpm_entry->DeviceIndex = htole16(mt_entry->id);
136991554f2SKenneth D. Merry 	dpm_entry->MappingInformation = et_entry->num_slots;
137991554f2SKenneth D. Merry 	dpm_entry->MappingInformation <<= MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT;
138991554f2SKenneth D. Merry 	dpm_entry->MappingInformation |= et_entry->missing_count;
139991554f2SKenneth D. Merry 	dpm_entry->MappingInformation = htole16(dpm_entry->MappingInformation);
140991554f2SKenneth D. Merry 	dpm_entry->PhysicalBitsMapping = htole32(et_entry->phy_bits);
141991554f2SKenneth D. Merry 	dpm_entry->Reserved1 = 0;
142991554f2SKenneth D. Merry 
143991554f2SKenneth D. Merry 	memcpy(&config_page.Entry, (u8 *)dpm_entry,
144991554f2SKenneth D. Merry 	    sizeof(Mpi2DriverMap0Entry_t));
145991554f2SKenneth D. Merry 	if (mpr_config_set_dpm_pg0(sc, &mpi_reply, &config_page,
146991554f2SKenneth D. Merry 	    et_entry->dpm_entry_num)) {
147991554f2SKenneth D. Merry 		printf("%s: write of dpm entry %d for enclosure failed\n",
148991554f2SKenneth D. Merry 		    __func__, et_entry->dpm_entry_num);
149991554f2SKenneth D. Merry 		dpm_entry->MappingInformation = le16toh(dpm_entry->
150991554f2SKenneth D. Merry 		    MappingInformation);
151991554f2SKenneth D. Merry 		dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
152991554f2SKenneth D. Merry 		dpm_entry->PhysicalBitsMapping =
153991554f2SKenneth D. Merry 		    le32toh(dpm_entry->PhysicalBitsMapping);
154991554f2SKenneth D. Merry 		return -1;
155991554f2SKenneth D. Merry 	}
156991554f2SKenneth D. Merry 	dpm_entry->MappingInformation = le16toh(dpm_entry->
157991554f2SKenneth D. Merry 	    MappingInformation);
158991554f2SKenneth D. Merry 	dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
159991554f2SKenneth D. Merry 	dpm_entry->PhysicalBitsMapping =
160991554f2SKenneth D. Merry 	    le32toh(dpm_entry->PhysicalBitsMapping);
161991554f2SKenneth D. Merry 	return 0;
162991554f2SKenneth D. Merry }
163991554f2SKenneth D. Merry 
164991554f2SKenneth D. Merry /**
165991554f2SKenneth D. Merry  * _mapping_commit_map_entry - write a particular map table entry in DPM page0.
166991554f2SKenneth D. Merry  * @sc: per adapter object
167991554f2SKenneth D. Merry  * @enc_entry: enclosure table entry
168991554f2SKenneth D. Merry  *
169991554f2SKenneth D. Merry  * Returns 0 for success, non-zero for failure.
170991554f2SKenneth D. Merry  */
171991554f2SKenneth D. Merry 
172991554f2SKenneth D. Merry static int
173991554f2SKenneth D. Merry _mapping_commit_map_entry(struct mpr_softc *sc,
174991554f2SKenneth D. Merry     struct dev_mapping_table *mt_entry)
175991554f2SKenneth D. Merry {
176991554f2SKenneth D. Merry 	Mpi2DriverMap0Entry_t *dpm_entry;
177991554f2SKenneth D. Merry 	Mpi2ConfigReply_t mpi_reply;
178991554f2SKenneth D. Merry 	Mpi2DriverMappingPage0_t config_page;
179991554f2SKenneth D. Merry 
180991554f2SKenneth D. Merry 	if (!sc->is_dpm_enable)
181991554f2SKenneth D. Merry 		return 0;
182991554f2SKenneth D. Merry 
183991554f2SKenneth D. Merry 	memset(&config_page, 0, sizeof(Mpi2DriverMappingPage0_t));
184991554f2SKenneth D. Merry 	memcpy(&config_page.Header, (u8 *)sc->dpm_pg0,
185991554f2SKenneth D. Merry 	    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
186991554f2SKenneth D. Merry 	dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *) sc->dpm_pg0 +
187991554f2SKenneth D. Merry 	    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
188991554f2SKenneth D. Merry 	dpm_entry = dpm_entry + mt_entry->dpm_entry_num;
189991554f2SKenneth D. Merry 	dpm_entry->PhysicalIdentifier.Low = (0xFFFFFFFF &
190991554f2SKenneth D. Merry 	    mt_entry->physical_id);
191991554f2SKenneth D. Merry 	dpm_entry->PhysicalIdentifier.High = (mt_entry->physical_id >> 32);
192991554f2SKenneth D. Merry 	dpm_entry->DeviceIndex = htole16(mt_entry->id);
193991554f2SKenneth D. Merry 	dpm_entry->MappingInformation = htole16(mt_entry->missing_count);
194991554f2SKenneth D. Merry 	dpm_entry->PhysicalBitsMapping = 0;
195991554f2SKenneth D. Merry 	dpm_entry->Reserved1 = 0;
196991554f2SKenneth D. Merry 	dpm_entry->MappingInformation = htole16(dpm_entry->MappingInformation);
197991554f2SKenneth D. Merry 	memcpy(&config_page.Entry, (u8 *)dpm_entry,
198991554f2SKenneth D. Merry 	    sizeof(Mpi2DriverMap0Entry_t));
199991554f2SKenneth D. Merry 	if (mpr_config_set_dpm_pg0(sc, &mpi_reply, &config_page,
200991554f2SKenneth D. Merry 	    mt_entry->dpm_entry_num)) {
201991554f2SKenneth D. Merry 		printf("%s: write of dpm entry %d for device failed\n",
202991554f2SKenneth D. Merry 		    __func__, mt_entry->dpm_entry_num);
203991554f2SKenneth D. Merry 		dpm_entry->MappingInformation = le16toh(dpm_entry->
204991554f2SKenneth D. Merry 		    MappingInformation);
205991554f2SKenneth D. Merry 		dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
206991554f2SKenneth D. Merry 		return -1;
207991554f2SKenneth D. Merry 	}
208991554f2SKenneth D. Merry 
209991554f2SKenneth D. Merry 	dpm_entry->MappingInformation = le16toh(dpm_entry->MappingInformation);
210991554f2SKenneth D. Merry 	dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
211991554f2SKenneth D. Merry 	return 0;
212991554f2SKenneth D. Merry }
213991554f2SKenneth D. Merry 
214991554f2SKenneth D. Merry /**
215991554f2SKenneth D. Merry  * _mapping_get_ir_maprange - get start and end index for IR map range.
216991554f2SKenneth D. Merry  * @sc: per adapter object
217991554f2SKenneth D. Merry  * @start_idx: place holder for start index
218991554f2SKenneth D. Merry  * @end_idx: place holder for end index
219991554f2SKenneth D. Merry  *
220991554f2SKenneth D. Merry  * The IR volumes can be mapped either at start or end of the mapping table
221991554f2SKenneth D. Merry  * this function gets the detail of where IR volume mapping starts and ends
222991554f2SKenneth D. Merry  * in the device mapping table
223991554f2SKenneth D. Merry  *
224991554f2SKenneth D. Merry  * Returns nothing.
225991554f2SKenneth D. Merry  */
226991554f2SKenneth D. Merry static void
227991554f2SKenneth D. Merry _mapping_get_ir_maprange(struct mpr_softc *sc, u32 *start_idx, u32 *end_idx)
228991554f2SKenneth D. Merry {
229991554f2SKenneth D. Merry 	u16 volume_mapping_flags;
230991554f2SKenneth D. Merry 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
231991554f2SKenneth D. Merry 
232991554f2SKenneth D. Merry 	volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) &
233991554f2SKenneth D. Merry 	    MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
234991554f2SKenneth D. Merry 	if (volume_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) {
235991554f2SKenneth D. Merry 		*start_idx = 0;
236991554f2SKenneth D. Merry 		if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0)
237991554f2SKenneth D. Merry 			*start_idx = 1;
238991554f2SKenneth D. Merry 	} else
239991554f2SKenneth D. Merry 		*start_idx = sc->max_devices - sc->max_volumes;
240991554f2SKenneth D. Merry 	*end_idx = *start_idx + sc->max_volumes - 1;
241991554f2SKenneth D. Merry }
242991554f2SKenneth D. Merry 
243991554f2SKenneth D. Merry /**
244991554f2SKenneth D. Merry  * _mapping_get_enc_idx_from_id - get enclosure index from enclosure ID
245991554f2SKenneth D. Merry  * @sc: per adapter object
246991554f2SKenneth D. Merry  * @enc_id: enclosure logical identifier
247991554f2SKenneth D. Merry  *
248991554f2SKenneth D. Merry  * Returns the index of enclosure entry on success or bad index.
249991554f2SKenneth D. Merry  */
250991554f2SKenneth D. Merry static u8
251991554f2SKenneth D. Merry _mapping_get_enc_idx_from_id(struct mpr_softc *sc, u64 enc_id,
252991554f2SKenneth D. Merry     u64 phy_bits)
253991554f2SKenneth D. Merry {
254991554f2SKenneth D. Merry 	struct enc_mapping_table *et_entry;
255991554f2SKenneth D. Merry 	u8 enc_idx = 0;
256991554f2SKenneth D. Merry 
257991554f2SKenneth D. Merry 	for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; enc_idx++) {
258991554f2SKenneth D. Merry 		et_entry = &sc->enclosure_table[enc_idx];
259991554f2SKenneth D. Merry 		if ((et_entry->enclosure_id == le64toh(enc_id)) &&
260991554f2SKenneth D. Merry 		    (!et_entry->phy_bits || (et_entry->phy_bits &
261991554f2SKenneth D. Merry 		    le32toh(phy_bits))))
262991554f2SKenneth D. Merry 			return enc_idx;
263991554f2SKenneth D. Merry 	}
264991554f2SKenneth D. Merry 	return MPR_ENCTABLE_BAD_IDX;
265991554f2SKenneth D. Merry }
266991554f2SKenneth D. Merry 
267991554f2SKenneth D. Merry /**
268991554f2SKenneth D. Merry  * _mapping_get_enc_idx_from_handle - get enclosure index from handle
269991554f2SKenneth D. Merry  * @sc: per adapter object
270991554f2SKenneth D. Merry  * @enc_id: enclosure handle
271991554f2SKenneth D. Merry  *
272991554f2SKenneth D. Merry  * Returns the index of enclosure entry on success or bad index.
273991554f2SKenneth D. Merry  */
274991554f2SKenneth D. Merry static u8
275991554f2SKenneth D. Merry _mapping_get_enc_idx_from_handle(struct mpr_softc *sc, u16 handle)
276991554f2SKenneth D. Merry {
277991554f2SKenneth D. Merry 	struct enc_mapping_table *et_entry;
278991554f2SKenneth D. Merry 	u8 enc_idx = 0;
279991554f2SKenneth D. Merry 
280991554f2SKenneth D. Merry 	for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; enc_idx++) {
281991554f2SKenneth D. Merry 		et_entry = &sc->enclosure_table[enc_idx];
282991554f2SKenneth D. Merry 		if (et_entry->missing_count)
283991554f2SKenneth D. Merry 			continue;
284991554f2SKenneth D. Merry 		if (et_entry->enc_handle == handle)
285991554f2SKenneth D. Merry 			return enc_idx;
286991554f2SKenneth D. Merry 	}
287991554f2SKenneth D. Merry 	return MPR_ENCTABLE_BAD_IDX;
288991554f2SKenneth D. Merry }
289991554f2SKenneth D. Merry 
290991554f2SKenneth D. Merry /**
291991554f2SKenneth D. Merry  * _mapping_get_high_missing_et_idx - get missing enclosure index
292991554f2SKenneth D. Merry  * @sc: per adapter object
293991554f2SKenneth D. Merry  *
294991554f2SKenneth D. Merry  * Search through the enclosure table and identifies the enclosure entry
295991554f2SKenneth D. Merry  * with high missing count and returns it's index
296991554f2SKenneth D. Merry  *
297991554f2SKenneth D. Merry  * Returns the index of enclosure entry on success or bad index.
298991554f2SKenneth D. Merry  */
299991554f2SKenneth D. Merry static u8
300991554f2SKenneth D. Merry _mapping_get_high_missing_et_idx(struct mpr_softc *sc)
301991554f2SKenneth D. Merry {
302991554f2SKenneth D. Merry 	struct enc_mapping_table *et_entry;
303991554f2SKenneth D. Merry 	u8 high_missing_count = 0;
304991554f2SKenneth D. Merry 	u8 enc_idx, high_idx = MPR_ENCTABLE_BAD_IDX;
305991554f2SKenneth D. Merry 
306991554f2SKenneth D. Merry 	for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; enc_idx++) {
307991554f2SKenneth D. Merry 		et_entry = &sc->enclosure_table[enc_idx];
308991554f2SKenneth D. Merry 		if ((et_entry->missing_count > high_missing_count) &&
309991554f2SKenneth D. Merry 		    !et_entry->skip_search) {
310991554f2SKenneth D. Merry 			high_missing_count =  et_entry->missing_count;
311991554f2SKenneth D. Merry 			high_idx = enc_idx;
312991554f2SKenneth D. Merry 		}
313991554f2SKenneth D. Merry 	}
314991554f2SKenneth D. Merry 	return high_idx;
315991554f2SKenneth D. Merry }
316991554f2SKenneth D. Merry 
317991554f2SKenneth D. Merry /**
318991554f2SKenneth D. Merry  * _mapping_get_high_missing_mt_idx - get missing map table index
319991554f2SKenneth D. Merry  * @sc: per adapter object
320991554f2SKenneth D. Merry  *
321991554f2SKenneth D. Merry  * Search through the map table and identifies the device entry
322991554f2SKenneth D. Merry  * with high missing count and returns it's index
323991554f2SKenneth D. Merry  *
324991554f2SKenneth D. Merry  * Returns the index of map table entry on success or bad index.
325991554f2SKenneth D. Merry  */
326991554f2SKenneth D. Merry static u32
327991554f2SKenneth D. Merry _mapping_get_high_missing_mt_idx(struct mpr_softc *sc)
328991554f2SKenneth D. Merry {
329991554f2SKenneth D. Merry 	u32 map_idx, high_idx = MPR_ENCTABLE_BAD_IDX;
330991554f2SKenneth D. Merry 	u8 high_missing_count = 0;
331a2c14879SStephen McConnell 	u32 start_idx, end_idx, start_idx_ir, end_idx_ir;
332991554f2SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
333991554f2SKenneth D. Merry 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
334991554f2SKenneth D. Merry 
335991554f2SKenneth D. Merry 	start_idx = 0;
336a2c14879SStephen McConnell 	start_idx_ir = 0;
337a2c14879SStephen McConnell 	end_idx_ir = 0;
338991554f2SKenneth D. Merry 	end_idx = sc->max_devices;
339991554f2SKenneth D. Merry 	if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0)
340991554f2SKenneth D. Merry 		start_idx = 1;
341991554f2SKenneth D. Merry 	if (sc->ir_firmware) {
342991554f2SKenneth D. Merry 		_mapping_get_ir_maprange(sc, &start_idx_ir, &end_idx_ir);
343991554f2SKenneth D. Merry 		if (start_idx == start_idx_ir)
344991554f2SKenneth D. Merry 			start_idx = end_idx_ir + 1;
345991554f2SKenneth D. Merry 		else
346991554f2SKenneth D. Merry 			end_idx = start_idx_ir;
347991554f2SKenneth D. Merry 	}
348991554f2SKenneth D. Merry 	mt_entry = &sc->mapping_table[start_idx];
349991554f2SKenneth D. Merry 	for (map_idx = start_idx; map_idx < end_idx; map_idx++, mt_entry++) {
350991554f2SKenneth D. Merry 		if (mt_entry->missing_count > high_missing_count) {
351991554f2SKenneth D. Merry 			high_missing_count =  mt_entry->missing_count;
352991554f2SKenneth D. Merry 			high_idx = map_idx;
353991554f2SKenneth D. Merry 		}
354991554f2SKenneth D. Merry 	}
355991554f2SKenneth D. Merry 	return high_idx;
356991554f2SKenneth D. Merry }
357991554f2SKenneth D. Merry 
358991554f2SKenneth D. Merry /**
359991554f2SKenneth D. Merry  * _mapping_get_ir_mt_idx_from_wwid - get map table index from volume WWID
360991554f2SKenneth D. Merry  * @sc: per adapter object
361991554f2SKenneth D. Merry  * @wwid: world wide unique ID of the volume
362991554f2SKenneth D. Merry  *
363991554f2SKenneth D. Merry  * Returns the index of map table entry on success or bad index.
364991554f2SKenneth D. Merry  */
365991554f2SKenneth D. Merry static u32
366991554f2SKenneth D. Merry _mapping_get_ir_mt_idx_from_wwid(struct mpr_softc *sc, u64 wwid)
367991554f2SKenneth D. Merry {
368991554f2SKenneth D. Merry 	u32 start_idx, end_idx, map_idx;
369991554f2SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
370991554f2SKenneth D. Merry 
371991554f2SKenneth D. Merry 	_mapping_get_ir_maprange(sc, &start_idx, &end_idx);
372991554f2SKenneth D. Merry 	mt_entry = &sc->mapping_table[start_idx];
373991554f2SKenneth D. Merry 	for (map_idx  = start_idx; map_idx <= end_idx; map_idx++, mt_entry++)
374991554f2SKenneth D. Merry 		if (mt_entry->physical_id == wwid)
375991554f2SKenneth D. Merry 			return map_idx;
376991554f2SKenneth D. Merry 
377991554f2SKenneth D. Merry 	return MPR_MAPTABLE_BAD_IDX;
378991554f2SKenneth D. Merry }
379991554f2SKenneth D. Merry 
380991554f2SKenneth D. Merry /**
381991554f2SKenneth D. Merry  * _mapping_get_mt_idx_from_id - get map table index from a device ID
382991554f2SKenneth D. Merry  * @sc: per adapter object
383991554f2SKenneth D. Merry  * @dev_id: device identifer (SAS Address)
384991554f2SKenneth D. Merry  *
385991554f2SKenneth D. Merry  * Returns the index of map table entry on success or bad index.
386991554f2SKenneth D. Merry  */
387991554f2SKenneth D. Merry static u32
388991554f2SKenneth D. Merry _mapping_get_mt_idx_from_id(struct mpr_softc *sc, u64 dev_id)
389991554f2SKenneth D. Merry {
390991554f2SKenneth D. Merry 	u32 map_idx;
391991554f2SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
392991554f2SKenneth D. Merry 
393991554f2SKenneth D. Merry 	for (map_idx = 0; map_idx < sc->max_devices; map_idx++) {
394991554f2SKenneth D. Merry 		mt_entry = &sc->mapping_table[map_idx];
395991554f2SKenneth D. Merry 		if (mt_entry->physical_id == dev_id)
396991554f2SKenneth D. Merry 			return map_idx;
397991554f2SKenneth D. Merry 	}
398991554f2SKenneth D. Merry 	return MPR_MAPTABLE_BAD_IDX;
399991554f2SKenneth D. Merry }
400991554f2SKenneth D. Merry 
401991554f2SKenneth D. Merry /**
402991554f2SKenneth D. Merry  * _mapping_get_ir_mt_idx_from_handle - get map table index from volume handle
403991554f2SKenneth D. Merry  * @sc: per adapter object
404991554f2SKenneth D. Merry  * @wwid: volume device handle
405991554f2SKenneth D. Merry  *
406991554f2SKenneth D. Merry  * Returns the index of map table entry on success or bad index.
407991554f2SKenneth D. Merry  */
408991554f2SKenneth D. Merry static u32
409991554f2SKenneth D. Merry _mapping_get_ir_mt_idx_from_handle(struct mpr_softc *sc, u16 volHandle)
410991554f2SKenneth D. Merry {
411991554f2SKenneth D. Merry 	u32 start_idx, end_idx, map_idx;
412991554f2SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
413991554f2SKenneth D. Merry 
414991554f2SKenneth D. Merry 	_mapping_get_ir_maprange(sc, &start_idx, &end_idx);
415991554f2SKenneth D. Merry 	mt_entry = &sc->mapping_table[start_idx];
416991554f2SKenneth D. Merry 	for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++)
417991554f2SKenneth D. Merry 		if (mt_entry->dev_handle == volHandle)
418991554f2SKenneth D. Merry 			return map_idx;
419991554f2SKenneth D. Merry 
420991554f2SKenneth D. Merry 	return MPR_MAPTABLE_BAD_IDX;
421991554f2SKenneth D. Merry }
422991554f2SKenneth D. Merry 
423991554f2SKenneth D. Merry /**
424991554f2SKenneth D. Merry  * _mapping_get_mt_idx_from_handle - get map table index from handle
425991554f2SKenneth D. Merry  * @sc: per adapter object
426991554f2SKenneth D. Merry  * @dev_id: device handle
427991554f2SKenneth D. Merry  *
428991554f2SKenneth D. Merry  * Returns the index of map table entry on success or bad index.
429991554f2SKenneth D. Merry  */
430991554f2SKenneth D. Merry static u32
431991554f2SKenneth D. Merry _mapping_get_mt_idx_from_handle(struct mpr_softc *sc, u16 handle)
432991554f2SKenneth D. Merry {
433991554f2SKenneth D. Merry 	u32 map_idx;
434991554f2SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
435991554f2SKenneth D. Merry 
436991554f2SKenneth D. Merry 	for (map_idx = 0; map_idx < sc->max_devices; map_idx++) {
437991554f2SKenneth D. Merry 		mt_entry = &sc->mapping_table[map_idx];
438991554f2SKenneth D. Merry 		if (mt_entry->dev_handle == handle)
439991554f2SKenneth D. Merry 			return map_idx;
440991554f2SKenneth D. Merry 	}
441991554f2SKenneth D. Merry 	return MPR_MAPTABLE_BAD_IDX;
442991554f2SKenneth D. Merry }
443991554f2SKenneth D. Merry 
444991554f2SKenneth D. Merry /**
445991554f2SKenneth D. Merry  * _mapping_get_free_ir_mt_idx - get first free index for a volume
446991554f2SKenneth D. Merry  * @sc: per adapter object
447991554f2SKenneth D. Merry  *
448991554f2SKenneth D. Merry  * Search through mapping table for free index for a volume and if no free
449991554f2SKenneth D. Merry  * index then looks for a volume with high mapping index
450991554f2SKenneth D. Merry  *
451991554f2SKenneth D. Merry  * Returns the index of map table entry on success or bad index.
452991554f2SKenneth D. Merry  */
453991554f2SKenneth D. Merry static u32
454991554f2SKenneth D. Merry _mapping_get_free_ir_mt_idx(struct mpr_softc *sc)
455991554f2SKenneth D. Merry {
456991554f2SKenneth D. Merry 	u8 high_missing_count = 0;
457991554f2SKenneth D. Merry 	u32 start_idx, end_idx, map_idx;
458991554f2SKenneth D. Merry 	u32 high_idx = MPR_MAPTABLE_BAD_IDX;
459991554f2SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
460991554f2SKenneth D. Merry 
461991554f2SKenneth D. Merry 	_mapping_get_ir_maprange(sc, &start_idx, &end_idx);
462991554f2SKenneth D. Merry 
463991554f2SKenneth D. Merry 	mt_entry = &sc->mapping_table[start_idx];
464991554f2SKenneth D. Merry 	for (map_idx  = start_idx; map_idx <= end_idx; map_idx++, mt_entry++)
465991554f2SKenneth D. Merry 		if (!(mt_entry->device_info & MPR_MAP_IN_USE))
466991554f2SKenneth D. Merry 			return map_idx;
467991554f2SKenneth D. Merry 
468991554f2SKenneth D. Merry 	mt_entry = &sc->mapping_table[start_idx];
469991554f2SKenneth D. Merry 	for (map_idx  = start_idx; map_idx <= end_idx; map_idx++, mt_entry++) {
470991554f2SKenneth D. Merry 		if (mt_entry->missing_count > high_missing_count) {
471991554f2SKenneth D. Merry 			high_missing_count = mt_entry->missing_count;
472991554f2SKenneth D. Merry 			high_idx = map_idx;
473991554f2SKenneth D. Merry 		}
474991554f2SKenneth D. Merry 	}
475991554f2SKenneth D. Merry 	return high_idx;
476991554f2SKenneth D. Merry }
477991554f2SKenneth D. Merry 
478991554f2SKenneth D. Merry /**
479991554f2SKenneth D. Merry  * _mapping_get_free_mt_idx - get first free index for a device
480991554f2SKenneth D. Merry  * @sc: per adapter object
481991554f2SKenneth D. Merry  * @start_idx: offset in the table to start search
482991554f2SKenneth D. Merry  *
483991554f2SKenneth D. Merry  * Returns the index of map table entry on success or bad index.
484991554f2SKenneth D. Merry  */
485991554f2SKenneth D. Merry static u32
486991554f2SKenneth D. Merry _mapping_get_free_mt_idx(struct mpr_softc *sc, u32 start_idx)
487991554f2SKenneth D. Merry {
488991554f2SKenneth D. Merry 	u32 map_idx, max_idx = sc->max_devices;
489991554f2SKenneth D. Merry 	struct dev_mapping_table *mt_entry = &sc->mapping_table[start_idx];
490991554f2SKenneth D. Merry 	u16 volume_mapping_flags;
491991554f2SKenneth D. Merry 
492991554f2SKenneth D. Merry 	volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) &
493991554f2SKenneth D. Merry 	    MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
494991554f2SKenneth D. Merry 	if (sc->ir_firmware && (volume_mapping_flags ==
495991554f2SKenneth D. Merry 	    MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING))
496991554f2SKenneth D. Merry 		max_idx -= sc->max_volumes;
497991554f2SKenneth D. Merry 	for (map_idx  = start_idx; map_idx < max_idx; map_idx++, mt_entry++)
498991554f2SKenneth D. Merry 		if (!(mt_entry->device_info & (MPR_MAP_IN_USE |
499991554f2SKenneth D. Merry 		    MPR_DEV_RESERVED)))
500991554f2SKenneth D. Merry 			return map_idx;
501991554f2SKenneth D. Merry 
502991554f2SKenneth D. Merry 	return MPR_MAPTABLE_BAD_IDX;
503991554f2SKenneth D. Merry }
504991554f2SKenneth D. Merry 
505991554f2SKenneth D. Merry /**
506991554f2SKenneth D. Merry  * _mapping_get_dpm_idx_from_id - get DPM index from ID
507991554f2SKenneth D. Merry  * @sc: per adapter object
508991554f2SKenneth D. Merry  * @id: volume WWID or enclosure ID or device ID
509991554f2SKenneth D. Merry  *
510991554f2SKenneth D. Merry  * Returns the index of DPM entry on success or bad index.
511991554f2SKenneth D. Merry  */
512991554f2SKenneth D. Merry static u16
513991554f2SKenneth D. Merry _mapping_get_dpm_idx_from_id(struct mpr_softc *sc, u64 id, u32 phy_bits)
514991554f2SKenneth D. Merry {
515991554f2SKenneth D. Merry 	u16 entry_num;
516991554f2SKenneth D. Merry 	uint64_t PhysicalIdentifier;
517991554f2SKenneth D. Merry 	Mpi2DriverMap0Entry_t *dpm_entry;
518991554f2SKenneth D. Merry 
519991554f2SKenneth D. Merry 	dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
520991554f2SKenneth D. Merry 	    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
521991554f2SKenneth D. Merry 	PhysicalIdentifier = dpm_entry->PhysicalIdentifier.High;
522991554f2SKenneth D. Merry 	PhysicalIdentifier = (PhysicalIdentifier << 32) |
523991554f2SKenneth D. Merry 	    dpm_entry->PhysicalIdentifier.Low;
524991554f2SKenneth D. Merry 	for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++,
525991554f2SKenneth D. Merry 	    dpm_entry++)
526991554f2SKenneth D. Merry 		if ((id == PhysicalIdentifier) &&
527991554f2SKenneth D. Merry 		    (!phy_bits || !dpm_entry->PhysicalBitsMapping ||
528991554f2SKenneth D. Merry 		    (phy_bits & dpm_entry->PhysicalBitsMapping)))
529991554f2SKenneth D. Merry 			return entry_num;
530991554f2SKenneth D. Merry 
531991554f2SKenneth D. Merry 	return MPR_DPM_BAD_IDX;
532991554f2SKenneth D. Merry }
533991554f2SKenneth D. Merry 
534991554f2SKenneth D. Merry 
535991554f2SKenneth D. Merry /**
536991554f2SKenneth D. Merry  * _mapping_get_free_dpm_idx - get first available DPM index
537991554f2SKenneth D. Merry  * @sc: per adapter object
538991554f2SKenneth D. Merry  *
539991554f2SKenneth D. Merry  * Returns the index of DPM entry on success or bad index.
540991554f2SKenneth D. Merry  */
541991554f2SKenneth D. Merry static u32
542991554f2SKenneth D. Merry _mapping_get_free_dpm_idx(struct mpr_softc *sc)
543991554f2SKenneth D. Merry {
544991554f2SKenneth D. Merry 	u16 entry_num;
545991554f2SKenneth D. Merry 
546991554f2SKenneth D. Merry 	for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++) {
547991554f2SKenneth D. Merry 		if (!sc->dpm_entry_used[entry_num])
548991554f2SKenneth D. Merry 			return entry_num;
549991554f2SKenneth D. Merry 	}
550991554f2SKenneth D. Merry 	return MPR_DPM_BAD_IDX;
551991554f2SKenneth D. Merry }
552991554f2SKenneth D. Merry 
553991554f2SKenneth D. Merry /**
554991554f2SKenneth D. Merry  * _mapping_update_ir_missing_cnt - Updates missing count for a volume
555991554f2SKenneth D. Merry  * @sc: per adapter object
556991554f2SKenneth D. Merry  * @map_idx: map table index of the volume
557991554f2SKenneth D. Merry  * @element: IR configuration change element
558991554f2SKenneth D. Merry  * @wwid: IR volume ID.
559991554f2SKenneth D. Merry  *
560991554f2SKenneth D. Merry  * Updates the missing count in the map table and in the DPM entry for a volume
561991554f2SKenneth D. Merry  *
562991554f2SKenneth D. Merry  * Returns nothing.
563991554f2SKenneth D. Merry  */
564991554f2SKenneth D. Merry static void
565991554f2SKenneth D. Merry _mapping_update_ir_missing_cnt(struct mpr_softc *sc, u32 map_idx,
566991554f2SKenneth D. Merry     Mpi2EventIrConfigElement_t *element, u64 wwid)
567991554f2SKenneth D. Merry {
568991554f2SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
569991554f2SKenneth D. Merry 	u8 missing_cnt, reason = element->ReasonCode;
570991554f2SKenneth D. Merry 	u16 dpm_idx;
571991554f2SKenneth D. Merry 	Mpi2DriverMap0Entry_t *dpm_entry;
572991554f2SKenneth D. Merry 
573991554f2SKenneth D. Merry 	if (!sc->is_dpm_enable)
574991554f2SKenneth D. Merry 		return;
575991554f2SKenneth D. Merry 	mt_entry = &sc->mapping_table[map_idx];
576991554f2SKenneth D. Merry 	if (reason == MPI2_EVENT_IR_CHANGE_RC_ADDED) {
577991554f2SKenneth D. Merry 		mt_entry->missing_count = 0;
578991554f2SKenneth D. Merry 	} else if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED) {
579991554f2SKenneth D. Merry 		mt_entry->missing_count = 0;
580991554f2SKenneth D. Merry 		mt_entry->init_complete = 0;
581991554f2SKenneth D. Merry 	} else if ((reason == MPI2_EVENT_IR_CHANGE_RC_REMOVED) ||
582991554f2SKenneth D. Merry 	    (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED)) {
583991554f2SKenneth D. Merry 		if (!mt_entry->init_complete) {
584991554f2SKenneth D. Merry 			if (mt_entry->missing_count < MPR_MAX_MISSING_COUNT)
585991554f2SKenneth D. Merry 				mt_entry->missing_count++;
586991554f2SKenneth D. Merry 			else
587991554f2SKenneth D. Merry 				mt_entry->init_complete = 1;
588991554f2SKenneth D. Merry 		}
589991554f2SKenneth D. Merry 		if (!mt_entry->missing_count)
590991554f2SKenneth D. Merry 			mt_entry->missing_count++;
591991554f2SKenneth D. Merry 		mt_entry->dev_handle = 0;
592991554f2SKenneth D. Merry 	}
593991554f2SKenneth D. Merry 
594991554f2SKenneth D. Merry 	dpm_idx = mt_entry->dpm_entry_num;
595991554f2SKenneth D. Merry 	if (dpm_idx == MPR_DPM_BAD_IDX) {
596991554f2SKenneth D. Merry 		if ((reason == MPI2_EVENT_IR_CHANGE_RC_ADDED) ||
597991554f2SKenneth D. Merry 		    (reason == MPI2_EVENT_IR_CHANGE_RC_REMOVED))
598991554f2SKenneth D. Merry 			dpm_idx = _mapping_get_dpm_idx_from_id(sc,
599991554f2SKenneth D. Merry 			    mt_entry->physical_id, 0);
600991554f2SKenneth D. Merry 		else if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED)
601991554f2SKenneth D. Merry 			return;
602991554f2SKenneth D. Merry 	}
603991554f2SKenneth D. Merry 	if (dpm_idx != MPR_DPM_BAD_IDX) {
604991554f2SKenneth D. Merry 		dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
605991554f2SKenneth D. Merry 		    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
606991554f2SKenneth D. Merry 		dpm_entry += dpm_idx;
607991554f2SKenneth D. Merry 		missing_cnt = dpm_entry->MappingInformation &
608991554f2SKenneth D. Merry 		    MPI2_DRVMAP0_MAPINFO_MISSING_MASK;
609991554f2SKenneth D. Merry 		if ((mt_entry->physical_id ==
610991554f2SKenneth D. Merry 		    le64toh((u64)dpm_entry->PhysicalIdentifier.High |
611991554f2SKenneth D. Merry 		    dpm_entry->PhysicalIdentifier.Low)) && (missing_cnt ==
612991554f2SKenneth D. Merry 		    mt_entry->missing_count))
613991554f2SKenneth D. Merry 			mt_entry->init_complete = 1;
614991554f2SKenneth D. Merry 	} else {
615991554f2SKenneth D. Merry 		dpm_idx = _mapping_get_free_dpm_idx(sc);
616991554f2SKenneth D. Merry 		mt_entry->init_complete = 0;
617991554f2SKenneth D. Merry 	}
618991554f2SKenneth D. Merry 
619991554f2SKenneth D. Merry 	if ((dpm_idx != MPR_DPM_BAD_IDX) && !mt_entry->init_complete) {
620991554f2SKenneth D. Merry 		mt_entry->init_complete = 1;
621991554f2SKenneth D. Merry 		mt_entry->dpm_entry_num = dpm_idx;
622991554f2SKenneth D. Merry 		dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
623991554f2SKenneth D. Merry 		    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
624991554f2SKenneth D. Merry 		dpm_entry += dpm_idx;
625991554f2SKenneth D. Merry 		dpm_entry->PhysicalIdentifier.Low =
626991554f2SKenneth D. Merry 		    (0xFFFFFFFF & mt_entry->physical_id);
627991554f2SKenneth D. Merry 		dpm_entry->PhysicalIdentifier.High =
628991554f2SKenneth D. Merry 		    (mt_entry->physical_id >> 32);
629991554f2SKenneth D. Merry 		dpm_entry->DeviceIndex = map_idx;
630991554f2SKenneth D. Merry 		dpm_entry->MappingInformation = mt_entry->missing_count;
631991554f2SKenneth D. Merry 		dpm_entry->PhysicalBitsMapping = 0;
632991554f2SKenneth D. Merry 		dpm_entry->Reserved1 = 0;
633991554f2SKenneth D. Merry 		sc->dpm_flush_entry[dpm_idx] = 1;
634991554f2SKenneth D. Merry 		sc->dpm_entry_used[dpm_idx] = 1;
635991554f2SKenneth D. Merry 	} else if (dpm_idx == MPR_DPM_BAD_IDX) {
636991554f2SKenneth D. Merry 		printf("%s: no space to add entry in DPM table\n", __func__);
637991554f2SKenneth D. Merry 		mt_entry->init_complete = 1;
638991554f2SKenneth D. Merry 	}
639991554f2SKenneth D. Merry }
640991554f2SKenneth D. Merry 
641991554f2SKenneth D. Merry /**
642991554f2SKenneth D. Merry  * _mapping_add_to_removal_table - mark an entry for removal
643991554f2SKenneth D. Merry  * @sc: per adapter object
644991554f2SKenneth D. Merry  * @handle: Handle of enclosures/device/volume
645991554f2SKenneth D. Merry  *
646991554f2SKenneth D. Merry  * Adds the handle or DPM entry number in removal table.
647991554f2SKenneth D. Merry  *
648991554f2SKenneth D. Merry  * Returns nothing.
649991554f2SKenneth D. Merry  */
650991554f2SKenneth D. Merry static void
651991554f2SKenneth D. Merry _mapping_add_to_removal_table(struct mpr_softc *sc, u16 handle,
652991554f2SKenneth D. Merry     u16 dpm_idx)
653991554f2SKenneth D. Merry {
654991554f2SKenneth D. Merry 	struct map_removal_table *remove_entry;
655991554f2SKenneth D. Merry 	u32 i;
656991554f2SKenneth D. Merry 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
657991554f2SKenneth D. Merry 
658991554f2SKenneth D. Merry 	remove_entry = sc->removal_table;
659991554f2SKenneth D. Merry 
660991554f2SKenneth D. Merry 	for (i = 0; i < sc->max_devices; i++, remove_entry++) {
661991554f2SKenneth D. Merry 		if (remove_entry->dev_handle || remove_entry->dpm_entry_num !=
662991554f2SKenneth D. Merry 		    MPR_DPM_BAD_IDX)
663991554f2SKenneth D. Merry 			continue;
664991554f2SKenneth D. Merry 		if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
665991554f2SKenneth D. Merry 		    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
666991554f2SKenneth D. Merry 			if (dpm_idx)
667991554f2SKenneth D. Merry 				remove_entry->dpm_entry_num = dpm_idx;
668991554f2SKenneth D. Merry 			if (remove_entry->dpm_entry_num == MPR_DPM_BAD_IDX)
669991554f2SKenneth D. Merry 				remove_entry->dev_handle = handle;
670991554f2SKenneth D. Merry 		} else if ((ioc_pg8_flags &
671991554f2SKenneth D. Merry 		    MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
672991554f2SKenneth D. Merry 		    MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING)
673991554f2SKenneth D. Merry 			remove_entry->dev_handle = handle;
674991554f2SKenneth D. Merry 		break;
675991554f2SKenneth D. Merry 	}
676991554f2SKenneth D. Merry 
677991554f2SKenneth D. Merry }
678991554f2SKenneth D. Merry 
679991554f2SKenneth D. Merry /**
680*67feec50SStephen McConnell  * _mapping_inc_missing_count
681991554f2SKenneth D. Merry  * @sc: per adapter object
682*67feec50SStephen McConnell  * @map_idx: index into the mapping table for the device that is missing
683991554f2SKenneth D. Merry  *
684*67feec50SStephen McConnell  * Increment the missing count in the mapping table for a SAS, SATA, or PCIe
685*67feec50SStephen McConnell  * device that is not responding. If Persitent Mapping is used, increment the
686*67feec50SStephen McConnell  * DPM entry as well. Also, add this device to the removal table for possible
687*67feec50SStephen McConnell  * removal if a new device is added.
688991554f2SKenneth D. Merry  *
689991554f2SKenneth D. Merry  * Returns nothing.
690991554f2SKenneth D. Merry  */
691991554f2SKenneth D. Merry static void
692*67feec50SStephen McConnell _mapping_inc_missing_count(struct mpr_softc *sc, u32 map_idx)
693991554f2SKenneth D. Merry {
694991554f2SKenneth D. Merry 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
695991554f2SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
696991554f2SKenneth D. Merry 	Mpi2DriverMap0Entry_t *dpm_entry;
697991554f2SKenneth D. Merry 
698991554f2SKenneth D. Merry 	if (map_idx == MPR_MAPTABLE_BAD_IDX) {
699*67feec50SStephen McConnell 		mpr_dprint(sc, MPR_INFO, "%s: device is already removed from "
700*67feec50SStephen McConnell 		    "mapping table\n", __func__);
701*67feec50SStephen McConnell 		return;
702991554f2SKenneth D. Merry 	}
703991554f2SKenneth D. Merry 	mt_entry = &sc->mapping_table[map_idx];
704991554f2SKenneth D. Merry 	if (!mt_entry->init_complete) {
705991554f2SKenneth D. Merry 		if (mt_entry->missing_count < MPR_MAX_MISSING_COUNT)
706991554f2SKenneth D. Merry 			mt_entry->missing_count++;
707991554f2SKenneth D. Merry 		else
708991554f2SKenneth D. Merry 			mt_entry->init_complete = 1;
709991554f2SKenneth D. Merry 	}
710991554f2SKenneth D. Merry 	if (!mt_entry->missing_count)
711991554f2SKenneth D. Merry 		mt_entry->missing_count++;
712991554f2SKenneth D. Merry 	_mapping_add_to_removal_table(sc, mt_entry->dev_handle, 0);
713991554f2SKenneth D. Merry 	mt_entry->dev_handle = 0;
714991554f2SKenneth D. Merry 
715991554f2SKenneth D. Merry 	if (((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
716991554f2SKenneth D. Merry 	    MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) &&
717991554f2SKenneth D. Merry 	    sc->is_dpm_enable && !mt_entry->init_complete &&
718991554f2SKenneth D. Merry 	    mt_entry->dpm_entry_num != MPR_DPM_BAD_IDX) {
719*67feec50SStephen McConnell 		dpm_entry = (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 +
720991554f2SKenneth D. Merry 		    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
721991554f2SKenneth D. Merry 		dpm_entry += mt_entry->dpm_entry_num;
722991554f2SKenneth D. Merry 		dpm_entry->MappingInformation = mt_entry->missing_count;
723991554f2SKenneth D. Merry 		sc->dpm_flush_entry[mt_entry->dpm_entry_num] = 1;
724991554f2SKenneth D. Merry 	}
725991554f2SKenneth D. Merry 	mt_entry->init_complete = 1;
726991554f2SKenneth D. Merry }
727*67feec50SStephen McConnell 
728*67feec50SStephen McConnell /**
729*67feec50SStephen McConnell  * _mapping_update_missing_count - Update missing count for a device
730*67feec50SStephen McConnell  * @sc: per adapter object
731*67feec50SStephen McConnell  * @topo_change: Topology change event entry
732*67feec50SStephen McConnell  *
733*67feec50SStephen McConnell  * Search through the topology change list and if any device is found not
734*67feec50SStephen McConnell  * responding it's associated map table entry and DPM entry is updated
735*67feec50SStephen McConnell  *
736*67feec50SStephen McConnell  * Returns nothing.
737*67feec50SStephen McConnell  */
738*67feec50SStephen McConnell static void
739*67feec50SStephen McConnell _mapping_update_missing_count(struct mpr_softc *sc,
740*67feec50SStephen McConnell     struct _map_topology_change *topo_change)
741*67feec50SStephen McConnell {
742*67feec50SStephen McConnell 	u8 entry;
743*67feec50SStephen McConnell 	struct _map_phy_change *phy_change;
744*67feec50SStephen McConnell 	u32 map_idx;
745*67feec50SStephen McConnell 
746*67feec50SStephen McConnell 	for (entry = 0; entry < topo_change->num_entries; entry++) {
747*67feec50SStephen McConnell 		phy_change = &topo_change->phy_details[entry];
748*67feec50SStephen McConnell 		if (!phy_change->dev_handle || (phy_change->reason !=
749*67feec50SStephen McConnell 		    MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING))
750*67feec50SStephen McConnell 			continue;
751*67feec50SStephen McConnell 		map_idx = _mapping_get_mt_idx_from_handle(sc, phy_change->
752*67feec50SStephen McConnell 		    dev_handle);
753*67feec50SStephen McConnell 		phy_change->is_processed = 1;
754*67feec50SStephen McConnell 		_mapping_inc_missing_count(sc, map_idx);
755*67feec50SStephen McConnell 	}
756*67feec50SStephen McConnell }
757*67feec50SStephen McConnell 
758*67feec50SStephen McConnell /**
759*67feec50SStephen McConnell  * _mapping_update_pcie_missing_count - Update missing count for a PCIe device
760*67feec50SStephen McConnell  * @sc: per adapter object
761*67feec50SStephen McConnell  * @topo_change: Topology change event entry
762*67feec50SStephen McConnell  *
763*67feec50SStephen McConnell  * Search through the PCIe topology change list and if any device is found not
764*67feec50SStephen McConnell  * responding it's associated map table entry and DPM entry is updated
765*67feec50SStephen McConnell  *
766*67feec50SStephen McConnell  * Returns nothing.
767*67feec50SStephen McConnell  */
768*67feec50SStephen McConnell static void
769*67feec50SStephen McConnell _mapping_update_pcie_missing_count(struct mpr_softc *sc,
770*67feec50SStephen McConnell     struct _map_pcie_topology_change *topo_change)
771*67feec50SStephen McConnell {
772*67feec50SStephen McConnell 	u8 entry;
773*67feec50SStephen McConnell 	struct _map_port_change *port_change;
774*67feec50SStephen McConnell 	u32 map_idx;
775*67feec50SStephen McConnell 
776*67feec50SStephen McConnell 	for (entry = 0; entry < topo_change->num_entries; entry++) {
777*67feec50SStephen McConnell 		port_change = &topo_change->port_details[entry];
778*67feec50SStephen McConnell 		if (!port_change->dev_handle || (port_change->reason !=
779*67feec50SStephen McConnell 		    MPI26_EVENT_PCIE_TOPO_PS_NOT_RESPONDING))
780*67feec50SStephen McConnell 			continue;
781*67feec50SStephen McConnell 		map_idx = _mapping_get_mt_idx_from_handle(sc, port_change->
782*67feec50SStephen McConnell 		    dev_handle);
783*67feec50SStephen McConnell 		port_change->is_processed = 1;
784*67feec50SStephen McConnell 		_mapping_inc_missing_count(sc, map_idx);
785*67feec50SStephen McConnell 	}
786991554f2SKenneth D. Merry }
787991554f2SKenneth D. Merry 
788991554f2SKenneth D. Merry /**
789991554f2SKenneth D. Merry  * _mapping_find_enc_map_space -find map table entries for enclosure
790991554f2SKenneth D. Merry  * @sc: per adapter object
791991554f2SKenneth D. Merry  * @et_entry: enclosure entry
792991554f2SKenneth D. Merry  *
793991554f2SKenneth D. Merry  * Search through the mapping table defragment it and provide contiguous
794991554f2SKenneth D. Merry  * space in map table for a particular enclosure entry
795991554f2SKenneth D. Merry  *
796991554f2SKenneth D. Merry  * Returns start index in map table or bad index.
797991554f2SKenneth D. Merry  */
798991554f2SKenneth D. Merry static u32
799991554f2SKenneth D. Merry _mapping_find_enc_map_space(struct mpr_softc *sc,
800991554f2SKenneth D. Merry     struct enc_mapping_table *et_entry)
801991554f2SKenneth D. Merry {
802991554f2SKenneth D. Merry 	u16 vol_mapping_flags;
803991554f2SKenneth D. Merry 	u32 skip_count, end_of_table, map_idx, enc_idx;
804991554f2SKenneth D. Merry 	u16 num_found;
805991554f2SKenneth D. Merry 	u32 start_idx = MPR_MAPTABLE_BAD_IDX;
806991554f2SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
807991554f2SKenneth D. Merry 	struct enc_mapping_table *enc_entry;
808991554f2SKenneth D. Merry 	unsigned char done_flag = 0, found_space;
809991554f2SKenneth D. Merry 	u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs);
810991554f2SKenneth D. Merry 
811991554f2SKenneth D. Merry 	skip_count = sc->num_rsvd_entries;
812991554f2SKenneth D. Merry 	num_found = 0;
813991554f2SKenneth D. Merry 
814991554f2SKenneth D. Merry 	vol_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) &
815991554f2SKenneth D. Merry 	    MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
816991554f2SKenneth D. Merry 
817991554f2SKenneth D. Merry 	if (!sc->ir_firmware)
818991554f2SKenneth D. Merry 		end_of_table = sc->max_devices;
819991554f2SKenneth D. Merry 	else if (vol_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING)
820991554f2SKenneth D. Merry 		end_of_table = sc->max_devices;
821991554f2SKenneth D. Merry 	else
822991554f2SKenneth D. Merry 		end_of_table = sc->max_devices - sc->max_volumes;
823991554f2SKenneth D. Merry 
824991554f2SKenneth D. Merry 	for (map_idx = (max_num_phy_ids + skip_count);
825991554f2SKenneth D. Merry 	    map_idx < end_of_table; map_idx++) {
826991554f2SKenneth D. Merry 		mt_entry = &sc->mapping_table[map_idx];
827991554f2SKenneth D. Merry 		if ((et_entry->enclosure_id == mt_entry->physical_id) &&
828991554f2SKenneth D. Merry 		    (!mt_entry->phy_bits || (mt_entry->phy_bits &
829991554f2SKenneth D. Merry 		    et_entry->phy_bits))) {
830991554f2SKenneth D. Merry 			num_found += 1;
831991554f2SKenneth D. Merry 			if (num_found == et_entry->num_slots) {
832991554f2SKenneth D. Merry 				start_idx = (map_idx - num_found) + 1;
833991554f2SKenneth D. Merry 				return start_idx;
834991554f2SKenneth D. Merry 			}
835991554f2SKenneth D. Merry 		} else
836991554f2SKenneth D. Merry 			num_found = 0;
837991554f2SKenneth D. Merry 	}
838991554f2SKenneth D. Merry 	for (map_idx = (max_num_phy_ids + skip_count);
839991554f2SKenneth D. Merry 	    map_idx < end_of_table; map_idx++) {
840991554f2SKenneth D. Merry 		mt_entry = &sc->mapping_table[map_idx];
841991554f2SKenneth D. Merry 		if (!(mt_entry->device_info & MPR_DEV_RESERVED)) {
842991554f2SKenneth D. Merry 			num_found += 1;
843991554f2SKenneth D. Merry 			if (num_found == et_entry->num_slots) {
844991554f2SKenneth D. Merry 				start_idx = (map_idx - num_found) + 1;
845991554f2SKenneth D. Merry 				return start_idx;
846991554f2SKenneth D. Merry 			}
847991554f2SKenneth D. Merry 		} else
848991554f2SKenneth D. Merry 			num_found = 0;
849991554f2SKenneth D. Merry 	}
850991554f2SKenneth D. Merry 
851991554f2SKenneth D. Merry 	while (!done_flag) {
852991554f2SKenneth D. Merry 		enc_idx = _mapping_get_high_missing_et_idx(sc);
853991554f2SKenneth D. Merry 		if (enc_idx == MPR_ENCTABLE_BAD_IDX)
854991554f2SKenneth D. Merry 			return MPR_MAPTABLE_BAD_IDX;
855991554f2SKenneth D. Merry 		enc_entry = &sc->enclosure_table[enc_idx];
856991554f2SKenneth D. Merry 		/*VSP FIXME*/
857991554f2SKenneth D. Merry 		enc_entry->skip_search = 1;
858991554f2SKenneth D. Merry 		mt_entry = &sc->mapping_table[enc_entry->start_index];
859991554f2SKenneth D. Merry 		for (map_idx = enc_entry->start_index; map_idx <
860991554f2SKenneth D. Merry 		    (enc_entry->start_index + enc_entry->num_slots); map_idx++,
861991554f2SKenneth D. Merry 		    mt_entry++)
862991554f2SKenneth D. Merry 			mt_entry->device_info  &= ~MPR_DEV_RESERVED;
863991554f2SKenneth D. Merry 		found_space = 0;
864991554f2SKenneth D. Merry 		for (map_idx = (max_num_phy_ids +
865991554f2SKenneth D. Merry 		    skip_count); map_idx < end_of_table; map_idx++) {
866991554f2SKenneth D. Merry 			mt_entry = &sc->mapping_table[map_idx];
867991554f2SKenneth D. Merry 			if (!(mt_entry->device_info & MPR_DEV_RESERVED)) {
868991554f2SKenneth D. Merry 				num_found += 1;
869991554f2SKenneth D. Merry 				if (num_found == et_entry->num_slots) {
870991554f2SKenneth D. Merry 					start_idx = (map_idx - num_found) + 1;
871991554f2SKenneth D. Merry 					found_space = 1;
872991554f2SKenneth D. Merry 				}
873991554f2SKenneth D. Merry 			} else
874991554f2SKenneth D. Merry 				num_found = 0;
875991554f2SKenneth D. Merry 		}
876991554f2SKenneth D. Merry 
877991554f2SKenneth D. Merry 		if (!found_space)
878991554f2SKenneth D. Merry 			continue;
879991554f2SKenneth D. Merry 		for (map_idx = start_idx; map_idx < (start_idx + num_found);
880991554f2SKenneth D. Merry 		    map_idx++) {
881991554f2SKenneth D. Merry 			enc_entry = sc->enclosure_table;
882991554f2SKenneth D. Merry 			for (enc_idx = 0; enc_idx < sc->num_enc_table_entries;
883991554f2SKenneth D. Merry 			    enc_idx++, enc_entry++) {
884991554f2SKenneth D. Merry 				if (map_idx < enc_entry->start_index ||
885991554f2SKenneth D. Merry 				    map_idx > (enc_entry->start_index +
886991554f2SKenneth D. Merry 				    enc_entry->num_slots))
887991554f2SKenneth D. Merry 					continue;
888991554f2SKenneth D. Merry 				if (!enc_entry->removal_flag) {
889991554f2SKenneth D. Merry 					enc_entry->removal_flag = 1;
890991554f2SKenneth D. Merry 					_mapping_add_to_removal_table(sc, 0,
891991554f2SKenneth D. Merry 					    enc_entry->dpm_entry_num);
892991554f2SKenneth D. Merry 				}
893991554f2SKenneth D. Merry 				mt_entry = &sc->mapping_table[map_idx];
894991554f2SKenneth D. Merry 				if (mt_entry->device_info &
895991554f2SKenneth D. Merry 				    MPR_MAP_IN_USE) {
896991554f2SKenneth D. Merry 					_mapping_add_to_removal_table(sc,
897991554f2SKenneth D. Merry 					    mt_entry->dev_handle, 0);
898991554f2SKenneth D. Merry 					_mapping_clear_map_entry(mt_entry);
899991554f2SKenneth D. Merry 				}
900991554f2SKenneth D. Merry 				if (map_idx == (enc_entry->start_index +
901991554f2SKenneth D. Merry 				    enc_entry->num_slots - 1))
902991554f2SKenneth D. Merry 					_mapping_clear_enc_entry(et_entry);
903991554f2SKenneth D. Merry 			}
904991554f2SKenneth D. Merry 		}
905991554f2SKenneth D. Merry 		enc_entry = sc->enclosure_table;
906991554f2SKenneth D. Merry 		for (enc_idx = 0; enc_idx < sc->num_enc_table_entries;
907991554f2SKenneth D. Merry 		    enc_idx++, enc_entry++) {
908991554f2SKenneth D. Merry 			if (!enc_entry->removal_flag) {
909991554f2SKenneth D. Merry 				mt_entry = &sc->mapping_table[enc_entry->
910991554f2SKenneth D. Merry 				    start_index];
911991554f2SKenneth D. Merry 				for (map_idx = enc_entry->start_index; map_idx <
912991554f2SKenneth D. Merry 				    (enc_entry->start_index +
913991554f2SKenneth D. Merry 				    enc_entry->num_slots); map_idx++,
914991554f2SKenneth D. Merry 				    mt_entry++)
915991554f2SKenneth D. Merry 					mt_entry->device_info |=
916991554f2SKenneth D. Merry 					    MPR_DEV_RESERVED;
917991554f2SKenneth D. Merry 				et_entry->skip_search = 0;
918991554f2SKenneth D. Merry 			}
919991554f2SKenneth D. Merry 		}
920991554f2SKenneth D. Merry 		done_flag = 1;
921991554f2SKenneth D. Merry 	}
922991554f2SKenneth D. Merry 	return start_idx;
923991554f2SKenneth D. Merry }
924991554f2SKenneth D. Merry 
925991554f2SKenneth D. Merry /**
926991554f2SKenneth D. Merry  * _mapping_get_dev_info -get information about newly added devices
927991554f2SKenneth D. Merry  * @sc: per adapter object
928991554f2SKenneth D. Merry  * @topo_change: Topology change event entry
929991554f2SKenneth D. Merry  *
930991554f2SKenneth D. Merry  * Search through the topology change event list and issues sas device pg0
931991554f2SKenneth D. Merry  * requests for the newly added device and reserved entries in tables
932991554f2SKenneth D. Merry  *
933991554f2SKenneth D. Merry  * Returns nothing
934991554f2SKenneth D. Merry  */
935991554f2SKenneth D. Merry static void
936991554f2SKenneth D. Merry _mapping_get_dev_info(struct mpr_softc *sc,
937991554f2SKenneth D. Merry     struct _map_topology_change *topo_change)
938991554f2SKenneth D. Merry {
939991554f2SKenneth D. Merry 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
940991554f2SKenneth D. Merry 	Mpi2ConfigReply_t mpi_reply;
941991554f2SKenneth D. Merry 	Mpi2SasDevicePage0_t sas_device_pg0;
942a2c14879SStephen McConnell 	u8 entry, enc_idx, phy_idx, sata_end_device;
943991554f2SKenneth D. Merry 	u32 map_idx, index, device_info;
944991554f2SKenneth D. Merry 	struct _map_phy_change *phy_change, *tmp_phy_change;
945991554f2SKenneth D. Merry 	uint64_t sas_address;
946991554f2SKenneth D. Merry 	struct enc_mapping_table *et_entry;
947991554f2SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
948991554f2SKenneth D. Merry 	u8 add_code = MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED;
949a2c14879SStephen McConnell 	int rc = 1;
950991554f2SKenneth D. Merry 
951991554f2SKenneth D. Merry 	for (entry = 0; entry < topo_change->num_entries; entry++) {
952991554f2SKenneth D. Merry 		phy_change = &topo_change->phy_details[entry];
953991554f2SKenneth D. Merry 		if (phy_change->is_processed || !phy_change->dev_handle ||
954991554f2SKenneth D. Merry 		    phy_change->reason != MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED)
955991554f2SKenneth D. Merry 			continue;
956991554f2SKenneth D. Merry 		if (mpr_config_get_sas_device_pg0(sc, &mpi_reply,
957991554f2SKenneth D. Merry 		    &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
958991554f2SKenneth D. Merry 		    phy_change->dev_handle)) {
959991554f2SKenneth D. Merry 			phy_change->is_processed = 1;
960991554f2SKenneth D. Merry 			continue;
961991554f2SKenneth D. Merry 		}
962991554f2SKenneth D. Merry 
963a2c14879SStephen McConnell 		/*
964a2c14879SStephen McConnell 		 * Always get SATA Identify information because this is used
965a2c14879SStephen McConnell 		 * to determine if Start/Stop Unit should be sent to the drive
966a2c14879SStephen McConnell 		 * when the system is shutdown.
967a2c14879SStephen McConnell 		 */
968991554f2SKenneth D. Merry 		device_info = le32toh(sas_device_pg0.DeviceInfo);
969991554f2SKenneth D. Merry 		sas_address = sas_device_pg0.SASAddress.High;
970991554f2SKenneth D. Merry 		sas_address = (sas_address << 32) |
971991554f2SKenneth D. Merry 		    sas_device_pg0.SASAddress.Low;
972a2c14879SStephen McConnell 		sata_end_device = 0;
973a2c14879SStephen McConnell 		if ((device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE) &&
974a2c14879SStephen McConnell 		    (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)) {
975a2c14879SStephen McConnell 			sata_end_device = 1;
976a2c14879SStephen McConnell 			rc = mprsas_get_sas_address_for_sata_disk(sc,
977a2c14879SStephen McConnell 			    &sas_address, phy_change->dev_handle, device_info,
978a2c14879SStephen McConnell 			    &phy_change->is_SATA_SSD);
979a2c14879SStephen McConnell 			if (rc) {
980a2c14879SStephen McConnell 				mpr_dprint(sc, MPR_ERROR, "%s: failed to get "
981a2c14879SStephen McConnell 				    "disk type (SSD or HDD) and SAS Address "
982a2c14879SStephen McConnell 				    "for SATA device with handle 0x%04x\n",
983a2c14879SStephen McConnell 				    __func__, phy_change->dev_handle);
984a2c14879SStephen McConnell 			} else {
985a2c14879SStephen McConnell 				mpr_dprint(sc, MPR_INFO, "SAS Address for SATA "
986a2c14879SStephen McConnell 				    "device = %jx\n", sas_address);
987991554f2SKenneth D. Merry 			}
988a2c14879SStephen McConnell 		}
989a2c14879SStephen McConnell 
990991554f2SKenneth D. Merry 		phy_change->physical_id = sas_address;
991991554f2SKenneth D. Merry 		phy_change->slot = le16toh(sas_device_pg0.Slot);
992*67feec50SStephen McConnell 		phy_change->device_info = device_info;
993991554f2SKenneth D. Merry 
994991554f2SKenneth D. Merry 		if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
995991554f2SKenneth D. Merry 		    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
996991554f2SKenneth D. Merry 			enc_idx = _mapping_get_enc_idx_from_handle(sc,
997991554f2SKenneth D. Merry 			    topo_change->enc_handle);
998991554f2SKenneth D. Merry 			if (enc_idx == MPR_ENCTABLE_BAD_IDX) {
999991554f2SKenneth D. Merry 				phy_change->is_processed = 1;
1000a2c14879SStephen McConnell 				mpr_dprint(sc, MPR_MAPPING, "%s: failed to add "
1001a2c14879SStephen McConnell 				    "the device with handle 0x%04x because the "
1002a2c14879SStephen McConnell 				    "enclosure is not in the mapping table\n",
1003a2c14879SStephen McConnell 				    __func__, phy_change->dev_handle);
1004991554f2SKenneth D. Merry 				continue;
1005991554f2SKenneth D. Merry 			}
1006991554f2SKenneth D. Merry 			if (!((phy_change->device_info &
1007991554f2SKenneth D. Merry 			    MPI2_SAS_DEVICE_INFO_END_DEVICE) &&
1008991554f2SKenneth D. Merry 			    (phy_change->device_info &
1009991554f2SKenneth D. Merry 			    (MPI2_SAS_DEVICE_INFO_SSP_TARGET |
1010991554f2SKenneth D. Merry 			    MPI2_SAS_DEVICE_INFO_STP_TARGET |
1011991554f2SKenneth D. Merry 			    MPI2_SAS_DEVICE_INFO_SATA_DEVICE)))) {
1012991554f2SKenneth D. Merry 				phy_change->is_processed = 1;
1013991554f2SKenneth D. Merry 				continue;
1014991554f2SKenneth D. Merry 			}
1015991554f2SKenneth D. Merry 			et_entry = &sc->enclosure_table[enc_idx];
1016991554f2SKenneth D. Merry 			if (et_entry->start_index != MPR_MAPTABLE_BAD_IDX)
1017991554f2SKenneth D. Merry 				continue;
1018991554f2SKenneth D. Merry 			if (!topo_change->exp_handle) {
1019991554f2SKenneth D. Merry 				map_idx	= sc->num_rsvd_entries;
1020991554f2SKenneth D. Merry 				et_entry->start_index = map_idx;
1021991554f2SKenneth D. Merry 			} else {
1022991554f2SKenneth D. Merry 				map_idx = _mapping_find_enc_map_space(sc,
1023991554f2SKenneth D. Merry 				    et_entry);
1024991554f2SKenneth D. Merry 				et_entry->start_index = map_idx;
1025991554f2SKenneth D. Merry 				if (et_entry->start_index ==
1026991554f2SKenneth D. Merry 				    MPR_MAPTABLE_BAD_IDX) {
1027991554f2SKenneth D. Merry 					phy_change->is_processed = 1;
1028991554f2SKenneth D. Merry 					for (phy_idx = 0; phy_idx <
1029991554f2SKenneth D. Merry 					    topo_change->num_entries;
1030991554f2SKenneth D. Merry 					    phy_idx++) {
1031991554f2SKenneth D. Merry 						tmp_phy_change =
1032991554f2SKenneth D. Merry 						    &topo_change->phy_details
1033991554f2SKenneth D. Merry 						    [phy_idx];
1034991554f2SKenneth D. Merry 						if (tmp_phy_change->reason ==
1035991554f2SKenneth D. Merry 						    add_code)
1036991554f2SKenneth D. Merry 							tmp_phy_change->
1037991554f2SKenneth D. Merry 							    is_processed = 1;
1038991554f2SKenneth D. Merry 					}
1039991554f2SKenneth D. Merry 					break;
1040991554f2SKenneth D. Merry 				}
1041991554f2SKenneth D. Merry 			}
1042*67feec50SStephen McConnell 
1043*67feec50SStephen McConnell 			/* Found space in enclosure for mapping entry */
1044991554f2SKenneth D. Merry 			mt_entry = &sc->mapping_table[map_idx];
1045991554f2SKenneth D. Merry 			for (index = map_idx; index < (et_entry->num_slots
1046991554f2SKenneth D. Merry 			    + map_idx); index++, mt_entry++) {
1047991554f2SKenneth D. Merry 				mt_entry->device_info = MPR_DEV_RESERVED;
1048991554f2SKenneth D. Merry 				mt_entry->physical_id = et_entry->enclosure_id;
1049991554f2SKenneth D. Merry 				mt_entry->phy_bits = et_entry->phy_bits;
1050*67feec50SStephen McConnell 				mt_entry->missing_count = 0;
1051*67feec50SStephen McConnell 			}
1052*67feec50SStephen McConnell 		}
1053*67feec50SStephen McConnell 	}
1054*67feec50SStephen McConnell }
1055*67feec50SStephen McConnell 
1056*67feec50SStephen McConnell /**
1057*67feec50SStephen McConnell  * _mapping_get_pcie_dev_info -get information about newly added PCIe devices
1058*67feec50SStephen McConnell  * @sc: per adapter object
1059*67feec50SStephen McConnell  * @topo_change: Topology change event entry
1060*67feec50SStephen McConnell  *
1061*67feec50SStephen McConnell  * Searches through the PCIe topology change event list and issues PCIe device
1062*67feec50SStephen McConnell  * pg0 requests for the newly added PCIe device. If the device is in an
1063*67feec50SStephen McConnell  * enclosure, search for available space in the enclosure mapping table for the
1064*67feec50SStephen McConnell  * device and reserve that space.
1065*67feec50SStephen McConnell  *
1066*67feec50SStephen McConnell  * Returns nothing
1067*67feec50SStephen McConnell  */
1068*67feec50SStephen McConnell static void
1069*67feec50SStephen McConnell _mapping_get_pcie_dev_info(struct mpr_softc *sc,
1070*67feec50SStephen McConnell     struct _map_pcie_topology_change *topo_change)
1071*67feec50SStephen McConnell {
1072*67feec50SStephen McConnell 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
1073*67feec50SStephen McConnell 	Mpi2ConfigReply_t mpi_reply;
1074*67feec50SStephen McConnell 	Mpi26PCIeDevicePage0_t pcie_device_pg0;
1075*67feec50SStephen McConnell 	u8 entry, enc_idx, port_idx;
1076*67feec50SStephen McConnell 	u32 map_idx, index;
1077*67feec50SStephen McConnell 	struct _map_port_change *port_change, *tmp_port_change;
1078*67feec50SStephen McConnell 	uint64_t pcie_wwid;
1079*67feec50SStephen McConnell 	struct enc_mapping_table *et_entry;
1080*67feec50SStephen McConnell 	struct dev_mapping_table *mt_entry;
1081*67feec50SStephen McConnell 	u8 add_code = MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED;
1082*67feec50SStephen McConnell 
1083*67feec50SStephen McConnell 	for (entry = 0; entry < topo_change->num_entries; entry++) {
1084*67feec50SStephen McConnell 		port_change = &topo_change->port_details[entry];
1085*67feec50SStephen McConnell 		if (port_change->is_processed || !port_change->dev_handle ||
1086*67feec50SStephen McConnell 		    port_change->reason != MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED)
1087*67feec50SStephen McConnell 			continue;
1088*67feec50SStephen McConnell 		if (mpr_config_get_pcie_device_pg0(sc, &mpi_reply,
1089*67feec50SStephen McConnell 		    &pcie_device_pg0, MPI26_PCIE_DEVICE_PGAD_FORM_HANDLE,
1090*67feec50SStephen McConnell 		    port_change->dev_handle)) {
1091*67feec50SStephen McConnell 			port_change->is_processed = 1;
1092*67feec50SStephen McConnell 			continue;
1093*67feec50SStephen McConnell 		}
1094*67feec50SStephen McConnell 
1095*67feec50SStephen McConnell 		pcie_wwid = pcie_device_pg0.WWID.High;
1096*67feec50SStephen McConnell 		pcie_wwid = (pcie_wwid << 32) | pcie_device_pg0.WWID.Low;
1097*67feec50SStephen McConnell 		port_change->physical_id = pcie_wwid;
1098*67feec50SStephen McConnell 		port_change->slot = le16toh(pcie_device_pg0.Slot);
1099*67feec50SStephen McConnell 		port_change->device_info = le32toh(pcie_device_pg0.DeviceInfo);
1100*67feec50SStephen McConnell 
1101*67feec50SStephen McConnell 		if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
1102*67feec50SStephen McConnell 		    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
1103*67feec50SStephen McConnell 			enc_idx = _mapping_get_enc_idx_from_handle(sc,
1104*67feec50SStephen McConnell 			    topo_change->enc_handle);
1105*67feec50SStephen McConnell 			if (enc_idx == MPR_ENCTABLE_BAD_IDX) {
1106*67feec50SStephen McConnell 				port_change->is_processed = 1;
1107*67feec50SStephen McConnell 				mpr_dprint(sc, MPR_MAPPING, "%s: failed to add "
1108*67feec50SStephen McConnell 				    "the device with handle 0x%04x because the "
1109*67feec50SStephen McConnell 				    "enclosure is not in the mapping table\n",
1110*67feec50SStephen McConnell 				    __func__, port_change->dev_handle);
1111*67feec50SStephen McConnell 				continue;
1112*67feec50SStephen McConnell 			}
1113*67feec50SStephen McConnell 			if (!(port_change->device_info &
1114*67feec50SStephen McConnell 			    MPI26_PCIE_DEVINFO_NVME)) {
1115*67feec50SStephen McConnell 				port_change->is_processed = 1;
1116*67feec50SStephen McConnell 				continue;
1117*67feec50SStephen McConnell 			}
1118*67feec50SStephen McConnell 			et_entry = &sc->enclosure_table[enc_idx];
1119*67feec50SStephen McConnell 			if (et_entry->start_index != MPR_MAPTABLE_BAD_IDX)
1120*67feec50SStephen McConnell 				continue;
1121*67feec50SStephen McConnell 			if (!topo_change->switch_dev_handle) {
1122*67feec50SStephen McConnell 				map_idx	= sc->num_rsvd_entries;
1123*67feec50SStephen McConnell 				et_entry->start_index = map_idx;
1124*67feec50SStephen McConnell 			} else {
1125*67feec50SStephen McConnell 				map_idx = _mapping_find_enc_map_space(sc,
1126*67feec50SStephen McConnell 				    et_entry);
1127*67feec50SStephen McConnell 				et_entry->start_index = map_idx;
1128*67feec50SStephen McConnell 				if (et_entry->start_index ==
1129*67feec50SStephen McConnell 				    MPR_MAPTABLE_BAD_IDX) {
1130*67feec50SStephen McConnell 					port_change->is_processed = 1;
1131*67feec50SStephen McConnell 					for (port_idx = 0; port_idx <
1132*67feec50SStephen McConnell 					    topo_change->num_entries;
1133*67feec50SStephen McConnell 					    port_idx++) {
1134*67feec50SStephen McConnell 						tmp_port_change =
1135*67feec50SStephen McConnell 						    &topo_change->port_details
1136*67feec50SStephen McConnell 						    [port_idx];
1137*67feec50SStephen McConnell 						if (tmp_port_change->reason ==
1138*67feec50SStephen McConnell 						    add_code)
1139*67feec50SStephen McConnell 							tmp_port_change->
1140*67feec50SStephen McConnell 							    is_processed = 1;
1141*67feec50SStephen McConnell 					}
1142*67feec50SStephen McConnell 					break;
1143*67feec50SStephen McConnell 				}
1144*67feec50SStephen McConnell 			}
1145*67feec50SStephen McConnell 
1146*67feec50SStephen McConnell 			/* Found space in enclosure for mapping entry */
1147*67feec50SStephen McConnell 			mt_entry = &sc->mapping_table[map_idx];
1148*67feec50SStephen McConnell 			for (index = map_idx; index < (et_entry->num_slots
1149*67feec50SStephen McConnell 			    + map_idx); index++, mt_entry++) {
1150*67feec50SStephen McConnell 				mt_entry->device_info = MPR_DEV_RESERVED;
1151*67feec50SStephen McConnell 				mt_entry->physical_id = et_entry->enclosure_id;
1152*67feec50SStephen McConnell 				mt_entry->phy_bits = et_entry->phy_bits;
1153*67feec50SStephen McConnell 				mt_entry->missing_count = 0;
1154991554f2SKenneth D. Merry 			}
1155991554f2SKenneth D. Merry 		}
1156991554f2SKenneth D. Merry 	}
1157991554f2SKenneth D. Merry }
1158991554f2SKenneth D. Merry 
1159991554f2SKenneth D. Merry /**
1160991554f2SKenneth D. Merry  * _mapping_set_mid_to_eid -set map table data from enclosure table
1161991554f2SKenneth D. Merry  * @sc: per adapter object
1162991554f2SKenneth D. Merry  * @et_entry: enclosure entry
1163991554f2SKenneth D. Merry  *
1164991554f2SKenneth D. Merry  * Returns nothing
1165991554f2SKenneth D. Merry  */
1166991554f2SKenneth D. Merry static inline void
1167991554f2SKenneth D. Merry _mapping_set_mid_to_eid(struct mpr_softc *sc,
1168991554f2SKenneth D. Merry     struct enc_mapping_table *et_entry)
1169991554f2SKenneth D. Merry {
1170991554f2SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
1171991554f2SKenneth D. Merry 	u16 slots = et_entry->num_slots, map_idx;
1172991554f2SKenneth D. Merry 	u32 start_idx = et_entry->start_index;
1173991554f2SKenneth D. Merry 	if (start_idx != MPR_MAPTABLE_BAD_IDX) {
1174991554f2SKenneth D. Merry 		mt_entry = &sc->mapping_table[start_idx];
1175991554f2SKenneth D. Merry 		for (map_idx = 0; map_idx < slots; map_idx++, mt_entry++)
1176991554f2SKenneth D. Merry 			mt_entry->physical_id = et_entry->enclosure_id;
1177991554f2SKenneth D. Merry 	}
1178991554f2SKenneth D. Merry }
1179991554f2SKenneth D. Merry 
1180991554f2SKenneth D. Merry /**
1181991554f2SKenneth D. Merry  * _mapping_clear_removed_entries - mark the entries to be cleared
1182991554f2SKenneth D. Merry  * @sc: per adapter object
1183991554f2SKenneth D. Merry  *
1184991554f2SKenneth D. Merry  * Search through the removal table and mark the entries which needs to be
1185991554f2SKenneth D. Merry  * flushed to DPM and also updates the map table and enclosure table by
1186991554f2SKenneth D. Merry  * clearing the corresponding entries.
1187991554f2SKenneth D. Merry  *
1188991554f2SKenneth D. Merry  * Returns nothing
1189991554f2SKenneth D. Merry  */
1190991554f2SKenneth D. Merry static void
1191991554f2SKenneth D. Merry _mapping_clear_removed_entries(struct mpr_softc *sc)
1192991554f2SKenneth D. Merry {
1193991554f2SKenneth D. Merry 	u32 remove_idx;
1194991554f2SKenneth D. Merry 	struct map_removal_table *remove_entry;
1195991554f2SKenneth D. Merry 	Mpi2DriverMap0Entry_t *dpm_entry;
1196991554f2SKenneth D. Merry 	u8 done_flag = 0, num_entries, m, i;
1197991554f2SKenneth D. Merry 	struct enc_mapping_table *et_entry, *from, *to;
1198991554f2SKenneth D. Merry 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
1199991554f2SKenneth D. Merry 
1200991554f2SKenneth D. Merry 	if (sc->is_dpm_enable) {
1201991554f2SKenneth D. Merry 		remove_entry = sc->removal_table;
1202991554f2SKenneth D. Merry 		for (remove_idx = 0; remove_idx < sc->max_devices;
1203991554f2SKenneth D. Merry 		    remove_idx++, remove_entry++) {
1204991554f2SKenneth D. Merry 			if (remove_entry->dpm_entry_num != MPR_DPM_BAD_IDX) {
1205991554f2SKenneth D. Merry 				dpm_entry = (Mpi2DriverMap0Entry_t *)
1206991554f2SKenneth D. Merry 				    ((u8 *) sc->dpm_pg0 +
1207991554f2SKenneth D. Merry 				    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
1208991554f2SKenneth D. Merry 				dpm_entry += remove_entry->dpm_entry_num;
1209991554f2SKenneth D. Merry 				dpm_entry->PhysicalIdentifier.Low = 0;
1210991554f2SKenneth D. Merry 				dpm_entry->PhysicalIdentifier.High = 0;
1211991554f2SKenneth D. Merry 				dpm_entry->DeviceIndex = 0;
1212991554f2SKenneth D. Merry 				dpm_entry->MappingInformation = 0;
1213991554f2SKenneth D. Merry 				dpm_entry->PhysicalBitsMapping = 0;
1214991554f2SKenneth D. Merry 				sc->dpm_flush_entry[remove_entry->
1215991554f2SKenneth D. Merry 				    dpm_entry_num] = 1;
1216991554f2SKenneth D. Merry 				sc->dpm_entry_used[remove_entry->dpm_entry_num]
1217991554f2SKenneth D. Merry 				    = 0;
1218991554f2SKenneth D. Merry 				remove_entry->dpm_entry_num = MPR_DPM_BAD_IDX;
1219991554f2SKenneth D. Merry 			}
1220991554f2SKenneth D. Merry 		}
1221991554f2SKenneth D. Merry 	}
1222991554f2SKenneth D. Merry 	if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
1223991554f2SKenneth D. Merry 	    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
1224991554f2SKenneth D. Merry 		num_entries = sc->num_enc_table_entries;
1225991554f2SKenneth D. Merry 		while (!done_flag) {
1226991554f2SKenneth D. Merry 			done_flag = 1;
1227991554f2SKenneth D. Merry 			et_entry = sc->enclosure_table;
1228991554f2SKenneth D. Merry 			for (i = 0; i < num_entries; i++, et_entry++) {
1229991554f2SKenneth D. Merry 				if (!et_entry->enc_handle && et_entry->
1230991554f2SKenneth D. Merry 				    init_complete) {
1231991554f2SKenneth D. Merry 					done_flag = 0;
1232991554f2SKenneth D. Merry 					if (i != (num_entries - 1)) {
1233991554f2SKenneth D. Merry 						from = &sc->enclosure_table
1234991554f2SKenneth D. Merry 						    [i+1];
1235991554f2SKenneth D. Merry 						to = &sc->enclosure_table[i];
1236991554f2SKenneth D. Merry 						for (m = i; m < (num_entries -
1237991554f2SKenneth D. Merry 						    1); m++, from++, to++) {
1238991554f2SKenneth D. Merry 							_mapping_set_mid_to_eid
1239991554f2SKenneth D. Merry 							    (sc, to);
1240991554f2SKenneth D. Merry 							*to = *from;
1241991554f2SKenneth D. Merry 						}
1242991554f2SKenneth D. Merry 						_mapping_clear_enc_entry(to);
1243991554f2SKenneth D. Merry 						sc->num_enc_table_entries--;
1244991554f2SKenneth D. Merry 						num_entries =
1245991554f2SKenneth D. Merry 						    sc->num_enc_table_entries;
1246991554f2SKenneth D. Merry 					} else {
1247991554f2SKenneth D. Merry 						_mapping_clear_enc_entry
1248991554f2SKenneth D. Merry 						    (et_entry);
1249991554f2SKenneth D. Merry 						sc->num_enc_table_entries--;
1250991554f2SKenneth D. Merry 						num_entries =
1251991554f2SKenneth D. Merry 						    sc->num_enc_table_entries;
1252991554f2SKenneth D. Merry 					}
1253991554f2SKenneth D. Merry 				}
1254991554f2SKenneth D. Merry 			}
1255991554f2SKenneth D. Merry 		}
1256991554f2SKenneth D. Merry 	}
1257991554f2SKenneth D. Merry }
1258991554f2SKenneth D. Merry 
1259991554f2SKenneth D. Merry /**
1260991554f2SKenneth D. Merry  * _mapping_add_new_device -Add the new device into mapping table
1261991554f2SKenneth D. Merry  * @sc: per adapter object
1262991554f2SKenneth D. Merry  * @topo_change: Topology change event entry
1263991554f2SKenneth D. Merry  *
1264*67feec50SStephen McConnell  * Search through the topology change event list and update map table,
1265*67feec50SStephen McConnell  * enclosure table and DPM pages for the newly added devices.
1266991554f2SKenneth D. Merry  *
1267991554f2SKenneth D. Merry  * Returns nothing
1268991554f2SKenneth D. Merry  */
1269991554f2SKenneth D. Merry static void
1270991554f2SKenneth D. Merry _mapping_add_new_device(struct mpr_softc *sc,
1271991554f2SKenneth D. Merry     struct _map_topology_change *topo_change)
1272991554f2SKenneth D. Merry {
1273991554f2SKenneth D. Merry 	u8 enc_idx, missing_cnt, is_removed = 0;
1274991554f2SKenneth D. Merry 	u16 dpm_idx;
1275991554f2SKenneth D. Merry 	u32 search_idx, map_idx;
1276991554f2SKenneth D. Merry 	u32 entry;
1277991554f2SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
1278991554f2SKenneth D. Merry 	struct enc_mapping_table *et_entry;
1279991554f2SKenneth D. Merry 	struct _map_phy_change *phy_change;
1280991554f2SKenneth D. Merry 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
1281991554f2SKenneth D. Merry 	Mpi2DriverMap0Entry_t *dpm_entry;
1282991554f2SKenneth D. Merry 	uint64_t temp64_var;
1283991554f2SKenneth D. Merry 	u8 map_shift = MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT;
1284991554f2SKenneth D. Merry 	u8 hdr_sz = sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER);
1285991554f2SKenneth D. Merry 	u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs);
1286991554f2SKenneth D. Merry 
1287991554f2SKenneth D. Merry 	for (entry = 0; entry < topo_change->num_entries; entry++) {
1288991554f2SKenneth D. Merry 		phy_change = &topo_change->phy_details[entry];
1289991554f2SKenneth D. Merry 		if (phy_change->is_processed)
1290991554f2SKenneth D. Merry 			continue;
1291991554f2SKenneth D. Merry 		if (phy_change->reason != MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED ||
1292991554f2SKenneth D. Merry 		    !phy_change->dev_handle) {
1293991554f2SKenneth D. Merry 			phy_change->is_processed = 1;
1294991554f2SKenneth D. Merry 			continue;
1295991554f2SKenneth D. Merry 		}
1296991554f2SKenneth D. Merry 		if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
1297991554f2SKenneth D. Merry 		    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
1298991554f2SKenneth D. Merry 			enc_idx = _mapping_get_enc_idx_from_handle
1299991554f2SKenneth D. Merry 			    (sc, topo_change->enc_handle);
1300991554f2SKenneth D. Merry 			if (enc_idx == MPR_ENCTABLE_BAD_IDX) {
1301991554f2SKenneth D. Merry 				phy_change->is_processed = 1;
1302*67feec50SStephen McConnell 				mpr_dprint(sc, MPR_ERROR, "%s: failed to add "
1303*67feec50SStephen McConnell 				    "the device with handle 0x%04x because the "
1304*67feec50SStephen McConnell 				    "enclosure is not in the mapping table\n",
1305*67feec50SStephen McConnell 				    __func__, phy_change->dev_handle);
1306991554f2SKenneth D. Merry 				continue;
1307991554f2SKenneth D. Merry 			}
1308991554f2SKenneth D. Merry 			et_entry = &sc->enclosure_table[enc_idx];
1309991554f2SKenneth D. Merry 			if (et_entry->start_index == MPR_MAPTABLE_BAD_IDX) {
1310991554f2SKenneth D. Merry 				phy_change->is_processed = 1;
1311991554f2SKenneth D. Merry 				if (!sc->mt_full_retry) {
1312991554f2SKenneth D. Merry 					sc->mt_add_device_failed = 1;
1313991554f2SKenneth D. Merry 					continue;
1314991554f2SKenneth D. Merry 				}
1315*67feec50SStephen McConnell 				mpr_dprint(sc, MPR_INFO, "%s: failed to add "
1316*67feec50SStephen McConnell 				    "the device with handle 0x%04x because "
1317*67feec50SStephen McConnell 				    "there is no free space available in the "
1318*67feec50SStephen McConnell 				    "mapping table\n", __func__,
1319*67feec50SStephen McConnell 				    phy_change->dev_handle);
1320991554f2SKenneth D. Merry 				continue;
1321991554f2SKenneth D. Merry 			}
1322991554f2SKenneth D. Merry 			map_idx = et_entry->start_index + phy_change->slot -
1323991554f2SKenneth D. Merry 			    et_entry->start_slot;
1324991554f2SKenneth D. Merry 			mt_entry = &sc->mapping_table[map_idx];
1325991554f2SKenneth D. Merry 			mt_entry->physical_id = phy_change->physical_id;
1326991554f2SKenneth D. Merry 			mt_entry->channel = 0;
1327991554f2SKenneth D. Merry 			mt_entry->id = map_idx;
1328991554f2SKenneth D. Merry 			mt_entry->dev_handle = phy_change->dev_handle;
1329991554f2SKenneth D. Merry 			mt_entry->missing_count = 0;
1330991554f2SKenneth D. Merry 			mt_entry->dpm_entry_num = et_entry->dpm_entry_num;
1331991554f2SKenneth D. Merry 			mt_entry->device_info = phy_change->device_info |
1332991554f2SKenneth D. Merry 			    (MPR_DEV_RESERVED | MPR_MAP_IN_USE);
1333991554f2SKenneth D. Merry 			if (sc->is_dpm_enable) {
1334991554f2SKenneth D. Merry 				dpm_idx = et_entry->dpm_entry_num;
1335991554f2SKenneth D. Merry 				if (dpm_idx == MPR_DPM_BAD_IDX)
1336991554f2SKenneth D. Merry 					dpm_idx = _mapping_get_dpm_idx_from_id
1337991554f2SKenneth D. Merry 					    (sc, et_entry->enclosure_id,
1338991554f2SKenneth D. Merry 					     et_entry->phy_bits);
1339991554f2SKenneth D. Merry 				if (dpm_idx == MPR_DPM_BAD_IDX) {
1340991554f2SKenneth D. Merry 					dpm_idx = _mapping_get_free_dpm_idx(sc);
1341991554f2SKenneth D. Merry 					if (dpm_idx != MPR_DPM_BAD_IDX) {
1342991554f2SKenneth D. Merry 						dpm_entry =
1343991554f2SKenneth D. Merry 						    (Mpi2DriverMap0Entry_t *)
1344991554f2SKenneth D. Merry 						    ((u8 *) sc->dpm_pg0 +
1345991554f2SKenneth D. Merry 						     hdr_sz);
1346991554f2SKenneth D. Merry 						dpm_entry += dpm_idx;
1347991554f2SKenneth D. Merry 						dpm_entry->
1348991554f2SKenneth D. Merry 						    PhysicalIdentifier.Low =
1349991554f2SKenneth D. Merry 						    (0xFFFFFFFF &
1350991554f2SKenneth D. Merry 						    et_entry->enclosure_id);
1351991554f2SKenneth D. Merry 						dpm_entry->
1352991554f2SKenneth D. Merry 						    PhysicalIdentifier.High =
1353991554f2SKenneth D. Merry 						    ( et_entry->enclosure_id
1354991554f2SKenneth D. Merry 						     >> 32);
1355991554f2SKenneth D. Merry 						dpm_entry->DeviceIndex =
1356991554f2SKenneth D. Merry 						    (U16)et_entry->start_index;
1357991554f2SKenneth D. Merry 						dpm_entry->MappingInformation =
1358991554f2SKenneth D. Merry 							et_entry->num_slots;
1359991554f2SKenneth D. Merry 						dpm_entry->MappingInformation
1360991554f2SKenneth D. Merry 						    <<= map_shift;
1361991554f2SKenneth D. Merry 						dpm_entry->PhysicalBitsMapping
1362991554f2SKenneth D. Merry 						    = et_entry->phy_bits;
1363991554f2SKenneth D. Merry 						et_entry->dpm_entry_num =
1364991554f2SKenneth D. Merry 						    dpm_idx;
1365991554f2SKenneth D. Merry 		/* FIXME Do I need to set the dpm_idxin mt_entry too */
1366991554f2SKenneth D. Merry 						sc->dpm_entry_used[dpm_idx] = 1;
1367991554f2SKenneth D. Merry 						sc->dpm_flush_entry[dpm_idx] =
1368991554f2SKenneth D. Merry 						    1;
1369991554f2SKenneth D. Merry 						phy_change->is_processed = 1;
1370991554f2SKenneth D. Merry 					} else {
1371991554f2SKenneth D. Merry 						phy_change->is_processed = 1;
1372991554f2SKenneth D. Merry 						mpr_dprint(sc, MPR_INFO, "%s: "
1373991554f2SKenneth D. Merry 						    "failed to add the device "
1374991554f2SKenneth D. Merry 						    "with handle 0x%04x to "
1375991554f2SKenneth D. Merry 						    "persistent table because "
1376991554f2SKenneth D. Merry 						    "there is no free space "
1377991554f2SKenneth D. Merry 						    "available\n", __func__,
1378991554f2SKenneth D. Merry 						    phy_change->dev_handle);
1379991554f2SKenneth D. Merry 					}
1380991554f2SKenneth D. Merry 				} else {
1381991554f2SKenneth D. Merry 					et_entry->dpm_entry_num = dpm_idx;
1382991554f2SKenneth D. Merry 					mt_entry->dpm_entry_num = dpm_idx;
1383991554f2SKenneth D. Merry 				}
1384991554f2SKenneth D. Merry 			}
1385991554f2SKenneth D. Merry 			/* FIXME Why not mt_entry too? */
1386991554f2SKenneth D. Merry 			et_entry->init_complete = 1;
1387991554f2SKenneth D. Merry 		} else if ((ioc_pg8_flags &
1388991554f2SKenneth D. Merry 		    MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
1389991554f2SKenneth D. Merry 		    MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
1390991554f2SKenneth D. Merry 			map_idx = _mapping_get_mt_idx_from_id
1391991554f2SKenneth D. Merry 			    (sc, phy_change->physical_id);
1392991554f2SKenneth D. Merry 			if (map_idx == MPR_MAPTABLE_BAD_IDX) {
1393991554f2SKenneth D. Merry 				search_idx = sc->num_rsvd_entries;
1394991554f2SKenneth D. Merry 				if (topo_change->exp_handle)
1395991554f2SKenneth D. Merry 					search_idx += max_num_phy_ids;
1396991554f2SKenneth D. Merry 				map_idx = _mapping_get_free_mt_idx(sc,
1397991554f2SKenneth D. Merry 				    search_idx);
1398991554f2SKenneth D. Merry 			}
1399991554f2SKenneth D. Merry 			if (map_idx == MPR_MAPTABLE_BAD_IDX) {
1400991554f2SKenneth D. Merry 				map_idx = _mapping_get_high_missing_mt_idx(sc);
1401991554f2SKenneth D. Merry 				if (map_idx != MPR_MAPTABLE_BAD_IDX) {
1402991554f2SKenneth D. Merry 					mt_entry = &sc->mapping_table[map_idx];
1403991554f2SKenneth D. Merry 					if (mt_entry->dev_handle) {
1404991554f2SKenneth D. Merry 						_mapping_add_to_removal_table
1405991554f2SKenneth D. Merry 						    (sc, mt_entry->dev_handle,
1406991554f2SKenneth D. Merry 						     0);
1407991554f2SKenneth D. Merry 						is_removed = 1;
1408991554f2SKenneth D. Merry 					}
1409991554f2SKenneth D. Merry 					mt_entry->init_complete = 0;
1410991554f2SKenneth D. Merry 				}
1411991554f2SKenneth D. Merry 			}
1412991554f2SKenneth D. Merry 			if (map_idx != MPR_MAPTABLE_BAD_IDX) {
1413991554f2SKenneth D. Merry 				mt_entry = &sc->mapping_table[map_idx];
1414991554f2SKenneth D. Merry 				mt_entry->physical_id = phy_change->physical_id;
1415991554f2SKenneth D. Merry 				mt_entry->channel = 0;
1416991554f2SKenneth D. Merry 				mt_entry->id = map_idx;
1417991554f2SKenneth D. Merry 				mt_entry->dev_handle = phy_change->dev_handle;
1418991554f2SKenneth D. Merry 				mt_entry->missing_count = 0;
1419991554f2SKenneth D. Merry 				mt_entry->device_info = phy_change->device_info
1420991554f2SKenneth D. Merry 				    | (MPR_DEV_RESERVED | MPR_MAP_IN_USE);
1421991554f2SKenneth D. Merry 			} else {
1422991554f2SKenneth D. Merry 				phy_change->is_processed = 1;
1423991554f2SKenneth D. Merry 				if (!sc->mt_full_retry) {
1424991554f2SKenneth D. Merry 					sc->mt_add_device_failed = 1;
1425991554f2SKenneth D. Merry 					continue;
1426991554f2SKenneth D. Merry 				}
1427*67feec50SStephen McConnell 				mpr_dprint(sc, MPR_INFO, "%s: failed to add "
1428*67feec50SStephen McConnell 				    "the device with handle 0x%04x because "
1429*67feec50SStephen McConnell 				    "there is no free space available in the "
1430*67feec50SStephen McConnell 				    "mapping table\n", __func__,
1431*67feec50SStephen McConnell 				    phy_change->dev_handle);
1432991554f2SKenneth D. Merry 				continue;
1433991554f2SKenneth D. Merry 			}
1434991554f2SKenneth D. Merry 			if (sc->is_dpm_enable) {
1435991554f2SKenneth D. Merry 				if (mt_entry->dpm_entry_num !=
1436991554f2SKenneth D. Merry 				    MPR_DPM_BAD_IDX) {
1437991554f2SKenneth D. Merry 					dpm_idx = mt_entry->dpm_entry_num;
1438991554f2SKenneth D. Merry 					dpm_entry = (Mpi2DriverMap0Entry_t *)
1439991554f2SKenneth D. Merry 					    ((u8 *)sc->dpm_pg0 + hdr_sz);
1440991554f2SKenneth D. Merry 					dpm_entry += dpm_idx;
1441991554f2SKenneth D. Merry 					missing_cnt = dpm_entry->
1442991554f2SKenneth D. Merry 					    MappingInformation &
1443991554f2SKenneth D. Merry 					    MPI2_DRVMAP0_MAPINFO_MISSING_MASK;
1444991554f2SKenneth D. Merry 					temp64_var = dpm_entry->
1445991554f2SKenneth D. Merry 					    PhysicalIdentifier.High;
1446991554f2SKenneth D. Merry 					temp64_var = (temp64_var << 32) |
1447991554f2SKenneth D. Merry 					   dpm_entry->PhysicalIdentifier.Low;
1448991554f2SKenneth D. Merry 					if ((mt_entry->physical_id ==
1449991554f2SKenneth D. Merry 					    temp64_var) && !missing_cnt)
1450991554f2SKenneth D. Merry 						mt_entry->init_complete = 1;
1451991554f2SKenneth D. Merry 				} else {
1452991554f2SKenneth D. Merry 					dpm_idx = _mapping_get_free_dpm_idx(sc);
1453991554f2SKenneth D. Merry 					mt_entry->init_complete = 0;
1454991554f2SKenneth D. Merry 				}
1455991554f2SKenneth D. Merry 				if (dpm_idx != MPR_DPM_BAD_IDX &&
1456991554f2SKenneth D. Merry 				    !mt_entry->init_complete) {
1457991554f2SKenneth D. Merry 					mt_entry->init_complete = 1;
1458991554f2SKenneth D. Merry 					mt_entry->dpm_entry_num = dpm_idx;
1459991554f2SKenneth D. Merry 					dpm_entry = (Mpi2DriverMap0Entry_t *)
1460991554f2SKenneth D. Merry 					    ((u8 *)sc->dpm_pg0 + hdr_sz);
1461991554f2SKenneth D. Merry 					dpm_entry += dpm_idx;
1462991554f2SKenneth D. Merry 					dpm_entry->PhysicalIdentifier.Low =
1463991554f2SKenneth D. Merry 					    (0xFFFFFFFF &
1464991554f2SKenneth D. Merry 					    mt_entry->physical_id);
1465991554f2SKenneth D. Merry 					dpm_entry->PhysicalIdentifier.High =
1466991554f2SKenneth D. Merry 					    (mt_entry->physical_id >> 32);
1467991554f2SKenneth D. Merry 					dpm_entry->DeviceIndex = (U16) map_idx;
1468991554f2SKenneth D. Merry 					dpm_entry->MappingInformation = 0;
1469991554f2SKenneth D. Merry 					dpm_entry->PhysicalBitsMapping = 0;
1470991554f2SKenneth D. Merry 					sc->dpm_entry_used[dpm_idx] = 1;
1471991554f2SKenneth D. Merry 					sc->dpm_flush_entry[dpm_idx] = 1;
1472991554f2SKenneth D. Merry 					phy_change->is_processed = 1;
1473991554f2SKenneth D. Merry 				} else if (dpm_idx == MPR_DPM_BAD_IDX) {
1474991554f2SKenneth D. Merry 					phy_change->is_processed = 1;
1475*67feec50SStephen McConnell 					mpr_dprint(sc, MPR_INFO, "%s: failed "
1476*67feec50SStephen McConnell 					    "to add the device with handle "
1477*67feec50SStephen McConnell 					    "0x%04x to persistent table "
1478*67feec50SStephen McConnell 					    "because there is no free space "
1479991554f2SKenneth D. Merry 					    "available\n", __func__,
1480991554f2SKenneth D. Merry 					    phy_change->dev_handle);
1481991554f2SKenneth D. Merry 				}
1482991554f2SKenneth D. Merry 			}
1483991554f2SKenneth D. Merry 			mt_entry->init_complete = 1;
1484991554f2SKenneth D. Merry 		}
1485991554f2SKenneth D. Merry 
1486991554f2SKenneth D. Merry 		phy_change->is_processed = 1;
1487991554f2SKenneth D. Merry 	}
1488991554f2SKenneth D. Merry 	if (is_removed)
1489991554f2SKenneth D. Merry 		_mapping_clear_removed_entries(sc);
1490991554f2SKenneth D. Merry }
1491991554f2SKenneth D. Merry 
1492991554f2SKenneth D. Merry /**
1493*67feec50SStephen McConnell  * _mapping_add_new_pcie_device -Add the new PCIe device into mapping table
1494*67feec50SStephen McConnell  * @sc: per adapter object
1495*67feec50SStephen McConnell  * @topo_change: Topology change event entry
1496*67feec50SStephen McConnell  *
1497*67feec50SStephen McConnell  * Search through the PCIe topology change event list and update map table,
1498*67feec50SStephen McConnell  * enclosure table and DPM pages for the newly added devices.
1499*67feec50SStephen McConnell  *
1500*67feec50SStephen McConnell  * Returns nothing
1501*67feec50SStephen McConnell  */
1502*67feec50SStephen McConnell static void
1503*67feec50SStephen McConnell _mapping_add_new_pcie_device(struct mpr_softc *sc,
1504*67feec50SStephen McConnell     struct _map_pcie_topology_change *topo_change)
1505*67feec50SStephen McConnell {
1506*67feec50SStephen McConnell 	u8 enc_idx, missing_cnt, is_removed = 0;
1507*67feec50SStephen McConnell 	u16 dpm_idx;
1508*67feec50SStephen McConnell 	u32 search_idx, map_idx;
1509*67feec50SStephen McConnell 	u32 entry;
1510*67feec50SStephen McConnell 	struct dev_mapping_table *mt_entry;
1511*67feec50SStephen McConnell 	struct enc_mapping_table *et_entry;
1512*67feec50SStephen McConnell 	struct _map_port_change *port_change;
1513*67feec50SStephen McConnell 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
1514*67feec50SStephen McConnell 	Mpi2DriverMap0Entry_t *dpm_entry;
1515*67feec50SStephen McConnell 	uint64_t temp64_var;
1516*67feec50SStephen McConnell 	u8 map_shift = MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT;
1517*67feec50SStephen McConnell 	u8 hdr_sz = sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER);
1518*67feec50SStephen McConnell 	u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs);
1519*67feec50SStephen McConnell 
1520*67feec50SStephen McConnell 	for (entry = 0; entry < topo_change->num_entries; entry++) {
1521*67feec50SStephen McConnell 		port_change = &topo_change->port_details[entry];
1522*67feec50SStephen McConnell 		if (port_change->is_processed)
1523*67feec50SStephen McConnell 			continue;
1524*67feec50SStephen McConnell 		if (port_change->reason != MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED ||
1525*67feec50SStephen McConnell 		    !port_change->dev_handle) {
1526*67feec50SStephen McConnell 			port_change->is_processed = 1;
1527*67feec50SStephen McConnell 			continue;
1528*67feec50SStephen McConnell 		}
1529*67feec50SStephen McConnell 		if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
1530*67feec50SStephen McConnell 		    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
1531*67feec50SStephen McConnell 			enc_idx = _mapping_get_enc_idx_from_handle
1532*67feec50SStephen McConnell 			    (sc, topo_change->enc_handle);
1533*67feec50SStephen McConnell 			if (enc_idx == MPR_ENCTABLE_BAD_IDX) {
1534*67feec50SStephen McConnell 				port_change->is_processed = 1;
1535*67feec50SStephen McConnell 				mpr_dprint(sc, MPR_ERROR, "%s: failed to add "
1536*67feec50SStephen McConnell 				    "the device with handle 0x%04x because the "
1537*67feec50SStephen McConnell 				    "enclosure is not in the mapping table\n",
1538*67feec50SStephen McConnell 				    __func__, port_change->dev_handle);
1539*67feec50SStephen McConnell 				continue;
1540*67feec50SStephen McConnell 			}
1541*67feec50SStephen McConnell 			et_entry = &sc->enclosure_table[enc_idx];
1542*67feec50SStephen McConnell 			if (et_entry->start_index == MPR_MAPTABLE_BAD_IDX) {
1543*67feec50SStephen McConnell 				port_change->is_processed = 1;
1544*67feec50SStephen McConnell 				if (!sc->mt_full_retry) {
1545*67feec50SStephen McConnell 					sc->mt_add_device_failed = 1;
1546*67feec50SStephen McConnell 					continue;
1547*67feec50SStephen McConnell 				}
1548*67feec50SStephen McConnell 				mpr_dprint(sc, MPR_INFO, "%s: failed to add "
1549*67feec50SStephen McConnell 				    "the device with handle 0x%04x because "
1550*67feec50SStephen McConnell 				    "there is no free space available in the "
1551*67feec50SStephen McConnell 				    "mapping table\n", __func__,
1552*67feec50SStephen McConnell 				    port_change->dev_handle);
1553*67feec50SStephen McConnell 				continue;
1554*67feec50SStephen McConnell 			}
1555*67feec50SStephen McConnell 			map_idx = et_entry->start_index + port_change->slot -
1556*67feec50SStephen McConnell 			    et_entry->start_slot;
1557*67feec50SStephen McConnell 			mt_entry = &sc->mapping_table[map_idx];
1558*67feec50SStephen McConnell 			mt_entry->physical_id = port_change->physical_id;
1559*67feec50SStephen McConnell 			mt_entry->channel = 0;
1560*67feec50SStephen McConnell 			mt_entry->id = map_idx;
1561*67feec50SStephen McConnell 			mt_entry->dev_handle = port_change->dev_handle;
1562*67feec50SStephen McConnell 			mt_entry->missing_count = 0;
1563*67feec50SStephen McConnell 			mt_entry->dpm_entry_num = et_entry->dpm_entry_num;
1564*67feec50SStephen McConnell 			mt_entry->device_info = port_change->device_info |
1565*67feec50SStephen McConnell 			    (MPR_DEV_RESERVED | MPR_MAP_IN_USE);
1566*67feec50SStephen McConnell 			if (sc->is_dpm_enable) {
1567*67feec50SStephen McConnell 				dpm_idx = et_entry->dpm_entry_num;
1568*67feec50SStephen McConnell 				if (dpm_idx == MPR_DPM_BAD_IDX)
1569*67feec50SStephen McConnell 					dpm_idx = _mapping_get_dpm_idx_from_id
1570*67feec50SStephen McConnell 					    (sc, et_entry->enclosure_id,
1571*67feec50SStephen McConnell 					     et_entry->phy_bits);
1572*67feec50SStephen McConnell 				if (dpm_idx == MPR_DPM_BAD_IDX) {
1573*67feec50SStephen McConnell 					dpm_idx = _mapping_get_free_dpm_idx(sc);
1574*67feec50SStephen McConnell 					if (dpm_idx != MPR_DPM_BAD_IDX) {
1575*67feec50SStephen McConnell 						dpm_entry =
1576*67feec50SStephen McConnell 						    (Mpi2DriverMap0Entry_t *)
1577*67feec50SStephen McConnell 						    ((u8 *) sc->dpm_pg0 +
1578*67feec50SStephen McConnell 						     hdr_sz);
1579*67feec50SStephen McConnell 						dpm_entry += dpm_idx;
1580*67feec50SStephen McConnell 						dpm_entry->
1581*67feec50SStephen McConnell 						    PhysicalIdentifier.Low =
1582*67feec50SStephen McConnell 						    (0xFFFFFFFF &
1583*67feec50SStephen McConnell 						    et_entry->enclosure_id);
1584*67feec50SStephen McConnell 						dpm_entry->
1585*67feec50SStephen McConnell 						    PhysicalIdentifier.High =
1586*67feec50SStephen McConnell 						    ( et_entry->enclosure_id
1587*67feec50SStephen McConnell 						     >> 32);
1588*67feec50SStephen McConnell 						dpm_entry->DeviceIndex =
1589*67feec50SStephen McConnell 						    (U16)et_entry->start_index;
1590*67feec50SStephen McConnell 						dpm_entry->MappingInformation =
1591*67feec50SStephen McConnell 							et_entry->num_slots;
1592*67feec50SStephen McConnell 						dpm_entry->MappingInformation
1593*67feec50SStephen McConnell 						    <<= map_shift;
1594*67feec50SStephen McConnell 						dpm_entry->PhysicalBitsMapping
1595*67feec50SStephen McConnell 						    = et_entry->phy_bits;
1596*67feec50SStephen McConnell 						et_entry->dpm_entry_num =
1597*67feec50SStephen McConnell 						    dpm_idx;
1598*67feec50SStephen McConnell 		/* FIXME Do I need to set the dpm_idxin mt_entry too */
1599*67feec50SStephen McConnell 						sc->dpm_entry_used[dpm_idx] = 1;
1600*67feec50SStephen McConnell 						sc->dpm_flush_entry[dpm_idx] =
1601*67feec50SStephen McConnell 						    1;
1602*67feec50SStephen McConnell 						port_change->is_processed = 1;
1603*67feec50SStephen McConnell 					} else {
1604*67feec50SStephen McConnell 						port_change->is_processed = 1;
1605*67feec50SStephen McConnell 						mpr_dprint(sc, MPR_INFO, "%s: "
1606*67feec50SStephen McConnell 						    "failed to add the device "
1607*67feec50SStephen McConnell 						    "with handle 0x%04x to "
1608*67feec50SStephen McConnell 						    "persistent table because "
1609*67feec50SStephen McConnell 						    "there is no free space "
1610*67feec50SStephen McConnell 						    "available\n", __func__,
1611*67feec50SStephen McConnell 						    port_change->dev_handle);
1612*67feec50SStephen McConnell 					}
1613*67feec50SStephen McConnell 				} else {
1614*67feec50SStephen McConnell 					et_entry->dpm_entry_num = dpm_idx;
1615*67feec50SStephen McConnell 					mt_entry->dpm_entry_num = dpm_idx;
1616*67feec50SStephen McConnell 				}
1617*67feec50SStephen McConnell 			}
1618*67feec50SStephen McConnell 			/* FIXME Why not mt_entry too? */
1619*67feec50SStephen McConnell 			et_entry->init_complete = 1;
1620*67feec50SStephen McConnell 		} else if ((ioc_pg8_flags &
1621*67feec50SStephen McConnell 		    MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
1622*67feec50SStephen McConnell 		    MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
1623*67feec50SStephen McConnell 			map_idx = _mapping_get_mt_idx_from_id
1624*67feec50SStephen McConnell 			    (sc, port_change->physical_id);
1625*67feec50SStephen McConnell 			if (map_idx == MPR_MAPTABLE_BAD_IDX) {
1626*67feec50SStephen McConnell 				search_idx = sc->num_rsvd_entries;
1627*67feec50SStephen McConnell 				if (topo_change->switch_dev_handle)
1628*67feec50SStephen McConnell 					search_idx += max_num_phy_ids;
1629*67feec50SStephen McConnell 				map_idx = _mapping_get_free_mt_idx(sc,
1630*67feec50SStephen McConnell 				    search_idx);
1631*67feec50SStephen McConnell 			}
1632*67feec50SStephen McConnell 			if (map_idx == MPR_MAPTABLE_BAD_IDX) {
1633*67feec50SStephen McConnell 				map_idx = _mapping_get_high_missing_mt_idx(sc);
1634*67feec50SStephen McConnell 				if (map_idx != MPR_MAPTABLE_BAD_IDX) {
1635*67feec50SStephen McConnell 					mt_entry = &sc->mapping_table[map_idx];
1636*67feec50SStephen McConnell 					if (mt_entry->dev_handle) {
1637*67feec50SStephen McConnell 						_mapping_add_to_removal_table
1638*67feec50SStephen McConnell 						    (sc, mt_entry->dev_handle,
1639*67feec50SStephen McConnell 						     0);
1640*67feec50SStephen McConnell 						is_removed = 1;
1641*67feec50SStephen McConnell 					}
1642*67feec50SStephen McConnell 					mt_entry->init_complete = 0;
1643*67feec50SStephen McConnell 				}
1644*67feec50SStephen McConnell 			}
1645*67feec50SStephen McConnell 			if (map_idx != MPR_MAPTABLE_BAD_IDX) {
1646*67feec50SStephen McConnell 				mt_entry = &sc->mapping_table[map_idx];
1647*67feec50SStephen McConnell 				mt_entry->physical_id =
1648*67feec50SStephen McConnell 				    port_change->physical_id;
1649*67feec50SStephen McConnell 				mt_entry->channel = 0;
1650*67feec50SStephen McConnell 				mt_entry->id = map_idx;
1651*67feec50SStephen McConnell 				mt_entry->dev_handle = port_change->dev_handle;
1652*67feec50SStephen McConnell 				mt_entry->missing_count = 0;
1653*67feec50SStephen McConnell 				mt_entry->device_info =
1654*67feec50SStephen McConnell 				    port_change->device_info |
1655*67feec50SStephen McConnell 				    (MPR_DEV_RESERVED | MPR_MAP_IN_USE);
1656*67feec50SStephen McConnell 			} else {
1657*67feec50SStephen McConnell 				port_change->is_processed = 1;
1658*67feec50SStephen McConnell 				if (!sc->mt_full_retry) {
1659*67feec50SStephen McConnell 					sc->mt_add_device_failed = 1;
1660*67feec50SStephen McConnell 					continue;
1661*67feec50SStephen McConnell 				}
1662*67feec50SStephen McConnell 				mpr_dprint(sc, MPR_INFO, "%s: failed to add "
1663*67feec50SStephen McConnell 				    "the device with handle 0x%04x because "
1664*67feec50SStephen McConnell 				    "there is no free space available in the "
1665*67feec50SStephen McConnell 				    "mapping table\n", __func__,
1666*67feec50SStephen McConnell 				    port_change->dev_handle);
1667*67feec50SStephen McConnell 				continue;
1668*67feec50SStephen McConnell 			}
1669*67feec50SStephen McConnell 			if (sc->is_dpm_enable) {
1670*67feec50SStephen McConnell 				if (mt_entry->dpm_entry_num !=
1671*67feec50SStephen McConnell 				    MPR_DPM_BAD_IDX) {
1672*67feec50SStephen McConnell 					dpm_idx = mt_entry->dpm_entry_num;
1673*67feec50SStephen McConnell 					dpm_entry = (Mpi2DriverMap0Entry_t *)
1674*67feec50SStephen McConnell 					    ((u8 *)sc->dpm_pg0 + hdr_sz);
1675*67feec50SStephen McConnell 					dpm_entry += dpm_idx;
1676*67feec50SStephen McConnell 					missing_cnt = dpm_entry->
1677*67feec50SStephen McConnell 					    MappingInformation &
1678*67feec50SStephen McConnell 					    MPI2_DRVMAP0_MAPINFO_MISSING_MASK;
1679*67feec50SStephen McConnell 					temp64_var = dpm_entry->
1680*67feec50SStephen McConnell 					    PhysicalIdentifier.High;
1681*67feec50SStephen McConnell 					temp64_var = (temp64_var << 32) |
1682*67feec50SStephen McConnell 					   dpm_entry->PhysicalIdentifier.Low;
1683*67feec50SStephen McConnell 					if ((mt_entry->physical_id ==
1684*67feec50SStephen McConnell 					    temp64_var) && !missing_cnt)
1685*67feec50SStephen McConnell 						mt_entry->init_complete = 1;
1686*67feec50SStephen McConnell 				} else {
1687*67feec50SStephen McConnell 					dpm_idx = _mapping_get_free_dpm_idx(sc);
1688*67feec50SStephen McConnell 					mt_entry->init_complete = 0;
1689*67feec50SStephen McConnell 				}
1690*67feec50SStephen McConnell 				if (dpm_idx != MPR_DPM_BAD_IDX &&
1691*67feec50SStephen McConnell 				    !mt_entry->init_complete) {
1692*67feec50SStephen McConnell 					mt_entry->init_complete = 1;
1693*67feec50SStephen McConnell 					mt_entry->dpm_entry_num = dpm_idx;
1694*67feec50SStephen McConnell 					dpm_entry = (Mpi2DriverMap0Entry_t *)
1695*67feec50SStephen McConnell 					    ((u8 *)sc->dpm_pg0 + hdr_sz);
1696*67feec50SStephen McConnell 					dpm_entry += dpm_idx;
1697*67feec50SStephen McConnell 					dpm_entry->PhysicalIdentifier.Low =
1698*67feec50SStephen McConnell 					    (0xFFFFFFFF &
1699*67feec50SStephen McConnell 					    mt_entry->physical_id);
1700*67feec50SStephen McConnell 					dpm_entry->PhysicalIdentifier.High =
1701*67feec50SStephen McConnell 					    (mt_entry->physical_id >> 32);
1702*67feec50SStephen McConnell 					dpm_entry->DeviceIndex = (U16) map_idx;
1703*67feec50SStephen McConnell 					dpm_entry->MappingInformation = 0;
1704*67feec50SStephen McConnell 					dpm_entry->PhysicalBitsMapping = 0;
1705*67feec50SStephen McConnell 					sc->dpm_entry_used[dpm_idx] = 1;
1706*67feec50SStephen McConnell 					sc->dpm_flush_entry[dpm_idx] = 1;
1707*67feec50SStephen McConnell 					port_change->is_processed = 1;
1708*67feec50SStephen McConnell 				} else if (dpm_idx == MPR_DPM_BAD_IDX) {
1709*67feec50SStephen McConnell 					port_change->is_processed = 1;
1710*67feec50SStephen McConnell 					mpr_dprint(sc, MPR_INFO, "%s: failed "
1711*67feec50SStephen McConnell 					    "to add the device with handle "
1712*67feec50SStephen McConnell 					    "0x%04x to persistent table "
1713*67feec50SStephen McConnell 					    "because there is no free space "
1714*67feec50SStephen McConnell 					    "available\n", __func__,
1715*67feec50SStephen McConnell 					    port_change->dev_handle);
1716*67feec50SStephen McConnell 				}
1717*67feec50SStephen McConnell 			}
1718*67feec50SStephen McConnell 			mt_entry->init_complete = 1;
1719*67feec50SStephen McConnell 		}
1720*67feec50SStephen McConnell 
1721*67feec50SStephen McConnell 		port_change->is_processed = 1;
1722*67feec50SStephen McConnell 	}
1723*67feec50SStephen McConnell 	if (is_removed)
1724*67feec50SStephen McConnell 		_mapping_clear_removed_entries(sc);
1725*67feec50SStephen McConnell }
1726*67feec50SStephen McConnell 
1727*67feec50SStephen McConnell /**
1728991554f2SKenneth D. Merry  * _mapping_flush_dpm_pages -Flush the DPM pages to NVRAM
1729991554f2SKenneth D. Merry  * @sc: per adapter object
1730991554f2SKenneth D. Merry  *
1731991554f2SKenneth D. Merry  * Returns nothing
1732991554f2SKenneth D. Merry  */
1733991554f2SKenneth D. Merry static void
1734991554f2SKenneth D. Merry _mapping_flush_dpm_pages(struct mpr_softc *sc)
1735991554f2SKenneth D. Merry {
1736991554f2SKenneth D. Merry 	Mpi2DriverMap0Entry_t *dpm_entry;
1737991554f2SKenneth D. Merry 	Mpi2ConfigReply_t mpi_reply;
1738991554f2SKenneth D. Merry 	Mpi2DriverMappingPage0_t config_page;
1739991554f2SKenneth D. Merry 	u16 entry_num;
1740991554f2SKenneth D. Merry 
1741991554f2SKenneth D. Merry 	for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++) {
1742991554f2SKenneth D. Merry 		if (!sc->dpm_flush_entry[entry_num])
1743991554f2SKenneth D. Merry 			continue;
1744991554f2SKenneth D. Merry 		memset(&config_page, 0, sizeof(Mpi2DriverMappingPage0_t));
1745991554f2SKenneth D. Merry 		memcpy(&config_page.Header, (u8 *)sc->dpm_pg0,
1746991554f2SKenneth D. Merry 		    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
1747991554f2SKenneth D. Merry 		dpm_entry = (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 +
1748991554f2SKenneth D. Merry 		    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
1749991554f2SKenneth D. Merry 		dpm_entry += entry_num;
1750991554f2SKenneth D. Merry 		dpm_entry->MappingInformation = htole16(dpm_entry->
1751991554f2SKenneth D. Merry 		    MappingInformation);
1752991554f2SKenneth D. Merry 		dpm_entry->DeviceIndex = htole16(dpm_entry->DeviceIndex);
1753991554f2SKenneth D. Merry 		dpm_entry->PhysicalBitsMapping = htole32(dpm_entry->
1754991554f2SKenneth D. Merry 		    PhysicalBitsMapping);
1755991554f2SKenneth D. Merry 		memcpy(&config_page.Entry, (u8 *)dpm_entry,
1756991554f2SKenneth D. Merry 		    sizeof(Mpi2DriverMap0Entry_t));
1757991554f2SKenneth D. Merry 		/* TODO-How to handle failed writes? */
1758991554f2SKenneth D. Merry 		if (mpr_config_set_dpm_pg0(sc, &mpi_reply, &config_page,
1759991554f2SKenneth D. Merry 		    entry_num)) {
1760991554f2SKenneth D. Merry 			printf("%s: write of dpm entry %d for device failed\n",
1761991554f2SKenneth D. Merry 			     __func__, entry_num);
1762991554f2SKenneth D. Merry 		} else
1763991554f2SKenneth D. Merry 			sc->dpm_flush_entry[entry_num] = 0;
1764991554f2SKenneth D. Merry 		dpm_entry->MappingInformation = le16toh(dpm_entry->
1765991554f2SKenneth D. Merry 		    MappingInformation);
1766991554f2SKenneth D. Merry 		dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
1767991554f2SKenneth D. Merry 		dpm_entry->PhysicalBitsMapping = le32toh(dpm_entry->
1768991554f2SKenneth D. Merry 		    PhysicalBitsMapping);
1769991554f2SKenneth D. Merry 	}
1770991554f2SKenneth D. Merry }
1771991554f2SKenneth D. Merry 
1772991554f2SKenneth D. Merry /**
1773991554f2SKenneth D. Merry  * _mapping_allocate_memory- allocates the memory required for mapping tables
1774991554f2SKenneth D. Merry  * @sc: per adapter object
1775991554f2SKenneth D. Merry  *
1776991554f2SKenneth D. Merry  * Allocates the memory for all the tables required for host mapping
1777991554f2SKenneth D. Merry  *
1778991554f2SKenneth D. Merry  * Return 0 on success or non-zero on failure.
1779991554f2SKenneth D. Merry  */
1780991554f2SKenneth D. Merry int
1781991554f2SKenneth D. Merry mpr_mapping_allocate_memory(struct mpr_softc *sc)
1782991554f2SKenneth D. Merry {
1783991554f2SKenneth D. Merry 	uint32_t dpm_pg0_sz;
1784991554f2SKenneth D. Merry 
1785991554f2SKenneth D. Merry 	sc->mapping_table = malloc((sizeof(struct dev_mapping_table) *
1786991554f2SKenneth D. Merry 	    sc->max_devices), M_MPR, M_ZERO|M_NOWAIT);
1787991554f2SKenneth D. Merry 	if (!sc->mapping_table)
1788991554f2SKenneth D. Merry 		goto free_resources;
1789991554f2SKenneth D. Merry 
1790991554f2SKenneth D. Merry 	sc->removal_table = malloc((sizeof(struct map_removal_table) *
1791991554f2SKenneth D. Merry 	    sc->max_devices), M_MPR, M_ZERO|M_NOWAIT);
1792991554f2SKenneth D. Merry 	if (!sc->removal_table)
1793991554f2SKenneth D. Merry 		goto free_resources;
1794991554f2SKenneth D. Merry 
1795991554f2SKenneth D. Merry 	sc->enclosure_table = malloc((sizeof(struct enc_mapping_table) *
1796991554f2SKenneth D. Merry 	    sc->max_enclosures), M_MPR, M_ZERO|M_NOWAIT);
1797991554f2SKenneth D. Merry 	if (!sc->enclosure_table)
1798991554f2SKenneth D. Merry 		goto free_resources;
1799991554f2SKenneth D. Merry 
1800991554f2SKenneth D. Merry 	sc->dpm_entry_used = malloc((sizeof(u8) * sc->max_dpm_entries),
1801991554f2SKenneth D. Merry 	    M_MPR, M_ZERO|M_NOWAIT);
1802991554f2SKenneth D. Merry 	if (!sc->dpm_entry_used)
1803991554f2SKenneth D. Merry 		goto free_resources;
1804991554f2SKenneth D. Merry 
1805991554f2SKenneth D. Merry 	sc->dpm_flush_entry = malloc((sizeof(u8) * sc->max_dpm_entries),
1806991554f2SKenneth D. Merry 	    M_MPR, M_ZERO|M_NOWAIT);
1807991554f2SKenneth D. Merry 	if (!sc->dpm_flush_entry)
1808991554f2SKenneth D. Merry 		goto free_resources;
1809991554f2SKenneth D. Merry 
1810991554f2SKenneth D. Merry 	dpm_pg0_sz = sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER) +
1811991554f2SKenneth D. Merry 	    (sc->max_dpm_entries * sizeof(MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY));
1812991554f2SKenneth D. Merry 
1813991554f2SKenneth D. Merry 	sc->dpm_pg0 = malloc(dpm_pg0_sz, M_MPR, M_ZERO|M_NOWAIT);
1814991554f2SKenneth D. Merry 	if (!sc->dpm_pg0) {
1815991554f2SKenneth D. Merry 		printf("%s: memory alloc failed for dpm page; disabling dpm\n",
1816991554f2SKenneth D. Merry 		    __func__);
1817991554f2SKenneth D. Merry 		sc->is_dpm_enable = 0;
1818991554f2SKenneth D. Merry 	}
1819991554f2SKenneth D. Merry 
1820991554f2SKenneth D. Merry 	return 0;
1821991554f2SKenneth D. Merry 
1822991554f2SKenneth D. Merry free_resources:
1823991554f2SKenneth D. Merry 	free(sc->mapping_table, M_MPR);
1824991554f2SKenneth D. Merry 	free(sc->removal_table, M_MPR);
1825991554f2SKenneth D. Merry 	free(sc->enclosure_table, M_MPR);
1826991554f2SKenneth D. Merry 	free(sc->dpm_entry_used, M_MPR);
1827991554f2SKenneth D. Merry 	free(sc->dpm_flush_entry, M_MPR);
1828991554f2SKenneth D. Merry 	free(sc->dpm_pg0, M_MPR);
1829991554f2SKenneth D. Merry 	printf("%s: device initialization failed due to failure in mapping "
1830991554f2SKenneth D. Merry 	    "table memory allocation\n", __func__);
1831991554f2SKenneth D. Merry 	return -1;
1832991554f2SKenneth D. Merry }
1833991554f2SKenneth D. Merry 
1834991554f2SKenneth D. Merry /**
1835991554f2SKenneth D. Merry  * mpr_mapping_free_memory- frees the memory allocated for mapping tables
1836991554f2SKenneth D. Merry  * @sc: per adapter object
1837991554f2SKenneth D. Merry  *
1838991554f2SKenneth D. Merry  * Returns nothing.
1839991554f2SKenneth D. Merry  */
1840991554f2SKenneth D. Merry void
1841991554f2SKenneth D. Merry mpr_mapping_free_memory(struct mpr_softc *sc)
1842991554f2SKenneth D. Merry {
1843991554f2SKenneth D. Merry 	free(sc->mapping_table, M_MPR);
1844991554f2SKenneth D. Merry 	free(sc->removal_table, M_MPR);
1845991554f2SKenneth D. Merry 	free(sc->enclosure_table, M_MPR);
1846991554f2SKenneth D. Merry 	free(sc->dpm_entry_used, M_MPR);
1847991554f2SKenneth D. Merry 	free(sc->dpm_flush_entry, M_MPR);
1848991554f2SKenneth D. Merry 	free(sc->dpm_pg0, M_MPR);
1849991554f2SKenneth D. Merry }
1850991554f2SKenneth D. Merry 
1851991554f2SKenneth D. Merry 
1852991554f2SKenneth D. Merry static void
1853991554f2SKenneth D. Merry _mapping_process_dpm_pg0(struct mpr_softc *sc)
1854991554f2SKenneth D. Merry {
1855991554f2SKenneth D. Merry 	u8 missing_cnt, enc_idx;
1856991554f2SKenneth D. Merry 	u16 slot_id, entry_num, num_slots;
1857991554f2SKenneth D. Merry 	u32 map_idx, dev_idx, start_idx, end_idx;
1858991554f2SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
1859991554f2SKenneth D. Merry 	Mpi2DriverMap0Entry_t *dpm_entry;
1860991554f2SKenneth D. Merry 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
1861991554f2SKenneth D. Merry 	u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs);
1862991554f2SKenneth D. Merry 	struct enc_mapping_table *et_entry;
1863991554f2SKenneth D. Merry 	u64 physical_id;
1864991554f2SKenneth D. Merry 	u32 phy_bits = 0;
1865991554f2SKenneth D. Merry 
1866991554f2SKenneth D. Merry 	if (sc->ir_firmware)
1867991554f2SKenneth D. Merry 		_mapping_get_ir_maprange(sc, &start_idx, &end_idx);
1868991554f2SKenneth D. Merry 
1869991554f2SKenneth D. Merry 	dpm_entry = (Mpi2DriverMap0Entry_t *) ((uint8_t *) sc->dpm_pg0 +
1870991554f2SKenneth D. Merry 	    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
1871991554f2SKenneth D. Merry 	for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++,
1872991554f2SKenneth D. Merry 	    dpm_entry++) {
1873991554f2SKenneth D. Merry 		physical_id = dpm_entry->PhysicalIdentifier.High;
1874991554f2SKenneth D. Merry 		physical_id = (physical_id << 32) |
1875991554f2SKenneth D. Merry 		    dpm_entry->PhysicalIdentifier.Low;
1876991554f2SKenneth D. Merry 		if (!physical_id) {
1877991554f2SKenneth D. Merry 			sc->dpm_entry_used[entry_num] = 0;
1878991554f2SKenneth D. Merry 			continue;
1879991554f2SKenneth D. Merry 		}
1880991554f2SKenneth D. Merry 		sc->dpm_entry_used[entry_num] = 1;
1881991554f2SKenneth D. Merry 		dpm_entry->MappingInformation = le16toh(dpm_entry->
1882991554f2SKenneth D. Merry 		    MappingInformation);
1883991554f2SKenneth D. Merry 		missing_cnt = dpm_entry->MappingInformation &
1884991554f2SKenneth D. Merry 		    MPI2_DRVMAP0_MAPINFO_MISSING_MASK;
1885991554f2SKenneth D. Merry 		dev_idx = le16toh(dpm_entry->DeviceIndex);
1886991554f2SKenneth D. Merry 		phy_bits = le32toh(dpm_entry->PhysicalBitsMapping);
1887991554f2SKenneth D. Merry 		if (sc->ir_firmware && (dev_idx >= start_idx) &&
1888991554f2SKenneth D. Merry 		    (dev_idx <= end_idx)) {
1889991554f2SKenneth D. Merry 			mt_entry = &sc->mapping_table[dev_idx];
1890991554f2SKenneth D. Merry 			mt_entry->physical_id = dpm_entry->PhysicalIdentifier.High;
1891991554f2SKenneth D. Merry 			mt_entry->physical_id = (mt_entry->physical_id << 32) |
1892991554f2SKenneth D. Merry 			    dpm_entry->PhysicalIdentifier.Low;
1893991554f2SKenneth D. Merry 			mt_entry->channel = MPR_RAID_CHANNEL;
1894991554f2SKenneth D. Merry 			mt_entry->id = dev_idx;
1895991554f2SKenneth D. Merry 			mt_entry->missing_count = missing_cnt;
1896991554f2SKenneth D. Merry 			mt_entry->dpm_entry_num = entry_num;
1897991554f2SKenneth D. Merry 			mt_entry->device_info = MPR_DEV_RESERVED;
1898991554f2SKenneth D. Merry 			continue;
1899991554f2SKenneth D. Merry 		}
1900991554f2SKenneth D. Merry 		if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
1901991554f2SKenneth D. Merry 		    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
1902991554f2SKenneth D. Merry 			if (dev_idx <  (sc->num_rsvd_entries +
1903991554f2SKenneth D. Merry 			    max_num_phy_ids)) {
1904991554f2SKenneth D. Merry 				slot_id = 0;
1905991554f2SKenneth D. Merry 				if (ioc_pg8_flags &
1906991554f2SKenneth D. Merry 				    MPI2_IOCPAGE8_FLAGS_DA_START_SLOT_1)
1907991554f2SKenneth D. Merry 					slot_id = 1;
1908991554f2SKenneth D. Merry 				num_slots = max_num_phy_ids;
1909991554f2SKenneth D. Merry 			} else {
1910991554f2SKenneth D. Merry 				slot_id = 0;
1911991554f2SKenneth D. Merry 				num_slots = dpm_entry->MappingInformation &
1912991554f2SKenneth D. Merry 				    MPI2_DRVMAP0_MAPINFO_SLOT_MASK;
1913991554f2SKenneth D. Merry 				num_slots >>= MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT;
1914991554f2SKenneth D. Merry 			}
1915991554f2SKenneth D. Merry 			enc_idx = sc->num_enc_table_entries;
1916991554f2SKenneth D. Merry 			if (enc_idx >= sc->max_enclosures) {
1917991554f2SKenneth D. Merry 				printf("%s: enclosure entries exceed max "
1918991554f2SKenneth D. Merry 				    "enclosures of %d\n", __func__,
1919991554f2SKenneth D. Merry 				    sc->max_enclosures);
1920991554f2SKenneth D. Merry 				break;
1921991554f2SKenneth D. Merry 			}
1922991554f2SKenneth D. Merry 			sc->num_enc_table_entries++;
1923991554f2SKenneth D. Merry 			et_entry = &sc->enclosure_table[enc_idx];
1924991554f2SKenneth D. Merry 			physical_id = dpm_entry->PhysicalIdentifier.High;
1925991554f2SKenneth D. Merry 			et_entry->enclosure_id = (physical_id << 32) |
1926991554f2SKenneth D. Merry 			    dpm_entry->PhysicalIdentifier.Low;
1927991554f2SKenneth D. Merry 			et_entry->start_index = dev_idx;
1928991554f2SKenneth D. Merry 			et_entry->dpm_entry_num = entry_num;
1929991554f2SKenneth D. Merry 			et_entry->num_slots = num_slots;
1930991554f2SKenneth D. Merry 			et_entry->start_slot = slot_id;
1931991554f2SKenneth D. Merry 			et_entry->missing_count = missing_cnt;
1932991554f2SKenneth D. Merry 			et_entry->phy_bits = phy_bits;
1933991554f2SKenneth D. Merry 
1934991554f2SKenneth D. Merry 			mt_entry = &sc->mapping_table[dev_idx];
1935991554f2SKenneth D. Merry 			for (map_idx = dev_idx; map_idx < (dev_idx + num_slots);
1936991554f2SKenneth D. Merry 			    map_idx++, mt_entry++) {
1937991554f2SKenneth D. Merry 				if (mt_entry->dpm_entry_num !=
1938991554f2SKenneth D. Merry 				    MPR_DPM_BAD_IDX) {
1939991554f2SKenneth D. Merry 					printf("%s: conflict in mapping table "
1940991554f2SKenneth D. Merry 					    "for enclosure %d\n", __func__,
1941991554f2SKenneth D. Merry 					    enc_idx);
1942991554f2SKenneth D. Merry 					break;
1943991554f2SKenneth D. Merry 				}
1944991554f2SKenneth D. Merry 				physical_id = dpm_entry->PhysicalIdentifier.High;
1945991554f2SKenneth D. Merry 				mt_entry->physical_id = (physical_id << 32) |
1946991554f2SKenneth D. Merry 				    dpm_entry->PhysicalIdentifier.Low;
1947991554f2SKenneth D. Merry 				mt_entry->phy_bits = phy_bits;
1948991554f2SKenneth D. Merry 				mt_entry->channel = 0;
1949991554f2SKenneth D. Merry 				mt_entry->id = dev_idx;
1950991554f2SKenneth D. Merry 				mt_entry->dpm_entry_num = entry_num;
1951991554f2SKenneth D. Merry 				mt_entry->missing_count = missing_cnt;
1952991554f2SKenneth D. Merry 				mt_entry->device_info = MPR_DEV_RESERVED;
1953991554f2SKenneth D. Merry 			}
1954991554f2SKenneth D. Merry 		} else if ((ioc_pg8_flags &
1955991554f2SKenneth D. Merry 		    MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
1956991554f2SKenneth D. Merry 		    MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
1957991554f2SKenneth D. Merry 			map_idx = dev_idx;
1958991554f2SKenneth D. Merry 			mt_entry = &sc->mapping_table[map_idx];
1959991554f2SKenneth D. Merry 			if (mt_entry->dpm_entry_num != MPR_DPM_BAD_IDX) {
1960991554f2SKenneth D. Merry 				printf("%s: conflict in mapping table for "
1961991554f2SKenneth D. Merry 				    "device %d\n", __func__, map_idx);
1962991554f2SKenneth D. Merry 				break;
1963991554f2SKenneth D. Merry 			}
1964991554f2SKenneth D. Merry 			physical_id = dpm_entry->PhysicalIdentifier.High;
1965991554f2SKenneth D. Merry 			mt_entry->physical_id = (physical_id << 32) |
1966991554f2SKenneth D. Merry 			    dpm_entry->PhysicalIdentifier.Low;
1967991554f2SKenneth D. Merry 			mt_entry->phy_bits = phy_bits;
1968991554f2SKenneth D. Merry 			mt_entry->channel = 0;
1969991554f2SKenneth D. Merry 			mt_entry->id = dev_idx;
1970991554f2SKenneth D. Merry 			mt_entry->missing_count = missing_cnt;
1971991554f2SKenneth D. Merry 			mt_entry->dpm_entry_num = entry_num;
1972991554f2SKenneth D. Merry 			mt_entry->device_info = MPR_DEV_RESERVED;
1973991554f2SKenneth D. Merry 		}
1974991554f2SKenneth D. Merry 	} /*close the loop for DPM table */
1975991554f2SKenneth D. Merry }
1976991554f2SKenneth D. Merry 
1977991554f2SKenneth D. Merry /*
1978991554f2SKenneth D. Merry  * mpr_mapping_check_devices - start of the day check for device availabilty
1979991554f2SKenneth D. Merry  * @sc: per adapter object
1980991554f2SKenneth D. Merry  * @sleep_flag: Flag indicating whether this function can sleep or not
1981991554f2SKenneth D. Merry  *
1982991554f2SKenneth D. Merry  * Returns nothing.
1983991554f2SKenneth D. Merry  */
1984991554f2SKenneth D. Merry void
1985991554f2SKenneth D. Merry mpr_mapping_check_devices(struct mpr_softc *sc, int sleep_flag)
1986991554f2SKenneth D. Merry {
1987991554f2SKenneth D. Merry 	u32 i;
1988991554f2SKenneth D. Merry /*	u32 cntdn, i;
1989991554f2SKenneth D. Merry 	u32 timeout = 60;*/
1990991554f2SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
1991991554f2SKenneth D. Merry 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
1992991554f2SKenneth D. Merry 	struct enc_mapping_table *et_entry;
1993991554f2SKenneth D. Merry 	u32 start_idx, end_idx;
1994991554f2SKenneth D. Merry 
1995991554f2SKenneth D. Merry 	/* We need to ucomment this when this function is called
1996991554f2SKenneth D. Merry 	 * from the port enable complete */
1997991554f2SKenneth D. Merry #if 0
1998991554f2SKenneth D. Merry 	sc->track_mapping_events = 0;
1999991554f2SKenneth D. Merry 	cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
2000991554f2SKenneth D. Merry 	do {
2001991554f2SKenneth D. Merry 		if (!sc->pending_map_events)
2002991554f2SKenneth D. Merry 			break;
2003991554f2SKenneth D. Merry 		if (sleep_flag == CAN_SLEEP)
2004991554f2SKenneth D. Merry 			pause("mpr_pause", (hz/1000));/* 1msec sleep */
2005991554f2SKenneth D. Merry 		else
2006991554f2SKenneth D. Merry 			DELAY(500); /* 500 useconds delay */
2007991554f2SKenneth D. Merry 	} while (--cntdn);
2008991554f2SKenneth D. Merry 
2009991554f2SKenneth D. Merry 
2010991554f2SKenneth D. Merry 	if (!cntdn)
2011991554f2SKenneth D. Merry 		printf("%s: there are %d"
2012991554f2SKenneth D. Merry 		    " pending events after %d seconds of delay\n",
2013991554f2SKenneth D. Merry 		    __func__, sc->pending_map_events, timeout);
2014991554f2SKenneth D. Merry #endif
2015991554f2SKenneth D. Merry 	sc->pending_map_events = 0;
2016991554f2SKenneth D. Merry 
2017991554f2SKenneth D. Merry 	if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
2018991554f2SKenneth D. Merry 	    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
2019991554f2SKenneth D. Merry 		et_entry = sc->enclosure_table;
2020991554f2SKenneth D. Merry 		for (i = 0; i < sc->num_enc_table_entries; i++, et_entry++) {
2021991554f2SKenneth D. Merry 			if (!et_entry->init_complete) {
2022991554f2SKenneth D. Merry 				if (et_entry->missing_count <
2023991554f2SKenneth D. Merry 				    MPR_MAX_MISSING_COUNT) {
2024991554f2SKenneth D. Merry 					et_entry->missing_count++;
2025991554f2SKenneth D. Merry 					if (et_entry->dpm_entry_num !=
2026991554f2SKenneth D. Merry 					    MPR_DPM_BAD_IDX)
2027991554f2SKenneth D. Merry 						_mapping_commit_enc_entry(sc,
2028991554f2SKenneth D. Merry 						    et_entry);
2029991554f2SKenneth D. Merry 				}
2030991554f2SKenneth D. Merry 				et_entry->init_complete = 1;
2031991554f2SKenneth D. Merry 			}
2032991554f2SKenneth D. Merry 		}
2033991554f2SKenneth D. Merry 		if (!sc->ir_firmware)
2034991554f2SKenneth D. Merry 			return;
2035991554f2SKenneth D. Merry 		_mapping_get_ir_maprange(sc, &start_idx, &end_idx);
2036991554f2SKenneth D. Merry 		mt_entry = &sc->mapping_table[start_idx];
2037991554f2SKenneth D. Merry 		for (i = start_idx; i < (end_idx + 1); i++, mt_entry++) {
2038991554f2SKenneth D. Merry 			if (mt_entry->device_info & MPR_DEV_RESERVED
2039991554f2SKenneth D. Merry 			    && !mt_entry->physical_id)
2040991554f2SKenneth D. Merry 				mt_entry->init_complete = 1;
2041991554f2SKenneth D. Merry 			else if (mt_entry->device_info & MPR_DEV_RESERVED) {
2042991554f2SKenneth D. Merry 				if (!mt_entry->init_complete) {
2043991554f2SKenneth D. Merry 					if (mt_entry->missing_count <
2044991554f2SKenneth D. Merry 					    MPR_MAX_MISSING_COUNT) {
2045991554f2SKenneth D. Merry 						mt_entry->missing_count++;
2046991554f2SKenneth D. Merry 						if (mt_entry->dpm_entry_num !=
2047991554f2SKenneth D. Merry 						    MPR_DPM_BAD_IDX)
2048991554f2SKenneth D. Merry 						_mapping_commit_map_entry(sc,
2049991554f2SKenneth D. Merry 						    mt_entry);
2050991554f2SKenneth D. Merry 					}
2051991554f2SKenneth D. Merry 					mt_entry->init_complete = 1;
2052991554f2SKenneth D. Merry 				}
2053991554f2SKenneth D. Merry 			}
2054991554f2SKenneth D. Merry 		}
2055991554f2SKenneth D. Merry 	} else if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
2056991554f2SKenneth D. Merry 	    MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
2057991554f2SKenneth D. Merry 		mt_entry = sc->mapping_table;
2058991554f2SKenneth D. Merry 		for (i = 0; i < sc->max_devices; i++, mt_entry++) {
2059991554f2SKenneth D. Merry 			if (mt_entry->device_info & MPR_DEV_RESERVED
2060991554f2SKenneth D. Merry 			    && !mt_entry->physical_id)
2061991554f2SKenneth D. Merry 				mt_entry->init_complete = 1;
2062991554f2SKenneth D. Merry 			else if (mt_entry->device_info & MPR_DEV_RESERVED) {
2063991554f2SKenneth D. Merry 				if (!mt_entry->init_complete) {
2064991554f2SKenneth D. Merry 					if (mt_entry->missing_count <
2065991554f2SKenneth D. Merry 					    MPR_MAX_MISSING_COUNT) {
2066991554f2SKenneth D. Merry 						mt_entry->missing_count++;
2067991554f2SKenneth D. Merry 						if (mt_entry->dpm_entry_num !=
2068991554f2SKenneth D. Merry 						    MPR_DPM_BAD_IDX)
2069991554f2SKenneth D. Merry 						_mapping_commit_map_entry(sc,
2070991554f2SKenneth D. Merry 						    mt_entry);
2071991554f2SKenneth D. Merry 					}
2072991554f2SKenneth D. Merry 					mt_entry->init_complete = 1;
2073991554f2SKenneth D. Merry 				}
2074991554f2SKenneth D. Merry 			}
2075991554f2SKenneth D. Merry 		}
2076991554f2SKenneth D. Merry 	}
2077991554f2SKenneth D. Merry }
2078991554f2SKenneth D. Merry 
2079991554f2SKenneth D. Merry 
2080991554f2SKenneth D. Merry /**
2081991554f2SKenneth D. Merry  * mpr_mapping_is_reinit_required - check whether event replay required
2082991554f2SKenneth D. Merry  * @sc: per adapter object
2083991554f2SKenneth D. Merry  *
2084991554f2SKenneth D. Merry  * Checks the per ioc flags and decide whether reinit of events required
2085991554f2SKenneth D. Merry  *
2086991554f2SKenneth D. Merry  * Returns 1 for reinit of ioc 0 for not.
2087991554f2SKenneth D. Merry  */
2088991554f2SKenneth D. Merry int mpr_mapping_is_reinit_required(struct mpr_softc *sc)
2089991554f2SKenneth D. Merry {
2090991554f2SKenneth D. Merry 	if (!sc->mt_full_retry && sc->mt_add_device_failed) {
2091991554f2SKenneth D. Merry 		sc->mt_full_retry = 1;
2092991554f2SKenneth D. Merry 		sc->mt_add_device_failed = 0;
2093991554f2SKenneth D. Merry 		_mapping_flush_dpm_pages(sc);
2094991554f2SKenneth D. Merry 		return 1;
2095991554f2SKenneth D. Merry 	}
2096991554f2SKenneth D. Merry 	sc->mt_full_retry = 1;
2097991554f2SKenneth D. Merry 	return 0;
2098991554f2SKenneth D. Merry }
2099991554f2SKenneth D. Merry 
2100991554f2SKenneth D. Merry /**
2101991554f2SKenneth D. Merry  * mpr_mapping_initialize - initialize mapping tables
2102991554f2SKenneth D. Merry  * @sc: per adapter object
2103991554f2SKenneth D. Merry  *
2104991554f2SKenneth D. Merry  * Read controller persitant mapping tables into internal data area.
2105991554f2SKenneth D. Merry  *
2106991554f2SKenneth D. Merry  * Return 0 for success or non-zero for failure.
2107991554f2SKenneth D. Merry  */
2108991554f2SKenneth D. Merry int
2109991554f2SKenneth D. Merry mpr_mapping_initialize(struct mpr_softc *sc)
2110991554f2SKenneth D. Merry {
2111991554f2SKenneth D. Merry 	uint16_t volume_mapping_flags, dpm_pg0_sz;
2112991554f2SKenneth D. Merry 	uint32_t i;
2113991554f2SKenneth D. Merry 	Mpi2ConfigReply_t mpi_reply;
2114991554f2SKenneth D. Merry 	int error;
2115991554f2SKenneth D. Merry 	uint8_t retry_count;
2116991554f2SKenneth D. Merry 	uint16_t ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
2117991554f2SKenneth D. Merry 
2118991554f2SKenneth D. Merry 	/* The additional 1 accounts for the virtual enclosure
2119991554f2SKenneth D. Merry 	 * created for the controller
2120991554f2SKenneth D. Merry 	 */
2121991554f2SKenneth D. Merry 	sc->max_enclosures = sc->facts->MaxEnclosures + 1;
2122991554f2SKenneth D. Merry 	sc->max_expanders = sc->facts->MaxSasExpanders;
2123991554f2SKenneth D. Merry 	sc->max_volumes = sc->facts->MaxVolumes;
2124991554f2SKenneth D. Merry 	sc->max_devices = sc->facts->MaxTargets + sc->max_volumes;
2125991554f2SKenneth D. Merry 	sc->pending_map_events = 0;
2126991554f2SKenneth D. Merry 	sc->num_enc_table_entries = 0;
2127991554f2SKenneth D. Merry 	sc->num_rsvd_entries = 0;
2128991554f2SKenneth D. Merry 	sc->num_channels = 1;
2129991554f2SKenneth D. Merry 	sc->max_dpm_entries = sc->ioc_pg8.MaxPersistentEntries;
2130991554f2SKenneth D. Merry 	sc->is_dpm_enable = (sc->max_dpm_entries) ? 1 : 0;
2131991554f2SKenneth D. Merry 	sc->track_mapping_events = 0;
2132991554f2SKenneth D. Merry 
2133991554f2SKenneth D. Merry 	if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_DISABLE_PERSISTENT_MAPPING)
2134991554f2SKenneth D. Merry 		sc->is_dpm_enable = 0;
2135991554f2SKenneth D. Merry 
2136991554f2SKenneth D. Merry 	if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0)
2137991554f2SKenneth D. Merry 		sc->num_rsvd_entries = 1;
2138991554f2SKenneth D. Merry 
2139991554f2SKenneth D. Merry 	volume_mapping_flags = sc->ioc_pg8.IRVolumeMappingFlags &
2140991554f2SKenneth D. Merry 	    MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
2141991554f2SKenneth D. Merry 	if (sc->ir_firmware && (volume_mapping_flags ==
2142991554f2SKenneth D. Merry 	    MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING))
2143991554f2SKenneth D. Merry 		sc->num_rsvd_entries += sc->max_volumes;
2144991554f2SKenneth D. Merry 
2145991554f2SKenneth D. Merry 	error = mpr_mapping_allocate_memory(sc);
2146991554f2SKenneth D. Merry 	if (error)
2147991554f2SKenneth D. Merry 		return (error);
2148991554f2SKenneth D. Merry 
2149991554f2SKenneth D. Merry 	for (i = 0; i < sc->max_devices; i++)
2150991554f2SKenneth D. Merry 		_mapping_clear_map_entry(sc->mapping_table + i);
2151991554f2SKenneth D. Merry 
2152991554f2SKenneth D. Merry 	for (i = 0; i < sc->max_enclosures; i++)
2153991554f2SKenneth D. Merry 		_mapping_clear_enc_entry(sc->enclosure_table + i);
2154991554f2SKenneth D. Merry 
2155991554f2SKenneth D. Merry 	for (i = 0; i < sc->max_devices; i++) {
2156991554f2SKenneth D. Merry 		sc->removal_table[i].dev_handle = 0;
2157991554f2SKenneth D. Merry 		sc->removal_table[i].dpm_entry_num = MPR_DPM_BAD_IDX;
2158991554f2SKenneth D. Merry 	}
2159991554f2SKenneth D. Merry 
2160991554f2SKenneth D. Merry 	memset(sc->dpm_entry_used, 0, sc->max_dpm_entries);
2161991554f2SKenneth D. Merry 	memset(sc->dpm_flush_entry, 0, sc->max_dpm_entries);
2162991554f2SKenneth D. Merry 
2163991554f2SKenneth D. Merry 	if (sc->is_dpm_enable) {
2164991554f2SKenneth D. Merry 		dpm_pg0_sz = sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER) +
2165991554f2SKenneth D. Merry 		    (sc->max_dpm_entries *
2166991554f2SKenneth D. Merry 		     sizeof(MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY));
2167991554f2SKenneth D. Merry 		retry_count = 0;
2168991554f2SKenneth D. Merry 
2169991554f2SKenneth D. Merry retry_read_dpm:
2170991554f2SKenneth D. Merry 		if (mpr_config_get_dpm_pg0(sc, &mpi_reply, sc->dpm_pg0,
2171991554f2SKenneth D. Merry 		    dpm_pg0_sz)) {
2172991554f2SKenneth D. Merry 			printf("%s: dpm page read failed; disabling dpm\n",
2173991554f2SKenneth D. Merry 			    __func__);
2174991554f2SKenneth D. Merry 			if (retry_count < 3) {
2175991554f2SKenneth D. Merry 				retry_count++;
2176991554f2SKenneth D. Merry 				goto retry_read_dpm;
2177991554f2SKenneth D. Merry 			}
2178991554f2SKenneth D. Merry 			sc->is_dpm_enable = 0;
2179991554f2SKenneth D. Merry 		}
2180991554f2SKenneth D. Merry 	}
2181991554f2SKenneth D. Merry 
2182991554f2SKenneth D. Merry 	if (sc->is_dpm_enable)
2183991554f2SKenneth D. Merry 		_mapping_process_dpm_pg0(sc);
2184991554f2SKenneth D. Merry 
2185991554f2SKenneth D. Merry 	sc->track_mapping_events = 1;
2186991554f2SKenneth D. Merry 	return 0;
2187991554f2SKenneth D. Merry }
2188991554f2SKenneth D. Merry 
2189991554f2SKenneth D. Merry /**
2190991554f2SKenneth D. Merry  * mpr_mapping_exit - clear mapping table and associated memory
2191991554f2SKenneth D. Merry  * @sc: per adapter object
2192991554f2SKenneth D. Merry  *
2193991554f2SKenneth D. Merry  * Returns nothing.
2194991554f2SKenneth D. Merry  */
2195991554f2SKenneth D. Merry void
2196991554f2SKenneth D. Merry mpr_mapping_exit(struct mpr_softc *sc)
2197991554f2SKenneth D. Merry {
2198991554f2SKenneth D. Merry 	_mapping_flush_dpm_pages(sc);
2199991554f2SKenneth D. Merry 	mpr_mapping_free_memory(sc);
2200991554f2SKenneth D. Merry }
2201991554f2SKenneth D. Merry 
2202991554f2SKenneth D. Merry /**
2203991554f2SKenneth D. Merry  * mpr_mapping_get_sas_id - assign a target id for sas device
2204991554f2SKenneth D. Merry  * @sc: per adapter object
2205991554f2SKenneth D. Merry  * @sas_address: sas address of the device
2206991554f2SKenneth D. Merry  * @handle: device handle
2207991554f2SKenneth D. Merry  *
2208991554f2SKenneth D. Merry  * Returns valid ID on success or BAD_ID.
2209991554f2SKenneth D. Merry  */
2210991554f2SKenneth D. Merry unsigned int
2211991554f2SKenneth D. Merry mpr_mapping_get_sas_id(struct mpr_softc *sc, uint64_t sas_address, u16 handle)
2212991554f2SKenneth D. Merry {
2213991554f2SKenneth D. Merry 	u32 map_idx;
2214991554f2SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
2215991554f2SKenneth D. Merry 
2216991554f2SKenneth D. Merry 	for (map_idx = 0; map_idx < sc->max_devices; map_idx++) {
2217991554f2SKenneth D. Merry 		mt_entry = &sc->mapping_table[map_idx];
2218991554f2SKenneth D. Merry 		if (mt_entry->dev_handle == handle && mt_entry->physical_id ==
2219991554f2SKenneth D. Merry 		    sas_address)
2220991554f2SKenneth D. Merry 			return mt_entry->id;
2221991554f2SKenneth D. Merry 	}
2222991554f2SKenneth D. Merry 
2223991554f2SKenneth D. Merry 	return MPR_MAP_BAD_ID;
2224991554f2SKenneth D. Merry }
2225991554f2SKenneth D. Merry 
2226991554f2SKenneth D. Merry /**
2227991554f2SKenneth D. Merry  * mpr_mapping_get_sas_id_from_handle - find a target id in mapping table using
2228991554f2SKenneth D. Merry  * only the dev handle.  This is just a wrapper function for the local function
2229991554f2SKenneth D. Merry  * _mapping_get_mt_idx_from_handle.
2230991554f2SKenneth D. Merry  * @sc: per adapter object
2231991554f2SKenneth D. Merry  * @handle: device handle
2232991554f2SKenneth D. Merry  *
2233991554f2SKenneth D. Merry  * Returns valid ID on success or BAD_ID.
2234991554f2SKenneth D. Merry  */
2235991554f2SKenneth D. Merry unsigned int
2236991554f2SKenneth D. Merry mpr_mapping_get_sas_id_from_handle(struct mpr_softc *sc, u16 handle)
2237991554f2SKenneth D. Merry {
2238991554f2SKenneth D. Merry 	return (_mapping_get_mt_idx_from_handle(sc, handle));
2239991554f2SKenneth D. Merry }
2240991554f2SKenneth D. Merry 
2241991554f2SKenneth D. Merry /**
2242991554f2SKenneth D. Merry  * mpr_mapping_get_raid_id - assign a target id for raid device
2243991554f2SKenneth D. Merry  * @sc: per adapter object
2244991554f2SKenneth D. Merry  * @wwid: world wide identifier for raid volume
2245991554f2SKenneth D. Merry  * @handle: device handle
2246991554f2SKenneth D. Merry  *
2247991554f2SKenneth D. Merry  * Returns valid ID on success or BAD_ID.
2248991554f2SKenneth D. Merry  */
2249991554f2SKenneth D. Merry unsigned int
2250991554f2SKenneth D. Merry mpr_mapping_get_raid_id(struct mpr_softc *sc, u64 wwid, u16 handle)
2251991554f2SKenneth D. Merry {
2252991554f2SKenneth D. Merry 	u32 map_idx;
2253991554f2SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
2254991554f2SKenneth D. Merry 
2255991554f2SKenneth D. Merry 	for (map_idx = 0; map_idx < sc->max_devices; map_idx++) {
2256991554f2SKenneth D. Merry 		mt_entry = &sc->mapping_table[map_idx];
2257991554f2SKenneth D. Merry 		if (mt_entry->dev_handle == handle && mt_entry->physical_id ==
2258991554f2SKenneth D. Merry 		    wwid)
2259991554f2SKenneth D. Merry 			return mt_entry->id;
2260991554f2SKenneth D. Merry 	}
2261991554f2SKenneth D. Merry 
2262991554f2SKenneth D. Merry 	return MPR_MAP_BAD_ID;
2263991554f2SKenneth D. Merry }
2264991554f2SKenneth D. Merry 
2265991554f2SKenneth D. Merry /**
2266991554f2SKenneth D. Merry  * mpr_mapping_get_raid_id_from_handle - find raid device in mapping table
2267991554f2SKenneth D. Merry  * using only the volume dev handle.  This is just a wrapper function for the
2268991554f2SKenneth D. Merry  * local function _mapping_get_ir_mt_idx_from_handle.
2269991554f2SKenneth D. Merry  * @sc: per adapter object
2270991554f2SKenneth D. Merry  * @volHandle: volume device handle
2271991554f2SKenneth D. Merry  *
2272991554f2SKenneth D. Merry  * Returns valid ID on success or BAD_ID.
2273991554f2SKenneth D. Merry  */
2274991554f2SKenneth D. Merry unsigned int
2275991554f2SKenneth D. Merry mpr_mapping_get_raid_id_from_handle(struct mpr_softc *sc, u16 volHandle)
2276991554f2SKenneth D. Merry {
2277991554f2SKenneth D. Merry 	return (_mapping_get_ir_mt_idx_from_handle(sc, volHandle));
2278991554f2SKenneth D. Merry }
2279991554f2SKenneth D. Merry 
2280991554f2SKenneth D. Merry /**
2281991554f2SKenneth D. Merry  * mpr_mapping_enclosure_dev_status_change_event - handle enclosure events
2282991554f2SKenneth D. Merry  * @sc: per adapter object
2283991554f2SKenneth D. Merry  * @event_data: event data payload
2284991554f2SKenneth D. Merry  *
2285991554f2SKenneth D. Merry  * Return nothing.
2286991554f2SKenneth D. Merry  */
2287991554f2SKenneth D. Merry void
2288991554f2SKenneth D. Merry mpr_mapping_enclosure_dev_status_change_event(struct mpr_softc *sc,
2289991554f2SKenneth D. Merry     Mpi2EventDataSasEnclDevStatusChange_t *event_data)
2290991554f2SKenneth D. Merry {
2291991554f2SKenneth D. Merry 	u8 enc_idx, missing_count;
2292991554f2SKenneth D. Merry 	struct enc_mapping_table *et_entry;
2293991554f2SKenneth D. Merry 	Mpi2DriverMap0Entry_t *dpm_entry;
2294991554f2SKenneth D. Merry 	u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
2295991554f2SKenneth D. Merry 	u8 map_shift = MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT;
2296991554f2SKenneth D. Merry 	u8 update_phy_bits = 0;
2297991554f2SKenneth D. Merry 	u32 saved_phy_bits;
2298991554f2SKenneth D. Merry 	uint64_t temp64_var;
2299991554f2SKenneth D. Merry 
2300991554f2SKenneth D. Merry 	if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) !=
2301991554f2SKenneth D. Merry 	    MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING)
2302991554f2SKenneth D. Merry 		goto out;
2303991554f2SKenneth D. Merry 
2304991554f2SKenneth D. Merry 	dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
2305991554f2SKenneth D. Merry 	    sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
2306991554f2SKenneth D. Merry 
2307991554f2SKenneth D. Merry 	if (event_data->ReasonCode == MPI2_EVENT_SAS_ENCL_RC_ADDED) {
2308991554f2SKenneth D. Merry 		if (!event_data->NumSlots) {
2309991554f2SKenneth D. Merry 			printf("%s: enclosure with handle = 0x%x reported 0 "
2310991554f2SKenneth D. Merry 			    "slots\n", __func__,
2311991554f2SKenneth D. Merry 			    le16toh(event_data->EnclosureHandle));
2312991554f2SKenneth D. Merry 			goto out;
2313991554f2SKenneth D. Merry 		}
2314991554f2SKenneth D. Merry 		temp64_var = event_data->EnclosureLogicalID.High;
2315991554f2SKenneth D. Merry 		temp64_var = (temp64_var << 32) |
2316991554f2SKenneth D. Merry 		    event_data->EnclosureLogicalID.Low;
2317991554f2SKenneth D. Merry 		enc_idx = _mapping_get_enc_idx_from_id(sc, temp64_var,
2318991554f2SKenneth D. Merry 		    event_data->PhyBits);
2319991554f2SKenneth D. Merry 		if (enc_idx != MPR_ENCTABLE_BAD_IDX) {
2320991554f2SKenneth D. Merry 			et_entry = &sc->enclosure_table[enc_idx];
2321991554f2SKenneth D. Merry 			if (et_entry->init_complete &&
2322991554f2SKenneth D. Merry 			    !et_entry->missing_count) {
2323991554f2SKenneth D. Merry 				printf("%s: enclosure %d is already present "
2324991554f2SKenneth D. Merry 				    "with handle = 0x%x\n",__func__, enc_idx,
2325991554f2SKenneth D. Merry 				    et_entry->enc_handle);
2326991554f2SKenneth D. Merry 				goto out;
2327991554f2SKenneth D. Merry 			}
2328991554f2SKenneth D. Merry 			et_entry->enc_handle = le16toh(event_data->
2329991554f2SKenneth D. Merry 			    EnclosureHandle);
2330991554f2SKenneth D. Merry 			et_entry->start_slot = le16toh(event_data->StartSlot);
2331991554f2SKenneth D. Merry 			saved_phy_bits = et_entry->phy_bits;
2332991554f2SKenneth D. Merry 			et_entry->phy_bits |= le32toh(event_data->PhyBits);
2333991554f2SKenneth D. Merry 			if (saved_phy_bits != et_entry->phy_bits)
2334991554f2SKenneth D. Merry 				update_phy_bits = 1;
2335991554f2SKenneth D. Merry 			if (et_entry->missing_count || update_phy_bits) {
2336991554f2SKenneth D. Merry 				et_entry->missing_count = 0;
2337991554f2SKenneth D. Merry 				if (sc->is_dpm_enable &&
2338991554f2SKenneth D. Merry 				    et_entry->dpm_entry_num !=
2339991554f2SKenneth D. Merry 				    MPR_DPM_BAD_IDX) {
2340991554f2SKenneth D. Merry 					dpm_entry += et_entry->dpm_entry_num;
2341991554f2SKenneth D. Merry 					missing_count =
2342991554f2SKenneth D. Merry 					    (u8)(dpm_entry->MappingInformation &
2343991554f2SKenneth D. Merry 					    MPI2_DRVMAP0_MAPINFO_MISSING_MASK);
2344991554f2SKenneth D. Merry 					if (!et_entry->init_complete && (
2345991554f2SKenneth D. Merry 					    missing_count || update_phy_bits)) {
2346991554f2SKenneth D. Merry 						dpm_entry->MappingInformation
2347991554f2SKenneth D. Merry 						    = et_entry->num_slots;
2348991554f2SKenneth D. Merry 						dpm_entry->MappingInformation
2349991554f2SKenneth D. Merry 						    <<= map_shift;
2350991554f2SKenneth D. Merry 						dpm_entry->PhysicalBitsMapping
2351991554f2SKenneth D. Merry 						    = et_entry->phy_bits;
2352991554f2SKenneth D. Merry 						sc->dpm_flush_entry[et_entry->
2353991554f2SKenneth D. Merry 						    dpm_entry_num] = 1;
2354991554f2SKenneth D. Merry 					}
2355991554f2SKenneth D. Merry 				}
2356991554f2SKenneth D. Merry 			}
2357991554f2SKenneth D. Merry 		} else {
2358991554f2SKenneth D. Merry 			enc_idx = sc->num_enc_table_entries;
2359991554f2SKenneth D. Merry 			if (enc_idx >= sc->max_enclosures) {
2360991554f2SKenneth D. Merry 				printf("%s: enclosure can not be added; "
2361991554f2SKenneth D. Merry 				    "mapping table is full\n", __func__);
2362991554f2SKenneth D. Merry 				goto out;
2363991554f2SKenneth D. Merry 			}
2364991554f2SKenneth D. Merry 			sc->num_enc_table_entries++;
2365991554f2SKenneth D. Merry 			et_entry = &sc->enclosure_table[enc_idx];
2366991554f2SKenneth D. Merry 			et_entry->enc_handle = le16toh(event_data->
2367991554f2SKenneth D. Merry 			    EnclosureHandle);
2368991554f2SKenneth D. Merry 			et_entry->enclosure_id = event_data->
2369991554f2SKenneth D. Merry 			    EnclosureLogicalID.High;
2370991554f2SKenneth D. Merry 			et_entry->enclosure_id = ( et_entry->enclosure_id <<
2371991554f2SKenneth D. Merry 			    32) | event_data->EnclosureLogicalID.Low;
2372991554f2SKenneth D. Merry 			et_entry->start_index = MPR_MAPTABLE_BAD_IDX;
2373991554f2SKenneth D. Merry 			et_entry->dpm_entry_num = MPR_DPM_BAD_IDX;
2374991554f2SKenneth D. Merry 			et_entry->num_slots = le16toh(event_data->NumSlots);
2375991554f2SKenneth D. Merry 			et_entry->start_slot = le16toh(event_data->StartSlot);
2376991554f2SKenneth D. Merry 			et_entry->phy_bits = le32toh(event_data->PhyBits);
2377991554f2SKenneth D. Merry 		}
2378991554f2SKenneth D. Merry 		et_entry->init_complete = 1;
2379991554f2SKenneth D. Merry 	} else if (event_data->ReasonCode ==
2380991554f2SKenneth D. Merry 	    MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING) {
2381991554f2SKenneth D. Merry 		enc_idx = _mapping_get_enc_idx_from_handle(sc,
2382991554f2SKenneth D. Merry 		    le16toh(event_data->EnclosureHandle));
2383991554f2SKenneth D. Merry 		if (enc_idx == MPR_ENCTABLE_BAD_IDX) {
2384991554f2SKenneth D. Merry 			printf("%s: cannot unmap enclosure %d because it has "
2385991554f2SKenneth D. Merry 			    "already been deleted", __func__, enc_idx);
2386991554f2SKenneth D. Merry 			goto out;
2387991554f2SKenneth D. Merry 		}
2388991554f2SKenneth D. Merry 		et_entry = &sc->enclosure_table[enc_idx];
2389991554f2SKenneth D. Merry 		if (!et_entry->init_complete) {
2390991554f2SKenneth D. Merry 			if (et_entry->missing_count < MPR_MAX_MISSING_COUNT)
2391991554f2SKenneth D. Merry 				et_entry->missing_count++;
2392991554f2SKenneth D. Merry 			else
2393991554f2SKenneth D. Merry 				et_entry->init_complete = 1;
2394991554f2SKenneth D. Merry 		}
2395991554f2SKenneth D. Merry 		if (!et_entry->missing_count)
2396991554f2SKenneth D. Merry 			et_entry->missing_count++;
2397991554f2SKenneth D. Merry 		if (sc->is_dpm_enable && !et_entry->init_complete &&
2398991554f2SKenneth D. Merry 		    et_entry->dpm_entry_num != MPR_DPM_BAD_IDX) {
2399991554f2SKenneth D. Merry 			dpm_entry += et_entry->dpm_entry_num;
2400991554f2SKenneth D. Merry 			dpm_entry->MappingInformation = et_entry->num_slots;
2401991554f2SKenneth D. Merry 			dpm_entry->MappingInformation <<= map_shift;
2402991554f2SKenneth D. Merry 			dpm_entry->MappingInformation |=
2403991554f2SKenneth D. Merry 			    et_entry->missing_count;
2404991554f2SKenneth D. Merry 			sc->dpm_flush_entry[et_entry->dpm_entry_num] = 1;
2405991554f2SKenneth D. Merry 		}
2406991554f2SKenneth D. Merry 		et_entry->init_complete = 1;
2407991554f2SKenneth D. Merry 	}
2408991554f2SKenneth D. Merry 
2409991554f2SKenneth D. Merry out:
2410991554f2SKenneth D. Merry 	_mapping_flush_dpm_pages(sc);
2411991554f2SKenneth D. Merry 	if (sc->pending_map_events)
2412991554f2SKenneth D. Merry 		sc->pending_map_events--;
2413991554f2SKenneth D. Merry }
2414991554f2SKenneth D. Merry 
2415991554f2SKenneth D. Merry /**
2416991554f2SKenneth D. Merry  * mpr_mapping_topology_change_event - handle topology change events
2417991554f2SKenneth D. Merry  * @sc: per adapter object
2418991554f2SKenneth D. Merry  * @event_data: event data payload
2419991554f2SKenneth D. Merry  *
2420991554f2SKenneth D. Merry  * Returns nothing.
2421991554f2SKenneth D. Merry  */
2422991554f2SKenneth D. Merry void
2423991554f2SKenneth D. Merry mpr_mapping_topology_change_event(struct mpr_softc *sc,
2424991554f2SKenneth D. Merry     Mpi2EventDataSasTopologyChangeList_t *event_data)
2425991554f2SKenneth D. Merry {
2426991554f2SKenneth D. Merry 	struct _map_topology_change topo_change;
2427991554f2SKenneth D. Merry 	struct _map_phy_change *phy_change;
2428991554f2SKenneth D. Merry 	Mpi2EventSasTopoPhyEntry_t *event_phy_change;
2429991554f2SKenneth D. Merry 	u8 i, num_entries;
2430991554f2SKenneth D. Merry 
2431991554f2SKenneth D. Merry 	topo_change.enc_handle = le16toh(event_data->EnclosureHandle);
2432991554f2SKenneth D. Merry 	topo_change.exp_handle = le16toh(event_data->ExpanderDevHandle);
2433991554f2SKenneth D. Merry 	num_entries = event_data->NumEntries;
2434991554f2SKenneth D. Merry 	topo_change.num_entries = num_entries;
2435991554f2SKenneth D. Merry 	topo_change.start_phy_num = event_data->StartPhyNum;
2436991554f2SKenneth D. Merry 	topo_change.num_phys = event_data->NumPhys;
2437991554f2SKenneth D. Merry 	topo_change.exp_status = event_data->ExpStatus;
2438991554f2SKenneth D. Merry 	event_phy_change = event_data->PHY;
2439991554f2SKenneth D. Merry 	topo_change.phy_details = NULL;
2440991554f2SKenneth D. Merry 
2441991554f2SKenneth D. Merry 	if (!num_entries)
2442991554f2SKenneth D. Merry 		goto out;
2443991554f2SKenneth D. Merry 	phy_change = malloc(sizeof(struct _map_phy_change) * num_entries,
2444991554f2SKenneth D. Merry 	    M_MPR, M_NOWAIT|M_ZERO);
2445991554f2SKenneth D. Merry 	topo_change.phy_details = phy_change;
2446991554f2SKenneth D. Merry 	if (!phy_change)
2447991554f2SKenneth D. Merry 		goto out;
2448991554f2SKenneth D. Merry 	for (i = 0; i < num_entries; i++, event_phy_change++, phy_change++) {
2449991554f2SKenneth D. Merry 		phy_change->dev_handle = le16toh(event_phy_change->
2450991554f2SKenneth D. Merry 		    AttachedDevHandle);
2451991554f2SKenneth D. Merry 		phy_change->reason = event_phy_change->PhyStatus &
2452991554f2SKenneth D. Merry 		    MPI2_EVENT_SAS_TOPO_RC_MASK;
2453991554f2SKenneth D. Merry 	}
2454991554f2SKenneth D. Merry 	_mapping_update_missing_count(sc, &topo_change);
2455991554f2SKenneth D. Merry 	_mapping_get_dev_info(sc, &topo_change);
2456991554f2SKenneth D. Merry 	_mapping_clear_removed_entries(sc);
2457991554f2SKenneth D. Merry 	_mapping_add_new_device(sc, &topo_change);
2458991554f2SKenneth D. Merry 
2459991554f2SKenneth D. Merry out:
2460991554f2SKenneth D. Merry 	free(topo_change.phy_details, M_MPR);
2461991554f2SKenneth D. Merry 	_mapping_flush_dpm_pages(sc);
2462991554f2SKenneth D. Merry 	if (sc->pending_map_events)
2463991554f2SKenneth D. Merry 		sc->pending_map_events--;
2464991554f2SKenneth D. Merry }
2465991554f2SKenneth D. Merry 
2466991554f2SKenneth D. Merry /**
2467*67feec50SStephen McConnell  * mpr_mapping_pcie_topology_change_event - handle PCIe topology change events
2468*67feec50SStephen McConnell  * @sc: per adapter object
2469*67feec50SStephen McConnell  * @event_data: event data payload
2470*67feec50SStephen McConnell  *
2471*67feec50SStephen McConnell  * Returns nothing.
2472*67feec50SStephen McConnell  */
2473*67feec50SStephen McConnell void
2474*67feec50SStephen McConnell mpr_mapping_pcie_topology_change_event(struct mpr_softc *sc,
2475*67feec50SStephen McConnell     Mpi26EventDataPCIeTopologyChangeList_t *event_data)
2476*67feec50SStephen McConnell {
2477*67feec50SStephen McConnell 	struct _map_pcie_topology_change topo_change;
2478*67feec50SStephen McConnell 	struct _map_port_change *port_change;
2479*67feec50SStephen McConnell 	Mpi26EventPCIeTopoPortEntry_t *event_port_change;
2480*67feec50SStephen McConnell 	u8 i, num_entries;
2481*67feec50SStephen McConnell 
2482*67feec50SStephen McConnell 	topo_change.switch_dev_handle = le16toh(event_data->SwitchDevHandle);
2483*67feec50SStephen McConnell 	topo_change.enc_handle = le16toh(event_data->EnclosureHandle);
2484*67feec50SStephen McConnell 	num_entries = event_data->NumEntries;
2485*67feec50SStephen McConnell 	topo_change.num_entries = num_entries;
2486*67feec50SStephen McConnell 	topo_change.start_port_num = event_data->StartPortNum;
2487*67feec50SStephen McConnell 	topo_change.num_ports = event_data->NumPorts;
2488*67feec50SStephen McConnell 	topo_change.switch_status = event_data->SwitchStatus;
2489*67feec50SStephen McConnell 	event_port_change = event_data->PortEntry;
2490*67feec50SStephen McConnell 	topo_change.port_details = NULL;
2491*67feec50SStephen McConnell 
2492*67feec50SStephen McConnell 	if (!num_entries)
2493*67feec50SStephen McConnell 		goto out;
2494*67feec50SStephen McConnell 	port_change = malloc(sizeof(struct _map_port_change) * num_entries,
2495*67feec50SStephen McConnell 	    M_MPR, M_NOWAIT|M_ZERO);
2496*67feec50SStephen McConnell 	topo_change.port_details = port_change;
2497*67feec50SStephen McConnell 	if (!port_change)
2498*67feec50SStephen McConnell 		goto out;
2499*67feec50SStephen McConnell 	for (i = 0; i < num_entries; i++, event_port_change++, port_change++) {
2500*67feec50SStephen McConnell 		port_change->dev_handle = le16toh(event_port_change->
2501*67feec50SStephen McConnell 		    AttachedDevHandle);
2502*67feec50SStephen McConnell 		port_change->reason = event_port_change->PortStatus;
2503*67feec50SStephen McConnell 	}
2504*67feec50SStephen McConnell 	_mapping_update_pcie_missing_count(sc, &topo_change);
2505*67feec50SStephen McConnell 	_mapping_get_pcie_dev_info(sc, &topo_change);
2506*67feec50SStephen McConnell 	_mapping_clear_removed_entries(sc);
2507*67feec50SStephen McConnell 	_mapping_add_new_pcie_device(sc, &topo_change);
2508*67feec50SStephen McConnell 
2509*67feec50SStephen McConnell out:
2510*67feec50SStephen McConnell 	free(topo_change.port_details, M_MPR);
2511*67feec50SStephen McConnell 	_mapping_flush_dpm_pages(sc);
2512*67feec50SStephen McConnell 	if (sc->pending_map_events)
2513*67feec50SStephen McConnell 		sc->pending_map_events--;
2514*67feec50SStephen McConnell }
2515*67feec50SStephen McConnell 
2516*67feec50SStephen McConnell /**
2517991554f2SKenneth D. Merry  * _mapping_check_update_ir_mt_idx - Check and update IR map table index
2518991554f2SKenneth D. Merry  * @sc: per adapter object
2519991554f2SKenneth D. Merry  * @event_data: event data payload
2520991554f2SKenneth D. Merry  * @evt_idx: current event index
2521991554f2SKenneth D. Merry  * @map_idx: current index and the place holder for new map table index
2522991554f2SKenneth D. Merry  * @wwid_table: world wide name for volumes in the element table
2523991554f2SKenneth D. Merry  *
2524991554f2SKenneth D. Merry  * pass through IR events and find whether any events matches and if so
2525991554f2SKenneth D. Merry  * tries to find new index if not returns failure
2526991554f2SKenneth D. Merry  *
2527991554f2SKenneth D. Merry  * Returns 0 on success and 1 on failure
2528991554f2SKenneth D. Merry  */
2529991554f2SKenneth D. Merry static int
2530991554f2SKenneth D. Merry _mapping_check_update_ir_mt_idx(struct mpr_softc *sc,
2531991554f2SKenneth D. Merry     Mpi2EventDataIrConfigChangeList_t *event_data, int evt_idx, u32 *map_idx,
2532991554f2SKenneth D. Merry     u64 *wwid_table)
2533991554f2SKenneth D. Merry {
2534991554f2SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
2535991554f2SKenneth D. Merry 	u32 st_idx, end_idx, mt_idx = *map_idx;
2536991554f2SKenneth D. Merry 	u8 match = 0;
2537991554f2SKenneth D. Merry 	Mpi2EventIrConfigElement_t *element;
2538991554f2SKenneth D. Merry 	u16 element_flags;
2539991554f2SKenneth D. Merry 	int i;
2540991554f2SKenneth D. Merry 
2541991554f2SKenneth D. Merry 	mt_entry = &sc->mapping_table[mt_idx];
2542991554f2SKenneth D. Merry 	_mapping_get_ir_maprange(sc, &st_idx, &end_idx);
2543991554f2SKenneth D. Merry search_again:
2544991554f2SKenneth D. Merry 	match = 0;
2545991554f2SKenneth D. Merry 	for (i = evt_idx + 1; i < event_data->NumElements; i++) {
2546991554f2SKenneth D. Merry 		element = (Mpi2EventIrConfigElement_t *)
2547991554f2SKenneth D. Merry 		    &event_data->ConfigElement[i];
2548991554f2SKenneth D. Merry 		element_flags = le16toh(element->ElementFlags);
2549991554f2SKenneth D. Merry 		if ((element_flags &
2550991554f2SKenneth D. Merry 		    MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK) !=
2551991554f2SKenneth D. Merry 		    MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT)
2552991554f2SKenneth D. Merry 			continue;
2553991554f2SKenneth D. Merry 		if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_ADDED ||
2554991554f2SKenneth D. Merry 		    element->ReasonCode ==
2555991554f2SKenneth D. Merry 		    MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED) {
2556991554f2SKenneth D. Merry 			if (mt_entry->physical_id == wwid_table[i]) {
2557991554f2SKenneth D. Merry 				match = 1;
2558991554f2SKenneth D. Merry 				break;
2559991554f2SKenneth D. Merry 			}
2560991554f2SKenneth D. Merry 		}
2561991554f2SKenneth D. Merry 	}
2562991554f2SKenneth D. Merry 
2563991554f2SKenneth D. Merry 	if (match) {
2564991554f2SKenneth D. Merry 		do {
2565991554f2SKenneth D. Merry 			mt_idx++;
2566991554f2SKenneth D. Merry 			if (mt_idx > end_idx)
2567991554f2SKenneth D. Merry 				return 1;
2568991554f2SKenneth D. Merry 			mt_entry = &sc->mapping_table[mt_idx];
2569991554f2SKenneth D. Merry 		} while (mt_entry->device_info & MPR_MAP_IN_USE);
2570991554f2SKenneth D. Merry 		goto search_again;
2571991554f2SKenneth D. Merry 	}
2572991554f2SKenneth D. Merry 	*map_idx = mt_idx;
2573991554f2SKenneth D. Merry 	return 0;
2574991554f2SKenneth D. Merry }
2575991554f2SKenneth D. Merry 
2576991554f2SKenneth D. Merry /**
2577991554f2SKenneth D. Merry  * mpr_mapping_ir_config_change_event - handle IR config change list events
2578991554f2SKenneth D. Merry  * @sc: per adapter object
2579991554f2SKenneth D. Merry  * @event_data: event data payload
2580991554f2SKenneth D. Merry  *
2581991554f2SKenneth D. Merry  * Returns nothing.
2582991554f2SKenneth D. Merry  */
2583991554f2SKenneth D. Merry void
2584991554f2SKenneth D. Merry mpr_mapping_ir_config_change_event(struct mpr_softc *sc,
2585991554f2SKenneth D. Merry     Mpi2EventDataIrConfigChangeList_t *event_data)
2586991554f2SKenneth D. Merry {
2587991554f2SKenneth D. Merry 	Mpi2EventIrConfigElement_t *element;
2588991554f2SKenneth D. Merry 	int i;
2589991554f2SKenneth D. Merry 	u64 *wwid_table;
2590991554f2SKenneth D. Merry 	u32 map_idx, flags;
2591991554f2SKenneth D. Merry 	struct dev_mapping_table *mt_entry;
2592991554f2SKenneth D. Merry 	u16 element_flags;
2593991554f2SKenneth D. Merry 	u8 log_full_error = 0;
2594991554f2SKenneth D. Merry 
2595991554f2SKenneth D. Merry 	wwid_table = malloc(sizeof(u64) * event_data->NumElements, M_MPR,
2596991554f2SKenneth D. Merry 	    M_NOWAIT | M_ZERO);
2597991554f2SKenneth D. Merry 	if (!wwid_table)
2598991554f2SKenneth D. Merry 		goto out;
2599991554f2SKenneth D. Merry 	element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
2600991554f2SKenneth D. Merry 	flags = le32toh(event_data->Flags);
2601991554f2SKenneth D. Merry 	for (i = 0; i < event_data->NumElements; i++, element++) {
2602991554f2SKenneth D. Merry 		element_flags = le16toh(element->ElementFlags);
2603991554f2SKenneth D. Merry 		if ((element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_ADDED) &&
2604991554f2SKenneth D. Merry 		    (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_REMOVED) &&
2605991554f2SKenneth D. Merry 		    (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE)
2606991554f2SKenneth D. Merry 		    && (element->ReasonCode !=
2607991554f2SKenneth D. Merry 			MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED))
2608991554f2SKenneth D. Merry 			continue;
2609991554f2SKenneth D. Merry 		if ((element_flags &
2610991554f2SKenneth D. Merry 		    MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK) ==
2611991554f2SKenneth D. Merry 		    MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT) {
2612991554f2SKenneth D. Merry 			mpr_config_get_volume_wwid(sc,
2613991554f2SKenneth D. Merry 			    le16toh(element->VolDevHandle), &wwid_table[i]);
2614991554f2SKenneth D. Merry 			map_idx = _mapping_get_ir_mt_idx_from_wwid(sc,
2615991554f2SKenneth D. Merry 			    wwid_table[i]);
2616991554f2SKenneth D. Merry 			if (map_idx != MPR_MAPTABLE_BAD_IDX) {
2617991554f2SKenneth D. Merry 				mt_entry = &sc->mapping_table[map_idx];
2618991554f2SKenneth D. Merry 				mt_entry->device_info |= MPR_MAP_IN_USE;
2619991554f2SKenneth D. Merry 			}
2620991554f2SKenneth D. Merry 		}
2621991554f2SKenneth D. Merry 	}
2622991554f2SKenneth D. Merry 	if (flags == MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG)
2623991554f2SKenneth D. Merry 		goto out;
2624991554f2SKenneth D. Merry 	else {
2625991554f2SKenneth D. Merry 		element = (Mpi2EventIrConfigElement_t *)&event_data->
2626991554f2SKenneth D. Merry 		    ConfigElement[0];
2627991554f2SKenneth D. Merry 		for (i = 0; i < event_data->NumElements; i++, element++) {
2628991554f2SKenneth D. Merry 			if (element->ReasonCode ==
2629991554f2SKenneth D. Merry 			    MPI2_EVENT_IR_CHANGE_RC_ADDED ||
2630991554f2SKenneth D. Merry 			    element->ReasonCode ==
2631991554f2SKenneth D. Merry 			    MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED) {
2632991554f2SKenneth D. Merry 				map_idx = _mapping_get_ir_mt_idx_from_wwid
2633991554f2SKenneth D. Merry 				    (sc, wwid_table[i]);
2634991554f2SKenneth D. Merry 				if (map_idx != MPR_MAPTABLE_BAD_IDX) {
2635991554f2SKenneth D. Merry 					mt_entry = &sc->mapping_table[map_idx];
2636991554f2SKenneth D. Merry 					mt_entry->channel = MPR_RAID_CHANNEL;
2637991554f2SKenneth D. Merry 					mt_entry->id = map_idx;
2638991554f2SKenneth D. Merry 					mt_entry->dev_handle = le16toh
2639991554f2SKenneth D. Merry 					    (element->VolDevHandle);
2640991554f2SKenneth D. Merry 					mt_entry->device_info =
2641991554f2SKenneth D. Merry 					    MPR_DEV_RESERVED | MPR_MAP_IN_USE;
2642991554f2SKenneth D. Merry 					_mapping_update_ir_missing_cnt(sc,
2643991554f2SKenneth D. Merry 					    map_idx, element, wwid_table[i]);
2644991554f2SKenneth D. Merry 					continue;
2645991554f2SKenneth D. Merry 				}
2646991554f2SKenneth D. Merry 				map_idx = _mapping_get_free_ir_mt_idx(sc);
2647991554f2SKenneth D. Merry 				if (map_idx == MPR_MAPTABLE_BAD_IDX)
2648991554f2SKenneth D. Merry 					log_full_error = 1;
2649991554f2SKenneth D. Merry 				else if (i < (event_data->NumElements - 1)) {
2650991554f2SKenneth D. Merry 					log_full_error =
2651991554f2SKenneth D. Merry 					    _mapping_check_update_ir_mt_idx
2652991554f2SKenneth D. Merry 					    (sc, event_data, i, &map_idx,
2653991554f2SKenneth D. Merry 					     wwid_table);
2654991554f2SKenneth D. Merry 				}
2655991554f2SKenneth D. Merry 				if (log_full_error) {
2656991554f2SKenneth D. Merry 					printf("%s: no space to add the RAID "
2657991554f2SKenneth D. Merry 					    "volume with handle 0x%04x in "
2658991554f2SKenneth D. Merry 					    "mapping table\n", __func__, le16toh
2659991554f2SKenneth D. Merry 					    (element->VolDevHandle));
2660991554f2SKenneth D. Merry 					continue;
2661991554f2SKenneth D. Merry 				}
2662991554f2SKenneth D. Merry 				mt_entry = &sc->mapping_table[map_idx];
2663991554f2SKenneth D. Merry 				mt_entry->physical_id = wwid_table[i];
2664991554f2SKenneth D. Merry 				mt_entry->channel = MPR_RAID_CHANNEL;
2665991554f2SKenneth D. Merry 				mt_entry->id = map_idx;
2666991554f2SKenneth D. Merry 				mt_entry->dev_handle = le16toh(element->
2667991554f2SKenneth D. Merry 				    VolDevHandle);
2668991554f2SKenneth D. Merry 				mt_entry->device_info = MPR_DEV_RESERVED |
2669991554f2SKenneth D. Merry 				    MPR_MAP_IN_USE;
2670991554f2SKenneth D. Merry 				mt_entry->init_complete = 0;
2671991554f2SKenneth D. Merry 				_mapping_update_ir_missing_cnt(sc, map_idx,
2672991554f2SKenneth D. Merry 				    element, wwid_table[i]);
2673991554f2SKenneth D. Merry 			} else if (element->ReasonCode ==
2674991554f2SKenneth D. Merry 			    MPI2_EVENT_IR_CHANGE_RC_REMOVED) {
2675991554f2SKenneth D. Merry 				map_idx = _mapping_get_ir_mt_idx_from_wwid(sc,
2676991554f2SKenneth D. Merry 				    wwid_table[i]);
2677991554f2SKenneth D. Merry 				if (map_idx == MPR_MAPTABLE_BAD_IDX) {
2678991554f2SKenneth D. Merry 					printf("%s: failed to remove a volume "
2679991554f2SKenneth D. Merry 					    "because it has already been "
2680991554f2SKenneth D. Merry 					    "removed\n", __func__);
2681991554f2SKenneth D. Merry 					continue;
2682991554f2SKenneth D. Merry 				}
2683991554f2SKenneth D. Merry 				_mapping_update_ir_missing_cnt(sc, map_idx,
2684991554f2SKenneth D. Merry 				    element, wwid_table[i]);
2685991554f2SKenneth D. Merry 			} else if (element->ReasonCode ==
2686991554f2SKenneth D. Merry 			    MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED) {
2687991554f2SKenneth D. Merry 				map_idx = _mapping_get_mt_idx_from_handle(sc,
2688991554f2SKenneth D. Merry 				    le16toh(element->VolDevHandle));
2689991554f2SKenneth D. Merry 				if (map_idx == MPR_MAPTABLE_BAD_IDX) {
2690991554f2SKenneth D. Merry 					printf("%s: failed to remove volume "
2691991554f2SKenneth D. Merry 					    "with handle 0x%04x because it has "
2692991554f2SKenneth D. Merry 					    "already been removed\n", __func__,
2693991554f2SKenneth D. Merry 					    le16toh(element->VolDevHandle));
2694991554f2SKenneth D. Merry 					continue;
2695991554f2SKenneth D. Merry 				}
2696991554f2SKenneth D. Merry 				mt_entry = &sc->mapping_table[map_idx];
2697991554f2SKenneth D. Merry 				_mapping_update_ir_missing_cnt(sc, map_idx,
2698991554f2SKenneth D. Merry 				    element, mt_entry->physical_id);
2699991554f2SKenneth D. Merry 			}
2700991554f2SKenneth D. Merry 		}
2701991554f2SKenneth D. Merry 	}
2702991554f2SKenneth D. Merry 
2703991554f2SKenneth D. Merry out:
2704991554f2SKenneth D. Merry 	_mapping_flush_dpm_pages(sc);
2705991554f2SKenneth D. Merry 	free(wwid_table, M_MPR);
2706991554f2SKenneth D. Merry 	if (sc->pending_map_events)
2707991554f2SKenneth D. Merry 		sc->pending_map_events--;
2708991554f2SKenneth D. Merry }
2709