Commit d6e32f53 authored by Matthew R. Ochs's avatar Matthew R. Ochs Committed by Martin K. Petersen
Browse files

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: default avatarMatthew R. Ochs <mrochs@linux.vnet.ibm.com>
Signed-off-by: default avatarUma Krishnan <ukrishn@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent cf243027
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -326,7 +326,7 @@ Code Seq#(hex) Include File Comments
0xB5	00-0F	uapi/linux/rpmsg.h	<mailto:linux-remoteproc@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.klein@puffin.lb.shuttle.de>
0xCD	01	linux/reiserfs_fs.h
+17 −2
Original line number Diff line number Diff line
@@ -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
+120 −1
Original line number Diff line number Diff line
@@ -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,
};

/**
+30 −1
Original line number Diff line number Diff line
@@ -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 */