Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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: 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 9cf43a36
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -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.
+5 −0
Original line number Diff line number Diff line
@@ -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);
+96 −0
Original line number Diff line number Diff line
@@ -3325,6 +3325,99 @@ static int cxlflash_lun_provision(struct cxlflash_cfg *cfg,
	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;
+1 −0
Original line number Diff line number Diff line
@@ -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
+2 −0
Original line number Diff line number Diff line
@@ -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 */
Loading