1 /* $NetBSD: altmem.c,v 1.6 2017/10/28 04:53:55 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2009 Jared D. McNeill <jmcneill (at) invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __KERNEL_RCSID(0, "$NetBSD: altmem.c,v 1.6 2017/10/28 04:53:55 riastradh Exp $"); 30 #include <sys/param.h> 31 #include <sys/types.h> 32 #include <sys/device.h> 33 #include <sys/conf.h> 34 #include <sys/buf.h> 35 #include <sys/disklabel.h> 36 #include <sys/disk.h> 37 38 #include <dev/altmem/altmemvar.h> 39 40 #include "ioconf.h" 41 42 struct altmem_softc { 43 device_t sc_dev; 44 45 struct disk sc_dkdev; 46 47 void *sc_cookie; 48 const struct altmem_memops *sc_memops; 49 50 size_t sc_size; 51 }; 52 53 static dev_type_open(altmemopen); 54 static dev_type_close(altmemclose); 55 static dev_type_read(altmemread); 56 static dev_type_write(altmemwrite); 57 static dev_type_ioctl(altmemioctl); 58 static dev_type_strategy(altmemstrategy); 59 static dev_type_size(altmemsize); 60 61 static int altmem_match(device_t, cfdata_t, void *); 62 static void altmem_attach(device_t, device_t, void *); 63 64 const struct bdevsw altmem_bdevsw = { 65 .d_open = altmemopen, 66 .d_close = altmemclose, 67 .d_strategy = altmemstrategy, 68 .d_ioctl = altmemioctl, 69 .d_dump = nodump, 70 .d_psize = altmemsize, 71 .d_discard = nodiscard, 72 .d_flag = D_DISK 73 }; 74 const struct cdevsw altmem_cdevsw = { 75 .d_open = altmemopen, 76 .d_close = altmemclose, 77 .d_read = altmemread, 78 .d_write = altmemwrite, 79 .d_ioctl = altmemioctl, 80 .d_stop = nostop, 81 .d_tty = notty, 82 .d_poll = nopoll, 83 .d_mmap = nommap, 84 .d_kqfilter = nokqfilter, 85 .d_discard = nodiscard, 86 .d_flag = D_DISK 87 }; 88 static struct dkdriver altmemdkdriver = { 89 .d_strategy = altmemstrategy, 90 .d_minphys = minphys 91 }; 92 93 CFATTACH_DECL_NEW(altmem, sizeof(struct altmem_softc), altmem_match, 94 altmem_attach, NULL, NULL); 95 96 static int 97 altmem_match(device_t parent, cfdata_t match, void *opaque) 98 { 99 return 1; 100 } 101 102 static void 103 altmem_attach(device_t parent, device_t self, void *opaque) 104 { 105 struct altmem_softc *sc = device_private(self); 106 struct altmem_attach_args *aaa = opaque; 107 char pbuf[9]; 108 109 sc->sc_dev = self; 110 sc->sc_cookie = aaa->cookie; 111 sc->sc_memops = aaa->memops; 112 sc->sc_size = sc->sc_memops->getsize(sc->sc_cookie); 113 114 format_bytes(pbuf, sizeof(pbuf), sc->sc_size); 115 116 aprint_naive("\n"); 117 aprint_normal(": %s\n", pbuf); 118 119 disk_init(&sc->sc_dkdev, device_xname(self), &altmemdkdriver); 120 disk_attach(&sc->sc_dkdev); 121 } 122 123 static int 124 altmemsize(dev_t dev) 125 { 126 struct altmem_softc *sc = device_lookup_private(&altmem_cd, DISKUNIT(dev)); 127 if (sc == NULL) 128 return 0; 129 return sc->sc_size >> DEV_BSHIFT; 130 } 131 132 static int 133 altmemopen(dev_t dev, int flag, int fmt, struct lwp *l) 134 { 135 struct altmem_softc *sc = device_lookup_private(&altmem_cd, DISKUNIT(dev)); 136 if (sc == NULL) 137 return ENXIO; 138 return 0; 139 } 140 141 static int 142 altmemclose(dev_t dev, int flag, int fmt, struct lwp *l) 143 { 144 return 0; 145 } 146 147 static int 148 altmemread(dev_t dev, struct uio *uio, int flags) 149 { 150 if (device_lookup_private(&altmem_cd, DISKUNIT(dev)) == NULL) 151 return ENXIO; 152 return physio(altmemstrategy, NULL, dev, B_READ, minphys, uio); 153 } 154 155 static int 156 altmemwrite(dev_t dev, struct uio *uio, int flags) 157 { 158 if (device_lookup_private(&altmem_cd, DISKUNIT(dev)) == NULL) 159 return ENXIO; 160 return physio(altmemstrategy, NULL, dev, B_WRITE, minphys, uio); 161 } 162 163 static void 164 altmemstrategy(struct buf *bp) 165 { 166 struct altmem_softc *sc = device_lookup_private(&altmem_cd, DISKUNIT(bp->b_dev)); 167 168 if (sc == NULL) { 169 bp->b_error = ENXIO; 170 biodone(bp); 171 return; 172 } 173 if (bp->b_bcount == 0) { 174 biodone(bp); 175 return; 176 } 177 178 sc->sc_memops->strategy(sc->sc_cookie, bp); 179 biodone(bp); 180 } 181 182 static int 183 altmemioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 184 { 185 struct altmem_softc *sc = device_lookup_private(&altmem_cd, DISKUNIT(dev)); 186 struct dkwedge_info *dkw; 187 188 switch (cmd) { 189 case DIOCGWEDGEINFO: 190 dkw = (void *)data; 191 strlcpy(dkw->dkw_devname, device_xname(sc->sc_dev), 192 sizeof(dkw->dkw_devname)); 193 strlcpy(dkw->dkw_wname, "altmem", sizeof(dkw->dkw_wname)); 194 dkw->dkw_parent[0] = '\0'; 195 dkw->dkw_offset = 0; 196 dkw->dkw_size = sc->sc_size >> DEV_BSHIFT; 197 strcpy(dkw->dkw_ptype, DKW_PTYPE_UNUSED); 198 break; 199 default: 200 return ENOTTY; 201 } 202 return 0; 203 } 204