diff options
author | Matthew R. Ochs <mrochs@linux.vnet.ibm.com> | 2017-06-22 05:16:13 +0300 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2017-06-26 22:01:12 +0300 |
commit | 9cf43a360450ddd758b0021d1b55f1cc5643b9ed (patch) | |
tree | 0d314def42874dd878a05dd713549d77dd255bd8 /drivers/scsi/cxlflash | |
parent | efa1c818d3458fe97d8f83f40051518b44183234 (diff) | |
download | linux-9cf43a360450ddd758b0021d1b55f1cc5643b9ed.tar.xz |
scsi: cxlflash: Support LUN provisioning
Adopt the SISLite AFU LUN provisioning capability to allow future CXL
Flash adapters the ability to better manage storage. Update the SISLite
header with the changes necessary to support LUN provision operations
and create a host ioctl interface for user LUN management software. Also
update the cxlflash documentation to describe this new host ioctl.
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>
Diffstat (limited to 'drivers/scsi/cxlflash')
-rw-r--r-- | drivers/scsi/cxlflash/common.h | 5 | ||||
-rw-r--r-- | drivers/scsi/cxlflash/main.c | 107 | ||||
-rw-r--r-- | drivers/scsi/cxlflash/main.h | 5 | ||||
-rw-r--r-- | drivers/scsi/cxlflash/sislite.h | 22 |
4 files changed, 135 insertions, 4 deletions
diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index c96526e1fb11..58107246c32f 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -262,6 +262,11 @@ static inline bool afu_has_cap(struct afu *afu, u64 cap) return afu_cap & cap; } +static inline bool afu_is_lun_provision(struct afu *afu) +{ + return afu_has_cap(afu, SISL_INTVER_CAP_LUN_PROVISION); +} + static inline bool afu_is_sq_cmd_mode(struct afu *afu) { return afu_has_cap(afu, SISL_INTVER_CAP_SQ_CMD_MODE); diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index be468ed1d884..1279293ff3b3 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -3227,14 +3227,105 @@ static int cxlflash_chr_open(struct inode *inode, struct file *file) static char *decode_hioctl(int cmd) { switch (cmd) { - default: - return "UNKNOWN"; + case HT_CXLFLASH_LUN_PROVISION: + return __stringify_1(HT_CXLFLASH_LUN_PROVISION); } return "UNKNOWN"; } /** + * cxlflash_lun_provision() - host LUN provisioning handler + * @cfg: Internal structure associated with the host. + * @arg: Kernel copy of userspace ioctl data structure. + * + * Return: 0 on success, -errno on failure + */ +static int cxlflash_lun_provision(struct cxlflash_cfg *cfg, + struct ht_cxlflash_lun_provision *lunprov) +{ + struct afu *afu = cfg->afu; + struct device *dev = &cfg->dev->dev; + struct sisl_ioarcb rcb; + struct sisl_ioasa asa; + __be64 __iomem *fc_port_regs; + u16 port = lunprov->port; + u16 scmd = lunprov->hdr.subcmd; + u16 type; + u64 reg; + u64 size; + u64 lun_id; + int rc = 0; + + if (!afu_is_lun_provision(afu)) { + rc = -ENOTSUPP; + goto out; + } + + if (port >= cfg->num_fc_ports) { + rc = -EINVAL; + goto out; + } + + switch (scmd) { + case HT_CXLFLASH_LUN_PROVISION_SUBCMD_CREATE_LUN: + type = SISL_AFU_LUN_PROVISION_CREATE; + size = lunprov->size; + lun_id = 0; + break; + case HT_CXLFLASH_LUN_PROVISION_SUBCMD_DELETE_LUN: + type = SISL_AFU_LUN_PROVISION_DELETE; + size = 0; + lun_id = lunprov->lun_id; + break; + case HT_CXLFLASH_LUN_PROVISION_SUBCMD_QUERY_PORT: + fc_port_regs = get_fc_port_regs(cfg, port); + + reg = readq_be(&fc_port_regs[FC_MAX_NUM_LUNS / 8]); + lunprov->max_num_luns = reg; + reg = readq_be(&fc_port_regs[FC_CUR_NUM_LUNS / 8]); + lunprov->cur_num_luns = reg; + reg = readq_be(&fc_port_regs[FC_MAX_CAP_PORT / 8]); + lunprov->max_cap_port = reg; + reg = readq_be(&fc_port_regs[FC_CUR_CAP_PORT / 8]); + lunprov->cur_cap_port = reg; + + goto out; + default: + rc = -EINVAL; + goto out; + } + + memset(&rcb, 0, sizeof(rcb)); + memset(&asa, 0, sizeof(asa)); + rcb.req_flags = SISL_REQ_FLAGS_AFU_CMD; + rcb.lun_id = lun_id; + rcb.msi = SISL_MSI_RRQ_UPDATED; + rcb.timeout = MC_LUN_PROV_TIMEOUT; + rcb.ioasa = &asa; + + rcb.cdb[0] = SISL_AFU_CMD_LUN_PROVISION; + rcb.cdb[1] = type; + rcb.cdb[2] = port; + put_unaligned_be64(size, &rcb.cdb[8]); + + rc = send_afu_cmd(afu, &rcb); + if (rc) { + dev_err(dev, "%s: send_afu_cmd failed rc=%d asc=%08x afux=%x\n", + __func__, rc, asa.ioasc, asa.afu_extra); + goto out; + } + + if (scmd == HT_CXLFLASH_LUN_PROVISION_SUBCMD_CREATE_LUN) { + lunprov->lun_id = (u64)asa.lunid_hi << 32 | asa.lunid_lo; + memcpy(lunprov->wwid, asa.wwid, sizeof(lunprov->wwid)); + } +out: + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** * cxlflash_chr_ioctl() - character device IOCTL handler * @file: File pointer for this device. * @cmd: IOCTL command. @@ -3270,6 +3361,8 @@ static long cxlflash_chr_ioctl(struct file *file, unsigned int cmd, size_t size; hioctl ioctl; } ioctl_tbl[] = { /* NOTE: order matters here */ + { sizeof(struct ht_cxlflash_lun_provision), + (hioctl)cxlflash_lun_provision }, }; /* Hold read semaphore so we can drain if needed */ @@ -3279,6 +3372,16 @@ static long cxlflash_chr_ioctl(struct file *file, unsigned int cmd, __func__, cmd, idx, sizeof(ioctl_tbl)); switch (cmd) { + case HT_CXLFLASH_LUN_PROVISION: + known_ioctl = true; + idx = _IOC_NR(HT_CXLFLASH_LUN_PROVISION) - _IOC_NR(cmd); + size = ioctl_tbl[idx].size; + do_ioctl = ioctl_tbl[idx].ioctl; + + if (likely(do_ioctl)) + break; + + /* fall through */ default: rc = -EINVAL; goto out; diff --git a/drivers/scsi/cxlflash/main.h b/drivers/scsi/cxlflash/main.h index 44c86c2d84f5..6ae8a118358a 100644 --- a/drivers/scsi/cxlflash/main.h +++ b/drivers/scsi/cxlflash/main.h @@ -41,6 +41,10 @@ /* FC defines */ #define FC_MTIP_CMDCONFIG 0x010 #define FC_MTIP_STATUS 0x018 +#define FC_MAX_NUM_LUNS 0x080 /* Max LUNs host can provision for port */ +#define FC_CUR_NUM_LUNS 0x088 /* Cur number LUNs provisioned for port */ +#define FC_MAX_CAP_PORT 0x090 /* Max capacity all LUNs for port (4K blocks) */ +#define FC_CUR_CAP_PORT 0x098 /* Cur capacity all LUNs for port (4K blocks) */ #define FC_PNAME 0x300 #define FC_CONFIG 0x320 @@ -63,6 +67,7 @@ /* AFU command timeout values */ #define MC_AFU_SYNC_TIMEOUT 5 /* 5 secs */ +#define MC_LUN_PROV_TIMEOUT 5 /* 5 secs */ /* AFU command room retry limit */ #define MC_ROOM_RETRY_CNT 10 diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h index 483710a89781..c216feeb8906 100644 --- a/drivers/scsi/cxlflash/sislite.h +++ b/drivers/scsi/cxlflash/sislite.h @@ -73,6 +73,10 @@ struct sisl_ioarcb { u32 rsvd1; u8 cdb[16]; /* must be in big endian */ #define SISL_AFU_CMD_SYNC 0xC0 /* AFU sync command */ +#define SISL_AFU_CMD_LUN_PROVISION 0xD0 /* AFU LUN provision command */ + +#define SISL_AFU_LUN_PROVISION_CREATE 0x00 /* LUN provision create type */ +#define SISL_AFU_LUN_PROVISION_DELETE 0x01 /* LUN provision delete type */ union { u64 reserved; /* Reserved for IOARRIN mode */ @@ -158,6 +162,7 @@ struct sisl_rc { }; #define SISL_SENSE_DATA_LEN 20 /* Sense data length */ +#define SISL_WWID_DATA_LEN 16 /* WWID data length */ /* * IOASA: 64 bytes & must follow IOARCB, min 16 byte alignment required, @@ -169,7 +174,12 @@ struct sisl_ioasa { u32 ioasc; #define SISL_IOASC_GOOD_COMPLETION 0x00000000U }; - u32 resid; + + union { + u32 resid; + u32 lunid_hi; + }; + u8 port; u8 afu_extra; /* when afu_rc=0x04, 0x14, 0x31 (_xxx_DMA_ERR): @@ -192,7 +202,14 @@ struct sisl_ioasa { u8 scsi_extra; u8 fc_extra; - u8 sense_data[SISL_SENSE_DATA_LEN]; + + union { + u8 sense_data[SISL_SENSE_DATA_LEN]; + struct { + u32 lunid_lo; + u8 wwid[SISL_WWID_DATA_LEN]; + }; + }; /* These fields are defined by the SISlite architecture for the * host to use as they see fit for their implementation. @@ -394,6 +411,7 @@ struct sisl_global_regs { #define SISL_INTVER_CAP_SQ_CMD_MODE 0x400000000000ULL #define SISL_INTVER_CAP_RESERVED_CMD_MODE_A 0x200000000000ULL #define SISL_INTVER_CAP_RESERVED_CMD_MODE_B 0x100000000000ULL +#define SISL_INTVER_CAP_LUN_PROVISION 0x080000000000ULL }; #define CXLFLASH_NUM_FC_PORTS_PER_BANK 2 /* fixed # of ports per bank */ |