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 memcpy(clink->header->id, newId, APA_IDMAX);
563
564 // touch creation time
565 apaGetTime(&clink->header->created);
566 clink->header->checksum = apaCheckSum(clink->header, 1);
567
568 clink->flags |= APA_CACHE_FLAG_DIRTY;
569
570 apaCacheFlushAllDirty(device);
571 apaCacheFree(clink);
572
573 return 0;
574}
575
576int hddRemove(iomanX_iop_file_t *f, const char *name)
577{
578 int rv;
579 apa_params_t params;
580
581 if ((rv = fioGetInput(name, &params)) < 0)
582 return rv;
583#ifdef APA_SUPPORT_BHDD
584 if (strcmp(f->device->name, "bhdd") == 0)
585 return -EACCES;
586#endif
587 WaitSema(fioSema);
588 rv = apaRemove(f->unit, params.id, params.fpwd);
589 SignalSema(fioSema);
590
591 return rv;
592}
593
594int hddOpen(iomanX_iop_file_t *f, const char *name, int flags, int mode)
595{
596 int rv;
597 apa_params_t params;
598 hdd_file_slot_t *fileSlot;
599
600 (void)mode;
601
602 if (f->unit >= BLKIO_MAX_VOLUMES || hddDevices[f->unit].status != 0)
603 return -ENODEV;
604
605#ifdef APA_SUPPORT_BHDD
606 if (strcmp(f->device->name, "bhdd") == 0)
607 if ((flags & FIO_O_CREAT) != 0)
608 return -EACCES;
609#endif
610
611 if (!(f->mode & FIO_O_DIROPEN))
612 if ((rv = fioGetInput(name, &params)) < 0)
613 return rv;
614
615 WaitSema(fioSema);
616 if ((rv = getFileSlot(&params, &fileSlot)) == 0) {
617 if (!(f->mode & FIO_O_DIROPEN)) {
618 if ((rv = apaOpen(f->unit, fileSlot, &params, flags)) == 0) {
619 fileSlot->f = f;
620 f->privdata = fileSlot;
621 }
622 } else {
623#ifdef APA_SUPPORT_BHDD
624 if (strcmp(f->device->name, "bhdd") == 0) {
625 fileSlot->parts[0].start = hddDevices[f->unit].totalLBA;
626 } else {
627 fileSlot->parts[0].start = 0;
628 }
629#endif
630 fileSlot->f = f;
631 f->privdata = fileSlot;
632 }
633 }
634 SignalSema(fioSema);
635 return rv;
636}
637
638int hddClose(iomanX_iop_file_t *f)
639{
640 WaitSema(fioSema);
641 memset(f->privdata, 0, sizeof(hdd_file_slot_t));
642 SignalSema(fioSema);
643 return 0;
644}
645
646int hddRead(iomanX_iop_file_t *f, void *buf, int size)
647{
648 return fioDataTransfer(f, buf, size, BLKIO_DIR_READ);
649}
650
651int hddWrite(iomanX_iop_file_t *f, void *buf, int size)
652{
653 if (!(f->mode & FIO_O_WRONLY))
654 return -EACCES;
655#ifdef APA_SUPPORT_BHDD
656 if (strcmp(f->device->name, "bhdd") == 0)
657 return -EACCES;
658#endif
659 return fioDataTransfer(f, buf, size, BLKIO_DIR_WRITE);
660}
661
662int hddLseek(iomanX_iop_file_t *f, int post, int whence)
663{
664 int rv = 0;
665 hdd_file_slot_t *fileSlot;
666
667 // test input( no seeking to end point less :P )
668 if (whence == FIO_SEEK_END)
669 return -EINVAL;
670 if ((post & 0x1FF))
671 return -EINVAL;
672
673 post >>= 9; // post/512
674
675 WaitSema(fioSema);
676 fileSlot = f->privdata;
677 if (whence == FIO_SEEK_CUR) {
678 if (((int)fileSlot->post + post) < 0 || (fileSlot->post + post) >= 0x1FF9)
679 rv = -EINVAL;
680 else {
681 fileSlot->post += post;
682 rv = fileSlot->post << 9;
683 }
684 } else if (whence == FIO_SEEK_SET) {
685 if (post < 0 || post >= 0x1FF9)
686 rv = -EINVAL;
687 else {
688 fileSlot->post = post;
689 rv = fileSlot->post << 9;
690 }
691 }
692 SignalSema(fioSema);
693 return rv;
694}
695
696static void fioGetStatFiller(apa_cache_t *clink, iox_stat_t *stat)
697{
698 stat->mode = clink->header->type;
699 stat->attr = clink->header->flags;
700 stat->hisize = 0;
701 stat->size = clink->header->length;
702 memcpy(&stat->ctime, &clink->header->created, sizeof(apa_ps2time_t));
703 memcpy(&stat->atime, &clink->header->created, sizeof(apa_ps2time_t));
704 memcpy(&stat->mtime, &clink->header->created, sizeof(apa_ps2time_t));
705 stat->private_1 = 0;
706 stat->private_2 = 0;
707 if (clink->header->flags & APA_FLAG_SUB)
708 stat->private_0 = clink->header->number;
709 else {
710 stat->private_0 = clink->header->nsub;
711
712 u64 totalsize = (u64)clink->header->length;
713 for (int i = 0; i < clink->header->nsub; i++) {
714 totalsize += (u64)clink->header->subs[i].length;
715 }
716 stat->private_1 = (u32)(totalsize & 0xFFFFFFFF); // low size
717 stat->private_2 = (u32)(totalsize >> 32); // high size
718 }
719 stat->private_3 = 0;
720 stat->private_4 = 0;
721#ifndef APA_STAT_RETURN_PART_LBA
722 stat->private_5 = 0; // game ver
723#else
724 stat->private_5 = clink->header->start; // SONY ver (return start LBA of the partition)
725#endif
726}
727
728int hddGetStat(iomanX_iop_file_t *f, const char *name, iox_stat_t *stat)
729{
730 apa_cache_t *clink;
731 apa_params_t params;
732 int rv;
733
734 if ((rv = fioGetInput(name, &params)) < 0)
735 return rv;
736
737 WaitSema(fioSema);
738 if ((clink = apaFindPartition(f->unit, params.id, &rv))) {
739 if ((rv = apaPassCmp(clink->header->fpwd, params.fpwd)) == 0 || (rv = apaPassCmp(clink->header->rpwd, params.rpwd)) == 0)
740 fioGetStatFiller(clink, stat);
741 apaCacheFree(clink);
742 }
743 SignalSema(fioSema);
744 return rv;
745}
746
747int hddDopen(iomanX_iop_file_t *f, const char *name)
748{
749 return hddOpen(f, name, 0, 0);
750}
751
752int hddDread(iomanX_iop_file_t *f, iox_dirent_t *dirent)
753{
754 int rv;
755 hdd_file_slot_t *fileSlot = f->privdata;
756 apa_cache_t *clink;
757
758 if (!(f->mode & FIO_O_DIROPEN))
759 return -ENOTDIR;
760
761 if (fileSlot->parts[0].start == (u32)(-1))
762 return 0; // end :)
763
764 WaitSema(fioSema);
765 if ((clink = apaCacheGetHeader(f->unit, fileSlot->parts[0].start, APA_IO_MODE_READ, &rv)) &&
766 clink->header->length) {
767 if (clink->header->flags & APA_FLAG_SUB) {
768 // if sub get id from main header...
769 apa_cache_t *cmain = apaCacheGetHeader(f->unit, clink->header->main, APA_IO_MODE_READ, &rv);
770 if (cmain != NULL) {
771 /* This was the SONY original, which didn't do bounds-checking:
772 rv=strlen(cmain->header->id);
773 strcpy(dirent->name, cmain->header->id); */
774 strncpy(dirent->name, cmain->header->id, APA_IDMAX);
775 dirent->name[APA_IDMAX] = '\0';
776 rv = strlen(dirent->name);
777
778 apaCacheFree(cmain);
779 }
780 } else {
781 /* This was the SONY original, which didn't do bounds-checking:
782 rv=strlen(clink->header->id);
783 strcpy(dirent->name, clink->header->id); */
784 strncpy(dirent->name, clink->header->id, APA_IDMAX);
785 dirent->name[APA_IDMAX] = '\0';
786 rv = strlen(dirent->name);
787 }
788 fioGetStatFiller(clink, &dirent->stat);
789 if (clink->header->next == 0)
790 fileSlot->parts[0].start = -1; // mark end
791 else
792 fileSlot->parts[0].start = clink->header->next; // set next
793 apaCacheFree(clink);
794 }
795 SignalSema(fioSema);
796 return rv;
797}
798
799/* Originally, SONY provided no function for renaming partitions.
800 Syntax: rename <Old ID> <New ID>*/
801int hddReName(iomanX_iop_file_t *f, const char *oldname, const char *newname)
802{
803 int rv;
804
805 WaitSema(fioSema);
806 rv = apaRename(f->unit, oldname, newname);
807 SignalSema(fioSema);
808
809 return rv;
810}
811
812static int ioctl2AddSub(hdd_file_slot_t *fileSlot, char *argp)
813{
814 int rv;
815 u32 device = fileSlot->f->unit;
816 apa_params_t params;
817 u32 emptyBlocks[32];
818 apa_cache_t *clink;
819 u32 sector = 0;
820 u32 length;
821
822 if (!(fileSlot->f->mode & FIO_O_WRONLY))
823 return -EACCES;
824
825 if (!(fileSlot->nsub < APA_MAXSUB))
826 return -EFBIG;
827
828 memset(&params, 0, sizeof(apa_params_t));
829
830 if ((rv = fioPartitionSizeLookUp(argp)) < 0)
831 return rv;
832
833 params.size = rv;
834 params.flags = APA_FLAG_SUB;
835 params.type = fileSlot->type;
836 params.main = fileSlot->parts[0].start;
837 params.number = fileSlot->nsub + 1;
838 if ((rv = hddCheckPartitionMax(device, params.size)) < 0)
839 return rv;
840
841 // walk all looking for any empty blocks
842 memset(&emptyBlocks, 0, sizeof(emptyBlocks));
843 clink = apaCacheGetHeader(device, APA_SECTOR_MBR, APA_IO_MODE_READ, &rv);
844 while (clink) {
845 sector = clink->sector;
846 apaAddEmptyBlock(clink->header, emptyBlocks);
847 clink = apaGetNextHeader(clink, &rv);
848 }
849 if (rv != 0)
850 return rv;
851
852 if (!(clink = hddAddPartitionHere(device, &params, emptyBlocks, sector, &rv)))
853 return rv;
854
855 sector = clink->header->start;
856 length = clink->header->length;
857 apaCacheFree(clink);
858 if (!(clink = apaCacheGetHeader(device, fileSlot->parts[0].start, APA_IO_MODE_READ, &rv)))
859 return rv;
860
861 clink->header->subs[clink->header->nsub].start = sector;
862 clink->header->subs[clink->header->nsub].length = length;
863 clink->header->nsub++;
864 fileSlot->nsub++;
865 fileSlot->parts[fileSlot->nsub].start = sector;
866 fileSlot->parts[fileSlot->nsub].length = length;
867 clink->flags |= APA_CACHE_FLAG_DIRTY;
868 apaCacheFlushAllDirty(device);
869 apaCacheFree(clink);
870 return rv;
871}
872
873static int ioctl2DeleteLastSub(hdd_file_slot_t *fileSlot)
874{
875 int rv;
876 u32 device = fileSlot->f->unit;
877 apa_cache_t *mainPart;
878 apa_cache_t *subPart;
879
880 if (!(fileSlot->f->mode & FIO_O_WRONLY))
881 return -EACCES;
882
883 if (fileSlot->nsub == 0)
884 return -ENOENT;
885
886 if (!(mainPart = apaCacheGetHeader(device, fileSlot->parts[0].start, APA_IO_MODE_READ, &rv)))
887 return rv;
888
889 if ((subPart = apaCacheGetHeader(device,
890 mainPart->header->subs[mainPart->header->nsub - 1].start, APA_IO_MODE_READ, &rv))) {
891 fileSlot->nsub--;
892 mainPart->header->nsub--;
893 mainPart->flags |= APA_CACHE_FLAG_DIRTY;
894 apaCacheFlushAllDirty(device);
895 rv = apaDelete(subPart);
896 }
897 apaCacheFree(mainPart);
898 return rv;
899}
900
901int hddIoctl2(iomanX_iop_file_t *f, int req, void *argp, unsigned int arglen,
902 void *bufp, unsigned int buflen)
903{
904 u32 rv = 0, err_lba;
905 hdd_file_slot_t *fileSlot = f->privdata;
906
907 (void)arglen;
908 (void)bufp;
909 (void)buflen;
910
911#ifdef APA_SUPPORT_BHDD
912 if (strcmp(f->device->name, "bhdd") == 0) {
913 switch (req) {
914 case HIOCADDSUB:
915 case HIOCDELSUB:
916 case HIOCFLUSH:
917 case HIOCSETPARTERROR:
918 case HIOCGETPARTERROR:
919 return -EACCES;
920 default:
921 break;
922 }
923 }
924#endif
925 WaitSema(fioSema);
926 switch (req) {
927 // cmd set 1
928 case HIOCADDSUB:
929 rv = ioctl2AddSub(fileSlot, (char *)argp);
930 break;
931
932 case HIOCDELSUB:
933 rv = ioctl2DeleteLastSub(fileSlot);
934 break;
935
936 case HIOCNSUB:
937 rv = fileSlot->nsub;
938 break;
939
940 case HIOCFLUSH:
941 blkIoFlushCache(f->unit);
942 break;
943
944 // cmd set 2
945 case HIOCTRANSFER:
946 rv = ioctl2Transfer(f->unit, fileSlot, argp);
947 break;
948
949 case HIOCGETSIZE:
950 rv = fileSlot->parts[*(u32 *)argp].length;
951 break;
952
953 case HIOCSETPARTERROR:
954 apaSetPartErrorSector(f->unit, fileSlot->parts[0].start);
955 rv = 0;
956 break;
957
958 case HIOCGETPARTERROR:
959 if ((rv = apaGetPartErrorSector(f->unit, APA_SECTOR_PART_ERROR, &err_lba)) > 0) {
960 if (err_lba == fileSlot->parts[0].start) {
961 rv = 0;
962 apaSetPartErrorSector(f->unit, 0); // clear last error :)
963 }
964 }
965 break;
966
967#ifdef APA_SUPPORT_IOCTL_GETPARTSTART
968 // Special HDD.IRX IOCTL2 command for supporting HDLFS
969 case HIOCGETPARTSTART:
970 rv = fileSlot->parts[*(u32 *)argp].start;
971 break;
972#endif
973
974 default:
975 rv = -EINVAL;
976 break;
977 }
978 SignalSema(fioSema);
979 return rv;
980}
981
982static int devctlSwapTemp(s32 device, char *argp)
983{
984 int rv;
985 apa_params_t params;
986 char szBuf[APA_IDMAX];
987 apa_cache_t *partTemp;
988 apa_cache_t *partNew;
989
990
991 if ((rv = fioGetInput(argp, &params)) < 0)
992 return rv;
993
994 if (params.id[0] == '_' && params.id[1] == '_') // test for '__' system partition
995 return -EINVAL;
996
997 memset(szBuf, 0, APA_IDMAX);
998 strcpy(szBuf, "_tmp");
999 if (!(partTemp = apaFindPartition(device, szBuf, &rv)))
1000 return rv;
1001
1002 if ((partNew = apaFindPartition(device, params.id, &rv))) {
1003 if ((rv = apaPassCmp(partNew->header->fpwd, params.fpwd)) == 0) {
1004 memcpy(partTemp->header->id, partNew->header->id, APA_IDMAX);
1005 memcpy(partTemp->header->rpwd, partNew->header->rpwd, APA_PASSMAX);
1006 memcpy(partTemp->header->fpwd, partNew->header->fpwd, APA_PASSMAX);
1007 // memset(partNew->header->id, 0, 8);// BUG! can make it so can not open!!
1008 memset(partNew->header->id, 0, APA_IDMAX);
1009 strcpy(partNew->header->id, "_tmp");
1010 memset(partNew->header->rpwd, 0, APA_PASSMAX);
1011 memset(partNew->header->fpwd, 0, APA_PASSMAX);
1012 partTemp->flags |= APA_CACHE_FLAG_DIRTY;
1013 partNew->flags |= APA_CACHE_FLAG_DIRTY;
1014 apaCacheFlushAllDirty(device);
1015 }
1016 apaCacheFree(partNew);
1017 }
1018 apaCacheFree(partTemp);
1019 return rv;
1020}
1021
1022static int devctlSetOsdMBR(s32 device, hddSetOsdMBR_t *mbrInfo)
1023{
1024 int rv;
1025 apa_cache_t *clink;
1026
1027 if (!(clink = apaCacheGetHeader(device, APA_SECTOR_MBR, APA_IO_MODE_READ, &rv)))
1028 return rv;
1029
1030 APA_PRINTF(APA_DRV_NAME ": mbr start: %ld\n" APA_DRV_NAME ": mbr size : %ld\n", mbrInfo->start, mbrInfo->size);
1031#ifdef APA_SUPPORT_GPT
1032 // osdStart should not overwrite APA journal
1033 if (mbrInfo->start < APA_SECTOR_MIN_OSDSTART)
1034 return -EINVAL;
1035#endif
1036 clink->header->mbr.osdStart = mbrInfo->start;
1037 clink->header->mbr.osdSize = mbrInfo->size;
1038 clink->flags |= APA_CACHE_FLAG_DIRTY;
1039 apaCacheFlushAllDirty(device);
1040 apaCacheFree(clink);
1041 return rv;
1042}
1043
1044int hddDevctl(iomanX_iop_file_t *f, const char *devname, int cmd, void *arg,
1045 unsigned int arglen, void *bufp, unsigned int buflen)
1046{
1047 int rv = 0;
1048
1049 (void)devname;
1050 (void)arglen;
1051 (void)buflen;
1052
1053#ifdef APA_SUPPORT_BHDD
1054 if (strcmp(f->device->name, "bhdd") == 0)
1055 return -ENODEV;
1056#endif
1057
1058 WaitSema(fioSema);
1059 switch (cmd) {
1060 // Command set 1 ('H')
1061 case HDIOC_DEV9OFF:
1062 // Early versions called sceAtaSmartSaveAttr() here, when their old dev9 versions did not support the pre-shutdown callback.
1063#ifdef APA_USE_DEV9
1064 Dev9CardStop();
1065#else
1066 blkIoSmartSaveAttr(f->unit);
1067#endif
1068 break;
1069
1070 case HDIOC_IDLE:
1071 rv = blkIoIdle(f->unit, *(char *)arg);
1072 break;
1073
1074 case HDIOC_MAXSECTOR:
1075 rv = hddDevices[f->unit].partitionMaxSize;
1076 break;
1077
1078 case HDIOC_TOTALSECTOR:
1079 rv = hddDevices[f->unit].totalLBA;
1080 break;
1081
1082 case HDIOC_FLUSH:
1083 if (blkIoFlushCache(f->unit))
1084 rv = -EIO;
1085 break;
1086
1087 case HDIOC_SWAPTMP:
1088 rv = devctlSwapTemp(f->unit, (char *)arg);
1089 break;
1090
1091 case HDIOC_SMARTSTAT:
1092 rv = blkIoSmartReturnStatus(f->unit);
1093 break;
1094
1095 case HDIOC_STATUS:
1096 rv = hddDevices[f->unit].status;
1097 break;
1098
1099 case HDIOC_FORMATVER:
1100 rv = hddDevices[f->unit].format;
1101 break;
1102
1103 case HDIOC_FREESECTOR:
1104 rv = apaGetFreeSectors(f->unit, bufp, hddDevices);
1105 break;
1106
1107 case HDIOC_IDLEIMM:
1108 rv = blkIoIdleImmediate(f->unit);
1109 break;
1110
1111 // Command set 2 ('h')
1112 case HDIOC_GETTIME:
1113 rv = apaGetTime((apa_ps2time_t *)bufp);
1114 break;
1115
1116 case HDIOC_SETOSDMBR:
1117 rv = devctlSetOsdMBR(f->unit, (hddSetOsdMBR_t *)arg);
1118 break;
1119
1120 case HDIOC_GETSECTORERROR:
1121 rv = apaGetPartErrorSector(f->unit, APA_SECTOR_SECTOR_ERROR, 0);
1122 break;
1123
1125 rv = apaGetPartErrorName(f->unit, (char *)bufp);
1126 break;
1127
1128 case HDIOC_READSECTOR:
1129 rv = blkIoDmaTransfer(f->unit, (void *)bufp, ((hddAtaTransfer_t *)arg)->lba,
1130 ((hddAtaTransfer_t *)arg)->size, BLKIO_DIR_READ);
1131 break;
1132
1133 case HDIOC_WRITESECTOR:
1134 rv = blkIoDmaTransfer(f->unit, ((hddAtaTransfer_t *)arg)->data,
1135 ((hddAtaTransfer_t *)arg)->lba, ((hddAtaTransfer_t *)arg)->size,
1136 BLKIO_DIR_WRITE);
1137 break;
1138
1139 case HDIOC_SCEIDENTIFY:
1140 rv = blkIoGetSceId(f->unit, (u16 *)bufp);
1141 break;
1142
1143 // HDIOC_INSTSEC is not implemented in DVRP firmware
1144 // HDIOC_SETMAXLBA28 is implemented in DVRP firmware
1145 // HDIOC_GETMAXLBA48 is implemented in DVRP firmware
1146 // HDIOC_ISLBA48 is implemented in DVRP firmware
1147 // HDIOC_PRESETMAXLBA28 is not implemented in DVRP firmware
1148 // HDIOC_POSTSETMAXLBA28 is not implemented in DVRP firmware
1149 // HDIOC_ENABLEWRITECACHE is implemented in DVRP firmware -> ATA 0xEF subcommand 0x02
1150 // HDIOC_DISABLEWRITECACHE is implemented in DVRP firmware -> ATA 0xEF subcommand 0x82
1151
1152 default:
1153 rv = -EINVAL;
1154 break;
1155 }
1156 SignalSema(fioSema);
1157
1158 return rv;
1159}
1160
1161#ifdef APA_USE_IOMANX
1162int hddMount(iomanX_iop_file_t *f, const char *fsname, const char *devname, int flag, void *arg, int arglen)
1163{
1164 int rv = 0;
1165
1166 (void)flag;
1167 (void)arg;
1168 (void)arglen;
1169
1170#ifdef APA_SUPPORT_BHDD
1171 if (strcmp(f->device->name, "bhdd") == 0)
1172 return -ENODEV;
1173#endif
1174
1175 WaitSema(fioSema);
1176 rv = hdd_blkio_vhdd_mount(f->unit, devname);
1177 SignalSema(fioSema);
1178
1179 return rv;
1180}
1181
1182int hddUmount(iomanX_iop_file_t *f, const char *fsname)
1183{
1184 int rv = 0;
1185
1186 (void)fsname;
1187
1188#ifdef APA_SUPPORT_BHDD
1189 if (strcmp(f->device->name, "bhdd") == 0)
1190 return -ENODEV;
1191#endif
1192
1193 WaitSema(fioSema);
1194 rv = hdd_blkio_vhdd_umount(f->unit);
1195 SignalSema(fioSema);
1196
1197 return rv;
1198}
1199#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