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; } }
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; } }
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; } }
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); }
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); }
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; } }
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; } }
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); }
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; } }