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
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...
28 apaSaveError(device
, clink
->header
, APA_SECTOR_PART_ERROR
, lba
);
32 int getPartErrorSector(u32 device
, u32 lba
, int *lba_out
)
37 if(!(clink
=cacheGetFree()))
40 if(atadDmaTransfer(device
, clink
->header
, lba
, 1, ATAD_MODE_READ
))
44 *lba_out
=((u32
*)(clink
->header
))[0];
45 if(((u32
*)(clink
->header
))[0])
46 rv
=1;// error is set ;)
51 int getPartErrorName(u32 device
, char *name
)
57 if((rv
=getPartErrorSector(device
, APA_SECTOR_PART_ERROR
, &lba
)) <= 0)
59 if(!(clink
=cacheGetHeader(device
, 0, THEADER_MODE_READ
, &rv
)))
64 if(clink
->header
->type
!=APA_TYPE_FREE
&&
65 !(clink
->header
->flags
& CACHE_FLAG_DIRTY
) &&
66 clink
->header
->start
==lba
) {
68 strncpy(name
, clink
->header
->id
, APA_IDMAX
- 1);
69 name
[APA_IDMAX
- 1] = '\0';
74 clink
=apaGetNextHeader(clink
, &rv
);
77 // clear error if no errors and partitions was not found...
79 setPartErrorSector(device
, 0);
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
93 if(!(clink
=cacheGetHeader(device
, start
, 1, err
)))
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
, ¶ms
->id
, APA_IDMAX
);
105 if(params
->flags
& APA_FLAG_SUB
) {
106 clink
->header
->main
=params
->main
;
107 clink
->header
->number
=params
->number
;
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
;
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)
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
);
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
);
153 apa_cache
*apaFindPartition(u32 device
, char *id
, int *err
)
157 clink
=cacheGetHeader(device
, 0, 0, err
);
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
);
169 //return (apa_cache *)-ENOENT; // <-- BUG code tests for NULL only
175 void addEmptyBlock(apa_header
*header
, u32
*emptyBlocks
)
176 { // small helper.... to track empty blocks..
179 if(header
->type
==APA_TYPE_FREE
) {
182 if(header
->length
==(1 << i
)) {
183 if(emptyBlocks
[i
]==APA_TYPE_FREE
) {
184 emptyBlocks
[i
]=header
->start
;
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
;
201 u32 tmp
, some_size
, part_end
;
204 // walk empty blocks in case can use one :)
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
))
219 cacheAdd(clink_this
);
223 if((clink_next
=cacheGetHeader(device
, 0, 0, err
))==NULL
){
224 cacheAdd(clink_this
);
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
;
239 clink_next
->flags
|=CACHE_FLAG_DIRTY
;
240 cacheFlushAllDirty(device
);
241 cacheAdd(clink_this
);
242 clink_this
=clink_new
;
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
);
262 int apaOpen(u32 device
, hdd_file_slot_t
*fileSlot
, input_param
*params
, int mode
)
271 // walk all looking for any empty blocks & look for partition
272 clink
=cacheGetHeader(device
, 0, 0, &rv
);
273 memset(&emptyBlocks
, 0, sizeof(emptyBlocks
));
276 sector
=clink
->sector
;
277 if(!(clink
->header
->flags
& APA_FLAG_SUB
)) {
278 if(memcmp(clink
->header
->id
, params
->id
, APA_IDMAX
) == 0)
281 addEmptyBlock(clink
->header
, emptyBlocks
);
282 clink
=apaGetNextHeader(clink
, &rv
);
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
);
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
);
312 rv
=0; if(passcmp(clink
->header
->fpwd
, NULL
)!=0)
317 int apaRemove(u32 device
, char *id
)
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)
332 if(id
[0]=='_' && id
[1]=='_')
334 if((clink
=apaFindPartition(device
, id
, &rv
))==NULL
)
336 if(passcmp(clink
->header
->fpwd
, NULL
))
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
))){
356 return apaDelete(clink
);
362 apa_cache
*apaRemovePartition(u32 device
, u32 start
, u32 next
, u32 prev
,
368 if((clink
=cacheGetHeader(device
, start
, 1, (int *)&err
))==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
;
382 void apaMakeEmpty(apa_cache
*clink
)
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
;
415 while(header
->start
) {
416 if(!(clink2
=cacheGetHeader(device
, header
->prev
, 0, err
))) {
420 header
=clink2
->header
;
421 tmp
=header
->length
+length
;
422 if(header
->type
!=0) {
426 if((header
->start
%tmp
) || (tmp
& (tmp
-1))) {
434 if(length
!=saved_length
) {
435 if(!(clink2
=cacheGetHeader(device
, saved_next
, 0, err
))) {
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
);
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
;
459 u32 device
=clink
->device
;
464 if(!(clink1
=cacheGetHeader(device
, lnext
, 0, err
))) {
468 header
=clink1
->header
;
469 tmp
=header
->length
+length
;
470 if(header
->type
!=0) {
474 if((clink
->header
->start
%tmp
)!=0 || ((tmp
-1) & tmp
)) {
482 if(length
!=saved_length
) {
483 if(!(clink2
=cacheGetHeader(device
, lnext
, 0, err
))) {
487 clink
->header
->length
=length
;
488 clink
->header
->next
=lnext
;
490 clink2
->header
->prev
=clink
->header
->start
;
491 clink2
->flags
|=CACHE_FLAG_DIRTY
;
492 cacheFlushAllDirty(device
);
499 int apaDelete(apa_cache
*clink
)
502 apa_cache
*clink_mbr
;
503 u32 device
=clink
->device
;
504 u32 start
=clink
->header
->start
;
512 if(clink
->header
->next
==0) {
513 if((clink_mbr
=cacheGetHeader(device
, 0, 0, &rv
))==NULL
)
520 if((clink
=cacheGetHeader(clink
->device
, clink
->header
->prev
, 0, &rv
))==NULL
)
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);
530 u32 length
=clink
->header
->length
;
533 if((clink
=apaDeleteFixPrev(clink
, &rv
))==NULL
)
535 if((clink
=apaDeleteFixNext(clink
, &rv
))==NULL
)
538 if(clink
->header
->start
==start
&& clink
->header
->length
==length
) {
540 cacheFlushAllDirty(clink
->device
);
547 int apaCheckSum(apa_header
*header
)
549 u32
*ptr
=(u32
*)header
;
553 for(i
=1; i
< 256; i
++)
558 int apaReadHeader(u32 device
, apa_header
*header
, u32 lba
)
560 if(atadDmaTransfer(device
, header
, lba
, 2, ATAD_MODE_READ
)!=0)
562 if(header
->magic
!=APA_MAGIC
)
564 if(apaCheckSum(header
)!=header
->checksum
)
566 if(lba
==APA_SECTOR_MBR
)
568 if(strncmp(header
->mbr
.magic
, mbrMagic
, 0x20)==0)
570 dprintf1("ps2hdd: Error: invalid partition table or version newer than I know.\n");
577 int apaWriteHeader(u32 device
, apa_header
*header
, u32 lba
)
579 if(atadDmaTransfer(device
, header
, lba
, 2, ATAD_MODE_WRITE
))
585 int apaGetFormat(u32 device
, int *format
)
588 int rv
=0;// u32 rv=0;
592 clink
=cacheGetFree();
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;
600 pDW
=(u32
*)clink
->header
;
601 for(i
=0;i
< 256; i
++)
603 if((i
& 0x7F) && pDW
[i
]!=0)
612 int apaGetPartitionMax(int totalLBA
)
617 totalLBA
>>=6; // totalLBA/64
630 apa_cache
*apaGetNextHeader(apa_cache
*clink
, int *err
)
632 u32 start
=clink
->header
->start
;
635 if(!clink
->header
->next
)
638 if(!(clink
=cacheGetHeader(clink
->device
, clink
->header
->next
, 0, err
)))
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
);