DF-4693 / trigger_sili_pm.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | /* * trigger_sili_pm.c - userland driver for the sili_pm.c defect family * (DF-4692 / DF-4693 / DF-4694 / DF-4695) * * On real hardware (SiI 3124/3132 HBA + SiL3726 port multiplier) this drives * the exact CAM entry points that reach the defective sili_pm.c code: * * - camcontrol reset <t> -> XPT_RESET_DEV -> sili_cam.c:904-915 -> * sili_port_reset(ap, atx, 0) -> * sili_pm_softreset() (DF-4694, DF-4695) * - camcontrol rescan <b> -> wildcard XPT_PATH_INQ -> port state machine -> * sili.c:530 sili_pm_read(EINFO), * sili.c:580 sili_pm_check_good -> * sili_pm_read/sili_pm_write (DF-4692, DF-4693) * * while the parallel dd loop keeps the port's ccb pool saturated and other * PM-target commands on-chip (the co-activity precondition). * * On the audit QEMU guest there is no sili(4) HBA at all (PCI inventory: * PIIX3 IDE + virtio only), so this trigger runs to completion against the * ata0/ata1 buses and documents the hardware gate honestly. * * cc -O2 -Wall -o trigger_sili_pm trigger_sili_pm.c * ./trigger_sili_pm <seconds> */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <stdarg.h> #include <time.h> static void run(const char *fmt, ...) { char cmd[256]; va_list ap; va_start(ap, fmt); vsnprintf(cmd, sizeof(cmd), fmt, ap); va_end(ap); printf("+ %s\n", cmd); fflush(stdout); if (system(cmd) != 0) printf(" (nonzero exit)\n"); } int main(int ac, char **av) { time_t deadline; char buses[8][32]; int nbusses = 0, i; FILE *p; char line[256]; if (ac > 1) deadline = time(NULL) + atoi(av[1]); else deadline = time(NULL) + 15; printf("== sili_pm defect family trigger ==\n"); printf("CAM device list:\n"); if ((p = popen("camcontrol devlist 2>&1", "r")) != NULL) { while (fgets(line, sizeof(line), p)) { printf(" %s", line); if (nbusses < 8 && sscanf(line, "on scbus%*d") == 0) { char *b = strstr(line, "bus"); if (b) ; } } pclose(p); } /* enumerate scbus numbers for rescan */ if ((p = popen("camcontrol devlist -v 2>/dev/null | " "grep '^scbus' | awk '{print $1}'", "r")) != NULL) { while (nbusses < 8 && fgets(line, sizeof(line), p)) { line[strcspn(line, "\r\n")] = 0; snprintf(buses[nbusses], sizeof(buses[0]), "%s", line + 5 /* skip "scbus" */); if (buses[nbusses][0]) nbusses++; } pclose(p); } printf("enumerated %d cam bus(es)\n", nbusses); /* * Saturation driver: keep a pending I/O stream on every direct disk * (on PM hardware this would be dd through the PM targets). */ if (system("for d in /dev/da*; do " "(dd if=$d of=/dev/null bs=64k count=400 " ">/dev/null 2>&1 &) ; done") != 0) ; while (time(NULL) < deadline) { for (i = 0; i < nbusses; i++) { run("camcontrol rescan %s", buses[i]); /* XPT_RESET_DEV on every present target */ run("camcontrol reset %s 2>&1", buses[i]); } sleep(1); } printf("== trigger loop finished ==\n"); return (0); } |