18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * CXL Flash Device Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Written by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>, IBM Corporation 68c2ecf20Sopenharmony_ci * Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright (C) 2015 IBM Corporation 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/pci.h> 138c2ecf20Sopenharmony_ci#include <linux/syscalls.h> 148c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 158c2ecf20Sopenharmony_ci#include <asm/bitsperlong.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 188c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 198c2ecf20Sopenharmony_ci#include <uapi/scsi/cxlflash_ioctl.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "sislite.h" 228c2ecf20Sopenharmony_ci#include "common.h" 238c2ecf20Sopenharmony_ci#include "vlun.h" 248c2ecf20Sopenharmony_ci#include "superpipe.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/** 278c2ecf20Sopenharmony_ci * marshal_virt_to_resize() - translate uvirtual to resize structure 288c2ecf20Sopenharmony_ci * @virt: Source structure from which to translate/copy. 298c2ecf20Sopenharmony_ci * @resize: Destination structure for the translate/copy. 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_cistatic void marshal_virt_to_resize(struct dk_cxlflash_uvirtual *virt, 328c2ecf20Sopenharmony_ci struct dk_cxlflash_resize *resize) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci resize->hdr = virt->hdr; 358c2ecf20Sopenharmony_ci resize->context_id = virt->context_id; 368c2ecf20Sopenharmony_ci resize->rsrc_handle = virt->rsrc_handle; 378c2ecf20Sopenharmony_ci resize->req_size = virt->lun_size; 388c2ecf20Sopenharmony_ci resize->last_lba = virt->last_lba; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/** 428c2ecf20Sopenharmony_ci * marshal_clone_to_rele() - translate clone to release structure 438c2ecf20Sopenharmony_ci * @clone: Source structure from which to translate/copy. 448c2ecf20Sopenharmony_ci * @rele: Destination structure for the translate/copy. 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_cistatic void marshal_clone_to_rele(struct dk_cxlflash_clone *clone, 478c2ecf20Sopenharmony_ci struct dk_cxlflash_release *release) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci release->hdr = clone->hdr; 508c2ecf20Sopenharmony_ci release->context_id = clone->context_id_dst; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/** 548c2ecf20Sopenharmony_ci * ba_init() - initializes a block allocator 558c2ecf20Sopenharmony_ci * @ba_lun: Block allocator to initialize. 568c2ecf20Sopenharmony_ci * 578c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_cistatic int ba_init(struct ba_lun *ba_lun) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct ba_lun_info *bali = NULL; 628c2ecf20Sopenharmony_ci int lun_size_au = 0, i = 0; 638c2ecf20Sopenharmony_ci int last_word_underflow = 0; 648c2ecf20Sopenharmony_ci u64 *lam; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci pr_debug("%s: Initializing LUN: lun_id=%016llx " 678c2ecf20Sopenharmony_ci "ba_lun->lsize=%lx ba_lun->au_size=%lX\n", 688c2ecf20Sopenharmony_ci __func__, ba_lun->lun_id, ba_lun->lsize, ba_lun->au_size); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci /* Calculate bit map size */ 718c2ecf20Sopenharmony_ci lun_size_au = ba_lun->lsize / ba_lun->au_size; 728c2ecf20Sopenharmony_ci if (lun_size_au == 0) { 738c2ecf20Sopenharmony_ci pr_debug("%s: Requested LUN size of 0!\n", __func__); 748c2ecf20Sopenharmony_ci return -EINVAL; 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* Allocate lun information container */ 788c2ecf20Sopenharmony_ci bali = kzalloc(sizeof(struct ba_lun_info), GFP_KERNEL); 798c2ecf20Sopenharmony_ci if (unlikely(!bali)) { 808c2ecf20Sopenharmony_ci pr_err("%s: Failed to allocate lun_info lun_id=%016llx\n", 818c2ecf20Sopenharmony_ci __func__, ba_lun->lun_id); 828c2ecf20Sopenharmony_ci return -ENOMEM; 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci bali->total_aus = lun_size_au; 868c2ecf20Sopenharmony_ci bali->lun_bmap_size = lun_size_au / BITS_PER_LONG; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (lun_size_au % BITS_PER_LONG) 898c2ecf20Sopenharmony_ci bali->lun_bmap_size++; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci /* Allocate bitmap space */ 928c2ecf20Sopenharmony_ci bali->lun_alloc_map = kzalloc((bali->lun_bmap_size * sizeof(u64)), 938c2ecf20Sopenharmony_ci GFP_KERNEL); 948c2ecf20Sopenharmony_ci if (unlikely(!bali->lun_alloc_map)) { 958c2ecf20Sopenharmony_ci pr_err("%s: Failed to allocate lun allocation map: " 968c2ecf20Sopenharmony_ci "lun_id=%016llx\n", __func__, ba_lun->lun_id); 978c2ecf20Sopenharmony_ci kfree(bali); 988c2ecf20Sopenharmony_ci return -ENOMEM; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* Initialize the bit map size and set all bits to '1' */ 1028c2ecf20Sopenharmony_ci bali->free_aun_cnt = lun_size_au; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci for (i = 0; i < bali->lun_bmap_size; i++) 1058c2ecf20Sopenharmony_ci bali->lun_alloc_map[i] = 0xFFFFFFFFFFFFFFFFULL; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* If the last word not fully utilized, mark extra bits as allocated */ 1088c2ecf20Sopenharmony_ci last_word_underflow = (bali->lun_bmap_size * BITS_PER_LONG); 1098c2ecf20Sopenharmony_ci last_word_underflow -= bali->free_aun_cnt; 1108c2ecf20Sopenharmony_ci if (last_word_underflow > 0) { 1118c2ecf20Sopenharmony_ci lam = &bali->lun_alloc_map[bali->lun_bmap_size - 1]; 1128c2ecf20Sopenharmony_ci for (i = (HIBIT - last_word_underflow + 1); 1138c2ecf20Sopenharmony_ci i < BITS_PER_LONG; 1148c2ecf20Sopenharmony_ci i++) 1158c2ecf20Sopenharmony_ci clear_bit(i, (ulong *)lam); 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* Initialize high elevator index, low/curr already at 0 from kzalloc */ 1198c2ecf20Sopenharmony_ci bali->free_high_idx = bali->lun_bmap_size; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* Allocate clone map */ 1228c2ecf20Sopenharmony_ci bali->aun_clone_map = kzalloc((bali->total_aus * sizeof(u8)), 1238c2ecf20Sopenharmony_ci GFP_KERNEL); 1248c2ecf20Sopenharmony_ci if (unlikely(!bali->aun_clone_map)) { 1258c2ecf20Sopenharmony_ci pr_err("%s: Failed to allocate clone map: lun_id=%016llx\n", 1268c2ecf20Sopenharmony_ci __func__, ba_lun->lun_id); 1278c2ecf20Sopenharmony_ci kfree(bali->lun_alloc_map); 1288c2ecf20Sopenharmony_ci kfree(bali); 1298c2ecf20Sopenharmony_ci return -ENOMEM; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* Pass the allocated LUN info as a handle to the user */ 1338c2ecf20Sopenharmony_ci ba_lun->ba_lun_handle = bali; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci pr_debug("%s: Successfully initialized the LUN: " 1368c2ecf20Sopenharmony_ci "lun_id=%016llx bitmap size=%x, free_aun_cnt=%llx\n", 1378c2ecf20Sopenharmony_ci __func__, ba_lun->lun_id, bali->lun_bmap_size, 1388c2ecf20Sopenharmony_ci bali->free_aun_cnt); 1398c2ecf20Sopenharmony_ci return 0; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/** 1438c2ecf20Sopenharmony_ci * find_free_range() - locates a free bit within the block allocator 1448c2ecf20Sopenharmony_ci * @low: First word in block allocator to start search. 1458c2ecf20Sopenharmony_ci * @high: Last word in block allocator to search. 1468c2ecf20Sopenharmony_ci * @bali: LUN information structure owning the block allocator to search. 1478c2ecf20Sopenharmony_ci * @bit_word: Passes back the word in the block allocator owning the free bit. 1488c2ecf20Sopenharmony_ci * 1498c2ecf20Sopenharmony_ci * Return: The bit position within the passed back word, -1 on failure 1508c2ecf20Sopenharmony_ci */ 1518c2ecf20Sopenharmony_cistatic int find_free_range(u32 low, 1528c2ecf20Sopenharmony_ci u32 high, 1538c2ecf20Sopenharmony_ci struct ba_lun_info *bali, int *bit_word) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci int i; 1568c2ecf20Sopenharmony_ci u64 bit_pos = -1; 1578c2ecf20Sopenharmony_ci ulong *lam, num_bits; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci for (i = low; i < high; i++) 1608c2ecf20Sopenharmony_ci if (bali->lun_alloc_map[i] != 0) { 1618c2ecf20Sopenharmony_ci lam = (ulong *)&bali->lun_alloc_map[i]; 1628c2ecf20Sopenharmony_ci num_bits = (sizeof(*lam) * BITS_PER_BYTE); 1638c2ecf20Sopenharmony_ci bit_pos = find_first_bit(lam, num_bits); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci pr_devel("%s: Found free bit %llu in LUN " 1668c2ecf20Sopenharmony_ci "map entry %016llx at bitmap index = %d\n", 1678c2ecf20Sopenharmony_ci __func__, bit_pos, bali->lun_alloc_map[i], i); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci *bit_word = i; 1708c2ecf20Sopenharmony_ci bali->free_aun_cnt--; 1718c2ecf20Sopenharmony_ci clear_bit(bit_pos, lam); 1728c2ecf20Sopenharmony_ci break; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci return bit_pos; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci/** 1798c2ecf20Sopenharmony_ci * ba_alloc() - allocates a block from the block allocator 1808c2ecf20Sopenharmony_ci * @ba_lun: Block allocator from which to allocate a block. 1818c2ecf20Sopenharmony_ci * 1828c2ecf20Sopenharmony_ci * Return: The allocated block, -1 on failure 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_cistatic u64 ba_alloc(struct ba_lun *ba_lun) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci u64 bit_pos = -1; 1878c2ecf20Sopenharmony_ci int bit_word = 0; 1888c2ecf20Sopenharmony_ci struct ba_lun_info *bali = NULL; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci bali = ba_lun->ba_lun_handle; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci pr_debug("%s: Received block allocation request: " 1938c2ecf20Sopenharmony_ci "lun_id=%016llx free_aun_cnt=%llx\n", 1948c2ecf20Sopenharmony_ci __func__, ba_lun->lun_id, bali->free_aun_cnt); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (bali->free_aun_cnt == 0) { 1978c2ecf20Sopenharmony_ci pr_debug("%s: No space left on LUN: lun_id=%016llx\n", 1988c2ecf20Sopenharmony_ci __func__, ba_lun->lun_id); 1998c2ecf20Sopenharmony_ci return -1ULL; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* Search to find a free entry, curr->high then low->curr */ 2038c2ecf20Sopenharmony_ci bit_pos = find_free_range(bali->free_curr_idx, 2048c2ecf20Sopenharmony_ci bali->free_high_idx, bali, &bit_word); 2058c2ecf20Sopenharmony_ci if (bit_pos == -1) { 2068c2ecf20Sopenharmony_ci bit_pos = find_free_range(bali->free_low_idx, 2078c2ecf20Sopenharmony_ci bali->free_curr_idx, 2088c2ecf20Sopenharmony_ci bali, &bit_word); 2098c2ecf20Sopenharmony_ci if (bit_pos == -1) { 2108c2ecf20Sopenharmony_ci pr_debug("%s: Could not find an allocation unit on LUN:" 2118c2ecf20Sopenharmony_ci " lun_id=%016llx\n", __func__, ba_lun->lun_id); 2128c2ecf20Sopenharmony_ci return -1ULL; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* Update the free_curr_idx */ 2178c2ecf20Sopenharmony_ci if (bit_pos == HIBIT) 2188c2ecf20Sopenharmony_ci bali->free_curr_idx = bit_word + 1; 2198c2ecf20Sopenharmony_ci else 2208c2ecf20Sopenharmony_ci bali->free_curr_idx = bit_word; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci pr_debug("%s: Allocating AU number=%llx lun_id=%016llx " 2238c2ecf20Sopenharmony_ci "free_aun_cnt=%llx\n", __func__, 2248c2ecf20Sopenharmony_ci ((bit_word * BITS_PER_LONG) + bit_pos), ba_lun->lun_id, 2258c2ecf20Sopenharmony_ci bali->free_aun_cnt); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci return (u64) ((bit_word * BITS_PER_LONG) + bit_pos); 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci/** 2318c2ecf20Sopenharmony_ci * validate_alloc() - validates the specified block has been allocated 2328c2ecf20Sopenharmony_ci * @ba_lun_info: LUN info owning the block allocator. 2338c2ecf20Sopenharmony_ci * @aun: Block to validate. 2348c2ecf20Sopenharmony_ci * 2358c2ecf20Sopenharmony_ci * Return: 0 on success, -1 on failure 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_cistatic int validate_alloc(struct ba_lun_info *bali, u64 aun) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci int idx = 0, bit_pos = 0; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci idx = aun / BITS_PER_LONG; 2428c2ecf20Sopenharmony_ci bit_pos = aun % BITS_PER_LONG; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (test_bit(bit_pos, (ulong *)&bali->lun_alloc_map[idx])) 2458c2ecf20Sopenharmony_ci return -1; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci return 0; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci/** 2518c2ecf20Sopenharmony_ci * ba_free() - frees a block from the block allocator 2528c2ecf20Sopenharmony_ci * @ba_lun: Block allocator from which to allocate a block. 2538c2ecf20Sopenharmony_ci * @to_free: Block to free. 2548c2ecf20Sopenharmony_ci * 2558c2ecf20Sopenharmony_ci * Return: 0 on success, -1 on failure 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_cistatic int ba_free(struct ba_lun *ba_lun, u64 to_free) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci int idx = 0, bit_pos = 0; 2608c2ecf20Sopenharmony_ci struct ba_lun_info *bali = NULL; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci bali = ba_lun->ba_lun_handle; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (validate_alloc(bali, to_free)) { 2658c2ecf20Sopenharmony_ci pr_debug("%s: AUN %llx is not allocated on lun_id=%016llx\n", 2668c2ecf20Sopenharmony_ci __func__, to_free, ba_lun->lun_id); 2678c2ecf20Sopenharmony_ci return -1; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci pr_debug("%s: Received a request to free AU=%llx lun_id=%016llx " 2718c2ecf20Sopenharmony_ci "free_aun_cnt=%llx\n", __func__, to_free, ba_lun->lun_id, 2728c2ecf20Sopenharmony_ci bali->free_aun_cnt); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (bali->aun_clone_map[to_free] > 0) { 2758c2ecf20Sopenharmony_ci pr_debug("%s: AUN %llx lun_id=%016llx cloned. Clone count=%x\n", 2768c2ecf20Sopenharmony_ci __func__, to_free, ba_lun->lun_id, 2778c2ecf20Sopenharmony_ci bali->aun_clone_map[to_free]); 2788c2ecf20Sopenharmony_ci bali->aun_clone_map[to_free]--; 2798c2ecf20Sopenharmony_ci return 0; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci idx = to_free / BITS_PER_LONG; 2838c2ecf20Sopenharmony_ci bit_pos = to_free % BITS_PER_LONG; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci set_bit(bit_pos, (ulong *)&bali->lun_alloc_map[idx]); 2868c2ecf20Sopenharmony_ci bali->free_aun_cnt++; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (idx < bali->free_low_idx) 2898c2ecf20Sopenharmony_ci bali->free_low_idx = idx; 2908c2ecf20Sopenharmony_ci else if (idx > bali->free_high_idx) 2918c2ecf20Sopenharmony_ci bali->free_high_idx = idx; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci pr_debug("%s: Successfully freed AU bit_pos=%x bit map index=%x " 2948c2ecf20Sopenharmony_ci "lun_id=%016llx free_aun_cnt=%llx\n", __func__, bit_pos, idx, 2958c2ecf20Sopenharmony_ci ba_lun->lun_id, bali->free_aun_cnt); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci return 0; 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci/** 3018c2ecf20Sopenharmony_ci * ba_clone() - Clone a chunk of the block allocation table 3028c2ecf20Sopenharmony_ci * @ba_lun: Block allocator from which to allocate a block. 3038c2ecf20Sopenharmony_ci * @to_free: Block to free. 3048c2ecf20Sopenharmony_ci * 3058c2ecf20Sopenharmony_ci * Return: 0 on success, -1 on failure 3068c2ecf20Sopenharmony_ci */ 3078c2ecf20Sopenharmony_cistatic int ba_clone(struct ba_lun *ba_lun, u64 to_clone) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci struct ba_lun_info *bali = ba_lun->ba_lun_handle; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (validate_alloc(bali, to_clone)) { 3128c2ecf20Sopenharmony_ci pr_debug("%s: AUN=%llx not allocated on lun_id=%016llx\n", 3138c2ecf20Sopenharmony_ci __func__, to_clone, ba_lun->lun_id); 3148c2ecf20Sopenharmony_ci return -1; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci pr_debug("%s: Received a request to clone AUN %llx on lun_id=%016llx\n", 3188c2ecf20Sopenharmony_ci __func__, to_clone, ba_lun->lun_id); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (bali->aun_clone_map[to_clone] == MAX_AUN_CLONE_CNT) { 3218c2ecf20Sopenharmony_ci pr_debug("%s: AUN %llx on lun_id=%016llx hit max clones already\n", 3228c2ecf20Sopenharmony_ci __func__, to_clone, ba_lun->lun_id); 3238c2ecf20Sopenharmony_ci return -1; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci bali->aun_clone_map[to_clone]++; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci return 0; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci/** 3328c2ecf20Sopenharmony_ci * ba_space() - returns the amount of free space left in the block allocator 3338c2ecf20Sopenharmony_ci * @ba_lun: Block allocator. 3348c2ecf20Sopenharmony_ci * 3358c2ecf20Sopenharmony_ci * Return: Amount of free space in block allocator 3368c2ecf20Sopenharmony_ci */ 3378c2ecf20Sopenharmony_cistatic u64 ba_space(struct ba_lun *ba_lun) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct ba_lun_info *bali = ba_lun->ba_lun_handle; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci return bali->free_aun_cnt; 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci/** 3458c2ecf20Sopenharmony_ci * cxlflash_ba_terminate() - frees resources associated with the block allocator 3468c2ecf20Sopenharmony_ci * @ba_lun: Block allocator. 3478c2ecf20Sopenharmony_ci * 3488c2ecf20Sopenharmony_ci * Safe to call in a partially allocated state. 3498c2ecf20Sopenharmony_ci */ 3508c2ecf20Sopenharmony_civoid cxlflash_ba_terminate(struct ba_lun *ba_lun) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci struct ba_lun_info *bali = ba_lun->ba_lun_handle; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci if (bali) { 3558c2ecf20Sopenharmony_ci kfree(bali->aun_clone_map); 3568c2ecf20Sopenharmony_ci kfree(bali->lun_alloc_map); 3578c2ecf20Sopenharmony_ci kfree(bali); 3588c2ecf20Sopenharmony_ci ba_lun->ba_lun_handle = NULL; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci/** 3638c2ecf20Sopenharmony_ci * init_vlun() - initializes a LUN for virtual use 3648c2ecf20Sopenharmony_ci * @lun_info: LUN information structure that owns the block allocator. 3658c2ecf20Sopenharmony_ci * 3668c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure 3678c2ecf20Sopenharmony_ci */ 3688c2ecf20Sopenharmony_cistatic int init_vlun(struct llun_info *lli) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci int rc = 0; 3718c2ecf20Sopenharmony_ci struct glun_info *gli = lli->parent; 3728c2ecf20Sopenharmony_ci struct blka *blka = &gli->blka; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci memset(blka, 0, sizeof(*blka)); 3758c2ecf20Sopenharmony_ci mutex_init(&blka->mutex); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci /* LUN IDs are unique per port, save the index instead */ 3788c2ecf20Sopenharmony_ci blka->ba_lun.lun_id = lli->lun_index; 3798c2ecf20Sopenharmony_ci blka->ba_lun.lsize = gli->max_lba + 1; 3808c2ecf20Sopenharmony_ci blka->ba_lun.lba_size = gli->blk_len; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci blka->ba_lun.au_size = MC_CHUNK_SIZE; 3838c2ecf20Sopenharmony_ci blka->nchunk = blka->ba_lun.lsize / MC_CHUNK_SIZE; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci rc = ba_init(&blka->ba_lun); 3868c2ecf20Sopenharmony_ci if (unlikely(rc)) 3878c2ecf20Sopenharmony_ci pr_debug("%s: cannot init block_alloc, rc=%d\n", __func__, rc); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci pr_debug("%s: returning rc=%d lli=%p\n", __func__, rc, lli); 3908c2ecf20Sopenharmony_ci return rc; 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci/** 3948c2ecf20Sopenharmony_ci * write_same16() - sends a SCSI WRITE_SAME16 (0) command to specified LUN 3958c2ecf20Sopenharmony_ci * @sdev: SCSI device associated with LUN. 3968c2ecf20Sopenharmony_ci * @lba: Logical block address to start write same. 3978c2ecf20Sopenharmony_ci * @nblks: Number of logical blocks to write same. 3988c2ecf20Sopenharmony_ci * 3998c2ecf20Sopenharmony_ci * The SCSI WRITE_SAME16 can take quite a while to complete. Should an EEH occur 4008c2ecf20Sopenharmony_ci * while in scsi_execute(), the EEH handler will attempt to recover. As part of 4018c2ecf20Sopenharmony_ci * the recovery, the handler drains all currently running ioctls, waiting until 4028c2ecf20Sopenharmony_ci * they have completed before proceeding with a reset. As this routine is used 4038c2ecf20Sopenharmony_ci * on the ioctl path, this can create a condition where the EEH handler becomes 4048c2ecf20Sopenharmony_ci * stuck, infinitely waiting for this ioctl thread. To avoid this behavior, 4058c2ecf20Sopenharmony_ci * temporarily unmark this thread as an ioctl thread by releasing the ioctl read 4068c2ecf20Sopenharmony_ci * semaphore. This will allow the EEH handler to proceed with a recovery while 4078c2ecf20Sopenharmony_ci * this thread is still running. Once the scsi_execute() returns, reacquire the 4088c2ecf20Sopenharmony_ci * ioctl read semaphore and check the adapter state in case it changed while 4098c2ecf20Sopenharmony_ci * inside of scsi_execute(). The state check will wait if the adapter is still 4108c2ecf20Sopenharmony_ci * being recovered or return a failure if the recovery failed. In the event that 4118c2ecf20Sopenharmony_ci * the adapter reset failed, simply return the failure as the ioctl would be 4128c2ecf20Sopenharmony_ci * unable to continue. 4138c2ecf20Sopenharmony_ci * 4148c2ecf20Sopenharmony_ci * Note that the above puts a requirement on this routine to only be called on 4158c2ecf20Sopenharmony_ci * an ioctl thread. 4168c2ecf20Sopenharmony_ci * 4178c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure 4188c2ecf20Sopenharmony_ci */ 4198c2ecf20Sopenharmony_cistatic int write_same16(struct scsi_device *sdev, 4208c2ecf20Sopenharmony_ci u64 lba, 4218c2ecf20Sopenharmony_ci u32 nblks) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci u8 *cmd_buf = NULL; 4248c2ecf20Sopenharmony_ci u8 *scsi_cmd = NULL; 4258c2ecf20Sopenharmony_ci int rc = 0; 4268c2ecf20Sopenharmony_ci int result = 0; 4278c2ecf20Sopenharmony_ci u64 offset = lba; 4288c2ecf20Sopenharmony_ci int left = nblks; 4298c2ecf20Sopenharmony_ci struct cxlflash_cfg *cfg = shost_priv(sdev->host); 4308c2ecf20Sopenharmony_ci struct device *dev = &cfg->dev->dev; 4318c2ecf20Sopenharmony_ci const u32 s = ilog2(sdev->sector_size) - 9; 4328c2ecf20Sopenharmony_ci const u32 to = sdev->request_queue->rq_timeout; 4338c2ecf20Sopenharmony_ci const u32 ws_limit = blk_queue_get_max_sectors(sdev->request_queue, 4348c2ecf20Sopenharmony_ci REQ_OP_WRITE_SAME) >> s; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci cmd_buf = kzalloc(CMD_BUFSIZE, GFP_KERNEL); 4378c2ecf20Sopenharmony_ci scsi_cmd = kzalloc(MAX_COMMAND_SIZE, GFP_KERNEL); 4388c2ecf20Sopenharmony_ci if (unlikely(!cmd_buf || !scsi_cmd)) { 4398c2ecf20Sopenharmony_ci rc = -ENOMEM; 4408c2ecf20Sopenharmony_ci goto out; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci while (left > 0) { 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci scsi_cmd[0] = WRITE_SAME_16; 4468c2ecf20Sopenharmony_ci scsi_cmd[1] = cfg->ws_unmap ? 0x8 : 0; 4478c2ecf20Sopenharmony_ci put_unaligned_be64(offset, &scsi_cmd[2]); 4488c2ecf20Sopenharmony_ci put_unaligned_be32(ws_limit < left ? ws_limit : left, 4498c2ecf20Sopenharmony_ci &scsi_cmd[10]); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci /* Drop the ioctl read semahpore across lengthy call */ 4528c2ecf20Sopenharmony_ci up_read(&cfg->ioctl_rwsem); 4538c2ecf20Sopenharmony_ci result = scsi_execute(sdev, scsi_cmd, DMA_TO_DEVICE, cmd_buf, 4548c2ecf20Sopenharmony_ci CMD_BUFSIZE, NULL, NULL, to, 4558c2ecf20Sopenharmony_ci CMD_RETRIES, 0, 0, NULL); 4568c2ecf20Sopenharmony_ci down_read(&cfg->ioctl_rwsem); 4578c2ecf20Sopenharmony_ci rc = check_state(cfg); 4588c2ecf20Sopenharmony_ci if (rc) { 4598c2ecf20Sopenharmony_ci dev_err(dev, "%s: Failed state result=%08x\n", 4608c2ecf20Sopenharmony_ci __func__, result); 4618c2ecf20Sopenharmony_ci rc = -ENODEV; 4628c2ecf20Sopenharmony_ci goto out; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci if (result) { 4668c2ecf20Sopenharmony_ci dev_err_ratelimited(dev, "%s: command failed for " 4678c2ecf20Sopenharmony_ci "offset=%lld result=%08x\n", 4688c2ecf20Sopenharmony_ci __func__, offset, result); 4698c2ecf20Sopenharmony_ci rc = -EIO; 4708c2ecf20Sopenharmony_ci goto out; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci left -= ws_limit; 4738c2ecf20Sopenharmony_ci offset += ws_limit; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ciout: 4778c2ecf20Sopenharmony_ci kfree(cmd_buf); 4788c2ecf20Sopenharmony_ci kfree(scsi_cmd); 4798c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); 4808c2ecf20Sopenharmony_ci return rc; 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci/** 4848c2ecf20Sopenharmony_ci * grow_lxt() - expands the translation table associated with the specified RHTE 4858c2ecf20Sopenharmony_ci * @afu: AFU associated with the host. 4868c2ecf20Sopenharmony_ci * @sdev: SCSI device associated with LUN. 4878c2ecf20Sopenharmony_ci * @ctxid: Context ID of context owning the RHTE. 4888c2ecf20Sopenharmony_ci * @rhndl: Resource handle associated with the RHTE. 4898c2ecf20Sopenharmony_ci * @rhte: Resource handle entry (RHTE). 4908c2ecf20Sopenharmony_ci * @new_size: Number of translation entries associated with RHTE. 4918c2ecf20Sopenharmony_ci * 4928c2ecf20Sopenharmony_ci * By design, this routine employs a 'best attempt' allocation and will 4938c2ecf20Sopenharmony_ci * truncate the requested size down if there is not sufficient space in 4948c2ecf20Sopenharmony_ci * the block allocator to satisfy the request but there does exist some 4958c2ecf20Sopenharmony_ci * amount of space. The user is made aware of this by returning the size 4968c2ecf20Sopenharmony_ci * allocated. 4978c2ecf20Sopenharmony_ci * 4988c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure 4998c2ecf20Sopenharmony_ci */ 5008c2ecf20Sopenharmony_cistatic int grow_lxt(struct afu *afu, 5018c2ecf20Sopenharmony_ci struct scsi_device *sdev, 5028c2ecf20Sopenharmony_ci ctx_hndl_t ctxid, 5038c2ecf20Sopenharmony_ci res_hndl_t rhndl, 5048c2ecf20Sopenharmony_ci struct sisl_rht_entry *rhte, 5058c2ecf20Sopenharmony_ci u64 *new_size) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci struct cxlflash_cfg *cfg = shost_priv(sdev->host); 5088c2ecf20Sopenharmony_ci struct device *dev = &cfg->dev->dev; 5098c2ecf20Sopenharmony_ci struct sisl_lxt_entry *lxt = NULL, *lxt_old = NULL; 5108c2ecf20Sopenharmony_ci struct llun_info *lli = sdev->hostdata; 5118c2ecf20Sopenharmony_ci struct glun_info *gli = lli->parent; 5128c2ecf20Sopenharmony_ci struct blka *blka = &gli->blka; 5138c2ecf20Sopenharmony_ci u32 av_size; 5148c2ecf20Sopenharmony_ci u32 ngrps, ngrps_old; 5158c2ecf20Sopenharmony_ci u64 aun; /* chunk# allocated by block allocator */ 5168c2ecf20Sopenharmony_ci u64 delta = *new_size - rhte->lxt_cnt; 5178c2ecf20Sopenharmony_ci u64 my_new_size; 5188c2ecf20Sopenharmony_ci int i, rc = 0; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci /* 5218c2ecf20Sopenharmony_ci * Check what is available in the block allocator before re-allocating 5228c2ecf20Sopenharmony_ci * LXT array. This is done up front under the mutex which must not be 5238c2ecf20Sopenharmony_ci * released until after allocation is complete. 5248c2ecf20Sopenharmony_ci */ 5258c2ecf20Sopenharmony_ci mutex_lock(&blka->mutex); 5268c2ecf20Sopenharmony_ci av_size = ba_space(&blka->ba_lun); 5278c2ecf20Sopenharmony_ci if (unlikely(av_size <= 0)) { 5288c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: ba_space error av_size=%d\n", 5298c2ecf20Sopenharmony_ci __func__, av_size); 5308c2ecf20Sopenharmony_ci mutex_unlock(&blka->mutex); 5318c2ecf20Sopenharmony_ci rc = -ENOSPC; 5328c2ecf20Sopenharmony_ci goto out; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci if (av_size < delta) 5368c2ecf20Sopenharmony_ci delta = av_size; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci lxt_old = rhte->lxt_start; 5398c2ecf20Sopenharmony_ci ngrps_old = LXT_NUM_GROUPS(rhte->lxt_cnt); 5408c2ecf20Sopenharmony_ci ngrps = LXT_NUM_GROUPS(rhte->lxt_cnt + delta); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (ngrps != ngrps_old) { 5438c2ecf20Sopenharmony_ci /* reallocate to fit new size */ 5448c2ecf20Sopenharmony_ci lxt = kzalloc((sizeof(*lxt) * LXT_GROUP_SIZE * ngrps), 5458c2ecf20Sopenharmony_ci GFP_KERNEL); 5468c2ecf20Sopenharmony_ci if (unlikely(!lxt)) { 5478c2ecf20Sopenharmony_ci mutex_unlock(&blka->mutex); 5488c2ecf20Sopenharmony_ci rc = -ENOMEM; 5498c2ecf20Sopenharmony_ci goto out; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci /* copy over all old entries */ 5538c2ecf20Sopenharmony_ci memcpy(lxt, lxt_old, (sizeof(*lxt) * rhte->lxt_cnt)); 5548c2ecf20Sopenharmony_ci } else 5558c2ecf20Sopenharmony_ci lxt = lxt_old; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci /* nothing can fail from now on */ 5588c2ecf20Sopenharmony_ci my_new_size = rhte->lxt_cnt + delta; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci /* add new entries to the end */ 5618c2ecf20Sopenharmony_ci for (i = rhte->lxt_cnt; i < my_new_size; i++) { 5628c2ecf20Sopenharmony_ci /* 5638c2ecf20Sopenharmony_ci * Due to the earlier check of available space, ba_alloc 5648c2ecf20Sopenharmony_ci * cannot fail here. If it did due to internal error, 5658c2ecf20Sopenharmony_ci * leave a rlba_base of -1u which will likely be a 5668c2ecf20Sopenharmony_ci * invalid LUN (too large). 5678c2ecf20Sopenharmony_ci */ 5688c2ecf20Sopenharmony_ci aun = ba_alloc(&blka->ba_lun); 5698c2ecf20Sopenharmony_ci if ((aun == -1ULL) || (aun >= blka->nchunk)) 5708c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: ba_alloc error allocated chunk=%llu " 5718c2ecf20Sopenharmony_ci "max=%llu\n", __func__, aun, blka->nchunk - 1); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* select both ports, use r/w perms from RHT */ 5748c2ecf20Sopenharmony_ci lxt[i].rlba_base = ((aun << MC_CHUNK_SHIFT) | 5758c2ecf20Sopenharmony_ci (lli->lun_index << LXT_LUNIDX_SHIFT) | 5768c2ecf20Sopenharmony_ci (RHT_PERM_RW << LXT_PERM_SHIFT | 5778c2ecf20Sopenharmony_ci lli->port_sel)); 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci mutex_unlock(&blka->mutex); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci /* 5838c2ecf20Sopenharmony_ci * The following sequence is prescribed in the SISlite spec 5848c2ecf20Sopenharmony_ci * for syncing up with the AFU when adding LXT entries. 5858c2ecf20Sopenharmony_ci */ 5868c2ecf20Sopenharmony_ci dma_wmb(); /* Make LXT updates are visible */ 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci rhte->lxt_start = lxt; 5898c2ecf20Sopenharmony_ci dma_wmb(); /* Make RHT entry's LXT table update visible */ 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci rhte->lxt_cnt = my_new_size; 5928c2ecf20Sopenharmony_ci dma_wmb(); /* Make RHT entry's LXT table size update visible */ 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci rc = cxlflash_afu_sync(afu, ctxid, rhndl, AFU_LW_SYNC); 5958c2ecf20Sopenharmony_ci if (unlikely(rc)) 5968c2ecf20Sopenharmony_ci rc = -EAGAIN; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci /* free old lxt if reallocated */ 5998c2ecf20Sopenharmony_ci if (lxt != lxt_old) 6008c2ecf20Sopenharmony_ci kfree(lxt_old); 6018c2ecf20Sopenharmony_ci *new_size = my_new_size; 6028c2ecf20Sopenharmony_ciout: 6038c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); 6048c2ecf20Sopenharmony_ci return rc; 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci/** 6088c2ecf20Sopenharmony_ci * shrink_lxt() - reduces translation table associated with the specified RHTE 6098c2ecf20Sopenharmony_ci * @afu: AFU associated with the host. 6108c2ecf20Sopenharmony_ci * @sdev: SCSI device associated with LUN. 6118c2ecf20Sopenharmony_ci * @rhndl: Resource handle associated with the RHTE. 6128c2ecf20Sopenharmony_ci * @rhte: Resource handle entry (RHTE). 6138c2ecf20Sopenharmony_ci * @ctxi: Context owning resources. 6148c2ecf20Sopenharmony_ci * @new_size: Number of translation entries associated with RHTE. 6158c2ecf20Sopenharmony_ci * 6168c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure 6178c2ecf20Sopenharmony_ci */ 6188c2ecf20Sopenharmony_cistatic int shrink_lxt(struct afu *afu, 6198c2ecf20Sopenharmony_ci struct scsi_device *sdev, 6208c2ecf20Sopenharmony_ci res_hndl_t rhndl, 6218c2ecf20Sopenharmony_ci struct sisl_rht_entry *rhte, 6228c2ecf20Sopenharmony_ci struct ctx_info *ctxi, 6238c2ecf20Sopenharmony_ci u64 *new_size) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci struct cxlflash_cfg *cfg = shost_priv(sdev->host); 6268c2ecf20Sopenharmony_ci struct device *dev = &cfg->dev->dev; 6278c2ecf20Sopenharmony_ci struct sisl_lxt_entry *lxt, *lxt_old; 6288c2ecf20Sopenharmony_ci struct llun_info *lli = sdev->hostdata; 6298c2ecf20Sopenharmony_ci struct glun_info *gli = lli->parent; 6308c2ecf20Sopenharmony_ci struct blka *blka = &gli->blka; 6318c2ecf20Sopenharmony_ci ctx_hndl_t ctxid = DECODE_CTXID(ctxi->ctxid); 6328c2ecf20Sopenharmony_ci bool needs_ws = ctxi->rht_needs_ws[rhndl]; 6338c2ecf20Sopenharmony_ci bool needs_sync = !ctxi->err_recovery_active; 6348c2ecf20Sopenharmony_ci u32 ngrps, ngrps_old; 6358c2ecf20Sopenharmony_ci u64 aun; /* chunk# allocated by block allocator */ 6368c2ecf20Sopenharmony_ci u64 delta = rhte->lxt_cnt - *new_size; 6378c2ecf20Sopenharmony_ci u64 my_new_size; 6388c2ecf20Sopenharmony_ci int i, rc = 0; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci lxt_old = rhte->lxt_start; 6418c2ecf20Sopenharmony_ci ngrps_old = LXT_NUM_GROUPS(rhte->lxt_cnt); 6428c2ecf20Sopenharmony_ci ngrps = LXT_NUM_GROUPS(rhte->lxt_cnt - delta); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if (ngrps != ngrps_old) { 6458c2ecf20Sopenharmony_ci /* Reallocate to fit new size unless new size is 0 */ 6468c2ecf20Sopenharmony_ci if (ngrps) { 6478c2ecf20Sopenharmony_ci lxt = kzalloc((sizeof(*lxt) * LXT_GROUP_SIZE * ngrps), 6488c2ecf20Sopenharmony_ci GFP_KERNEL); 6498c2ecf20Sopenharmony_ci if (unlikely(!lxt)) { 6508c2ecf20Sopenharmony_ci rc = -ENOMEM; 6518c2ecf20Sopenharmony_ci goto out; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci /* Copy over old entries that will remain */ 6558c2ecf20Sopenharmony_ci memcpy(lxt, lxt_old, 6568c2ecf20Sopenharmony_ci (sizeof(*lxt) * (rhte->lxt_cnt - delta))); 6578c2ecf20Sopenharmony_ci } else 6588c2ecf20Sopenharmony_ci lxt = NULL; 6598c2ecf20Sopenharmony_ci } else 6608c2ecf20Sopenharmony_ci lxt = lxt_old; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci /* Nothing can fail from now on */ 6638c2ecf20Sopenharmony_ci my_new_size = rhte->lxt_cnt - delta; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci /* 6668c2ecf20Sopenharmony_ci * The following sequence is prescribed in the SISlite spec 6678c2ecf20Sopenharmony_ci * for syncing up with the AFU when removing LXT entries. 6688c2ecf20Sopenharmony_ci */ 6698c2ecf20Sopenharmony_ci rhte->lxt_cnt = my_new_size; 6708c2ecf20Sopenharmony_ci dma_wmb(); /* Make RHT entry's LXT table size update visible */ 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci rhte->lxt_start = lxt; 6738c2ecf20Sopenharmony_ci dma_wmb(); /* Make RHT entry's LXT table update visible */ 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci if (needs_sync) { 6768c2ecf20Sopenharmony_ci rc = cxlflash_afu_sync(afu, ctxid, rhndl, AFU_HW_SYNC); 6778c2ecf20Sopenharmony_ci if (unlikely(rc)) 6788c2ecf20Sopenharmony_ci rc = -EAGAIN; 6798c2ecf20Sopenharmony_ci } 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci if (needs_ws) { 6828c2ecf20Sopenharmony_ci /* 6838c2ecf20Sopenharmony_ci * Mark the context as unavailable, so that we can release 6848c2ecf20Sopenharmony_ci * the mutex safely. 6858c2ecf20Sopenharmony_ci */ 6868c2ecf20Sopenharmony_ci ctxi->unavail = true; 6878c2ecf20Sopenharmony_ci mutex_unlock(&ctxi->mutex); 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci /* Free LBAs allocated to freed chunks */ 6918c2ecf20Sopenharmony_ci mutex_lock(&blka->mutex); 6928c2ecf20Sopenharmony_ci for (i = delta - 1; i >= 0; i--) { 6938c2ecf20Sopenharmony_ci aun = lxt_old[my_new_size + i].rlba_base >> MC_CHUNK_SHIFT; 6948c2ecf20Sopenharmony_ci if (needs_ws) 6958c2ecf20Sopenharmony_ci write_same16(sdev, aun, MC_CHUNK_SIZE); 6968c2ecf20Sopenharmony_ci ba_free(&blka->ba_lun, aun); 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci mutex_unlock(&blka->mutex); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (needs_ws) { 7018c2ecf20Sopenharmony_ci /* Make the context visible again */ 7028c2ecf20Sopenharmony_ci mutex_lock(&ctxi->mutex); 7038c2ecf20Sopenharmony_ci ctxi->unavail = false; 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci /* Free old lxt if reallocated */ 7078c2ecf20Sopenharmony_ci if (lxt != lxt_old) 7088c2ecf20Sopenharmony_ci kfree(lxt_old); 7098c2ecf20Sopenharmony_ci *new_size = my_new_size; 7108c2ecf20Sopenharmony_ciout: 7118c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); 7128c2ecf20Sopenharmony_ci return rc; 7138c2ecf20Sopenharmony_ci} 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci/** 7168c2ecf20Sopenharmony_ci * _cxlflash_vlun_resize() - changes the size of a virtual LUN 7178c2ecf20Sopenharmony_ci * @sdev: SCSI device associated with LUN owning virtual LUN. 7188c2ecf20Sopenharmony_ci * @ctxi: Context owning resources. 7198c2ecf20Sopenharmony_ci * @resize: Resize ioctl data structure. 7208c2ecf20Sopenharmony_ci * 7218c2ecf20Sopenharmony_ci * On successful return, the user is informed of the new size (in blocks) 7228c2ecf20Sopenharmony_ci * of the virtual LUN in last LBA format. When the size of the virtual 7238c2ecf20Sopenharmony_ci * LUN is zero, the last LBA is reflected as -1. See comment in the 7248c2ecf20Sopenharmony_ci * prologue for _cxlflash_disk_release() regarding AFU syncs and contexts 7258c2ecf20Sopenharmony_ci * on the error recovery list. 7268c2ecf20Sopenharmony_ci * 7278c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure 7288c2ecf20Sopenharmony_ci */ 7298c2ecf20Sopenharmony_ciint _cxlflash_vlun_resize(struct scsi_device *sdev, 7308c2ecf20Sopenharmony_ci struct ctx_info *ctxi, 7318c2ecf20Sopenharmony_ci struct dk_cxlflash_resize *resize) 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci struct cxlflash_cfg *cfg = shost_priv(sdev->host); 7348c2ecf20Sopenharmony_ci struct device *dev = &cfg->dev->dev; 7358c2ecf20Sopenharmony_ci struct llun_info *lli = sdev->hostdata; 7368c2ecf20Sopenharmony_ci struct glun_info *gli = lli->parent; 7378c2ecf20Sopenharmony_ci struct afu *afu = cfg->afu; 7388c2ecf20Sopenharmony_ci bool put_ctx = false; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci res_hndl_t rhndl = resize->rsrc_handle; 7418c2ecf20Sopenharmony_ci u64 new_size; 7428c2ecf20Sopenharmony_ci u64 nsectors; 7438c2ecf20Sopenharmony_ci u64 ctxid = DECODE_CTXID(resize->context_id), 7448c2ecf20Sopenharmony_ci rctxid = resize->context_id; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci struct sisl_rht_entry *rhte; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci int rc = 0; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci /* 7518c2ecf20Sopenharmony_ci * The requested size (req_size) is always assumed to be in 4k blocks, 7528c2ecf20Sopenharmony_ci * so we have to convert it here from 4k to chunk size. 7538c2ecf20Sopenharmony_ci */ 7548c2ecf20Sopenharmony_ci nsectors = (resize->req_size * CXLFLASH_BLOCK_SIZE) / gli->blk_len; 7558c2ecf20Sopenharmony_ci new_size = DIV_ROUND_UP(nsectors, MC_CHUNK_SIZE); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: ctxid=%llu rhndl=%llu req_size=%llu new_size=%llu\n", 7588c2ecf20Sopenharmony_ci __func__, ctxid, resize->rsrc_handle, resize->req_size, 7598c2ecf20Sopenharmony_ci new_size); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (unlikely(gli->mode != MODE_VIRTUAL)) { 7628c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: LUN mode does not support resize mode=%d\n", 7638c2ecf20Sopenharmony_ci __func__, gli->mode); 7648c2ecf20Sopenharmony_ci rc = -EINVAL; 7658c2ecf20Sopenharmony_ci goto out; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci if (!ctxi) { 7708c2ecf20Sopenharmony_ci ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); 7718c2ecf20Sopenharmony_ci if (unlikely(!ctxi)) { 7728c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: Bad context ctxid=%llu\n", 7738c2ecf20Sopenharmony_ci __func__, ctxid); 7748c2ecf20Sopenharmony_ci rc = -EINVAL; 7758c2ecf20Sopenharmony_ci goto out; 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci put_ctx = true; 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci rhte = get_rhte(ctxi, rhndl, lli); 7828c2ecf20Sopenharmony_ci if (unlikely(!rhte)) { 7838c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: Bad resource handle rhndl=%u\n", 7848c2ecf20Sopenharmony_ci __func__, rhndl); 7858c2ecf20Sopenharmony_ci rc = -EINVAL; 7868c2ecf20Sopenharmony_ci goto out; 7878c2ecf20Sopenharmony_ci } 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci if (new_size > rhte->lxt_cnt) 7908c2ecf20Sopenharmony_ci rc = grow_lxt(afu, sdev, ctxid, rhndl, rhte, &new_size); 7918c2ecf20Sopenharmony_ci else if (new_size < rhte->lxt_cnt) 7928c2ecf20Sopenharmony_ci rc = shrink_lxt(afu, sdev, rhndl, rhte, ctxi, &new_size); 7938c2ecf20Sopenharmony_ci else { 7948c2ecf20Sopenharmony_ci /* 7958c2ecf20Sopenharmony_ci * Rare case where there is already sufficient space, just 7968c2ecf20Sopenharmony_ci * need to perform a translation sync with the AFU. This 7978c2ecf20Sopenharmony_ci * scenario likely follows a previous sync failure during 7988c2ecf20Sopenharmony_ci * a resize operation. Accordingly, perform the heavyweight 7998c2ecf20Sopenharmony_ci * form of translation sync as it is unknown which type of 8008c2ecf20Sopenharmony_ci * resize failed previously. 8018c2ecf20Sopenharmony_ci */ 8028c2ecf20Sopenharmony_ci rc = cxlflash_afu_sync(afu, ctxid, rhndl, AFU_HW_SYNC); 8038c2ecf20Sopenharmony_ci if (unlikely(rc)) { 8048c2ecf20Sopenharmony_ci rc = -EAGAIN; 8058c2ecf20Sopenharmony_ci goto out; 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci resize->hdr.return_flags = 0; 8108c2ecf20Sopenharmony_ci resize->last_lba = (new_size * MC_CHUNK_SIZE * gli->blk_len); 8118c2ecf20Sopenharmony_ci resize->last_lba /= CXLFLASH_BLOCK_SIZE; 8128c2ecf20Sopenharmony_ci resize->last_lba--; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ciout: 8158c2ecf20Sopenharmony_ci if (put_ctx) 8168c2ecf20Sopenharmony_ci put_context(ctxi); 8178c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: resized to %llu returning rc=%d\n", 8188c2ecf20Sopenharmony_ci __func__, resize->last_lba, rc); 8198c2ecf20Sopenharmony_ci return rc; 8208c2ecf20Sopenharmony_ci} 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ciint cxlflash_vlun_resize(struct scsi_device *sdev, 8238c2ecf20Sopenharmony_ci struct dk_cxlflash_resize *resize) 8248c2ecf20Sopenharmony_ci{ 8258c2ecf20Sopenharmony_ci return _cxlflash_vlun_resize(sdev, NULL, resize); 8268c2ecf20Sopenharmony_ci} 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci/** 8298c2ecf20Sopenharmony_ci * cxlflash_restore_luntable() - Restore LUN table to prior state 8308c2ecf20Sopenharmony_ci * @cfg: Internal structure associated with the host. 8318c2ecf20Sopenharmony_ci */ 8328c2ecf20Sopenharmony_civoid cxlflash_restore_luntable(struct cxlflash_cfg *cfg) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci struct llun_info *lli, *temp; 8358c2ecf20Sopenharmony_ci u32 lind; 8368c2ecf20Sopenharmony_ci int k; 8378c2ecf20Sopenharmony_ci struct device *dev = &cfg->dev->dev; 8388c2ecf20Sopenharmony_ci __be64 __iomem *fc_port_luns; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci mutex_lock(&global.mutex); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci list_for_each_entry_safe(lli, temp, &cfg->lluns, list) { 8438c2ecf20Sopenharmony_ci if (!lli->in_table) 8448c2ecf20Sopenharmony_ci continue; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci lind = lli->lun_index; 8478c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: Virtual LUNs on slot %d:\n", __func__, lind); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci for (k = 0; k < cfg->num_fc_ports; k++) 8508c2ecf20Sopenharmony_ci if (lli->port_sel & (1 << k)) { 8518c2ecf20Sopenharmony_ci fc_port_luns = get_fc_port_luns(cfg, k); 8528c2ecf20Sopenharmony_ci writeq_be(lli->lun_id[k], &fc_port_luns[lind]); 8538c2ecf20Sopenharmony_ci dev_dbg(dev, "\t%d=%llx\n", k, lli->lun_id[k]); 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci mutex_unlock(&global.mutex); 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci/** 8618c2ecf20Sopenharmony_ci * get_num_ports() - compute number of ports from port selection mask 8628c2ecf20Sopenharmony_ci * @psm: Port selection mask. 8638c2ecf20Sopenharmony_ci * 8648c2ecf20Sopenharmony_ci * Return: Population count of port selection mask 8658c2ecf20Sopenharmony_ci */ 8668c2ecf20Sopenharmony_cistatic inline u8 get_num_ports(u32 psm) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci static const u8 bits[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 8698c2ecf20Sopenharmony_ci 1, 2, 2, 3, 2, 3, 3, 4 }; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci return bits[psm & 0xf]; 8728c2ecf20Sopenharmony_ci} 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci/** 8758c2ecf20Sopenharmony_ci * init_luntable() - write an entry in the LUN table 8768c2ecf20Sopenharmony_ci * @cfg: Internal structure associated with the host. 8778c2ecf20Sopenharmony_ci * @lli: Per adapter LUN information structure. 8788c2ecf20Sopenharmony_ci * 8798c2ecf20Sopenharmony_ci * On successful return, a LUN table entry is created: 8808c2ecf20Sopenharmony_ci * - at the top for LUNs visible on multiple ports. 8818c2ecf20Sopenharmony_ci * - at the bottom for LUNs visible only on one port. 8828c2ecf20Sopenharmony_ci * 8838c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure 8848c2ecf20Sopenharmony_ci */ 8858c2ecf20Sopenharmony_cistatic int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli) 8868c2ecf20Sopenharmony_ci{ 8878c2ecf20Sopenharmony_ci u32 chan; 8888c2ecf20Sopenharmony_ci u32 lind; 8898c2ecf20Sopenharmony_ci u32 nports; 8908c2ecf20Sopenharmony_ci int rc = 0; 8918c2ecf20Sopenharmony_ci int k; 8928c2ecf20Sopenharmony_ci struct device *dev = &cfg->dev->dev; 8938c2ecf20Sopenharmony_ci __be64 __iomem *fc_port_luns; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci mutex_lock(&global.mutex); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci if (lli->in_table) 8988c2ecf20Sopenharmony_ci goto out; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci nports = get_num_ports(lli->port_sel); 9018c2ecf20Sopenharmony_ci if (nports == 0 || nports > cfg->num_fc_ports) { 9028c2ecf20Sopenharmony_ci WARN(1, "Unsupported port configuration nports=%u", nports); 9038c2ecf20Sopenharmony_ci rc = -EIO; 9048c2ecf20Sopenharmony_ci goto out; 9058c2ecf20Sopenharmony_ci } 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci if (nports > 1) { 9088c2ecf20Sopenharmony_ci /* 9098c2ecf20Sopenharmony_ci * When LUN is visible from multiple ports, we will put 9108c2ecf20Sopenharmony_ci * it in the top half of the LUN table. 9118c2ecf20Sopenharmony_ci */ 9128c2ecf20Sopenharmony_ci for (k = 0; k < cfg->num_fc_ports; k++) { 9138c2ecf20Sopenharmony_ci if (!(lli->port_sel & (1 << k))) 9148c2ecf20Sopenharmony_ci continue; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci if (cfg->promote_lun_index == cfg->last_lun_index[k]) { 9178c2ecf20Sopenharmony_ci rc = -ENOSPC; 9188c2ecf20Sopenharmony_ci goto out; 9198c2ecf20Sopenharmony_ci } 9208c2ecf20Sopenharmony_ci } 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci lind = lli->lun_index = cfg->promote_lun_index; 9238c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: Virtual LUNs on slot %d:\n", __func__, lind); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci for (k = 0; k < cfg->num_fc_ports; k++) { 9268c2ecf20Sopenharmony_ci if (!(lli->port_sel & (1 << k))) 9278c2ecf20Sopenharmony_ci continue; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci fc_port_luns = get_fc_port_luns(cfg, k); 9308c2ecf20Sopenharmony_ci writeq_be(lli->lun_id[k], &fc_port_luns[lind]); 9318c2ecf20Sopenharmony_ci dev_dbg(dev, "\t%d=%llx\n", k, lli->lun_id[k]); 9328c2ecf20Sopenharmony_ci } 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci cfg->promote_lun_index++; 9358c2ecf20Sopenharmony_ci } else { 9368c2ecf20Sopenharmony_ci /* 9378c2ecf20Sopenharmony_ci * When LUN is visible only from one port, we will put 9388c2ecf20Sopenharmony_ci * it in the bottom half of the LUN table. 9398c2ecf20Sopenharmony_ci */ 9408c2ecf20Sopenharmony_ci chan = PORTMASK2CHAN(lli->port_sel); 9418c2ecf20Sopenharmony_ci if (cfg->promote_lun_index == cfg->last_lun_index[chan]) { 9428c2ecf20Sopenharmony_ci rc = -ENOSPC; 9438c2ecf20Sopenharmony_ci goto out; 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci lind = lli->lun_index = cfg->last_lun_index[chan]; 9478c2ecf20Sopenharmony_ci fc_port_luns = get_fc_port_luns(cfg, chan); 9488c2ecf20Sopenharmony_ci writeq_be(lli->lun_id[chan], &fc_port_luns[lind]); 9498c2ecf20Sopenharmony_ci cfg->last_lun_index[chan]--; 9508c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: Virtual LUNs on slot %d:\n\t%d=%llx\n", 9518c2ecf20Sopenharmony_ci __func__, lind, chan, lli->lun_id[chan]); 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci lli->in_table = true; 9558c2ecf20Sopenharmony_ciout: 9568c2ecf20Sopenharmony_ci mutex_unlock(&global.mutex); 9578c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); 9588c2ecf20Sopenharmony_ci return rc; 9598c2ecf20Sopenharmony_ci} 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci/** 9628c2ecf20Sopenharmony_ci * cxlflash_disk_virtual_open() - open a virtual disk of specified size 9638c2ecf20Sopenharmony_ci * @sdev: SCSI device associated with LUN owning virtual LUN. 9648c2ecf20Sopenharmony_ci * @arg: UVirtual ioctl data structure. 9658c2ecf20Sopenharmony_ci * 9668c2ecf20Sopenharmony_ci * On successful return, the user is informed of the resource handle 9678c2ecf20Sopenharmony_ci * to be used to identify the virtual LUN and the size (in blocks) of 9688c2ecf20Sopenharmony_ci * the virtual LUN in last LBA format. When the size of the virtual LUN 9698c2ecf20Sopenharmony_ci * is zero, the last LBA is reflected as -1. 9708c2ecf20Sopenharmony_ci * 9718c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure 9728c2ecf20Sopenharmony_ci */ 9738c2ecf20Sopenharmony_ciint cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg) 9748c2ecf20Sopenharmony_ci{ 9758c2ecf20Sopenharmony_ci struct cxlflash_cfg *cfg = shost_priv(sdev->host); 9768c2ecf20Sopenharmony_ci struct device *dev = &cfg->dev->dev; 9778c2ecf20Sopenharmony_ci struct llun_info *lli = sdev->hostdata; 9788c2ecf20Sopenharmony_ci struct glun_info *gli = lli->parent; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci struct dk_cxlflash_uvirtual *virt = (struct dk_cxlflash_uvirtual *)arg; 9818c2ecf20Sopenharmony_ci struct dk_cxlflash_resize resize; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci u64 ctxid = DECODE_CTXID(virt->context_id), 9848c2ecf20Sopenharmony_ci rctxid = virt->context_id; 9858c2ecf20Sopenharmony_ci u64 lun_size = virt->lun_size; 9868c2ecf20Sopenharmony_ci u64 last_lba = 0; 9878c2ecf20Sopenharmony_ci u64 rsrc_handle = -1; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci int rc = 0; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci struct ctx_info *ctxi = NULL; 9928c2ecf20Sopenharmony_ci struct sisl_rht_entry *rhte = NULL; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: ctxid=%llu ls=%llu\n", __func__, ctxid, lun_size); 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci /* Setup the LUNs block allocator on first call */ 9978c2ecf20Sopenharmony_ci mutex_lock(&gli->mutex); 9988c2ecf20Sopenharmony_ci if (gli->mode == MODE_NONE) { 9998c2ecf20Sopenharmony_ci rc = init_vlun(lli); 10008c2ecf20Sopenharmony_ci if (rc) { 10018c2ecf20Sopenharmony_ci dev_err(dev, "%s: init_vlun failed rc=%d\n", 10028c2ecf20Sopenharmony_ci __func__, rc); 10038c2ecf20Sopenharmony_ci rc = -ENOMEM; 10048c2ecf20Sopenharmony_ci goto err0; 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci } 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci rc = cxlflash_lun_attach(gli, MODE_VIRTUAL, true); 10098c2ecf20Sopenharmony_ci if (unlikely(rc)) { 10108c2ecf20Sopenharmony_ci dev_err(dev, "%s: Failed attach to LUN (VIRTUAL)\n", __func__); 10118c2ecf20Sopenharmony_ci goto err0; 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci mutex_unlock(&gli->mutex); 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci rc = init_luntable(cfg, lli); 10168c2ecf20Sopenharmony_ci if (rc) { 10178c2ecf20Sopenharmony_ci dev_err(dev, "%s: init_luntable failed rc=%d\n", __func__, rc); 10188c2ecf20Sopenharmony_ci goto err1; 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci ctxi = get_context(cfg, rctxid, lli, 0); 10228c2ecf20Sopenharmony_ci if (unlikely(!ctxi)) { 10238c2ecf20Sopenharmony_ci dev_err(dev, "%s: Bad context ctxid=%llu\n", __func__, ctxid); 10248c2ecf20Sopenharmony_ci rc = -EINVAL; 10258c2ecf20Sopenharmony_ci goto err1; 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci rhte = rhte_checkout(ctxi, lli); 10298c2ecf20Sopenharmony_ci if (unlikely(!rhte)) { 10308c2ecf20Sopenharmony_ci dev_err(dev, "%s: too many opens ctxid=%llu\n", 10318c2ecf20Sopenharmony_ci __func__, ctxid); 10328c2ecf20Sopenharmony_ci rc = -EMFILE; /* too many opens */ 10338c2ecf20Sopenharmony_ci goto err1; 10348c2ecf20Sopenharmony_ci } 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci rsrc_handle = (rhte - ctxi->rht_start); 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci /* Populate RHT format 0 */ 10398c2ecf20Sopenharmony_ci rhte->nmask = MC_RHT_NMASK; 10408c2ecf20Sopenharmony_ci rhte->fp = SISL_RHT_FP(0U, ctxi->rht_perms); 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci /* Resize even if requested size is 0 */ 10438c2ecf20Sopenharmony_ci marshal_virt_to_resize(virt, &resize); 10448c2ecf20Sopenharmony_ci resize.rsrc_handle = rsrc_handle; 10458c2ecf20Sopenharmony_ci rc = _cxlflash_vlun_resize(sdev, ctxi, &resize); 10468c2ecf20Sopenharmony_ci if (rc) { 10478c2ecf20Sopenharmony_ci dev_err(dev, "%s: resize failed rc=%d\n", __func__, rc); 10488c2ecf20Sopenharmony_ci goto err2; 10498c2ecf20Sopenharmony_ci } 10508c2ecf20Sopenharmony_ci last_lba = resize.last_lba; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci if (virt->hdr.flags & DK_CXLFLASH_UVIRTUAL_NEED_WRITE_SAME) 10538c2ecf20Sopenharmony_ci ctxi->rht_needs_ws[rsrc_handle] = true; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci virt->hdr.return_flags = 0; 10568c2ecf20Sopenharmony_ci virt->last_lba = last_lba; 10578c2ecf20Sopenharmony_ci virt->rsrc_handle = rsrc_handle; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci if (get_num_ports(lli->port_sel) > 1) 10608c2ecf20Sopenharmony_ci virt->hdr.return_flags |= DK_CXLFLASH_ALL_PORTS_ACTIVE; 10618c2ecf20Sopenharmony_ciout: 10628c2ecf20Sopenharmony_ci if (likely(ctxi)) 10638c2ecf20Sopenharmony_ci put_context(ctxi); 10648c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: returning handle=%llu rc=%d llba=%llu\n", 10658c2ecf20Sopenharmony_ci __func__, rsrc_handle, rc, last_lba); 10668c2ecf20Sopenharmony_ci return rc; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_cierr2: 10698c2ecf20Sopenharmony_ci rhte_checkin(ctxi, rhte); 10708c2ecf20Sopenharmony_cierr1: 10718c2ecf20Sopenharmony_ci cxlflash_lun_detach(gli); 10728c2ecf20Sopenharmony_ci goto out; 10738c2ecf20Sopenharmony_cierr0: 10748c2ecf20Sopenharmony_ci /* Special common cleanup prior to successful LUN attach */ 10758c2ecf20Sopenharmony_ci cxlflash_ba_terminate(&gli->blka.ba_lun); 10768c2ecf20Sopenharmony_ci mutex_unlock(&gli->mutex); 10778c2ecf20Sopenharmony_ci goto out; 10788c2ecf20Sopenharmony_ci} 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci/** 10818c2ecf20Sopenharmony_ci * clone_lxt() - copies translation tables from source to destination RHTE 10828c2ecf20Sopenharmony_ci * @afu: AFU associated with the host. 10838c2ecf20Sopenharmony_ci * @blka: Block allocator associated with LUN. 10848c2ecf20Sopenharmony_ci * @ctxid: Context ID of context owning the RHTE. 10858c2ecf20Sopenharmony_ci * @rhndl: Resource handle associated with the RHTE. 10868c2ecf20Sopenharmony_ci * @rhte: Destination resource handle entry (RHTE). 10878c2ecf20Sopenharmony_ci * @rhte_src: Source resource handle entry (RHTE). 10888c2ecf20Sopenharmony_ci * 10898c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure 10908c2ecf20Sopenharmony_ci */ 10918c2ecf20Sopenharmony_cistatic int clone_lxt(struct afu *afu, 10928c2ecf20Sopenharmony_ci struct blka *blka, 10938c2ecf20Sopenharmony_ci ctx_hndl_t ctxid, 10948c2ecf20Sopenharmony_ci res_hndl_t rhndl, 10958c2ecf20Sopenharmony_ci struct sisl_rht_entry *rhte, 10968c2ecf20Sopenharmony_ci struct sisl_rht_entry *rhte_src) 10978c2ecf20Sopenharmony_ci{ 10988c2ecf20Sopenharmony_ci struct cxlflash_cfg *cfg = afu->parent; 10998c2ecf20Sopenharmony_ci struct device *dev = &cfg->dev->dev; 11008c2ecf20Sopenharmony_ci struct sisl_lxt_entry *lxt = NULL; 11018c2ecf20Sopenharmony_ci bool locked = false; 11028c2ecf20Sopenharmony_ci u32 ngrps; 11038c2ecf20Sopenharmony_ci u64 aun; /* chunk# allocated by block allocator */ 11048c2ecf20Sopenharmony_ci int j; 11058c2ecf20Sopenharmony_ci int i = 0; 11068c2ecf20Sopenharmony_ci int rc = 0; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci ngrps = LXT_NUM_GROUPS(rhte_src->lxt_cnt); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci if (ngrps) { 11118c2ecf20Sopenharmony_ci /* allocate new LXTs for clone */ 11128c2ecf20Sopenharmony_ci lxt = kzalloc((sizeof(*lxt) * LXT_GROUP_SIZE * ngrps), 11138c2ecf20Sopenharmony_ci GFP_KERNEL); 11148c2ecf20Sopenharmony_ci if (unlikely(!lxt)) { 11158c2ecf20Sopenharmony_ci rc = -ENOMEM; 11168c2ecf20Sopenharmony_ci goto out; 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci /* copy over */ 11208c2ecf20Sopenharmony_ci memcpy(lxt, rhte_src->lxt_start, 11218c2ecf20Sopenharmony_ci (sizeof(*lxt) * rhte_src->lxt_cnt)); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci /* clone the LBAs in block allocator via ref_cnt, note that the 11248c2ecf20Sopenharmony_ci * block allocator mutex must be held until it is established 11258c2ecf20Sopenharmony_ci * that this routine will complete without the need for a 11268c2ecf20Sopenharmony_ci * cleanup. 11278c2ecf20Sopenharmony_ci */ 11288c2ecf20Sopenharmony_ci mutex_lock(&blka->mutex); 11298c2ecf20Sopenharmony_ci locked = true; 11308c2ecf20Sopenharmony_ci for (i = 0; i < rhte_src->lxt_cnt; i++) { 11318c2ecf20Sopenharmony_ci aun = (lxt[i].rlba_base >> MC_CHUNK_SHIFT); 11328c2ecf20Sopenharmony_ci if (ba_clone(&blka->ba_lun, aun) == -1ULL) { 11338c2ecf20Sopenharmony_ci rc = -EIO; 11348c2ecf20Sopenharmony_ci goto err; 11358c2ecf20Sopenharmony_ci } 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci } 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci /* 11408c2ecf20Sopenharmony_ci * The following sequence is prescribed in the SISlite spec 11418c2ecf20Sopenharmony_ci * for syncing up with the AFU when adding LXT entries. 11428c2ecf20Sopenharmony_ci */ 11438c2ecf20Sopenharmony_ci dma_wmb(); /* Make LXT updates are visible */ 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci rhte->lxt_start = lxt; 11468c2ecf20Sopenharmony_ci dma_wmb(); /* Make RHT entry's LXT table update visible */ 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci rhte->lxt_cnt = rhte_src->lxt_cnt; 11498c2ecf20Sopenharmony_ci dma_wmb(); /* Make RHT entry's LXT table size update visible */ 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci rc = cxlflash_afu_sync(afu, ctxid, rhndl, AFU_LW_SYNC); 11528c2ecf20Sopenharmony_ci if (unlikely(rc)) { 11538c2ecf20Sopenharmony_ci rc = -EAGAIN; 11548c2ecf20Sopenharmony_ci goto err2; 11558c2ecf20Sopenharmony_ci } 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ciout: 11588c2ecf20Sopenharmony_ci if (locked) 11598c2ecf20Sopenharmony_ci mutex_unlock(&blka->mutex); 11608c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); 11618c2ecf20Sopenharmony_ci return rc; 11628c2ecf20Sopenharmony_cierr2: 11638c2ecf20Sopenharmony_ci /* Reset the RHTE */ 11648c2ecf20Sopenharmony_ci rhte->lxt_cnt = 0; 11658c2ecf20Sopenharmony_ci dma_wmb(); 11668c2ecf20Sopenharmony_ci rhte->lxt_start = NULL; 11678c2ecf20Sopenharmony_ci dma_wmb(); 11688c2ecf20Sopenharmony_cierr: 11698c2ecf20Sopenharmony_ci /* free the clones already made */ 11708c2ecf20Sopenharmony_ci for (j = 0; j < i; j++) { 11718c2ecf20Sopenharmony_ci aun = (lxt[j].rlba_base >> MC_CHUNK_SHIFT); 11728c2ecf20Sopenharmony_ci ba_free(&blka->ba_lun, aun); 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_ci kfree(lxt); 11758c2ecf20Sopenharmony_ci goto out; 11768c2ecf20Sopenharmony_ci} 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci/** 11798c2ecf20Sopenharmony_ci * cxlflash_disk_clone() - clone a context by making snapshot of another 11808c2ecf20Sopenharmony_ci * @sdev: SCSI device associated with LUN owning virtual LUN. 11818c2ecf20Sopenharmony_ci * @clone: Clone ioctl data structure. 11828c2ecf20Sopenharmony_ci * 11838c2ecf20Sopenharmony_ci * This routine effectively performs cxlflash_disk_open operation for each 11848c2ecf20Sopenharmony_ci * in-use virtual resource in the source context. Note that the destination 11858c2ecf20Sopenharmony_ci * context must be in pristine state and cannot have any resource handles 11868c2ecf20Sopenharmony_ci * open at the time of the clone. 11878c2ecf20Sopenharmony_ci * 11888c2ecf20Sopenharmony_ci * Return: 0 on success, -errno on failure 11898c2ecf20Sopenharmony_ci */ 11908c2ecf20Sopenharmony_ciint cxlflash_disk_clone(struct scsi_device *sdev, 11918c2ecf20Sopenharmony_ci struct dk_cxlflash_clone *clone) 11928c2ecf20Sopenharmony_ci{ 11938c2ecf20Sopenharmony_ci struct cxlflash_cfg *cfg = shost_priv(sdev->host); 11948c2ecf20Sopenharmony_ci struct device *dev = &cfg->dev->dev; 11958c2ecf20Sopenharmony_ci struct llun_info *lli = sdev->hostdata; 11968c2ecf20Sopenharmony_ci struct glun_info *gli = lli->parent; 11978c2ecf20Sopenharmony_ci struct blka *blka = &gli->blka; 11988c2ecf20Sopenharmony_ci struct afu *afu = cfg->afu; 11998c2ecf20Sopenharmony_ci struct dk_cxlflash_release release = { { 0 }, 0 }; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci struct ctx_info *ctxi_src = NULL, 12028c2ecf20Sopenharmony_ci *ctxi_dst = NULL; 12038c2ecf20Sopenharmony_ci struct lun_access *lun_access_src, *lun_access_dst; 12048c2ecf20Sopenharmony_ci u32 perms; 12058c2ecf20Sopenharmony_ci u64 ctxid_src = DECODE_CTXID(clone->context_id_src), 12068c2ecf20Sopenharmony_ci ctxid_dst = DECODE_CTXID(clone->context_id_dst), 12078c2ecf20Sopenharmony_ci rctxid_src = clone->context_id_src, 12088c2ecf20Sopenharmony_ci rctxid_dst = clone->context_id_dst; 12098c2ecf20Sopenharmony_ci int i, j; 12108c2ecf20Sopenharmony_ci int rc = 0; 12118c2ecf20Sopenharmony_ci bool found; 12128c2ecf20Sopenharmony_ci LIST_HEAD(sidecar); 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: ctxid_src=%llu ctxid_dst=%llu\n", 12158c2ecf20Sopenharmony_ci __func__, ctxid_src, ctxid_dst); 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci /* Do not clone yourself */ 12188c2ecf20Sopenharmony_ci if (unlikely(rctxid_src == rctxid_dst)) { 12198c2ecf20Sopenharmony_ci rc = -EINVAL; 12208c2ecf20Sopenharmony_ci goto out; 12218c2ecf20Sopenharmony_ci } 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci if (unlikely(gli->mode != MODE_VIRTUAL)) { 12248c2ecf20Sopenharmony_ci rc = -EINVAL; 12258c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: Only supported on virtual LUNs mode=%u\n", 12268c2ecf20Sopenharmony_ci __func__, gli->mode); 12278c2ecf20Sopenharmony_ci goto out; 12288c2ecf20Sopenharmony_ci } 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci ctxi_src = get_context(cfg, rctxid_src, lli, CTX_CTRL_CLONE); 12318c2ecf20Sopenharmony_ci ctxi_dst = get_context(cfg, rctxid_dst, lli, 0); 12328c2ecf20Sopenharmony_ci if (unlikely(!ctxi_src || !ctxi_dst)) { 12338c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: Bad context ctxid_src=%llu ctxid_dst=%llu\n", 12348c2ecf20Sopenharmony_ci __func__, ctxid_src, ctxid_dst); 12358c2ecf20Sopenharmony_ci rc = -EINVAL; 12368c2ecf20Sopenharmony_ci goto out; 12378c2ecf20Sopenharmony_ci } 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci /* Verify there is no open resource handle in the destination context */ 12408c2ecf20Sopenharmony_ci for (i = 0; i < MAX_RHT_PER_CONTEXT; i++) 12418c2ecf20Sopenharmony_ci if (ctxi_dst->rht_start[i].nmask != 0) { 12428c2ecf20Sopenharmony_ci rc = -EINVAL; 12438c2ecf20Sopenharmony_ci goto out; 12448c2ecf20Sopenharmony_ci } 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci /* Clone LUN access list */ 12478c2ecf20Sopenharmony_ci list_for_each_entry(lun_access_src, &ctxi_src->luns, list) { 12488c2ecf20Sopenharmony_ci found = false; 12498c2ecf20Sopenharmony_ci list_for_each_entry(lun_access_dst, &ctxi_dst->luns, list) 12508c2ecf20Sopenharmony_ci if (lun_access_dst->sdev == lun_access_src->sdev) { 12518c2ecf20Sopenharmony_ci found = true; 12528c2ecf20Sopenharmony_ci break; 12538c2ecf20Sopenharmony_ci } 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci if (!found) { 12568c2ecf20Sopenharmony_ci lun_access_dst = kzalloc(sizeof(*lun_access_dst), 12578c2ecf20Sopenharmony_ci GFP_KERNEL); 12588c2ecf20Sopenharmony_ci if (unlikely(!lun_access_dst)) { 12598c2ecf20Sopenharmony_ci dev_err(dev, "%s: lun_access allocation fail\n", 12608c2ecf20Sopenharmony_ci __func__); 12618c2ecf20Sopenharmony_ci rc = -ENOMEM; 12628c2ecf20Sopenharmony_ci goto out; 12638c2ecf20Sopenharmony_ci } 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci *lun_access_dst = *lun_access_src; 12668c2ecf20Sopenharmony_ci list_add(&lun_access_dst->list, &sidecar); 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci } 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci if (unlikely(!ctxi_src->rht_out)) { 12718c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: Nothing to clone\n", __func__); 12728c2ecf20Sopenharmony_ci goto out_success; 12738c2ecf20Sopenharmony_ci } 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci /* User specified permission on attach */ 12768c2ecf20Sopenharmony_ci perms = ctxi_dst->rht_perms; 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci /* 12798c2ecf20Sopenharmony_ci * Copy over checked-out RHT (and their associated LXT) entries by 12808c2ecf20Sopenharmony_ci * hand, stopping after we've copied all outstanding entries and 12818c2ecf20Sopenharmony_ci * cleaning up if the clone fails. 12828c2ecf20Sopenharmony_ci * 12838c2ecf20Sopenharmony_ci * Note: This loop is equivalent to performing cxlflash_disk_open and 12848c2ecf20Sopenharmony_ci * cxlflash_vlun_resize. As such, LUN accounting needs to be taken into 12858c2ecf20Sopenharmony_ci * account by attaching after each successful RHT entry clone. In the 12868c2ecf20Sopenharmony_ci * event that a clone failure is experienced, the LUN detach is handled 12878c2ecf20Sopenharmony_ci * via the cleanup performed by _cxlflash_disk_release. 12888c2ecf20Sopenharmony_ci */ 12898c2ecf20Sopenharmony_ci for (i = 0; i < MAX_RHT_PER_CONTEXT; i++) { 12908c2ecf20Sopenharmony_ci if (ctxi_src->rht_out == ctxi_dst->rht_out) 12918c2ecf20Sopenharmony_ci break; 12928c2ecf20Sopenharmony_ci if (ctxi_src->rht_start[i].nmask == 0) 12938c2ecf20Sopenharmony_ci continue; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci /* Consume a destination RHT entry */ 12968c2ecf20Sopenharmony_ci ctxi_dst->rht_out++; 12978c2ecf20Sopenharmony_ci ctxi_dst->rht_start[i].nmask = ctxi_src->rht_start[i].nmask; 12988c2ecf20Sopenharmony_ci ctxi_dst->rht_start[i].fp = 12998c2ecf20Sopenharmony_ci SISL_RHT_FP_CLONE(ctxi_src->rht_start[i].fp, perms); 13008c2ecf20Sopenharmony_ci ctxi_dst->rht_lun[i] = ctxi_src->rht_lun[i]; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci rc = clone_lxt(afu, blka, ctxid_dst, i, 13038c2ecf20Sopenharmony_ci &ctxi_dst->rht_start[i], 13048c2ecf20Sopenharmony_ci &ctxi_src->rht_start[i]); 13058c2ecf20Sopenharmony_ci if (rc) { 13068c2ecf20Sopenharmony_ci marshal_clone_to_rele(clone, &release); 13078c2ecf20Sopenharmony_ci for (j = 0; j < i; j++) { 13088c2ecf20Sopenharmony_ci release.rsrc_handle = j; 13098c2ecf20Sopenharmony_ci _cxlflash_disk_release(sdev, ctxi_dst, 13108c2ecf20Sopenharmony_ci &release); 13118c2ecf20Sopenharmony_ci } 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci /* Put back the one we failed on */ 13148c2ecf20Sopenharmony_ci rhte_checkin(ctxi_dst, &ctxi_dst->rht_start[i]); 13158c2ecf20Sopenharmony_ci goto err; 13168c2ecf20Sopenharmony_ci } 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci cxlflash_lun_attach(gli, gli->mode, false); 13198c2ecf20Sopenharmony_ci } 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ciout_success: 13228c2ecf20Sopenharmony_ci list_splice(&sidecar, &ctxi_dst->luns); 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci /* fall through */ 13258c2ecf20Sopenharmony_ciout: 13268c2ecf20Sopenharmony_ci if (ctxi_src) 13278c2ecf20Sopenharmony_ci put_context(ctxi_src); 13288c2ecf20Sopenharmony_ci if (ctxi_dst) 13298c2ecf20Sopenharmony_ci put_context(ctxi_dst); 13308c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); 13318c2ecf20Sopenharmony_ci return rc; 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_cierr: 13348c2ecf20Sopenharmony_ci list_for_each_entry_safe(lun_access_src, lun_access_dst, &sidecar, list) 13358c2ecf20Sopenharmony_ci kfree(lun_access_src); 13368c2ecf20Sopenharmony_ci goto out; 13378c2ecf20Sopenharmony_ci} 1338