2 Copyright © 2004-2007, The AROS Development Team. All rights reserved
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-01-26 T. Wiszkowski Added 'nodma' flag for ata driver
21 * Moved variables out of global scope
22 * Replaced static variables
23 * 2008-02-08 T. Wiszkowski Fixed DMA accesses for direct scsi devices,
24 * Corrected IO Areas to allow ATA to talk to PCI controllers
25 * 2008-02-24 T. Wiszkowski Corrected unit open function
29 #include <aros/debug.h>
31 #include <aros/symbolsets.h>
33 #include <exec/types.h>
34 #include <exec/exec.h>
35 #include <exec/resident.h>
36 #include <exec/tasks.h>
37 #include <exec/memory.h>
38 #include <exec/nodes.h>
39 #include <utility/utility.h>
41 #include <libraries/expansion.h>
42 #include <libraries/configvars.h>
45 #include <dos/filehandler.h>
48 #include <proto/exec.h>
49 #include <proto/timer.h>
50 #include <proto/bootloader.h>
51 #include <proto/expansion.h>
55 #include <proto/oop.h>
59 #include LC_LIBDEFS_FILE
64 struct ataBase
*ATABase
;
69 /* Add a bootnode using expansion.library */
70 BOOL
AddVolume(ULONG StartCyl
, ULONG EndCyl
, struct ata_Unit
*unit
)
72 struct ExpansionBase
*ExpansionBase
;
73 struct DeviceNode
*devnode
;
76 TEXT dosdevname
[4] = "HD0", *handler
;
79 ExpansionBase
= (struct ExpansionBase
*)OpenLibrary("expansion.library",
84 pp
= AllocMem(24*sizeof(IPTR
), MEMF_PUBLIC
| MEMF_CLEAR
);
88 /* This should be dealt with using some sort of volume manager or such. */
89 switch (unit
->au_DevType
)
91 case DG_DIRECT_ACCESS
:
97 D(bug("IDE: AddVolume called on unknown devicetype\n"));
99 dosdevname
[2] += volnum
;
100 pp
[0] = (IPTR
)dosdevname
;
101 pp
[1] = (IPTR
)MOD_NAME_STRING
;
102 pp
[2] = unit
->au_UnitNum
;
103 pp
[DE_TABLESIZE
+ 4] = DE_BOOTBLOCKS
;
104 pp
[DE_SIZEBLOCK
+ 4] = 1 << (unit
->au_SectorShift
- 2);
105 pp
[DE_NUMHEADS
+ 4] = unit
->au_Heads
;
106 pp
[DE_SECSPERBLOCK
+ 4] = 1;
107 pp
[DE_BLKSPERTRACK
+ 4] = unit
->au_Sectors
;
108 pp
[DE_RESERVEDBLKS
+ 4] = 2;
109 pp
[DE_LOWCYL
+ 4] = StartCyl
;
110 pp
[DE_HIGHCYL
+ 4] = EndCyl
;
111 pp
[DE_NUMBUFFERS
+ 4] = 10;
112 pp
[DE_BUFMEMTYPE
+ 4] = MEMF_PUBLIC
| MEMF_CHIP
;
113 pp
[DE_MAXTRANSFER
+ 4] = 0x00200000;
114 pp
[DE_MASK
+ 4] = 0x7FFFFFFE;
115 pp
[DE_BOOTPRI
+ 4] = ((!unit
->au_DevType
) ? 0 : 10);
116 pp
[DE_DOSTYPE
+ 4] = 0x444F5301;
117 pp
[DE_BOOTBLOCKS
+ 4] = 2;
118 devnode
= MakeDosNode(pp
);
122 if(unit
->au_DevType
== DG_DIRECT_ACCESS
)
123 handler
= "afs.handler";
125 handler
= "cdrom.handler";
126 len
= strlen(handler
);
127 if ((devnode
->dn_Handler
=
128 MKBADDR(AllocMem(AROS_BSTR_MEMSIZE4LEN(len
),
129 MEMF_PUBLIC
| MEMF_CLEAR
134 CopyMem(handler
, AROS_BSTR_ADDR(devnode
->dn_Handler
), len
);
135 AROS_BSTR_setstrlen(devnode
->dn_Handler
, len
);
137 D(bug("-Adding volume %s with SC=%d, EC=%d\n",
138 &(devnode
->dn_Ext
.dn_AROS
.dn_DevName
[0]), StartCyl
, EndCyl
));
139 AddBootNode(pp
[DE_BOOTPRI
+ 4], 0, devnode
, 0);
149 CloseLibrary((struct Library
*)ExpansionBase
);
157 * collect ALL ata/ide capable devices (including SATA and other) and spawn consecutive tasks
161 AROS_UFH3(void, Enumerator
,
162 AROS_UFHA(struct Hook
*, hook
, A0
),
163 AROS_UFHA(OOP_Object
*, Device
, A2
),
164 AROS_UFHA(APTR
, message
,A1
))
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 * parameters we will want to acquire
202 OOP_AttrBase HiddPCIDeviceAttrBase
= OOP_ObtainAttrBase(IID_Hidd_PCIDevice
);
205 * new parameters for every device:
206 * - allow bus mastering
208 struct TagItem attrs
[] =
210 { aHidd_PCIDevice_isMaster
, TRUE
},
217 EnumeratorArgs
*a
= (EnumeratorArgs
*)hook
->h_Data
;
220 * temporary variables
225 * obtain more or less useful data
227 OOP_GetAttr(Device
, aHidd_PCIDevice_ProductID
, &ProductID
);
228 OOP_GetAttr(Device
, aHidd_PCIDevice_VendorID
, &VendorID
);
229 OOP_GetAttr(Device
, aHidd_PCIDevice_Base4
, &DMABase
);
231 if (a
->ATABase
->ata_NoDMA
)
235 * we can have as many as four ports assigned to this device
240 * obtain base and interrupt
245 OOP_GetAttr(Device
, aHidd_PCIDevice_Base0
, &IOBase
);
246 OOP_GetAttr(Device
, aHidd_PCIDevice_Base1
, &IOAlt
);
249 OOP_GetAttr(Device
, aHidd_PCIDevice_Base2
, &IOBase
);
250 OOP_GetAttr(Device
, aHidd_PCIDevice_Base3
, &IOAlt
);
253 OOP_GetAttr(Device
, aHidd_PCIDevice_INTLine
, &INTLine
);
256 * see if IO Base is valid. otherwise pick device from static list
257 * (this most likely means the device is right there)
261 if (a
->PredefBus
< (sizeof(Buses
) / sizeof(Buses
[0])))
264 * collect IOBase and interrupt from the above list
266 IOBase
= Buses
[a
->PredefBus
].port
;
267 IOAlt
= Buses
[a
->PredefBus
].alt
;
268 INTLine
= Buses
[a
->PredefBus
].irq
;
277 bug("[ATA ] Found more controllers\n");
279 * we're all done. no idea what else they want from us
285 D(bug("[ATA.scanbus] IDE device %04x:%04x - IO: %x:%x DMA: %x\n", ProductID
, VendorID
, IOBase
, IOAlt
, DMABase
));
288 * initialize structure
290 ab
= (struct ata_Bus
*) AllocVecPooled(a
->ATABase
->ata_MemPool
, sizeof(struct ata_Bus
));
294 ab
->ab_Base
= a
->ATABase
;
295 ab
->ab_Port
= IOBase
;
297 ab
->ab_Irq
= INTLine
;
298 ab
->ab_Dev
[0] = DEV_NONE
;
299 ab
->ab_Dev
[1] = DEV_NONE
;
301 ab
->ab_SleepySignal
= 0;
302 ab
->ab_BusNum
= a
->CurrentBus
++;
307 ab
->ab_IntHandler
= (HIDDT_IRQ_Handler
*)AllocVecPooled(a
->ATABase
->ata_MemPool
, sizeof(HIDDT_IRQ_Handler
));
308 D(bug("[ATA ] Analysing bus %d, units %d and %d\n", ab
->ab_BusNum
, ab
->ab_BusNum
<<1, (ab
->ab_BusNum
<<1)+1));
313 ab
->ab_PRD
= AllocVecPooled(a
->ATABase
->ata_MemPool
, (PRD_MAX
+1) * 2 * sizeof(struct PRDEntry
));
314 if ((0x10000 - ((ULONG
)ab
->ab_PRD
& 0xffff)) < PRD_MAX
* sizeof(struct PRDEntry
))
315 ab
->ab_PRD
= (void*)((((IPTR
)ab
->ab_PRD
)+0xffff) &~ 0xffff);
317 InitSemaphore(&ab
->ab_Lock
);
320 * scan bus - try to locate all devices
323 if (ab
->ab_Dev
[0] > DEV_UNKNOWN
)
325 ab
->ab_Units
[0] = AllocVecPooled(a
->ATABase
->ata_MemPool
, sizeof(struct ata_Unit
));
326 ab
->ab_Units
[0]->au_DMAPort
= (DMABase
!= 0 ? DMABase
+ (x
<<3) : 0);
328 if (ab
->ab_Dev
[1] > DEV_UNKNOWN
)
330 ab
->ab_Units
[1] = AllocVecPooled(a
->ATABase
->ata_MemPool
, sizeof(struct ata_Unit
));
331 ab
->ab_Units
[1]->au_DMAPort
= (DMABase
!= 0 ? DMABase
+ (x
<<3) : 0);
334 D(bug("[ATA ] Bus %ld: Unit 0 - %x, Unit 1 - %x\n", ab
->ab_BusNum
, ab
->ab_Dev
[0], ab
->ab_Dev
[1]));
338 * note: this happens no matter there are devices or not
339 * sort of almost-ready-for-hotplug ;)
341 AddTail((struct List
*)&a
->ATABase
->ata_Buses
, (struct Node
*)ab
);
350 D(bug("[ATA ] Bus0 status says %02x, Bus1 status says %02x\n", inb(DMABase
+ 2), inb(DMABase
+ 10)));
352 OOP_SetAttrs(Device
, attrs
);
353 OOP_ReleaseAttrBase(IID_Hidd_PCIDevice
);
359 void ata_Scan(struct ataBase
*base
)
363 D(bug("[ATA--] Enumerating devices\n"));
365 pci
= OOP_NewObject(NULL
, CLID_Hidd_PCI
, NULL
);
376 struct Hook FindHook
= {
377 h_Entry
: (IPTR (*)())Enumerator
,
381 struct TagItem Requirements
[] = {
382 {tHidd_PCI_Class
, 0x01},
383 {tHidd_PCI_SubClass
, 0x01},
388 struct pHidd_PCI_EnumDevices enummsg
= {
389 mID
: OOP_GetMethodID(IID_Hidd_PCI
, moHidd_PCI_EnumDevices
),
391 requirements
: (struct TagItem
*)&Requirements
,
394 OOP_DoMethod(pci
, (OOP_Msg
)msg
);
396 OOP_DisposeObject(pci
);
401 Here shall we start. Make function static as it shouldn't be visible from
404 static int ata_init(LIBBASETYPEPTR LIBBASE
)
406 struct BootLoaderBase
*BootLoaderBase
;
409 * I've decided to use memory pools again. Alloc everything needed from
410 * a pool, so that we avoid memory fragmentation.
412 LIBBASE
->ata_MemPool
= CreatePool(MEMF_CLEAR
| MEMF_PUBLIC
| MEMF_SEM_PROTECTED
, 8192, 4096);
413 if (LIBBASE
->ata_MemPool
== NULL
)
417 * store library pointer so we can use it later
419 LIBBASE
->ata_32bit
= FALSE
;
420 LIBBASE
->ata_NoDMA
= FALSE
;
423 * start initialization:
424 * obtain kernel parameters
426 D(bug("[ATA--] ata.device initialization\n"));
427 BootLoaderBase
= OpenResource("bootloader.resource");
428 D(bug("[ATA--] BootloaderBase = %p\n", BootLoaderBase
));
429 if (BootLoaderBase
!= NULL
)
434 list
= (struct List
*)GetBootInfo(BL_Args
);
437 ForeachNode(list
, node
)
439 if (strncmp(node
->ln_Name
, "ATA=", 4) == 0)
441 if (strstr(node
->ln_Name
, "32bit"))
443 D(bug("[ATA ] Using 32-bit IO transfers\n"));
444 LIBBASE
->ata_32bit
= TRUE
;
446 if (strstr(node
->ln_Name
, "nodma"))
448 D(bug("[ATA ] Disabled DMA transfers\n"));
449 LIBBASE
->ata_NoDMA
= TRUE
;
457 * Initialize BUS list
459 LIBBASE
->ata_Buses
.mlh_Head
= (struct MinNode
*) &LIBBASE
->ata_Buses
.mlh_Tail
;
460 LIBBASE
->ata_Buses
.mlh_Tail
= NULL
;
461 LIBBASE
->ata_Buses
.mlh_TailPred
= (struct MinNode
*) &LIBBASE
->ata_Buses
.mlh_Head
;
465 /* Try to setup daemon task looking for diskchanges */
466 ata_InitDaemonTask(LIBBASE
);
472 LIBBASETYPEPTR LIBBASE
,
473 struct IORequest
*iorq
,
486 iorq
->io_Error
= IOERR_OPENFAIL
;
491 struct ata_Bus
*b
= (struct ata_Bus
*)LIBBASE
->ata_Buses
.mlh_Head
;
494 * Extract bus and device numbers
496 bus
= unitnum
>> 1; // 0xff00 >> 8
497 dev
= (unitnum
& 0x1); // 0x00ff
504 b
= (struct ata_Bus
*)b
->ab_Node
.mln_Succ
;
509 if (b
->ab_Node
.mln_Succ
== NULL
)
515 if (b
->ab_Units
[dev
] == NULL
)
521 iorq
->io_Device
= &LIBBASE
->ata_Device
;
522 iorq
->io_Unit
= &b
->ab_Units
[dev
]->au_Unit
;
525 b
->ab_Units
[dev
]->au_Unit
.unit_OpenCnt
++;
530 /* Close given device */
533 LIBBASETYPEPTR LIBBASE
,
534 struct IORequest
*iorq
537 struct ata_Unit
*unit
= (struct ata_Unit
*)iorq
->io_Unit
;
539 /* First of all make the important fields of struct IORequest invalid! */
540 iorq
->io_Unit
= (struct Unit
*)~0;
542 /* Decrease use counters of unit */
543 unit
->au_Unit
.unit_OpenCnt
--;
548 ADD2INITLIB(ata_init
, 0)
550 ADD2CLOSEDEV(close
, 0)
551 ADD2LIBS("irq.hidd", 0, static struct Library
*, __irqhidd
)