xref: /openbsd-src/sys/arch/sparc64/dev/vdsp.c (revision eb7eaf8de3ff431d305450f61b441e5460c82246)
1*eb7eaf8dSmpi /*	$OpenBSD: vdsp.c,v 1.48 2021/10/24 17:05:04 mpi Exp $	*/
2c396b9d4Skettenis /*
3cd2d2b14Skettenis  * Copyright (c) 2009, 2011, 2014 Mark Kettenis
4c396b9d4Skettenis  *
5c396b9d4Skettenis  * Permission to use, copy, modify, and distribute this software for any
6c396b9d4Skettenis  * purpose with or without fee is hereby granted, provided that the above
7c396b9d4Skettenis  * copyright notice and this permission notice appear in all copies.
8c396b9d4Skettenis  *
9c396b9d4Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10c396b9d4Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11c396b9d4Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12c396b9d4Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13c396b9d4Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14c396b9d4Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15c396b9d4Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16c396b9d4Skettenis  */
17c396b9d4Skettenis 
18c396b9d4Skettenis #include <sys/param.h>
1946169cb9Skettenis #include <sys/conf.h>
203b7eaf03Sderaadt #include <sys/proc.h>
21c396b9d4Skettenis #include <sys/buf.h>
22c396b9d4Skettenis #include <sys/device.h>
23aa73aceeSkettenis #include <sys/disklabel.h>
24c396b9d4Skettenis #include <sys/fcntl.h>
25803de20fSmiod #include <sys/lock.h>
26c396b9d4Skettenis #include <sys/malloc.h>
2785350ca0Skettenis #include <sys/mutex.h>
28c396b9d4Skettenis #include <sys/namei.h>
29c396b9d4Skettenis #include <sys/systm.h>
307ee2c656Skettenis #include <sys/task.h>
31c396b9d4Skettenis #include <sys/vnode.h>
32a61c3679Skettenis #include <sys/dkio.h>
33a61c3679Skettenis #include <sys/specdev.h>
34c396b9d4Skettenis 
35c396b9d4Skettenis #include <machine/autoconf.h>
3646169cb9Skettenis #include <machine/conf.h>
37c396b9d4Skettenis #include <machine/hypervisor.h>
38c396b9d4Skettenis #include <machine/mdesc.h>
39c396b9d4Skettenis 
408716a13cSmpi #include <uvm/uvm_extern.h>
41c396b9d4Skettenis 
42c396b9d4Skettenis #include <scsi/scsi_all.h>
43c396b9d4Skettenis #include <scsi/scsi_disk.h>
44c396b9d4Skettenis #include <scsi/scsiconf.h>
45c396b9d4Skettenis 
46784607d3Skettenis #include <isofs/cd9660/iso.h>
47784607d3Skettenis 
48aa73aceeSkettenis #include <dev/sun/disklabel.h>
49aa73aceeSkettenis 
50c396b9d4Skettenis #include <sparc64/dev/cbusvar.h>
51c396b9d4Skettenis #include <sparc64/dev/ldcvar.h>
52c396b9d4Skettenis #include <sparc64/dev/viovar.h>
53c396b9d4Skettenis 
54c396b9d4Skettenis #ifdef VDSP_DEBUG
55c396b9d4Skettenis #define DPRINTF(x)	printf x
56c396b9d4Skettenis #else
57c396b9d4Skettenis #define DPRINTF(x)
58c396b9d4Skettenis #endif
59c396b9d4Skettenis 
60c396b9d4Skettenis #define VDSK_TX_ENTRIES			64
61c396b9d4Skettenis #define VDSK_RX_ENTRIES			64
62c396b9d4Skettenis 
63c396b9d4Skettenis #define VDSK_MAX_DESCRIPTORS		1024
649b09334aSkettenis #define VDSK_MAX_DESCRIPTOR_SIZE	512
65c396b9d4Skettenis 
66c396b9d4Skettenis struct vd_attr_info {
67c396b9d4Skettenis 	struct vio_msg_tag	tag;
68c396b9d4Skettenis 	uint8_t			xfer_mode;
69c396b9d4Skettenis 	uint8_t			vd_type;
70c396b9d4Skettenis 	uint8_t			vd_mtype;
71c396b9d4Skettenis 	uint8_t			_reserved1;
72c396b9d4Skettenis 	uint32_t		vdisk_block_size;
73c396b9d4Skettenis 	uint64_t		operations;
74c396b9d4Skettenis 	uint64_t		vdisk_size;
75c396b9d4Skettenis 	uint64_t		max_xfer_sz;
76c396b9d4Skettenis 	uint64_t		_reserved2[2];
77c396b9d4Skettenis };
78c396b9d4Skettenis 
79c396b9d4Skettenis #define VD_DISK_TYPE_SLICE	0x01
80c396b9d4Skettenis #define VD_DISK_TYPE_DISK	0x02
81c396b9d4Skettenis 
82c396b9d4Skettenis #define VD_MEDIA_TYPE_FIXED	0x01
83c396b9d4Skettenis #define VD_MEDIA_TYPE_CD	0x02
84c396b9d4Skettenis #define VD_MEDIA_TYPE_DVD	0x03
85c396b9d4Skettenis 
86c396b9d4Skettenis /* vDisk version 1.0. */
87c396b9d4Skettenis #define VD_OP_BREAD		0x01
88c396b9d4Skettenis #define VD_OP_BWRITE		0x02
89c396b9d4Skettenis #define VD_OP_FLUSH		0x03
90c396b9d4Skettenis #define VD_OP_GET_WCE		0x04
91c396b9d4Skettenis #define VD_OP_SET_WCE		0x05
92c396b9d4Skettenis #define VD_OP_GET_VTOC		0x06
93c396b9d4Skettenis #define VD_OP_SET_VTOC		0x07
94c396b9d4Skettenis #define VD_OP_GET_DISKGEOM	0x08
95c396b9d4Skettenis #define VD_OP_SET_DISKGEOM	0x09
96c396b9d4Skettenis #define VD_OP_GET_DEVID		0x0b
97c396b9d4Skettenis #define VD_OP_GET_EFI		0x0c
98c396b9d4Skettenis #define VD_OP_SET_EFI		0x0d
99c396b9d4Skettenis 
100c396b9d4Skettenis /* vDisk version 1.1 */
101c396b9d4Skettenis #define VD_OP_SCSICMD		0x0a
102c396b9d4Skettenis #define VD_OP_RESET		0x0e
103c396b9d4Skettenis #define VD_OP_GET_ACCESS	0x0f
104c396b9d4Skettenis #define VD_OP_SET_ACCESS	0x10
105c396b9d4Skettenis #define VD_OP_GET_CAPACITY	0x11
106c396b9d4Skettenis 
1070e924c63Skettenis /* Sun standard fields. */
1080e924c63Skettenis struct sun_vtoc_preamble {
1090e924c63Skettenis 	char	sl_text[128];
1100e924c63Skettenis 	u_int	sl_version;	/* label version */
1110e924c63Skettenis 	char	sl_volume[8];	/* short volume name */
1120e924c63Skettenis 	u_short	sl_nparts;	/* partition count */
1130e924c63Skettenis 
1140e924c63Skettenis 	struct sun_partinfo sl_part[8];
1150e924c63Skettenis 
1160e924c63Skettenis 	u_int	sl_bootinfo[3];
1170e924c63Skettenis 	u_int	sl_sanity;
1180e924c63Skettenis };
1190e924c63Skettenis 
120aa73aceeSkettenis struct vd_vtoc_part {
121aa73aceeSkettenis 	uint16_t	id_tag;
122aa73aceeSkettenis 	uint16_t	perm;
123aa73aceeSkettenis 	uint32_t	reserved;
124aa73aceeSkettenis 	uint64_t	start;
125aa73aceeSkettenis 	uint64_t	nblocks;
126aa73aceeSkettenis 
127aa73aceeSkettenis };
128aa73aceeSkettenis struct vd_vtoc {
129aa73aceeSkettenis 	uint8_t		volume_name[8];
130aa73aceeSkettenis 	uint16_t	sector_size;
131aa73aceeSkettenis 	uint16_t	num_partitions;
132aa73aceeSkettenis 	uint32_t	reserved;
133aa73aceeSkettenis 	uint8_t		ascii_label[128];
134aa73aceeSkettenis 	struct vd_vtoc_part partition[8];
135aa73aceeSkettenis };
136aa73aceeSkettenis 
137aa73aceeSkettenis struct vd_diskgeom {
138aa73aceeSkettenis 	uint16_t	ncyl;
139aa73aceeSkettenis 	uint16_t	acyl;
140aa73aceeSkettenis 	uint16_t	bcyl;
141aa73aceeSkettenis 	uint16_t	nhead;
142aa73aceeSkettenis 	uint16_t	nsect;
143aa73aceeSkettenis 	uint16_t	intrlv;
144aa73aceeSkettenis 	uint16_t	apc;
145aa73aceeSkettenis 	uint16_t	rpm;
146aa73aceeSkettenis 	uint16_t	pcyl;
147aa73aceeSkettenis 	uint16_t	write_reinstruct;
148aa73aceeSkettenis 	uint16_t	read_reinstruct;
149aa73aceeSkettenis };
150aa73aceeSkettenis 
151c396b9d4Skettenis struct vd_desc {
152c396b9d4Skettenis 	struct vio_dring_hdr	hdr;
153c396b9d4Skettenis 	uint64_t		req_id;
154c396b9d4Skettenis 	uint8_t			operation;
155c396b9d4Skettenis 	uint8_t			slice;
156c396b9d4Skettenis 	uint16_t		_reserved1;
157c396b9d4Skettenis 	uint32_t		status;
158c396b9d4Skettenis 	uint64_t		offset;
159c396b9d4Skettenis 	uint64_t		size;
160c396b9d4Skettenis 	uint32_t		ncookies;
161c396b9d4Skettenis 	uint32_t		_reserved2;
1629b09334aSkettenis 	struct ldc_cookie	cookie[1];
163c396b9d4Skettenis };
164c396b9d4Skettenis 
165c396b9d4Skettenis #define VD_SLICE_NONE		0xff
166c396b9d4Skettenis 
167c396b9d4Skettenis struct vdsk_desc_msg {
168c396b9d4Skettenis 	struct vio_msg_tag	tag;
169c396b9d4Skettenis 	uint64_t		seq_no;
170c396b9d4Skettenis 	uint64_t		desc_handle;
171c396b9d4Skettenis 	uint64_t		req_id;
172c396b9d4Skettenis 	uint8_t			operation;
173c396b9d4Skettenis 	uint8_t			slice;
174c396b9d4Skettenis 	uint16_t		_reserved1;
175c396b9d4Skettenis 	uint32_t		status;
176c396b9d4Skettenis 	uint64_t		offset;
177c396b9d4Skettenis 	uint64_t		size;
178c396b9d4Skettenis 	uint32_t		ncookies;
179c396b9d4Skettenis 	uint32_t		_reserved2;
180c396b9d4Skettenis 	struct ldc_cookie	cookie[1];
181c396b9d4Skettenis };
182c396b9d4Skettenis 
183c396b9d4Skettenis /*
1840e924c63Skettenis  * We support vDisk 1.1.
185c396b9d4Skettenis  */
186c396b9d4Skettenis #define VDSK_MAJOR	1
1870e924c63Skettenis #define VDSK_MINOR	1
188c396b9d4Skettenis 
1894334b178Skettenis /*
1900e924c63Skettenis  * But we only support a subset of the defined commands.
1914334b178Skettenis  */
1924334b178Skettenis #define VD_OP_MASK \
193aa73aceeSkettenis     ((1 << VD_OP_BREAD) | (1 << VD_OP_BWRITE) | (1 << VD_OP_FLUSH) | \
1948d2dc513Skettenis      (1 << VD_OP_GET_WCE) | (1 << VD_OP_SET_WCE) | \
1950e924c63Skettenis      (1 << VD_OP_GET_VTOC) | (1 << VD_OP_SET_VTOC) | \
1960e924c63Skettenis      (1 << VD_OP_GET_DISKGEOM))
1974334b178Skettenis 
198c396b9d4Skettenis struct vdsp_softc {
199c396b9d4Skettenis 	struct device	sc_dv;
200c396b9d4Skettenis 	int		sc_idx;
201c396b9d4Skettenis 	bus_space_tag_t	sc_bustag;
202c396b9d4Skettenis 	bus_dma_tag_t	sc_dmatag;
203c396b9d4Skettenis 
204b3a497edSkettenis 	uint64_t	sc_tx_ino;
205b3a497edSkettenis 	uint64_t	sc_rx_ino;
206c396b9d4Skettenis 	void		*sc_tx_ih;
207c396b9d4Skettenis 	void		*sc_rx_ih;
208c396b9d4Skettenis 
209c396b9d4Skettenis 	struct ldc_conn	sc_lc;
210c396b9d4Skettenis 
211c396b9d4Skettenis 	uint16_t	sc_vio_state;
212c396b9d4Skettenis #define VIO_SND_VER_INFO	0x0001
213c396b9d4Skettenis #define VIO_ACK_VER_INFO	0x0002
214c396b9d4Skettenis #define VIO_RCV_VER_INFO	0x0004
215c396b9d4Skettenis #define VIO_SND_ATTR_INFO	0x0008
216c396b9d4Skettenis #define VIO_ACK_ATTR_INFO	0x0010
217c396b9d4Skettenis #define VIO_RCV_ATTR_INFO	0x0020
218c396b9d4Skettenis #define VIO_SND_DRING_REG	0x0040
219c396b9d4Skettenis #define VIO_ACK_DRING_REG	0x0080
220c396b9d4Skettenis #define VIO_RCV_DRING_REG	0x0100
221c396b9d4Skettenis #define VIO_SND_RDX		0x0200
222c396b9d4Skettenis #define VIO_ACK_RDX		0x0400
223c396b9d4Skettenis #define VIO_RCV_RDX		0x0800
224c396b9d4Skettenis 
225c396b9d4Skettenis 	uint16_t	sc_major;
226c396b9d4Skettenis 	uint16_t	sc_minor;
227c396b9d4Skettenis 
228c396b9d4Skettenis 	uint8_t		sc_xfer_mode;
229c396b9d4Skettenis 
230c396b9d4Skettenis 	uint32_t	sc_local_sid;
231c396b9d4Skettenis 	uint64_t	sc_seq_no;
232c396b9d4Skettenis 
233c396b9d4Skettenis 	uint64_t	sc_dring_ident;
234c396b9d4Skettenis 	uint32_t	sc_num_descriptors;
235c396b9d4Skettenis 	uint32_t	sc_descriptor_size;
236c396b9d4Skettenis 	struct ldc_cookie sc_dring_cookie;
237c396b9d4Skettenis 
2387ee2c656Skettenis 	struct task	sc_open_task;
2397ee2c656Skettenis 	struct task	sc_alloc_task;
2407ee2c656Skettenis 	struct task	sc_close_task;
2417ee2c656Skettenis 
24285350ca0Skettenis 	struct mutex	sc_desc_mtx;
243cd2d2b14Skettenis 	struct vdsk_desc_msg *sc_desc_msg[VDSK_RX_ENTRIES];
244cd2d2b14Skettenis 	int		sc_desc_head;
245cd2d2b14Skettenis 	int		sc_desc_tail;
246cd2d2b14Skettenis 
247cd2d2b14Skettenis 	struct task	sc_read_task;
248cd2d2b14Skettenis 
2499b09334aSkettenis 	caddr_t		sc_vd;
250bef97659Sdlg 	struct task	sc_vd_task;
251bef97659Sdlg 	struct vd_desc	**sc_vd_ring;
252bef97659Sdlg 	u_int		sc_vd_prod;
253bef97659Sdlg 	u_int		sc_vd_cons;
254c396b9d4Skettenis 
255c396b9d4Skettenis 	uint32_t	sc_vdisk_block_size;
256c396b9d4Skettenis 	uint64_t	sc_vdisk_size;
257c396b9d4Skettenis 
258c396b9d4Skettenis 	struct vnode	*sc_vp;
259aa73aceeSkettenis 
260aa73aceeSkettenis 	struct sun_disklabel *sc_label;
2610e924c63Skettenis 	uint16_t	sc_ncyl;
2620e924c63Skettenis 	uint16_t	sc_acyl;
2630e924c63Skettenis 	uint16_t	sc_nhead;
2640e924c63Skettenis 	uint16_t	sc_nsect;
265c396b9d4Skettenis };
266c396b9d4Skettenis 
267c396b9d4Skettenis int	vdsp_match(struct device *, void *, void *);
268c396b9d4Skettenis void	vdsp_attach(struct device *, struct device *, void *);
269c396b9d4Skettenis 
270*eb7eaf8dSmpi const struct cfattach vdsp_ca = {
271c396b9d4Skettenis 	sizeof(struct vdsp_softc), vdsp_match, vdsp_attach
272c396b9d4Skettenis };
273c396b9d4Skettenis 
274c396b9d4Skettenis struct cfdriver vdsp_cd = {
275c396b9d4Skettenis 	NULL, "vdsp", DV_DULL
276c396b9d4Skettenis };
277c396b9d4Skettenis 
278c396b9d4Skettenis int	vdsp_tx_intr(void *);
279c396b9d4Skettenis int	vdsp_rx_intr(void *);
280c396b9d4Skettenis 
281c396b9d4Skettenis void	vdsp_rx_data(struct ldc_conn *, struct ldc_pkt *);
282c396b9d4Skettenis void	vdsp_rx_vio_ctrl(struct vdsp_softc *, struct vio_msg *);
283c396b9d4Skettenis void	vdsp_rx_vio_ver_info(struct vdsp_softc *, struct vio_msg_tag *);
284c396b9d4Skettenis void	vdsp_rx_vio_attr_info(struct vdsp_softc *, struct vio_msg_tag *);
285c396b9d4Skettenis void	vdsp_rx_vio_dring_reg(struct vdsp_softc *, struct vio_msg_tag *);
286c396b9d4Skettenis void	vdsp_rx_vio_rdx(struct vdsp_softc *sc, struct vio_msg_tag *);
287c396b9d4Skettenis void	vdsp_rx_vio_data(struct vdsp_softc *sc, struct vio_msg *);
288c396b9d4Skettenis void	vdsp_rx_vio_dring_data(struct vdsp_softc *sc,
289c396b9d4Skettenis 	    struct vio_msg_tag *);
290c396b9d4Skettenis void	vdsp_rx_vio_desc_data(struct vdsp_softc *sc, struct vio_msg_tag *);
291c396b9d4Skettenis 
292c396b9d4Skettenis void	vdsp_ldc_reset(struct ldc_conn *);
293c396b9d4Skettenis void	vdsp_ldc_start(struct ldc_conn *);
294c396b9d4Skettenis 
2956943088aSkettenis void	vdsp_sendmsg(struct vdsp_softc *, void *, size_t, int dowait);
296c396b9d4Skettenis 
297e4195480Sdlg void	vdsp_open(void *);
298e4195480Sdlg void	vdsp_close(void *);
299e4195480Sdlg void	vdsp_alloc(void *);
300aa73aceeSkettenis void	vdsp_readlabel(struct vdsp_softc *);
3010e924c63Skettenis int	vdsp_writelabel(struct vdsp_softc *);
302784607d3Skettenis int	vdsp_is_iso(struct vdsp_softc *);
303e4195480Sdlg void	vdsp_read(void *);
304cd2d2b14Skettenis void	vdsp_read_desc(struct vdsp_softc *, struct vdsk_desc_msg *);
305e4195480Sdlg void	vdsp_vd_task(void *);
306c396b9d4Skettenis void	vdsp_read_dring(void *, void *);
307c396b9d4Skettenis void	vdsp_write_dring(void *, void *);
308c396b9d4Skettenis void	vdsp_flush_dring(void *, void *);
309aa73aceeSkettenis void	vdsp_get_vtoc(void *, void *);
3100e924c63Skettenis void	vdsp_set_vtoc(void *, void *);
311aa73aceeSkettenis void	vdsp_get_diskgeom(void *, void *);
312aa73aceeSkettenis void	vdsp_unimp(void *, void *);
313aa73aceeSkettenis 
314aa73aceeSkettenis void	vdsp_ack_desc(struct vdsp_softc *, struct vd_desc *);
315c396b9d4Skettenis 
316c396b9d4Skettenis int
vdsp_match(struct device * parent,void * match,void * aux)317c396b9d4Skettenis vdsp_match(struct device *parent, void *match, void *aux)
318c396b9d4Skettenis {
319c396b9d4Skettenis 	struct cbus_attach_args *ca = aux;
320c396b9d4Skettenis 
321c396b9d4Skettenis 	if (strcmp(ca->ca_name, "vds-port") == 0)
322c396b9d4Skettenis 		return (1);
323c396b9d4Skettenis 
324c396b9d4Skettenis 	return (0);
325c396b9d4Skettenis }
326c396b9d4Skettenis 
327c396b9d4Skettenis void
vdsp_attach(struct device * parent,struct device * self,void * aux)328c396b9d4Skettenis vdsp_attach(struct device *parent, struct device *self, void *aux)
329c396b9d4Skettenis {
330c396b9d4Skettenis 	struct vdsp_softc *sc = (struct vdsp_softc *)self;
331c396b9d4Skettenis 	struct cbus_attach_args *ca = aux;
332c396b9d4Skettenis 	struct ldc_conn *lc;
333c396b9d4Skettenis 
334c396b9d4Skettenis 	sc->sc_idx = ca->ca_idx;
335c396b9d4Skettenis 	sc->sc_bustag = ca->ca_bustag;
336c396b9d4Skettenis 	sc->sc_dmatag = ca->ca_dmatag;
337b3a497edSkettenis 	sc->sc_tx_ino = ca->ca_tx_ino;
338b3a497edSkettenis 	sc->sc_rx_ino = ca->ca_rx_ino;
339c396b9d4Skettenis 
340b3a497edSkettenis 	printf(": ivec 0x%llx, 0x%llx", sc->sc_tx_ino, sc->sc_rx_ino);
341c396b9d4Skettenis 
34285350ca0Skettenis 	mtx_init(&sc->sc_desc_mtx, IPL_BIO);
34385350ca0Skettenis 
344c396b9d4Skettenis 	/*
345c396b9d4Skettenis 	 * Un-configure queues before registering interrupt handlers,
346c396b9d4Skettenis 	 * such that we dont get any stale LDC packets or events.
347c396b9d4Skettenis 	 */
348c396b9d4Skettenis 	hv_ldc_tx_qconf(ca->ca_id, 0, 0);
349c396b9d4Skettenis 	hv_ldc_rx_qconf(ca->ca_id, 0, 0);
350c396b9d4Skettenis 
351b3a497edSkettenis 	sc->sc_tx_ih = bus_intr_establish(ca->ca_bustag, sc->sc_tx_ino,
352ec03ab55Skettenis 	    IPL_BIO, BUS_INTR_ESTABLISH_MPSAFE, vdsp_tx_intr, sc,
353ec03ab55Skettenis 	    sc->sc_dv.dv_xname);
354b3a497edSkettenis 	sc->sc_rx_ih = bus_intr_establish(ca->ca_bustag, sc->sc_rx_ino,
355ec03ab55Skettenis 	    IPL_BIO, BUS_INTR_ESTABLISH_MPSAFE, vdsp_rx_intr, sc,
356ec03ab55Skettenis 	    sc->sc_dv.dv_xname);
357c396b9d4Skettenis 	if (sc->sc_tx_ih == NULL || sc->sc_rx_ih == NULL) {
358c396b9d4Skettenis 		printf(", can't establish interrupt\n");
359c396b9d4Skettenis 		return;
360c396b9d4Skettenis 	}
361c396b9d4Skettenis 
362c396b9d4Skettenis 	lc = &sc->sc_lc;
363c396b9d4Skettenis 	lc->lc_id = ca->ca_id;
364c396b9d4Skettenis 	lc->lc_sc = sc;
365c396b9d4Skettenis 	lc->lc_reset = vdsp_ldc_reset;
366c396b9d4Skettenis 	lc->lc_start = vdsp_ldc_start;
367c396b9d4Skettenis 	lc->lc_rx_data = vdsp_rx_data;
368c396b9d4Skettenis 
369c396b9d4Skettenis 	lc->lc_txq = ldc_queue_alloc(sc->sc_dmatag, VDSK_TX_ENTRIES);
370c396b9d4Skettenis 	if (lc->lc_txq == NULL) {
371c396b9d4Skettenis 		printf(", can't allocate tx queue\n");
372c396b9d4Skettenis 		return;
373c396b9d4Skettenis 	}
374c396b9d4Skettenis 
375c396b9d4Skettenis 	lc->lc_rxq = ldc_queue_alloc(sc->sc_dmatag, VDSK_RX_ENTRIES);
376c396b9d4Skettenis 	if (lc->lc_rxq == NULL) {
377c396b9d4Skettenis 		printf(", can't allocate rx queue\n");
378c396b9d4Skettenis 		goto free_txqueue;
379c396b9d4Skettenis 	}
380c396b9d4Skettenis 
381e4195480Sdlg 	task_set(&sc->sc_open_task, vdsp_open, sc);
382e4195480Sdlg 	task_set(&sc->sc_alloc_task, vdsp_alloc, sc);
383e4195480Sdlg 	task_set(&sc->sc_close_task, vdsp_close, sc);
384e4195480Sdlg 	task_set(&sc->sc_read_task, vdsp_read, sc);
3857ee2c656Skettenis 
386c396b9d4Skettenis 	printf("\n");
387c396b9d4Skettenis 
388c396b9d4Skettenis 	return;
389c396b9d4Skettenis 
390c396b9d4Skettenis #if 0
391c396b9d4Skettenis free_rxqueue:
392c396b9d4Skettenis 	ldc_queue_free(sc->sc_dmatag, lc->lc_rxq);
393c396b9d4Skettenis #endif
394c396b9d4Skettenis free_txqueue:
395c396b9d4Skettenis 	ldc_queue_free(sc->sc_dmatag, lc->lc_txq);
396c396b9d4Skettenis }
397c396b9d4Skettenis 
398c396b9d4Skettenis int
vdsp_tx_intr(void * arg)399c396b9d4Skettenis vdsp_tx_intr(void *arg)
400c396b9d4Skettenis {
401c396b9d4Skettenis 	struct vdsp_softc *sc = arg;
402c396b9d4Skettenis 	struct ldc_conn *lc = &sc->sc_lc;
403c396b9d4Skettenis 	uint64_t tx_head, tx_tail, tx_state;
4046943088aSkettenis 	int err;
405c396b9d4Skettenis 
40693cba3bbSkettenis 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
4076943088aSkettenis 	if (err != H_EOK) {
4086943088aSkettenis 		printf("hv_ldc_rx_get_state %d\n", err);
4096943088aSkettenis 		return (0);
4106943088aSkettenis 	}
4116943088aSkettenis 
412c396b9d4Skettenis 	if (tx_state != lc->lc_tx_state) {
413c396b9d4Skettenis 		switch (tx_state) {
414c396b9d4Skettenis 		case LDC_CHANNEL_DOWN:
4158f296756Sstsp 			DPRINTF(("%s: Tx link down\n", __func__));
416c396b9d4Skettenis 			break;
417c396b9d4Skettenis 		case LDC_CHANNEL_UP:
4188f296756Sstsp 			DPRINTF(("%s: Tx link up\n", __func__));
419c396b9d4Skettenis 			break;
420c396b9d4Skettenis 		case LDC_CHANNEL_RESET:
4218f296756Sstsp 			DPRINTF(("%s: Tx link reset\n", __func__));
422c396b9d4Skettenis 			break;
423c396b9d4Skettenis 		}
424c396b9d4Skettenis 		lc->lc_tx_state = tx_state;
425c396b9d4Skettenis 	}
426c396b9d4Skettenis 
4276943088aSkettenis 	wakeup(lc->lc_txq);
428c396b9d4Skettenis 	return (1);
429c396b9d4Skettenis }
430c396b9d4Skettenis 
431c396b9d4Skettenis int
vdsp_rx_intr(void * arg)432c396b9d4Skettenis vdsp_rx_intr(void *arg)
433c396b9d4Skettenis {
434c396b9d4Skettenis 	struct vdsp_softc *sc = arg;
435c396b9d4Skettenis 	struct ldc_conn *lc = &sc->sc_lc;
436c396b9d4Skettenis 	uint64_t rx_head, rx_tail, rx_state;
437c396b9d4Skettenis 	struct ldc_pkt *lp;
438c396b9d4Skettenis 	int err;
439c396b9d4Skettenis 
440c396b9d4Skettenis 	err = hv_ldc_rx_get_state(lc->lc_id, &rx_head, &rx_tail, &rx_state);
441c396b9d4Skettenis 	if (err == H_EINVAL)
442c396b9d4Skettenis 		return (0);
443c396b9d4Skettenis 	if (err != H_EOK) {
444c396b9d4Skettenis 		printf("hv_ldc_rx_get_state %d\n", err);
445c396b9d4Skettenis 		return (0);
446c396b9d4Skettenis 	}
447c396b9d4Skettenis 
448c396b9d4Skettenis 	if (rx_state != lc->lc_rx_state) {
449c396b9d4Skettenis 		switch (rx_state) {
450c396b9d4Skettenis 		case LDC_CHANNEL_DOWN:
4518f296756Sstsp 			DPRINTF(("%s: Rx link down\n", __func__));
452c396b9d4Skettenis 			lc->lc_tx_seqid = 0;
453c396b9d4Skettenis 			lc->lc_state = 0;
454c396b9d4Skettenis 			lc->lc_reset(lc);
455c396b9d4Skettenis 			break;
456c396b9d4Skettenis 		case LDC_CHANNEL_UP:
4578f296756Sstsp 			DPRINTF(("%s: Rx link up\n", __func__));
458c396b9d4Skettenis 			break;
459c396b9d4Skettenis 		case LDC_CHANNEL_RESET:
4608f296756Sstsp 			DPRINTF(("%s: Rx link reset\n", __func__));
461c396b9d4Skettenis 			lc->lc_tx_seqid = 0;
462c396b9d4Skettenis 			lc->lc_state = 0;
463c396b9d4Skettenis 			lc->lc_reset(lc);
464c396b9d4Skettenis 			break;
465c396b9d4Skettenis 		}
466c396b9d4Skettenis 		lc->lc_rx_state = rx_state;
467c396b9d4Skettenis 		return (1);
468c396b9d4Skettenis 	}
469c396b9d4Skettenis 
470c396b9d4Skettenis 	if (lc->lc_rx_state == LDC_CHANNEL_DOWN)
471c396b9d4Skettenis 		return (1);
472c396b9d4Skettenis 
473c396b9d4Skettenis 	lp = (struct ldc_pkt *)(lc->lc_rxq->lq_va + rx_head);
474c396b9d4Skettenis 	switch (lp->type) {
475c396b9d4Skettenis 	case LDC_CTRL:
476c396b9d4Skettenis 		ldc_rx_ctrl(lc, lp);
477c396b9d4Skettenis 		break;
478c396b9d4Skettenis 
479c396b9d4Skettenis 	case LDC_DATA:
480c396b9d4Skettenis 		ldc_rx_data(lc, lp);
481c396b9d4Skettenis 		break;
482c396b9d4Skettenis 
483c396b9d4Skettenis 	default:
484c396b9d4Skettenis 		DPRINTF(("0x%02x/0x%02x/0x%02x\n", lp->type, lp->stype,
485c396b9d4Skettenis 		    lp->ctrl));
486c396b9d4Skettenis 		ldc_reset(lc);
487c396b9d4Skettenis 		break;
488c396b9d4Skettenis 	}
489c396b9d4Skettenis 
490c396b9d4Skettenis 	rx_head += sizeof(*lp);
491c396b9d4Skettenis 	rx_head &= ((lc->lc_rxq->lq_nentries * sizeof(*lp)) - 1);
492c396b9d4Skettenis 	err = hv_ldc_rx_set_qhead(lc->lc_id, rx_head);
493c396b9d4Skettenis 	if (err != H_EOK)
494c396b9d4Skettenis 		printf("%s: hv_ldc_rx_set_qhead %d\n", __func__, err);
495c396b9d4Skettenis 
496c396b9d4Skettenis 	return (1);
497c396b9d4Skettenis }
498c396b9d4Skettenis 
499c396b9d4Skettenis void
vdsp_rx_data(struct ldc_conn * lc,struct ldc_pkt * lp)500c396b9d4Skettenis vdsp_rx_data(struct ldc_conn *lc, struct ldc_pkt *lp)
501c396b9d4Skettenis {
502c396b9d4Skettenis 	struct vio_msg *vm = (struct vio_msg *)lp;
503c396b9d4Skettenis 
504c396b9d4Skettenis 	switch (vm->type) {
505c396b9d4Skettenis 	case VIO_TYPE_CTRL:
506c396b9d4Skettenis 		if ((lp->env & LDC_FRAG_START) == 0 &&
507c396b9d4Skettenis 		    (lp->env & LDC_FRAG_STOP) == 0)
508c396b9d4Skettenis 			return;
509c396b9d4Skettenis 		vdsp_rx_vio_ctrl(lc->lc_sc, vm);
510c396b9d4Skettenis 		break;
511c396b9d4Skettenis 
512c396b9d4Skettenis 	case VIO_TYPE_DATA:
513c396b9d4Skettenis 		if((lp->env & LDC_FRAG_START) == 0)
514c396b9d4Skettenis 			return;
515c396b9d4Skettenis 		vdsp_rx_vio_data(lc->lc_sc, vm);
516c396b9d4Skettenis 		break;
517c396b9d4Skettenis 
518c396b9d4Skettenis 	default:
519c396b9d4Skettenis 		DPRINTF(("Unhandled packet type 0x%02x\n", vm->type));
520c396b9d4Skettenis 		ldc_reset(lc);
521c396b9d4Skettenis 		break;
522c396b9d4Skettenis 	}
523c396b9d4Skettenis }
524c396b9d4Skettenis 
525c396b9d4Skettenis void
vdsp_rx_vio_ctrl(struct vdsp_softc * sc,struct vio_msg * vm)526c396b9d4Skettenis vdsp_rx_vio_ctrl(struct vdsp_softc *sc, struct vio_msg *vm)
527c396b9d4Skettenis {
528c396b9d4Skettenis 	struct vio_msg_tag *tag = (struct vio_msg_tag *)&vm->type;
529c396b9d4Skettenis 
530c396b9d4Skettenis 	switch (tag->stype_env) {
531c396b9d4Skettenis 	case VIO_VER_INFO:
532c396b9d4Skettenis 		vdsp_rx_vio_ver_info(sc, tag);
533c396b9d4Skettenis 		break;
534c396b9d4Skettenis 	case VIO_ATTR_INFO:
535c396b9d4Skettenis 		vdsp_rx_vio_attr_info(sc, tag);
536c396b9d4Skettenis 		break;
537c396b9d4Skettenis 	case VIO_DRING_REG:
538c396b9d4Skettenis 		vdsp_rx_vio_dring_reg(sc, tag);
539c396b9d4Skettenis 		break;
540c396b9d4Skettenis 	case VIO_RDX:
541c396b9d4Skettenis 		vdsp_rx_vio_rdx(sc, tag);
542c396b9d4Skettenis 		break;
543c396b9d4Skettenis 	default:
544c396b9d4Skettenis 		DPRINTF(("CTRL/0x%02x/0x%04x\n", tag->stype, tag->stype_env));
545c396b9d4Skettenis 		break;
546c396b9d4Skettenis 	}
547c396b9d4Skettenis }
548c396b9d4Skettenis 
549c396b9d4Skettenis void
vdsp_rx_vio_ver_info(struct vdsp_softc * sc,struct vio_msg_tag * tag)550c396b9d4Skettenis vdsp_rx_vio_ver_info(struct vdsp_softc *sc, struct vio_msg_tag *tag)
551c396b9d4Skettenis {
552c396b9d4Skettenis 	struct vio_ver_info *vi = (struct vio_ver_info *)tag;
553c396b9d4Skettenis 
554c396b9d4Skettenis 	switch (vi->tag.stype) {
555c396b9d4Skettenis 	case VIO_SUBTYPE_INFO:
556c396b9d4Skettenis 		DPRINTF(("CTRL/INFO/VER_INFO\n"));
557c396b9d4Skettenis 
558c396b9d4Skettenis 		/* Make sure we're talking to a virtual disk. */
559c396b9d4Skettenis 		if (vi->dev_class != VDEV_DISK) {
560c396b9d4Skettenis 			/* Huh, we're not talking to a disk device? */
561c396b9d4Skettenis 			printf("%s: peer is not a disk device\n",
562c396b9d4Skettenis 			    sc->sc_dv.dv_xname);
563c396b9d4Skettenis 			vi->tag.stype = VIO_SUBTYPE_NACK;
564c396b9d4Skettenis 			vi->major = 0;
5656943088aSkettenis 			vdsp_sendmsg(sc, vi, sizeof(*vi), 0);
566c396b9d4Skettenis 			return;
567c396b9d4Skettenis 		}
568c396b9d4Skettenis 
569c396b9d4Skettenis 		if (vi->major != VDSK_MAJOR) {
570c396b9d4Skettenis 			vi->tag.stype = VIO_SUBTYPE_NACK;
571c396b9d4Skettenis 			vi->major = VDSK_MAJOR;
572c396b9d4Skettenis 			vi->minor = VDSK_MINOR;
5736943088aSkettenis 			vdsp_sendmsg(sc, vi, sizeof(*vi), 0);
574c396b9d4Skettenis 			return;
575c396b9d4Skettenis 		}
576c396b9d4Skettenis 
5770e924c63Skettenis 		sc->sc_major = vi->major;
5780e924c63Skettenis 		sc->sc_minor = vi->minor;
5794334b178Skettenis 		sc->sc_local_sid = vi->tag.sid;
5804334b178Skettenis 
581c396b9d4Skettenis 		vi->tag.stype = VIO_SUBTYPE_ACK;
5820e924c63Skettenis 		if (vi->minor > VDSK_MINOR)
583c396b9d4Skettenis 			vi->minor = VDSK_MINOR;
58415ac3531Skettenis 		vi->dev_class = VDEV_DISK_SERVER;
5856943088aSkettenis 		vdsp_sendmsg(sc, vi, sizeof(*vi), 0);
586c396b9d4Skettenis 		sc->sc_vio_state |= VIO_RCV_VER_INFO;
587c396b9d4Skettenis 		break;
588c396b9d4Skettenis 
589c396b9d4Skettenis 	case VIO_SUBTYPE_ACK:
590c396b9d4Skettenis 		DPRINTF(("CTRL/ACK/VER_INFO\n"));
591c396b9d4Skettenis 		break;
592c396b9d4Skettenis 
593c396b9d4Skettenis 	default:
594c396b9d4Skettenis 		DPRINTF(("CTRL/0x%02x/VER_INFO\n", vi->tag.stype));
595c396b9d4Skettenis 		break;
596c396b9d4Skettenis 	}
597c396b9d4Skettenis }
598c396b9d4Skettenis 
599c396b9d4Skettenis void
vdsp_rx_vio_attr_info(struct vdsp_softc * sc,struct vio_msg_tag * tag)600c396b9d4Skettenis vdsp_rx_vio_attr_info(struct vdsp_softc *sc, struct vio_msg_tag *tag)
601c396b9d4Skettenis {
602c396b9d4Skettenis 	struct vd_attr_info *ai = (struct vd_attr_info *)tag;
603c396b9d4Skettenis 
604c396b9d4Skettenis 	switch (ai->tag.stype) {
605c396b9d4Skettenis 	case VIO_SUBTYPE_INFO:
606c396b9d4Skettenis 		DPRINTF(("CTRL/INFO/ATTR_INFO\n"));
607c396b9d4Skettenis 
608c396b9d4Skettenis 		if (ai->xfer_mode != VIO_DESC_MODE &&
609c396b9d4Skettenis 		    ai->xfer_mode != VIO_DRING_MODE) {
610c396b9d4Skettenis 			printf("%s: peer uses unsupported xfer mode 0x%02x\n",
611c396b9d4Skettenis 			    sc->sc_dv.dv_xname, ai->xfer_mode);
612c396b9d4Skettenis 			ai->tag.stype = VIO_SUBTYPE_NACK;
6136943088aSkettenis 			vdsp_sendmsg(sc, ai, sizeof(*ai), 0);
614c396b9d4Skettenis 			return;
615c396b9d4Skettenis 		}
616c396b9d4Skettenis 		sc->sc_xfer_mode = ai->xfer_mode;
617c396b9d4Skettenis 		sc->sc_vio_state |= VIO_RCV_ATTR_INFO;
618c396b9d4Skettenis 
6197ee2c656Skettenis 		task_add(systq, &sc->sc_open_task);
620c396b9d4Skettenis 		break;
621c396b9d4Skettenis 
622c396b9d4Skettenis 	case VIO_SUBTYPE_ACK:
623c396b9d4Skettenis 		DPRINTF(("CTRL/ACK/ATTR_INFO\n"));
624c396b9d4Skettenis 		break;
625c396b9d4Skettenis 
626c396b9d4Skettenis 	default:
627c396b9d4Skettenis 		DPRINTF(("CTRL/0x%02x/ATTR_INFO\n", ai->tag.stype));
628c396b9d4Skettenis 		break;
629c396b9d4Skettenis 	}
630c396b9d4Skettenis }
631c396b9d4Skettenis 
632c396b9d4Skettenis void
vdsp_rx_vio_dring_reg(struct vdsp_softc * sc,struct vio_msg_tag * tag)633c396b9d4Skettenis vdsp_rx_vio_dring_reg(struct vdsp_softc *sc, struct vio_msg_tag *tag)
634c396b9d4Skettenis {
635c396b9d4Skettenis 	struct vio_dring_reg *dr = (struct vio_dring_reg *)tag;
636c396b9d4Skettenis 
637c396b9d4Skettenis 	switch (dr->tag.stype) {
638c396b9d4Skettenis 	case VIO_SUBTYPE_INFO:
639c396b9d4Skettenis 		DPRINTF(("CTRL/INFO/DRING_REG\n"));
640c396b9d4Skettenis 
641c396b9d4Skettenis 		if (dr->num_descriptors > VDSK_MAX_DESCRIPTORS ||
6429b09334aSkettenis 		    dr->descriptor_size > VDSK_MAX_DESCRIPTOR_SIZE ||
643c396b9d4Skettenis 		    dr->ncookies > 1) {
644c396b9d4Skettenis 			dr->tag.stype = VIO_SUBTYPE_NACK;
6456943088aSkettenis 			vdsp_sendmsg(sc, dr, sizeof(*dr), 0);
646c396b9d4Skettenis 			return;
647c396b9d4Skettenis 		}
648c396b9d4Skettenis 		sc->sc_num_descriptors = dr->num_descriptors;
649c396b9d4Skettenis 		sc->sc_descriptor_size = dr->descriptor_size;
650c396b9d4Skettenis 		sc->sc_dring_cookie = dr->cookie[0];
651c396b9d4Skettenis 		sc->sc_vio_state |= VIO_RCV_DRING_REG;
652c396b9d4Skettenis 
6537ee2c656Skettenis 		task_add(systq, &sc->sc_alloc_task);
654c396b9d4Skettenis 		break;
655c396b9d4Skettenis 
656c396b9d4Skettenis 	case VIO_SUBTYPE_ACK:
657c396b9d4Skettenis 		DPRINTF(("CTRL/ACK/DRING_REG\n"));
658c396b9d4Skettenis 		break;
659c396b9d4Skettenis 
660c396b9d4Skettenis 	default:
661c396b9d4Skettenis 		DPRINTF(("CTRL/0x%02x/DRING_REG\n", dr->tag.stype));
662c396b9d4Skettenis 		break;
663c396b9d4Skettenis 	}
664c396b9d4Skettenis }
665c396b9d4Skettenis 
666c396b9d4Skettenis void
vdsp_rx_vio_rdx(struct vdsp_softc * sc,struct vio_msg_tag * tag)667c396b9d4Skettenis vdsp_rx_vio_rdx(struct vdsp_softc *sc, struct vio_msg_tag *tag)
668c396b9d4Skettenis {
669c396b9d4Skettenis 	switch(tag->stype) {
670c396b9d4Skettenis 	case VIO_SUBTYPE_INFO:
671c396b9d4Skettenis 		DPRINTF(("CTRL/INFO/RDX\n"));
672c396b9d4Skettenis 
673c396b9d4Skettenis 		tag->stype = VIO_SUBTYPE_ACK;
674c396b9d4Skettenis 		tag->sid = sc->sc_local_sid;
6756943088aSkettenis 		vdsp_sendmsg(sc, tag, sizeof(*tag), 0);
676c396b9d4Skettenis 		sc->sc_vio_state |= VIO_RCV_RDX;
677c396b9d4Skettenis 		break;
678c396b9d4Skettenis 
679c396b9d4Skettenis 	case VIO_SUBTYPE_ACK:
680c396b9d4Skettenis 		DPRINTF(("CTRL/ACK/RDX\n"));
681c396b9d4Skettenis 		break;
682c396b9d4Skettenis 
683c396b9d4Skettenis 	default:
684c396b9d4Skettenis 		DPRINTF(("CTRL/0x%02x/RDX (VIO)\n", tag->stype));
685c396b9d4Skettenis 		break;
686c396b9d4Skettenis 	}
687c396b9d4Skettenis }
688c396b9d4Skettenis 
689c396b9d4Skettenis void
vdsp_rx_vio_data(struct vdsp_softc * sc,struct vio_msg * vm)690c396b9d4Skettenis vdsp_rx_vio_data(struct vdsp_softc *sc, struct vio_msg *vm)
691c396b9d4Skettenis {
692c396b9d4Skettenis 	struct vio_msg_tag *tag = (struct vio_msg_tag *)&vm->type;
693c396b9d4Skettenis 
694c396b9d4Skettenis 	if (!ISSET(sc->sc_vio_state, VIO_RCV_RDX)) {
695c396b9d4Skettenis 		DPRINTF(("Spurious DATA/0x%02x/0x%04x\n", tag->stype,
696c396b9d4Skettenis 		    tag->stype_env));
697c396b9d4Skettenis 		return;
698c396b9d4Skettenis 	}
699c396b9d4Skettenis 
700c396b9d4Skettenis 	switch(tag->stype_env) {
701c396b9d4Skettenis 	case VIO_DESC_DATA:
702c396b9d4Skettenis 		vdsp_rx_vio_desc_data(sc, tag);
703c396b9d4Skettenis 		break;
704c396b9d4Skettenis 
705c396b9d4Skettenis 	case VIO_DRING_DATA:
706c396b9d4Skettenis 		vdsp_rx_vio_dring_data(sc, tag);
707c396b9d4Skettenis 		break;
708c396b9d4Skettenis 
709c396b9d4Skettenis 	default:
710c396b9d4Skettenis 		DPRINTF(("DATA/0x%02x/0x%04x\n", tag->stype, tag->stype_env));
711c396b9d4Skettenis 		break;
712c396b9d4Skettenis 	}
713c396b9d4Skettenis }
714c396b9d4Skettenis 
715c396b9d4Skettenis void
vdsp_rx_vio_dring_data(struct vdsp_softc * sc,struct vio_msg_tag * tag)716c396b9d4Skettenis vdsp_rx_vio_dring_data(struct vdsp_softc *sc, struct vio_msg_tag *tag)
717c396b9d4Skettenis {
718c396b9d4Skettenis 	struct vio_dring_msg *dm = (struct vio_dring_msg *)tag;
719c396b9d4Skettenis 	struct vd_desc *vd;
720aa73aceeSkettenis 	vaddr_t va;
721aa73aceeSkettenis 	paddr_t pa;
722aa73aceeSkettenis 	uint64_t size, off;
723c396b9d4Skettenis 	psize_t nbytes;
724c396b9d4Skettenis 	int err;
725c396b9d4Skettenis 
726c396b9d4Skettenis 	switch(tag->stype) {
727c396b9d4Skettenis 	case VIO_SUBTYPE_INFO:
728c396b9d4Skettenis 		DPRINTF(("DATA/INFO/DRING_DATA\n"));
729c396b9d4Skettenis 
730c396b9d4Skettenis 		if (dm->dring_ident != sc->sc_dring_ident ||
731c396b9d4Skettenis 		    dm->start_idx >= sc->sc_num_descriptors) {
732c396b9d4Skettenis 			dm->tag.stype = VIO_SUBTYPE_NACK;
7336943088aSkettenis 			vdsp_sendmsg(sc, dm, sizeof(*dm), 0);
734c396b9d4Skettenis 			return;
735c396b9d4Skettenis 		}
736c396b9d4Skettenis 
737aa73aceeSkettenis 		off = dm->start_idx * sc->sc_descriptor_size;
738aa73aceeSkettenis 		vd = (struct vd_desc *)(sc->sc_vd + off);
739aa73aceeSkettenis 		va = (vaddr_t)vd;
740aa73aceeSkettenis 		size = sc->sc_descriptor_size;
741aa73aceeSkettenis 		while (size > 0) {
742aa73aceeSkettenis 			pmap_extract(pmap_kernel(), va, &pa);
7436467609bSkettenis 			nbytes = MIN(size, PAGE_SIZE - (off & PAGE_MASK));
744c396b9d4Skettenis 			err = hv_ldc_copy(sc->sc_lc.lc_id, LDC_COPY_IN,
745b04fbd6eSkettenis 			    sc->sc_dring_cookie.addr + off, pa,
746aa73aceeSkettenis 			    nbytes, &nbytes);
747c396b9d4Skettenis 			if (err != H_EOK) {
748aa73aceeSkettenis 				printf("%s: hv_ldc_copy %d\n", __func__, err);
749c396b9d4Skettenis 				return;
750c396b9d4Skettenis 			}
751b04fbd6eSkettenis 			va += nbytes;
752b04fbd6eSkettenis 			size -= nbytes;
753b04fbd6eSkettenis 			off += nbytes;
754b04fbd6eSkettenis 		}
755c396b9d4Skettenis 
756bef97659Sdlg 		sc->sc_vd_ring[sc->sc_vd_prod % sc->sc_num_descriptors] = vd;
757bef97659Sdlg 		membar_producer();
758bef97659Sdlg 		sc->sc_vd_prod++;
759bef97659Sdlg 		task_add(systq, &sc->sc_vd_task);
760bef97659Sdlg 
761c396b9d4Skettenis 		break;
762c396b9d4Skettenis 
763c396b9d4Skettenis 	case VIO_SUBTYPE_ACK:
764c396b9d4Skettenis 		DPRINTF(("DATA/ACK/DRING_DATA\n"));
765c396b9d4Skettenis 		break;
766c396b9d4Skettenis 
767c396b9d4Skettenis 	case VIO_SUBTYPE_NACK:
768c396b9d4Skettenis 		DPRINTF(("DATA/NACK/DRING_DATA\n"));
769c396b9d4Skettenis 		break;
770c396b9d4Skettenis 
771c396b9d4Skettenis 	default:
772c396b9d4Skettenis 		DPRINTF(("DATA/0x%02x/DRING_DATA\n", tag->stype));
773c396b9d4Skettenis 		break;
774c396b9d4Skettenis 	}
775c396b9d4Skettenis }
776c396b9d4Skettenis 
777c396b9d4Skettenis void
vdsp_vd_task(void * xsc)778e4195480Sdlg vdsp_vd_task(void *xsc)
779bef97659Sdlg {
780bef97659Sdlg 	struct vdsp_softc *sc = xsc;
781bef97659Sdlg 	struct vd_desc *vd;
782bef97659Sdlg 
783bef97659Sdlg 	while (sc->sc_vd_cons != sc->sc_vd_prod) {
784bef97659Sdlg 		membar_consumer();
785bef97659Sdlg 		vd = sc->sc_vd_ring[sc->sc_vd_cons++ % sc->sc_num_descriptors];
786bef97659Sdlg 
787bef97659Sdlg 		DPRINTF(("%s: operation %x\n", sc->sc_dv.dv_xname,
788bef97659Sdlg 		    vd->operation));
789bef97659Sdlg 		switch (vd->operation) {
790bef97659Sdlg 		case VD_OP_BREAD:
791bef97659Sdlg 			vdsp_read_dring(sc, vd);
792bef97659Sdlg 			break;
793bef97659Sdlg 		case VD_OP_BWRITE:
794bef97659Sdlg 			vdsp_write_dring(sc, vd);
795bef97659Sdlg 			break;
796bef97659Sdlg 		case VD_OP_FLUSH:
797bef97659Sdlg 			vdsp_flush_dring(sc, vd);
798bef97659Sdlg 			break;
799bef97659Sdlg 		case VD_OP_GET_VTOC:
800bef97659Sdlg 			vdsp_get_vtoc(sc, vd);
801bef97659Sdlg 			break;
802bef97659Sdlg 		case VD_OP_SET_VTOC:
803bef97659Sdlg 			vdsp_set_vtoc(sc, vd);
804bef97659Sdlg 			break;
805bef97659Sdlg 		case VD_OP_GET_DISKGEOM:
806bef97659Sdlg 			vdsp_get_diskgeom(sc, vd);
807bef97659Sdlg 			break;
808bef97659Sdlg 		case VD_OP_GET_WCE:
809bef97659Sdlg 		case VD_OP_SET_WCE:
810bef97659Sdlg 		case VD_OP_GET_DEVID:
811bef97659Sdlg 			/*
812bef97659Sdlg 			 * Solaris issues VD_OP_GET_DEVID despite the
813bef97659Sdlg 			 * fact that we don't advertise it.  It seems
814bef97659Sdlg 			 * to be able to handle failure just fine, so
815bef97659Sdlg 			 * we silently ignore it.
816bef97659Sdlg 			 */
817bef97659Sdlg 			vdsp_unimp(sc, vd);
818bef97659Sdlg 			break;
819bef97659Sdlg 		default:
820bef97659Sdlg 			printf("%s: unsupported operation 0x%02x\n",
821bef97659Sdlg 			    sc->sc_dv.dv_xname, vd->operation);
822bef97659Sdlg 			vdsp_unimp(sc, vd);
823bef97659Sdlg 			break;
824bef97659Sdlg 		}
825bef97659Sdlg 	}
826bef97659Sdlg }
827bef97659Sdlg 
828bef97659Sdlg void
vdsp_rx_vio_desc_data(struct vdsp_softc * sc,struct vio_msg_tag * tag)829c396b9d4Skettenis vdsp_rx_vio_desc_data(struct vdsp_softc *sc, struct vio_msg_tag *tag)
830c396b9d4Skettenis {
831c396b9d4Skettenis 	struct vdsk_desc_msg *dm = (struct vdsk_desc_msg *)tag;
832c396b9d4Skettenis 
833c396b9d4Skettenis 	switch(tag->stype) {
834c396b9d4Skettenis 	case VIO_SUBTYPE_INFO:
835c396b9d4Skettenis 		DPRINTF(("DATA/INFO/DESC_DATA\n"));
836c396b9d4Skettenis 
837c396b9d4Skettenis 		switch (dm->operation) {
838c396b9d4Skettenis 		case VD_OP_BREAD:
83985350ca0Skettenis 			mtx_enter(&sc->sc_desc_mtx);
840cd2d2b14Skettenis 			sc->sc_desc_msg[sc->sc_desc_head++] = dm;
841cd2d2b14Skettenis 			sc->sc_desc_head &= (VDSK_RX_ENTRIES - 1);
842cd2d2b14Skettenis 			KASSERT(sc->sc_desc_head != sc->sc_desc_tail);
84385350ca0Skettenis 			mtx_leave(&sc->sc_desc_mtx);
844cd2d2b14Skettenis 			task_add(systq, &sc->sc_read_task);
845c396b9d4Skettenis 			break;
846c396b9d4Skettenis 		default:
847c396b9d4Skettenis 			printf("%s: unsupported operation 0x%02x\n",
848c396b9d4Skettenis 			    sc->sc_dv.dv_xname, dm->operation);
849c396b9d4Skettenis 			break;
850c396b9d4Skettenis 		}
851c396b9d4Skettenis 		break;
852c396b9d4Skettenis 
853c396b9d4Skettenis 	case VIO_SUBTYPE_ACK:
854c396b9d4Skettenis 		DPRINTF(("DATA/ACK/DESC_DATA\n"));
855c396b9d4Skettenis 		break;
856c396b9d4Skettenis 
857c396b9d4Skettenis 	case VIO_SUBTYPE_NACK:
858c396b9d4Skettenis 		DPRINTF(("DATA/NACK/DESC_DATA\n"));
859c396b9d4Skettenis 		break;
860c396b9d4Skettenis 
861c396b9d4Skettenis 	default:
862c396b9d4Skettenis 		DPRINTF(("DATA/0x%02x/DESC_DATA\n", tag->stype));
863c396b9d4Skettenis 		break;
864c396b9d4Skettenis 	}
865c396b9d4Skettenis }
866c396b9d4Skettenis 
867c396b9d4Skettenis void
vdsp_ldc_reset(struct ldc_conn * lc)868c396b9d4Skettenis vdsp_ldc_reset(struct ldc_conn *lc)
869c396b9d4Skettenis {
870c396b9d4Skettenis 	struct vdsp_softc *sc = lc->lc_sc;
871c396b9d4Skettenis 
872c396b9d4Skettenis 	sc->sc_vio_state = 0;
8737ee2c656Skettenis 	task_add(systq, &sc->sc_close_task);
874c396b9d4Skettenis }
875c396b9d4Skettenis 
876c396b9d4Skettenis void
vdsp_ldc_start(struct ldc_conn * lc)877c396b9d4Skettenis vdsp_ldc_start(struct ldc_conn *lc)
878c396b9d4Skettenis {
879c396b9d4Skettenis 	/* The vDisk client is supposed to initiate the handshake. */
880c396b9d4Skettenis }
881c396b9d4Skettenis 
882c396b9d4Skettenis void
vdsp_sendmsg(struct vdsp_softc * sc,void * msg,size_t len,int dowait)8836943088aSkettenis vdsp_sendmsg(struct vdsp_softc *sc, void *msg, size_t len, int dowait)
884c396b9d4Skettenis {
885c396b9d4Skettenis 	struct ldc_conn *lc = &sc->sc_lc;
886c396b9d4Skettenis 	int err;
887c396b9d4Skettenis 
8886943088aSkettenis 	do {
8896943088aSkettenis 		err = ldc_send_unreliable(lc, msg, len);
8908b5ca3f9Skettenis 		if (dowait && err == EWOULDBLOCK) {
8916943088aSkettenis 			/*
8926943088aSkettenis 			 * Seems like the hypervisor doesn't actually
8936943088aSkettenis 			 * generate interrupts for transmit queues, so
8946943088aSkettenis 			 * we specify a timeout such that we don't
8956943088aSkettenis 			 * block forever.
8966943088aSkettenis 			 */
897cf102894Smpi 			err = tsleep_nsec(lc->lc_txq, PWAIT, "vdsp",
898cf102894Smpi 			    MSEC_TO_NSEC(10));
899c396b9d4Skettenis 		}
9006943088aSkettenis 	} while (dowait && err == EWOULDBLOCK);
901c396b9d4Skettenis }
902c396b9d4Skettenis 
903c396b9d4Skettenis void
vdsp_open(void * arg1)904e4195480Sdlg vdsp_open(void *arg1)
905c396b9d4Skettenis {
906c396b9d4Skettenis 	struct vdsp_softc *sc = arg1;
907c396b9d4Skettenis 	struct proc *p = curproc;
908c396b9d4Skettenis 	struct vd_attr_info ai;
909c396b9d4Skettenis 
910c396b9d4Skettenis 	if (sc->sc_vp == NULL) {
911c396b9d4Skettenis 		struct nameidata nd;
912c396b9d4Skettenis 		struct vattr va;
913a61c3679Skettenis 		struct partinfo pi;
914c396b9d4Skettenis 		const char *name;
915a61c3679Skettenis 		dev_t dev;
916c396b9d4Skettenis 		int error;
917c396b9d4Skettenis 
918c396b9d4Skettenis 		name = mdesc_get_prop_str(sc->sc_idx, "vds-block-device");
919c396b9d4Skettenis 		if (name == NULL)
920c396b9d4Skettenis 			return;
921c396b9d4Skettenis 
922c0626199Sbeck 		NDINIT(&nd, 0, 0, UIO_SYSSPACE, name, p);
92302fc192bSkettenis 		error = vn_open(&nd, FREAD | FWRITE, 0);
924c396b9d4Skettenis 		if (error) {
925c396b9d4Skettenis 			printf("VOP_OPEN: %s, %d\n", name, error);
926c396b9d4Skettenis 			return;
927c396b9d4Skettenis 		}
928c396b9d4Skettenis 
929a61c3679Skettenis 		if (nd.ni_vp->v_type == VBLK) {
930a61c3679Skettenis 			dev = nd.ni_vp->v_rdev;
931a61c3679Skettenis 			error = (*bdevsw[major(dev)].d_ioctl)(dev,
932a61c3679Skettenis 			    DIOCGPART, (caddr_t)&pi, FREAD, curproc);
933a61c3679Skettenis 			if (error)
934a61c3679Skettenis 				printf("DIOCGPART: %s, %d\n", name, error);
935a61c3679Skettenis 			sc->sc_vdisk_block_size = pi.disklab->d_secsize;
936a61c3679Skettenis 			sc->sc_vdisk_size = DL_GETPSIZE(pi.part);
937a61c3679Skettenis 		} else {
938c396b9d4Skettenis 			error = VOP_GETATTR(nd.ni_vp, &va, p->p_ucred, p);
939c396b9d4Skettenis 			if (error)
940c396b9d4Skettenis 				printf("VOP_GETATTR: %s, %d\n", name, error);
941c396b9d4Skettenis 			sc->sc_vdisk_block_size = DEV_BSIZE;
942c396b9d4Skettenis 			sc->sc_vdisk_size = va.va_size / DEV_BSIZE;
943a61c3679Skettenis 		}
944c396b9d4Skettenis 
94536bb23f1Svisa 		VOP_UNLOCK(nd.ni_vp);
946c396b9d4Skettenis 		sc->sc_vp = nd.ni_vp;
947aa73aceeSkettenis 
948aa73aceeSkettenis 		vdsp_readlabel(sc);
949c396b9d4Skettenis 	}
950c396b9d4Skettenis 
951c396b9d4Skettenis 	bzero(&ai, sizeof(ai));
952c396b9d4Skettenis 	ai.tag.type = VIO_TYPE_CTRL;
953c396b9d4Skettenis 	ai.tag.stype = VIO_SUBTYPE_ACK;
954c396b9d4Skettenis 	ai.tag.stype_env = VIO_ATTR_INFO;
955c396b9d4Skettenis 	ai.tag.sid = sc->sc_local_sid;
956c396b9d4Skettenis 	ai.xfer_mode = sc->sc_xfer_mode;
9574334b178Skettenis 	ai.vd_type = VD_DISK_TYPE_DISK;
958784607d3Skettenis 	if (sc->sc_major > 1 || sc->sc_minor >= 1) {
959784607d3Skettenis 		if (vdsp_is_iso(sc))
960784607d3Skettenis 			ai.vd_mtype = VD_MEDIA_TYPE_CD;
961784607d3Skettenis 		else
9620e924c63Skettenis 			ai.vd_mtype = VD_MEDIA_TYPE_FIXED;
963784607d3Skettenis 	}
964c396b9d4Skettenis 	ai.vdisk_block_size = sc->sc_vdisk_block_size;
9654334b178Skettenis 	ai.operations = VD_OP_MASK;
966c396b9d4Skettenis 	ai.vdisk_size = sc->sc_vdisk_size;
9674334b178Skettenis 	ai.max_xfer_sz = MAXPHYS / sc->sc_vdisk_block_size;
9686943088aSkettenis 	vdsp_sendmsg(sc, &ai, sizeof(ai), 1);
969c396b9d4Skettenis }
970c396b9d4Skettenis 
971c396b9d4Skettenis void
vdsp_close(void * arg1)972e4195480Sdlg vdsp_close(void *arg1)
97302fc192bSkettenis {
97402fc192bSkettenis 	struct vdsp_softc *sc = arg1;
97502fc192bSkettenis 	struct proc *p = curproc;
97602fc192bSkettenis 
977356a67c0Skettenis 	sc->sc_seq_no = 0;
978356a67c0Skettenis 
979356a67c0Skettenis 	free(sc->sc_vd, M_DEVBUF, 0);
980356a67c0Skettenis 	sc->sc_vd = NULL;
981bef97659Sdlg 	free(sc->sc_vd_ring, M_DEVBUF,
982bef97659Sdlg 	     sc->sc_num_descriptors * sizeof(*sc->sc_vd_ring));
983bef97659Sdlg 	sc->sc_vd_ring = NULL;
984356a67c0Skettenis 	free(sc->sc_label, M_DEVBUF, 0);
985356a67c0Skettenis 	sc->sc_label = NULL;
98602fc192bSkettenis 	if (sc->sc_vp) {
98702fc192bSkettenis 		vn_close(sc->sc_vp, FREAD | FWRITE, p->p_ucred, p);
98802fc192bSkettenis 		sc->sc_vp = NULL;
98902fc192bSkettenis 	}
99002fc192bSkettenis }
99102fc192bSkettenis 
99202fc192bSkettenis void
vdsp_readlabel(struct vdsp_softc * sc)993aa73aceeSkettenis vdsp_readlabel(struct vdsp_softc *sc)
994aa73aceeSkettenis {
995aa73aceeSkettenis 	struct proc *p = curproc;
996aa73aceeSkettenis 	struct iovec iov;
997aa73aceeSkettenis 	struct uio uio;
998aa73aceeSkettenis 	int err;
999aa73aceeSkettenis 
1000aa73aceeSkettenis 	if (sc->sc_vp == NULL)
1001aa73aceeSkettenis 		return;
1002aa73aceeSkettenis 
1003aa73aceeSkettenis 	sc->sc_label = malloc(sizeof(*sc->sc_label), M_DEVBUF, M_WAITOK);
1004aa73aceeSkettenis 
1005aa73aceeSkettenis 	iov.iov_base = sc->sc_label;
1006aa73aceeSkettenis 	iov.iov_len = sizeof(*sc->sc_label);
1007aa73aceeSkettenis 	uio.uio_iov = &iov;
1008aa73aceeSkettenis 	uio.uio_iovcnt = 1;
1009aa73aceeSkettenis 	uio.uio_offset = 0;
1010aa73aceeSkettenis 	uio.uio_resid = sizeof(*sc->sc_label);
1011aa73aceeSkettenis 	uio.uio_segflg = UIO_SYSSPACE;
1012aa73aceeSkettenis 	uio.uio_rw = UIO_READ;
1013aa73aceeSkettenis 	uio.uio_procp = p;
1014aa73aceeSkettenis 
10156e880534Svisa 	vn_lock(sc->sc_vp, LK_EXCLUSIVE | LK_RETRY);
1016aa73aceeSkettenis 	err = VOP_READ(sc->sc_vp, &uio, 0, p->p_ucred);
101736bb23f1Svisa 	VOP_UNLOCK(sc->sc_vp);
1018aa73aceeSkettenis 	if (err) {
1019f8e6c425Stedu 		free(sc->sc_label, M_DEVBUF, 0);
1020aa73aceeSkettenis 		sc->sc_label = NULL;
1021aa73aceeSkettenis 	}
1022aa73aceeSkettenis }
1023aa73aceeSkettenis 
10240e924c63Skettenis int
vdsp_writelabel(struct vdsp_softc * sc)10250e924c63Skettenis vdsp_writelabel(struct vdsp_softc *sc)
10260e924c63Skettenis {
10270e924c63Skettenis 	struct proc *p = curproc;
10280e924c63Skettenis 	struct iovec iov;
10290e924c63Skettenis 	struct uio uio;
10300e924c63Skettenis 	int err;
10310e924c63Skettenis 
10320e924c63Skettenis 	if (sc->sc_vp == NULL || sc->sc_label == NULL)
10330e924c63Skettenis 		return (EINVAL);
10340e924c63Skettenis 
10350e924c63Skettenis 	iov.iov_base = sc->sc_label;
10360e924c63Skettenis 	iov.iov_len = sizeof(*sc->sc_label);
10370e924c63Skettenis 	uio.uio_iov = &iov;
10380e924c63Skettenis 	uio.uio_iovcnt = 1;
10390e924c63Skettenis 	uio.uio_offset = 0;
10400e924c63Skettenis 	uio.uio_resid = sizeof(*sc->sc_label);
10410e924c63Skettenis 	uio.uio_segflg = UIO_SYSSPACE;
10420e924c63Skettenis 	uio.uio_rw = UIO_WRITE;
10430e924c63Skettenis 	uio.uio_procp = p;
10440e924c63Skettenis 
10456e880534Svisa 	vn_lock(sc->sc_vp, LK_EXCLUSIVE | LK_RETRY);
10460e924c63Skettenis 	err = VOP_WRITE(sc->sc_vp, &uio, 0, p->p_ucred);
104736bb23f1Svisa 	VOP_UNLOCK(sc->sc_vp);
10480e924c63Skettenis 
10490e924c63Skettenis 	return (err);
10500e924c63Skettenis }
10510e924c63Skettenis 
1052784607d3Skettenis int
vdsp_is_iso(struct vdsp_softc * sc)1053784607d3Skettenis vdsp_is_iso(struct vdsp_softc *sc)
1054784607d3Skettenis {
1055784607d3Skettenis 	struct proc *p = curproc;
1056784607d3Skettenis 	struct iovec iov;
1057784607d3Skettenis 	struct uio uio;
1058784607d3Skettenis 	struct iso_volume_descriptor *vdp;
1059784607d3Skettenis 	int err;
1060784607d3Skettenis 
1061784607d3Skettenis 	if (sc->sc_vp == NULL)
1062784607d3Skettenis 		return (0);
1063784607d3Skettenis 
1064784607d3Skettenis 	vdp = malloc(sizeof(*vdp), M_DEVBUF, M_WAITOK);
1065784607d3Skettenis 
1066784607d3Skettenis 	iov.iov_base = vdp;
1067784607d3Skettenis 	iov.iov_len = sizeof(*vdp);
1068784607d3Skettenis 	uio.uio_iov = &iov;
1069784607d3Skettenis 	uio.uio_iovcnt = 1;
1070784607d3Skettenis 	uio.uio_offset = 16 * ISO_DEFAULT_BLOCK_SIZE;
1071784607d3Skettenis 	uio.uio_resid = sizeof(*vdp);
1072784607d3Skettenis 	uio.uio_segflg = UIO_SYSSPACE;
1073784607d3Skettenis 	uio.uio_rw = UIO_READ;
1074784607d3Skettenis 	uio.uio_procp = p;
1075784607d3Skettenis 
10766e880534Svisa 	vn_lock(sc->sc_vp, LK_EXCLUSIVE | LK_RETRY);
1077784607d3Skettenis 	err = VOP_READ(sc->sc_vp, &uio, 0, p->p_ucred);
107836bb23f1Svisa 	VOP_UNLOCK(sc->sc_vp);
1079784607d3Skettenis 
1080784607d3Skettenis 	if (err == 0 && memcmp(vdp->id, ISO_STANDARD_ID, sizeof(vdp->id)))
1081784607d3Skettenis 		err = ENOENT;
1082784607d3Skettenis 
1083f8e6c425Stedu 	free(vdp, M_DEVBUF, 0);
1084784607d3Skettenis 	return (err == 0);
1085784607d3Skettenis }
1086784607d3Skettenis 
1087aa73aceeSkettenis void
vdsp_alloc(void * arg1)1088e4195480Sdlg vdsp_alloc(void *arg1)
1089c396b9d4Skettenis {
1090c396b9d4Skettenis 	struct vdsp_softc *sc = arg1;
1091c396b9d4Skettenis 	struct vio_dring_reg dr;
1092c396b9d4Skettenis 
10939b09334aSkettenis 	KASSERT(sc->sc_num_descriptors <= VDSK_MAX_DESCRIPTORS);
10949b09334aSkettenis 	KASSERT(sc->sc_descriptor_size <= VDSK_MAX_DESCRIPTOR_SIZE);
1095bef97659Sdlg 	sc->sc_vd = mallocarray(sc->sc_num_descriptors,
1096bef97659Sdlg 	    sc->sc_descriptor_size, M_DEVBUF, M_WAITOK);
1097bef97659Sdlg 	sc->sc_vd_ring = mallocarray(sc->sc_num_descriptors,
1098bef97659Sdlg 	    sizeof(*sc->sc_vd_ring), M_DEVBUF, M_WAITOK);
1099e4195480Sdlg 	task_set(&sc->sc_vd_task, vdsp_vd_task, sc);
1100c396b9d4Skettenis 
1101c396b9d4Skettenis 	bzero(&dr, sizeof(dr));
1102c396b9d4Skettenis 	dr.tag.type = VIO_TYPE_CTRL;
1103c396b9d4Skettenis 	dr.tag.stype = VIO_SUBTYPE_ACK;
1104c396b9d4Skettenis 	dr.tag.stype_env = VIO_DRING_REG;
1105c396b9d4Skettenis 	dr.tag.sid = sc->sc_local_sid;
1106c396b9d4Skettenis 	dr.dring_ident = ++sc->sc_dring_ident;
11076943088aSkettenis 	vdsp_sendmsg(sc, &dr, sizeof(dr), 1);
1108c396b9d4Skettenis }
1109c396b9d4Skettenis 
1110c396b9d4Skettenis void
vdsp_read(void * arg1)1111e4195480Sdlg vdsp_read(void *arg1)
1112c396b9d4Skettenis {
1113c396b9d4Skettenis 	struct vdsp_softc *sc = arg1;
1114cd2d2b14Skettenis 
111585350ca0Skettenis 	mtx_enter(&sc->sc_desc_mtx);
1116cd2d2b14Skettenis 	while (sc->sc_desc_tail != sc->sc_desc_head) {
111785350ca0Skettenis 		mtx_leave(&sc->sc_desc_mtx);
111885350ca0Skettenis 		vdsp_read_desc(sc, sc->sc_desc_msg[sc->sc_desc_tail]);
111985350ca0Skettenis 		mtx_enter(&sc->sc_desc_mtx);
112085350ca0Skettenis 		sc->sc_desc_tail++;
1121cd2d2b14Skettenis 		sc->sc_desc_tail &= (VDSK_RX_ENTRIES - 1);
1122cd2d2b14Skettenis 	}
112385350ca0Skettenis 	mtx_leave(&sc->sc_desc_mtx);
1124cd2d2b14Skettenis }
1125cd2d2b14Skettenis 
1126cd2d2b14Skettenis void
vdsp_read_desc(struct vdsp_softc * sc,struct vdsk_desc_msg * dm)1127cd2d2b14Skettenis vdsp_read_desc(struct vdsp_softc *sc, struct vdsk_desc_msg *dm)
1128cd2d2b14Skettenis {
1129c396b9d4Skettenis 	struct ldc_conn *lc = &sc->sc_lc;
1130c396b9d4Skettenis 	struct proc *p = curproc;
1131c396b9d4Skettenis 	struct iovec iov;
1132c396b9d4Skettenis 	struct uio uio;
1133c396b9d4Skettenis 	caddr_t buf;
1134c396b9d4Skettenis 	vaddr_t va;
1135c396b9d4Skettenis 	paddr_t pa;
1136c396b9d4Skettenis 	uint64_t size, off;
1137c396b9d4Skettenis 	psize_t nbytes;
1138c396b9d4Skettenis 	int err, i;
1139c396b9d4Skettenis 
1140c396b9d4Skettenis 	if (sc->sc_vp == NULL)
1141c396b9d4Skettenis 		return;
1142c396b9d4Skettenis 
1143c396b9d4Skettenis 	buf = malloc(dm->size, M_DEVBUF, M_WAITOK);
1144c396b9d4Skettenis 
1145c396b9d4Skettenis 	iov.iov_base = buf;
1146c396b9d4Skettenis 	iov.iov_len = dm->size;
1147c396b9d4Skettenis 	uio.uio_iov = &iov;
1148c396b9d4Skettenis 	uio.uio_iovcnt = 1;
1149c396b9d4Skettenis 	uio.uio_offset = dm->offset * DEV_BSIZE;
1150c396b9d4Skettenis 	uio.uio_resid = dm->size;
1151c396b9d4Skettenis 	uio.uio_segflg = UIO_SYSSPACE;
1152c396b9d4Skettenis 	uio.uio_rw = UIO_READ;
1153c396b9d4Skettenis 	uio.uio_procp = p;
1154c396b9d4Skettenis 
11556e880534Svisa 	vn_lock(sc->sc_vp, LK_EXCLUSIVE | LK_RETRY);
1156c396b9d4Skettenis 	dm->status = VOP_READ(sc->sc_vp, &uio, 0, p->p_ucred);
115736bb23f1Svisa 	VOP_UNLOCK(sc->sc_vp);
1158c396b9d4Skettenis 
1159b16def3cSkettenis 	KERNEL_UNLOCK();
1160c396b9d4Skettenis 	if (dm->status == 0) {
1161c396b9d4Skettenis 		i = 0;
1162c396b9d4Skettenis 		va = (vaddr_t)buf;
1163c396b9d4Skettenis 		size = dm->size;
1164c396b9d4Skettenis 		off = 0;
1165c396b9d4Skettenis 		while (size > 0 && i < dm->ncookies) {
1166c396b9d4Skettenis 			pmap_extract(pmap_kernel(), va, &pa);
11676467609bSkettenis 			nbytes = MIN(size, dm->cookie[i].size - off);
11686467609bSkettenis 			nbytes = MIN(nbytes, PAGE_SIZE - (off & PAGE_MASK));
1169c396b9d4Skettenis 			err = hv_ldc_copy(lc->lc_id, LDC_COPY_OUT,
1170c396b9d4Skettenis 			    dm->cookie[i].addr + off, pa, nbytes, &nbytes);
11716633ec97Skettenis 			if (err != H_EOK) {
1172aa73aceeSkettenis 				printf("%s: hv_ldc_copy: %d\n", __func__, err);
117324dcbee2Skettenis 				dm->status = EIO;
1174b16def3cSkettenis 				KERNEL_LOCK();
117524dcbee2Skettenis 				goto fail;
11766633ec97Skettenis 			}
1177c396b9d4Skettenis 			va += nbytes;
1178c396b9d4Skettenis 			size -= nbytes;
1179c396b9d4Skettenis 			off += nbytes;
1180c396b9d4Skettenis 			if (off >= dm->cookie[i].size) {
1181c396b9d4Skettenis 				off = 0;
1182c396b9d4Skettenis 				i++;
1183c396b9d4Skettenis 			}
1184c396b9d4Skettenis 		}
1185c396b9d4Skettenis 	}
1186b16def3cSkettenis 	KERNEL_LOCK();
1187c396b9d4Skettenis 
118824dcbee2Skettenis fail:
1189f8e6c425Stedu 	free(buf, M_DEVBUF, 0);
1190c396b9d4Skettenis 
1191c396b9d4Skettenis 	/* ACK the descriptor. */
1192c396b9d4Skettenis 	dm->tag.stype = VIO_SUBTYPE_ACK;
1193c396b9d4Skettenis 	dm->tag.sid = sc->sc_local_sid;
1194c396b9d4Skettenis 	vdsp_sendmsg(sc, dm, sizeof(*dm) +
11956943088aSkettenis 	    (dm->ncookies - 1) * sizeof(struct ldc_cookie), 1);
1196c396b9d4Skettenis }
1197c396b9d4Skettenis 
1198c396b9d4Skettenis void
vdsp_read_dring(void * arg1,void * arg2)1199c396b9d4Skettenis vdsp_read_dring(void *arg1, void *arg2)
1200c396b9d4Skettenis {
1201c396b9d4Skettenis 	struct vdsp_softc *sc = arg1;
1202c396b9d4Skettenis 	struct ldc_conn *lc = &sc->sc_lc;
1203c396b9d4Skettenis 	struct vd_desc *vd = arg2;
1204c396b9d4Skettenis 	struct proc *p = curproc;
1205c396b9d4Skettenis 	struct iovec iov;
1206c396b9d4Skettenis 	struct uio uio;
1207c396b9d4Skettenis 	caddr_t buf;
1208c396b9d4Skettenis 	vaddr_t va;
1209aa73aceeSkettenis 	paddr_t pa;
1210c396b9d4Skettenis 	uint64_t size, off;
1211c396b9d4Skettenis 	psize_t nbytes;
1212c396b9d4Skettenis 	int err, i;
1213c396b9d4Skettenis 
1214c396b9d4Skettenis 	if (sc->sc_vp == NULL)
1215c396b9d4Skettenis 		return;
1216c396b9d4Skettenis 
1217c396b9d4Skettenis 	buf = malloc(vd->size, M_DEVBUF, M_WAITOK);
1218c396b9d4Skettenis 
1219c396b9d4Skettenis 	iov.iov_base = buf;
1220c396b9d4Skettenis 	iov.iov_len = vd->size;
1221c396b9d4Skettenis 	uio.uio_iov = &iov;
1222c396b9d4Skettenis 	uio.uio_iovcnt = 1;
1223c396b9d4Skettenis 	uio.uio_offset = vd->offset * DEV_BSIZE;
1224c396b9d4Skettenis 	uio.uio_resid = vd->size;
1225c396b9d4Skettenis 	uio.uio_segflg = UIO_SYSSPACE;
1226c396b9d4Skettenis 	uio.uio_rw = UIO_READ;
1227c396b9d4Skettenis 	uio.uio_procp = p;
1228c396b9d4Skettenis 
12296e880534Svisa 	vn_lock(sc->sc_vp, LK_EXCLUSIVE | LK_RETRY);
1230c396b9d4Skettenis 	vd->status = VOP_READ(sc->sc_vp, &uio, 0, p->p_ucred);
123136bb23f1Svisa 	VOP_UNLOCK(sc->sc_vp);
1232c396b9d4Skettenis 
1233b16def3cSkettenis 	KERNEL_UNLOCK();
1234c396b9d4Skettenis 	if (vd->status == 0) {
1235c396b9d4Skettenis 		i = 0;
1236c396b9d4Skettenis 		va = (vaddr_t)buf;
1237c396b9d4Skettenis 		size = vd->size;
1238c396b9d4Skettenis 		off = 0;
1239c396b9d4Skettenis 		while (size > 0 && i < vd->ncookies) {
1240c396b9d4Skettenis 			pmap_extract(pmap_kernel(), va, &pa);
12416467609bSkettenis 			nbytes = MIN(size, vd->cookie[i].size - off);
12426467609bSkettenis 			nbytes = MIN(nbytes, PAGE_SIZE - (off & PAGE_MASK));
1243c396b9d4Skettenis 			err = hv_ldc_copy(lc->lc_id, LDC_COPY_OUT,
1244c396b9d4Skettenis 			    vd->cookie[i].addr + off, pa, nbytes, &nbytes);
12456633ec97Skettenis 			if (err != H_EOK) {
1246aa73aceeSkettenis 				printf("%s: hv_ldc_copy: %d\n", __func__, err);
124724dcbee2Skettenis 				vd->status = EIO;
1248b16def3cSkettenis 				KERNEL_LOCK();
124924dcbee2Skettenis 				goto fail;
12506633ec97Skettenis 			}
1251c396b9d4Skettenis 			va += nbytes;
1252c396b9d4Skettenis 			size -= nbytes;
1253c396b9d4Skettenis 			off += nbytes;
1254c396b9d4Skettenis 			if (off >= vd->cookie[i].size) {
1255c396b9d4Skettenis 				off = 0;
1256c396b9d4Skettenis 				i++;
1257c396b9d4Skettenis 			}
1258c396b9d4Skettenis 		}
1259c396b9d4Skettenis 	}
1260b16def3cSkettenis 	KERNEL_LOCK();
1261c396b9d4Skettenis 
126224dcbee2Skettenis fail:
1263f8e6c425Stedu 	free(buf, M_DEVBUF, 0);
1264c396b9d4Skettenis 
1265c396b9d4Skettenis 	/* ACK the descriptor. */
1266aa73aceeSkettenis 	vd->hdr.dstate = VIO_DESC_DONE;
1267aa73aceeSkettenis 	vdsp_ack_desc(sc, vd);
1268c396b9d4Skettenis }
1269c396b9d4Skettenis 
1270c396b9d4Skettenis void
vdsp_write_dring(void * arg1,void * arg2)1271c396b9d4Skettenis vdsp_write_dring(void *arg1, void *arg2)
1272c396b9d4Skettenis {
1273c396b9d4Skettenis 	struct vdsp_softc *sc = arg1;
1274c396b9d4Skettenis 	struct ldc_conn *lc = &sc->sc_lc;
1275c396b9d4Skettenis 	struct vd_desc *vd = arg2;
1276c396b9d4Skettenis 	struct proc *p = curproc;
1277c396b9d4Skettenis 	struct iovec iov;
1278c396b9d4Skettenis 	struct uio uio;
1279c396b9d4Skettenis 	caddr_t buf;
1280c396b9d4Skettenis 	vaddr_t va;
1281aa73aceeSkettenis 	paddr_t pa;
1282c396b9d4Skettenis 	uint64_t size, off;
1283c396b9d4Skettenis 	psize_t nbytes;
1284c396b9d4Skettenis 	int err, i;
1285c396b9d4Skettenis 
1286c396b9d4Skettenis 	if (sc->sc_vp == NULL)
1287c396b9d4Skettenis 		return;
1288c396b9d4Skettenis 
1289c396b9d4Skettenis 	buf = malloc(vd->size, M_DEVBUF, M_WAITOK);
1290c396b9d4Skettenis 
1291b16def3cSkettenis 	KERNEL_UNLOCK();
1292c396b9d4Skettenis 	i = 0;
1293c396b9d4Skettenis 	va = (vaddr_t)buf;
1294c396b9d4Skettenis 	size = vd->size;
1295c396b9d4Skettenis 	off = 0;
1296c396b9d4Skettenis 	while (size > 0 && i < vd->ncookies) {
1297c396b9d4Skettenis 		pmap_extract(pmap_kernel(), va, &pa);
12986467609bSkettenis 		nbytes = MIN(size, vd->cookie[i].size - off);
12996467609bSkettenis 		nbytes = MIN(nbytes, PAGE_SIZE - (off & PAGE_MASK));
1300c396b9d4Skettenis 		err = hv_ldc_copy(lc->lc_id, LDC_COPY_IN,
1301c396b9d4Skettenis 		    vd->cookie[i].addr + off, pa, nbytes, &nbytes);
13026633ec97Skettenis 		if (err != H_EOK) {
1303aa73aceeSkettenis 			printf("%s: hv_ldc_copy: %d\n", __func__, err);
130424dcbee2Skettenis 			vd->status = EIO;
1305b16def3cSkettenis 			KERNEL_LOCK();
130624dcbee2Skettenis 			goto fail;
13076633ec97Skettenis 		}
1308c396b9d4Skettenis 		va += nbytes;
1309c396b9d4Skettenis 		size -= nbytes;
1310c396b9d4Skettenis 		off += nbytes;
1311c396b9d4Skettenis 		if (off >= vd->cookie[i].size) {
1312c396b9d4Skettenis 			off = 0;
1313c396b9d4Skettenis 			i++;
1314c396b9d4Skettenis 		}
1315c396b9d4Skettenis 	}
1316b16def3cSkettenis 	KERNEL_LOCK();
1317c396b9d4Skettenis 
1318c396b9d4Skettenis 	iov.iov_base = buf;
1319c396b9d4Skettenis 	iov.iov_len = vd->size;
1320c396b9d4Skettenis 	uio.uio_iov = &iov;
1321c396b9d4Skettenis 	uio.uio_iovcnt = 1;
1322c396b9d4Skettenis 	uio.uio_offset = vd->offset * DEV_BSIZE;
1323c396b9d4Skettenis 	uio.uio_resid = vd->size;
1324c396b9d4Skettenis 	uio.uio_segflg = UIO_SYSSPACE;
1325c396b9d4Skettenis 	uio.uio_rw = UIO_WRITE;
1326c396b9d4Skettenis 	uio.uio_procp = p;
1327c396b9d4Skettenis 
13286e880534Svisa 	vn_lock(sc->sc_vp, LK_EXCLUSIVE | LK_RETRY);
1329c396b9d4Skettenis 	vd->status = VOP_WRITE(sc->sc_vp, &uio, 0, p->p_ucred);
133036bb23f1Svisa 	VOP_UNLOCK(sc->sc_vp);
1331c396b9d4Skettenis 
133224dcbee2Skettenis fail:
1333f8e6c425Stedu 	free(buf, M_DEVBUF, 0);
1334c396b9d4Skettenis 
1335c396b9d4Skettenis 	/* ACK the descriptor. */
1336aa73aceeSkettenis 	vd->hdr.dstate = VIO_DESC_DONE;
1337aa73aceeSkettenis 	vdsp_ack_desc(sc, vd);
1338c396b9d4Skettenis }
1339c396b9d4Skettenis 
1340c396b9d4Skettenis void
vdsp_flush_dring(void * arg1,void * arg2)1341c396b9d4Skettenis vdsp_flush_dring(void *arg1, void *arg2)
1342c396b9d4Skettenis {
1343c396b9d4Skettenis 	struct vdsp_softc *sc = arg1;
1344c396b9d4Skettenis 	struct vd_desc *vd = arg2;
1345c396b9d4Skettenis 
1346c396b9d4Skettenis 	if (sc->sc_vp == NULL)
1347c396b9d4Skettenis 		return;
1348c396b9d4Skettenis 
1349aa73aceeSkettenis 	/* ACK the descriptor. */
1350c396b9d4Skettenis 	vd->status = 0;
1351c396b9d4Skettenis 	vd->hdr.dstate = VIO_DESC_DONE;
1352aa73aceeSkettenis 	vdsp_ack_desc(sc, vd);
13539b09334aSkettenis }
13549b09334aSkettenis 
13559b09334aSkettenis void
vdsp_get_vtoc(void * arg1,void * arg2)1356aa73aceeSkettenis vdsp_get_vtoc(void *arg1, void *arg2)
1357aa73aceeSkettenis {
1358aa73aceeSkettenis 	struct vdsp_softc *sc = arg1;
1359aa73aceeSkettenis 	struct ldc_conn *lc = &sc->sc_lc;
1360aa73aceeSkettenis 	struct vd_desc *vd = arg2;
13610e924c63Skettenis 	struct sun_vtoc_preamble *sl;
1362aa73aceeSkettenis 	struct vd_vtoc *vt;
1363aa73aceeSkettenis 	vaddr_t va;
1364aa73aceeSkettenis 	paddr_t pa;
1365aa73aceeSkettenis 	uint64_t size, off;
1366aa73aceeSkettenis 	psize_t nbytes;
1367aa73aceeSkettenis 	int err, i;
1368aa73aceeSkettenis 
13690e924c63Skettenis 	vt = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK | M_ZERO);
1370aa73aceeSkettenis 
1371aa73aceeSkettenis 	if (sc->sc_label == NULL)
1372aa73aceeSkettenis 		vdsp_readlabel(sc);
1373aa73aceeSkettenis 
1374aa73aceeSkettenis 	if (sc->sc_label && sc->sc_label->sl_magic == SUN_DKMAGIC) {
13750e924c63Skettenis 		sl = (struct sun_vtoc_preamble *)sc->sc_label;
1376aa73aceeSkettenis 
13770e924c63Skettenis 		memcpy(vt->ascii_label, sl->sl_text, sizeof(sl->sl_text));
1378aa73aceeSkettenis 		memcpy(vt->volume_name, sl->sl_volume, sizeof(sl->sl_volume));
1379aa73aceeSkettenis 		vt->sector_size = DEV_BSIZE;
1380aa73aceeSkettenis 		vt->num_partitions = sl->sl_nparts;
1381aa73aceeSkettenis 		for (i = 0; i < vt->num_partitions; i++) {
1382aa73aceeSkettenis 			vt->partition[i].id_tag = sl->sl_part[i].spi_tag;
1383aa73aceeSkettenis 			vt->partition[i].perm = sl->sl_part[i].spi_flag;
1384aa73aceeSkettenis 			vt->partition[i].start =
1385aa73aceeSkettenis 			    sc->sc_label->sl_part[i].sdkp_cyloffset *
1386aa73aceeSkettenis 				sc->sc_label->sl_ntracks *
1387aa73aceeSkettenis 				sc->sc_label->sl_nsectors;
1388aa73aceeSkettenis 			vt->partition[i].nblocks =
1389aa73aceeSkettenis 			    sc->sc_label->sl_part[i].sdkp_nsectors;
1390aa73aceeSkettenis 		}
13910e924c63Skettenis 	} else {
13920e924c63Skettenis 		uint64_t disk_size;
13930e924c63Skettenis 		int unit;
13940e924c63Skettenis 
13950e924c63Skettenis 		/* Human-readable disk size. */
13960e924c63Skettenis 		disk_size = sc->sc_vdisk_size * sc->sc_vdisk_block_size;
13970e924c63Skettenis 		disk_size >>= 10;
13980e924c63Skettenis 		unit = 'K';
13990e924c63Skettenis 		if (disk_size > (2 << 10)) {
14000e924c63Skettenis 			disk_size >>= 10;
14010e924c63Skettenis 			unit = 'M';
14020e924c63Skettenis 		}
14030e924c63Skettenis 		if (disk_size > (2 << 10)) {
14040e924c63Skettenis 			disk_size >>= 10;
14050e924c63Skettenis 			unit = 'G';
14060e924c63Skettenis 		}
14070e924c63Skettenis 
14080e924c63Skettenis 		snprintf(vt->ascii_label, sizeof(vt->ascii_label),
14090e924c63Skettenis 		    "OpenBSD-DiskImage-%lld%cB cyl %d alt %d hd %d sec %d",
14100e924c63Skettenis 		    disk_size, unit, sc->sc_ncyl, sc->sc_acyl,
14110e924c63Skettenis 		    sc->sc_nhead, sc->sc_nsect);
14120e924c63Skettenis 		vt->sector_size = sc->sc_vdisk_block_size;
14130e924c63Skettenis 		vt->num_partitions = 8;
14140e924c63Skettenis 		vt->partition[2].id_tag = SPTAG_WHOLE_DISK;
14150e924c63Skettenis 		vt->partition[2].nblocks =
14160e924c63Skettenis 		    sc->sc_ncyl * sc->sc_nhead * sc->sc_nsect;
14170e924c63Skettenis 	}
1418aa73aceeSkettenis 
1419aa73aceeSkettenis 	i = 0;
1420aa73aceeSkettenis 	va = (vaddr_t)vt;
1421aa73aceeSkettenis 	size = roundup(sizeof(*vt), 64);
1422aa73aceeSkettenis 	off = 0;
1423aa73aceeSkettenis 	while (size > 0 && i < vd->ncookies) {
1424aa73aceeSkettenis 		pmap_extract(pmap_kernel(), va, &pa);
14256467609bSkettenis 		nbytes = MIN(size, vd->cookie[i].size - off);
14266467609bSkettenis 		nbytes = MIN(nbytes, PAGE_SIZE - (off & PAGE_MASK));
1427aa73aceeSkettenis 		err = hv_ldc_copy(lc->lc_id, LDC_COPY_OUT,
1428aa73aceeSkettenis 		    vd->cookie[i].addr + off, pa, nbytes, &nbytes);
14296633ec97Skettenis 		if (err != H_EOK) {
1430aa73aceeSkettenis 			printf("%s: hv_ldc_copy: %d\n", __func__, err);
143124dcbee2Skettenis 			vd->status = EIO;
143224dcbee2Skettenis 			goto fail;
14336633ec97Skettenis 		}
1434aa73aceeSkettenis 		va += nbytes;
1435aa73aceeSkettenis 		size -= nbytes;
1436aa73aceeSkettenis 		off += nbytes;
1437aa73aceeSkettenis 		if (off >= vd->cookie[i].size) {
1438aa73aceeSkettenis 			off = 0;
1439aa73aceeSkettenis 			i++;
1440aa73aceeSkettenis 		}
1441aa73aceeSkettenis 	}
1442aa73aceeSkettenis 
144324dcbee2Skettenis 	vd->status = 0;
144424dcbee2Skettenis 
144524dcbee2Skettenis fail:
1446f8e6c425Stedu 	free(vt, M_DEVBUF, 0);
14470e924c63Skettenis 
14480e924c63Skettenis 	/* ACK the descriptor. */
14490e924c63Skettenis 	vd->hdr.dstate = VIO_DESC_DONE;
14500e924c63Skettenis 	vdsp_ack_desc(sc, vd);
1451aa73aceeSkettenis }
1452aa73aceeSkettenis 
14530e924c63Skettenis void
vdsp_set_vtoc(void * arg1,void * arg2)14540e924c63Skettenis vdsp_set_vtoc(void *arg1, void *arg2)
14550e924c63Skettenis {
14560e924c63Skettenis 	struct vdsp_softc *sc = arg1;
14570e924c63Skettenis 	struct ldc_conn *lc = &sc->sc_lc;
14580e924c63Skettenis 	struct vd_desc *vd = arg2;
14590e924c63Skettenis 	struct sun_vtoc_preamble *sl;
14600e924c63Skettenis 	struct vd_vtoc *vt;
14610e924c63Skettenis 	u_short cksum = 0, *sp1, *sp2;
14620e924c63Skettenis 	vaddr_t va;
14630e924c63Skettenis 	paddr_t pa;
14640e924c63Skettenis 	uint64_t size, off;
14650e924c63Skettenis 	psize_t nbytes;
14660e924c63Skettenis 	int err, i;
14670e924c63Skettenis 
14680e924c63Skettenis 	vt = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK | M_ZERO);
14690e924c63Skettenis 
14700e924c63Skettenis 	i = 0;
14710e924c63Skettenis 	va = (vaddr_t)vt;
14720e924c63Skettenis 	size = sizeof(*vt);
14730e924c63Skettenis 	off = 0;
14740e924c63Skettenis 	while (size > 0 && i < vd->ncookies) {
14750e924c63Skettenis 		pmap_extract(pmap_kernel(), va, &pa);
14766467609bSkettenis 		nbytes = MIN(size, vd->cookie[i].size - off);
14776467609bSkettenis 		nbytes = MIN(nbytes, PAGE_SIZE - (off & PAGE_MASK));
14780e924c63Skettenis 		err = hv_ldc_copy(lc->lc_id, LDC_COPY_IN,
14790e924c63Skettenis 		    vd->cookie[i].addr + off, pa, nbytes, &nbytes);
14806633ec97Skettenis 		if (err != H_EOK) {
14810e924c63Skettenis 			printf("%s: hv_ldc_copy: %d\n", __func__, err);
148224dcbee2Skettenis 			vd->status = EIO;
148324dcbee2Skettenis 			goto fail;
14846633ec97Skettenis 		}
14850e924c63Skettenis 		va += nbytes;
14860e924c63Skettenis 		size -= nbytes;
14870e924c63Skettenis 		off += nbytes;
14880e924c63Skettenis 		if (off >= vd->cookie[i].size) {
14890e924c63Skettenis 			off = 0;
14900e924c63Skettenis 			i++;
14910e924c63Skettenis 		}
14920e924c63Skettenis 	}
14930e924c63Skettenis 
14940e924c63Skettenis 	if (vt->num_partitions > nitems(sc->sc_label->sl_part)) {
14950e924c63Skettenis 		vd->status = EINVAL;
14960e924c63Skettenis 		goto fail;
14970e924c63Skettenis 	}
14980e924c63Skettenis 
14990e924c63Skettenis 	if (sc->sc_label == NULL || sc->sc_label->sl_magic != SUN_DKMAGIC) {
15000e924c63Skettenis 		sc->sc_label = malloc(sizeof(*sc->sc_label),
15010e924c63Skettenis 		    M_DEVBUF, M_WAITOK | M_ZERO);
15020e924c63Skettenis 
15030e924c63Skettenis 		sc->sc_label->sl_ntracks = sc->sc_nhead;
15040e924c63Skettenis 		sc->sc_label->sl_nsectors = sc->sc_nsect;
15050e924c63Skettenis 		sc->sc_label->sl_ncylinders = sc->sc_ncyl;
15060e924c63Skettenis 		sc->sc_label->sl_acylinders = sc->sc_acyl;
15070e924c63Skettenis 		sc->sc_label->sl_pcylinders = sc->sc_ncyl + sc->sc_acyl;
15080e924c63Skettenis 		sc->sc_label->sl_rpm = 3600;
15090e924c63Skettenis 
15100e924c63Skettenis 		sc->sc_label->sl_magic = SUN_DKMAGIC;
15110e924c63Skettenis 	}
15120e924c63Skettenis 
15130e924c63Skettenis 	sl = (struct sun_vtoc_preamble *)sc->sc_label;
15140e924c63Skettenis 	memcpy(sl->sl_text, vt->ascii_label, sizeof(sl->sl_text));
15150e924c63Skettenis 	sl->sl_version = 0x01;
15168f235949Skettenis 	memcpy(sl->sl_volume, vt->volume_name, sizeof(sl->sl_volume));
15170e924c63Skettenis 	sl->sl_nparts = vt->num_partitions;
15180e924c63Skettenis 	for (i = 0; i < vt->num_partitions; i++) {
15190e924c63Skettenis 		sl->sl_part[i].spi_tag = vt->partition[i].id_tag;
15200e924c63Skettenis 		sl->sl_part[i].spi_flag = vt->partition[i].perm;
15210e924c63Skettenis 		sc->sc_label->sl_part[i].sdkp_cyloffset =
15220e924c63Skettenis 		    vt->partition[i].start / (sc->sc_nhead * sc->sc_nsect);
15230e924c63Skettenis 		sc->sc_label->sl_part[i].sdkp_nsectors =
15240e924c63Skettenis 		    vt->partition[i].nblocks;
15250e924c63Skettenis 	}
15260e924c63Skettenis 	sl->sl_sanity = 0x600ddeee;
15270e924c63Skettenis 
15280e924c63Skettenis 	/* Compute the checksum. */
15290e924c63Skettenis 	sp1 = (u_short *)sc->sc_label;
15300e924c63Skettenis 	sp2 = (u_short *)(sc->sc_label + 1);
15310e924c63Skettenis 	while (sp1 < sp2)
15320e924c63Skettenis 		cksum ^= *sp1++;
15330e924c63Skettenis 	sc->sc_label->sl_cksum = cksum;
15340e924c63Skettenis 
15350e924c63Skettenis 	vd->status = vdsp_writelabel(sc);
15360e924c63Skettenis 
15370e924c63Skettenis fail:
1538f8e6c425Stedu 	free(vt, M_DEVBUF, 0);
15390e924c63Skettenis 
1540aa73aceeSkettenis 	/* ACK the descriptor. */
1541aa73aceeSkettenis 	vd->hdr.dstate = VIO_DESC_DONE;
1542aa73aceeSkettenis 	vdsp_ack_desc(sc, vd);
1543aa73aceeSkettenis }
1544aa73aceeSkettenis 
1545aa73aceeSkettenis void
vdsp_get_diskgeom(void * arg1,void * arg2)1546aa73aceeSkettenis vdsp_get_diskgeom(void *arg1, void *arg2)
1547aa73aceeSkettenis {
1548aa73aceeSkettenis 	struct vdsp_softc *sc = arg1;
1549aa73aceeSkettenis 	struct ldc_conn *lc = &sc->sc_lc;
1550aa73aceeSkettenis 	struct vd_desc *vd = arg2;
1551aa73aceeSkettenis 	struct vd_diskgeom *vg;
1552aa73aceeSkettenis 	vaddr_t va;
1553aa73aceeSkettenis 	paddr_t pa;
1554aa73aceeSkettenis 	uint64_t size, off;
1555aa73aceeSkettenis 	psize_t nbytes;
1556aa73aceeSkettenis 	int err, i;
1557aa73aceeSkettenis 
1558aa73aceeSkettenis 	vg = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK | M_ZERO);
1559aa73aceeSkettenis 
1560aa73aceeSkettenis 	if (sc->sc_label == NULL)
1561aa73aceeSkettenis 		vdsp_readlabel(sc);
1562aa73aceeSkettenis 
1563aa73aceeSkettenis 	if (sc->sc_label && sc->sc_label->sl_magic == SUN_DKMAGIC) {
1564aa73aceeSkettenis 		vg->ncyl = sc->sc_label->sl_ncylinders;
1565aa73aceeSkettenis 		vg->acyl = sc->sc_label->sl_acylinders;
1566aa73aceeSkettenis 		vg->nhead = sc->sc_label->sl_ntracks;
1567aa73aceeSkettenis 		vg->nsect = sc->sc_label->sl_nsectors;
1568aa73aceeSkettenis 		vg->intrlv = sc->sc_label->sl_interleave;
1569aa73aceeSkettenis 		vg->apc = sc->sc_label->sl_sparespercyl;
1570aa73aceeSkettenis 		vg->rpm = sc->sc_label->sl_rpm;
1571aa73aceeSkettenis 		vg->pcyl = sc->sc_label->sl_pcylinders;
1572aa73aceeSkettenis 	} else {
1573aa73aceeSkettenis 		uint64_t disk_size, block_size;
1574aa73aceeSkettenis 
1575aa73aceeSkettenis 		disk_size = sc->sc_vdisk_size * sc->sc_vdisk_block_size;
1576aa73aceeSkettenis 		block_size = sc->sc_vdisk_block_size;
1577aa73aceeSkettenis 
1578aa73aceeSkettenis 		if (disk_size >= 8L * 1024 * 1024 * 1024) {
1579aa73aceeSkettenis 			vg->nhead = 96;
1580aa73aceeSkettenis 			vg->nsect = 768;
1581aa73aceeSkettenis 		} else if (disk_size >= 2 *1024 * 1024) {
1582aa73aceeSkettenis 			vg->nhead = 1;
1583aa73aceeSkettenis 			vg->nsect = 600;
1584aa73aceeSkettenis 		} else {
1585aa73aceeSkettenis 			vg->nhead = 1;
1586aa73aceeSkettenis 			vg->nsect = 200;
1587aa73aceeSkettenis 		}
1588aa73aceeSkettenis 
1589aa73aceeSkettenis 		vg->pcyl = disk_size / (block_size * vg->nhead * vg->nsect);
1590aa73aceeSkettenis 		if (vg->pcyl == 0)
1591aa73aceeSkettenis 			vg->pcyl = 1;
1592aa73aceeSkettenis 		if (vg->pcyl > 2)
1593aa73aceeSkettenis 			vg->acyl = 2;
1594aa73aceeSkettenis 		vg->ncyl = vg->pcyl - vg->acyl;
1595aa73aceeSkettenis 
1596aa73aceeSkettenis 		vg->rpm = 3600;
1597aa73aceeSkettenis 	}
1598aa73aceeSkettenis 
15990e924c63Skettenis 	sc->sc_ncyl = vg->ncyl;
16000e924c63Skettenis 	sc->sc_acyl = vg->acyl;
16010e924c63Skettenis 	sc->sc_nhead = vg->nhead;
16020e924c63Skettenis 	sc->sc_nsect = vg->nsect;
16030e924c63Skettenis 
1604aa73aceeSkettenis 	i = 0;
1605aa73aceeSkettenis 	va = (vaddr_t)vg;
1606aa73aceeSkettenis 	size = roundup(sizeof(*vg), 64);
1607aa73aceeSkettenis 	off = 0;
1608aa73aceeSkettenis 	while (size > 0 && i < vd->ncookies) {
1609aa73aceeSkettenis 		pmap_extract(pmap_kernel(), va, &pa);
16106467609bSkettenis 		nbytes = MIN(size, vd->cookie[i].size - off);
16116467609bSkettenis 		nbytes = MIN(nbytes, PAGE_SIZE - (off & PAGE_MASK));
1612aa73aceeSkettenis 		err = hv_ldc_copy(lc->lc_id, LDC_COPY_OUT,
1613aa73aceeSkettenis 		    vd->cookie[i].addr + off, pa, nbytes, &nbytes);
16146633ec97Skettenis 		if (err != H_EOK) {
1615aa73aceeSkettenis 			printf("%s: hv_ldc_copy: %d\n", __func__, err);
161624dcbee2Skettenis 			vd->status = EIO;
161724dcbee2Skettenis 			goto fail;
16186633ec97Skettenis 		}
1619aa73aceeSkettenis 		va += nbytes;
1620aa73aceeSkettenis 		size -= nbytes;
1621aa73aceeSkettenis 		off += nbytes;
1622aa73aceeSkettenis 		if (off >= vd->cookie[i].size) {
1623aa73aceeSkettenis 			off = 0;
1624aa73aceeSkettenis 			i++;
1625aa73aceeSkettenis 		}
1626aa73aceeSkettenis 	}
1627aa73aceeSkettenis 
162824dcbee2Skettenis 	vd->status = 0;
162924dcbee2Skettenis 
163024dcbee2Skettenis fail:
1631f8e6c425Stedu 	free(vg, M_DEVBUF, 0);
16326633ec97Skettenis 
1633aa73aceeSkettenis 	/* ACK the descriptor. */
1634aa73aceeSkettenis 	vd->hdr.dstate = VIO_DESC_DONE;
1635aa73aceeSkettenis 	vdsp_ack_desc(sc, vd);
1636aa73aceeSkettenis }
1637aa73aceeSkettenis 
1638aa73aceeSkettenis void
vdsp_unimp(void * arg1,void * arg2)1639aa73aceeSkettenis vdsp_unimp(void *arg1, void *arg2)
1640aa73aceeSkettenis {
1641aa73aceeSkettenis 	struct vdsp_softc *sc = arg1;
1642aa73aceeSkettenis 	struct vd_desc *vd = arg2;
1643aa73aceeSkettenis 
1644aa73aceeSkettenis 	/* ACK the descriptor. */
1645aa73aceeSkettenis 	vd->status = ENOTSUP;
1646aa73aceeSkettenis 	vd->hdr.dstate = VIO_DESC_DONE;
1647aa73aceeSkettenis 	vdsp_ack_desc(sc, vd);
1648aa73aceeSkettenis }
1649aa73aceeSkettenis 
1650aa73aceeSkettenis void
vdsp_ack_desc(struct vdsp_softc * sc,struct vd_desc * vd)1651aa73aceeSkettenis vdsp_ack_desc(struct vdsp_softc *sc, struct vd_desc *vd)
16529b09334aSkettenis {
16539b09334aSkettenis 	struct vio_dring_msg dm;
1654aa73aceeSkettenis 	vaddr_t va;
1655aa73aceeSkettenis 	paddr_t pa;
1656aa73aceeSkettenis 	uint64_t size, off;
16579b09334aSkettenis 	psize_t nbytes;
16589b09334aSkettenis 	int err;
16599b09334aSkettenis 
1660aa73aceeSkettenis 	va = (vaddr_t)vd;
1661aa73aceeSkettenis 	off = (caddr_t)vd - sc->sc_vd;
1662aa73aceeSkettenis 	size = sc->sc_descriptor_size;
1663aa73aceeSkettenis 	while (size > 0) {
1664aa73aceeSkettenis 		pmap_extract(pmap_kernel(), va, &pa);
16656467609bSkettenis 		nbytes = MIN(size, PAGE_SIZE - (off & PAGE_MASK));
16669b09334aSkettenis 		err = hv_ldc_copy(sc->sc_lc.lc_id, LDC_COPY_OUT,
1667b04fbd6eSkettenis 		    sc->sc_dring_cookie.addr + off, pa, nbytes, &nbytes);
16689b09334aSkettenis 		if (err != H_EOK) {
1669aa73aceeSkettenis 			printf("%s: hv_ldc_copy %d\n", __func__, err);
16709b09334aSkettenis 			return;
16719b09334aSkettenis 		}
1672b04fbd6eSkettenis 		va += nbytes;
1673b04fbd6eSkettenis 		size -= nbytes;
1674b04fbd6eSkettenis 		off += nbytes;
1675b04fbd6eSkettenis 	}
16769b09334aSkettenis 
16779b09334aSkettenis 	/* ACK the descriptor. */
16789b09334aSkettenis 	bzero(&dm, sizeof(dm));
16799b09334aSkettenis 	dm.tag.type = VIO_TYPE_DATA;
16809b09334aSkettenis 	dm.tag.stype = VIO_SUBTYPE_ACK;
16819b09334aSkettenis 	dm.tag.stype_env = VIO_DRING_DATA;
16829b09334aSkettenis 	dm.tag.sid = sc->sc_local_sid;
16834138715aSkettenis 	dm.seq_no = ++sc->sc_seq_no;
16849b09334aSkettenis 	dm.dring_ident = sc->sc_dring_ident;
1685aa73aceeSkettenis 	off = (caddr_t)vd - sc->sc_vd;
1686aa73aceeSkettenis 	dm.start_idx = off / sc->sc_descriptor_size;
1687aa73aceeSkettenis 	dm.end_idx = off / sc->sc_descriptor_size;
16886943088aSkettenis 	vdsp_sendmsg(sc, &dm, sizeof(dm), 1);
1689c396b9d4Skettenis }
169046169cb9Skettenis 
169146169cb9Skettenis int
vdspopen(dev_t dev,int flag,int mode,struct proc * p)169246169cb9Skettenis vdspopen(dev_t dev, int flag, int mode, struct proc *p)
169346169cb9Skettenis {
169446169cb9Skettenis 	struct vdsp_softc *sc;
169546169cb9Skettenis 	struct ldc_conn *lc;
169646169cb9Skettenis 	int unit = minor(dev);
169746169cb9Skettenis 	int err;
169846169cb9Skettenis 
169946169cb9Skettenis 	if (unit >= vdsp_cd.cd_ndevs)
170046169cb9Skettenis 		return (ENXIO);
170146169cb9Skettenis 	sc = vdsp_cd.cd_devs[unit];
170246169cb9Skettenis 	if (sc == NULL)
170346169cb9Skettenis 		return (ENXIO);
170446169cb9Skettenis 
170546169cb9Skettenis 	lc = &sc->sc_lc;
170646169cb9Skettenis 
170746169cb9Skettenis 	err = hv_ldc_tx_qconf(lc->lc_id,
170846169cb9Skettenis 	    lc->lc_txq->lq_map->dm_segs[0].ds_addr, lc->lc_txq->lq_nentries);
170946169cb9Skettenis 	if (err != H_EOK)
171046169cb9Skettenis 		printf("%s: hv_ldc_tx_qconf %d\n", __func__, err);
171146169cb9Skettenis 
171246169cb9Skettenis 	err = hv_ldc_rx_qconf(lc->lc_id,
171346169cb9Skettenis 	    lc->lc_rxq->lq_map->dm_segs[0].ds_addr, lc->lc_rxq->lq_nentries);
171446169cb9Skettenis 	if (err != H_EOK)
171502aa388cSkettenis 		printf("%s: hv_ldc_rx_qconf %d\n", __func__, err);
171646169cb9Skettenis 
1717b3a497edSkettenis 	cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, INTR_ENABLED);
1718b3a497edSkettenis 	cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, INTR_ENABLED);
171946169cb9Skettenis 
172046169cb9Skettenis 	return (0);
172146169cb9Skettenis }
172246169cb9Skettenis 
172346169cb9Skettenis int
vdspclose(dev_t dev,int flag,int mode,struct proc * p)172446169cb9Skettenis vdspclose(dev_t dev, int flag, int mode, struct proc *p)
172546169cb9Skettenis {
172646169cb9Skettenis 	struct vdsp_softc *sc;
172746169cb9Skettenis 	int unit = minor(dev);
172846169cb9Skettenis 
172946169cb9Skettenis 	if (unit >= vdsp_cd.cd_ndevs)
173046169cb9Skettenis 		return (ENXIO);
173146169cb9Skettenis 	sc = vdsp_cd.cd_devs[unit];
173246169cb9Skettenis 	if (sc == NULL)
173346169cb9Skettenis 		return (ENXIO);
173446169cb9Skettenis 
1735b3a497edSkettenis 	cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, INTR_DISABLED);
1736b3a497edSkettenis 	cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, INTR_DISABLED);
173746169cb9Skettenis 
173846169cb9Skettenis 	hv_ldc_tx_qconf(sc->sc_lc.lc_id, 0, 0);
173946169cb9Skettenis 	hv_ldc_rx_qconf(sc->sc_lc.lc_id, 0, 0);
174046169cb9Skettenis 
1741356a67c0Skettenis 	task_add(systq, &sc->sc_close_task);
174246169cb9Skettenis 	return (0);
174346169cb9Skettenis }
174446169cb9Skettenis 
174546169cb9Skettenis int
vdspioctl(dev_t dev,u_long cmd,caddr_t data,int flag,struct proc * p)174646169cb9Skettenis vdspioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
174746169cb9Skettenis {
174846169cb9Skettenis 	struct vdsp_softc *sc;
174946169cb9Skettenis 	int unit = minor(dev);
175046169cb9Skettenis 
175146169cb9Skettenis 	if (unit >= vdsp_cd.cd_ndevs)
175246169cb9Skettenis 		return (ENXIO);
175346169cb9Skettenis 	sc = vdsp_cd.cd_devs[unit];
175446169cb9Skettenis 	if (sc == NULL)
175546169cb9Skettenis 		return (ENXIO);
175646169cb9Skettenis 
175746169cb9Skettenis 	return (ENOTTY);
175846169cb9Skettenis }
1759