{"id":804353,"url":"http://patchwork.ozlabs.org/api/1.2/patches/804353/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-mtd/patch/1503394972-12541-1-git-send-email-andrea.adami@gmail.com/","project":{"id":3,"url":"http://patchwork.ozlabs.org/api/1.2/projects/3/?format=json","name":"Linux MTD development","link_name":"linux-mtd","list_id":"linux-mtd.lists.infradead.org","list_email":"linux-mtd@lists.infradead.org","web_url":null,"scm_url":null,"webscm_url":null,"list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<1503394972-12541-1-git-send-email-andrea.adami@gmail.com>","list_archive_url":null,"date":"2017-08-22T09:42:52","name":"[v6] mtd: sharpslpart: Add sharpslpart partition parser","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"01a5b3ff58179fd64dfe8eef8754075d0fbd903c","submitter":{"id":30311,"url":"http://patchwork.ozlabs.org/api/1.2/people/30311/?format=json","name":"Andrea Adami","email":"andrea.adami@gmail.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/linux-mtd/patch/1503394972-12541-1-git-send-email-andrea.adami@gmail.com/mbox/","series":[],"comments":"http://patchwork.ozlabs.org/api/patches/804353/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/804353/checks/","tags":{},"related":[],"headers":{"Return-Path":"<linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@bilbo.ozlabs.org","Authentication-Results":["ozlabs.org; spf=none (mailfrom)\n\tsmtp.mailfrom=lists.infradead.org (client-ip=65.50.211.133;\n\thelo=bombadil.infradead.org;\n\tenvelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org;\n\treceiver=<UNKNOWN>)","ozlabs.org; dkim=pass (2048-bit key;\n\tunprotected) header.d=lists.infradead.org\n\theader.i=@lists.infradead.org header.b=\"a66rlYSj\"; \n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=gmail.com header.i=@gmail.com\n\theader.b=\"THLopG1p\"; dkim-atps=neutral"],"Received":["from bombadil.infradead.org (bombadil.infradead.org\n\t[65.50.211.133])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xc5GX02Xhz9t2Z\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue, 22 Aug 2017 19:43:32 +1000 (AEST)","from localhost ([127.0.0.1] helo=bombadil.infradead.org)\n\tby bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux))\n\tid 1dk5iU-0005R6-6M; Tue, 22 Aug 2017 09:43:22 +0000","from mail-wr0-x242.google.com ([2a00:1450:400c:c0c::242])\n\tby bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux))\n\tid 1dk5iP-00058b-4C\n\tfor linux-mtd@lists.infradead.org; Tue, 22 Aug 2017 09:43:20 +0000","by mail-wr0-x242.google.com with SMTP id p14so16397522wrg.1\n\tfor <linux-mtd@lists.infradead.org>;\n\tTue, 22 Aug 2017 02:42:56 -0700 (PDT)","from andrea-ThinkPad-T520.homenet.telecomitalia.it\n\t(host11-249-dynamic.16-79-r.retail.telecomitalia.it. [79.16.249.11])\n\tby smtp.gmail.com with ESMTPSA id\n\tl3sm15005219wrc.4.2017.08.22.02.42.53\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128);\n\tTue, 22 Aug 2017 02:42:53 -0700 (PDT)"],"DKIM-Signature":["v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;\n\td=lists.infradead.org; s=bombadil.20170209; h=Sender:\n\tContent-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe:\n\tList-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:Message-Id:Date:\n\tSubject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date:\n\tResent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:\n\tReferences:List-Owner; bh=sLPIfb1QDjr6DEnIF5Llz9f8OWZQtbxgvSONDTXNmlY=;\n\tb=a66\n\trlYSjVwJO1y7O0TGiqMdJVruWzGl0un2wMWQC3ciPPzDs2v6PexUhdNM86KQZqBno5a0JOrxrTjgs\n\ttTpNpCJi+hGAOvD1nLDCn6lexj0D6j4HL/vwuhMLGQL6490irSqdUw25z51qnaYG56gi3X8rDiBnE\n\t91ti0y/U9d+swOH+AIx0jT9jB7BjUYIT9d6FMuOvaVpIX9Hd7TBtqjNGb8sauSbROp52kIAdknlET\n\tZts1RiSSvPtGI/s0FZhu/i7JK7f2in13viA9w5UcH/EyDGv18984AuJvOy5t4oQzRbb6STHlOhhaG\n\tw0fpt0E/06pabyUc51Qhyr+P0T8TJyg==;","v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;\n\th=from:to:cc:subject:date:message-id;\n\tbh=+93WR46uTjFJuvvUS4UV9Z6dk7SsZ5HQRWlWEIG7Gqc=;\n\tb=THLopG1pcYaxYO47ljHw72v9R92GNknFmezHNWv9hSA/qyYYbvH19Xe+f/jYnFJndG\n\t6MX/sRREnGkGnAqN2CASxVRUrbSyEVevB+MBcE6htmkNQlm/GCTIoo8EVsDkTMCoqBx0\n\tlLGw9DawzR3VyoqK2w27CjHuXr/yOnZj2MO+MVVcptMXJobsPC1TtfmlQmaXC5eW6Jno\n\tfOpfgWjoWE+HnRUhNnf/xa/7A9MH4l6MuQP1EAqgfP36pq3Gglv2DgY4UAbWpWyt7Z+A\n\t1O4vgCn6mf1T3aI2pTNTrpNSLcoavrStpjGIAc1AFgIXskoP43UAZYsKIMXIHLBsW9Rx\n\tDCTA=="],"X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id;\n\tbh=+93WR46uTjFJuvvUS4UV9Z6dk7SsZ5HQRWlWEIG7Gqc=;\n\tb=XkWPJocowTnkm2Tra4bzxO1Oxm64MSEetM8529G0OlaCBCdS7ribNvjtl1HRdQV0jx\n\tRo1CSHvlmNjdm/etOyY/Gl4tiW/qAKLzRZlCzLOVAqP1ofo3mZiCGnDa7xFMBrlws5RQ\n\tqao8pLMyLMr7JqRKk8b+nNrQq3hsY6qK9V+PdyNRtelppFQWry7xx6qgmt90wo0KTJnb\n\tIfNps2jHpJDd3a7QbiatSayDPdaR2E3Y5ugOWEkg4+qj8UzN/yNsdpqQGKOd5HN7ldDt\n\t3eh3wYSktvt5skyH7MWqO+M/4nxVxcGH1FluZLBO5Owq3MPShP4YyJWWB6KRnF1oRW/a\n\tah8A==","X-Gm-Message-State":"AHYfb5jI+R58Wsdz55mEItw709IerbsBnzzTsAg/vIJ8HzDIOhAYfHe1\n\taunJilfnts/02gld","X-Received":"by 10.28.175.65 with SMTP id y62mr42011wme.77.1503394974600;\n\tTue, 22 Aug 2017 02:42:54 -0700 (PDT)","From":"Andrea Adami <andrea.adami@gmail.com>","To":"linux-mtd@lists.infradead.org","Subject":"[PATCH v6] mtd: sharpslpart: Add sharpslpart partition parser","Date":"Tue, 22 Aug 2017 11:42:52 +0200","Message-Id":"<1503394972-12541-1-git-send-email-andrea.adami@gmail.com>","X-Mailer":"git-send-email 2.7.4","X-CRM114-Version":"20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 ","X-CRM114-CacheID":"sfid-20170822_024317_562034_06AE8529 ","X-CRM114-Status":"GOOD (  31.19  )","X-Spam-Score":"-2.0 (--)","X-Spam-Report":"SpamAssassin version 3.4.1 on bombadil.infradead.org summary:\n\tContent analysis details:   (-2.0 points)\n\tpts rule name              description\n\t---- ----------------------\n\t--------------------------------------------------\n\t-0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/,\n\tno\n\ttrust [2a00:1450:400c:c0c:0:0:0:242 listed in] [list.dnswl.org]\n\t-0.0 SPF_PASS               SPF: sender matches SPF record\n\t0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail\n\tprovider (andrea.adami[at]gmail.com)\n\t-1.9 BAYES_00               BODY: Bayes spam probability is 0 to 1%\n\t[score: 0.0000]\n\t-0.1 DKIM_VALID Message has at least one valid DKIM or DK signature\n\t0.1 DKIM_SIGNED            Message has a DKIM or DK signature,\n\tnot necessarily valid\n\t-0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from\n\tauthor's domain","X-BeenThere":"linux-mtd@lists.infradead.org","X-Mailman-Version":"2.1.21","Precedence":"list","List-Id":"Linux MTD discussion mailing list <linux-mtd.lists.infradead.org>","List-Unsubscribe":"<http://lists.infradead.org/mailman/options/linux-mtd>,\n\t<mailto:linux-mtd-request@lists.infradead.org?subject=unsubscribe>","List-Archive":"<http://lists.infradead.org/pipermail/linux-mtd/>","List-Post":"<mailto:linux-mtd@lists.infradead.org>","List-Help":"<mailto:linux-mtd-request@lists.infradead.org?subject=help>","List-Subscribe":"<http://lists.infradead.org/mailman/listinfo/linux-mtd>,\n\t<mailto:linux-mtd-request@lists.infradead.org?subject=subscribe>","Cc":"Boris Brezillon <boris.brezillon@free-electrons.com>,\n\tDmitry Eremin-Solenikov <dbaryshkov@gmail.com>,\n\tRichard Weinberger <richard@nod.at>,\n\tRobert Jarzmik <robert.jarzmik@free.fr>, linux-kernel@vger.kernel.org,\n\tHaojian Zhuang <haojian.zhuang@gmail.com>, \n\tMarek Vasut <marek.vasut@gmail.com>,\n\tCyrille Pitchen <cyrille.pitchen@wedev4u.fr>,\n\t=?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>,\n\tBrian Norris <computersforpeace@gmail.com>,\n\tDavid Woodhouse <dwmw2@infradead.org>","MIME-Version":"1.0","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Sender":"\"linux-mtd\" <linux-mtd-bounces@lists.infradead.org>","Errors-To":"linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org"},"content":"The Sharp SL Series (Zaurus) PXA handhelds have 16/64/128M of NAND flash\nand share the same layout of the first 7M partition, managed by Sharp FTL.\n\nThe purpose of this self-contained patch is to add a common parser and\nremove the hardcoded sizes in the board files (these devices are not yet\nconverted to devicetree).\nUsers will have benefits because the mtdparts= tag will not be necessary\nanymore and they will be free to repartition the little sized flash.\n\nThe obsolete bootloader can not pass the partitioning info to modern\nkernels anymore so it has to be read from flash at known logical addresses.\n(see http://www.h5.dion.ne.jp/~rimemoon/zaurus/memo_006.htm )\n\nIn kernel, under arch/arm/mach-pxa we have already 8 machines:\nMACH_POODLE, MACH_CORGI, MACH_SHEPERD, MACH_HUSKY, MACH_AKITA, MACH_SPITZ,\nMACH_BORZOI, MACH_TOSA.\nLost after the 2.4 vendor kernel are MACH_BOXER and MACH_TERRIER.\n\nAlmost every model has different factory partitioning: add to this the\nunits can be repartitioned by users with userspace tools (nandlogical)\nand installers for popular (back then) linux distributions.\n\nThe Parameter Area in the first (boot) partition extends from 0x00040000 to\n0x0007bfff (176k) and contains two copies of the partition table:\n...\n0x00060000: Partition Info1     16k\n0x00064000: Partition Info2     16k\n0x00668000: Model               16k\n...\n\nThe first 7M partition is managed by the Sharp FTL reserving 5% + 1 blocks\nfor wear-leveling: some blocks are remapped and one layer of translation\n(logical to physical) is necessary.\n\nThere isn't much documentation about this FTL in the 2.4 sources, just the\nMTD methods for reading and writing using logical addresses and the block\nmanagement (wear-leveling, use counter).\nFor the purpose of the MTD parser only the read part of the code was taken.\n\nThe NAND drivers that can use this parser are sharpsl.c and tmio_nand.c.\n\nSigned-off-by: Andrea Adami <andrea.adami@gmail.com>\n---\n drivers/mtd/parsers/Kconfig       |   7 +\n drivers/mtd/parsers/Makefile      |   1 +\n drivers/mtd/parsers/sharpslpart.c | 382 ++++++++++++++++++++++++++++++++++++++\n 3 files changed, 390 insertions(+)\n create mode 100644 drivers/mtd/parsers/sharpslpart.c","diff":"diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig\nindex d206b3c..f371022 100644\n--- a/drivers/mtd/parsers/Kconfig\n+++ b/drivers/mtd/parsers/Kconfig\n@@ -6,3 +6,10 @@ config MTD_PARSER_TRX\n \t  may contain up to 3/4 partitions (depending on the version).\n \t  This driver will parse TRX header and report at least two partitions:\n \t  kernel and rootfs.\n+config MTD_SHARPSL_PARTS\n+\ttristate \"Sharp SL Series NAND flash partition parser\"\n+\tdepends on MTD_NAND_SHARPSL || MTD_NAND_TMIO || COMPILE_TEST\n+\thelp\n+\t  This provides the read-only FTL logic necessary to read the partition\n+\t  table from the NAND flash of Sharp SL Series (Zaurus) and the MTD\n+\t  partition parser using this code.\ndiff --git a/drivers/mtd/parsers/Makefile b/drivers/mtd/parsers/Makefile\nindex 4d9024e..5b1bcc3 100644\n--- a/drivers/mtd/parsers/Makefile\n+++ b/drivers/mtd/parsers/Makefile\n@@ -1 +1,2 @@\n obj-$(CONFIG_MTD_PARSER_TRX)\t\t+= parser_trx.o\n+obj-$(CONFIG_MTD_SHARPSL_PARTS)\t\t+= sharpslpart.o\ndiff --git a/drivers/mtd/parsers/sharpslpart.c b/drivers/mtd/parsers/sharpslpart.c\nnew file mode 100644\nindex 0000000..b2333ae\n--- /dev/null\n+++ b/drivers/mtd/parsers/sharpslpart.c\n@@ -0,0 +1,382 @@\n+/*\n+ * sharpslpart.c - MTD partition parser for NAND flash using the SHARP FTL\n+ * for logical addressing, as used on the PXA models of the SHARP SL Series.\n+ *\n+ * Copyright (C) 2017 Andrea Adami <andrea.adami@gmail.com>\n+ *\n+ * Based on 2.4 sources:\n+ *  drivers/mtd/nand/sharp_sl_logical.c\n+ *  linux/include/asm-arm/sharp_nand_logical.h\n+ *\n+ * Copyright (C) 2002 SHARP\n+ *\n+ * This program is free software; you can redistribute it and/or modify\n+ * it under the terms of the GNU General Public License as published by\n+ * the Free Software Foundation; either version 2 of the License, or\n+ * (at your option) any later version.\n+ *\n+ * This program is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n+ * GNU General Public License for more details.\n+ *\n+ */\n+\n+#include <linux/kernel.h>\n+#include <linux/slab.h>\n+#include <linux/module.h>\n+#include <linux/types.h>\n+#include <linux/mtd/mtd.h>\n+#include <linux/mtd/partitions.h>\n+\n+/* oob structure */\n+#define NAND_NOOB_LOGADDR_00\t\t8\n+#define NAND_NOOB_LOGADDR_01\t\t9\n+#define NAND_NOOB_LOGADDR_10\t\t10\n+#define NAND_NOOB_LOGADDR_11\t\t11\n+#define NAND_NOOB_LOGADDR_20\t\t12\n+#define NAND_NOOB_LOGADDR_21\t\t13\n+\n+#define BLOCK_IS_RESERVED\t\t0xffff\n+#define BLOCK_UNMASK\t\t\t0x07fe\n+#define BLOCK_UNMASK_COMPLEMENT\t\t1\n+\n+/* factory defaults */\n+#define SHARPSL_NAND_PARTS\t\t3\n+#define SHARPSL_FTL_PART_SIZE\t\t(7 * 1024 * 1024)\n+#define PARAM_BLOCK_PARTITIONINFO1\t0x00060000\n+#define PARAM_BLOCK_PARTITIONINFO2\t0x00064000\n+\n+#define BOOT_MAGIC\t\t\t0x424f4f54\n+#define FSRO_MAGIC\t\t\t0x4653524f\n+#define FSRW_MAGIC\t\t\t0x46535257\n+\n+/**\n+ * struct sharpsl_ftl - Sharp FTL Logical Table\n+ * @logmax:\t\tnumber of logical blocks\n+ * @log2phy:\t\tthe logical-to-physical table\n+ *\n+ * Stripped down from 2.4 sources for read-only purposes.\n+ */\n+struct sharpsl_ftl {\n+\tu_int logmax;\n+\tu_int *log2phy;\n+};\n+\n+static int sharpsl_nand_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,\n+\t\t\t\t uint8_t *buf)\n+{\n+\tloff_t mask = mtd->writesize - 1;\n+\tstruct mtd_oob_ops ops;\n+\tint ret;\n+\n+\tops.mode = MTD_OPS_PLACE_OOB;\n+\tops.ooboffs = offs & mask;\n+\tops.ooblen = len;\n+\tops.oobbuf = buf;\n+\tops.datbuf = NULL;\n+\n+\tret = mtd_read_oob(mtd, offs & ~mask, &ops);\n+\tif (ret != 0 || len != ops.oobretlen)\n+\t\treturn -1;\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * The logical block number assigned to a physical block is stored in the OOB\n+ * of the first page, in 3 16-bit copies with the following layout:\n+ *\n+ * 01234567 89abcdef\n+ * -------- --------\n+ * ECC BB   xyxyxy\n+ *\n+ * When reading we check that the first two copies agree.\n+ * In case of error, matching is tried using the following pairs.\n+ * Reserved values 0xffff mean the block is kept for wear leveling.\n+ *\n+ * 01234567 89abcdef\n+ * -------- --------\n+ * ECC BB   xyxy    oob[8]==oob[10] && oob[9]==oob[11]   -> byte0=8   byte1=9\n+ * ECC BB     xyxy  oob[10]==oob[12] && oob[11]==oob[13] -> byte0=10  byte1=11\n+ * ECC BB   xy  xy  oob[12]==oob[8] && oob[13]==oob[9]   -> byte0=12  byte1=13\n+ *\n+ */\n+static u_int sharpsl_nand_get_logical_num(u_char *oob)\n+{\n+\tu16 us;\n+\tint good0, good1;\n+\n+\tif (oob[NAND_NOOB_LOGADDR_00] == oob[NAND_NOOB_LOGADDR_10] &&\n+\t    oob[NAND_NOOB_LOGADDR_01] == oob[NAND_NOOB_LOGADDR_11]) {\n+\t\tgood0 = NAND_NOOB_LOGADDR_00;\n+\t\tgood1 = NAND_NOOB_LOGADDR_01;\n+\t} else if (oob[NAND_NOOB_LOGADDR_10] == oob[NAND_NOOB_LOGADDR_20] &&\n+\t\t   oob[NAND_NOOB_LOGADDR_11] == oob[NAND_NOOB_LOGADDR_21]) {\n+\t\tgood0 = NAND_NOOB_LOGADDR_10;\n+\t\tgood1 = NAND_NOOB_LOGADDR_11;\n+\t} else if (oob[NAND_NOOB_LOGADDR_20] == oob[NAND_NOOB_LOGADDR_00] &&\n+\t\t   oob[NAND_NOOB_LOGADDR_21] == oob[NAND_NOOB_LOGADDR_01]) {\n+\t\tgood0 = NAND_NOOB_LOGADDR_20;\n+\t\tgood1 = NAND_NOOB_LOGADDR_21;\n+\t} else {\n+\t\t/* wrong oob fingerprint, maybe here by mistake? */\n+\t\treturn UINT_MAX;\n+\t}\n+\n+\tus = oob[good0] | oob[good1] << 8;\n+\n+\t/* parity check */\n+\tif (hweight16(us) & BLOCK_UNMASK_COMPLEMENT)\n+\t\treturn (UINT_MAX - 1);\n+\n+\t/* reserved */\n+\tif (us == BLOCK_IS_RESERVED)\n+\t\treturn BLOCK_IS_RESERVED;\n+\telse\n+\t\treturn (us & BLOCK_UNMASK) >> 1;\n+}\n+\n+static int sharpsl_nand_init_logical(struct mtd_info *mtd, u32 partition_size,\n+\t\t\t\t     struct sharpsl_ftl *ftl)\n+{\n+\tu_int block_num, log_num, phymax;\n+\tloff_t block_adr;\n+\tu_char *oob;\n+\tint i, ret;\n+\n+\toob = kzalloc(mtd->oobsize, GFP_KERNEL);\n+\tif (!oob)\n+\t\treturn -ENOMEM;\n+\n+\t/* initialize management structure */\n+\tphymax = (partition_size / mtd->erasesize);\n+\n+\t/* FTL reserves 5% of the blocks + 1 spare  */\n+\tftl->logmax = ((phymax * 95) / 100) - 1;\n+\n+\tftl->log2phy = kmalloc_array(ftl->logmax, sizeof(u_int),\n+\t\t\t\t     GFP_KERNEL);\n+\tif (!ftl->log2phy) {\n+\t\tret = -ENOMEM;\n+\t\tgoto exit;\n+\t}\n+\n+\t/* initialize ftl->log2phy */\n+\tfor (i = 0; i < ftl->logmax; i++)\n+\t\tftl->log2phy[i] = UINT_MAX;\n+\n+\t/* create physical-logical table */\n+\tfor (block_num = 0; block_num < phymax; block_num++) {\n+\t\tblock_adr = block_num * mtd->erasesize;\n+\n+\t\tif (mtd_block_isbad(mtd, block_adr))\n+\t\t\tcontinue;\n+\n+\t\tif (sharpsl_nand_read_oob(mtd, block_adr, mtd->oobsize, oob))\n+\t\t\tcontinue;\n+\n+\t\t/* get logical block */\n+\t\tlog_num = sharpsl_nand_get_logical_num(oob);\n+\n+\t\t/* FTL is not used? Exit here if the oob fingerprint is wrong */\n+\t\tif (log_num == UINT_MAX) {\n+\t\t\tpr_info(\"sharpslpart: Sharp SL FTL not found.\\n\");\n+\t\t\tret = -EINVAL;\n+\t\t\tgoto exit;\n+\t\t}\n+\n+\t\t/* skip out of range and not unique values */\n+\t\tif (log_num < ftl->logmax) {\n+\t\t\tif (ftl->log2phy[log_num] == UINT_MAX)\n+\t\t\t\tftl->log2phy[log_num] = block_num;\n+\t\t}\n+\t}\n+\n+\tpr_info(\"Sharp SL FTL: %d blocks used (%d logical, %d reserved)\\n\",\n+\t\tphymax, ftl->logmax,\n+\t\tphymax - ftl->logmax);\n+\n+\tret = 0;\n+exit:\n+\tkfree(oob);\n+\treturn ret;\n+}\n+\n+void sharpsl_nand_cleanup_logical(struct sharpsl_ftl *ftl)\n+{\n+\tkfree(ftl->log2phy);\n+}\n+\n+static int sharpsl_nand_read_laddr(struct mtd_info *mtd,\n+\t\t\t\t   loff_t from,\n+\t\t\t\t   size_t len,\n+\t\t\t\t   u_char *buf,\n+\t\t\t\t   struct sharpsl_ftl *ftl)\n+{\n+\tu_int log_num, log_new;\n+\tu_int block_num;\n+\tloff_t block_adr;\n+\tloff_t block_ofs;\n+\tsize_t retlen;\n+\tint err;\n+\n+\tlog_num = (u32)from / mtd->erasesize;\n+\tlog_new = ((u32)from + len - 1) / mtd->erasesize;\n+\n+\tif (len <= 0 || log_num >= ftl->logmax || log_new > log_num)\n+\t\treturn -EINVAL;\n+\n+\tblock_num = ftl->log2phy[log_num];\n+\tblock_adr = block_num * mtd->erasesize;\n+\tblock_ofs = (u32)from % mtd->erasesize;\n+\n+\terr = mtd_read(mtd, block_adr + block_ofs, len, &retlen, buf);\n+\t/* Ignore corrected ECC errors */\n+\tif (mtd_is_bitflip(err))\n+\t\terr = 0;\n+\tif (!err && retlen != len)\n+\t\terr = -EIO;\n+\tif (err)\n+\t\tpr_err(\"sharpslpart: error, read failed at %#llx\\n\",\n+\t\t       block_adr + block_ofs);\n+\n+\treturn err;\n+}\n+\n+/*\n+ * MTD Partition Parser\n+ *\n+ * Sample values read from SL-C860\n+ *\n+ * # cat /proc/mtd\n+ * dev:    size   erasesize  name\n+ * mtd0: 006d0000 00020000 \"Filesystem\"\n+ * mtd1: 00700000 00004000 \"smf\"\n+ * mtd2: 03500000 00004000 \"root\"\n+ * mtd3: 04400000 00004000 \"home\"\n+ *\n+ * PARTITIONINFO1\n+ * 0x00060000: 00 00 00 00 00 00 70 00 42 4f 4f 54 00 00 00 00  ......p.BOOT....\n+ * 0x00060010: 00 00 70 00 00 00 c0 03 46 53 52 4f 00 00 00 00  ..p.....FSRO....\n+ * 0x00060020: 00 00 c0 03 00 00 00 04 46 53 52 57 00 00 00 00  ........FSRW....\n+ * 0x00060030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................\n+ *\n+ */\n+struct sharpsl_nand_partinfo {\n+\t__le32 start;\n+\t__le32 end;\n+\t__be32 magic;\n+\tu32 reserved;\n+};\n+\n+static int sharpsl_nand_read_partinfo(struct mtd_info *master,\n+\t\t\t\t      loff_t from,\n+\t\t\t\t      size_t len,\n+\t\t\t\t      struct sharpsl_nand_partinfo *buf,\n+\t\t\t\t      struct sharpsl_ftl *ftl)\n+{\n+\tint ret;\n+\n+\tret = sharpsl_nand_read_laddr(master, (u32)from, len, (u_char *)buf,\n+\t\t\t\t      ftl);\n+\tif (ret)\n+\t\tgoto exit;\n+\n+\t/* check for magics */\n+\tif (be32_to_cpu(buf[0].magic) != BOOT_MAGIC ||\n+\t    be32_to_cpu(buf[1].magic) != FSRO_MAGIC ||\n+\t    be32_to_cpu(buf[2].magic) != FSRW_MAGIC) {\n+\t\tpr_err(\"sharpslpart: magic values mismatch\\n\");\n+\t\tret = -EINVAL;\n+\t\tgoto exit;\n+\t}\n+\n+\t/* fixup for hardcoded value 64 MiB (for older models) */\n+\tbuf[2].end = cpu_to_le32(master->size);\n+\n+\t/* extra sanity check */\n+\tif (le32_to_cpu(buf[0].end) <= le32_to_cpu(buf[0].start) ||\n+\t    le32_to_cpu(buf[1].start) < le32_to_cpu(buf[0].end) ||\n+\t    le32_to_cpu(buf[1].end) <= le32_to_cpu(buf[1].start) ||\n+\t    le32_to_cpu(buf[2].start) < le32_to_cpu(buf[1].end) ||\n+\t    le32_to_cpu(buf[2].end) <= le32_to_cpu(buf[2].start)) {\n+\t\tpr_err(\"sharpslpart: partition sizes mismatch\\n\");\n+\t\tret = -EINVAL;\n+\t\tgoto exit;\n+\t}\n+\n+\tret = 0;\n+exit:\n+\treturn ret;\n+}\n+\n+static int sharpsl_parse_mtd_partitions(struct mtd_info *master,\n+\t\t\t\t\tconst struct mtd_partition **pparts,\n+\t\t\t\t\tstruct mtd_part_parser_data *data)\n+{\n+\tstruct sharpsl_ftl ftl;\n+\tstruct sharpsl_nand_partinfo buf[SHARPSL_NAND_PARTS];\n+\tstruct mtd_partition *sharpsl_nand_parts;\n+\tint err, ret;\n+\n+\t/* init logical mgmt (FTL) */\n+\terr = sharpsl_nand_init_logical(master, SHARPSL_FTL_PART_SIZE, &ftl);\n+\tif (err)\n+\t\treturn err;\n+\n+\t/* read and validate first partition table */\n+\tpr_info(\"sharpslpart: using first partition table\\n\");\n+\terr = sharpsl_nand_read_partinfo(master,\n+\t\t\t\t\t PARAM_BLOCK_PARTITIONINFO1,\n+\t\t\t\t\t sizeof(buf), buf, &ftl);\n+\tif (err) {\n+\t\t/* fallback: read second partition table */\n+\t\tpr_warn(\"sharpslpart: retry using second partition table\\n\");\n+\t\tret = sharpsl_nand_read_partinfo(master,\n+\t\t\t\t\t\t PARAM_BLOCK_PARTITIONINFO2,\n+\t\t\t\t\t\t sizeof(buf), buf, &ftl);\n+\t\tif (ret) {\n+\t\t\tpr_err(\"sharpslpart: partition tables are invalid\\n\");\n+\t\t\tsharpsl_nand_cleanup_logical(&ftl);\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\n+\t/* cleanup logical mgmt (FTL) */\n+\tsharpsl_nand_cleanup_logical(&ftl);\n+\n+\tsharpsl_nand_parts = kzalloc(sizeof(*sharpsl_nand_parts) *\n+\t\t\t\t     SHARPSL_NAND_PARTS, GFP_KERNEL);\n+\tif (!sharpsl_nand_parts)\n+\t\treturn -ENOMEM;\n+\n+\t/* original names */\n+\tsharpsl_nand_parts[0].name = \"smf\";\n+\tsharpsl_nand_parts[0].offset = le32_to_cpu(buf[0].start);\n+\tsharpsl_nand_parts[0].size = le32_to_cpu(buf[0].end) -\n+\t\t\t\t     le32_to_cpu(buf[0].start);\n+\n+\tsharpsl_nand_parts[1].name = \"root\";\n+\tsharpsl_nand_parts[1].offset = le32_to_cpu(buf[1].start);\n+\tsharpsl_nand_parts[1].size = le32_to_cpu(buf[1].end) -\n+\t\t\t\t     le32_to_cpu(buf[1].start);\n+\n+\tsharpsl_nand_parts[2].name = \"home\";\n+\tsharpsl_nand_parts[2].offset = le32_to_cpu(buf[2].start);\n+\tsharpsl_nand_parts[2].size = le32_to_cpu(buf[2].end) -\n+\t\t\t\t     le32_to_cpu(buf[2].start);\n+\n+\t*pparts = sharpsl_nand_parts;\n+\treturn SHARPSL_NAND_PARTS;\n+}\n+\n+static struct mtd_part_parser sharpsl_mtd_parser = {\n+\t.parse_fn = sharpsl_parse_mtd_partitions,\n+\t.name = \"sharpslpart\",\n+};\n+module_mtd_part_parser(sharpsl_mtd_parser);\n+\n+MODULE_LICENSE(\"GPL\");\n+MODULE_AUTHOR(\"Andrea Adami <andrea.adami@gmail.com>\");\n+MODULE_DESCRIPTION(\"MTD partitioning for NAND flash on Sharp SL Series\");\n","prefixes":["v6"]}