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