| @@ -1,316 +1,306 @@ | | | @@ -1,316 +1,306 @@ |
1 | /* $NetBSD: xmd.c,v 1.1.2.4 2010/08/28 16:27:02 uebayasi Exp $ */ | | 1 | /* $NetBSD: xmd.c,v 1.1.2.5 2010/10/30 08:51:10 uebayasi Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2010 Tsubai Masanari. All rights reserved. | | 4 | * Copyright (c) 2010 Tsubai Masanari. All rights reserved. |
5 | * Copyright (c) 2010 Masao Uebayashi. All rights reserved. | | 5 | * Copyright (c) 2010 Masao Uebayashi. 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 | * 3. The name of the author may not be used to endorse or promote products | | 15 | * 3. The name of the author may not be used to endorse or promote products |
16 | * derived from this software without specific prior written permission. | | 16 | * derived from this software without specific prior written permission. |
17 | * | | 17 | * |
18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | | 21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | | 22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | | 23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | | 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | | 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | | 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | | 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | */ | | 28 | */ |
29 | | | 29 | |
30 | #include <sys/cdefs.h> | | 30 | #include <sys/cdefs.h> |
31 | __KERNEL_RCSID(0, "$NetBSD: xmd.c,v 1.1.2.4 2010/08/28 16:27:02 uebayasi Exp $"); | | 31 | __KERNEL_RCSID(0, "$NetBSD: xmd.c,v 1.1.2.5 2010/10/30 08:51:10 uebayasi Exp $"); |
32 | | | 32 | |
33 | #include "opt_xip.h" | | 33 | #include "opt_xip.h" |
34 | #include "opt_xmd.h" | | 34 | #include "opt_xmd.h" |
35 | | | 35 | |
36 | #ifndef XIP | | | |
37 | #error xmd(4) needs options XIP | | | |
38 | #endif | | | |
39 | | | | |
40 | #include <sys/param.h> | | 36 | #include <sys/param.h> |
41 | #include <sys/bus.h> | | 37 | #include <sys/bus.h> |
42 | #include <sys/conf.h> | | 38 | #include <sys/conf.h> |
43 | #include <sys/ioctl.h> | | 39 | #include <sys/ioctl.h> |
44 | #include <sys/kmem.h> | | 40 | #include <sys/kmem.h> |
45 | #include <sys/buf.h> | | 41 | #include <sys/buf.h> |
46 | #include <sys/bufq.h> | | 42 | #include <sys/bufq.h> |
47 | #include <sys/device.h> | | 43 | #include <sys/device.h> |
48 | #include <sys/disk.h> | | 44 | #include <sys/disk.h> |
49 | #include <sys/disklabel.h> | | 45 | #include <sys/disklabel.h> |
50 | #include <sys/stat.h> | | 46 | #include <sys/stat.h> |
51 | #include <sys/mman.h> | | 47 | #include <sys/mman.h> |
52 | #include <sys/kmem.h> | | 48 | #include <sys/kmem.h> |
53 | | | 49 | |
54 | #include <machine/vmparam.h> | | 50 | #include <machine/vmparam.h> |
55 | | | 51 | |
56 | #include <dev/xmdvar.h> | | 52 | #include <uvm/uvm_extern.h> |
57 | | | 53 | |
58 | struct xmd_softc { | | 54 | struct xmd_softc { |
59 | vaddr_t sc_addr; | | 55 | vaddr_t sc_addr; |
60 | size_t sc_size; | | 56 | size_t sc_size; |
61 | | | 57 | |
62 | void *sc_phys; | | 58 | void *sc_phys; |
63 | | | 59 | |
64 | struct disk sc_dkdev; | | 60 | struct disk sc_dkdev; |
65 | struct bufq_state *sc_buflist; | | 61 | struct bufq_state *sc_buflist; |
66 | }; | | 62 | }; |
67 | | | 63 | |
68 | void xmdattach(int); | | 64 | void xmdattach(int); |
69 | static void xmd_attach(device_t, device_t, void *); | | 65 | static void xmd_attach(device_t, device_t, void *); |
70 | static int xmd_detach(device_t, int); | | 66 | static int xmd_detach(device_t, int); |
71 | static dev_type_open(xmd_open); | | 67 | static dev_type_open(xmd_open); |
72 | static dev_type_close(xmd_close); | | 68 | static dev_type_close(xmd_close); |
73 | static dev_type_ioctl(xmd_ioctl); | | 69 | static dev_type_ioctl(xmd_ioctl); |
74 | static dev_type_read(xmd_read); | | 70 | static dev_type_read(xmd_read); |
75 | static dev_type_mmap(xmd_mmap); | | 71 | static dev_type_mmap(xmd_mmap); |
76 | static dev_type_strategy(xmd_strategy); | | 72 | static dev_type_strategy(xmd_strategy); |
77 | static dev_type_size(xmd_size); | | 73 | static dev_type_size(xmd_size); |
78 | | | 74 | |
79 | struct bdevsw xmd_bdevsw = { | | 75 | struct bdevsw xmd_bdevsw = { |
80 | xmd_open, xmd_close, xmd_strategy, xmd_ioctl, | | 76 | xmd_open, xmd_close, xmd_strategy, xmd_ioctl, |
81 | nodump, xmd_size, D_DISK | D_MPSAFE | | 77 | nodump, xmd_size, D_DISK | D_MPSAFE |
82 | }; | | 78 | }; |
83 | | | 79 | |
84 | struct cdevsw xmd_cdevsw = { | | 80 | struct cdevsw xmd_cdevsw = { |
85 | xmd_open, xmd_close, xmd_read, nowrite, xmd_ioctl, | | 81 | xmd_open, xmd_close, xmd_read, nowrite, xmd_ioctl, |
86 | nostop, notty, nopoll, xmd_mmap, nokqfilter, D_DISK | D_MPSAFE | | 82 | nostop, notty, nopoll, xmd_mmap, nokqfilter, D_DISK | D_MPSAFE |
87 | }; | | 83 | }; |
88 | | | 84 | |
89 | extern struct cfdriver xmd_cd; | | 85 | extern struct cfdriver xmd_cd; |
90 | CFATTACH_DECL3_NEW(xmd, sizeof(struct xmd_softc), | | 86 | CFATTACH_DECL3_NEW(xmd, sizeof(struct xmd_softc), |
91 | NULL, xmd_attach, xmd_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN); | | 87 | NULL, xmd_attach, xmd_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN); |
92 | | | 88 | |
93 | const char md_root_image[XMD_ROOT_SIZE << DEV_BSHIFT] __aligned(PAGE_SIZE) = | | 89 | const char md_root_image[XMD_ROOT_SIZE << DEV_BSHIFT] __aligned(PAGE_SIZE) = |
94 | "|This is the root ramdisk!\n"; | | 90 | "|This is the root ramdisk!\n"; |
95 | const size_t md_root_size = XMD_ROOT_SIZE << DEV_BSHIFT; | | 91 | const size_t md_root_size = XMD_ROOT_SIZE << DEV_BSHIFT; |
96 | | | 92 | |
97 | void | | 93 | void |
98 | xmdattach(int n) | | 94 | xmdattach(int n) |
99 | { | | 95 | { |
100 | int i; | | 96 | int i; |
101 | cfdata_t cf; | | 97 | cfdata_t cf; |
102 | | | 98 | |
103 | if (config_cfattach_attach("xmd", &xmd_ca)) { | | 99 | if (config_cfattach_attach("xmd", &xmd_ca)) { |
104 | aprint_error("xmd: cfattach_attach failed\n"); | | 100 | aprint_error("xmd: cfattach_attach failed\n"); |
105 | return; | | 101 | return; |
106 | } | | 102 | } |
107 | | | 103 | |
108 | /* XXX Support single instance for now. */ | | 104 | /* XXX Support single instance for now. */ |
109 | KASSERT(n == 1); | | 105 | KASSERT(n == 1); |
110 | | | 106 | |
111 | for (i = 0; i < n; i++) { | | 107 | for (i = 0; i < n; i++) { |
112 | cf = kmem_alloc(sizeof(*cf), KM_SLEEP); | | 108 | cf = kmem_alloc(sizeof(*cf), KM_SLEEP); |
113 | KASSERT(cf != NULL); | | 109 | KASSERT(cf != NULL); |
114 | cf->cf_name = "xmd"; | | 110 | cf->cf_name = "xmd"; |
115 | cf->cf_atname = "xmd"; | | 111 | cf->cf_atname = "xmd"; |
116 | cf->cf_unit = i; | | 112 | cf->cf_unit = i; |
117 | cf->cf_fstate = FSTATE_NOTFOUND; | | 113 | cf->cf_fstate = FSTATE_NOTFOUND; |
118 | (void)config_attach_pseudo(cf); | | 114 | (void)config_attach_pseudo(cf); |
119 | } | | 115 | } |
120 | } | | 116 | } |
121 | | | 117 | |
122 | static void | | 118 | static void |
123 | xmd_attach(device_t parent, device_t self, void *aux) | | 119 | xmd_attach(device_t parent, device_t self, void *aux) |
124 | { | | 120 | { |
125 | struct xmd_softc *sc = device_private(self); | | 121 | struct xmd_softc *sc = device_private(self); |
126 | | | 122 | |
127 | sc->sc_addr = (vaddr_t)md_root_image; | | 123 | sc->sc_addr = (vaddr_t)md_root_image; |
128 | sc->sc_size = (size_t)md_root_size; | | 124 | sc->sc_size = (size_t)md_root_size; |
129 | | | 125 | |
130 | #ifdef XIP | | 126 | sc->sc_phys = pmap_physload_device(sc->sc_addr, sc->sc_size, PROT_READ, 0); |
131 | sc->sc_phys = xmd_machdep_physload(sc->sc_addr, sc->sc_size); | | | |
132 | #endif | | | |
133 | | | 127 | |
134 | disk_init(&sc->sc_dkdev, device_xname(self), NULL); | | 128 | disk_init(&sc->sc_dkdev, device_xname(self), NULL); |
135 | disk_attach(&sc->sc_dkdev); | | 129 | disk_attach(&sc->sc_dkdev); |
136 | | | 130 | |
137 | if (!pmf_device_register(self, NULL, NULL)) | | 131 | if (!pmf_device_register(self, NULL, NULL)) |
138 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 132 | aprint_error_dev(self, "couldn't establish power handler\n"); |
139 | } | | 133 | } |
140 | | | 134 | |
141 | static int | | 135 | static int |
142 | xmd_detach(device_t self, int flags) | | 136 | xmd_detach(device_t self, int flags) |
143 | { | | 137 | { |
144 | struct xmd_softc *sc = device_private(self); | | 138 | struct xmd_softc *sc = device_private(self); |
145 | int rc; | | 139 | int rc; |
146 | | | 140 | |
147 | rc = 0; | | 141 | rc = 0; |
148 | mutex_enter(&sc->sc_dkdev.dk_openlock); | | 142 | mutex_enter(&sc->sc_dkdev.dk_openlock); |
149 | if (sc->sc_dkdev.dk_openmask == 0) | | 143 | if (sc->sc_dkdev.dk_openmask == 0) |
150 | ; /* nothing to do */ | | 144 | ; /* nothing to do */ |
151 | else if ((flags & DETACH_FORCE) == 0) | | 145 | else if ((flags & DETACH_FORCE) == 0) |
152 | rc = EBUSY; | | 146 | rc = EBUSY; |
153 | mutex_exit(&sc->sc_dkdev.dk_openlock); | | 147 | mutex_exit(&sc->sc_dkdev.dk_openlock); |
154 | | | 148 | |
155 | if (rc != 0) | | 149 | if (rc != 0) |
156 | return rc; | | 150 | return rc; |
157 | | | 151 | |
158 | pmf_device_deregister(self); | | 152 | pmf_device_deregister(self); |
159 | disk_detach(&sc->sc_dkdev); | | 153 | disk_detach(&sc->sc_dkdev); |
160 | disk_destroy(&sc->sc_dkdev); | | 154 | disk_destroy(&sc->sc_dkdev); |
161 | | | 155 | |
162 | #ifdef XIP | | 156 | pmap_physunload_device(sc->sc_phys); |
163 | xmd_machdep_physunload(sc->sc_phys); | | | |
164 | #endif | | | |
165 | | | 157 | |
166 | return 0; | | 158 | return 0; |
167 | } | | 159 | } |
168 | | | 160 | |
169 | static int | | 161 | static int |
170 | xmd_open(dev_t dev, int flags, int fmt, struct lwp *l) | | 162 | xmd_open(dev_t dev, int flags, int fmt, struct lwp *l) |
171 | { | | 163 | { |
172 | struct xmd_softc *sc = device_lookup_private(&xmd_cd, DISKUNIT(dev)); | | 164 | struct xmd_softc *sc = device_lookup_private(&xmd_cd, DISKUNIT(dev)); |
173 | struct disk *dk = &sc->sc_dkdev; | | 165 | struct disk *dk = &sc->sc_dkdev; |
174 | const int part = DISKUNIT(dev); | | 166 | const int part = DISKUNIT(dev); |
175 | const int pmask = 1 << part; | | 167 | const int pmask = 1 << part; |
176 | | | 168 | |
177 | if (sc == NULL) | | 169 | if (sc == NULL) |
178 | return ENXIO; | | 170 | return ENXIO; |
179 | | | 171 | |
180 | mutex_enter(&dk->dk_openlock); | | 172 | mutex_enter(&dk->dk_openlock); |
181 | switch (fmt) { | | 173 | switch (fmt) { |
182 | case S_IFCHR: | | 174 | case S_IFCHR: |
183 | dk->dk_copenmask |= pmask; | | 175 | dk->dk_copenmask |= pmask; |
184 | break; | | 176 | break; |
185 | case S_IFBLK: | | 177 | case S_IFBLK: |
186 | dk->dk_bopenmask |= pmask; | | 178 | dk->dk_bopenmask |= pmask; |
187 | break; | | 179 | break; |
188 | } | | 180 | } |
189 | dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask; | | 181 | dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask; |
190 | mutex_exit(&dk->dk_openlock); | | 182 | mutex_exit(&dk->dk_openlock); |
191 | | | 183 | |
192 | return 0; | | 184 | return 0; |
193 | } | | 185 | } |
194 | | | 186 | |
195 | static int | | 187 | static int |
196 | xmd_close(dev_t dev, int flags, int fmt, struct lwp *l) | | 188 | xmd_close(dev_t dev, int flags, int fmt, struct lwp *l) |
197 | { | | 189 | { |
198 | | | 190 | |
199 | return 0; | | 191 | return 0; |
200 | } | | 192 | } |
201 | | | 193 | |
202 | int | | 194 | int |
203 | xmd_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) | | 195 | xmd_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) |
204 | { | | 196 | { |
205 | struct xmd_softc *sc = device_lookup_private(&xmd_cd, DISKUNIT(dev)); | | 197 | struct xmd_softc *sc = device_lookup_private(&xmd_cd, DISKUNIT(dev)); |
206 | const int part = DISKUNIT(dev); | | 198 | const int part = DISKUNIT(dev); |
207 | int error = 0; | | 199 | int error = 0; |
208 | | | 200 | |
209 | if (sc == NULL) | | 201 | if (sc == NULL) |
210 | return -1; | | 202 | return -1; |
211 | | | 203 | |
212 | switch (cmd) { | | 204 | switch (cmd) { |
213 | #ifdef XIP | | | |
214 | case DIOCGPHYSSEG: | | 205 | case DIOCGPHYSSEG: |
215 | if (sc->sc_phys == NULL) | | 206 | if (sc->sc_phys == NULL) |
216 | error = EINVAL; | | 207 | error = EINVAL; |
217 | else | | 208 | else |
218 | *(void **)data = sc->sc_phys; | | 209 | *(void **)data = sc->sc_phys; |
219 | break; | | 210 | break; |
220 | #endif | | | |
221 | | | 211 | |
222 | case DIOCGDINFO: | | 212 | case DIOCGDINFO: |
223 | *(struct disklabel *)data = *sc->sc_dkdev.dk_label; | | 213 | *(struct disklabel *)data = *sc->sc_dkdev.dk_label; |
224 | break; | | 214 | break; |
225 | | | 215 | |
226 | case DIOCGPART: | | 216 | case DIOCGPART: |
227 | ((struct partinfo *)data)->disklab = sc->sc_dkdev.dk_label; | | 217 | ((struct partinfo *)data)->disklab = sc->sc_dkdev.dk_label; |
228 | ((struct partinfo *)data)->part = | | 218 | ((struct partinfo *)data)->part = |
229 | &sc->sc_dkdev.dk_label->d_partitions[part]; | | 219 | &sc->sc_dkdev.dk_label->d_partitions[part]; |
230 | break; | | 220 | break; |
231 | | | 221 | |
232 | default: | | 222 | default: |
233 | error = EINVAL; | | 223 | error = EINVAL; |
234 | break; | | 224 | break; |
235 | } | | 225 | } |
236 | | | 226 | |
237 | return error; | | 227 | return error; |
238 | } | | 228 | } |
239 | | | 229 | |
240 | static int | | 230 | static int |
241 | xmd_read(dev_t dev, struct uio *uio, int flags) | | 231 | xmd_read(dev_t dev, struct uio *uio, int flags) |
242 | { | | 232 | { |
243 | struct xmd_softc *sc; | | 233 | struct xmd_softc *sc; |
244 | | | 234 | |
245 | sc = device_lookup_private(&xmd_cd, DISKUNIT(dev)); | | 235 | sc = device_lookup_private(&xmd_cd, DISKUNIT(dev)); |
246 | | | 236 | |
247 | if (sc == NULL) | | 237 | if (sc == NULL) |
248 | return ENXIO; | | 238 | return ENXIO; |
249 | | | 239 | |
250 | return physio(xmd_strategy, NULL, dev, B_READ, minphys, uio); | | 240 | return physio(xmd_strategy, NULL, dev, B_READ, minphys, uio); |
251 | } | | 241 | } |
252 | | | 242 | |
253 | paddr_t | | 243 | paddr_t |
254 | xmd_mmap(dev_t dev, off_t off, int prot) | | 244 | xmd_mmap(dev_t dev, off_t off, int prot) |
255 | { | | 245 | { |
256 | struct xmd_softc *sc = device_lookup_private(&xmd_cd, DISKUNIT(dev)); | | 246 | struct xmd_softc *sc = device_lookup_private(&xmd_cd, DISKUNIT(dev)); |
257 | | | 247 | |
258 | if (sc == NULL) | | 248 | if (sc == NULL) |
259 | return -1; | | 249 | return -1; |
260 | | | 250 | |
261 | if ((u_int64_t)off >= sc->sc_size) | | 251 | if ((u_int64_t)off >= sc->sc_size) |
262 | return -1; | | 252 | return -1; |
263 | | | 253 | |
264 | return xmd_machdep_mmap(sc->sc_addr, off, prot); | | 254 | return pmap_mmap(sc->sc_addr, off); |
265 | } | | 255 | } |
266 | | | 256 | |
267 | static void | | 257 | static void |
268 | xmd_strategy(struct buf *bp) | | 258 | xmd_strategy(struct buf *bp) |
269 | { | | 259 | { |
270 | struct xmd_softc *sc; | | 260 | struct xmd_softc *sc; |
271 | void *addr; | | 261 | void *addr; |
272 | size_t off, count; | | 262 | size_t off, count; |
273 | | | 263 | |
274 | sc = device_lookup_private(&xmd_cd, DISKUNIT(bp->b_dev)); | | 264 | sc = device_lookup_private(&xmd_cd, DISKUNIT(bp->b_dev)); |
275 | | | 265 | |
276 | off = bp->b_blkno << DEV_BSHIFT; | | 266 | off = bp->b_blkno << DEV_BSHIFT; |
277 | | | 267 | |
278 | /* XXX is b_bcount==0 legal? */ | | 268 | /* XXX is b_bcount==0 legal? */ |
279 | | | 269 | |
280 | if (off >= sc->sc_size) { | | 270 | if (off >= sc->sc_size) { |
281 | if (bp->b_flags & B_READ) | | 271 | if (bp->b_flags & B_READ) |
282 | /* XXX why not error? */ | | 272 | /* XXX why not error? */ |
283 | goto done; | | 273 | goto done; |
284 | bp->b_error = EIO; | | 274 | bp->b_error = EIO; |
285 | goto done; | | 275 | goto done; |
286 | } | | 276 | } |
287 | | | 277 | |
288 | if (bp->b_bcount <= (sc->sc_size - off)) | | 278 | if (bp->b_bcount <= (sc->sc_size - off)) |
289 | count = bp->b_bcount; | | 279 | count = bp->b_bcount; |
290 | else | | 280 | else |
291 | count = sc->sc_size - off; | | 281 | count = sc->sc_size - off; |
292 | | | 282 | |
293 | addr = (void *)(sc->sc_addr + off); | | 283 | addr = (void *)(sc->sc_addr + off); |
294 | | | 284 | |
295 | if (bp->b_flags & B_READ) | | 285 | if (bp->b_flags & B_READ) |
296 | memcpy(bp->b_data, addr, count); | | 286 | memcpy(bp->b_data, addr, count); |
297 | else | | 287 | else |
298 | panic("%s: block write is not supported", __func__); | | 288 | panic("%s: block write is not supported", __func__); |
299 | | | 289 | |
300 | bp->b_resid = bp->b_bcount - count; | | 290 | bp->b_resid = bp->b_bcount - count; |
301 | | | 291 | |
302 | done: | | 292 | done: |
303 | biodone(bp); | | 293 | biodone(bp); |
304 | } | | 294 | } |
305 | | | 295 | |
306 | static int | | 296 | static int |
307 | xmd_size(dev_t dev) | | 297 | xmd_size(dev_t dev) |
308 | { | | 298 | { |
309 | struct xmd_softc *sc; | | 299 | struct xmd_softc *sc; |
310 | | | 300 | |
311 | sc = device_lookup_private(&xmd_cd, DISKUNIT(dev)); | | 301 | sc = device_lookup_private(&xmd_cd, DISKUNIT(dev)); |
312 | if (sc == NULL) | | 302 | if (sc == NULL) |
313 | return 0; | | 303 | return 0; |
314 | | | 304 | |
315 | return sc->sc_size >> DEV_BSHIFT; | | 305 | return sc->sc_size >> DEV_BSHIFT; |
316 | } | | 306 | } |