DF-3657 / trig_abort.c
/* DF-3657 trigger: attempt XPT_ABORT of an XPT_SCSI_IO via /dev/xpt0. * * Bug (sys/dev/disk/isp/isp_freebsd.c:4541): isp_action(XPT_ABORT) passes the * XPT_ABORT CCB itself to isp_control(ISPCTL_ABORT_CMD) instead of * ccb->cab.abort_ccb (the CCB to abort). isp_find_handle() matches by pointer * against isp->isp_xflist[] (isp_library.c:260-274); the XPT_ABORT CCB was * never started, so the handle lookup always fails and every XPT_ABORT of an * XPT_SCSI_IO returns CAM_UA_ABORT ("cannot find handle for command to abort"). * * On real hardware the in-kernel CAM periphs (da(4)/cd(4) error recovery, * cam_periph_timeout) are the callers; they get CAM_UA_ABORT and must escalate * straight to device/bus reset. * * This program documents the userland reachability boundary: DragonFly's * xptioctl() CAMIOCOMMAND whitelist (sys/bus/cam/cam_xpt.c:1028+) only accepts * XPT_SCAN_BUS/XPT_RESET_BUS/XPT_PATH_INQ/XPT_ENG_INQ/XPT_SCAN_LUN/XPT_DEBUG/ * XPT_DEV_MATCH - XPT_ABORT from userland returns EINVAL before any SIM sees * it, and with no isp(4) HBA attached there is no isp bus at all. */ #include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <sys/ioctl.h> #include <bus/cam/cam.h> #include <bus/cam/cam_ccb.h> #include <bus/cam/scsi/scsi_pass.h> int main(void) { union ccb ccb; int fd, rv; fd = open("/dev/xpt0", O_RDWR); if (fd < 0) { printf("open(/dev/xpt0): %s\n", strerror(errno)); return (1); } /* Route to whatever bus would host an isp SIM; on this guest there is * none (no QLogic PCI device), so even a whitelisted func code cannot * reach isp_action(). */ memset(&ccb, 0, sizeof(ccb)); ccb.ccb_h.func_code = XPT_ABORT; ccb.ccb_h.path_id = 0; /* first registered bus */ ccb.ccb_h.target_id = 0; ccb.ccb_h.target_lun = 0; ccb.cab.abort_ccb = NULL; rv = ioctl(fd, CAMIOCOMMAND, &ccb); printf("CAMIOCOMMAND(XPT_ABORT) -> rv=%d errno=%d (%s)\n", rv, errno, strerror(errno)); if (rv == 0) printf("ccb status 0x%x\n", ccb.ccb_h.status); else printf("userland XPT_ABORT rejected before reaching any SIM " "(not in xptioctl whitelist / no isp bus)\n"); /* Prove no isp bus exists on this machine. */ memset(&ccb, 0, sizeof(ccb)); ccb.ccb_h.func_code = XPT_PATH_INQ; ccb.ccb_h.path_id = 0; ccb.ccb_h.target_id = CAM_TARGET_WILDCARD; ccb.ccb_h.target_lun = CAM_LUN_WILDCARD; rv = ioctl(fd, CAMIOCOMMAND, &ccb); if (rv == 0) { printf("bus0 path inq: sim=\"%s\" hba_vid=\"%s\" status 0x%x\n", ccb.cpi.sim_vid, ccb.cpi.hba_vid, ccb.cpi.ccb_h.status); } else { printf("XPT_PATH_INQ bus0 -> rv=%d errno=%d (%s)\n", rv, errno, strerror(errno)); } close(fd); return (0); } |