SpiderScript - Commenting changes
[tpg/acess2.git] / Modules / Storage / ATA / main.c
1 /*
2  * Acess2 IDE Harddisk Driver
3  * - main.c
4  */
5 #define DEBUG   0
6 #define VERSION 0x0032
7 #include <acess.h>
8 #include <modules.h>
9 #include <vfs.h>
10 #include <fs_devfs.h>
11 #include <tpl_drv_common.h>
12 #include <tpl_drv_disk.h>
13 #include "common.h"
14
15 // === MACROS ===
16 #define IO_DELAY()      do{inb(0x80); inb(0x80); inb(0x80); inb(0x80);}while(0)
17
18 // === PROTOTYPES ===
19  int    ATA_Install(char **Arguments);
20 void    ATA_SetupPartitions(void);
21 void    ATA_SetupVFS(void);
22  int    ATA_ScanDisk(int Disk);
23 void    ATA_ParseGPT(int Disk);
24 void    ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length);
25 Uint16  ATA_GetBasePort(int Disk);
26 // Filesystem Interface
27 char    *ATA_ReadDir(tVFS_Node *Node, int Pos);
28 tVFS_Node       *ATA_FindDir(tVFS_Node *Node, const char *Name);
29 Uint64  ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
30 Uint64  ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
31  int    ATA_IOCtl(tVFS_Node *Node, int Id, void *Data);
32 // Read/Write Interface/Quantiser
33 Uint    ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
34 Uint    ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
35
36 // === GLOBALS ===
37 MODULE_DEFINE(0, VERSION, i386ATA, ATA_Install, NULL, "PCI", NULL);
38 tDevFS_Driver   gATA_DriverInfo = {
39         NULL, "ata",
40         {
41                 .NumACLs = 1,
42                 .Size = -1,
43                 .Flags = VFS_FFLAG_DIRECTORY,
44                 .ACLs = &gVFS_ACL_EveryoneRX,
45                 .ReadDir = ATA_ReadDir,
46                 .FindDir = ATA_FindDir
47         }
48 };
49 tATA_Disk       gATA_Disks[MAX_ATA_DISKS];
50  int    giATA_NumNodes;
51 tVFS_Node       **gATA_Nodes;
52
53 // === CODE ===
54 /**
55  * \brief Initialise the ATA driver
56  */
57 int ATA_Install(char **Arguments)
58 {
59         int     ret;
60
61         ret = ATA_SetupIO();
62         if(ret) return ret;
63
64         ATA_SetupPartitions();
65
66         ATA_SetupVFS();
67
68         if( DevFS_AddDevice( &gATA_DriverInfo ) == 0 )
69                 return MODULE_ERR_MISC;
70
71         return MODULE_ERR_OK;
72 }
73
74 /**
75  * \brief Scan all disks, looking for partitions
76  */
77 void ATA_SetupPartitions(void)
78 {
79          int    i;
80         for( i = 0; i < MAX_ATA_DISKS; i ++ )
81         {
82                 if( !ATA_ScanDisk(i) ) {
83                         gATA_Disks[i].Name[0] = '\0';   // Mark as unused
84                         continue;
85                 }
86         }
87 }
88
89 /**
90  * \brief Sets up the ATA drivers VFS information and registers with DevFS
91  */
92 void ATA_SetupVFS(void)
93 {
94          int    i, j, k;
95
96         // Count number of nodes needed
97         giATA_NumNodes = 0;
98         for( i = 0; i < MAX_ATA_DISKS; i++ )
99         {
100                 if(gATA_Disks[i].Name[0] == '\0')       continue;       // Ignore
101                 giATA_NumNodes ++;
102                 giATA_NumNodes += gATA_Disks[i].NumPartitions;
103         }
104
105         // Allocate Node space
106         gATA_Nodes = malloc( giATA_NumNodes * sizeof(void*) );
107
108         // Set nodes
109         k = 0;
110         for( i = 0; i < MAX_ATA_DISKS; i++ )
111         {
112                 if(gATA_Disks[i].Name[0] == '\0')       continue;       // Ignore
113                 gATA_Nodes[ k++ ] = &gATA_Disks[i].Node;
114                 for( j = 0; j < gATA_Disks[i].NumPartitions; j ++ )
115                         gATA_Nodes[ k++ ] = &gATA_Disks[i].Partitions[j].Node;
116         }
117
118         gATA_DriverInfo.RootNode.Size = giATA_NumNodes;
119 }
120
121 /**
122  * \brief Scan a disk, getting the size and any paritions
123  * \param Disk  Disk ID to scan
124  */
125 int ATA_ScanDisk(int Disk)
126 {
127         tVFS_Node       *node;
128         tMBR    mbr;
129
130         ENTER("iDisk", Disk);
131         
132         // Get the disk size
133         gATA_Disks[ Disk ].Sectors = ATA_GetDiskSize(Disk);
134         if(gATA_Disks[ Disk ].Sectors == 0)
135         {
136                 LEAVE('i', 0);
137                 return 0;
138         }
139
140         LOG("gATA_Disks[ %i ].Sectors = 0x%x", Disk, gATA_Disks[ Disk ].Sectors);
141
142         {
143                 Uint64  val = gATA_Disks[ Disk ].Sectors / 2;
144                 char    *units = "KiB";
145                 if( val > 4*1024 ) {
146                         val /= 1024;
147                         units = "MiB";
148                 }
149                 else if( val > 4*1024 ) {
150                         val /= 1024;
151                         units = "GiB";
152                 }
153                 else if( val > 4*1024 ) {
154                         val /= 1024;
155                         units = "TiB";
156                 }
157                 Log_Log("ATA", "Disk %i: 0x%llx Sectors (%lli %s)", Disk,
158                         gATA_Disks[ Disk ].Sectors, val, units);
159         }
160
161         // Create Name
162         gATA_Disks[ Disk ].Name[0] = 'A'+Disk;
163         gATA_Disks[ Disk ].Name[1] = '\0';
164
165         // Get pointer to vfs node and populate it
166         node = &gATA_Disks[ Disk ].Node;
167         node->Size = gATA_Disks[Disk].Sectors * SECTOR_SIZE;
168         node->NumACLs = 0;      // Means Superuser only can access it
169         node->Inode = (Disk << 8) | 0xFF;
170         node->ImplPtr = gATA_Disks[ Disk ].Name;
171
172         node->ATime = node->MTime
173                 = node->CTime = now();
174
175         node->Read = ATA_ReadFS;
176         node->Write = ATA_WriteFS;
177         node->IOCtl = ATA_IOCtl;
178
179         // --- Scan Partitions ---
180         LOG("Reading MBR");
181         // Read Boot Sector
182         if( ATA_ReadDMA( Disk, 0, 1, &mbr ) != 0 ) {
183                 Log_Warning("ATA", "Error in reading MBR on %i", Disk);
184                 LEAVE('i', 0);
185                 return 0;
186         }
187
188         // Check for a GPT table
189         if(mbr.Parts[0].SystemID == 0xEE)
190                 ATA_ParseGPT(Disk);
191         else    // No? Just parse the MBR
192                 ATA_ParseMBR(Disk, &mbr);
193         
194         #if DEBUG >= 2
195         ATA_ReadDMA( Disk, 1, 1, &mbr );
196         Debug_HexDump("ATA_ScanDisk", &mbr, 512);
197         #endif
198
199         LEAVE('i', 1);
200         return 1;
201 }
202
203 /**
204  * \fn void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
205  * \brief Fills a parition's information structure
206  */
207 void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
208 {
209         ENTER("pPart iDisk iNum XStart XLength", Part, Disk, Num, Start, Length);
210         Part->Start = Start;
211         Part->Length = Length;
212         Part->Name[0] = 'A'+Disk;
213         if(Num >= 10) {
214                 Part->Name[1] = '1'+Num/10;
215                 Part->Name[2] = '1'+Num%10;
216                 Part->Name[3] = '\0';
217         } else {
218                 Part->Name[1] = '1'+Num;
219                 Part->Name[2] = '\0';
220         }
221         Part->Node.NumACLs = 0; // Only root can read/write raw block devices
222         Part->Node.Inode = (Disk << 8) | Num;
223         Part->Node.ImplPtr = Part->Name;
224
225         Part->Node.Read = ATA_ReadFS;
226         Part->Node.Write = ATA_WriteFS;
227         Part->Node.IOCtl = ATA_IOCtl;
228         Log_Notice("ATA", "Note '%s' at 0x%llx, 0x%llx long", Part->Name, Part->Start, Part->Length);
229         LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
230         LEAVE('-');
231 }
232
233 /**
234  * \fn void ATA_ParseGPT(int Disk)
235  * \brief Parses the GUID Partition Table
236  */
237 void ATA_ParseGPT(int Disk)
238 {
239         ///\todo Support GPT Disks
240         Warning("GPT Disks are currently unsupported (Disk %i)", Disk);
241 }
242
243 /**
244  * \fn char *ATA_ReadDir(tVFS_Node *Node, int Pos)
245  */
246 char *ATA_ReadDir(tVFS_Node *UNUSED(Node), int Pos)
247 {
248         if(Pos >= giATA_NumNodes || Pos < 0)    return NULL;
249         return strdup( gATA_Nodes[Pos]->ImplPtr );
250 }
251
252 /**
253  * \fn tVFS_Node *ATA_FindDir(tVFS_Node *Node, const char *Name)
254  */
255 tVFS_Node *ATA_FindDir(tVFS_Node *UNUSED(Node), const char *Name)
256 {
257          int    part;
258         tATA_Disk       *disk;
259         
260         // Check first character
261         if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS)
262                 return NULL;
263         disk = &gATA_Disks[Name[0]-'A'];
264         // Raw Disk
265         if(Name[1] == '\0') {
266                 if( disk->Sectors == 0 && disk->Name[0] == '\0')
267                         return NULL;
268                 return &disk->Node;
269         }
270
271         // Partitions
272         if(Name[1] < '0' || '9' < Name[1])      return NULL;
273         if(Name[2] == '\0') {   // <= 9
274                 part = Name[1] - '0';
275                 part --;
276                 return &disk->Partitions[part].Node;
277         }
278         // > 9
279         if('0' > Name[2] || '9' < Name[2])      return NULL;
280         if(Name[3] != '\0')     return NULL;
281
282         part = (Name[1] - '0') * 10;
283         part += Name[2] - '0';
284         part --;
285         return &disk->Partitions[part].Node;
286
287 }
288
289 /**
290  * \fn Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
291  */
292 Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
293 {
294          int    disk = Node->Inode >> 8;
295          int    part = Node->Inode & 0xFF;
296
297         ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
298
299         // Raw Disk Access
300         if(part == 0xFF)
301         {
302                 if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE ) {
303                         LEAVE('i', 0);
304                         return 0;
305                 }
306                 if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
307                         Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
308         }
309         // Partition
310         else
311         {
312                 if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE ) {
313                         LEAVE('i', 0);
314                         return 0;
315                 }
316                 if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
317                         Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
318                 Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
319         }
320
321         {
322                 int ret = DrvUtil_ReadBlock(Offset, Length, Buffer, ATA_ReadRaw, SECTOR_SIZE, disk);
323                 //Log("ATA_ReadFS: disk=%i, Offset=%lli, Length=%lli", disk, Offset, Length);
324                 //Debug_HexDump("ATA_ReadFS", Buffer, Length);
325                 LEAVE('i', ret);
326                 return ret;
327         }
328 }
329
330 /**
331  * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
332  */
333 Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
334 {
335          int    disk = Node->Inode >> 8;
336          int    part = Node->Inode & 0xFF;
337
338         // Raw Disk Access
339         if(part == 0xFF)
340         {
341                 if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
342                         return 0;
343                 if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
344                         Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
345         }
346         // Partition
347         else
348         {
349                 if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
350                         return 0;
351                 if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
352                         Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
353                 Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
354         }
355
356         Log("ATA_WriteFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer);
357         Debug_HexDump("ATA_WriteFS", Buffer, Length);
358         return DrvUtil_WriteBlock(Offset, Length, Buffer, ATA_ReadRaw, ATA_WriteRaw, SECTOR_SIZE, disk);
359 }
360
361 const char      *csaATA_IOCtls[] = {DRV_IOCTLNAMES, DRV_DISK_IOCTLNAMES, NULL};
362 /**
363  * \fn int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
364  * \brief IO Control Funtion
365  */
366 int ATA_IOCtl(tVFS_Node *UNUSED(Node), int Id, void *Data)
367 {
368         switch(Id)
369         {
370         BASE_IOCTLS(DRV_TYPE_DISK, "i386ATA", VERSION, csaATA_IOCtls);
371         
372         case DISK_IOCTL_GETBLOCKSIZE:
373                 return 512;     
374         
375         default:
376                 return 0;
377         }
378         return 0;
379 }
380
381 // --- Disk Access ---
382 /**
383  * \fn Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
384  */
385 Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
386 {
387          int    ret;
388         Uint    offset;
389         Uint    done = 0;
390
391         // Pass straight on to ATA_ReadDMAPage if we can
392         if(Count <= MAX_DMA_SECTORS)
393         {
394                 ret = ATA_ReadDMA(Disk, Address, Count, Buffer);
395                 if(ret == 0)    return 0;
396                 return Count;
397         }
398
399         // Else we will have to break up the transfer
400         offset = 0;
401         while(Count > MAX_DMA_SECTORS)
402         {
403                 ret = ATA_ReadDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
404                 // Check for errors
405                 if(ret != 1)    return done;
406                 // Change Position
407                 done += MAX_DMA_SECTORS;
408                 Count -= MAX_DMA_SECTORS;
409                 offset += MAX_DMA_SECTORS*SECTOR_SIZE;
410         }
411
412         ret = ATA_ReadDMA(Disk, Address+offset, Count, Buffer+offset);
413         if(ret != 1)    return 0;
414         return done+Count;
415 }
416
417 /**
418  * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
419  */
420 Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
421 {
422          int    ret;
423         Uint    offset;
424         Uint    done = 0;
425
426         // Pass straight on to ATA_WriteDMA, if we can
427         if(Count <= MAX_DMA_SECTORS)
428         {
429                 ret = ATA_WriteDMA(Disk, Address, Count, Buffer);
430                 if(ret == 0)    return 0;
431                 return Count;
432         }
433
434         // Else we will have to break up the transfer
435         offset = 0;
436         while(Count > MAX_DMA_SECTORS)
437         {
438                 ret = ATA_WriteDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
439                 // Check for errors
440                 if(ret != 1)    return done;
441                 // Change Position
442                 done += MAX_DMA_SECTORS;
443                 Count -= MAX_DMA_SECTORS;
444                 offset += MAX_DMA_SECTORS*SECTOR_SIZE;
445         }
446
447         ret = ATA_WriteDMA(Disk, Address+offset, Count, Buffer+offset);
448         if(ret != 1)    return 0;
449         return done+Count;
450 }

UCC git Repository :: git.ucc.asn.au