From c2c292f45029a6850cd14c7c2fa4fc479b8f74aa Mon Sep 17 00:00:00 2001 From: Uma Krishnan Date: Wed, 21 Jun 2017 21:14:30 -0500 Subject: scsi: cxlflash: Handle AFU sync failures AFU sync operations are not currently evaluated for failure. This is acceptable for paths where there is not a dependency on the AFU being consistent with the host. Examples include link reset events and LUN cleanup operations. On paths where there is a dependency, such as a LUN open, a sync failure should be acted upon. In the event of AFU sync failures, either log or cleanup as appropriate for operations that are dependent on a successful sync completion. Update documentation to reflect behavior in the event of an AFU sync failure. Signed-off-by: Uma Krishnan Acked-by: Matthew R. Ochs Signed-off-by: Martin K. Petersen --- Documentation/powerpc/cxlflash.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'Documentation/powerpc/cxlflash.txt') diff --git a/Documentation/powerpc/cxlflash.txt b/Documentation/powerpc/cxlflash.txt index 66b4496d6619..f9036cb0170d 100644 --- a/Documentation/powerpc/cxlflash.txt +++ b/Documentation/powerpc/cxlflash.txt @@ -257,6 +257,12 @@ DK_CXLFLASH_VLUN_RESIZE operating in the virtual mode and used to program a LUN translation table that the AFU references when provided with a resource handle. + This ioctl can return -EAGAIN if an AFU sync operation takes too long. + In addition to returning a failure to user, cxlflash will also schedule + an asynchronous AFU reset. Should the user choose to retry the operation, + it is expected to succeed. If this ioctl fails with -EAGAIN, the user + can either retry the operation or treat it as a failure. + DK_CXLFLASH_RELEASE ------------------- This ioctl is responsible for releasing a previously obtained @@ -309,6 +315,12 @@ DK_CXLFLASH_VLUN_CLONE clone. This is to avoid a stale entry in the file descriptor table of the child process. + This ioctl can return -EAGAIN if an AFU sync operation takes too long. + In addition to returning a failure to user, cxlflash will also schedule + an asynchronous AFU reset. Should the user choose to retry the operation, + it is expected to succeed. If this ioctl fails with -EAGAIN, the user + can either retry the operation or treat it as a failure. + DK_CXLFLASH_VERIFY ------------------ This ioctl is used to detect various changes such as the capacity of -- cgit v1.2.3 From d6e32f530df9827070c45b55a6c67dfa8562184c Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Jun 2017 21:15:42 -0500 Subject: scsi: cxlflash: Introduce host ioctl support As staging for supporting various host management functions, add a host ioctl infrastructure to filter ioctl commands and perform operations that are common for all host ioctls. Also update the cxlflash documentation to create a new section for documenting host ioctls. Signed-off-by: Matthew R. Ochs Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen --- Documentation/ioctl/ioctl-number.txt | 2 +- Documentation/powerpc/cxlflash.txt | 19 +++++- drivers/scsi/cxlflash/main.c | 121 ++++++++++++++++++++++++++++++++++- include/uapi/scsi/cxlflash_ioctl.h | 31 ++++++++- 4 files changed, 168 insertions(+), 5 deletions(-) (limited to 'Documentation/powerpc/cxlflash.txt') diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 1e9fcb4d0ec8..3e3fdae5f3ed 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -326,7 +326,7 @@ Code Seq#(hex) Include File Comments 0xB5 00-0F uapi/linux/rpmsg.h 0xC0 00-0F linux/usb/iowarrior.h 0xCA 00-0F uapi/misc/cxl.h -0xCA 80-8F uapi/scsi/cxlflash_ioctl.h +0xCA 80-BF uapi/scsi/cxlflash_ioctl.h 0xCB 00-1F CBM serial IEC bus in development: 0xCD 01 linux/reiserfs_fs.h diff --git a/Documentation/powerpc/cxlflash.txt b/Documentation/powerpc/cxlflash.txt index f9036cb0170d..ee67021bbfe4 100644 --- a/Documentation/powerpc/cxlflash.txt +++ b/Documentation/powerpc/cxlflash.txt @@ -124,8 +124,8 @@ Block library API http://github.com/open-power/capiflash -CXL Flash Driver IOCTLs -======================= +CXL Flash Driver LUN IOCTLs +=========================== Users, such as the block library, that wish to interface with a flash device (LUN) via user space access need to use the services provided @@ -367,3 +367,18 @@ DK_CXLFLASH_MANAGE_LUN exclusive user space access (superpipe). In case a LUN is visible across multiple ports and adapters, this ioctl is used to uniquely identify each LUN by its World Wide Node Name (WWNN). + + +CXL Flash Driver Host IOCTLs +============================ + + Each host adapter instance that is supported by the cxlflash driver + has a special character device associated with it to enable a set of + host management function. These character devices are hosted in a + class dedicated for cxlflash and can be accessed via /dev/cxlflash/*. + + Applications can be written to perform various functions using the + host ioctl APIs below. + + The structure definitions for these IOCTLs are available in: + uapi/scsi/cxlflash_ioctl.h diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 7732dfc099c4..be468ed1d884 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -2693,7 +2693,14 @@ static ssize_t lun_mode_store(struct device *dev, static ssize_t ioctl_version_show(struct device *dev, struct device_attribute *attr, char *buf) { - return scnprintf(buf, PAGE_SIZE, "%u\n", DK_CXLFLASH_VERSION_0); + ssize_t bytes = 0; + + bytes = scnprintf(buf, PAGE_SIZE, + "disk: %u\n", DK_CXLFLASH_VERSION_0); + bytes += scnprintf(buf + bytes, PAGE_SIZE - bytes, + "host: %u\n", HT_CXLFLASH_VERSION_0); + + return bytes; } /** @@ -3211,12 +3218,124 @@ static int cxlflash_chr_open(struct inode *inode, struct file *file) return 0; } +/** + * decode_hioctl() - translates encoded host ioctl to easily identifiable string + * @cmd: The host ioctl command to decode. + * + * Return: A string identifying the decoded host ioctl. + */ +static char *decode_hioctl(int cmd) +{ + switch (cmd) { + default: + return "UNKNOWN"; + } + + return "UNKNOWN"; +} + +/** + * cxlflash_chr_ioctl() - character device IOCTL handler + * @file: File pointer for this device. + * @cmd: IOCTL command. + * @arg: Userspace ioctl data structure. + * + * A read/write semaphore is used to implement a 'drain' of currently + * running ioctls. The read semaphore is taken at the beginning of each + * ioctl thread and released upon concluding execution. Additionally the + * semaphore should be released and then reacquired in any ioctl execution + * path which will wait for an event to occur that is outside the scope of + * the ioctl (i.e. an adapter reset). To drain the ioctls currently running, + * a thread simply needs to acquire the write semaphore. + * + * Return: 0 on success, -errno on failure + */ +static long cxlflash_chr_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + typedef int (*hioctl) (struct cxlflash_cfg *, void *); + + struct cxlflash_cfg *cfg = file->private_data; + struct device *dev = &cfg->dev->dev; + char buf[sizeof(union cxlflash_ht_ioctls)]; + void __user *uarg = (void __user *)arg; + struct ht_cxlflash_hdr *hdr; + size_t size = 0; + bool known_ioctl = false; + int idx = 0; + int rc = 0; + hioctl do_ioctl = NULL; + + static const struct { + size_t size; + hioctl ioctl; + } ioctl_tbl[] = { /* NOTE: order matters here */ + }; + + /* Hold read semaphore so we can drain if needed */ + down_read(&cfg->ioctl_rwsem); + + dev_dbg(dev, "%s: cmd=%u idx=%d tbl_size=%lu\n", + __func__, cmd, idx, sizeof(ioctl_tbl)); + + switch (cmd) { + default: + rc = -EINVAL; + goto out; + } + + if (unlikely(copy_from_user(&buf, uarg, size))) { + dev_err(dev, "%s: copy_from_user() fail " + "size=%lu cmd=%d (%s) uarg=%p\n", + __func__, size, cmd, decode_hioctl(cmd), uarg); + rc = -EFAULT; + goto out; + } + + hdr = (struct ht_cxlflash_hdr *)&buf; + if (hdr->version != HT_CXLFLASH_VERSION_0) { + dev_dbg(dev, "%s: Version %u not supported for %s\n", + __func__, hdr->version, decode_hioctl(cmd)); + rc = -EINVAL; + goto out; + } + + if (hdr->rsvd[0] || hdr->rsvd[1] || hdr->return_flags) { + dev_dbg(dev, "%s: Reserved/rflags populated\n", __func__); + rc = -EINVAL; + goto out; + } + + rc = do_ioctl(cfg, (void *)&buf); + if (likely(!rc)) + if (unlikely(copy_to_user(uarg, &buf, size))) { + dev_err(dev, "%s: copy_to_user() fail " + "size=%lu cmd=%d (%s) uarg=%p\n", + __func__, size, cmd, decode_hioctl(cmd), uarg); + rc = -EFAULT; + } + + /* fall through to exit */ + +out: + up_read(&cfg->ioctl_rwsem); + if (unlikely(rc && known_ioctl)) + dev_err(dev, "%s: ioctl %s (%08X) returned rc=%d\n", + __func__, decode_hioctl(cmd), cmd, rc); + else + dev_dbg(dev, "%s: ioctl %s (%08X) returned rc=%d\n", + __func__, decode_hioctl(cmd), cmd, rc); + return rc; +} + /* * Character device file operations */ static const struct file_operations cxlflash_chr_fops = { .owner = THIS_MODULE, .open = cxlflash_chr_open, + .unlocked_ioctl = cxlflash_chr_ioctl, + .compat_ioctl = cxlflash_chr_ioctl, }; /** diff --git a/include/uapi/scsi/cxlflash_ioctl.h b/include/uapi/scsi/cxlflash_ioctl.h index e9fdc12ad984..87e1f63029bf 100644 --- a/include/uapi/scsi/cxlflash_ioctl.h +++ b/include/uapi/scsi/cxlflash_ioctl.h @@ -31,7 +31,7 @@ struct dk_cxlflash_hdr { }; /* - * Return flag definitions available to all ioctls + * Return flag definitions available to all superpipe ioctls * * Similar to the input flags, these are grown from the bottom-up with the * intention that ioctl-specific return flag definitions would grow from the @@ -180,6 +180,10 @@ union cxlflash_ioctls { #define CXL_MAGIC 0xCA #define CXL_IOWR(_n, _s) _IOWR(CXL_MAGIC, _n, struct _s) +/* + * CXL Flash superpipe ioctls start at base of the reserved CXL_MAGIC + * region (0x80) and grow upwards. + */ #define DK_CXLFLASH_ATTACH CXL_IOWR(0x80, dk_cxlflash_attach) #define DK_CXLFLASH_USER_DIRECT CXL_IOWR(0x81, dk_cxlflash_udirect) #define DK_CXLFLASH_RELEASE CXL_IOWR(0x82, dk_cxlflash_release) @@ -191,4 +195,29 @@ union cxlflash_ioctls { #define DK_CXLFLASH_VLUN_RESIZE CXL_IOWR(0x88, dk_cxlflash_resize) #define DK_CXLFLASH_VLUN_CLONE CXL_IOWR(0x89, dk_cxlflash_clone) +/* + * Structure and flag definitions CXL Flash host ioctls + */ + +#define HT_CXLFLASH_VERSION_0 0 + +struct ht_cxlflash_hdr { + __u16 version; /* Version data */ + __u16 subcmd; /* Sub-command */ + __u16 rsvd[2]; /* Reserved for future use */ + __u64 flags; /* Input flags */ + __u64 return_flags; /* Returned flags */ +}; + +union cxlflash_ht_ioctls { +}; + +#define MAX_HT_CXLFLASH_IOCTL_SZ (sizeof(union cxlflash_ht_ioctls)) + +/* + * CXL Flash host ioctls start at the top of the reserved CXL_MAGIC + * region (0xBF) and grow downwards. + */ + + #endif /* ifndef _CXLFLASH_IOCTL_H */ -- cgit v1.2.3 From 9cf43a360450ddd758b0021d1b55f1cc5643b9ed Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Jun 2017 21:16:13 -0500 Subject: 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 Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen --- Documentation/powerpc/cxlflash.txt | 31 +++++++++++ drivers/scsi/cxlflash/common.h | 5 ++ drivers/scsi/cxlflash/main.c | 107 ++++++++++++++++++++++++++++++++++++- drivers/scsi/cxlflash/main.h | 5 ++ drivers/scsi/cxlflash/sislite.h | 22 +++++++- include/uapi/scsi/cxlflash_ioctl.h | 31 +++++++++-- 6 files changed, 192 insertions(+), 9 deletions(-) (limited to 'Documentation/powerpc/cxlflash.txt') diff --git a/Documentation/powerpc/cxlflash.txt b/Documentation/powerpc/cxlflash.txt index ee67021bbfe4..2d6297b4ad80 100644 --- a/Documentation/powerpc/cxlflash.txt +++ b/Documentation/powerpc/cxlflash.txt @@ -382,3 +382,34 @@ CXL Flash Driver Host IOCTLs The structure definitions for these IOCTLs are available in: uapi/scsi/cxlflash_ioctl.h + +HT_CXLFLASH_LUN_PROVISION +------------------------- + This ioctl is used to create and delete persistent LUNs on cxlflash + devices that lack an external LUN management interface. It is only + valid when used with AFUs that support the LUN provision capability. + + When sufficient space is available, LUNs can be created by specifying + the target port to host the LUN and a desired size in 4K blocks. Upon + success, the LUN ID and WWID of the created LUN will be returned and + the SCSI bus can be scanned to detect the change in LUN topology. Note + that partial allocations are not supported. Should a creation fail due + to a space issue, the target port can be queried for its current LUN + geometry. + + To remove a LUN, the device must first be disassociated from the Linux + SCSI subsystem. The LUN deletion can then be initiated by specifying a + target port and LUN ID. Upon success, the LUN geometry associated with + the port will be updated to reflect new number of provisioned LUNs and + available capacity. + + To query the LUN geometry of a port, the target port is specified and + upon success, the following information is presented: + + - Maximum number of provisioned LUNs allowed for the port + - Current number of provisioned LUNs for the port + - Maximum total capacity of provisioned LUNs for the port (4K blocks) + - Current total capacity of provisioned LUNs for the port (4K blocks) + + With this information, the number of available LUNs and capacity can be + can be calculated. 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,13 +3227,104 @@ 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. @@ -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 */ diff --git a/include/uapi/scsi/cxlflash_ioctl.h b/include/uapi/scsi/cxlflash_ioctl.h index 87e1f63029bf..ad79c34f4d11 100644 --- a/include/uapi/scsi/cxlflash_ioctl.h +++ b/include/uapi/scsi/cxlflash_ioctl.h @@ -202,14 +202,34 @@ union cxlflash_ioctls { #define HT_CXLFLASH_VERSION_0 0 struct ht_cxlflash_hdr { - __u16 version; /* Version data */ - __u16 subcmd; /* Sub-command */ - __u16 rsvd[2]; /* Reserved for future use */ - __u64 flags; /* Input flags */ - __u64 return_flags; /* Returned flags */ + __u16 version; /* Version data */ + __u16 subcmd; /* Sub-command */ + __u16 rsvd[2]; /* Reserved for future use */ + __u64 flags; /* Input flags */ + __u64 return_flags; /* Returned flags */ +}; + +#define HT_CXLFLASH_LUN_PROVISION_SUBCMD_CREATE_LUN 0x0001 +#define HT_CXLFLASH_LUN_PROVISION_SUBCMD_DELETE_LUN 0x0002 +#define HT_CXLFLASH_LUN_PROVISION_SUBCMD_QUERY_PORT 0x0003 +#define HT_CXLFLASH_LUN_PROVISION_WWID_LEN 16 + +struct ht_cxlflash_lun_provision { + struct ht_cxlflash_hdr hdr; /* Common fields */ + __u16 port; /* Target port for provision request */ + __u16 reserved16[3]; /* Reserved for future use */ + __u64 size; /* Size of LUN (4K blocks) */ + __u64 lun_id; /* SCSI LUN ID */ + __u8 wwid[HT_CXLFLASH_LUN_PROVISION_WWID_LEN]; /* Page83 WWID, NAA-6 */ + __u64 max_num_luns; /* Maximum number of LUNs provisioned */ + __u64 cur_num_luns; /* Current number of LUNs provisioned */ + __u64 max_cap_port; /* Total capacity for port (4K blocks) */ + __u64 cur_cap_port; /* Current capacity for port (4K blocks) */ + __u64 reserved[8]; /* Reserved for future use */ }; union cxlflash_ht_ioctls { + struct ht_cxlflash_lun_provision lun_provision; }; #define MAX_HT_CXLFLASH_IOCTL_SZ (sizeof(union cxlflash_ht_ioctls)) @@ -218,6 +238,7 @@ union cxlflash_ht_ioctls { * CXL Flash host ioctls start at the top of the reserved CXL_MAGIC * region (0xBF) and grow downwards. */ +#define HT_CXLFLASH_LUN_PROVISION CXL_IOWR(0xBF, ht_cxlflash_lun_provision) #endif /* ifndef _CXLFLASH_IOCTL_H */ -- cgit v1.2.3 From bc88ac47d5cb11c7dd9896781f793fae519d53fa Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 21 Jun 2017 21:16:22 -0500 Subject: scsi: cxlflash: Support AFU debug Adopt the SISLite AFU debug capability to allow future CXL Flash adapters the ability to better debug AFU issues. Update the SISLite header with the changes necessary to support AFU debug operations and create a host ioctl interface for user debug software. Also update the cxlflash documentation to describe this new host ioctl. Signed-off-by: Matthew R. Ochs Signed-off-by: Uma Krishnan Signed-off-by: Martin K. Petersen --- Documentation/powerpc/cxlflash.txt | 14 ++++++ drivers/scsi/cxlflash/common.h | 5 ++ drivers/scsi/cxlflash/main.c | 96 ++++++++++++++++++++++++++++++++++++++ drivers/scsi/cxlflash/main.h | 1 + drivers/scsi/cxlflash/sislite.h | 2 + include/uapi/scsi/cxlflash_ioctl.h | 37 +++++++++++++-- 6 files changed, 152 insertions(+), 3 deletions(-) (limited to 'Documentation/powerpc/cxlflash.txt') diff --git a/Documentation/powerpc/cxlflash.txt b/Documentation/powerpc/cxlflash.txt index 2d6297b4ad80..a64bdaa0a1cf 100644 --- a/Documentation/powerpc/cxlflash.txt +++ b/Documentation/powerpc/cxlflash.txt @@ -413,3 +413,17 @@ HT_CXLFLASH_LUN_PROVISION With this information, the number of available LUNs and capacity can be can be calculated. + +HT_CXLFLASH_AFU_DEBUG +--------------------- + This ioctl is used to debug AFUs by supporting a command pass-through + interface. It is only valid when used with AFUs that support the AFU + debug capability. + + With exception of buffer management, AFU debug commands are opaque to + cxlflash and treated as pass-through. For debug commands that do require + data transfer, the user supplies an adequately sized data buffer and must + specify the data transfer direction with respect to the host. There is a + maximum transfer size of 256K imposed. Note that partial read completions + are not supported - when errors are experienced with a host read data + transfer, the data buffer is not copied back to the user. diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index 58107246c32f..a91151c4a4fc 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_afu_debug(struct afu *afu) +{ + return afu_has_cap(afu, SISL_INTVER_CAP_AFU_DEBUG); +} + static inline bool afu_is_lun_provision(struct afu *afu) { return afu_has_cap(afu, SISL_INTVER_CAP_LUN_PROVISION); diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 1279293ff3b3..d3ad52ec5314 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -3325,6 +3325,99 @@ out: return rc; } +/** + * cxlflash_afu_debug() - host AFU debug handler + * @cfg: Internal structure associated with the host. + * @arg: Kernel copy of userspace ioctl data structure. + * + * For debug requests requiring a data buffer, always provide an aligned + * (cache line) buffer to the AFU to appease any alignment requirements. + * + * Return: 0 on success, -errno on failure + */ +static int cxlflash_afu_debug(struct cxlflash_cfg *cfg, + struct ht_cxlflash_afu_debug *afu_dbg) +{ + struct afu *afu = cfg->afu; + struct device *dev = &cfg->dev->dev; + struct sisl_ioarcb rcb; + struct sisl_ioasa asa; + char *buf = NULL; + char *kbuf = NULL; + void __user *ubuf = (__force void __user *)afu_dbg->data_ea; + u16 req_flags = SISL_REQ_FLAGS_AFU_CMD; + u32 ulen = afu_dbg->data_len; + bool is_write = afu_dbg->hdr.flags & HT_CXLFLASH_HOST_WRITE; + int rc = 0; + + if (!afu_is_afu_debug(afu)) { + rc = -ENOTSUPP; + goto out; + } + + if (ulen) { + req_flags |= SISL_REQ_FLAGS_SUP_UNDERRUN; + + if (ulen > HT_CXLFLASH_AFU_DEBUG_MAX_DATA_LEN) { + rc = -EINVAL; + goto out; + } + + if (unlikely(!access_ok(is_write ? VERIFY_READ : VERIFY_WRITE, + ubuf, ulen))) { + rc = -EFAULT; + goto out; + } + + buf = kmalloc(ulen + cache_line_size() - 1, GFP_KERNEL); + if (unlikely(!buf)) { + rc = -ENOMEM; + goto out; + } + + kbuf = PTR_ALIGN(buf, cache_line_size()); + + if (is_write) { + req_flags |= SISL_REQ_FLAGS_HOST_WRITE; + + rc = copy_from_user(kbuf, ubuf, ulen); + if (unlikely(rc)) + goto out; + } + } + + memset(&rcb, 0, sizeof(rcb)); + memset(&asa, 0, sizeof(asa)); + + rcb.req_flags = req_flags; + rcb.msi = SISL_MSI_RRQ_UPDATED; + rcb.timeout = MC_AFU_DEBUG_TIMEOUT; + rcb.ioasa = &asa; + + if (ulen) { + rcb.data_len = ulen; + rcb.data_ea = (uintptr_t)kbuf; + } + + rcb.cdb[0] = SISL_AFU_CMD_DEBUG; + memcpy(&rcb.cdb[4], afu_dbg->afu_subcmd, + HT_CXLFLASH_AFU_DEBUG_SUBCMD_LEN); + + 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 (ulen && !is_write) + rc = copy_to_user(ubuf, kbuf, ulen); +out: + kfree(buf); + 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. @@ -3363,6 +3456,8 @@ static long cxlflash_chr_ioctl(struct file *file, unsigned int cmd, } ioctl_tbl[] = { /* NOTE: order matters here */ { sizeof(struct ht_cxlflash_lun_provision), (hioctl)cxlflash_lun_provision }, + { sizeof(struct ht_cxlflash_afu_debug), + (hioctl)cxlflash_afu_debug }, }; /* Hold read semaphore so we can drain if needed */ @@ -3373,6 +3468,7 @@ static long cxlflash_chr_ioctl(struct file *file, unsigned int cmd, switch (cmd) { case HT_CXLFLASH_LUN_PROVISION: + case HT_CXLFLASH_AFU_DEBUG: known_ioctl = true; idx = _IOC_NR(HT_CXLFLASH_LUN_PROVISION) - _IOC_NR(cmd); size = ioctl_tbl[idx].size; diff --git a/drivers/scsi/cxlflash/main.h b/drivers/scsi/cxlflash/main.h index 6ae8a118358a..880e348ed5c9 100644 --- a/drivers/scsi/cxlflash/main.h +++ b/drivers/scsi/cxlflash/main.h @@ -68,6 +68,7 @@ /* AFU command timeout values */ #define MC_AFU_SYNC_TIMEOUT 5 /* 5 secs */ #define MC_LUN_PROV_TIMEOUT 5 /* 5 secs */ +#define MC_AFU_DEBUG_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 c216feeb8906..d671fae19697 100644 --- a/drivers/scsi/cxlflash/sislite.h +++ b/drivers/scsi/cxlflash/sislite.h @@ -74,6 +74,7 @@ struct sisl_ioarcb { 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_CMD_DEBUG 0xE0 /* AFU debug command */ #define SISL_AFU_LUN_PROVISION_CREATE 0x00 /* LUN provision create type */ #define SISL_AFU_LUN_PROVISION_DELETE 0x01 /* LUN provision delete type */ @@ -412,6 +413,7 @@ struct sisl_global_regs { #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 SISL_INTVER_CAP_AFU_DEBUG 0x040000000000ULL }; #define CXLFLASH_NUM_FC_PORTS_PER_BANK 2 /* fixed # of ports per bank */ diff --git a/include/uapi/scsi/cxlflash_ioctl.h b/include/uapi/scsi/cxlflash_ioctl.h index ad79c34f4d11..48d107e75cf2 100644 --- a/include/uapi/scsi/cxlflash_ioctl.h +++ b/include/uapi/scsi/cxlflash_ioctl.h @@ -17,6 +17,11 @@ #include +/* + * Structure and definitions for all CXL Flash ioctls + */ +#define CXLFLASH_WWID_LEN 16 + /* * Structure and flag definitions CXL Flash superpipe ioctls */ @@ -151,7 +156,7 @@ struct dk_cxlflash_recover_afu { __u64 reserved[8]; /* Reserved for future use */ }; -#define DK_CXLFLASH_MANAGE_LUN_WWID_LEN 16 +#define DK_CXLFLASH_MANAGE_LUN_WWID_LEN CXLFLASH_WWID_LEN #define DK_CXLFLASH_MANAGE_LUN_ENABLE_SUPERPIPE 0x8000000000000000ULL #define DK_CXLFLASH_MANAGE_LUN_DISABLE_SUPERPIPE 0x4000000000000000ULL #define DK_CXLFLASH_MANAGE_LUN_ALL_PORTS_ACCESSIBLE 0x2000000000000000ULL @@ -209,10 +214,20 @@ struct ht_cxlflash_hdr { __u64 return_flags; /* Returned flags */ }; +/* + * Input flag definitions available to all host ioctls + * + * These are grown from the bottom-up with the intention that ioctl-specific + * input flag definitions would grow from the top-down, allowing the two sets + * to co-exist. While not required/enforced at this time, this provides future + * flexibility. + */ +#define HT_CXLFLASH_HOST_READ 0x0000000000000000ULL +#define HT_CXLFLASH_HOST_WRITE 0x0000000000000001ULL + #define HT_CXLFLASH_LUN_PROVISION_SUBCMD_CREATE_LUN 0x0001 #define HT_CXLFLASH_LUN_PROVISION_SUBCMD_DELETE_LUN 0x0002 #define HT_CXLFLASH_LUN_PROVISION_SUBCMD_QUERY_PORT 0x0003 -#define HT_CXLFLASH_LUN_PROVISION_WWID_LEN 16 struct ht_cxlflash_lun_provision { struct ht_cxlflash_hdr hdr; /* Common fields */ @@ -220,7 +235,7 @@ struct ht_cxlflash_lun_provision { __u16 reserved16[3]; /* Reserved for future use */ __u64 size; /* Size of LUN (4K blocks) */ __u64 lun_id; /* SCSI LUN ID */ - __u8 wwid[HT_CXLFLASH_LUN_PROVISION_WWID_LEN]; /* Page83 WWID, NAA-6 */ + __u8 wwid[CXLFLASH_WWID_LEN];/* Page83 WWID, NAA-6 */ __u64 max_num_luns; /* Maximum number of LUNs provisioned */ __u64 cur_num_luns; /* Current number of LUNs provisioned */ __u64 max_cap_port; /* Total capacity for port (4K blocks) */ @@ -228,8 +243,23 @@ struct ht_cxlflash_lun_provision { __u64 reserved[8]; /* Reserved for future use */ }; +#define HT_CXLFLASH_AFU_DEBUG_MAX_DATA_LEN 262144 /* 256K */ +#define HT_CXLFLASH_AFU_DEBUG_SUBCMD_LEN 12 +struct ht_cxlflash_afu_debug { + struct ht_cxlflash_hdr hdr; /* Common fields */ + __u8 reserved8[4]; /* Reserved for future use */ + __u8 afu_subcmd[HT_CXLFLASH_AFU_DEBUG_SUBCMD_LEN]; /* AFU subcommand, + * (pass through) + */ + __u64 data_ea; /* Data buffer effective address */ + __u32 data_len; /* Data buffer length */ + __u32 reserved32; /* Reserved for future use */ + __u64 reserved[8]; /* Reserved for future use */ +}; + union cxlflash_ht_ioctls { struct ht_cxlflash_lun_provision lun_provision; + struct ht_cxlflash_afu_debug afu_debug; }; #define MAX_HT_CXLFLASH_IOCTL_SZ (sizeof(union cxlflash_ht_ioctls)) @@ -239,6 +269,7 @@ union cxlflash_ht_ioctls { * region (0xBF) and grow downwards. */ #define HT_CXLFLASH_LUN_PROVISION CXL_IOWR(0xBF, ht_cxlflash_lun_provision) +#define HT_CXLFLASH_AFU_DEBUG CXL_IOWR(0xBE, ht_cxlflash_afu_debug) #endif /* ifndef _CXLFLASH_IOCTL_H */ -- cgit v1.2.3