diff mbox series

[v1,3/6] mpi3mr: Dump driver and dmesg logs into driver diag buffer

Message ID 20240514142858.51992-4-ranjan.kumar@broadcom.com (mailing list archive)
State Superseded
Headers show
Series mpi3mr: Host diag buffer support | expand

Commit Message

Ranjan Kumar May 14, 2024, 2:28 p.m. UTC
This patch adds support for collecting the kernel messages based
on the driver buffer capture level set in the module parameter
and copy the pertinent information to the driver diagnostic buffer
posted to the controller.  The buffer capture and copy will be
executed when the driver detected the controller in the fault state.

Signed-off-by: Sathya Prakash <sathya.prakash@broadcom.com>
Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com>
---
 drivers/scsi/mpi3mr/mpi/mpi30_tool.h |   2 +
 drivers/scsi/mpi3mr/mpi3mr.h         |   5 ++
 drivers/scsi/mpi3mr/mpi3mr_fw.c      | 126 +++++++++++++++++++++++++++
 3 files changed, 133 insertions(+)

Comments

kernel test robot May 15, 2024, 11 a.m. UTC | #1
Hi Ranjan,

kernel test robot noticed the following build warnings:

[auto build test WARNING on mkp-scsi/for-next]
[also build test WARNING on jejb-scsi/for-next linus/master v6.9 next-20240515]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Ranjan-Kumar/mpi3mr-HDB-allocation-and-posting-for-hardware-and-Firmware-buffers/20240514-223346
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git for-next
patch link:    https://lore.kernel.org/r/20240514142858.51992-4-ranjan.kumar%40broadcom.com
patch subject: [PATCH v1 3/6] mpi3mr: Dump driver and dmesg logs into driver diag buffer
config: alpha-allyesconfig (https://download.01.org/0day-ci/archive/20240515/202405151829.zc0uNh0u-lkp@intel.com/config)
compiler: alpha-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240515/202405151829.zc0uNh0u-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202405151829.zc0uNh0u-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/scsi/mpi3mr/mpi3mr_fw.c:1214: warning: Excess function parameter 'prev_offset' description in 'mpi3mr_do_mini_dump'


vim +1214 drivers/scsi/mpi3mr/mpi3mr_fw.c

  1202	
  1203	/**
  1204	 * mpi3mr_do_mini_dump - copy system logs associated with mrioc.
  1205	 * @mrioc: Adapter instance reference
  1206	 * @prev_offset: offset returned from previous operation
  1207	 *
  1208	 * Read system logs and search for pattern mpi3mr%d and copy the lines
  1209	 * into driver diag buffer
  1210	 *
  1211	 * Return: next available location in driver diag buffer.
  1212	 */
  1213	static int mpi3mr_do_mini_dump(struct mpi3mr_ioc *mrioc)
> 1214	{
  1215		int n = 0, lines, pos_mini_dump = 0;
  1216		struct mpi3mr_kmsg_dumper dumper;
  1217		size_t len;
  1218		char buf[201];
  1219		char *mini_start = "<6> Minidump start\n";
  1220		char *mini_end = "<6> Minidump end\n";
  1221	
  1222		struct mpi3_driver_buffer_header *drv_buff_header = NULL;
  1223	
  1224		dumper = mrioc->dump;
  1225	
  1226		kmsg_dump_rewind(&dumper.kdumper);
  1227		while (kmsg_dump_get_line(&dumper.kdumper, 1, NULL, 0, NULL))
  1228			n++;
  1229	
  1230		lines = n;
  1231		kmsg_dump_rewind(&dumper.kdumper);
  1232	
  1233		drv_buff_header = (struct mpi3_driver_buffer_header *)mrioc->drv_diag_buffer;
  1234		drv_buff_header->signature = 0x43495243;
  1235		drv_buff_header->logical_buffer_start = 0;
  1236		drv_buff_header->circular_buffer_size =
  1237			mrioc->drv_diag_buffer_sz - sizeof(struct mpi3_driver_buffer_header);
  1238		drv_buff_header->flags =
  1239			MPI3_DRIVER_DIAG_BUFFER_HEADER_FLAGS_CIRCULAR_BUF_FORMAT_ASCII;
  1240	
  1241		if ((pos_mini_dump + strlen(mini_start)
  1242				    < mrioc->drv_diag_buffer_sz)) {
  1243			sprintf((char *)mrioc->drv_diag_buffer + pos_mini_dump,
  1244				"%s\n", mini_start);
  1245			pos_mini_dump += strlen(mini_start);
  1246		} else {
  1247			ioc_info(mrioc, "driver diag buffer is full. minidump is not started\n");
  1248			goto out;
  1249		}
  1250	
  1251		while (kmsg_dump_get_line(&dumper.kdumper, 1, buf, sizeof(buf), &len)) {
  1252			if (!lines--)
  1253				break;
  1254			if (strstr(buf, mrioc->name) &&
  1255				((pos_mini_dump + len + strlen(mini_end))
  1256				    < mrioc->drv_diag_buffer_sz)) {
  1257				sprintf((char *)mrioc->drv_diag_buffer
  1258				    + pos_mini_dump, "%s", buf);
  1259				pos_mini_dump += len;
  1260			}
  1261		}
  1262	
  1263		if ((pos_mini_dump + strlen(mini_end)
  1264				    < mrioc->drv_diag_buffer_sz)) {
  1265			sprintf((char *)mrioc->drv_diag_buffer + pos_mini_dump,
  1266				"%s\n", mini_end);
  1267			pos_mini_dump += strlen(mini_end);
  1268		}
  1269	
  1270	out:
  1271		drv_buff_header->logical_buffer_end =
  1272			pos_mini_dump - sizeof(struct mpi3_driver_buffer_header);
  1273	
  1274		ioc_info(mrioc, "driver diag buffer base_address(including 4K header) 0x%016llx, end_address 0x%016llx\n",
  1275		    (unsigned long long)mrioc->drv_diag_buffer_dma,
  1276		    (unsigned long long)mrioc->drv_diag_buffer_dma +
  1277		    mrioc->drv_diag_buffer_sz);
  1278		ioc_info(mrioc, "logical_buffer end_address 0x%016llx, logical_buffer_end 0x%08x\n",
  1279		    (unsigned long long)mrioc->drv_diag_buffer_dma +
  1280		    drv_buff_header->logical_buffer_end,
  1281		    drv_buff_header->logical_buffer_end);
  1282	
  1283		return pos_mini_dump;
  1284	}
  1285
diff mbox series

Patch

diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_tool.h b/drivers/scsi/mpi3mr/mpi/mpi30_tool.h
index 495933856006..8b8b6ba00c7b 100644
--- a/drivers/scsi/mpi3mr/mpi/mpi30_tool.h
+++ b/drivers/scsi/mpi3mr/mpi/mpi30_tool.h
@@ -10,6 +10,8 @@ 
 #define MPI3_DIAG_BUFFER_TYPE_DRIVER	(0x10)
 #define MPI3_DIAG_BUFFER_ACTION_RELEASE	(0x01)
 
+#define MPI3_DRIVER_DIAG_BUFFER_HEADER_FLAGS_CIRCULAR_BUF_FORMAT_ASCII	(0x00000000)
+
 struct mpi3_diag_buffer_post_request {
 	__le16                     host_tag;
 	u8                         ioc_use_only02;
diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index dc7e8f461826..b6030a665ec8 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -226,6 +226,10 @@  extern atomic64_t event_counter;
 #define MPI3MR_WRITE_SAME_MAX_LEN_256_BLKS 256
 #define MPI3MR_WRITE_SAME_MAX_LEN_2048_BLKS 2048
 
+struct mpi3mr_kmsg_dumper {
+	struct kmsg_dump_iter kdumper;
+};
+
 /* Driver diag buffer levels */
 enum mpi3mr_drv_db_level {
 	MRIOC_DRV_DB_DISABLED = 0,
@@ -1331,6 +1335,7 @@  struct mpi3mr_ioc {
 	void *drv_diag_buffer;
 	dma_addr_t drv_diag_buffer_dma;
 	u32 drv_diag_buffer_sz;
+	struct mpi3mr_kmsg_dumper dump;
 };
 
 /**
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
index 5937054b3cdb..35143d2b7fe4 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -1200,6 +1200,128 @@  static void mpi3mr_alloc_ioctl_dma_memory(struct mpi3mr_ioc *mrioc)
 	mpi3mr_free_ioctl_dma_memory(mrioc);
 }
 
+/**
+ * mpi3mr_do_mini_dump - copy system logs associated with mrioc.
+ * @mrioc: Adapter instance reference
+ * @prev_offset: offset returned from previous operation
+ *
+ * Read system logs and search for pattern mpi3mr%d and copy the lines
+ * into driver diag buffer
+ *
+ * Return: next available location in driver diag buffer.
+ */
+static int mpi3mr_do_mini_dump(struct mpi3mr_ioc *mrioc)
+{
+	int n = 0, lines, pos_mini_dump = 0;
+	struct mpi3mr_kmsg_dumper dumper;
+	size_t len;
+	char buf[201];
+	char *mini_start = "<6> Minidump start\n";
+	char *mini_end = "<6> Minidump end\n";
+
+	struct mpi3_driver_buffer_header *drv_buff_header = NULL;
+
+	dumper = mrioc->dump;
+
+	kmsg_dump_rewind(&dumper.kdumper);
+	while (kmsg_dump_get_line(&dumper.kdumper, 1, NULL, 0, NULL))
+		n++;
+
+	lines = n;
+	kmsg_dump_rewind(&dumper.kdumper);
+
+	drv_buff_header = (struct mpi3_driver_buffer_header *)mrioc->drv_diag_buffer;
+	drv_buff_header->signature = 0x43495243;
+	drv_buff_header->logical_buffer_start = 0;
+	drv_buff_header->circular_buffer_size =
+		mrioc->drv_diag_buffer_sz - sizeof(struct mpi3_driver_buffer_header);
+	drv_buff_header->flags =
+		MPI3_DRIVER_DIAG_BUFFER_HEADER_FLAGS_CIRCULAR_BUF_FORMAT_ASCII;
+
+	if ((pos_mini_dump + strlen(mini_start)
+			    < mrioc->drv_diag_buffer_sz)) {
+		sprintf((char *)mrioc->drv_diag_buffer + pos_mini_dump,
+			"%s\n", mini_start);
+		pos_mini_dump += strlen(mini_start);
+	} else {
+		ioc_info(mrioc, "driver diag buffer is full. minidump is not started\n");
+		goto out;
+	}
+
+	while (kmsg_dump_get_line(&dumper.kdumper, 1, buf, sizeof(buf), &len)) {
+		if (!lines--)
+			break;
+		if (strstr(buf, mrioc->name) &&
+			((pos_mini_dump + len + strlen(mini_end))
+			    < mrioc->drv_diag_buffer_sz)) {
+			sprintf((char *)mrioc->drv_diag_buffer
+			    + pos_mini_dump, "%s", buf);
+			pos_mini_dump += len;
+		}
+	}
+
+	if ((pos_mini_dump + strlen(mini_end)
+			    < mrioc->drv_diag_buffer_sz)) {
+		sprintf((char *)mrioc->drv_diag_buffer + pos_mini_dump,
+			"%s\n", mini_end);
+		pos_mini_dump += strlen(mini_end);
+	}
+
+out:
+	drv_buff_header->logical_buffer_end =
+		pos_mini_dump - sizeof(struct mpi3_driver_buffer_header);
+
+	ioc_info(mrioc, "driver diag buffer base_address(including 4K header) 0x%016llx, end_address 0x%016llx\n",
+	    (unsigned long long)mrioc->drv_diag_buffer_dma,
+	    (unsigned long long)mrioc->drv_diag_buffer_dma +
+	    mrioc->drv_diag_buffer_sz);
+	ioc_info(mrioc, "logical_buffer end_address 0x%016llx, logical_buffer_end 0x%08x\n",
+	    (unsigned long long)mrioc->drv_diag_buffer_dma +
+	    drv_buff_header->logical_buffer_end,
+	    drv_buff_header->logical_buffer_end);
+
+	return pos_mini_dump;
+}
+
+/**
+ * mpi3mr_do_dump - copy system logs into driver diag buffer.
+ * @mrioc: Adapter instance reference
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_do_dump(struct mpi3mr_ioc *mrioc)
+{
+	int offset = 0;
+	size_t dump_size;
+	struct mpi3_driver_buffer_header *drv_buff_header = NULL;
+
+	if (!mrioc->drv_diag_buffer)
+		return;
+
+	memset(mrioc->drv_diag_buffer, 0, mrioc->drv_diag_buffer_sz);
+
+	if (drv_db_level == MRIOC_DRV_DB_DISABLED)
+		return;
+
+	/* Copy controller specific logs */
+	offset += mpi3mr_do_mini_dump(mrioc);
+	if (drv_db_level != MRIOC_DRV_DB_FULL)
+		return;
+
+	kmsg_dump_rewind(&mrioc->dump.kdumper);
+	kmsg_dump_get_buffer(&mrioc->dump.kdumper, true,
+		mrioc->drv_diag_buffer + offset,
+		mrioc->drv_diag_buffer_sz - offset, &dump_size);
+
+	drv_buff_header = (struct mpi3_driver_buffer_header *)
+	    mrioc->drv_diag_buffer;
+	drv_buff_header->logical_buffer_end += dump_size;
+	ioc_info(mrioc, "logical_buffer end_address(0x%016llx), logical_buffer_end(0x%08x)\n",
+	    (unsigned long long)mrioc->drv_diag_buffer_dma +
+	    drv_buff_header->logical_buffer_end,
+	    drv_buff_header->logical_buffer_end);
+}
+
 /**
  * mpi3mr_clear_reset_history - clear reset history
  * @mrioc: Adapter instance reference
@@ -2767,6 +2889,7 @@  static void mpi3mr_watchdog_work(struct work_struct *work)
 		if (!mrioc->diagsave_timeout) {
 			mpi3mr_print_fault_info(mrioc);
 			ioc_warn(mrioc, "diag save in progress\n");
+			mpi3mr_do_dump(mrioc);
 		}
 		if ((mrioc->diagsave_timeout++) <= MPI3_SYSIF_DIAG_SAVE_TIMEOUT)
 			goto schedule_work;
@@ -5311,6 +5434,9 @@  int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
 	mpi3mr_ioc_disable_intr(mrioc);
 
 	if (snapdump) {
+		dprint_reset(mrioc,
+		    "soft_reset_handler: saving snapdump\n");
+		mpi3mr_do_dump(mrioc);
 		mpi3mr_set_diagsave(mrioc);
 		retval = mpi3mr_issue_reset(mrioc,
 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);