| @@ -1,645 +1,652 @@ | | | @@ -1,645 +1,652 @@ |
1 | /* $NetBSD: ld_virtio.c,v 1.17 2018/06/03 02:13:09 jakllsch Exp $ */ | | 1 | /* $NetBSD: ld_virtio.c,v 1.18 2018/06/03 19:47:35 jakllsch Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2010 Minoura Makoto. | | 4 | * Copyright (c) 2010 Minoura Makoto. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
15 | * | | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | | 19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | | 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | | 21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | | 22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | | 23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | | 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | | 26 | */ |
27 | | | 27 | |
28 | #include <sys/cdefs.h> | | 28 | #include <sys/cdefs.h> |
29 | __KERNEL_RCSID(0, "$NetBSD: ld_virtio.c,v 1.17 2018/06/03 02:13:09 jakllsch Exp $"); | | 29 | __KERNEL_RCSID(0, "$NetBSD: ld_virtio.c,v 1.18 2018/06/03 19:47:35 jakllsch Exp $"); |
30 | | | 30 | |
31 | #include <sys/param.h> | | 31 | #include <sys/param.h> |
32 | #include <sys/systm.h> | | 32 | #include <sys/systm.h> |
33 | #include <sys/kernel.h> | | 33 | #include <sys/kernel.h> |
34 | #include <sys/buf.h> | | 34 | #include <sys/buf.h> |
35 | #include <sys/bufq.h> | | 35 | #include <sys/bufq.h> |
36 | #include <sys/bus.h> | | 36 | #include <sys/bus.h> |
37 | #include <sys/device.h> | | 37 | #include <sys/device.h> |
38 | #include <sys/disk.h> | | 38 | #include <sys/disk.h> |
39 | #include <sys/mutex.h> | | 39 | #include <sys/mutex.h> |
40 | #include <sys/module.h> | | 40 | #include <sys/module.h> |
41 | | | 41 | |
42 | #include <dev/pci/pcidevs.h> | | 42 | #include <dev/pci/pcidevs.h> |
43 | #include <dev/pci/pcireg.h> | | 43 | #include <dev/pci/pcireg.h> |
44 | #include <dev/pci/pcivar.h> | | 44 | #include <dev/pci/pcivar.h> |
45 | | | 45 | |
46 | #include <dev/ldvar.h> | | 46 | #include <dev/ldvar.h> |
47 | #include <dev/pci/virtioreg.h> | | 47 | #include <dev/pci/virtioreg.h> |
48 | #include <dev/pci/virtiovar.h> | | 48 | #include <dev/pci/virtiovar.h> |
49 | | | 49 | |
50 | #include "ioconf.h" | | 50 | #include "ioconf.h" |
51 | | | 51 | |
52 | /* | | 52 | /* |
53 | * ld_virtioreg: | | 53 | * ld_virtioreg: |
54 | */ | | 54 | */ |
55 | /* Configuration registers */ | | 55 | /* Configuration registers */ |
56 | #define VIRTIO_BLK_CONFIG_CAPACITY 0 /* 64bit */ | | 56 | #define VIRTIO_BLK_CONFIG_CAPACITY 0 /* 64bit */ |
57 | #define VIRTIO_BLK_CONFIG_SIZE_MAX 8 /* 32bit */ | | 57 | #define VIRTIO_BLK_CONFIG_SIZE_MAX 8 /* 32bit */ |
58 | #define VIRTIO_BLK_CONFIG_SEG_MAX 12 /* 32bit */ | | 58 | #define VIRTIO_BLK_CONFIG_SEG_MAX 12 /* 32bit */ |
59 | #define VIRTIO_BLK_CONFIG_GEOMETRY_C 16 /* 16bit */ | | 59 | #define VIRTIO_BLK_CONFIG_GEOMETRY_C 16 /* 16bit */ |
60 | #define VIRTIO_BLK_CONFIG_GEOMETRY_H 18 /* 8bit */ | | 60 | #define VIRTIO_BLK_CONFIG_GEOMETRY_H 18 /* 8bit */ |
61 | #define VIRTIO_BLK_CONFIG_GEOMETRY_S 19 /* 8bit */ | | 61 | #define VIRTIO_BLK_CONFIG_GEOMETRY_S 19 /* 8bit */ |
62 | #define VIRTIO_BLK_CONFIG_BLK_SIZE 20 /* 32bit */ | | 62 | #define VIRTIO_BLK_CONFIG_BLK_SIZE 20 /* 32bit */ |
| | | 63 | #define VIRTIO_BLK_CONFIG_WRITEBACK 32 /* 8bit */ |
63 | | | 64 | |
64 | /* Feature bits */ | | 65 | /* Feature bits */ |
65 | #define VIRTIO_BLK_F_BARRIER (1<<0) | | 66 | #define VIRTIO_BLK_F_BARRIER (1<<0) |
66 | #define VIRTIO_BLK_F_SIZE_MAX (1<<1) | | 67 | #define VIRTIO_BLK_F_SIZE_MAX (1<<1) |
67 | #define VIRTIO_BLK_F_SEG_MAX (1<<2) | | 68 | #define VIRTIO_BLK_F_SEG_MAX (1<<2) |
68 | #define VIRTIO_BLK_F_GEOMETRY (1<<4) | | 69 | #define VIRTIO_BLK_F_GEOMETRY (1<<4) |
69 | #define VIRTIO_BLK_F_RO (1<<5) | | 70 | #define VIRTIO_BLK_F_RO (1<<5) |
70 | #define VIRTIO_BLK_F_BLK_SIZE (1<<6) | | 71 | #define VIRTIO_BLK_F_BLK_SIZE (1<<6) |
71 | #define VIRTIO_BLK_F_SCSI (1<<7) | | 72 | #define VIRTIO_BLK_F_SCSI (1<<7) |
72 | #define VIRTIO_BLK_F_FLUSH (1<<9) | | 73 | #define VIRTIO_BLK_F_FLUSH (1<<9) |
| | | 74 | #define VIRTIO_BLK_F_TOPOLOGY (1<<10) |
| | | 75 | #define VIRTIO_BLK_F_CONFIG_WCE (1<<11) |
73 | | | 76 | |
74 | /* | | 77 | /* |
75 | * Each block request uses at least two segments - one for the header | | 78 | * Each block request uses at least two segments - one for the header |
76 | * and one for the status. | | 79 | * and one for the status. |
77 | */ | | 80 | */ |
78 | #define VIRTIO_BLK_MIN_SEGMENTS 2 | | 81 | #define VIRTIO_BLK_MIN_SEGMENTS 2 |
79 | | | 82 | |
80 | #define VIRTIO_BLK_FLAG_BITS \ | | 83 | #define VIRTIO_BLK_FLAG_BITS \ |
81 | VIRTIO_COMMON_FLAG_BITS \ | | 84 | VIRTIO_COMMON_FLAG_BITS \ |
| | | 85 | "\x0c""CONFIG_WCE" \ |
| | | 86 | "\x0b""TOPOLOGY" \ |
82 | "\x0a""FLUSH" \ | | 87 | "\x0a""FLUSH" \ |
83 | "\x08""SCSI" \ | | 88 | "\x08""SCSI" \ |
84 | "\x07""BLK_SIZE" \ | | 89 | "\x07""BLK_SIZE" \ |
85 | "\x06""RO" \ | | 90 | "\x06""RO" \ |
86 | "\x05""GEOMETRY" \ | | 91 | "\x05""GEOMETRY" \ |
87 | "\x03""SEG_MAX" \ | | 92 | "\x03""SEG_MAX" \ |
88 | "\x02""SIZE_MAX" \ | | 93 | "\x02""SIZE_MAX" \ |
89 | "\x01""BARRIER" | | 94 | "\x01""BARRIER" |
90 | | | 95 | |
91 | /* Command */ | | 96 | /* Command */ |
92 | #define VIRTIO_BLK_T_IN 0 | | 97 | #define VIRTIO_BLK_T_IN 0 |
93 | #define VIRTIO_BLK_T_OUT 1 | | 98 | #define VIRTIO_BLK_T_OUT 1 |
| | | 99 | #define VIRTIO_BLK_T_FLUSH 4 |
94 | #define VIRTIO_BLK_T_BARRIER 0x80000000 | | 100 | #define VIRTIO_BLK_T_BARRIER 0x80000000 |
95 | | | 101 | |
96 | /* Status */ | | 102 | /* Status */ |
97 | #define VIRTIO_BLK_S_OK 0 | | 103 | #define VIRTIO_BLK_S_OK 0 |
98 | #define VIRTIO_BLK_S_IOERR 1 | | 104 | #define VIRTIO_BLK_S_IOERR 1 |
| | | 105 | #define VIRTIO_BLK_S_UNSUPP 2 |
99 | | | 106 | |
100 | /* Request header structure */ | | 107 | /* Request header structure */ |
101 | struct virtio_blk_req_hdr { | | 108 | struct virtio_blk_req_hdr { |
102 | uint32_t type; /* VIRTIO_BLK_T_* */ | | 109 | uint32_t type; /* VIRTIO_BLK_T_* */ |
103 | uint32_t ioprio; | | 110 | uint32_t ioprio; |
104 | uint64_t sector; | | 111 | uint64_t sector; |
105 | } __packed; | | 112 | } __packed; |
106 | /* 512*virtio_blk_req_hdr.sector byte payload and 1 byte status follows */ | | 113 | /* 512*virtio_blk_req_hdr.sector byte payload and 1 byte status follows */ |
107 | | | 114 | |
108 | | | 115 | |
109 | /* | | 116 | /* |
110 | * ld_virtiovar: | | 117 | * ld_virtiovar: |
111 | */ | | 118 | */ |
112 | struct virtio_blk_req { | | 119 | struct virtio_blk_req { |
113 | struct virtio_blk_req_hdr vr_hdr; | | 120 | struct virtio_blk_req_hdr vr_hdr; |
114 | uint8_t vr_status; | | 121 | uint8_t vr_status; |
115 | struct buf *vr_bp; | | 122 | struct buf *vr_bp; |
116 | bus_dmamap_t vr_cmdsts; | | 123 | bus_dmamap_t vr_cmdsts; |
117 | bus_dmamap_t vr_payload; | | 124 | bus_dmamap_t vr_payload; |
118 | }; | | 125 | }; |
119 | | | 126 | |
120 | struct ld_virtio_softc { | | 127 | struct ld_virtio_softc { |
121 | struct ld_softc sc_ld; | | 128 | struct ld_softc sc_ld; |
122 | device_t sc_dev; | | 129 | device_t sc_dev; |
123 | | | 130 | |
124 | struct virtio_softc *sc_virtio; | | 131 | struct virtio_softc *sc_virtio; |
125 | struct virtqueue sc_vq; | | 132 | struct virtqueue sc_vq; |
126 | | | 133 | |
127 | struct virtio_blk_req *sc_reqs; | | 134 | struct virtio_blk_req *sc_reqs; |
128 | bus_dma_segment_t sc_reqs_seg; | | 135 | bus_dma_segment_t sc_reqs_seg; |
129 | | | 136 | |
130 | int sc_readonly; | | 137 | int sc_readonly; |
131 | }; | | 138 | }; |
132 | | | 139 | |
133 | static int ld_virtio_match(device_t, cfdata_t, void *); | | 140 | static int ld_virtio_match(device_t, cfdata_t, void *); |
134 | static void ld_virtio_attach(device_t, device_t, void *); | | 141 | static void ld_virtio_attach(device_t, device_t, void *); |
135 | static int ld_virtio_detach(device_t, int); | | 142 | static int ld_virtio_detach(device_t, int); |
136 | | | 143 | |
137 | CFATTACH_DECL_NEW(ld_virtio, sizeof(struct ld_virtio_softc), | | 144 | CFATTACH_DECL_NEW(ld_virtio, sizeof(struct ld_virtio_softc), |
138 | ld_virtio_match, ld_virtio_attach, ld_virtio_detach, NULL); | | 145 | ld_virtio_match, ld_virtio_attach, ld_virtio_detach, NULL); |
139 | | | 146 | |
140 | static int | | 147 | static int |
141 | ld_virtio_match(device_t parent, cfdata_t match, void *aux) | | 148 | ld_virtio_match(device_t parent, cfdata_t match, void *aux) |
142 | { | | 149 | { |
143 | struct virtio_attach_args *va = aux; | | 150 | struct virtio_attach_args *va = aux; |
144 | | | 151 | |
145 | if (va->sc_childdevid == PCI_PRODUCT_VIRTIO_BLOCK) | | 152 | if (va->sc_childdevid == PCI_PRODUCT_VIRTIO_BLOCK) |
146 | return 1; | | 153 | return 1; |
147 | | | 154 | |
148 | return 0; | | 155 | return 0; |
149 | } | | 156 | } |
150 | | | 157 | |
151 | static int ld_virtio_vq_done(struct virtqueue *); | | 158 | static int ld_virtio_vq_done(struct virtqueue *); |
152 | static int ld_virtio_dump(struct ld_softc *, void *, int, int); | | 159 | static int ld_virtio_dump(struct ld_softc *, void *, int, int); |
153 | static int ld_virtio_start(struct ld_softc *, struct buf *); | | 160 | static int ld_virtio_start(struct ld_softc *, struct buf *); |
154 | | | 161 | |
155 | static int | | 162 | static int |
156 | ld_virtio_alloc_reqs(struct ld_virtio_softc *sc, int qsize) | | 163 | ld_virtio_alloc_reqs(struct ld_virtio_softc *sc, int qsize) |
157 | { | | 164 | { |
158 | int allocsize, r, rsegs, i; | | 165 | int allocsize, r, rsegs, i; |
159 | struct ld_softc *ld = &sc->sc_ld; | | 166 | struct ld_softc *ld = &sc->sc_ld; |
160 | void *vaddr; | | 167 | void *vaddr; |
161 | | | 168 | |
162 | allocsize = sizeof(struct virtio_blk_req) * qsize; | | 169 | allocsize = sizeof(struct virtio_blk_req) * qsize; |
163 | r = bus_dmamem_alloc(virtio_dmat(sc->sc_virtio), allocsize, 0, 0, | | 170 | r = bus_dmamem_alloc(virtio_dmat(sc->sc_virtio), allocsize, 0, 0, |
164 | &sc->sc_reqs_seg, 1, &rsegs, BUS_DMA_NOWAIT); | | 171 | &sc->sc_reqs_seg, 1, &rsegs, BUS_DMA_NOWAIT); |
165 | if (r != 0) { | | 172 | if (r != 0) { |
166 | aprint_error_dev(sc->sc_dev, | | 173 | aprint_error_dev(sc->sc_dev, |
167 | "DMA memory allocation failed, size %d, " | | 174 | "DMA memory allocation failed, size %d, " |
168 | "error code %d\n", allocsize, r); | | 175 | "error code %d\n", allocsize, r); |
169 | goto err_none; | | 176 | goto err_none; |
170 | } | | 177 | } |
171 | r = bus_dmamem_map(virtio_dmat(sc->sc_virtio), | | 178 | r = bus_dmamem_map(virtio_dmat(sc->sc_virtio), |
172 | &sc->sc_reqs_seg, 1, allocsize, | | 179 | &sc->sc_reqs_seg, 1, allocsize, |
173 | &vaddr, BUS_DMA_NOWAIT); | | 180 | &vaddr, BUS_DMA_NOWAIT); |
174 | if (r != 0) { | | 181 | if (r != 0) { |
175 | aprint_error_dev(sc->sc_dev, | | 182 | aprint_error_dev(sc->sc_dev, |
176 | "DMA memory map failed, " | | 183 | "DMA memory map failed, " |
177 | "error code %d\n", r); | | 184 | "error code %d\n", r); |
178 | goto err_dmamem_alloc; | | 185 | goto err_dmamem_alloc; |
179 | } | | 186 | } |
180 | sc->sc_reqs = vaddr; | | 187 | sc->sc_reqs = vaddr; |
181 | memset(vaddr, 0, allocsize); | | 188 | memset(vaddr, 0, allocsize); |
182 | for (i = 0; i < qsize; i++) { | | 189 | for (i = 0; i < qsize; i++) { |
183 | struct virtio_blk_req *vr = &sc->sc_reqs[i]; | | 190 | struct virtio_blk_req *vr = &sc->sc_reqs[i]; |
184 | r = bus_dmamap_create(virtio_dmat(sc->sc_virtio), | | 191 | r = bus_dmamap_create(virtio_dmat(sc->sc_virtio), |
185 | offsetof(struct virtio_blk_req, vr_bp), | | 192 | offsetof(struct virtio_blk_req, vr_bp), |
186 | 1, | | 193 | 1, |
187 | offsetof(struct virtio_blk_req, vr_bp), | | 194 | offsetof(struct virtio_blk_req, vr_bp), |
188 | 0, | | 195 | 0, |
189 | BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, | | 196 | BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, |
190 | &vr->vr_cmdsts); | | 197 | &vr->vr_cmdsts); |
191 | if (r != 0) { | | 198 | if (r != 0) { |
192 | aprint_error_dev(sc->sc_dev, | | 199 | aprint_error_dev(sc->sc_dev, |
193 | "command dmamap creation failed, " | | 200 | "command dmamap creation failed, " |
194 | "error code %d\n", r); | | 201 | "error code %d\n", r); |
195 | goto err_reqs; | | 202 | goto err_reqs; |
196 | } | | 203 | } |
197 | r = bus_dmamap_load(virtio_dmat(sc->sc_virtio), vr->vr_cmdsts, | | 204 | r = bus_dmamap_load(virtio_dmat(sc->sc_virtio), vr->vr_cmdsts, |
198 | &vr->vr_hdr, | | 205 | &vr->vr_hdr, |
199 | offsetof(struct virtio_blk_req, vr_bp), | | 206 | offsetof(struct virtio_blk_req, vr_bp), |
200 | NULL, BUS_DMA_NOWAIT); | | 207 | NULL, BUS_DMA_NOWAIT); |
201 | if (r != 0) { | | 208 | if (r != 0) { |
202 | aprint_error_dev(sc->sc_dev, | | 209 | aprint_error_dev(sc->sc_dev, |
203 | "command dmamap load failed, " | | 210 | "command dmamap load failed, " |
204 | "error code %d\n", r); | | 211 | "error code %d\n", r); |
205 | goto err_reqs; | | 212 | goto err_reqs; |
206 | } | | 213 | } |
207 | r = bus_dmamap_create(virtio_dmat(sc->sc_virtio), | | 214 | r = bus_dmamap_create(virtio_dmat(sc->sc_virtio), |
208 | ld->sc_maxxfer, | | 215 | ld->sc_maxxfer, |
209 | (ld->sc_maxxfer / NBPG) + | | 216 | (ld->sc_maxxfer / NBPG) + |
210 | VIRTIO_BLK_MIN_SEGMENTS, | | 217 | VIRTIO_BLK_MIN_SEGMENTS, |
211 | ld->sc_maxxfer, | | 218 | ld->sc_maxxfer, |
212 | 0, | | 219 | 0, |
213 | BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, | | 220 | BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, |
214 | &vr->vr_payload); | | 221 | &vr->vr_payload); |
215 | if (r != 0) { | | 222 | if (r != 0) { |
216 | aprint_error_dev(sc->sc_dev, | | 223 | aprint_error_dev(sc->sc_dev, |
217 | "payload dmamap creation failed, " | | 224 | "payload dmamap creation failed, " |
218 | "error code %d\n", r); | | 225 | "error code %d\n", r); |
219 | goto err_reqs; | | 226 | goto err_reqs; |
220 | } | | 227 | } |
221 | } | | 228 | } |
222 | return 0; | | 229 | return 0; |
223 | | | 230 | |
224 | err_reqs: | | 231 | err_reqs: |
225 | for (i = 0; i < qsize; i++) { | | 232 | for (i = 0; i < qsize; i++) { |
226 | struct virtio_blk_req *vr = &sc->sc_reqs[i]; | | 233 | struct virtio_blk_req *vr = &sc->sc_reqs[i]; |
227 | if (vr->vr_cmdsts) { | | 234 | if (vr->vr_cmdsts) { |
228 | bus_dmamap_destroy(virtio_dmat(sc->sc_virtio), | | 235 | bus_dmamap_destroy(virtio_dmat(sc->sc_virtio), |
229 | vr->vr_cmdsts); | | 236 | vr->vr_cmdsts); |
230 | vr->vr_cmdsts = 0; | | 237 | vr->vr_cmdsts = 0; |
231 | } | | 238 | } |
232 | if (vr->vr_payload) { | | 239 | if (vr->vr_payload) { |
233 | bus_dmamap_destroy(virtio_dmat(sc->sc_virtio), | | 240 | bus_dmamap_destroy(virtio_dmat(sc->sc_virtio), |
234 | vr->vr_payload); | | 241 | vr->vr_payload); |
235 | vr->vr_payload = 0; | | 242 | vr->vr_payload = 0; |
236 | } | | 243 | } |
237 | } | | 244 | } |
238 | bus_dmamem_unmap(virtio_dmat(sc->sc_virtio), sc->sc_reqs, allocsize); | | 245 | bus_dmamem_unmap(virtio_dmat(sc->sc_virtio), sc->sc_reqs, allocsize); |
239 | err_dmamem_alloc: | | 246 | err_dmamem_alloc: |
240 | bus_dmamem_free(virtio_dmat(sc->sc_virtio), &sc->sc_reqs_seg, 1); | | 247 | bus_dmamem_free(virtio_dmat(sc->sc_virtio), &sc->sc_reqs_seg, 1); |
241 | err_none: | | 248 | err_none: |
242 | return -1; | | 249 | return -1; |
243 | } | | 250 | } |
244 | | | 251 | |
245 | static void | | 252 | static void |
246 | ld_virtio_attach(device_t parent, device_t self, void *aux) | | 253 | ld_virtio_attach(device_t parent, device_t self, void *aux) |
247 | { | | 254 | { |
248 | struct ld_virtio_softc *sc = device_private(self); | | 255 | struct ld_virtio_softc *sc = device_private(self); |
249 | struct ld_softc *ld = &sc->sc_ld; | | 256 | struct ld_softc *ld = &sc->sc_ld; |
250 | struct virtio_softc *vsc = device_private(parent); | | 257 | struct virtio_softc *vsc = device_private(parent); |
251 | uint32_t features; | | 258 | uint32_t features; |
252 | int qsize, maxxfersize, maxnsegs; | | 259 | int qsize, maxxfersize, maxnsegs; |
253 | | | 260 | |
254 | if (virtio_child(vsc) != NULL) { | | 261 | if (virtio_child(vsc) != NULL) { |
255 | aprint_normal(": child already attached for %s; " | | 262 | aprint_normal(": child already attached for %s; " |
256 | "something wrong...\n", device_xname(parent)); | | 263 | "something wrong...\n", device_xname(parent)); |
257 | return; | | 264 | return; |
258 | } | | 265 | } |
259 | | | 266 | |
260 | sc->sc_dev = self; | | 267 | sc->sc_dev = self; |
261 | sc->sc_virtio = vsc; | | 268 | sc->sc_virtio = vsc; |
262 | | | 269 | |
263 | virtio_child_attach_start(vsc, self, IPL_BIO, &sc->sc_vq, | | 270 | virtio_child_attach_start(vsc, self, IPL_BIO, &sc->sc_vq, |
264 | NULL, virtio_vq_intr, 0, | | 271 | NULL, virtio_vq_intr, 0, |
265 | (VIRTIO_BLK_F_SIZE_MAX | VIRTIO_BLK_F_SEG_MAX | | | 272 | (VIRTIO_BLK_F_SIZE_MAX | VIRTIO_BLK_F_SEG_MAX | |
266 | VIRTIO_BLK_F_GEOMETRY | VIRTIO_BLK_F_RO | VIRTIO_BLK_F_BLK_SIZE), | | 273 | VIRTIO_BLK_F_GEOMETRY | VIRTIO_BLK_F_RO | VIRTIO_BLK_F_BLK_SIZE), |
267 | VIRTIO_BLK_FLAG_BITS); | | 274 | VIRTIO_BLK_FLAG_BITS); |
268 | | | 275 | |
269 | features = virtio_features(vsc); | | 276 | features = virtio_features(vsc); |
270 | | | 277 | |
271 | if (features & VIRTIO_BLK_F_RO) | | 278 | if (features & VIRTIO_BLK_F_RO) |
272 | sc->sc_readonly = 1; | | 279 | sc->sc_readonly = 1; |
273 | else | | 280 | else |
274 | sc->sc_readonly = 0; | | 281 | sc->sc_readonly = 0; |
275 | | | 282 | |
276 | if (features & VIRTIO_BLK_F_BLK_SIZE) { | | 283 | if (features & VIRTIO_BLK_F_BLK_SIZE) { |
277 | ld->sc_secsize = virtio_read_device_config_4(vsc, | | 284 | ld->sc_secsize = virtio_read_device_config_4(vsc, |
278 | VIRTIO_BLK_CONFIG_BLK_SIZE); | | 285 | VIRTIO_BLK_CONFIG_BLK_SIZE); |
279 | } else | | 286 | } else |
280 | ld->sc_secsize = 512; | | 287 | ld->sc_secsize = 512; |
281 | | | 288 | |
282 | /* At least genfs_io assumes maxxfer == MAXPHYS. */ | | 289 | /* At least genfs_io assumes maxxfer == MAXPHYS. */ |
283 | if (features & VIRTIO_BLK_F_SIZE_MAX) { | | 290 | if (features & VIRTIO_BLK_F_SIZE_MAX) { |
284 | maxxfersize = virtio_read_device_config_4(vsc, | | 291 | maxxfersize = virtio_read_device_config_4(vsc, |
285 | VIRTIO_BLK_CONFIG_SIZE_MAX); | | 292 | VIRTIO_BLK_CONFIG_SIZE_MAX); |
286 | if (maxxfersize < MAXPHYS) { | | 293 | if (maxxfersize < MAXPHYS) { |
287 | aprint_error_dev(sc->sc_dev, | | 294 | aprint_error_dev(sc->sc_dev, |
288 | "Too small SIZE_MAX %dK minimum is %dK\n", | | 295 | "Too small SIZE_MAX %dK minimum is %dK\n", |
289 | maxxfersize / 1024, MAXPHYS / 1024); | | 296 | maxxfersize / 1024, MAXPHYS / 1024); |
290 | // goto err; | | 297 | // goto err; |
291 | maxxfersize = MAXPHYS; | | 298 | maxxfersize = MAXPHYS; |
292 | } else if (maxxfersize > MAXPHYS) { | | 299 | } else if (maxxfersize > MAXPHYS) { |
293 | aprint_normal_dev(sc->sc_dev, | | 300 | aprint_normal_dev(sc->sc_dev, |
294 | "Clip SEG_MAX from %dK to %dK\n", | | 301 | "Clip SEG_MAX from %dK to %dK\n", |
295 | maxxfersize / 1024, | | 302 | maxxfersize / 1024, |
296 | MAXPHYS / 1024); | | 303 | MAXPHYS / 1024); |
297 | maxxfersize = MAXPHYS; | | 304 | maxxfersize = MAXPHYS; |
298 | } | | 305 | } |
299 | } else | | 306 | } else |
300 | maxxfersize = MAXPHYS; | | 307 | maxxfersize = MAXPHYS; |
301 | | | 308 | |
302 | if (features & VIRTIO_BLK_F_SEG_MAX) { | | 309 | if (features & VIRTIO_BLK_F_SEG_MAX) { |
303 | maxnsegs = virtio_read_device_config_4(vsc, | | 310 | maxnsegs = virtio_read_device_config_4(vsc, |
304 | VIRTIO_BLK_CONFIG_SEG_MAX); | | 311 | VIRTIO_BLK_CONFIG_SEG_MAX); |
305 | if (maxnsegs < VIRTIO_BLK_MIN_SEGMENTS) { | | 312 | if (maxnsegs < VIRTIO_BLK_MIN_SEGMENTS) { |
306 | aprint_error_dev(sc->sc_dev, | | 313 | aprint_error_dev(sc->sc_dev, |
307 | "Too small SEG_MAX %d minimum is %d\n", | | 314 | "Too small SEG_MAX %d minimum is %d\n", |
308 | maxnsegs, VIRTIO_BLK_MIN_SEGMENTS); | | 315 | maxnsegs, VIRTIO_BLK_MIN_SEGMENTS); |
309 | maxnsegs = maxxfersize / NBPG; | | 316 | maxnsegs = maxxfersize / NBPG; |
310 | // goto err; | | 317 | // goto err; |
311 | } | | 318 | } |
312 | } else | | 319 | } else |
313 | maxnsegs = maxxfersize / NBPG; | | 320 | maxnsegs = maxxfersize / NBPG; |
314 | | | 321 | |
315 | /* 2 for the minimum size */ | | 322 | /* 2 for the minimum size */ |
316 | maxnsegs += VIRTIO_BLK_MIN_SEGMENTS; | | 323 | maxnsegs += VIRTIO_BLK_MIN_SEGMENTS; |
317 | | | 324 | |
318 | if (virtio_alloc_vq(vsc, &sc->sc_vq, 0, maxxfersize, maxnsegs, | | 325 | if (virtio_alloc_vq(vsc, &sc->sc_vq, 0, maxxfersize, maxnsegs, |
319 | "I/O request") != 0) { | | 326 | "I/O request") != 0) { |
320 | goto err; | | 327 | goto err; |
321 | } | | 328 | } |
322 | qsize = sc->sc_vq.vq_num; | | 329 | qsize = sc->sc_vq.vq_num; |
323 | sc->sc_vq.vq_done = ld_virtio_vq_done; | | 330 | sc->sc_vq.vq_done = ld_virtio_vq_done; |
324 | | | 331 | |
325 | if (virtio_child_attach_finish(vsc) != 0) | | 332 | if (virtio_child_attach_finish(vsc) != 0) |
326 | goto err; | | 333 | goto err; |
327 | | | 334 | |
328 | ld->sc_dv = self; | | 335 | ld->sc_dv = self; |
329 | ld->sc_secperunit = virtio_read_device_config_8(vsc, | | 336 | ld->sc_secperunit = virtio_read_device_config_8(vsc, |
330 | VIRTIO_BLK_CONFIG_CAPACITY); | | 337 | VIRTIO_BLK_CONFIG_CAPACITY); |
331 | ld->sc_maxxfer = maxxfersize; | | 338 | ld->sc_maxxfer = maxxfersize; |
332 | if (features & VIRTIO_BLK_F_GEOMETRY) { | | 339 | if (features & VIRTIO_BLK_F_GEOMETRY) { |
333 | ld->sc_ncylinders = virtio_read_device_config_2(vsc, | | 340 | ld->sc_ncylinders = virtio_read_device_config_2(vsc, |
334 | VIRTIO_BLK_CONFIG_GEOMETRY_C); | | 341 | VIRTIO_BLK_CONFIG_GEOMETRY_C); |
335 | ld->sc_nheads = virtio_read_device_config_1(vsc, | | 342 | ld->sc_nheads = virtio_read_device_config_1(vsc, |
336 | VIRTIO_BLK_CONFIG_GEOMETRY_H); | | 343 | VIRTIO_BLK_CONFIG_GEOMETRY_H); |
337 | ld->sc_nsectors = virtio_read_device_config_1(vsc, | | 344 | ld->sc_nsectors = virtio_read_device_config_1(vsc, |
338 | VIRTIO_BLK_CONFIG_GEOMETRY_S); | | 345 | VIRTIO_BLK_CONFIG_GEOMETRY_S); |
339 | } | | 346 | } |
340 | ld->sc_maxqueuecnt = qsize; | | 347 | ld->sc_maxqueuecnt = qsize; |
341 | | | 348 | |
342 | if (ld_virtio_alloc_reqs(sc, qsize) < 0) | | 349 | if (ld_virtio_alloc_reqs(sc, qsize) < 0) |
343 | goto err; | | 350 | goto err; |
344 | | | 351 | |
345 | ld->sc_dump = ld_virtio_dump; | | 352 | ld->sc_dump = ld_virtio_dump; |
346 | ld->sc_start = ld_virtio_start; | | 353 | ld->sc_start = ld_virtio_start; |
347 | | | 354 | |
348 | ld->sc_flags = LDF_ENABLED | LDF_MPSAFE; | | 355 | ld->sc_flags = LDF_ENABLED | LDF_MPSAFE; |
349 | ldattach(ld, BUFQ_DISK_DEFAULT_STRAT); | | 356 | ldattach(ld, BUFQ_DISK_DEFAULT_STRAT); |
350 | | | 357 | |
351 | return; | | 358 | return; |
352 | | | 359 | |
353 | err: | | 360 | err: |
354 | virtio_child_attach_failed(vsc); | | 361 | virtio_child_attach_failed(vsc); |
355 | return; | | 362 | return; |
356 | } | | 363 | } |
357 | | | 364 | |
358 | static int | | 365 | static int |
359 | ld_virtio_start(struct ld_softc *ld, struct buf *bp) | | 366 | ld_virtio_start(struct ld_softc *ld, struct buf *bp) |
360 | { | | 367 | { |
361 | /* splbio */ | | 368 | /* splbio */ |
362 | struct ld_virtio_softc *sc = device_private(ld->sc_dv); | | 369 | struct ld_virtio_softc *sc = device_private(ld->sc_dv); |
363 | struct virtio_softc *vsc = sc->sc_virtio; | | 370 | struct virtio_softc *vsc = sc->sc_virtio; |
364 | struct virtqueue *vq = &sc->sc_vq; | | 371 | struct virtqueue *vq = &sc->sc_vq; |
365 | struct virtio_blk_req *vr; | | 372 | struct virtio_blk_req *vr; |
366 | int r; | | 373 | int r; |
367 | int isread = (bp->b_flags & B_READ); | | 374 | int isread = (bp->b_flags & B_READ); |
368 | int slot; | | 375 | int slot; |
369 | | | 376 | |
370 | if (sc->sc_readonly && !isread) | | 377 | if (sc->sc_readonly && !isread) |
371 | return EIO; | | 378 | return EIO; |
372 | | | 379 | |
373 | r = virtio_enqueue_prep(vsc, vq, &slot); | | 380 | r = virtio_enqueue_prep(vsc, vq, &slot); |
374 | if (r != 0) | | 381 | if (r != 0) |
375 | return r; | | 382 | return r; |
376 | | | 383 | |
377 | vr = &sc->sc_reqs[slot]; | | 384 | vr = &sc->sc_reqs[slot]; |
378 | KASSERT(vr->vr_bp == NULL); | | 385 | KASSERT(vr->vr_bp == NULL); |
379 | | | 386 | |
380 | r = bus_dmamap_load(virtio_dmat(vsc), vr->vr_payload, | | 387 | r = bus_dmamap_load(virtio_dmat(vsc), vr->vr_payload, |
381 | bp->b_data, bp->b_bcount, NULL, | | 388 | bp->b_data, bp->b_bcount, NULL, |
382 | ((isread?BUS_DMA_READ:BUS_DMA_WRITE) | | 389 | ((isread?BUS_DMA_READ:BUS_DMA_WRITE) |
383 | |BUS_DMA_NOWAIT)); | | 390 | |BUS_DMA_NOWAIT)); |
384 | if (r != 0) { | | 391 | if (r != 0) { |
385 | aprint_error_dev(sc->sc_dev, | | 392 | aprint_error_dev(sc->sc_dev, |
386 | "payload dmamap failed, error code %d\n", r); | | 393 | "payload dmamap failed, error code %d\n", r); |
387 | virtio_enqueue_abort(vsc, vq, slot); | | 394 | virtio_enqueue_abort(vsc, vq, slot); |
388 | return r; | | 395 | return r; |
389 | } | | 396 | } |
390 | | | 397 | |
391 | r = virtio_enqueue_reserve(vsc, vq, slot, vr->vr_payload->dm_nsegs + | | 398 | r = virtio_enqueue_reserve(vsc, vq, slot, vr->vr_payload->dm_nsegs + |
392 | VIRTIO_BLK_MIN_SEGMENTS); | | 399 | VIRTIO_BLK_MIN_SEGMENTS); |
393 | if (r != 0) { | | 400 | if (r != 0) { |
394 | bus_dmamap_unload(virtio_dmat(vsc), vr->vr_payload); | | 401 | bus_dmamap_unload(virtio_dmat(vsc), vr->vr_payload); |
395 | return r; | | 402 | return r; |
396 | } | | 403 | } |
397 | | | 404 | |
398 | vr->vr_bp = bp; | | 405 | vr->vr_bp = bp; |
399 | vr->vr_hdr.type = isread?VIRTIO_BLK_T_IN:VIRTIO_BLK_T_OUT; | | 406 | vr->vr_hdr.type = isread?VIRTIO_BLK_T_IN:VIRTIO_BLK_T_OUT; |
400 | vr->vr_hdr.ioprio = 0; | | 407 | vr->vr_hdr.ioprio = 0; |
401 | vr->vr_hdr.sector = bp->b_rawblkno * sc->sc_ld.sc_secsize / 512; | | 408 | vr->vr_hdr.sector = bp->b_rawblkno * sc->sc_ld.sc_secsize / 512; |
402 | | | 409 | |
403 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts, | | 410 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts, |
404 | 0, sizeof(struct virtio_blk_req_hdr), | | 411 | 0, sizeof(struct virtio_blk_req_hdr), |
405 | BUS_DMASYNC_PREWRITE); | | 412 | BUS_DMASYNC_PREWRITE); |
406 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_payload, | | 413 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_payload, |
407 | 0, bp->b_bcount, | | 414 | 0, bp->b_bcount, |
408 | isread?BUS_DMASYNC_PREREAD:BUS_DMASYNC_PREWRITE); | | 415 | isread?BUS_DMASYNC_PREREAD:BUS_DMASYNC_PREWRITE); |
409 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts, | | 416 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts, |
410 | offsetof(struct virtio_blk_req, vr_status), | | 417 | offsetof(struct virtio_blk_req, vr_status), |
411 | sizeof(uint8_t), | | 418 | sizeof(uint8_t), |
412 | BUS_DMASYNC_PREREAD); | | 419 | BUS_DMASYNC_PREREAD); |
413 | | | 420 | |
414 | virtio_enqueue_p(vsc, vq, slot, vr->vr_cmdsts, | | 421 | virtio_enqueue_p(vsc, vq, slot, vr->vr_cmdsts, |
415 | 0, sizeof(struct virtio_blk_req_hdr), | | 422 | 0, sizeof(struct virtio_blk_req_hdr), |
416 | true); | | 423 | true); |
417 | virtio_enqueue(vsc, vq, slot, vr->vr_payload, !isread); | | 424 | virtio_enqueue(vsc, vq, slot, vr->vr_payload, !isread); |
418 | virtio_enqueue_p(vsc, vq, slot, vr->vr_cmdsts, | | 425 | virtio_enqueue_p(vsc, vq, slot, vr->vr_cmdsts, |
419 | offsetof(struct virtio_blk_req, vr_status), | | 426 | offsetof(struct virtio_blk_req, vr_status), |
420 | sizeof(uint8_t), | | 427 | sizeof(uint8_t), |
421 | false); | | 428 | false); |
422 | virtio_enqueue_commit(vsc, vq, slot, true); | | 429 | virtio_enqueue_commit(vsc, vq, slot, true); |
423 | | | 430 | |
424 | return 0; | | 431 | return 0; |
425 | } | | 432 | } |
426 | | | 433 | |
427 | static void | | 434 | static void |
428 | ld_virtio_vq_done1(struct ld_virtio_softc *sc, struct virtio_softc *vsc, | | 435 | ld_virtio_vq_done1(struct ld_virtio_softc *sc, struct virtio_softc *vsc, |
429 | struct virtqueue *vq, int slot) | | 436 | struct virtqueue *vq, int slot) |
430 | { | | 437 | { |
431 | struct virtio_blk_req *vr = &sc->sc_reqs[slot]; | | 438 | struct virtio_blk_req *vr = &sc->sc_reqs[slot]; |
432 | struct buf *bp = vr->vr_bp; | | 439 | struct buf *bp = vr->vr_bp; |
433 | | | 440 | |
434 | vr->vr_bp = NULL; | | 441 | vr->vr_bp = NULL; |
435 | | | 442 | |
436 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts, | | 443 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts, |
437 | 0, sizeof(struct virtio_blk_req_hdr), | | 444 | 0, sizeof(struct virtio_blk_req_hdr), |
438 | BUS_DMASYNC_POSTWRITE); | | 445 | BUS_DMASYNC_POSTWRITE); |
439 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_payload, | | 446 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_payload, |
440 | 0, bp->b_bcount, | | 447 | 0, bp->b_bcount, |
441 | (bp->b_flags & B_READ)?BUS_DMASYNC_POSTREAD | | 448 | (bp->b_flags & B_READ)?BUS_DMASYNC_POSTREAD |
442 | :BUS_DMASYNC_POSTWRITE); | | 449 | :BUS_DMASYNC_POSTWRITE); |
443 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts, | | 450 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts, |
444 | sizeof(struct virtio_blk_req_hdr), sizeof(uint8_t), | | 451 | sizeof(struct virtio_blk_req_hdr), sizeof(uint8_t), |
445 | BUS_DMASYNC_POSTREAD); | | 452 | BUS_DMASYNC_POSTREAD); |
446 | | | 453 | |
447 | if (vr->vr_status != VIRTIO_BLK_S_OK) { | | 454 | if (vr->vr_status != VIRTIO_BLK_S_OK) { |
448 | bp->b_error = EIO; | | 455 | bp->b_error = EIO; |
449 | bp->b_resid = bp->b_bcount; | | 456 | bp->b_resid = bp->b_bcount; |
450 | } else { | | 457 | } else { |
451 | bp->b_error = 0; | | 458 | bp->b_error = 0; |
452 | bp->b_resid = 0; | | 459 | bp->b_resid = 0; |
453 | } | | 460 | } |
454 | | | 461 | |
455 | virtio_dequeue_commit(vsc, vq, slot); | | 462 | virtio_dequeue_commit(vsc, vq, slot); |
456 | | | 463 | |
457 | lddone(&sc->sc_ld, bp); | | 464 | lddone(&sc->sc_ld, bp); |
458 | } | | 465 | } |
459 | | | 466 | |
460 | static int | | 467 | static int |
461 | ld_virtio_vq_done(struct virtqueue *vq) | | 468 | ld_virtio_vq_done(struct virtqueue *vq) |
462 | { | | 469 | { |
463 | struct virtio_softc *vsc = vq->vq_owner; | | 470 | struct virtio_softc *vsc = vq->vq_owner; |
464 | struct ld_virtio_softc *sc = device_private(virtio_child(vsc)); | | 471 | struct ld_virtio_softc *sc = device_private(virtio_child(vsc)); |
465 | int r = 0; | | 472 | int r = 0; |
466 | int slot; | | 473 | int slot; |
467 | | | 474 | |
468 | again: | | 475 | again: |
469 | if (virtio_dequeue(vsc, vq, &slot, NULL)) | | 476 | if (virtio_dequeue(vsc, vq, &slot, NULL)) |
470 | return r; | | 477 | return r; |
471 | r = 1; | | 478 | r = 1; |
472 | | | 479 | |
473 | ld_virtio_vq_done1(sc, vsc, vq, slot); | | 480 | ld_virtio_vq_done1(sc, vsc, vq, slot); |
474 | goto again; | | 481 | goto again; |
475 | } | | 482 | } |
476 | | | 483 | |
477 | static int | | 484 | static int |
478 | ld_virtio_dump(struct ld_softc *ld, void *data, int blkno, int blkcnt) | | 485 | ld_virtio_dump(struct ld_softc *ld, void *data, int blkno, int blkcnt) |
479 | { | | 486 | { |
480 | struct ld_virtio_softc *sc = device_private(ld->sc_dv); | | 487 | struct ld_virtio_softc *sc = device_private(ld->sc_dv); |
481 | struct virtio_softc *vsc = sc->sc_virtio; | | 488 | struct virtio_softc *vsc = sc->sc_virtio; |
482 | struct virtqueue *vq = &sc->sc_vq; | | 489 | struct virtqueue *vq = &sc->sc_vq; |
483 | struct virtio_blk_req *vr; | | 490 | struct virtio_blk_req *vr; |
484 | int slot, r; | | 491 | int slot, r; |
485 | | | 492 | |
486 | if (sc->sc_readonly) | | 493 | if (sc->sc_readonly) |
487 | return EIO; | | 494 | return EIO; |
488 | | | 495 | |
489 | r = virtio_enqueue_prep(vsc, vq, &slot); | | 496 | r = virtio_enqueue_prep(vsc, vq, &slot); |
490 | if (r != 0) { | | 497 | if (r != 0) { |
491 | if (r == EAGAIN) { /* no free slot; dequeue first */ | | 498 | if (r == EAGAIN) { /* no free slot; dequeue first */ |
492 | delay(100); | | 499 | delay(100); |
493 | ld_virtio_vq_done(vq); | | 500 | ld_virtio_vq_done(vq); |
494 | r = virtio_enqueue_prep(vsc, vq, &slot); | | 501 | r = virtio_enqueue_prep(vsc, vq, &slot); |
495 | if (r != 0) | | 502 | if (r != 0) |
496 | return r; | | 503 | return r; |
497 | } | | 504 | } |
498 | return r; | | 505 | return r; |
499 | } | | 506 | } |
500 | vr = &sc->sc_reqs[slot]; | | 507 | vr = &sc->sc_reqs[slot]; |
501 | r = bus_dmamap_load(virtio_dmat(vsc), vr->vr_payload, | | 508 | r = bus_dmamap_load(virtio_dmat(vsc), vr->vr_payload, |
502 | data, blkcnt*ld->sc_secsize, NULL, | | 509 | data, blkcnt*ld->sc_secsize, NULL, |
503 | BUS_DMA_WRITE|BUS_DMA_NOWAIT); | | 510 | BUS_DMA_WRITE|BUS_DMA_NOWAIT); |
504 | if (r != 0) | | 511 | if (r != 0) |
505 | return r; | | 512 | return r; |
506 | | | 513 | |
507 | r = virtio_enqueue_reserve(vsc, vq, slot, vr->vr_payload->dm_nsegs + | | 514 | r = virtio_enqueue_reserve(vsc, vq, slot, vr->vr_payload->dm_nsegs + |
508 | VIRTIO_BLK_MIN_SEGMENTS); | | 515 | VIRTIO_BLK_MIN_SEGMENTS); |
509 | if (r != 0) { | | 516 | if (r != 0) { |
510 | bus_dmamap_unload(virtio_dmat(vsc), vr->vr_payload); | | 517 | bus_dmamap_unload(virtio_dmat(vsc), vr->vr_payload); |
511 | return r; | | 518 | return r; |
512 | } | | 519 | } |
513 | | | 520 | |
514 | vr->vr_bp = (void*)0xdeadbeef; | | 521 | vr->vr_bp = (void*)0xdeadbeef; |
515 | vr->vr_hdr.type = VIRTIO_BLK_T_OUT; | | 522 | vr->vr_hdr.type = VIRTIO_BLK_T_OUT; |
516 | vr->vr_hdr.ioprio = 0; | | 523 | vr->vr_hdr.ioprio = 0; |
517 | vr->vr_hdr.sector = (daddr_t) blkno * ld->sc_secsize / 512; | | 524 | vr->vr_hdr.sector = (daddr_t) blkno * ld->sc_secsize / 512; |
518 | | | 525 | |
519 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts, | | 526 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts, |
520 | 0, sizeof(struct virtio_blk_req_hdr), | | 527 | 0, sizeof(struct virtio_blk_req_hdr), |
521 | BUS_DMASYNC_PREWRITE); | | 528 | BUS_DMASYNC_PREWRITE); |
522 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_payload, | | 529 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_payload, |
523 | 0, blkcnt*ld->sc_secsize, | | 530 | 0, blkcnt*ld->sc_secsize, |
524 | BUS_DMASYNC_PREWRITE); | | 531 | BUS_DMASYNC_PREWRITE); |
525 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts, | | 532 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts, |
526 | offsetof(struct virtio_blk_req, vr_status), | | 533 | offsetof(struct virtio_blk_req, vr_status), |
527 | sizeof(uint8_t), | | 534 | sizeof(uint8_t), |
528 | BUS_DMASYNC_PREREAD); | | 535 | BUS_DMASYNC_PREREAD); |
529 | | | 536 | |
530 | virtio_enqueue_p(vsc, vq, slot, vr->vr_cmdsts, | | 537 | virtio_enqueue_p(vsc, vq, slot, vr->vr_cmdsts, |
531 | 0, sizeof(struct virtio_blk_req_hdr), | | 538 | 0, sizeof(struct virtio_blk_req_hdr), |
532 | true); | | 539 | true); |
533 | virtio_enqueue(vsc, vq, slot, vr->vr_payload, true); | | 540 | virtio_enqueue(vsc, vq, slot, vr->vr_payload, true); |
534 | virtio_enqueue_p(vsc, vq, slot, vr->vr_cmdsts, | | 541 | virtio_enqueue_p(vsc, vq, slot, vr->vr_cmdsts, |
535 | offsetof(struct virtio_blk_req, vr_status), | | 542 | offsetof(struct virtio_blk_req, vr_status), |
536 | sizeof(uint8_t), | | 543 | sizeof(uint8_t), |
537 | false); | | 544 | false); |
538 | virtio_enqueue_commit(vsc, vq, slot, true); | | 545 | virtio_enqueue_commit(vsc, vq, slot, true); |
539 | | | 546 | |
540 | for ( ; ; ) { | | 547 | for ( ; ; ) { |
541 | int dslot; | | 548 | int dslot; |
542 | | | 549 | |
543 | r = virtio_dequeue(vsc, vq, &dslot, NULL); | | 550 | r = virtio_dequeue(vsc, vq, &dslot, NULL); |
544 | if (r != 0) | | 551 | if (r != 0) |
545 | continue; | | 552 | continue; |
546 | if (dslot != slot) { | | 553 | if (dslot != slot) { |
547 | ld_virtio_vq_done1(sc, vsc, vq, dslot); | | 554 | ld_virtio_vq_done1(sc, vsc, vq, dslot); |
548 | continue; | | 555 | continue; |
549 | } else | | 556 | } else |
550 | break; | | 557 | break; |
551 | } | | 558 | } |
552 | | | 559 | |
553 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts, | | 560 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts, |
554 | 0, sizeof(struct virtio_blk_req_hdr), | | 561 | 0, sizeof(struct virtio_blk_req_hdr), |
555 | BUS_DMASYNC_POSTWRITE); | | 562 | BUS_DMASYNC_POSTWRITE); |
556 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_payload, | | 563 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_payload, |
557 | 0, blkcnt*ld->sc_secsize, | | 564 | 0, blkcnt*ld->sc_secsize, |
558 | BUS_DMASYNC_POSTWRITE); | | 565 | BUS_DMASYNC_POSTWRITE); |
559 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts, | | 566 | bus_dmamap_sync(virtio_dmat(vsc), vr->vr_cmdsts, |
560 | offsetof(struct virtio_blk_req, vr_status), | | 567 | offsetof(struct virtio_blk_req, vr_status), |
561 | sizeof(uint8_t), | | 568 | sizeof(uint8_t), |
562 | BUS_DMASYNC_POSTREAD); | | 569 | BUS_DMASYNC_POSTREAD); |
563 | if (vr->vr_status == VIRTIO_BLK_S_OK) | | 570 | if (vr->vr_status == VIRTIO_BLK_S_OK) |
564 | r = 0; | | 571 | r = 0; |
565 | else | | 572 | else |
566 | r = EIO; | | 573 | r = EIO; |
567 | virtio_dequeue_commit(vsc, vq, slot); | | 574 | virtio_dequeue_commit(vsc, vq, slot); |
568 | | | 575 | |
569 | return r; | | 576 | return r; |
570 | } | | 577 | } |
571 | | | 578 | |
572 | static int | | 579 | static int |
573 | ld_virtio_detach(device_t self, int flags) | | 580 | ld_virtio_detach(device_t self, int flags) |
574 | { | | 581 | { |
575 | struct ld_virtio_softc *sc = device_private(self); | | 582 | struct ld_virtio_softc *sc = device_private(self); |
576 | struct ld_softc *ld = &sc->sc_ld; | | 583 | struct ld_softc *ld = &sc->sc_ld; |
577 | bus_dma_tag_t dmat = virtio_dmat(sc->sc_virtio); | | 584 | bus_dma_tag_t dmat = virtio_dmat(sc->sc_virtio); |
578 | int r, i, qsize; | | 585 | int r, i, qsize; |
579 | | | 586 | |
580 | qsize = sc->sc_vq.vq_num; | | 587 | qsize = sc->sc_vq.vq_num; |
581 | r = ldbegindetach(ld, flags); | | 588 | r = ldbegindetach(ld, flags); |
582 | if (r != 0) | | 589 | if (r != 0) |
583 | return r; | | 590 | return r; |
584 | virtio_reset(sc->sc_virtio); | | 591 | virtio_reset(sc->sc_virtio); |
585 | virtio_free_vq(sc->sc_virtio, &sc->sc_vq); | | 592 | virtio_free_vq(sc->sc_virtio, &sc->sc_vq); |
586 | | | 593 | |
587 | for (i = 0; i < qsize; i++) { | | 594 | for (i = 0; i < qsize; i++) { |
588 | bus_dmamap_destroy(dmat, | | 595 | bus_dmamap_destroy(dmat, |
589 | sc->sc_reqs[i].vr_cmdsts); | | 596 | sc->sc_reqs[i].vr_cmdsts); |
590 | bus_dmamap_destroy(dmat, | | 597 | bus_dmamap_destroy(dmat, |
591 | sc->sc_reqs[i].vr_payload); | | 598 | sc->sc_reqs[i].vr_payload); |
592 | } | | 599 | } |
593 | bus_dmamem_unmap(dmat, sc->sc_reqs, | | 600 | bus_dmamem_unmap(dmat, sc->sc_reqs, |
594 | sizeof(struct virtio_blk_req) * qsize); | | 601 | sizeof(struct virtio_blk_req) * qsize); |
595 | bus_dmamem_free(dmat, &sc->sc_reqs_seg, 1); | | 602 | bus_dmamem_free(dmat, &sc->sc_reqs_seg, 1); |
596 | | | 603 | |
597 | ldenddetach(ld); | | 604 | ldenddetach(ld); |
598 | | | 605 | |
599 | virtio_child_detach(sc->sc_virtio); | | 606 | virtio_child_detach(sc->sc_virtio); |
600 | | | 607 | |
601 | return 0; | | 608 | return 0; |
602 | } | | 609 | } |
603 | | | 610 | |
604 | MODULE(MODULE_CLASS_DRIVER, ld_virtio, "ld,virtio"); | | 611 | MODULE(MODULE_CLASS_DRIVER, ld_virtio, "ld,virtio"); |
605 | | | 612 | |
606 | #ifdef _MODULE | | 613 | #ifdef _MODULE |
607 | /* | | 614 | /* |
608 | * XXX Don't allow ioconf.c to redefine the "struct cfdriver ld_cd" | | 615 | * XXX Don't allow ioconf.c to redefine the "struct cfdriver ld_cd" |
609 | * XXX it will be defined in the common-code module | | 616 | * XXX it will be defined in the common-code module |
610 | */ | | 617 | */ |
611 | #undef CFDRIVER_DECL | | 618 | #undef CFDRIVER_DECL |
612 | #define CFDRIVER_DECL(name, class, attr) | | 619 | #define CFDRIVER_DECL(name, class, attr) |
613 | #include "ioconf.c" | | 620 | #include "ioconf.c" |
614 | #endif | | 621 | #endif |
615 | | | 622 | |
616 | static int | | 623 | static int |
617 | ld_virtio_modcmd(modcmd_t cmd, void *opaque) | | 624 | ld_virtio_modcmd(modcmd_t cmd, void *opaque) |
618 | { | | 625 | { |
619 | #ifdef _MODULE | | 626 | #ifdef _MODULE |
620 | /* | | 627 | /* |
621 | * We ignore the cfdriver_vec[] that ioconf provides, since | | 628 | * We ignore the cfdriver_vec[] that ioconf provides, since |
622 | * the cfdrivers are attached already. | | 629 | * the cfdrivers are attached already. |
623 | */ | | 630 | */ |
624 | static struct cfdriver * const no_cfdriver_vec[] = { NULL }; | | 631 | static struct cfdriver * const no_cfdriver_vec[] = { NULL }; |
625 | #endif | | 632 | #endif |
626 | int error = 0; | | 633 | int error = 0; |
627 | | | 634 | |
628 | #ifdef _MODULE | | 635 | #ifdef _MODULE |
629 | switch (cmd) { | | 636 | switch (cmd) { |
630 | case MODULE_CMD_INIT: | | 637 | case MODULE_CMD_INIT: |
631 | error = config_init_component(no_cfdriver_vec, | | 638 | error = config_init_component(no_cfdriver_vec, |
632 | cfattach_ioconf_ld_virtio, cfdata_ioconf_ld_virtio); | | 639 | cfattach_ioconf_ld_virtio, cfdata_ioconf_ld_virtio); |
633 | break; | | 640 | break; |
634 | case MODULE_CMD_FINI: | | 641 | case MODULE_CMD_FINI: |
635 | error = config_fini_component(no_cfdriver_vec, | | 642 | error = config_fini_component(no_cfdriver_vec, |
636 | cfattach_ioconf_ld_virtio, cfdata_ioconf_ld_virtio); | | 643 | cfattach_ioconf_ld_virtio, cfdata_ioconf_ld_virtio); |
637 | break; | | 644 | break; |
638 | default: | | 645 | default: |
639 | error = ENOTTY; | | 646 | error = ENOTTY; |
640 | break; | | 647 | break; |
641 | } | | 648 | } |
642 | #endif | | 649 | #endif |
643 | | | 650 | |
644 | return error; | | 651 | return error; |
645 | } | | 652 | } |