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

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