]> git.sur5r.net Git - u-boot/blobdiff - drivers/mtd/ubi/eba.c
mtd: nand: mxs_nand: add use_minimum_ecc to struct
[u-boot] / drivers / mtd / ubi / eba.c
index 3c2a7e69e1841aa587b6fd6a2e7bf2d4f3f7650b..809782b3726d34fa67364c79ba20c14b9ebfdb04 100644 (file)
@@ -1,8 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Copyright (c) International Business Machines Corp., 2006
  *
- * SPDX-License-Identifier:    GPL-2.0+
- *
  * Author: Artem Bityutskiy (Битюцкий Артём)
  */
 
@@ -29,7 +28,6 @@
  * 64 bits is enough to never overflow.
  */
 
-#define __UBOOT__
 #ifndef __UBOOT__
 #include <linux/slab.h>
 #include <linux/crc32.h>
@@ -334,9 +332,9 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
 
        dbg_eba("erase LEB %d:%d, PEB %d", vol_id, lnum, pnum);
 
-       down_read(&ubi->fm_sem);
+       down_read(&ubi->fm_eba_sem);
        vol->eba_tbl[lnum] = UBI_LEB_UNMAPPED;
-       up_read(&ubi->fm_sem);
+       up_read(&ubi->fm_eba_sem);
        err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 0);
 
 out_unlock:
@@ -416,11 +414,13 @@ retry:
                                 */
                                if (err == UBI_IO_BAD_HDR_EBADMSG ||
                                    err == UBI_IO_BAD_HDR) {
-                                       ubi_warn("corrupted VID header at PEB %d, LEB %d:%d",
+                                       ubi_warn(ubi, "corrupted VID header at PEB %d, LEB %d:%d",
                                                 pnum, vol_id, lnum);
                                        err = -EBADMSG;
-                               } else
+                               } else {
+                                       err = -EINVAL;
                                        ubi_ro_mode(ubi);
+                               }
                        }
                        goto out_free;
                } else if (err == UBI_IO_BITFLIPS)
@@ -435,15 +435,14 @@ retry:
 
        err = ubi_io_read_data(ubi, buf, pnum, offset, len);
        if (err) {
-               if (err == UBI_IO_BITFLIPS) {
+               if (err == UBI_IO_BITFLIPS)
                        scrub = 1;
-                       err = 0;
-               } else if (mtd_is_eccerr(err)) {
+               else if (mtd_is_eccerr(err)) {
                        if (vol->vol_type == UBI_DYNAMIC_VOLUME)
                                goto out_unlock;
                        scrub = 1;
                        if (!check) {
-                               ubi_msg("force data checking");
+                               ubi_msg(ubi, "force data checking");
                                check = 1;
                                goto retry;
                        }
@@ -454,7 +453,7 @@ retry:
        if (check) {
                uint32_t crc1 = crc32(UBI_CRC32_INIT, buf, len);
                if (crc1 != crc) {
-                       ubi_warn("CRC error: calculated %#08x, must be %#08x",
+                       ubi_warn(ubi, "CRC error: calculated %#08x, must be %#08x",
                                 crc1, crc);
                        err = -EBADMSG;
                        goto out_unlock;
@@ -474,6 +473,63 @@ out_unlock:
        return err;
 }
 
+#ifndef __UBOOT__
+/**
+ * ubi_eba_read_leb_sg - read data into a scatter gather list.
+ * @ubi: UBI device description object
+ * @vol: volume description object
+ * @lnum: logical eraseblock number
+ * @sgl: UBI scatter gather list to store the read data
+ * @offset: offset from where to read
+ * @len: how many bytes to read
+ * @check: data CRC check flag
+ *
+ * This function works exactly like ubi_eba_read_leb(). But instead of
+ * storing the read data into a buffer it writes to an UBI scatter gather
+ * list.
+ */
+int ubi_eba_read_leb_sg(struct ubi_device *ubi, struct ubi_volume *vol,
+                       struct ubi_sgl *sgl, int lnum, int offset, int len,
+                       int check)
+{
+       int to_read;
+       int ret;
+       struct scatterlist *sg;
+
+       for (;;) {
+               ubi_assert(sgl->list_pos < UBI_MAX_SG_COUNT);
+               sg = &sgl->sg[sgl->list_pos];
+               if (len < sg->length - sgl->page_pos)
+                       to_read = len;
+               else
+                       to_read = sg->length - sgl->page_pos;
+
+               ret = ubi_eba_read_leb(ubi, vol, lnum,
+                                      sg_virt(sg) + sgl->page_pos, offset,
+                                      to_read, check);
+               if (ret < 0)
+                       return ret;
+
+               offset += to_read;
+               len -= to_read;
+               if (!len) {
+                       sgl->page_pos += to_read;
+                       if (sgl->page_pos == sg->length) {
+                               sgl->list_pos++;
+                               sgl->page_pos = 0;
+                       }
+
+                       break;
+               }
+
+               sgl->list_pos++;
+               sgl->page_pos = 0;
+       }
+
+       return ret;
+}
+#endif
+
 /**
  * recover_peb - recover from write failure.
  * @ubi: UBI device description object
@@ -505,22 +561,27 @@ retry:
        new_pnum = ubi_wl_get_peb(ubi);
        if (new_pnum < 0) {
                ubi_free_vid_hdr(ubi, vid_hdr);
+               up_read(&ubi->fm_eba_sem);
                return new_pnum;
        }
 
-       ubi_msg("recover PEB %d, move data to PEB %d", pnum, new_pnum);
+       ubi_msg(ubi, "recover PEB %d, move data to PEB %d",
+               pnum, new_pnum);
 
        err = ubi_io_read_vid_hdr(ubi, pnum, vid_hdr, 1);
        if (err && err != UBI_IO_BITFLIPS) {
                if (err > 0)
                        err = -EIO;
+               up_read(&ubi->fm_eba_sem);
                goto out_put;
        }
 
        vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
        err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr);
-       if (err)
+       if (err) {
+               up_read(&ubi->fm_eba_sem);
                goto write_error;
+       }
 
        data_size = offset + len;
        mutex_lock(&ubi->buf_mutex);
@@ -529,8 +590,10 @@ retry:
        /* Read everything before the area where the write failure happened */
        if (offset > 0) {
                err = ubi_io_read_data(ubi, ubi->peb_buf, pnum, 0, offset);
-               if (err && err != UBI_IO_BITFLIPS)
+               if (err && err != UBI_IO_BITFLIPS) {
+                       up_read(&ubi->fm_eba_sem);
                        goto out_unlock;
+               }
        }
 
        memcpy(ubi->peb_buf + offset, buf, len);
@@ -538,18 +601,18 @@ retry:
        err = ubi_io_write_data(ubi, ubi->peb_buf, new_pnum, 0, data_size);
        if (err) {
                mutex_unlock(&ubi->buf_mutex);
+               up_read(&ubi->fm_eba_sem);
                goto write_error;
        }
 
        mutex_unlock(&ubi->buf_mutex);
        ubi_free_vid_hdr(ubi, vid_hdr);
 
-       down_read(&ubi->fm_sem);
        vol->eba_tbl[lnum] = new_pnum;
-       up_read(&ubi->fm_sem);
+       up_read(&ubi->fm_eba_sem);
        ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
 
-       ubi_msg("data was successfully recovered");
+       ubi_msg(ubi, "data was successfully recovered");
        return 0;
 
 out_unlock:
@@ -564,13 +627,13 @@ write_error:
         * Bad luck? This physical eraseblock is bad too? Crud. Let's try to
         * get another one.
         */
-       ubi_warn("failed to write to PEB %d", new_pnum);
+       ubi_warn(ubi, "failed to write to PEB %d", new_pnum);
        ubi_wl_put_peb(ubi, vol_id, lnum, new_pnum, 1);
        if (++tries > UBI_IO_RETRIES) {
                ubi_free_vid_hdr(ubi, vid_hdr);
                return err;
        }
-       ubi_msg("try again");
+       ubi_msg(ubi, "try again");
        goto retry;
 }
 
@@ -608,7 +671,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
 
                err = ubi_io_write_data(ubi, buf, pnum, offset, len);
                if (err) {
-                       ubi_warn("failed to write data to PEB %d", pnum);
+                       ubi_warn(ubi, "failed to write data to PEB %d", pnum);
                        if (err == -EIO && ubi->bad_allowed)
                                err = recover_peb(ubi, pnum, vol_id, lnum, buf,
                                                  offset, len);
@@ -641,6 +704,7 @@ retry:
        if (pnum < 0) {
                ubi_free_vid_hdr(ubi, vid_hdr);
                leb_write_unlock(ubi, vol_id, lnum);
+               up_read(&ubi->fm_eba_sem);
                return pnum;
        }
 
@@ -649,23 +713,24 @@ retry:
 
        err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr);
        if (err) {
-               ubi_warn("failed to write VID header to LEB %d:%d, PEB %d",
+               ubi_warn(ubi, "failed to write VID header to LEB %d:%d, PEB %d",
                         vol_id, lnum, pnum);
+               up_read(&ubi->fm_eba_sem);
                goto write_error;
        }
 
        if (len) {
                err = ubi_io_write_data(ubi, buf, pnum, offset, len);
                if (err) {
-                       ubi_warn("failed to write %d bytes at offset %d of LEB %d:%d, PEB %d",
+                       ubi_warn(ubi, "failed to write %d bytes at offset %d of LEB %d:%d, PEB %d",
                                 len, offset, vol_id, lnum, pnum);
+                       up_read(&ubi->fm_eba_sem);
                        goto write_error;
                }
        }
 
-       down_read(&ubi->fm_sem);
        vol->eba_tbl[lnum] = pnum;
-       up_read(&ubi->fm_sem);
+       up_read(&ubi->fm_eba_sem);
 
        leb_write_unlock(ubi, vol_id, lnum);
        ubi_free_vid_hdr(ubi, vid_hdr);
@@ -693,7 +758,7 @@ write_error:
        }
 
        vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
-       ubi_msg("try another PEB");
+       ubi_msg(ubi, "try another PEB");
        goto retry;
 }
 
@@ -762,6 +827,7 @@ retry:
        if (pnum < 0) {
                ubi_free_vid_hdr(ubi, vid_hdr);
                leb_write_unlock(ubi, vol_id, lnum);
+               up_read(&ubi->fm_eba_sem);
                return pnum;
        }
 
@@ -770,22 +836,23 @@ retry:
 
        err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr);
        if (err) {
-               ubi_warn("failed to write VID header to LEB %d:%d, PEB %d",
+               ubi_warn(ubi, "failed to write VID header to LEB %d:%d, PEB %d",
                         vol_id, lnum, pnum);
+               up_read(&ubi->fm_eba_sem);
                goto write_error;
        }
 
        err = ubi_io_write_data(ubi, buf, pnum, 0, len);
        if (err) {
-               ubi_warn("failed to write %d bytes of data to PEB %d",
+               ubi_warn(ubi, "failed to write %d bytes of data to PEB %d",
                         len, pnum);
+               up_read(&ubi->fm_eba_sem);
                goto write_error;
        }
 
        ubi_assert(vol->eba_tbl[lnum] < 0);
-       down_read(&ubi->fm_sem);
        vol->eba_tbl[lnum] = pnum;
-       up_read(&ubi->fm_sem);
+       up_read(&ubi->fm_eba_sem);
 
        leb_write_unlock(ubi, vol_id, lnum);
        ubi_free_vid_hdr(ubi, vid_hdr);
@@ -813,7 +880,7 @@ write_error:
        }
 
        vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
-       ubi_msg("try another PEB");
+       ubi_msg(ubi, "try another PEB");
        goto retry;
 }
 
@@ -837,7 +904,7 @@ write_error:
 int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
                              int lnum, const void *buf, int len)
 {
-       int err, pnum, tries = 0, vol_id = vol->vol_id;
+       int err, pnum, old_pnum, tries = 0, vol_id = vol->vol_id;
        struct ubi_vid_hdr *vid_hdr;
        uint32_t crc;
 
@@ -880,6 +947,7 @@ retry:
        pnum = ubi_wl_get_peb(ubi);
        if (pnum < 0) {
                err = pnum;
+               up_read(&ubi->fm_eba_sem);
                goto out_leb_unlock;
        }
 
@@ -888,28 +956,30 @@ retry:
 
        err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr);
        if (err) {
-               ubi_warn("failed to write VID header to LEB %d:%d, PEB %d",
+               ubi_warn(ubi, "failed to write VID header to LEB %d:%d, PEB %d",
                         vol_id, lnum, pnum);
+               up_read(&ubi->fm_eba_sem);
                goto write_error;
        }
 
        err = ubi_io_write_data(ubi, buf, pnum, 0, len);
        if (err) {
-               ubi_warn("failed to write %d bytes of data to PEB %d",
+               ubi_warn(ubi, "failed to write %d bytes of data to PEB %d",
                         len, pnum);
+               up_read(&ubi->fm_eba_sem);
                goto write_error;
        }
 
-       if (vol->eba_tbl[lnum] >= 0) {
-               err = ubi_wl_put_peb(ubi, vol_id, lnum, vol->eba_tbl[lnum], 0);
+       old_pnum = vol->eba_tbl[lnum];
+       vol->eba_tbl[lnum] = pnum;
+       up_read(&ubi->fm_eba_sem);
+
+       if (old_pnum >= 0) {
+               err = ubi_wl_put_peb(ubi, vol_id, lnum, old_pnum, 0);
                if (err)
                        goto out_leb_unlock;
        }
 
-       down_read(&ubi->fm_sem);
-       vol->eba_tbl[lnum] = pnum;
-       up_read(&ubi->fm_sem);
-
 out_leb_unlock:
        leb_write_unlock(ubi, vol_id, lnum);
 out_mutex:
@@ -935,7 +1005,7 @@ write_error:
        }
 
        vid_hdr->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
-       ubi_msg("try another PEB");
+       ubi_msg(ubi, "try another PEB");
        goto retry;
 }
 
@@ -1058,7 +1128,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
        dbg_wl("read %d bytes of data", aldata_size);
        err = ubi_io_read_data(ubi, ubi->peb_buf, from, 0, aldata_size);
        if (err && err != UBI_IO_BITFLIPS) {
-               ubi_warn("error %d while reading data from PEB %d",
+               ubi_warn(ubi, "error %d while reading data from PEB %d",
                         err, from);
                err = MOVE_SOURCE_RD_ERR;
                goto out_unlock_buf;
@@ -1108,7 +1178,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
        err = ubi_io_read_vid_hdr(ubi, to, vid_hdr, 1);
        if (err) {
                if (err != UBI_IO_BITFLIPS) {
-                       ubi_warn("error %d while reading VID header back from PEB %d",
+                       ubi_warn(ubi, "error %d while reading VID header back from PEB %d",
                                 err, to);
                        if (is_error_sane(err))
                                err = MOVE_TARGET_RD_ERR;
@@ -1135,7 +1205,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
                err = ubi_io_read_data(ubi, ubi->peb_buf, to, 0, aldata_size);
                if (err) {
                        if (err != UBI_IO_BITFLIPS) {
-                               ubi_warn("error %d while reading data back from PEB %d",
+                               ubi_warn(ubi, "error %d while reading data back from PEB %d",
                                         err, to);
                                if (is_error_sane(err))
                                        err = MOVE_TARGET_RD_ERR;
@@ -1147,7 +1217,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
                cond_resched();
 
                if (crc != crc32(UBI_CRC32_INIT, ubi->peb_buf, data_size)) {
-                       ubi_warn("read data back from PEB %d and it is different",
+                       ubi_warn(ubi, "read data back from PEB %d and it is different",
                                 to);
                        err = -EINVAL;
                        goto out_unlock_buf;
@@ -1155,9 +1225,9 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
        }
 
        ubi_assert(vol->eba_tbl[lnum] == from);
-       down_read(&ubi->fm_sem);
+       down_read(&ubi->fm_eba_sem);
        vol->eba_tbl[lnum] = to;
-       up_read(&ubi->fm_sem);
+       up_read(&ubi->fm_eba_sem);
 
 out_unlock_buf:
        mutex_unlock(&ubi->buf_mutex);
@@ -1200,10 +1270,10 @@ static void print_rsvd_warning(struct ubi_device *ubi,
                        return;
        }
 
-       ubi_warn("cannot reserve enough PEBs for bad PEB handling, reserved %d, need %d",
+       ubi_warn(ubi, "cannot reserve enough PEBs for bad PEB handling, reserved %d, need %d",
                 ubi->beb_rsvd_pebs, ubi->beb_rsvd_level);
        if (ubi->corr_peb_count)
-               ubi_warn("%d PEBs are corrupted and not used",
+               ubi_warn(ubi, "%d PEBs are corrupted and not used",
                         ubi->corr_peb_count);
 }
 
@@ -1281,7 +1351,7 @@ int self_check_eba(struct ubi_device *ubi, struct ubi_attach_info *ai_fastmap,
                                        fm_eba[i][j] == UBI_LEB_UNMAPPED)
                                        continue;
 
-                               ubi_err("LEB:%i:%i is PEB:%i instead of %i!",
+                               ubi_err(ubi, "LEB:%i:%i is PEB:%i instead of %i!",
                                        vol->vol_id, i, fm_eba[i][j],
                                        scan_eba[i][j]);
                                ubi_assert(0);
@@ -1356,15 +1426,16 @@ int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
                                 * during re-size.
                                 */
                                ubi_move_aeb_to_list(av, aeb, &ai->erase);
-                       vol->eba_tbl[aeb->lnum] = aeb->pnum;
+                       else
+                               vol->eba_tbl[aeb->lnum] = aeb->pnum;
                }
        }
 
        if (ubi->avail_pebs < EBA_RESERVED_PEBS) {
-               ubi_err("no enough physical eraseblocks (%d, need %d)",
+               ubi_err(ubi, "no enough physical eraseblocks (%d, need %d)",
                        ubi->avail_pebs, EBA_RESERVED_PEBS);
                if (ubi->corr_peb_count)
-                       ubi_err("%d PEBs are corrupted and not used",
+                       ubi_err(ubi, "%d PEBs are corrupted and not used",
                                ubi->corr_peb_count);
                err = -ENOSPC;
                goto out_free;