static void ld_virtio_attach(device_t parent, device_t self, void *aux) { struct ld_virtio_softc *sc = device_private(self); struct ld_softc *ld = &sc->sc_ld; struct virtio_softc *vsc = device_private(parent); uint32_t features; char buf[256]; int qsize, maxxfersize, maxnsegs; if (vsc->sc_child != NULL) { aprint_normal(": child already attached for %s; " "something wrong...\n", device_xname(parent)); return; } sc->sc_dev = self; sc->sc_virtio = vsc; vsc->sc_child = self; vsc->sc_ipl = IPL_BIO; vsc->sc_vqs = &sc->sc_vq; vsc->sc_nvqs = 1; vsc->sc_config_change = NULL; vsc->sc_intrhand = virtio_vq_intr; vsc->sc_flags = 0; features = virtio_negotiate_features(vsc, (VIRTIO_BLK_F_SIZE_MAX | VIRTIO_BLK_F_SEG_MAX | VIRTIO_BLK_F_GEOMETRY | VIRTIO_BLK_F_RO | VIRTIO_BLK_F_BLK_SIZE)); if (features & VIRTIO_BLK_F_RO) sc->sc_readonly = 1; else sc->sc_readonly = 0; snprintb(buf, sizeof(buf), VIRTIO_BLK_FLAG_BITS, features); aprint_normal(": Features: %s\n", buf); aprint_naive("\n"); if (features & VIRTIO_BLK_F_BLK_SIZE) { ld->sc_secsize = virtio_read_device_config_4(vsc, VIRTIO_BLK_CONFIG_BLK_SIZE); } else ld->sc_secsize = 512; /* At least genfs_io assumes maxxfer == MAXPHYS. */ if (features & VIRTIO_BLK_F_SIZE_MAX) { maxxfersize = virtio_read_device_config_4(vsc, VIRTIO_BLK_CONFIG_SIZE_MAX); if (maxxfersize < MAXPHYS) { aprint_error_dev(sc->sc_dev, "Too small SIZE_MAX %dK minimum is %dK\n", maxxfersize / 1024, MAXPHYS / 1024); // goto err; maxxfersize = MAXPHYS; } else if (maxxfersize > MAXPHYS) { aprint_normal_dev(sc->sc_dev, "Clip SEG_MAX from %dK to %dK\n", maxxfersize / 1024, MAXPHYS / 1024); maxxfersize = MAXPHYS; } } else maxxfersize = MAXPHYS; if (features & VIRTIO_BLK_F_SEG_MAX) { maxnsegs = virtio_read_device_config_4(vsc, VIRTIO_BLK_CONFIG_SEG_MAX); if (maxnsegs < VIRTIO_BLK_MIN_SEGMENTS) { aprint_error_dev(sc->sc_dev, "Too small SEG_MAX %d minimum is %d\n", maxnsegs, VIRTIO_BLK_MIN_SEGMENTS); maxnsegs = maxxfersize / NBPG; // goto err; } } else maxnsegs = maxxfersize / NBPG; /* 2 for the minimum size */ maxnsegs += VIRTIO_BLK_MIN_SEGMENTS; if (virtio_alloc_vq(vsc, &sc->sc_vq, 0, maxxfersize, maxnsegs, "I/O request") != 0) { goto err; } qsize = sc->sc_vq.vq_num; sc->sc_vq.vq_done = ld_virtio_vq_done; ld->sc_dv = self; ld->sc_secperunit = virtio_read_device_config_8(vsc, VIRTIO_BLK_CONFIG_CAPACITY); ld->sc_maxxfer = maxxfersize; if (features & VIRTIO_BLK_F_GEOMETRY) { ld->sc_ncylinders = virtio_read_device_config_2(vsc, VIRTIO_BLK_CONFIG_GEOMETRY_C); ld->sc_nheads = virtio_read_device_config_1(vsc, VIRTIO_BLK_CONFIG_GEOMETRY_H); ld->sc_nsectors = virtio_read_device_config_1(vsc, VIRTIO_BLK_CONFIG_GEOMETRY_S); } ld->sc_maxqueuecnt = qsize; if (ld_virtio_alloc_reqs(sc, qsize) < 0) goto err; ld->sc_dump = ld_virtio_dump; ld->sc_flush = NULL; ld->sc_start = ld_virtio_start; ld->sc_flags = LDF_ENABLED; ldattach(ld, BUFQ_DISK_DEFAULT_STRAT); return; err: vsc->sc_child = (void*)1; return; }
int viocon_port_create(struct viocon_softc *sc, int portidx) { struct virtio_softc *vsc = sc->sc_virtio; int rxidx, txidx, allocsize, nsegs; char name[6]; struct viocon_port *vp; caddr_t kva; struct tty *tp; vp = malloc(sizeof(*vp), M_DEVBUF, M_WAITOK|M_CANFAIL|M_ZERO); if (vp == NULL) return ENOMEM; sc->sc_ports[portidx] = vp; vp->vp_sc = sc; DBGPRINT("vp: %p\n", vp); if (portidx == 0) rxidx = 0; else rxidx = 2 * (portidx + 1); txidx = rxidx + 1; snprintf(name, sizeof(name), "p%drx", portidx); if (virtio_alloc_vq(vsc, &vsc->sc_vqs[rxidx], rxidx, BUFSIZE, 1, name) != 0) { printf("\nCan't alloc %s virtqueue\n", name); goto err; } vp->vp_rx = &vsc->sc_vqs[rxidx]; vp->vp_rx->vq_done = viocon_rx_intr; vp->vp_si = softintr_establish(IPL_TTY, viocon_rx_soft, vp); DBGPRINT("rx: %p\n", vp->vp_rx); snprintf(name, sizeof(name), "p%dtx", portidx); if (virtio_alloc_vq(vsc, &vsc->sc_vqs[txidx], txidx, BUFSIZE, 1, name) != 0) { printf("\nCan't alloc %s virtqueue\n", name); goto err; } vp->vp_tx = &vsc->sc_vqs[txidx]; vp->vp_tx->vq_done = viocon_tx_intr; DBGPRINT("tx: %p\n", vp->vp_tx); vsc->sc_nvqs += 2; allocsize = (vp->vp_rx->vq_num + vp->vp_tx->vq_num) * BUFSIZE; if (bus_dmamap_create(vsc->sc_dmat, allocsize, 1, allocsize, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &vp->vp_dmamap) != 0) goto err; if (bus_dmamem_alloc(vsc->sc_dmat, allocsize, 8, 0, &vp->vp_dmaseg, 1, &nsegs, BUS_DMA_NOWAIT | BUS_DMA_ZERO) != 0) goto err; if (bus_dmamem_map(vsc->sc_dmat, &vp->vp_dmaseg, nsegs, allocsize, &kva, BUS_DMA_NOWAIT) != 0) goto err; if (bus_dmamap_load(vsc->sc_dmat, vp->vp_dmamap, kva, allocsize, NULL, BUS_DMA_NOWAIT) != 0) goto err; vp->vp_rx_buf = (unsigned char *)kva; /* * XXX use only a small circular tx buffer instead of many BUFSIZE buffers? */ vp->vp_tx_buf = vp->vp_rx_buf + vp->vp_rx->vq_num * BUFSIZE; if (vsc->sc_features & VIRTIO_CONSOLE_F_SIZE) { vp->vp_cols = virtio_read_device_config_2(vsc, VIRTIO_CONSOLE_COLS); vp->vp_rows = virtio_read_device_config_2(vsc, VIRTIO_CONSOLE_ROWS); } tp = ttymalloc(1000000); tp->t_oproc = vioconstart; tp->t_param = vioconparam; tp->t_hwiflow = vioconhwiflow; tp->t_dev = (sc->sc_dev.dv_unit << 4) | portidx; vp->vp_tty = tp; DBGPRINT("tty: %p\n", tp); virtio_start_vq_intr(vsc, vp->vp_rx); virtio_start_vq_intr(vsc, vp->vp_tx); return 0; err: panic("%s failed", __func__); return -1; }
static void ld_virtio_attach(device_t parent, device_t self, void *aux) { struct ld_virtio_softc *sc = device_private(self); struct ld_softc *ld = &sc->sc_ld; struct virtio_softc *vsc = device_private(parent); uint32_t features; int qsize, maxxfersize; if (vsc->sc_child != NULL) { aprint_normal(": child already attached for %s; " "something wrong...\n", device_xname(parent)); return; } aprint_normal("\n"); aprint_naive("\n"); sc->sc_dev = self; sc->sc_virtio = vsc; vsc->sc_child = self; vsc->sc_ipl = IPL_BIO; vsc->sc_vqs = &sc->sc_vq[0]; vsc->sc_nvqs = 1; vsc->sc_config_change = 0; vsc->sc_intrhand = virtio_vq_intr; vsc->sc_flags = 0; features = virtio_negotiate_features(vsc, (VIRTIO_BLK_F_SIZE_MAX | VIRTIO_BLK_F_SEG_MAX | VIRTIO_BLK_F_GEOMETRY | VIRTIO_BLK_F_RO | VIRTIO_BLK_F_BLK_SIZE)); if (features & VIRTIO_BLK_F_RO) sc->sc_readonly = 1; else sc->sc_readonly = 0; ld->sc_secsize = 512; if (features & VIRTIO_BLK_F_BLK_SIZE) { ld->sc_secsize = virtio_read_device_config_4(vsc, VIRTIO_BLK_CONFIG_BLK_SIZE); } maxxfersize = MAXPHYS; #if 0 /* At least genfs_io assumes maxxfer == MAXPHYS. */ if (features & VIRTIO_BLK_F_SEG_MAX) { maxxfersize = virtio_read_device_config_4(vsc, VIRTIO_BLK_CONFIG_SEG_MAX) * ld->sc_secsize; if (maxxfersize > MAXPHYS) maxxfersize = MAXPHYS; } #endif if (virtio_alloc_vq(vsc, &sc->sc_vq[0], 0, maxxfersize, maxxfersize / NBPG + 2, "I/O request") != 0) { goto err; } qsize = sc->sc_vq[0].vq_num; sc->sc_vq[0].vq_done = ld_virtio_vq_done; ld->sc_dv = self; ld->sc_secperunit = virtio_read_device_config_8(vsc, VIRTIO_BLK_CONFIG_CAPACITY); ld->sc_maxxfer = maxxfersize; if (features & VIRTIO_BLK_F_GEOMETRY) { ld->sc_ncylinders = virtio_read_device_config_2(vsc, VIRTIO_BLK_CONFIG_GEOMETRY_C); ld->sc_nheads = virtio_read_device_config_1(vsc, VIRTIO_BLK_CONFIG_GEOMETRY_H); ld->sc_nsectors = virtio_read_device_config_1(vsc, VIRTIO_BLK_CONFIG_GEOMETRY_S); } ld->sc_maxqueuecnt = qsize; if (ld_virtio_alloc_reqs(sc, qsize) < 0) goto err; mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_BIO); ld->sc_dump = ld_virtio_dump; ld->sc_flush = NULL; ld->sc_start = ld_virtio_start; ld->sc_flags = LDF_ENABLED; ldattach(ld); return; err: vsc->sc_child = (void*)1; return; }
static void vioscsi_attach(device_t parent, device_t self, void *aux) { struct vioscsi_softc *sc = device_private(self); struct virtio_softc *vsc = device_private(parent); struct scsipi_adapter *adapt = &sc->sc_adapter; struct scsipi_channel *chan = &sc->sc_channel; uint32_t features; char buf[256]; int rv; if (vsc->sc_child != NULL) { aprint_error(": parent %s already has a child\n", device_xname(parent)); return; } sc->sc_dev = self; vsc->sc_child = self; vsc->sc_ipl = IPL_BIO; vsc->sc_vqs = sc->sc_vqs; vsc->sc_nvqs = __arraycount(sc->sc_vqs); vsc->sc_config_change = NULL; vsc->sc_intrhand = virtio_vq_intr; vsc->sc_flags = 0; features = virtio_negotiate_features(vsc, 0); snprintb(buf, sizeof(buf), VIRTIO_COMMON_FLAG_BITS, features); aprint_normal(": Features: %s\n", buf); aprint_naive("\n"); uint32_t cmd_per_lun = virtio_read_device_config_4(vsc, VIRTIO_SCSI_CONFIG_CMD_PER_LUN); uint32_t seg_max = virtio_read_device_config_4(vsc, VIRTIO_SCSI_CONFIG_SEG_MAX); uint16_t max_target = virtio_read_device_config_2(vsc, VIRTIO_SCSI_CONFIG_MAX_TARGET); uint16_t max_channel = virtio_read_device_config_2(vsc, VIRTIO_SCSI_CONFIG_MAX_CHANNEL); uint32_t max_lun = virtio_read_device_config_4(vsc, VIRTIO_SCSI_CONFIG_MAX_LUN); sc->sc_seg_max = seg_max; for (size_t i = 0; i < __arraycount(sc->sc_vqs); i++) { rv = virtio_alloc_vq(vsc, &sc->sc_vqs[i], i, MAXPHYS, 1 + howmany(MAXPHYS, NBPG), vioscsi_vq_names[i]); if (rv) { aprint_error_dev(sc->sc_dev, "failed to allocate virtqueue %zu\n", i); return; } sc->sc_vqs[i].vq_done = vioscsi_vq_done; } int qsize = sc->sc_vqs[2].vq_num; aprint_normal_dev(sc->sc_dev, "qsize %d\n", qsize); if (vioscsi_alloc_reqs(sc, vsc, qsize, seg_max)) return; /* * Fill in the scsipi_adapter. */ memset(adapt, 0, sizeof(*adapt)); adapt->adapt_dev = sc->sc_dev; adapt->adapt_nchannels = max_channel; adapt->adapt_openings = cmd_per_lun; adapt->adapt_max_periph = adapt->adapt_openings; adapt->adapt_request = vioscsi_scsipi_request; adapt->adapt_minphys = minphys; /* * Fill in the scsipi_channel. */ memset(chan, 0, sizeof(*chan)); chan->chan_adapter = adapt; chan->chan_bustype = &scsi_bustype; chan->chan_channel = 0; chan->chan_ntargets = max_target; chan->chan_nluns = max_lun; chan->chan_id = 0; chan->chan_flags = SCSIPI_CHAN_NOSETTLE; config_found(sc->sc_dev, &sc->sc_channel, scsiprint); }