Broke out the ATA IO functions (Read/WriteDMA into their own file to improve code...
[tpg/acess2.git] / Modules / Storage / ATA / io.c
1 /*
2  * Acess2 IDE Harddisk Driver
3  * - io.c
4  *
5  * Disk Input/Output control
6  */
7 #define DEBUG   1
8 #include <acess.h>
9 #include <modules.h>    // Needed for error codes
10 #include <drv_pci.h>
11 #include "common.h"
12
13 // === MACROS ===
14 #define IO_DELAY()      do{inb(0x80); inb(0x80); inb(0x80); inb(0x80);}while(0)
15
16 // === TYPES ===
17 /**
18  * \brief PRDT Entry
19  */
20 typedef struct
21 {
22         Uint32  PBufAddr;       // Physical Buffer Address
23         Uint16  Bytes;  // Size of transfer entry
24         Uint16  Flags;  // Flags
25 } __attribute__ ((packed))      tPRDT_Ent;
26
27 /**
28  * \brief Structure returned by the ATA IDENTIFY command
29  */
30 typedef struct
31 {
32         Uint16  Flags;          // 1
33         Uint16  Usused1[9];     // 10
34         char    SerialNum[20];  // 20
35         Uint16  Usused2[3];     // 23
36         char    FirmwareVer[8]; // 27
37         char    ModelNumber[40];        // 47
38         Uint16  SectPerInt;     // 48 - Low byte only
39         Uint16  Unused3;        // 49
40         Uint16  Capabilities[2];        // 51
41         Uint16  Unused4[2];     // 53
42         Uint16  ValidExtData;   // 54
43         Uint16  Unused5[5];      // 59
44         Uint16  SizeOfRWMultiple;       // 60
45         Uint32  Sectors28;      // 62
46         Uint16  Unused6[100-62];
47         Uint64  Sectors48;
48         Uint16  Unused7[256-104];
49 } __attribute__ ((packed))      tIdentify;
50
51 // === PROTOTYPES ===
52  int    ATA_SetupIO(void);
53 Uint64  ATA_GetDiskSize(int Disk);
54 Uint16  ATA_GetBasePort(int Disk);
55 // Read/Write DMA
56  int    ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer);
57  int    ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, const void *Buffer);
58 // IRQs
59 void    ATA_IRQHandlerPri(int UNUSED(IRQ));
60 void    ATA_IRQHandlerSec(int UNUSED(IRQ));
61 // Controller IO
62 Uint8   ATA_int_BusMasterReadByte(int Ofs);
63 void    ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value);
64 void    ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value);
65
66 // === GLOBALS ===
67 Uint32  gATA_BusMasterBase = 0;
68 Uint8   *gATA_BusMasterBasePtr = 0;
69  int    gATA_IRQPri = 14;
70  int    gATA_IRQSec = 15;
71  int    giaATA_ControllerLock[2] = {0}; //!< Spinlocks for each controller
72 Uint8   gATA_Buffers[2][(MAX_DMA_SECTORS+0xFFF)&~0xFFF] __attribute__ ((section(".padata")));
73 volatile int    gaATA_IRQs[2] = {0};
74 tPRDT_Ent       gATA_PRDTs[2] = {
75         {0, 512, IDE_PRDT_LAST},
76         {0, 512, IDE_PRDT_LAST}
77 };
78
79 // === CODE ===
80 /**
81  * \brief Sets up the ATA controller's DMA mode
82  */
83 int ATA_SetupIO(void)
84 {
85          int    ent;
86         tPAddr  addr;
87
88         ENTER("");
89
90         // Get IDE Controller's PCI Entry
91         ent = PCI_GetDeviceByClass(0x0101, 0xFFFF, -1);
92         LOG("ent = %i", ent);
93         gATA_BusMasterBase = PCI_GetBAR4( ent );
94         if( gATA_BusMasterBase == 0 ) {
95                 Log_Warning("ATA", "It seems that there is no Bus Master Controller on this machine. Get one");
96                 // TODO: Use PIO mode instead
97                 LEAVE('i', MODULE_ERR_NOTNEEDED);
98                 return MODULE_ERR_NOTNEEDED;
99         }
100         
101         // Map memory
102         if( !(gATA_BusMasterBase & 1) )
103         {
104                 if( gATA_BusMasterBase < 0x100000 )
105                         gATA_BusMasterBasePtr = (void*)(KERNEL_BASE | (tVAddr)gATA_BusMasterBase);
106                 else
107                         gATA_BusMasterBasePtr = (void*)( MM_MapHWPages( gATA_BusMasterBase, 1 ) + (gATA_BusMasterBase&0xFFF) );
108                 LOG("gATA_BusMasterBasePtr = %p", gATA_BusMasterBasePtr);
109         }
110         else {
111                 // Bit 0 is left set as a flag to other functions
112                 LOG("gATA_BusMasterBase = 0x%x", gATA_BusMasterBase & ~1);
113         }
114
115         // Register IRQs and get Buffers
116         IRQ_AddHandler( gATA_IRQPri, ATA_IRQHandlerPri );
117         IRQ_AddHandler( gATA_IRQSec, ATA_IRQHandlerSec );
118
119         gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( (tVAddr)&gATA_Buffers[0] );
120         gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( (tVAddr)&gATA_Buffers[1] );
121
122         LOG("gATA_PRDTs = {PBufAddr: 0x%x, PBufAddr: 0x%x}", gATA_PRDTs[0].PBufAddr, gATA_PRDTs[1].PBufAddr);
123
124         addr = MM_GetPhysAddr( (tVAddr)&gATA_PRDTs[0] );
125         LOG("addr = 0x%x", addr);
126         ATA_int_BusMasterWriteDWord(4, addr);
127         addr = MM_GetPhysAddr( (tVAddr)&gATA_PRDTs[1] );
128         LOG("addr = 0x%x", addr);
129         ATA_int_BusMasterWriteDWord(12, addr);
130
131         // Enable controllers
132         outb(IDE_PRI_BASE+1, 1);
133         outb(IDE_SEC_BASE+1, 1);
134
135         // return
136         LEAVE('i', MODULE_ERR_OK);
137         return MODULE_ERR_OK;
138 }
139
140 Uint64 ATA_GetDiskSize(int Disk)
141 {
142         union {
143                 Uint16  buf[256];
144                 tIdentify       identify;
145         }       data;
146         Uint16  base;
147         Uint8   val;
148          int    i;
149         ENTER("iDisk", Disk);
150
151         base = ATA_GetBasePort( Disk );
152
153         // Send Disk Selector
154         if(Disk == 1 || Disk == 3)
155                 outb(base+6, 0xB0);
156         else
157                 outb(base+6, 0xA0);
158         IO_DELAY();
159         
160         // Check for a floating bus
161         if( 0xFF == inb(base+7) ) {
162                 LOG("Floating bus");
163                 LEAVE('i', 0);
164                 return 0;
165         }
166         
167         // Check for the controller
168         outb(base+0x02, 0x66);
169         outb(base+0x03, 0xFF);
170         if(inb(base+0x02) != 0x66 || inb(base+0x03) != 0xFF) {
171                 LOG("No controller");
172                 LEAVE('i', 0);
173                 return 0;
174         }
175
176         // Send IDENTIFY
177         outb(base+7, 0xEC);
178         IO_DELAY();
179         val = inb(base+7);      // Read status
180         LOG("val = 0x%02x", val);
181         if(val == 0) {
182                 LEAVE('i', 0);
183                 return 0;       // Disk does not exist
184         }
185
186         // Poll until BSY clears and DRQ sets or ERR is set
187         while( ((val & 0x80) || !(val & 0x08)) && !(val & 1))
188                 val = inb(base+7);
189
190         // Check for an error
191         if(val & 1) {
192                 LEAVE('i', 0);
193                 return 0;       // Error occured, so return false
194         }
195
196         // Read Data
197         for( i = 0; i < 256; i++ )
198                 data.buf[i] = inw(base);
199
200         // Return the disk size
201         if(data.identify.Sectors48 != 0)
202                 return data.identify.Sectors48;
203         else
204                 return data.identify.Sectors28;
205 }
206
207 /**
208  * \fn Uint16 ATA_GetPortBase(int Disk)
209  * \brief Returns the base port for a given disk
210  */
211 Uint16 ATA_GetBasePort(int Disk)
212 {
213         switch(Disk)
214         {
215         case 0: case 1:         return IDE_PRI_BASE;
216         case 2: case 3:         return IDE_SEC_BASE;
217         }
218         return 0;
219 }
220
221 /**
222  * \fn int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
223  */
224 int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
225 {
226          int    cont = (Disk>>1)&1;     // Controller ID
227          int    disk = Disk & 1;
228         Uint16  base;
229         Uint8   val;
230
231         ENTER("iDisk XAddress iCount pBuffer", Disk, Address, Count, Buffer);
232
233         // Check if the count is small enough
234         if(Count > MAX_DMA_SECTORS) {
235                 Warning("Passed too many sectors for a bulk DMA read (%i > %i)",
236                         Count, MAX_DMA_SECTORS);
237                 LEAVE('i');
238                 return 0;
239         }
240
241         // Get exclusive access to the disk controller
242         LOCK( &giaATA_ControllerLock[ cont ] );
243
244         // Set Size
245         gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
246
247         // Get Port Base
248         base = ATA_GetBasePort(Disk);
249
250         // Reset IRQ Flag
251         gaATA_IRQs[cont] = 0;
252
253         // Set up transfer
254         if( Address > 0x0FFFFFFF )      // Use LBA48
255         {
256                 outb(base+0x6, 0x40 | (disk << 4));
257                 outb(base+0x2, 0 >> 8); // Upper Sector Count
258                 outb(base+0x3, Address >> 24);  // Low 2 Addr
259                 outb(base+0x4, Address >> 28);  // Mid 2 Addr
260                 outb(base+0x5, Address >> 32);  // High 2 Addr
261         }
262         else
263         {
264                 outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); // Magic, Disk, High addr
265         }
266
267         outb(base+0x01, 0x01);  //?
268         outb(base+0x02, (Uint8) Count);         // Sector Count
269         outb(base+0x03, (Uint8) Address);               // Low Addr
270         outb(base+0x04, (Uint8) (Address >> 8));        // Middle Addr
271         outb(base+0x05, (Uint8) (Address >> 16));       // High Addr
272
273         LOG("Starting Transfer");
274         LOG("gATA_PRDTs[%i].Bytes = %i", cont, gATA_PRDTs[cont].Bytes);
275         if( Address > 0x0FFFFFFF )
276                 outb(base+0x07, HDD_DMA_R48);   // Read Command (LBA48)
277         else
278                 outb(base+0x07, HDD_DMA_R28);   // Read Command (LBA28)
279
280         // Start transfer
281         ATA_int_BusMasterWriteByte( cont << 3, 9 );     // Read and start
282
283         // Wait for transfer to complete
284         while( gaATA_IRQs[cont] == 0 )  Threads_Yield();
285
286         // Complete Transfer
287         ATA_int_BusMasterWriteByte( cont << 3, 8 );     // Read and stop
288
289         val = inb(base+0x7);
290         LOG("Status byte = 0x%02x", val);
291
292         LOG("gATA_PRDTs[%i].Bytes = %i", cont, gATA_PRDTs[cont].Bytes);
293         LOG("Transfer Completed & Acknowledged");
294
295         // Copy to destination buffer
296         memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE );
297
298         // Release controller lock
299         RELEASE( &giaATA_ControllerLock[ cont ] );
300
301         LEAVE('i', 1);
302         return 1;
303 }
304
305 /**
306  * \fn int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
307  * \brief Write up to \a MAX_DMA_SECTORS to a disk
308  * \param Disk  Disk ID to write to
309  * \param Address       LBA of first sector
310  * \param Count Number of sectors to write (must be >= \a MAX_DMA_SECTORS)
311  * \param Buffer        Source buffer for data
312  */
313 int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, const void *Buffer)
314 {
315          int    cont = (Disk>>1)&1;     // Controller ID
316          int    disk = Disk & 1;
317         Uint16  base;
318
319         // Check if the count is small enough
320         if(Count > MAX_DMA_SECTORS)     return 0;
321
322         // Get exclusive access to the disk controller
323         LOCK( &giaATA_ControllerLock[ cont ] );
324
325         // Set Size
326         gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
327
328         // Get Port Base
329         base = ATA_GetBasePort(Disk);
330
331         // Set up transfer
332         outb(base+0x01, 0x00);
333         if( Address > 0x0FFFFFFF )      // Use LBA48
334         {
335                 outb(base+0x6, 0x40 | (disk << 4));
336                 outb(base+0x2, 0 >> 8); // Upper Sector Count
337                 outb(base+0x3, Address >> 24);  // Low 2 Addr
338                 outb(base+0x3, Address >> 28);  // Mid 2 Addr
339                 outb(base+0x3, Address >> 32);  // High 2 Addr
340         }
341         else
342         {
343                 outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); //Disk,Magic,High addr
344         }
345
346         outb(base+0x02, (Uint8) Count);         // Sector Count
347         outb(base+0x03, (Uint8) Address);               // Low Addr
348         outb(base+0x04, (Uint8) (Address >> 8));        // Middle Addr
349         outb(base+0x05, (Uint8) (Address >> 16));       // High Addr
350         if( Address > 0x0FFFFFFF )
351                 outb(base+0x07, HDD_DMA_W48);   // Write Command (LBA48)
352         else
353                 outb(base+0x07, HDD_DMA_W28);   // Write Command (LBA28)
354
355         // Reset IRQ Flag
356         gaATA_IRQs[cont] = 0;
357
358         // Copy to output buffer
359         memcpy( gATA_Buffers[cont], Buffer, Count*SECTOR_SIZE );
360
361         // Start transfer
362         ATA_int_BusMasterWriteByte( cont << 3, 1 );     // Write and start
363
364         // Wait for transfer to complete
365         while( gaATA_IRQs[cont] == 0 )  Threads_Yield();
366
367         // Complete Transfer
368         ATA_int_BusMasterWriteByte( cont << 3, 0 );     // Write and stop
369
370         // Release controller lock
371         RELEASE( &giaATA_ControllerLock[ cont ] );
372
373         return 1;
374 }
375
376 /**
377  * \brief Primary ATA Channel IRQ handler
378  */
379 void ATA_IRQHandlerPri(int UNUSED(IRQ))
380 {
381         Uint8   val;
382
383         // IRQ bit set for Primary Controller
384         val = ATA_int_BusMasterReadByte( 0x2 );
385         LOG("IRQ val = 0x%x", val);
386         if(val & 4) {
387                 LOG("IRQ hit (val = 0x%x)", val);
388                 ATA_int_BusMasterWriteByte( 0x2, 4 );
389                 gaATA_IRQs[0] = 1;
390                 return ;
391         }
392 }
393
394 /**
395  * \brief Second ATA Channel IRQ handler
396  */
397 void ATA_IRQHandlerSec(int UNUSED(IRQ))
398 {
399         Uint8   val;
400         // IRQ bit set for Secondary Controller
401         val = ATA_int_BusMasterReadByte( 0xA );
402         LOG("IRQ val = 0x%x", val);
403         if(val & 4) {
404                 LOG("IRQ hit (val = 0x%x)", val);
405                 ATA_int_BusMasterWriteByte( 0xA, 4 );
406                 gaATA_IRQs[1] = 1;
407                 return ;
408         }
409 }
410
411 /**
412  * \brief Read an 8-bit value from a Bus Master register
413  * \param Ofs   Register offset
414  */
415 Uint8 ATA_int_BusMasterReadByte(int Ofs)
416 {
417         if( gATA_BusMasterBase & 1 )
418                 return inb( (gATA_BusMasterBase & ~1) + Ofs );
419         else
420                 return *(Uint8*)(gATA_BusMasterBasePtr + Ofs);
421 }
422
423 /**
424  * \brief Writes a byte to a Bus Master Register
425  * \param Ofs   Register Offset
426  * \param Value Value to write
427  */
428 void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value)
429 {
430         if( gATA_BusMasterBase & 1 )
431                 outb( (gATA_BusMasterBase & ~1) + Ofs, Value );
432         else
433                 *(Uint8*)(gATA_BusMasterBasePtr + Ofs) = Value;
434 }
435
436 /**
437  * \brief Writes a 32-bit value to a Bus Master Register
438  * \param Ofs   Register offset
439  * \param Value Value to write
440  */
441 void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value)
442 {
443         if( gATA_BusMasterBase & 1 )
444                 outd( (gATA_BusMasterBase & ~1) + Ofs, Value );
445         else
446                 *(Uint32*)(gATA_BusMasterBasePtr + Ofs) = Value;
447 }

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