1176348Smarcel/*-
2185099Sraj * Copyright (c) 2008 Semihalf, Rafal Jaworowski
3191829Sraj * Copyright (c) 2009 Semihalf, Piotr Ziecik
4243243Sae * Copyright (c) 2012 Andrey V. Elsukov <ae@FreeBSD.org>
5176348Smarcel * All rights reserved.
6176348Smarcel *
7176348Smarcel * Redistribution and use in source and binary forms, with or without
8176348Smarcel * modification, are permitted provided that the following conditions
9176348Smarcel * are met:
10176348Smarcel * 1. Redistributions of source code must retain the above copyright
11176348Smarcel *    notice, this list of conditions and the following disclaimer.
12176348Smarcel * 2. Redistributions in binary form must reproduce the above copyright
13176348Smarcel *    notice, this list of conditions and the following disclaimer in the
14176348Smarcel *    documentation and/or other materials provided with the distribution.
15176348Smarcel *
16185099Sraj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17185099Sraj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18185099Sraj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19185099Sraj * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20185099Sraj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21185099Sraj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22185099Sraj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23185099Sraj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24185099Sraj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25185099Sraj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26185099Sraj * SUCH DAMAGE.
27185099Sraj *
28176348Smarcel */
29176348Smarcel
30185099Sraj/*
31185099Sraj * Block storage I/O routines for U-Boot
32185099Sraj */
33185099Sraj
34176348Smarcel#include <sys/cdefs.h>
35176348Smarcel__FBSDID("$FreeBSD$");
36176348Smarcel
37176348Smarcel#include <sys/param.h>
38243243Sae#include <sys/disk.h>
39176348Smarcel#include <machine/stdarg.h>
40176348Smarcel#include <stand.h>
41176348Smarcel
42185099Sraj#include "api_public.h"
43176348Smarcel#include "bootstrap.h"
44243243Sae#include "disk.h"
45185099Sraj#include "glue.h"
46185099Sraj#include "libuboot.h"
47176348Smarcel
48185099Sraj#define DEBUG
49185099Sraj#undef DEBUG
50176348Smarcel
51185099Sraj#define stor_printf(fmt, args...) do {			\
52185099Sraj    printf("%s%d: ", dev->d_dev->dv_name, dev->d_unit);	\
53185099Sraj    printf(fmt, ##args);				\
54185099Sraj} while (0)
55185099Sraj
56185099Sraj#ifdef DEBUG
57185099Sraj#define debugf(fmt, args...) do { printf("%s(): ", __func__);	\
58185099Sraj    printf(fmt,##args); } while (0)
59185099Sraj#else
60185099Sraj#define debugf(fmt, args...)
61185099Sraj#endif
62185099Sraj
63243243Saestatic struct {
64243243Sae	int		opened;	/* device is opened */
65243243Sae	int		handle;	/* storage device handle */
66243243Sae	int		type;	/* storage type */
67243243Sae	off_t		blocks;	/* block count */
68243243Sae	u_int		bsize;	/* block size */
69243243Sae} stor_info[UB_MAX_DEV];
70176348Smarcel
71243243Sae#define	SI(dev)		(stor_info[(dev)->d_unit])
72176348Smarcel
73185099Srajstatic int stor_info_no = 0;
74243243Saestatic int stor_opendev(struct disk_devdesc *);
75243243Saestatic int stor_readdev(struct disk_devdesc *, daddr_t, size_t, char *);
76185099Sraj
77185099Sraj/* devsw I/F */
78185099Srajstatic int stor_init(void);
79185099Srajstatic int stor_strategy(void *, int, daddr_t, size_t, char *, size_t *);
80185099Srajstatic int stor_open(struct open_file *, ...);
81185099Srajstatic int stor_close(struct open_file *);
82243243Saestatic int stor_ioctl(struct open_file *f, u_long cmd, void *data);
83185099Srajstatic void stor_print(int);
84243243Saestatic void stor_cleanup(void);
85185099Sraj
86185099Srajstruct devsw uboot_storage = {
87185099Sraj	"disk",
88185099Sraj	DEVT_DISK,
89185099Sraj	stor_init,
90185099Sraj	stor_strategy,
91185099Sraj	stor_open,
92185099Sraj	stor_close,
93243243Sae	stor_ioctl,
94243243Sae	stor_print,
95243243Sae	stor_cleanup
96185099Sraj};
97185099Sraj
98176348Smarcelstatic int
99185099Srajstor_init(void)
100176348Smarcel{
101185099Sraj	struct device_info *di;
102243243Sae	int i;
103177152Sobrien
104185099Sraj	if (devs_no == 0) {
105185099Sraj		printf("No U-Boot devices! Really enumerated?\n");
106185099Sraj		return (-1);
107185099Sraj	}
108185099Sraj
109185099Sraj	for (i = 0; i < devs_no; i++) {
110185099Sraj		di = ub_dev_get(i);
111185099Sraj		if ((di != NULL) && (di->type & DEV_TYP_STOR)) {
112185099Sraj			if (stor_info_no >= UB_MAX_DEV) {
113185099Sraj				printf("Too many storage devices: %d\n",
114185099Sraj				    stor_info_no);
115185099Sraj				return (-1);
116185099Sraj			}
117243243Sae			stor_info[stor_info_no].handle = i;
118243243Sae			stor_info[stor_info_no].opened = 0;
119243243Sae			stor_info[stor_info_no].type = di->type;
120243243Sae			stor_info[stor_info_no].blocks =
121243243Sae			    di->di_stor.block_count;
122243243Sae			stor_info[stor_info_no].bsize =
123243243Sae			    di->di_stor.block_size;
124243243Sae			stor_info_no++;
125185099Sraj		}
126185099Sraj	}
127185099Sraj
128243243Sae	if (!stor_info_no) {
129208534Sraj		debugf("No storage devices\n");
130185099Sraj		return (-1);
131185099Sraj	}
132185099Sraj
133185099Sraj	debugf("storage devices found: %d\n", stor_info_no);
134185099Sraj	return (0);
135176348Smarcel}
136176348Smarcel
137243243Saestatic void
138243243Saestor_cleanup(void)
139243243Sae{
140243243Sae	int i;
141243243Sae
142243243Sae	for (i = 0; i < stor_info_no; i++)
143243243Sae		if (stor_info[i].opened > 0)
144243243Sae			ub_dev_close(stor_info[i].handle);
145243243Sae	disk_cleanup(&uboot_storage);
146243243Sae}
147243243Sae
148176348Smarcelstatic int
149185099Srajstor_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf,
150176348Smarcel    size_t *rsize)
151176348Smarcel{
152243243Sae	struct disk_devdesc *dev = (struct disk_devdesc *)devdata;
153243243Sae	daddr_t bcount;
154243243Sae	int err;
155177152Sobrien
156185099Sraj	if (rw != F_READ) {
157185099Sraj		stor_printf("write attempt, operation not supported!\n");
158185099Sraj		return (EROFS);
159185099Sraj	}
160185099Sraj
161243243Sae	if (size % SI(dev).bsize) {
162185099Sraj		stor_printf("size=%d not multiple of device block size=%d\n",
163243243Sae		    size, SI(dev).bsize);
164185099Sraj		return (EIO);
165185099Sraj	}
166243243Sae	bcount = size / SI(dev).bsize;
167185099Sraj	if (rsize)
168185099Sraj		*rsize = 0;
169185099Sraj
170243243Sae	err = stor_readdev(dev, blk + dev->d_offset, bcount, buf);
171185099Sraj	if (!err && rsize)
172185099Sraj		*rsize = size;
173185099Sraj
174185099Sraj	return (err);
175176348Smarcel}
176176348Smarcel
177176348Smarcelstatic int
178185099Srajstor_open(struct open_file *f, ...)
179176348Smarcel{
180185099Sraj	va_list ap;
181243243Sae	struct disk_devdesc *dev;
182177152Sobrien
183185099Sraj	va_start(ap, f);
184243243Sae	dev = va_arg(ap, struct disk_devdesc *);
185185099Sraj	va_end(ap);
186185099Sraj
187243243Sae	return (stor_opendev(dev));
188176348Smarcel}
189176348Smarcel
190176348Smarcelstatic int
191243243Saestor_opendev(struct disk_devdesc *dev)
192176348Smarcel{
193243243Sae	int err;
194177152Sobrien
195243243Sae	if (dev->d_unit < 0 || dev->d_unit >= stor_info_no)
196243243Sae		return (EIO);
197185099Sraj
198243243Sae	if (SI(dev).opened == 0) {
199243243Sae		err = ub_dev_open(SI(dev).handle);
200243243Sae		if (err != 0) {
201243243Sae			stor_printf("device open failed with error=%d, "
202243243Sae			    "handle=%d\n", err, SI(dev).handle);
203243243Sae			return (ENXIO);
204191829Sraj		}
205243243Sae		SI(dev).opened++;
206191829Sraj	}
207243243Sae	return (disk_open(dev, SI(dev).blocks * SI(dev).bsize,
208243243Sae	    SI(dev).bsize, 0));
209176348Smarcel}
210176348Smarcel
211185099Srajstatic int
212243243Saestor_close(struct open_file *f)
213243236Sae{
214243243Sae	struct disk_devdesc *dev;
215243236Sae
216243243Sae	dev = (struct disk_devdesc *)(f->f_devdata);
217243243Sae	return (disk_close(dev));
218243236Sae}
219243236Sae
220243236Saestatic int
221243243Saestor_readdev(struct disk_devdesc *dev, daddr_t blk, size_t size, char *buf)
222185099Sraj{
223185099Sraj	lbasize_t real_size;
224243243Sae	int err;
225185099Sraj
226243236Sae	debugf("reading blk=%d size=%d @ 0x%08x\n", (int)blk, size, (uint32_t)buf);
227185099Sraj
228243243Sae	err = ub_dev_read(SI(dev).handle, buf, size, blk, &real_size);
229185099Sraj	if (err != 0) {
230185099Sraj		stor_printf("read failed, error=%d\n", err);
231185099Sraj		return (EIO);
232185099Sraj	}
233185099Sraj
234185099Sraj	if (real_size != size) {
235185099Sraj		stor_printf("real size != size\n");
236185099Sraj		err = EIO;
237185099Sraj	}
238185099Sraj
239185099Sraj	return (err);
240185099Sraj}
241185099Sraj
242176348Smarcelstatic void
243243243Saestor_print(int verbose)
244176348Smarcel{
245243243Sae	struct disk_devdesc dev;
246243243Sae	static char line[80];
247243243Sae	int i;
248176348Smarcel
249243243Sae	for (i = 0; i < stor_info_no; i++) {
250243243Sae		dev.d_dev = &uboot_storage;
251243243Sae		dev.d_unit = i;
252243243Sae		dev.d_slice = -1;
253243243Sae		dev.d_partition = -1;
254243243Sae		sprintf(line, "\tdisk%d (%s)\n", i,
255243243Sae		    ub_stor_type(SI(&dev).type));
256185099Sraj		pager_output(line);
257243243Sae		if (stor_opendev(&dev) == 0) {
258243243Sae			sprintf(line, "\tdisk%d", i);
259243243Sae			disk_print(&dev, line, verbose);
260243243Sae			disk_close(&dev);
261185099Sraj		}
262185099Sraj	}
263176348Smarcel}
264185099Sraj
265243243Saestatic int
266243243Saestor_ioctl(struct open_file *f, u_long cmd, void *data)
267191829Sraj{
268243243Sae	struct disk_devdesc *dev;
269191829Sraj
270243243Sae	dev = (struct disk_devdesc *)f->f_devdata;
271243243Sae	switch (cmd) {
272243243Sae	case DIOCGSECTORSIZE:
273243243Sae		*(u_int *)data = SI(dev).bsize;
274243243Sae		break;
275243243Sae	case DIOCGMEDIASIZE:
276243243Sae		*(off_t *)data = SI(dev).bsize * SI(dev).blocks;
277243243Sae		break;
278243243Sae	default:
279243243Sae		return (ENOTTY);
280191829Sraj	}
281243243Sae	return (0);
282191829Sraj}
283191829Sraj
284