1991554f2SKenneth D. Merry /*-
2a2c14879SStephen McConnell * Copyright (c) 2011-2015 LSI Corp.
37a2a6a1aSStephen McConnell * Copyright (c) 2013-2016 Avago Technologies
446b23587SKashyap D Desai * Copyright 2000-2020 Broadcom Inc.
5991554f2SKenneth D. Merry * All rights reserved.
6991554f2SKenneth D. Merry *
7991554f2SKenneth D. Merry * Redistribution and use in source and binary forms, with or without
8991554f2SKenneth D. Merry * modification, are permitted provided that the following conditions
9991554f2SKenneth D. Merry * are met:
10991554f2SKenneth D. Merry * 1. Redistributions of source code must retain the above copyright
11991554f2SKenneth D. Merry * notice, this list of conditions and the following disclaimer.
12991554f2SKenneth D. Merry * 2. Redistributions in binary form must reproduce the above copyright
13991554f2SKenneth D. Merry * notice, this list of conditions and the following disclaimer in the
14991554f2SKenneth D. Merry * documentation and/or other materials provided with the distribution.
15991554f2SKenneth D. Merry *
16991554f2SKenneth D. Merry * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17991554f2SKenneth D. Merry * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18991554f2SKenneth D. Merry * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19991554f2SKenneth D. Merry * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20991554f2SKenneth D. Merry * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21991554f2SKenneth D. Merry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22991554f2SKenneth D. Merry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23991554f2SKenneth D. Merry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24991554f2SKenneth D. Merry * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25991554f2SKenneth D. Merry * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26991554f2SKenneth D. Merry * SUCH DAMAGE.
27991554f2SKenneth D. Merry *
2846b23587SKashyap D Desai * Broadcom Inc. (LSI) MPT-Fusion Host Adapter FreeBSD
29991554f2SKenneth D. Merry */
30991554f2SKenneth D. Merry
31991554f2SKenneth D. Merry #include <sys/cdefs.h>
32991554f2SKenneth D. Merry /* TODO Move headers to mprvar */
33991554f2SKenneth D. Merry #include <sys/types.h>
34991554f2SKenneth D. Merry #include <sys/param.h>
35991554f2SKenneth D. Merry #include <sys/lock.h>
36991554f2SKenneth D. Merry #include <sys/mutex.h>
37991554f2SKenneth D. Merry #include <sys/systm.h>
38991554f2SKenneth D. Merry #include <sys/kernel.h>
39991554f2SKenneth D. Merry #include <sys/malloc.h>
40991554f2SKenneth D. Merry #include <sys/kthread.h>
41991554f2SKenneth D. Merry #include <sys/taskqueue.h>
42991554f2SKenneth D. Merry #include <sys/bus.h>
43991554f2SKenneth D. Merry #include <sys/endian.h>
44991554f2SKenneth D. Merry #include <sys/sysctl.h>
45991554f2SKenneth D. Merry #include <sys/eventhandler.h>
46991554f2SKenneth D. Merry #include <sys/uio.h>
47991554f2SKenneth D. Merry #include <machine/bus.h>
48991554f2SKenneth D. Merry #include <machine/resource.h>
49991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_type.h>
50991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2.h>
51991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_ioc.h>
52991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_sas.h>
5367feec50SStephen McConnell #include <dev/mpr/mpi/mpi2_pci.h>
54991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_cnfg.h>
55991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_init.h>
56991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_tool.h>
57991554f2SKenneth D. Merry #include <dev/mpr/mpr_ioctl.h>
58991554f2SKenneth D. Merry #include <dev/mpr/mprvar.h>
59991554f2SKenneth D. Merry #include <dev/mpr/mpr_mapping.h>
60991554f2SKenneth D. Merry
61991554f2SKenneth D. Merry /**
62327f2e6cSStephen McConnell * _mapping_clear_map_entry - Clear a particular mapping entry.
63991554f2SKenneth D. Merry * @map_entry: map table entry
64991554f2SKenneth D. Merry *
65991554f2SKenneth D. Merry * Returns nothing.
66991554f2SKenneth D. Merry */
67991554f2SKenneth D. Merry static inline void
_mapping_clear_map_entry(struct dev_mapping_table * map_entry)68991554f2SKenneth D. Merry _mapping_clear_map_entry(struct dev_mapping_table *map_entry)
69991554f2SKenneth D. Merry {
70991554f2SKenneth D. Merry map_entry->physical_id = 0;
71991554f2SKenneth D. Merry map_entry->device_info = 0;
72991554f2SKenneth D. Merry map_entry->phy_bits = 0;
73991554f2SKenneth D. Merry map_entry->dpm_entry_num = MPR_DPM_BAD_IDX;
74991554f2SKenneth D. Merry map_entry->dev_handle = 0;
75991554f2SKenneth D. Merry map_entry->id = -1;
76991554f2SKenneth D. Merry map_entry->missing_count = 0;
77991554f2SKenneth D. Merry map_entry->init_complete = 0;
78991554f2SKenneth D. Merry map_entry->TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR;
79991554f2SKenneth D. Merry }
80991554f2SKenneth D. Merry
81991554f2SKenneth D. Merry /**
82991554f2SKenneth D. Merry * _mapping_clear_enc_entry - Clear a particular enclosure table entry.
83991554f2SKenneth D. Merry * @enc_entry: enclosure table entry
84991554f2SKenneth D. Merry *
85991554f2SKenneth D. Merry * Returns nothing.
86991554f2SKenneth D. Merry */
87991554f2SKenneth D. Merry static inline void
_mapping_clear_enc_entry(struct enc_mapping_table * enc_entry)88991554f2SKenneth D. Merry _mapping_clear_enc_entry(struct enc_mapping_table *enc_entry)
89991554f2SKenneth D. Merry {
90991554f2SKenneth D. Merry enc_entry->enclosure_id = 0;
91991554f2SKenneth D. Merry enc_entry->start_index = MPR_MAPTABLE_BAD_IDX;
92991554f2SKenneth D. Merry enc_entry->phy_bits = 0;
93991554f2SKenneth D. Merry enc_entry->dpm_entry_num = MPR_DPM_BAD_IDX;
94991554f2SKenneth D. Merry enc_entry->enc_handle = 0;
95991554f2SKenneth D. Merry enc_entry->num_slots = 0;
96991554f2SKenneth D. Merry enc_entry->start_slot = 0;
97991554f2SKenneth D. Merry enc_entry->missing_count = 0;
98991554f2SKenneth D. Merry enc_entry->removal_flag = 0;
99991554f2SKenneth D. Merry enc_entry->skip_search = 0;
100991554f2SKenneth D. Merry enc_entry->init_complete = 0;
101991554f2SKenneth D. Merry }
102991554f2SKenneth D. Merry
103991554f2SKenneth D. Merry /**
104991554f2SKenneth D. Merry * _mapping_commit_enc_entry - write a particular enc entry in DPM page0.
105991554f2SKenneth D. Merry * @sc: per adapter object
106991554f2SKenneth D. Merry * @enc_entry: enclosure table entry
107991554f2SKenneth D. Merry *
108991554f2SKenneth D. Merry * Returns 0 for success, non-zero for failure.
109991554f2SKenneth D. Merry */
110991554f2SKenneth D. Merry static int
_mapping_commit_enc_entry(struct mpr_softc * sc,struct enc_mapping_table * et_entry)111991554f2SKenneth D. Merry _mapping_commit_enc_entry(struct mpr_softc *sc,
112991554f2SKenneth D. Merry struct enc_mapping_table *et_entry)
113991554f2SKenneth D. Merry {
114991554f2SKenneth D. Merry Mpi2DriverMap0Entry_t *dpm_entry;
115991554f2SKenneth D. Merry struct dev_mapping_table *mt_entry;
116991554f2SKenneth D. Merry Mpi2ConfigReply_t mpi_reply;
117991554f2SKenneth D. Merry Mpi2DriverMappingPage0_t config_page;
118991554f2SKenneth D. Merry
119991554f2SKenneth D. Merry if (!sc->is_dpm_enable)
120991554f2SKenneth D. Merry return 0;
121991554f2SKenneth D. Merry
122991554f2SKenneth D. Merry memset(&config_page, 0, sizeof(Mpi2DriverMappingPage0_t));
123991554f2SKenneth D. Merry memcpy(&config_page.Header, (u8 *) sc->dpm_pg0,
124991554f2SKenneth D. Merry sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
125991554f2SKenneth D. Merry dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
126991554f2SKenneth D. Merry sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
127991554f2SKenneth D. Merry dpm_entry += et_entry->dpm_entry_num;
128991554f2SKenneth D. Merry dpm_entry->PhysicalIdentifier.Low =
129991554f2SKenneth D. Merry ( 0xFFFFFFFF & et_entry->enclosure_id);
130991554f2SKenneth D. Merry dpm_entry->PhysicalIdentifier.High =
131991554f2SKenneth D. Merry ( et_entry->enclosure_id >> 32);
132991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[et_entry->start_index];
133991554f2SKenneth D. Merry dpm_entry->DeviceIndex = htole16(mt_entry->id);
134991554f2SKenneth D. Merry dpm_entry->MappingInformation = et_entry->num_slots;
135991554f2SKenneth D. Merry dpm_entry->MappingInformation <<= MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT;
136991554f2SKenneth D. Merry dpm_entry->MappingInformation |= et_entry->missing_count;
137991554f2SKenneth D. Merry dpm_entry->MappingInformation = htole16(dpm_entry->MappingInformation);
138991554f2SKenneth D. Merry dpm_entry->PhysicalBitsMapping = htole32(et_entry->phy_bits);
139991554f2SKenneth D. Merry dpm_entry->Reserved1 = 0;
140991554f2SKenneth D. Merry
141327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Writing DPM entry %d for enclosure.\n",
142327f2e6cSStephen McConnell __func__, et_entry->dpm_entry_num);
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)) {
147327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: Write of DPM "
148327f2e6cSStephen McConnell "entry %d for enclosure failed.\n", __func__,
149327f2e6cSStephen McConnell et_entry->dpm_entry_num);
150991554f2SKenneth D. Merry dpm_entry->MappingInformation = le16toh(dpm_entry->
151991554f2SKenneth D. Merry MappingInformation);
152991554f2SKenneth D. Merry dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
153991554f2SKenneth D. Merry dpm_entry->PhysicalBitsMapping =
154991554f2SKenneth D. Merry le32toh(dpm_entry->PhysicalBitsMapping);
155991554f2SKenneth D. Merry return -1;
156991554f2SKenneth D. Merry }
157991554f2SKenneth D. Merry dpm_entry->MappingInformation = le16toh(dpm_entry->
158991554f2SKenneth D. Merry MappingInformation);
159991554f2SKenneth D. Merry dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
160991554f2SKenneth D. Merry dpm_entry->PhysicalBitsMapping =
161991554f2SKenneth D. Merry le32toh(dpm_entry->PhysicalBitsMapping);
162991554f2SKenneth D. Merry return 0;
163991554f2SKenneth D. Merry }
164991554f2SKenneth D. Merry
165991554f2SKenneth D. Merry /**
166991554f2SKenneth D. Merry * _mapping_commit_map_entry - write a particular map table entry in DPM page0.
167991554f2SKenneth D. Merry * @sc: per adapter object
168327f2e6cSStephen McConnell * @mt_entry: mapping table entry
169991554f2SKenneth D. Merry *
170991554f2SKenneth D. Merry * Returns 0 for success, non-zero for failure.
171991554f2SKenneth D. Merry */
172991554f2SKenneth D. Merry
173991554f2SKenneth D. Merry static int
_mapping_commit_map_entry(struct mpr_softc * sc,struct dev_mapping_table * mt_entry)174991554f2SKenneth D. Merry _mapping_commit_map_entry(struct mpr_softc *sc,
175991554f2SKenneth D. Merry struct dev_mapping_table *mt_entry)
176991554f2SKenneth D. Merry {
177991554f2SKenneth D. Merry Mpi2DriverMap0Entry_t *dpm_entry;
178991554f2SKenneth D. Merry Mpi2ConfigReply_t mpi_reply;
179991554f2SKenneth D. Merry Mpi2DriverMappingPage0_t config_page;
180991554f2SKenneth D. Merry
181991554f2SKenneth D. Merry if (!sc->is_dpm_enable)
182991554f2SKenneth D. Merry return 0;
183991554f2SKenneth D. Merry
184327f2e6cSStephen McConnell /*
185327f2e6cSStephen McConnell * It's possible that this Map Entry points to a BAD DPM index. This
186327f2e6cSStephen McConnell * can happen if the Map Entry is a for a missing device and the DPM
187327f2e6cSStephen McConnell * entry that was being used by this device is now being used by some
188327f2e6cSStephen McConnell * new device. So, check for a BAD DPM index and just return if so.
189327f2e6cSStephen McConnell */
190327f2e6cSStephen McConnell if (mt_entry->dpm_entry_num == MPR_DPM_BAD_IDX) {
191327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: DPM entry location for target "
192327f2e6cSStephen McConnell "%d is invalid. DPM will not be written.\n", __func__,
193327f2e6cSStephen McConnell mt_entry->id);
194327f2e6cSStephen McConnell return 0;
195327f2e6cSStephen McConnell }
196327f2e6cSStephen McConnell
197991554f2SKenneth D. Merry memset(&config_page, 0, sizeof(Mpi2DriverMappingPage0_t));
198991554f2SKenneth D. Merry memcpy(&config_page.Header, (u8 *)sc->dpm_pg0,
199991554f2SKenneth D. Merry sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
200991554f2SKenneth D. Merry dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *) sc->dpm_pg0 +
201991554f2SKenneth D. Merry sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
202991554f2SKenneth D. Merry dpm_entry = dpm_entry + mt_entry->dpm_entry_num;
203991554f2SKenneth D. Merry dpm_entry->PhysicalIdentifier.Low = (0xFFFFFFFF &
204991554f2SKenneth D. Merry mt_entry->physical_id);
205991554f2SKenneth D. Merry dpm_entry->PhysicalIdentifier.High = (mt_entry->physical_id >> 32);
206991554f2SKenneth D. Merry dpm_entry->DeviceIndex = htole16(mt_entry->id);
207991554f2SKenneth D. Merry dpm_entry->MappingInformation = htole16(mt_entry->missing_count);
208991554f2SKenneth D. Merry dpm_entry->PhysicalBitsMapping = 0;
209991554f2SKenneth D. Merry dpm_entry->Reserved1 = 0;
210991554f2SKenneth D. Merry memcpy(&config_page.Entry, (u8 *)dpm_entry,
211991554f2SKenneth D. Merry sizeof(Mpi2DriverMap0Entry_t));
212327f2e6cSStephen McConnell
213327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Writing DPM entry %d for target %d.\n",
214327f2e6cSStephen McConnell __func__, mt_entry->dpm_entry_num, mt_entry->id);
215991554f2SKenneth D. Merry if (mpr_config_set_dpm_pg0(sc, &mpi_reply, &config_page,
216991554f2SKenneth D. Merry mt_entry->dpm_entry_num)) {
217327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: Write of DPM "
218327f2e6cSStephen McConnell "entry %d for target %d failed.\n", __func__,
219327f2e6cSStephen McConnell mt_entry->dpm_entry_num, mt_entry->id);
220991554f2SKenneth D. Merry dpm_entry->MappingInformation = le16toh(dpm_entry->
221991554f2SKenneth D. Merry MappingInformation);
222991554f2SKenneth D. Merry dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
223991554f2SKenneth D. Merry return -1;
224991554f2SKenneth D. Merry }
225991554f2SKenneth D. Merry
226991554f2SKenneth D. Merry dpm_entry->MappingInformation = le16toh(dpm_entry->MappingInformation);
227991554f2SKenneth D. Merry dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
228991554f2SKenneth D. Merry return 0;
229991554f2SKenneth D. Merry }
230991554f2SKenneth D. Merry
231991554f2SKenneth D. Merry /**
232991554f2SKenneth D. Merry * _mapping_get_ir_maprange - get start and end index for IR map range.
233991554f2SKenneth D. Merry * @sc: per adapter object
234991554f2SKenneth D. Merry * @start_idx: place holder for start index
235991554f2SKenneth D. Merry * @end_idx: place holder for end index
236991554f2SKenneth D. Merry *
237991554f2SKenneth D. Merry * The IR volumes can be mapped either at start or end of the mapping table
238991554f2SKenneth D. Merry * this function gets the detail of where IR volume mapping starts and ends
239991554f2SKenneth D. Merry * in the device mapping table
240991554f2SKenneth D. Merry *
241991554f2SKenneth D. Merry * Returns nothing.
242991554f2SKenneth D. Merry */
243991554f2SKenneth D. Merry static void
_mapping_get_ir_maprange(struct mpr_softc * sc,u32 * start_idx,u32 * end_idx)244991554f2SKenneth D. Merry _mapping_get_ir_maprange(struct mpr_softc *sc, u32 *start_idx, u32 *end_idx)
245991554f2SKenneth D. Merry {
246991554f2SKenneth D. Merry u16 volume_mapping_flags;
247991554f2SKenneth D. Merry u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
248991554f2SKenneth D. Merry
249991554f2SKenneth D. Merry volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) &
250991554f2SKenneth D. Merry MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
251991554f2SKenneth D. Merry if (volume_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) {
252991554f2SKenneth D. Merry *start_idx = 0;
253991554f2SKenneth D. Merry if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0)
254991554f2SKenneth D. Merry *start_idx = 1;
255991554f2SKenneth D. Merry } else
256991554f2SKenneth D. Merry *start_idx = sc->max_devices - sc->max_volumes;
257991554f2SKenneth D. Merry *end_idx = *start_idx + sc->max_volumes - 1;
258991554f2SKenneth D. Merry }
259991554f2SKenneth D. Merry
260991554f2SKenneth D. Merry /**
261991554f2SKenneth D. Merry * _mapping_get_enc_idx_from_id - get enclosure index from enclosure ID
262991554f2SKenneth D. Merry * @sc: per adapter object
263991554f2SKenneth D. Merry * @enc_id: enclosure logical identifier
264991554f2SKenneth D. Merry *
265991554f2SKenneth D. Merry * Returns the index of enclosure entry on success or bad index.
266991554f2SKenneth D. Merry */
267991554f2SKenneth D. Merry static u8
_mapping_get_enc_idx_from_id(struct mpr_softc * sc,u64 enc_id,u64 phy_bits)268991554f2SKenneth D. Merry _mapping_get_enc_idx_from_id(struct mpr_softc *sc, u64 enc_id,
269991554f2SKenneth D. Merry u64 phy_bits)
270991554f2SKenneth D. Merry {
271991554f2SKenneth D. Merry struct enc_mapping_table *et_entry;
272991554f2SKenneth D. Merry u8 enc_idx = 0;
273991554f2SKenneth D. Merry
274991554f2SKenneth D. Merry for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; enc_idx++) {
275991554f2SKenneth D. Merry et_entry = &sc->enclosure_table[enc_idx];
276991554f2SKenneth D. Merry if ((et_entry->enclosure_id == le64toh(enc_id)) &&
277991554f2SKenneth D. Merry (!et_entry->phy_bits || (et_entry->phy_bits &
278991554f2SKenneth D. Merry le32toh(phy_bits))))
279991554f2SKenneth D. Merry return enc_idx;
280991554f2SKenneth D. Merry }
281991554f2SKenneth D. Merry return MPR_ENCTABLE_BAD_IDX;
282991554f2SKenneth D. Merry }
283991554f2SKenneth D. Merry
284991554f2SKenneth D. Merry /**
285991554f2SKenneth D. Merry * _mapping_get_enc_idx_from_handle - get enclosure index from handle
286991554f2SKenneth D. Merry * @sc: per adapter object
287991554f2SKenneth D. Merry * @enc_id: enclosure handle
288991554f2SKenneth D. Merry *
289991554f2SKenneth D. Merry * Returns the index of enclosure entry on success or bad index.
290991554f2SKenneth D. Merry */
291991554f2SKenneth D. Merry static u8
_mapping_get_enc_idx_from_handle(struct mpr_softc * sc,u16 handle)292991554f2SKenneth D. Merry _mapping_get_enc_idx_from_handle(struct mpr_softc *sc, u16 handle)
293991554f2SKenneth D. Merry {
294991554f2SKenneth D. Merry struct enc_mapping_table *et_entry;
295991554f2SKenneth D. Merry u8 enc_idx = 0;
296991554f2SKenneth D. Merry
297991554f2SKenneth D. Merry for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; enc_idx++) {
298991554f2SKenneth D. Merry et_entry = &sc->enclosure_table[enc_idx];
299991554f2SKenneth D. Merry if (et_entry->missing_count)
300991554f2SKenneth D. Merry continue;
301991554f2SKenneth D. Merry if (et_entry->enc_handle == handle)
302991554f2SKenneth D. Merry return enc_idx;
303991554f2SKenneth D. Merry }
304991554f2SKenneth D. Merry return MPR_ENCTABLE_BAD_IDX;
305991554f2SKenneth D. Merry }
306991554f2SKenneth D. Merry
307991554f2SKenneth D. Merry /**
308991554f2SKenneth D. Merry * _mapping_get_high_missing_et_idx - get missing enclosure index
309991554f2SKenneth D. Merry * @sc: per adapter object
310991554f2SKenneth D. Merry *
311991554f2SKenneth D. Merry * Search through the enclosure table and identifies the enclosure entry
312991554f2SKenneth D. Merry * with high missing count and returns it's index
313991554f2SKenneth D. Merry *
314991554f2SKenneth D. Merry * Returns the index of enclosure entry on success or bad index.
315991554f2SKenneth D. Merry */
316991554f2SKenneth D. Merry static u8
_mapping_get_high_missing_et_idx(struct mpr_softc * sc)317991554f2SKenneth D. Merry _mapping_get_high_missing_et_idx(struct mpr_softc *sc)
318991554f2SKenneth D. Merry {
319991554f2SKenneth D. Merry struct enc_mapping_table *et_entry;
320991554f2SKenneth D. Merry u8 high_missing_count = 0;
321991554f2SKenneth D. Merry u8 enc_idx, high_idx = MPR_ENCTABLE_BAD_IDX;
322991554f2SKenneth D. Merry
323991554f2SKenneth D. Merry for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; enc_idx++) {
324991554f2SKenneth D. Merry et_entry = &sc->enclosure_table[enc_idx];
325991554f2SKenneth D. Merry if ((et_entry->missing_count > high_missing_count) &&
326991554f2SKenneth D. Merry !et_entry->skip_search) {
327991554f2SKenneth D. Merry high_missing_count = et_entry->missing_count;
328991554f2SKenneth D. Merry high_idx = enc_idx;
329991554f2SKenneth D. Merry }
330991554f2SKenneth D. Merry }
331991554f2SKenneth D. Merry return high_idx;
332991554f2SKenneth D. Merry }
333991554f2SKenneth D. Merry
334991554f2SKenneth D. Merry /**
335991554f2SKenneth D. Merry * _mapping_get_high_missing_mt_idx - get missing map table index
336991554f2SKenneth D. Merry * @sc: per adapter object
337991554f2SKenneth D. Merry *
338991554f2SKenneth D. Merry * Search through the map table and identifies the device entry
339991554f2SKenneth D. Merry * with high missing count and returns it's index
340991554f2SKenneth D. Merry *
341991554f2SKenneth D. Merry * Returns the index of map table entry on success or bad index.
342991554f2SKenneth D. Merry */
343991554f2SKenneth D. Merry static u32
_mapping_get_high_missing_mt_idx(struct mpr_softc * sc)344991554f2SKenneth D. Merry _mapping_get_high_missing_mt_idx(struct mpr_softc *sc)
345991554f2SKenneth D. Merry {
346327f2e6cSStephen McConnell u32 map_idx, high_idx = MPR_MAPTABLE_BAD_IDX;
347991554f2SKenneth D. Merry u8 high_missing_count = 0;
348a2c14879SStephen McConnell u32 start_idx, end_idx, start_idx_ir, end_idx_ir;
349991554f2SKenneth D. Merry struct dev_mapping_table *mt_entry;
350991554f2SKenneth D. Merry u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
351991554f2SKenneth D. Merry
352991554f2SKenneth D. Merry start_idx = 0;
353a2c14879SStephen McConnell start_idx_ir = 0;
354a2c14879SStephen McConnell end_idx_ir = 0;
355991554f2SKenneth D. Merry end_idx = sc->max_devices;
356991554f2SKenneth D. Merry if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0)
357991554f2SKenneth D. Merry start_idx = 1;
358991554f2SKenneth D. Merry if (sc->ir_firmware) {
359991554f2SKenneth D. Merry _mapping_get_ir_maprange(sc, &start_idx_ir, &end_idx_ir);
360991554f2SKenneth D. Merry if (start_idx == start_idx_ir)
361991554f2SKenneth D. Merry start_idx = end_idx_ir + 1;
362991554f2SKenneth D. Merry else
363991554f2SKenneth D. Merry end_idx = start_idx_ir;
364991554f2SKenneth D. Merry }
365991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[start_idx];
366991554f2SKenneth D. Merry for (map_idx = start_idx; map_idx < end_idx; map_idx++, mt_entry++) {
367991554f2SKenneth D. Merry if (mt_entry->missing_count > high_missing_count) {
368991554f2SKenneth D. Merry high_missing_count = mt_entry->missing_count;
369991554f2SKenneth D. Merry high_idx = map_idx;
370991554f2SKenneth D. Merry }
371991554f2SKenneth D. Merry }
372991554f2SKenneth D. Merry return high_idx;
373991554f2SKenneth D. Merry }
374991554f2SKenneth D. Merry
375991554f2SKenneth D. Merry /**
376991554f2SKenneth D. Merry * _mapping_get_ir_mt_idx_from_wwid - get map table index from volume WWID
377991554f2SKenneth D. Merry * @sc: per adapter object
378991554f2SKenneth D. Merry * @wwid: world wide unique ID of the volume
379991554f2SKenneth D. Merry *
380991554f2SKenneth D. Merry * Returns the index of map table entry on success or bad index.
381991554f2SKenneth D. Merry */
382991554f2SKenneth D. Merry static u32
_mapping_get_ir_mt_idx_from_wwid(struct mpr_softc * sc,u64 wwid)383991554f2SKenneth D. Merry _mapping_get_ir_mt_idx_from_wwid(struct mpr_softc *sc, u64 wwid)
384991554f2SKenneth D. Merry {
385991554f2SKenneth D. Merry u32 start_idx, end_idx, map_idx;
386991554f2SKenneth D. Merry struct dev_mapping_table *mt_entry;
387991554f2SKenneth D. Merry
388991554f2SKenneth D. Merry _mapping_get_ir_maprange(sc, &start_idx, &end_idx);
389991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[start_idx];
390991554f2SKenneth D. Merry for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++)
391991554f2SKenneth D. Merry if (mt_entry->physical_id == wwid)
392991554f2SKenneth D. Merry return map_idx;
393991554f2SKenneth D. Merry
394991554f2SKenneth D. Merry return MPR_MAPTABLE_BAD_IDX;
395991554f2SKenneth D. Merry }
396991554f2SKenneth D. Merry
397991554f2SKenneth D. Merry /**
398991554f2SKenneth D. Merry * _mapping_get_mt_idx_from_id - get map table index from a device ID
399991554f2SKenneth D. Merry * @sc: per adapter object
400991554f2SKenneth D. Merry * @dev_id: device identifer (SAS Address)
401991554f2SKenneth D. Merry *
402991554f2SKenneth D. Merry * Returns the index of map table entry on success or bad index.
403991554f2SKenneth D. Merry */
404991554f2SKenneth D. Merry static u32
_mapping_get_mt_idx_from_id(struct mpr_softc * sc,u64 dev_id)405991554f2SKenneth D. Merry _mapping_get_mt_idx_from_id(struct mpr_softc *sc, u64 dev_id)
406991554f2SKenneth D. Merry {
407991554f2SKenneth D. Merry u32 map_idx;
408991554f2SKenneth D. Merry struct dev_mapping_table *mt_entry;
409991554f2SKenneth D. Merry
410991554f2SKenneth D. Merry for (map_idx = 0; map_idx < sc->max_devices; map_idx++) {
411991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[map_idx];
412991554f2SKenneth D. Merry if (mt_entry->physical_id == dev_id)
413991554f2SKenneth D. Merry return map_idx;
414991554f2SKenneth D. Merry }
415991554f2SKenneth D. Merry return MPR_MAPTABLE_BAD_IDX;
416991554f2SKenneth D. Merry }
417991554f2SKenneth D. Merry
418991554f2SKenneth D. Merry /**
419991554f2SKenneth D. Merry * _mapping_get_ir_mt_idx_from_handle - get map table index from volume handle
420991554f2SKenneth D. Merry * @sc: per adapter object
421991554f2SKenneth D. Merry * @wwid: volume device handle
422991554f2SKenneth D. Merry *
423991554f2SKenneth D. Merry * Returns the index of map table entry on success or bad index.
424991554f2SKenneth D. Merry */
425991554f2SKenneth D. Merry static u32
_mapping_get_ir_mt_idx_from_handle(struct mpr_softc * sc,u16 volHandle)426991554f2SKenneth D. Merry _mapping_get_ir_mt_idx_from_handle(struct mpr_softc *sc, u16 volHandle)
427991554f2SKenneth D. Merry {
428991554f2SKenneth D. Merry u32 start_idx, end_idx, map_idx;
429991554f2SKenneth D. Merry struct dev_mapping_table *mt_entry;
430991554f2SKenneth D. Merry
431991554f2SKenneth D. Merry _mapping_get_ir_maprange(sc, &start_idx, &end_idx);
432991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[start_idx];
433991554f2SKenneth D. Merry for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++)
434991554f2SKenneth D. Merry if (mt_entry->dev_handle == volHandle)
435991554f2SKenneth D. Merry return map_idx;
436991554f2SKenneth D. Merry
437991554f2SKenneth D. Merry return MPR_MAPTABLE_BAD_IDX;
438991554f2SKenneth D. Merry }
439991554f2SKenneth D. Merry
440991554f2SKenneth D. Merry /**
441991554f2SKenneth D. Merry * _mapping_get_mt_idx_from_handle - get map table index from handle
442991554f2SKenneth D. Merry * @sc: per adapter object
443991554f2SKenneth D. Merry * @dev_id: device handle
444991554f2SKenneth D. Merry *
445991554f2SKenneth D. Merry * Returns the index of map table entry on success or bad index.
446991554f2SKenneth D. Merry */
447991554f2SKenneth D. Merry static u32
_mapping_get_mt_idx_from_handle(struct mpr_softc * sc,u16 handle)448991554f2SKenneth D. Merry _mapping_get_mt_idx_from_handle(struct mpr_softc *sc, u16 handle)
449991554f2SKenneth D. Merry {
450991554f2SKenneth D. Merry u32 map_idx;
451991554f2SKenneth D. Merry struct dev_mapping_table *mt_entry;
452991554f2SKenneth D. Merry
453991554f2SKenneth D. Merry for (map_idx = 0; map_idx < sc->max_devices; map_idx++) {
454991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[map_idx];
455991554f2SKenneth D. Merry if (mt_entry->dev_handle == handle)
456991554f2SKenneth D. Merry return map_idx;
457991554f2SKenneth D. Merry }
458991554f2SKenneth D. Merry return MPR_MAPTABLE_BAD_IDX;
459991554f2SKenneth D. Merry }
460991554f2SKenneth D. Merry
461991554f2SKenneth D. Merry /**
462991554f2SKenneth D. Merry * _mapping_get_free_ir_mt_idx - get first free index for a volume
463991554f2SKenneth D. Merry * @sc: per adapter object
464991554f2SKenneth D. Merry *
465991554f2SKenneth D. Merry * Search through mapping table for free index for a volume and if no free
466991554f2SKenneth D. Merry * index then looks for a volume with high mapping index
467991554f2SKenneth D. Merry *
468991554f2SKenneth D. Merry * Returns the index of map table entry on success or bad index.
469991554f2SKenneth D. Merry */
470991554f2SKenneth D. Merry static u32
_mapping_get_free_ir_mt_idx(struct mpr_softc * sc)471991554f2SKenneth D. Merry _mapping_get_free_ir_mt_idx(struct mpr_softc *sc)
472991554f2SKenneth D. Merry {
473991554f2SKenneth D. Merry u8 high_missing_count = 0;
474991554f2SKenneth D. Merry u32 start_idx, end_idx, map_idx;
475991554f2SKenneth D. Merry u32 high_idx = MPR_MAPTABLE_BAD_IDX;
476991554f2SKenneth D. Merry struct dev_mapping_table *mt_entry;
477991554f2SKenneth D. Merry
478327f2e6cSStephen McConnell /*
479327f2e6cSStephen McConnell * The IN_USE flag should be clear if the entry is available to use.
480327f2e6cSStephen McConnell * This flag is cleared on initialization and and when a volume is
481327f2e6cSStephen McConnell * deleted. All other times this flag should be set. If, for some
482327f2e6cSStephen McConnell * reason, a free entry cannot be found, look for the entry with the
483327f2e6cSStephen McConnell * highest missing count just in case there is one.
484327f2e6cSStephen McConnell */
485991554f2SKenneth D. Merry _mapping_get_ir_maprange(sc, &start_idx, &end_idx);
486991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[start_idx];
487327f2e6cSStephen McConnell for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++) {
488991554f2SKenneth D. Merry if (!(mt_entry->device_info & MPR_MAP_IN_USE))
489991554f2SKenneth D. Merry return map_idx;
490991554f2SKenneth D. Merry
491991554f2SKenneth D. Merry if (mt_entry->missing_count > high_missing_count) {
492991554f2SKenneth D. Merry high_missing_count = mt_entry->missing_count;
493991554f2SKenneth D. Merry high_idx = map_idx;
494991554f2SKenneth D. Merry }
495991554f2SKenneth D. Merry }
496327f2e6cSStephen McConnell
497327f2e6cSStephen McConnell if (high_idx == MPR_MAPTABLE_BAD_IDX) {
498327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: Could not find a "
499327f2e6cSStephen McConnell "free entry in the mapping table for a Volume. The mapping "
500327f2e6cSStephen McConnell "table is probably corrupt.\n", __func__);
501327f2e6cSStephen McConnell }
502327f2e6cSStephen McConnell
503991554f2SKenneth D. Merry return high_idx;
504991554f2SKenneth D. Merry }
505991554f2SKenneth D. Merry
506991554f2SKenneth D. Merry /**
507991554f2SKenneth D. Merry * _mapping_get_free_mt_idx - get first free index for a device
508991554f2SKenneth D. Merry * @sc: per adapter object
509991554f2SKenneth D. Merry * @start_idx: offset in the table to start search
510991554f2SKenneth D. Merry *
511991554f2SKenneth D. Merry * Returns the index of map table entry on success or bad index.
512991554f2SKenneth D. Merry */
513991554f2SKenneth D. Merry static u32
_mapping_get_free_mt_idx(struct mpr_softc * sc,u32 start_idx)514991554f2SKenneth D. Merry _mapping_get_free_mt_idx(struct mpr_softc *sc, u32 start_idx)
515991554f2SKenneth D. Merry {
516991554f2SKenneth D. Merry u32 map_idx, max_idx = sc->max_devices;
517991554f2SKenneth D. Merry struct dev_mapping_table *mt_entry = &sc->mapping_table[start_idx];
518991554f2SKenneth D. Merry u16 volume_mapping_flags;
519991554f2SKenneth D. Merry
520991554f2SKenneth D. Merry volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) &
521991554f2SKenneth D. Merry MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
522991554f2SKenneth D. Merry if (sc->ir_firmware && (volume_mapping_flags ==
523991554f2SKenneth D. Merry MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING))
524991554f2SKenneth D. Merry max_idx -= sc->max_volumes;
525327f2e6cSStephen McConnell
526991554f2SKenneth D. Merry for (map_idx = start_idx; map_idx < max_idx; map_idx++, mt_entry++)
527991554f2SKenneth D. Merry if (!(mt_entry->device_info & (MPR_MAP_IN_USE |
528991554f2SKenneth D. Merry MPR_DEV_RESERVED)))
529991554f2SKenneth D. Merry return map_idx;
530991554f2SKenneth D. Merry
531991554f2SKenneth D. Merry return MPR_MAPTABLE_BAD_IDX;
532991554f2SKenneth D. Merry }
533991554f2SKenneth D. Merry
534991554f2SKenneth D. Merry /**
535991554f2SKenneth D. Merry * _mapping_get_dpm_idx_from_id - get DPM index from ID
536991554f2SKenneth D. Merry * @sc: per adapter object
537991554f2SKenneth D. Merry * @id: volume WWID or enclosure ID or device ID
538991554f2SKenneth D. Merry *
539991554f2SKenneth D. Merry * Returns the index of DPM entry on success or bad index.
540991554f2SKenneth D. Merry */
541991554f2SKenneth D. Merry static u16
_mapping_get_dpm_idx_from_id(struct mpr_softc * sc,u64 id,u32 phy_bits)542991554f2SKenneth D. Merry _mapping_get_dpm_idx_from_id(struct mpr_softc *sc, u64 id, u32 phy_bits)
543991554f2SKenneth D. Merry {
544991554f2SKenneth D. Merry u16 entry_num;
545991554f2SKenneth D. Merry uint64_t PhysicalIdentifier;
546991554f2SKenneth D. Merry Mpi2DriverMap0Entry_t *dpm_entry;
547991554f2SKenneth D. Merry
548991554f2SKenneth D. Merry dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
549991554f2SKenneth D. Merry sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
550991554f2SKenneth D. Merry PhysicalIdentifier = dpm_entry->PhysicalIdentifier.High;
551991554f2SKenneth D. Merry PhysicalIdentifier = (PhysicalIdentifier << 32) |
552991554f2SKenneth D. Merry dpm_entry->PhysicalIdentifier.Low;
553991554f2SKenneth D. Merry for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++,
554991554f2SKenneth D. Merry dpm_entry++)
555991554f2SKenneth D. Merry if ((id == PhysicalIdentifier) &&
556991554f2SKenneth D. Merry (!phy_bits || !dpm_entry->PhysicalBitsMapping ||
557991554f2SKenneth D. Merry (phy_bits & dpm_entry->PhysicalBitsMapping)))
558991554f2SKenneth D. Merry return entry_num;
559991554f2SKenneth D. Merry
560991554f2SKenneth D. Merry return MPR_DPM_BAD_IDX;
561991554f2SKenneth D. Merry }
562991554f2SKenneth D. Merry
563991554f2SKenneth D. Merry /**
564991554f2SKenneth D. Merry * _mapping_get_free_dpm_idx - get first available DPM index
565991554f2SKenneth D. Merry * @sc: per adapter object
566991554f2SKenneth D. Merry *
567991554f2SKenneth D. Merry * Returns the index of DPM entry on success or bad index.
568991554f2SKenneth D. Merry */
569991554f2SKenneth D. Merry static u32
_mapping_get_free_dpm_idx(struct mpr_softc * sc)570991554f2SKenneth D. Merry _mapping_get_free_dpm_idx(struct mpr_softc *sc)
571991554f2SKenneth D. Merry {
572991554f2SKenneth D. Merry u16 entry_num;
573327f2e6cSStephen McConnell Mpi2DriverMap0Entry_t *dpm_entry;
574327f2e6cSStephen McConnell u16 current_entry = MPR_DPM_BAD_IDX, missing_cnt, high_missing_cnt = 0;
575327f2e6cSStephen McConnell u64 physical_id;
576327f2e6cSStephen McConnell struct dev_mapping_table *mt_entry;
577327f2e6cSStephen McConnell u32 map_idx;
578991554f2SKenneth D. Merry
579991554f2SKenneth D. Merry for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++) {
580327f2e6cSStephen McConnell dpm_entry = (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 +
581327f2e6cSStephen McConnell sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
582327f2e6cSStephen McConnell dpm_entry += entry_num;
583327f2e6cSStephen McConnell missing_cnt = dpm_entry->MappingInformation &
584327f2e6cSStephen McConnell MPI2_DRVMAP0_MAPINFO_MISSING_MASK;
585327f2e6cSStephen McConnell
586327f2e6cSStephen McConnell /*
587327f2e6cSStephen McConnell * If entry is used and not missing, then this entry can't be
588327f2e6cSStephen McConnell * used. Look at next one.
589327f2e6cSStephen McConnell */
590327f2e6cSStephen McConnell if (sc->dpm_entry_used[entry_num] && !missing_cnt)
591327f2e6cSStephen McConnell continue;
592327f2e6cSStephen McConnell
593327f2e6cSStephen McConnell /*
594327f2e6cSStephen McConnell * If this entry is not used at all, then the missing count
595327f2e6cSStephen McConnell * doesn't matter. Just use this one. Otherwise, keep looking
596327f2e6cSStephen McConnell * and make sure the entry with the highest missing count is
597327f2e6cSStephen McConnell * used.
598327f2e6cSStephen McConnell */
599327f2e6cSStephen McConnell if (!sc->dpm_entry_used[entry_num]) {
600327f2e6cSStephen McConnell current_entry = entry_num;
601327f2e6cSStephen McConnell break;
602991554f2SKenneth D. Merry }
603327f2e6cSStephen McConnell if ((current_entry == MPR_DPM_BAD_IDX) ||
604327f2e6cSStephen McConnell (missing_cnt > high_missing_cnt)) {
605327f2e6cSStephen McConnell current_entry = entry_num;
606327f2e6cSStephen McConnell high_missing_cnt = missing_cnt;
607327f2e6cSStephen McConnell }
608327f2e6cSStephen McConnell }
609327f2e6cSStephen McConnell
610327f2e6cSStephen McConnell /*
611327f2e6cSStephen McConnell * If an entry has been found to use and it's already marked as used
612327f2e6cSStephen McConnell * it means that some device was already using this entry but it's
613327f2e6cSStephen McConnell * missing, and that means that the connection between the missing
614327f2e6cSStephen McConnell * device's DPM entry and the mapping table needs to be cleared. To do
615327f2e6cSStephen McConnell * this, use the Physical ID of the old device still in the DPM entry
616327f2e6cSStephen McConnell * to find its mapping table entry, then mark its DPM entry as BAD.
617327f2e6cSStephen McConnell */
618327f2e6cSStephen McConnell if ((current_entry != MPR_DPM_BAD_IDX) &&
619327f2e6cSStephen McConnell sc->dpm_entry_used[current_entry]) {
620327f2e6cSStephen McConnell dpm_entry = (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 +
621327f2e6cSStephen McConnell sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
622327f2e6cSStephen McConnell dpm_entry += current_entry;
623327f2e6cSStephen McConnell physical_id = dpm_entry->PhysicalIdentifier.High;
624327f2e6cSStephen McConnell physical_id = (physical_id << 32) |
625327f2e6cSStephen McConnell dpm_entry->PhysicalIdentifier.Low;
626327f2e6cSStephen McConnell map_idx = _mapping_get_mt_idx_from_id(sc, physical_id);
627327f2e6cSStephen McConnell if (map_idx != MPR_MAPTABLE_BAD_IDX) {
628327f2e6cSStephen McConnell mt_entry = &sc->mapping_table[map_idx];
629327f2e6cSStephen McConnell mt_entry->dpm_entry_num = MPR_DPM_BAD_IDX;
630327f2e6cSStephen McConnell }
631327f2e6cSStephen McConnell }
632327f2e6cSStephen McConnell return current_entry;
633991554f2SKenneth D. Merry }
634991554f2SKenneth D. Merry
635991554f2SKenneth D. Merry /**
636991554f2SKenneth D. Merry * _mapping_update_ir_missing_cnt - Updates missing count for a volume
637991554f2SKenneth D. Merry * @sc: per adapter object
638991554f2SKenneth D. Merry * @map_idx: map table index of the volume
639991554f2SKenneth D. Merry * @element: IR configuration change element
640991554f2SKenneth D. Merry * @wwid: IR volume ID.
641991554f2SKenneth D. Merry *
642991554f2SKenneth D. Merry * Updates the missing count in the map table and in the DPM entry for a volume
643991554f2SKenneth D. Merry *
644991554f2SKenneth D. Merry * Returns nothing.
645991554f2SKenneth D. Merry */
646991554f2SKenneth D. Merry static void
_mapping_update_ir_missing_cnt(struct mpr_softc * sc,u32 map_idx,Mpi2EventIrConfigElement_t * element,u64 wwid)647991554f2SKenneth D. Merry _mapping_update_ir_missing_cnt(struct mpr_softc *sc, u32 map_idx,
648991554f2SKenneth D. Merry Mpi2EventIrConfigElement_t *element, u64 wwid)
649991554f2SKenneth D. Merry {
650991554f2SKenneth D. Merry struct dev_mapping_table *mt_entry;
651327f2e6cSStephen McConnell u8 missing_cnt, reason = element->ReasonCode, update_dpm = 1;
652991554f2SKenneth D. Merry u16 dpm_idx;
653991554f2SKenneth D. Merry Mpi2DriverMap0Entry_t *dpm_entry;
654991554f2SKenneth D. Merry
655327f2e6cSStephen McConnell /*
656327f2e6cSStephen McConnell * Depending on the reason code, update the missing count. Always set
657327f2e6cSStephen McConnell * the init_complete flag when here, so just do it first. That flag is
658327f2e6cSStephen McConnell * used for volumes to make sure that the DPM entry has been updated.
659327f2e6cSStephen McConnell * When a volume is deleted, clear the map entry's IN_USE flag so that
660327f2e6cSStephen McConnell * the entry can be used again if another volume is created. Also clear
661327f2e6cSStephen McConnell * its dev_handle entry so that other functions can't find this volume
662327f2e6cSStephen McConnell * by the handle, since it's not defined any longer.
663327f2e6cSStephen McConnell */
664991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[map_idx];
665327f2e6cSStephen McConnell mt_entry->init_complete = 1;
666327f2e6cSStephen McConnell if ((reason == MPI2_EVENT_IR_CHANGE_RC_ADDED) ||
667327f2e6cSStephen McConnell (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED)) {
668991554f2SKenneth D. Merry mt_entry->missing_count = 0;
669327f2e6cSStephen McConnell } else if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED) {
670991554f2SKenneth D. Merry if (mt_entry->missing_count < MPR_MAX_MISSING_COUNT)
671991554f2SKenneth D. Merry mt_entry->missing_count++;
672327f2e6cSStephen McConnell
673327f2e6cSStephen McConnell mt_entry->device_info &= ~MPR_MAP_IN_USE;
674991554f2SKenneth D. Merry mt_entry->dev_handle = 0;
675991554f2SKenneth D. Merry }
676991554f2SKenneth D. Merry
677327f2e6cSStephen McConnell /*
678327f2e6cSStephen McConnell * If persistent mapping is enabled, update the DPM with the new missing
679327f2e6cSStephen McConnell * count for the volume. If the DPM index is bad, get a free one. If
680327f2e6cSStephen McConnell * it's bad for a volume that's being deleted do nothing because that
681327f2e6cSStephen McConnell * volume doesn't have a DPM entry.
682327f2e6cSStephen McConnell */
683327f2e6cSStephen McConnell if (!sc->is_dpm_enable)
684327f2e6cSStephen McConnell return;
685991554f2SKenneth D. Merry dpm_idx = mt_entry->dpm_entry_num;
686991554f2SKenneth D. Merry if (dpm_idx == MPR_DPM_BAD_IDX) {
687327f2e6cSStephen McConnell if (reason == MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED)
688327f2e6cSStephen McConnell {
689327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Volume being deleted "
690327f2e6cSStephen McConnell "is not in DPM so DPM missing count will not be "
691327f2e6cSStephen McConnell "updated.\n", __func__);
692991554f2SKenneth D. Merry return;
693991554f2SKenneth D. Merry }
694327f2e6cSStephen McConnell }
695327f2e6cSStephen McConnell if (dpm_idx == MPR_DPM_BAD_IDX)
696327f2e6cSStephen McConnell dpm_idx = _mapping_get_free_dpm_idx(sc);
697327f2e6cSStephen McConnell
698327f2e6cSStephen McConnell /*
699327f2e6cSStephen McConnell * Got the DPM entry for the volume or found a free DPM entry if this is
700327f2e6cSStephen McConnell * a new volume. Check if the current information is outdated.
701327f2e6cSStephen McConnell */
702991554f2SKenneth D. Merry if (dpm_idx != MPR_DPM_BAD_IDX) {
703991554f2SKenneth D. Merry dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
704991554f2SKenneth D. Merry sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
705991554f2SKenneth D. Merry dpm_entry += dpm_idx;
706991554f2SKenneth D. Merry missing_cnt = dpm_entry->MappingInformation &
707991554f2SKenneth D. Merry MPI2_DRVMAP0_MAPINFO_MISSING_MASK;
708991554f2SKenneth D. Merry if ((mt_entry->physical_id ==
709327f2e6cSStephen McConnell le64toh(((u64)dpm_entry->PhysicalIdentifier.High << 32) |
710327f2e6cSStephen McConnell (u64)dpm_entry->PhysicalIdentifier.Low)) && (missing_cnt ==
711327f2e6cSStephen McConnell mt_entry->missing_count)) {
712327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: DPM entry for volume "
713327f2e6cSStephen McConnell "with target ID %d does not require an update.\n",
714327f2e6cSStephen McConnell __func__, mt_entry->id);
715327f2e6cSStephen McConnell update_dpm = 0;
716327f2e6cSStephen McConnell }
717991554f2SKenneth D. Merry }
718991554f2SKenneth D. Merry
719327f2e6cSStephen McConnell /*
720327f2e6cSStephen McConnell * Update the volume's persistent info if it's new or the ID or missing
721327f2e6cSStephen McConnell * count has changed. If a good DPM index has not been found by now,
722327f2e6cSStephen McConnell * there is no space left in the DPM table.
723327f2e6cSStephen McConnell */
724327f2e6cSStephen McConnell if ((dpm_idx != MPR_DPM_BAD_IDX) && update_dpm) {
725327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Update DPM entry for volume "
726327f2e6cSStephen McConnell "with target ID %d.\n", __func__, mt_entry->id);
727991554f2SKenneth D. Merry mt_entry->dpm_entry_num = dpm_idx;
728991554f2SKenneth D. Merry dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
729991554f2SKenneth D. Merry sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
730991554f2SKenneth D. Merry dpm_entry += dpm_idx;
731991554f2SKenneth D. Merry dpm_entry->PhysicalIdentifier.Low =
732991554f2SKenneth D. Merry (0xFFFFFFFF & mt_entry->physical_id);
733991554f2SKenneth D. Merry dpm_entry->PhysicalIdentifier.High =
734991554f2SKenneth D. Merry (mt_entry->physical_id >> 32);
735991554f2SKenneth D. Merry dpm_entry->DeviceIndex = map_idx;
736991554f2SKenneth D. Merry dpm_entry->MappingInformation = mt_entry->missing_count;
737991554f2SKenneth D. Merry dpm_entry->PhysicalBitsMapping = 0;
738991554f2SKenneth D. Merry dpm_entry->Reserved1 = 0;
739991554f2SKenneth D. Merry sc->dpm_flush_entry[dpm_idx] = 1;
740991554f2SKenneth D. Merry sc->dpm_entry_used[dpm_idx] = 1;
741991554f2SKenneth D. Merry } else if (dpm_idx == MPR_DPM_BAD_IDX) {
742327f2e6cSStephen McConnell mpr_dprint(sc, MPR_INFO | MPR_MAPPING, "%s: No space to add an "
743327f2e6cSStephen McConnell "entry in the DPM table for volume with target ID %d.\n",
744327f2e6cSStephen McConnell __func__, mt_entry->id);
745991554f2SKenneth D. Merry }
746991554f2SKenneth D. Merry }
747991554f2SKenneth D. Merry
748991554f2SKenneth D. Merry /**
749327f2e6cSStephen McConnell * _mapping_add_to_removal_table - add DPM index to the removal table
750991554f2SKenneth D. Merry * @sc: per adapter object
751327f2e6cSStephen McConnell * @dpm_idx: Index of DPM entry to remove
752991554f2SKenneth D. Merry *
753327f2e6cSStephen McConnell * Adds a DPM entry number to the removal table.
754991554f2SKenneth D. Merry *
755991554f2SKenneth D. Merry * Returns nothing.
756991554f2SKenneth D. Merry */
757991554f2SKenneth D. Merry static void
_mapping_add_to_removal_table(struct mpr_softc * sc,u16 dpm_idx)758327f2e6cSStephen McConnell _mapping_add_to_removal_table(struct mpr_softc *sc, u16 dpm_idx)
759991554f2SKenneth D. Merry {
760991554f2SKenneth D. Merry struct map_removal_table *remove_entry;
761991554f2SKenneth D. Merry u32 i;
762991554f2SKenneth D. Merry
763327f2e6cSStephen McConnell /*
764327f2e6cSStephen McConnell * This is only used to remove entries from the DPM in the controller.
765327f2e6cSStephen McConnell * If DPM is not enabled, just return.
766327f2e6cSStephen McConnell */
767327f2e6cSStephen McConnell if (!sc->is_dpm_enable)
768327f2e6cSStephen McConnell return;
769327f2e6cSStephen McConnell
770327f2e6cSStephen McConnell /*
771327f2e6cSStephen McConnell * Find the first available removal_table entry and add the new entry
772327f2e6cSStephen McConnell * there.
773327f2e6cSStephen McConnell */
774991554f2SKenneth D. Merry remove_entry = sc->removal_table;
775991554f2SKenneth D. Merry for (i = 0; i < sc->max_devices; i++, remove_entry++) {
776327f2e6cSStephen McConnell if (remove_entry->dpm_entry_num != MPR_DPM_BAD_IDX)
777991554f2SKenneth D. Merry continue;
778327f2e6cSStephen McConnell
779327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Adding DPM entry %d to table "
780327f2e6cSStephen McConnell "for removal.\n", __func__, dpm_idx);
781991554f2SKenneth D. Merry remove_entry->dpm_entry_num = dpm_idx;
782991554f2SKenneth D. Merry break;
783991554f2SKenneth D. Merry }
784991554f2SKenneth D. Merry
785991554f2SKenneth D. Merry }
786991554f2SKenneth D. Merry
787991554f2SKenneth D. Merry /**
78867feec50SStephen McConnell * _mapping_inc_missing_count
789991554f2SKenneth D. Merry * @sc: per adapter object
79067feec50SStephen McConnell * @map_idx: index into the mapping table for the device that is missing
791991554f2SKenneth D. Merry *
79267feec50SStephen McConnell * Increment the missing count in the mapping table for a SAS, SATA, or PCIe
79367feec50SStephen McConnell * device that is not responding. If Persitent Mapping is used, increment the
794327f2e6cSStephen McConnell * DPM entry as well. Currently, this function is only called if the target
795327f2e6cSStephen McConnell * goes missing, so after initialization has completed. This means that the
796327f2e6cSStephen McConnell * missing count can only go from 0 to 1 here. The missing count is incremented
797327f2e6cSStephen McConnell * during initialization as well, so that's where a target's missing count can
798327f2e6cSStephen McConnell * go past 1.
799991554f2SKenneth D. Merry *
800991554f2SKenneth D. Merry * Returns nothing.
801991554f2SKenneth D. Merry */
802991554f2SKenneth D. Merry static void
_mapping_inc_missing_count(struct mpr_softc * sc,u32 map_idx)80367feec50SStephen McConnell _mapping_inc_missing_count(struct mpr_softc *sc, u32 map_idx)
804991554f2SKenneth D. Merry {
805991554f2SKenneth D. Merry u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
806991554f2SKenneth D. Merry struct dev_mapping_table *mt_entry;
807991554f2SKenneth D. Merry Mpi2DriverMap0Entry_t *dpm_entry;
808991554f2SKenneth D. Merry
809991554f2SKenneth D. Merry if (map_idx == MPR_MAPTABLE_BAD_IDX) {
810327f2e6cSStephen McConnell mpr_dprint(sc, MPR_INFO | MPR_MAPPING, "%s: device is already "
811327f2e6cSStephen McConnell "removed from mapping table\n", __func__);
81267feec50SStephen McConnell return;
813991554f2SKenneth D. Merry }
814991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[map_idx];
815991554f2SKenneth D. Merry if (mt_entry->missing_count < MPR_MAX_MISSING_COUNT)
816991554f2SKenneth D. Merry mt_entry->missing_count++;
817991554f2SKenneth D. Merry
818327f2e6cSStephen McConnell /*
819327f2e6cSStephen McConnell * When using Enc/Slot mapping, when a device is removed, it's mapping
820327f2e6cSStephen McConnell * table information should be cleared. Otherwise, the target ID will
821327f2e6cSStephen McConnell * be incorrect if this same device is re-added to a different slot.
822327f2e6cSStephen McConnell */
823327f2e6cSStephen McConnell if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
824327f2e6cSStephen McConnell MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
825327f2e6cSStephen McConnell _mapping_clear_map_entry(mt_entry);
826327f2e6cSStephen McConnell }
827327f2e6cSStephen McConnell
828327f2e6cSStephen McConnell /*
829327f2e6cSStephen McConnell * When using device mapping, update the missing count in the DPM entry,
830327f2e6cSStephen McConnell * but only if the missing count has changed.
831327f2e6cSStephen McConnell */
832991554f2SKenneth D. Merry if (((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
833991554f2SKenneth D. Merry MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) &&
834327f2e6cSStephen McConnell sc->is_dpm_enable &&
835991554f2SKenneth D. Merry mt_entry->dpm_entry_num != MPR_DPM_BAD_IDX) {
83667feec50SStephen McConnell dpm_entry = (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 +
837991554f2SKenneth D. Merry sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
838991554f2SKenneth D. Merry dpm_entry += mt_entry->dpm_entry_num;
839327f2e6cSStephen McConnell if (dpm_entry->MappingInformation != mt_entry->missing_count) {
840991554f2SKenneth D. Merry dpm_entry->MappingInformation = mt_entry->missing_count;
841991554f2SKenneth D. Merry sc->dpm_flush_entry[mt_entry->dpm_entry_num] = 1;
842991554f2SKenneth D. Merry }
843327f2e6cSStephen McConnell }
844991554f2SKenneth D. Merry }
84567feec50SStephen McConnell
84667feec50SStephen McConnell /**
84767feec50SStephen McConnell * _mapping_update_missing_count - Update missing count for a device
84867feec50SStephen McConnell * @sc: per adapter object
84967feec50SStephen McConnell * @topo_change: Topology change event entry
85067feec50SStephen McConnell *
85167feec50SStephen McConnell * Search through the topology change list and if any device is found not
85267feec50SStephen McConnell * responding it's associated map table entry and DPM entry is updated
85367feec50SStephen McConnell *
85467feec50SStephen McConnell * Returns nothing.
85567feec50SStephen McConnell */
85667feec50SStephen McConnell static void
_mapping_update_missing_count(struct mpr_softc * sc,struct _map_topology_change * topo_change)85767feec50SStephen McConnell _mapping_update_missing_count(struct mpr_softc *sc,
85867feec50SStephen McConnell struct _map_topology_change *topo_change)
85967feec50SStephen McConnell {
86067feec50SStephen McConnell u8 entry;
86167feec50SStephen McConnell struct _map_phy_change *phy_change;
86267feec50SStephen McConnell u32 map_idx;
86367feec50SStephen McConnell
86467feec50SStephen McConnell for (entry = 0; entry < topo_change->num_entries; entry++) {
86567feec50SStephen McConnell phy_change = &topo_change->phy_details[entry];
86667feec50SStephen McConnell if (!phy_change->dev_handle || (phy_change->reason !=
86767feec50SStephen McConnell MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING))
86867feec50SStephen McConnell continue;
86967feec50SStephen McConnell map_idx = _mapping_get_mt_idx_from_handle(sc, phy_change->
87067feec50SStephen McConnell dev_handle);
87167feec50SStephen McConnell phy_change->is_processed = 1;
87267feec50SStephen McConnell _mapping_inc_missing_count(sc, map_idx);
87367feec50SStephen McConnell }
87467feec50SStephen McConnell }
87567feec50SStephen McConnell
87667feec50SStephen McConnell /**
87767feec50SStephen McConnell * _mapping_update_pcie_missing_count - Update missing count for a PCIe device
87867feec50SStephen McConnell * @sc: per adapter object
87967feec50SStephen McConnell * @topo_change: Topology change event entry
88067feec50SStephen McConnell *
88167feec50SStephen McConnell * Search through the PCIe topology change list and if any device is found not
88267feec50SStephen McConnell * responding it's associated map table entry and DPM entry is updated
88367feec50SStephen McConnell *
88467feec50SStephen McConnell * Returns nothing.
88567feec50SStephen McConnell */
88667feec50SStephen McConnell static void
_mapping_update_pcie_missing_count(struct mpr_softc * sc,struct _map_pcie_topology_change * topo_change)88767feec50SStephen McConnell _mapping_update_pcie_missing_count(struct mpr_softc *sc,
88867feec50SStephen McConnell struct _map_pcie_topology_change *topo_change)
88967feec50SStephen McConnell {
89067feec50SStephen McConnell u8 entry;
89167feec50SStephen McConnell struct _map_port_change *port_change;
89267feec50SStephen McConnell u32 map_idx;
89367feec50SStephen McConnell
89467feec50SStephen McConnell for (entry = 0; entry < topo_change->num_entries; entry++) {
89567feec50SStephen McConnell port_change = &topo_change->port_details[entry];
89667feec50SStephen McConnell if (!port_change->dev_handle || (port_change->reason !=
89767feec50SStephen McConnell MPI26_EVENT_PCIE_TOPO_PS_NOT_RESPONDING))
89867feec50SStephen McConnell continue;
89967feec50SStephen McConnell map_idx = _mapping_get_mt_idx_from_handle(sc, port_change->
90067feec50SStephen McConnell dev_handle);
90167feec50SStephen McConnell port_change->is_processed = 1;
90267feec50SStephen McConnell _mapping_inc_missing_count(sc, map_idx);
90367feec50SStephen McConnell }
904991554f2SKenneth D. Merry }
905991554f2SKenneth D. Merry
906991554f2SKenneth D. Merry /**
907991554f2SKenneth D. Merry * _mapping_find_enc_map_space -find map table entries for enclosure
908991554f2SKenneth D. Merry * @sc: per adapter object
909991554f2SKenneth D. Merry * @et_entry: enclosure entry
910991554f2SKenneth D. Merry *
911991554f2SKenneth D. Merry * Search through the mapping table defragment it and provide contiguous
912991554f2SKenneth D. Merry * space in map table for a particular enclosure entry
913991554f2SKenneth D. Merry *
914991554f2SKenneth D. Merry * Returns start index in map table or bad index.
915991554f2SKenneth D. Merry */
916991554f2SKenneth D. Merry static u32
_mapping_find_enc_map_space(struct mpr_softc * sc,struct enc_mapping_table * et_entry)917991554f2SKenneth D. Merry _mapping_find_enc_map_space(struct mpr_softc *sc,
918991554f2SKenneth D. Merry struct enc_mapping_table *et_entry)
919991554f2SKenneth D. Merry {
920991554f2SKenneth D. Merry u16 vol_mapping_flags;
921991554f2SKenneth D. Merry u32 skip_count, end_of_table, map_idx, enc_idx;
922991554f2SKenneth D. Merry u16 num_found;
923991554f2SKenneth D. Merry u32 start_idx = MPR_MAPTABLE_BAD_IDX;
924991554f2SKenneth D. Merry struct dev_mapping_table *mt_entry;
925991554f2SKenneth D. Merry struct enc_mapping_table *enc_entry;
926991554f2SKenneth D. Merry unsigned char done_flag = 0, found_space;
927991554f2SKenneth D. Merry u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs);
928991554f2SKenneth D. Merry
929991554f2SKenneth D. Merry skip_count = sc->num_rsvd_entries;
930991554f2SKenneth D. Merry num_found = 0;
931991554f2SKenneth D. Merry
932991554f2SKenneth D. Merry vol_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) &
933991554f2SKenneth D. Merry MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
934991554f2SKenneth D. Merry
935327f2e6cSStephen McConnell /*
936327f2e6cSStephen McConnell * The end of the mapping table depends on where volumes are kept, if
937327f2e6cSStephen McConnell * IR is enabled.
938327f2e6cSStephen McConnell */
939991554f2SKenneth D. Merry if (!sc->ir_firmware)
940991554f2SKenneth D. Merry end_of_table = sc->max_devices;
941991554f2SKenneth D. Merry else if (vol_mapping_flags == MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING)
942991554f2SKenneth D. Merry end_of_table = sc->max_devices;
943991554f2SKenneth D. Merry else
944991554f2SKenneth D. Merry end_of_table = sc->max_devices - sc->max_volumes;
945991554f2SKenneth D. Merry
946327f2e6cSStephen McConnell /*
947327f2e6cSStephen McConnell * The skip_count is the number of entries that are reserved at the
948327f2e6cSStephen McConnell * beginning of the mapping table. But, it does not include the number
949327f2e6cSStephen McConnell * of Physical IDs that are reserved for direct attached devices. Look
950327f2e6cSStephen McConnell * through the mapping table after these reserved entries to see if
951327f2e6cSStephen McConnell * the devices for this enclosure are already mapped. The PHY bit check
952327f2e6cSStephen McConnell * is used to make sure that at least one PHY bit is common between the
953327f2e6cSStephen McConnell * enclosure and the device that is already mapped.
954327f2e6cSStephen McConnell */
955327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Looking for space in the mapping "
956327f2e6cSStephen McConnell "table for added enclosure.\n", __func__);
957991554f2SKenneth D. Merry for (map_idx = (max_num_phy_ids + skip_count);
958991554f2SKenneth D. Merry map_idx < end_of_table; map_idx++) {
959991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[map_idx];
960991554f2SKenneth D. Merry if ((et_entry->enclosure_id == mt_entry->physical_id) &&
961991554f2SKenneth D. Merry (!mt_entry->phy_bits || (mt_entry->phy_bits &
962991554f2SKenneth D. Merry et_entry->phy_bits))) {
963991554f2SKenneth D. Merry num_found += 1;
964991554f2SKenneth D. Merry if (num_found == et_entry->num_slots) {
965991554f2SKenneth D. Merry start_idx = (map_idx - num_found) + 1;
966327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Found space "
967327f2e6cSStephen McConnell "in the mapping for enclosure at map index "
968327f2e6cSStephen McConnell "%d.\n", __func__, start_idx);
969991554f2SKenneth D. Merry return start_idx;
970991554f2SKenneth D. Merry }
971991554f2SKenneth D. Merry } else
972991554f2SKenneth D. Merry num_found = 0;
973991554f2SKenneth D. Merry }
974327f2e6cSStephen McConnell
975327f2e6cSStephen McConnell /*
976327f2e6cSStephen McConnell * If the enclosure's devices are not mapped already, look for
977327f2e6cSStephen McConnell * contiguous entries in the mapping table that are not reserved. If
978327f2e6cSStephen McConnell * enough entries are found, return the starting index for that space.
979327f2e6cSStephen McConnell */
980327f2e6cSStephen McConnell num_found = 0;
981991554f2SKenneth D. Merry for (map_idx = (max_num_phy_ids + skip_count);
982991554f2SKenneth D. Merry map_idx < end_of_table; map_idx++) {
983991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[map_idx];
984991554f2SKenneth D. Merry if (!(mt_entry->device_info & MPR_DEV_RESERVED)) {
985991554f2SKenneth D. Merry num_found += 1;
986991554f2SKenneth D. Merry if (num_found == et_entry->num_slots) {
987991554f2SKenneth D. Merry start_idx = (map_idx - num_found) + 1;
988327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Found space "
989327f2e6cSStephen McConnell "in the mapping for enclosure at map index "
990327f2e6cSStephen McConnell "%d.\n", __func__, start_idx);
991991554f2SKenneth D. Merry return start_idx;
992991554f2SKenneth D. Merry }
993991554f2SKenneth D. Merry } else
994991554f2SKenneth D. Merry num_found = 0;
995991554f2SKenneth D. Merry }
996991554f2SKenneth D. Merry
997327f2e6cSStephen McConnell /*
998327f2e6cSStephen McConnell * If here, it means that not enough space in the mapping table was
999327f2e6cSStephen McConnell * found to support this enclosure, so go through the enclosure table to
1000327f2e6cSStephen McConnell * see if any enclosure entries have a missing count. If so, get the
1001327f2e6cSStephen McConnell * enclosure with the highest missing count and check it to see if there
1002327f2e6cSStephen McConnell * is enough space for the new enclosure.
1003327f2e6cSStephen McConnell */
1004991554f2SKenneth D. Merry while (!done_flag) {
1005991554f2SKenneth D. Merry enc_idx = _mapping_get_high_missing_et_idx(sc);
1006327f2e6cSStephen McConnell if (enc_idx == MPR_ENCTABLE_BAD_IDX) {
1007327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Not enough space was "
1008327f2e6cSStephen McConnell "found in the mapping for the added enclosure.\n",
1009327f2e6cSStephen McConnell __func__);
1010991554f2SKenneth D. Merry return MPR_MAPTABLE_BAD_IDX;
1011327f2e6cSStephen McConnell }
1012327f2e6cSStephen McConnell
1013327f2e6cSStephen McConnell /*
1014327f2e6cSStephen McConnell * Found a missing enclosure. Set the skip_search flag so this
1015327f2e6cSStephen McConnell * enclosure is not checked again for a high missing count if
1016327f2e6cSStephen McConnell * the loop continues. This way, all missing enclosures can
1017327f2e6cSStephen McConnell * have their space added together to find enough space in the
1018327f2e6cSStephen McConnell * mapping table for the added enclosure. The space must be
1019327f2e6cSStephen McConnell * contiguous.
1020327f2e6cSStephen McConnell */
1021327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Space from a missing "
1022327f2e6cSStephen McConnell "enclosure was found.\n", __func__);
1023991554f2SKenneth D. Merry enc_entry = &sc->enclosure_table[enc_idx];
1024991554f2SKenneth D. Merry enc_entry->skip_search = 1;
1025327f2e6cSStephen McConnell
1026327f2e6cSStephen McConnell /*
1027327f2e6cSStephen McConnell * Unmark all of the missing enclosure's device's reserved
1028327f2e6cSStephen McConnell * space. These will be remarked as reserved if this missing
1029327f2e6cSStephen McConnell * enclosure's space is not used.
1030327f2e6cSStephen McConnell */
1031327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Clear the reserved flag for "
1032327f2e6cSStephen McConnell "all of the map entries for the enclosure.\n", __func__);
1033991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[enc_entry->start_index];
1034991554f2SKenneth D. Merry for (map_idx = enc_entry->start_index; map_idx <
1035991554f2SKenneth D. Merry (enc_entry->start_index + enc_entry->num_slots); map_idx++,
1036991554f2SKenneth D. Merry mt_entry++)
1037991554f2SKenneth D. Merry mt_entry->device_info &= ~MPR_DEV_RESERVED;
1038327f2e6cSStephen McConnell
1039327f2e6cSStephen McConnell /*
1040327f2e6cSStephen McConnell * Now that space has been unreserved, check again to see if
1041327f2e6cSStephen McConnell * enough space is available for the new enclosure.
1042327f2e6cSStephen McConnell */
1043327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Check if new mapping space is "
1044327f2e6cSStephen McConnell "enough for the new enclosure.\n", __func__);
1045991554f2SKenneth D. Merry found_space = 0;
1046327f2e6cSStephen McConnell num_found = 0;
1047327f2e6cSStephen McConnell for (map_idx = (max_num_phy_ids + skip_count);
1048327f2e6cSStephen McConnell map_idx < end_of_table; map_idx++) {
1049991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[map_idx];
1050991554f2SKenneth D. Merry if (!(mt_entry->device_info & MPR_DEV_RESERVED)) {
1051991554f2SKenneth D. Merry num_found += 1;
1052991554f2SKenneth D. Merry if (num_found == et_entry->num_slots) {
1053991554f2SKenneth D. Merry start_idx = (map_idx - num_found) + 1;
1054991554f2SKenneth D. Merry found_space = 1;
1055327f2e6cSStephen McConnell break;
1056991554f2SKenneth D. Merry }
1057991554f2SKenneth D. Merry } else
1058991554f2SKenneth D. Merry num_found = 0;
1059991554f2SKenneth D. Merry }
1060991554f2SKenneth D. Merry if (!found_space)
1061991554f2SKenneth D. Merry continue;
1062327f2e6cSStephen McConnell
1063327f2e6cSStephen McConnell /*
1064327f2e6cSStephen McConnell * If enough space was found, all of the missing enclosures that
1065327f2e6cSStephen McConnell * will be used for the new enclosure must be added to the
1066327f2e6cSStephen McConnell * removal table. Then all mappings for the enclosure's devices
1067327f2e6cSStephen McConnell * and for the enclosure itself need to be cleared. There may be
1068327f2e6cSStephen McConnell * more than one enclosure to add to the removal table and
1069327f2e6cSStephen McConnell * clear.
1070327f2e6cSStephen McConnell */
1071327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Found space in the mapping "
1072327f2e6cSStephen McConnell "for enclosure at map index %d.\n", __func__, start_idx);
1073991554f2SKenneth D. Merry for (map_idx = start_idx; map_idx < (start_idx + num_found);
1074991554f2SKenneth D. Merry map_idx++) {
1075991554f2SKenneth D. Merry enc_entry = sc->enclosure_table;
1076991554f2SKenneth D. Merry for (enc_idx = 0; enc_idx < sc->num_enc_table_entries;
1077991554f2SKenneth D. Merry enc_idx++, enc_entry++) {
1078991554f2SKenneth D. Merry if (map_idx < enc_entry->start_index ||
1079991554f2SKenneth D. Merry map_idx > (enc_entry->start_index +
1080991554f2SKenneth D. Merry enc_entry->num_slots))
1081991554f2SKenneth D. Merry continue;
1082991554f2SKenneth D. Merry if (!enc_entry->removal_flag) {
1083327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: "
1084327f2e6cSStephen McConnell "Enclosure %d will be removed from "
1085327f2e6cSStephen McConnell "the mapping table.\n", __func__,
1086327f2e6cSStephen McConnell enc_idx);
1087991554f2SKenneth D. Merry enc_entry->removal_flag = 1;
1088327f2e6cSStephen McConnell _mapping_add_to_removal_table(sc,
1089991554f2SKenneth D. Merry enc_entry->dpm_entry_num);
1090991554f2SKenneth D. Merry }
1091991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[map_idx];
1092991554f2SKenneth D. Merry _mapping_clear_map_entry(mt_entry);
1093991554f2SKenneth D. Merry if (map_idx == (enc_entry->start_index +
1094991554f2SKenneth D. Merry enc_entry->num_slots - 1))
1095991554f2SKenneth D. Merry _mapping_clear_enc_entry(et_entry);
1096991554f2SKenneth D. Merry }
1097991554f2SKenneth D. Merry }
1098327f2e6cSStephen McConnell
1099327f2e6cSStephen McConnell /*
1100327f2e6cSStephen McConnell * During the search for space for this enclosure, some entries
1101327f2e6cSStephen McConnell * in the mapping table may have been unreserved. Go back and
1102327f2e6cSStephen McConnell * change all of these to reserved again. Only the enclosures
1103327f2e6cSStephen McConnell * with the removal_flag set should be left as unreserved. The
1104327f2e6cSStephen McConnell * skip_search flag needs to be cleared as well so that the
1105327f2e6cSStephen McConnell * enclosure's space will be looked at the next time space is
1106327f2e6cSStephen McConnell * needed.
1107327f2e6cSStephen McConnell */
1108991554f2SKenneth D. Merry enc_entry = sc->enclosure_table;
1109991554f2SKenneth D. Merry for (enc_idx = 0; enc_idx < sc->num_enc_table_entries;
1110991554f2SKenneth D. Merry enc_idx++, enc_entry++) {
1111991554f2SKenneth D. Merry if (!enc_entry->removal_flag) {
1112327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Reset the "
1113327f2e6cSStephen McConnell "reserved flag for all of the map entries "
1114327f2e6cSStephen McConnell "for enclosure %d.\n", __func__, enc_idx);
1115991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[enc_entry->
1116991554f2SKenneth D. Merry start_index];
1117991554f2SKenneth D. Merry for (map_idx = enc_entry->start_index; map_idx <
1118991554f2SKenneth D. Merry (enc_entry->start_index +
1119991554f2SKenneth D. Merry enc_entry->num_slots); map_idx++,
1120991554f2SKenneth D. Merry mt_entry++)
1121991554f2SKenneth D. Merry mt_entry->device_info |=
1122991554f2SKenneth D. Merry MPR_DEV_RESERVED;
1123991554f2SKenneth D. Merry et_entry->skip_search = 0;
1124991554f2SKenneth D. Merry }
1125991554f2SKenneth D. Merry }
1126991554f2SKenneth D. Merry done_flag = 1;
1127991554f2SKenneth D. Merry }
1128991554f2SKenneth D. Merry return start_idx;
1129991554f2SKenneth D. Merry }
1130991554f2SKenneth D. Merry
1131991554f2SKenneth D. Merry /**
1132991554f2SKenneth D. Merry * _mapping_get_dev_info -get information about newly added devices
1133991554f2SKenneth D. Merry * @sc: per adapter object
1134991554f2SKenneth D. Merry * @topo_change: Topology change event entry
1135991554f2SKenneth D. Merry *
1136991554f2SKenneth D. Merry * Search through the topology change event list and issues sas device pg0
1137991554f2SKenneth D. Merry * requests for the newly added device and reserved entries in tables
1138991554f2SKenneth D. Merry *
1139991554f2SKenneth D. Merry * Returns nothing
1140991554f2SKenneth D. Merry */
1141991554f2SKenneth D. Merry static void
_mapping_get_dev_info(struct mpr_softc * sc,struct _map_topology_change * topo_change)1142991554f2SKenneth D. Merry _mapping_get_dev_info(struct mpr_softc *sc,
1143991554f2SKenneth D. Merry struct _map_topology_change *topo_change)
1144991554f2SKenneth D. Merry {
1145991554f2SKenneth D. Merry u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
1146991554f2SKenneth D. Merry Mpi2ConfigReply_t mpi_reply;
1147991554f2SKenneth D. Merry Mpi2SasDevicePage0_t sas_device_pg0;
1148327f2e6cSStephen McConnell u8 entry, enc_idx, phy_idx;
1149991554f2SKenneth D. Merry u32 map_idx, index, device_info;
1150991554f2SKenneth D. Merry struct _map_phy_change *phy_change, *tmp_phy_change;
1151991554f2SKenneth D. Merry uint64_t sas_address;
1152991554f2SKenneth D. Merry struct enc_mapping_table *et_entry;
1153991554f2SKenneth D. Merry struct dev_mapping_table *mt_entry;
1154991554f2SKenneth D. Merry u8 add_code = MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED;
1155a2c14879SStephen McConnell int rc = 1;
1156991554f2SKenneth D. Merry
1157991554f2SKenneth D. Merry for (entry = 0; entry < topo_change->num_entries; entry++) {
1158991554f2SKenneth D. Merry phy_change = &topo_change->phy_details[entry];
1159991554f2SKenneth D. Merry if (phy_change->is_processed || !phy_change->dev_handle ||
1160991554f2SKenneth D. Merry phy_change->reason != MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED)
1161991554f2SKenneth D. Merry continue;
1162327f2e6cSStephen McConnell
1163991554f2SKenneth D. Merry if (mpr_config_get_sas_device_pg0(sc, &mpi_reply,
1164991554f2SKenneth D. Merry &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
1165991554f2SKenneth D. Merry phy_change->dev_handle)) {
1166991554f2SKenneth D. Merry phy_change->is_processed = 1;
1167991554f2SKenneth D. Merry continue;
1168991554f2SKenneth D. Merry }
1169991554f2SKenneth D. Merry
1170a2c14879SStephen McConnell /*
1171a2c14879SStephen McConnell * Always get SATA Identify information because this is used
1172a2c14879SStephen McConnell * to determine if Start/Stop Unit should be sent to the drive
1173a2c14879SStephen McConnell * when the system is shutdown.
1174a2c14879SStephen McConnell */
1175991554f2SKenneth D. Merry device_info = le32toh(sas_device_pg0.DeviceInfo);
1176327f2e6cSStephen McConnell sas_address = le32toh(sas_device_pg0.SASAddress.High);
1177991554f2SKenneth D. Merry sas_address = (sas_address << 32) |
1178327f2e6cSStephen McConnell le32toh(sas_device_pg0.SASAddress.Low);
1179a2c14879SStephen McConnell if ((device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE) &&
1180a2c14879SStephen McConnell (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)) {
1181a2c14879SStephen McConnell rc = mprsas_get_sas_address_for_sata_disk(sc,
1182a2c14879SStephen McConnell &sas_address, phy_change->dev_handle, device_info,
1183a2c14879SStephen McConnell &phy_change->is_SATA_SSD);
1184a2c14879SStephen McConnell if (rc) {
1185a2c14879SStephen McConnell mpr_dprint(sc, MPR_ERROR, "%s: failed to get "
1186a2c14879SStephen McConnell "disk type (SSD or HDD) and SAS Address "
1187a2c14879SStephen McConnell "for SATA device with handle 0x%04x\n",
1188a2c14879SStephen McConnell __func__, phy_change->dev_handle);
1189991554f2SKenneth D. Merry }
1190a2c14879SStephen McConnell }
1191a2c14879SStephen McConnell
1192991554f2SKenneth D. Merry phy_change->physical_id = sas_address;
1193991554f2SKenneth D. Merry phy_change->slot = le16toh(sas_device_pg0.Slot);
119467feec50SStephen McConnell phy_change->device_info = device_info;
1195991554f2SKenneth D. Merry
1196327f2e6cSStephen McConnell /*
1197327f2e6cSStephen McConnell * When using Enc/Slot mapping, if this device is an enclosure
1198327f2e6cSStephen McConnell * make sure that all of its slots can fit into the mapping
1199327f2e6cSStephen McConnell * table.
1200327f2e6cSStephen McConnell */
1201991554f2SKenneth D. Merry if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
1202991554f2SKenneth D. Merry MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
1203327f2e6cSStephen McConnell /*
1204327f2e6cSStephen McConnell * The enclosure should already be in the enclosure
1205327f2e6cSStephen McConnell * table due to the Enclosure Add event. If not, just
1206327f2e6cSStephen McConnell * continue, nothing can be done.
1207327f2e6cSStephen McConnell */
1208991554f2SKenneth D. Merry enc_idx = _mapping_get_enc_idx_from_handle(sc,
1209991554f2SKenneth D. Merry topo_change->enc_handle);
1210991554f2SKenneth D. Merry if (enc_idx == MPR_ENCTABLE_BAD_IDX) {
1211991554f2SKenneth D. Merry phy_change->is_processed = 1;
1212327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: "
1213327f2e6cSStephen McConnell "failed to add the device with handle "
1214b99419aeSAlexander Motin "0x%04x because enclosure handle 0x%04x "
1215b99419aeSAlexander Motin "is not in the mapping table\n", __func__,
1216b99419aeSAlexander Motin phy_change->dev_handle,
1217b99419aeSAlexander Motin topo_change->enc_handle);
1218991554f2SKenneth D. Merry continue;
1219991554f2SKenneth D. Merry }
1220991554f2SKenneth D. Merry if (!((phy_change->device_info &
1221991554f2SKenneth D. Merry MPI2_SAS_DEVICE_INFO_END_DEVICE) &&
1222991554f2SKenneth D. Merry (phy_change->device_info &
1223991554f2SKenneth D. Merry (MPI2_SAS_DEVICE_INFO_SSP_TARGET |
1224991554f2SKenneth D. Merry MPI2_SAS_DEVICE_INFO_STP_TARGET |
1225991554f2SKenneth D. Merry MPI2_SAS_DEVICE_INFO_SATA_DEVICE)))) {
1226991554f2SKenneth D. Merry phy_change->is_processed = 1;
1227991554f2SKenneth D. Merry continue;
1228991554f2SKenneth D. Merry }
1229991554f2SKenneth D. Merry et_entry = &sc->enclosure_table[enc_idx];
1230327f2e6cSStephen McConnell
1231327f2e6cSStephen McConnell /*
1232327f2e6cSStephen McConnell * If the enclosure already has a start_index, it's been
1233327f2e6cSStephen McConnell * mapped, so go to the next Topo change.
1234327f2e6cSStephen McConnell */
1235991554f2SKenneth D. Merry if (et_entry->start_index != MPR_MAPTABLE_BAD_IDX)
1236991554f2SKenneth D. Merry continue;
1237327f2e6cSStephen McConnell
1238327f2e6cSStephen McConnell /*
1239327f2e6cSStephen McConnell * If the Expander Handle is 0, the devices are direct
1240327f2e6cSStephen McConnell * attached. In that case, the start_index must be just
1241327f2e6cSStephen McConnell * after the reserved entries. Otherwise, find space in
1242327f2e6cSStephen McConnell * the mapping table for the enclosure's devices.
1243327f2e6cSStephen McConnell */
1244991554f2SKenneth D. Merry if (!topo_change->exp_handle) {
1245991554f2SKenneth D. Merry map_idx = sc->num_rsvd_entries;
1246991554f2SKenneth D. Merry et_entry->start_index = map_idx;
1247991554f2SKenneth D. Merry } else {
1248991554f2SKenneth D. Merry map_idx = _mapping_find_enc_map_space(sc,
1249991554f2SKenneth D. Merry et_entry);
1250991554f2SKenneth D. Merry et_entry->start_index = map_idx;
1251327f2e6cSStephen McConnell
1252327f2e6cSStephen McConnell /*
1253327f2e6cSStephen McConnell * If space cannot be found to hold all of the
1254327f2e6cSStephen McConnell * enclosure's devices in the mapping table,
1255327f2e6cSStephen McConnell * there's no need to continue checking the
1256327f2e6cSStephen McConnell * other devices in this event. Set all of the
1257327f2e6cSStephen McConnell * phy_details for this event (if the change is
1258327f2e6cSStephen McConnell * for an add) as already processed because none
1259327f2e6cSStephen McConnell * of these devices can be added to the mapping
1260327f2e6cSStephen McConnell * table.
1261327f2e6cSStephen McConnell */
1262991554f2SKenneth D. Merry if (et_entry->start_index ==
1263991554f2SKenneth D. Merry MPR_MAPTABLE_BAD_IDX) {
1264327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING,
1265327f2e6cSStephen McConnell "%s: failed to add the enclosure "
1266327f2e6cSStephen McConnell "with ID 0x%016jx because there is "
1267327f2e6cSStephen McConnell "no free space available in the "
1268327f2e6cSStephen McConnell "mapping table for all of the "
1269327f2e6cSStephen McConnell "enclosure's devices.\n", __func__,
1270327f2e6cSStephen McConnell (uintmax_t)et_entry->enclosure_id);
1271991554f2SKenneth D. Merry phy_change->is_processed = 1;
1272991554f2SKenneth D. Merry for (phy_idx = 0; phy_idx <
1273991554f2SKenneth D. Merry topo_change->num_entries;
1274991554f2SKenneth D. Merry phy_idx++) {
1275991554f2SKenneth D. Merry tmp_phy_change =
1276991554f2SKenneth D. Merry &topo_change->phy_details
1277991554f2SKenneth D. Merry [phy_idx];
1278991554f2SKenneth D. Merry if (tmp_phy_change->reason ==
1279991554f2SKenneth D. Merry add_code)
1280991554f2SKenneth D. Merry tmp_phy_change->
1281991554f2SKenneth D. Merry is_processed = 1;
1282991554f2SKenneth D. Merry }
1283991554f2SKenneth D. Merry break;
1284991554f2SKenneth D. Merry }
1285991554f2SKenneth D. Merry }
128667feec50SStephen McConnell
1287327f2e6cSStephen McConnell /*
1288327f2e6cSStephen McConnell * Found space in the mapping table for this enclosure.
1289327f2e6cSStephen McConnell * Initialize each mapping table entry for the
1290327f2e6cSStephen McConnell * enclosure.
1291327f2e6cSStephen McConnell */
1292327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Initialize %d map "
1293327f2e6cSStephen McConnell "entries for the enclosure, starting at map index "
1294327f2e6cSStephen McConnell " %d.\n", __func__, et_entry->num_slots, map_idx);
1295991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[map_idx];
1296991554f2SKenneth D. Merry for (index = map_idx; index < (et_entry->num_slots
1297991554f2SKenneth D. Merry + map_idx); index++, mt_entry++) {
1298991554f2SKenneth D. Merry mt_entry->device_info = MPR_DEV_RESERVED;
1299991554f2SKenneth D. Merry mt_entry->physical_id = et_entry->enclosure_id;
1300991554f2SKenneth D. Merry mt_entry->phy_bits = et_entry->phy_bits;
130167feec50SStephen McConnell mt_entry->missing_count = 0;
130267feec50SStephen McConnell }
130367feec50SStephen McConnell }
130467feec50SStephen McConnell }
130567feec50SStephen McConnell }
130667feec50SStephen McConnell
130767feec50SStephen McConnell /**
130867feec50SStephen McConnell * _mapping_get_pcie_dev_info -get information about newly added PCIe devices
130967feec50SStephen McConnell * @sc: per adapter object
131067feec50SStephen McConnell * @topo_change: Topology change event entry
131167feec50SStephen McConnell *
131267feec50SStephen McConnell * Searches through the PCIe topology change event list and issues PCIe device
131367feec50SStephen McConnell * pg0 requests for the newly added PCIe device. If the device is in an
131467feec50SStephen McConnell * enclosure, search for available space in the enclosure mapping table for the
131567feec50SStephen McConnell * device and reserve that space.
131667feec50SStephen McConnell *
131767feec50SStephen McConnell * Returns nothing
131867feec50SStephen McConnell */
131967feec50SStephen McConnell static void
_mapping_get_pcie_dev_info(struct mpr_softc * sc,struct _map_pcie_topology_change * topo_change)132067feec50SStephen McConnell _mapping_get_pcie_dev_info(struct mpr_softc *sc,
132167feec50SStephen McConnell struct _map_pcie_topology_change *topo_change)
132267feec50SStephen McConnell {
132367feec50SStephen McConnell u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
132467feec50SStephen McConnell Mpi2ConfigReply_t mpi_reply;
132567feec50SStephen McConnell Mpi26PCIeDevicePage0_t pcie_device_pg0;
132667feec50SStephen McConnell u8 entry, enc_idx, port_idx;
132767feec50SStephen McConnell u32 map_idx, index;
132867feec50SStephen McConnell struct _map_port_change *port_change, *tmp_port_change;
132967feec50SStephen McConnell uint64_t pcie_wwid;
133067feec50SStephen McConnell struct enc_mapping_table *et_entry;
133167feec50SStephen McConnell struct dev_mapping_table *mt_entry;
133267feec50SStephen McConnell u8 add_code = MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED;
133367feec50SStephen McConnell
133467feec50SStephen McConnell for (entry = 0; entry < topo_change->num_entries; entry++) {
133567feec50SStephen McConnell port_change = &topo_change->port_details[entry];
133667feec50SStephen McConnell if (port_change->is_processed || !port_change->dev_handle ||
133767feec50SStephen McConnell port_change->reason != MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED)
133867feec50SStephen McConnell continue;
133967feec50SStephen McConnell if (mpr_config_get_pcie_device_pg0(sc, &mpi_reply,
134067feec50SStephen McConnell &pcie_device_pg0, MPI26_PCIE_DEVICE_PGAD_FORM_HANDLE,
134167feec50SStephen McConnell port_change->dev_handle)) {
134267feec50SStephen McConnell port_change->is_processed = 1;
134367feec50SStephen McConnell continue;
134467feec50SStephen McConnell }
134567feec50SStephen McConnell
134667feec50SStephen McConnell pcie_wwid = pcie_device_pg0.WWID.High;
134767feec50SStephen McConnell pcie_wwid = (pcie_wwid << 32) | pcie_device_pg0.WWID.Low;
134867feec50SStephen McConnell port_change->physical_id = pcie_wwid;
134967feec50SStephen McConnell port_change->slot = le16toh(pcie_device_pg0.Slot);
135067feec50SStephen McConnell port_change->device_info = le32toh(pcie_device_pg0.DeviceInfo);
135167feec50SStephen McConnell
1352327f2e6cSStephen McConnell /*
1353327f2e6cSStephen McConnell * When using Enc/Slot mapping, if this device is an enclosure
1354327f2e6cSStephen McConnell * make sure that all of its slots can fit into the mapping
1355327f2e6cSStephen McConnell * table.
1356327f2e6cSStephen McConnell */
135767feec50SStephen McConnell if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
135867feec50SStephen McConnell MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
1359327f2e6cSStephen McConnell /*
1360327f2e6cSStephen McConnell * The enclosure should already be in the enclosure
1361327f2e6cSStephen McConnell * table due to the Enclosure Add event. If not, just
1362327f2e6cSStephen McConnell * continue, nothing can be done.
1363327f2e6cSStephen McConnell */
136467feec50SStephen McConnell enc_idx = _mapping_get_enc_idx_from_handle(sc,
136567feec50SStephen McConnell topo_change->enc_handle);
136667feec50SStephen McConnell if (enc_idx == MPR_ENCTABLE_BAD_IDX) {
136767feec50SStephen McConnell port_change->is_processed = 1;
1368327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: "
1369327f2e6cSStephen McConnell "failed to add the device with handle "
1370b99419aeSAlexander Motin "0x%04x because enclosure handle 0x%04x "
1371b99419aeSAlexander Motin "is not in the mapping table\n", __func__,
1372b99419aeSAlexander Motin port_change->dev_handle,
1373b99419aeSAlexander Motin topo_change->enc_handle);
137467feec50SStephen McConnell continue;
137567feec50SStephen McConnell }
137667feec50SStephen McConnell if (!(port_change->device_info &
137767feec50SStephen McConnell MPI26_PCIE_DEVINFO_NVME)) {
137867feec50SStephen McConnell port_change->is_processed = 1;
137967feec50SStephen McConnell continue;
138067feec50SStephen McConnell }
138167feec50SStephen McConnell et_entry = &sc->enclosure_table[enc_idx];
1382327f2e6cSStephen McConnell
1383327f2e6cSStephen McConnell /*
1384327f2e6cSStephen McConnell * If the enclosure already has a start_index, it's been
1385327f2e6cSStephen McConnell * mapped, so go to the next Topo change.
1386327f2e6cSStephen McConnell */
138767feec50SStephen McConnell if (et_entry->start_index != MPR_MAPTABLE_BAD_IDX)
138867feec50SStephen McConnell continue;
1389327f2e6cSStephen McConnell
1390327f2e6cSStephen McConnell /*
1391327f2e6cSStephen McConnell * If the Switch Handle is 0, the devices are direct
1392327f2e6cSStephen McConnell * attached. In that case, the start_index must be just
1393327f2e6cSStephen McConnell * after the reserved entries. Otherwise, find space in
1394327f2e6cSStephen McConnell * the mapping table for the enclosure's devices.
1395327f2e6cSStephen McConnell */
139667feec50SStephen McConnell if (!topo_change->switch_dev_handle) {
139767feec50SStephen McConnell map_idx = sc->num_rsvd_entries;
139867feec50SStephen McConnell et_entry->start_index = map_idx;
139967feec50SStephen McConnell } else {
140067feec50SStephen McConnell map_idx = _mapping_find_enc_map_space(sc,
140167feec50SStephen McConnell et_entry);
140267feec50SStephen McConnell et_entry->start_index = map_idx;
1403327f2e6cSStephen McConnell
1404327f2e6cSStephen McConnell /*
1405327f2e6cSStephen McConnell * If space cannot be found to hold all of the
1406327f2e6cSStephen McConnell * enclosure's devices in the mapping table,
1407327f2e6cSStephen McConnell * there's no need to continue checking the
1408327f2e6cSStephen McConnell * other devices in this event. Set all of the
1409327f2e6cSStephen McConnell * port_details for this event (if the change is
1410327f2e6cSStephen McConnell * for an add) as already processed because none
1411327f2e6cSStephen McConnell * of these devices can be added to the mapping
1412327f2e6cSStephen McConnell * table.
1413327f2e6cSStephen McConnell */
141467feec50SStephen McConnell if (et_entry->start_index ==
141567feec50SStephen McConnell MPR_MAPTABLE_BAD_IDX) {
1416327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING,
1417327f2e6cSStephen McConnell "%s: failed to add the enclosure "
1418327f2e6cSStephen McConnell "with ID 0x%016jx because there is "
1419327f2e6cSStephen McConnell "no free space available in the "
1420327f2e6cSStephen McConnell "mapping table for all of the "
1421327f2e6cSStephen McConnell "enclosure's devices.\n", __func__,
1422327f2e6cSStephen McConnell (uintmax_t)et_entry->enclosure_id);
142367feec50SStephen McConnell port_change->is_processed = 1;
142467feec50SStephen McConnell for (port_idx = 0; port_idx <
142567feec50SStephen McConnell topo_change->num_entries;
142667feec50SStephen McConnell port_idx++) {
142767feec50SStephen McConnell tmp_port_change =
142867feec50SStephen McConnell &topo_change->port_details
142967feec50SStephen McConnell [port_idx];
143067feec50SStephen McConnell if (tmp_port_change->reason ==
143167feec50SStephen McConnell add_code)
143267feec50SStephen McConnell tmp_port_change->
143367feec50SStephen McConnell is_processed = 1;
143467feec50SStephen McConnell }
143567feec50SStephen McConnell break;
143667feec50SStephen McConnell }
143767feec50SStephen McConnell }
143867feec50SStephen McConnell
1439327f2e6cSStephen McConnell /*
1440327f2e6cSStephen McConnell * Found space in the mapping table for this enclosure.
1441327f2e6cSStephen McConnell * Initialize each mapping table entry for the
1442327f2e6cSStephen McConnell * enclosure.
1443327f2e6cSStephen McConnell */
1444327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Initialize %d map "
1445327f2e6cSStephen McConnell "entries for the enclosure, starting at map index "
1446327f2e6cSStephen McConnell " %d.\n", __func__, et_entry->num_slots, map_idx);
144767feec50SStephen McConnell mt_entry = &sc->mapping_table[map_idx];
144867feec50SStephen McConnell for (index = map_idx; index < (et_entry->num_slots
144967feec50SStephen McConnell + map_idx); index++, mt_entry++) {
145067feec50SStephen McConnell mt_entry->device_info = MPR_DEV_RESERVED;
145167feec50SStephen McConnell mt_entry->physical_id = et_entry->enclosure_id;
145267feec50SStephen McConnell mt_entry->phy_bits = et_entry->phy_bits;
145367feec50SStephen McConnell mt_entry->missing_count = 0;
1454991554f2SKenneth D. Merry }
1455991554f2SKenneth D. Merry }
1456991554f2SKenneth D. Merry }
1457991554f2SKenneth D. Merry }
1458991554f2SKenneth D. Merry
1459991554f2SKenneth D. Merry /**
1460991554f2SKenneth D. Merry * _mapping_set_mid_to_eid -set map table data from enclosure table
1461991554f2SKenneth D. Merry * @sc: per adapter object
1462991554f2SKenneth D. Merry * @et_entry: enclosure entry
1463991554f2SKenneth D. Merry *
1464991554f2SKenneth D. Merry * Returns nothing
1465991554f2SKenneth D. Merry */
1466991554f2SKenneth D. Merry static inline void
_mapping_set_mid_to_eid(struct mpr_softc * sc,struct enc_mapping_table * et_entry)1467991554f2SKenneth D. Merry _mapping_set_mid_to_eid(struct mpr_softc *sc,
1468991554f2SKenneth D. Merry struct enc_mapping_table *et_entry)
1469991554f2SKenneth D. Merry {
1470991554f2SKenneth D. Merry struct dev_mapping_table *mt_entry;
1471991554f2SKenneth D. Merry u16 slots = et_entry->num_slots, map_idx;
1472991554f2SKenneth D. Merry u32 start_idx = et_entry->start_index;
1473327f2e6cSStephen McConnell
1474991554f2SKenneth D. Merry if (start_idx != MPR_MAPTABLE_BAD_IDX) {
1475991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[start_idx];
1476991554f2SKenneth D. Merry for (map_idx = 0; map_idx < slots; map_idx++, mt_entry++)
1477991554f2SKenneth D. Merry mt_entry->physical_id = et_entry->enclosure_id;
1478991554f2SKenneth D. Merry }
1479991554f2SKenneth D. Merry }
1480991554f2SKenneth D. Merry
1481991554f2SKenneth D. Merry /**
1482991554f2SKenneth D. Merry * _mapping_clear_removed_entries - mark the entries to be cleared
1483991554f2SKenneth D. Merry * @sc: per adapter object
1484991554f2SKenneth D. Merry *
1485991554f2SKenneth D. Merry * Search through the removal table and mark the entries which needs to be
1486991554f2SKenneth D. Merry * flushed to DPM and also updates the map table and enclosure table by
1487991554f2SKenneth D. Merry * clearing the corresponding entries.
1488991554f2SKenneth D. Merry *
1489991554f2SKenneth D. Merry * Returns nothing
1490991554f2SKenneth D. Merry */
1491991554f2SKenneth D. Merry static void
_mapping_clear_removed_entries(struct mpr_softc * sc)1492991554f2SKenneth D. Merry _mapping_clear_removed_entries(struct mpr_softc *sc)
1493991554f2SKenneth D. Merry {
1494991554f2SKenneth D. Merry u32 remove_idx;
1495991554f2SKenneth D. Merry struct map_removal_table *remove_entry;
1496991554f2SKenneth D. Merry Mpi2DriverMap0Entry_t *dpm_entry;
1497991554f2SKenneth D. Merry u8 done_flag = 0, num_entries, m, i;
1498991554f2SKenneth D. Merry struct enc_mapping_table *et_entry, *from, *to;
1499991554f2SKenneth D. Merry u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
1500991554f2SKenneth D. Merry
1501991554f2SKenneth D. Merry if (sc->is_dpm_enable) {
1502991554f2SKenneth D. Merry remove_entry = sc->removal_table;
1503991554f2SKenneth D. Merry for (remove_idx = 0; remove_idx < sc->max_devices;
1504991554f2SKenneth D. Merry remove_idx++, remove_entry++) {
1505991554f2SKenneth D. Merry if (remove_entry->dpm_entry_num != MPR_DPM_BAD_IDX) {
1506991554f2SKenneth D. Merry dpm_entry = (Mpi2DriverMap0Entry_t *)
1507991554f2SKenneth D. Merry ((u8 *) sc->dpm_pg0 +
1508991554f2SKenneth D. Merry sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
1509991554f2SKenneth D. Merry dpm_entry += remove_entry->dpm_entry_num;
1510991554f2SKenneth D. Merry dpm_entry->PhysicalIdentifier.Low = 0;
1511991554f2SKenneth D. Merry dpm_entry->PhysicalIdentifier.High = 0;
1512991554f2SKenneth D. Merry dpm_entry->DeviceIndex = 0;
1513991554f2SKenneth D. Merry dpm_entry->MappingInformation = 0;
1514991554f2SKenneth D. Merry dpm_entry->PhysicalBitsMapping = 0;
1515991554f2SKenneth D. Merry sc->dpm_flush_entry[remove_entry->
1516991554f2SKenneth D. Merry dpm_entry_num] = 1;
1517991554f2SKenneth D. Merry sc->dpm_entry_used[remove_entry->dpm_entry_num]
1518991554f2SKenneth D. Merry = 0;
1519991554f2SKenneth D. Merry remove_entry->dpm_entry_num = MPR_DPM_BAD_IDX;
1520991554f2SKenneth D. Merry }
1521991554f2SKenneth D. Merry }
1522991554f2SKenneth D. Merry }
1523327f2e6cSStephen McConnell
1524327f2e6cSStephen McConnell /*
1525327f2e6cSStephen McConnell * When using Enc/Slot mapping, if a new enclosure was added and old
1526327f2e6cSStephen McConnell * enclosure space was needed, the enclosure table may now have gaps
1527327f2e6cSStephen McConnell * that need to be closed. All enclosure mappings need to be contiguous
1528327f2e6cSStephen McConnell * so that space can be reused correctly if available.
1529327f2e6cSStephen McConnell */
1530991554f2SKenneth D. Merry if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
1531991554f2SKenneth D. Merry MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
1532991554f2SKenneth D. Merry num_entries = sc->num_enc_table_entries;
1533991554f2SKenneth D. Merry while (!done_flag) {
1534991554f2SKenneth D. Merry done_flag = 1;
1535991554f2SKenneth D. Merry et_entry = sc->enclosure_table;
1536991554f2SKenneth D. Merry for (i = 0; i < num_entries; i++, et_entry++) {
1537991554f2SKenneth D. Merry if (!et_entry->enc_handle && et_entry->
1538991554f2SKenneth D. Merry init_complete) {
1539991554f2SKenneth D. Merry done_flag = 0;
1540991554f2SKenneth D. Merry if (i != (num_entries - 1)) {
1541991554f2SKenneth D. Merry from = &sc->enclosure_table
1542991554f2SKenneth D. Merry [i+1];
1543991554f2SKenneth D. Merry to = &sc->enclosure_table[i];
1544991554f2SKenneth D. Merry for (m = i; m < (num_entries -
1545991554f2SKenneth D. Merry 1); m++, from++, to++) {
1546991554f2SKenneth D. Merry _mapping_set_mid_to_eid
1547991554f2SKenneth D. Merry (sc, to);
1548991554f2SKenneth D. Merry *to = *from;
1549991554f2SKenneth D. Merry }
1550991554f2SKenneth D. Merry _mapping_clear_enc_entry(to);
1551991554f2SKenneth D. Merry sc->num_enc_table_entries--;
1552991554f2SKenneth D. Merry num_entries =
1553991554f2SKenneth D. Merry sc->num_enc_table_entries;
1554991554f2SKenneth D. Merry } else {
1555991554f2SKenneth D. Merry _mapping_clear_enc_entry
1556991554f2SKenneth D. Merry (et_entry);
1557991554f2SKenneth D. Merry sc->num_enc_table_entries--;
1558991554f2SKenneth D. Merry num_entries =
1559991554f2SKenneth D. Merry sc->num_enc_table_entries;
1560991554f2SKenneth D. Merry }
1561991554f2SKenneth D. Merry }
1562991554f2SKenneth D. Merry }
1563991554f2SKenneth D. Merry }
1564991554f2SKenneth D. Merry }
1565991554f2SKenneth D. Merry }
1566991554f2SKenneth D. Merry
1567991554f2SKenneth D. Merry /**
1568991554f2SKenneth D. Merry * _mapping_add_new_device -Add the new device into mapping table
1569991554f2SKenneth D. Merry * @sc: per adapter object
1570991554f2SKenneth D. Merry * @topo_change: Topology change event entry
1571991554f2SKenneth D. Merry *
157267feec50SStephen McConnell * Search through the topology change event list and update map table,
157367feec50SStephen McConnell * enclosure table and DPM pages for the newly added devices.
1574991554f2SKenneth D. Merry *
1575991554f2SKenneth D. Merry * Returns nothing
1576991554f2SKenneth D. Merry */
1577991554f2SKenneth D. Merry static void
_mapping_add_new_device(struct mpr_softc * sc,struct _map_topology_change * topo_change)1578991554f2SKenneth D. Merry _mapping_add_new_device(struct mpr_softc *sc,
1579991554f2SKenneth D. Merry struct _map_topology_change *topo_change)
1580991554f2SKenneth D. Merry {
1581991554f2SKenneth D. Merry u8 enc_idx, missing_cnt, is_removed = 0;
1582991554f2SKenneth D. Merry u16 dpm_idx;
1583991554f2SKenneth D. Merry u32 search_idx, map_idx;
1584991554f2SKenneth D. Merry u32 entry;
1585991554f2SKenneth D. Merry struct dev_mapping_table *mt_entry;
1586991554f2SKenneth D. Merry struct enc_mapping_table *et_entry;
1587991554f2SKenneth D. Merry struct _map_phy_change *phy_change;
1588991554f2SKenneth D. Merry u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
1589991554f2SKenneth D. Merry Mpi2DriverMap0Entry_t *dpm_entry;
1590991554f2SKenneth D. Merry uint64_t temp64_var;
1591991554f2SKenneth D. Merry u8 map_shift = MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT;
1592991554f2SKenneth D. Merry u8 hdr_sz = sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER);
1593991554f2SKenneth D. Merry u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs);
1594991554f2SKenneth D. Merry
1595991554f2SKenneth D. Merry for (entry = 0; entry < topo_change->num_entries; entry++) {
1596991554f2SKenneth D. Merry phy_change = &topo_change->phy_details[entry];
1597991554f2SKenneth D. Merry if (phy_change->is_processed)
1598991554f2SKenneth D. Merry continue;
1599991554f2SKenneth D. Merry if (phy_change->reason != MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED ||
1600991554f2SKenneth D. Merry !phy_change->dev_handle) {
1601991554f2SKenneth D. Merry phy_change->is_processed = 1;
1602991554f2SKenneth D. Merry continue;
1603991554f2SKenneth D. Merry }
1604991554f2SKenneth D. Merry if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
1605991554f2SKenneth D. Merry MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
1606991554f2SKenneth D. Merry enc_idx = _mapping_get_enc_idx_from_handle
1607991554f2SKenneth D. Merry (sc, topo_change->enc_handle);
1608991554f2SKenneth D. Merry if (enc_idx == MPR_ENCTABLE_BAD_IDX) {
1609991554f2SKenneth D. Merry phy_change->is_processed = 1;
1610327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: "
1611327f2e6cSStephen McConnell "failed to add the device with handle "
1612b99419aeSAlexander Motin "0x%04x because enclosure handle 0x%04x "
1613b99419aeSAlexander Motin "is not in the mapping table\n", __func__,
1614b99419aeSAlexander Motin phy_change->dev_handle,
1615b99419aeSAlexander Motin topo_change->enc_handle);
1616991554f2SKenneth D. Merry continue;
1617991554f2SKenneth D. Merry }
1618327f2e6cSStephen McConnell
1619327f2e6cSStephen McConnell /*
1620327f2e6cSStephen McConnell * If the enclosure's start_index is BAD here, it means
1621327f2e6cSStephen McConnell * that there is no room in the mapping table to cover
1622327f2e6cSStephen McConnell * all of the devices that could be in the enclosure.
1623327f2e6cSStephen McConnell * There's no reason to process any of the devices for
1624327f2e6cSStephen McConnell * this enclosure since they can't be mapped.
1625327f2e6cSStephen McConnell */
1626327f2e6cSStephen McConnell et_entry = &sc->enclosure_table[enc_idx];
1627327f2e6cSStephen McConnell if (et_entry->start_index == MPR_MAPTABLE_BAD_IDX) {
1628327f2e6cSStephen McConnell phy_change->is_processed = 1;
1629327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: "
1630327f2e6cSStephen McConnell "failed to add the device with handle "
1631327f2e6cSStephen McConnell "0x%04x because there is no free space "
1632327f2e6cSStephen McConnell "available in the mapping table\n",
1633327f2e6cSStephen McConnell __func__, phy_change->dev_handle);
1634327f2e6cSStephen McConnell continue;
1635327f2e6cSStephen McConnell }
1636327f2e6cSStephen McConnell
1637327f2e6cSStephen McConnell /*
1638327f2e6cSStephen McConnell * Add this device to the mapping table at the correct
1639327f2e6cSStephen McConnell * offset where space was found to map the enclosure.
1640327f2e6cSStephen McConnell * Then setup the DPM entry information if being used.
1641327f2e6cSStephen McConnell */
1642991554f2SKenneth D. Merry map_idx = et_entry->start_index + phy_change->slot -
1643991554f2SKenneth D. Merry et_entry->start_slot;
1644991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[map_idx];
1645991554f2SKenneth D. Merry mt_entry->physical_id = phy_change->physical_id;
1646991554f2SKenneth D. Merry mt_entry->id = map_idx;
1647991554f2SKenneth D. Merry mt_entry->dev_handle = phy_change->dev_handle;
1648991554f2SKenneth D. Merry mt_entry->missing_count = 0;
1649991554f2SKenneth D. Merry mt_entry->dpm_entry_num = et_entry->dpm_entry_num;
1650991554f2SKenneth D. Merry mt_entry->device_info = phy_change->device_info |
1651991554f2SKenneth D. Merry (MPR_DEV_RESERVED | MPR_MAP_IN_USE);
1652991554f2SKenneth D. Merry if (sc->is_dpm_enable) {
1653991554f2SKenneth D. Merry dpm_idx = et_entry->dpm_entry_num;
1654991554f2SKenneth D. Merry if (dpm_idx == MPR_DPM_BAD_IDX)
1655991554f2SKenneth D. Merry dpm_idx = _mapping_get_dpm_idx_from_id
1656991554f2SKenneth D. Merry (sc, et_entry->enclosure_id,
1657991554f2SKenneth D. Merry et_entry->phy_bits);
1658991554f2SKenneth D. Merry if (dpm_idx == MPR_DPM_BAD_IDX) {
1659991554f2SKenneth D. Merry dpm_idx = _mapping_get_free_dpm_idx(sc);
1660991554f2SKenneth D. Merry if (dpm_idx != MPR_DPM_BAD_IDX) {
1661991554f2SKenneth D. Merry dpm_entry =
1662991554f2SKenneth D. Merry (Mpi2DriverMap0Entry_t *)
1663991554f2SKenneth D. Merry ((u8 *) sc->dpm_pg0 +
1664991554f2SKenneth D. Merry hdr_sz);
1665991554f2SKenneth D. Merry dpm_entry += dpm_idx;
1666991554f2SKenneth D. Merry dpm_entry->
1667991554f2SKenneth D. Merry PhysicalIdentifier.Low =
1668991554f2SKenneth D. Merry (0xFFFFFFFF &
1669991554f2SKenneth D. Merry et_entry->enclosure_id);
1670991554f2SKenneth D. Merry dpm_entry->
1671991554f2SKenneth D. Merry PhysicalIdentifier.High =
1672991554f2SKenneth D. Merry (et_entry->enclosure_id
1673991554f2SKenneth D. Merry >> 32);
1674991554f2SKenneth D. Merry dpm_entry->DeviceIndex =
1675991554f2SKenneth D. Merry (U16)et_entry->start_index;
1676991554f2SKenneth D. Merry dpm_entry->MappingInformation =
1677991554f2SKenneth D. Merry et_entry->num_slots;
1678991554f2SKenneth D. Merry dpm_entry->MappingInformation
1679991554f2SKenneth D. Merry <<= map_shift;
1680991554f2SKenneth D. Merry dpm_entry->PhysicalBitsMapping
1681991554f2SKenneth D. Merry = et_entry->phy_bits;
1682991554f2SKenneth D. Merry et_entry->dpm_entry_num =
1683991554f2SKenneth D. Merry dpm_idx;
1684991554f2SKenneth D. Merry sc->dpm_entry_used[dpm_idx] = 1;
1685991554f2SKenneth D. Merry sc->dpm_flush_entry[dpm_idx] =
1686991554f2SKenneth D. Merry 1;
1687991554f2SKenneth D. Merry phy_change->is_processed = 1;
1688991554f2SKenneth D. Merry } else {
1689991554f2SKenneth D. Merry phy_change->is_processed = 1;
1690327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR |
1691327f2e6cSStephen McConnell MPR_MAPPING, "%s: failed "
1692327f2e6cSStephen McConnell "to add the device with "
1693327f2e6cSStephen McConnell "handle 0x%04x to "
1694991554f2SKenneth D. Merry "persistent table because "
1695991554f2SKenneth D. Merry "there is no free space "
1696991554f2SKenneth D. Merry "available\n", __func__,
1697991554f2SKenneth D. Merry phy_change->dev_handle);
1698991554f2SKenneth D. Merry }
1699991554f2SKenneth D. Merry } else {
1700991554f2SKenneth D. Merry et_entry->dpm_entry_num = dpm_idx;
1701991554f2SKenneth D. Merry mt_entry->dpm_entry_num = dpm_idx;
1702991554f2SKenneth D. Merry }
1703991554f2SKenneth D. Merry }
1704991554f2SKenneth D. Merry et_entry->init_complete = 1;
1705991554f2SKenneth D. Merry } else if ((ioc_pg8_flags &
1706991554f2SKenneth D. Merry MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
1707991554f2SKenneth D. Merry MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
1708327f2e6cSStephen McConnell /*
1709327f2e6cSStephen McConnell * Get the mapping table index for this device. If it's
1710327f2e6cSStephen McConnell * not in the mapping table yet, find a free entry if
1711327f2e6cSStephen McConnell * one is available. If there are no free entries, look
1712327f2e6cSStephen McConnell * for the entry that has the highest missing count. If
1713327f2e6cSStephen McConnell * none of that works to find an entry in the mapping
1714327f2e6cSStephen McConnell * table, there is a problem. Log a message and just
1715327f2e6cSStephen McConnell * continue on.
1716327f2e6cSStephen McConnell */
1717991554f2SKenneth D. Merry map_idx = _mapping_get_mt_idx_from_id
1718991554f2SKenneth D. Merry (sc, phy_change->physical_id);
1719991554f2SKenneth D. Merry if (map_idx == MPR_MAPTABLE_BAD_IDX) {
1720991554f2SKenneth D. Merry search_idx = sc->num_rsvd_entries;
1721991554f2SKenneth D. Merry if (topo_change->exp_handle)
1722991554f2SKenneth D. Merry search_idx += max_num_phy_ids;
1723991554f2SKenneth D. Merry map_idx = _mapping_get_free_mt_idx(sc,
1724991554f2SKenneth D. Merry search_idx);
1725991554f2SKenneth D. Merry }
1726327f2e6cSStephen McConnell
1727327f2e6cSStephen McConnell /*
1728327f2e6cSStephen McConnell * If an entry will be used that has a missing device,
1729327f2e6cSStephen McConnell * clear its entry from the DPM in the controller.
1730327f2e6cSStephen McConnell */
1731991554f2SKenneth D. Merry if (map_idx == MPR_MAPTABLE_BAD_IDX) {
1732991554f2SKenneth D. Merry map_idx = _mapping_get_high_missing_mt_idx(sc);
1733991554f2SKenneth D. Merry if (map_idx != MPR_MAPTABLE_BAD_IDX) {
1734991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[map_idx];
1735327f2e6cSStephen McConnell _mapping_add_to_removal_table(sc,
1736327f2e6cSStephen McConnell mt_entry->dpm_entry_num);
1737991554f2SKenneth D. Merry is_removed = 1;
1738991554f2SKenneth D. Merry mt_entry->init_complete = 0;
1739991554f2SKenneth D. Merry }
1740991554f2SKenneth D. Merry }
1741991554f2SKenneth D. Merry if (map_idx != MPR_MAPTABLE_BAD_IDX) {
1742991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[map_idx];
1743991554f2SKenneth D. Merry mt_entry->physical_id = phy_change->physical_id;
1744991554f2SKenneth D. Merry mt_entry->id = map_idx;
1745991554f2SKenneth D. Merry mt_entry->dev_handle = phy_change->dev_handle;
1746991554f2SKenneth D. Merry mt_entry->missing_count = 0;
1747991554f2SKenneth D. Merry mt_entry->device_info = phy_change->device_info
1748991554f2SKenneth D. Merry | (MPR_DEV_RESERVED | MPR_MAP_IN_USE);
1749991554f2SKenneth D. Merry } else {
1750991554f2SKenneth D. Merry phy_change->is_processed = 1;
1751327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: "
1752327f2e6cSStephen McConnell "failed to add the device with handle "
1753327f2e6cSStephen McConnell "0x%04x because there is no free space "
1754327f2e6cSStephen McConnell "available in the mapping table\n",
1755327f2e6cSStephen McConnell __func__, phy_change->dev_handle);
1756991554f2SKenneth D. Merry continue;
1757991554f2SKenneth D. Merry }
1758991554f2SKenneth D. Merry if (sc->is_dpm_enable) {
1759991554f2SKenneth D. Merry if (mt_entry->dpm_entry_num !=
1760991554f2SKenneth D. Merry MPR_DPM_BAD_IDX) {
1761991554f2SKenneth D. Merry dpm_idx = mt_entry->dpm_entry_num;
1762991554f2SKenneth D. Merry dpm_entry = (Mpi2DriverMap0Entry_t *)
1763991554f2SKenneth D. Merry ((u8 *)sc->dpm_pg0 + hdr_sz);
1764991554f2SKenneth D. Merry dpm_entry += dpm_idx;
1765991554f2SKenneth D. Merry missing_cnt = dpm_entry->
1766991554f2SKenneth D. Merry MappingInformation &
1767991554f2SKenneth D. Merry MPI2_DRVMAP0_MAPINFO_MISSING_MASK;
1768991554f2SKenneth D. Merry temp64_var = dpm_entry->
1769991554f2SKenneth D. Merry PhysicalIdentifier.High;
1770991554f2SKenneth D. Merry temp64_var = (temp64_var << 32) |
1771991554f2SKenneth D. Merry dpm_entry->PhysicalIdentifier.Low;
1772327f2e6cSStephen McConnell
1773327f2e6cSStephen McConnell /*
1774327f2e6cSStephen McConnell * If the Mapping Table's info is not
1775327f2e6cSStephen McConnell * the same as the DPM entry, clear the
1776327f2e6cSStephen McConnell * init_complete flag so that it's
1777327f2e6cSStephen McConnell * updated.
1778327f2e6cSStephen McConnell */
1779991554f2SKenneth D. Merry if ((mt_entry->physical_id ==
1780991554f2SKenneth D. Merry temp64_var) && !missing_cnt)
1781991554f2SKenneth D. Merry mt_entry->init_complete = 1;
1782327f2e6cSStephen McConnell else
1783327f2e6cSStephen McConnell mt_entry->init_complete = 0;
1784991554f2SKenneth D. Merry } else {
1785991554f2SKenneth D. Merry dpm_idx = _mapping_get_free_dpm_idx(sc);
1786991554f2SKenneth D. Merry mt_entry->init_complete = 0;
1787991554f2SKenneth D. Merry }
1788991554f2SKenneth D. Merry if (dpm_idx != MPR_DPM_BAD_IDX &&
1789991554f2SKenneth D. Merry !mt_entry->init_complete) {
1790991554f2SKenneth D. Merry mt_entry->dpm_entry_num = dpm_idx;
1791991554f2SKenneth D. Merry dpm_entry = (Mpi2DriverMap0Entry_t *)
1792991554f2SKenneth D. Merry ((u8 *)sc->dpm_pg0 + hdr_sz);
1793991554f2SKenneth D. Merry dpm_entry += dpm_idx;
1794991554f2SKenneth D. Merry dpm_entry->PhysicalIdentifier.Low =
1795991554f2SKenneth D. Merry (0xFFFFFFFF &
1796991554f2SKenneth D. Merry mt_entry->physical_id);
1797991554f2SKenneth D. Merry dpm_entry->PhysicalIdentifier.High =
1798991554f2SKenneth D. Merry (mt_entry->physical_id >> 32);
1799991554f2SKenneth D. Merry dpm_entry->DeviceIndex = (U16) map_idx;
1800991554f2SKenneth D. Merry dpm_entry->MappingInformation = 0;
1801991554f2SKenneth D. Merry dpm_entry->PhysicalBitsMapping = 0;
1802991554f2SKenneth D. Merry sc->dpm_entry_used[dpm_idx] = 1;
1803991554f2SKenneth D. Merry sc->dpm_flush_entry[dpm_idx] = 1;
1804991554f2SKenneth D. Merry phy_change->is_processed = 1;
1805991554f2SKenneth D. Merry } else if (dpm_idx == MPR_DPM_BAD_IDX) {
1806991554f2SKenneth D. Merry phy_change->is_processed = 1;
1807327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING,
1808327f2e6cSStephen McConnell "%s: failed to add the device with "
1809327f2e6cSStephen McConnell "handle 0x%04x to persistent table "
181067feec50SStephen McConnell "because there is no free space "
1811991554f2SKenneth D. Merry "available\n", __func__,
1812991554f2SKenneth D. Merry phy_change->dev_handle);
1813991554f2SKenneth D. Merry }
1814991554f2SKenneth D. Merry }
1815991554f2SKenneth D. Merry mt_entry->init_complete = 1;
1816991554f2SKenneth D. Merry }
1817991554f2SKenneth D. Merry
1818991554f2SKenneth D. Merry phy_change->is_processed = 1;
1819991554f2SKenneth D. Merry }
1820991554f2SKenneth D. Merry if (is_removed)
1821991554f2SKenneth D. Merry _mapping_clear_removed_entries(sc);
1822991554f2SKenneth D. Merry }
1823991554f2SKenneth D. Merry
1824991554f2SKenneth D. Merry /**
182567feec50SStephen McConnell * _mapping_add_new_pcie_device -Add the new PCIe device into mapping table
182667feec50SStephen McConnell * @sc: per adapter object
182767feec50SStephen McConnell * @topo_change: Topology change event entry
182867feec50SStephen McConnell *
182967feec50SStephen McConnell * Search through the PCIe topology change event list and update map table,
183067feec50SStephen McConnell * enclosure table and DPM pages for the newly added devices.
183167feec50SStephen McConnell *
183267feec50SStephen McConnell * Returns nothing
183367feec50SStephen McConnell */
183467feec50SStephen McConnell static void
_mapping_add_new_pcie_device(struct mpr_softc * sc,struct _map_pcie_topology_change * topo_change)183567feec50SStephen McConnell _mapping_add_new_pcie_device(struct mpr_softc *sc,
183667feec50SStephen McConnell struct _map_pcie_topology_change *topo_change)
183767feec50SStephen McConnell {
183867feec50SStephen McConnell u8 enc_idx, missing_cnt, is_removed = 0;
183967feec50SStephen McConnell u16 dpm_idx;
184067feec50SStephen McConnell u32 search_idx, map_idx;
184167feec50SStephen McConnell u32 entry;
184267feec50SStephen McConnell struct dev_mapping_table *mt_entry;
184367feec50SStephen McConnell struct enc_mapping_table *et_entry;
184467feec50SStephen McConnell struct _map_port_change *port_change;
184567feec50SStephen McConnell u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
184667feec50SStephen McConnell Mpi2DriverMap0Entry_t *dpm_entry;
184767feec50SStephen McConnell uint64_t temp64_var;
184867feec50SStephen McConnell u8 map_shift = MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT;
184967feec50SStephen McConnell u8 hdr_sz = sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER);
185067feec50SStephen McConnell u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs);
185167feec50SStephen McConnell
185267feec50SStephen McConnell for (entry = 0; entry < topo_change->num_entries; entry++) {
185367feec50SStephen McConnell port_change = &topo_change->port_details[entry];
185467feec50SStephen McConnell if (port_change->is_processed)
185567feec50SStephen McConnell continue;
185667feec50SStephen McConnell if (port_change->reason != MPI26_EVENT_PCIE_TOPO_PS_DEV_ADDED ||
185767feec50SStephen McConnell !port_change->dev_handle) {
185867feec50SStephen McConnell port_change->is_processed = 1;
185967feec50SStephen McConnell continue;
186067feec50SStephen McConnell }
186167feec50SStephen McConnell if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
186267feec50SStephen McConnell MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
186367feec50SStephen McConnell enc_idx = _mapping_get_enc_idx_from_handle
186467feec50SStephen McConnell (sc, topo_change->enc_handle);
186567feec50SStephen McConnell if (enc_idx == MPR_ENCTABLE_BAD_IDX) {
186667feec50SStephen McConnell port_change->is_processed = 1;
1867327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: "
1868327f2e6cSStephen McConnell "failed to add the device with handle "
1869b99419aeSAlexander Motin "0x%04x because enclosure handle 0x%04x "
1870b99419aeSAlexander Motin "is not in the mapping table\n", __func__,
1871b99419aeSAlexander Motin port_change->dev_handle,
1872b99419aeSAlexander Motin topo_change->enc_handle);
187367feec50SStephen McConnell continue;
187467feec50SStephen McConnell }
1875327f2e6cSStephen McConnell
1876327f2e6cSStephen McConnell /*
1877327f2e6cSStephen McConnell * If the enclosure's start_index is BAD here, it means
1878327f2e6cSStephen McConnell * that there is no room in the mapping table to cover
1879327f2e6cSStephen McConnell * all of the devices that could be in the enclosure.
1880327f2e6cSStephen McConnell * There's no reason to process any of the devices for
1881327f2e6cSStephen McConnell * this enclosure since they can't be mapped.
1882327f2e6cSStephen McConnell */
1883327f2e6cSStephen McConnell et_entry = &sc->enclosure_table[enc_idx];
1884327f2e6cSStephen McConnell if (et_entry->start_index == MPR_MAPTABLE_BAD_IDX) {
1885327f2e6cSStephen McConnell port_change->is_processed = 1;
1886327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: "
1887327f2e6cSStephen McConnell "failed to add the device with handle "
1888327f2e6cSStephen McConnell "0x%04x because there is no free space "
1889327f2e6cSStephen McConnell "available in the mapping table\n",
1890327f2e6cSStephen McConnell __func__, port_change->dev_handle);
1891327f2e6cSStephen McConnell continue;
1892327f2e6cSStephen McConnell }
1893327f2e6cSStephen McConnell
1894327f2e6cSStephen McConnell /*
1895327f2e6cSStephen McConnell * Add this device to the mapping table at the correct
1896327f2e6cSStephen McConnell * offset where space was found to map the enclosure.
1897327f2e6cSStephen McConnell * Then setup the DPM entry information if being used.
1898327f2e6cSStephen McConnell */
189967feec50SStephen McConnell map_idx = et_entry->start_index + port_change->slot -
190067feec50SStephen McConnell et_entry->start_slot;
190167feec50SStephen McConnell mt_entry = &sc->mapping_table[map_idx];
190267feec50SStephen McConnell mt_entry->physical_id = port_change->physical_id;
190367feec50SStephen McConnell mt_entry->id = map_idx;
190467feec50SStephen McConnell mt_entry->dev_handle = port_change->dev_handle;
190567feec50SStephen McConnell mt_entry->missing_count = 0;
190667feec50SStephen McConnell mt_entry->dpm_entry_num = et_entry->dpm_entry_num;
190767feec50SStephen McConnell mt_entry->device_info = port_change->device_info |
190867feec50SStephen McConnell (MPR_DEV_RESERVED | MPR_MAP_IN_USE);
190967feec50SStephen McConnell if (sc->is_dpm_enable) {
191067feec50SStephen McConnell dpm_idx = et_entry->dpm_entry_num;
191167feec50SStephen McConnell if (dpm_idx == MPR_DPM_BAD_IDX)
191267feec50SStephen McConnell dpm_idx = _mapping_get_dpm_idx_from_id
191367feec50SStephen McConnell (sc, et_entry->enclosure_id,
191467feec50SStephen McConnell et_entry->phy_bits);
191567feec50SStephen McConnell if (dpm_idx == MPR_DPM_BAD_IDX) {
191667feec50SStephen McConnell dpm_idx = _mapping_get_free_dpm_idx(sc);
191767feec50SStephen McConnell if (dpm_idx != MPR_DPM_BAD_IDX) {
191867feec50SStephen McConnell dpm_entry =
191967feec50SStephen McConnell (Mpi2DriverMap0Entry_t *)
192067feec50SStephen McConnell ((u8 *) sc->dpm_pg0 +
192167feec50SStephen McConnell hdr_sz);
192267feec50SStephen McConnell dpm_entry += dpm_idx;
192367feec50SStephen McConnell dpm_entry->
192467feec50SStephen McConnell PhysicalIdentifier.Low =
192567feec50SStephen McConnell (0xFFFFFFFF &
192667feec50SStephen McConnell et_entry->enclosure_id);
192767feec50SStephen McConnell dpm_entry->
192867feec50SStephen McConnell PhysicalIdentifier.High =
192967feec50SStephen McConnell (et_entry->enclosure_id
193067feec50SStephen McConnell >> 32);
193167feec50SStephen McConnell dpm_entry->DeviceIndex =
193267feec50SStephen McConnell (U16)et_entry->start_index;
193367feec50SStephen McConnell dpm_entry->MappingInformation =
193467feec50SStephen McConnell et_entry->num_slots;
193567feec50SStephen McConnell dpm_entry->MappingInformation
193667feec50SStephen McConnell <<= map_shift;
193767feec50SStephen McConnell dpm_entry->PhysicalBitsMapping
193867feec50SStephen McConnell = et_entry->phy_bits;
193967feec50SStephen McConnell et_entry->dpm_entry_num =
194067feec50SStephen McConnell dpm_idx;
194167feec50SStephen McConnell sc->dpm_entry_used[dpm_idx] = 1;
194267feec50SStephen McConnell sc->dpm_flush_entry[dpm_idx] =
194367feec50SStephen McConnell 1;
194467feec50SStephen McConnell port_change->is_processed = 1;
194567feec50SStephen McConnell } else {
194667feec50SStephen McConnell port_change->is_processed = 1;
1947327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR |
1948327f2e6cSStephen McConnell MPR_MAPPING, "%s: failed "
1949327f2e6cSStephen McConnell "to add the device with "
1950327f2e6cSStephen McConnell "handle 0x%04x to "
195167feec50SStephen McConnell "persistent table because "
195267feec50SStephen McConnell "there is no free space "
195367feec50SStephen McConnell "available\n", __func__,
195467feec50SStephen McConnell port_change->dev_handle);
195567feec50SStephen McConnell }
195667feec50SStephen McConnell } else {
195767feec50SStephen McConnell et_entry->dpm_entry_num = dpm_idx;
195867feec50SStephen McConnell mt_entry->dpm_entry_num = dpm_idx;
195967feec50SStephen McConnell }
196067feec50SStephen McConnell }
196167feec50SStephen McConnell et_entry->init_complete = 1;
196267feec50SStephen McConnell } else if ((ioc_pg8_flags &
196367feec50SStephen McConnell MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
196467feec50SStephen McConnell MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
1965327f2e6cSStephen McConnell /*
1966327f2e6cSStephen McConnell * Get the mapping table index for this device. If it's
1967327f2e6cSStephen McConnell * not in the mapping table yet, find a free entry if
1968327f2e6cSStephen McConnell * one is available. If there are no free entries, look
1969327f2e6cSStephen McConnell * for the entry that has the highest missing count. If
1970327f2e6cSStephen McConnell * none of that works to find an entry in the mapping
1971327f2e6cSStephen McConnell * table, there is a problem. Log a message and just
1972327f2e6cSStephen McConnell * continue on.
1973327f2e6cSStephen McConnell */
197467feec50SStephen McConnell map_idx = _mapping_get_mt_idx_from_id
197567feec50SStephen McConnell (sc, port_change->physical_id);
197667feec50SStephen McConnell if (map_idx == MPR_MAPTABLE_BAD_IDX) {
197767feec50SStephen McConnell search_idx = sc->num_rsvd_entries;
197867feec50SStephen McConnell if (topo_change->switch_dev_handle)
197967feec50SStephen McConnell search_idx += max_num_phy_ids;
198067feec50SStephen McConnell map_idx = _mapping_get_free_mt_idx(sc,
198167feec50SStephen McConnell search_idx);
198267feec50SStephen McConnell }
1983327f2e6cSStephen McConnell
1984327f2e6cSStephen McConnell /*
1985327f2e6cSStephen McConnell * If an entry will be used that has a missing device,
1986327f2e6cSStephen McConnell * clear its entry from the DPM in the controller.
1987327f2e6cSStephen McConnell */
198867feec50SStephen McConnell if (map_idx == MPR_MAPTABLE_BAD_IDX) {
198967feec50SStephen McConnell map_idx = _mapping_get_high_missing_mt_idx(sc);
199067feec50SStephen McConnell if (map_idx != MPR_MAPTABLE_BAD_IDX) {
199167feec50SStephen McConnell mt_entry = &sc->mapping_table[map_idx];
1992327f2e6cSStephen McConnell _mapping_add_to_removal_table(sc,
1993327f2e6cSStephen McConnell mt_entry->dpm_entry_num);
199467feec50SStephen McConnell is_removed = 1;
199567feec50SStephen McConnell mt_entry->init_complete = 0;
199667feec50SStephen McConnell }
199767feec50SStephen McConnell }
199867feec50SStephen McConnell if (map_idx != MPR_MAPTABLE_BAD_IDX) {
199967feec50SStephen McConnell mt_entry = &sc->mapping_table[map_idx];
200067feec50SStephen McConnell mt_entry->physical_id =
200167feec50SStephen McConnell port_change->physical_id;
200267feec50SStephen McConnell mt_entry->id = map_idx;
200367feec50SStephen McConnell mt_entry->dev_handle = port_change->dev_handle;
200467feec50SStephen McConnell mt_entry->missing_count = 0;
200567feec50SStephen McConnell mt_entry->device_info =
200667feec50SStephen McConnell port_change->device_info |
200767feec50SStephen McConnell (MPR_DEV_RESERVED | MPR_MAP_IN_USE);
200867feec50SStephen McConnell } else {
200967feec50SStephen McConnell port_change->is_processed = 1;
2010327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: "
2011327f2e6cSStephen McConnell "failed to add the device with handle "
2012327f2e6cSStephen McConnell "0x%04x because there is no free space "
2013327f2e6cSStephen McConnell "available in the mapping table\n",
2014327f2e6cSStephen McConnell __func__, port_change->dev_handle);
201567feec50SStephen McConnell continue;
201667feec50SStephen McConnell }
201767feec50SStephen McConnell if (sc->is_dpm_enable) {
201867feec50SStephen McConnell if (mt_entry->dpm_entry_num !=
201967feec50SStephen McConnell MPR_DPM_BAD_IDX) {
202067feec50SStephen McConnell dpm_idx = mt_entry->dpm_entry_num;
202167feec50SStephen McConnell dpm_entry = (Mpi2DriverMap0Entry_t *)
202267feec50SStephen McConnell ((u8 *)sc->dpm_pg0 + hdr_sz);
202367feec50SStephen McConnell dpm_entry += dpm_idx;
202467feec50SStephen McConnell missing_cnt = dpm_entry->
202567feec50SStephen McConnell MappingInformation &
202667feec50SStephen McConnell MPI2_DRVMAP0_MAPINFO_MISSING_MASK;
202767feec50SStephen McConnell temp64_var = dpm_entry->
202867feec50SStephen McConnell PhysicalIdentifier.High;
202967feec50SStephen McConnell temp64_var = (temp64_var << 32) |
203067feec50SStephen McConnell dpm_entry->PhysicalIdentifier.Low;
2031327f2e6cSStephen McConnell
2032327f2e6cSStephen McConnell /*
2033327f2e6cSStephen McConnell * If the Mapping Table's info is not
2034327f2e6cSStephen McConnell * the same as the DPM entry, clear the
2035327f2e6cSStephen McConnell * init_complete flag so that it's
2036327f2e6cSStephen McConnell * updated.
2037327f2e6cSStephen McConnell */
203867feec50SStephen McConnell if ((mt_entry->physical_id ==
203967feec50SStephen McConnell temp64_var) && !missing_cnt)
204067feec50SStephen McConnell mt_entry->init_complete = 1;
2041327f2e6cSStephen McConnell else
2042327f2e6cSStephen McConnell mt_entry->init_complete = 0;
204367feec50SStephen McConnell } else {
204467feec50SStephen McConnell dpm_idx = _mapping_get_free_dpm_idx(sc);
204567feec50SStephen McConnell mt_entry->init_complete = 0;
204667feec50SStephen McConnell }
204767feec50SStephen McConnell if (dpm_idx != MPR_DPM_BAD_IDX &&
204867feec50SStephen McConnell !mt_entry->init_complete) {
204967feec50SStephen McConnell mt_entry->dpm_entry_num = dpm_idx;
205067feec50SStephen McConnell dpm_entry = (Mpi2DriverMap0Entry_t *)
205167feec50SStephen McConnell ((u8 *)sc->dpm_pg0 + hdr_sz);
205267feec50SStephen McConnell dpm_entry += dpm_idx;
205367feec50SStephen McConnell dpm_entry->PhysicalIdentifier.Low =
205467feec50SStephen McConnell (0xFFFFFFFF &
205567feec50SStephen McConnell mt_entry->physical_id);
205667feec50SStephen McConnell dpm_entry->PhysicalIdentifier.High =
205767feec50SStephen McConnell (mt_entry->physical_id >> 32);
205867feec50SStephen McConnell dpm_entry->DeviceIndex = (U16) map_idx;
205967feec50SStephen McConnell dpm_entry->MappingInformation = 0;
206067feec50SStephen McConnell dpm_entry->PhysicalBitsMapping = 0;
206167feec50SStephen McConnell sc->dpm_entry_used[dpm_idx] = 1;
206267feec50SStephen McConnell sc->dpm_flush_entry[dpm_idx] = 1;
206367feec50SStephen McConnell port_change->is_processed = 1;
206467feec50SStephen McConnell } else if (dpm_idx == MPR_DPM_BAD_IDX) {
206567feec50SStephen McConnell port_change->is_processed = 1;
2066327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING,
2067327f2e6cSStephen McConnell "%s: failed to add the device with "
2068327f2e6cSStephen McConnell "handle 0x%04x to persistent table "
206967feec50SStephen McConnell "because there is no free space "
207067feec50SStephen McConnell "available\n", __func__,
207167feec50SStephen McConnell port_change->dev_handle);
207267feec50SStephen McConnell }
207367feec50SStephen McConnell }
207467feec50SStephen McConnell mt_entry->init_complete = 1;
207567feec50SStephen McConnell }
207667feec50SStephen McConnell
207767feec50SStephen McConnell port_change->is_processed = 1;
207867feec50SStephen McConnell }
207967feec50SStephen McConnell if (is_removed)
208067feec50SStephen McConnell _mapping_clear_removed_entries(sc);
208167feec50SStephen McConnell }
208267feec50SStephen McConnell
208367feec50SStephen McConnell /**
2084991554f2SKenneth D. Merry * _mapping_flush_dpm_pages -Flush the DPM pages to NVRAM
2085991554f2SKenneth D. Merry * @sc: per adapter object
2086991554f2SKenneth D. Merry *
2087991554f2SKenneth D. Merry * Returns nothing
2088991554f2SKenneth D. Merry */
2089991554f2SKenneth D. Merry static void
_mapping_flush_dpm_pages(struct mpr_softc * sc)2090991554f2SKenneth D. Merry _mapping_flush_dpm_pages(struct mpr_softc *sc)
2091991554f2SKenneth D. Merry {
2092991554f2SKenneth D. Merry Mpi2DriverMap0Entry_t *dpm_entry;
2093991554f2SKenneth D. Merry Mpi2ConfigReply_t mpi_reply;
2094991554f2SKenneth D. Merry Mpi2DriverMappingPage0_t config_page;
2095991554f2SKenneth D. Merry u16 entry_num;
2096991554f2SKenneth D. Merry
2097991554f2SKenneth D. Merry for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++) {
2098991554f2SKenneth D. Merry if (!sc->dpm_flush_entry[entry_num])
2099991554f2SKenneth D. Merry continue;
2100991554f2SKenneth D. Merry memset(&config_page, 0, sizeof(Mpi2DriverMappingPage0_t));
2101991554f2SKenneth D. Merry memcpy(&config_page.Header, (u8 *)sc->dpm_pg0,
2102991554f2SKenneth D. Merry sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
2103991554f2SKenneth D. Merry dpm_entry = (Mpi2DriverMap0Entry_t *) ((u8 *)sc->dpm_pg0 +
2104991554f2SKenneth D. Merry sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
2105991554f2SKenneth D. Merry dpm_entry += entry_num;
2106991554f2SKenneth D. Merry dpm_entry->MappingInformation = htole16(dpm_entry->
2107991554f2SKenneth D. Merry MappingInformation);
2108991554f2SKenneth D. Merry dpm_entry->DeviceIndex = htole16(dpm_entry->DeviceIndex);
2109991554f2SKenneth D. Merry dpm_entry->PhysicalBitsMapping = htole32(dpm_entry->
2110991554f2SKenneth D. Merry PhysicalBitsMapping);
2111991554f2SKenneth D. Merry memcpy(&config_page.Entry, (u8 *)dpm_entry,
2112991554f2SKenneth D. Merry sizeof(Mpi2DriverMap0Entry_t));
2113991554f2SKenneth D. Merry /* TODO-How to handle failed writes? */
2114327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Flushing DPM entry %d.\n",
2115327f2e6cSStephen McConnell __func__, entry_num);
2116991554f2SKenneth D. Merry if (mpr_config_set_dpm_pg0(sc, &mpi_reply, &config_page,
2117991554f2SKenneth D. Merry entry_num)) {
2118327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: Flush of "
2119327f2e6cSStephen McConnell "DPM entry %d for device failed\n", __func__,
2120327f2e6cSStephen McConnell entry_num);
2121991554f2SKenneth D. Merry } else
2122991554f2SKenneth D. Merry sc->dpm_flush_entry[entry_num] = 0;
2123991554f2SKenneth D. Merry dpm_entry->MappingInformation = le16toh(dpm_entry->
2124991554f2SKenneth D. Merry MappingInformation);
2125991554f2SKenneth D. Merry dpm_entry->DeviceIndex = le16toh(dpm_entry->DeviceIndex);
2126991554f2SKenneth D. Merry dpm_entry->PhysicalBitsMapping = le32toh(dpm_entry->
2127991554f2SKenneth D. Merry PhysicalBitsMapping);
2128991554f2SKenneth D. Merry }
2129991554f2SKenneth D. Merry }
2130991554f2SKenneth D. Merry
2131991554f2SKenneth D. Merry /**
2132991554f2SKenneth D. Merry * _mapping_allocate_memory- allocates the memory required for mapping tables
2133991554f2SKenneth D. Merry * @sc: per adapter object
2134991554f2SKenneth D. Merry *
2135991554f2SKenneth D. Merry * Allocates the memory for all the tables required for host mapping
2136991554f2SKenneth D. Merry *
2137991554f2SKenneth D. Merry * Return 0 on success or non-zero on failure.
2138991554f2SKenneth D. Merry */
2139991554f2SKenneth D. Merry int
mpr_mapping_allocate_memory(struct mpr_softc * sc)2140991554f2SKenneth D. Merry mpr_mapping_allocate_memory(struct mpr_softc *sc)
2141991554f2SKenneth D. Merry {
2142991554f2SKenneth D. Merry uint32_t dpm_pg0_sz;
2143991554f2SKenneth D. Merry
2144ac2fffa4SPedro F. Giffuni sc->mapping_table = malloc((sizeof(struct dev_mapping_table) *
2145ac2fffa4SPedro F. Giffuni sc->max_devices), M_MPR, M_ZERO|M_NOWAIT);
2146991554f2SKenneth D. Merry if (!sc->mapping_table)
2147991554f2SKenneth D. Merry goto free_resources;
2148991554f2SKenneth D. Merry
2149ac2fffa4SPedro F. Giffuni sc->removal_table = malloc((sizeof(struct map_removal_table) *
2150ac2fffa4SPedro F. Giffuni sc->max_devices), M_MPR, M_ZERO|M_NOWAIT);
2151991554f2SKenneth D. Merry if (!sc->removal_table)
2152991554f2SKenneth D. Merry goto free_resources;
2153991554f2SKenneth D. Merry
2154ac2fffa4SPedro F. Giffuni sc->enclosure_table = malloc((sizeof(struct enc_mapping_table) *
2155ac2fffa4SPedro F. Giffuni sc->max_enclosures), M_MPR, M_ZERO|M_NOWAIT);
2156991554f2SKenneth D. Merry if (!sc->enclosure_table)
2157991554f2SKenneth D. Merry goto free_resources;
2158991554f2SKenneth D. Merry
2159ac2fffa4SPedro F. Giffuni sc->dpm_entry_used = malloc((sizeof(u8) * sc->max_dpm_entries),
2160991554f2SKenneth D. Merry M_MPR, M_ZERO|M_NOWAIT);
2161991554f2SKenneth D. Merry if (!sc->dpm_entry_used)
2162991554f2SKenneth D. Merry goto free_resources;
2163991554f2SKenneth D. Merry
2164ac2fffa4SPedro F. Giffuni sc->dpm_flush_entry = malloc((sizeof(u8) * sc->max_dpm_entries),
2165991554f2SKenneth D. Merry M_MPR, M_ZERO|M_NOWAIT);
2166991554f2SKenneth D. Merry if (!sc->dpm_flush_entry)
2167991554f2SKenneth D. Merry goto free_resources;
2168991554f2SKenneth D. Merry
2169991554f2SKenneth D. Merry dpm_pg0_sz = sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER) +
2170991554f2SKenneth D. Merry (sc->max_dpm_entries * sizeof(MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY));
2171991554f2SKenneth D. Merry
2172991554f2SKenneth D. Merry sc->dpm_pg0 = malloc(dpm_pg0_sz, M_MPR, M_ZERO|M_NOWAIT);
2173991554f2SKenneth D. Merry if (!sc->dpm_pg0) {
2174991554f2SKenneth D. Merry printf("%s: memory alloc failed for dpm page; disabling dpm\n",
2175991554f2SKenneth D. Merry __func__);
2176991554f2SKenneth D. Merry sc->is_dpm_enable = 0;
2177991554f2SKenneth D. Merry }
2178991554f2SKenneth D. Merry
2179991554f2SKenneth D. Merry return 0;
2180991554f2SKenneth D. Merry
2181991554f2SKenneth D. Merry free_resources:
2182991554f2SKenneth D. Merry free(sc->mapping_table, M_MPR);
2183991554f2SKenneth D. Merry free(sc->removal_table, M_MPR);
2184991554f2SKenneth D. Merry free(sc->enclosure_table, M_MPR);
2185991554f2SKenneth D. Merry free(sc->dpm_entry_used, M_MPR);
2186991554f2SKenneth D. Merry free(sc->dpm_flush_entry, M_MPR);
2187991554f2SKenneth D. Merry free(sc->dpm_pg0, M_MPR);
2188991554f2SKenneth D. Merry printf("%s: device initialization failed due to failure in mapping "
2189991554f2SKenneth D. Merry "table memory allocation\n", __func__);
2190991554f2SKenneth D. Merry return -1;
2191991554f2SKenneth D. Merry }
2192991554f2SKenneth D. Merry
2193991554f2SKenneth D. Merry /**
2194991554f2SKenneth D. Merry * mpr_mapping_free_memory- frees the memory allocated for mapping tables
2195991554f2SKenneth D. Merry * @sc: per adapter object
2196991554f2SKenneth D. Merry *
2197991554f2SKenneth D. Merry * Returns nothing.
2198991554f2SKenneth D. Merry */
2199991554f2SKenneth D. Merry void
mpr_mapping_free_memory(struct mpr_softc * sc)2200991554f2SKenneth D. Merry mpr_mapping_free_memory(struct mpr_softc *sc)
2201991554f2SKenneth D. Merry {
2202991554f2SKenneth D. Merry free(sc->mapping_table, M_MPR);
2203991554f2SKenneth D. Merry free(sc->removal_table, M_MPR);
2204991554f2SKenneth D. Merry free(sc->enclosure_table, M_MPR);
2205991554f2SKenneth D. Merry free(sc->dpm_entry_used, M_MPR);
2206991554f2SKenneth D. Merry free(sc->dpm_flush_entry, M_MPR);
2207991554f2SKenneth D. Merry free(sc->dpm_pg0, M_MPR);
2208991554f2SKenneth D. Merry }
2209991554f2SKenneth D. Merry
2210b99419aeSAlexander Motin static void
_mapping_process_dpm_pg0(struct mpr_softc * sc)2211991554f2SKenneth D. Merry _mapping_process_dpm_pg0(struct mpr_softc *sc)
2212991554f2SKenneth D. Merry {
2213991554f2SKenneth D. Merry u8 missing_cnt, enc_idx;
2214991554f2SKenneth D. Merry u16 slot_id, entry_num, num_slots;
2215991554f2SKenneth D. Merry u32 map_idx, dev_idx, start_idx, end_idx;
2216991554f2SKenneth D. Merry struct dev_mapping_table *mt_entry;
2217991554f2SKenneth D. Merry Mpi2DriverMap0Entry_t *dpm_entry;
2218991554f2SKenneth D. Merry u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
2219991554f2SKenneth D. Merry u16 max_num_phy_ids = le16toh(sc->ioc_pg8.MaxNumPhysicalMappedIDs);
2220991554f2SKenneth D. Merry struct enc_mapping_table *et_entry;
2221991554f2SKenneth D. Merry u64 physical_id;
2222991554f2SKenneth D. Merry u32 phy_bits = 0;
2223991554f2SKenneth D. Merry
2224327f2e6cSStephen McConnell /*
2225327f2e6cSStephen McConnell * start_idx and end_idx are only used for IR.
2226327f2e6cSStephen McConnell */
2227991554f2SKenneth D. Merry if (sc->ir_firmware)
2228991554f2SKenneth D. Merry _mapping_get_ir_maprange(sc, &start_idx, &end_idx);
2229991554f2SKenneth D. Merry
2230327f2e6cSStephen McConnell /*
2231327f2e6cSStephen McConnell * Look through all of the DPM entries that were read from the
2232327f2e6cSStephen McConnell * controller and copy them over to the driver's internal table if they
2233327f2e6cSStephen McConnell * have a non-zero ID. At this point, any ID with a value of 0 would be
2234327f2e6cSStephen McConnell * invalid, so don't copy it.
2235327f2e6cSStephen McConnell */
2236327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Start copy of %d DPM entries into the "
2237327f2e6cSStephen McConnell "mapping table.\n", __func__, sc->max_dpm_entries);
2238991554f2SKenneth D. Merry dpm_entry = (Mpi2DriverMap0Entry_t *) ((uint8_t *) sc->dpm_pg0 +
2239991554f2SKenneth D. Merry sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
2240991554f2SKenneth D. Merry for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++,
2241991554f2SKenneth D. Merry dpm_entry++) {
2242991554f2SKenneth D. Merry physical_id = dpm_entry->PhysicalIdentifier.High;
2243991554f2SKenneth D. Merry physical_id = (physical_id << 32) |
2244991554f2SKenneth D. Merry dpm_entry->PhysicalIdentifier.Low;
2245991554f2SKenneth D. Merry if (!physical_id) {
2246991554f2SKenneth D. Merry sc->dpm_entry_used[entry_num] = 0;
2247991554f2SKenneth D. Merry continue;
2248991554f2SKenneth D. Merry }
2249991554f2SKenneth D. Merry sc->dpm_entry_used[entry_num] = 1;
2250991554f2SKenneth D. Merry dpm_entry->MappingInformation = le16toh(dpm_entry->
2251991554f2SKenneth D. Merry MappingInformation);
2252991554f2SKenneth D. Merry missing_cnt = dpm_entry->MappingInformation &
2253991554f2SKenneth D. Merry MPI2_DRVMAP0_MAPINFO_MISSING_MASK;
2254991554f2SKenneth D. Merry dev_idx = le16toh(dpm_entry->DeviceIndex);
2255991554f2SKenneth D. Merry phy_bits = le32toh(dpm_entry->PhysicalBitsMapping);
2256327f2e6cSStephen McConnell
2257327f2e6cSStephen McConnell /*
2258327f2e6cSStephen McConnell * Volumes are at special locations in the mapping table so
2259327f2e6cSStephen McConnell * account for that. Volume mapping table entries do not depend
2260327f2e6cSStephen McConnell * on the type of mapping, so continue the loop after adding
2261327f2e6cSStephen McConnell * volumes to the mapping table.
2262327f2e6cSStephen McConnell */
2263991554f2SKenneth D. Merry if (sc->ir_firmware && (dev_idx >= start_idx) &&
2264991554f2SKenneth D. Merry (dev_idx <= end_idx)) {
2265991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[dev_idx];
2266327f2e6cSStephen McConnell mt_entry->physical_id =
2267327f2e6cSStephen McConnell dpm_entry->PhysicalIdentifier.High;
2268991554f2SKenneth D. Merry mt_entry->physical_id = (mt_entry->physical_id << 32) |
2269991554f2SKenneth D. Merry dpm_entry->PhysicalIdentifier.Low;
2270991554f2SKenneth D. Merry mt_entry->id = dev_idx;
2271991554f2SKenneth D. Merry mt_entry->missing_count = missing_cnt;
2272991554f2SKenneth D. Merry mt_entry->dpm_entry_num = entry_num;
2273991554f2SKenneth D. Merry mt_entry->device_info = MPR_DEV_RESERVED;
2274991554f2SKenneth D. Merry continue;
2275991554f2SKenneth D. Merry }
2276991554f2SKenneth D. Merry if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
2277991554f2SKenneth D. Merry MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
2278327f2e6cSStephen McConnell /*
2279327f2e6cSStephen McConnell * The dev_idx for an enclosure is the start index. If
2280327f2e6cSStephen McConnell * the start index is within the controller's default
2281327f2e6cSStephen McConnell * enclosure area, set the number of slots for this
2282327f2e6cSStephen McConnell * enclosure to the max allowed. Otherwise, it should be
2283327f2e6cSStephen McConnell * a normal enclosure and the number of slots is in the
2284327f2e6cSStephen McConnell * DPM entry's Mapping Information.
2285327f2e6cSStephen McConnell */
2286991554f2SKenneth D. Merry if (dev_idx < (sc->num_rsvd_entries +
2287991554f2SKenneth D. Merry max_num_phy_ids)) {
2288991554f2SKenneth D. Merry slot_id = 0;
2289991554f2SKenneth D. Merry if (ioc_pg8_flags &
2290991554f2SKenneth D. Merry MPI2_IOCPAGE8_FLAGS_DA_START_SLOT_1)
2291991554f2SKenneth D. Merry slot_id = 1;
2292991554f2SKenneth D. Merry num_slots = max_num_phy_ids;
2293991554f2SKenneth D. Merry } else {
2294991554f2SKenneth D. Merry slot_id = 0;
2295991554f2SKenneth D. Merry num_slots = dpm_entry->MappingInformation &
2296991554f2SKenneth D. Merry MPI2_DRVMAP0_MAPINFO_SLOT_MASK;
2297991554f2SKenneth D. Merry num_slots >>= MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT;
2298991554f2SKenneth D. Merry }
2299991554f2SKenneth D. Merry enc_idx = sc->num_enc_table_entries;
2300991554f2SKenneth D. Merry if (enc_idx >= sc->max_enclosures) {
2301327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: "
2302327f2e6cSStephen McConnell "Number of enclosure entries in DPM exceed "
2303327f2e6cSStephen McConnell "the max allowed of %d.\n", __func__,
2304991554f2SKenneth D. Merry sc->max_enclosures);
2305991554f2SKenneth D. Merry break;
2306991554f2SKenneth D. Merry }
2307991554f2SKenneth D. Merry sc->num_enc_table_entries++;
2308991554f2SKenneth D. Merry et_entry = &sc->enclosure_table[enc_idx];
2309991554f2SKenneth D. Merry physical_id = dpm_entry->PhysicalIdentifier.High;
2310991554f2SKenneth D. Merry et_entry->enclosure_id = (physical_id << 32) |
2311991554f2SKenneth D. Merry dpm_entry->PhysicalIdentifier.Low;
2312991554f2SKenneth D. Merry et_entry->start_index = dev_idx;
2313991554f2SKenneth D. Merry et_entry->dpm_entry_num = entry_num;
2314991554f2SKenneth D. Merry et_entry->num_slots = num_slots;
2315991554f2SKenneth D. Merry et_entry->start_slot = slot_id;
2316991554f2SKenneth D. Merry et_entry->missing_count = missing_cnt;
2317991554f2SKenneth D. Merry et_entry->phy_bits = phy_bits;
2318991554f2SKenneth D. Merry
2319327f2e6cSStephen McConnell /*
2320327f2e6cSStephen McConnell * Initialize all entries for this enclosure in the
2321327f2e6cSStephen McConnell * mapping table and mark them as reserved. The actual
2322327f2e6cSStephen McConnell * devices have not been processed yet but when they are
2323327f2e6cSStephen McConnell * they will use these entries. If an entry is found
2324327f2e6cSStephen McConnell * that already has a valid DPM index, the mapping table
2325327f2e6cSStephen McConnell * is corrupt. This can happen if the mapping type is
2326327f2e6cSStephen McConnell * changed without clearing all of the DPM entries in
2327327f2e6cSStephen McConnell * the controller.
2328327f2e6cSStephen McConnell */
2329991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[dev_idx];
2330991554f2SKenneth D. Merry for (map_idx = dev_idx; map_idx < (dev_idx + num_slots);
2331991554f2SKenneth D. Merry map_idx++, mt_entry++) {
2332991554f2SKenneth D. Merry if (mt_entry->dpm_entry_num !=
2333991554f2SKenneth D. Merry MPR_DPM_BAD_IDX) {
2334327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING,
2335327f2e6cSStephen McConnell "%s: Conflict in mapping table for "
2336b99419aeSAlexander Motin "enclosure %d device %d\n",
2337b99419aeSAlexander Motin __func__, enc_idx, map_idx);
23381d909844SAlan Somers goto fail;
2339991554f2SKenneth D. Merry }
2340327f2e6cSStephen McConnell physical_id =
2341327f2e6cSStephen McConnell dpm_entry->PhysicalIdentifier.High;
2342991554f2SKenneth D. Merry mt_entry->physical_id = (physical_id << 32) |
2343991554f2SKenneth D. Merry dpm_entry->PhysicalIdentifier.Low;
2344991554f2SKenneth D. Merry mt_entry->phy_bits = phy_bits;
2345991554f2SKenneth D. Merry mt_entry->id = dev_idx;
2346991554f2SKenneth D. Merry mt_entry->dpm_entry_num = entry_num;
2347991554f2SKenneth D. Merry mt_entry->missing_count = missing_cnt;
2348991554f2SKenneth D. Merry mt_entry->device_info = MPR_DEV_RESERVED;
2349991554f2SKenneth D. Merry }
2350991554f2SKenneth D. Merry } else if ((ioc_pg8_flags &
2351991554f2SKenneth D. Merry MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
2352991554f2SKenneth D. Merry MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
2353327f2e6cSStephen McConnell /*
2354327f2e6cSStephen McConnell * Device mapping, so simply copy the DPM entries to the
2355327f2e6cSStephen McConnell * mapping table, but check for a corrupt mapping table
2356327f2e6cSStephen McConnell * (as described above in Enc/Slot mapping).
2357327f2e6cSStephen McConnell */
2358991554f2SKenneth D. Merry map_idx = dev_idx;
2359991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[map_idx];
2360991554f2SKenneth D. Merry if (mt_entry->dpm_entry_num != MPR_DPM_BAD_IDX) {
2361327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: "
2362327f2e6cSStephen McConnell "Conflict in mapping table for device %d\n",
2363327f2e6cSStephen McConnell __func__, map_idx);
23641d909844SAlan Somers goto fail;
2365991554f2SKenneth D. Merry }
2366991554f2SKenneth D. Merry physical_id = dpm_entry->PhysicalIdentifier.High;
2367991554f2SKenneth D. Merry mt_entry->physical_id = (physical_id << 32) |
2368991554f2SKenneth D. Merry dpm_entry->PhysicalIdentifier.Low;
2369991554f2SKenneth D. Merry mt_entry->phy_bits = phy_bits;
2370991554f2SKenneth D. Merry mt_entry->id = dev_idx;
2371991554f2SKenneth D. Merry mt_entry->missing_count = missing_cnt;
2372991554f2SKenneth D. Merry mt_entry->dpm_entry_num = entry_num;
2373991554f2SKenneth D. Merry mt_entry->device_info = MPR_DEV_RESERVED;
2374991554f2SKenneth D. Merry }
2375991554f2SKenneth D. Merry } /*close the loop for DPM table */
2376b99419aeSAlexander Motin return;
23771d909844SAlan Somers
23781d909844SAlan Somers fail:
2379b99419aeSAlexander Motin mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: "
2380b99419aeSAlexander Motin "Wiping DPM to start from scratch\n", __func__);
2381b99419aeSAlexander Motin dpm_entry = (Mpi2DriverMap0Entry_t *) ((uint8_t *) sc->dpm_pg0 +
2382b99419aeSAlexander Motin sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
2383b99419aeSAlexander Motin bzero(dpm_entry, sizeof(Mpi2DriverMap0Entry_t) * sc->max_dpm_entries);
23841d909844SAlan Somers for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++) {
2385b99419aeSAlexander Motin sc->dpm_flush_entry[entry_num] = 1;
23861d909844SAlan Somers sc->dpm_entry_used[entry_num] = 0;
23871d909844SAlan Somers /*
23881d909844SAlan Somers * for IR firmware, it may be necessary to wipe out
23891d909844SAlan Somers * sc->mapping_table volumes tooi
23901d909844SAlan Somers */
23911d909844SAlan Somers }
2392b99419aeSAlexander Motin _mapping_flush_dpm_pages(sc);
2393fc9bdb4eSAlexander Motin for (enc_idx = 0; enc_idx < sc->num_enc_table_entries; enc_idx++)
2394fc9bdb4eSAlexander Motin _mapping_clear_enc_entry(sc->enclosure_table + enc_idx);
23951d909844SAlan Somers sc->num_enc_table_entries = 0;
2396991554f2SKenneth D. Merry }
2397991554f2SKenneth D. Merry
2398991554f2SKenneth D. Merry /*
2399991554f2SKenneth D. Merry * mpr_mapping_check_devices - start of the day check for device availabilty
2400991554f2SKenneth D. Merry * @sc: per adapter object
2401991554f2SKenneth D. Merry *
2402991554f2SKenneth D. Merry * Returns nothing.
2403991554f2SKenneth D. Merry */
2404991554f2SKenneth D. Merry void
mpr_mapping_check_devices(void * data)2405327f2e6cSStephen McConnell mpr_mapping_check_devices(void *data)
2406991554f2SKenneth D. Merry {
2407991554f2SKenneth D. Merry u32 i;
2408991554f2SKenneth D. Merry struct dev_mapping_table *mt_entry;
2409327f2e6cSStephen McConnell struct mpr_softc *sc = (struct mpr_softc *)data;
2410991554f2SKenneth D. Merry u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
2411991554f2SKenneth D. Merry struct enc_mapping_table *et_entry;
2412327f2e6cSStephen McConnell u32 start_idx = 0, end_idx = 0;
2413327f2e6cSStephen McConnell u8 stop_device_checks = 0;
2414991554f2SKenneth D. Merry
2415327f2e6cSStephen McConnell MPR_FUNCTRACE(sc);
2416327f2e6cSStephen McConnell
2417327f2e6cSStephen McConnell /*
2418327f2e6cSStephen McConnell * Clear this flag so that this function is never called again except
2419327f2e6cSStephen McConnell * within this function if the check needs to be done again. The
2420327f2e6cSStephen McConnell * purpose is to check for missing devices that are currently in the
2421327f2e6cSStephen McConnell * mapping table so do this only at driver init after discovery.
2422327f2e6cSStephen McConnell */
2423991554f2SKenneth D. Merry sc->track_mapping_events = 0;
2424327f2e6cSStephen McConnell
2425327f2e6cSStephen McConnell /*
2426327f2e6cSStephen McConnell * callout synchronization
2427327f2e6cSStephen McConnell * This is used to prevent race conditions for the callout.
2428327f2e6cSStephen McConnell */
2429327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Start check for missing devices.\n",
2430327f2e6cSStephen McConnell __func__);
2431327f2e6cSStephen McConnell mtx_assert(&sc->mpr_mtx, MA_OWNED);
2432327f2e6cSStephen McConnell if ((callout_pending(&sc->device_check_callout)) ||
2433327f2e6cSStephen McConnell (!callout_active(&sc->device_check_callout))) {
2434327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Device Check Callout is "
2435327f2e6cSStephen McConnell "already pending or not active.\n", __func__);
2436327f2e6cSStephen McConnell return;
2437327f2e6cSStephen McConnell }
2438327f2e6cSStephen McConnell callout_deactivate(&sc->device_check_callout);
2439327f2e6cSStephen McConnell
2440327f2e6cSStephen McConnell /*
2441327f2e6cSStephen McConnell * Use callout to check if any devices in the mapping table have been
2442327f2e6cSStephen McConnell * processed yet. If ALL devices are marked as not init_complete, no
2443327f2e6cSStephen McConnell * devices have been processed and mapped. Until devices are mapped
2444327f2e6cSStephen McConnell * there's no reason to mark them as missing. Continue resetting this
2445327f2e6cSStephen McConnell * callout until devices have been mapped.
2446327f2e6cSStephen McConnell */
2447327f2e6cSStephen McConnell if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
2448327f2e6cSStephen McConnell MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
2449327f2e6cSStephen McConnell et_entry = sc->enclosure_table;
2450327f2e6cSStephen McConnell for (i = 0; i < sc->num_enc_table_entries; i++, et_entry++) {
2451327f2e6cSStephen McConnell if (et_entry->init_complete) {
2452327f2e6cSStephen McConnell stop_device_checks = 1;
2453991554f2SKenneth D. Merry break;
2454327f2e6cSStephen McConnell }
2455327f2e6cSStephen McConnell }
2456327f2e6cSStephen McConnell } else if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
2457327f2e6cSStephen McConnell MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
2458327f2e6cSStephen McConnell mt_entry = sc->mapping_table;
2459327f2e6cSStephen McConnell for (i = 0; i < sc->max_devices; i++, mt_entry++) {
2460327f2e6cSStephen McConnell if (mt_entry->init_complete) {
2461327f2e6cSStephen McConnell stop_device_checks = 1;
2462327f2e6cSStephen McConnell break;
2463327f2e6cSStephen McConnell }
2464327f2e6cSStephen McConnell }
2465327f2e6cSStephen McConnell }
2466991554f2SKenneth D. Merry
2467327f2e6cSStephen McConnell /*
2468327f2e6cSStephen McConnell * Setup another callout check after a delay. Keep doing this until
2469327f2e6cSStephen McConnell * devices are mapped.
2470327f2e6cSStephen McConnell */
2471327f2e6cSStephen McConnell if (!stop_device_checks) {
2472327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: No devices have been mapped. "
2473327f2e6cSStephen McConnell "Reset callout to check again after a %d second delay.\n",
2474327f2e6cSStephen McConnell __func__, MPR_MISSING_CHECK_DELAY);
2475327f2e6cSStephen McConnell callout_reset(&sc->device_check_callout,
2476327f2e6cSStephen McConnell MPR_MISSING_CHECK_DELAY * hz, mpr_mapping_check_devices,
2477327f2e6cSStephen McConnell sc);
2478327f2e6cSStephen McConnell return;
2479327f2e6cSStephen McConnell }
2480327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Device check complete.\n", __func__);
2481991554f2SKenneth D. Merry
2482327f2e6cSStephen McConnell /*
2483327f2e6cSStephen McConnell * Depending on the mapping type, check if devices have been processed
2484327f2e6cSStephen McConnell * and update their missing counts if not processed.
2485327f2e6cSStephen McConnell */
2486991554f2SKenneth D. Merry if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
2487991554f2SKenneth D. Merry MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING) {
2488991554f2SKenneth D. Merry et_entry = sc->enclosure_table;
2489991554f2SKenneth D. Merry for (i = 0; i < sc->num_enc_table_entries; i++, et_entry++) {
2490991554f2SKenneth D. Merry if (!et_entry->init_complete) {
2491991554f2SKenneth D. Merry if (et_entry->missing_count <
2492991554f2SKenneth D. Merry MPR_MAX_MISSING_COUNT) {
2493327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: "
2494327f2e6cSStephen McConnell "Enclosure %d is missing from the "
2495327f2e6cSStephen McConnell "topology. Update its missing "
2496327f2e6cSStephen McConnell "count.\n", __func__, i);
2497991554f2SKenneth D. Merry et_entry->missing_count++;
2498991554f2SKenneth D. Merry if (et_entry->dpm_entry_num !=
2499327f2e6cSStephen McConnell MPR_DPM_BAD_IDX) {
2500991554f2SKenneth D. Merry _mapping_commit_enc_entry(sc,
2501991554f2SKenneth D. Merry et_entry);
2502991554f2SKenneth D. Merry }
2503327f2e6cSStephen McConnell }
2504991554f2SKenneth D. Merry et_entry->init_complete = 1;
2505991554f2SKenneth D. Merry }
2506991554f2SKenneth D. Merry }
2507991554f2SKenneth D. Merry if (!sc->ir_firmware)
2508991554f2SKenneth D. Merry return;
2509991554f2SKenneth D. Merry _mapping_get_ir_maprange(sc, &start_idx, &end_idx);
2510991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[start_idx];
2511327f2e6cSStephen McConnell } else if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) ==
2512327f2e6cSStephen McConnell MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING) {
2513327f2e6cSStephen McConnell start_idx = 0;
2514327f2e6cSStephen McConnell end_idx = sc->max_devices - 1;
2515327f2e6cSStephen McConnell mt_entry = sc->mapping_table;
2516327f2e6cSStephen McConnell }
2517327f2e6cSStephen McConnell
2518327f2e6cSStephen McConnell /*
2519327f2e6cSStephen McConnell * The start and end indices have been set above according to the
2520327f2e6cSStephen McConnell * mapping type. Go through these mappings and update any entries that
2521327f2e6cSStephen McConnell * do not have the init_complete flag set, which means they are missing.
2522327f2e6cSStephen McConnell */
2523327f2e6cSStephen McConnell if (end_idx == 0)
2524327f2e6cSStephen McConnell return;
2525991554f2SKenneth D. Merry for (i = start_idx; i < (end_idx + 1); i++, mt_entry++) {
2526991554f2SKenneth D. Merry if (mt_entry->device_info & MPR_DEV_RESERVED
2527991554f2SKenneth D. Merry && !mt_entry->physical_id)
2528991554f2SKenneth D. Merry mt_entry->init_complete = 1;
2529991554f2SKenneth D. Merry else if (mt_entry->device_info & MPR_DEV_RESERVED) {
2530991554f2SKenneth D. Merry if (!mt_entry->init_complete) {
2531327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Device in "
2532327f2e6cSStephen McConnell "mapping table at index %d is missing from "
2533327f2e6cSStephen McConnell "topology. Update its missing count.\n",
2534327f2e6cSStephen McConnell __func__, i);
2535991554f2SKenneth D. Merry if (mt_entry->missing_count <
2536991554f2SKenneth D. Merry MPR_MAX_MISSING_COUNT) {
2537991554f2SKenneth D. Merry mt_entry->missing_count++;
2538991554f2SKenneth D. Merry if (mt_entry->dpm_entry_num !=
2539327f2e6cSStephen McConnell MPR_DPM_BAD_IDX) {
2540991554f2SKenneth D. Merry _mapping_commit_map_entry(sc,
2541991554f2SKenneth D. Merry mt_entry);
2542991554f2SKenneth D. Merry }
2543991554f2SKenneth D. Merry }
2544991554f2SKenneth D. Merry mt_entry->init_complete = 1;
2545991554f2SKenneth D. Merry }
2546991554f2SKenneth D. Merry }
2547991554f2SKenneth D. Merry }
2548991554f2SKenneth D. Merry }
2549991554f2SKenneth D. Merry
2550991554f2SKenneth D. Merry /**
2551991554f2SKenneth D. Merry * mpr_mapping_initialize - initialize mapping tables
2552991554f2SKenneth D. Merry * @sc: per adapter object
2553991554f2SKenneth D. Merry *
2554991554f2SKenneth D. Merry * Read controller persitant mapping tables into internal data area.
2555991554f2SKenneth D. Merry *
2556991554f2SKenneth D. Merry * Return 0 for success or non-zero for failure.
2557991554f2SKenneth D. Merry */
2558991554f2SKenneth D. Merry int
mpr_mapping_initialize(struct mpr_softc * sc)2559991554f2SKenneth D. Merry mpr_mapping_initialize(struct mpr_softc *sc)
2560991554f2SKenneth D. Merry {
2561991554f2SKenneth D. Merry uint16_t volume_mapping_flags, dpm_pg0_sz;
2562991554f2SKenneth D. Merry uint32_t i;
2563991554f2SKenneth D. Merry Mpi2ConfigReply_t mpi_reply;
2564991554f2SKenneth D. Merry int error;
2565991554f2SKenneth D. Merry uint8_t retry_count;
2566991554f2SKenneth D. Merry uint16_t ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
2567991554f2SKenneth D. Merry
2568991554f2SKenneth D. Merry /* The additional 1 accounts for the virtual enclosure
2569991554f2SKenneth D. Merry * created for the controller
2570991554f2SKenneth D. Merry */
2571991554f2SKenneth D. Merry sc->max_enclosures = sc->facts->MaxEnclosures + 1;
2572991554f2SKenneth D. Merry sc->max_expanders = sc->facts->MaxSasExpanders;
2573991554f2SKenneth D. Merry sc->max_volumes = sc->facts->MaxVolumes;
2574991554f2SKenneth D. Merry sc->max_devices = sc->facts->MaxTargets + sc->max_volumes;
2575991554f2SKenneth D. Merry sc->pending_map_events = 0;
2576991554f2SKenneth D. Merry sc->num_enc_table_entries = 0;
2577991554f2SKenneth D. Merry sc->num_rsvd_entries = 0;
257871900a79SAlfredo Dal'Ava Junior sc->max_dpm_entries = le16toh(sc->ioc_pg8.MaxPersistentEntries);
2579991554f2SKenneth D. Merry sc->is_dpm_enable = (sc->max_dpm_entries) ? 1 : 0;
2580991554f2SKenneth D. Merry sc->track_mapping_events = 0;
2581991554f2SKenneth D. Merry
2582327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Mapping table has a max of %d entries "
2583327f2e6cSStephen McConnell "and DPM has a max of %d entries.\n", __func__, sc->max_devices,
2584327f2e6cSStephen McConnell sc->max_dpm_entries);
2585327f2e6cSStephen McConnell
2586991554f2SKenneth D. Merry if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_DISABLE_PERSISTENT_MAPPING)
2587991554f2SKenneth D. Merry sc->is_dpm_enable = 0;
2588991554f2SKenneth D. Merry
2589991554f2SKenneth D. Merry if (ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0)
2590991554f2SKenneth D. Merry sc->num_rsvd_entries = 1;
2591991554f2SKenneth D. Merry
259271900a79SAlfredo Dal'Ava Junior volume_mapping_flags = le16toh(sc->ioc_pg8.IRVolumeMappingFlags) &
2593991554f2SKenneth D. Merry MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
2594991554f2SKenneth D. Merry if (sc->ir_firmware && (volume_mapping_flags ==
2595991554f2SKenneth D. Merry MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING))
2596991554f2SKenneth D. Merry sc->num_rsvd_entries += sc->max_volumes;
2597991554f2SKenneth D. Merry
2598991554f2SKenneth D. Merry error = mpr_mapping_allocate_memory(sc);
2599991554f2SKenneth D. Merry if (error)
2600991554f2SKenneth D. Merry return (error);
2601991554f2SKenneth D. Merry
2602991554f2SKenneth D. Merry for (i = 0; i < sc->max_devices; i++)
2603991554f2SKenneth D. Merry _mapping_clear_map_entry(sc->mapping_table + i);
2604991554f2SKenneth D. Merry
2605991554f2SKenneth D. Merry for (i = 0; i < sc->max_enclosures; i++)
2606991554f2SKenneth D. Merry _mapping_clear_enc_entry(sc->enclosure_table + i);
2607991554f2SKenneth D. Merry
2608991554f2SKenneth D. Merry for (i = 0; i < sc->max_devices; i++) {
2609991554f2SKenneth D. Merry sc->removal_table[i].dev_handle = 0;
2610991554f2SKenneth D. Merry sc->removal_table[i].dpm_entry_num = MPR_DPM_BAD_IDX;
2611991554f2SKenneth D. Merry }
2612991554f2SKenneth D. Merry
2613991554f2SKenneth D. Merry memset(sc->dpm_entry_used, 0, sc->max_dpm_entries);
2614991554f2SKenneth D. Merry memset(sc->dpm_flush_entry, 0, sc->max_dpm_entries);
2615991554f2SKenneth D. Merry
2616991554f2SKenneth D. Merry if (sc->is_dpm_enable) {
2617991554f2SKenneth D. Merry dpm_pg0_sz = sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER) +
2618991554f2SKenneth D. Merry (sc->max_dpm_entries *
2619991554f2SKenneth D. Merry sizeof(MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY));
2620991554f2SKenneth D. Merry retry_count = 0;
2621991554f2SKenneth D. Merry
2622991554f2SKenneth D. Merry retry_read_dpm:
2623991554f2SKenneth D. Merry if (mpr_config_get_dpm_pg0(sc, &mpi_reply, sc->dpm_pg0,
2624991554f2SKenneth D. Merry dpm_pg0_sz)) {
2625327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: DPM page "
2626327f2e6cSStephen McConnell "read failed.\n", __func__);
2627991554f2SKenneth D. Merry if (retry_count < 3) {
2628991554f2SKenneth D. Merry retry_count++;
2629991554f2SKenneth D. Merry goto retry_read_dpm;
2630991554f2SKenneth D. Merry }
2631991554f2SKenneth D. Merry sc->is_dpm_enable = 0;
2632991554f2SKenneth D. Merry }
2633991554f2SKenneth D. Merry }
2634991554f2SKenneth D. Merry
2635b99419aeSAlexander Motin if (sc->is_dpm_enable)
2636b99419aeSAlexander Motin _mapping_process_dpm_pg0(sc);
26371d909844SAlan Somers if (! sc->is_dpm_enable) {
2638327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: DPM processing is disabled. "
2639327f2e6cSStephen McConnell "Device mappings will not persist across reboots or "
2640327f2e6cSStephen McConnell "resets.\n", __func__);
2641327f2e6cSStephen McConnell }
2642991554f2SKenneth D. Merry
2643991554f2SKenneth D. Merry sc->track_mapping_events = 1;
2644991554f2SKenneth D. Merry return 0;
2645991554f2SKenneth D. Merry }
2646991554f2SKenneth D. Merry
2647991554f2SKenneth D. Merry /**
2648991554f2SKenneth D. Merry * mpr_mapping_exit - clear mapping table and associated memory
2649991554f2SKenneth D. Merry * @sc: per adapter object
2650991554f2SKenneth D. Merry *
2651991554f2SKenneth D. Merry * Returns nothing.
2652991554f2SKenneth D. Merry */
2653991554f2SKenneth D. Merry void
mpr_mapping_exit(struct mpr_softc * sc)2654991554f2SKenneth D. Merry mpr_mapping_exit(struct mpr_softc *sc)
2655991554f2SKenneth D. Merry {
2656991554f2SKenneth D. Merry _mapping_flush_dpm_pages(sc);
2657991554f2SKenneth D. Merry mpr_mapping_free_memory(sc);
2658991554f2SKenneth D. Merry }
2659991554f2SKenneth D. Merry
2660991554f2SKenneth D. Merry /**
2661327f2e6cSStephen McConnell * mpr_mapping_get_tid - return the target id for sas device and handle
2662991554f2SKenneth D. Merry * @sc: per adapter object
2663991554f2SKenneth D. Merry * @sas_address: sas address of the device
2664991554f2SKenneth D. Merry * @handle: device handle
2665991554f2SKenneth D. Merry *
2666327f2e6cSStephen McConnell * Returns valid target ID on success or BAD_ID.
2667991554f2SKenneth D. Merry */
2668991554f2SKenneth D. Merry unsigned int
mpr_mapping_get_tid(struct mpr_softc * sc,uint64_t sas_address,u16 handle)2669327f2e6cSStephen McConnell mpr_mapping_get_tid(struct mpr_softc *sc, uint64_t sas_address, u16 handle)
2670991554f2SKenneth D. Merry {
2671991554f2SKenneth D. Merry u32 map_idx;
2672991554f2SKenneth D. Merry struct dev_mapping_table *mt_entry;
2673991554f2SKenneth D. Merry
2674991554f2SKenneth D. Merry for (map_idx = 0; map_idx < sc->max_devices; map_idx++) {
2675991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[map_idx];
2676991554f2SKenneth D. Merry if (mt_entry->dev_handle == handle && mt_entry->physical_id ==
2677991554f2SKenneth D. Merry sas_address)
2678991554f2SKenneth D. Merry return mt_entry->id;
2679991554f2SKenneth D. Merry }
2680991554f2SKenneth D. Merry
2681991554f2SKenneth D. Merry return MPR_MAP_BAD_ID;
2682991554f2SKenneth D. Merry }
2683991554f2SKenneth D. Merry
2684991554f2SKenneth D. Merry /**
2685327f2e6cSStephen McConnell * mpr_mapping_get_tid_from_handle - find a target id in mapping table using
2686991554f2SKenneth D. Merry * only the dev handle. This is just a wrapper function for the local function
2687991554f2SKenneth D. Merry * _mapping_get_mt_idx_from_handle.
2688991554f2SKenneth D. Merry * @sc: per adapter object
2689991554f2SKenneth D. Merry * @handle: device handle
2690991554f2SKenneth D. Merry *
2691327f2e6cSStephen McConnell * Returns valid target ID on success or BAD_ID.
2692991554f2SKenneth D. Merry */
2693991554f2SKenneth D. Merry unsigned int
mpr_mapping_get_tid_from_handle(struct mpr_softc * sc,u16 handle)2694327f2e6cSStephen McConnell mpr_mapping_get_tid_from_handle(struct mpr_softc *sc, u16 handle)
2695991554f2SKenneth D. Merry {
2696991554f2SKenneth D. Merry return (_mapping_get_mt_idx_from_handle(sc, handle));
2697991554f2SKenneth D. Merry }
2698991554f2SKenneth D. Merry
2699991554f2SKenneth D. Merry /**
2700327f2e6cSStephen McConnell * mpr_mapping_get_raid_tid - return the target id for raid device
2701991554f2SKenneth D. Merry * @sc: per adapter object
2702991554f2SKenneth D. Merry * @wwid: world wide identifier for raid volume
2703327f2e6cSStephen McConnell * @volHandle: volume device handle
2704991554f2SKenneth D. Merry *
2705327f2e6cSStephen McConnell * Returns valid target ID on success or BAD_ID.
2706991554f2SKenneth D. Merry */
2707991554f2SKenneth D. Merry unsigned int
mpr_mapping_get_raid_tid(struct mpr_softc * sc,u64 wwid,u16 volHandle)2708327f2e6cSStephen McConnell mpr_mapping_get_raid_tid(struct mpr_softc *sc, u64 wwid, u16 volHandle)
2709991554f2SKenneth D. Merry {
2710327f2e6cSStephen McConnell u32 start_idx, end_idx, map_idx;
2711991554f2SKenneth D. Merry struct dev_mapping_table *mt_entry;
2712991554f2SKenneth D. Merry
2713327f2e6cSStephen McConnell _mapping_get_ir_maprange(sc, &start_idx, &end_idx);
2714327f2e6cSStephen McConnell mt_entry = &sc->mapping_table[start_idx];
2715327f2e6cSStephen McConnell for (map_idx = start_idx; map_idx <= end_idx; map_idx++, mt_entry++) {
2716327f2e6cSStephen McConnell if (mt_entry->dev_handle == volHandle &&
2717327f2e6cSStephen McConnell mt_entry->physical_id == wwid)
2718991554f2SKenneth D. Merry return mt_entry->id;
2719991554f2SKenneth D. Merry }
2720991554f2SKenneth D. Merry
2721991554f2SKenneth D. Merry return MPR_MAP_BAD_ID;
2722991554f2SKenneth D. Merry }
2723991554f2SKenneth D. Merry
2724991554f2SKenneth D. Merry /**
2725327f2e6cSStephen McConnell * mpr_mapping_get_raid_tid_from_handle - find raid device in mapping table
2726991554f2SKenneth D. Merry * using only the volume dev handle. This is just a wrapper function for the
2727991554f2SKenneth D. Merry * local function _mapping_get_ir_mt_idx_from_handle.
2728991554f2SKenneth D. Merry * @sc: per adapter object
2729991554f2SKenneth D. Merry * @volHandle: volume device handle
2730991554f2SKenneth D. Merry *
2731327f2e6cSStephen McConnell * Returns valid target ID on success or BAD_ID.
2732991554f2SKenneth D. Merry */
2733991554f2SKenneth D. Merry unsigned int
mpr_mapping_get_raid_tid_from_handle(struct mpr_softc * sc,u16 volHandle)2734327f2e6cSStephen McConnell mpr_mapping_get_raid_tid_from_handle(struct mpr_softc *sc, u16 volHandle)
2735991554f2SKenneth D. Merry {
2736991554f2SKenneth D. Merry return (_mapping_get_ir_mt_idx_from_handle(sc, volHandle));
2737991554f2SKenneth D. Merry }
2738991554f2SKenneth D. Merry
2739991554f2SKenneth D. Merry /**
2740991554f2SKenneth D. Merry * mpr_mapping_enclosure_dev_status_change_event - handle enclosure events
2741991554f2SKenneth D. Merry * @sc: per adapter object
2742991554f2SKenneth D. Merry * @event_data: event data payload
2743991554f2SKenneth D. Merry *
2744991554f2SKenneth D. Merry * Return nothing.
2745991554f2SKenneth D. Merry */
2746991554f2SKenneth D. Merry void
mpr_mapping_enclosure_dev_status_change_event(struct mpr_softc * sc,Mpi2EventDataSasEnclDevStatusChange_t * event_data)2747991554f2SKenneth D. Merry mpr_mapping_enclosure_dev_status_change_event(struct mpr_softc *sc,
2748991554f2SKenneth D. Merry Mpi2EventDataSasEnclDevStatusChange_t *event_data)
2749991554f2SKenneth D. Merry {
2750991554f2SKenneth D. Merry u8 enc_idx, missing_count;
2751991554f2SKenneth D. Merry struct enc_mapping_table *et_entry;
2752991554f2SKenneth D. Merry Mpi2DriverMap0Entry_t *dpm_entry;
2753991554f2SKenneth D. Merry u16 ioc_pg8_flags = le16toh(sc->ioc_pg8.Flags);
2754991554f2SKenneth D. Merry u8 map_shift = MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT;
2755991554f2SKenneth D. Merry u8 update_phy_bits = 0;
2756991554f2SKenneth D. Merry u32 saved_phy_bits;
2757991554f2SKenneth D. Merry uint64_t temp64_var;
2758991554f2SKenneth D. Merry
2759991554f2SKenneth D. Merry if ((ioc_pg8_flags & MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE) !=
2760991554f2SKenneth D. Merry MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING)
2761991554f2SKenneth D. Merry goto out;
2762991554f2SKenneth D. Merry
2763991554f2SKenneth D. Merry dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 +
2764991554f2SKenneth D. Merry sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
2765991554f2SKenneth D. Merry
2766991554f2SKenneth D. Merry if (event_data->ReasonCode == MPI2_EVENT_SAS_ENCL_RC_ADDED) {
2767991554f2SKenneth D. Merry if (!event_data->NumSlots) {
2768327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: Enclosure "
2769327f2e6cSStephen McConnell "with handle = 0x%x reported 0 slots.\n", __func__,
2770991554f2SKenneth D. Merry le16toh(event_data->EnclosureHandle));
2771991554f2SKenneth D. Merry goto out;
2772991554f2SKenneth D. Merry }
2773991554f2SKenneth D. Merry temp64_var = event_data->EnclosureLogicalID.High;
2774991554f2SKenneth D. Merry temp64_var = (temp64_var << 32) |
2775991554f2SKenneth D. Merry event_data->EnclosureLogicalID.Low;
2776991554f2SKenneth D. Merry enc_idx = _mapping_get_enc_idx_from_id(sc, temp64_var,
2777991554f2SKenneth D. Merry event_data->PhyBits);
2778327f2e6cSStephen McConnell
2779327f2e6cSStephen McConnell /*
2780327f2e6cSStephen McConnell * If the Added enclosure is already in the Enclosure Table,
2781*2f9de90bSGordon Bergling * make sure that all the enclosure info is up to date. If
2782327f2e6cSStephen McConnell * the enclosure was missing and has just been added back, or if
2783327f2e6cSStephen McConnell * the enclosure's Phy Bits have changed, clear the missing
2784327f2e6cSStephen McConnell * count and update the Phy Bits in the mapping table and in the
2785327f2e6cSStephen McConnell * DPM, if it's being used.
2786327f2e6cSStephen McConnell */
2787991554f2SKenneth D. Merry if (enc_idx != MPR_ENCTABLE_BAD_IDX) {
2788991554f2SKenneth D. Merry et_entry = &sc->enclosure_table[enc_idx];
2789991554f2SKenneth D. Merry if (et_entry->init_complete &&
2790991554f2SKenneth D. Merry !et_entry->missing_count) {
2791327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING, "%s: Enclosure %d "
2792327f2e6cSStephen McConnell "is already present with handle = 0x%x\n",
2793327f2e6cSStephen McConnell __func__, enc_idx, et_entry->enc_handle);
2794991554f2SKenneth D. Merry goto out;
2795991554f2SKenneth D. Merry }
2796991554f2SKenneth D. Merry et_entry->enc_handle = le16toh(event_data->
2797991554f2SKenneth D. Merry EnclosureHandle);
2798991554f2SKenneth D. Merry et_entry->start_slot = le16toh(event_data->StartSlot);
2799991554f2SKenneth D. Merry saved_phy_bits = et_entry->phy_bits;
2800991554f2SKenneth D. Merry et_entry->phy_bits |= le32toh(event_data->PhyBits);
2801991554f2SKenneth D. Merry if (saved_phy_bits != et_entry->phy_bits)
2802991554f2SKenneth D. Merry update_phy_bits = 1;
2803991554f2SKenneth D. Merry if (et_entry->missing_count || update_phy_bits) {
2804991554f2SKenneth D. Merry et_entry->missing_count = 0;
2805991554f2SKenneth D. Merry if (sc->is_dpm_enable &&
2806991554f2SKenneth D. Merry et_entry->dpm_entry_num !=
2807991554f2SKenneth D. Merry MPR_DPM_BAD_IDX) {
2808991554f2SKenneth D. Merry dpm_entry += et_entry->dpm_entry_num;
2809991554f2SKenneth D. Merry missing_count =
2810991554f2SKenneth D. Merry (u8)(dpm_entry->MappingInformation &
2811991554f2SKenneth D. Merry MPI2_DRVMAP0_MAPINFO_MISSING_MASK);
2812327f2e6cSStephen McConnell if (missing_count || update_phy_bits) {
2813991554f2SKenneth D. Merry dpm_entry->MappingInformation
2814991554f2SKenneth D. Merry = et_entry->num_slots;
2815991554f2SKenneth D. Merry dpm_entry->MappingInformation
2816991554f2SKenneth D. Merry <<= map_shift;
2817991554f2SKenneth D. Merry dpm_entry->PhysicalBitsMapping
2818991554f2SKenneth D. Merry = et_entry->phy_bits;
2819991554f2SKenneth D. Merry sc->dpm_flush_entry[et_entry->
2820991554f2SKenneth D. Merry dpm_entry_num] = 1;
2821991554f2SKenneth D. Merry }
2822991554f2SKenneth D. Merry }
2823991554f2SKenneth D. Merry }
2824991554f2SKenneth D. Merry } else {
2825327f2e6cSStephen McConnell /*
2826327f2e6cSStephen McConnell * This is a new enclosure that is being added.
2827327f2e6cSStephen McConnell * Initialize the Enclosure Table entry. It will be
2828327f2e6cSStephen McConnell * finalized when a device is added for the enclosure
2829327f2e6cSStephen McConnell * and the enclosure has enough space in the Mapping
2830327f2e6cSStephen McConnell * Table to map its devices.
2831327f2e6cSStephen McConnell */
2832b99419aeSAlexander Motin if (sc->num_enc_table_entries < sc->max_enclosures) {
2833991554f2SKenneth D. Merry enc_idx = sc->num_enc_table_entries;
2834b99419aeSAlexander Motin sc->num_enc_table_entries++;
2835b99419aeSAlexander Motin } else {
2836b99419aeSAlexander Motin enc_idx = _mapping_get_high_missing_et_idx(sc);
2837b99419aeSAlexander Motin if (enc_idx != MPR_ENCTABLE_BAD_IDX) {
2838b99419aeSAlexander Motin et_entry = &sc->enclosure_table[enc_idx];
2839b99419aeSAlexander Motin _mapping_add_to_removal_table(sc,
2840b99419aeSAlexander Motin et_entry->dpm_entry_num);
2841b99419aeSAlexander Motin _mapping_clear_enc_entry(et_entry);
2842b99419aeSAlexander Motin }
2843b99419aeSAlexander Motin }
2844b99419aeSAlexander Motin if (enc_idx == MPR_ENCTABLE_BAD_IDX) {
2845327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: "
2846327f2e6cSStephen McConnell "Enclosure cannot be added to mapping "
2847327f2e6cSStephen McConnell "table because it's full.\n", __func__);
2848991554f2SKenneth D. Merry goto out;
2849991554f2SKenneth D. Merry }
2850991554f2SKenneth D. Merry et_entry = &sc->enclosure_table[enc_idx];
2851991554f2SKenneth D. Merry et_entry->enc_handle = le16toh(event_data->
2852991554f2SKenneth D. Merry EnclosureHandle);
2853327f2e6cSStephen McConnell et_entry->enclosure_id = le64toh(event_data->
2854327f2e6cSStephen McConnell EnclosureLogicalID.High);
2855327f2e6cSStephen McConnell et_entry->enclosure_id =
2856327f2e6cSStephen McConnell ((et_entry->enclosure_id << 32) |
2857327f2e6cSStephen McConnell le64toh(event_data->EnclosureLogicalID.Low));
2858991554f2SKenneth D. Merry et_entry->start_index = MPR_MAPTABLE_BAD_IDX;
2859991554f2SKenneth D. Merry et_entry->dpm_entry_num = MPR_DPM_BAD_IDX;
2860991554f2SKenneth D. Merry et_entry->num_slots = le16toh(event_data->NumSlots);
2861991554f2SKenneth D. Merry et_entry->start_slot = le16toh(event_data->StartSlot);
2862991554f2SKenneth D. Merry et_entry->phy_bits = le32toh(event_data->PhyBits);
2863991554f2SKenneth D. Merry }
2864991554f2SKenneth D. Merry et_entry->init_complete = 1;
2865991554f2SKenneth D. Merry } else if (event_data->ReasonCode ==
2866991554f2SKenneth D. Merry MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING) {
2867327f2e6cSStephen McConnell /*
2868327f2e6cSStephen McConnell * An enclosure was removed. Update its missing count and then
2869327f2e6cSStephen McConnell * update the DPM entry with the new missing count for the
2870327f2e6cSStephen McConnell * enclosure.
2871327f2e6cSStephen McConnell */
2872991554f2SKenneth D. Merry enc_idx = _mapping_get_enc_idx_from_handle(sc,
2873991554f2SKenneth D. Merry le16toh(event_data->EnclosureHandle));
2874991554f2SKenneth D. Merry if (enc_idx == MPR_ENCTABLE_BAD_IDX) {
2875327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: Cannot "
2876b99419aeSAlexander Motin "unmap enclosure with handle 0x%04x because it "
2877b99419aeSAlexander Motin "has already been deleted.\n", __func__,
2878b99419aeSAlexander Motin le16toh(event_data->EnclosureHandle));
2879991554f2SKenneth D. Merry goto out;
2880991554f2SKenneth D. Merry }
2881991554f2SKenneth D. Merry et_entry = &sc->enclosure_table[enc_idx];
2882991554f2SKenneth D. Merry if (et_entry->missing_count < MPR_MAX_MISSING_COUNT)
2883991554f2SKenneth D. Merry et_entry->missing_count++;
2884327f2e6cSStephen McConnell if (sc->is_dpm_enable &&
2885991554f2SKenneth D. Merry et_entry->dpm_entry_num != MPR_DPM_BAD_IDX) {
2886991554f2SKenneth D. Merry dpm_entry += et_entry->dpm_entry_num;
2887991554f2SKenneth D. Merry dpm_entry->MappingInformation = et_entry->num_slots;
2888991554f2SKenneth D. Merry dpm_entry->MappingInformation <<= map_shift;
2889991554f2SKenneth D. Merry dpm_entry->MappingInformation |=
2890991554f2SKenneth D. Merry et_entry->missing_count;
2891991554f2SKenneth D. Merry sc->dpm_flush_entry[et_entry->dpm_entry_num] = 1;
2892991554f2SKenneth D. Merry }
2893991554f2SKenneth D. Merry et_entry->init_complete = 1;
2894991554f2SKenneth D. Merry }
2895991554f2SKenneth D. Merry
2896991554f2SKenneth D. Merry out:
2897991554f2SKenneth D. Merry _mapping_flush_dpm_pages(sc);
2898991554f2SKenneth D. Merry if (sc->pending_map_events)
2899991554f2SKenneth D. Merry sc->pending_map_events--;
2900991554f2SKenneth D. Merry }
2901991554f2SKenneth D. Merry
2902991554f2SKenneth D. Merry /**
2903991554f2SKenneth D. Merry * mpr_mapping_topology_change_event - handle topology change events
2904991554f2SKenneth D. Merry * @sc: per adapter object
2905991554f2SKenneth D. Merry * @event_data: event data payload
2906991554f2SKenneth D. Merry *
2907991554f2SKenneth D. Merry * Returns nothing.
2908991554f2SKenneth D. Merry */
2909991554f2SKenneth D. Merry void
mpr_mapping_topology_change_event(struct mpr_softc * sc,Mpi2EventDataSasTopologyChangeList_t * event_data)2910991554f2SKenneth D. Merry mpr_mapping_topology_change_event(struct mpr_softc *sc,
2911991554f2SKenneth D. Merry Mpi2EventDataSasTopologyChangeList_t *event_data)
2912991554f2SKenneth D. Merry {
2913991554f2SKenneth D. Merry struct _map_topology_change topo_change;
2914991554f2SKenneth D. Merry struct _map_phy_change *phy_change;
2915991554f2SKenneth D. Merry Mpi2EventSasTopoPhyEntry_t *event_phy_change;
2916991554f2SKenneth D. Merry u8 i, num_entries;
2917991554f2SKenneth D. Merry
2918991554f2SKenneth D. Merry topo_change.enc_handle = le16toh(event_data->EnclosureHandle);
2919991554f2SKenneth D. Merry topo_change.exp_handle = le16toh(event_data->ExpanderDevHandle);
2920991554f2SKenneth D. Merry num_entries = event_data->NumEntries;
2921991554f2SKenneth D. Merry topo_change.num_entries = num_entries;
2922991554f2SKenneth D. Merry topo_change.start_phy_num = event_data->StartPhyNum;
2923991554f2SKenneth D. Merry topo_change.num_phys = event_data->NumPhys;
2924991554f2SKenneth D. Merry topo_change.exp_status = event_data->ExpStatus;
2925991554f2SKenneth D. Merry event_phy_change = event_data->PHY;
2926991554f2SKenneth D. Merry topo_change.phy_details = NULL;
2927991554f2SKenneth D. Merry
2928991554f2SKenneth D. Merry if (!num_entries)
2929991554f2SKenneth D. Merry goto out;
2930ac2fffa4SPedro F. Giffuni phy_change = malloc(sizeof(struct _map_phy_change) * num_entries,
2931991554f2SKenneth D. Merry M_MPR, M_NOWAIT|M_ZERO);
2932991554f2SKenneth D. Merry topo_change.phy_details = phy_change;
2933991554f2SKenneth D. Merry if (!phy_change)
2934991554f2SKenneth D. Merry goto out;
2935991554f2SKenneth D. Merry for (i = 0; i < num_entries; i++, event_phy_change++, phy_change++) {
2936991554f2SKenneth D. Merry phy_change->dev_handle = le16toh(event_phy_change->
2937991554f2SKenneth D. Merry AttachedDevHandle);
2938991554f2SKenneth D. Merry phy_change->reason = event_phy_change->PhyStatus &
2939991554f2SKenneth D. Merry MPI2_EVENT_SAS_TOPO_RC_MASK;
2940991554f2SKenneth D. Merry }
2941991554f2SKenneth D. Merry _mapping_update_missing_count(sc, &topo_change);
2942991554f2SKenneth D. Merry _mapping_get_dev_info(sc, &topo_change);
2943991554f2SKenneth D. Merry _mapping_clear_removed_entries(sc);
2944991554f2SKenneth D. Merry _mapping_add_new_device(sc, &topo_change);
2945991554f2SKenneth D. Merry
2946991554f2SKenneth D. Merry out:
2947991554f2SKenneth D. Merry free(topo_change.phy_details, M_MPR);
2948991554f2SKenneth D. Merry _mapping_flush_dpm_pages(sc);
2949991554f2SKenneth D. Merry if (sc->pending_map_events)
2950991554f2SKenneth D. Merry sc->pending_map_events--;
2951991554f2SKenneth D. Merry }
2952991554f2SKenneth D. Merry
2953991554f2SKenneth D. Merry /**
295467feec50SStephen McConnell * mpr_mapping_pcie_topology_change_event - handle PCIe topology change events
295567feec50SStephen McConnell * @sc: per adapter object
295667feec50SStephen McConnell * @event_data: event data payload
295767feec50SStephen McConnell *
295867feec50SStephen McConnell * Returns nothing.
295967feec50SStephen McConnell */
296067feec50SStephen McConnell void
mpr_mapping_pcie_topology_change_event(struct mpr_softc * sc,Mpi26EventDataPCIeTopologyChangeList_t * event_data)296167feec50SStephen McConnell mpr_mapping_pcie_topology_change_event(struct mpr_softc *sc,
296267feec50SStephen McConnell Mpi26EventDataPCIeTopologyChangeList_t *event_data)
296367feec50SStephen McConnell {
296467feec50SStephen McConnell struct _map_pcie_topology_change topo_change;
296567feec50SStephen McConnell struct _map_port_change *port_change;
296667feec50SStephen McConnell Mpi26EventPCIeTopoPortEntry_t *event_port_change;
296767feec50SStephen McConnell u8 i, num_entries;
296867feec50SStephen McConnell
296967feec50SStephen McConnell topo_change.switch_dev_handle = le16toh(event_data->SwitchDevHandle);
297067feec50SStephen McConnell topo_change.enc_handle = le16toh(event_data->EnclosureHandle);
297167feec50SStephen McConnell num_entries = event_data->NumEntries;
297267feec50SStephen McConnell topo_change.num_entries = num_entries;
297367feec50SStephen McConnell topo_change.start_port_num = event_data->StartPortNum;
297467feec50SStephen McConnell topo_change.num_ports = event_data->NumPorts;
297567feec50SStephen McConnell topo_change.switch_status = event_data->SwitchStatus;
297667feec50SStephen McConnell event_port_change = event_data->PortEntry;
297767feec50SStephen McConnell topo_change.port_details = NULL;
297867feec50SStephen McConnell
297967feec50SStephen McConnell if (!num_entries)
298067feec50SStephen McConnell goto out;
2981ac2fffa4SPedro F. Giffuni port_change = malloc(sizeof(struct _map_port_change) * num_entries,
298267feec50SStephen McConnell M_MPR, M_NOWAIT|M_ZERO);
298367feec50SStephen McConnell topo_change.port_details = port_change;
298467feec50SStephen McConnell if (!port_change)
298567feec50SStephen McConnell goto out;
298667feec50SStephen McConnell for (i = 0; i < num_entries; i++, event_port_change++, port_change++) {
298767feec50SStephen McConnell port_change->dev_handle = le16toh(event_port_change->
298867feec50SStephen McConnell AttachedDevHandle);
298967feec50SStephen McConnell port_change->reason = event_port_change->PortStatus;
299067feec50SStephen McConnell }
299167feec50SStephen McConnell _mapping_update_pcie_missing_count(sc, &topo_change);
299267feec50SStephen McConnell _mapping_get_pcie_dev_info(sc, &topo_change);
299367feec50SStephen McConnell _mapping_clear_removed_entries(sc);
299467feec50SStephen McConnell _mapping_add_new_pcie_device(sc, &topo_change);
299567feec50SStephen McConnell
299667feec50SStephen McConnell out:
299767feec50SStephen McConnell free(topo_change.port_details, M_MPR);
299867feec50SStephen McConnell _mapping_flush_dpm_pages(sc);
299967feec50SStephen McConnell if (sc->pending_map_events)
300067feec50SStephen McConnell sc->pending_map_events--;
300167feec50SStephen McConnell }
300267feec50SStephen McConnell
300367feec50SStephen McConnell /**
3004991554f2SKenneth D. Merry * mpr_mapping_ir_config_change_event - handle IR config change list events
3005991554f2SKenneth D. Merry * @sc: per adapter object
3006991554f2SKenneth D. Merry * @event_data: event data payload
3007991554f2SKenneth D. Merry *
3008991554f2SKenneth D. Merry * Returns nothing.
3009991554f2SKenneth D. Merry */
3010991554f2SKenneth D. Merry void
mpr_mapping_ir_config_change_event(struct mpr_softc * sc,Mpi2EventDataIrConfigChangeList_t * event_data)3011991554f2SKenneth D. Merry mpr_mapping_ir_config_change_event(struct mpr_softc *sc,
3012991554f2SKenneth D. Merry Mpi2EventDataIrConfigChangeList_t *event_data)
3013991554f2SKenneth D. Merry {
3014991554f2SKenneth D. Merry Mpi2EventIrConfigElement_t *element;
3015991554f2SKenneth D. Merry int i;
3016991554f2SKenneth D. Merry u64 *wwid_table;
3017991554f2SKenneth D. Merry u32 map_idx, flags;
3018991554f2SKenneth D. Merry struct dev_mapping_table *mt_entry;
3019991554f2SKenneth D. Merry u16 element_flags;
3020991554f2SKenneth D. Merry
3021ac2fffa4SPedro F. Giffuni wwid_table = malloc(sizeof(u64) * event_data->NumElements, M_MPR,
3022991554f2SKenneth D. Merry M_NOWAIT | M_ZERO);
3023991554f2SKenneth D. Merry if (!wwid_table)
3024991554f2SKenneth D. Merry goto out;
3025991554f2SKenneth D. Merry element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
3026991554f2SKenneth D. Merry flags = le32toh(event_data->Flags);
3027327f2e6cSStephen McConnell
3028327f2e6cSStephen McConnell /*
3029327f2e6cSStephen McConnell * For volume changes, get the WWID for the volume and put it in a
3030327f2e6cSStephen McConnell * table to be used in the processing of the IR change event.
3031327f2e6cSStephen McConnell */
3032991554f2SKenneth D. Merry for (i = 0; i < event_data->NumElements; i++, element++) {
3033991554f2SKenneth D. Merry element_flags = le16toh(element->ElementFlags);
3034991554f2SKenneth D. Merry if ((element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_ADDED) &&
3035991554f2SKenneth D. Merry (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_REMOVED) &&
3036991554f2SKenneth D. Merry (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE)
3037991554f2SKenneth D. Merry && (element->ReasonCode !=
3038991554f2SKenneth D. Merry MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED))
3039991554f2SKenneth D. Merry continue;
3040991554f2SKenneth D. Merry if ((element_flags &
3041991554f2SKenneth D. Merry MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK) ==
3042991554f2SKenneth D. Merry MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT) {
3043991554f2SKenneth D. Merry mpr_config_get_volume_wwid(sc,
3044991554f2SKenneth D. Merry le16toh(element->VolDevHandle), &wwid_table[i]);
3045991554f2SKenneth D. Merry }
3046991554f2SKenneth D. Merry }
3047327f2e6cSStephen McConnell
3048327f2e6cSStephen McConnell /*
3049327f2e6cSStephen McConnell * Check the ReasonCode for each element in the IR event and Add/Remove
3050327f2e6cSStephen McConnell * Volumes or Physical Disks of Volumes to/from the mapping table. Use
3051327f2e6cSStephen McConnell * the WWIDs gotten above in wwid_table.
3052327f2e6cSStephen McConnell */
3053991554f2SKenneth D. Merry if (flags == MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG)
3054991554f2SKenneth D. Merry goto out;
3055991554f2SKenneth D. Merry else {
3056991554f2SKenneth D. Merry element = (Mpi2EventIrConfigElement_t *)&event_data->
3057991554f2SKenneth D. Merry ConfigElement[0];
3058991554f2SKenneth D. Merry for (i = 0; i < event_data->NumElements; i++, element++) {
3059991554f2SKenneth D. Merry if (element->ReasonCode ==
3060991554f2SKenneth D. Merry MPI2_EVENT_IR_CHANGE_RC_ADDED ||
3061991554f2SKenneth D. Merry element->ReasonCode ==
3062991554f2SKenneth D. Merry MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED) {
3063991554f2SKenneth D. Merry map_idx = _mapping_get_ir_mt_idx_from_wwid
3064991554f2SKenneth D. Merry (sc, wwid_table[i]);
3065991554f2SKenneth D. Merry if (map_idx != MPR_MAPTABLE_BAD_IDX) {
3066327f2e6cSStephen McConnell /*
3067327f2e6cSStephen McConnell * The volume is already in the mapping
3068327f2e6cSStephen McConnell * table. Just update it's info.
3069327f2e6cSStephen McConnell */
3070991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[map_idx];
3071991554f2SKenneth D. Merry mt_entry->id = map_idx;
3072991554f2SKenneth D. Merry mt_entry->dev_handle = le16toh
3073991554f2SKenneth D. Merry (element->VolDevHandle);
3074991554f2SKenneth D. Merry mt_entry->device_info =
3075991554f2SKenneth D. Merry MPR_DEV_RESERVED | MPR_MAP_IN_USE;
3076991554f2SKenneth D. Merry _mapping_update_ir_missing_cnt(sc,
3077991554f2SKenneth D. Merry map_idx, element, wwid_table[i]);
3078991554f2SKenneth D. Merry continue;
3079991554f2SKenneth D. Merry }
3080327f2e6cSStephen McConnell
3081327f2e6cSStephen McConnell /*
3082327f2e6cSStephen McConnell * Volume is not in mapping table yet. Find a
3083327f2e6cSStephen McConnell * free entry in the mapping table at the
3084327f2e6cSStephen McConnell * volume mapping locations. If no entries are
3085327f2e6cSStephen McConnell * available, this is an error because it means
3086327f2e6cSStephen McConnell * there are more volumes than can be mapped
3087327f2e6cSStephen McConnell * and that should never happen for volumes.
3088327f2e6cSStephen McConnell */
3089991554f2SKenneth D. Merry map_idx = _mapping_get_free_ir_mt_idx(sc);
3090991554f2SKenneth D. Merry if (map_idx == MPR_MAPTABLE_BAD_IDX)
3091327f2e6cSStephen McConnell {
3092327f2e6cSStephen McConnell mpr_dprint(sc, MPR_ERROR | MPR_MAPPING,
3093327f2e6cSStephen McConnell "%s: failed to add the volume with "
3094327f2e6cSStephen McConnell "handle 0x%04x because there is no "
3095327f2e6cSStephen McConnell "free space available in the "
3096327f2e6cSStephen McConnell "mapping table\n", __func__,
3097327f2e6cSStephen McConnell le16toh(element->VolDevHandle));
3098991554f2SKenneth D. Merry continue;
3099991554f2SKenneth D. Merry }
3100991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[map_idx];
3101991554f2SKenneth D. Merry mt_entry->physical_id = wwid_table[i];
3102991554f2SKenneth D. Merry mt_entry->id = map_idx;
3103991554f2SKenneth D. Merry mt_entry->dev_handle = le16toh(element->
3104991554f2SKenneth D. Merry VolDevHandle);
3105991554f2SKenneth D. Merry mt_entry->device_info = MPR_DEV_RESERVED |
3106991554f2SKenneth D. Merry MPR_MAP_IN_USE;
3107991554f2SKenneth D. Merry _mapping_update_ir_missing_cnt(sc, map_idx,
3108991554f2SKenneth D. Merry element, wwid_table[i]);
3109991554f2SKenneth D. Merry } else if (element->ReasonCode ==
3110991554f2SKenneth D. Merry MPI2_EVENT_IR_CHANGE_RC_REMOVED) {
3111991554f2SKenneth D. Merry map_idx = _mapping_get_ir_mt_idx_from_wwid(sc,
3112991554f2SKenneth D. Merry wwid_table[i]);
3113991554f2SKenneth D. Merry if (map_idx == MPR_MAPTABLE_BAD_IDX) {
3114327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING,"%s: Failed "
3115327f2e6cSStephen McConnell "to remove a volume because it has "
3116327f2e6cSStephen McConnell "already been removed.\n",
3117327f2e6cSStephen McConnell __func__);
3118991554f2SKenneth D. Merry continue;
3119991554f2SKenneth D. Merry }
3120991554f2SKenneth D. Merry _mapping_update_ir_missing_cnt(sc, map_idx,
3121991554f2SKenneth D. Merry element, wwid_table[i]);
3122991554f2SKenneth D. Merry } else if (element->ReasonCode ==
3123991554f2SKenneth D. Merry MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED) {
3124991554f2SKenneth D. Merry map_idx = _mapping_get_mt_idx_from_handle(sc,
3125991554f2SKenneth D. Merry le16toh(element->VolDevHandle));
3126991554f2SKenneth D. Merry if (map_idx == MPR_MAPTABLE_BAD_IDX) {
3127327f2e6cSStephen McConnell mpr_dprint(sc, MPR_MAPPING,"%s: Failed "
3128327f2e6cSStephen McConnell "to remove volume with handle "
3129327f2e6cSStephen McConnell "0x%04x because it has already "
3130327f2e6cSStephen McConnell "been removed.\n", __func__,
3131991554f2SKenneth D. Merry le16toh(element->VolDevHandle));
3132991554f2SKenneth D. Merry continue;
3133991554f2SKenneth D. Merry }
3134991554f2SKenneth D. Merry mt_entry = &sc->mapping_table[map_idx];
3135991554f2SKenneth D. Merry _mapping_update_ir_missing_cnt(sc, map_idx,
3136991554f2SKenneth D. Merry element, mt_entry->physical_id);
3137991554f2SKenneth D. Merry }
3138991554f2SKenneth D. Merry }
3139991554f2SKenneth D. Merry }
3140991554f2SKenneth D. Merry
3141991554f2SKenneth D. Merry out:
3142991554f2SKenneth D. Merry _mapping_flush_dpm_pages(sc);
3143991554f2SKenneth D. Merry free(wwid_table, M_MPR);
3144991554f2SKenneth D. Merry if (sc->pending_map_events)
3145991554f2SKenneth D. Merry sc->pending_map_events--;
3146991554f2SKenneth D. Merry }
3147