mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
scsi: mpi3mr: Add ioctl support for HDB
Add interface for applications to manage the host diagnostic buffers and update the automatic diag buffer capture triggers. Co-developed-by: Sathya Prakash <sathya.prakash@broadcom.com> Signed-off-by: Sathya Prakash <sathya.prakash@broadcom.com> Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com> Link: https://lore.kernel.org/r/20240626102646.14298-4-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
d8d08d1638
commit
78b506984e
@ -200,6 +200,18 @@ extern atomic64_t event_counter;
|
||||
#define MPI3MR_HDB_TRIGGER_TYPE_SOFT_RESET 4
|
||||
#define MPI3MR_HDB_TRIGGER_TYPE_FW_RELEASED 5
|
||||
|
||||
#define MPI3MR_HDB_REFRESH_TYPE_RESERVED 0
|
||||
#define MPI3MR_HDB_REFRESH_TYPE_CURRENT 1
|
||||
#define MPI3MR_HDB_REFRESH_TYPE_DEFAULT 2
|
||||
#define MPI3MR_HDB_HDB_REFRESH_TYPE_PERSISTENT 3
|
||||
|
||||
#define MPI3MR_DEFAULT_HDB_SZ (4 * 1024 * 1024)
|
||||
#define MPI3MR_MAX_NUM_HDB 2
|
||||
|
||||
#define MPI3MR_HDB_QUERY_ELEMENT_TRIGGER_FORMAT_INDEX 0
|
||||
#define MPI3MR_HDB_QUERY_ELEMENT_TRIGGER_FORMAT_DATA 1
|
||||
|
||||
|
||||
/* SGE Flag definition */
|
||||
#define MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST \
|
||||
(MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | MPI3_SGE_FLAGS_DLAS_SYSTEM | \
|
||||
|
@ -940,6 +940,259 @@ static struct mpi3mr_ioc *mpi3mr_bsg_verify_adapter(int ioc_number)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpi3mr_bsg_refresh_hdb_triggers - Refresh HDB trigger data
|
||||
* @mrioc: Adapter instance reference
|
||||
* @job: BSG Job pointer
|
||||
*
|
||||
* This function reads the controller trigger config page as
|
||||
* defined by the input page type and refreshes the driver's
|
||||
* local trigger information structures with the controller's
|
||||
* config page data.
|
||||
*
|
||||
* Return: 0 on success and proper error codes on failure
|
||||
*/
|
||||
static long
|
||||
mpi3mr_bsg_refresh_hdb_triggers(struct mpi3mr_ioc *mrioc,
|
||||
struct bsg_job *job)
|
||||
{
|
||||
struct mpi3mr_bsg_out_refresh_hdb_triggers refresh_triggers;
|
||||
uint32_t data_out_sz;
|
||||
u8 page_action;
|
||||
long rval = -EINVAL;
|
||||
|
||||
data_out_sz = job->request_payload.payload_len;
|
||||
|
||||
if (data_out_sz != sizeof(refresh_triggers)) {
|
||||
dprint_bsg_err(mrioc, "%s: invalid size argument\n",
|
||||
__func__);
|
||||
return rval;
|
||||
}
|
||||
|
||||
if (mrioc->unrecoverable) {
|
||||
dprint_bsg_err(mrioc, "%s: unrecoverable controller\n",
|
||||
__func__);
|
||||
return -EFAULT;
|
||||
}
|
||||
if (mrioc->reset_in_progress) {
|
||||
dprint_bsg_err(mrioc, "%s: reset in progress\n", __func__);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
sg_copy_to_buffer(job->request_payload.sg_list,
|
||||
job->request_payload.sg_cnt,
|
||||
&refresh_triggers, sizeof(refresh_triggers));
|
||||
|
||||
switch (refresh_triggers.page_type) {
|
||||
case MPI3MR_HDB_REFRESH_TYPE_CURRENT:
|
||||
page_action = MPI3_CONFIG_ACTION_READ_CURRENT;
|
||||
break;
|
||||
case MPI3MR_HDB_REFRESH_TYPE_DEFAULT:
|
||||
page_action = MPI3_CONFIG_ACTION_READ_DEFAULT;
|
||||
break;
|
||||
case MPI3MR_HDB_HDB_REFRESH_TYPE_PERSISTENT:
|
||||
page_action = MPI3_CONFIG_ACTION_READ_PERSISTENT;
|
||||
break;
|
||||
default:
|
||||
dprint_bsg_err(mrioc,
|
||||
"%s: unsupported refresh trigger, page_type %d\n",
|
||||
__func__, refresh_triggers.page_type);
|
||||
return rval;
|
||||
}
|
||||
rval = mpi3mr_refresh_trigger(mrioc, page_action);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpi3mr_bsg_upload_hdb - Upload a specific HDB to user space
|
||||
* @mrioc: Adapter instance reference
|
||||
* @job: BSG Job pointer
|
||||
*
|
||||
* Return: 0 on success and proper error codes on failure
|
||||
*/
|
||||
static long mpi3mr_bsg_upload_hdb(struct mpi3mr_ioc *mrioc,
|
||||
struct bsg_job *job)
|
||||
{
|
||||
struct mpi3mr_bsg_out_upload_hdb upload_hdb;
|
||||
struct diag_buffer_desc *diag_buffer;
|
||||
uint32_t data_out_size;
|
||||
uint32_t data_in_size;
|
||||
|
||||
data_out_size = job->request_payload.payload_len;
|
||||
data_in_size = job->reply_payload.payload_len;
|
||||
|
||||
if (data_out_size != sizeof(upload_hdb)) {
|
||||
dprint_bsg_err(mrioc, "%s: invalid size argument\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sg_copy_to_buffer(job->request_payload.sg_list,
|
||||
job->request_payload.sg_cnt,
|
||||
&upload_hdb, sizeof(upload_hdb));
|
||||
|
||||
if ((!upload_hdb.length) || (data_in_size != upload_hdb.length)) {
|
||||
dprint_bsg_err(mrioc, "%s: invalid length argument\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
diag_buffer = mpi3mr_diag_buffer_for_type(mrioc, upload_hdb.buf_type);
|
||||
if ((!diag_buffer) || (!diag_buffer->addr)) {
|
||||
dprint_bsg_err(mrioc, "%s: invalid buffer type %d\n",
|
||||
__func__, upload_hdb.buf_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((diag_buffer->status != MPI3MR_HDB_BUFSTATUS_RELEASED) &&
|
||||
(diag_buffer->status != MPI3MR_HDB_BUFSTATUS_POSTED_PAUSED)) {
|
||||
dprint_bsg_err(mrioc,
|
||||
"%s: invalid buffer status %d for type %d\n",
|
||||
__func__, diag_buffer->status, upload_hdb.buf_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((upload_hdb.start_offset + upload_hdb.length) > diag_buffer->size) {
|
||||
dprint_bsg_err(mrioc,
|
||||
"%s: invalid start offset %d, length %d for type %d\n",
|
||||
__func__, upload_hdb.start_offset, upload_hdb.length,
|
||||
upload_hdb.buf_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
sg_copy_from_buffer(job->reply_payload.sg_list,
|
||||
job->reply_payload.sg_cnt,
|
||||
(diag_buffer->addr + upload_hdb.start_offset),
|
||||
data_in_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpi3mr_bsg_repost_hdb - Re-post HDB
|
||||
* @mrioc: Adapter instance reference
|
||||
* @job: BSG job pointer
|
||||
*
|
||||
* This function retrieves the HDB descriptor corresponding to a
|
||||
* given buffer type and if the HDB is in released status then
|
||||
* posts the HDB with the firmware.
|
||||
*
|
||||
* Return: 0 on success and proper error codes on failure
|
||||
*/
|
||||
static long mpi3mr_bsg_repost_hdb(struct mpi3mr_ioc *mrioc,
|
||||
struct bsg_job *job)
|
||||
{
|
||||
struct mpi3mr_bsg_out_repost_hdb repost_hdb;
|
||||
struct diag_buffer_desc *diag_buffer;
|
||||
uint32_t data_out_sz;
|
||||
|
||||
data_out_sz = job->request_payload.payload_len;
|
||||
|
||||
if (data_out_sz != sizeof(repost_hdb)) {
|
||||
dprint_bsg_err(mrioc, "%s: invalid size argument\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (mrioc->unrecoverable) {
|
||||
dprint_bsg_err(mrioc, "%s: unrecoverable controller\n",
|
||||
__func__);
|
||||
return -EFAULT;
|
||||
}
|
||||
if (mrioc->reset_in_progress) {
|
||||
dprint_bsg_err(mrioc, "%s: reset in progress\n", __func__);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
sg_copy_to_buffer(job->request_payload.sg_list,
|
||||
job->request_payload.sg_cnt,
|
||||
&repost_hdb, sizeof(repost_hdb));
|
||||
|
||||
diag_buffer = mpi3mr_diag_buffer_for_type(mrioc, repost_hdb.buf_type);
|
||||
if ((!diag_buffer) || (!diag_buffer->addr)) {
|
||||
dprint_bsg_err(mrioc, "%s: invalid buffer type %d\n",
|
||||
__func__, repost_hdb.buf_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (diag_buffer->status != MPI3MR_HDB_BUFSTATUS_RELEASED) {
|
||||
dprint_bsg_err(mrioc,
|
||||
"%s: invalid buffer status %d for type %d\n",
|
||||
__func__, diag_buffer->status, repost_hdb.buf_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (mpi3mr_issue_diag_buf_post(mrioc, diag_buffer)) {
|
||||
dprint_bsg_err(mrioc, "%s: post failed for type %d\n",
|
||||
__func__, repost_hdb.buf_type);
|
||||
return -EFAULT;
|
||||
}
|
||||
mpi3mr_set_trigger_data_in_hdb(diag_buffer,
|
||||
MPI3MR_HDB_TRIGGER_TYPE_UNKNOWN, NULL, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpi3mr_bsg_query_hdb - Handler for query HDB command
|
||||
* @mrioc: Adapter instance reference
|
||||
* @job: BSG job pointer
|
||||
*
|
||||
* This function prepares and copies the host diagnostic buffer
|
||||
* entries to the user buffer.
|
||||
*
|
||||
* Return: 0 on success and proper error codes on failure
|
||||
*/
|
||||
static long mpi3mr_bsg_query_hdb(struct mpi3mr_ioc *mrioc,
|
||||
struct bsg_job *job)
|
||||
{
|
||||
long rval = 0;
|
||||
struct mpi3mr_bsg_in_hdb_status *hbd_status;
|
||||
struct mpi3mr_hdb_entry *hbd_status_entry;
|
||||
u32 length, min_length;
|
||||
u8 i;
|
||||
struct diag_buffer_desc *diag_buffer;
|
||||
uint32_t data_in_sz = 0;
|
||||
|
||||
data_in_sz = job->request_payload.payload_len;
|
||||
|
||||
length = (sizeof(*hbd_status) + ((MPI3MR_MAX_NUM_HDB - 1) *
|
||||
sizeof(*hbd_status_entry)));
|
||||
hbd_status = kmalloc(length, GFP_KERNEL);
|
||||
if (!hbd_status)
|
||||
return -ENOMEM;
|
||||
hbd_status_entry = &hbd_status->entry[0];
|
||||
|
||||
hbd_status->num_hdb_types = MPI3MR_MAX_NUM_HDB;
|
||||
for (i = 0; i < MPI3MR_MAX_NUM_HDB; i++) {
|
||||
diag_buffer = &mrioc->diag_buffers[i];
|
||||
hbd_status_entry->buf_type = diag_buffer->type;
|
||||
hbd_status_entry->status = diag_buffer->status;
|
||||
hbd_status_entry->trigger_type = diag_buffer->trigger_type;
|
||||
memcpy(&hbd_status_entry->trigger_data,
|
||||
&diag_buffer->trigger_data,
|
||||
sizeof(hbd_status_entry->trigger_data));
|
||||
hbd_status_entry->size = (diag_buffer->size / 1024);
|
||||
hbd_status_entry++;
|
||||
}
|
||||
hbd_status->element_trigger_format =
|
||||
MPI3MR_HDB_QUERY_ELEMENT_TRIGGER_FORMAT_DATA;
|
||||
|
||||
if (data_in_sz < 4) {
|
||||
dprint_bsg_err(mrioc, "%s: invalid size passed\n", __func__);
|
||||
rval = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
min_length = min(data_in_sz, length);
|
||||
if (job->request_payload.payload_len >= min_length) {
|
||||
sg_copy_from_buffer(job->request_payload.sg_list,
|
||||
job->request_payload.sg_cnt,
|
||||
hbd_status, min_length);
|
||||
rval = 0;
|
||||
}
|
||||
out:
|
||||
kfree(hbd_status);
|
||||
return rval;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* mpi3mr_enable_logdata - Handler for log data enable
|
||||
* @mrioc: Adapter instance reference
|
||||
@ -1368,6 +1621,18 @@ static long mpi3mr_bsg_process_drv_cmds(struct bsg_job *job)
|
||||
case MPI3MR_DRVBSG_OPCODE_PELENABLE:
|
||||
rval = mpi3mr_bsg_pel_enable(mrioc, job);
|
||||
break;
|
||||
case MPI3MR_DRVBSG_OPCODE_QUERY_HDB:
|
||||
rval = mpi3mr_bsg_query_hdb(mrioc, job);
|
||||
break;
|
||||
case MPI3MR_DRVBSG_OPCODE_REPOST_HDB:
|
||||
rval = mpi3mr_bsg_repost_hdb(mrioc, job);
|
||||
break;
|
||||
case MPI3MR_DRVBSG_OPCODE_UPLOAD_HDB:
|
||||
rval = mpi3mr_bsg_upload_hdb(mrioc, job);
|
||||
break;
|
||||
case MPI3MR_DRVBSG_OPCODE_REFRESH_HDB_TRIGGERS:
|
||||
rval = mpi3mr_bsg_refresh_hdb_triggers(mrioc, job);
|
||||
break;
|
||||
case MPI3MR_DRVBSG_OPCODE_UNKNOWN:
|
||||
default:
|
||||
pr_err("%s: unsupported driver command opcode %d\n",
|
||||
|
@ -296,6 +296,7 @@ struct mpi3mr_hdb_entry {
|
||||
* multiple hdb entries.
|
||||
*
|
||||
* @num_hdb_types: Number of host diag buffer types supported
|
||||
* @element_trigger_format: Element trigger format
|
||||
* @rsvd1: Reserved
|
||||
* @rsvd2: Reserved
|
||||
* @rsvd3: Reserved
|
||||
@ -303,7 +304,7 @@ struct mpi3mr_hdb_entry {
|
||||
*/
|
||||
struct mpi3mr_bsg_in_hdb_status {
|
||||
__u8 num_hdb_types;
|
||||
__u8 rsvd1;
|
||||
__u8 element_trigger_format;
|
||||
__u16 rsvd2;
|
||||
__u32 rsvd3;
|
||||
struct mpi3mr_hdb_entry entry[1];
|
||||
|
Loading…
Reference in New Issue
Block a user