Annotation of sys/dev/flash.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: flash.c,v 1.8 2007/06/20 18:15:46 deraadt Exp $ */
2:
3: /*
4: * Copyright (c) 2005 Uwe Stuehler <uwe@openbsd.org>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: #include <sys/param.h>
20: #include <sys/buf.h>
21: #include <sys/conf.h>
22: #include <sys/device.h>
23: #include <sys/disk.h>
24: #include <sys/disklabel.h>
25: #include <sys/dkio.h>
26: #include <sys/kernel.h>
27: #include <sys/stat.h>
28: #include <sys/systm.h>
29:
30: #include <dev/flashvar.h>
31:
32: #include <ufs/ffs/fs.h> /* XXX */
33:
34: /* Samsung command set */
35: #define SAMSUNG_CMD_PTRLO 0x00
36: #define SAMSUNG_CMD_PTRHI 0x01
37: #define SAMSUNG_CMD_PTROOB 0x50
38: #define SAMSUNG_CMD_READ 0x30
39: #define SAMSUNG_CMD_SEQIN 0x80
40: #define SAMSUNG_CMD_WRITE 0x10
41: #define SAMSUNG_CMD_ERASE0 0x60
42: #define SAMSUNG_CMD_ERASE1 0xd0
43: #define SAMSUNG_CMD_STATUS 0x70
44: #define STATUS_FAIL (1<<0)
45: #define STATUS_READY (1<<6)
46: #define STATUS_NWP (1<<7)
47: #define SAMSUNG_CMD_READID 0x90
48: #define SAMSUNG_CMD_RESET 0xff
49:
50: int flash_wait_ready(struct flash_softc *);
51: int flash_wait_complete(struct flash_softc *);
52:
53: /* XXX: these should go elsewhere */
54: cdev_decl(flash);
55: bdev_decl(flash);
56:
57: #define flashlock(sc) disk_lock(&(sc)->sc_dk)
58: #define flashunlock(sc) disk_unlock(&(sc)->sc_dk)
59: #define flashlookup(unit) \
60: (struct flash_softc *)device_lookup(&flash_cd, (unit))
61:
62: void flashminphys(struct buf *);
63: void flashstart(struct flash_softc *);
64: void _flashstart(struct flash_softc *, struct buf *);
65: void flashdone(void *);
66:
67: int flashsafestrategy(struct flash_softc *, struct buf *);
68: void flashgetdefaultlabel(dev_t, struct flash_softc *,
69: struct disklabel *);
70: void flashgetdisklabel(dev_t, struct flash_softc *, struct disklabel *, int);
71:
72: /*
73: * Driver attachment glue
74: */
75:
76: struct flashvendor {
77: u_int8_t vendor;
78: const char *name;
79: };
80:
81: static const struct flashvendor flashvendors[] = {
82: { FLASH_VENDOR_SAMSUNG, "Samsung" }
83: };
84: #define FLASH_NVENDORS (sizeof(flashvendors) / sizeof(flashvendors[0]))
85:
86: static const struct flashdev flashdevs[] = {
87: { FLASH_DEVICE_SAMSUNG_K9F2808U0C, "K9F2808U0C 16Mx8 3.3V",
88: 512, 16, 32, 32768 },
89: { FLASH_DEVICE_SAMSUNG_K9F1G08U0A, "K9F1G08U0A 128Mx8 3.3V",
90: 2048, 64, 64, 65536 },
91: };
92: #define FLASH_NDEVS (sizeof(flashdevs) / sizeof(flashdevs[0]))
93:
94: struct cfdriver flash_cd = {
95: NULL, "flash", DV_DISK
96: };
97:
98: struct dkdriver flashdkdriver = { flashstrategy };
99:
100: void
101: flashattach(struct flash_softc *sc, struct flash_ctl_tag *tag,
102: void *cookie)
103: {
104: u_int8_t vendor, device;
105: u_int16_t id;
106: int i;
107:
108: sc->sc_tag = tag;
109: sc->sc_cookie = cookie;
110:
111: if (sc->sc_maxwaitready <= 0)
112: sc->sc_maxwaitready = 1000; /* 1ms */
113: if (sc->sc_maxwaitcomplete <= 0)
114: sc->sc_maxwaitcomplete = 200000; /* 200ms */
115:
116: flash_chip_enable(sc);
117:
118: /* Identify the flash device. */
119: if (flash_chip_identify(sc, &vendor, &device) != 0) {
120: printf(": identification failed\n");
121: flash_chip_disable(sc);
122: return;
123: }
124: id = (vendor << 8) | device;
125:
126: /* Look up device characteristics, abort if not recognized. */
127: for (i = 0; i < FLASH_NVENDORS; i++) {
128: if (flashvendors[i].vendor == vendor) {
129: printf(": %s", flashvendors[i].name);
130: break;
131: }
132: }
133: if (i == FLASH_NVENDORS)
134: printf(": vendor 0x%02x", vendor);
135: for (i = 0; i < FLASH_NDEVS; i++) {
136: if (flashdevs[i].id == id) {
137: printf(" %s\n", flashdevs[i].longname);
138: break;
139: }
140: }
141: if (i == FLASH_NDEVS) {
142: /* Need to add this device to flashdevs first. */
143: printf(" device 0x%02x\n", device);
144: flash_chip_disable(sc);
145: return;
146: }
147: sc->sc_flashdev = &flashdevs[i];
148:
149: /* Check if the device really works or fail early. */
150: if (flash_chip_reset(sc) != 0) {
151: printf("%s: reset failed\n", sc->sc_dev.dv_xname);
152: flash_chip_disable(sc);
153: return;
154: }
155:
156: flash_chip_disable(sc);
157:
158: /*
159: * Initialize and attach the disk structure.
160: */
161: sc->sc_dk.dk_driver = &flashdkdriver;
162: sc->sc_dk.dk_name = sc->sc_dev.dv_xname;
163: disk_attach(&sc->sc_dk);
164:
165: /* XXX establish shutdown hook to finish any commands. */
166: }
167:
168: int
169: flashdetach(struct device *self, int flags)
170: {
171: struct flash_softc *sc = (struct flash_softc *)self;
172:
173: /* Detach disk. */
174: disk_detach(&sc->sc_dk);
175:
176: /* XXX more resources need to be freed here. */
177: return 0;
178: }
179:
180: int
181: flashactivate(struct device *self, enum devact act)
182: {
183: /* XXX anything to be done here? */
184: return 0;
185: }
186:
187: /*
188: * Flash controller and chip functions
189: */
190:
191: u_int8_t
192: flash_reg8_read(struct flash_softc *sc, int reg)
193: {
194: return sc->sc_tag->reg8_read(sc->sc_cookie, reg);
195: }
196:
197: void
198: flash_reg8_read_page(struct flash_softc *sc, caddr_t data, caddr_t oob)
199: {
200: int i;
201:
202: for (i = 0; i < sc->sc_flashdev->pagesize; i++)
203: data[i] = flash_reg8_read(sc, FLASH_REG_DATA);
204:
205: if (oob != NULL)
206: for (i = 0; i < sc->sc_flashdev->oobsize; i++)
207: oob[i] = flash_reg8_read(sc, FLASH_REG_DATA);
208: }
209:
210: void
211: flash_reg8_write(struct flash_softc *sc, int reg, u_int8_t value)
212: {
213: sc->sc_tag->reg8_write(sc->sc_cookie, reg, value);
214: }
215:
216: void
217: flash_reg8_write_page(struct flash_softc *sc, caddr_t data, caddr_t oob)
218: {
219: int i;
220:
221: for (i = 0; i < sc->sc_flashdev->pagesize; i++)
222: flash_reg8_write(sc, FLASH_REG_DATA, data[i]);
223:
224: if (oob != NULL)
225: for (i = 0; i < sc->sc_flashdev->oobsize; i++)
226: flash_reg8_write(sc, FLASH_REG_DATA, oob[i]);
227: }
228:
229: /*
230: * Wait for the "Ready/Busy" signal to go high, indicating that the
231: * device is ready to accept another command.
232: */
233: int
234: flash_wait_ready(struct flash_softc *sc)
235: {
236: int timo = sc->sc_maxwaitready;
237: u_int8_t ready;
238:
239: ready = flash_reg8_read(sc, FLASH_REG_READY);
240: while (ready == 0 && timo-- > 0) {
241: delay(1);
242: ready = flash_reg8_read(sc, FLASH_REG_READY);
243: }
244: return (ready == 0 ? EIO : 0);
245: }
246:
247: /*
248: * Similar to flash_wait_ready() but looks at IO 6 and IO 0 signals
249: * besides R/B to decide whether the last operation was successful.
250: */
251: int
252: flash_wait_complete(struct flash_softc *sc)
253: {
254: int timo = sc->sc_maxwaitcomplete;
255: u_int8_t status;
256:
257: (void)flash_wait_ready(sc);
258:
259: flash_reg8_write(sc, FLASH_REG_CLE, 1);
260: flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_STATUS);
261: flash_reg8_write(sc, FLASH_REG_CLE, 0);
262:
263: status = flash_reg8_read(sc, FLASH_REG_DATA);
264: while ((status & STATUS_READY) == 0 && timo-- > 0) {
265: if (flash_reg8_read(sc, FLASH_REG_READY))
266: break;
267: delay(1);
268: status = flash_reg8_read(sc, FLASH_REG_DATA);
269: }
270:
271: status = flash_reg8_read(sc, FLASH_REG_DATA);
272: return ((status & STATUS_FAIL) != 0 ? EIO : 0);
273: }
274:
275: void
276: flash_chip_enable(struct flash_softc *sc)
277: {
278: /* XXX aquire the lock. */
279: flash_reg8_write(sc, FLASH_REG_CE, 1);
280: }
281:
282: void
283: flash_chip_disable(struct flash_softc *sc)
284: {
285: flash_reg8_write(sc, FLASH_REG_CE, 0);
286: /* XXX release the lock. */
287: }
288:
289: int
290: flash_chip_reset(struct flash_softc *sc)
291: {
292: flash_reg8_write(sc, FLASH_REG_CLE, 1);
293: flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_RESET);
294: flash_reg8_write(sc, FLASH_REG_CLE, 0);
295:
296: return flash_wait_ready(sc);
297: }
298:
299: int
300: flash_chip_identify(struct flash_softc *sc, u_int8_t *vendor,
301: u_int8_t *device)
302: {
303: int error;
304:
305: (void)flash_wait_ready(sc);
306:
307: flash_reg8_write(sc, FLASH_REG_CLE, 1);
308: flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_READID);
309: flash_reg8_write(sc, FLASH_REG_CLE, 0);
310:
311: error = flash_wait_ready(sc);
312: if (error == 0) {
313: *vendor = flash_reg8_read(sc, FLASH_REG_DATA);
314: *device = flash_reg8_read(sc, FLASH_REG_DATA);
315: }
316: return error;
317: }
318:
319: int
320: flash_chip_erase_block(struct flash_softc *sc, long blkno)
321: {
322: long pageno = blkno * sc->sc_flashdev->blkpages;
323: int error;
324:
325: (void)flash_wait_ready(sc);
326:
327: /* Disable write-protection. */
328: flash_reg8_write(sc, FLASH_REG_WP, 0);
329:
330: switch (sc->sc_flashdev->id) {
331: case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
332: case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
333: flash_reg8_write(sc, FLASH_REG_CLE, 1);
334: flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_ERASE0);
335: flash_reg8_write(sc, FLASH_REG_CLE, 0);
336: break;
337: }
338:
339: switch (sc->sc_flashdev->id) {
340: case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
341: case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
342: flash_reg8_write(sc, FLASH_REG_ALE, 1);
343: flash_reg8_write(sc, FLASH_REG_ROW, pageno);
344: flash_reg8_write(sc, FLASH_REG_ROW, pageno >> 8);
345: flash_reg8_write(sc, FLASH_REG_ALE, 0);
346: break;
347: }
348:
349: switch (sc->sc_flashdev->id) {
350: case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
351: case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
352: flash_reg8_write(sc, FLASH_REG_CLE, 1);
353: flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_ERASE1);
354: flash_reg8_write(sc, FLASH_REG_CLE, 0);
355: break;
356: }
357:
358: error = flash_wait_complete(sc);
359:
360: /* Re-enable write-protection. */
361: flash_reg8_write(sc, FLASH_REG_WP, 1);
362:
363: return error;
364: }
365:
366: int
367: flash_chip_read_block(struct flash_softc *sc, long blkno, caddr_t data)
368: {
369: long pageno;
370: long blkend;
371: int error;
372:
373: pageno = blkno * sc->sc_flashdev->blkpages;
374: blkend = pageno + sc->sc_flashdev->blkpages;
375:
376: while (pageno < blkend) {
377: error = flash_chip_read_page(sc, pageno, data, NULL);
378: if (error != 0)
379: return error;
380: data += sc->sc_flashdev->pagesize;
381: pageno++;
382: }
383: return 0;
384: }
385:
386: int
387: flash_chip_read_page(struct flash_softc *sc, long pageno, caddr_t data,
388: caddr_t oob)
389: {
390: int error;
391:
392: (void)flash_wait_ready(sc);
393:
394: switch (sc->sc_flashdev->id) {
395: case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
396: case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
397: flash_reg8_write(sc, FLASH_REG_CLE, 1);
398: flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_PTRLO);
399: flash_reg8_write(sc, FLASH_REG_CLE, 0);
400: break;
401: }
402:
403: switch (sc->sc_flashdev->id) {
404: case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
405: flash_reg8_write(sc, FLASH_REG_ALE, 1);
406: flash_reg8_write(sc, FLASH_REG_COL, 0x00);
407: flash_reg8_write(sc, FLASH_REG_ALE, 0);
408: break;
409: case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
410: flash_reg8_write(sc, FLASH_REG_ALE, 1);
411: flash_reg8_write(sc, FLASH_REG_COL, 0x00);
412: flash_reg8_write(sc, FLASH_REG_COL, 0x00);
413: flash_reg8_write(sc, FLASH_REG_ALE, 0);
414: break;
415: }
416:
417: switch (sc->sc_flashdev->id) {
418: case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
419: case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
420: flash_reg8_write(sc, FLASH_REG_ALE, 1);
421: flash_reg8_write(sc, FLASH_REG_ROW, pageno);
422: flash_reg8_write(sc, FLASH_REG_ROW, pageno >> 8);
423: flash_reg8_write(sc, FLASH_REG_ALE, 0);
424: break;
425: }
426:
427: switch (sc->sc_flashdev->id) {
428: case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
429: flash_reg8_write(sc, FLASH_REG_CLE, 1);
430: flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_READ);
431: flash_reg8_write(sc, FLASH_REG_CLE, 0);
432: break;
433: }
434:
435: if ((error = flash_wait_ready(sc)) != 0)
436: return error;
437:
438: /* Support hardware ECC calculation. */
439: if (sc->sc_tag->regx_read_page) {
440: error = sc->sc_tag->regx_read_page(sc->sc_cookie, data,
441: oob);
442: if (error != 0)
443: return error;
444: } else
445: flash_reg8_read_page(sc, data, oob);
446:
447: return 0;
448: }
449:
450: int
451: flash_chip_read_oob(struct flash_softc *sc, long pageno, caddr_t oob)
452: {
453: u_int8_t *p = (u_int8_t *)oob;
454: int error;
455: int i;
456:
457: (void)flash_wait_ready(sc);
458:
459: switch (sc->sc_flashdev->id) {
460: case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
461: flash_reg8_write(sc, FLASH_REG_CLE, 1);
462: flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_PTROOB);
463: flash_reg8_write(sc, FLASH_REG_CLE, 0);
464: break;
465: case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
466: flash_reg8_write(sc, FLASH_REG_CLE, 1);
467: flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_PTRLO);
468: flash_reg8_write(sc, FLASH_REG_CLE, 0);
469: break;
470: }
471:
472: switch (sc->sc_flashdev->id) {
473: case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
474: flash_reg8_write(sc, FLASH_REG_ALE, 1);
475: flash_reg8_write(sc, FLASH_REG_COL, 0x00);
476: flash_reg8_write(sc, FLASH_REG_ALE, 0);
477: break;
478: case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
479: flash_reg8_write(sc, FLASH_REG_ALE, 1);
480: flash_reg8_write(sc, FLASH_REG_COL, 0x00);
481: flash_reg8_write(sc, FLASH_REG_COL, 0x08);
482: flash_reg8_write(sc, FLASH_REG_ALE, 0);
483: break;
484: }
485:
486: switch (sc->sc_flashdev->id) {
487: case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
488: case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
489: flash_reg8_write(sc, FLASH_REG_ALE, 1);
490: flash_reg8_write(sc, FLASH_REG_ROW, pageno);
491: flash_reg8_write(sc, FLASH_REG_ROW, pageno >> 8);
492: flash_reg8_write(sc, FLASH_REG_ALE, 0);
493: break;
494: }
495:
496: switch (sc->sc_flashdev->id) {
497: case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
498: flash_reg8_write(sc, FLASH_REG_CLE, 1);
499: flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_READ);
500: flash_reg8_write(sc, FLASH_REG_CLE, 0);
501: break;
502: }
503:
504: if ((error = flash_wait_ready(sc)) != 0)
505: return error;
506:
507: for (i = 0; i < sc->sc_flashdev->oobsize; i++)
508: p[i] = flash_reg8_read(sc, FLASH_REG_DATA);
509:
510: return 0;
511: }
512:
513: int
514: flash_chip_write_block(struct flash_softc *sc, long blkno, caddr_t data,
515: caddr_t oob)
516: {
517: long pageno;
518: long blkend;
519: caddr_t p;
520: int error;
521:
522: pageno = blkno * sc->sc_flashdev->blkpages;
523: blkend = pageno + sc->sc_flashdev->blkpages;
524:
525: p = data;
526: while (pageno < blkend) {
527: error = flash_chip_write_page(sc, pageno, p, oob);
528: if (error != 0)
529: return error;
530: p += sc->sc_flashdev->pagesize;
531: pageno++;
532: }
533:
534: /* Verify the newly written block. */
535: return flash_chip_verify_block(sc, blkno, data, oob);
536: }
537:
538: int
539: flash_chip_write_page(struct flash_softc *sc, long pageno, caddr_t data,
540: caddr_t oob)
541: {
542: int error;
543:
544: (void)flash_wait_ready(sc);
545:
546: /* Disable write-protection. */
547: flash_reg8_write(sc, FLASH_REG_WP, 0);
548:
549: switch (sc->sc_flashdev->id) {
550: case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
551: case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
552: flash_reg8_write(sc, FLASH_REG_CLE, 1);
553: flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_PTRLO);
554: flash_reg8_write(sc, FLASH_REG_CLE, 0);
555: break;
556: }
557:
558: switch (sc->sc_flashdev->id) {
559: case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
560: case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
561: flash_reg8_write(sc, FLASH_REG_CLE, 1);
562: flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_SEQIN);
563: flash_reg8_write(sc, FLASH_REG_CLE, 0);
564: break;
565: }
566:
567: switch (sc->sc_flashdev->id) {
568: case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
569: flash_reg8_write(sc, FLASH_REG_ALE, 1);
570: flash_reg8_write(sc, FLASH_REG_COL, 0x00);
571: flash_reg8_write(sc, FLASH_REG_ALE, 0);
572: break;
573: case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
574: flash_reg8_write(sc, FLASH_REG_ALE, 1);
575: flash_reg8_write(sc, FLASH_REG_COL, 0x00);
576: flash_reg8_write(sc, FLASH_REG_COL, 0x00);
577: flash_reg8_write(sc, FLASH_REG_ALE, 0);
578: break;
579: }
580:
581: switch (sc->sc_flashdev->id) {
582: case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
583: case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
584: flash_reg8_write(sc, FLASH_REG_ALE, 1);
585: flash_reg8_write(sc, FLASH_REG_ROW, pageno);
586: flash_reg8_write(sc, FLASH_REG_ROW, pageno >> 8);
587: flash_reg8_write(sc, FLASH_REG_ALE, 0);
588: break;
589: }
590:
591: /* Support hardware ECC calculation. */
592: if (sc->sc_tag->regx_write_page) {
593: error = sc->sc_tag->regx_write_page(sc->sc_cookie, data,
594: oob);
595: if (error != 0)
596: return error;
597: } else
598: flash_reg8_write_page(sc, data, oob);
599:
600: switch (sc->sc_flashdev->id) {
601: case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
602: case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
603: flash_reg8_write(sc, FLASH_REG_CLE, 1);
604: flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_WRITE);
605: flash_reg8_write(sc, FLASH_REG_CLE, 0);
606: break;
607: }
608:
609: /*
610: * Wait for the write operation to complete although this can
611: * take up to 700 us for the K9F1G08U0A flash type.
612: */
613: error = flash_wait_complete(sc);
614:
615: /* Re-enable write-protection. */
616: flash_reg8_write(sc, FLASH_REG_WP, 1);
617:
618: return error;
619: }
620:
621: int
622: flash_chip_verify_block(struct flash_softc *sc, long blkno, caddr_t data,
623: caddr_t oob)
624: {
625: long pageno;
626: long blkend;
627: int error;
628:
629: pageno = blkno * sc->sc_flashdev->blkpages;
630: blkend = pageno + sc->sc_flashdev->blkpages;
631:
632: while (pageno < blkend) {
633: error = flash_chip_verify_page(sc, pageno, data, oob);
634: if (error != 0) {
635: printf("block %d page %d verify failed\n",
636: blkno, pageno);
637: return error;
638: }
639: data += sc->sc_flashdev->pagesize;
640: pageno++;
641: }
642: return 0;
643: }
644:
645: int
646: flash_chip_verify_page(struct flash_softc *sc, long pageno, caddr_t data,
647: caddr_t oob)
648: {
649: static u_char rbuf[FLASH_MAXPAGESIZE];
650: static u_char roob[FLASH_MAXOOBSIZE];
651: int error;
652:
653: error = flash_chip_read_page(sc, pageno, rbuf,
654: oob == NULL ? NULL : roob);
655: if (error != 0)
656: return error;
657:
658: if (memcmp((const void *)&rbuf[0], (const void *)data,
659: sc->sc_flashdev->pagesize) != 0)
660: return EIO;
661:
662: if (oob != NULL && memcmp((const void *)&roob[0],
663: (const void *)oob, sc->sc_flashdev->oobsize) != 0)
664: return EIO;
665:
666: return 0;
667: }
668:
669: /*
670: * Block device functions
671: */
672:
673: int
674: flashopen(dev_t dev, int oflags, int devtype, struct proc *p)
675: {
676: struct flash_softc *sc;
677: int error;
678: int part;
679:
680: sc = flashlookup(flashunit(dev));
681: if (sc == NULL)
682: return ENXIO;
683:
684: if ((error = flashlock(sc)) != 0) {
685: device_unref(&sc->sc_dev);
686: return error;
687: }
688:
689: /*
690: * If no partition is open load the partition info if it is
691: * not already valid. If partitions are already open, allow
692: * opens only for the same kind of device.
693: */
694: if (sc->sc_dk.dk_openmask == 0) {
695: if ((sc->sc_flags & FDK_LOADED) == 0 ||
696: ((sc->sc_flags & FDK_SAFE) == 0) !=
697: (flashsafe(dev) == 0)) {
698: sc->sc_flags &= ~FDK_SAFE;
699: sc->sc_flags |= FDK_LOADED;
700: if (flashsafe(dev))
701: sc->sc_flags |= FDK_SAFE;
702: flashgetdisklabel(dev, sc, sc->sc_dk.dk_label, 0);
703: }
704: } else if (((sc->sc_flags & FDK_SAFE) == 0) !=
705: (flashsafe(dev) == 0)) {
706: flashunlock(sc);
707: device_unref(&sc->sc_dev);
708: return EBUSY;
709: }
710:
711: /* Check that the partition exists. */
712: part = flashpart(dev);
713: if (part != RAW_PART &&
714: (part >= sc->sc_dk.dk_label->d_npartitions ||
715: sc->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
716: flashunlock(sc);
717: device_unref(&sc->sc_dev);
718: return ENXIO;
719: }
720:
721: /* Prevent our unit from being deconfigured while open. */
722: switch (devtype) {
723: case S_IFCHR:
724: sc->sc_dk.dk_copenmask |= (1 << part);
725: break;
726: case S_IFBLK:
727: sc->sc_dk.dk_bopenmask |= (1 << part);
728: break;
729: }
730: sc->sc_dk.dk_openmask =
731: sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
732:
733: flashunlock(sc);
734: device_unref(&sc->sc_dev);
735: return 0;
736: }
737:
738: int
739: flashclose(dev_t dev, int fflag, int devtype, struct proc *p)
740: {
741: struct flash_softc *sc;
742: int error;
743: int part;
744:
745: sc = flashlookup(flashunit(dev));
746: if (sc == NULL)
747: return ENXIO;
748:
749: if ((error = flashlock(sc)) != 0) {
750: device_unref(&sc->sc_dev);
751: return error;
752: }
753:
754: /* Close one open partition. */
755: part = flashpart(dev);
756: switch (devtype) {
757: case S_IFCHR:
758: sc->sc_dk.dk_copenmask &= ~(1 << part);
759: break;
760: case S_IFBLK:
761: sc->sc_dk.dk_bopenmask &= ~(1 << part);
762: break;
763: }
764: sc->sc_dk.dk_openmask =
765: sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
766:
767: if (sc->sc_dk.dk_openmask == 0) {
768: /* XXX wait for I/O to complete? */
769: }
770:
771: flashunlock(sc);
772: device_unref(&sc->sc_dev);
773: return 0;
774: }
775:
776: /*
777: * Queue the transfer of one or more flash pages.
778: */
779: void
780: flashstrategy(struct buf *bp)
781: {
782: struct flash_softc *sc;
783: int s;
784:
785: sc = flashlookup(flashunit(bp->b_dev));
786: if (sc == NULL) {
787: bp->b_error = ENXIO;
788: goto bad;
789: }
790:
791: /* Transfer only a multiple of the flash page size. */
792: if ((bp->b_bcount % sc->sc_flashdev->pagesize) != 0) {
793: bp->b_error = EINVAL;
794: goto bad;
795: }
796:
797: /* If the device has been invalidated, error out. */
798: if ((sc->sc_flags & FDK_LOADED) == 0) {
799: bp->b_error = EIO;
800: goto bad;
801: }
802:
803: /* Translate logical block numbers to physical. */
804: if (flashsafe(bp->b_dev) && flashsafestrategy(sc, bp) <= 0)
805: goto done;
806:
807: /* Return immediately if it is a null transfer. */
808: if (bp->b_bcount == 0)
809: goto done;
810:
811: /* Do bounds checking on partitions. */
812: if (flashpart(bp->b_dev) != RAW_PART &&
813: bounds_check_with_label(bp, sc->sc_dk.dk_label, 0) <= 0)
814: goto done;
815:
816: /* Queue the transfer. */
817: s = splbio();
818: disksort(&sc->sc_q, bp);
819: flashstart(sc);
820: splx(s);
821: device_unref(&sc->sc_dev);
822: return;
823:
824: bad:
825: bp->b_flags |= B_ERROR;
826: done:
827: if ((bp->b_flags & B_ERROR) != 0)
828: bp->b_resid = bp->b_bcount;
829: s = splbio();
830: biodone(bp);
831: splx(s);
832: if (sc != NULL)
833: device_unref(&sc->sc_dev);
834: }
835:
836: int
837: flashioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
838: {
839: struct flash_softc *sc;
840: int error = 0;
841:
842: sc = flashlookup(flashunit(dev));
843: if (sc == NULL)
844: return ENXIO;
845:
846: if ((sc->sc_flags & FDK_LOADED) == 0) {
847: device_unref(&sc->sc_dev);
848: return EIO;
849: }
850:
851: switch (cmd) {
852: case DIOCGDINFO:
853: *(struct disklabel *)data = *sc->sc_dk.dk_label;
854: break;
855: default:
856: error = ENOTTY;
857: break;
858: }
859:
860: device_unref(&sc->sc_dev);
861: return error;
862: }
863:
864: int
865: flashdump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size)
866: {
867: printf("flashdump\n");
868: return ENODEV;
869: }
870:
871: daddr64_t
872: flashsize(dev_t dev)
873: {
874: printf("flashsize\n");
875: return ENODEV;
876: }
877:
878: void
879: flashstart(struct flash_softc *sc)
880: {
881: struct buf *dp, *bp;
882:
883: while (1) {
884: /* Remove the next buffer from the queue or stop. */
885: dp = &sc->sc_q;
886: bp = dp->b_actf;
887: if (bp == NULL)
888: return;
889: dp->b_actf = bp->b_actf;
890:
891: /* Transfer this buffer now. */
892: _flashstart(sc, bp);
893: }
894: }
895:
896: void
897: _flashstart(struct flash_softc *sc, struct buf *bp)
898: {
899: int part;
900: daddr64_t offset;
901: long pgno;
902:
903: part = flashpart(bp->b_dev);
904: offset = DL_GETPOFFSET(&sc->sc_dk.dk_label->d_partitions[part]) +
905: bp->b_blkno;
906: pgno = offset / (sc->sc_flashdev->pagesize / DEV_BSIZE);
907:
908: /*
909: * If the requested page is exactly at the end of flash and it
910: * is an "unsafe" device, return EOF, else error out.
911: */
912: if (!flashsafe(bp->b_dev) && pgno == sc->sc_flashdev->capacity) {
913: bp->b_resid = bp->b_bcount;
914: biodone(bp);
915: return;
916: } else if (pgno >= sc->sc_flashdev->capacity) {
917: bp->b_error = EINVAL;
918: bp->b_flags |= B_ERROR;
919: biodone(bp);
920: return;
921: }
922:
923: sc->sc_bp = bp;
924:
925: /* Instrumentation. */
926: disk_busy(&sc->sc_dk);
927:
928: /* XXX this should be done asynchronously. */
929: flash_chip_enable(sc);
930: if ((bp->b_flags & B_READ) != 0)
931: bp->b_error = flash_chip_read_page(sc, pgno, bp->b_data,
932: NULL);
933: else
934: bp->b_error = flash_chip_write_page(sc, pgno, bp->b_data,
935: NULL);
936: if (bp->b_error == 0)
937: bp->b_resid = bp->b_bcount - sc->sc_flashdev->pagesize;
938: flash_chip_disable(sc);
939: flashdone(sc);
940: }
941:
942: void
943: flashdone(void *v)
944: {
945: struct flash_softc *sc = v;
946: struct buf *bp = sc->sc_bp;
947:
948: /* Instrumentation. */
949: disk_unbusy(&sc->sc_dk, bp->b_bcount - bp->b_resid,
950: (bp->b_flags & B_READ) != 0);
951:
952: if (bp->b_error != 0)
953: bp->b_flags |= B_ERROR;
954:
955: biodone(bp);
956: flashstart(sc);
957: }
958:
959: void
960: flashgetdefaultlabel(dev_t dev, struct flash_softc *sc,
961: struct disklabel *lp)
962: {
963: size_t len;
964:
965: bzero(lp, sizeof(struct disklabel));
966:
967: lp->d_type = 0;
968: lp->d_subtype = 0;
969: strncpy(lp->d_typename, "NAND flash", sizeof(lp->d_typename));
970:
971: /* Use the product name up to the first space. */
972: strncpy(lp->d_packname, sc->sc_flashdev->longname,
973: sizeof(lp->d_packname));
974: for (len = 0; len < sizeof(lp->d_packname); len++)
975: if (lp->d_packname[len] == ' ') {
976: lp->d_packname[len] = '\0';
977: break;
978: }
979:
980: /* Fake the disk geometry. */
981: lp->d_ncylinders = 1;
982: lp->d_ntracks = 16;
983: lp->d_secsize = sc->sc_flashdev->pagesize;
984: lp->d_nsectors = sc->sc_flashdev->capacity / lp->d_ntracks
985: / lp->d_ncylinders;
986: lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
987: DL_SETDSIZE(lp, (daddr64_t)lp->d_ncylinders * lp->d_secpercyl);
988:
989: /* Fake hardware characteristics. */
990: lp->d_rpm = 3600;
991: lp->d_interleave = 1;
992: lp->d_version = 1;
993:
994: /* XXX these values assume ffs. */
995: lp->d_bbsize = BBSIZE;
996: lp->d_sbsize = SBSIZE;
997:
998: /* Wrap it up. */
999: lp->d_magic = DISKMAGIC;
1000: lp->d_magic2 = DISKMAGIC;
1001: lp->d_checksum = dkcksum(lp);
1002: }
1003:
1004: void
1005: flashgetdisklabel(dev_t dev, struct flash_softc *sc,
1006: struct disklabel *lp, int spoofonly)
1007: {
1008: char *errstring;
1009: dev_t labeldev;
1010:
1011: flashgetdefaultlabel(dev, sc, lp);
1012:
1013: if (sc->sc_tag->default_disklabel != NULL)
1014: sc->sc_tag->default_disklabel(sc->sc_cookie, dev, lp);
1015:
1016: /* Call the generic disklabel extraction routine. */
1017: labeldev = flashlabeldev(dev);
1018: errstring = readdisklabel(labeldev, flashstrategy, lp, spoofonly);
1019: if (errstring != NULL) {
1020: /*printf("%s: %s\n", sc->sc_dev.dv_xname, errstring);*/
1021: }
1022: }
1023:
1024: /*
1025: * Character device functions
1026: */
1027:
1028: void
1029: flashminphys(struct buf *bp)
1030: {
1031: struct flash_softc *sc;
1032:
1033: sc = flashlookup(flashunit(bp->b_dev));
1034:
1035: if (bp->b_bcount > sc->sc_flashdev->pagesize)
1036: bp->b_bcount = sc->sc_flashdev->pagesize;
1037: }
1038:
1039: int
1040: flashread(dev_t dev, struct uio *uio, int ioflag)
1041: {
1042: return physio(flashstrategy, NULL, dev, B_READ, flashminphys, uio);
1043: }
1044:
1045: int
1046: flashwrite(dev_t dev, struct uio *uio, int ioflag)
1047: {
1048: return physio(flashstrategy, NULL, dev, B_WRITE, flashminphys, uio);
1049: }
1050:
1051: /*
1052: * Physical access strategy "fixup" routines for transparent bad
1053: * blocks management, wear-leveling, etc.
1054: */
1055:
1056: /*
1057: * Call the machine-specific routine if there is any or use just a
1058: * default strategy for bad blocks management.
1059: */
1060: int
1061: flashsafestrategy(struct flash_softc *sc, struct buf *bp)
1062: {
1063: if (sc->sc_tag->safe_strategy) {
1064: return sc->sc_tag->safe_strategy(sc->sc_cookie, bp);
1065: }
1066:
1067: /* XXX no default bad blocks management strategy yet */
1068: return 1;
1069: }
1070:
1071: void dumppage(u_char *);
1072: void dumppage(u_char *buf)
1073: {
1074: int i;
1075: for (i = 0; i < 512; i++) {
1076: if ((i % 16) == 0)
1077: printf("%04x: ", i);
1078: if ((i % 16) == 8)
1079: printf(" ");
1080: printf(" %02x", buf[i]);
1081: if ((i % 16) == 15)
1082: printf("\n");
1083: }
1084: if ((i % 16) != 0)
1085: printf("\n");
1086: }
CVSweb