pud_dev.c revision 1.4.24.1 1 /* $NetBSD: pud_dev.c,v 1.4.24.1 2010/03/11 15:04:01 yamt Exp $ */
2
3 /*
4 * Copyright (c) 2007 Antti Kantee. All Rights Reserved.
5 *
6 * Development of this software was supported by the
7 * Research Foundation of Helsinki University of Technology
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: pud_dev.c,v 1.4.24.1 2010/03/11 15:04:01 yamt Exp $");
33
34 #include <sys/param.h>
35 #include <sys/buf.h>
36 #include <sys/conf.h>
37 #include <sys/event.h>
38 #include <sys/ioccom.h>
39 #include <sys/kmem.h>
40 #include <sys/poll.h>
41 #include <sys/socketvar.h>
42
43 #include <dev/pud/pud_sys.h>
44
45 /*
46 * b/c independent helpers
47 */
48
49 static int
50 doopenclose(dev_t dev, int flags, int fmt, int class, int type)
51 {
52 struct pud_req_openclose pc_oc; /* XXX: stack = stupid */
53
54 pc_oc.pm_flags = flags;
55 pc_oc.pm_fmt = fmt;
56
57 return pud_request(dev, &pc_oc, sizeof(pc_oc), class, type);
58 }
59
60 #include <sys/disklabel.h>
61 /*
62 * XXX: this is not "reentrant". But then again, partinfo isn't
63 * exactly safe in any case.
64 */
65 static struct disklabel dl_partinfo;
66
67 static int
68 doioctl(dev_t dev, u_long cmd, void *data, int flag, int class, int type)
69 {
70 struct pud_req_ioctl *pc_ioctl;
71 size_t dlen, allocsize;
72 u_long origcmd = cmd;
73 void *origdata = NULL; /* XXXgcc */
74 int error;
75
76 /*
77 * XXX: kludge. This is a horrible abstraction violation, but
78 * then again DIOCGPART is a horrible ioctl (even more horrible
79 * than the generic ioctl). We handle it specially here since
80 * the server in userspace has no chance to handle it. And it's
81 * a common operation used by most file systems. But really, it
82 * should be replaced by something a bit more ... transactional.
83 */
84 if (cmd == DIOCGPART) {
85 cmd = DIOCGDINFO;
86 origdata = data;
87 flag = 0;
88 data = &dl_partinfo;
89 }
90
91 dlen = IOCPARM_LEN(cmd);
92 allocsize = sizeof(struct pud_req_ioctl) + dlen;
93 pc_ioctl = kmem_zalloc(allocsize, KM_SLEEP);
94
95 pc_ioctl->pm_iocmd = cmd;
96 pc_ioctl->pm_flag = flag;
97
98 if (cmd & IOC_IN)
99 memcpy(pc_ioctl->pm_data, data, dlen);
100 error = pud_request(dev, pc_ioctl, allocsize, class, type);
101 if (error)
102 goto out;
103 if (cmd & IOC_OUT)
104 memcpy(data, pc_ioctl->pm_data, dlen);
105
106 /*
107 * In case doing the infamous DIOCGPART, issue the real
108 * ioctl and do pointer arithmetic to figure out the right
109 * partition. We could use DISKPART() too, but this seems
110 * "better".
111 */
112 if (origcmd == DIOCGPART) {
113 struct partinfo *pi, *pi_user;
114 int labidx;
115
116 CTASSERT(sizeof(struct partinfo) <= sizeof(struct disklabel));
117
118 pc_ioctl->pm_iocmd = DIOCGPART;
119 pc_ioctl->pm_flag = 0;
120
121 error = pud_request(dev, pc_ioctl, allocsize, class, type);
122 if (error)
123 goto out;
124
125 pi_user = (struct partinfo *)pc_ioctl->pm_data;
126 labidx = pi_user->part - &pi_user->disklab->d_partitions[0];
127 /* userspace error, but punish caller, since we have no infra */
128 if (labidx >= MAXPARTITIONS) {
129 error = E2BIG;
130 goto out;
131 }
132
133 pi = origdata;
134 pi->disklab = &dl_partinfo;
135 pi->part = &dl_partinfo.d_partitions[labidx];
136
137 }
138
139 out:
140 kmem_free(pc_ioctl, allocsize);
141 return error;
142 }
143
144 /*
145 * Block de-vices
146 */
147
148 static dev_type_open(pud_bdev_open);
149 static dev_type_close(pud_bdev_close);
150 static dev_type_strategy(pud_bdev_strategy);
151 static dev_type_ioctl(pud_bdev_ioctl);
152 #if 0
153 static dev_type_dump(pud_bdev_dump);
154 static dev_type_size(pud_bdev_size);
155 #endif
156
157 struct bdevsw pud_bdevsw = {
158 .d_open = pud_bdev_open,
159 .d_close = pud_bdev_close,
160 .d_strategy = pud_bdev_strategy,
161 .d_ioctl = pud_bdev_ioctl,
162 #if 0
163 .d_dump = pud_bdev_dump,
164 .d_psize = pud_bdev_size,
165 #endif
166 };
167
168 static int
169 pud_bdev_open(dev_t dev, int flags, int fmt, lwp_t *l)
170 {
171
172 return doopenclose(dev, flags, fmt, PUD_REQ_BDEV, PUD_BDEV_OPEN);
173 }
174
175 static int
176 pud_bdev_close(dev_t dev, int flags, int fmt, lwp_t *l)
177 {
178
179 return doopenclose(dev, flags, fmt, PUD_REQ_BDEV, PUD_BDEV_CLOSE);
180 }
181
182 static void
183 pud_bdev_strategy(struct buf *bp)
184 {
185 struct pud_req_readwrite *pc_rw;
186 size_t allocsize;
187 int error;
188
189 allocsize = sizeof(struct pud_req_readwrite) + bp->b_bcount;
190 pc_rw = kmem_zalloc(allocsize, KM_SLEEP);
191
192 pc_rw->pm_offset = bp->b_blkno << DEV_BSHIFT;
193 pc_rw->pm_resid = bp->b_bcount;
194
195 if (BUF_ISWRITE(bp))
196 memcpy(pc_rw->pm_data, bp->b_data, bp->b_bcount);
197
198 error = pud_request(bp->b_dev, pc_rw, allocsize, PUD_REQ_BDEV,
199 BUF_ISREAD(bp) ? PUD_BDEV_STRATREAD : PUD_BDEV_STRATWRITE);
200 if (error)
201 goto out;
202
203 if (pc_rw->pm_resid > bp->b_bcount) {
204 error = EINVAL;
205 goto out;
206 }
207
208 if (BUF_ISREAD(bp))
209 memcpy(bp->b_data,pc_rw->pm_data,bp->b_bcount-pc_rw->pm_resid);
210
211 bp->b_resid = pc_rw->pm_resid;
212
213 out:
214 kmem_free(pc_rw, allocsize);
215 bp->b_error = error;
216 biodone(bp);
217 }
218
219 int
220 pud_bdev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l)
221 {
222
223 return doioctl(dev, cmd, data, flag, PUD_REQ_BDEV, PUD_BDEV_IOCTL);
224 }
225
226 /* hnmmm */
227 #if 0
228 int
229 pud_bdev_dump(dev_t dev, daddr_t addr, void *data, size_t sz)
230 {
231
232 return EOPNOTSUPP;
233 }
234
235 int
236 pud_bdev_size(dev_t dev)
237 {
238
239 return 0;
240 }
241 #endif
242
243 /*
244 * Charrr devices
245 */
246
247 static dev_type_open(pud_cdev_open);
248 static dev_type_close(pud_cdev_close);
249 static dev_type_read(pud_cdev_read);
250 static dev_type_write(pud_cdev_write);
251 static dev_type_ioctl(pud_cdev_ioctl);
252 static dev_type_poll(pud_cdev_poll);
253 static dev_type_mmap(pud_cdev_mmap);
254 static dev_type_kqfilter(pud_cdev_kqfilter);
255
256 struct cdevsw pud_cdevsw = {
257 .d_open = pud_cdev_open,
258 .d_close = pud_cdev_close,
259 .d_read = pud_cdev_read,
260 .d_write = pud_cdev_write,
261 .d_ioctl = pud_cdev_ioctl,
262 #if 0
263 .d_stop = pud_cdev_stop,
264 .d_tty = pud_cdev_tty,
265 #endif
266 .d_poll = pud_cdev_poll,
267 .d_mmap = pud_cdev_mmap,
268 .d_kqfilter = pud_cdev_kqfilter,
269 .d_flag = D_OTHER,
270 };
271
272 static int
273 pud_cdev_open(dev_t dev, int flags, int fmt, lwp_t *l)
274 {
275
276 return doopenclose(dev, flags, fmt, PUD_REQ_CDEV, PUD_CDEV_OPEN);
277 }
278
279 static int
280 pud_cdev_close(dev_t dev, int flags, int fmt, lwp_t *l)
281 {
282
283 return doopenclose(dev, flags, fmt, PUD_REQ_CDEV, PUD_CDEV_CLOSE);
284 }
285
286 static int
287 pud_cdev_read(dev_t dev, struct uio *uio, int flag)
288 {
289 struct pud_creq_read *pc_read;
290 size_t allocsize;
291 int error;
292
293 allocsize = sizeof(struct pud_creq_read) + uio->uio_resid;
294 pc_read = kmem_zalloc(allocsize, KM_SLEEP);
295
296 pc_read->pm_offset = uio->uio_offset;
297 pc_read->pm_resid = uio->uio_resid;
298
299 error = pud_request(dev, pc_read, allocsize,
300 PUD_REQ_CDEV, PUD_CDEV_READ);
301 if (error)
302 goto out;
303
304 if (pc_read->pm_resid > uio->uio_resid) {
305 error = EINVAL;
306 goto out;
307 }
308
309 error = uiomove(pc_read->pm_data,
310 uio->uio_resid - pc_read->pm_resid, uio);
311
312 out:
313 kmem_free(pc_read, allocsize);
314 return error;
315 }
316
317 static int
318 pud_cdev_write(dev_t dev, struct uio *uio, int flag)
319 {
320 struct pud_creq_write *pc_write;
321 size_t allocsize;
322 int error;
323
324 allocsize = sizeof(struct pud_creq_write) + uio->uio_resid;
325 pc_write = kmem_zalloc(allocsize, KM_SLEEP);
326
327 pc_write->pm_offset = uio->uio_offset;
328 pc_write->pm_resid = uio->uio_resid;
329
330 error = uiomove(pc_write->pm_data, uio->uio_resid, uio);
331 if (error)
332 goto out;
333
334 error = pud_request(dev, pc_write, allocsize,
335 PUD_REQ_CDEV, PUD_CDEV_WRITE);
336 if (error)
337 goto out;
338
339 if (pc_write->pm_resid)
340 error = EIO;
341
342 out:
343 kmem_free(pc_write, allocsize);
344 return error;
345 }
346
347 static int
348 pud_cdev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l)
349 {
350
351 return doioctl(dev, cmd, data, flag, PUD_REQ_CDEV, PUD_CDEV_IOCTL);
352 }
353
354 static paddr_t
355 pud_cdev_mmap(dev_t dev, off_t off, int flag)
356 {
357
358 return (paddr_t)-1;
359 }
360
361 static int
362 pud_cdev_poll(dev_t dev, int flag, lwp_t *l)
363 {
364
365 return EOPNOTSUPP;
366 }
367
368 static int
369 pud_cdev_kqfilter(dev_t dev, struct knote *kn)
370 {
371
372 return EOPNOTSUPP;
373 }
374