Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Ranjan Kumar and committed by
Martin K. Petersen
78b50698 d8d08d16

+279 -1
+12
drivers/scsi/mpi3mr/mpi3mr.h
··· 200 200 #define MPI3MR_HDB_TRIGGER_TYPE_SOFT_RESET 4 201 201 #define MPI3MR_HDB_TRIGGER_TYPE_FW_RELEASED 5 202 202 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 + 203 215 /* SGE Flag definition */ 204 216 #define MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST \ 205 217 (MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | MPI3_SGE_FLAGS_DLAS_SYSTEM | \
+265
drivers/scsi/mpi3mr/mpi3mr_app.c
··· 941 941 } 942 942 943 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 + 1196 + /** 944 1197 * mpi3mr_enable_logdata - Handler for log data enable 945 1198 * @mrioc: Adapter instance reference 946 1199 * @job: BSG job reference ··· 1620 1367 break; 1621 1368 case MPI3MR_DRVBSG_OPCODE_PELENABLE: 1622 1369 rval = mpi3mr_bsg_pel_enable(mrioc, job); 1370 + break; 1371 + case MPI3MR_DRVBSG_OPCODE_QUERY_HDB: 1372 + rval = mpi3mr_bsg_query_hdb(mrioc, job); 1373 + break; 1374 + case MPI3MR_DRVBSG_OPCODE_REPOST_HDB: 1375 + rval = mpi3mr_bsg_repost_hdb(mrioc, job); 1376 + break; 1377 + case MPI3MR_DRVBSG_OPCODE_UPLOAD_HDB: 1378 + rval = mpi3mr_bsg_upload_hdb(mrioc, job); 1379 + break; 1380 + case MPI3MR_DRVBSG_OPCODE_REFRESH_HDB_TRIGGERS: 1381 + rval = mpi3mr_bsg_refresh_hdb_triggers(mrioc, job); 1623 1382 break; 1624 1383 case MPI3MR_DRVBSG_OPCODE_UNKNOWN: 1625 1384 default:
+2 -1
include/uapi/scsi/scsi_bsg_mpi3mr.h
··· 296 296 * multiple hdb entries. 297 297 * 298 298 * @num_hdb_types: Number of host diag buffer types supported 299 + * @element_trigger_format: Element trigger format 299 300 * @rsvd1: Reserved 300 301 * @rsvd2: Reserved 301 302 * @rsvd3: Reserved ··· 304 303 */ 305 304 struct mpi3mr_bsg_in_hdb_status { 306 305 __u8 num_hdb_types; 307 - __u8 rsvd1; 306 + __u8 element_trigger_format; 308 307 __u16 rsvd2; 309 308 __u32 rsvd3; 310 309 struct mpi3mr_hdb_entry entry[1];