/* DF-5071 trigger: drive the amr parked-bio sink.
 *
 *   shutdown <ctldev> - ioctl 71: amr_pci_shutdown/amr_rescan_drives analog
 *   online   <ctldev> - ioctl 73: amr_startup analog
 *   poke     <ctldev> - ioctl 72: drain the parked bios (external completion)
 *   wedge    <rawdev> - pread @2M: normal bio (parks forever when shut down)
 *   wedgehold <rawdev> <secs> - open the RAW device NOW (before shutdown),
 *                       sleep, then pread @2M: models an fd that was open
 *                       before the controller went away — amrd_open's gate
 *                       never sees it and amrd_strategy has no gate.
 *   freshopen <rawdev> - plain open(): amrd_open's ENXIO gate (contrast arm)
 */
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>

#define	DF5071_CTL_SHUTDOWN	_IOW('D', 71, int)
#define	DF5071_CTL_POKE		_IOW('D', 72, int)
#define	DF5071_CTL_ONLINE	_IOW('D', 73, int)

int
main(int argc, char **argv)
{
	char buf[512];
	ssize_t r;
	int fd, secs;

	if (argc < 3) {
		fprintf(stderr, "usage: %s shutdown|online|poke <ctldev>\n"
		    "       %s wedge <rawdev>\n"
		    "       %s wedgehold <rawdev> <secs>\n"
		    "       %s freshopen <rawdev>\n",
		    argv[0], argv[0], argv[0], argv[0]);
		exit(2);
	}
	if (strcmp(argv[1], "shutdown") == 0 ||
	    strcmp(argv[1], "online") == 0 ||
	    strcmp(argv[1], "poke") == 0) {
		unsigned long cmd = strcmp(argv[1], "shutdown") == 0 ?
		    DF5071_CTL_SHUTDOWN : strcmp(argv[1], "online") == 0 ?
		    DF5071_CTL_ONLINE : DF5071_CTL_POKE;
		fd = open(argv[2], O_RDWR);
		if (fd < 0) {
			perror("open ctl");
			exit(1);
		}
		if (ioctl(fd, cmd, &(int){0}) < 0) {
			perror("ioctl");
			exit(1);
		}
		fprintf(stderr, "%s: ioctl ok\n", argv[1]);
		return (0);
	}
	if (strcmp(argv[1], "freshopen") == 0) {
		fd = open(argv[2], O_RDONLY);
		fprintf(stderr, "freshopen: open(%s) fd=%d errno=%d(%s) — "
		    "amrd_open refuses once SHUTDOWN is set\n", argv[2], fd,
		    fd < 0 ? errno : 0, fd < 0 ? strerror(errno) : "ok");
		if (fd >= 0)
			close(fd);
		return (0);
	}

	if (strcmp(argv[1], "wedgehold") == 0) {
		secs = argc > 3 ? atoi(argv[3]) : 6;
		fd = open(argv[2], O_RDONLY);
		if (fd < 0) {
			perror("wedgehold open");
			exit(1);
		}
		fprintf(stderr, "wedgehold: fd=%d open BEFORE shutdown; "
		    "sleeping %ds then pread@2M\n", fd, secs);
		sleep(secs);
		r = pread(fd, buf, sizeof(buf), 2UL << 20);
		fprintf(stderr, "wedgehold: pread@2M r=%zd errno=%d(%s) — "
		    "returned only when the bio was completed externally\n",
		    r, r < 0 ? errno : 0, r < 0 ? strerror(errno) : "ok");
		return (0);
	}

	/* plain wedge: fresh open + pread (fine while online) */
	fd = open(argv[2], O_RDONLY);
	if (fd < 0) {
		perror("open");
		exit(1);
	}
	r = pread(fd, buf, sizeof(buf), 2UL << 20);
	fprintf(stderr, "%s: pread@%lu r=%zd errno=%d(%s)\n", argv[1],
	    2UL << 20, r, r < 0 ? errno : 0, r < 0 ? strerror(errno) : "ok");
	return (0);
}
