lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Thu, 22 Jan 2015 12:06:21 +0530
From:	Archit Taneja <architt@...eaurora.org>
To:	Daniel Ehrenberg <dehrenberg@...gle.com>
CC:	linux-arm-msm@...r.kernel.org, galak@...eaurora.org,
	"linux-mtd@...ts.infradead.org" <linux-mtd@...ts.infradead.org>,
	linux-kernel@...r.kernel.org, agross@...eaurora.org
Subject: Re: [PATCH 2/5] mtd: nand: Add qcom nand controller driver

Hi,

On 01/21/2015 06:24 AM, Daniel Ehrenberg wrote:
> On Fri, Jan 16, 2015 at 6:48 AM, Archit Taneja <architt@...eaurora.org> wrote:
>> +/*
>> + * the bad block marker is readable only when we read the page with ECC
>> + * disabled. all the read/write commands like NAND_CMD_READOOB, NAND_CMD_READ0
>> + * and NAND_CMD_PAGEPROG are executed in the driver with ECC enabled. therefore,
>> + * the default nand helper functions to detect a bad block or mark a bad block
>> + * can't be used.
>> + */
>> +static int qcom_nandc_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
>> +{
>> +       int page, r, mark, bad = 0;
>> +       struct nand_chip *chip = mtd->priv;
>> +       struct nand_ecc_ctrl *ecc = &chip->ecc;
>> +       int cwperpage = ecc->steps;
>> +       struct qcom_nandc_data *this = chip->priv;
>> +       u32 flash_status;
>> +
>> +       pre_command(this, NAND_CMD_NONE);
>> +
>> +       page = (int)(ofs >> chip->page_shift) & chip->pagemask;
>> +
>> +       /*
>> +        * configure registers for a raw page read, the address is set to the
>> +        * beginning of the last codeword
>> +        */
>> +       this->use_ecc = false;
>> +       set_address(this, this->cw_size * (cwperpage - 1), page);
>> +
>> +       /* we just read one codeword that contains the bad block marker */
>> +       update_rw_regs(this, 1, true);
>> +
>> +       read_cw(this, this->cw_size, 0);
>> +
>> +       r = submit_descs(this);
>> +       if (r) {
>> +               dev_err(this->dev, "error submitting descs\n");
>> +               goto err;
>> +       }
>> +
>> +       flash_status = this->reg_read_buf[0];
>> +
>> +       /*
>> +        * unable to read the marker successfully, is that sufficient to report
>> +        * the block as bad?
>> +        */
>> +       if (flash_status & (FS_OP_ERR | FS_MPU_ERR)) {
>> +               dev_warn(this->dev, "error while reading bad block mark\n");
>> +               goto err;
>> +       }
>> +
>> +       mark = mtd->writesize - (this->cw_size * (cwperpage - 1));
>> +
>> +       if (chip->options & NAND_BUSWIDTH_16)
>> +               bad = this->data_buffer[mark] != 0xff ||
>> +                       this->data_buffer[mark + 1] != 0xff;
>> +
>> +       bad = this->data_buffer[mark] != 0xff;
>> +err:
>> +       free_descs(this);
>> +
>> +       return bad;
>> +}
>> +
>> +static int qcom_nandc_block_markbad(struct mtd_info *mtd, loff_t ofs)
>> +{
>> +       int page, r;
>> +       struct nand_chip *chip = mtd->priv;
>> +       struct nand_ecc_ctrl *ecc = &chip->ecc;
>> +       int cwperpage = ecc->steps;
>> +       struct qcom_nandc_data *this = chip->priv;
>> +       u32 flash_status;
>> +
>> +       pre_command(this, NAND_CMD_NONE);
>> +
>> +       /* fill our internal buffer's oob area with 0's */
>> +       memset(this->data_buffer, 0x00, mtd->writesize + mtd->oobsize);
>> +
>> +       page = (int)(ofs >> chip->page_shift) & chip->pagemask;
>> +
>> +       this->use_ecc = false;
>> +       set_address(this, this->cw_size * (cwperpage - 1), page);
>> +
>> +       /* we just write to one codeword that contains the bad block marker*/
>> +       update_rw_regs(this, 1, false);
>> +
>> +       /*
>> +        * overwrite the last codeword with 0s, this will result in setting
>> +        * the bad block marker to 0 too
>> +        */
>> +       write_cw(this, this->cw_size, 0);
>> +
>> +       r = submit_descs(this);
>> +       if (r) {
>> +               dev_err(this->dev, "error submitting descs\n");
>> +               r = -EIO;
>> +               goto err;
>> +       }
>> +
>> +       flash_status = this->reg_read_buf[0];
>> +
>> +       if (flash_status & (FS_OP_ERR | FS_MPU_ERR))
>> +               r = -EIO;
>> +
>> +err:
>> +       free_descs(this);
>> +
>> +       return r;
>> +}
>
> Looks like this code marks block bad and reads bad block information
> based on information in the OOB area. And in qcom_nandc_init,
> NAND_SKIP_BBTSCAN is set, meaning that this is the code used in
> practice on the chip in the mtd_block_isbad path. Can this driver be
> used with an on-flash OOB table by editing the init function's chip
> flags, or would it need more significant changes to allow that?

The code doesn't exactly read the OOB area. When the ECC HW block is 
enabled, the bad block isn't in either oob or data area! We can access 
it only when ECC is disabled. With ECC disabled, the bad block marker 
lies in the last codeword somewhere in the middle of the user data. For 
the mtd_read_oob()/write_oob() functions, we have the ECC always 
enabled, hence, we never access the bad block marker through them at all.

Creating an on-flash bad block table won't work right now. The reason is 
that the nand_bbt library assumes that it can find the bad block marker 
by reading oob. While creating a bbt in memory, it scans the device for 
bad blocks using the function scan_block_fast(). This would currently 
result in not reading the bad block marker, and therefore break things.

I'm trying to find out if there is a way by which the controller can 
access the bad block marker with ECC HW enabled. If that works, we can 
use the nand_bbt helper as is. For now, I wanted to get the driver 
upstream without the BBT functionality.

Archit
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ