summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/cxlflash
diff options
context:
space:
mode:
authorMatthew R. Ochs <mrochs@linux.vnet.ibm.com>2017-06-21 21:16:22 -0500
committerMartin K. Petersen <martin.petersen@oracle.com>2017-06-26 15:01:12 -0400
commitbc88ac47d5cb11c7dd9896781f793fae519d53fa (patch)
tree0a5955e480acc1eeef0a2388697f77c516695d80 /drivers/scsi/cxlflash
parent9cf43a360450ddd758b0021d1b55f1cc5643b9ed (diff)
downloadlinux-stable-bc88ac47d5cb11c7dd9896781f793fae519d53fa.tar.gz
linux-stable-bc88ac47d5cb11c7dd9896781f793fae519d53fa.tar.bz2
linux-stable-bc88ac47d5cb11c7dd9896781f793fae519d53fa.zip
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 <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.h5
-rw-r--r--drivers/scsi/cxlflash/main.c96
-rw-r--r--drivers/scsi/cxlflash/main.h1
-rw-r--r--drivers/scsi/cxlflash/sislite.h2
4 files changed, 104 insertions, 0 deletions
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
@@ -3326,6 +3326,99 @@ out:
}
/**
+ * 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.
* @cmd: IOCTL command.
@@ -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 */