/*
 * nftldump.c: Dumping the content of NFTL partitions on a "Physical Disk"
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * ToDo:
 *	1. UnitSizeFactor != 0xFF cases
 *	2. test, test, and test !!!
 */

#define _XOPEN_SOURCE 500 /* For pread */

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>

#include <sys/ioctl.h>
#include <asm/types.h>
#include <mtd/mtd-user.h>
#include <mtd/nftl-user.h>
#include <mtd_swab.h>

static struct NFTLMediaHeader MedHead[2];
static mtd_info_t meminfo;

static struct nftl_oob oobbuf;
static struct mtd_oob_buf oob = {0, 16, (unsigned char *)&oobbuf};

static int fd, ofd = -1;;
static int NumMedHeads;

static unsigned char BadUnitTable[MAX_ERASE_ZONES];

#if __BYTE_ORDER == __LITTLE_ENDIAN
#define SWAP16(x) do { ; } while(0)
#define SWAP32(x) do { ; } while(0)
#else
#define SWAP16(x) do { x = swab16(x); } while(0)
#define SWAP32(x) do { x = swab32(x); } while(0)
#endif

/* VUCtable, store the Erase Unit Number of the first Erase Unit in the chain */
static unsigned short *VUCtable;

/* FixMe: make this dynamic allocated */
#define ERASESIZE 0x2000
#define NUMVUNITS ((40*1024*1024) / ERASESIZE)
static union nftl_uci UCItable[NUMVUNITS][3];

static unsigned short nextEUN(unsigned short curEUN)
{
	return UCItable[curEUN][0].a.ReplUnitNum;
}

static unsigned int find_media_headers(void)
{
	int i;
	static unsigned long ofs = 0;

	NumMedHeads = 0;
	while (ofs < meminfo.size) {
		pread(fd, &MedHead[NumMedHeads], sizeof(struct NFTLMediaHeader), ofs);
		if (!strncmp(MedHead[NumMedHeads].DataOrgID, "ANAND", 6)) {
			SWAP16(MedHead[NumMedHeads].NumEraseUnits);
			SWAP16(MedHead[NumMedHeads].FirstPhysicalEUN);
			SWAP32(MedHead[NumMedHeads].FormattedSize);

			if (NumMedHeads == 0) {
				printf("NFTL Media Header found at offset 0x%08lx:\n", ofs);
				printf("NumEraseUnits:    %d\n",
						MedHead[NumMedHeads].NumEraseUnits);
				printf("FirstPhysicalEUN: %d\n",
						MedHead[NumMedHeads].FirstPhysicalEUN);
				printf("Formatted Size:   %d\n",
						MedHead[NumMedHeads].FormattedSize);
				printf("UnitSizeFactor:   0x%x\n",
						MedHead[NumMedHeads].UnitSizeFactor);

				/* read BadUnitTable, I don't know why pread() does not work for
				   larger (7680 bytes) chunks */
				for (i = 0; i < MAX_ERASE_ZONES; i += 512)
					pread(fd, &BadUnitTable[i], 512, ofs + 512 + i);
			} else
				printf("Second NFTL Media Header found at offset 0x%08lx\n",ofs);
			NumMedHeads++;
		}

		ofs += meminfo.erasesize;
		if (NumMedHeads == 2) {
			if (strncmp((char *)&MedHead[0], (char *)&MedHead[1], sizeof(struct NFTLMediaHeader)) != 0) {
				printf("warning: NFTL Media Header is not consistent with "
						"Spare NFTL Media Header\n");
			}
			break;
		}
	}

	/* allocate Virtual Unit Chain table for this NFTL partition */
	VUCtable = calloc(MedHead[0].NumEraseUnits, sizeof(unsigned short));
	return NumMedHeads;
}

static void dump_erase_units(void)
{
	int i, j;
	unsigned long ofs;

	for (i = MedHead[0].FirstPhysicalEUN; i < MedHead[0].FirstPhysicalEUN +
			MedHead[0].NumEraseUnits; i++) {
		/* For each Erase Unit */
		ofs = i * meminfo.erasesize;

		/* read the Unit Control Information */
		for (j = 0; j < 3; j++) {
			oob.start = ofs + (j * 512);
			if (ioctl(fd, MEMREADOOB, &oob))
				printf("MEMREADOOB at %lx: %s\n",
						(unsigned long) oob.start, strerror(errno));
			memcpy(&UCItable[i][j], &oobbuf.u, 8);
		}
		if (UCItable[i][1].b.EraseMark != cpu_to_le16(0x3c69)) {
			printf("EraseMark not present in unit %d: %x\n",
					i, UCItable[i][1].b.EraseMark);
		} else {
			/* a properly formatted unit */
			SWAP16(UCItable[i][0].a.VirtUnitNum);
			SWAP16(UCItable[i][0].a.ReplUnitNum);
			SWAP16(UCItable[i][0].a.SpareVirtUnitNum);
			SWAP16(UCItable[i][0].a.SpareReplUnitNum);
			SWAP32(UCItable[i][1].b.WearInfo);
			SWAP16(UCItable[i][1].b.EraseMark);
			SWAP16(UCItable[i][1].b.EraseMark1);
			SWAP16(UCItable[i][2].c.FoldMark);
			SWAP16(UCItable[i][2].c.FoldMark1);

			if (!(UCItable[i][0].a.VirtUnitNum & 0x8000)) {
				/* If this is the first in a chain, store the EUN in the VUC table */
				if (VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff]) {
					printf("Duplicate start of chain for VUC %d: "
							"Unit %d replaces Unit %d\n",
							UCItable[i][0].a.VirtUnitNum & 0x7fff,
							i, VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff]);
				}
				VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff] = i;
			}
		}

		switch (BadUnitTable[i]) {
			case ZONE_BAD_ORIGINAL:
				printf("Unit %d is marked as ZONE_BAD_ORIGINAL\n", i);
				continue;
			case ZONE_BAD_MARKED:
				printf("Unit %d is marked as ZONE_BAD_MARKED\n", i);
				continue;
		}

		/* ZONE_GOOD */
		if (UCItable[i][0].a.VirtUnitNum == 0xffff)
			printf("Unit %d is free\n", i);
		else
			printf("Unit %d is in chain %d and %s a replacement\n", i,
					UCItable[i][0].a.VirtUnitNum & 0x7fff,
					UCItable[i][0].a.VirtUnitNum & 0x8000 ? "is" : "is not");
	}
}

static void dump_virtual_units(void)
{
	int i, j;
	char readbuf[512];

	for (i = 0; i < (MedHead[0].FormattedSize / meminfo.erasesize); i++) {
		unsigned short curEUN = VUCtable[i];

		printf("Virtual Unit #%d: ", i);
		if (!curEUN) {
			printf("Not present\n");
			continue;
		}
		printf("%d", curEUN);

		/* walk through the Virtual Unit Chain */
		while ((curEUN = nextEUN(curEUN)) != 0xffff) {
			printf(", %d", curEUN & 0x7fff);
		}
		printf("\n");

		if (ofd != -1) {
			/* Actually write out the data */
			for (j = 0; j < meminfo.erasesize / 512; j++) {
				/* For each sector in the block */
				unsigned short lastgoodEUN = 0xffff, thisEUN = VUCtable[i];
				unsigned int status;

				if (thisEUN == 0xffff) thisEUN = 0;

				while (thisEUN && (thisEUN & 0x7fff) != 0x7fff) {
					oob.start = (thisEUN * ERASESIZE) + (j * 512);
					ioctl(fd, MEMREADOOB, &oob);
					status = oobbuf.b.Status | oobbuf.b.Status1;

					switch (status) {
						case SECTOR_FREE:
							/* This is still free. Don't look any more */
							thisEUN = 0;
							break;

						case SECTOR_USED:
							/* SECTOR_USED. This is a good one. */
							lastgoodEUN = thisEUN;
							break;
					}

					/* Find the next erase unit in this chain, if any */
					if (thisEUN)
						thisEUN = nextEUN(thisEUN) & 0x7fff;
				}

				if (lastgoodEUN == 0xffff)
					memset(readbuf, 0, 512);
				else
					pread(fd, readbuf, 512,
							(lastgoodEUN * ERASESIZE) + (j * 512));

				write(ofd, readbuf, 512);
			}

		}
	}
}

int main(int argc, char **argv)
{
	if (argc < 2) {
		printf("Usage: %s <device> [<outfile>]\n", argv[0]);
		exit(1);
	}
	fd = open(argv[1], O_RDONLY);
	if (fd == -1) {
		perror("open flash");
		exit (1);
	}

	if (argc > 2) {
		ofd = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0644);
		if (ofd == -1)
			perror ("open outfile");
	}

	/* get size information of the MTD device */
	if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
		perror("ioctl(MEMGETINFO)");
		close(fd);
		return 1;
	}

	while (find_media_headers() != 0) {
		dump_erase_units();
		dump_virtual_units();
		free(VUCtable);
	}

	exit(0);
}
