- Give PCI controllers lower unit numbers than legacy controllers.
[cake.git] / arch / common / ata.device / ata_init.c
blob218dc937dd7cbf495a559336b6de7760ea4651d9
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-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
39 * 2008-06-24 P. Fedin Added 'NoMulti' flag to disable multisector transfers
40 * 2009-03-05 T. Wiszkowski remade timeouts, added timer-based and benchmark-based delays.
43 #define DEBUG 0
44 #include <aros/debug.h>
46 #include <aros/symbolsets.h>
48 #include <exec/types.h>
49 #include <exec/exec.h>
50 #include <exec/resident.h>
51 #include <exec/tasks.h>
52 #include <exec/memory.h>
53 #include <exec/nodes.h>
54 #include <utility/utility.h>
55 #include <oop/oop.h>
56 #include <libraries/expansion.h>
57 #include <libraries/configvars.h>
59 #include <dos/bptr.h>
60 #include <dos/filehandler.h>
61 #include <string.h>
63 #include <proto/exec.h>
64 #include <proto/timer.h>
65 #include <proto/bootloader.h>
66 #include <proto/expansion.h>
68 #include <oop/oop.h>
69 #include <hidd/pci.h>
70 #include <proto/oop.h>
72 #include "ata.h"
73 #include "timer.h"
75 #include LC_LIBDEFS_FILE
77 typedef struct
79 struct ataBase *ATABase;
80 UWORD CurrentBus;
81 } EnumeratorArgs;
83 struct ata_ProbedBus
85 struct Node atapb_Node;
86 IPTR atapb_IOBase;
87 IPTR atapb_IOAlt;
88 IPTR atapb_INTLine;
89 IPTR atapb_DMABase;
90 EnumeratorArgs *atapb_a;
91 BOOL atapb_Has80Wire;
94 struct ata_LegacyBus
96 struct Node atalb_Node;
97 IPTR atalb_IOBase;
98 IPTR atalb_IOAlt;
99 IPTR atalb_INTLine;
100 IPTR atalb_DMABase;
101 UBYTE atalb_ControllerID;
102 UBYTE atalb_BusID;
105 #define ATABUSNODEPRI_PROBED 50
106 #define ATABUSNODEPRI_PROBEDLEGACY 100
107 #define ATABUSNODEPRI_LEGACY 0
109 #define RANGESIZE0 8
110 #define RANGESIZE1 4
111 #define DMASIZE 16
113 /* static list of io/irqs that we can handle */
114 static struct ata__legacybus
116 ULONG lb_Port;
117 ULONG lb_Alt;
118 UBYTE lb_IRQ;
119 UBYTE lb_ControllerID;
120 UBYTE lb_Bus;
121 } LegacyBuses[] =
123 {0x1f0, 0x3f4, 14, 0, 0},
124 {0x170, 0x374, 15, 0, 1},
125 {0x168, 0x36c, 10, 1, 0},
126 {0x1e8, 0x3ec, 11, 1, 1},
127 {0, 0, 0, 0, 0},
130 /* Add a bootnode using expansion.library */
131 BOOL ata_RegisterVolume(ULONG StartCyl, ULONG EndCyl, struct ata_Unit *unit)
133 struct ExpansionBase *ExpansionBase;
134 struct DeviceNode *devnode;
135 IPTR *pp;
136 TEXT dosdevname[4] = "HD0", *handler;
137 UWORD len;
139 ExpansionBase = (struct ExpansionBase *)OpenLibrary("expansion.library",
140 40L);
142 if (ExpansionBase)
144 pp = AllocMem(24*sizeof(IPTR), MEMF_PUBLIC | MEMF_CLEAR);
146 if (pp)
148 /* This should be dealt with using some sort of volume manager or such. */
149 switch (unit->au_DevType)
151 case DG_DIRECT_ACCESS:
152 break;
153 case DG_CDROM:
154 dosdevname[0] = 'C';
155 break;
156 default:
157 D(bug("[ATA>>]:-ata_RegisterVolume called on unknown devicetype\n"));
160 if (unit->au_UnitNum < 10)
161 dosdevname[2] += unit->au_UnitNum % 10;
162 else
163 dosdevname[2] = 'A' - 10 + unit->au_UnitNum;
164 pp[0] = (IPTR)dosdevname;
165 pp[1] = (IPTR)MOD_NAME_STRING;
166 pp[2] = unit->au_UnitNum;
167 pp[DE_TABLESIZE + 4] = DE_BOOTBLOCKS;
168 pp[DE_SIZEBLOCK + 4] = 1 << (unit->au_SectorShift - 2);
169 pp[DE_NUMHEADS + 4] = unit->au_Heads;
170 pp[DE_SECSPERBLOCK + 4] = 1;
171 pp[DE_BLKSPERTRACK + 4] = unit->au_Sectors;
172 pp[DE_RESERVEDBLKS + 4] = 2;
173 pp[DE_LOWCYL + 4] = StartCyl;
174 pp[DE_HIGHCYL + 4] = EndCyl;
175 pp[DE_NUMBUFFERS + 4] = 10;
176 pp[DE_BUFMEMTYPE + 4] = MEMF_PUBLIC | MEMF_CHIP;
177 pp[DE_MAXTRANSFER + 4] = 0x00200000;
178 pp[DE_MASK + 4] = 0x7FFFFFFE;
179 pp[DE_BOOTPRI + 4] = ((!unit->au_DevType) ? 0 : 10);
180 pp[DE_DOSTYPE + 4] = 0x444F5301;
181 pp[DE_BOOTBLOCKS + 4] = 2;
182 devnode = MakeDosNode(pp);
184 if (devnode)
186 if(unit->au_DevType == DG_DIRECT_ACCESS)
187 handler = "afs.handler";
188 else
189 handler = "cdrom.handler";
190 len = strlen(handler);
191 if ((devnode->dn_Handler =
192 MKBADDR(AllocMem(AROS_BSTR_MEMSIZE4LEN(len),
193 MEMF_PUBLIC | MEMF_CLEAR
198 CopyMem(handler, AROS_BSTR_ADDR(devnode->dn_Handler), len);
199 AROS_BSTR_setstrlen(devnode->dn_Handler, len);
201 D(bug("[ATA>>]:-ata_RegisterVolume: '%s' with StartCyl=%d, EndCyl=%d .. ",
202 &(devnode->dn_Ext.dn_AROS.dn_DevName[0]), StartCyl, EndCyl));
203 AddBootNode(pp[DE_BOOTPRI + 4], 0, devnode, 0);
204 D(bug("done\n"));
206 return TRUE;
211 CloseLibrary((struct Library *)ExpansionBase);
214 return FALSE;
217 static void ata_RegisterBus(IPTR IOBase, IPTR IOAlt, IPTR INTLine,
218 IPTR DMABase, BOOL has80Wire, EnumeratorArgs *a)
221 * ata bus - this is going to be created and linked to the master list here
223 struct ata_Bus *ab;
225 UWORD i;
228 * initialize structure
230 ab = (struct ata_Bus*) AllocVecPooled(a->ATABase->ata_MemPool, sizeof(struct ata_Bus));
231 if (ab == NULL)
232 return;
234 ab->ab_Base = a->ATABase;
235 ab->ab_Port = IOBase;
236 ab->ab_Alt = IOAlt;
237 ab->ab_IRQ = INTLine;
238 ab->ab_Dev[0] = DEV_NONE;
239 ab->ab_Dev[1] = DEV_NONE;
240 ab->ab_Flags = 0;
241 ab->ab_SleepySignal = 0;
242 ab->ab_BusNum = a->CurrentBus++;
243 ab->ab_Timeout = 0;
244 ab->ab_Units[0] = NULL;
245 ab->ab_Units[1] = NULL;
246 ab->ab_IntHandler = (HIDDT_IRQ_Handler *)AllocVecPooled(a->ATABase->ata_MemPool, sizeof(HIDDT_IRQ_Handler));
247 ab->ab_Task = NULL;
248 ab->ab_HandleIRQ = NULL;
250 D(bug("[ATA>>] ata_RegisterBus: Analysing bus %d, units %d and %d\n", ab->ab_BusNum, ab->ab_BusNum<<1, (ab->ab_BusNum<<1)+1));
251 D(bug("[ATA>>] ata_RegisterBus: IRQ %d, IO: %x:%x, DMA: %x\n", INTLine, IOBase, IOAlt, DMABase));
254 * allocate DMA PRD
256 ab->ab_PRD = AllocVecPooled(a->ATABase->ata_MemPool, (PRD_MAX+1) * 2 * sizeof(struct PRDEntry));
257 if ((0x10000 - ((ULONG)ab->ab_PRD & 0xffff)) < PRD_MAX * sizeof(struct PRDEntry))
258 ab->ab_PRD = (void*)((((IPTR)ab->ab_PRD)+0xffff) &~ 0xffff);
261 * scan bus - try to locate all devices (disables irq)
263 ata_InitBus(ab);
264 for (i = 0; i < MAX_BUSUNITS; i++)
266 if (ab->ab_Dev[i] > DEV_UNKNOWN)
268 ab->ab_Units[i] = AllocVecPooled(a->ATABase->ata_MemPool,
269 sizeof(struct ata_Unit));
270 ab->ab_Units[i]->au_DMAPort = DMABase;
271 ab->ab_Units[i]->au_Flags = has80Wire ? AF_80Wire : 0;
272 ata_init_unit(ab, i);
276 D(bug("[ATA>>] ata_RegisterBus: Bus %ld: Unit 0 - %x, Unit 1 - %x\n", ab->ab_BusNum, ab->ab_Dev[0], ab->ab_Dev[1]));
279 * start things up :)
280 * note: this happens no matter there are devices or not
281 * sort of almost-ready-for-hotplug ;)
283 AddTail((struct List*)&a->ATABase->ata_Buses, (struct Node*)ab);
287 * PCI BUS ENUMERATOR
288 * collect ALL ata/ide capable devices (including SATA and other) and
289 * spawn concurrent tasks.
291 * This function is growing too large. It will shorten drasticly once this whole mess gets converted into c++
294 static
295 AROS_UFH3(void, ata_PCIEnumerator_h,
296 AROS_UFHA(struct Hook *, hook, A0),
297 AROS_UFHA(OOP_Object *, Device, A2),
298 AROS_UFHA(APTR, message,A1))
300 AROS_USERFUNC_INIT
303 * parameters we will want to acquire
305 IPTR ProductID,
306 VendorID,
307 DMABase,
308 DMASize,
309 INTLine,
310 IOBase,
311 IOAlt,
312 IOSize,
313 AltSize,
314 SubClass,
315 Interface;
317 BOOL _usablebus = FALSE;
320 * the PCI Attr Base
322 OOP_AttrBase HiddPCIDeviceAttrBase = OOP_ObtainAttrBase(IID_Hidd_PCIDevice);
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_VendorID, &VendorID);
338 OOP_GetAttr(Device, aHidd_PCIDevice_ProductID, &ProductID);
339 OOP_GetAttr(Device, aHidd_PCIDevice_Base4, &DMABase);
340 OOP_GetAttr(Device, aHidd_PCIDevice_Size4, &DMASize);
341 OOP_GetAttr(Device, aHidd_PCIDevice_SubClass, &SubClass);
342 OOP_GetAttr(Device, aHidd_PCIDevice_Interface, &Interface);
344 if (a->ATABase->ata_NoDMA || !(Interface & 0x80))
345 DMABase = 0;
348 * we can have up to two buses assigned to this device
350 for (x = 0; SubClass != 0 && SubClass != 7 && x < MAX_DEVICEBUSES; x++)
352 struct ata_LegacyBus *_legacyBus = NULL;
353 BOOL isLegacy = FALSE;
355 if (x == 0)
357 bug("[ATA ] ata_PCIEnumerator_h: Found IDE device %04x:%04x\n", VendorID, ProductID);
361 * obtain I/O bases and interrupt line
363 if ((Interface & (1 << (x << 1))) || SubClass != 1)
365 switch (x)
367 case 0:
368 OOP_GetAttr(Device, aHidd_PCIDevice_Base0, &IOBase);
369 OOP_GetAttr(Device, aHidd_PCIDevice_Size0, &IOSize);
370 OOP_GetAttr(Device, aHidd_PCIDevice_Base1, &IOAlt);
371 OOP_GetAttr(Device, aHidd_PCIDevice_Size1, &AltSize);
372 break;
373 case 1:
374 OOP_GetAttr(Device, aHidd_PCIDevice_Base2, &IOBase);
375 OOP_GetAttr(Device, aHidd_PCIDevice_Size2, &IOSize);
376 OOP_GetAttr(Device, aHidd_PCIDevice_Base3, &IOAlt);
377 OOP_GetAttr(Device, aHidd_PCIDevice_Size3, &AltSize);
378 break;
380 OOP_GetAttr(Device, aHidd_PCIDevice_INTLine, &INTLine);
382 else if ((_legacyBus = (struct ata_LegacyBus *)
383 a->ATABase->ata__legacybuses.lh_Head)->atalb_ControllerID == 0)
385 Remove((struct Node *)_legacyBus);
386 IOBase = _legacyBus->atalb_IOBase;
387 IOAlt = _legacyBus->atalb_IOAlt;
388 INTLine = _legacyBus->atalb_INTLine;
389 FreeMem(_legacyBus, sizeof(struct ata_LegacyBus));
390 isLegacy = TRUE;
391 IOSize = RANGESIZE0;
392 AltSize = RANGESIZE1;
394 else
396 bug("[ATA ] ata_PCIEnumerator_h: Ran out of legacy buses\n");
397 IOBase = 0;
400 if (IOBase != (IPTR)NULL && IOSize == RANGESIZE0
401 && AltSize == RANGESIZE1
402 && (DMASize = DMASIZE || DMABase == NULL || SubClass == 1))
404 struct ata_ProbedBus *probedbus;
405 D(bug("[ATA ] ata_PCIEnumerator_h: Adding Bus %d - IRQ %d, IO: %x:%x, DMA: %x\n", x, INTLine, IOBase, IOAlt, DMABase));
406 if ((probedbus = AllocMem(sizeof(struct ata_ProbedBus), MEMF_CLEAR | MEMF_PUBLIC)) != (IPTR)NULL)
408 probedbus->atapb_IOBase = IOBase;
409 probedbus->atapb_IOAlt = IOAlt;
410 probedbus->atapb_INTLine = INTLine;
411 if (DMABase != 0)
412 probedbus->atapb_DMABase = DMABase + (x << 3);
413 probedbus->atapb_a = a;
414 probedbus->atapb_Has80Wire = TRUE;
416 if (isLegacy)
418 D(bug("[ATA ] ata_PCIEnumerator_h: Device using Legacy-Bus IOPorts\n"));
419 probedbus->atapb_Node.ln_Pri = ATABUSNODEPRI_PROBEDLEGACY - (a->ATABase->ata__buscount++);
421 else
422 probedbus->atapb_Node.ln_Pri = ATABUSNODEPRI_PROBED - (a->ATABase->ata__buscount++);
424 Enqueue((struct List *)&a->ATABase->ata__probedbuses, (struct Node *)probedbus);
425 _usablebus = TRUE;
430 if (_usablebus)
432 struct TagItem attrs[] =
434 { aHidd_PCIDevice_isIO, TRUE },
435 { aHidd_PCIDevice_isMaster, DMABase != 0 },
436 { TAG_DONE, 0UL }
438 OOP_SetAttrs(Device, attrs);
441 /* check dma status if applicable */
442 if (DMABase != 0)
443 D(bug("[ATA ] ata_PCIEnumerator_h: Bus0 DMA Status %02x, Bus1 DMA Status %02x\n", ata_in(2, DMABase), ata_in(10, DMABase)));
445 OOP_ReleaseAttrBase(IID_Hidd_PCIDevice);
447 AROS_USERFUNC_EXIT
451 void ata_Scan(struct ataBase *base)
453 OOP_Object *pci;
454 struct SignalSemaphore ssem;
455 struct ata_ProbedBus *probedbus;
457 struct Node* node;
458 EnumeratorArgs Args=
460 base,
464 D(bug("[ATA--] ata_Scan: Enumerating devices\n"));
466 if (base->ata_ScanFlags & ATA_SCANPCI) {
467 D(bug("[ATA--] ata_Scan: Checking for supported PCI devices ..\n"));
468 pci = OOP_NewObject(NULL, CLID_Hidd_PCI, NULL);
470 if (pci)
472 struct Hook FindHook = {
473 h_Entry: (IPTR (*)())ata_PCIEnumerator_h,
474 h_Data: &Args
477 struct TagItem Requirements[] = {
478 {tHidd_PCI_Class, 0x01},
479 {TAG_DONE, 0x00}
482 struct pHidd_PCI_EnumDevices enummsg = {
483 mID: OOP_GetMethodID(IID_Hidd_PCI, moHidd_PCI_EnumDevices),
484 callback: &FindHook,
485 requirements: (struct TagItem *)&Requirements,
486 }, *msg = &enummsg;
488 OOP_DoMethod(pci, (OOP_Msg)msg);
490 OOP_DisposeObject(pci);
493 if (base->ata_ScanFlags & ATA_SCANLEGACY) {
494 struct ata_LegacyBus *legacybus;
495 D(bug("[ATA--] ata_Scan: Adding Remaining Legacy-Buses\n"));
496 while ((legacybus = (struct ata_LegacyBus *)
497 RemHead((struct List *)&base->ata__legacybuses)) != NULL)
499 if ((probedbus = AllocMem(sizeof(struct ata_ProbedBus), MEMF_CLEAR | MEMF_PUBLIC)) != NULL)
501 probedbus->atapb_IOBase = legacybus->atalb_IOBase;
502 probedbus->atapb_IOAlt = legacybus->atalb_IOAlt;
503 probedbus->atapb_INTLine = legacybus->atalb_INTLine;
504 probedbus->atapb_DMABase = (IPTR)NULL;
505 probedbus->atapb_Has80Wire = FALSE;
506 probedbus->atapb_a = &Args;
507 probedbus->atapb_Node.ln_Pri = ATABUSNODEPRI_LEGACY - (base->ata__buscount++);
508 D(bug("[ATA--] ata_Scan: Adding Legacy Bus - IO: %x:%x\n",
509 probedbus->atapb_IOBase, probedbus->atapb_IOAlt));
510 Enqueue((struct List *)&base->ata__probedbuses, (struct Node *)&probedbus->atapb_Node);
513 FreeMem(legacybus, sizeof(struct ata_LegacyBus));
516 D(bug("[ATA--] ata_Scan: Registering Probed Buses..\n"));
517 while ((probedbus = (struct ata_ProbedBus *)
518 RemHead((struct List *)&base->ata__probedbuses)) != NULL)
520 ata_RegisterBus(
521 probedbus->atapb_IOBase,
522 probedbus->atapb_IOAlt,
523 probedbus->atapb_INTLine,
524 probedbus->atapb_DMABase,
525 probedbus->atapb_Has80Wire,
526 probedbus->atapb_a);
528 FreeMem(probedbus, sizeof(struct ata_ProbedBus));
531 D(bug("[ATA--] ata_Scan: Initialising Bus Tasks..\n"));
532 InitSemaphore(&ssem);
533 ForeachNode(&base->ata_Buses, node)
535 ata_InitBusTask((struct ata_Bus*)node, &ssem);
539 * wait for all buses to complete their init
541 D(bug("[ATA--] ata_Scan: Waiting for Buses to finish Initialising\n"));
542 ObtainSemaphore(&ssem);
545 * and leave.
547 ReleaseSemaphore(&ssem);
548 D(bug("[ATA--] ata_Scan: Finished\n"));
552 Here shall we start. Make function static as it shouldn't be visible from
553 outside.
555 static int ata_init(LIBBASETYPEPTR LIBBASE)
557 struct BootLoaderBase *BootLoaderBase;
558 struct ata_LegacyBus *_legacybus;
559 int i;
561 D(bug("[ATA--] ata_init: ata.device Initialization\n"));
564 * I've decided to use memory pools again. Alloc everything needed from
565 * a pool, so that we avoid memory fragmentation.
567 LIBBASE->ata_MemPool = CreatePool(MEMF_CLEAR | MEMF_PUBLIC | MEMF_SEM_PROTECTED , 8192, 4096);
568 if (LIBBASE->ata_MemPool == NULL)
569 return FALSE;
571 D(bug("[ATA--] ata_init: MemPool @ %p\n", LIBBASE->ata_MemPool));
573 /* Prepare lists for probed/found ide buses */
574 NEWLIST((struct List *)&LIBBASE->ata__legacybuses);
575 NEWLIST((struct List *)&LIBBASE->ata__probedbuses);
577 /* Build the list of possible legacy-bus ports */
578 for (i = 0; LegacyBuses[i].lb_Port != 0 ; i++)
580 if ((_legacybus = AllocMem(sizeof(struct ata_LegacyBus), MEMF_CLEAR | MEMF_PUBLIC)) != NULL)
582 D(bug("[ATA--] ata_init: Prepare Legacy Bus %d:%d entry [IOPorts %x:%x IRQ %d]\n", LegacyBuses[i].lb_ControllerID, LegacyBuses[i].lb_Bus, LegacyBuses[i].lb_Port, LegacyBuses[i].lb_Alt, LegacyBuses[i].lb_IRQ));
584 _legacybus->atalb_IOBase = (IPTR)LegacyBuses[i].lb_Port;
585 _legacybus->atalb_IOAlt = (IPTR)LegacyBuses[i].lb_Alt;
586 _legacybus->atalb_INTLine = (IPTR)LegacyBuses[i].lb_IRQ;
587 _legacybus->atalb_ControllerID = (IPTR)LegacyBuses[i].lb_ControllerID;
588 _legacybus->atalb_BusID = (IPTR)LegacyBuses[i].lb_Bus;
589 AddTail(&LIBBASE->ata__legacybuses, &_legacybus->atalb_Node);
593 /* Set default ata.device config options */
594 LIBBASE->ata_ScanFlags = ATA_SCANPCI | ATA_SCANLEGACY;
595 LIBBASE->ata_32bit = FALSE;
596 LIBBASE->ata_NoMulti = FALSE;
597 LIBBASE->ata_NoDMA = FALSE;
600 * start initialization:
601 * obtain kernel parameters
603 BootLoaderBase = OpenResource("bootloader.resource");
604 D(bug("[ATA--] ata_init: BootloaderBase = %p\n", BootLoaderBase));
605 if (BootLoaderBase != NULL)
607 struct List *list;
608 struct Node *node;
610 list = (struct List *)GetBootInfo(BL_Args);
611 if (list)
613 ForeachNode(list, node)
615 if (strncmp(node->ln_Name, "ATA=", 4) == 0)
617 if (strstr(node->ln_Name, "nopci"))
619 D(bug("[ATA ] ata_init: Disabling PCI device scan\n"));
620 LIBBASE->ata_ScanFlags &= ~ATA_SCANPCI;
622 if (strstr(node->ln_Name, "nolegacy"))
624 D(bug("[ATA ] ata_init: Disabling Legacy ports\n"));
625 LIBBASE->ata_ScanFlags &= ~ATA_SCANLEGACY;
627 if (strstr(node->ln_Name, "32bit"))
629 D(bug("[ATA ] ata_init: Using 32-bit IO transfers\n"));
630 LIBBASE->ata_32bit = TRUE;
632 if (strstr(node->ln_Name, "nomulti"))
634 D(bug("[ATA ] ata_init: Disabled multisector transfers\n"));
635 LIBBASE->ata_NoMulti = TRUE;
637 if (strstr(node->ln_Name, "nodma"))
639 D(bug("[ATA ] ata_init: Disabled DMA transfers\n"));
640 LIBBASE->ata_NoDMA = TRUE;
648 * Initialize BUS list
650 LIBBASE->ata_Buses.mlh_Head = (struct MinNode*) &LIBBASE->ata_Buses.mlh_Tail;
651 LIBBASE->ata_Buses.mlh_Tail = NULL;
652 LIBBASE->ata_Buses.mlh_TailPred = (struct MinNode*) &LIBBASE->ata_Buses.mlh_Head;
655 * Find all suitable devices ..
657 ata_Scan(LIBBASE);
659 /* Try to setup daemon task looking for diskchanges */
660 ata_InitDaemonTask(LIBBASE);
661 return TRUE;
664 static int open
666 LIBBASETYPEPTR LIBBASE,
667 struct IORequest *iorq,
668 ULONG unitnum,
669 ULONG flags
673 * device location
675 ULONG bus, dev;
678 * Assume it failed
680 iorq->io_Error = IOERR_OPENFAIL;
683 * actual bus
685 struct ata_Bus *b = (struct ata_Bus*)LIBBASE->ata_Buses.mlh_Head;
688 * Extract bus and device numbers
690 bus = unitnum >> 1; // 0xff00 >> 8
691 dev = (unitnum & 0x1); // 0x00ff
694 * locate bus
696 while (bus--)
698 b = (struct ata_Bus*)b->ab_Node.mln_Succ;
699 if (b == NULL)
700 return FALSE;
703 if (b->ab_Node.mln_Succ == NULL)
704 return FALSE;
707 * locate unit
709 if (b->ab_Units[dev] == NULL)
710 return FALSE;
713 * set up iorequest
715 iorq->io_Device = &LIBBASE->ata_Device;
716 iorq->io_Unit = &b->ab_Units[dev]->au_Unit;
717 iorq->io_Error = 0;
719 b->ab_Units[dev]->au_Unit.unit_OpenCnt++;
721 return TRUE;
724 /* Close given device */
725 static int close
727 LIBBASETYPEPTR LIBBASE,
728 struct IORequest *iorq
731 struct ata_Unit *unit = (struct ata_Unit *)iorq->io_Unit;
733 /* First of all make the important fields of struct IORequest invalid! */
734 iorq->io_Unit = (struct Unit *)~0;
736 /* Decrease use counters of unit */
737 unit->au_Unit.unit_OpenCnt--;
739 return TRUE;
742 ADD2INITLIB(ata_init, 0)
743 ADD2OPENDEV(open, 0)
744 ADD2CLOSEDEV(close, 0)
745 ADD2LIBS("irq.hidd", 0, static struct Library *, __irqhidd)
746 /* vim: set ts=8 sts=4 et : */