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, void *Buffer);
31 int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data);
32 // Read/Write Interface/Quantiser
33 Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
34 Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk);
37 MODULE_DEFINE(0, VERSION, i386ATA, ATA_Install, NULL, "PCI", NULL);
38 tDevFS_Driver gATA_DriverInfo = {
43 .Flags = VFS_FFLAG_DIRECTORY,
44 .ACLs = &gVFS_ACL_EveryoneRX,
45 .ReadDir = ATA_ReadDir,
46 .FindDir = ATA_FindDir
49 tATA_Disk gATA_Disks[MAX_ATA_DISKS];
51 tVFS_Node **gATA_Nodes;
55 * \brief Initialise the ATA driver
57 int ATA_Install(char **Arguments)
64 ATA_SetupPartitions();
68 if( DevFS_AddDevice( &gATA_DriverInfo ) == 0 )
69 return MODULE_ERR_MISC;
75 * \brief Scan all disks, looking for partitions
77 void ATA_SetupPartitions(void)
80 for( i = 0; i < MAX_ATA_DISKS; i ++ )
82 if( !ATA_ScanDisk(i) ) {
83 gATA_Disks[i].Name[0] = '\0'; // Mark as unused
90 * \brief Sets up the ATA drivers VFS information and registers with DevFS
92 void ATA_SetupVFS(void)
96 // Count number of nodes needed
98 for( i = 0; i < MAX_ATA_DISKS; i++ )
100 if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore
102 giATA_NumNodes += gATA_Disks[i].NumPartitions;
105 // Allocate Node space
106 gATA_Nodes = malloc( giATA_NumNodes * sizeof(void*) );
110 for( i = 0; i < MAX_ATA_DISKS; i++ )
112 if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore
113 gATA_Nodes[ k++ ] = &gATA_Disks[i].Node;
114 for( j = 0; j < gATA_Disks[i].NumPartitions; j ++ )
115 gATA_Nodes[ k++ ] = &gATA_Disks[i].Partitions[j].Node;
118 gATA_DriverInfo.RootNode.Size = giATA_NumNodes;
122 * \brief Scan a disk, getting the size and any paritions
123 * \param Disk Disk ID to scan
125 int ATA_ScanDisk(int Disk)
130 ENTER("iDisk", Disk);
133 gATA_Disks[ Disk ].Sectors = ATA_GetDiskSize(Disk);
134 if(gATA_Disks[ Disk ].Sectors == 0)
140 LOG("gATA_Disks[ %i ].Sectors = 0x%x", Disk, gATA_Disks[ Disk ].Sectors);
143 gATA_Disks[ Disk ].Name[0] = 'A'+Disk;
144 gATA_Disks[ Disk ].Name[1] = '\0';
148 Uint64 val = gATA_Disks[ Disk ].Sectors / 2;
154 else if( val > 4*1024 ) {
158 else if( val > 4*1024 ) {
162 Log_Notice("ATA", "Disk %s: 0x%llx Sectors (%lli %s)",
163 gATA_Disks[ Disk ].Name, gATA_Disks[ Disk ].Sectors, val, units);
167 // Get pointer to vfs node and populate it
168 node = &gATA_Disks[ Disk ].Node;
169 node->Size = gATA_Disks[Disk].Sectors * SECTOR_SIZE;
170 node->NumACLs = 0; // Means Superuser only can access it
171 node->Inode = (Disk << 8) | 0xFF;
172 node->ImplPtr = gATA_Disks[ Disk ].Name;
174 node->ATime = node->MTime
175 = node->CTime = now();
177 node->Read = ATA_ReadFS;
178 node->Write = ATA_WriteFS;
179 node->IOCtl = ATA_IOCtl;
181 // --- Scan Partitions ---
184 if( ATA_ReadDMA( Disk, 0, 1, &mbr ) != 0 ) {
185 Log_Warning("ATA", "Error in reading MBR on %i", Disk);
190 // Check for a GPT table
191 if(mbr.Parts[0].SystemID == 0xEE)
193 else // No? Just parse the MBR
194 ATA_ParseMBR(Disk, &mbr);
197 ATA_ReadDMA( Disk, 1, 1, &mbr );
198 Debug_HexDump("ATA_ScanDisk", &mbr, 512);
206 * \fn void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
207 * \brief Fills a parition's information structure
209 void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
211 ENTER("pPart iDisk iNum XStart XLength", Part, Disk, Num, Start, Length);
213 Part->Length = Length;
214 Part->Name[0] = 'A'+Disk;
216 Part->Name[1] = '1'+Num/10;
217 Part->Name[2] = '1'+Num%10;
218 Part->Name[3] = '\0';
220 Part->Name[1] = '1'+Num;
221 Part->Name[2] = '\0';
223 Part->Node.NumACLs = 0; // Only root can read/write raw block devices
224 Part->Node.Inode = (Disk << 8) | Num;
225 Part->Node.ImplPtr = Part->Name;
227 Part->Node.Read = ATA_ReadFS;
228 Part->Node.Write = ATA_WriteFS;
229 Part->Node.IOCtl = ATA_IOCtl;
230 Log_Notice("ATA", "Partition %s at 0x%llx+0x%llx", Part->Name, Part->Start, Part->Length);
231 LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
236 * \fn void ATA_ParseGPT(int Disk)
237 * \brief Parses the GUID Partition Table
239 void ATA_ParseGPT(int Disk)
241 ///\todo Support GPT Disks
242 Warning("GPT Disks are currently unsupported (Disk %i)", Disk);
246 * \fn char *ATA_ReadDir(tVFS_Node *Node, int Pos)
248 char *ATA_ReadDir(tVFS_Node *UNUSED(Node), int Pos)
250 if(Pos >= giATA_NumNodes || Pos < 0) return NULL;
251 return strdup( gATA_Nodes[Pos]->ImplPtr );
255 * \fn tVFS_Node *ATA_FindDir(tVFS_Node *Node, const char *Name)
257 tVFS_Node *ATA_FindDir(tVFS_Node *UNUSED(Node), const char *Name)
262 // Check first character
263 if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS)
265 disk = &gATA_Disks[Name[0]-'A'];
267 if(Name[1] == '\0') {
268 if( disk->Sectors == 0 && disk->Name[0] == '\0')
274 if(Name[1] < '0' || '9' < Name[1]) return NULL;
275 if(Name[2] == '\0') { // <= 9
276 part = Name[1] - '0';
278 return &disk->Partitions[part].Node;
281 if('0' > Name[2] || '9' < Name[2]) return NULL;
282 if(Name[3] != '\0') return NULL;
284 part = (Name[1] - '0') * 10;
285 part += Name[2] - '0';
287 return &disk->Partitions[part].Node;
292 * \fn Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
294 Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
296 int disk = Node->Inode >> 8;
297 int part = Node->Inode & 0xFF;
299 ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
304 if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE ) {
308 if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
309 Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
314 if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE ) {
318 if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
319 Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
320 Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
324 int ret = DrvUtil_ReadBlock(Offset, Length, Buffer, ATA_ReadRaw, SECTOR_SIZE, disk);
325 //Log("ATA_ReadFS: disk=%i, Offset=%lli, Length=%lli", disk, Offset, Length);
326 //Debug_HexDump("ATA_ReadFS", Buffer, Length);
333 * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
335 Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
337 int disk = Node->Inode >> 8;
338 int part = Node->Inode & 0xFF;
343 if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
345 if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
346 Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
351 if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
353 if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
354 Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
355 Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
358 Log("ATA_WriteFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer);
359 Debug_HexDump("ATA_WriteFS", Buffer, Length);
360 return DrvUtil_WriteBlock(Offset, Length, Buffer, ATA_ReadRaw, ATA_WriteRaw, SECTOR_SIZE, disk);
363 const char *csaATA_IOCtls[] = {DRV_IOCTLNAMES, DRV_DISK_IOCTLNAMES, NULL};
365 * \fn int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
366 * \brief IO Control Funtion
368 int ATA_IOCtl(tVFS_Node *UNUSED(Node), int Id, void *Data)
372 BASE_IOCTLS(DRV_TYPE_DISK, "i386ATA", VERSION, csaATA_IOCtls);
374 case DISK_IOCTL_GETBLOCKSIZE:
383 // --- Disk Access ---
385 * \fn Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
387 Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
393 // Pass straight on to ATA_ReadDMAPage if we can
394 if(Count <= MAX_DMA_SECTORS)
396 ret = ATA_ReadDMA(Disk, Address, Count, Buffer);
397 if(ret == 0) return 0;
401 // Else we will have to break up the transfer
403 while(Count > MAX_DMA_SECTORS)
405 ret = ATA_ReadDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
407 if(ret != 1) return done;
409 done += MAX_DMA_SECTORS;
410 Count -= MAX_DMA_SECTORS;
411 offset += MAX_DMA_SECTORS*SECTOR_SIZE;
414 ret = ATA_ReadDMA(Disk, Address+offset, Count, Buffer+offset);
415 if(ret != 1) return 0;
420 * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
422 Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
428 // Pass straight on to ATA_WriteDMA, if we can
429 if(Count <= MAX_DMA_SECTORS)
431 ret = ATA_WriteDMA(Disk, Address, Count, Buffer);
432 if(ret == 0) return 0;
436 // Else we will have to break up the transfer
438 while(Count > MAX_DMA_SECTORS)
440 ret = ATA_WriteDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
442 if(ret != 1) return done;
444 done += MAX_DMA_SECTORS;
445 Count -= MAX_DMA_SECTORS;
446 offset += MAX_DMA_SECTORS*SECTOR_SIZE;
449 ret = ATA_WriteDMA(Disk, Address+offset, Count, Buffer+offset);
450 if(ret != 1) return 0;