xref: /freebsd/sys/dev/mrsas/mrsas_fp.c (revision 665484d8f0c735d367ecdfc53aa49c19060703b1)
1*665484d8SDoug Ambrisko /*
2*665484d8SDoug Ambrisko  * Copyright (c) 2014, LSI Corp.
3*665484d8SDoug Ambrisko  * All rights reserved.
4*665484d8SDoug Ambrisko  * Author: Marian Choy
5*665484d8SDoug Ambrisko  * Support: freebsdraid@lsi.com
6*665484d8SDoug Ambrisko  *
7*665484d8SDoug Ambrisko  * Redistribution and use in source and binary forms, with or without
8*665484d8SDoug Ambrisko  * modification, are permitted provided that the following conditions
9*665484d8SDoug Ambrisko  * are met:
10*665484d8SDoug Ambrisko  *
11*665484d8SDoug Ambrisko  * 1. Redistributions of source code must retain the above copyright
12*665484d8SDoug Ambrisko  *    notice, this list of conditions and the following disclaimer.
13*665484d8SDoug Ambrisko  * 2. Redistributions in binary form must reproduce the above copyright
14*665484d8SDoug Ambrisko  *    notice, this list of conditions and the following disclaimer in
15*665484d8SDoug Ambrisko  *    the documentation and/or other materials provided with the
16*665484d8SDoug Ambrisko  *    distribution.
17*665484d8SDoug Ambrisko  * 3. Neither the name of the <ORGANIZATION> nor the names of its
18*665484d8SDoug Ambrisko  *    contributors may be used to endorse or promote products derived
19*665484d8SDoug Ambrisko  *    from this software without specific prior written permission.
20*665484d8SDoug Ambrisko  *
21*665484d8SDoug Ambrisko  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22*665484d8SDoug Ambrisko  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23*665484d8SDoug Ambrisko  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24*665484d8SDoug Ambrisko  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25*665484d8SDoug Ambrisko  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26*665484d8SDoug Ambrisko  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27*665484d8SDoug Ambrisko  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28*665484d8SDoug Ambrisko  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29*665484d8SDoug Ambrisko  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30*665484d8SDoug Ambrisko  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31*665484d8SDoug Ambrisko  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32*665484d8SDoug Ambrisko  * POSSIBILITY OF SUCH DAMAGE.
33*665484d8SDoug Ambrisko  *
34*665484d8SDoug Ambrisko  * The views and conclusions contained in the software and documentation
35*665484d8SDoug Ambrisko  * are those of the authors and should not be interpreted as representing
36*665484d8SDoug Ambrisko  * official policies,either expressed or implied, of the FreeBSD Project.
37*665484d8SDoug Ambrisko  *
38*665484d8SDoug Ambrisko  * Send feedback to: <megaraidfbsd@lsi.com>
39*665484d8SDoug Ambrisko  * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
40*665484d8SDoug Ambrisko  *    ATTN: MegaRaid FreeBSD
41*665484d8SDoug Ambrisko  *
42*665484d8SDoug Ambrisko  */
43*665484d8SDoug Ambrisko 
44*665484d8SDoug Ambrisko #include <sys/cdefs.h>
45*665484d8SDoug Ambrisko __FBSDID("$FreeBSD$");
46*665484d8SDoug Ambrisko 
47*665484d8SDoug Ambrisko #include <dev/mrsas/mrsas.h>
48*665484d8SDoug Ambrisko 
49*665484d8SDoug Ambrisko #include <cam/cam.h>
50*665484d8SDoug Ambrisko #include <cam/cam_ccb.h>
51*665484d8SDoug Ambrisko #include <cam/cam_sim.h>
52*665484d8SDoug Ambrisko #include <cam/cam_xpt_sim.h>
53*665484d8SDoug Ambrisko #include <cam/cam_debug.h>
54*665484d8SDoug Ambrisko #include <cam/cam_periph.h>
55*665484d8SDoug Ambrisko #include <cam/cam_xpt_periph.h>
56*665484d8SDoug Ambrisko 
57*665484d8SDoug Ambrisko 
58*665484d8SDoug Ambrisko /*
59*665484d8SDoug Ambrisko  * Function prototypes
60*665484d8SDoug Ambrisko  */
61*665484d8SDoug Ambrisko u_int8_t MR_ValidateMapInfo(struct mrsas_softc *sc);
62*665484d8SDoug Ambrisko u_int8_t mrsas_get_best_arm(PLD_LOAD_BALANCE_INFO lbInfo, u_int8_t arm,
63*665484d8SDoug Ambrisko        u_int64_t block, u_int32_t count);
64*665484d8SDoug Ambrisko u_int8_t MR_BuildRaidContext(struct mrsas_softc *sc,
65*665484d8SDoug Ambrisko         struct IO_REQUEST_INFO *io_info,
66*665484d8SDoug Ambrisko         RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map);
67*665484d8SDoug Ambrisko u_int8_t MR_GetPhyParams(struct mrsas_softc *sc, u_int32_t ld,
68*665484d8SDoug Ambrisko         u_int64_t stripRow, u_int16_t stripRef, struct IO_REQUEST_INFO *io_info,
69*665484d8SDoug Ambrisko         RAID_CONTEXT *pRAID_Context,
70*665484d8SDoug Ambrisko         MR_FW_RAID_MAP_ALL *map);
71*665484d8SDoug Ambrisko u_int16_t MR_TargetIdToLdGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map);
72*665484d8SDoug Ambrisko u_int32_t MR_LdBlockSizeGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map);
73*665484d8SDoug Ambrisko u_int16_t MR_GetLDTgtId(u_int32_t ld, MR_FW_RAID_MAP_ALL *map);
74*665484d8SDoug Ambrisko u_int16_t mrsas_get_updated_dev_handle(PLD_LOAD_BALANCE_INFO lbInfo,
75*665484d8SDoug Ambrisko         struct IO_REQUEST_INFO *io_info);
76*665484d8SDoug Ambrisko u_int32_t mega_mod64(u_int64_t dividend, u_int32_t divisor);
77*665484d8SDoug Ambrisko u_int32_t MR_GetSpanBlock(u_int32_t ld, u_int64_t row, u_int64_t *span_blk,
78*665484d8SDoug Ambrisko         MR_FW_RAID_MAP_ALL *map, int *div_error);
79*665484d8SDoug Ambrisko u_int64_t mega_div64_32(u_int64_t dividend, u_int32_t divisor);
80*665484d8SDoug Ambrisko void mrsas_update_load_balance_params(MR_FW_RAID_MAP_ALL *map,
81*665484d8SDoug Ambrisko         PLD_LOAD_BALANCE_INFO lbInfo);
82*665484d8SDoug Ambrisko void mrsas_set_pd_lba(MRSAS_RAID_SCSI_IO_REQUEST *io_request,
83*665484d8SDoug Ambrisko         u_int8_t cdb_len, struct IO_REQUEST_INFO *io_info, union ccb *ccb,
84*665484d8SDoug Ambrisko         MR_FW_RAID_MAP_ALL *local_map_ptr, u_int32_t ref_tag,
85*665484d8SDoug Ambrisko         u_int32_t ld_block_size);
86*665484d8SDoug Ambrisko static u_int16_t MR_LdSpanArrayGet(u_int32_t ld, u_int32_t span,
87*665484d8SDoug Ambrisko         MR_FW_RAID_MAP_ALL *map);
88*665484d8SDoug Ambrisko static u_int16_t MR_PdDevHandleGet(u_int32_t pd, MR_FW_RAID_MAP_ALL *map);
89*665484d8SDoug Ambrisko static u_int16_t MR_ArPdGet(u_int32_t ar, u_int32_t arm,
90*665484d8SDoug Ambrisko         MR_FW_RAID_MAP_ALL *map);
91*665484d8SDoug Ambrisko static MR_LD_SPAN *MR_LdSpanPtrGet(u_int32_t ld, u_int32_t span,
92*665484d8SDoug Ambrisko         MR_FW_RAID_MAP_ALL *map);
93*665484d8SDoug Ambrisko static u_int8_t MR_LdDataArmGet(u_int32_t ld, u_int32_t armIdx,
94*665484d8SDoug Ambrisko         MR_FW_RAID_MAP_ALL *map);
95*665484d8SDoug Ambrisko static MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u_int32_t ld,
96*665484d8SDoug Ambrisko         MR_FW_RAID_MAP_ALL *map);
97*665484d8SDoug Ambrisko MR_LD_RAID *MR_LdRaidGet(u_int32_t ld, MR_FW_RAID_MAP_ALL *map);
98*665484d8SDoug Ambrisko 
99*665484d8SDoug Ambrisko /*
100*665484d8SDoug Ambrisko  * Spanset related function prototypes
101*665484d8SDoug Ambrisko  * Added for PRL11 configuration (Uneven span support)
102*665484d8SDoug Ambrisko  */
103*665484d8SDoug Ambrisko void mr_update_span_set(MR_FW_RAID_MAP_ALL *map, PLD_SPAN_INFO ldSpanInfo);
104*665484d8SDoug Ambrisko static u_int8_t mr_spanset_get_phy_params(struct mrsas_softc *sc, u_int32_t ld,
105*665484d8SDoug Ambrisko        u_int64_t stripRow, u_int16_t stripRef, struct IO_REQUEST_INFO *io_info,
106*665484d8SDoug Ambrisko        RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map);
107*665484d8SDoug Ambrisko static u_int64_t get_row_from_strip(struct mrsas_softc *sc, u_int32_t ld,
108*665484d8SDoug Ambrisko        u_int64_t strip, MR_FW_RAID_MAP_ALL *map);
109*665484d8SDoug Ambrisko static u_int32_t mr_spanset_get_span_block(struct mrsas_softc *sc,
110*665484d8SDoug Ambrisko        u_int32_t ld, u_int64_t row, u_int64_t *span_blk,
111*665484d8SDoug Ambrisko        MR_FW_RAID_MAP_ALL *map, int *div_error);
112*665484d8SDoug Ambrisko static u_int8_t get_arm(struct mrsas_softc *sc, u_int32_t ld, u_int8_t span,
113*665484d8SDoug Ambrisko        u_int64_t stripe, MR_FW_RAID_MAP_ALL *map);
114*665484d8SDoug Ambrisko 
115*665484d8SDoug Ambrisko 
116*665484d8SDoug Ambrisko /*
117*665484d8SDoug Ambrisko  * Spanset related defines
118*665484d8SDoug Ambrisko  * Added for PRL11 configuration(Uneven span support)
119*665484d8SDoug Ambrisko  */
120*665484d8SDoug Ambrisko #define SPAN_ROW_SIZE(map, ld, index_) MR_LdSpanPtrGet(ld, index_, map)->spanRowSize
121*665484d8SDoug Ambrisko #define SPAN_ROW_DATA_SIZE(map_, ld, index_)   MR_LdSpanPtrGet(ld, index_, map)->spanRowDataSize
122*665484d8SDoug Ambrisko #define SPAN_INVALID    0xff
123*665484d8SDoug Ambrisko #define SPAN_DEBUG 0
124*665484d8SDoug Ambrisko 
125*665484d8SDoug Ambrisko /*
126*665484d8SDoug Ambrisko  * Related Defines
127*665484d8SDoug Ambrisko  */
128*665484d8SDoug Ambrisko 
129*665484d8SDoug Ambrisko typedef u_int64_t  REGION_KEY;
130*665484d8SDoug Ambrisko typedef u_int32_t  REGION_LEN;
131*665484d8SDoug Ambrisko 
132*665484d8SDoug Ambrisko #define MR_LD_STATE_OPTIMAL 3
133*665484d8SDoug Ambrisko #define FALSE 0
134*665484d8SDoug Ambrisko #define TRUE 1
135*665484d8SDoug Ambrisko 
136*665484d8SDoug Ambrisko 
137*665484d8SDoug Ambrisko /*
138*665484d8SDoug Ambrisko  * Related Macros
139*665484d8SDoug Ambrisko  */
140*665484d8SDoug Ambrisko 
141*665484d8SDoug Ambrisko #define ABS_DIFF(a,b)   ( ((a) > (b)) ? ((a) - (b)) : ((b) - (a)) )
142*665484d8SDoug Ambrisko 
143*665484d8SDoug Ambrisko #define swap32(x) \
144*665484d8SDoug Ambrisko   ((unsigned int)( \
145*665484d8SDoug Ambrisko     (((unsigned int)(x) & (unsigned int)0x000000ffUL) << 24) | \
146*665484d8SDoug Ambrisko     (((unsigned int)(x) & (unsigned int)0x0000ff00UL) <<  8) | \
147*665484d8SDoug Ambrisko     (((unsigned int)(x) & (unsigned int)0x00ff0000UL) >>  8) | \
148*665484d8SDoug Ambrisko     (((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24) ))
149*665484d8SDoug Ambrisko 
150*665484d8SDoug Ambrisko 
151*665484d8SDoug Ambrisko /*
152*665484d8SDoug Ambrisko  * In-line functions for mod and divide of 64-bit dividend and 32-bit divisor.
153*665484d8SDoug Ambrisko  * Assumes a check for a divisor of zero is not possible.
154*665484d8SDoug Ambrisko  *
155*665484d8SDoug Ambrisko  * @param dividend   : Dividend
156*665484d8SDoug Ambrisko  * @param divisor    : Divisor
157*665484d8SDoug Ambrisko  * @return remainder
158*665484d8SDoug Ambrisko  */
159*665484d8SDoug Ambrisko 
160*665484d8SDoug Ambrisko #define mega_mod64(dividend, divisor) ({ \
161*665484d8SDoug Ambrisko int remainder; \
162*665484d8SDoug Ambrisko remainder = ((u_int64_t) (dividend)) % (u_int32_t) (divisor); \
163*665484d8SDoug Ambrisko remainder;})
164*665484d8SDoug Ambrisko 
165*665484d8SDoug Ambrisko #define mega_div64_32(dividend, divisor) ({ \
166*665484d8SDoug Ambrisko int quotient; \
167*665484d8SDoug Ambrisko quotient = ((u_int64_t) (dividend)) / (u_int32_t) (divisor); \
168*665484d8SDoug Ambrisko quotient;})
169*665484d8SDoug Ambrisko 
170*665484d8SDoug Ambrisko 
171*665484d8SDoug Ambrisko /*
172*665484d8SDoug Ambrisko  * Various RAID map access functions.  These functions access the various
173*665484d8SDoug Ambrisko  * parts of the RAID map and returns the appropriate parameters.
174*665484d8SDoug Ambrisko  */
175*665484d8SDoug Ambrisko 
176*665484d8SDoug Ambrisko MR_LD_RAID *MR_LdRaidGet(u_int32_t ld, MR_FW_RAID_MAP_ALL *map)
177*665484d8SDoug Ambrisko {
178*665484d8SDoug Ambrisko     return (&map->raidMap.ldSpanMap[ld].ldRaid);
179*665484d8SDoug Ambrisko }
180*665484d8SDoug Ambrisko 
181*665484d8SDoug Ambrisko u_int16_t MR_GetLDTgtId(u_int32_t ld, MR_FW_RAID_MAP_ALL *map)
182*665484d8SDoug Ambrisko {
183*665484d8SDoug Ambrisko     return (map->raidMap.ldSpanMap[ld].ldRaid.targetId);
184*665484d8SDoug Ambrisko }
185*665484d8SDoug Ambrisko 
186*665484d8SDoug Ambrisko static u_int16_t MR_LdSpanArrayGet(u_int32_t ld, u_int32_t span, MR_FW_RAID_MAP_ALL *map)
187*665484d8SDoug Ambrisko {
188*665484d8SDoug Ambrisko     return map->raidMap.ldSpanMap[ld].spanBlock[span].span.arrayRef;
189*665484d8SDoug Ambrisko }
190*665484d8SDoug Ambrisko 
191*665484d8SDoug Ambrisko static u_int8_t MR_LdDataArmGet(u_int32_t ld, u_int32_t armIdx, MR_FW_RAID_MAP_ALL *map)
192*665484d8SDoug Ambrisko {
193*665484d8SDoug Ambrisko     return map->raidMap.ldSpanMap[ld].dataArmMap[armIdx];
194*665484d8SDoug Ambrisko }
195*665484d8SDoug Ambrisko 
196*665484d8SDoug Ambrisko static u_int16_t MR_PdDevHandleGet(u_int32_t pd, MR_FW_RAID_MAP_ALL *map)
197*665484d8SDoug Ambrisko {
198*665484d8SDoug Ambrisko     return map->raidMap.devHndlInfo[pd].curDevHdl;
199*665484d8SDoug Ambrisko }
200*665484d8SDoug Ambrisko 
201*665484d8SDoug Ambrisko static u_int16_t MR_ArPdGet(u_int32_t ar, u_int32_t arm, MR_FW_RAID_MAP_ALL *map)
202*665484d8SDoug Ambrisko {
203*665484d8SDoug Ambrisko     return map->raidMap.arMapInfo[ar].pd[arm];
204*665484d8SDoug Ambrisko }
205*665484d8SDoug Ambrisko 
206*665484d8SDoug Ambrisko static MR_LD_SPAN *MR_LdSpanPtrGet(u_int32_t ld, u_int32_t span, MR_FW_RAID_MAP_ALL *map)
207*665484d8SDoug Ambrisko {
208*665484d8SDoug Ambrisko     return &map->raidMap.ldSpanMap[ld].spanBlock[span].span;
209*665484d8SDoug Ambrisko }
210*665484d8SDoug Ambrisko 
211*665484d8SDoug Ambrisko static MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u_int32_t ld, MR_FW_RAID_MAP_ALL *map)
212*665484d8SDoug Ambrisko {
213*665484d8SDoug Ambrisko     return &map->raidMap.ldSpanMap[ld].spanBlock[0];
214*665484d8SDoug Ambrisko }
215*665484d8SDoug Ambrisko 
216*665484d8SDoug Ambrisko u_int16_t MR_TargetIdToLdGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map)
217*665484d8SDoug Ambrisko {
218*665484d8SDoug Ambrisko     return map->raidMap.ldTgtIdToLd[ldTgtId];
219*665484d8SDoug Ambrisko }
220*665484d8SDoug Ambrisko 
221*665484d8SDoug Ambrisko u_int32_t MR_LdBlockSizeGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map)
222*665484d8SDoug Ambrisko {
223*665484d8SDoug Ambrisko     MR_LD_RAID *raid;
224*665484d8SDoug Ambrisko     u_int32_t ld, ldBlockSize = MRSAS_SCSIBLOCKSIZE;
225*665484d8SDoug Ambrisko 
226*665484d8SDoug Ambrisko     ld = MR_TargetIdToLdGet(ldTgtId, map);
227*665484d8SDoug Ambrisko 
228*665484d8SDoug Ambrisko     /*
229*665484d8SDoug Ambrisko      * Check if logical drive was removed.
230*665484d8SDoug Ambrisko      */
231*665484d8SDoug Ambrisko     if (ld >= MAX_LOGICAL_DRIVES)
232*665484d8SDoug Ambrisko         return ldBlockSize;
233*665484d8SDoug Ambrisko 
234*665484d8SDoug Ambrisko     raid = MR_LdRaidGet(ld, map);
235*665484d8SDoug Ambrisko     ldBlockSize = raid->logicalBlockLength;
236*665484d8SDoug Ambrisko     if (!ldBlockSize)
237*665484d8SDoug Ambrisko         ldBlockSize = MRSAS_SCSIBLOCKSIZE;
238*665484d8SDoug Ambrisko 
239*665484d8SDoug Ambrisko     return ldBlockSize;
240*665484d8SDoug Ambrisko }
241*665484d8SDoug Ambrisko 
242*665484d8SDoug Ambrisko /**
243*665484d8SDoug Ambrisko  * MR_ValidateMapInfo:        Validate RAID map
244*665484d8SDoug Ambrisko  * input:                     Adapter instance soft state
245*665484d8SDoug Ambrisko  *
246*665484d8SDoug Ambrisko  * This function checks and validates the loaded RAID map. It returns 0 if
247*665484d8SDoug Ambrisko  * successful, and 1 otherwise.
248*665484d8SDoug Ambrisko  */
249*665484d8SDoug Ambrisko u_int8_t MR_ValidateMapInfo(struct mrsas_softc *sc)
250*665484d8SDoug Ambrisko {
251*665484d8SDoug Ambrisko 	if (!sc) {
252*665484d8SDoug Ambrisko 		return 1;
253*665484d8SDoug Ambrisko 	}
254*665484d8SDoug Ambrisko     uint32_t total_map_sz;
255*665484d8SDoug Ambrisko     MR_FW_RAID_MAP_ALL *map = sc->raidmap_mem[(sc->map_id & 1)];
256*665484d8SDoug Ambrisko     MR_FW_RAID_MAP *pFwRaidMap = &map->raidMap;
257*665484d8SDoug Ambrisko     PLD_SPAN_INFO ldSpanInfo = (PLD_SPAN_INFO) &sc->log_to_span;
258*665484d8SDoug Ambrisko 
259*665484d8SDoug Ambrisko     total_map_sz = (sizeof(MR_FW_RAID_MAP) - sizeof(MR_LD_SPAN_MAP) +
260*665484d8SDoug Ambrisko                      (sizeof(MR_LD_SPAN_MAP) * pFwRaidMap->ldCount));
261*665484d8SDoug Ambrisko 
262*665484d8SDoug Ambrisko     if (pFwRaidMap->totalSize != total_map_sz) {
263*665484d8SDoug Ambrisko         device_printf(sc->mrsas_dev, "map size %x not matching ld count\n", total_map_sz);
264*665484d8SDoug Ambrisko         device_printf(sc->mrsas_dev, "span map= %x\n", (unsigned int)sizeof(MR_LD_SPAN_MAP));
265*665484d8SDoug Ambrisko         device_printf(sc->mrsas_dev, "pFwRaidMap->totalSize=%x\n", pFwRaidMap->totalSize);
266*665484d8SDoug Ambrisko         return 1;
267*665484d8SDoug Ambrisko     }
268*665484d8SDoug Ambrisko 
269*665484d8SDoug Ambrisko     if (sc->UnevenSpanSupport) {
270*665484d8SDoug Ambrisko         mr_update_span_set(map, ldSpanInfo);
271*665484d8SDoug Ambrisko 	}
272*665484d8SDoug Ambrisko 
273*665484d8SDoug Ambrisko     mrsas_update_load_balance_params(map, sc->load_balance_info);
274*665484d8SDoug Ambrisko 
275*665484d8SDoug Ambrisko     return 0;
276*665484d8SDoug Ambrisko }
277*665484d8SDoug Ambrisko 
278*665484d8SDoug Ambrisko /*
279*665484d8SDoug Ambrisko  * ******************************************************************************
280*665484d8SDoug Ambrisko  *
281*665484d8SDoug Ambrisko  *  Function to print info about span set created in driver from FW raid map
282*665484d8SDoug Ambrisko  *
283*665484d8SDoug Ambrisko  *  Inputs :
284*665484d8SDoug Ambrisko  *  map    - LD map
285*665484d8SDoug Ambrisko  *  ldSpanInfo - ldSpanInfo per HBA instance
286*665484d8SDoug Ambrisko  *
287*665484d8SDoug Ambrisko  *
288*665484d8SDoug Ambrisko  * */
289*665484d8SDoug Ambrisko #if SPAN_DEBUG
290*665484d8SDoug Ambrisko static int getSpanInfo(MR_FW_RAID_MAP_ALL *map, PLD_SPAN_INFO ldSpanInfo)
291*665484d8SDoug Ambrisko {
292*665484d8SDoug Ambrisko 
293*665484d8SDoug Ambrisko        u_int8_t   span;
294*665484d8SDoug Ambrisko        u_int32_t    element;
295*665484d8SDoug Ambrisko        MR_LD_RAID *raid;
296*665484d8SDoug Ambrisko        LD_SPAN_SET *span_set;
297*665484d8SDoug Ambrisko        MR_QUAD_ELEMENT    *quad;
298*665484d8SDoug Ambrisko        int ldCount;
299*665484d8SDoug Ambrisko        u_int16_t ld;
300*665484d8SDoug Ambrisko 
301*665484d8SDoug Ambrisko        for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++)
302*665484d8SDoug Ambrisko        {
303*665484d8SDoug Ambrisko                ld = MR_TargetIdToLdGet(ldCount, map);
304*665484d8SDoug Ambrisko                        if (ld >= MAX_LOGICAL_DRIVES) {
305*665484d8SDoug Ambrisko                        continue;
306*665484d8SDoug Ambrisko                }
307*665484d8SDoug Ambrisko                raid = MR_LdRaidGet(ld, map);
308*665484d8SDoug Ambrisko                printf("LD %x: span_depth=%x\n", ld, raid->spanDepth);
309*665484d8SDoug Ambrisko                for (span=0; span<raid->spanDepth; span++)
310*665484d8SDoug Ambrisko                        printf("Span=%x, number of quads=%x\n", span,
311*665484d8SDoug Ambrisko                        map->raidMap.ldSpanMap[ld].spanBlock[span].
312*665484d8SDoug Ambrisko                        block_span_info.noElements);
313*665484d8SDoug Ambrisko                for (element=0; element < MAX_QUAD_DEPTH; element++) {
314*665484d8SDoug Ambrisko                        span_set = &(ldSpanInfo[ld].span_set[element]);
315*665484d8SDoug Ambrisko                        if (span_set->span_row_data_width == 0) break;
316*665484d8SDoug Ambrisko 
317*665484d8SDoug Ambrisko                        printf("  Span Set %x: width=%x, diff=%x\n", element,
318*665484d8SDoug Ambrisko                                (unsigned int)span_set->span_row_data_width,
319*665484d8SDoug Ambrisko                                (unsigned int)span_set->diff);
320*665484d8SDoug Ambrisko                        printf("    logical LBA start=0x%08lx, end=0x%08lx\n",
321*665484d8SDoug Ambrisko                                (long unsigned int)span_set->log_start_lba,
322*665484d8SDoug Ambrisko                                (long unsigned int)span_set->log_end_lba);
323*665484d8SDoug Ambrisko                        printf("       span row start=0x%08lx, end=0x%08lx\n",
324*665484d8SDoug Ambrisko                                (long unsigned int)span_set->span_row_start,
325*665484d8SDoug Ambrisko                                (long unsigned int)span_set->span_row_end);
326*665484d8SDoug Ambrisko                        printf("       data row start=0x%08lx, end=0x%08lx\n",
327*665484d8SDoug Ambrisko                                (long unsigned int)span_set->data_row_start,
328*665484d8SDoug Ambrisko                                (long unsigned int)span_set->data_row_end);
329*665484d8SDoug Ambrisko                        printf("       data strip start=0x%08lx, end=0x%08lx\n",
330*665484d8SDoug Ambrisko                                (long unsigned int)span_set->data_strip_start,
331*665484d8SDoug Ambrisko                                (long unsigned int)span_set->data_strip_end);
332*665484d8SDoug Ambrisko 
333*665484d8SDoug Ambrisko                        for (span=0; span<raid->spanDepth; span++) {
334*665484d8SDoug Ambrisko                                if (map->raidMap.ldSpanMap[ld].spanBlock[span].
335*665484d8SDoug Ambrisko                                        block_span_info.noElements >=element+1){
336*665484d8SDoug Ambrisko                                        quad = &map->raidMap.ldSpanMap[ld].
337*665484d8SDoug Ambrisko                                                spanBlock[span].block_span_info.
338*665484d8SDoug Ambrisko                                                quad[element];
339*665484d8SDoug Ambrisko                                printf("  Span=%x, Quad=%x, diff=%x\n", span,
340*665484d8SDoug Ambrisko                                        element, quad->diff);
341*665484d8SDoug Ambrisko                                printf("    offset_in_span=0x%08lx\n",
342*665484d8SDoug Ambrisko                                        (long unsigned int)quad->offsetInSpan);
343*665484d8SDoug Ambrisko                                printf("     logical start=0x%08lx, end=0x%08lx\n",
344*665484d8SDoug Ambrisko                                        (long unsigned int)quad->logStart,
345*665484d8SDoug Ambrisko                                        (long unsigned int)quad->logEnd);
346*665484d8SDoug Ambrisko                                }
347*665484d8SDoug Ambrisko                        }
348*665484d8SDoug Ambrisko                }
349*665484d8SDoug Ambrisko        }
350*665484d8SDoug Ambrisko     return 0;
351*665484d8SDoug Ambrisko }
352*665484d8SDoug Ambrisko #endif
353*665484d8SDoug Ambrisko /*
354*665484d8SDoug Ambrisko ******************************************************************************
355*665484d8SDoug Ambrisko *
356*665484d8SDoug Ambrisko * This routine calculates the Span block for given row using spanset.
357*665484d8SDoug Ambrisko *
358*665484d8SDoug Ambrisko * Inputs :
359*665484d8SDoug Ambrisko *    instance - HBA instance
360*665484d8SDoug Ambrisko *    ld   - Logical drive number
361*665484d8SDoug Ambrisko *    row        - Row number
362*665484d8SDoug Ambrisko *    map    - LD map
363*665484d8SDoug Ambrisko *
364*665484d8SDoug Ambrisko * Outputs :
365*665484d8SDoug Ambrisko *
366*665484d8SDoug Ambrisko *    span          - Span number
367*665484d8SDoug Ambrisko *    block         - Absolute Block number in the physical disk
368*665484d8SDoug Ambrisko *    div_error    - Devide error code.
369*665484d8SDoug Ambrisko */
370*665484d8SDoug Ambrisko 
371*665484d8SDoug Ambrisko u_int32_t mr_spanset_get_span_block(struct mrsas_softc *sc, u_int32_t ld, u_int64_t row,
372*665484d8SDoug Ambrisko                u_int64_t *span_blk, MR_FW_RAID_MAP_ALL *map, int *div_error)
373*665484d8SDoug Ambrisko {
374*665484d8SDoug Ambrisko        MR_LD_RAID         *raid = MR_LdRaidGet(ld, map);
375*665484d8SDoug Ambrisko        LD_SPAN_SET *span_set;
376*665484d8SDoug Ambrisko        MR_QUAD_ELEMENT    *quad;
377*665484d8SDoug Ambrisko        u_int32_t    span, info;
378*665484d8SDoug Ambrisko        PLD_SPAN_INFO ldSpanInfo = sc->log_to_span;
379*665484d8SDoug Ambrisko 
380*665484d8SDoug Ambrisko        for (info=0; info < MAX_QUAD_DEPTH; info++) {
381*665484d8SDoug Ambrisko                span_set = &(ldSpanInfo[ld].span_set[info]);
382*665484d8SDoug Ambrisko 
383*665484d8SDoug Ambrisko                if (span_set->span_row_data_width == 0) break;
384*665484d8SDoug Ambrisko                if (row > span_set->data_row_end) continue;
385*665484d8SDoug Ambrisko 
386*665484d8SDoug Ambrisko                for (span=0; span<raid->spanDepth; span++)
387*665484d8SDoug Ambrisko                        if (map->raidMap.ldSpanMap[ld].spanBlock[span].
388*665484d8SDoug Ambrisko                                block_span_info.noElements >= info+1) {
389*665484d8SDoug Ambrisko                                quad = &map->raidMap.ldSpanMap[ld].
390*665484d8SDoug Ambrisko                                        spanBlock[span].
391*665484d8SDoug Ambrisko                                        block_span_info.quad[info];
392*665484d8SDoug Ambrisko                                if (quad->diff == 0) {
393*665484d8SDoug Ambrisko                                        *div_error = 1;
394*665484d8SDoug Ambrisko                                        return span;
395*665484d8SDoug Ambrisko                                }
396*665484d8SDoug Ambrisko                                if ( quad->logStart <= row  &&
397*665484d8SDoug Ambrisko                                        row <= quad->logEnd  &&
398*665484d8SDoug Ambrisko                                        (mega_mod64(row - quad->logStart,
399*665484d8SDoug Ambrisko                                                quad->diff)) == 0 ) {
400*665484d8SDoug Ambrisko                                        if (span_blk != NULL) {
401*665484d8SDoug Ambrisko                                               u_int64_t  blk;
402*665484d8SDoug Ambrisko                                                blk = mega_div64_32
403*665484d8SDoug Ambrisko                                                    ((row - quad->logStart),
404*665484d8SDoug Ambrisko                                                    quad->diff);
405*665484d8SDoug Ambrisko                                                blk = (blk + quad->offsetInSpan)
406*665484d8SDoug Ambrisko                                                         << raid->stripeShift;
407*665484d8SDoug Ambrisko                                                *span_blk = blk;
408*665484d8SDoug Ambrisko                                        }
409*665484d8SDoug Ambrisko                                        return span;
410*665484d8SDoug Ambrisko                                }
411*665484d8SDoug Ambrisko                        }
412*665484d8SDoug Ambrisko        }
413*665484d8SDoug Ambrisko        return SPAN_INVALID;
414*665484d8SDoug Ambrisko }
415*665484d8SDoug Ambrisko 
416*665484d8SDoug Ambrisko /*
417*665484d8SDoug Ambrisko ******************************************************************************
418*665484d8SDoug Ambrisko *
419*665484d8SDoug Ambrisko * This routine calculates the row for given strip using spanset.
420*665484d8SDoug Ambrisko *
421*665484d8SDoug Ambrisko * Inputs :
422*665484d8SDoug Ambrisko *    instance - HBA instance
423*665484d8SDoug Ambrisko *    ld   - Logical drive number
424*665484d8SDoug Ambrisko *    Strip        - Strip
425*665484d8SDoug Ambrisko *    map    - LD map
426*665484d8SDoug Ambrisko *
427*665484d8SDoug Ambrisko * Outputs :
428*665484d8SDoug Ambrisko *
429*665484d8SDoug Ambrisko *    row         - row associated with strip
430*665484d8SDoug Ambrisko */
431*665484d8SDoug Ambrisko 
432*665484d8SDoug Ambrisko static u_int64_t  get_row_from_strip(struct mrsas_softc *sc,
433*665484d8SDoug Ambrisko        u_int32_t ld, u_int64_t strip, MR_FW_RAID_MAP_ALL *map)
434*665484d8SDoug Ambrisko {
435*665484d8SDoug Ambrisko        MR_LD_RAID      *raid = MR_LdRaidGet(ld, map);
436*665484d8SDoug Ambrisko        LD_SPAN_SET     *span_set;
437*665484d8SDoug Ambrisko        PLD_SPAN_INFO   ldSpanInfo = sc->log_to_span;
438*665484d8SDoug Ambrisko        u_int32_t             info, strip_offset, span, span_offset;
439*665484d8SDoug Ambrisko        u_int64_t             span_set_Strip, span_set_Row;
440*665484d8SDoug Ambrisko 
441*665484d8SDoug Ambrisko        for (info=0; info < MAX_QUAD_DEPTH; info++) {
442*665484d8SDoug Ambrisko                span_set = &(ldSpanInfo[ld].span_set[info]);
443*665484d8SDoug Ambrisko 
444*665484d8SDoug Ambrisko                if (span_set->span_row_data_width == 0) break;
445*665484d8SDoug Ambrisko                if (strip > span_set->data_strip_end) continue;
446*665484d8SDoug Ambrisko 
447*665484d8SDoug Ambrisko                span_set_Strip = strip - span_set->data_strip_start;
448*665484d8SDoug Ambrisko                strip_offset = mega_mod64(span_set_Strip,
449*665484d8SDoug Ambrisko                                span_set->span_row_data_width);
450*665484d8SDoug Ambrisko                span_set_Row = mega_div64_32(span_set_Strip,
451*665484d8SDoug Ambrisko                                span_set->span_row_data_width) * span_set->diff;
452*665484d8SDoug Ambrisko                for (span=0,span_offset=0; span<raid->spanDepth; span++)
453*665484d8SDoug Ambrisko                        if (map->raidMap.ldSpanMap[ld].spanBlock[span].
454*665484d8SDoug Ambrisko                                block_span_info.noElements >=info+1) {
455*665484d8SDoug Ambrisko                                if (strip_offset >=
456*665484d8SDoug Ambrisko                                        span_set->strip_offset[span])
457*665484d8SDoug Ambrisko                                        span_offset++;
458*665484d8SDoug Ambrisko                                else
459*665484d8SDoug Ambrisko                                        break;
460*665484d8SDoug Ambrisko                        }
461*665484d8SDoug Ambrisko                mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : Strip 0x%llx, span_set_Strip 0x%llx, span_set_Row 0x%llx "
462*665484d8SDoug Ambrisko                        "data width 0x%llx span offset 0x%llx\n", (unsigned long long)strip,
463*665484d8SDoug Ambrisko                        (unsigned long long)span_set_Strip,
464*665484d8SDoug Ambrisko                        (unsigned long long)span_set_Row,
465*665484d8SDoug Ambrisko                        (unsigned long long)span_set->span_row_data_width, (unsigned long long)span_offset);
466*665484d8SDoug Ambrisko                mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : For strip 0x%llx row is 0x%llx\n", (unsigned long long)strip,
467*665484d8SDoug Ambrisko                        (unsigned long long) span_set->data_row_start +
468*665484d8SDoug Ambrisko                        (unsigned long long) span_set_Row + (span_offset - 1));
469*665484d8SDoug Ambrisko                return (span_set->data_row_start + span_set_Row + (span_offset - 1));
470*665484d8SDoug Ambrisko        }
471*665484d8SDoug Ambrisko        return -1LLU;
472*665484d8SDoug Ambrisko }
473*665484d8SDoug Ambrisko 
474*665484d8SDoug Ambrisko 
475*665484d8SDoug Ambrisko /*
476*665484d8SDoug Ambrisko ******************************************************************************
477*665484d8SDoug Ambrisko *
478*665484d8SDoug Ambrisko * This routine calculates the Start Strip for given row using spanset.
479*665484d8SDoug Ambrisko *
480*665484d8SDoug Ambrisko * Inputs :
481*665484d8SDoug Ambrisko *    instance - HBA instance
482*665484d8SDoug Ambrisko *    ld   - Logical drive number
483*665484d8SDoug Ambrisko *    row        - Row number
484*665484d8SDoug Ambrisko *    map    - LD map
485*665484d8SDoug Ambrisko *
486*665484d8SDoug Ambrisko * Outputs :
487*665484d8SDoug Ambrisko *
488*665484d8SDoug Ambrisko *    Strip         - Start strip associated with row
489*665484d8SDoug Ambrisko */
490*665484d8SDoug Ambrisko 
491*665484d8SDoug Ambrisko static u_int64_t get_strip_from_row(struct mrsas_softc *sc,
492*665484d8SDoug Ambrisko                u_int32_t ld, u_int64_t row, MR_FW_RAID_MAP_ALL *map)
493*665484d8SDoug Ambrisko {
494*665484d8SDoug Ambrisko        MR_LD_RAID         *raid = MR_LdRaidGet(ld, map);
495*665484d8SDoug Ambrisko        LD_SPAN_SET *span_set;
496*665484d8SDoug Ambrisko        MR_QUAD_ELEMENT    *quad;
497*665484d8SDoug Ambrisko        PLD_SPAN_INFO ldSpanInfo = sc->log_to_span;
498*665484d8SDoug Ambrisko        u_int32_t    span, info;
499*665484d8SDoug Ambrisko        u_int64_t  strip;
500*665484d8SDoug Ambrisko 
501*665484d8SDoug Ambrisko        for (info=0; info<MAX_QUAD_DEPTH; info++) {
502*665484d8SDoug Ambrisko                span_set = &(ldSpanInfo[ld].span_set[info]);
503*665484d8SDoug Ambrisko 
504*665484d8SDoug Ambrisko                if (span_set->span_row_data_width == 0) break;
505*665484d8SDoug Ambrisko                if (row > span_set->data_row_end) continue;
506*665484d8SDoug Ambrisko 
507*665484d8SDoug Ambrisko                for (span=0; span<raid->spanDepth; span++)
508*665484d8SDoug Ambrisko                        if (map->raidMap.ldSpanMap[ld].spanBlock[span].
509*665484d8SDoug Ambrisko                                block_span_info.noElements >=info+1) {
510*665484d8SDoug Ambrisko                                quad = &map->raidMap.ldSpanMap[ld].
511*665484d8SDoug Ambrisko                                        spanBlock[span].block_span_info.quad[info];
512*665484d8SDoug Ambrisko                                if ( quad->logStart <= row  &&
513*665484d8SDoug Ambrisko                                        row <= quad->logEnd  &&
514*665484d8SDoug Ambrisko                                        mega_mod64((row - quad->logStart),
515*665484d8SDoug Ambrisko                                        quad->diff) == 0 ) {
516*665484d8SDoug Ambrisko                                        strip = mega_div64_32
517*665484d8SDoug Ambrisko                                                (((row - span_set->data_row_start)
518*665484d8SDoug Ambrisko                                                        - quad->logStart),
519*665484d8SDoug Ambrisko                                                        quad->diff);
520*665484d8SDoug Ambrisko                                        strip *= span_set->span_row_data_width;
521*665484d8SDoug Ambrisko                                        strip += span_set->data_strip_start;
522*665484d8SDoug Ambrisko                                        strip += span_set->strip_offset[span];
523*665484d8SDoug Ambrisko                                        return strip;
524*665484d8SDoug Ambrisko                                }
525*665484d8SDoug Ambrisko                        }
526*665484d8SDoug Ambrisko        }
527*665484d8SDoug Ambrisko        mrsas_dprint(sc, MRSAS_PRL11,"LSI Debug - get_strip_from_row: returns invalid "
528*665484d8SDoug Ambrisko                "strip for ld=%x, row=%lx\n", ld, (long unsigned int)row);
529*665484d8SDoug Ambrisko        return -1;
530*665484d8SDoug Ambrisko }
531*665484d8SDoug Ambrisko 
532*665484d8SDoug Ambrisko /*
533*665484d8SDoug Ambrisko ******************************************************************************
534*665484d8SDoug Ambrisko *
535*665484d8SDoug Ambrisko * This routine calculates the Physical Arm for given strip using spanset.
536*665484d8SDoug Ambrisko *
537*665484d8SDoug Ambrisko * Inputs :
538*665484d8SDoug Ambrisko *    instance - HBA instance
539*665484d8SDoug Ambrisko *    ld   - Logical drive number
540*665484d8SDoug Ambrisko *    strip      - Strip
541*665484d8SDoug Ambrisko *    map    - LD map
542*665484d8SDoug Ambrisko *
543*665484d8SDoug Ambrisko * Outputs :
544*665484d8SDoug Ambrisko *
545*665484d8SDoug Ambrisko *    Phys Arm         - Phys Arm associated with strip
546*665484d8SDoug Ambrisko */
547*665484d8SDoug Ambrisko 
548*665484d8SDoug Ambrisko static u_int32_t get_arm_from_strip(struct mrsas_softc *sc,
549*665484d8SDoug Ambrisko        u_int32_t ld, u_int64_t strip, MR_FW_RAID_MAP_ALL *map)
550*665484d8SDoug Ambrisko {
551*665484d8SDoug Ambrisko        MR_LD_RAID         *raid = MR_LdRaidGet(ld, map);
552*665484d8SDoug Ambrisko        LD_SPAN_SET *span_set;
553*665484d8SDoug Ambrisko        PLD_SPAN_INFO ldSpanInfo = sc->log_to_span;
554*665484d8SDoug Ambrisko        u_int32_t    info, strip_offset, span, span_offset;
555*665484d8SDoug Ambrisko 
556*665484d8SDoug Ambrisko        for (info=0; info<MAX_QUAD_DEPTH; info++) {
557*665484d8SDoug Ambrisko                span_set = &(ldSpanInfo[ld].span_set[info]);
558*665484d8SDoug Ambrisko 
559*665484d8SDoug Ambrisko                if (span_set->span_row_data_width == 0) break;
560*665484d8SDoug Ambrisko                if (strip > span_set->data_strip_end) continue;
561*665484d8SDoug Ambrisko 
562*665484d8SDoug Ambrisko                strip_offset = (u_int32_t)mega_mod64
563*665484d8SDoug Ambrisko                                ((strip - span_set->data_strip_start),
564*665484d8SDoug Ambrisko                                span_set->span_row_data_width);
565*665484d8SDoug Ambrisko 
566*665484d8SDoug Ambrisko                for (span=0,span_offset=0; span<raid->spanDepth; span++)
567*665484d8SDoug Ambrisko                        if (map->raidMap.ldSpanMap[ld].spanBlock[span].
568*665484d8SDoug Ambrisko                                block_span_info.noElements >=info+1) {
569*665484d8SDoug Ambrisko                                if (strip_offset >=
570*665484d8SDoug Ambrisko                                        span_set->strip_offset[span])
571*665484d8SDoug Ambrisko                                        span_offset =
572*665484d8SDoug Ambrisko                                                span_set->strip_offset[span];
573*665484d8SDoug Ambrisko                                else
574*665484d8SDoug Ambrisko                                        break;
575*665484d8SDoug Ambrisko                        }
576*665484d8SDoug Ambrisko                mrsas_dprint(sc, MRSAS_PRL11, "LSI PRL11: get_arm_from_strip: "
577*665484d8SDoug Ambrisko                        " for ld=0x%x strip=0x%lx arm is  0x%x\n", ld,
578*665484d8SDoug Ambrisko                        (long unsigned int)strip, (strip_offset - span_offset));
579*665484d8SDoug Ambrisko                return (strip_offset - span_offset);
580*665484d8SDoug Ambrisko        }
581*665484d8SDoug Ambrisko 
582*665484d8SDoug Ambrisko        mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: - get_arm_from_strip: returns invalid arm"
583*665484d8SDoug Ambrisko                " for ld=%x strip=%lx\n", ld, (long unsigned int)strip);
584*665484d8SDoug Ambrisko 
585*665484d8SDoug Ambrisko        return -1;
586*665484d8SDoug Ambrisko }
587*665484d8SDoug Ambrisko 
588*665484d8SDoug Ambrisko 
589*665484d8SDoug Ambrisko /* This Function will return Phys arm */
590*665484d8SDoug Ambrisko u_int8_t get_arm(struct mrsas_softc *sc, u_int32_t ld, u_int8_t span, u_int64_t stripe,
591*665484d8SDoug Ambrisko                MR_FW_RAID_MAP_ALL *map)
592*665484d8SDoug Ambrisko {
593*665484d8SDoug Ambrisko        MR_LD_RAID  *raid = MR_LdRaidGet(ld, map);
594*665484d8SDoug Ambrisko        /* Need to check correct default value */
595*665484d8SDoug Ambrisko        u_int32_t    arm = 0;
596*665484d8SDoug Ambrisko 
597*665484d8SDoug Ambrisko        switch (raid->level) {
598*665484d8SDoug Ambrisko                case 0:
599*665484d8SDoug Ambrisko                case 5:
600*665484d8SDoug Ambrisko                case 6:
601*665484d8SDoug Ambrisko                        arm = mega_mod64(stripe, SPAN_ROW_SIZE(map, ld, span));
602*665484d8SDoug Ambrisko                        break;
603*665484d8SDoug Ambrisko                case 1:
604*665484d8SDoug Ambrisko                        // start with logical arm
605*665484d8SDoug Ambrisko                        arm = get_arm_from_strip(sc, ld, stripe, map);
606*665484d8SDoug Ambrisko                        arm *= 2;
607*665484d8SDoug Ambrisko                        break;
608*665484d8SDoug Ambrisko 
609*665484d8SDoug Ambrisko        }
610*665484d8SDoug Ambrisko 
611*665484d8SDoug Ambrisko        return arm;
612*665484d8SDoug Ambrisko }
613*665484d8SDoug Ambrisko 
614*665484d8SDoug Ambrisko /*
615*665484d8SDoug Ambrisko ******************************************************************************
616*665484d8SDoug Ambrisko *
617*665484d8SDoug Ambrisko * This routine calculates the arm, span and block for the specified stripe and
618*665484d8SDoug Ambrisko * reference in stripe using spanset
619*665484d8SDoug Ambrisko *
620*665484d8SDoug Ambrisko * Inputs :
621*665484d8SDoug Ambrisko *
622*665484d8SDoug Ambrisko *    ld   - Logical drive number
623*665484d8SDoug Ambrisko *    stripRow        - Stripe number
624*665484d8SDoug Ambrisko *    stripRef    - Reference in stripe
625*665484d8SDoug Ambrisko *
626*665484d8SDoug Ambrisko * Outputs :
627*665484d8SDoug Ambrisko *
628*665484d8SDoug Ambrisko *    span          - Span number
629*665484d8SDoug Ambrisko *    block         - Absolute Block number in the physical disk
630*665484d8SDoug Ambrisko */
631*665484d8SDoug Ambrisko static u_int8_t mr_spanset_get_phy_params(struct mrsas_softc *sc, u_int32_t ld, u_int64_t stripRow,
632*665484d8SDoug Ambrisko                   u_int16_t stripRef, struct IO_REQUEST_INFO *io_info,
633*665484d8SDoug Ambrisko                   RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map)
634*665484d8SDoug Ambrisko {
635*665484d8SDoug Ambrisko        MR_LD_RAID  *raid = MR_LdRaidGet(ld, map);
636*665484d8SDoug Ambrisko        u_int32_t     pd, arRef;
637*665484d8SDoug Ambrisko        u_int8_t      physArm, span;
638*665484d8SDoug Ambrisko        u_int64_t     row;
639*665484d8SDoug Ambrisko        u_int8_t      retval = TRUE;
640*665484d8SDoug Ambrisko        u_int64_t     *pdBlock = &io_info->pdBlock;
641*665484d8SDoug Ambrisko        u_int16_t     *pDevHandle = &io_info->devHandle;
642*665484d8SDoug Ambrisko        u_int32_t     logArm, rowMod, armQ, arm;
643*665484d8SDoug Ambrisko        u_int8_t do_invader = 0;
644*665484d8SDoug Ambrisko 
645*665484d8SDoug Ambrisko        if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY))
646*665484d8SDoug Ambrisko            do_invader = 1;
647*665484d8SDoug Ambrisko 
648*665484d8SDoug Ambrisko        // Get row and span from io_info for Uneven Span IO.
649*665484d8SDoug Ambrisko        row         = io_info->start_row;
650*665484d8SDoug Ambrisko        span        = io_info->start_span;
651*665484d8SDoug Ambrisko 
652*665484d8SDoug Ambrisko 
653*665484d8SDoug Ambrisko        if (raid->level == 6) {
654*665484d8SDoug Ambrisko                logArm = get_arm_from_strip(sc, ld, stripRow, map);
655*665484d8SDoug Ambrisko                rowMod = mega_mod64(row, SPAN_ROW_SIZE(map, ld, span));
656*665484d8SDoug Ambrisko                armQ = SPAN_ROW_SIZE(map,ld,span) - 1 - rowMod;
657*665484d8SDoug Ambrisko                arm = armQ + 1 + logArm;
658*665484d8SDoug Ambrisko                if (arm >= SPAN_ROW_SIZE(map, ld, span))
659*665484d8SDoug Ambrisko                        arm -= SPAN_ROW_SIZE(map ,ld ,span);
660*665484d8SDoug Ambrisko                physArm = (u_int8_t)arm;
661*665484d8SDoug Ambrisko        } else
662*665484d8SDoug Ambrisko                // Calculate the arm
663*665484d8SDoug Ambrisko                physArm = get_arm(sc, ld, span, stripRow, map);
664*665484d8SDoug Ambrisko 
665*665484d8SDoug Ambrisko 
666*665484d8SDoug Ambrisko        arRef       = MR_LdSpanArrayGet(ld, span, map);
667*665484d8SDoug Ambrisko        pd          = MR_ArPdGet(arRef, physArm, map);
668*665484d8SDoug Ambrisko 
669*665484d8SDoug Ambrisko        if (pd != MR_PD_INVALID)
670*665484d8SDoug Ambrisko                *pDevHandle = MR_PdDevHandleGet(pd, map);
671*665484d8SDoug Ambrisko        else {
672*665484d8SDoug Ambrisko                *pDevHandle = MR_PD_INVALID;
673*665484d8SDoug Ambrisko                if ((raid->level >= 5) && ((!do_invader) || (do_invader &&
674*665484d8SDoug Ambrisko                   raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))
675*665484d8SDoug Ambrisko                   pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
676*665484d8SDoug Ambrisko                else if (raid->level == 1) {
677*665484d8SDoug Ambrisko                	  pd = MR_ArPdGet(arRef, physArm + 1, map);
678*665484d8SDoug Ambrisko                   if (pd != MR_PD_INVALID)
679*665484d8SDoug Ambrisko                      *pDevHandle = MR_PdDevHandleGet(pd, map);
680*665484d8SDoug Ambrisko                }
681*665484d8SDoug Ambrisko        }
682*665484d8SDoug Ambrisko 
683*665484d8SDoug Ambrisko        *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk;
684*665484d8SDoug Ambrisko        pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm;
685*665484d8SDoug Ambrisko        return retval;
686*665484d8SDoug Ambrisko }
687*665484d8SDoug Ambrisko 
688*665484d8SDoug Ambrisko /**
689*665484d8SDoug Ambrisko * MR_BuildRaidContext:           Set up Fast path RAID context
690*665484d8SDoug Ambrisko *
691*665484d8SDoug Ambrisko * This function will initiate command processing.  The start/end row
692*665484d8SDoug Ambrisko * and strip information is calculated then the lock is acquired.
693*665484d8SDoug Ambrisko * This function will return 0 if region lock was acquired OR return
694*665484d8SDoug Ambrisko * num strips.
695*665484d8SDoug Ambrisko */
696*665484d8SDoug Ambrisko u_int8_t
697*665484d8SDoug Ambrisko MR_BuildRaidContext(struct mrsas_softc *sc, struct IO_REQUEST_INFO *io_info,
698*665484d8SDoug Ambrisko                     RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map)
699*665484d8SDoug Ambrisko {
700*665484d8SDoug Ambrisko     MR_LD_RAID *raid;
701*665484d8SDoug Ambrisko     u_int32_t ld, stripSize, stripe_mask;
702*665484d8SDoug Ambrisko     u_int64_t endLba, endStrip, endRow, start_row, start_strip;
703*665484d8SDoug Ambrisko     REGION_KEY regStart;
704*665484d8SDoug Ambrisko     REGION_LEN regSize;
705*665484d8SDoug Ambrisko     u_int8_t num_strips, numRows;
706*665484d8SDoug Ambrisko     u_int16_t ref_in_start_stripe, ref_in_end_stripe;
707*665484d8SDoug Ambrisko     u_int64_t ldStartBlock;
708*665484d8SDoug Ambrisko     u_int32_t numBlocks, ldTgtId;
709*665484d8SDoug Ambrisko     u_int8_t isRead, stripIdx;
710*665484d8SDoug Ambrisko     u_int8_t retval = 0;
711*665484d8SDoug Ambrisko 	u_int8_t startlba_span = SPAN_INVALID;
712*665484d8SDoug Ambrisko     u_int64_t *pdBlock = &io_info->pdBlock;
713*665484d8SDoug Ambrisko     int error_code = 0;
714*665484d8SDoug Ambrisko 
715*665484d8SDoug Ambrisko     ldStartBlock = io_info->ldStartBlock;
716*665484d8SDoug Ambrisko     numBlocks = io_info->numBlocks;
717*665484d8SDoug Ambrisko     ldTgtId = io_info->ldTgtId;
718*665484d8SDoug Ambrisko     isRead = io_info->isRead;
719*665484d8SDoug Ambrisko 
720*665484d8SDoug Ambrisko 	io_info->IoforUnevenSpan = 0;
721*665484d8SDoug Ambrisko     io_info->start_span     = SPAN_INVALID;
722*665484d8SDoug Ambrisko 
723*665484d8SDoug Ambrisko     ld = MR_TargetIdToLdGet(ldTgtId, map);
724*665484d8SDoug Ambrisko     raid = MR_LdRaidGet(ld, map);
725*665484d8SDoug Ambrisko 
726*665484d8SDoug Ambrisko     /*
727*665484d8SDoug Ambrisko  	* if rowDataSize @RAID map and spanRowDataSize @SPAN INFO are zero
728*665484d8SDoug Ambrisko     * return FALSE
729*665484d8SDoug Ambrisko     */
730*665484d8SDoug Ambrisko 	if (raid->rowDataSize == 0) {
731*665484d8SDoug Ambrisko 	   if (MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize == 0)
732*665484d8SDoug Ambrisko 		   return FALSE;
733*665484d8SDoug Ambrisko 	   else if (sc->UnevenSpanSupport) {
734*665484d8SDoug Ambrisko 		   io_info->IoforUnevenSpan = 1;
735*665484d8SDoug Ambrisko 	   }
736*665484d8SDoug Ambrisko 	   else {
737*665484d8SDoug Ambrisko 		   mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: raid->rowDataSize is 0, but has SPAN[0] rowDataSize = 0x%0x,"
738*665484d8SDoug Ambrisko 				   " but there is _NO_ UnevenSpanSupport\n",
739*665484d8SDoug Ambrisko 		   MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize);
740*665484d8SDoug Ambrisko 		   return FALSE;
741*665484d8SDoug Ambrisko 	   }
742*665484d8SDoug Ambrisko 	}
743*665484d8SDoug Ambrisko     stripSize = 1 << raid->stripeShift;
744*665484d8SDoug Ambrisko     stripe_mask = stripSize-1;
745*665484d8SDoug Ambrisko     /*
746*665484d8SDoug Ambrisko      * calculate starting row and stripe, and number of strips and rows
747*665484d8SDoug Ambrisko      */
748*665484d8SDoug Ambrisko     start_strip = ldStartBlock >> raid->stripeShift;
749*665484d8SDoug Ambrisko     ref_in_start_stripe = (u_int16_t)(ldStartBlock & stripe_mask);
750*665484d8SDoug Ambrisko     endLba = ldStartBlock + numBlocks - 1;
751*665484d8SDoug Ambrisko     ref_in_end_stripe = (u_int16_t)(endLba & stripe_mask);
752*665484d8SDoug Ambrisko     endStrip = endLba >> raid->stripeShift;
753*665484d8SDoug Ambrisko     num_strips = (u_int8_t)(endStrip - start_strip + 1);     // End strip
754*665484d8SDoug Ambrisko        if (io_info->IoforUnevenSpan) {
755*665484d8SDoug Ambrisko                start_row = get_row_from_strip(sc, ld, start_strip, map);
756*665484d8SDoug Ambrisko                endRow    = get_row_from_strip(sc, ld, endStrip, map);
757*665484d8SDoug Ambrisko                if (raid->spanDepth == 1) {
758*665484d8SDoug Ambrisko                        startlba_span = 0;
759*665484d8SDoug Ambrisko                        *pdBlock = start_row << raid->stripeShift;
760*665484d8SDoug Ambrisko                } else {
761*665484d8SDoug Ambrisko                        startlba_span = (u_int8_t)mr_spanset_get_span_block(sc, ld, start_row,
762*665484d8SDoug Ambrisko                                                pdBlock, map, &error_code);
763*665484d8SDoug Ambrisko                        if (error_code == 1) {
764*665484d8SDoug Ambrisko                                mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: return from %s %d. Send IO w/o region lock.\n",
765*665484d8SDoug Ambrisko                                        __func__, __LINE__);
766*665484d8SDoug Ambrisko                                return FALSE;
767*665484d8SDoug Ambrisko                        }
768*665484d8SDoug Ambrisko                }
769*665484d8SDoug Ambrisko                if (startlba_span == SPAN_INVALID) {
770*665484d8SDoug Ambrisko                        mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: return from %s %d for row 0x%llx,"
771*665484d8SDoug Ambrisko                                "start strip %llx endSrip %llx\n", __func__,
772*665484d8SDoug Ambrisko                                __LINE__, (unsigned long long)start_row,
773*665484d8SDoug Ambrisko                                (unsigned long long)start_strip,
774*665484d8SDoug Ambrisko                                (unsigned long long)endStrip);
775*665484d8SDoug Ambrisko                        return FALSE;
776*665484d8SDoug Ambrisko                }
777*665484d8SDoug Ambrisko                io_info->start_span     = startlba_span;
778*665484d8SDoug Ambrisko                io_info->start_row      = start_row;
779*665484d8SDoug Ambrisko                mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: Check Span number from %s %d for row 0x%llx, "
780*665484d8SDoug Ambrisko                                " start strip 0x%llx endSrip 0x%llx span 0x%x\n",
781*665484d8SDoug Ambrisko                                 __func__, __LINE__, (unsigned long long)start_row,
782*665484d8SDoug Ambrisko                                (unsigned long long)start_strip,
783*665484d8SDoug Ambrisko                                (unsigned long long)endStrip, startlba_span);
784*665484d8SDoug Ambrisko                mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : 1. start_row 0x%llx endRow 0x%llx Start span 0x%x\n",
785*665484d8SDoug Ambrisko                        (unsigned long long)start_row, (unsigned long long)endRow, startlba_span);
786*665484d8SDoug Ambrisko        } else {
787*665484d8SDoug Ambrisko                start_row           =  mega_div64_32(start_strip, raid->rowDataSize);      // Start Row
788*665484d8SDoug Ambrisko                endRow              =  mega_div64_32(endStrip, raid->rowDataSize);
789*665484d8SDoug Ambrisko        }
790*665484d8SDoug Ambrisko 
791*665484d8SDoug Ambrisko     numRows = (u_int8_t)(endRow - start_row + 1);   // get the row count
792*665484d8SDoug Ambrisko 
793*665484d8SDoug Ambrisko     /*
794*665484d8SDoug Ambrisko      * Calculate region info.  (Assume region at start of first row, and
795*665484d8SDoug Ambrisko      * assume this IO needs the full row - will adjust if not true.)
796*665484d8SDoug Ambrisko      */
797*665484d8SDoug Ambrisko     regStart = start_row << raid->stripeShift;
798*665484d8SDoug Ambrisko     regSize = stripSize;
799*665484d8SDoug Ambrisko 
800*665484d8SDoug Ambrisko     /* Check if we can send this I/O via FastPath */
801*665484d8SDoug Ambrisko     if (raid->capability.fpCapable) {
802*665484d8SDoug Ambrisko         if (isRead)
803*665484d8SDoug Ambrisko             io_info->fpOkForIo = (raid->capability.fpReadCapable &&
804*665484d8SDoug Ambrisko                                               ((num_strips == 1) ||
805*665484d8SDoug Ambrisko                                                raid->capability.
806*665484d8SDoug Ambrisko                                                fpReadAcrossStripe));
807*665484d8SDoug Ambrisko         else
808*665484d8SDoug Ambrisko             io_info->fpOkForIo = (raid->capability.fpWriteCapable &&
809*665484d8SDoug Ambrisko                                               ((num_strips == 1) ||
810*665484d8SDoug Ambrisko                                                raid->capability.
811*665484d8SDoug Ambrisko                                                fpWriteAcrossStripe));
812*665484d8SDoug Ambrisko     }
813*665484d8SDoug Ambrisko     else
814*665484d8SDoug Ambrisko         io_info->fpOkForIo = FALSE;
815*665484d8SDoug Ambrisko 
816*665484d8SDoug Ambrisko     if (numRows == 1) {
817*665484d8SDoug Ambrisko         if (num_strips == 1) {
818*665484d8SDoug Ambrisko             /* single-strip IOs can always lock only the data needed,
819*665484d8SDoug Ambrisko                multi-strip IOs always need to full stripe locked */
820*665484d8SDoug Ambrisko             regStart += ref_in_start_stripe;
821*665484d8SDoug Ambrisko             regSize = numBlocks;
822*665484d8SDoug Ambrisko         }
823*665484d8SDoug Ambrisko     }
824*665484d8SDoug Ambrisko     else if (io_info->IoforUnevenSpan == 0){
825*665484d8SDoug Ambrisko         // For Even span region lock optimization.
826*665484d8SDoug Ambrisko         // If the start strip is the last in the start row
827*665484d8SDoug Ambrisko         if (start_strip == (start_row + 1) * raid->rowDataSize - 1) {
828*665484d8SDoug Ambrisko             regStart += ref_in_start_stripe;
829*665484d8SDoug Ambrisko             // initialize count to sectors from startRef to end of strip
830*665484d8SDoug Ambrisko             regSize = stripSize - ref_in_start_stripe;
831*665484d8SDoug Ambrisko         }
832*665484d8SDoug Ambrisko 		// add complete rows in the middle of the transfer
833*665484d8SDoug Ambrisko 		if (numRows > 2)
834*665484d8SDoug Ambrisko             regSize += (numRows-2) << raid->stripeShift;
835*665484d8SDoug Ambrisko 
836*665484d8SDoug Ambrisko         // if IO ends within first strip of last row
837*665484d8SDoug Ambrisko         if (endStrip == endRow*raid->rowDataSize)
838*665484d8SDoug Ambrisko                         regSize += ref_in_end_stripe+1;
839*665484d8SDoug Ambrisko                 else
840*665484d8SDoug Ambrisko                         regSize += stripSize;
841*665484d8SDoug Ambrisko     } else {
842*665484d8SDoug Ambrisko 		//For Uneven span region lock optimization.
843*665484d8SDoug Ambrisko         // If the start strip is the last in the start row
844*665484d8SDoug Ambrisko         if (start_strip == (get_strip_from_row(sc, ld, start_row, map) +
845*665484d8SDoug Ambrisko             	SPAN_ROW_DATA_SIZE(map, ld, startlba_span) - 1)) {
846*665484d8SDoug Ambrisko             regStart += ref_in_start_stripe;
847*665484d8SDoug Ambrisko 			// initialize count to sectors from startRef to end of strip
848*665484d8SDoug Ambrisko 			regSize = stripSize - ref_in_start_stripe;
849*665484d8SDoug Ambrisko         }
850*665484d8SDoug Ambrisko         // add complete rows in the middle of the transfer
851*665484d8SDoug Ambrisko         if (numRows > 2)
852*665484d8SDoug Ambrisko             regSize += (numRows-2) << raid->stripeShift;
853*665484d8SDoug Ambrisko 
854*665484d8SDoug Ambrisko         // if IO ends within first strip of last row
855*665484d8SDoug Ambrisko         if (endStrip == get_strip_from_row(sc, ld, endRow, map))
856*665484d8SDoug Ambrisko             regSize += ref_in_end_stripe+1;
857*665484d8SDoug Ambrisko         else
858*665484d8SDoug Ambrisko             regSize += stripSize;
859*665484d8SDoug Ambrisko     }
860*665484d8SDoug Ambrisko     pRAID_Context->timeoutValue = map->raidMap.fpPdIoTimeoutSec;
861*665484d8SDoug Ambrisko     if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY))
862*665484d8SDoug Ambrisko                 pRAID_Context->regLockFlags = (isRead)? raid->regTypeReqOnRead : raid->regTypeReqOnWrite;
863*665484d8SDoug Ambrisko     else
864*665484d8SDoug Ambrisko     	pRAID_Context->regLockFlags = (isRead)? REGION_TYPE_SHARED_READ : raid->regTypeReqOnWrite;
865*665484d8SDoug Ambrisko     pRAID_Context->VirtualDiskTgtId = raid->targetId;
866*665484d8SDoug Ambrisko     pRAID_Context->regLockRowLBA = regStart;
867*665484d8SDoug Ambrisko     pRAID_Context->regLockLength = regSize;
868*665484d8SDoug Ambrisko     pRAID_Context->configSeqNum = raid->seqNum;
869*665484d8SDoug Ambrisko 
870*665484d8SDoug Ambrisko     /*
871*665484d8SDoug Ambrisko      * Get Phy Params only if FP capable, or else leave it to MR firmware
872*665484d8SDoug Ambrisko      * to do the calculation.
873*665484d8SDoug Ambrisko      */
874*665484d8SDoug Ambrisko     if (io_info->fpOkForIo) {
875*665484d8SDoug Ambrisko         retval = io_info->IoforUnevenSpan ?
876*665484d8SDoug Ambrisko                                mr_spanset_get_phy_params(sc, ld,
877*665484d8SDoug Ambrisko                                    start_strip, ref_in_start_stripe, io_info,
878*665484d8SDoug Ambrisko                                    pRAID_Context, map) :
879*665484d8SDoug Ambrisko                                MR_GetPhyParams(sc, ld, start_strip,
880*665484d8SDoug Ambrisko                                    ref_in_start_stripe, io_info, pRAID_Context, map);
881*665484d8SDoug Ambrisko         /* If IO on an invalid Pd, then FP is not possible */
882*665484d8SDoug Ambrisko         if (io_info->devHandle == MR_PD_INVALID)
883*665484d8SDoug Ambrisko             io_info->fpOkForIo = FALSE;
884*665484d8SDoug Ambrisko         return retval;
885*665484d8SDoug Ambrisko     }
886*665484d8SDoug Ambrisko     else if (isRead) {
887*665484d8SDoug Ambrisko         for (stripIdx=0; stripIdx<num_strips; stripIdx++) {
888*665484d8SDoug Ambrisko              retval = io_info->IoforUnevenSpan ?
889*665484d8SDoug Ambrisko                         mr_spanset_get_phy_params(sc, ld,
890*665484d8SDoug Ambrisko                             start_strip + stripIdx,
891*665484d8SDoug Ambrisko                             ref_in_start_stripe, io_info,
892*665484d8SDoug Ambrisko                             pRAID_Context, map) :
893*665484d8SDoug Ambrisko                         MR_GetPhyParams(sc, ld,
894*665484d8SDoug Ambrisko                             start_strip + stripIdx, ref_in_start_stripe,
895*665484d8SDoug Ambrisko                             io_info, pRAID_Context, map);
896*665484d8SDoug Ambrisko               if (!retval)
897*665484d8SDoug Ambrisko                   return TRUE;
898*665484d8SDoug Ambrisko         }
899*665484d8SDoug Ambrisko     }
900*665484d8SDoug Ambrisko #if SPAN_DEBUG
901*665484d8SDoug Ambrisko        // Just for testing what arm we get for strip.
902*665484d8SDoug Ambrisko        get_arm_from_strip(sc, ld, start_strip, map);
903*665484d8SDoug Ambrisko #endif
904*665484d8SDoug Ambrisko     return TRUE;
905*665484d8SDoug Ambrisko }
906*665484d8SDoug Ambrisko 
907*665484d8SDoug Ambrisko /*
908*665484d8SDoug Ambrisko ******************************************************************************
909*665484d8SDoug Ambrisko *
910*665484d8SDoug Ambrisko * This routine pepare spanset info from Valid Raid map and store it into
911*665484d8SDoug Ambrisko * local copy of ldSpanInfo per instance data structure.
912*665484d8SDoug Ambrisko *
913*665484d8SDoug Ambrisko * Inputs :
914*665484d8SDoug Ambrisko *    map    - LD map
915*665484d8SDoug Ambrisko *    ldSpanInfo - ldSpanInfo per HBA instance
916*665484d8SDoug Ambrisko *
917*665484d8SDoug Ambrisko */
918*665484d8SDoug Ambrisko void mr_update_span_set(MR_FW_RAID_MAP_ALL *map, PLD_SPAN_INFO ldSpanInfo)
919*665484d8SDoug Ambrisko {
920*665484d8SDoug Ambrisko        u_int8_t   span,count;
921*665484d8SDoug Ambrisko        u_int32_t    element,span_row_width;
922*665484d8SDoug Ambrisko        u_int64_t  span_row;
923*665484d8SDoug Ambrisko        MR_LD_RAID *raid;
924*665484d8SDoug Ambrisko        LD_SPAN_SET *span_set, *span_set_prev;
925*665484d8SDoug Ambrisko        MR_QUAD_ELEMENT    *quad;
926*665484d8SDoug Ambrisko        int ldCount;
927*665484d8SDoug Ambrisko        u_int16_t ld;
928*665484d8SDoug Ambrisko 
929*665484d8SDoug Ambrisko 	if (!ldSpanInfo)
930*665484d8SDoug Ambrisko 		return;
931*665484d8SDoug Ambrisko 
932*665484d8SDoug Ambrisko        for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++)
933*665484d8SDoug Ambrisko        {
934*665484d8SDoug Ambrisko                ld = MR_TargetIdToLdGet(ldCount, map);
935*665484d8SDoug Ambrisko                if (ld >= MAX_LOGICAL_DRIVES)
936*665484d8SDoug Ambrisko                        continue;
937*665484d8SDoug Ambrisko                raid = MR_LdRaidGet(ld, map);
938*665484d8SDoug Ambrisko                for (element=0; element < MAX_QUAD_DEPTH; element++) {
939*665484d8SDoug Ambrisko                        for (span=0; span < raid->spanDepth; span++) {
940*665484d8SDoug Ambrisko                                if (map->raidMap.ldSpanMap[ld].spanBlock[span].
941*665484d8SDoug Ambrisko                                        block_span_info.noElements < element+1)
942*665484d8SDoug Ambrisko                                        continue;
943*665484d8SDoug Ambrisko                                // TO-DO
944*665484d8SDoug Ambrisko                                span_set = &(ldSpanInfo[ld].span_set[element]);
945*665484d8SDoug Ambrisko                                quad = &map->raidMap.ldSpanMap[ld].
946*665484d8SDoug Ambrisko                                        spanBlock[span].block_span_info.
947*665484d8SDoug Ambrisko                                        quad[element];
948*665484d8SDoug Ambrisko 
949*665484d8SDoug Ambrisko                                span_set->diff = quad->diff;
950*665484d8SDoug Ambrisko 
951*665484d8SDoug Ambrisko                                for (count=0,span_row_width=0;
952*665484d8SDoug Ambrisko                                                count<raid->spanDepth; count++) {
953*665484d8SDoug Ambrisko                                        if (map->raidMap.ldSpanMap[ld].
954*665484d8SDoug Ambrisko                                                spanBlock[count].
955*665484d8SDoug Ambrisko                                                block_span_info.
956*665484d8SDoug Ambrisko                                                noElements >=element+1) {
957*665484d8SDoug Ambrisko                                                span_set->strip_offset[count] =
958*665484d8SDoug Ambrisko                                                        span_row_width;
959*665484d8SDoug Ambrisko                                                span_row_width +=
960*665484d8SDoug Ambrisko                                                        MR_LdSpanPtrGet
961*665484d8SDoug Ambrisko                                                        (ld, count, map)->spanRowDataSize;
962*665484d8SDoug Ambrisko #if SPAN_DEBUG
963*665484d8SDoug Ambrisko                                                printf("LSI Debug span %x rowDataSize %x\n",
964*665484d8SDoug Ambrisko                                                count, MR_LdSpanPtrGet
965*665484d8SDoug Ambrisko                                                        (ld, count, map)->spanRowDataSize);
966*665484d8SDoug Ambrisko #endif
967*665484d8SDoug Ambrisko                                        }
968*665484d8SDoug Ambrisko                                }
969*665484d8SDoug Ambrisko 
970*665484d8SDoug Ambrisko                                span_set->span_row_data_width = span_row_width;
971*665484d8SDoug Ambrisko                                span_row = mega_div64_32(((quad->logEnd -
972*665484d8SDoug Ambrisko                                        quad->logStart) + quad->diff), quad->diff);
973*665484d8SDoug Ambrisko 
974*665484d8SDoug Ambrisko                                if (element == 0) {
975*665484d8SDoug Ambrisko                                        span_set->log_start_lba = 0;
976*665484d8SDoug Ambrisko                                        span_set->log_end_lba =
977*665484d8SDoug Ambrisko                                        ((span_row << raid->stripeShift) * span_row_width) - 1;
978*665484d8SDoug Ambrisko 
979*665484d8SDoug Ambrisko                                        span_set->span_row_start = 0;
980*665484d8SDoug Ambrisko                                        span_set->span_row_end = span_row - 1;
981*665484d8SDoug Ambrisko 
982*665484d8SDoug Ambrisko                                        span_set->data_strip_start = 0;
983*665484d8SDoug Ambrisko                                        span_set->data_strip_end =
984*665484d8SDoug Ambrisko                                                (span_row * span_row_width) - 1;
985*665484d8SDoug Ambrisko 
986*665484d8SDoug Ambrisko                                        span_set->data_row_start = 0;
987*665484d8SDoug Ambrisko                                        span_set->data_row_end =
988*665484d8SDoug Ambrisko                                                (span_row * quad->diff) - 1;
989*665484d8SDoug Ambrisko                                } else {
990*665484d8SDoug Ambrisko                                        span_set_prev = &(ldSpanInfo[ld].
991*665484d8SDoug Ambrisko                                                        span_set[element - 1]);
992*665484d8SDoug Ambrisko                                        span_set->log_start_lba =
993*665484d8SDoug Ambrisko                                                span_set_prev->log_end_lba + 1;
994*665484d8SDoug Ambrisko                                        span_set->log_end_lba =
995*665484d8SDoug Ambrisko                                                span_set->log_start_lba +
996*665484d8SDoug Ambrisko                                                ((span_row << raid->stripeShift) * span_row_width) - 1;
997*665484d8SDoug Ambrisko 
998*665484d8SDoug Ambrisko                                        span_set->span_row_start =
999*665484d8SDoug Ambrisko                                                span_set_prev->span_row_end + 1;
1000*665484d8SDoug Ambrisko                                        span_set->span_row_end =
1001*665484d8SDoug Ambrisko                                                span_set->span_row_start + span_row - 1;
1002*665484d8SDoug Ambrisko 
1003*665484d8SDoug Ambrisko                                        span_set->data_strip_start =
1004*665484d8SDoug Ambrisko                                                span_set_prev->data_strip_end + 1;
1005*665484d8SDoug Ambrisko                                        span_set->data_strip_end =
1006*665484d8SDoug Ambrisko                                                span_set->data_strip_start +
1007*665484d8SDoug Ambrisko                                                (span_row * span_row_width) - 1;
1008*665484d8SDoug Ambrisko 
1009*665484d8SDoug Ambrisko                                        span_set->data_row_start =
1010*665484d8SDoug Ambrisko                                                span_set_prev->data_row_end + 1;
1011*665484d8SDoug Ambrisko                                        span_set->data_row_end =
1012*665484d8SDoug Ambrisko                                                span_set->data_row_start +
1013*665484d8SDoug Ambrisko                                                (span_row * quad->diff) - 1;
1014*665484d8SDoug Ambrisko                                }
1015*665484d8SDoug Ambrisko                                break;
1016*665484d8SDoug Ambrisko                }
1017*665484d8SDoug Ambrisko                if (span == raid->spanDepth) break; // no quads remain
1018*665484d8SDoug Ambrisko            }
1019*665484d8SDoug Ambrisko        }
1020*665484d8SDoug Ambrisko #if SPAN_DEBUG
1021*665484d8SDoug Ambrisko        getSpanInfo(map, ldSpanInfo);   //to get span set info
1022*665484d8SDoug Ambrisko #endif
1023*665484d8SDoug Ambrisko }
1024*665484d8SDoug Ambrisko 
1025*665484d8SDoug Ambrisko /**
1026*665484d8SDoug Ambrisko  * mrsas_update_load_balance_params:  Update load balance parmas
1027*665484d8SDoug Ambrisko  * Inputs:                         map pointer
1028*665484d8SDoug Ambrisko  *                                 Load balance info
1029*665484d8SDoug Ambrisko  *                                 io_info pointer
1030*665484d8SDoug Ambrisko  *
1031*665484d8SDoug Ambrisko  * This function updates the load balance parameters for the LD config
1032*665484d8SDoug Ambrisko  * of a two drive optimal RAID-1.
1033*665484d8SDoug Ambrisko  */
1034*665484d8SDoug Ambrisko void mrsas_update_load_balance_params(MR_FW_RAID_MAP_ALL *map,
1035*665484d8SDoug Ambrisko         PLD_LOAD_BALANCE_INFO lbInfo)
1036*665484d8SDoug Ambrisko {
1037*665484d8SDoug Ambrisko     int ldCount;
1038*665484d8SDoug Ambrisko     u_int16_t ld;
1039*665484d8SDoug Ambrisko     u_int32_t pd, arRef;
1040*665484d8SDoug Ambrisko     MR_LD_RAID *raid;
1041*665484d8SDoug Ambrisko 
1042*665484d8SDoug Ambrisko     for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++)
1043*665484d8SDoug Ambrisko     {
1044*665484d8SDoug Ambrisko         ld = MR_TargetIdToLdGet(ldCount, map);
1045*665484d8SDoug Ambrisko         if (ld >= MAX_LOGICAL_DRIVES) {
1046*665484d8SDoug Ambrisko             lbInfo[ldCount].loadBalanceFlag = 0;
1047*665484d8SDoug Ambrisko             continue;
1048*665484d8SDoug Ambrisko         }
1049*665484d8SDoug Ambrisko 
1050*665484d8SDoug Ambrisko         raid = MR_LdRaidGet(ld, map);
1051*665484d8SDoug Ambrisko 
1052*665484d8SDoug Ambrisko         /* Two drive Optimal RAID 1 */
1053*665484d8SDoug Ambrisko         if ((raid->level == 1) && (raid->rowSize == 2) &&
1054*665484d8SDoug Ambrisko                 (raid->spanDepth == 1)
1055*665484d8SDoug Ambrisko                 && raid->ldState == MR_LD_STATE_OPTIMAL) {
1056*665484d8SDoug Ambrisko             lbInfo[ldCount].loadBalanceFlag = 1;
1057*665484d8SDoug Ambrisko 
1058*665484d8SDoug Ambrisko             /* Get the array on which this span is present */
1059*665484d8SDoug Ambrisko             arRef = MR_LdSpanArrayGet(ld, 0, map);
1060*665484d8SDoug Ambrisko 
1061*665484d8SDoug Ambrisko             /* Get the PD */
1062*665484d8SDoug Ambrisko             pd = MR_ArPdGet(arRef, 0, map);
1063*665484d8SDoug Ambrisko             /* Get dev handle from PD */
1064*665484d8SDoug Ambrisko             lbInfo[ldCount].raid1DevHandle[0] = MR_PdDevHandleGet(pd, map);
1065*665484d8SDoug Ambrisko             pd = MR_ArPdGet(arRef, 1, map);
1066*665484d8SDoug Ambrisko             lbInfo[ldCount].raid1DevHandle[1] = MR_PdDevHandleGet(pd, map);
1067*665484d8SDoug Ambrisko         }
1068*665484d8SDoug Ambrisko         else
1069*665484d8SDoug Ambrisko             lbInfo[ldCount].loadBalanceFlag = 0;
1070*665484d8SDoug Ambrisko     }
1071*665484d8SDoug Ambrisko }
1072*665484d8SDoug Ambrisko 
1073*665484d8SDoug Ambrisko 
1074*665484d8SDoug Ambrisko /**
1075*665484d8SDoug Ambrisko  * mrsas_set_pd_lba:    Sets PD LBA
1076*665484d8SDoug Ambrisko  * input:               io_request pointer
1077*665484d8SDoug Ambrisko  *                      CDB length
1078*665484d8SDoug Ambrisko  *                      io_info pointer
1079*665484d8SDoug Ambrisko  *                      Pointer to CCB
1080*665484d8SDoug Ambrisko  *                      Local RAID map pointer
1081*665484d8SDoug Ambrisko  *                      Start block of IO
1082*665484d8SDoug Ambrisko  *                      Block Size
1083*665484d8SDoug Ambrisko  *
1084*665484d8SDoug Ambrisko  * Used to set the PD logical block address in CDB for FP IOs.
1085*665484d8SDoug Ambrisko  */
1086*665484d8SDoug Ambrisko void mrsas_set_pd_lba(MRSAS_RAID_SCSI_IO_REQUEST *io_request, u_int8_t cdb_len,
1087*665484d8SDoug Ambrisko     struct IO_REQUEST_INFO *io_info, union ccb *ccb,
1088*665484d8SDoug Ambrisko     MR_FW_RAID_MAP_ALL *local_map_ptr, u_int32_t ref_tag,
1089*665484d8SDoug Ambrisko     u_int32_t ld_block_size)
1090*665484d8SDoug Ambrisko {
1091*665484d8SDoug Ambrisko     MR_LD_RAID *raid;
1092*665484d8SDoug Ambrisko     u_int32_t ld;
1093*665484d8SDoug Ambrisko     u_int64_t start_blk = io_info->pdBlock;
1094*665484d8SDoug Ambrisko     u_int8_t *cdb = io_request->CDB.CDB32;
1095*665484d8SDoug Ambrisko     u_int32_t num_blocks = io_info->numBlocks;
1096*665484d8SDoug Ambrisko     u_int8_t opcode = 0, flagvals = 0, groupnum = 0, control = 0;
1097*665484d8SDoug Ambrisko     struct ccb_hdr *ccb_h = &(ccb->ccb_h);
1098*665484d8SDoug Ambrisko 
1099*665484d8SDoug Ambrisko     /* Check if T10 PI (DIF) is enabled for this LD */
1100*665484d8SDoug Ambrisko     ld = MR_TargetIdToLdGet(io_info->ldTgtId, local_map_ptr);
1101*665484d8SDoug Ambrisko     raid = MR_LdRaidGet(ld, local_map_ptr);
1102*665484d8SDoug Ambrisko     if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER) {
1103*665484d8SDoug Ambrisko         memset(cdb, 0, sizeof(io_request->CDB.CDB32));
1104*665484d8SDoug Ambrisko         cdb[0] =  MRSAS_SCSI_VARIABLE_LENGTH_CMD;
1105*665484d8SDoug Ambrisko         cdb[7] =  MRSAS_SCSI_ADDL_CDB_LEN;
1106*665484d8SDoug Ambrisko 
1107*665484d8SDoug Ambrisko         if (ccb_h->flags == CAM_DIR_OUT)
1108*665484d8SDoug Ambrisko             cdb[9] = MRSAS_SCSI_SERVICE_ACTION_READ32;
1109*665484d8SDoug Ambrisko         else
1110*665484d8SDoug Ambrisko             cdb[9] = MRSAS_SCSI_SERVICE_ACTION_WRITE32;
1111*665484d8SDoug Ambrisko         cdb[10] = MRSAS_RD_WR_PROTECT_CHECK_ALL;
1112*665484d8SDoug Ambrisko 
1113*665484d8SDoug Ambrisko         /* LBA */
1114*665484d8SDoug Ambrisko         cdb[12] = (u_int8_t)((start_blk >> 56) & 0xff);
1115*665484d8SDoug Ambrisko         cdb[13] = (u_int8_t)((start_blk >> 48) & 0xff);
1116*665484d8SDoug Ambrisko         cdb[14] = (u_int8_t)((start_blk >> 40) & 0xff);
1117*665484d8SDoug Ambrisko         cdb[15] = (u_int8_t)((start_blk >> 32) & 0xff);
1118*665484d8SDoug Ambrisko         cdb[16] = (u_int8_t)((start_blk >> 24) & 0xff);
1119*665484d8SDoug Ambrisko         cdb[17] = (u_int8_t)((start_blk >> 16) & 0xff);
1120*665484d8SDoug Ambrisko         cdb[18] = (u_int8_t)((start_blk >> 8) & 0xff);
1121*665484d8SDoug Ambrisko         cdb[19] = (u_int8_t)(start_blk & 0xff);
1122*665484d8SDoug Ambrisko 
1123*665484d8SDoug Ambrisko         /* Logical block reference tag */
1124*665484d8SDoug Ambrisko         io_request->CDB.EEDP32.PrimaryReferenceTag = swap32(ref_tag);
1125*665484d8SDoug Ambrisko         io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0xffff;
1126*665484d8SDoug Ambrisko         io_request->IoFlags = 32; /* Specify 32-byte cdb */
1127*665484d8SDoug Ambrisko 
1128*665484d8SDoug Ambrisko         /* Transfer length */
1129*665484d8SDoug Ambrisko         cdb[28] = (u_int8_t)((num_blocks >> 24) & 0xff);
1130*665484d8SDoug Ambrisko         cdb[29] = (u_int8_t)((num_blocks >> 16) & 0xff);
1131*665484d8SDoug Ambrisko         cdb[30] = (u_int8_t)((num_blocks >> 8) & 0xff);
1132*665484d8SDoug Ambrisko         cdb[31] = (u_int8_t)(num_blocks & 0xff);
1133*665484d8SDoug Ambrisko 
1134*665484d8SDoug Ambrisko         /* set SCSI IO EEDP Flags */
1135*665484d8SDoug Ambrisko         if (ccb_h->flags == CAM_DIR_OUT) {
1136*665484d8SDoug Ambrisko             io_request->EEDPFlags =
1137*665484d8SDoug Ambrisko                 MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG  |
1138*665484d8SDoug Ambrisko                 MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
1139*665484d8SDoug Ambrisko                 MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP |
1140*665484d8SDoug Ambrisko                 MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG |
1141*665484d8SDoug Ambrisko                 MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
1142*665484d8SDoug Ambrisko         }
1143*665484d8SDoug Ambrisko         else {
1144*665484d8SDoug Ambrisko                 io_request->EEDPFlags =
1145*665484d8SDoug Ambrisko                      MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
1146*665484d8SDoug Ambrisko                      MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
1147*665484d8SDoug Ambrisko         }
1148*665484d8SDoug Ambrisko         io_request->Control |= (0x4 << 26);
1149*665484d8SDoug Ambrisko         io_request->EEDPBlockSize = ld_block_size;
1150*665484d8SDoug Ambrisko     }
1151*665484d8SDoug Ambrisko     else {
1152*665484d8SDoug Ambrisko         /* Some drives don't support 16/12 byte CDB's, convert to 10 */
1153*665484d8SDoug Ambrisko         if (((cdb_len == 12) || (cdb_len == 16)) &&
1154*665484d8SDoug Ambrisko                     (start_blk <= 0xffffffff)) {
1155*665484d8SDoug Ambrisko             if (cdb_len == 16) {
1156*665484d8SDoug Ambrisko                 opcode = cdb[0] == READ_16 ? READ_10 : WRITE_10;
1157*665484d8SDoug Ambrisko                 flagvals = cdb[1];
1158*665484d8SDoug Ambrisko                 groupnum = cdb[14];
1159*665484d8SDoug Ambrisko                 control = cdb[15];
1160*665484d8SDoug Ambrisko             }
1161*665484d8SDoug Ambrisko             else {
1162*665484d8SDoug Ambrisko                 opcode = cdb[0] == READ_12 ? READ_10 : WRITE_10;
1163*665484d8SDoug Ambrisko                 flagvals = cdb[1];
1164*665484d8SDoug Ambrisko                 groupnum = cdb[10];
1165*665484d8SDoug Ambrisko                 control = cdb[11];
1166*665484d8SDoug Ambrisko             }
1167*665484d8SDoug Ambrisko 
1168*665484d8SDoug Ambrisko             memset(cdb, 0, sizeof(io_request->CDB.CDB32));
1169*665484d8SDoug Ambrisko 
1170*665484d8SDoug Ambrisko             cdb[0] = opcode;
1171*665484d8SDoug Ambrisko             cdb[1] = flagvals;
1172*665484d8SDoug Ambrisko             cdb[6] = groupnum;
1173*665484d8SDoug Ambrisko             cdb[9] = control;
1174*665484d8SDoug Ambrisko 
1175*665484d8SDoug Ambrisko             /* Transfer length */
1176*665484d8SDoug Ambrisko             cdb[8] = (u_int8_t)(num_blocks & 0xff);
1177*665484d8SDoug Ambrisko             cdb[7] = (u_int8_t)((num_blocks >> 8) & 0xff);
1178*665484d8SDoug Ambrisko 
1179*665484d8SDoug Ambrisko             io_request->IoFlags = 10; /* Specify 10-byte cdb */
1180*665484d8SDoug Ambrisko             cdb_len = 10;
1181*665484d8SDoug Ambrisko         } else if ((cdb_len < 16) && (start_blk > 0xffffffff)) {
1182*665484d8SDoug Ambrisko             /* Convert to 16 byte CDB for large LBA's */
1183*665484d8SDoug Ambrisko             switch (cdb_len) {
1184*665484d8SDoug Ambrisko                 case 6:
1185*665484d8SDoug Ambrisko                     opcode = cdb[0] == READ_6 ? READ_16 : WRITE_16;
1186*665484d8SDoug Ambrisko                     control = cdb[5];
1187*665484d8SDoug Ambrisko                     break;
1188*665484d8SDoug Ambrisko                 case 10:
1189*665484d8SDoug Ambrisko                     opcode = cdb[0] == READ_10 ? READ_16 : WRITE_16;
1190*665484d8SDoug Ambrisko                     flagvals = cdb[1];
1191*665484d8SDoug Ambrisko                     groupnum = cdb[6];
1192*665484d8SDoug Ambrisko                     control = cdb[9];
1193*665484d8SDoug Ambrisko                     break;
1194*665484d8SDoug Ambrisko                 case 12:
1195*665484d8SDoug Ambrisko                     opcode = cdb[0] == READ_12 ? READ_16 : WRITE_16;
1196*665484d8SDoug Ambrisko                     flagvals = cdb[1];
1197*665484d8SDoug Ambrisko                     groupnum = cdb[10];
1198*665484d8SDoug Ambrisko                     control = cdb[11];
1199*665484d8SDoug Ambrisko                     break;
1200*665484d8SDoug Ambrisko             }
1201*665484d8SDoug Ambrisko 
1202*665484d8SDoug Ambrisko             memset(cdb, 0, sizeof(io_request->CDB.CDB32));
1203*665484d8SDoug Ambrisko 
1204*665484d8SDoug Ambrisko             cdb[0] = opcode;
1205*665484d8SDoug Ambrisko             cdb[1] = flagvals;
1206*665484d8SDoug Ambrisko             cdb[14] = groupnum;
1207*665484d8SDoug Ambrisko             cdb[15] = control;
1208*665484d8SDoug Ambrisko 
1209*665484d8SDoug Ambrisko             /* Transfer length */
1210*665484d8SDoug Ambrisko             cdb[13] = (u_int8_t)(num_blocks & 0xff);
1211*665484d8SDoug Ambrisko             cdb[12] = (u_int8_t)((num_blocks >> 8) & 0xff);
1212*665484d8SDoug Ambrisko             cdb[11] = (u_int8_t)((num_blocks >> 16) & 0xff);
1213*665484d8SDoug Ambrisko             cdb[10] = (u_int8_t)((num_blocks >> 24) & 0xff);
1214*665484d8SDoug Ambrisko 
1215*665484d8SDoug Ambrisko             io_request->IoFlags = 16; /* Specify 16-byte cdb */
1216*665484d8SDoug Ambrisko             cdb_len = 16;
1217*665484d8SDoug Ambrisko         } else if ((cdb_len == 6) && (start_blk > 0x1fffff)) {
1218*665484d8SDoug Ambrisko             /* convert to 10 byte CDB */
1219*665484d8SDoug Ambrisko 	    opcode = cdb[0] == READ_6 ? READ_10 : WRITE_10;
1220*665484d8SDoug Ambrisko 	    control = cdb[5];
1221*665484d8SDoug Ambrisko 
1222*665484d8SDoug Ambrisko 	    memset(cdb, 0, sizeof(cdb));
1223*665484d8SDoug Ambrisko 	    cdb[0] = opcode;
1224*665484d8SDoug Ambrisko 	    cdb[9] = control;
1225*665484d8SDoug Ambrisko 
1226*665484d8SDoug Ambrisko 	    /* Set transfer length */
1227*665484d8SDoug Ambrisko 	    cdb[8] = (u_int8_t)(num_blocks & 0xff);
1228*665484d8SDoug Ambrisko 	    cdb[7] = (u_int8_t)((num_blocks >> 8) & 0xff);
1229*665484d8SDoug Ambrisko 
1230*665484d8SDoug Ambrisko 	    /* Specify 10-byte cdb */
1231*665484d8SDoug Ambrisko 	    cdb_len = 10;
1232*665484d8SDoug Ambrisko 	}
1233*665484d8SDoug Ambrisko 
1234*665484d8SDoug Ambrisko         /* Fall through normal case, just load LBA here */
1235*665484d8SDoug Ambrisko         switch (cdb_len)
1236*665484d8SDoug Ambrisko         {
1237*665484d8SDoug Ambrisko             case 6:
1238*665484d8SDoug Ambrisko             {
1239*665484d8SDoug Ambrisko                 u_int8_t val = cdb[1] & 0xE0;
1240*665484d8SDoug Ambrisko                 cdb[3] = (u_int8_t)(start_blk & 0xff);
1241*665484d8SDoug Ambrisko                 cdb[2] = (u_int8_t)((start_blk >> 8) & 0xff);
1242*665484d8SDoug Ambrisko                 cdb[1] = val | ((u_int8_t)(start_blk >> 16) & 0x1f);
1243*665484d8SDoug Ambrisko                 break;
1244*665484d8SDoug Ambrisko             }
1245*665484d8SDoug Ambrisko             case 10:
1246*665484d8SDoug Ambrisko                 cdb[5] = (u_int8_t)(start_blk & 0xff);
1247*665484d8SDoug Ambrisko                 cdb[4] = (u_int8_t)((start_blk >> 8) & 0xff);
1248*665484d8SDoug Ambrisko                 cdb[3] = (u_int8_t)((start_blk >> 16) & 0xff);
1249*665484d8SDoug Ambrisko                 cdb[2] = (u_int8_t)((start_blk >> 24) & 0xff);
1250*665484d8SDoug Ambrisko                 break;
1251*665484d8SDoug Ambrisko             case 12:
1252*665484d8SDoug Ambrisko                 cdb[5] = (u_int8_t)(start_blk & 0xff);
1253*665484d8SDoug Ambrisko                 cdb[4] = (u_int8_t)((start_blk >> 8) & 0xff);
1254*665484d8SDoug Ambrisko                 cdb[3] = (u_int8_t)((start_blk >> 16) & 0xff);
1255*665484d8SDoug Ambrisko                 cdb[2] = (u_int8_t)((start_blk >> 24) & 0xff);
1256*665484d8SDoug Ambrisko                 break;
1257*665484d8SDoug Ambrisko             case 16:
1258*665484d8SDoug Ambrisko                 cdb[9] = (u_int8_t)(start_blk & 0xff);
1259*665484d8SDoug Ambrisko                 cdb[8] = (u_int8_t)((start_blk >> 8) & 0xff);
1260*665484d8SDoug Ambrisko                 cdb[7] = (u_int8_t)((start_blk >> 16) & 0xff);
1261*665484d8SDoug Ambrisko                 cdb[6] = (u_int8_t)((start_blk >> 24) & 0xff);
1262*665484d8SDoug Ambrisko                 cdb[5] = (u_int8_t)((start_blk >> 32) & 0xff);
1263*665484d8SDoug Ambrisko                 cdb[4] = (u_int8_t)((start_blk >> 40) & 0xff);
1264*665484d8SDoug Ambrisko                 cdb[3] = (u_int8_t)((start_blk >> 48) & 0xff);
1265*665484d8SDoug Ambrisko                 cdb[2] = (u_int8_t)((start_blk >> 56) & 0xff);
1266*665484d8SDoug Ambrisko                 break;
1267*665484d8SDoug Ambrisko         }
1268*665484d8SDoug Ambrisko     }
1269*665484d8SDoug Ambrisko }
1270*665484d8SDoug Ambrisko 
1271*665484d8SDoug Ambrisko /**
1272*665484d8SDoug Ambrisko  * mrsas_get_best_arm         Determine the best spindle arm
1273*665484d8SDoug Ambrisko  * Inputs:                    Load balance info
1274*665484d8SDoug Ambrisko  *
1275*665484d8SDoug Ambrisko  * This function determines and returns the best arm by looking at the
1276*665484d8SDoug Ambrisko  * parameters of the last PD access.
1277*665484d8SDoug Ambrisko  */
1278*665484d8SDoug Ambrisko u_int8_t mrsas_get_best_arm(PLD_LOAD_BALANCE_INFO lbInfo, u_int8_t arm,
1279*665484d8SDoug Ambrisko         u_int64_t block, u_int32_t count)
1280*665484d8SDoug Ambrisko {
1281*665484d8SDoug Ambrisko     u_int16_t     pend0, pend1;
1282*665484d8SDoug Ambrisko     u_int64_t     diff0, diff1;
1283*665484d8SDoug Ambrisko     u_int8_t      bestArm;
1284*665484d8SDoug Ambrisko 
1285*665484d8SDoug Ambrisko     /* get the pending cmds for the data and mirror arms */
1286*665484d8SDoug Ambrisko     pend0 = atomic_read(&lbInfo->scsi_pending_cmds[0]);
1287*665484d8SDoug Ambrisko     pend1 = atomic_read(&lbInfo->scsi_pending_cmds[1]);
1288*665484d8SDoug Ambrisko 
1289*665484d8SDoug Ambrisko     /* Determine the disk whose head is nearer to the req. block */
1290*665484d8SDoug Ambrisko     diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[0]);
1291*665484d8SDoug Ambrisko     diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[1]);
1292*665484d8SDoug Ambrisko     bestArm = (diff0 <= diff1 ? 0 : 1);
1293*665484d8SDoug Ambrisko 
1294*665484d8SDoug Ambrisko     if ((bestArm == arm && pend0 > pend1 + 16) || (bestArm != arm && pend1 > pend0 + 16))
1295*665484d8SDoug Ambrisko         bestArm ^= 1;
1296*665484d8SDoug Ambrisko 
1297*665484d8SDoug Ambrisko     /* Update the last accessed block on the correct pd */
1298*665484d8SDoug Ambrisko     lbInfo->last_accessed_block[bestArm] = block + count - 1;
1299*665484d8SDoug Ambrisko 
1300*665484d8SDoug Ambrisko     return bestArm;
1301*665484d8SDoug Ambrisko }
1302*665484d8SDoug Ambrisko 
1303*665484d8SDoug Ambrisko /**
1304*665484d8SDoug Ambrisko  * mrsas_get_updated_dev_handle    Get the update dev handle
1305*665484d8SDoug Ambrisko  * Inputs:                         Load balance info
1306*665484d8SDoug Ambrisko  *                                 io_info pointer
1307*665484d8SDoug Ambrisko  *
1308*665484d8SDoug Ambrisko  * This function determines and returns the updated dev handle.
1309*665484d8SDoug Ambrisko  */
1310*665484d8SDoug Ambrisko u_int16_t mrsas_get_updated_dev_handle(PLD_LOAD_BALANCE_INFO lbInfo,
1311*665484d8SDoug Ambrisko         struct IO_REQUEST_INFO *io_info)
1312*665484d8SDoug Ambrisko {
1313*665484d8SDoug Ambrisko     u_int8_t arm, old_arm;
1314*665484d8SDoug Ambrisko     u_int16_t devHandle;
1315*665484d8SDoug Ambrisko 
1316*665484d8SDoug Ambrisko     old_arm = lbInfo->raid1DevHandle[0] == io_info->devHandle ? 0 : 1;
1317*665484d8SDoug Ambrisko 
1318*665484d8SDoug Ambrisko     /* get best new arm */
1319*665484d8SDoug Ambrisko     arm  = mrsas_get_best_arm(lbInfo, old_arm, io_info->ldStartBlock, io_info->numBlocks);
1320*665484d8SDoug Ambrisko     devHandle = lbInfo->raid1DevHandle[arm];
1321*665484d8SDoug Ambrisko     atomic_inc(&lbInfo->scsi_pending_cmds[arm]);
1322*665484d8SDoug Ambrisko 
1323*665484d8SDoug Ambrisko     return devHandle;
1324*665484d8SDoug Ambrisko }
1325*665484d8SDoug Ambrisko 
1326*665484d8SDoug Ambrisko /**
1327*665484d8SDoug Ambrisko  * MR_GetPhyParams     Calculates arm, span, and block
1328*665484d8SDoug Ambrisko  * Inputs:             Adapter instance soft state
1329*665484d8SDoug Ambrisko  *                     Logical drive number (LD)
1330*665484d8SDoug Ambrisko  *                     Stripe number (stripRow)
1331*665484d8SDoug Ambrisko  *                     Reference in stripe (stripRef)
1332*665484d8SDoug Ambrisko  * Outputs:            Span number
1333*665484d8SDoug Ambrisko  *                     Absolute Block number in the physical disk
1334*665484d8SDoug Ambrisko  *
1335*665484d8SDoug Ambrisko  * This routine calculates the arm, span and block for the specified stripe
1336*665484d8SDoug Ambrisko  * and reference in stripe.
1337*665484d8SDoug Ambrisko  */
1338*665484d8SDoug Ambrisko u_int8_t MR_GetPhyParams(struct mrsas_softc *sc, u_int32_t ld,
1339*665484d8SDoug Ambrisko             u_int64_t stripRow,
1340*665484d8SDoug Ambrisko             u_int16_t stripRef, struct IO_REQUEST_INFO *io_info,
1341*665484d8SDoug Ambrisko             RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map)
1342*665484d8SDoug Ambrisko {
1343*665484d8SDoug Ambrisko     MR_LD_RAID  *raid = MR_LdRaidGet(ld, map);
1344*665484d8SDoug Ambrisko     u_int32_t pd, arRef;
1345*665484d8SDoug Ambrisko     u_int8_t physArm, span;
1346*665484d8SDoug Ambrisko     u_int64_t row;
1347*665484d8SDoug Ambrisko     u_int8_t retval = TRUE;
1348*665484d8SDoug Ambrisko     int error_code = 0;
1349*665484d8SDoug Ambrisko 	u_int64_t *pdBlock = &io_info->pdBlock;
1350*665484d8SDoug Ambrisko     u_int16_t *pDevHandle = &io_info->devHandle;
1351*665484d8SDoug Ambrisko     u_int32_t rowMod, armQ, arm, logArm;
1352*665484d8SDoug Ambrisko 	u_int8_t do_invader = 0;
1353*665484d8SDoug Ambrisko 
1354*665484d8SDoug Ambrisko 	if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY))
1355*665484d8SDoug Ambrisko 		do_invader = 1;
1356*665484d8SDoug Ambrisko 
1357*665484d8SDoug Ambrisko     row =  mega_div64_32(stripRow, raid->rowDataSize);
1358*665484d8SDoug Ambrisko 
1359*665484d8SDoug Ambrisko     if (raid->level == 6) {
1360*665484d8SDoug Ambrisko         logArm = mega_mod64(stripRow, raid->rowDataSize); // logical arm within row
1361*665484d8SDoug Ambrisko         if (raid->rowSize == 0)
1362*665484d8SDoug Ambrisko             return FALSE;
1363*665484d8SDoug Ambrisko         rowMod = mega_mod64(row, raid->rowSize);  // get logical row mod
1364*665484d8SDoug Ambrisko         armQ = raid->rowSize-1-rowMod;  // index of Q drive
1365*665484d8SDoug Ambrisko         arm = armQ+1+logArm;    // data always logically follows Q
1366*665484d8SDoug Ambrisko         if (arm >= raid->rowSize)         // handle wrap condition
1367*665484d8SDoug Ambrisko             arm -= raid->rowSize;
1368*665484d8SDoug Ambrisko         physArm = (u_int8_t)arm;
1369*665484d8SDoug Ambrisko     }
1370*665484d8SDoug Ambrisko     else {
1371*665484d8SDoug Ambrisko         if (raid->modFactor == 0)
1372*665484d8SDoug Ambrisko             return FALSE;
1373*665484d8SDoug Ambrisko         physArm = MR_LdDataArmGet(ld, mega_mod64(stripRow, raid->modFactor), map);
1374*665484d8SDoug Ambrisko     }
1375*665484d8SDoug Ambrisko 
1376*665484d8SDoug Ambrisko     if (raid->spanDepth == 1) {
1377*665484d8SDoug Ambrisko         span = 0;
1378*665484d8SDoug Ambrisko         *pdBlock = row << raid->stripeShift;
1379*665484d8SDoug Ambrisko     }
1380*665484d8SDoug Ambrisko     else {
1381*665484d8SDoug Ambrisko         span = (u_int8_t)MR_GetSpanBlock(ld, row, pdBlock, map, &error_code);
1382*665484d8SDoug Ambrisko         if (error_code == 1)
1383*665484d8SDoug Ambrisko             return FALSE;
1384*665484d8SDoug Ambrisko     }
1385*665484d8SDoug Ambrisko 
1386*665484d8SDoug Ambrisko     /*  Get the array on which this span is present */
1387*665484d8SDoug Ambrisko     arRef = MR_LdSpanArrayGet(ld, span, map);
1388*665484d8SDoug Ambrisko 
1389*665484d8SDoug Ambrisko     pd = MR_ArPdGet(arRef, physArm, map);     // Get the Pd.
1390*665484d8SDoug Ambrisko 
1391*665484d8SDoug Ambrisko     if (pd != MR_PD_INVALID)
1392*665484d8SDoug Ambrisko         *pDevHandle = MR_PdDevHandleGet(pd, map);  // Get dev handle from Pd.
1393*665484d8SDoug Ambrisko     else {
1394*665484d8SDoug Ambrisko         *pDevHandle = MR_PD_INVALID; // set dev handle as invalid.
1395*665484d8SDoug Ambrisko         if ((raid->level >= 5) && ((!do_invader) || (do_invader &&
1396*665484d8SDoug Ambrisko              raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))
1397*665484d8SDoug Ambrisko              pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
1398*665484d8SDoug Ambrisko         else if (raid->level == 1) {
1399*665484d8SDoug Ambrisko             pd = MR_ArPdGet(arRef, physArm + 1, map); // Get Alternate Pd.
1400*665484d8SDoug Ambrisko             if (pd != MR_PD_INVALID)
1401*665484d8SDoug Ambrisko                 *pDevHandle = MR_PdDevHandleGet(pd, map);//Get dev handle from Pd.
1402*665484d8SDoug Ambrisko         }
1403*665484d8SDoug Ambrisko     }
1404*665484d8SDoug Ambrisko 
1405*665484d8SDoug Ambrisko     *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk;
1406*665484d8SDoug Ambrisko     pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm;
1407*665484d8SDoug Ambrisko     return retval;
1408*665484d8SDoug Ambrisko }
1409*665484d8SDoug Ambrisko 
1410*665484d8SDoug Ambrisko /**
1411*665484d8SDoug Ambrisko  * MR_GetSpanBlock     Calculates span block
1412*665484d8SDoug Ambrisko  * Inputs:             LD
1413*665484d8SDoug Ambrisko  *                     row
1414*665484d8SDoug Ambrisko  *                     PD span block
1415*665484d8SDoug Ambrisko  *                     RAID map pointer
1416*665484d8SDoug Ambrisko  * Outputs:            Span number
1417*665484d8SDoug Ambrisko  *                     Error code
1418*665484d8SDoug Ambrisko  *
1419*665484d8SDoug Ambrisko  * This routine calculates the span from the span block info.
1420*665484d8SDoug Ambrisko  */
1421*665484d8SDoug Ambrisko u_int32_t MR_GetSpanBlock(u_int32_t ld, u_int64_t row, u_int64_t *span_blk,
1422*665484d8SDoug Ambrisko         MR_FW_RAID_MAP_ALL *map, int *div_error)
1423*665484d8SDoug Ambrisko {
1424*665484d8SDoug Ambrisko     MR_SPAN_BLOCK_INFO *pSpanBlock = MR_LdSpanInfoGet(ld, map);
1425*665484d8SDoug Ambrisko     MR_QUAD_ELEMENT *quad;
1426*665484d8SDoug Ambrisko     MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
1427*665484d8SDoug Ambrisko     u_int32_t span, j;
1428*665484d8SDoug Ambrisko     u_int64_t blk, debugBlk;
1429*665484d8SDoug Ambrisko 
1430*665484d8SDoug Ambrisko     for (span=0; span < raid->spanDepth; span++, pSpanBlock++) {
1431*665484d8SDoug Ambrisko         for (j=0; j < pSpanBlock->block_span_info.noElements; j++) {
1432*665484d8SDoug Ambrisko             quad = &pSpanBlock->block_span_info.quad[j];
1433*665484d8SDoug Ambrisko             if (quad->diff == 0) {
1434*665484d8SDoug Ambrisko                 *div_error = 1;
1435*665484d8SDoug Ambrisko                 return span;
1436*665484d8SDoug Ambrisko             }
1437*665484d8SDoug Ambrisko             if (quad->logStart <= row  &&  row <= quad->logEnd  &&
1438*665484d8SDoug Ambrisko                     (mega_mod64(row-quad->logStart, quad->diff)) == 0) {
1439*665484d8SDoug Ambrisko                 if (span_blk != NULL) {
1440*665484d8SDoug Ambrisko                     blk =  mega_div64_32((row-quad->logStart), quad->diff);
1441*665484d8SDoug Ambrisko                     debugBlk = blk;
1442*665484d8SDoug Ambrisko                     blk = (blk + quad->offsetInSpan) << raid->stripeShift;
1443*665484d8SDoug Ambrisko                     *span_blk = blk;
1444*665484d8SDoug Ambrisko                 }
1445*665484d8SDoug Ambrisko                 return span;
1446*665484d8SDoug Ambrisko             }
1447*665484d8SDoug Ambrisko         }
1448*665484d8SDoug Ambrisko     }
1449*665484d8SDoug Ambrisko     return span;
1450*665484d8SDoug Ambrisko }
1451*665484d8SDoug Ambrisko 
1452