2 * Acess2 IDE Harddisk Driver
11 #include <tpl_drv_common.h>
12 #include <tpl_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, 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 Uint64 val = gATA_Disks[ Disk ].Sectors / 2;
149 else if( val > 4*1024 ) {
153 else if( val > 4*1024 ) {
157 Log_Log("ATA", "Disk %i: 0x%llx Sectors (%lli %s)", Disk,
158 gATA_Disks[ Disk ].Sectors, val, units);
162 gATA_Disks[ Disk ].Name[0] = 'A'+Disk;
163 gATA_Disks[ Disk ].Name[1] = '\0';
165 // Get pointer to vfs node and populate it
166 node = &gATA_Disks[ Disk ].Node;
167 node->Size = gATA_Disks[Disk].Sectors * SECTOR_SIZE;
168 node->NumACLs = 0; // Means Superuser only can access it
169 node->Inode = (Disk << 8) | 0xFF;
170 node->ImplPtr = gATA_Disks[ Disk ].Name;
172 node->ATime = node->MTime
173 = node->CTime = now();
175 node->Read = ATA_ReadFS;
176 node->Write = ATA_WriteFS;
177 node->IOCtl = ATA_IOCtl;
179 // --- Scan Partitions ---
182 ATA_ReadDMA( Disk, 0, 1, &mbr );
184 // Check for a GPT table
185 if(mbr.Parts[0].SystemID == 0xEE)
187 else // No? Just parse the MBR
188 ATA_ParseMBR(Disk, &mbr);
191 ATA_ReadDMA( Disk, 1, 1, &mbr );
192 Debug_HexDump("ATA_ScanDisk", &mbr, 512);
200 * \fn void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
201 * \brief Fills a parition's information structure
203 void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
205 ENTER("pPart iDisk iNum XStart XLength", Part, Disk, Num, Start, Length);
207 Part->Length = Length;
208 Part->Name[0] = 'A'+Disk;
210 Part->Name[1] = '1'+Num/10;
211 Part->Name[2] = '1'+Num%10;
212 Part->Name[3] = '\0';
214 Part->Name[1] = '1'+Num;
215 Part->Name[2] = '\0';
217 Part->Node.NumACLs = 0; // Only root can read/write raw block devices
218 Part->Node.Inode = (Disk << 8) | Num;
219 Part->Node.ImplPtr = Part->Name;
221 Part->Node.Read = ATA_ReadFS;
222 Part->Node.Write = ATA_WriteFS;
223 Part->Node.IOCtl = ATA_IOCtl;
224 Log_Notice("ATA", "Note '%s' at 0x%llx, 0x%llx long", Part->Name, Part->Start, Part->Length);
225 LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
230 * \fn void ATA_ParseGPT(int Disk)
231 * \brief Parses the GUID Partition Table
233 void ATA_ParseGPT(int Disk)
235 ///\todo Support GPT Disks
236 Warning("GPT Disks are currently unsupported (Disk %i)", Disk);
240 * \fn char *ATA_ReadDir(tVFS_Node *Node, int Pos)
242 char *ATA_ReadDir(tVFS_Node *UNUSED(Node), int Pos)
244 if(Pos >= giATA_NumNodes || Pos < 0) return NULL;
245 return strdup( gATA_Nodes[Pos]->ImplPtr );
249 * \fn tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name)
251 tVFS_Node *ATA_FindDir(tVFS_Node *UNUSED(Node), char *Name)
256 // Check first character
257 if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS)
259 disk = &gATA_Disks[Name[0]-'A'];
261 if(Name[1] == '\0') {
262 if( disk->Sectors == 0 && disk->Name[0] == '\0')
268 if(Name[1] < '0' || '9' < Name[1]) return NULL;
269 if(Name[2] == '\0') { // <= 9
270 part = Name[1] - '0';
272 return &disk->Partitions[part].Node;
275 if('0' > Name[2] || '9' < Name[2]) return NULL;
276 if(Name[3] != '\0') return NULL;
278 part = (Name[1] - '0') * 10;
279 part += Name[2] - '0';
281 return &disk->Partitions[part].Node;
286 * \fn Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
288 Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
290 int disk = Node->Inode >> 8;
291 int part = Node->Inode & 0xFF;
293 ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
298 if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE ) {
302 if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
303 Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
308 if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE ) {
312 if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
313 Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
314 Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
318 int ret = DrvUtil_ReadBlock(Offset, Length, Buffer, ATA_ReadRaw, SECTOR_SIZE, disk);
319 Log("ATA_ReadFS: disk=%i, Offset=%lli, Length=%lli", disk, Offset, Length);
320 Debug_HexDump("ATA_ReadFS", Buffer, Length);
327 * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
329 Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
331 int disk = Node->Inode >> 8;
332 int part = Node->Inode & 0xFF;
337 if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
339 if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
340 Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
345 if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
347 if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
348 Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
349 Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
352 Log("ATA_WriteFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer);
353 Debug_HexDump("ATA_WriteFS", Buffer, Length);
354 return DrvUtil_WriteBlock(Offset, Length, Buffer, ATA_ReadRaw, ATA_WriteRaw, SECTOR_SIZE, disk);
357 const char *csaATA_IOCtls[] = {DRV_IOCTLNAMES, DRV_DISK_IOCTLNAMES, NULL};
359 * \fn int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
360 * \brief IO Control Funtion
362 int ATA_IOCtl(tVFS_Node *UNUSED(Node), int Id, void *Data)
366 BASE_IOCTLS(DRV_TYPE_DISK, "i386ATA", VERSION, csaATA_IOCtls);
368 case DISK_IOCTL_GETBLOCKSIZE:
377 // --- Disk Access ---
379 * \fn Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
381 Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
387 // Pass straight on to ATA_ReadDMAPage if we can
388 if(Count <= MAX_DMA_SECTORS)
390 ret = ATA_ReadDMA(Disk, Address, Count, Buffer);
391 if(ret == 0) return 0;
395 // Else we will have to break up the transfer
397 while(Count > MAX_DMA_SECTORS)
399 ret = ATA_ReadDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
401 if(ret != 1) return done;
403 done += MAX_DMA_SECTORS;
404 Count -= MAX_DMA_SECTORS;
405 offset += MAX_DMA_SECTORS*SECTOR_SIZE;
408 ret = ATA_ReadDMA(Disk, Address+offset, Count, Buffer+offset);
409 if(ret != 1) return 0;
414 * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
416 Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
422 // Pass straight on to ATA_WriteDMA, if we can
423 if(Count <= MAX_DMA_SECTORS)
425 ret = ATA_WriteDMA(Disk, Address, Count, Buffer);
426 if(ret == 0) return 0;
430 // Else we will have to break up the transfer
432 while(Count > MAX_DMA_SECTORS)
434 ret = ATA_WriteDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
436 if(ret != 1) return done;
438 done += MAX_DMA_SECTORS;
439 Count -= MAX_DMA_SECTORS;
440 offset += MAX_DMA_SECTORS*SECTOR_SIZE;
443 ret = ATA_WriteDMA(Disk, Address+offset, Count, Buffer+offset);
444 if(ret != 1) return 0;