Skip to content

Commit 78b5069

Browse files
Ranjan Kumarmartinkpetersen
authored andcommitted
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 <[email protected]> Signed-off-by: Sathya Prakash <[email protected]> Signed-off-by: Ranjan Kumar <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Martin K. Petersen <[email protected]>
1 parent d8d08d1 commit 78b5069

File tree

3 files changed

+279
-1
lines changed

3 files changed

+279
-1
lines changed

drivers/scsi/mpi3mr/mpi3mr.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,18 @@ extern atomic64_t event_counter;
200200
#define MPI3MR_HDB_TRIGGER_TYPE_SOFT_RESET 4
201201
#define MPI3MR_HDB_TRIGGER_TYPE_FW_RELEASED 5
202202

203+
#define MPI3MR_HDB_REFRESH_TYPE_RESERVED 0
204+
#define MPI3MR_HDB_REFRESH_TYPE_CURRENT 1
205+
#define MPI3MR_HDB_REFRESH_TYPE_DEFAULT 2
206+
#define MPI3MR_HDB_HDB_REFRESH_TYPE_PERSISTENT 3
207+
208+
#define MPI3MR_DEFAULT_HDB_SZ (4 * 1024 * 1024)
209+
#define MPI3MR_MAX_NUM_HDB 2
210+
211+
#define MPI3MR_HDB_QUERY_ELEMENT_TRIGGER_FORMAT_INDEX 0
212+
#define MPI3MR_HDB_QUERY_ELEMENT_TRIGGER_FORMAT_DATA 1
213+
214+
203215
/* SGE Flag definition */
204216
#define MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST \
205217
(MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | MPI3_SGE_FLAGS_DLAS_SYSTEM | \

drivers/scsi/mpi3mr/mpi3mr_app.c

Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,259 @@ static struct mpi3mr_ioc *mpi3mr_bsg_verify_adapter(int ioc_number)
940940
return NULL;
941941
}
942942

943+
/**
944+
* mpi3mr_bsg_refresh_hdb_triggers - Refresh HDB trigger data
945+
* @mrioc: Adapter instance reference
946+
* @job: BSG Job pointer
947+
*
948+
* This function reads the controller trigger config page as
949+
* defined by the input page type and refreshes the driver's
950+
* local trigger information structures with the controller's
951+
* config page data.
952+
*
953+
* Return: 0 on success and proper error codes on failure
954+
*/
955+
static long
956+
mpi3mr_bsg_refresh_hdb_triggers(struct mpi3mr_ioc *mrioc,
957+
struct bsg_job *job)
958+
{
959+
struct mpi3mr_bsg_out_refresh_hdb_triggers refresh_triggers;
960+
uint32_t data_out_sz;
961+
u8 page_action;
962+
long rval = -EINVAL;
963+
964+
data_out_sz = job->request_payload.payload_len;
965+
966+
if (data_out_sz != sizeof(refresh_triggers)) {
967+
dprint_bsg_err(mrioc, "%s: invalid size argument\n",
968+
__func__);
969+
return rval;
970+
}
971+
972+
if (mrioc->unrecoverable) {
973+
dprint_bsg_err(mrioc, "%s: unrecoverable controller\n",
974+
__func__);
975+
return -EFAULT;
976+
}
977+
if (mrioc->reset_in_progress) {
978+
dprint_bsg_err(mrioc, "%s: reset in progress\n", __func__);
979+
return -EAGAIN;
980+
}
981+
982+
sg_copy_to_buffer(job->request_payload.sg_list,
983+
job->request_payload.sg_cnt,
984+
&refresh_triggers, sizeof(refresh_triggers));
985+
986+
switch (refresh_triggers.page_type) {
987+
case MPI3MR_HDB_REFRESH_TYPE_CURRENT:
988+
page_action = MPI3_CONFIG_ACTION_READ_CURRENT;
989+
break;
990+
case MPI3MR_HDB_REFRESH_TYPE_DEFAULT:
991+
page_action = MPI3_CONFIG_ACTION_READ_DEFAULT;
992+
break;
993+
case MPI3MR_HDB_HDB_REFRESH_TYPE_PERSISTENT:
994+
page_action = MPI3_CONFIG_ACTION_READ_PERSISTENT;
995+
break;
996+
default:
997+
dprint_bsg_err(mrioc,
998+
"%s: unsupported refresh trigger, page_type %d\n",
999+
__func__, refresh_triggers.page_type);
1000+
return rval;
1001+
}
1002+
rval = mpi3mr_refresh_trigger(mrioc, page_action);
1003+
1004+
return rval;
1005+
}
1006+
1007+
/**
1008+
* mpi3mr_bsg_upload_hdb - Upload a specific HDB to user space
1009+
* @mrioc: Adapter instance reference
1010+
* @job: BSG Job pointer
1011+
*
1012+
* Return: 0 on success and proper error codes on failure
1013+
*/
1014+
static long mpi3mr_bsg_upload_hdb(struct mpi3mr_ioc *mrioc,
1015+
struct bsg_job *job)
1016+
{
1017+
struct mpi3mr_bsg_out_upload_hdb upload_hdb;
1018+
struct diag_buffer_desc *diag_buffer;
1019+
uint32_t data_out_size;
1020+
uint32_t data_in_size;
1021+
1022+
data_out_size = job->request_payload.payload_len;
1023+
data_in_size = job->reply_payload.payload_len;
1024+
1025+
if (data_out_size != sizeof(upload_hdb)) {
1026+
dprint_bsg_err(mrioc, "%s: invalid size argument\n",
1027+
__func__);
1028+
return -EINVAL;
1029+
}
1030+
1031+
sg_copy_to_buffer(job->request_payload.sg_list,
1032+
job->request_payload.sg_cnt,
1033+
&upload_hdb, sizeof(upload_hdb));
1034+
1035+
if ((!upload_hdb.length) || (data_in_size != upload_hdb.length)) {
1036+
dprint_bsg_err(mrioc, "%s: invalid length argument\n",
1037+
__func__);
1038+
return -EINVAL;
1039+
}
1040+
diag_buffer = mpi3mr_diag_buffer_for_type(mrioc, upload_hdb.buf_type);
1041+
if ((!diag_buffer) || (!diag_buffer->addr)) {
1042+
dprint_bsg_err(mrioc, "%s: invalid buffer type %d\n",
1043+
__func__, upload_hdb.buf_type);
1044+
return -EINVAL;
1045+
}
1046+
1047+
if ((diag_buffer->status != MPI3MR_HDB_BUFSTATUS_RELEASED) &&
1048+
(diag_buffer->status != MPI3MR_HDB_BUFSTATUS_POSTED_PAUSED)) {
1049+
dprint_bsg_err(mrioc,
1050+
"%s: invalid buffer status %d for type %d\n",
1051+
__func__, diag_buffer->status, upload_hdb.buf_type);
1052+
return -EINVAL;
1053+
}
1054+
1055+
if ((upload_hdb.start_offset + upload_hdb.length) > diag_buffer->size) {
1056+
dprint_bsg_err(mrioc,
1057+
"%s: invalid start offset %d, length %d for type %d\n",
1058+
__func__, upload_hdb.start_offset, upload_hdb.length,
1059+
upload_hdb.buf_type);
1060+
return -EINVAL;
1061+
}
1062+
sg_copy_from_buffer(job->reply_payload.sg_list,
1063+
job->reply_payload.sg_cnt,
1064+
(diag_buffer->addr + upload_hdb.start_offset),
1065+
data_in_size);
1066+
return 0;
1067+
}
1068+
1069+
/**
1070+
* mpi3mr_bsg_repost_hdb - Re-post HDB
1071+
* @mrioc: Adapter instance reference
1072+
* @job: BSG job pointer
1073+
*
1074+
* This function retrieves the HDB descriptor corresponding to a
1075+
* given buffer type and if the HDB is in released status then
1076+
* posts the HDB with the firmware.
1077+
*
1078+
* Return: 0 on success and proper error codes on failure
1079+
*/
1080+
static long mpi3mr_bsg_repost_hdb(struct mpi3mr_ioc *mrioc,
1081+
struct bsg_job *job)
1082+
{
1083+
struct mpi3mr_bsg_out_repost_hdb repost_hdb;
1084+
struct diag_buffer_desc *diag_buffer;
1085+
uint32_t data_out_sz;
1086+
1087+
data_out_sz = job->request_payload.payload_len;
1088+
1089+
if (data_out_sz != sizeof(repost_hdb)) {
1090+
dprint_bsg_err(mrioc, "%s: invalid size argument\n",
1091+
__func__);
1092+
return -EINVAL;
1093+
}
1094+
if (mrioc->unrecoverable) {
1095+
dprint_bsg_err(mrioc, "%s: unrecoverable controller\n",
1096+
__func__);
1097+
return -EFAULT;
1098+
}
1099+
if (mrioc->reset_in_progress) {
1100+
dprint_bsg_err(mrioc, "%s: reset in progress\n", __func__);
1101+
return -EAGAIN;
1102+
}
1103+
1104+
sg_copy_to_buffer(job->request_payload.sg_list,
1105+
job->request_payload.sg_cnt,
1106+
&repost_hdb, sizeof(repost_hdb));
1107+
1108+
diag_buffer = mpi3mr_diag_buffer_for_type(mrioc, repost_hdb.buf_type);
1109+
if ((!diag_buffer) || (!diag_buffer->addr)) {
1110+
dprint_bsg_err(mrioc, "%s: invalid buffer type %d\n",
1111+
__func__, repost_hdb.buf_type);
1112+
return -EINVAL;
1113+
}
1114+
1115+
if (diag_buffer->status != MPI3MR_HDB_BUFSTATUS_RELEASED) {
1116+
dprint_bsg_err(mrioc,
1117+
"%s: invalid buffer status %d for type %d\n",
1118+
__func__, diag_buffer->status, repost_hdb.buf_type);
1119+
return -EINVAL;
1120+
}
1121+
1122+
if (mpi3mr_issue_diag_buf_post(mrioc, diag_buffer)) {
1123+
dprint_bsg_err(mrioc, "%s: post failed for type %d\n",
1124+
__func__, repost_hdb.buf_type);
1125+
return -EFAULT;
1126+
}
1127+
mpi3mr_set_trigger_data_in_hdb(diag_buffer,
1128+
MPI3MR_HDB_TRIGGER_TYPE_UNKNOWN, NULL, 1);
1129+
1130+
return 0;
1131+
}
1132+
1133+
/**
1134+
* mpi3mr_bsg_query_hdb - Handler for query HDB command
1135+
* @mrioc: Adapter instance reference
1136+
* @job: BSG job pointer
1137+
*
1138+
* This function prepares and copies the host diagnostic buffer
1139+
* entries to the user buffer.
1140+
*
1141+
* Return: 0 on success and proper error codes on failure
1142+
*/
1143+
static long mpi3mr_bsg_query_hdb(struct mpi3mr_ioc *mrioc,
1144+
struct bsg_job *job)
1145+
{
1146+
long rval = 0;
1147+
struct mpi3mr_bsg_in_hdb_status *hbd_status;
1148+
struct mpi3mr_hdb_entry *hbd_status_entry;
1149+
u32 length, min_length;
1150+
u8 i;
1151+
struct diag_buffer_desc *diag_buffer;
1152+
uint32_t data_in_sz = 0;
1153+
1154+
data_in_sz = job->request_payload.payload_len;
1155+
1156+
length = (sizeof(*hbd_status) + ((MPI3MR_MAX_NUM_HDB - 1) *
1157+
sizeof(*hbd_status_entry)));
1158+
hbd_status = kmalloc(length, GFP_KERNEL);
1159+
if (!hbd_status)
1160+
return -ENOMEM;
1161+
hbd_status_entry = &hbd_status->entry[0];
1162+
1163+
hbd_status->num_hdb_types = MPI3MR_MAX_NUM_HDB;
1164+
for (i = 0; i < MPI3MR_MAX_NUM_HDB; i++) {
1165+
diag_buffer = &mrioc->diag_buffers[i];
1166+
hbd_status_entry->buf_type = diag_buffer->type;
1167+
hbd_status_entry->status = diag_buffer->status;
1168+
hbd_status_entry->trigger_type = diag_buffer->trigger_type;
1169+
memcpy(&hbd_status_entry->trigger_data,
1170+
&diag_buffer->trigger_data,
1171+
sizeof(hbd_status_entry->trigger_data));
1172+
hbd_status_entry->size = (diag_buffer->size / 1024);
1173+
hbd_status_entry++;
1174+
}
1175+
hbd_status->element_trigger_format =
1176+
MPI3MR_HDB_QUERY_ELEMENT_TRIGGER_FORMAT_DATA;
1177+
1178+
if (data_in_sz < 4) {
1179+
dprint_bsg_err(mrioc, "%s: invalid size passed\n", __func__);
1180+
rval = -EINVAL;
1181+
goto out;
1182+
}
1183+
min_length = min(data_in_sz, length);
1184+
if (job->request_payload.payload_len >= min_length) {
1185+
sg_copy_from_buffer(job->request_payload.sg_list,
1186+
job->request_payload.sg_cnt,
1187+
hbd_status, min_length);
1188+
rval = 0;
1189+
}
1190+
out:
1191+
kfree(hbd_status);
1192+
return rval;
1193+
}
1194+
1195+
9431196
/**
9441197
* mpi3mr_enable_logdata - Handler for log data enable
9451198
* @mrioc: Adapter instance reference
@@ -1368,6 +1621,18 @@ static long mpi3mr_bsg_process_drv_cmds(struct bsg_job *job)
13681621
case MPI3MR_DRVBSG_OPCODE_PELENABLE:
13691622
rval = mpi3mr_bsg_pel_enable(mrioc, job);
13701623
break;
1624+
case MPI3MR_DRVBSG_OPCODE_QUERY_HDB:
1625+
rval = mpi3mr_bsg_query_hdb(mrioc, job);
1626+
break;
1627+
case MPI3MR_DRVBSG_OPCODE_REPOST_HDB:
1628+
rval = mpi3mr_bsg_repost_hdb(mrioc, job);
1629+
break;
1630+
case MPI3MR_DRVBSG_OPCODE_UPLOAD_HDB:
1631+
rval = mpi3mr_bsg_upload_hdb(mrioc, job);
1632+
break;
1633+
case MPI3MR_DRVBSG_OPCODE_REFRESH_HDB_TRIGGERS:
1634+
rval = mpi3mr_bsg_refresh_hdb_triggers(mrioc, job);
1635+
break;
13711636
case MPI3MR_DRVBSG_OPCODE_UNKNOWN:
13721637
default:
13731638
pr_err("%s: unsupported driver command opcode %d\n",

include/uapi/scsi/scsi_bsg_mpi3mr.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,14 +296,15 @@ struct mpi3mr_hdb_entry {
296296
* multiple hdb entries.
297297
*
298298
* @num_hdb_types: Number of host diag buffer types supported
299+
* @element_trigger_format: Element trigger format
299300
* @rsvd1: Reserved
300301
* @rsvd2: Reserved
301302
* @rsvd3: Reserved
302303
* @entry: Variable length Diag buffer status entry array
303304
*/
304305
struct mpi3mr_bsg_in_hdb_status {
305306
__u8 num_hdb_types;
306-
__u8 rsvd1;
307+
__u8 element_trigger_format;
307308
__u16 rsvd2;
308309
__u32 rsvd3;
309310
struct mpi3mr_hdb_entry entry[1];

0 commit comments

Comments
 (0)