xref: /openbsd/sys/arch/sparc64/dev/vdsp.c (revision cca36db2)
1 /*	$OpenBSD: vdsp.c,v 1.10 2011/01/07 00:46:48 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2009, 2011 Mark Kettenis
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/proc.h>
20 #include <sys/buf.h>
21 #include <sys/device.h>
22 #include <sys/disklabel.h>
23 #include <sys/fcntl.h>
24 #include <sys/malloc.h>
25 #include <sys/namei.h>
26 #include <sys/systm.h>
27 #include <sys/vnode.h>
28 #include <sys/workq.h>
29 
30 #include <machine/autoconf.h>
31 #include <machine/hypervisor.h>
32 #include <machine/mdesc.h>
33 
34 #include <uvm/uvm.h>
35 
36 #include <scsi/scsi_all.h>
37 #include <scsi/scsi_disk.h>
38 #include <scsi/scsiconf.h>
39 
40 #include <isofs/cd9660/iso.h>
41 
42 #include <dev/sun/disklabel.h>
43 
44 #include <sparc64/dev/cbusvar.h>
45 #include <sparc64/dev/ldcvar.h>
46 #include <sparc64/dev/viovar.h>
47 
48 #ifdef VDSP_DEBUG
49 #define DPRINTF(x)	printf x
50 #else
51 #define DPRINTF(x)
52 #endif
53 
54 #define VDSK_TX_ENTRIES			64
55 #define VDSK_RX_ENTRIES			64
56 
57 #define VDSK_MAX_DESCRIPTORS		1024
58 #define VDSK_MAX_DESCRIPTOR_SIZE	512
59 
60 struct vd_attr_info {
61 	struct vio_msg_tag	tag;
62 	uint8_t			xfer_mode;
63 	uint8_t			vd_type;
64 	uint8_t			vd_mtype;
65 	uint8_t			_reserved1;
66 	uint32_t		vdisk_block_size;
67 	uint64_t		operations;
68 	uint64_t		vdisk_size;
69 	uint64_t		max_xfer_sz;
70 	uint64_t		_reserved2[2];
71 };
72 
73 #define VD_DISK_TYPE_SLICE	0x01
74 #define VD_DISK_TYPE_DISK	0x02
75 
76 #define VD_MEDIA_TYPE_FIXED	0x01
77 #define VD_MEDIA_TYPE_CD	0x02
78 #define VD_MEDIA_TYPE_DVD	0x03
79 
80 /* vDisk version 1.0. */
81 #define VD_OP_BREAD		0x01
82 #define VD_OP_BWRITE		0x02
83 #define VD_OP_FLUSH		0x03
84 #define VD_OP_GET_WCE		0x04
85 #define VD_OP_SET_WCE		0x05
86 #define VD_OP_GET_VTOC		0x06
87 #define VD_OP_SET_VTOC		0x07
88 #define VD_OP_GET_DISKGEOM	0x08
89 #define VD_OP_SET_DISKGEOM	0x09
90 #define VD_OP_GET_DEVID		0x0b
91 #define VD_OP_GET_EFI		0x0c
92 #define VD_OP_SET_EFI		0x0d
93 
94 /* vDisk version 1.1 */
95 #define VD_OP_SCSICMD		0x0a
96 #define VD_OP_RESET		0x0e
97 #define VD_OP_GET_ACCESS	0x0f
98 #define VD_OP_SET_ACCESS	0x10
99 #define VD_OP_GET_CAPACITY	0x11
100 
101 /* Sun standard fields. */
102 struct sun_vtoc_preamble {
103 	char	sl_text[128];
104 	u_int	sl_version;	/* label version */
105 	char	sl_volume[8];	/* short volume name */
106 	u_short	sl_nparts;	/* partition count */
107 
108 	struct sun_partinfo sl_part[8];
109 
110 	u_int	sl_bootinfo[3];
111 	u_int	sl_sanity;
112 };
113 
114 struct vd_vtoc_part {
115 	uint16_t	id_tag;
116 	uint16_t	perm;
117 	uint32_t	reserved;
118 	uint64_t	start;
119 	uint64_t	nblocks;
120 
121 };
122 struct vd_vtoc {
123 	uint8_t		volume_name[8];
124 	uint16_t	sector_size;
125 	uint16_t	num_partitions;
126 	uint32_t	reserved;
127 	uint8_t		ascii_label[128];
128 	struct vd_vtoc_part partition[8];
129 };
130 
131 struct vd_diskgeom {
132 	uint16_t	ncyl;
133 	uint16_t	acyl;
134 	uint16_t	bcyl;
135 	uint16_t	nhead;
136 	uint16_t	nsect;
137 	uint16_t	intrlv;
138 	uint16_t	apc;
139 	uint16_t	rpm;
140 	uint16_t	pcyl;
141 	uint16_t	write_reinstruct;
142 	uint16_t	read_reinstruct;
143 };
144 
145 struct vd_desc {
146 	struct vio_dring_hdr	hdr;
147 	uint64_t		req_id;
148 	uint8_t			operation;
149 	uint8_t			slice;
150 	uint16_t		_reserved1;
151 	uint32_t		status;
152 	uint64_t		offset;
153 	uint64_t		size;
154 	uint32_t		ncookies;
155 	uint32_t		_reserved2;
156 	struct ldc_cookie	cookie[1];
157 };
158 
159 #define VD_SLICE_NONE		0xff
160 
161 struct vdsk_desc_msg {
162 	struct vio_msg_tag	tag;
163 	uint64_t		seq_no;
164 	uint64_t		desc_handle;
165 	uint64_t		req_id;
166 	uint8_t			operation;
167 	uint8_t			slice;
168 	uint16_t		_reserved1;
169 	uint32_t		status;
170 	uint64_t		offset;
171 	uint64_t		size;
172 	uint32_t		ncookies;
173 	uint32_t		_reserved2;
174 	struct ldc_cookie	cookie[1];
175 };
176 
177 /*
178  * We support vDisk 1.1.
179  */
180 #define VDSK_MAJOR	1
181 #define VDSK_MINOR	1
182 
183 /*
184  * But we only support a subset of the defined commands.
185  */
186 #define VD_OP_MASK \
187     ((1 << VD_OP_BREAD) | (1 << VD_OP_BWRITE) | (1 << VD_OP_FLUSH) | \
188      (1 << VD_OP_GET_VTOC) | (1 << VD_OP_SET_VTOC) | \
189      (1 << VD_OP_GET_DISKGEOM))
190 
191 struct vdsp_softc {
192 	struct device	sc_dv;
193 	int		sc_idx;
194 	bus_space_tag_t	sc_bustag;
195 	bus_dma_tag_t	sc_dmatag;
196 
197 	uint64_t	sc_tx_sysino;
198 	uint64_t	sc_rx_sysino;
199 	void		*sc_tx_ih;
200 	void		*sc_rx_ih;
201 
202 	struct ldc_conn	sc_lc;
203 
204 	uint16_t	sc_vio_state;
205 #define VIO_SND_VER_INFO	0x0001
206 #define VIO_ACK_VER_INFO	0x0002
207 #define VIO_RCV_VER_INFO	0x0004
208 #define VIO_SND_ATTR_INFO	0x0008
209 #define VIO_ACK_ATTR_INFO	0x0010
210 #define VIO_RCV_ATTR_INFO	0x0020
211 #define VIO_SND_DRING_REG	0x0040
212 #define VIO_ACK_DRING_REG	0x0080
213 #define VIO_RCV_DRING_REG	0x0100
214 #define VIO_SND_RDX		0x0200
215 #define VIO_ACK_RDX		0x0400
216 #define VIO_RCV_RDX		0x0800
217 
218 	uint16_t	sc_major;
219 	uint16_t	sc_minor;
220 
221 	uint8_t		sc_xfer_mode;
222 
223 	uint32_t	sc_local_sid;
224 	uint64_t	sc_seq_no;
225 
226 	uint64_t	sc_dring_ident;
227 	uint32_t	sc_num_descriptors;
228 	uint32_t	sc_descriptor_size;
229 	struct ldc_cookie sc_dring_cookie;
230 
231 	caddr_t		sc_vd;
232 
233 	int		sc_tx_cnt;
234 	int		sc_tx_prod;
235 	int		sc_tx_cons;
236 
237 	uint32_t	sc_vdisk_block_size;
238 	uint64_t	sc_vdisk_size;
239 
240 	struct vnode	*sc_vp;
241 
242 	struct sun_disklabel *sc_label;
243 	uint16_t	sc_ncyl;
244 	uint16_t	sc_acyl;
245 	uint16_t	sc_nhead;
246 	uint16_t	sc_nsect;
247 };
248 
249 int	vdsp_match(struct device *, void *, void *);
250 void	vdsp_attach(struct device *, struct device *, void *);
251 
252 struct cfattach vdsp_ca = {
253 	sizeof(struct vdsp_softc), vdsp_match, vdsp_attach
254 };
255 
256 struct cfdriver vdsp_cd = {
257 	NULL, "vdsp", DV_DULL
258 };
259 
260 int	vdsp_tx_intr(void *);
261 int	vdsp_rx_intr(void *);
262 
263 void	vdsp_rx_data(struct ldc_conn *, struct ldc_pkt *);
264 void	vdsp_rx_vio_ctrl(struct vdsp_softc *, struct vio_msg *);
265 void	vdsp_rx_vio_ver_info(struct vdsp_softc *, struct vio_msg_tag *);
266 void	vdsp_rx_vio_attr_info(struct vdsp_softc *, struct vio_msg_tag *);
267 void	vdsp_rx_vio_dring_reg(struct vdsp_softc *, struct vio_msg_tag *);
268 void	vdsp_rx_vio_rdx(struct vdsp_softc *sc, struct vio_msg_tag *);
269 void	vdsp_rx_vio_data(struct vdsp_softc *sc, struct vio_msg *);
270 void	vdsp_rx_vio_dring_data(struct vdsp_softc *sc,
271 	    struct vio_msg_tag *);
272 void	vdsp_rx_vio_desc_data(struct vdsp_softc *sc, struct vio_msg_tag *);
273 
274 void	vdsp_ldc_reset(struct ldc_conn *);
275 void	vdsp_ldc_start(struct ldc_conn *);
276 
277 void	vdsp_sendmsg(struct vdsp_softc *, void *, size_t);
278 
279 void	vdsp_mountroot(void *);
280 void	vdsp_open(void *, void *);
281 void	vdsp_alloc(void *, void *);
282 void	vdsp_readlabel(struct vdsp_softc *);
283 int	vdsp_writelabel(struct vdsp_softc *);
284 int	vdsp_is_iso(struct vdsp_softc *);
285 void	vdsp_read(void *, void *);
286 void	vdsp_read_dring(void *, void *);
287 void	vdsp_write_dring(void *, void *);
288 void	vdsp_flush_dring(void *, void *);
289 void	vdsp_get_vtoc(void *, void *);
290 void	vdsp_set_vtoc(void *, void *);
291 void	vdsp_get_diskgeom(void *, void *);
292 void	vdsp_unimp(void *, void *);
293 
294 void	vdsp_ack_desc(struct vdsp_softc *, struct vd_desc *);
295 
296 int
297 vdsp_match(struct device *parent, void *match, void *aux)
298 {
299 	struct cbus_attach_args *ca = aux;
300 
301 	if (strcmp(ca->ca_name, "vds-port") == 0)
302 		return (1);
303 
304 	return (0);
305 }
306 
307 void
308 vdsp_attach(struct device *parent, struct device *self, void *aux)
309 {
310 	struct vdsp_softc *sc = (struct vdsp_softc *)self;
311 	struct cbus_attach_args *ca = aux;
312 	struct ldc_conn *lc;
313 
314 	sc->sc_idx = ca->ca_idx;
315 	sc->sc_bustag = ca->ca_bustag;
316 	sc->sc_dmatag = ca->ca_dmatag;
317 
318 	if (cbus_intr_map(ca->ca_node, ca->ca_tx_ino, &sc->sc_tx_sysino) ||
319 	    cbus_intr_map(ca->ca_node, ca->ca_rx_ino, &sc->sc_rx_sysino)) {
320 		printf(": can't map interrupt\n");
321 		return;
322 	}
323 	printf(": ivec 0x%lx, 0x%lx", sc->sc_tx_sysino, sc->sc_tx_sysino);
324 
325 	/*
326 	 * Un-configure queues before registering interrupt handlers,
327 	 * such that we dont get any stale LDC packets or events.
328 	 */
329 	hv_ldc_tx_qconf(ca->ca_id, 0, 0);
330 	hv_ldc_rx_qconf(ca->ca_id, 0, 0);
331 
332 	sc->sc_tx_ih = bus_intr_establish(ca->ca_bustag, sc->sc_tx_sysino,
333 	    IPL_BIO, 0, vdsp_tx_intr, sc, sc->sc_dv.dv_xname);
334 	sc->sc_rx_ih = bus_intr_establish(ca->ca_bustag, sc->sc_rx_sysino,
335 	    IPL_BIO, 0, vdsp_rx_intr, sc, sc->sc_dv.dv_xname);
336 	if (sc->sc_tx_ih == NULL || sc->sc_rx_ih == NULL) {
337 		printf(", can't establish interrupt\n");
338 		return;
339 	}
340 
341 	/*
342 	 * Disable interrupts while we have no queues allocated.
343 	 * Otherwise we may end up with an interrupt storm as soon as
344 	 * our peer places a packet in their transmit queue.
345 	 */
346 	cbus_intr_setenabled(sc->sc_tx_sysino, INTR_DISABLED);
347 	cbus_intr_setenabled(sc->sc_rx_sysino, INTR_DISABLED);
348 
349 	lc = &sc->sc_lc;
350 	lc->lc_id = ca->ca_id;
351 	lc->lc_sc = sc;
352 	lc->lc_reset = vdsp_ldc_reset;
353 	lc->lc_start = vdsp_ldc_start;
354 	lc->lc_rx_data = vdsp_rx_data;
355 
356 	lc->lc_txq = ldc_queue_alloc(sc->sc_dmatag, VDSK_TX_ENTRIES);
357 	if (lc->lc_txq == NULL) {
358 		printf(", can't allocate tx queue\n");
359 		return;
360 	}
361 
362 	lc->lc_rxq = ldc_queue_alloc(sc->sc_dmatag, VDSK_RX_ENTRIES);
363 	if (lc->lc_rxq == NULL) {
364 		printf(", can't allocate rx queue\n");
365 		goto free_txqueue;
366 	}
367 
368 	printf("\n");
369 
370 	mountroothook_establish(vdsp_mountroot, sc);
371 	return;
372 
373 #if 0
374 free_rxqueue:
375 	ldc_queue_free(sc->sc_dmatag, lc->lc_rxq);
376 #endif
377 free_txqueue:
378 	ldc_queue_free(sc->sc_dmatag, lc->lc_txq);
379 }
380 
381 int
382 vdsp_tx_intr(void *arg)
383 {
384 	struct vdsp_softc *sc = arg;
385 	struct ldc_conn *lc = &sc->sc_lc;
386 	uint64_t tx_head, tx_tail, tx_state;
387 
388 	hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
389 	if (tx_state != lc->lc_tx_state) {
390 		switch (tx_state) {
391 		case LDC_CHANNEL_DOWN:
392 			DPRINTF(("Tx link down\n"));
393 			break;
394 		case LDC_CHANNEL_UP:
395 			DPRINTF(("Tx link up\n"));
396 			break;
397 		case LDC_CHANNEL_RESET:
398 			DPRINTF(("Tx link reset\n"));
399 			break;
400 		}
401 		lc->lc_tx_state = tx_state;
402 	}
403 
404 	return (1);
405 }
406 
407 int
408 vdsp_rx_intr(void *arg)
409 {
410 	struct vdsp_softc *sc = arg;
411 	struct ldc_conn *lc = &sc->sc_lc;
412 	uint64_t rx_head, rx_tail, rx_state;
413 	struct ldc_pkt *lp;
414 	int err;
415 
416 	err = hv_ldc_rx_get_state(lc->lc_id, &rx_head, &rx_tail, &rx_state);
417 	if (err == H_EINVAL)
418 		return (0);
419 	if (err != H_EOK) {
420 		printf("hv_ldc_rx_get_state %d\n", err);
421 		return (0);
422 	}
423 
424 	if (rx_state != lc->lc_rx_state) {
425 		switch (rx_state) {
426 		case LDC_CHANNEL_DOWN:
427 			DPRINTF(("Rx link down\n"));
428 			lc->lc_tx_seqid = 0;
429 			lc->lc_state = 0;
430 			lc->lc_reset(lc);
431 			break;
432 		case LDC_CHANNEL_UP:
433 			DPRINTF(("Rx link up\n"));
434 			break;
435 		case LDC_CHANNEL_RESET:
436 			DPRINTF(("Rx link reset\n"));
437 			lc->lc_tx_seqid = 0;
438 			lc->lc_state = 0;
439 			lc->lc_reset(lc);
440 			break;
441 		}
442 		lc->lc_rx_state = rx_state;
443 		return (1);
444 	}
445 
446 	if (lc->lc_rx_state == LDC_CHANNEL_DOWN)
447 		return (1);
448 
449 	lp = (struct ldc_pkt *)(lc->lc_rxq->lq_va + rx_head);
450 	switch (lp->type) {
451 	case LDC_CTRL:
452 		ldc_rx_ctrl(lc, lp);
453 		break;
454 
455 	case LDC_DATA:
456 		ldc_rx_data(lc, lp);
457 		break;
458 
459 	default:
460 		DPRINTF(("0x%02x/0x%02x/0x%02x\n", lp->type, lp->stype,
461 		    lp->ctrl));
462 		ldc_reset(lc);
463 		break;
464 	}
465 
466 	rx_head += sizeof(*lp);
467 	rx_head &= ((lc->lc_rxq->lq_nentries * sizeof(*lp)) - 1);
468 	err = hv_ldc_rx_set_qhead(lc->lc_id, rx_head);
469 	if (err != H_EOK)
470 		printf("%s: hv_ldc_rx_set_qhead %d\n", __func__, err);
471 
472 	return (1);
473 }
474 
475 void
476 vdsp_rx_data(struct ldc_conn *lc, struct ldc_pkt *lp)
477 {
478 	struct vio_msg *vm = (struct vio_msg *)lp;
479 
480 	switch (vm->type) {
481 	case VIO_TYPE_CTRL:
482 		if ((lp->env & LDC_FRAG_START) == 0 &&
483 		    (lp->env & LDC_FRAG_STOP) == 0)
484 			return;
485 		vdsp_rx_vio_ctrl(lc->lc_sc, vm);
486 		break;
487 
488 	case VIO_TYPE_DATA:
489 		if((lp->env & LDC_FRAG_START) == 0)
490 			return;
491 		vdsp_rx_vio_data(lc->lc_sc, vm);
492 		break;
493 
494 	default:
495 		DPRINTF(("Unhandled packet type 0x%02x\n", vm->type));
496 		ldc_reset(lc);
497 		break;
498 	}
499 }
500 
501 void
502 vdsp_rx_vio_ctrl(struct vdsp_softc *sc, struct vio_msg *vm)
503 {
504 	struct vio_msg_tag *tag = (struct vio_msg_tag *)&vm->type;
505 
506 	switch (tag->stype_env) {
507 	case VIO_VER_INFO:
508 		vdsp_rx_vio_ver_info(sc, tag);
509 		break;
510 	case VIO_ATTR_INFO:
511 		vdsp_rx_vio_attr_info(sc, tag);
512 		break;
513 	case VIO_DRING_REG:
514 		vdsp_rx_vio_dring_reg(sc, tag);
515 		break;
516 	case VIO_RDX:
517 		vdsp_rx_vio_rdx(sc, tag);
518 		break;
519 	default:
520 		DPRINTF(("CTRL/0x%02x/0x%04x\n", tag->stype, tag->stype_env));
521 		break;
522 	}
523 }
524 
525 void
526 vdsp_rx_vio_ver_info(struct vdsp_softc *sc, struct vio_msg_tag *tag)
527 {
528 	struct vio_ver_info *vi = (struct vio_ver_info *)tag;
529 
530 	switch (vi->tag.stype) {
531 	case VIO_SUBTYPE_INFO:
532 		DPRINTF(("CTRL/INFO/VER_INFO\n"));
533 
534 		/* Make sure we're talking to a virtual disk. */
535 		if (vi->dev_class != VDEV_DISK) {
536 			/* Huh, we're not talking to a disk device? */
537 			printf("%s: peer is not a disk device\n",
538 			    sc->sc_dv.dv_xname);
539 			vi->tag.stype = VIO_SUBTYPE_NACK;
540 			vi->major = 0;
541 			vdsp_sendmsg(sc, vi, sizeof(*vi));
542 			return;
543 		}
544 
545 		if (vi->major != VDSK_MAJOR) {
546 			vi->tag.stype = VIO_SUBTYPE_NACK;
547 			vi->major = VDSK_MAJOR;
548 			vi->minor = VDSK_MINOR;
549 			vdsp_sendmsg(sc, vi, sizeof(*vi));
550 			return;
551 		}
552 
553 		sc->sc_major = vi->major;
554 		sc->sc_minor = vi->minor;
555 		sc->sc_local_sid = vi->tag.sid;
556 
557 		vi->tag.stype = VIO_SUBTYPE_ACK;
558 		if (vi->minor > VDSK_MINOR)
559 			vi->minor = VDSK_MINOR;
560 		vi->dev_class = VDEV_DISK_SERVER;
561 		vdsp_sendmsg(sc, vi, sizeof(*vi));
562 		sc->sc_vio_state |= VIO_RCV_VER_INFO;
563 		break;
564 
565 	case VIO_SUBTYPE_ACK:
566 		DPRINTF(("CTRL/ACK/VER_INFO\n"));
567 		break;
568 
569 	default:
570 		DPRINTF(("CTRL/0x%02x/VER_INFO\n", vi->tag.stype));
571 		break;
572 	}
573 }
574 
575 void
576 vdsp_rx_vio_attr_info(struct vdsp_softc *sc, struct vio_msg_tag *tag)
577 {
578 	struct vd_attr_info *ai = (struct vd_attr_info *)tag;
579 
580 	switch (ai->tag.stype) {
581 	case VIO_SUBTYPE_INFO:
582 		DPRINTF(("CTRL/INFO/ATTR_INFO\n"));
583 
584 		if (ai->xfer_mode != VIO_DESC_MODE &&
585 		    ai->xfer_mode != VIO_DRING_MODE) {
586 			printf("%s: peer uses unsupported xfer mode 0x%02x\n",
587 			    sc->sc_dv.dv_xname, ai->xfer_mode);
588 			ai->tag.stype = VIO_SUBTYPE_NACK;
589 			vdsp_sendmsg(sc, ai, sizeof(*ai));
590 			return;
591 		}
592 		sc->sc_xfer_mode = ai->xfer_mode;
593 		sc->sc_vio_state |= VIO_RCV_ATTR_INFO;
594 
595 		workq_add_task(NULL, 0, vdsp_open, sc, NULL);
596 		break;
597 
598 	case VIO_SUBTYPE_ACK:
599 		DPRINTF(("CTRL/ACK/ATTR_INFO\n"));
600 		break;
601 
602 	default:
603 		DPRINTF(("CTRL/0x%02x/ATTR_INFO\n", ai->tag.stype));
604 		break;
605 	}
606 }
607 
608 void
609 vdsp_rx_vio_dring_reg(struct vdsp_softc *sc, struct vio_msg_tag *tag)
610 {
611 	struct vio_dring_reg *dr = (struct vio_dring_reg *)tag;
612 
613 	switch (dr->tag.stype) {
614 	case VIO_SUBTYPE_INFO:
615 		DPRINTF(("CTRL/INFO/DRING_REG\n"));
616 
617 		if (dr->num_descriptors > VDSK_MAX_DESCRIPTORS ||
618 		    dr->descriptor_size > VDSK_MAX_DESCRIPTOR_SIZE ||
619 		    dr->ncookies > 1) {
620 			dr->tag.stype = VIO_SUBTYPE_NACK;
621 			vdsp_sendmsg(sc, dr, sizeof(*dr));
622 			return;
623 		}
624 		sc->sc_num_descriptors = dr->num_descriptors;
625 		sc->sc_descriptor_size = dr->descriptor_size;
626 		sc->sc_dring_cookie = dr->cookie[0];
627 		sc->sc_vio_state |= VIO_RCV_DRING_REG;
628 
629 		workq_add_task(NULL, 0, vdsp_alloc, sc, NULL);
630 		break;
631 
632 	case VIO_SUBTYPE_ACK:
633 		DPRINTF(("CTRL/ACK/DRING_REG\n"));
634 		break;
635 
636 	default:
637 		DPRINTF(("CTRL/0x%02x/DRING_REG\n", dr->tag.stype));
638 		break;
639 	}
640 }
641 
642 void
643 vdsp_rx_vio_rdx(struct vdsp_softc *sc, struct vio_msg_tag *tag)
644 {
645 	switch(tag->stype) {
646 	case VIO_SUBTYPE_INFO:
647 		DPRINTF(("CTRL/INFO/RDX\n"));
648 
649 		tag->stype = VIO_SUBTYPE_ACK;
650 		tag->sid = sc->sc_local_sid;
651 		vdsp_sendmsg(sc, tag, sizeof(*tag));
652 		sc->sc_vio_state |= VIO_RCV_RDX;
653 		break;
654 
655 	case VIO_SUBTYPE_ACK:
656 		DPRINTF(("CTRL/ACK/RDX\n"));
657 		break;
658 
659 	default:
660 		DPRINTF(("CTRL/0x%02x/RDX (VIO)\n", tag->stype));
661 		break;
662 	}
663 }
664 
665 void
666 vdsp_rx_vio_data(struct vdsp_softc *sc, struct vio_msg *vm)
667 {
668 	struct vio_msg_tag *tag = (struct vio_msg_tag *)&vm->type;
669 
670 	if (!ISSET(sc->sc_vio_state, VIO_RCV_RDX)) {
671 		DPRINTF(("Spurious DATA/0x%02x/0x%04x\n", tag->stype,
672 		    tag->stype_env));
673 		return;
674 	}
675 
676 	switch(tag->stype_env) {
677 	case VIO_DESC_DATA:
678 		vdsp_rx_vio_desc_data(sc, tag);
679 		break;
680 
681 	case VIO_DRING_DATA:
682 		vdsp_rx_vio_dring_data(sc, tag);
683 		break;
684 
685 	default:
686 		DPRINTF(("DATA/0x%02x/0x%04x\n", tag->stype, tag->stype_env));
687 		break;
688 	}
689 }
690 
691 void
692 vdsp_rx_vio_dring_data(struct vdsp_softc *sc, struct vio_msg_tag *tag)
693 {
694 	struct vio_dring_msg *dm = (struct vio_dring_msg *)tag;
695 	struct vd_desc *vd;
696 	vaddr_t va;
697 	paddr_t pa;
698 	uint64_t size, off;
699 	psize_t nbytes;
700 	int err;
701 
702 	switch(tag->stype) {
703 	case VIO_SUBTYPE_INFO:
704 		DPRINTF(("DATA/INFO/DRING_DATA\n"));
705 
706 		if (dm->dring_ident != sc->sc_dring_ident ||
707 		    dm->start_idx >= sc->sc_num_descriptors) {
708 			dm->tag.stype = VIO_SUBTYPE_NACK;
709 			vdsp_sendmsg(sc, dm, sizeof(*dm));
710 			return;
711 		}
712 
713 		off = dm->start_idx * sc->sc_descriptor_size;
714 		vd = (struct vd_desc *)(sc->sc_vd + off);
715 		va = (vaddr_t)vd;
716 		size = sc->sc_descriptor_size;
717 		while (size > 0) {
718 			pmap_extract(pmap_kernel(), va, &pa);
719 			nbytes = min(size, PAGE_SIZE - (off & PAGE_MASK));
720 			err = hv_ldc_copy(sc->sc_lc.lc_id, LDC_COPY_IN,
721 			    sc->sc_dring_cookie.addr | off, pa,
722 			    nbytes, &nbytes);
723 			va += nbytes;
724 			size -= nbytes;
725 			off += nbytes;
726 		}
727 		if (err != H_EOK) {
728 			printf("%s: hv_ldc_copy %d\n", __func__, err);
729 			return;
730 		}
731 
732 		DPRINTF(("%s: start_idx %d, end_idx %d, operation %x\n",
733 		    sc->sc_dv.dv_xname, dm->start_idx, dm->end_idx,
734 		    vd->operation));
735 		switch (vd->operation) {
736 		case VD_OP_BREAD:
737 			workq_add_task(NULL, 0, vdsp_read_dring, sc, vd);
738 			break;
739 		case VD_OP_BWRITE:
740 			workq_add_task(NULL, 0, vdsp_write_dring, sc, vd);
741 			break;
742 		case VD_OP_FLUSH:
743 			workq_add_task(NULL, 0, vdsp_flush_dring, sc, vd);
744 			break;
745 		case VD_OP_GET_VTOC:
746 			workq_add_task(NULL, 0, vdsp_get_vtoc, sc, vd);
747 			break;
748 		case VD_OP_SET_VTOC:
749 			workq_add_task(NULL, 0, vdsp_set_vtoc, sc, vd);
750 			break;
751 		case VD_OP_GET_DISKGEOM:
752 			workq_add_task(NULL, 0, vdsp_get_diskgeom, sc, vd);
753 			break;
754 		default:
755 			printf("%s: unsupported operation 0x%02x\n",
756 			    sc->sc_dv.dv_xname, vd->operation);
757 			workq_add_task(NULL, 0, vdsp_unimp, sc, vd);
758 			break;
759 		}
760 		break;
761 
762 	case VIO_SUBTYPE_ACK:
763 		DPRINTF(("DATA/ACK/DRING_DATA\n"));
764 		break;
765 
766 	case VIO_SUBTYPE_NACK:
767 		DPRINTF(("DATA/NACK/DRING_DATA\n"));
768 		break;
769 
770 	default:
771 		DPRINTF(("DATA/0x%02x/DRING_DATA\n", tag->stype));
772 		break;
773 	}
774 }
775 
776 void
777 vdsp_rx_vio_desc_data(struct vdsp_softc *sc, struct vio_msg_tag *tag)
778 {
779 	struct vdsk_desc_msg *dm = (struct vdsk_desc_msg *)tag;
780 
781 	switch(tag->stype) {
782 	case VIO_SUBTYPE_INFO:
783 		DPRINTF(("DATA/INFO/DESC_DATA\n"));
784 
785 		switch (dm->operation) {
786 		case VD_OP_BREAD:
787 			workq_add_task(NULL, 0, vdsp_read, sc, dm);
788 			break;
789 		default:
790 			printf("%s: unsupported operation 0x%02x\n",
791 			    sc->sc_dv.dv_xname, dm->operation);
792 			break;
793 		}
794 		break;
795 
796 	case VIO_SUBTYPE_ACK:
797 		DPRINTF(("DATA/ACK/DESC_DATA\n"));
798 		break;
799 
800 	case VIO_SUBTYPE_NACK:
801 		DPRINTF(("DATA/NACK/DESC_DATA\n"));
802 		break;
803 
804 	default:
805 		DPRINTF(("DATA/0x%02x/DESC_DATA\n", tag->stype));
806 		break;
807 	}
808 }
809 
810 void
811 vdsp_ldc_reset(struct ldc_conn *lc)
812 {
813 	struct vdsp_softc *sc = lc->lc_sc;
814 
815 	sc->sc_vio_state = 0;
816 	sc->sc_seq_no = 0;
817 	if (sc->sc_vd) {
818 		free(sc->sc_vd, M_DEVBUF);
819 		sc->sc_vd = NULL;
820 	}
821 	if (sc->sc_label) {
822 		free(sc->sc_label, M_DEVBUF);
823 		sc->sc_label = NULL;
824 	}
825 }
826 
827 void
828 vdsp_ldc_start(struct ldc_conn *lc)
829 {
830 	/* The vDisk client is supposed to initiate the handshake. */
831 }
832 
833 void
834 vdsp_sendmsg(struct vdsp_softc *sc, void *msg, size_t len)
835 {
836 	struct ldc_conn *lc = &sc->sc_lc;
837 	struct ldc_pkt *lp;
838 	uint64_t tx_head, tx_tail, tx_state;
839 	uint8_t *p = msg;
840 	int err;
841 
842 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
843 	if (err != H_EOK)
844 		return;
845 
846 	while (len > 0) {
847 		lp = (struct ldc_pkt *)(lc->lc_txq->lq_va + tx_tail);
848 		bzero(lp, sizeof(struct ldc_pkt));
849 		lp->type = LDC_DATA;
850 		lp->stype = LDC_INFO;
851 		lp->env = min(len, LDC_PKT_PAYLOAD);
852 		if (p == msg)
853 			lp->env |= LDC_FRAG_START;
854 		if (len <= LDC_PKT_PAYLOAD)
855 			lp->env |= LDC_FRAG_STOP;
856 		lp->seqid = lc->lc_tx_seqid++;
857 		bcopy(p, &lp->major, min(len, LDC_PKT_PAYLOAD));
858 
859 		tx_tail += sizeof(*lp);
860 		tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
861 		err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
862 		if (err != H_EOK)
863 			printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
864 		p += min(len, LDC_PKT_PAYLOAD);
865 		len -= min(len, LDC_PKT_PAYLOAD);
866 	}
867 }
868 
869 void
870 vdsp_mountroot(void *arg)
871 {
872 	struct vdsp_softc *sc = arg;
873 	struct ldc_conn *lc = &sc->sc_lc;
874 	int err;
875 
876 	err = hv_ldc_tx_qconf(lc->lc_id,
877 	    lc->lc_txq->lq_map->dm_segs[0].ds_addr, lc->lc_txq->lq_nentries);
878 	if (err != H_EOK)
879 		printf("%s: hv_ldc_tx_qconf %d\n", __func__, err);
880 
881 	err = hv_ldc_rx_qconf(lc->lc_id,
882 	    lc->lc_rxq->lq_map->dm_segs[0].ds_addr, lc->lc_rxq->lq_nentries);
883 	if (err != H_EOK)
884 		printf("%s: hv_ldc_rx_qconf %d\n", err, __func__);
885 
886 	cbus_intr_setenabled(sc->sc_tx_sysino, INTR_ENABLED);
887 	cbus_intr_setenabled(sc->sc_rx_sysino, INTR_ENABLED);
888 }
889 
890 void
891 vdsp_open(void *arg1, void *arg2)
892 {
893 	struct vdsp_softc *sc = arg1;
894 	struct proc *p = curproc;
895 	struct vd_attr_info ai;
896 
897 	if (sc->sc_vp == NULL) {
898 		struct nameidata nd;
899 		struct vattr va;
900 		const char *name;
901 		int error;
902 
903 		name = mdesc_get_prop_str(sc->sc_idx, "vds-block-device");
904 		if (name == NULL)
905 			return;
906 
907 		NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, name, p);
908 		error = vn_open(&nd, FREAD, 0);
909 		if (error) {
910 			printf("VOP_OPEN: %s, %d\n", name, error);
911 			return;
912 		}
913 
914 		error = VOP_GETATTR(nd.ni_vp, &va, p->p_ucred, p);
915 		if (error)
916 			printf("VOP_GETATTR: %s, %d\n", name, error);
917 		sc->sc_vdisk_block_size = DEV_BSIZE;
918 		sc->sc_vdisk_size = va.va_size / DEV_BSIZE;
919 
920 		VOP_UNLOCK(nd.ni_vp, 0, p);
921 		sc->sc_vp = nd.ni_vp;
922 
923 		vdsp_readlabel(sc);
924 	}
925 
926 	bzero(&ai, sizeof(ai));
927 	ai.tag.type = VIO_TYPE_CTRL;
928 	ai.tag.stype = VIO_SUBTYPE_ACK;
929 	ai.tag.stype_env = VIO_ATTR_INFO;
930 	ai.tag.sid = sc->sc_local_sid;
931 	ai.xfer_mode = sc->sc_xfer_mode;
932 	ai.vd_type = VD_DISK_TYPE_DISK;
933 	if (sc->sc_major > 1 || sc->sc_minor >= 1) {
934 		if (vdsp_is_iso(sc))
935 			ai.vd_mtype = VD_MEDIA_TYPE_CD;
936 		else
937 			ai.vd_mtype = VD_MEDIA_TYPE_FIXED;
938 	}
939 	ai.vdisk_block_size = sc->sc_vdisk_block_size;
940 	ai.operations = VD_OP_MASK;
941 	ai.vdisk_size = sc->sc_vdisk_size;
942 	ai.max_xfer_sz = MAXPHYS / sc->sc_vdisk_block_size;
943 	vdsp_sendmsg(sc, &ai, sizeof(ai));
944 }
945 
946 void
947 vdsp_readlabel(struct vdsp_softc *sc)
948 {
949 	struct proc *p = curproc;
950 	struct iovec iov;
951 	struct uio uio;
952 	int err;
953 
954 	if (sc->sc_vp == NULL)
955 		return;
956 
957 	sc->sc_label = malloc(sizeof(*sc->sc_label), M_DEVBUF, M_WAITOK);
958 
959 	iov.iov_base = sc->sc_label;
960 	iov.iov_len = sizeof(*sc->sc_label);
961 	uio.uio_iov = &iov;
962 	uio.uio_iovcnt = 1;
963 	uio.uio_offset = 0;
964 	uio.uio_resid = sizeof(*sc->sc_label);
965 	uio.uio_segflg = UIO_SYSSPACE;
966 	uio.uio_rw = UIO_READ;
967 	uio.uio_procp = p;
968 
969 	vn_lock(sc->sc_vp, LK_EXCLUSIVE | LK_RETRY, p);
970 	err = VOP_READ(sc->sc_vp, &uio, 0, p->p_ucred);
971 	VOP_UNLOCK(sc->sc_vp, 0, p);
972 	if (err) {
973 		free(sc->sc_label, M_DEVBUF);
974 		sc->sc_label = NULL;
975 	}
976 }
977 
978 int
979 vdsp_writelabel(struct vdsp_softc *sc)
980 {
981 	struct proc *p = curproc;
982 	struct iovec iov;
983 	struct uio uio;
984 	int err;
985 
986 	if (sc->sc_vp == NULL || sc->sc_label == NULL)
987 		return (EINVAL);
988 
989 	iov.iov_base = sc->sc_label;
990 	iov.iov_len = sizeof(*sc->sc_label);
991 	uio.uio_iov = &iov;
992 	uio.uio_iovcnt = 1;
993 	uio.uio_offset = 0;
994 	uio.uio_resid = sizeof(*sc->sc_label);
995 	uio.uio_segflg = UIO_SYSSPACE;
996 	uio.uio_rw = UIO_WRITE;
997 	uio.uio_procp = p;
998 
999 	vn_lock(sc->sc_vp, LK_EXCLUSIVE | LK_RETRY, p);
1000 	err = VOP_WRITE(sc->sc_vp, &uio, 0, p->p_ucred);
1001 	VOP_UNLOCK(sc->sc_vp, 0, p);
1002 
1003 	return (err);
1004 }
1005 
1006 int
1007 vdsp_is_iso(struct vdsp_softc *sc)
1008 {
1009 	struct proc *p = curproc;
1010 	struct iovec iov;
1011 	struct uio uio;
1012 	struct iso_volume_descriptor *vdp;
1013 	int err;
1014 
1015 	if (sc->sc_vp == NULL)
1016 		return (0);
1017 
1018 	vdp = malloc(sizeof(*vdp), M_DEVBUF, M_WAITOK);
1019 
1020 	iov.iov_base = vdp;
1021 	iov.iov_len = sizeof(*vdp);
1022 	uio.uio_iov = &iov;
1023 	uio.uio_iovcnt = 1;
1024 	uio.uio_offset = 16 * ISO_DEFAULT_BLOCK_SIZE;
1025 	uio.uio_resid = sizeof(*vdp);
1026 	uio.uio_segflg = UIO_SYSSPACE;
1027 	uio.uio_rw = UIO_READ;
1028 	uio.uio_procp = p;
1029 
1030 	vn_lock(sc->sc_vp, LK_EXCLUSIVE | LK_RETRY, p);
1031 	err = VOP_READ(sc->sc_vp, &uio, 0, p->p_ucred);
1032 	VOP_UNLOCK(sc->sc_vp, 0, p);
1033 
1034 	if (err == 0 && memcmp(vdp->id, ISO_STANDARD_ID, sizeof(vdp->id)))
1035 		err = ENOENT;
1036 
1037 	free(vdp, M_DEVBUF);
1038 	return (err == 0);
1039 }
1040 
1041 void
1042 vdsp_alloc(void *arg1, void *arg2)
1043 {
1044 	struct vdsp_softc *sc = arg1;
1045 	struct vio_dring_reg dr;
1046 
1047 	KASSERT(sc->sc_num_descriptors <= VDSK_MAX_DESCRIPTORS);
1048 	KASSERT(sc->sc_descriptor_size <= VDSK_MAX_DESCRIPTOR_SIZE);
1049 	sc->sc_vd = malloc(sc->sc_num_descriptors * sc->sc_descriptor_size,
1050 	    M_DEVBUF, M_WAITOK);
1051 
1052 	bzero(&dr, sizeof(dr));
1053 	dr.tag.type = VIO_TYPE_CTRL;
1054 	dr.tag.stype = VIO_SUBTYPE_ACK;
1055 	dr.tag.stype_env = VIO_DRING_REG;
1056 	dr.tag.sid = sc->sc_local_sid;
1057 	dr.dring_ident = ++sc->sc_dring_ident;
1058 	vdsp_sendmsg(sc, &dr, sizeof(dr));
1059 }
1060 
1061 void
1062 vdsp_read(void *arg1, void *arg2)
1063 {
1064 	struct vdsp_softc *sc = arg1;
1065 	struct ldc_conn *lc = &sc->sc_lc;
1066 	struct vdsk_desc_msg *dm = arg2;
1067 	struct proc *p = curproc;
1068 	struct iovec iov;
1069 	struct uio uio;
1070 	caddr_t buf;
1071 	vaddr_t va;
1072 	paddr_t pa;
1073 	uint64_t size, off;
1074 	psize_t nbytes;
1075 	int err, i;
1076 
1077 	if (sc->sc_vp == NULL)
1078 		return;
1079 
1080 	buf = malloc(dm->size, M_DEVBUF, M_WAITOK);
1081 
1082 	iov.iov_base = buf;
1083 	iov.iov_len = dm->size;
1084 	uio.uio_iov = &iov;
1085 	uio.uio_iovcnt = 1;
1086 	uio.uio_offset = dm->offset * DEV_BSIZE;
1087 	uio.uio_resid = dm->size;
1088 	uio.uio_segflg = UIO_SYSSPACE;
1089 	uio.uio_rw = UIO_READ;
1090 	uio.uio_procp = p;
1091 
1092 	vn_lock(sc->sc_vp, LK_EXCLUSIVE | LK_RETRY, p);
1093 	dm->status = VOP_READ(sc->sc_vp, &uio, 0, p->p_ucred);
1094 	VOP_UNLOCK(sc->sc_vp, 0, p);
1095 
1096 	if (dm->status == 0) {
1097 		i = 0;
1098 		va = (vaddr_t)buf;
1099 		size = dm->size;
1100 		off = 0;
1101 		while (size > 0 && i < dm->ncookies) {
1102 			pmap_extract(pmap_kernel(), va, &pa);
1103 			nbytes = min(size, dm->cookie[i].size - off);
1104 			nbytes = min(nbytes, PAGE_SIZE - (off & PAGE_MASK));
1105 			err = hv_ldc_copy(lc->lc_id, LDC_COPY_OUT,
1106 			    dm->cookie[i].addr + off, pa, nbytes, &nbytes);
1107 			if (err != H_EOK)
1108 				printf("%s: hv_ldc_copy: %d\n", __func__, err);
1109 			va += nbytes;
1110 			size -= nbytes;
1111 			off += nbytes;
1112 			if (off >= dm->cookie[i].size) {
1113 				off = 0;
1114 				i++;
1115 			}
1116 		}
1117 	}
1118 
1119 	free(buf, M_DEVBUF);
1120 
1121 	/* ACK the descriptor. */
1122 	dm->tag.stype = VIO_SUBTYPE_ACK;
1123 	dm->tag.sid = sc->sc_local_sid;
1124 	vdsp_sendmsg(sc, dm, sizeof(*dm) +
1125 	    (dm->ncookies - 1) * sizeof(struct ldc_cookie));
1126 }
1127 
1128 void
1129 vdsp_read_dring(void *arg1, void *arg2)
1130 {
1131 	struct vdsp_softc *sc = arg1;
1132 	struct ldc_conn *lc = &sc->sc_lc;
1133 	struct vd_desc *vd = arg2;
1134 	struct proc *p = curproc;
1135 	struct iovec iov;
1136 	struct uio uio;
1137 	caddr_t buf;
1138 	vaddr_t va;
1139 	paddr_t pa;
1140 	uint64_t size, off;
1141 	psize_t nbytes;
1142 	int err, i;
1143 
1144 	if (sc->sc_vp == NULL)
1145 		return;
1146 
1147 	buf = malloc(vd->size, M_DEVBUF, M_WAITOK);
1148 
1149 	iov.iov_base = buf;
1150 	iov.iov_len = vd->size;
1151 	uio.uio_iov = &iov;
1152 	uio.uio_iovcnt = 1;
1153 	uio.uio_offset = vd->offset * DEV_BSIZE;
1154 	uio.uio_resid = vd->size;
1155 	uio.uio_segflg = UIO_SYSSPACE;
1156 	uio.uio_rw = UIO_READ;
1157 	uio.uio_procp = p;
1158 
1159 	vn_lock(sc->sc_vp, LK_EXCLUSIVE | LK_RETRY, p);
1160 	vd->status = VOP_READ(sc->sc_vp, &uio, 0, p->p_ucred);
1161 	VOP_UNLOCK(sc->sc_vp, 0, p);
1162 
1163 	if (vd->status == 0) {
1164 		i = 0;
1165 		va = (vaddr_t)buf;
1166 		size = vd->size;
1167 		off = 0;
1168 		while (size > 0 && i < vd->ncookies) {
1169 			pmap_extract(pmap_kernel(), va, &pa);
1170 			nbytes = min(size, vd->cookie[i].size - off);
1171 			nbytes = min(nbytes, PAGE_SIZE - (off & PAGE_MASK));
1172 			err = hv_ldc_copy(lc->lc_id, LDC_COPY_OUT,
1173 			    vd->cookie[i].addr + off, pa, nbytes, &nbytes);
1174 			if (err != H_EOK)
1175 				printf("%s: hv_ldc_copy: %d\n", __func__, err);
1176 			va += nbytes;
1177 			size -= nbytes;
1178 			off += nbytes;
1179 			if (off >= vd->cookie[i].size) {
1180 				off = 0;
1181 				i++;
1182 			}
1183 		}
1184 	}
1185 
1186 	free(buf, M_DEVBUF);
1187 
1188 	/* ACK the descriptor. */
1189 	vd->hdr.dstate = VIO_DESC_DONE;
1190 	vdsp_ack_desc(sc, vd);
1191 }
1192 
1193 void
1194 vdsp_write_dring(void *arg1, void *arg2)
1195 {
1196 	struct vdsp_softc *sc = arg1;
1197 	struct ldc_conn *lc = &sc->sc_lc;
1198 	struct vd_desc *vd = arg2;
1199 	struct proc *p = curproc;
1200 	struct iovec iov;
1201 	struct uio uio;
1202 	caddr_t buf;
1203 	vaddr_t va;
1204 	paddr_t pa;
1205 	uint64_t size, off;
1206 	psize_t nbytes;
1207 	int err, i;
1208 
1209 	if (sc->sc_vp == NULL)
1210 		return;
1211 
1212 	buf = malloc(vd->size, M_DEVBUF, M_WAITOK);
1213 
1214 	i = 0;
1215 	va = (vaddr_t)buf;
1216 	size = vd->size;
1217 	off = 0;
1218 	while (size > 0 && i < vd->ncookies) {
1219 		pmap_extract(pmap_kernel(), va, &pa);
1220 		nbytes = min(size, vd->cookie[i].size - off);
1221 		nbytes = min(nbytes, PAGE_SIZE - (off & PAGE_MASK));
1222 		err = hv_ldc_copy(lc->lc_id, LDC_COPY_IN,
1223 		    vd->cookie[i].addr + off, pa, nbytes, &nbytes);
1224 		if (err != H_EOK)
1225 			printf("%s: hv_ldc_copy: %d\n", __func__, err);
1226 		va += nbytes;
1227 		size -= nbytes;
1228 		off += nbytes;
1229 		if (off >= vd->cookie[i].size) {
1230 			off = 0;
1231 			i++;
1232 		}
1233 	}
1234 
1235 	iov.iov_base = buf;
1236 	iov.iov_len = vd->size;
1237 	uio.uio_iov = &iov;
1238 	uio.uio_iovcnt = 1;
1239 	uio.uio_offset = vd->offset * DEV_BSIZE;
1240 	uio.uio_resid = vd->size;
1241 	uio.uio_segflg = UIO_SYSSPACE;
1242 	uio.uio_rw = UIO_WRITE;
1243 	uio.uio_procp = p;
1244 
1245 	vn_lock(sc->sc_vp, LK_EXCLUSIVE | LK_RETRY, p);
1246 	vd->status = VOP_WRITE(sc->sc_vp, &uio, 0, p->p_ucred);
1247 	VOP_UNLOCK(sc->sc_vp, 0, p);
1248 
1249 	free(buf, M_DEVBUF);
1250 
1251 	/* ACK the descriptor. */
1252 	vd->hdr.dstate = VIO_DESC_DONE;
1253 	vdsp_ack_desc(sc, vd);
1254 }
1255 
1256 void
1257 vdsp_flush_dring(void *arg1, void *arg2)
1258 {
1259 	struct vdsp_softc *sc = arg1;
1260 	struct vd_desc *vd = arg2;
1261 
1262 	if (sc->sc_vp == NULL)
1263 		return;
1264 
1265 	/* ACK the descriptor. */
1266 	vd->status = 0;
1267 	vd->hdr.dstate = VIO_DESC_DONE;
1268 	vdsp_ack_desc(sc, vd);
1269 }
1270 
1271 void
1272 vdsp_get_vtoc(void *arg1, void *arg2)
1273 {
1274 	struct vdsp_softc *sc = arg1;
1275 	struct ldc_conn *lc = &sc->sc_lc;
1276 	struct vd_desc *vd = arg2;
1277 	struct sun_vtoc_preamble *sl;
1278 	struct vd_vtoc *vt;
1279 	vaddr_t va;
1280 	paddr_t pa;
1281 	uint64_t size, off;
1282 	psize_t nbytes;
1283 	int err, i;
1284 
1285 	vt = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK | M_ZERO);
1286 
1287 	if (sc->sc_label == NULL)
1288 		vdsp_readlabel(sc);
1289 
1290 	if (sc->sc_label && sc->sc_label->sl_magic == SUN_DKMAGIC) {
1291 		sl = (struct sun_vtoc_preamble *)sc->sc_label;
1292 
1293 		memcpy(vt->ascii_label, sl->sl_text, sizeof(sl->sl_text));
1294 		memcpy(vt->volume_name, sl->sl_volume, sizeof(sl->sl_volume));
1295 		vt->sector_size = DEV_BSIZE;
1296 		vt->num_partitions = sl->sl_nparts;
1297 		for (i = 0; i < vt->num_partitions; i++) {
1298 			vt->partition[i].id_tag = sl->sl_part[i].spi_tag;
1299 			vt->partition[i].perm = sl->sl_part[i].spi_flag;
1300 			vt->partition[i].start =
1301 			    sc->sc_label->sl_part[i].sdkp_cyloffset *
1302 				sc->sc_label->sl_ntracks *
1303 				sc->sc_label->sl_nsectors;
1304 			vt->partition[i].nblocks =
1305 			    sc->sc_label->sl_part[i].sdkp_nsectors;
1306 		}
1307 	} else {
1308 		uint64_t disk_size;
1309 		int unit;
1310 
1311 		/* Human-readable disk size. */
1312 		disk_size = sc->sc_vdisk_size * sc->sc_vdisk_block_size;
1313 		disk_size >>= 10;
1314 		unit = 'K';
1315 		if (disk_size > (2 << 10)) {
1316 			disk_size >>= 10;
1317 			unit = 'M';
1318 		}
1319 		if (disk_size > (2 << 10)) {
1320 			disk_size >>= 10;
1321 			unit = 'G';
1322 		}
1323 
1324 		snprintf(vt->ascii_label, sizeof(vt->ascii_label),
1325 		    "OpenBSD-DiskImage-%lld%cB cyl %d alt %d hd %d sec %d",
1326 		    disk_size, unit, sc->sc_ncyl, sc->sc_acyl,
1327 		    sc->sc_nhead, sc->sc_nsect);
1328 		vt->sector_size = sc->sc_vdisk_block_size;
1329 		vt->num_partitions = 8;
1330 		vt->partition[2].id_tag = SPTAG_WHOLE_DISK;
1331 		vt->partition[2].nblocks =
1332 		    sc->sc_ncyl * sc->sc_nhead * sc->sc_nsect;
1333 	}
1334 
1335 	i = 0;
1336 	va = (vaddr_t)vt;
1337 	size = roundup(sizeof(*vt), 64);
1338 	off = 0;
1339 	while (size > 0 && i < vd->ncookies) {
1340 		pmap_extract(pmap_kernel(), va, &pa);
1341 		nbytes = min(size, vd->cookie[i].size - off);
1342 		nbytes = min(nbytes, PAGE_SIZE - (off & PAGE_MASK));
1343 		err = hv_ldc_copy(lc->lc_id, LDC_COPY_OUT,
1344 		    vd->cookie[i].addr + off, pa, nbytes, &nbytes);
1345 		if (err != H_EOK)
1346 			printf("%s: hv_ldc_copy: %d\n", __func__, err);
1347 		va += nbytes;
1348 		size -= nbytes;
1349 		off += nbytes;
1350 		if (off >= vd->cookie[i].size) {
1351 			off = 0;
1352 			i++;
1353 		}
1354 	}
1355 
1356 	free(vt, M_DEVBUF);
1357 
1358 	/* ACK the descriptor. */
1359 	vd->status = 0;
1360 	vd->hdr.dstate = VIO_DESC_DONE;
1361 	vdsp_ack_desc(sc, vd);
1362 }
1363 
1364 void
1365 vdsp_set_vtoc(void *arg1, void *arg2)
1366 {
1367 	struct vdsp_softc *sc = arg1;
1368 	struct ldc_conn *lc = &sc->sc_lc;
1369 	struct vd_desc *vd = arg2;
1370 	struct sun_vtoc_preamble *sl;
1371 	struct vd_vtoc *vt;
1372 	u_short cksum = 0, *sp1, *sp2;
1373 	vaddr_t va;
1374 	paddr_t pa;
1375 	uint64_t size, off;
1376 	psize_t nbytes;
1377 	int err, i;
1378 
1379 	vt = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK | M_ZERO);
1380 
1381 	i = 0;
1382 	va = (vaddr_t)vt;
1383 	size = sizeof(*vt);
1384 	off = 0;
1385 	while (size > 0 && i < vd->ncookies) {
1386 		pmap_extract(pmap_kernel(), va, &pa);
1387 		nbytes = min(size, vd->cookie[i].size - off);
1388 		nbytes = min(nbytes, PAGE_SIZE - (off & PAGE_MASK));
1389 		err = hv_ldc_copy(lc->lc_id, LDC_COPY_IN,
1390 		    vd->cookie[i].addr + off, pa, nbytes, &nbytes);
1391 		if (err != H_EOK)
1392 			printf("%s: hv_ldc_copy: %d\n", __func__, err);
1393 		va += nbytes;
1394 		size -= nbytes;
1395 		off += nbytes;
1396 		if (off >= vd->cookie[i].size) {
1397 			off = 0;
1398 			i++;
1399 		}
1400 	}
1401 
1402 	if (vt->num_partitions > nitems(sc->sc_label->sl_part)) {
1403 		vd->status = EINVAL;
1404 		goto fail;
1405 	}
1406 
1407 	if (sc->sc_label == NULL || sc->sc_label->sl_magic != SUN_DKMAGIC) {
1408 		sc->sc_label = malloc(sizeof(*sc->sc_label),
1409 		    M_DEVBUF, M_WAITOK | M_ZERO);
1410 
1411 		sc->sc_label->sl_ntracks = sc->sc_nhead;
1412 		sc->sc_label->sl_nsectors = sc->sc_nsect;
1413 		sc->sc_label->sl_ncylinders = sc->sc_ncyl;
1414 		sc->sc_label->sl_acylinders = sc->sc_acyl;
1415 		sc->sc_label->sl_pcylinders = sc->sc_ncyl + sc->sc_acyl;
1416 		sc->sc_label->sl_rpm = 3600;
1417 
1418 		sc->sc_label->sl_magic = SUN_DKMAGIC;
1419 	}
1420 
1421 	sl = (struct sun_vtoc_preamble *)sc->sc_label;
1422 	memcpy(sl->sl_text, vt->ascii_label, sizeof(sl->sl_text));
1423 	sl->sl_version = 0x01;
1424 	memcpy(sl->sl_volume, sl->sl_volume, sizeof(sl->sl_volume));
1425 	sl->sl_nparts = vt->num_partitions;
1426 	for (i = 0; i < vt->num_partitions; i++) {
1427 		sl->sl_part[i].spi_tag = vt->partition[i].id_tag;
1428 		sl->sl_part[i].spi_flag = vt->partition[i].perm;
1429 		sc->sc_label->sl_part[i].sdkp_cyloffset =
1430 		    vt->partition[i].start / (sc->sc_nhead * sc->sc_nsect);
1431 		sc->sc_label->sl_part[i].sdkp_nsectors =
1432 		    vt->partition[i].nblocks;
1433 	}
1434 	sl->sl_sanity = 0x600ddeee;
1435 
1436 	/* Compute the checksum. */
1437 	sp1 = (u_short *)sc->sc_label;
1438 	sp2 = (u_short *)(sc->sc_label + 1);
1439 	while (sp1 < sp2)
1440 		cksum ^= *sp1++;
1441 	sc->sc_label->sl_cksum = cksum;
1442 
1443 	vd->status = vdsp_writelabel(sc);
1444 
1445 fail:
1446 	free(vt, M_DEVBUF);
1447 
1448 	/* ACK the descriptor. */
1449 	vd->hdr.dstate = VIO_DESC_DONE;
1450 	vdsp_ack_desc(sc, vd);
1451 }
1452 
1453 void
1454 vdsp_get_diskgeom(void *arg1, void *arg2)
1455 {
1456 	struct vdsp_softc *sc = arg1;
1457 	struct ldc_conn *lc = &sc->sc_lc;
1458 	struct vd_desc *vd = arg2;
1459 	struct vd_diskgeom *vg;
1460 	vaddr_t va;
1461 	paddr_t pa;
1462 	uint64_t size, off;
1463 	psize_t nbytes;
1464 	int err, i;
1465 
1466 	vg = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK | M_ZERO);
1467 
1468 	if (sc->sc_label == NULL)
1469 		vdsp_readlabel(sc);
1470 
1471 	if (sc->sc_label && sc->sc_label->sl_magic == SUN_DKMAGIC) {
1472 		vg->ncyl = sc->sc_label->sl_ncylinders;
1473 		vg->acyl = sc->sc_label->sl_acylinders;
1474 		vg->nhead = sc->sc_label->sl_ntracks;
1475 		vg->nsect = sc->sc_label->sl_nsectors;
1476 		vg->intrlv = sc->sc_label->sl_interleave;
1477 		vg->apc = sc->sc_label->sl_sparespercyl;
1478 		vg->rpm = sc->sc_label->sl_rpm;
1479 		vg->pcyl = sc->sc_label->sl_pcylinders;
1480 	} else {
1481 		uint64_t disk_size, block_size;
1482 
1483 		disk_size = sc->sc_vdisk_size * sc->sc_vdisk_block_size;
1484 		block_size = sc->sc_vdisk_block_size;
1485 
1486 		if (disk_size >= 8L * 1024 * 1024 * 1024) {
1487 			vg->nhead = 96;
1488 			vg->nsect = 768;
1489 		} else if (disk_size >= 2 *1024 * 1024) {
1490 			vg->nhead = 1;
1491 			vg->nsect = 600;
1492 		} else {
1493 			vg->nhead = 1;
1494 			vg->nsect = 200;
1495 		}
1496 
1497 		vg->pcyl = disk_size / (block_size * vg->nhead * vg->nsect);
1498 		if (vg->pcyl == 0)
1499 			vg->pcyl = 1;
1500 		if (vg->pcyl > 2)
1501 			vg->acyl = 2;
1502 		vg->ncyl = vg->pcyl - vg->acyl;
1503 
1504 		vg->rpm = 3600;
1505 	}
1506 
1507 	sc->sc_ncyl = vg->ncyl;
1508 	sc->sc_acyl = vg->acyl;
1509 	sc->sc_nhead = vg->nhead;
1510 	sc->sc_nsect = vg->nsect;
1511 
1512 	i = 0;
1513 	va = (vaddr_t)vg;
1514 	size = roundup(sizeof(*vg), 64);
1515 	off = 0;
1516 	while (size > 0 && i < vd->ncookies) {
1517 		pmap_extract(pmap_kernel(), va, &pa);
1518 		nbytes = min(size, vd->cookie[i].size - off);
1519 		nbytes = min(nbytes, PAGE_SIZE - (off & PAGE_MASK));
1520 		err = hv_ldc_copy(lc->lc_id, LDC_COPY_OUT,
1521 		    vd->cookie[i].addr + off, pa, nbytes, &nbytes);
1522 		if (err != H_EOK)
1523 			printf("%s: hv_ldc_copy: %d\n", __func__, err);
1524 		va += nbytes;
1525 		size -= nbytes;
1526 		off += nbytes;
1527 		if (off >= vd->cookie[i].size) {
1528 			off = 0;
1529 			i++;
1530 		}
1531 	}
1532 
1533 	/* ACK the descriptor. */
1534 	vd->status = 0;
1535 	vd->hdr.dstate = VIO_DESC_DONE;
1536 	vdsp_ack_desc(sc, vd);
1537 }
1538 
1539 void
1540 vdsp_unimp(void *arg1, void *arg2)
1541 {
1542 	struct vdsp_softc *sc = arg1;
1543 	struct vd_desc *vd = arg2;
1544 
1545 	/* ACK the descriptor. */
1546 	vd->status = ENOTSUP;
1547 	vd->hdr.dstate = VIO_DESC_DONE;
1548 	vdsp_ack_desc(sc, vd);
1549 }
1550 
1551 void
1552 vdsp_ack_desc(struct vdsp_softc *sc, struct vd_desc *vd)
1553 {
1554 	struct vio_dring_msg dm;
1555 	vaddr_t va;
1556 	paddr_t pa;
1557 	uint64_t size, off;
1558 	psize_t nbytes;
1559 	int err;
1560 
1561 	va = (vaddr_t)vd;
1562 	off = (caddr_t)vd - sc->sc_vd;
1563 	size = sc->sc_descriptor_size;
1564 	while (size > 0) {
1565 		pmap_extract(pmap_kernel(), va, &pa);
1566 		nbytes = min(size, PAGE_SIZE - (off & PAGE_MASK));
1567 		err = hv_ldc_copy(sc->sc_lc.lc_id, LDC_COPY_OUT,
1568 		    sc->sc_dring_cookie.addr | off, pa, nbytes, &nbytes);
1569 		va += nbytes;
1570 		size -= nbytes;
1571 		off += nbytes;
1572 	}
1573 	if (err != H_EOK) {
1574 		printf("%s: hv_ldc_copy %d\n", __func__, err);
1575 		return;
1576 	}
1577 
1578 	/* ACK the descriptor. */
1579 	bzero(&dm, sizeof(dm));
1580 	dm.tag.type = VIO_TYPE_DATA;
1581 	dm.tag.stype = VIO_SUBTYPE_ACK;
1582 	dm.tag.stype_env = VIO_DRING_DATA;
1583 	dm.tag.sid = sc->sc_local_sid;
1584 	dm.seq_no = ++sc->sc_seq_no;
1585 	dm.dring_ident = sc->sc_dring_ident;
1586 	off = (caddr_t)vd - sc->sc_vd;
1587 	dm.start_idx = off / sc->sc_descriptor_size;
1588 	dm.end_idx = off / sc->sc_descriptor_size;
1589 	vdsp_sendmsg(sc, &dm, sizeof(dm));
1590 }
1591