*
  */
 
+static unsigned int reliable_mode = 0;
+module_param(reliable_mode, uint, 0);
+MODULE_PARM_DESC(reliable_mode, "Set the docg3 mode (0=normal MLC, 1=fast, "
+                "2=reliable) : MLC normal operations are in normal mode");
+
 /**
  * struct docg3_oobinfo - DiskOnChip G3 OOB layout
  * @eccbytes: 8 bytes are used (1 for Hamming ECC, 7 for BCH ECC)
 }
 
 /**
- * doc_set_data_mode - Sets the flash to reliable data mode
+ * doc_set_data_mode - Sets the flash to normal or reliable data mode
  * @docg3: the device
  *
  * The reliable data mode is a bit slower than the fast mode, but less errors
  * occur.  Entering the reliable mode cannot be done without entering the fast
  * mode first.
+ *
+ * In reliable mode, pages 2*n and 2*n+1 are clones. Writing to page 0 of blocks
+ * (4,5) make the hardware write also to page 1 of blocks blocks(4,5). Reading
+ * from page 0 of blocks (4,5) or from page 1 of blocks (4,5) gives the same
+ * result, which is a logical and between bytes from page 0 and page 1 (which is
+ * consistent with the fact that writing to a page is _clearing_ bits of that
+ * page).
  */
 static void doc_set_reliable_mode(struct docg3 *docg3)
 {
-       doc_dbg("doc_set_reliable_mode()\n");
-       doc_flash_sequence(docg3, DOC_SEQ_SET_MODE);
-       doc_flash_command(docg3, DOC_CMD_FAST_MODE);
-       doc_flash_command(docg3, DOC_CMD_RELIABLE_MODE);
+       static char *strmode[] = { "normal", "fast", "reliable", "invalid" };
+
+       doc_dbg("doc_set_reliable_mode(%s)\n", strmode[docg3->reliable]);
+       switch (docg3->reliable) {
+       case 0:
+               break;
+       case 1:
+               doc_flash_sequence(docg3, DOC_SEQ_SET_FASTMODE);
+               doc_flash_command(docg3, DOC_CMD_FAST_MODE);
+               break;
+       case 2:
+               doc_flash_sequence(docg3, DOC_SEQ_SET_RELIABLEMODE);
+               doc_flash_command(docg3, DOC_CMD_FAST_MODE);
+               doc_flash_command(docg3, DOC_CMD_RELIABLE_MODE);
+               break;
+       default:
+               doc_err("doc_set_reliable_mode(): invalid mode\n");
+               break;
+       }
        doc_delay(docg3, 2);
 }
 
  * @block1: second plane block index calculated
  * @page: page calculated
  * @ofs: offset in page
+ * @reliable: 0 if docg3 in normal mode, 1 if docg3 in fast mode, 2 if docg3 in
+ * reliable mode.
+ *
+ * The calculation is based on the reliable/normal mode. In normal mode, the 64
+ * pages of a block are available. In reliable mode, as pages 2*n and 2*n+1 are
+ * clones, only 32 pages per block are available.
  */
 static void calc_block_sector(loff_t from, int *block0, int *block1, int *page,
-                             int *ofs)
+                             int *ofs, int reliable)
 {
-       uint sector;
+       uint sector, pages_biblock;
+
+       pages_biblock = DOC_LAYOUT_PAGES_PER_BLOCK * DOC_LAYOUT_NBPLANES;
+       if (reliable == 1 || reliable == 2)
+               pages_biblock /= 2;
 
        sector = from / DOC_LAYOUT_PAGE_SIZE;
-       *block0 = sector / (DOC_LAYOUT_PAGES_PER_BLOCK * DOC_LAYOUT_NBPLANES)
-               * DOC_LAYOUT_NBPLANES;
+       *block0 = sector / pages_biblock * DOC_LAYOUT_NBPLANES;
        *block1 = *block0 + 1;
-       *page = sector % (DOC_LAYOUT_PAGES_PER_BLOCK * DOC_LAYOUT_NBPLANES);
+       *page = sector % pages_biblock;
        *page /= DOC_LAYOUT_NBPLANES;
+       if (reliable == 1 || reliable == 2)
+               *page *= 2;
        if (sector % 2)
                *ofs = DOC_LAYOUT_PAGE_OOB_SIZE;
        else
                return -EINVAL;
 
        ret = -EINVAL;
-       calc_block_sector(from + len, &block0, &block1, &page, &ofs);
+       calc_block_sector(from + len, &block0, &block1, &page, &ofs,
+                         docg3->reliable);
        if (block1 > docg3->max_block)
                goto err;
 
        ops->retlen = 0;
        ret = 0;
        while (!ret && (len > 0 || ooblen > 0)) {
-               calc_block_sector(from, &block0, &block1, &page, &ofs);
+               calc_block_sector(from, &block0, &block1, &page, &ofs,
+                       docg3->reliable);
                nbdata = min_t(size_t, len, (size_t)DOC_LAYOUT_PAGE_SIZE);
                nboob = min_t(size_t, ooblen, (size_t)DOC_LAYOUT_OOB_SIZE);
                ret = doc_read_page_prepare(docg3, block0, block1, page, ofs);
        struct docg3 *docg3 = mtd->priv;
        int block0, block1, page, ofs, is_good;
 
-       calc_block_sector(from, &block0, &block1, &page, &ofs);
+       calc_block_sector(from, &block0, &block1, &page, &ofs,
+               docg3->reliable);
        doc_dbg("doc_block_isbad(from=%lld) => block=(%d,%d), page=%d, ofs=%d\n",
                from, block0, block1, page, ofs);
 
        doc_dbg("doc_get_erase_count(from=%lld, buf=%p)\n", from, buf);
        if (from % DOC_LAYOUT_PAGE_SIZE)
                return -EINVAL;
-       calc_block_sector(from, &block0, &block1, &page, &ofs);
+       calc_block_sector(from, &block0, &block1, &page, &ofs, docg3->reliable);
        if (block1 > docg3->max_block)
                return -EINVAL;
 
        doc_set_device_id(docg3, docg3->device_id);
 
        info->state = MTD_ERASE_PENDING;
-       calc_block_sector(info->addr + info->len,
-                         &block0, &block1, &page, &ofs);
+       calc_block_sector(info->addr + info->len, &block0, &block1, &page,
+                         &ofs, docg3->reliable);
        ret = -EINVAL;
        if (block1 > docg3->max_block || page || ofs)
                goto reset_err;
 
        ret = 0;
-       calc_block_sector(info->addr, &block0, &block1, &page, &ofs);
+       calc_block_sector(info->addr, &block0, &block1, &page, &ofs,
+                         docg3->reliable);
        doc_set_reliable_mode(docg3);
        for (len = info->len; !ret && len > 0; len -= mtd->erasesize) {
                info->state = MTD_ERASING;
        u8 syn[DOC_ECC_BCH_SIZE], hamming;
 
        doc_dbg("doc_write_page(to=%lld)\n", to);
-       calc_block_sector(to, &block0, &block1, &page, &ofs);
+       calc_block_sector(to, &block0, &block1, &page, &ofs, docg3->reliable);
 
        doc_set_device_id(docg3, docg3->device_id);
        ret = doc_reset_seq(docg3);
                return -EINVAL;
 
        ret = -EINVAL;
-       calc_block_sector(ofs + len, &block0, &block1, &page, &pofs);
+       calc_block_sector(ofs + len, &block0, &block1, &page, &pofs,
+                         docg3->reliable);
        if (block1 > docg3->max_block)
                goto err;
 
 
        cfg = doc_register_readb(docg3, DOC_CONFIGURATION);
        docg3->if_cfg = (cfg & DOC_CONF_IF_CFG ? 1 : 0);
+       docg3->reliable = reliable_mode;
 
        switch (chip_id) {
        case DOC_CHIPID_G3:
        mtd->type = MTD_NANDFLASH;
        mtd->flags = MTD_CAP_NANDFLASH;
        mtd->size = (docg3->max_block + 1) * DOC_LAYOUT_BLOCK_SIZE;
+       if (docg3->reliable == 2)
+               mtd->size /= 2;
        mtd->erasesize = DOC_LAYOUT_BLOCK_SIZE * DOC_LAYOUT_NBPLANES;
+       if (docg3->reliable == 2)
+               mtd->erasesize /= 2;
        mtd->writesize = DOC_LAYOUT_PAGE_SIZE;
        mtd->oobsize = DOC_LAYOUT_OOB_SIZE;
        mtd->owner = THIS_MODULE;