1 /*-
2 * Copyright (c) 2015-2016 Ruslan Bukin <br@bsdpad.com>
3 * All rights reserved.
4 *
5 * Portions of this software were developed by SRI International and the
6 * University of Cambridge Computer Laboratory under DARPA/AFRL contract
7 * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
8 *
9 * Portions of this software were developed by the University of Cambridge
10 * Computer Laboratory as part of the CTSRD Project, with support from the
11 * UK Higher Education Innovation Fund (HEIF).
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/kthread.h>
42 #include <sys/selinfo.h>
43 #include <sys/module.h>
44 #include <sys/lock.h>
45 #include <sys/mutex.h>
46 #include <sys/malloc.h>
47 #include <sys/sysctl.h>
48 #include <sys/uio.h>
49
50 #include <sys/bio.h>
51 #include <sys/bus.h>
52 #include <sys/conf.h>
53 #include <sys/disk.h>
54 #include <geom/geom_disk.h>
55
56 #include <vm/vm.h>
57 #include <vm/pmap.h>
58
59 #include <machine/md_var.h>
60 #include <machine/bus.h>
61 #include <machine/trap.h>
62 #include <sys/rman.h>
63
64 #include "htif.h"
65
66 #define SECTOR_SIZE_SHIFT (9)
67 #define SECTOR_SIZE (1 << SECTOR_SIZE_SHIFT)
68
69 #define HTIF_BLK_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
70 #define HTIF_BLK_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
71 #define HTIF_BLK_LOCK_INIT(_sc) \
72 mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \
73 "htif_blk", MTX_DEF)
74 #define HTIF_BLK_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
75 #define HTIF_BLK_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
76 #define HTIF_BLK_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
77
78 static void htif_blk_task(void *arg);
79
80 static disk_open_t htif_blk_open;
81 static disk_close_t htif_blk_close;
82 static disk_strategy_t htif_blk_strategy;
83
84 struct htif_blk_softc {
85 device_t dev;
86 struct disk *disk;
87 struct mtx htif_io_mtx;
88 struct mtx sc_mtx;
89 struct proc *p;
90 struct bio_queue_head bio_queue;
91 int running;
92 int intr_chan;
93 int cmd_done;
94 int index;
95 uint16_t curtag;
96 };
97
98 struct htif_blk_request {
99 uint64_t addr;
100 uint64_t offset; /* offset in bytes */
101 uint64_t size; /* length in bytes */
102 uint64_t tag;
103 };
104
105 static void
106 htif_blk_intr(void *arg, uint64_t entry)
107 {
108 struct htif_blk_softc *sc;
109 uint64_t devcmd;
110 uint64_t data;
111
112 sc = arg;
113
114 devcmd = HTIF_DEV_CMD(entry);
115 data = HTIF_DEV_DATA(entry);
116
117 if (sc->curtag == data) {
118 wmb();
119 sc->cmd_done = 1;
120 wakeup(&sc->intr_chan);
121 } else {
122 device_printf(sc->dev, "Unexpected tag %d (should be %d)\n",
123 data, sc->curtag);
124 }
125 }
126
127 static int
128 htif_blk_probe(device_t dev)
129 {
130
131 return (0);
132 }
133
134 static int
135 htif_blk_attach(device_t dev)
136 {
137 struct htif_blk_softc *sc;
138 char prefix[] = " size=";
139 char *str;
140 long size;
141
142 sc = device_get_softc(dev);
143 sc->dev = dev;
144
145 mtx_init(&sc->htif_io_mtx, device_get_nameunit(dev), "htif_blk", MTX_DEF);
146 HTIF_BLK_LOCK_INIT(sc);
147
148 str = strstr(htif_get_id(dev), prefix);
149
150 size = strtol((str + 6), NULL, 10);
151 if (size == 0) {
152 return (ENXIO);
153 }
154
155 sc->index = htif_get_index(dev);
156 if (sc->index < 0)
157 return (EINVAL);
158 htif_setup_intr(sc->index, htif_blk_intr, sc);
159
160 sc->disk = disk_alloc();
161 sc->disk->d_drv1 = sc;
162
163 sc->disk->d_maxsize = 4096; /* Max transfer */
164 sc->disk->d_name = "htif_blk";
165 sc->disk->d_open = htif_blk_open;
166 sc->disk->d_close = htif_blk_close;
167 sc->disk->d_strategy = htif_blk_strategy;
168 sc->disk->d_unit = 0;
169 sc->disk->d_sectorsize = SECTOR_SIZE;
170 sc->disk->d_mediasize = size;
171 disk_create(sc->disk, DISK_VERSION);
172
173 bioq_init(&sc->bio_queue);
174
175 sc->running = 1;
176
177 kproc_create(&htif_blk_task, sc, &sc->p, 0, 0, "%s: transfer",
178 device_get_nameunit(dev));
179
180 return (0);
181 }
182
183 static int
184 htif_blk_open(struct disk *dp)
185 {
186
187 return (0);
188 }
189
190 static int
191 htif_blk_close(struct disk *dp)
192 {
193
194 return (0);
195 }
196
197 static void
198 htif_blk_task(void *arg)
199 {
200 struct htif_blk_request req __aligned(HTIF_ALIGN);
201 struct htif_blk_softc *sc;
202 uint64_t req_paddr;
203 struct bio *bp;
204 uint64_t paddr;
205 uint64_t cmd;
206 int i;
207
208 sc = (struct htif_blk_softc *)arg;
209
210 while (1) {
211 HTIF_BLK_LOCK(sc);
212 do {
213 bp = bioq_takefirst(&sc->bio_queue);
214 if (bp == NULL)
215 msleep(sc, &sc->sc_mtx, PRIBIO, "jobqueue", 0);
216 } while (bp == NULL);
217 HTIF_BLK_UNLOCK(sc);
218
219 if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) {
220 HTIF_BLK_LOCK(sc);
221
222 rmb();
223 req.offset = (bp->bio_pblkno * sc->disk->d_sectorsize);
224 req.size = bp->bio_bcount;
225 paddr = vtophys(bp->bio_data);
226 KASSERT(paddr != 0, ("paddr is 0"));
227 req.addr = paddr;
228 sc->curtag++;
229 req.tag = sc->curtag;
230
231 cmd = sc->index;
232 cmd <<= HTIF_DEV_ID_SHIFT;
233 if (bp->bio_cmd == BIO_READ)
234 cmd |= (HTIF_CMD_READ << HTIF_CMD_SHIFT);
235 else
236 cmd |= (HTIF_CMD_WRITE << HTIF_CMD_SHIFT);
237 req_paddr = vtophys(&req);
238 KASSERT(req_paddr != 0, ("req_paddr is 0"));
239 cmd |= req_paddr;
240
241 sc->cmd_done = 0;
242 htif_command(cmd);
243
244 /* Wait for interrupt */
245 i = 0;
246 while (sc->cmd_done == 0) {
247 msleep(&sc->intr_chan, &sc->sc_mtx, PRIBIO, "intr", hz/2);
248
249 if (i++ > 2) {
250 /* TODO: try to re-issue operation on timeout ? */
251 bp->bio_error = EIO;
252 bp->bio_flags |= BIO_ERROR;
253 disk_err(bp, "hard error", -1, 1);
254 break;
255 }
256 }
257 HTIF_BLK_UNLOCK(sc);
258
259 biodone(bp);
260 } else {
261 printf("unknown op %d\n", bp->bio_cmd);
262 }
263 }
264 }
265
266 static void
267 htif_blk_strategy(struct bio *bp)
268 {
269 struct htif_blk_softc *sc;
270
271 sc = bp->bio_disk->d_drv1;
272
273 HTIF_BLK_LOCK(sc);
274 if (sc->running > 0) {
275 bioq_disksort(&sc->bio_queue, bp);
276 HTIF_BLK_UNLOCK(sc);
277 wakeup(sc);
278 } else {
279 HTIF_BLK_UNLOCK(sc);
280 biofinish(bp, NULL, ENXIO);
281 }
282 }
283
284 static device_method_t htif_blk_methods[] = {
285 DEVMETHOD(device_probe, htif_blk_probe),
286 DEVMETHOD(device_attach, htif_blk_attach),
287 };
288
289 static driver_t htif_blk_driver = {
290 "htif_blk",
291 htif_blk_methods,
292 sizeof(struct htif_blk_softc)
293 };
294
295 static devclass_t htif_blk_devclass;
296
297 DRIVER_MODULE(htif_blk, htif, htif_blk_driver, htif_blk_devclass, 0, 0);
Cache object: 42db317b73a753c6519d6be0c508e8e8
|