sdk-core v2026.11.05
PS2 SDK - core tier (build-critical EE/IOP modules)
Loading...
Searching...
No Matches
hdd_fio.c
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.
9#
10# APA File System routines
11*/
12
13#include <stdio.h>
14#ifdef _IOP
15#include <irx.h>
16#include <loadcore.h>
17#include <sysclib.h>
18#else
19#include <string.h>
20#endif
21#ifdef APA_USE_DEV9
22#include <dev9.h>
23#endif
24#include <errno.h>
25#include <iomanX.h>
26#include <thsemap.h>
27#include <hdd-ioctl.h>
28
29#include <libapa.h>
30#include "hdd.h"
31#include "hdd_fio.h"
32#include "hdd_blkio.h"
33
34hdd_file_slot_t *hddFileSlots;
35int fioSema;
36int apaMaxOpen = 1;
37
38extern const char apaMBRMagic[];
39extern apa_device_t hddDevices[];
40
41#ifdef APA_FORMAT_MAKE_PARTITIONS
42// TODO: For DVRP firmware 48-bit, __xdata and __xcontents partitions are created
43#ifndef APA_FORMAT_WIPE_COMMON_ONLY
44static const char *formatPartList[] = {
45 "__net", "__system", "__sysconf", "__common", NULL};
46#endif
47#endif
48
49#ifdef APA_FORMAT_WIPE_COMMON_ONLY
50#define APA_WIPE_CHUNK_START (8 + 256)
51#else
52#define APA_WIPE_CHUNK_START 8
53#endif
54
55#ifndef APA_8MB_PARTITION_SIZE
56#define APA_NUMBER_OF_SIZES 9
57static const char *sizeList[APA_NUMBER_OF_SIZES] = {
58 "128M",
59 "256M",
60 "512M",
61 "1G",
62 "2G",
63 "4G",
64 "8G",
65 "16G",
66 "32G",
67};
68#else
69#define APA_NUMBER_OF_SIZES 13
70static const char *sizeList[APA_NUMBER_OF_SIZES] = {
71 "8M",
72 "16M",
73 "32M",
74 "64M",
75 "128M",
76 "256M",
77 "512M",
78 "1G",
79 "2G",
80 "4G",
81 "8G",
82 "16G",
83 "32G",
84};
85#endif
86
88// Function declarations
89static int fioPartitionSizeLookUp(char *str);
90static int fioInputBreaker(char const **arg, char *outBuf, int maxout);
91static int fioDataTransfer(iomanX_iop_file_t *f, void *buf, int size, int mode);
92static int getFileSlot(apa_params_t *params, hdd_file_slot_t **fileSlot, iomanX_iop_file_t *file);
93static int ioctl2Transfer(s32 device, hdd_file_slot_t *fileSlot, hddIoctl2Transfer_t *arg);
94static void fioGetStatFiller(apa_cache_t *clink1, iox_stat_t *stat);
95static int ioctl2AddSub(hdd_file_slot_t *fileSlot, char *argp);
96static int ioctl2DeleteLastSub(hdd_file_slot_t *fileSlot);
97static int devctlSwapTemp(s32 device, char *argp);
98
99static int fioPartitionSizeLookUp(char *str)
100{
101 int i;
102
103 for (i = 0; i < APA_NUMBER_OF_SIZES; i++) {
104 if (strcmp(str, sizeList[i]) == 0)
105#ifndef APA_8MB_PARTITION_SIZE
106 return (2 * 128 * 1024) << i; // 128MB
107#else
108 return (2 * 8 * 1024) << i; // 8MB
109#endif
110 }
111 APA_PRINTF(APA_DRV_NAME ": Error: Invalid partition size, %s.\n", str);
112 return -EINVAL;
113}
114
115static int fioInputBreaker(char const **arg, char *outBuf, int maxout)
116{
117 int len;
118 char *p;
119
120 if ((p = strchr(arg[0], ','))) {
121 if (maxout < (len = p - arg[0]))
122 return -EINVAL;
123 memcpy(outBuf, arg[0], len);
124 arg[0] = p + 1;
125 while (arg[0][0] == ' ')
126 arg[0] += 1;
127 return 0;
128 } // else
129 if (maxout < (len = strlen(arg[0])))
130 return -EINVAL;
131 memcpy(outBuf, arg[0], len);
132 arg[0] += len;
133 return 0;
134}
135
137{
138 const char *desc;
139 u16 type;
140};
141
142static int fioGetInput(const char *arg, apa_params_t *params)
143{
144 char argBuf[32];
145 int rv = 0;
146 static const struct apaFsType fsTypes[] = {
147#ifdef APA_SUPPORT_MBR
148 {"MBR", APA_TYPE_MBR},
149#endif
150 {"EXT2SWAP", APA_TYPE_EXT2SWAP},
151 {"EXT2", APA_TYPE_EXT2},
152 {"REISER", APA_TYPE_REISER},
153 {"PFS", APA_TYPE_PFS},
154 {"CFS", APA_TYPE_CFS},
155#ifdef APA_SUPPORT_HDL
156 {"HDL", APA_TYPE_HDL},
157#endif
158 };
159
160 if (params == NULL)
161 return -EINVAL;
162 memset(params, 0, sizeof(apa_params_t));
163
164 while (arg[0] == ' ')
165 arg++;
166
167 if (arg[0] == 0 || arg[0] == ',')
168 return -EINVAL;
169 if ((rv = fioInputBreaker(&arg, params->id, APA_IDMAX)) != 0)
170 return rv;
171 if (arg[0] == '\0') // Return if there are no further parameters.
172 return 0;
173
174 if ((rv = fioInputBreaker(&arg, params->fpwd, APA_PASSMAX)) != 0)
175 return rv;
176
177 if (params->fpwd[0] != '\0')
178 apaEncryptPassword(params->id, params->fpwd, params->fpwd);
179
180 if (arg[0] == '\0') // Return if there are no further parameters.
181 return 0;
182
183 if ((rv = fioInputBreaker(&arg, params->rpwd, APA_PASSMAX)) != 0)
184 return rv;
185
186 if (params->rpwd[0] != '\0')
187 apaEncryptPassword(params->id, params->rpwd, params->rpwd);
188
189 if (arg[0] == '\0') // Return if there are no further parameters.
190 return 0;
191
192 memset(argBuf, 0, sizeof(argBuf));
193 if ((rv = fioInputBreaker(&arg, argBuf, sizeof(argBuf))) != 0)
194 return rv;
195
196 if ((rv = fioPartitionSizeLookUp(argBuf)) < 0)
197 return rv;
198 params->size = rv;
199
200 memset(argBuf, 0, sizeof(argBuf));
201 if ((rv = fioInputBreaker(&arg, argBuf, sizeof(argBuf))) != 0)
202 return rv;
203
204 // scan through fstypes if found none - error
205 {
206 int i;
207
208 for (i = 0; (unsigned int)i < (sizeof(fsTypes))/(sizeof(fsTypes[0])); i++) {
209 if (!strcmp(argBuf, fsTypes[i].desc)) {
210 params->type = fsTypes[i].type;
211 break;
212 }
213 }
214
215 if ((unsigned int)i == (sizeof(fsTypes))/(sizeof(fsTypes[0]))) {
216 APA_PRINTF(APA_DRV_NAME ": error: Invalid fstype, %s.\n", argBuf);
217 return -EINVAL;
218 }
219 }
220
221 return rv;
222}
223
224static int getFileSlot(apa_params_t *params, hdd_file_slot_t **fileSlot, iomanX_iop_file_t *file)
225{
226 int i;
227
228 for (i = 0; i < apaMaxOpen; i++) {
229 if (hddFileSlots[i].f)
230 if ((hddFileSlots[i].f->unit == file->unit) && (memcmp(hddFileSlots[i].id, &params->id, APA_IDMAX) == 0))
231 return -EBUSY; // file is open
232 }
233 for (i = 0; i < apaMaxOpen; i++) {
234 if (!hddFileSlots[i].f) {
235 *fileSlot = &hddFileSlots[i];
236 return 0;
237 }
238 }
239 return -EMFILE; // no file slots free :(
240}
241
242static int fioDataTransfer(iomanX_iop_file_t *f, void *buf, int size, int mode)
243{
244 hdd_file_slot_t *fileSlot = (hdd_file_slot_t *)f->privdata;
245
246 if ((size & 0x1FF))
247 return -EINVAL;
248 size >>= 9; // size/512
249
250 if (fileSlot->post + size >= 0x1FF9) // no over reading
251 size = 0x1FF8 - fileSlot->post;
252
253 if (size != 0) {
254 int rv = 0;
255
256 WaitSema(fioSema);
257 if (blkIoDmaTransfer(f->unit, buf, fileSlot->post + fileSlot->parts[0].start + 8, size, mode))
258 rv = -EIO;
259 SignalSema(fioSema);
260 if (rv == 0) {
261 fileSlot->post += size;
262 return size << 9;
263 }
264
265 return rv;
266 }
267 return 0;
268}
269
270static int ioctl2Transfer(s32 device, hdd_file_slot_t *fileSlot, hddIoctl2Transfer_t *arg)
271{
272 if (fileSlot->nsub < arg->sub)
273 return -ENODEV;
274
275 // main partitions can only be read starting from the 4MB offset.
276 if (arg->sub == 0 && (arg->sector < 0x2000))
277 return -EINVAL;
278 // sub-partitions can only be read starting from after the header.
279 if (arg->sub != 0 && (arg->sector < 2))
280 return -EINVAL;
281
282 if (fileSlot->parts[arg->sub].length < arg->sector + arg->size)
283 return -ENXIO;
284
285 if (blkIoDmaTransfer(device, arg->buffer,
286 fileSlot->parts[arg->sub].start + arg->sector, arg->size, arg->mode))
287 return -EIO;
288
289 return 0;
290}
291
292int hddInit(iomanX_iop_device_t *f)
293{
294 iop_sema_t sema;
295 (void)f;
296
297 sema.attr = 1;
298 sema.initial = 1;
299 sema.max = 1;
300 sema.option = 0;
301 fioSema = CreateSema(&sema);
302
303 return 0;
304}
305
306int hddDeinit(iomanX_iop_device_t *f)
307{
308 (void)f;
309
310 DeleteSema(fioSema);
311 return 0;
312}
313
314int hddFormat(iomanX_iop_file_t *f, const char *dev, const char *blockdev, void *arg, int arglen)
315{
316 int rv = 0;
317 apa_cache_t *clink;
318 u32 i;
319#ifdef APA_FORMAT_MAKE_PARTITIONS
320 apa_params_t params;
321 u32 emptyBlocks[32];
322#endif
323
324 (void)dev;
325 (void)blockdev;
326 (void)arg;
327 (void)arglen;
328
329#ifdef APA_SUPPORT_BHDD
330 if (strcmp(f->device->name, "bhdd") == 0)
331 return -ENODEV;
332#endif
333
334 if (f->unit >= BLKIO_MAX_VOLUMES)
335 return -ENXIO;
336
337 // clear all errors on hdd
338 clink = apaCacheAlloc();
339 memset(clink->header, 0, sizeof(apa_header_t));
340 if (blkIoDmaTransfer(f->unit, clink->header, APA_SECTOR_SECTOR_ERROR, 1, BLKIO_DIR_WRITE)) {
341 apaCacheFree(clink);
342 return -EIO;
343 }
344 if (blkIoDmaTransfer(f->unit, clink->header, APA_SECTOR_PART_ERROR, 1, BLKIO_DIR_WRITE)) {
345 apaCacheFree(clink);
346 return -EIO;
347 }
348 // clear apa headers
349 // TODO: Why does DVRP firmware start clearing at 1024 * 4104 when not 48-bit?
350 // TODO: DVRP firmware 48-bit clears offset_24+0x2000, offset_24+0x42000, offset_24+0x242000
351 for (i = 1024 * APA_WIPE_CHUNK_START; i < hddDevices[f->unit].totalLBA; i += (1024 * 256)) {
352 // NOTE: XOSD variant traps on LBA 0 if __mbr detected:
353 // "hdd: <trap> __mbr will be unformated or destroyed."
354 blkIoDmaTransfer(f->unit, clink->header, i, sizeof(apa_header_t) / 512,
355 BLKIO_DIR_WRITE);
356 }
357 apaCacheFree(clink);
358 if ((rv = apaJournalReset(f->unit)) != 0)
359 return rv;
360
361#ifndef APA_FORMAT_WIPE_COMMON_ONLY
362 // set up mbr :)
363 if ((clink = apaCacheGetHeader(f->unit, APA_SECTOR_MBR, APA_IO_MODE_WRITE, &rv))) {
364 apa_header_t *header = clink->header;
365 memset(header, 0, sizeof(apa_header_t));
366 header->magic = APA_MAGIC;
367 // TODO: DVRP firmware sets this to 0x400 bytes
368 header->length = (1024 * 256); // 128MB
369 header->type = APA_TYPE_MBR;
370 // TODO: DVRP firmware 48-bit sets this to __extend
371 strcpy(header->id, "__mbr");
372#ifdef APA_FORMAT_LOCK_MBR
373 apaEncryptPassword(header->id, header->fpwd, "sce_mbr");
374 apaEncryptPassword(header->id, header->rpwd, "sce_mbr");
375#endif
376 memcpy(header->mbr.magic, apaMBRMagic, sizeof(header->mbr.magic));
377
378 header->mbr.version = APA_MBR_VERSION;
379 header->mbr.nsector = 0;
380 apaGetTime(&header->created);
381 apaGetTime(&header->mbr.created);
382
383#ifdef APA_SUPPORT_GPT
384 header->mbr.protective_mbr.UniqueMbrSignature = 0;
385 header->mbr.protective_mbr.Unknown = 0;
386 header->mbr.protective_mbr.partition_record1.BootIndicator = 0;
387 header->mbr.protective_mbr.partition_record1.StartHead = 0;
388 header->mbr.protective_mbr.partition_record1.StartSector = 2;
389 header->mbr.protective_mbr.partition_record1.StartTrack = 0;
390 header->mbr.protective_mbr.partition_record1.OSIndicator = 0xEE;
391 header->mbr.protective_mbr.partition_record1.EndHead = 0xFF;
392 header->mbr.protective_mbr.partition_record1.EndSector = 0xFF;
393 header->mbr.protective_mbr.partition_record1.EndTrack = 0xFF;
394 header->mbr.protective_mbr.partition_record1.StartingLBA = 1;
395 header->mbr.protective_mbr.partition_record1.SizeInLBA = hddDevices[f->unit].totalLBA - header->mbr.protective_mbr.partition_record1.StartingLBA;
396 header->mbr.protective_mbr.Signature = 0xAA55;
397#endif
398
399 header->checksum = apaCheckSum(header, 1);
400 clink->flags |= APA_CACHE_FLAG_DIRTY;
401 apaCacheFlushDirty(clink);
402 blkIoFlushCache(f->unit);
403 apaCacheFree(clink);
404 hddDevices[f->unit].status = 0;
405 hddDevices[f->unit].format = APA_MBR_VERSION;
406 }
407#endif
408 // TODO: DVRP firmware 48-bit creates __extend partition at offset_24_bit, with same params as __mbr except content is empty
409#ifdef APA_FORMAT_MAKE_PARTITIONS
410 memset(&emptyBlocks, 0, sizeof(emptyBlocks));
411 memset(&params, 0, sizeof(apa_params_t));
412 params.size = (1024 * 256);
413 params.type = APA_TYPE_PFS;
414
415 // TODO: For DVRP firmware 48-bit, __xdata is created with size 1024 * 2048
416 // TODO: For DVRP firmware 48-bit, __xcontents is created with size (offset_48_bit - offset_24_bit) - 0x240000 & 0xfffff7ff
417 // add __net, __system....
418#ifdef APA_FORMAT_WIPE_COMMON_ONLY
419 memset(params.id, 0, sizeof(params.id));
420 strcpy(params.id, "__sysconf");
421 if ( !(clink = apaFindPartition(f->unit, params.id, &rv)) )
422 return rv;
423 apaCacheFree(clink);
424 memset(params.id, 0, APA_IDMAX);
425 strcpy(params.id, "__common");
426 if ( !hddAddPartitionHere(f->unit, &params, emptyBlocks, clink->sector, &rv) )
427 return rv;
428#else
429 for (i = 0; formatPartList[i]; i++) {
430 memset(params.id, 0, APA_IDMAX);
431 strcpy(params.id, formatPartList[i]);
432 if (!(clink = hddAddPartitionHere(f->unit, &params, emptyBlocks, i ? clink->sector : 0, &rv)))
433 return rv;
434 apaCacheFree(clink);
435
436 params.size <<= 1;
437 if (hddDevices[f->unit].partitionMaxSize < params.size)
438 params.size = hddDevices[f->unit].partitionMaxSize;
439 }
440#endif
441#endif
442 return rv;
443}
444
445static int apaOpen(s32 device, hdd_file_slot_t *fileSlot, apa_params_t *params, int mode)
446{
447 int rv = 0;
448 u32 emptyBlocks[32];
449 apa_cache_t *clink;
450 apa_cache_t *clink2;
451 u32 sector = 0;
452
453#ifdef APA_SUPPORT_BHDD
454 // TODO: start sector usually is at either 0x4A817C8 (40GB offset) or 0x400000 (2GiB offset)
455 if (strcmp(params->id, "__xcontents") == 0 || strcmp(params->id, "__extend") == 0 || strcmp(params->id, "__xdata") == 0)
456 sector = hddDevices[device].totalLBA;
457#endif
458
459 // walk all looking for any empty blocks & look for partition
460 clink = apaCacheGetHeader(device, sector, APA_IO_MODE_READ, &rv);
461 memset(&emptyBlocks, 0, sizeof(emptyBlocks));
462 while (clink) {
463 sector = clink->sector;
464 if (!(clink->header->flags & APA_FLAG_SUB)) {
465 if (memcmp(clink->header->id, params->id, APA_IDMAX) == 0)
466 break; // found :)
467 }
468 apaAddEmptyBlock(clink->header, emptyBlocks);
469 clink = apaGetNextHeader(clink, &rv);
470 }
471
472 if (rv != 0)
473 return rv;
474 rv = -ENOENT;
475
476 if (clink == NULL && (mode & FIO_O_CREAT)) {
477 if ((rv = hddCheckPartitionMax(device, params->size)) >= 0) {
478 if ((clink = hddAddPartitionHere(device, params, emptyBlocks, sector, &rv)) != NULL) {
479 sector = clink->header->start;
480 clink2 = apaCacheAlloc();
481 memset(clink2->header, 0, sizeof(apa_header_t));
482 blkIoDmaTransfer(device, clink2->header, sector + 8, 2, BLKIO_DIR_WRITE);
483 blkIoDmaTransfer(device, clink2->header, sector + 0x2000, 2, BLKIO_DIR_WRITE);
484 apaCacheFree(clink2);
485 }
486 }
487 }
488 if (clink == NULL)
489 return rv;
490 fileSlot->parts[0].start = clink->header->start;
491 fileSlot->parts[0].length = clink->header->length;
492 memcpy(&fileSlot->parts[1], &clink->header->subs, APA_MAXSUB * sizeof(apa_sub_t));
493 fileSlot->type = clink->header->type;
494 fileSlot->nsub = clink->header->nsub;
495 memcpy(&fileSlot->id, &clink->header->id, APA_IDMAX);
496 apaCacheFree(clink);
497 if (apaPassCmp(clink->header->fpwd, params->fpwd) != 0) {
498 rv = (!(mode & FIO_O_WRONLY)) ? apaPassCmp(clink->header->rpwd, params->rpwd) : -EACCES;
499 } else
500 rv = 0;
501
502 return rv;
503}
504
505static int apaRemove(s32 device, const char *id, const char *fpwd)
506{
507 u32 nsub;
508 apa_cache_t *clink;
509 int rv, i;
510
511 for (i = 0; i < apaMaxOpen; i++) // look to see if open
512 {
513 if (hddFileSlots[i].f != 0) {
514 if (memcmp(hddFileSlots[i].id, id, APA_IDMAX) == 0)
515 return -EBUSY;
516 }
517 }
518#ifndef APA_ALLOW_REMOVE_PARTITION_WITH_LEADING_UNDERSCORE
519 if (id[0] == '_' && id[1] == '_')
520 return -EACCES;
521#endif
522 if ((clink = apaFindPartition(device, id, &rv)) == NULL)
523 return rv;
524 if (apaPassCmp(clink->header->fpwd, fpwd)) {
525 apaCacheFree(clink);
526 return -EACCES;
527 }
528 // remove all subs first...
529 nsub = clink->header->nsub;
530 clink->header->nsub = 0;
531 clink->flags |= APA_CACHE_FLAG_DIRTY;
532 apaCacheFlushAllDirty(device);
533 for (i = nsub - 1; i != -1; i--) {
534 apa_cache_t *clink2;
535
536 if ((clink2 = apaCacheGetHeader(device, clink->header->subs[i].start, APA_IO_MODE_READ, &rv))) {
537 if ((rv = apaDelete(clink2))) {
538 apaCacheFree(clink);
539 return rv;
540 }
541 }
542 }
543 if (rv == 0)
544 return apaDelete(clink);
545
546 apaCacheFree(clink);
547 return rv;
548}
549
550// Unofficial helper for renaming APA partitions.
551static int apaRename(s32 device, const char *oldId, const char *newId)
552{
553 apa_cache_t *clink;
554 int i, rv;
555
556 // look to see if can make(newname) or not...
557 if ((clink = apaFindPartition(device, newId, &rv)) != NULL) {
558 apaCacheFree(clink);
559 SignalSema(fioSema);
560 return -EEXIST; // File exists
561 }
562
563 // look to see if open(oldname)
564 for (i = 0; i < apaMaxOpen; i++) {
565 if (hddFileSlots[i].f != NULL) {
566 if (memcmp(hddFileSlots[i].id, oldId, APA_IDMAX) == 0) {
567 SignalSema(fioSema);
568 return -EBUSY;
569 }
570 }
571 }
572
573 // Do not allow system partitions (__*) to be renamed.
574#ifndef APA_ALLOW_REMOVE_PARTITION_WITH_LEADING_UNDERSCORE
575 if (oldId[0] == '_' && oldId[1] == '_')
576 return -EACCES;
577#endif
578
579 // find :)
580 if ((clink = apaFindPartition(device, oldId, &rv)) == NULL) {
581 SignalSema(fioSema);
582 return rv;
583 }
584
585 // do the renaming :) note: subs have no names!!
586 memset(clink->header->id, 0, APA_IDMAX);
587 strncpy(clink->header->id, newId, APA_IDMAX - 1);
588
589 // touch creation time
590 apaGetTime(&clink->header->created);
591 clink->header->checksum = apaCheckSum(clink->header, 1);
592
593 clink->flags |= APA_CACHE_FLAG_DIRTY;
594
595 apaCacheFlushAllDirty(device);
596 apaCacheFree(clink);
597
598 return 0;
599}
600
601int hddRemove(iomanX_iop_file_t *f, const char *name)
602{
603 int rv;
604 apa_params_t params;
605
606 if ((rv = fioGetInput(name, &params)) < 0)
607 return rv;
608#ifdef APA_SUPPORT_BHDD
609 if (strcmp(f->device->name, "bhdd") == 0)
610 return -EACCES;
611#endif
612 WaitSema(fioSema);
613 rv = apaRemove(f->unit, params.id, params.fpwd);
614 SignalSema(fioSema);
615
616 return rv;
617}
618
619int hddOpen(iomanX_iop_file_t *f, const char *name, int flags, int mode)
620{
621 int rv;
622 apa_params_t params;
623 hdd_file_slot_t *fileSlot;
624
625 (void)mode;
626
627 if (f->unit >= BLKIO_MAX_VOLUMES || hddDevices[f->unit].status != 0)
628 return -ENODEV;
629
630#ifdef APA_SUPPORT_BHDD
631 if (strcmp(f->device->name, "bhdd") == 0)
632 if ((flags & FIO_O_CREAT) != 0)
633 return -EACCES;
634#endif
635
636 if (!(f->mode & FIO_O_DIROPEN))
637 if ((rv = fioGetInput(name, &params)) < 0)
638 return rv;
639
640 WaitSema(fioSema);
641 if ((rv = getFileSlot(&params, &fileSlot, f)) == 0) {
642 if (!(f->mode & FIO_O_DIROPEN)) {
643 if ((rv = apaOpen(f->unit, fileSlot, &params, flags)) == 0) {
644 fileSlot->f = f;
645 f->privdata = fileSlot;
646 }
647 } else {
648#ifdef APA_SUPPORT_BHDD
649 if (strcmp(f->device->name, "bhdd") == 0) {
650 fileSlot->parts[0].start = hddDevices[f->unit].totalLBA;
651 } else {
652 fileSlot->parts[0].start = 0;
653 }
654#endif
655 fileSlot->f = f;
656 f->privdata = fileSlot;
657 }
658 }
659 SignalSema(fioSema);
660 return rv;
661}
662
663int hddClose(iomanX_iop_file_t *f)
664{
665 WaitSema(fioSema);
666 memset(f->privdata, 0, sizeof(hdd_file_slot_t));
667 SignalSema(fioSema);
668 return 0;
669}
670
671int hddRead(iomanX_iop_file_t *f, void *buf, int size)
672{
673 return fioDataTransfer(f, buf, size, BLKIO_DIR_READ);
674}
675
676int hddWrite(iomanX_iop_file_t *f, void *buf, int size)
677{
678 if (!(f->mode & FIO_O_WRONLY))
679 return -EACCES;
680#ifdef APA_SUPPORT_BHDD
681 if (strcmp(f->device->name, "bhdd") == 0)
682 return -EACCES;
683#endif
684 return fioDataTransfer(f, buf, size, BLKIO_DIR_WRITE);
685}
686
687int hddLseek(iomanX_iop_file_t *f, int post, int whence)
688{
689 int rv = 0;
690 hdd_file_slot_t *fileSlot;
691
692 // test input( no seeking to end point less :P )
693 if (whence == FIO_SEEK_END)
694 return -EINVAL;
695 if ((post & 0x1FF))
696 return -EINVAL;
697
698 post >>= 9; // post/512
699
700 WaitSema(fioSema);
701 fileSlot = f->privdata;
702 if (whence == FIO_SEEK_CUR) {
703 if (((int)fileSlot->post + post) < 0 || (fileSlot->post + post) >= 0x1FF9)
704 rv = -EINVAL;
705 else {
706 fileSlot->post += post;
707 rv = fileSlot->post << 9;
708 }
709 } else if (whence == FIO_SEEK_SET) {
710 if (post < 0 || post >= 0x1FF9)
711 rv = -EINVAL;
712 else {
713 fileSlot->post = post;
714 rv = fileSlot->post << 9;
715 }
716 }
717 SignalSema(fioSema);
718 return rv;
719}
720
721static void fioGetStatFiller(apa_cache_t *clink, iox_stat_t *stat)
722{
723 stat->mode = clink->header->type;
724 stat->attr = clink->header->flags;
725 stat->hisize = 0;
726 stat->size = clink->header->length;
727 memcpy(&stat->ctime, &clink->header->created, sizeof(apa_ps2time_t));
728 memcpy(&stat->atime, &clink->header->created, sizeof(apa_ps2time_t));
729 memcpy(&stat->mtime, &clink->header->created, sizeof(apa_ps2time_t));
730 stat->private_1 = 0;
731 stat->private_2 = 0;
732 if (clink->header->flags & APA_FLAG_SUB)
733 stat->private_0 = clink->header->number;
734 else {
735 stat->private_0 = clink->header->nsub;
736
737 u64 totalsize = (u64)clink->header->length;
738 for (int i = 0; i < clink->header->nsub; i++) {
739 totalsize += (u64)clink->header->subs[i].length;
740 }
741 stat->private_1 = (u32)(totalsize & 0xFFFFFFFF); // low size
742 stat->private_2 = (u32)(totalsize >> 32); // high size
743 }
744 stat->private_3 = 0;
745 stat->private_4 = 0;
746#ifndef APA_STAT_RETURN_PART_LBA
747 stat->private_5 = 0; // game ver
748#else
749 stat->private_5 = clink->header->start; // SONY ver (return start LBA of the partition)
750#endif
751}
752
753int hddGetStat(iomanX_iop_file_t *f, const char *name, iox_stat_t *stat)
754{
755 apa_cache_t *clink;
756 apa_params_t params;
757 int rv;
758
759 if ((rv = fioGetInput(name, &params)) < 0)
760 return rv;
761
762 WaitSema(fioSema);
763 if ((clink = apaFindPartition(f->unit, params.id, &rv))) {
764 if ((rv = apaPassCmp(clink->header->fpwd, params.fpwd)) == 0 || (rv = apaPassCmp(clink->header->rpwd, params.rpwd)) == 0)
765 fioGetStatFiller(clink, stat);
766 apaCacheFree(clink);
767 }
768 SignalSema(fioSema);
769 return rv;
770}
771
772int hddDopen(iomanX_iop_file_t *f, const char *name)
773{
774 return hddOpen(f, name, 0, 0);
775}
776
777int hddDread(iomanX_iop_file_t *f, iox_dirent_t *dirent)
778{
779 int rv;
780 hdd_file_slot_t *fileSlot = f->privdata;
781 apa_cache_t *clink;
782
783 if (!(f->mode & FIO_O_DIROPEN))
784 return -ENOTDIR;
785
786 if (fileSlot->parts[0].start == (u32)(-1))
787 return 0; // end :)
788
789 WaitSema(fioSema);
790 if ((clink = apaCacheGetHeader(f->unit, fileSlot->parts[0].start, APA_IO_MODE_READ, &rv)) &&
791 clink->header->length) {
792 if (clink->header->flags & APA_FLAG_SUB) {
793 // if sub get id from main header...
794 apa_cache_t *cmain = apaCacheGetHeader(f->unit, clink->header->main, APA_IO_MODE_READ, &rv);
795 if (cmain != NULL) {
796 /* This was the SONY original, which didn't do bounds-checking:
797 rv=strlen(cmain->header->id);
798 strcpy(dirent->name, cmain->header->id); */
799 strncpy(dirent->name, cmain->header->id, APA_IDMAX);
800 dirent->name[APA_IDMAX] = '\0';
801 rv = strlen(dirent->name);
802
803 apaCacheFree(cmain);
804 }
805 } else {
806 /* This was the SONY original, which didn't do bounds-checking:
807 rv=strlen(clink->header->id);
808 strcpy(dirent->name, clink->header->id); */
809 strncpy(dirent->name, clink->header->id, APA_IDMAX);
810 dirent->name[APA_IDMAX] = '\0';
811 rv = strlen(dirent->name);
812 }
813 fioGetStatFiller(clink, &dirent->stat);
814 if (clink->header->next == 0)
815 fileSlot->parts[0].start = -1; // mark end
816 else
817 fileSlot->parts[0].start = clink->header->next; // set next
818 apaCacheFree(clink);
819 }
820 SignalSema(fioSema);
821 return rv;
822}
823
824/* Originally, SONY provided no function for renaming partitions.
825 Syntax: rename <Old ID> <New ID>*/
826int hddReName(iomanX_iop_file_t *f, const char *oldname, const char *newname)
827{
828 int rv;
829
830 WaitSema(fioSema);
831 rv = apaRename(f->unit, oldname, newname);
832 SignalSema(fioSema);
833
834 return rv;
835}
836
837static int ioctl2AddSub(hdd_file_slot_t *fileSlot, char *argp)
838{
839 int rv;
840 u32 device = fileSlot->f->unit;
841 apa_params_t params;
842 u32 emptyBlocks[32];
843 apa_cache_t *clink;
844 u32 sector = 0;
845 u32 length;
846
847 if (!(fileSlot->f->mode & FIO_O_WRONLY))
848 return -EACCES;
849
850 if (!(fileSlot->nsub < APA_MAXSUB))
851 return -EFBIG;
852
853 memset(&params, 0, sizeof(apa_params_t));
854
855 if ((rv = fioPartitionSizeLookUp(argp)) < 0)
856 return rv;
857
858 params.size = rv;
859 params.flags = APA_FLAG_SUB;
860 params.type = fileSlot->type;
861 params.main = fileSlot->parts[0].start;
862 params.number = fileSlot->nsub + 1;
863 if ((rv = hddCheckPartitionMax(device, params.size)) < 0)
864 return rv;
865
866 // walk all looking for any empty blocks
867 memset(&emptyBlocks, 0, sizeof(emptyBlocks));
868 clink = apaCacheGetHeader(device, APA_SECTOR_MBR, APA_IO_MODE_READ, &rv);
869 while (clink) {
870 sector = clink->sector;
871 apaAddEmptyBlock(clink->header, emptyBlocks);
872 clink = apaGetNextHeader(clink, &rv);
873 }
874 if (rv != 0)
875 return rv;
876
877 if (!(clink = hddAddPartitionHere(device, &params, emptyBlocks, sector, &rv)))
878 return rv;
879
880 sector = clink->header->start;
881 length = clink->header->length;
882 apaCacheFree(clink);
883 if (!(clink = apaCacheGetHeader(device, fileSlot->parts[0].start, APA_IO_MODE_READ, &rv)))
884 return rv;
885
886 clink->header->subs[clink->header->nsub].start = sector;
887 clink->header->subs[clink->header->nsub].length = length;
888 clink->header->nsub++;
889 fileSlot->nsub++;
890 fileSlot->parts[fileSlot->nsub].start = sector;
891 fileSlot->parts[fileSlot->nsub].length = length;
892 clink->flags |= APA_CACHE_FLAG_DIRTY;
893 apaCacheFlushAllDirty(device);
894 apaCacheFree(clink);
895 return rv;
896}
897
898static int ioctl2DeleteLastSub(hdd_file_slot_t *fileSlot)
899{
900 int rv;
901 u32 device = fileSlot->f->unit;
902 apa_cache_t *mainPart;
903 apa_cache_t *subPart;
904
905 if (!(fileSlot->f->mode & FIO_O_WRONLY))
906 return -EACCES;
907
908 if (fileSlot->nsub == 0)
909 return -ENOENT;
910
911 if (!(mainPart = apaCacheGetHeader(device, fileSlot->parts[0].start, APA_IO_MODE_READ, &rv)))
912 return rv;
913
914 if ((subPart = apaCacheGetHeader(device,
915 mainPart->header->subs[mainPart->header->nsub - 1].start, APA_IO_MODE_READ, &rv))) {
916 fileSlot->nsub--;
917 mainPart->header->nsub--;
918 mainPart->flags |= APA_CACHE_FLAG_DIRTY;
919 apaCacheFlushAllDirty(device);
920 rv = apaDelete(subPart);
921 }
922 apaCacheFree(mainPart);
923 return rv;
924}
925
926int hddIoctl2(iomanX_iop_file_t *f, int req, void *argp, unsigned int arglen,
927 void *bufp, unsigned int buflen)
928{
929 u32 rv = 0, err_lba;
930 hdd_file_slot_t *fileSlot = f->privdata;
931
932 (void)arglen;
933 (void)bufp;
934 (void)buflen;
935
936#ifdef APA_SUPPORT_BHDD
937 if (strcmp(f->device->name, "bhdd") == 0) {
938 switch (req) {
939 case HIOCADDSUB:
940 case HIOCDELSUB:
941 case HIOCFLUSH:
942 case HIOCSETPARTERROR:
943 case HIOCGETPARTERROR:
944 return -EACCES;
945 default:
946 break;
947 }
948 }
949#endif
950 WaitSema(fioSema);
951 switch (req) {
952 // cmd set 1
953 case HIOCADDSUB:
954 rv = ioctl2AddSub(fileSlot, (char *)argp);
955 break;
956
957 case HIOCDELSUB:
958 rv = ioctl2DeleteLastSub(fileSlot);
959 break;
960
961 case HIOCNSUB:
962 rv = fileSlot->nsub;
963 break;
964
965 case HIOCFLUSH:
966 blkIoFlushCache(f->unit);
967 break;
968
969 // cmd set 2
970 case HIOCTRANSFER:
971 rv = ioctl2Transfer(f->unit, fileSlot, argp);
972 break;
973
974 case HIOCGETSIZE:
975 rv = fileSlot->parts[*(u32 *)argp].length;
976 break;
977
978 case HIOCSETPARTERROR:
979 apaSetPartErrorSector(f->unit, fileSlot->parts[0].start);
980 rv = 0;
981 break;
982
983 case HIOCGETPARTERROR:
984 if ((rv = apaGetPartErrorSector(f->unit, APA_SECTOR_PART_ERROR, &err_lba)) > 0) {
985 if (err_lba == fileSlot->parts[0].start) {
986 rv = 0;
987 apaSetPartErrorSector(f->unit, 0); // clear last error :)
988 }
989 }
990 break;
991
992#ifdef APA_SUPPORT_IOCTL_GETPARTSTART
993 // Special HDD.IRX IOCTL2 command for supporting HDLFS
994 case HIOCGETPARTSTART:
995 rv = fileSlot->parts[*(u32 *)argp].start;
996 break;
997#endif
998
999 default:
1000 rv = -EINVAL;
1001 break;
1002 }
1003 SignalSema(fioSema);
1004 return rv;
1005}
1006
1007static int devctlSwapTemp(s32 device, char *argp)
1008{
1009 int rv;
1010 apa_params_t params;
1011 char szBuf[APA_IDMAX];
1012 apa_cache_t *partTemp;
1013 apa_cache_t *partNew;
1014
1015
1016 if ((rv = fioGetInput(argp, &params)) < 0)
1017 return rv;
1018
1019 if (params.id[0] == '_' && params.id[1] == '_') // test for '__' system partition
1020 return -EINVAL;
1021
1022 memset(szBuf, 0, APA_IDMAX);
1023 strcpy(szBuf, "_tmp");
1024 if (!(partTemp = apaFindPartition(device, szBuf, &rv)))
1025 return rv;
1026
1027 if ((partNew = apaFindPartition(device, params.id, &rv))) {
1028 if ((rv = apaPassCmp(partNew->header->fpwd, params.fpwd)) == 0) {
1029 memcpy(partTemp->header->id, partNew->header->id, APA_IDMAX);
1030 memcpy(partTemp->header->rpwd, partNew->header->rpwd, APA_PASSMAX);
1031 memcpy(partTemp->header->fpwd, partNew->header->fpwd, APA_PASSMAX);
1032 // memset(partNew->header->id, 0, 8);// BUG! can make it so can not open!!
1033 memset(partNew->header->id, 0, APA_IDMAX);
1034 strcpy(partNew->header->id, "_tmp");
1035 memset(partNew->header->rpwd, 0, APA_PASSMAX);
1036 memset(partNew->header->fpwd, 0, APA_PASSMAX);
1037 partTemp->flags |= APA_CACHE_FLAG_DIRTY;
1038 partNew->flags |= APA_CACHE_FLAG_DIRTY;
1039 apaCacheFlushAllDirty(device);
1040 }
1041 apaCacheFree(partNew);
1042 }
1043 apaCacheFree(partTemp);
1044 return rv;
1045}
1046
1047static int devctlSetOsdMBR(s32 device, hddSetOsdMBR_t *mbrInfo)
1048{
1049 int rv;
1050 apa_cache_t *clink;
1051
1052 if (!(clink = apaCacheGetHeader(device, APA_SECTOR_MBR, APA_IO_MODE_READ, &rv)))
1053 return rv;
1054
1055 APA_PRINTF(APA_DRV_NAME ": mbr start: %ld\n" APA_DRV_NAME ": mbr size : %ld\n", mbrInfo->start, mbrInfo->size);
1056#ifdef APA_SUPPORT_GPT
1057 // osdStart should not overwrite APA journal
1058 if (mbrInfo->start < APA_SECTOR_MIN_OSDSTART)
1059 return -EINVAL;
1060#endif
1061 clink->header->mbr.osdStart = mbrInfo->start;
1062 clink->header->mbr.osdSize = mbrInfo->size;
1063 clink->flags |= APA_CACHE_FLAG_DIRTY;
1064 apaCacheFlushAllDirty(device);
1065 apaCacheFree(clink);
1066 return rv;
1067}
1068
1069int hddDevctl(iomanX_iop_file_t *f, const char *devname, int cmd, void *arg,
1070 unsigned int arglen, void *bufp, unsigned int buflen)
1071{
1072 int rv = 0;
1073
1074 (void)devname;
1075 (void)arglen;
1076 (void)buflen;
1077
1078#ifdef APA_SUPPORT_BHDD
1079 if (strcmp(f->device->name, "bhdd") == 0)
1080 return -ENODEV;
1081#endif
1082
1083 WaitSema(fioSema);
1084 switch (cmd) {
1085 // Command set 1 ('H')
1086 case HDIOC_DEV9OFF:
1087 // Early versions called sceAtaSmartSaveAttr() here, when their old dev9 versions did not support the pre-shutdown callback.
1088#ifdef APA_USE_DEV9
1089 Dev9CardStop();
1090#else
1091 blkIoSmartSaveAttr(f->unit);
1092#endif
1093 break;
1094
1095 case HDIOC_IDLE:
1096 rv = blkIoIdle(f->unit, *(char *)arg);
1097 break;
1098
1099 case HDIOC_MAXSECTOR:
1100 rv = hddDevices[f->unit].partitionMaxSize;
1101 break;
1102
1103 case HDIOC_TOTALSECTOR:
1104 rv = hddDevices[f->unit].totalLBA;
1105 break;
1106
1107 case HDIOC_FLUSH:
1108 if (blkIoFlushCache(f->unit))
1109 rv = -EIO;
1110 break;
1111
1112 case HDIOC_SWAPTMP:
1113 rv = devctlSwapTemp(f->unit, (char *)arg);
1114 break;
1115
1116 case HDIOC_SMARTSTAT:
1117 rv = blkIoSmartReturnStatus(f->unit);
1118 break;
1119
1120 case HDIOC_STATUS:
1121 rv = hddDevices[f->unit].status;
1122 break;
1123
1124 case HDIOC_FORMATVER:
1125 rv = hddDevices[f->unit].format;
1126 break;
1127
1128 case HDIOC_FREESECTOR:
1129 rv = apaGetFreeSectors(f->unit, bufp, hddDevices);
1130 break;
1131
1132 case HDIOC_IDLEIMM:
1133 rv = blkIoIdleImmediate(f->unit);
1134 break;
1135
1136 // Command set 2 ('h')
1137 case HDIOC_GETTIME:
1138 rv = apaGetTime((apa_ps2time_t *)bufp);
1139 break;
1140
1141 case HDIOC_SETOSDMBR:
1142 rv = devctlSetOsdMBR(f->unit, (hddSetOsdMBR_t *)arg);
1143 break;
1144
1145 case HDIOC_GETSECTORERROR:
1146 rv = apaGetPartErrorSector(f->unit, APA_SECTOR_SECTOR_ERROR, 0);
1147 break;
1148
1150 rv = apaGetPartErrorName(f->unit, (char *)bufp);
1151 break;
1152
1153 case HDIOC_READSECTOR:
1154 rv = blkIoDmaTransfer(f->unit, (void *)bufp, ((hddAtaTransfer_t *)arg)->lba,
1155 ((hddAtaTransfer_t *)arg)->size, BLKIO_DIR_READ);
1156 break;
1157
1158 case HDIOC_WRITESECTOR:
1159 rv = blkIoDmaTransfer(f->unit, ((hddAtaTransfer_t *)arg)->data,
1160 ((hddAtaTransfer_t *)arg)->lba, ((hddAtaTransfer_t *)arg)->size,
1161 BLKIO_DIR_WRITE);
1162 break;
1163
1164 case HDIOC_SCEIDENTIFY:
1165 rv = blkIoGetSceId(f->unit, (u16 *)bufp);
1166 break;
1167
1168 // HDIOC_INSTSEC is not implemented in DVRP firmware
1169 // HDIOC_SETMAXLBA28 is implemented in DVRP firmware
1170 // HDIOC_GETMAXLBA48 is implemented in DVRP firmware
1171 // HDIOC_ISLBA48 is implemented in DVRP firmware
1172 // HDIOC_PRESETMAXLBA28 is not implemented in DVRP firmware
1173 // HDIOC_POSTSETMAXLBA28 is not implemented in DVRP firmware
1174 // HDIOC_ENABLEWRITECACHE is implemented in DVRP firmware -> ATA 0xEF subcommand 0x02
1175 // HDIOC_DISABLEWRITECACHE is implemented in DVRP firmware -> ATA 0xEF subcommand 0x82
1176
1177 default:
1178 rv = -EINVAL;
1179 break;
1180 }
1181 SignalSema(fioSema);
1182
1183 return rv;
1184}
1185
1186#ifdef APA_USE_IOMANX
1187int hddMount(iomanX_iop_file_t *f, const char *fsname, const char *devname, int flag, void *arg, int arglen)
1188{
1189 int rv = 0;
1190
1191 (void)flag;
1192 (void)arg;
1193 (void)arglen;
1194
1195#ifdef APA_SUPPORT_BHDD
1196 if (strcmp(f->device->name, "bhdd") == 0)
1197 return -ENODEV;
1198#endif
1199
1200 WaitSema(fioSema);
1201 rv = hdd_blkio_vhdd_mount(f->unit, devname);
1202 SignalSema(fioSema);
1203
1204 return rv;
1205}
1206
1207int hddUmount(iomanX_iop_file_t *f, const char *fsname)
1208{
1209 int rv = 0;
1210
1211 (void)fsname;
1212
1213#ifdef APA_SUPPORT_BHDD
1214 if (strcmp(f->device->name, "bhdd") == 0)
1215 return -ENODEV;
1216#endif
1217
1218 WaitSema(fioSema);
1219 rv = hdd_blkio_vhdd_umount(f->unit);
1220 SignalSema(fioSema);
1221
1222 return rv;
1223}
1224#endif
#define ENOENT
Definition errno.h:32
#define EEXIST
Definition errno.h:62
#define ENXIO
Definition errno.h:40
#define EINVAL
Definition errno.h:72
#define EMFILE
Definition errno.h:76
#define EIO
Definition errno.h:38
#define EBUSY
Definition errno.h:60
#define ENOTDIR
Definition errno.h:68
#define ENODEV
Definition errno.h:66
#define EACCES
Definition errno.h:54
#define EFBIG
Definition errno.h:82
#define HDIOC_TOTALSECTOR
Definition hdd-ioctl.h:99
#define APA_TYPE_MBR
Definition hdd-ioctl.h:39
#define HIOCGETSIZE
Definition hdd-ioctl.h:66
#define HIOCGETPARTERROR
Definition hdd-ioctl.h:70
#define HDIOC_FREESECTOR
Definition hdd-ioctl.h:108
#define HDIOC_WRITESECTOR
Definition hdd-ioctl.h:122
#define APA_MAXSUB
Definition hdd-ioctl.h:49
#define HIOCSETPARTERROR
Definition hdd-ioctl.h:68
#define HDIOC_SETOSDMBR
Definition hdd-ioctl.h:115
#define HDIOC_MAXSECTOR
Definition hdd-ioctl.h:97
#define HIOCTRANSFER
Definition hdd-ioctl.h:64
#define APA_FLAG_SUB
Definition hdd-ioctl.h:52
#define HDIOC_SCEIDENTIFY
Definition hdd-ioctl.h:124
#define HDIOC_READSECTOR
Definition hdd-ioctl.h:120
#define HDIOC_GETERRORPARTNAME
Definition hdd-ioctl.h:118
struct _iomanX_iop_file iomanX_iop_file_t
struct _iomanX_iop_device * device
Definition iomanX.h:77
void * privdata
Definition iomanX.h:79
unsigned int private_0
Definition iox_stat.h:103
unsigned int private_5
Definition iox_stat.h:109