Getting EINVAL when trying to write to mtd device
Asked Answered
S

2

1

I am referring to the code in this answer. I added error handling though. The open() erase and the read() all perform without error and the 20 bytes that I read all are 0xff. However, when trying to write the 20 bytes from the data[] array, I get an EINVAL errorcode from the write() function. What could be the cause of the problem? I did erase the memory before trying to write...

Saurian answered 19/6, 2014 at 8:37 Comment(3)
Can you give some more information about the system you are attempting to do this on?Clergy
It's a linux kernel 3.6.9 on a custom board with an ARM Cortex-A5 and 128MB of NAND Flash.Saurian
That answer explains possible causes for EINVAL - have you eliminated all of those reasons?Brander
D
1

I have seen your original post. I have the same problem recently, and I found that the write size is important.

mtd_info_t(struct mtd_info_user) have a variable named writesize (reference: https://elixir.bootlin.com/linux/v3.2/source/include/mtd/mtd-abi.h#L125)

struct mtd_info_user {
    __u8 type;
    __u32 flags;
    __u32 size; /* Total size of the MTD */
    __u32 erasesize;
    __u32 writesize;
    __u32 oobsize;  /* Amount of OOB data per block (e.g. 16) */
    __u64 padding;  /* Old obsolete field; do not use */
};

when write to the mtd, should notice writesize

#include <fcntl.h>
#include <mtd/mtd-user.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <sys/ioctl.h>

int main(){
    mtd_info_t mtd_info;           // the MTD structure
    erase_info_t ei;               // the erase block structure
    int i;

    unsigned char read_buf[20] = {0x00};                // empty array for reading

    int fd = open("/dev/mtd0", O_RDWR); // open the mtd device for reading and 
                                        // writing. Note you want mtd0 not mtdblock0
                                        // also you probably need to open permissions
                                        // to the dev (sudo chmod 777 /dev/mtd0)

    ioctl(fd, MEMGETINFO, &mtd_info);   // get the device info

    // dump it for a sanity check, should match what's in /proc/mtd
    printf("MTD Type: %x\nMTD total size: %x(hex) bytes\nMTD erase size: %x(hex) bytes\nMTD write size: %x(hex) bytes\n",
        mtd_info.type, mtd_info.size, mtd_info.erasesize, mtd_info.writesize);

    ei.length = mtd_info.erasesize;   //set the erase block size
    for(ei.start = 0; ei.start < mtd_info.size; ei.start += ei.length)
    {
        ioctl(fd, MEMUNLOCK, &ei);
        // printf("Eraseing Block %#x\n", ei.start); // show the blocks erasing
                                                  // warning, this prints a lot!
        ioctl(fd, MEMERASE, &ei);
    }    

    lseek(fd, 0, SEEK_SET);               // go to the first block
    read(fd, read_buf, sizeof(read_buf)); // read 20 bytes

    // sanity check, should be all 0xFF if erase worked
    for(i = 0; i<20; i++)
        printf("buf[%d] = 0x%02x\n", i, (unsigned int)read_buf[i]);

    /**********************************************************
     *   important part!                                      *
     *   notice the size of data array is mtd_info.writesize  *
     **********************************************************/
    uint32_t write_size = mtd_info.writesize;
    unsigned char data[write_size];//write 0
    bzero(data, write_size);

    lseek(fd, 0, SEEK_SET);        // go back to first block's start
    write(fd, data, sizeof(data)); // write our message

    lseek(fd, 0, SEEK_SET);              // go back to first block's start
    read(fd, read_buf, sizeof(read_buf));// read the data

    // sanity check, now you see the message we wrote!    
    for(i = 0; i<20; i++)
        printf("buf[%d] = 0x%02x\n", i, (unsigned int)read_buf[i]);

    close(fd);
    return 0;
}

Hope it can help

Diantha answered 22/5, 2018 at 2:14 Comment(0)
C
0

From ./drivers/mtd/nand/nand_base.c

#define NOTALIGNED(x) ((x & (chip->subpagesize - 1)) != 0)

This is the check performed by driver:

/* Reject writes, which are not page aligned */
if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
    pr_notice("%s: attempt to write non page aligned data\n",__func__);
return -EINVAL;
}

Both the address you are starting the write and and length of the buffer you are writing must satisfy the macro condition(to be multiple of the subpage size).

Cloudburst answered 25/8, 2020 at 12:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.