Linux SCSI subsystem development
 help / color / mirror / Atom feed
From: Bart Van Assche <bvanassche@acm.org>
To: "Martin K . Petersen" <martin.petersen@oracle.com>
Cc: linux-scsi@vger.kernel.org, John Garry <john.g.garry@oracle.com>,
	Bart Van Assche <bvanassche@acm.org>,
	"James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>,
	"Martin K. Petersen" <mkp@kernel.org>
Subject: [PATCH v2 1/2] scsi: core: Add KUnit tests for scsi_logging.c
Date: Mon, 31 Aug 2026 10:58:18 -0700	[thread overview]
Message-ID: <ae3eb010e5f6b4451c6e18cae3ae152d45fe2d95.1788198780.git.bvanassche@acm.org> (raw)
In-Reply-To: <cover.1788198780.git.bvanassche@acm.org>

Add regression unit tests for the functions in drivers/scsi/scsi_logging.c
that call dev_printk().

Implement a macro redefinition approach where dev_printk() is intercepted
when CONFIG_SCSI_LOGGING_KUNIT_TEST is enabled, allowing the test suite to
capture the emitted log levels, target device references, and formatted
log strings into a test buffer without side effects.

Add test cases covering:
 - sdev_prefix_printk() with and without device name prefix.
 - scmd_printk() with tag only, disk name and tag, and untagged commands.
 - scsi_print_command() with 6, 10, 16, and multi-line 32-byte CDBs,
   as well as vendor-specific and reserved opcodes.
 - scsi_print_sense_hdr() with standard, descriptor, and deferred formats.
 - __scsi_print_sense() with normalized sense data and raw hex dumps.
 - scsi_print_sense() with command-attached sense buffers.
 - scsi_print_result() with custom messages, default messages, unknown
   dispositions, and unknown hostbyte statuses.

Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
 drivers/scsi/Kconfig             |   9 +
 drivers/scsi/scsi_logging.c      |  30 +++
 drivers/scsi/scsi_logging_test.c | 422 +++++++++++++++++++++++++++++++
 3 files changed, 461 insertions(+)
 create mode 100644 drivers/scsi/scsi_logging_test.c

diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 4a2af0f702e1..8c2a44b55900 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -76,6 +76,15 @@ config SCSI_LIB_KUNIT_TEST
 
 	  If unsure say N.
 
+config SCSI_LOGGING_KUNIT_TEST
+	bool "KUnit tests for SCSI logging functions" if !KUNIT_ALL_TESTS
+	depends on SCSI && KUNIT=y && SCSI_CONSTANTS
+	default KUNIT_ALL_TESTS
+	help
+	  Run SCSI Mid Layer's KUnit tests for scsi_logging.
+
+	  If unsure say N.
+
 comment "SCSI support type (disk, tape, CD-ROM)"
 	depends on SCSI
 
diff --git a/drivers/scsi/scsi_logging.c b/drivers/scsi/scsi_logging.c
index 3cd0d3074085..3bff4dea4c6a 100644
--- a/drivers/scsi/scsi_logging.c
+++ b/drivers/scsi/scsi_logging.c
@@ -15,6 +15,32 @@
 #include <scsi/scsi_eh.h>
 #include <scsi/scsi_dbg.h>
 
+#if IS_ENABLED(CONFIG_SCSI_LOGGING_KUNIT_TEST)
+static void (*scsi_logging_test_dev_printk)(const char *level,
+					    const struct device *dev,
+					    const char *fmt, va_list args);
+
+static void scsi_logging_dev_printk(const char *level, const struct device *dev,
+				    const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	if (unlikely(scsi_logging_test_dev_printk)) {
+		scsi_logging_test_dev_printk(level, dev, fmt, args);
+	} else {
+		struct va_format vaf = { .fmt = fmt, .va = &args };
+
+		_dev_printk(level, dev, "%pV", &vaf);
+	}
+	va_end(args);
+}
+
+#undef dev_printk
+#define dev_printk(level, dev, fmt, ...) \
+	scsi_logging_dev_printk(level, dev, fmt, ##__VA_ARGS__)
+#endif
+
 static char *scsi_log_reserve_buffer(size_t *len)
 {
 	*len = 128;
@@ -436,3 +462,7 @@ void scsi_print_result(struct scsi_cmnd *cmd, const char *msg, int disposition)
 	scsi_log_release_buffer(logbuf);
 }
 EXPORT_SYMBOL(scsi_print_result);
+
+#if IS_ENABLED(CONFIG_SCSI_LOGGING_KUNIT_TEST)
+#include "scsi_logging_test.c"
+#endif
diff --git a/drivers/scsi/scsi_logging_test.c b/drivers/scsi/scsi_logging_test.c
new file mode 100644
index 000000000000..1dcebc383052
--- /dev/null
+++ b/drivers/scsi/scsi_logging_test.c
@@ -0,0 +1,422 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * KUnit tests for scsi_logging.c.
+ *
+ * Copyright 2026 Google LLC
+ */
+#include <kunit/test.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_proto.h>
+
+#define MAX_CAPTURED_LINES 16
+#define MAX_LINE_LEN 256
+
+struct captured_dev_printk {
+	const char *level;
+	const struct device *dev;
+	char msg[MAX_LINE_LEN];
+};
+
+static struct captured_dev_printk captured_logs[MAX_CAPTURED_LINES];
+static int captured_count;
+
+static void test_capture_dev_printk(const char *level, const struct device *dev,
+				    const char *fmt, va_list args)
+{
+	if (captured_count < MAX_CAPTURED_LINES) {
+		captured_logs[captured_count].level = level;
+		captured_logs[captured_count].dev = dev;
+		vscnprintf(captured_logs[captured_count].msg,
+			   sizeof(captured_logs[captured_count].msg), fmt,
+			   args);
+		captured_count++;
+	}
+}
+
+static void scsi_logging_test_reset(void)
+{
+	captured_count = 0;
+	memset(captured_logs, 0, sizeof(captured_logs));
+}
+
+static int scsi_logging_test_init(struct kunit *test)
+{
+	scsi_logging_test_reset();
+	scsi_logging_test_dev_printk = test_capture_dev_printk;
+	return 0;
+}
+
+static void scsi_logging_test_exit(struct kunit *test)
+{
+	scsi_logging_test_dev_printk = NULL;
+}
+
+struct test_scsi_cmd {
+	struct request rq;
+	struct scsi_cmnd cmd;
+};
+
+struct test_fixture {
+	struct scsi_device *sdev;
+	struct gendisk *disk;
+	struct request_queue *q;
+	struct test_scsi_cmd *tscmd;
+};
+
+static struct test_fixture *scsi_logging_create_fixture(struct kunit *test)
+{
+	struct test_fixture *tf = kunit_kzalloc(test, sizeof(*tf), GFP_KERNEL);
+
+	KUNIT_ASSERT_NOT_NULL(test, tf);
+
+	tf->sdev = kunit_kzalloc(test, sizeof(*tf->sdev), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, tf->sdev);
+
+	tf->disk = kunit_kzalloc(test, sizeof(*tf->disk), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, tf->disk);
+
+	tf->q = kunit_kzalloc(test, sizeof(*tf->q), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, tf->q);
+
+	tf->tscmd = kunit_kzalloc(test, sizeof(*tf->tscmd), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, tf->tscmd);
+
+	tf->q->disk = tf->disk;
+	tf->tscmd->cmd.device = tf->sdev;
+	strscpy(tf->disk->disk_name, "sda", sizeof(tf->disk->disk_name));
+
+	return tf;
+}
+
+static void test_sdev_prefix_printk(struct kunit *test)
+{
+	struct test_fixture *tf = scsi_logging_create_fixture(test);
+
+	/* NULL sdev should produce no output */
+	sdev_prefix_printk(KERN_INFO, NULL, "test", "should not print");
+	KUNIT_EXPECT_EQ(test, captured_count, 0);
+
+	/* Without name prefix */
+	sdev_prefix_printk(KERN_WARNING, tf->sdev, NULL, "warning %d", 42);
+	KUNIT_EXPECT_EQ(test, captured_count, 1);
+	KUNIT_EXPECT_STREQ(test, captured_logs[0].level, KERN_WARNING);
+	KUNIT_EXPECT_PTR_EQ(test, captured_logs[0].dev, &tf->sdev->sdev_gendev);
+	KUNIT_EXPECT_STREQ(test, captured_logs[0].msg, "warning 42");
+
+	/* With name prefix */
+	scsi_logging_test_reset();
+	sdev_prefix_printk(KERN_ERR, tf->sdev, "adapter0", "error code %d", -5);
+	KUNIT_EXPECT_EQ(test, captured_count, 1);
+	KUNIT_EXPECT_STREQ(test, captured_logs[0].level, KERN_ERR);
+	KUNIT_EXPECT_PTR_EQ(test, captured_logs[0].dev, &tf->sdev->sdev_gendev);
+	KUNIT_EXPECT_STREQ(test, captured_logs[0].msg,
+			   "[adapter0] error code -5");
+}
+
+static void test_scmd_printk(struct kunit *test)
+{
+	struct test_fixture *tf = scsi_logging_create_fixture(test);
+
+	/* NULL scmd should produce no output */
+	scmd_printk(KERN_INFO, NULL, "should not print");
+	KUNIT_EXPECT_EQ(test, captured_count, 0);
+
+	/* scmd with tag but no disk name */
+	tf->tscmd->rq.q = NULL;
+	tf->tscmd->rq.tag = 5;
+	scmd_printk(KERN_INFO, &tf->tscmd->cmd, "test msg %d", 10);
+	KUNIT_EXPECT_EQ(test, captured_count, 1);
+	KUNIT_EXPECT_STREQ(test, captured_logs[0].level, KERN_INFO);
+	KUNIT_EXPECT_PTR_EQ(test, captured_logs[0].dev, &tf->sdev->sdev_gendev);
+	KUNIT_EXPECT_STREQ(test, captured_logs[0].msg, "tag#5 test msg 10");
+
+	/* scmd with disk name and tag */
+	scsi_logging_test_reset();
+	tf->tscmd->rq.q = tf->q;
+	tf->tscmd->rq.tag = 12;
+	scmd_printk(KERN_ERR, &tf->tscmd->cmd, "failed status");
+	KUNIT_EXPECT_EQ(test, captured_count, 1);
+	KUNIT_EXPECT_STREQ(test, captured_logs[0].level, KERN_ERR);
+	KUNIT_EXPECT_STREQ(test, captured_logs[0].msg,
+			   "[sda] tag#12 failed status");
+
+	/* scmd with disk name but no tag (tag < 0) */
+	scsi_logging_test_reset();
+	tf->tscmd->rq.tag = -1;
+	scmd_printk(KERN_NOTICE, &tf->tscmd->cmd, "no tag notification");
+	KUNIT_EXPECT_EQ(test, captured_count, 1);
+	KUNIT_EXPECT_STREQ(test, captured_logs[0].msg,
+			   "[sda] no tag notification");
+}
+
+static void test_scsi_print_command(struct kunit *test)
+{
+	struct test_fixture *tf = scsi_logging_create_fixture(test);
+	static const unsigned char cdb6[6] = { 0x00, 0x00, 0x00,
+					       0x00, 0x00, 0x00 };
+	static const unsigned char cdb10[10] = { 0x28, 0x00, 0x00, 0x00, 0x00,
+						 0x00, 0x00, 0x00, 0x08, 0x00 };
+	static const unsigned char cdb16[16] = { 0x88, 0x00, 0x00, 0x00,
+						 0x00, 0x00, 0x00, 0x00,
+						 0x00, 0x00, 0x00, 0x00,
+						 0x00, 0x00, 0x08, 0x00 };
+	static const unsigned char cdb32[32] = {
+		0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+		0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00
+	};
+	static const unsigned char cdb_vendor[6] = { 0xc0, 0x00, 0x00,
+						     0x00, 0x00, 0x00 };
+	static const unsigned char cdb_reserved[6] = { 0x60, 0x00, 0x00,
+						       0x00, 0x00, 0x00 };
+
+	tf->tscmd->rq.q = tf->q;
+	tf->tscmd->rq.tag = 1;
+
+	/* 6-byte TEST UNIT READY */
+	memcpy(tf->tscmd->cmd.cmnd, cdb6, sizeof(cdb6));
+	tf->tscmd->cmd.cmd_len = sizeof(cdb6);
+	scsi_print_command(&tf->tscmd->cmd);
+	KUNIT_EXPECT_EQ(test, captured_count, 1);
+	KUNIT_EXPECT_STREQ(
+		test, captured_logs[0].msg,
+		"[sda] tag#1 CDB: Test Unit Ready 00 00 00 00 00 00");
+
+	/* 10-byte READ(10) */
+	scsi_logging_test_reset();
+	memcpy(tf->tscmd->cmd.cmnd, cdb10, sizeof(cdb10));
+	tf->tscmd->cmd.cmd_len = sizeof(cdb10);
+	scsi_print_command(&tf->tscmd->cmd);
+	KUNIT_EXPECT_EQ(test, captured_count, 1);
+	KUNIT_EXPECT_STREQ(
+		test, captured_logs[0].msg,
+		"[sda] tag#1 CDB: Read(10) 28 00 00 00 00 00 00 00 08 00");
+
+	/* 16-byte READ(16) */
+	scsi_logging_test_reset();
+	memcpy(tf->tscmd->cmd.cmnd, cdb16, sizeof(cdb16));
+	tf->tscmd->cmd.cmd_len = sizeof(cdb16);
+	scsi_print_command(&tf->tscmd->cmd);
+	KUNIT_EXPECT_EQ(test, captured_count, 1);
+	KUNIT_EXPECT_STREQ(
+		test, captured_logs[0].msg,
+		"[sda] tag#1 CDB: Read(16) 88 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00");
+
+	/* 32-byte CDB (CDB len > 16 generates multiple printk lines) */
+	scsi_logging_test_reset();
+	memcpy(tf->tscmd->cmd.cmnd, cdb32, sizeof(cdb32));
+	tf->tscmd->cmd.cmd_len = sizeof(cdb32);
+	scsi_print_command(&tf->tscmd->cmd);
+	KUNIT_EXPECT_EQ(test, captured_count, 3);
+	KUNIT_EXPECT_STREQ(test, captured_logs[0].msg,
+			   "[sda] tag#1 CDB: Read(32)\n");
+	KUNIT_EXPECT_STREQ(
+		test, captured_logs[1].msg,
+		"[sda] tag#1 CDB[00]: 7f 00 00 00 00 00 00 18 00 09 00 00 00 00 00 00");
+	KUNIT_EXPECT_STREQ(
+		test, captured_logs[2].msg,
+		"[sda] tag#1 CDB[10]: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 00");
+
+	/* Vendor-specific opcode */
+	scsi_logging_test_reset();
+	memcpy(tf->tscmd->cmd.cmnd, cdb_vendor, sizeof(cdb_vendor));
+	tf->tscmd->cmd.cmd_len = sizeof(cdb_vendor);
+	scsi_print_command(&tf->tscmd->cmd);
+	KUNIT_EXPECT_EQ(test, captured_count, 1);
+	KUNIT_EXPECT_STREQ(
+		test, captured_logs[0].msg,
+		"[sda] tag#1 CDB: opcode=0xc0 (vendor) c0 00 00 00 00 00");
+
+	/* Reserved opcode */
+	scsi_logging_test_reset();
+	memcpy(tf->tscmd->cmd.cmnd, cdb_reserved, sizeof(cdb_reserved));
+	tf->tscmd->cmd.cmd_len = sizeof(cdb_reserved);
+	scsi_print_command(&tf->tscmd->cmd);
+	KUNIT_EXPECT_EQ(test, captured_count, 1);
+	KUNIT_EXPECT_STREQ(
+		test, captured_logs[0].msg,
+		"[sda] tag#1 CDB: opcode=0x60 (reserved) 60 00 00 00 00 00");
+}
+
+static void test_scsi_print_sense_hdr(struct kunit *test)
+{
+	struct test_fixture *tf = scsi_logging_create_fixture(test);
+	struct scsi_sense_hdr sshdr = {
+		.response_code = 0x70,
+		.sense_key = ILLEGAL_REQUEST,
+		.asc = 0x20,
+		.ascq = 0x00,
+	};
+
+	scsi_print_sense_hdr(tf->sdev, "sda", &sshdr);
+	KUNIT_EXPECT_EQ(test, captured_count, 2);
+	KUNIT_EXPECT_STREQ(test, captured_logs[0].msg,
+			   "[sda] Sense Key : Illegal Request [current] ");
+	KUNIT_EXPECT_STREQ(test, captured_logs[1].msg,
+			   "[sda] Add. Sense: Invalid command operation code");
+
+	/* Deferred and descriptor format */
+	scsi_logging_test_reset();
+	sshdr.response_code = 0x73;
+	sshdr.sense_key = UNIT_ATTENTION;
+	sshdr.asc = 0x29;
+	sshdr.ascq = 0x00;
+	scsi_print_sense_hdr(tf->sdev, "sdb", &sshdr);
+	KUNIT_EXPECT_EQ(test, captured_count, 2);
+	KUNIT_EXPECT_STREQ(
+		test, captured_logs[0].msg,
+		"[sdb] Sense Key : Unit Attention [deferred] [descriptor] ");
+	KUNIT_EXPECT_STREQ(
+		test, captured_logs[1].msg,
+		"[sdb] Add. Sense: Power on, reset, or bus device reset occurred");
+
+	/* Additional sense: Invalid token operation, remote rod token creation not supported */
+	scsi_logging_test_reset();
+	sshdr.response_code = 0x70;
+	sshdr.sense_key = ILLEGAL_REQUEST;
+	sshdr.asc = 0x23;
+	sshdr.ascq = 0x03;
+	scsi_print_sense_hdr(tf->sdev, "sdc", &sshdr);
+	KUNIT_EXPECT_EQ(test, captured_count, 2);
+	KUNIT_EXPECT_STREQ(
+		test, captured_logs[0].msg,
+		"[sdc] Sense Key : Illegal Request [current] ");
+	KUNIT_EXPECT_STREQ(
+		test, captured_logs[1].msg,
+		"[sdc] Add. Sense: Invalid token operation, remote rod token creation not supported");
+}
+
+static void test_scsi_print_sense_buffer(struct kunit *test)
+{
+	struct test_fixture *tf = scsi_logging_create_fixture(test);
+	unsigned char normalized_sense[18] = {
+		[0] = 0x70, [2] = NOT_READY, [7] = 10, [12] = 0x04, [13] = 0x01,
+	};
+	unsigned char raw_sense[16] = { 0 };
+
+	/* Normalized sense buffer */
+	__scsi_print_sense(tf->sdev, "sda", normalized_sense,
+			   sizeof(normalized_sense));
+	KUNIT_EXPECT_EQ(test, captured_count, 2);
+	KUNIT_EXPECT_STREQ(test, captured_logs[0].msg,
+			   "[sda] Sense Key : Not Ready [current] ");
+	KUNIT_EXPECT_STREQ(
+		test, captured_logs[1].msg,
+		"[sda] Add. Sense: Logical unit is in process of becoming ready");
+
+	/* Unnormalized / raw sense buffer dumped in hex */
+	scsi_logging_test_reset();
+	__scsi_print_sense(tf->sdev, "sda", raw_sense, sizeof(raw_sense));
+	KUNIT_EXPECT_EQ(test, captured_count, 1);
+	KUNIT_EXPECT_STREQ(
+		test, captured_logs[0].msg,
+		"[sda] 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");
+}
+
+static void test_scsi_print_sense_cmd(struct kunit *test)
+{
+	struct test_fixture *tf = scsi_logging_create_fixture(test);
+	unsigned char *sense_buffer =
+		kunit_kzalloc(test, SCSI_SENSE_BUFFERSIZE, GFP_KERNEL);
+
+	KUNIT_ASSERT_NOT_NULL(test, sense_buffer);
+	sense_buffer[0] = 0x70;
+	sense_buffer[2] = UNIT_ATTENTION;
+	sense_buffer[7] = 10;
+	sense_buffer[12] = 0x28;
+	sense_buffer[13] = 0x00;
+
+	tf->tscmd->cmd.sense_buffer = sense_buffer;
+	tf->tscmd->rq.q = tf->q;
+	tf->tscmd->rq.tag = 3;
+
+	scsi_print_sense(&tf->tscmd->cmd);
+	KUNIT_EXPECT_EQ(test, captured_count, 2);
+	KUNIT_EXPECT_STREQ(test, captured_logs[0].msg,
+			   "[sda] tag#3 Sense Key : Unit Attention [current] ");
+	KUNIT_EXPECT_STREQ(
+		test, captured_logs[1].msg,
+		"[sda] tag#3 Add. Sense: Not ready to ready change, medium may have changed");
+}
+
+static void test_scsi_print_result(struct kunit *test)
+{
+	struct test_fixture *tf = scsi_logging_create_fixture(test);
+
+	tf->tscmd->rq.q = tf->q;
+	tf->tscmd->rq.tag = 4;
+	tf->tscmd->cmd.result = (DID_OK << 16) | SAM_STAT_CHECK_CONDITION;
+	tf->tscmd->cmd.jiffies_at_alloc = jiffies - 5 * HZ;
+
+	/* Result with message */
+	scsi_print_result(&tf->tscmd->cmd, "Failed command", FAILED);
+	KUNIT_EXPECT_EQ(test, captured_count, 1);
+	KUNIT_EXPECT_STREQ(
+		test, captured_logs[0].msg,
+		"[sda] tag#4 Failed command: FAILED Result: hostbyte=DID_OK driverbyte=DRIVER_OK cmd_age=5s");
+
+	/* Result without message */
+	scsi_logging_test_reset();
+	scsi_print_result(&tf->tscmd->cmd, NULL, SUCCESS);
+	KUNIT_EXPECT_EQ(test, captured_count, 1);
+	KUNIT_EXPECT_STREQ(
+		test, captured_logs[0].msg,
+		"[sda] tag#4 SUCCESS Result: hostbyte=DID_OK driverbyte=DRIVER_OK cmd_age=5s");
+
+	/* Result with DID_TRANSPORT_DISRUPTED hostbyte */
+	scsi_logging_test_reset();
+	tf->tscmd->cmd.result = (DID_TRANSPORT_DISRUPTED << 16) | SAM_STAT_CHECK_CONDITION;
+	scsi_print_result(&tf->tscmd->cmd, "Transport disrupted", NEEDS_RETRY);
+	KUNIT_EXPECT_EQ(test, captured_count, 1);
+	KUNIT_EXPECT_STREQ(
+		test, captured_logs[0].msg,
+		"[sda] tag#4 Transport disrupted: NEEDS_RETRY Result: hostbyte=DID_TRANSPORT_DISRUPTED driverbyte=DRIVER_OK cmd_age=5s");
+
+	/* Result with hostbyte without known string */
+	scsi_logging_test_reset();
+	tf->tscmd->cmd.result = (0x1f << 16);
+	scsi_print_result(&tf->tscmd->cmd, "Unknown hostbyte", FAILED);
+	KUNIT_EXPECT_EQ(test, captured_count, 1);
+	KUNIT_EXPECT_STREQ(
+		test, captured_logs[0].msg,
+		"[sda] tag#4 Unknown hostbyte: FAILED Result: hostbyte=0x1f driverbyte=DRIVER_OK cmd_age=5s");
+
+	/* Result with unknown disposition */
+	scsi_logging_test_reset();
+	tf->tscmd->cmd.result = (DID_OK << 16);
+	scsi_print_result(&tf->tscmd->cmd, "Unknown disp", 0x7f);
+	KUNIT_EXPECT_EQ(test, captured_count, 1);
+	KUNIT_EXPECT_STREQ(
+		test, captured_logs[0].msg,
+		"[sda] tag#4 Unknown disp: UNKNOWN(0x7f) Result: hostbyte=DID_OK driverbyte=DRIVER_OK cmd_age=5s");
+}
+
+static struct kunit_case scsi_logging_test_cases[] = {
+	KUNIT_CASE(test_sdev_prefix_printk),
+	KUNIT_CASE(test_scmd_printk),
+	KUNIT_CASE(test_scsi_print_command),
+	KUNIT_CASE(test_scsi_print_sense_hdr),
+	KUNIT_CASE(test_scsi_print_sense_buffer),
+	KUNIT_CASE(test_scsi_print_sense_cmd),
+	KUNIT_CASE(test_scsi_print_result),
+	{}
+};
+
+static struct kunit_suite scsi_logging_test_suite = {
+	.name = "scsi_logging",
+	.init = scsi_logging_test_init,
+	.exit = scsi_logging_test_exit,
+	.test_cases = scsi_logging_test_cases,
+};
+
+kunit_test_suite(scsi_logging_test_suite);
+
+MODULE_DESCRIPTION("SCSI logging unit tests");
+MODULE_AUTHOR("Bart Van Assche");
+MODULE_LICENSE("GPL");

  reply	other threads:[~2026-08-31 17:58 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-31 17:58 [PATCH v2 0/2] scsi: core: Optimize the SCSI printk() variants Bart Van Assche
2026-08-31 17:58 ` Bart Van Assche [this message]
2026-08-31 20:05   ` [PATCH v2 1/2] scsi: core: Add KUnit tests for scsi_logging.c sashiko-bot
2026-08-31 17:58 ` [PATCH v2 2/2] scsi: core: Eliminate scsi_log_{reserve,release}_buffer() Bart Van Assche

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ae3eb010e5f6b4451c6e18cae3ae152d45fe2d95.1788198780.git.bvanassche@acm.org \
    --to=bvanassche@acm.org \
    --cc=James.Bottomley@HansenPartnership.com \
    --cc=john.g.garry@oracle.com \
    --cc=linux-scsi@vger.kernel.org \
    --cc=martin.petersen@oracle.com \
    --cc=mkp@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox