2 * Acess2 IDE Harddisk Driver
11 #include <api_drv_common.h>
12 #include <api_drv_disk.h>
16 #define IO_DELAY() do{inb(0x80); inb(0x80); inb(0x80); inb(0x80);}while(0)
19 int ATA_Install(char **Arguments);
20 void ATA_SetupPartitions(void);
21 void ATA_SetupVFS(void);
22 int ATA_ScanDisk(int Disk);
23 void ATA_ParseGPT(int Disk);
24 void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length);
25 Uint16 ATA_GetBasePort(int Disk);
26 // Filesystem Interface
27 char *ATA_ReadDir(tVFS_Node *Node, int Pos);
28 tVFS_Node *ATA_FindDir(tVFS_Node *Node, const char *Name);
29 Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
30 Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
31 int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data);
32 // Read/Write Interface/Quantiser
33 Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
34 Uint ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, Uint Disk);
37 MODULE_DEFINE(0, VERSION, i386ATA, ATA_Install, NULL, "PCI", NULL);
38 tVFS_NodeType gATA_RootNodeType = {
39 .TypeName = "ATA Root Node",
40 .ReadDir = ATA_ReadDir,
41 .FindDir = ATA_FindDir
43 tVFS_NodeType gATA_DiskNodeType = {
44 .TypeName = "ATA Volume",
49 tDevFS_Driver gATA_DriverInfo = {
54 .Flags = VFS_FFLAG_DIRECTORY,
55 .ACLs = &gVFS_ACL_EveryoneRX,
56 .Type = &gATA_RootNodeType
59 tATA_Disk gATA_Disks[MAX_ATA_DISKS];
61 tVFS_Node **gATA_Nodes;
65 * \brief Initialise the ATA driver
67 int ATA_Install(char **Arguments)
74 ATA_SetupPartitions();
78 if( DevFS_AddDevice( &gATA_DriverInfo ) == 0 )
79 return MODULE_ERR_MISC;
85 * \brief Scan all disks, looking for partitions
87 void ATA_SetupPartitions(void)
90 for( i = 0; i < MAX_ATA_DISKS; i ++ )
92 if( !ATA_ScanDisk(i) ) {
93 gATA_Disks[i].Name[0] = '\0'; // Mark as unused
100 * \brief Sets up the ATA drivers VFS information and registers with DevFS
102 void ATA_SetupVFS(void)
106 // Count number of nodes needed
108 for( i = 0; i < MAX_ATA_DISKS; i++ )
110 if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore
112 giATA_NumNodes += gATA_Disks[i].NumPartitions;
115 // Allocate Node space
116 gATA_Nodes = malloc( giATA_NumNodes * sizeof(void*) );
120 for( i = 0; i < MAX_ATA_DISKS; i++ )
122 if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore
123 gATA_Nodes[ k++ ] = &gATA_Disks[i].Node;
124 for( j = 0; j < gATA_Disks[i].NumPartitions; j ++ )
125 gATA_Nodes[ k++ ] = &gATA_Disks[i].Partitions[j].Node;
128 gATA_DriverInfo.RootNode.Size = giATA_NumNodes;
132 * \brief Scan a disk, getting the size and any paritions
133 * \param Disk Disk ID to scan
135 int ATA_ScanDisk(int Disk)
140 ENTER("iDisk", Disk);
143 gATA_Disks[ Disk ].Sectors = ATA_GetDiskSize(Disk);
144 if(gATA_Disks[ Disk ].Sectors == 0)
150 LOG("gATA_Disks[ %i ].Sectors = 0x%x", Disk, gATA_Disks[ Disk ].Sectors);
153 gATA_Disks[ Disk ].Name[0] = 'A'+Disk;
154 gATA_Disks[ Disk ].Name[1] = '\0';
158 Uint64 val = gATA_Disks[ Disk ].Sectors / 2;
164 else if( val > 4*1024 ) {
168 else if( val > 4*1024 ) {
172 Log_Notice("ATA", "Disk %s: 0x%llx Sectors (%lli %s)",
173 gATA_Disks[ Disk ].Name, gATA_Disks[ Disk ].Sectors, val, units);
177 // Get pointer to vfs node and populate it
178 node = &gATA_Disks[ Disk ].Node;
179 node->Size = gATA_Disks[Disk].Sectors * SECTOR_SIZE;
180 node->NumACLs = 0; // Means Superuser only can access it
181 node->Inode = (Disk << 8) | 0xFF;
182 node->ImplPtr = gATA_Disks[ Disk ].Name;
184 node->ATime = node->MTime = node->CTime = now();
186 node->Type = &gATA_DiskNodeType;
188 // --- Scan Partitions ---
191 if( ATA_ReadDMA( Disk, 0, 1, &mbr ) != 0 ) {
192 Log_Warning("ATA", "Error in reading MBR on %i", Disk);
197 // Check for a GPT table
198 if(mbr.Parts[0].SystemID == 0xEE)
200 else // No? Just parse the MBR
201 ATA_ParseMBR(Disk, &mbr);
204 ATA_ReadDMA( Disk, 1, 1, &mbr );
205 Debug_HexDump("ATA_ScanDisk", &mbr, 512);
213 * \fn void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
214 * \brief Fills a parition's information structure
216 void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
218 ENTER("pPart iDisk iNum XStart XLength", Part, Disk, Num, Start, Length);
220 Part->Length = Length;
221 Part->Name[0] = 'A'+Disk;
223 Part->Name[1] = '1'+Num/10;
224 Part->Name[2] = '1'+Num%10;
225 Part->Name[3] = '\0';
227 Part->Name[1] = '1'+Num;
228 Part->Name[2] = '\0';
230 Part->Node.NumACLs = 0; // Only root can read/write raw block devices
231 Part->Node.Inode = (Disk << 8) | Num;
232 Part->Node.ImplPtr = Part->Name;
234 Part->Node.Type = &gATA_DiskNodeType;
235 Log_Notice("ATA", "Partition %s at 0x%llx+0x%llx", Part->Name, Part->Start, Part->Length);
236 LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
241 * \fn void ATA_ParseGPT(int Disk)
242 * \brief Parses the GUID Partition Table
244 void ATA_ParseGPT(int Disk)
246 ///\todo Support GPT Disks
247 Warning("GPT Disks are currently unsupported (Disk %i)", Disk);
251 * \fn char *ATA_ReadDir(tVFS_Node *Node, int Pos)
253 char *ATA_ReadDir(tVFS_Node *UNUSED(Node), int Pos)
255 if(Pos >= giATA_NumNodes || Pos < 0) return NULL;
256 return strdup( gATA_Nodes[Pos]->ImplPtr );
260 * \fn tVFS_Node *ATA_FindDir(tVFS_Node *Node, const char *Name)
262 tVFS_Node *ATA_FindDir(tVFS_Node *UNUSED(Node), const char *Name)
267 // Check first character
268 if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS)
270 disk = &gATA_Disks[Name[0]-'A'];
272 if(Name[1] == '\0') {
273 if( disk->Sectors == 0 && disk->Name[0] == '\0')
279 if(Name[1] < '0' || '9' < Name[1]) return NULL;
280 if(Name[2] == '\0') { // <= 9
281 part = Name[1] - '0';
283 return &disk->Partitions[part].Node;
286 if('0' > Name[2] || '9' < Name[2]) return NULL;
287 if(Name[3] != '\0') return NULL;
289 part = (Name[1] - '0') * 10;
290 part += Name[2] - '0';
292 return &disk->Partitions[part].Node;
297 * \fn Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
299 Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
301 int disk = Node->Inode >> 8;
302 int part = Node->Inode & 0xFF;
304 ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
309 if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE ) {
313 if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
314 Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
319 if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE ) {
323 if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
324 Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
325 Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
329 int ret = DrvUtil_ReadBlock(Offset, Length, Buffer, ATA_ReadRaw, SECTOR_SIZE, disk);
330 //Log("ATA_ReadFS: disk=%i, Offset=%lli, Length=%lli", disk, Offset, Length);
331 //Debug_HexDump("ATA_ReadFS", Buffer, Length);
338 * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
340 Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
342 int disk = Node->Inode >> 8;
343 int part = Node->Inode & 0xFF;
348 if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
350 if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
351 Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
356 if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
358 if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
359 Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
360 Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
363 Log("ATA_WriteFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer);
364 Debug_HexDump("ATA_WriteFS", Buffer, Length);
365 return DrvUtil_WriteBlock(Offset, Length, Buffer, ATA_ReadRaw, ATA_WriteRaw, SECTOR_SIZE, disk);
368 const char *csaATA_IOCtls[] = {DRV_IOCTLNAMES, DRV_DISK_IOCTLNAMES, NULL};
370 * \fn int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
371 * \brief IO Control Funtion
373 int ATA_IOCtl(tVFS_Node *UNUSED(Node), int Id, void *Data)
377 BASE_IOCTLS(DRV_TYPE_DISK, "i386ATA", VERSION, csaATA_IOCtls);
379 case DISK_IOCTL_GETBLOCKSIZE:
388 // --- Disk Access ---
390 * \fn Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
392 Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
398 // Pass straight on to ATA_ReadDMAPage if we can
399 if(Count <= MAX_DMA_SECTORS)
401 ret = ATA_ReadDMA(Disk, Address, Count, Buffer);
402 if(ret == 0) return 0;
406 // Else we will have to break up the transfer
408 while(Count > MAX_DMA_SECTORS)
410 ret = ATA_ReadDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
412 if(ret != 1) return done;
414 done += MAX_DMA_SECTORS;
415 Count -= MAX_DMA_SECTORS;
416 offset += MAX_DMA_SECTORS*SECTOR_SIZE;
419 ret = ATA_ReadDMA(Disk, Address+offset, Count, Buffer+offset);
420 if(ret != 1) return 0;
425 * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, Uint Disk)
427 Uint ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, Uint Disk)
433 // Pass straight on to ATA_WriteDMA, if we can
434 if(Count <= MAX_DMA_SECTORS)
436 ret = ATA_WriteDMA(Disk, Address, Count, Buffer);
437 if(ret == 0) return 0;
441 // Else we will have to break up the transfer
443 while(Count > MAX_DMA_SECTORS)
445 ret = ATA_WriteDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
447 if(ret != 1) return done;
449 done += MAX_DMA_SECTORS;
450 Count -= MAX_DMA_SECTORS;
451 offset += MAX_DMA_SECTORS*SECTOR_SIZE;
454 ret = ATA_WriteDMA(Disk, Address+offset, Count, Buffer+offset);
455 if(ret != 1) return 0;