Dear Guennadi Liakhovetski, In message <[EMAIL PROTECTED]> you wrote: > > --- a/tools/env/fw_env.c > +++ b/tools/env/fw_env.c > @@ -44,6 +44,12 @@ > #define CMD_GETENV "fw_printenv" > #define CMD_SETENV "fw_setenv" > > +#define min(x, y) ({ \ > + typeof(x) _min1 = (x); \ > + typeof(y) _min2 = (y); \ > + (void) (&_min1 == &_min2); \
What does this do? > + _min1 < _min2 ? _min1 : _min2; }) > typedef struct envdev_s { > char devname[16]; /* Device name */ > ulong devoff; /* Device offset */ > @@ -413,179 +419,290 @@ int fw_setenv (int argc, char *argv[]) > return 0; > } > > +static int flash_bad_block (int dev, int fd, struct mtd_info_user *mtdinfo, > + loff_t *blockstart, size_t blocklen) > +{ > + if (mtdinfo->type == MTD_NANDFLASH) { > + int badblock = ioctl (fd, MEMGETBADBLOCK, blockstart); > + > + if (badblock < 0) { > + perror ("Cannot read bad block mark"); It would be probably helpful to print the block address. > + return badblock; > + } > + > + if (badblock) { > + fprintf (stderr, "Bad block at 0x%llx, " > + "skipping\n", *blockstart); > + *blockstart += blocklen; > + return badblock; > + } > + } > + > + return 0; > +} > + > +/* > + * We are called with count == 0 for backing up as much data from the > + * range as possible > + */ Backing up? > static int flash_read_buf (int dev, int fd, void *buf, size_t count, > - off_t offset) > + off_t offset, size_t range) > { > + struct mtd_info_user mtdinfo; > + size_t blocklen, processed = 0; > + size_t readlen = count ? : range; > + off_t erase_offset, block_seek; > + loff_t blockstart; > int rc; > + int backup_mode = !count; backup_mode ? I think there should be an explanation what exactly you are trying to do. > - rc = lseek (fd, offset, SEEK_SET); > - if (rc == -1) { > - fprintf (stderr, > - "seek error on %s: %s\n", > - DEVNAME (dev), strerror (errno)); > + if (!count) > + count = range; > + > + rc = ioctl (fd, MEMGETINFO, &mtdinfo); > + if (rc < 0) { > + perror ("Cannot get MTD information"); > return rc; > } Did you verify that the code still builds when MTD_OLD is set? > > - rc = read (fd, buf, count); > - if (rc != count) { > - fprintf (stderr, > - "Read error on %s: %s\n", > - DEVNAME (dev), strerror (errno)); > - return -1; > + /* Erase sector size is always a power of 2 */ > + erase_offset = offset & ~(mtdinfo.erasesize - 1); Please explain this logic. > + blockstart = erase_offset; > + /* Offset inside a block */ > + block_seek = offset - erase_offset; > + > + if (mtdinfo.type == MTD_NANDFLASH) { > + /* > + * NAND: calculate which blocks we are reading. We have > + * to read one block at a time to skip bad blocks. > + */ > + blocklen = mtdinfo.erasesize; > + /* Limit to one block for the first read */ > + if (readlen > blocklen - block_seek) > + readlen = blocklen - block_seek; > + } else { > + blocklen = 0; > } > > - return rc; > + /* This only runs once for NOR flash */ > + while (processed < count) { > + rc = flash_bad_block (dev, fd, &mtdinfo, &blockstart, blocklen); But - NOR flash does not have bad block, so all of this is not needed at all? > + if (rc < 0) > + return -1; > + else if (blockstart + block_seek + readlen > offset + range) { I do not understand what you are doing here. Comment? > + /* End of range is reached */ > + if (backup_mode) { > + return processed; > + } else { > + fprintf (stderr, > + "Too few good blocks within range\n"); > + return -1; > + } > + } else if (rc) > + continue; > + > + /* > + * If a block is bad, we retry in the next block > + * at the same offset - see common/env_nand.c:: > + * writeenv() > + */ > + lseek (fd, blockstart + block_seek, SEEK_SET); I don't see that you remember which blocks were bad. Does that mean that you will attemopt to write the environment to known bad blocks? Sonds not like a good idea to me. > + rc = read (fd, buf + processed, readlen); > + if (rc != readlen) { > + fprintf (stderr, > + "Read error on %s: %s\n", > + DEVNAME (dev), strerror (errno)); > + return -1; > + } > + processed += readlen; > + readlen = min(blocklen, count - processed); > + block_seek = 0; > + blockstart += blocklen; > + } > + > + return processed; > } > > -static int flash_write (void) > +static int flash_write_buf (int dev, int fd, void *buf, size_t count, > + off_t offset) > { > - int fd_current, fd_target, rc, dev_target; > - erase_info_t erase_current = {}, erase_target; > char *data = NULL; > - off_t erase_offset; > - struct mtd_info_user mtdinfo_target; > + erase_info_t erase; > + struct mtd_info_user mtdinfo; > + size_t blocklen, erase_len, processed = 0; > + size_t writelen, write_total = DEVESIZE (dev); > + off_t erase_offset, block_seek; > + loff_t blockstart; > + int rc; > > - /* dev_current: fd_current, erase_current */ > - if ((fd_current = open (DEVNAME (dev_current), O_RDWR)) < 0) { > - fprintf (stderr, > - "Can't open %s: %s\n", > - DEVNAME (dev_current), strerror (errno)); > + rc = ioctl (fd, MEMGETINFO, &mtdinfo); > + if (rc < 0) { > + perror ("Cannot get MTD information"); > return -1; > } > > - if (HaveRedundEnv) { > - /* switch to next partition for writing */ > - dev_target = !dev_current; > - /* dev_target: fd_target, erase_target */ > - if ((fd_target = open (DEVNAME (dev_target), O_RDWR)) < 0) { > - fprintf (stderr, > - "Can't open %s: %s\n", > - DEVNAME (dev_target), > - strerror (errno)); > - return -1; > - } > - } else { > - dev_target = dev_current; > - fd_target = fd_current; > - } > + /* Erase sector size is always a power of 2 */ > + erase_offset = offset & ~(mtdinfo.erasesize - 1); > + /* Maximum area we may use */ > + erase_len = (offset - erase_offset + DEVESIZE (dev) + > + mtdinfo.erasesize - 1) & ~(mtdinfo.erasesize - 1); > + > + blockstart = erase_offset; > + /* Offset inside a block */ > + block_seek = offset - erase_offset; > > /* > * Support environment anywhere within erase sectors: read out the > * complete area to be erased, replace the environment image, write > * the whole block back again. > */ > - if (DEVESIZE (dev_target) > CFG_ENV_SIZE) { > - data = malloc (DEVESIZE (dev_target)); > + if (erase_len > DEVESIZE (dev)) { > + data = malloc (erase_len); > if (!data) { > fprintf (stderr, > - "Cannot malloc %lu bytes: %s\n", > - DEVESIZE (dev_target), > - strerror (errno)); > + "Cannot malloc %u bytes: %s\n", > + erase_len, strerror (errno)); > return -1; > } > > - rc = ioctl (fd_target, MEMGETINFO, &mtdinfo_target); > - if (rc < 0) { > - perror ("Cannot get MTD information"); > + /* > + * This is different from a normal read. We have to read as much > + * as we can from a certain area, and it should be at least X > + * bytes, instead of having to read a fixed number of bytes as > + * usual. This also tells us how much data "fits" in the good > + * blocks in the area. > + */ > + write_total = flash_read_buf (dev, fd, data, 0, > + erase_offset, erase_len); > + if (write_total < block_seek + CFG_ENV_SIZE) Ummm...this is flash_write_buf(), and we start reading data? Please explain your code. Best regards, Wolfgang Denk -- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: [EMAIL PROTECTED] It would seem that evil retreats when forcibly confronted -- Yarnek of Excalbia, "The Savage Curtain", stardate 5906.5 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot