flash_io.c revision 1.4.18.1 1 /* $NetBSD: flash_io.c,v 1.4.18.1 2014/05/18 17:45:36 rmind 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.4.18.1 2014/05/18 17:45:36 rmind 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, device_t dev,
100 struct flash_interface *flash_if)
101 {
102 int error;
103
104 FLDPRINTF(("starting flash io thread\n"));
105
106 fio->fio_dev = dev;
107 fio->fio_if = flash_if;
108
109 fio->fio_data = kmem_alloc(fio->fio_if->erasesize, KM_SLEEP);
110
111 mutex_init(&fio->fio_lock, MUTEX_DEFAULT, IPL_NONE);
112 cv_init(&fio->fio_cv, "flashcv");
113
114 error = bufq_alloc(&fio->fio_bufq, "fcfs", BUFQ_SORT_RAWBLOCK);
115 if (error)
116 goto err_bufq;
117
118 fio->fio_exiting = false;
119 fio->fio_write_pending = false;
120
121 /* arrange to allocate the kthread */
122 error = kthread_create(PRI_NONE, KTHREAD_MUSTJOIN | KTHREAD_MPSAFE,
123 NULL, flash_sync_thread, fio, &fio->fio_thread, "flashio");
124
125 if (!error)
126 return 0;
127
128 bufq_free(fio->fio_bufq);
129 err_bufq:
130 cv_destroy(&fio->fio_cv);
131 mutex_destroy(&fio->fio_lock);
132 kmem_free(fio->fio_data, fio->fio_if->erasesize);
133
134 return error;
135 }
136
137 void
138 flash_sync_thread_destroy(struct flash_io *fio)
139 {
140 FLDPRINTF(("stopping flash io thread\n"));
141
142 mutex_enter(&fio->fio_lock);
143
144 fio->fio_exiting = true;
145 cv_broadcast(&fio->fio_cv);
146
147 mutex_exit(&fio->fio_lock);
148
149 kthread_join(fio->fio_thread);
150
151 kmem_free(fio->fio_data, fio->fio_if->erasesize);
152 bufq_free(fio->fio_bufq);
153 mutex_destroy(&fio->fio_lock);
154 cv_destroy(&fio->fio_cv);
155 }
156
157 int
158 flash_io_submit(struct flash_io *fio, struct buf *bp)
159 {
160 FLDPRINTF(("submitting job to flash io thread: %p\n", bp));
161
162 if (__predict_false(fio->fio_exiting)) {
163 flash_io_done(fio, bp, ENODEV);
164 return ENODEV;
165 }
166
167 if (BUF_ISREAD(bp)) {
168 FLDPRINTF(("we have a read job\n"));
169
170 mutex_enter(&fio->fio_lock);
171 if (fio->fio_write_pending)
172 flash_io_cache_sync(fio);
173 mutex_exit(&fio->fio_lock);
174
175 flash_io_read(fio, bp);
176 } else {
177 FLDPRINTF(("we have a write job\n"));
178
179 flash_io_write(fio, bp);
180 }
181 return 0;
182 }
183
184 int
185 flash_io_cache_write(struct flash_io *fio, flash_addr_t block, struct buf *bp)
186 {
187 size_t retlen;
188 flash_addr_t base, offset;
189 int error;
190
191 KASSERT(mutex_owned(&fio->fio_lock));
192 KASSERT(fio->fio_if->erasesize != 0);
193
194 base = block * fio->fio_if->erasesize;
195 offset = bp->b_rawblkno * DEV_BSIZE - base;
196
197 FLDPRINTF(("io cache write, offset: %jd\n", (intmax_t )offset));
198
199 if (!fio->fio_write_pending) {
200 fio->fio_block = block;
201 /*
202 * fill the cache with data from flash,
203 * so we dont have to bother with gaps later
204 */
205 FLDPRINTF(("filling buffer from offset %ju\n", (uintmax_t)base));
206 error = fio->fio_if->read(fio->fio_dev,
207 base, fio->fio_if->erasesize,
208 &retlen, fio->fio_data);
209 FLDPRINTF(("cache filled\n"));
210
211 if (error)
212 return error;
213
214 fio->fio_write_pending = true;
215 /* save creation time for aging */
216 binuptime(&fio->fio_creation);
217 }
218 /* copy data to cache */
219 memcpy(fio->fio_data + offset, bp->b_data, bp->b_resid);
220 bufq_put(fio->fio_bufq, bp);
221
222 /* update timestamp */
223 binuptime(&fio->fio_last_write);
224
225 return 0;
226 }
227
228 void
229 flash_io_cache_sync(struct flash_io *fio)
230 {
231 struct flash_erase_instruction ei;
232 struct buf *bp;
233 size_t retlen;
234 flash_addr_t base;
235 int error;
236
237 KASSERT(mutex_owned(&fio->fio_lock));
238
239 if (!fio->fio_write_pending) {
240 FLDPRINTF(("trying to sync with an invalid buffer\n"));
241 return;
242 }
243
244 base = fio->fio_block * fio->fio_if->erasesize;
245
246 FLDPRINTF(("eraseing block at 0x%jx\n", (uintmax_t )base));
247 ei.ei_addr = base;
248 ei.ei_len = fio->fio_if->erasesize;
249 ei.ei_callback = NULL;
250 error = fio->fio_if->erase(fio->fio_dev, &ei);
251
252 if (error) {
253 aprint_error_dev(fio->fio_dev, "cannot erase flash flash!\n");
254 goto out;
255 }
256
257 FLDPRINTF(("writing %" PRIu32 " bytes to 0x%jx\n",
258 fio->fio_if->erasesize, (uintmax_t )base));
259
260 error = fio->fio_if->write(fio->fio_dev,
261 base, fio->fio_if->erasesize, &retlen, fio->fio_data);
262
263 if (error || retlen != fio->fio_if->erasesize) {
264 aprint_error_dev(fio->fio_dev, "can't sync write cache: %d\n", error);
265 goto out;
266 }
267
268 out:
269 while ((bp = bufq_get(fio->fio_bufq)) != NULL)
270 flash_io_done(fio, bp, error);
271
272 fio->fio_block = -1;
273 fio->fio_write_pending = false;
274 }
275
276 void
277 flash_sync_thread(void * arg)
278 {
279 struct flash_io *fio = arg;
280 struct bintime now;
281
282 mutex_enter(&fio->fio_lock);
283
284 while (!fio->fio_exiting) {
285 cv_timedwait_sig(&fio->fio_cv, &fio->fio_lock, hz / 4);
286 if (!fio->fio_write_pending) {
287 continue;
288 }
289 /* see if the cache is older than 3 seconds (safety limit),
290 * or if we havent touched the cache since more than 1 ms
291 */
292 binuptime(&now);
293 if (flash_timestamp_diff(&now, &fio->fio_last_write) > hz / 5) {
294 FLDPRINTF(("syncing write cache after timeout\n"));
295 flash_io_cache_sync(fio);
296 } else if (flash_timestamp_diff(&now, &fio->fio_creation)
297 > 3 * hz) {
298 aprint_error_dev(fio->fio_dev,
299 "syncing write cache after 3 sec timeout!\n");
300 flash_io_cache_sync(fio);
301 }
302 }
303
304 mutex_exit(&fio->fio_lock);
305
306 kthread_exit(0);
307 }
308
309 void
310 flash_io_read(struct flash_io *fio, struct buf *bp)
311 {
312 size_t retlen;
313 flash_addr_t offset;
314 int error;
315
316 FLDPRINTF(("flash io read\n"));
317
318 offset = bp->b_rawblkno * DEV_BSIZE;
319
320 error = fio->fio_if->read(fio->fio_dev, offset, bp->b_resid,
321 &retlen, bp->b_data);
322
323 flash_io_done(fio, bp, error);
324 }
325
326 void
327 flash_io_write(struct flash_io *fio, struct buf *bp)
328 {
329 flash_addr_t block;
330
331 FLDPRINTF(("flash io write\n"));
332
333 block = flash_io_getblock(fio, bp);
334 FLDPRINTF(("write to block %jd\n", (intmax_t )block));
335
336 mutex_enter(&fio->fio_lock);
337
338 if (fio->fio_write_pending && fio->fio_block != block) {
339 FLDPRINTF(("writing to new block, syncing caches\n"));
340 flash_io_cache_sync(fio);
341 }
342
343 flash_io_cache_write(fio, block, bp);
344
345 mutex_exit(&fio->fio_lock);
346 }
347
348 void
349 flash_io_done(struct flash_io *fio, struct buf *bp, int error)
350 {
351 FLDPRINTF(("io done: %p\n", bp));
352
353 if (error == 0)
354 bp->b_resid = 0;
355
356 bp->b_error = error;
357 biodone(bp);
358 }
359
360 static int
361 sysctl_flash_verify(SYSCTLFN_ARGS)
362 {
363 int error, t;
364 struct sysctlnode node;
365
366 node = *rnode;
367 t = *(int *)rnode->sysctl_data;
368 node.sysctl_data = &t;
369 error = sysctl_lookup(SYSCTLFN_CALL(&node));
370 if (error || newp == NULL)
371 return error;
372
373 if (node.sysctl_num == flash_cachesync_nodenum) {
374 if (t <= 0 || t > 60)
375 return EINVAL;
376 } else {
377 return EINVAL;
378 }
379
380 *(int *)rnode->sysctl_data = t;
381
382 return 0;
383 }
384
385 SYSCTL_SETUP(sysctl_flash, "sysctl flash subtree setup")
386 {
387 int rc, flash_root_num;
388 const struct sysctlnode *node;
389
390 if ((rc = sysctl_createv(clog, 0, NULL, &node,
391 CTLFLAG_PERMANENT, CTLTYPE_NODE, "flash",
392 SYSCTL_DESCR("FLASH driver controls"),
393 NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) {
394 goto error;
395 }
396
397 flash_root_num = node->sysctl_num;
398
399 if ((rc = sysctl_createv(clog, 0, NULL, &node,
400 CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
401 CTLTYPE_INT, "cache_sync_timeout",
402 SYSCTL_DESCR("FLASH write cache sync timeout in seconds"),
403 sysctl_flash_verify, 0, &flash_cachesync_timeout,
404 0, CTL_HW, flash_root_num, CTL_CREATE,
405 CTL_EOL)) != 0) {
406 goto error;
407 }
408
409 flash_cachesync_nodenum = node->sysctl_num;
410
411 return;
412
413 error:
414 aprint_error("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
415 }
416