]> CyberLeo.Net >> Repos - FreeBSD/releng/10.1.git/blob - sys/dev/mrsas/mrsas_fp.c
Copy stable/10@r272459 to releng/10.1 as part of
[FreeBSD/releng/10.1.git] / sys / dev / mrsas / mrsas_fp.c
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  */
61 u_int8_t MR_ValidateMapInfo(struct mrsas_softc *sc);
62 u_int8_t mrsas_get_best_arm(PLD_LOAD_BALANCE_INFO lbInfo, u_int8_t arm, 
63        u_int64_t block, u_int32_t count);
64 u_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);
67 u_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);
71 u_int16_t MR_TargetIdToLdGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map);
72 u_int32_t MR_LdBlockSizeGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map);
73 u_int16_t MR_GetLDTgtId(u_int32_t ld, MR_FW_RAID_MAP_ALL *map);
74 u_int16_t mrsas_get_updated_dev_handle(PLD_LOAD_BALANCE_INFO lbInfo, 
75         struct IO_REQUEST_INFO *io_info);
76 u_int32_t mega_mod64(u_int64_t dividend, u_int32_t divisor);
77 u_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);
79 u_int64_t mega_div64_32(u_int64_t dividend, u_int32_t divisor);
80 void mrsas_update_load_balance_params(MR_FW_RAID_MAP_ALL *map, 
81         PLD_LOAD_BALANCE_INFO lbInfo);
82 void 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);
86 static u_int16_t MR_LdSpanArrayGet(u_int32_t ld, u_int32_t span, 
87         MR_FW_RAID_MAP_ALL *map);
88 static u_int16_t MR_PdDevHandleGet(u_int32_t pd, MR_FW_RAID_MAP_ALL *map);
89 static u_int16_t MR_ArPdGet(u_int32_t ar, u_int32_t arm, 
90         MR_FW_RAID_MAP_ALL *map);
91 static MR_LD_SPAN *MR_LdSpanPtrGet(u_int32_t ld, u_int32_t span, 
92         MR_FW_RAID_MAP_ALL *map);
93 static u_int8_t MR_LdDataArmGet(u_int32_t ld, u_int32_t armIdx, 
94         MR_FW_RAID_MAP_ALL *map);
95 static MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u_int32_t ld, 
96         MR_FW_RAID_MAP_ALL *map);
97 MR_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  */
103 void mr_update_span_set(MR_FW_RAID_MAP_ALL *map, PLD_SPAN_INFO ldSpanInfo);
104 static 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);
107 static 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);
109 static 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);
112 static 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
129 typedef u_int64_t  REGION_KEY;
130 typedef 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) ({ \
161 int remainder; \
162 remainder = ((u_int64_t) (dividend)) % (u_int32_t) (divisor); \
163 remainder;})
164
165 #define mega_div64_32(dividend, divisor) ({ \
166 int quotient; \
167 quotient = ((u_int64_t) (dividend)) / (u_int32_t) (divisor); \
168 quotient;})
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
176 MR_LD_RAID *MR_LdRaidGet(u_int32_t ld, MR_FW_RAID_MAP_ALL *map)
177 {
178     return (&map->raidMap.ldSpanMap[ld].ldRaid);
179 }
180
181 u_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
186 static 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
191 static 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
196 static 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
201 static 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
206 static 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
211 static 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
216 u_int16_t MR_TargetIdToLdGet(u_int32_t ldTgtId, MR_FW_RAID_MAP_ALL *map)
217 {
218     return map->raidMap.ldTgtIdToLd[ldTgtId];
219 }
220
221 u_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  */
249 u_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
290 static 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
371 u_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
432 static 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
491 static 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
548 static 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 */
590 u_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 */
631 static 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 */
696 u_int8_t 
697 MR_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 */
918 void 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  */
1034 void 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  */
1086 void 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(io_request->CDB.CDB32));
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  */
1278 u_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  */
1310 u_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  */
1338 u_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  */
1421 u_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