2 Copyright © 2004-2008, The AROS Development Team. All rights reserved
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.
39 #include <aros/debug.h>
41 #include <aros/symbolsets.h>
43 #include <exec/types.h>
44 #include <exec/exec.h>
45 #include <exec/resident.h>
46 #include <exec/tasks.h>
47 #include <exec/memory.h>
48 #include <exec/nodes.h>
49 #include <utility/utility.h>
51 #include <libraries/expansion.h>
52 #include <libraries/configvars.h>
55 #include <dos/filehandler.h>
58 #include <proto/exec.h>
59 #include <proto/timer.h>
60 #include <proto/bootloader.h>
61 #include <proto/expansion.h>
65 #include <proto/oop.h>
69 #include LC_LIBDEFS_FILE
74 struct ataBase
*ATABase
;
79 /* Add a bootnode using expansion.library */
80 BOOL
AddVolume(ULONG StartCyl
, ULONG EndCyl
, struct ata_Unit
*unit
)
82 struct ExpansionBase
*ExpansionBase
;
83 struct DeviceNode
*devnode
;
86 TEXT dosdevname
[4] = "HD0", *handler
;
89 ExpansionBase
= (struct ExpansionBase
*)OpenLibrary("expansion.library",
94 pp
= AllocMem(24*sizeof(IPTR
), MEMF_PUBLIC
| MEMF_CLEAR
);
98 /* This should be dealt with using some sort of volume manager or such. */
99 switch (unit
->au_DevType
)
101 case DG_DIRECT_ACCESS
:
107 D(bug("IDE: AddVolume called on unknown devicetype\n"));
109 dosdevname
[2] += volnum
;
110 pp
[0] = (IPTR
)dosdevname
;
111 pp
[1] = (IPTR
)MOD_NAME_STRING
;
112 pp
[2] = unit
->au_UnitNum
;
113 pp
[DE_TABLESIZE
+ 4] = DE_BOOTBLOCKS
;
114 pp
[DE_SIZEBLOCK
+ 4] = 1 << (unit
->au_SectorShift
- 2);
115 pp
[DE_NUMHEADS
+ 4] = unit
->au_Heads
;
116 pp
[DE_SECSPERBLOCK
+ 4] = 1;
117 pp
[DE_BLKSPERTRACK
+ 4] = unit
->au_Sectors
;
118 pp
[DE_RESERVEDBLKS
+ 4] = 2;
119 pp
[DE_LOWCYL
+ 4] = StartCyl
;
120 pp
[DE_HIGHCYL
+ 4] = EndCyl
;
121 pp
[DE_NUMBUFFERS
+ 4] = 10;
122 pp
[DE_BUFMEMTYPE
+ 4] = MEMF_PUBLIC
| MEMF_CHIP
;
123 pp
[DE_MAXTRANSFER
+ 4] = 0x00200000;
124 pp
[DE_MASK
+ 4] = 0x7FFFFFFE;
125 pp
[DE_BOOTPRI
+ 4] = ((!unit
->au_DevType
) ? 0 : 10);
126 pp
[DE_DOSTYPE
+ 4] = 0x444F5301;
127 pp
[DE_BOOTBLOCKS
+ 4] = 2;
128 devnode
= MakeDosNode(pp
);
132 if(unit
->au_DevType
== DG_DIRECT_ACCESS
)
133 handler
= "afs.handler";
135 handler
= "cdrom.handler";
136 len
= strlen(handler
);
137 if ((devnode
->dn_Handler
=
138 MKBADDR(AllocMem(AROS_BSTR_MEMSIZE4LEN(len
),
139 MEMF_PUBLIC
| MEMF_CLEAR
144 CopyMem(handler
, AROS_BSTR_ADDR(devnode
->dn_Handler
), len
);
145 AROS_BSTR_setstrlen(devnode
->dn_Handler
, len
);
147 D(bug("-Adding volume %s with SC=%d, EC=%d\n",
148 &(devnode
->dn_Ext
.dn_AROS
.dn_DevName
[0]), StartCyl
, EndCyl
));
149 AddBootNode(pp
[DE_BOOTPRI
+ 4], 0, devnode
, 0);
159 CloseLibrary((struct Library
*)ExpansionBase
);
165 static void Add_Device(IPTR IOBase
, IPTR IOAlt
, IPTR INTLine
,
166 IPTR DMABase
, int x
, EnumeratorArgs
*a
)
169 * static list of io/irqs that we can handle
185 * ata bus - this is going to be created and linked to the master list here
190 * see if IO Base is valid. otherwise pick device from static list
191 * (this most likely means the device is right there)
195 if (a
->PredefBus
< (sizeof(Buses
) / sizeof(Buses
[0])))
198 * collect IOBase and interrupt from the above list
200 IOBase
= Buses
[a
->PredefBus
].port
;
201 IOAlt
= Buses
[a
->PredefBus
].alt
;
202 INTLine
= Buses
[a
->PredefBus
].irq
;
211 bug("[ATA ] Found more controllers\n");
213 * we're all done. no idea what else they want from us
219 D(bug("[ATA.Add_Device] IO: %x:%x DMA: %x\n", IOBase
, IOAlt
, DMABase
));
222 * initialize structure
224 ab
= (struct ata_Bus
*) AllocVecPooled(a
->ATABase
->ata_MemPool
, sizeof(struct ata_Bus
));
228 ab
->ab_Base
= a
->ATABase
;
229 ab
->ab_Port
= IOBase
;
231 ab
->ab_Irq
= INTLine
;
232 ab
->ab_Dev
[0] = DEV_NONE
;
233 ab
->ab_Dev
[1] = DEV_NONE
;
235 ab
->ab_SleepySignal
= 0;
236 ab
->ab_BusNum
= a
->CurrentBus
++;
237 ab
->ab_Waiting
= FALSE
;
241 ab
->ab_IntHandler
= (HIDDT_IRQ_Handler
*)AllocVecPooled(a
->ATABase
->ata_MemPool
, sizeof(HIDDT_IRQ_Handler
));
242 D(bug("[ATA ] Analysing bus %d, units %d and %d\n", ab
->ab_BusNum
, ab
->ab_BusNum
<<1, (ab
->ab_BusNum
<<1)+1));
247 ab
->ab_PRD
= AllocVecPooled(a
->ATABase
->ata_MemPool
, (PRD_MAX
+1) * 2 * sizeof(struct PRDEntry
));
248 if ((0x10000 - ((ULONG
)ab
->ab_PRD
& 0xffff)) < PRD_MAX
* sizeof(struct PRDEntry
))
249 ab
->ab_PRD
= (void*)((((IPTR
)ab
->ab_PRD
)+0xffff) &~ 0xffff);
251 InitSemaphore(&ab
->ab_Lock
);
254 * scan bus - try to locate all devices
257 if (ab
->ab_Dev
[0] > DEV_UNKNOWN
)
259 ab
->ab_Units
[0] = AllocVecPooled(a
->ATABase
->ata_MemPool
, sizeof(struct ata_Unit
));
260 ab
->ab_Units
[0]->au_DMAPort
= (DMABase
!= 0 ? DMABase
+ (x
<<3) : 0);
261 ata_init_unit(ab
, 0);
263 if (ab
->ab_Dev
[1] > DEV_UNKNOWN
)
265 ab
->ab_Units
[1] = AllocVecPooled(a
->ATABase
->ata_MemPool
, sizeof(struct ata_Unit
));
266 ab
->ab_Units
[1]->au_DMAPort
= (DMABase
!= 0 ? DMABase
+ (x
<<3) : 0);
267 ata_init_unit(ab
, 1);
270 D(bug("[ATA ] Bus %ld: Unit 0 - %x, Unit 1 - %x\n", ab
->ab_BusNum
, ab
->ab_Dev
[0], ab
->ab_Dev
[1]));
274 * note: this happens no matter there are devices or not
275 * sort of almost-ready-for-hotplug ;)
277 AddTail((struct List
*)&a
->ATABase
->ata_Buses
, (struct Node
*)ab
);
282 * collect ALL ata/ide capable devices (including SATA and other) and spawn consecutive tasks
284 * This function is growing too large. It will shorten drasticly once this whole mess gets converted into c++
288 AROS_UFH3(void, Enumerator
,
289 AROS_UFHA(struct Hook
*, hook
, A0
),
290 AROS_UFHA(OOP_Object
*, Device
, A2
),
291 AROS_UFHA(APTR
, message
,A1
))
296 * parameters we will want to acquire
308 OOP_AttrBase HiddPCIDeviceAttrBase
= OOP_ObtainAttrBase(IID_Hidd_PCIDevice
);
311 * new parameters for every device:
312 * - allow bus mastering
314 struct TagItem attrs
[] =
316 { aHidd_PCIDevice_isMaster
, TRUE
},
323 EnumeratorArgs
*a
= (EnumeratorArgs
*)hook
->h_Data
;
326 * temporary variables
331 * obtain more or less useful data
333 OOP_GetAttr(Device
, aHidd_PCIDevice_ProductID
, &ProductID
);
334 OOP_GetAttr(Device
, aHidd_PCIDevice_VendorID
, &VendorID
);
335 OOP_GetAttr(Device
, aHidd_PCIDevice_Base4
, &DMABase
);
337 if (a
->ATABase
->ata_NoDMA
)
341 * we can have as many as four ports assigned to this device
346 * obtain base and interrupt
351 OOP_GetAttr(Device
, aHidd_PCIDevice_Base0
, &IOBase
);
352 OOP_GetAttr(Device
, aHidd_PCIDevice_Base1
, &IOAlt
);
355 OOP_GetAttr(Device
, aHidd_PCIDevice_Base2
, &IOBase
);
356 OOP_GetAttr(Device
, aHidd_PCIDevice_Base3
, &IOAlt
);
359 OOP_GetAttr(Device
, aHidd_PCIDevice_INTLine
, &INTLine
);
361 D(bug("[ATA.scanbus] IDE device %04x:%04x - IO: %x:%x DMA: %x\n", ProductID
, VendorID
, IOBase
, IOAlt
, DMABase
));
362 Add_Device(IOBase
, IOAlt
, INTLine
, DMABase
, x
, a
);
370 D(bug("[ATA ] Bus0 status says %02x, Bus1 status says %02x\n", ata_in(2, DMABase
), ata_in(10, DMABase
)));
372 OOP_SetAttrs(Device
, attrs
);
373 OOP_ReleaseAttrBase(IID_Hidd_PCIDevice
);
379 void ata_Scan(struct ataBase
*base
)
391 D(bug("[ATA--] Enumerating devices\n"));
393 pci
= OOP_NewObject(NULL
, CLID_Hidd_PCI
, NULL
);
397 struct Hook FindHook
= {
398 h_Entry
: (IPTR (*)())Enumerator
,
402 struct TagItem Requirements
[] = {
403 {tHidd_PCI_Class
, 0x01},
404 {tHidd_PCI_SubClass
, 0x01},
408 struct pHidd_PCI_EnumDevices enummsg
= {
409 mID
: OOP_GetMethodID(IID_Hidd_PCI
, moHidd_PCI_EnumDevices
),
411 requirements
: (struct TagItem
*)&Requirements
,
414 OOP_DoMethod(pci
, (OOP_Msg
)msg
);
417 * The SiL3114 chip yields Class 0x01 and SubClass 0x80. Therefore it will not be find
418 * with the enumeration above. Do an explicit search now since ata.device may handle it
419 * in legacy mode without any issues.
421 * Note: This chip is used on Sam440 board.
423 Requirements
[0].ti_Tag
= tHidd_PCI_VendorID
;
424 Requirements
[0].ti_Data
= 0x1095;
425 Requirements
[1].ti_Tag
= tHidd_PCI_ProductID
;
426 Requirements
[1].ti_Data
= 0x3114;
428 OOP_DoMethod(pci
, (OOP_Msg
)msg
);
430 OOP_DisposeObject(pci
);
432 if (!Args
.CurrentBus
) {
433 D(bug("[ATA--] No PCI devices found, attempting defaults\n"));
435 Add_Device(0, 0, 0, 0, i
& 1, &Args
);
438 ForeachNode(&base
->ata_Buses
, node
)
440 ata_InitBusTask((struct ata_Bus
*)node
);
445 Here shall we start. Make function static as it shouldn't be visible from
448 static int ata_init(LIBBASETYPEPTR LIBBASE
)
450 struct BootLoaderBase
*BootLoaderBase
;
453 * I've decided to use memory pools again. Alloc everything needed from
454 * a pool, so that we avoid memory fragmentation.
456 LIBBASE
->ata_MemPool
= CreatePool(MEMF_CLEAR
| MEMF_PUBLIC
| MEMF_SEM_PROTECTED
, 8192, 4096);
457 if (LIBBASE
->ata_MemPool
== NULL
)
461 * store library pointer so we can use it later
463 LIBBASE
->ata_32bit
= FALSE
;
464 LIBBASE
->ata_NoDMA
= FALSE
;
467 * start initialization:
468 * obtain kernel parameters
470 D(bug("[ATA--] ata.device initialization\n"));
471 BootLoaderBase
= OpenResource("bootloader.resource");
472 D(bug("[ATA--] BootloaderBase = %p\n", BootLoaderBase
));
473 if (BootLoaderBase
!= NULL
)
478 list
= (struct List
*)GetBootInfo(BL_Args
);
481 ForeachNode(list
, node
)
483 if (strncmp(node
->ln_Name
, "ATA=", 4) == 0)
485 if (strstr(node
->ln_Name
, "32bit"))
487 D(bug("[ATA ] Using 32-bit IO transfers\n"));
488 LIBBASE
->ata_32bit
= TRUE
;
490 if (strstr(node
->ln_Name
, "nodma"))
492 D(bug("[ATA ] Disabled DMA transfers\n"));
493 LIBBASE
->ata_NoDMA
= TRUE
;
501 * Initialize BUS list
503 LIBBASE
->ata_Buses
.mlh_Head
= (struct MinNode
*) &LIBBASE
->ata_Buses
.mlh_Tail
;
504 LIBBASE
->ata_Buses
.mlh_Tail
= NULL
;
505 LIBBASE
->ata_Buses
.mlh_TailPred
= (struct MinNode
*) &LIBBASE
->ata_Buses
.mlh_Head
;
509 /* Try to setup daemon task looking for diskchanges */
510 ata_InitDaemonTask(LIBBASE
);
516 LIBBASETYPEPTR LIBBASE
,
517 struct IORequest
*iorq
,
530 iorq
->io_Error
= IOERR_OPENFAIL
;
535 struct ata_Bus
*b
= (struct ata_Bus
*)LIBBASE
->ata_Buses
.mlh_Head
;
538 * Extract bus and device numbers
540 bus
= unitnum
>> 1; // 0xff00 >> 8
541 dev
= (unitnum
& 0x1); // 0x00ff
548 b
= (struct ata_Bus
*)b
->ab_Node
.mln_Succ
;
553 if (b
->ab_Node
.mln_Succ
== NULL
)
559 if (b
->ab_Units
[dev
] == NULL
)
565 iorq
->io_Device
= &LIBBASE
->ata_Device
;
566 iorq
->io_Unit
= &b
->ab_Units
[dev
]->au_Unit
;
569 b
->ab_Units
[dev
]->au_Unit
.unit_OpenCnt
++;
574 /* Close given device */
577 LIBBASETYPEPTR LIBBASE
,
578 struct IORequest
*iorq
581 struct ata_Unit
*unit
= (struct ata_Unit
*)iorq
->io_Unit
;
583 /* First of all make the important fields of struct IORequest invalid! */
584 iorq
->io_Unit
= (struct Unit
*)~0;
586 /* Decrease use counters of unit */
587 unit
->au_Unit
.unit_OpenCnt
--;
592 ADD2INITLIB(ata_init
, 0)
594 ADD2CLOSEDEV(close
, 0)
595 ADD2LIBS("irq.hidd", 0, static struct Library
*, __irqhidd
)
596 /* vim: set ts=8 sts=4 et : */