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