]>
git.ipfire.org Git - thirdparty/u-boot.git/blob - drivers/mtd/ubi/debug.c
1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (c) International Business Machines Corp., 2006
5 * Author: Artem Bityutskiy (Битюцкий Артём)
10 #include <ubi_uboot.h>
13 #include <linux/debugfs.h>
14 #include <linux/err.h>
15 #include <linux/uaccess.h>
16 #include <linux/module.h>
20 * ubi_dump_flash - dump a region of flash.
21 * @ubi: UBI device description object
22 * @pnum: the physical eraseblock number to dump
23 * @offset: the starting offset within the physical eraseblock to dump
24 * @len: the length of the region to dump
26 void ubi_dump_flash(struct ubi_device
*ubi
, int pnum
, int offset
, int len
)
31 loff_t addr
= (loff_t
)pnum
* ubi
->peb_size
+ offset
;
36 err
= mtd_read(ubi
->mtd
, addr
, len
, &read
, buf
);
37 if (err
&& err
!= -EUCLEAN
) {
38 ubi_err(ubi
, "err %d while reading %d bytes from PEB %d:%d, read %zd bytes",
39 err
, len
, pnum
, offset
, read
);
43 ubi_msg(ubi
, "dumping %d bytes of data from PEB %d, offset %d",
45 print_hex_dump("", DUMP_PREFIX_OFFSET
, 32, 1, buf
, len
, 1);
52 * ubi_dump_ec_hdr - dump an erase counter header.
53 * @ec_hdr: the erase counter header to dump
55 void ubi_dump_ec_hdr(const struct ubi_ec_hdr
*ec_hdr
)
57 pr_err("Erase counter header dump:\n");
58 pr_err("\tmagic %#08x\n", be32_to_cpu(ec_hdr
->magic
));
59 pr_err("\tversion %d\n", (int)ec_hdr
->version
);
60 pr_err("\tec %llu\n", (long long)be64_to_cpu(ec_hdr
->ec
));
61 pr_err("\tvid_hdr_offset %d\n", be32_to_cpu(ec_hdr
->vid_hdr_offset
));
62 pr_err("\tdata_offset %d\n", be32_to_cpu(ec_hdr
->data_offset
));
63 pr_err("\timage_seq %d\n", be32_to_cpu(ec_hdr
->image_seq
));
64 pr_err("\thdr_crc %#08x\n", be32_to_cpu(ec_hdr
->hdr_crc
));
65 pr_err("erase counter header hexdump:\n");
66 print_hex_dump("", DUMP_PREFIX_OFFSET
, 32, 1,
67 ec_hdr
, UBI_EC_HDR_SIZE
, 1);
71 * ubi_dump_vid_hdr - dump a volume identifier header.
72 * @vid_hdr: the volume identifier header to dump
74 void ubi_dump_vid_hdr(const struct ubi_vid_hdr
*vid_hdr
)
76 pr_err("Volume identifier header dump:\n");
77 pr_err("\tmagic %08x\n", be32_to_cpu(vid_hdr
->magic
));
78 pr_err("\tversion %d\n", (int)vid_hdr
->version
);
79 pr_err("\tvol_type %d\n", (int)vid_hdr
->vol_type
);
80 pr_err("\tcopy_flag %d\n", (int)vid_hdr
->copy_flag
);
81 pr_err("\tcompat %d\n", (int)vid_hdr
->compat
);
82 pr_err("\tvol_id %d\n", be32_to_cpu(vid_hdr
->vol_id
));
83 pr_err("\tlnum %d\n", be32_to_cpu(vid_hdr
->lnum
));
84 pr_err("\tdata_size %d\n", be32_to_cpu(vid_hdr
->data_size
));
85 pr_err("\tused_ebs %d\n", be32_to_cpu(vid_hdr
->used_ebs
));
86 pr_err("\tdata_pad %d\n", be32_to_cpu(vid_hdr
->data_pad
));
87 pr_err("\tsqnum %llu\n",
88 (unsigned long long)be64_to_cpu(vid_hdr
->sqnum
));
89 pr_err("\thdr_crc %08x\n", be32_to_cpu(vid_hdr
->hdr_crc
));
90 pr_err("Volume identifier header hexdump:\n");
91 print_hex_dump("", DUMP_PREFIX_OFFSET
, 32, 1,
92 vid_hdr
, UBI_VID_HDR_SIZE
, 1);
96 * ubi_dump_vol_info - dump volume information.
97 * @vol: UBI volume description object
99 void ubi_dump_vol_info(const struct ubi_volume
*vol
)
101 printf("Volume information dump:\n");
102 printf("\tvol_id %d\n", vol
->vol_id
);
103 printf("\treserved_pebs %d\n", vol
->reserved_pebs
);
104 printf("\talignment %d\n", vol
->alignment
);
105 printf("\tdata_pad %d\n", vol
->data_pad
);
106 printf("\tvol_type %d\n", vol
->vol_type
);
107 printf("\tname_len %d\n", vol
->name_len
);
108 printf("\tusable_leb_size %d\n", vol
->usable_leb_size
);
109 printf("\tused_ebs %d\n", vol
->used_ebs
);
110 printf("\tused_bytes %lld\n", vol
->used_bytes
);
111 printf("\tlast_eb_bytes %d\n", vol
->last_eb_bytes
);
112 printf("\tcorrupted %d\n", vol
->corrupted
);
113 printf("\tupd_marker %d\n", vol
->upd_marker
);
114 printf("\tskip_check %d\n", vol
->skip_check
);
116 if (vol
->name_len
<= UBI_VOL_NAME_MAX
&&
117 strnlen(vol
->name
, vol
->name_len
+ 1) == vol
->name_len
) {
118 printf("\tname %s\n", vol
->name
);
120 printf("\t1st 5 characters of name: %c%c%c%c%c\n",
121 vol
->name
[0], vol
->name
[1], vol
->name
[2],
122 vol
->name
[3], vol
->name
[4]);
127 * ubi_dump_vtbl_record - dump a &struct ubi_vtbl_record object.
128 * @r: the object to dump
129 * @idx: volume table index
131 void ubi_dump_vtbl_record(const struct ubi_vtbl_record
*r
, int idx
)
133 int name_len
= be16_to_cpu(r
->name_len
);
135 pr_err("Volume table record %d dump:\n", idx
);
136 pr_err("\treserved_pebs %d\n", be32_to_cpu(r
->reserved_pebs
));
137 pr_err("\talignment %d\n", be32_to_cpu(r
->alignment
));
138 pr_err("\tdata_pad %d\n", be32_to_cpu(r
->data_pad
));
139 pr_err("\tvol_type %d\n", (int)r
->vol_type
);
140 pr_err("\tupd_marker %d\n", (int)r
->upd_marker
);
141 pr_err("\tname_len %d\n", name_len
);
143 if (r
->name
[0] == '\0') {
144 pr_err("\tname NULL\n");
148 if (name_len
<= UBI_VOL_NAME_MAX
&&
149 strnlen(&r
->name
[0], name_len
+ 1) == name_len
) {
150 pr_err("\tname %s\n", &r
->name
[0]);
152 pr_err("\t1st 5 characters of name: %c%c%c%c%c\n",
153 r
->name
[0], r
->name
[1], r
->name
[2], r
->name
[3],
156 pr_err("\tcrc %#08x\n", be32_to_cpu(r
->crc
));
160 * ubi_dump_av - dump a &struct ubi_ainf_volume object.
161 * @av: the object to dump
163 void ubi_dump_av(const struct ubi_ainf_volume
*av
)
165 pr_err("Volume attaching information dump:\n");
166 pr_err("\tvol_id %d\n", av
->vol_id
);
167 pr_err("\thighest_lnum %d\n", av
->highest_lnum
);
168 pr_err("\tleb_count %d\n", av
->leb_count
);
169 pr_err("\tcompat %d\n", av
->compat
);
170 pr_err("\tvol_type %d\n", av
->vol_type
);
171 pr_err("\tused_ebs %d\n", av
->used_ebs
);
172 pr_err("\tlast_data_size %d\n", av
->last_data_size
);
173 pr_err("\tdata_pad %d\n", av
->data_pad
);
177 * ubi_dump_aeb - dump a &struct ubi_ainf_peb object.
178 * @aeb: the object to dump
179 * @type: object type: 0 - not corrupted, 1 - corrupted
181 void ubi_dump_aeb(const struct ubi_ainf_peb
*aeb
, int type
)
183 pr_err("eraseblock attaching information dump:\n");
184 pr_err("\tec %d\n", aeb
->ec
);
185 pr_err("\tpnum %d\n", aeb
->pnum
);
187 pr_err("\tlnum %d\n", aeb
->lnum
);
188 pr_err("\tscrub %d\n", aeb
->scrub
);
189 pr_err("\tsqnum %llu\n", aeb
->sqnum
);
194 * ubi_dump_mkvol_req - dump a &struct ubi_mkvol_req object.
195 * @req: the object to dump
197 void ubi_dump_mkvol_req(const struct ubi_mkvol_req
*req
)
201 pr_err("Volume creation request dump:\n");
202 pr_err("\tvol_id %d\n", req
->vol_id
);
203 pr_err("\talignment %d\n", req
->alignment
);
204 pr_err("\tbytes %lld\n", (long long)req
->bytes
);
205 pr_err("\tvol_type %d\n", req
->vol_type
);
206 pr_err("\tname_len %d\n", req
->name_len
);
208 memcpy(nm
, req
->name
, 16);
210 pr_err("\t1st 16 characters of name: %s\n", nm
);
215 * Root directory for UBI stuff in debugfs. Contains sub-directories which
216 * contain the stuff specific to particular UBI devices.
218 static struct dentry
*dfs_rootdir
;
221 * ubi_debugfs_init - create UBI debugfs directory.
223 * Create UBI debugfs directory. Returns zero in case of success and a negative
224 * error code in case of failure.
226 int ubi_debugfs_init(void)
228 if (!IS_ENABLED(CONFIG_DEBUG_FS
))
231 dfs_rootdir
= debugfs_create_dir("ubi", NULL
);
232 if (IS_ERR_OR_NULL(dfs_rootdir
)) {
233 int err
= dfs_rootdir
? -ENODEV
: PTR_ERR(dfs_rootdir
);
235 pr_err("UBI error: cannot create \"ubi\" debugfs directory, error %d\n",
244 * ubi_debugfs_exit - remove UBI debugfs directory.
246 void ubi_debugfs_exit(void)
248 if (IS_ENABLED(CONFIG_DEBUG_FS
))
249 debugfs_remove(dfs_rootdir
);
252 /* Read an UBI debugfs file */
253 static ssize_t
dfs_file_read(struct file
*file
, char __user
*user_buf
,
254 size_t count
, loff_t
*ppos
)
256 unsigned long ubi_num
= (unsigned long)file
->private_data
;
257 struct dentry
*dent
= file
->f_path
.dentry
;
258 struct ubi_device
*ubi
;
259 struct ubi_debug_info
*d
;
263 ubi
= ubi_get_device(ubi_num
);
268 if (dent
== d
->dfs_chk_gen
)
270 else if (dent
== d
->dfs_chk_io
)
272 else if (dent
== d
->dfs_chk_fastmap
)
273 val
= d
->chk_fastmap
;
274 else if (dent
== d
->dfs_disable_bgt
)
275 val
= d
->disable_bgt
;
276 else if (dent
== d
->dfs_emulate_bitflips
)
277 val
= d
->emulate_bitflips
;
278 else if (dent
== d
->dfs_emulate_io_failures
)
279 val
= d
->emulate_io_failures
;
280 else if (dent
== d
->dfs_emulate_power_cut
) {
281 snprintf(buf
, sizeof(buf
), "%u\n", d
->emulate_power_cut
);
282 count
= simple_read_from_buffer(user_buf
, count
, ppos
,
285 } else if (dent
== d
->dfs_power_cut_min
) {
286 snprintf(buf
, sizeof(buf
), "%u\n", d
->power_cut_min
);
287 count
= simple_read_from_buffer(user_buf
, count
, ppos
,
290 } else if (dent
== d
->dfs_power_cut_max
) {
291 snprintf(buf
, sizeof(buf
), "%u\n", d
->power_cut_max
);
292 count
= simple_read_from_buffer(user_buf
, count
, ppos
,
308 count
= simple_read_from_buffer(user_buf
, count
, ppos
, buf
, 2);
315 /* Write an UBI debugfs file */
316 static ssize_t
dfs_file_write(struct file
*file
, const char __user
*user_buf
,
317 size_t count
, loff_t
*ppos
)
319 unsigned long ubi_num
= (unsigned long)file
->private_data
;
320 struct dentry
*dent
= file
->f_path
.dentry
;
321 struct ubi_device
*ubi
;
322 struct ubi_debug_info
*d
;
327 ubi
= ubi_get_device(ubi_num
);
332 buf_size
= min_t(size_t, count
, (sizeof(buf
) - 1));
333 if (copy_from_user(buf
, user_buf
, buf_size
)) {
338 if (dent
== d
->dfs_power_cut_min
) {
339 if (kstrtouint(buf
, 0, &d
->power_cut_min
) != 0)
342 } else if (dent
== d
->dfs_power_cut_max
) {
343 if (kstrtouint(buf
, 0, &d
->power_cut_max
) != 0)
346 } else if (dent
== d
->dfs_emulate_power_cut
) {
347 if (kstrtoint(buf
, 0, &val
) != 0)
349 d
->emulate_power_cut
= val
;
355 else if (buf
[0] == '0')
362 if (dent
== d
->dfs_chk_gen
)
364 else if (dent
== d
->dfs_chk_io
)
366 else if (dent
== d
->dfs_chk_fastmap
)
367 d
->chk_fastmap
= val
;
368 else if (dent
== d
->dfs_disable_bgt
)
369 d
->disable_bgt
= val
;
370 else if (dent
== d
->dfs_emulate_bitflips
)
371 d
->emulate_bitflips
= val
;
372 else if (dent
== d
->dfs_emulate_io_failures
)
373 d
->emulate_io_failures
= val
;
382 /* File operations for all UBI debugfs files */
383 static const struct file_operations dfs_fops
= {
384 .read
= dfs_file_read
,
385 .write
= dfs_file_write
,
388 .owner
= THIS_MODULE
,
392 * ubi_debugfs_init_dev - initialize debugfs for an UBI device.
393 * @ubi: UBI device description object
395 * This function creates all debugfs files for UBI device @ubi. Returns zero in
396 * case of success and a negative error code in case of failure.
398 int ubi_debugfs_init_dev(struct ubi_device
*ubi
)
401 unsigned long ubi_num
= ubi
->ubi_num
;
404 struct ubi_debug_info
*d
= &ubi
->dbg
;
406 if (!IS_ENABLED(CONFIG_DEBUG_FS
))
409 n
= snprintf(d
->dfs_dir_name
, UBI_DFS_DIR_LEN
+ 1, UBI_DFS_DIR_NAME
,
411 if (n
== UBI_DFS_DIR_LEN
) {
412 /* The array size is too small */
413 fname
= UBI_DFS_DIR_NAME
;
414 dent
= ERR_PTR(-EINVAL
);
418 fname
= d
->dfs_dir_name
;
419 dent
= debugfs_create_dir(fname
, dfs_rootdir
);
420 if (IS_ERR_OR_NULL(dent
))
425 dent
= debugfs_create_file(fname
, S_IWUSR
, d
->dfs_dir
, (void *)ubi_num
,
427 if (IS_ERR_OR_NULL(dent
))
429 d
->dfs_chk_gen
= dent
;
432 dent
= debugfs_create_file(fname
, S_IWUSR
, d
->dfs_dir
, (void *)ubi_num
,
434 if (IS_ERR_OR_NULL(dent
))
436 d
->dfs_chk_io
= dent
;
438 fname
= "chk_fastmap";
439 dent
= debugfs_create_file(fname
, S_IWUSR
, d
->dfs_dir
, (void *)ubi_num
,
441 if (IS_ERR_OR_NULL(dent
))
443 d
->dfs_chk_fastmap
= dent
;
445 fname
= "tst_disable_bgt";
446 dent
= debugfs_create_file(fname
, S_IWUSR
, d
->dfs_dir
, (void *)ubi_num
,
448 if (IS_ERR_OR_NULL(dent
))
450 d
->dfs_disable_bgt
= dent
;
452 fname
= "tst_emulate_bitflips";
453 dent
= debugfs_create_file(fname
, S_IWUSR
, d
->dfs_dir
, (void *)ubi_num
,
455 if (IS_ERR_OR_NULL(dent
))
457 d
->dfs_emulate_bitflips
= dent
;
459 fname
= "tst_emulate_io_failures";
460 dent
= debugfs_create_file(fname
, S_IWUSR
, d
->dfs_dir
, (void *)ubi_num
,
462 if (IS_ERR_OR_NULL(dent
))
464 d
->dfs_emulate_io_failures
= dent
;
466 fname
= "tst_emulate_power_cut";
467 dent
= debugfs_create_file(fname
, S_IWUSR
, d
->dfs_dir
, (void *)ubi_num
,
469 if (IS_ERR_OR_NULL(dent
))
471 d
->dfs_emulate_power_cut
= dent
;
473 fname
= "tst_emulate_power_cut_min";
474 dent
= debugfs_create_file(fname
, S_IWUSR
, d
->dfs_dir
, (void *)ubi_num
,
476 if (IS_ERR_OR_NULL(dent
))
478 d
->dfs_power_cut_min
= dent
;
480 fname
= "tst_emulate_power_cut_max";
481 dent
= debugfs_create_file(fname
, S_IWUSR
, d
->dfs_dir
, (void *)ubi_num
,
483 if (IS_ERR_OR_NULL(dent
))
485 d
->dfs_power_cut_max
= dent
;
490 debugfs_remove_recursive(d
->dfs_dir
);
492 err
= dent
? PTR_ERR(dent
) : -ENODEV
;
493 ubi_err(ubi
, "cannot create \"%s\" debugfs file or directory, error %d\n",
499 * dbg_debug_exit_dev - free all debugfs files corresponding to device @ubi
500 * @ubi: UBI device description object
502 void ubi_debugfs_exit_dev(struct ubi_device
*ubi
)
504 if (IS_ENABLED(CONFIG_DEBUG_FS
))
505 debugfs_remove_recursive(ubi
->dbg
.dfs_dir
);
509 * ubi_dbg_power_cut - emulate a power cut if it is time to do so
510 * @ubi: UBI device description object
511 * @caller: Flags set to indicate from where the function is being called
513 * Returns non-zero if a power cut was emulated, zero if not.
515 int ubi_dbg_power_cut(struct ubi_device
*ubi
, int caller
)
519 if ((ubi
->dbg
.emulate_power_cut
& caller
) == 0)
522 if (ubi
->dbg
.power_cut_counter
== 0) {
523 ubi
->dbg
.power_cut_counter
= ubi
->dbg
.power_cut_min
;
525 if (ubi
->dbg
.power_cut_max
> ubi
->dbg
.power_cut_min
) {
526 range
= ubi
->dbg
.power_cut_max
- ubi
->dbg
.power_cut_min
;
527 ubi
->dbg
.power_cut_counter
+= prandom_u32() % range
;
532 ubi
->dbg
.power_cut_counter
--;
533 if (ubi
->dbg
.power_cut_counter
)
536 ubi_msg(ubi
, "XXXXXXXXXXXXXXX emulating a power cut XXXXXXXXXXXXXXXX");
541 int ubi_debugfs_init(void)
546 void ubi_debugfs_exit(void)
550 int ubi_debugfs_init_dev(struct ubi_device
*ubi
)
555 void ubi_debugfs_exit_dev(struct ubi_device
*ubi
)
559 int ubi_dbg_power_cut(struct ubi_device
*ubi
, int caller
)