/*
 * DF-1126 userspace harness — isp_intr response-queue infinite-loop primitive.
 *
 * The kernel bug (sys/dev/disk/isp/isp.c:5121-5124):
 *     uint32_t tsto = oop;
 *     r = isp_handle_other_response(isp, etype, hp, &tsto);
 *     ...
 *     while (tsto != oop) {
 *         optr = ISP_NXT_QENTRY(tsto, RESULT_QUEUE_LEN(isp));
 *     }
 *
 * isp_handle_other_response -> isp_target_notify (isp_target.c:178-181) advances
 * *optrp (= tsto) via `*optrp = ISP_NXT_QENTRY(*optrp, ...)` when an ATIO7
 * long-IU continuation is processed in ISP_TARGET_MODE. After it returns,
 * tsto != oop but the loop body NEVER modifies tsto or oop -> invariant
 * condition -> unconditional infinite loop in hard interrupt context -> kernel
 * hang.
 *
 * Reachability: requires ISP_TARGET_MODE compiled AND a target-mode FC adapter
 * AND a remote initiator sending Extended CDB/IU > 56 bytes. Doubly gated, not
 * reachable on this audit guest.
 *
 * This harness simulates the queue bookkeeping and demonstrates the loop never
 * terminates. We cap iterations to prove the invariance rather than actually
 * hang.
 *
 * Build:  cc -O2 -o harness harness.c
 * Run:    ./harness
 * Expected: "LOOP DID NOT ADVANCE tsto -- infinite loop confirmed".
 */
#include <stdio.h>
#include <stdint.h>

#define RESULT_QUEUE_LEN(isp)   256
#define ISP_NXT_QENTRY(i, l)    (((i) + 1) & ((l) - 1))

/* stand-in for isp_handle_other_response having processed a long IU and
 * advanced *optrp by one queue slot (isp_target.c:179). */
static int handle_other_response_advances_tsto(uint32_t *optrp) {
    *optrp = ISP_NXT_QENTRY(*optrp, RESULT_QUEUE_LEN(0));
    return 1;   /* target_notify succeeded */
}

int main(void) {
    uint32_t oop = 100;
    uint32_t optr = oop;
    uint32_t tsto = oop;

    /* simulate one entry processed that triggers long-IU continuation */
    handle_other_response_advances_tsto(&tsto);
    printf("oop  = %u\n", oop);
    printf("tsto = %u  (advanced by isp_target_notify long-IU path)\n", tsto);

    unsigned long iters = 0;
    const unsigned long CAP = 1000000;   /* would never return in-kernel */
    uint32_t tsto_before = tsto;

    /* exactly the kernel loop body: assigns optr, never touches tsto/oop */
    while (tsto != oop) {
        optr = ISP_NXT_QENTRY(tsto, RESULT_QUEUE_LEN(0));
        if (++iters >= CAP) break;
    }

    if (iters >= CAP) {
        printf("\nHit iteration cap (%lu) without termination.\n", CAP);
        printf("tsto before loop = %u, tsto after = %u (UNCHANGED)\n",
               tsto_before, tsto);
        printf("optr = %u (recomputed each iter from constant tsto)\n", optr);
        printf("\n*** LOOP DID NOT ADVANCE tsto -- infinite loop confirmed ***\n");
        printf("    Fix: change `while` to `if` so the body runs at most once.\n");
        return 0;
    }
    printf("loop terminated after %lu iters -- unexpected.\n", iters);
    return 1;
}
