1 /* $NetBSD: altmem.c,v 1.5 2015/04/26 15:15:20 mlelstv Exp $ */ 2 3 /*- 4 * Copyright (c) 2009 Jared D. McNeill <jmcneill@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.5 2015/04/26 15:15:20 mlelstv 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 struct altmem_softc { 41 device_t sc_dev; 42 43 struct disk sc_dkdev; 44 45 void *sc_cookie; 46 const struct altmem_memops *sc_memops; 47 48 size_t sc_size; 49 }; 50 51 static dev_type_open(altmemopen); 52 static dev_type_close(altmemclose); 53 static dev_type_read(altmemread); 54 static dev_type_write(altmemwrite); 55 static dev_type_ioctl(altmemioctl); 56 static dev_type_strategy(altmemstrategy); 57 static dev_type_size(altmemsize); 58 59 static int altmem_match(device_t, cfdata_t, void *); 60 static void altmem_attach(device_t, device_t, void *); 61 62 const struct bdevsw altmem_bdevsw = { 63 .d_open = altmemopen, 64 .d_close = altmemclose, 65 .d_strategy = altmemstrategy, 66 .d_ioctl = altmemioctl, 67 .d_dump = nodump, 68 .d_psize = altmemsize, 69 .d_discard = nodiscard, 70 .d_flag = D_DISK 71 }; 72 const struct cdevsw altmem_cdevsw = { 73 .d_open = altmemopen, 74 .d_close = altmemclose, 75 .d_read = altmemread, 76 .d_write = altmemwrite, 77 .d_ioctl = altmemioctl, 78 .d_stop = nostop, 79 .d_tty = notty, 80 .d_poll = nopoll, 81 .d_mmap = nommap, 82 .d_kqfilter = nokqfilter, 83 .d_discard = nodiscard, 84 .d_flag = D_DISK 85 }; 86 static struct dkdriver altmemdkdriver = { 87 .d_strategy = altmemstrategy, 88 .d_minphys = minphys 89 }; 90 extern struct cfdriver altmem_cd; 91 92 CFATTACH_DECL_NEW(altmem, sizeof(struct altmem_softc), altmem_match, 93 altmem_attach, NULL, NULL); 94 95 static int 96 altmem_match(device_t parent, cfdata_t match, void *opaque) 97 { 98 return 1; 99 } 100 101 static void 102 altmem_attach(device_t parent, device_t self, void *opaque) 103 { 104 struct altmem_softc *sc = device_private(self); 105 struct altmem_attach_args *aaa = opaque; 106 char pbuf[9]; 107 108 sc->sc_dev = self; 109 sc->sc_cookie = aaa->cookie; 110 sc->sc_memops = aaa->memops; 111 sc->sc_size = sc->sc_memops->getsize(sc->sc_cookie); 112 113 format_bytes(pbuf, sizeof(pbuf), sc->sc_size); 114 115 aprint_naive("\n"); 116 aprint_normal(": %s\n", pbuf); 117 118 disk_init(&sc->sc_dkdev, device_xname(self), &altmemdkdriver); 119 disk_attach(&sc->sc_dkdev); 120 } 121 122 static int 123 altmemsize(dev_t dev) 124 { 125 struct altmem_softc *sc = device_lookup_private(&altmem_cd, DISKUNIT(dev)); 126 if (sc == NULL) 127 return 0; 128 return sc->sc_size >> DEV_BSHIFT; 129 } 130 131 static int 132 altmemopen(dev_t dev, int flag, int fmt, struct lwp *l) 133 { 134 struct altmem_softc *sc = device_lookup_private(&altmem_cd, DISKUNIT(dev)); 135 if (sc == NULL) 136 return ENXIO; 137 return 0; 138 } 139 140 static int 141 altmemclose(dev_t dev, int flag, int fmt, struct lwp *l) 142 { 143 return 0; 144 } 145 146 static int 147 altmemread(dev_t dev, struct uio *uio, int flags) 148 { 149 if (device_lookup_private(&altmem_cd, DISKUNIT(dev)) == NULL) 150 return ENXIO; 151 return physio(altmemstrategy, NULL, dev, B_READ, minphys, uio); 152 } 153 154 static int 155 altmemwrite(dev_t dev, struct uio *uio, int flags) 156 { 157 if (device_lookup_private(&altmem_cd, DISKUNIT(dev)) == NULL) 158 return ENXIO; 159 return physio(altmemstrategy, NULL, dev, B_WRITE, minphys, uio); 160 } 161 162 static void 163 altmemstrategy(struct buf *bp) 164 { 165 struct altmem_softc *sc = device_lookup_private(&altmem_cd, DISKUNIT(bp->b_dev)); 166 167 if (sc == NULL) { 168 bp->b_error = ENXIO; 169 biodone(bp); 170 return; 171 } 172 if (bp->b_bcount == 0) { 173 biodone(bp); 174 return; 175 } 176 177 sc->sc_memops->strategy(sc->sc_cookie, bp); 178 biodone(bp); 179 } 180 181 static int 182 altmemioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 183 { 184 struct altmem_softc *sc = device_lookup_private(&altmem_cd, DISKUNIT(dev)); 185 struct dkwedge_info *dkw; 186 187 switch (cmd) { 188 case DIOCGWEDGEINFO: 189 dkw = (void *)data; 190 strlcpy(dkw->dkw_devname, device_xname(sc->sc_dev), 191 sizeof(dkw->dkw_devname)); 192 strlcpy(dkw->dkw_wname, "altmem", sizeof(dkw->dkw_wname)); 193 dkw->dkw_parent[0] = '\0'; 194 dkw->dkw_offset = 0; 195 dkw->dkw_size = sc->sc_size >> DEV_BSHIFT; 196 strcpy(dkw->dkw_ptype, DKW_PTYPE_UNUSED); 197 break; 198 default: 199 return ENOTTY; 200 } 201 return 0; 202 } 203