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, 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 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 if( ATA_ReadDMA( Disk, 0, 1, &mbr ) != 0 ) {
183 Log_Warning("ATA", "Error in reading MBR on %i", Disk);
188 // Check for a GPT table
189 if(mbr.Parts[0].SystemID == 0xEE)
191 else // No? Just parse the MBR
192 ATA_ParseMBR(Disk, &mbr);
195 ATA_ReadDMA( Disk, 1, 1, &mbr );
196 Debug_HexDump("ATA_ScanDisk", &mbr, 512);
204 * \fn void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
205 * \brief Fills a parition's information structure
207 void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
209 ENTER("pPart iDisk iNum XStart XLength", Part, Disk, Num, Start, Length);
211 Part->Length = Length;
212 Part->Name[0] = 'A'+Disk;
214 Part->Name[1] = '1'+Num/10;
215 Part->Name[2] = '1'+Num%10;
216 Part->Name[3] = '\0';
218 Part->Name[1] = '1'+Num;
219 Part->Name[2] = '\0';
221 Part->Node.NumACLs = 0; // Only root can read/write raw block devices
222 Part->Node.Inode = (Disk << 8) | Num;
223 Part->Node.ImplPtr = Part->Name;
225 Part->Node.Read = ATA_ReadFS;
226 Part->Node.Write = ATA_WriteFS;
227 Part->Node.IOCtl = ATA_IOCtl;
228 Log_Notice("ATA", "Note '%s' at 0x%llx, 0x%llx long", Part->Name, Part->Start, Part->Length);
229 LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
234 * \fn void ATA_ParseGPT(int Disk)
235 * \brief Parses the GUID Partition Table
237 void ATA_ParseGPT(int Disk)
239 ///\todo Support GPT Disks
240 Warning("GPT Disks are currently unsupported (Disk %i)", Disk);
244 * \fn char *ATA_ReadDir(tVFS_Node *Node, int Pos)
246 char *ATA_ReadDir(tVFS_Node *UNUSED(Node), int Pos)
248 if(Pos >= giATA_NumNodes || Pos < 0) return NULL;
249 return strdup( gATA_Nodes[Pos]->ImplPtr );
253 * \fn tVFS_Node *ATA_FindDir(tVFS_Node *Node, const char *Name)
255 tVFS_Node *ATA_FindDir(tVFS_Node *UNUSED(Node), const char *Name)
260 // Check first character
261 if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS)
263 disk = &gATA_Disks[Name[0]-'A'];
265 if(Name[1] == '\0') {
266 if( disk->Sectors == 0 && disk->Name[0] == '\0')
272 if(Name[1] < '0' || '9' < Name[1]) return NULL;
273 if(Name[2] == '\0') { // <= 9
274 part = Name[1] - '0';
276 return &disk->Partitions[part].Node;
279 if('0' > Name[2] || '9' < Name[2]) return NULL;
280 if(Name[3] != '\0') return NULL;
282 part = (Name[1] - '0') * 10;
283 part += Name[2] - '0';
285 return &disk->Partitions[part].Node;
290 * \fn Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
292 Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
294 int disk = Node->Inode >> 8;
295 int part = Node->Inode & 0xFF;
297 ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
302 if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE ) {
306 if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
307 Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
312 if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE ) {
316 if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
317 Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
318 Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
322 int ret = DrvUtil_ReadBlock(Offset, Length, Buffer, ATA_ReadRaw, SECTOR_SIZE, disk);
323 //Log("ATA_ReadFS: disk=%i, Offset=%lli, Length=%lli", disk, Offset, Length);
324 //Debug_HexDump("ATA_ReadFS", Buffer, Length);
331 * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
333 Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
335 int disk = Node->Inode >> 8;
336 int part = Node->Inode & 0xFF;
341 if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
343 if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
344 Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
349 if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
351 if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
352 Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
353 Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
356 Log("ATA_WriteFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer);
357 Debug_HexDump("ATA_WriteFS", Buffer, Length);
358 return DrvUtil_WriteBlock(Offset, Length, Buffer, ATA_ReadRaw, ATA_WriteRaw, SECTOR_SIZE, disk);
361 const char *csaATA_IOCtls[] = {DRV_IOCTLNAMES, DRV_DISK_IOCTLNAMES, NULL};
363 * \fn int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
364 * \brief IO Control Funtion
366 int ATA_IOCtl(tVFS_Node *UNUSED(Node), int Id, void *Data)
370 BASE_IOCTLS(DRV_TYPE_DISK, "i386ATA", VERSION, csaATA_IOCtls);
372 case DISK_IOCTL_GETBLOCKSIZE:
381 // --- Disk Access ---
383 * \fn Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
385 Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
391 // Pass straight on to ATA_ReadDMAPage if we can
392 if(Count <= MAX_DMA_SECTORS)
394 ret = ATA_ReadDMA(Disk, Address, Count, Buffer);
395 if(ret == 0) return 0;
399 // Else we will have to break up the transfer
401 while(Count > MAX_DMA_SECTORS)
403 ret = ATA_ReadDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
405 if(ret != 1) return done;
407 done += MAX_DMA_SECTORS;
408 Count -= MAX_DMA_SECTORS;
409 offset += MAX_DMA_SECTORS*SECTOR_SIZE;
412 ret = ATA_ReadDMA(Disk, Address+offset, Count, Buffer+offset);
413 if(ret != 1) return 0;
418 * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
420 Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
426 // Pass straight on to ATA_WriteDMA, if we can
427 if(Count <= MAX_DMA_SECTORS)
429 ret = ATA_WriteDMA(Disk, Address, Count, Buffer);
430 if(ret == 0) return 0;
434 // Else we will have to break up the transfer
436 while(Count > MAX_DMA_SECTORS)
438 ret = ATA_WriteDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset);
440 if(ret != 1) return done;
442 done += MAX_DMA_SECTORS;
443 Count -= MAX_DMA_SECTORS;
444 offset += MAX_DMA_SECTORS*SECTOR_SIZE;
447 ret = ATA_WriteDMA(Disk, Address+offset, Count, Buffer+offset);
448 if(ret != 1) return 0;