flash_io.c revision 1.1 1 /* $NetBSD: flash_io.c,v 1.1 2011/06/28 18:14:11 ahoka Exp $ */
2
3 /*-
4 * Copyright (c) 2011 Department of Software Engineering,
5 * University of Szeged, Hungary
6 * Copyright (c) 2011 Adam Hoka <ahoka (at) NetBSD.org>
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by the Department of Software Engineering, University of Szeged, Hungary
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: flash_io.c,v 1.1 2011/06/28 18:14:11 ahoka Exp $");
36
37 #include <sys/param.h>
38 #include <sys/buf.h>
39 #include <sys/bufq.h>
40 #include <sys/kernel.h>
41 #include <sys/kmem.h>
42 #include <sys/kthread.h>
43 #include <sys/mutex.h>
44 #include <sys/sysctl.h>
45
46 #include <dev/flash/flash.h>
47 #include <dev/flash/flash_io.h>
48
49 #ifdef FLASH_DEBUG
50 extern int flashdebug;
51 #endif
52
53 int flash_cachesync_timeout = 1;
54 int flash_cachesync_nodenum;
55
56 void flash_io_read(struct flash_io *, struct buf *);
57 void flash_io_write(struct flash_io *, struct buf *);
58 void flash_io_done(struct flash_io *, struct buf *, int);
59 int flash_io_cache_write(struct flash_io *, flash_addr_t, struct buf *);
60 void flash_io_cache_sync(struct flash_io *);
61
62 static int
63 flash_timestamp_diff(struct bintime *bt, struct bintime *b2)
64 {
65 struct bintime b1 = *bt;
66 struct timeval tv;
67
68 bintime_sub(&b1, b2);
69 bintime2timeval(&b1, &tv);
70
71 return tvtohz(&tv);
72 }
73
74 static flash_addr_t
75 flash_io_getblock(struct flash_io *fio, struct buf *bp)
76 {
77 flash_off_t block, last;
78
79 /* get block number of first byte */
80 block = bp->b_rawblkno * DEV_BSIZE / fio->fio_if->erasesize;
81
82 /* block of the last bite */
83 last = (bp->b_rawblkno * DEV_BSIZE + bp->b_resid - 1)
84 / fio->fio_if->erasesize;
85
86 /* spans trough multiple blocks, needs special handling */
87 if (last != block) {
88 printf("0x%jx -> 0x%jx\n",
89 bp->b_rawblkno * DEV_BSIZE,
90 bp->b_rawblkno * DEV_BSIZE + bp->b_resid - 1);
91 panic("TODO: multiple block write. last: %jd, current: %jd",
92 (intmax_t )last, (intmax_t )block);
93 }
94
95 return block;
96 }
97
98 int
99 flash_sync_thread_init(struct flash_io *fio, struct flash_interface *flash_if)
100 {
101 int error;
102
103 FLDPRINTF(("starting flash io thread\n"));
104
105 fio->fio_if = flash_if;
106
107 fio->fio_data = kmem_alloc(fio->fio_if->erasesize, KM_SLEEP);
108
109 mutex_init(&fio->fio_lock, MUTEX_DEFAULT, IPL_NONE);
110 cv_init(&fio->fio_cv, "flashcv");
111
112 error = bufq_alloc(&fio->fio_bufq, "fcfs", BUFQ_SORT_RAWBLOCK);
113 if (error)
114 goto err_bufq;
115
116 fio->fio_exiting = false;
117 fio->fio_write_pending = false;
118
119 /* arrange to allocate the kthread */
120 error = kthread_create(PRI_NONE, KTHREAD_JOINABLE | KTHREAD_MPSAFE,
121 NULL, flash_sync_thread, fio, &fio->fio_thread, "flashio");
122
123 if (!error)
124 return 0;
125
126 bufq_free(fio->fio_bufq);
127 err_bufq:
128 cv_destroy(&fio->fio_cv);
129 mutex_destroy(&fio->fio_lock);
130 kmem_free(fio->fio_data, fio->fio_if->erasesize);
131
132 return error;
133 }
134
135 void
136 flash_sync_thread_destroy(struct flash_io *fio)
137 {
138 FLDPRINTF(("stopping flash io thread\n"));
139
140 mutex_enter(&fio->fio_lock);
141
142 fio->fio_exiting = true;
143 cv_broadcast(&fio->fio_cv);
144
145 mutex_exit(&fio->fio_lock);
146
147 kthread_join(fio->fio_thread);
148
149 kmem_free(fio->fio_data, fio->fio_if->erasesize);
150 bufq_free(fio->fio_bufq);
151 mutex_destroy(&fio->fio_lock);
152 cv_destroy(&fio->fio_cv);
153 }
154
155 int
156 flash_io_submit(struct flash_io *fio, struct buf *bp)
157 {
158 FLDPRINTF(("submitting job to flash io thread: %p\n", bp));
159
160 if (__predict_false(fio->fio_exiting)) {
161 flash_io_done(fio, bp, ENODEV);
162 return ENODEV;
163 }
164
165 if (BUF_ISREAD(bp)) {
166 FLDPRINTF(("we have a read job\n"));
167
168 mutex_enter(&fio->fio_lock);
169 if (fio->fio_write_pending)
170 flash_io_cache_sync(fio);
171 mutex_exit(&fio->fio_lock);
172
173 flash_io_read(fio, bp);
174 } else {
175 FLDPRINTF(("we have a write job\n"));
176
177 flash_io_write(fio, bp);
178 }
179 return 0;
180 }
181
182 int
183 flash_io_cache_write(struct flash_io *fio, flash_addr_t block, struct buf *bp)
184 {
185 size_t retlen;
186 flash_addr_t base, offset;
187 int error;
188
189 KASSERT(mutex_owned(&fio->fio_lock));
190 KASSERT(fio->fio_if->erasesize != 0);
191
192 base = block * fio->fio_if->erasesize;
193 offset = bp->b_rawblkno * DEV_BSIZE - base;
194
195 FLDPRINTF(("io cache write, offset: %jd\n", (intmax_t )offset));
196
197 if (!fio->fio_write_pending) {
198 fio->fio_block = block;
199 /*
200 * fill the cache with data from flash,
201 * so we dont have to bother with gaps later
202 */
203 FLDPRINTF(("filling buffer from offset %ju\n", (uintmax_t)base));
204 error = fio->fio_if->read(fio->fio_dev,
205 base, fio->fio_if->erasesize,
206 &retlen, fio->fio_data);
207 FLDPRINTF(("cache filled\n"));
208
209 if (error)
210 return error;
211
212 fio->fio_write_pending = true;
213 /* save creation time for aging */
214 binuptime(&fio->fio_creation);
215 }
216 /* copy data to cache */
217 memcpy(fio->fio_data + offset, bp->b_data, bp->b_resid);
218 bufq_put(fio->fio_bufq, bp);
219
220 /* update timestamp */
221 binuptime(&fio->fio_last_write);
222
223 return 0;
224 }
225
226 void
227 flash_io_cache_sync(struct flash_io *fio)
228 {
229 struct flash_erase_instruction ei;
230 struct buf *bp;
231 size_t retlen;
232 flash_addr_t base;
233 int error;
234
235 KASSERT(mutex_owned(&fio->fio_lock));
236
237 if (!fio->fio_write_pending) {
238 FLDPRINTF(("trying to sync with an invalid buffer\n"));
239 return;
240 }
241
242 base = fio->fio_block * fio->fio_if->erasesize;
243
244 FLDPRINTF(("eraseing block at 0x%jx\n", (uintmax_t )base));
245 ei.ei_addr = base;
246 ei.ei_len = fio->fio_if->erasesize;
247 ei.ei_callback = NULL;
248 error = fio->fio_if->erase(fio->fio_dev, &ei);
249
250 if (error) {
251 aprint_error_dev(fio->fio_dev, "cannot erase flash flash!\n");
252 goto out;
253 }
254
255 FLDPRINTF(("writing %zu bytes to 0x%jx\n",
256 fio->fio_if->erasesize, (uintmax_t )base));
257
258 error = fio->fio_if->write(fio->fio_dev,
259 base, fio->fio_if->erasesize, &retlen, fio->fio_data);
260
261 if (error || retlen != fio->fio_if->erasesize) {
262 aprint_error_dev(fio->fio_dev, "can't sync write cache: %d\n", error);
263 goto out;
264 }
265
266 out:
267 while ((bp = bufq_get(fio->fio_bufq)) != NULL)
268 flash_io_done(fio, bp, error);
269
270 fio->fio_block = -1;
271 fio->fio_write_pending = false;
272 }
273
274 void
275 flash_sync_thread(void * arg)
276 {
277 struct flash_io *fio = arg;
278 struct bintime now;
279
280 mutex_enter(&fio->fio_lock);
281
282 while (!fio->fio_exiting) {
283 cv_timedwait_sig(&fio->fio_cv, &fio->fio_lock, hz / 4);
284 if (!fio->fio_write_pending) {
285 continue;
286 }
287 /* see if the cache is older than 3 seconds (safety limit),
288 * or if we havent touched the cache since more than 1 ms
289 */
290 binuptime(&now);
291 if (flash_timestamp_diff(&now, &fio->fio_last_write) > hz / 5) {
292 FLDPRINTF(("syncing write cache after timeout\n"));
293 flash_io_cache_sync(fio);
294 } else if (flash_timestamp_diff(&now, &fio->fio_creation)
295 > 3 * hz) {
296 aprint_error_dev(fio->fio_dev,
297 "syncing write cache after 3 sec timeout!\n");
298 flash_io_cache_sync(fio);
299 }
300 }
301
302 mutex_exit(&fio->fio_lock);
303
304 kthread_exit(0);
305 }
306
307 void
308 flash_io_read(struct flash_io *fio, struct buf *bp)
309 {
310 size_t retlen;
311 flash_addr_t offset;
312 int error;
313
314 FLDPRINTF(("flash io read\n"));
315
316 offset = bp->b_rawblkno * DEV_BSIZE;
317
318 error = fio->fio_if->read(fio->fio_dev, offset, bp->b_resid,
319 &retlen, bp->b_data);
320
321 flash_io_done(fio, bp, error);
322 }
323
324 void
325 flash_io_write(struct flash_io *fio, struct buf *bp)
326 {
327 flash_addr_t block;
328
329 FLDPRINTF(("flash io write\n"));
330
331 block = flash_io_getblock(fio, bp);
332 FLDPRINTF(("write to block %jd\n", (intmax_t )block));
333
334 mutex_enter(&fio->fio_lock);
335
336 if (fio->fio_write_pending && fio->fio_block != block) {
337 FLDPRINTF(("writing to new block, syncing caches\n"));
338 flash_io_cache_sync(fio);
339 }
340
341 flash_io_cache_write(fio, block, bp);
342
343 mutex_exit(&fio->fio_lock);
344 }
345
346 void
347 flash_io_done(struct flash_io *fio, struct buf *bp, int error)
348 {
349 FLDPRINTF(("io done: %p\n", bp));
350
351 if (error == 0)
352 bp->b_resid = 0;
353
354 bp->b_error = error;
355 biodone(bp);
356 }
357
358 static int
359 sysctl_flash_verify(SYSCTLFN_ARGS)
360 {
361 int error, t;
362 struct sysctlnode node;
363
364 node = *rnode;
365 t = *(int *)rnode->sysctl_data;
366 node.sysctl_data = &t;
367 error = sysctl_lookup(SYSCTLFN_CALL(&node));
368 if (error || newp == NULL)
369 return error;
370
371 if (node.sysctl_num == flash_cachesync_nodenum) {
372 if (t <= 0 || t > 60)
373 return EINVAL;
374 } else {
375 return EINVAL;
376 }
377
378 *(int *)rnode->sysctl_data = t;
379
380 return 0;
381 }
382
383 SYSCTL_SETUP(sysctl_flash, "sysctl flash subtree setup")
384 {
385 int rc, flash_root_num;
386 const struct sysctlnode *node;
387
388 if ((rc = sysctl_createv(clog, 0, NULL, NULL,
389 CTLFLAG_PERMANENT, CTLTYPE_NODE, "hw", NULL,
390 NULL, 0, NULL, 0, CTL_HW, CTL_EOL)) != 0) {
391 goto error;
392 }
393
394 if ((rc = sysctl_createv(clog, 0, NULL, &node,
395 CTLFLAG_PERMANENT, CTLTYPE_NODE, "flash",
396 SYSCTL_DESCR("FLASH driver controls"),
397 NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) {
398 goto error;
399 }
400
401 flash_root_num = node->sysctl_num;
402
403 if ((rc = sysctl_createv(clog, 0, NULL, &node,
404 CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
405 CTLTYPE_INT, "cache_sync_timeout",
406 SYSCTL_DESCR("FLASH write cache sync timeout in seconds"),
407 sysctl_flash_verify, 0, &flash_cachesync_timeout,
408 0, CTL_HW, flash_root_num, CTL_CREATE,
409 CTL_EOL)) != 0) {
410 goto error;
411 }
412
413 flash_cachesync_nodenum = node->sysctl_num;
414
415 return;
416
417 error:
418 aprint_error("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
419 }
420