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

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