Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * CXL Flash Device Driver
0004  *
0005  * Written by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>, IBM Corporation
0006  *             Matthew R. Ochs <mrochs@linux.vnet.ibm.com>, IBM Corporation
0007  *
0008  * Copyright (C) 2015 IBM Corporation
0009  */
0010 
0011 #include <asm/unaligned.h>
0012 
0013 #include <linux/interrupt.h>
0014 #include <linux/pci.h>
0015 
0016 #include <scsi/scsi_host.h>
0017 #include <uapi/scsi/cxlflash_ioctl.h>
0018 
0019 #include "sislite.h"
0020 #include "common.h"
0021 #include "vlun.h"
0022 #include "superpipe.h"
0023 
0024 /**
0025  * create_local() - allocate and initialize a local LUN information structure
0026  * @sdev:   SCSI device associated with LUN.
0027  * @wwid:   World Wide Node Name for LUN.
0028  *
0029  * Return: Allocated local llun_info structure on success, NULL on failure
0030  */
0031 static struct llun_info *create_local(struct scsi_device *sdev, u8 *wwid)
0032 {
0033     struct cxlflash_cfg *cfg = shost_priv(sdev->host);
0034     struct device *dev = &cfg->dev->dev;
0035     struct llun_info *lli = NULL;
0036 
0037     lli = kzalloc(sizeof(*lli), GFP_KERNEL);
0038     if (unlikely(!lli)) {
0039         dev_err(dev, "%s: could not allocate lli\n", __func__);
0040         goto out;
0041     }
0042 
0043     lli->sdev = sdev;
0044     lli->host_no = sdev->host->host_no;
0045     lli->in_table = false;
0046 
0047     memcpy(lli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN);
0048 out:
0049     return lli;
0050 }
0051 
0052 /**
0053  * create_global() - allocate and initialize a global LUN information structure
0054  * @sdev:   SCSI device associated with LUN.
0055  * @wwid:   World Wide Node Name for LUN.
0056  *
0057  * Return: Allocated global glun_info structure on success, NULL on failure
0058  */
0059 static struct glun_info *create_global(struct scsi_device *sdev, u8 *wwid)
0060 {
0061     struct cxlflash_cfg *cfg = shost_priv(sdev->host);
0062     struct device *dev = &cfg->dev->dev;
0063     struct glun_info *gli = NULL;
0064 
0065     gli = kzalloc(sizeof(*gli), GFP_KERNEL);
0066     if (unlikely(!gli)) {
0067         dev_err(dev, "%s: could not allocate gli\n", __func__);
0068         goto out;
0069     }
0070 
0071     mutex_init(&gli->mutex);
0072     memcpy(gli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN);
0073 out:
0074     return gli;
0075 }
0076 
0077 /**
0078  * lookup_local() - find a local LUN information structure by WWID
0079  * @cfg:    Internal structure associated with the host.
0080  * @wwid:   WWID associated with LUN.
0081  *
0082  * Return: Found local lun_info structure on success, NULL on failure
0083  */
0084 static struct llun_info *lookup_local(struct cxlflash_cfg *cfg, u8 *wwid)
0085 {
0086     struct llun_info *lli, *temp;
0087 
0088     list_for_each_entry_safe(lli, temp, &cfg->lluns, list)
0089         if (!memcmp(lli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN))
0090             return lli;
0091 
0092     return NULL;
0093 }
0094 
0095 /**
0096  * lookup_global() - find a global LUN information structure by WWID
0097  * @wwid:   WWID associated with LUN.
0098  *
0099  * Return: Found global lun_info structure on success, NULL on failure
0100  */
0101 static struct glun_info *lookup_global(u8 *wwid)
0102 {
0103     struct glun_info *gli, *temp;
0104 
0105     list_for_each_entry_safe(gli, temp, &global.gluns, list)
0106         if (!memcmp(gli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN))
0107             return gli;
0108 
0109     return NULL;
0110 }
0111 
0112 /**
0113  * find_and_create_lun() - find or create a local LUN information structure
0114  * @sdev:   SCSI device associated with LUN.
0115  * @wwid:   WWID associated with LUN.
0116  *
0117  * The LUN is kept both in a local list (per adapter) and in a global list
0118  * (across all adapters). Certain attributes of the LUN are local to the
0119  * adapter (such as index, port selection mask, etc.).
0120  *
0121  * The block allocation map is shared across all adapters (i.e. associated
0122  * wih the global list). Since different attributes are associated with
0123  * the per adapter and global entries, allocate two separate structures for each
0124  * LUN (one local, one global).
0125  *
0126  * Keep a pointer back from the local to the global entry.
0127  *
0128  * This routine assumes the caller holds the global mutex.
0129  *
0130  * Return: Found/Allocated local lun_info structure on success, NULL on failure
0131  */
0132 static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid)
0133 {
0134     struct cxlflash_cfg *cfg = shost_priv(sdev->host);
0135     struct device *dev = &cfg->dev->dev;
0136     struct llun_info *lli = NULL;
0137     struct glun_info *gli = NULL;
0138 
0139     if (unlikely(!wwid))
0140         goto out;
0141 
0142     lli = lookup_local(cfg, wwid);
0143     if (lli)
0144         goto out;
0145 
0146     lli = create_local(sdev, wwid);
0147     if (unlikely(!lli))
0148         goto out;
0149 
0150     gli = lookup_global(wwid);
0151     if (gli) {
0152         lli->parent = gli;
0153         list_add(&lli->list, &cfg->lluns);
0154         goto out;
0155     }
0156 
0157     gli = create_global(sdev, wwid);
0158     if (unlikely(!gli)) {
0159         kfree(lli);
0160         lli = NULL;
0161         goto out;
0162     }
0163 
0164     lli->parent = gli;
0165     list_add(&lli->list, &cfg->lluns);
0166 
0167     list_add(&gli->list, &global.gluns);
0168 
0169 out:
0170     dev_dbg(dev, "%s: returning lli=%p, gli=%p\n", __func__, lli, gli);
0171     return lli;
0172 }
0173 
0174 /**
0175  * cxlflash_term_local_luns() - Delete all entries from local LUN list, free.
0176  * @cfg:    Internal structure associated with the host.
0177  */
0178 void cxlflash_term_local_luns(struct cxlflash_cfg *cfg)
0179 {
0180     struct llun_info *lli, *temp;
0181 
0182     mutex_lock(&global.mutex);
0183     list_for_each_entry_safe(lli, temp, &cfg->lluns, list) {
0184         list_del(&lli->list);
0185         kfree(lli);
0186     }
0187     mutex_unlock(&global.mutex);
0188 }
0189 
0190 /**
0191  * cxlflash_list_init() - initializes the global LUN list
0192  */
0193 void cxlflash_list_init(void)
0194 {
0195     INIT_LIST_HEAD(&global.gluns);
0196     mutex_init(&global.mutex);
0197     global.err_page = NULL;
0198 }
0199 
0200 /**
0201  * cxlflash_term_global_luns() - frees resources associated with global LUN list
0202  */
0203 void cxlflash_term_global_luns(void)
0204 {
0205     struct glun_info *gli, *temp;
0206 
0207     mutex_lock(&global.mutex);
0208     list_for_each_entry_safe(gli, temp, &global.gluns, list) {
0209         list_del(&gli->list);
0210         cxlflash_ba_terminate(&gli->blka.ba_lun);
0211         kfree(gli);
0212     }
0213     mutex_unlock(&global.mutex);
0214 }
0215 
0216 /**
0217  * cxlflash_manage_lun() - handles LUN management activities
0218  * @sdev:   SCSI device associated with LUN.
0219  * @manage: Manage ioctl data structure.
0220  *
0221  * This routine is used to notify the driver about a LUN's WWID and associate
0222  * SCSI devices (sdev) with a global LUN instance. Additionally it serves to
0223  * change a LUN's operating mode: legacy or superpipe.
0224  *
0225  * Return: 0 on success, -errno on failure
0226  */
0227 int cxlflash_manage_lun(struct scsi_device *sdev,
0228             struct dk_cxlflash_manage_lun *manage)
0229 {
0230     struct cxlflash_cfg *cfg = shost_priv(sdev->host);
0231     struct device *dev = &cfg->dev->dev;
0232     struct llun_info *lli = NULL;
0233     int rc = 0;
0234     u64 flags = manage->hdr.flags;
0235     u32 chan = sdev->channel;
0236 
0237     mutex_lock(&global.mutex);
0238     lli = find_and_create_lun(sdev, manage->wwid);
0239     dev_dbg(dev, "%s: WWID=%016llx%016llx, flags=%016llx lli=%p\n",
0240         __func__, get_unaligned_be64(&manage->wwid[0]),
0241         get_unaligned_be64(&manage->wwid[8]), manage->hdr.flags, lli);
0242     if (unlikely(!lli)) {
0243         rc = -ENOMEM;
0244         goto out;
0245     }
0246 
0247     if (flags & DK_CXLFLASH_MANAGE_LUN_ENABLE_SUPERPIPE) {
0248         /*
0249          * Update port selection mask based upon channel, store off LUN
0250          * in unpacked, AFU-friendly format, and hang LUN reference in
0251          * the sdev.
0252          */
0253         lli->port_sel |= CHAN2PORTMASK(chan);
0254         lli->lun_id[chan] = lun_to_lunid(sdev->lun);
0255         sdev->hostdata = lli;
0256     } else if (flags & DK_CXLFLASH_MANAGE_LUN_DISABLE_SUPERPIPE) {
0257         if (lli->parent->mode != MODE_NONE)
0258             rc = -EBUSY;
0259         else {
0260             /*
0261              * Clean up local LUN for this port and reset table
0262              * tracking when no more references exist.
0263              */
0264             sdev->hostdata = NULL;
0265             lli->port_sel &= ~CHAN2PORTMASK(chan);
0266             if (lli->port_sel == 0U)
0267                 lli->in_table = false;
0268         }
0269     }
0270 
0271     dev_dbg(dev, "%s: port_sel=%08x chan=%u lun_id=%016llx\n",
0272         __func__, lli->port_sel, chan, lli->lun_id[chan]);
0273 
0274 out:
0275     mutex_unlock(&global.mutex);
0276     dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc);
0277     return rc;
0278 }