2 * Copyright (c) 2014, LSI Corp. All rights reserved. Author: Marian Choy
3 * Support: freebsdraid@lsi.com
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer. 2. Redistributions
11 * in binary form must reproduce the above copyright notice, this list of
12 * conditions and the following disclaimer in the documentation and/or other
13 * materials provided with the distribution. 3. Neither the name of the
14 * <ORGANIZATION> nor the names of its contributors may be used to endorse or
15 * promote products derived from this software without specific prior written
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
30 * The views and conclusions contained in the software and documentation are
31 * those of the authors and should not be interpreted as representing
32 * official policies,either expressed or implied, of the FreeBSD Project.
34 * Send feedback to: <megaraidfbsd@lsi.com> Mail to: LSI Corporation, 1621
35 * Barber Lane, Milpitas, CA 95035 ATTN: MegaRaid FreeBSD
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
42 #include <dev/mrsas/mrsas.h>
45 #include <cam/cam_ccb.h>
46 #include <cam/cam_sim.h>
47 #include <cam/cam_xpt_sim.h>
48 #include <cam/cam_debug.h>
49 #include <cam/cam_periph.h>
50 #include <cam/cam_xpt_periph.h>
56 u_int8_t MR_ValidateMapInfo(struct mrsas_softc *sc);
58 mrsas_get_best_arm(PLD_LOAD_BALANCE_INFO lbInfo, u_int8_t arm,
59 u_int64_t block, u_int32_t count);
61 MR_BuildRaidContext(struct mrsas_softc *sc,
62 struct IO_REQUEST_INFO *io_info,
63 RAID_CONTEXT * pRAID_Context, MR_DRV_RAID_MAP_ALL * map);
65 MR_GetPhyParams(struct mrsas_softc *sc, u_int32_t ld,
66 u_int64_t stripRow, u_int16_t stripRef, struct IO_REQUEST_INFO *io_info,
67 RAID_CONTEXT * pRAID_Context,
68 MR_DRV_RAID_MAP_ALL * map);
69 u_int16_t MR_TargetIdToLdGet(u_int32_t ldTgtId, MR_DRV_RAID_MAP_ALL * map);
70 u_int32_t MR_LdBlockSizeGet(u_int32_t ldTgtId, MR_DRV_RAID_MAP_ALL * map);
71 u_int16_t MR_GetLDTgtId(u_int32_t ld, MR_DRV_RAID_MAP_ALL * map);
73 mrsas_get_updated_dev_handle(PLD_LOAD_BALANCE_INFO lbInfo,
74 struct IO_REQUEST_INFO *io_info);
75 u_int32_t mega_mod64(u_int64_t dividend, u_int32_t divisor);
77 MR_GetSpanBlock(u_int32_t ld, u_int64_t row, u_int64_t *span_blk,
78 MR_DRV_RAID_MAP_ALL * map, int *div_error);
79 u_int64_t mega_div64_32(u_int64_t dividend, u_int32_t divisor);
81 mrsas_update_load_balance_params(MR_DRV_RAID_MAP_ALL * map,
82 PLD_LOAD_BALANCE_INFO lbInfo);
84 mrsas_set_pd_lba(MRSAS_RAID_SCSI_IO_REQUEST * io_request,
85 u_int8_t cdb_len, struct IO_REQUEST_INFO *io_info, union ccb *ccb,
86 MR_DRV_RAID_MAP_ALL * local_map_ptr, u_int32_t ref_tag,
87 u_int32_t ld_block_size);
89 MR_LdSpanArrayGet(u_int32_t ld, u_int32_t span,
90 MR_DRV_RAID_MAP_ALL * map);
91 static u_int16_t MR_PdDevHandleGet(u_int32_t pd, MR_DRV_RAID_MAP_ALL * map);
93 MR_ArPdGet(u_int32_t ar, u_int32_t arm,
94 MR_DRV_RAID_MAP_ALL * map);
96 MR_LdSpanPtrGet(u_int32_t ld, u_int32_t span,
97 MR_DRV_RAID_MAP_ALL * map);
99 MR_LdDataArmGet(u_int32_t ld, u_int32_t armIdx,
100 MR_DRV_RAID_MAP_ALL * map);
101 static MR_SPAN_BLOCK_INFO *
102 MR_LdSpanInfoGet(u_int32_t ld,
103 MR_DRV_RAID_MAP_ALL * map);
104 MR_LD_RAID *MR_LdRaidGet(u_int32_t ld, MR_DRV_RAID_MAP_ALL * map);
105 void MR_PopulateDrvRaidMap(struct mrsas_softc *sc);
109 * Spanset related function prototypes Added for PRL11 configuration (Uneven
112 void mr_update_span_set(MR_DRV_RAID_MAP_ALL * map, PLD_SPAN_INFO ldSpanInfo);
114 mr_spanset_get_phy_params(struct mrsas_softc *sc, u_int32_t ld,
115 u_int64_t stripRow, u_int16_t stripRef, struct IO_REQUEST_INFO *io_info,
116 RAID_CONTEXT * pRAID_Context, MR_DRV_RAID_MAP_ALL * map);
118 get_row_from_strip(struct mrsas_softc *sc, u_int32_t ld,
119 u_int64_t strip, MR_DRV_RAID_MAP_ALL * map);
121 mr_spanset_get_span_block(struct mrsas_softc *sc,
122 u_int32_t ld, u_int64_t row, u_int64_t *span_blk,
123 MR_DRV_RAID_MAP_ALL * map, int *div_error);
125 get_arm(struct mrsas_softc *sc, u_int32_t ld, u_int8_t span,
126 u_int64_t stripe, MR_DRV_RAID_MAP_ALL * map);
130 * Spanset related defines Added for PRL11 configuration(Uneven span support)
132 #define SPAN_ROW_SIZE(map, ld, index_) MR_LdSpanPtrGet(ld, index_, map)->spanRowSize
133 #define SPAN_ROW_DATA_SIZE(map_, ld, index_) \
134 MR_LdSpanPtrGet(ld, index_, map)->spanRowDataSize
135 #define SPAN_INVALID 0xff
142 typedef u_int64_t REGION_KEY;
143 typedef u_int32_t REGION_LEN;
145 #define MR_LD_STATE_OPTIMAL 3
154 #define ABS_DIFF(a,b) ( ((a) > (b)) ? ((a) - (b)) : ((b) - (a)) )
158 (((unsigned int)(x) & (unsigned int)0x000000ffUL) << 24) | \
159 (((unsigned int)(x) & (unsigned int)0x0000ff00UL) << 8) | \
160 (((unsigned int)(x) & (unsigned int)0x00ff0000UL) >> 8) | \
161 (((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24) ))
165 * In-line functions for mod and divide of 64-bit dividend and 32-bit
166 * divisor. Assumes a check for a divisor of zero is not possible.
168 * @param dividend: Dividend
169 * @param divisor: Divisor
173 #define mega_mod64(dividend, divisor) ({ \
175 remainder = ((u_int64_t) (dividend)) % (u_int32_t) (divisor); \
178 #define mega_div64_32(dividend, divisor) ({ \
180 quotient = ((u_int64_t) (dividend)) / (u_int32_t) (divisor); \
185 * Various RAID map access functions. These functions access the various
186 * parts of the RAID map and returns the appropriate parameters.
190 MR_LdRaidGet(u_int32_t ld, MR_DRV_RAID_MAP_ALL * map)
192 return (&map->raidMap.ldSpanMap[ld].ldRaid);
196 MR_GetLDTgtId(u_int32_t ld, MR_DRV_RAID_MAP_ALL * map)
198 return (map->raidMap.ldSpanMap[ld].ldRaid.targetId);
202 MR_LdSpanArrayGet(u_int32_t ld, u_int32_t span, MR_DRV_RAID_MAP_ALL * map)
204 return map->raidMap.ldSpanMap[ld].spanBlock[span].span.arrayRef;
208 MR_LdDataArmGet(u_int32_t ld, u_int32_t armIdx, MR_DRV_RAID_MAP_ALL * map)
210 return map->raidMap.ldSpanMap[ld].dataArmMap[armIdx];
214 MR_PdDevHandleGet(u_int32_t pd, MR_DRV_RAID_MAP_ALL * map)
216 return map->raidMap.devHndlInfo[pd].curDevHdl;
220 MR_ArPdGet(u_int32_t ar, u_int32_t arm, MR_DRV_RAID_MAP_ALL * map)
222 return map->raidMap.arMapInfo[ar].pd[arm];
226 MR_LdSpanPtrGet(u_int32_t ld, u_int32_t span, MR_DRV_RAID_MAP_ALL * map)
228 return &map->raidMap.ldSpanMap[ld].spanBlock[span].span;
231 static MR_SPAN_BLOCK_INFO *
232 MR_LdSpanInfoGet(u_int32_t ld, MR_DRV_RAID_MAP_ALL * map)
234 return &map->raidMap.ldSpanMap[ld].spanBlock[0];
238 MR_TargetIdToLdGet(u_int32_t ldTgtId, MR_DRV_RAID_MAP_ALL * map)
240 return map->raidMap.ldTgtIdToLd[ldTgtId];
244 MR_LdBlockSizeGet(u_int32_t ldTgtId, MR_DRV_RAID_MAP_ALL * map)
247 u_int32_t ld, ldBlockSize = MRSAS_SCSIBLOCKSIZE;
249 ld = MR_TargetIdToLdGet(ldTgtId, map);
252 * Check if logical drive was removed.
254 if (ld >= MAX_LOGICAL_DRIVES)
257 raid = MR_LdRaidGet(ld, map);
258 ldBlockSize = raid->logicalBlockLength;
260 ldBlockSize = MRSAS_SCSIBLOCKSIZE;
266 * This function will Populate Driver Map using firmware raid map
269 MR_PopulateDrvRaidMap(struct mrsas_softc *sc)
271 MR_FW_RAID_MAP_ALL *fw_map_old = NULL;
272 MR_FW_RAID_MAP *pFwRaidMap = NULL;
275 MR_DRV_RAID_MAP_ALL *drv_map = sc->ld_drv_map[(sc->map_id & 1)];
276 MR_DRV_RAID_MAP *pDrvRaidMap = &drv_map->raidMap;
278 if (sc->max256vdSupport) {
279 memcpy(sc->ld_drv_map[sc->map_id & 1],
280 sc->raidmap_mem[sc->map_id & 1],
283 * New Raid map will not set totalSize, so keep expected
284 * value for legacy code in ValidateMapInfo
286 pDrvRaidMap->totalSize = sizeof(MR_FW_RAID_MAP_EXT);
288 fw_map_old = (MR_FW_RAID_MAP_ALL *) sc->raidmap_mem[(sc->map_id & 1)];
289 pFwRaidMap = &fw_map_old->raidMap;
292 for (i = 0; i < pFwRaidMap->ldCount; i++) {
293 device_printf(sc->mrsas_dev,
294 "Index 0x%x Target Id 0x%x Seq Num 0x%x Size 0/%lx\n", i,
295 fw_map_old->raidMap.ldSpanMap[i].ldRaid.targetId,
296 fw_map_old->raidMap.ldSpanMap[i].ldRaid.seqNum,
297 fw_map_old->raidMap.ldSpanMap[i].ldRaid.size);
301 memset(drv_map, 0, sc->drv_map_sz);
302 pDrvRaidMap->totalSize = pFwRaidMap->totalSize;
303 pDrvRaidMap->ldCount = pFwRaidMap->ldCount;
304 pDrvRaidMap->fpPdIoTimeoutSec =
305 pFwRaidMap->fpPdIoTimeoutSec;
307 for (i = 0; i < MAX_RAIDMAP_LOGICAL_DRIVES + MAX_RAIDMAP_VIEWS; i++) {
308 pDrvRaidMap->ldTgtIdToLd[i] =
309 (u_int8_t)pFwRaidMap->ldTgtIdToLd[i];
312 for (i = 0; i < pDrvRaidMap->ldCount; i++) {
313 pDrvRaidMap->ldSpanMap[i] =
314 pFwRaidMap->ldSpanMap[i];
317 device_printf(sc->mrsas_dev, "pFwRaidMap->ldSpanMap[%d].ldRaid.targetId 0x%x "
318 "pFwRaidMap->ldSpanMap[%d].ldRaid.seqNum 0x%x size 0x%x\n",
319 i, i, pFwRaidMap->ldSpanMap[i].ldRaid.targetId,
320 pFwRaidMap->ldSpanMap[i].ldRaid.seqNum,
321 (u_int32_t)pFwRaidMap->ldSpanMap[i].ldRaid.rowSize);
322 device_printf(sc->mrsas_dev, "pDrvRaidMap->ldSpanMap[%d].ldRaid.targetId 0x%x"
323 "pDrvRaidMap->ldSpanMap[%d].ldRaid.seqNum 0x%x size 0x%x\n", i, i,
324 pDrvRaidMap->ldSpanMap[i].ldRaid.targetId,
325 pDrvRaidMap->ldSpanMap[i].ldRaid.seqNum,
326 (u_int32_t)pDrvRaidMap->ldSpanMap[i].ldRaid.rowSize);
327 device_printf(sc->mrsas_dev, "drv raid map all %p raid map %p LD RAID MAP %p/%p\n",
328 drv_map, pDrvRaidMap,
329 &pFwRaidMap->ldSpanMap[i].ldRaid, &pDrvRaidMap->ldSpanMap[i].ldRaid);
333 memcpy(pDrvRaidMap->arMapInfo, pFwRaidMap->arMapInfo,
334 sizeof(MR_ARRAY_INFO) * MAX_RAIDMAP_ARRAYS);
335 memcpy(pDrvRaidMap->devHndlInfo, pFwRaidMap->devHndlInfo,
336 sizeof(MR_DEV_HANDLE_INFO) *
337 MAX_RAIDMAP_PHYSICAL_DEVICES);
342 * MR_ValidateMapInfo: Validate RAID map
343 * input: Adapter instance soft state
345 * This function checks and validates the loaded RAID map. It returns 0 if
346 * successful, and 1 otherwise.
349 MR_ValidateMapInfo(struct mrsas_softc *sc)
354 MR_PopulateDrvRaidMap(sc);
356 MR_DRV_RAID_MAP_ALL *drv_map = sc->ld_drv_map[(sc->map_id & 1)];
357 MR_DRV_RAID_MAP *pDrvRaidMap = &drv_map->raidMap;
359 u_int32_t expected_map_size;
361 drv_map = sc->ld_drv_map[(sc->map_id & 1)];
362 pDrvRaidMap = &drv_map->raidMap;
363 PLD_SPAN_INFO ldSpanInfo = (PLD_SPAN_INFO) & sc->log_to_span;
365 if (sc->max256vdSupport)
366 expected_map_size = sizeof(MR_FW_RAID_MAP_EXT);
369 (sizeof(MR_FW_RAID_MAP) - sizeof(MR_LD_SPAN_MAP)) +
370 (sizeof(MR_LD_SPAN_MAP) * pDrvRaidMap->ldCount);
372 if (pDrvRaidMap->totalSize != expected_map_size) {
373 device_printf(sc->mrsas_dev, "map size %x not matching ld count\n", expected_map_size);
374 device_printf(sc->mrsas_dev, "span map= %x\n", (unsigned int)sizeof(MR_LD_SPAN_MAP));
375 device_printf(sc->mrsas_dev, "pDrvRaidMap->totalSize=%x\n", pDrvRaidMap->totalSize);
378 if (sc->UnevenSpanSupport) {
379 printf("Updating span set\n\n");
380 mr_update_span_set(drv_map, ldSpanInfo);
382 mrsas_update_load_balance_params(drv_map, sc->load_balance_info);
389 * Function to print info about span set created in driver from FW raid map
392 * ldSpanInfo: ld map span info per HBA instance
398 getSpanInfo(MR_DRV_RAID_MAP_ALL * map, PLD_SPAN_INFO ldSpanInfo)
404 LD_SPAN_SET *span_set;
405 MR_QUAD_ELEMENT *quad;
409 for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++) {
410 ld = MR_TargetIdToLdGet(ldCount, map);
411 if (ld >= MAX_LOGICAL_DRIVES) {
414 raid = MR_LdRaidGet(ld, map);
415 printf("LD %x: span_depth=%x\n", ld, raid->spanDepth);
416 for (span = 0; span < raid->spanDepth; span++)
417 printf("Span=%x, number of quads=%x\n", span,
418 map->raidMap.ldSpanMap[ld].spanBlock[span].
419 block_span_info.noElements);
420 for (element = 0; element < MAX_QUAD_DEPTH; element++) {
421 span_set = &(ldSpanInfo[ld].span_set[element]);
422 if (span_set->span_row_data_width == 0)
425 printf("Span Set %x: width=%x, diff=%x\n", element,
426 (unsigned int)span_set->span_row_data_width,
427 (unsigned int)span_set->diff);
428 printf("logical LBA start=0x%08lx, end=0x%08lx\n",
429 (long unsigned int)span_set->log_start_lba,
430 (long unsigned int)span_set->log_end_lba);
431 printf("span row start=0x%08lx, end=0x%08lx\n",
432 (long unsigned int)span_set->span_row_start,
433 (long unsigned int)span_set->span_row_end);
434 printf("data row start=0x%08lx, end=0x%08lx\n",
435 (long unsigned int)span_set->data_row_start,
436 (long unsigned int)span_set->data_row_end);
437 printf("data strip start=0x%08lx, end=0x%08lx\n",
438 (long unsigned int)span_set->data_strip_start,
439 (long unsigned int)span_set->data_strip_end);
441 for (span = 0; span < raid->spanDepth; span++) {
442 if (map->raidMap.ldSpanMap[ld].spanBlock[span].
443 block_span_info.noElements >= element + 1) {
444 quad = &map->raidMap.ldSpanMap[ld].
445 spanBlock[span].block_span_info.
447 printf("Span=%x, Quad=%x, diff=%x\n", span,
448 element, quad->diff);
449 printf("offset_in_span=0x%08lx\n",
450 (long unsigned int)quad->offsetInSpan);
451 printf("logical start=0x%08lx, end=0x%08lx\n",
452 (long unsigned int)quad->logStart,
453 (long unsigned int)quad->logEnd);
464 * This routine calculates the Span block for given row using spanset.
466 * Inputs : HBA instance
467 * ld: Logical drive number
471 * Outputs : span - Span number block
472 * - Absolute Block number in the physical disk
473 * div_error - Devide error code.
477 mr_spanset_get_span_block(struct mrsas_softc *sc, u_int32_t ld, u_int64_t row,
478 u_int64_t *span_blk, MR_DRV_RAID_MAP_ALL * map, int *div_error)
480 MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
481 LD_SPAN_SET *span_set;
482 MR_QUAD_ELEMENT *quad;
483 u_int32_t span, info;
484 PLD_SPAN_INFO ldSpanInfo = sc->log_to_span;
486 for (info = 0; info < MAX_QUAD_DEPTH; info++) {
487 span_set = &(ldSpanInfo[ld].span_set[info]);
489 if (span_set->span_row_data_width == 0)
491 if (row > span_set->data_row_end)
494 for (span = 0; span < raid->spanDepth; span++)
495 if (map->raidMap.ldSpanMap[ld].spanBlock[span].
496 block_span_info.noElements >= info + 1) {
497 quad = &map->raidMap.ldSpanMap[ld].
499 block_span_info.quad[info];
500 if (quad->diff == 0) {
504 if (quad->logStart <= row &&
505 row <= quad->logEnd &&
506 (mega_mod64(row - quad->logStart,
508 if (span_blk != NULL) {
512 ((row - quad->logStart),
514 blk = (blk + quad->offsetInSpan)
515 << raid->stripeShift;
527 * This routine calculates the row for given strip using spanset.
529 * Inputs : HBA instance
530 * ld: Logical drive number
534 * Outputs : row - row associated with strip
538 get_row_from_strip(struct mrsas_softc *sc,
539 u_int32_t ld, u_int64_t strip, MR_DRV_RAID_MAP_ALL * map)
541 MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
542 LD_SPAN_SET *span_set;
543 PLD_SPAN_INFO ldSpanInfo = sc->log_to_span;
544 u_int32_t info, strip_offset, span, span_offset;
545 u_int64_t span_set_Strip, span_set_Row;
547 for (info = 0; info < MAX_QUAD_DEPTH; info++) {
548 span_set = &(ldSpanInfo[ld].span_set[info]);
550 if (span_set->span_row_data_width == 0)
552 if (strip > span_set->data_strip_end)
555 span_set_Strip = strip - span_set->data_strip_start;
556 strip_offset = mega_mod64(span_set_Strip,
557 span_set->span_row_data_width);
558 span_set_Row = mega_div64_32(span_set_Strip,
559 span_set->span_row_data_width) * span_set->diff;
560 for (span = 0, span_offset = 0; span < raid->spanDepth; span++)
561 if (map->raidMap.ldSpanMap[ld].spanBlock[span].
562 block_span_info.noElements >= info + 1) {
564 span_set->strip_offset[span])
569 mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : Strip 0x%llx, span_set_Strip 0x%llx, span_set_Row 0x%llx "
570 "data width 0x%llx span offset 0x%llx\n", (unsigned long long)strip,
571 (unsigned long long)span_set_Strip,
572 (unsigned long long)span_set_Row,
573 (unsigned long long)span_set->span_row_data_width, (unsigned long long)span_offset);
574 mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : For strip 0x%llx row is 0x%llx\n", (unsigned long long)strip,
575 (unsigned long long)span_set->data_row_start +
576 (unsigned long long)span_set_Row + (span_offset - 1));
577 return (span_set->data_row_start + span_set_Row + (span_offset - 1));
585 * This routine calculates the Start Strip for given row using spanset.
587 * Inputs: HBA instance
588 * ld: Logical drive number
592 * Outputs : Strip - Start strip associated with row
596 get_strip_from_row(struct mrsas_softc *sc,
597 u_int32_t ld, u_int64_t row, MR_DRV_RAID_MAP_ALL * map)
599 MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
600 LD_SPAN_SET *span_set;
601 MR_QUAD_ELEMENT *quad;
602 PLD_SPAN_INFO ldSpanInfo = sc->log_to_span;
603 u_int32_t span, info;
606 for (info = 0; info < MAX_QUAD_DEPTH; info++) {
607 span_set = &(ldSpanInfo[ld].span_set[info]);
609 if (span_set->span_row_data_width == 0)
611 if (row > span_set->data_row_end)
614 for (span = 0; span < raid->spanDepth; span++)
615 if (map->raidMap.ldSpanMap[ld].spanBlock[span].
616 block_span_info.noElements >= info + 1) {
617 quad = &map->raidMap.ldSpanMap[ld].
618 spanBlock[span].block_span_info.quad[info];
619 if (quad->logStart <= row &&
620 row <= quad->logEnd &&
621 mega_mod64((row - quad->logStart),
623 strip = mega_div64_32
624 (((row - span_set->data_row_start)
627 strip *= span_set->span_row_data_width;
628 strip += span_set->data_strip_start;
629 strip += span_set->strip_offset[span];
634 mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug - get_strip_from_row: returns invalid "
635 "strip for ld=%x, row=%lx\n", ld, (long unsigned int)row);
640 * *****************************************************************************
643 * This routine calculates the Physical Arm for given strip using spanset.
645 * Inputs : HBA instance
646 * Logical drive number
650 * Outputs : Phys Arm - Phys Arm associated with strip
654 get_arm_from_strip(struct mrsas_softc *sc,
655 u_int32_t ld, u_int64_t strip, MR_DRV_RAID_MAP_ALL * map)
657 MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
658 LD_SPAN_SET *span_set;
659 PLD_SPAN_INFO ldSpanInfo = sc->log_to_span;
660 u_int32_t info, strip_offset, span, span_offset;
662 for (info = 0; info < MAX_QUAD_DEPTH; info++) {
663 span_set = &(ldSpanInfo[ld].span_set[info]);
665 if (span_set->span_row_data_width == 0)
667 if (strip > span_set->data_strip_end)
670 strip_offset = (u_int32_t)mega_mod64
671 ((strip - span_set->data_strip_start),
672 span_set->span_row_data_width);
674 for (span = 0, span_offset = 0; span < raid->spanDepth; span++)
675 if (map->raidMap.ldSpanMap[ld].spanBlock[span].
676 block_span_info.noElements >= info + 1) {
677 if (strip_offset >= span_set->strip_offset[span])
678 span_offset = span_set->strip_offset[span];
682 mrsas_dprint(sc, MRSAS_PRL11, "LSI PRL11: get_arm_from_strip: "
683 "for ld=0x%x strip=0x%lx arm is 0x%x\n", ld,
684 (long unsigned int)strip, (strip_offset - span_offset));
685 return (strip_offset - span_offset);
688 mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: - get_arm_from_strip: returns invalid arm"
689 " for ld=%x strip=%lx\n", ld, (long unsigned int)strip);
695 /* This Function will return Phys arm */
697 get_arm(struct mrsas_softc *sc, u_int32_t ld, u_int8_t span, u_int64_t stripe,
698 MR_DRV_RAID_MAP_ALL * map)
700 MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
702 /* Need to check correct default value */
705 switch (raid->level) {
709 arm = mega_mod64(stripe, SPAN_ROW_SIZE(map, ld, span));
712 /* start with logical arm */
713 arm = get_arm_from_strip(sc, ld, stripe, map);
723 * This routine calculates the arm, span and block for the specified stripe and
724 * reference in stripe using spanset
726 * Inputs : Logical drive number
727 * stripRow: Stripe number
728 * stripRef: Reference in stripe
730 * Outputs : span - Span number block - Absolute Block
731 * number in the physical disk
734 mr_spanset_get_phy_params(struct mrsas_softc *sc, u_int32_t ld, u_int64_t stripRow,
735 u_int16_t stripRef, struct IO_REQUEST_INFO *io_info,
736 RAID_CONTEXT * pRAID_Context, MR_DRV_RAID_MAP_ALL * map)
738 MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
740 u_int8_t physArm, span;
742 u_int8_t retval = TRUE;
743 u_int64_t *pdBlock = &io_info->pdBlock;
744 u_int16_t *pDevHandle = &io_info->devHandle;
745 u_int32_t logArm, rowMod, armQ, arm;
746 u_int8_t do_invader = 0;
748 if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY))
751 /* Get row and span from io_info for Uneven Span IO. */
752 row = io_info->start_row;
753 span = io_info->start_span;
756 if (raid->level == 6) {
757 logArm = get_arm_from_strip(sc, ld, stripRow, map);
758 rowMod = mega_mod64(row, SPAN_ROW_SIZE(map, ld, span));
759 armQ = SPAN_ROW_SIZE(map, ld, span) - 1 - rowMod;
760 arm = armQ + 1 + logArm;
761 if (arm >= SPAN_ROW_SIZE(map, ld, span))
762 arm -= SPAN_ROW_SIZE(map, ld, span);
763 physArm = (u_int8_t)arm;
765 /* Calculate the arm */
766 physArm = get_arm(sc, ld, span, stripRow, map);
769 arRef = MR_LdSpanArrayGet(ld, span, map);
770 pd = MR_ArPdGet(arRef, physArm, map);
772 if (pd != MR_PD_INVALID)
773 *pDevHandle = MR_PdDevHandleGet(pd, map);
775 *pDevHandle = MR_PD_INVALID;
776 if ((raid->level >= 5) && ((!do_invader) || (do_invader &&
777 raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))
778 pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
779 else if (raid->level == 1) {
780 pd = MR_ArPdGet(arRef, physArm + 1, map);
781 if (pd != MR_PD_INVALID)
782 *pDevHandle = MR_PdDevHandleGet(pd, map);
786 *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk;
787 pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm;
792 * MR_BuildRaidContext: Set up Fast path RAID context
794 * This function will initiate command processing. The start/end row and strip
795 * information is calculated then the lock is acquired. This function will
796 * return 0 if region lock was acquired OR return num strips.
799 MR_BuildRaidContext(struct mrsas_softc *sc, struct IO_REQUEST_INFO *io_info,
800 RAID_CONTEXT * pRAID_Context, MR_DRV_RAID_MAP_ALL * map)
803 u_int32_t ld, stripSize, stripe_mask;
804 u_int64_t endLba, endStrip, endRow, start_row, start_strip;
807 u_int8_t num_strips, numRows;
808 u_int16_t ref_in_start_stripe, ref_in_end_stripe;
809 u_int64_t ldStartBlock;
810 u_int32_t numBlocks, ldTgtId;
811 u_int8_t isRead, stripIdx;
813 u_int8_t startlba_span = SPAN_INVALID;
814 u_int64_t *pdBlock = &io_info->pdBlock;
817 ldStartBlock = io_info->ldStartBlock;
818 numBlocks = io_info->numBlocks;
819 ldTgtId = io_info->ldTgtId;
820 isRead = io_info->isRead;
822 io_info->IoforUnevenSpan = 0;
823 io_info->start_span = SPAN_INVALID;
825 ld = MR_TargetIdToLdGet(ldTgtId, map);
826 raid = MR_LdRaidGet(ld, map);
828 if (raid->rowDataSize == 0) {
829 if (MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize == 0)
831 else if (sc->UnevenSpanSupport) {
832 io_info->IoforUnevenSpan = 1;
834 mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: raid->rowDataSize is 0, but has SPAN[0] rowDataSize = 0x%0x,"
835 " but there is _NO_ UnevenSpanSupport\n",
836 MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize);
840 stripSize = 1 << raid->stripeShift;
841 stripe_mask = stripSize - 1;
843 * calculate starting row and stripe, and number of strips and rows
845 start_strip = ldStartBlock >> raid->stripeShift;
846 ref_in_start_stripe = (u_int16_t)(ldStartBlock & stripe_mask);
847 endLba = ldStartBlock + numBlocks - 1;
848 ref_in_end_stripe = (u_int16_t)(endLba & stripe_mask);
849 endStrip = endLba >> raid->stripeShift;
850 num_strips = (u_int8_t)(endStrip - start_strip + 1); /* End strip */
851 if (io_info->IoforUnevenSpan) {
852 start_row = get_row_from_strip(sc, ld, start_strip, map);
853 endRow = get_row_from_strip(sc, ld, endStrip, map);
854 if (raid->spanDepth == 1) {
856 *pdBlock = start_row << raid->stripeShift;
858 startlba_span = (u_int8_t)mr_spanset_get_span_block(sc, ld, start_row,
859 pdBlock, map, &error_code);
860 if (error_code == 1) {
861 mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: return from %s %d. Send IO w/o region lock.\n",
866 if (startlba_span == SPAN_INVALID) {
867 mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: return from %s %d for row 0x%llx,"
868 "start strip %llx endSrip %llx\n", __func__,
869 __LINE__, (unsigned long long)start_row,
870 (unsigned long long)start_strip,
871 (unsigned long long)endStrip);
874 io_info->start_span = startlba_span;
875 io_info->start_row = start_row;
876 mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug: Check Span number from %s %d for row 0x%llx, "
877 " start strip 0x%llx endSrip 0x%llx span 0x%x\n",
878 __func__, __LINE__, (unsigned long long)start_row,
879 (unsigned long long)start_strip,
880 (unsigned long long)endStrip, startlba_span);
881 mrsas_dprint(sc, MRSAS_PRL11, "LSI Debug : 1. start_row 0x%llx endRow 0x%llx Start span 0x%x\n",
882 (unsigned long long)start_row, (unsigned long long)endRow, startlba_span);
884 start_row = mega_div64_32(start_strip, raid->rowDataSize);
885 endRow = mega_div64_32(endStrip, raid->rowDataSize);
888 numRows = (u_int8_t)(endRow - start_row + 1); /* get the row count */
891 * Calculate region info. (Assume region at start of first row, and
892 * assume this IO needs the full row - will adjust if not true.)
894 regStart = start_row << raid->stripeShift;
897 /* Check if we can send this I/O via FastPath */
898 if (raid->capability.fpCapable) {
900 io_info->fpOkForIo = (raid->capability.fpReadCapable &&
901 ((num_strips == 1) ||
902 raid->capability.fpReadAcrossStripe));
904 io_info->fpOkForIo = (raid->capability.fpWriteCapable &&
905 ((num_strips == 1) ||
906 raid->capability.fpWriteAcrossStripe));
908 io_info->fpOkForIo = FALSE;
911 if (num_strips == 1) {
912 regStart += ref_in_start_stripe;
915 } else if (io_info->IoforUnevenSpan == 0) {
917 * For Even span region lock optimization. If the start strip
918 * is the last in the start row
920 if (start_strip == (start_row + 1) * raid->rowDataSize - 1) {
921 regStart += ref_in_start_stripe;
923 * initialize count to sectors from startRef to end
926 regSize = stripSize - ref_in_start_stripe;
928 /* add complete rows in the middle of the transfer */
930 regSize += (numRows - 2) << raid->stripeShift;
932 /* if IO ends within first strip of last row */
933 if (endStrip == endRow * raid->rowDataSize)
934 regSize += ref_in_end_stripe + 1;
936 regSize += stripSize;
938 if (start_strip == (get_strip_from_row(sc, ld, start_row, map) +
939 SPAN_ROW_DATA_SIZE(map, ld, startlba_span) - 1)) {
940 regStart += ref_in_start_stripe;
942 * initialize count to sectors from startRef to end
945 regSize = stripSize - ref_in_start_stripe;
947 /* add complete rows in the middle of the transfer */
949 regSize += (numRows - 2) << raid->stripeShift;
951 /* if IO ends within first strip of last row */
952 if (endStrip == get_strip_from_row(sc, ld, endRow, map))
953 regSize += ref_in_end_stripe + 1;
955 regSize += stripSize;
957 pRAID_Context->timeoutValue = map->raidMap.fpPdIoTimeoutSec;
958 if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY))
959 pRAID_Context->regLockFlags = (isRead) ? raid->regTypeReqOnRead : raid->regTypeReqOnWrite;
961 pRAID_Context->regLockFlags = (isRead) ? REGION_TYPE_SHARED_READ : raid->regTypeReqOnWrite;
962 pRAID_Context->VirtualDiskTgtId = raid->targetId;
963 pRAID_Context->regLockRowLBA = regStart;
964 pRAID_Context->regLockLength = regSize;
965 pRAID_Context->configSeqNum = raid->seqNum;
968 * Get Phy Params only if FP capable, or else leave it to MR firmware
969 * to do the calculation.
971 if (io_info->fpOkForIo) {
972 retval = io_info->IoforUnevenSpan ?
973 mr_spanset_get_phy_params(sc, ld, start_strip,
974 ref_in_start_stripe, io_info, pRAID_Context, map) :
975 MR_GetPhyParams(sc, ld, start_strip,
976 ref_in_start_stripe, io_info, pRAID_Context, map);
977 /* If IO on an invalid Pd, then FP is not possible */
978 if (io_info->devHandle == MR_PD_INVALID)
979 io_info->fpOkForIo = FALSE;
982 for (stripIdx = 0; stripIdx < num_strips; stripIdx++) {
983 retval = io_info->IoforUnevenSpan ?
984 mr_spanset_get_phy_params(sc, ld, start_strip + stripIdx,
985 ref_in_start_stripe, io_info, pRAID_Context, map) :
986 MR_GetPhyParams(sc, ld, start_strip + stripIdx,
987 ref_in_start_stripe, io_info, pRAID_Context, map);
993 /* Just for testing what arm we get for strip. */
994 get_arm_from_strip(sc, ld, start_strip, map);
1001 * This routine pepare spanset info from Valid Raid map and store it into local
1002 * copy of ldSpanInfo per instance data structure.
1005 * ldSpanInfo per HBA instance
1009 mr_update_span_set(MR_DRV_RAID_MAP_ALL * map, PLD_SPAN_INFO ldSpanInfo)
1011 u_int8_t span, count;
1012 u_int32_t element, span_row_width;
1015 LD_SPAN_SET *span_set, *span_set_prev;
1016 MR_QUAD_ELEMENT *quad;
1020 for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++) {
1021 ld = MR_TargetIdToLdGet(ldCount, map);
1022 if (ld >= MAX_LOGICAL_DRIVES)
1024 raid = MR_LdRaidGet(ld, map);
1025 for (element = 0; element < MAX_QUAD_DEPTH; element++) {
1026 for (span = 0; span < raid->spanDepth; span++) {
1027 if (map->raidMap.ldSpanMap[ld].spanBlock[span].
1028 block_span_info.noElements < element + 1)
1031 span_set = &(ldSpanInfo[ld].span_set[element]);
1032 quad = &map->raidMap.ldSpanMap[ld].
1033 spanBlock[span].block_span_info.quad[element];
1035 span_set->diff = quad->diff;
1037 for (count = 0, span_row_width = 0;
1038 count < raid->spanDepth; count++) {
1039 if (map->raidMap.ldSpanMap[ld].spanBlock[count].
1040 block_span_info.noElements >= element + 1) {
1041 span_set->strip_offset[count] = span_row_width;
1043 MR_LdSpanPtrGet(ld, count, map)->spanRowDataSize;
1045 printf("LSI Debug span %x rowDataSize %x\n", count,
1046 MR_LdSpanPtrGet(ld, count, map)->spanRowDataSize);
1051 span_set->span_row_data_width = span_row_width;
1052 span_row = mega_div64_32(((quad->logEnd -
1053 quad->logStart) + quad->diff), quad->diff);
1056 span_set->log_start_lba = 0;
1057 span_set->log_end_lba =
1058 ((span_row << raid->stripeShift) * span_row_width) - 1;
1060 span_set->span_row_start = 0;
1061 span_set->span_row_end = span_row - 1;
1063 span_set->data_strip_start = 0;
1064 span_set->data_strip_end = (span_row * span_row_width) - 1;
1066 span_set->data_row_start = 0;
1067 span_set->data_row_end = (span_row * quad->diff) - 1;
1069 span_set_prev = &(ldSpanInfo[ld].span_set[element - 1]);
1070 span_set->log_start_lba = span_set_prev->log_end_lba + 1;
1071 span_set->log_end_lba = span_set->log_start_lba +
1072 ((span_row << raid->stripeShift) * span_row_width) - 1;
1074 span_set->span_row_start = span_set_prev->span_row_end + 1;
1075 span_set->span_row_end =
1076 span_set->span_row_start + span_row - 1;
1078 span_set->data_strip_start =
1079 span_set_prev->data_strip_end + 1;
1080 span_set->data_strip_end = span_set->data_strip_start +
1081 (span_row * span_row_width) - 1;
1083 span_set->data_row_start = span_set_prev->data_row_end + 1;
1084 span_set->data_row_end = span_set->data_row_start +
1085 (span_row * quad->diff) - 1;
1089 if (span == raid->spanDepth)
1090 break; /* no quads remain */
1094 getSpanInfo(map, ldSpanInfo); /* to get span set info */
1099 * mrsas_update_load_balance_params: Update load balance parmas
1100 * Inputs: map pointer
1103 * This function updates the load balance parameters for the LD config of a two
1104 * drive optimal RAID-1.
1107 mrsas_update_load_balance_params(MR_DRV_RAID_MAP_ALL * map,
1108 PLD_LOAD_BALANCE_INFO lbInfo)
1112 u_int32_t pd, arRef;
1115 for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++) {
1116 ld = MR_TargetIdToLdGet(ldCount, map);
1117 if (ld >= MAX_LOGICAL_DRIVES) {
1118 lbInfo[ldCount].loadBalanceFlag = 0;
1121 raid = MR_LdRaidGet(ld, map);
1123 /* Two drive Optimal RAID 1 */
1124 if ((raid->level == 1) && (raid->rowSize == 2) &&
1125 (raid->spanDepth == 1)
1126 && raid->ldState == MR_LD_STATE_OPTIMAL) {
1127 lbInfo[ldCount].loadBalanceFlag = 1;
1129 /* Get the array on which this span is present */
1130 arRef = MR_LdSpanArrayGet(ld, 0, map);
1133 pd = MR_ArPdGet(arRef, 0, map);
1134 /* Get dev handle from PD */
1135 lbInfo[ldCount].raid1DevHandle[0] = MR_PdDevHandleGet(pd, map);
1136 pd = MR_ArPdGet(arRef, 1, map);
1137 lbInfo[ldCount].raid1DevHandle[1] = MR_PdDevHandleGet(pd, map);
1139 lbInfo[ldCount].loadBalanceFlag = 0;
1145 * mrsas_set_pd_lba: Sets PD LBA
1146 * input: io_request pointer
1150 * Local RAID map pointer
1151 * Start block of IO Block Size
1153 * Used to set the PD logical block address in CDB for FP IOs.
1156 mrsas_set_pd_lba(MRSAS_RAID_SCSI_IO_REQUEST * io_request, u_int8_t cdb_len,
1157 struct IO_REQUEST_INFO *io_info, union ccb *ccb,
1158 MR_DRV_RAID_MAP_ALL * local_map_ptr, u_int32_t ref_tag,
1159 u_int32_t ld_block_size)
1163 u_int64_t start_blk = io_info->pdBlock;
1164 u_int8_t *cdb = io_request->CDB.CDB32;
1165 u_int32_t num_blocks = io_info->numBlocks;
1166 u_int8_t opcode = 0, flagvals = 0, groupnum = 0, control = 0;
1167 struct ccb_hdr *ccb_h = &(ccb->ccb_h);
1169 /* Check if T10 PI (DIF) is enabled for this LD */
1170 ld = MR_TargetIdToLdGet(io_info->ldTgtId, local_map_ptr);
1171 raid = MR_LdRaidGet(ld, local_map_ptr);
1172 if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER) {
1173 memset(cdb, 0, sizeof(io_request->CDB.CDB32));
1174 cdb[0] = MRSAS_SCSI_VARIABLE_LENGTH_CMD;
1175 cdb[7] = MRSAS_SCSI_ADDL_CDB_LEN;
1177 if (ccb_h->flags == CAM_DIR_OUT)
1178 cdb[9] = MRSAS_SCSI_SERVICE_ACTION_READ32;
1180 cdb[9] = MRSAS_SCSI_SERVICE_ACTION_WRITE32;
1181 cdb[10] = MRSAS_RD_WR_PROTECT_CHECK_ALL;
1184 cdb[12] = (u_int8_t)((start_blk >> 56) & 0xff);
1185 cdb[13] = (u_int8_t)((start_blk >> 48) & 0xff);
1186 cdb[14] = (u_int8_t)((start_blk >> 40) & 0xff);
1187 cdb[15] = (u_int8_t)((start_blk >> 32) & 0xff);
1188 cdb[16] = (u_int8_t)((start_blk >> 24) & 0xff);
1189 cdb[17] = (u_int8_t)((start_blk >> 16) & 0xff);
1190 cdb[18] = (u_int8_t)((start_blk >> 8) & 0xff);
1191 cdb[19] = (u_int8_t)(start_blk & 0xff);
1193 /* Logical block reference tag */
1194 io_request->CDB.EEDP32.PrimaryReferenceTag = swap32(ref_tag);
1195 io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0xffff;
1196 io_request->IoFlags = 32; /* Specify 32-byte cdb */
1198 /* Transfer length */
1199 cdb[28] = (u_int8_t)((num_blocks >> 24) & 0xff);
1200 cdb[29] = (u_int8_t)((num_blocks >> 16) & 0xff);
1201 cdb[30] = (u_int8_t)((num_blocks >> 8) & 0xff);
1202 cdb[31] = (u_int8_t)(num_blocks & 0xff);
1204 /* set SCSI IO EEDP Flags */
1205 if (ccb_h->flags == CAM_DIR_OUT) {
1206 io_request->EEDPFlags =
1207 MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
1208 MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
1209 MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP |
1210 MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG |
1211 MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
1213 io_request->EEDPFlags =
1214 MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
1215 MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
1217 io_request->Control |= (0x4 << 26);
1218 io_request->EEDPBlockSize = ld_block_size;
1220 /* Some drives don't support 16/12 byte CDB's, convert to 10 */
1221 if (((cdb_len == 12) || (cdb_len == 16)) &&
1222 (start_blk <= 0xffffffff)) {
1223 if (cdb_len == 16) {
1224 opcode = cdb[0] == READ_16 ? READ_10 : WRITE_10;
1229 opcode = cdb[0] == READ_12 ? READ_10 : WRITE_10;
1235 memset(cdb, 0, sizeof(io_request->CDB.CDB32));
1242 /* Transfer length */
1243 cdb[8] = (u_int8_t)(num_blocks & 0xff);
1244 cdb[7] = (u_int8_t)((num_blocks >> 8) & 0xff);
1246 io_request->IoFlags = 10; /* Specify 10-byte cdb */
1248 } else if ((cdb_len < 16) && (start_blk > 0xffffffff)) {
1249 /* Convert to 16 byte CDB for large LBA's */
1252 opcode = cdb[0] == READ_6 ? READ_16 : WRITE_16;
1256 opcode = cdb[0] == READ_10 ? READ_16 : WRITE_16;
1262 opcode = cdb[0] == READ_12 ? READ_16 : WRITE_16;
1269 memset(cdb, 0, sizeof(io_request->CDB.CDB32));
1276 /* Transfer length */
1277 cdb[13] = (u_int8_t)(num_blocks & 0xff);
1278 cdb[12] = (u_int8_t)((num_blocks >> 8) & 0xff);
1279 cdb[11] = (u_int8_t)((num_blocks >> 16) & 0xff);
1280 cdb[10] = (u_int8_t)((num_blocks >> 24) & 0xff);
1282 io_request->IoFlags = 16; /* Specify 16-byte cdb */
1284 } else if ((cdb_len == 6) && (start_blk > 0x1fffff)) {
1285 /* convert to 10 byte CDB */
1286 opcode = cdb[0] == READ_6 ? READ_10 : WRITE_10;
1289 memset(cdb, 0, sizeof(io_request->CDB.CDB32));
1293 /* Set transfer length */
1294 cdb[8] = (u_int8_t)(num_blocks & 0xff);
1295 cdb[7] = (u_int8_t)((num_blocks >> 8) & 0xff);
1297 /* Specify 10-byte cdb */
1300 /* Fall through normal case, just load LBA here */
1301 u_int8_t val = cdb[1] & 0xE0;
1304 cdb[3] = (u_int8_t)(start_blk & 0xff);
1305 cdb[2] = (u_int8_t)((start_blk >> 8) & 0xff);
1306 cdb[1] = val | ((u_int8_t)(start_blk >> 16) & 0x1f);
1309 cdb[5] = (u_int8_t)(start_blk & 0xff);
1310 cdb[4] = (u_int8_t)((start_blk >> 8) & 0xff);
1311 cdb[3] = (u_int8_t)((start_blk >> 16) & 0xff);
1312 cdb[2] = (u_int8_t)((start_blk >> 24) & 0xff);
1315 cdb[5] = (u_int8_t)(start_blk & 0xff);
1316 cdb[4] = (u_int8_t)((start_blk >> 8) & 0xff);
1317 cdb[3] = (u_int8_t)((start_blk >> 16) & 0xff);
1318 cdb[2] = (u_int8_t)((start_blk >> 24) & 0xff);
1321 cdb[9] = (u_int8_t)(start_blk & 0xff);
1322 cdb[8] = (u_int8_t)((start_blk >> 8) & 0xff);
1323 cdb[7] = (u_int8_t)((start_blk >> 16) & 0xff);
1324 cdb[6] = (u_int8_t)((start_blk >> 24) & 0xff);
1325 cdb[5] = (u_int8_t)((start_blk >> 32) & 0xff);
1326 cdb[4] = (u_int8_t)((start_blk >> 40) & 0xff);
1327 cdb[3] = (u_int8_t)((start_blk >> 48) & 0xff);
1328 cdb[2] = (u_int8_t)((start_blk >> 56) & 0xff);
1335 * mrsas_get_best_arm: Determine the best spindle arm
1336 * Inputs: Load balance info
1338 * This function determines and returns the best arm by looking at the
1339 * parameters of the last PD access.
1342 mrsas_get_best_arm(PLD_LOAD_BALANCE_INFO lbInfo, u_int8_t arm,
1343 u_int64_t block, u_int32_t count)
1345 u_int16_t pend0, pend1;
1346 u_int64_t diff0, diff1;
1349 /* get the pending cmds for the data and mirror arms */
1350 pend0 = mrsas_atomic_read(&lbInfo->scsi_pending_cmds[0]);
1351 pend1 = mrsas_atomic_read(&lbInfo->scsi_pending_cmds[1]);
1353 /* Determine the disk whose head is nearer to the req. block */
1354 diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[0]);
1355 diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[1]);
1356 bestArm = (diff0 <= diff1 ? 0 : 1);
1358 if ((bestArm == arm && pend0 > pend1 + 16) || (bestArm != arm && pend1 > pend0 + 16))
1361 /* Update the last accessed block on the correct pd */
1362 lbInfo->last_accessed_block[bestArm] = block + count - 1;
1368 * mrsas_get_updated_dev_handle: Get the update dev handle
1369 * Inputs: Load balance info io_info pointer
1371 * This function determines and returns the updated dev handle.
1374 mrsas_get_updated_dev_handle(PLD_LOAD_BALANCE_INFO lbInfo,
1375 struct IO_REQUEST_INFO *io_info)
1377 u_int8_t arm, old_arm;
1378 u_int16_t devHandle;
1380 old_arm = lbInfo->raid1DevHandle[0] == io_info->devHandle ? 0 : 1;
1382 /* get best new arm */
1383 arm = mrsas_get_best_arm(lbInfo, old_arm, io_info->ldStartBlock, io_info->numBlocks);
1384 devHandle = lbInfo->raid1DevHandle[arm];
1385 mrsas_atomic_inc(&lbInfo->scsi_pending_cmds[arm]);
1391 * MR_GetPhyParams: Calculates arm, span, and block
1392 * Inputs: Adapter soft state
1393 * Logical drive number (LD)
1394 * Stripe number(stripRow)
1395 * Reference in stripe (stripRef)
1397 * Outputs: Absolute Block number in the physical disk
1399 * This routine calculates the arm, span and block for the specified stripe and
1400 * reference in stripe.
1403 MR_GetPhyParams(struct mrsas_softc *sc, u_int32_t ld,
1405 u_int16_t stripRef, struct IO_REQUEST_INFO *io_info,
1406 RAID_CONTEXT * pRAID_Context, MR_DRV_RAID_MAP_ALL * map)
1408 MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
1409 u_int32_t pd, arRef;
1410 u_int8_t physArm, span;
1412 u_int8_t retval = TRUE;
1414 u_int64_t *pdBlock = &io_info->pdBlock;
1415 u_int16_t *pDevHandle = &io_info->devHandle;
1416 u_int32_t rowMod, armQ, arm, logArm;
1417 u_int8_t do_invader = 0;
1419 if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY))
1422 row = mega_div64_32(stripRow, raid->rowDataSize);
1424 if (raid->level == 6) {
1425 /* logical arm within row */
1426 logArm = mega_mod64(stripRow, raid->rowDataSize);
1427 if (raid->rowSize == 0)
1429 rowMod = mega_mod64(row, raid->rowSize); /* get logical row mod */
1430 armQ = raid->rowSize - 1 - rowMod; /* index of Q drive */
1431 arm = armQ + 1 + logArm;/* data always logically follows Q */
1432 if (arm >= raid->rowSize) /* handle wrap condition */
1433 arm -= raid->rowSize;
1434 physArm = (u_int8_t)arm;
1436 if (raid->modFactor == 0)
1438 physArm = MR_LdDataArmGet(ld, mega_mod64(stripRow, raid->modFactor), map);
1441 if (raid->spanDepth == 1) {
1443 *pdBlock = row << raid->stripeShift;
1445 span = (u_int8_t)MR_GetSpanBlock(ld, row, pdBlock, map, &error_code);
1446 if (error_code == 1)
1450 /* Get the array on which this span is present */
1451 arRef = MR_LdSpanArrayGet(ld, span, map);
1453 pd = MR_ArPdGet(arRef, physArm, map); /* Get the Pd. */
1455 if (pd != MR_PD_INVALID)
1456 /* Get dev handle from Pd */
1457 *pDevHandle = MR_PdDevHandleGet(pd, map);
1459 *pDevHandle = MR_PD_INVALID; /* set dev handle as invalid. */
1460 if ((raid->level >= 5) && ((!do_invader) || (do_invader &&
1461 raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))
1462 pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
1463 else if (raid->level == 1) {
1464 /* Get Alternate Pd. */
1465 pd = MR_ArPdGet(arRef, physArm + 1, map);
1466 if (pd != MR_PD_INVALID)
1467 /* Get dev handle from Pd. */
1468 *pDevHandle = MR_PdDevHandleGet(pd, map);
1472 *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk;
1473 pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm;
1478 * MR_GetSpanBlock: Calculates span block
1484 * Outputs: Span number Error code
1486 * This routine calculates the span from the span block info.
1489 MR_GetSpanBlock(u_int32_t ld, u_int64_t row, u_int64_t *span_blk,
1490 MR_DRV_RAID_MAP_ALL * map, int *div_error)
1492 MR_SPAN_BLOCK_INFO *pSpanBlock = MR_LdSpanInfoGet(ld, map);
1493 MR_QUAD_ELEMENT *quad;
1494 MR_LD_RAID *raid = MR_LdRaidGet(ld, map);
1496 u_int64_t blk, debugBlk;
1498 for (span = 0; span < raid->spanDepth; span++, pSpanBlock++) {
1499 for (j = 0; j < pSpanBlock->block_span_info.noElements; j++) {
1500 quad = &pSpanBlock->block_span_info.quad[j];
1501 if (quad->diff == 0) {
1505 if (quad->logStart <= row && row <= quad->logEnd &&
1506 (mega_mod64(row - quad->logStart, quad->diff)) == 0) {
1507 if (span_blk != NULL) {
1508 blk = mega_div64_32((row - quad->logStart), quad->diff);
1510 blk = (blk + quad->offsetInSpan) << raid->stripeShift;