linux/drivers/scsi/megaraid/megaraid_sas_fp.c
<<
>>
Prefs
   1/*
   2 *  Linux MegaRAID driver for SAS based RAID controllers
   3 *
   4 *  Copyright (c) 2009-2012  LSI Corporation.
   5 *
   6 *  This program is free software; you can redistribute it and/or
   7 *  modify it under the terms of the GNU General Public License
   8 *  as published by the Free Software Foundation; either version 2
   9 *  of the License, or (at your option) any later version.
  10 *
  11 *  This program is distributed in the hope that it will be useful,
  12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 *  GNU General Public License for more details.
  15 *
  16 *  You should have received a copy of the GNU General Public License
  17 *  along with this program; if not, write to the Free Software
  18 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19 *
  20 *  FILE: megaraid_sas_fp.c
  21 *
  22 *  Authors: LSI Corporation
  23 *           Sumant Patro
  24 *           Varad Talamacki
  25 *           Manoj Jose
  26 *
  27 *  Send feedback to: <megaraidlinux@lsi.com>
  28 *
  29 *  Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
  30 *     ATTN: Linuxraid
  31 */
  32
  33#include <linux/kernel.h>
  34#include <linux/types.h>
  35#include <linux/pci.h>
  36#include <linux/list.h>
  37#include <linux/moduleparam.h>
  38#include <linux/module.h>
  39#include <linux/spinlock.h>
  40#include <linux/interrupt.h>
  41#include <linux/delay.h>
  42#include <linux/uio.h>
  43#include <linux/uaccess.h>
  44#include <linux/fs.h>
  45#include <linux/compat.h>
  46#include <linux/blkdev.h>
  47#include <linux/poll.h>
  48
  49#include <scsi/scsi.h>
  50#include <scsi/scsi_cmnd.h>
  51#include <scsi/scsi_device.h>
  52#include <scsi/scsi_host.h>
  53
  54#include "megaraid_sas_fusion.h"
  55#include "megaraid_sas.h"
  56#include <asm/div64.h>
  57
  58#define ABS_DIFF(a, b)   (((a) > (b)) ? ((a) - (b)) : ((b) - (a)))
  59#define MR_LD_STATE_OPTIMAL 3
  60#define FALSE 0
  61#define TRUE 1
  62
  63#define SPAN_DEBUG 0
  64#define SPAN_ROW_SIZE(map, ld, index_) (MR_LdSpanPtrGet(ld, index_, map)->spanRowSize)
  65#define SPAN_ROW_DATA_SIZE(map_, ld, index_)   (MR_LdSpanPtrGet(ld, index_, map)->spanRowDataSize)
  66#define SPAN_INVALID  0xff
  67
  68/* Prototypes */
  69void mr_update_load_balance_params(struct MR_FW_RAID_MAP_ALL *map,
  70        struct LD_LOAD_BALANCE_INFO *lbInfo);
  71
  72static void mr_update_span_set(struct MR_FW_RAID_MAP_ALL *map,
  73        PLD_SPAN_INFO ldSpanInfo);
  74static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld,
  75        u64 stripRow, u16 stripRef, struct IO_REQUEST_INFO *io_info,
  76        struct RAID_CONTEXT *pRAID_Context, struct MR_FW_RAID_MAP_ALL *map);
  77static u64 get_row_from_strip(struct megasas_instance *instance, u32 ld,
  78        u64 strip, struct MR_FW_RAID_MAP_ALL *map);
  79
  80u32 mega_mod64(u64 dividend, u32 divisor)
  81{
  82        u64 d;
  83        u32 remainder;
  84
  85        if (!divisor)
  86                printk(KERN_ERR "megasas : DIVISOR is zero, in div fn\n");
  87        d = dividend;
  88        remainder = do_div(d, divisor);
  89        return remainder;
  90}
  91
  92/**
  93 * @param dividend    : Dividend
  94 * @param divisor    : Divisor
  95 *
  96 * @return quotient
  97 **/
  98u64 mega_div64_32(uint64_t dividend, uint32_t divisor)
  99{
 100        u32 remainder;
 101        u64 d;
 102
 103        if (!divisor)
 104                printk(KERN_ERR "megasas : DIVISOR is zero in mod fn\n");
 105
 106        d = dividend;
 107        remainder = do_div(d, divisor);
 108
 109        return d;
 110}
 111
 112struct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_FW_RAID_MAP_ALL *map)
 113{
 114        return &map->raidMap.ldSpanMap[ld].ldRaid;
 115}
 116
 117static struct MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u32 ld,
 118                                                   struct MR_FW_RAID_MAP_ALL
 119                                                   *map)
 120{
 121        return &map->raidMap.ldSpanMap[ld].spanBlock[0];
 122}
 123
 124static u8 MR_LdDataArmGet(u32 ld, u32 armIdx, struct MR_FW_RAID_MAP_ALL *map)
 125{
 126        return map->raidMap.ldSpanMap[ld].dataArmMap[armIdx];
 127}
 128
 129u16 MR_ArPdGet(u32 ar, u32 arm, struct MR_FW_RAID_MAP_ALL *map)
 130{
 131        return le16_to_cpu(map->raidMap.arMapInfo[ar].pd[arm]);
 132}
 133
 134u16 MR_LdSpanArrayGet(u32 ld, u32 span, struct MR_FW_RAID_MAP_ALL *map)
 135{
 136        return le16_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].span.arrayRef);
 137}
 138
 139u16 MR_PdDevHandleGet(u32 pd, struct MR_FW_RAID_MAP_ALL *map)
 140{
 141        return map->raidMap.devHndlInfo[pd].curDevHdl;
 142}
 143
 144u16 MR_GetLDTgtId(u32 ld, struct MR_FW_RAID_MAP_ALL *map)
 145{
 146        return map->raidMap.ldSpanMap[ld].ldRaid.targetId;
 147}
 148
 149u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map)
 150{
 151        return le16_to_cpu(map->raidMap.ldTgtIdToLd[ldTgtId]);
 152}
 153
 154static struct MR_LD_SPAN *MR_LdSpanPtrGet(u32 ld, u32 span,
 155                                          struct MR_FW_RAID_MAP_ALL *map)
 156{
 157        return &map->raidMap.ldSpanMap[ld].spanBlock[span].span;
 158}
 159
 160/*
 161 * This function will validate Map info data provided by FW
 162 */
 163u8 MR_ValidateMapInfo(struct megasas_instance *instance)
 164{
 165        struct fusion_context *fusion = instance->ctrl_context;
 166        struct MR_FW_RAID_MAP_ALL *map = fusion->ld_map[(instance->map_id & 1)];
 167        struct LD_LOAD_BALANCE_INFO *lbInfo = fusion->load_balance_info;
 168        PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span;
 169        struct MR_FW_RAID_MAP *pFwRaidMap = &map->raidMap;
 170        struct MR_LD_RAID         *raid;
 171        int ldCount, num_lds;
 172        u16 ld;
 173
 174
 175        if (le32_to_cpu(pFwRaidMap->totalSize) !=
 176            (sizeof(struct MR_FW_RAID_MAP) -sizeof(struct MR_LD_SPAN_MAP) +
 177             (sizeof(struct MR_LD_SPAN_MAP) * le32_to_cpu(pFwRaidMap->ldCount)))) {
 178                printk(KERN_ERR "megasas: map info structure size 0x%x is not matching with ld count\n",
 179                       (unsigned int)((sizeof(struct MR_FW_RAID_MAP) -
 180                                       sizeof(struct MR_LD_SPAN_MAP)) +
 181                                      (sizeof(struct MR_LD_SPAN_MAP) *
 182                                        le32_to_cpu(pFwRaidMap->ldCount))));
 183                printk(KERN_ERR "megasas: span map %x, pFwRaidMap->totalSize "
 184                       ": %x\n", (unsigned int)sizeof(struct MR_LD_SPAN_MAP),
 185                        le32_to_cpu(pFwRaidMap->totalSize));
 186                return 0;
 187        }
 188
 189        if (instance->UnevenSpanSupport)
 190                mr_update_span_set(map, ldSpanInfo);
 191
 192        mr_update_load_balance_params(map, lbInfo);
 193
 194        num_lds = le32_to_cpu(map->raidMap.ldCount);
 195
 196        /*Convert Raid capability values to CPU arch */
 197        for (ldCount = 0; ldCount < num_lds; ldCount++) {
 198                ld = MR_TargetIdToLdGet(ldCount, map);
 199                raid = MR_LdRaidGet(ld, map);
 200                le32_to_cpus((u32 *)&raid->capability);
 201        }
 202
 203        return 1;
 204}
 205
 206u32 MR_GetSpanBlock(u32 ld, u64 row, u64 *span_blk,
 207                    struct MR_FW_RAID_MAP_ALL *map)
 208{
 209        struct MR_SPAN_BLOCK_INFO *pSpanBlock = MR_LdSpanInfoGet(ld, map);
 210        struct MR_QUAD_ELEMENT    *quad;
 211        struct MR_LD_RAID         *raid = MR_LdRaidGet(ld, map);
 212        u32                span, j;
 213
 214        for (span = 0; span < raid->spanDepth; span++, pSpanBlock++) {
 215
 216                for (j = 0; j < le32_to_cpu(pSpanBlock->block_span_info.noElements); j++) {
 217                        quad = &pSpanBlock->block_span_info.quad[j];
 218
 219                        if (le32_to_cpu(quad->diff) == 0)
 220                                return SPAN_INVALID;
 221                        if (le64_to_cpu(quad->logStart) <= row && row <=
 222                                le64_to_cpu(quad->logEnd) && (mega_mod64(row - le64_to_cpu(quad->logStart),
 223                                le32_to_cpu(quad->diff))) == 0) {
 224                                if (span_blk != NULL) {
 225                                        u64  blk, debugBlk;
 226                                        blk =  mega_div64_32((row-le64_to_cpu(quad->logStart)), le32_to_cpu(quad->diff));
 227                                        debugBlk = blk;
 228
 229                                        blk = (blk + le64_to_cpu(quad->offsetInSpan)) << raid->stripeShift;
 230                                        *span_blk = blk;
 231                                }
 232                                return span;
 233                        }
 234                }
 235        }
 236        return SPAN_INVALID;
 237}
 238
 239/*
 240******************************************************************************
 241*
 242* Function to print info about span set created in driver from FW raid map
 243*
 244* Inputs :
 245* map    - LD map
 246* ldSpanInfo - ldSpanInfo per HBA instance
 247*/
 248#if SPAN_DEBUG
 249static int getSpanInfo(struct MR_FW_RAID_MAP_ALL *map, PLD_SPAN_INFO ldSpanInfo)
 250{
 251
 252        u8   span;
 253        u32    element;
 254        struct MR_LD_RAID *raid;
 255        LD_SPAN_SET *span_set;
 256        struct MR_QUAD_ELEMENT    *quad;
 257        int ldCount;
 258        u16 ld;
 259
 260        for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++) {
 261                ld = MR_TargetIdToLdGet(ldCount, map);
 262                        if (ld >= MAX_LOGICAL_DRIVES)
 263                                continue;
 264                raid = MR_LdRaidGet(ld, map);
 265                dev_dbg(&instance->pdev->dev, "LD %x: span_depth=%x\n",
 266                        ld, raid->spanDepth);
 267                for (span = 0; span < raid->spanDepth; span++)
 268                        dev_dbg(&instance->pdev->dev, "Span=%x,"
 269                        " number of quads=%x\n", span,
 270                        le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].
 271                        block_span_info.noElements));
 272                for (element = 0; element < MAX_QUAD_DEPTH; element++) {
 273                        span_set = &(ldSpanInfo[ld].span_set[element]);
 274                        if (span_set->span_row_data_width == 0)
 275                                break;
 276
 277                        dev_dbg(&instance->pdev->dev, "Span Set %x:"
 278                                "width=%x, diff=%x\n", element,
 279                                (unsigned int)span_set->span_row_data_width,
 280                                (unsigned int)span_set->diff);
 281                        dev_dbg(&instance->pdev->dev, "logical LBA"
 282                                "start=0x%08lx, end=0x%08lx\n",
 283                                (long unsigned int)span_set->log_start_lba,
 284                                (long unsigned int)span_set->log_end_lba);
 285                        dev_dbg(&instance->pdev->dev, "span row start=0x%08lx,"
 286                                " end=0x%08lx\n",
 287                                (long unsigned int)span_set->span_row_start,
 288                                (long unsigned int)span_set->span_row_end);
 289                        dev_dbg(&instance->pdev->dev, "data row start=0x%08lx,"
 290                                " end=0x%08lx\n",
 291                                (long unsigned int)span_set->data_row_start,
 292                                (long unsigned int)span_set->data_row_end);
 293                        dev_dbg(&instance->pdev->dev, "data strip start=0x%08lx,"
 294                                " end=0x%08lx\n",
 295                                (long unsigned int)span_set->data_strip_start,
 296                                (long unsigned int)span_set->data_strip_end);
 297
 298                        for (span = 0; span < raid->spanDepth; span++) {
 299                                if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].
 300                                        block_span_info.noElements) >=
 301                                        element + 1) {
 302                                        quad = &map->raidMap.ldSpanMap[ld].
 303                                                spanBlock[span].block_span_info.
 304                                                quad[element];
 305                                dev_dbg(&instance->pdev->dev, "Span=%x,"
 306                                        "Quad=%x, diff=%x\n", span,
 307                                        element, le32_to_cpu(quad->diff));
 308                                dev_dbg(&instance->pdev->dev,
 309                                        "offset_in_span=0x%08lx\n",
 310                                        (long unsigned int)le64_to_cpu(quad->offsetInSpan));
 311                                dev_dbg(&instance->pdev->dev,
 312                                        "logical start=0x%08lx, end=0x%08lx\n",
 313                                        (long unsigned int)le64_to_cpu(quad->logStart),
 314                                        (long unsigned int)le64_to_cpu(quad->logEnd));
 315                                }
 316                        }
 317                }
 318        }
 319        return 0;
 320}
 321#endif
 322
 323/*
 324******************************************************************************
 325*
 326* This routine calculates the Span block for given row using spanset.
 327*
 328* Inputs :
 329*    instance - HBA instance
 330*    ld   - Logical drive number
 331*    row        - Row number
 332*    map    - LD map
 333*
 334* Outputs :
 335*
 336*    span          - Span number
 337*    block         - Absolute Block number in the physical disk
 338*    div_error     - Devide error code.
 339*/
 340
 341u32 mr_spanset_get_span_block(struct megasas_instance *instance,
 342                u32 ld, u64 row, u64 *span_blk, struct MR_FW_RAID_MAP_ALL *map)
 343{
 344        struct fusion_context *fusion = instance->ctrl_context;
 345        struct MR_LD_RAID         *raid = MR_LdRaidGet(ld, map);
 346        LD_SPAN_SET *span_set;
 347        struct MR_QUAD_ELEMENT    *quad;
 348        u32    span, info;
 349        PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span;
 350
 351        for (info = 0; info < MAX_QUAD_DEPTH; info++) {
 352                span_set = &(ldSpanInfo[ld].span_set[info]);
 353
 354                if (span_set->span_row_data_width == 0)
 355                        break;
 356
 357                if (row > span_set->data_row_end)
 358                        continue;
 359
 360                for (span = 0; span < raid->spanDepth; span++)
 361                        if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].
 362                                block_span_info.noElements) >= info+1) {
 363                                quad = &map->raidMap.ldSpanMap[ld].
 364                                        spanBlock[span].
 365                                        block_span_info.quad[info];
 366                                if (le32_to_cpu(quad->diff == 0))
 367                                        return SPAN_INVALID;
 368                                if (le64_to_cpu(quad->logStart) <= row  &&
 369                                        row <= le64_to_cpu(quad->logEnd)  &&
 370                                        (mega_mod64(row - le64_to_cpu(quad->logStart),
 371                                                le32_to_cpu(quad->diff))) == 0) {
 372                                        if (span_blk != NULL) {
 373                                                u64  blk;
 374                                                blk = mega_div64_32
 375                                                    ((row - le64_to_cpu(quad->logStart)),
 376                                                    le32_to_cpu(quad->diff));
 377                                                blk = (blk + le64_to_cpu(quad->offsetInSpan))
 378                                                         << raid->stripeShift;
 379                                                *span_blk = blk;
 380                                        }
 381                                        return span;
 382                                }
 383                        }
 384        }
 385        return SPAN_INVALID;
 386}
 387
 388/*
 389******************************************************************************
 390*
 391* This routine calculates the row for given strip using spanset.
 392*
 393* Inputs :
 394*    instance - HBA instance
 395*    ld   - Logical drive number
 396*    Strip        - Strip
 397*    map    - LD map
 398*
 399* Outputs :
 400*
 401*    row         - row associated with strip
 402*/
 403
 404static u64  get_row_from_strip(struct megasas_instance *instance,
 405        u32 ld, u64 strip, struct MR_FW_RAID_MAP_ALL *map)
 406{
 407        struct fusion_context *fusion = instance->ctrl_context;
 408        struct MR_LD_RAID       *raid = MR_LdRaidGet(ld, map);
 409        LD_SPAN_SET     *span_set;
 410        PLD_SPAN_INFO   ldSpanInfo = fusion->log_to_span;
 411        u32             info, strip_offset, span, span_offset;
 412        u64             span_set_Strip, span_set_Row, retval;
 413
 414        for (info = 0; info < MAX_QUAD_DEPTH; info++) {
 415                span_set = &(ldSpanInfo[ld].span_set[info]);
 416
 417                if (span_set->span_row_data_width == 0)
 418                        break;
 419                if (strip > span_set->data_strip_end)
 420                        continue;
 421
 422                span_set_Strip = strip - span_set->data_strip_start;
 423                strip_offset = mega_mod64(span_set_Strip,
 424                                span_set->span_row_data_width);
 425                span_set_Row = mega_div64_32(span_set_Strip,
 426                                span_set->span_row_data_width) * span_set->diff;
 427                for (span = 0, span_offset = 0; span < raid->spanDepth; span++)
 428                        if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].
 429                                block_span_info.noElements >= info+1)) {
 430                                if (strip_offset >=
 431                                        span_set->strip_offset[span])
 432                                        span_offset++;
 433                                else
 434                                        break;
 435                        }
 436#if SPAN_DEBUG
 437                dev_info(&instance->pdev->dev, "Strip 0x%llx,"
 438                        "span_set_Strip 0x%llx, span_set_Row 0x%llx"
 439                        "data width 0x%llx span offset 0x%x\n", strip,
 440                        (unsigned long long)span_set_Strip,
 441                        (unsigned long long)span_set_Row,
 442                        (unsigned long long)span_set->span_row_data_width,
 443                        span_offset);
 444                dev_info(&instance->pdev->dev, "For strip 0x%llx"
 445                        "row is 0x%llx\n", strip,
 446                        (unsigned long long) span_set->data_row_start +
 447                        (unsigned long long) span_set_Row + (span_offset - 1));
 448#endif
 449                retval = (span_set->data_row_start + span_set_Row +
 450                                (span_offset - 1));
 451                return retval;
 452        }
 453        return -1LLU;
 454}
 455
 456
 457/*
 458******************************************************************************
 459*
 460* This routine calculates the Start Strip for given row using spanset.
 461*
 462* Inputs :
 463*    instance - HBA instance
 464*    ld   - Logical drive number
 465*    row        - Row number
 466*    map    - LD map
 467*
 468* Outputs :
 469*
 470*    Strip         - Start strip associated with row
 471*/
 472
 473static u64 get_strip_from_row(struct megasas_instance *instance,
 474                u32 ld, u64 row, struct MR_FW_RAID_MAP_ALL *map)
 475{
 476        struct fusion_context *fusion = instance->ctrl_context;
 477        struct MR_LD_RAID         *raid = MR_LdRaidGet(ld, map);
 478        LD_SPAN_SET *span_set;
 479        struct MR_QUAD_ELEMENT    *quad;
 480        PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span;
 481        u32    span, info;
 482        u64  strip;
 483
 484        for (info = 0; info < MAX_QUAD_DEPTH; info++) {
 485                span_set = &(ldSpanInfo[ld].span_set[info]);
 486
 487                if (span_set->span_row_data_width == 0)
 488                        break;
 489                if (row > span_set->data_row_end)
 490                        continue;
 491
 492                for (span = 0; span < raid->spanDepth; span++)
 493                        if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].
 494                                block_span_info.noElements) >= info+1) {
 495                                quad = &map->raidMap.ldSpanMap[ld].
 496                                        spanBlock[span].block_span_info.quad[info];
 497                                if (le64_to_cpu(quad->logStart) <= row  &&
 498                                        row <= le64_to_cpu(quad->logEnd)  &&
 499                                        mega_mod64((row - le64_to_cpu(quad->logStart)),
 500                                        le32_to_cpu(quad->diff)) == 0) {
 501                                        strip = mega_div64_32
 502                                                (((row - span_set->data_row_start)
 503                                                        - le64_to_cpu(quad->logStart)),
 504                                                        le32_to_cpu(quad->diff));
 505                                        strip *= span_set->span_row_data_width;
 506                                        strip += span_set->data_strip_start;
 507                                        strip += span_set->strip_offset[span];
 508                                        return strip;
 509                                }
 510                        }
 511        }
 512        dev_err(&instance->pdev->dev, "get_strip_from_row"
 513                "returns invalid strip for ld=%x, row=%lx\n",
 514                ld, (long unsigned int)row);
 515        return -1;
 516}
 517
 518/*
 519******************************************************************************
 520*
 521* This routine calculates the Physical Arm for given strip using spanset.
 522*
 523* Inputs :
 524*    instance - HBA instance
 525*    ld   - Logical drive number
 526*    strip      - Strip
 527*    map    - LD map
 528*
 529* Outputs :
 530*
 531*    Phys Arm         - Phys Arm associated with strip
 532*/
 533
 534static u32 get_arm_from_strip(struct megasas_instance *instance,
 535        u32 ld, u64 strip, struct MR_FW_RAID_MAP_ALL *map)
 536{
 537        struct fusion_context *fusion = instance->ctrl_context;
 538        struct MR_LD_RAID         *raid = MR_LdRaidGet(ld, map);
 539        LD_SPAN_SET *span_set;
 540        PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span;
 541        u32    info, strip_offset, span, span_offset, retval;
 542
 543        for (info = 0 ; info < MAX_QUAD_DEPTH; info++) {
 544                span_set = &(ldSpanInfo[ld].span_set[info]);
 545
 546                if (span_set->span_row_data_width == 0)
 547                        break;
 548                if (strip > span_set->data_strip_end)
 549                        continue;
 550
 551                strip_offset = (uint)mega_mod64
 552                                ((strip - span_set->data_strip_start),
 553                                span_set->span_row_data_width);
 554
 555                for (span = 0, span_offset = 0; span < raid->spanDepth; span++)
 556                        if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].
 557                                block_span_info.noElements) >= info+1) {
 558                                if (strip_offset >=
 559                                        span_set->strip_offset[span])
 560                                        span_offset =
 561                                                span_set->strip_offset[span];
 562                                else
 563                                        break;
 564                        }
 565#if SPAN_DEBUG
 566                dev_info(&instance->pdev->dev, "get_arm_from_strip:"
 567                        "for ld=0x%x strip=0x%lx arm is  0x%x\n", ld,
 568                        (long unsigned int)strip, (strip_offset - span_offset));
 569#endif
 570                retval = (strip_offset - span_offset);
 571                return retval;
 572        }
 573
 574        dev_err(&instance->pdev->dev, "get_arm_from_strip"
 575                "returns invalid arm for ld=%x strip=%lx\n",
 576                ld, (long unsigned int)strip);
 577
 578        return -1;
 579}
 580
 581/* This Function will return Phys arm */
 582u8 get_arm(struct megasas_instance *instance, u32 ld, u8 span, u64 stripe,
 583                struct MR_FW_RAID_MAP_ALL *map)
 584{
 585        struct MR_LD_RAID  *raid = MR_LdRaidGet(ld, map);
 586        /* Need to check correct default value */
 587        u32    arm = 0;
 588
 589        switch (raid->level) {
 590        case 0:
 591        case 5:
 592        case 6:
 593                arm = mega_mod64(stripe, SPAN_ROW_SIZE(map, ld, span));
 594                break;
 595        case 1:
 596                /* start with logical arm */
 597                arm = get_arm_from_strip(instance, ld, stripe, map);
 598                if (arm != -1U)
 599                        arm *= 2;
 600                break;
 601        }
 602
 603        return arm;
 604}
 605
 606
 607/*
 608******************************************************************************
 609*
 610* This routine calculates the arm, span and block for the specified stripe and
 611* reference in stripe using spanset
 612*
 613* Inputs :
 614*
 615*    ld   - Logical drive number
 616*    stripRow        - Stripe number
 617*    stripRef    - Reference in stripe
 618*
 619* Outputs :
 620*
 621*    span          - Span number
 622*    block         - Absolute Block number in the physical disk
 623*/
 624static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld,
 625                u64 stripRow, u16 stripRef, struct IO_REQUEST_INFO *io_info,
 626                struct RAID_CONTEXT *pRAID_Context,
 627                struct MR_FW_RAID_MAP_ALL *map)
 628{
 629        struct MR_LD_RAID  *raid = MR_LdRaidGet(ld, map);
 630        u32     pd, arRef;
 631        u8      physArm, span;
 632        u64     row;
 633        u8      retval = TRUE;
 634        u8      do_invader = 0;
 635        u64     *pdBlock = &io_info->pdBlock;
 636        u16     *pDevHandle = &io_info->devHandle;
 637        u32     logArm, rowMod, armQ, arm;
 638
 639        if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER ||
 640                instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
 641                do_invader = 1;
 642
 643        /*Get row and span from io_info for Uneven Span IO.*/
 644        row         = io_info->start_row;
 645        span        = io_info->start_span;
 646
 647
 648        if (raid->level == 6) {
 649                logArm = get_arm_from_strip(instance, ld, stripRow, map);
 650                if (logArm == -1U)
 651                        return FALSE;
 652                rowMod = mega_mod64(row, SPAN_ROW_SIZE(map, ld, span));
 653                armQ = SPAN_ROW_SIZE(map, ld, span) - 1 - rowMod;
 654                arm = armQ + 1 + logArm;
 655                if (arm >= SPAN_ROW_SIZE(map, ld, span))
 656                        arm -= SPAN_ROW_SIZE(map, ld, span);
 657                physArm = (u8)arm;
 658        } else
 659                /* Calculate the arm */
 660                physArm = get_arm(instance, ld, span, stripRow, map);
 661        if (physArm == 0xFF)
 662                return FALSE;
 663
 664        arRef       = MR_LdSpanArrayGet(ld, span, map);
 665        pd          = MR_ArPdGet(arRef, physArm, map);
 666
 667        if (pd != MR_PD_INVALID)
 668                *pDevHandle = MR_PdDevHandleGet(pd, map);
 669        else {
 670                *pDevHandle = MR_PD_INVALID;
 671                if ((raid->level >= 5) &&
 672                        (!do_invader  || (do_invader &&
 673                        (raid->regTypeReqOnRead != REGION_TYPE_UNUSED))))
 674                        pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
 675                else if (raid->level == 1) {
 676                        pd = MR_ArPdGet(arRef, physArm + 1, map);
 677                        if (pd != MR_PD_INVALID)
 678                                *pDevHandle = MR_PdDevHandleGet(pd, map);
 679                }
 680        }
 681
 682        *pdBlock += stripRef + le64_to_cpu(MR_LdSpanPtrGet(ld, span, map)->startBlk);
 683        pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) |
 684                                        physArm;
 685        return retval;
 686}
 687
 688/*
 689******************************************************************************
 690*
 691* This routine calculates the arm, span and block for the specified stripe and
 692* reference in stripe.
 693*
 694* Inputs :
 695*
 696*    ld   - Logical drive number
 697*    stripRow        - Stripe number
 698*    stripRef    - Reference in stripe
 699*
 700* Outputs :
 701*
 702*    span          - Span number
 703*    block         - Absolute Block number in the physical disk
 704*/
 705u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow,
 706                u16 stripRef, struct IO_REQUEST_INFO *io_info,
 707                struct RAID_CONTEXT *pRAID_Context,
 708                struct MR_FW_RAID_MAP_ALL *map)
 709{
 710        struct MR_LD_RAID  *raid = MR_LdRaidGet(ld, map);
 711        u32         pd, arRef;
 712        u8          physArm, span;
 713        u64         row;
 714        u8          retval = TRUE;
 715        u8          do_invader = 0;
 716        u64         *pdBlock = &io_info->pdBlock;
 717        u16         *pDevHandle = &io_info->devHandle;
 718
 719        if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER ||
 720                instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
 721                do_invader = 1;
 722
 723        row =  mega_div64_32(stripRow, raid->rowDataSize);
 724
 725        if (raid->level == 6) {
 726                /* logical arm within row */
 727                u32 logArm =  mega_mod64(stripRow, raid->rowDataSize);
 728                u32 rowMod, armQ, arm;
 729
 730                if (raid->rowSize == 0)
 731                        return FALSE;
 732                /* get logical row mod */
 733                rowMod = mega_mod64(row, raid->rowSize);
 734                armQ = raid->rowSize-1-rowMod; /* index of Q drive */
 735                arm = armQ+1+logArm; /* data always logically follows Q */
 736                if (arm >= raid->rowSize) /* handle wrap condition */
 737                        arm -= raid->rowSize;
 738                physArm = (u8)arm;
 739        } else  {
 740                if (raid->modFactor == 0)
 741                        return FALSE;
 742                physArm = MR_LdDataArmGet(ld,  mega_mod64(stripRow,
 743                                                          raid->modFactor),
 744                                          map);
 745        }
 746
 747        if (raid->spanDepth == 1) {
 748                span = 0;
 749                *pdBlock = row << raid->stripeShift;
 750        } else {
 751                span = (u8)MR_GetSpanBlock(ld, row, pdBlock, map);
 752                if (span == SPAN_INVALID)
 753                        return FALSE;
 754        }
 755
 756        /* Get the array on which this span is present */
 757        arRef       = MR_LdSpanArrayGet(ld, span, map);
 758        pd          = MR_ArPdGet(arRef, physArm, map); /* Get the pd */
 759
 760        if (pd != MR_PD_INVALID)
 761                /* Get dev handle from Pd. */
 762                *pDevHandle = MR_PdDevHandleGet(pd, map);
 763        else {
 764                *pDevHandle = MR_PD_INVALID; /* set dev handle as invalid. */
 765                if ((raid->level >= 5) &&
 766                        (!do_invader  || (do_invader &&
 767                        (raid->regTypeReqOnRead != REGION_TYPE_UNUSED))))
 768                        pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
 769                else if (raid->level == 1) {
 770                        /* Get alternate Pd. */
 771                        pd = MR_ArPdGet(arRef, physArm + 1, map);
 772                        if (pd != MR_PD_INVALID)
 773                                /* Get dev handle from Pd */
 774                                *pDevHandle = MR_PdDevHandleGet(pd, map);
 775                }
 776        }
 777
 778        *pdBlock += stripRef + le64_to_cpu(MR_LdSpanPtrGet(ld, span, map)->startBlk);
 779        pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) |
 780                physArm;
 781        return retval;
 782}
 783
 784/*
 785******************************************************************************
 786*
 787* MR_BuildRaidContext function
 788*
 789* This function will initiate command processing.  The start/end row and strip
 790* information is calculated then the lock is acquired.
 791* This function will return 0 if region lock was acquired OR return num strips
 792*/
 793u8
 794MR_BuildRaidContext(struct megasas_instance *instance,
 795                    struct IO_REQUEST_INFO *io_info,
 796                    struct RAID_CONTEXT *pRAID_Context,
 797                    struct MR_FW_RAID_MAP_ALL *map, u8 **raidLUN)
 798{
 799        struct MR_LD_RAID  *raid;
 800        u32         ld, stripSize, stripe_mask;
 801        u64         endLba, endStrip, endRow, start_row, start_strip;
 802        u64         regStart;
 803        u32         regSize;
 804        u8          num_strips, numRows;
 805        u16         ref_in_start_stripe, ref_in_end_stripe;
 806        u64         ldStartBlock;
 807        u32         numBlocks, ldTgtId;
 808        u8          isRead;
 809        u8          retval = 0;
 810        u8          startlba_span = SPAN_INVALID;
 811        u64 *pdBlock = &io_info->pdBlock;
 812
 813        ldStartBlock = io_info->ldStartBlock;
 814        numBlocks = io_info->numBlocks;
 815        ldTgtId = io_info->ldTgtId;
 816        isRead = io_info->isRead;
 817        io_info->IoforUnevenSpan = 0;
 818        io_info->start_span     = SPAN_INVALID;
 819
 820        ld = MR_TargetIdToLdGet(ldTgtId, map);
 821        raid = MR_LdRaidGet(ld, map);
 822
 823        /*
 824         * if rowDataSize @RAID map and spanRowDataSize @SPAN INFO are zero
 825         * return FALSE
 826         */
 827        if (raid->rowDataSize == 0) {
 828                if (MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize == 0)
 829                        return FALSE;
 830                else if (instance->UnevenSpanSupport) {
 831                        io_info->IoforUnevenSpan = 1;
 832                } else {
 833                        dev_info(&instance->pdev->dev,
 834                                "raid->rowDataSize is 0, but has SPAN[0]"
 835                                "rowDataSize = 0x%0x,"
 836                                "but there is _NO_ UnevenSpanSupport\n",
 837                                MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize);
 838                        return FALSE;
 839                }
 840        }
 841
 842        stripSize = 1 << raid->stripeShift;
 843        stripe_mask = stripSize-1;
 844
 845
 846        /*
 847         * calculate starting row and stripe, and number of strips and rows
 848         */
 849        start_strip         = ldStartBlock >> raid->stripeShift;
 850        ref_in_start_stripe = (u16)(ldStartBlock & stripe_mask);
 851        endLba              = ldStartBlock + numBlocks - 1;
 852        ref_in_end_stripe   = (u16)(endLba & stripe_mask);
 853        endStrip            = endLba >> raid->stripeShift;
 854        num_strips          = (u8)(endStrip - start_strip + 1); /* End strip */
 855
 856        if (io_info->IoforUnevenSpan) {
 857                start_row = get_row_from_strip(instance, ld, start_strip, map);
 858                endRow    = get_row_from_strip(instance, ld, endStrip, map);
 859                if (start_row == -1ULL || endRow == -1ULL) {
 860                        dev_info(&instance->pdev->dev, "return from %s %d."
 861                                "Send IO w/o region lock.\n",
 862                                __func__, __LINE__);
 863                        return FALSE;
 864                }
 865
 866                if (raid->spanDepth == 1) {
 867                        startlba_span = 0;
 868                        *pdBlock = start_row << raid->stripeShift;
 869                } else
 870                        startlba_span = (u8)mr_spanset_get_span_block(instance,
 871                                                ld, start_row, pdBlock, map);
 872                if (startlba_span == SPAN_INVALID) {
 873                        dev_info(&instance->pdev->dev, "return from %s %d"
 874                                "for row 0x%llx,start strip %llx"
 875                                "endSrip %llx\n", __func__, __LINE__,
 876                                (unsigned long long)start_row,
 877                                (unsigned long long)start_strip,
 878                                (unsigned long long)endStrip);
 879                        return FALSE;
 880                }
 881                io_info->start_span     = startlba_span;
 882                io_info->start_row      = start_row;
 883#if SPAN_DEBUG
 884                dev_dbg(&instance->pdev->dev, "Check Span number from %s %d"
 885                        "for row 0x%llx, start strip 0x%llx end strip 0x%llx"
 886                        " span 0x%x\n", __func__, __LINE__,
 887                        (unsigned long long)start_row,
 888                        (unsigned long long)start_strip,
 889                        (unsigned long long)endStrip, startlba_span);
 890                dev_dbg(&instance->pdev->dev, "start_row 0x%llx endRow 0x%llx"
 891                        "Start span 0x%x\n", (unsigned long long)start_row,
 892                        (unsigned long long)endRow, startlba_span);
 893#endif
 894        } else {
 895                start_row = mega_div64_32(start_strip, raid->rowDataSize);
 896                endRow    = mega_div64_32(endStrip, raid->rowDataSize);
 897        }
 898        numRows = (u8)(endRow - start_row + 1);
 899
 900        /*
 901         * calculate region info.
 902         */
 903
 904        /* assume region is at the start of the first row */
 905        regStart            = start_row << raid->stripeShift;
 906        /* assume this IO needs the full row - we'll adjust if not true */
 907        regSize             = stripSize;
 908
 909        /* Check if we can send this I/O via FastPath */
 910        if (raid->capability.fpCapable) {
 911                if (isRead)
 912                        io_info->fpOkForIo = (raid->capability.fpReadCapable &&
 913                                              ((num_strips == 1) ||
 914                                               raid->capability.
 915                                               fpReadAcrossStripe));
 916                else
 917                        io_info->fpOkForIo = (raid->capability.fpWriteCapable &&
 918                                              ((num_strips == 1) ||
 919                                               raid->capability.
 920                                               fpWriteAcrossStripe));
 921        } else
 922                io_info->fpOkForIo = FALSE;
 923
 924        if (numRows == 1) {
 925                /* single-strip IOs can always lock only the data needed */
 926                if (num_strips == 1) {
 927                        regStart += ref_in_start_stripe;
 928                        regSize = numBlocks;
 929                }
 930                /* multi-strip IOs always need to full stripe locked */
 931        } else if (io_info->IoforUnevenSpan == 0) {
 932                /*
 933                 * For Even span region lock optimization.
 934                 * If the start strip is the last in the start row
 935                 */
 936                if (start_strip == (start_row + 1) * raid->rowDataSize - 1) {
 937                        regStart += ref_in_start_stripe;
 938                        /* initialize count to sectors from startref to end
 939                           of strip */
 940                        regSize = stripSize - ref_in_start_stripe;
 941                }
 942
 943                /* add complete rows in the middle of the transfer */
 944                if (numRows > 2)
 945                        regSize += (numRows-2) << raid->stripeShift;
 946
 947                /* if IO ends within first strip of last row*/
 948                if (endStrip == endRow*raid->rowDataSize)
 949                        regSize += ref_in_end_stripe+1;
 950                else
 951                        regSize += stripSize;
 952        } else {
 953                /*
 954                 * For Uneven span region lock optimization.
 955                 * If the start strip is the last in the start row
 956                 */
 957                if (start_strip == (get_strip_from_row(instance, ld, start_row, map) +
 958                                SPAN_ROW_DATA_SIZE(map, ld, startlba_span) - 1)) {
 959                        regStart += ref_in_start_stripe;
 960                        /* initialize count to sectors from
 961                         * startRef to end of strip
 962                         */
 963                        regSize = stripSize - ref_in_start_stripe;
 964                }
 965                /* Add complete rows in the middle of the transfer*/
 966
 967                if (numRows > 2)
 968                        /* Add complete rows in the middle of the transfer*/
 969                        regSize += (numRows-2) << raid->stripeShift;
 970
 971                /* if IO ends within first strip of last row */
 972                if (endStrip == get_strip_from_row(instance, ld, endRow, map))
 973                        regSize += ref_in_end_stripe + 1;
 974                else
 975                        regSize += stripSize;
 976        }
 977
 978        pRAID_Context->timeoutValue     = cpu_to_le16(map->raidMap.fpPdIoTimeoutSec);
 979        if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
 980                (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
 981                pRAID_Context->regLockFlags = (isRead) ?
 982                        raid->regTypeReqOnRead : raid->regTypeReqOnWrite;
 983        else
 984                pRAID_Context->regLockFlags = (isRead) ?
 985                        REGION_TYPE_SHARED_READ : raid->regTypeReqOnWrite;
 986        pRAID_Context->VirtualDiskTgtId = raid->targetId;
 987        pRAID_Context->regLockRowLBA    = cpu_to_le64(regStart);
 988        pRAID_Context->regLockLength    = cpu_to_le32(regSize);
 989        pRAID_Context->configSeqNum     = raid->seqNum;
 990        /* save pointer to raid->LUN array */
 991        *raidLUN = raid->LUN;
 992
 993
 994        /*Get Phy Params only if FP capable, or else leave it to MR firmware
 995          to do the calculation.*/
 996        if (io_info->fpOkForIo) {
 997                retval = io_info->IoforUnevenSpan ?
 998                                mr_spanset_get_phy_params(instance, ld,
 999                                        start_strip, ref_in_start_stripe,
1000                                        io_info, pRAID_Context, map) :
1001                                MR_GetPhyParams(instance, ld, start_strip,
1002                                        ref_in_start_stripe, io_info,
1003                                        pRAID_Context, map);
1004                /* If IO on an invalid Pd, then FP is not possible.*/
1005                if (io_info->devHandle == MR_PD_INVALID)
1006                        io_info->fpOkForIo = FALSE;
1007                return retval;
1008        } else if (isRead) {
1009                uint stripIdx;
1010                for (stripIdx = 0; stripIdx < num_strips; stripIdx++) {
1011                        retval = io_info->IoforUnevenSpan ?
1012                                mr_spanset_get_phy_params(instance, ld,
1013                                    start_strip + stripIdx,
1014                                    ref_in_start_stripe, io_info,
1015                                    pRAID_Context, map) :
1016                                MR_GetPhyParams(instance, ld,
1017                                    start_strip + stripIdx, ref_in_start_stripe,
1018                                    io_info, pRAID_Context, map);
1019                        if (!retval)
1020                                return TRUE;
1021                }
1022        }
1023
1024#if SPAN_DEBUG
1025        /* Just for testing what arm we get for strip.*/
1026        if (io_info->IoforUnevenSpan)
1027                get_arm_from_strip(instance, ld, start_strip, map);
1028#endif
1029        return TRUE;
1030}
1031
1032/*
1033******************************************************************************
1034*
1035* This routine pepare spanset info from Valid Raid map and store it into
1036* local copy of ldSpanInfo per instance data structure.
1037*
1038* Inputs :
1039* map    - LD map
1040* ldSpanInfo - ldSpanInfo per HBA instance
1041*
1042*/
1043void mr_update_span_set(struct MR_FW_RAID_MAP_ALL *map,
1044                        PLD_SPAN_INFO ldSpanInfo)
1045{
1046        u8   span, count;
1047        u32  element, span_row_width;
1048        u64  span_row;
1049        struct MR_LD_RAID *raid;
1050        LD_SPAN_SET *span_set, *span_set_prev;
1051        struct MR_QUAD_ELEMENT    *quad;
1052        int ldCount;
1053        u16 ld;
1054
1055
1056        for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++) {
1057                ld = MR_TargetIdToLdGet(ldCount, map);
1058                if (ld >= MAX_LOGICAL_DRIVES)
1059                        continue;
1060                raid = MR_LdRaidGet(ld, map);
1061                for (element = 0; element < MAX_QUAD_DEPTH; element++) {
1062                        for (span = 0; span < raid->spanDepth; span++) {
1063                                if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].
1064                                        block_span_info.noElements) <
1065                                        element + 1)
1066                                        continue;
1067                                span_set = &(ldSpanInfo[ld].span_set[element]);
1068                                quad = &map->raidMap.ldSpanMap[ld].
1069                                        spanBlock[span].block_span_info.
1070                                        quad[element];
1071
1072                                span_set->diff = le32_to_cpu(quad->diff);
1073
1074                                for (count = 0, span_row_width = 0;
1075                                        count < raid->spanDepth; count++) {
1076                                        if (le32_to_cpu(map->raidMap.ldSpanMap[ld].
1077                                                spanBlock[count].
1078                                                block_span_info.
1079                                                noElements) >= element + 1) {
1080                                                span_set->strip_offset[count] =
1081                                                        span_row_width;
1082                                                span_row_width +=
1083                                                        MR_LdSpanPtrGet
1084                                                        (ld, count, map)->spanRowDataSize;
1085                                                printk(KERN_INFO "megasas:"
1086                                                        "span %x rowDataSize %x\n",
1087                                                        count, MR_LdSpanPtrGet
1088                                                        (ld, count, map)->spanRowDataSize);
1089                                        }
1090                                }
1091
1092                                span_set->span_row_data_width = span_row_width;
1093                                span_row = mega_div64_32(((le64_to_cpu(quad->logEnd) -
1094                                        le64_to_cpu(quad->logStart)) + le32_to_cpu(quad->diff)),
1095                                        le32_to_cpu(quad->diff));
1096
1097                                if (element == 0) {
1098                                        span_set->log_start_lba = 0;
1099                                        span_set->log_end_lba =
1100                                                ((span_row << raid->stripeShift)
1101                                                * span_row_width) - 1;
1102
1103                                        span_set->span_row_start = 0;
1104                                        span_set->span_row_end = span_row - 1;
1105
1106                                        span_set->data_strip_start = 0;
1107                                        span_set->data_strip_end =
1108                                                (span_row * span_row_width) - 1;
1109
1110                                        span_set->data_row_start = 0;
1111                                        span_set->data_row_end =
1112                                                (span_row * le32_to_cpu(quad->diff)) - 1;
1113                                } else {
1114                                        span_set_prev = &(ldSpanInfo[ld].
1115                                                        span_set[element - 1]);
1116                                        span_set->log_start_lba =
1117                                                span_set_prev->log_end_lba + 1;
1118                                        span_set->log_end_lba =
1119                                                span_set->log_start_lba +
1120                                                ((span_row << raid->stripeShift)
1121                                                * span_row_width) - 1;
1122
1123                                        span_set->span_row_start =
1124                                                span_set_prev->span_row_end + 1;
1125                                        span_set->span_row_end =
1126                                        span_set->span_row_start + span_row - 1;
1127
1128                                        span_set->data_strip_start =
1129                                        span_set_prev->data_strip_end + 1;
1130                                        span_set->data_strip_end =
1131                                                span_set->data_strip_start +
1132                                                (span_row * span_row_width) - 1;
1133
1134                                        span_set->data_row_start =
1135                                                span_set_prev->data_row_end + 1;
1136                                        span_set->data_row_end =
1137                                                span_set->data_row_start +
1138                                                (span_row * le32_to_cpu(quad->diff)) - 1;
1139                                }
1140                                break;
1141                }
1142                if (span == raid->spanDepth)
1143                        break;
1144            }
1145        }
1146#if SPAN_DEBUG
1147        getSpanInfo(map, ldSpanInfo);
1148#endif
1149
1150}
1151
1152void
1153mr_update_load_balance_params(struct MR_FW_RAID_MAP_ALL *map,
1154                              struct LD_LOAD_BALANCE_INFO *lbInfo)
1155{
1156        int ldCount;
1157        u16 ld;
1158        struct MR_LD_RAID *raid;
1159
1160        for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++) {
1161                ld = MR_TargetIdToLdGet(ldCount, map);
1162                if (ld >= MAX_LOGICAL_DRIVES) {
1163                        lbInfo[ldCount].loadBalanceFlag = 0;
1164                        continue;
1165                }
1166
1167                raid = MR_LdRaidGet(ld, map);
1168
1169                /* Two drive Optimal RAID 1 */
1170                if ((raid->level == 1)  &&  (raid->rowSize == 2) &&
1171                    (raid->spanDepth == 1) && raid->ldState ==
1172                    MR_LD_STATE_OPTIMAL) {
1173                        u32 pd, arRef;
1174
1175                        lbInfo[ldCount].loadBalanceFlag = 1;
1176
1177                        /* Get the array on which this span is present */
1178                        arRef = MR_LdSpanArrayGet(ld, 0, map);
1179
1180                        /* Get the Pd */
1181                        pd = MR_ArPdGet(arRef, 0, map);
1182                        /* Get dev handle from Pd */
1183                        lbInfo[ldCount].raid1DevHandle[0] =
1184                                MR_PdDevHandleGet(pd, map);
1185                        /* Get the Pd */
1186                        pd = MR_ArPdGet(arRef, 1, map);
1187
1188                        /* Get the dev handle from Pd */
1189                        lbInfo[ldCount].raid1DevHandle[1] =
1190                                MR_PdDevHandleGet(pd, map);
1191                } else
1192                        lbInfo[ldCount].loadBalanceFlag = 0;
1193        }
1194}
1195
1196u8 megasas_get_best_arm(struct LD_LOAD_BALANCE_INFO *lbInfo, u8 arm, u64 block,
1197                        u32 count)
1198{
1199        u16     pend0, pend1;
1200        u64     diff0, diff1;
1201        u8      bestArm;
1202
1203        /* get the pending cmds for the data and mirror arms */
1204        pend0 = atomic_read(&lbInfo->scsi_pending_cmds[0]);
1205        pend1 = atomic_read(&lbInfo->scsi_pending_cmds[1]);
1206
1207        /* Determine the disk whose head is nearer to the req. block */
1208        diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[0]);
1209        diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[1]);
1210        bestArm = (diff0 <= diff1 ? 0 : 1);
1211
1212        /*Make balance count from 16 to 4 to keep driver in sync with Firmware*/
1213        if ((bestArm == arm && pend0 > pend1 + 4)  ||
1214            (bestArm != arm && pend1 > pend0 + 4))
1215                bestArm ^= 1;
1216
1217        /* Update the last accessed block on the correct pd */
1218        lbInfo->last_accessed_block[bestArm] = block + count - 1;
1219
1220        return bestArm;
1221}
1222
1223u16 get_updated_dev_handle(struct LD_LOAD_BALANCE_INFO *lbInfo,
1224                           struct IO_REQUEST_INFO *io_info)
1225{
1226        u8 arm, old_arm;
1227        u16 devHandle;
1228
1229        old_arm = lbInfo->raid1DevHandle[0] == io_info->devHandle ? 0 : 1;
1230
1231        /* get best new arm */
1232        arm  = megasas_get_best_arm(lbInfo, old_arm, io_info->ldStartBlock,
1233                                    io_info->numBlocks);
1234        devHandle = lbInfo->raid1DevHandle[arm];
1235        atomic_inc(&lbInfo->scsi_pending_cmds[arm]);
1236
1237        return devHandle;
1238}
1239