1 /*-
2 * Copyright (C) 2009-2012 Semihalf
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/conf.h>
33 #include <sys/bus.h>
34 #include <sys/malloc.h>
35 #include <sys/uio.h>
36 #include <sys/bio.h>
37
38 #include <dev/nand/nand.h>
39 #include <dev/nand/nandbus.h>
40 #include <dev/nand/nand_dev.h>
41 #include "nand_if.h"
42 #include "nandbus_if.h"
43
44 static int nand_page_stat(struct nand_chip *, struct page_stat_io *);
45 static int nand_block_stat(struct nand_chip *, struct block_stat_io *);
46
47 static d_ioctl_t nand_ioctl;
48 static d_open_t nand_open;
49 static d_strategy_t nand_strategy;
50
51 static struct cdevsw nand_cdevsw = {
52 .d_version = D_VERSION,
53 .d_name = "nand",
54 .d_open = nand_open,
55 .d_read = physread,
56 .d_write = physwrite,
57 .d_ioctl = nand_ioctl,
58 .d_strategy = nand_strategy,
59 };
60
61 static int
offset_to_page(struct chip_geom * cg,uint32_t offset)62 offset_to_page(struct chip_geom *cg, uint32_t offset)
63 {
64
65 return (offset / cg->page_size);
66 }
67
68 static int
offset_to_page_off(struct chip_geom * cg,uint32_t offset)69 offset_to_page_off(struct chip_geom *cg, uint32_t offset)
70 {
71
72 return (offset % cg->page_size);
73 }
74
75 int
nand_make_dev(struct nand_chip * chip)76 nand_make_dev(struct nand_chip *chip)
77 {
78 struct nandbus_ivar *ivar;
79 device_t parent, nandbus;
80 int parent_unit, unit;
81 char *name;
82
83 ivar = device_get_ivars(chip->dev);
84 nandbus = device_get_parent(chip->dev);
85
86 if (ivar->chip_cdev_name) {
87 name = ivar->chip_cdev_name;
88
89 /*
90 * If we got distinct name for chip device we can enumarete it
91 * based on contoller number.
92 */
93 parent = device_get_parent(nandbus);
94 } else {
95 name = "nand";
96 parent = nandbus;
97 }
98
99 parent_unit = device_get_unit(parent);
100 unit = parent_unit * 4 + chip->num;
101 chip->cdev = make_dev(&nand_cdevsw, unit, UID_ROOT, GID_WHEEL,
102 0640, "%s%d.%d", name, parent_unit, chip->num);
103
104 if (chip->cdev == NULL)
105 return (ENXIO);
106
107 if (bootverbose)
108 device_printf(chip->dev, "Created cdev %s%d.%d for chip "
109 "[0x%0x, 0x%0x]\n", name, parent_unit, chip->num,
110 ivar->man_id, ivar->dev_id);
111
112 chip->cdev->si_drv1 = chip;
113
114 return (0);
115 }
116
117 void
nand_destroy_dev(struct nand_chip * chip)118 nand_destroy_dev(struct nand_chip *chip)
119 {
120
121 if (chip->cdev)
122 destroy_dev(chip->cdev);
123 }
124
125 static int
nand_open(struct cdev * dev,int oflags,int devtype,struct thread * td)126 nand_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
127 {
128
129 return (0);
130 }
131
132 static int
nand_read(struct nand_chip * chip,uint32_t offset,void * buf,uint32_t len)133 nand_read(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len)
134 {
135 struct chip_geom *cg;
136 device_t nandbus;
137 int start_page, count, off, err = 0;
138 uint8_t *ptr, *tmp;
139
140 nand_debug(NDBG_CDEV, "Read from chip%d [%p] at %d\n", chip->num,
141 chip, offset);
142
143 nandbus = device_get_parent(chip->dev);
144 NANDBUS_LOCK(nandbus);
145 NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num);
146
147 cg = &chip->chip_geom;
148 start_page = offset_to_page(cg, offset);
149 off = offset_to_page_off(cg, offset);
150 count = (len > cg->page_size - off) ? cg->page_size - off : len;
151
152 ptr = (uint8_t *)buf;
153 while (len > 0) {
154 if (len < cg->page_size) {
155 tmp = malloc(cg->page_size, M_NAND, M_WAITOK);
156 if (!tmp) {
157 err = ENOMEM;
158 break;
159 }
160 err = NAND_READ_PAGE(chip->dev, start_page,
161 tmp, cg->page_size, 0);
162 if (err) {
163 free(tmp, M_NAND);
164 break;
165 }
166 bcopy(tmp + off, ptr, count);
167 free(tmp, M_NAND);
168 } else {
169 err = NAND_READ_PAGE(chip->dev, start_page,
170 ptr, cg->page_size, 0);
171 if (err)
172 break;
173 }
174
175 len -= count;
176 start_page++;
177 ptr += count;
178 count = (len > cg->page_size) ? cg->page_size : len;
179 off = 0;
180 }
181
182 NANDBUS_UNLOCK(nandbus);
183 return (err);
184 }
185
186 static int
nand_write(struct nand_chip * chip,uint32_t offset,void * buf,uint32_t len)187 nand_write(struct nand_chip *chip, uint32_t offset, void* buf, uint32_t len)
188 {
189 struct chip_geom *cg;
190 device_t nandbus;
191 int off, start_page, err = 0;
192 uint8_t *ptr;
193
194 nand_debug(NDBG_CDEV, "Write to chip %d [%p] at %d\n", chip->num,
195 chip, offset);
196
197 nandbus = device_get_parent(chip->dev);
198 NANDBUS_LOCK(nandbus);
199 NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num);
200
201 cg = &chip->chip_geom;
202 start_page = offset_to_page(cg, offset);
203 off = offset_to_page_off(cg, offset);
204
205 if (off != 0 || (len % cg->page_size) != 0) {
206 printf("Not aligned write start [0x%08x] size [0x%08x]\n",
207 off, len);
208 NANDBUS_UNLOCK(nandbus);
209 return (EINVAL);
210 }
211
212 ptr = (uint8_t *)buf;
213 while (len > 0) {
214 err = NAND_PROGRAM_PAGE(chip->dev, start_page, ptr,
215 cg->page_size, 0);
216 if (err)
217 break;
218
219 len -= cg->page_size;
220 start_page++;
221 ptr += cg->page_size;
222 }
223
224 NANDBUS_UNLOCK(nandbus);
225 return (err);
226 }
227
228 static void
nand_strategy(struct bio * bp)229 nand_strategy(struct bio *bp)
230 {
231 struct nand_chip *chip;
232 struct cdev *dev;
233 int err = 0;
234
235 dev = bp->bio_dev;
236 chip = dev->si_drv1;
237
238 nand_debug(NDBG_CDEV, "Strategy %s on chip %d [%p]\n",
239 bp->bio_cmd == BIO_READ ? "READ" : "WRITE",
240 chip->num, chip);
241
242 if (bp->bio_cmd == BIO_READ) {
243 err = nand_read(chip,
244 bp->bio_offset & 0xffffffff,
245 bp->bio_data, bp->bio_bcount);
246 } else {
247 err = nand_write(chip,
248 bp->bio_offset & 0xffffffff,
249 bp->bio_data, bp->bio_bcount);
250 }
251
252 if (err == 0)
253 bp->bio_resid = 0;
254 else {
255 bp->bio_error = EIO;
256 bp->bio_flags |= BIO_ERROR;
257 bp->bio_resid = bp->bio_bcount;
258 }
259
260 biodone(bp);
261 }
262
263 static int
nand_oob_access(struct nand_chip * chip,uint32_t page,uint32_t offset,uint32_t len,uint8_t * data,uint8_t write)264 nand_oob_access(struct nand_chip *chip, uint32_t page, uint32_t offset,
265 uint32_t len, uint8_t *data, uint8_t write)
266 {
267 struct chip_geom *cg;
268 uint8_t *buf = NULL;
269 int ret = 0;
270
271 cg = &chip->chip_geom;
272
273 buf = malloc(cg->oob_size, M_NAND, M_WAITOK);
274 if (!buf)
275 return (ENOMEM);
276
277 memset(buf, 0xff, cg->oob_size);
278
279 if (!write) {
280 ret = nand_read_oob(chip, page, buf, cg->oob_size);
281 copyout(buf, data, len);
282 } else {
283 copyin(data, buf, len);
284 ret = nand_prog_oob(chip, page, buf, cg->oob_size);
285 }
286
287 free(buf, M_NAND);
288
289 return (ret);
290 }
291
292 static int
nand_ioctl(struct cdev * dev,u_long cmd,caddr_t data,int fflag,struct thread * td)293 nand_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
294 struct thread *td)
295 {
296 struct nand_chip *chip;
297 struct chip_geom *cg;
298 struct nand_oob_rw *oob_rw = NULL;
299 struct nand_raw_rw *raw_rw = NULL;
300 device_t nandbus;
301 size_t bufsize = 0, len = 0;
302 size_t raw_size;
303 off_t off;
304 uint8_t *buf = NULL;
305 int ret = 0;
306 uint8_t status;
307
308 chip = (struct nand_chip *)dev->si_drv1;
309 cg = &chip->chip_geom;
310 nandbus = device_get_parent(chip->dev);
311
312 if ((cmd == NAND_IO_RAW_READ) || (cmd == NAND_IO_RAW_PROG)) {
313 raw_rw = (struct nand_raw_rw *)data;
314 raw_size = cg->pgs_per_blk * (cg->page_size + cg->oob_size);
315
316 /* Check if len is not bigger than chip size */
317 if (raw_rw->len > raw_size)
318 return (EFBIG);
319
320 /*
321 * Do not ask for too much memory, in case of large transfers
322 * read/write in 16-pages chunks
323 */
324 bufsize = 16 * (cg->page_size + cg->oob_size);
325 if (raw_rw->len < bufsize)
326 bufsize = raw_rw->len;
327
328 buf = malloc(bufsize, M_NAND, M_WAITOK);
329 len = raw_rw->len;
330 off = 0;
331 }
332 switch(cmd) {
333 case NAND_IO_ERASE:
334 ret = nand_erase_blocks(chip, ((off_t *)data)[0],
335 ((off_t *)data)[1]);
336 break;
337
338 case NAND_IO_OOB_READ:
339 oob_rw = (struct nand_oob_rw *)data;
340 ret = nand_oob_access(chip, oob_rw->page, 0,
341 oob_rw->len, oob_rw->data, 0);
342 break;
343
344 case NAND_IO_OOB_PROG:
345 oob_rw = (struct nand_oob_rw *)data;
346 ret = nand_oob_access(chip, oob_rw->page, 0,
347 oob_rw->len, oob_rw->data, 1);
348 break;
349
350 case NAND_IO_GET_STATUS:
351 NANDBUS_LOCK(nandbus);
352 ret = NANDBUS_GET_STATUS(nandbus, &status);
353 if (ret == 0)
354 *(uint8_t *)data = status;
355 NANDBUS_UNLOCK(nandbus);
356 break;
357
358 case NAND_IO_RAW_PROG:
359 while (len > 0) {
360 if (len < bufsize)
361 bufsize = len;
362 ret = copyin(raw_rw->data + off, buf, bufsize);
363 if (ret)
364 break;
365 ret = nand_prog_pages_raw(chip, raw_rw->off + off, buf,
366 bufsize);
367 if (ret)
368 break;
369 len -= bufsize;
370 off += bufsize;
371 }
372 break;
373
374 case NAND_IO_RAW_READ:
375 while (len > 0) {
376 if (len < bufsize)
377 bufsize = len;
378
379 ret = nand_read_pages_raw(chip, raw_rw->off + off, buf,
380 bufsize);
381 if (ret)
382 break;
383
384 ret = copyout(buf, raw_rw->data + off, bufsize);
385 if (ret)
386 break;
387 len -= bufsize;
388 off += bufsize;
389 }
390 break;
391
392 case NAND_IO_PAGE_STAT:
393 ret = nand_page_stat(chip, (struct page_stat_io *)data);
394 break;
395
396 case NAND_IO_BLOCK_STAT:
397 ret = nand_block_stat(chip, (struct block_stat_io *)data);
398 break;
399
400 case NAND_IO_GET_CHIP_PARAM:
401 nand_get_chip_param(chip, (struct chip_param_io *)data);
402 break;
403
404 default:
405 printf("Unknown nand_ioctl request \n");
406 ret = EIO;
407 }
408
409 if (buf)
410 free(buf, M_NAND);
411
412 return (ret);
413 }
414
415 static int
nand_page_stat(struct nand_chip * chip,struct page_stat_io * page_stat)416 nand_page_stat(struct nand_chip *chip, struct page_stat_io *page_stat)
417 {
418 struct chip_geom *cg;
419 struct page_stat *stat;
420 int num_pages;
421
422 cg = &chip->chip_geom;
423 num_pages = cg->pgs_per_blk * cg->blks_per_lun * cg->luns;
424 if (page_stat->page_num >= num_pages)
425 return (EINVAL);
426
427 stat = &chip->pg_stat[page_stat->page_num];
428 page_stat->page_read = stat->page_read;
429 page_stat->page_written = stat->page_written;
430 page_stat->page_raw_read = stat->page_raw_read;
431 page_stat->page_raw_written = stat->page_raw_written;
432 page_stat->ecc_succeded = stat->ecc_stat.ecc_succeded;
433 page_stat->ecc_corrected = stat->ecc_stat.ecc_corrected;
434 page_stat->ecc_failed = stat->ecc_stat.ecc_failed;
435
436 return (0);
437 }
438
439 static int
nand_block_stat(struct nand_chip * chip,struct block_stat_io * block_stat)440 nand_block_stat(struct nand_chip *chip, struct block_stat_io *block_stat)
441 {
442 struct chip_geom *cg;
443 uint32_t block_num = block_stat->block_num;
444
445 cg = &chip->chip_geom;
446 if (block_num >= cg->blks_per_lun * cg->luns)
447 return (EINVAL);
448
449 block_stat->block_erased = chip->blk_stat[block_num].block_erased;
450
451 return (0);
452 }
453