Added `strdup` library function and removed VFS_FREEPLZ, also added valid tVFS_Node...
[tpg/acess2.git] / Kernel / drv / ata_x86.c
1 /*
2  * Acess2 IDE Harddisk Driver
3  * drv/ide.c
4  */
5 #include <common.h>
6 #include <modules.h>
7 #include <vfs.h>
8 #include <fs_devfs.h>
9 #include <drv_pci.h>
10 #include <tpl_drv_common.h>
11
12 // === CONSTANTS ===
13 #define MAX_ATA_DISKS   4
14 #define SECTOR_SIZE             512
15 #define MAX_DMA_SECTORS (0x1000 / SECTOR_SIZE)
16
17 #define IDE_PRI_BASE    0x1F0
18 #define IDE_SEC_BASE    0x170
19
20 #define IDE_PRDT_LAST   0x8000
21 /**
22  \enum HddControls
23  \brief Commands to be sent to HDD_CMD
24 */
25 enum HddControls {
26         HDD_PIO_R28 = 0x20,
27         HDD_PIO_R48 = 0x24,
28         HDD_DMA_R48 = 0x25,
29         HDD_PIO_W28 = 0x30,
30         HDD_PIO_W48 = 0x34,
31         HDD_DMA_W48 = 0x35,
32         HDD_DMA_R28 = 0xC8,
33         HDD_DMA_W28 = 0xCA,
34 };
35
36 // === STRUCTURES ===
37 typedef struct {
38         Uint32  PBufAddr;
39         Uint16  Bytes;
40         Uint16  Flags;
41 } tPRDT_Ent;
42 typedef struct {
43         Uint16  Flags;          // 1
44         Uint16  Usused1[9];     // 10
45         char    SerialNum[20];  // 20
46         Uint16  Usused2[3];     // 23
47         char    FirmwareVer[8]; // 27
48         char    ModelNumber[40];        // 47
49         Uint16  SectPerInt;     // 48 - and with 0xFF to get true value;
50         Uint16  Unused3;        // 49
51         Uint16  Capabilities[2];        // 51
52         Uint16  Unused4[2];     // 53
53         Uint16  ValidExtData;   // 54
54         Uint16  Unused5[5];      // 59
55         Uint16  SizeOfRWMultiple;       // 60
56         Uint32  Sectors28;      // 62
57         Uint16  Unused6[100-62];
58         Uint64  Sectors48;
59         Uint16  Unused7[256-104];
60 } tIdentify;
61 typedef struct {
62         Uint8   BootCode[0x1BE];
63         struct {
64                 Uint8   Boot;
65                 Uint8   Unused1;        // Also CHS Start
66                 Uint16  StartHi;        // Also CHS Start
67                 Uint8   SystemID;
68                 Uint8   Unused2;        // Also CHS Length
69                 Uint16  LengthHi;       // Also CHS Length
70                 Uint32  LBAStart;
71                 Uint32  LBALength;
72         } __attribute__ ((packed)) Parts[4];
73         Uint16  BootFlag;       // = 0xAA 55
74 } __attribute__ ((packed)) tMBR;
75
76 typedef struct {
77         Uint64  Start;
78         Uint64  Length;
79         char    Name[4];
80         tVFS_Node       Node;
81 } tATA_Partition;
82 typedef struct {
83         Uint64  Sectors;
84         char    Name[2];
85         tVFS_Node       Node;
86          int    NumPartitions;
87         tATA_Partition  *Partitions;
88 } tATA_Disk;
89
90 // === PROTOTYPES ===
91  int    ATA_Install();
92  int    ATA_SetupIO();
93 static void     ATA_SetupPartitions();
94  void   ATA_SetupVFS();
95  int    ATA_ScanDisk(int Disk);
96 void    ATA_ParseGPT(int Disk);
97 void    ATA_ParseMBR(int Disk);
98 void    ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length);
99 Uint16  ATA_GetBasePort(int Disk);
100 char    *ATA_ReadDir(tVFS_Node *Node, int Pos);
101 tVFS_Node       *ATA_FindDir(tVFS_Node *Node, char *Name);
102 Uint64  ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
103  int    ATA_IOCtl(tVFS_Node *Node, int Id, void *Data);
104  int    ATA_Read(Uint8 Disk, Uint64 Address, Uint64 Count, void *Buffer);
105  int    ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
106 void    ATA_IRQHandlerPri(void);
107 void    ATA_IRQHandlerSec(void);
108 Uint8   ATA_int_BusMasterReadByte(int Ofs);
109 void    ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value);
110 void    ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value);
111
112 // === GLOBALS ===
113 MODULE_DEFINE(0, 0x0032, i386ATA, ATA_Install, NULL);
114 tDevFS_Driver   gATA_DriverInfo = {
115         NULL, "ata",
116         {
117                 .NumACLs = 1,
118                 .Size = -1,
119                 .Flags = VFS_FFLAG_DIRECTORY,
120                 .ACLs = &gVFS_ACL_EveryoneRX,
121                 .ReadDir = ATA_ReadDir,
122                 .FindDir = ATA_FindDir
123         }
124 };
125 tATA_Disk       gATA_Disks[MAX_ATA_DISKS];
126  int    giATA_NumNodes;
127 tVFS_Node       **gATA_Nodes;
128 Uint16  gATA_BusMasterBase = 0;
129 Uint8   *gATA_BusMasterBasePtr = 0;
130  int    gATA_IRQPri = 14;
131  int    gATA_IRQSec = 15;
132  int    giaATA_ControllerLock[2] = {0}; //!< Spinlocks for each controller
133 Uint8   gATA_Buffers[2][4096] __attribute__ ((section(".padata")));
134  int    gaATA_IRQs[2] = {0};
135 tPRDT_Ent       gATA_PRDTs[2] = {
136         {0, 512, IDE_PRDT_LAST},
137         {0, 512, IDE_PRDT_LAST}
138 };
139
140 // === CODE ===
141 /**
142  * \fn int ATA_Install()
143  */
144 int ATA_Install()
145 {
146         int     ret;
147         
148         ret = ATA_SetupIO();
149         if(ret != 1)    return ret;
150         
151         ATA_SetupPartitions();
152         
153         ATA_SetupVFS();
154         
155         if( DevFS_AddDevice( &gATA_DriverInfo ) == 0 )
156                 return 0;
157         
158         return 1;
159 }
160
161 /**
162  * \fn int ATA_SetupIO()
163  * \brief Sets up the ATA controller's DMA mode
164  */
165 int ATA_SetupIO()
166 {
167          int    ent;
168         Uint    addr;
169         
170         ENTER("");
171         
172         // Get IDE Controller's PCI Entry
173         ent = PCI_GetDeviceByClass(0x0101, 0xFFFF, -1);
174         LOG("ent = %i\n", ent);
175         gATA_BusMasterBase = PCI_GetBAR4( ent );
176         LOG("gATA_BusMasterBase = 0x%x\n", gATA_BusMasterBase);
177         if( gATA_BusMasterBase == 0 ) {
178                 Warning("It seems that there is no Bus Master Controller on this machine, get one");
179                 LEAVE('i', 0);
180                 return 0;
181         }
182         if( !(gATA_BusMasterBase & 1) )
183         {
184                 if( gATA_BusMasterBase < 0x100000 )
185                         gATA_BusMasterBasePtr = (void*)(0xC0000000|gATA_BusMasterBase);
186                 else
187                         gATA_BusMasterBasePtr = (void*)( MM_MapHWPage( gATA_BusMasterBase, 1 ) + (gATA_BusMasterBase&0xFFF) );
188         }
189         
190         IRQ_AddHandler( gATA_IRQPri, ATA_IRQHandlerPri );
191         IRQ_AddHandler( gATA_IRQSec, ATA_IRQHandlerSec );
192         
193         gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[0] );
194         gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[1] );
195         
196         LOG("gATA_PRDTs = {0x%x, 0x%x}", gATA_PRDTs[0].PBufAddr, gATA_PRDTs[1].PBufAddr);
197         
198         addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[0] );
199         ATA_int_BusMasterWriteDWord(4, addr);
200         addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[1] );
201         ATA_int_BusMasterWriteDWord(12, addr);
202         
203         LEAVE('i', 1);
204         return 1;
205 }
206
207 /**
208  * \fn static void      ATA_SetupPartitions()
209  */
210 static void     ATA_SetupPartitions()
211 {
212          int    i;
213         for( i = 0; i < MAX_ATA_DISKS; i ++ )
214         {
215                 if( !ATA_ScanDisk(i) ) {
216                         gATA_Disks[i].Name[0] = '\0';   // Mark as unused
217                         continue;
218                 }
219         }
220 }
221
222 /**
223  * \fn void ATA_SetupVFS()
224  * \brief Sets up the ATA drivers VFS information and registers with DevFS
225  */
226 void ATA_SetupVFS()
227 {
228          int    i, j, k;
229         
230         // Count number of nodes needed
231         giATA_NumNodes = 0;
232         for( i = 0; i < MAX_ATA_DISKS; i++ )
233         {
234                 if(gATA_Disks[i].Name[0] == '\0')       continue;       // Ignore
235                 giATA_NumNodes ++;
236                 giATA_NumNodes += gATA_Disks[i].NumPartitions;
237         }
238         
239         // Allocate Node space
240         gATA_Nodes = malloc( giATA_NumNodes * sizeof(void*) );
241         
242         // Set nodes
243         k = 0;
244         for( i = 0; i < MAX_ATA_DISKS; i++ )
245         {
246                 if(gATA_Disks[i].Name[0] == '\0')       continue;       // Ignore
247                 gATA_Nodes[ k++ ] = &gATA_Disks[i].Node;
248                 for( j = 0; j < gATA_Disks[i].NumPartitions; j ++ )
249                         gATA_Nodes[ k++ ] = &gATA_Disks[i].Partitions[j].Node;
250         }
251         
252         gATA_DriverInfo.RootNode.Size = giATA_NumNodes;
253 }
254
255 /**
256  * \fn int ATA_ScanDisk(int Disk)
257  */
258 int ATA_ScanDisk(int Disk)
259 {
260         Uint16  buf[256];
261         tIdentify       *identify = (void*)buf;
262         tMBR    *mbr = (void*)buf;
263         Uint16  base;
264         Uint8   val;
265          int    i;
266         tVFS_Node       *node;
267         
268         base = ATA_GetBasePort( Disk );
269         
270         // Send Disk Selector
271         if(Disk == 1 || Disk == 3)
272                 outb(base+6, 0xB0);
273         else
274                 outb(base+6, 0xA0);
275         
276         // Send IDENTIFY
277         outb(base+7, 0xEC);
278         val = inb(base+7);      // Read status
279         if(val == 0)    return 0;       // Disk does not exist
280         
281         // Poll until BSY clears and DRQ sets or ERR is set
282         while( ((val & 0x80) || !(val & 0x08)) && !(val & 1))   val = inb(base+7);
283         
284         if(val & 1)     return 0;       // Error occured, so return false
285         
286         // Read Data
287         for(i=0;i<256;i++)      buf[i] = inw(base);
288         
289         // Populate Disk Structure
290         if(identify->Sectors48 != 0)
291                 gATA_Disks[ Disk ].Sectors = identify->Sectors48;
292         else
293                 gATA_Disks[ Disk ].Sectors = identify->Sectors28;
294         
295         
296         if( gATA_Disks[ Disk ].Sectors / (2048*1024) )
297                 Log("Disk %i: 0x%llx Sectors (%i GiB)", Disk,
298                         gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / (2048*1024));
299         else if( gATA_Disks[ Disk ].Sectors / 2048 )
300                 Log("Disk %i: 0x%llx Sectors (%i MiB)", Disk,
301                         gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / 2048);
302         else
303                 Log("Disk %i: 0x%llx Sectors (%i KiB)", Disk,
304                         gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / 2);
305         
306         // Create Name
307         gATA_Disks[ Disk ].Name[0] = 'A'+Disk;
308         gATA_Disks[ Disk ].Name[1] = '\0';
309         
310         // Get pointer to vfs node and populate it
311         node = &gATA_Disks[ Disk ].Node;
312         node->Size = gATA_Disks[Disk].Sectors * SECTOR_SIZE;
313         node->NumACLs = 0;      // Means Superuser only can access it
314         node->Inode = (Disk << 8) | 0xFF;
315         node->ImplPtr = gATA_Disks[ Disk ].Name;
316         
317         node->ATime = node->MTime
318                 = node->CTime = now();
319         
320         node->Read = ATA_ReadFS;
321         //node->Write = ATA_WriteFS;
322         node->IOCtl = ATA_IOCtl;
323
324
325         // --- Scan Partitions ---
326         // Read Boot Sector
327         ATA_ReadDMA( Disk, 0, 1, mbr );
328         
329         // Check for a GPT table
330         if(mbr->Parts[0].SystemID == 0xEE)
331                 ATA_ParseGPT(Disk);
332         else    // No? Just parse the MBR
333                 ATA_ParseMBR(Disk);
334         
335         return 1;
336 }
337
338 /**
339  * \fn void ATA_ParseGPT(int Disk)
340  * \brief Parses the GUID Partition Table
341  */
342 void ATA_ParseGPT(int Disk)
343 {
344         ///\todo Support GPT Disks
345         Warning("GPT Disks are currently unsupported");
346 }
347
348 /**
349  * \fn void ATA_ParseMBR(int Disk)
350  */
351 void ATA_ParseMBR(int Disk)
352 {
353          int    i, j = 0, k = 4;
354         tMBR    mbr;
355         Uint64  extendedLBA;
356         
357         // Read Boot Sector
358         ATA_ReadDMA( Disk, 0, 1, &mbr );
359         
360         // Count Partitions
361         gATA_Disks[Disk].NumPartitions = 0;
362         extendedLBA = 0;
363         for( i = 0; i < 4; i ++ )
364         {
365                 if( mbr.Parts[i].SystemID == 0 )        continue;
366                 if(
367                         mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80   // LBA 28
368                 ||      mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81   // LBA 48
369                         )
370                 {
371                         if( mbr.Parts[i].SystemID == 0xF || mbr.Parts[i].SystemID == 5 ) {
372                                 if(extendedLBA != 0) {
373                                         Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
374                                         continue;
375                                 }
376                                 extendedLBA = mbr.Parts[i].LBAStart;
377                                 continue;
378                         }
379                         
380                         gATA_Disks[Disk].NumPartitions ++;
381                         continue;
382                 }
383                 // Invalid Partition, so don't count it
384         }
385         while(extendedLBA != 0)
386         {
387                 if( ATA_ReadDMA( Disk, extendedLBA, 1, &mbr ) != 0 )
388                         break;  // Stop on Errors
389                 
390                 extendedLBA = 0;
391                 
392                 if( mbr.Parts[0].SystemID == 0 )        continue;
393                 if(     mbr.Parts[0].Boot == 0x0 || mbr.Parts[0].Boot == 0x80   // LBA 28
394                 ||      mbr.Parts[0].Boot == 0x1 || mbr.Parts[0].Boot == 0x81   // LBA 48
395                         )
396                 {
397                         if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
398                                 extendedLBA = mbr.Parts[0].LBAStart;
399                         else
400                                 gATA_Disks[Disk].NumPartitions ++;
401                 }
402                 
403                 if( mbr.Parts[1].SystemID == 0 )        continue;
404                 if(     mbr.Parts[1].Boot == 0x0 || mbr.Parts[1].Boot == 0x80   // LBA 28
405                 ||      mbr.Parts[1].Boot == 0x1 || mbr.Parts[1].Boot == 0x81   // LBA 48
406                         )
407                 {
408                         if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
409                                 if(extendedLBA == 0) {
410                                         Warning("Disk %i has twp forward link in the extended partition",
411                                                 Disk);
412                                         break;
413                                 }
414                                 extendedLBA = mbr.Parts[1].LBAStart;
415                         }
416                         else {
417                                 if(extendedLBA != 0) {
418                                         Warning("Disk %i lacks a forward link in the extended partition",
419                                                 Disk);
420                                         break;
421                                 }
422                                 gATA_Disks[Disk].NumPartitions ++;
423                         }
424                 }
425         }
426         
427         // Create patition array
428         gATA_Disks[Disk].Partitions = malloc( gATA_Disks[Disk].NumPartitions * sizeof(tATA_Partition) );
429         
430         // --- Fill Partition Info ---
431         extendedLBA = 0;
432         for( i = 0; i < 4; i ++ )
433         {
434                 if( mbr.Parts[i].SystemID == 0 )        continue;
435                 if(     mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 ) // LBA 28
436                 {
437                         if( mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 5 ) {
438                                 if(extendedLBA != 0) {
439                                         Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
440                                         continue;
441                                 }
442                                 extendedLBA = mbr.Parts[1].LBAStart;
443                                 continue;
444                         }
445                         // Create Partition
446                         ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, i,
447                                 mbr.Parts[i].LBAStart, mbr.Parts[i].LBALength
448                                 );
449                         j ++;
450                         continue;
451                 }
452                 if(     mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 ) // LBA 48
453                 {
454                         if( mbr.Parts[i].SystemID == 0xF || mbr.Parts[i].SystemID == 5 ) {
455                                 if(extendedLBA != 0) {
456                                         Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
457                                         continue;
458                                 }
459                                 extendedLBA = (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart;
460                                 continue;
461                         }
462                         ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, i,
463                                 (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart,
464                                 (mbr.Parts[i].LengthHi << 16) | mbr.Parts[i].LBALength
465                                 );
466                         j ++;
467                 }
468                 // Invalid Partition, so don't count it
469         }
470         // Scan extended partition
471         while(extendedLBA != 0)
472         {
473                 if( ATA_ReadDMA( Disk, extendedLBA, 1, &mbr ) != 0 )
474                         break;  // Stop on Errors
475                 
476                 extendedLBA = 0;
477                 
478                 // Check first entry (should be partition)
479                 if( mbr.Parts[0].SystemID != 0)
480                 {
481                         if( mbr.Parts[0].Boot == 0x0 || mbr.Parts[0].Boot == 0x80 )     // LBA 28
482                         {
483                                 // Forward Link to next Extended partition entry
484                                 if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
485                                         extendedLBA = mbr.Parts[0].LBAStart;
486                                 else {
487                                         ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
488                                                 mbr.Parts[0].LBAStart, mbr.Parts[0].LBALength
489                                                 );
490                                         j ++;   k ++;
491                                 }
492                         }
493                         else if( mbr.Parts[0].Boot == 0x1 || mbr.Parts[0].Boot == 0x81 )        // LBA 48
494                         {
495                                 if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7)
496                                         extendedLBA = (mbr.Parts[0].StartHi << 16) | mbr.Parts[0].LBAStart;
497                                 else {
498                                         ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
499                                                 (mbr.Parts[0].StartHi << 16) | mbr.Parts[0].LBAStart,
500                                                 (mbr.Parts[0].LengthHi << 16) | mbr.Parts[0].LBALength
501                                                 );
502                                         j ++;   k ++;
503                                 }
504                         }
505                 }
506                 
507                 // Check second entry (should be forward link)
508                 if( mbr.Parts[1].SystemID != 0)
509                 {
510                         if(mbr.Parts[1].Boot == 0x0 || mbr.Parts[1].Boot == 0x80 )      // LBA 28
511                         {
512                                 if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
513                                         if(extendedLBA == 0) {
514                                                 Warning("Disk %i has twp forward link in the extended partition",
515                                                         Disk);
516                                                 break;
517                                         }
518                                         extendedLBA = mbr.Parts[1].LBAStart;
519                                 }
520                                 else
521                                 {
522                                         if(extendedLBA != 0) {
523                                                 Warning("Disk %i lacks a forward link in the extended partition",
524                                                         Disk);
525                                                 break;
526                                         }
527                                         ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
528                                                 mbr.Parts[1].LBAStart, mbr.Parts[1].LBALength
529                                                 );
530                                         j ++;   k ++;
531                                 }
532                                 
533                         }
534                         else if( mbr.Parts[1].Boot == 0x1 || mbr.Parts[1].Boot == 0x81 )        // LBA 48
535                         {
536                                 if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) {
537                                         if(extendedLBA == 0) {
538                                                 Warning("Disk %i has twp forward link in the extended partition",
539                                                         Disk);
540                                                 break;
541                                         }
542                                         extendedLBA = (mbr.Parts[1].StartHi << 16) | mbr.Parts[1].LBAStart;
543                                 }
544                                 else
545                                 {
546                                         if(extendedLBA != 0) {
547                                                 Warning("Disk %i lacks a forward link in the extended partition",
548                                                         Disk);
549                                                 break;
550                                         }
551                                         ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k,
552                                                 (mbr.Parts[1].StartHi << 16) | mbr.Parts[1].LBAStart,
553                                                 (mbr.Parts[1].LengthHi << 16) | mbr.Parts[1].LBALength
554                                                 );
555                                         j ++;   k ++;
556                                 }
557                         }
558                 }
559         }
560 }
561
562 /**
563  * \fn void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
564  * \brief Fills a parition's information structure
565  */
566 void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
567 {
568         ENTER("pPart iDisk iNum XStart XLength", Part, Disk, Num, Start, Length);
569         Part->Start = Start;
570         Part->Length = Length;
571         Part->Name[0] = 'A'+Disk;
572         if(Num >= 10) {
573                 Part->Name[1] = '1'+Num/10;
574                 Part->Name[2] = '1'+Num%10;
575                 Part->Name[3] = '\0';
576         } else {
577                 Part->Name[1] = '1'+Num;
578                 Part->Name[2] = '\0';
579         }
580         Part->Node.NumACLs = 0; // Only root can read/write raw block devices
581         Part->Node.Inode = (Disk << 8) | Num;
582         Part->Node.ImplPtr = Part->Name;
583         
584         Part->Node.Read = ATA_ReadFS;
585         Part->Node.IOCtl = ATA_IOCtl;
586         LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
587         LEAVE('-');
588 }
589
590 /**
591  * \fn Uint16 ATA_GetPortBase(int Disk)
592  * \brief Returns the base port for a given disk
593  */
594 Uint16 ATA_GetBasePort(int Disk)
595 {
596         switch(Disk)
597         {
598         case 0: case 1:         return IDE_PRI_BASE;
599         case 2: case 3:         return IDE_SEC_BASE;
600         }
601         return 0;
602 }
603
604 /**
605  * \fn char *ATA_ReadDir(tVFS_Node *Node, int Pos)
606  */
607 char *ATA_ReadDir(tVFS_Node *Node, int Pos)
608 {
609         if(Pos >= giATA_NumNodes || Pos < 0)    return NULL;
610         return strdup( gATA_Nodes[Pos]->ImplPtr );
611 }
612
613 /**
614  * \fn tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name)
615  */
616 tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name)
617 {
618          int    part;
619         // Check first character
620         if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS)
621                 return NULL;
622         // Raw Disk
623         if(Name[1] == '\0')     return &gATA_Disks[Name[0]-'A'].Node;
624         
625         // Partitions
626         if(Name[1] < '0' || '9' < Name[1])      return NULL;
627         if(Name[2] == '\0') {   // <= 9
628                 part = Name[1] - '0';
629                 part --;
630                 return &gATA_Disks[Name[0]-'A'].Partitions[part].Node;
631         }
632         // > 9
633         if('0' > Name[2] || '9' < Name[2])      return NULL;
634         if(Name[3] != '\0')     return NULL;
635         
636         part = (Name[1] - '0') * 10;
637         part += Name[2] - '0';
638         part --;
639         return &gATA_Disks[Name[0]-'A'].Partitions[part].Node;
640         
641 }
642
643 /**
644  * \fn Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
645  */
646 Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
647 {
648          int    ret;
649          int    disk, part;
650         Uint64  sector, count;
651         
652         disk = Node->Inode >> 8;
653         part = Node->Inode & 0xFF;
654         
655         // Aligned Read
656         if(Offset % SECTOR_SIZE == 0 && Length % SECTOR_SIZE == 0)
657         {
658                 sector = Offset / SECTOR_SIZE;
659                 count = Length / SECTOR_SIZE;
660                 // Raw Disk?
661                 if(part == 0xFF)
662                 {
663                         // Bounds Check
664                         if( sector >= gATA_Disks[disk].Sectors )        return 0;
665                         if( sector + count > gATA_Disks[disk].Sectors )
666                                 count = gATA_Disks[disk].Sectors - sector;
667                         // Read Data
668                         ret = ATA_Read(disk, sector, count, Buffer);
669                 }
670                 else    // Or a partition
671                 {
672                         //Log(" ATA_ReadFS: %i:%i 0x%llx + 0x%llx\n", disk, part,
673                         //      gATA_Disks[disk].Partitions[part].Start,
674                         //      gATA_Disks[disk].Partitions[part].Length );
675                         
676                         // Bounds Check
677                         if( sector >= gATA_Disks[disk].Partitions[part].Length )        return 0;
678                         if( sector + count > gATA_Disks[disk].Partitions[part].Length )
679                                 count = gATA_Disks[disk].Partitions[part].Length - sector;
680                         // Read Disk
681                         ret = ATA_Read(disk,
682                                 gATA_Disks[disk].Partitions[part].Start + sector,
683                                 count,
684                                 Buffer);
685                 }
686                 // Check return value
687                 if(ret == 1)
688                         return count * SECTOR_SIZE;
689                 else {
690                         Warning("ATA_ReadFS: RETURN 0 (Read failed with ret = %i)", ret);
691                         return 0;
692                 }
693         }
694         Warning("ATA_ReadFS: RETURN 0 (Non-Aligned Read 0x%llx 0x%llx)", Offset, Length);
695         return 0;
696 }
697
698 /**
699  * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
700  */
701 Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
702 {
703         return 0;
704 }
705
706 /**
707  * \fn int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
708  * \brief IO Control Funtion
709  */
710 int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
711 {
712         switch(Id)
713         {
714         case DRV_IOCTL_TYPE:    return DRV_TYPE_DISK;
715         }
716         return 0;
717 }
718
719 // --- Disk Access ---
720 /**
721  * \fn int ATA_Read(Uint8 Disk, Uint64 Address, Uint64 Count, void *Buffer)
722  */
723 int ATA_Read(Uint8 Disk, Uint64 Address, Uint64 Count, void *Buffer)
724 {
725          int    ret;
726         Uint    offset;
727          
728         // Pass straight on to ATA_ReadDMAPage if we can
729         if(Count <= MAX_DMA_SECTORS)
730                 return ATA_ReadDMA(Disk, Address, Count, Buffer);
731         
732         // Else we will have to break up the transfer
733         offset = 0;
734         while(Count > MAX_DMA_SECTORS)
735         {
736                 ret = ATA_ReadDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
737                 // Check for errors
738                 if(ret != 1)    return ret;
739                 // Change Position
740                 Count -= MAX_DMA_SECTORS;
741                 offset += MAX_DMA_SECTORS*SECTOR_SIZE;
742         }
743         
744         return ATA_ReadDMA(Disk, Address+offset, Count, Buffer+offset);
745 }
746
747 /**
748  * \fn int ATA_ReadDMAPage(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
749  */
750 int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
751 {
752          int    cont = (Disk>>1)&1;     // Controller ID
753          int    disk = Disk & 1;
754         Uint16  base;
755         
756         // Check if the count is small enough
757         if(Count > MAX_DMA_SECTORS)     return -1;
758         
759         // Get exclusive access to the disk controller
760         LOCK( &giaATA_ControllerLock[ cont ] );
761         
762         // Set Size
763         gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
764         
765         // Get Port Base
766         base = ATA_GetBasePort(Disk);
767         
768         // Set up transfer
769         outb(base+0x01, 0x00);
770         if( Address > 0x0FFFFFFF )      // Use LBA48
771         {
772                 outb(base+0x6, 0x40 | (disk << 4));
773                 outb(base+0x2, 0 >> 8); // Upper Sector Count
774                 outb(base+0x3, Address >> 24);  // Low 2 Addr
775                 outb(base+0x3, Address >> 28);  // Mid 2 Addr
776                 outb(base+0x3, Address >> 32);  // High 2 Addr
777         }
778         else
779         {
780                 outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); //Disk,Magic,High addr
781         }
782         
783         outb(base+0x02, (Uint8) Count);         // Sector Count
784         outb(base+0x03, (Uint8) Address);               // Low Addr
785         outb(base+0x04, (Uint8) (Address >> 8));        // Middle Addr
786         outb(base+0x05, (Uint8) (Address >> 16));       // High Addr
787         if( Address > 0x0FFFFFFF )
788                 outb(base+0x07, HDD_DMA_R48);   // Read Command (LBA48)
789         else
790                 outb(base+0x07, HDD_DMA_R28);   // Read Command (LBA28)
791         
792         // Reset IRQ Flag
793         gaATA_IRQs[cont] = 0;
794         
795         // Start transfer
796         ATA_int_BusMasterWriteByte( cont << 3, 9 );     // Read and start
797         
798         // Wait for transfer to complete
799         while( gaATA_IRQs[cont] == 0 )  Threads_Yield();
800         
801         // Complete Transfer
802         ATA_int_BusMasterWriteByte( cont << 3, 0 );     // Write and stop
803         
804         // Copy to destination buffer
805         memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE );
806         
807         // Release controller lock
808         RELEASE( &giaATA_ControllerLock[ cont ] );
809         
810         return 1;
811 }
812
813 /**
814  * \fn void ATA_IRQHandlerPri(void)
815  */
816 void ATA_IRQHandlerPri(void)
817 {
818         Uint8   val;
819         
820         // IRQ bit set for Primary Controller
821         val = ATA_int_BusMasterReadByte( 0x2 );
822         if(val & 4) {
823                 //Log(" ATA_IRQHandlerPri: IRQ hit (val = 0x%x)", val);
824                 ATA_int_BusMasterWriteByte( 0x2, 4 );
825                 gaATA_IRQs[0] = 1;
826                 return ;
827         }
828 }
829
830 /**
831  * \fn void ATA_IRQHandlerSec(void)
832  */
833 void ATA_IRQHandlerSec(void)
834 {
835         Uint8   val;
836         // IRQ bit set for Secondary Controller
837         val = ATA_int_BusMasterReadByte( 0xA );
838         if(val & 4) {
839                 //Log(" ATA_IRQHandlerSec: IRQ hit (val = 0x%x)", val);
840                 ATA_int_BusMasterWriteByte( 0xA, 4 );
841                 gaATA_IRQs[1] = 1;
842                 return ;
843         }
844 }
845
846 /**
847  * \fn Uint8 ATA_int_BusMasterReadByte(int Ofs)
848  */
849 Uint8 ATA_int_BusMasterReadByte(int Ofs)
850 {
851         if( gATA_BusMasterBase & 1 )
852                 return inb( (gATA_BusMasterBase & ~1) + Ofs );
853         else
854                 return *(Uint8*)(gATA_BusMasterBasePtr + Ofs);
855 }
856
857 /**
858  * \fn void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
859  * \brief Writes a byte to a Bus Master Register
860  */
861 void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
862 {
863         if( gATA_BusMasterBase & 1 )
864                 outb( (gATA_BusMasterBase & ~1) + Ofs, Value );
865         else
866                 *(Uint8*)(gATA_BusMasterBasePtr + Ofs) = Value;
867 }
868
869 /**
870  * \fn void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
871  * \brief Writes a dword to a Bus Master Register
872  */
873 void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
874 {
875         
876         if( gATA_BusMasterBase & 1 )
877                 outd( (gATA_BusMasterBase & ~1) + Ofs, Value );
878         else
879                 *(Uint32*)(gATA_BusMasterBasePtr + Ofs) = Value;
880 }

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