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: stable/11/sys/dev/nand/nand_cdev.c 350226 2019-07-22 20:33:19Z emaste $");
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
44static int nand_page_stat(struct nand_chip *, struct page_stat_io *);
45static int nand_block_stat(struct nand_chip *, struct block_stat_io *);
46
47static d_ioctl_t nand_ioctl;
48static d_open_t nand_open;
49static d_strategy_t nand_strategy;
50
51static 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
61static int
62offset_to_page(struct chip_geom *cg, uint32_t offset)
63{
64
65	return (offset / cg->page_size);
66}
67
68static int
69offset_to_page_off(struct chip_geom *cg, uint32_t offset)
70{
71
72	return (offset % cg->page_size);
73}
74
75int
76nand_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
117void
118nand_destroy_dev(struct nand_chip *chip)
119{
120
121	if (chip->cdev)
122		destroy_dev(chip->cdev);
123}
124
125static int
126nand_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
127{
128
129	return (0);
130}
131
132static int
133nand_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
186static int
187nand_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
228static void
229nand_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
263static int
264nand_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
292static int
293nand_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
415static int
416nand_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
439static int
440nand_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