1/* $NetBSD: pud_dev.c,v 1.8 2024/02/04 18:52:36 andvar 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.8 2024/02/04 18:52:36 andvar 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 49static int 50doopenclose(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> 61static int 62doioctl(dev_t dev, u_long cmd, void *data, int flag, int class, int type) 63{ 64 struct pud_req_ioctl *pc_ioctl; 65 size_t dlen, allocsize; 66 int error; 67 68 dlen = IOCPARM_LEN(cmd); 69 allocsize = sizeof(struct pud_req_ioctl) + dlen; 70 pc_ioctl = kmem_zalloc(allocsize, KM_SLEEP); 71 72 pc_ioctl->pm_iocmd = cmd; 73 pc_ioctl->pm_flag = flag; 74 75 if (cmd & IOC_IN) 76 memcpy(pc_ioctl->pm_data, data, dlen); 77 error = pud_request(dev, pc_ioctl, allocsize, class, type); 78 if (error) 79 goto out; 80 if (cmd & IOC_OUT) 81 memcpy(data, pc_ioctl->pm_data, dlen); 82 83 out: 84 kmem_free(pc_ioctl, allocsize); 85 return error; 86} 87 88/* 89 * Block de-vices 90 */ 91 92static dev_type_open(pud_bdev_open); 93static dev_type_close(pud_bdev_close); 94static dev_type_strategy(pud_bdev_strategy); 95static dev_type_ioctl(pud_bdev_ioctl); 96#if 0 97static dev_type_dump(pud_bdev_dump); 98static dev_type_size(pud_bdev_size); 99#endif 100 101struct bdevsw pud_bdevsw = { 102 .d_open = pud_bdev_open, 103 .d_close = pud_bdev_close, 104 .d_strategy = pud_bdev_strategy, 105 .d_ioctl = pud_bdev_ioctl, 106#if 0 107 .d_dump = pud_bdev_dump, 108 .d_psize = pud_bdev_size, 109#endif 110}; 111 112static int 113pud_bdev_open(dev_t dev, int flags, int fmt, lwp_t *l) 114{ 115 116 return doopenclose(dev, flags, fmt, PUD_REQ_BDEV, PUD_BDEV_OPEN); 117} 118 119static int 120pud_bdev_close(dev_t dev, int flags, int fmt, lwp_t *l) 121{ 122 123 return doopenclose(dev, flags, fmt, PUD_REQ_BDEV, PUD_BDEV_CLOSE); 124} 125 126static void 127pud_bdev_strategy(struct buf *bp) 128{ 129 struct pud_req_readwrite *pc_rw; 130 size_t allocsize; 131 int error; 132 133 allocsize = sizeof(struct pud_req_readwrite) + bp->b_bcount; 134 pc_rw = kmem_zalloc(allocsize, KM_SLEEP); 135 136 pc_rw->pm_offset = bp->b_blkno << DEV_BSHIFT; 137 pc_rw->pm_resid = bp->b_bcount; 138 139 if (BUF_ISWRITE(bp)) 140 memcpy(pc_rw->pm_data, bp->b_data, bp->b_bcount); 141 142 error = pud_request(bp->b_dev, pc_rw, allocsize, PUD_REQ_BDEV, 143 BUF_ISREAD(bp) ? PUD_BDEV_STRATREAD : PUD_BDEV_STRATWRITE); 144 if (error) 145 goto out; 146 147 if (pc_rw->pm_resid > bp->b_bcount) { 148 error = EINVAL; 149 goto out; 150 } 151 152 if (BUF_ISREAD(bp)) 153 memcpy(bp->b_data,pc_rw->pm_data,bp->b_bcount-pc_rw->pm_resid); 154 155 bp->b_resid = pc_rw->pm_resid; 156 157 out: 158 kmem_free(pc_rw, allocsize); 159 bp->b_error = error; 160 biodone(bp); 161} 162 163int 164pud_bdev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l) 165{ 166 167 return doioctl(dev, cmd, data, flag, PUD_REQ_BDEV, PUD_BDEV_IOCTL); 168} 169 170/* hnmmm */ 171#if 0 172int 173pud_bdev_dump(dev_t dev, daddr_t addr, void *data, size_t sz) 174{ 175 176 return EOPNOTSUPP; 177} 178 179int 180pud_bdev_size(dev_t dev) 181{ 182 183 return 0; 184} 185#endif 186 187/* 188 * Char devices 189 */ 190 191static dev_type_open(pud_cdev_open); 192static dev_type_close(pud_cdev_close); 193static dev_type_read(pud_cdev_read); 194static dev_type_write(pud_cdev_write); 195static dev_type_ioctl(pud_cdev_ioctl); 196static dev_type_poll(pud_cdev_poll); 197static dev_type_mmap(pud_cdev_mmap); 198static dev_type_kqfilter(pud_cdev_kqfilter); 199 200struct cdevsw pud_cdevsw = { 201 .d_open = pud_cdev_open, 202 .d_close = pud_cdev_close, 203 .d_read = pud_cdev_read, 204 .d_write = pud_cdev_write, 205 .d_ioctl = pud_cdev_ioctl, 206#if 0 207 .d_stop = pud_cdev_stop, 208 .d_tty = pud_cdev_tty, 209#endif 210 .d_poll = pud_cdev_poll, 211 .d_mmap = pud_cdev_mmap, 212 .d_kqfilter = pud_cdev_kqfilter, 213 .d_flag = D_OTHER, 214}; 215 216static int 217pud_cdev_open(dev_t dev, int flags, int fmt, lwp_t *l) 218{ 219 220 return doopenclose(dev, flags, fmt, PUD_REQ_CDEV, PUD_CDEV_OPEN); 221} 222 223static int 224pud_cdev_close(dev_t dev, int flags, int fmt, lwp_t *l) 225{ 226 227 return doopenclose(dev, flags, fmt, PUD_REQ_CDEV, PUD_CDEV_CLOSE); 228} 229 230static int 231pud_cdev_read(dev_t dev, struct uio *uio, int flag) 232{ 233 struct pud_creq_read *pc_read; 234 size_t allocsize; 235 int error; 236 237 allocsize = sizeof(struct pud_creq_read) + uio->uio_resid; 238 pc_read = kmem_zalloc(allocsize, KM_SLEEP); 239 240 pc_read->pm_offset = uio->uio_offset; 241 pc_read->pm_resid = uio->uio_resid; 242 243 error = pud_request(dev, pc_read, allocsize, 244 PUD_REQ_CDEV, PUD_CDEV_READ); 245 if (error) 246 goto out; 247 248 if (pc_read->pm_resid > uio->uio_resid) { 249 error = EINVAL; 250 goto out; 251 } 252 253 error = uiomove(pc_read->pm_data, 254 uio->uio_resid - pc_read->pm_resid, uio); 255 256 out: 257 kmem_free(pc_read, allocsize); 258 return error; 259} 260 261static int 262pud_cdev_write(dev_t dev, struct uio *uio, int flag) 263{ 264 struct pud_creq_write *pc_write; 265 size_t allocsize; 266 int error; 267 268 allocsize = sizeof(struct pud_creq_write) + uio->uio_resid; 269 pc_write = kmem_zalloc(allocsize, KM_SLEEP); 270 271 pc_write->pm_offset = uio->uio_offset; 272 pc_write->pm_resid = uio->uio_resid; 273 274 error = uiomove(pc_write->pm_data, uio->uio_resid, uio); 275 if (error) 276 goto out; 277 278 error = pud_request(dev, pc_write, allocsize, 279 PUD_REQ_CDEV, PUD_CDEV_WRITE); 280 if (error) 281 goto out; 282 283 if (pc_write->pm_resid) 284 error = EIO; 285 286 out: 287 kmem_free(pc_write, allocsize); 288 return error; 289} 290 291static int 292pud_cdev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l) 293{ 294 295 return doioctl(dev, cmd, data, flag, PUD_REQ_CDEV, PUD_CDEV_IOCTL); 296} 297 298static paddr_t 299pud_cdev_mmap(dev_t dev, off_t off, int flag) 300{ 301 302 return (paddr_t)-1; 303} 304 305static int 306pud_cdev_poll(dev_t dev, int flag, lwp_t *l) 307{ 308 309 return EOPNOTSUPP; 310} 311 312static int 313pud_cdev_kqfilter(dev_t dev, struct knote *kn) 314{ 315 316 return EOPNOTSUPP; 317} 318