mrsas_fp.c revision 265555
1265555Sambrisko/*
2265555Sambrisko * Copyright (c) 2014, LSI Corp.
3265555Sambrisko * All rights reserved.
4265555Sambrisko * Author: Marian Choy
5265555Sambrisko * Support: freebsdraid@lsi.com
6265555Sambrisko *
7265555Sambrisko * Redistribution and use in source and binary forms, with or without
8265555Sambrisko * modification, are permitted provided that the following conditions
9265555Sambrisko * are met:
10265555Sambrisko *
11265555Sambrisko * 1. Redistributions of source code must retain the above copyright
12265555Sambrisko *    notice, this list of conditions and the following disclaimer.
13265555Sambrisko * 2. Redistributions in binary form must reproduce the above copyright
14265555Sambrisko *    notice, this list of conditions and the following disclaimer in
15265555Sambrisko *    the documentation and/or other materials provided with the
16265555Sambrisko *    distribution.
17265555Sambrisko * 3. Neither the name of the <ORGANIZATION> nor the names of its
18265555Sambrisko *    contributors may be used to endorse or promote products derived
19265555Sambrisko *    from this software without specific prior written permission.
20265555Sambrisko *
21265555Sambrisko * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22265555Sambrisko * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23265555Sambrisko * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24265555Sambrisko * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25265555Sambrisko * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26265555Sambrisko * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27265555Sambrisko * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28265555Sambrisko * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29265555Sambrisko * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30265555Sambrisko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31265555Sambrisko * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32265555Sambrisko * POSSIBILITY OF SUCH DAMAGE.
33265555Sambrisko *
34265555Sambrisko * The views and conclusions contained in the software and documentation
35265555Sambrisko * are those of the authors and should not be interpreted as representing
36265555Sambrisko * official policies,either expressed or implied, of the FreeBSD Project.
37265555Sambrisko *
38265555Sambrisko * Send feedback to: <megaraidfbsd@lsi.com>
39265555Sambrisko * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
40265555Sambrisko *    ATTN: MegaRaid FreeBSD
41265555Sambrisko *
42265555Sambrisko */
43265555Sambrisko
44265555Sambrisko#include <sys/cdefs.h>
45265555Sambrisko__FBSDID("$FreeBSD: head/sys/dev/mrsas/mrsas_fp.c 265555 2014-05-07 16:16:49Z ambrisko $");
46265555Sambrisko
47265555Sambrisko#include <dev/mrsas/mrsas.h>
48265555Sambrisko
49265555Sambrisko#include <cam/cam.h>
50265555Sambrisko#include <cam/cam_ccb.h>
51265555Sambrisko#include <cam/cam_sim.h>
52265555Sambrisko#include <cam/cam_xpt_sim.h>
53265555Sambrisko#include <cam/cam_debug.h>
54265555Sambrisko#include <cam/cam_periph.h>
55265555Sambrisko#include <cam/cam_xpt_periph.h>
56265555Sambrisko
57265555Sambrisko
58265555Sambrisko/*
59265555Sambrisko * Function prototypes
60265555Sambrisko */
61265555Sambriskou_int8_t MR_ValidateMapInfo(struct mrsas_softc *sc);
62265555Sambriskou_int8_t mrsas_get_best_arm(PLD_LOAD_BALANCE_INFO lbInfo, u_int8_t arm,
63265555Sambrisko       u_int64_t block, u_int32_t count);
64265555Sambriskou_int8_t MR_BuildRaidContext(struct mrsas_softc *sc,
65265555Sambrisko        struct IO_REQUEST_INFO *io_info,
66265555Sambrisko        RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map);
67265555Sambriskou_int8_t MR_GetPhyParams(struct mrsas_softc *sc, u_int32_t ld,
68265555Sambrisko        u_int64_t stripRow, u_int16_t stripRef, struct IO_REQUEST_INFO *io_info,
69265555Sambrisko        RAID_CONTEXT *pRAID_Context,
70265555Sambrisko        MR_FW_RAID_MAP_ALL *map);
71265555Sambriskou_int16_t MR_TargetIdToLdGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map);
72265555Sambriskou_int32_t MR_LdBlockSizeGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map);
73265555Sambriskou_int16_t MR_GetLDTgtId(u_int32_t ld, MR_FW_RAID_MAP_ALL *map);
74265555Sambriskou_int16_t mrsas_get_updated_dev_handle(PLD_LOAD_BALANCE_INFO lbInfo,
75265555Sambrisko        struct IO_REQUEST_INFO *io_info);
76265555Sambriskou_int32_t mega_mod64(u_int64_t dividend, u_int32_t divisor);
77265555Sambriskou_int32_t MR_GetSpanBlock(u_int32_t ld, u_int64_t row, u_int64_t *span_blk,
78265555Sambrisko        MR_FW_RAID_MAP_ALL *map, int *div_error);
79265555Sambriskou_int64_t mega_div64_32(u_int64_t dividend, u_int32_t divisor);
80265555Sambriskovoid mrsas_update_load_balance_params(MR_FW_RAID_MAP_ALL *map,
81265555Sambrisko        PLD_LOAD_BALANCE_INFO lbInfo);
82265555Sambriskovoid mrsas_set_pd_lba(MRSAS_RAID_SCSI_IO_REQUEST *io_request,
83265555Sambrisko        u_int8_t cdb_len, struct IO_REQUEST_INFO *io_info, union ccb *ccb,
84265555Sambrisko        MR_FW_RAID_MAP_ALL *local_map_ptr, u_int32_t ref_tag,
85265555Sambrisko        u_int32_t ld_block_size);
86265555Sambriskostatic u_int16_t MR_LdSpanArrayGet(u_int32_t ld, u_int32_t span,
87265555Sambrisko        MR_FW_RAID_MAP_ALL *map);
88265555Sambriskostatic u_int16_t MR_PdDevHandleGet(u_int32_t pd, MR_FW_RAID_MAP_ALL *map);
89265555Sambriskostatic u_int16_t MR_ArPdGet(u_int32_t ar, u_int32_t arm,
90265555Sambrisko        MR_FW_RAID_MAP_ALL *map);
91265555Sambriskostatic MR_LD_SPAN *MR_LdSpanPtrGet(u_int32_t ld, u_int32_t span,
92265555Sambrisko        MR_FW_RAID_MAP_ALL *map);
93265555Sambriskostatic u_int8_t MR_LdDataArmGet(u_int32_t ld, u_int32_t armIdx,
94265555Sambrisko        MR_FW_RAID_MAP_ALL *map);
95265555Sambriskostatic MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u_int32_t ld,
96265555Sambrisko        MR_FW_RAID_MAP_ALL *map);
97265555SambriskoMR_LD_RAID *MR_LdRaidGet(u_int32_t ld, MR_FW_RAID_MAP_ALL *map);
98265555Sambrisko
99265555Sambrisko/*
100265555Sambrisko * Spanset related function prototypes
101265555Sambrisko * Added for PRL11 configuration (Uneven span support)
102265555Sambrisko */
103265555Sambriskovoid mr_update_span_set(MR_FW_RAID_MAP_ALL *map, PLD_SPAN_INFO ldSpanInfo);
104265555Sambriskostatic u_int8_t mr_spanset_get_phy_params(struct mrsas_softc *sc, u_int32_t ld,
105265555Sambrisko       u_int64_t stripRow, u_int16_t stripRef, struct IO_REQUEST_INFO *io_info,
106265555Sambrisko       RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map);
107265555Sambriskostatic u_int64_t get_row_from_strip(struct mrsas_softc *sc, u_int32_t ld,
108265555Sambrisko       u_int64_t strip, MR_FW_RAID_MAP_ALL *map);
109265555Sambriskostatic u_int32_t mr_spanset_get_span_block(struct mrsas_softc *sc,
110265555Sambrisko       u_int32_t ld, u_int64_t row, u_int64_t *span_blk,
111265555Sambrisko       MR_FW_RAID_MAP_ALL *map, int *div_error);
112265555Sambriskostatic u_int8_t get_arm(struct mrsas_softc *sc, u_int32_t ld, u_int8_t span,
113265555Sambrisko       u_int64_t stripe, MR_FW_RAID_MAP_ALL *map);
114265555Sambrisko
115265555Sambrisko
116265555Sambrisko/*
117265555Sambrisko * Spanset related defines
118265555Sambrisko * Added for PRL11 configuration(Uneven span support)
119265555Sambrisko */
120265555Sambrisko#define SPAN_ROW_SIZE(map, ld, index_) MR_LdSpanPtrGet(ld, index_, map)->spanRowSize
121265555Sambrisko#define SPAN_ROW_DATA_SIZE(map_, ld, index_)   MR_LdSpanPtrGet(ld, index_, map)->spanRowDataSize
122265555Sambrisko#define SPAN_INVALID    0xff
123265555Sambrisko#define SPAN_DEBUG 0
124265555Sambrisko
125265555Sambrisko/*
126265555Sambrisko * Related Defines
127265555Sambrisko */
128265555Sambrisko
129265555Sambriskotypedef u_int64_t  REGION_KEY;
130265555Sambriskotypedef u_int32_t  REGION_LEN;
131265555Sambrisko
132265555Sambrisko#define MR_LD_STATE_OPTIMAL 3
133265555Sambrisko#define FALSE 0
134265555Sambrisko#define TRUE 1
135265555Sambrisko
136265555Sambrisko
137265555Sambrisko/*
138265555Sambrisko * Related Macros
139265555Sambrisko */
140265555Sambrisko
141265555Sambrisko#define ABS_DIFF(a,b)   ( ((a) > (b)) ? ((a) - (b)) : ((b) - (a)) )
142265555Sambrisko
143265555Sambrisko#define swap32(x) \
144265555Sambrisko  ((unsigned int)( \
145265555Sambrisko    (((unsigned int)(x) & (unsigned int)0x000000ffUL) << 24) | \
146265555Sambrisko    (((unsigned int)(x) & (unsigned int)0x0000ff00UL) <<  8) | \
147265555Sambrisko    (((unsigned int)(x) & (unsigned int)0x00ff0000UL) >>  8) | \
148265555Sambrisko    (((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24) ))
149265555Sambrisko
150265555Sambrisko
151265555Sambrisko/*
152265555Sambrisko * In-line functions for mod and divide of 64-bit dividend and 32-bit divisor.
153265555Sambrisko * Assumes a check for a divisor of zero is not possible.
154265555Sambrisko *
155265555Sambrisko * @param dividend   : Dividend
156265555Sambrisko * @param divisor    : Divisor
157265555Sambrisko * @return remainder
158265555Sambrisko */
159265555Sambrisko
160265555Sambrisko#define mega_mod64(dividend, divisor) ({ \
161265555Sambriskoint remainder; \
162265555Sambriskoremainder = ((u_int64_t) (dividend)) % (u_int32_t) (divisor); \
163265555Sambriskoremainder;})
164265555Sambrisko
165265555Sambrisko#define mega_div64_32(dividend, divisor) ({ \
166265555Sambriskoint quotient; \
167265555Sambriskoquotient = ((u_int64_t) (dividend)) / (u_int32_t) (divisor); \
168265555Sambriskoquotient;})
169265555Sambrisko
170265555Sambrisko
171265555Sambrisko/*
172265555Sambrisko * Various RAID map access functions.  These functions access the various
173265555Sambrisko * parts of the RAID map and returns the appropriate parameters.
174265555Sambrisko */
175265555Sambrisko
176265555SambriskoMR_LD_RAID *MR_LdRaidGet(u_int32_t ld, MR_FW_RAID_MAP_ALL *map)
177265555Sambrisko{
178265555Sambrisko    return (&map->raidMap.ldSpanMap[ld].ldRaid);
179265555Sambrisko}
180265555Sambrisko
181265555Sambriskou_int16_t MR_GetLDTgtId(u_int32_t ld, MR_FW_RAID_MAP_ALL *map)
182265555Sambrisko{
183265555Sambrisko    return (map->raidMap.ldSpanMap[ld].ldRaid.targetId);
184265555Sambrisko}
185265555Sambrisko
186265555Sambriskostatic u_int16_t MR_LdSpanArrayGet(u_int32_t ld, u_int32_t span, MR_FW_RAID_MAP_ALL *map)
187265555Sambrisko{
188265555Sambrisko    return map->raidMap.ldSpanMap[ld].spanBlock[span].span.arrayRef;
189265555Sambrisko}
190265555Sambrisko
191265555Sambriskostatic u_int8_t MR_LdDataArmGet(u_int32_t ld, u_int32_t armIdx, MR_FW_RAID_MAP_ALL *map)
192265555Sambrisko{
193265555Sambrisko    return map->raidMap.ldSpanMap[ld].dataArmMap[armIdx];
194265555Sambrisko}
195265555Sambrisko
196265555Sambriskostatic u_int16_t MR_PdDevHandleGet(u_int32_t pd, MR_FW_RAID_MAP_ALL *map)
197265555Sambrisko{
198265555Sambrisko    return map->raidMap.devHndlInfo[pd].curDevHdl;
199265555Sambrisko}
200265555Sambrisko
201265555Sambriskostatic u_int16_t MR_ArPdGet(u_int32_t ar, u_int32_t arm, MR_FW_RAID_MAP_ALL *map)
202265555Sambrisko{
203265555Sambrisko    return map->raidMap.arMapInfo[ar].pd[arm];
204265555Sambrisko}
205265555Sambrisko
206265555Sambriskostatic MR_LD_SPAN *MR_LdSpanPtrGet(u_int32_t ld, u_int32_t span, MR_FW_RAID_MAP_ALL *map)
207265555Sambrisko{
208265555Sambrisko    return &map->raidMap.ldSpanMap[ld].spanBlock[span].span;
209265555Sambrisko}
210265555Sambrisko
211265555Sambriskostatic MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u_int32_t ld, MR_FW_RAID_MAP_ALL *map)
212265555Sambrisko{
213265555Sambrisko    return &map->raidMap.ldSpanMap[ld].spanBlock[0];
214265555Sambrisko}
215265555Sambrisko
216265555Sambriskou_int16_t MR_TargetIdToLdGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map)
217265555Sambrisko{
218265555Sambrisko    return map->raidMap.ldTgtIdToLd[ldTgtId];
219265555Sambrisko}
220265555Sambrisko
221265555Sambriskou_int32_t MR_LdBlockSizeGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map)
222265555Sambrisko{
223265555Sambrisko    MR_LD_RAID *raid;
224265555Sambrisko    u_int32_t ld, ldBlockSize = MRSAS_SCSIBLOCKSIZE;
225265555Sambrisko
226265555Sambrisko    ld = MR_TargetIdToLdGet(ldTgtId, map);
227265555Sambrisko
228265555Sambrisko    /*
229265555Sambrisko     * Check if logical drive was removed.
230265555Sambrisko     */
231265555Sambrisko    if (ld >= MAX_LOGICAL_DRIVES)
232265555Sambrisko        return ldBlockSize;
233265555Sambrisko
234265555Sambrisko    raid = MR_LdRaidGet(ld, map);
235265555Sambrisko    ldBlockSize = raid->logicalBlockLength;
236265555Sambrisko    if (!ldBlockSize)
237265555Sambrisko        ldBlockSize = MRSAS_SCSIBLOCKSIZE;
238265555Sambrisko
239265555Sambrisko    return ldBlockSize;
240265555Sambrisko}
241265555Sambrisko
242265555Sambrisko/**
243265555Sambrisko * MR_ValidateMapInfo:        Validate RAID map
244265555Sambrisko * input:                     Adapter instance soft state
245265555Sambrisko *
246265555Sambrisko * This function checks and validates the loaded RAID map. It returns 0 if
247265555Sambrisko * successful, and 1 otherwise.
248265555Sambrisko */
249265555Sambriskou_int8_t MR_ValidateMapInfo(struct mrsas_softc *sc)
250265555Sambrisko{
251265555Sambrisko	if (!sc) {
252265555Sambrisko		return 1;
253265555Sambrisko	}
254265555Sambrisko    uint32_t total_map_sz;
255265555Sambrisko    MR_FW_RAID_MAP_ALL *map = sc->raidmap_mem[(sc->map_id & 1)];
256265555Sambrisko    MR_FW_RAID_MAP *pFwRaidMap = &map->raidMap;
257265555Sambrisko    PLD_SPAN_INFO ldSpanInfo = (PLD_SPAN_INFO) &sc->log_to_span;
258265555Sambrisko
259265555Sambrisko    total_map_sz = (sizeof(MR_FW_RAID_MAP) - sizeof(MR_LD_SPAN_MAP) +
260265555Sambrisko                     (sizeof(MR_LD_SPAN_MAP) * pFwRaidMap->ldCount));
261265555Sambrisko
262265555Sambrisko    if (pFwRaidMap->totalSize != total_map_sz) {
263265555Sambrisko        device_printf(sc->mrsas_dev, "map size %x not matching ld count\n", total_map_sz);
264265555Sambrisko        device_printf(sc->mrsas_dev, "span map= %x\n", (unsigned int)sizeof(MR_LD_SPAN_MAP));
265265555Sambrisko        device_printf(sc->mrsas_dev, "pFwRaidMap->totalSize=%x\n", pFwRaidMap->totalSize);
266265555Sambrisko        return 1;
267265555Sambrisko    }
268265555Sambrisko
269265555Sambrisko    if (sc->UnevenSpanSupport) {
270265555Sambrisko        mr_update_span_set(map, ldSpanInfo);
271265555Sambrisko	}
272265555Sambrisko
273265555Sambrisko    mrsas_update_load_balance_params(map, sc->load_balance_info);
274265555Sambrisko
275265555Sambrisko    return 0;
276265555Sambrisko}
277265555Sambrisko
278265555Sambrisko/*
279265555Sambrisko * ******************************************************************************
280265555Sambrisko *
281265555Sambrisko *  Function to print info about span set created in driver from FW raid map
282265555Sambrisko *
283265555Sambrisko *  Inputs :
284265555Sambrisko *  map    - LD map
285265555Sambrisko *  ldSpanInfo - ldSpanInfo per HBA instance
286265555Sambrisko *
287265555Sambrisko *
288265555Sambrisko * */
289265555Sambrisko#if SPAN_DEBUG
290265555Sambriskostatic int getSpanInfo(MR_FW_RAID_MAP_ALL *map, PLD_SPAN_INFO ldSpanInfo)
291265555Sambrisko{
292265555Sambrisko
293265555Sambrisko       u_int8_t   span;
294265555Sambrisko       u_int32_t    element;
295265555Sambrisko       MR_LD_RAID *raid;
296265555Sambrisko       LD_SPAN_SET *span_set;
297265555Sambrisko       MR_QUAD_ELEMENT    *quad;
298265555Sambrisko       int ldCount;
299265555Sambrisko       u_int16_t ld;
300265555Sambrisko
301265555Sambrisko       for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++)
302265555Sambrisko       {
303265555Sambrisko               ld = MR_TargetIdToLdGet(ldCount, map);
304265555Sambrisko                       if (ld >= MAX_LOGICAL_DRIVES) {
305265555Sambrisko                       continue;
306265555Sambrisko               }
307265555Sambrisko               raid = MR_LdRaidGet(ld, map);
308265555Sambrisko               printf("LD %x: span_depth=%x\n", ld, raid->spanDepth);
309265555Sambrisko               for (span=0; span<raid->spanDepth; span++)
310265555Sambrisko                       printf("Span=%x, number of quads=%x\n", span,
311265555Sambrisko                       map->raidMap.ldSpanMap[ld].spanBlock[span].
312265555Sambrisko                       block_span_info.noElements);
313265555Sambrisko               for (element=0; element < MAX_QUAD_DEPTH; element++) {
314265555Sambrisko                       span_set = &(ldSpanInfo[ld].span_set[element]);
315265555Sambrisko                       if (span_set->span_row_data_width == 0) break;
316265555Sambrisko
317265555Sambrisko                       printf("  Span Set %x: width=%x, diff=%x\n", element,
318265555Sambrisko                               (unsigned int)span_set->span_row_data_width,
319265555Sambrisko                               (unsigned int)span_set->diff);
320265555Sambrisko                       printf("    logical LBA start=0x%08lx, end=0x%08lx\n",
321265555Sambrisko                               (long unsigned int)span_set->log_start_lba,
322265555Sambrisko                               (long unsigned int)span_set->log_end_lba);
323265555Sambrisko                       printf("       span row start=0x%08lx, end=0x%08lx\n",
324265555Sambrisko                               (long unsigned int)span_set->span_row_start,
325265555Sambrisko                               (long unsigned int)span_set->span_row_end);
326265555Sambrisko                       printf("       data row start=0x%08lx, end=0x%08lx\n",
327265555Sambrisko                               (long unsigned int)span_set->data_row_start,
328265555Sambrisko                               (long unsigned int)span_set->data_row_end);
329265555Sambrisko                       printf("       data strip start=0x%08lx, end=0x%08lx\n",
330265555Sambrisko                               (long unsigned int)span_set->data_strip_start,
331265555Sambrisko                               (long unsigned int)span_set->data_strip_end);
332265555Sambrisko
333265555Sambrisko                       for (span=0; span<raid->spanDepth; span++) {
334265555Sambrisko                               if (map->raidMap.ldSpanMap[ld].spanBlock[span].
335265555Sambrisko                                       block_span_info.noElements >=element+1){
336265555Sambrisko                                       quad = &map->raidMap.ldSpanMap[ld].
337265555Sambrisko                                               spanBlock[span].block_span_info.
338265555Sambrisko                                               quad[element];
339265555Sambrisko                               printf("  Span=%x, Quad=%x, diff=%x\n", span,
340265555Sambrisko                                       element, quad->diff);
341265555Sambrisko                               printf("    offset_in_span=0x%08lx\n",
342265555Sambrisko                                       (long unsigned int)quad->offsetInSpan);
343265555Sambrisko                               printf("     logical start=0x%08lx, end=0x%08lx\n",
344265555Sambrisko                                       (long unsigned int)quad->logStart,
345265555Sambrisko                                       (long unsigned int)quad->logEnd);
346265555Sambrisko                               }
347265555Sambrisko                       }
348265555Sambrisko               }
349265555Sambrisko       }
350265555Sambrisko    return 0;
351265555Sambrisko}
352265555Sambrisko#endif
353265555Sambrisko/*
354265555Sambrisko******************************************************************************
355265555Sambrisko*
356265555Sambrisko* This routine calculates the Span block for given row using spanset.
357265555Sambrisko*
358265555Sambrisko* Inputs :
359265555Sambrisko*    instance - HBA instance
360265555Sambrisko*    ld   - Logical drive number
361265555Sambrisko*    row        - Row number
362265555Sambrisko*    map    - LD map
363265555Sambrisko*
364265555Sambrisko* Outputs :
365265555Sambrisko*
366265555Sambrisko*    span          - Span number
367265555Sambrisko*    block         - Absolute Block number in the physical disk
368265555Sambrisko*    div_error    - Devide error code.
369265555Sambrisko*/
370265555Sambrisko
371265555Sambriskou_int32_t mr_spanset_get_span_block(struct mrsas_softc *sc, u_int32_t ld, u_int64_t row,
372265555Sambrisko               u_int64_t *span_blk, MR_FW_RAID_MAP_ALL *map, int *div_error)
373265555Sambrisko{
374265555Sambrisko       MR_LD_RAID         *raid = MR_LdRaidGet(ld, map);
375265555Sambrisko       LD_SPAN_SET *span_set;
376265555Sambrisko       MR_QUAD_ELEMENT    *quad;
377265555Sambrisko       u_int32_t    span, info;
378265555Sambrisko       PLD_SPAN_INFO ldSpanInfo = sc->log_to_span;
379265555Sambrisko
380265555Sambrisko       for (info=0; info < MAX_QUAD_DEPTH; info++) {
381265555Sambrisko               span_set = &(ldSpanInfo[ld].span_set[info]);
382265555Sambrisko
383265555Sambrisko               if (span_set->span_row_data_width == 0) break;
384265555Sambrisko               if (row > span_set->data_row_end) continue;
385265555Sambrisko
386265555Sambrisko               for (span=0; span<raid->spanDepth; span++)
387265555Sambrisko                       if (map->raidMap.ldSpanMap[ld].spanBlock[span].
388265555Sambrisko                               block_span_info.noElements >= info+1) {
389265555Sambrisko                               quad = &map->raidMap.ldSpanMap[ld].
390265555Sambrisko                                       spanBlock[span].
391265555Sambrisko                                       block_span_info.quad[info];
392265555Sambrisko                               if (quad->diff == 0) {
393265555Sambrisko                                       *div_error = 1;
394265555Sambrisko                                       return span;
395265555Sambrisko                               }
396265555Sambrisko                               if ( quad->logStart <= row  &&
397265555Sambrisko                                       row <= quad->logEnd  &&
398265555Sambrisko                                       (mega_mod64(row - quad->logStart,
399265555Sambrisko                                               quad->diff)) == 0 ) {
400265555Sambrisko                                       if (span_blk != NULL) {
401265555Sambrisko                                              u_int64_t  blk;
402265555Sambrisko                                               blk = mega_div64_32
403265555Sambrisko                                                   ((row - quad->logStart),
404265555Sambrisko                                                   quad->diff);
405265555Sambrisko                                               blk = (blk + quad->offsetInSpan)
406265555Sambrisko                                                        << raid->stripeShift;
407265555Sambrisko                                               *span_blk = blk;
408265555Sambrisko                                       }
409265555Sambrisko                                       return span;
410265555Sambrisko                               }
411265555Sambrisko                       }
412265555Sambrisko       }
413265555Sambrisko       return SPAN_INVALID;
414265555Sambrisko}
415265555Sambrisko
416265555Sambrisko/*
417265555Sambrisko******************************************************************************
418265555Sambrisko*
419265555Sambrisko* This routine calculates the row for given strip using spanset.
420265555Sambrisko*
421265555Sambrisko* Inputs :
422265555Sambrisko*    instance - HBA instance
423265555Sambrisko*    ld   - Logical drive number
424265555Sambrisko*    Strip        - Strip
425265555Sambrisko*    map    - LD map
426265555Sambrisko*
427265555Sambrisko* Outputs :
428265555Sambrisko*
429265555Sambrisko*    row         - row associated with strip
430265555Sambrisko*/
431265555Sambrisko
432265555Sambriskostatic u_int64_t  get_row_from_strip(struct mrsas_softc *sc,
433265555Sambrisko       u_int32_t ld, u_int64_t strip, MR_FW_RAID_MAP_ALL *map)
434265555Sambrisko{
435265555Sambrisko       MR_LD_RAID      *raid = MR_LdRaidGet(ld, map);
436265555Sambrisko       LD_SPAN_SET     *span_set;
437265555Sambrisko       PLD_SPAN_INFO   ldSpanInfo = sc->log_to_span;
438265555Sambrisko       u_int32_t             info, strip_offset, span, span_offset;
439265555Sambrisko       u_int64_t             span_set_Strip, span_set_Row;
440265555Sambrisko
441265555Sambrisko       for (info=0; info < MAX_QUAD_DEPTH; info++) {
442265555Sambrisko               span_set = &(ldSpanInfo[ld].span_set[info]);
443265555Sambrisko
444265555Sambrisko               if (span_set->span_row_data_width == 0) break;
445265555Sambrisko               if (strip > span_set->data_strip_end) continue;
446265555Sambrisko
447265555Sambrisko               span_set_Strip = strip - span_set->data_strip_start;
448265555Sambrisko               strip_offset = mega_mod64(span_set_Strip,
449265555Sambrisko                               span_set->span_row_data_width);
450265555Sambrisko               span_set_Row = mega_div64_32(span_set_Strip,
451265555Sambrisko                               span_set->span_row_data_width) * span_set->diff;
452265555Sambrisko               for (span=0,span_offset=0; span<raid->spanDepth; span++)
453265555Sambrisko                       if (map->raidMap.ldSpanMap[ld].spanBlock[span].
454265555Sambrisko                               block_span_info.noElements >=info+1) {
455265555Sambrisko                               if (strip_offset >=
456265555Sambrisko                                       span_set->strip_offset[span])
457265555Sambrisko                                       span_offset++;
458265555Sambrisko                               else
459265555Sambrisko                                       break;
460265555Sambrisko                       }
461265555Sambrisko               mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : Strip 0x%llx, span_set_Strip 0x%llx, span_set_Row 0x%llx "
462265555Sambrisko                       "data width 0x%llx span offset 0x%llx\n", (unsigned long long)strip,
463265555Sambrisko                       (unsigned long long)span_set_Strip,
464265555Sambrisko                       (unsigned long long)span_set_Row,
465265555Sambrisko                       (unsigned long long)span_set->span_row_data_width, (unsigned long long)span_offset);
466265555Sambrisko               mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : For strip 0x%llx row is 0x%llx\n", (unsigned long long)strip,
467265555Sambrisko                       (unsigned long long) span_set->data_row_start +
468265555Sambrisko                       (unsigned long long) span_set_Row + (span_offset - 1));
469265555Sambrisko               return (span_set->data_row_start + span_set_Row + (span_offset - 1));
470265555Sambrisko       }
471265555Sambrisko       return -1LLU;
472265555Sambrisko}
473265555Sambrisko
474265555Sambrisko
475265555Sambrisko/*
476265555Sambrisko******************************************************************************
477265555Sambrisko*
478265555Sambrisko* This routine calculates the Start Strip for given row using spanset.
479265555Sambrisko*
480265555Sambrisko* Inputs :
481265555Sambrisko*    instance - HBA instance
482265555Sambrisko*    ld   - Logical drive number
483265555Sambrisko*    row        - Row number
484265555Sambrisko*    map    - LD map
485265555Sambrisko*
486265555Sambrisko* Outputs :
487265555Sambrisko*
488265555Sambrisko*    Strip         - Start strip associated with row
489265555Sambrisko*/
490265555Sambrisko
491265555Sambriskostatic u_int64_t get_strip_from_row(struct mrsas_softc *sc,
492265555Sambrisko               u_int32_t ld, u_int64_t row, MR_FW_RAID_MAP_ALL *map)
493265555Sambrisko{
494265555Sambrisko       MR_LD_RAID         *raid = MR_LdRaidGet(ld, map);
495265555Sambrisko       LD_SPAN_SET *span_set;
496265555Sambrisko       MR_QUAD_ELEMENT    *quad;
497265555Sambrisko       PLD_SPAN_INFO ldSpanInfo = sc->log_to_span;
498265555Sambrisko       u_int32_t    span, info;
499265555Sambrisko       u_int64_t  strip;
500265555Sambrisko
501265555Sambrisko       for (info=0; info<MAX_QUAD_DEPTH; info++) {
502265555Sambrisko               span_set = &(ldSpanInfo[ld].span_set[info]);
503265555Sambrisko
504265555Sambrisko               if (span_set->span_row_data_width == 0) break;
505265555Sambrisko               if (row > span_set->data_row_end) continue;
506265555Sambrisko
507265555Sambrisko               for (span=0; span<raid->spanDepth; span++)
508265555Sambrisko                       if (map->raidMap.ldSpanMap[ld].spanBlock[span].
509265555Sambrisko                               block_span_info.noElements >=info+1) {
510265555Sambrisko                               quad = &map->raidMap.ldSpanMap[ld].
511265555Sambrisko                                       spanBlock[span].block_span_info.quad[info];
512265555Sambrisko                               if ( quad->logStart <= row  &&
513265555Sambrisko                                       row <= quad->logEnd  &&
514265555Sambrisko                                       mega_mod64((row - quad->logStart),
515265555Sambrisko                                       quad->diff) == 0 ) {
516265555Sambrisko                                       strip = mega_div64_32
517265555Sambrisko                                               (((row - span_set->data_row_start)
518265555Sambrisko                                                       - quad->logStart),
519265555Sambrisko                                                       quad->diff);
520265555Sambrisko                                       strip *= span_set->span_row_data_width;
521265555Sambrisko                                       strip += span_set->data_strip_start;
522265555Sambrisko                                       strip += span_set->strip_offset[span];
523265555Sambrisko                                       return strip;
524265555Sambrisko                               }
525265555Sambrisko                       }
526265555Sambrisko       }
527265555Sambrisko       mrsas_dprint(sc, MRSAS_PRL11,"LSI Debug - get_strip_from_row: returns invalid "
528265555Sambrisko               "strip for ld=%x, row=%lx\n", ld, (long unsigned int)row);
529265555Sambrisko       return -1;
530265555Sambrisko}
531265555Sambrisko
532265555Sambrisko/*
533265555Sambrisko******************************************************************************
534265555Sambrisko*
535265555Sambrisko* This routine calculates the Physical Arm for given strip using spanset.
536265555Sambrisko*
537265555Sambrisko* Inputs :
538265555Sambrisko*    instance - HBA instance
539265555Sambrisko*    ld   - Logical drive number
540265555Sambrisko*    strip      - Strip
541265555Sambrisko*    map    - LD map
542265555Sambrisko*
543265555Sambrisko* Outputs :
544265555Sambrisko*
545265555Sambrisko*    Phys Arm         - Phys Arm associated with strip
546265555Sambrisko*/
547265555Sambrisko
548265555Sambriskostatic u_int32_t get_arm_from_strip(struct mrsas_softc *sc,
549265555Sambrisko       u_int32_t ld, u_int64_t strip, MR_FW_RAID_MAP_ALL *map)
550265555Sambrisko{
551265555Sambrisko       MR_LD_RAID         *raid = MR_LdRaidGet(ld, map);
552265555Sambrisko       LD_SPAN_SET *span_set;
553265555Sambrisko       PLD_SPAN_INFO ldSpanInfo = sc->log_to_span;
554265555Sambrisko       u_int32_t    info, strip_offset, span, span_offset;
555265555Sambrisko
556265555Sambrisko       for (info=0; info<MAX_QUAD_DEPTH; info++) {
557265555Sambrisko               span_set = &(ldSpanInfo[ld].span_set[info]);
558265555Sambrisko
559265555Sambrisko               if (span_set->span_row_data_width == 0) break;
560265555Sambrisko               if (strip > span_set->data_strip_end) continue;
561265555Sambrisko
562265555Sambrisko               strip_offset = (u_int32_t)mega_mod64
563265555Sambrisko                               ((strip - span_set->data_strip_start),
564265555Sambrisko                               span_set->span_row_data_width);
565265555Sambrisko
566265555Sambrisko               for (span=0,span_offset=0; span<raid->spanDepth; span++)
567265555Sambrisko                       if (map->raidMap.ldSpanMap[ld].spanBlock[span].
568265555Sambrisko                               block_span_info.noElements >=info+1) {
569265555Sambrisko                               if (strip_offset >=
570265555Sambrisko                                       span_set->strip_offset[span])
571265555Sambrisko                                       span_offset =
572265555Sambrisko                                               span_set->strip_offset[span];
573265555Sambrisko                               else
574265555Sambrisko                                       break;
575265555Sambrisko                       }
576265555Sambrisko               mrsas_dprint(sc, MRSAS_PRL11, "LSI PRL11: get_arm_from_strip: "
577265555Sambrisko                       " for ld=0x%x strip=0x%lx arm is  0x%x\n", ld,
578265555Sambrisko                       (long unsigned int)strip, (strip_offset - span_offset));
579265555Sambrisko               return (strip_offset - span_offset);
580265555Sambrisko       }
581265555Sambrisko
582265555Sambrisko       mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: - get_arm_from_strip: returns invalid arm"
583265555Sambrisko               " for ld=%x strip=%lx\n", ld, (long unsigned int)strip);
584265555Sambrisko
585265555Sambrisko       return -1;
586265555Sambrisko}
587265555Sambrisko
588265555Sambrisko
589265555Sambrisko/* This Function will return Phys arm */
590265555Sambriskou_int8_t get_arm(struct mrsas_softc *sc, u_int32_t ld, u_int8_t span, u_int64_t stripe,
591265555Sambrisko               MR_FW_RAID_MAP_ALL *map)
592265555Sambrisko{
593265555Sambrisko       MR_LD_RAID  *raid = MR_LdRaidGet(ld, map);
594265555Sambrisko       /* Need to check correct default value */
595265555Sambrisko       u_int32_t    arm = 0;
596265555Sambrisko
597265555Sambrisko       switch (raid->level) {
598265555Sambrisko               case 0:
599265555Sambrisko               case 5:
600265555Sambrisko               case 6:
601265555Sambrisko                       arm = mega_mod64(stripe, SPAN_ROW_SIZE(map, ld, span));
602265555Sambrisko                       break;
603265555Sambrisko               case 1:
604265555Sambrisko                       // start with logical arm
605265555Sambrisko                       arm = get_arm_from_strip(sc, ld, stripe, map);
606265555Sambrisko                       arm *= 2;
607265555Sambrisko                       break;
608265555Sambrisko
609265555Sambrisko       }
610265555Sambrisko
611265555Sambrisko       return arm;
612265555Sambrisko}
613265555Sambrisko
614265555Sambrisko/*
615265555Sambrisko******************************************************************************
616265555Sambrisko*
617265555Sambrisko* This routine calculates the arm, span and block for the specified stripe and
618265555Sambrisko* reference in stripe using spanset
619265555Sambrisko*
620265555Sambrisko* Inputs :
621265555Sambrisko*
622265555Sambrisko*    ld   - Logical drive number
623265555Sambrisko*    stripRow        - Stripe number
624265555Sambrisko*    stripRef    - Reference in stripe
625265555Sambrisko*
626265555Sambrisko* Outputs :
627265555Sambrisko*
628265555Sambrisko*    span          - Span number
629265555Sambrisko*    block         - Absolute Block number in the physical disk
630265555Sambrisko*/
631265555Sambriskostatic u_int8_t mr_spanset_get_phy_params(struct mrsas_softc *sc, u_int32_t ld, u_int64_t stripRow,
632265555Sambrisko                  u_int16_t stripRef, struct IO_REQUEST_INFO *io_info,
633265555Sambrisko                  RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map)
634265555Sambrisko{
635265555Sambrisko       MR_LD_RAID  *raid = MR_LdRaidGet(ld, map);
636265555Sambrisko       u_int32_t     pd, arRef;
637265555Sambrisko       u_int8_t      physArm, span;
638265555Sambrisko       u_int64_t     row;
639265555Sambrisko       u_int8_t      retval = TRUE;
640265555Sambrisko       u_int64_t     *pdBlock = &io_info->pdBlock;
641265555Sambrisko       u_int16_t     *pDevHandle = &io_info->devHandle;
642265555Sambrisko       u_int32_t     logArm, rowMod, armQ, arm;
643265555Sambrisko       u_int8_t do_invader = 0;
644265555Sambrisko
645265555Sambrisko       if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY))
646265555Sambrisko           do_invader = 1;
647265555Sambrisko
648265555Sambrisko       // Get row and span from io_info for Uneven Span IO.
649265555Sambrisko       row         = io_info->start_row;
650265555Sambrisko       span        = io_info->start_span;
651265555Sambrisko
652265555Sambrisko
653265555Sambrisko       if (raid->level == 6) {
654265555Sambrisko               logArm = get_arm_from_strip(sc, ld, stripRow, map);
655265555Sambrisko               rowMod = mega_mod64(row, SPAN_ROW_SIZE(map, ld, span));
656265555Sambrisko               armQ = SPAN_ROW_SIZE(map,ld,span) - 1 - rowMod;
657265555Sambrisko               arm = armQ + 1 + logArm;
658265555Sambrisko               if (arm >= SPAN_ROW_SIZE(map, ld, span))
659265555Sambrisko                       arm -= SPAN_ROW_SIZE(map ,ld ,span);
660265555Sambrisko               physArm = (u_int8_t)arm;
661265555Sambrisko       } else
662265555Sambrisko               // Calculate the arm
663265555Sambrisko               physArm = get_arm(sc, ld, span, stripRow, map);
664265555Sambrisko
665265555Sambrisko
666265555Sambrisko       arRef       = MR_LdSpanArrayGet(ld, span, map);
667265555Sambrisko       pd          = MR_ArPdGet(arRef, physArm, map);
668265555Sambrisko
669265555Sambrisko       if (pd != MR_PD_INVALID)
670265555Sambrisko               *pDevHandle = MR_PdDevHandleGet(pd, map);
671265555Sambrisko       else {
672265555Sambrisko               *pDevHandle = MR_PD_INVALID;
673265555Sambrisko               if ((raid->level >= 5) && ((!do_invader) || (do_invader &&
674265555Sambrisko                  raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))
675265555Sambrisko                  pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
676265555Sambrisko               else if (raid->level == 1) {
677265555Sambrisko               	  pd = MR_ArPdGet(arRef, physArm + 1, map);
678265555Sambrisko                  if (pd != MR_PD_INVALID)
679265555Sambrisko                     *pDevHandle = MR_PdDevHandleGet(pd, map);
680265555Sambrisko               }
681265555Sambrisko       }
682265555Sambrisko
683265555Sambrisko       *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk;
684265555Sambrisko       pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm;
685265555Sambrisko       return retval;
686265555Sambrisko}
687265555Sambrisko
688265555Sambrisko/**
689265555Sambrisko* MR_BuildRaidContext:           Set up Fast path RAID context
690265555Sambrisko*
691265555Sambrisko* This function will initiate command processing.  The start/end row
692265555Sambrisko* and strip information is calculated then the lock is acquired.
693265555Sambrisko* This function will return 0 if region lock was acquired OR return
694265555Sambrisko* num strips.
695265555Sambrisko*/
696265555Sambriskou_int8_t
697265555SambriskoMR_BuildRaidContext(struct mrsas_softc *sc, struct IO_REQUEST_INFO *io_info,
698265555Sambrisko                    RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map)
699265555Sambrisko{
700265555Sambrisko    MR_LD_RAID *raid;
701265555Sambrisko    u_int32_t ld, stripSize, stripe_mask;
702265555Sambrisko    u_int64_t endLba, endStrip, endRow, start_row, start_strip;
703265555Sambrisko    REGION_KEY regStart;
704265555Sambrisko    REGION_LEN regSize;
705265555Sambrisko    u_int8_t num_strips, numRows;
706265555Sambrisko    u_int16_t ref_in_start_stripe, ref_in_end_stripe;
707265555Sambrisko    u_int64_t ldStartBlock;
708265555Sambrisko    u_int32_t numBlocks, ldTgtId;
709265555Sambrisko    u_int8_t isRead, stripIdx;
710265555Sambrisko    u_int8_t retval = 0;
711265555Sambrisko	u_int8_t startlba_span = SPAN_INVALID;
712265555Sambrisko    u_int64_t *pdBlock = &io_info->pdBlock;
713265555Sambrisko    int error_code = 0;
714265555Sambrisko
715265555Sambrisko    ldStartBlock = io_info->ldStartBlock;
716265555Sambrisko    numBlocks = io_info->numBlocks;
717265555Sambrisko    ldTgtId = io_info->ldTgtId;
718265555Sambrisko    isRead = io_info->isRead;
719265555Sambrisko
720265555Sambrisko	io_info->IoforUnevenSpan = 0;
721265555Sambrisko    io_info->start_span     = SPAN_INVALID;
722265555Sambrisko
723265555Sambrisko    ld = MR_TargetIdToLdGet(ldTgtId, map);
724265555Sambrisko    raid = MR_LdRaidGet(ld, map);
725265555Sambrisko
726265555Sambrisko    /*
727265555Sambrisko 	* if rowDataSize @RAID map and spanRowDataSize @SPAN INFO are zero
728265555Sambrisko    * return FALSE
729265555Sambrisko    */
730265555Sambrisko	if (raid->rowDataSize == 0) {
731265555Sambrisko	   if (MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize == 0)
732265555Sambrisko		   return FALSE;
733265555Sambrisko	   else if (sc->UnevenSpanSupport) {
734265555Sambrisko		   io_info->IoforUnevenSpan = 1;
735265555Sambrisko	   }
736265555Sambrisko	   else {
737265555Sambrisko		   mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: raid->rowDataSize is 0, but has SPAN[0] rowDataSize = 0x%0x,"
738265555Sambrisko				   " but there is _NO_ UnevenSpanSupport\n",
739265555Sambrisko		   MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize);
740265555Sambrisko		   return FALSE;
741265555Sambrisko	   }
742265555Sambrisko	}
743265555Sambrisko    stripSize = 1 << raid->stripeShift;
744265555Sambrisko    stripe_mask = stripSize-1;
745265555Sambrisko    /*
746265555Sambrisko     * calculate starting row and stripe, and number of strips and rows
747265555Sambrisko     */
748265555Sambrisko    start_strip = ldStartBlock >> raid->stripeShift;
749265555Sambrisko    ref_in_start_stripe = (u_int16_t)(ldStartBlock & stripe_mask);
750265555Sambrisko    endLba = ldStartBlock + numBlocks - 1;
751265555Sambrisko    ref_in_end_stripe = (u_int16_t)(endLba & stripe_mask);
752265555Sambrisko    endStrip = endLba >> raid->stripeShift;
753265555Sambrisko    num_strips = (u_int8_t)(endStrip - start_strip + 1);     // End strip
754265555Sambrisko       if (io_info->IoforUnevenSpan) {
755265555Sambrisko               start_row = get_row_from_strip(sc, ld, start_strip, map);
756265555Sambrisko               endRow    = get_row_from_strip(sc, ld, endStrip, map);
757265555Sambrisko               if (raid->spanDepth == 1) {
758265555Sambrisko                       startlba_span = 0;
759265555Sambrisko                       *pdBlock = start_row << raid->stripeShift;
760265555Sambrisko               } else {
761265555Sambrisko                       startlba_span = (u_int8_t)mr_spanset_get_span_block(sc, ld, start_row,
762265555Sambrisko                                               pdBlock, map, &error_code);
763265555Sambrisko                       if (error_code == 1) {
764265555Sambrisko                               mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: return from %s %d. Send IO w/o region lock.\n",
765265555Sambrisko                                       __func__, __LINE__);
766265555Sambrisko                               return FALSE;
767265555Sambrisko                       }
768265555Sambrisko               }
769265555Sambrisko               if (startlba_span == SPAN_INVALID) {
770265555Sambrisko                       mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: return from %s %d for row 0x%llx,"
771265555Sambrisko                               "start strip %llx endSrip %llx\n", __func__,
772265555Sambrisko                               __LINE__, (unsigned long long)start_row,
773265555Sambrisko                               (unsigned long long)start_strip,
774265555Sambrisko                               (unsigned long long)endStrip);
775265555Sambrisko                       return FALSE;
776265555Sambrisko               }
777265555Sambrisko               io_info->start_span     = startlba_span;
778265555Sambrisko               io_info->start_row      = start_row;
779265555Sambrisko               mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: Check Span number from %s %d for row 0x%llx, "
780265555Sambrisko                               " start strip 0x%llx endSrip 0x%llx span 0x%x\n",
781265555Sambrisko                                __func__, __LINE__, (unsigned long long)start_row,
782265555Sambrisko                               (unsigned long long)start_strip,
783265555Sambrisko                               (unsigned long long)endStrip, startlba_span);
784265555Sambrisko               mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : 1. start_row 0x%llx endRow 0x%llx Start span 0x%x\n",
785265555Sambrisko                       (unsigned long long)start_row, (unsigned long long)endRow, startlba_span);
786265555Sambrisko       } else {
787265555Sambrisko               start_row           =  mega_div64_32(start_strip, raid->rowDataSize);      // Start Row
788265555Sambrisko               endRow              =  mega_div64_32(endStrip, raid->rowDataSize);
789265555Sambrisko       }
790265555Sambrisko
791265555Sambrisko    numRows = (u_int8_t)(endRow - start_row + 1);   // get the row count
792265555Sambrisko
793265555Sambrisko    /*
794265555Sambrisko     * Calculate region info.  (Assume region at start of first row, and
795265555Sambrisko     * assume this IO needs the full row - will adjust if not true.)
796265555Sambrisko     */
797265555Sambrisko    regStart = start_row << raid->stripeShift;
798265555Sambrisko    regSize = stripSize;
799265555Sambrisko
800265555Sambrisko    /* Check if we can send this I/O via FastPath */
801265555Sambrisko    if (raid->capability.fpCapable) {
802265555Sambrisko        if (isRead)
803265555Sambrisko            io_info->fpOkForIo = (raid->capability.fpReadCapable &&
804265555Sambrisko                                              ((num_strips == 1) ||
805265555Sambrisko                                               raid->capability.
806265555Sambrisko                                               fpReadAcrossStripe));
807265555Sambrisko        else
808265555Sambrisko            io_info->fpOkForIo = (raid->capability.fpWriteCapable &&
809265555Sambrisko                                              ((num_strips == 1) ||
810265555Sambrisko                                               raid->capability.
811265555Sambrisko                                               fpWriteAcrossStripe));
812265555Sambrisko    }
813265555Sambrisko    else
814265555Sambrisko        io_info->fpOkForIo = FALSE;
815265555Sambrisko
816265555Sambrisko    if (numRows == 1) {
817265555Sambrisko        if (num_strips == 1) {
818265555Sambrisko            /* single-strip IOs can always lock only the data needed,
819265555Sambrisko               multi-strip IOs always need to full stripe locked */
820265555Sambrisko            regStart += ref_in_start_stripe;
821265555Sambrisko            regSize = numBlocks;
822265555Sambrisko        }
823265555Sambrisko    }
824265555Sambrisko    else if (io_info->IoforUnevenSpan == 0){
825265555Sambrisko        // For Even span region lock optimization.
826265555Sambrisko        // If the start strip is the last in the start row
827265555Sambrisko        if (start_strip == (start_row + 1) * raid->rowDataSize - 1) {
828265555Sambrisko            regStart += ref_in_start_stripe;
829265555Sambrisko            // initialize count to sectors from startRef to end of strip
830265555Sambrisko            regSize = stripSize - ref_in_start_stripe;
831265555Sambrisko        }
832265555Sambrisko		// add complete rows in the middle of the transfer
833265555Sambrisko		if (numRows > 2)
834265555Sambrisko            regSize += (numRows-2) << raid->stripeShift;
835265555Sambrisko
836265555Sambrisko        // if IO ends within first strip of last row
837265555Sambrisko        if (endStrip == endRow*raid->rowDataSize)
838265555Sambrisko                        regSize += ref_in_end_stripe+1;
839265555Sambrisko                else
840265555Sambrisko                        regSize += stripSize;
841265555Sambrisko    } else {
842265555Sambrisko		//For Uneven span region lock optimization.
843265555Sambrisko        // If the start strip is the last in the start row
844265555Sambrisko        if (start_strip == (get_strip_from_row(sc, ld, start_row, map) +
845265555Sambrisko            	SPAN_ROW_DATA_SIZE(map, ld, startlba_span) - 1)) {
846265555Sambrisko            regStart += ref_in_start_stripe;
847265555Sambrisko			// initialize count to sectors from startRef to end of strip
848265555Sambrisko			regSize = stripSize - ref_in_start_stripe;
849265555Sambrisko        }
850265555Sambrisko        // add complete rows in the middle of the transfer
851265555Sambrisko        if (numRows > 2)
852265555Sambrisko            regSize += (numRows-2) << raid->stripeShift;
853265555Sambrisko
854265555Sambrisko        // if IO ends within first strip of last row
855265555Sambrisko        if (endStrip == get_strip_from_row(sc, ld, endRow, map))
856265555Sambrisko            regSize += ref_in_end_stripe+1;
857265555Sambrisko        else
858265555Sambrisko            regSize += stripSize;
859265555Sambrisko    }
860265555Sambrisko    pRAID_Context->timeoutValue = map->raidMap.fpPdIoTimeoutSec;
861265555Sambrisko    if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY))
862265555Sambrisko                pRAID_Context->regLockFlags = (isRead)? raid->regTypeReqOnRead : raid->regTypeReqOnWrite;
863265555Sambrisko    else
864265555Sambrisko    	pRAID_Context->regLockFlags = (isRead)? REGION_TYPE_SHARED_READ : raid->regTypeReqOnWrite;
865265555Sambrisko    pRAID_Context->VirtualDiskTgtId = raid->targetId;
866265555Sambrisko    pRAID_Context->regLockRowLBA = regStart;
867265555Sambrisko    pRAID_Context->regLockLength = regSize;
868265555Sambrisko    pRAID_Context->configSeqNum = raid->seqNum;
869265555Sambrisko
870265555Sambrisko    /*
871265555Sambrisko     * Get Phy Params only if FP capable, or else leave it to MR firmware
872265555Sambrisko     * to do the calculation.
873265555Sambrisko     */
874265555Sambrisko    if (io_info->fpOkForIo) {
875265555Sambrisko        retval = io_info->IoforUnevenSpan ?
876265555Sambrisko                               mr_spanset_get_phy_params(sc, ld,
877265555Sambrisko                                   start_strip, ref_in_start_stripe, io_info,
878265555Sambrisko                                   pRAID_Context, map) :
879265555Sambrisko                               MR_GetPhyParams(sc, ld, start_strip,
880265555Sambrisko                                   ref_in_start_stripe, io_info, pRAID_Context, map);
881265555Sambrisko        /* If IO on an invalid Pd, then FP is not possible */
882265555Sambrisko        if (io_info->devHandle == MR_PD_INVALID)
883265555Sambrisko            io_info->fpOkForIo = FALSE;
884265555Sambrisko        return retval;
885265555Sambrisko    }
886265555Sambrisko    else if (isRead) {
887265555Sambrisko        for (stripIdx=0; stripIdx<num_strips; stripIdx++) {
888265555Sambrisko             retval = io_info->IoforUnevenSpan ?
889265555Sambrisko                        mr_spanset_get_phy_params(sc, ld,
890265555Sambrisko                            start_strip + stripIdx,
891265555Sambrisko                            ref_in_start_stripe, io_info,
892265555Sambrisko                            pRAID_Context, map) :
893265555Sambrisko                        MR_GetPhyParams(sc, ld,
894265555Sambrisko                            start_strip + stripIdx, ref_in_start_stripe,
895265555Sambrisko                            io_info, pRAID_Context, map);
896265555Sambrisko              if (!retval)
897265555Sambrisko                  return TRUE;
898265555Sambrisko        }
899265555Sambrisko    }
900265555Sambrisko#if SPAN_DEBUG
901265555Sambrisko       // Just for testing what arm we get for strip.
902265555Sambrisko       get_arm_from_strip(sc, ld, start_strip, map);
903265555Sambrisko#endif
904265555Sambrisko    return TRUE;
905265555Sambrisko}
906265555Sambrisko
907265555Sambrisko/*
908265555Sambrisko******************************************************************************
909265555Sambrisko*
910265555Sambrisko* This routine pepare spanset info from Valid Raid map and store it into
911265555Sambrisko* local copy of ldSpanInfo per instance data structure.
912265555Sambrisko*
913265555Sambrisko* Inputs :
914265555Sambrisko*    map    - LD map
915265555Sambrisko*    ldSpanInfo - ldSpanInfo per HBA instance
916265555Sambrisko*
917265555Sambrisko*/
918265555Sambriskovoid mr_update_span_set(MR_FW_RAID_MAP_ALL *map, PLD_SPAN_INFO ldSpanInfo)
919265555Sambrisko{
920265555Sambrisko       u_int8_t   span,count;
921265555Sambrisko       u_int32_t    element,span_row_width;
922265555Sambrisko       u_int64_t  span_row;
923265555Sambrisko       MR_LD_RAID *raid;
924265555Sambrisko       LD_SPAN_SET *span_set, *span_set_prev;
925265555Sambrisko       MR_QUAD_ELEMENT    *quad;
926265555Sambrisko       int ldCount;
927265555Sambrisko       u_int16_t ld;
928265555Sambrisko
929265555Sambrisko	if (!ldSpanInfo)
930265555Sambrisko		return;
931265555Sambrisko
932265555Sambrisko       for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++)
933265555Sambrisko       {
934265555Sambrisko               ld = MR_TargetIdToLdGet(ldCount, map);
935265555Sambrisko               if (ld >= MAX_LOGICAL_DRIVES)
936265555Sambrisko                       continue;
937265555Sambrisko               raid = MR_LdRaidGet(ld, map);
938265555Sambrisko               for (element=0; element < MAX_QUAD_DEPTH; element++) {
939265555Sambrisko                       for (span=0; span < raid->spanDepth; span++) {
940265555Sambrisko                               if (map->raidMap.ldSpanMap[ld].spanBlock[span].
941265555Sambrisko                                       block_span_info.noElements < element+1)
942265555Sambrisko                                       continue;
943265555Sambrisko                               // TO-DO
944265555Sambrisko                               span_set = &(ldSpanInfo[ld].span_set[element]);
945265555Sambrisko                               quad = &map->raidMap.ldSpanMap[ld].
946265555Sambrisko                                       spanBlock[span].block_span_info.
947265555Sambrisko                                       quad[element];
948265555Sambrisko
949265555Sambrisko                               span_set->diff = quad->diff;
950265555Sambrisko
951265555Sambrisko                               for (count=0,span_row_width=0;
952265555Sambrisko                                               count<raid->spanDepth; count++) {
953265555Sambrisko                                       if (map->raidMap.ldSpanMap[ld].
954265555Sambrisko                                               spanBlock[count].
955265555Sambrisko                                               block_span_info.
956265555Sambrisko                                               noElements >=element+1) {
957265555Sambrisko                                               span_set->strip_offset[count] =
958265555Sambrisko                                                       span_row_width;
959265555Sambrisko                                               span_row_width +=
960265555Sambrisko                                                       MR_LdSpanPtrGet
961265555Sambrisko                                                       (ld, count, map)->spanRowDataSize;
962265555Sambrisko#if SPAN_DEBUG
963265555Sambrisko                                               printf("LSI Debug span %x rowDataSize %x\n",
964265555Sambrisko                                               count, MR_LdSpanPtrGet
965265555Sambrisko                                                       (ld, count, map)->spanRowDataSize);
966265555Sambrisko#endif
967265555Sambrisko                                       }
968265555Sambrisko                               }
969265555Sambrisko
970265555Sambrisko                               span_set->span_row_data_width = span_row_width;
971265555Sambrisko                               span_row = mega_div64_32(((quad->logEnd -
972265555Sambrisko                                       quad->logStart) + quad->diff), quad->diff);
973265555Sambrisko
974265555Sambrisko                               if (element == 0) {
975265555Sambrisko                                       span_set->log_start_lba = 0;
976265555Sambrisko                                       span_set->log_end_lba =
977265555Sambrisko                                       ((span_row << raid->stripeShift) * span_row_width) - 1;
978265555Sambrisko
979265555Sambrisko                                       span_set->span_row_start = 0;
980265555Sambrisko                                       span_set->span_row_end = span_row - 1;
981265555Sambrisko
982265555Sambrisko                                       span_set->data_strip_start = 0;
983265555Sambrisko                                       span_set->data_strip_end =
984265555Sambrisko                                               (span_row * span_row_width) - 1;
985265555Sambrisko
986265555Sambrisko                                       span_set->data_row_start = 0;
987265555Sambrisko                                       span_set->data_row_end =
988265555Sambrisko                                               (span_row * quad->diff) - 1;
989265555Sambrisko                               } else {
990265555Sambrisko                                       span_set_prev = &(ldSpanInfo[ld].
991265555Sambrisko                                                       span_set[element - 1]);
992265555Sambrisko                                       span_set->log_start_lba =
993265555Sambrisko                                               span_set_prev->log_end_lba + 1;
994265555Sambrisko                                       span_set->log_end_lba =
995265555Sambrisko                                               span_set->log_start_lba +
996265555Sambrisko                                               ((span_row << raid->stripeShift) * span_row_width) - 1;
997265555Sambrisko
998265555Sambrisko                                       span_set->span_row_start =
999265555Sambrisko                                               span_set_prev->span_row_end + 1;
1000265555Sambrisko                                       span_set->span_row_end =
1001265555Sambrisko                                               span_set->span_row_start + span_row - 1;
1002265555Sambrisko
1003265555Sambrisko                                       span_set->data_strip_start =
1004265555Sambrisko                                               span_set_prev->data_strip_end + 1;
1005265555Sambrisko                                       span_set->data_strip_end =
1006265555Sambrisko                                               span_set->data_strip_start +
1007265555Sambrisko                                               (span_row * span_row_width) - 1;
1008265555Sambrisko
1009265555Sambrisko                                       span_set->data_row_start =
1010265555Sambrisko                                               span_set_prev->data_row_end + 1;
1011265555Sambrisko                                       span_set->data_row_end =
1012265555Sambrisko                                               span_set->data_row_start +
1013265555Sambrisko                                               (span_row * quad->diff) - 1;
1014265555Sambrisko                               }
1015265555Sambrisko                               break;
1016265555Sambrisko               }
1017265555Sambrisko               if (span == raid->spanDepth) break; // no quads remain
1018265555Sambrisko           }
1019265555Sambrisko       }
1020265555Sambrisko#if SPAN_DEBUG
1021265555Sambrisko       getSpanInfo(map, ldSpanInfo);   //to get span set info
1022265555Sambrisko#endif
1023265555Sambrisko}
1024265555Sambrisko
1025265555Sambrisko/**
1026265555Sambrisko * mrsas_update_load_balance_params:  Update load balance parmas
1027265555Sambrisko * Inputs:                         map pointer
1028265555Sambrisko *                                 Load balance info
1029265555Sambrisko *                                 io_info pointer
1030265555Sambrisko *
1031265555Sambrisko * This function updates the load balance parameters for the LD config
1032265555Sambrisko * of a two drive optimal RAID-1.
1033265555Sambrisko */
1034265555Sambriskovoid mrsas_update_load_balance_params(MR_FW_RAID_MAP_ALL *map,
1035265555Sambrisko        PLD_LOAD_BALANCE_INFO lbInfo)
1036265555Sambrisko{
1037265555Sambrisko    int ldCount;
1038265555Sambrisko    u_int16_t ld;
1039265555Sambrisko    u_int32_t pd, arRef;
1040265555Sambrisko    MR_LD_RAID *raid;
1041265555Sambrisko
1042265555Sambrisko    for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++)
1043265555Sambrisko    {
1044265555Sambrisko        ld = MR_TargetIdToLdGet(ldCount, map);
1045265555Sambrisko        if (ld >= MAX_LOGICAL_DRIVES) {
1046265555Sambrisko            lbInfo[ldCount].loadBalanceFlag = 0;
1047265555Sambrisko            continue;
1048265555Sambrisko        }
1049265555Sambrisko
1050265555Sambrisko        raid = MR_LdRaidGet(ld, map);
1051265555Sambrisko
1052265555Sambrisko        /* Two drive Optimal RAID 1 */
1053265555Sambrisko        if ((raid->level == 1) && (raid->rowSize == 2) &&
1054265555Sambrisko                (raid->spanDepth == 1)
1055265555Sambrisko                && raid->ldState == MR_LD_STATE_OPTIMAL) {
1056265555Sambrisko            lbInfo[ldCount].loadBalanceFlag = 1;
1057265555Sambrisko
1058265555Sambrisko            /* Get the array on which this span is present */
1059265555Sambrisko            arRef = MR_LdSpanArrayGet(ld, 0, map);
1060265555Sambrisko
1061265555Sambrisko            /* Get the PD */
1062265555Sambrisko            pd = MR_ArPdGet(arRef, 0, map);
1063265555Sambrisko            /* Get dev handle from PD */
1064265555Sambrisko            lbInfo[ldCount].raid1DevHandle[0] = MR_PdDevHandleGet(pd, map);
1065265555Sambrisko            pd = MR_ArPdGet(arRef, 1, map);
1066265555Sambrisko            lbInfo[ldCount].raid1DevHandle[1] = MR_PdDevHandleGet(pd, map);
1067265555Sambrisko        }
1068265555Sambrisko        else
1069265555Sambrisko            lbInfo[ldCount].loadBalanceFlag = 0;
1070265555Sambrisko    }
1071265555Sambrisko}
1072265555Sambrisko
1073265555Sambrisko
1074265555Sambrisko/**
1075265555Sambrisko * mrsas_set_pd_lba:    Sets PD LBA
1076265555Sambrisko * input:               io_request pointer
1077265555Sambrisko *                      CDB length
1078265555Sambrisko *                      io_info pointer
1079265555Sambrisko *                      Pointer to CCB
1080265555Sambrisko *                      Local RAID map pointer
1081265555Sambrisko *                      Start block of IO
1082265555Sambrisko *                      Block Size
1083265555Sambrisko *
1084265555Sambrisko * Used to set the PD logical block address in CDB for FP IOs.
1085265555Sambrisko */
1086265555Sambriskovoid mrsas_set_pd_lba(MRSAS_RAID_SCSI_IO_REQUEST *io_request, u_int8_t cdb_len,
1087265555Sambrisko    struct IO_REQUEST_INFO *io_info, union ccb *ccb,
1088265555Sambrisko    MR_FW_RAID_MAP_ALL *local_map_ptr, u_int32_t ref_tag,
1089265555Sambrisko    u_int32_t ld_block_size)
1090265555Sambrisko{
1091265555Sambrisko    MR_LD_RAID *raid;
1092265555Sambrisko    u_int32_t ld;
1093265555Sambrisko    u_int64_t start_blk = io_info->pdBlock;
1094265555Sambrisko    u_int8_t *cdb = io_request->CDB.CDB32;
1095265555Sambrisko    u_int32_t num_blocks = io_info->numBlocks;
1096265555Sambrisko    u_int8_t opcode = 0, flagvals = 0, groupnum = 0, control = 0;
1097265555Sambrisko    struct ccb_hdr *ccb_h = &(ccb->ccb_h);
1098265555Sambrisko
1099265555Sambrisko    /* Check if T10 PI (DIF) is enabled for this LD */
1100265555Sambrisko    ld = MR_TargetIdToLdGet(io_info->ldTgtId, local_map_ptr);
1101265555Sambrisko    raid = MR_LdRaidGet(ld, local_map_ptr);
1102265555Sambrisko    if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER) {
1103265555Sambrisko        memset(cdb, 0, sizeof(io_request->CDB.CDB32));
1104265555Sambrisko        cdb[0] =  MRSAS_SCSI_VARIABLE_LENGTH_CMD;
1105265555Sambrisko        cdb[7] =  MRSAS_SCSI_ADDL_CDB_LEN;
1106265555Sambrisko
1107265555Sambrisko        if (ccb_h->flags == CAM_DIR_OUT)
1108265555Sambrisko            cdb[9] = MRSAS_SCSI_SERVICE_ACTION_READ32;
1109265555Sambrisko        else
1110265555Sambrisko            cdb[9] = MRSAS_SCSI_SERVICE_ACTION_WRITE32;
1111265555Sambrisko        cdb[10] = MRSAS_RD_WR_PROTECT_CHECK_ALL;
1112265555Sambrisko
1113265555Sambrisko        /* LBA */
1114265555Sambrisko        cdb[12] = (u_int8_t)((start_blk >> 56) & 0xff);
1115265555Sambrisko        cdb[13] = (u_int8_t)((start_blk >> 48) & 0xff);
1116265555Sambrisko        cdb[14] = (u_int8_t)((start_blk >> 40) & 0xff);
1117265555Sambrisko        cdb[15] = (u_int8_t)((start_blk >> 32) & 0xff);
1118265555Sambrisko        cdb[16] = (u_int8_t)((start_blk >> 24) & 0xff);
1119265555Sambrisko        cdb[17] = (u_int8_t)((start_blk >> 16) & 0xff);
1120265555Sambrisko        cdb[18] = (u_int8_t)((start_blk >> 8) & 0xff);
1121265555Sambrisko        cdb[19] = (u_int8_t)(start_blk & 0xff);
1122265555Sambrisko
1123265555Sambrisko        /* Logical block reference tag */
1124265555Sambrisko        io_request->CDB.EEDP32.PrimaryReferenceTag = swap32(ref_tag);
1125265555Sambrisko        io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0xffff;
1126265555Sambrisko        io_request->IoFlags = 32; /* Specify 32-byte cdb */
1127265555Sambrisko
1128265555Sambrisko        /* Transfer length */
1129265555Sambrisko        cdb[28] = (u_int8_t)((num_blocks >> 24) & 0xff);
1130265555Sambrisko        cdb[29] = (u_int8_t)((num_blocks >> 16) & 0xff);
1131265555Sambrisko        cdb[30] = (u_int8_t)((num_blocks >> 8) & 0xff);
1132265555Sambrisko        cdb[31] = (u_int8_t)(num_blocks & 0xff);
1133265555Sambrisko
1134265555Sambrisko        /* set SCSI IO EEDP Flags */
1135265555Sambrisko        if (ccb_h->flags == CAM_DIR_OUT) {
1136265555Sambrisko            io_request->EEDPFlags =
1137265555Sambrisko                MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG  |
1138265555Sambrisko                MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
1139265555Sambrisko                MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP |
1140265555Sambrisko                MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG |
1141265555Sambrisko                MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
1142265555Sambrisko        }
1143265555Sambrisko        else {
1144265555Sambrisko                io_request->EEDPFlags =
1145265555Sambrisko                     MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
1146265555Sambrisko                     MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
1147265555Sambrisko        }
1148265555Sambrisko        io_request->Control |= (0x4 << 26);
1149265555Sambrisko        io_request->EEDPBlockSize = ld_block_size;
1150265555Sambrisko    }
1151265555Sambrisko    else {
1152265555Sambrisko        /* Some drives don't support 16/12 byte CDB's, convert to 10 */
1153265555Sambrisko        if (((cdb_len == 12) || (cdb_len == 16)) &&
1154265555Sambrisko                    (start_blk <= 0xffffffff)) {
1155265555Sambrisko            if (cdb_len == 16) {
1156265555Sambrisko                opcode = cdb[0] == READ_16 ? READ_10 : WRITE_10;
1157265555Sambrisko                flagvals = cdb[1];
1158265555Sambrisko                groupnum = cdb[14];
1159265555Sambrisko                control = cdb[15];
1160265555Sambrisko            }
1161265555Sambrisko            else {
1162265555Sambrisko                opcode = cdb[0] == READ_12 ? READ_10 : WRITE_10;
1163265555Sambrisko                flagvals = cdb[1];
1164265555Sambrisko                groupnum = cdb[10];
1165265555Sambrisko                control = cdb[11];
1166265555Sambrisko            }
1167265555Sambrisko
1168265555Sambrisko            memset(cdb, 0, sizeof(io_request->CDB.CDB32));
1169265555Sambrisko
1170265555Sambrisko            cdb[0] = opcode;
1171265555Sambrisko            cdb[1] = flagvals;
1172265555Sambrisko            cdb[6] = groupnum;
1173265555Sambrisko            cdb[9] = control;
1174265555Sambrisko
1175265555Sambrisko            /* Transfer length */
1176265555Sambrisko            cdb[8] = (u_int8_t)(num_blocks & 0xff);
1177265555Sambrisko            cdb[7] = (u_int8_t)((num_blocks >> 8) & 0xff);
1178265555Sambrisko
1179265555Sambrisko            io_request->IoFlags = 10; /* Specify 10-byte cdb */
1180265555Sambrisko            cdb_len = 10;
1181265555Sambrisko        } else if ((cdb_len < 16) && (start_blk > 0xffffffff)) {
1182265555Sambrisko            /* Convert to 16 byte CDB for large LBA's */
1183265555Sambrisko            switch (cdb_len) {
1184265555Sambrisko                case 6:
1185265555Sambrisko                    opcode = cdb[0] == READ_6 ? READ_16 : WRITE_16;
1186265555Sambrisko                    control = cdb[5];
1187265555Sambrisko                    break;
1188265555Sambrisko                case 10:
1189265555Sambrisko                    opcode = cdb[0] == READ_10 ? READ_16 : WRITE_16;
1190265555Sambrisko                    flagvals = cdb[1];
1191265555Sambrisko                    groupnum = cdb[6];
1192265555Sambrisko                    control = cdb[9];
1193265555Sambrisko                    break;
1194265555Sambrisko                case 12:
1195265555Sambrisko                    opcode = cdb[0] == READ_12 ? READ_16 : WRITE_16;
1196265555Sambrisko                    flagvals = cdb[1];
1197265555Sambrisko                    groupnum = cdb[10];
1198265555Sambrisko                    control = cdb[11];
1199265555Sambrisko                    break;
1200265555Sambrisko            }
1201265555Sambrisko
1202265555Sambrisko            memset(cdb, 0, sizeof(io_request->CDB.CDB32));
1203265555Sambrisko
1204265555Sambrisko            cdb[0] = opcode;
1205265555Sambrisko            cdb[1] = flagvals;
1206265555Sambrisko            cdb[14] = groupnum;
1207265555Sambrisko            cdb[15] = control;
1208265555Sambrisko
1209265555Sambrisko            /* Transfer length */
1210265555Sambrisko            cdb[13] = (u_int8_t)(num_blocks & 0xff);
1211265555Sambrisko            cdb[12] = (u_int8_t)((num_blocks >> 8) & 0xff);
1212265555Sambrisko            cdb[11] = (u_int8_t)((num_blocks >> 16) & 0xff);
1213265555Sambrisko            cdb[10] = (u_int8_t)((num_blocks >> 24) & 0xff);
1214265555Sambrisko
1215265555Sambrisko            io_request->IoFlags = 16; /* Specify 16-byte cdb */
1216265555Sambrisko            cdb_len = 16;
1217265555Sambrisko        } else if ((cdb_len == 6) && (start_blk > 0x1fffff)) {
1218265555Sambrisko            /* convert to 10 byte CDB */
1219265555Sambrisko	    opcode = cdb[0] == READ_6 ? READ_10 : WRITE_10;
1220265555Sambrisko	    control = cdb[5];
1221265555Sambrisko
1222265555Sambrisko	    memset(cdb, 0, sizeof(cdb));
1223265555Sambrisko	    cdb[0] = opcode;
1224265555Sambrisko	    cdb[9] = control;
1225265555Sambrisko
1226265555Sambrisko	    /* Set transfer length */
1227265555Sambrisko	    cdb[8] = (u_int8_t)(num_blocks & 0xff);
1228265555Sambrisko	    cdb[7] = (u_int8_t)((num_blocks >> 8) & 0xff);
1229265555Sambrisko
1230265555Sambrisko	    /* Specify 10-byte cdb */
1231265555Sambrisko	    cdb_len = 10;
1232265555Sambrisko	}
1233265555Sambrisko
1234265555Sambrisko        /* Fall through normal case, just load LBA here */
1235265555Sambrisko        switch (cdb_len)
1236265555Sambrisko        {
1237265555Sambrisko            case 6:
1238265555Sambrisko            {
1239265555Sambrisko                u_int8_t val = cdb[1] & 0xE0;
1240265555Sambrisko                cdb[3] = (u_int8_t)(start_blk & 0xff);
1241265555Sambrisko                cdb[2] = (u_int8_t)((start_blk >> 8) & 0xff);
1242265555Sambrisko                cdb[1] = val | ((u_int8_t)(start_blk >> 16) & 0x1f);
1243265555Sambrisko                break;
1244265555Sambrisko            }
1245265555Sambrisko            case 10:
1246265555Sambrisko                cdb[5] = (u_int8_t)(start_blk & 0xff);
1247265555Sambrisko                cdb[4] = (u_int8_t)((start_blk >> 8) & 0xff);
1248265555Sambrisko                cdb[3] = (u_int8_t)((start_blk >> 16) & 0xff);
1249265555Sambrisko                cdb[2] = (u_int8_t)((start_blk >> 24) & 0xff);
1250265555Sambrisko                break;
1251265555Sambrisko            case 12:
1252265555Sambrisko                cdb[5] = (u_int8_t)(start_blk & 0xff);
1253265555Sambrisko                cdb[4] = (u_int8_t)((start_blk >> 8) & 0xff);
1254265555Sambrisko                cdb[3] = (u_int8_t)((start_blk >> 16) & 0xff);
1255265555Sambrisko                cdb[2] = (u_int8_t)((start_blk >> 24) & 0xff);
1256265555Sambrisko                break;
1257265555Sambrisko            case 16:
1258265555Sambrisko                cdb[9] = (u_int8_t)(start_blk & 0xff);
1259265555Sambrisko                cdb[8] = (u_int8_t)((start_blk >> 8) & 0xff);
1260265555Sambrisko                cdb[7] = (u_int8_t)((start_blk >> 16) & 0xff);
1261265555Sambrisko                cdb[6] = (u_int8_t)((start_blk >> 24) & 0xff);
1262265555Sambrisko                cdb[5] = (u_int8_t)((start_blk >> 32) & 0xff);
1263265555Sambrisko                cdb[4] = (u_int8_t)((start_blk >> 40) & 0xff);
1264265555Sambrisko                cdb[3] = (u_int8_t)((start_blk >> 48) & 0xff);
1265265555Sambrisko                cdb[2] = (u_int8_t)((start_blk >> 56) & 0xff);
1266265555Sambrisko                break;
1267265555Sambrisko        }
1268265555Sambrisko    }
1269265555Sambrisko}
1270265555Sambrisko
1271265555Sambrisko/**
1272265555Sambrisko * mrsas_get_best_arm         Determine the best spindle arm
1273265555Sambrisko * Inputs:                    Load balance info
1274265555Sambrisko *
1275265555Sambrisko * This function determines and returns the best arm by looking at the
1276265555Sambrisko * parameters of the last PD access.
1277265555Sambrisko */
1278265555Sambriskou_int8_t mrsas_get_best_arm(PLD_LOAD_BALANCE_INFO lbInfo, u_int8_t arm,
1279265555Sambrisko        u_int64_t block, u_int32_t count)
1280265555Sambrisko{
1281265555Sambrisko    u_int16_t     pend0, pend1;
1282265555Sambrisko    u_int64_t     diff0, diff1;
1283265555Sambrisko    u_int8_t      bestArm;
1284265555Sambrisko
1285265555Sambrisko    /* get the pending cmds for the data and mirror arms */
1286265555Sambrisko    pend0 = atomic_read(&lbInfo->scsi_pending_cmds[0]);
1287265555Sambrisko    pend1 = atomic_read(&lbInfo->scsi_pending_cmds[1]);
1288265555Sambrisko
1289265555Sambrisko    /* Determine the disk whose head is nearer to the req. block */
1290265555Sambrisko    diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[0]);
1291265555Sambrisko    diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[1]);
1292265555Sambrisko    bestArm = (diff0 <= diff1 ? 0 : 1);
1293265555Sambrisko
1294265555Sambrisko    if ((bestArm == arm && pend0 > pend1 + 16) || (bestArm != arm && pend1 > pend0 + 16))
1295265555Sambrisko        bestArm ^= 1;
1296265555Sambrisko
1297265555Sambrisko    /* Update the last accessed block on the correct pd */
1298265555Sambrisko    lbInfo->last_accessed_block[bestArm] = block + count - 1;
1299265555Sambrisko
1300265555Sambrisko    return bestArm;
1301265555Sambrisko}
1302265555Sambrisko
1303265555Sambrisko/**
1304265555Sambrisko * mrsas_get_updated_dev_handle    Get the update dev handle
1305265555Sambrisko * Inputs:                         Load balance info
1306265555Sambrisko *                                 io_info pointer
1307265555Sambrisko *
1308265555Sambrisko * This function determines and returns the updated dev handle.
1309265555Sambrisko */
1310265555Sambriskou_int16_t mrsas_get_updated_dev_handle(PLD_LOAD_BALANCE_INFO lbInfo,
1311265555Sambrisko        struct IO_REQUEST_INFO *io_info)
1312265555Sambrisko{
1313265555Sambrisko    u_int8_t arm, old_arm;
1314265555Sambrisko    u_int16_t devHandle;
1315265555Sambrisko
1316265555Sambrisko    old_arm = lbInfo->raid1DevHandle[0] == io_info->devHandle ? 0 : 1;
1317265555Sambrisko
1318265555Sambrisko    /* get best new arm */
1319265555Sambrisko    arm  = mrsas_get_best_arm(lbInfo, old_arm, io_info->ldStartBlock, io_info->numBlocks);
1320265555Sambrisko    devHandle = lbInfo->raid1DevHandle[arm];
1321265555Sambrisko    atomic_inc(&lbInfo->scsi_pending_cmds[arm]);
1322265555Sambrisko
1323265555Sambrisko    return devHandle;
1324265555Sambrisko}
1325265555Sambrisko
1326265555Sambrisko/**
1327265555Sambrisko * MR_GetPhyParams     Calculates arm, span, and block
1328265555Sambrisko * Inputs:             Adapter instance soft state
1329265555Sambrisko *                     Logical drive number (LD)
1330265555Sambrisko *                     Stripe number (stripRow)
1331265555Sambrisko *                     Reference in stripe (stripRef)
1332265555Sambrisko * Outputs:            Span number
1333265555Sambrisko *                     Absolute Block number in the physical disk
1334265555Sambrisko *
1335265555Sambrisko * This routine calculates the arm, span and block for the specified stripe
1336265555Sambrisko * and reference in stripe.
1337265555Sambrisko */
1338265555Sambriskou_int8_t MR_GetPhyParams(struct mrsas_softc *sc, u_int32_t ld,
1339265555Sambrisko            u_int64_t stripRow,
1340265555Sambrisko            u_int16_t stripRef, struct IO_REQUEST_INFO *io_info,
1341265555Sambrisko            RAID_CONTEXT *pRAID_Context, MR_FW_RAID_MAP_ALL *map)
1342265555Sambrisko{
1343265555Sambrisko    MR_LD_RAID  *raid = MR_LdRaidGet(ld, map);
1344265555Sambrisko    u_int32_t pd, arRef;
1345265555Sambrisko    u_int8_t physArm, span;
1346265555Sambrisko    u_int64_t row;
1347265555Sambrisko    u_int8_t retval = TRUE;
1348265555Sambrisko    int error_code = 0;
1349265555Sambrisko	u_int64_t *pdBlock = &io_info->pdBlock;
1350265555Sambrisko    u_int16_t *pDevHandle = &io_info->devHandle;
1351265555Sambrisko    u_int32_t rowMod, armQ, arm, logArm;
1352265555Sambrisko	u_int8_t do_invader = 0;
1353265555Sambrisko
1354265555Sambrisko	if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY))
1355265555Sambrisko		do_invader = 1;
1356265555Sambrisko
1357265555Sambrisko    row =  mega_div64_32(stripRow, raid->rowDataSize);
1358265555Sambrisko
1359265555Sambrisko    if (raid->level == 6) {
1360265555Sambrisko        logArm = mega_mod64(stripRow, raid->rowDataSize); // logical arm within row
1361265555Sambrisko        if (raid->rowSize == 0)
1362265555Sambrisko            return FALSE;
1363265555Sambrisko        rowMod = mega_mod64(row, raid->rowSize);  // get logical row mod
1364265555Sambrisko        armQ = raid->rowSize-1-rowMod;  // index of Q drive
1365265555Sambrisko        arm = armQ+1+logArm;    // data always logically follows Q
1366265555Sambrisko        if (arm >= raid->rowSize)         // handle wrap condition
1367265555Sambrisko            arm -= raid->rowSize;
1368265555Sambrisko        physArm = (u_int8_t)arm;
1369265555Sambrisko    }
1370265555Sambrisko    else {
1371265555Sambrisko        if (raid->modFactor == 0)
1372265555Sambrisko            return FALSE;
1373265555Sambrisko        physArm = MR_LdDataArmGet(ld, mega_mod64(stripRow, raid->modFactor), map);
1374265555Sambrisko    }
1375265555Sambrisko
1376265555Sambrisko    if (raid->spanDepth == 1) {
1377265555Sambrisko        span = 0;
1378265555Sambrisko        *pdBlock = row << raid->stripeShift;
1379265555Sambrisko    }
1380265555Sambrisko    else {
1381265555Sambrisko        span = (u_int8_t)MR_GetSpanBlock(ld, row, pdBlock, map, &error_code);
1382265555Sambrisko        if (error_code == 1)
1383265555Sambrisko            return FALSE;
1384265555Sambrisko    }
1385265555Sambrisko
1386265555Sambrisko    /*  Get the array on which this span is present */
1387265555Sambrisko    arRef = MR_LdSpanArrayGet(ld, span, map);
1388265555Sambrisko
1389265555Sambrisko    pd = MR_ArPdGet(arRef, physArm, map);     // Get the Pd.
1390265555Sambrisko
1391265555Sambrisko    if (pd != MR_PD_INVALID)
1392265555Sambrisko        *pDevHandle = MR_PdDevHandleGet(pd, map);  // Get dev handle from Pd.
1393265555Sambrisko    else {
1394265555Sambrisko        *pDevHandle = MR_PD_INVALID; // set dev handle as invalid.
1395265555Sambrisko        if ((raid->level >= 5) && ((!do_invader) || (do_invader &&
1396265555Sambrisko             raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))
1397265555Sambrisko             pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
1398265555Sambrisko        else if (raid->level == 1) {
1399265555Sambrisko            pd = MR_ArPdGet(arRef, physArm + 1, map); // Get Alternate Pd.
1400265555Sambrisko            if (pd != MR_PD_INVALID)
1401265555Sambrisko                *pDevHandle = MR_PdDevHandleGet(pd, map);//Get dev handle from Pd.
1402265555Sambrisko        }
1403265555Sambrisko    }
1404265555Sambrisko
1405265555Sambrisko    *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk;
1406265555Sambrisko    pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm;
1407265555Sambrisko    return retval;
1408265555Sambrisko}
1409265555Sambrisko
1410265555Sambrisko/**
1411265555Sambrisko * MR_GetSpanBlock     Calculates span block
1412265555Sambrisko * Inputs:             LD
1413265555Sambrisko *                     row
1414265555Sambrisko *                     PD span block
1415265555Sambrisko *                     RAID map pointer
1416265555Sambrisko * Outputs:            Span number
1417265555Sambrisko *                     Error code
1418265555Sambrisko *
1419265555Sambrisko * This routine calculates the span from the span block info.
1420265555Sambrisko */
1421265555Sambriskou_int32_t MR_GetSpanBlock(u_int32_t ld, u_int64_t row, u_int64_t *span_blk,
1422265555Sambrisko        MR_FW_RAID_MAP_ALL *map, int *div_error)
1423265555Sambrisko{
1424265555Sambrisko    MR_SPAN_BLOCK_INFO *pSpanBlock = MR_LdSpanInfoGet(ld, map);
1425265555Sambrisko    MR_QUAD_ELEMENT *quad;
1426265555Sambrisko    MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
1427265555Sambrisko    u_int32_t span, j;
1428265555Sambrisko    u_int64_t blk, debugBlk;
1429265555Sambrisko
1430265555Sambrisko    for (span=0; span < raid->spanDepth; span++, pSpanBlock++) {
1431265555Sambrisko        for (j=0; j < pSpanBlock->block_span_info.noElements; j++) {
1432265555Sambrisko            quad = &pSpanBlock->block_span_info.quad[j];
1433265555Sambrisko            if (quad->diff == 0) {
1434265555Sambrisko                *div_error = 1;
1435265555Sambrisko                return span;
1436265555Sambrisko            }
1437265555Sambrisko            if (quad->logStart <= row  &&  row <= quad->logEnd  &&
1438265555Sambrisko                    (mega_mod64(row-quad->logStart, quad->diff)) == 0) {
1439265555Sambrisko                if (span_blk != NULL) {
1440265555Sambrisko                    blk =  mega_div64_32((row-quad->logStart), quad->diff);
1441265555Sambrisko                    debugBlk = blk;
1442265555Sambrisko                    blk = (blk + quad->offsetInSpan) << raid->stripeShift;
1443265555Sambrisko                    *span_blk = blk;
1444265555Sambrisko                }
1445265555Sambrisko                return span;
1446265555Sambrisko            }
1447265555Sambrisko        }
1448265555Sambrisko    }
1449265555Sambrisko    return span;
1450265555Sambrisko}
1451265555Sambrisko
1452