1/*
2 * Copyright (c) 2012 Mike Frysinger <vapier@gentoo.org>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 *    derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "defs.h"
28
29#include <sys/ioctl.h>
30
31/* The mtd api changes quickly, so we have to keep a local copy */
32#include <linux/version.h>
33#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
34# include "mtd-abi.h"
35#else
36# include <mtd/mtd-abi.h>
37#endif
38#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)
39# include "ubi-user.h"
40#else
41# include <mtd/ubi-user.h>
42#endif
43
44#include "xlat/mtd_mode_options.h"
45#include "xlat/mtd_type_options.h"
46#include "xlat/mtd_flags_options.h"
47#include "xlat/mtd_otp_options.h"
48#include "xlat/mtd_nandecc_options.h"
49
50int mtd_ioctl(struct tcb *tcp, long code, long arg)
51{
52	struct mtd_info_user minfo;
53	struct erase_info_user einfo;
54	struct erase_info_user64 einfo64;
55	struct mtd_oob_buf mbuf;
56	struct mtd_oob_buf64 mbuf64;
57	struct region_info_user rinfo;
58	struct otp_info oinfo;
59	struct mtd_ecc_stats estat;
60	struct mtd_write_req mreq;
61	struct nand_oobinfo ninfo;
62	struct nand_ecclayout_user nlay;
63	int i, j;
64
65	if (entering(tcp))
66		return 0;
67
68	switch (code) {
69
70	case MEMGETINFO:
71		if (!verbose(tcp) || umove(tcp, arg, &minfo) < 0)
72			return 0;
73
74		tprints(", {type=");
75		printxval(mtd_type_options, minfo.type, "MTD_???");
76		tprints(", flags=");
77		printflags(mtd_flags_options, minfo.flags, "MTD_???");
78		tprintf(", size=%#" PRIx32 ", erasesize=%#" PRIx32,
79			minfo.size, minfo.erasesize);
80		tprintf(", writesize=%#" PRIx32 ", oobsize=%#" PRIx32,
81			minfo.writesize, minfo.oobsize);
82		tprintf(", padding=%#" PRIx64 "}",
83			(uint64_t) minfo.padding);
84		return 1;
85
86	case MEMERASE:
87	case MEMLOCK:
88	case MEMUNLOCK:
89	case MEMISLOCKED:
90		if (!verbose(tcp) || umove(tcp, arg, &einfo) < 0)
91			return 0;
92
93		tprintf(", {start=%#" PRIx32 ", length=%#" PRIx32 "}",
94			einfo.start, einfo.length);
95		return 1;
96
97	case MEMERASE64:
98		if (!verbose(tcp) || umove(tcp, arg, &einfo64) < 0)
99			return 0;
100
101		tprintf(", {start=%#" PRIx64 ", length=%#" PRIx64 "}",
102			(uint64_t) einfo64.start, (uint64_t) einfo64.length);
103		return 1;
104
105	case MEMWRITEOOB:
106	case MEMREADOOB:
107		if (!verbose(tcp) || umove(tcp, arg, &mbuf) < 0)
108			return 0;
109
110		tprintf(", {start=%#" PRIx32 ", length=%#" PRIx32 ", ptr=...}",
111			mbuf.start, mbuf.length);
112		return 1;
113
114	case MEMWRITEOOB64:
115	case MEMREADOOB64:
116		if (!verbose(tcp) || umove(tcp, arg, &mbuf64) < 0)
117			return 0;
118
119		tprintf(", {start=%#" PRIx64 ", length=%#" PRIx64 ", ptr=...}",
120			(uint64_t) mbuf64.start, (uint64_t) mbuf64.length);
121		return 1;
122
123	case MEMGETREGIONINFO:
124		if (!verbose(tcp) || umove(tcp, arg, &rinfo) < 0)
125			return 0;
126
127		tprintf(", {offset=%#" PRIx32 ", erasesize=%#" PRIx32,
128			rinfo.offset, rinfo.erasesize);
129		tprintf(", numblocks=%#" PRIx32 ", regionindex=%#" PRIx32 "}",
130			rinfo.numblocks, rinfo.regionindex);
131		return 1;
132
133	case MEMGETOOBSEL:
134		if (!verbose(tcp) || umove(tcp, arg, &ninfo) < 0)
135			return 0;
136
137		tprints(", {useecc=");
138		printxval(mtd_nandecc_options, ninfo.useecc, "MTD_NANDECC_???");
139		tprintf(", eccbytes=%#" PRIx32, ninfo.eccbytes);
140
141		tprints(", oobfree={");
142		for (i = 0; i < ARRAY_SIZE(ninfo.oobfree); ++i) {
143			if (i)
144				tprints("}, ");
145			tprints("{");
146			for (j = 0; j < ARRAY_SIZE(ninfo.oobfree[0]); ++j) {
147				if (j)
148					tprints(", ");
149				tprintf("%#" PRIx32, ninfo.oobfree[i][j]);
150			}
151		}
152
153		tprints("}}, eccpos={");
154		for (i = 0; i < ARRAY_SIZE(ninfo.eccpos); ++i) {
155			if (i)
156				tprints(", ");
157			tprintf("%#" PRIx32, ninfo.eccpos[i]);
158		}
159
160		tprints("}");
161		return 1;
162
163	case OTPGETREGIONINFO:
164	case OTPLOCK:
165		if (!verbose(tcp) || umove(tcp, arg, &oinfo) < 0)
166			return 0;
167
168		tprintf(", {start=%#" PRIx32 ", length=%#" PRIx32 ", locked=%" PRIu32 "}",
169			oinfo.start, oinfo.length, oinfo.locked);
170		return 1;
171
172	case ECCGETLAYOUT:
173		if (!verbose(tcp) || umove(tcp, arg, &nlay) < 0)
174			return 0;
175
176		tprintf(", {eccbytes=%#" PRIx32 ", eccpos={", nlay.eccbytes);
177		for (i = 0; i < ARRAY_SIZE(nlay.eccpos); ++i) {
178			if (i)
179				tprints(", ");
180			tprintf("%#" PRIx32, nlay.eccpos[i]);
181		}
182		tprintf("}, oobavail=%#" PRIx32 ", oobfree={", nlay.oobavail);
183		for (i = 0; i < ARRAY_SIZE(nlay.oobfree); ++i) {
184			if (i)
185				tprints(", ");
186			tprintf("{offset=%#" PRIx32 ", length=%#" PRIx32 "}",
187				nlay.oobfree[i].offset, nlay.oobfree[i].length);
188		}
189		tprints("}");
190		return 1;
191
192	case ECCGETSTATS:
193		if (!verbose(tcp) || umove(tcp, arg, &estat) < 0)
194			return 0;
195
196		tprintf(", {corrected=%#" PRIx32 ", failed=%#" PRIx32,
197			estat.corrected, estat.failed);
198		tprintf(", badblocks=%#" PRIx32 ", bbtblocks=%#" PRIx32 "}",
199			estat.badblocks, estat.bbtblocks);
200		return 1;
201
202	case MEMWRITE:
203		if (!verbose(tcp) || umove(tcp, arg, &mreq) < 0)
204			return 0;
205
206		tprintf(", {start=%#" PRIx64 ", len=%#" PRIx64,
207			(uint64_t) mreq.start, (uint64_t) mreq.len);
208		tprintf(", ooblen=%#" PRIx64 ", usr_data=%#" PRIx64,
209			(uint64_t) mreq.ooblen, (uint64_t) mreq.usr_data);
210		tprintf(", usr_oob=%#" PRIx64 ", mode=",
211			(uint64_t) mreq.usr_oob);
212		printxval(mtd_mode_options, mreq.mode, "MTD_OPS_???");
213		tprints(", padding=...}");
214		return 1;
215
216	case OTPSELECT:
217		if (!verbose(tcp) || umove(tcp, arg, &i) < 0)
218			return 0;
219
220		tprints(", [");
221		printxval(mtd_otp_options, i, "MTD_OTP_???");
222		tprints("]");
223		return 1;
224
225	case MEMGETBADBLOCK:
226	case MEMSETBADBLOCK:
227		if (!verbose(tcp))
228			return 0;
229
230		tprints(", ");
231		print_loff_t(tcp, arg);
232		return 1;
233
234	case OTPGETREGIONCOUNT:
235		if (!verbose(tcp) || umove(tcp, arg, &i) < 0)
236			return 0;
237
238		tprintf(", [%d]", i);
239		return 1;
240
241	case MTDFILEMODE:
242		/* XXX: process return value as enum mtd_file_modes */
243
244	case MEMGETREGIONCOUNT:
245		/* These ones take simple args, so let default printer handle it */
246
247	default:
248		return 0;
249	}
250}
251
252#include "xlat/ubi_volume_types.h"
253#include "xlat/ubi_volume_props.h"
254
255int ubi_ioctl(struct tcb *tcp, long code, long arg)
256{
257	struct ubi_mkvol_req mkvol;
258	struct ubi_rsvol_req rsvol;
259	struct ubi_rnvol_req rnvol;
260	struct ubi_attach_req attach;
261	struct ubi_map_req map;
262	struct ubi_set_vol_prop_req prop;
263	/* 4*(n-1) + 3 for quotes and NUL */
264	char vol_name[(UBI_MAX_VOLUME_NAME + 1) * 4];
265	int ret;
266
267	if (entering(tcp))
268		return 0;
269
270	switch (code) {
271	case UBI_IOCMKVOL:
272		if (!verbose(tcp) || umove(tcp, arg, &mkvol) < 0)
273			return 0;
274
275		tprintf(", {vol_id=%" PRIi32 ", alignment=%" PRIi32
276			", bytes=%" PRIi64 ", vol_type=", mkvol.vol_id,
277			mkvol.alignment, (int64_t)mkvol.bytes);
278		printxval(ubi_volume_types, mkvol.vol_type, "UBI_???_VOLUME");
279		ret = string_quote(mkvol.name, vol_name, -1,
280			CLAMP(mkvol.name_len, 0, UBI_MAX_VOLUME_NAME));
281		tprintf(", name_len=%" PRIi16 ", name=%s%s",
282			mkvol.name_len, vol_name, ret ? "..." : "");
283		tprints("}");
284		return 1;
285
286	case UBI_IOCRSVOL:
287		if (!verbose(tcp) || umove(tcp, arg, &rsvol) < 0)
288			return 0;
289
290		tprintf(", {vol_id=%" PRIi32 ", bytes=%" PRIi64 "}",
291			rsvol.vol_id, (int64_t)rsvol.bytes);
292		return 1;
293
294	case UBI_IOCRNVOL: {
295		__s32 c;
296
297		if (!verbose(tcp) || umove(tcp, arg, &rnvol) < 0)
298			return 0;
299
300		tprintf(", {count=%" PRIi32 ", ents=[", rnvol.count);
301		for (c = 0; c < CLAMP(rnvol.count, 0, UBI_MAX_RNVOL); ++c) {
302			if (c)
303				tprints(", ");
304			ret = string_quote(rnvol.ents[c].name, vol_name, -1,
305				CLAMP(rnvol.ents[c].name_len, 0, UBI_MAX_VOLUME_NAME));
306			tprintf("{vol_id=%" PRIi32 ", name_len=%" PRIi16
307				", name=%s%s}", rnvol.ents[c].vol_id,
308				rnvol.ents[c].name_len, vol_name, ret ? "..." : "");
309		}
310		tprints("]}");
311		return 1;
312	}
313
314	case UBI_IOCVOLUP: {
315		__s64 bytes;
316
317		if (!verbose(tcp) || umove(tcp, arg, &bytes) < 0)
318			return 0;
319
320		tprintf(", %" PRIi64, (int64_t)bytes);
321		return 1;
322	}
323
324	case UBI_IOCATT:
325		if (!verbose(tcp) || umove(tcp, arg, &attach) < 0)
326			return 0;
327
328		tprintf(", {ubi_num=%" PRIi32 ", mtd_num=%" PRIi32
329			", vid_hdr_offset=%" PRIi32
330			", max_beb_per1024=%" PRIi16 "}",
331			attach.ubi_num, attach.mtd_num,
332			attach.vid_hdr_offset, attach.max_beb_per1024);
333		return 1;
334
335	case UBI_IOCEBMAP:
336		if (!verbose(tcp) || umove(tcp, arg, &map) < 0)
337			return 0;
338
339		tprintf(", {lnum=%" PRIi32 ", dtype=%" PRIi8 "}",
340			map.lnum, map.dtype);
341		return 1;
342
343	case UBI_IOCSETVOLPROP:
344		if (!verbose(tcp) || umove(tcp, arg, &prop) < 0)
345			return 0;
346
347		tprints(", {property=");
348		printxval(ubi_volume_props, prop.property, "UBI_VOL_PROP_???");
349		tprintf(", value=%#" PRIx64 "}", (uint64_t)prop.value);
350		return 1;
351
352	case UBI_IOCRMVOL:
353	case UBI_IOCDET:
354	case UBI_IOCEBER:
355	case UBI_IOCEBCH:
356	case UBI_IOCEBUNMAP:
357	case UBI_IOCEBISMAP:
358		/* These ones take simple args, so let default printer handle it */
359
360	default:
361		return 0;
362	}
363}
364