]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/nand/nand_geom.c
powerpc: Transition to Secure-PLT, like most other OSs (Toolchain part)
[FreeBSD/FreeBSD.git] / sys / dev / nand / nand_geom.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (C) 2009-2012 Semihalf
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/conf.h>
35 #include <sys/bus.h>
36 #include <sys/malloc.h>
37 #include <sys/uio.h>
38 #include <sys/bio.h>
39 #include <geom/geom.h>
40 #include <geom/geom_disk.h>
41
42 #include <dev/nand/nand.h>
43 #include <dev/nand/nandbus.h>
44 #include <dev/nand/nand_dev.h>
45 #include "nand_if.h"
46 #include "nandbus_if.h"
47
48 #define BIO_NAND_STD    ((void *)1)
49 #define BIO_NAND_RAW    ((void *)2)
50
51 static disk_ioctl_t nand_ioctl;
52 static disk_getattr_t nand_getattr;
53 static disk_strategy_t nand_strategy;
54 static disk_strategy_t nand_strategy_raw;
55
56 static int
57 nand_read(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len)
58 {
59
60         nand_debug(NDBG_GEOM, "Read from chip %d [%p] at %d", chip->num, chip,
61             offset);
62
63         return (nand_read_pages(chip, offset, buf, len));
64 }
65
66 static int
67 nand_write(struct nand_chip *chip, uint32_t offset, void* buf, uint32_t len)
68 {
69
70         nand_debug(NDBG_GEOM, "Write to chip %d [%p] at %d", chip->num, chip,
71             offset);
72
73         return (nand_prog_pages(chip, offset, buf, len));
74 }
75
76 static int
77 nand_read_raw(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len)
78 {
79         nand_debug(NDBG_GEOM, "Raw read from chip %d [%p] at %d", chip->num,
80             chip, offset);
81
82         return (nand_read_pages_raw(chip, offset, buf, len));
83 }
84
85 static int
86 nand_write_raw(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len)
87 {
88
89         nand_debug(NDBG_GEOM, "Raw write to chip %d [%p] at %d", chip->num,
90             chip, offset);
91
92         return (nand_prog_pages_raw(chip, offset, buf, len));
93 }
94
95 static void
96 nand_strategy(struct bio *bp)
97 {
98         struct nand_chip *chip;
99
100         chip = (struct nand_chip *)bp->bio_disk->d_drv1;
101
102         bp->bio_driver1 = BIO_NAND_STD;
103
104         nand_debug(NDBG_GEOM, "Strategy %s on chip %d [%p]",
105             bp->bio_cmd == BIO_READ ? "READ" :
106             (bp->bio_cmd == BIO_WRITE ? "WRITE" :
107             (bp->bio_cmd == BIO_DELETE ? "DELETE" : "UNKNOWN")),
108             chip->num, chip);
109
110         mtx_lock(&chip->qlock);
111         bioq_insert_tail(&chip->bioq, bp);
112         mtx_unlock(&chip->qlock);
113         taskqueue_enqueue(chip->tq, &chip->iotask);
114 }
115
116 static void
117 nand_strategy_raw(struct bio *bp)
118 {
119         struct nand_chip *chip;
120
121         chip = (struct nand_chip *)bp->bio_disk->d_drv1;
122
123         /* Inform taskqueue that it's a raw access */
124         bp->bio_driver1 = BIO_NAND_RAW;
125
126         nand_debug(NDBG_GEOM, "Strategy %s on chip %d [%p]",
127             bp->bio_cmd == BIO_READ ? "READ" :
128             (bp->bio_cmd == BIO_WRITE ? "WRITE" :
129             (bp->bio_cmd == BIO_DELETE ? "DELETE" : "UNKNOWN")),
130             chip->num, chip);
131
132         mtx_lock(&chip->qlock);
133         bioq_insert_tail(&chip->bioq, bp);
134         mtx_unlock(&chip->qlock);
135         taskqueue_enqueue(chip->tq, &chip->iotask);
136 }
137
138 static int
139 nand_oob_access(struct nand_chip *chip, uint32_t page, uint32_t offset,
140     uint32_t len, uint8_t *data, uint8_t write)
141 {
142         struct chip_geom *cg;
143         int ret = 0;
144
145         cg = &chip->chip_geom;
146
147         if (!write)
148                 ret = nand_read_oob(chip, page, data, cg->oob_size);
149         else
150                 ret = nand_prog_oob(chip, page, data, cg->oob_size);
151
152         return (ret);
153 }
154
155 static int
156 nand_getattr(struct bio *bp)
157 {
158         struct nand_chip *chip;
159         struct chip_geom *cg;
160         device_t dev;
161         int val;
162
163         if (bp->bio_disk == NULL || bp->bio_disk->d_drv1 == NULL)
164                 return (ENXIO);
165
166         chip = (struct nand_chip *)bp->bio_disk->d_drv1;
167         cg = &(chip->chip_geom);
168
169         dev = device_get_parent(chip->dev);
170         dev = device_get_parent(dev);
171
172         if (strcmp(bp->bio_attribute, "NAND::device") == 0) {
173                 if (bp->bio_length != sizeof(dev))
174                         return (EFAULT);
175                 bcopy(&dev, bp->bio_data, sizeof(dev));
176         } else {
177                 if (strcmp(bp->bio_attribute, "NAND::oobsize") == 0)
178                         val = cg->oob_size;
179                 else if (strcmp(bp->bio_attribute, "NAND::pagesize") == 0)
180                         val = cg->page_size;
181                 else if (strcmp(bp->bio_attribute, "NAND::blocksize") == 0)
182                         val = cg->block_size;
183                 else
184                         return (-1);
185                 if (bp->bio_length != sizeof(val))
186                         return (EFAULT);
187                 bcopy(&val, bp->bio_data, sizeof(val));
188         }
189         bp->bio_completed = bp->bio_length;
190         return (0);
191 }
192
193 static int
194 nand_ioctl(struct disk *ndisk, u_long cmd, void *data, int fflag,
195     struct thread *td)
196 {
197         struct nand_chip *chip;
198         struct chip_geom  *cg;
199         struct nand_oob_rw *oob_rw = NULL;
200         struct nand_raw_rw *raw_rw = NULL;
201         device_t nandbus;
202         size_t bufsize = 0, len = 0;
203         size_t raw_size;
204         off_t off;
205         uint8_t *buf = NULL;
206         int ret = 0;
207         uint8_t status;
208
209         chip = (struct nand_chip *)ndisk->d_drv1;
210         cg = &chip->chip_geom;
211         nandbus = device_get_parent(chip->dev);
212
213         if ((cmd == NAND_IO_RAW_READ) || (cmd == NAND_IO_RAW_PROG)) {
214                 raw_rw = (struct nand_raw_rw *)data;
215                 raw_size =  cg->pgs_per_blk * (cg->page_size + cg->oob_size);
216
217                 /* Check if len is not bigger than chip size */
218                 if (raw_rw->len > raw_size)
219                         return (EFBIG);
220
221                 /*
222                  * Do not ask for too much memory, in case of large transfers
223                  * read/write in 16-pages chunks
224                  */
225                 bufsize = 16 * (cg->page_size + cg->oob_size);
226                 if (raw_rw->len < bufsize)
227                         bufsize = raw_rw->len;
228
229                 buf = malloc(bufsize, M_NAND, M_WAITOK);
230                 len = raw_rw->len;
231                 off = 0;
232         }
233
234         switch (cmd) {
235         case NAND_IO_ERASE:
236                 ret = nand_erase_blocks(chip, ((off_t *)data)[0],
237                     ((off_t *)data)[1]);
238                 break;
239
240         case NAND_IO_OOB_READ:
241                 oob_rw = (struct nand_oob_rw *)data;
242                 ret = nand_oob_access(chip, oob_rw->page, 0,
243                     oob_rw->len, oob_rw->data, 0);
244                 break;
245
246         case NAND_IO_OOB_PROG:
247                 oob_rw = (struct nand_oob_rw *)data;
248                 ret = nand_oob_access(chip, oob_rw->page, 0,
249                     oob_rw->len, oob_rw->data, 1);
250                 break;
251
252         case NAND_IO_GET_STATUS:
253                 NANDBUS_LOCK(nandbus);
254                 ret = NANDBUS_GET_STATUS(nandbus, &status);
255                 if (ret == 0)
256                         *(uint8_t *)data = status;
257                 NANDBUS_UNLOCK(nandbus);
258                 break;
259
260         case NAND_IO_RAW_PROG:
261                 while (len > 0) {
262                         if (len < bufsize)
263                                 bufsize = len;
264
265                         ret = copyin(raw_rw->data + off, buf, bufsize);
266                         if (ret)
267                                 break;
268                         ret = nand_prog_pages_raw(chip, raw_rw->off + off, buf,
269                             bufsize);
270                         if (ret)
271                                 break;
272                         len -= bufsize;
273                         off += bufsize;
274                 }
275                 break;
276
277         case NAND_IO_RAW_READ:
278                 while (len > 0) {
279                         if (len < bufsize)
280                                 bufsize = len;
281
282                         ret = nand_read_pages_raw(chip, raw_rw->off + off, buf,
283                             bufsize);
284                         if (ret)
285                                 break;
286
287                         ret = copyout(buf, raw_rw->data + off, bufsize);
288                         if (ret)
289                                 break;
290                         len -= bufsize;
291                         off += bufsize;
292                 }
293                 break;
294
295         case NAND_IO_GET_CHIP_PARAM:
296                 nand_get_chip_param(chip, (struct chip_param_io *)data);
297                 break;
298
299         default:
300                 printf("Unknown nand_ioctl request \n");
301                 ret = EIO;
302         }
303
304         if (buf)
305                 free(buf, M_NAND);
306
307         return (ret);
308 }
309
310 static void
311 nand_io_proc(void *arg, int pending)
312 {
313         struct nand_chip *chip = arg;
314         struct bio *bp;
315         int err = 0;
316
317         for (;;) {
318                 mtx_lock(&chip->qlock);
319                 bp = bioq_takefirst(&chip->bioq);
320                 mtx_unlock(&chip->qlock);
321                 if (bp == NULL)
322                         break;
323
324                 if (bp->bio_driver1 == BIO_NAND_STD) {
325                         if (bp->bio_cmd == BIO_READ) {
326                                 err = nand_read(chip,
327                                     bp->bio_offset & 0xffffffff,
328                                     bp->bio_data, bp->bio_bcount);
329                         } else if (bp->bio_cmd == BIO_WRITE) {
330                                 err = nand_write(chip,
331                                     bp->bio_offset & 0xffffffff,
332                                     bp->bio_data, bp->bio_bcount);
333                         }
334                 } else if (bp->bio_driver1 == BIO_NAND_RAW) {
335                         if (bp->bio_cmd == BIO_READ) {
336                                 err = nand_read_raw(chip,
337                                     bp->bio_offset & 0xffffffff,
338                                     bp->bio_data, bp->bio_bcount);
339                         } else if (bp->bio_cmd == BIO_WRITE) {
340                                 err = nand_write_raw(chip,
341                                     bp->bio_offset & 0xffffffff,
342                                     bp->bio_data, bp->bio_bcount);
343                         }
344                 } else
345                         panic("Unknown access type in bio->bio_driver1\n");
346
347                 if (bp->bio_cmd == BIO_DELETE) {
348                         nand_debug(NDBG_GEOM, "Delete on chip%d offset %lld "
349                             "length %ld\n", chip->num, bp->bio_offset,
350                             bp->bio_bcount);
351                         err = nand_erase_blocks(chip,
352                             bp->bio_offset & 0xffffffff,
353                             bp->bio_bcount);
354                 }
355
356                 if (err == 0 || err == ECC_CORRECTABLE)
357                         bp->bio_resid = 0;
358                 else {
359                         nand_debug(NDBG_GEOM,"nand_[read|write|erase_blocks] "
360                             "error: %d\n", err);
361
362                         bp->bio_error = EIO;
363                         bp->bio_flags |= BIO_ERROR;
364                         bp->bio_resid = bp->bio_bcount;
365                 }
366                 biodone(bp);
367         }
368 }
369
370 int
371 create_geom_disk(struct nand_chip *chip)
372 {
373         struct disk *ndisk, *rdisk;
374
375         /* Create the disk device */
376         ndisk = disk_alloc();
377         ndisk->d_strategy = nand_strategy;
378         ndisk->d_ioctl = nand_ioctl;
379         ndisk->d_getattr = nand_getattr;
380         ndisk->d_name = "gnand";
381         ndisk->d_drv1 = chip;
382         ndisk->d_maxsize = chip->chip_geom.block_size;
383         ndisk->d_sectorsize = chip->chip_geom.page_size;
384         ndisk->d_mediasize = chip->chip_geom.chip_size;
385         ndisk->d_unit = chip->num +
386             10 * device_get_unit(device_get_parent(chip->dev));
387
388         /*
389          * When using BBT, make two last blocks of device unavailable
390          * to user (because those are used to store BBT table).
391          */
392         if (chip->bbt != NULL)
393                 ndisk->d_mediasize -= (2 * chip->chip_geom.block_size);
394
395         ndisk->d_flags = DISKFLAG_CANDELETE;
396
397         snprintf(ndisk->d_ident, sizeof(ndisk->d_ident),
398             "nand: Man:0x%02x Dev:0x%02x", chip->id.man_id, chip->id.dev_id);
399         ndisk->d_rotation_rate = DISK_RR_NON_ROTATING;
400
401         disk_create(ndisk, DISK_VERSION);
402
403         /* Create the RAW disk device */
404         rdisk = disk_alloc();
405         rdisk->d_strategy = nand_strategy_raw;
406         rdisk->d_ioctl = nand_ioctl;
407         rdisk->d_getattr = nand_getattr;
408         rdisk->d_name = "gnand.raw";
409         rdisk->d_drv1 = chip;
410         rdisk->d_maxsize = chip->chip_geom.block_size;
411         rdisk->d_sectorsize = chip->chip_geom.page_size;
412         rdisk->d_mediasize = chip->chip_geom.chip_size;
413         rdisk->d_unit = chip->num +
414             10 * device_get_unit(device_get_parent(chip->dev));
415
416         rdisk->d_flags = DISKFLAG_CANDELETE;
417
418         snprintf(rdisk->d_ident, sizeof(rdisk->d_ident),
419             "nand_raw: Man:0x%02x Dev:0x%02x", chip->id.man_id,
420             chip->id.dev_id);
421         rdisk->d_rotation_rate = DISK_RR_NON_ROTATING;
422
423         disk_create(rdisk, DISK_VERSION);
424
425         chip->ndisk = ndisk;
426         chip->rdisk = rdisk;
427
428         mtx_init(&chip->qlock, "NAND I/O lock", NULL, MTX_DEF);
429         bioq_init(&chip->bioq);
430
431         TASK_INIT(&chip->iotask, 0, nand_io_proc, chip);
432         chip->tq = taskqueue_create("nand_taskq", M_WAITOK,
433             taskqueue_thread_enqueue, &chip->tq);
434         taskqueue_start_threads(&chip->tq, 1, PI_DISK, "nand taskq");
435
436         if (bootverbose)
437                 device_printf(chip->dev, "Created gnand%d for chip [0x%0x, "
438                     "0x%0x]\n", ndisk->d_unit, chip->id.man_id,
439                     chip->id.dev_id);
440
441         return (0);
442 }
443
444 void
445 destroy_geom_disk(struct nand_chip *chip)
446 {
447         struct bio *bp;
448
449         taskqueue_free(chip->tq);
450         disk_destroy(chip->ndisk);
451         disk_destroy(chip->rdisk);
452
453         mtx_lock(&chip->qlock);
454         for (;;) {
455                 bp = bioq_takefirst(&chip->bioq);
456                 if (bp == NULL)
457                         break;
458                 bp->bio_error = EIO;
459                 bp->bio_flags |= BIO_ERROR;
460                 bp->bio_resid = bp->bio_bcount;
461
462                 biodone(bp);
463         }
464         mtx_unlock(&chip->qlock);
465
466         mtx_destroy(&chip->qlock);
467 }