1 /* $NetBSD: flash_io.c,v 1.2 2011/06/28 20:58:00 ahoka Exp $ */ 2 3 /*- 4 * Copyright (c) 2011 Department of Software Engineering, 5 * University of Szeged, Hungary 6 * Copyright (c) 2011 Adam Hoka <ahoka@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.2 2011/06/28 20:58:00 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 %" PRIu32 " 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