xref: /freebsd-12.1/sys/dev/nand/nand_cdev.c (revision 3f07d125)
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 
40 #include <dev/nand/nand.h>
41 #include <dev/nand/nandbus.h>
42 #include <dev/nand/nand_dev.h>
43 #include "nand_if.h"
44 #include "nandbus_if.h"
45 
46 static int nand_page_stat(struct nand_chip *, struct page_stat_io *);
47 static int nand_block_stat(struct nand_chip *, struct block_stat_io *);
48 
49 static d_ioctl_t nand_ioctl;
50 static d_open_t nand_open;
51 static d_strategy_t nand_strategy;
52 
53 static struct cdevsw nand_cdevsw = {
54 	.d_version	= D_VERSION,
55 	.d_name		= "nand",
56 	.d_open		= nand_open,
57 	.d_read		= physread,
58 	.d_write	= physwrite,
59 	.d_ioctl	= nand_ioctl,
60 	.d_strategy =	nand_strategy,
61 };
62 
63 static int
offset_to_page(struct chip_geom * cg,uint32_t offset)64 offset_to_page(struct chip_geom *cg, uint32_t offset)
65 {
66 
67 	return (offset / cg->page_size);
68 }
69 
70 static int
offset_to_page_off(struct chip_geom * cg,uint32_t offset)71 offset_to_page_off(struct chip_geom *cg, uint32_t offset)
72 {
73 
74 	return (offset % cg->page_size);
75 }
76 
77 int
nand_make_dev(struct nand_chip * chip)78 nand_make_dev(struct nand_chip *chip)
79 {
80 	struct nandbus_ivar *ivar;
81 	device_t parent, nandbus;
82 	int parent_unit, unit;
83 	char *name;
84 
85 	ivar = device_get_ivars(chip->dev);
86 	nandbus = device_get_parent(chip->dev);
87 
88 	if (ivar->chip_cdev_name) {
89 		name = ivar->chip_cdev_name;
90 
91 		/*
92 		 * If we got distinct name for chip device we can enumarete it
93 		 * based on contoller number.
94 		 */
95 		parent = device_get_parent(nandbus);
96 	} else {
97 		name = "nand";
98 		parent = nandbus;
99 	}
100 
101 	parent_unit = device_get_unit(parent);
102 	unit = parent_unit * 4 + chip->num;
103 	chip->cdev = make_dev(&nand_cdevsw, unit, UID_ROOT, GID_WHEEL,
104 	    0640, "%s%d.%d", name, parent_unit, chip->num);
105 
106 	if (chip->cdev == NULL)
107 		return (ENXIO);
108 
109 	if (bootverbose)
110 		device_printf(chip->dev, "Created cdev %s%d.%d for chip "
111 		    "[0x%0x, 0x%0x]\n", name, parent_unit, chip->num,
112 		    ivar->man_id, ivar->dev_id);
113 
114 	chip->cdev->si_drv1 = chip;
115 
116 	return (0);
117 }
118 
119 void
nand_destroy_dev(struct nand_chip * chip)120 nand_destroy_dev(struct nand_chip *chip)
121 {
122 
123 	if (chip->cdev)
124 		destroy_dev(chip->cdev);
125 }
126 
127 static int
nand_open(struct cdev * dev,int oflags,int devtype,struct thread * td)128 nand_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
129 {
130 
131 	return (0);
132 }
133 
134 static int
nand_read(struct nand_chip * chip,uint32_t offset,void * buf,uint32_t len)135 nand_read(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len)
136 {
137 	struct chip_geom *cg;
138 	device_t nandbus;
139 	int start_page, count, off, err = 0;
140 	uint8_t *ptr, *tmp;
141 
142 	nand_debug(NDBG_CDEV, "Read from chip%d [%p] at %d\n", chip->num,
143 	    chip, offset);
144 
145 	nandbus = device_get_parent(chip->dev);
146 	NANDBUS_LOCK(nandbus);
147 	NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num);
148 
149 	cg = &chip->chip_geom;
150 	start_page = offset_to_page(cg, offset);
151 	off = offset_to_page_off(cg, offset);
152 	count = (len > cg->page_size - off) ? cg->page_size - off : len;
153 
154 	ptr = (uint8_t *)buf;
155 	while (len > 0) {
156 		if (len < cg->page_size) {
157 			tmp = malloc(cg->page_size, M_NAND, M_WAITOK);
158 			if (!tmp) {
159 				err = ENOMEM;
160 				break;
161 			}
162 			err = NAND_READ_PAGE(chip->dev, start_page,
163 			    tmp, cg->page_size, 0);
164 			if (err) {
165 				free(tmp, M_NAND);
166 				break;
167 			}
168 			bcopy(tmp + off, ptr, count);
169 			free(tmp, M_NAND);
170 		} else {
171 			err = NAND_READ_PAGE(chip->dev, start_page,
172 			    ptr, cg->page_size, 0);
173 			if (err)
174 				break;
175 		}
176 
177 		len -= count;
178 		start_page++;
179 		ptr += count;
180 		count = (len > cg->page_size) ? cg->page_size : len;
181 		off = 0;
182 	}
183 
184 	NANDBUS_UNLOCK(nandbus);
185 	return (err);
186 }
187 
188 static int
nand_write(struct nand_chip * chip,uint32_t offset,void * buf,uint32_t len)189 nand_write(struct nand_chip *chip, uint32_t offset, void* buf, uint32_t len)
190 {
191 	struct chip_geom *cg;
192 	device_t nandbus;
193 	int off, start_page, err = 0;
194 	uint8_t *ptr;
195 
196 	nand_debug(NDBG_CDEV, "Write to chip %d [%p] at %d\n", chip->num,
197 	    chip, offset);
198 
199 	nandbus = device_get_parent(chip->dev);
200 	NANDBUS_LOCK(nandbus);
201 	NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num);
202 
203 	cg = &chip->chip_geom;
204 	start_page = offset_to_page(cg, offset);
205 	off = offset_to_page_off(cg, offset);
206 
207 	if (off != 0 || (len % cg->page_size) != 0) {
208 		printf("Not aligned write start [0x%08x] size [0x%08x]\n",
209 		    off, len);
210 		NANDBUS_UNLOCK(nandbus);
211 		return (EINVAL);
212 	}
213 
214 	ptr = (uint8_t *)buf;
215 	while (len > 0) {
216 		err = NAND_PROGRAM_PAGE(chip->dev, start_page, ptr,
217 		    cg->page_size, 0);
218 		if (err)
219 			break;
220 
221 		len -= cg->page_size;
222 		start_page++;
223 		ptr += cg->page_size;
224 	}
225 
226 	NANDBUS_UNLOCK(nandbus);
227 	return (err);
228 }
229 
230 static void
nand_strategy(struct bio * bp)231 nand_strategy(struct bio *bp)
232 {
233 	struct nand_chip *chip;
234 	struct cdev *dev;
235 	int err = 0;
236 
237 	dev = bp->bio_dev;
238 	chip = dev->si_drv1;
239 
240 	nand_debug(NDBG_CDEV, "Strategy %s on chip %d [%p]\n",
241 	    bp->bio_cmd == BIO_READ ? "READ" : "WRITE",
242 	    chip->num, chip);
243 
244 	if (bp->bio_cmd == BIO_READ) {
245 		err = nand_read(chip,
246 		    bp->bio_offset & 0xffffffff,
247 		    bp->bio_data, bp->bio_bcount);
248 	} else {
249 		err = nand_write(chip,
250 		    bp->bio_offset & 0xffffffff,
251 		    bp->bio_data, bp->bio_bcount);
252 	}
253 
254 	if (err == 0)
255 		bp->bio_resid = 0;
256 	else {
257 		bp->bio_error = EIO;
258 		bp->bio_flags |= BIO_ERROR;
259 		bp->bio_resid = bp->bio_bcount;
260 	}
261 
262 	biodone(bp);
263 }
264 
265 static int
nand_oob_access(struct nand_chip * chip,uint32_t page,uint32_t offset,uint32_t len,uint8_t * data,uint8_t write)266 nand_oob_access(struct nand_chip *chip, uint32_t page, uint32_t offset,
267     uint32_t len, uint8_t *data, uint8_t write)
268 {
269 	struct chip_geom *cg;
270 	uint8_t *buf = NULL;
271 	int ret = 0;
272 
273 	cg = &chip->chip_geom;
274 
275 	buf = malloc(cg->oob_size, M_NAND, M_WAITOK);
276 	if (!buf)
277 		return (ENOMEM);
278 
279 	memset(buf, 0xff, cg->oob_size);
280 
281 	if (!write) {
282 		ret = nand_read_oob(chip, page, buf, cg->oob_size);
283 		copyout(buf, data, len);
284 	} else {
285 		copyin(data, buf, len);
286 		ret = nand_prog_oob(chip, page, buf, cg->oob_size);
287 	}
288 
289 	free(buf, M_NAND);
290 
291 	return (ret);
292 }
293 
294 static int
nand_ioctl(struct cdev * dev,u_long cmd,caddr_t data,int fflag,struct thread * td)295 nand_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
296     struct thread *td)
297 {
298 	struct nand_chip *chip;
299 	struct chip_geom  *cg;
300 	struct nand_oob_rw *oob_rw = NULL;
301 	struct nand_raw_rw *raw_rw = NULL;
302 	device_t nandbus;
303 	size_t bufsize = 0, len = 0;
304 	size_t raw_size;
305 	off_t off;
306 	uint8_t *buf = NULL;
307 	int ret = 0;
308 	uint8_t status;
309 
310 	chip = (struct nand_chip *)dev->si_drv1;
311 	cg = &chip->chip_geom;
312 	nandbus = device_get_parent(chip->dev);
313 
314 	if ((cmd == NAND_IO_RAW_READ) || (cmd == NAND_IO_RAW_PROG)) {
315 		raw_rw = (struct nand_raw_rw *)data;
316 		raw_size =  cg->pgs_per_blk * (cg->page_size + cg->oob_size);
317 
318 		/* Check if len is not bigger than chip size */
319 		if (raw_rw->len > raw_size)
320 			return (EFBIG);
321 
322 		/*
323 		 * Do not ask for too much memory, in case of large transfers
324 		 * read/write in 16-pages chunks
325 		 */
326 		bufsize = 16 * (cg->page_size + cg->oob_size);
327 		if (raw_rw->len < bufsize)
328 			bufsize = raw_rw->len;
329 
330 		buf = malloc(bufsize, M_NAND, M_WAITOK);
331 		len = raw_rw->len;
332 		off = 0;
333 	}
334 	switch(cmd) {
335 	case NAND_IO_ERASE:
336 		ret = nand_erase_blocks(chip, ((off_t *)data)[0],
337 		    ((off_t *)data)[1]);
338 		break;
339 
340 	case NAND_IO_OOB_READ:
341 		oob_rw = (struct nand_oob_rw *)data;
342 		ret = nand_oob_access(chip, oob_rw->page, 0,
343 		    oob_rw->len, oob_rw->data, 0);
344 		break;
345 
346 	case NAND_IO_OOB_PROG:
347 		oob_rw = (struct nand_oob_rw *)data;
348 		ret = nand_oob_access(chip, oob_rw->page, 0,
349 		    oob_rw->len, oob_rw->data, 1);
350 		break;
351 
352 	case NAND_IO_GET_STATUS:
353 		NANDBUS_LOCK(nandbus);
354 		ret = NANDBUS_GET_STATUS(nandbus, &status);
355 		if (ret == 0)
356 			*(uint8_t *)data = status;
357 		NANDBUS_UNLOCK(nandbus);
358 		break;
359 
360 	case NAND_IO_RAW_PROG:
361 		while (len > 0) {
362 			if (len < bufsize)
363 				bufsize = len;
364 			ret = copyin(raw_rw->data + off, buf, bufsize);
365 			if (ret)
366 				break;
367 			ret = nand_prog_pages_raw(chip, raw_rw->off + off, buf,
368 			    bufsize);
369 			if (ret)
370 				break;
371 			len -= bufsize;
372 			off += bufsize;
373 		}
374 		break;
375 
376 	case NAND_IO_RAW_READ:
377 		while (len > 0) {
378 			if (len < bufsize)
379 				bufsize = len;
380 
381 			ret = nand_read_pages_raw(chip, raw_rw->off + off, buf,
382 			    bufsize);
383 			if (ret)
384 				break;
385 
386 			ret = copyout(buf, raw_rw->data + off, bufsize);
387 			if (ret)
388 				break;
389 			len -= bufsize;
390 			off += bufsize;
391 		}
392 		break;
393 
394 	case NAND_IO_PAGE_STAT:
395 		ret = nand_page_stat(chip, (struct page_stat_io *)data);
396 		break;
397 
398 	case NAND_IO_BLOCK_STAT:
399 		ret = nand_block_stat(chip, (struct block_stat_io *)data);
400 		break;
401 
402 	case NAND_IO_GET_CHIP_PARAM:
403 		nand_get_chip_param(chip, (struct chip_param_io *)data);
404 		break;
405 
406 	default:
407 		printf("Unknown nand_ioctl request \n");
408 		ret = EIO;
409 	}
410 
411 	if (buf)
412 		free(buf, M_NAND);
413 
414 	return (ret);
415 }
416 
417 static int
nand_page_stat(struct nand_chip * chip,struct page_stat_io * page_stat)418 nand_page_stat(struct nand_chip *chip, struct page_stat_io *page_stat)
419 {
420 	struct chip_geom *cg;
421 	struct page_stat *stat;
422 	int num_pages;
423 
424 	cg = &chip->chip_geom;
425 	num_pages = cg->pgs_per_blk * cg->blks_per_lun * cg->luns;
426 	if (page_stat->page_num >= num_pages)
427 		return (EINVAL);
428 
429 	stat = &chip->pg_stat[page_stat->page_num];
430 	page_stat->page_read = stat->page_read;
431 	page_stat->page_written = stat->page_written;
432 	page_stat->page_raw_read = stat->page_raw_read;
433 	page_stat->page_raw_written = stat->page_raw_written;
434 	page_stat->ecc_succeded = stat->ecc_stat.ecc_succeded;
435 	page_stat->ecc_corrected = stat->ecc_stat.ecc_corrected;
436 	page_stat->ecc_failed = stat->ecc_stat.ecc_failed;
437 
438 	return (0);
439 }
440 
441 static int
nand_block_stat(struct nand_chip * chip,struct block_stat_io * block_stat)442 nand_block_stat(struct nand_chip *chip, struct block_stat_io *block_stat)
443 {
444 	struct chip_geom *cg;
445 	uint32_t block_num = block_stat->block_num;
446 
447 	cg = &chip->chip_geom;
448 	if (block_num >= cg->blks_per_lun * cg->luns)
449 		return (EINVAL);
450 
451 	block_stat->block_erased = chip->blk_stat[block_num].block_erased;
452 
453 	return (0);
454 }
455