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

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