PS2SDK
PS2 Homebrew Libraries
hdd.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 # Start Up routines
11 */
12 
13 #include <stdio.h>
14 #ifdef _IOP
15 #include <sysclib.h>
16 #include <loadcore.h>
17 #else
18 #include <string.h>
19 #include <stdlib.h>
20 #endif
21 #ifdef APA_USE_ATAD
22 #include <atad.h>
23 #endif
24 #ifdef APA_USE_DEV9
25 #include <dev9.h>
26 #endif
27 #include <errno.h>
28 #include <irx.h>
29 #include <iomanX.h>
30 #include <hdd-ioctl.h>
31 
32 #include <libapa.h>
33 #include "hdd.h"
34 #include "hdd_fio.h"
35 #include "hdd_blkio.h"
36 
37 #ifdef _IOP
38 IRX_ID("hdd_driver", APA_MODVER_MAJOR, APA_MODVER_MINOR);
39 #endif
40 
41 IOMANX_RETURN_VALUE_IMPL(EPERM);
42 
43 static iomanX_iop_device_ops_t hddOps={
44  &hddInit, // init
45  &hddDeinit, // deinit
46  &hddFormat, // format
47  &hddOpen, // open
48  &hddClose, // close
49  &hddRead, // read
50  &hddWrite, // write
51  &hddLseek, // lseek
52  IOMANX_RETURN_VALUE(EPERM), // ioctl
53  &hddRemove, // remove
54  IOMANX_RETURN_VALUE(EPERM), // mkdir
55  IOMANX_RETURN_VALUE(EPERM), // rmdir
56  &hddDopen, // dopen
57  &hddClose, // dclose
58  &hddDread, // dread
59  &hddGetStat, // getstat
60  IOMANX_RETURN_VALUE(EPERM), // chstat
61  &hddReName, // rename
62  IOMANX_RETURN_VALUE(EPERM), // chdir
63  IOMANX_RETURN_VALUE(EPERM), // sync
64  hddMount, // mount
65  hddUmount, // umount
66  IOMANX_RETURN_VALUE_S64(EPERM), // lseek64
67  &hddDevctl, // devctl
68  IOMANX_RETURN_VALUE(EPERM), // symlink
69  IOMANX_RETURN_VALUE(EPERM), // readlink
70  &hddIoctl2, // ioctl2
71 };
72 static iomanX_iop_device_t hddFioDev={
73  "hdd",
74  IOP_DT_BLOCK | IOP_DT_FSEXT,
75  1,
76  "HDD",
77  &hddOps,
78 };
79 #ifdef APA_SUPPORT_BHDD
80 static iomanX_iop_device_t bhddFioDev={
81  "bhdd",
82  IOP_DT_BLOCK | IOP_DT_FSEXT,
83  1,
84  "HDD",
85  &hddOps,
86 };
87 #endif
88 
89 apa_device_t hddDevices[BLKIO_MAX_VOLUMES];
90 
91 extern int apaMaxOpen;
92 extern hdd_file_slot_t *hddFileSlots;
93 
94 static int inputError(char *input);
95 #ifdef APA_USE_ATAD
96 static int unlockDrive(s32 device);
97 #endif
98 #ifdef APA_USE_DEV9
99 static void hddShutdownCb(void);
100 #endif
101 static int hddInitError(void);
102 
103 int hddCheckPartitionMax(s32 device, u32 size)
104 {
105  // TODO: In DVRP firmware, this check always succeeds
106  return (hddDevices[device].partitionMaxSize >= size) ? 0 : -EINVAL;
107 }
108 
109 apa_cache_t *hddAddPartitionHere(s32 device, const apa_params_t *params, u32 *emptyBlocks,
110  u32 sector, int *err)
111 {
112  apa_cache_t *clink_this;
113  apa_cache_t *clink_next;
114  apa_cache_t *clink_new;
115  apa_header_t *header;
116  u32 i;
117  u32 tmp, some_size, part_end;
118  u32 tempSize;
119  u32 minsize = 0x3FFFF; // 128MB
120 #ifdef APA_8MB_PARTITION_SIZE
121  minsize = 0x3FFF; // 8Mb
122 #endif
123 
124  // walk empty blocks in case can use one :)
125  for(i=0;i< 32;i++)
126  {
127  if((u32)(1 << i) >= params->size && emptyBlocks[i]!=0)
128  return apaInsertPartition(device, params, emptyBlocks[i], err);
129  }
130  clink_this=apaCacheGetHeader(device, sector, APA_IO_MODE_READ, err);
131  header=clink_this->header;
132  part_end=header->start+header->length;
133  some_size=(part_end%params->size);
134  tmp = some_size ? params->size - some_size : 0;
135 
136  if(hddDevices[device].totalLBA < (part_end + params->size + tmp)
137  //Non-SONY: when dealing with large disks, this check may overflow (therefore, check for overflows!).
138  || (part_end < sector))
139  {
140  *err=-ENOSPC;
141  apaCacheFree(clink_this);
142  return NULL;
143  }
144 
145  if((clink_next=apaCacheGetHeader(device, APA_SECTOR_MBR, APA_IO_MODE_READ, err))==NULL)
146  {
147  apaCacheFree(clink_this);
148  return NULL;
149  }
150 
151  while(part_end%params->size)
152  {
153  tempSize=params->size>>1;
154  while (minsize < tempSize) // 128MB
155  {
156  if(!(part_end%tempSize))
157  {
158  clink_new=apaRemovePartition(device, part_end, 0,
159  clink_this->header->start, tempSize);
160  clink_this->header->next=part_end;
161  clink_this->flags|=APA_CACHE_FLAG_DIRTY;
162  clink_next->header->prev=clink_new->header->start;
163  part_end+=tempSize;
164  clink_next->flags|=APA_CACHE_FLAG_DIRTY;
165  apaCacheFlushAllDirty(device);
166  apaCacheFree(clink_this);
167  clink_this=clink_new;
168  break;
169  }
170  tempSize>>=1;
171  }
172  }
173  if((clink_new=apaFillHeader(device, params, part_end, 0, clink_this->header->start,
174  params->size, err))!=NULL)
175  {
176  clink_this->header->next=part_end;
177  clink_this->flags|=APA_CACHE_FLAG_DIRTY;
178  clink_next->header->prev=clink_new->header->start;
179  clink_next->flags|=APA_CACHE_FLAG_DIRTY;
180  apaCacheFlushAllDirty(device);
181  }
182  apaCacheFree(clink_this);
183  apaCacheFree(clink_next);
184  return clink_new;
185 }
186 
187 static int inputError(char *input)
188 {
189  APA_PRINTF(APA_DRV_NAME": Error: Usage: %s [-o <apaMaxOpen>] [-n <maxcache>]\n", input);
190  return MODULE_NO_RESIDENT_END;
191 }
192 
193 static void printStartup(void)
194 {
195  APA_PRINTF(APA_DRV_NAME": PS2 APA Driver v%d.%d (c) 2003 Vector\n", APA_MODVER_MAJOR, APA_MODVER_MINOR);
196  return;
197 }
198 
199 #ifdef APA_USE_ATAD
200 static int unlockDrive(s32 device)
201 {
202  int rv;
203  u8 id[32];
204  if((rv=apaGetIlinkID(id))==0)
205  return sceAtaSecurityUnLock(device, id);
206  return rv;
207 }
208 #endif
209 
210 #ifdef _IOP
211 int APA_ENTRYPOINT(int argc, char *argv[], void *startaddr, ModuleInfo_t *mi)
212 #else
213 int APA_ENTRYPOINT(int argc, char *argv[])
214 #endif
215 {
216  int i, ret;
217  char *input;
218  int cacheSize=3;
219  apa_ps2time_t tm;
220 #ifdef APA_USE_ATAD
221  ata_devinfo_t *hddInfo;
222 #endif
223 
224 #ifdef _IOP
225  (void)startaddr;
226  if (argc < 0)
227  {
228  for ( i = 0; i < apaMaxOpen; i += 1 )
229  {
230  if ( hddFileSlots[i].f )
231  {
232  APA_PRINTF(APA_DRV_NAME": error: can't stop module(fd busy)\n");
233  return MODULE_REMOVABLE_END;
234  }
235  }
236 #ifdef APA_USE_DEV9
237  Dev9RegisterPowerOffHandler(0, NULL);
238 #endif
239  iomanX_DelDrv(hddFioDev.name);
240 #ifdef APA_SUPPORT_BHDD
241  iomanX_DelDrv(bhddFioDev.name);
242 #endif
243  if (hddFileSlots)
244  {
245  apaFreeMem(hddFileSlots);
246  }
247  apaCacheDeinit();
248  APA_PRINTF(APA_DRV_NAME": stopped module\n");
249  return MODULE_NO_RESIDENT_END;
250  }
251 #endif
252 
253  printStartup();
254 
255  if((input=strrchr(argv[0], '/')))
256  input++;
257  else
258  input=argv[0];
259 
260  argc--; argv++;
261  while(argc)
262  {
263  if(argv[0][0] != '-')
264  break;
265  if(strcmp("-o", argv[0])==0)
266  {
267  argc--; argv++;
268  if(!argc)
269  return inputError(input);
270  i=strtol(argv[0], 0, 10);
271  if(i-1<32)
272  apaMaxOpen=i;
273  }
274  else if(strcmp("-n", argv[0])==0)
275  {
276  argc--; argv++;
277  if(!argc)
278  return inputError(input);
279  i=strtol(*argv, 0, 10);
280  if(cacheSize<i)
281  cacheSize=i;
282  }
283  argc--; argv++;
284  }
285 
286  APA_PRINTF(APA_DRV_NAME": max open = %d, %d buffers\n", apaMaxOpen, cacheSize);
287 #ifdef APA_USE_DEV9
288  if(Dev9RegisterPowerOffHandler(0, &hddShutdownCb) != 0)
289  {
290  APA_PRINTF(APA_DRV_NAME": error: dev9 may not be resident.\n");
291  return hddInitError();
292  }
293 #endif
294 
295  if(apaGetTime(&tm) != 0)
296  {
297  APA_PRINTF(APA_DRV_NAME": error: could not get date.\n");
298  return hddInitError();
299  }
300 
301  APA_PRINTF(APA_DRV_NAME": %02d:%02d:%02d %02d/%02d/%d\n",
302  tm.hour, tm.min, tm.sec, tm.month, tm.day, tm.year);
303  memset(&hddDevices, 0, sizeof(hddDevices));
304  for(i = 0; i < BLKIO_MAX_VOLUMES; i++)
305  {
306  hddDevices[i].status = 3;
307 #ifdef APA_USE_ATAD
308  if(!(hddInfo=sceAtaInit(i)))
309  {
310  APA_PRINTF(APA_DRV_NAME": Error: ata initialization failed.\n");
311  return hddInitError();
312  }
313  if(hddInfo->exists!=0 && hddInfo->has_packet==0)
314  {
315  hddDevices[i].status--;
316  hddDevices[i].totalLBA=hddInfo->total_sectors;
317  hddDevices[i].partitionMaxSize=apaGetPartitionMax(hddInfo->total_sectors);
318  if(unlockDrive(i)==0)
319  hddDevices[i].status--;
320  APA_PRINTF(APA_DRV_NAME": disk%d: 0x%08lx sectors, max 0x%08lx\n", i,
321  hddDevices[i].totalLBA, hddDevices[i].partitionMaxSize);
322  }
323 #endif
324  }
325  hddFileSlots=apaAllocMem(apaMaxOpen*sizeof(hdd_file_slot_t));
326  ret = (hddFileSlots == NULL) ? -ENOMEM : 0;
327  if(ret != 0)
328  {
329  APA_PRINTF(APA_DRV_NAME": error: file descriptor initialization failed.\n");
330  return hddInitError();
331  }
332 
333  memset(hddFileSlots, 0, apaMaxOpen*sizeof(hdd_file_slot_t));
334 
335  if(apaCacheInit(cacheSize) != 0)
336  {
337  APA_PRINTF(APA_DRV_NAME": error: cache buffer initialization failed.\n");
338  return hddInitError();
339  }
340 
341 #ifdef APA_USE_ATAD
342  for(i=0;i < BLKIO_MAX_VOLUMES;i++)
343  {
344  if(hddDevices[i].status<2)
345  {
346  if((hddDevices[i].status != 1) && apaJournalRestore(i) != 0)
347  {
348  APA_PRINTF(APA_DRV_NAME": error: log check failed.\n");
349  return hddInitError();
350  }
351  if(apaGetFormat(i, &hddDevices[i].format))
352  hddDevices[i].status--;
353  APA_PRINTF(APA_DRV_NAME": drive status %d, format version %08x\n",
354  hddDevices[i].status, hddDevices[i].format);
355  }
356  }
357 #endif
358  blkIoInit();
359  iomanX_DelDrv(hddFioDev.name);
360  if(iomanX_AddDrv(&hddFioDev) == 0)
361  {
362 #ifdef APA_SUPPORT_BHDD
363  iomanX_DelDrv(bhddFioDev.name);
364  if(iomanX_AddDrv(&bhddFioDev) == 0)
365 #endif
366  {
367 #if defined(APA_XOSD_VER)
368  APA_PRINTF(APA_DRV_NAME": version %04x driver start. This is XOSD LBA48 VERSION !!!!!!!!!!!\n", IRX_VER(APA_MODVER_MAJOR, APA_MODVER_MINOR));
369 #elif defined(APA_OSD_VER)
370  APA_PRINTF(APA_DRV_NAME": version %04x driver start. This is OSD version!\n", IRX_VER(APA_MODVER_MAJOR, APA_MODVER_MINOR));
371 #else
372  APA_PRINTF(APA_DRV_NAME": version %04x driver start.\n", IRX_VER(APA_MODVER_MAJOR, APA_MODVER_MINOR));
373 #endif
374 #ifdef _IOP
375  if (mi && ((mi->newflags & 2) != 0))
376  mi->newflags |= 0x10;
377 #endif
378  return MODULE_RESIDENT_END;
379  }
380  }
381  {
382  APA_PRINTF(APA_DRV_NAME": error: add device failed.\n");
383  return hddInitError();
384  }
385 }
386 
387 #ifdef APA_USE_DEV9
388 static void hddShutdownCb(void)
389 {
390  int i;
391 
392  for(i = 0; i < BLKIO_MAX_VOLUMES; i++)
393  {
394  if(hddDevices[i].status == 0)
395  blkIoSmartSaveAttr(i);
396  }
397 }
398 #endif
399 
400 static int hddInitError(void)
401 {
402 #ifdef APA_USE_DEV9
403  Dev9RegisterPowerOffHandler(0, NULL);
404 #endif
405  return MODULE_NO_RESIDENT_END;
406 }
iomanX.h
_ModuleInfo::newflags
u16 newflags
Definition: loadcore.h:36
apa_header_t
Definition: libapa.h:62
IOP_DT_FSEXT
#define IOP_DT_FSEXT
Definition: iomanX.h:66
_ata_devinfo::has_packet
s32 has_packet
Definition: xatapi.c:43
_ata_devinfo
Definition: xatapi.c:40
sysclib.h
ENOMEM
#define ENOMEM
Definition: errno.h:43
EPERM
#define EPERM
Definition: errno.h:21
atad.h
sapa_cache
Definition: libapa.h:120
loadcore.h
apa_ps2time_t
Definition: libapa.h:42
hdd-ioctl.h
hdd_file_slot_t
Definition: hdd.h:16
_ata_devinfo::exists
s32 exists
Definition: xatapi.c:42
irx.h
_iomanX_iop_device_ops
Definition: iomanX.h:95
_iomanX_iop_device
Definition: iomanX.h:81
stdio.h
ENOSPC
#define ENOSPC
Definition: errno.h:75
_ata_devinfo::total_sectors
u32 total_sectors
Definition: xatapi.c:44
apa_device_t
Definition: libapa.h:209
dev9.h
EINVAL
#define EINVAL
Definition: errno.h:63
stdlib.h
_ModuleInfo
Definition: loadcore.h:31
errno.h
apa_params_t
Definition: libapa.h:135