Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / arch / common / ata.device / dma_generic.c
blob535a7ebdad2c71c272467fb5898cd11f65e13957
1 /*
2 Copyright © 2004-2009, The AROS Development Team. All rights reserved
3 $Id$
5 Desc:
6 Lang: English
7 */
8 /*
9 * PARTIAL CHANGELOG:
10 * DATE NAME ENTRY
11 * ---------- ------------------ -------------------------------------------------------------------
12 * 2008-01-25 T. Wiszkowski Rebuilt, rearranged and partially fixed 60% of the code here
13 * Enabled implementation to scan for other PCI IDE controllers
14 * Implemented ATAPI Packet Support for both read and write
15 * Corrected ATAPI DMA handling
16 * Fixed major IDE enumeration bugs severely handicapping transfers with more than one controller
17 * Compacted source and implemented major ATA support procedure
18 * Improved DMA and Interrupt management
19 * Removed obsolete code
20 * 2008-04-03 M. Schulz inb, outb and outl are not used directly anymore. Instead, the ata_* macros are taken.
21 * PRD should be set in little endian mode up (at least I guess so...)
22 * 2008-04-07 M. Schulz Once PRD is ready one has to clear data caches. PRD might still be in cache only on
23 * writeback systems otherwise
26 #define DEBUG 0
27 #include <aros/debug.h>
29 #include <exec/types.h>
30 #include <exec/exec.h>
31 #include <exec/resident.h>
32 #include <utility/utility.h>
33 #include <dos/bptr.h>
35 #include <proto/exec.h>
37 #include "ata.h"
40 Prepare PRD entries for sectors transfer. This function assumes that no one
41 else will even touch PRD. It should be however truth, as for given bus all
42 ATA accesses are protected with a semaphore.
44 LONG dma_Setup(APTR addr, ULONG len, BOOL read, struct PRDEntry* array)
46 ULONG tmp = 0, rem = 0;
47 ULONG flg = read ? DMA_ReadFromRAM : 0;
48 IPTR phy_mem;
49 LONG items = 0;
51 D(bug("[ATA ] dma_Setup(addr %p, len %d, PRDEntry @ %p for %s)\n", addr, len, array, read ? "READ" : "WRITE"));
54 * in future you may have to put this in prd construction procedure
56 while (0 < len)
58 tmp = len;
59 phy_mem = (IPTR)CachePreDMA(addr, &tmp, flg);
61 D(bug("[ATA ] dma_Setup: Translating V:%p > P:%p (%ld bytes)\n", addr, phy_mem, tmp));
63 * update all addresses for the next call
65 addr = &((UBYTE*)addr)[tmp];
66 len -= tmp;
67 flg |= DMA_Continue;
69 /*
70 * check if we're crossing the magic 64k boundary:
72 while (0 < tmp)
75 * politely say what sucks
77 if (phy_mem > 0xffffffffull)
79 bug("[ATA ] dma_Setup: ERROR: ATA DMA POINTERS BEYOND MAXIMUM ALLOWED ADDRESS!\n");
80 return 0;
82 if (items > PRD_MAX)
84 bug("[ATA ] dma_Setup: ERROR: ATA DMA PRD TABLE SIZE TOO LARGE\n");
85 return 0;
89 * calculate remainder and see if it is larger of the current memory block.
90 * if smaller, adjust its size.
92 rem = 0x10000 - (phy_mem & 0xffff);
93 if (rem > tmp)
94 rem = tmp;
96 * update PRD with address and remainder
98 D(bug("[ATA ] dma_Setup: Inserting into PRD Table: %p / %ld @ %p\n", phy_mem, rem, array));
99 array->prde_Address = AROS_LONG2LE(phy_mem);
100 array->prde_Length = AROS_LONG2LE((rem & 0xffff));
101 ++array;
102 ++items;
105 * update locals ;-)
107 phy_mem += rem;
108 tmp -= rem;
112 if (items > 0)
114 --array;
115 array->prde_Length |= AROS_LONG2LE(PRDE_EOT);
117 D(bug("[ATA ] dma_Setup: PRD Table set - %ld items in total.\n", items));
119 * PRD table all set.
121 return items;
125 BOOL dma_SetupPRD(struct ata_Unit *unit, APTR buffer, ULONG sectors, BOOL io)
127 return dma_SetupPRDSize(unit, buffer, sectors << unit->au_SectorShift, io);
130 BOOL dma_SetupPRDSize(struct ata_Unit *unit, APTR buffer, ULONG size, BOOL read)
132 LONG items = 0;
134 D(bug("[ATA%02ld] dma_SetupPRDSize(buffer @ %p, %ld bytes, PRD @ %x for %s)\n", unit->au_UnitNum, buffer, size, unit->au_Bus->ab_PRD, read ? "READ" : "WRITE"));
136 items = dma_Setup(buffer, size, read, unit->au_Bus->ab_PRD);
138 if (0 == items)
139 return FALSE;
141 CacheClearE(unit->au_Bus->ab_PRD, items * sizeof(struct PRDEntry), CACRF_ClearD);
143 ata_outl((ULONG)unit->au_Bus->ab_PRD, dma_PRD, unit->au_DMAPort);
145 if (read)
146 ata_out(DMA_WRITE, dma_Command, unit->au_DMAPort); /* inverse logic */
147 else
148 ata_out(DMA_READ, dma_Command, unit->au_DMAPort);
149 return TRUE;
152 VOID dma_Cleanup(APTR addr, ULONG len, BOOL read)
154 ULONG tmp = 0;
155 ULONG flg = read ? DMA_ReadFromRAM : 0;
157 D(bug("[ATA ] dma_Cleanup(%p, %d bytes)\n", addr, len));
159 while (len > 0)
161 tmp = len;
162 CachePostDMA(addr, &tmp, flg);
163 addr = &((UBYTE*)addr)[tmp];
164 len -= tmp;
165 flg |= DMA_Continue;
169 VOID dma_StartDMA(struct ata_Unit *unit)
171 D(bug("[ATA%02ld] dma_StartDMA()\n", unit->au_UnitNum));
172 ata_out(ata_in(dma_Command, unit->au_DMAPort) | DMA_START, dma_Command, unit->au_DMAPort);
175 VOID dma_StopDMA(struct ata_Unit *unit)
177 D(bug("[ATA%02ld] dma_StopDMA()\n", unit->au_UnitNum));
178 ata_out(ata_in(dma_Command, unit->au_DMAPort) & ~DMA_START, dma_Command, unit->au_DMAPort);