cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

lunmgt.c (7369B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * CXL Flash Device Driver
      4 *
      5 * Written by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>, IBM Corporation
      6 *             Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation
      7 *
      8 * Copyright (C) 2015 IBM Corporation
      9 */
     10
     11#include <asm/unaligned.h>
     12
     13#include <linux/interrupt.h>
     14#include <linux/pci.h>
     15
     16#include <scsi/scsi_host.h>
     17#include <uapi/scsi/cxlflash_ioctl.h>
     18
     19#include "sislite.h"
     20#include "common.h"
     21#include "vlun.h"
     22#include "superpipe.h"
     23
     24/**
     25 * create_local() - allocate and initialize a local LUN information structure
     26 * @sdev:	SCSI device associated with LUN.
     27 * @wwid:	World Wide Node Name for LUN.
     28 *
     29 * Return: Allocated local llun_info structure on success, NULL on failure
     30 */
     31static struct llun_info *create_local(struct scsi_device *sdev, u8 *wwid)
     32{
     33	struct cxlflash_cfg *cfg = shost_priv(sdev->host);
     34	struct device *dev = &cfg->dev->dev;
     35	struct llun_info *lli = NULL;
     36
     37	lli = kzalloc(sizeof(*lli), GFP_KERNEL);
     38	if (unlikely(!lli)) {
     39		dev_err(dev, "%s: could not allocate lli\n", __func__);
     40		goto out;
     41	}
     42
     43	lli->sdev = sdev;
     44	lli->host_no = sdev->host->host_no;
     45	lli->in_table = false;
     46
     47	memcpy(lli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN);
     48out:
     49	return lli;
     50}
     51
     52/**
     53 * create_global() - allocate and initialize a global LUN information structure
     54 * @sdev:	SCSI device associated with LUN.
     55 * @wwid:	World Wide Node Name for LUN.
     56 *
     57 * Return: Allocated global glun_info structure on success, NULL on failure
     58 */
     59static struct glun_info *create_global(struct scsi_device *sdev, u8 *wwid)
     60{
     61	struct cxlflash_cfg *cfg = shost_priv(sdev->host);
     62	struct device *dev = &cfg->dev->dev;
     63	struct glun_info *gli = NULL;
     64
     65	gli = kzalloc(sizeof(*gli), GFP_KERNEL);
     66	if (unlikely(!gli)) {
     67		dev_err(dev, "%s: could not allocate gli\n", __func__);
     68		goto out;
     69	}
     70
     71	mutex_init(&gli->mutex);
     72	memcpy(gli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN);
     73out:
     74	return gli;
     75}
     76
     77/**
     78 * lookup_local() - find a local LUN information structure by WWID
     79 * @cfg:	Internal structure associated with the host.
     80 * @wwid:	WWID associated with LUN.
     81 *
     82 * Return: Found local lun_info structure on success, NULL on failure
     83 */
     84static struct llun_info *lookup_local(struct cxlflash_cfg *cfg, u8 *wwid)
     85{
     86	struct llun_info *lli, *temp;
     87
     88	list_for_each_entry_safe(lli, temp, &cfg->lluns, list)
     89		if (!memcmp(lli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN))
     90			return lli;
     91
     92	return NULL;
     93}
     94
     95/**
     96 * lookup_global() - find a global LUN information structure by WWID
     97 * @wwid:	WWID associated with LUN.
     98 *
     99 * Return: Found global lun_info structure on success, NULL on failure
    100 */
    101static struct glun_info *lookup_global(u8 *wwid)
    102{
    103	struct glun_info *gli, *temp;
    104
    105	list_for_each_entry_safe(gli, temp, &global.gluns, list)
    106		if (!memcmp(gli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN))
    107			return gli;
    108
    109	return NULL;
    110}
    111
    112/**
    113 * find_and_create_lun() - find or create a local LUN information structure
    114 * @sdev:	SCSI device associated with LUN.
    115 * @wwid:	WWID associated with LUN.
    116 *
    117 * The LUN is kept both in a local list (per adapter) and in a global list
    118 * (across all adapters). Certain attributes of the LUN are local to the
    119 * adapter (such as index, port selection mask, etc.).
    120 *
    121 * The block allocation map is shared across all adapters (i.e. associated
    122 * wih the global list). Since different attributes are associated with
    123 * the per adapter and global entries, allocate two separate structures for each
    124 * LUN (one local, one global).
    125 *
    126 * Keep a pointer back from the local to the global entry.
    127 *
    128 * This routine assumes the caller holds the global mutex.
    129 *
    130 * Return: Found/Allocated local lun_info structure on success, NULL on failure
    131 */
    132static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid)
    133{
    134	struct cxlflash_cfg *cfg = shost_priv(sdev->host);
    135	struct device *dev = &cfg->dev->dev;
    136	struct llun_info *lli = NULL;
    137	struct glun_info *gli = NULL;
    138
    139	if (unlikely(!wwid))
    140		goto out;
    141
    142	lli = lookup_local(cfg, wwid);
    143	if (lli)
    144		goto out;
    145
    146	lli = create_local(sdev, wwid);
    147	if (unlikely(!lli))
    148		goto out;
    149
    150	gli = lookup_global(wwid);
    151	if (gli) {
    152		lli->parent = gli;
    153		list_add(&lli->list, &cfg->lluns);
    154		goto out;
    155	}
    156
    157	gli = create_global(sdev, wwid);
    158	if (unlikely(!gli)) {
    159		kfree(lli);
    160		lli = NULL;
    161		goto out;
    162	}
    163
    164	lli->parent = gli;
    165	list_add(&lli->list, &cfg->lluns);
    166
    167	list_add(&gli->list, &global.gluns);
    168
    169out:
    170	dev_dbg(dev, "%s: returning lli=%p, gli=%p\n", __func__, lli, gli);
    171	return lli;
    172}
    173
    174/**
    175 * cxlflash_term_local_luns() - Delete all entries from local LUN list, free.
    176 * @cfg:	Internal structure associated with the host.
    177 */
    178void cxlflash_term_local_luns(struct cxlflash_cfg *cfg)
    179{
    180	struct llun_info *lli, *temp;
    181
    182	mutex_lock(&global.mutex);
    183	list_for_each_entry_safe(lli, temp, &cfg->lluns, list) {
    184		list_del(&lli->list);
    185		kfree(lli);
    186	}
    187	mutex_unlock(&global.mutex);
    188}
    189
    190/**
    191 * cxlflash_list_init() - initializes the global LUN list
    192 */
    193void cxlflash_list_init(void)
    194{
    195	INIT_LIST_HEAD(&global.gluns);
    196	mutex_init(&global.mutex);
    197	global.err_page = NULL;
    198}
    199
    200/**
    201 * cxlflash_term_global_luns() - frees resources associated with global LUN list
    202 */
    203void cxlflash_term_global_luns(void)
    204{
    205	struct glun_info *gli, *temp;
    206
    207	mutex_lock(&global.mutex);
    208	list_for_each_entry_safe(gli, temp, &global.gluns, list) {
    209		list_del(&gli->list);
    210		cxlflash_ba_terminate(&gli->blka.ba_lun);
    211		kfree(gli);
    212	}
    213	mutex_unlock(&global.mutex);
    214}
    215
    216/**
    217 * cxlflash_manage_lun() - handles LUN management activities
    218 * @sdev:	SCSI device associated with LUN.
    219 * @manage:	Manage ioctl data structure.
    220 *
    221 * This routine is used to notify the driver about a LUN's WWID and associate
    222 * SCSI devices (sdev) with a global LUN instance. Additionally it serves to
    223 * change a LUN's operating mode: legacy or superpipe.
    224 *
    225 * Return: 0 on success, -errno on failure
    226 */
    227int cxlflash_manage_lun(struct scsi_device *sdev,
    228			struct dk_cxlflash_manage_lun *manage)
    229{
    230	struct cxlflash_cfg *cfg = shost_priv(sdev->host);
    231	struct device *dev = &cfg->dev->dev;
    232	struct llun_info *lli = NULL;
    233	int rc = 0;
    234	u64 flags = manage->hdr.flags;
    235	u32 chan = sdev->channel;
    236
    237	mutex_lock(&global.mutex);
    238	lli = find_and_create_lun(sdev, manage->wwid);
    239	dev_dbg(dev, "%s: WWID=%016llx%016llx, flags=%016llx lli=%p\n",
    240		__func__, get_unaligned_be64(&manage->wwid[0]),
    241		get_unaligned_be64(&manage->wwid[8]), manage->hdr.flags, lli);
    242	if (unlikely(!lli)) {
    243		rc = -ENOMEM;
    244		goto out;
    245	}
    246
    247	if (flags & DK_CXLFLASH_MANAGE_LUN_ENABLE_SUPERPIPE) {
    248		/*
    249		 * Update port selection mask based upon channel, store off LUN
    250		 * in unpacked, AFU-friendly format, and hang LUN reference in
    251		 * the sdev.
    252		 */
    253		lli->port_sel |= CHAN2PORTMASK(chan);
    254		lli->lun_id[chan] = lun_to_lunid(sdev->lun);
    255		sdev->hostdata = lli;
    256	} else if (flags & DK_CXLFLASH_MANAGE_LUN_DISABLE_SUPERPIPE) {
    257		if (lli->parent->mode != MODE_NONE)
    258			rc = -EBUSY;
    259		else {
    260			/*
    261			 * Clean up local LUN for this port and reset table
    262			 * tracking when no more references exist.
    263			 */
    264			sdev->hostdata = NULL;
    265			lli->port_sel &= ~CHAN2PORTMASK(chan);
    266			if (lli->port_sel == 0U)
    267				lli->in_table = false;
    268		}
    269	}
    270
    271	dev_dbg(dev, "%s: port_sel=%08x chan=%u lun_id=%016llx\n",
    272		__func__, lli->port_sel, chan, lli->lun_id[chan]);
    273
    274out:
    275	mutex_unlock(&global.mutex);
    276	dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
    277	return rc;
    278}