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

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