25IRX_ID(
"hdck", APA_MODVER_MAJOR, APA_MODVER_MINOR);
30static int HdckDevctl(
iomanX_iop_file_t *fd,
const char *name,
int cmd,
void *arg,
unsigned int arglen,
void *buf,
unsigned int buflen);
32static u8 IOBuffer[128 * 512];
33static u8 IOBuffer2[128 * 512];
35IOMANX_RETURN_VALUE_IMPL(0);
36IOMANX_RETURN_VALUE_IMPL(
EPERM);
40 IOMANX_RETURN_VALUE(0),
41 IOMANX_RETURN_VALUE(
EPERM),
42 IOMANX_RETURN_VALUE(
EPERM),
43 IOMANX_RETURN_VALUE(
EPERM),
44 IOMANX_RETURN_VALUE(
EPERM),
45 IOMANX_RETURN_VALUE(
EPERM),
46 IOMANX_RETURN_VALUE(
EPERM),
47 IOMANX_RETURN_VALUE(
EPERM),
48 IOMANX_RETURN_VALUE(
EPERM),
49 IOMANX_RETURN_VALUE(
EPERM),
50 IOMANX_RETURN_VALUE(
EPERM),
51 IOMANX_RETURN_VALUE(
EPERM),
52 IOMANX_RETURN_VALUE(
EPERM),
53 IOMANX_RETURN_VALUE(
EPERM),
54 IOMANX_RETURN_VALUE(
EPERM),
55 IOMANX_RETURN_VALUE(
EPERM),
56 IOMANX_RETURN_VALUE(
EPERM),
57 IOMANX_RETURN_VALUE(
EPERM),
58 IOMANX_RETURN_VALUE(
EPERM),
59 IOMANX_RETURN_VALUE(
EPERM),
60 IOMANX_RETURN_VALUE(
EPERM),
61 IOMANX_RETURN_VALUE_S64(
EPERM),
63 IOMANX_RETURN_VALUE(
EPERM),
64 IOMANX_RETURN_VALUE(
EPERM),
65 IOMANX_RETURN_VALUE(
EPERM),
87 u32 ErrorPartitionLBA;
88 u32 ErrorPartition2LBA;
89 u32 ErrorPartitionPrevLBA;
90 u32 ErrorPartition2PrevLBA;
110#ifdef HDCK_CHECK_CROSSLINK
111static int AddPartitionToList(u32 *list,
unsigned int *pCount, u32 sector)
116 for (i = 0; i < *pCount; i++) {
117 if (list[i] == sector) {
127 APA_PRINTF(
"found cross-linked partition: 0x%lx\n", sector);
135static int CheckAPAPartitionLinks(
int device,
apa_cache_t *clink)
138#ifdef HDCK_CHECK_CROSSLINK
139 unsigned int partitions;
142 u32 CurrentLBA, ParentLBA;
144 APA_PRINTF(
"scan partitions.\n");
147 PrivateData.ErrorPartition2LBA = 0;
148 PrivateData.ErrorPartitionLBA = 0;
149 PrivateData.ErrorPartition2PrevLBA = 0;
150 PrivateData.ErrorPartitionPrevLBA = 0;
153#ifdef HDCK_CHECK_CROSSLINK
156 CurrentLBA = clink->header->next;
157 while (CurrentLBA != 0
158#ifdef HDCK_CHECK_CROSSLINK
159 && ((result = AddPartitionToList((u32 *)IOBuffer, &partitions, CurrentLBA)) >= 0)
161 && (clink2 = apaCacheGetHeader(device, CurrentLBA, 0, &result)) != NULL) {
162 if (clink2->header->prev != ParentLBA) {
163 APA_PRINTF(
"found invalid previous partition address, fix it.\n");
164 clink2->header->prev = ParentLBA;
165 clink2->flags |= APA_CACHE_FLAG_DIRTY;
166 apaCacheFlushAllDirty(device);
169 ParentLBA = clink2->header->start;
170 CurrentLBA = clink2->header->next;
171 apaCacheFree(clink2);
175 if (clink->header->prev != ParentLBA) {
176 APA_PRINTF(
"found invalid last partition address, fix it.\n");
177 clink->header->prev = ParentLBA;
178 clink->flags |= APA_CACHE_FLAG_DIRTY;
179 apaCacheFlushAllDirty(device);
182 APA_PRINTF(
"we do not have an error partition.\n");
184 APA_PRINTF(
"found error partition.\n");
186 PrivateData.ErrorPartitionLBA = CurrentLBA;
187 PrivateData.ErrorPartitionPrevLBA = ParentLBA;
190 CurrentLBA = clink->header->prev;
192#ifdef HDCK_CHECK_CROSSLINK
195 while (CurrentLBA != 0
196#ifdef HDCK_CHECK_CROSSLINK
197 && ((result = AddPartitionToList((u32 *)IOBuffer, &partitions, CurrentLBA)) >= 0)
199 && (clink2 = apaCacheGetHeader(device, CurrentLBA, 0, &result)) != NULL) {
200 if (clink2->header->next != ParentLBA) {
201 APA_PRINTF(
"found invalid next partition address, fix it.\n");
203 clink2->header->next = ParentLBA;
204 clink2->flags |= APA_CACHE_FLAG_DIRTY;
205 apaCacheFlushAllDirty(device);
208 ParentLBA = clink2->header->start;
209 CurrentLBA = clink2->header->prev;
210 apaCacheFree(clink2);
214 if (clink->header->next != ParentLBA) {
215 APA_PRINTF(
"found invalid first partition address, fix it.\n");
216 clink->header->next = ParentLBA;
217 clink->flags |= APA_CACHE_FLAG_DIRTY;
218 apaCacheFlushAllDirty(device);
221 APA_PRINTF(
"found inconsistency, but already fixed.\n");
222 APA_PRINTF(
"we do not have an error partition.\n");
224 PrivateData.ErrorPartitionLBA = 0;
226 APA_PRINTF(
"found error partition.\n");
228 PrivateData.ErrorPartition2LBA = CurrentLBA;
229 PrivateData.ErrorPartition2PrevLBA = ParentLBA;
233 return PrivateData.ErrorPartitionLBA;
236static void EraseSector(
int unit,
void *buffer, u32 lba)
238 memset(buffer, 0, 512);
239 sceAtaDmaTransfer(unit, buffer, lba, 1, ATA_DIR_WRITE);
240 sceAtaFlushCache(unit);
243static void RemoveBadPartitions(
int device,
apa_cache_t *clink)
248 APA_PRINTF(
"remove all partitions after unreadable one.\n");
250 if ((clink2 = apaCacheGetHeader(device, PrivateData.ErrorPartitionPrevLBA, 0, &result)) != NULL) {
251 clink2->header->next = 0;
252 clink->header->prev = PrivateData.ErrorPartitionPrevLBA;
253 clink2->header->flags |= APA_CACHE_FLAG_DIRTY;
254 clink->header->flags |= APA_CACHE_FLAG_DIRTY;
256 apaCacheFlushAllDirty(device);
257 apaCacheFree(clink2);
259 PrivateData.ErrorPartition2LBA = 0;
260 PrivateData.ErrorPartitionLBA = 0;
264static void RecoverSubPartition(
apa_cache_t *clink, u32 lba, u32 previous, u32 sublength, u32 substart, u16 type,
int sub)
269 clink2 = apaCacheGetHeader(clink->device, lba, 1, &result);
271 APA_PRINTF(
"found this sub partition's main, so I recover it.\n");
274 clink2->header->magic = APA_MAGIC;
275 clink2->header->start = lba;
276 if (lba < clink->header->prev) {
277 clink2->header->next = lba + sublength;
279 clink2->header->prev = previous;
280 clink2->header->length = sublength;
281 clink2->header->type = type;
283 clink2->header->main = substart;
284 clink2->header->number = sub;
286 apaGetTime(&clink2->header->created);
288 clink2->flags |= APA_CACHE_FLAG_DIRTY;
290 apaCacheFlushAllDirty(clink->device);
291 apaCacheFree(clink2);
295static void RecoverPartitionIfSub(
int device,
apa_cache_t *clink)
297 int result,
count, sub;
302 APA_PRINTF(
"check if error partition is belong to someone as sub partition.\n");
306 if ((NextPartSector = clink->header->next) != 0 && PrivateData.ErrorPartitionLBA != clink->header->next) {
307 while ((clink2 = apaCacheGetHeader(device, NextPartSector, 0, &result)) != NULL) {
308 if (clink2->header->type && !(clink2->header->flags &
APA_FLAG_SUB)) {
309 for (
count = 1, sub = 0, pSubs = clink2->header->subs; (u32)sub < clink2->header->nsub; sub++, pSubs++,
count++) {
310 if (PrivateData.ErrorPartitionLBA && pSubs->start == PrivateData.ErrorPartitionLBA) {
311 RecoverSubPartition(clink, PrivateData.ErrorPartitionLBA, PrivateData.ErrorPartitionPrevLBA, pSubs->length, clink2->header->start, clink2->header->type,
count);
313 if (PrivateData.ErrorPartition2LBA == PrivateData.ErrorPartitionLBA) {
314 PrivateData.ErrorPartition2LBA = 0;
316 PrivateData.ErrorPartitionLBA = 0;
319 if (PrivateData.ErrorPartition2LBA && pSubs->start == PrivateData.ErrorPartition2LBA) {
320 RecoverSubPartition(clink, PrivateData.ErrorPartition2LBA, PrivateData.ErrorPartitionLBA, pSubs->length, clink2->header->start, clink2->header->type,
count);
322 PrivateData.ErrorPartition2LBA = 0;
327 NextPartSector = clink2->header->next;
328 apaCacheFree(clink2);
330 if (!PrivateData.ErrorPartitionLBA && !PrivateData.ErrorPartition2LBA) {
334 if (!NextPartSector || NextPartSector == PrivateData.ErrorPartitionLBA) {
342 if ((NextPartSector = clink->header->prev) != 0 && clink->header->prev != PrivateData.ErrorPartition2LBA) {
343 while ((clink2 = apaCacheGetHeader(device, NextPartSector, 0, &result)) != NULL) {
344 if (clink2->header->type && !(clink2->header->flags &
APA_FLAG_SUB)) {
345 for (
count = 1, sub = 0, pSubs = clink2->header->subs; (u32)sub < clink2->header->nsub; sub++, pSubs++,
count++) {
346 if (PrivateData.ErrorPartitionLBA && pSubs->start == PrivateData.ErrorPartitionLBA) {
347 RecoverSubPartition(clink, PrivateData.ErrorPartitionLBA, PrivateData.ErrorPartitionPrevLBA, pSubs->length, clink2->header->start, clink2->header->type,
count);
349 if (PrivateData.ErrorPartition2LBA == PrivateData.ErrorPartitionLBA) {
350 PrivateData.ErrorPartition2LBA = 0;
352 PrivateData.ErrorPartitionLBA = 0;
355 if (PrivateData.ErrorPartition2LBA && pSubs->start == PrivateData.ErrorPartition2LBA) {
356 RecoverSubPartition(clink, PrivateData.ErrorPartition2LBA, PrivateData.ErrorPartitionLBA, pSubs->length, clink2->header->start, clink2->header->type,
count);
358 PrivateData.ErrorPartition2LBA = 0;
363 NextPartSector = clink2->header->prev;
364 apaCacheFree(clink2);
366 if (!PrivateData.ErrorPartitionLBA && !PrivateData.ErrorPartition2LBA) {
370 if (!NextPartSector || NextPartSector == PrivateData.ErrorPartitionLBA) {
380 u32 minsize = 0x3FFFF;
381#ifdef APA_8MB_PARTITION_SIZE
385 for (length >>= 1; minsize < length; length >>= 1) {
386 if (lba % length == 0) {
387 result = apaRemovePartition(clink->device, lba, lba + length, clink->header->start, length);
388 clink->header->next = lba;
389 clink->flags |= APA_CACHE_FLAG_DIRTY;
390 apaCacheFlushAllDirty(clink->device);
400static void MarkUnreadablePartionAsEmpty(
int device, u32 lba, u32 parent, u32 length)
407 clink = apaCacheGetHeader(device, parent, 0, &result);
408 APA_PRINTF(
"make unreadable partition as empty.\n");
411 while (length != 0) {
414 for (i = 31; i >= 0; i--) {
415 if ((new_length = ((u32)1) << i) & length) {
420 if (lba % new_length) {
421 clink = apaCreateAlignedEmptyPartition(clink, lba, new_length);
423 apaRemovePartition(device, lba, lba + new_length, clink->header->start, new_length);
424 clink->header->next = lba;
425 clink->flags |= APA_CACHE_FLAG_DIRTY;
426 apaCacheFlushAllDirty(device);
430 length -= clink->header->length;
434 PrivateData.ErrorPartition2LBA = 0;
435 PrivateData.ErrorPartitionLBA = 0;
439static void DeleteFreePartitions(
int device,
apa_cache_t *clink)
445 sector = clink->header->next;
446 while (sector != 0 && (clink2 = apaCacheGetHeader(device, sector, 0, &result)) != NULL) {
447 if (clink2->header->type == 0) {
448 if ((clink2 = apaDeleteFixPrev(clink2, &result)) == NULL) {
453 sector = clink2->header->next;
454 apaCacheFree(clink2);
459static int ReadPartitionMap(
int device,
apa_cache_t *clink,
int *pMainCount,
int *pSubCount)
463 u32 sector, *MainMap, *SubMap;
468 sector = clink->header->next;
469 MainMap = (u32 *)IOBuffer;
470 SubMap = (u32 *)IOBuffer2;
471 while (sector != 0) {
472 if ((clink2 = apaCacheGetHeader(device, sector, 0, &result)) != NULL) {
473 if (clink2->header->type) {
475 APA_PRINTF(
"main, start %08lx, nsector %08lx, nsub %ld, id %s\n", clink2->header->start, clink2->header->length, clink2->header->nsub, clink2->header->id);
477 MainMap[(*pMainCount)] = clink2->header->start;
480 if (clink2->header->type && clink2->header->flags &
APA_FLAG_SUB) {
481 APA_PRINTF(
"sub , start %08lx, nsector %08lx, num %2ld, main %08lx\n", clink2->header->start, clink2->header->length, clink2->header->number, clink2->header->main);
482 SubMap[(*pSubCount)] = clink2->header->start;
487 sector = clink2->header->next;
488 apaCacheFree(clink2);
498static int CheckPartitions(
int device,
apa_cache_t *clink)
500 int result, MainCount, SubCount;
502 if ((result = ReadPartitionMap(device, clink, &MainCount, &SubCount)) == 0) {
506 APA_PRINTF(
"check main partitions.\n");
508 for (i = 0; i < MainCount && result == 0; i++) {
509 if ((clink2 = apaCacheGetHeader(device, ((u32 *)IOBuffer)[i], 0, &result)) != NULL) {
510 int missing_sub_found;
514 for (missing_sub_found = 0, sub = 0, pSubs = clink2->header->subs; (u32)sub < clink2->header->nsub; sub++, pSubs++) {
518 if (pSubs->start == ((u32 *)IOBuffer2)[
count]) {
526 APA_PRINTF(
"missing sub partition found.\n");
528 if (!missing_sub_found) {
529 clink2->header->nsub = sub;
530 clink2->flags |= APA_CACHE_FLAG_DIRTY;
531 missing_sub_found = 1;
532 apaCacheFlushAllDirty(device);
536 if (missing_sub_found) {
537 APA_PRINTF(
"remove sub partition follows missing partition.\n");
539 if ((clink_sub = apaCacheGetHeader(device, pSubs->start, 0, &result)) != NULL) {
540 result = apaDelete(clink_sub);
546 apaCacheFree(clink2);
551 if ((result = ReadPartitionMap(device, clink, &MainCount, &SubCount)) == 0) {
554 APA_PRINTF(
"check sub partitions.\n");
556 for (sub = 0, ptr = (u32 *)IOBuffer2; sub < SubCount && result == 0; ptr++, sub++) {
558 if ((clink2 = apaCacheGetHeader(device, *ptr, 0, &result)) != NULL) {
559 for (i = 0; ((u32 *)IOBuffer)[i] != clink2->header->main && i < MainCount; i++)
562 if (MainCount == i) {
563 APA_PRINTF(
"this sub(start = %08lx)is not belong to anyone, remove it.\n", clink2->header->start);
564 if ((result = apaDelete(clink2)) != 0) {
565 APA_PRINTF(
"remove partition failed.\n");
569 if ((clink_sub = apaCacheGetHeader(device, clink2->header->main, 0, &result)) != NULL) {
571 if (clink_sub->header->subs[
count].start == *ptr) {
576 if (clink_sub->header->nsub == (u32)
count) {
577 APA_PRINTF(
"this subpartition is not belong to sub list.\n");
579 apaCacheFree(clink_sub);
581 apaCacheFree(clink_sub);
582 apaCacheFree(clink2);
585 apaCacheFree(clink2);
599static int HdckDevctl(
iomanX_iop_file_t *fd,
const char *name,
int cmd,
void *arg,
unsigned int arglen,
void *buf,
unsigned int buflen)
601 int result, badParts;
611 if (PrivateData.HddInfo[fd->unit].status != 0) {
615 if ((clink = apaCacheGetHeader(fd->unit, APA_SECTOR_MBR, 0, &result)) != NULL) {
617 while (CheckAPAPartitionLinks(fd->unit, clink) != 0) {
619 if (PrivateData.ErrorPartitionLBA == PrivateData.ErrorPartition2LBA) {
620 APA_PRINTF(
"only one partition has problem, try to fix it.\n");
621 RecoverPartitionIfSub(fd->unit, clink);
624 if (PrivateData.ErrorPartitionLBA && PrivateData.ErrorPartition2LBA) {
626 if (clink->header->prev != PrivateData.ErrorPartitionLBA) {
627 MarkUnreadablePartionAsEmpty(fd->unit, PrivateData.ErrorPartitionLBA, PrivateData.ErrorPartitionPrevLBA, PrivateData.ErrorPartition2PrevLBA - PrivateData.ErrorPartitionLBA);
629 RemoveBadPartitions(fd->unit, clink);
635 }
else if (PrivateData.ErrorPartitionLBA < PrivateData.ErrorPartition2LBA) {
636 APA_PRINTF(
"two or more partitions have problem, try to fix it.\n");
638 RecoverPartitionIfSub(fd->unit, clink);
641 if (PrivateData.ErrorPartitionLBA && PrivateData.ErrorPartition2LBA) {
643 if (clink->header->prev != PrivateData.ErrorPartitionLBA && clink->header->prev != PrivateData.ErrorPartition2LBA) {
644 MarkUnreadablePartionAsEmpty(fd->unit, PrivateData.ErrorPartitionLBA, PrivateData.ErrorPartitionPrevLBA, PrivateData.ErrorPartition2PrevLBA - PrivateData.ErrorPartitionLBA);
646 RemoveBadPartitions(fd->unit, clink);
653 APA_PRINTF(
"partition table completely inconsistent.\n");
654 RemoveBadPartitions(fd->unit, clink);
664 EraseSector(fd->unit, IOBuffer, APA_SECTOR_SECTOR_ERROR);
665 DeleteFreePartitions(fd->unit, clink);
666 result = CheckPartitions(fd->unit, clink);
670 APA_PRINTF(
"done\n");
672 APA_PRINTF(
"cannot read mbr partition, I cannot continue.\n");
678int APA_ENTRYPOINT(
int argc,
char **argv)
687 if (apaGetTime(&time) != 0) {
688 APA_PRINTF(
"error: could not get date\n");
689 return MODULE_NO_RESIDENT_END;
692 APA_PRINTF(
"%02d:%02d:%02d %02d/%02d/%d\n", time.hour, time.min, time.sec, time.month, time.day, time.year);
694 for (i = 0; i < 2; i++) {
695 if ((pDevInfo = sceAtaInit(i)) == NULL) {
696 APA_PRINTF(
"error: ata initialization failed.\n");
697 return MODULE_NO_RESIDENT_END;
701 PrivateData.HddInfo[i].status--;
704 PrivateData.HddInfo[i].MaxPartSize = apaGetPartitionMax(pDevInfo->
total_sectors);
705 if (HdckUnlockHdd(i) == 0) {
706 PrivateData.HddInfo[i].status--;
709 APA_PRINTF(
"disk%d: 0x%08lx sectors, max 0x%08lx\n", i, PrivateData.HddInfo[i].sectors, PrivateData.HddInfo[i].MaxPartSize);
714 for (i = 0; i < 2; i++) {
715 if (PrivateData.HddInfo[i].status < 2) {
716 if (apaJournalRestore(i) != 0) {
717 return MODULE_NO_RESIDENT_END;
720 if (apaGetFormat(i, (
int *)&PrivateData.HddInfo[i].format)) {
721 PrivateData.HddInfo[i].status--;
726 iomanX_DelDrv(HdckDevice.name);
727 if (iomanX_AddDrv(&HdckDevice) == 0) {
728 APA_PRINTF(
"driver start.\n");
729 return MODULE_RESIDENT_END;
732 return MODULE_NO_RESIDENT_END;
u32 count
start sector of fragmented bd/file