aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew R. Ochs <mrochs@linux.vnet.ibm.com>2015-10-21 16:16:15 -0400
committerJames Bottomley <JBottomley@Odin.com>2015-10-30 04:23:55 -0400
commit1a47401bb397183e0500db2c7d5f8d2a3506598e (patch)
tree484fd193fca6695a44cfbdb0d204eb9bbdfa8fb3
parente6e6df3f71a0b567e55d17b08f5bad8f1043afa3 (diff)
cxlflash: Fix to avoid corrupting port selection mask
The port selection mask of a LUN can be corrupted when the manage LUN ioctl (DK_CXLFLASH_MANAGE_LUN) is issued more than once for any device. This mask indicates to the AFU which port[s] can be used for a data transfer to/from a particular LUN. The mask is critical to ensuring the correct behavior when using the virtual LUN function of this adapter. When the mask is configured for both ports, an I/O may be sent to either port as the AFU assumes that each port has access to the same physical device (specified by LUN ID in the port LUN table). In a situation where the mask becomes incorrectly configured to reflect access to both ports when in fact there is only access through a single port, an I/O can be targeted to the wrong physical device. This can lead to data corruption among other ill effects (e.g. security leaks). The cause for this corruption is the assumption that the ioctl will only be called a second time for a LUN when it is being configured for access via a second port. A boolean 'newly_created' variable is used to differentiate between a LUN that was created (and subsequently configured for single port access) and one that is destined for access across both ports. While initially set to 'true', this sticky boolean is toggled to the 'false' state during a lookup on any next ioctl performed on a device with a matching WWN/WWID. The code fails to realize that the match could in fact be the same device calling in again. From here, an assumption is made that any LUN with 'newly_created' set to 'false' is configured for access over both ports and the port selection mask is set to reflect this. Any future attempts to use this LUN for hosting a virtual LUN will result in the port LUN table being incorrectly programmed. As a remedy, the 'newly_created' concept was removed entirely and replaced with code that always constructs the port selection mask based upon the SCSI channel of the LUN being accessed. The bits remain sticky, therefore allowing for a device to be accessed over both ports when that is in fact the correct physical configuration. Also included in this commit are a few minor related changes to enhance the fix and provide better debug information for port selection mask and port LUN table bugs in the future. These include renaming refresh_local() to lookup_local(), tracing the WWN/WWID as a big-endian entity, and tracing the port selection mask, SCSI channel, and LUN ID each time the port LUN table is programmed. Signed-off-by: Matthew R. Ochs <mrochs@linux.vnet.ibm.com> Acked-by: Manoj Kumar <manoj@linux.vnet.ibm.com> Reviewed-by: Andrew Donnellan <andrew.donnellan@au1.ibm.com> Signed-off-by: James Bottomley <JBottomley@Odin.com>
-rw-r--r--drivers/scsi/cxlflash/lunmgt.c36
-rw-r--r--drivers/scsi/cxlflash/superpipe.h1
2 files changed, 18 insertions, 19 deletions
diff --git a/drivers/scsi/cxlflash/lunmgt.c b/drivers/scsi/cxlflash/lunmgt.c
index 8c372fc73e1f..a0923cade6f3 100644
--- a/drivers/scsi/cxlflash/lunmgt.c
+++ b/drivers/scsi/cxlflash/lunmgt.c
@@ -41,7 +41,6 @@ static struct llun_info *create_local(struct scsi_device *sdev, u8 *wwid)
41 } 41 }
42 42
43 lli->sdev = sdev; 43 lli->sdev = sdev;
44 lli->newly_created = true;
45 lli->host_no = sdev->host->host_no; 44 lli->host_no = sdev->host->host_no;
46 lli->in_table = false; 45 lli->in_table = false;
47 46
@@ -74,24 +73,19 @@ out:
74} 73}
75 74
76/** 75/**
77 * refresh_local() - find and update local LUN information structure by WWID 76 * lookup_local() - find a local LUN information structure by WWID
78 * @cfg: Internal structure associated with the host. 77 * @cfg: Internal structure associated with the host.
79 * @wwid: WWID associated with LUN. 78 * @wwid: WWID associated with LUN.
80 * 79 *
81 * When the LUN is found, mark it by updating it's newly_created field.
82 *
83 * Return: Found local lun_info structure on success, NULL on failure 80 * Return: Found local lun_info structure on success, NULL on failure
84 * If a LUN with the WWID is found in the list, refresh it's state.
85 */ 81 */
86static struct llun_info *refresh_local(struct cxlflash_cfg *cfg, u8 *wwid) 82static struct llun_info *lookup_local(struct cxlflash_cfg *cfg, u8 *wwid)
87{ 83{
88 struct llun_info *lli, *temp; 84 struct llun_info *lli, *temp;
89 85
90 list_for_each_entry_safe(lli, temp, &cfg->lluns, list) 86 list_for_each_entry_safe(lli, temp, &cfg->lluns, list)
91 if (!memcmp(lli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN)) { 87 if (!memcmp(lli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN))
92 lli->newly_created = false;
93 return lli; 88 return lli;
94 }
95 89
96 return NULL; 90 return NULL;
97} 91}
@@ -143,7 +137,7 @@ static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid)
143 if (unlikely(!wwid)) 137 if (unlikely(!wwid))
144 goto out; 138 goto out;
145 139
146 lli = refresh_local(cfg, wwid); 140 lli = lookup_local(cfg, wwid);
147 if (lli) 141 if (lli)
148 goto out; 142 goto out;
149 143
@@ -239,8 +233,8 @@ int cxlflash_manage_lun(struct scsi_device *sdev,
239 mutex_lock(&global.mutex); 233 mutex_lock(&global.mutex);
240 lli = find_and_create_lun(sdev, manage->wwid); 234 lli = find_and_create_lun(sdev, manage->wwid);
241 pr_debug("%s: ENTER: WWID = %016llX%016llX, flags = %016llX li = %p\n", 235 pr_debug("%s: ENTER: WWID = %016llX%016llX, flags = %016llX li = %p\n",
242 __func__, get_unaligned_le64(&manage->wwid[0]), 236 __func__, get_unaligned_be64(&manage->wwid[0]),
243 get_unaligned_le64(&manage->wwid[8]), 237 get_unaligned_be64(&manage->wwid[8]),
244 manage->hdr.flags, lli); 238 manage->hdr.flags, lli);
245 if (unlikely(!lli)) { 239 if (unlikely(!lli)) {
246 rc = -ENOMEM; 240 rc = -ENOMEM;
@@ -248,20 +242,26 @@ int cxlflash_manage_lun(struct scsi_device *sdev,
248 } 242 }
249 243
250 if (flags & DK_CXLFLASH_MANAGE_LUN_ENABLE_SUPERPIPE) { 244 if (flags & DK_CXLFLASH_MANAGE_LUN_ENABLE_SUPERPIPE) {
251 if (lli->newly_created) 245 /*
252 lli->port_sel = CHAN2PORT(chan); 246 * Update port selection mask based upon channel, store off LUN
253 else 247 * in unpacked, AFU-friendly format, and hang LUN reference in
254 lli->port_sel = BOTH_PORTS; 248 * the sdev.
255 /* Store off lun in unpacked, AFU-friendly format */ 249 */
250 lli->port_sel |= CHAN2PORT(chan);
256 lli->lun_id[chan] = lun_to_lunid(sdev->lun); 251 lli->lun_id[chan] = lun_to_lunid(sdev->lun);
257 sdev->hostdata = lli; 252 sdev->hostdata = lli;
258 } else if (flags & DK_CXLFLASH_MANAGE_LUN_DISABLE_SUPERPIPE) { 253 } else if (flags & DK_CXLFLASH_MANAGE_LUN_DISABLE_SUPERPIPE) {
259 if (lli->parent->mode != MODE_NONE) 254 if (lli->parent->mode != MODE_NONE)
260 rc = -EBUSY; 255 rc = -EBUSY;
261 else 256 else {
262 sdev->hostdata = NULL; 257 sdev->hostdata = NULL;
258 lli->port_sel &= ~CHAN2PORT(chan);
259 }
263 } 260 }
264 261
262 pr_debug("%s: port_sel = %08X chan = %u lun_id = %016llX\n", __func__,
263 lli->port_sel, chan, lli->lun_id[chan]);
264
265out: 265out:
266 mutex_unlock(&global.mutex); 266 mutex_unlock(&global.mutex);
267 pr_debug("%s: returning rc=%d\n", __func__, rc); 267 pr_debug("%s: returning rc=%d\n", __func__, rc);
diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h
index 06a805ab1439..bede574bcd77 100644
--- a/drivers/scsi/cxlflash/superpipe.h
+++ b/drivers/scsi/cxlflash/superpipe.h
@@ -63,7 +63,6 @@ struct llun_info {
63 u32 lun_index; /* Index in the LUN table */ 63 u32 lun_index; /* Index in the LUN table */
64 u32 host_no; /* host_no from Scsi_host */ 64 u32 host_no; /* host_no from Scsi_host */
65 u32 port_sel; /* What port to use for this LUN */ 65 u32 port_sel; /* What port to use for this LUN */
66 bool newly_created; /* Whether the LUN was just discovered */
67 bool in_table; /* Whether a LUN table entry was created */ 66 bool in_table; /* Whether a LUN table entry was created */
68 67
69 u8 wwid[16]; /* Keep a duplicate copy here? */ 68 u8 wwid[16]; /* Keep a duplicate copy here? */