xref: /freebsd/sys/dev/mrsas/mrsas_fp.c (revision 02190a5647d1ff1bd72a1a5fcca1f770c9144d01)
1665484d8SDoug Ambrisko /*
2665484d8SDoug Ambrisko  * Copyright (c) 2014, LSI Corp.
3665484d8SDoug Ambrisko  * All rights reserved.
4665484d8SDoug Ambrisko  * Author: Marian Choy
5665484d8SDoug Ambrisko  * Support: freebsdraid@lsi.com
6665484d8SDoug Ambrisko  *
7665484d8SDoug Ambrisko  * Redistribution and use in source and binary forms, with or without
8665484d8SDoug Ambrisko  * modification, are permitted provided that the following conditions
9665484d8SDoug Ambrisko  * are met:
10665484d8SDoug Ambrisko  *
11665484d8SDoug Ambrisko  * 1. Redistributions of source code must retain the above copyright
12665484d8SDoug Ambrisko  *    notice, this list of conditions and the following disclaimer.
13665484d8SDoug Ambrisko  * 2. Redistributions in binary form must reproduce the above copyright
14665484d8SDoug Ambrisko  *    notice, this list of conditions and the following disclaimer in
15665484d8SDoug Ambrisko  *    the documentation and/or other materials provided with the
16665484d8SDoug Ambrisko  *    distribution.
17665484d8SDoug Ambrisko  * 3. Neither the name of the <ORGANIZATION> nor the names of its
18665484d8SDoug Ambrisko  *    contributors may be used to endorse or promote products derived
19665484d8SDoug Ambrisko  *    from this software without specific prior written permission.
20665484d8SDoug Ambrisko  *
21665484d8SDoug Ambrisko  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22665484d8SDoug Ambrisko  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23665484d8SDoug Ambrisko  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24665484d8SDoug Ambrisko  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25665484d8SDoug Ambrisko  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26665484d8SDoug Ambrisko  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27665484d8SDoug Ambrisko  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28665484d8SDoug Ambrisko  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29665484d8SDoug Ambrisko  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30665484d8SDoug Ambrisko  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31665484d8SDoug Ambrisko  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32665484d8SDoug Ambrisko  * POSSIBILITY OF SUCH DAMAGE.
33665484d8SDoug Ambrisko  *
34665484d8SDoug Ambrisko  * The views and conclusions contained in the software and documentation
35665484d8SDoug Ambrisko  * are those of the authors and should not be interpreted as representing
36665484d8SDoug Ambrisko  * official policies,either expressed or implied, of the FreeBSD Project.
37665484d8SDoug Ambrisko  *
38665484d8SDoug Ambrisko  * Send feedback to: <megaraidfbsd@lsi.com>
39665484d8SDoug Ambrisko  * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
40665484d8SDoug Ambrisko  *    ATTN: MegaRaid FreeBSD
41665484d8SDoug Ambrisko  *
42665484d8SDoug Ambrisko  */
43665484d8SDoug Ambrisko 
44665484d8SDoug Ambrisko #include <sys/cdefs.h>
45665484d8SDoug Ambrisko __FBSDID("$FreeBSD$");
46665484d8SDoug Ambrisko 
47665484d8SDoug Ambrisko #include <dev/mrsas/mrsas.h>
48665484d8SDoug Ambrisko 
49665484d8SDoug Ambrisko #include <cam/cam.h>
50665484d8SDoug Ambrisko #include <cam/cam_ccb.h>
51665484d8SDoug Ambrisko #include <cam/cam_sim.h>
52665484d8SDoug Ambrisko #include <cam/cam_xpt_sim.h>
53665484d8SDoug Ambrisko #include <cam/cam_debug.h>
54665484d8SDoug Ambrisko #include <cam/cam_periph.h>
55665484d8SDoug Ambrisko #include <cam/cam_xpt_periph.h>
56665484d8SDoug Ambrisko 
57665484d8SDoug Ambrisko 
58665484d8SDoug Ambrisko /*
59665484d8SDoug Ambrisko  * Function prototypes
60665484d8SDoug Ambrisko  */
61665484d8SDoug Ambrisko u_int8_t MR_ValidateMapInfo(struct mrsas_softc *sc);
62665484d8SDoug Ambrisko u_int8_t mrsas_get_best_arm(PLD_LOAD_BALANCE_INFO lbInfo, u_int8_t arm,
63665484d8SDoug Ambrisko        u_int64_t block, u_int32_t count);
64665484d8SDoug Ambrisko u_int8_t MR_BuildRaidContext(struct mrsas_softc *sc,
65665484d8SDoug Ambrisko         struct IO_REQUEST_INFO *io_info,
66665484d8SDoug Ambrisko         RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map);
67665484d8SDoug Ambrisko u_int8_t MR_GetPhyParams(struct mrsas_softc *sc, u_int32_t ld,
68665484d8SDoug Ambrisko         u_int64_t stripRow, u_int16_t stripRef, struct IO_REQUEST_INFO *io_info,
69665484d8SDoug Ambrisko         RAID_CONTEXT *pRAID_Context,
70665484d8SDoug Ambrisko         MR_FW_RAID_MAP_ALL *map);
71665484d8SDoug Ambrisko u_int16_t MR_TargetIdToLdGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map);
72665484d8SDoug Ambrisko u_int32_t MR_LdBlockSizeGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map);
73665484d8SDoug Ambrisko u_int16_t MR_GetLDTgtId(u_int32_t ld, MR_FW_RAID_MAP_ALL *map);
74665484d8SDoug Ambrisko u_int16_t mrsas_get_updated_dev_handle(PLD_LOAD_BALANCE_INFO lbInfo,
75665484d8SDoug Ambrisko         struct IO_REQUEST_INFO *io_info);
76665484d8SDoug Ambrisko u_int32_t mega_mod64(u_int64_t dividend, u_int32_t divisor);
77665484d8SDoug Ambrisko u_int32_t MR_GetSpanBlock(u_int32_t ld, u_int64_t row, u_int64_t *span_blk,
78665484d8SDoug Ambrisko         MR_FW_RAID_MAP_ALL *map, int *div_error);
79665484d8SDoug Ambrisko u_int64_t mega_div64_32(u_int64_t dividend, u_int32_t divisor);
80665484d8SDoug Ambrisko void mrsas_update_load_balance_params(MR_FW_RAID_MAP_ALL *map,
81665484d8SDoug Ambrisko         PLD_LOAD_BALANCE_INFO lbInfo);
82665484d8SDoug Ambrisko void mrsas_set_pd_lba(MRSAS_RAID_SCSI_IO_REQUEST *io_request,
83665484d8SDoug Ambrisko         u_int8_t cdb_len, struct IO_REQUEST_INFO *io_info, union ccb *ccb,
84665484d8SDoug Ambrisko         MR_FW_RAID_MAP_ALL *local_map_ptr, u_int32_t ref_tag,
85665484d8SDoug Ambrisko         u_int32_t ld_block_size);
86665484d8SDoug Ambrisko static u_int16_t MR_LdSpanArrayGet(u_int32_t ld, u_int32_t span,
87665484d8SDoug Ambrisko         MR_FW_RAID_MAP_ALL *map);
88665484d8SDoug Ambrisko static u_int16_t MR_PdDevHandleGet(u_int32_t pd, MR_FW_RAID_MAP_ALL *map);
89665484d8SDoug Ambrisko static u_int16_t MR_ArPdGet(u_int32_t ar, u_int32_t arm,
90665484d8SDoug Ambrisko         MR_FW_RAID_MAP_ALL *map);
91665484d8SDoug Ambrisko static MR_LD_SPAN *MR_LdSpanPtrGet(u_int32_t ld, u_int32_t span,
92665484d8SDoug Ambrisko         MR_FW_RAID_MAP_ALL *map);
93665484d8SDoug Ambrisko static u_int8_t MR_LdDataArmGet(u_int32_t ld, u_int32_t armIdx,
94665484d8SDoug Ambrisko         MR_FW_RAID_MAP_ALL *map);
95665484d8SDoug Ambrisko static MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u_int32_t ld,
96665484d8SDoug Ambrisko         MR_FW_RAID_MAP_ALL *map);
97665484d8SDoug Ambrisko MR_LD_RAID *MR_LdRaidGet(u_int32_t ld, MR_FW_RAID_MAP_ALL *map);
98665484d8SDoug Ambrisko 
99665484d8SDoug Ambrisko /*
100665484d8SDoug Ambrisko  * Spanset related function prototypes
101665484d8SDoug Ambrisko  * Added for PRL11 configuration (Uneven span support)
102665484d8SDoug Ambrisko  */
103665484d8SDoug Ambrisko void mr_update_span_set(MR_FW_RAID_MAP_ALL *map, PLD_SPAN_INFO ldSpanInfo);
104665484d8SDoug Ambrisko static u_int8_t mr_spanset_get_phy_params(struct mrsas_softc *sc, u_int32_t ld,
105665484d8SDoug Ambrisko        u_int64_t stripRow, u_int16_t stripRef, struct IO_REQUEST_INFO *io_info,
106665484d8SDoug Ambrisko        RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map);
107665484d8SDoug Ambrisko static u_int64_t get_row_from_strip(struct mrsas_softc *sc, u_int32_t ld,
108665484d8SDoug Ambrisko        u_int64_t strip, MR_FW_RAID_MAP_ALL *map);
109665484d8SDoug Ambrisko static u_int32_t mr_spanset_get_span_block(struct mrsas_softc *sc,
110665484d8SDoug Ambrisko        u_int32_t ld, u_int64_t row, u_int64_t *span_blk,
111665484d8SDoug Ambrisko        MR_FW_RAID_MAP_ALL *map, int *div_error);
112665484d8SDoug Ambrisko static u_int8_t get_arm(struct mrsas_softc *sc, u_int32_t ld, u_int8_t span,
113665484d8SDoug Ambrisko        u_int64_t stripe, MR_FW_RAID_MAP_ALL *map);
114665484d8SDoug Ambrisko 
115665484d8SDoug Ambrisko 
116665484d8SDoug Ambrisko /*
117665484d8SDoug Ambrisko  * Spanset related defines
118665484d8SDoug Ambrisko  * Added for PRL11 configuration(Uneven span support)
119665484d8SDoug Ambrisko  */
120665484d8SDoug Ambrisko #define SPAN_ROW_SIZE(map, ld, index_) MR_LdSpanPtrGet(ld, index_, map)->spanRowSize
121665484d8SDoug Ambrisko #define SPAN_ROW_DATA_SIZE(map_, ld, index_)   MR_LdSpanPtrGet(ld, index_, map)->spanRowDataSize
122665484d8SDoug Ambrisko #define SPAN_INVALID    0xff
123665484d8SDoug Ambrisko #define SPAN_DEBUG 0
124665484d8SDoug Ambrisko 
125665484d8SDoug Ambrisko /*
126665484d8SDoug Ambrisko  * Related Defines
127665484d8SDoug Ambrisko  */
128665484d8SDoug Ambrisko 
129665484d8SDoug Ambrisko typedef u_int64_t  REGION_KEY;
130665484d8SDoug Ambrisko typedef u_int32_t  REGION_LEN;
131665484d8SDoug Ambrisko 
132665484d8SDoug Ambrisko #define MR_LD_STATE_OPTIMAL 3
133665484d8SDoug Ambrisko #define FALSE 0
134665484d8SDoug Ambrisko #define TRUE 1
135665484d8SDoug Ambrisko 
136665484d8SDoug Ambrisko 
137665484d8SDoug Ambrisko /*
138665484d8SDoug Ambrisko  * Related Macros
139665484d8SDoug Ambrisko  */
140665484d8SDoug Ambrisko 
141665484d8SDoug Ambrisko #define ABS_DIFF(a,b)   ( ((a) > (b)) ? ((a) - (b)) : ((b) - (a)) )
142665484d8SDoug Ambrisko 
143665484d8SDoug Ambrisko #define swap32(x) \
144665484d8SDoug Ambrisko   ((unsigned int)( \
145665484d8SDoug Ambrisko     (((unsigned int)(x) & (unsigned int)0x000000ffUL) << 24) | \
146665484d8SDoug Ambrisko     (((unsigned int)(x) & (unsigned int)0x0000ff00UL) <<  8) | \
147665484d8SDoug Ambrisko     (((unsigned int)(x) & (unsigned int)0x00ff0000UL) >>  8) | \
148665484d8SDoug Ambrisko     (((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24) ))
149665484d8SDoug Ambrisko 
150665484d8SDoug Ambrisko 
151665484d8SDoug Ambrisko /*
152665484d8SDoug Ambrisko  * In-line functions for mod and divide of 64-bit dividend and 32-bit divisor.
153665484d8SDoug Ambrisko  * Assumes a check for a divisor of zero is not possible.
154665484d8SDoug Ambrisko  *
155665484d8SDoug Ambrisko  * @param dividend   : Dividend
156665484d8SDoug Ambrisko  * @param divisor    : Divisor
157665484d8SDoug Ambrisko  * @return remainder
158665484d8SDoug Ambrisko  */
159665484d8SDoug Ambrisko 
160665484d8SDoug Ambrisko #define mega_mod64(dividend, divisor) ({ \
161665484d8SDoug Ambrisko int remainder; \
162665484d8SDoug Ambrisko remainder = ((u_int64_t) (dividend)) % (u_int32_t) (divisor); \
163665484d8SDoug Ambrisko remainder;})
164665484d8SDoug Ambrisko 
165665484d8SDoug Ambrisko #define mega_div64_32(dividend, divisor) ({ \
166665484d8SDoug Ambrisko int quotient; \
167665484d8SDoug Ambrisko quotient = ((u_int64_t) (dividend)) / (u_int32_t) (divisor); \
168665484d8SDoug Ambrisko quotient;})
169665484d8SDoug Ambrisko 
170665484d8SDoug Ambrisko 
171665484d8SDoug Ambrisko /*
172665484d8SDoug Ambrisko  * Various RAID map access functions.  These functions access the various
173665484d8SDoug Ambrisko  * parts of the RAID map and returns the appropriate parameters.
174665484d8SDoug Ambrisko  */
175665484d8SDoug Ambrisko 
176665484d8SDoug Ambrisko MR_LD_RAID *MR_LdRaidGet(u_int32_t ld, MR_FW_RAID_MAP_ALL *map)
177665484d8SDoug Ambrisko {
178665484d8SDoug Ambrisko     return (&map->raidMap.ldSpanMap[ld].ldRaid);
179665484d8SDoug Ambrisko }
180665484d8SDoug Ambrisko 
181665484d8SDoug Ambrisko u_int16_t MR_GetLDTgtId(u_int32_t ld, MR_FW_RAID_MAP_ALL *map)
182665484d8SDoug Ambrisko {
183665484d8SDoug Ambrisko     return (map->raidMap.ldSpanMap[ld].ldRaid.targetId);
184665484d8SDoug Ambrisko }
185665484d8SDoug Ambrisko 
186665484d8SDoug Ambrisko static u_int16_t MR_LdSpanArrayGet(u_int32_t ld, u_int32_t span, MR_FW_RAID_MAP_ALL *map)
187665484d8SDoug Ambrisko {
188665484d8SDoug Ambrisko     return map->raidMap.ldSpanMap[ld].spanBlock[span].span.arrayRef;
189665484d8SDoug Ambrisko }
190665484d8SDoug Ambrisko 
191665484d8SDoug Ambrisko static u_int8_t MR_LdDataArmGet(u_int32_t ld, u_int32_t armIdx, MR_FW_RAID_MAP_ALL *map)
192665484d8SDoug Ambrisko {
193665484d8SDoug Ambrisko     return map->raidMap.ldSpanMap[ld].dataArmMap[armIdx];
194665484d8SDoug Ambrisko }
195665484d8SDoug Ambrisko 
196665484d8SDoug Ambrisko static u_int16_t MR_PdDevHandleGet(u_int32_t pd, MR_FW_RAID_MAP_ALL *map)
197665484d8SDoug Ambrisko {
198665484d8SDoug Ambrisko     return map->raidMap.devHndlInfo[pd].curDevHdl;
199665484d8SDoug Ambrisko }
200665484d8SDoug Ambrisko 
201665484d8SDoug Ambrisko static u_int16_t MR_ArPdGet(u_int32_t ar, u_int32_t arm, MR_FW_RAID_MAP_ALL *map)
202665484d8SDoug Ambrisko {
203665484d8SDoug Ambrisko     return map->raidMap.arMapInfo[ar].pd[arm];
204665484d8SDoug Ambrisko }
205665484d8SDoug Ambrisko 
206665484d8SDoug Ambrisko static MR_LD_SPAN *MR_LdSpanPtrGet(u_int32_t ld, u_int32_t span, MR_FW_RAID_MAP_ALL *map)
207665484d8SDoug Ambrisko {
208665484d8SDoug Ambrisko     return &map->raidMap.ldSpanMap[ld].spanBlock[span].span;
209665484d8SDoug Ambrisko }
210665484d8SDoug Ambrisko 
211665484d8SDoug Ambrisko static MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u_int32_t ld, MR_FW_RAID_MAP_ALL *map)
212665484d8SDoug Ambrisko {
213665484d8SDoug Ambrisko     return &map->raidMap.ldSpanMap[ld].spanBlock[0];
214665484d8SDoug Ambrisko }
215665484d8SDoug Ambrisko 
216665484d8SDoug Ambrisko u_int16_t MR_TargetIdToLdGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map)
217665484d8SDoug Ambrisko {
218665484d8SDoug Ambrisko     return map->raidMap.ldTgtIdToLd[ldTgtId];
219665484d8SDoug Ambrisko }
220665484d8SDoug Ambrisko 
221665484d8SDoug Ambrisko u_int32_t MR_LdBlockSizeGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map)
222665484d8SDoug Ambrisko {
223665484d8SDoug Ambrisko     MR_LD_RAID *raid;
224665484d8SDoug Ambrisko     u_int32_t ld, ldBlockSize = MRSAS_SCSIBLOCKSIZE;
225665484d8SDoug Ambrisko 
226665484d8SDoug Ambrisko     ld = MR_TargetIdToLdGet(ldTgtId, map);
227665484d8SDoug Ambrisko 
228665484d8SDoug Ambrisko     /*
229665484d8SDoug Ambrisko      * Check if logical drive was removed.
230665484d8SDoug Ambrisko      */
231665484d8SDoug Ambrisko     if (ld >= MAX_LOGICAL_DRIVES)
232665484d8SDoug Ambrisko         return ldBlockSize;
233665484d8SDoug Ambrisko 
234665484d8SDoug Ambrisko     raid = MR_LdRaidGet(ld, map);
235665484d8SDoug Ambrisko     ldBlockSize = raid->logicalBlockLength;
236665484d8SDoug Ambrisko     if (!ldBlockSize)
237665484d8SDoug Ambrisko         ldBlockSize = MRSAS_SCSIBLOCKSIZE;
238665484d8SDoug Ambrisko 
239665484d8SDoug Ambrisko     return ldBlockSize;
240665484d8SDoug Ambrisko }
241665484d8SDoug Ambrisko 
242665484d8SDoug Ambrisko /**
243665484d8SDoug Ambrisko  * MR_ValidateMapInfo:        Validate RAID map
244665484d8SDoug Ambrisko  * input:                     Adapter instance soft state
245665484d8SDoug Ambrisko  *
246665484d8SDoug Ambrisko  * This function checks and validates the loaded RAID map. It returns 0 if
247665484d8SDoug Ambrisko  * successful, and 1 otherwise.
248665484d8SDoug Ambrisko  */
249665484d8SDoug Ambrisko u_int8_t MR_ValidateMapInfo(struct mrsas_softc *sc)
250665484d8SDoug Ambrisko {
251665484d8SDoug Ambrisko 	if (!sc) {
252665484d8SDoug Ambrisko 		return 1;
253665484d8SDoug Ambrisko 	}
254665484d8SDoug Ambrisko     uint32_t total_map_sz;
255665484d8SDoug Ambrisko     MR_FW_RAID_MAP_ALL *map = sc->raidmap_mem[(sc->map_id & 1)];
256665484d8SDoug Ambrisko     MR_FW_RAID_MAP *pFwRaidMap = &map->raidMap;
257665484d8SDoug Ambrisko     PLD_SPAN_INFO ldSpanInfo = (PLD_SPAN_INFO) &sc->log_to_span;
258665484d8SDoug Ambrisko 
259665484d8SDoug Ambrisko     total_map_sz = (sizeof(MR_FW_RAID_MAP) - sizeof(MR_LD_SPAN_MAP) +
260665484d8SDoug Ambrisko                      (sizeof(MR_LD_SPAN_MAP) * pFwRaidMap->ldCount));
261665484d8SDoug Ambrisko 
262665484d8SDoug Ambrisko     if (pFwRaidMap->totalSize != total_map_sz) {
263665484d8SDoug Ambrisko         device_printf(sc->mrsas_dev, "map size %x not matching ld count\n", total_map_sz);
264665484d8SDoug Ambrisko         device_printf(sc->mrsas_dev, "span map= %x\n", (unsigned int)sizeof(MR_LD_SPAN_MAP));
265665484d8SDoug Ambrisko         device_printf(sc->mrsas_dev, "pFwRaidMap->totalSize=%x\n", pFwRaidMap->totalSize);
266665484d8SDoug Ambrisko         return 1;
267665484d8SDoug Ambrisko     }
268665484d8SDoug Ambrisko 
269665484d8SDoug Ambrisko     if (sc->UnevenSpanSupport) {
270665484d8SDoug Ambrisko         mr_update_span_set(map, ldSpanInfo);
271665484d8SDoug Ambrisko 	}
272665484d8SDoug Ambrisko 
273665484d8SDoug Ambrisko     mrsas_update_load_balance_params(map, sc->load_balance_info);
274665484d8SDoug Ambrisko 
275665484d8SDoug Ambrisko     return 0;
276665484d8SDoug Ambrisko }
277665484d8SDoug Ambrisko 
278665484d8SDoug Ambrisko /*
279665484d8SDoug Ambrisko  * ******************************************************************************
280665484d8SDoug Ambrisko  *
281665484d8SDoug Ambrisko  *  Function to print info about span set created in driver from FW raid map
282665484d8SDoug Ambrisko  *
283665484d8SDoug Ambrisko  *  Inputs :
284665484d8SDoug Ambrisko  *  map    - LD map
285665484d8SDoug Ambrisko  *  ldSpanInfo - ldSpanInfo per HBA instance
286665484d8SDoug Ambrisko  *
287665484d8SDoug Ambrisko  *
288665484d8SDoug Ambrisko  * */
289665484d8SDoug Ambrisko #if SPAN_DEBUG
290665484d8SDoug Ambrisko static int getSpanInfo(MR_FW_RAID_MAP_ALL *map, PLD_SPAN_INFO ldSpanInfo)
291665484d8SDoug Ambrisko {
292665484d8SDoug Ambrisko 
293665484d8SDoug Ambrisko        u_int8_t   span;
294665484d8SDoug Ambrisko        u_int32_t    element;
295665484d8SDoug Ambrisko        MR_LD_RAID *raid;
296665484d8SDoug Ambrisko        LD_SPAN_SET *span_set;
297665484d8SDoug Ambrisko        MR_QUAD_ELEMENT    *quad;
298665484d8SDoug Ambrisko        int ldCount;
299665484d8SDoug Ambrisko        u_int16_t ld;
300665484d8SDoug Ambrisko 
301665484d8SDoug Ambrisko        for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++)
302665484d8SDoug Ambrisko        {
303665484d8SDoug Ambrisko                ld = MR_TargetIdToLdGet(ldCount, map);
304665484d8SDoug Ambrisko                        if (ld >= MAX_LOGICAL_DRIVES) {
305665484d8SDoug Ambrisko                        continue;
306665484d8SDoug Ambrisko                }
307665484d8SDoug Ambrisko                raid = MR_LdRaidGet(ld, map);
308665484d8SDoug Ambrisko                printf("LD %x: span_depth=%x\n", ld, raid->spanDepth);
309665484d8SDoug Ambrisko                for (span=0; span<raid->spanDepth; span++)
310665484d8SDoug Ambrisko                        printf("Span=%x, number of quads=%x\n", span,
311665484d8SDoug Ambrisko                        map->raidMap.ldSpanMap[ld].spanBlock[span].
312665484d8SDoug Ambrisko                        block_span_info.noElements);
313665484d8SDoug Ambrisko                for (element=0; element < MAX_QUAD_DEPTH; element++) {
314665484d8SDoug Ambrisko                        span_set = &(ldSpanInfo[ld].span_set[element]);
315665484d8SDoug Ambrisko                        if (span_set->span_row_data_width == 0) break;
316665484d8SDoug Ambrisko 
317665484d8SDoug Ambrisko                        printf("  Span Set %x: width=%x, diff=%x\n", element,
318665484d8SDoug Ambrisko                                (unsigned int)span_set->span_row_data_width,
319665484d8SDoug Ambrisko                                (unsigned int)span_set->diff);
320665484d8SDoug Ambrisko                        printf("    logical LBA start=0x%08lx, end=0x%08lx\n",
321665484d8SDoug Ambrisko                                (long unsigned int)span_set->log_start_lba,
322665484d8SDoug Ambrisko                                (long unsigned int)span_set->log_end_lba);
323665484d8SDoug Ambrisko                        printf("       span row start=0x%08lx, end=0x%08lx\n",
324665484d8SDoug Ambrisko                                (long unsigned int)span_set->span_row_start,
325665484d8SDoug Ambrisko                                (long unsigned int)span_set->span_row_end);
326665484d8SDoug Ambrisko                        printf("       data row start=0x%08lx, end=0x%08lx\n",
327665484d8SDoug Ambrisko                                (long unsigned int)span_set->data_row_start,
328665484d8SDoug Ambrisko                                (long unsigned int)span_set->data_row_end);
329665484d8SDoug Ambrisko                        printf("       data strip start=0x%08lx, end=0x%08lx\n",
330665484d8SDoug Ambrisko                                (long unsigned int)span_set->data_strip_start,
331665484d8SDoug Ambrisko                                (long unsigned int)span_set->data_strip_end);
332665484d8SDoug Ambrisko 
333665484d8SDoug Ambrisko                        for (span=0; span<raid->spanDepth; span++) {
334665484d8SDoug Ambrisko                                if (map->raidMap.ldSpanMap[ld].spanBlock[span].
335665484d8SDoug Ambrisko                                        block_span_info.noElements >=element+1){
336665484d8SDoug Ambrisko                                        quad = &map->raidMap.ldSpanMap[ld].
337665484d8SDoug Ambrisko                                                spanBlock[span].block_span_info.
338665484d8SDoug Ambrisko                                                quad[element];
339665484d8SDoug Ambrisko                                printf("  Span=%x, Quad=%x, diff=%x\n", span,
340665484d8SDoug Ambrisko                                        element, quad->diff);
341665484d8SDoug Ambrisko                                printf("    offset_in_span=0x%08lx\n",
342665484d8SDoug Ambrisko                                        (long unsigned int)quad->offsetInSpan);
343665484d8SDoug Ambrisko                                printf("     logical start=0x%08lx, end=0x%08lx\n",
344665484d8SDoug Ambrisko                                        (long unsigned int)quad->logStart,
345665484d8SDoug Ambrisko                                        (long unsigned int)quad->logEnd);
346665484d8SDoug Ambrisko                                }
347665484d8SDoug Ambrisko                        }
348665484d8SDoug Ambrisko                }
349665484d8SDoug Ambrisko        }
350665484d8SDoug Ambrisko     return 0;
351665484d8SDoug Ambrisko }
352665484d8SDoug Ambrisko #endif
353665484d8SDoug Ambrisko /*
354665484d8SDoug Ambrisko ******************************************************************************
355665484d8SDoug Ambrisko *
356665484d8SDoug Ambrisko * This routine calculates the Span block for given row using spanset.
357665484d8SDoug Ambrisko *
358665484d8SDoug Ambrisko * Inputs :
359665484d8SDoug Ambrisko *    instance - HBA instance
360665484d8SDoug Ambrisko *    ld   - Logical drive number
361665484d8SDoug Ambrisko *    row        - Row number
362665484d8SDoug Ambrisko *    map    - LD map
363665484d8SDoug Ambrisko *
364665484d8SDoug Ambrisko * Outputs :
365665484d8SDoug Ambrisko *
366665484d8SDoug Ambrisko *    span          - Span number
367665484d8SDoug Ambrisko *    block         - Absolute Block number in the physical disk
368665484d8SDoug Ambrisko *    div_error    - Devide error code.
369665484d8SDoug Ambrisko */
370665484d8SDoug Ambrisko 
371665484d8SDoug Ambrisko u_int32_t mr_spanset_get_span_block(struct mrsas_softc *sc, u_int32_t ld, u_int64_t row,
372665484d8SDoug Ambrisko                u_int64_t *span_blk, MR_FW_RAID_MAP_ALL *map, int *div_error)
373665484d8SDoug Ambrisko {
374665484d8SDoug Ambrisko        MR_LD_RAID         *raid = MR_LdRaidGet(ld, map);
375665484d8SDoug Ambrisko        LD_SPAN_SET *span_set;
376665484d8SDoug Ambrisko        MR_QUAD_ELEMENT    *quad;
377665484d8SDoug Ambrisko        u_int32_t    span, info;
378665484d8SDoug Ambrisko        PLD_SPAN_INFO ldSpanInfo = sc->log_to_span;
379665484d8SDoug Ambrisko 
380665484d8SDoug Ambrisko        for (info=0; info < MAX_QUAD_DEPTH; info++) {
381665484d8SDoug Ambrisko                span_set = &(ldSpanInfo[ld].span_set[info]);
382665484d8SDoug Ambrisko 
383665484d8SDoug Ambrisko                if (span_set->span_row_data_width == 0) break;
384665484d8SDoug Ambrisko                if (row > span_set->data_row_end) continue;
385665484d8SDoug Ambrisko 
386665484d8SDoug Ambrisko                for (span=0; span<raid->spanDepth; span++)
387665484d8SDoug Ambrisko                        if (map->raidMap.ldSpanMap[ld].spanBlock[span].
388665484d8SDoug Ambrisko                                block_span_info.noElements >= info+1) {
389665484d8SDoug Ambrisko                                quad = &map->raidMap.ldSpanMap[ld].
390665484d8SDoug Ambrisko                                        spanBlock[span].
391665484d8SDoug Ambrisko                                        block_span_info.quad[info];
392665484d8SDoug Ambrisko                                if (quad->diff == 0) {
393665484d8SDoug Ambrisko                                        *div_error = 1;
394665484d8SDoug Ambrisko                                        return span;
395665484d8SDoug Ambrisko                                }
396665484d8SDoug Ambrisko                                if ( quad->logStart <= row  &&
397665484d8SDoug Ambrisko                                        row <= quad->logEnd  &&
398665484d8SDoug Ambrisko                                        (mega_mod64(row - quad->logStart,
399665484d8SDoug Ambrisko                                                quad->diff)) == 0 ) {
400665484d8SDoug Ambrisko                                        if (span_blk != NULL) {
401665484d8SDoug Ambrisko                                               u_int64_t  blk;
402665484d8SDoug Ambrisko                                                blk = mega_div64_32
403665484d8SDoug Ambrisko                                                    ((row - quad->logStart),
404665484d8SDoug Ambrisko                                                    quad->diff);
405665484d8SDoug Ambrisko                                                blk = (blk + quad->offsetInSpan)
406665484d8SDoug Ambrisko                                                         << raid->stripeShift;
407665484d8SDoug Ambrisko                                                *span_blk = blk;
408665484d8SDoug Ambrisko                                        }
409665484d8SDoug Ambrisko                                        return span;
410665484d8SDoug Ambrisko                                }
411665484d8SDoug Ambrisko                        }
412665484d8SDoug Ambrisko        }
413665484d8SDoug Ambrisko        return SPAN_INVALID;
414665484d8SDoug Ambrisko }
415665484d8SDoug Ambrisko 
416665484d8SDoug Ambrisko /*
417665484d8SDoug Ambrisko ******************************************************************************
418665484d8SDoug Ambrisko *
419665484d8SDoug Ambrisko * This routine calculates the row for given strip using spanset.
420665484d8SDoug Ambrisko *
421665484d8SDoug Ambrisko * Inputs :
422665484d8SDoug Ambrisko *    instance - HBA instance
423665484d8SDoug Ambrisko *    ld   - Logical drive number
424665484d8SDoug Ambrisko *    Strip        - Strip
425665484d8SDoug Ambrisko *    map    - LD map
426665484d8SDoug Ambrisko *
427665484d8SDoug Ambrisko * Outputs :
428665484d8SDoug Ambrisko *
429665484d8SDoug Ambrisko *    row         - row associated with strip
430665484d8SDoug Ambrisko */
431665484d8SDoug Ambrisko 
432665484d8SDoug Ambrisko static u_int64_t  get_row_from_strip(struct mrsas_softc *sc,
433665484d8SDoug Ambrisko        u_int32_t ld, u_int64_t strip, MR_FW_RAID_MAP_ALL *map)
434665484d8SDoug Ambrisko {
435665484d8SDoug Ambrisko        MR_LD_RAID      *raid = MR_LdRaidGet(ld, map);
436665484d8SDoug Ambrisko        LD_SPAN_SET     *span_set;
437665484d8SDoug Ambrisko        PLD_SPAN_INFO   ldSpanInfo = sc->log_to_span;
438665484d8SDoug Ambrisko        u_int32_t             info, strip_offset, span, span_offset;
439665484d8SDoug Ambrisko        u_int64_t             span_set_Strip, span_set_Row;
440665484d8SDoug Ambrisko 
441665484d8SDoug Ambrisko        for (info=0; info < MAX_QUAD_DEPTH; info++) {
442665484d8SDoug Ambrisko                span_set = &(ldSpanInfo[ld].span_set[info]);
443665484d8SDoug Ambrisko 
444665484d8SDoug Ambrisko                if (span_set->span_row_data_width == 0) break;
445665484d8SDoug Ambrisko                if (strip > span_set->data_strip_end) continue;
446665484d8SDoug Ambrisko 
447665484d8SDoug Ambrisko                span_set_Strip = strip - span_set->data_strip_start;
448665484d8SDoug Ambrisko                strip_offset = mega_mod64(span_set_Strip,
449665484d8SDoug Ambrisko                                span_set->span_row_data_width);
450665484d8SDoug Ambrisko                span_set_Row = mega_div64_32(span_set_Strip,
451665484d8SDoug Ambrisko                                span_set->span_row_data_width) * span_set->diff;
452665484d8SDoug Ambrisko                for (span=0,span_offset=0; span<raid->spanDepth; span++)
453665484d8SDoug Ambrisko                        if (map->raidMap.ldSpanMap[ld].spanBlock[span].
454665484d8SDoug Ambrisko                                block_span_info.noElements >=info+1) {
455665484d8SDoug Ambrisko                                if (strip_offset >=
456665484d8SDoug Ambrisko                                        span_set->strip_offset[span])
457665484d8SDoug Ambrisko                                        span_offset++;
458665484d8SDoug Ambrisko                                else
459665484d8SDoug Ambrisko                                        break;
460665484d8SDoug Ambrisko                        }
461665484d8SDoug Ambrisko                mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : Strip 0x%llx, span_set_Strip 0x%llx, span_set_Row 0x%llx "
462665484d8SDoug Ambrisko                        "data width 0x%llx span offset 0x%llx\n", (unsigned long long)strip,
463665484d8SDoug Ambrisko                        (unsigned long long)span_set_Strip,
464665484d8SDoug Ambrisko                        (unsigned long long)span_set_Row,
465665484d8SDoug Ambrisko                        (unsigned long long)span_set->span_row_data_width, (unsigned long long)span_offset);
466665484d8SDoug Ambrisko                mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : For strip 0x%llx row is 0x%llx\n", (unsigned long long)strip,
467665484d8SDoug Ambrisko                        (unsigned long long) span_set->data_row_start +
468665484d8SDoug Ambrisko                        (unsigned long long) span_set_Row + (span_offset - 1));
469665484d8SDoug Ambrisko                return (span_set->data_row_start + span_set_Row + (span_offset - 1));
470665484d8SDoug Ambrisko        }
471665484d8SDoug Ambrisko        return -1LLU;
472665484d8SDoug Ambrisko }
473665484d8SDoug Ambrisko 
474665484d8SDoug Ambrisko 
475665484d8SDoug Ambrisko /*
476665484d8SDoug Ambrisko ******************************************************************************
477665484d8SDoug Ambrisko *
478665484d8SDoug Ambrisko * This routine calculates the Start Strip for given row using spanset.
479665484d8SDoug Ambrisko *
480665484d8SDoug Ambrisko * Inputs :
481665484d8SDoug Ambrisko *    instance - HBA instance
482665484d8SDoug Ambrisko *    ld   - Logical drive number
483665484d8SDoug Ambrisko *    row        - Row number
484665484d8SDoug Ambrisko *    map    - LD map
485665484d8SDoug Ambrisko *
486665484d8SDoug Ambrisko * Outputs :
487665484d8SDoug Ambrisko *
488665484d8SDoug Ambrisko *    Strip         - Start strip associated with row
489665484d8SDoug Ambrisko */
490665484d8SDoug Ambrisko 
491665484d8SDoug Ambrisko static u_int64_t get_strip_from_row(struct mrsas_softc *sc,
492665484d8SDoug Ambrisko                u_int32_t ld, u_int64_t row, MR_FW_RAID_MAP_ALL *map)
493665484d8SDoug Ambrisko {
494665484d8SDoug Ambrisko        MR_LD_RAID         *raid = MR_LdRaidGet(ld, map);
495665484d8SDoug Ambrisko        LD_SPAN_SET *span_set;
496665484d8SDoug Ambrisko        MR_QUAD_ELEMENT    *quad;
497665484d8SDoug Ambrisko        PLD_SPAN_INFO ldSpanInfo = sc->log_to_span;
498665484d8SDoug Ambrisko        u_int32_t    span, info;
499665484d8SDoug Ambrisko        u_int64_t  strip;
500665484d8SDoug Ambrisko 
501665484d8SDoug Ambrisko        for (info=0; info<MAX_QUAD_DEPTH; info++) {
502665484d8SDoug Ambrisko                span_set = &(ldSpanInfo[ld].span_set[info]);
503665484d8SDoug Ambrisko 
504665484d8SDoug Ambrisko                if (span_set->span_row_data_width == 0) break;
505665484d8SDoug Ambrisko                if (row > span_set->data_row_end) continue;
506665484d8SDoug Ambrisko 
507665484d8SDoug Ambrisko                for (span=0; span<raid->spanDepth; span++)
508665484d8SDoug Ambrisko                        if (map->raidMap.ldSpanMap[ld].spanBlock[span].
509665484d8SDoug Ambrisko                                block_span_info.noElements >=info+1) {
510665484d8SDoug Ambrisko                                quad = &map->raidMap.ldSpanMap[ld].
511665484d8SDoug Ambrisko                                        spanBlock[span].block_span_info.quad[info];
512665484d8SDoug Ambrisko                                if ( quad->logStart <= row  &&
513665484d8SDoug Ambrisko                                        row <= quad->logEnd  &&
514665484d8SDoug Ambrisko                                        mega_mod64((row - quad->logStart),
515665484d8SDoug Ambrisko                                        quad->diff) == 0 ) {
516665484d8SDoug Ambrisko                                        strip = mega_div64_32
517665484d8SDoug Ambrisko                                                (((row - span_set->data_row_start)
518665484d8SDoug Ambrisko                                                        - quad->logStart),
519665484d8SDoug Ambrisko                                                        quad->diff);
520665484d8SDoug Ambrisko                                        strip *= span_set->span_row_data_width;
521665484d8SDoug Ambrisko                                        strip += span_set->data_strip_start;
522665484d8SDoug Ambrisko                                        strip += span_set->strip_offset[span];
523665484d8SDoug Ambrisko                                        return strip;
524665484d8SDoug Ambrisko                                }
525665484d8SDoug Ambrisko                        }
526665484d8SDoug Ambrisko        }
527665484d8SDoug Ambrisko        mrsas_dprint(sc, MRSAS_PRL11,"LSI Debug - get_strip_from_row: returns invalid "
528665484d8SDoug Ambrisko                "strip for ld=%x, row=%lx\n", ld, (long unsigned int)row);
529665484d8SDoug Ambrisko        return -1;
530665484d8SDoug Ambrisko }
531665484d8SDoug Ambrisko 
532665484d8SDoug Ambrisko /*
533665484d8SDoug Ambrisko ******************************************************************************
534665484d8SDoug Ambrisko *
535665484d8SDoug Ambrisko * This routine calculates the Physical Arm for given strip using spanset.
536665484d8SDoug Ambrisko *
537665484d8SDoug Ambrisko * Inputs :
538665484d8SDoug Ambrisko *    instance - HBA instance
539665484d8SDoug Ambrisko *    ld   - Logical drive number
540665484d8SDoug Ambrisko *    strip      - Strip
541665484d8SDoug Ambrisko *    map    - LD map
542665484d8SDoug Ambrisko *
543665484d8SDoug Ambrisko * Outputs :
544665484d8SDoug Ambrisko *
545665484d8SDoug Ambrisko *    Phys Arm         - Phys Arm associated with strip
546665484d8SDoug Ambrisko */
547665484d8SDoug Ambrisko 
548665484d8SDoug Ambrisko static u_int32_t get_arm_from_strip(struct mrsas_softc *sc,
549665484d8SDoug Ambrisko        u_int32_t ld, u_int64_t strip, MR_FW_RAID_MAP_ALL *map)
550665484d8SDoug Ambrisko {
551665484d8SDoug Ambrisko        MR_LD_RAID         *raid = MR_LdRaidGet(ld, map);
552665484d8SDoug Ambrisko        LD_SPAN_SET *span_set;
553665484d8SDoug Ambrisko        PLD_SPAN_INFO ldSpanInfo = sc->log_to_span;
554665484d8SDoug Ambrisko        u_int32_t    info, strip_offset, span, span_offset;
555665484d8SDoug Ambrisko 
556665484d8SDoug Ambrisko        for (info=0; info<MAX_QUAD_DEPTH; info++) {
557665484d8SDoug Ambrisko                span_set = &(ldSpanInfo[ld].span_set[info]);
558665484d8SDoug Ambrisko 
559665484d8SDoug Ambrisko                if (span_set->span_row_data_width == 0) break;
560665484d8SDoug Ambrisko                if (strip > span_set->data_strip_end) continue;
561665484d8SDoug Ambrisko 
562665484d8SDoug Ambrisko                strip_offset = (u_int32_t)mega_mod64
563665484d8SDoug Ambrisko                                ((strip - span_set->data_strip_start),
564665484d8SDoug Ambrisko                                span_set->span_row_data_width);
565665484d8SDoug Ambrisko 
566665484d8SDoug Ambrisko                for (span=0,span_offset=0; span<raid->spanDepth; span++)
567665484d8SDoug Ambrisko                        if (map->raidMap.ldSpanMap[ld].spanBlock[span].
568665484d8SDoug Ambrisko                                block_span_info.noElements >=info+1) {
569665484d8SDoug Ambrisko                                if (strip_offset >=
570665484d8SDoug Ambrisko                                        span_set->strip_offset[span])
571665484d8SDoug Ambrisko                                        span_offset =
572665484d8SDoug Ambrisko                                                span_set->strip_offset[span];
573665484d8SDoug Ambrisko                                else
574665484d8SDoug Ambrisko                                        break;
575665484d8SDoug Ambrisko                        }
576665484d8SDoug Ambrisko                mrsas_dprint(sc, MRSAS_PRL11, "LSI PRL11: get_arm_from_strip: "
577665484d8SDoug Ambrisko                        " for ld=0x%x strip=0x%lx arm is  0x%x\n", ld,
578665484d8SDoug Ambrisko                        (long unsigned int)strip, (strip_offset - span_offset));
579665484d8SDoug Ambrisko                return (strip_offset - span_offset);
580665484d8SDoug Ambrisko        }
581665484d8SDoug Ambrisko 
582665484d8SDoug Ambrisko        mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: - get_arm_from_strip: returns invalid arm"
583665484d8SDoug Ambrisko                " for ld=%x strip=%lx\n", ld, (long unsigned int)strip);
584665484d8SDoug Ambrisko 
585665484d8SDoug Ambrisko        return -1;
586665484d8SDoug Ambrisko }
587665484d8SDoug Ambrisko 
588665484d8SDoug Ambrisko 
589665484d8SDoug Ambrisko /* This Function will return Phys arm */
590665484d8SDoug Ambrisko u_int8_t get_arm(struct mrsas_softc *sc, u_int32_t ld, u_int8_t span, u_int64_t stripe,
591665484d8SDoug Ambrisko                MR_FW_RAID_MAP_ALL *map)
592665484d8SDoug Ambrisko {
593665484d8SDoug Ambrisko        MR_LD_RAID  *raid = MR_LdRaidGet(ld, map);
594665484d8SDoug Ambrisko        /* Need to check correct default value */
595665484d8SDoug Ambrisko        u_int32_t    arm = 0;
596665484d8SDoug Ambrisko 
597665484d8SDoug Ambrisko        switch (raid->level) {
598665484d8SDoug Ambrisko                case 0:
599665484d8SDoug Ambrisko                case 5:
600665484d8SDoug Ambrisko                case 6:
601665484d8SDoug Ambrisko                        arm = mega_mod64(stripe, SPAN_ROW_SIZE(map, ld, span));
602665484d8SDoug Ambrisko                        break;
603665484d8SDoug Ambrisko                case 1:
604665484d8SDoug Ambrisko                        // start with logical arm
605665484d8SDoug Ambrisko                        arm = get_arm_from_strip(sc, ld, stripe, map);
606665484d8SDoug Ambrisko                        arm *= 2;
607665484d8SDoug Ambrisko                        break;
608665484d8SDoug Ambrisko 
609665484d8SDoug Ambrisko        }
610665484d8SDoug Ambrisko 
611665484d8SDoug Ambrisko        return arm;
612665484d8SDoug Ambrisko }
613665484d8SDoug Ambrisko 
614665484d8SDoug Ambrisko /*
615665484d8SDoug Ambrisko ******************************************************************************
616665484d8SDoug Ambrisko *
617665484d8SDoug Ambrisko * This routine calculates the arm, span and block for the specified stripe and
618665484d8SDoug Ambrisko * reference in stripe using spanset
619665484d8SDoug Ambrisko *
620665484d8SDoug Ambrisko * Inputs :
621665484d8SDoug Ambrisko *
622665484d8SDoug Ambrisko *    ld   - Logical drive number
623665484d8SDoug Ambrisko *    stripRow        - Stripe number
624665484d8SDoug Ambrisko *    stripRef    - Reference in stripe
625665484d8SDoug Ambrisko *
626665484d8SDoug Ambrisko * Outputs :
627665484d8SDoug Ambrisko *
628665484d8SDoug Ambrisko *    span          - Span number
629665484d8SDoug Ambrisko *    block         - Absolute Block number in the physical disk
630665484d8SDoug Ambrisko */
631665484d8SDoug Ambrisko static u_int8_t mr_spanset_get_phy_params(struct mrsas_softc *sc, u_int32_t ld, u_int64_t stripRow,
632665484d8SDoug Ambrisko                   u_int16_t stripRef, struct IO_REQUEST_INFO *io_info,
633665484d8SDoug Ambrisko                   RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map)
634665484d8SDoug Ambrisko {
635665484d8SDoug Ambrisko        MR_LD_RAID  *raid = MR_LdRaidGet(ld, map);
636665484d8SDoug Ambrisko        u_int32_t     pd, arRef;
637665484d8SDoug Ambrisko        u_int8_t      physArm, span;
638665484d8SDoug Ambrisko        u_int64_t     row;
639665484d8SDoug Ambrisko        u_int8_t      retval = TRUE;
640665484d8SDoug Ambrisko        u_int64_t     *pdBlock = &io_info->pdBlock;
641665484d8SDoug Ambrisko        u_int16_t     *pDevHandle = &io_info->devHandle;
642665484d8SDoug Ambrisko        u_int32_t     logArm, rowMod, armQ, arm;
643665484d8SDoug Ambrisko        u_int8_t do_invader = 0;
644665484d8SDoug Ambrisko 
645665484d8SDoug Ambrisko        if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY))
646665484d8SDoug Ambrisko            do_invader = 1;
647665484d8SDoug Ambrisko 
648665484d8SDoug Ambrisko        // Get row and span from io_info for Uneven Span IO.
649665484d8SDoug Ambrisko        row         = io_info->start_row;
650665484d8SDoug Ambrisko        span        = io_info->start_span;
651665484d8SDoug Ambrisko 
652665484d8SDoug Ambrisko 
653665484d8SDoug Ambrisko        if (raid->level == 6) {
654665484d8SDoug Ambrisko                logArm = get_arm_from_strip(sc, ld, stripRow, map);
655665484d8SDoug Ambrisko                rowMod = mega_mod64(row, SPAN_ROW_SIZE(map, ld, span));
656665484d8SDoug Ambrisko                armQ = SPAN_ROW_SIZE(map,ld,span) - 1 - rowMod;
657665484d8SDoug Ambrisko                arm = armQ + 1 + logArm;
658665484d8SDoug Ambrisko                if (arm >= SPAN_ROW_SIZE(map, ld, span))
659665484d8SDoug Ambrisko                        arm -= SPAN_ROW_SIZE(map ,ld ,span);
660665484d8SDoug Ambrisko                physArm = (u_int8_t)arm;
661665484d8SDoug Ambrisko        } else
662665484d8SDoug Ambrisko                // Calculate the arm
663665484d8SDoug Ambrisko                physArm = get_arm(sc, ld, span, stripRow, map);
664665484d8SDoug Ambrisko 
665665484d8SDoug Ambrisko 
666665484d8SDoug Ambrisko        arRef       = MR_LdSpanArrayGet(ld, span, map);
667665484d8SDoug Ambrisko        pd          = MR_ArPdGet(arRef, physArm, map);
668665484d8SDoug Ambrisko 
669665484d8SDoug Ambrisko        if (pd != MR_PD_INVALID)
670665484d8SDoug Ambrisko                *pDevHandle = MR_PdDevHandleGet(pd, map);
671665484d8SDoug Ambrisko        else {
672665484d8SDoug Ambrisko                *pDevHandle = MR_PD_INVALID;
673665484d8SDoug Ambrisko                if ((raid->level >= 5) && ((!do_invader) || (do_invader &&
674665484d8SDoug Ambrisko                   raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))
675665484d8SDoug Ambrisko                   pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
676665484d8SDoug Ambrisko                else if (raid->level == 1) {
677665484d8SDoug Ambrisko                	  pd = MR_ArPdGet(arRef, physArm + 1, map);
678665484d8SDoug Ambrisko                   if (pd != MR_PD_INVALID)
679665484d8SDoug Ambrisko                      *pDevHandle = MR_PdDevHandleGet(pd, map);
680665484d8SDoug Ambrisko                }
681665484d8SDoug Ambrisko        }
682665484d8SDoug Ambrisko 
683665484d8SDoug Ambrisko        *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk;
684665484d8SDoug Ambrisko        pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm;
685665484d8SDoug Ambrisko        return retval;
686665484d8SDoug Ambrisko }
687665484d8SDoug Ambrisko 
688665484d8SDoug Ambrisko /**
689665484d8SDoug Ambrisko * MR_BuildRaidContext:           Set up Fast path RAID context
690665484d8SDoug Ambrisko *
691665484d8SDoug Ambrisko * This function will initiate command processing.  The start/end row
692665484d8SDoug Ambrisko * and strip information is calculated then the lock is acquired.
693665484d8SDoug Ambrisko * This function will return 0 if region lock was acquired OR return
694665484d8SDoug Ambrisko * num strips.
695665484d8SDoug Ambrisko */
696665484d8SDoug Ambrisko u_int8_t
697665484d8SDoug Ambrisko MR_BuildRaidContext(struct mrsas_softc *sc, struct IO_REQUEST_INFO *io_info,
698665484d8SDoug Ambrisko                     RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map)
699665484d8SDoug Ambrisko {
700665484d8SDoug Ambrisko     MR_LD_RAID *raid;
701665484d8SDoug Ambrisko     u_int32_t ld, stripSize, stripe_mask;
702665484d8SDoug Ambrisko     u_int64_t endLba, endStrip, endRow, start_row, start_strip;
703665484d8SDoug Ambrisko     REGION_KEY regStart;
704665484d8SDoug Ambrisko     REGION_LEN regSize;
705665484d8SDoug Ambrisko     u_int8_t num_strips, numRows;
706665484d8SDoug Ambrisko     u_int16_t ref_in_start_stripe, ref_in_end_stripe;
707665484d8SDoug Ambrisko     u_int64_t ldStartBlock;
708665484d8SDoug Ambrisko     u_int32_t numBlocks, ldTgtId;
709665484d8SDoug Ambrisko     u_int8_t isRead, stripIdx;
710665484d8SDoug Ambrisko     u_int8_t retval = 0;
711665484d8SDoug Ambrisko 	u_int8_t startlba_span = SPAN_INVALID;
712665484d8SDoug Ambrisko     u_int64_t *pdBlock = &io_info->pdBlock;
713665484d8SDoug Ambrisko     int error_code = 0;
714665484d8SDoug Ambrisko 
715665484d8SDoug Ambrisko     ldStartBlock = io_info->ldStartBlock;
716665484d8SDoug Ambrisko     numBlocks = io_info->numBlocks;
717665484d8SDoug Ambrisko     ldTgtId = io_info->ldTgtId;
718665484d8SDoug Ambrisko     isRead = io_info->isRead;
719665484d8SDoug Ambrisko 
720665484d8SDoug Ambrisko 	io_info->IoforUnevenSpan = 0;
721665484d8SDoug Ambrisko     io_info->start_span     = SPAN_INVALID;
722665484d8SDoug Ambrisko 
723665484d8SDoug Ambrisko     ld = MR_TargetIdToLdGet(ldTgtId, map);
724665484d8SDoug Ambrisko     raid = MR_LdRaidGet(ld, map);
725665484d8SDoug Ambrisko 
726665484d8SDoug Ambrisko     /*
727665484d8SDoug Ambrisko  	* if rowDataSize @RAID map and spanRowDataSize @SPAN INFO are zero
728665484d8SDoug Ambrisko     * return FALSE
729665484d8SDoug Ambrisko     */
730665484d8SDoug Ambrisko 	if (raid->rowDataSize == 0) {
731665484d8SDoug Ambrisko 	   if (MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize == 0)
732665484d8SDoug Ambrisko 		   return FALSE;
733665484d8SDoug Ambrisko 	   else if (sc->UnevenSpanSupport) {
734665484d8SDoug Ambrisko 		   io_info->IoforUnevenSpan = 1;
735665484d8SDoug Ambrisko 	   }
736665484d8SDoug Ambrisko 	   else {
737665484d8SDoug Ambrisko 		   mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: raid->rowDataSize is 0, but has SPAN[0] rowDataSize = 0x%0x,"
738665484d8SDoug Ambrisko 				   " but there is _NO_ UnevenSpanSupport\n",
739665484d8SDoug Ambrisko 		   MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize);
740665484d8SDoug Ambrisko 		   return FALSE;
741665484d8SDoug Ambrisko 	   }
742665484d8SDoug Ambrisko 	}
743665484d8SDoug Ambrisko     stripSize = 1 << raid->stripeShift;
744665484d8SDoug Ambrisko     stripe_mask = stripSize-1;
745665484d8SDoug Ambrisko     /*
746665484d8SDoug Ambrisko      * calculate starting row and stripe, and number of strips and rows
747665484d8SDoug Ambrisko      */
748665484d8SDoug Ambrisko     start_strip = ldStartBlock >> raid->stripeShift;
749665484d8SDoug Ambrisko     ref_in_start_stripe = (u_int16_t)(ldStartBlock & stripe_mask);
750665484d8SDoug Ambrisko     endLba = ldStartBlock + numBlocks - 1;
751665484d8SDoug Ambrisko     ref_in_end_stripe = (u_int16_t)(endLba & stripe_mask);
752665484d8SDoug Ambrisko     endStrip = endLba >> raid->stripeShift;
753665484d8SDoug Ambrisko     num_strips = (u_int8_t)(endStrip - start_strip + 1);     // End strip
754665484d8SDoug Ambrisko        if (io_info->IoforUnevenSpan) {
755665484d8SDoug Ambrisko                start_row = get_row_from_strip(sc, ld, start_strip, map);
756665484d8SDoug Ambrisko                endRow    = get_row_from_strip(sc, ld, endStrip, map);
757665484d8SDoug Ambrisko                if (raid->spanDepth == 1) {
758665484d8SDoug Ambrisko                        startlba_span = 0;
759665484d8SDoug Ambrisko                        *pdBlock = start_row << raid->stripeShift;
760665484d8SDoug Ambrisko                } else {
761665484d8SDoug Ambrisko                        startlba_span = (u_int8_t)mr_spanset_get_span_block(sc, ld, start_row,
762665484d8SDoug Ambrisko                                                pdBlock, map, &error_code);
763665484d8SDoug Ambrisko                        if (error_code == 1) {
764665484d8SDoug Ambrisko                                mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: return from %s %d. Send IO w/o region lock.\n",
765665484d8SDoug Ambrisko                                        __func__, __LINE__);
766665484d8SDoug Ambrisko                                return FALSE;
767665484d8SDoug Ambrisko                        }
768665484d8SDoug Ambrisko                }
769665484d8SDoug Ambrisko                if (startlba_span == SPAN_INVALID) {
770665484d8SDoug Ambrisko                        mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: return from %s %d for row 0x%llx,"
771665484d8SDoug Ambrisko                                "start strip %llx endSrip %llx\n", __func__,
772665484d8SDoug Ambrisko                                __LINE__, (unsigned long long)start_row,
773665484d8SDoug Ambrisko                                (unsigned long long)start_strip,
774665484d8SDoug Ambrisko                                (unsigned long long)endStrip);
775665484d8SDoug Ambrisko                        return FALSE;
776665484d8SDoug Ambrisko                }
777665484d8SDoug Ambrisko                io_info->start_span     = startlba_span;
778665484d8SDoug Ambrisko                io_info->start_row      = start_row;
779665484d8SDoug Ambrisko                mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: Check Span number from %s %d for row 0x%llx, "
780665484d8SDoug Ambrisko                                " start strip 0x%llx endSrip 0x%llx span 0x%x\n",
781665484d8SDoug Ambrisko                                 __func__, __LINE__, (unsigned long long)start_row,
782665484d8SDoug Ambrisko                                (unsigned long long)start_strip,
783665484d8SDoug Ambrisko                                (unsigned long long)endStrip, startlba_span);
784665484d8SDoug Ambrisko                mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : 1. start_row 0x%llx endRow 0x%llx Start span 0x%x\n",
785665484d8SDoug Ambrisko                        (unsigned long long)start_row, (unsigned long long)endRow, startlba_span);
786665484d8SDoug Ambrisko        } else {
787665484d8SDoug Ambrisko                start_row           =  mega_div64_32(start_strip, raid->rowDataSize);      // Start Row
788665484d8SDoug Ambrisko                endRow              =  mega_div64_32(endStrip, raid->rowDataSize);
789665484d8SDoug Ambrisko        }
790665484d8SDoug Ambrisko 
791665484d8SDoug Ambrisko     numRows = (u_int8_t)(endRow - start_row + 1);   // get the row count
792665484d8SDoug Ambrisko 
793665484d8SDoug Ambrisko     /*
794665484d8SDoug Ambrisko      * Calculate region info.  (Assume region at start of first row, and
795665484d8SDoug Ambrisko      * assume this IO needs the full row - will adjust if not true.)
796665484d8SDoug Ambrisko      */
797665484d8SDoug Ambrisko     regStart = start_row << raid->stripeShift;
798665484d8SDoug Ambrisko     regSize = stripSize;
799665484d8SDoug Ambrisko 
800665484d8SDoug Ambrisko     /* Check if we can send this I/O via FastPath */
801665484d8SDoug Ambrisko     if (raid->capability.fpCapable) {
802665484d8SDoug Ambrisko         if (isRead)
803665484d8SDoug Ambrisko             io_info->fpOkForIo = (raid->capability.fpReadCapable &&
804665484d8SDoug Ambrisko                                               ((num_strips == 1) ||
805665484d8SDoug Ambrisko                                                raid->capability.
806665484d8SDoug Ambrisko                                                fpReadAcrossStripe));
807665484d8SDoug Ambrisko         else
808665484d8SDoug Ambrisko             io_info->fpOkForIo = (raid->capability.fpWriteCapable &&
809665484d8SDoug Ambrisko                                               ((num_strips == 1) ||
810665484d8SDoug Ambrisko                                                raid->capability.
811665484d8SDoug Ambrisko                                                fpWriteAcrossStripe));
812665484d8SDoug Ambrisko     }
813665484d8SDoug Ambrisko     else
814665484d8SDoug Ambrisko         io_info->fpOkForIo = FALSE;
815665484d8SDoug Ambrisko 
816665484d8SDoug Ambrisko     if (numRows == 1) {
817665484d8SDoug Ambrisko         if (num_strips == 1) {
818665484d8SDoug Ambrisko             /* single-strip IOs can always lock only the data needed,
819665484d8SDoug Ambrisko                multi-strip IOs always need to full stripe locked */
820665484d8SDoug Ambrisko             regStart += ref_in_start_stripe;
821665484d8SDoug Ambrisko             regSize = numBlocks;
822665484d8SDoug Ambrisko         }
823665484d8SDoug Ambrisko     }
824665484d8SDoug Ambrisko     else if (io_info->IoforUnevenSpan == 0){
825665484d8SDoug Ambrisko         // For Even span region lock optimization.
826665484d8SDoug Ambrisko         // If the start strip is the last in the start row
827665484d8SDoug Ambrisko         if (start_strip == (start_row + 1) * raid->rowDataSize - 1) {
828665484d8SDoug Ambrisko             regStart += ref_in_start_stripe;
829665484d8SDoug Ambrisko             // initialize count to sectors from startRef to end of strip
830665484d8SDoug Ambrisko             regSize = stripSize - ref_in_start_stripe;
831665484d8SDoug Ambrisko         }
832665484d8SDoug Ambrisko 		// add complete rows in the middle of the transfer
833665484d8SDoug Ambrisko 		if (numRows > 2)
834665484d8SDoug Ambrisko             regSize += (numRows-2) << raid->stripeShift;
835665484d8SDoug Ambrisko 
836665484d8SDoug Ambrisko         // if IO ends within first strip of last row
837665484d8SDoug Ambrisko         if (endStrip == endRow*raid->rowDataSize)
838665484d8SDoug Ambrisko                         regSize += ref_in_end_stripe+1;
839665484d8SDoug Ambrisko                 else
840665484d8SDoug Ambrisko                         regSize += stripSize;
841665484d8SDoug Ambrisko     } else {
842665484d8SDoug Ambrisko 		//For Uneven span region lock optimization.
843665484d8SDoug Ambrisko         // If the start strip is the last in the start row
844665484d8SDoug Ambrisko         if (start_strip == (get_strip_from_row(sc, ld, start_row, map) +
845665484d8SDoug Ambrisko             	SPAN_ROW_DATA_SIZE(map, ld, startlba_span) - 1)) {
846665484d8SDoug Ambrisko             regStart += ref_in_start_stripe;
847665484d8SDoug Ambrisko 			// initialize count to sectors from startRef to end of strip
848665484d8SDoug Ambrisko 			regSize = stripSize - ref_in_start_stripe;
849665484d8SDoug Ambrisko         }
850665484d8SDoug Ambrisko         // add complete rows in the middle of the transfer
851665484d8SDoug Ambrisko         if (numRows > 2)
852665484d8SDoug Ambrisko             regSize += (numRows-2) << raid->stripeShift;
853665484d8SDoug Ambrisko 
854665484d8SDoug Ambrisko         // if IO ends within first strip of last row
855665484d8SDoug Ambrisko         if (endStrip == get_strip_from_row(sc, ld, endRow, map))
856665484d8SDoug Ambrisko             regSize += ref_in_end_stripe+1;
857665484d8SDoug Ambrisko         else
858665484d8SDoug Ambrisko             regSize += stripSize;
859665484d8SDoug Ambrisko     }
860665484d8SDoug Ambrisko     pRAID_Context->timeoutValue = map->raidMap.fpPdIoTimeoutSec;
861665484d8SDoug Ambrisko     if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY))
862665484d8SDoug Ambrisko                 pRAID_Context->regLockFlags = (isRead)? raid->regTypeReqOnRead : raid->regTypeReqOnWrite;
863665484d8SDoug Ambrisko     else
864665484d8SDoug Ambrisko     	pRAID_Context->regLockFlags = (isRead)? REGION_TYPE_SHARED_READ : raid->regTypeReqOnWrite;
865665484d8SDoug Ambrisko     pRAID_Context->VirtualDiskTgtId = raid->targetId;
866665484d8SDoug Ambrisko     pRAID_Context->regLockRowLBA = regStart;
867665484d8SDoug Ambrisko     pRAID_Context->regLockLength = regSize;
868665484d8SDoug Ambrisko     pRAID_Context->configSeqNum = raid->seqNum;
869665484d8SDoug Ambrisko 
870665484d8SDoug Ambrisko     /*
871665484d8SDoug Ambrisko      * Get Phy Params only if FP capable, or else leave it to MR firmware
872665484d8SDoug Ambrisko      * to do the calculation.
873665484d8SDoug Ambrisko      */
874665484d8SDoug Ambrisko     if (io_info->fpOkForIo) {
875665484d8SDoug Ambrisko         retval = io_info->IoforUnevenSpan ?
876665484d8SDoug Ambrisko                                mr_spanset_get_phy_params(sc, ld,
877665484d8SDoug Ambrisko                                    start_strip, ref_in_start_stripe, io_info,
878665484d8SDoug Ambrisko                                    pRAID_Context, map) :
879665484d8SDoug Ambrisko                                MR_GetPhyParams(sc, ld, start_strip,
880665484d8SDoug Ambrisko                                    ref_in_start_stripe, io_info, pRAID_Context, map);
881665484d8SDoug Ambrisko         /* If IO on an invalid Pd, then FP is not possible */
882665484d8SDoug Ambrisko         if (io_info->devHandle == MR_PD_INVALID)
883665484d8SDoug Ambrisko             io_info->fpOkForIo = FALSE;
884665484d8SDoug Ambrisko         return retval;
885665484d8SDoug Ambrisko     }
886665484d8SDoug Ambrisko     else if (isRead) {
887665484d8SDoug Ambrisko         for (stripIdx=0; stripIdx<num_strips; stripIdx++) {
888665484d8SDoug Ambrisko              retval = io_info->IoforUnevenSpan ?
889665484d8SDoug Ambrisko                         mr_spanset_get_phy_params(sc, ld,
890665484d8SDoug Ambrisko                             start_strip + stripIdx,
891665484d8SDoug Ambrisko                             ref_in_start_stripe, io_info,
892665484d8SDoug Ambrisko                             pRAID_Context, map) :
893665484d8SDoug Ambrisko                         MR_GetPhyParams(sc, ld,
894665484d8SDoug Ambrisko                             start_strip + stripIdx, ref_in_start_stripe,
895665484d8SDoug Ambrisko                             io_info, pRAID_Context, map);
896665484d8SDoug Ambrisko               if (!retval)
897665484d8SDoug Ambrisko                   return TRUE;
898665484d8SDoug Ambrisko         }
899665484d8SDoug Ambrisko     }
900665484d8SDoug Ambrisko #if SPAN_DEBUG
901665484d8SDoug Ambrisko        // Just for testing what arm we get for strip.
902665484d8SDoug Ambrisko        get_arm_from_strip(sc, ld, start_strip, map);
903665484d8SDoug Ambrisko #endif
904665484d8SDoug Ambrisko     return TRUE;
905665484d8SDoug Ambrisko }
906665484d8SDoug Ambrisko 
907665484d8SDoug Ambrisko /*
908665484d8SDoug Ambrisko ******************************************************************************
909665484d8SDoug Ambrisko *
910665484d8SDoug Ambrisko * This routine pepare spanset info from Valid Raid map and store it into
911665484d8SDoug Ambrisko * local copy of ldSpanInfo per instance data structure.
912665484d8SDoug Ambrisko *
913665484d8SDoug Ambrisko * Inputs :
914665484d8SDoug Ambrisko *    map    - LD map
915665484d8SDoug Ambrisko *    ldSpanInfo - ldSpanInfo per HBA instance
916665484d8SDoug Ambrisko *
917665484d8SDoug Ambrisko */
918665484d8SDoug Ambrisko void mr_update_span_set(MR_FW_RAID_MAP_ALL *map, PLD_SPAN_INFO ldSpanInfo)
919665484d8SDoug Ambrisko {
920665484d8SDoug Ambrisko        u_int8_t   span,count;
921665484d8SDoug Ambrisko        u_int32_t    element,span_row_width;
922665484d8SDoug Ambrisko        u_int64_t  span_row;
923665484d8SDoug Ambrisko        MR_LD_RAID *raid;
924665484d8SDoug Ambrisko        LD_SPAN_SET *span_set, *span_set_prev;
925665484d8SDoug Ambrisko        MR_QUAD_ELEMENT    *quad;
926665484d8SDoug Ambrisko        int ldCount;
927665484d8SDoug Ambrisko        u_int16_t ld;
928665484d8SDoug Ambrisko 
929665484d8SDoug Ambrisko 	if (!ldSpanInfo)
930665484d8SDoug Ambrisko 		return;
931665484d8SDoug Ambrisko 
932665484d8SDoug Ambrisko        for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++)
933665484d8SDoug Ambrisko        {
934665484d8SDoug Ambrisko                ld = MR_TargetIdToLdGet(ldCount, map);
935665484d8SDoug Ambrisko                if (ld >= MAX_LOGICAL_DRIVES)
936665484d8SDoug Ambrisko                        continue;
937665484d8SDoug Ambrisko                raid = MR_LdRaidGet(ld, map);
938665484d8SDoug Ambrisko                for (element=0; element < MAX_QUAD_DEPTH; element++) {
939665484d8SDoug Ambrisko                        for (span=0; span < raid->spanDepth; span++) {
940665484d8SDoug Ambrisko                                if (map->raidMap.ldSpanMap[ld].spanBlock[span].
941665484d8SDoug Ambrisko                                        block_span_info.noElements < element+1)
942665484d8SDoug Ambrisko                                        continue;
943665484d8SDoug Ambrisko                                // TO-DO
944665484d8SDoug Ambrisko                                span_set = &(ldSpanInfo[ld].span_set[element]);
945665484d8SDoug Ambrisko                                quad = &map->raidMap.ldSpanMap[ld].
946665484d8SDoug Ambrisko                                        spanBlock[span].block_span_info.
947665484d8SDoug Ambrisko                                        quad[element];
948665484d8SDoug Ambrisko 
949665484d8SDoug Ambrisko                                span_set->diff = quad->diff;
950665484d8SDoug Ambrisko 
951665484d8SDoug Ambrisko                                for (count=0,span_row_width=0;
952665484d8SDoug Ambrisko                                                count<raid->spanDepth; count++) {
953665484d8SDoug Ambrisko                                        if (map->raidMap.ldSpanMap[ld].
954665484d8SDoug Ambrisko                                                spanBlock[count].
955665484d8SDoug Ambrisko                                                block_span_info.
956665484d8SDoug Ambrisko                                                noElements >=element+1) {
957665484d8SDoug Ambrisko                                                span_set->strip_offset[count] =
958665484d8SDoug Ambrisko                                                        span_row_width;
959665484d8SDoug Ambrisko                                                span_row_width +=
960665484d8SDoug Ambrisko                                                        MR_LdSpanPtrGet
961665484d8SDoug Ambrisko                                                        (ld, count, map)->spanRowDataSize;
962665484d8SDoug Ambrisko #if SPAN_DEBUG
963665484d8SDoug Ambrisko                                                printf("LSI Debug span %x rowDataSize %x\n",
964665484d8SDoug Ambrisko                                                count, MR_LdSpanPtrGet
965665484d8SDoug Ambrisko                                                        (ld, count, map)->spanRowDataSize);
966665484d8SDoug Ambrisko #endif
967665484d8SDoug Ambrisko                                        }
968665484d8SDoug Ambrisko                                }
969665484d8SDoug Ambrisko 
970665484d8SDoug Ambrisko                                span_set->span_row_data_width = span_row_width;
971665484d8SDoug Ambrisko                                span_row = mega_div64_32(((quad->logEnd -
972665484d8SDoug Ambrisko                                        quad->logStart) + quad->diff), quad->diff);
973665484d8SDoug Ambrisko 
974665484d8SDoug Ambrisko                                if (element == 0) {
975665484d8SDoug Ambrisko                                        span_set->log_start_lba = 0;
976665484d8SDoug Ambrisko                                        span_set->log_end_lba =
977665484d8SDoug Ambrisko                                        ((span_row << raid->stripeShift) * span_row_width) - 1;
978665484d8SDoug Ambrisko 
979665484d8SDoug Ambrisko                                        span_set->span_row_start = 0;
980665484d8SDoug Ambrisko                                        span_set->span_row_end = span_row - 1;
981665484d8SDoug Ambrisko 
982665484d8SDoug Ambrisko                                        span_set->data_strip_start = 0;
983665484d8SDoug Ambrisko                                        span_set->data_strip_end =
984665484d8SDoug Ambrisko                                                (span_row * span_row_width) - 1;
985665484d8SDoug Ambrisko 
986665484d8SDoug Ambrisko                                        span_set->data_row_start = 0;
987665484d8SDoug Ambrisko                                        span_set->data_row_end =
988665484d8SDoug Ambrisko                                                (span_row * quad->diff) - 1;
989665484d8SDoug Ambrisko                                } else {
990665484d8SDoug Ambrisko                                        span_set_prev = &(ldSpanInfo[ld].
991665484d8SDoug Ambrisko                                                        span_set[element - 1]);
992665484d8SDoug Ambrisko                                        span_set->log_start_lba =
993665484d8SDoug Ambrisko                                                span_set_prev->log_end_lba + 1;
994665484d8SDoug Ambrisko                                        span_set->log_end_lba =
995665484d8SDoug Ambrisko                                                span_set->log_start_lba +
996665484d8SDoug Ambrisko                                                ((span_row << raid->stripeShift) * span_row_width) - 1;
997665484d8SDoug Ambrisko 
998665484d8SDoug Ambrisko                                        span_set->span_row_start =
999665484d8SDoug Ambrisko                                                span_set_prev->span_row_end + 1;
1000665484d8SDoug Ambrisko                                        span_set->span_row_end =
1001665484d8SDoug Ambrisko                                                span_set->span_row_start + span_row - 1;
1002665484d8SDoug Ambrisko 
1003665484d8SDoug Ambrisko                                        span_set->data_strip_start =
1004665484d8SDoug Ambrisko                                                span_set_prev->data_strip_end + 1;
1005665484d8SDoug Ambrisko                                        span_set->data_strip_end =
1006665484d8SDoug Ambrisko                                                span_set->data_strip_start +
1007665484d8SDoug Ambrisko                                                (span_row * span_row_width) - 1;
1008665484d8SDoug Ambrisko 
1009665484d8SDoug Ambrisko                                        span_set->data_row_start =
1010665484d8SDoug Ambrisko                                                span_set_prev->data_row_end + 1;
1011665484d8SDoug Ambrisko                                        span_set->data_row_end =
1012665484d8SDoug Ambrisko                                                span_set->data_row_start +
1013665484d8SDoug Ambrisko                                                (span_row * quad->diff) - 1;
1014665484d8SDoug Ambrisko                                }
1015665484d8SDoug Ambrisko                                break;
1016665484d8SDoug Ambrisko                }
1017665484d8SDoug Ambrisko                if (span == raid->spanDepth) break; // no quads remain
1018665484d8SDoug Ambrisko            }
1019665484d8SDoug Ambrisko        }
1020665484d8SDoug Ambrisko #if SPAN_DEBUG
1021665484d8SDoug Ambrisko        getSpanInfo(map, ldSpanInfo);   //to get span set info
1022665484d8SDoug Ambrisko #endif
1023665484d8SDoug Ambrisko }
1024665484d8SDoug Ambrisko 
1025665484d8SDoug Ambrisko /**
1026665484d8SDoug Ambrisko  * mrsas_update_load_balance_params:  Update load balance parmas
1027665484d8SDoug Ambrisko  * Inputs:                         map pointer
1028665484d8SDoug Ambrisko  *                                 Load balance info
1029665484d8SDoug Ambrisko  *                                 io_info pointer
1030665484d8SDoug Ambrisko  *
1031665484d8SDoug Ambrisko  * This function updates the load balance parameters for the LD config
1032665484d8SDoug Ambrisko  * of a two drive optimal RAID-1.
1033665484d8SDoug Ambrisko  */
1034665484d8SDoug Ambrisko void mrsas_update_load_balance_params(MR_FW_RAID_MAP_ALL *map,
1035665484d8SDoug Ambrisko         PLD_LOAD_BALANCE_INFO lbInfo)
1036665484d8SDoug Ambrisko {
1037665484d8SDoug Ambrisko     int ldCount;
1038665484d8SDoug Ambrisko     u_int16_t ld;
1039665484d8SDoug Ambrisko     u_int32_t pd, arRef;
1040665484d8SDoug Ambrisko     MR_LD_RAID *raid;
1041665484d8SDoug Ambrisko 
1042665484d8SDoug Ambrisko     for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++)
1043665484d8SDoug Ambrisko     {
1044665484d8SDoug Ambrisko         ld = MR_TargetIdToLdGet(ldCount, map);
1045665484d8SDoug Ambrisko         if (ld >= MAX_LOGICAL_DRIVES) {
1046665484d8SDoug Ambrisko             lbInfo[ldCount].loadBalanceFlag = 0;
1047665484d8SDoug Ambrisko             continue;
1048665484d8SDoug Ambrisko         }
1049665484d8SDoug Ambrisko 
1050665484d8SDoug Ambrisko         raid = MR_LdRaidGet(ld, map);
1051665484d8SDoug Ambrisko 
1052665484d8SDoug Ambrisko         /* Two drive Optimal RAID 1 */
1053665484d8SDoug Ambrisko         if ((raid->level == 1) && (raid->rowSize == 2) &&
1054665484d8SDoug Ambrisko                 (raid->spanDepth == 1)
1055665484d8SDoug Ambrisko                 && raid->ldState == MR_LD_STATE_OPTIMAL) {
1056665484d8SDoug Ambrisko             lbInfo[ldCount].loadBalanceFlag = 1;
1057665484d8SDoug Ambrisko 
1058665484d8SDoug Ambrisko             /* Get the array on which this span is present */
1059665484d8SDoug Ambrisko             arRef = MR_LdSpanArrayGet(ld, 0, map);
1060665484d8SDoug Ambrisko 
1061665484d8SDoug Ambrisko             /* Get the PD */
1062665484d8SDoug Ambrisko             pd = MR_ArPdGet(arRef, 0, map);
1063665484d8SDoug Ambrisko             /* Get dev handle from PD */
1064665484d8SDoug Ambrisko             lbInfo[ldCount].raid1DevHandle[0] = MR_PdDevHandleGet(pd, map);
1065665484d8SDoug Ambrisko             pd = MR_ArPdGet(arRef, 1, map);
1066665484d8SDoug Ambrisko             lbInfo[ldCount].raid1DevHandle[1] = MR_PdDevHandleGet(pd, map);
1067665484d8SDoug Ambrisko         }
1068665484d8SDoug Ambrisko         else
1069665484d8SDoug Ambrisko             lbInfo[ldCount].loadBalanceFlag = 0;
1070665484d8SDoug Ambrisko     }
1071665484d8SDoug Ambrisko }
1072665484d8SDoug Ambrisko 
1073665484d8SDoug Ambrisko 
1074665484d8SDoug Ambrisko /**
1075665484d8SDoug Ambrisko  * mrsas_set_pd_lba:    Sets PD LBA
1076665484d8SDoug Ambrisko  * input:               io_request pointer
1077665484d8SDoug Ambrisko  *                      CDB length
1078665484d8SDoug Ambrisko  *                      io_info pointer
1079665484d8SDoug Ambrisko  *                      Pointer to CCB
1080665484d8SDoug Ambrisko  *                      Local RAID map pointer
1081665484d8SDoug Ambrisko  *                      Start block of IO
1082665484d8SDoug Ambrisko  *                      Block Size
1083665484d8SDoug Ambrisko  *
1084665484d8SDoug Ambrisko  * Used to set the PD logical block address in CDB for FP IOs.
1085665484d8SDoug Ambrisko  */
1086665484d8SDoug Ambrisko void mrsas_set_pd_lba(MRSAS_RAID_SCSI_IO_REQUEST *io_request, u_int8_t cdb_len,
1087665484d8SDoug Ambrisko     struct IO_REQUEST_INFO *io_info, union ccb *ccb,
1088665484d8SDoug Ambrisko     MR_FW_RAID_MAP_ALL *local_map_ptr, u_int32_t ref_tag,
1089665484d8SDoug Ambrisko     u_int32_t ld_block_size)
1090665484d8SDoug Ambrisko {
1091665484d8SDoug Ambrisko     MR_LD_RAID *raid;
1092665484d8SDoug Ambrisko     u_int32_t ld;
1093665484d8SDoug Ambrisko     u_int64_t start_blk = io_info->pdBlock;
1094665484d8SDoug Ambrisko     u_int8_t *cdb = io_request->CDB.CDB32;
1095665484d8SDoug Ambrisko     u_int32_t num_blocks = io_info->numBlocks;
1096665484d8SDoug Ambrisko     u_int8_t opcode = 0, flagvals = 0, groupnum = 0, control = 0;
1097665484d8SDoug Ambrisko     struct ccb_hdr *ccb_h = &(ccb->ccb_h);
1098665484d8SDoug Ambrisko 
1099665484d8SDoug Ambrisko     /* Check if T10 PI (DIF) is enabled for this LD */
1100665484d8SDoug Ambrisko     ld = MR_TargetIdToLdGet(io_info->ldTgtId, local_map_ptr);
1101665484d8SDoug Ambrisko     raid = MR_LdRaidGet(ld, local_map_ptr);
1102665484d8SDoug Ambrisko     if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER) {
1103665484d8SDoug Ambrisko         memset(cdb, 0, sizeof(io_request->CDB.CDB32));
1104665484d8SDoug Ambrisko         cdb[0] =  MRSAS_SCSI_VARIABLE_LENGTH_CMD;
1105665484d8SDoug Ambrisko         cdb[7] =  MRSAS_SCSI_ADDL_CDB_LEN;
1106665484d8SDoug Ambrisko 
1107665484d8SDoug Ambrisko         if (ccb_h->flags == CAM_DIR_OUT)
1108665484d8SDoug Ambrisko             cdb[9] = MRSAS_SCSI_SERVICE_ACTION_READ32;
1109665484d8SDoug Ambrisko         else
1110665484d8SDoug Ambrisko             cdb[9] = MRSAS_SCSI_SERVICE_ACTION_WRITE32;
1111665484d8SDoug Ambrisko         cdb[10] = MRSAS_RD_WR_PROTECT_CHECK_ALL;
1112665484d8SDoug Ambrisko 
1113665484d8SDoug Ambrisko         /* LBA */
1114665484d8SDoug Ambrisko         cdb[12] = (u_int8_t)((start_blk >> 56) & 0xff);
1115665484d8SDoug Ambrisko         cdb[13] = (u_int8_t)((start_blk >> 48) & 0xff);
1116665484d8SDoug Ambrisko         cdb[14] = (u_int8_t)((start_blk >> 40) & 0xff);
1117665484d8SDoug Ambrisko         cdb[15] = (u_int8_t)((start_blk >> 32) & 0xff);
1118665484d8SDoug Ambrisko         cdb[16] = (u_int8_t)((start_blk >> 24) & 0xff);
1119665484d8SDoug Ambrisko         cdb[17] = (u_int8_t)((start_blk >> 16) & 0xff);
1120665484d8SDoug Ambrisko         cdb[18] = (u_int8_t)((start_blk >> 8) & 0xff);
1121665484d8SDoug Ambrisko         cdb[19] = (u_int8_t)(start_blk & 0xff);
1122665484d8SDoug Ambrisko 
1123665484d8SDoug Ambrisko         /* Logical block reference tag */
1124665484d8SDoug Ambrisko         io_request->CDB.EEDP32.PrimaryReferenceTag = swap32(ref_tag);
1125665484d8SDoug Ambrisko         io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0xffff;
1126665484d8SDoug Ambrisko         io_request->IoFlags = 32; /* Specify 32-byte cdb */
1127665484d8SDoug Ambrisko 
1128665484d8SDoug Ambrisko         /* Transfer length */
1129665484d8SDoug Ambrisko         cdb[28] = (u_int8_t)((num_blocks >> 24) & 0xff);
1130665484d8SDoug Ambrisko         cdb[29] = (u_int8_t)((num_blocks >> 16) & 0xff);
1131665484d8SDoug Ambrisko         cdb[30] = (u_int8_t)((num_blocks >> 8) & 0xff);
1132665484d8SDoug Ambrisko         cdb[31] = (u_int8_t)(num_blocks & 0xff);
1133665484d8SDoug Ambrisko 
1134665484d8SDoug Ambrisko         /* set SCSI IO EEDP Flags */
1135665484d8SDoug Ambrisko         if (ccb_h->flags == CAM_DIR_OUT) {
1136665484d8SDoug Ambrisko             io_request->EEDPFlags =
1137665484d8SDoug Ambrisko                 MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG  |
1138665484d8SDoug Ambrisko                 MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
1139665484d8SDoug Ambrisko                 MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP |
1140665484d8SDoug Ambrisko                 MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG |
1141665484d8SDoug Ambrisko                 MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
1142665484d8SDoug Ambrisko         }
1143665484d8SDoug Ambrisko         else {
1144665484d8SDoug Ambrisko                 io_request->EEDPFlags =
1145665484d8SDoug Ambrisko                      MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
1146665484d8SDoug Ambrisko                      MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
1147665484d8SDoug Ambrisko         }
1148665484d8SDoug Ambrisko         io_request->Control |= (0x4 << 26);
1149665484d8SDoug Ambrisko         io_request->EEDPBlockSize = ld_block_size;
1150665484d8SDoug Ambrisko     }
1151665484d8SDoug Ambrisko     else {
1152665484d8SDoug Ambrisko         /* Some drives don't support 16/12 byte CDB's, convert to 10 */
1153665484d8SDoug Ambrisko         if (((cdb_len == 12) || (cdb_len == 16)) &&
1154665484d8SDoug Ambrisko                     (start_blk <= 0xffffffff)) {
1155665484d8SDoug Ambrisko             if (cdb_len == 16) {
1156665484d8SDoug Ambrisko                 opcode = cdb[0] == READ_16 ? READ_10 : WRITE_10;
1157665484d8SDoug Ambrisko                 flagvals = cdb[1];
1158665484d8SDoug Ambrisko                 groupnum = cdb[14];
1159665484d8SDoug Ambrisko                 control = cdb[15];
1160665484d8SDoug Ambrisko             }
1161665484d8SDoug Ambrisko             else {
1162665484d8SDoug Ambrisko                 opcode = cdb[0] == READ_12 ? READ_10 : WRITE_10;
1163665484d8SDoug Ambrisko                 flagvals = cdb[1];
1164665484d8SDoug Ambrisko                 groupnum = cdb[10];
1165665484d8SDoug Ambrisko                 control = cdb[11];
1166665484d8SDoug Ambrisko             }
1167665484d8SDoug Ambrisko 
1168665484d8SDoug Ambrisko             memset(cdb, 0, sizeof(io_request->CDB.CDB32));
1169665484d8SDoug Ambrisko 
1170665484d8SDoug Ambrisko             cdb[0] = opcode;
1171665484d8SDoug Ambrisko             cdb[1] = flagvals;
1172665484d8SDoug Ambrisko             cdb[6] = groupnum;
1173665484d8SDoug Ambrisko             cdb[9] = control;
1174665484d8SDoug Ambrisko 
1175665484d8SDoug Ambrisko             /* Transfer length */
1176665484d8SDoug Ambrisko             cdb[8] = (u_int8_t)(num_blocks & 0xff);
1177665484d8SDoug Ambrisko             cdb[7] = (u_int8_t)((num_blocks >> 8) & 0xff);
1178665484d8SDoug Ambrisko 
1179665484d8SDoug Ambrisko             io_request->IoFlags = 10; /* Specify 10-byte cdb */
1180665484d8SDoug Ambrisko             cdb_len = 10;
1181665484d8SDoug Ambrisko         } else if ((cdb_len < 16) && (start_blk > 0xffffffff)) {
1182665484d8SDoug Ambrisko             /* Convert to 16 byte CDB for large LBA's */
1183665484d8SDoug Ambrisko             switch (cdb_len) {
1184665484d8SDoug Ambrisko                 case 6:
1185665484d8SDoug Ambrisko                     opcode = cdb[0] == READ_6 ? READ_16 : WRITE_16;
1186665484d8SDoug Ambrisko                     control = cdb[5];
1187665484d8SDoug Ambrisko                     break;
1188665484d8SDoug Ambrisko                 case 10:
1189665484d8SDoug Ambrisko                     opcode = cdb[0] == READ_10 ? READ_16 : WRITE_16;
1190665484d8SDoug Ambrisko                     flagvals = cdb[1];
1191665484d8SDoug Ambrisko                     groupnum = cdb[6];
1192665484d8SDoug Ambrisko                     control = cdb[9];
1193665484d8SDoug Ambrisko                     break;
1194665484d8SDoug Ambrisko                 case 12:
1195665484d8SDoug Ambrisko                     opcode = cdb[0] == READ_12 ? READ_16 : WRITE_16;
1196665484d8SDoug Ambrisko                     flagvals = cdb[1];
1197665484d8SDoug Ambrisko                     groupnum = cdb[10];
1198665484d8SDoug Ambrisko                     control = cdb[11];
1199665484d8SDoug Ambrisko                     break;
1200665484d8SDoug Ambrisko             }
1201665484d8SDoug Ambrisko 
1202665484d8SDoug Ambrisko             memset(cdb, 0, sizeof(io_request->CDB.CDB32));
1203665484d8SDoug Ambrisko 
1204665484d8SDoug Ambrisko             cdb[0] = opcode;
1205665484d8SDoug Ambrisko             cdb[1] = flagvals;
1206665484d8SDoug Ambrisko             cdb[14] = groupnum;
1207665484d8SDoug Ambrisko             cdb[15] = control;
1208665484d8SDoug Ambrisko 
1209665484d8SDoug Ambrisko             /* Transfer length */
1210665484d8SDoug Ambrisko             cdb[13] = (u_int8_t)(num_blocks & 0xff);
1211665484d8SDoug Ambrisko             cdb[12] = (u_int8_t)((num_blocks >> 8) & 0xff);
1212665484d8SDoug Ambrisko             cdb[11] = (u_int8_t)((num_blocks >> 16) & 0xff);
1213665484d8SDoug Ambrisko             cdb[10] = (u_int8_t)((num_blocks >> 24) & 0xff);
1214665484d8SDoug Ambrisko 
1215665484d8SDoug Ambrisko             io_request->IoFlags = 16; /* Specify 16-byte cdb */
1216665484d8SDoug Ambrisko             cdb_len = 16;
1217665484d8SDoug Ambrisko         } else if ((cdb_len == 6) && (start_blk > 0x1fffff)) {
1218665484d8SDoug Ambrisko             /* convert to 10 byte CDB */
1219665484d8SDoug Ambrisko 	    opcode = cdb[0] == READ_6 ? READ_10 : WRITE_10;
1220665484d8SDoug Ambrisko 	    control = cdb[5];
1221665484d8SDoug Ambrisko 
1222*02190a56SXin LI 	    memset(cdb, 0, sizeof(io_request->CDB.CDB32));
1223665484d8SDoug Ambrisko 	    cdb[0] = opcode;
1224665484d8SDoug Ambrisko 	    cdb[9] = control;
1225665484d8SDoug Ambrisko 
1226665484d8SDoug Ambrisko 	    /* Set transfer length */
1227665484d8SDoug Ambrisko 	    cdb[8] = (u_int8_t)(num_blocks & 0xff);
1228665484d8SDoug Ambrisko 	    cdb[7] = (u_int8_t)((num_blocks >> 8) & 0xff);
1229665484d8SDoug Ambrisko 
1230665484d8SDoug Ambrisko 	    /* Specify 10-byte cdb */
1231665484d8SDoug Ambrisko 	    cdb_len = 10;
1232665484d8SDoug Ambrisko 	}
1233665484d8SDoug Ambrisko 
1234665484d8SDoug Ambrisko         /* Fall through normal case, just load LBA here */
1235665484d8SDoug Ambrisko         switch (cdb_len)
1236665484d8SDoug Ambrisko         {
1237665484d8SDoug Ambrisko             case 6:
1238665484d8SDoug Ambrisko             {
1239665484d8SDoug Ambrisko                 u_int8_t val = cdb[1] & 0xE0;
1240665484d8SDoug Ambrisko                 cdb[3] = (u_int8_t)(start_blk & 0xff);
1241665484d8SDoug Ambrisko                 cdb[2] = (u_int8_t)((start_blk >> 8) & 0xff);
1242665484d8SDoug Ambrisko                 cdb[1] = val | ((u_int8_t)(start_blk >> 16) & 0x1f);
1243665484d8SDoug Ambrisko                 break;
1244665484d8SDoug Ambrisko             }
1245665484d8SDoug Ambrisko             case 10:
1246665484d8SDoug Ambrisko                 cdb[5] = (u_int8_t)(start_blk & 0xff);
1247665484d8SDoug Ambrisko                 cdb[4] = (u_int8_t)((start_blk >> 8) & 0xff);
1248665484d8SDoug Ambrisko                 cdb[3] = (u_int8_t)((start_blk >> 16) & 0xff);
1249665484d8SDoug Ambrisko                 cdb[2] = (u_int8_t)((start_blk >> 24) & 0xff);
1250665484d8SDoug Ambrisko                 break;
1251665484d8SDoug Ambrisko             case 12:
1252665484d8SDoug Ambrisko                 cdb[5] = (u_int8_t)(start_blk & 0xff);
1253665484d8SDoug Ambrisko                 cdb[4] = (u_int8_t)((start_blk >> 8) & 0xff);
1254665484d8SDoug Ambrisko                 cdb[3] = (u_int8_t)((start_blk >> 16) & 0xff);
1255665484d8SDoug Ambrisko                 cdb[2] = (u_int8_t)((start_blk >> 24) & 0xff);
1256665484d8SDoug Ambrisko                 break;
1257665484d8SDoug Ambrisko             case 16:
1258665484d8SDoug Ambrisko                 cdb[9] = (u_int8_t)(start_blk & 0xff);
1259665484d8SDoug Ambrisko                 cdb[8] = (u_int8_t)((start_blk >> 8) & 0xff);
1260665484d8SDoug Ambrisko                 cdb[7] = (u_int8_t)((start_blk >> 16) & 0xff);
1261665484d8SDoug Ambrisko                 cdb[6] = (u_int8_t)((start_blk >> 24) & 0xff);
1262665484d8SDoug Ambrisko                 cdb[5] = (u_int8_t)((start_blk >> 32) & 0xff);
1263665484d8SDoug Ambrisko                 cdb[4] = (u_int8_t)((start_blk >> 40) & 0xff);
1264665484d8SDoug Ambrisko                 cdb[3] = (u_int8_t)((start_blk >> 48) & 0xff);
1265665484d8SDoug Ambrisko                 cdb[2] = (u_int8_t)((start_blk >> 56) & 0xff);
1266665484d8SDoug Ambrisko                 break;
1267665484d8SDoug Ambrisko         }
1268665484d8SDoug Ambrisko     }
1269665484d8SDoug Ambrisko }
1270665484d8SDoug Ambrisko 
1271665484d8SDoug Ambrisko /**
1272665484d8SDoug Ambrisko  * mrsas_get_best_arm         Determine the best spindle arm
1273665484d8SDoug Ambrisko  * Inputs:                    Load balance info
1274665484d8SDoug Ambrisko  *
1275665484d8SDoug Ambrisko  * This function determines and returns the best arm by looking at the
1276665484d8SDoug Ambrisko  * parameters of the last PD access.
1277665484d8SDoug Ambrisko  */
1278665484d8SDoug Ambrisko u_int8_t mrsas_get_best_arm(PLD_LOAD_BALANCE_INFO lbInfo, u_int8_t arm,
1279665484d8SDoug Ambrisko         u_int64_t block, u_int32_t count)
1280665484d8SDoug Ambrisko {
1281665484d8SDoug Ambrisko     u_int16_t     pend0, pend1;
1282665484d8SDoug Ambrisko     u_int64_t     diff0, diff1;
1283665484d8SDoug Ambrisko     u_int8_t      bestArm;
1284665484d8SDoug Ambrisko 
1285665484d8SDoug Ambrisko     /* get the pending cmds for the data and mirror arms */
1286665484d8SDoug Ambrisko     pend0 = atomic_read(&lbInfo->scsi_pending_cmds[0]);
1287665484d8SDoug Ambrisko     pend1 = atomic_read(&lbInfo->scsi_pending_cmds[1]);
1288665484d8SDoug Ambrisko 
1289665484d8SDoug Ambrisko     /* Determine the disk whose head is nearer to the req. block */
1290665484d8SDoug Ambrisko     diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[0]);
1291665484d8SDoug Ambrisko     diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[1]);
1292665484d8SDoug Ambrisko     bestArm = (diff0 <= diff1 ? 0 : 1);
1293665484d8SDoug Ambrisko 
1294665484d8SDoug Ambrisko     if ((bestArm == arm && pend0 > pend1 + 16) || (bestArm != arm && pend1 > pend0 + 16))
1295665484d8SDoug Ambrisko         bestArm ^= 1;
1296665484d8SDoug Ambrisko 
1297665484d8SDoug Ambrisko     /* Update the last accessed block on the correct pd */
1298665484d8SDoug Ambrisko     lbInfo->last_accessed_block[bestArm] = block + count - 1;
1299665484d8SDoug Ambrisko 
1300665484d8SDoug Ambrisko     return bestArm;
1301665484d8SDoug Ambrisko }
1302665484d8SDoug Ambrisko 
1303665484d8SDoug Ambrisko /**
1304665484d8SDoug Ambrisko  * mrsas_get_updated_dev_handle    Get the update dev handle
1305665484d8SDoug Ambrisko  * Inputs:                         Load balance info
1306665484d8SDoug Ambrisko  *                                 io_info pointer
1307665484d8SDoug Ambrisko  *
1308665484d8SDoug Ambrisko  * This function determines and returns the updated dev handle.
1309665484d8SDoug Ambrisko  */
1310665484d8SDoug Ambrisko u_int16_t mrsas_get_updated_dev_handle(PLD_LOAD_BALANCE_INFO lbInfo,
1311665484d8SDoug Ambrisko         struct IO_REQUEST_INFO *io_info)
1312665484d8SDoug Ambrisko {
1313665484d8SDoug Ambrisko     u_int8_t arm, old_arm;
1314665484d8SDoug Ambrisko     u_int16_t devHandle;
1315665484d8SDoug Ambrisko 
1316665484d8SDoug Ambrisko     old_arm = lbInfo->raid1DevHandle[0] == io_info->devHandle ? 0 : 1;
1317665484d8SDoug Ambrisko 
1318665484d8SDoug Ambrisko     /* get best new arm */
1319665484d8SDoug Ambrisko     arm  = mrsas_get_best_arm(lbInfo, old_arm, io_info->ldStartBlock, io_info->numBlocks);
1320665484d8SDoug Ambrisko     devHandle = lbInfo->raid1DevHandle[arm];
1321665484d8SDoug Ambrisko     atomic_inc(&lbInfo->scsi_pending_cmds[arm]);
1322665484d8SDoug Ambrisko 
1323665484d8SDoug Ambrisko     return devHandle;
1324665484d8SDoug Ambrisko }
1325665484d8SDoug Ambrisko 
1326665484d8SDoug Ambrisko /**
1327665484d8SDoug Ambrisko  * MR_GetPhyParams     Calculates arm, span, and block
1328665484d8SDoug Ambrisko  * Inputs:             Adapter instance soft state
1329665484d8SDoug Ambrisko  *                     Logical drive number (LD)
1330665484d8SDoug Ambrisko  *                     Stripe number (stripRow)
1331665484d8SDoug Ambrisko  *                     Reference in stripe (stripRef)
1332665484d8SDoug Ambrisko  * Outputs:            Span number
1333665484d8SDoug Ambrisko  *                     Absolute Block number in the physical disk
1334665484d8SDoug Ambrisko  *
1335665484d8SDoug Ambrisko  * This routine calculates the arm, span and block for the specified stripe
1336665484d8SDoug Ambrisko  * and reference in stripe.
1337665484d8SDoug Ambrisko  */
1338665484d8SDoug Ambrisko u_int8_t MR_GetPhyParams(struct mrsas_softc *sc, u_int32_t ld,
1339665484d8SDoug Ambrisko             u_int64_t stripRow,
1340665484d8SDoug Ambrisko             u_int16_t stripRef, struct IO_REQUEST_INFO *io_info,
1341665484d8SDoug Ambrisko             RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map)
1342665484d8SDoug Ambrisko {
1343665484d8SDoug Ambrisko     MR_LD_RAID  *raid = MR_LdRaidGet(ld, map);
1344665484d8SDoug Ambrisko     u_int32_t pd, arRef;
1345665484d8SDoug Ambrisko     u_int8_t physArm, span;
1346665484d8SDoug Ambrisko     u_int64_t row;
1347665484d8SDoug Ambrisko     u_int8_t retval = TRUE;
1348665484d8SDoug Ambrisko     int error_code = 0;
1349665484d8SDoug Ambrisko 	u_int64_t *pdBlock = &io_info->pdBlock;
1350665484d8SDoug Ambrisko     u_int16_t *pDevHandle = &io_info->devHandle;
1351665484d8SDoug Ambrisko     u_int32_t rowMod, armQ, arm, logArm;
1352665484d8SDoug Ambrisko 	u_int8_t do_invader = 0;
1353665484d8SDoug Ambrisko 
1354665484d8SDoug Ambrisko 	if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY))
1355665484d8SDoug Ambrisko 		do_invader = 1;
1356665484d8SDoug Ambrisko 
1357665484d8SDoug Ambrisko     row =  mega_div64_32(stripRow, raid->rowDataSize);
1358665484d8SDoug Ambrisko 
1359665484d8SDoug Ambrisko     if (raid->level == 6) {
1360665484d8SDoug Ambrisko         logArm = mega_mod64(stripRow, raid->rowDataSize); // logical arm within row
1361665484d8SDoug Ambrisko         if (raid->rowSize == 0)
1362665484d8SDoug Ambrisko             return FALSE;
1363665484d8SDoug Ambrisko         rowMod = mega_mod64(row, raid->rowSize);  // get logical row mod
1364665484d8SDoug Ambrisko         armQ = raid->rowSize-1-rowMod;  // index of Q drive
1365665484d8SDoug Ambrisko         arm = armQ+1+logArm;    // data always logically follows Q
1366665484d8SDoug Ambrisko         if (arm >= raid->rowSize)         // handle wrap condition
1367665484d8SDoug Ambrisko             arm -= raid->rowSize;
1368665484d8SDoug Ambrisko         physArm = (u_int8_t)arm;
1369665484d8SDoug Ambrisko     }
1370665484d8SDoug Ambrisko     else {
1371665484d8SDoug Ambrisko         if (raid->modFactor == 0)
1372665484d8SDoug Ambrisko             return FALSE;
1373665484d8SDoug Ambrisko         physArm = MR_LdDataArmGet(ld, mega_mod64(stripRow, raid->modFactor), map);
1374665484d8SDoug Ambrisko     }
1375665484d8SDoug Ambrisko 
1376665484d8SDoug Ambrisko     if (raid->spanDepth == 1) {
1377665484d8SDoug Ambrisko         span = 0;
1378665484d8SDoug Ambrisko         *pdBlock = row << raid->stripeShift;
1379665484d8SDoug Ambrisko     }
1380665484d8SDoug Ambrisko     else {
1381665484d8SDoug Ambrisko         span = (u_int8_t)MR_GetSpanBlock(ld, row, pdBlock, map, &error_code);
1382665484d8SDoug Ambrisko         if (error_code == 1)
1383665484d8SDoug Ambrisko             return FALSE;
1384665484d8SDoug Ambrisko     }
1385665484d8SDoug Ambrisko 
1386665484d8SDoug Ambrisko     /*  Get the array on which this span is present */
1387665484d8SDoug Ambrisko     arRef = MR_LdSpanArrayGet(ld, span, map);
1388665484d8SDoug Ambrisko 
1389665484d8SDoug Ambrisko     pd = MR_ArPdGet(arRef, physArm, map);     // Get the Pd.
1390665484d8SDoug Ambrisko 
1391665484d8SDoug Ambrisko     if (pd != MR_PD_INVALID)
1392665484d8SDoug Ambrisko         *pDevHandle = MR_PdDevHandleGet(pd, map);  // Get dev handle from Pd.
1393665484d8SDoug Ambrisko     else {
1394665484d8SDoug Ambrisko         *pDevHandle = MR_PD_INVALID; // set dev handle as invalid.
1395665484d8SDoug Ambrisko         if ((raid->level >= 5) && ((!do_invader) || (do_invader &&
1396665484d8SDoug Ambrisko              raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))
1397665484d8SDoug Ambrisko              pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
1398665484d8SDoug Ambrisko         else if (raid->level == 1) {
1399665484d8SDoug Ambrisko             pd = MR_ArPdGet(arRef, physArm + 1, map); // Get Alternate Pd.
1400665484d8SDoug Ambrisko             if (pd != MR_PD_INVALID)
1401665484d8SDoug Ambrisko                 *pDevHandle = MR_PdDevHandleGet(pd, map);//Get dev handle from Pd.
1402665484d8SDoug Ambrisko         }
1403665484d8SDoug Ambrisko     }
1404665484d8SDoug Ambrisko 
1405665484d8SDoug Ambrisko     *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk;
1406665484d8SDoug Ambrisko     pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm;
1407665484d8SDoug Ambrisko     return retval;
1408665484d8SDoug Ambrisko }
1409665484d8SDoug Ambrisko 
1410665484d8SDoug Ambrisko /**
1411665484d8SDoug Ambrisko  * MR_GetSpanBlock     Calculates span block
1412665484d8SDoug Ambrisko  * Inputs:             LD
1413665484d8SDoug Ambrisko  *                     row
1414665484d8SDoug Ambrisko  *                     PD span block
1415665484d8SDoug Ambrisko  *                     RAID map pointer
1416665484d8SDoug Ambrisko  * Outputs:            Span number
1417665484d8SDoug Ambrisko  *                     Error code
1418665484d8SDoug Ambrisko  *
1419665484d8SDoug Ambrisko  * This routine calculates the span from the span block info.
1420665484d8SDoug Ambrisko  */
1421665484d8SDoug Ambrisko u_int32_t MR_GetSpanBlock(u_int32_t ld, u_int64_t row, u_int64_t *span_blk,
1422665484d8SDoug Ambrisko         MR_FW_RAID_MAP_ALL *map, int *div_error)
1423665484d8SDoug Ambrisko {
1424665484d8SDoug Ambrisko     MR_SPAN_BLOCK_INFO *pSpanBlock = MR_LdSpanInfoGet(ld, map);
1425665484d8SDoug Ambrisko     MR_QUAD_ELEMENT *quad;
1426665484d8SDoug Ambrisko     MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
1427665484d8SDoug Ambrisko     u_int32_t span, j;
1428665484d8SDoug Ambrisko     u_int64_t blk, debugBlk;
1429665484d8SDoug Ambrisko 
1430665484d8SDoug Ambrisko     for (span=0; span < raid->spanDepth; span++, pSpanBlock++) {
1431665484d8SDoug Ambrisko         for (j=0; j < pSpanBlock->block_span_info.noElements; j++) {
1432665484d8SDoug Ambrisko             quad = &pSpanBlock->block_span_info.quad[j];
1433665484d8SDoug Ambrisko             if (quad->diff == 0) {
1434665484d8SDoug Ambrisko                 *div_error = 1;
1435665484d8SDoug Ambrisko                 return span;
1436665484d8SDoug Ambrisko             }
1437665484d8SDoug Ambrisko             if (quad->logStart <= row  &&  row <= quad->logEnd  &&
1438665484d8SDoug Ambrisko                     (mega_mod64(row-quad->logStart, quad->diff)) == 0) {
1439665484d8SDoug Ambrisko                 if (span_blk != NULL) {
1440665484d8SDoug Ambrisko                     blk =  mega_div64_32((row-quad->logStart), quad->diff);
1441665484d8SDoug Ambrisko                     debugBlk = blk;
1442665484d8SDoug Ambrisko                     blk = (blk + quad->offsetInSpan) << raid->stripeShift;
1443665484d8SDoug Ambrisko                     *span_blk = blk;
1444665484d8SDoug Ambrisko                 }
1445665484d8SDoug Ambrisko                 return span;
1446665484d8SDoug Ambrisko             }
1447665484d8SDoug Ambrisko         }
1448665484d8SDoug Ambrisko     }
1449665484d8SDoug Ambrisko     return span;
1450665484d8SDoug Ambrisko }
1451665484d8SDoug Ambrisko 
1452