@@ -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.
@@ -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);
@@ -3227,14 +3227,105 @@ 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.
* @cmd: IOCTL command.
@@ -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;
@@ -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
@@ -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 */
@@ -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 */