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