Disabling auto-refresh of game list by default, as it is causing bugs sometimes
[open-ps2-loader.git] / modules / hdd / ps2hdd / apa.c
blob84dd679af058305f3993ef952383b14e02fcdb47
1 /*
2 # _____ ___ ____ ___ ____
3 # ____| | ____| | | |____|
4 # | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5 #-----------------------------------------------------------------------
6 # Copyright 2001-2004, ps2dev - http://www.ps2dev.org
7 # Licenced under Academic Free License version 2.0
8 # Review ps2sdk README & LICENSE files for further details.
10 # $Id: apa.c 1158 2005-06-13 22:31:13Z oopo $
11 # Main APA related routines
14 #include "hdd.h"
16 void apaSaveError(u32 device, void *buffer, u32 lba, u32 err_lba)
18 memset(buffer, 0, 512);
19 *(u32 *)buffer=err_lba;
20 atadDmaTransfer(device, buffer, lba, 1, ATAD_MODE_WRITE);
21 atadFlushCache(device);
24 void setPartErrorSector(u32 device, u32 lba)
25 {// used to set the lba of a partition that has a error...
26 apa_cache *clink;
27 clink=cacheGetFree();
28 apaSaveError(device, clink->header, APA_SECTOR_PART_ERROR, lba);
29 cacheAdd(clink);
32 int getPartErrorSector(u32 device, u32 lba, int *lba_out)
34 apa_cache *clink;
35 int rv=0;
37 if(!(clink=cacheGetFree()))
38 return -ENOMEM;
40 if(atadDmaTransfer(device, clink->header, lba, 1, ATAD_MODE_READ))
41 return -EIO;
43 if(lba_out)
44 *lba_out=((u32 *)(clink->header))[0];
45 if(((u32 *)(clink->header))[0])
46 rv=1;// error is set ;)
47 cacheAdd(clink);
48 return rv;
51 int getPartErrorName(u32 device, char *name)
53 int lba;
54 int rv=0;
55 apa_cache *clink;
57 if((rv=getPartErrorSector(device, APA_SECTOR_PART_ERROR, &lba)) <= 0)
58 return rv;
59 if(!(clink=cacheGetHeader(device, 0, THEADER_MODE_READ, &rv)))
60 return rv;
62 while(clink)
64 if(clink->header->type!=APA_TYPE_FREE &&
65 !(clink->header->flags & CACHE_FLAG_DIRTY) &&
66 clink->header->start==lba) {
67 if(name) {
68 strncpy(name, clink->header->id, APA_IDMAX - 1);
69 name[APA_IDMAX - 1] = '\0';
71 cacheAdd(clink);
72 return 1;
74 clink=apaGetNextHeader(clink, &rv);
77 // clear error if no errors and partitions was not found...
78 if(rv==0)
79 setPartErrorSector(device, 0);
80 return rv;
83 int apaCheckPartitionMax(u32 device, s32 size)
85 return (hddDeviceBuf[device].partitionMaxSize >= size) ? 0 : -EINVAL;
88 apa_cache *apaFillHeader(u32 device, input_param *params, int start, int next,
89 int prev, int length, int *err)
90 { // used for makeing a new partition
91 apa_cache *clink;
93 if(!(clink=cacheGetHeader(device, start, 1, err)))
94 return NULL;
95 memset(clink->header, 0, sizeof(apa_header));
96 clink->header->magic=APA_MAGIC;
97 clink->header->start=start;
98 clink->header->next=next;
99 clink->header->prev=prev;
100 clink->header->length=length;
101 clink->header->type=params->type;
102 clink->header->flags=params->flags;
103 clink->header->modver=APA_MODVER;
104 memcpy(&clink->header->id, &params->id, APA_IDMAX);
105 if(params->flags & APA_FLAG_SUB) {
106 clink->header->main=params->main;
107 clink->header->number=params->number;
109 else
111 if(strncmp(clink->header->id, "_tmp", APA_IDMAX)!=0) {
112 memcpy(&clink->header->rpwd, &myPassHash, APA_PASSMAX);
113 memcpy(&clink->header->fpwd, &myPassHash, APA_PASSMAX);
116 getPs2Time(&clink->header->created);
117 clink->flags|=CACHE_FLAG_DIRTY;
118 return clink;
121 apa_cache *apaInsertPartition(u32 device, input_param *params, u32 sector, int *err)
122 { // add's a new partition useing a empty block...
123 apa_cache *clink_empty;
124 apa_cache *clink_this;
125 apa_cache *clink_next;
127 if((clink_this=cacheGetHeader(device, sector, 0, err))==0)
128 return 0;
129 while(clink_this->header->length!=params->size) {
130 if((clink_next=cacheGetHeader(device, clink_this->header->next, 0, err))==NULL) { // get next
131 cacheAdd(clink_this);
132 return 0;
134 clink_this->header->length>>=1;
135 clink_empty=apaRemovePartition(device, (clink_this->header->start+clink_this->header->length),
136 clink_this->header->next, clink_this->header->start, clink_this->header->length);
137 clink_this->header->next=clink_empty->header->start;
138 clink_this->flags|=CACHE_FLAG_DIRTY;
139 clink_next->header->prev=clink_empty->header->start;
140 clink_next->flags|=CACHE_FLAG_DIRTY;
142 cacheFlushAllDirty(device);
143 cacheAdd(clink_empty);
144 cacheAdd(clink_next);
146 cacheAdd(clink_this);
147 clink_this=apaFillHeader(device, params, clink_this->header->start, clink_this->header->next,
148 clink_this->header->prev, params->size, err);
149 cacheFlushAllDirty(device);
150 return clink_this;
153 apa_cache *apaFindPartition(u32 device, char *id, int *err)
155 apa_cache *clink;
157 clink=cacheGetHeader(device, 0, 0, err);
158 while(clink)
160 if(!(clink->header->flags & APA_FLAG_SUB)) {
161 if(memcmp(clink->header->id, id, APA_IDMAX)==0)
162 return clink; // found
164 clink=apaGetNextHeader(clink, (int *)err);
166 if(*err==0) {
167 *err=-ENOENT;
168 return NULL;
169 //return (apa_cache *)-ENOENT; // <-- BUG code tests for NULL only
171 *err=0;
172 return NULL;
175 void addEmptyBlock(apa_header *header, u32 *emptyBlocks)
176 { // small helper.... to track empty blocks..
177 int i;
179 if(header->type==APA_TYPE_FREE) {
180 for(i=0;i<32;i++)
182 if(header->length==(1 << i)) {
183 if(emptyBlocks[i]==APA_TYPE_FREE) {
184 emptyBlocks[i]=header->start;
185 return;
193 apa_cache *apaAddPartitionHere(u32 device, input_param *params, u32 *emptyBlocks,
194 u32 sector, int *err)
196 apa_cache *clink_this;
197 apa_cache *clink_next;
198 apa_cache *clink_new;
199 apa_header *header;
200 u32 i;
201 u32 tmp, some_size, part_end;
202 u32 tempSize;
204 // walk empty blocks in case can use one :)
205 for(i=0;i< 32;i++)
207 if((1 << i) >= params->size && emptyBlocks[i]!=0)
208 return apaInsertPartition(device, params, emptyBlocks[i], err);
210 clink_this=cacheGetHeader(device, sector, 0, err);
211 header=clink_this->header;
212 part_end=header->start+header->length;
213 some_size=(part_end%params->size);
214 tmp = some_size ? params->size - some_size : 0;
216 if(hddDeviceBuf[device].totalLBA < (part_end+params->size+tmp))
218 *err=-ENOSPC;
219 cacheAdd(clink_this);
220 return NULL;
223 if((clink_next=cacheGetHeader(device, 0, 0, err))==NULL){
224 cacheAdd(clink_this);
225 return NULL;
228 tempSize=params->size;
229 while(part_end%params->size){
230 tempSize=params->size>>1;
231 while(0x3FFFF<tempSize){
232 if(!(part_end%tempSize)) {
233 clink_new=apaRemovePartition(device, part_end, 0,
234 clink_this->header->start, tempSize);
235 clink_this->header->next=part_end;
236 clink_this->flags|=CACHE_FLAG_DIRTY;
237 clink_next->header->prev=clink_new->header->start;
238 part_end+=tempSize;
239 clink_next->flags|=CACHE_FLAG_DIRTY;
240 cacheFlushAllDirty(device);
241 cacheAdd(clink_this);
242 clink_this=clink_new;
243 break;
245 tempSize>>=1;
248 if((clink_new=apaFillHeader(device, params, part_end, 0, clink_this->header->start,
249 params->size, err))!=NULL) {
250 clink_this->header->next=part_end;
251 clink_this->flags|=CACHE_FLAG_DIRTY;
252 clink_next->header->prev=clink_new->header->start;
253 clink_next->flags|=CACHE_FLAG_DIRTY;
254 cacheFlushAllDirty(device);
256 cacheAdd(clink_this);
257 cacheAdd(clink_next);
258 return clink_new;
262 int apaOpen(u32 device, hdd_file_slot_t *fileSlot, input_param *params, int mode)
264 int rv=0;
265 u32 emptyBlocks[32];
266 apa_cache *clink;
267 apa_cache *clink2;
268 u32 sector=0;
271 // walk all looking for any empty blocks & look for partition
272 clink=cacheGetHeader(device, 0, 0, &rv);
273 memset(&emptyBlocks, 0, sizeof(emptyBlocks));
274 while(clink)
276 sector=clink->sector;
277 if(!(clink->header->flags & APA_FLAG_SUB)) {
278 if(memcmp(clink->header->id, params->id, APA_IDMAX) == 0)
279 break; // found :)
281 addEmptyBlock(clink->header, emptyBlocks);
282 clink=apaGetNextHeader(clink, &rv);
285 if(rv!=0)
286 return rv;
287 rv=-ENOENT;
289 if(clink==NULL && (mode & O_CREAT))
291 if((rv=apaCheckPartitionMax(device, params->size))>=0) {
292 if((clink=apaAddPartitionHere(device, params, emptyBlocks, sector, &rv))!=NULL)
294 sector=clink->header->start;
295 clink2=cacheGetFree();
296 memset(clink2->header, 0, sizeof(apa_header));
297 atadDmaTransfer(device, clink2->header, sector+8 , 2, ATAD_MODE_WRITE);
298 atadDmaTransfer(device, clink2->header, sector+0x2000, 2, ATAD_MODE_WRITE);
299 cacheAdd(clink2);
303 if(clink==NULL)
304 return rv;
305 fileSlot->start=clink->header->start;
306 fileSlot->length=clink->header->length;
307 memcpy(&fileSlot->subs, &clink->header->subs, APA_MAXSUB*sizeof(apa_subs));
308 fileSlot->type=clink->header->type;
309 fileSlot->nsub=clink->header->nsub;
310 memcpy(&fileSlot->id, &clink->header->id, APA_IDMAX);
311 cacheAdd(clink);
312 rv=0; if(passcmp(clink->header->fpwd, NULL)!=0)
313 rv=-EACCES;
314 return rv;
317 int apaRemove(u32 device, char *id)
319 int i;
320 u32 nsub;
321 apa_cache *clink;
322 apa_cache *clink2;
323 int rv;
325 for(i=0;i<maxOpen;i++) // look to see if open
327 if(fileSlots[i].f!=0) {
328 if(memcmp(fileSlots[i].id, id, APA_IDMAX)==0)
329 return -EBUSY;
332 if(id[0]=='_' && id[1]=='_')
333 return -EACCES;
334 if((clink=apaFindPartition(device, id, &rv))==NULL)
335 return rv;
336 if(passcmp(clink->header->fpwd, NULL))
338 cacheAdd(clink);
339 return -EACCES;
341 // remove all subs frist...
342 nsub=clink->header->nsub;
343 clink->header->nsub=0;
344 clink->flags|=CACHE_FLAG_DIRTY;
345 cacheFlushAllDirty(device);
346 for(i=nsub-1;i!=-1;i--)
348 if((clink2=cacheGetHeader(device, clink->header->subs[i].start, 0, &rv))){
349 if((rv=apaDelete(clink2))){
350 cacheAdd(clink);
351 return rv;
355 if(rv==0)
356 return apaDelete(clink);
358 cacheAdd(clink);
359 return rv;
362 apa_cache *apaRemovePartition(u32 device, u32 start, u32 next, u32 prev,
363 u32 length)
365 apa_cache *clink;
366 u32 err;
368 if((clink=cacheGetHeader(device, start, 1, (int *)&err))==NULL)
369 return NULL;
370 memset(clink->header, 0, sizeof(apa_header));
371 clink->header->magic=APA_MAGIC;
372 clink->header->start=start;
373 clink->header->next=next;
374 clink->header->prev=prev;
375 clink->header->length=length;
376 strcpy(clink->header->id, "__empty");
377 getPs2Time(&clink->header->created);
378 clink->flags|=CACHE_FLAG_DIRTY;
379 return clink;
382 void apaMakeEmpty(apa_cache *clink)
384 u32 saved_start;
385 u32 saved_next;
386 u32 saved_prev;
387 u32 saved_length;
389 saved_start = clink->header->start;
390 saved_next = clink->header->next;
391 saved_prev = clink->header->prev;
392 saved_length = clink->header->length;
393 memset(clink->header, 0, sizeof(apa_header));
394 clink->header->magic = APA_MAGIC;
395 clink->header->start = saved_start;
396 clink->header->next = saved_next;
397 clink->header->prev = saved_prev;
398 clink->header->length = saved_length;
399 getPs2Time(&clink->header->created);
400 strcpy(clink->header->id, "__empty");
401 clink->flags|=CACHE_FLAG_DIRTY;
404 apa_cache *apaDeleteFixPrev(apa_cache *clink, int *err)
406 apa_cache *clink2=clink;
407 apa_header *header=clink2->header;
408 u32 device=clink->device;
409 u32 length=clink->header->length;
410 u32 saved_next=clink->header->next;
411 u32 saved_length=clink->header->length;
412 u32 tmp;
415 while(header->start) {
416 if(!(clink2=cacheGetHeader(device, header->prev, 0, err))) {
417 cacheAdd(clink);
418 return NULL;
420 header=clink2->header;
421 tmp=header->length+length;
422 if(header->type!=0) {
423 cacheAdd(clink2);
424 break;
426 if((header->start%tmp) || (tmp & (tmp-1))) {
427 cacheAdd(clink2);
428 break;
430 length=tmp;
431 cacheAdd(clink);
432 clink=clink2;
434 if(length!=saved_length) {
435 if(!(clink2=cacheGetHeader(device, saved_next, 0, err))) {
436 cacheAdd(clink);
437 return NULL;
439 clink->header->length=length;
440 clink->header->next=clink->header->start+length;
441 clink2->header->prev=clink->header->start;
442 clink2->flags|=CACHE_FLAG_DIRTY;
443 clink->flags|=CACHE_FLAG_DIRTY;
444 cacheFlushAllDirty(device);
445 cacheAdd(clink2);
447 return clink;
451 apa_cache *apaDeleteFixNext(apa_cache *clink, int *err)
453 apa_header *header=clink->header;
454 u32 length=header->length;
455 u32 saved_length=header->length;
456 u32 lnext=header->next;
457 apa_cache *clink1;
458 apa_cache *clink2;
459 u32 device=clink->device;
460 u32 tmp;
462 while(lnext!=0)
464 if(!(clink1=cacheGetHeader(device, lnext, 0, err))) {
465 cacheAdd(clink);
466 return 0;
468 header=clink1->header;
469 tmp=header->length+length;
470 if(header->type!=0) {
471 cacheAdd(clink1);
472 break;
474 if((clink->header->start%tmp)!=0 || ((tmp-1) & tmp)) {
475 cacheAdd(clink1);
476 break;
478 length=tmp;
479 cacheAdd(clink1);
480 lnext=header->next;
482 if(length!=saved_length) {
483 if(!(clink2=cacheGetHeader(device, lnext, 0, err))) {
484 cacheAdd(clink);
485 return NULL;
487 clink->header->length=length;
488 clink->header->next=lnext;
489 apaMakeEmpty(clink);
490 clink2->header->prev=clink->header->start;
491 clink2->flags|=CACHE_FLAG_DIRTY;
492 cacheFlushAllDirty(device);
493 cacheAdd(clink2);
495 return clink;
499 int apaDelete(apa_cache *clink)
501 int rv=0;
502 apa_cache *clink_mbr;
503 u32 device=clink->device;
504 u32 start=clink->header->start;
505 int i;
507 if(!start) {
508 cacheAdd(clink);
509 return -EACCES;
512 if(clink->header->next==0) {
513 if((clink_mbr=cacheGetHeader(device, 0, 0, &rv))==NULL)
515 cacheAdd(clink);
516 return rv;
518 do {
519 cacheAdd(clink);
520 if((clink=cacheGetHeader(clink->device, clink->header->prev, 0, &rv))==NULL)
521 return 0;
522 clink->header->next=0;
523 clink->flags|=CACHE_FLAG_DIRTY;
524 clink_mbr->header->prev=clink->header->start;
525 clink_mbr->flags|=CACHE_FLAG_DIRTY;
526 cacheFlushAllDirty(device);
527 } while(clink->header->type==0);
528 cacheAdd(clink_mbr);
529 } else {
530 u32 length=clink->header->length;
532 for(i=0;i < 2;i++){
533 if((clink=apaDeleteFixPrev(clink, &rv))==NULL)
534 return 0;
535 if((clink=apaDeleteFixNext(clink, &rv))==NULL)
536 return 0;
538 if(clink->header->start==start && clink->header->length==length) {
539 apaMakeEmpty(clink);
540 cacheFlushAllDirty(clink->device);
543 cacheAdd(clink);
544 return rv;
547 int apaCheckSum(apa_header *header)
549 u32 *ptr=(u32 *)header;
550 u32 sum=0;
551 int i;
553 for(i=1; i < 256; i++)
554 sum+=ptr[i];
555 return sum;
558 int apaReadHeader(u32 device, apa_header *header, u32 lba)
560 if(atadDmaTransfer(device, header, lba, 2, ATAD_MODE_READ)!=0)
561 return -EIO;
562 if(header->magic!=APA_MAGIC)
563 return -EIO;
564 if(apaCheckSum(header)!=header->checksum)
565 return -EIO;
566 if(lba==APA_SECTOR_MBR)
568 if(strncmp(header->mbr.magic, mbrMagic, 0x20)==0)
569 return 0;
570 dprintf1("ps2hdd: Error: invalid partition table or version newer than I know.\n");
571 return -EIO;
573 return 0;
577 int apaWriteHeader(u32 device, apa_header *header, u32 lba)
579 if(atadDmaTransfer(device, header, lba, 2, ATAD_MODE_WRITE))
580 return -EIO;
581 return 0;
585 int apaGetFormat(u32 device, int *format)
587 apa_cache *clink;
588 int rv=0;// u32 rv=0;
589 u32 *pDW;
590 int i;
592 clink=cacheGetFree();
593 *format=0;
594 if((rv=apaReadHeader(device, clink->header, 0))==0)
596 *format=clink->header->mbr.version;
597 if(atadDmaTransfer(device, clink->header, APA_SECTOR_SECTOR_ERROR, 2, ATAD_MODE_READ))
598 rv=-EIO; // return -EIO;
599 if(rv==0){
600 pDW=(u32 *)clink->header;
601 for(i=0;i < 256; i++)
603 if((i & 0x7F) && pDW[i]!=0)
604 rv=1;
608 cacheAdd(clink);
609 return rv==0;
612 int apaGetPartitionMax(int totalLBA)
614 int i;
615 int size;
617 totalLBA>>=6; // totalLBA/64
618 size=(1<<0x1F);
619 for(i=31;i!=0;i--)
621 size=1<<i;
622 if(size&totalLBA)
623 break;
625 if(size<totalLBA)
626 i++;
627 return(1 << i);
630 apa_cache *apaGetNextHeader(apa_cache *clink, int *err)
632 u32 start=clink->header->start;
634 cacheAdd(clink);
635 if(!clink->header->next)
636 return NULL;
638 if(!(clink=cacheGetHeader(clink->device, clink->header->next, 0, err)))
639 return NULL;
641 if(start!=clink->header->prev) {
642 dprintf1("ps2hdd: Warning: Invalid partition information. start != prev\n");
643 clink->header->prev=start;
644 clink->flags|=CACHE_FLAG_DIRTY;
645 cacheFlushAllDirty(clink->device);
647 return clink;