mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 03:35:32 -04:00
scsi: qla2xxx: Add flash block read/write BSG support for 29xx
Introduce QL_VND_READ_FLASH_BLOCK and QL_VND_WRITE_FLASH_BLOCK BSG vendor commands so that userspace tools can perform flash block-level operations on 29xx adapters via the isp_ops interface. Signed-off-by: Manish Rangankar <mrangankar@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Reviewed-by: Hannes Reinecke <hare@kernel.org> Link: https://patch.msgid.link/20260723050413.3897522-8-njavali@marvell.com Signed-off-by: Martin K. Petersen (Oracle) <mkp@kernel.org>
This commit is contained in:
committed by
Martin K. Petersen (Oracle)
parent
5cbc49d5c4
commit
2efa08b894
@@ -1407,23 +1407,14 @@ qla24xx_iidma(struct bsg_job *bsg_job)
|
||||
|
||||
static int
|
||||
qla2x00_optrom_setup(struct bsg_job *bsg_job, scsi_qla_host_t *vha,
|
||||
uint8_t is_update)
|
||||
uint32_t start, uint8_t is_update)
|
||||
{
|
||||
struct fc_bsg_request *bsg_request = bsg_job->request;
|
||||
uint32_t start = 0;
|
||||
int valid = 0;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (unlikely(pci_channel_offline(ha->pdev)))
|
||||
return -EINVAL;
|
||||
|
||||
start = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
|
||||
if (start > ha->optrom_size) {
|
||||
ql_log(ql_log_warn, vha, 0x7055,
|
||||
"start %d > optrom_size %d.\n", start, ha->optrom_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ha->optrom_state != QLA_SWAITING) {
|
||||
ql_log(ql_log_info, vha, 0x7056,
|
||||
"optrom_state %d.\n", ha->optrom_state);
|
||||
@@ -1431,42 +1422,79 @@ qla2x00_optrom_setup(struct bsg_job *bsg_job, scsi_qla_host_t *vha,
|
||||
}
|
||||
|
||||
ha->optrom_region_start = start;
|
||||
ql_dbg(ql_dbg_user, vha, 0x7057, "is_update=%d.\n", is_update);
|
||||
if (is_update) {
|
||||
if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)
|
||||
valid = 1;
|
||||
else if (start == (ha->flt_region_boot * 4) ||
|
||||
start == (ha->flt_region_fw * 4))
|
||||
valid = 1;
|
||||
else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) ||
|
||||
IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) ||
|
||||
IS_QLA28XX(ha))
|
||||
valid = 1;
|
||||
if (!valid) {
|
||||
ql_log(ql_log_warn, vha, 0x7058,
|
||||
"Invalid start region 0x%x/0x%x.\n", start,
|
||||
bsg_job->request_payload.payload_len);
|
||||
|
||||
if (IS_QLA29XX(ha)) {
|
||||
if (start > ha->optrom_size) {
|
||||
ql_log(ql_log_warn, vha, 0x7055,
|
||||
"start %d > optrom_size %d.\n", start,
|
||||
ha->optrom_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ha->optrom_region_size = start +
|
||||
bsg_job->request_payload.payload_len > ha->optrom_size ?
|
||||
ha->optrom_size - start :
|
||||
bsg_job->request_payload.payload_len;
|
||||
ha->optrom_state = QLA_SWRITING;
|
||||
if (is_update) {
|
||||
ha->optrom_region_size = start +
|
||||
bsg_job->request_payload.payload_len >
|
||||
ha->optrom_size ?
|
||||
ha->optrom_size - start :
|
||||
bsg_job->request_payload.payload_len;
|
||||
ha->optrom_state = QLA_SWRITING;
|
||||
} else {
|
||||
ha->optrom_region_size = start +
|
||||
bsg_job->reply_payload.payload_len >
|
||||
ha->optrom_size ?
|
||||
ha->optrom_size - start :
|
||||
bsg_job->reply_payload.payload_len;
|
||||
ha->optrom_state = QLA_SREADING;
|
||||
}
|
||||
} else {
|
||||
ha->optrom_region_size = start +
|
||||
bsg_job->reply_payload.payload_len > ha->optrom_size ?
|
||||
ha->optrom_size - start :
|
||||
bsg_job->reply_payload.payload_len;
|
||||
ha->optrom_state = QLA_SREADING;
|
||||
if (start > ha->optrom_size) {
|
||||
ql_log(ql_log_warn, vha, 0x7055,
|
||||
"start %d > optrom_size %d.\n", start,
|
||||
ha->optrom_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ql_dbg(ql_dbg_user, vha, 0x7057,
|
||||
"is_update=%d.\n", is_update);
|
||||
if (is_update) {
|
||||
if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)
|
||||
valid = 1;
|
||||
else if (start == (ha->flt_region_boot * 4) ||
|
||||
start == (ha->flt_region_fw * 4))
|
||||
valid = 1;
|
||||
else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) ||
|
||||
IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) ||
|
||||
IS_QLA27XX(ha) || IS_QLA28XX(ha))
|
||||
valid = 1;
|
||||
if (!valid) {
|
||||
ql_log(ql_log_warn, vha, 0x7058,
|
||||
"Invalid start region 0x%x/0x%x.\n",
|
||||
start,
|
||||
bsg_job->request_payload.payload_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ha->optrom_region_size = start +
|
||||
bsg_job->request_payload.payload_len >
|
||||
ha->optrom_size ?
|
||||
ha->optrom_size - start :
|
||||
bsg_job->request_payload.payload_len;
|
||||
ha->optrom_state = QLA_SWRITING;
|
||||
} else {
|
||||
ha->optrom_region_size = start +
|
||||
bsg_job->reply_payload.payload_len >
|
||||
ha->optrom_size ?
|
||||
ha->optrom_size - start :
|
||||
bsg_job->reply_payload.payload_len;
|
||||
ha->optrom_state = QLA_SREADING;
|
||||
}
|
||||
}
|
||||
|
||||
ha->optrom_buffer = vzalloc(ha->optrom_region_size);
|
||||
if (!ha->optrom_buffer) {
|
||||
ql_log(ql_log_warn, vha, 0x7059,
|
||||
"Read: Unable to allocate memory for optrom retrieval "
|
||||
"(%x)\n", ha->optrom_region_size);
|
||||
"%s: Unable to allocate memory for optrom retrieval (%x)\n",
|
||||
__func__, ha->optrom_region_size);
|
||||
|
||||
ha->optrom_state = QLA_SWAITING;
|
||||
return -ENOMEM;
|
||||
@@ -1478,17 +1506,25 @@ qla2x00_optrom_setup(struct bsg_job *bsg_job, scsi_qla_host_t *vha,
|
||||
static int
|
||||
qla2x00_read_optrom(struct bsg_job *bsg_job)
|
||||
{
|
||||
struct fc_bsg_request *bsg_request = bsg_job->request;
|
||||
struct fc_bsg_reply *bsg_reply = bsg_job->reply;
|
||||
struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
|
||||
scsi_qla_host_t *vha = shost_priv(host);
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint32_t start = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
|
||||
int rval = 0;
|
||||
|
||||
if (ha->flags.nic_core_reset_hdlr_active)
|
||||
return -EBUSY;
|
||||
|
||||
if (IS_QLA29XX(ha)) {
|
||||
ql_log(ql_log_warn, vha, 0x7070,
|
||||
"Legacy optrom read not supported on 29xx.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&ha->optrom_mutex);
|
||||
rval = qla2x00_optrom_setup(bsg_job, vha, 0);
|
||||
rval = qla2x00_optrom_setup(bsg_job, vha, start, 0);
|
||||
if (rval) {
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
return rval;
|
||||
@@ -1515,14 +1551,16 @@ qla2x00_read_optrom(struct bsg_job *bsg_job)
|
||||
static int
|
||||
qla2x00_update_optrom(struct bsg_job *bsg_job)
|
||||
{
|
||||
struct fc_bsg_request *bsg_request = bsg_job->request;
|
||||
struct fc_bsg_reply *bsg_reply = bsg_job->reply;
|
||||
struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
|
||||
scsi_qla_host_t *vha = shost_priv(host);
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint32_t start = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
|
||||
int rval = 0;
|
||||
|
||||
mutex_lock(&ha->optrom_mutex);
|
||||
rval = qla2x00_optrom_setup(bsg_job, vha, 1);
|
||||
rval = qla2x00_optrom_setup(bsg_job, vha, start, 1);
|
||||
if (rval) {
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
return rval;
|
||||
@@ -1554,6 +1592,182 @@ qla2x00_update_optrom(struct bsg_job *bsg_job)
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla29xx_bsg_flash_block_read - Read flash block for QLA29XX.
|
||||
* @bsg_job: BSG job structure.
|
||||
*
|
||||
* Returns 0 on success, error code on failure.
|
||||
*/
|
||||
static int qla29xx_bsg_flash_block_read(struct bsg_job *bsg_job)
|
||||
{
|
||||
struct fc_bsg_request *bsg_req = bsg_job->request;
|
||||
struct fc_bsg_reply *bsg_reply = bsg_job->reply;
|
||||
struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
|
||||
scsi_qla_host_t *vha = shost_priv(host);
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct qla_block_rw *brcmd;
|
||||
void *buf;
|
||||
uint16_t opts = 0;
|
||||
int rval = 0;
|
||||
|
||||
if (bsg_job->request_len < sizeof(struct fc_bsg_request) +
|
||||
2 * sizeof(uint32_t) + sizeof(struct qla_block_rw))
|
||||
return -EINVAL;
|
||||
|
||||
brcmd =
|
||||
(struct qla_block_rw *)&bsg_req->rqst_data.h_vendor.vendor_cmd[2];
|
||||
|
||||
ql_log(ql_log_info, vha, 0x7062,
|
||||
"%s: region 0x%x options 0x%x rw_length 0x%x offset 0x%x chunk_length 0x%x\n",
|
||||
__func__, brcmd->region, brcmd->options, brcmd->rw_length,
|
||||
brcmd->region_offset, brcmd->chunk_length);
|
||||
|
||||
if (brcmd->region > U16_MAX) {
|
||||
ql_log(ql_log_warn, vha, 0x7066,
|
||||
"%s: invalid region 0x%x\n", __func__, brcmd->region);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&ha->optrom_mutex);
|
||||
rval = qla2x00_optrom_setup(bsg_job, vha, brcmd->region_offset, 0);
|
||||
if (rval) {
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
return rval;
|
||||
}
|
||||
|
||||
check_and_set_mbc_bits(brcmd->options, opts, QLA_IS_TIM, BIT_15);
|
||||
check_and_set_mbc_bits(brcmd->options, opts, QLA_IS_SECURE, BIT_7);
|
||||
check_and_set_mbc_bits(brcmd->options, opts, QLA_UPDATE_MBR, BIT_8);
|
||||
|
||||
if (!ha->isp_ops->read_optrom_region) {
|
||||
vfree(ha->optrom_buffer);
|
||||
ha->optrom_buffer = NULL;
|
||||
ha->optrom_state = QLA_SWAITING;
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
buf = ha->isp_ops->read_optrom_region(vha, brcmd->region, opts,
|
||||
ha->optrom_buffer, ha->optrom_region_start,
|
||||
ha->optrom_region_size);
|
||||
if (!buf) {
|
||||
ql_log(ql_log_warn, vha, 0x7063,
|
||||
"%s failed to read flash region 0x%x\n",
|
||||
__func__, brcmd->region);
|
||||
bsg_reply->result = -EINVAL;
|
||||
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
|
||||
EXT_STATUS_MAILBOX;
|
||||
bsg_reply->reply_payload_rcv_len = 0;
|
||||
} else {
|
||||
bsg_reply->result = DID_OK;
|
||||
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
|
||||
EXT_STATUS_OK;
|
||||
|
||||
ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, vha, 0x72a6,
|
||||
ha->optrom_buffer, ha->optrom_region_size);
|
||||
|
||||
sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
|
||||
bsg_job->reply_payload.sg_cnt,
|
||||
ha->optrom_buffer,
|
||||
ha->optrom_region_size);
|
||||
|
||||
bsg_reply->reply_payload_rcv_len = ha->optrom_region_size;
|
||||
}
|
||||
vfree(ha->optrom_buffer);
|
||||
ha->optrom_buffer = NULL;
|
||||
ha->optrom_state = QLA_SWAITING;
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
bsg_job_done(bsg_job, bsg_reply->result,
|
||||
bsg_reply->reply_payload_rcv_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla29xx_bsg_flash_block_write - Write flash block for QLA29XX.
|
||||
* @bsg_job: BSG job structure.
|
||||
*
|
||||
* Returns 0 on success, error code on failure.
|
||||
*/
|
||||
static int qla29xx_bsg_flash_block_write(struct bsg_job *bsg_job)
|
||||
{
|
||||
struct fc_bsg_request *bsg_req = bsg_job->request;
|
||||
struct fc_bsg_reply *bsg_reply = bsg_job->reply;
|
||||
struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
|
||||
scsi_qla_host_t *vha = shost_priv(host);
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct qla_block_rw *bwcmd;
|
||||
uint16_t opts = 0;
|
||||
int rval = 0;
|
||||
|
||||
if (bsg_job->request_len < sizeof(struct fc_bsg_request) +
|
||||
2 * sizeof(uint32_t) + sizeof(struct qla_block_rw))
|
||||
return -EINVAL;
|
||||
|
||||
bwcmd =
|
||||
(struct qla_block_rw *)&bsg_req->rqst_data.h_vendor.vendor_cmd[2];
|
||||
|
||||
ql_log(ql_log_info, vha, 0x7064,
|
||||
"%s: region 0x%x options 0x%x rw_length 0x%x offset 0x%x chunk_length 0x%x\n",
|
||||
__func__, bwcmd->region, bwcmd->options, bwcmd->rw_length,
|
||||
bwcmd->region_offset, bwcmd->chunk_length);
|
||||
|
||||
if (bwcmd->region > U16_MAX) {
|
||||
ql_log(ql_log_warn, vha, 0x7067,
|
||||
"%s: invalid region 0x%x\n", __func__, bwcmd->region);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&ha->optrom_mutex);
|
||||
rval = qla2x00_optrom_setup(bsg_job, vha, bwcmd->region_offset, 1);
|
||||
if (rval) {
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
return rval;
|
||||
}
|
||||
|
||||
sg_copy_to_buffer(bsg_job->request_payload.sg_list,
|
||||
bsg_job->request_payload.sg_cnt, ha->optrom_buffer,
|
||||
ha->optrom_region_size);
|
||||
|
||||
ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, vha, 0x73a6,
|
||||
ha->optrom_buffer, ha->optrom_region_size);
|
||||
|
||||
check_and_set_mbc_bits(bwcmd->options, opts, QLA_IS_TIM, BIT_15);
|
||||
check_and_set_mbc_bits(bwcmd->options, opts, QLA_IS_SECURE, BIT_7);
|
||||
check_and_set_mbc_bits(bwcmd->options, opts, QLA_UPDATE_MBR, BIT_8);
|
||||
|
||||
if (!ha->isp_ops->write_optrom_region) {
|
||||
vfree(ha->optrom_buffer);
|
||||
ha->optrom_buffer = NULL;
|
||||
ha->optrom_state = QLA_SWAITING;
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rval = ha->isp_ops->write_optrom_region(vha, bwcmd->region, opts,
|
||||
ha->optrom_buffer, ha->optrom_region_start,
|
||||
ha->optrom_region_size);
|
||||
if (rval) {
|
||||
ql_log(ql_log_warn, vha, 0x7065,
|
||||
"%s failed to write flash %x\n", __func__, rval);
|
||||
bsg_reply->result = -EINVAL;
|
||||
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
|
||||
EXT_STATUS_MAILBOX;
|
||||
} else {
|
||||
bsg_reply->result = DID_OK;
|
||||
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
|
||||
EXT_STATUS_OK;
|
||||
}
|
||||
vfree(ha->optrom_buffer);
|
||||
ha->optrom_buffer = NULL;
|
||||
ha->optrom_state = QLA_SWAITING;
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
bsg_job->reply_len = sizeof(struct fc_bsg_reply);
|
||||
bsg_job_done(bsg_job, bsg_reply->result,
|
||||
bsg_reply->reply_payload_rcv_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
qla2x00_update_fru_versions(struct bsg_job *bsg_job)
|
||||
{
|
||||
@@ -3007,6 +3221,12 @@ qla2x00_process_vendor_specific(struct scsi_qla_host *vha, struct bsg_job *bsg_j
|
||||
case QL_VND_MBX_PASSTHRU:
|
||||
return qla2x00_mailbox_passthru(bsg_job);
|
||||
|
||||
case QL_VND_READ_FLASH_BLOCK:
|
||||
return qla29xx_bsg_flash_block_read(bsg_job);
|
||||
|
||||
case QL_VND_WRITE_FLASH_BLOCK:
|
||||
return qla29xx_bsg_flash_block_write(bsg_job);
|
||||
|
||||
default:
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
#define QL_VND_MBX_PASSTHRU 0x2B
|
||||
#define QL_VND_DPORT_DIAGNOSTICS_V2 0x2C
|
||||
#define QL_VND_IMG_SET_VALID 0x30
|
||||
#define QL_VND_READ_FLASH_BLOCK 0x33
|
||||
#define QL_VND_WRITE_FLASH_BLOCK 0x34
|
||||
|
||||
/* BSG Vendor specific subcode returns */
|
||||
#define EXT_STATUS_OK 0
|
||||
@@ -83,6 +85,20 @@
|
||||
#define ELS_OPCODE_BYTE 0x10
|
||||
|
||||
/* BSG Vendor specific definations */
|
||||
|
||||
#define QLA_IS_TIM 0x1
|
||||
#define QLA_IS_SECURE 0x2
|
||||
#define QLA_UPDATE_MBR 0x4
|
||||
|
||||
struct qla_block_rw {
|
||||
uint32_t region;
|
||||
uint32_t rw_length;
|
||||
uint32_t options;
|
||||
uint32_t region_offset;
|
||||
uint32_t chunk_length;
|
||||
uint8_t reserved[44];
|
||||
} __packed;
|
||||
|
||||
#define A84_ISSUE_WRITE_TYPE_CMD 0
|
||||
#define A84_ISSUE_READ_TYPE_CMD 1
|
||||
#define A84_CLEANUP_CMD 2
|
||||
|
||||
@@ -3534,6 +3534,13 @@ struct isp_operations {
|
||||
int (*write_optrom)(struct scsi_qla_host *, void *, uint32_t,
|
||||
uint32_t);
|
||||
|
||||
void *(*read_optrom_region)(struct scsi_qla_host *vha,
|
||||
uint16_t reg_code, uint16_t opts, void *buf,
|
||||
uint32_t offset, uint32_t length);
|
||||
int (*write_optrom_region)(struct scsi_qla_host *vha,
|
||||
uint16_t reg_code, uint16_t opts, void *buf,
|
||||
uint32_t offset, uint32_t length);
|
||||
|
||||
int (*get_flash_version) (struct scsi_qla_host *, void *);
|
||||
int (*start_scsi) (srb_t *);
|
||||
int (*start_scsi_mq) (srb_t *);
|
||||
|
||||
@@ -2640,6 +2640,24 @@ static struct isp_operations qla27xx_isp_ops = {
|
||||
.initialize_adapter = qla2x00_initialize_adapter,
|
||||
};
|
||||
|
||||
static void *
|
||||
qla29xx_read_optrom_stub(struct scsi_qla_host *vha, void *buf,
|
||||
uint32_t offset, uint32_t length)
|
||||
{
|
||||
ql_dbg(ql_dbg_init, vha, 0x0191,
|
||||
"read_optrom not supported on 29xx, use read_optrom_region.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
qla29xx_write_optrom_stub(struct scsi_qla_host *vha, void *buf,
|
||||
uint32_t offset, uint32_t length)
|
||||
{
|
||||
ql_dbg(ql_dbg_init, vha, 0x0192,
|
||||
"write_optrom not supported on 29xx, use write_optrom_region.\n");
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
static struct isp_operations qla29xx_isp_ops = {
|
||||
.pci_config = qla25xx_pci_config,
|
||||
.reset_chip = qla24xx_reset_chip,
|
||||
@@ -2670,8 +2688,10 @@ static struct isp_operations qla29xx_isp_ops = {
|
||||
.beacon_on = qla24xx_beacon_on,
|
||||
.beacon_off = qla24xx_beacon_off,
|
||||
.beacon_blink = qla83xx_beacon_blink,
|
||||
.read_optrom = qla25xx_read_optrom_data,
|
||||
.write_optrom = qla24xx_write_optrom_data,
|
||||
.read_optrom = qla29xx_read_optrom_stub,
|
||||
.write_optrom = qla29xx_write_optrom_stub,
|
||||
.read_optrom_region = qla29xx_read_optrom_data,
|
||||
.write_optrom_region = qla29xx_write_optrom_data,
|
||||
.get_flash_version = qla24xx_get_flash_version,
|
||||
.start_scsi_mq = qla2xxx_dif_start_scsi_mq,
|
||||
.abort_isp = qla2x00_abort_isp,
|
||||
|
||||
Reference in New Issue
Block a user