From: Mike Larkin Subject: Re: make vmd's vioscsi a child process To: Dave Voutila Cc: tech@openbsd.org Date: Thu, 12 Feb 2026 13:50:48 -0800 On Wed, Feb 11, 2026 at 09:51:42PM -0500, Dave Voutila wrote: > There are three virtio devices that don't fork/exec into child > processes: vmmci, the entropy device, and the scsi device (for cdrom > emulation). > > This diff updates vioscsi to follow the fork/exec dance into a > privsep process. Only two will remain in the vm process (viornd, vmmci). > > Design mimics vioblk as they're very similar being single-threaded > operating on a single fd, but virtio scsi has device specific registers > to handle reads from/writes to. > > Tests definitely welcome as not all virtio scsi drivers exercise all > of the device specific virtio registers. > > oherwise, ok? > first read seems ok. I will test a bit this weekend and let you know if I run into anything. > -dv > > diff refs/heads/master refs/heads/vmd-vioscsi > commit - b421eb1ff206c81187a06b7792023e34196771b5 > commit + bddff255892ea933c6b0beee6c6ac755e8c0f01a > blob - 4fcd95f19be0ae4637629852acd8fa9390327bdb > blob + 8fab755ed3f8e06a032de0a192c3fd504be2608c > --- usr.sbin/vmd/vioscsi.c > +++ usr.sbin/vmd/vioscsi.c > @@ -25,9 +25,13 @@ > #include > #include > > +#include > +#include > #include > #include > +#include > > +#include "atomicio.h" > #include "vmd.h" > #include "vioscsi.h" > #include "virtio.h" > @@ -42,6 +46,159 @@ > #define DPRINTF(x...) do {} while(0) > #endif /* VIOSCSI_DEBUG */ > > +extern struct vmd_vm *current_vm; > + > +static void dev_dispatch_vm(int, short, void *); > +static void handle_sync_io(int, short, void *); > +static uint32_t vioscsi_io_cfg(struct virtio_dev *, int, uint8_t, uint32_t, > + uint8_t); > +static int vioscsi_notifyq(struct virtio_dev *, uint16_t); > +static uint32_t vioscsi_read(struct virtio_dev *, struct viodev_msg *, int *); > +static int vioscsi_write(struct virtio_dev *, struct viodev_msg *); > + > +__dead void > +vioscsi_main(int fd, int fd_vmm) > +{ > + struct virtio_dev dev; > + struct vioscsi_dev *vioscsi = NULL; > + struct viodev_msg msg; > + struct vmd_vm vm; > + ssize_t sz; > + int ret; > + > + /* > + * stdio - needed for read/write to disk fds and channels to the vm. > + * vmm + proc - needed to create shared vm mappings. > + */ > + if (pledge("stdio vmm proc", NULL) == -1) > + fatal("pledge"); > + > + /* Receive our virtio_dev, mostly preconfigured. */ > + memset(&dev, 0, sizeof(dev)); > + sz = atomicio(read, fd, &dev, sizeof(dev)); > + if (sz != sizeof(dev)) { > + ret = errno; > + log_warn("failed to receive vioscsi"); > + goto fail; > + } > + if (dev.dev_type != VMD_DEVTYPE_SCSI) { > + ret = EINVAL; > + log_warn("received invalid device type"); > + goto fail; > + } > + dev.sync_fd = fd; > + vioscsi = &dev.vioscsi; > + > + log_debug("%s: got vioscsi dev. cdrom fd = %d, syncfd = %d, " > + "asyncfd = %d, vmm fd = %d", __func__, vioscsi->cdrom_fd, > + dev.sync_fd, dev.async_fd, fd_vmm); > + > + /* Receive our vm information from the vm process. */ > + memset(&vm, 0, sizeof(vm)); > + sz = atomicio(read, dev.sync_fd, &vm, sizeof(vm)); > + if (sz != sizeof(vm)) { > + ret = EIO; > + log_warnx("failed to receive vm details"); > + goto fail; > + } > + current_vm = &vm; > + > + setproctitle("%s/vioscsi", vm.vm_params.vmc_name); > + log_procinit("vm/%s/vioscsi", vm.vm_params.vmc_name); > + > + /* Now that we have our vm information, we can remap memory. */ > + ret = remap_guest_mem(&vm, fd_vmm); > + if (ret) { > + log_warnx("failed to remap guest memory"); > + goto fail; > + } > + > + /* > + * We no longer need /dev/vmm access. > + */ > + close_fd(fd_vmm); > + if (pledge("stdio", NULL) == -1) > + fatal("pledge2"); > + > + /* Initialize the vioscsi backing file. */ > + ret = virtio_raw_init(&vioscsi->file, &vioscsi->sz, > + &vioscsi->cdrom_fd, 1); > + if (ret == -1) { > + log_warnx("%s: unable to determine iso format", __func__); > + goto fail; > + } > + vioscsi->n_blocks = vioscsi->sz / VIOSCSI_BLOCK_SIZE_CDROM; > + > + /* Initialize libevent so we can start wiring event handlers. */ > + event_init(); > + > + /* Wire up an async imsg channel. */ > + log_debug("%s: wiring in async vm event handler (fd=%d)", __func__, > + dev.async_fd); > + if (vm_device_pipe(&dev, dev_dispatch_vm, NULL)) { > + ret = EIO; > + log_warnx("vm_device_pipe"); > + goto fail; > + } > + > + /* Configure our sync channel event handler. */ > + log_debug("%s: wiring in sync channel handler (fd=%d)", __func__, > + dev.sync_fd); > + if (imsgbuf_init(&dev.sync_iev.ibuf, dev.sync_fd) == -1) { > + log_warn("imsgbuf_init"); > + goto fail; > + } > + dev.sync_iev.handler = handle_sync_io; > + dev.sync_iev.data = &dev; > + dev.sync_iev.events = EV_READ; > + imsg_event_add(&dev.sync_iev); > + > + /* Send a ready message over the sync channel. */ > + log_debug("%s: telling vm %s device is ready", __func__, > + vm.vm_params.vmc_name); > + memset(&msg, 0, sizeof(msg)); > + msg.type = VIODEV_MSG_READY; > + imsg_compose_event(&dev.sync_iev, IMSG_DEVOP_MSG, 0, 0, -1, &msg, > + sizeof(msg)); > + > + /* Send a ready message over the async channel. */ > + log_debug("%s: sending heartbeat", __func__); > + ret = imsg_compose_event(&dev.async_iev, IMSG_DEVOP_MSG, 0, 0, -1, > + &msg, sizeof(msg)); > + if (ret == -1) { > + log_warnx("%s: failed to send async ready message!", __func__); > + goto fail; > + } > + > + /* Engage the event loop! */ > + ret = event_dispatch(); > + > + if (ret == 0) { > + /* Clean shutdown. */ > + close_fd(dev.sync_fd); > + close_fd(dev.async_fd); > + close_fd(vioscsi->cdrom_fd); > + _exit(0); > + /* NOTREACHED */ > + } > + > +fail: > + /* Try letting the vm know we've failed something. */ > + memset(&msg, 0, sizeof(msg)); > + msg.type = VIODEV_MSG_ERROR; > + msg.data = ret; > + imsg_compose(&dev.sync_iev.ibuf, IMSG_DEVOP_MSG, 0, 0, -1, &msg, > + sizeof(msg)); > + imsgbuf_flush(&dev.sync_iev.ibuf); > + > + close_fd(dev.sync_fd); > + close_fd(dev.async_fd); > + if (vioscsi != NULL) > + close_fd(vioscsi->cdrom_fd); > + _exit(ret); > + /* NOTREACHED */ > +} > + > static void > vioscsi_prepare_resp(struct virtio_scsi_res_hdr *resp, uint8_t vio_status, > uint8_t scsi_status, uint8_t err_flags, uint8_t add_sense_code, > @@ -262,7 +419,204 @@ vioscsi_handle_tur(struct virtio_dev *dev, struct virt > return (ret); > } > > +static void > +dev_dispatch_vm(int fd, short event, void *arg) > +{ > + struct virtio_dev *dev = (struct virtio_dev *)arg; > + struct imsgev *iev = &dev->async_iev; > + struct imsgbuf *ibuf = &iev->ibuf; > + struct imsg imsg; > + ssize_t n = 0; > + uint32_t type; > + int verbose; > + > + if (event & EV_READ) { > + if ((n = imsgbuf_read(ibuf)) == -1) > + fatal("%s: imsgbuf_read", __func__); > + if (n == 0) { > + /* this pipe is dead, so remove the event handler */ > + log_debug("%s: vioscsi pipe dead (EV_READ)", __func__); > + event_del(&iev->ev); > + event_loopexit(NULL); > + return; > + } > + } > + > + if (event & EV_WRITE) { > + if (imsgbuf_write(ibuf) == -1) { > + if (errno == EPIPE) { > + /* this pipe is dead, remove the handler */ > + log_debug("%s: pipe dead (EV_WRITE)", __func__); > + event_del(&iev->ev); > + event_loopexit(NULL); > + return; > + } > + fatal("%s: imsgbuf_write", __func__); > + } > + } > + > + for (;;) { > + if ((n = imsg_get(ibuf, &imsg)) == -1) > + fatal("%s: imsg_get", __func__); > + if (n == 0) > + break; > + > + type = imsg_get_type(&imsg); > + switch (type) { > + case IMSG_VMDOP_PAUSE_VM: > + log_debug("%s: pausing", __func__); > + break; > + case IMSG_VMDOP_UNPAUSE_VM: > + log_debug("%s: unpausing", __func__); > + break; > + case IMSG_CTL_VERBOSE: > + verbose = imsg_int_read(&imsg); > + log_setverbose(verbose); > + break; > + default: > + log_warnx("%s: unhandled imsg type %d", __func__, type); > + break; > + } > + imsg_free(&imsg); > + } > + imsg_event_add(iev); > +} > + > +/* > + * Synchronous IO handler. > + */ > +static void > +handle_sync_io(int fd, short event, void *arg) > +{ > + struct virtio_dev *dev = (struct virtio_dev *)arg; > + struct imsgev *iev = &dev->sync_iev; > + struct imsgbuf *ibuf = &iev->ibuf; > + struct viodev_msg msg; > + struct imsg imsg; > + ssize_t n; > + int deassert = 0; > + > + if (event & EV_READ) { > + if ((n = imsgbuf_read(ibuf)) == -1) > + fatal("%s: imsgbuf_read", __func__); > + if (n == 0) { > + /* this pipe is dead, so remove the event handler */ > + log_debug("%s: vioscsi pipe dead (EV_READ)", __func__); > + event_del(&iev->ev); > + event_loopexit(NULL); > + return; > + } > + } > + > + if (event & EV_WRITE) { > + if (imsgbuf_write(ibuf) == -1) { > + if (errno == EPIPE) { > + /* this pipe is dead, remove the handler */ > + log_debug("%s: pipe dead (EV_WRITE)", __func__); > + event_del(&iev->ev); > + event_loopexit(NULL); > + return; > + } > + fatal("%s: imsgbuf_write", __func__); > + } > + } > + > + for (;;) { > + if ((n = imsg_get(ibuf, &imsg)) == -1) > + fatalx("%s: imsg_get (n=%ld)", __func__, n); > + if (n == 0) > + break; > + > + /* Unpack our message. They ALL should be dev messages! */ > + viodev_msg_read(&imsg, &msg); > + imsg_free(&imsg); > + > + switch (msg.type) { > + case VIODEV_MSG_IO_READ: > + /* Read IO: make sure to send a reply */ > + msg.data = vioscsi_read(dev, &msg, &deassert); > + msg.data_valid = 1; > + if (deassert) { > + /* Inline any interrupt deassertions. */ > + msg.state = INTR_STATE_DEASSERT; > + } > + imsg_compose_event(iev, IMSG_DEVOP_MSG, 0, 0, -1, &msg, > + sizeof(msg)); > + break; > + case VIODEV_MSG_IO_WRITE: > + /* Write IO: no reply needed, but maybe an irq assert */ > + if (vioscsi_write(dev, &msg)) > + virtio_assert_irq(dev, 0); > + break; > + case VIODEV_MSG_SHUTDOWN: > + event_del(&dev->sync_iev.ev); > + event_loopbreak(); > + return; > + default: > + fatalx("%s: invalid msg type %d", __func__, msg.type); > + } > + } > + imsg_event_add(iev); > +} > + > static int > +vioscsi_write(struct virtio_dev *dev, struct viodev_msg *msg) > +{ > + uint32_t data = msg->data; > + uint16_t reg = msg->reg; > + uint8_t sz = msg->io_sz; > + int notify = 0; > + > + switch (reg & 0xFF00) { > + case VIO1_CFG_BAR_OFFSET: > + (void)virtio_io_cfg(dev, VEI_DIR_OUT, (reg & 0xFF), data, sz); > + break; > + case VIO1_DEV_BAR_OFFSET: > + (void)vioscsi_io_cfg(dev, VEI_DIR_OUT, (reg & 0xFF), data, sz); > + break; > + case VIO1_NOTIFY_BAR_OFFSET: > + notify = vioscsi_notifyq(dev, (uint16_t)(msg->data)); > + break; > + case VIO1_ISR_BAR_OFFSET: > + /* Ignore writes to ISR. */ > + break; > + default: > + log_debug("%s: no handler for reg 0x%04x", __func__, reg); > + } > + > + return (notify); > +} > + > +static uint32_t > +vioscsi_read(struct virtio_dev *dev, struct viodev_msg *msg, int *deassert) > +{ > + uint32_t data = 0; > + uint16_t reg = msg->reg; > + uint8_t sz = msg->io_sz; > + > + switch (reg & 0xFF00) { > + case VIO1_CFG_BAR_OFFSET: > + data = virtio_io_cfg(dev, VEI_DIR_IN, (reg & 0xFF), 0, sz); > + break; > + case VIO1_DEV_BAR_OFFSET: > + data = vioscsi_io_cfg(dev, VEI_DIR_IN, (reg & 0xFF), 0, sz); > + break; > + case VIO1_NOTIFY_BAR_OFFSET: > + /* Reads of notify register return all 1's. */ > + break; > + case VIO1_ISR_BAR_OFFSET: > + data = dev->isr; > + dev->isr = 0; > + *deassert = 1; > + break; > + default: > + log_debug("%s: no handler for reg 0x%04x", __func__, reg); > + } > + > + return (data); > +} > + > +static int > vioscsi_handle_inquiry(struct virtio_dev *dev, struct virtio_vq_info *vq_info, > struct virtio_scsi_req_hdr *req, struct virtio_vq_acct *acct) > { > @@ -1708,19 +2062,17 @@ get_config_out: > return (ret); > } > > -int > -vioscsi_io(int dir, uint16_t reg, uint32_t *data, uint8_t *intr, > - void *cookie, uint8_t sz) > +static uint32_t > +vioscsi_io_cfg(struct virtio_dev *dev, int dir, uint8_t reg, uint32_t data, > + uint8_t sz) > { > - struct virtio_dev *dev = (struct virtio_dev *)cookie; > struct vioscsi_dev *vioscsi = NULL; > + uint32_t res = 0; > > if (dev->device_id != PCI_PRODUCT_VIRTIO_SCSI) > fatalx("%s: virtio device is not a scsi device", __func__); > vioscsi = &dev->vioscsi; > > - *intr = 0xFF; > - > DPRINTF("%s: request %s reg %s sz %u", __func__, > dir ? "READ" : "WRITE", vioscsi_reg_name(reg), sz); > > @@ -1728,13 +2080,13 @@ vioscsi_io(int dir, uint16_t reg, uint32_t *data, uint > switch (reg) { > case VIRTIO_SCSI_CONFIG_SENSE_SIZE: > /* Support writing to sense size register. */ > - if (*data != VIOSCSI_SENSE_LEN) > + if (data != VIOSCSI_SENSE_LEN) > log_warnx("%s: guest write to sense size " > "register ignored", __func__); > break; > case VIRTIO_SCSI_CONFIG_CDB_SIZE: > /* Support writing CDB size. */ > - if (*data != VIOSCSI_CDB_LEN) > + if (data != VIOSCSI_CDB_LEN) > log_warnx("%s: guest write to cdb size " > "register ignored", __func__); > break; > @@ -1747,63 +2099,63 @@ vioscsi_io(int dir, uint16_t reg, uint32_t *data, uint > case VIRTIO_SCSI_CONFIG_NUM_QUEUES: > /* Number of request queues, not number of all queues. */ > if (sz == 4) > - *data = (uint32_t)(VIOSCSI_NUM_REQ_QUEUES); > + res = (uint32_t)(VIOSCSI_NUM_REQ_QUEUES); > else > log_warnx("%s: unaligned read of num queues " > "register", __func__); > break; > case VIRTIO_SCSI_CONFIG_SEG_MAX: > if (sz == 4) > - *data = (uint32_t)(VIOSCSI_SEG_MAX); > + res = (uint32_t)(VIOSCSI_SEG_MAX); > else > log_warnx("%s: unaligned read of seg max " > "register", __func__); > break; > case VIRTIO_SCSI_CONFIG_MAX_SECTORS: > if (sz == 4) > - *data = (uint32_t)(vioscsi->max_xfer); > + res = (uint32_t)(vioscsi->max_xfer); > else > log_warnx("%s: unaligned read of max sectors " > "register", __func__); > break; > case VIRTIO_SCSI_CONFIG_CMD_PER_LUN: > if (sz == 4) > - *data = (uint32_t)(VIOSCSI_CMD_PER_LUN); > + res = (uint32_t)(VIOSCSI_CMD_PER_LUN); > else > log_warnx("%s: unaligned read of cmd per lun " > "register", __func__); > break; > case VIRTIO_SCSI_CONFIG_EVENT_INFO_SIZE: > - *data = 0; > + res = 0; > break; > case VIRTIO_SCSI_CONFIG_SENSE_SIZE: > if (sz == 4) > - *data = (uint32_t)(VIOSCSI_SENSE_LEN); > + res = (uint32_t)(VIOSCSI_SENSE_LEN); > else > log_warnx("%s: unaligned read of sense size " > "register", __func__); > break; > case VIRTIO_SCSI_CONFIG_CDB_SIZE: > if (sz == 4) > - *data = (uint32_t)(VIOSCSI_CDB_LEN); > + res = (uint32_t)(VIOSCSI_CDB_LEN); > else > log_warnx("%s: unaligned read of cdb size " > "register", __func__); > break; > case VIRTIO_SCSI_CONFIG_MAX_CHANNEL: > /* defined by standard to be zero */ > - *data = 0; > + res = 0; > break; > case VIRTIO_SCSI_CONFIG_MAX_TARGET: > if (sz == 2) > - *data = (uint32_t)(VIOSCSI_MAX_TARGET); > + res = (uint32_t)(VIOSCSI_MAX_TARGET); > else > log_warnx("%s: unaligned read of max target " > "register", __func__); > break; > case VIRTIO_SCSI_CONFIG_MAX_LUN: > if (sz == 4) > - *data = (uint32_t)(VIOSCSI_MAX_LUN); > + res = (uint32_t)(VIOSCSI_MAX_LUN); > else > log_warnx("%s: unaligned read of max lun " > "register", __func__); > @@ -1813,7 +2165,7 @@ vioscsi_io(int dir, uint16_t reg, uint32_t *data, uint > } > } > > - return (0); > + return (res); > } > > /* > @@ -1826,7 +2178,7 @@ vioscsi_io(int dir, uint16_t reg, uint32_t *data, uint > * Return 1 if an interrupt should be generated (response written) > * 0 otherwise > */ > -int > +static int > vioscsi_notifyq(struct virtio_dev *dev, uint16_t vq_idx) > { > size_t cnt; > blob - fa0845746230386b1dc3a9a3e7671bd243b21c92 > blob + 5083fa8d2c2246b0b3bebfb066c99b16cbea4edb > --- usr.sbin/vmd/virtio.c > +++ usr.sbin/vmd/virtio.c > @@ -332,9 +332,7 @@ virtio_io_dispatch(int dir, uint16_t reg, uint32_t *da > *data = virtio_io_cfg(dev, dir, actual, *data, sz); > break; > case VIO1_DEV_BAR_OFFSET: > - if (dev->device_id == PCI_PRODUCT_VIRTIO_SCSI) > - return vioscsi_io(dir, actual, data, intr, arg, sz); > - else if (dir == VEI_DIR_IN) { > + if (dir == VEI_DIR_IN) { > log_debug("%s: no device specific handler", __func__); > *data = (uint32_t)(-1); > } > @@ -643,7 +641,8 @@ virtio_io_isr(int dir, uint16_t reg, uint32_t *data, u > > /* Limit to in-process devices. */ > if (dev->device_id == PCI_PRODUCT_VIRTIO_BLOCK || > - dev->device_id == PCI_PRODUCT_VIRTIO_NETWORK) > + dev->device_id == PCI_PRODUCT_VIRTIO_NETWORK || > + dev->device_id == PCI_PRODUCT_VIRTIO_SCSI) > fatalx("%s: cannot use on multi-process virtio dev", __func__); > > if (dir == VEI_DIR_IN) { > @@ -670,7 +669,8 @@ virtio_io_notify(int dir, uint16_t reg, uint32_t *data > > /* Limit this handler to in-process devices */ > if (dev->device_id == PCI_PRODUCT_VIRTIO_BLOCK || > - dev->device_id == PCI_PRODUCT_VIRTIO_NETWORK) > + dev->device_id == PCI_PRODUCT_VIRTIO_NETWORK || > + dev->device_id == PCI_PRODUCT_VIRTIO_SCSI) > fatalx("%s: cannot use on multi-process virtio dev", __func__); > > if (vq_idx >= dev->num_queues) { > @@ -688,9 +688,6 @@ virtio_io_notify(int dir, uint16_t reg, uint32_t *data > case PCI_PRODUCT_VIRTIO_ENTROPY: > raise_intr = viornd_notifyq(dev, vq_idx); > break; > - case PCI_PRODUCT_VIRTIO_SCSI: > - raise_intr = vioscsi_notifyq(dev, vq_idx); > - break; > case PCI_PRODUCT_VIRTIO_VMMCI: > /* Does not use a virtqueue. */ > break; > @@ -1138,16 +1135,6 @@ virtio_init(struct vmd_vm *vm, int child_cdrom, > } > } > > - /* > - * Launch virtio devices that support subprocess execution. > - */ > - SLIST_FOREACH(dev, &virtio_devs, dev_next) { > - if (virtio_dev_launch(vm, dev) != 0) { > - log_warnx("failed to launch virtio device"); > - return (1); > - } > - } > - > /* Virtio 1.x SCSI CD-ROM */ > if (strlen(vmc->vmc_cdrom)) { > dev = malloc(sizeof(struct virtio_dev)); > @@ -1164,7 +1151,7 @@ virtio_init(struct vmd_vm *vm, int child_cdrom, > } > virtio_dev_init(vm, dev, id, VIOSCSI_QUEUE_SIZE_DEFAULT, > VIRTIO_SCSI_QUEUES, VIRTIO_F_VERSION_1); > - if (pci_add_bar(id, PCI_MAPREG_TYPE_IO, virtio_io_dispatch, dev) > + if (pci_add_bar(id, PCI_MAPREG_TYPE_IO, virtio_pci_io, dev) > == -1) { > log_warnx("can't add bar for vioscsi device"); > return (1); > @@ -1175,19 +1162,25 @@ virtio_init(struct vmd_vm *vm, int child_cdrom, > virtio_pci_add_cap(id, VIRTIO_PCI_CAP_NOTIFY_CFG, bar_id, 0); > > /* Device specific initialization. */ > - if (virtio_raw_init(&dev->vioscsi.file, &dev->vioscsi.sz, > - &child_cdrom, 1) == -1) { > - log_warnx("%s: unable to determine iso format", > - __func__); > - return (1); > - } > + dev->dev_type = VMD_DEVTYPE_SCSI; > + dev->vmm_id = vm->vm_vmmid; > + dev->vioscsi.cdrom_fd = child_cdrom; > dev->vioscsi.locked = 0; > dev->vioscsi.lba = 0; > - dev->vioscsi.n_blocks = dev->vioscsi.sz / > - VIOSCSI_BLOCK_SIZE_CDROM; > dev->vioscsi.max_xfer = VIOSCSI_BLOCK_SIZE_CDROM; > + SLIST_INSERT_HEAD(&virtio_devs, dev, dev_next); > } > > + /* > + * Launch virtio devices that support subprocess execution. > + */ > + SLIST_FOREACH(dev, &virtio_devs, dev_next) { > + if (virtio_dev_launch(vm, dev) != 0) { > + log_warnx("failed to launch virtio device"); > + return (1); > + } > + } > + > /* Virtio 0.9 VMM Control Interface */ > dev = &vmmci; > if (pci_add_device(&id, PCI_VENDOR_OPENBSD, PCI_PRODUCT_OPENBSD_CONTROL, > @@ -1483,6 +1476,9 @@ virtio_dev_launch(struct vmd_vm *vm, struct virtio_dev > log_debug("%s: launching vioblk%d", vm->vm_params.vmc_name, > dev->vioblk.idx); > break; > + case VMD_DEVTYPE_SCSI: > + log_debug("%s: launching vioscsi", vm->vm_params.vmc_name); > + break; > /* NOTREACHED */ > default: > log_warn("%s: invalid device type", __func__); > @@ -1595,7 +1591,7 @@ virtio_dev_launch(struct vmd_vm *vm, struct virtio_dev > close_fd(vm->vm_tty); > vm->vm_tty = -1; > > - if (vm->vm_cdrom != -1) { > + if (vm->vm_cdrom != -1 && dev->dev_type != VMD_DEVTYPE_SCSI) { > close_fd(vm->vm_cdrom); > vm->vm_cdrom = -1; > } > @@ -1917,6 +1913,10 @@ virtio_dev_closefds(struct virtio_dev *dev) > close_fd(dev->vionet.data_fd); > dev->vionet.data_fd = -1; > break; > + case VMD_DEVTYPE_SCSI: > + close_fd(dev->vioscsi.cdrom_fd); > + dev->vioscsi.cdrom_fd = -1; > + break; > default: > log_warnx("%s: invalid device type", __func__); > return (-1); > blob - 026ad278a8c22b6e96516e383adf566a083943a5 > blob + eb9212ec7db57e0a565980fa7119a9192d692955 > --- usr.sbin/vmd/virtio.h > +++ usr.sbin/vmd/virtio.h > @@ -269,6 +269,7 @@ struct vioblk_dev { > */ > struct vioscsi_dev { > struct virtio_backing file; > + int cdrom_fd; /* fd for iso file */ > > int locked; /* is the device locked? */ > uint64_t sz; /* size of iso file in bytes */ > @@ -412,10 +413,6 @@ const char *vioblk_cmd_name(uint32_t); > /* dhcp.c */ > ssize_t dhcp_request(struct virtio_dev *, char *, size_t, char **); > > -/* vioscsi.c */ > -int vioscsi_io(int, uint16_t, uint32_t *, uint8_t *, void *, uint8_t); > -int vioscsi_notifyq(struct virtio_dev *, uint16_t); > - > /* imsg handling */ > void viodev_msg_read(struct imsg *, struct viodev_msg *); > void vionet_hostmac_read(struct imsg *, struct vionet_dev *); > blob - de6b15d36231d4d9c3e85f1408a0a6c180d0ffca > blob + 14a5d12b5ae4ea7a0793907e62661123e12fb90c > --- usr.sbin/vmd/vmd.c > +++ usr.sbin/vmd/vmd.c > @@ -603,6 +603,7 @@ main(int argc, char **argv) > switch (dev_type) { > case VMD_DEVTYPE_NET: > case VMD_DEVTYPE_DISK: > + case VMD_DEVTYPE_SCSI: > break; > default: fatalx("invalid device type"); > } > @@ -673,6 +674,10 @@ main(int argc, char **argv) > log_procinit("vm/%s/vioblk", title); > vioblk_main(vm_fd, vmm_fd); > /* NOTREACHED */ > + } else if (dev_type == VMD_DEVTYPE_SCSI) { > + log_procinit("vm/%s/vioscsi", title); > + vioscsi_main(vm_fd, vmm_fd); > + /* NOTREACHED */ > } > fatalx("unsupported device type '%c'", dev_type); > } > blob - 5ddfd9e4823fe00b29c0489da53503b68405571c > blob + f7ac0d112ede43b417d185bc920e4f76bb778fcb > --- usr.sbin/vmd/vmd.h > +++ usr.sbin/vmd/vmd.h > @@ -83,6 +83,7 @@ > > #define VMD_DEVTYPE_NET 'n' > #define VMD_DEVTYPE_DISK 'd' > +#define VMD_DEVTYPE_SCSI 's' > > /* Rate-limit fast reboots */ > #define VM_START_RATE_SEC 6 /* min. seconds since last reboot */ > @@ -588,6 +589,8 @@ __dead void vionet_main(int, int); > > /* vioblk.c */ > __dead void vioblk_main(int, int); > +/* vioscsi.c */ > +__dead void vioscsi_main(int, int); > > /* psp.c */ > int psp_get_pstate(uint16_t *, uint8_t *, uint8_t *, uint8_t *, uint8_t *); >