1426 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Linux MegaRAID driver for SAS based RAID controllers4 *5 * Copyright (c) 2009-2013 LSI Corporation6 * Copyright (c) 2013-2016 Avago Technologies7 * Copyright (c) 2016-2018 Broadcom Inc.8 *9 * FILE: megaraid_sas_fp.c10 *11 * Authors: Broadcom Inc.12 * Sumant Patro13 * Varad Talamacki14 * Manoj Jose15 * Kashyap Desai <kashyap.desai@broadcom.com>16 * Sumit Saxena <sumit.saxena@broadcom.com>17 *18 * Send feedback to: megaraidlinux.pdl@broadcom.com19 */20 21#include <linux/kernel.h>22#include <linux/types.h>23#include <linux/pci.h>24#include <linux/list.h>25#include <linux/moduleparam.h>26#include <linux/module.h>27#include <linux/spinlock.h>28#include <linux/interrupt.h>29#include <linux/delay.h>30#include <linux/uio.h>31#include <linux/uaccess.h>32#include <linux/fs.h>33#include <linux/compat.h>34#include <linux/blkdev.h>35#include <linux/poll.h>36#include <linux/irq_poll.h>37 38#include <scsi/scsi.h>39#include <scsi/scsi_cmnd.h>40#include <scsi/scsi_device.h>41#include <scsi/scsi_host.h>42 43#include "megaraid_sas_fusion.h"44#include "megaraid_sas.h"45#include <asm/div64.h>46 47#define LB_PENDING_CMDS_DEFAULT 448static unsigned int lb_pending_cmds = LB_PENDING_CMDS_DEFAULT;49module_param(lb_pending_cmds, int, 0444);50MODULE_PARM_DESC(lb_pending_cmds, "Change raid-1 load balancing outstanding "51 "threshold. Valid Values are 1-128. Default: 4");52 53 54#define ABS_DIFF(a, b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a)))55#define MR_LD_STATE_OPTIMAL 356 57#define SPAN_ROW_SIZE(map, ld, index_) (MR_LdSpanPtrGet(ld, index_, map)->spanRowSize)58#define SPAN_ROW_DATA_SIZE(map_, ld, index_) (MR_LdSpanPtrGet(ld, index_, map)->spanRowDataSize)59#define SPAN_INVALID 0xff60 61/* Prototypes */62static void mr_update_span_set(struct MR_DRV_RAID_MAP_ALL *map,63 PLD_SPAN_INFO ldSpanInfo);64static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld,65 u64 stripRow, u16 stripRef, struct IO_REQUEST_INFO *io_info,66 struct RAID_CONTEXT *pRAID_Context, struct MR_DRV_RAID_MAP_ALL *map);67static u64 get_row_from_strip(struct megasas_instance *instance, u32 ld,68 u64 strip, struct MR_DRV_RAID_MAP_ALL *map);69 70u32 mega_mod64(u64 dividend, u32 divisor)71{72 u64 d;73 u32 remainder;74 75 if (!divisor)76 printk(KERN_ERR "megasas : DIVISOR is zero, in div fn\n");77 d = dividend;78 remainder = do_div(d, divisor);79 return remainder;80}81 82/**83 * mega_div64_32 - Do a 64-bit division84 * @dividend: Dividend85 * @divisor: Divisor86 *87 * @return quotient88 **/89static u64 mega_div64_32(uint64_t dividend, uint32_t divisor)90{91 u64 d = dividend;92 93 if (!divisor)94 printk(KERN_ERR "megasas : DIVISOR is zero in mod fn\n");95 96 do_div(d, divisor);97 98 return d;99}100 101struct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_DRV_RAID_MAP_ALL *map)102{103 return &map->raidMap.ldSpanMap[ld].ldRaid;104}105 106static struct MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u32 ld,107 struct MR_DRV_RAID_MAP_ALL108 *map)109{110 return &map->raidMap.ldSpanMap[ld].spanBlock[0];111}112 113static u8 MR_LdDataArmGet(u32 ld, u32 armIdx, struct MR_DRV_RAID_MAP_ALL *map)114{115 return map->raidMap.ldSpanMap[ld].dataArmMap[armIdx];116}117 118u16 MR_ArPdGet(u32 ar, u32 arm, struct MR_DRV_RAID_MAP_ALL *map)119{120 return le16_to_cpu(map->raidMap.arMapInfo[ar].pd[arm]);121}122 123u16 MR_LdSpanArrayGet(u32 ld, u32 span, struct MR_DRV_RAID_MAP_ALL *map)124{125 return le16_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].span.arrayRef);126}127 128__le16 MR_PdDevHandleGet(u32 pd, struct MR_DRV_RAID_MAP_ALL *map)129{130 return map->raidMap.devHndlInfo[pd].curDevHdl;131}132 133static u8 MR_PdInterfaceTypeGet(u32 pd, struct MR_DRV_RAID_MAP_ALL *map)134{135 return map->raidMap.devHndlInfo[pd].interfaceType;136}137 138u16 MR_GetLDTgtId(u32 ld, struct MR_DRV_RAID_MAP_ALL *map)139{140 return le16_to_cpu(map->raidMap.ldSpanMap[ld].ldRaid.targetId);141}142 143u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_DRV_RAID_MAP_ALL *map)144{145 return map->raidMap.ldTgtIdToLd[ldTgtId];146}147 148static struct MR_LD_SPAN *MR_LdSpanPtrGet(u32 ld, u32 span,149 struct MR_DRV_RAID_MAP_ALL *map)150{151 return &map->raidMap.ldSpanMap[ld].spanBlock[span].span;152}153 154/*155 * This function will Populate Driver Map using firmware raid map156 */157static int MR_PopulateDrvRaidMap(struct megasas_instance *instance, u64 map_id)158{159 struct fusion_context *fusion = instance->ctrl_context;160 struct MR_FW_RAID_MAP_ALL *fw_map_old = NULL;161 struct MR_FW_RAID_MAP *pFwRaidMap = NULL;162 int i, j;163 u16 ld_count;164 struct MR_FW_RAID_MAP_DYNAMIC *fw_map_dyn;165 struct MR_FW_RAID_MAP_EXT *fw_map_ext;166 struct MR_RAID_MAP_DESC_TABLE *desc_table;167 168 169 struct MR_DRV_RAID_MAP_ALL *drv_map =170 fusion->ld_drv_map[(map_id & 1)];171 struct MR_DRV_RAID_MAP *pDrvRaidMap = &drv_map->raidMap;172 void *raid_map_data = NULL;173 174 memset(drv_map, 0, fusion->drv_map_sz);175 memset(pDrvRaidMap->ldTgtIdToLd,176 0xff, (sizeof(u16) * MAX_LOGICAL_DRIVES_DYN));177 178 if (instance->max_raid_mapsize) {179 fw_map_dyn = fusion->ld_map[(map_id & 1)];180 desc_table =181 (struct MR_RAID_MAP_DESC_TABLE *)((void *)fw_map_dyn + le32_to_cpu(fw_map_dyn->desc_table_offset));182 if (desc_table != fw_map_dyn->raid_map_desc_table)183 dev_dbg(&instance->pdev->dev, "offsets of desc table are not matching desc %p original %p\n",184 desc_table, fw_map_dyn->raid_map_desc_table);185 186 ld_count = (u16)le16_to_cpu(fw_map_dyn->ld_count);187 pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count);188 pDrvRaidMap->fpPdIoTimeoutSec =189 fw_map_dyn->fp_pd_io_timeout_sec;190 pDrvRaidMap->totalSize =191 cpu_to_le32(sizeof(struct MR_DRV_RAID_MAP_ALL));192 /* point to actual data starting point*/193 raid_map_data = (void *)fw_map_dyn +194 le32_to_cpu(fw_map_dyn->desc_table_offset) +195 le32_to_cpu(fw_map_dyn->desc_table_size);196 197 for (i = 0; i < le32_to_cpu(fw_map_dyn->desc_table_num_elements); ++i) {198 switch (le32_to_cpu(desc_table->raid_map_desc_type)) {199 case RAID_MAP_DESC_TYPE_DEVHDL_INFO:200 fw_map_dyn->dev_hndl_info =201 (struct MR_DEV_HANDLE_INFO *)(raid_map_data + le32_to_cpu(desc_table->raid_map_desc_offset));202 memcpy(pDrvRaidMap->devHndlInfo,203 fw_map_dyn->dev_hndl_info,204 sizeof(struct MR_DEV_HANDLE_INFO) *205 le32_to_cpu(desc_table->raid_map_desc_elements));206 break;207 case RAID_MAP_DESC_TYPE_TGTID_INFO:208 fw_map_dyn->ld_tgt_id_to_ld =209 (u16 *)(raid_map_data +210 le32_to_cpu(desc_table->raid_map_desc_offset));211 for (j = 0; j < le32_to_cpu(desc_table->raid_map_desc_elements); j++) {212 pDrvRaidMap->ldTgtIdToLd[j] =213 le16_to_cpu(fw_map_dyn->ld_tgt_id_to_ld[j]);214 }215 break;216 case RAID_MAP_DESC_TYPE_ARRAY_INFO:217 fw_map_dyn->ar_map_info =218 (struct MR_ARRAY_INFO *)219 (raid_map_data + le32_to_cpu(desc_table->raid_map_desc_offset));220 memcpy(pDrvRaidMap->arMapInfo,221 fw_map_dyn->ar_map_info,222 sizeof(struct MR_ARRAY_INFO) *223 le32_to_cpu(desc_table->raid_map_desc_elements));224 break;225 case RAID_MAP_DESC_TYPE_SPAN_INFO:226 fw_map_dyn->ld_span_map =227 (struct MR_LD_SPAN_MAP *)228 (raid_map_data +229 le32_to_cpu(desc_table->raid_map_desc_offset));230 memcpy(pDrvRaidMap->ldSpanMap,231 fw_map_dyn->ld_span_map,232 sizeof(struct MR_LD_SPAN_MAP) *233 le32_to_cpu(desc_table->raid_map_desc_elements));234 break;235 default:236 dev_dbg(&instance->pdev->dev, "wrong number of desctableElements %d\n",237 fw_map_dyn->desc_table_num_elements);238 }239 ++desc_table;240 }241 242 } else if (instance->supportmax256vd) {243 fw_map_ext =244 (struct MR_FW_RAID_MAP_EXT *)fusion->ld_map[(map_id & 1)];245 ld_count = (u16)le16_to_cpu(fw_map_ext->ldCount);246 if (ld_count > MAX_LOGICAL_DRIVES_EXT) {247 dev_dbg(&instance->pdev->dev, "megaraid_sas: LD count exposed in RAID map in not valid\n");248 return 1;249 }250 251 pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count);252 pDrvRaidMap->fpPdIoTimeoutSec = fw_map_ext->fpPdIoTimeoutSec;253 for (i = 0; i < (MAX_LOGICAL_DRIVES_EXT); i++)254 pDrvRaidMap->ldTgtIdToLd[i] =255 (u16)fw_map_ext->ldTgtIdToLd[i];256 memcpy(pDrvRaidMap->ldSpanMap, fw_map_ext->ldSpanMap,257 sizeof(struct MR_LD_SPAN_MAP) * ld_count);258 memcpy(pDrvRaidMap->arMapInfo, fw_map_ext->arMapInfo,259 sizeof(struct MR_ARRAY_INFO) * MAX_API_ARRAYS_EXT);260 memcpy(pDrvRaidMap->devHndlInfo, fw_map_ext->devHndlInfo,261 sizeof(struct MR_DEV_HANDLE_INFO) *262 MAX_RAIDMAP_PHYSICAL_DEVICES);263 264 /* New Raid map will not set totalSize, so keep expected value265 * for legacy code in ValidateMapInfo266 */267 pDrvRaidMap->totalSize =268 cpu_to_le32(sizeof(struct MR_FW_RAID_MAP_EXT));269 } else {270 fw_map_old = (struct MR_FW_RAID_MAP_ALL *)271 fusion->ld_map[(map_id & 1)];272 pFwRaidMap = &fw_map_old->raidMap;273 ld_count = (u16)le32_to_cpu(pFwRaidMap->ldCount);274 if (ld_count > MAX_LOGICAL_DRIVES) {275 dev_dbg(&instance->pdev->dev,276 "LD count exposed in RAID map in not valid\n");277 return 1;278 }279 280 pDrvRaidMap->totalSize = pFwRaidMap->totalSize;281 pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count);282 pDrvRaidMap->fpPdIoTimeoutSec = pFwRaidMap->fpPdIoTimeoutSec;283 for (i = 0; i < MAX_RAIDMAP_LOGICAL_DRIVES + MAX_RAIDMAP_VIEWS; i++)284 pDrvRaidMap->ldTgtIdToLd[i] =285 (u8)pFwRaidMap->ldTgtIdToLd[i];286 for (i = 0; i < ld_count; i++) {287 pDrvRaidMap->ldSpanMap[i] = pFwRaidMap->ldSpanMap[i];288 }289 memcpy(pDrvRaidMap->arMapInfo, pFwRaidMap->arMapInfo,290 sizeof(struct MR_ARRAY_INFO) * MAX_RAIDMAP_ARRAYS);291 memcpy(pDrvRaidMap->devHndlInfo, pFwRaidMap->devHndlInfo,292 sizeof(struct MR_DEV_HANDLE_INFO) *293 MAX_RAIDMAP_PHYSICAL_DEVICES);294 }295 296 return 0;297}298 299/*300 * This function will validate Map info data provided by FW301 */302u8 MR_ValidateMapInfo(struct megasas_instance *instance, u64 map_id)303{304 struct fusion_context *fusion;305 struct MR_DRV_RAID_MAP_ALL *drv_map;306 struct MR_DRV_RAID_MAP *pDrvRaidMap;307 struct LD_LOAD_BALANCE_INFO *lbInfo;308 PLD_SPAN_INFO ldSpanInfo;309 struct MR_LD_RAID *raid;310 u16 num_lds, i;311 u16 ld;312 u32 expected_size;313 314 if (MR_PopulateDrvRaidMap(instance, map_id))315 return 0;316 317 fusion = instance->ctrl_context;318 drv_map = fusion->ld_drv_map[(map_id & 1)];319 pDrvRaidMap = &drv_map->raidMap;320 321 lbInfo = fusion->load_balance_info;322 ldSpanInfo = fusion->log_to_span;323 324 if (instance->max_raid_mapsize)325 expected_size = sizeof(struct MR_DRV_RAID_MAP_ALL);326 else if (instance->supportmax256vd)327 expected_size = sizeof(struct MR_FW_RAID_MAP_EXT);328 else329 expected_size = struct_size_t(struct MR_FW_RAID_MAP,330 ldSpanMap,331 le16_to_cpu(pDrvRaidMap->ldCount));332 333 if (le32_to_cpu(pDrvRaidMap->totalSize) != expected_size) {334 dev_dbg(&instance->pdev->dev, "megasas: map info structure size 0x%x",335 le32_to_cpu(pDrvRaidMap->totalSize));336 dev_dbg(&instance->pdev->dev, "is not matching expected size 0x%x\n",337 (unsigned int)expected_size);338 dev_err(&instance->pdev->dev, "megasas: span map %x, pDrvRaidMap->totalSize : %x\n",339 (unsigned int)sizeof(struct MR_LD_SPAN_MAP),340 le32_to_cpu(pDrvRaidMap->totalSize));341 return 0;342 }343 344 if (instance->UnevenSpanSupport)345 mr_update_span_set(drv_map, ldSpanInfo);346 347 if (lbInfo)348 mr_update_load_balance_params(drv_map, lbInfo);349 350 num_lds = le16_to_cpu(drv_map->raidMap.ldCount);351 352 memcpy(instance->ld_ids_prev,353 instance->ld_ids_from_raidmap,354 sizeof(instance->ld_ids_from_raidmap));355 memset(instance->ld_ids_from_raidmap, 0xff, MEGASAS_MAX_LD_IDS);356 /*Convert Raid capability values to CPU arch */357 for (i = 0; (num_lds > 0) && (i < MAX_LOGICAL_DRIVES_EXT); i++) {358 ld = MR_TargetIdToLdGet(i, drv_map);359 360 /* For non existing VDs, iterate to next VD*/361 if (ld >= MEGASAS_MAX_SUPPORTED_LD_IDS)362 continue;363 364 raid = MR_LdRaidGet(ld, drv_map);365 le32_to_cpus((u32 *)&raid->capability);366 instance->ld_ids_from_raidmap[i] = i;367 num_lds--;368 }369 370 return 1;371}372 373static u32 MR_GetSpanBlock(u32 ld, u64 row, u64 *span_blk,374 struct MR_DRV_RAID_MAP_ALL *map)375{376 struct MR_SPAN_BLOCK_INFO *pSpanBlock = MR_LdSpanInfoGet(ld, map);377 struct MR_QUAD_ELEMENT *quad;378 struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);379 u32 span, j;380 381 for (span = 0; span < raid->spanDepth; span++, pSpanBlock++) {382 383 for (j = 0; j < le32_to_cpu(pSpanBlock->block_span_info.noElements); j++) {384 quad = &pSpanBlock->block_span_info.quad[j];385 386 if (le32_to_cpu(quad->diff) == 0)387 return SPAN_INVALID;388 if (le64_to_cpu(quad->logStart) <= row && row <=389 le64_to_cpu(quad->logEnd) && (mega_mod64(row - le64_to_cpu(quad->logStart),390 le32_to_cpu(quad->diff))) == 0) {391 if (span_blk != NULL) {392 u64 blk;393 blk = mega_div64_32((row-le64_to_cpu(quad->logStart)), le32_to_cpu(quad->diff));394 395 blk = (blk + le64_to_cpu(quad->offsetInSpan)) << raid->stripeShift;396 *span_blk = blk;397 }398 return span;399 }400 }401 }402 return SPAN_INVALID;403}404 405/*406******************************************************************************407*408* This routine calculates the Span block for given row using spanset.409*410* Inputs :411* instance - HBA instance412* ld - Logical drive number413* row - Row number414* map - LD map415*416* Outputs :417*418* span - Span number419* block - Absolute Block number in the physical disk420* div_error - Devide error code.421*/422 423static u32 mr_spanset_get_span_block(struct megasas_instance *instance,424 u32 ld, u64 row, u64 *span_blk, struct MR_DRV_RAID_MAP_ALL *map)425{426 struct fusion_context *fusion = instance->ctrl_context;427 struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);428 LD_SPAN_SET *span_set;429 struct MR_QUAD_ELEMENT *quad;430 u32 span, info;431 PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span;432 433 for (info = 0; info < MAX_QUAD_DEPTH; info++) {434 span_set = &(ldSpanInfo[ld].span_set[info]);435 436 if (span_set->span_row_data_width == 0)437 break;438 439 if (row > span_set->data_row_end)440 continue;441 442 for (span = 0; span < raid->spanDepth; span++)443 if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].444 block_span_info.noElements) >= info+1) {445 quad = &map->raidMap.ldSpanMap[ld].446 spanBlock[span].447 block_span_info.quad[info];448 if (le32_to_cpu(quad->diff) == 0)449 return SPAN_INVALID;450 if (le64_to_cpu(quad->logStart) <= row &&451 row <= le64_to_cpu(quad->logEnd) &&452 (mega_mod64(row - le64_to_cpu(quad->logStart),453 le32_to_cpu(quad->diff))) == 0) {454 if (span_blk != NULL) {455 u64 blk;456 blk = mega_div64_32457 ((row - le64_to_cpu(quad->logStart)),458 le32_to_cpu(quad->diff));459 blk = (blk + le64_to_cpu(quad->offsetInSpan))460 << raid->stripeShift;461 *span_blk = blk;462 }463 return span;464 }465 }466 }467 return SPAN_INVALID;468}469 470/*471******************************************************************************472*473* This routine calculates the row for given strip using spanset.474*475* Inputs :476* instance - HBA instance477* ld - Logical drive number478* Strip - Strip479* map - LD map480*481* Outputs :482*483* row - row associated with strip484*/485 486static u64 get_row_from_strip(struct megasas_instance *instance,487 u32 ld, u64 strip, struct MR_DRV_RAID_MAP_ALL *map)488{489 struct fusion_context *fusion = instance->ctrl_context;490 struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);491 LD_SPAN_SET *span_set;492 PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span;493 u32 info, strip_offset, span, span_offset;494 u64 span_set_Strip, span_set_Row, retval;495 496 for (info = 0; info < MAX_QUAD_DEPTH; info++) {497 span_set = &(ldSpanInfo[ld].span_set[info]);498 499 if (span_set->span_row_data_width == 0)500 break;501 if (strip > span_set->data_strip_end)502 continue;503 504 span_set_Strip = strip - span_set->data_strip_start;505 strip_offset = mega_mod64(span_set_Strip,506 span_set->span_row_data_width);507 span_set_Row = mega_div64_32(span_set_Strip,508 span_set->span_row_data_width) * span_set->diff;509 for (span = 0, span_offset = 0; span < raid->spanDepth; span++)510 if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].511 block_span_info.noElements) >= info+1) {512 if (strip_offset >=513 span_set->strip_offset[span])514 span_offset++;515 else516 break;517 }518 519 retval = (span_set->data_row_start + span_set_Row +520 (span_offset - 1));521 return retval;522 }523 return -1LLU;524}525 526 527/*528******************************************************************************529*530* This routine calculates the Start Strip for given row using spanset.531*532* Inputs :533* instance - HBA instance534* ld - Logical drive number535* row - Row number536* map - LD map537*538* Outputs :539*540* Strip - Start strip associated with row541*/542 543static u64 get_strip_from_row(struct megasas_instance *instance,544 u32 ld, u64 row, struct MR_DRV_RAID_MAP_ALL *map)545{546 struct fusion_context *fusion = instance->ctrl_context;547 struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);548 LD_SPAN_SET *span_set;549 struct MR_QUAD_ELEMENT *quad;550 PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span;551 u32 span, info;552 u64 strip;553 554 for (info = 0; info < MAX_QUAD_DEPTH; info++) {555 span_set = &(ldSpanInfo[ld].span_set[info]);556 557 if (span_set->span_row_data_width == 0)558 break;559 if (row > span_set->data_row_end)560 continue;561 562 for (span = 0; span < raid->spanDepth; span++)563 if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].564 block_span_info.noElements) >= info+1) {565 quad = &map->raidMap.ldSpanMap[ld].566 spanBlock[span].block_span_info.quad[info];567 if (le64_to_cpu(quad->logStart) <= row &&568 row <= le64_to_cpu(quad->logEnd) &&569 mega_mod64((row - le64_to_cpu(quad->logStart)),570 le32_to_cpu(quad->diff)) == 0) {571 strip = mega_div64_32572 (((row - span_set->data_row_start)573 - le64_to_cpu(quad->logStart)),574 le32_to_cpu(quad->diff));575 strip *= span_set->span_row_data_width;576 strip += span_set->data_strip_start;577 strip += span_set->strip_offset[span];578 return strip;579 }580 }581 }582 dev_err(&instance->pdev->dev, "get_strip_from_row"583 "returns invalid strip for ld=%x, row=%lx\n",584 ld, (long unsigned int)row);585 return -1;586}587 588/*589******************************************************************************590*591* This routine calculates the Physical Arm for given strip using spanset.592*593* Inputs :594* instance - HBA instance595* ld - Logical drive number596* strip - Strip597* map - LD map598*599* Outputs :600*601* Phys Arm - Phys Arm associated with strip602*/603 604static u32 get_arm_from_strip(struct megasas_instance *instance,605 u32 ld, u64 strip, struct MR_DRV_RAID_MAP_ALL *map)606{607 struct fusion_context *fusion = instance->ctrl_context;608 struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);609 LD_SPAN_SET *span_set;610 PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span;611 u32 info, strip_offset, span, span_offset, retval;612 613 for (info = 0 ; info < MAX_QUAD_DEPTH; info++) {614 span_set = &(ldSpanInfo[ld].span_set[info]);615 616 if (span_set->span_row_data_width == 0)617 break;618 if (strip > span_set->data_strip_end)619 continue;620 621 strip_offset = (uint)mega_mod64622 ((strip - span_set->data_strip_start),623 span_set->span_row_data_width);624 625 for (span = 0, span_offset = 0; span < raid->spanDepth; span++)626 if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].627 block_span_info.noElements) >= info+1) {628 if (strip_offset >=629 span_set->strip_offset[span])630 span_offset =631 span_set->strip_offset[span];632 else633 break;634 }635 636 retval = (strip_offset - span_offset);637 return retval;638 }639 640 dev_err(&instance->pdev->dev, "get_arm_from_strip"641 "returns invalid arm for ld=%x strip=%lx\n",642 ld, (long unsigned int)strip);643 644 return -1;645}646 647/* This Function will return Phys arm */648static u8 get_arm(struct megasas_instance *instance, u32 ld, u8 span, u64 stripe,649 struct MR_DRV_RAID_MAP_ALL *map)650{651 struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);652 /* Need to check correct default value */653 u32 arm = 0;654 655 switch (raid->level) {656 case 0:657 case 5:658 case 6:659 arm = mega_mod64(stripe, SPAN_ROW_SIZE(map, ld, span));660 break;661 case 1:662 /* start with logical arm */663 arm = get_arm_from_strip(instance, ld, stripe, map);664 if (arm != -1U)665 arm *= 2;666 break;667 }668 669 return arm;670}671 672 673/*674******************************************************************************675*676* This routine calculates the arm, span and block for the specified stripe and677* reference in stripe using spanset678*679* Inputs :680*681* ld - Logical drive number682* stripRow - Stripe number683* stripRef - Reference in stripe684*685* Outputs :686*687* span - Span number688* block - Absolute Block number in the physical disk689*/690static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld,691 u64 stripRow, u16 stripRef, struct IO_REQUEST_INFO *io_info,692 struct RAID_CONTEXT *pRAID_Context,693 struct MR_DRV_RAID_MAP_ALL *map)694{695 struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);696 u32 pd, arRef, r1_alt_pd;697 u8 physArm, span;698 u64 row;699 u8 retval = true;700 u64 *pdBlock = &io_info->pdBlock;701 __le16 *pDevHandle = &io_info->devHandle;702 u8 *pPdInterface = &io_info->pd_interface;703 u32 logArm, rowMod, armQ, arm;704 705 *pDevHandle = cpu_to_le16(MR_DEVHANDLE_INVALID);706 707 /*Get row and span from io_info for Uneven Span IO.*/708 row = io_info->start_row;709 span = io_info->start_span;710 711 712 if (raid->level == 6) {713 logArm = get_arm_from_strip(instance, ld, stripRow, map);714 if (logArm == -1U)715 return false;716 rowMod = mega_mod64(row, SPAN_ROW_SIZE(map, ld, span));717 armQ = SPAN_ROW_SIZE(map, ld, span) - 1 - rowMod;718 arm = armQ + 1 + logArm;719 if (arm >= SPAN_ROW_SIZE(map, ld, span))720 arm -= SPAN_ROW_SIZE(map, ld, span);721 physArm = (u8)arm;722 } else723 /* Calculate the arm */724 physArm = get_arm(instance, ld, span, stripRow, map);725 if (physArm == 0xFF)726 return false;727 728 arRef = MR_LdSpanArrayGet(ld, span, map);729 pd = MR_ArPdGet(arRef, physArm, map);730 731 if (pd != MR_PD_INVALID) {732 *pDevHandle = MR_PdDevHandleGet(pd, map);733 *pPdInterface = MR_PdInterfaceTypeGet(pd, map);734 /* get second pd also for raid 1/10 fast path writes*/735 if ((instance->adapter_type >= VENTURA_SERIES) &&736 (raid->level == 1) &&737 !io_info->isRead) {738 r1_alt_pd = MR_ArPdGet(arRef, physArm + 1, map);739 if (r1_alt_pd != MR_PD_INVALID)740 io_info->r1_alt_dev_handle =741 MR_PdDevHandleGet(r1_alt_pd, map);742 }743 } else {744 if ((raid->level >= 5) &&745 ((instance->adapter_type == THUNDERBOLT_SERIES) ||746 ((instance->adapter_type == INVADER_SERIES) &&747 (raid->regTypeReqOnRead != REGION_TYPE_UNUSED))))748 pRAID_Context->reg_lock_flags = REGION_TYPE_EXCLUSIVE;749 else if (raid->level == 1) {750 physArm = physArm + 1;751 pd = MR_ArPdGet(arRef, physArm, map);752 if (pd != MR_PD_INVALID) {753 *pDevHandle = MR_PdDevHandleGet(pd, map);754 *pPdInterface = MR_PdInterfaceTypeGet(pd, map);755 }756 }757 }758 759 *pdBlock += stripRef + le64_to_cpu(MR_LdSpanPtrGet(ld, span, map)->startBlk);760 if (instance->adapter_type >= VENTURA_SERIES) {761 ((struct RAID_CONTEXT_G35 *)pRAID_Context)->span_arm =762 (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm;763 io_info->span_arm =764 (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm;765 } else {766 pRAID_Context->span_arm =767 (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm;768 io_info->span_arm = pRAID_Context->span_arm;769 }770 io_info->pd_after_lb = pd;771 return retval;772}773 774/*775******************************************************************************776*777* This routine calculates the arm, span and block for the specified stripe and778* reference in stripe.779*780* Inputs :781*782* ld - Logical drive number783* stripRow - Stripe number784* stripRef - Reference in stripe785*786* Outputs :787*788* span - Span number789* block - Absolute Block number in the physical disk790*/791static u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow,792 u16 stripRef, struct IO_REQUEST_INFO *io_info,793 struct RAID_CONTEXT *pRAID_Context,794 struct MR_DRV_RAID_MAP_ALL *map)795{796 struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);797 u32 pd, arRef, r1_alt_pd;798 u8 physArm, span;799 u64 row;800 u8 retval = true;801 u64 *pdBlock = &io_info->pdBlock;802 __le16 *pDevHandle = &io_info->devHandle;803 u8 *pPdInterface = &io_info->pd_interface;804 805 *pDevHandle = cpu_to_le16(MR_DEVHANDLE_INVALID);806 807 row = mega_div64_32(stripRow, raid->rowDataSize);808 809 if (raid->level == 6) {810 /* logical arm within row */811 u32 logArm = mega_mod64(stripRow, raid->rowDataSize);812 u32 rowMod, armQ, arm;813 814 if (raid->rowSize == 0)815 return false;816 /* get logical row mod */817 rowMod = mega_mod64(row, raid->rowSize);818 armQ = raid->rowSize-1-rowMod; /* index of Q drive */819 arm = armQ+1+logArm; /* data always logically follows Q */820 if (arm >= raid->rowSize) /* handle wrap condition */821 arm -= raid->rowSize;822 physArm = (u8)arm;823 } else {824 if (raid->modFactor == 0)825 return false;826 physArm = MR_LdDataArmGet(ld, mega_mod64(stripRow,827 raid->modFactor),828 map);829 }830 831 if (raid->spanDepth == 1) {832 span = 0;833 *pdBlock = row << raid->stripeShift;834 } else {835 span = (u8)MR_GetSpanBlock(ld, row, pdBlock, map);836 if (span == SPAN_INVALID)837 return false;838 }839 840 /* Get the array on which this span is present */841 arRef = MR_LdSpanArrayGet(ld, span, map);842 pd = MR_ArPdGet(arRef, physArm, map); /* Get the pd */843 844 if (pd != MR_PD_INVALID) {845 /* Get dev handle from Pd. */846 *pDevHandle = MR_PdDevHandleGet(pd, map);847 *pPdInterface = MR_PdInterfaceTypeGet(pd, map);848 /* get second pd also for raid 1/10 fast path writes*/849 if ((instance->adapter_type >= VENTURA_SERIES) &&850 (raid->level == 1) &&851 !io_info->isRead) {852 r1_alt_pd = MR_ArPdGet(arRef, physArm + 1, map);853 if (r1_alt_pd != MR_PD_INVALID)854 io_info->r1_alt_dev_handle =855 MR_PdDevHandleGet(r1_alt_pd, map);856 }857 } else {858 if ((raid->level >= 5) &&859 ((instance->adapter_type == THUNDERBOLT_SERIES) ||860 ((instance->adapter_type == INVADER_SERIES) &&861 (raid->regTypeReqOnRead != REGION_TYPE_UNUSED))))862 pRAID_Context->reg_lock_flags = REGION_TYPE_EXCLUSIVE;863 else if (raid->level == 1) {864 /* Get alternate Pd. */865 physArm = physArm + 1;866 pd = MR_ArPdGet(arRef, physArm, map);867 if (pd != MR_PD_INVALID) {868 /* Get dev handle from Pd */869 *pDevHandle = MR_PdDevHandleGet(pd, map);870 *pPdInterface = MR_PdInterfaceTypeGet(pd, map);871 }872 }873 }874 875 *pdBlock += stripRef + le64_to_cpu(MR_LdSpanPtrGet(ld, span, map)->startBlk);876 if (instance->adapter_type >= VENTURA_SERIES) {877 ((struct RAID_CONTEXT_G35 *)pRAID_Context)->span_arm =878 (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm;879 io_info->span_arm =880 (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm;881 } else {882 pRAID_Context->span_arm =883 (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm;884 io_info->span_arm = pRAID_Context->span_arm;885 }886 io_info->pd_after_lb = pd;887 return retval;888}889 890/*891 * mr_get_phy_params_r56_rmw - Calculate parameters for R56 CTIO write operation892 * @instance: Adapter soft state893 * @ld: LD index894 * @stripNo: Strip Number895 * @io_info: IO info structure pointer896 * pRAID_Context: RAID context pointer897 * map: RAID map pointer898 *899 * This routine calculates the logical arm, data Arm, row number and parity arm900 * for R56 CTIO write operation.901 */902static void mr_get_phy_params_r56_rmw(struct megasas_instance *instance,903 u32 ld, u64 stripNo,904 struct IO_REQUEST_INFO *io_info,905 struct RAID_CONTEXT_G35 *pRAID_Context,906 struct MR_DRV_RAID_MAP_ALL *map)907{908 struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map);909 u8 span, dataArms, arms, dataArm, logArm;910 s8 rightmostParityArm, PParityArm;911 u64 rowNum;912 u64 *pdBlock = &io_info->pdBlock;913 914 dataArms = raid->rowDataSize;915 arms = raid->rowSize;916 917 rowNum = mega_div64_32(stripNo, dataArms);918 /* parity disk arm, first arm is 0 */919 rightmostParityArm = (arms - 1) - mega_mod64(rowNum, arms);920 921 /* logical arm within row */922 logArm = mega_mod64(stripNo, dataArms);923 /* physical arm for data */924 dataArm = mega_mod64((rightmostParityArm + 1 + logArm), arms);925 926 if (raid->spanDepth == 1) {927 span = 0;928 } else {929 span = (u8)MR_GetSpanBlock(ld, rowNum, pdBlock, map);930 if (span == SPAN_INVALID)931 return;932 }933 934 if (raid->level == 6) {935 /* P Parity arm, note this can go negative adjust if negative */936 PParityArm = (arms - 2) - mega_mod64(rowNum, arms);937 938 if (PParityArm < 0)939 PParityArm += arms;940 941 /* rightmostParityArm is P-Parity for RAID 5 and Q-Parity for RAID */942 pRAID_Context->flow_specific.r56_arm_map = rightmostParityArm;943 pRAID_Context->flow_specific.r56_arm_map |=944 (u16)(PParityArm << RAID_CTX_R56_P_ARM_SHIFT);945 } else {946 pRAID_Context->flow_specific.r56_arm_map |=947 (u16)(rightmostParityArm << RAID_CTX_R56_P_ARM_SHIFT);948 }949 950 pRAID_Context->reg_lock_row_lba = cpu_to_le64(rowNum);951 pRAID_Context->flow_specific.r56_arm_map |=952 (u16)(logArm << RAID_CTX_R56_LOG_ARM_SHIFT);953 cpu_to_le16s(&pRAID_Context->flow_specific.r56_arm_map);954 pRAID_Context->span_arm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | dataArm;955 pRAID_Context->raid_flags = (MR_RAID_FLAGS_IO_SUB_TYPE_R56_DIV_OFFLOAD <<956 MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT);957 958 return;959}960 961/*962******************************************************************************963*964* MR_BuildRaidContext function965*966* This function will initiate command processing. The start/end row and strip967* information is calculated then the lock is acquired.968* This function will return 0 if region lock was acquired OR return num strips969*/970u8971MR_BuildRaidContext(struct megasas_instance *instance,972 struct IO_REQUEST_INFO *io_info,973 struct RAID_CONTEXT *pRAID_Context,974 struct MR_DRV_RAID_MAP_ALL *map, u8 **raidLUN)975{976 struct fusion_context *fusion;977 struct MR_LD_RAID *raid;978 u32 stripSize, stripe_mask;979 u64 endLba, endStrip, endRow, start_row, start_strip;980 u64 regStart;981 u32 regSize;982 u8 num_strips, numRows;983 u16 ref_in_start_stripe, ref_in_end_stripe;984 u64 ldStartBlock;985 u32 numBlocks, ldTgtId;986 u8 isRead;987 u8 retval = 0;988 u8 startlba_span = SPAN_INVALID;989 u64 *pdBlock = &io_info->pdBlock;990 u16 ld;991 992 ldStartBlock = io_info->ldStartBlock;993 numBlocks = io_info->numBlocks;994 ldTgtId = io_info->ldTgtId;995 isRead = io_info->isRead;996 io_info->IoforUnevenSpan = 0;997 io_info->start_span = SPAN_INVALID;998 fusion = instance->ctrl_context;999 1000 ld = MR_TargetIdToLdGet(ldTgtId, map);1001 raid = MR_LdRaidGet(ld, map);1002 /*check read ahead bit*/1003 io_info->ra_capable = raid->capability.ra_capable;1004 1005 /*1006 * if rowDataSize @RAID map and spanRowDataSize @SPAN INFO are zero1007 * return FALSE1008 */1009 if (raid->rowDataSize == 0) {1010 if (MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize == 0)1011 return false;1012 else if (instance->UnevenSpanSupport) {1013 io_info->IoforUnevenSpan = 1;1014 } else {1015 dev_info(&instance->pdev->dev,1016 "raid->rowDataSize is 0, but has SPAN[0]"1017 "rowDataSize = 0x%0x,"1018 "but there is _NO_ UnevenSpanSupport\n",1019 MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize);1020 return false;1021 }1022 }1023 1024 stripSize = 1 << raid->stripeShift;1025 stripe_mask = stripSize-1;1026 1027 io_info->data_arms = raid->rowDataSize;1028 1029 /*1030 * calculate starting row and stripe, and number of strips and rows1031 */1032 start_strip = ldStartBlock >> raid->stripeShift;1033 ref_in_start_stripe = (u16)(ldStartBlock & stripe_mask);1034 endLba = ldStartBlock + numBlocks - 1;1035 ref_in_end_stripe = (u16)(endLba & stripe_mask);1036 endStrip = endLba >> raid->stripeShift;1037 num_strips = (u8)(endStrip - start_strip + 1); /* End strip */1038 1039 if (io_info->IoforUnevenSpan) {1040 start_row = get_row_from_strip(instance, ld, start_strip, map);1041 endRow = get_row_from_strip(instance, ld, endStrip, map);1042 if (start_row == -1ULL || endRow == -1ULL) {1043 dev_info(&instance->pdev->dev, "return from %s %d."1044 "Send IO w/o region lock.\n",1045 __func__, __LINE__);1046 return false;1047 }1048 1049 if (raid->spanDepth == 1) {1050 startlba_span = 0;1051 *pdBlock = start_row << raid->stripeShift;1052 } else1053 startlba_span = (u8)mr_spanset_get_span_block(instance,1054 ld, start_row, pdBlock, map);1055 if (startlba_span == SPAN_INVALID) {1056 dev_info(&instance->pdev->dev, "return from %s %d"1057 "for row 0x%llx,start strip %llx"1058 "endSrip %llx\n", __func__, __LINE__,1059 (unsigned long long)start_row,1060 (unsigned long long)start_strip,1061 (unsigned long long)endStrip);1062 return false;1063 }1064 io_info->start_span = startlba_span;1065 io_info->start_row = start_row;1066 } else {1067 start_row = mega_div64_32(start_strip, raid->rowDataSize);1068 endRow = mega_div64_32(endStrip, raid->rowDataSize);1069 }1070 numRows = (u8)(endRow - start_row + 1);1071 1072 /*1073 * calculate region info.1074 */1075 1076 /* assume region is at the start of the first row */1077 regStart = start_row << raid->stripeShift;1078 /* assume this IO needs the full row - we'll adjust if not true */1079 regSize = stripSize;1080 1081 io_info->do_fp_rlbypass = raid->capability.fpBypassRegionLock;1082 1083 /* Check if we can send this I/O via FastPath */1084 if (raid->capability.fpCapable) {1085 if (isRead)1086 io_info->fpOkForIo = (raid->capability.fpReadCapable &&1087 ((num_strips == 1) ||1088 raid->capability.1089 fpReadAcrossStripe));1090 else1091 io_info->fpOkForIo = (raid->capability.fpWriteCapable &&1092 ((num_strips == 1) ||1093 raid->capability.1094 fpWriteAcrossStripe));1095 } else1096 io_info->fpOkForIo = false;1097 1098 if (numRows == 1) {1099 /* single-strip IOs can always lock only the data needed */1100 if (num_strips == 1) {1101 regStart += ref_in_start_stripe;1102 regSize = numBlocks;1103 }1104 /* multi-strip IOs always need to full stripe locked */1105 } else if (io_info->IoforUnevenSpan == 0) {1106 /*1107 * For Even span region lock optimization.1108 * If the start strip is the last in the start row1109 */1110 if (start_strip == (start_row + 1) * raid->rowDataSize - 1) {1111 regStart += ref_in_start_stripe;1112 /* initialize count to sectors from startref to end1113 of strip */1114 regSize = stripSize - ref_in_start_stripe;1115 }1116 1117 /* add complete rows in the middle of the transfer */1118 if (numRows > 2)1119 regSize += (numRows-2) << raid->stripeShift;1120 1121 /* if IO ends within first strip of last row*/1122 if (endStrip == endRow*raid->rowDataSize)1123 regSize += ref_in_end_stripe+1;1124 else1125 regSize += stripSize;1126 } else {1127 /*1128 * For Uneven span region lock optimization.1129 * If the start strip is the last in the start row1130 */1131 if (start_strip == (get_strip_from_row(instance, ld, start_row, map) +1132 SPAN_ROW_DATA_SIZE(map, ld, startlba_span) - 1)) {1133 regStart += ref_in_start_stripe;1134 /* initialize count to sectors from1135 * startRef to end of strip1136 */1137 regSize = stripSize - ref_in_start_stripe;1138 }1139 /* Add complete rows in the middle of the transfer*/1140 1141 if (numRows > 2)1142 /* Add complete rows in the middle of the transfer*/1143 regSize += (numRows-2) << raid->stripeShift;1144 1145 /* if IO ends within first strip of last row */1146 if (endStrip == get_strip_from_row(instance, ld, endRow, map))1147 regSize += ref_in_end_stripe + 1;1148 else1149 regSize += stripSize;1150 }1151 1152 pRAID_Context->timeout_value =1153 cpu_to_le16(raid->fpIoTimeoutForLd ?1154 raid->fpIoTimeoutForLd :1155 map->raidMap.fpPdIoTimeoutSec);1156 if (instance->adapter_type == INVADER_SERIES)1157 pRAID_Context->reg_lock_flags = (isRead) ?1158 raid->regTypeReqOnRead : raid->regTypeReqOnWrite;1159 else if (instance->adapter_type == THUNDERBOLT_SERIES)1160 pRAID_Context->reg_lock_flags = (isRead) ?1161 REGION_TYPE_SHARED_READ : raid->regTypeReqOnWrite;1162 pRAID_Context->virtual_disk_tgt_id = raid->targetId;1163 pRAID_Context->reg_lock_row_lba = cpu_to_le64(regStart);1164 pRAID_Context->reg_lock_length = cpu_to_le32(regSize);1165 pRAID_Context->config_seq_num = raid->seqNum;1166 /* save pointer to raid->LUN array */1167 *raidLUN = raid->LUN;1168 1169 /* Aero R5/6 Division Offload for WRITE */1170 if (fusion->r56_div_offload && (raid->level >= 5) && !isRead) {1171 mr_get_phy_params_r56_rmw(instance, ld, start_strip, io_info,1172 (struct RAID_CONTEXT_G35 *)pRAID_Context,1173 map);1174 return true;1175 }1176 1177 /*Get Phy Params only if FP capable, or else leave it to MR firmware1178 to do the calculation.*/1179 if (io_info->fpOkForIo) {1180 retval = io_info->IoforUnevenSpan ?1181 mr_spanset_get_phy_params(instance, ld,1182 start_strip, ref_in_start_stripe,1183 io_info, pRAID_Context, map) :1184 MR_GetPhyParams(instance, ld, start_strip,1185 ref_in_start_stripe, io_info,1186 pRAID_Context, map);1187 /* If IO on an invalid Pd, then FP is not possible.*/1188 if (io_info->devHandle == MR_DEVHANDLE_INVALID)1189 io_info->fpOkForIo = false;1190 return retval;1191 } else if (isRead) {1192 uint stripIdx;1193 for (stripIdx = 0; stripIdx < num_strips; stripIdx++) {1194 retval = io_info->IoforUnevenSpan ?1195 mr_spanset_get_phy_params(instance, ld,1196 start_strip + stripIdx,1197 ref_in_start_stripe, io_info,1198 pRAID_Context, map) :1199 MR_GetPhyParams(instance, ld,1200 start_strip + stripIdx, ref_in_start_stripe,1201 io_info, pRAID_Context, map);1202 if (!retval)1203 return true;1204 }1205 }1206 return true;1207}1208 1209/*1210******************************************************************************1211*1212* This routine pepare spanset info from Valid Raid map and store it into1213* local copy of ldSpanInfo per instance data structure.1214*1215* Inputs :1216* map - LD map1217* ldSpanInfo - ldSpanInfo per HBA instance1218*1219*/1220void mr_update_span_set(struct MR_DRV_RAID_MAP_ALL *map,1221 PLD_SPAN_INFO ldSpanInfo)1222{1223 u8 span, count;1224 u32 element, span_row_width;1225 u64 span_row;1226 struct MR_LD_RAID *raid;1227 LD_SPAN_SET *span_set, *span_set_prev;1228 struct MR_QUAD_ELEMENT *quad;1229 int ldCount;1230 u16 ld;1231 1232 1233 for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES_EXT; ldCount++) {1234 ld = MR_TargetIdToLdGet(ldCount, map);1235 if (ld >= (MAX_LOGICAL_DRIVES_EXT - 1))1236 continue;1237 raid = MR_LdRaidGet(ld, map);1238 for (element = 0; element < MAX_QUAD_DEPTH; element++) {1239 for (span = 0; span < raid->spanDepth; span++) {1240 if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].1241 block_span_info.noElements) <1242 element + 1)1243 continue;1244 span_set = &(ldSpanInfo[ld].span_set[element]);1245 quad = &map->raidMap.ldSpanMap[ld].1246 spanBlock[span].block_span_info.1247 quad[element];1248 1249 span_set->diff = le32_to_cpu(quad->diff);1250 1251 for (count = 0, span_row_width = 0;1252 count < raid->spanDepth; count++) {1253 if (le32_to_cpu(map->raidMap.ldSpanMap[ld].1254 spanBlock[count].1255 block_span_info.1256 noElements) >= element + 1) {1257 span_set->strip_offset[count] =1258 span_row_width;1259 span_row_width +=1260 MR_LdSpanPtrGet1261 (ld, count, map)->spanRowDataSize;1262 }1263 }1264 1265 span_set->span_row_data_width = span_row_width;1266 span_row = mega_div64_32(((le64_to_cpu(quad->logEnd) -1267 le64_to_cpu(quad->logStart)) + le32_to_cpu(quad->diff)),1268 le32_to_cpu(quad->diff));1269 1270 if (element == 0) {1271 span_set->log_start_lba = 0;1272 span_set->log_end_lba =1273 ((span_row << raid->stripeShift)1274 * span_row_width) - 1;1275 1276 span_set->span_row_start = 0;1277 span_set->span_row_end = span_row - 1;1278 1279 span_set->data_strip_start = 0;1280 span_set->data_strip_end =1281 (span_row * span_row_width) - 1;1282 1283 span_set->data_row_start = 0;1284 span_set->data_row_end =1285 (span_row * le32_to_cpu(quad->diff)) - 1;1286 } else {1287 span_set_prev = &(ldSpanInfo[ld].1288 span_set[element - 1]);1289 span_set->log_start_lba =1290 span_set_prev->log_end_lba + 1;1291 span_set->log_end_lba =1292 span_set->log_start_lba +1293 ((span_row << raid->stripeShift)1294 * span_row_width) - 1;1295 1296 span_set->span_row_start =1297 span_set_prev->span_row_end + 1;1298 span_set->span_row_end =1299 span_set->span_row_start + span_row - 1;1300 1301 span_set->data_strip_start =1302 span_set_prev->data_strip_end + 1;1303 span_set->data_strip_end =1304 span_set->data_strip_start +1305 (span_row * span_row_width) - 1;1306 1307 span_set->data_row_start =1308 span_set_prev->data_row_end + 1;1309 span_set->data_row_end =1310 span_set->data_row_start +1311 (span_row * le32_to_cpu(quad->diff)) - 1;1312 }1313 break;1314 }1315 if (span == raid->spanDepth)1316 break;1317 }1318 }1319}1320 1321void mr_update_load_balance_params(struct MR_DRV_RAID_MAP_ALL *drv_map,1322 struct LD_LOAD_BALANCE_INFO *lbInfo)1323{1324 int ldCount;1325 u16 ld;1326 struct MR_LD_RAID *raid;1327 1328 if (lb_pending_cmds > 128 || lb_pending_cmds < 1)1329 lb_pending_cmds = LB_PENDING_CMDS_DEFAULT;1330 1331 for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES_EXT; ldCount++) {1332 ld = MR_TargetIdToLdGet(ldCount, drv_map);1333 if (ld >= MAX_LOGICAL_DRIVES_EXT - 1) {1334 lbInfo[ldCount].loadBalanceFlag = 0;1335 continue;1336 }1337 1338 raid = MR_LdRaidGet(ld, drv_map);1339 if ((raid->level != 1) ||1340 (raid->ldState != MR_LD_STATE_OPTIMAL)) {1341 lbInfo[ldCount].loadBalanceFlag = 0;1342 continue;1343 }1344 lbInfo[ldCount].loadBalanceFlag = 1;1345 }1346}1347 1348static u8 megasas_get_best_arm_pd(struct megasas_instance *instance,1349 struct LD_LOAD_BALANCE_INFO *lbInfo,1350 struct IO_REQUEST_INFO *io_info,1351 struct MR_DRV_RAID_MAP_ALL *drv_map)1352{1353 struct MR_LD_RAID *raid;1354 u16 pd1_dev_handle;1355 u16 pend0, pend1, ld;1356 u64 diff0, diff1;1357 u8 bestArm, pd0, pd1, span, arm;1358 u32 arRef, span_row_size;1359 1360 u64 block = io_info->ldStartBlock;1361 u32 count = io_info->numBlocks;1362 1363 span = ((io_info->span_arm & RAID_CTX_SPANARM_SPAN_MASK)1364 >> RAID_CTX_SPANARM_SPAN_SHIFT);1365 arm = (io_info->span_arm & RAID_CTX_SPANARM_ARM_MASK);1366 1367 ld = MR_TargetIdToLdGet(io_info->ldTgtId, drv_map);1368 raid = MR_LdRaidGet(ld, drv_map);1369 span_row_size = instance->UnevenSpanSupport ?1370 SPAN_ROW_SIZE(drv_map, ld, span) : raid->rowSize;1371 1372 arRef = MR_LdSpanArrayGet(ld, span, drv_map);1373 pd0 = MR_ArPdGet(arRef, arm, drv_map);1374 pd1 = MR_ArPdGet(arRef, (arm + 1) >= span_row_size ?1375 (arm + 1 - span_row_size) : arm + 1, drv_map);1376 1377 /* Get PD1 Dev Handle */1378 1379 pd1_dev_handle = MR_PdDevHandleGet(pd1, drv_map);1380 1381 if (pd1_dev_handle == MR_DEVHANDLE_INVALID) {1382 bestArm = arm;1383 } else {1384 /* get the pending cmds for the data and mirror arms */1385 pend0 = atomic_read(&lbInfo->scsi_pending_cmds[pd0]);1386 pend1 = atomic_read(&lbInfo->scsi_pending_cmds[pd1]);1387 1388 /* Determine the disk whose head is nearer to the req. block */1389 diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[pd0]);1390 diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[pd1]);1391 bestArm = (diff0 <= diff1 ? arm : arm ^ 1);1392 1393 /* Make balance count from 16 to 4 to1394 * keep driver in sync with Firmware1395 */1396 if ((bestArm == arm && pend0 > pend1 + lb_pending_cmds) ||1397 (bestArm != arm && pend1 > pend0 + lb_pending_cmds))1398 bestArm ^= 1;1399 1400 /* Update the last accessed block on the correct pd */1401 io_info->span_arm =1402 (span << RAID_CTX_SPANARM_SPAN_SHIFT) | bestArm;1403 io_info->pd_after_lb = (bestArm == arm) ? pd0 : pd1;1404 }1405 1406 lbInfo->last_accessed_block[io_info->pd_after_lb] = block + count - 1;1407 return io_info->pd_after_lb;1408}1409 1410__le16 get_updated_dev_handle(struct megasas_instance *instance,1411 struct LD_LOAD_BALANCE_INFO *lbInfo,1412 struct IO_REQUEST_INFO *io_info,1413 struct MR_DRV_RAID_MAP_ALL *drv_map)1414{1415 u8 arm_pd;1416 __le16 devHandle;1417 1418 /* get best new arm (PD ID) */1419 arm_pd = megasas_get_best_arm_pd(instance, lbInfo, io_info, drv_map);1420 devHandle = MR_PdDevHandleGet(arm_pd, drv_map);1421 io_info->pd_interface = MR_PdInterfaceTypeGet(arm_pd, drv_map);1422 atomic_inc(&lbInfo->scsi_pending_cmds[arm_pd]);1423 1424 return devHandle;1425}1426