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" 11*ff94bc40SHeiko Schocher #define __UBOOT__ 12*ff94bc40SHeiko Schocher #ifndef __UBOOT__ 13*ff94bc40SHeiko Schocher #include <linux/debugfs.h> 14*ff94bc40SHeiko Schocher #include <linux/uaccess.h> 15*ff94bc40SHeiko Schocher #include <linux/module.h> 16*ff94bc40SHeiko Schocher #endif 17961df833SKyungmin Park 18961df833SKyungmin Park /** 19*ff94bc40SHeiko Schocher * ubi_dump_flash - dump a region of flash. 20*ff94bc40SHeiko Schocher * @ubi: UBI device description object 21*ff94bc40SHeiko Schocher * @pnum: the physical eraseblock number to dump 22*ff94bc40SHeiko Schocher * @offset: the starting offset within the physical eraseblock to dump 23*ff94bc40SHeiko Schocher * @len: the length of the region to dump 24*ff94bc40SHeiko Schocher */ 25*ff94bc40SHeiko Schocher void ubi_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len) 26*ff94bc40SHeiko Schocher { 27*ff94bc40SHeiko Schocher int err; 28*ff94bc40SHeiko Schocher size_t read; 29*ff94bc40SHeiko Schocher void *buf; 30*ff94bc40SHeiko Schocher loff_t addr = (loff_t)pnum * ubi->peb_size + offset; 31*ff94bc40SHeiko Schocher 32*ff94bc40SHeiko Schocher buf = vmalloc(len); 33*ff94bc40SHeiko Schocher if (!buf) 34*ff94bc40SHeiko Schocher return; 35*ff94bc40SHeiko Schocher err = mtd_read(ubi->mtd, addr, len, &read, buf); 36*ff94bc40SHeiko Schocher if (err && err != -EUCLEAN) { 37*ff94bc40SHeiko Schocher ubi_err("error %d while reading %d bytes from PEB %d:%d, read %zd bytes", 38*ff94bc40SHeiko Schocher err, len, pnum, offset, read); 39*ff94bc40SHeiko Schocher goto out; 40*ff94bc40SHeiko Schocher } 41*ff94bc40SHeiko Schocher 42*ff94bc40SHeiko Schocher ubi_msg("dumping %d bytes of data from PEB %d, offset %d", 43*ff94bc40SHeiko Schocher len, pnum, offset); 44*ff94bc40SHeiko Schocher print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1); 45*ff94bc40SHeiko Schocher out: 46*ff94bc40SHeiko Schocher vfree(buf); 47*ff94bc40SHeiko Schocher return; 48*ff94bc40SHeiko Schocher } 49*ff94bc40SHeiko Schocher 50*ff94bc40SHeiko Schocher /** 51*ff94bc40SHeiko Schocher * ubi_dump_ec_hdr - dump an erase counter header. 52961df833SKyungmin Park * @ec_hdr: the erase counter header to dump 53961df833SKyungmin Park */ 54*ff94bc40SHeiko Schocher void ubi_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr) 55961df833SKyungmin Park { 56*ff94bc40SHeiko Schocher pr_err("Erase counter header dump:\n"); 57*ff94bc40SHeiko Schocher pr_err("\tmagic %#08x\n", be32_to_cpu(ec_hdr->magic)); 58*ff94bc40SHeiko Schocher pr_err("\tversion %d\n", (int)ec_hdr->version); 59*ff94bc40SHeiko Schocher pr_err("\tec %llu\n", (long long)be64_to_cpu(ec_hdr->ec)); 60*ff94bc40SHeiko Schocher pr_err("\tvid_hdr_offset %d\n", be32_to_cpu(ec_hdr->vid_hdr_offset)); 61*ff94bc40SHeiko Schocher pr_err("\tdata_offset %d\n", be32_to_cpu(ec_hdr->data_offset)); 62*ff94bc40SHeiko Schocher pr_err("\timage_seq %d\n", be32_to_cpu(ec_hdr->image_seq)); 63*ff94bc40SHeiko Schocher pr_err("\thdr_crc %#08x\n", be32_to_cpu(ec_hdr->hdr_crc)); 64*ff94bc40SHeiko Schocher pr_err("erase counter header hexdump:\n"); 65961df833SKyungmin Park print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, 66961df833SKyungmin Park ec_hdr, UBI_EC_HDR_SIZE, 1); 67961df833SKyungmin Park } 68961df833SKyungmin Park 69961df833SKyungmin Park /** 70*ff94bc40SHeiko Schocher * ubi_dump_vid_hdr - dump a volume identifier header. 71961df833SKyungmin Park * @vid_hdr: the volume identifier header to dump 72961df833SKyungmin Park */ 73*ff94bc40SHeiko Schocher void ubi_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr) 74961df833SKyungmin Park { 75*ff94bc40SHeiko Schocher pr_err("Volume identifier header dump:\n"); 76*ff94bc40SHeiko Schocher pr_err("\tmagic %08x\n", be32_to_cpu(vid_hdr->magic)); 77*ff94bc40SHeiko Schocher pr_err("\tversion %d\n", (int)vid_hdr->version); 78*ff94bc40SHeiko Schocher pr_err("\tvol_type %d\n", (int)vid_hdr->vol_type); 79*ff94bc40SHeiko Schocher pr_err("\tcopy_flag %d\n", (int)vid_hdr->copy_flag); 80*ff94bc40SHeiko Schocher pr_err("\tcompat %d\n", (int)vid_hdr->compat); 81*ff94bc40SHeiko Schocher pr_err("\tvol_id %d\n", be32_to_cpu(vid_hdr->vol_id)); 82*ff94bc40SHeiko Schocher pr_err("\tlnum %d\n", be32_to_cpu(vid_hdr->lnum)); 83*ff94bc40SHeiko Schocher pr_err("\tdata_size %d\n", be32_to_cpu(vid_hdr->data_size)); 84*ff94bc40SHeiko Schocher pr_err("\tused_ebs %d\n", be32_to_cpu(vid_hdr->used_ebs)); 85*ff94bc40SHeiko Schocher pr_err("\tdata_pad %d\n", be32_to_cpu(vid_hdr->data_pad)); 86*ff94bc40SHeiko Schocher pr_err("\tsqnum %llu\n", 87961df833SKyungmin Park (unsigned long long)be64_to_cpu(vid_hdr->sqnum)); 88*ff94bc40SHeiko Schocher pr_err("\thdr_crc %08x\n", be32_to_cpu(vid_hdr->hdr_crc)); 89*ff94bc40SHeiko Schocher pr_err("Volume identifier header hexdump:\n"); 90*ff94bc40SHeiko Schocher print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, 91*ff94bc40SHeiko Schocher vid_hdr, UBI_VID_HDR_SIZE, 1); 92961df833SKyungmin Park } 93961df833SKyungmin Park 94961df833SKyungmin Park /** 95*ff94bc40SHeiko Schocher * ubi_dump_vol_info - dump volume information. 96961df833SKyungmin Park * @vol: UBI volume description object 97961df833SKyungmin Park */ 98*ff94bc40SHeiko Schocher void ubi_dump_vol_info(const struct ubi_volume *vol) 99961df833SKyungmin Park { 100*ff94bc40SHeiko Schocher printf("Volume information dump:\n"); 101*ff94bc40SHeiko Schocher printf("\tvol_id %d\n", vol->vol_id); 102*ff94bc40SHeiko Schocher printf("\treserved_pebs %d\n", vol->reserved_pebs); 103*ff94bc40SHeiko Schocher printf("\talignment %d\n", vol->alignment); 104*ff94bc40SHeiko Schocher printf("\tdata_pad %d\n", vol->data_pad); 105*ff94bc40SHeiko Schocher printf("\tvol_type %d\n", vol->vol_type); 106*ff94bc40SHeiko Schocher printf("\tname_len %d\n", vol->name_len); 107*ff94bc40SHeiko Schocher printf("\tusable_leb_size %d\n", vol->usable_leb_size); 108*ff94bc40SHeiko Schocher printf("\tused_ebs %d\n", vol->used_ebs); 109*ff94bc40SHeiko Schocher printf("\tused_bytes %lld\n", vol->used_bytes); 110*ff94bc40SHeiko Schocher printf("\tlast_eb_bytes %d\n", vol->last_eb_bytes); 111*ff94bc40SHeiko Schocher printf("\tcorrupted %d\n", vol->corrupted); 112*ff94bc40SHeiko Schocher printf("\tupd_marker %d\n", vol->upd_marker); 113961df833SKyungmin Park 114961df833SKyungmin Park if (vol->name_len <= UBI_VOL_NAME_MAX && 115961df833SKyungmin Park strnlen(vol->name, vol->name_len + 1) == vol->name_len) { 116*ff94bc40SHeiko Schocher printf("\tname %s\n", vol->name); 117961df833SKyungmin Park } else { 118*ff94bc40SHeiko Schocher printf("\t1st 5 characters of name: %c%c%c%c%c\n", 119961df833SKyungmin Park vol->name[0], vol->name[1], vol->name[2], 120961df833SKyungmin Park vol->name[3], vol->name[4]); 121961df833SKyungmin Park } 122961df833SKyungmin Park } 123961df833SKyungmin Park 124961df833SKyungmin Park /** 125*ff94bc40SHeiko Schocher * ubi_dump_vtbl_record - dump a &struct ubi_vtbl_record object. 126961df833SKyungmin Park * @r: the object to dump 127961df833SKyungmin Park * @idx: volume table index 128961df833SKyungmin Park */ 129*ff94bc40SHeiko Schocher void ubi_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx) 130961df833SKyungmin Park { 131961df833SKyungmin Park int name_len = be16_to_cpu(r->name_len); 132961df833SKyungmin Park 133*ff94bc40SHeiko Schocher pr_err("Volume table record %d dump:\n", idx); 134*ff94bc40SHeiko Schocher pr_err("\treserved_pebs %d\n", be32_to_cpu(r->reserved_pebs)); 135*ff94bc40SHeiko Schocher pr_err("\talignment %d\n", be32_to_cpu(r->alignment)); 136*ff94bc40SHeiko Schocher pr_err("\tdata_pad %d\n", be32_to_cpu(r->data_pad)); 137*ff94bc40SHeiko Schocher pr_err("\tvol_type %d\n", (int)r->vol_type); 138*ff94bc40SHeiko Schocher pr_err("\tupd_marker %d\n", (int)r->upd_marker); 139*ff94bc40SHeiko Schocher pr_err("\tname_len %d\n", name_len); 140961df833SKyungmin Park 141961df833SKyungmin Park if (r->name[0] == '\0') { 142*ff94bc40SHeiko Schocher pr_err("\tname NULL\n"); 143961df833SKyungmin Park return; 144961df833SKyungmin Park } 145961df833SKyungmin Park 146961df833SKyungmin Park if (name_len <= UBI_VOL_NAME_MAX && 147961df833SKyungmin Park strnlen(&r->name[0], name_len + 1) == name_len) { 148*ff94bc40SHeiko Schocher pr_err("\tname %s\n", &r->name[0]); 149961df833SKyungmin Park } else { 150*ff94bc40SHeiko Schocher pr_err("\t1st 5 characters of name: %c%c%c%c%c\n", 151961df833SKyungmin Park r->name[0], r->name[1], r->name[2], r->name[3], 152961df833SKyungmin Park r->name[4]); 153961df833SKyungmin Park } 154*ff94bc40SHeiko Schocher pr_err("\tcrc %#08x\n", be32_to_cpu(r->crc)); 155961df833SKyungmin Park } 156961df833SKyungmin Park 157961df833SKyungmin Park /** 158*ff94bc40SHeiko Schocher * ubi_dump_av - dump a &struct ubi_ainf_volume object. 159*ff94bc40SHeiko Schocher * @av: the object to dump 160961df833SKyungmin Park */ 161*ff94bc40SHeiko Schocher void ubi_dump_av(const struct ubi_ainf_volume *av) 162961df833SKyungmin Park { 163*ff94bc40SHeiko Schocher pr_err("Volume attaching information dump:\n"); 164*ff94bc40SHeiko Schocher pr_err("\tvol_id %d\n", av->vol_id); 165*ff94bc40SHeiko Schocher pr_err("\thighest_lnum %d\n", av->highest_lnum); 166*ff94bc40SHeiko Schocher pr_err("\tleb_count %d\n", av->leb_count); 167*ff94bc40SHeiko Schocher pr_err("\tcompat %d\n", av->compat); 168*ff94bc40SHeiko Schocher pr_err("\tvol_type %d\n", av->vol_type); 169*ff94bc40SHeiko Schocher pr_err("\tused_ebs %d\n", av->used_ebs); 170*ff94bc40SHeiko Schocher pr_err("\tlast_data_size %d\n", av->last_data_size); 171*ff94bc40SHeiko Schocher pr_err("\tdata_pad %d\n", av->data_pad); 172961df833SKyungmin Park } 173961df833SKyungmin Park 174961df833SKyungmin Park /** 175*ff94bc40SHeiko Schocher * ubi_dump_aeb - dump a &struct ubi_ainf_peb object. 176*ff94bc40SHeiko Schocher * @aeb: the object to dump 177961df833SKyungmin Park * @type: object type: 0 - not corrupted, 1 - corrupted 178961df833SKyungmin Park */ 179*ff94bc40SHeiko Schocher void ubi_dump_aeb(const struct ubi_ainf_peb *aeb, int type) 180961df833SKyungmin Park { 181*ff94bc40SHeiko Schocher pr_err("eraseblock attaching information dump:\n"); 182*ff94bc40SHeiko Schocher pr_err("\tec %d\n", aeb->ec); 183*ff94bc40SHeiko Schocher pr_err("\tpnum %d\n", aeb->pnum); 184961df833SKyungmin Park if (type == 0) { 185*ff94bc40SHeiko Schocher pr_err("\tlnum %d\n", aeb->lnum); 186*ff94bc40SHeiko Schocher pr_err("\tscrub %d\n", aeb->scrub); 187*ff94bc40SHeiko Schocher pr_err("\tsqnum %llu\n", aeb->sqnum); 188961df833SKyungmin Park } 189961df833SKyungmin Park } 190961df833SKyungmin Park 191961df833SKyungmin Park /** 192*ff94bc40SHeiko Schocher * ubi_dump_mkvol_req - dump a &struct ubi_mkvol_req object. 193961df833SKyungmin Park * @req: the object to dump 194961df833SKyungmin Park */ 195*ff94bc40SHeiko Schocher void ubi_dump_mkvol_req(const struct ubi_mkvol_req *req) 196961df833SKyungmin Park { 197961df833SKyungmin Park char nm[17]; 198961df833SKyungmin Park 199*ff94bc40SHeiko Schocher pr_err("Volume creation request dump:\n"); 200*ff94bc40SHeiko Schocher pr_err("\tvol_id %d\n", req->vol_id); 201*ff94bc40SHeiko Schocher pr_err("\talignment %d\n", req->alignment); 202*ff94bc40SHeiko Schocher pr_err("\tbytes %lld\n", (long long)req->bytes); 203*ff94bc40SHeiko Schocher pr_err("\tvol_type %d\n", req->vol_type); 204*ff94bc40SHeiko Schocher pr_err("\tname_len %d\n", req->name_len); 205961df833SKyungmin Park 206961df833SKyungmin Park memcpy(nm, req->name, 16); 207961df833SKyungmin Park nm[16] = 0; 208*ff94bc40SHeiko Schocher pr_err("\t1st 16 characters of name: %s\n", nm); 209961df833SKyungmin Park } 210961df833SKyungmin Park 211*ff94bc40SHeiko Schocher #ifndef __UBOOT__ 212*ff94bc40SHeiko Schocher /* 213*ff94bc40SHeiko Schocher * Root directory for UBI stuff in debugfs. Contains sub-directories which 214*ff94bc40SHeiko Schocher * contain the stuff specific to particular UBI devices. 215*ff94bc40SHeiko Schocher */ 216*ff94bc40SHeiko Schocher static struct dentry *dfs_rootdir; 217*ff94bc40SHeiko Schocher 218*ff94bc40SHeiko Schocher /** 219*ff94bc40SHeiko Schocher * ubi_debugfs_init - create UBI debugfs directory. 220*ff94bc40SHeiko Schocher * 221*ff94bc40SHeiko Schocher * Create UBI debugfs directory. Returns zero in case of success and a negative 222*ff94bc40SHeiko Schocher * error code in case of failure. 223*ff94bc40SHeiko Schocher */ 224*ff94bc40SHeiko Schocher int ubi_debugfs_init(void) 225*ff94bc40SHeiko Schocher { 226*ff94bc40SHeiko Schocher if (!IS_ENABLED(CONFIG_DEBUG_FS)) 227*ff94bc40SHeiko Schocher return 0; 228*ff94bc40SHeiko Schocher 229*ff94bc40SHeiko Schocher dfs_rootdir = debugfs_create_dir("ubi", NULL); 230*ff94bc40SHeiko Schocher if (IS_ERR_OR_NULL(dfs_rootdir)) { 231*ff94bc40SHeiko Schocher int err = dfs_rootdir ? -ENODEV : PTR_ERR(dfs_rootdir); 232*ff94bc40SHeiko Schocher 233*ff94bc40SHeiko Schocher ubi_err("cannot create \"ubi\" debugfs directory, error %d\n", 234*ff94bc40SHeiko Schocher err); 235*ff94bc40SHeiko Schocher return err; 236*ff94bc40SHeiko Schocher } 237*ff94bc40SHeiko Schocher 238*ff94bc40SHeiko Schocher return 0; 239*ff94bc40SHeiko Schocher } 240*ff94bc40SHeiko Schocher 241*ff94bc40SHeiko Schocher /** 242*ff94bc40SHeiko Schocher * ubi_debugfs_exit - remove UBI debugfs directory. 243*ff94bc40SHeiko Schocher */ 244*ff94bc40SHeiko Schocher void ubi_debugfs_exit(void) 245*ff94bc40SHeiko Schocher { 246*ff94bc40SHeiko Schocher if (IS_ENABLED(CONFIG_DEBUG_FS)) 247*ff94bc40SHeiko Schocher debugfs_remove(dfs_rootdir); 248*ff94bc40SHeiko Schocher } 249*ff94bc40SHeiko Schocher 250*ff94bc40SHeiko Schocher /* Read an UBI debugfs file */ 251*ff94bc40SHeiko Schocher static ssize_t dfs_file_read(struct file *file, char __user *user_buf, 252*ff94bc40SHeiko Schocher size_t count, loff_t *ppos) 253*ff94bc40SHeiko Schocher { 254*ff94bc40SHeiko Schocher unsigned long ubi_num = (unsigned long)file->private_data; 255*ff94bc40SHeiko Schocher struct dentry *dent = file->f_path.dentry; 256*ff94bc40SHeiko Schocher struct ubi_device *ubi; 257*ff94bc40SHeiko Schocher struct ubi_debug_info *d; 258*ff94bc40SHeiko Schocher char buf[3]; 259*ff94bc40SHeiko Schocher int val; 260*ff94bc40SHeiko Schocher 261*ff94bc40SHeiko Schocher ubi = ubi_get_device(ubi_num); 262*ff94bc40SHeiko Schocher if (!ubi) 263*ff94bc40SHeiko Schocher return -ENODEV; 264*ff94bc40SHeiko Schocher d = &ubi->dbg; 265*ff94bc40SHeiko Schocher 266*ff94bc40SHeiko Schocher if (dent == d->dfs_chk_gen) 267*ff94bc40SHeiko Schocher val = d->chk_gen; 268*ff94bc40SHeiko Schocher else if (dent == d->dfs_chk_io) 269*ff94bc40SHeiko Schocher val = d->chk_io; 270*ff94bc40SHeiko Schocher else if (dent == d->dfs_disable_bgt) 271*ff94bc40SHeiko Schocher val = d->disable_bgt; 272*ff94bc40SHeiko Schocher else if (dent == d->dfs_emulate_bitflips) 273*ff94bc40SHeiko Schocher val = d->emulate_bitflips; 274*ff94bc40SHeiko Schocher else if (dent == d->dfs_emulate_io_failures) 275*ff94bc40SHeiko Schocher val = d->emulate_io_failures; 276*ff94bc40SHeiko Schocher else { 277*ff94bc40SHeiko Schocher count = -EINVAL; 278*ff94bc40SHeiko Schocher goto out; 279*ff94bc40SHeiko Schocher } 280*ff94bc40SHeiko Schocher 281*ff94bc40SHeiko Schocher if (val) 282*ff94bc40SHeiko Schocher buf[0] = '1'; 283*ff94bc40SHeiko Schocher else 284*ff94bc40SHeiko Schocher buf[0] = '0'; 285*ff94bc40SHeiko Schocher buf[1] = '\n'; 286*ff94bc40SHeiko Schocher buf[2] = 0x00; 287*ff94bc40SHeiko Schocher 288*ff94bc40SHeiko Schocher count = simple_read_from_buffer(user_buf, count, ppos, buf, 2); 289*ff94bc40SHeiko Schocher 290*ff94bc40SHeiko Schocher out: 291*ff94bc40SHeiko Schocher ubi_put_device(ubi); 292*ff94bc40SHeiko Schocher return count; 293*ff94bc40SHeiko Schocher } 294*ff94bc40SHeiko Schocher 295*ff94bc40SHeiko Schocher /* Write an UBI debugfs file */ 296*ff94bc40SHeiko Schocher static ssize_t dfs_file_write(struct file *file, const char __user *user_buf, 297*ff94bc40SHeiko Schocher size_t count, loff_t *ppos) 298*ff94bc40SHeiko Schocher { 299*ff94bc40SHeiko Schocher unsigned long ubi_num = (unsigned long)file->private_data; 300*ff94bc40SHeiko Schocher struct dentry *dent = file->f_path.dentry; 301*ff94bc40SHeiko Schocher struct ubi_device *ubi; 302*ff94bc40SHeiko Schocher struct ubi_debug_info *d; 303*ff94bc40SHeiko Schocher size_t buf_size; 304*ff94bc40SHeiko Schocher char buf[8]; 305*ff94bc40SHeiko Schocher int val; 306*ff94bc40SHeiko Schocher 307*ff94bc40SHeiko Schocher ubi = ubi_get_device(ubi_num); 308*ff94bc40SHeiko Schocher if (!ubi) 309*ff94bc40SHeiko Schocher return -ENODEV; 310*ff94bc40SHeiko Schocher d = &ubi->dbg; 311*ff94bc40SHeiko Schocher 312*ff94bc40SHeiko Schocher buf_size = min_t(size_t, count, (sizeof(buf) - 1)); 313*ff94bc40SHeiko Schocher if (copy_from_user(buf, user_buf, buf_size)) { 314*ff94bc40SHeiko Schocher count = -EFAULT; 315*ff94bc40SHeiko Schocher goto out; 316*ff94bc40SHeiko Schocher } 317*ff94bc40SHeiko Schocher 318*ff94bc40SHeiko Schocher if (buf[0] == '1') 319*ff94bc40SHeiko Schocher val = 1; 320*ff94bc40SHeiko Schocher else if (buf[0] == '0') 321*ff94bc40SHeiko Schocher val = 0; 322*ff94bc40SHeiko Schocher else { 323*ff94bc40SHeiko Schocher count = -EINVAL; 324*ff94bc40SHeiko Schocher goto out; 325*ff94bc40SHeiko Schocher } 326*ff94bc40SHeiko Schocher 327*ff94bc40SHeiko Schocher if (dent == d->dfs_chk_gen) 328*ff94bc40SHeiko Schocher d->chk_gen = val; 329*ff94bc40SHeiko Schocher else if (dent == d->dfs_chk_io) 330*ff94bc40SHeiko Schocher d->chk_io = val; 331*ff94bc40SHeiko Schocher else if (dent == d->dfs_disable_bgt) 332*ff94bc40SHeiko Schocher d->disable_bgt = val; 333*ff94bc40SHeiko Schocher else if (dent == d->dfs_emulate_bitflips) 334*ff94bc40SHeiko Schocher d->emulate_bitflips = val; 335*ff94bc40SHeiko Schocher else if (dent == d->dfs_emulate_io_failures) 336*ff94bc40SHeiko Schocher d->emulate_io_failures = val; 337*ff94bc40SHeiko Schocher else 338*ff94bc40SHeiko Schocher count = -EINVAL; 339*ff94bc40SHeiko Schocher 340*ff94bc40SHeiko Schocher out: 341*ff94bc40SHeiko Schocher ubi_put_device(ubi); 342*ff94bc40SHeiko Schocher return count; 343*ff94bc40SHeiko Schocher } 344*ff94bc40SHeiko Schocher 345*ff94bc40SHeiko Schocher /* File operations for all UBI debugfs files */ 346*ff94bc40SHeiko Schocher static const struct file_operations dfs_fops = { 347*ff94bc40SHeiko Schocher .read = dfs_file_read, 348*ff94bc40SHeiko Schocher .write = dfs_file_write, 349*ff94bc40SHeiko Schocher .open = simple_open, 350*ff94bc40SHeiko Schocher .llseek = no_llseek, 351*ff94bc40SHeiko Schocher .owner = THIS_MODULE, 352*ff94bc40SHeiko Schocher }; 353*ff94bc40SHeiko Schocher 354*ff94bc40SHeiko Schocher /** 355*ff94bc40SHeiko Schocher * ubi_debugfs_init_dev - initialize debugfs for an UBI device. 356*ff94bc40SHeiko Schocher * @ubi: UBI device description object 357*ff94bc40SHeiko Schocher * 358*ff94bc40SHeiko Schocher * This function creates all debugfs files for UBI device @ubi. Returns zero in 359*ff94bc40SHeiko Schocher * case of success and a negative error code in case of failure. 360*ff94bc40SHeiko Schocher */ 361*ff94bc40SHeiko Schocher int ubi_debugfs_init_dev(struct ubi_device *ubi) 362*ff94bc40SHeiko Schocher { 363*ff94bc40SHeiko Schocher int err, n; 364*ff94bc40SHeiko Schocher unsigned long ubi_num = ubi->ubi_num; 365*ff94bc40SHeiko Schocher const char *fname; 366*ff94bc40SHeiko Schocher struct dentry *dent; 367*ff94bc40SHeiko Schocher struct ubi_debug_info *d = &ubi->dbg; 368*ff94bc40SHeiko Schocher 369*ff94bc40SHeiko Schocher if (!IS_ENABLED(CONFIG_DEBUG_FS)) 370*ff94bc40SHeiko Schocher return 0; 371*ff94bc40SHeiko Schocher 372*ff94bc40SHeiko Schocher n = snprintf(d->dfs_dir_name, UBI_DFS_DIR_LEN + 1, UBI_DFS_DIR_NAME, 373*ff94bc40SHeiko Schocher ubi->ubi_num); 374*ff94bc40SHeiko Schocher if (n == UBI_DFS_DIR_LEN) { 375*ff94bc40SHeiko Schocher /* The array size is too small */ 376*ff94bc40SHeiko Schocher fname = UBI_DFS_DIR_NAME; 377*ff94bc40SHeiko Schocher dent = ERR_PTR(-EINVAL); 378*ff94bc40SHeiko Schocher goto out; 379*ff94bc40SHeiko Schocher } 380*ff94bc40SHeiko Schocher 381*ff94bc40SHeiko Schocher fname = d->dfs_dir_name; 382*ff94bc40SHeiko Schocher dent = debugfs_create_dir(fname, dfs_rootdir); 383*ff94bc40SHeiko Schocher if (IS_ERR_OR_NULL(dent)) 384*ff94bc40SHeiko Schocher goto out; 385*ff94bc40SHeiko Schocher d->dfs_dir = dent; 386*ff94bc40SHeiko Schocher 387*ff94bc40SHeiko Schocher fname = "chk_gen"; 388*ff94bc40SHeiko Schocher dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num, 389*ff94bc40SHeiko Schocher &dfs_fops); 390*ff94bc40SHeiko Schocher if (IS_ERR_OR_NULL(dent)) 391*ff94bc40SHeiko Schocher goto out_remove; 392*ff94bc40SHeiko Schocher d->dfs_chk_gen = dent; 393*ff94bc40SHeiko Schocher 394*ff94bc40SHeiko Schocher fname = "chk_io"; 395*ff94bc40SHeiko Schocher dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num, 396*ff94bc40SHeiko Schocher &dfs_fops); 397*ff94bc40SHeiko Schocher if (IS_ERR_OR_NULL(dent)) 398*ff94bc40SHeiko Schocher goto out_remove; 399*ff94bc40SHeiko Schocher d->dfs_chk_io = dent; 400*ff94bc40SHeiko Schocher 401*ff94bc40SHeiko Schocher fname = "tst_disable_bgt"; 402*ff94bc40SHeiko Schocher dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num, 403*ff94bc40SHeiko Schocher &dfs_fops); 404*ff94bc40SHeiko Schocher if (IS_ERR_OR_NULL(dent)) 405*ff94bc40SHeiko Schocher goto out_remove; 406*ff94bc40SHeiko Schocher d->dfs_disable_bgt = dent; 407*ff94bc40SHeiko Schocher 408*ff94bc40SHeiko Schocher fname = "tst_emulate_bitflips"; 409*ff94bc40SHeiko Schocher dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num, 410*ff94bc40SHeiko Schocher &dfs_fops); 411*ff94bc40SHeiko Schocher if (IS_ERR_OR_NULL(dent)) 412*ff94bc40SHeiko Schocher goto out_remove; 413*ff94bc40SHeiko Schocher d->dfs_emulate_bitflips = dent; 414*ff94bc40SHeiko Schocher 415*ff94bc40SHeiko Schocher fname = "tst_emulate_io_failures"; 416*ff94bc40SHeiko Schocher dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, (void *)ubi_num, 417*ff94bc40SHeiko Schocher &dfs_fops); 418*ff94bc40SHeiko Schocher if (IS_ERR_OR_NULL(dent)) 419*ff94bc40SHeiko Schocher goto out_remove; 420*ff94bc40SHeiko Schocher d->dfs_emulate_io_failures = dent; 421*ff94bc40SHeiko Schocher 422*ff94bc40SHeiko Schocher return 0; 423*ff94bc40SHeiko Schocher 424*ff94bc40SHeiko Schocher out_remove: 425*ff94bc40SHeiko Schocher debugfs_remove_recursive(d->dfs_dir); 426*ff94bc40SHeiko Schocher out: 427*ff94bc40SHeiko Schocher err = dent ? PTR_ERR(dent) : -ENODEV; 428*ff94bc40SHeiko Schocher ubi_err("cannot create \"%s\" debugfs file or directory, error %d\n", 429*ff94bc40SHeiko Schocher fname, err); 430*ff94bc40SHeiko Schocher return err; 431*ff94bc40SHeiko Schocher } 432*ff94bc40SHeiko Schocher 433*ff94bc40SHeiko Schocher /** 434*ff94bc40SHeiko Schocher * dbg_debug_exit_dev - free all debugfs files corresponding to device @ubi 435*ff94bc40SHeiko Schocher * @ubi: UBI device description object 436*ff94bc40SHeiko Schocher */ 437*ff94bc40SHeiko Schocher void ubi_debugfs_exit_dev(struct ubi_device *ubi) 438*ff94bc40SHeiko Schocher { 439*ff94bc40SHeiko Schocher if (IS_ENABLED(CONFIG_DEBUG_FS)) 440*ff94bc40SHeiko Schocher debugfs_remove_recursive(ubi->dbg.dfs_dir); 441*ff94bc40SHeiko Schocher } 442*ff94bc40SHeiko Schocher #else 443*ff94bc40SHeiko Schocher int ubi_debugfs_init(void) 444*ff94bc40SHeiko Schocher { 445*ff94bc40SHeiko Schocher return 0; 446*ff94bc40SHeiko Schocher } 447*ff94bc40SHeiko Schocher 448*ff94bc40SHeiko Schocher void ubi_debugfs_exit(void) 449*ff94bc40SHeiko Schocher { 450*ff94bc40SHeiko Schocher } 451*ff94bc40SHeiko Schocher 452*ff94bc40SHeiko Schocher int ubi_debugfs_init_dev(struct ubi_device *ubi) 453*ff94bc40SHeiko Schocher { 454*ff94bc40SHeiko Schocher return 0; 455*ff94bc40SHeiko Schocher } 456*ff94bc40SHeiko Schocher 457*ff94bc40SHeiko Schocher void ubi_debugfs_exit_dev(struct ubi_device *ubi) 458*ff94bc40SHeiko Schocher { 459*ff94bc40SHeiko Schocher } 460*ff94bc40SHeiko Schocher #endif 461