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