162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Linux MegaRAID driver for SAS based RAID controllers 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2009-2013 LSI Corporation 662306a36Sopenharmony_ci * Copyright (c) 2013-2016 Avago Technologies 762306a36Sopenharmony_ci * Copyright (c) 2016-2018 Broadcom Inc. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * FILE: megaraid_sas_fp.c 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Authors: Broadcom Inc. 1262306a36Sopenharmony_ci * Sumant Patro 1362306a36Sopenharmony_ci * Varad Talamacki 1462306a36Sopenharmony_ci * Manoj Jose 1562306a36Sopenharmony_ci * Kashyap Desai <kashyap.desai@broadcom.com> 1662306a36Sopenharmony_ci * Sumit Saxena <sumit.saxena@broadcom.com> 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * Send feedback to: megaraidlinux.pdl@broadcom.com 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <linux/kernel.h> 2262306a36Sopenharmony_ci#include <linux/types.h> 2362306a36Sopenharmony_ci#include <linux/pci.h> 2462306a36Sopenharmony_ci#include <linux/list.h> 2562306a36Sopenharmony_ci#include <linux/moduleparam.h> 2662306a36Sopenharmony_ci#include <linux/module.h> 2762306a36Sopenharmony_ci#include <linux/spinlock.h> 2862306a36Sopenharmony_ci#include <linux/interrupt.h> 2962306a36Sopenharmony_ci#include <linux/delay.h> 3062306a36Sopenharmony_ci#include <linux/uio.h> 3162306a36Sopenharmony_ci#include <linux/uaccess.h> 3262306a36Sopenharmony_ci#include <linux/fs.h> 3362306a36Sopenharmony_ci#include <linux/compat.h> 3462306a36Sopenharmony_ci#include <linux/blkdev.h> 3562306a36Sopenharmony_ci#include <linux/poll.h> 3662306a36Sopenharmony_ci#include <linux/irq_poll.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#include <scsi/scsi.h> 3962306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 4062306a36Sopenharmony_ci#include <scsi/scsi_device.h> 4162306a36Sopenharmony_ci#include <scsi/scsi_host.h> 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#include "megaraid_sas_fusion.h" 4462306a36Sopenharmony_ci#include "megaraid_sas.h" 4562306a36Sopenharmony_ci#include <asm/div64.h> 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define LB_PENDING_CMDS_DEFAULT 4 4862306a36Sopenharmony_cistatic unsigned int lb_pending_cmds = LB_PENDING_CMDS_DEFAULT; 4962306a36Sopenharmony_cimodule_param(lb_pending_cmds, int, 0444); 5062306a36Sopenharmony_ciMODULE_PARM_DESC(lb_pending_cmds, "Change raid-1 load balancing outstanding " 5162306a36Sopenharmony_ci "threshold. Valid Values are 1-128. Default: 4"); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define ABS_DIFF(a, b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a))) 5562306a36Sopenharmony_ci#define MR_LD_STATE_OPTIMAL 3 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define SPAN_ROW_SIZE(map, ld, index_) (MR_LdSpanPtrGet(ld, index_, map)->spanRowSize) 5862306a36Sopenharmony_ci#define SPAN_ROW_DATA_SIZE(map_, ld, index_) (MR_LdSpanPtrGet(ld, index_, map)->spanRowDataSize) 5962306a36Sopenharmony_ci#define SPAN_INVALID 0xff 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* Prototypes */ 6262306a36Sopenharmony_cistatic void mr_update_span_set(struct MR_DRV_RAID_MAP_ALL *map, 6362306a36Sopenharmony_ci PLD_SPAN_INFO ldSpanInfo); 6462306a36Sopenharmony_cistatic u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld, 6562306a36Sopenharmony_ci u64 stripRow, u16 stripRef, struct IO_REQUEST_INFO *io_info, 6662306a36Sopenharmony_ci struct RAID_CONTEXT *pRAID_Context, struct MR_DRV_RAID_MAP_ALL *map); 6762306a36Sopenharmony_cistatic u64 get_row_from_strip(struct megasas_instance *instance, u32 ld, 6862306a36Sopenharmony_ci u64 strip, struct MR_DRV_RAID_MAP_ALL *map); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ciu32 mega_mod64(u64 dividend, u32 divisor) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci u64 d; 7362306a36Sopenharmony_ci u32 remainder; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (!divisor) 7662306a36Sopenharmony_ci printk(KERN_ERR "megasas : DIVISOR is zero, in div fn\n"); 7762306a36Sopenharmony_ci d = dividend; 7862306a36Sopenharmony_ci remainder = do_div(d, divisor); 7962306a36Sopenharmony_ci return remainder; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/** 8362306a36Sopenharmony_ci * mega_div64_32 - Do a 64-bit division 8462306a36Sopenharmony_ci * @dividend: Dividend 8562306a36Sopenharmony_ci * @divisor: Divisor 8662306a36Sopenharmony_ci * 8762306a36Sopenharmony_ci * @return quotient 8862306a36Sopenharmony_ci **/ 8962306a36Sopenharmony_cistatic u64 mega_div64_32(uint64_t dividend, uint32_t divisor) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci u64 d = dividend; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (!divisor) 9462306a36Sopenharmony_ci printk(KERN_ERR "megasas : DIVISOR is zero in mod fn\n"); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci do_div(d, divisor); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci return d; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistruct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_DRV_RAID_MAP_ALL *map) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci return &map->raidMap.ldSpanMap[ld].ldRaid; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic struct MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u32 ld, 10762306a36Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL 10862306a36Sopenharmony_ci *map) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci return &map->raidMap.ldSpanMap[ld].spanBlock[0]; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic u8 MR_LdDataArmGet(u32 ld, u32 armIdx, struct MR_DRV_RAID_MAP_ALL *map) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci return map->raidMap.ldSpanMap[ld].dataArmMap[armIdx]; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ciu16 MR_ArPdGet(u32 ar, u32 arm, struct MR_DRV_RAID_MAP_ALL *map) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci return le16_to_cpu(map->raidMap.arMapInfo[ar].pd[arm]); 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ciu16 MR_LdSpanArrayGet(u32 ld, u32 span, struct MR_DRV_RAID_MAP_ALL *map) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci return le16_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].span.arrayRef); 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci__le16 MR_PdDevHandleGet(u32 pd, struct MR_DRV_RAID_MAP_ALL *map) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci return map->raidMap.devHndlInfo[pd].curDevHdl; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic u8 MR_PdInterfaceTypeGet(u32 pd, struct MR_DRV_RAID_MAP_ALL *map) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci return map->raidMap.devHndlInfo[pd].interfaceType; 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ciu16 MR_GetLDTgtId(u32 ld, struct MR_DRV_RAID_MAP_ALL *map) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci return le16_to_cpu(map->raidMap.ldSpanMap[ld].ldRaid.targetId); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ciu16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_DRV_RAID_MAP_ALL *map) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci return map->raidMap.ldTgtIdToLd[ldTgtId]; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic struct MR_LD_SPAN *MR_LdSpanPtrGet(u32 ld, u32 span, 14962306a36Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *map) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci return &map->raidMap.ldSpanMap[ld].spanBlock[span].span; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/* 15562306a36Sopenharmony_ci * This function will Populate Driver Map using firmware raid map 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_cistatic int MR_PopulateDrvRaidMap(struct megasas_instance *instance, u64 map_id) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 16062306a36Sopenharmony_ci struct MR_FW_RAID_MAP_ALL *fw_map_old = NULL; 16162306a36Sopenharmony_ci struct MR_FW_RAID_MAP *pFwRaidMap = NULL; 16262306a36Sopenharmony_ci int i, j; 16362306a36Sopenharmony_ci u16 ld_count; 16462306a36Sopenharmony_ci struct MR_FW_RAID_MAP_DYNAMIC *fw_map_dyn; 16562306a36Sopenharmony_ci struct MR_FW_RAID_MAP_EXT *fw_map_ext; 16662306a36Sopenharmony_ci struct MR_RAID_MAP_DESC_TABLE *desc_table; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *drv_map = 17062306a36Sopenharmony_ci fusion->ld_drv_map[(map_id & 1)]; 17162306a36Sopenharmony_ci struct MR_DRV_RAID_MAP *pDrvRaidMap = &drv_map->raidMap; 17262306a36Sopenharmony_ci void *raid_map_data = NULL; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci memset(drv_map, 0, fusion->drv_map_sz); 17562306a36Sopenharmony_ci memset(pDrvRaidMap->ldTgtIdToLd, 17662306a36Sopenharmony_ci 0xff, (sizeof(u16) * MAX_LOGICAL_DRIVES_DYN)); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (instance->max_raid_mapsize) { 17962306a36Sopenharmony_ci fw_map_dyn = fusion->ld_map[(map_id & 1)]; 18062306a36Sopenharmony_ci desc_table = 18162306a36Sopenharmony_ci (struct MR_RAID_MAP_DESC_TABLE *)((void *)fw_map_dyn + le32_to_cpu(fw_map_dyn->desc_table_offset)); 18262306a36Sopenharmony_ci if (desc_table != fw_map_dyn->raid_map_desc_table) 18362306a36Sopenharmony_ci dev_dbg(&instance->pdev->dev, "offsets of desc table are not matching desc %p original %p\n", 18462306a36Sopenharmony_ci desc_table, fw_map_dyn->raid_map_desc_table); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci ld_count = (u16)le16_to_cpu(fw_map_dyn->ld_count); 18762306a36Sopenharmony_ci pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count); 18862306a36Sopenharmony_ci pDrvRaidMap->fpPdIoTimeoutSec = 18962306a36Sopenharmony_ci fw_map_dyn->fp_pd_io_timeout_sec; 19062306a36Sopenharmony_ci pDrvRaidMap->totalSize = 19162306a36Sopenharmony_ci cpu_to_le32(sizeof(struct MR_DRV_RAID_MAP_ALL)); 19262306a36Sopenharmony_ci /* point to actual data starting point*/ 19362306a36Sopenharmony_ci raid_map_data = (void *)fw_map_dyn + 19462306a36Sopenharmony_ci le32_to_cpu(fw_map_dyn->desc_table_offset) + 19562306a36Sopenharmony_ci le32_to_cpu(fw_map_dyn->desc_table_size); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci for (i = 0; i < le32_to_cpu(fw_map_dyn->desc_table_num_elements); ++i) { 19862306a36Sopenharmony_ci switch (le32_to_cpu(desc_table->raid_map_desc_type)) { 19962306a36Sopenharmony_ci case RAID_MAP_DESC_TYPE_DEVHDL_INFO: 20062306a36Sopenharmony_ci fw_map_dyn->dev_hndl_info = 20162306a36Sopenharmony_ci (struct MR_DEV_HANDLE_INFO *)(raid_map_data + le32_to_cpu(desc_table->raid_map_desc_offset)); 20262306a36Sopenharmony_ci memcpy(pDrvRaidMap->devHndlInfo, 20362306a36Sopenharmony_ci fw_map_dyn->dev_hndl_info, 20462306a36Sopenharmony_ci sizeof(struct MR_DEV_HANDLE_INFO) * 20562306a36Sopenharmony_ci le32_to_cpu(desc_table->raid_map_desc_elements)); 20662306a36Sopenharmony_ci break; 20762306a36Sopenharmony_ci case RAID_MAP_DESC_TYPE_TGTID_INFO: 20862306a36Sopenharmony_ci fw_map_dyn->ld_tgt_id_to_ld = 20962306a36Sopenharmony_ci (u16 *)(raid_map_data + 21062306a36Sopenharmony_ci le32_to_cpu(desc_table->raid_map_desc_offset)); 21162306a36Sopenharmony_ci for (j = 0; j < le32_to_cpu(desc_table->raid_map_desc_elements); j++) { 21262306a36Sopenharmony_ci pDrvRaidMap->ldTgtIdToLd[j] = 21362306a36Sopenharmony_ci le16_to_cpu(fw_map_dyn->ld_tgt_id_to_ld[j]); 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci break; 21662306a36Sopenharmony_ci case RAID_MAP_DESC_TYPE_ARRAY_INFO: 21762306a36Sopenharmony_ci fw_map_dyn->ar_map_info = 21862306a36Sopenharmony_ci (struct MR_ARRAY_INFO *) 21962306a36Sopenharmony_ci (raid_map_data + le32_to_cpu(desc_table->raid_map_desc_offset)); 22062306a36Sopenharmony_ci memcpy(pDrvRaidMap->arMapInfo, 22162306a36Sopenharmony_ci fw_map_dyn->ar_map_info, 22262306a36Sopenharmony_ci sizeof(struct MR_ARRAY_INFO) * 22362306a36Sopenharmony_ci le32_to_cpu(desc_table->raid_map_desc_elements)); 22462306a36Sopenharmony_ci break; 22562306a36Sopenharmony_ci case RAID_MAP_DESC_TYPE_SPAN_INFO: 22662306a36Sopenharmony_ci fw_map_dyn->ld_span_map = 22762306a36Sopenharmony_ci (struct MR_LD_SPAN_MAP *) 22862306a36Sopenharmony_ci (raid_map_data + 22962306a36Sopenharmony_ci le32_to_cpu(desc_table->raid_map_desc_offset)); 23062306a36Sopenharmony_ci memcpy(pDrvRaidMap->ldSpanMap, 23162306a36Sopenharmony_ci fw_map_dyn->ld_span_map, 23262306a36Sopenharmony_ci sizeof(struct MR_LD_SPAN_MAP) * 23362306a36Sopenharmony_ci le32_to_cpu(desc_table->raid_map_desc_elements)); 23462306a36Sopenharmony_ci break; 23562306a36Sopenharmony_ci default: 23662306a36Sopenharmony_ci dev_dbg(&instance->pdev->dev, "wrong number of desctableElements %d\n", 23762306a36Sopenharmony_ci fw_map_dyn->desc_table_num_elements); 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci ++desc_table; 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci } else if (instance->supportmax256vd) { 24362306a36Sopenharmony_ci fw_map_ext = 24462306a36Sopenharmony_ci (struct MR_FW_RAID_MAP_EXT *)fusion->ld_map[(map_id & 1)]; 24562306a36Sopenharmony_ci ld_count = (u16)le16_to_cpu(fw_map_ext->ldCount); 24662306a36Sopenharmony_ci if (ld_count > MAX_LOGICAL_DRIVES_EXT) { 24762306a36Sopenharmony_ci dev_dbg(&instance->pdev->dev, "megaraid_sas: LD count exposed in RAID map in not valid\n"); 24862306a36Sopenharmony_ci return 1; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count); 25262306a36Sopenharmony_ci pDrvRaidMap->fpPdIoTimeoutSec = fw_map_ext->fpPdIoTimeoutSec; 25362306a36Sopenharmony_ci for (i = 0; i < (MAX_LOGICAL_DRIVES_EXT); i++) 25462306a36Sopenharmony_ci pDrvRaidMap->ldTgtIdToLd[i] = 25562306a36Sopenharmony_ci (u16)fw_map_ext->ldTgtIdToLd[i]; 25662306a36Sopenharmony_ci memcpy(pDrvRaidMap->ldSpanMap, fw_map_ext->ldSpanMap, 25762306a36Sopenharmony_ci sizeof(struct MR_LD_SPAN_MAP) * ld_count); 25862306a36Sopenharmony_ci memcpy(pDrvRaidMap->arMapInfo, fw_map_ext->arMapInfo, 25962306a36Sopenharmony_ci sizeof(struct MR_ARRAY_INFO) * MAX_API_ARRAYS_EXT); 26062306a36Sopenharmony_ci memcpy(pDrvRaidMap->devHndlInfo, fw_map_ext->devHndlInfo, 26162306a36Sopenharmony_ci sizeof(struct MR_DEV_HANDLE_INFO) * 26262306a36Sopenharmony_ci MAX_RAIDMAP_PHYSICAL_DEVICES); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* New Raid map will not set totalSize, so keep expected value 26562306a36Sopenharmony_ci * for legacy code in ValidateMapInfo 26662306a36Sopenharmony_ci */ 26762306a36Sopenharmony_ci pDrvRaidMap->totalSize = 26862306a36Sopenharmony_ci cpu_to_le32(sizeof(struct MR_FW_RAID_MAP_EXT)); 26962306a36Sopenharmony_ci } else { 27062306a36Sopenharmony_ci fw_map_old = (struct MR_FW_RAID_MAP_ALL *) 27162306a36Sopenharmony_ci fusion->ld_map[(map_id & 1)]; 27262306a36Sopenharmony_ci pFwRaidMap = &fw_map_old->raidMap; 27362306a36Sopenharmony_ci ld_count = (u16)le32_to_cpu(pFwRaidMap->ldCount); 27462306a36Sopenharmony_ci if (ld_count > MAX_LOGICAL_DRIVES) { 27562306a36Sopenharmony_ci dev_dbg(&instance->pdev->dev, 27662306a36Sopenharmony_ci "LD count exposed in RAID map in not valid\n"); 27762306a36Sopenharmony_ci return 1; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci pDrvRaidMap->totalSize = pFwRaidMap->totalSize; 28162306a36Sopenharmony_ci pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count); 28262306a36Sopenharmony_ci pDrvRaidMap->fpPdIoTimeoutSec = pFwRaidMap->fpPdIoTimeoutSec; 28362306a36Sopenharmony_ci for (i = 0; i < MAX_RAIDMAP_LOGICAL_DRIVES + MAX_RAIDMAP_VIEWS; i++) 28462306a36Sopenharmony_ci pDrvRaidMap->ldTgtIdToLd[i] = 28562306a36Sopenharmony_ci (u8)pFwRaidMap->ldTgtIdToLd[i]; 28662306a36Sopenharmony_ci for (i = 0; i < ld_count; i++) { 28762306a36Sopenharmony_ci pDrvRaidMap->ldSpanMap[i] = pFwRaidMap->ldSpanMap[i]; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci memcpy(pDrvRaidMap->arMapInfo, pFwRaidMap->arMapInfo, 29062306a36Sopenharmony_ci sizeof(struct MR_ARRAY_INFO) * MAX_RAIDMAP_ARRAYS); 29162306a36Sopenharmony_ci memcpy(pDrvRaidMap->devHndlInfo, pFwRaidMap->devHndlInfo, 29262306a36Sopenharmony_ci sizeof(struct MR_DEV_HANDLE_INFO) * 29362306a36Sopenharmony_ci MAX_RAIDMAP_PHYSICAL_DEVICES); 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci return 0; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci/* 30062306a36Sopenharmony_ci * This function will validate Map info data provided by FW 30162306a36Sopenharmony_ci */ 30262306a36Sopenharmony_ciu8 MR_ValidateMapInfo(struct megasas_instance *instance, u64 map_id) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct fusion_context *fusion; 30562306a36Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *drv_map; 30662306a36Sopenharmony_ci struct MR_DRV_RAID_MAP *pDrvRaidMap; 30762306a36Sopenharmony_ci struct LD_LOAD_BALANCE_INFO *lbInfo; 30862306a36Sopenharmony_ci PLD_SPAN_INFO ldSpanInfo; 30962306a36Sopenharmony_ci struct MR_LD_RAID *raid; 31062306a36Sopenharmony_ci u16 num_lds, i; 31162306a36Sopenharmony_ci u16 ld; 31262306a36Sopenharmony_ci u32 expected_size; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (MR_PopulateDrvRaidMap(instance, map_id)) 31562306a36Sopenharmony_ci return 0; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci fusion = instance->ctrl_context; 31862306a36Sopenharmony_ci drv_map = fusion->ld_drv_map[(map_id & 1)]; 31962306a36Sopenharmony_ci pDrvRaidMap = &drv_map->raidMap; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci lbInfo = fusion->load_balance_info; 32262306a36Sopenharmony_ci ldSpanInfo = fusion->log_to_span; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (instance->max_raid_mapsize) 32562306a36Sopenharmony_ci expected_size = sizeof(struct MR_DRV_RAID_MAP_ALL); 32662306a36Sopenharmony_ci else if (instance->supportmax256vd) 32762306a36Sopenharmony_ci expected_size = sizeof(struct MR_FW_RAID_MAP_EXT); 32862306a36Sopenharmony_ci else 32962306a36Sopenharmony_ci expected_size = struct_size_t(struct MR_FW_RAID_MAP, 33062306a36Sopenharmony_ci ldSpanMap, 33162306a36Sopenharmony_ci le16_to_cpu(pDrvRaidMap->ldCount)); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (le32_to_cpu(pDrvRaidMap->totalSize) != expected_size) { 33462306a36Sopenharmony_ci dev_dbg(&instance->pdev->dev, "megasas: map info structure size 0x%x", 33562306a36Sopenharmony_ci le32_to_cpu(pDrvRaidMap->totalSize)); 33662306a36Sopenharmony_ci dev_dbg(&instance->pdev->dev, "is not matching expected size 0x%x\n", 33762306a36Sopenharmony_ci (unsigned int)expected_size); 33862306a36Sopenharmony_ci dev_err(&instance->pdev->dev, "megasas: span map %x, pDrvRaidMap->totalSize : %x\n", 33962306a36Sopenharmony_ci (unsigned int)sizeof(struct MR_LD_SPAN_MAP), 34062306a36Sopenharmony_ci le32_to_cpu(pDrvRaidMap->totalSize)); 34162306a36Sopenharmony_ci return 0; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (instance->UnevenSpanSupport) 34562306a36Sopenharmony_ci mr_update_span_set(drv_map, ldSpanInfo); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (lbInfo) 34862306a36Sopenharmony_ci mr_update_load_balance_params(drv_map, lbInfo); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci num_lds = le16_to_cpu(drv_map->raidMap.ldCount); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci memcpy(instance->ld_ids_prev, 35362306a36Sopenharmony_ci instance->ld_ids_from_raidmap, 35462306a36Sopenharmony_ci sizeof(instance->ld_ids_from_raidmap)); 35562306a36Sopenharmony_ci memset(instance->ld_ids_from_raidmap, 0xff, MEGASAS_MAX_LD_IDS); 35662306a36Sopenharmony_ci /*Convert Raid capability values to CPU arch */ 35762306a36Sopenharmony_ci for (i = 0; (num_lds > 0) && (i < MAX_LOGICAL_DRIVES_EXT); i++) { 35862306a36Sopenharmony_ci ld = MR_TargetIdToLdGet(i, drv_map); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* For non existing VDs, iterate to next VD*/ 36162306a36Sopenharmony_ci if (ld >= MEGASAS_MAX_SUPPORTED_LD_IDS) 36262306a36Sopenharmony_ci continue; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci raid = MR_LdRaidGet(ld, drv_map); 36562306a36Sopenharmony_ci le32_to_cpus((u32 *)&raid->capability); 36662306a36Sopenharmony_ci instance->ld_ids_from_raidmap[i] = i; 36762306a36Sopenharmony_ci num_lds--; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci return 1; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic u32 MR_GetSpanBlock(u32 ld, u64 row, u64 *span_blk, 37462306a36Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *map) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci struct MR_SPAN_BLOCK_INFO *pSpanBlock = MR_LdSpanInfoGet(ld, map); 37762306a36Sopenharmony_ci struct MR_QUAD_ELEMENT *quad; 37862306a36Sopenharmony_ci struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 37962306a36Sopenharmony_ci u32 span, j; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci for (span = 0; span < raid->spanDepth; span++, pSpanBlock++) { 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci for (j = 0; j < le32_to_cpu(pSpanBlock->block_span_info.noElements); j++) { 38462306a36Sopenharmony_ci quad = &pSpanBlock->block_span_info.quad[j]; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (le32_to_cpu(quad->diff) == 0) 38762306a36Sopenharmony_ci return SPAN_INVALID; 38862306a36Sopenharmony_ci if (le64_to_cpu(quad->logStart) <= row && row <= 38962306a36Sopenharmony_ci le64_to_cpu(quad->logEnd) && (mega_mod64(row - le64_to_cpu(quad->logStart), 39062306a36Sopenharmony_ci le32_to_cpu(quad->diff))) == 0) { 39162306a36Sopenharmony_ci if (span_blk != NULL) { 39262306a36Sopenharmony_ci u64 blk; 39362306a36Sopenharmony_ci blk = mega_div64_32((row-le64_to_cpu(quad->logStart)), le32_to_cpu(quad->diff)); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci blk = (blk + le64_to_cpu(quad->offsetInSpan)) << raid->stripeShift; 39662306a36Sopenharmony_ci *span_blk = blk; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci return span; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci return SPAN_INVALID; 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci/* 40662306a36Sopenharmony_ci****************************************************************************** 40762306a36Sopenharmony_ci* 40862306a36Sopenharmony_ci* This routine calculates the Span block for given row using spanset. 40962306a36Sopenharmony_ci* 41062306a36Sopenharmony_ci* Inputs : 41162306a36Sopenharmony_ci* instance - HBA instance 41262306a36Sopenharmony_ci* ld - Logical drive number 41362306a36Sopenharmony_ci* row - Row number 41462306a36Sopenharmony_ci* map - LD map 41562306a36Sopenharmony_ci* 41662306a36Sopenharmony_ci* Outputs : 41762306a36Sopenharmony_ci* 41862306a36Sopenharmony_ci* span - Span number 41962306a36Sopenharmony_ci* block - Absolute Block number in the physical disk 42062306a36Sopenharmony_ci* div_error - Devide error code. 42162306a36Sopenharmony_ci*/ 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic u32 mr_spanset_get_span_block(struct megasas_instance *instance, 42462306a36Sopenharmony_ci u32 ld, u64 row, u64 *span_blk, struct MR_DRV_RAID_MAP_ALL *map) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 42762306a36Sopenharmony_ci struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 42862306a36Sopenharmony_ci LD_SPAN_SET *span_set; 42962306a36Sopenharmony_ci struct MR_QUAD_ELEMENT *quad; 43062306a36Sopenharmony_ci u32 span, info; 43162306a36Sopenharmony_ci PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci for (info = 0; info < MAX_QUAD_DEPTH; info++) { 43462306a36Sopenharmony_ci span_set = &(ldSpanInfo[ld].span_set[info]); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (span_set->span_row_data_width == 0) 43762306a36Sopenharmony_ci break; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (row > span_set->data_row_end) 44062306a36Sopenharmony_ci continue; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci for (span = 0; span < raid->spanDepth; span++) 44362306a36Sopenharmony_ci if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span]. 44462306a36Sopenharmony_ci block_span_info.noElements) >= info+1) { 44562306a36Sopenharmony_ci quad = &map->raidMap.ldSpanMap[ld]. 44662306a36Sopenharmony_ci spanBlock[span]. 44762306a36Sopenharmony_ci block_span_info.quad[info]; 44862306a36Sopenharmony_ci if (le32_to_cpu(quad->diff) == 0) 44962306a36Sopenharmony_ci return SPAN_INVALID; 45062306a36Sopenharmony_ci if (le64_to_cpu(quad->logStart) <= row && 45162306a36Sopenharmony_ci row <= le64_to_cpu(quad->logEnd) && 45262306a36Sopenharmony_ci (mega_mod64(row - le64_to_cpu(quad->logStart), 45362306a36Sopenharmony_ci le32_to_cpu(quad->diff))) == 0) { 45462306a36Sopenharmony_ci if (span_blk != NULL) { 45562306a36Sopenharmony_ci u64 blk; 45662306a36Sopenharmony_ci blk = mega_div64_32 45762306a36Sopenharmony_ci ((row - le64_to_cpu(quad->logStart)), 45862306a36Sopenharmony_ci le32_to_cpu(quad->diff)); 45962306a36Sopenharmony_ci blk = (blk + le64_to_cpu(quad->offsetInSpan)) 46062306a36Sopenharmony_ci << raid->stripeShift; 46162306a36Sopenharmony_ci *span_blk = blk; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci return span; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci return SPAN_INVALID; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci/* 47162306a36Sopenharmony_ci****************************************************************************** 47262306a36Sopenharmony_ci* 47362306a36Sopenharmony_ci* This routine calculates the row for given strip using spanset. 47462306a36Sopenharmony_ci* 47562306a36Sopenharmony_ci* Inputs : 47662306a36Sopenharmony_ci* instance - HBA instance 47762306a36Sopenharmony_ci* ld - Logical drive number 47862306a36Sopenharmony_ci* Strip - Strip 47962306a36Sopenharmony_ci* map - LD map 48062306a36Sopenharmony_ci* 48162306a36Sopenharmony_ci* Outputs : 48262306a36Sopenharmony_ci* 48362306a36Sopenharmony_ci* row - row associated with strip 48462306a36Sopenharmony_ci*/ 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic u64 get_row_from_strip(struct megasas_instance *instance, 48762306a36Sopenharmony_ci u32 ld, u64 strip, struct MR_DRV_RAID_MAP_ALL *map) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 49062306a36Sopenharmony_ci struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 49162306a36Sopenharmony_ci LD_SPAN_SET *span_set; 49262306a36Sopenharmony_ci PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span; 49362306a36Sopenharmony_ci u32 info, strip_offset, span, span_offset; 49462306a36Sopenharmony_ci u64 span_set_Strip, span_set_Row, retval; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci for (info = 0; info < MAX_QUAD_DEPTH; info++) { 49762306a36Sopenharmony_ci span_set = &(ldSpanInfo[ld].span_set[info]); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if (span_set->span_row_data_width == 0) 50062306a36Sopenharmony_ci break; 50162306a36Sopenharmony_ci if (strip > span_set->data_strip_end) 50262306a36Sopenharmony_ci continue; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci span_set_Strip = strip - span_set->data_strip_start; 50562306a36Sopenharmony_ci strip_offset = mega_mod64(span_set_Strip, 50662306a36Sopenharmony_ci span_set->span_row_data_width); 50762306a36Sopenharmony_ci span_set_Row = mega_div64_32(span_set_Strip, 50862306a36Sopenharmony_ci span_set->span_row_data_width) * span_set->diff; 50962306a36Sopenharmony_ci for (span = 0, span_offset = 0; span < raid->spanDepth; span++) 51062306a36Sopenharmony_ci if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span]. 51162306a36Sopenharmony_ci block_span_info.noElements) >= info+1) { 51262306a36Sopenharmony_ci if (strip_offset >= 51362306a36Sopenharmony_ci span_set->strip_offset[span]) 51462306a36Sopenharmony_ci span_offset++; 51562306a36Sopenharmony_ci else 51662306a36Sopenharmony_ci break; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci retval = (span_set->data_row_start + span_set_Row + 52062306a36Sopenharmony_ci (span_offset - 1)); 52162306a36Sopenharmony_ci return retval; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci return -1LLU; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci/* 52862306a36Sopenharmony_ci****************************************************************************** 52962306a36Sopenharmony_ci* 53062306a36Sopenharmony_ci* This routine calculates the Start Strip for given row using spanset. 53162306a36Sopenharmony_ci* 53262306a36Sopenharmony_ci* Inputs : 53362306a36Sopenharmony_ci* instance - HBA instance 53462306a36Sopenharmony_ci* ld - Logical drive number 53562306a36Sopenharmony_ci* row - Row number 53662306a36Sopenharmony_ci* map - LD map 53762306a36Sopenharmony_ci* 53862306a36Sopenharmony_ci* Outputs : 53962306a36Sopenharmony_ci* 54062306a36Sopenharmony_ci* Strip - Start strip associated with row 54162306a36Sopenharmony_ci*/ 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_cistatic u64 get_strip_from_row(struct megasas_instance *instance, 54462306a36Sopenharmony_ci u32 ld, u64 row, struct MR_DRV_RAID_MAP_ALL *map) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 54762306a36Sopenharmony_ci struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 54862306a36Sopenharmony_ci LD_SPAN_SET *span_set; 54962306a36Sopenharmony_ci struct MR_QUAD_ELEMENT *quad; 55062306a36Sopenharmony_ci PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span; 55162306a36Sopenharmony_ci u32 span, info; 55262306a36Sopenharmony_ci u64 strip; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci for (info = 0; info < MAX_QUAD_DEPTH; info++) { 55562306a36Sopenharmony_ci span_set = &(ldSpanInfo[ld].span_set[info]); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (span_set->span_row_data_width == 0) 55862306a36Sopenharmony_ci break; 55962306a36Sopenharmony_ci if (row > span_set->data_row_end) 56062306a36Sopenharmony_ci continue; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci for (span = 0; span < raid->spanDepth; span++) 56362306a36Sopenharmony_ci if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span]. 56462306a36Sopenharmony_ci block_span_info.noElements) >= info+1) { 56562306a36Sopenharmony_ci quad = &map->raidMap.ldSpanMap[ld]. 56662306a36Sopenharmony_ci spanBlock[span].block_span_info.quad[info]; 56762306a36Sopenharmony_ci if (le64_to_cpu(quad->logStart) <= row && 56862306a36Sopenharmony_ci row <= le64_to_cpu(quad->logEnd) && 56962306a36Sopenharmony_ci mega_mod64((row - le64_to_cpu(quad->logStart)), 57062306a36Sopenharmony_ci le32_to_cpu(quad->diff)) == 0) { 57162306a36Sopenharmony_ci strip = mega_div64_32 57262306a36Sopenharmony_ci (((row - span_set->data_row_start) 57362306a36Sopenharmony_ci - le64_to_cpu(quad->logStart)), 57462306a36Sopenharmony_ci le32_to_cpu(quad->diff)); 57562306a36Sopenharmony_ci strip *= span_set->span_row_data_width; 57662306a36Sopenharmony_ci strip += span_set->data_strip_start; 57762306a36Sopenharmony_ci strip += span_set->strip_offset[span]; 57862306a36Sopenharmony_ci return strip; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci dev_err(&instance->pdev->dev, "get_strip_from_row" 58362306a36Sopenharmony_ci "returns invalid strip for ld=%x, row=%lx\n", 58462306a36Sopenharmony_ci ld, (long unsigned int)row); 58562306a36Sopenharmony_ci return -1; 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci/* 58962306a36Sopenharmony_ci****************************************************************************** 59062306a36Sopenharmony_ci* 59162306a36Sopenharmony_ci* This routine calculates the Physical Arm for given strip using spanset. 59262306a36Sopenharmony_ci* 59362306a36Sopenharmony_ci* Inputs : 59462306a36Sopenharmony_ci* instance - HBA instance 59562306a36Sopenharmony_ci* ld - Logical drive number 59662306a36Sopenharmony_ci* strip - Strip 59762306a36Sopenharmony_ci* map - LD map 59862306a36Sopenharmony_ci* 59962306a36Sopenharmony_ci* Outputs : 60062306a36Sopenharmony_ci* 60162306a36Sopenharmony_ci* Phys Arm - Phys Arm associated with strip 60262306a36Sopenharmony_ci*/ 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic u32 get_arm_from_strip(struct megasas_instance *instance, 60562306a36Sopenharmony_ci u32 ld, u64 strip, struct MR_DRV_RAID_MAP_ALL *map) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 60862306a36Sopenharmony_ci struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 60962306a36Sopenharmony_ci LD_SPAN_SET *span_set; 61062306a36Sopenharmony_ci PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span; 61162306a36Sopenharmony_ci u32 info, strip_offset, span, span_offset, retval; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci for (info = 0 ; info < MAX_QUAD_DEPTH; info++) { 61462306a36Sopenharmony_ci span_set = &(ldSpanInfo[ld].span_set[info]); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if (span_set->span_row_data_width == 0) 61762306a36Sopenharmony_ci break; 61862306a36Sopenharmony_ci if (strip > span_set->data_strip_end) 61962306a36Sopenharmony_ci continue; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci strip_offset = (uint)mega_mod64 62262306a36Sopenharmony_ci ((strip - span_set->data_strip_start), 62362306a36Sopenharmony_ci span_set->span_row_data_width); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci for (span = 0, span_offset = 0; span < raid->spanDepth; span++) 62662306a36Sopenharmony_ci if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span]. 62762306a36Sopenharmony_ci block_span_info.noElements) >= info+1) { 62862306a36Sopenharmony_ci if (strip_offset >= 62962306a36Sopenharmony_ci span_set->strip_offset[span]) 63062306a36Sopenharmony_ci span_offset = 63162306a36Sopenharmony_ci span_set->strip_offset[span]; 63262306a36Sopenharmony_ci else 63362306a36Sopenharmony_ci break; 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci retval = (strip_offset - span_offset); 63762306a36Sopenharmony_ci return retval; 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci dev_err(&instance->pdev->dev, "get_arm_from_strip" 64162306a36Sopenharmony_ci "returns invalid arm for ld=%x strip=%lx\n", 64262306a36Sopenharmony_ci ld, (long unsigned int)strip); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci return -1; 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci/* This Function will return Phys arm */ 64862306a36Sopenharmony_cistatic u8 get_arm(struct megasas_instance *instance, u32 ld, u8 span, u64 stripe, 64962306a36Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *map) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 65262306a36Sopenharmony_ci /* Need to check correct default value */ 65362306a36Sopenharmony_ci u32 arm = 0; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci switch (raid->level) { 65662306a36Sopenharmony_ci case 0: 65762306a36Sopenharmony_ci case 5: 65862306a36Sopenharmony_ci case 6: 65962306a36Sopenharmony_ci arm = mega_mod64(stripe, SPAN_ROW_SIZE(map, ld, span)); 66062306a36Sopenharmony_ci break; 66162306a36Sopenharmony_ci case 1: 66262306a36Sopenharmony_ci /* start with logical arm */ 66362306a36Sopenharmony_ci arm = get_arm_from_strip(instance, ld, stripe, map); 66462306a36Sopenharmony_ci if (arm != -1U) 66562306a36Sopenharmony_ci arm *= 2; 66662306a36Sopenharmony_ci break; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci return arm; 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci/* 67462306a36Sopenharmony_ci****************************************************************************** 67562306a36Sopenharmony_ci* 67662306a36Sopenharmony_ci* This routine calculates the arm, span and block for the specified stripe and 67762306a36Sopenharmony_ci* reference in stripe using spanset 67862306a36Sopenharmony_ci* 67962306a36Sopenharmony_ci* Inputs : 68062306a36Sopenharmony_ci* 68162306a36Sopenharmony_ci* ld - Logical drive number 68262306a36Sopenharmony_ci* stripRow - Stripe number 68362306a36Sopenharmony_ci* stripRef - Reference in stripe 68462306a36Sopenharmony_ci* 68562306a36Sopenharmony_ci* Outputs : 68662306a36Sopenharmony_ci* 68762306a36Sopenharmony_ci* span - Span number 68862306a36Sopenharmony_ci* block - Absolute Block number in the physical disk 68962306a36Sopenharmony_ci*/ 69062306a36Sopenharmony_cistatic u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld, 69162306a36Sopenharmony_ci u64 stripRow, u16 stripRef, struct IO_REQUEST_INFO *io_info, 69262306a36Sopenharmony_ci struct RAID_CONTEXT *pRAID_Context, 69362306a36Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *map) 69462306a36Sopenharmony_ci{ 69562306a36Sopenharmony_ci struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 69662306a36Sopenharmony_ci u32 pd, arRef, r1_alt_pd; 69762306a36Sopenharmony_ci u8 physArm, span; 69862306a36Sopenharmony_ci u64 row; 69962306a36Sopenharmony_ci u8 retval = true; 70062306a36Sopenharmony_ci u64 *pdBlock = &io_info->pdBlock; 70162306a36Sopenharmony_ci __le16 *pDevHandle = &io_info->devHandle; 70262306a36Sopenharmony_ci u8 *pPdInterface = &io_info->pd_interface; 70362306a36Sopenharmony_ci u32 logArm, rowMod, armQ, arm; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci *pDevHandle = cpu_to_le16(MR_DEVHANDLE_INVALID); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci /*Get row and span from io_info for Uneven Span IO.*/ 70862306a36Sopenharmony_ci row = io_info->start_row; 70962306a36Sopenharmony_ci span = io_info->start_span; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci if (raid->level == 6) { 71362306a36Sopenharmony_ci logArm = get_arm_from_strip(instance, ld, stripRow, map); 71462306a36Sopenharmony_ci if (logArm == -1U) 71562306a36Sopenharmony_ci return false; 71662306a36Sopenharmony_ci rowMod = mega_mod64(row, SPAN_ROW_SIZE(map, ld, span)); 71762306a36Sopenharmony_ci armQ = SPAN_ROW_SIZE(map, ld, span) - 1 - rowMod; 71862306a36Sopenharmony_ci arm = armQ + 1 + logArm; 71962306a36Sopenharmony_ci if (arm >= SPAN_ROW_SIZE(map, ld, span)) 72062306a36Sopenharmony_ci arm -= SPAN_ROW_SIZE(map, ld, span); 72162306a36Sopenharmony_ci physArm = (u8)arm; 72262306a36Sopenharmony_ci } else 72362306a36Sopenharmony_ci /* Calculate the arm */ 72462306a36Sopenharmony_ci physArm = get_arm(instance, ld, span, stripRow, map); 72562306a36Sopenharmony_ci if (physArm == 0xFF) 72662306a36Sopenharmony_ci return false; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci arRef = MR_LdSpanArrayGet(ld, span, map); 72962306a36Sopenharmony_ci pd = MR_ArPdGet(arRef, physArm, map); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci if (pd != MR_PD_INVALID) { 73262306a36Sopenharmony_ci *pDevHandle = MR_PdDevHandleGet(pd, map); 73362306a36Sopenharmony_ci *pPdInterface = MR_PdInterfaceTypeGet(pd, map); 73462306a36Sopenharmony_ci /* get second pd also for raid 1/10 fast path writes*/ 73562306a36Sopenharmony_ci if ((instance->adapter_type >= VENTURA_SERIES) && 73662306a36Sopenharmony_ci (raid->level == 1) && 73762306a36Sopenharmony_ci !io_info->isRead) { 73862306a36Sopenharmony_ci r1_alt_pd = MR_ArPdGet(arRef, physArm + 1, map); 73962306a36Sopenharmony_ci if (r1_alt_pd != MR_PD_INVALID) 74062306a36Sopenharmony_ci io_info->r1_alt_dev_handle = 74162306a36Sopenharmony_ci MR_PdDevHandleGet(r1_alt_pd, map); 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci } else { 74462306a36Sopenharmony_ci if ((raid->level >= 5) && 74562306a36Sopenharmony_ci ((instance->adapter_type == THUNDERBOLT_SERIES) || 74662306a36Sopenharmony_ci ((instance->adapter_type == INVADER_SERIES) && 74762306a36Sopenharmony_ci (raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))) 74862306a36Sopenharmony_ci pRAID_Context->reg_lock_flags = REGION_TYPE_EXCLUSIVE; 74962306a36Sopenharmony_ci else if (raid->level == 1) { 75062306a36Sopenharmony_ci physArm = physArm + 1; 75162306a36Sopenharmony_ci pd = MR_ArPdGet(arRef, physArm, map); 75262306a36Sopenharmony_ci if (pd != MR_PD_INVALID) { 75362306a36Sopenharmony_ci *pDevHandle = MR_PdDevHandleGet(pd, map); 75462306a36Sopenharmony_ci *pPdInterface = MR_PdInterfaceTypeGet(pd, map); 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci } 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci *pdBlock += stripRef + le64_to_cpu(MR_LdSpanPtrGet(ld, span, map)->startBlk); 76062306a36Sopenharmony_ci if (instance->adapter_type >= VENTURA_SERIES) { 76162306a36Sopenharmony_ci ((struct RAID_CONTEXT_G35 *)pRAID_Context)->span_arm = 76262306a36Sopenharmony_ci (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; 76362306a36Sopenharmony_ci io_info->span_arm = 76462306a36Sopenharmony_ci (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; 76562306a36Sopenharmony_ci } else { 76662306a36Sopenharmony_ci pRAID_Context->span_arm = 76762306a36Sopenharmony_ci (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; 76862306a36Sopenharmony_ci io_info->span_arm = pRAID_Context->span_arm; 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci io_info->pd_after_lb = pd; 77162306a36Sopenharmony_ci return retval; 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci/* 77562306a36Sopenharmony_ci****************************************************************************** 77662306a36Sopenharmony_ci* 77762306a36Sopenharmony_ci* This routine calculates the arm, span and block for the specified stripe and 77862306a36Sopenharmony_ci* reference in stripe. 77962306a36Sopenharmony_ci* 78062306a36Sopenharmony_ci* Inputs : 78162306a36Sopenharmony_ci* 78262306a36Sopenharmony_ci* ld - Logical drive number 78362306a36Sopenharmony_ci* stripRow - Stripe number 78462306a36Sopenharmony_ci* stripRef - Reference in stripe 78562306a36Sopenharmony_ci* 78662306a36Sopenharmony_ci* Outputs : 78762306a36Sopenharmony_ci* 78862306a36Sopenharmony_ci* span - Span number 78962306a36Sopenharmony_ci* block - Absolute Block number in the physical disk 79062306a36Sopenharmony_ci*/ 79162306a36Sopenharmony_cistatic u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow, 79262306a36Sopenharmony_ci u16 stripRef, struct IO_REQUEST_INFO *io_info, 79362306a36Sopenharmony_ci struct RAID_CONTEXT *pRAID_Context, 79462306a36Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *map) 79562306a36Sopenharmony_ci{ 79662306a36Sopenharmony_ci struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 79762306a36Sopenharmony_ci u32 pd, arRef, r1_alt_pd; 79862306a36Sopenharmony_ci u8 physArm, span; 79962306a36Sopenharmony_ci u64 row; 80062306a36Sopenharmony_ci u8 retval = true; 80162306a36Sopenharmony_ci u64 *pdBlock = &io_info->pdBlock; 80262306a36Sopenharmony_ci __le16 *pDevHandle = &io_info->devHandle; 80362306a36Sopenharmony_ci u8 *pPdInterface = &io_info->pd_interface; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci *pDevHandle = cpu_to_le16(MR_DEVHANDLE_INVALID); 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci row = mega_div64_32(stripRow, raid->rowDataSize); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci if (raid->level == 6) { 81062306a36Sopenharmony_ci /* logical arm within row */ 81162306a36Sopenharmony_ci u32 logArm = mega_mod64(stripRow, raid->rowDataSize); 81262306a36Sopenharmony_ci u32 rowMod, armQ, arm; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci if (raid->rowSize == 0) 81562306a36Sopenharmony_ci return false; 81662306a36Sopenharmony_ci /* get logical row mod */ 81762306a36Sopenharmony_ci rowMod = mega_mod64(row, raid->rowSize); 81862306a36Sopenharmony_ci armQ = raid->rowSize-1-rowMod; /* index of Q drive */ 81962306a36Sopenharmony_ci arm = armQ+1+logArm; /* data always logically follows Q */ 82062306a36Sopenharmony_ci if (arm >= raid->rowSize) /* handle wrap condition */ 82162306a36Sopenharmony_ci arm -= raid->rowSize; 82262306a36Sopenharmony_ci physArm = (u8)arm; 82362306a36Sopenharmony_ci } else { 82462306a36Sopenharmony_ci if (raid->modFactor == 0) 82562306a36Sopenharmony_ci return false; 82662306a36Sopenharmony_ci physArm = MR_LdDataArmGet(ld, mega_mod64(stripRow, 82762306a36Sopenharmony_ci raid->modFactor), 82862306a36Sopenharmony_ci map); 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci if (raid->spanDepth == 1) { 83262306a36Sopenharmony_ci span = 0; 83362306a36Sopenharmony_ci *pdBlock = row << raid->stripeShift; 83462306a36Sopenharmony_ci } else { 83562306a36Sopenharmony_ci span = (u8)MR_GetSpanBlock(ld, row, pdBlock, map); 83662306a36Sopenharmony_ci if (span == SPAN_INVALID) 83762306a36Sopenharmony_ci return false; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci /* Get the array on which this span is present */ 84162306a36Sopenharmony_ci arRef = MR_LdSpanArrayGet(ld, span, map); 84262306a36Sopenharmony_ci pd = MR_ArPdGet(arRef, physArm, map); /* Get the pd */ 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci if (pd != MR_PD_INVALID) { 84562306a36Sopenharmony_ci /* Get dev handle from Pd. */ 84662306a36Sopenharmony_ci *pDevHandle = MR_PdDevHandleGet(pd, map); 84762306a36Sopenharmony_ci *pPdInterface = MR_PdInterfaceTypeGet(pd, map); 84862306a36Sopenharmony_ci /* get second pd also for raid 1/10 fast path writes*/ 84962306a36Sopenharmony_ci if ((instance->adapter_type >= VENTURA_SERIES) && 85062306a36Sopenharmony_ci (raid->level == 1) && 85162306a36Sopenharmony_ci !io_info->isRead) { 85262306a36Sopenharmony_ci r1_alt_pd = MR_ArPdGet(arRef, physArm + 1, map); 85362306a36Sopenharmony_ci if (r1_alt_pd != MR_PD_INVALID) 85462306a36Sopenharmony_ci io_info->r1_alt_dev_handle = 85562306a36Sopenharmony_ci MR_PdDevHandleGet(r1_alt_pd, map); 85662306a36Sopenharmony_ci } 85762306a36Sopenharmony_ci } else { 85862306a36Sopenharmony_ci if ((raid->level >= 5) && 85962306a36Sopenharmony_ci ((instance->adapter_type == THUNDERBOLT_SERIES) || 86062306a36Sopenharmony_ci ((instance->adapter_type == INVADER_SERIES) && 86162306a36Sopenharmony_ci (raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))) 86262306a36Sopenharmony_ci pRAID_Context->reg_lock_flags = REGION_TYPE_EXCLUSIVE; 86362306a36Sopenharmony_ci else if (raid->level == 1) { 86462306a36Sopenharmony_ci /* Get alternate Pd. */ 86562306a36Sopenharmony_ci physArm = physArm + 1; 86662306a36Sopenharmony_ci pd = MR_ArPdGet(arRef, physArm, map); 86762306a36Sopenharmony_ci if (pd != MR_PD_INVALID) { 86862306a36Sopenharmony_ci /* Get dev handle from Pd */ 86962306a36Sopenharmony_ci *pDevHandle = MR_PdDevHandleGet(pd, map); 87062306a36Sopenharmony_ci *pPdInterface = MR_PdInterfaceTypeGet(pd, map); 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci *pdBlock += stripRef + le64_to_cpu(MR_LdSpanPtrGet(ld, span, map)->startBlk); 87662306a36Sopenharmony_ci if (instance->adapter_type >= VENTURA_SERIES) { 87762306a36Sopenharmony_ci ((struct RAID_CONTEXT_G35 *)pRAID_Context)->span_arm = 87862306a36Sopenharmony_ci (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; 87962306a36Sopenharmony_ci io_info->span_arm = 88062306a36Sopenharmony_ci (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; 88162306a36Sopenharmony_ci } else { 88262306a36Sopenharmony_ci pRAID_Context->span_arm = 88362306a36Sopenharmony_ci (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; 88462306a36Sopenharmony_ci io_info->span_arm = pRAID_Context->span_arm; 88562306a36Sopenharmony_ci } 88662306a36Sopenharmony_ci io_info->pd_after_lb = pd; 88762306a36Sopenharmony_ci return retval; 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci/* 89162306a36Sopenharmony_ci * mr_get_phy_params_r56_rmw - Calculate parameters for R56 CTIO write operation 89262306a36Sopenharmony_ci * @instance: Adapter soft state 89362306a36Sopenharmony_ci * @ld: LD index 89462306a36Sopenharmony_ci * @stripNo: Strip Number 89562306a36Sopenharmony_ci * @io_info: IO info structure pointer 89662306a36Sopenharmony_ci * pRAID_Context: RAID context pointer 89762306a36Sopenharmony_ci * map: RAID map pointer 89862306a36Sopenharmony_ci * 89962306a36Sopenharmony_ci * This routine calculates the logical arm, data Arm, row number and parity arm 90062306a36Sopenharmony_ci * for R56 CTIO write operation. 90162306a36Sopenharmony_ci */ 90262306a36Sopenharmony_cistatic void mr_get_phy_params_r56_rmw(struct megasas_instance *instance, 90362306a36Sopenharmony_ci u32 ld, u64 stripNo, 90462306a36Sopenharmony_ci struct IO_REQUEST_INFO *io_info, 90562306a36Sopenharmony_ci struct RAID_CONTEXT_G35 *pRAID_Context, 90662306a36Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *map) 90762306a36Sopenharmony_ci{ 90862306a36Sopenharmony_ci struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 90962306a36Sopenharmony_ci u8 span, dataArms, arms, dataArm, logArm; 91062306a36Sopenharmony_ci s8 rightmostParityArm, PParityArm; 91162306a36Sopenharmony_ci u64 rowNum; 91262306a36Sopenharmony_ci u64 *pdBlock = &io_info->pdBlock; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci dataArms = raid->rowDataSize; 91562306a36Sopenharmony_ci arms = raid->rowSize; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci rowNum = mega_div64_32(stripNo, dataArms); 91862306a36Sopenharmony_ci /* parity disk arm, first arm is 0 */ 91962306a36Sopenharmony_ci rightmostParityArm = (arms - 1) - mega_mod64(rowNum, arms); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci /* logical arm within row */ 92262306a36Sopenharmony_ci logArm = mega_mod64(stripNo, dataArms); 92362306a36Sopenharmony_ci /* physical arm for data */ 92462306a36Sopenharmony_ci dataArm = mega_mod64((rightmostParityArm + 1 + logArm), arms); 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci if (raid->spanDepth == 1) { 92762306a36Sopenharmony_ci span = 0; 92862306a36Sopenharmony_ci } else { 92962306a36Sopenharmony_ci span = (u8)MR_GetSpanBlock(ld, rowNum, pdBlock, map); 93062306a36Sopenharmony_ci if (span == SPAN_INVALID) 93162306a36Sopenharmony_ci return; 93262306a36Sopenharmony_ci } 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci if (raid->level == 6) { 93562306a36Sopenharmony_ci /* P Parity arm, note this can go negative adjust if negative */ 93662306a36Sopenharmony_ci PParityArm = (arms - 2) - mega_mod64(rowNum, arms); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci if (PParityArm < 0) 93962306a36Sopenharmony_ci PParityArm += arms; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci /* rightmostParityArm is P-Parity for RAID 5 and Q-Parity for RAID */ 94262306a36Sopenharmony_ci pRAID_Context->flow_specific.r56_arm_map = rightmostParityArm; 94362306a36Sopenharmony_ci pRAID_Context->flow_specific.r56_arm_map |= 94462306a36Sopenharmony_ci (u16)(PParityArm << RAID_CTX_R56_P_ARM_SHIFT); 94562306a36Sopenharmony_ci } else { 94662306a36Sopenharmony_ci pRAID_Context->flow_specific.r56_arm_map |= 94762306a36Sopenharmony_ci (u16)(rightmostParityArm << RAID_CTX_R56_P_ARM_SHIFT); 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci pRAID_Context->reg_lock_row_lba = cpu_to_le64(rowNum); 95162306a36Sopenharmony_ci pRAID_Context->flow_specific.r56_arm_map |= 95262306a36Sopenharmony_ci (u16)(logArm << RAID_CTX_R56_LOG_ARM_SHIFT); 95362306a36Sopenharmony_ci cpu_to_le16s(&pRAID_Context->flow_specific.r56_arm_map); 95462306a36Sopenharmony_ci pRAID_Context->span_arm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | dataArm; 95562306a36Sopenharmony_ci pRAID_Context->raid_flags = (MR_RAID_FLAGS_IO_SUB_TYPE_R56_DIV_OFFLOAD << 95662306a36Sopenharmony_ci MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci return; 95962306a36Sopenharmony_ci} 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci/* 96262306a36Sopenharmony_ci****************************************************************************** 96362306a36Sopenharmony_ci* 96462306a36Sopenharmony_ci* MR_BuildRaidContext function 96562306a36Sopenharmony_ci* 96662306a36Sopenharmony_ci* This function will initiate command processing. The start/end row and strip 96762306a36Sopenharmony_ci* information is calculated then the lock is acquired. 96862306a36Sopenharmony_ci* This function will return 0 if region lock was acquired OR return num strips 96962306a36Sopenharmony_ci*/ 97062306a36Sopenharmony_ciu8 97162306a36Sopenharmony_ciMR_BuildRaidContext(struct megasas_instance *instance, 97262306a36Sopenharmony_ci struct IO_REQUEST_INFO *io_info, 97362306a36Sopenharmony_ci struct RAID_CONTEXT *pRAID_Context, 97462306a36Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *map, u8 **raidLUN) 97562306a36Sopenharmony_ci{ 97662306a36Sopenharmony_ci struct fusion_context *fusion; 97762306a36Sopenharmony_ci struct MR_LD_RAID *raid; 97862306a36Sopenharmony_ci u32 stripSize, stripe_mask; 97962306a36Sopenharmony_ci u64 endLba, endStrip, endRow, start_row, start_strip; 98062306a36Sopenharmony_ci u64 regStart; 98162306a36Sopenharmony_ci u32 regSize; 98262306a36Sopenharmony_ci u8 num_strips, numRows; 98362306a36Sopenharmony_ci u16 ref_in_start_stripe, ref_in_end_stripe; 98462306a36Sopenharmony_ci u64 ldStartBlock; 98562306a36Sopenharmony_ci u32 numBlocks, ldTgtId; 98662306a36Sopenharmony_ci u8 isRead; 98762306a36Sopenharmony_ci u8 retval = 0; 98862306a36Sopenharmony_ci u8 startlba_span = SPAN_INVALID; 98962306a36Sopenharmony_ci u64 *pdBlock = &io_info->pdBlock; 99062306a36Sopenharmony_ci u16 ld; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci ldStartBlock = io_info->ldStartBlock; 99362306a36Sopenharmony_ci numBlocks = io_info->numBlocks; 99462306a36Sopenharmony_ci ldTgtId = io_info->ldTgtId; 99562306a36Sopenharmony_ci isRead = io_info->isRead; 99662306a36Sopenharmony_ci io_info->IoforUnevenSpan = 0; 99762306a36Sopenharmony_ci io_info->start_span = SPAN_INVALID; 99862306a36Sopenharmony_ci fusion = instance->ctrl_context; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci ld = MR_TargetIdToLdGet(ldTgtId, map); 100162306a36Sopenharmony_ci raid = MR_LdRaidGet(ld, map); 100262306a36Sopenharmony_ci /*check read ahead bit*/ 100362306a36Sopenharmony_ci io_info->ra_capable = raid->capability.ra_capable; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci /* 100662306a36Sopenharmony_ci * if rowDataSize @RAID map and spanRowDataSize @SPAN INFO are zero 100762306a36Sopenharmony_ci * return FALSE 100862306a36Sopenharmony_ci */ 100962306a36Sopenharmony_ci if (raid->rowDataSize == 0) { 101062306a36Sopenharmony_ci if (MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize == 0) 101162306a36Sopenharmony_ci return false; 101262306a36Sopenharmony_ci else if (instance->UnevenSpanSupport) { 101362306a36Sopenharmony_ci io_info->IoforUnevenSpan = 1; 101462306a36Sopenharmony_ci } else { 101562306a36Sopenharmony_ci dev_info(&instance->pdev->dev, 101662306a36Sopenharmony_ci "raid->rowDataSize is 0, but has SPAN[0]" 101762306a36Sopenharmony_ci "rowDataSize = 0x%0x," 101862306a36Sopenharmony_ci "but there is _NO_ UnevenSpanSupport\n", 101962306a36Sopenharmony_ci MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize); 102062306a36Sopenharmony_ci return false; 102162306a36Sopenharmony_ci } 102262306a36Sopenharmony_ci } 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci stripSize = 1 << raid->stripeShift; 102562306a36Sopenharmony_ci stripe_mask = stripSize-1; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci io_info->data_arms = raid->rowDataSize; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci /* 103062306a36Sopenharmony_ci * calculate starting row and stripe, and number of strips and rows 103162306a36Sopenharmony_ci */ 103262306a36Sopenharmony_ci start_strip = ldStartBlock >> raid->stripeShift; 103362306a36Sopenharmony_ci ref_in_start_stripe = (u16)(ldStartBlock & stripe_mask); 103462306a36Sopenharmony_ci endLba = ldStartBlock + numBlocks - 1; 103562306a36Sopenharmony_ci ref_in_end_stripe = (u16)(endLba & stripe_mask); 103662306a36Sopenharmony_ci endStrip = endLba >> raid->stripeShift; 103762306a36Sopenharmony_ci num_strips = (u8)(endStrip - start_strip + 1); /* End strip */ 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci if (io_info->IoforUnevenSpan) { 104062306a36Sopenharmony_ci start_row = get_row_from_strip(instance, ld, start_strip, map); 104162306a36Sopenharmony_ci endRow = get_row_from_strip(instance, ld, endStrip, map); 104262306a36Sopenharmony_ci if (start_row == -1ULL || endRow == -1ULL) { 104362306a36Sopenharmony_ci dev_info(&instance->pdev->dev, "return from %s %d." 104462306a36Sopenharmony_ci "Send IO w/o region lock.\n", 104562306a36Sopenharmony_ci __func__, __LINE__); 104662306a36Sopenharmony_ci return false; 104762306a36Sopenharmony_ci } 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci if (raid->spanDepth == 1) { 105062306a36Sopenharmony_ci startlba_span = 0; 105162306a36Sopenharmony_ci *pdBlock = start_row << raid->stripeShift; 105262306a36Sopenharmony_ci } else 105362306a36Sopenharmony_ci startlba_span = (u8)mr_spanset_get_span_block(instance, 105462306a36Sopenharmony_ci ld, start_row, pdBlock, map); 105562306a36Sopenharmony_ci if (startlba_span == SPAN_INVALID) { 105662306a36Sopenharmony_ci dev_info(&instance->pdev->dev, "return from %s %d" 105762306a36Sopenharmony_ci "for row 0x%llx,start strip %llx" 105862306a36Sopenharmony_ci "endSrip %llx\n", __func__, __LINE__, 105962306a36Sopenharmony_ci (unsigned long long)start_row, 106062306a36Sopenharmony_ci (unsigned long long)start_strip, 106162306a36Sopenharmony_ci (unsigned long long)endStrip); 106262306a36Sopenharmony_ci return false; 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci io_info->start_span = startlba_span; 106562306a36Sopenharmony_ci io_info->start_row = start_row; 106662306a36Sopenharmony_ci } else { 106762306a36Sopenharmony_ci start_row = mega_div64_32(start_strip, raid->rowDataSize); 106862306a36Sopenharmony_ci endRow = mega_div64_32(endStrip, raid->rowDataSize); 106962306a36Sopenharmony_ci } 107062306a36Sopenharmony_ci numRows = (u8)(endRow - start_row + 1); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci /* 107362306a36Sopenharmony_ci * calculate region info. 107462306a36Sopenharmony_ci */ 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci /* assume region is at the start of the first row */ 107762306a36Sopenharmony_ci regStart = start_row << raid->stripeShift; 107862306a36Sopenharmony_ci /* assume this IO needs the full row - we'll adjust if not true */ 107962306a36Sopenharmony_ci regSize = stripSize; 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci io_info->do_fp_rlbypass = raid->capability.fpBypassRegionLock; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci /* Check if we can send this I/O via FastPath */ 108462306a36Sopenharmony_ci if (raid->capability.fpCapable) { 108562306a36Sopenharmony_ci if (isRead) 108662306a36Sopenharmony_ci io_info->fpOkForIo = (raid->capability.fpReadCapable && 108762306a36Sopenharmony_ci ((num_strips == 1) || 108862306a36Sopenharmony_ci raid->capability. 108962306a36Sopenharmony_ci fpReadAcrossStripe)); 109062306a36Sopenharmony_ci else 109162306a36Sopenharmony_ci io_info->fpOkForIo = (raid->capability.fpWriteCapable && 109262306a36Sopenharmony_ci ((num_strips == 1) || 109362306a36Sopenharmony_ci raid->capability. 109462306a36Sopenharmony_ci fpWriteAcrossStripe)); 109562306a36Sopenharmony_ci } else 109662306a36Sopenharmony_ci io_info->fpOkForIo = false; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci if (numRows == 1) { 109962306a36Sopenharmony_ci /* single-strip IOs can always lock only the data needed */ 110062306a36Sopenharmony_ci if (num_strips == 1) { 110162306a36Sopenharmony_ci regStart += ref_in_start_stripe; 110262306a36Sopenharmony_ci regSize = numBlocks; 110362306a36Sopenharmony_ci } 110462306a36Sopenharmony_ci /* multi-strip IOs always need to full stripe locked */ 110562306a36Sopenharmony_ci } else if (io_info->IoforUnevenSpan == 0) { 110662306a36Sopenharmony_ci /* 110762306a36Sopenharmony_ci * For Even span region lock optimization. 110862306a36Sopenharmony_ci * If the start strip is the last in the start row 110962306a36Sopenharmony_ci */ 111062306a36Sopenharmony_ci if (start_strip == (start_row + 1) * raid->rowDataSize - 1) { 111162306a36Sopenharmony_ci regStart += ref_in_start_stripe; 111262306a36Sopenharmony_ci /* initialize count to sectors from startref to end 111362306a36Sopenharmony_ci of strip */ 111462306a36Sopenharmony_ci regSize = stripSize - ref_in_start_stripe; 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci /* add complete rows in the middle of the transfer */ 111862306a36Sopenharmony_ci if (numRows > 2) 111962306a36Sopenharmony_ci regSize += (numRows-2) << raid->stripeShift; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci /* if IO ends within first strip of last row*/ 112262306a36Sopenharmony_ci if (endStrip == endRow*raid->rowDataSize) 112362306a36Sopenharmony_ci regSize += ref_in_end_stripe+1; 112462306a36Sopenharmony_ci else 112562306a36Sopenharmony_ci regSize += stripSize; 112662306a36Sopenharmony_ci } else { 112762306a36Sopenharmony_ci /* 112862306a36Sopenharmony_ci * For Uneven span region lock optimization. 112962306a36Sopenharmony_ci * If the start strip is the last in the start row 113062306a36Sopenharmony_ci */ 113162306a36Sopenharmony_ci if (start_strip == (get_strip_from_row(instance, ld, start_row, map) + 113262306a36Sopenharmony_ci SPAN_ROW_DATA_SIZE(map, ld, startlba_span) - 1)) { 113362306a36Sopenharmony_ci regStart += ref_in_start_stripe; 113462306a36Sopenharmony_ci /* initialize count to sectors from 113562306a36Sopenharmony_ci * startRef to end of strip 113662306a36Sopenharmony_ci */ 113762306a36Sopenharmony_ci regSize = stripSize - ref_in_start_stripe; 113862306a36Sopenharmony_ci } 113962306a36Sopenharmony_ci /* Add complete rows in the middle of the transfer*/ 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci if (numRows > 2) 114262306a36Sopenharmony_ci /* Add complete rows in the middle of the transfer*/ 114362306a36Sopenharmony_ci regSize += (numRows-2) << raid->stripeShift; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci /* if IO ends within first strip of last row */ 114662306a36Sopenharmony_ci if (endStrip == get_strip_from_row(instance, ld, endRow, map)) 114762306a36Sopenharmony_ci regSize += ref_in_end_stripe + 1; 114862306a36Sopenharmony_ci else 114962306a36Sopenharmony_ci regSize += stripSize; 115062306a36Sopenharmony_ci } 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci pRAID_Context->timeout_value = 115362306a36Sopenharmony_ci cpu_to_le16(raid->fpIoTimeoutForLd ? 115462306a36Sopenharmony_ci raid->fpIoTimeoutForLd : 115562306a36Sopenharmony_ci map->raidMap.fpPdIoTimeoutSec); 115662306a36Sopenharmony_ci if (instance->adapter_type == INVADER_SERIES) 115762306a36Sopenharmony_ci pRAID_Context->reg_lock_flags = (isRead) ? 115862306a36Sopenharmony_ci raid->regTypeReqOnRead : raid->regTypeReqOnWrite; 115962306a36Sopenharmony_ci else if (instance->adapter_type == THUNDERBOLT_SERIES) 116062306a36Sopenharmony_ci pRAID_Context->reg_lock_flags = (isRead) ? 116162306a36Sopenharmony_ci REGION_TYPE_SHARED_READ : raid->regTypeReqOnWrite; 116262306a36Sopenharmony_ci pRAID_Context->virtual_disk_tgt_id = raid->targetId; 116362306a36Sopenharmony_ci pRAID_Context->reg_lock_row_lba = cpu_to_le64(regStart); 116462306a36Sopenharmony_ci pRAID_Context->reg_lock_length = cpu_to_le32(regSize); 116562306a36Sopenharmony_ci pRAID_Context->config_seq_num = raid->seqNum; 116662306a36Sopenharmony_ci /* save pointer to raid->LUN array */ 116762306a36Sopenharmony_ci *raidLUN = raid->LUN; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci /* Aero R5/6 Division Offload for WRITE */ 117062306a36Sopenharmony_ci if (fusion->r56_div_offload && (raid->level >= 5) && !isRead) { 117162306a36Sopenharmony_ci mr_get_phy_params_r56_rmw(instance, ld, start_strip, io_info, 117262306a36Sopenharmony_ci (struct RAID_CONTEXT_G35 *)pRAID_Context, 117362306a36Sopenharmony_ci map); 117462306a36Sopenharmony_ci return true; 117562306a36Sopenharmony_ci } 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci /*Get Phy Params only if FP capable, or else leave it to MR firmware 117862306a36Sopenharmony_ci to do the calculation.*/ 117962306a36Sopenharmony_ci if (io_info->fpOkForIo) { 118062306a36Sopenharmony_ci retval = io_info->IoforUnevenSpan ? 118162306a36Sopenharmony_ci mr_spanset_get_phy_params(instance, ld, 118262306a36Sopenharmony_ci start_strip, ref_in_start_stripe, 118362306a36Sopenharmony_ci io_info, pRAID_Context, map) : 118462306a36Sopenharmony_ci MR_GetPhyParams(instance, ld, start_strip, 118562306a36Sopenharmony_ci ref_in_start_stripe, io_info, 118662306a36Sopenharmony_ci pRAID_Context, map); 118762306a36Sopenharmony_ci /* If IO on an invalid Pd, then FP is not possible.*/ 118862306a36Sopenharmony_ci if (io_info->devHandle == MR_DEVHANDLE_INVALID) 118962306a36Sopenharmony_ci io_info->fpOkForIo = false; 119062306a36Sopenharmony_ci return retval; 119162306a36Sopenharmony_ci } else if (isRead) { 119262306a36Sopenharmony_ci uint stripIdx; 119362306a36Sopenharmony_ci for (stripIdx = 0; stripIdx < num_strips; stripIdx++) { 119462306a36Sopenharmony_ci retval = io_info->IoforUnevenSpan ? 119562306a36Sopenharmony_ci mr_spanset_get_phy_params(instance, ld, 119662306a36Sopenharmony_ci start_strip + stripIdx, 119762306a36Sopenharmony_ci ref_in_start_stripe, io_info, 119862306a36Sopenharmony_ci pRAID_Context, map) : 119962306a36Sopenharmony_ci MR_GetPhyParams(instance, ld, 120062306a36Sopenharmony_ci start_strip + stripIdx, ref_in_start_stripe, 120162306a36Sopenharmony_ci io_info, pRAID_Context, map); 120262306a36Sopenharmony_ci if (!retval) 120362306a36Sopenharmony_ci return true; 120462306a36Sopenharmony_ci } 120562306a36Sopenharmony_ci } 120662306a36Sopenharmony_ci return true; 120762306a36Sopenharmony_ci} 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci/* 121062306a36Sopenharmony_ci****************************************************************************** 121162306a36Sopenharmony_ci* 121262306a36Sopenharmony_ci* This routine pepare spanset info from Valid Raid map and store it into 121362306a36Sopenharmony_ci* local copy of ldSpanInfo per instance data structure. 121462306a36Sopenharmony_ci* 121562306a36Sopenharmony_ci* Inputs : 121662306a36Sopenharmony_ci* map - LD map 121762306a36Sopenharmony_ci* ldSpanInfo - ldSpanInfo per HBA instance 121862306a36Sopenharmony_ci* 121962306a36Sopenharmony_ci*/ 122062306a36Sopenharmony_civoid mr_update_span_set(struct MR_DRV_RAID_MAP_ALL *map, 122162306a36Sopenharmony_ci PLD_SPAN_INFO ldSpanInfo) 122262306a36Sopenharmony_ci{ 122362306a36Sopenharmony_ci u8 span, count; 122462306a36Sopenharmony_ci u32 element, span_row_width; 122562306a36Sopenharmony_ci u64 span_row; 122662306a36Sopenharmony_ci struct MR_LD_RAID *raid; 122762306a36Sopenharmony_ci LD_SPAN_SET *span_set, *span_set_prev; 122862306a36Sopenharmony_ci struct MR_QUAD_ELEMENT *quad; 122962306a36Sopenharmony_ci int ldCount; 123062306a36Sopenharmony_ci u16 ld; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES_EXT; ldCount++) { 123462306a36Sopenharmony_ci ld = MR_TargetIdToLdGet(ldCount, map); 123562306a36Sopenharmony_ci if (ld >= (MAX_LOGICAL_DRIVES_EXT - 1)) 123662306a36Sopenharmony_ci continue; 123762306a36Sopenharmony_ci raid = MR_LdRaidGet(ld, map); 123862306a36Sopenharmony_ci for (element = 0; element < MAX_QUAD_DEPTH; element++) { 123962306a36Sopenharmony_ci for (span = 0; span < raid->spanDepth; span++) { 124062306a36Sopenharmony_ci if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span]. 124162306a36Sopenharmony_ci block_span_info.noElements) < 124262306a36Sopenharmony_ci element + 1) 124362306a36Sopenharmony_ci continue; 124462306a36Sopenharmony_ci span_set = &(ldSpanInfo[ld].span_set[element]); 124562306a36Sopenharmony_ci quad = &map->raidMap.ldSpanMap[ld]. 124662306a36Sopenharmony_ci spanBlock[span].block_span_info. 124762306a36Sopenharmony_ci quad[element]; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci span_set->diff = le32_to_cpu(quad->diff); 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci for (count = 0, span_row_width = 0; 125262306a36Sopenharmony_ci count < raid->spanDepth; count++) { 125362306a36Sopenharmony_ci if (le32_to_cpu(map->raidMap.ldSpanMap[ld]. 125462306a36Sopenharmony_ci spanBlock[count]. 125562306a36Sopenharmony_ci block_span_info. 125662306a36Sopenharmony_ci noElements) >= element + 1) { 125762306a36Sopenharmony_ci span_set->strip_offset[count] = 125862306a36Sopenharmony_ci span_row_width; 125962306a36Sopenharmony_ci span_row_width += 126062306a36Sopenharmony_ci MR_LdSpanPtrGet 126162306a36Sopenharmony_ci (ld, count, map)->spanRowDataSize; 126262306a36Sopenharmony_ci } 126362306a36Sopenharmony_ci } 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci span_set->span_row_data_width = span_row_width; 126662306a36Sopenharmony_ci span_row = mega_div64_32(((le64_to_cpu(quad->logEnd) - 126762306a36Sopenharmony_ci le64_to_cpu(quad->logStart)) + le32_to_cpu(quad->diff)), 126862306a36Sopenharmony_ci le32_to_cpu(quad->diff)); 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci if (element == 0) { 127162306a36Sopenharmony_ci span_set->log_start_lba = 0; 127262306a36Sopenharmony_ci span_set->log_end_lba = 127362306a36Sopenharmony_ci ((span_row << raid->stripeShift) 127462306a36Sopenharmony_ci * span_row_width) - 1; 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci span_set->span_row_start = 0; 127762306a36Sopenharmony_ci span_set->span_row_end = span_row - 1; 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci span_set->data_strip_start = 0; 128062306a36Sopenharmony_ci span_set->data_strip_end = 128162306a36Sopenharmony_ci (span_row * span_row_width) - 1; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci span_set->data_row_start = 0; 128462306a36Sopenharmony_ci span_set->data_row_end = 128562306a36Sopenharmony_ci (span_row * le32_to_cpu(quad->diff)) - 1; 128662306a36Sopenharmony_ci } else { 128762306a36Sopenharmony_ci span_set_prev = &(ldSpanInfo[ld]. 128862306a36Sopenharmony_ci span_set[element - 1]); 128962306a36Sopenharmony_ci span_set->log_start_lba = 129062306a36Sopenharmony_ci span_set_prev->log_end_lba + 1; 129162306a36Sopenharmony_ci span_set->log_end_lba = 129262306a36Sopenharmony_ci span_set->log_start_lba + 129362306a36Sopenharmony_ci ((span_row << raid->stripeShift) 129462306a36Sopenharmony_ci * span_row_width) - 1; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci span_set->span_row_start = 129762306a36Sopenharmony_ci span_set_prev->span_row_end + 1; 129862306a36Sopenharmony_ci span_set->span_row_end = 129962306a36Sopenharmony_ci span_set->span_row_start + span_row - 1; 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci span_set->data_strip_start = 130262306a36Sopenharmony_ci span_set_prev->data_strip_end + 1; 130362306a36Sopenharmony_ci span_set->data_strip_end = 130462306a36Sopenharmony_ci span_set->data_strip_start + 130562306a36Sopenharmony_ci (span_row * span_row_width) - 1; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci span_set->data_row_start = 130862306a36Sopenharmony_ci span_set_prev->data_row_end + 1; 130962306a36Sopenharmony_ci span_set->data_row_end = 131062306a36Sopenharmony_ci span_set->data_row_start + 131162306a36Sopenharmony_ci (span_row * le32_to_cpu(quad->diff)) - 1; 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci break; 131462306a36Sopenharmony_ci } 131562306a36Sopenharmony_ci if (span == raid->spanDepth) 131662306a36Sopenharmony_ci break; 131762306a36Sopenharmony_ci } 131862306a36Sopenharmony_ci } 131962306a36Sopenharmony_ci} 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_civoid mr_update_load_balance_params(struct MR_DRV_RAID_MAP_ALL *drv_map, 132262306a36Sopenharmony_ci struct LD_LOAD_BALANCE_INFO *lbInfo) 132362306a36Sopenharmony_ci{ 132462306a36Sopenharmony_ci int ldCount; 132562306a36Sopenharmony_ci u16 ld; 132662306a36Sopenharmony_ci struct MR_LD_RAID *raid; 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci if (lb_pending_cmds > 128 || lb_pending_cmds < 1) 132962306a36Sopenharmony_ci lb_pending_cmds = LB_PENDING_CMDS_DEFAULT; 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES_EXT; ldCount++) { 133262306a36Sopenharmony_ci ld = MR_TargetIdToLdGet(ldCount, drv_map); 133362306a36Sopenharmony_ci if (ld >= MAX_LOGICAL_DRIVES_EXT - 1) { 133462306a36Sopenharmony_ci lbInfo[ldCount].loadBalanceFlag = 0; 133562306a36Sopenharmony_ci continue; 133662306a36Sopenharmony_ci } 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci raid = MR_LdRaidGet(ld, drv_map); 133962306a36Sopenharmony_ci if ((raid->level != 1) || 134062306a36Sopenharmony_ci (raid->ldState != MR_LD_STATE_OPTIMAL)) { 134162306a36Sopenharmony_ci lbInfo[ldCount].loadBalanceFlag = 0; 134262306a36Sopenharmony_ci continue; 134362306a36Sopenharmony_ci } 134462306a36Sopenharmony_ci lbInfo[ldCount].loadBalanceFlag = 1; 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci} 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_cistatic u8 megasas_get_best_arm_pd(struct megasas_instance *instance, 134962306a36Sopenharmony_ci struct LD_LOAD_BALANCE_INFO *lbInfo, 135062306a36Sopenharmony_ci struct IO_REQUEST_INFO *io_info, 135162306a36Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *drv_map) 135262306a36Sopenharmony_ci{ 135362306a36Sopenharmony_ci struct MR_LD_RAID *raid; 135462306a36Sopenharmony_ci u16 pd1_dev_handle; 135562306a36Sopenharmony_ci u16 pend0, pend1, ld; 135662306a36Sopenharmony_ci u64 diff0, diff1; 135762306a36Sopenharmony_ci u8 bestArm, pd0, pd1, span, arm; 135862306a36Sopenharmony_ci u32 arRef, span_row_size; 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci u64 block = io_info->ldStartBlock; 136162306a36Sopenharmony_ci u32 count = io_info->numBlocks; 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci span = ((io_info->span_arm & RAID_CTX_SPANARM_SPAN_MASK) 136462306a36Sopenharmony_ci >> RAID_CTX_SPANARM_SPAN_SHIFT); 136562306a36Sopenharmony_ci arm = (io_info->span_arm & RAID_CTX_SPANARM_ARM_MASK); 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci ld = MR_TargetIdToLdGet(io_info->ldTgtId, drv_map); 136862306a36Sopenharmony_ci raid = MR_LdRaidGet(ld, drv_map); 136962306a36Sopenharmony_ci span_row_size = instance->UnevenSpanSupport ? 137062306a36Sopenharmony_ci SPAN_ROW_SIZE(drv_map, ld, span) : raid->rowSize; 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci arRef = MR_LdSpanArrayGet(ld, span, drv_map); 137362306a36Sopenharmony_ci pd0 = MR_ArPdGet(arRef, arm, drv_map); 137462306a36Sopenharmony_ci pd1 = MR_ArPdGet(arRef, (arm + 1) >= span_row_size ? 137562306a36Sopenharmony_ci (arm + 1 - span_row_size) : arm + 1, drv_map); 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci /* Get PD1 Dev Handle */ 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci pd1_dev_handle = MR_PdDevHandleGet(pd1, drv_map); 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci if (pd1_dev_handle == MR_DEVHANDLE_INVALID) { 138262306a36Sopenharmony_ci bestArm = arm; 138362306a36Sopenharmony_ci } else { 138462306a36Sopenharmony_ci /* get the pending cmds for the data and mirror arms */ 138562306a36Sopenharmony_ci pend0 = atomic_read(&lbInfo->scsi_pending_cmds[pd0]); 138662306a36Sopenharmony_ci pend1 = atomic_read(&lbInfo->scsi_pending_cmds[pd1]); 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci /* Determine the disk whose head is nearer to the req. block */ 138962306a36Sopenharmony_ci diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[pd0]); 139062306a36Sopenharmony_ci diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[pd1]); 139162306a36Sopenharmony_ci bestArm = (diff0 <= diff1 ? arm : arm ^ 1); 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci /* Make balance count from 16 to 4 to 139462306a36Sopenharmony_ci * keep driver in sync with Firmware 139562306a36Sopenharmony_ci */ 139662306a36Sopenharmony_ci if ((bestArm == arm && pend0 > pend1 + lb_pending_cmds) || 139762306a36Sopenharmony_ci (bestArm != arm && pend1 > pend0 + lb_pending_cmds)) 139862306a36Sopenharmony_ci bestArm ^= 1; 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci /* Update the last accessed block on the correct pd */ 140162306a36Sopenharmony_ci io_info->span_arm = 140262306a36Sopenharmony_ci (span << RAID_CTX_SPANARM_SPAN_SHIFT) | bestArm; 140362306a36Sopenharmony_ci io_info->pd_after_lb = (bestArm == arm) ? pd0 : pd1; 140462306a36Sopenharmony_ci } 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci lbInfo->last_accessed_block[io_info->pd_after_lb] = block + count - 1; 140762306a36Sopenharmony_ci return io_info->pd_after_lb; 140862306a36Sopenharmony_ci} 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci__le16 get_updated_dev_handle(struct megasas_instance *instance, 141162306a36Sopenharmony_ci struct LD_LOAD_BALANCE_INFO *lbInfo, 141262306a36Sopenharmony_ci struct IO_REQUEST_INFO *io_info, 141362306a36Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *drv_map) 141462306a36Sopenharmony_ci{ 141562306a36Sopenharmony_ci u8 arm_pd; 141662306a36Sopenharmony_ci __le16 devHandle; 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci /* get best new arm (PD ID) */ 141962306a36Sopenharmony_ci arm_pd = megasas_get_best_arm_pd(instance, lbInfo, io_info, drv_map); 142062306a36Sopenharmony_ci devHandle = MR_PdDevHandleGet(arm_pd, drv_map); 142162306a36Sopenharmony_ci io_info->pd_interface = MR_PdInterfaceTypeGet(arm_pd, drv_map); 142262306a36Sopenharmony_ci atomic_inc(&lbInfo->scsi_pending_cmds[arm_pd]); 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci return devHandle; 142562306a36Sopenharmony_ci} 1426