Added 400ns delay in ata_WaitBusyTO before read of device status.
[tangerine.git] / arch / common / ata.device / ata_init.c
blobb5f301e75afadbd479968d97562007a4aea3a9c7
1 /*
2 Copyright © 2004-2008, The AROS Development Team. All rights reserved
3 $Id$
5 Desc:
6 Lang: English
7 */
8 /*
9 * CHANGELOG:
10 * DATE NAME ENTRY
11 * ---------- ------------------ -------------------------------------------------------------------
12 * 2008-04-25 P. Fedin Brought back device discovery for old machines without PCI IDE controllers
13 * 2008-01-25 T. Wiszkowski Rebuilt, rearranged and partially fixed 60% of the code here
14 * Enabled implementation to scan for other PCI IDE controllers
15 * Implemented ATAPI Packet Support for both read and write
16 * Corrected ATAPI DMA handling
17 * Fixed major IDE enumeration bugs severely handicapping transfers with more than one controller
18 * Compacted source and implemented major ATA support procedure
19 * Improved DMA and Interrupt management
20 * Removed obsolete code
21 * 2008-01-26 T. Wiszkowski Added 'nodma' flag for ata driver
22 * Moved variables out of global scope
23 * Replaced static variables
24 * 2008-02-08 T. Wiszkowski Fixed DMA accesses for direct scsi devices,
25 * Corrected IO Areas to allow ATA to talk to PCI controllers
26 * 2008-02-24 T. Wiszkowski Corrected unit open function
27 * 2008-03-03 T. Wiszkowski Added drive reselection + setup delay on Init
28 * 2008-03-23 T. Wiszkowski Corrected Alternative Command block position
29 * 2008-03-30 T. Wiszkowski Added workaround for interrupt collision handling; fixed SATA in LEGACY mode.
30 * nForce and Intel SATA chipsets should now be operational.
31 * 2008-04-03 T. Wiszkowski Fixed IRQ flood issue, eliminated and reduced obsolete / redundant code
32 * 2008-04-07 T. Wiszkowski Changed bus timeout mechanism
33 * 2008-04-07 M. Schulz The SiL3114 chip yields Class 0x01 and SubClass 0x80. Therefore it will
34 * not be find with the generic enumeration. Do an explicit search after it
35 * since ata.device may handle it in legacy mode without any issues.
36 * 2008-05-11 T. Wiszkowski Remade the ata trannsfers altogether, corrected the pio/irq handling
37 * medium removal, device detection, bus management and much more
38 * 2008-05-18 T. Wiszkowski corrected device naming to handle cases where more than 10 physical units may be available
41 #define DEBUG 0
42 #include <aros/debug.h>
44 #include <aros/symbolsets.h>
46 #include <exec/types.h>
47 #include <exec/exec.h>
48 #include <exec/resident.h>
49 #include <exec/tasks.h>
50 #include <exec/memory.h>
51 #include <exec/nodes.h>
52 #include <utility/utility.h>
53 #include <oop/oop.h>
54 #include <libraries/expansion.h>
55 #include <libraries/configvars.h>
57 #include <dos/bptr.h>
58 #include <dos/filehandler.h>
59 #include <string.h>
61 #include <proto/exec.h>
62 #include <proto/timer.h>
63 #include <proto/bootloader.h>
64 #include <proto/expansion.h>
66 #include <oop/oop.h>
67 #include <hidd/pci.h>
68 #include <proto/oop.h>
71 #include "ata.h"
72 #include LC_LIBDEFS_FILE
75 typedef struct
77 struct ataBase *ATABase;
78 UWORD CurrentBus;
79 UWORD PredefBus;
80 } EnumeratorArgs;
82 /* Add a bootnode using expansion.library */
83 BOOL AddVolume(ULONG StartCyl, ULONG EndCyl, struct ata_Unit *unit)
85 struct ExpansionBase *ExpansionBase;
86 struct DeviceNode *devnode;
87 IPTR *pp;
88 TEXT dosdevname[4] = "HD0", *handler;
89 UWORD len;
91 ExpansionBase = (struct ExpansionBase *)OpenLibrary("expansion.library",
92 40L);
94 if (ExpansionBase)
96 pp = AllocMem(24*sizeof(IPTR), MEMF_PUBLIC | MEMF_CLEAR);
98 if (pp)
100 /* This should be dealt with using some sort of volume manager or such. */
101 switch (unit->au_DevType)
103 case DG_DIRECT_ACCESS:
104 break;
105 case DG_CDROM:
106 dosdevname[0] = 'C';
107 break;
108 default:
109 D(bug("IDE: AddVolume called on unknown devicetype\n"));
112 if (unit->au_UnitNum < 10)
113 dosdevname[2] += unit->au_UnitNum % 10;
114 else
115 dosdevname[2] = 'A' - 10 + unit->au_UnitNum;
116 pp[0] = (IPTR)dosdevname;
117 pp[1] = (IPTR)MOD_NAME_STRING;
118 pp[2] = unit->au_UnitNum;
119 pp[DE_TABLESIZE + 4] = DE_BOOTBLOCKS;
120 pp[DE_SIZEBLOCK + 4] = 1 << (unit->au_SectorShift - 2);
121 pp[DE_NUMHEADS + 4] = unit->au_Heads;
122 pp[DE_SECSPERBLOCK + 4] = 1;
123 pp[DE_BLKSPERTRACK + 4] = unit->au_Sectors;
124 pp[DE_RESERVEDBLKS + 4] = 2;
125 pp[DE_LOWCYL + 4] = StartCyl;
126 pp[DE_HIGHCYL + 4] = EndCyl;
127 pp[DE_NUMBUFFERS + 4] = 10;
128 pp[DE_BUFMEMTYPE + 4] = MEMF_PUBLIC | MEMF_CHIP;
129 pp[DE_MAXTRANSFER + 4] = 0x00200000;
130 pp[DE_MASK + 4] = 0x7FFFFFFE;
131 pp[DE_BOOTPRI + 4] = ((!unit->au_DevType) ? 0 : 10);
132 pp[DE_DOSTYPE + 4] = 0x444F5301;
133 pp[DE_BOOTBLOCKS + 4] = 2;
134 devnode = MakeDosNode(pp);
136 if (devnode)
138 if(unit->au_DevType == DG_DIRECT_ACCESS)
139 handler = "afs.handler";
140 else
141 handler = "cdrom.handler";
142 len = strlen(handler);
143 if ((devnode->dn_Handler =
144 MKBADDR(AllocMem(AROS_BSTR_MEMSIZE4LEN(len),
145 MEMF_PUBLIC | MEMF_CLEAR
150 CopyMem(handler, AROS_BSTR_ADDR(devnode->dn_Handler), len);
151 AROS_BSTR_setstrlen(devnode->dn_Handler, len);
153 D(bug("-Adding volume %s with SC=%d, EC=%d\n",
154 &(devnode->dn_Ext.dn_AROS.dn_DevName[0]), StartCyl, EndCyl));
155 AddBootNode(pp[DE_BOOTPRI + 4], 0, devnode, 0);
156 D(bug("done\n"));
158 return TRUE;
163 CloseLibrary((struct Library *)ExpansionBase);
166 return FALSE;
169 static void Add_Device(IPTR IOBase, IPTR IOAlt, IPTR INTLine,
170 IPTR DMABase, int x, EnumeratorArgs *a)
173 * static list of io/irqs that we can handle
175 static struct __bus
177 ULONG port;
178 ULONG alt;
179 UBYTE irq;
180 } Buses[] =
182 {0x1f0, 0x3f4, 14},
183 {0x170, 0x374, 15},
184 {0x168, 0x36c, 10},
185 {0x1e8, 0x3ec, 11},
189 * ata bus - this is going to be created and linked to the master list here
191 struct ata_Bus *ab;
194 * see if IO Base is valid. otherwise pick device from static list
195 * (this most likely means the device is right there)
197 if (IOBase == 0)
199 if (a->PredefBus < (sizeof(Buses) / sizeof(Buses[0])))
202 * collect IOBase and interrupt from the above list
204 IOBase = Buses[a->PredefBus].port;
205 IOAlt = Buses[a->PredefBus].alt;
206 INTLine = Buses[a->PredefBus].irq;
207 a->PredefBus++;
209 else
211 IOBase = 0;
212 IOAlt = 0;
213 DMABase = 0;
214 INTLine = 0;
215 bug("[ATA>>] Found more controllers\n");
217 * we're all done. no idea what else they want from us
219 return;
223 D(bug("[ATA>>] IO: %x:%x DMA: %x\n", IOBase, IOAlt, DMABase));
226 * initialize structure
228 ab = (struct ata_Bus*) AllocVecPooled(a->ATABase->ata_MemPool, sizeof(struct ata_Bus));
229 if (ab == NULL)
230 return;
232 ab->ab_Base = a->ATABase;
233 ab->ab_Port = IOBase;
234 ab->ab_Alt = IOAlt;
235 ab->ab_Irq = INTLine;
236 ab->ab_Dev[0] = DEV_NONE;
237 ab->ab_Dev[1] = DEV_NONE;
238 ab->ab_Flags = 0;
239 ab->ab_SleepySignal = 0;
240 ab->ab_BusNum = a->CurrentBus++;
241 ab->ab_Timeout = 0;
242 ab->ab_Units[0] = 0;
243 ab->ab_Units[1] = 0;
244 ab->ab_IntHandler = (HIDDT_IRQ_Handler *)AllocVecPooled(a->ATABase->ata_MemPool, sizeof(HIDDT_IRQ_Handler));
245 ab->ab_Task = 0;
246 ab->ab_HandleIRQ = 0;
248 D(bug("[ATA>>] Analysing bus %d, units %d and %d\n", ab->ab_BusNum, ab->ab_BusNum<<1, (ab->ab_BusNum<<1)+1));
251 * allocate DMA PRD
253 ab->ab_PRD = AllocVecPooled(a->ATABase->ata_MemPool, (PRD_MAX+1) * 2 * sizeof(struct PRDEntry));
254 if ((0x10000 - ((ULONG)ab->ab_PRD & 0xffff)) < PRD_MAX * sizeof(struct PRDEntry))
255 ab->ab_PRD = (void*)((((IPTR)ab->ab_PRD)+0xffff) &~ 0xffff);
258 * scan bus - try to locate all devices (disables irq)
260 ata_InitBus(ab);
261 if (ab->ab_Dev[0] > DEV_UNKNOWN)
263 ab->ab_Units[0] = AllocVecPooled(a->ATABase->ata_MemPool, sizeof(struct ata_Unit));
264 ab->ab_Units[0]->au_DMAPort = (DMABase != 0 ? DMABase + (x<<3) : 0);
265 ata_init_unit(ab, 0);
267 if (ab->ab_Dev[1] > DEV_UNKNOWN)
269 ab->ab_Units[1] = AllocVecPooled(a->ATABase->ata_MemPool, sizeof(struct ata_Unit));
270 ab->ab_Units[1]->au_DMAPort = (DMABase != 0 ? DMABase + (x<<3) : 0);
271 ata_init_unit(ab, 1);
274 D(bug("[ATA>>] Bus %ld: Unit 0 - %x, Unit 1 - %x\n", ab->ab_BusNum, ab->ab_Dev[0], ab->ab_Dev[1]));
277 * start things up :)
278 * note: this happens no matter there are devices or not
279 * sort of almost-ready-for-hotplug ;)
281 AddTail((struct List*)&a->ATABase->ata_Buses, (struct Node*)ab);
285 * PCI BUS ENUMERATOR
286 * collect ALL ata/ide capable devices (including SATA and other) and spawn consecutive tasks
288 * This function is growing too large. It will shorten drasticly once this whole mess gets converted into c++
291 static
292 AROS_UFH3(void, Enumerator,
293 AROS_UFHA(struct Hook *, hook, A0),
294 AROS_UFHA(OOP_Object *, Device, A2),
295 AROS_UFHA(APTR, message,A1))
297 AROS_USERFUNC_INIT
300 * parameters we will want to acquire
302 IPTR ProductID,
303 VendorID,
304 DMABase,
305 INTLine,
306 IOBase,
307 IOAlt;
310 * the PCI Attr Base
312 OOP_AttrBase HiddPCIDeviceAttrBase = OOP_ObtainAttrBase(IID_Hidd_PCIDevice);
315 * new parameters for every device:
316 * - allow bus mastering
318 struct TagItem attrs[] =
320 { aHidd_PCIDevice_isMaster, TRUE },
321 { TAG_DONE, 0UL }
325 * enumerator params
327 EnumeratorArgs *a = (EnumeratorArgs*)hook->h_Data;
330 * temporary variables
332 int x;
335 * obtain more or less useful data
337 OOP_GetAttr(Device, aHidd_PCIDevice_ProductID, &ProductID);
338 OOP_GetAttr(Device, aHidd_PCIDevice_VendorID, &VendorID);
339 OOP_GetAttr(Device, aHidd_PCIDevice_Base4, &DMABase);
341 if (a->ATABase->ata_NoDMA)
342 DMABase = 0;
345 * we can have as many as four ports assigned to this device
347 for (x=0; x<2; x++)
350 * obtain base and interrupt
352 switch (x)
354 case 0:
355 OOP_GetAttr(Device, aHidd_PCIDevice_Base0, &IOBase);
356 OOP_GetAttr(Device, aHidd_PCIDevice_Base1, &IOAlt);
357 break;
358 case 1:
359 OOP_GetAttr(Device, aHidd_PCIDevice_Base2, &IOBase);
360 OOP_GetAttr(Device, aHidd_PCIDevice_Base3, &IOAlt);
361 break;
363 OOP_GetAttr(Device, aHidd_PCIDevice_INTLine, &INTLine);
365 D(bug("[ATA.scanbus] IDE device %04x:%04x - IO: %x:%x DMA: %x\n", ProductID, VendorID, IOBase, IOAlt, DMABase));
366 Add_Device(IOBase, IOAlt, INTLine, DMABase, x, a);
371 * check dma status
373 if (DMABase != 0)
374 D(bug("[ATA ] Bus0 status says %02x, Bus1 status says %02x\n", ata_in(2, DMABase), ata_in(10, DMABase)));
376 OOP_SetAttrs(Device, attrs);
377 OOP_ReleaseAttrBase(IID_Hidd_PCIDevice);
379 AROS_USERFUNC_EXIT
383 void ata_Scan(struct ataBase *base)
385 OOP_Object *pci;
386 struct SignalSemaphore ssem;
388 struct Node* node;
389 int i;
390 EnumeratorArgs Args=
392 base,
397 D(bug("[ATA--] Enumerating devices\n"));
399 pci = OOP_NewObject(NULL, CLID_Hidd_PCI, NULL);
401 if (pci)
403 struct Hook FindHook = {
404 h_Entry: (IPTR (*)())Enumerator,
405 h_Data: &Args
408 struct TagItem Requirements[] = {
409 {tHidd_PCI_Class, 0x01},
410 {tHidd_PCI_SubClass, 0x01},
411 {TAG_DONE, 0x00}
414 struct pHidd_PCI_EnumDevices enummsg = {
415 mID: OOP_GetMethodID(IID_Hidd_PCI, moHidd_PCI_EnumDevices),
416 callback: &FindHook,
417 requirements: (struct TagItem *)&Requirements,
418 }, *msg = &enummsg;
420 OOP_DoMethod(pci, (OOP_Msg)msg);
423 * The SiL3114 chip yields Class 0x01 and SubClass 0x80. Therefore it will not be find
424 * with the enumeration above. Do an explicit search now since ata.device may handle it
425 * in legacy mode without any issues.
427 * Note: This chip is used on Sam440 board.
429 Requirements[0].ti_Tag = tHidd_PCI_VendorID;
430 Requirements[0].ti_Data = 0x1095;
431 Requirements[1].ti_Tag = tHidd_PCI_ProductID;
432 Requirements[1].ti_Data = 0x3114;
434 OOP_DoMethod(pci, (OOP_Msg)msg);
436 Requirements[0].ti_Tag = tHidd_PCI_VendorID;
437 Requirements[0].ti_Data = 0x1095;
438 Requirements[1].ti_Tag = tHidd_PCI_ProductID;
439 Requirements[1].ti_Data = 0x3512;
441 OOP_DoMethod(pci, (OOP_Msg)msg);
443 OOP_DisposeObject(pci);
445 if (!Args.CurrentBus) {
446 D(bug("[ATA--] No PCI devices found, attempting defaults\n"));
447 for (i=0; i<4; i++)
448 Add_Device(0, 0, 0, 0, i & 1, &Args);
452 InitSemaphore(&ssem);
453 ForeachNode(&base->ata_Buses, node)
455 ata_InitBusTask((struct ata_Bus*)node, &ssem);
459 * wait for all buses to complete their init
461 ObtainSemaphore(&ssem);
464 * and leave.
466 ReleaseSemaphore(&ssem);
470 Here shall we start. Make function static as it shouldn't be visible from
471 outside.
473 static int ata_init(LIBBASETYPEPTR LIBBASE)
475 struct BootLoaderBase *BootLoaderBase;
478 * I've decided to use memory pools again. Alloc everything needed from
479 * a pool, so that we avoid memory fragmentation.
481 LIBBASE->ata_MemPool = CreatePool(MEMF_CLEAR | MEMF_PUBLIC | MEMF_SEM_PROTECTED , 8192, 4096);
482 if (LIBBASE->ata_MemPool == NULL)
483 return FALSE;
486 * store library pointer so we can use it later
488 LIBBASE->ata_32bit = FALSE;
489 LIBBASE->ata_NoDMA = FALSE;
492 * start initialization:
493 * obtain kernel parameters
495 D(bug("[ATA--] ata.device initialization\n"));
496 BootLoaderBase = OpenResource("bootloader.resource");
497 D(bug("[ATA--] BootloaderBase = %p\n", BootLoaderBase));
498 if (BootLoaderBase != NULL)
500 struct List *list;
501 struct Node *node;
503 list = (struct List *)GetBootInfo(BL_Args);
504 if (list)
506 ForeachNode(list, node)
508 if (strncmp(node->ln_Name, "ATA=", 4) == 0)
510 if (strstr(node->ln_Name, "32bit"))
512 D(bug("[ATA ] Using 32-bit IO transfers\n"));
513 LIBBASE->ata_32bit = TRUE;
515 if (strstr(node->ln_Name, "nodma"))
517 D(bug("[ATA ] Disabled DMA transfers\n"));
518 LIBBASE->ata_NoDMA = TRUE;
526 * Initialize BUS list
528 LIBBASE->ata_Buses.mlh_Head = (struct MinNode*) &LIBBASE->ata_Buses.mlh_Tail;
529 LIBBASE->ata_Buses.mlh_Tail = NULL;
530 LIBBASE->ata_Buses.mlh_TailPred = (struct MinNode*) &LIBBASE->ata_Buses.mlh_Head;
532 ata_Scan(LIBBASE);
534 /* Try to setup daemon task looking for diskchanges */
535 ata_InitDaemonTask(LIBBASE);
536 return TRUE;
539 static int open
541 LIBBASETYPEPTR LIBBASE,
542 struct IORequest *iorq,
543 ULONG unitnum,
544 ULONG flags
548 * device location
550 ULONG bus, dev;
553 * Assume it failed
555 iorq->io_Error = IOERR_OPENFAIL;
558 * actual bus
560 struct ata_Bus *b = (struct ata_Bus*)LIBBASE->ata_Buses.mlh_Head;
563 * Extract bus and device numbers
565 bus = unitnum >> 1; // 0xff00 >> 8
566 dev = (unitnum & 0x1); // 0x00ff
569 * locate bus
571 while (bus--)
573 b = (struct ata_Bus*)b->ab_Node.mln_Succ;
574 if (b == NULL)
575 return FALSE;
578 if (b->ab_Node.mln_Succ == NULL)
579 return FALSE;
582 * locate unit
584 if (b->ab_Units[dev] == NULL)
585 return FALSE;
588 * set up iorequest
590 iorq->io_Device = &LIBBASE->ata_Device;
591 iorq->io_Unit = &b->ab_Units[dev]->au_Unit;
592 iorq->io_Error = 0;
594 b->ab_Units[dev]->au_Unit.unit_OpenCnt++;
596 return TRUE;
599 /* Close given device */
600 static int close
602 LIBBASETYPEPTR LIBBASE,
603 struct IORequest *iorq
606 struct ata_Unit *unit = (struct ata_Unit *)iorq->io_Unit;
608 /* First of all make the important fields of struct IORequest invalid! */
609 iorq->io_Unit = (struct Unit *)~0;
611 /* Decrease use counters of unit */
612 unit->au_Unit.unit_OpenCnt--;
614 return TRUE;
617 ADD2INITLIB(ata_init, 0)
618 ADD2OPENDEV(open, 0)
619 ADD2CLOSEDEV(close, 0)
620 ADD2LIBS("irq.hidd", 0, static struct Library *, __irqhidd)
621 /* vim: set ts=8 sts=4 et : */