scsi: cxlflash: Support LUN provisioning

Adopt the SISLite AFU LUN provisioning capability to allow future CXL
Flash adapters the ability to better manage storage. Update the SISLite
header with the changes necessary to support LUN provision operations
and create a host ioctl interface for user LUN management 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>
This commit is contained in:
Matthew R. Ochs 2017-06-21 21:16:13 -05:00 committed by Martin K. Petersen
parent efa1c818d3
commit 9cf43a3604
6 changed files with 192 additions and 9 deletions

View File

@ -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.

View File

@ -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);

View File

@ -3227,13 +3227,104 @@ 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.
@ -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;

View File

@ -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

View File

@ -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 */

View File

@ -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 */