18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Linux MegaRAID driver for SAS based RAID controllers 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2009-2013 LSI Corporation 68c2ecf20Sopenharmony_ci * Copyright (c) 2013-2016 Avago Technologies 78c2ecf20Sopenharmony_ci * Copyright (c) 2016-2018 Broadcom Inc. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * FILE: megaraid_sas_fp.c 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Authors: Broadcom Inc. 128c2ecf20Sopenharmony_ci * Sumant Patro 138c2ecf20Sopenharmony_ci * Varad Talamacki 148c2ecf20Sopenharmony_ci * Manoj Jose 158c2ecf20Sopenharmony_ci * Kashyap Desai <kashyap.desai@broadcom.com> 168c2ecf20Sopenharmony_ci * Sumit Saxena <sumit.saxena@broadcom.com> 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Send feedback to: megaraidlinux.pdl@broadcom.com 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/kernel.h> 228c2ecf20Sopenharmony_ci#include <linux/types.h> 238c2ecf20Sopenharmony_ci#include <linux/pci.h> 248c2ecf20Sopenharmony_ci#include <linux/list.h> 258c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 268c2ecf20Sopenharmony_ci#include <linux/module.h> 278c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 288c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 298c2ecf20Sopenharmony_ci#include <linux/delay.h> 308c2ecf20Sopenharmony_ci#include <linux/uio.h> 318c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 328c2ecf20Sopenharmony_ci#include <linux/fs.h> 338c2ecf20Sopenharmony_ci#include <linux/compat.h> 348c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 358c2ecf20Sopenharmony_ci#include <linux/poll.h> 368c2ecf20Sopenharmony_ci#include <linux/irq_poll.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 398c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 408c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 418c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#include "megaraid_sas_fusion.h" 448c2ecf20Sopenharmony_ci#include "megaraid_sas.h" 458c2ecf20Sopenharmony_ci#include <asm/div64.h> 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define LB_PENDING_CMDS_DEFAULT 4 488c2ecf20Sopenharmony_cistatic unsigned int lb_pending_cmds = LB_PENDING_CMDS_DEFAULT; 498c2ecf20Sopenharmony_cimodule_param(lb_pending_cmds, int, 0444); 508c2ecf20Sopenharmony_ciMODULE_PARM_DESC(lb_pending_cmds, "Change raid-1 load balancing outstanding " 518c2ecf20Sopenharmony_ci "threshold. Valid Values are 1-128. Default: 4"); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define ABS_DIFF(a, b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a))) 558c2ecf20Sopenharmony_ci#define MR_LD_STATE_OPTIMAL 3 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define SPAN_ROW_SIZE(map, ld, index_) (MR_LdSpanPtrGet(ld, index_, map)->spanRowSize) 588c2ecf20Sopenharmony_ci#define SPAN_ROW_DATA_SIZE(map_, ld, index_) (MR_LdSpanPtrGet(ld, index_, map)->spanRowDataSize) 598c2ecf20Sopenharmony_ci#define SPAN_INVALID 0xff 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* Prototypes */ 628c2ecf20Sopenharmony_cistatic void mr_update_span_set(struct MR_DRV_RAID_MAP_ALL *map, 638c2ecf20Sopenharmony_ci PLD_SPAN_INFO ldSpanInfo); 648c2ecf20Sopenharmony_cistatic u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld, 658c2ecf20Sopenharmony_ci u64 stripRow, u16 stripRef, struct IO_REQUEST_INFO *io_info, 668c2ecf20Sopenharmony_ci struct RAID_CONTEXT *pRAID_Context, struct MR_DRV_RAID_MAP_ALL *map); 678c2ecf20Sopenharmony_cistatic u64 get_row_from_strip(struct megasas_instance *instance, u32 ld, 688c2ecf20Sopenharmony_ci u64 strip, struct MR_DRV_RAID_MAP_ALL *map); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ciu32 mega_mod64(u64 dividend, u32 divisor) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci u64 d; 738c2ecf20Sopenharmony_ci u32 remainder; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (!divisor) 768c2ecf20Sopenharmony_ci printk(KERN_ERR "megasas : DIVISOR is zero, in div fn\n"); 778c2ecf20Sopenharmony_ci d = dividend; 788c2ecf20Sopenharmony_ci remainder = do_div(d, divisor); 798c2ecf20Sopenharmony_ci return remainder; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/** 838c2ecf20Sopenharmony_ci * mega_div64_32 - Do a 64-bit division 848c2ecf20Sopenharmony_ci * @dividend: Dividend 858c2ecf20Sopenharmony_ci * @divisor: Divisor 868c2ecf20Sopenharmony_ci * 878c2ecf20Sopenharmony_ci * @return quotient 888c2ecf20Sopenharmony_ci **/ 898c2ecf20Sopenharmony_cistatic u64 mega_div64_32(uint64_t dividend, uint32_t divisor) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci u64 d = dividend; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (!divisor) 948c2ecf20Sopenharmony_ci printk(KERN_ERR "megasas : DIVISOR is zero in mod fn\n"); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci do_div(d, divisor); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci return d; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistruct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_DRV_RAID_MAP_ALL *map) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci return &map->raidMap.ldSpanMap[ld].ldRaid; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic struct MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u32 ld, 1078c2ecf20Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL 1088c2ecf20Sopenharmony_ci *map) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci return &map->raidMap.ldSpanMap[ld].spanBlock[0]; 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic u8 MR_LdDataArmGet(u32 ld, u32 armIdx, struct MR_DRV_RAID_MAP_ALL *map) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci return map->raidMap.ldSpanMap[ld].dataArmMap[armIdx]; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ciu16 MR_ArPdGet(u32 ar, u32 arm, struct MR_DRV_RAID_MAP_ALL *map) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci return le16_to_cpu(map->raidMap.arMapInfo[ar].pd[arm]); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ciu16 MR_LdSpanArrayGet(u32 ld, u32 span, struct MR_DRV_RAID_MAP_ALL *map) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci return le16_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].span.arrayRef); 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci__le16 MR_PdDevHandleGet(u32 pd, struct MR_DRV_RAID_MAP_ALL *map) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci return map->raidMap.devHndlInfo[pd].curDevHdl; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic u8 MR_PdInterfaceTypeGet(u32 pd, struct MR_DRV_RAID_MAP_ALL *map) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci return map->raidMap.devHndlInfo[pd].interfaceType; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ciu16 MR_GetLDTgtId(u32 ld, struct MR_DRV_RAID_MAP_ALL *map) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci return le16_to_cpu(map->raidMap.ldSpanMap[ld].ldRaid.targetId); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ciu16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_DRV_RAID_MAP_ALL *map) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci return map->raidMap.ldTgtIdToLd[ldTgtId]; 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic struct MR_LD_SPAN *MR_LdSpanPtrGet(u32 ld, u32 span, 1498c2ecf20Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *map) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci return &map->raidMap.ldSpanMap[ld].spanBlock[span].span; 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci/* 1558c2ecf20Sopenharmony_ci * This function will Populate Driver Map using firmware raid map 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_cistatic int MR_PopulateDrvRaidMap(struct megasas_instance *instance, u64 map_id) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 1608c2ecf20Sopenharmony_ci struct MR_FW_RAID_MAP_ALL *fw_map_old = NULL; 1618c2ecf20Sopenharmony_ci struct MR_FW_RAID_MAP *pFwRaidMap = NULL; 1628c2ecf20Sopenharmony_ci int i, j; 1638c2ecf20Sopenharmony_ci u16 ld_count; 1648c2ecf20Sopenharmony_ci struct MR_FW_RAID_MAP_DYNAMIC *fw_map_dyn; 1658c2ecf20Sopenharmony_ci struct MR_FW_RAID_MAP_EXT *fw_map_ext; 1668c2ecf20Sopenharmony_ci struct MR_RAID_MAP_DESC_TABLE *desc_table; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *drv_map = 1708c2ecf20Sopenharmony_ci fusion->ld_drv_map[(map_id & 1)]; 1718c2ecf20Sopenharmony_ci struct MR_DRV_RAID_MAP *pDrvRaidMap = &drv_map->raidMap; 1728c2ecf20Sopenharmony_ci void *raid_map_data = NULL; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci memset(drv_map, 0, fusion->drv_map_sz); 1758c2ecf20Sopenharmony_ci memset(pDrvRaidMap->ldTgtIdToLd, 1768c2ecf20Sopenharmony_ci 0xff, (sizeof(u16) * MAX_LOGICAL_DRIVES_DYN)); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (instance->max_raid_mapsize) { 1798c2ecf20Sopenharmony_ci fw_map_dyn = fusion->ld_map[(map_id & 1)]; 1808c2ecf20Sopenharmony_ci desc_table = 1818c2ecf20Sopenharmony_ci (struct MR_RAID_MAP_DESC_TABLE *)((void *)fw_map_dyn + le32_to_cpu(fw_map_dyn->desc_table_offset)); 1828c2ecf20Sopenharmony_ci if (desc_table != fw_map_dyn->raid_map_desc_table) 1838c2ecf20Sopenharmony_ci dev_dbg(&instance->pdev->dev, "offsets of desc table are not matching desc %p original %p\n", 1848c2ecf20Sopenharmony_ci desc_table, fw_map_dyn->raid_map_desc_table); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci ld_count = (u16)le16_to_cpu(fw_map_dyn->ld_count); 1878c2ecf20Sopenharmony_ci pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count); 1888c2ecf20Sopenharmony_ci pDrvRaidMap->fpPdIoTimeoutSec = 1898c2ecf20Sopenharmony_ci fw_map_dyn->fp_pd_io_timeout_sec; 1908c2ecf20Sopenharmony_ci pDrvRaidMap->totalSize = 1918c2ecf20Sopenharmony_ci cpu_to_le32(sizeof(struct MR_DRV_RAID_MAP_ALL)); 1928c2ecf20Sopenharmony_ci /* point to actual data starting point*/ 1938c2ecf20Sopenharmony_ci raid_map_data = (void *)fw_map_dyn + 1948c2ecf20Sopenharmony_ci le32_to_cpu(fw_map_dyn->desc_table_offset) + 1958c2ecf20Sopenharmony_ci le32_to_cpu(fw_map_dyn->desc_table_size); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci for (i = 0; i < le32_to_cpu(fw_map_dyn->desc_table_num_elements); ++i) { 1988c2ecf20Sopenharmony_ci switch (le32_to_cpu(desc_table->raid_map_desc_type)) { 1998c2ecf20Sopenharmony_ci case RAID_MAP_DESC_TYPE_DEVHDL_INFO: 2008c2ecf20Sopenharmony_ci fw_map_dyn->dev_hndl_info = 2018c2ecf20Sopenharmony_ci (struct MR_DEV_HANDLE_INFO *)(raid_map_data + le32_to_cpu(desc_table->raid_map_desc_offset)); 2028c2ecf20Sopenharmony_ci memcpy(pDrvRaidMap->devHndlInfo, 2038c2ecf20Sopenharmony_ci fw_map_dyn->dev_hndl_info, 2048c2ecf20Sopenharmony_ci sizeof(struct MR_DEV_HANDLE_INFO) * 2058c2ecf20Sopenharmony_ci le32_to_cpu(desc_table->raid_map_desc_elements)); 2068c2ecf20Sopenharmony_ci break; 2078c2ecf20Sopenharmony_ci case RAID_MAP_DESC_TYPE_TGTID_INFO: 2088c2ecf20Sopenharmony_ci fw_map_dyn->ld_tgt_id_to_ld = 2098c2ecf20Sopenharmony_ci (u16 *)(raid_map_data + 2108c2ecf20Sopenharmony_ci le32_to_cpu(desc_table->raid_map_desc_offset)); 2118c2ecf20Sopenharmony_ci for (j = 0; j < le32_to_cpu(desc_table->raid_map_desc_elements); j++) { 2128c2ecf20Sopenharmony_ci pDrvRaidMap->ldTgtIdToLd[j] = 2138c2ecf20Sopenharmony_ci le16_to_cpu(fw_map_dyn->ld_tgt_id_to_ld[j]); 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci break; 2168c2ecf20Sopenharmony_ci case RAID_MAP_DESC_TYPE_ARRAY_INFO: 2178c2ecf20Sopenharmony_ci fw_map_dyn->ar_map_info = 2188c2ecf20Sopenharmony_ci (struct MR_ARRAY_INFO *) 2198c2ecf20Sopenharmony_ci (raid_map_data + le32_to_cpu(desc_table->raid_map_desc_offset)); 2208c2ecf20Sopenharmony_ci memcpy(pDrvRaidMap->arMapInfo, 2218c2ecf20Sopenharmony_ci fw_map_dyn->ar_map_info, 2228c2ecf20Sopenharmony_ci sizeof(struct MR_ARRAY_INFO) * 2238c2ecf20Sopenharmony_ci le32_to_cpu(desc_table->raid_map_desc_elements)); 2248c2ecf20Sopenharmony_ci break; 2258c2ecf20Sopenharmony_ci case RAID_MAP_DESC_TYPE_SPAN_INFO: 2268c2ecf20Sopenharmony_ci fw_map_dyn->ld_span_map = 2278c2ecf20Sopenharmony_ci (struct MR_LD_SPAN_MAP *) 2288c2ecf20Sopenharmony_ci (raid_map_data + 2298c2ecf20Sopenharmony_ci le32_to_cpu(desc_table->raid_map_desc_offset)); 2308c2ecf20Sopenharmony_ci memcpy(pDrvRaidMap->ldSpanMap, 2318c2ecf20Sopenharmony_ci fw_map_dyn->ld_span_map, 2328c2ecf20Sopenharmony_ci sizeof(struct MR_LD_SPAN_MAP) * 2338c2ecf20Sopenharmony_ci le32_to_cpu(desc_table->raid_map_desc_elements)); 2348c2ecf20Sopenharmony_ci break; 2358c2ecf20Sopenharmony_ci default: 2368c2ecf20Sopenharmony_ci dev_dbg(&instance->pdev->dev, "wrong number of desctableElements %d\n", 2378c2ecf20Sopenharmony_ci fw_map_dyn->desc_table_num_elements); 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci ++desc_table; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci } else if (instance->supportmax256vd) { 2438c2ecf20Sopenharmony_ci fw_map_ext = 2448c2ecf20Sopenharmony_ci (struct MR_FW_RAID_MAP_EXT *)fusion->ld_map[(map_id & 1)]; 2458c2ecf20Sopenharmony_ci ld_count = (u16)le16_to_cpu(fw_map_ext->ldCount); 2468c2ecf20Sopenharmony_ci if (ld_count > MAX_LOGICAL_DRIVES_EXT) { 2478c2ecf20Sopenharmony_ci dev_dbg(&instance->pdev->dev, "megaraid_sas: LD count exposed in RAID map in not valid\n"); 2488c2ecf20Sopenharmony_ci return 1; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count); 2528c2ecf20Sopenharmony_ci pDrvRaidMap->fpPdIoTimeoutSec = fw_map_ext->fpPdIoTimeoutSec; 2538c2ecf20Sopenharmony_ci for (i = 0; i < (MAX_LOGICAL_DRIVES_EXT); i++) 2548c2ecf20Sopenharmony_ci pDrvRaidMap->ldTgtIdToLd[i] = 2558c2ecf20Sopenharmony_ci (u16)fw_map_ext->ldTgtIdToLd[i]; 2568c2ecf20Sopenharmony_ci memcpy(pDrvRaidMap->ldSpanMap, fw_map_ext->ldSpanMap, 2578c2ecf20Sopenharmony_ci sizeof(struct MR_LD_SPAN_MAP) * ld_count); 2588c2ecf20Sopenharmony_ci memcpy(pDrvRaidMap->arMapInfo, fw_map_ext->arMapInfo, 2598c2ecf20Sopenharmony_ci sizeof(struct MR_ARRAY_INFO) * MAX_API_ARRAYS_EXT); 2608c2ecf20Sopenharmony_ci memcpy(pDrvRaidMap->devHndlInfo, fw_map_ext->devHndlInfo, 2618c2ecf20Sopenharmony_ci sizeof(struct MR_DEV_HANDLE_INFO) * 2628c2ecf20Sopenharmony_ci MAX_RAIDMAP_PHYSICAL_DEVICES); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* New Raid map will not set totalSize, so keep expected value 2658c2ecf20Sopenharmony_ci * for legacy code in ValidateMapInfo 2668c2ecf20Sopenharmony_ci */ 2678c2ecf20Sopenharmony_ci pDrvRaidMap->totalSize = 2688c2ecf20Sopenharmony_ci cpu_to_le32(sizeof(struct MR_FW_RAID_MAP_EXT)); 2698c2ecf20Sopenharmony_ci } else { 2708c2ecf20Sopenharmony_ci fw_map_old = (struct MR_FW_RAID_MAP_ALL *) 2718c2ecf20Sopenharmony_ci fusion->ld_map[(map_id & 1)]; 2728c2ecf20Sopenharmony_ci pFwRaidMap = &fw_map_old->raidMap; 2738c2ecf20Sopenharmony_ci ld_count = (u16)le32_to_cpu(pFwRaidMap->ldCount); 2748c2ecf20Sopenharmony_ci if (ld_count > MAX_LOGICAL_DRIVES) { 2758c2ecf20Sopenharmony_ci dev_dbg(&instance->pdev->dev, 2768c2ecf20Sopenharmony_ci "LD count exposed in RAID map in not valid\n"); 2778c2ecf20Sopenharmony_ci return 1; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci pDrvRaidMap->totalSize = pFwRaidMap->totalSize; 2818c2ecf20Sopenharmony_ci pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count); 2828c2ecf20Sopenharmony_ci pDrvRaidMap->fpPdIoTimeoutSec = pFwRaidMap->fpPdIoTimeoutSec; 2838c2ecf20Sopenharmony_ci for (i = 0; i < MAX_RAIDMAP_LOGICAL_DRIVES + MAX_RAIDMAP_VIEWS; i++) 2848c2ecf20Sopenharmony_ci pDrvRaidMap->ldTgtIdToLd[i] = 2858c2ecf20Sopenharmony_ci (u8)pFwRaidMap->ldTgtIdToLd[i]; 2868c2ecf20Sopenharmony_ci for (i = 0; i < ld_count; i++) { 2878c2ecf20Sopenharmony_ci pDrvRaidMap->ldSpanMap[i] = pFwRaidMap->ldSpanMap[i]; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci memcpy(pDrvRaidMap->arMapInfo, pFwRaidMap->arMapInfo, 2908c2ecf20Sopenharmony_ci sizeof(struct MR_ARRAY_INFO) * MAX_RAIDMAP_ARRAYS); 2918c2ecf20Sopenharmony_ci memcpy(pDrvRaidMap->devHndlInfo, pFwRaidMap->devHndlInfo, 2928c2ecf20Sopenharmony_ci sizeof(struct MR_DEV_HANDLE_INFO) * 2938c2ecf20Sopenharmony_ci MAX_RAIDMAP_PHYSICAL_DEVICES); 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return 0; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci/* 3008c2ecf20Sopenharmony_ci * This function will validate Map info data provided by FW 3018c2ecf20Sopenharmony_ci */ 3028c2ecf20Sopenharmony_ciu8 MR_ValidateMapInfo(struct megasas_instance *instance, u64 map_id) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct fusion_context *fusion; 3058c2ecf20Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *drv_map; 3068c2ecf20Sopenharmony_ci struct MR_DRV_RAID_MAP *pDrvRaidMap; 3078c2ecf20Sopenharmony_ci struct LD_LOAD_BALANCE_INFO *lbInfo; 3088c2ecf20Sopenharmony_ci PLD_SPAN_INFO ldSpanInfo; 3098c2ecf20Sopenharmony_ci struct MR_LD_RAID *raid; 3108c2ecf20Sopenharmony_ci u16 num_lds, i; 3118c2ecf20Sopenharmony_ci u16 ld; 3128c2ecf20Sopenharmony_ci u32 expected_size; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (MR_PopulateDrvRaidMap(instance, map_id)) 3158c2ecf20Sopenharmony_ci return 0; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 3188c2ecf20Sopenharmony_ci drv_map = fusion->ld_drv_map[(map_id & 1)]; 3198c2ecf20Sopenharmony_ci pDrvRaidMap = &drv_map->raidMap; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci lbInfo = fusion->load_balance_info; 3228c2ecf20Sopenharmony_ci ldSpanInfo = fusion->log_to_span; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (instance->max_raid_mapsize) 3258c2ecf20Sopenharmony_ci expected_size = sizeof(struct MR_DRV_RAID_MAP_ALL); 3268c2ecf20Sopenharmony_ci else if (instance->supportmax256vd) 3278c2ecf20Sopenharmony_ci expected_size = sizeof(struct MR_FW_RAID_MAP_EXT); 3288c2ecf20Sopenharmony_ci else 3298c2ecf20Sopenharmony_ci expected_size = 3308c2ecf20Sopenharmony_ci (sizeof(struct MR_FW_RAID_MAP) - sizeof(struct MR_LD_SPAN_MAP) + 3318c2ecf20Sopenharmony_ci (sizeof(struct MR_LD_SPAN_MAP) * le16_to_cpu(pDrvRaidMap->ldCount))); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (le32_to_cpu(pDrvRaidMap->totalSize) != expected_size) { 3348c2ecf20Sopenharmony_ci dev_dbg(&instance->pdev->dev, "megasas: map info structure size 0x%x", 3358c2ecf20Sopenharmony_ci le32_to_cpu(pDrvRaidMap->totalSize)); 3368c2ecf20Sopenharmony_ci dev_dbg(&instance->pdev->dev, "is not matching expected size 0x%x\n", 3378c2ecf20Sopenharmony_ci (unsigned int)expected_size); 3388c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "megasas: span map %x, pDrvRaidMap->totalSize : %x\n", 3398c2ecf20Sopenharmony_ci (unsigned int)sizeof(struct MR_LD_SPAN_MAP), 3408c2ecf20Sopenharmony_ci le32_to_cpu(pDrvRaidMap->totalSize)); 3418c2ecf20Sopenharmony_ci return 0; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (instance->UnevenSpanSupport) 3458c2ecf20Sopenharmony_ci mr_update_span_set(drv_map, ldSpanInfo); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (lbInfo) 3488c2ecf20Sopenharmony_ci mr_update_load_balance_params(drv_map, lbInfo); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci num_lds = le16_to_cpu(drv_map->raidMap.ldCount); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci memcpy(instance->ld_ids_prev, 3538c2ecf20Sopenharmony_ci instance->ld_ids_from_raidmap, 3548c2ecf20Sopenharmony_ci sizeof(instance->ld_ids_from_raidmap)); 3558c2ecf20Sopenharmony_ci memset(instance->ld_ids_from_raidmap, 0xff, MEGASAS_MAX_LD_IDS); 3568c2ecf20Sopenharmony_ci /*Convert Raid capability values to CPU arch */ 3578c2ecf20Sopenharmony_ci for (i = 0; (num_lds > 0) && (i < MAX_LOGICAL_DRIVES_EXT); i++) { 3588c2ecf20Sopenharmony_ci ld = MR_TargetIdToLdGet(i, drv_map); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* For non existing VDs, iterate to next VD*/ 3618c2ecf20Sopenharmony_ci if (ld >= MEGASAS_MAX_SUPPORTED_LD_IDS) 3628c2ecf20Sopenharmony_ci continue; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci raid = MR_LdRaidGet(ld, drv_map); 3658c2ecf20Sopenharmony_ci le32_to_cpus((u32 *)&raid->capability); 3668c2ecf20Sopenharmony_ci instance->ld_ids_from_raidmap[i] = i; 3678c2ecf20Sopenharmony_ci num_lds--; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci return 1; 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cistatic u32 MR_GetSpanBlock(u32 ld, u64 row, u64 *span_blk, 3748c2ecf20Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *map) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci struct MR_SPAN_BLOCK_INFO *pSpanBlock = MR_LdSpanInfoGet(ld, map); 3778c2ecf20Sopenharmony_ci struct MR_QUAD_ELEMENT *quad; 3788c2ecf20Sopenharmony_ci struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 3798c2ecf20Sopenharmony_ci u32 span, j; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci for (span = 0; span < raid->spanDepth; span++, pSpanBlock++) { 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci for (j = 0; j < le32_to_cpu(pSpanBlock->block_span_info.noElements); j++) { 3848c2ecf20Sopenharmony_ci quad = &pSpanBlock->block_span_info.quad[j]; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci if (le32_to_cpu(quad->diff) == 0) 3878c2ecf20Sopenharmony_ci return SPAN_INVALID; 3888c2ecf20Sopenharmony_ci if (le64_to_cpu(quad->logStart) <= row && row <= 3898c2ecf20Sopenharmony_ci le64_to_cpu(quad->logEnd) && (mega_mod64(row - le64_to_cpu(quad->logStart), 3908c2ecf20Sopenharmony_ci le32_to_cpu(quad->diff))) == 0) { 3918c2ecf20Sopenharmony_ci if (span_blk != NULL) { 3928c2ecf20Sopenharmony_ci u64 blk; 3938c2ecf20Sopenharmony_ci blk = mega_div64_32((row-le64_to_cpu(quad->logStart)), le32_to_cpu(quad->diff)); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci blk = (blk + le64_to_cpu(quad->offsetInSpan)) << raid->stripeShift; 3968c2ecf20Sopenharmony_ci *span_blk = blk; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci return span; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci return SPAN_INVALID; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci/* 4068c2ecf20Sopenharmony_ci****************************************************************************** 4078c2ecf20Sopenharmony_ci* 4088c2ecf20Sopenharmony_ci* This routine calculates the Span block for given row using spanset. 4098c2ecf20Sopenharmony_ci* 4108c2ecf20Sopenharmony_ci* Inputs : 4118c2ecf20Sopenharmony_ci* instance - HBA instance 4128c2ecf20Sopenharmony_ci* ld - Logical drive number 4138c2ecf20Sopenharmony_ci* row - Row number 4148c2ecf20Sopenharmony_ci* map - LD map 4158c2ecf20Sopenharmony_ci* 4168c2ecf20Sopenharmony_ci* Outputs : 4178c2ecf20Sopenharmony_ci* 4188c2ecf20Sopenharmony_ci* span - Span number 4198c2ecf20Sopenharmony_ci* block - Absolute Block number in the physical disk 4208c2ecf20Sopenharmony_ci* div_error - Devide error code. 4218c2ecf20Sopenharmony_ci*/ 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic u32 mr_spanset_get_span_block(struct megasas_instance *instance, 4248c2ecf20Sopenharmony_ci u32 ld, u64 row, u64 *span_blk, struct MR_DRV_RAID_MAP_ALL *map) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 4278c2ecf20Sopenharmony_ci struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 4288c2ecf20Sopenharmony_ci LD_SPAN_SET *span_set; 4298c2ecf20Sopenharmony_ci struct MR_QUAD_ELEMENT *quad; 4308c2ecf20Sopenharmony_ci u32 span, info; 4318c2ecf20Sopenharmony_ci PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci for (info = 0; info < MAX_QUAD_DEPTH; info++) { 4348c2ecf20Sopenharmony_ci span_set = &(ldSpanInfo[ld].span_set[info]); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (span_set->span_row_data_width == 0) 4378c2ecf20Sopenharmony_ci break; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci if (row > span_set->data_row_end) 4408c2ecf20Sopenharmony_ci continue; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci for (span = 0; span < raid->spanDepth; span++) 4438c2ecf20Sopenharmony_ci if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span]. 4448c2ecf20Sopenharmony_ci block_span_info.noElements) >= info+1) { 4458c2ecf20Sopenharmony_ci quad = &map->raidMap.ldSpanMap[ld]. 4468c2ecf20Sopenharmony_ci spanBlock[span]. 4478c2ecf20Sopenharmony_ci block_span_info.quad[info]; 4488c2ecf20Sopenharmony_ci if (le32_to_cpu(quad->diff) == 0) 4498c2ecf20Sopenharmony_ci return SPAN_INVALID; 4508c2ecf20Sopenharmony_ci if (le64_to_cpu(quad->logStart) <= row && 4518c2ecf20Sopenharmony_ci row <= le64_to_cpu(quad->logEnd) && 4528c2ecf20Sopenharmony_ci (mega_mod64(row - le64_to_cpu(quad->logStart), 4538c2ecf20Sopenharmony_ci le32_to_cpu(quad->diff))) == 0) { 4548c2ecf20Sopenharmony_ci if (span_blk != NULL) { 4558c2ecf20Sopenharmony_ci u64 blk; 4568c2ecf20Sopenharmony_ci blk = mega_div64_32 4578c2ecf20Sopenharmony_ci ((row - le64_to_cpu(quad->logStart)), 4588c2ecf20Sopenharmony_ci le32_to_cpu(quad->diff)); 4598c2ecf20Sopenharmony_ci blk = (blk + le64_to_cpu(quad->offsetInSpan)) 4608c2ecf20Sopenharmony_ci << raid->stripeShift; 4618c2ecf20Sopenharmony_ci *span_blk = blk; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci return span; 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci return SPAN_INVALID; 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci/* 4718c2ecf20Sopenharmony_ci****************************************************************************** 4728c2ecf20Sopenharmony_ci* 4738c2ecf20Sopenharmony_ci* This routine calculates the row for given strip using spanset. 4748c2ecf20Sopenharmony_ci* 4758c2ecf20Sopenharmony_ci* Inputs : 4768c2ecf20Sopenharmony_ci* instance - HBA instance 4778c2ecf20Sopenharmony_ci* ld - Logical drive number 4788c2ecf20Sopenharmony_ci* Strip - Strip 4798c2ecf20Sopenharmony_ci* map - LD map 4808c2ecf20Sopenharmony_ci* 4818c2ecf20Sopenharmony_ci* Outputs : 4828c2ecf20Sopenharmony_ci* 4838c2ecf20Sopenharmony_ci* row - row associated with strip 4848c2ecf20Sopenharmony_ci*/ 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic u64 get_row_from_strip(struct megasas_instance *instance, 4878c2ecf20Sopenharmony_ci u32 ld, u64 strip, struct MR_DRV_RAID_MAP_ALL *map) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 4908c2ecf20Sopenharmony_ci struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 4918c2ecf20Sopenharmony_ci LD_SPAN_SET *span_set; 4928c2ecf20Sopenharmony_ci PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span; 4938c2ecf20Sopenharmony_ci u32 info, strip_offset, span, span_offset; 4948c2ecf20Sopenharmony_ci u64 span_set_Strip, span_set_Row, retval; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci for (info = 0; info < MAX_QUAD_DEPTH; info++) { 4978c2ecf20Sopenharmony_ci span_set = &(ldSpanInfo[ld].span_set[info]); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (span_set->span_row_data_width == 0) 5008c2ecf20Sopenharmony_ci break; 5018c2ecf20Sopenharmony_ci if (strip > span_set->data_strip_end) 5028c2ecf20Sopenharmony_ci continue; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci span_set_Strip = strip - span_set->data_strip_start; 5058c2ecf20Sopenharmony_ci strip_offset = mega_mod64(span_set_Strip, 5068c2ecf20Sopenharmony_ci span_set->span_row_data_width); 5078c2ecf20Sopenharmony_ci span_set_Row = mega_div64_32(span_set_Strip, 5088c2ecf20Sopenharmony_ci span_set->span_row_data_width) * span_set->diff; 5098c2ecf20Sopenharmony_ci for (span = 0, span_offset = 0; span < raid->spanDepth; span++) 5108c2ecf20Sopenharmony_ci if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span]. 5118c2ecf20Sopenharmony_ci block_span_info.noElements) >= info+1) { 5128c2ecf20Sopenharmony_ci if (strip_offset >= 5138c2ecf20Sopenharmony_ci span_set->strip_offset[span]) 5148c2ecf20Sopenharmony_ci span_offset++; 5158c2ecf20Sopenharmony_ci else 5168c2ecf20Sopenharmony_ci break; 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci retval = (span_set->data_row_start + span_set_Row + 5208c2ecf20Sopenharmony_ci (span_offset - 1)); 5218c2ecf20Sopenharmony_ci return retval; 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci return -1LLU; 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci/* 5288c2ecf20Sopenharmony_ci****************************************************************************** 5298c2ecf20Sopenharmony_ci* 5308c2ecf20Sopenharmony_ci* This routine calculates the Start Strip for given row using spanset. 5318c2ecf20Sopenharmony_ci* 5328c2ecf20Sopenharmony_ci* Inputs : 5338c2ecf20Sopenharmony_ci* instance - HBA instance 5348c2ecf20Sopenharmony_ci* ld - Logical drive number 5358c2ecf20Sopenharmony_ci* row - Row number 5368c2ecf20Sopenharmony_ci* map - LD map 5378c2ecf20Sopenharmony_ci* 5388c2ecf20Sopenharmony_ci* Outputs : 5398c2ecf20Sopenharmony_ci* 5408c2ecf20Sopenharmony_ci* Strip - Start strip associated with row 5418c2ecf20Sopenharmony_ci*/ 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic u64 get_strip_from_row(struct megasas_instance *instance, 5448c2ecf20Sopenharmony_ci u32 ld, u64 row, struct MR_DRV_RAID_MAP_ALL *map) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 5478c2ecf20Sopenharmony_ci struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 5488c2ecf20Sopenharmony_ci LD_SPAN_SET *span_set; 5498c2ecf20Sopenharmony_ci struct MR_QUAD_ELEMENT *quad; 5508c2ecf20Sopenharmony_ci PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span; 5518c2ecf20Sopenharmony_ci u32 span, info; 5528c2ecf20Sopenharmony_ci u64 strip; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci for (info = 0; info < MAX_QUAD_DEPTH; info++) { 5558c2ecf20Sopenharmony_ci span_set = &(ldSpanInfo[ld].span_set[info]); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci if (span_set->span_row_data_width == 0) 5588c2ecf20Sopenharmony_ci break; 5598c2ecf20Sopenharmony_ci if (row > span_set->data_row_end) 5608c2ecf20Sopenharmony_ci continue; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci for (span = 0; span < raid->spanDepth; span++) 5638c2ecf20Sopenharmony_ci if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span]. 5648c2ecf20Sopenharmony_ci block_span_info.noElements) >= info+1) { 5658c2ecf20Sopenharmony_ci quad = &map->raidMap.ldSpanMap[ld]. 5668c2ecf20Sopenharmony_ci spanBlock[span].block_span_info.quad[info]; 5678c2ecf20Sopenharmony_ci if (le64_to_cpu(quad->logStart) <= row && 5688c2ecf20Sopenharmony_ci row <= le64_to_cpu(quad->logEnd) && 5698c2ecf20Sopenharmony_ci mega_mod64((row - le64_to_cpu(quad->logStart)), 5708c2ecf20Sopenharmony_ci le32_to_cpu(quad->diff)) == 0) { 5718c2ecf20Sopenharmony_ci strip = mega_div64_32 5728c2ecf20Sopenharmony_ci (((row - span_set->data_row_start) 5738c2ecf20Sopenharmony_ci - le64_to_cpu(quad->logStart)), 5748c2ecf20Sopenharmony_ci le32_to_cpu(quad->diff)); 5758c2ecf20Sopenharmony_ci strip *= span_set->span_row_data_width; 5768c2ecf20Sopenharmony_ci strip += span_set->data_strip_start; 5778c2ecf20Sopenharmony_ci strip += span_set->strip_offset[span]; 5788c2ecf20Sopenharmony_ci return strip; 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "get_strip_from_row" 5838c2ecf20Sopenharmony_ci "returns invalid strip for ld=%x, row=%lx\n", 5848c2ecf20Sopenharmony_ci ld, (long unsigned int)row); 5858c2ecf20Sopenharmony_ci return -1; 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci/* 5898c2ecf20Sopenharmony_ci****************************************************************************** 5908c2ecf20Sopenharmony_ci* 5918c2ecf20Sopenharmony_ci* This routine calculates the Physical Arm for given strip using spanset. 5928c2ecf20Sopenharmony_ci* 5938c2ecf20Sopenharmony_ci* Inputs : 5948c2ecf20Sopenharmony_ci* instance - HBA instance 5958c2ecf20Sopenharmony_ci* ld - Logical drive number 5968c2ecf20Sopenharmony_ci* strip - Strip 5978c2ecf20Sopenharmony_ci* map - LD map 5988c2ecf20Sopenharmony_ci* 5998c2ecf20Sopenharmony_ci* Outputs : 6008c2ecf20Sopenharmony_ci* 6018c2ecf20Sopenharmony_ci* Phys Arm - Phys Arm associated with strip 6028c2ecf20Sopenharmony_ci*/ 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_cistatic u32 get_arm_from_strip(struct megasas_instance *instance, 6058c2ecf20Sopenharmony_ci u32 ld, u64 strip, struct MR_DRV_RAID_MAP_ALL *map) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci struct fusion_context *fusion = instance->ctrl_context; 6088c2ecf20Sopenharmony_ci struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 6098c2ecf20Sopenharmony_ci LD_SPAN_SET *span_set; 6108c2ecf20Sopenharmony_ci PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span; 6118c2ecf20Sopenharmony_ci u32 info, strip_offset, span, span_offset, retval; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci for (info = 0 ; info < MAX_QUAD_DEPTH; info++) { 6148c2ecf20Sopenharmony_ci span_set = &(ldSpanInfo[ld].span_set[info]); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci if (span_set->span_row_data_width == 0) 6178c2ecf20Sopenharmony_ci break; 6188c2ecf20Sopenharmony_ci if (strip > span_set->data_strip_end) 6198c2ecf20Sopenharmony_ci continue; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci strip_offset = (uint)mega_mod64 6228c2ecf20Sopenharmony_ci ((strip - span_set->data_strip_start), 6238c2ecf20Sopenharmony_ci span_set->span_row_data_width); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci for (span = 0, span_offset = 0; span < raid->spanDepth; span++) 6268c2ecf20Sopenharmony_ci if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span]. 6278c2ecf20Sopenharmony_ci block_span_info.noElements) >= info+1) { 6288c2ecf20Sopenharmony_ci if (strip_offset >= 6298c2ecf20Sopenharmony_ci span_set->strip_offset[span]) 6308c2ecf20Sopenharmony_ci span_offset = 6318c2ecf20Sopenharmony_ci span_set->strip_offset[span]; 6328c2ecf20Sopenharmony_ci else 6338c2ecf20Sopenharmony_ci break; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci retval = (strip_offset - span_offset); 6378c2ecf20Sopenharmony_ci return retval; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci dev_err(&instance->pdev->dev, "get_arm_from_strip" 6418c2ecf20Sopenharmony_ci "returns invalid arm for ld=%x strip=%lx\n", 6428c2ecf20Sopenharmony_ci ld, (long unsigned int)strip); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci return -1; 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci/* This Function will return Phys arm */ 6488c2ecf20Sopenharmony_cistatic u8 get_arm(struct megasas_instance *instance, u32 ld, u8 span, u64 stripe, 6498c2ecf20Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *map) 6508c2ecf20Sopenharmony_ci{ 6518c2ecf20Sopenharmony_ci struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 6528c2ecf20Sopenharmony_ci /* Need to check correct default value */ 6538c2ecf20Sopenharmony_ci u32 arm = 0; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci switch (raid->level) { 6568c2ecf20Sopenharmony_ci case 0: 6578c2ecf20Sopenharmony_ci case 5: 6588c2ecf20Sopenharmony_ci case 6: 6598c2ecf20Sopenharmony_ci arm = mega_mod64(stripe, SPAN_ROW_SIZE(map, ld, span)); 6608c2ecf20Sopenharmony_ci break; 6618c2ecf20Sopenharmony_ci case 1: 6628c2ecf20Sopenharmony_ci /* start with logical arm */ 6638c2ecf20Sopenharmony_ci arm = get_arm_from_strip(instance, ld, stripe, map); 6648c2ecf20Sopenharmony_ci if (arm != -1U) 6658c2ecf20Sopenharmony_ci arm *= 2; 6668c2ecf20Sopenharmony_ci break; 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci return arm; 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci/* 6748c2ecf20Sopenharmony_ci****************************************************************************** 6758c2ecf20Sopenharmony_ci* 6768c2ecf20Sopenharmony_ci* This routine calculates the arm, span and block for the specified stripe and 6778c2ecf20Sopenharmony_ci* reference in stripe using spanset 6788c2ecf20Sopenharmony_ci* 6798c2ecf20Sopenharmony_ci* Inputs : 6808c2ecf20Sopenharmony_ci* 6818c2ecf20Sopenharmony_ci* ld - Logical drive number 6828c2ecf20Sopenharmony_ci* stripRow - Stripe number 6838c2ecf20Sopenharmony_ci* stripRef - Reference in stripe 6848c2ecf20Sopenharmony_ci* 6858c2ecf20Sopenharmony_ci* Outputs : 6868c2ecf20Sopenharmony_ci* 6878c2ecf20Sopenharmony_ci* span - Span number 6888c2ecf20Sopenharmony_ci* block - Absolute Block number in the physical disk 6898c2ecf20Sopenharmony_ci*/ 6908c2ecf20Sopenharmony_cistatic u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld, 6918c2ecf20Sopenharmony_ci u64 stripRow, u16 stripRef, struct IO_REQUEST_INFO *io_info, 6928c2ecf20Sopenharmony_ci struct RAID_CONTEXT *pRAID_Context, 6938c2ecf20Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *map) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 6968c2ecf20Sopenharmony_ci u32 pd, arRef, r1_alt_pd; 6978c2ecf20Sopenharmony_ci u8 physArm, span; 6988c2ecf20Sopenharmony_ci u64 row; 6998c2ecf20Sopenharmony_ci u8 retval = true; 7008c2ecf20Sopenharmony_ci u64 *pdBlock = &io_info->pdBlock; 7018c2ecf20Sopenharmony_ci __le16 *pDevHandle = &io_info->devHandle; 7028c2ecf20Sopenharmony_ci u8 *pPdInterface = &io_info->pd_interface; 7038c2ecf20Sopenharmony_ci u32 logArm, rowMod, armQ, arm; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci *pDevHandle = cpu_to_le16(MR_DEVHANDLE_INVALID); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci /*Get row and span from io_info for Uneven Span IO.*/ 7088c2ecf20Sopenharmony_ci row = io_info->start_row; 7098c2ecf20Sopenharmony_ci span = io_info->start_span; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci if (raid->level == 6) { 7138c2ecf20Sopenharmony_ci logArm = get_arm_from_strip(instance, ld, stripRow, map); 7148c2ecf20Sopenharmony_ci if (logArm == -1U) 7158c2ecf20Sopenharmony_ci return false; 7168c2ecf20Sopenharmony_ci rowMod = mega_mod64(row, SPAN_ROW_SIZE(map, ld, span)); 7178c2ecf20Sopenharmony_ci armQ = SPAN_ROW_SIZE(map, ld, span) - 1 - rowMod; 7188c2ecf20Sopenharmony_ci arm = armQ + 1 + logArm; 7198c2ecf20Sopenharmony_ci if (arm >= SPAN_ROW_SIZE(map, ld, span)) 7208c2ecf20Sopenharmony_ci arm -= SPAN_ROW_SIZE(map, ld, span); 7218c2ecf20Sopenharmony_ci physArm = (u8)arm; 7228c2ecf20Sopenharmony_ci } else 7238c2ecf20Sopenharmony_ci /* Calculate the arm */ 7248c2ecf20Sopenharmony_ci physArm = get_arm(instance, ld, span, stripRow, map); 7258c2ecf20Sopenharmony_ci if (physArm == 0xFF) 7268c2ecf20Sopenharmony_ci return false; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci arRef = MR_LdSpanArrayGet(ld, span, map); 7298c2ecf20Sopenharmony_ci pd = MR_ArPdGet(arRef, physArm, map); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci if (pd != MR_PD_INVALID) { 7328c2ecf20Sopenharmony_ci *pDevHandle = MR_PdDevHandleGet(pd, map); 7338c2ecf20Sopenharmony_ci *pPdInterface = MR_PdInterfaceTypeGet(pd, map); 7348c2ecf20Sopenharmony_ci /* get second pd also for raid 1/10 fast path writes*/ 7358c2ecf20Sopenharmony_ci if ((instance->adapter_type >= VENTURA_SERIES) && 7368c2ecf20Sopenharmony_ci (raid->level == 1) && 7378c2ecf20Sopenharmony_ci !io_info->isRead) { 7388c2ecf20Sopenharmony_ci r1_alt_pd = MR_ArPdGet(arRef, physArm + 1, map); 7398c2ecf20Sopenharmony_ci if (r1_alt_pd != MR_PD_INVALID) 7408c2ecf20Sopenharmony_ci io_info->r1_alt_dev_handle = 7418c2ecf20Sopenharmony_ci MR_PdDevHandleGet(r1_alt_pd, map); 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci } else { 7448c2ecf20Sopenharmony_ci if ((raid->level >= 5) && 7458c2ecf20Sopenharmony_ci ((instance->adapter_type == THUNDERBOLT_SERIES) || 7468c2ecf20Sopenharmony_ci ((instance->adapter_type == INVADER_SERIES) && 7478c2ecf20Sopenharmony_ci (raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))) 7488c2ecf20Sopenharmony_ci pRAID_Context->reg_lock_flags = REGION_TYPE_EXCLUSIVE; 7498c2ecf20Sopenharmony_ci else if (raid->level == 1) { 7508c2ecf20Sopenharmony_ci physArm = physArm + 1; 7518c2ecf20Sopenharmony_ci pd = MR_ArPdGet(arRef, physArm, map); 7528c2ecf20Sopenharmony_ci if (pd != MR_PD_INVALID) { 7538c2ecf20Sopenharmony_ci *pDevHandle = MR_PdDevHandleGet(pd, map); 7548c2ecf20Sopenharmony_ci *pPdInterface = MR_PdInterfaceTypeGet(pd, map); 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci *pdBlock += stripRef + le64_to_cpu(MR_LdSpanPtrGet(ld, span, map)->startBlk); 7608c2ecf20Sopenharmony_ci if (instance->adapter_type >= VENTURA_SERIES) { 7618c2ecf20Sopenharmony_ci ((struct RAID_CONTEXT_G35 *)pRAID_Context)->span_arm = 7628c2ecf20Sopenharmony_ci (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; 7638c2ecf20Sopenharmony_ci io_info->span_arm = 7648c2ecf20Sopenharmony_ci (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; 7658c2ecf20Sopenharmony_ci } else { 7668c2ecf20Sopenharmony_ci pRAID_Context->span_arm = 7678c2ecf20Sopenharmony_ci (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; 7688c2ecf20Sopenharmony_ci io_info->span_arm = pRAID_Context->span_arm; 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci io_info->pd_after_lb = pd; 7718c2ecf20Sopenharmony_ci return retval; 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci/* 7758c2ecf20Sopenharmony_ci****************************************************************************** 7768c2ecf20Sopenharmony_ci* 7778c2ecf20Sopenharmony_ci* This routine calculates the arm, span and block for the specified stripe and 7788c2ecf20Sopenharmony_ci* reference in stripe. 7798c2ecf20Sopenharmony_ci* 7808c2ecf20Sopenharmony_ci* Inputs : 7818c2ecf20Sopenharmony_ci* 7828c2ecf20Sopenharmony_ci* ld - Logical drive number 7838c2ecf20Sopenharmony_ci* stripRow - Stripe number 7848c2ecf20Sopenharmony_ci* stripRef - Reference in stripe 7858c2ecf20Sopenharmony_ci* 7868c2ecf20Sopenharmony_ci* Outputs : 7878c2ecf20Sopenharmony_ci* 7888c2ecf20Sopenharmony_ci* span - Span number 7898c2ecf20Sopenharmony_ci* block - Absolute Block number in the physical disk 7908c2ecf20Sopenharmony_ci*/ 7918c2ecf20Sopenharmony_cistatic u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow, 7928c2ecf20Sopenharmony_ci u16 stripRef, struct IO_REQUEST_INFO *io_info, 7938c2ecf20Sopenharmony_ci struct RAID_CONTEXT *pRAID_Context, 7948c2ecf20Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *map) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 7978c2ecf20Sopenharmony_ci u32 pd, arRef, r1_alt_pd; 7988c2ecf20Sopenharmony_ci u8 physArm, span; 7998c2ecf20Sopenharmony_ci u64 row; 8008c2ecf20Sopenharmony_ci u8 retval = true; 8018c2ecf20Sopenharmony_ci u64 *pdBlock = &io_info->pdBlock; 8028c2ecf20Sopenharmony_ci __le16 *pDevHandle = &io_info->devHandle; 8038c2ecf20Sopenharmony_ci u8 *pPdInterface = &io_info->pd_interface; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci *pDevHandle = cpu_to_le16(MR_DEVHANDLE_INVALID); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci row = mega_div64_32(stripRow, raid->rowDataSize); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci if (raid->level == 6) { 8108c2ecf20Sopenharmony_ci /* logical arm within row */ 8118c2ecf20Sopenharmony_ci u32 logArm = mega_mod64(stripRow, raid->rowDataSize); 8128c2ecf20Sopenharmony_ci u32 rowMod, armQ, arm; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci if (raid->rowSize == 0) 8158c2ecf20Sopenharmony_ci return false; 8168c2ecf20Sopenharmony_ci /* get logical row mod */ 8178c2ecf20Sopenharmony_ci rowMod = mega_mod64(row, raid->rowSize); 8188c2ecf20Sopenharmony_ci armQ = raid->rowSize-1-rowMod; /* index of Q drive */ 8198c2ecf20Sopenharmony_ci arm = armQ+1+logArm; /* data always logically follows Q */ 8208c2ecf20Sopenharmony_ci if (arm >= raid->rowSize) /* handle wrap condition */ 8218c2ecf20Sopenharmony_ci arm -= raid->rowSize; 8228c2ecf20Sopenharmony_ci physArm = (u8)arm; 8238c2ecf20Sopenharmony_ci } else { 8248c2ecf20Sopenharmony_ci if (raid->modFactor == 0) 8258c2ecf20Sopenharmony_ci return false; 8268c2ecf20Sopenharmony_ci physArm = MR_LdDataArmGet(ld, mega_mod64(stripRow, 8278c2ecf20Sopenharmony_ci raid->modFactor), 8288c2ecf20Sopenharmony_ci map); 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci if (raid->spanDepth == 1) { 8328c2ecf20Sopenharmony_ci span = 0; 8338c2ecf20Sopenharmony_ci *pdBlock = row << raid->stripeShift; 8348c2ecf20Sopenharmony_ci } else { 8358c2ecf20Sopenharmony_ci span = (u8)MR_GetSpanBlock(ld, row, pdBlock, map); 8368c2ecf20Sopenharmony_ci if (span == SPAN_INVALID) 8378c2ecf20Sopenharmony_ci return false; 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci /* Get the array on which this span is present */ 8418c2ecf20Sopenharmony_ci arRef = MR_LdSpanArrayGet(ld, span, map); 8428c2ecf20Sopenharmony_ci pd = MR_ArPdGet(arRef, physArm, map); /* Get the pd */ 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci if (pd != MR_PD_INVALID) { 8458c2ecf20Sopenharmony_ci /* Get dev handle from Pd. */ 8468c2ecf20Sopenharmony_ci *pDevHandle = MR_PdDevHandleGet(pd, map); 8478c2ecf20Sopenharmony_ci *pPdInterface = MR_PdInterfaceTypeGet(pd, map); 8488c2ecf20Sopenharmony_ci /* get second pd also for raid 1/10 fast path writes*/ 8498c2ecf20Sopenharmony_ci if ((instance->adapter_type >= VENTURA_SERIES) && 8508c2ecf20Sopenharmony_ci (raid->level == 1) && 8518c2ecf20Sopenharmony_ci !io_info->isRead) { 8528c2ecf20Sopenharmony_ci r1_alt_pd = MR_ArPdGet(arRef, physArm + 1, map); 8538c2ecf20Sopenharmony_ci if (r1_alt_pd != MR_PD_INVALID) 8548c2ecf20Sopenharmony_ci io_info->r1_alt_dev_handle = 8558c2ecf20Sopenharmony_ci MR_PdDevHandleGet(r1_alt_pd, map); 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci } else { 8588c2ecf20Sopenharmony_ci if ((raid->level >= 5) && 8598c2ecf20Sopenharmony_ci ((instance->adapter_type == THUNDERBOLT_SERIES) || 8608c2ecf20Sopenharmony_ci ((instance->adapter_type == INVADER_SERIES) && 8618c2ecf20Sopenharmony_ci (raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))) 8628c2ecf20Sopenharmony_ci pRAID_Context->reg_lock_flags = REGION_TYPE_EXCLUSIVE; 8638c2ecf20Sopenharmony_ci else if (raid->level == 1) { 8648c2ecf20Sopenharmony_ci /* Get alternate Pd. */ 8658c2ecf20Sopenharmony_ci physArm = physArm + 1; 8668c2ecf20Sopenharmony_ci pd = MR_ArPdGet(arRef, physArm, map); 8678c2ecf20Sopenharmony_ci if (pd != MR_PD_INVALID) { 8688c2ecf20Sopenharmony_ci /* Get dev handle from Pd */ 8698c2ecf20Sopenharmony_ci *pDevHandle = MR_PdDevHandleGet(pd, map); 8708c2ecf20Sopenharmony_ci *pPdInterface = MR_PdInterfaceTypeGet(pd, map); 8718c2ecf20Sopenharmony_ci } 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci *pdBlock += stripRef + le64_to_cpu(MR_LdSpanPtrGet(ld, span, map)->startBlk); 8768c2ecf20Sopenharmony_ci if (instance->adapter_type >= VENTURA_SERIES) { 8778c2ecf20Sopenharmony_ci ((struct RAID_CONTEXT_G35 *)pRAID_Context)->span_arm = 8788c2ecf20Sopenharmony_ci (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; 8798c2ecf20Sopenharmony_ci io_info->span_arm = 8808c2ecf20Sopenharmony_ci (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; 8818c2ecf20Sopenharmony_ci } else { 8828c2ecf20Sopenharmony_ci pRAID_Context->span_arm = 8838c2ecf20Sopenharmony_ci (span << RAID_CTX_SPANARM_SPAN_SHIFT) | physArm; 8848c2ecf20Sopenharmony_ci io_info->span_arm = pRAID_Context->span_arm; 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci io_info->pd_after_lb = pd; 8878c2ecf20Sopenharmony_ci return retval; 8888c2ecf20Sopenharmony_ci} 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci/* 8918c2ecf20Sopenharmony_ci * mr_get_phy_params_r56_rmw - Calculate parameters for R56 CTIO write operation 8928c2ecf20Sopenharmony_ci * @instance: Adapter soft state 8938c2ecf20Sopenharmony_ci * @ld: LD index 8948c2ecf20Sopenharmony_ci * @stripNo: Strip Number 8958c2ecf20Sopenharmony_ci * @io_info: IO info structure pointer 8968c2ecf20Sopenharmony_ci * pRAID_Context: RAID context pointer 8978c2ecf20Sopenharmony_ci * map: RAID map pointer 8988c2ecf20Sopenharmony_ci * 8998c2ecf20Sopenharmony_ci * This routine calculates the logical arm, data Arm, row number and parity arm 9008c2ecf20Sopenharmony_ci * for R56 CTIO write operation. 9018c2ecf20Sopenharmony_ci */ 9028c2ecf20Sopenharmony_cistatic void mr_get_phy_params_r56_rmw(struct megasas_instance *instance, 9038c2ecf20Sopenharmony_ci u32 ld, u64 stripNo, 9048c2ecf20Sopenharmony_ci struct IO_REQUEST_INFO *io_info, 9058c2ecf20Sopenharmony_ci struct RAID_CONTEXT_G35 *pRAID_Context, 9068c2ecf20Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *map) 9078c2ecf20Sopenharmony_ci{ 9088c2ecf20Sopenharmony_ci struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); 9098c2ecf20Sopenharmony_ci u8 span, dataArms, arms, dataArm, logArm; 9108c2ecf20Sopenharmony_ci s8 rightmostParityArm, PParityArm; 9118c2ecf20Sopenharmony_ci u64 rowNum; 9128c2ecf20Sopenharmony_ci u64 *pdBlock = &io_info->pdBlock; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci dataArms = raid->rowDataSize; 9158c2ecf20Sopenharmony_ci arms = raid->rowSize; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci rowNum = mega_div64_32(stripNo, dataArms); 9188c2ecf20Sopenharmony_ci /* parity disk arm, first arm is 0 */ 9198c2ecf20Sopenharmony_ci rightmostParityArm = (arms - 1) - mega_mod64(rowNum, arms); 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci /* logical arm within row */ 9228c2ecf20Sopenharmony_ci logArm = mega_mod64(stripNo, dataArms); 9238c2ecf20Sopenharmony_ci /* physical arm for data */ 9248c2ecf20Sopenharmony_ci dataArm = mega_mod64((rightmostParityArm + 1 + logArm), arms); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci if (raid->spanDepth == 1) { 9278c2ecf20Sopenharmony_ci span = 0; 9288c2ecf20Sopenharmony_ci } else { 9298c2ecf20Sopenharmony_ci span = (u8)MR_GetSpanBlock(ld, rowNum, pdBlock, map); 9308c2ecf20Sopenharmony_ci if (span == SPAN_INVALID) 9318c2ecf20Sopenharmony_ci return; 9328c2ecf20Sopenharmony_ci } 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci if (raid->level == 6) { 9358c2ecf20Sopenharmony_ci /* P Parity arm, note this can go negative adjust if negative */ 9368c2ecf20Sopenharmony_ci PParityArm = (arms - 2) - mega_mod64(rowNum, arms); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci if (PParityArm < 0) 9398c2ecf20Sopenharmony_ci PParityArm += arms; 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci /* rightmostParityArm is P-Parity for RAID 5 and Q-Parity for RAID */ 9428c2ecf20Sopenharmony_ci pRAID_Context->flow_specific.r56_arm_map = rightmostParityArm; 9438c2ecf20Sopenharmony_ci pRAID_Context->flow_specific.r56_arm_map |= 9448c2ecf20Sopenharmony_ci (u16)(PParityArm << RAID_CTX_R56_P_ARM_SHIFT); 9458c2ecf20Sopenharmony_ci } else { 9468c2ecf20Sopenharmony_ci pRAID_Context->flow_specific.r56_arm_map |= 9478c2ecf20Sopenharmony_ci (u16)(rightmostParityArm << RAID_CTX_R56_P_ARM_SHIFT); 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci pRAID_Context->reg_lock_row_lba = cpu_to_le64(rowNum); 9518c2ecf20Sopenharmony_ci pRAID_Context->flow_specific.r56_arm_map |= 9528c2ecf20Sopenharmony_ci (u16)(logArm << RAID_CTX_R56_LOG_ARM_SHIFT); 9538c2ecf20Sopenharmony_ci cpu_to_le16s(&pRAID_Context->flow_specific.r56_arm_map); 9548c2ecf20Sopenharmony_ci pRAID_Context->span_arm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | dataArm; 9558c2ecf20Sopenharmony_ci pRAID_Context->raid_flags = (MR_RAID_FLAGS_IO_SUB_TYPE_R56_DIV_OFFLOAD << 9568c2ecf20Sopenharmony_ci MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT); 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci return; 9598c2ecf20Sopenharmony_ci} 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci/* 9628c2ecf20Sopenharmony_ci****************************************************************************** 9638c2ecf20Sopenharmony_ci* 9648c2ecf20Sopenharmony_ci* MR_BuildRaidContext function 9658c2ecf20Sopenharmony_ci* 9668c2ecf20Sopenharmony_ci* This function will initiate command processing. The start/end row and strip 9678c2ecf20Sopenharmony_ci* information is calculated then the lock is acquired. 9688c2ecf20Sopenharmony_ci* This function will return 0 if region lock was acquired OR return num strips 9698c2ecf20Sopenharmony_ci*/ 9708c2ecf20Sopenharmony_ciu8 9718c2ecf20Sopenharmony_ciMR_BuildRaidContext(struct megasas_instance *instance, 9728c2ecf20Sopenharmony_ci struct IO_REQUEST_INFO *io_info, 9738c2ecf20Sopenharmony_ci struct RAID_CONTEXT *pRAID_Context, 9748c2ecf20Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *map, u8 **raidLUN) 9758c2ecf20Sopenharmony_ci{ 9768c2ecf20Sopenharmony_ci struct fusion_context *fusion; 9778c2ecf20Sopenharmony_ci struct MR_LD_RAID *raid; 9788c2ecf20Sopenharmony_ci u32 stripSize, stripe_mask; 9798c2ecf20Sopenharmony_ci u64 endLba, endStrip, endRow, start_row, start_strip; 9808c2ecf20Sopenharmony_ci u64 regStart; 9818c2ecf20Sopenharmony_ci u32 regSize; 9828c2ecf20Sopenharmony_ci u8 num_strips, numRows; 9838c2ecf20Sopenharmony_ci u16 ref_in_start_stripe, ref_in_end_stripe; 9848c2ecf20Sopenharmony_ci u64 ldStartBlock; 9858c2ecf20Sopenharmony_ci u32 numBlocks, ldTgtId; 9868c2ecf20Sopenharmony_ci u8 isRead; 9878c2ecf20Sopenharmony_ci u8 retval = 0; 9888c2ecf20Sopenharmony_ci u8 startlba_span = SPAN_INVALID; 9898c2ecf20Sopenharmony_ci u64 *pdBlock = &io_info->pdBlock; 9908c2ecf20Sopenharmony_ci u16 ld; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci ldStartBlock = io_info->ldStartBlock; 9938c2ecf20Sopenharmony_ci numBlocks = io_info->numBlocks; 9948c2ecf20Sopenharmony_ci ldTgtId = io_info->ldTgtId; 9958c2ecf20Sopenharmony_ci isRead = io_info->isRead; 9968c2ecf20Sopenharmony_ci io_info->IoforUnevenSpan = 0; 9978c2ecf20Sopenharmony_ci io_info->start_span = SPAN_INVALID; 9988c2ecf20Sopenharmony_ci fusion = instance->ctrl_context; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci ld = MR_TargetIdToLdGet(ldTgtId, map); 10018c2ecf20Sopenharmony_ci raid = MR_LdRaidGet(ld, map); 10028c2ecf20Sopenharmony_ci /*check read ahead bit*/ 10038c2ecf20Sopenharmony_ci io_info->ra_capable = raid->capability.ra_capable; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci /* 10068c2ecf20Sopenharmony_ci * if rowDataSize @RAID map and spanRowDataSize @SPAN INFO are zero 10078c2ecf20Sopenharmony_ci * return FALSE 10088c2ecf20Sopenharmony_ci */ 10098c2ecf20Sopenharmony_ci if (raid->rowDataSize == 0) { 10108c2ecf20Sopenharmony_ci if (MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize == 0) 10118c2ecf20Sopenharmony_ci return false; 10128c2ecf20Sopenharmony_ci else if (instance->UnevenSpanSupport) { 10138c2ecf20Sopenharmony_ci io_info->IoforUnevenSpan = 1; 10148c2ecf20Sopenharmony_ci } else { 10158c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, 10168c2ecf20Sopenharmony_ci "raid->rowDataSize is 0, but has SPAN[0]" 10178c2ecf20Sopenharmony_ci "rowDataSize = 0x%0x," 10188c2ecf20Sopenharmony_ci "but there is _NO_ UnevenSpanSupport\n", 10198c2ecf20Sopenharmony_ci MR_LdSpanPtrGet(ld, 0, map)->spanRowDataSize); 10208c2ecf20Sopenharmony_ci return false; 10218c2ecf20Sopenharmony_ci } 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci stripSize = 1 << raid->stripeShift; 10258c2ecf20Sopenharmony_ci stripe_mask = stripSize-1; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci io_info->data_arms = raid->rowDataSize; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci /* 10308c2ecf20Sopenharmony_ci * calculate starting row and stripe, and number of strips and rows 10318c2ecf20Sopenharmony_ci */ 10328c2ecf20Sopenharmony_ci start_strip = ldStartBlock >> raid->stripeShift; 10338c2ecf20Sopenharmony_ci ref_in_start_stripe = (u16)(ldStartBlock & stripe_mask); 10348c2ecf20Sopenharmony_ci endLba = ldStartBlock + numBlocks - 1; 10358c2ecf20Sopenharmony_ci ref_in_end_stripe = (u16)(endLba & stripe_mask); 10368c2ecf20Sopenharmony_ci endStrip = endLba >> raid->stripeShift; 10378c2ecf20Sopenharmony_ci num_strips = (u8)(endStrip - start_strip + 1); /* End strip */ 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci if (io_info->IoforUnevenSpan) { 10408c2ecf20Sopenharmony_ci start_row = get_row_from_strip(instance, ld, start_strip, map); 10418c2ecf20Sopenharmony_ci endRow = get_row_from_strip(instance, ld, endStrip, map); 10428c2ecf20Sopenharmony_ci if (start_row == -1ULL || endRow == -1ULL) { 10438c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "return from %s %d." 10448c2ecf20Sopenharmony_ci "Send IO w/o region lock.\n", 10458c2ecf20Sopenharmony_ci __func__, __LINE__); 10468c2ecf20Sopenharmony_ci return false; 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci if (raid->spanDepth == 1) { 10508c2ecf20Sopenharmony_ci startlba_span = 0; 10518c2ecf20Sopenharmony_ci *pdBlock = start_row << raid->stripeShift; 10528c2ecf20Sopenharmony_ci } else 10538c2ecf20Sopenharmony_ci startlba_span = (u8)mr_spanset_get_span_block(instance, 10548c2ecf20Sopenharmony_ci ld, start_row, pdBlock, map); 10558c2ecf20Sopenharmony_ci if (startlba_span == SPAN_INVALID) { 10568c2ecf20Sopenharmony_ci dev_info(&instance->pdev->dev, "return from %s %d" 10578c2ecf20Sopenharmony_ci "for row 0x%llx,start strip %llx" 10588c2ecf20Sopenharmony_ci "endSrip %llx\n", __func__, __LINE__, 10598c2ecf20Sopenharmony_ci (unsigned long long)start_row, 10608c2ecf20Sopenharmony_ci (unsigned long long)start_strip, 10618c2ecf20Sopenharmony_ci (unsigned long long)endStrip); 10628c2ecf20Sopenharmony_ci return false; 10638c2ecf20Sopenharmony_ci } 10648c2ecf20Sopenharmony_ci io_info->start_span = startlba_span; 10658c2ecf20Sopenharmony_ci io_info->start_row = start_row; 10668c2ecf20Sopenharmony_ci } else { 10678c2ecf20Sopenharmony_ci start_row = mega_div64_32(start_strip, raid->rowDataSize); 10688c2ecf20Sopenharmony_ci endRow = mega_div64_32(endStrip, raid->rowDataSize); 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci numRows = (u8)(endRow - start_row + 1); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci /* 10738c2ecf20Sopenharmony_ci * calculate region info. 10748c2ecf20Sopenharmony_ci */ 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci /* assume region is at the start of the first row */ 10778c2ecf20Sopenharmony_ci regStart = start_row << raid->stripeShift; 10788c2ecf20Sopenharmony_ci /* assume this IO needs the full row - we'll adjust if not true */ 10798c2ecf20Sopenharmony_ci regSize = stripSize; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci io_info->do_fp_rlbypass = raid->capability.fpBypassRegionLock; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci /* Check if we can send this I/O via FastPath */ 10848c2ecf20Sopenharmony_ci if (raid->capability.fpCapable) { 10858c2ecf20Sopenharmony_ci if (isRead) 10868c2ecf20Sopenharmony_ci io_info->fpOkForIo = (raid->capability.fpReadCapable && 10878c2ecf20Sopenharmony_ci ((num_strips == 1) || 10888c2ecf20Sopenharmony_ci raid->capability. 10898c2ecf20Sopenharmony_ci fpReadAcrossStripe)); 10908c2ecf20Sopenharmony_ci else 10918c2ecf20Sopenharmony_ci io_info->fpOkForIo = (raid->capability.fpWriteCapable && 10928c2ecf20Sopenharmony_ci ((num_strips == 1) || 10938c2ecf20Sopenharmony_ci raid->capability. 10948c2ecf20Sopenharmony_ci fpWriteAcrossStripe)); 10958c2ecf20Sopenharmony_ci } else 10968c2ecf20Sopenharmony_ci io_info->fpOkForIo = false; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci if (numRows == 1) { 10998c2ecf20Sopenharmony_ci /* single-strip IOs can always lock only the data needed */ 11008c2ecf20Sopenharmony_ci if (num_strips == 1) { 11018c2ecf20Sopenharmony_ci regStart += ref_in_start_stripe; 11028c2ecf20Sopenharmony_ci regSize = numBlocks; 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci /* multi-strip IOs always need to full stripe locked */ 11058c2ecf20Sopenharmony_ci } else if (io_info->IoforUnevenSpan == 0) { 11068c2ecf20Sopenharmony_ci /* 11078c2ecf20Sopenharmony_ci * For Even span region lock optimization. 11088c2ecf20Sopenharmony_ci * If the start strip is the last in the start row 11098c2ecf20Sopenharmony_ci */ 11108c2ecf20Sopenharmony_ci if (start_strip == (start_row + 1) * raid->rowDataSize - 1) { 11118c2ecf20Sopenharmony_ci regStart += ref_in_start_stripe; 11128c2ecf20Sopenharmony_ci /* initialize count to sectors from startref to end 11138c2ecf20Sopenharmony_ci of strip */ 11148c2ecf20Sopenharmony_ci regSize = stripSize - ref_in_start_stripe; 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci /* add complete rows in the middle of the transfer */ 11188c2ecf20Sopenharmony_ci if (numRows > 2) 11198c2ecf20Sopenharmony_ci regSize += (numRows-2) << raid->stripeShift; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci /* if IO ends within first strip of last row*/ 11228c2ecf20Sopenharmony_ci if (endStrip == endRow*raid->rowDataSize) 11238c2ecf20Sopenharmony_ci regSize += ref_in_end_stripe+1; 11248c2ecf20Sopenharmony_ci else 11258c2ecf20Sopenharmony_ci regSize += stripSize; 11268c2ecf20Sopenharmony_ci } else { 11278c2ecf20Sopenharmony_ci /* 11288c2ecf20Sopenharmony_ci * For Uneven span region lock optimization. 11298c2ecf20Sopenharmony_ci * If the start strip is the last in the start row 11308c2ecf20Sopenharmony_ci */ 11318c2ecf20Sopenharmony_ci if (start_strip == (get_strip_from_row(instance, ld, start_row, map) + 11328c2ecf20Sopenharmony_ci SPAN_ROW_DATA_SIZE(map, ld, startlba_span) - 1)) { 11338c2ecf20Sopenharmony_ci regStart += ref_in_start_stripe; 11348c2ecf20Sopenharmony_ci /* initialize count to sectors from 11358c2ecf20Sopenharmony_ci * startRef to end of strip 11368c2ecf20Sopenharmony_ci */ 11378c2ecf20Sopenharmony_ci regSize = stripSize - ref_in_start_stripe; 11388c2ecf20Sopenharmony_ci } 11398c2ecf20Sopenharmony_ci /* Add complete rows in the middle of the transfer*/ 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci if (numRows > 2) 11428c2ecf20Sopenharmony_ci /* Add complete rows in the middle of the transfer*/ 11438c2ecf20Sopenharmony_ci regSize += (numRows-2) << raid->stripeShift; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci /* if IO ends within first strip of last row */ 11468c2ecf20Sopenharmony_ci if (endStrip == get_strip_from_row(instance, ld, endRow, map)) 11478c2ecf20Sopenharmony_ci regSize += ref_in_end_stripe + 1; 11488c2ecf20Sopenharmony_ci else 11498c2ecf20Sopenharmony_ci regSize += stripSize; 11508c2ecf20Sopenharmony_ci } 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci pRAID_Context->timeout_value = 11538c2ecf20Sopenharmony_ci cpu_to_le16(raid->fpIoTimeoutForLd ? 11548c2ecf20Sopenharmony_ci raid->fpIoTimeoutForLd : 11558c2ecf20Sopenharmony_ci map->raidMap.fpPdIoTimeoutSec); 11568c2ecf20Sopenharmony_ci if (instance->adapter_type == INVADER_SERIES) 11578c2ecf20Sopenharmony_ci pRAID_Context->reg_lock_flags = (isRead) ? 11588c2ecf20Sopenharmony_ci raid->regTypeReqOnRead : raid->regTypeReqOnWrite; 11598c2ecf20Sopenharmony_ci else if (instance->adapter_type == THUNDERBOLT_SERIES) 11608c2ecf20Sopenharmony_ci pRAID_Context->reg_lock_flags = (isRead) ? 11618c2ecf20Sopenharmony_ci REGION_TYPE_SHARED_READ : raid->regTypeReqOnWrite; 11628c2ecf20Sopenharmony_ci pRAID_Context->virtual_disk_tgt_id = raid->targetId; 11638c2ecf20Sopenharmony_ci pRAID_Context->reg_lock_row_lba = cpu_to_le64(regStart); 11648c2ecf20Sopenharmony_ci pRAID_Context->reg_lock_length = cpu_to_le32(regSize); 11658c2ecf20Sopenharmony_ci pRAID_Context->config_seq_num = raid->seqNum; 11668c2ecf20Sopenharmony_ci /* save pointer to raid->LUN array */ 11678c2ecf20Sopenharmony_ci *raidLUN = raid->LUN; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci /* Aero R5/6 Division Offload for WRITE */ 11708c2ecf20Sopenharmony_ci if (fusion->r56_div_offload && (raid->level >= 5) && !isRead) { 11718c2ecf20Sopenharmony_ci mr_get_phy_params_r56_rmw(instance, ld, start_strip, io_info, 11728c2ecf20Sopenharmony_ci (struct RAID_CONTEXT_G35 *)pRAID_Context, 11738c2ecf20Sopenharmony_ci map); 11748c2ecf20Sopenharmony_ci return true; 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci /*Get Phy Params only if FP capable, or else leave it to MR firmware 11788c2ecf20Sopenharmony_ci to do the calculation.*/ 11798c2ecf20Sopenharmony_ci if (io_info->fpOkForIo) { 11808c2ecf20Sopenharmony_ci retval = io_info->IoforUnevenSpan ? 11818c2ecf20Sopenharmony_ci mr_spanset_get_phy_params(instance, ld, 11828c2ecf20Sopenharmony_ci start_strip, ref_in_start_stripe, 11838c2ecf20Sopenharmony_ci io_info, pRAID_Context, map) : 11848c2ecf20Sopenharmony_ci MR_GetPhyParams(instance, ld, start_strip, 11858c2ecf20Sopenharmony_ci ref_in_start_stripe, io_info, 11868c2ecf20Sopenharmony_ci pRAID_Context, map); 11878c2ecf20Sopenharmony_ci /* If IO on an invalid Pd, then FP is not possible.*/ 11888c2ecf20Sopenharmony_ci if (io_info->devHandle == MR_DEVHANDLE_INVALID) 11898c2ecf20Sopenharmony_ci io_info->fpOkForIo = false; 11908c2ecf20Sopenharmony_ci return retval; 11918c2ecf20Sopenharmony_ci } else if (isRead) { 11928c2ecf20Sopenharmony_ci uint stripIdx; 11938c2ecf20Sopenharmony_ci for (stripIdx = 0; stripIdx < num_strips; stripIdx++) { 11948c2ecf20Sopenharmony_ci retval = io_info->IoforUnevenSpan ? 11958c2ecf20Sopenharmony_ci mr_spanset_get_phy_params(instance, ld, 11968c2ecf20Sopenharmony_ci start_strip + stripIdx, 11978c2ecf20Sopenharmony_ci ref_in_start_stripe, io_info, 11988c2ecf20Sopenharmony_ci pRAID_Context, map) : 11998c2ecf20Sopenharmony_ci MR_GetPhyParams(instance, ld, 12008c2ecf20Sopenharmony_ci start_strip + stripIdx, ref_in_start_stripe, 12018c2ecf20Sopenharmony_ci io_info, pRAID_Context, map); 12028c2ecf20Sopenharmony_ci if (!retval) 12038c2ecf20Sopenharmony_ci return true; 12048c2ecf20Sopenharmony_ci } 12058c2ecf20Sopenharmony_ci } 12068c2ecf20Sopenharmony_ci return true; 12078c2ecf20Sopenharmony_ci} 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci/* 12108c2ecf20Sopenharmony_ci****************************************************************************** 12118c2ecf20Sopenharmony_ci* 12128c2ecf20Sopenharmony_ci* This routine pepare spanset info from Valid Raid map and store it into 12138c2ecf20Sopenharmony_ci* local copy of ldSpanInfo per instance data structure. 12148c2ecf20Sopenharmony_ci* 12158c2ecf20Sopenharmony_ci* Inputs : 12168c2ecf20Sopenharmony_ci* map - LD map 12178c2ecf20Sopenharmony_ci* ldSpanInfo - ldSpanInfo per HBA instance 12188c2ecf20Sopenharmony_ci* 12198c2ecf20Sopenharmony_ci*/ 12208c2ecf20Sopenharmony_civoid mr_update_span_set(struct MR_DRV_RAID_MAP_ALL *map, 12218c2ecf20Sopenharmony_ci PLD_SPAN_INFO ldSpanInfo) 12228c2ecf20Sopenharmony_ci{ 12238c2ecf20Sopenharmony_ci u8 span, count; 12248c2ecf20Sopenharmony_ci u32 element, span_row_width; 12258c2ecf20Sopenharmony_ci u64 span_row; 12268c2ecf20Sopenharmony_ci struct MR_LD_RAID *raid; 12278c2ecf20Sopenharmony_ci LD_SPAN_SET *span_set, *span_set_prev; 12288c2ecf20Sopenharmony_ci struct MR_QUAD_ELEMENT *quad; 12298c2ecf20Sopenharmony_ci int ldCount; 12308c2ecf20Sopenharmony_ci u16 ld; 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES_EXT; ldCount++) { 12348c2ecf20Sopenharmony_ci ld = MR_TargetIdToLdGet(ldCount, map); 12358c2ecf20Sopenharmony_ci if (ld >= (MAX_LOGICAL_DRIVES_EXT - 1)) 12368c2ecf20Sopenharmony_ci continue; 12378c2ecf20Sopenharmony_ci raid = MR_LdRaidGet(ld, map); 12388c2ecf20Sopenharmony_ci for (element = 0; element < MAX_QUAD_DEPTH; element++) { 12398c2ecf20Sopenharmony_ci for (span = 0; span < raid->spanDepth; span++) { 12408c2ecf20Sopenharmony_ci if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span]. 12418c2ecf20Sopenharmony_ci block_span_info.noElements) < 12428c2ecf20Sopenharmony_ci element + 1) 12438c2ecf20Sopenharmony_ci continue; 12448c2ecf20Sopenharmony_ci span_set = &(ldSpanInfo[ld].span_set[element]); 12458c2ecf20Sopenharmony_ci quad = &map->raidMap.ldSpanMap[ld]. 12468c2ecf20Sopenharmony_ci spanBlock[span].block_span_info. 12478c2ecf20Sopenharmony_ci quad[element]; 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci span_set->diff = le32_to_cpu(quad->diff); 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci for (count = 0, span_row_width = 0; 12528c2ecf20Sopenharmony_ci count < raid->spanDepth; count++) { 12538c2ecf20Sopenharmony_ci if (le32_to_cpu(map->raidMap.ldSpanMap[ld]. 12548c2ecf20Sopenharmony_ci spanBlock[count]. 12558c2ecf20Sopenharmony_ci block_span_info. 12568c2ecf20Sopenharmony_ci noElements) >= element + 1) { 12578c2ecf20Sopenharmony_ci span_set->strip_offset[count] = 12588c2ecf20Sopenharmony_ci span_row_width; 12598c2ecf20Sopenharmony_ci span_row_width += 12608c2ecf20Sopenharmony_ci MR_LdSpanPtrGet 12618c2ecf20Sopenharmony_ci (ld, count, map)->spanRowDataSize; 12628c2ecf20Sopenharmony_ci } 12638c2ecf20Sopenharmony_ci } 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci span_set->span_row_data_width = span_row_width; 12668c2ecf20Sopenharmony_ci span_row = mega_div64_32(((le64_to_cpu(quad->logEnd) - 12678c2ecf20Sopenharmony_ci le64_to_cpu(quad->logStart)) + le32_to_cpu(quad->diff)), 12688c2ecf20Sopenharmony_ci le32_to_cpu(quad->diff)); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci if (element == 0) { 12718c2ecf20Sopenharmony_ci span_set->log_start_lba = 0; 12728c2ecf20Sopenharmony_ci span_set->log_end_lba = 12738c2ecf20Sopenharmony_ci ((span_row << raid->stripeShift) 12748c2ecf20Sopenharmony_ci * span_row_width) - 1; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci span_set->span_row_start = 0; 12778c2ecf20Sopenharmony_ci span_set->span_row_end = span_row - 1; 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci span_set->data_strip_start = 0; 12808c2ecf20Sopenharmony_ci span_set->data_strip_end = 12818c2ecf20Sopenharmony_ci (span_row * span_row_width) - 1; 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci span_set->data_row_start = 0; 12848c2ecf20Sopenharmony_ci span_set->data_row_end = 12858c2ecf20Sopenharmony_ci (span_row * le32_to_cpu(quad->diff)) - 1; 12868c2ecf20Sopenharmony_ci } else { 12878c2ecf20Sopenharmony_ci span_set_prev = &(ldSpanInfo[ld]. 12888c2ecf20Sopenharmony_ci span_set[element - 1]); 12898c2ecf20Sopenharmony_ci span_set->log_start_lba = 12908c2ecf20Sopenharmony_ci span_set_prev->log_end_lba + 1; 12918c2ecf20Sopenharmony_ci span_set->log_end_lba = 12928c2ecf20Sopenharmony_ci span_set->log_start_lba + 12938c2ecf20Sopenharmony_ci ((span_row << raid->stripeShift) 12948c2ecf20Sopenharmony_ci * span_row_width) - 1; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci span_set->span_row_start = 12978c2ecf20Sopenharmony_ci span_set_prev->span_row_end + 1; 12988c2ecf20Sopenharmony_ci span_set->span_row_end = 12998c2ecf20Sopenharmony_ci span_set->span_row_start + span_row - 1; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci span_set->data_strip_start = 13028c2ecf20Sopenharmony_ci span_set_prev->data_strip_end + 1; 13038c2ecf20Sopenharmony_ci span_set->data_strip_end = 13048c2ecf20Sopenharmony_ci span_set->data_strip_start + 13058c2ecf20Sopenharmony_ci (span_row * span_row_width) - 1; 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci span_set->data_row_start = 13088c2ecf20Sopenharmony_ci span_set_prev->data_row_end + 1; 13098c2ecf20Sopenharmony_ci span_set->data_row_end = 13108c2ecf20Sopenharmony_ci span_set->data_row_start + 13118c2ecf20Sopenharmony_ci (span_row * le32_to_cpu(quad->diff)) - 1; 13128c2ecf20Sopenharmony_ci } 13138c2ecf20Sopenharmony_ci break; 13148c2ecf20Sopenharmony_ci } 13158c2ecf20Sopenharmony_ci if (span == raid->spanDepth) 13168c2ecf20Sopenharmony_ci break; 13178c2ecf20Sopenharmony_ci } 13188c2ecf20Sopenharmony_ci } 13198c2ecf20Sopenharmony_ci} 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_civoid mr_update_load_balance_params(struct MR_DRV_RAID_MAP_ALL *drv_map, 13228c2ecf20Sopenharmony_ci struct LD_LOAD_BALANCE_INFO *lbInfo) 13238c2ecf20Sopenharmony_ci{ 13248c2ecf20Sopenharmony_ci int ldCount; 13258c2ecf20Sopenharmony_ci u16 ld; 13268c2ecf20Sopenharmony_ci struct MR_LD_RAID *raid; 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci if (lb_pending_cmds > 128 || lb_pending_cmds < 1) 13298c2ecf20Sopenharmony_ci lb_pending_cmds = LB_PENDING_CMDS_DEFAULT; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES_EXT; ldCount++) { 13328c2ecf20Sopenharmony_ci ld = MR_TargetIdToLdGet(ldCount, drv_map); 13338c2ecf20Sopenharmony_ci if (ld >= MAX_LOGICAL_DRIVES_EXT - 1) { 13348c2ecf20Sopenharmony_ci lbInfo[ldCount].loadBalanceFlag = 0; 13358c2ecf20Sopenharmony_ci continue; 13368c2ecf20Sopenharmony_ci } 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci raid = MR_LdRaidGet(ld, drv_map); 13398c2ecf20Sopenharmony_ci if ((raid->level != 1) || 13408c2ecf20Sopenharmony_ci (raid->ldState != MR_LD_STATE_OPTIMAL)) { 13418c2ecf20Sopenharmony_ci lbInfo[ldCount].loadBalanceFlag = 0; 13428c2ecf20Sopenharmony_ci continue; 13438c2ecf20Sopenharmony_ci } 13448c2ecf20Sopenharmony_ci lbInfo[ldCount].loadBalanceFlag = 1; 13458c2ecf20Sopenharmony_ci } 13468c2ecf20Sopenharmony_ci} 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_cistatic u8 megasas_get_best_arm_pd(struct megasas_instance *instance, 13498c2ecf20Sopenharmony_ci struct LD_LOAD_BALANCE_INFO *lbInfo, 13508c2ecf20Sopenharmony_ci struct IO_REQUEST_INFO *io_info, 13518c2ecf20Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *drv_map) 13528c2ecf20Sopenharmony_ci{ 13538c2ecf20Sopenharmony_ci struct MR_LD_RAID *raid; 13548c2ecf20Sopenharmony_ci u16 pd1_dev_handle; 13558c2ecf20Sopenharmony_ci u16 pend0, pend1, ld; 13568c2ecf20Sopenharmony_ci u64 diff0, diff1; 13578c2ecf20Sopenharmony_ci u8 bestArm, pd0, pd1, span, arm; 13588c2ecf20Sopenharmony_ci u32 arRef, span_row_size; 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci u64 block = io_info->ldStartBlock; 13618c2ecf20Sopenharmony_ci u32 count = io_info->numBlocks; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci span = ((io_info->span_arm & RAID_CTX_SPANARM_SPAN_MASK) 13648c2ecf20Sopenharmony_ci >> RAID_CTX_SPANARM_SPAN_SHIFT); 13658c2ecf20Sopenharmony_ci arm = (io_info->span_arm & RAID_CTX_SPANARM_ARM_MASK); 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci ld = MR_TargetIdToLdGet(io_info->ldTgtId, drv_map); 13688c2ecf20Sopenharmony_ci raid = MR_LdRaidGet(ld, drv_map); 13698c2ecf20Sopenharmony_ci span_row_size = instance->UnevenSpanSupport ? 13708c2ecf20Sopenharmony_ci SPAN_ROW_SIZE(drv_map, ld, span) : raid->rowSize; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci arRef = MR_LdSpanArrayGet(ld, span, drv_map); 13738c2ecf20Sopenharmony_ci pd0 = MR_ArPdGet(arRef, arm, drv_map); 13748c2ecf20Sopenharmony_ci pd1 = MR_ArPdGet(arRef, (arm + 1) >= span_row_size ? 13758c2ecf20Sopenharmony_ci (arm + 1 - span_row_size) : arm + 1, drv_map); 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci /* Get PD1 Dev Handle */ 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci pd1_dev_handle = MR_PdDevHandleGet(pd1, drv_map); 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci if (pd1_dev_handle == MR_DEVHANDLE_INVALID) { 13828c2ecf20Sopenharmony_ci bestArm = arm; 13838c2ecf20Sopenharmony_ci } else { 13848c2ecf20Sopenharmony_ci /* get the pending cmds for the data and mirror arms */ 13858c2ecf20Sopenharmony_ci pend0 = atomic_read(&lbInfo->scsi_pending_cmds[pd0]); 13868c2ecf20Sopenharmony_ci pend1 = atomic_read(&lbInfo->scsi_pending_cmds[pd1]); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci /* Determine the disk whose head is nearer to the req. block */ 13898c2ecf20Sopenharmony_ci diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[pd0]); 13908c2ecf20Sopenharmony_ci diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[pd1]); 13918c2ecf20Sopenharmony_ci bestArm = (diff0 <= diff1 ? arm : arm ^ 1); 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci /* Make balance count from 16 to 4 to 13948c2ecf20Sopenharmony_ci * keep driver in sync with Firmware 13958c2ecf20Sopenharmony_ci */ 13968c2ecf20Sopenharmony_ci if ((bestArm == arm && pend0 > pend1 + lb_pending_cmds) || 13978c2ecf20Sopenharmony_ci (bestArm != arm && pend1 > pend0 + lb_pending_cmds)) 13988c2ecf20Sopenharmony_ci bestArm ^= 1; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci /* Update the last accessed block on the correct pd */ 14018c2ecf20Sopenharmony_ci io_info->span_arm = 14028c2ecf20Sopenharmony_ci (span << RAID_CTX_SPANARM_SPAN_SHIFT) | bestArm; 14038c2ecf20Sopenharmony_ci io_info->pd_after_lb = (bestArm == arm) ? pd0 : pd1; 14048c2ecf20Sopenharmony_ci } 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci lbInfo->last_accessed_block[io_info->pd_after_lb] = block + count - 1; 14078c2ecf20Sopenharmony_ci return io_info->pd_after_lb; 14088c2ecf20Sopenharmony_ci} 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci__le16 get_updated_dev_handle(struct megasas_instance *instance, 14118c2ecf20Sopenharmony_ci struct LD_LOAD_BALANCE_INFO *lbInfo, 14128c2ecf20Sopenharmony_ci struct IO_REQUEST_INFO *io_info, 14138c2ecf20Sopenharmony_ci struct MR_DRV_RAID_MAP_ALL *drv_map) 14148c2ecf20Sopenharmony_ci{ 14158c2ecf20Sopenharmony_ci u8 arm_pd; 14168c2ecf20Sopenharmony_ci __le16 devHandle; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci /* get best new arm (PD ID) */ 14198c2ecf20Sopenharmony_ci arm_pd = megasas_get_best_arm_pd(instance, lbInfo, io_info, drv_map); 14208c2ecf20Sopenharmony_ci devHandle = MR_PdDevHandleGet(arm_pd, drv_map); 14218c2ecf20Sopenharmony_ci io_info->pd_interface = MR_PdInterfaceTypeGet(arm_pd, drv_map); 14228c2ecf20Sopenharmony_ci atomic_inc(&lbInfo->scsi_pending_cmds[arm_pd]); 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci return devHandle; 14258c2ecf20Sopenharmony_ci} 1426