From: "Matthew R. Ochs" <mro...@linux.vnet.ibm.com>

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 <mro...@linux.vnet.ibm.com>
Signed-off-by: Uma Krishnan <ukri...@linux.vnet.ibm.com>
---
 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(-)

diff --git a/Documentation/ioctl/ioctl-number.txt 
b/Documentation/ioctl/ioctl-number.txt
index 08244be..6b6cc4c 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -324,7 +324,7 @@ Code  Seq#(hex)     Include File            Comments
 0xB5   00-0F   uapi/linux/rpmsg.h      
<mailto:linux-remotep...@vger.kernel.org>
 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:
                                        
<mailto:michael.kl...@puffin.lb.shuttle.de>
 0xCD   01      linux/reiserfs_fs.h
diff --git a/Documentation/powerpc/cxlflash.txt 
b/Documentation/powerpc/cxlflash.txt
index f9036cb..ee67021 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 7732dfc..be468ed1 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 e9fdc12..87e1f63 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 */
-- 
2.1.0

Reply via email to