PS2SDK
PS2 Homebrew Libraries
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 
34 hdd_file_slot_t *hddFileSlots;
35 int fioSema;
36 int apaMaxOpen = 1;
37 
38 extern const char apaMBRMagic[];
39 extern apa_device_t hddDevices[];
40 
41 #ifdef APA_FORMAT_MAKE_PARTITIONS
42 // TODO: For DVRP firmware 48-bit, __xdata and __xcontents partitions are created
43 static 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
49 static 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
62 static 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
81 static int fioPartitionSizeLookUp(char *str);
82 static int fioInputBreaker(char const **arg, char *outBuf, int maxout);
83 static int fioDataTransfer(iomanX_iop_file_t *f, void *buf, int size, int mode);
84 static int getFileSlot(apa_params_t *params, hdd_file_slot_t **fileSlot, iomanX_iop_file_t *file);
85 static int ioctl2Transfer(s32 device, hdd_file_slot_t *fileSlot, hddIoctl2Transfer_t *arg);
86 static void fioGetStatFiller(apa_cache_t *clink1, iox_stat_t *stat);
87 static int ioctl2AddSub(hdd_file_slot_t *fileSlot, char *argp);
88 static int ioctl2DeleteLastSub(hdd_file_slot_t *fileSlot);
89 static int devctlSwapTemp(s32 device, char *argp);
90 
91 static 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 
107 static 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 
128 struct apaFsType
129 {
130  const char *desc;
131  u16 type;
132 };
133 
134 static 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 
216 static int getFileSlot(apa_params_t *params, hdd_file_slot_t **fileSlot, iomanX_iop_file_t *file)
217 {
218  int i;
219 
220  for (i = 0; i < apaMaxOpen; i++) {
221  if (hddFileSlots[i].f)
222  if ((hddFileSlots[i].f->unit == file->unit) && (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 
234 static 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 
262 static 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 
284 int 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 
298 int hddDeinit(iomanX_iop_device_t *f)
299 {
300  (void)f;
301 
302  DeleteSema(fioSema);
303  return 0;
304 }
305 
306 int 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 
421 static 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 
481 static 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.
527 static 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 
577 int 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 
595 int 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, f)) == 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 
639 int 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 
647 int hddRead(iomanX_iop_file_t *f, void *buf, int size)
648 {
649  return fioDataTransfer(f, buf, size, BLKIO_DIR_READ);
650 }
651 
652 int 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 
663 int 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 
697 static 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 
729 int 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 
748 int hddDopen(iomanX_iop_file_t *f, const char *name)
749 {
750  return hddOpen(f, name, 0, 0);
751 }
752 
753 int 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>*/
802 int 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 
813 static 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 
874 static 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 
902 int 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 
983 static 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 
1023 static 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 
1045 int 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
1163 int 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 
1183 int 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
_iomanX_iop_file::unit
int unit
Definition: iomanX.h:74
iomanX.h
hddIoctl2Transfer_t
Definition: hdd-ioctl.h:79
apa_sub_t
Definition: libapa.h:56
_iomanX_iop_file::device
struct _iomanX_iop_device * device
Definition: iomanX.h:76
iox_stat_t
Definition: iox_stat.h:92
apa_header_t
Definition: libapa.h:62
APA_TYPE_MBR
#define APA_TYPE_MBR
Definition: hdd-ioctl.h:38
HIOCGETSIZE
#define HIOCGETSIZE
Definition: hdd-ioctl.h:65
iop_sema_t
Definition: thsemap.h:38
_iomanX_iop_file
Definition: iomanX.h:70
sysclib.h
HDIOC_TOTALSECTOR
#define HDIOC_TOTALSECTOR
Definition: hdd-ioctl.h:98
HDIOC_WRITESECTOR
#define HDIOC_WRITESECTOR
Definition: hdd-ioctl.h:121
ENXIO
#define ENXIO
Definition: errno.h:31
sapa_cache
Definition: libapa.h:120
EIO
#define EIO
Definition: errno.h:29
loadcore.h
_iomanX_iop_file::mode
int mode
Definition: iomanX.h:72
ENOENT
#define ENOENT
Definition: errno.h:23
apaFsType
Definition: hdd_fio.c:128
apa_ps2time_t
Definition: libapa.h:42
HDIOC_SCEIDENTIFY
#define HDIOC_SCEIDENTIFY
Definition: hdd-ioctl.h:123
HIOCTRANSFER
#define HIOCTRANSFER
Definition: hdd-ioctl.h:63
hdd-ioctl.h
hdd_file_slot_t
Definition: hdd.h:16
APA_FLAG_SUB
#define APA_FLAG_SUB
Definition: hdd-ioctl.h:51
irx.h
_iomanX_iop_file::privdata
void * privdata
Definition: iomanX.h:78
hddIoctl2Transfer_t::mode
u32 mode
Definition: hdd-ioctl.h:87
thsemap.h
HDIOC_MAXSECTOR
#define HDIOC_MAXSECTOR
Definition: hdd-ioctl.h:96
HIOCSETPARTERROR
#define HIOCSETPARTERROR
Definition: hdd-ioctl.h:67
hddIoctl2Transfer_t::sub
u32 sub
Definition: hdd-ioctl.h:82
EBUSY
#define EBUSY
Definition: errno.h:51
hddSetOsdMBR_t
Definition: hdd-ioctl.h:144
hddIoctl2Transfer_t::size
u32 size
Definition: hdd-ioctl.h:85
HDIOC_SETOSDMBR
#define HDIOC_SETOSDMBR
Definition: hdd-ioctl.h:114
_iomanX_iop_device
Definition: iomanX.h:81
stdio.h
ENOTDIR
#define ENOTDIR
Definition: errno.h:59
EEXIST
#define EEXIST
Definition: errno.h:53
HDIOC_READSECTOR
#define HDIOC_READSECTOR
Definition: hdd-ioctl.h:119
iox_dirent_t
Definition: iox_stat.h:111
APA_MAXSUB
#define APA_MAXSUB
Definition: hdd-ioctl.h:48
apa_device_t
Definition: libapa.h:209
iox_stat_t::private_0
unsigned int private_0
Definition: iox_stat.h:102
dev9.h
EINVAL
#define EINVAL
Definition: errno.h:63
iox_stat_t::private_5
unsigned int private_5
Definition: iox_stat.h:108
HIOCGETPARTERROR
#define HIOCGETPARTERROR
Definition: hdd-ioctl.h:69
hddAtaTransfer_t
Definition: hdd-ioctl.h:137
HDIOC_GETERRORPARTNAME
#define HDIOC_GETERRORPARTNAME
Definition: hdd-ioctl.h:117
EACCES
#define EACCES
Definition: errno.h:45
EFBIG
#define EFBIG
Definition: errno.h:73
HDIOC_FREESECTOR
#define HDIOC_FREESECTOR
Definition: hdd-ioctl.h:107
errno.h
EMFILE
#define EMFILE
Definition: errno.h:67
ENODEV
#define ENODEV
Definition: errno.h:57
apa_params_t
Definition: libapa.h:135