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