958855fce819038e59d92fe63661ee351f69c639
[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, 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         // Create Name
143         gATA_Disks[ Disk ].Name[0] = 'A'+Disk;
144         gATA_Disks[ Disk ].Name[1] = '\0';
145
146         #if 1
147         {
148                 Uint64  val = gATA_Disks[ Disk ].Sectors / 2;
149                 char    *units = "KiB";
150                 if( val > 4*1024 ) {
151                         val /= 1024;
152                         units = "MiB";
153                 }
154                 else if( val > 4*1024 ) {
155                         val /= 1024;
156                         units = "GiB";
157                 }
158                 else if( val > 4*1024 ) {
159                         val /= 1024;
160                         units = "TiB";
161                 }
162                 Log_Notice("ATA", "Disk %s: 0x%llx Sectors (%lli %s)",
163                         gATA_Disks[ Disk ].Name, gATA_Disks[ Disk ].Sectors, val, units);
164         }
165         #endif
166
167         // Get pointer to vfs node and populate it
168         node = &gATA_Disks[ Disk ].Node;
169         node->Size = gATA_Disks[Disk].Sectors * SECTOR_SIZE;
170         node->NumACLs = 0;      // Means Superuser only can access it
171         node->Inode = (Disk << 8) | 0xFF;
172         node->ImplPtr = gATA_Disks[ Disk ].Name;
173
174         node->ATime = node->MTime
175                 = node->CTime = now();
176
177         node->Read = ATA_ReadFS;
178         node->Write = ATA_WriteFS;
179         node->IOCtl = ATA_IOCtl;
180
181         // --- Scan Partitions ---
182         LOG("Reading MBR");
183         // Read Boot Sector
184         if( ATA_ReadDMA( Disk, 0, 1, &mbr ) != 0 ) {
185                 Log_Warning("ATA", "Error in reading MBR on %i", Disk);
186                 LEAVE('i', 0);
187                 return 0;
188         }
189
190         // Check for a GPT table
191         if(mbr.Parts[0].SystemID == 0xEE)
192                 ATA_ParseGPT(Disk);
193         else    // No? Just parse the MBR
194                 ATA_ParseMBR(Disk, &mbr);
195         
196         #if DEBUG >= 2
197         ATA_ReadDMA( Disk, 1, 1, &mbr );
198         Debug_HexDump("ATA_ScanDisk", &mbr, 512);
199         #endif
200
201         LEAVE('i', 1);
202         return 1;
203 }
204
205 /**
206  * \fn void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
207  * \brief Fills a parition's information structure
208  */
209 void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
210 {
211         ENTER("pPart iDisk iNum XStart XLength", Part, Disk, Num, Start, Length);
212         Part->Start = Start;
213         Part->Length = Length;
214         Part->Name[0] = 'A'+Disk;
215         if(Num >= 10) {
216                 Part->Name[1] = '1'+Num/10;
217                 Part->Name[2] = '1'+Num%10;
218                 Part->Name[3] = '\0';
219         } else {
220                 Part->Name[1] = '1'+Num;
221                 Part->Name[2] = '\0';
222         }
223         Part->Node.NumACLs = 0; // Only root can read/write raw block devices
224         Part->Node.Inode = (Disk << 8) | Num;
225         Part->Node.ImplPtr = Part->Name;
226
227         Part->Node.Read = ATA_ReadFS;
228         Part->Node.Write = ATA_WriteFS;
229         Part->Node.IOCtl = ATA_IOCtl;
230         Log_Notice("ATA", "Partition %s at 0x%llx+0x%llx", Part->Name, Part->Start, Part->Length);
231         LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
232         LEAVE('-');
233 }
234
235 /**
236  * \fn void ATA_ParseGPT(int Disk)
237  * \brief Parses the GUID Partition Table
238  */
239 void ATA_ParseGPT(int Disk)
240 {
241         ///\todo Support GPT Disks
242         Warning("GPT Disks are currently unsupported (Disk %i)", Disk);
243 }
244
245 /**
246  * \fn char *ATA_ReadDir(tVFS_Node *Node, int Pos)
247  */
248 char *ATA_ReadDir(tVFS_Node *UNUSED(Node), int Pos)
249 {
250         if(Pos >= giATA_NumNodes || Pos < 0)    return NULL;
251         return strdup( gATA_Nodes[Pos]->ImplPtr );
252 }
253
254 /**
255  * \fn tVFS_Node *ATA_FindDir(tVFS_Node *Node, const char *Name)
256  */
257 tVFS_Node *ATA_FindDir(tVFS_Node *UNUSED(Node), const char *Name)
258 {
259          int    part;
260         tATA_Disk       *disk;
261         
262         // Check first character
263         if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS)
264                 return NULL;
265         disk = &gATA_Disks[Name[0]-'A'];
266         // Raw Disk
267         if(Name[1] == '\0') {
268                 if( disk->Sectors == 0 && disk->Name[0] == '\0')
269                         return NULL;
270                 return &disk->Node;
271         }
272
273         // Partitions
274         if(Name[1] < '0' || '9' < Name[1])      return NULL;
275         if(Name[2] == '\0') {   // <= 9
276                 part = Name[1] - '0';
277                 part --;
278                 return &disk->Partitions[part].Node;
279         }
280         // > 9
281         if('0' > Name[2] || '9' < Name[2])      return NULL;
282         if(Name[3] != '\0')     return NULL;
283
284         part = (Name[1] - '0') * 10;
285         part += Name[2] - '0';
286         part --;
287         return &disk->Partitions[part].Node;
288
289 }
290
291 /**
292  * \fn Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
293  */
294 Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
295 {
296          int    disk = Node->Inode >> 8;
297          int    part = Node->Inode & 0xFF;
298
299         ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
300
301         // Raw Disk Access
302         if(part == 0xFF)
303         {
304                 if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE ) {
305                         LEAVE('i', 0);
306                         return 0;
307                 }
308                 if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
309                         Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
310         }
311         // Partition
312         else
313         {
314                 if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE ) {
315                         LEAVE('i', 0);
316                         return 0;
317                 }
318                 if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
319                         Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
320                 Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
321         }
322
323         {
324                 int ret = DrvUtil_ReadBlock(Offset, Length, Buffer, ATA_ReadRaw, SECTOR_SIZE, disk);
325                 //Log("ATA_ReadFS: disk=%i, Offset=%lli, Length=%lli", disk, Offset, Length);
326                 //Debug_HexDump("ATA_ReadFS", Buffer, Length);
327                 LEAVE('i', ret);
328                 return ret;
329         }
330 }
331
332 /**
333  * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
334  */
335 Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
336 {
337          int    disk = Node->Inode >> 8;
338          int    part = Node->Inode & 0xFF;
339
340         // Raw Disk Access
341         if(part == 0xFF)
342         {
343                 if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
344                         return 0;
345                 if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
346                         Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
347         }
348         // Partition
349         else
350         {
351                 if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
352                         return 0;
353                 if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
354                         Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
355                 Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
356         }
357
358         Log("ATA_WriteFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer);
359         Debug_HexDump("ATA_WriteFS", Buffer, Length);
360         return DrvUtil_WriteBlock(Offset, Length, Buffer, ATA_ReadRaw, ATA_WriteRaw, SECTOR_SIZE, disk);
361 }
362
363 const char      *csaATA_IOCtls[] = {DRV_IOCTLNAMES, DRV_DISK_IOCTLNAMES, NULL};
364 /**
365  * \fn int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
366  * \brief IO Control Funtion
367  */
368 int ATA_IOCtl(tVFS_Node *UNUSED(Node), int Id, void *Data)
369 {
370         switch(Id)
371         {
372         BASE_IOCTLS(DRV_TYPE_DISK, "i386ATA", VERSION, csaATA_IOCtls);
373         
374         case DISK_IOCTL_GETBLOCKSIZE:
375                 return 512;     
376         
377         default:
378                 return 0;
379         }
380         return 0;
381 }
382
383 // --- Disk Access ---
384 /**
385  * \fn Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
386  */
387 Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
388 {
389          int    ret;
390         Uint    offset;
391         Uint    done = 0;
392
393         // Pass straight on to ATA_ReadDMAPage if we can
394         if(Count <= MAX_DMA_SECTORS)
395         {
396                 ret = ATA_ReadDMA(Disk, Address, Count, Buffer);
397                 if(ret == 0)    return 0;
398                 return Count;
399         }
400
401         // Else we will have to break up the transfer
402         offset = 0;
403         while(Count > MAX_DMA_SECTORS)
404         {
405                 ret = ATA_ReadDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
406                 // Check for errors
407                 if(ret != 1)    return done;
408                 // Change Position
409                 done += MAX_DMA_SECTORS;
410                 Count -= MAX_DMA_SECTORS;
411                 offset += MAX_DMA_SECTORS*SECTOR_SIZE;
412         }
413
414         ret = ATA_ReadDMA(Disk, Address+offset, Count, Buffer+offset);
415         if(ret != 1)    return 0;
416         return done+Count;
417 }
418
419 /**
420  * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
421  */
422 Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
423 {
424          int    ret;
425         Uint    offset;
426         Uint    done = 0;
427
428         // Pass straight on to ATA_WriteDMA, if we can
429         if(Count <= MAX_DMA_SECTORS)
430         {
431                 ret = ATA_WriteDMA(Disk, Address, Count, Buffer);
432                 if(ret == 0)    return 0;
433                 return Count;
434         }
435
436         // Else we will have to break up the transfer
437         offset = 0;
438         while(Count > MAX_DMA_SECTORS)
439         {
440                 ret = ATA_WriteDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
441                 // Check for errors
442                 if(ret != 1)    return done;
443                 // Change Position
444                 done += MAX_DMA_SECTORS;
445                 Count -= MAX_DMA_SECTORS;
446                 offset += MAX_DMA_SECTORS*SECTOR_SIZE;
447         }
448
449         ret = ATA_WriteDMA(Disk, Address+offset, Count, Buffer+offset);
450         if(ret != 1)    return 0;
451         return done+Count;
452 }

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