2 Copyright © 2004-2019, The AROS Development Team. All rights reserved.
5 Desc: Hardware detection routine
9 #include <aros/debug.h>
10 #include <proto/exec.h>
12 /* We want all other bases obtained from our base */
15 #include <proto/bootloader.h>
16 #include <proto/oop.h>
18 #include <aros/asmcall.h>
19 #include <aros/bootloader.h>
20 #include <aros/symbolsets.h>
22 #include <exec/lists.h>
23 #include <exec/rawfmt.h>
24 #include <hardware/ahci.h>
27 #include <hidd/storage.h>
33 #include "bus_class.h"
34 #include "interface_pio.h"
35 #include "interface_dma.h"
41 * Currently we support legacy ISA ports only on x86.
42 * This can change only if someone ports AROS to PowerPC
43 * retro-machine like PReP.
46 #define SUPPORT_LEGACY
49 #define SUPPORT_LEGACY
52 #define NAME_BUFFER 128
58 CONST_STRPTR ataPCIName
= "ata_pci.hidd";
59 CONST_STRPTR ataPCIControllerName
= "PCI Dual Channel IDE Controller";
61 CONST_STRPTR ataISAControllerName
= "ISA IDE Controller";
64 /* static list of io/irqs that we can handle */
70 UBYTE lb_ControllerID
;
75 static const struct ata__legacybus LegacyBuses
[] =
77 {0x1f0, 0x3f4, 14, 0, 0, "ISA IDE0 primary channel" },
78 {0x170, 0x374, 15, 0, 1, "ISA IDE0 secondary channel"},
79 {0x168, 0x36c, 10, 1, 0, "ISA IDE1 primary channel" },
80 {0x1e8, 0x3ec, 11, 1, 1, "ISA IDE1 secondary channel"},
81 { 0, 0, 0, 0, 0, NULL
}
84 #ifdef DO_SATA_HANDOFF
86 /* SATA handoff code needs timer */
88 static struct IORequest
*OpenTimer(void)
90 struct MsgPort
*p
= CreateMsgPort();
94 struct IORequest
*io
= CreateIORequest(p
, sizeof(struct timerequest
));
98 if (0 == OpenDevice("timer.device", UNIT_MICROHZ
, io
, 0))
110 static void CloseTimer(struct IORequest
*tmr
)
114 struct MsgPort
*p
= tmr
->io_Message
.mn_ReplyPort
;
117 DeleteIORequest(tmr
);
122 static void WaitTO(struct IORequest
* tmr
, ULONG secs
, ULONG micro
)
124 tmr
->io_Command
= TR_ADDREQUEST
;
125 ((struct timerequest
*)tmr
)->tr_time
.tv_secs
= secs
;
126 ((struct timerequest
*)tmr
)->tr_time
.tv_micro
= micro
;
135 * collect ALL ata/ide capable devices (including SATA and other) and
136 * spawn concurrent tasks.
138 * This function is growing too large. It will shorten drasticly once this whole mess gets converted into c++
142 AROS_UFH3(void, ata_PCIEnumerator_h
,
143 AROS_UFHA(struct Hook
*, hook
, A0
),
144 AROS_UFHA(OOP_Object
*, Device
, A2
),
145 AROS_UFHA(APTR
, message
,A1
))
149 struct atapciBase
*base
= hook
->h_Data
;
151 struct PCIDeviceRef
*devRef
;
152 IPTR DMABase
, DMASize
, INTLine
;
153 IPTR IOBase
, IOAlt
, IOSize
, AltSize
, SubClass
, Interface
;
156 OOP_Object
*ata_PCI
= NULL
;
157 struct TagItem ata_tags
[] =
159 {aHidd_Name
, (IPTR
)ataPCIName
},
160 {aHidd_HardwareName
, (IPTR
)ataPCIControllerName
},
161 {aHidd_Producer
, 0 },
162 #define ATA_TAG_VEND 2
163 {aHidd_Product
, 0 },
164 #define ATA_TAG_PROD 3
169 * obtain more or less useful data
171 OOP_GetAttr(Device
, aHidd_PCIDevice_Driver
, (IPTR
*)&Driver
);
172 OOP_GetAttr(Device
, aHidd_PCIDevice_VendorID
, &ata_tags
[ATA_TAG_VEND
].ti_Data
);
173 OOP_GetAttr(Device
, aHidd_PCIDevice_ProductID
, &ata_tags
[ATA_TAG_PROD
].ti_Data
);
174 OOP_GetAttr(Device
, aHidd_PCIDevice_SubClass
, &SubClass
);
175 OOP_GetAttr(Device
, aHidd_PCIDevice_Base4
, &DMABase
);
176 OOP_GetAttr(Device
, aHidd_PCIDevice_Size4
, &DMASize
);
177 OOP_GetAttr(Device
, aHidd_PCIDevice_Interface
, &Interface
);
179 D(bug("[ATA:PCI] ata_PCIEnumerator_h: Found IDE device %04x:%04x\n", ata_tags
[ATA_TAG_VEND
].ti_Data
, ata_tags
[ATA_TAG_PROD
].ti_Data
));
181 /* First check subclass */
182 if ((SubClass
== PCI_SUBCLASS_SCSI
) || (SubClass
== PCI_SUBCLASS_SAS
))
184 D(bug("[ATA:PCI] Unsupported subclass %d\n", SubClass
));
188 owner
= HIDD_PCIDevice_Obtain(Device
, base
->lib
.lib_Node
.ln_Name
);
191 D(bug("[ATA:PCI] Already owned by %s\n", owner
));
195 devRef
= AllocMem(sizeof(struct PCIDeviceRef
), MEMF_ANY
);
198 D(bug("[ATA:PCI] Failed to allocate reference structure\n"));
202 devRef
->ref_Device
= Device
;
203 devRef
->ref_Count
= 0;
206 * SATA controllers may need a special treatment before becoming usable.
207 * The machine's firmware (EFI on Mac) may operate them in native AHCI mode
208 * and not set up legacy mode by itself.
209 * In this case we have to do it ourselves.
210 * This code is based on incomplete ahci.device source code by DissyOfCRN.
211 * CHECKME: In order to work on PPC it uses explicit little-endian I/O,
212 * assuming AHCI register file is always little-endian. Is it correct?
214 if (SubClass
== PCI_SUBCLASS_SATA
)
216 APTR hba_phys
= NULL
;
218 volatile struct ahci_hwhba
*hwhba
;
221 OOP_GetAttr(Device
, aHidd_PCIDevice_Base5
, (IPTR
*)&hba_phys
);
222 OOP_GetAttr(Device
, aHidd_PCIDevice_Size5
, &hba_size
);
224 DSATA(bug("[ATA:PCI] Device %04x:%04x is a SATA device, HBA 0x%p, size 0x%p\n", ata_tags
[ATA_TAG_VEND
].ti_Data
, ata_tags
[ATA_TAG_PROD
].ti_Data
, hba_phys
, hba_size
));
226 hwhba
= HIDD_PCIDriver_MapPCI(Driver
, hba_phys
, hba_size
);
227 DSATA(bug("[ATA:PCI] Mapped at 0x%p\n", hwhba
));
231 DSATA(bug("[ATA:PCI] Mapping failed, device will be ignored\n"));
232 DeviceFree(devRef
, base
);
236 cap
= mmio_inl_le(&hwhba
->cap
);
237 ghc
= mmio_inl_le(&hwhba
->ghc
);
238 DSATA(bug("[ATA:PCI] Capabilities: 0x%08X, host control: 0x%08X\n", cap
, ghc
));
241 * Some hardware may report GHC_AE to be zero, together with CAP_SAM set (indicating
242 * that the device doesn't support legacy IDE registers). Seems to be spec violation
243 * (the AHCI specification says that in this cases GHC_AE is read-only bit which is
245 * Attempting to drive such a hardware causes ata.device to freeze.
246 * This effect has been observed on Marvel 9172 controller (and some other HW,
247 * according to user reports, but nobody has ever provided a debug log).
251 DSATA(bug("[ATA:PCI] Legacy mode is not supported, device will be ignored\n"));
253 HIDD_PCIDriver_UnmapPCI(Driver
, hba_phys
, hba_size
);
254 DeviceFree(devRef
, base
);
260 DSATA(bug("[ATA:PCI] AHCI enabled\n"));
263 * This is ATA driver, not SATA driver, so i'd like to keep SATA-specific code
264 * at a minimum. None of tests revealed a real need for BIOS handoff, no BIOS
265 * was discovered to use controllers in SMI mode.
266 * However, if on some machine we have problems, we can try
269 #ifdef DO_SATA_HANDOFF
270 ULONG version
= mmio_inl_le(&hwhba
->vs
);
271 ULONG cap2
= mmio_inl_le(&hwhba
->cap2
);
273 DSATA(bug("[ATA:PCI] Version: 0x%08X, Cap2: 0x%08X\n", version
, cap2
));
275 if ((version
>= AHCI_VERSION_1_20
) && (cap2
&& CAP2_BOH
))
279 DSATA(bug("[ATA:PCI] HBA supports BIOS/OS handoff\n"));
281 bohc
= mmio_inl_le(&hwhba
->bohc
);
282 if (bohc
&& BOHC_BOS
)
284 struct IORequest
*timereq
;
286 DSATA(bug("[ATA:PCI] Device owned by BIOS, performing handoff\n"));
289 * We need timer.device in order to perform delays.
290 * TODO: in ata_InitBus() it will be opened and closed again.
291 * This is not optimal, it could be opened and closed just once.
293 timereq
= OpenTimer(base
);
296 DSATA(bug("[ATA:PCI] Failed to open timer, can't perform handoff. Device will be ignored\n"));
298 HIDD_PCIDriver_UnmapPCI(Driver
, hba_phys
, hba_size
);
299 DeviceFree(devRef
, base
);
303 mmio_outl_le(bohc
| BOHC_OOS
, &hwhba
->bohc
);
304 /* Spin on BOHC_BOS bit FIXME: Possible dead lock. No maximum time given on AHCI1.3 specs... */
305 while (mmio_inl_le(&hwhba
->bohc
) & BOHC_BOS
);
307 WaitTO(timereq
, 0, 25000);
308 /* If after 25ms BOHC_BB bit is still set give bios a minimum of 2 seconds more time to run */
310 if (mmio_inl_le(&hwhba
->bohc
) & BOHC_BB
)
312 DSATA(bug("[ATA:PCI] Delayed handoff, waiting...\n"));
313 ata_WaitTO(timereq
, 2, 0);
316 DSATA(bug("[ATA:PCI] Handoff done\n"));
321 /* This resets GHC_AE bit, disabling AHCI */
322 mmio_outl_le(0, &hwhba
->ghc
);
325 HIDD_PCIDriver_UnmapPCI(Driver
, (APTR
)hwhba
, hba_size
);
328 ata_PCI
= HW_AddDriver(base
->storageRoot
, base
->ataClass
, ata_tags
);
331 D(bug("[ATA:PCI] ata_PCIEnumerator_h: ATA HW Object @ 0x%p\n", ata_PCI
));
333 * we can have up to two buses assigned to this device
335 for (x
= 0; devRef
!= NULL
&& x
< MAX_DEVICEBUSES
; x
++)
337 BYTE basePri
= ATABUSNODEPRI_PROBED
;
340 * obtain I/O bases and interrupt line
342 if ((Interface
& (1 << (x
<< 1))) || SubClass
!= PCI_SUBCLASS_IDE
)
347 OOP_GetAttr(Device
, aHidd_PCIDevice_Base0
, &IOBase
);
348 OOP_GetAttr(Device
, aHidd_PCIDevice_Size0
, &IOSize
);
349 OOP_GetAttr(Device
, aHidd_PCIDevice_Base1
, &IOAlt
);
350 OOP_GetAttr(Device
, aHidd_PCIDevice_Size1
, &AltSize
);
354 OOP_GetAttr(Device
, aHidd_PCIDevice_Base2
, &IOBase
);
355 OOP_GetAttr(Device
, aHidd_PCIDevice_Size2
, &IOSize
);
356 OOP_GetAttr(Device
, aHidd_PCIDevice_Base3
, &IOAlt
);
357 OOP_GetAttr(Device
, aHidd_PCIDevice_Size3
, &AltSize
);
360 OOP_GetAttr(Device
, aHidd_PCIDevice_INTLine
, &INTLine
);
362 else if (LegacyBuses
[base
->legacycount
].lb_ControllerID
== 0)
366 OOP_GetAttr(Driver
, aHidd_PCIDriver_IOBase
, &isa_io_base
);
367 D(bug("[ATA:PCI] Device using Legacy-Bus IOPorts @ 0x%p\n", isa_io_base
));
369 IOBase
= LegacyBuses
[base
->legacycount
].lb_Port
+ isa_io_base
;
370 IOAlt
= LegacyBuses
[base
->legacycount
].lb_Alt
+ isa_io_base
;
371 INTLine
= LegacyBuses
[base
->legacycount
].lb_IRQ
;
372 basePri
= ATABUSNODEPRI_PROBEDLEGACY
;
374 AltSize
= RANGESIZE1
;
380 D(bug("[ATA:PCI] Legacy buses exhausted\n"));
384 if (IOBase
!= 0 && IOSize
== RANGESIZE0
&& AltSize
== RANGESIZE1
&&
385 (DMASize
>= DMASIZE
|| DMABase
== 0 || SubClass
== PCI_SUBCLASS_IDE
))
387 struct ata_ProbedBus
*probedbus
;
391 D(bug("[ATA:PCI] ata_PCIEnumerator_h: Adding Bus %d - IRQ %d, IO: %x:%x, DMA: %x\n",
392 x
, INTLine
, IOBase
, IOAlt
, DMABase
));
394 OOP_GetAttr(Device
, aHidd_PCIDevice_SubClassDesc
, (IPTR
*)&str
[0]);
395 str
[1] = x
? "secondary" : "primary";
396 len
= 14 + strlen(str
[0]) + strlen(str
[1]);
398 probedbus
= AllocVec(sizeof(struct ata_ProbedBus
) + len
, MEMF_ANY
);
401 IPTR dmaBase
= DMABase
? DMABase
+ (x
<< 3) : 0;
402 STRPTR name
= (char *)probedbus
+ sizeof(struct ata_ProbedBus
);
404 RawDoFmt("PCI %s %s channel", (RAWARG
)str
, RAWFMTFUNC_STRING
, name
);
406 probedbus
->atapb_Parent
= ata_PCI
;
407 probedbus
->atapb_Node
.ln_Name
= name
;
408 probedbus
->atapb_Node
.ln_Type
= basePri
;
409 probedbus
->atapb_Node
.ln_Pri
= basePri
- (base
->ata__buscount
++);
410 probedbus
->atapb_Device
= devRef
;
411 probedbus
->atapb_Vendor
= ata_tags
[ATA_TAG_VEND
].ti_Data
;
412 probedbus
->atapb_Product
= ata_tags
[ATA_TAG_PROD
].ti_Data
;
413 probedbus
->atapb_BusNo
= x
;
414 probedbus
->atapb_IOBase
= IOBase
;
415 probedbus
->atapb_IOAlt
= IOAlt
;
416 probedbus
->atapb_INTLine
= INTLine
;
417 probedbus
->atapb_DMABase
= dmaBase
;
420 Enqueue((struct List
*)&base
->probedbuses
, &probedbus
->atapb_Node
);
422 OOP_SetAttrsTags(Device
, aHidd_PCIDevice_isIO
, TRUE
,
423 aHidd_PCIDevice_isMaster
, DMABase
!= 0,
428 if (!devRef
->ref_Count
)
430 DeviceFree(devRef
, base
);
438 static CONST_STRPTR pciInterfaceIDs
[] =
446 /* We need no attributes for IID_Hidd_PCI, only methods */
447 #define ATTR_OFFSET 1
449 static const struct TagItem Requirements
[] =
451 {tHidd_PCI_Class
, PCI_CLASS_MASSSTORAGE
},
456 * The manner in which this code is written can look a little bit overcomplicated.
457 * However it's just experimental attempt to write hardware scan routine which
458 * can be run more than once, and is hotplug-aware.
459 * In future this may assist implementation of "Rescan devices" functionality
460 * in SysExplorer (for example). This will provide a possibility to load and unload
461 * device drivers on the fly.
462 * For now it's just experiment... Don't pay much attention please. :)
464 static int ata_bus_Detect(struct atapciBase
*base
)
467 struct ata_ProbedBus
*probedbus
;
469 #ifdef SUPPORT_LEGACY
470 BOOL scanlegacy
= TRUE
;
471 OOP_Object
*ata_ISA
= NULL
;
472 int ata_ISA_Ports
= 0;
475 D(bug("[ATA:PCI] %s()\n", __PRETTY_FUNCTION__
));
477 /* Prepare lists for probed/found ide buses */
478 NEWLIST(&base
->probedbuses
);
479 base
->ata__buscount
= 0;
480 base
->legacycount
= 0;
482 /* Obtain command line parameters */
483 BootLoaderBase
= OpenResource("bootloader.resource");
484 D(bug("[ATA:PCI] BootloaderBase = %p\n", BootLoaderBase
));
485 if (BootLoaderBase
!= NULL
)
490 list
= (struct List
*)GetBootInfo(BL_Args
);
493 ForeachNode(list
, node
)
495 if (strncmp(node
->ln_Name
, "ATA=", 4) == 0)
497 const char *cmdline
= &node
->ln_Name
[4];
499 if (strstr(cmdline
, "nopci"))
501 D(bug("[ATA:PCI] Disabling PCI device scan\n"));
504 #ifdef SUPPORT_LEGACY
505 if (strstr(cmdline
, "nolegacy"))
507 D(bug("[ATA:PCI] Disabling Legacy ports\n"));
511 if (strstr(cmdline
, "disable"))
513 D(bug("[ATA:PCI] Disabling all ATA devices\n"));
514 #ifdef SUPPORT_LEGACY
525 D(bug("[ATA:PCI] ata_bus_Detect: Enumerating devices\n"));
529 BOOL doPCIScan
= TRUE
;
531 * Attempt to get PCI subsytem object.
532 * If this fails, PCI isn't there. But it's not fatal for us.
534 OOP_Object
*pci
= OOP_NewObject(NULL
, CLID_Hidd_PCI
, NULL
);
538 struct Hook FindHook
=
540 .h_Entry
= (IPTR (*)())ata_PCIEnumerator_h
,
545 * Obtain PCI attribute and method bases only once.
547 if (!base
->PCIDeviceAttrBase
)
549 if (OOP_ObtainAttrBasesArray(&base
->PCIDeviceAttrBase
, &pciInterfaceIDs
[ATTR_OFFSET
]))
553 if (OOP_ObtainMethodBasesArray(&base
->PCIMethodBase
, pciInterfaceIDs
))
561 D(bug("[ATA:PCI] ata_bus_Detect: Checking for supported PCI devices ..\n"));
563 HIDD_PCI_EnumDevices(pci
, &FindHook
, Requirements
);
568 #ifdef SUPPORT_LEGACY
571 struct TagItem ata_tags
[] =
573 {aHidd_Name
, (IPTR
)ataPCIName
},
574 {aHidd_HardwareName
, (IPTR
)ataISAControllerName
},
577 UBYTE n
= base
->legacycount
;
579 D(bug("[ATA:PCI] ata_bus_Detect: Detecting Legacy-Buses\n"));
581 ata_ISA
= HW_AddDriver(base
->storageRoot
, base
->ataClass
, ata_tags
);
584 D(bug("[ATA:PCI] ata_bus_Detect: Adding Remaining Legacy-Buses\n"));
586 while (LegacyBuses
[n
].lb_Port
)
588 probedbus
= AllocVec(sizeof(struct ata_ProbedBus
), MEMF_ANY
);
591 probedbus
->atapb_Parent
= ata_ISA
;
592 probedbus
->atapb_Node
.ln_Name
= (STRPTR
)LegacyBuses
[n
].lb_Name
;
593 probedbus
->atapb_Node
.ln_Type
= ATABUSNODEPRI_LEGACY
;
594 probedbus
->atapb_Node
.ln_Pri
= ATABUSNODEPRI_LEGACY
- (base
->ata__buscount
++);
595 probedbus
->atapb_Device
= NULL
;
596 probedbus
->atapb_Vendor
= 0;
597 probedbus
->atapb_Product
= 0;
598 probedbus
->atapb_BusNo
= LegacyBuses
[n
].lb_Bus
;
599 probedbus
->atapb_IOBase
= LegacyBuses
[n
].lb_Port
;
600 probedbus
->atapb_IOAlt
= LegacyBuses
[n
].lb_Alt
;
601 probedbus
->atapb_INTLine
= LegacyBuses
[n
].lb_IRQ
;
602 probedbus
->atapb_DMABase
= 0;
604 D(bug("[ATA:PCI] ata_bus_Detect: Adding Legacy Bus - IO: %x:%x\n",
605 probedbus
->atapb_IOBase
, probedbus
->atapb_IOAlt
));
607 Enqueue((struct List
*)&base
->probedbuses
, &probedbus
->atapb_Node
);
615 D(bug("[ATA:PCI] ata_bus_Detect: Registering Probed Buses..\n"));
617 while ((probedbus
= (struct ata_ProbedBus
*)RemHead((struct List
*)&base
->probedbuses
)) != NULL
)
619 struct TagItem attrs
[] =
621 {aHidd_Name
, (IPTR
)ataPCIName
},
622 {aHidd_HardwareName
, (IPTR
)probedbus
->atapb_Node
.ln_Name
},
623 {aHidd_Producer
, probedbus
->atapb_Vendor
},
624 {aHidd_Product
, probedbus
->atapb_Product
},
625 {aHidd_DriverData
, (IPTR
)probedbus
},
626 {aHidd_ATABus_PIODataSize
, sizeof(struct pio_data
) },
627 {aHidd_ATABus_BusVectors
, (IPTR
)bus_FuncTable
},
628 {aHidd_ATABus_PIOVectors
, (IPTR
)pio_FuncTable
},
629 {aHidd_ATABus_DMADataSize
, sizeof(struct dma_data
) },
630 {aHidd_ATABus_DMAVectors
, (IPTR
)dma_FuncTable
},
632 * Legacy ISA controllers have no other way to detect their
633 * presence. Do not confuse the user with phantom devices.
635 {aHidd_Bus_KeepEmpty
, probedbus
->atapb_Node
.ln_Type
== ATABUSNODEPRI_LEGACY
642 * We use this field as ownership indicator.
643 * The trick is that HW_AddDriver() fails if either object creation fails
644 * or subsystem-side setup fails. In the latter case our object will be
646 * We need to know whether OOP_DisposeObject() or we should deallocate
647 * this structure on failure.
649 probedbus
->atapb_Node
.ln_Succ
= NULL
;
651 D(bug("[ATA:PCI] ata_bus_Detect: Attaching Instance of 0x%p to Controller @ 0x%p\n", base
->busClass
, probedbus
->atapb_Parent
));
653 bus
= HIDD_StorageController_AddBus(probedbus
->atapb_Parent
, base
->busClass
, attrs
);
656 D(bug("[ATA:PCI] Failed to create object for device %04X:%04X - IRQ %d, IO: %x:%x, DMA: %x\n",
657 probedbus
->atapb_Vendor
, probedbus
->atapb_Product
, probedbus
->atapb_INTLine
,
658 probedbus
->atapb_IOBase
, probedbus
->atapb_IOAlt
, probedbus
->atapb_DMABase
));
661 * Free the structure only upon object creation failure!
662 * In case of success it becomes owned by the driver object!
664 if (!probedbus
->atapb_Node
.ln_Succ
)
666 DeviceUnref(probedbus
->atapb_Device
, base
);
670 #ifdef SUPPORT_LEGACY
671 else if ((ata_ISA
) && (probedbus
->atapb_Parent
== ata_ISA
))
676 #ifdef SUPPORT_LEGACY
677 if ((ata_ISA
) && (ata_ISA_Ports
== 0))
679 D(bug("[ATA:PCI] ata_bus_Detect: Disposing Unused ISA controller object\n");)
680 HW_RemoveDriver(base
->storageRoot
, ata_ISA
);
684 D(bug("[ATA:PCI] ata_bus_Detect: Finished..\n");)
689 ADD2INITLIB(ata_bus_Detect
, 30)