flash.c revision 1.1.4.3 1 /* $NetBSD: flash.c,v 1.1.4.3 2011/04/21 01:41:46 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 * Copyright (c) 2010 David Tengeri <dtengeri (at) inf.u-szeged.hu>
8 * All rights reserved.
9 *
10 * This code is derived from software contributed to The NetBSD Foundation
11 * by the Department of Software Engineering, University of Szeged, Hungary
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 ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * 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 /*-
36 * Framework for storage devices based on Flash technology
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: flash.c,v 1.1.4.3 2011/04/21 01:41:46 rmind Exp $");
41
42 #include <sys/param.h>
43 #include <sys/types.h>
44 #include <sys/proc.h>
45 #include <sys/errno.h>
46 #include <sys/ioctl.h>
47 #include <sys/device.h>
48 #include <sys/conf.h>
49 #include <sys/kmem.h>
50 #include <sys/uio.h>
51 #include <sys/kernel.h>
52
53 #include <sys/atomic.h>
54 #include <sys/buf.h>
55 #include <sys/bufq.h>
56 #include <sys/disk.h>
57 #include <sys/disklabel.h>
58 #include <sys/malloc.h>
59 #include <sys/reboot.h>
60
61 #include <sys/flashio.h>
62 #include "flash.h"
63
64 #define FLASH_DEBUG 1
65 #ifdef FLASH_DEBUG
66 #define DPRINTF(x) if (flashdebug) printf x
67 #define DPRINTFN(n,x) if (flashdebug>(n)) printf x
68 int flashdebug = FLASH_DEBUG;
69 #else
70 #define DPRINTF(x)
71 #define DPRINTFN(n,x)
72 #endif
73
74 extern struct cfdriver flash_cd;
75
76 dev_type_open(flashopen);
77 dev_type_close(flashclose);
78 dev_type_read(flashread);
79 dev_type_write(flashwrite);
80 dev_type_ioctl(flashioctl);
81 dev_type_strategy(flashstrategy);
82 dev_type_dump(flashdump);
83 dev_type_size(flashsize);
84
85 int flash_print(void *aux, const char *pnp);
86
87 bool flash_shutdown(device_t dev, int how);
88 int flash_nsectors(struct buf *bp);
89 int flash_sector(struct buf *bp);
90
91 static inline flash_off_t flash_get_part_offset(struct flash_softc *fl,
92 size_t poffset);
93
94 int flash_match(device_t parent, cfdata_t match, void *aux);
95 void flash_attach(device_t parent, device_t self, void *aux);
96 int flash_detach(device_t device, int flags);
97
98 CFATTACH_DECL_NEW(flash, sizeof(struct flash_softc),
99 flash_match, flash_attach, flash_detach, NULL);
100
101 /**
102 * Block device's operation
103 */
104 const struct bdevsw flash_bdevsw = {
105 .d_open = flashopen,
106 .d_close = flashclose,
107 .d_strategy = flashstrategy,
108 .d_ioctl = flashioctl,
109 .d_dump = flashdump,
110 .d_psize = flashsize,
111 .d_flag = D_DISK | D_MPSAFE
112 };
113
114 /**
115 * Character device's operations
116 */
117 const struct cdevsw flash_cdevsw = {
118 .d_open = flashopen,
119 .d_close = flashclose,
120 .d_read = flashread,
121 .d_write = flashwrite,
122 .d_ioctl = flashioctl,
123 .d_stop = nostop,
124 .d_tty = notty,
125 .d_poll = nopoll,
126 .d_mmap = nommap,
127 .d_kqfilter = nokqfilter,
128 .d_flag = D_DISK | D_MPSAFE
129 };
130
131 /* ARGSUSED */
132 int
133 flash_match(device_t parent, cfdata_t match, void *aux)
134 {
135 /* pseudo device, always attaches */
136 return 1;
137 }
138
139 /* ARGSUSED */
140 void
141 flash_attach(device_t parent, device_t self, void *aux)
142 {
143 struct flash_softc *sc = device_private(self);
144 struct flash_attach_args *faa = aux;
145 char pbuf[2][sizeof("9999 KB")];
146
147 sc->sc_dev = self;
148 sc->sc_parent_dev = parent;
149 sc->flash_if = faa->flash_if;
150 sc->hw_softc = device_private(parent);
151
152 format_bytes(pbuf[0], sizeof(pbuf[0]), sc->flash_if->size);
153 format_bytes(pbuf[1], sizeof(pbuf[1]), sc->flash_if->erasesize);
154
155 aprint_naive("\n");
156
157 switch (sc->flash_if->type) {
158 case FLASH_TYPE_NOR:
159 aprint_normal(": %s NOR flash\n", pbuf[0]);
160 break;
161
162 case FLASH_TYPE_NAND:
163 aprint_normal(": %s NAND flash\n", pbuf[0]);
164 break;
165
166 default:
167 aprint_normal(": %s unknown flash\n", pbuf[0]);
168 }
169
170 aprint_normal_dev(sc->sc_dev,
171 "size: 0x%jx, offset: 0x%jx",
172 (uintmax_t )sc->flash_if->partition.part_size,
173 (uintmax_t )sc->flash_if->partition.part_offset);
174
175 if (sc->flash_if->partition.part_flags & FLASH_PART_READONLY) {
176 sc->sc_readonly = true;
177 aprint_normal(", read only");
178 } else {
179 sc->sc_readonly = false;
180 }
181
182 aprint_normal("\n");
183
184 if (sc->flash_if->partition.part_size == 0) {
185 aprint_error_dev(self,
186 "partition size must be larger than 0\n");
187 return;
188 }
189
190 switch (sc->flash_if->type) {
191 case FLASH_TYPE_NOR:
192 aprint_normal_dev(sc->sc_dev,
193 "erase size %s bytes, write size %d bytes\n",
194 pbuf[1], sc->flash_if->writesize);
195 break;
196
197 case FLASH_TYPE_NAND:
198 default:
199 aprint_normal_dev(sc->sc_dev,
200 "erase size %s, page size %d bytes, write size %d bytes\n",
201 pbuf[1], sc->flash_if->page_size,
202 sc->flash_if->writesize);
203 break;
204 }
205
206 if (!pmf_device_register1(sc->sc_dev, NULL, NULL, flash_shutdown))
207 aprint_error_dev(sc->sc_dev,
208 "couldn't establish power handler\n");
209 }
210
211 int
212 flash_detach(device_t device, int flags)
213 {
214 struct flash_softc *sc = device_private(device);
215
216 pmf_device_deregister(sc->sc_dev);
217
218 /* freeing flash_if is our responsibility */
219 printf("freeing flash_if...");
220 kmem_free(sc->flash_if, sizeof(*sc->flash_if));
221 printf("done!\n");
222
223 return 0;
224 }
225
226 int
227 flash_print(void *aux, const char *pnp)
228 {
229 struct flash_attach_args *arg;
230 const char *type;
231
232 if (pnp != NULL) {
233 arg = aux;
234 switch (arg->flash_if->type) {
235 case FLASH_TYPE_NOR:
236 type = "NOR";
237 break;
238 case FLASH_TYPE_NAND:
239 type = "NAND";
240 break;
241 default:
242 panic("flash_print: unknown type %d",
243 arg->flash_if->type);
244 }
245 aprint_normal("%s flash at %s", type, pnp);
246 }
247 return UNCONF;
248 }
249
250 device_t
251 flash_attach_mi(struct flash_interface *flash_if, device_t device)
252 {
253 struct flash_attach_args arg;
254
255 #ifdef DIAGNOSTIC
256 if (flash_if == NULL) {
257 aprint_error("flash_attach_mi: NULL\n");
258 return 0;
259 }
260 #endif
261 arg.flash_if = flash_if;
262
263 return config_found_ia(device, "flashbus", &arg, flash_print);
264 }
265
266 /**
267 * flash_open - open the character device
268 * Checks if there is a driver registered to the minor number of the open
269 * request.
270 */
271 int
272 flashopen(dev_t dev, int flags, int fmt, struct lwp *l)
273 {
274 int unit = minor(dev);
275 struct flash_softc *sc;
276
277 DPRINTFN(1, ("flash: opening device unit %d\n", unit));
278
279 if ((sc = device_lookup_private(&flash_cd, unit)) == NULL)
280 return ENXIO;
281
282 /* TODO return eperm if want to open for writing a read only dev */
283
284 /* reset buffer length */
285 // sc->sc_cache->fc_len = 0;
286
287 return 0;
288 }
289
290 /**
291 * flash_close - close device
292 * We don't have to release any resources, so just return 0.
293 */
294 int
295 flashclose(dev_t dev, int flags, int fmt, struct lwp *l)
296 {
297 int unit = minor(dev);
298 struct flash_softc *sc;
299 int err;
300
301 DPRINTFN(1, ("flash: closing flash device unit %d\n", unit));
302
303 if ((sc = device_lookup_private(&flash_cd, unit)) == NULL)
304 return ENXIO;
305
306 if (!sc->sc_readonly) {
307 err = flash_sync(sc->sc_dev);
308 if (err)
309 return err;
310 }
311
312 return 0;
313 }
314
315 /**
316 * flash_read - read from character device
317 * This function uses the registered driver's read function to read the requested length to
318 * a buffer and then moves this buffer to userspace.
319 */
320 int
321 flashread(dev_t dev, struct uio *uio, int flag)
322 {
323 return physio(flashstrategy, NULL, dev, B_READ, minphys, uio);
324 }
325
326 /**
327 * flash_write - write to character device
328 * This function moves the data into a buffer from userspace to kernel space,
329 * then uses the registered driver's write function to write out the data to
330 * the media.
331 */
332 int
333 flashwrite(dev_t dev, struct uio *uio, int flag)
334 {
335 return physio(flashstrategy, NULL, dev, B_WRITE, minphys, uio);
336 }
337
338 void
339 flashstrategy(struct buf *bp)
340 {
341 struct flash_softc *sc;
342 const struct flash_interface *flash_if;
343 const struct flash_partition *part;
344 int unit, device_blks;
345
346 unit = minor(bp->b_dev);
347 sc = device_lookup_private(&flash_cd, unit);
348 if (sc == NULL) {
349 bp->b_error = ENXIO;
350 goto done;
351 }
352
353 flash_if = sc->flash_if;
354 part = &flash_if->partition;
355
356 /* divider */
357 KASSERT(flash_if->writesize != 0);
358
359 aprint_debug_dev(sc->sc_dev, "flash_strategy()\n");
360
361 if (!(bp->b_flags & B_READ) && sc->sc_readonly) {
362 bp->b_error = EACCES;
363 goto done;
364 }
365
366 /* check if length is not negative */
367 if (bp->b_blkno < 0) {
368 bp->b_error = EINVAL;
369 goto done;
370 }
371
372 /* zero lenght i/o */
373 if (bp->b_bcount == 0) {
374 goto done;
375 }
376
377 device_blks = sc->flash_if->size / DEV_BSIZE;
378 KASSERT(part->part_offset % DEV_BSIZE == 0);
379 bp->b_rawblkno = bp->b_blkno + (part->part_offset / DEV_BSIZE);
380
381 if (bounds_check_with_mediasize(bp, DEV_BSIZE, device_blks) <= 0) {
382 goto done;
383 }
384
385 bp->b_resid = bp->b_bcount;
386 flash_if->submit(sc->sc_parent_dev, bp);
387
388 return;
389 done:
390 bp->b_resid = bp->b_bcount;
391 biodone(bp);
392 }
393
394 /*
395 * Handle the ioctl for the device
396 */
397 int
398 flashioctl(dev_t dev, u_long command, void *data, int flags, struct lwp *l)
399 {
400 struct flash_erase_params *ep;
401 struct flash_info_params *ip;
402 struct flash_dump_params *dp;
403 struct flash_badblock_params *bbp;
404 struct flash_erase_instruction ei;
405 struct flash_softc *sc;
406 int unit, err;
407 size_t retlen;
408 flash_off_t offset;
409 bool bad;
410
411 unit = minor(dev);
412 if ((sc = device_lookup_private(&flash_cd, unit)) == NULL)
413 return ENXIO;
414
415 err = 0;
416 switch (command) {
417 case FLASH_ERASE_BLOCK:
418 /**
419 * Set up an erase instruction then call the registered
420 * driver's erase operation.
421 */
422 ep = data;
423
424 if (sc->sc_readonly) {
425 return EACCES;
426 }
427
428 ei.ei_addr = ep->ep_addr;
429 ei.ei_len = ep->ep_len;
430 ei.ei_callback = NULL;
431
432 err = flash_erase(sc->sc_dev, &ei);
433 if (err) {
434 return err;
435 }
436
437 break;
438 case FLASH_BLOCK_ISBAD:
439 /**
440 * Set up an erase instruction then call the registered
441 * driver's erase operation.
442 */
443 bbp = data;
444
445 err = flash_block_isbad(sc->sc_dev, bbp->bbp_addr, &bad);
446 if (err) {
447 return err;
448 }
449 bbp->bbp_isbad = bad;
450
451 break;
452 case FLASH_BLOCK_MARKBAD:
453 bbp = data;
454
455 err = flash_block_markbad(sc->sc_dev, bbp->bbp_addr);
456
457 break;
458 case FLASH_DUMP:
459 dp = data;
460 offset = dp->dp_block * sc->flash_if->erasesize;
461 DPRINTF(("Reading from block: %jd len: %jd\n",
462 (intmax_t )dp->dp_block, (intmax_t )dp->dp_len));
463 err = flash_read(sc->sc_parent_dev, offset, dp->dp_len,
464 &retlen, dp->dp_buf);
465 if (err)
466 return err;
467 if (retlen != dp->dp_len) {
468 dp->dp_len = -1;
469 dp->dp_buf = NULL;
470 }
471
472 break;
473 case FLASH_GET_INFO:
474 ip = data;
475
476 ip->ip_page_size = sc->flash_if->page_size;
477 ip->ip_erase_size = sc->flash_if->erasesize;
478 ip->ip_flash_type = sc->flash_if->type;
479 ip->ip_flash_size = sc->flash_if->size;
480 break;
481 default:
482 err = ENODEV;
483 }
484
485 return err;
486 }
487
488 int
489 flashsize(dev_t dev)
490 {
491 return -1;
492 }
493
494 int
495 flashdump(dev_t dev, daddr_t blkno, void *va, size_t size)
496 {
497 return EACCES;
498 }
499
500 bool
501 flash_shutdown(device_t self, int how)
502 {
503 struct flash_softc *sc = device_private(self);
504
505 if ((how & RB_NOSYNC) == 0 && !sc->sc_readonly)
506 flash_sync(self);
507
508 return true;
509 }
510
511 const struct flash_interface *
512 flash_get_interface(dev_t dev)
513 {
514 struct flash_softc *sc;
515 int unit;
516
517 unit = minor(dev);
518 if ((sc = device_lookup_private(&flash_cd, unit)) == NULL)
519 return NULL;
520
521 return sc->flash_if;
522 }
523
524 const struct flash_softc *
525 flash_get_softc(dev_t dev)
526 {
527 struct flash_softc *sc;
528 int unit;
529
530 unit = minor(dev);
531 sc = device_lookup_private(&flash_cd, unit);
532
533 return sc;
534 }
535
536 device_t
537 flash_get_device(dev_t dev)
538 {
539 struct flash_softc *sc;
540 int unit;
541
542 unit = minor(dev);
543 sc = device_lookup_private(&flash_cd, unit);
544
545 return sc->sc_dev;
546 }
547
548 static inline flash_off_t
549 flash_get_part_offset(struct flash_softc *fl, size_t poffset)
550 {
551 return fl->flash_if->partition.part_offset + poffset;
552 }
553
554 int
555 flash_erase(device_t self, struct flash_erase_instruction *ei)
556 {
557 struct flash_softc *sc = device_private(self);
558 KASSERT(ei != NULL);
559 struct flash_erase_instruction e = *ei;
560
561 if (sc->sc_readonly)
562 return EACCES;
563
564 /* adjust for flash partition */
565 e.ei_addr += sc->flash_if->partition.part_offset;
566
567 /* bounds check for flash partition */
568 if (e.ei_addr + e.ei_len > sc->flash_if->partition.part_size +
569 sc->flash_if->partition.part_offset)
570 return EINVAL;
571
572 return sc->flash_if->erase(device_parent(self), &e);
573 }
574
575 int
576 flash_read(device_t self,
577 flash_off_t offset, size_t len, size_t *retlen, uint8_t *buf)
578 {
579 struct flash_softc *sc = device_private(self);
580
581 offset += sc->flash_if->partition.part_offset;
582
583 if (offset + len > sc->flash_if->partition.part_size +
584 sc->flash_if->partition.part_offset)
585 return EINVAL;
586
587 return sc->flash_if->read(device_parent(self),
588 offset, len, retlen, buf);
589 }
590
591 int
592 flash_write(device_t self,
593 flash_off_t offset, size_t len, size_t *retlen, const uint8_t *buf)
594 {
595 struct flash_softc *sc = device_private(self);
596
597 if (sc->sc_readonly)
598 return EACCES;
599
600 offset += sc->flash_if->partition.part_offset;
601
602 if (offset + len > sc->flash_if->partition.part_size +
603 sc->flash_if->partition.part_offset)
604 return EINVAL;
605
606 return sc->flash_if->write(device_parent(self),
607 offset, len, retlen, buf);
608 }
609
610 int
611 flash_block_markbad(device_t self, flash_off_t offset)
612 {
613 struct flash_softc *sc = device_private(self);
614
615 if (sc->sc_readonly)
616 return EACCES;
617
618 offset += sc->flash_if->partition.part_offset;
619
620 if (offset + sc->flash_if->erasesize >=
621 sc->flash_if->partition.part_size +
622 sc->flash_if->partition.part_offset)
623 return EINVAL;
624
625 return sc->flash_if->block_markbad(device_parent(self), offset);
626 }
627
628 int
629 flash_block_isbad(device_t self, flash_off_t offset, bool *bad)
630 {
631 struct flash_softc *sc = device_private(self);
632
633 offset += sc->flash_if->partition.part_offset;
634
635 if (offset + sc->flash_if->erasesize >
636 sc->flash_if->partition.part_size +
637 sc->flash_if->partition.part_offset)
638 return EINVAL;
639
640 return sc->flash_if->block_isbad(device_parent(self), offset, bad);
641 }
642
643 int
644 flash_sync(device_t self)
645 {
646 struct flash_softc *sc = device_private(self);
647
648 if (sc->sc_readonly)
649 return EACCES;
650
651 /* noop now TODO: implement */
652 return 0;
653 }
654
655 MODULE(MODULE_CLASS_DRIVER, flash, NULL);
656
657 #ifdef _MODULE
658 #include "ioconf.c"
659 #endif
660
661 static int
662 flash_modcmd(modcmd_t cmd, void *opaque)
663 {
664 int error = 0;
665 #ifdef _MODULE
666 int bmaj = -1, cmaj = -1;
667 #endif
668
669 switch (cmd) {
670 case MODULE_CMD_INIT:
671 #ifdef _MODULE
672 error = config_init_component(cfdriver_ioconf_flash,
673 cfattach_ioconf_flash, cfdata_ioconf_flash);
674 if (error)
675 return error;
676 error = devsw_attach("flash", &flash_bdevsw, &bmaj,
677 &flash_cdevsw, &cmaj);
678 if (error)
679 config_fini_component(cfdriver_ioconf_flash,
680 cfattach_ioconf_flash, cfdata_ioconf_flash);
681 #endif
682 return error;
683 case MODULE_CMD_FINI:
684 #ifdef _MODULE
685 devsw_detach(&flash_bdevsw, &flash_cdevsw);
686 error = config_fini_component(cfdriver_ioconf_flash,
687 cfattach_ioconf_flash, cfdata_ioconf_flash);
688 #endif
689 return error;
690 default:
691 return ENOTTY;
692 }
693 }
694