1 /* $NetBSD: pud_dev.c,v 1.5 2009/12/22 14:12:40 pooka Exp $ */
4 * Copyright (c) 2007 Antti Kantee. All Rights Reserved.
6 * Development of this software was supported by the
7 * Research Foundation of Helsinki University of Technology
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: pud_dev.c,v 1.5 2009/12/22 14:12:40 pooka Exp $");
34 #include <sys/param.h>
37 #include <sys/event.h>
38 #include <sys/ioccom.h>
41 #include <sys/socketvar.h>
43 #include <dev/pud/pud_sys.h>
46 * b/c independent helpers
50 doopenclose(dev_t dev
, int flags
, int fmt
, int class, int type
)
52 struct pud_req_openclose pc_oc
; /* XXX: stack = stupid */
54 pc_oc
.pm_flags
= flags
;
57 return pud_request(dev
, &pc_oc
, sizeof(pc_oc
), class, type
);
60 #include <sys/disklabel.h>
62 * XXX: this is not "reentrant". But then again, partinfo isn't
63 * exactly safe in any case.
65 static struct disklabel dl_partinfo
;
68 doioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, int class, int type
)
70 struct pud_req_ioctl
*pc_ioctl
;
71 size_t dlen
, allocsize
;
73 void *origdata
= NULL
; /* XXXgcc */
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.
84 if (cmd
== DIOCGPART
) {
91 dlen
= IOCPARM_LEN(cmd
);
92 allocsize
= sizeof(struct pud_req_ioctl
) + dlen
;
93 pc_ioctl
= kmem_zalloc(allocsize
, KM_SLEEP
);
95 pc_ioctl
->pm_iocmd
= cmd
;
96 pc_ioctl
->pm_flag
= flag
;
99 memcpy(pc_ioctl
->pm_data
, data
, dlen
);
100 error
= pud_request(dev
, pc_ioctl
, allocsize
, class, type
);
104 memcpy(data
, pc_ioctl
->pm_data
, dlen
);
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
112 if (origcmd
== DIOCGPART
) {
113 struct partinfo
*pi
, *pi_user
;
116 CTASSERT(sizeof(struct partinfo
) <= sizeof(struct disklabel
));
118 pc_ioctl
->pm_iocmd
= DIOCGPART
;
119 pc_ioctl
->pm_flag
= 0;
121 error
= pud_request(dev
, pc_ioctl
, allocsize
, class, type
);
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
) {
134 pi
->disklab
= &dl_partinfo
;
135 pi
->part
= &dl_partinfo
.d_partitions
[labidx
];
140 kmem_free(pc_ioctl
, allocsize
);
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
);
153 static dev_type_dump(pud_bdev_dump
);
154 static dev_type_size(pud_bdev_size
);
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
,
163 .d_dump
= pud_bdev_dump
,
164 .d_psize
= pud_bdev_size
,
169 pud_bdev_open(dev_t dev
, int flags
, int fmt
, lwp_t
*l
)
172 return doopenclose(dev
, flags
, fmt
, PUD_REQ_BDEV
, PUD_BDEV_OPEN
);
176 pud_bdev_close(dev_t dev
, int flags
, int fmt
, lwp_t
*l
)
179 return doopenclose(dev
, flags
, fmt
, PUD_REQ_BDEV
, PUD_BDEV_CLOSE
);
183 pud_bdev_strategy(struct buf
*bp
)
185 struct pud_req_readwrite
*pc_rw
;
189 allocsize
= sizeof(struct pud_req_readwrite
) + bp
->b_bcount
;
190 pc_rw
= kmem_zalloc(allocsize
, KM_SLEEP
);
192 pc_rw
->pm_offset
= bp
->b_blkno
<< DEV_BSHIFT
;
193 pc_rw
->pm_resid
= bp
->b_bcount
;
196 memcpy(pc_rw
->pm_data
, bp
->b_data
, bp
->b_bcount
);
198 error
= pud_request(bp
->b_dev
, pc_rw
, allocsize
, PUD_REQ_BDEV
,
199 BUF_ISREAD(bp
) ? PUD_BDEV_STRATREAD
: PUD_BDEV_STRATWRITE
);
203 if (pc_rw
->pm_resid
> bp
->b_bcount
) {
209 memcpy(bp
->b_data
,pc_rw
->pm_data
,bp
->b_bcount
-pc_rw
->pm_resid
);
211 bp
->b_resid
= pc_rw
->pm_resid
;
214 kmem_free(pc_rw
, allocsize
);
220 pud_bdev_ioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, lwp_t
*l
)
223 return doioctl(dev
, cmd
, data
, flag
, PUD_REQ_BDEV
, PUD_BDEV_IOCTL
);
229 pud_bdev_dump(dev_t dev
, daddr_t addr
, void *data
, size_t sz
)
236 pud_bdev_size(dev_t dev
)
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
);
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
,
263 .d_stop
= pud_cdev_stop
,
264 .d_tty
= pud_cdev_tty
,
266 .d_poll
= pud_cdev_poll
,
267 .d_mmap
= pud_cdev_mmap
,
268 .d_kqfilter
= pud_cdev_kqfilter
,
273 pud_cdev_open(dev_t dev
, int flags
, int fmt
, lwp_t
*l
)
276 return doopenclose(dev
, flags
, fmt
, PUD_REQ_CDEV
, PUD_CDEV_OPEN
);
280 pud_cdev_close(dev_t dev
, int flags
, int fmt
, lwp_t
*l
)
283 return doopenclose(dev
, flags
, fmt
, PUD_REQ_CDEV
, PUD_CDEV_CLOSE
);
287 pud_cdev_read(dev_t dev
, struct uio
*uio
, int flag
)
289 struct pud_creq_read
*pc_read
;
293 allocsize
= sizeof(struct pud_creq_read
) + uio
->uio_resid
;
294 pc_read
= kmem_zalloc(allocsize
, KM_SLEEP
);
296 pc_read
->pm_offset
= uio
->uio_offset
;
297 pc_read
->pm_resid
= uio
->uio_resid
;
299 error
= pud_request(dev
, pc_read
, allocsize
,
300 PUD_REQ_CDEV
, PUD_CDEV_READ
);
304 if (pc_read
->pm_resid
> uio
->uio_resid
) {
309 error
= uiomove(pc_read
->pm_data
,
310 uio
->uio_resid
- pc_read
->pm_resid
, uio
);
313 kmem_free(pc_read
, allocsize
);
318 pud_cdev_write(dev_t dev
, struct uio
*uio
, int flag
)
320 struct pud_creq_write
*pc_write
;
324 allocsize
= sizeof(struct pud_creq_write
) + uio
->uio_resid
;
325 pc_write
= kmem_zalloc(allocsize
, KM_SLEEP
);
327 pc_write
->pm_offset
= uio
->uio_offset
;
328 pc_write
->pm_resid
= uio
->uio_resid
;
330 error
= uiomove(pc_write
->pm_data
, uio
->uio_resid
, uio
);
334 error
= pud_request(dev
, pc_write
, allocsize
,
335 PUD_REQ_CDEV
, PUD_CDEV_WRITE
);
339 if (pc_write
->pm_resid
)
343 kmem_free(pc_write
, allocsize
);
348 pud_cdev_ioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, lwp_t
*l
)
351 return doioctl(dev
, cmd
, data
, flag
, PUD_REQ_CDEV
, PUD_CDEV_IOCTL
);
355 pud_cdev_mmap(dev_t dev
, off_t off
, int flag
)
362 pud_cdev_poll(dev_t dev
, int flag
, lwp_t
*l
)
369 pud_cdev_kqfilter(dev_t dev
, struct knote
*kn
)