Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
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);
}