summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew R. Ochs <mrochs@linux.vnet.ibm.com>2017-04-12 21:14:05 +0200
committerMartin K. Petersen <martin.petersen@oracle.com>2017-04-14 04:55:41 +0200
commit8fa4f1770d56af6f0a5a862f1fd298a4eeea94f3 (patch)
treed3d4bff0c8c1f1836861000f0a4ccc4a1025cd3e
parentscsi: cxlflash: Support dynamic number of FC ports (diff)
downloadlinux-8fa4f1770d56af6f0a5a862f1fd298a4eeea94f3.tar.xz
linux-8fa4f1770d56af6f0a5a862f1fd298a4eeea94f3.zip
scsi: cxlflash: Remove port configuration assumptions
At present, the cxlflash driver only supports hardware with two FC ports. The code was initially designed with this assumption and is dependent on having two FC ports - adding more ports will break logic within the driver. To mitigate this issue, remove the existing port assumptions and transition the code to support more than two ports. As a side effect, clarify the interpretation of the DK_CXLFLASH_ALL_PORTS_ACTIVE flag. Signed-off-by: Matthew R. Ochs <mrochs@linux.vnet.ibm.com> Signed-off-by: Uma Krishnan <ukrishn@linux.vnet.ibm.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r--Documentation/powerpc/cxlflash.txt5
-rw-r--r--drivers/scsi/cxlflash/common.h4
-rw-r--r--drivers/scsi/cxlflash/lunmgt.c4
-rw-r--r--drivers/scsi/cxlflash/main.c13
-rw-r--r--drivers/scsi/cxlflash/sislite.h2
-rw-r--r--drivers/scsi/cxlflash/superpipe.c2
-rw-r--r--drivers/scsi/cxlflash/superpipe.h3
-rw-r--r--drivers/scsi/cxlflash/vlun.c89
8 files changed, 77 insertions, 45 deletions
diff --git a/Documentation/powerpc/cxlflash.txt b/Documentation/powerpc/cxlflash.txt
index 6d9a2ed32cad..66b4496d6619 100644
--- a/Documentation/powerpc/cxlflash.txt
+++ b/Documentation/powerpc/cxlflash.txt
@@ -239,6 +239,11 @@ DK_CXLFLASH_USER_VIRTUAL
resource handle that is provided is already referencing provisioned
storage. This is reflected by the last LBA being a non-zero value.
+ When a LUN is accessible from more than one port, this ioctl will
+ return with the DK_CXLFLASH_ALL_PORTS_ACTIVE return flag set. This
+ provides the user with a hint that I/O can be retried in the event
+ of an I/O error as the LUN can be reached over multiple paths.
+
DK_CXLFLASH_VLUN_RESIZE
-----------------------
This ioctl is responsible for resizing a previously created virtual
diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h
index 6a04867a0eec..ee23e81994c4 100644
--- a/drivers/scsi/cxlflash/common.h
+++ b/drivers/scsi/cxlflash/common.h
@@ -29,6 +29,10 @@ extern const struct file_operations cxlflash_cxl_fops;
#define NUM_FC_PORTS CXLFLASH_NUM_FC_PORTS /* ports per AFU */
#define MAX_FC_PORTS CXLFLASH_MAX_FC_PORTS /* ports per AFU */
+#define CHAN2PORTMASK(_x) (1 << (_x)) /* channel to port mask */
+#define PORTMASK2CHAN(_x) (ilog2((_x))) /* port mask to channel */
+#define PORTNUM2CHAN(_x) ((_x) - 1) /* port number to channel */
+
#define CXLFLASH_BLOCK_SIZE 4096 /* 4K blocks */
#define CXLFLASH_MAX_XFER_SIZE 16777216 /* 16MB transfer */
#define CXLFLASH_MAX_SECTORS (CXLFLASH_MAX_XFER_SIZE/512) /* SCSI wants
diff --git a/drivers/scsi/cxlflash/lunmgt.c b/drivers/scsi/cxlflash/lunmgt.c
index 0efed177cc8b..4d232e271af6 100644
--- a/drivers/scsi/cxlflash/lunmgt.c
+++ b/drivers/scsi/cxlflash/lunmgt.c
@@ -252,7 +252,7 @@ int cxlflash_manage_lun(struct scsi_device *sdev,
* in unpacked, AFU-friendly format, and hang LUN reference in
* the sdev.
*/
- lli->port_sel |= CHAN2PORT(chan);
+ lli->port_sel |= CHAN2PORTMASK(chan);
lli->lun_id[chan] = lun_to_lunid(sdev->lun);
sdev->hostdata = lli;
} else if (flags & DK_CXLFLASH_MANAGE_LUN_DISABLE_SUPERPIPE) {
@@ -264,7 +264,7 @@ int cxlflash_manage_lun(struct scsi_device *sdev,
* tracking when no more references exist.
*/
sdev->hostdata = NULL;
- lli->port_sel &= ~CHAN2PORT(chan);
+ lli->port_sel &= ~CHAN2PORTMASK(chan);
if (lli->port_sel == 0U)
lli->in_table = false;
}
diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c
index 3f9c8690af0d..04e1a8effa76 100644
--- a/drivers/scsi/cxlflash/main.c
+++ b/drivers/scsi/cxlflash/main.c
@@ -365,7 +365,6 @@ static int wait_resp(struct afu *afu, struct afu_cmd *cmd)
*/
static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd)
{
- u32 port_sel = scp->device->channel + 1;
struct cxlflash_cfg *cfg = shost_priv(scp->device->host);
struct afu_cmd *cmd = sc_to_afucz(scp);
struct device *dev = &cfg->dev->dev;
@@ -388,7 +387,7 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd)
cmd->rcb.ctx_id = afu->ctx_hndl;
cmd->rcb.msi = SISL_MSI_RRQ_UPDATED;
- cmd->rcb.port_sel = port_sel;
+ cmd->rcb.port_sel = CHAN2PORTMASK(scp->device->channel);
cmd->rcb.lun_id = lun_to_lunid(scp->device->lun);
cmd->rcb.req_flags = (SISL_REQ_FLAGS_PORT_LUN_ID |
SISL_REQ_FLAGS_SUP_UNDERRUN |
@@ -444,7 +443,6 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
struct device *dev = &cfg->dev->dev;
struct afu_cmd *cmd = sc_to_afucz(scp);
struct scatterlist *sg = scsi_sglist(scp);
- u32 port_sel = scp->device->channel + 1;
u16 req_flags = SISL_REQ_FLAGS_SUP_UNDERRUN;
ulong lock_flags;
int nseg = 0;
@@ -503,7 +501,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
cmd->rcb.ctx_id = afu->ctx_hndl;
cmd->rcb.msi = SISL_MSI_RRQ_UPDATED;
- cmd->rcb.port_sel = port_sel;
+ cmd->rcb.port_sel = CHAN2PORTMASK(scp->device->channel);
cmd->rcb.lun_id = lun_to_lunid(scp->device->lun);
if (scp->sc_data_direction == DMA_TO_DEVICE)
@@ -1558,7 +1556,8 @@ static int init_global(struct cxlflash_cfg *cfg)
writeq_be(PORT0, &afu->afu_map->global.regs.afu_port_sel);
num_ports = 0;
} else {
- writeq_be(BOTH_PORTS, &afu->afu_map->global.regs.afu_port_sel);
+ writeq_be(PORT_MASK(cfg->num_fc_ports),
+ &afu->afu_map->global.regs.afu_port_sel);
num_ports = cfg->num_fc_ports;
}
@@ -2190,7 +2189,7 @@ static ssize_t lun_mode_store(struct device *dev,
if (afu->internal_lun)
shost->max_channel = 0;
else
- shost->max_channel = cfg->num_fc_ports - 1;
+ shost->max_channel = PORTNUM2CHAN(cfg->num_fc_ports);
afu_reset(cfg);
scsi_scan_host(cfg->host);
@@ -2529,7 +2528,7 @@ static int cxlflash_probe(struct pci_dev *pdev,
host->max_id = CXLFLASH_MAX_NUM_TARGETS_PER_BUS;
host->max_lun = CXLFLASH_MAX_NUM_LUNS_PER_TARGET;
- host->max_channel = NUM_FC_PORTS - 1;
+ host->max_channel = PORTNUM2CHAN(NUM_FC_PORTS);
host->unique_id = host->host_no;
host->max_cmd_len = CXLFLASH_MAX_CDB_LEN;
diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h
index 0db4bc1f4e23..f26f41be5efb 100644
--- a/drivers/scsi/cxlflash/sislite.h
+++ b/drivers/scsi/cxlflash/sislite.h
@@ -479,7 +479,7 @@ struct sisl_rht_entry_f1 {
#define PORT0 0x01U
#define PORT1 0x02U
-#define BOTH_PORTS (PORT0 | PORT1)
+#define PORT_MASK(_n) ((1 << (_n)) - 1)
/* AFU Sync Mode byte */
#define AFU_LW_SYNC 0x0U
diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c
index b46fd2f45628..f3997bed88f4 100644
--- a/drivers/scsi/cxlflash/superpipe.c
+++ b/drivers/scsi/cxlflash/superpipe.c
@@ -1933,7 +1933,7 @@ static int cxlflash_disk_direct_open(struct scsi_device *sdev, void *arg)
u64 lun_size = 0;
u64 last_lba = 0;
u64 rsrc_handle = -1;
- u32 port = CHAN2PORT(sdev->channel);
+ u32 port = CHAN2PORTMASK(sdev->channel);
int rc = 0;
diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h
index 690ce9c652b2..8269ff854bbe 100644
--- a/drivers/scsi/cxlflash/superpipe.h
+++ b/drivers/scsi/cxlflash/superpipe.h
@@ -33,9 +33,6 @@ extern struct cxlflash_global global;
#define MAX_SECTOR_UNIT 512 /* max_sector is in 512 byte multiples */
-#define CHAN2PORT(_x) ((_x) + 1)
-#define PORT2CHAN(_x) ((_x) - 1)
-
enum lun_mode {
MODE_NONE = 0,
MODE_VIRTUAL,
diff --git a/drivers/scsi/cxlflash/vlun.c b/drivers/scsi/cxlflash/vlun.c
index 7aa06ef229fd..067605b80fcd 100644
--- a/drivers/scsi/cxlflash/vlun.c
+++ b/drivers/scsi/cxlflash/vlun.c
@@ -819,8 +819,8 @@ int cxlflash_vlun_resize(struct scsi_device *sdev,
void cxlflash_restore_luntable(struct cxlflash_cfg *cfg)
{
struct llun_info *lli, *temp;
- u32 chan;
u32 lind;
+ int k;
struct afu *afu = cfg->afu;
struct device *dev = &cfg->dev->dev;
struct sisl_global_map __iomem *agm = &afu->afu_map->global;
@@ -832,33 +832,41 @@ void cxlflash_restore_luntable(struct cxlflash_cfg *cfg)
continue;
lind = lli->lun_index;
+ dev_dbg(dev, "%s: Virtual LUNs on slot %d:\n", __func__, lind);
- if (lli->port_sel == BOTH_PORTS) {
- writeq_be(lli->lun_id[0], &agm->fc_port[0][lind]);
- writeq_be(lli->lun_id[1], &agm->fc_port[1][lind]);
- dev_dbg(dev, "%s: Virtual LUN on slot %d id0=%llx "
- "id1=%llx\n", __func__, lind,
- lli->lun_id[0], lli->lun_id[1]);
- } else {
- chan = PORT2CHAN(lli->port_sel);
- writeq_be(lli->lun_id[chan], &agm->fc_port[chan][lind]);
- dev_dbg(dev, "%s: Virtual LUN on slot %d chan=%d "
- "id=%llx\n", __func__, lind, chan,
- lli->lun_id[chan]);
- }
+ for (k = 0; k < cfg->num_fc_ports; k++)
+ if (lli->port_sel & (1 << k)) {
+ writeq_be(lli->lun_id[k],
+ &agm->fc_port[k][lind]);
+ dev_dbg(dev, "\t%d=%llx\n", k, lli->lun_id[k]);
+ }
}
mutex_unlock(&global.mutex);
}
/**
+ * get_num_ports() - compute number of ports from port selection mask
+ * @psm: Port selection mask.
+ *
+ * Return: Population count of port selection mask
+ */
+static inline u8 get_num_ports(u32 psm)
+{
+ static const u8 bits[16] = { 0, 1, 1, 2, 1, 2, 2, 3,
+ 1, 2, 2, 3, 2, 3, 3, 4 };
+
+ return bits[psm & 0xf];
+}
+
+/**
* init_luntable() - write an entry in the LUN table
* @cfg: Internal structure associated with the host.
* @lli: Per adapter LUN information structure.
*
- * On successful return, a LUN table entry is created.
- * At the top for LUNs visible on both ports.
- * At the bottom for LUNs visible only on one port.
+ * On successful return, a LUN table entry is created:
+ * - at the top for LUNs visible on multiple ports.
+ * - at the bottom for LUNs visible only on one port.
*
* Return: 0 on success, -errno on failure
*/
@@ -866,7 +874,9 @@ static int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli)
{
u32 chan;
u32 lind;
+ u32 nports;
int rc = 0;
+ int k;
struct afu *afu = cfg->afu;
struct device *dev = &cfg->dev->dev;
struct sisl_global_map __iomem *agm = &afu->afu_map->global;
@@ -876,29 +886,46 @@ static int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli)
if (lli->in_table)
goto out;
- if (lli->port_sel == BOTH_PORTS) {
+ nports = get_num_ports(lli->port_sel);
+ if (nports == 0 || nports > cfg->num_fc_ports) {
+ WARN(1, "Unsupported port configuration nports=%u", nports);
+ rc = -EIO;
+ goto out;
+ }
+
+ if (nports > 1) {
/*
- * If this LUN is visible from both ports, we will put
+ * When LUN is visible from multiple ports, we will put
* it in the top half of the LUN table.
*/
- if ((cfg->promote_lun_index == cfg->last_lun_index[0]) ||
- (cfg->promote_lun_index == cfg->last_lun_index[1])) {
- rc = -ENOSPC;
- goto out;
+ for (k = 0; k < cfg->num_fc_ports; k++) {
+ if (!(lli->port_sel & (1 << k)))
+ continue;
+
+ if (cfg->promote_lun_index == cfg->last_lun_index[k]) {
+ rc = -ENOSPC;
+ goto out;
+ }
}
lind = lli->lun_index = cfg->promote_lun_index;
- writeq_be(lli->lun_id[0], &agm->fc_port[0][lind]);
- writeq_be(lli->lun_id[1], &agm->fc_port[1][lind]);
+ dev_dbg(dev, "%s: Virtual LUNs on slot %d:\n", __func__, lind);
+
+ for (k = 0; k < cfg->num_fc_ports; k++) {
+ if (!(lli->port_sel & (1 << k)))
+ continue;
+
+ writeq_be(lli->lun_id[k], &agm->fc_port[k][lind]);
+ dev_dbg(dev, "\t%d=%llx\n", k, lli->lun_id[k]);
+ }
+
cfg->promote_lun_index++;
- dev_dbg(dev, "%s: Virtual LUN on slot %d id0=%llx id1=%llx\n",
- __func__, lind, lli->lun_id[0], lli->lun_id[1]);
} else {
/*
- * If this LUN is visible only from one port, we will put
+ * When LUN is visible only from one port, we will put
* it in the bottom half of the LUN table.
*/
- chan = PORT2CHAN(lli->port_sel);
+ chan = PORTMASK2CHAN(lli->port_sel);
if (cfg->promote_lun_index == cfg->last_lun_index[chan]) {
rc = -ENOSPC;
goto out;
@@ -907,7 +934,7 @@ static int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli)
lind = lli->lun_index = cfg->last_lun_index[chan];
writeq_be(lli->lun_id[chan], &agm->fc_port[chan][lind]);
cfg->last_lun_index[chan]--;
- dev_dbg(dev, "%s: Virtual LUN on slot %d chan=%d id=%llx\n",
+ dev_dbg(dev, "%s: Virtual LUNs on slot %d:\n\t%d=%llx\n",
__func__, lind, chan, lli->lun_id[chan]);
}
@@ -1016,7 +1043,7 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg)
virt->last_lba = last_lba;
virt->rsrc_handle = rsrc_handle;
- if (lli->port_sel == BOTH_PORTS)
+ if (get_num_ports(lli->port_sel) > 1)
virt->hdr.return_flags |= DK_CXLFLASH_ALL_PORTS_ACTIVE;
out:
if (likely(ctxi))