1961df833SKyungmin Park /* 2961df833SKyungmin Park * Copyright (c) International Business Machines Corp., 2006 3961df833SKyungmin Park * 41a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 5961df833SKyungmin Park * 6961df833SKyungmin Park * Author: Artem Bityutskiy (Битюцкий Артём) 7961df833SKyungmin Park */ 8961df833SKyungmin Park 9961df833SKyungmin Park #include <ubi_uboot.h> 10961df833SKyungmin Park #include "ubi.h" 11ff94bc40SHeiko Schocher #ifndef __UBOOT__ 12ff94bc40SHeiko Schocher #include <linux/debugfs.h> 13ff94bc40SHeiko Schocher #include <linux/uaccess.h> 14ff94bc40SHeiko Schocher #include <linux/module.h> 15ff94bc40SHeiko Schocher #endif 16961df833SKyungmin Park 17961df833SKyungmin Park /** 18ff94bc40SHeiko Schocher * ubi_dump_flash - dump a region of flash. 19ff94bc40SHeiko Schocher * @ubi: UBI device description object 20ff94bc40SHeiko Schocher * @pnum: the physical eraseblock number to dump 21ff94bc40SHeiko Schocher * @offset: the starting offset within the physical eraseblock to dump 22ff94bc40SHeiko Schocher * @len: the length of the region to dump 23ff94bc40SHeiko Schocher */ 24ff94bc40SHeiko Schocher void ubi_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len) 25ff94bc40SHeiko Schocher { 26ff94bc40SHeiko Schocher int err; 27ff94bc40SHeiko Schocher size_t read; 28ff94bc40SHeiko Schocher void *buf; 29ff94bc40SHeiko Schocher loff_t addr = (loff_t)pnum * ubi->peb_size + offset; 30ff94bc40SHeiko Schocher 31ff94bc40SHeiko Schocher buf = vmalloc(len); 32ff94bc40SHeiko Schocher if (!buf) 33ff94bc40SHeiko Schocher return; 34ff94bc40SHeiko Schocher err = mtd_read(ubi->mtd, addr, len, &read, buf); 35ff94bc40SHeiko Schocher if (err && err != -EUCLEAN) { 36*0195a7bbSHeiko Schocher ubi_err(ubi, "err %d while reading %d bytes from PEB %d:%d, read %zd bytes", 37ff94bc40SHeiko Schocher err, len, pnum, offset, read); 38ff94bc40SHeiko Schocher goto out; 39ff94bc40SHeiko Schocher } 40ff94bc40SHeiko Schocher 41*0195a7bbSHeiko Schocher ubi_msg(ubi, "dumping %d bytes of data from PEB %d, offset %d", 42ff94bc40SHeiko Schocher len, pnum, offset); 43ff94bc40SHeiko Schocher print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1); 44ff94bc40SHeiko Schocher out: 45ff94bc40SHeiko Schocher vfree(buf); 46ff94bc40SHeiko Schocher return; 47ff94bc40SHeiko Schocher } 48ff94bc40SHeiko Schocher 49ff94bc40SHeiko Schocher /** 50ff94bc40SHeiko Schocher * ubi_dump_ec_hdr - dump an erase counter header. 51961df833SKyungmin Park * @ec_hdr: the erase counter header to dump 52961df833SKyungmin Park */ 53ff94bc40SHeiko Schocher void ubi_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr) 54961df833SKyungmin Park { 55ff94bc40SHeiko Schocher pr_err("Erase counter header dump:\n"); 56ff94bc40SHeiko Schocher pr_err("\tmagic %#08x\n", be32_to_cpu(ec_hdr->magic)); 57ff94bc40SHeiko Schocher pr_err("\tversion %d\n", (int)ec_hdr->version); 58ff94bc40SHeiko Schocher pr_err("\tec %llu\n", (long long)be64_to_cpu(ec_hdr->ec)); 59ff94bc40SHeiko Schocher pr_err("\tvid_hdr_offset %d\n", be32_to_cpu(ec_hdr->vid_hdr_offset)); 60ff94bc40SHeiko Schocher pr_err("\tdata_offset %d\n", be32_to_cpu(ec_hdr->data_offset)); 61ff94bc40SHeiko Schocher pr_err("\timage_seq %d\n", be32_to_cpu(ec_hdr->image_seq)); 62ff94bc40SHeiko Schocher pr_err("\thdr_crc %#08x\n", be32_to_cpu(ec_hdr->hdr_crc)); 63ff94bc40SHeiko Schocher pr_err("erase counter header hexdump:\n"); 64961df833SKyungmin Park print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, 65961df833SKyungmin Park ec_hdr, UBI_EC_HDR_SIZE, 1); 66961df833SKyungmin Park } 67961df833SKyungmin Park 68961df833SKyungmin Park /** 69ff94bc40SHeiko Schocher * ubi_dump_vid_hdr - dump a volume identifier header. 70961df833SKyungmin Park * @vid_hdr: the volume identifier header to dump 71961df833SKyungmin Park */ 72ff94bc40SHeiko Schocher void ubi_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr) 73961df833SKyungmin Park { 74ff94bc40SHeiko Schocher pr_err("Volume identifier header dump:\n"); 75ff94bc40SHeiko Schocher pr_err("\tmagic %08x\n", be32_to_cpu(vid_hdr->magic)); 76ff94bc40SHeiko Schocher pr_err("\tversion %d\n", (int)vid_hdr->version); 77ff94bc40SHeiko Schocher pr_err("\tvol_type %d\n", (int)vid_hdr->vol_type); 78ff94bc40SHeiko Schocher pr_err("\tcopy_flag %d\n", (int)vid_hdr->copy_flag); 79ff94bc40SHeiko Schocher pr_err("\tcompat %d\n", (int)vid_hdr->compat); 80ff94bc40SHeiko Schocher pr_err("\tvol_id %d\n", be32_to_cpu(vid_hdr->vol_id)); 81ff94bc40SHeiko Schocher pr_err("\tlnum %d\n", be32_to_cpu(vid_hdr->lnum)); 82ff94bc40SHeiko Schocher pr_err("\tdata_size %d\n", be32_to_cpu(vid_hdr->data_size)); 83ff94bc40SHeiko Schocher pr_err("\tused_ebs %d\n", be32_to_cpu(vid_hdr->used_ebs)); 84ff94bc40SHeiko Schocher pr_err("\tdata_pad %d\n", be32_to_cpu(vid_hdr->data_pad)); 85ff94bc40SHeiko Schocher pr_err("\tsqnum %llu\n", 86961df833SKyungmin Park (unsigned long long)be64_to_cpu(vid_hdr->sqnum)); 87ff94bc40SHeiko Schocher pr_err("\thdr_crc %08x\n", be32_to_cpu(vid_hdr->hdr_crc)); 88ff94bc40SHeiko Schocher pr_err("Volume identifier header hexdump:\n"); 89ff94bc40SHeiko Schocher print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, 90ff94bc40SHeiko Schocher vid_hdr, UBI_VID_HDR_SIZE, 1); 91961df833SKyungmin Park } 92961df833SKyungmin Park 93961df833SKyungmin Park /** 94ff94bc40SHeiko Schocher * ubi_dump_vol_info - dump volume information. 95961df833SKyungmin Park * @vol: UBI volume description object 96961df833SKyungmin Park */ 97ff94bc40SHeiko Schocher void ubi_dump_vol_info(const struct ubi_volume *vol) 98961df833SKyungmin Park { 99ff94bc40SHeiko Schocher printf("Volume information dump:\n"); 100ff94bc40SHeiko Schocher printf("\tvol_id %d\n", vol->vol_id); 101ff94bc40SHeiko Schocher printf("\treserved_pebs %d\n", vol->reserved_pebs); 102ff94bc40SHeiko Schocher printf("\talignment %d\n", vol->alignment); 103ff94bc40SHeiko Schocher printf("\tdata_pad %d\n", vol->data_pad); 104ff94bc40SHeiko Schocher printf("\tvol_type %d\n", vol->vol_type); 105ff94bc40SHeiko Schocher printf("\tname_len %d\n", vol->name_len); 106ff94bc40SHeiko Schocher printf("\tusable_leb_size %d\n", vol->usable_leb_size); 107ff94bc40SHeiko Schocher printf("\tused_ebs %d\n", vol->used_ebs); 108ff94bc40SHeiko Schocher printf("\tused_bytes %lld\n", vol->used_bytes); 109ff94bc40SHeiko Schocher printf("\tlast_eb_bytes %d\n", vol->last_eb_bytes); 110ff94bc40SHeiko Schocher printf("\tcorrupted %d\n", vol->corrupted); 111ff94bc40SHeiko Schocher printf("\tupd_marker %d\n", vol->upd_marker); 112961df833SKyungmin Park 113961df833SKyungmin Park if (vol->name_len <= UBI_VOL_NAME_MAX && 114961df833SKyungmin Park strnlen(vol->name, vol->name_len + 1) == vol->name_len) { 115ff94bc40SHeiko Schocher printf("\tname %s\n", vol->name); 116961df833SKyungmin Park } else { 117ff94bc40SHeiko Schocher printf("\t1st 5 characters of name: %c%c%c%c%c\n", 118961df833SKyungmin Park vol->name[0], vol->name[1], vol->name[2], 119961df833SKyungmin Park vol->name[3], vol->name[4]); 120961df833SKyungmin Park } 121961df833SKyungmin Park } 122961df833SKyungmin Park 123961df833SKyungmin Park /** 124ff94bc40SHeiko Schocher * ubi_dump_vtbl_record - dump a &struct ubi_vtbl_record object. 125961df833SKyungmin Park * @r: the object to dump 126961df833SKyungmin Park * @idx: volume table index 127961df833SKyungmin Park */ 128ff94bc40SHeiko Schocher void ubi_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx) 129961df833SKyungmin Park { 130961df833SKyungmin Park int name_len = be16_to_cpu(r->name_len); 131961df833SKyungmin Park 132ff94bc40SHeiko Schocher pr_err("Volume table record %d dump:\n", idx); 133ff94bc40SHeiko Schocher pr_err("\treserved_pebs %d\n", be32_to_cpu(r->reserved_pebs)); 134ff94bc40SHeiko Schocher pr_err("\talignment %d\n", be32_to_cpu(r->alignment)); 135ff94bc40SHeiko Schocher pr_err("\tdata_pad %d\n", be32_to_cpu(r->data_pad)); 136ff94bc40SHeiko Schocher pr_err("\tvol_type %d\n", (int)r->vol_type); 137ff94bc40SHeiko Schocher pr_err("\tupd_marker %d\n", (int)r->upd_marker); 138ff94bc40SHeiko Schocher pr_err("\tname_len %d\n", name_len); 139961df833SKyungmin Park 140961df833SKyungmin Park if (r->name[0] == '\0') { 141ff94bc40SHeiko Schocher pr_err("\tname NULL\n"); 142961df833SKyungmin Park return; 143961df833SKyungmin Park } 144961df833SKyungmin Park 145961df833SKyungmin Park if (name_len <= UBI_VOL_NAME_MAX && 146961df833SKyungmin Park strnlen(&r->name[0], name_len + 1) == name_len) { 147ff94bc40SHeiko Schocher pr_err("\tname %s\n", &r->name[0]); 148961df833SKyungmin Park } else { 149ff94bc40SHeiko Schocher pr_err("\t1st 5 characters of name: %c%c%c%c%c\n", 150961df833SKyungmin Park r->name[0], r->name[1], r->name[2], r->name[3], 151961df833SKyungmin Park r->name[4]); 152961df833SKyungmin Park } 153ff94bc40SHeiko Schocher pr_err("\tcrc %#08x\n", be32_to_cpu(r->crc)); 154961df833SKyungmin Park } 155961df833SKyungmin Park 156961df833SKyungmin Park /** 157ff94bc40SHeiko Schocher * ubi_dump_av - dump a &struct ubi_ainf_volume object. 158ff94bc40SHeiko Schocher * @av: the object to dump 159961df833SKyungmin Park */ 160ff94bc40SHeiko Schocher void ubi_dump_av(const struct ubi_ainf_volume *av) 161961df833SKyungmin Park { 162ff94bc40SHeiko Schocher pr_err("Volume attaching information dump:\n"); 163ff94bc40SHeiko Schocher pr_err("\tvol_id %d\n", av->vol_id); 164ff94bc40SHeiko Schocher pr_err("\thighest_lnum %d\n", av->highest_lnum); 165ff94bc40SHeiko Schocher pr_err("\tleb_count %d\n", av->leb_count); 166ff94bc40SHeiko Schocher pr_err("\tcompat %d\n", av->compat); 167ff94bc40SHeiko Schocher pr_err("\tvol_type %d\n", av->vol_type); 168ff94bc40SHeiko Schocher pr_err("\tused_ebs %d\n", av->used_ebs); 169ff94bc40SHeiko Schocher pr_err("\tlast_data_size %d\n", av->last_data_size); 170ff94bc40SHeiko Schocher pr_err("\tdata_pad %d\n", av->data_pad); 171961df833SKyungmin Park } 172961df833SKyungmin Park 173961df833SKyungmin Park /** 174ff94bc40SHeiko Schocher * ubi_dump_aeb - dump a &struct ubi_ainf_peb object. 175ff94bc40SHeiko Schocher * @aeb: the object to dump 176961df833SKyungmin Park * @type: object type: 0 - not corrupted, 1 - corrupted 177961df833SKyungmin Park */ 178ff94bc40SHeiko Schocher void ubi_dump_aeb(const struct ubi_ainf_peb *aeb, int type) 179961df833SKyungmin Park { 180ff94bc40SHeiko Schocher pr_err("eraseblock attaching information dump:\n"); 181ff94bc40SHeiko Schocher pr_err("\tec %d\n", aeb->ec); 182ff94bc40SHeiko Schocher pr_err("\tpnum %d\n", aeb->pnum); 183961df833SKyungmin Park if (type == 0) { 184ff94bc40SHeiko Schocher pr_err("\tlnum %d\n", aeb->lnum); 185ff94bc40SHeiko Schocher pr_err("\tscrub %d\n", aeb->scrub); 186ff94bc40SHeiko Schocher pr_err("\tsqnum %llu\n", aeb->sqnum); 187961df833SKyungmin Park } 188961df833SKyungmin Park } 189961df833SKyungmin Park 190961df833SKyungmin Park /** 191ff94bc40SHeiko Schocher * ubi_dump_mkvol_req - dump a &struct ubi_mkvol_req object. 192961df833SKyungmin Park * @req: the object to dump 193961df833SKyungmin Park */ 194ff94bc40SHeiko Schocher void ubi_dump_mkvol_req(const struct ubi_mkvol_req *req) 195961df833SKyungmin Park { 196961df833SKyungmin Park char nm[17]; 197961df833SKyungmin Park 198ff94bc40SHeiko Schocher pr_err("Volume creation request dump:\n"); 199ff94bc40SHeiko Schocher pr_err("\tvol_id %d\n", req->vol_id); 200ff94bc40SHeiko Schocher pr_err("\talignment %d\n", req->alignment); 201ff94bc40SHeiko Schocher pr_err("\tbytes %lld\n", (long long)req->bytes); 202ff94bc40SHeiko Schocher pr_err("\tvol_type %d\n", req->vol_type); 203ff94bc40SHeiko Schocher pr_err("\tname_len %d\n", req->name_len); 204961df833SKyungmin Park 205961df833SKyungmin Park memcpy(nm, req->name, 16); 206961df833SKyungmin Park nm[16] = 0; 207ff94bc40SHeiko Schocher pr_err("\t1st 16 characters of name: %s\n", nm); 208961df833SKyungmin Park } 209961df833SKyungmin Park 210ff94bc40SHeiko Schocher #ifndef __UBOOT__ 211ff94bc40SHeiko Schocher /* 212ff94bc40SHeiko Schocher * Root directory for UBI stuff in debugfs. Contains sub-directories which 213ff94bc40SHeiko Schocher * contain the stuff specific to particular UBI devices. 214ff94bc40SHeiko Schocher */ 215ff94bc40SHeiko Schocher static struct dentry *dfs_rootdir; 216ff94bc40SHeiko Schocher 217ff94bc40SHeiko Schocher /** 218ff94bc40SHeiko Schocher * ubi_debugfs_init - create UBI debugfs directory. 219ff94bc40SHeiko Schocher * 220ff94bc40SHeiko Schocher * Create UBI debugfs directory. Returns zero in case of success and a negative 221ff94bc40SHeiko Schocher * error code in case of failure. 222ff94bc40SHeiko Schocher */ 223ff94bc40SHeiko Schocher int ubi_debugfs_init(void) 224ff94bc40SHeiko Schocher { 225ff94bc40SHeiko Schocher if (!IS_ENABLED(CONFIG_DEBUG_FS)) 226ff94bc40SHeiko Schocher return 0; 227ff94bc40SHeiko Schocher 228ff94bc40SHeiko Schocher dfs_rootdir = debugfs_create_dir("ubi", NULL); 229ff94bc40SHeiko Schocher if (IS_ERR_OR_NULL(dfs_rootdir)) { 230ff94bc40SHeiko Schocher int err = dfs_rootdir ? -ENODEV : PTR_ERR(dfs_rootdir); 231ff94bc40SHeiko Schocher 232*0195a7bbSHeiko Schocher pr_err("UBI error: cannot create \"ubi\" debugfs directory, error %d\n", 233ff94bc40SHeiko Schocher err); 234ff94bc40SHeiko Schocher return err; 235ff94bc40SHeiko Schocher } 236ff94bc40SHeiko Schocher 237ff94bc40SHeiko Schocher return 0; 238ff94bc40SHeiko Schocher } 239ff94bc40SHeiko Schocher 240ff94bc40SHeiko Schocher /** 241ff94bc40SHeiko Schocher * ubi_debugfs_exit - remove UBI debugfs directory. 242ff94bc40SHeiko Schocher */ 243ff94bc40SHeiko Schocher void ubi_debugfs_exit(void) 244ff94bc40SHeiko Schocher { 245ff94bc40SHeiko Schocher if (IS_ENABLED(CONFIG_DEBUG_FS)) 246ff94bc40SHeiko Schocher debugfs_remove(dfs_rootdir); 247ff94bc40SHeiko Schocher } 248ff94bc40SHeiko Schocher 249ff94bc40SHeiko Schocher /* Read an UBI debugfs file */ 250ff94bc40SHeiko Schocher static ssize_t dfs_file_read(struct file *file, char __user *user_buf, 251ff94bc40SHeiko Schocher size_t count, loff_t *ppos) 252ff94bc40SHeiko Schocher { 253ff94bc40SHeiko Schocher unsigned long ubi_num = (unsigned long)file->private_data; 254ff94bc40SHeiko Schocher struct dentry *dent = file->f_path.dentry; 255ff94bc40SHeiko Schocher struct ubi_device *ubi; 256ff94bc40SHeiko Schocher struct ubi_debug_info *d; 257*0195a7bbSHeiko Schocher char buf[8]; 258ff94bc40SHeiko Schocher int val; 259ff94bc40SHeiko Schocher 260ff94bc40SHeiko Schocher ubi = ubi_get_device(ubi_num); 261ff94bc40SHeiko Schocher if (!ubi) 262ff94bc40SHeiko Schocher return -ENODEV; 263ff94bc40SHeiko Schocher d = &ubi->dbg; 264ff94bc40SHeiko Schocher 265ff94bc40SHeiko Schocher if (dent == d->dfs_chk_gen) 266ff94bc40SHeiko Schocher val = d->chk_gen; 267ff94bc40SHeiko Schocher else if (dent == d->dfs_chk_io) 268ff94bc40SHeiko Schocher val = d->chk_io; 269*0195a7bbSHeiko Schocher else if (dent == d->dfs_chk_fastmap) 270*0195a7bbSHeiko Schocher val = d->chk_fastmap; 271ff94bc40SHeiko Schocher else if (dent == d->dfs_disable_bgt) 272ff94bc40SHeiko Schocher val = d->disable_bgt; 273ff94bc40SHeiko Schocher else if (dent == d->dfs_emulate_bitflips) 274ff94bc40SHeiko Schocher val = d->emulate_bitflips; 275ff94bc40SHeiko Schocher else if (dent == d->dfs_emulate_io_failures) 276ff94bc40SHeiko Schocher val = d->emulate_io_failures; 277*0195a7bbSHeiko Schocher else if (dent == d->dfs_emulate_power_cut) { 278*0195a7bbSHeiko Schocher snprintf(buf, sizeof(buf), "%u\n", d->emulate_power_cut); 279*0195a7bbSHeiko Schocher count = simple_read_from_buffer(user_buf, count, ppos, 280*0195a7bbSHeiko Schocher buf, strlen(buf)); 281*0195a7bbSHeiko Schocher goto out; 282*0195a7bbSHeiko Schocher } else if (dent == d->dfs_power_cut_min) { 283*0195a7bbSHeiko Schocher snprintf(buf, sizeof(buf), "%u\n", d->power_cut_min); 284*0195a7bbSHeiko Schocher count = simple_read_from_buffer(user_buf, count, ppos, 285*0195a7bbSHeiko Schocher buf, strlen(buf)); 286*0195a7bbSHeiko Schocher goto out; 287*0195a7bbSHeiko Schocher } else if (dent == d->dfs_power_cut_max) { 288*0195a7bbSHeiko Schocher snprintf(buf, sizeof(buf), "%u\n", d->power_cut_max); 289*0195a7bbSHeiko Schocher count = simple_read_from_buffer(user_buf, count, ppos, 290*0195a7bbSHeiko Schocher buf, strlen(buf)); 291*0195a7bbSHeiko Schocher goto out; 292*0195a7bbSHeiko Schocher } 293ff94bc40SHeiko Schocher else { 294ff94bc40SHeiko Schocher count = -EINVAL; 295ff94bc40SHeiko Schocher goto out; 296ff94bc40SHeiko Schocher } 297ff94bc40SHeiko Schocher 298ff94bc40SHeiko Schocher if (val) 299ff94bc40SHeiko Schocher buf[0] = '1'; 300ff94bc40SHeiko Schocher else 301ff94bc40SHeiko Schocher buf[0] = '0'; 302ff94bc40SHeiko Schocher buf[1] = '\n'; 303ff94bc40SHeiko Schocher buf[2] = 0x00; 304ff94bc40SHeiko Schocher 305ff94bc40SHeiko Schocher count = simple_read_from_buffer(user_buf, count, ppos, buf, 2); 306ff94bc40SHeiko Schocher 307ff94bc40SHeiko Schocher out: 308ff94bc40SHeiko Schocher ubi_put_device(ubi); 309ff94bc40SHeiko Schocher return count; 310ff94bc40SHeiko Schocher } 311ff94bc40SHeiko Schocher 312ff94bc40SHeiko Schocher /* Write an UBI debugfs file */ 313ff94bc40SHeiko Schocher static ssize_t dfs_file_write(struct file *file, const char __user *user_buf, 314ff94bc40SHeiko Schocher size_t count, loff_t *ppos) 315ff94bc40SHeiko Schocher { 316ff94bc40SHeiko Schocher unsigned long ubi_num = (unsigned long)file->private_data; 317ff94bc40SHeiko Schocher struct dentry *dent = file->f_path.dentry; 318ff94bc40SHeiko Schocher struct ubi_device *ubi; 319ff94bc40SHeiko Schocher struct ubi_debug_info *d; 320ff94bc40SHeiko Schocher size_t buf_size; 321*0195a7bbSHeiko Schocher char buf[8] = {0}; 322ff94bc40SHeiko Schocher int val; 323ff94bc40SHeiko Schocher 324ff94bc40SHeiko Schocher ubi = ubi_get_device(ubi_num); 325ff94bc40SHeiko Schocher if (!ubi) 326ff94bc40SHeiko Schocher return -ENODEV; 327ff94bc40SHeiko Schocher d = &ubi->dbg; 328ff94bc40SHeiko Schocher 329ff94bc40SHeiko Schocher buf_size = min_t(size_t, count, (sizeof(buf) - 1)); 330ff94bc40SHeiko Schocher if (copy_from_user(buf, user_buf, buf_size)) { 331ff94bc40SHeiko Schocher count = -EFAULT; 332ff94bc40SHeiko Schocher goto out; 333ff94bc40SHeiko Schocher } 334ff94bc40SHeiko Schocher 335*0195a7bbSHeiko Schocher if (dent == d->dfs_power_cut_min) { 336*0195a7bbSHeiko Schocher if (kstrtouint(buf, 0, &d->power_cut_min) != 0) 337*0195a7bbSHeiko Schocher count = -EINVAL; 338*0195a7bbSHeiko Schocher goto out; 339*0195a7bbSHeiko Schocher } else if (dent == d->dfs_power_cut_max) { 340*0195a7bbSHeiko Schocher if (kstrtouint(buf, 0, &d->power_cut_max) != 0) 341*0195a7bbSHeiko Schocher count = -EINVAL; 342*0195a7bbSHeiko Schocher goto out; 343*0195a7bbSHeiko Schocher } else if (dent == d->dfs_emulate_power_cut) { 344*0195a7bbSHeiko Schocher if (kstrtoint(buf, 0, &val) != 0) 345*0195a7bbSHeiko Schocher count = -EINVAL; 346*0195a7bbSHeiko Schocher d->emulate_power_cut = val; 347*0195a7bbSHeiko Schocher goto out; 348*0195a7bbSHeiko Schocher } 349*0195a7bbSHeiko Schocher 350ff94bc40SHeiko Schocher if (buf[0] == '1') 351ff94bc40SHeiko Schocher val = 1; 352ff94bc40SHeiko Schocher else if (buf[0] == '0') 353ff94bc40SHeiko Schocher val = 0; 354ff94bc40SHeiko Schocher else { 355ff94bc40SHeiko Schocher count = -EINVAL; 356ff94bc40SHeiko Schocher goto out; 357ff94bc40SHeiko Schocher } 358ff94bc40SHeiko Schocher 359ff94bc40SHeiko Schocher if (dent == d->dfs_chk_gen) 360ff94bc40SHeiko Schocher d->chk_gen = val; 361ff94bc40SHeiko Schocher else if (dent == d->dfs_chk_io) 362ff94bc40SHeiko Schocher d->chk_io = val; 363*0195a7bbSHeiko Schocher else if (dent == d->dfs_chk_fastmap) 364*0195a7bbSHeiko Schocher d->chk_fastmap = val; 365ff94bc40SHeiko Schocher else if (dent == d->dfs_disable_bgt) 366ff94bc40SHeiko Schocher d->disable_bgt = val; 367ff94bc40SHeiko Schocher else if (dent == d->dfs_emulate_bitflips) 368ff94bc40SHeiko Schocher d->emulate_bitflips = val; 369ff94bc40SHeiko Schocher else if (dent == d->dfs_emulate_io_failures) 370ff94bc40SHeiko Schocher d->emulate_io_failures = val; 371ff94bc40SHeiko Schocher else 372ff94bc40SHeiko Schocher count = -EINVAL; 373ff94bc40SHeiko Schocher 374ff94bc40SHeiko Schocher out: 375ff94bc40SHeiko Schocher ubi_put_device(ubi); 376ff94bc40SHeiko Schocher return count; 377ff94bc40SHeiko Schocher } 378ff94bc40SHeiko Schocher 379ff94bc40SHeiko Schocher /* File operations for all UBI debugfs files */ 380ff94bc40SHeiko Schocher static const struct file_operations dfs_fops = { 381ff94bc40SHeiko Schocher .read = dfs_file_read, 382ff94bc40SHeiko Schocher .write = dfs_file_write, 383ff94bc40SHeiko Schocher .open = simple_open, 384ff94bc40SHeiko Schocher .llseek = no_llseek, 385ff94bc40SHeiko Schocher .owner = THIS_MODULE, 386ff94bc40SHeiko Schocher }; 387ff94bc40SHeiko Schocher 388ff94bc40SHeiko Schocher /** 389ff94bc40SHeiko Schocher * ubi_debugfs_init_dev - initialize debugfs for an UBI device. 390ff94bc40SHeiko Schocher * @ubi: UBI device description object 391ff94bc40SHeiko Schocher * 392ff94bc40SHeiko Schocher * This function creates all debugfs files for UBI device @ubi. Returns zero in 393ff94bc40SHeiko Schocher * case of success and a negative error code in case of failure. 394ff94bc40SHeiko Schocher */ 395ff94bc40SHeiko Schocher int ubi_debugfs_init_dev(struct ubi_device *ubi) 396ff94bc40SHeiko Schocher { 397ff94bc40SHeiko Schocher int err, n; 398ff94bc40SHeiko Schocher unsigned long ubi_num = ubi->ubi_num; 399ff94bc40SHeiko Schocher const char *fname; 400ff94bc40SHeiko Schocher struct dentry *dent; 401ff94bc40SHeiko Schocher struct ubi_debug_info *d = &ubi->dbg; 402ff94bc40SHeiko Schocher 403ff94bc40SHeiko Schocher if (!IS_ENABLED(CONFIG_DEBUG_FS)) 404ff94bc40SHeiko Schocher return 0; 405ff94bc40SHeiko Schocher 406ff94bc40SHeiko Schocher n = snprintf(d->dfs_dir_name, UBI_DFS_DIR_LEN + 1, UBI_DFS_DIR_NAME, 407ff94bc40SHeiko Schocher ubi->ubi_num); 408ff94bc40SHeiko Schocher if (n == UBI_DFS_DIR_LEN) { 409ff94bc40SHeiko Schocher /* The array size is too small */ 410ff94bc40SHeiko Schocher fname = UBI_DFS_DIR_NAME; 411ff94bc40SHeiko Schocher dent = ERR_PTR(-EINVAL); 412ff94bc40SHeiko Schocher goto out; 413ff94bc40SHeiko Schocher } 414ff94bc40SHeiko Schocher 415ff94bc40SHeiko Schocher fname = d->dfs_dir_name; 416ff94bc40SHeiko Schocher dent = debugfs_create_dir(fname, dfs_rootdir); 417ff94bc40SHeiko Schocher if (IS_ERR_OR_NULL(dent)) 418ff94bc40SHeiko Schocher goto out; 419ff94bc40SHeiko Schocher d->dfs_dir = dent; 420ff94bc40SHeiko Schocher 421ff94bc40SHeiko Schocher fname = "chk_gen"; 422ff94bc40SHeiko Schocher dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num, 423ff94bc40SHeiko Schocher &dfs_fops); 424ff94bc40SHeiko Schocher if (IS_ERR_OR_NULL(dent)) 425ff94bc40SHeiko Schocher goto out_remove; 426ff94bc40SHeiko Schocher d->dfs_chk_gen = dent; 427ff94bc40SHeiko Schocher 428ff94bc40SHeiko Schocher fname = "chk_io"; 429ff94bc40SHeiko Schocher dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num, 430ff94bc40SHeiko Schocher &dfs_fops); 431ff94bc40SHeiko Schocher if (IS_ERR_OR_NULL(dent)) 432ff94bc40SHeiko Schocher goto out_remove; 433ff94bc40SHeiko Schocher d->dfs_chk_io = dent; 434ff94bc40SHeiko Schocher 435*0195a7bbSHeiko Schocher fname = "chk_fastmap"; 436*0195a7bbSHeiko Schocher dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num, 437*0195a7bbSHeiko Schocher &dfs_fops); 438*0195a7bbSHeiko Schocher if (IS_ERR_OR_NULL(dent)) 439*0195a7bbSHeiko Schocher goto out_remove; 440*0195a7bbSHeiko Schocher d->dfs_chk_fastmap = dent; 441*0195a7bbSHeiko Schocher 442ff94bc40SHeiko Schocher fname = "tst_disable_bgt"; 443ff94bc40SHeiko Schocher dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num, 444ff94bc40SHeiko Schocher &dfs_fops); 445ff94bc40SHeiko Schocher if (IS_ERR_OR_NULL(dent)) 446ff94bc40SHeiko Schocher goto out_remove; 447ff94bc40SHeiko Schocher d->dfs_disable_bgt = dent; 448ff94bc40SHeiko Schocher 449ff94bc40SHeiko Schocher fname = "tst_emulate_bitflips"; 450ff94bc40SHeiko Schocher dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num, 451ff94bc40SHeiko Schocher &dfs_fops); 452ff94bc40SHeiko Schocher if (IS_ERR_OR_NULL(dent)) 453ff94bc40SHeiko Schocher goto out_remove; 454ff94bc40SHeiko Schocher d->dfs_emulate_bitflips = dent; 455ff94bc40SHeiko Schocher 456ff94bc40SHeiko Schocher fname = "tst_emulate_io_failures"; 457ff94bc40SHeiko Schocher dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num, 458ff94bc40SHeiko Schocher &dfs_fops); 459ff94bc40SHeiko Schocher if (IS_ERR_OR_NULL(dent)) 460ff94bc40SHeiko Schocher goto out_remove; 461ff94bc40SHeiko Schocher d->dfs_emulate_io_failures = dent; 462ff94bc40SHeiko Schocher 463*0195a7bbSHeiko Schocher fname = "tst_emulate_power_cut"; 464*0195a7bbSHeiko Schocher dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num, 465*0195a7bbSHeiko Schocher &dfs_fops); 466*0195a7bbSHeiko Schocher if (IS_ERR_OR_NULL(dent)) 467*0195a7bbSHeiko Schocher goto out_remove; 468*0195a7bbSHeiko Schocher d->dfs_emulate_power_cut = dent; 469*0195a7bbSHeiko Schocher 470*0195a7bbSHeiko Schocher fname = "tst_emulate_power_cut_min"; 471*0195a7bbSHeiko Schocher dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num, 472*0195a7bbSHeiko Schocher &dfs_fops); 473*0195a7bbSHeiko Schocher if (IS_ERR_OR_NULL(dent)) 474*0195a7bbSHeiko Schocher goto out_remove; 475*0195a7bbSHeiko Schocher d->dfs_power_cut_min = dent; 476*0195a7bbSHeiko Schocher 477*0195a7bbSHeiko Schocher fname = "tst_emulate_power_cut_max"; 478*0195a7bbSHeiko Schocher dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num, 479*0195a7bbSHeiko Schocher &dfs_fops); 480*0195a7bbSHeiko Schocher if (IS_ERR_OR_NULL(dent)) 481*0195a7bbSHeiko Schocher goto out_remove; 482*0195a7bbSHeiko Schocher d->dfs_power_cut_max = dent; 483*0195a7bbSHeiko Schocher 484ff94bc40SHeiko Schocher return 0; 485ff94bc40SHeiko Schocher 486ff94bc40SHeiko Schocher out_remove: 487ff94bc40SHeiko Schocher debugfs_remove_recursive(d->dfs_dir); 488ff94bc40SHeiko Schocher out: 489ff94bc40SHeiko Schocher err = dent ? PTR_ERR(dent) : -ENODEV; 490*0195a7bbSHeiko Schocher ubi_err(ubi, "cannot create \"%s\" debugfs file or directory, error %d\n", 491ff94bc40SHeiko Schocher fname, err); 492ff94bc40SHeiko Schocher return err; 493ff94bc40SHeiko Schocher } 494ff94bc40SHeiko Schocher 495ff94bc40SHeiko Schocher /** 496ff94bc40SHeiko Schocher * dbg_debug_exit_dev - free all debugfs files corresponding to device @ubi 497ff94bc40SHeiko Schocher * @ubi: UBI device description object 498ff94bc40SHeiko Schocher */ 499ff94bc40SHeiko Schocher void ubi_debugfs_exit_dev(struct ubi_device *ubi) 500ff94bc40SHeiko Schocher { 501ff94bc40SHeiko Schocher if (IS_ENABLED(CONFIG_DEBUG_FS)) 502ff94bc40SHeiko Schocher debugfs_remove_recursive(ubi->dbg.dfs_dir); 503ff94bc40SHeiko Schocher } 504*0195a7bbSHeiko Schocher 505*0195a7bbSHeiko Schocher /** 506*0195a7bbSHeiko Schocher * ubi_dbg_power_cut - emulate a power cut if it is time to do so 507*0195a7bbSHeiko Schocher * @ubi: UBI device description object 508*0195a7bbSHeiko Schocher * @caller: Flags set to indicate from where the function is being called 509*0195a7bbSHeiko Schocher * 510*0195a7bbSHeiko Schocher * Returns non-zero if a power cut was emulated, zero if not. 511*0195a7bbSHeiko Schocher */ 512*0195a7bbSHeiko Schocher int ubi_dbg_power_cut(struct ubi_device *ubi, int caller) 513*0195a7bbSHeiko Schocher { 514*0195a7bbSHeiko Schocher unsigned int range; 515*0195a7bbSHeiko Schocher 516*0195a7bbSHeiko Schocher if ((ubi->dbg.emulate_power_cut & caller) == 0) 517*0195a7bbSHeiko Schocher return 0; 518*0195a7bbSHeiko Schocher 519*0195a7bbSHeiko Schocher if (ubi->dbg.power_cut_counter == 0) { 520*0195a7bbSHeiko Schocher ubi->dbg.power_cut_counter = ubi->dbg.power_cut_min; 521*0195a7bbSHeiko Schocher 522*0195a7bbSHeiko Schocher if (ubi->dbg.power_cut_max > ubi->dbg.power_cut_min) { 523*0195a7bbSHeiko Schocher range = ubi->dbg.power_cut_max - ubi->dbg.power_cut_min; 524*0195a7bbSHeiko Schocher ubi->dbg.power_cut_counter += prandom_u32() % range; 525*0195a7bbSHeiko Schocher } 526*0195a7bbSHeiko Schocher return 0; 527*0195a7bbSHeiko Schocher } 528*0195a7bbSHeiko Schocher 529*0195a7bbSHeiko Schocher ubi->dbg.power_cut_counter--; 530*0195a7bbSHeiko Schocher if (ubi->dbg.power_cut_counter) 531*0195a7bbSHeiko Schocher return 0; 532*0195a7bbSHeiko Schocher 533*0195a7bbSHeiko Schocher ubi_msg(ubi, "XXXXXXXXXXXXXXX emulating a power cut XXXXXXXXXXXXXXXX"); 534*0195a7bbSHeiko Schocher ubi_ro_mode(ubi); 535*0195a7bbSHeiko Schocher return 1; 536*0195a7bbSHeiko Schocher } 537ff94bc40SHeiko Schocher #else 538ff94bc40SHeiko Schocher int ubi_debugfs_init(void) 539ff94bc40SHeiko Schocher { 540ff94bc40SHeiko Schocher return 0; 541ff94bc40SHeiko Schocher } 542ff94bc40SHeiko Schocher 543ff94bc40SHeiko Schocher void ubi_debugfs_exit(void) 544ff94bc40SHeiko Schocher { 545ff94bc40SHeiko Schocher } 546ff94bc40SHeiko Schocher 547ff94bc40SHeiko Schocher int ubi_debugfs_init_dev(struct ubi_device *ubi) 548ff94bc40SHeiko Schocher { 549ff94bc40SHeiko Schocher return 0; 550ff94bc40SHeiko Schocher } 551ff94bc40SHeiko Schocher 552ff94bc40SHeiko Schocher void ubi_debugfs_exit_dev(struct ubi_device *ubi) 553ff94bc40SHeiko Schocher { 554ff94bc40SHeiko Schocher } 555*0195a7bbSHeiko Schocher 556*0195a7bbSHeiko Schocher int ubi_dbg_power_cut(struct ubi_device *ubi, int caller) 557*0195a7bbSHeiko Schocher { 558*0195a7bbSHeiko Schocher return 0; 559*0195a7bbSHeiko Schocher } 560ff94bc40SHeiko Schocher #endif 561