/*
 * DF-4639 PoC harness — inverted debug.ips.ignore_flush_cmd polarity in
 * sys/dev/raid/ips/ips_commands.c ips_send_flush_request (lines 195-220).
 *
 * The control flow below is a faithful extraction of the kernel function:
 * only the kernel-only calls (command-buffer fill, bus_dmamap_sync,
 * sc->ips_issue_cmd) are replaced by instrumented stubs.  The *branch* is
 * verbatim:
 *
 *     if (!ips_debug_ignore_flush_cmd) {      // ips_commands.c:202
 *             ips_insert_free_cmd(sc, command);
 *             ipsd_finish(bio);
 *             return 0;                       // flush SKIPPED, bio completed OK
 *     }
 *     ... build IPS_CACHE_FLUSH_CMD, issue to adapter ...
 *
 * against the tunable's own description (ips_commands.c:40):
 *     "Do not issue IPS_CACHE_FLUSH_CMD on BUF_CMD_FLUSH"
 * i.e. documented semantics: flag SET (1) -> skip the command.
 * Actual semantics: flag CLEAR (0, the default) -> skip the command.
 *
 * Build: cc -O2 -o flush_invert_harness flush_invert_harness.c
 * Run:   ./flush_invert_harness
 * Success criterion (bug present): flag=0 -> 0 adapter commands issued,
 * bio finished with no error; flag=1 -> exactly 1 adapter command issued
 * with opcode 0x0A (IPS_CACHE_FLUSH_CMD).
 */
#include <stdio.h>

/* ---- ips.h constants ---- */
#define IPS_CACHE_FLUSH_CMD 0x0A	/* ips.h:141 */

/* ---- stubs for the kernel symbols used by ips_send_flush_request ---- */
static int ips_debug_ignore_flush_cmd;	/* ips_commands.c:35 (TUNABLE_INT/SYSCTL_INT, default 0) */

typedef struct { int n; } ips_softc_t;
typedef struct { int n; } ips_command_t;
struct bio { int n; };

static int adapter_cmds_issued;
static unsigned char last_cmd_opcode;
static int bios_finished;

static void ips_insert_free_cmd(ips_softc_t *sc, ips_command_t *c) { (void)sc; (void)c; }
static void ipsd_finish(struct bio *b) { bios_finished = 1; (void)b; }
static void adapter_issue(ips_command_t *c, unsigned char opcode) { (void)c; adapter_cmds_issued++; last_cmd_opcode = opcode; }

/* ==== ips_commands.c:195-220, verbatim control flow ==== */
static int
ips_send_flush_request(ips_command_t *command, struct bio *bio)
{
	(void)command;
	ips_softc_t *sc = (ips_softc_t *)0;

	if (!ips_debug_ignore_flush_cmd) {
		ips_insert_free_cmd(sc, command);
		ipsd_finish(bio);
		return 0;
	}

	/* real path: flush_cmd->command = IPS_CACHE_FLUSH_CMD; ...; sc->ips_issue_cmd(command) */
	adapter_issue(command, IPS_CACHE_FLUSH_CMD);
	return 0;
}

static int run_case(int flag, const char *label)
{
	adapter_cmds_issued = 0;
	last_cmd_opcode = 0;
	bios_finished = 0;
	ips_debug_ignore_flush_cmd = flag;

	ips_send_flush_request((ips_command_t *)0, (struct bio *)0);

	printf("%-28s flag=%d -> adapter_cmds_issued=%d last_opcode=0x%02x bio_finished=%d(no error)\n",
	       label, flag, adapter_cmds_issued, last_cmd_opcode, bios_finished);
	return adapter_cmds_issued;
}

int main(void)
{
	int n0, n1;

	printf("sysctl description (ips_commands.c:40): \"Do not issue IPS_CACHE_FLUSH_CMD on BUF_CMD_FLUSH\"\n");
	printf("kernel default (TUNABLE_INT): debug.ips.ignore_flush_cmd = 0\n\n");

	n0 = run_case(0, "DEFAULT (flag=0):");	/* expected: 0 cmds  => flush silently dropped */
	n1 = run_case(1, "DEBUG SET (flag=1):");	/* expected: 1 cmd opcode 0x0A => real flush */

	printf("\n");
	if (n0 == 0 && n1 == 1) {
		printf("RESULT: INVERTED — with the DEFAULT value the real adapter cache-flush\n");
		printf("        command is never issued; BUF_CMD_FLUSH bios complete as if flushed.\n");
		return 42;	/* distinctive marker: inversion reproduced */
	}
	printf("RESULT: not inverted (unexpected)\n");
	return 1;
}
