nftl_format.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. /*
  2. * nftl_format.c: Creating a NFTL/INFTL partition on an MTD device
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. *
  18. * ToDo:
  19. * 1. UnitSizeFactor != 0xFF cases
  20. * 2. test, test, and test !!!
  21. */
  22. #define PROGRAM_NAME "nftl_format"
  23. #define _XOPEN_SOURCE 500 /* for pread/pwrite */
  24. #include <unistd.h>
  25. #include <stdlib.h>
  26. #include <stdio.h>
  27. #include <fcntl.h>
  28. #include <time.h>
  29. #include <sys/stat.h>
  30. #include <sys/ioctl.h>
  31. #include <sys/mount.h>
  32. #include <errno.h>
  33. #include <string.h>
  34. #include <getopt.h>
  35. #include <asm/types.h>
  36. #include <mtd/mtd-user.h>
  37. #include <mtd/nftl-user.h>
  38. #include <mtd/inftl-user.h>
  39. #include <mtd_swab.h>
  40. #include "common.h"
  41. unsigned char BadUnitTable[MAX_ERASE_ZONES];
  42. unsigned char *readbuf;
  43. unsigned char *writebuf[4];
  44. mtd_info_t meminfo;
  45. erase_info_t erase;
  46. int fd;
  47. struct NFTLMediaHeader *NFTLhdr;
  48. struct INFTLMediaHeader *INFTLhdr;
  49. static int do_oobcheck = 1;
  50. static int do_rwecheck = 1;
  51. static const struct option long_opts[] = {
  52. {"version", no_argument, 0, 'V'},
  53. {"help", no_argument, 0, 'h'},
  54. {0, 0, 0, 0},
  55. };
  56. static unsigned char check_block_1(unsigned long block)
  57. {
  58. unsigned char oobbuf[16];
  59. struct mtd_oob_buf oob = { 0, 16, oobbuf };
  60. oob.start = block * meminfo.erasesize;
  61. if (ioctl(fd, MEMREADOOB, &oob))
  62. return ZONE_BAD_ORIGINAL;
  63. if(oobbuf[5] == 0)
  64. return ZONE_BAD_ORIGINAL;
  65. oob.start = block * meminfo.erasesize + 512 /* FIXME */;
  66. if (ioctl(fd, MEMREADOOB, &oob))
  67. return ZONE_BAD_ORIGINAL;
  68. if(oobbuf[5] == 0)
  69. return ZONE_BAD_ORIGINAL;
  70. return ZONE_GOOD;
  71. }
  72. static unsigned char check_block_2(unsigned long block)
  73. {
  74. unsigned long ofs = block * meminfo.erasesize;
  75. unsigned long blockofs;
  76. /* Erase test */
  77. erase.start = ofs;
  78. for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) {
  79. pread_nocheck(fd, readbuf, 512, ofs + blockofs);
  80. if (memcmp(readbuf, writebuf[0], 512)) {
  81. /* Block wasn't 0xff after erase */
  82. printf(": Block not 0xff after erase\n");
  83. return ZONE_BAD_ORIGINAL;
  84. }
  85. pwrite_nocheck(fd, writebuf[1], 512, blockofs + ofs);
  86. pread_nocheck(fd, readbuf, 512, blockofs + ofs);
  87. if (memcmp(readbuf, writebuf[1], 512)) {
  88. printf(": Block not zero after clearing\n");
  89. return ZONE_BAD_ORIGINAL;
  90. }
  91. }
  92. /* Write test */
  93. if (ioctl(fd, MEMERASE, &erase) != 0) {
  94. printf(": Second erase failed (%s)\n", strerror(errno));
  95. return ZONE_BAD_ORIGINAL;
  96. }
  97. for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) {
  98. pwrite_nocheck(fd, writebuf[2], 512, blockofs + ofs);
  99. pread_nocheck(fd, readbuf, 512, blockofs + ofs);
  100. if (memcmp(readbuf, writebuf[2], 512)) {
  101. printf(": Block not 0x5a after writing\n");
  102. return ZONE_BAD_ORIGINAL;
  103. }
  104. }
  105. if (ioctl(fd, MEMERASE, &erase) != 0) {
  106. printf(": Third erase failed (%s)\n", strerror(errno));
  107. return ZONE_BAD_ORIGINAL;
  108. }
  109. for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) {
  110. pwrite_nocheck(fd, writebuf[3], 512, blockofs + ofs);
  111. pread_nocheck(fd, readbuf, 512, blockofs + ofs);
  112. if (memcmp(readbuf, writebuf[3], 512)) {
  113. printf(": Block not 0xa5 after writing\n");
  114. return ZONE_BAD_ORIGINAL;
  115. }
  116. }
  117. if (ioctl(fd, MEMERASE, &erase) != 0) {
  118. printf(": Fourth erase failed (%s)\n", strerror(errno));
  119. return ZONE_BAD_ORIGINAL;
  120. }
  121. return ZONE_GOOD;
  122. }
  123. static unsigned char erase_block(unsigned long block)
  124. {
  125. unsigned char status;
  126. int ret;
  127. status = (do_oobcheck) ? check_block_1(block) : ZONE_GOOD;
  128. erase.start = block * meminfo.erasesize;
  129. if (status != ZONE_GOOD) {
  130. printf("\rSkipping bad zone (factory marked) #%ld @ 0x%x\n", block, erase.start);
  131. fflush(stdout);
  132. return status;
  133. }
  134. printf("\r\t Erasing Zone #%ld @ 0x%x", block, erase.start);
  135. fflush(stdout);
  136. if ((ret=ioctl(fd, MEMERASE, &erase)) != 0) {
  137. printf(": Erase failed (%s)\n", strerror(errno));
  138. return ZONE_BAD_ORIGINAL;
  139. }
  140. if (do_rwecheck) {
  141. printf("\r\tChecking Zone #%ld @ 0x%x", block, erase.start);
  142. fflush(stdout);
  143. status = check_block_2(block);
  144. if (status != ZONE_GOOD) {
  145. printf("\rSkipping bad zone (RWE test failed) #%ld @ 0x%x\n", block, erase.start);
  146. fflush(stdout);
  147. }
  148. }
  149. return status;
  150. }
  151. static int checkbbt(void)
  152. {
  153. unsigned char bbt[512];
  154. unsigned char bits;
  155. int i, addr;
  156. if (pread_nocheck(fd, bbt, 512, 0x800) < 0) {
  157. printf("%s: failed to read BBT, errno=%d\n", PROGRAM_NAME, errno);
  158. return (-1);
  159. }
  160. for (i = 0; (i < 512); i++) {
  161. addr = i / 4;
  162. bits = 0x3 << ((i % 4) * 2);
  163. if ((bbt[addr] & bits) == 0) {
  164. BadUnitTable[i] = ZONE_BAD_ORIGINAL;
  165. }
  166. }
  167. return (0);
  168. }
  169. static NORETURN void usage(int rc)
  170. {
  171. fprintf(stderr, "Usage: %s [-ib] <mtddevice> [<start offset> [<size>]]\n", PROGRAM_NAME);
  172. exit(rc);
  173. }
  174. static void display_version(void)
  175. {
  176. common_print_version();
  177. printf("Copyright (C) 2005 Thomas Gleixner \n"
  178. "\n"
  179. "%1$s comes with NO WARRANTY\n"
  180. "to the extent permitted by law.\n"
  181. "\n"
  182. "You may redistribute copies of %1$s\n"
  183. "under the terms of the GNU General Public Licence.\n"
  184. "See the file `COPYING' for more information.\n",
  185. PROGRAM_NAME);
  186. exit(EXIT_SUCCESS);
  187. }
  188. int main(int argc, char **argv)
  189. {
  190. unsigned long startofs = 0, part_size = 0;
  191. unsigned long ezones = 0, ezone = 0, bad_zones = 0;
  192. unsigned char unit_factor = 0xFF;
  193. long MediaUnit1 = -1, MediaUnit2 = -1;
  194. long MediaUnitOff1 = 0, MediaUnitOff2 = 0;
  195. unsigned char oobbuf[16];
  196. struct mtd_oob_buf oob = {0, 16, oobbuf};
  197. char *mtddevice;
  198. const char *nftl;
  199. int c, do_inftl = 0, do_bbt = 0;
  200. int idx = 0;
  201. if (argc < 2)
  202. usage(EXIT_FAILURE);
  203. nftl = "NFTL";
  204. while ((c = getopt_long(argc, argv, "?hibV", long_opts, &idx)) != -1) {
  205. switch (c) {
  206. case 'i':
  207. nftl = "INFTL";
  208. do_inftl = 1;
  209. break;
  210. case 'b':
  211. do_bbt = 1;
  212. break;
  213. case 'h':
  214. case '?':
  215. usage(EXIT_SUCCESS);
  216. case 'V':
  217. display_version();
  218. break;
  219. default:
  220. usage(EXIT_FAILURE);
  221. }
  222. }
  223. mtddevice = argv[optind++];
  224. if (argc > optind) {
  225. startofs = strtoul(argv[optind++], NULL, 0);
  226. }
  227. if (argc > optind) {
  228. part_size = strtoul(argv[optind++], NULL, 0);
  229. }
  230. // Open and size the device
  231. if ((fd = open(mtddevice, O_RDWR)) < 0) {
  232. perror("Open flash device");
  233. return 1;
  234. }
  235. if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
  236. perror("ioctl(MEMGETINFO)");
  237. close(fd);
  238. return 1;
  239. }
  240. switch (meminfo.erasesize) {
  241. case 0x1000:
  242. case 0x2000:
  243. case 0x4000:
  244. case 0x8000:
  245. break;
  246. default:
  247. printf("Unrecognized Erase size, 0x%x - I'm confused\n",
  248. meminfo.erasesize);
  249. close(fd);
  250. return 1;
  251. }
  252. writebuf[0] = malloc(meminfo.erasesize * 5);
  253. if (!writebuf[0]) {
  254. printf("Malloc failed\n");
  255. close(fd);
  256. return 1;
  257. }
  258. writebuf[1] = writebuf[0] + meminfo.erasesize;
  259. writebuf[2] = writebuf[1] + meminfo.erasesize;
  260. writebuf[3] = writebuf[2] + meminfo.erasesize;
  261. readbuf = writebuf[3] + meminfo.erasesize;
  262. memset(writebuf[0], 0xff, meminfo.erasesize);
  263. memset(writebuf[1], 0x00, meminfo.erasesize);
  264. memset(writebuf[2], 0x5a, meminfo.erasesize);
  265. memset(writebuf[3], 0xa5, meminfo.erasesize);
  266. memset(BadUnitTable, ZONE_GOOD, MAX_ERASE_ZONES);
  267. if (part_size == 0 || (part_size > meminfo.size - startofs))
  268. /* the user doest not or incorrectly specify NFTL partition size */
  269. part_size = meminfo.size - startofs;
  270. erase.length = meminfo.erasesize;
  271. ezones = part_size / meminfo.erasesize;
  272. if (ezones > MAX_ERASE_ZONES) {
  273. /* Ought to change the UnitSizeFactor. But later. */
  274. part_size = meminfo.erasesize * MAX_ERASE_ZONES;
  275. ezones = MAX_ERASE_ZONES;
  276. unit_factor = 0xFF;
  277. }
  278. /* If using device BBT then parse that now */
  279. if (do_bbt) {
  280. checkbbt();
  281. do_oobcheck = 0;
  282. do_rwecheck = 0;
  283. }
  284. /* Phase 1. Erasing and checking each erase zones in the NFTL partition.
  285. N.B. Erase Zones not used by the NFTL partition are untouched and marked ZONE_GOOD */
  286. printf("Phase 1. Checking and erasing Erase Zones from 0x%08lx to 0x%08lx\n",
  287. startofs, startofs + part_size);
  288. for (ezone = startofs / meminfo.erasesize;
  289. ezone < (ezones + startofs / meminfo.erasesize); ezone++) {
  290. if (BadUnitTable[ezone] != ZONE_GOOD)
  291. continue;
  292. if ((BadUnitTable[ezone] = erase_block(ezone)) == ZONE_GOOD) {
  293. if (MediaUnit1 == -1) {
  294. MediaUnit1 = ezone;
  295. } else if (MediaUnit2 == -1) {
  296. MediaUnit2 = ezone;
  297. }
  298. } else {
  299. bad_zones++;
  300. }
  301. }
  302. printf("\n");
  303. /* N.B. from dump of M-System original chips, NumEraseUnits counts the 2 Erase Unit used
  304. by MediaHeader and the FirstPhysicalEUN starts from the MediaHeader */
  305. if (do_inftl) {
  306. unsigned long maxzones, pezstart, pezend, numvunits;
  307. INFTLhdr = (struct INFTLMediaHeader *) (writebuf[0]);
  308. strcpy(INFTLhdr->bootRecordID, "BNAND");
  309. INFTLhdr->NoOfBootImageBlocks = cpu_to_le32(0);
  310. INFTLhdr->NoOfBinaryPartitions = cpu_to_le32(0);
  311. INFTLhdr->NoOfBDTLPartitions = cpu_to_le32(1);
  312. INFTLhdr->BlockMultiplierBits = cpu_to_le32(0);
  313. INFTLhdr->FormatFlags = cpu_to_le32(0);
  314. INFTLhdr->OsakVersion = cpu_to_le32(OSAK_VERSION);
  315. INFTLhdr->PercentUsed = cpu_to_le32(PERCENTUSED);
  316. /*
  317. * Calculate number of virtual units we will have to work
  318. * with. I am calculating out the known bad units here, not
  319. * sure if that is what M-Systems do...
  320. */
  321. MediaUnit2 = MediaUnit1;
  322. MediaUnitOff2 = 4096;
  323. maxzones = meminfo.size / meminfo.erasesize;
  324. pezstart = startofs / meminfo.erasesize + 1;
  325. pezend = startofs / meminfo.erasesize + ezones - 1;
  326. numvunits = (ezones - 2) * PERCENTUSED / 100;
  327. for (ezone = pezstart; ezone < maxzones; ezone++) {
  328. if (BadUnitTable[ezone] != ZONE_GOOD) {
  329. if (numvunits > 1)
  330. numvunits--;
  331. }
  332. }
  333. INFTLhdr->Partitions[0].virtualUnits = cpu_to_le32(numvunits);
  334. INFTLhdr->Partitions[0].firstUnit = cpu_to_le32(pezstart);
  335. INFTLhdr->Partitions[0].lastUnit = cpu_to_le32(pezend);
  336. INFTLhdr->Partitions[0].flags = cpu_to_le32(INFTL_BDTL);
  337. INFTLhdr->Partitions[0].spareUnits = cpu_to_le32(0);
  338. INFTLhdr->Partitions[0].Reserved0 = INFTLhdr->Partitions[0].firstUnit;
  339. INFTLhdr->Partitions[0].Reserved1 = cpu_to_le32(0);
  340. } else {
  341. NFTLhdr = (struct NFTLMediaHeader *) (writebuf[0]);
  342. strcpy(NFTLhdr->DataOrgID, "ANAND");
  343. NFTLhdr->NumEraseUnits = cpu_to_le16(part_size / meminfo.erasesize);
  344. NFTLhdr->FirstPhysicalEUN = cpu_to_le16(MediaUnit1);
  345. /* N.B. we reserve 2 more Erase Units for "folding" of Virtual Unit Chain */
  346. NFTLhdr->FormattedSize = cpu_to_le32(part_size - ( (5+bad_zones) * meminfo.erasesize));
  347. NFTLhdr->UnitSizeFactor = unit_factor;
  348. }
  349. /* Phase 2. Writing NFTL Media Headers and Bad Unit Table */
  350. printf("Phase 2.a Writing %s Media Header and Bad Unit Table\n", nftl);
  351. pwrite_nocheck(fd, writebuf[0], 512, MediaUnit1 * meminfo.erasesize + MediaUnitOff1);
  352. for (ezone = 0; ezone < (meminfo.size / meminfo.erasesize); ezone += 512) {
  353. pwrite_nocheck(fd, BadUnitTable + ezone, 512,
  354. (MediaUnit1 * meminfo.erasesize) + 512 * (1 + ezone / 512));
  355. }
  356. #if 0
  357. printf(" MediaHeader contents:\n");
  358. printf(" NumEraseUnits: %d\n", le16_to_cpu(NFTLhdr->NumEraseUnits));
  359. printf(" FirstPhysicalEUN: %d\n", le16_to_cpu(NFTLhdr->FirstPhysicalEUN));
  360. printf(" FormattedSize: %d (%d sectors)\n", le32_to_cpu(NFTLhdr->FormattedSize),
  361. le32_to_cpu(NFTLhdr->FormattedSize)/512);
  362. #endif
  363. printf("Phase 2.b Writing Spare %s Media Header and Spare Bad Unit Table\n", nftl);
  364. pwrite_nocheck(fd, writebuf[0], 512, MediaUnit2 * meminfo.erasesize + MediaUnitOff2);
  365. for (ezone = 0; ezone < (meminfo.size / meminfo.erasesize); ezone += 512) {
  366. pwrite_nocheck(fd, BadUnitTable + ezone, 512,
  367. (MediaUnit2 * meminfo.erasesize + MediaUnitOff2) + 512 * (1 + ezone / 512));
  368. }
  369. /* UCI #1 for newly erased Erase Unit */
  370. memset(oobbuf, 0xff, 16);
  371. oobbuf[11] = oobbuf[10] = oobbuf[9] = 0;
  372. oobbuf[8] = (do_inftl) ? 0x00 : 0x03;
  373. oobbuf[12] = oobbuf[14] = 0x69;
  374. oobbuf[13] = oobbuf[15] = 0x3c;
  375. /* N.B. The Media Header and Bad Erase Unit Table are considered as Free Erase Unit
  376. by M-System i.e. their Virtual Unit Number == 0xFFFF in the Unit Control Information #0,
  377. but their Block Status is BLOCK_USED (0x5555) in their Block Control Information */
  378. /* Phase 3. Writing Unit Control Information for each Erase Unit */
  379. printf("Phase 3. Writing Unit Control Information to each Erase Unit\n");
  380. for (ezone = MediaUnit1; ezone < (ezones + startofs / meminfo.erasesize); ezone++) {
  381. /* write UCI #1 to each Erase Unit */
  382. if (BadUnitTable[ezone] != ZONE_GOOD)
  383. continue;
  384. oob.start = (ezone * meminfo.erasesize) + 512 + (do_inftl * 512);
  385. if (ioctl(fd, MEMWRITEOOB, &oob))
  386. printf("MEMWRITEOOB at %lx: %s\n", (unsigned long)oob.start, strerror(errno));
  387. }
  388. exit(0);
  389. }