OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / user / mtd-utils / docfdisk.c
1 /*
2  * docfdisk.c: Modify INFTL partition tables
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
19 #define PROGRAM_NAME "docfdisk"
20
21 #define _XOPEN_SOURCE 500 /* for pread/pwrite */
22 #include <unistd.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <fcntl.h>
26 #include <time.h>
27 #include <sys/stat.h>
28 #include <sys/ioctl.h>
29 #include <sys/mount.h>
30 #include <errno.h>
31 #include <string.h>
32
33 #include <asm/types.h>
34 #include <mtd/mtd-user.h>
35 #include <mtd/inftl-user.h>
36 #include <mtd_swab.h>
37
38 unsigned char *buf;
39
40 mtd_info_t meminfo;
41 erase_info_t erase;
42 int fd;
43 struct INFTLMediaHeader *mh;
44
45 #define MAXSCAN 10
46
47 void show_header(int mhoffs) {
48         int i, unitsize, numunits, bmbits, numpart;
49         int start, end, num, nextunit;
50         unsigned int flags;
51         struct INFTLPartition *ip;
52
53         bmbits = le32_to_cpu(mh->BlockMultiplierBits);
54         printf("  bootRecordID          = %s\n"
55                         "  NoOfBootImageBlocks   = %d\n"
56                         "  NoOfBinaryPartitions  = %d\n"
57                         "  NoOfBDTLPartitions    = %d\n"
58                         "  BlockMultiplierBits   = %d\n"
59                         "  FormatFlags           = %d\n"
60                         "  OsakVersion           = %d.%d.%d.%d\n"
61                         "  PercentUsed           = %d\n",
62                         mh->bootRecordID, le32_to_cpu(mh->NoOfBootImageBlocks),
63                         le32_to_cpu(mh->NoOfBinaryPartitions),
64                         le32_to_cpu(mh->NoOfBDTLPartitions),
65                         bmbits,
66                         le32_to_cpu(mh->FormatFlags),
67                         ((unsigned char *) &mh->OsakVersion)[0] & 0xf,
68                         ((unsigned char *) &mh->OsakVersion)[1] & 0xf,
69                         ((unsigned char *) &mh->OsakVersion)[2] & 0xf,
70                         ((unsigned char *) &mh->OsakVersion)[3] & 0xf,
71                         le32_to_cpu(mh->PercentUsed));
72
73         numpart = le32_to_cpu(mh->NoOfBinaryPartitions) +
74                 le32_to_cpu(mh->NoOfBDTLPartitions);
75         unitsize = meminfo.erasesize >> bmbits;
76         numunits = meminfo.size / unitsize;
77         nextunit = mhoffs / unitsize;
78         nextunit++;
79         printf("Unitsize is %d bytes.  Device has %d units.\n",
80                         unitsize, numunits);
81         if (numunits > 32768) {
82                 printf("WARNING: More than 32768 units! Unexpectedly small BlockMultiplierBits.\n");
83         }
84         if (bmbits && (numunits <= 16384)) {
85                 printf("NOTICE: Unexpectedly large BlockMultiplierBits.\n");
86         }
87         for (i = 0; i < 4; i++) {
88                 ip = &(mh->Partitions[i]);
89                 flags = le32_to_cpu(ip->flags);
90                 start = le32_to_cpu(ip->firstUnit);
91                 end = le32_to_cpu(ip->lastUnit);
92                 num = le32_to_cpu(ip->virtualUnits);
93                 if (start < nextunit) {
94                         printf("ERROR: Overlapping or misordered partitions!\n");
95                 }
96                 if (start > nextunit) {
97                         printf("  Unpartitioned space: %d bytes\n"
98                                         "    virtualUnits  = %d\n"
99                                         "    firstUnit     = %d\n"
100                                         "    lastUnit      = %d\n",
101                                         (start - nextunit) * unitsize, start - nextunit,
102                                         nextunit, start - 1);
103                 }
104                 if (flags & INFTL_BINARY)
105                         printf("  Partition %d   (BDK):", i+1);
106                 else
107                         printf("  Partition %d  (BDTL):", i+1);
108                 printf(" %d bytes\n"
109                                 "    virtualUnits  = %d\n"
110                                 "    firstUnit     = %d\n"
111                                 "    lastUnit      = %d\n"
112                                 "    flags         = 0x%x\n"
113                                 "    spareUnits    = %d\n",
114                                 num * unitsize, num, start, end,
115                                 le32_to_cpu(ip->flags), le32_to_cpu(ip->spareUnits));
116                 if (num > (1 + end - start)) {
117                         printf("ERROR: virtualUnits not consistent with first/lastUnit!\n");
118                 }
119                 end++;
120                 if (end > nextunit)
121                         nextunit = end;
122                 if (flags & INFTL_LAST)
123                         break;
124         }
125         if (i >= 4) {
126                 printf("Odd.  Last partition was not marked with INFTL_LAST.\n");
127                 i--;
128         }
129         if ((i+1) != numpart) {
130                 printf("ERROR: Number of partitions != (NoOfBinaryPartitions + NoOfBDTLPartitions)\n");
131         }
132         if (nextunit > numunits) {
133                 printf("ERROR: Partitions appear to extend beyond end of device!\n");
134         }
135         if (nextunit < numunits) {
136                 printf("  Unpartitioned space: %d bytes\n"
137                                 "    virtualUnits  = %d\n"
138                                 "    firstUnit     = %d\n"
139                                 "    lastUnit      = %d\n",
140                                 (numunits - nextunit) * unitsize, numunits - nextunit,
141                                 nextunit, numunits - 1);
142         }
143 }
144
145
146 int main(int argc, char **argv)
147 {
148         int ret, i, mhblock, unitsize, block;
149         unsigned int nblocks[4], npart;
150         unsigned int totblocks;
151         struct INFTLPartition *ip;
152         unsigned char *oobbuf;
153         struct mtd_oob_buf oob;
154         char line[20];
155         int mhoffs;
156         struct INFTLMediaHeader *mh2;
157
158         if (argc < 2) {
159                 printf(
160                                 "Usage: %s <mtddevice> [<size1> [<size2> [<size3> [<size4]]]]\n"
161                                 "  Sizes are in device units (run with no sizes to show unitsize and current\n"
162                                 "  partitions).  Last size = 0 means go to end of device.\n",
163                                 PROGRAM_NAME);
164                 return 1;
165         }
166
167         npart = argc - 2;
168         if (npart > 4) {
169                 printf("Max 4 partitions allowed.\n");
170                 return 1;
171         }
172
173         for (i = 0; i < npart; i++) {
174                 nblocks[i] = strtoul(argv[2+i], NULL, 0);
175                 if (i && !nblocks[i-1]) {
176                         printf("No sizes allowed after 0\n");
177                         return 1;
178                 }
179         }
180
181         // Open and size the device
182         if ((fd = open(argv[1], O_RDWR)) < 0) {
183                 perror("Open flash device");
184                 return 1;
185         }
186
187         if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
188                 perror("ioctl(MEMGETINFO)");
189                 return 1;
190         }
191
192         printf("Device size is %d bytes.  Erasesize is %d bytes.\n",
193                         meminfo.size, meminfo.erasesize);
194
195         buf = malloc(meminfo.erasesize);
196         oobbuf = malloc((meminfo.erasesize / meminfo.writesize) * meminfo.oobsize);
197         if (!buf || !oobbuf) {
198                 printf("Can't malloc block buffer\n");
199                 return 1;
200         }
201         oob.length = meminfo.oobsize;
202
203         mh = (struct INFTLMediaHeader *) buf;
204
205         for (mhblock = 0; mhblock < MAXSCAN; mhblock++) {
206                 if ((ret = pread(fd, buf, meminfo.erasesize, mhblock * meminfo.erasesize)) < 0) {
207                         if (errno == EBADMSG) {
208                                 printf("ECC error at eraseblock %d\n", mhblock);
209                                 continue;
210                         }
211                         perror("Read eraseblock");
212                         return 1;
213                 }
214                 if (ret != meminfo.erasesize) {
215                         printf("Short read!\n");
216                         return 1;
217                 }
218                 if (!strcmp("BNAND", mh->bootRecordID)) break;
219         }
220         if (mhblock >= MAXSCAN) {
221                 printf("Unable to find INFTL Media Header\n");
222                 return 1;
223         }
224         printf("Found INFTL Media Header at block %d:\n", mhblock);
225         mhoffs = mhblock * meminfo.erasesize;
226
227         oob.ptr = oobbuf;
228         oob.start = mhoffs;
229         for (i = 0; i < meminfo.erasesize; i += meminfo.writesize) {
230                 if (ioctl(fd, MEMREADOOB, &oob)) {
231                         perror("ioctl(MEMREADOOB)");
232                         return 1;
233                 }
234                 oob.start += meminfo.writesize;
235                 oob.ptr += meminfo.oobsize;
236         }
237
238         show_header(mhoffs);
239
240         if (!npart)
241                 return 0;
242
243         printf("\n"
244                         "-------------------------------------------------------------------------\n");
245
246         unitsize = meminfo.erasesize >> le32_to_cpu(mh->BlockMultiplierBits);
247         totblocks = meminfo.size / unitsize;
248         block = mhoffs / unitsize;
249         block++;
250
251         mh->NoOfBDTLPartitions = 0;
252         mh->NoOfBinaryPartitions = npart;
253
254         for (i = 0; i < npart; i++) {
255                 ip = &(mh->Partitions[i]);
256                 ip->firstUnit = cpu_to_le32(block);
257                 if (!nblocks[i])
258                         nblocks[i] = totblocks - block;
259                 ip->virtualUnits = cpu_to_le32(nblocks[i]);
260                 block += nblocks[i];
261                 ip->lastUnit = cpu_to_le32(block-1);
262                 ip->spareUnits = 0;
263                 ip->flags = cpu_to_le32(INFTL_BINARY);
264         }
265         if (block > totblocks) {
266                 printf("Requested partitions extend beyond end of device.\n");
267                 return 1;
268         }
269         ip->flags = cpu_to_le32(INFTL_BINARY | INFTL_LAST);
270
271         /* update the spare as well */
272         mh2 = (struct INFTLMediaHeader *) (buf + 4096);
273         memcpy((void *) mh2, (void *) mh, sizeof(struct INFTLMediaHeader));
274
275         printf("\nProposed new Media Header:\n");
276         show_header(mhoffs);
277
278         printf("\nReady to update device.  Type 'yes' to proceed, anything else to abort: ");
279         fgets(line, sizeof(line), stdin);
280         if (strcmp("yes\n", line))
281                 return 0;
282         printf("Updating MediaHeader...\n");
283
284         erase.start = mhoffs;
285         erase.length = meminfo.erasesize;
286         if (ioctl(fd, MEMERASE, &erase)) {
287                 perror("ioctl(MEMERASE)");
288                 printf("Your MediaHeader may be hosed.  UHOH!\n");
289                 return 1;
290         }
291
292         oob.ptr = oobbuf;
293         oob.start = mhoffs;
294         for (i = 0; i < meminfo.erasesize; i += meminfo.writesize) {
295                 memset(oob.ptr, 0xff, 6); // clear ECC.
296                 if (ioctl(fd, MEMWRITEOOB, &oob)) {
297                         perror("ioctl(MEMWRITEOOB)");
298                         printf("Your MediaHeader may be hosed.  UHOH!\n");
299                         return 1;
300                 }
301                 if ((ret = pwrite(fd, buf, meminfo.writesize, oob.start)) < 0) {
302                         perror("Write page");
303                         printf("Your MediaHeader may be hosed.  UHOH!\n");
304                         return 1;
305                 }
306                 if (ret != meminfo.writesize) {
307                         printf("Short write!\n");
308                         printf("Your MediaHeader may be hosed.  UHOH!\n");
309                         return 1;
310                 }
311
312                 oob.start += meminfo.writesize;
313                 oob.ptr += meminfo.oobsize;
314                 buf += meminfo.writesize;
315         }
316
317         printf("Success.  REBOOT or unload the diskonchip module to update partitions!\n");
318         return 0;
319 }