Exemple #1
0
void
vdsp_rx_vio_ver_info(struct vdsp_softc *sc, struct vio_msg_tag *tag)
{
	struct vio_ver_info *vi = (struct vio_ver_info *)tag;

	switch (vi->tag.stype) {
	case VIO_SUBTYPE_INFO:
		DPRINTF(("CTRL/INFO/VER_INFO\n"));

		/* Make sure we're talking to a virtual disk. */
		if (vi->dev_class != VDEV_DISK) {
			/* Huh, we're not talking to a disk device? */
			printf("%s: peer is not a disk device\n",
			    sc->sc_dv.dv_xname);
			vi->tag.stype = VIO_SUBTYPE_NACK;
			vi->major = 0;
			vdsp_sendmsg(sc, vi, sizeof(*vi), 0);
			return;
		}

		if (vi->major != VDSK_MAJOR) {
			vi->tag.stype = VIO_SUBTYPE_NACK;
			vi->major = VDSK_MAJOR;
			vi->minor = VDSK_MINOR;
			vdsp_sendmsg(sc, vi, sizeof(*vi), 0);
			return;
		}

		sc->sc_major = vi->major;
		sc->sc_minor = vi->minor;
		sc->sc_local_sid = vi->tag.sid;

		vi->tag.stype = VIO_SUBTYPE_ACK;
		if (vi->minor > VDSK_MINOR)
			vi->minor = VDSK_MINOR;
		vi->dev_class = VDEV_DISK_SERVER;
		vdsp_sendmsg(sc, vi, sizeof(*vi), 0);
		sc->sc_vio_state |= VIO_RCV_VER_INFO;
		break;

	case VIO_SUBTYPE_ACK:
		DPRINTF(("CTRL/ACK/VER_INFO\n"));
		break;

	default:
		DPRINTF(("CTRL/0x%02x/VER_INFO\n", vi->tag.stype));
		break;
	}
}
Exemple #2
0
void
vdsp_rx_vio_dring_reg(struct vdsp_softc *sc, struct vio_msg_tag *tag)
{
	struct vio_dring_reg *dr = (struct vio_dring_reg *)tag;

	switch (dr->tag.stype) {
	case VIO_SUBTYPE_INFO:
		DPRINTF(("CTRL/INFO/DRING_REG\n"));

		if (dr->num_descriptors > VDSK_MAX_DESCRIPTORS ||
		    dr->descriptor_size > VDSK_MAX_DESCRIPTOR_SIZE ||
		    dr->ncookies > 1) {
			dr->tag.stype = VIO_SUBTYPE_NACK;
			vdsp_sendmsg(sc, dr, sizeof(*dr), 0);
			return;
		}
		sc->sc_num_descriptors = dr->num_descriptors;
		sc->sc_descriptor_size = dr->descriptor_size;
		sc->sc_dring_cookie = dr->cookie[0];
		sc->sc_vio_state |= VIO_RCV_DRING_REG;

		task_add(systq, &sc->sc_alloc_task);
		break;

	case VIO_SUBTYPE_ACK:
		DPRINTF(("CTRL/ACK/DRING_REG\n"));
		break;

	default:
		DPRINTF(("CTRL/0x%02x/DRING_REG\n", dr->tag.stype));
		break;
	}
}
Exemple #3
0
void
vdsp_rx_vio_attr_info(struct vdsp_softc *sc, struct vio_msg_tag *tag)
{
	struct vd_attr_info *ai = (struct vd_attr_info *)tag;

	switch (ai->tag.stype) {
	case VIO_SUBTYPE_INFO:
		DPRINTF(("CTRL/INFO/ATTR_INFO\n"));

		if (ai->xfer_mode != VIO_DESC_MODE &&
		    ai->xfer_mode != VIO_DRING_MODE) {
			printf("%s: peer uses unsupported xfer mode 0x%02x\n",
			    sc->sc_dv.dv_xname, ai->xfer_mode);
			ai->tag.stype = VIO_SUBTYPE_NACK;
			vdsp_sendmsg(sc, ai, sizeof(*ai), 0);
			return;
		}
		sc->sc_xfer_mode = ai->xfer_mode;
		sc->sc_vio_state |= VIO_RCV_ATTR_INFO;

		task_add(systq, &sc->sc_open_task);
		break;

	case VIO_SUBTYPE_ACK:
		DPRINTF(("CTRL/ACK/ATTR_INFO\n"));
		break;

	default:
		DPRINTF(("CTRL/0x%02x/ATTR_INFO\n", ai->tag.stype));
		break;
	}
}
Exemple #4
0
void
vdsp_open(void *arg1, void *arg2)
{
	struct vdsp_softc *sc = arg1;
	struct proc *p = curproc;
	struct vd_attr_info ai;

	if (sc->sc_vp == NULL) {
		struct nameidata nd;
		struct vattr va;
		const char *name;
		int error;

		name = mdesc_get_prop_str(sc->sc_idx, "vds-block-device");
		if (name == NULL)
			return;

		NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, name, p);
		error = vn_open(&nd, FREAD | FWRITE, 0);
		if (error) {
			printf("VOP_OPEN: %s, %d\n", name, error);
			return;
		}

		error = VOP_GETATTR(nd.ni_vp, &va, p->p_ucred, p);
		if (error)
			printf("VOP_GETATTR: %s, %d\n", name, error);
		sc->sc_vdisk_block_size = DEV_BSIZE;
		sc->sc_vdisk_size = va.va_size / DEV_BSIZE;

		VOP_UNLOCK(nd.ni_vp, 0, p);
		sc->sc_vp = nd.ni_vp;

		vdsp_readlabel(sc);
	}

	bzero(&ai, sizeof(ai));
	ai.tag.type = VIO_TYPE_CTRL;
	ai.tag.stype = VIO_SUBTYPE_ACK;
	ai.tag.stype_env = VIO_ATTR_INFO;
	ai.tag.sid = sc->sc_local_sid;
	ai.xfer_mode = sc->sc_xfer_mode;
	ai.vd_type = VD_DISK_TYPE_DISK;
	if (sc->sc_major > 1 || sc->sc_minor >= 1) {
		if (vdsp_is_iso(sc))
			ai.vd_mtype = VD_MEDIA_TYPE_CD;
		else
			ai.vd_mtype = VD_MEDIA_TYPE_FIXED;
	}
	ai.vdisk_block_size = sc->sc_vdisk_block_size;
	ai.operations = VD_OP_MASK;
	ai.vdisk_size = sc->sc_vdisk_size;
	ai.max_xfer_sz = MAXPHYS / sc->sc_vdisk_block_size;
	vdsp_sendmsg(sc, &ai, sizeof(ai), 1);
}
Exemple #5
0
void
vdsp_alloc(void *arg1, void *arg2)
{
	struct vdsp_softc *sc = arg1;
	struct vio_dring_reg dr;

	KASSERT(sc->sc_num_descriptors <= VDSK_MAX_DESCRIPTORS);
	KASSERT(sc->sc_descriptor_size <= VDSK_MAX_DESCRIPTOR_SIZE);
	sc->sc_vd = malloc(sc->sc_num_descriptors * sc->sc_descriptor_size,
	    M_DEVBUF, M_WAITOK);
	sc->sc_vd_task = malloc(sc->sc_num_descriptors * sizeof(struct task),
	    M_DEVBUF, M_WAITOK);

	bzero(&dr, sizeof(dr));
	dr.tag.type = VIO_TYPE_CTRL;
	dr.tag.stype = VIO_SUBTYPE_ACK;
	dr.tag.stype_env = VIO_DRING_REG;
	dr.tag.sid = sc->sc_local_sid;
	dr.dring_ident = ++sc->sc_dring_ident;
	vdsp_sendmsg(sc, &dr, sizeof(dr), 1);
}
Exemple #6
0
void
vdsp_rx_vio_rdx(struct vdsp_softc *sc, struct vio_msg_tag *tag)
{
	switch(tag->stype) {
	case VIO_SUBTYPE_INFO:
		DPRINTF(("CTRL/INFO/RDX\n"));

		tag->stype = VIO_SUBTYPE_ACK;
		tag->sid = sc->sc_local_sid;
		vdsp_sendmsg(sc, tag, sizeof(*tag), 0);
		sc->sc_vio_state |= VIO_RCV_RDX;
		break;

	case VIO_SUBTYPE_ACK:
		DPRINTF(("CTRL/ACK/RDX\n"));
		break;

	default:
		DPRINTF(("CTRL/0x%02x/RDX (VIO)\n", tag->stype));
		break;
	}
}
Exemple #7
0
void
vdsp_rx_vio_dring_data(struct vdsp_softc *sc, struct vio_msg_tag *tag)
{
	struct vio_dring_msg *dm = (struct vio_dring_msg *)tag;
	struct vd_desc *vd;
	vaddr_t va;
	paddr_t pa;
	uint64_t size, off;
	psize_t nbytes;
	int err;

	switch(tag->stype) {
	case VIO_SUBTYPE_INFO:
		DPRINTF(("DATA/INFO/DRING_DATA\n"));

		if (dm->dring_ident != sc->sc_dring_ident ||
		    dm->start_idx >= sc->sc_num_descriptors) {
			dm->tag.stype = VIO_SUBTYPE_NACK;
			vdsp_sendmsg(sc, dm, sizeof(*dm), 0);
			return;
		}

		off = dm->start_idx * sc->sc_descriptor_size;
		vd = (struct vd_desc *)(sc->sc_vd + off);
		va = (vaddr_t)vd;
		size = sc->sc_descriptor_size;
		while (size > 0) {
			pmap_extract(pmap_kernel(), va, &pa);
			nbytes = MIN(size, PAGE_SIZE - (off & PAGE_MASK));
			err = hv_ldc_copy(sc->sc_lc.lc_id, LDC_COPY_IN,
			    sc->sc_dring_cookie.addr + off, pa,
			    nbytes, &nbytes);
			if (err != H_EOK) {
				printf("%s: hv_ldc_copy %d\n", __func__, err);
				return;
			}
			va += nbytes;
			size -= nbytes;
			off += nbytes;
		}

		sc->sc_vd_ring[sc->sc_vd_prod % sc->sc_num_descriptors] = vd;
		membar_producer();
		sc->sc_vd_prod++;
		task_add(systq, &sc->sc_vd_task);

		break;

	case VIO_SUBTYPE_ACK:
		DPRINTF(("DATA/ACK/DRING_DATA\n"));
		break;

	case VIO_SUBTYPE_NACK:
		DPRINTF(("DATA/NACK/DRING_DATA\n"));
		break;

	default:
		DPRINTF(("DATA/0x%02x/DRING_DATA\n", tag->stype));
		break;
	}
}
Exemple #8
0
void
vdsp_read_desc(struct vdsp_softc *sc, struct vdsk_desc_msg *dm)
{
	struct ldc_conn *lc = &sc->sc_lc;
	struct proc *p = curproc;
	struct iovec iov;
	struct uio uio;
	caddr_t buf;
	vaddr_t va;
	paddr_t pa;
	uint64_t size, off;
	psize_t nbytes;
	int err, i;

	if (sc->sc_vp == NULL)
		return;

	buf = malloc(dm->size, M_DEVBUF, M_WAITOK);

	iov.iov_base = buf;
	iov.iov_len = dm->size;
	uio.uio_iov = &iov;
	uio.uio_iovcnt = 1;
	uio.uio_offset = dm->offset * DEV_BSIZE;
	uio.uio_resid = dm->size;
	uio.uio_segflg = UIO_SYSSPACE;
	uio.uio_rw = UIO_READ;
	uio.uio_procp = p;

	vn_lock(sc->sc_vp, LK_EXCLUSIVE | LK_RETRY, p);
	dm->status = VOP_READ(sc->sc_vp, &uio, 0, p->p_ucred);
	VOP_UNLOCK(sc->sc_vp, 0, p);

	KERNEL_UNLOCK();
	if (dm->status == 0) {
		i = 0;
		va = (vaddr_t)buf;
		size = dm->size;
		off = 0;
		while (size > 0 && i < dm->ncookies) {
			pmap_extract(pmap_kernel(), va, &pa);
			nbytes = MIN(size, dm->cookie[i].size - off);
			nbytes = MIN(nbytes, PAGE_SIZE - (off & PAGE_MASK));
			err = hv_ldc_copy(lc->lc_id, LDC_COPY_OUT,
			    dm->cookie[i].addr + off, pa, nbytes, &nbytes);
			if (err != H_EOK) {
				printf("%s: hv_ldc_copy: %d\n", __func__, err);
				dm->status = EIO;
				KERNEL_LOCK();
				goto fail;
			}
			va += nbytes;
			size -= nbytes;
			off += nbytes;
			if (off >= dm->cookie[i].size) {
				off = 0;
				i++;
			}
		}
	}
	KERNEL_LOCK();

fail:
	free(buf, M_DEVBUF, 0);

	/* ACK the descriptor. */
	dm->tag.stype = VIO_SUBTYPE_ACK;
	dm->tag.sid = sc->sc_local_sid;
	vdsp_sendmsg(sc, dm, sizeof(*dm) +
	    (dm->ncookies - 1) * sizeof(struct ldc_cookie), 1);
}
Exemple #9
0
void
vdsp_rx_vio_dring_data(struct vdsp_softc *sc, struct vio_msg_tag *tag)
{
	struct vio_dring_msg *dm = (struct vio_dring_msg *)tag;
	struct vd_desc *vd;
	struct task *task;
	vaddr_t va;
	paddr_t pa;
	uint64_t size, off;
	psize_t nbytes;
	int err;

	switch(tag->stype) {
	case VIO_SUBTYPE_INFO:
		DPRINTF(("DATA/INFO/DRING_DATA\n"));

		if (dm->dring_ident != sc->sc_dring_ident ||
		    dm->start_idx >= sc->sc_num_descriptors) {
			dm->tag.stype = VIO_SUBTYPE_NACK;
			vdsp_sendmsg(sc, dm, sizeof(*dm), 0);
			return;
		}

		off = dm->start_idx * sc->sc_descriptor_size;
		vd = (struct vd_desc *)(sc->sc_vd + off);
		va = (vaddr_t)vd;
		size = sc->sc_descriptor_size;
		while (size > 0) {
			pmap_extract(pmap_kernel(), va, &pa);
			nbytes = MIN(size, PAGE_SIZE - (off & PAGE_MASK));
			err = hv_ldc_copy(sc->sc_lc.lc_id, LDC_COPY_IN,
			    sc->sc_dring_cookie.addr + off, pa,
			    nbytes, &nbytes);
			if (err != H_EOK) {
				printf("%s: hv_ldc_copy %d\n", __func__, err);
				return;
			}
			va += nbytes;
			size -= nbytes;
			off += nbytes;
		}
		task = &sc->sc_vd_task[dm->start_idx];

		DPRINTF(("%s: start_idx %d, end_idx %d, operation %x\n",
		    sc->sc_dv.dv_xname, dm->start_idx, dm->end_idx,
		    vd->operation));
		switch (vd->operation) {
		case VD_OP_BREAD:
			task_set(task, vdsp_read_dring, sc, vd);
			break;
		case VD_OP_BWRITE:
			task_set(task, vdsp_write_dring, sc, vd);
			break;
		case VD_OP_FLUSH:
			task_set(task, vdsp_flush_dring, sc, vd);
			break;
		case VD_OP_GET_VTOC:
			task_set(task, vdsp_get_vtoc, sc, vd);
			break;
		case VD_OP_SET_VTOC:
			task_set(task, vdsp_set_vtoc, sc, vd);
			break;
		case VD_OP_GET_DISKGEOM:
			task_set(task, vdsp_get_diskgeom, sc, vd);
			break;
		case VD_OP_GET_WCE:
		case VD_OP_SET_WCE:
		case VD_OP_GET_DEVID:
			/*
			 * Solaris issues VD_OP_GET_DEVID despite the
			 * fact that we don't advertise it.  It seems
			 * to be able to handle failure just fine, so
			 * we silently ignore it.
			 */
			task_set(task, vdsp_unimp, sc, vd);
			break;
		default:
			printf("%s: unsupported operation 0x%02x\n",
			    sc->sc_dv.dv_xname, vd->operation);
			task_set(task, vdsp_unimp, sc, vd);
			break;
		}
		task_add(systq, task);
		break;

	case VIO_SUBTYPE_ACK:
		DPRINTF(("DATA/ACK/DRING_DATA\n"));
		break;

	case VIO_SUBTYPE_NACK:
		DPRINTF(("DATA/NACK/DRING_DATA\n"));
		break;

	default:
		DPRINTF(("DATA/0x%02x/DRING_DATA\n", tag->stype));
		break;
	}
}