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

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