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

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