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) {
381 for (length >>= 1; 0x0003FFFF < length; length >>= 1) {
382 if (lba % length == 0) {
383 result = apaRemovePartition(clink->device, lba, lba + length, clink->header->start, length);
384 clink->header->next = lba;
385 clink->flags |= APA_CACHE_FLAG_DIRTY;
386 apaCacheFlushAllDirty(clink->device);
396static void MarkUnreadablePartionAsEmpty(
int device, u32 lba, u32 parent, u32 length)
403 clink = apaCacheGetHeader(device, parent, 0, &result);
404 APA_PRINTF(
"make unreadable partition as empty.\n");
407 while (length != 0) {
410 for (i = 31; i >= 0; i--) {
411 if ((new_length = ((u32)1) << i) & length) {
416 if (lba % new_length) {
417 clink = apaCreateAlignedEmptyPartition(clink, lba, new_length);
419 apaRemovePartition(device, lba, lba + new_length, clink->header->start, new_length);
420 clink->header->next = lba;
421 clink->flags |= APA_CACHE_FLAG_DIRTY;
422 apaCacheFlushAllDirty(device);
426 length -= clink->header->length;
430 PrivateData.ErrorPartition2LBA = 0;
431 PrivateData.ErrorPartitionLBA = 0;
435static void DeleteFreePartitions(
int device,
apa_cache_t *clink)
441 sector = clink->header->next;
442 while (sector != 0 && (clink2 = apaCacheGetHeader(device, sector, 0, &result)) != NULL) {
443 if (clink2->header->type == 0) {
444 if ((clink2 = apaDeleteFixPrev(clink2, &result)) == NULL) {
449 sector = clink2->header->next;
450 apaCacheFree(clink2);
455static int ReadPartitionMap(
int device,
apa_cache_t *clink,
int *pMainCount,
int *pSubCount)
459 u32 sector, *MainMap, *SubMap;
464 sector = clink->header->next;
465 MainMap = (u32 *)IOBuffer;
466 SubMap = (u32 *)IOBuffer2;
467 while (sector != 0) {
468 if ((clink2 = apaCacheGetHeader(device, sector, 0, &result)) != NULL) {
469 if (clink2->header->type) {
471 APA_PRINTF(
"main, start %08lx, nsector %08lx, nsub %ld, id %s\n", clink2->header->start, clink2->header->length, clink2->header->nsub, clink2->header->id);
473 MainMap[(*pMainCount)] = clink2->header->start;
476 if (clink2->header->type && clink2->header->flags &
APA_FLAG_SUB) {
477 APA_PRINTF(
"sub , start %08lx, nsector %08lx, num %2ld, main %08lx\n", clink2->header->start, clink2->header->length, clink2->header->number, clink2->header->main);
478 SubMap[(*pSubCount)] = clink2->header->start;
483 sector = clink2->header->next;
484 apaCacheFree(clink2);
494static int CheckPartitions(
int device,
apa_cache_t *clink)
496 int result, MainCount, SubCount;
498 if ((result = ReadPartitionMap(device, clink, &MainCount, &SubCount)) == 0) {
502 APA_PRINTF(
"check main partitions.\n");
504 for (i = 0; i < MainCount && result == 0; i++) {
505 if ((clink2 = apaCacheGetHeader(device, ((u32 *)IOBuffer)[i], 0, &result)) != NULL) {
506 int missing_sub_found;
510 for (missing_sub_found = 0, sub = 0, pSubs = clink2->header->subs; (u32)sub < clink2->header->nsub; sub++, pSubs++) {
514 if (pSubs->start == ((u32 *)IOBuffer2)[
count]) {
522 APA_PRINTF(
"missing sub partition found.\n");
524 if (!missing_sub_found) {
525 clink2->header->nsub = sub;
526 clink2->flags |= APA_CACHE_FLAG_DIRTY;
527 missing_sub_found = 1;
528 apaCacheFlushAllDirty(device);
532 if (missing_sub_found) {
533 APA_PRINTF(
"remove sub partition follows missing partition.\n");
535 if ((clink_sub = apaCacheGetHeader(device, pSubs->start, 0, &result)) != NULL) {
536 result = apaDelete(clink_sub);
542 apaCacheFree(clink2);
547 if ((result = ReadPartitionMap(device, clink, &MainCount, &SubCount)) == 0) {
550 APA_PRINTF(
"check sub partitions.\n");
552 for (sub = 0, ptr = (u32 *)IOBuffer2; sub < SubCount && result == 0; ptr++, sub++) {
554 if ((clink2 = apaCacheGetHeader(device, *ptr, 0, &result)) != NULL) {
555 for (i = 0; ((u32 *)IOBuffer)[i] != clink2->header->main && i < MainCount; i++)
558 if (MainCount == i) {
559 APA_PRINTF(
"this sub(start = %08lx)is not belong to anyone, remove it.\n", clink2->header->start);
560 if ((result = apaDelete(clink2)) != 0) {
561 APA_PRINTF(
"remove partition failed.\n");
565 if ((clink_sub = apaCacheGetHeader(device, clink2->header->main, 0, &result)) != NULL) {
567 if (clink_sub->header->subs[
count].start == *ptr) {
572 if (clink_sub->header->nsub == (u32)
count) {
573 APA_PRINTF(
"this subpartition is not belong to sub list.\n");
575 apaCacheFree(clink_sub);
577 apaCacheFree(clink_sub);
578 apaCacheFree(clink2);
581 apaCacheFree(clink2);
595static int HdckDevctl(
iomanX_iop_file_t *fd,
const char *name,
int cmd,
void *arg,
unsigned int arglen,
void *buf,
unsigned int buflen)
597 int result, badParts;
607 if (PrivateData.HddInfo[fd->unit].status != 0) {
611 if ((clink = apaCacheGetHeader(fd->unit, APA_SECTOR_MBR, 0, &result)) != NULL) {
613 while (CheckAPAPartitionLinks(fd->unit, clink) != 0) {
615 if (PrivateData.ErrorPartitionLBA == PrivateData.ErrorPartition2LBA) {
616 APA_PRINTF(
"only one partition has problem, try to fix it.\n");
617 RecoverPartitionIfSub(fd->unit, clink);
620 if (PrivateData.ErrorPartitionLBA && PrivateData.ErrorPartition2LBA) {
622 if (clink->header->prev != PrivateData.ErrorPartitionLBA) {
623 MarkUnreadablePartionAsEmpty(fd->unit, PrivateData.ErrorPartitionLBA, PrivateData.ErrorPartitionPrevLBA, PrivateData.ErrorPartition2PrevLBA - PrivateData.ErrorPartitionLBA);
625 RemoveBadPartitions(fd->unit, clink);
631 }
else if (PrivateData.ErrorPartitionLBA < PrivateData.ErrorPartition2LBA) {
632 APA_PRINTF(
"two or more partitions have problem, try to fix it.\n");
634 RecoverPartitionIfSub(fd->unit, clink);
637 if (PrivateData.ErrorPartitionLBA && PrivateData.ErrorPartition2LBA) {
639 if (clink->header->prev != PrivateData.ErrorPartitionLBA && clink->header->prev != PrivateData.ErrorPartition2LBA) {
640 MarkUnreadablePartionAsEmpty(fd->unit, PrivateData.ErrorPartitionLBA, PrivateData.ErrorPartitionPrevLBA, PrivateData.ErrorPartition2PrevLBA - PrivateData.ErrorPartitionLBA);
642 RemoveBadPartitions(fd->unit, clink);
649 APA_PRINTF(
"partition table completely inconsistent.\n");
650 RemoveBadPartitions(fd->unit, clink);
660 EraseSector(fd->unit, IOBuffer, APA_SECTOR_SECTOR_ERROR);
661 DeleteFreePartitions(fd->unit, clink);
662 result = CheckPartitions(fd->unit, clink);
666 APA_PRINTF(
"done\n");
668 APA_PRINTF(
"cannot read mbr partition, I cannot continue.\n");
674int APA_ENTRYPOINT(
int argc,
char **argv)
683 if (apaGetTime(&time) != 0) {
684 APA_PRINTF(
"error: could not get date\n");
685 return MODULE_NO_RESIDENT_END;
688 APA_PRINTF(
"%02d:%02d:%02d %02d/%02d/%d\n", time.hour, time.min, time.sec, time.month, time.day, time.year);
690 for (i = 0; i < 2; i++) {
691 if ((pDevInfo = sceAtaInit(i)) == NULL) {
692 APA_PRINTF(
"error: ata initialization failed.\n");
693 return MODULE_NO_RESIDENT_END;
697 PrivateData.HddInfo[i].status--;
700 PrivateData.HddInfo[i].MaxPartSize = apaGetPartitionMax(pDevInfo->
total_sectors);
701 if (HdckUnlockHdd(i) == 0) {
702 PrivateData.HddInfo[i].status--;
705 APA_PRINTF(
"disk%d: 0x%08lx sectors, max 0x%08lx\n", i, PrivateData.HddInfo[i].sectors, PrivateData.HddInfo[i].MaxPartSize);
710 for (i = 0; i < 2; i++) {
711 if (PrivateData.HddInfo[i].status < 2) {
712 if (apaJournalRestore(i) != 0) {
713 return MODULE_NO_RESIDENT_END;
716 if (apaGetFormat(i, (
int *)&PrivateData.HddInfo[i].format)) {
717 PrivateData.HddInfo[i].status--;
722 iomanX_DelDrv(HdckDevice.name);
723 if (iomanX_AddDrv(&HdckDevice) == 0) {
724 APA_PRINTF(
"driver start.\n");
725 return MODULE_RESIDENT_END;
728 return MODULE_NO_RESIDENT_END;
u32 count
start sector of fragmented bd/file